@quillmark/svelte 0.0.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 (143) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +58 -0
  3. package/README.md +241 -0
  4. package/THEMING.md +153 -0
  5. package/dist/core/address.d.ts +56 -0
  6. package/dist/core/address.js +95 -0
  7. package/dist/core/bloom.d.ts +37 -0
  8. package/dist/core/bloom.js +116 -0
  9. package/dist/core/codec/anchor.d.ts +19 -0
  10. package/dist/core/codec/anchor.js +36 -0
  11. package/dist/core/codec/code.d.ts +12 -0
  12. package/dist/core/codec/code.js +118 -0
  13. package/dist/core/codec/decode.d.ts +24 -0
  14. package/dist/core/codec/decode.js +270 -0
  15. package/dist/core/codec/encode.d.ts +71 -0
  16. package/dist/core/codec/encode.js +480 -0
  17. package/dist/core/codec/field.d.ts +171 -0
  18. package/dist/core/codec/field.js +493 -0
  19. package/dist/core/codec/index.d.ts +22 -0
  20. package/dist/core/codec/index.js +43 -0
  21. package/dist/core/codec/inputrules.d.ts +7 -0
  22. package/dist/core/codec/inputrules.js +168 -0
  23. package/dist/core/codec/islands.d.ts +36 -0
  24. package/dist/core/codec/islands.js +82 -0
  25. package/dist/core/codec/keymap.d.ts +13 -0
  26. package/dist/core/codec/keymap.js +29 -0
  27. package/dist/core/codec/lists.d.ts +22 -0
  28. package/dist/core/codec/lists.js +104 -0
  29. package/dist/core/codec/marks.d.ts +37 -0
  30. package/dist/core/codec/marks.js +74 -0
  31. package/dist/core/codec/positions.d.ts +17 -0
  32. package/dist/core/codec/positions.js +108 -0
  33. package/dist/core/codec/prose.css +458 -0
  34. package/dist/core/codec/reconcile.d.ts +26 -0
  35. package/dist/core/codec/reconcile.js +64 -0
  36. package/dist/core/codec/schema.d.ts +13 -0
  37. package/dist/core/codec/schema.js +155 -0
  38. package/dist/core/codec/slash.d.ts +79 -0
  39. package/dist/core/codec/slash.js +0 -0
  40. package/dist/core/codec/table-view.d.ts +50 -0
  41. package/dist/core/codec/table-view.js +928 -0
  42. package/dist/core/codec/table.d.ts +85 -0
  43. package/dist/core/codec/table.js +224 -0
  44. package/dist/core/errors.d.ts +73 -0
  45. package/dist/core/errors.js +24 -0
  46. package/dist/core/index.d.ts +5 -0
  47. package/dist/core/index.js +19 -0
  48. package/dist/core/lifecycle.d.ts +7 -0
  49. package/dist/core/lifecycle.js +21 -0
  50. package/dist/core/rebind.svelte.d.ts +18 -0
  51. package/dist/core/rebind.svelte.js +44 -0
  52. package/dist/core/teardown.d.ts +20 -0
  53. package/dist/core/teardown.js +37 -0
  54. package/dist/core/theme.css +276 -0
  55. package/dist/index.d.ts +1 -0
  56. package/dist/index.js +9 -0
  57. package/dist/preset/index.css +10 -0
  58. package/dist/preset/recipes.css +188 -0
  59. package/dist/preset/scale.css +97 -0
  60. package/dist/preview/Preview.svelte +118 -0
  61. package/dist/preview/Preview.svelte.d.ts +39 -0
  62. package/dist/preview/bridge.d.ts +13 -0
  63. package/dist/preview/bridge.js +88 -0
  64. package/dist/preview/controller.d.ts +40 -0
  65. package/dist/preview/controller.js +141 -0
  66. package/dist/preview/geometry.d.ts +37 -0
  67. package/dist/preview/geometry.js +45 -0
  68. package/dist/preview/index.d.ts +5 -0
  69. package/dist/preview/index.js +14 -0
  70. package/dist/preview/overlay.d.ts +10 -0
  71. package/dist/preview/overlay.js +82 -0
  72. package/dist/preview/paint.d.ts +17 -0
  73. package/dist/preview/paint.js +262 -0
  74. package/dist/preview/strings.d.ts +14 -0
  75. package/dist/preview/strings.js +22 -0
  76. package/dist/visual/ArrayField.svelte +362 -0
  77. package/dist/visual/ArrayField.svelte.d.ts +24 -0
  78. package/dist/visual/BooleanField.svelte +88 -0
  79. package/dist/visual/BooleanField.svelte.d.ts +20 -0
  80. package/dist/visual/Card.svelte +849 -0
  81. package/dist/visual/Card.svelte.d.ts +43 -0
  82. package/dist/visual/CardControls.svelte +92 -0
  83. package/dist/visual/CardControls.svelte.d.ts +11 -0
  84. package/dist/visual/DateField.svelte +203 -0
  85. package/dist/visual/DateField.svelte.d.ts +28 -0
  86. package/dist/visual/DiagnosticList.svelte +50 -0
  87. package/dist/visual/DiagnosticList.svelte.d.ts +7 -0
  88. package/dist/visual/EnumField.svelte +169 -0
  89. package/dist/visual/EnumField.svelte.d.ts +25 -0
  90. package/dist/visual/Field.svelte +270 -0
  91. package/dist/visual/Field.svelte.d.ts +37 -0
  92. package/dist/visual/FieldHint.svelte +185 -0
  93. package/dist/visual/FieldHint.svelte.d.ts +13 -0
  94. package/dist/visual/FieldLabel.svelte +141 -0
  95. package/dist/visual/FieldLabel.svelte.d.ts +19 -0
  96. package/dist/visual/FormatPopover.svelte +396 -0
  97. package/dist/visual/FormatPopover.svelte.d.ts +9 -0
  98. package/dist/visual/NumberField.svelte +72 -0
  99. package/dist/visual/NumberField.svelte.d.ts +19 -0
  100. package/dist/visual/ObjectField.svelte +131 -0
  101. package/dist/visual/ObjectField.svelte.d.ts +17 -0
  102. package/dist/visual/ProseArrayElement.svelte +98 -0
  103. package/dist/visual/ProseArrayElement.svelte.d.ts +19 -0
  104. package/dist/visual/ProseField.svelte +213 -0
  105. package/dist/visual/ProseField.svelte.d.ts +50 -0
  106. package/dist/visual/SlashMenu.svelte +126 -0
  107. package/dist/visual/SlashMenu.svelte.d.ts +14 -0
  108. package/dist/visual/TextField.svelte +63 -0
  109. package/dist/visual/TextField.svelte.d.ts +23 -0
  110. package/dist/visual/TipsCard.svelte +191 -0
  111. package/dist/visual/TipsCard.svelte.d.ts +13 -0
  112. package/dist/visual/VisualEditor.svelte +96 -0
  113. package/dist/visual/VisualEditor.svelte.d.ts +14 -0
  114. package/dist/visual/VisualEditorInner.svelte +1032 -0
  115. package/dist/visual/VisualEditorInner.svelte.d.ts +17 -0
  116. package/dist/visual/controls.css +272 -0
  117. package/dist/visual/diagnostics.d.ts +52 -0
  118. package/dist/visual/diagnostics.js +83 -0
  119. package/dist/visual/domid.d.ts +21 -0
  120. package/dist/visual/domid.js +36 -0
  121. package/dist/visual/ext.d.ts +19 -0
  122. package/dist/visual/ext.js +29 -0
  123. package/dist/visual/icons/Icon.svelte +39 -0
  124. package/dist/visual/icons/Icon.svelte.d.ts +12 -0
  125. package/dist/visual/icons/nodes.d.ts +103 -0
  126. package/dist/visual/icons/nodes.js +55 -0
  127. package/dist/visual/index.d.ts +9 -0
  128. package/dist/visual/index.js +24 -0
  129. package/dist/visual/motion.d.ts +18 -0
  130. package/dist/visual/motion.js +53 -0
  131. package/dist/visual/props.d.ts +77 -0
  132. package/dist/visual/props.js +1 -0
  133. package/dist/visual/signals.d.ts +59 -0
  134. package/dist/visual/signals.js +1 -0
  135. package/dist/visual/strings.d.ts +123 -0
  136. package/dist/visual/strings.js +80 -0
  137. package/dist/visual/structure.d.ts +224 -0
  138. package/dist/visual/structure.js +270 -0
  139. package/dist/visual/synced.svelte.d.ts +15 -0
  140. package/dist/visual/synced.svelte.js +34 -0
  141. package/dist/visual/tips.d.ts +24 -0
  142. package/dist/visual/tips.js +50 -0
  143. package/package.json +102 -0
@@ -0,0 +1,155 @@
1
+ // The PM schema: the codec OWNS it; decode/encode target it. Nodes mirror the
2
+ // content block kinds (para/heading/code/rule/island) and its container nesting
3
+ // (list_item/quote → lists/blockquote); marks mirror the content formatting set.
4
+ // Each of the three open sets gets an inert carrier so an unrecognized value
5
+ // survives a round-trip: the `unknown` mark, the paragraph's `unknown` attribute,
6
+ // and the `unknown_container` node. `blockSchema` is the full field; `inlineSchema`
7
+ // is the constrained single-textblock form for `richtext(inline)` / `plaintext`
8
+ // (one paragraph, no block split, no containers, no islands): same decode/lower/
9
+ // position machinery, narrower shape. Anchors are NOT marks here (decorations).
10
+ import { Schema } from 'prosemirror-model';
11
+ import { islandBlockSpec, islandInlineSpec } from './islands.js';
12
+ // ── Marks (shared by both schemas; plaintext mounts none) ───────────────────
13
+ const marks = {
14
+ // Order matters: it fixes mark-set sort order and parse precedence. `link`
15
+ // last so it wraps outermost; `unknown` after it, non-exclusive so several
16
+ // distinct unknown marks coexist on one range.
17
+ strong: { parseDOM: [{ tag: 'strong' }, { tag: 'b' }], toDOM: () => ['strong', 0] },
18
+ em: { parseDOM: [{ tag: 'em' }, { tag: 'i' }], toDOM: () => ['em', 0] },
19
+ underline: { parseDOM: [{ tag: 'u' }], toDOM: () => ['u', 0] },
20
+ strike: { parseDOM: [{ tag: 's' }, { tag: 'del' }], toDOM: () => ['s', 0] },
21
+ code: { parseDOM: [{ tag: 'code' }], toDOM: () => ['code', 0] },
22
+ link: {
23
+ attrs: { href: { default: '' } },
24
+ inclusive: false,
25
+ parseDOM: [
26
+ { tag: 'a[href]', getAttrs: (el) => ({ href: el.getAttribute('href') }) }
27
+ ],
28
+ toDOM: (mark) => ['a', { href: mark.attrs.href }, 0]
29
+ },
30
+ // The open-set escape hatch: an inert mark that renders as a bare span and
31
+ // re-emits its stored `type`/`attrs` on encode. `excludes: ''` lets marks of
32
+ // this type with different attrs share a range (they are distinct families).
33
+ unknown: {
34
+ attrs: { type: { default: '' }, attrs: { default: null } },
35
+ excludes: '',
36
+ toDOM: () => ['span', { 'data-unknown': '' }, 0]
37
+ }
38
+ };
39
+ // ── Block nodes ─────────────────────────────────────────────────────────────
40
+ const blockNodes = {
41
+ doc: { content: 'block+' },
42
+ // `unknown` carries a line `kind` this build does not know (`{ kind, attrs }`,
43
+ // else null). A paragraph IS how such a line renders, so the carrier is an
44
+ // attribute rather than a node type: every paragraph command already reaches it,
45
+ // and retyping it to a heading or a list drops the attribute: an explicit
46
+ // conversion, which is the one place the unknown kind SHOULD be lost.
47
+ paragraph: {
48
+ content: 'inline*',
49
+ group: 'block',
50
+ attrs: { unknown: { default: null } },
51
+ parseDOM: [{ tag: 'p' }],
52
+ toDOM: (node) => {
53
+ const u = node.attrs.unknown;
54
+ return u ? ['p', { 'data-qm-unknown-line': u.kind }, 0] : ['p', 0];
55
+ }
56
+ },
57
+ heading: {
58
+ content: 'inline*',
59
+ group: 'block',
60
+ defining: true,
61
+ attrs: { level: { default: 1 } },
62
+ parseDOM: [1, 2, 3, 4, 5, 6].map((level) => ({ tag: `h${level}`, attrs: { level } })),
63
+ toDOM: (node) => [`h${node.attrs.level}`, 0]
64
+ },
65
+ code_block: {
66
+ content: 'text*',
67
+ group: 'block',
68
+ code: true,
69
+ defining: true,
70
+ marks: '',
71
+ whitespace: 'pre',
72
+ attrs: { lang: { default: null } },
73
+ parseDOM: [{ tag: 'pre', preserveWhitespace: 'full' }],
74
+ toDOM: (node) => [
75
+ 'pre',
76
+ node.attrs.lang ? { 'data-lang': node.attrs.lang } : {},
77
+ ['code', 0]
78
+ ]
79
+ },
80
+ blockquote: {
81
+ content: 'block+',
82
+ group: 'block',
83
+ defining: true,
84
+ parseDOM: [{ tag: 'blockquote' }],
85
+ toDOM: () => ['blockquote', 0]
86
+ },
87
+ horizontal_rule: { group: 'block', parseDOM: [{ tag: 'hr' }], toDOM: () => ['hr'] },
88
+ ordered_list: {
89
+ content: 'list_item+',
90
+ group: 'block',
91
+ attrs: { start: { default: 1 } },
92
+ parseDOM: [{ tag: 'ol' }],
93
+ toDOM: (node) => node.attrs.start === 1 ? ['ol', 0] : ['ol', { start: node.attrs.start }, 0]
94
+ },
95
+ bullet_list: {
96
+ content: 'list_item+',
97
+ group: 'block',
98
+ parseDOM: [{ tag: 'ul' }],
99
+ toDOM: () => ['ul', 0]
100
+ },
101
+ list_item: {
102
+ content: 'block+',
103
+ defining: true,
104
+ parseDOM: [{ tag: 'li' }],
105
+ toDOM: () => ['li', 0]
106
+ },
107
+ // A container this build does not know: a transparent wrapper that renders as a
108
+ // bare block (its children flow at the enclosing level, which is how upstream
109
+ // renders it) and re-emits its `container`/`attrs` on encode. `defining` so a
110
+ // lift out of it is deliberate rather than a backspace away.
111
+ unknown_container: {
112
+ content: 'block+',
113
+ group: 'block',
114
+ defining: true,
115
+ attrs: { container: { default: '' }, attrs: { default: null } },
116
+ toDOM: (node) => ['div', { 'data-qm-unknown-container': node.attrs.container }, 0]
117
+ },
118
+ island_block: islandBlockSpec
119
+ };
120
+ // ── Inline nodes ────────────────────────────────────────────────────────────
121
+ const inlineLeafNodes = {
122
+ text: { group: 'inline' },
123
+ hard_break: {
124
+ inline: true,
125
+ group: 'inline',
126
+ selectable: false,
127
+ parseDOM: [{ tag: 'br' }],
128
+ toDOM: () => ['br']
129
+ },
130
+ island_inline: islandInlineSpec
131
+ };
132
+ /** The full field schema: every block kind, container, mark, and island. */
133
+ export const blockSchema = new Schema({
134
+ nodes: { ...blockNodes, ...inlineLeafNodes },
135
+ marks
136
+ });
137
+ /**
138
+ * The constrained inline schema: one paragraph, no block splitting, no
139
+ * containers, no islands. `doc: "paragraph"` (exactly one child) is what makes an
140
+ * Enter a no-op at the model level: there is no second block for a split to land.
141
+ * Marks are present; `plaintext` fields strip them at decode and mount no
142
+ * mark input (a schema-level distinction the field draws, per CODEC §Inline mode).
143
+ */
144
+ export const inlineSchema = new Schema({
145
+ nodes: {
146
+ doc: { content: 'paragraph' },
147
+ paragraph: { content: 'inline*', toDOM: () => ['p', 0] },
148
+ text: { group: 'inline' }
149
+ },
150
+ marks
151
+ });
152
+ /** True for the constrained inline schema (no block containers); decode branches on it. */
153
+ export function isInlineSchema(schema) {
154
+ return !schema.nodes.blockquote;
155
+ }
@@ -0,0 +1,79 @@
1
+ import { Plugin, type Command } from 'prosemirror-state';
2
+ import type { EditorView } from 'prosemirror-view';
3
+ import { type RangeAnchor } from './anchor.js';
4
+ /** One offer in the menu: what the chrome draws, and what a pick names. */
5
+ export interface SlashItem {
6
+ id: string;
7
+ label: string;
8
+ }
9
+ /** The menu as the chrome sees it: the filtered offers, the keyboard's cursor, and
10
+ * the trigger's anchor to hang off. `undefined` is a closed menu. */
11
+ export interface SlashState {
12
+ items: SlashItem[];
13
+ index: number;
14
+ 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. */
17
+ anchor: RangeAnchor;
18
+ }
19
+ /** The menu's wording. Each label is also its own search key (§`filterItems`), so a
20
+ * translated menu filters in the language it is displayed in. */
21
+ export interface SlashStrings {
22
+ slashLabel: string;
23
+ slashTable: string;
24
+ slashBulletList: string;
25
+ slashOrderedList: string;
26
+ }
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
+ export declare const DEFAULT_SLASH_STRINGS: SlashStrings;
30
+ /** The menu's offers, in order, from a wording. The set is the CONTAINERS: a construct
31
+ * that opens a place the caret then lives in. A construct that retypes the block the
32
+ * caret is already in (a heading, a quote, a code block, a divider) is the
33
+ * shorthand's, not the menu's. The island is first, being the one with no
34
+ * shorthand at all. */
35
+ export declare function slashItems(s: SlashStrings): SlashItem[];
36
+ /** The query filter: a substring of the LABEL, or a prefix of the id. The label is
37
+ * what the user reads, so it is the primary key; the id catches the shorthands a
38
+ * label does not carry (`/h1`, `/ul` never having been words). Both
39
+ * case-insensitive; an empty query offers everything. */
40
+ export declare function filterItems(items: SlashItem[], query: string): SlashItem[];
41
+ /** The live trigger: where the `/` sits, what has been typed after it, and which
42
+ * offer the keyboard is on. */
43
+ interface SlashRun {
44
+ from: number;
45
+ query: string;
46
+ index: number;
47
+ }
48
+ /**
49
+ * The trigger plugin. It holds the run in PM state, so every ordinary dismissal is
50
+ * free: a caret move out of it, an undo, or a re-hydrate all fail the recompute
51
+ * below and close the menu without a listener of their own. A dismissal edits no
52
+ * text; only a pick does, and it consumes exactly the run.
53
+ */
54
+ export declare function slashPlugin(opts: {
55
+ items: () => SlashItem[];
56
+ onState: (state: SlashState | undefined) => void;
57
+ }): Plugin<SlashRun | null>;
58
+ /**
59
+ * The menu's keys, the INNERMOST link of the leaf's chain (`keymap.ts`). Every one
60
+ * declines when no run is live, so a body with no menu open keeps Enter, Escape and
61
+ * the arrows exactly as it had them.
62
+ *
63
+ * Escape is the contended key: a table gives it three claimants (this menu, the
64
+ * format popover, an island selection). Innermost first, and this is the innermost
65
+ * of the three that can be open over a caret in text.
66
+ */
67
+ export declare function slashKeymap(items: () => SlashItem[]): Record<string, Command>;
68
+ /** Move the keyboard cursor onto `id`: what a pointer entering an item calls, so the
69
+ * highlight has ONE lane rather than a hover painting a second one. */
70
+ export declare function focusSlashItem(view: EditorView, id: string, items: SlashItem[]): void;
71
+ /**
72
+ * Run an offer: ONE transaction that deletes the trigger run and applies the item's
73
+ * own edit. One rather than two because two would be two commits, two undo steps and
74
+ * two recompiles for one gesture; the item's command is built against the post-delete
75
+ * state and its steps are replayed onto the same transaction, which is exactly what
76
+ * they were computed for.
77
+ */
78
+ export declare function runSlashItem(view: EditorView, id: string): void;
79
+ export {};
Binary file
@@ -0,0 +1,50 @@
1
+ import { EditorView, type NodeViewConstructor } from 'prosemirror-view';
2
+ /** Everything the island's chrome says. Accessible names, not decoration: a handle
3
+ * is a bar and a seam is a glyph, so an untranslated one reads the wrong language
4
+ * rather than merely inconsistent (VISUAL_EDITOR §"What the surface says"). */
5
+ export interface TableChromeStrings {
6
+ /** The island's own name, on the wrapper. */
7
+ tableLabel: string;
8
+ /** Row 0 is the header, which is not "Row 0". */
9
+ tableHeaderRow: string;
10
+ tableRow: (index: number) => string;
11
+ tableColumn: (index: number) => string;
12
+ /** A cell's accessible name: nothing else names a nested leaf. */
13
+ tableCell: (row: string, column: string) => string;
14
+ /** A handle's name. It SELECTS its line, and the verbs are then the selection's
15
+ * (Backspace, Alt+arrows), so the name is the gesture and not a menu's. */
16
+ tableSelectRow: (index: number) => string;
17
+ tableSelectColumn: (index: number) => string;
18
+ /** The corner's, whose line is the whole table. */
19
+ tableSelectTable: string;
20
+ /** A seam's, named by the line it would open rather than by a neighbour and a
21
+ * side: "insert row 3" is one fact where "insert below row 2" is two. */
22
+ tableInsertRow: (index: number) => string;
23
+ tableInsertColumn: (index: number) => string;
24
+ tableAlignDefault: string;
25
+ tableAlignLeft: string;
26
+ tableAlignCenter: string;
27
+ tableAlignRight: string;
28
+ }
29
+ /**
30
+ * The package's English for the island chrome. It lives HERE, beside the surface
31
+ * that draws it, rather than in the visual tier's table: the codec mounts this
32
+ * chrome and a consumer reaching `createField` directly gets wording with it. The
33
+ * visual `strings` set extends this one, so a consumer overrides these keys beside
34
+ * every other key and there is still one English list.
35
+ */
36
+ export declare const DEFAULT_TABLE_STRINGS: TableChromeStrings;
37
+ /** What the field hands each island view: its wording (read live, so a locale swap
38
+ * re-renders) and the callbacks that keep a nested view visible to the leaf. */
39
+ export interface TableViewDeps {
40
+ strings: () => TableChromeStrings;
41
+ /** Register a mounted cell view; the returned function unregisters it. The field
42
+ * needs the set to answer "which view holds the caret" for the format popover. */
43
+ register: (view: EditorView) => () => void;
44
+ /** A cell took focus: the leaf's own `focus` handler never fires for one (a focus
45
+ * event does not bubble), so the active address would not follow the caret. */
46
+ onCellFocus: () => void;
47
+ }
48
+ /** The `island_block` node view: a table island's editing surface, and the literal
49
+ * placeholder for every other island type. */
50
+ export declare function tableNodeView(deps: TableViewDeps): NodeViewConstructor;