Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

7.7KB

Epic: Composite Address Controls and Mixed-Content Text

Vision / why this matters: Today every text element is one line, and each line is either pure static text or a single bound CSV column. Real address blocks and salutation lines need to combine literal text with one or more fields on the same line (e.g., “Attn: {First Name} {Last Name}"), and operators currently have to place, align, and manage every address line by hand with no notion that they belong together. This epic adds that composition, then lets operators place a whole address block as one manageable unit.

Stories

Mix static text and CSV fields within a single text element - Status: Not Started

Card As a print operator, I want to combine literal text and one or more CSV fields within a single text element (e.g., “Attn: {First Name} {Last Name}"), so that I can compose natural sentences and labels instead of being limited to one static line or one bound field per element.

Conversation notes

  • Confirmed with the user (2026-09-29): this is a general upgrade, not scoped only to the Address Control below — every text element in the designer gains this capability, replacing today's mutually-exclusive StaticText/ColumnName model (TextElementLayout, TemplateElement) everywhere.
  • Content becomes an ordered sequence of “runs”: literal text runs and field-token runs (each bound to a CSV column), concatenated per record at render time.
  • Backward compatibility is non-negotiable: every existing saved template (pure static text, or a single bound column) must continue to render byte-for-byte identically — model these as the one-run special case of the new run-sequence, not a separate parallel code path that could drift from it.
  • A field token bound to a column that isn't a real CSV header remains a hard, whole-run failure before any page renders — the same blocking rule as today's single-column binding (TEMPLATE_FORMAT.md's “Known gaps”), just evaluated per token instead of per element.
  • The properties panel needs a real editing affordance for composing mixed content — not a plain text box where a field token is just a raw substring an operator could accidentally mistype or break. Exact mechanism (e.g., an “Insert field” action that drops in a protected token chip at the cursor, or a {Column Name} bracket-typing convention that's parsed back into runs on commit) is a Development Team design decision; document whichever is chosen.
  • Canvas display should visually distinguish the field-token portions from literal text within the same element, extending today's highlight-fill treatment for pure dynamic elements so it now applies per-run rather than per-element.
  • Persisted XML shape (e.g., nested run/field child elements, or an inline token syntax within the element's own text content) is a Development Team decision, to be documented in TEMPLATE_FORMAT.md — but it must remain backward-compatible with every template saved before this story.
  • Out of scope: any formatting/transformation applied to a token's value (date formatting, casing, truncation) — verbatim column value substitution only, matching today's single-column binding behavior exactly.

Confirmation (Acceptance Criteria)

  • A text element can contain any combination of literal text runs and CSV-field-bound runs, rendered concatenated per record.
  • Existing templates using only static text or only a single bound column render identically to before this story (a real regression check against previously-saved templates, not just new-template testing).
  • The properties panel lets an operator compose and edit mixed content without accidentally corrupting a field token.
  • The canvas visually distinguishes field-token portions from literal text within the same element.
  • The mixed content is persisted in the saved XML template and restored correctly on reopen.
  • A field token bound to a column that isn't a real CSV header fails the whole run before any page renders, same as today's single-column rule.

Estimate: TBD (dev-team to size) Dependencies: Depends on “Create a dynamic text token from a CSV column” (Done, Sprint 3) — extends, rather than replaces, that story's persisted format for the existing single-run case.

Group lines into a single, movable Address Control - Status: Not Started

Card As a print operator, I want to group a custom, ordered set of lines (each using the mixed static-text-and-field content from the previous story) into a single Address Control element that I can place, move, and resize on the canvas as one unit, so that I can build and manage address blocks without positioning every line by hand.

Conversation notes

  • Confirmed with the user (2026-09-29): the operator builds a fully custom line list — add, remove, and reorder any number of lines — not a fixed starter template of pre-named lines.
  • Confirmed with the user: the whole control moves and resizes via a single anchor point; line spacing is automatic. Exact spacing rule (derived from each line's own font size/leading, or an explicit “line spacing” value stored on the control) is a Development Team design decision, documented alongside the persisted format.
  • Confirmed with the user: “Collapse if blank” (already shipped, Sprint 4) stays a per-line checkbox exactly as it works today, but defaults to checked/on for a line added inside an Address Control — an explicit change from a standalone element's default-off. Existing standalone elements are unaffected.
  • AddressLineCollapser's current grouping rule (lines sharing the same X position stack together) is an implicit heuristic from before this story existed. Once lines live inside one named control, the team should decide whether the collapse-stack grouping should key off “belongs to the same control” instead of (or in addition to) shared X — flagged for the team to resolve during implementation, not decided here, since it affects whether two visually-adjacent-but-unrelated elements could accidentally group.
  • Persisted format: a new container element (e.g. <addressControl>) wrapping its child lines — exact shape is a Development Team decision, documented in TEMPLATE_FORMAT.md, but must round-trip through save/reopen and remain independently renderable by the CLI without the desktop app, same as every other template element.
  • Rotating the control as a whole group (interacting with Sprint 4's rotation feature) is explicitly out of scope for this story — note as a candidate follow-up, not required here.
  • Selecting the control on canvas must still allow editing an individual line's content/binding (via the previous story's editing UI) without breaking the group's single-anchor movement behavior.

Confirmation (Acceptance Criteria)

  • An operator can create an Address Control on the canvas and add, remove, and reorder any number of lines within it.
  • Each line supports the same static/field/mixed content as a standalone text element (previous story).
  • The control moves and resizes on the canvas as a single unit via one anchor point, with line spacing computed automatically.
  • Each line's “Collapse if blank” defaults to on within a control, remains individually toggleable, and the resulting collapse/shift behavior matches the existing per-line collapse rule (Sprint 4).
  • The control's full structure (lines, content, per-line settings) is persisted in the saved XML template and restored correctly on reopen.
  • The rendered PDF reflects the same line content, order, and collapse behavior shown in the designer canvas.

Estimate: TBD (dev-team to size) Dependencies: Depends on “Mix static text and CSV fields within a single text element” (above, same epic) and “Collapse blank optional address lines consistently” (Done, Sprint 4).

Powered by TurnKey Linux.