@quillmark/svelte 0.27.0 → 0.28.0

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 (95) hide show
  1. package/NOTICE +4 -4
  2. package/README.md +26 -8
  3. package/THEMING.md +10 -8
  4. package/dist/core/address.d.ts +35 -64
  5. package/dist/core/address.js +35 -55
  6. package/dist/core/bloom.d.ts +4 -10
  7. package/dist/core/bloom.js +14 -27
  8. package/dist/core/codec/blocks.d.ts +41 -43
  9. package/dist/core/codec/blocks.js +97 -130
  10. package/dist/core/codec/code.d.ts +7 -10
  11. package/dist/core/codec/code.js +37 -46
  12. package/dist/core/codec/decode.d.ts +19 -23
  13. package/dist/core/codec/decode.js +76 -111
  14. package/dist/core/codec/encode.d.ts +11 -15
  15. package/dist/core/codec/encode.js +60 -67
  16. package/dist/core/codec/field.d.ts +62 -95
  17. package/dist/core/codec/field.js +107 -179
  18. package/dist/core/codec/islands.d.ts +33 -41
  19. package/dist/core/codec/islands.js +76 -86
  20. package/dist/core/codec/lists.d.ts +17 -26
  21. package/dist/core/codec/lists.js +117 -157
  22. package/dist/core/codec/marks.d.ts +4 -3
  23. package/dist/core/codec/marks.js +8 -3
  24. package/dist/core/codec/prose.css +84 -46
  25. package/dist/core/codec/schema.d.ts +18 -23
  26. package/dist/core/codec/schema.js +84 -76
  27. package/dist/core/codec/slash.d.ts +42 -48
  28. package/dist/core/codec/slash.js +0 -0
  29. package/dist/core/codec/table-copy.d.ts +4 -3
  30. package/dist/core/codec/table-copy.js +25 -7
  31. package/dist/core/codec/table-view.d.ts +12 -12
  32. package/dist/core/codec/table-view.js +460 -383
  33. package/dist/core/codec/table.d.ts +94 -61
  34. package/dist/core/codec/table.js +331 -83
  35. package/dist/core/codec/tasks.d.ts +6 -0
  36. package/dist/core/codec/tasks.js +30 -3
  37. package/dist/core/errors.d.ts +15 -30
  38. package/dist/core/errors.js +2 -6
  39. package/dist/core/index.js +7 -12
  40. package/dist/core/lifecycle.d.ts +7 -16
  41. package/dist/core/lifecycle.js +10 -21
  42. package/dist/core/rebind.svelte.d.ts +10 -20
  43. package/dist/core/rebind.svelte.js +15 -27
  44. package/dist/core/rungs.d.ts +14 -11
  45. package/dist/core/rungs.js +17 -19
  46. package/dist/core/teardown.d.ts +4 -6
  47. package/dist/core/teardown.js +7 -10
  48. package/dist/core/theme.css +74 -54
  49. package/dist/index.js +3 -8
  50. package/dist/preset/app.css +3 -1
  51. package/dist/preset/index.css +6 -8
  52. package/dist/preset/recipes.css +12 -15
  53. package/dist/preset/scale.css +18 -17
  54. package/dist/preset/shell.css +10 -0
  55. package/dist/preview/bridge.d.ts +18 -22
  56. package/dist/preview/bridge.js +29 -58
  57. package/dist/preview/controller.d.ts +21 -29
  58. package/dist/preview/controller.js +14 -39
  59. package/dist/preview/geometry.d.ts +13 -34
  60. package/dist/preview/geometry.js +13 -34
  61. package/dist/preview/index.js +4 -16
  62. package/dist/preview/paint.d.ts +3 -3
  63. package/dist/preview/paint.js +28 -68
  64. package/dist/preview/strings.d.ts +1 -1
  65. package/dist/preview/strings.js +2 -14
  66. package/dist/preview/zoom.d.ts +18 -23
  67. package/dist/preview/zoom.js +28 -27
  68. package/dist/visual/ArrayField.svelte +77 -16
  69. package/dist/visual/BooleanField.svelte +27 -14
  70. package/dist/visual/Card.svelte +61 -48
  71. package/dist/visual/CardControls.svelte +5 -11
  72. package/dist/visual/DateField.svelte +20 -4
  73. package/dist/visual/EnumField.svelte +3 -0
  74. package/dist/visual/FieldHint.svelte +2 -1
  75. package/dist/visual/FormatPopover.svelte +82 -15
  76. package/dist/visual/FormatPopover.svelte.d.ts +4 -0
  77. package/dist/visual/MatrixAdd.svelte +30 -12
  78. package/dist/visual/MatrixField.svelte +24 -16
  79. package/dist/visual/NumberField.svelte +7 -0
  80. package/dist/visual/ObjectField.svelte +4 -4
  81. package/dist/visual/ProseField.svelte +0 -5
  82. package/dist/visual/TipsCard.svelte +11 -10
  83. package/dist/visual/VariantField.svelte +3 -1
  84. package/dist/visual/VisualEditorInner.svelte +19 -3
  85. package/dist/visual/controls.css +7 -2
  86. package/dist/visual/fonts.d.ts +18 -0
  87. package/dist/visual/fonts.js +59 -0
  88. package/dist/visual/icons/nodes.d.ts +0 -5
  89. package/dist/visual/icons/nodes.js +0 -4
  90. package/dist/visual/props.d.ts +14 -1
  91. package/dist/visual/strings.d.ts +7 -0
  92. package/dist/visual/strings.js +5 -2
  93. package/dist/visual/structure.d.ts +43 -87
  94. package/dist/visual/structure.js +42 -83
  95. package/package.json +2 -2
@@ -1,83 +1,77 @@
1
1
  import { EditorState, Plugin, type Command } from 'prosemirror-state';
2
2
  import { type EditorView } from 'prosemirror-view';
3
3
  import { type RangeAnchor } from './anchor.js';
4
- /** The menu as the chrome sees it: the command names the query matched, the keyboard's
5
- * cursor, and the trigger's anchor to hang off. `undefined` is a closed menu.
6
- *
7
- * An empty `items` is a live trigger with nothing to offer, and nothing is drawn over
8
- * it. The run is the shape of the text (a `/` at a boundary, no whitespace since) and
9
- * the menu the shape of the match; splitting the two is what lets a query typed past
10
- * the last match narrow back into one. */
4
+ /**
5
+ * The menu as the chrome sees it: the command names the query matched, the keyboard's cursor, and
6
+ * the trigger's anchor to hang off. `undefined` is a closed menu. An empty `items` is a live
7
+ * trigger with nothing to offer, drawn as nothing: the run is the shape of the text and the menu
8
+ * the shape of the match, so a query typed past the last match can narrow back into one.
9
+ */
11
10
  export interface SlashState {
12
11
  items: string[];
13
12
  index: number;
14
13
  query: string;
15
- /** The trigger's caret to hang off, live rather than measured (`anchor.ts`): an
16
- * open menu outlives any one scroll position of the leaf. */
14
+ /**
15
+ * The trigger's caret to hang off, live rather than measured (`anchor.ts`): an open menu
16
+ * outlives any one scroll position.
17
+ */
17
18
  anchor: RangeAnchor;
18
19
  }
19
- /** The menu's wording, which is its accessible name and the empty line's hint: the
20
- * offers are command names, and a name is not translated. */
20
+ /**
21
+ * The menu's wording: its accessible name and the empty line's hint. Offers are command names,
22
+ * which are not translated.
23
+ */
21
24
  export interface SlashStrings {
22
25
  slashLabel: string;
23
- /** Drawn on the empty line a focused caret holds, naming the key that opens the
24
- * menu there. */
26
+ /** Drawn on the empty line a focused caret holds, naming the key that opens the menu. */
25
27
  slashHint: string;
26
28
  }
27
- /** The package's English, beside the surface that draws it: the same rule the island
28
- * chrome's wording follows, and the visual `strings` set extends both. */
29
+ /** The package's English, beside the surface that draws it; the visual `strings` set extends it. */
29
30
  export declare const DEFAULT_SLASH_STRINGS: SlashStrings;
30
31
  /**
31
- * The vocabulary a caret can run, in menu order: the names `SLASH_COMMANDS` is keyed
32
- * by, each asked whether it would fire here. A row that declines when picked is worse
33
- * than an absent one, and asking the command rather than restating its guards is what
34
- * keeps the menu from drifting off what a pick does. So the offers narrow as the caret
35
- * moves: the lists and the island alone mid-paragraph, and at an item's head only the
36
- * list of the other kind, which retypes the item's list.
32
+ * The vocabulary a caret can run, in menu order, each name asked whether it would fire here: a row
33
+ * that declines when picked is worse than an absent one, and asking the command keeps the menu from
34
+ * drifting off what a pick does. So the offers narrow as the caret moves (the lists and the island
35
+ * alone mid-paragraph; at an item's head only the list of the other kind).
37
36
  *
38
- * `state` is the state a pick leaves behind — the run already consumed — since that is
39
- * the caret every command answers for (`blocks.ts`).
37
+ * `state` is the state a pick leaves behind, the run already consumed (`blocks.ts`).
40
38
  */
41
39
  export declare function slashItems(state: EditorState): string[];
42
- /** The query filter: a case-insensitive prefix of the name or of any of its words, which
43
- * is how a command line completes and how a two-word name stays reachable by the noun a
44
- * writer has — `/list` offers both lists. A prefix and not a substring: `note` is inside
45
- * `footnote` and completes nothing. An empty query offers everything, and the
46
- * vocabulary's order survives, so the menu never reorders under a keystroke. */
40
+ /**
41
+ * The query filter: a case-insensitive prefix of the name or of any of its words, so `/list` offers
42
+ * both lists. A prefix and not a substring (`note` is inside `footnote` and completes nothing). An
43
+ * empty query offers everything in the vocabulary's order.
44
+ */
47
45
  export declare function filterItems(items: string[], query: string): string[];
48
- /** The live trigger: where the `/` sits, what has been typed after it, and which
49
- * offer the keyboard is on. */
46
+ /**
47
+ * The live trigger: where the `/` sits, what has been typed after it, and which offer the keyboard
48
+ * is on.
49
+ */
50
50
  interface SlashRun {
51
51
  from: number;
52
52
  query: string;
53
53
  index: number;
54
54
  }
55
55
  /**
56
- * The trigger plugin. It holds the run in PM state, so every ordinary dismissal is
57
- * free: a caret move out of it, an undo, or a re-hydrate all fail the recompute
58
- * below and close the menu without a listener of their own. A dismissal edits no
59
- * text; only a pick does, and it consumes exactly the run.
56
+ * The trigger plugin. It holds the run in PM state, so a caret move out of it, an undo or a
57
+ * re-hydrate fail the recompute and close the menu without a listener. A dismissal edits no text;
58
+ * only a pick does, consuming exactly the run.
60
59
  */
61
60
  export declare function slashPlugin(onState: (state: SlashState | undefined) => void, hint?: () => string | undefined): Plugin<SlashRun | null>;
62
61
  /**
63
- * The menu's keys, the innermost link of the leaf's chain (`keymap.ts`). Every one
64
- * declines on an empty offer list rather than on a dead run (§`SlashState`): a key an
65
- * undrawn run claimed would be a key lost to a surface nobody can see. So a body with
66
- * no menu on screen keeps Enter, Escape and the arrows exactly as it had them.
67
- *
68
- * Escape is the contended key: a table gives it three claimants (this menu, the
69
- * format popover, an island selection). Innermost first, and this is the innermost
70
- * of the three that can be open over a caret in text.
62
+ * The menu's keys, the innermost link of the leaf's chain (`keymap.ts`). Every one declines on an
63
+ * empty offer list rather than a dead run (§`SlashState`), so a body with no menu on screen keeps
64
+ * Enter, Escape and the arrows as it had them. Escape has three claimants over a table (this menu,
65
+ * the format popover, an island selection); this is the innermost that can be open over a caret in
66
+ * text.
71
67
  */
72
68
  export declare function slashKeymap(): Record<string, Command>;
73
- /** Move the keyboard cursor onto `name`: what a pointer entering an item calls, so the
74
- * highlight has one lane rather than a hover painting a second one. */
69
+ /** Move the keyboard cursor onto `name` (a pointer entering an item): one highlight lane. */
75
70
  export declare function focusSlashItem(view: EditorView, name: string): void;
76
71
  /**
77
- * Run a command: one transaction that deletes the trigger run and applies the command's
78
- * own edit (`blocks.ts` §`consuming`). A command that declines consumes nothing. The
79
- * menu never picks one, offering only what would run; `slashPick` is a public seam and
80
- * can.
72
+ * Run a command: one transaction that deletes the trigger run and applies the command's edit
73
+ * (`blocks.ts` §`consuming`). A command that declines consumes nothing. The menu only offers what
74
+ * would run; `slashPick` is a public seam and can pick any.
81
75
  */
82
76
  export declare function runSlashItem(view: EditorView, name: string): void;
83
77
  export {};
Binary file
@@ -7,9 +7,10 @@ export interface CellRange {
7
7
  r1: number;
8
8
  c1: number;
9
9
  }
10
- /** The cells of `range` as a `<table>`, the header row in a `<thead>` where the range
11
- * holds it and the table has one. The cells carry their marks and breaks, and nothing
12
- * of the table's layout. */
10
+ /** The cells of `range` as a `<table>`, the header rows in a `<thead>` where the range
11
+ * holds them. The cells carry their marks, breaks and spans, a span cut to the range,
12
+ * and nothing else of the table's layout. A slot a merged cell in the range covers
13
+ * draws nothing; one whose cell starts outside the range draws empty. */
13
14
  export declare function tableElement(props: TableProps, range?: CellRange): HTMLTableElement;
14
15
  /** The cells of `range` as tab-separated text, a line a row. */
15
16
  export declare function tableText(props: TableProps, range?: CellRange): string;
@@ -8,7 +8,7 @@ import { Plugin } from 'prosemirror-state';
8
8
  import { decode } from './decode.js';
9
9
  import { tablePropsOfNode } from './islands.js';
10
10
  import { blockSchema, cellSchema } from './schema.js';
11
- import { cellAt, cellContent, columnCount, rowCount } from './table.js';
11
+ import { anchorAt, cellAt, cellContent, columnCount, headRows, rowCount, spanGrid } from './table.js';
12
12
  const whole = (props) => ({
13
13
  r0: 0,
14
14
  c0: 0,
@@ -23,18 +23,36 @@ function cellDOM(tag, cell) {
23
23
  dom.append(cellSerializer.serializeFragment(paragraph.content));
24
24
  return dom;
25
25
  }
26
- /** The cells of `range` as a `<table>`, the header row in a `<thead>` where the range
27
- * holds it and the table has one. The cells carry their marks and breaks, and nothing
28
- * of the table's layout. */
26
+ /** The cells of `range` as a `<table>`, the header rows in a `<thead>` where the range
27
+ * holds them. The cells carry their marks, breaks and spans, a span cut to the range,
28
+ * and nothing else of the table's layout. A slot a merged cell in the range covers
29
+ * draws nothing; one whose cell starts outside the range draws empty. */
29
30
  export function tableElement(props, range = whole(props)) {
30
31
  const table = document.createElement('table');
32
+ const grid = spanGrid(props);
31
33
  let body;
32
34
  for (let r = range.r0; r <= range.r1; r++) {
33
- const head = r === 0 && !props.headless;
35
+ const head = r < headRows(props);
34
36
  const section = head ? table.createTHead() : (body ??= table.createTBody());
35
37
  const tr = section.insertRow();
36
- for (let c = range.c0; c <= range.c1; c++)
37
- tr.append(cellDOM(head ? 'th' : 'td', cellAt(props, r, c)));
38
+ for (let c = range.c0; c <= range.c1; c++) {
39
+ const tag = head ? 'th' : 'td';
40
+ const at = anchorAt(grid, r, c);
41
+ if (at.r < range.r0 || at.c < range.c0) {
42
+ tr.append(cellDOM(tag, { text: '', marks: [] }));
43
+ continue;
44
+ }
45
+ if (at.r !== r || at.c !== c)
46
+ continue;
47
+ const dom = cellDOM(tag, cellAt(props, r, c));
48
+ const colspan = Math.min(at.span.colspan, range.c1 - c + 1);
49
+ const rowspan = Math.min(at.span.rowspan, range.r1 - r + 1);
50
+ if (colspan > 1)
51
+ dom.setAttribute('colspan', String(colspan));
52
+ if (rowspan > 1)
53
+ dom.setAttribute('rowspan', String(rowspan));
54
+ tr.append(dom);
55
+ }
38
56
  }
39
57
  return table;
40
58
  }
@@ -27,28 +27,28 @@ export interface TableChromeStrings {
27
27
  tableAlignRight: string;
28
28
  /** The held first row's toggle, pressed while the row draws as the header. */
29
29
  tableHeaderToggle: string;
30
+ /** The held cells' cluster: one cell from the block, and the merged cells in it back
31
+ * to the cells under them. */
32
+ tableMergeCells: string;
33
+ tableSplitCell: string;
30
34
  }
31
35
  /**
32
- * The package's English for the island chrome. It lives here, beside the surface
33
- * that draws it, rather than in the visual tier's table: the codec mounts this
34
- * chrome and a consumer reaching `createField` directly gets wording with it. The
35
- * visual `strings` set extends this one, so a consumer overrides these keys beside
36
- * every other key and there is still one English list.
36
+ * The package's English for the island chrome. It lives beside the surface that draws it so a
37
+ * consumer reaching `createField` directly gets wording; the visual `strings` set extends it.
37
38
  */
38
39
  export declare const DEFAULT_TABLE_STRINGS: TableChromeStrings;
39
40
  /** What the field hands each island view: its wording (read live, so a locale swap
40
41
  * re-renders) and the callbacks that keep a nested view visible to the leaf. */
41
42
  export interface TableViewDeps {
42
43
  strings: () => TableChromeStrings;
43
- /** Register a mounted cell view; the returned function unregisters it. The field
44
- * needs the set to answer "which view holds the caret" for the format popover. */
44
+ /** Register a mounted cell view; the returned function unregisters it. */
45
45
  register: (view: EditorView) => () => void;
46
- /** A cell took focus: the leaf's own `focus` handler never fires for one (a focus
47
- * event does not bubble), so the active address would not follow the caret. */
46
+ /** A cell took focus; a focus event does not bubble to the leaf's own handler. */
48
47
  onCellFocus: () => void;
49
- /** The clearance a revealed caret keeps, in the leaf's own line box (`field.ts`), which
50
- * is a cell's line box too. `undefined` where the derivation is out of reach (jsdom),
51
- * which is PM's 5px default. */
48
+ /**
49
+ * The clearance a revealed caret keeps; `undefined` where the derivation is out of reach
50
+ * (jsdom).
51
+ */
52
52
  clearance: number | undefined;
53
53
  }
54
54
  /** The table island mounted at `pos` in `view`, which a caret can step into; `undefined`