@pilotiq/tiptap 0.1.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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/Block.d.ts +47 -0
  4. package/dist/Block.d.ts.map +1 -0
  5. package/dist/Block.js +56 -0
  6. package/dist/Block.js.map +1 -0
  7. package/dist/MentionProvider.d.ts +97 -0
  8. package/dist/MentionProvider.d.ts.map +1 -0
  9. package/dist/MentionProvider.js +104 -0
  10. package/dist/MentionProvider.js.map +1 -0
  11. package/dist/RichTextField.d.ts +286 -0
  12. package/dist/RichTextField.d.ts.map +1 -0
  13. package/dist/RichTextField.js +369 -0
  14. package/dist/RichTextField.js.map +1 -0
  15. package/dist/extensions/BlockNodeExtension.d.ts +41 -0
  16. package/dist/extensions/BlockNodeExtension.d.ts.map +1 -0
  17. package/dist/extensions/BlockNodeExtension.js +103 -0
  18. package/dist/extensions/BlockNodeExtension.js.map +1 -0
  19. package/dist/extensions/DragHandleExtension.d.ts +19 -0
  20. package/dist/extensions/DragHandleExtension.d.ts.map +1 -0
  21. package/dist/extensions/DragHandleExtension.js +166 -0
  22. package/dist/extensions/DragHandleExtension.js.map +1 -0
  23. package/dist/extensions/GridExtension.d.ts +49 -0
  24. package/dist/extensions/GridExtension.d.ts.map +1 -0
  25. package/dist/extensions/GridExtension.js +105 -0
  26. package/dist/extensions/GridExtension.js.map +1 -0
  27. package/dist/extensions/MentionExtension.d.ts +71 -0
  28. package/dist/extensions/MentionExtension.d.ts.map +1 -0
  29. package/dist/extensions/MentionExtension.js +165 -0
  30. package/dist/extensions/MentionExtension.js.map +1 -0
  31. package/dist/extensions/MergeTagExtension.d.ts +24 -0
  32. package/dist/extensions/MergeTagExtension.d.ts.map +1 -0
  33. package/dist/extensions/MergeTagExtension.js +57 -0
  34. package/dist/extensions/MergeTagExtension.js.map +1 -0
  35. package/dist/extensions/SlashCommandExtension.d.ts +71 -0
  36. package/dist/extensions/SlashCommandExtension.d.ts.map +1 -0
  37. package/dist/extensions/SlashCommandExtension.js +244 -0
  38. package/dist/extensions/SlashCommandExtension.js.map +1 -0
  39. package/dist/extensions/TextSizeMarks.d.ts +33 -0
  40. package/dist/extensions/TextSizeMarks.d.ts.map +1 -0
  41. package/dist/extensions/TextSizeMarks.js +47 -0
  42. package/dist/extensions/TextSizeMarks.js.map +1 -0
  43. package/dist/index.d.ts +8 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +8 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/plugin.d.ts +18 -0
  48. package/dist/plugin.d.ts.map +1 -0
  49. package/dist/plugin.js +25 -0
  50. package/dist/plugin.js.map +1 -0
  51. package/dist/react/BlockNodeView.d.ts +19 -0
  52. package/dist/react/BlockNodeView.d.ts.map +1 -0
  53. package/dist/react/BlockNodeView.js +60 -0
  54. package/dist/react/BlockNodeView.js.map +1 -0
  55. package/dist/react/BlockSidePanel.d.ts +105 -0
  56. package/dist/react/BlockSidePanel.d.ts.map +1 -0
  57. package/dist/react/BlockSidePanel.js +339 -0
  58. package/dist/react/BlockSidePanel.js.map +1 -0
  59. package/dist/react/FloatingToolbar.d.ts +13 -0
  60. package/dist/react/FloatingToolbar.d.ts.map +1 -0
  61. package/dist/react/FloatingToolbar.js +113 -0
  62. package/dist/react/FloatingToolbar.js.map +1 -0
  63. package/dist/react/MentionMenu.d.ts +26 -0
  64. package/dist/react/MentionMenu.d.ts.map +1 -0
  65. package/dist/react/MentionMenu.js +64 -0
  66. package/dist/react/MentionMenu.js.map +1 -0
  67. package/dist/react/Palette.d.ts +26 -0
  68. package/dist/react/Palette.d.ts.map +1 -0
  69. package/dist/react/Palette.js +21 -0
  70. package/dist/react/Palette.js.map +1 -0
  71. package/dist/react/SlashMenu.d.ts +24 -0
  72. package/dist/react/SlashMenu.d.ts.map +1 -0
  73. package/dist/react/SlashMenu.js +74 -0
  74. package/dist/react/SlashMenu.js.map +1 -0
  75. package/dist/react/TableFloatingToolbar.d.ts +7 -0
  76. package/dist/react/TableFloatingToolbar.d.ts.map +1 -0
  77. package/dist/react/TableFloatingToolbar.js +108 -0
  78. package/dist/react/TableFloatingToolbar.js.map +1 -0
  79. package/dist/react/TiptapEditor.d.ts +20 -0
  80. package/dist/react/TiptapEditor.d.ts.map +1 -0
  81. package/dist/react/TiptapEditor.js +398 -0
  82. package/dist/react/TiptapEditor.js.map +1 -0
  83. package/dist/react/Toolbar.d.ts +45 -0
  84. package/dist/react/Toolbar.d.ts.map +1 -0
  85. package/dist/react/Toolbar.js +204 -0
  86. package/dist/react/Toolbar.js.map +1 -0
  87. package/dist/react/toolbarButtons.d.ts +36 -0
  88. package/dist/react/toolbarButtons.d.ts.map +1 -0
  89. package/dist/react/toolbarButtons.js +300 -0
  90. package/dist/react/toolbarButtons.js.map +1 -0
  91. package/dist/register.d.ts +20 -0
  92. package/dist/register.d.ts.map +1 -0
  93. package/dist/register.js +27 -0
  94. package/dist/register.js.map +1 -0
  95. package/dist/render.d.ts +89 -0
  96. package/dist/render.d.ts.map +1 -0
  97. package/dist/render.js +439 -0
  98. package/dist/render.js.map +1 -0
  99. package/package.json +92 -0
  100. package/src/Block.ts +75 -0
  101. package/src/MentionProvider.ts +153 -0
  102. package/src/RichTextField.test.ts +447 -0
  103. package/src/RichTextField.ts +508 -0
  104. package/src/extensions/BlockNodeExtension.ts +134 -0
  105. package/src/extensions/DragHandleExtension.ts +184 -0
  106. package/src/extensions/GridExtension.test.ts +31 -0
  107. package/src/extensions/GridExtension.ts +138 -0
  108. package/src/extensions/MentionExtension.ts +248 -0
  109. package/src/extensions/MergeTagExtension.ts +75 -0
  110. package/src/extensions/SlashCommandExtension.test.ts +147 -0
  111. package/src/extensions/SlashCommandExtension.ts +332 -0
  112. package/src/extensions/TextSizeMarks.ts +73 -0
  113. package/src/index.ts +28 -0
  114. package/src/plugin.test.ts +19 -0
  115. package/src/plugin.ts +26 -0
  116. package/src/react/BlockNodeView.tsx +99 -0
  117. package/src/react/BlockSidePanel.test.ts +412 -0
  118. package/src/react/BlockSidePanel.tsx +451 -0
  119. package/src/react/FloatingToolbar.tsx +304 -0
  120. package/src/react/MentionMenu.tsx +120 -0
  121. package/src/react/Palette.tsx +86 -0
  122. package/src/react/SlashMenu.tsx +129 -0
  123. package/src/react/TableFloatingToolbar.tsx +154 -0
  124. package/src/react/TiptapEditor.tsx +535 -0
  125. package/src/react/Toolbar.tsx +438 -0
  126. package/src/react/toolbarButtons.tsx +579 -0
  127. package/src/register.test.ts +14 -0
  128. package/src/register.ts +27 -0
  129. package/src/render.test.ts +745 -0
  130. package/src/render.ts +480 -0
@@ -0,0 +1,165 @@
1
+ import { Node, mergeAttributes } from '@tiptap/core';
2
+ import Suggestion from '@tiptap/suggestion';
3
+ import { PluginKey } from '@tiptap/pm/state';
4
+ /**
5
+ * Inline atom node + a Suggestion plugin per registered provider.
6
+ *
7
+ * The node carries `id`, `label`, and `trigger` attributes. Storage is JSON:
8
+ * `{ type: 'mention', attrs: { id: 'sleman', label: 'Sleman', trigger: '@' } }`.
9
+ *
10
+ * Each provider gets its own ProseMirror Suggestion plugin instance so users
11
+ * can mix multiple trigger characters in the same editor (`@user`, `#room`).
12
+ * Items are static — declared via `MentionProvider.make('@').items([...])`.
13
+ *
14
+ * Read-side rendering happens through `renderRichTextToHtml(content,
15
+ * { resolveMention: (trigger, id) => latestLabel })`. Without an override
16
+ * the cached label is used — the editor stamps it at insert time so
17
+ * static-content snapshots stay self-contained.
18
+ */
19
+ export const MentionExtension = Node.create({
20
+ name: 'mention',
21
+ group: 'inline',
22
+ inline: true,
23
+ atom: true,
24
+ selectable: true,
25
+ addOptions() {
26
+ return {
27
+ providers: [],
28
+ onStateChange: () => { },
29
+ };
30
+ },
31
+ addAttributes() {
32
+ return {
33
+ id: {
34
+ default: null,
35
+ parseHTML: (el) => el.getAttribute('data-id'),
36
+ renderHTML: (a) => (a['id'] ? { 'data-id': String(a['id']) } : {}),
37
+ },
38
+ label: {
39
+ default: null,
40
+ parseHTML: (el) => el.getAttribute('data-label'),
41
+ renderHTML: (a) => (a['label'] ? { 'data-label': String(a['label']) } : {}),
42
+ },
43
+ trigger: {
44
+ default: null,
45
+ parseHTML: (el) => el.getAttribute('data-trigger'),
46
+ renderHTML: (a) => (a['trigger'] ? { 'data-trigger': String(a['trigger']) } : {}),
47
+ },
48
+ };
49
+ },
50
+ parseHTML() {
51
+ return [{ tag: 'span[data-pilotiq-mention]' }];
52
+ },
53
+ renderHTML({ node, HTMLAttributes }) {
54
+ const trigger = String(node.attrs['trigger'] ?? '');
55
+ const label = String(node.attrs['label'] ?? node.attrs['id'] ?? '');
56
+ return [
57
+ 'span',
58
+ mergeAttributes({
59
+ 'data-pilotiq-mention': '',
60
+ class: 'pilotiq-mention rounded bg-blue-500/10 px-1.5 py-0.5 text-xs font-medium text-blue-700 dark:text-blue-300 align-baseline',
61
+ }, HTMLAttributes),
62
+ `${trigger}${label}`,
63
+ ];
64
+ },
65
+ addCommands() {
66
+ return {
67
+ insertMention: ({ id, label, trigger }) => ({ commands }) => commands.insertContent([
68
+ { type: this.name, attrs: { id, label, trigger } },
69
+ { type: 'text', text: ' ' },
70
+ ]),
71
+ };
72
+ },
73
+ addProseMirrorPlugins() {
74
+ const providers = this.options.providers;
75
+ const emit = this.options.onStateChange;
76
+ const editor = this.editor;
77
+ const url = this.options.mentionsUrl;
78
+ const fieldName = this.options.fieldName;
79
+ return providers.map((provider, i) => Suggestion({
80
+ pluginKey: new PluginKey(`pilotiqMentionSuggestion-${i}`),
81
+ editor,
82
+ char: provider.trigger,
83
+ startOfLine: false,
84
+ allowSpaces: false,
85
+ items: provider.async
86
+ ? async ({ query }) => fetchAsyncMentionItems(url, fieldName, provider.trigger, query)
87
+ : ({ query }) => filterMentionItems(provider.items, query),
88
+ command: ({ editor: ed, range, props }) => {
89
+ ed
90
+ .chain()
91
+ .focus()
92
+ .deleteRange(range)
93
+ .insertContent([
94
+ {
95
+ type: 'mention',
96
+ attrs: { id: props.id, label: props.label, trigger: provider.trigger },
97
+ },
98
+ { type: 'text', text: ' ' },
99
+ ])
100
+ .run();
101
+ },
102
+ render: () => ({
103
+ onStart: (props) => emit(stateFrom(provider.trigger, props)),
104
+ onUpdate: (props) => emit(stateFrom(provider.trigger, props)),
105
+ // Keys handled at the document level by TiptapEditor — same posture
106
+ // as the slash menu.
107
+ onKeyDown: () => false,
108
+ onExit: () => emit(null),
109
+ }),
110
+ }));
111
+ },
112
+ });
113
+ function stateFrom(trigger, props) {
114
+ return {
115
+ trigger,
116
+ items: props.items,
117
+ command: props.command,
118
+ clientRect: props.clientRect ?? (() => null),
119
+ query: props.query,
120
+ };
121
+ }
122
+ function filterMentionItems(items, query) {
123
+ if (!query)
124
+ return items;
125
+ const needle = query.toLowerCase();
126
+ return items.filter((item) => `${item.label} ${item.id} ${item.group ?? ''}`.toLowerCase().includes(needle));
127
+ }
128
+ /**
129
+ * Async path — POST `{ field, trigger, query }` to the field's
130
+ * `mentionsUrl` and return the resolved items. Returns `[]` for any
131
+ * failure (missing URL / network error / non-200 response / malformed
132
+ * payload) so the menu degrades to "no matches" instead of throwing
133
+ * inside Suggestion's items pipeline.
134
+ *
135
+ * Suggestion handles its own debouncing; we don't need a setTimeout
136
+ * wrapper. In-flight races aren't tracked here either — Suggestion's
137
+ * internal sequence handling owns "newer query supersedes older one".
138
+ */
139
+ async function fetchAsyncMentionItems(url, field, trigger, query) {
140
+ if (!url || !field)
141
+ return [];
142
+ try {
143
+ const res = await fetch(url, {
144
+ method: 'POST',
145
+ headers: {
146
+ 'Content-Type': 'application/json',
147
+ 'Accept': 'application/json',
148
+ },
149
+ body: JSON.stringify({ field, trigger, query }),
150
+ });
151
+ if (!res.ok)
152
+ return [];
153
+ const json = await res.json();
154
+ if (!json.ok || !Array.isArray(json.items))
155
+ return [];
156
+ return json.items.filter((item) => item != null
157
+ && typeof item === 'object'
158
+ && typeof item['id'] === 'string'
159
+ && typeof item['label'] === 'string');
160
+ }
161
+ catch {
162
+ return [];
163
+ }
164
+ }
165
+ //# sourceMappingURL=MentionExtension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MentionExtension.js","sourceRoot":"","sources":["../../src/extensions/MentionExtension.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { Node } from '@tiptap/core';
2
+ declare module '@tiptap/core' {
3
+ interface Commands<ReturnType> {
4
+ mergeTag: {
5
+ /** Insert a `mergeTag` atom node carrying the given identifier. */
6
+ insertMergeTag: (id: string) => ReturnType;
7
+ };
8
+ }
9
+ }
10
+ /**
11
+ * Inline atom that represents a `{{ tag }}` placeholder in the document.
12
+ *
13
+ * The editor renders the node as a small chip — `{{ id }}` inside a styled
14
+ * `<span>` — so the author sees what gets substituted at read time. Storage
15
+ * is JSON: `{ type: 'mergeTag', attrs: { id: 'name' } }`.
16
+ *
17
+ * Read-side rendering happens through `renderRichTextToHtml(content,
18
+ * { mergeTags: { name: 'Sleman' } })` — pass a substitution map and the
19
+ * placeholder is replaced with the value (HTML-escaped). Without a map,
20
+ * the renderer emits `<span class="merge-tag" data-id="name">{{ name }}</span>`
21
+ * so previews on the server stay informative.
22
+ */
23
+ export declare const MergeTagExtension: Node<any, any>;
24
+ //# sourceMappingURL=MergeTagExtension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MergeTagExtension.d.ts","sourceRoot":"","sources":["../../src/extensions/MergeTagExtension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,cAAc,CAAA;AAEpD,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,QAAQ,CAAC,UAAU;QAC3B,QAAQ,EAAE;YACR,mEAAmE;YACnE,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,UAAU,CAAA;SAC3C,CAAA;KACF;CACF;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,gBAkD5B,CAAA"}
@@ -0,0 +1,57 @@
1
+ import { Node, mergeAttributes } from '@tiptap/core';
2
+ /**
3
+ * Inline atom that represents a `{{ tag }}` placeholder in the document.
4
+ *
5
+ * The editor renders the node as a small chip — `{{ id }}` inside a styled
6
+ * `<span>` — so the author sees what gets substituted at read time. Storage
7
+ * is JSON: `{ type: 'mergeTag', attrs: { id: 'name' } }`.
8
+ *
9
+ * Read-side rendering happens through `renderRichTextToHtml(content,
10
+ * { mergeTags: { name: 'Sleman' } })` — pass a substitution map and the
11
+ * placeholder is replaced with the value (HTML-escaped). Without a map,
12
+ * the renderer emits `<span class="merge-tag" data-id="name">{{ name }}</span>`
13
+ * so previews on the server stay informative.
14
+ */
15
+ export const MergeTagExtension = Node.create({
16
+ name: 'mergeTag',
17
+ group: 'inline',
18
+ inline: true,
19
+ atom: true,
20
+ selectable: true,
21
+ addAttributes() {
22
+ return {
23
+ id: {
24
+ default: null,
25
+ parseHTML: (el) => el.getAttribute('data-id'),
26
+ renderHTML: (attrs) => {
27
+ if (!attrs['id'])
28
+ return {};
29
+ return { 'data-id': String(attrs['id']) };
30
+ },
31
+ },
32
+ };
33
+ },
34
+ parseHTML() {
35
+ return [{ tag: 'span[data-pilotiq-merge-tag]' }];
36
+ },
37
+ renderHTML({ node, HTMLAttributes }) {
38
+ const id = String(node.attrs['id'] ?? '');
39
+ return [
40
+ 'span',
41
+ mergeAttributes({
42
+ 'data-pilotiq-merge-tag': '',
43
+ class: 'pilotiq-merge-tag rounded bg-primary/10 px-1.5 py-0.5 text-xs font-medium text-primary align-baseline',
44
+ }, HTMLAttributes),
45
+ `{{ ${id} }}`,
46
+ ];
47
+ },
48
+ addCommands() {
49
+ return {
50
+ insertMergeTag: (id) => ({ commands }) => commands.insertContent({
51
+ type: this.name,
52
+ attrs: { id },
53
+ }),
54
+ };
55
+ },
56
+ });
57
+ //# sourceMappingURL=MergeTagExtension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MergeTagExtension.js","sourceRoot":"","sources":["../../src/extensions/MergeTagExtension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAWpD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3C,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,UAAU,EAAE,IAAI;IAEhB,aAAa;QACX,OAAO;YACL,EAAE,EAAE;gBACF,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC;gBAC7C,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE;oBACpB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;wBAAE,OAAO,EAAE,CAAA;oBAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAA;gBAC3C,CAAC;aACF;SACF,CAAA;IACH,CAAC;IAED,SAAS;QACP,OAAO,CAAC,EAAE,GAAG,EAAE,8BAA8B,EAAE,CAAC,CAAA;IAClD,CAAC;IAED,UAAU,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE;QACjC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QACzC,OAAO;YACL,MAAM;YACN,eAAe,CACb;gBACE,wBAAwB,EAAE,EAAE;gBAC5B,KAAK,EAAE,uGAAuG;aAC/G,EACD,cAAc,CACf;YACD,MAAM,EAAE,KAAK;SACd,CAAA;IACH,CAAC;IAED,WAAW;QACT,OAAO;YACL,cAAc,EACZ,CAAC,EAAU,EAAE,EAAE,CACf,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CACf,QAAQ,CAAC,aAAa,CAAC;gBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,EAAE,EAAE,EAAE;aACd,CAAC;SACP,CAAA;IACH,CAAC;CACF,CAAC,CAAA"}
@@ -0,0 +1,71 @@
1
+ import { Extension, type Editor, type Range } from '@tiptap/core';
2
+ import type { BlockMeta } from '../Block.js';
3
+ export interface SlashItem {
4
+ /** Stable id used to dedupe + as React key. */
5
+ key: string;
6
+ label: string;
7
+ icon: string | undefined;
8
+ group?: string;
9
+ /** Free-text searched against label + group. */
10
+ searchKey: string;
11
+ /** Run when the user picks this item. `range` is the slash + query slice. */
12
+ command: (args: {
13
+ editor: Editor;
14
+ range: Range;
15
+ }) => void;
16
+ }
17
+ /**
18
+ * State the React side of the editor needs to render the slash menu. Set to
19
+ * `null` when the menu should be unmounted.
20
+ */
21
+ export interface SlashState {
22
+ items: SlashItem[];
23
+ /** Pick item — Suggestion will replace the slash range and run the command. */
24
+ command: (item: SlashItem) => void;
25
+ /**
26
+ * Cursor / range coords in viewport space. Re-call this every layout tick
27
+ * (the popover positioner does) so scroll/resize tracking comes for free.
28
+ */
29
+ clientRect: () => DOMRect | null;
30
+ query: string;
31
+ }
32
+ export interface SlashCommandOptions {
33
+ /** Custom blocks contributed by RichTextField.blocks([...]). */
34
+ blocks: BlockMeta[];
35
+ /** Merge-tag identifiers contributed by RichTextField.mergeTags([...]). */
36
+ mergeTags: string[];
37
+ /**
38
+ * Called whenever the menu should mount, update, or unmount. TiptapEditor
39
+ * holds the React state and passes a setter here.
40
+ */
41
+ onStateChange: (state: SlashState | null) => void;
42
+ /**
43
+ * `true` when the panel has wired an `UploadAdapter` (mirrors the
44
+ * toolbar's `attachFiles` gating). Drives whether the "Image" entry
45
+ * appears in the menu — it would have nowhere to upload otherwise.
46
+ */
47
+ hasUpload: boolean;
48
+ /**
49
+ * Called when the user picks the "Image" slash entry. The slash range
50
+ * is already deleted before this fires; the callback just opens the
51
+ * shared attach-files dialog (whose UI lives in `Toolbar`).
52
+ */
53
+ onInsertImage: () => void;
54
+ }
55
+ /**
56
+ * `/`-triggered slash menu. The plugin owns the suggestion lifecycle (range
57
+ * detection + command invocation); rendering is React-side via a Base UI
58
+ * Popover anchored to a virtual element. Keyboard events are NOT forwarded
59
+ * through the Suggestion plugin — TiptapEditor installs a document-level
60
+ * capture-phase keydown listener while the menu is open, because Base UI's
61
+ * focus manager can briefly steal focus from the editor when the popup mounts
62
+ * and the suggestion plugin's `handleKeyDown` only fires when the editor has
63
+ * focus.
64
+ */
65
+ export declare const SlashCommandExtension: Extension<SlashCommandOptions, any>;
66
+ export interface SlashInsertEntries {
67
+ hasUpload: boolean;
68
+ onInsertImage: () => void;
69
+ }
70
+ export declare function buildSlashItems(blocks: BlockMeta[], mergeTags: string[], query: string, insert: SlashInsertEntries): SlashItem[];
71
+ //# sourceMappingURL=SlashCommandExtension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlashCommandExtension.d.ts","sourceRoot":"","sources":["../../src/extensions/SlashCommandExtension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,cAAc,CAAA;AAKjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,WAAW,SAAS;IACxB,+CAA+C;IAC/C,GAAG,EAAS,MAAM,CAAA;IAClB,KAAK,EAAO,MAAM,CAAA;IAClB,IAAI,EAAQ,MAAM,GAAG,SAAS,CAAA;IAC9B,KAAK,CAAC,EAAM,MAAM,CAAA;IAClB,gDAAgD;IAChD,SAAS,EAAG,MAAM,CAAA;IAClB,6EAA6E;IAC7E,OAAO,EAAK,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI,CAAA;CAC7D;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAO,SAAS,EAAE,CAAA;IACvB,+EAA+E;IAC/E,OAAO,EAAK,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACrC;;;OAGG;IACH,UAAU,EAAE,MAAM,OAAO,GAAG,IAAI,CAAA;IAChC,KAAK,EAAO,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB;;;OAGG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAA;IACjD;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,qCA2ChC,CAAA;AAgBF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAM,OAAO,CAAA;IACtB,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAQD,wBAAgB,eAAe,CAC7B,MAAM,EAAK,SAAS,EAAE,EACtB,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAM,MAAM,EACjB,MAAM,EAAK,kBAAkB,GAC5B,SAAS,EAAE,CAmLb"}
@@ -0,0 +1,244 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import Suggestion from '@tiptap/suggestion';
3
+ import { PluginKey } from '@tiptap/pm/state';
4
+ const SLASH_PLUGIN_KEY = new PluginKey('pilotiqSlashSuggestion');
5
+ /**
6
+ * `/`-triggered slash menu. The plugin owns the suggestion lifecycle (range
7
+ * detection + command invocation); rendering is React-side via a Base UI
8
+ * Popover anchored to a virtual element. Keyboard events are NOT forwarded
9
+ * through the Suggestion plugin — TiptapEditor installs a document-level
10
+ * capture-phase keydown listener while the menu is open, because Base UI's
11
+ * focus manager can briefly steal focus from the editor when the popup mounts
12
+ * and the suggestion plugin's `handleKeyDown` only fires when the editor has
13
+ * focus.
14
+ */
15
+ export const SlashCommandExtension = Extension.create({
16
+ name: 'slashCommand',
17
+ addOptions() {
18
+ return {
19
+ blocks: [],
20
+ mergeTags: [],
21
+ onStateChange: () => { },
22
+ hasUpload: false,
23
+ onInsertImage: () => { },
24
+ };
25
+ },
26
+ addProseMirrorPlugins() {
27
+ const blocks = this.options.blocks;
28
+ const mergeTags = this.options.mergeTags;
29
+ const emit = this.options.onStateChange;
30
+ const hasUpload = this.options.hasUpload;
31
+ const onInsertImage = this.options.onInsertImage;
32
+ return [
33
+ Suggestion({
34
+ pluginKey: SLASH_PLUGIN_KEY,
35
+ editor: this.editor,
36
+ char: '/',
37
+ startOfLine: false,
38
+ allowSpaces: false,
39
+ items: ({ query }) => buildSlashItems(blocks, mergeTags, query, { hasUpload, onInsertImage }),
40
+ command: ({ editor, range, props }) => {
41
+ props.command({ editor, range });
42
+ },
43
+ render: () => ({
44
+ onStart: (props) => emit(stateFrom(props)),
45
+ onUpdate: (props) => emit(stateFrom(props)),
46
+ // Keys are handled at the document level by TiptapEditor; nothing
47
+ // to do here. Returning false lets PM's keymap handle anything we
48
+ // don't intercept (typing more of the slash query, etc.).
49
+ onKeyDown: () => false,
50
+ onExit: () => emit(null),
51
+ }),
52
+ }),
53
+ ];
54
+ },
55
+ });
56
+ function stateFrom(props) {
57
+ return {
58
+ items: props.items,
59
+ command: props.command,
60
+ clientRect: props.clientRect ?? (() => null),
61
+ query: props.query,
62
+ };
63
+ }
64
+ // Built-in items mirror the standard rich-text-editor slash menu. Custom
65
+ // blocks append, then merge-tag placeholders.
66
+ //
67
+ // Exported so tests can pin down the menu contents without spinning up an
68
+ // editor instance — the function is pure and deterministic given its
69
+ // inputs.
70
+ export function buildSlashItems(blocks, mergeTags, query, insert) {
71
+ const builtins = [
72
+ {
73
+ key: 'paragraph', label: 'Text', icon: '¶', group: 'Basic',
74
+ searchKey: 'text paragraph p',
75
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setNode('paragraph').run(),
76
+ },
77
+ ...[1, 2, 3, 4, 5, 6].map((level) => ({
78
+ key: `heading-${level}`,
79
+ label: `Heading ${level}`,
80
+ icon: `H${level}`,
81
+ group: 'Headings',
82
+ searchKey: `heading ${level} h${level}${level === 1 ? ' title' : level === 2 ? ' subtitle' : ''}`,
83
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setNode('heading', { level }).run(),
84
+ })),
85
+ {
86
+ key: 'bullet-list', label: 'Bullet list', icon: '•', group: 'Lists',
87
+ searchKey: 'bullet list ul unordered',
88
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).toggleBulletList().run(),
89
+ },
90
+ {
91
+ key: 'ordered-list', label: 'Numbered list', icon: '1.', group: 'Lists',
92
+ searchKey: 'numbered ordered list ol',
93
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).toggleOrderedList().run(),
94
+ },
95
+ {
96
+ key: 'quote', label: 'Quote', icon: '❝', group: 'Basic',
97
+ searchKey: 'quote blockquote',
98
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).toggleBlockquote().run(),
99
+ },
100
+ {
101
+ key: 'code', label: 'Code block', icon: '</>', group: 'Basic',
102
+ searchKey: 'code block pre',
103
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
104
+ },
105
+ {
106
+ key: 'hr', label: 'Divider', icon: '—', group: 'Basic',
107
+ searchKey: 'divider hr horizontal rule',
108
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setHorizontalRule().run(),
109
+ },
110
+ // 3×3 table with a header row — same shape as the toolbar `table` button.
111
+ // No upload gate; tables are pure schema, available everywhere.
112
+ {
113
+ key: 'table', label: 'Table', icon: '⊞', group: 'Insert',
114
+ searchKey: 'table grid rows columns',
115
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range)
116
+ .insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(),
117
+ },
118
+ // Collapsible `<details>` block. `setDetails` wraps the cursor's
119
+ // paragraph in a details node with an empty summary; the user starts
120
+ // typing the summary and presses Enter to drop into the body. No
121
+ // upload gate — pure schema, available everywhere.
122
+ {
123
+ key: 'details', label: 'Collapsible block', icon: '▸', group: 'Insert',
124
+ searchKey: 'details collapsible disclosure summary toggle expand',
125
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setDetails().run(),
126
+ },
127
+ // Multi-column grid layout. Two distinct entries (2-col + 3-col) so
128
+ // the user picks the column count from the slash menu directly,
129
+ // matching how the toolbar's `grid` button defaults to 2 cols.
130
+ {
131
+ key: 'grid-2', label: 'Two-column grid', icon: '⊞', group: 'Insert',
132
+ searchKey: 'grid columns layout 2 two split side',
133
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setGrid({ columns: 2 }).run(),
134
+ },
135
+ {
136
+ key: 'grid-3', label: 'Three-column grid', icon: '⊞', group: 'Insert',
137
+ searchKey: 'grid columns layout 3 three split',
138
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setGrid({ columns: 3 }).run(),
139
+ },
140
+ // Image entry shares the toolbar's attach-files dialog; only surfaced
141
+ // when the panel has wired an `UploadAdapter`. Without one, the dialog
142
+ // would post to a missing endpoint — the slash item degrades the same
143
+ // way the toolbar's `attachFiles` button does (server-stripped at meta
144
+ // build time when no adapter is set).
145
+ ...(insert.hasUpload ? [{
146
+ key: 'image', label: 'Image', icon: '🖼', group: 'Insert',
147
+ searchKey: 'image upload media file attach',
148
+ command: ({ editor, range }) => {
149
+ // Drop the slash range first so the user doesn't return to a
150
+ // dangling `/image` after closing the dialog. Inserting the
151
+ // actual image happens inside the dialog's upload handler.
152
+ editor.chain().focus().deleteRange(range).run();
153
+ insert.onInsertImage();
154
+ },
155
+ }] : []),
156
+ {
157
+ key: 'align-left', label: 'Align left', icon: '⇤', group: 'Align',
158
+ searchKey: 'align left start',
159
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setTextAlign('left').run(),
160
+ },
161
+ {
162
+ key: 'align-center', label: 'Align center', icon: '⇔', group: 'Align',
163
+ searchKey: 'align center middle',
164
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setTextAlign('center').run(),
165
+ },
166
+ {
167
+ key: 'align-right', label: 'Align right', icon: '⇥', group: 'Align',
168
+ searchKey: 'align right end',
169
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).setTextAlign('right').run(),
170
+ },
171
+ {
172
+ key: 'clear-format', label: 'Clear formatting', icon: '⌫', group: 'Basic',
173
+ searchKey: 'clear formatting reset',
174
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).clearNodes().unsetAllMarks().run(),
175
+ },
176
+ // Inline-mark size variants. Slash-menu form leaves the slash range in
177
+ // place rather than swallowing it, so the user runs the command on the
178
+ // word they were just typing — the alternative ("/lead" deletes the
179
+ // range, then user types more) requires re-positioning the cursor and
180
+ // breaks the "type-toggle-keep-typing" rhythm authors use most.
181
+ {
182
+ key: 'lead', label: 'Lead', icon: 'P+', group: 'Style',
183
+ searchKey: 'lead lede intro paragraph emphasis',
184
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).toggleMark('lead').run(),
185
+ },
186
+ {
187
+ key: 'small', label: 'Small', icon: 'P-', group: 'Style',
188
+ searchKey: 'small fine print footnote caption',
189
+ command: ({ editor, range }) => editor.chain().focus().deleteRange(range).toggleMark('small').run(),
190
+ },
191
+ ];
192
+ const customs = blocks.map((b) => ({
193
+ key: `block:${b.name}`,
194
+ label: b.label,
195
+ icon: b.icon,
196
+ group: 'Blocks',
197
+ searchKey: `${b.label} ${b.name} block`,
198
+ command: ({ editor, range }) => {
199
+ // Use insertContent directly with explicit attrs rather than chaining
200
+ // through our custom `insertBlock` command — chained custom commands
201
+ // sometimes drop the `attrs` payload depending on Tiptap version.
202
+ editor
203
+ .chain()
204
+ .focus()
205
+ .deleteRange(range)
206
+ .insertContent({
207
+ type: 'pilotiqBlock',
208
+ attrs: {
209
+ blockType: b.name,
210
+ blockData: defaultsFromSchema(b),
211
+ },
212
+ })
213
+ .run();
214
+ },
215
+ }));
216
+ const merges = mergeTags.map((id) => ({
217
+ key: `merge-tag:${id}`,
218
+ label: `{{ ${id} }}`,
219
+ icon: '{{}}',
220
+ group: 'Merge tags',
221
+ searchKey: `merge tag placeholder ${id}`,
222
+ command: ({ editor, range }) => {
223
+ editor
224
+ .chain()
225
+ .focus()
226
+ .deleteRange(range)
227
+ .insertContent({ type: 'mergeTag', attrs: { id } })
228
+ .run();
229
+ },
230
+ }));
231
+ const all = [...builtins, ...customs, ...merges];
232
+ if (!query)
233
+ return all;
234
+ const needle = query.toLowerCase();
235
+ return all.filter((item) => `${item.label} ${item.searchKey} ${item.group ?? ''}`.toLowerCase().includes(needle));
236
+ }
237
+ function defaultsFromSchema(block) {
238
+ const out = {};
239
+ for (const f of block.schema) {
240
+ out[f.name] = '';
241
+ }
242
+ return out;
243
+ }
244
+ //# sourceMappingURL=SlashCommandExtension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlashCommandExtension.js","sourceRoot":"","sources":["../../src/extensions/SlashCommandExtension.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { Mark } from '@tiptap/core';
2
+ declare module '@tiptap/core' {
3
+ interface Commands<ReturnType> {
4
+ lead: {
5
+ /** Toggle the `lead` mark on the current selection. */
6
+ toggleLead: () => ReturnType;
7
+ };
8
+ small: {
9
+ /** Toggle the `small` mark on the current selection. */
10
+ toggleSmall: () => ReturnType;
11
+ };
12
+ }
13
+ }
14
+ /**
15
+ * Two inline marks for paragraph-style size variants beyond the standard
16
+ * heading levels:
17
+ *
18
+ * - `lead` — opening / lede paragraph styling. Renders as
19
+ * `<span class="lead">…</span>` so authors keep paragraph
20
+ * semantics; styling is owned by the consumer's CSS (the
21
+ * adapter doesn't ship a `.lead` rule — every site already
22
+ * has one).
23
+ * - `small` — semantic `<small>` mark. Mirrors the HTML element so
24
+ * read-side renderers don't need a special class to style
25
+ * fine print.
26
+ *
27
+ * Both marks live in the standard inline group so they compose with bold,
28
+ * italic, color, etc. without exclusivity rules. Excluding each other isn't
29
+ * useful — a `<small lead>` selection would be inert visually anyway.
30
+ */
31
+ export declare const LeadMarkExtension: Mark<any, any>;
32
+ export declare const SmallMarkExtension: Mark<any, any>;
33
+ //# sourceMappingURL=TextSizeMarks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextSizeMarks.d.ts","sourceRoot":"","sources":["../../src/extensions/TextSizeMarks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,cAAc,CAAA;AAEpD,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,QAAQ,CAAC,UAAU;QAC3B,IAAI,EAAE;YACJ,uDAAuD;YACvD,UAAU,EAAE,MAAM,UAAU,CAAA;SAC7B,CAAA;QACD,KAAK,EAAE;YACL,wDAAwD;YACxD,WAAW,EAAE,MAAM,UAAU,CAAA;SAC9B,CAAA;KACF;CACF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,gBAmB5B,CAAA;AAEF,eAAO,MAAM,kBAAkB,gBAmB7B,CAAA"}