diff --git a/ROADMAP.md b/ROADMAP.md index 016e9818a..ab7583439 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~15 points (60% → 75% ready for real work) and ~150–230 h away -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** trivial (progress log: Hebrew field results and smart quotes, #1670; previously trivial: Backspace removes a selected table, rows or columns, #1844; previously trivial: progress log: mixed Hebrew/Latin text keeps its order in Word, #1543; previously trivial: progress log: web typing in non-Latin text no longer repeats, #1480; previously trivial: progress log: font family caches bounded and math font lookups follow font changes, #1354; previously trivial: `-->` AutoCorrect replacement, #2223; previously trivial: numbered headings, #1793; previously trivial: Navigation Find exposes Results, #2096; previously trivial: progress log: Columns on selected text, #2024; previously trivial: progress log: legacy outline, shadow, emboss and imprint text effects drawn, #2534; previously trivial: progress log: Indonesian proofing, #498; previously trivial: progress log: DOCX glossary documents (building blocks); previously trivial: progress log: Read Mode keeps the keyboard and shows whole, unobscured columns, #1772); previously trivial: progress log: font list entries of tall-ascent fonts no longer cut off, #2570); previously trivial: progress log: Split Cells and Convert Text to Table dialogs follow the Word check, #2592; previously trivial: a new source's Tag is made like Word's, three letters of the author and two digits of the year with a number added when taken, and an edit keeps the Tag, #2094; previously trivial: Web Layout fills the window width, #1876; previously trivial: progress log: Different First Page headers reachable from page 1, #2826; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717); previously trivial: progress log: web preferences kept between visits, #2132; previously trivial: progress log: undrawable private-use list bullets show the level's default bullet, #1683); previously trivial: table style editor formats every part, #714; previously trivial: VML freeforms read and kept on save; previously trivial: progress log: consistent preferred cell widths; previously trivial: multi-paragraph field instructions no longer add blank lines; previously trivial: page-break-only list paragraphs hide their labels; previously trivial: progress log: grouped `flowChartOr` shapes draw their circle and crossing spokes; previously trivial: progress log: copies keep their formatting in other programs, #1523; previously trivial: progress log: privacy options on save, #1062; previously trivial: progress log: equation pictures in theme colours on Windows, #1002; previously trivial: symbol fonts, #776; previously trivial: the save prompt answers from the keyboard, #861; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** trivial (a mouse drag on a table leaves the view where it is, #1738; previously trivial: progress log: Hebrew field results and smart quotes, #1670; previously trivial: Backspace removes a selected table, rows or columns, #1844; previously trivial: progress log: mixed Hebrew/Latin text keeps its order in Word, #1543; previously trivial: progress log: web typing in non-Latin text no longer repeats, #1480; previously trivial: progress log: font family caches bounded and math font lookups follow font changes, #1354; previously trivial: `-->` AutoCorrect replacement, #2223; previously trivial: numbered headings, #1793; previously trivial: Navigation Find exposes Results, #2096; previously trivial: progress log: Columns on selected text, #2024; previously trivial: progress log: legacy outline, shadow, emboss and imprint text effects drawn, #2534; previously trivial: progress log: Indonesian proofing, #498; previously trivial: progress log: DOCX glossary documents (building blocks); previously trivial: progress log: Read Mode keeps the keyboard and shows whole, unobscured columns, #1772); previously trivial: progress log: font list entries of tall-ascent fonts no longer cut off, #2570); previously trivial: progress log: Split Cells and Convert Text to Table dialogs follow the Word check, #2592; previously trivial: a new source's Tag is made like Word's, three letters of the author and two digits of the year with a number added when taken, and an edit keeps the Tag, #2094; previously trivial: Web Layout fills the window width, #1876; previously trivial: progress log: Different First Page headers reachable from page 1, #2826; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717); previously trivial: progress log: web preferences kept between visits, #2132; previously trivial: progress log: undrawable private-use list bullets show the level's default bullet, #1683); previously trivial: table style editor formats every part, #714; previously trivial: VML freeforms read and kept on save; previously trivial: progress log: consistent preferred cell widths; previously trivial: multi-paragraph field instructions no longer add blank lines; previously trivial: page-break-only list paragraphs hide their labels; previously trivial: progress log: grouped `flowChartOr` shapes draw their circle and crossing spokes; previously trivial: progress log: copies keep their formatting in other programs, #1523; previously trivial: progress log: privacy options on save, #1062; previously trivial: progress log: equation pictures in theme colours on Windows, #1002; previously trivial: symbol fonts, #776; previously trivial: the save prompt answers from the keyboard, #861; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4 > **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** trivial (progress log: pasted blockquotes are indented paragraphs, #1270; previously trivial: progress log: print-area strings translated in every catalog; previously trivial: progress log: comments readable in the dark theme, #2045; previously trivial: progress log: ODT sections, #1379; previously trivial: progress log: table deletes, Change Case and Unlink Fields respect Track Changes and locked content controls, #1329; previously trivial: progress log: rounded rectangle corners, #1476; previously trivial: progress log: Save As type list, #1399; previously trivial: progress log: privacy options on save, #1062; previously trivial: progress log: equation pictures in theme colours on Windows, #1002; previously trivial: symbol fonts, #776; previously trivial: the save prompt answers from the keyboard, #861; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4 > **Printing update:** 2026-10-12 · direct desktop printing through craft-print; details below. @@ -137,6 +137,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm - 2026-10-15: Find opens Navigation on Results; editing the query restores Results after manual Headings/Pages navigation. Typed and selected-text searches retain document contents (#2096). | Date | What landed | +| 2026-10-16 | Releasing a table drag with the mouse (column or row border, move handle, selection areas) leaves the view where it is instead of scrolling back to the caret (#1738) | | 2026-10-16 | Hebrew in fields and quotes (#1670): a STYLEREF (or any field) showing right-to-left text such as "פרק א" reads right to left in headers and the body instead of reversed; smart quotes in Hebrew pinned to Word's logical-order result (“ before, ” after, ” in acronyms like צה"ל) | | 2026-10-15 | Backspace with a whole table selected removes it, as in Word, and selected whole rows or columns go the same way; Delete clears them and keeps the table. A selection that covers a table and the paragraph before or after it removes the table, also when it starts inside the table or the table is nested (#1844) | | 2026-10-15 | Image size limits are checked before allocating (#1321): a picture whose header declares more RGBA bytes than the 512 MiB budget is refused before decoding (render and PDF share one helper in `wordcraft-geom`), and page rasters are capped at 100 million pixels in total, scaled down rather than only per side. | diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 487309349..c7cb690ff 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -45,6 +45,9 @@ pub struct CanvasState { /// revision: finding out walks every paragraph, too slow for every frame (#811). markup_facts: std::cell::Cell>, pub scroll_to_caret: bool, + /// Set while a command runs for a mouse drag on a table: the pointer is already + /// on the target, so the view stays put instead of following the caret (#1738). + pub keep_view: bool, /// A heading navigation click aligns its page against the navigation pane, not just visible. pub(crate) nav_to_caret: bool, /// Touchpad travel not yet converted to an entire reading-column turn. @@ -198,6 +201,7 @@ impl Default for CanvasState { page_keys: PageKeys::default(), markup_facts: std::cell::Cell::new(None), scroll_to_caret: true, + keep_view: false, nav_to_caret: false, read_wheel_accum: 0.0, read_viewport: Settle::default(), diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 052b567fe..968fc6db9 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -823,6 +823,14 @@ impl WordApp { } } + /// `run` for a command a mouse drag on a table sends: the view stays where it is. + pub(crate) fn run_keep_view(&mut self, id: &str, params: Value) -> Result { + self.canvas.keep_view = true; + let r = self.run(id, params); + self.canvas.keep_view = false; + r + } + /// Run a command the user asked for (ribbon, shortcut, Backstage, file drop). New, Open, /// Close, Envelopes, Labels and Finish & Merge on a document with unsaved changes first ask /// Save / Don't Save / Cancel, and the command runs once that is answered (`ui.saveChanges`). @@ -1264,7 +1272,8 @@ impl WordApp { self.canvas.read_first_visible = None; } // Drawing leaves the caret where it was: following it would pull the view off the ink. - if self.session.selects_whole_story() || id == "select.all" { + // A mouse drag on a table (`run_keep_view`) does the same (#1738). + if self.session.selects_whole_story() || id == "select.all" || self.canvas.keep_view { self.canvas.scroll_to_caret = false; } else if !["ui.", "view.", "document.", "format.state", "draw."].iter().any(|p| id.starts_with(p)) { self.canvas.scroll_to_caret = true; diff --git a/crates/ui-egui/src/objects.rs b/crates/ui-egui/src/objects.rs index 37af3f7b8..6a0c79ea6 100644 --- a/crates/ui-egui/src/objects.rs +++ b/crates/ui-egui/src/objects.rs @@ -751,6 +751,55 @@ mod tests { let r = shape(&mut h); assert!((r.x + r.w / 2.0 - centre - 1.5).abs() < 0.01, "{r:?}"); } + /// #1738: a floating shape dragged from page 1 onto page 2 leaves the view where it is, even + /// though the command that drops it (`arrange.bounds`) is not a view command. + #[test] + fn dropping_a_shape_on_another_page_keeps_the_view_where_it_is() { + use egui::{Event, PointerButton}; + let mut a = WordApp::new(wordcraft_engine::Session::new(Document::new()), crate::Services::default()); + a.run("view.commentsPane", json!({"value": false})).unwrap(); + a.run("insert.shape", json!({"kind": "rectangle", "width": 100, "height": 50})).unwrap(); + a.run("arrange.bounds", json!({"page": 0, "x": 100, "y": 250})).unwrap(); + let end = Pos::body(0, wordcraft_doc::para::OBJ.len_utf8()); + a.run("caret.set", json!({"pos": end})).unwrap(); + a.run("text.insert", json!({"text": "one"})).unwrap(); + a.run("text.newParagraph", json!({})).unwrap(); + a.run("para.pageBreakBefore", json!({})).unwrap(); + a.run("text.insert", json!({"text": "two"})).unwrap(); + a.run("view.zoom", json!({"value": 30})).unwrap(); + a.run("select.range", json!({"anchor": Pos::body(0, 0), "focus": end})).unwrap(); + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1440.0, 900.0)).with_step_dt(1.0 / 60.0).build_ui_state( + |ui, app: &mut WordApp| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }, + a, + ); + for _ in 0..6 { + h.step(); + } + let r = h.state_mut().session.layout().object(&Pos::body(0, 0), 0).unwrap().rect; + let from = crate::canvas::page_to_screen(h.state_mut(), 0, r.x + r.w / 2.0, r.y + r.h / 2.0).unwrap(); + let to = crate::canvas::page_to_screen(h.state_mut(), 1, 200.0, 300.0).unwrap(); + let button = + |at: Pos2, pressed: bool| Event::PointerButton { pos: at, button: PointerButton::Primary, pressed, modifiers: Default::default() }; + h.event(Event::PointerMoved(from)); + h.event(button(from, true)); + h.step(); + for k in 1..=4 { + h.event(Event::PointerMoved(from + (to - from) * (k as f32 / 4.0))); + h.step(); + } + h.state_mut().canvas.scroll_to_caret = false; + h.event(button(to, false)); + h.step(); + h.step(); + let landed = h.state_mut().session.layout().object_at(1, 200.0, 300.0, 0.0).is_some(); + assert!(landed, "the shape landed on page 2"); + assert!(!h.state().canvas.scroll_to_caret, "the drop scrolled to the caret"); + } + /// A floating rectangle shape, `w` × `h`. fn floating_rect(w: f32, h: f32) -> InlineObject { InlineObject::Shape { diff --git a/crates/ui-egui/src/table_mouse.rs b/crates/ui-egui/src/table_mouse.rs index 8cce90d9e..4c5f8daf9 100644 --- a/crates/ui-egui/src/table_mouse.rs +++ b/crates/ui-egui/src/table_mouse.rs @@ -66,7 +66,7 @@ pub fn pointer(app: &mut WordApp, ui: &Ui, resp: &egui::Response, rects: &[Rect] // Released: a drag moves the table (one undo step), a click selects it. let moved = (d.to.0 - d.from.0).abs() >= 0.5 || (d.to.1 - d.from.1).abs() >= 0.5; let id = if moved && table_mouse::movable(&d.target.geom) { "table.moveDrag" } else { "table.selectAt" }; - if let Err(e) = app.run(id, at) { + if let Err(e) = app.run_keep_view(id, at) { app.status(e); } return true; @@ -76,7 +76,7 @@ pub fn pointer(app: &mut WordApp, ui: &Ui, resp: &egui::Response, rects: &[Rect] if down { if d.to != d.sent { d.sent = d.to; - let _ = app.run("table.selectAt", at); + let _ = app.run_keep_view("table.selectAt", at); } app.canvas.table_drag = Some(d); } else if matches!(d.target.spot, Spot::Cell(..)) @@ -95,14 +95,14 @@ pub fn pointer(app: &mut WordApp, ui: &Ui, resp: &egui::Response, rects: &[Rect] let at = json!({"page": page, "x": x, "y": y, "reach": reach}); match target.spot { Spot::InsertRow(_) | Spot::InsertColumn(_) => { - if let Err(e) = app.run("table.insertAt", at) { + if let Err(e) = app.run_keep_view("table.insertAt", at) { app.status(e); } } spot => { // A selection area selects at once; the move handle waits for the release. if spot != Spot::Handle - && let Err(e) = app.run("table.selectAt", at) + && let Err(e) = app.run_keep_view("table.selectAt", at) { app.status(e); } @@ -399,4 +399,26 @@ mod tests { assert!((moved.x - (a.x + 40.0)).abs() < 1.0 && (moved.y - (a.y + 30.0)).abs() < 1.0, "{a:?} → {moved:?}"); assert_eq!(h.state().session.undo_depth(), depth + 1); } + + /// #1738: dropping the move handle leaves the view where it is. + #[test] + fn dropping_the_move_handle_keeps_the_view_where_it_is() { + let mut h = table_window(); + let a = cell(&mut h, 0, 0); + let (hx, hy) = (a.x - 6.0, a.y - 6.0); + let start = screen(&mut h, hx, hy); + h.event(egui::Event::PointerMoved(start)); + steps(&mut h, 2); + button(&h, start, true); + h.step(); + let end = screen(&mut h, hx + 40.0, hy + 30.0); + h.event(egui::Event::PointerMoved(end)); + steps(&mut h, 2); + h.state_mut().canvas.scroll_to_caret = false; + let depth = h.state().session.undo_depth(); + button(&h, end, false); + h.step(); + assert_eq!(h.state().session.undo_depth(), depth + 1, "the table moved"); + assert!(!h.state().canvas.scroll_to_caret, "the move scrolled to the caret"); + } } diff --git a/crates/ui-egui/src/table_resize.rs b/crates/ui-egui/src/table_resize.rs index 67be6b86a..69d8d7085 100644 --- a/crates/ui-egui/src/table_resize.rs +++ b/crates/ui-egui/src/table_resize.rs @@ -133,7 +133,7 @@ pub fn pointer(app: &mut WordApp, ui: &Ui, resp: &egui::Response, rects: &[Rect] if resp.double_clicked() && matches!(d.target.edge, Edge::Column(_)) { let sc = page_scale(rects, layout, scale, d.page).unwrap_or(1.0); let params = json!({"page": d.page, "x": d.from.0, "y": d.from.1, "reach": REACH_PX / sc}); - if let Err(e) = app.run("table.fitColumn", params) { + if let Err(e) = app.run_keep_view("table.fitColumn", params) { app.status(e); } } @@ -145,7 +145,7 @@ pub fn pointer(app: &mut WordApp, ui: &Ui, resp: &egui::Response, rects: &[Rect] "page": d.page, "x": d.from.0, "y": d.from.1, "toX": d.to.0, "toY": d.to.1, "shift": share == Share::LeftOnly, "ctrl": share == Share::Proportional, "reach": REACH_PX / sc, }); - if let Err(e) = app.run("table.resizeDrag", params) { + if let Err(e) = app.run_keep_view("table.resizeDrag", params) { app.status(e); } return true; @@ -380,6 +380,30 @@ pub(crate) mod tests { assert_eq!(cell(&mut h, 0, 0), a); } + /// #1738: releasing a column-border drag leaves the view where it is, not scrolled back to + /// the caret; typing afterwards still follows the caret. + #[test] + fn dragging_a_column_border_keeps_the_view_where_it_is() { + let mut h = table_window(); + let a = cell(&mut h, 0, 0); + let start = screen(&mut h, a.right(), a.y + a.h / 2.0); + let end = screen(&mut h, a.right() + 30.0, a.y + a.h / 2.0); + h.event(egui::Event::PointerMoved(start)); + steps(&mut h, 2); + button(&h, start, true); + h.step(); + h.event(egui::Event::PointerMoved(end)); + steps(&mut h, 2); + h.state_mut().canvas.scroll_to_caret = false; + let depth = h.state().session.undo_depth(); + button(&h, end, false); + h.step(); + assert_eq!(h.state().session.undo_depth(), depth + 1, "the drag was applied"); + assert!(!h.state().canvas.scroll_to_caret, "the resize scrolled to the caret"); + h.state_mut().run("text.insert", json!({"text": "x"})).unwrap(); + assert!(h.state().canvas.scroll_to_caret, "typing still brings the caret into view"); + } + /// The zone of the ruler marker named `label` nearest to screen point `near`. fn ruler_marker(h: &H, label: &str, near: Pos2) -> Rect { use egui_kittest::kittest::Queryable; diff --git a/docs/ui-parity.md b/docs/ui-parity.md index c6229559c..d8db932ad 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI parity with Microsoft Word -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** trivial (numbered headings, #1793; previously trivial: Navigation Find exposes Results, #2096; previously trivial: the tab strip never draws tabs over Comments / Editing / Share, #2026; previously trivial: Columns on selected text, #2024; previously trivial: Different First Page headers reachable from page 1, #2826; previously trivial: a copied equation also goes in the clipboard's MathML formats, #1297; previously trivial: Read Mode keeps the keyboard, shows whole columns and keeps text clear of the page-turn bar, #1772); previously trivial: font list entries of tall-ascent fonts sit in their row, not cut off, #2570); previously trivial: Split Cells and Convert Text to Table dialogs follow Word's merged-cell limits and Initial column width, #2592; previously trivial: a new source's Tag is made like Word's, three letters of the author and two digits of the year with a number added when taken, and an edit keeps the Tag, #2094; previously trivial: Web Layout text fills the window width, #1876; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717)); previously trivial: comment balloons readable in the dark theme, #2045; previously trivial: Recently Used Fonts section at the top of the font list, #2068; previously trivial: web preferences kept between visits, #2132; previously trivial: dialog close control: a Windows-style box at the title bar's right end, the whole box clickable, red on hover, #1885); previously trivial (Modify Table Style formats every table style part, #714); previously trivial: a click on the ribbon chrome hands the keyboard to the page in the same frame, #1093 follow-up; previously trivial: Page Setup vertical alignment, #1320; previously trivial: the app opens on the Home tab every launch, as in Word; previously trivial: no document behind the Start screen, #1129; previously trivial: equation pictures share a few textures, #1002; previously trivial: selection bar in the left margin, #856; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously major: first version; ribbon, dialogs, shortcuts and on-canvas interaction measured from `crates/ui-egui` and the command registry) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** trivial (a mouse drag on a table leaves the view where it is, #1738; previously trivial: numbered headings, #1793; previously trivial: Navigation Find exposes Results, #2096; previously trivial: the tab strip never draws tabs over Comments / Editing / Share, #2026; previously trivial: Columns on selected text, #2024; previously trivial: Different First Page headers reachable from page 1, #2826; previously trivial: a copied equation also goes in the clipboard's MathML formats, #1297; previously trivial: Read Mode keeps the keyboard, shows whole columns and keeps text clear of the page-turn bar, #1772); previously trivial: font list entries of tall-ascent fonts sit in their row, not cut off, #2570); previously trivial: Split Cells and Convert Text to Table dialogs follow Word's merged-cell limits and Initial column width, #2592; previously trivial: a new source's Tag is made like Word's, three letters of the author and two digits of the year with a number added when taken, and an edit keeps the Tag, #2094; previously trivial: Web Layout text fills the window width, #1876; previously trivial: Language dialog keeps inherited proofing language and no-proof choices (#2717)); previously trivial: comment balloons readable in the dark theme, #2045; previously trivial: Recently Used Fonts section at the top of the font list, #2068; previously trivial: web preferences kept between visits, #2132; previously trivial: dialog close control: a Windows-style box at the title bar's right end, the whole box clickable, red on hover, #1885); previously trivial (Modify Table Style formats every table style part, #714); previously trivial: a click on the ribbon chrome hands the keyboard to the page in the same frame, #1093 follow-up; previously trivial: Page Setup vertical alignment, #1320; previously trivial: the app opens on the Home tab every launch, as in Word; previously trivial: no document behind the Start screen, #1129; previously trivial: equation pictures share a few textures, #1002; previously trivial: selection bar in the left margin, #856; previously trivial: table column and row markers on the rulers, #700; previously trivial: table borders and the resize handle drag on the page, #217; previously major: first version; ribbon, dialogs, shortcuts and on-canvas interaction measured from `crates/ui-egui` and the command registry) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4 How WordCraft looks and feels next to Word: ribbon, dialogs, panes, keyboard, mouse and touch. Typing behaviour has its own checklist ([`typing-parity.md`](typing-parity.md)). All assets are our @@ -83,6 +83,7 @@ Find selects the Results tab, including when it prefills selected text. Editing | 2026-10-16 | trivial | Multilevel List heading presets: every selected paragraph takes the first level (Heading 1), as Word for Mac does; headings outside the selection keep their styles and levels (#1793) | | 2026-10-16 | trivial | Multilevel List heading presets: selected paragraphs already in a Heading style keep their style and level, every other selected paragraph becomes Heading 1, as Word for Mac does (#1793) | | 2026-10-15 | trivial | Multilevel List gallery: four lists linked to Heading 1–9 (1 / 1.1 / 1.1.1; Article I. / Section 1.01 / (a); I. / A. / 1.; Chapter 1), `list.multilevelPreset`; headings keep their styles and new headings are numbered (#1793). Style gallery previews don't show the numbers yet | +| 2026-10-16 | trivial | A mouse drag that edits a table (column or row border, move handle) leaves the view where it is; typing still follows the caret (#1738) | | 2026-10-13 | trivial | New/Modify Table Style: No Border on a part that inherits its lines hides them; emptying the font box makes the part's font inherited again (#1288) | | 2026-10-14 | trivial | Tab stops edited on the ruler: corner kind selector, click to set, drag to move or off to clear, per-kind markers mirrored for RTL; each gesture one `para.tabs` call and one undo step; Rulers 85% → 90% | | 2026-10-12 | trivial | Tables on the page: one selected cell (Select Cell, or a click along its left edge) is a cell selection when its border is dragged: the border moves in its row only (#962) |