@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.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/Block.d.ts +47 -0
- package/dist/Block.d.ts.map +1 -0
- package/dist/Block.js +56 -0
- package/dist/Block.js.map +1 -0
- package/dist/MentionProvider.d.ts +97 -0
- package/dist/MentionProvider.d.ts.map +1 -0
- package/dist/MentionProvider.js +104 -0
- package/dist/MentionProvider.js.map +1 -0
- package/dist/RichTextField.d.ts +286 -0
- package/dist/RichTextField.d.ts.map +1 -0
- package/dist/RichTextField.js +369 -0
- package/dist/RichTextField.js.map +1 -0
- package/dist/extensions/BlockNodeExtension.d.ts +41 -0
- package/dist/extensions/BlockNodeExtension.d.ts.map +1 -0
- package/dist/extensions/BlockNodeExtension.js +103 -0
- package/dist/extensions/BlockNodeExtension.js.map +1 -0
- package/dist/extensions/DragHandleExtension.d.ts +19 -0
- package/dist/extensions/DragHandleExtension.d.ts.map +1 -0
- package/dist/extensions/DragHandleExtension.js +166 -0
- package/dist/extensions/DragHandleExtension.js.map +1 -0
- package/dist/extensions/GridExtension.d.ts +49 -0
- package/dist/extensions/GridExtension.d.ts.map +1 -0
- package/dist/extensions/GridExtension.js +105 -0
- package/dist/extensions/GridExtension.js.map +1 -0
- package/dist/extensions/MentionExtension.d.ts +71 -0
- package/dist/extensions/MentionExtension.d.ts.map +1 -0
- package/dist/extensions/MentionExtension.js +165 -0
- package/dist/extensions/MentionExtension.js.map +1 -0
- package/dist/extensions/MergeTagExtension.d.ts +24 -0
- package/dist/extensions/MergeTagExtension.d.ts.map +1 -0
- package/dist/extensions/MergeTagExtension.js +57 -0
- package/dist/extensions/MergeTagExtension.js.map +1 -0
- package/dist/extensions/SlashCommandExtension.d.ts +71 -0
- package/dist/extensions/SlashCommandExtension.d.ts.map +1 -0
- package/dist/extensions/SlashCommandExtension.js +244 -0
- package/dist/extensions/SlashCommandExtension.js.map +1 -0
- package/dist/extensions/TextSizeMarks.d.ts +33 -0
- package/dist/extensions/TextSizeMarks.d.ts.map +1 -0
- package/dist/extensions/TextSizeMarks.js +47 -0
- package/dist/extensions/TextSizeMarks.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +18 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +25 -0
- package/dist/plugin.js.map +1 -0
- package/dist/react/BlockNodeView.d.ts +19 -0
- package/dist/react/BlockNodeView.d.ts.map +1 -0
- package/dist/react/BlockNodeView.js +60 -0
- package/dist/react/BlockNodeView.js.map +1 -0
- package/dist/react/BlockSidePanel.d.ts +105 -0
- package/dist/react/BlockSidePanel.d.ts.map +1 -0
- package/dist/react/BlockSidePanel.js +339 -0
- package/dist/react/BlockSidePanel.js.map +1 -0
- package/dist/react/FloatingToolbar.d.ts +13 -0
- package/dist/react/FloatingToolbar.d.ts.map +1 -0
- package/dist/react/FloatingToolbar.js +113 -0
- package/dist/react/FloatingToolbar.js.map +1 -0
- package/dist/react/MentionMenu.d.ts +26 -0
- package/dist/react/MentionMenu.d.ts.map +1 -0
- package/dist/react/MentionMenu.js +64 -0
- package/dist/react/MentionMenu.js.map +1 -0
- package/dist/react/Palette.d.ts +26 -0
- package/dist/react/Palette.d.ts.map +1 -0
- package/dist/react/Palette.js +21 -0
- package/dist/react/Palette.js.map +1 -0
- package/dist/react/SlashMenu.d.ts +24 -0
- package/dist/react/SlashMenu.d.ts.map +1 -0
- package/dist/react/SlashMenu.js +74 -0
- package/dist/react/SlashMenu.js.map +1 -0
- package/dist/react/TableFloatingToolbar.d.ts +7 -0
- package/dist/react/TableFloatingToolbar.d.ts.map +1 -0
- package/dist/react/TableFloatingToolbar.js +108 -0
- package/dist/react/TableFloatingToolbar.js.map +1 -0
- package/dist/react/TiptapEditor.d.ts +20 -0
- package/dist/react/TiptapEditor.d.ts.map +1 -0
- package/dist/react/TiptapEditor.js +398 -0
- package/dist/react/TiptapEditor.js.map +1 -0
- package/dist/react/Toolbar.d.ts +45 -0
- package/dist/react/Toolbar.d.ts.map +1 -0
- package/dist/react/Toolbar.js +204 -0
- package/dist/react/Toolbar.js.map +1 -0
- package/dist/react/toolbarButtons.d.ts +36 -0
- package/dist/react/toolbarButtons.d.ts.map +1 -0
- package/dist/react/toolbarButtons.js +300 -0
- package/dist/react/toolbarButtons.js.map +1 -0
- package/dist/register.d.ts +20 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +27 -0
- package/dist/register.js.map +1 -0
- package/dist/render.d.ts +89 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +439 -0
- package/dist/render.js.map +1 -0
- package/package.json +92 -0
- package/src/Block.ts +75 -0
- package/src/MentionProvider.ts +153 -0
- package/src/RichTextField.test.ts +447 -0
- package/src/RichTextField.ts +508 -0
- package/src/extensions/BlockNodeExtension.ts +134 -0
- package/src/extensions/DragHandleExtension.ts +184 -0
- package/src/extensions/GridExtension.test.ts +31 -0
- package/src/extensions/GridExtension.ts +138 -0
- package/src/extensions/MentionExtension.ts +248 -0
- package/src/extensions/MergeTagExtension.ts +75 -0
- package/src/extensions/SlashCommandExtension.test.ts +147 -0
- package/src/extensions/SlashCommandExtension.ts +332 -0
- package/src/extensions/TextSizeMarks.ts +73 -0
- package/src/index.ts +28 -0
- package/src/plugin.test.ts +19 -0
- package/src/plugin.ts +26 -0
- package/src/react/BlockNodeView.tsx +99 -0
- package/src/react/BlockSidePanel.test.ts +412 -0
- package/src/react/BlockSidePanel.tsx +451 -0
- package/src/react/FloatingToolbar.tsx +304 -0
- package/src/react/MentionMenu.tsx +120 -0
- package/src/react/Palette.tsx +86 -0
- package/src/react/SlashMenu.tsx +129 -0
- package/src/react/TableFloatingToolbar.tsx +154 -0
- package/src/react/TiptapEditor.tsx +535 -0
- package/src/react/Toolbar.tsx +438 -0
- package/src/react/toolbarButtons.tsx +579 -0
- package/src/register.test.ts +14 -0
- package/src/register.ts +27 -0
- package/src/render.test.ts +745 -0
- 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"}
|