@sametalmdr/word-editor 0.2.0-alpha → 0.3.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +108 -70
  2. package/LICENSE +21 -21
  3. package/README.md +286 -247
  4. package/dist/canvas/box-clipboard.js +238 -238
  5. package/dist/canvas/box-selection.js +80 -80
  6. package/dist/canvas/canvas-editor.js +502 -502
  7. package/dist/canvas/controller.js +717 -717
  8. package/dist/canvas/geometry.js +131 -131
  9. package/dist/canvas/gesture.d.ts +0 -1
  10. package/dist/canvas/gesture.js +289 -289
  11. package/dist/canvas/handles.js +212 -212
  12. package/dist/canvas/menu.js +82 -82
  13. package/dist/canvas/mode-controller.js +81 -81
  14. package/dist/canvas/nudge.js +108 -108
  15. package/dist/canvas/overlay.js +149 -149
  16. package/dist/canvas/snap.js +132 -132
  17. package/dist/canvas/viewport.js +112 -112
  18. package/dist/canvas/z-order.js +171 -171
  19. package/dist/commands/alignment.js +150 -150
  20. package/dist/commands/box.js +272 -272
  21. package/dist/commands/clipboard.js +93 -93
  22. package/dist/commands/graphemes.js +112 -112
  23. package/dist/commands/marks.js +153 -153
  24. package/dist/commands/paragraph-props.js +176 -176
  25. package/dist/commands/size.js +368 -368
  26. package/dist/commands/text.js +291 -291
  27. package/dist/docx.d.ts +1 -0
  28. package/dist/docx.js +15 -13
  29. package/dist/editor/editing-host.js +434 -434
  30. package/dist/element.js +41 -41
  31. package/dist/fonts/OFL-Carlito.txt +94 -0
  32. package/dist/fonts/calibri-metrics.d.ts +27 -0
  33. package/dist/fonts/calibri-metrics.js +88 -0
  34. package/dist/history/history.js +433 -433
  35. package/dist/index.js +63 -63
  36. package/dist/input/beforeinput.js +224 -224
  37. package/dist/input/clipboard.js +107 -107
  38. package/dist/input/composition.js +341 -341
  39. package/dist/input/keymap.js +54 -54
  40. package/dist/io/ooxml/custgeom.js +72 -72
  41. package/dist/io/ooxml/drawingml.js +232 -232
  42. package/dist/io/ooxml/edits.js +67 -67
  43. package/dist/io/ooxml/export-splice.js +880 -880
  44. package/dist/io/ooxml/export.js +365 -365
  45. package/dist/io/ooxml/fill.d.ts +93 -8
  46. package/dist/io/ooxml/fill.js +618 -562
  47. package/dist/io/ooxml/fit.d.ts +252 -0
  48. package/dist/io/ooxml/fit.js +598 -0
  49. package/dist/io/ooxml/import-gate.js +200 -200
  50. package/dist/io/ooxml/import.js +691 -691
  51. package/dist/io/ooxml/inflate.js +126 -126
  52. package/dist/io/ooxml/media.js +87 -87
  53. package/dist/io/ooxml/ns.d.ts +2 -0
  54. package/dist/io/ooxml/ns.js +26 -21
  55. package/dist/io/ooxml/numbering.js +290 -290
  56. package/dist/io/ooxml/opc-write.js +171 -171
  57. package/dist/io/ooxml/provenance.js +93 -93
  58. package/dist/io/ooxml/recipe.js +708 -708
  59. package/dist/io/ooxml/relationships.js +59 -59
  60. package/dist/io/ooxml/run-fonts.d.ts +89 -0
  61. package/dist/io/ooxml/run-fonts.js +378 -0
  62. package/dist/io/ooxml/slots.d.ts +4 -0
  63. package/dist/io/ooxml/slots.js +582 -581
  64. package/dist/io/ooxml/styles-resolve.js +257 -257
  65. package/dist/io/ooxml/units.js +43 -43
  66. package/dist/io/ooxml/value.js +120 -120
  67. package/dist/io/ooxml/xml-scan.js +616 -616
  68. package/dist/io/ooxml/zip-container.js +228 -228
  69. package/dist/io/ooxml/zip-reject.js +106 -106
  70. package/dist/measure/placement.js +83 -83
  71. package/dist/measure/report.js +75 -75
  72. package/dist/model/ids.js +70 -70
  73. package/dist/model/normalize.js +146 -146
  74. package/dist/model/position.js +283 -283
  75. package/dist/model/transaction.js +209 -209
  76. package/dist/platform/capabilities.js +25 -25
  77. package/dist/react/index.js +21 -21
  78. package/dist/selection/controller.js +315 -315
  79. package/dist/selection/dom-map.js +334 -334
  80. package/dist/state/editor-state.js +109 -109
  81. package/dist/styles.css +66 -66
  82. package/package.json +94 -93
@@ -1,81 +1,81 @@
1
- // The box-mode <-> text-mode state machine for the unified canvas editor
2
- // (ADR-0024, P3b mode-merge parça 1). It owns ONLY the mode state and its two
3
- // transitions. Deliberately inert otherwise: it listens to NO DOM events (parça
4
- // 3's click-router calls enterTextMode/exitToBoxMode), and touches NO model, NO
5
- // renderer, NO editing. SelectionController and the future click-router only
6
- // READ `mode`; nothing writes it except the two methods here.
7
- //
8
- // - box mode (initial): a single click selects/moves a box (CanvasController).
9
- // - text mode: a caret lives in one box; typing edits it (editing assembly).
10
- //
11
- // Double-click a box enters text mode on it; Esc — or a single click on another
12
- // box / outside — returns to box mode (ADR-0024 §1). Those DOM triggers are
13
- // parça 3's job; here they are just the two methods those handlers will call.
14
-
15
- /** @typedef {"box" | "text"} Mode */
16
-
17
- export class ModeController {
18
- /**
19
- * @param {object} [options]
20
- * @param {(mode: Mode, activeContainerId: import("../model/node.js").NodeId | null) => void} [options.onChange]
21
- * Fired after every REAL transition (never on a no-op). Omitted -> no observer.
22
- */
23
- constructor({ onChange } = {}) {
24
- /** @type {Mode} */
25
- this._mode = "box";
26
- /** @type {import("../model/node.js").NodeId | null} */
27
- this._activeContainerId = null;
28
- this._onChange = onChange ?? null;
29
- }
30
-
31
- /** @returns {Mode} */
32
- get mode() {
33
- return this._mode;
34
- }
35
-
36
- /**
37
- * The box currently in text mode, or null in box mode.
38
- * @returns {import("../model/node.js").NodeId | null}
39
- */
40
- get activeContainerId() {
41
- return this._activeContainerId;
42
- }
43
-
44
- /**
45
- * box -> text on `containerId` (a double-click on a box, ADR-0024). Also
46
- * switches the active box when already in text mode on a DIFFERENT one
47
- * (double-click box B while editing box A). A no-op — no `onChange` — when
48
- * already in text mode on the SAME box.
49
- * @param {import("../model/node.js").NodeId} containerId
50
- * @returns {void}
51
- */
52
- enterTextMode(containerId) {
53
- if (this._mode === "text" && this._activeContainerId === containerId) {
54
- return;
55
- }
56
- this._mode = "text";
57
- this._activeContainerId = containerId;
58
- this._emit();
59
- }
60
-
61
- /**
62
- * text -> box (Esc, or a single click on another box / outside — ADR-0024).
63
- * A no-op — no `onChange` — when already in box mode.
64
- * @returns {void}
65
- */
66
- exitToBoxMode() {
67
- if (this._mode === "box") {
68
- return;
69
- }
70
- this._mode = "box";
71
- this._activeContainerId = null;
72
- this._emit();
73
- }
74
-
75
- /** @returns {void} */
76
- _emit() {
77
- if (this._onChange !== null) {
78
- this._onChange(this._mode, this._activeContainerId);
79
- }
80
- }
81
- }
1
+ // The box-mode <-> text-mode state machine for the unified canvas editor
2
+ // (ADR-0024, P3b mode-merge parça 1). It owns ONLY the mode state and its two
3
+ // transitions. Deliberately inert otherwise: it listens to NO DOM events (parça
4
+ // 3's click-router calls enterTextMode/exitToBoxMode), and touches NO model, NO
5
+ // renderer, NO editing. SelectionController and the future click-router only
6
+ // READ `mode`; nothing writes it except the two methods here.
7
+ //
8
+ // - box mode (initial): a single click selects/moves a box (CanvasController).
9
+ // - text mode: a caret lives in one box; typing edits it (editing assembly).
10
+ //
11
+ // Double-click a box enters text mode on it; Esc — or a single click on another
12
+ // box / outside — returns to box mode (ADR-0024 §1). Those DOM triggers are
13
+ // parça 3's job; here they are just the two methods those handlers will call.
14
+
15
+ /** @typedef {"box" | "text"} Mode */
16
+
17
+ export class ModeController {
18
+ /**
19
+ * @param {object} [options]
20
+ * @param {(mode: Mode, activeContainerId: import("../model/node.js").NodeId | null) => void} [options.onChange]
21
+ * Fired after every REAL transition (never on a no-op). Omitted -> no observer.
22
+ */
23
+ constructor({ onChange } = {}) {
24
+ /** @type {Mode} */
25
+ this._mode = "box";
26
+ /** @type {import("../model/node.js").NodeId | null} */
27
+ this._activeContainerId = null;
28
+ this._onChange = onChange ?? null;
29
+ }
30
+
31
+ /** @returns {Mode} */
32
+ get mode() {
33
+ return this._mode;
34
+ }
35
+
36
+ /**
37
+ * The box currently in text mode, or null in box mode.
38
+ * @returns {import("../model/node.js").NodeId | null}
39
+ */
40
+ get activeContainerId() {
41
+ return this._activeContainerId;
42
+ }
43
+
44
+ /**
45
+ * box -> text on `containerId` (a double-click on a box, ADR-0024). Also
46
+ * switches the active box when already in text mode on a DIFFERENT one
47
+ * (double-click box B while editing box A). A no-op — no `onChange` — when
48
+ * already in text mode on the SAME box.
49
+ * @param {import("../model/node.js").NodeId} containerId
50
+ * @returns {void}
51
+ */
52
+ enterTextMode(containerId) {
53
+ if (this._mode === "text" && this._activeContainerId === containerId) {
54
+ return;
55
+ }
56
+ this._mode = "text";
57
+ this._activeContainerId = containerId;
58
+ this._emit();
59
+ }
60
+
61
+ /**
62
+ * text -> box (Esc, or a single click on another box / outside — ADR-0024).
63
+ * A no-op — no `onChange` — when already in box mode.
64
+ * @returns {void}
65
+ */
66
+ exitToBoxMode() {
67
+ if (this._mode === "box") {
68
+ return;
69
+ }
70
+ this._mode = "box";
71
+ this._activeContainerId = null;
72
+ this._emit();
73
+ }
74
+
75
+ /** @returns {void} */
76
+ _emit() {
77
+ if (this._onChange !== null) {
78
+ this._onChange(this._mode, this._activeContainerId);
79
+ }
80
+ }
81
+ }
@@ -1,108 +1,108 @@
1
- // The keyboard nudge bracket (ADR-0016 §4, measured in two engines). No
2
- // src/, DOM, or history import.
3
- //
4
- // ⚠ SENTETİK DİZİLER KANIT DEĞİL — same disclaimer as gesture.js: this
5
- // file's tests drive hand-written keydown/keyup sequences. That proves the
6
- // state machine is correct GIVEN that sequence, not that a real keyboard
7
- // produces it. The real evidence is ADR-0016's G9/G10 measurements.
8
- //
9
- // MEASURED RULES this module encodes:
10
- // - PRIMARY signal is the `repeat: true` flag, NOT a time window. Measured
11
- // reason: first-repeat delay is 501.1-562.5ms (Chrome) / 500-593ms
12
- // (Firefox) — every single measured first repeat lands 1-64ms ABOVE
13
- // `COALESCE_MS` (500), so a time-window bracket sits right on the
14
- // boundary and would jitter between one undo entry and two.
15
- // - `keyup` is NOT reliable: an orphaned keyup (no matching keydown,
16
- // key: "Tab") was observed twice in Chrome, seven times in Firefox.
17
- // - G10 (Firefox): a key's own `keyup` can arrive AFTER the NEXT key's
18
- // `keydown` (observed twice) — `keyUpSealsOpenBracket` must still
19
- // recognize it, checking only which KEY it belongs to, never assuming
20
- // arrival order.
21
- // - A `repeat: false` keydown after a focus loss always opens a NEW
22
- // bracket, even on the same key — the conservative choice (splitting
23
- // one gesture into two costs less than wrongly merging two).
24
- // - The nudge window is `idleAbandonMs`-shaped but must NEVER reuse
25
- // `COALESCE_MS` — see the first bullet. Reuses `isIdleAbandoned`
26
- // (gesture.js) rather than redefining its own copy: both brackets ask
27
- // "how long since the last event", the SAME question `Gesture` already
28
- // answers, just with a different injected threshold.
29
-
30
- /**
31
- * @typedef {object} NudgeBracket
32
- * @property {number} gestureId minted by the caller's IdFactory
33
- * @property {string} key e.g. "ArrowUp" — the physical key this bracket belongs to
34
- * @property {number} lastEventAt
35
- */
36
-
37
- /**
38
- * @typedef {object} NudgeKeyEvent
39
- * @property {"keydown" | "keyup"} type
40
- * @property {string} key
41
- * @property {boolean} [repeat] keydown only
42
- * @property {number} timestamp
43
- * @property {number} [gestureId] keydown only: pre-minted id for the bracket this event WOULD open
44
- */
45
-
46
- /**
47
- * @typedef {object} NudgePlan
48
- * @property {NudgeBracket} bracket the bracket to use for THIS keydown
49
- * @property {boolean} extend true = the SAME gesture as an already-open bracket; false = a NEW one
50
- */
51
-
52
- /**
53
- * PRIMARY signal only: `event.repeat` on the SAME key extends the existing
54
- * bracket. Anything else — a different key, `repeat: false` even on the
55
- * same key (the post-focus-loss reset case), or no bracket open at all —
56
- * opens a NEW one. Never mints its own id; `event.gestureId` is the
57
- * caller's pre-minted candidate, used only when actually needed.
58
- *
59
- * @param {NudgeBracket | null} bracket
60
- * @param {NudgeKeyEvent} event a "keydown"
61
- * @returns {NudgePlan}
62
- */
63
- export function nudgeTransition(bracket, event) {
64
- if (bracket !== null && bracket.key === event.key && event.repeat) {
65
- return { bracket: { ...bracket, lastEventAt: event.timestamp }, extend: true };
66
- }
67
- return {
68
- bracket: { gestureId: /** @type {number} */ (event.gestureId), key: event.key, lastEventAt: event.timestamp },
69
- extend: false,
70
- };
71
- }
72
-
73
- /**
74
- * Whether `event` (a "keyup") finalizes `bracket` — true purely by KEY
75
- * match, never by arrival order (G10: a key's own keyup can arrive after
76
- * the NEXT key's keydown has already opened a new bracket). Sealing is
77
- * IDEMPOTENT: calling this again for an already-finalized bracket, or for
78
- * an unmatched/orphaned keyup (G9: a keyup with no matching keydown was
79
- * observed for "Tab"), is harmless — it simply returns `false` because no
80
- * candidate bracket has that key.
81
- *
82
- * @param {NudgeBracket | null} bracket
83
- * @param {NudgeKeyEvent} event a "keyup"
84
- * @returns {boolean}
85
- */
86
- export function keyUpSealsOpenBracket(bracket, event) {
87
- return bracket !== null && bracket.key === event.key;
88
- }
89
-
90
- const KEY_DIRECTIONS = {
91
- ArrowUp: { dx: 0, dy: -1 },
92
- ArrowDown: { dx: 0, dy: 1 },
93
- ArrowLeft: { dx: -1, dy: 0 },
94
- ArrowRight: { dx: 1, dy: 0 },
95
- };
96
-
97
- /**
98
- * @param {string} key one of ArrowUp/ArrowDown/ArrowLeft/ArrowRight
99
- * @param {number} step pt — injected, no default (an unmeasured UI constant, CanvasMetrics' `nudgeStep`)
100
- * @returns {{dx: number, dy: number}}
101
- */
102
- export function nudgeDelta(key, step) {
103
- const direction = KEY_DIRECTIONS[/** @type {keyof typeof KEY_DIRECTIONS} */ (key)];
104
- if (direction === undefined) {
105
- throw new TypeError(`nudgeDelta: unknown key ${JSON.stringify(key)}`);
106
- }
107
- return { dx: direction.dx * step, dy: direction.dy * step };
108
- }
1
+ // The keyboard nudge bracket (ADR-0016 §4, measured in two engines). No
2
+ // src/, DOM, or history import.
3
+ //
4
+ // ⚠ SENTETİK DİZİLER KANIT DEĞİL — same disclaimer as gesture.js: this
5
+ // file's tests drive hand-written keydown/keyup sequences. That proves the
6
+ // state machine is correct GIVEN that sequence, not that a real keyboard
7
+ // produces it. The real evidence is ADR-0016's G9/G10 measurements.
8
+ //
9
+ // MEASURED RULES this module encodes:
10
+ // - PRIMARY signal is the `repeat: true` flag, NOT a time window. Measured
11
+ // reason: first-repeat delay is 501.1-562.5ms (Chrome) / 500-593ms
12
+ // (Firefox) — every single measured first repeat lands 1-64ms ABOVE
13
+ // `COALESCE_MS` (500), so a time-window bracket sits right on the
14
+ // boundary and would jitter between one undo entry and two.
15
+ // - `keyup` is NOT reliable: an orphaned keyup (no matching keydown,
16
+ // key: "Tab") was observed twice in Chrome, seven times in Firefox.
17
+ // - G10 (Firefox): a key's own `keyup` can arrive AFTER the NEXT key's
18
+ // `keydown` (observed twice) — `keyUpSealsOpenBracket` must still
19
+ // recognize it, checking only which KEY it belongs to, never assuming
20
+ // arrival order.
21
+ // - A `repeat: false` keydown after a focus loss always opens a NEW
22
+ // bracket, even on the same key — the conservative choice (splitting
23
+ // one gesture into two costs less than wrongly merging two).
24
+ // - The nudge window is `idleAbandonMs`-shaped but must NEVER reuse
25
+ // `COALESCE_MS` — see the first bullet. Reuses `isIdleAbandoned`
26
+ // (gesture.js) rather than redefining its own copy: both brackets ask
27
+ // "how long since the last event", the SAME question `Gesture` already
28
+ // answers, just with a different injected threshold.
29
+
30
+ /**
31
+ * @typedef {object} NudgeBracket
32
+ * @property {number} gestureId minted by the caller's IdFactory
33
+ * @property {string} key e.g. "ArrowUp" — the physical key this bracket belongs to
34
+ * @property {number} lastEventAt
35
+ */
36
+
37
+ /**
38
+ * @typedef {object} NudgeKeyEvent
39
+ * @property {"keydown" | "keyup"} type
40
+ * @property {string} key
41
+ * @property {boolean} [repeat] keydown only
42
+ * @property {number} timestamp
43
+ * @property {number} [gestureId] keydown only: pre-minted id for the bracket this event WOULD open
44
+ */
45
+
46
+ /**
47
+ * @typedef {object} NudgePlan
48
+ * @property {NudgeBracket} bracket the bracket to use for THIS keydown
49
+ * @property {boolean} extend true = the SAME gesture as an already-open bracket; false = a NEW one
50
+ */
51
+
52
+ /**
53
+ * PRIMARY signal only: `event.repeat` on the SAME key extends the existing
54
+ * bracket. Anything else — a different key, `repeat: false` even on the
55
+ * same key (the post-focus-loss reset case), or no bracket open at all —
56
+ * opens a NEW one. Never mints its own id; `event.gestureId` is the
57
+ * caller's pre-minted candidate, used only when actually needed.
58
+ *
59
+ * @param {NudgeBracket | null} bracket
60
+ * @param {NudgeKeyEvent} event a "keydown"
61
+ * @returns {NudgePlan}
62
+ */
63
+ export function nudgeTransition(bracket, event) {
64
+ if (bracket !== null && bracket.key === event.key && event.repeat) {
65
+ return { bracket: { ...bracket, lastEventAt: event.timestamp }, extend: true };
66
+ }
67
+ return {
68
+ bracket: { gestureId: /** @type {number} */ (event.gestureId), key: event.key, lastEventAt: event.timestamp },
69
+ extend: false,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Whether `event` (a "keyup") finalizes `bracket` — true purely by KEY
75
+ * match, never by arrival order (G10: a key's own keyup can arrive after
76
+ * the NEXT key's keydown has already opened a new bracket). Sealing is
77
+ * IDEMPOTENT: calling this again for an already-finalized bracket, or for
78
+ * an unmatched/orphaned keyup (G9: a keyup with no matching keydown was
79
+ * observed for "Tab"), is harmless — it simply returns `false` because no
80
+ * candidate bracket has that key.
81
+ *
82
+ * @param {NudgeBracket | null} bracket
83
+ * @param {NudgeKeyEvent} event a "keyup"
84
+ * @returns {boolean}
85
+ */
86
+ export function keyUpSealsOpenBracket(bracket, event) {
87
+ return bracket !== null && bracket.key === event.key;
88
+ }
89
+
90
+ const KEY_DIRECTIONS = {
91
+ ArrowUp: { dx: 0, dy: -1 },
92
+ ArrowDown: { dx: 0, dy: 1 },
93
+ ArrowLeft: { dx: -1, dy: 0 },
94
+ ArrowRight: { dx: 1, dy: 0 },
95
+ };
96
+
97
+ /**
98
+ * @param {string} key one of ArrowUp/ArrowDown/ArrowLeft/ArrowRight
99
+ * @param {number} step pt — injected, no default (an unmeasured UI constant, CanvasMetrics' `nudgeStep`)
100
+ * @returns {{dx: number, dy: number}}
101
+ */
102
+ export function nudgeDelta(key, step) {
103
+ const direction = KEY_DIRECTIONS[/** @type {keyof typeof KEY_DIRECTIONS} */ (key)];
104
+ if (direction === undefined) {
105
+ throw new TypeError(`nudgeDelta: unknown key ${JSON.stringify(key)}`);
106
+ }
107
+ return { dx: direction.dx * step, dy: direction.dy * step };
108
+ }