Commit Graph
824 Commits
Author SHA1 Message Date
aiongg 4e5e040a79 Integration: Numbering & Section Options keeps Enter and Escape for an open popup
#342's Numbering & Section Options draws its OK and Cancel beside the options and reads Enter and Escape there, before the footer that #325's update guards. The same popup_open guard applies to those checks, so Enter and Escape in an open menu or name field go to the popup.
2026-10-10 16:19:06 +00:00
aiongg 4a6fef0ba1 Merge #325 update: popup Enter/Escape guard, presets as engine commands
Conflict: ROADMAP.md: the PR's New Document line (file.savePreset, file.deletePreset), next's Numbering & Section Options and chapter numbering lines
2026-10-10 16:19:02 +00:00
aiongg d241a22f80 Merge #83 update: drop cap fixes
Drop cap style through IDML as a Dropcap nested style, spaces after the cap, one-line caps, nested styles after the cap, own nested-style lists clearing an inherited drop cap style (cells and notes too), cleared styles round-tripping, tabs in right-to-left drop caps.
Conflict: ROADMAP.md: next's INDD, Interface language and Show CJK Features lines (the PR's main-merge resolution, already on next)
Conflict: crates/compose/src/lib.rs: next's warichu placement followed by the trimmed trailing spaces
Conflict: crates/compose/src/tests.rs: next's side; the PR's side repeats helpers and tests next already has
Conflict: crates/idml/src/import.rs: next's range_format
Conflict: crates/idml/src/tests.rs: next's side, with the PR's drop_caps_import_and_round_trip and its new drop_cap_fixture and nested-style clearing tests in place of next's older drop cap test
2026-10-10 16:18:49 +00:00
aiongg 435408d840 Merge #84 update: upstream main merged into the PR
next already holds both parents of the PR's main merge; the conflicts come from the two different resolutions of the same pair, and next's tree stays unchanged.
Conflict: ROADMAP.md: next's INDD, Interface language and Show CJK Features lines
Conflict: crates/compose/src/tests.rs: next's side (tracked_lines and the spacing/GREP tests already sit elsewhere in next's file)
Conflict: crates/fonts/src/fontdb.rs: next's canonical_family lookup in exact_style_traits (#126)
Conflict: crates/idml/src/import.rs: next's range_format
Conflict: crates/idml/src/tests.rs: next's side; the PR's block repeats tests next already has
2026-10-10 16:17:21 +00:00
aiongg e6ddea8edf Merge #81 update: upstream main merged into the PR
next already holds both parents of the PR's main merge (dc18c104 and main 92649ffd); the conflicts come from the two different resolutions of the same pair.
Conflict: ROADMAP.md: next's IDML, INDD and Interface language lines; the PR's PDF export line, which keeps main's Export PDF options dialog sentence that next had dropped
Conflict: crates/compose/src/tests.rs: next's side (tracked_lines and the spacing/GREP tests already sit elsewhere in next's file)
Conflict: crates/fonts/src/fontdb.rs: next's canonical_family lookup in exact_style_traits (#126)
Conflict: crates/idml/src/import.rs: next's range_format
Conflict: crates/idml/src/tests.rs: next's side; the PR's block repeats tests next already has
2026-10-10 16:17:03 +00:00
aiongg a2ff7d03f8 Drop caps: nested-style lists in table cells and notes clear an inherited drop cap style too
The IDML import pass walks each story's table cells, footnotes and
endnotes (nested, depth-bounded) as well as its own paragraphs.
2026-10-10 16:11:43 +00:00
aiongg 5365d0f7ca Drop caps: tabs in right-to-left drop caps advance to the tab stops
Measured from the column's right edge, past the right indent.
2026-10-10 15:57:10 +00:00
aiongg f9fb640229 Drop caps: a cleared drop cap style round-trips through IDML
A drop cap style set at a level ([None] included) restyles the leading Dropcap entry of the nested style list, in export and when composing. A paragraph or style without nested styles of its own that clears an inherited drop cap style is written with the inherited list, whose Dropcap entry it sets to [None], or with an empty list.
2026-10-10 15:57:10 +00:00
aiongg 276b6f3170 Drop caps: an IDML nested style list of its own clears an inherited drop cap style
A style or paragraph whose nested style list has no leading Dropcap entry gets no drop cap style, since its list replaces the inherited one, Dropcap entry included.
2026-10-10 15:57:07 +00:00
aiongg 70e41a297d Drop caps: nested styles start after the drop cap style
Test that the drop cap style counts as a leading "through 1 Dropcap" nested style, and describe the IDML form in ROADMAP. The previous drop cap commit also makes the cap reach down the text's leading rather than to where line N is set.
2026-10-10 15:50:14 +00:00
aiongg bcdbb68eee Drop caps: one-line caps keep a smaller size and set their tabs
A one-line drop cap keeps its characters' own point size when it is smaller than the text (verse numbers), and tabs inside a left-to-right drop cap advance to the paragraph's tab stops.
2026-10-10 15:50:05 +00:00
aiongg 21863563f3 Drop caps: a space after the cap doesn't widen the indent
Spaces right after the drop cap are set at its size on its baseline and leave the lines beside it starting where its characters end.
2026-10-10 15:49:48 +00:00
aiongg 7636af73e4 Drop caps: the cap style goes through IDML as a Dropcap nested style
IDML has no drop cap style attribute. Import reads the nested style list's leading "through 1 Dropcap" entry as the drop cap style; export writes the drop cap style as that entry. The drop cap style counts as that entry when composing, so nested styles after it start after the drop cap.
2026-10-10 15:48:58 +00:00
aiongg a82174d53e Merge upstream main into fix/29-kerning-across-runs
Every conflicted file resolves as in the merge of main into feat/text-editing-and-frames (this branch carries #83 and #84 up to "Merge #83 into feat/text-editing-and-frames").
Conflict: ROADMAP.md, crates/compose/src/lib.rs, crates/engine/src/cmd/text.rs, crates/fonts/src/fontdb.rs, crates/idml/src/import.rs, crates/idml/src/tests.rs, crates/ui-egui/src/canvas.rs, crates/ui-egui/src/control.rs, crates/ui-egui/src/lib.rs: as feat/text-editing-and-frames's merge, without that branch's later copy and paste keys commit
Conflict: crates/compose/src/tests.rs: both sides' tests (this branch's kerning and kenten tests, main's Spanish hyphenation test)
2026-10-10 15:37:42 +00:00
aiongg 5551cf9a25 Merge upstream main into feat/text-editing-and-frames
The layout-parity files (ROADMAP, compose lib/tests, engine text, fonts fontdb, idml import/tests, canvas) resolve as in the merge of main into feat/layout-parity.
Conflict: ROADMAP.md: as feat/layout-parity's merge
Conflict: crates/compose/src/lib.rs: as feat/layout-parity's merge; this branch's trimmed trailing spaces follow main's warichu::place and come before the drop cap splice
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/engine/src/cmd/text.rs: as feat/layout-parity's merge; this branch's TypingFormat/typing_format and main's warichu_cmd
Conflict: crates/fonts/src/fontdb.rs: this branch's styles/traits_of/linked_style over style_traits; style_traits falls back to the family without main's format suffix (exact_style_traits)
Conflict: crates/idml/src/import.rs, crates/idml/src/tests.rs, crates/ui-egui/src/canvas.rs: as feat/layout-parity's merge
Conflict: crates/ui-egui/src/control.rs: main's page_index and automation_contract_tests, then this branch's tests module
Conflict: crates/ui-egui/src/lib.rs: this branch's ClipboardFn and main's Inbox of ImportedFile
Conflict: crates/ui-egui/src/menus.rs: main's Quick Apply tests, then this branch's copy and paste keys test
2026-10-10 15:36:43 +00:00
aiongg 7f23a5e05b Merge upstream main into feat/layout-parity
Conflict: ROADMAP.md: this branch's Text engine, IDML interchange and Right-to-left lines; main's FID2, PDF export and Interface language lines
Conflict: crates/compose/src/lib.rs: list labels as main's number_label/bullet_label/empty-paragraph arms, kept in this branch's list_label form that marks label glyphs; main's layout_line call (ends_para, forced_mid) and warichu::place, then the drop cap splice; rule above uses main's first-line column/end_x span with this branch's rule_color; caret(): drop-cap branch, then main's stacked-row metrics
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/engine/src/cmd/text.rs: type.para doc lists the drop cap fields and main's rule fields
Conflict: crates/fonts/src/fontdb.rs: both (plausible/measured_top/typo_ascent and without_format_suffix)
Conflict: crates/idml/src/import.rs: main's table style regions, borders and alternating fill/stroke attrs (this branch's alt_fills helper dropped, unused); underline/strikethrough colour from main with this branch's tint(); frame_options takes the object-style chain's TextFramePreference elements, the frame's column rule colour resolved after it
Conflict: crates/idml/src/tests.rs: main's tests, plus this branch's added tests and helpers
Conflict: crates/ui-egui/src/canvas.rs: main's compose::highlight_quads, then this branch's drop-cap highlight
2026-10-10 15:34:23 +00:00
aiongg c205b53b10 Integration: German and Japanese entries for the Numbering & Section Options strings
#342 adds twelve Layout › Numbering & Section Options strings to the shared table; next's de.rs
(#311) and ja.rs (#272) keep a row for every shared key. The rows carry over the shared table's
German and Japanese columns, so lookups are unchanged.
2026-10-10 14:56:33 +00:00
aiongg ba8e5e90ef Merge #344: fix(ui): Highlight swatch list rows and keep panels clear of scroll bars 2026-10-10 14:56:15 +00:00
aiongg 816ce1b756 Merge #342: feat(ui): Lay out Numbering & Section Options like InDesign's
Conflict: ROADMAP.md: kept both entries (New Document, then Numbering & Section Options).
Conflict: crates/ui-egui/src/dialogs.rs: width match keeps "newDocument" => 960.0 and adds "numberingSection" => 560.0, dropping the PR's "newDocument" if is_rtl => 380.0; tests keep next's helper block and add only the PR's numbering_and_section_options_keep_their_actions_in_view.
Conflict: crates/ui-egui/src/i18n.rs: kept both TABLE tail blocks (File › New › Document, then Layout › Numbering & Section Options).
Conflict: crates/ui-egui/src/i18n/it.rs: kept both tail blocks.
2026-10-10 14:56:15 +00:00
aiongg 54504fa341 Merge #341: feat(engine): Document chapter numbering and section prefix rules
Conflict: ROADMAP.md: kept both entries (New Document, then Document chapter numbering).
Conflict: crates/engine/src/cmd/book.rs: book.paginate keeps #341's chapter resolution with fix/section-start-bound's saturating page count (u32::try_from) and saturating "pages" result.
Conflict: crates/engine/src/cmd/layout.rs: page_numbering_view_tests keeps both tests (section_start_numbers_are_bounded, section_prefixes_are_short_and_avoid_plus_and_comma).
2026-10-10 14:55:15 +00:00
aiongg 39f72c5cd4 Merge fix/section-start-bound: Layout: section start numbers are bounded and page numbering can't overflow 2026-10-10 14:54:46 +00:00
aiongg 1ec2136c84 Layout: section start numbers are bounded and page numbering can't overflow
layout.section refuses a startNumber outside 1..=99 999, and so does layout.documentSetup for startPage (both go through one start_number check against designcraft_doc::MAX_PAGE_NUMBER). Document::page_number walks continuing sections in a loop with saturating arithmetic, so start numbers loaded from a file can't overflow it, and book pagination saturates its running page count.
2026-10-10 14:50:48 +00:00
moppeeerandClaude Opus 5.5 e78407027e fix(ui): Keep Enter and Escape in the Save Document Preset popup; saved presets in the engine
Review follow-up. Enter in the Save Document Preset popup created the
document and Escape closed the whole dialog: the dialog footer took
both keys while a popup was open. The dialog now leaves Enter and
Escape to an open popup (read before it draws, as egui closes a popup
on Escape that frame): Enter in the preset name saves the preset,
Escape closes only the popup. Clicking the name field no longer closes
the popup either (menus close on any click; this one only outside), and
the field takes focus when the popup opens.

Saved presets lived only in the UI state, so `file.new {preset: name}`
refused them. They are now engine preferences (saved with prefs.json):
`file.savePreset {name, …the file.new settings}` replaces a preset of
that name and refuses built-in names, `file.deletePreset {name}` removes
one, `file.presets` lists them after the built-in ones (`saved: true`),
and `file.new {preset}` makes documents from them by name. The Saved tab
reads and writes them through those commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:37:21 +02:00
aiongg e0019d7005 Integration: Japanese entries for the New Document strings
#325 adds fifteen File › New › Document strings to the shared table; next's ja.rs (#272) keeps a
row for every shared key. The rows carry over the shared table's Japanese column, so lookups are
unchanged.
2026-10-10 14:23:41 +00:00
aiongg aee7e2e38d Integration: German entries for the New Document strings
#325 adds fifteen File › New › Document strings to the shared table; next's de.rs (#311) keeps a
row for every shared key. The rows carry over the shared table's German column, so lookups are
unchanged.
2026-10-10 14:23:41 +00:00
aiongg 0b5c4fefd4 Merge #325: feat(ui): Lay out the New Document window like InDesign's
Conflict: crates/ui-egui/src/lib.rs: both modules kept, mod new_document before mod object_control
Conflict: crates/ui-egui/src/dialogs.rs: the PR's translated ok_label plus next's findFont arm, translated the same way ("Replace All"); cancel_label is a match: newDocument "Close", findFont "Done", else "Cancel"
Conflict: crates/ui-egui/src/i18n/it.rs: both blocks kept (next's machine-translated and Tabs rows, then the PR's File › New › Document rows)
2026-10-10 14:23:26 +00:00
aiongg c26d0bacbe Integration: Japanese entries for the Tabs strings
#343 adds its twelve Tabs strings to the shared table; next's ja.rs (#272) keeps a row for every
shared key. The rows carry over the shared table's Japanese column, so lookups are unchanged.
2026-10-10 14:22:35 +00:00
aiongg 944ef17f62 Integration: German entries for the Tabs strings
#343 adds its twelve Tabs strings to the shared table; next's de.rs (#311) keeps a row for every
shared key. The rows carry over the shared table's German column, so lookups are unchanged.
2026-10-10 14:22:35 +00:00
aiongg 33a26228f5 Merge #343: Tabs: commands, Tabs panel and a Tabs section in Paragraph Style Options
Conflict: ROADMAP.md: both lines kept (next's IDML1 line, then the Tabs panel line)
Conflict: crates/engine/src/cmd/mod.rs: both spec lists kept (thread::specs, then tabs::specs)
Conflict: crates/ui-egui/src/dialogs.rs: next's delete_paragraph_style and the PR's style_tabs both kept, without the section_list doc comment that next removed; in the tests the PR's copies of draw, ruled_paragraph, undo_steps, the rule tests, command_app, the generic command tests and the text frame options test duplicated next's identical ones and were dropped, keeping only the PR's new Tabs section test
Conflict: crates/ui-egui/src/i18n/it.rs: both blocks kept (next's machine-translated rows, then the Tabs rows)
Conflict: crates/ui-egui/src/i18n/uk.rs: both blocks kept (next's machine-translated rows, then the Tabs rows)
2026-10-10 14:22:16 +00:00
moppeeerandClaude Opus 5.5 d361d84e38 fix(ui): Highlight swatch list rows and keep panels clear of scroll bars
Swatch lists (Character panel, Properties, task bar) shaded the row under
the pointer with the theme's hover grey, a few levels from the popup's
own background, so it looked as if nothing changed. The row under the
pointer is now white on blue, like a menu; the current swatch keeps its
shading. The lists also grow to fit their longest name, and their rows
stop short of the scroll bar that floats over the list's edge, so names
like C=15 M=100 Y=100 K=0 are no longer cut by it. The four copies of
the list are one shared function now.

The Glyphs panel counted its columns from the panel's whole width, so
the last column ran under the floating scroll bar and was cut off; the
columns now leave the bar room.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:18:48 +02:00
aiongg ea3f11b9b7 UI: Tabs section in Paragraph Style Options
The style's stops on the same ruler and fields as the Tabs panel, with
Clear All, applied with the other edits on OK.
2026-10-10 14:17:58 +00:00
aiongg 2e3d954f5b UI: Tabs panel with a ruler over the text column
Type › Tabs (Cmd+Shift+T) floats a Tabs panel: alignment buttons, X,
Leader and Align On fields, and a ruler where a click adds a stop, a
drag moves it and dragging it off the ruler deletes it. The triangles
on the ruler drag the first-line, left and right indents. The panel
menu has Clear All, Delete Tab, Repeat Tab and Reset Indents. The panel
opens above the selected horizontal text frame with the ruler at the
view's zoom over the column; the magnet button places it there again.
2026-10-10 14:17:58 +00:00
aiongg 0f94bbb1ac Text: commands to add, move, change, delete, clear and repeat tab stops
type.tabs.* edit the stops of the selected paragraphs or, with a style
parameter, of a paragraph style. Positions are finite and clamped, a
paragraph holds at most 100 stops, leaders up to 8 characters and the
align-on character is one character. type.tabs.get reports the stops,
indents and the text column they are measured in.
2026-10-10 14:05:09 +00:00
moppeeerandClaude Opus 5.5 9c683f3ef8 feat(ui): Lay out Numbering & Section Options like InDesign's
Layout > Numbering & Section Options now opens its own window instead of
the generated command form, on the section of the page in view: Start
Section (always on for page 1), Automatic Page Numbering or Start Page
Numbering at, and a Page Numbering group with Section Prefix, Style,
Section Marker and Include Prefix when Numbering Pages; then Document
Chapter Numbering with its style, Automatic Chapter Numbering, Start
Chapter Numbering at, Same as Previous Document in the Book (only in a
book) and the book's name. OK and Cancel sit beside the options, out of
the scrolling body.

OK runs layout.section and layout.chapterNumbering; a refused value
(a prefix over eight characters or with + or a comma, a start number
below 1) keeps the window open and changes nothing. Opening the window
reads the chapter numbering without running a command, so it doesn't
stop a Data Merge preview. New strings are translated (German, French,
Spanish, Japanese, Chinese, Italian).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:58:33 +02:00
aiongg d4a7cc33fe Merge #329: Fix help buttons disabled when on homepage 2026-10-10 13:50:55 +00:00
aiongg d1587fc354 Integration: German entry for Show CJK Features
#336 adds the Show CJK Features string to the shared table and the ja, ar, pt_br, it and uk tables; next's German table (#311) covers every key of those tables, so it gets a row too (machine translation, the shared table's German column).
2026-10-10 13:50:55 +00:00
aiongg 6286f7c0a5 Merge #336: UI: CJK features behind a preference that follows the interface language
Conflict: ROADMAP.md: next's Right-to-left and Interface language lines (IDML Kashidas, German and Japanese cover every catalog, Ukrainian covers every key) plus the PR's Show CJK Features line
Conflict: crates/ui-egui/src/lib.rs: the PR's cjk_features() before next's opens_as_document (with .indd/.indt and its doc comment)
2026-10-10 13:50:51 +00:00
aiongg 4fd3c0fcae UI: CJK features behind a preference that follows the interface language
Preferences > Type > Show CJK Features (cjkFeatures; unset follows the
interface language: on for Japanese, Chinese and Korean) hides the
CJK-only Type menu items (Tate-Chu-Yoko, Ruby, Kenten, Warichu) and the
Ruby Quick Apply entry. The commands, layout and IDML work either way.
2026-10-10 13:48:07 +00:00
moppeeerandClaude Opus 5.5 498e3d401c fix(engine): Keep section prefixes to InDesign's rules
A section prefix is at most eight characters and contains no plus or
comma (page references and ranges use them); `layout.section` refuses
others and leaves the section unchanged. Symbols, a footnote style,
no longer number pages. The parameter documentation lists the 01, 001
and 0001 styles, and a test pins the fields the generated dialogs read
from both numbering commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:39:38 +02:00
moppeeerandClaude Opus 5.5 f061be9b3c feat(engine): Document chapter numbering
A document's chapter number now has a style (1, I, i, A, a, 01, 001,
0001) and a source, as in Numbering & Section Options > Document
Chapter Numbering: Automatic Chapter Numbering (one more than the
previous document in the book; 1 first), Start Chapter Numbering at,
or Same as Previous Document in the Book.

`layout.chapterNumbering {style?, start?, source?}` sets them (undoable)
and, with no parameters, reports them with the open book that holds the
document. The book's Update Numbering (`book.paginate`) resolves chapter
numbers in book order and reports them. Chapter Number variables and
cross-reference chapter numbers use the style.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:39:33 +02:00
aiongg bb4fd03f7e Merge #319: DTD: memoize content-model matching, let entity names be any length 2026-10-10 13:19:59 +00:00
aiongg 3692eba3c4 Integration: fonts match a face's own style name before other faces' aliases (#126)
Static families such as Alexandria name every weight's legacy family
"Alexandria <Weight>" with subfamily "Regular". Matching names and aliases in
one pass let the first such face (Black) answer for Regular, so text set in
Regular came out in Black, wider, and pushed lines into overset.

(cherry picked from commit 681a3ec499834b866dd18244e5b25b425c682b10)
2026-10-10 13:19:53 +00:00
aiongg 9a0e26a6a1 Merge #331: Compose: page numbers take the Digits setting of their text
Conflict: crates/compose/src/shape.rs: next's shape_segment call with `styles`; added the PR's comment and digit mapping of the page name before it
2026-10-10 13:19:50 +00:00
aiongg 1abb74da0f Merge #330: Compose: the CJK leading model and character alignment apply only under the Japanese composers 2026-10-10 13:18:52 +00:00
Michał Kosior crqch 371bd15dc5 Fix help buttons disabled when on homepage 2026-10-10 15:15:57 +02:00
moppeeerandClaude Opus 5.5 651ef6aec2 feat(ui): Lay out the New Document window like InDesign's
File > New > Document now shows Recent, Saved, Print, Web and Mobile
tabs of page cards (drawn to the preset's proportions; double-click
creates) beside the preset's details: document name, width and height
with arrows, units, orientation, pages, start page #, facing pages,
primary text frame, columns and gutter, and collapsible margins and
bleed and slug per edge with link toggles. Save Document Preset keeps
presets by name; documents made are remembered for the Recent tab.
Small windows stack the details above the presets and scroll; the
layout mirrors for right-to-left languages. New strings go through the
translation tables (Italian, German, French, Spanish, Japanese, Chinese).

file.new takes intent, units, startPage and per-edge bleed and slug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:53:51 +02:00
Ikki NishiharaandClaude Sonnet 5.5 a46da6eff0 DTD: memoize content-model matching, let entity names be any length
Nested repetitions such as ((a)*)* asked the group below for the same end
positions again and again, which is exponential in their depth: remember
the positions of a group per start position while one element's children
are matched. The search for the closing semicolon of a parameter-entity
reference had a 256-byte window, so a longer name was left unexpanded
without an error: stop the search at whitespace or the next percent sign
instead, which keeps a round linear and puts no limit on the name.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 21:10:16 +09:00
aiongg 5dc8383a50 Compose: apply the CJK leading model and character alignment only under the Japanese composers
Every IDML root style carries LeadingModelAkiBelow and AlignEmCenter, but only
the Japanese composers (HL Composer J, HL Single J) use them; the Adobe and
World-Ready composers set lines baseline to baseline with every character on
the Roman baseline. Applying them everywhere moved lines down after a size
change and lowered smaller-em glyphs, pushing the last lines of tight frames
(and whole keep-together paragraphs) into overset.

Composer gains Japanese and JapaneseSingleLine, read from and written to IDML;
the composer choice in the UI keeps the kind.
2026-10-10 11:56:45 +00:00
aiongg e6428d2111 Compose: page numbers take the Digits setting of their text
Automatic page numbers (and section markers) were set from the page name as
typed, so a page number in Hindi Digits text drew Western digits, which an
Arabic-only font shows as missing-glyph boxes. They now map their digits like
typed text does.
2026-10-10 11:55:28 +00:00
aiongg 7d39f0061c Integration: #305's reopen tests read legacy JSON as format 1 (#83)
#83 adds native format 2 and an upgrade that pins Keep Lines Together and Align Left Edge where a format-1 style chain leaves them unset. #305's tests save the same document as native ZIP and as legacy JSON (format 1) and compared both as whole documents. The base style now sets both attributes, and only the native ZIP is compared as a whole document; the nullable resolution is checked for both.
2026-10-10 11:13:49 +00:00