@threadlabs/looma 0.26.10 → 0.26.12
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/components/ui-callout/ui-callout.html +13 -0
- package/components/ui-card/ui-card.html +26 -9
- package/components/ui-list-item/ui-list-item.html +4 -4
- package/components/ui-nav-item/ui-nav-item.html +4 -4
- package/components/ui-search-result-row/ui-search-result-row.html +3 -3
- package/components/ui-section/ui-section.html +12 -0
- package/components/ui-tree-item/ui-tree-item.html +6 -6
- package/dist/index.js +1 -1
- package/package.json +7 -2
- package/styles/ui-callout.css +13 -0
- package/styles/ui-card.css +26 -7
- package/styles/ui-list-item.css +4 -4
- package/styles/ui-nav-item.css +4 -4
- package/styles/ui-search-result-row.css +3 -3
- package/styles/ui-section.css +12 -0
- package/styles/ui-tree-item.css +6 -6
- package/tokens.css +2 -2
- package/vue/UiCallout.vue +33 -0
- package/vue/UiCard.vue +29 -8
- package/vue/UiListItem.vue +5 -4
- package/vue/UiNavItem.vue +8 -4
- package/vue/UiSearchResultRow.vue +3 -3
- package/vue/UiSection.vue +12 -0
- package/vue/UiTreeItem.vue +8 -6
- package/vue/chunks/UiCallout.js +1 -1
- package/vue/chunks/UiCard.js +2 -2
- package/vue/chunks/UiListItem.js +1 -1
- package/vue/chunks/UiNavItem.js +1 -1
- package/vue/chunks/UiSearchResultRow.js +1 -1
- package/vue/chunks/UiSection.js +1 -1
- package/vue/chunks/UiTreeItem.js +1 -1
- package/vue/components.css +359 -250
- package/vue/editor/compact/extensions.d.ts +3 -0
- package/vue/editor/compact/index.d.ts +84 -0
- package/vue/editor/compact/index.js +517 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type PropType } from "vue";
|
|
2
|
+
import type { AnyExtension, JSONContent } from "@tiptap/core";
|
|
3
|
+
import { Editor } from "@tiptap/vue-3";
|
|
4
|
+
import "./compact-editor.css";
|
|
5
|
+
export { getCompactEditorExtensions } from "./extensions.js";
|
|
6
|
+
/**
|
|
7
|
+
* Toolbar-free editing for short rich text. Owns editor lifecycle and standard
|
|
8
|
+
* formatting/history shortcuts; the host owns persistence and optional extensions.
|
|
9
|
+
* Importing this entry is SSR-safe and does not load the full document editor.
|
|
10
|
+
* @ownership The component owns the editor; callers own content and extensions.
|
|
11
|
+
* @lifecycle Mount creates one editor; unmount destroys it and prop watchers.
|
|
12
|
+
* @failure Persistence failures are host-owned; the controlled document can restore input.
|
|
13
|
+
*/
|
|
14
|
+
export declare const LoomaCompactEditor: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
15
|
+
modelValue: {
|
|
16
|
+
type: PropType<JSONContent>;
|
|
17
|
+
default: () => JSONContent;
|
|
18
|
+
};
|
|
19
|
+
label: {
|
|
20
|
+
type: StringConstructor;
|
|
21
|
+
default: string;
|
|
22
|
+
};
|
|
23
|
+
id: {
|
|
24
|
+
type: StringConstructor;
|
|
25
|
+
default: string;
|
|
26
|
+
};
|
|
27
|
+
editable: {
|
|
28
|
+
type: BooleanConstructor;
|
|
29
|
+
default: boolean;
|
|
30
|
+
};
|
|
31
|
+
extensions: {
|
|
32
|
+
type: PropType<AnyExtension[]>;
|
|
33
|
+
default: () => never[];
|
|
34
|
+
};
|
|
35
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
36
|
+
[key: string]: any;
|
|
37
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
38
|
+
"update:modelValue": (_value: JSONContent) => true;
|
|
39
|
+
ready: (_editor: Editor) => true;
|
|
40
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
41
|
+
modelValue: {
|
|
42
|
+
type: PropType<JSONContent>;
|
|
43
|
+
default: () => JSONContent;
|
|
44
|
+
};
|
|
45
|
+
label: {
|
|
46
|
+
type: StringConstructor;
|
|
47
|
+
default: string;
|
|
48
|
+
};
|
|
49
|
+
id: {
|
|
50
|
+
type: StringConstructor;
|
|
51
|
+
default: string;
|
|
52
|
+
};
|
|
53
|
+
editable: {
|
|
54
|
+
type: BooleanConstructor;
|
|
55
|
+
default: boolean;
|
|
56
|
+
};
|
|
57
|
+
extensions: {
|
|
58
|
+
type: PropType<AnyExtension[]>;
|
|
59
|
+
default: () => never[];
|
|
60
|
+
};
|
|
61
|
+
}>> & Readonly<{
|
|
62
|
+
"onUpdate:modelValue"?: ((_value: JSONContent) => any) | undefined;
|
|
63
|
+
onReady?: ((_editor: Editor) => any) | undefined;
|
|
64
|
+
}>, {
|
|
65
|
+
label: string;
|
|
66
|
+
id: string;
|
|
67
|
+
modelValue: JSONContent;
|
|
68
|
+
editable: boolean;
|
|
69
|
+
extensions: AnyExtension[];
|
|
70
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
71
|
+
/** Renders basic compact JSON as escaped Vue nodes, including during SSR. */
|
|
72
|
+
export declare const LoomaCompactContent: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
73
|
+
content: {
|
|
74
|
+
type: PropType<JSONContent>;
|
|
75
|
+
required: true;
|
|
76
|
+
};
|
|
77
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
78
|
+
[key: string]: any;
|
|
79
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
80
|
+
content: {
|
|
81
|
+
type: PropType<JSONContent>;
|
|
82
|
+
required: true;
|
|
83
|
+
};
|
|
84
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { defineComponent, h, onBeforeUnmount, onMounted, shallowRef, watch } from "vue";
|
|
2
|
+
import { Extension, Mark, Node, markInputRule, markPasteRule, mergeAttributes } from "@tiptap/core";
|
|
3
|
+
import { Editor, EditorContent } from "@tiptap/vue-3";
|
|
4
|
+
import { history, redo, undo } from "@tiptap/pm/history";
|
|
5
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-document@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-document/dist/index.js
|
|
6
|
+
/**
|
|
7
|
+
* The default document node which represents the top level node of the editor.
|
|
8
|
+
* @see https://tiptap.dev/api/nodes/document
|
|
9
|
+
*/
|
|
10
|
+
var Document = Node.create({
|
|
11
|
+
name: "doc",
|
|
12
|
+
topNode: true,
|
|
13
|
+
content: "block+"
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-paragraph@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-paragraph/dist/index.js
|
|
17
|
+
/**
|
|
18
|
+
* This extension allows you to create paragraphs.
|
|
19
|
+
* @see https://www.tiptap.dev/api/nodes/paragraph
|
|
20
|
+
*/
|
|
21
|
+
var Paragraph = Node.create({
|
|
22
|
+
name: "paragraph",
|
|
23
|
+
priority: 1e3,
|
|
24
|
+
addOptions() {
|
|
25
|
+
return { HTMLAttributes: {} };
|
|
26
|
+
},
|
|
27
|
+
group: "block",
|
|
28
|
+
content: "inline*",
|
|
29
|
+
parseHTML() {
|
|
30
|
+
return [{ tag: "p" }];
|
|
31
|
+
},
|
|
32
|
+
renderHTML({ HTMLAttributes }) {
|
|
33
|
+
return [
|
|
34
|
+
"p",
|
|
35
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
36
|
+
0
|
|
37
|
+
];
|
|
38
|
+
},
|
|
39
|
+
addCommands() {
|
|
40
|
+
return { setParagraph: () => ({ commands }) => {
|
|
41
|
+
return commands.setNode(this.name);
|
|
42
|
+
} };
|
|
43
|
+
},
|
|
44
|
+
addKeyboardShortcuts() {
|
|
45
|
+
return { "Mod-Alt-0": () => this.editor.commands.setParagraph() };
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-text@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-text/dist/index.js
|
|
50
|
+
/**
|
|
51
|
+
* This extension allows you to create text nodes.
|
|
52
|
+
* @see https://www.tiptap.dev/api/nodes/text
|
|
53
|
+
*/
|
|
54
|
+
var Text = Node.create({
|
|
55
|
+
name: "text",
|
|
56
|
+
group: "inline"
|
|
57
|
+
});
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-bold@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-bold/dist/index.js
|
|
60
|
+
/**
|
|
61
|
+
* Matches bold text via `**` as input.
|
|
62
|
+
*/
|
|
63
|
+
var starInputRegex$1 = /(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))$/;
|
|
64
|
+
/**
|
|
65
|
+
* Matches bold text via `**` while pasting.
|
|
66
|
+
*/
|
|
67
|
+
var starPasteRegex$1 = /(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))/g;
|
|
68
|
+
/**
|
|
69
|
+
* Matches bold text via `__` as input.
|
|
70
|
+
*/
|
|
71
|
+
var underscoreInputRegex$1 = /(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))$/;
|
|
72
|
+
/**
|
|
73
|
+
* Matches bold text via `__` while pasting.
|
|
74
|
+
*/
|
|
75
|
+
var underscorePasteRegex$1 = /(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))/g;
|
|
76
|
+
/**
|
|
77
|
+
* This extension allows you to mark text as bold.
|
|
78
|
+
* @see https://tiptap.dev/api/marks/bold
|
|
79
|
+
*/
|
|
80
|
+
var Bold = Mark.create({
|
|
81
|
+
name: "bold",
|
|
82
|
+
addOptions() {
|
|
83
|
+
return { HTMLAttributes: {} };
|
|
84
|
+
},
|
|
85
|
+
parseHTML() {
|
|
86
|
+
return [
|
|
87
|
+
{ tag: "strong" },
|
|
88
|
+
{
|
|
89
|
+
tag: "b",
|
|
90
|
+
getAttrs: (node) => node.style.fontWeight !== "normal" && null
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
style: "font-weight=400",
|
|
94
|
+
clearMark: (mark) => mark.type.name === this.name
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
style: "font-weight",
|
|
98
|
+
getAttrs: (value) => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
|
|
99
|
+
}
|
|
100
|
+
];
|
|
101
|
+
},
|
|
102
|
+
renderHTML({ HTMLAttributes }) {
|
|
103
|
+
return [
|
|
104
|
+
"strong",
|
|
105
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
106
|
+
0
|
|
107
|
+
];
|
|
108
|
+
},
|
|
109
|
+
addCommands() {
|
|
110
|
+
return {
|
|
111
|
+
setBold: () => ({ commands }) => {
|
|
112
|
+
return commands.setMark(this.name);
|
|
113
|
+
},
|
|
114
|
+
toggleBold: () => ({ commands }) => {
|
|
115
|
+
return commands.toggleMark(this.name);
|
|
116
|
+
},
|
|
117
|
+
unsetBold: () => ({ commands }) => {
|
|
118
|
+
return commands.unsetMark(this.name);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
addKeyboardShortcuts() {
|
|
123
|
+
return {
|
|
124
|
+
"Mod-b": () => this.editor.commands.toggleBold(),
|
|
125
|
+
"Mod-B": () => this.editor.commands.toggleBold()
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
addInputRules() {
|
|
129
|
+
return [markInputRule({
|
|
130
|
+
find: starInputRegex$1,
|
|
131
|
+
type: this.type
|
|
132
|
+
}), markInputRule({
|
|
133
|
+
find: underscoreInputRegex$1,
|
|
134
|
+
type: this.type
|
|
135
|
+
})];
|
|
136
|
+
},
|
|
137
|
+
addPasteRules() {
|
|
138
|
+
return [markPasteRule({
|
|
139
|
+
find: starPasteRegex$1,
|
|
140
|
+
type: this.type
|
|
141
|
+
}), markPasteRule({
|
|
142
|
+
find: underscorePasteRegex$1,
|
|
143
|
+
type: this.type
|
|
144
|
+
})];
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-italic@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-italic/dist/index.js
|
|
149
|
+
/**
|
|
150
|
+
* Matches an italic to a *italic* on input.
|
|
151
|
+
*/
|
|
152
|
+
var starInputRegex = /(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))$/;
|
|
153
|
+
/**
|
|
154
|
+
* Matches an italic to a *italic* on paste.
|
|
155
|
+
*/
|
|
156
|
+
var starPasteRegex = /(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))/g;
|
|
157
|
+
/**
|
|
158
|
+
* Matches an italic to a _italic_ on input.
|
|
159
|
+
*/
|
|
160
|
+
var underscoreInputRegex = /(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))$/;
|
|
161
|
+
/**
|
|
162
|
+
* Matches an italic to a _italic_ on paste.
|
|
163
|
+
*/
|
|
164
|
+
var underscorePasteRegex = /(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))/g;
|
|
165
|
+
/**
|
|
166
|
+
* This extension allows you to create italic text.
|
|
167
|
+
* @see https://www.tiptap.dev/api/marks/italic
|
|
168
|
+
*/
|
|
169
|
+
var Italic = Mark.create({
|
|
170
|
+
name: "italic",
|
|
171
|
+
addOptions() {
|
|
172
|
+
return { HTMLAttributes: {} };
|
|
173
|
+
},
|
|
174
|
+
parseHTML() {
|
|
175
|
+
return [
|
|
176
|
+
{ tag: "em" },
|
|
177
|
+
{
|
|
178
|
+
tag: "i",
|
|
179
|
+
getAttrs: (node) => node.style.fontStyle !== "normal" && null
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
style: "font-style=normal",
|
|
183
|
+
clearMark: (mark) => mark.type.name === this.name
|
|
184
|
+
},
|
|
185
|
+
{ style: "font-style=italic" }
|
|
186
|
+
];
|
|
187
|
+
},
|
|
188
|
+
renderHTML({ HTMLAttributes }) {
|
|
189
|
+
return [
|
|
190
|
+
"em",
|
|
191
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
192
|
+
0
|
|
193
|
+
];
|
|
194
|
+
},
|
|
195
|
+
addCommands() {
|
|
196
|
+
return {
|
|
197
|
+
setItalic: () => ({ commands }) => {
|
|
198
|
+
return commands.setMark(this.name);
|
|
199
|
+
},
|
|
200
|
+
toggleItalic: () => ({ commands }) => {
|
|
201
|
+
return commands.toggleMark(this.name);
|
|
202
|
+
},
|
|
203
|
+
unsetItalic: () => ({ commands }) => {
|
|
204
|
+
return commands.unsetMark(this.name);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
addKeyboardShortcuts() {
|
|
209
|
+
return {
|
|
210
|
+
"Mod-i": () => this.editor.commands.toggleItalic(),
|
|
211
|
+
"Mod-I": () => this.editor.commands.toggleItalic()
|
|
212
|
+
};
|
|
213
|
+
},
|
|
214
|
+
addInputRules() {
|
|
215
|
+
return [markInputRule({
|
|
216
|
+
find: starInputRegex,
|
|
217
|
+
type: this.type
|
|
218
|
+
}), markInputRule({
|
|
219
|
+
find: underscoreInputRegex,
|
|
220
|
+
type: this.type
|
|
221
|
+
})];
|
|
222
|
+
},
|
|
223
|
+
addPasteRules() {
|
|
224
|
+
return [markPasteRule({
|
|
225
|
+
find: starPasteRegex,
|
|
226
|
+
type: this.type
|
|
227
|
+
}), markPasteRule({
|
|
228
|
+
find: underscorePasteRegex,
|
|
229
|
+
type: this.type
|
|
230
|
+
})];
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-code@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-code/dist/index.js
|
|
235
|
+
/**
|
|
236
|
+
* Regular expressions to match inline code blocks enclosed in backticks.
|
|
237
|
+
* It matches:
|
|
238
|
+
* - An opening backtick, followed by
|
|
239
|
+
* - Any text that doesn't include a backtick (captured for marking), followed by
|
|
240
|
+
* - A closing backtick.
|
|
241
|
+
* This ensures that any text between backticks is formatted as code,
|
|
242
|
+
* regardless of the surrounding characters (exception being another backtick).
|
|
243
|
+
*/
|
|
244
|
+
var inputRegex = /(^|[^`])`([^`]+)`(?!`)/;
|
|
245
|
+
/**
|
|
246
|
+
* Matches inline code while pasting.
|
|
247
|
+
*/
|
|
248
|
+
var pasteRegex = /(^|[^`])`([^`]+)`(?!`)/g;
|
|
249
|
+
/**
|
|
250
|
+
* This extension allows you to mark text as inline code.
|
|
251
|
+
* @see https://tiptap.dev/api/marks/code
|
|
252
|
+
*/
|
|
253
|
+
var Code = Mark.create({
|
|
254
|
+
name: "code",
|
|
255
|
+
addOptions() {
|
|
256
|
+
return { HTMLAttributes: {} };
|
|
257
|
+
},
|
|
258
|
+
excludes: "_",
|
|
259
|
+
code: true,
|
|
260
|
+
exitable: true,
|
|
261
|
+
parseHTML() {
|
|
262
|
+
return [{ tag: "code" }];
|
|
263
|
+
},
|
|
264
|
+
renderHTML({ HTMLAttributes }) {
|
|
265
|
+
return [
|
|
266
|
+
"code",
|
|
267
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
268
|
+
0
|
|
269
|
+
];
|
|
270
|
+
},
|
|
271
|
+
addCommands() {
|
|
272
|
+
return {
|
|
273
|
+
setCode: () => ({ commands }) => {
|
|
274
|
+
return commands.setMark(this.name);
|
|
275
|
+
},
|
|
276
|
+
toggleCode: () => ({ commands }) => {
|
|
277
|
+
return commands.toggleMark(this.name);
|
|
278
|
+
},
|
|
279
|
+
unsetCode: () => ({ commands }) => {
|
|
280
|
+
return commands.unsetMark(this.name);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
addKeyboardShortcuts() {
|
|
285
|
+
return { "Mod-e": () => this.editor.commands.toggleCode() };
|
|
286
|
+
},
|
|
287
|
+
addInputRules() {
|
|
288
|
+
return [markInputRule({
|
|
289
|
+
find: inputRegex,
|
|
290
|
+
type: this.type
|
|
291
|
+
})];
|
|
292
|
+
},
|
|
293
|
+
addPasteRules() {
|
|
294
|
+
return [markPasteRule({
|
|
295
|
+
find: pasteRegex,
|
|
296
|
+
type: this.type
|
|
297
|
+
})];
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-hard-break@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-hard-break/dist/index.js
|
|
302
|
+
/**
|
|
303
|
+
* This extension allows you to insert hard breaks.
|
|
304
|
+
* @see https://www.tiptap.dev/api/nodes/hard-break
|
|
305
|
+
*/
|
|
306
|
+
var HardBreak = Node.create({
|
|
307
|
+
name: "hardBreak",
|
|
308
|
+
addOptions() {
|
|
309
|
+
return {
|
|
310
|
+
keepMarks: true,
|
|
311
|
+
HTMLAttributes: {}
|
|
312
|
+
};
|
|
313
|
+
},
|
|
314
|
+
inline: true,
|
|
315
|
+
group: "inline",
|
|
316
|
+
selectable: false,
|
|
317
|
+
linebreakReplacement: true,
|
|
318
|
+
parseHTML() {
|
|
319
|
+
return [{ tag: "br" }];
|
|
320
|
+
},
|
|
321
|
+
renderHTML({ HTMLAttributes }) {
|
|
322
|
+
return ["br", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
|
|
323
|
+
},
|
|
324
|
+
renderText() {
|
|
325
|
+
return "\n";
|
|
326
|
+
},
|
|
327
|
+
addCommands() {
|
|
328
|
+
return { setHardBreak: () => ({ commands, chain, state, editor }) => {
|
|
329
|
+
return commands.first([() => commands.exitCode(), () => commands.command(() => {
|
|
330
|
+
const { selection, storedMarks } = state;
|
|
331
|
+
if (selection.$from.parent.type.spec.isolating) return false;
|
|
332
|
+
const { keepMarks } = this.options;
|
|
333
|
+
const { splittableMarks } = editor.extensionManager;
|
|
334
|
+
const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
|
|
335
|
+
return chain().insertContent({ type: this.name }).command(({ tr, dispatch }) => {
|
|
336
|
+
if (dispatch && marks && keepMarks) {
|
|
337
|
+
const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
|
|
338
|
+
tr.ensureMarks(filteredMarks);
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
341
|
+
}).run();
|
|
342
|
+
})]);
|
|
343
|
+
} };
|
|
344
|
+
},
|
|
345
|
+
addKeyboardShortcuts() {
|
|
346
|
+
return {
|
|
347
|
+
"Mod-Enter": () => this.editor.commands.setHardBreak(),
|
|
348
|
+
"Shift-Enter": () => this.editor.commands.setHardBreak()
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region ../../node_modules/.pnpm/@tiptap+extension-history@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2__@tiptap+pm@2.27.2/node_modules/@tiptap/extension-history/dist/index.js
|
|
354
|
+
/**
|
|
355
|
+
* This extension allows you to undo and redo recent changes.
|
|
356
|
+
* @see https://www.tiptap.dev/api/extensions/history
|
|
357
|
+
*
|
|
358
|
+
* **Important**: If the `@tiptap/extension-collaboration` package is used, make sure to remove
|
|
359
|
+
* the `history` extension, as it is not compatible with the `collaboration` extension.
|
|
360
|
+
*
|
|
361
|
+
* `@tiptap/extension-collaboration` uses its own history implementation.
|
|
362
|
+
*/
|
|
363
|
+
var History = Extension.create({
|
|
364
|
+
name: "history",
|
|
365
|
+
addOptions() {
|
|
366
|
+
return {
|
|
367
|
+
depth: 100,
|
|
368
|
+
newGroupDelay: 500
|
|
369
|
+
};
|
|
370
|
+
},
|
|
371
|
+
addCommands() {
|
|
372
|
+
return {
|
|
373
|
+
undo: () => ({ state, dispatch }) => {
|
|
374
|
+
return undo(state, dispatch);
|
|
375
|
+
},
|
|
376
|
+
redo: () => ({ state, dispatch }) => {
|
|
377
|
+
return redo(state, dispatch);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
},
|
|
381
|
+
addProseMirrorPlugins() {
|
|
382
|
+
return [history(this.options)];
|
|
383
|
+
},
|
|
384
|
+
addKeyboardShortcuts() {
|
|
385
|
+
return {
|
|
386
|
+
"Mod-z": () => this.editor.commands.undo(),
|
|
387
|
+
"Shift-Mod-z": () => this.editor.commands.redo(),
|
|
388
|
+
"Mod-y": () => this.editor.commands.redo(),
|
|
389
|
+
"Mod-я": () => this.editor.commands.undo(),
|
|
390
|
+
"Shift-Mod-я": () => this.editor.commands.redo()
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/vue/editor/compact/extensions.ts
|
|
396
|
+
/** Minimal short-form schema; additional consumer extensions are opt-in. */
|
|
397
|
+
function getCompactEditorExtensions() {
|
|
398
|
+
return [
|
|
399
|
+
Document,
|
|
400
|
+
Paragraph,
|
|
401
|
+
Text,
|
|
402
|
+
Bold,
|
|
403
|
+
Italic,
|
|
404
|
+
Code,
|
|
405
|
+
HardBreak,
|
|
406
|
+
History
|
|
407
|
+
];
|
|
408
|
+
}
|
|
409
|
+
//#endregion
|
|
410
|
+
//#region src/vue/editor/compact/index.ts
|
|
411
|
+
var emptyDocument = () => ({
|
|
412
|
+
type: "doc",
|
|
413
|
+
content: [{ type: "paragraph" }]
|
|
414
|
+
});
|
|
415
|
+
/**
|
|
416
|
+
* Toolbar-free editing for short rich text. Owns editor lifecycle and standard
|
|
417
|
+
* formatting/history shortcuts; the host owns persistence and optional extensions.
|
|
418
|
+
* Importing this entry is SSR-safe and does not load the full document editor.
|
|
419
|
+
* @ownership The component owns the editor; callers own content and extensions.
|
|
420
|
+
* @lifecycle Mount creates one editor; unmount destroys it and prop watchers.
|
|
421
|
+
* @failure Persistence failures are host-owned; the controlled document can restore input.
|
|
422
|
+
*/
|
|
423
|
+
var LoomaCompactEditor = defineComponent({
|
|
424
|
+
name: "LoomaCompactEditor",
|
|
425
|
+
inheritAttrs: false,
|
|
426
|
+
props: {
|
|
427
|
+
modelValue: {
|
|
428
|
+
type: Object,
|
|
429
|
+
default: emptyDocument
|
|
430
|
+
},
|
|
431
|
+
label: {
|
|
432
|
+
type: String,
|
|
433
|
+
default: "Message"
|
|
434
|
+
},
|
|
435
|
+
id: {
|
|
436
|
+
type: String,
|
|
437
|
+
default: ""
|
|
438
|
+
},
|
|
439
|
+
editable: {
|
|
440
|
+
type: Boolean,
|
|
441
|
+
default: true
|
|
442
|
+
},
|
|
443
|
+
extensions: {
|
|
444
|
+
type: Array,
|
|
445
|
+
default: () => []
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
emits: {
|
|
449
|
+
"update:modelValue": (_value) => true,
|
|
450
|
+
ready: (_editor) => true
|
|
451
|
+
},
|
|
452
|
+
setup(props, { attrs, emit, expose }) {
|
|
453
|
+
const editor = shallowRef();
|
|
454
|
+
onMounted(() => {
|
|
455
|
+
editor.value = new Editor({
|
|
456
|
+
extensions: [...getCompactEditorExtensions(), ...props.extensions],
|
|
457
|
+
content: props.modelValue,
|
|
458
|
+
editable: props.editable,
|
|
459
|
+
editorProps: { attributes: () => ({
|
|
460
|
+
role: "textbox",
|
|
461
|
+
"aria-multiline": "true",
|
|
462
|
+
"aria-label": props.label,
|
|
463
|
+
"aria-readonly": String(!props.editable),
|
|
464
|
+
id: props.id
|
|
465
|
+
}) },
|
|
466
|
+
onUpdate: ({ editor }) => emit("update:modelValue", editor.getJSON())
|
|
467
|
+
});
|
|
468
|
+
emit("ready", editor.value);
|
|
469
|
+
});
|
|
470
|
+
watch(() => props.modelValue, (value) => {
|
|
471
|
+
if (editor.value && JSON.stringify(value) !== JSON.stringify(editor.value.getJSON())) editor.value.commands.setContent(value, false);
|
|
472
|
+
}, { deep: true });
|
|
473
|
+
watch(() => [
|
|
474
|
+
props.id,
|
|
475
|
+
props.label,
|
|
476
|
+
props.editable
|
|
477
|
+
], () => editor.value?.setEditable(props.editable, false));
|
|
478
|
+
onBeforeUnmount(() => editor.value?.destroy());
|
|
479
|
+
expose({
|
|
480
|
+
focus: () => editor.value?.commands.focus(),
|
|
481
|
+
getEditor: () => editor.value
|
|
482
|
+
});
|
|
483
|
+
return () => h("div", {
|
|
484
|
+
...attrs,
|
|
485
|
+
id: void 0,
|
|
486
|
+
class: ["looma-compact-editor", attrs.class]
|
|
487
|
+
}, [editor.value ? h(EditorContent, { editor: editor.value }) : null]);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
function renderNode(node) {
|
|
491
|
+
if (node.type === "hardBreak") return h("br");
|
|
492
|
+
if (node.type === "text") {
|
|
493
|
+
let text = node.text ?? "";
|
|
494
|
+
for (const mark of node.marks ?? []) {
|
|
495
|
+
const tag = {
|
|
496
|
+
bold: "strong",
|
|
497
|
+
italic: "em",
|
|
498
|
+
code: "code"
|
|
499
|
+
}[mark.type];
|
|
500
|
+
if (tag) text = h(tag, {}, [text]);
|
|
501
|
+
}
|
|
502
|
+
return text;
|
|
503
|
+
}
|
|
504
|
+
const children = (node.content ?? []).map(renderNode);
|
|
505
|
+
return node.type === "paragraph" ? h("p", {}, children) : children;
|
|
506
|
+
}
|
|
507
|
+
/** Renders basic compact JSON as escaped Vue nodes, including during SSR. */
|
|
508
|
+
var LoomaCompactContent = defineComponent({
|
|
509
|
+
name: "LoomaCompactContent",
|
|
510
|
+
props: { content: {
|
|
511
|
+
type: Object,
|
|
512
|
+
required: true
|
|
513
|
+
} },
|
|
514
|
+
setup: (props) => () => h("div", { class: "looma-compact-content" }, [renderNode(props.content)])
|
|
515
|
+
});
|
|
516
|
+
//#endregion
|
|
517
|
+
export { LoomaCompactContent, LoomaCompactEditor, getCompactEditorExtensions };
|