mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-24 10:27:44 -06:00
* Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
co-authored by
Dmitrii Khlapov
Brandon Thomas
parent
0254f3afc7
commit
559f16601d
+2
-1
@@ -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. |
|
||||
|
||||
@@ -45,6 +45,9 @@ pub struct CanvasState {
|
||||
/// revision: finding out walks every paragraph, too slow for every frame (#811).
|
||||
markup_facts: std::cell::Cell<Option<((u64, u64), [bool; 3])>>,
|
||||
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(),
|
||||
|
||||
@@ -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<Value, String> {
|
||||
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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+2
-1
@@ -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) |
|
||||
|
||||
Reference in New Issue
Block a user