@primeui/texteditor-core 0.0.1-alpha.1
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 +23 -0
- package/README.md +1 -0
- package/dist/chunk-22B454VC.mjs +83 -0
- package/dist/chunk-22B454VC.mjs.map +1 -0
- package/dist/chunk-3RKMABZR.mjs +320 -0
- package/dist/chunk-3RKMABZR.mjs.map +1 -0
- package/dist/chunk-6GY64GPU.mjs +18 -0
- package/dist/chunk-6GY64GPU.mjs.map +1 -0
- package/dist/chunk-6YDCG63C.mjs +833 -0
- package/dist/chunk-6YDCG63C.mjs.map +1 -0
- package/dist/chunk-6ZN5XRH2.mjs +45 -0
- package/dist/chunk-6ZN5XRH2.mjs.map +1 -0
- package/dist/chunk-72T5I4O4.mjs +76 -0
- package/dist/chunk-72T5I4O4.mjs.map +1 -0
- package/dist/chunk-7QCHSEN2.mjs +16 -0
- package/dist/chunk-7QCHSEN2.mjs.map +1 -0
- package/dist/chunk-AJOKUIQD.mjs +33 -0
- package/dist/chunk-AJOKUIQD.mjs.map +1 -0
- package/dist/chunk-AUTGNC2Q.mjs +197 -0
- package/dist/chunk-AUTGNC2Q.mjs.map +1 -0
- package/dist/chunk-CRAB2MFE.mjs +19 -0
- package/dist/chunk-CRAB2MFE.mjs.map +1 -0
- package/dist/chunk-DXPG5XMX.mjs +18 -0
- package/dist/chunk-DXPG5XMX.mjs.map +1 -0
- package/dist/chunk-E2KXUP3F.mjs +9 -0
- package/dist/chunk-E2KXUP3F.mjs.map +1 -0
- package/dist/chunk-EA2YI7LA.mjs +23 -0
- package/dist/chunk-EA2YI7LA.mjs.map +1 -0
- package/dist/chunk-F7BJWPT6.mjs +401 -0
- package/dist/chunk-F7BJWPT6.mjs.map +1 -0
- package/dist/chunk-FFCQLWS5.mjs +32 -0
- package/dist/chunk-FFCQLWS5.mjs.map +1 -0
- package/dist/chunk-GG56GLXC.mjs +42 -0
- package/dist/chunk-GG56GLXC.mjs.map +1 -0
- package/dist/chunk-GGPBV4BM.mjs +37 -0
- package/dist/chunk-GGPBV4BM.mjs.map +1 -0
- package/dist/chunk-H3RFOYCT.mjs +27 -0
- package/dist/chunk-H3RFOYCT.mjs.map +1 -0
- package/dist/chunk-IUQKSDKG.mjs +23 -0
- package/dist/chunk-IUQKSDKG.mjs.map +1 -0
- package/dist/chunk-J5LGTIGS.mjs +9 -0
- package/dist/chunk-J5LGTIGS.mjs.map +1 -0
- package/dist/chunk-KNZAMA6H.mjs +198 -0
- package/dist/chunk-KNZAMA6H.mjs.map +1 -0
- package/dist/chunk-MNKMKFLQ.mjs +27 -0
- package/dist/chunk-MNKMKFLQ.mjs.map +1 -0
- package/dist/chunk-MWT5PK3Z.mjs +52 -0
- package/dist/chunk-MWT5PK3Z.mjs.map +1 -0
- package/dist/chunk-NWRVBNBW.mjs +65 -0
- package/dist/chunk-NWRVBNBW.mjs.map +1 -0
- package/dist/chunk-OGEMGWLR.mjs +180 -0
- package/dist/chunk-OGEMGWLR.mjs.map +1 -0
- package/dist/chunk-PRFYR67X.mjs +60 -0
- package/dist/chunk-PRFYR67X.mjs.map +1 -0
- package/dist/chunk-PT2O4RV7.mjs +143 -0
- package/dist/chunk-PT2O4RV7.mjs.map +1 -0
- package/dist/chunk-PT5V6UYE.mjs +10 -0
- package/dist/chunk-PT5V6UYE.mjs.map +1 -0
- package/dist/chunk-RH45QRSV.mjs +26 -0
- package/dist/chunk-RH45QRSV.mjs.map +1 -0
- package/dist/chunk-RQ2HHNI6.mjs +55 -0
- package/dist/chunk-RQ2HHNI6.mjs.map +1 -0
- package/dist/chunk-TB7ZSSR2.mjs +6 -0
- package/dist/chunk-TB7ZSSR2.mjs.map +1 -0
- package/dist/chunk-TBQVZVKA.mjs +1891 -0
- package/dist/chunk-TBQVZVKA.mjs.map +1 -0
- package/dist/chunk-VWGQMUPD.mjs +182 -0
- package/dist/chunk-VWGQMUPD.mjs.map +1 -0
- package/dist/chunk-XKY2VYPW.mjs +26 -0
- package/dist/chunk-XKY2VYPW.mjs.map +1 -0
- package/dist/chunk-XSVIGDQR.mjs +22 -0
- package/dist/chunk-XSVIGDQR.mjs.map +1 -0
- package/dist/chunk-YHMP6AN3.mjs +231 -0
- package/dist/chunk-YHMP6AN3.mjs.map +1 -0
- package/dist/commands/index.d.mts +13 -0
- package/dist/commands/index.mjs +13 -0
- package/dist/commands/index.mjs.map +1 -0
- package/dist/createTextEditor.d.mts +7 -0
- package/dist/createTextEditor.mjs +31 -0
- package/dist/createTextEditor.mjs.map +1 -0
- package/dist/index.d.mts +17 -0
- package/dist/index.mjs +45 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugins/columnWidthPin.d.mts +5 -0
- package/dist/plugins/columnWidthPin.mjs +4 -0
- package/dist/plugins/columnWidthPin.mjs.map +1 -0
- package/dist/plugins/contextToolbar.d.mts +9 -0
- package/dist/plugins/contextToolbar.mjs +5 -0
- package/dist/plugins/contextToolbar.mjs.map +1 -0
- package/dist/plugins/defineTextEditorPlugin.d.mts +20 -0
- package/dist/plugins/defineTextEditorPlugin.mjs +4 -0
- package/dist/plugins/defineTextEditorPlugin.mjs.map +1 -0
- package/dist/plugins/inputRules.d.mts +14 -0
- package/dist/plugins/inputRules.mjs +8 -0
- package/dist/plugins/inputRules.mjs.map +1 -0
- package/dist/plugins/keymap.d.mts +16 -0
- package/dist/plugins/keymap.mjs +6 -0
- package/dist/plugins/keymap.mjs.map +1 -0
- package/dist/plugins/mention.d.mts +24 -0
- package/dist/plugins/mention.mjs +5 -0
- package/dist/plugins/mention.mjs.map +1 -0
- package/dist/plugins/mentionController.d.mts +16 -0
- package/dist/plugins/mentionController.mjs +4 -0
- package/dist/plugins/mentionController.mjs.map +1 -0
- package/dist/plugins/placeholder.d.mts +9 -0
- package/dist/plugins/placeholder.mjs +5 -0
- package/dist/plugins/placeholder.mjs.map +1 -0
- package/dist/plugins/registry.d.mts +7 -0
- package/dist/plugins/registry.mjs +4 -0
- package/dist/plugins/registry.mjs.map +1 -0
- package/dist/plugins/selectionHighlight.d.mts +14 -0
- package/dist/plugins/selectionHighlight.mjs +5 -0
- package/dist/plugins/selectionHighlight.mjs.map +1 -0
- package/dist/plugins/slashCommands.d.mts +28 -0
- package/dist/plugins/slashCommands.mjs +5 -0
- package/dist/plugins/slashCommands.mjs.map +1 -0
- package/dist/plugins/tableOverlay.d.mts +15 -0
- package/dist/plugins/tableOverlay.mjs +6 -0
- package/dist/plugins/tableOverlay.mjs.map +1 -0
- package/dist/plugins/trailingNode.d.mts +6 -0
- package/dist/plugins/trailingNode.mjs +4 -0
- package/dist/plugins/trailingNode.mjs.map +1 -0
- package/dist/position-DbkbTrFL.d.mts +50 -0
- package/dist/schema/index.d.mts +89 -0
- package/dist/schema/index.mjs +8 -0
- package/dist/schema/index.mjs.map +1 -0
- package/dist/serialization/index.d.mts +8 -0
- package/dist/serialization/index.mjs +5 -0
- package/dist/serialization/index.mjs.map +1 -0
- package/dist/texteditor.classes.d.mts +34 -0
- package/dist/texteditor.classes.mjs +4 -0
- package/dist/texteditor.classes.mjs.map +1 -0
- package/dist/texteditor.constants.d.mts +36 -0
- package/dist/texteditor.constants.mjs +4 -0
- package/dist/texteditor.constants.mjs.map +1 -0
- package/dist/texteditor.props.d.mts +5 -0
- package/dist/texteditor.props.mjs +4 -0
- package/dist/texteditor.props.mjs.map +1 -0
- package/dist/texteditor.refs.d.mts +5 -0
- package/dist/texteditor.refs.mjs +4 -0
- package/dist/texteditor.refs.mjs.map +1 -0
- package/dist/texteditor.state.d.mts +5 -0
- package/dist/texteditor.state.mjs +4 -0
- package/dist/texteditor.state.mjs.map +1 -0
- package/dist/ui/focus.d.mts +5 -0
- package/dist/ui/focus.mjs +4 -0
- package/dist/ui/focus.mjs.map +1 -0
- package/dist/ui/index.d.mts +6 -0
- package/dist/ui/index.mjs +9 -0
- package/dist/ui/index.mjs.map +1 -0
- package/dist/ui/keyboard.d.mts +4 -0
- package/dist/ui/keyboard.mjs +4 -0
- package/dist/ui/keyboard.mjs.map +1 -0
- package/dist/ui/menu.d.mts +10 -0
- package/dist/ui/menu.mjs +4 -0
- package/dist/ui/menu.mjs.map +1 -0
- package/dist/ui/positioning.d.mts +30 -0
- package/dist/ui/positioning.mjs +5 -0
- package/dist/ui/positioning.mjs.map +1 -0
- package/dist/ui/scroll.d.mts +6 -0
- package/dist/ui/scroll.mjs +4 -0
- package/dist/ui/scroll.mjs.map +1 -0
- package/dist/utils/index.d.mts +18 -0
- package/dist/utils/index.mjs +18 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { clearTypographyMarks } from './chunk-VWGQMUPD.mjs';
|
|
2
|
+
import { DEFAULT_HIGHLIGHT_COLOR } from './chunk-TB7ZSSR2.mjs';
|
|
3
|
+
import { sanitizeImageUrl, sanitizeTextAttr, sanitizeUrl } from './chunk-MNKMKFLQ.mjs';
|
|
4
|
+
import { inputRules, InputRule, wrappingInputRule, textblockTypeInputRule } from 'prosemirror-inputrules';
|
|
5
|
+
|
|
6
|
+
function headingRule(schema, nodeType, maxLevel) {
|
|
7
|
+
return new InputRule(new RegExp(`^(#{1,${maxLevel}})\\s$`), (state, match, start, end) => {
|
|
8
|
+
const level = match[1].length;
|
|
9
|
+
const $start = state.doc.resolve(start);
|
|
10
|
+
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) return null;
|
|
11
|
+
const tr = state.tr.delete(start, end).setBlockType(start, start, nodeType, { level });
|
|
12
|
+
const $pos = tr.doc.resolve(start);
|
|
13
|
+
clearTypographyMarks(tr, schema, $pos.start(), $pos.end());
|
|
14
|
+
return tr;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function blockquoteRule(nodeType) {
|
|
18
|
+
return wrappingInputRule(/^>\s$/, nodeType);
|
|
19
|
+
}
|
|
20
|
+
function bulletListRule(nodeType) {
|
|
21
|
+
return wrappingInputRule(/^[-*+]\s$/, nodeType);
|
|
22
|
+
}
|
|
23
|
+
function orderedListRule(nodeType) {
|
|
24
|
+
return wrappingInputRule(
|
|
25
|
+
/^(\d+)\.\s$/,
|
|
26
|
+
nodeType,
|
|
27
|
+
(match) => ({ start: +match[1] }),
|
|
28
|
+
(match, node) => node.childCount + node.attrs.start === +match[1]
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
function checkListRule(nodeType, itemType, schema) {
|
|
32
|
+
return new InputRule(/^\[([xX ])?\]\s$/, (state, match, start, end) => {
|
|
33
|
+
const checked = match[1] === "x" || match[1] === "X";
|
|
34
|
+
const listItem = itemType.create({ checked }, schema.nodes.paragraph.create());
|
|
35
|
+
const list = nodeType.create(null, listItem);
|
|
36
|
+
return state.tr.replaceWith(start - 1, end, list);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function codeBlockRule(nodeType) {
|
|
40
|
+
return textblockTypeInputRule(/^(?:```|~~~)([\w-]*)$/, nodeType, (match) => ({ language: match[1] || null }));
|
|
41
|
+
}
|
|
42
|
+
function horizontalRuleRule(nodeType) {
|
|
43
|
+
return new InputRule(/^---$/, (state, _match, start, end) => {
|
|
44
|
+
return state.tr.replaceWith(start - 1, end, nodeType.create());
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function markInputRule(regexp, markType) {
|
|
48
|
+
return new InputRule(regexp, (state, match, start, end) => {
|
|
49
|
+
const [fullMatch, openDelim, content] = match;
|
|
50
|
+
if (!content) return null;
|
|
51
|
+
const textStart = start + fullMatch.indexOf(openDelim);
|
|
52
|
+
const tr = state.tr;
|
|
53
|
+
tr.replaceWith(textStart, end, state.schema.text(content, [markType.create()]));
|
|
54
|
+
tr.removeStoredMark(markType);
|
|
55
|
+
return tr;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function autolinkRule(schema, markType) {
|
|
59
|
+
return new InputRule(/<((?:https?|mailto):[^>\s]+)>$/, (state, match, start, end) => {
|
|
60
|
+
const raw = match[1];
|
|
61
|
+
const href = sanitizeUrl(raw);
|
|
62
|
+
if (!href) return null;
|
|
63
|
+
const tr = state.tr;
|
|
64
|
+
tr.replaceWith(start, end, schema.text(raw, [markType.create({ href })]));
|
|
65
|
+
tr.removeStoredMark(markType);
|
|
66
|
+
return tr;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function linkRule(schema, markType) {
|
|
70
|
+
return new InputRule(/(?:^|[^!])\[([^\]]+)\]\(([^)\s]+)\)$/, (state, match, start, end) => {
|
|
71
|
+
const [fullMatch, text, rawHref] = match;
|
|
72
|
+
const href = sanitizeUrl(rawHref);
|
|
73
|
+
if (!text || !href) return null;
|
|
74
|
+
const linkStart = start + fullMatch.indexOf("[");
|
|
75
|
+
const tr = state.tr;
|
|
76
|
+
tr.replaceWith(linkStart, end, schema.text(text, [markType.create({ href })]));
|
|
77
|
+
tr.removeStoredMark(markType);
|
|
78
|
+
return tr;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function imageRule(schema, nodeType) {
|
|
82
|
+
return new InputRule(/!\[([^\]]*)\]\(([^)\s]+)\)$/, (state, match, start, end) => {
|
|
83
|
+
const [, alt, rawSrc] = match;
|
|
84
|
+
const src = sanitizeImageUrl(rawSrc);
|
|
85
|
+
if (!src) return null;
|
|
86
|
+
return state.tr.replaceWith(start, end, nodeType.create({ src, alt: sanitizeTextAttr(alt) || null }));
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function highlightRule(schema) {
|
|
90
|
+
return new InputRule(/(?:^|\s)(==)([^=]+)==$/, (state, match, start, end) => {
|
|
91
|
+
const [fullMatch, openDelim, content] = match;
|
|
92
|
+
if (!content || !schema.marks.textStyle) return null;
|
|
93
|
+
const textStart = start + fullMatch.indexOf(openDelim);
|
|
94
|
+
return state.tr.replaceWith(textStart, end, state.schema.text(content, [schema.marks.textStyle.create({ backgroundColor: DEFAULT_HIGHLIGHT_COLOR })]));
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function boldItalicRule(schema, bold, italic) {
|
|
98
|
+
return new InputRule(/(?:^|\s)(\*\*\*)([^*]+)\*\*\*$/, (state, match, start, end) => {
|
|
99
|
+
const [fullMatch, openDelim, content] = match;
|
|
100
|
+
if (!content) return null;
|
|
101
|
+
const textStart = start + fullMatch.indexOf(openDelim);
|
|
102
|
+
const tr = state.tr;
|
|
103
|
+
tr.replaceWith(textStart, end, state.schema.text(content, [bold.create(), italic.create()]));
|
|
104
|
+
tr.removeStoredMark(bold);
|
|
105
|
+
tr.removeStoredMark(italic);
|
|
106
|
+
return tr;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function tableRule(schema) {
|
|
110
|
+
return new InputRule(/^\|(.+\|.+)\|\s$/, (state, match, start) => {
|
|
111
|
+
if (!schema.nodes.table) return null;
|
|
112
|
+
const labels = match[1].split("|").map((h) => h.trim());
|
|
113
|
+
if (labels.length < 2 || labels.every((l) => !l)) return null;
|
|
114
|
+
const headerCells = labels.map((label) => schema.nodes.table_header.create(null, label ? schema.nodes.paragraph.create(null, schema.text(label)) : schema.nodes.paragraph.create()));
|
|
115
|
+
const bodyCells = labels.map(() => schema.nodes.table_cell.create(null, schema.nodes.paragraph.create()));
|
|
116
|
+
const rows = [schema.nodes.table_row.create(null, headerCells), schema.nodes.table_row.create(null, bodyCells)];
|
|
117
|
+
const table = schema.nodes.table.create(null, rows);
|
|
118
|
+
const $start = state.doc.resolve(start);
|
|
119
|
+
return state.tr.replaceWith($start.before(), $start.after(), table);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function createMarkdownInputRules(schema) {
|
|
123
|
+
const rules = [];
|
|
124
|
+
if (schema.nodes.heading) {
|
|
125
|
+
rules.push(headingRule(schema, schema.nodes.heading, 6));
|
|
126
|
+
}
|
|
127
|
+
if (schema.nodes.blockquote) {
|
|
128
|
+
rules.push(blockquoteRule(schema.nodes.blockquote));
|
|
129
|
+
}
|
|
130
|
+
if (schema.nodes.bullet_list) {
|
|
131
|
+
rules.push(bulletListRule(schema.nodes.bullet_list));
|
|
132
|
+
}
|
|
133
|
+
if (schema.nodes.ordered_list) {
|
|
134
|
+
rules.push(orderedListRule(schema.nodes.ordered_list));
|
|
135
|
+
}
|
|
136
|
+
if (schema.nodes.check_list && schema.nodes.check_list_item) {
|
|
137
|
+
rules.push(checkListRule(schema.nodes.check_list, schema.nodes.check_list_item, schema));
|
|
138
|
+
}
|
|
139
|
+
if (schema.nodes.code_block) {
|
|
140
|
+
rules.push(codeBlockRule(schema.nodes.code_block));
|
|
141
|
+
}
|
|
142
|
+
if (schema.nodes.horizontal_rule) {
|
|
143
|
+
rules.push(horizontalRuleRule(schema.nodes.horizontal_rule));
|
|
144
|
+
}
|
|
145
|
+
if (schema.nodes.table && schema.nodes.table_row && schema.nodes.table_header && schema.nodes.table_cell) {
|
|
146
|
+
rules.push(tableRule(schema));
|
|
147
|
+
}
|
|
148
|
+
if (schema.nodes.image) {
|
|
149
|
+
rules.push(imageRule(schema, schema.nodes.image));
|
|
150
|
+
}
|
|
151
|
+
if (schema.marks.link) {
|
|
152
|
+
rules.push(linkRule(schema, schema.marks.link));
|
|
153
|
+
rules.push(autolinkRule(schema, schema.marks.link));
|
|
154
|
+
}
|
|
155
|
+
if (schema.marks.textStyle) {
|
|
156
|
+
rules.push(highlightRule(schema));
|
|
157
|
+
}
|
|
158
|
+
if (schema.marks.bold && schema.marks.italic) {
|
|
159
|
+
rules.push(boldItalicRule(schema, schema.marks.bold, schema.marks.italic));
|
|
160
|
+
}
|
|
161
|
+
if (schema.marks.bold) {
|
|
162
|
+
rules.push(markInputRule(/(?:^|\s)(\*\*)(.+?)\*\*$/, schema.marks.bold));
|
|
163
|
+
rules.push(markInputRule(/(?:^|\s)(__)(.+?)__$/, schema.marks.bold));
|
|
164
|
+
}
|
|
165
|
+
if (schema.marks.italic) {
|
|
166
|
+
rules.push(markInputRule(/(?:^|[^*])(\*)([^*]+)\*$/, schema.marks.italic));
|
|
167
|
+
rules.push(markInputRule(/(?:^|\s)(_)([^_]+)_$/, schema.marks.italic));
|
|
168
|
+
}
|
|
169
|
+
if (schema.marks.code) {
|
|
170
|
+
rules.push(markInputRule(/(?:^|\s)(`)([^`]+)`$/, schema.marks.code));
|
|
171
|
+
}
|
|
172
|
+
if (schema.marks.strikethrough) {
|
|
173
|
+
rules.push(markInputRule(/(?:^|\s)(~~)(.+?)~~$/, schema.marks.strikethrough));
|
|
174
|
+
}
|
|
175
|
+
return inputRules({ rules });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { createMarkdownInputRules };
|
|
179
|
+
//# sourceMappingURL=chunk-OGEMGWLR.mjs.map
|
|
180
|
+
//# sourceMappingURL=chunk-OGEMGWLR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/inputRules.ts"],"names":[],"mappings":"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","file":"chunk-OGEMGWLR.mjs","sourcesContent":["import { InputRule, inputRules, textblockTypeInputRule, wrappingInputRule } from 'prosemirror-inputrules';\nimport type { MarkType, NodeType, Schema } from 'prosemirror-model';\nimport { clearTypographyMarks } from '../commands/blocks';\nimport { DEFAULT_HIGHLIGHT_COLOR } from '../commands/constants';\nimport { sanitizeImageUrl, sanitizeTextAttr, sanitizeUrl } from '../utils/url';\n\n// --- Block rules ---\n\n// Markdown \"# \" -> heading. Clears explicit font-size/font-family so the\n// heading owns its typography, matching the toolbar heading command.\nfunction headingRule(schema: Schema, nodeType: NodeType, maxLevel: number) {\n return new InputRule(new RegExp(`^(#{1,${maxLevel}})\\\\s$`), (state, match, start, end) => {\n const level = match[1].length;\n const $start = state.doc.resolve(start);\n\n if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) return null;\n\n const tr = state.tr.delete(start, end).setBlockType(start, start, nodeType, { level });\n const $pos = tr.doc.resolve(start);\n\n clearTypographyMarks(tr, schema, $pos.start(), $pos.end());\n\n return tr;\n });\n}\n\nfunction blockquoteRule(nodeType: NodeType) {\n return wrappingInputRule(/^>\\s$/, nodeType);\n}\n\nfunction bulletListRule(nodeType: NodeType) {\n return wrappingInputRule(/^[-*+]\\s$/, nodeType);\n}\n\nfunction orderedListRule(nodeType: NodeType) {\n return wrappingInputRule(\n /^(\\d+)\\.\\s$/,\n nodeType,\n (match) => ({ start: +match[1] }),\n (match, node) => node.childCount + node.attrs.start === +match[1]\n );\n}\n\nfunction checkListRule(nodeType: NodeType, itemType: NodeType, schema: Schema) {\n return new InputRule(/^\\[([xX ])?\\]\\s$/, (state, match, start, end) => {\n const checked = match[1] === 'x' || match[1] === 'X';\n const listItem = itemType.create({ checked }, schema.nodes.paragraph.create());\n const list = nodeType.create(null, listItem);\n\n return state.tr.replaceWith(start - 1, end, list);\n });\n}\n\nfunction codeBlockRule(nodeType: NodeType) {\n // ``` / ~~~ (or with a trailing lang) at the start of a line opens a code\n // block, capturing the optional language so it survives into serialization.\n return textblockTypeInputRule(/^(?:```|~~~)([\\w-]*)$/, nodeType, (match) => ({ language: match[1] || null }));\n}\n\nfunction horizontalRuleRule(nodeType: NodeType) {\n return new InputRule(/^---$/, (state, _match, start, end) => {\n return state.tr.replaceWith(start - 1, end, nodeType.create());\n });\n}\n\n// --- Inline mark rules ---\n\n/**\n * Creates an input rule that wraps text between delimiters with a mark.\n * Pattern must have two capture groups: (openingDelimiter)(content)\n * The closing delimiter is part of the regex but not captured.\n */\nfunction markInputRule(regexp: RegExp, markType: MarkType) {\n return new InputRule(regexp, (state, match, start, end) => {\n const [fullMatch, openDelim, content] = match;\n\n if (!content) return null;\n\n const textStart = start + fullMatch.indexOf(openDelim);\n const tr = state.tr;\n\n tr.replaceWith(textStart, end, state.schema.text(content, [markType.create()]));\n tr.removeStoredMark(markType);\n\n return tr;\n });\n}\n\n// Markdown autolink \"<https://...>\" -> clickable link over the URL.\nfunction autolinkRule(schema: Schema, markType: MarkType) {\n return new InputRule(/<((?:https?|mailto):[^>\\s]+)>$/, (state, match, start, end) => {\n const raw = match[1];\n const href = sanitizeUrl(raw);\n\n if (!href) return null;\n\n const tr = state.tr;\n\n tr.replaceWith(start, end, schema.text(raw, [markType.create({ href })]));\n tr.removeStoredMark(markType);\n\n return tr;\n });\n}\n\n// Markdown \"[text](url)\" -> linked text.\nfunction linkRule(schema: Schema, markType: MarkType) {\n return new InputRule(/(?:^|[^!])\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/, (state, match, start, end) => {\n const [fullMatch, text, rawHref] = match;\n const href = sanitizeUrl(rawHref);\n\n if (!text || !href) return null;\n\n // Skip the optional leading non-\"!\" char the regex consumed.\n const linkStart = start + fullMatch.indexOf('[');\n const tr = state.tr;\n\n tr.replaceWith(linkStart, end, schema.text(text, [markType.create({ href })]));\n tr.removeStoredMark(markType);\n\n return tr;\n });\n}\n\n// Markdown \"\" -> image.\nfunction imageRule(schema: Schema, nodeType: NodeType) {\n return new InputRule(/!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)$/, (state, match, start, end) => {\n const [, alt, rawSrc] = match;\n const src = sanitizeImageUrl(rawSrc);\n\n if (!src) return null;\n\n return state.tr.replaceWith(start, end, nodeType.create({ src, alt: sanitizeTextAttr(alt) || null }));\n });\n}\n\n// Markdown \"==text==\" -> highlighted text (default highlight color via textStyle).\nfunction highlightRule(schema: Schema) {\n return new InputRule(/(?:^|\\s)(==)([^=]+)==$/, (state, match, start, end) => {\n const [fullMatch, openDelim, content] = match;\n\n if (!content || !schema.marks.textStyle) return null;\n\n const textStart = start + fullMatch.indexOf(openDelim);\n\n return state.tr.replaceWith(textStart, end, state.schema.text(content, [schema.marks.textStyle.create({ backgroundColor: DEFAULT_HIGHLIGHT_COLOR })]));\n });\n}\n\n// Markdown \"***text***\" -> bold + italic.\nfunction boldItalicRule(schema: Schema, bold: MarkType, italic: MarkType) {\n return new InputRule(/(?:^|\\s)(\\*\\*\\*)([^*]+)\\*\\*\\*$/, (state, match, start, end) => {\n const [fullMatch, openDelim, content] = match;\n\n if (!content) return null;\n\n const textStart = start + fullMatch.indexOf(openDelim);\n const tr = state.tr;\n\n tr.replaceWith(textStart, end, state.schema.text(content, [bold.create(), italic.create()]));\n tr.removeStoredMark(bold);\n tr.removeStoredMark(italic);\n\n return tr;\n });\n}\n\n// Markdown table header \"| a | b |\" + trailing space -> table seeded with the\n// header cells. Requires at least two columns so a lone \"| x |\" in prose (a\n// single cell) doesn't prematurely convert; the inner pipe disambiguates intent.\nfunction tableRule(schema: Schema) {\n return new InputRule(/^\\|(.+\\|.+)\\|\\s$/, (state, match, start) => {\n if (!schema.nodes.table) return null;\n\n const labels = match[1].split('|').map((h) => h.trim());\n\n // Need genuine columns: at least two cells and no fully-empty header.\n if (labels.length < 2 || labels.every((l) => !l)) return null;\n\n const headerCells = labels.map((label) => schema.nodes.table_header.create(null, label ? schema.nodes.paragraph.create(null, schema.text(label)) : schema.nodes.paragraph.create()));\n const bodyCells = labels.map(() => schema.nodes.table_cell.create(null, schema.nodes.paragraph.create()));\n const rows = [schema.nodes.table_row.create(null, headerCells), schema.nodes.table_row.create(null, bodyCells)];\n const table = schema.nodes.table.create(null, rows);\n\n const $start = state.doc.resolve(start);\n\n return state.tr.replaceWith($start.before(), $start.after(), table);\n });\n}\n\n/**\n * Create all markdown input rules for the given schema.\n */\nexport function createMarkdownInputRules(schema: Schema) {\n const rules: InputRule[] = [];\n\n // Block rules\n if (schema.nodes.heading) {\n rules.push(headingRule(schema, schema.nodes.heading, 6));\n }\n\n if (schema.nodes.blockquote) {\n rules.push(blockquoteRule(schema.nodes.blockquote));\n }\n\n if (schema.nodes.bullet_list) {\n rules.push(bulletListRule(schema.nodes.bullet_list));\n }\n\n if (schema.nodes.ordered_list) {\n rules.push(orderedListRule(schema.nodes.ordered_list));\n }\n\n if (schema.nodes.check_list && schema.nodes.check_list_item) {\n rules.push(checkListRule(schema.nodes.check_list, schema.nodes.check_list_item, schema));\n }\n\n if (schema.nodes.code_block) {\n rules.push(codeBlockRule(schema.nodes.code_block));\n }\n\n if (schema.nodes.horizontal_rule) {\n rules.push(horizontalRuleRule(schema.nodes.horizontal_rule));\n }\n\n if (schema.nodes.table && schema.nodes.table_row && schema.nodes.table_header && schema.nodes.table_cell) {\n rules.push(tableRule(schema));\n }\n\n // Image before link: \"\" contains \"[alt](url)\", so the image rule\n // must win or the link rule would fire on the inner pattern.\n if (schema.nodes.image) {\n rules.push(imageRule(schema, schema.nodes.image));\n }\n\n if (schema.marks.link) {\n rules.push(linkRule(schema, schema.marks.link));\n rules.push(autolinkRule(schema, schema.marks.link));\n }\n\n if (schema.marks.textStyle) {\n rules.push(highlightRule(schema));\n }\n\n // Inline mark rules — *** (bold+italic) before ** before * to avoid conflicts.\n if (schema.marks.bold && schema.marks.italic) {\n rules.push(boldItalicRule(schema, schema.marks.bold, schema.marks.italic));\n }\n\n if (schema.marks.bold) {\n rules.push(markInputRule(/(?:^|\\s)(\\*\\*)(.+?)\\*\\*$/, schema.marks.bold));\n // __text__ -> bold; leading boundary keeps intra-word underscores intact.\n rules.push(markInputRule(/(?:^|\\s)(__)(.+?)__$/, schema.marks.bold));\n }\n\n if (schema.marks.italic) {\n rules.push(markInputRule(/(?:^|[^*])(\\*)([^*]+)\\*$/, schema.marks.italic));\n // _text_ -> italic; requires a boundary before \"_\" so foo_bar_baz stays plain.\n rules.push(markInputRule(/(?:^|\\s)(_)([^_]+)_$/, schema.marks.italic));\n }\n\n if (schema.marks.code) {\n rules.push(markInputRule(/(?:^|\\s)(`)([^`]+)`$/, schema.marks.code));\n }\n\n if (schema.marks.strikethrough) {\n rules.push(markInputRule(/(?:^|\\s)(~~)(.+?)~~$/, schema.marks.strikethrough));\n }\n\n return inputRules({ rules });\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { DOMParser } from 'prosemirror-model';
|
|
2
|
+
|
|
3
|
+
// src/serialization/htmlParser.ts
|
|
4
|
+
var parserCache = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
function getParser(schema) {
|
|
6
|
+
let parser = parserCache.get(schema);
|
|
7
|
+
if (!parser) {
|
|
8
|
+
parser = DOMParser.fromSchema(schema);
|
|
9
|
+
parserCache.set(schema, parser);
|
|
10
|
+
}
|
|
11
|
+
return parser;
|
|
12
|
+
}
|
|
13
|
+
var MAX_PARSE_DEPTH = 200;
|
|
14
|
+
var MAX_PARSE_TAGS = 5e4;
|
|
15
|
+
function tagCountExceeds(html, max) {
|
|
16
|
+
let count = 0;
|
|
17
|
+
let i = -1;
|
|
18
|
+
while ((i = html.indexOf("<", i + 1)) !== -1) {
|
|
19
|
+
const next = html.charCodeAt(i + 1);
|
|
20
|
+
if (next !== 47 && next !== 33 && next !== 63 && ++count > max) return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
function exceedsMaxDepth(root, max) {
|
|
25
|
+
const stack = [];
|
|
26
|
+
for (const child of Array.from(root.children)) stack.push({ el: child, depth: 1 });
|
|
27
|
+
while (stack.length) {
|
|
28
|
+
const { el, depth } = stack.pop();
|
|
29
|
+
if (depth > max) return true;
|
|
30
|
+
for (const child of Array.from(el.children)) stack.push({ el: child, depth: depth + 1 });
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
function htmlExceedsMaxDepth(html) {
|
|
35
|
+
if (tagCountExceeds(html, MAX_PARSE_TAGS)) return true;
|
|
36
|
+
const tpl = document.createElement("template");
|
|
37
|
+
tpl.innerHTML = html;
|
|
38
|
+
return exceedsMaxDepth(tpl.content, MAX_PARSE_DEPTH);
|
|
39
|
+
}
|
|
40
|
+
function htmlToInertFragment(html) {
|
|
41
|
+
if (tagCountExceeds(html, MAX_PARSE_TAGS)) {
|
|
42
|
+
throw new RangeError(`HTML exceeds the maximum of ${MAX_PARSE_TAGS} tags`);
|
|
43
|
+
}
|
|
44
|
+
const tpl = document.createElement("template");
|
|
45
|
+
tpl.innerHTML = html;
|
|
46
|
+
if (exceedsMaxDepth(tpl.content, MAX_PARSE_DEPTH)) {
|
|
47
|
+
throw new RangeError(`HTML nesting depth exceeds the maximum of ${MAX_PARSE_DEPTH}`);
|
|
48
|
+
}
|
|
49
|
+
return tpl.content;
|
|
50
|
+
}
|
|
51
|
+
function htmlToDoc(html, schema) {
|
|
52
|
+
return getParser(schema).parse(htmlToInertFragment(html));
|
|
53
|
+
}
|
|
54
|
+
function htmlToSlice(html, schema) {
|
|
55
|
+
return getParser(schema).parseSlice(htmlToInertFragment(html), { preserveWhitespace: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { htmlExceedsMaxDepth, htmlToDoc, htmlToInertFragment, htmlToSlice };
|
|
59
|
+
//# sourceMappingURL=chunk-PRFYR67X.mjs.map
|
|
60
|
+
//# sourceMappingURL=chunk-PRFYR67X.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/serialization/htmlParser.ts"],"names":["ProseMirrorDOMParser"],"mappings":"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","file":"chunk-PRFYR67X.mjs","sourcesContent":["import { DOMParser as ProseMirrorDOMParser, Slice, type Schema } from 'prosemirror-model';\n\nconst parserCache = new WeakMap<Schema, ProseMirrorDOMParser>();\n\nfunction getParser(schema: Schema): ProseMirrorDOMParser {\n let parser = parserCache.get(schema);\n\n if (!parser) {\n parser = ProseMirrorDOMParser.fromSchema(schema);\n parserCache.set(schema, parser);\n }\n\n return parser;\n}\n\n// Maximum element nesting depth allowed in incoming HTML. Pathologically deep\n// input (thousands of nested nodes) overflows the parser/renderer call stack and\n// crashes the editor; reject it before it reaches ProseMirror.\nconst MAX_PARSE_DEPTH = 200;\n// Cheap pre-parse cap on total open tags. Parsing the DOM tree itself is the\n// expensive step (super-linear for huge/deep input), so reject obviously\n// oversized HTML by counting tags in the string before ever building a tree.\nconst MAX_PARSE_TAGS = 50000;\n\nfunction tagCountExceeds(html: string, max: number): boolean {\n let count = 0;\n let i = -1;\n\n while ((i = html.indexOf('<', i + 1)) !== -1) {\n const next = html.charCodeAt(i + 1);\n\n // Count element open tags only (skip '</', '<!', '<?').\n if (next !== 0x2f && next !== 0x21 && next !== 0x3f && ++count > max) return true;\n }\n\n return false;\n}\n\nfunction exceedsMaxDepth(root: ParentNode, max: number): boolean {\n // Iterative DFS (no recursion — recursion would overflow on the very input we guard against).\n const stack: Array<{ el: Element; depth: number }> = [];\n\n for (const child of Array.from(root.children)) stack.push({ el: child, depth: 1 });\n\n while (stack.length) {\n const { el, depth } = stack.pop()!;\n\n if (depth > max) return true;\n\n for (const child of Array.from(el.children)) stack.push({ el: child, depth: depth + 1 });\n }\n\n return false;\n}\n\n// True when an HTML string is too large or nests deeper than MAX_PARSE_DEPTH.\nexport function htmlExceedsMaxDepth(html: string): boolean {\n if (tagCountExceeds(html, MAX_PARSE_TAGS)) return true;\n\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n return exceedsMaxDepth(tpl.content, MAX_PARSE_DEPTH);\n}\n\n// Parse untrusted HTML into an INERT fragment. A <template>'s content document\n// is inert: <img>/<iframe> resources are never fetched and event handlers like\n// onerror never fire, so no side effect runs before ProseMirror strips bad attrs.\nexport function htmlToInertFragment(html: string): DocumentFragment {\n if (tagCountExceeds(html, MAX_PARSE_TAGS)) {\n throw new RangeError(`HTML exceeds the maximum of ${MAX_PARSE_TAGS} tags`);\n }\n\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n if (exceedsMaxDepth(tpl.content, MAX_PARSE_DEPTH)) {\n throw new RangeError(`HTML nesting depth exceeds the maximum of ${MAX_PARSE_DEPTH}`);\n }\n\n return tpl.content;\n}\n\nexport function htmlToDoc(html: string, schema: Schema) {\n return getParser(schema).parse(htmlToInertFragment(html));\n}\n\n/**\n * Parse HTML into a maximally-open {@link Slice}, suitable for\n * `tr.replaceSelection(slice)` at any cursor position.\n *\n * Unlike `htmlToDoc(...).content` — which yields closed block nodes and throws\n * `RangeError: Invalid content for node` when spliced into an inline position —\n * an open slice lets ProseMirror fit block OR inline content into the current\n * selection context.\n */\nexport function htmlToSlice(html: string, schema: Schema): Slice {\n return getParser(schema).parseSlice(htmlToInertFragment(html), { preserveWhitespace: true });\n}\n"]}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { textEditorClasses } from './chunk-GG56GLXC.mjs';
|
|
2
|
+
import { PluginKey, Plugin } from 'prosemirror-state';
|
|
3
|
+
import { DecorationSet, Decoration } from 'prosemirror-view';
|
|
4
|
+
|
|
5
|
+
var mentionPluginKey = new PluginKey("mention");
|
|
6
|
+
function getCaretCoords(view, pos) {
|
|
7
|
+
const coords = view.coordsAtPos(pos);
|
|
8
|
+
return {
|
|
9
|
+
top: coords.top,
|
|
10
|
+
left: coords.left,
|
|
11
|
+
bottom: coords.bottom,
|
|
12
|
+
height: coords.bottom - coords.top,
|
|
13
|
+
width: 0
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function findMentionTrigger(doc, cursorPos) {
|
|
17
|
+
const $pos = doc.resolve(cursorPos);
|
|
18
|
+
const parentOffset = $pos.parentOffset;
|
|
19
|
+
const parentText = $pos.parent.textBetween(0, parentOffset, void 0, "\uFFFC");
|
|
20
|
+
for (let i = parentText.length - 1; i >= 0; i--) {
|
|
21
|
+
const char = parentText[i];
|
|
22
|
+
if (char === " " || char === "\n" || char === "\xA0") return -1;
|
|
23
|
+
if (char === "@") {
|
|
24
|
+
if (i === 0 || parentText[i - 1] === " " || parentText[i - 1] === "\n" || parentText[i - 1] === "\xA0") {
|
|
25
|
+
return $pos.start() + i;
|
|
26
|
+
}
|
|
27
|
+
return -1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return -1;
|
|
31
|
+
}
|
|
32
|
+
function createMentionPlugin(_schema, callbacks) {
|
|
33
|
+
let activated = false;
|
|
34
|
+
return new Plugin({
|
|
35
|
+
key: mentionPluginKey,
|
|
36
|
+
props: {
|
|
37
|
+
handleDOMEvents: {
|
|
38
|
+
keydown(view, event) {
|
|
39
|
+
if (event.key === "Escape" && activated) {
|
|
40
|
+
activated = false;
|
|
41
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
42
|
+
view.dispatch(view.state.tr);
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
},
|
|
46
|
+
blur(view) {
|
|
47
|
+
if (activated) {
|
|
48
|
+
activated = false;
|
|
49
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
50
|
+
view.dispatch(view.state.tr);
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
handleTextInput(_view, _from, _to, text) {
|
|
56
|
+
if (text.endsWith("@")) {
|
|
57
|
+
activated = true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
},
|
|
61
|
+
handleKeyDown(view, event) {
|
|
62
|
+
if (event.key !== "Backspace") return false;
|
|
63
|
+
const { $from, empty } = view.state.selection;
|
|
64
|
+
if (!empty) return false;
|
|
65
|
+
const parent = $from.parent;
|
|
66
|
+
const offset = $from.parentOffset;
|
|
67
|
+
if (offset < 2) return false;
|
|
68
|
+
const charBefore = parent.textBetween(offset - 1, offset, void 0, "\uFFFC");
|
|
69
|
+
if (charBefore !== " " && charBefore !== "\xA0") return false;
|
|
70
|
+
const $beforeSpace = view.state.doc.resolve($from.pos - 1);
|
|
71
|
+
const mentionNode = $beforeSpace.nodeBefore;
|
|
72
|
+
if (!mentionNode || mentionNode.type.name !== "mention") return false;
|
|
73
|
+
const tr = view.state.tr.delete($from.pos - 1 - mentionNode.nodeSize, $from.pos);
|
|
74
|
+
view.dispatch(tr);
|
|
75
|
+
return true;
|
|
76
|
+
},
|
|
77
|
+
decorations(state) {
|
|
78
|
+
if (!activated) return DecorationSet.empty;
|
|
79
|
+
const { from } = state.selection;
|
|
80
|
+
const triggerPos = findMentionTrigger(state.doc, from);
|
|
81
|
+
if (triggerPos < 0) return DecorationSet.empty;
|
|
82
|
+
const deco = Decoration.inline(triggerPos, from, {
|
|
83
|
+
class: textEditorClasses.mentionTyping,
|
|
84
|
+
"data-mention-query": "true"
|
|
85
|
+
});
|
|
86
|
+
return DecorationSet.create(state.doc, [deco]);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
view() {
|
|
90
|
+
return {
|
|
91
|
+
update(view) {
|
|
92
|
+
if (!activated) return;
|
|
93
|
+
const { from, to } = view.state.selection;
|
|
94
|
+
if (from !== to) {
|
|
95
|
+
activated = false;
|
|
96
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const triggerPos = findMentionTrigger(view.state.doc, from);
|
|
100
|
+
if (triggerPos >= 0) {
|
|
101
|
+
const text = from > triggerPos + 1 ? view.state.doc.textBetween(triggerPos + 1, from, void 0, "\uFFFC") : "";
|
|
102
|
+
callbacks.onUpdate({
|
|
103
|
+
active: true,
|
|
104
|
+
text,
|
|
105
|
+
position: getCaretCoords(view, triggerPos)
|
|
106
|
+
});
|
|
107
|
+
} else {
|
|
108
|
+
activated = false;
|
|
109
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function insertMention(view, schema, data, options) {
|
|
117
|
+
const { from } = view.state.selection;
|
|
118
|
+
const triggerPos = findMentionTrigger(view.state.doc, from);
|
|
119
|
+
if (triggerPos < 0) return;
|
|
120
|
+
let label = "";
|
|
121
|
+
if (options?.template) {
|
|
122
|
+
label = options.template(data);
|
|
123
|
+
} else if (options?.filterField && data && typeof data === "object") {
|
|
124
|
+
label = String(data[options.filterField] || "");
|
|
125
|
+
} else if (data && typeof data === "object" && "name" in data) {
|
|
126
|
+
label = String(data.name || "");
|
|
127
|
+
} else {
|
|
128
|
+
label = String(data);
|
|
129
|
+
}
|
|
130
|
+
const id = data && typeof data === "object" && "id" in data ? String(data.id) : null;
|
|
131
|
+
const mentionNode = schema.nodes.mention.create({
|
|
132
|
+
id,
|
|
133
|
+
label,
|
|
134
|
+
data
|
|
135
|
+
});
|
|
136
|
+
const tr = view.state.tr.replaceWith(triggerPos, from, mentionNode).insertText("\xA0");
|
|
137
|
+
view.dispatch(tr);
|
|
138
|
+
view.focus();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export { createMentionPlugin, insertMention, mentionPluginKey };
|
|
142
|
+
//# sourceMappingURL=chunk-PT2O4RV7.mjs.map
|
|
143
|
+
//# sourceMappingURL=chunk-PT2O4RV7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/mention.ts"],"names":[],"mappings":"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","file":"chunk-PT2O4RV7.mjs","sourcesContent":["import type { CaretPosition } from '@primeui/texteditor-types';\nimport type { Node as PMNode, Schema } from 'prosemirror-model';\nimport { Plugin, PluginKey } from 'prosemirror-state';\nimport type { EditorView } from 'prosemirror-view';\nimport { Decoration, DecorationSet } from 'prosemirror-view';\nimport { textEditorClasses as classes } from '../texteditor.classes';\n\nexport const mentionPluginKey = new PluginKey('mention');\n\nexport interface MentionUpdate {\n active: boolean;\n text: string;\n position: CaretPosition | null;\n}\n\ninterface MentionPluginCallbacks {\n onUpdate: (update: MentionUpdate) => void;\n}\n\nfunction getCaretCoords(view: EditorView, pos: number): CaretPosition {\n const coords = view.coordsAtPos(pos);\n\n return {\n top: coords.top,\n left: coords.left,\n bottom: coords.bottom,\n height: coords.bottom - coords.top,\n width: 0\n };\n}\n\n/**\n * Scan backwards from cursor to find '@' preceded by whitespace or start of block.\n * Returns the document position of '@' if found, or -1.\n */\nfunction findMentionTrigger(doc: PMNode, cursorPos: number): number {\n const $pos = doc.resolve(cursorPos);\n const parentOffset = $pos.parentOffset;\n const parentText = $pos.parent.textBetween(0, parentOffset, undefined, '\\ufffc');\n\n // Scan backwards from cursor to find '@'\n for (let i = parentText.length - 1; i >= 0; i--) {\n const char = parentText[i];\n\n // Found a space before finding '@' — no mention\n if (char === ' ' || char === '\\n' || char === '\\u00A0') return -1;\n\n if (char === '@') {\n // '@' must be at start of text or preceded by whitespace\n if (i === 0 || parentText[i - 1] === ' ' || parentText[i - 1] === '\\n' || parentText[i - 1] === '\\u00A0') {\n // Convert parent-relative offset to document position\n return $pos.start() + i;\n }\n\n return -1;\n }\n }\n\n return -1;\n}\n\nexport function createMentionPlugin(_schema: Schema, callbacks: MentionPluginCallbacks) {\n let activated = false;\n\n return new Plugin({\n key: mentionPluginKey,\n props: {\n handleDOMEvents: {\n keydown(view, event) {\n if (event.key === 'Escape' && activated) {\n activated = false;\n // Notify directly — the view.update hook early-returns on !activated and can't emit it.\n callbacks.onUpdate({ active: false, text: '', position: null });\n view.dispatch(view.state.tr);\n }\n\n return false;\n },\n blur(view) {\n if (activated) {\n activated = false;\n callbacks.onUpdate({ active: false, text: '', position: null });\n view.dispatch(view.state.tr);\n }\n\n return false;\n }\n },\n handleTextInput(_view, _from, _to, text) {\n if (text.endsWith('@')) {\n activated = true;\n }\n\n return false;\n },\n handleKeyDown(view, event) {\n if (event.key !== 'Backspace') return false;\n\n const { $from, empty } = view.state.selection;\n\n if (!empty) return false;\n\n const parent = $from.parent;\n const offset = $from.parentOffset;\n\n if (offset < 2) return false;\n\n // Check if character before cursor is whitespace\n const charBefore = parent.textBetween(offset - 1, offset, undefined, '\\ufffc');\n\n if (charBefore !== ' ' && charBefore !== '\\u00A0') return false;\n\n // Check if node before the whitespace is a mention\n const $beforeSpace = view.state.doc.resolve($from.pos - 1);\n const mentionNode = $beforeSpace.nodeBefore;\n\n if (!mentionNode || mentionNode.type.name !== 'mention') return false;\n\n // Delete both the whitespace and the mention in one operation\n const tr = view.state.tr.delete($from.pos - 1 - mentionNode.nodeSize, $from.pos);\n\n view.dispatch(tr);\n\n return true;\n },\n decorations(state) {\n if (!activated) return DecorationSet.empty;\n\n const { from } = state.selection;\n const triggerPos = findMentionTrigger(state.doc, from);\n\n if (triggerPos < 0) return DecorationSet.empty;\n\n const deco = Decoration.inline(triggerPos, from, {\n class: classes.mentionTyping,\n 'data-mention-query': 'true'\n });\n\n return DecorationSet.create(state.doc, [deco]);\n }\n },\n view() {\n return {\n update(view) {\n if (!activated) return;\n\n const { from, to } = view.state.selection;\n\n // Deactivate on range selection\n if (from !== to) {\n activated = false;\n callbacks.onUpdate({ active: false, text: '', position: null });\n\n return;\n }\n\n const triggerPos = findMentionTrigger(view.state.doc, from);\n\n if (triggerPos >= 0) {\n const text = from > triggerPos + 1 ? view.state.doc.textBetween(triggerPos + 1, from, undefined, '\\ufffc') : '';\n\n callbacks.onUpdate({\n active: true,\n text,\n position: getCaretCoords(view, triggerPos)\n });\n } else {\n activated = false;\n callbacks.onUpdate({ active: false, text: '', position: null });\n }\n }\n };\n }\n });\n}\n\n/**\n * Insert a mention node, replacing the '@query' text.\n */\nexport function insertMention(view: EditorView, schema: Schema, data: unknown, options?: { filterField?: string; template?: (data: unknown) => string }) {\n const { from } = view.state.selection;\n const triggerPos = findMentionTrigger(view.state.doc, from);\n\n if (triggerPos < 0) return;\n\n // Determine the label\n let label = '';\n\n if (options?.template) {\n label = options.template(data);\n } else if (options?.filterField && data && typeof data === 'object') {\n label = String((data as Record<string, unknown>)[options.filterField] || '');\n } else if (data && typeof data === 'object' && 'name' in data) {\n label = String((data as Record<string, unknown>).name || '');\n } else {\n label = String(data);\n }\n\n const id = data && typeof data === 'object' && 'id' in data ? String((data as Record<string, unknown>).id) : null;\n\n const mentionNode = schema.nodes.mention.create({\n id,\n label,\n data\n });\n\n // Replace from '@' position to cursor\n const tr = view.state.tr.replaceWith(triggerPos, from, mentionNode).insertText('\\u00A0'); // Non-breaking space after mention\n\n view.dispatch(tr);\n view.focus();\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/texteditor.state.ts
|
|
2
|
+
var defaultTextEditorState = {
|
|
3
|
+
formatState: null,
|
|
4
|
+
isMentionEnabled: false,
|
|
5
|
+
isSlashCommandsEnabled: false
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export { defaultTextEditorState };
|
|
9
|
+
//# sourceMappingURL=chunk-PT5V6UYE.mjs.map
|
|
10
|
+
//# sourceMappingURL=chunk-PT5V6UYE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/texteditor.state.ts"],"names":[],"mappings":";AAEO,IAAM,sBAAA,GAA0C;AAAA,EACnD,WAAA,EAAa,IAAA;AAAA,EACb,gBAAA,EAAkB,KAAA;AAAA,EAClB,sBAAA,EAAwB;AAC5B","file":"chunk-PT5V6UYE.mjs","sourcesContent":["import type { TextEditorState } from '@primeui/texteditor-types';\n\nexport const defaultTextEditorState: TextEditorState = {\n formatState: null,\n isMentionEnabled: false,\n isSlashCommandsEnabled: false\n};\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/ui/menu.ts
|
|
2
|
+
var MENU_ITEM_SELECTOR = 'button:not([hidden]):not([disabled]), [role="menuitem"]:not([hidden]):not([disabled])';
|
|
3
|
+
function getVisibleMenuItems(container) {
|
|
4
|
+
return Array.from(container.querySelectorAll(MENU_ITEM_SELECTOR));
|
|
5
|
+
}
|
|
6
|
+
function filterMenuItemsByText(items, query) {
|
|
7
|
+
const q = query.trim().toLowerCase();
|
|
8
|
+
const visible = [];
|
|
9
|
+
let hiddenCount = 0;
|
|
10
|
+
for (const item of items) {
|
|
11
|
+
const match = q === "" || (item.textContent ?? "").toLowerCase().includes(q);
|
|
12
|
+
item.hidden = !match;
|
|
13
|
+
if (match) visible.push(item);
|
|
14
|
+
else hiddenCount++;
|
|
15
|
+
}
|
|
16
|
+
return { visible, hiddenCount };
|
|
17
|
+
}
|
|
18
|
+
function assignActiveDescendantId(item, idPrefix, counter) {
|
|
19
|
+
if (!item) return null;
|
|
20
|
+
if (!item.id) item.id = `${idPrefix}-option-${++counter.value}`;
|
|
21
|
+
return item.id;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { assignActiveDescendantId, filterMenuItemsByText, getVisibleMenuItems };
|
|
25
|
+
//# sourceMappingURL=chunk-RH45QRSV.mjs.map
|
|
26
|
+
//# sourceMappingURL=chunk-RH45QRSV.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/menu.ts"],"names":[],"mappings":";AAAA,IAAM,kBAAA,GAAqB,uFAAA;AAEpB,SAAS,oBAAoB,SAAA,EAAuC;AACvE,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,gBAAA,CAA8B,kBAAkB,CAAC,CAAA;AACjF;AAEO,SAAS,qBAAA,CAAsB,OAAsB,KAAA,EAAgE;AACxH,EAAA,MAAM,CAAA,GAAI,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY;AACnC,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,IAAI,WAAA,GAAc,CAAA;AAElB,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACtB,IAAA,MAAM,KAAA,GAAQ,MAAM,EAAA,IAAA,CAAO,IAAA,CAAK,eAAe,EAAA,EAAI,WAAA,EAAY,CAAE,QAAA,CAAS,CAAC,CAAA;AAE3E,IAAA,IAAA,CAAK,SAAS,CAAC,KAAA;AAEf,IAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA;AAAA,SACvB,WAAA,EAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,SAAS,WAAA,EAAY;AAClC;AAEO,SAAS,wBAAA,CAAyB,IAAA,EAA0B,QAAA,EAAkB,OAAA,EAA2C;AAC5H,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,EAAA,IAAI,CAAC,IAAA,CAAK,EAAA,EAAI,IAAA,CAAK,EAAA,GAAK,GAAG,QAAQ,CAAA,QAAA,EAAW,EAAE,OAAA,CAAQ,KAAK,CAAA,CAAA;AAE7D,EAAA,OAAO,IAAA,CAAK,EAAA;AAChB","file":"chunk-RH45QRSV.mjs","sourcesContent":["const MENU_ITEM_SELECTOR = 'button:not([hidden]):not([disabled]), [role=\"menuitem\"]:not([hidden]):not([disabled])';\n\nexport function getVisibleMenuItems(container: HTMLElement): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(MENU_ITEM_SELECTOR));\n}\n\nexport function filterMenuItemsByText(items: HTMLElement[], query: string): { visible: HTMLElement[]; hiddenCount: number } {\n const q = query.trim().toLowerCase();\n const visible: HTMLElement[] = [];\n let hiddenCount = 0;\n\n for (const item of items) {\n const match = q === '' || (item.textContent ?? '').toLowerCase().includes(q);\n\n item.hidden = !match;\n\n if (match) visible.push(item);\n else hiddenCount++;\n }\n\n return { visible, hiddenCount };\n}\n\nexport function assignActiveDescendantId(item: HTMLElement | null, idPrefix: string, counter: { value: number }): string | null {\n if (!item) return null;\n\n if (!item.id) item.id = `${idPrefix}-option-${++counter.value}`;\n\n return item.id;\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { textEditorClasses } from './chunk-GG56GLXC.mjs';
|
|
2
|
+
import { PluginKey, Plugin } from 'prosemirror-state';
|
|
3
|
+
import { DecorationSet, Decoration } from 'prosemirror-view';
|
|
4
|
+
|
|
5
|
+
var selectionHighlightKey = new PluginKey("selectionHighlight");
|
|
6
|
+
var EMPTY_STATE = { active: false, from: -1, to: -1, decorations: DecorationSet.empty };
|
|
7
|
+
function createSelectionHighlightPlugin() {
|
|
8
|
+
return new Plugin({
|
|
9
|
+
key: selectionHighlightKey,
|
|
10
|
+
state: {
|
|
11
|
+
init() {
|
|
12
|
+
return EMPTY_STATE;
|
|
13
|
+
},
|
|
14
|
+
apply(tr, prev, _oldState, newState) {
|
|
15
|
+
const meta = tr.getMeta(selectionHighlightKey);
|
|
16
|
+
if (meta?.show) {
|
|
17
|
+
const { from: from2, to: to2 } = meta;
|
|
18
|
+
if (from2 === to2) return EMPTY_STATE;
|
|
19
|
+
const deco = Decoration.inline(from2, to2, {
|
|
20
|
+
class: textEditorClasses.selection
|
|
21
|
+
});
|
|
22
|
+
return { active: true, from: from2, to: to2, decorations: DecorationSet.create(tr.doc, [deco]) };
|
|
23
|
+
}
|
|
24
|
+
if (!prev.active) return prev;
|
|
25
|
+
const { from, to } = newState.selection;
|
|
26
|
+
if (from === to) {
|
|
27
|
+
return EMPTY_STATE;
|
|
28
|
+
}
|
|
29
|
+
if (tr.docChanged) {
|
|
30
|
+
const mappedFrom = tr.mapping.map(prev.from);
|
|
31
|
+
const mappedTo = tr.mapping.map(prev.to);
|
|
32
|
+
const deco = Decoration.inline(mappedFrom, mappedTo, {
|
|
33
|
+
class: textEditorClasses.selection
|
|
34
|
+
});
|
|
35
|
+
return { active: true, from: mappedFrom, to: mappedTo, decorations: DecorationSet.create(tr.doc, [deco]) };
|
|
36
|
+
}
|
|
37
|
+
return prev;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
props: {
|
|
41
|
+
decorations(state) {
|
|
42
|
+
return selectionHighlightKey.getState(state)?.decorations ?? DecorationSet.empty;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function preserveSelection(view) {
|
|
48
|
+
const { from, to } = view.state.selection;
|
|
49
|
+
if (from === to) return;
|
|
50
|
+
view.dispatch(view.state.tr.setMeta(selectionHighlightKey, { show: true, from, to }));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { createSelectionHighlightPlugin, preserveSelection, selectionHighlightKey };
|
|
54
|
+
//# sourceMappingURL=chunk-RQ2HHNI6.mjs.map
|
|
55
|
+
//# sourceMappingURL=chunk-RQ2HHNI6.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/selectionHighlight.ts"],"names":["from","to"],"mappings":";;;;AAKO,IAAM,qBAAA,GAAwB,IAAI,SAAA,CAAU,oBAAoB;AASvE,IAAM,WAAA,GAA8B,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,IAAI,EAAA,EAAI,EAAA,EAAI,WAAA,EAAa,aAAA,CAAc,KAAA,EAAM;AAEjG,SAAS,8BAAA,GAAiC;AAC7C,EAAA,OAAO,IAAI,MAAA,CAAO;AAAA,IACd,GAAA,EAAK,qBAAA;AAAA,IACL,KAAA,EAAO;AAAA,MACH,IAAA,GAAuB;AACnB,QAAA,OAAO,WAAA;AAAA,MACX,CAAA;AAAA,MACA,KAAA,CAAM,EAAA,EAAI,IAAA,EAAM,SAAA,EAAW,QAAA,EAA0B;AACjD,QAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,qBAAqB,CAAA;AAE7C,QAAA,IAAI,MAAM,IAAA,EAAM;AACZ,UAAA,MAAM,EAAE,IAAA,EAAAA,KAAAA,EAAM,EAAA,EAAAC,KAAG,GAAI,IAAA;AAErB,UAAA,IAAID,KAAAA,KAASC,KAAI,OAAO,WAAA;AAExB,UAAA,MAAM,IAAA,GAAO,UAAA,CAAW,MAAA,CAAOD,KAAAA,EAAMC,GAAAA,EAAI;AAAA,YACrC,OAAO,iBAAA,CAAQ;AAAA,WAClB,CAAA;AAED,UAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAAD,OAAM,EAAA,EAAAC,GAAAA,EAAI,WAAA,EAAa,aAAA,CAAc,OAAO,EAAA,CAAG,GAAA,EAAK,CAAC,IAAI,CAAC,CAAA,EAAE;AAAA,QACvF;AAEA,QAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,OAAO,IAAA;AAGzB,QAAA,MAAM,EAAE,IAAA,EAAM,EAAA,EAAG,GAAI,QAAA,CAAS,SAAA;AAE9B,QAAA,IAAI,SAAS,EAAA,EAAI;AACb,UAAA,OAAO,WAAA;AAAA,QACX;AAGA,QAAA,IAAI,GAAG,UAAA,EAAY;AACf,UAAA,MAAM,UAAA,GAAa,EAAA,CAAG,OAAA,CAAQ,GAAA,CAAI,KAAK,IAAI,CAAA;AAC3C,UAAA,MAAM,QAAA,GAAW,EAAA,CAAG,OAAA,CAAQ,GAAA,CAAI,KAAK,EAAE,CAAA;AAEvC,UAAA,MAAM,IAAA,GAAO,UAAA,CAAW,MAAA,CAAO,UAAA,EAAY,QAAA,EAAU;AAAA,YACjD,OAAO,iBAAA,CAAQ;AAAA,WAClB,CAAA;AAED,UAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,YAAY,EAAA,EAAI,QAAA,EAAU,WAAA,EAAa,aAAA,CAAc,OAAO,EAAA,CAAG,GAAA,EAAK,CAAC,IAAI,CAAC,CAAA,EAAE;AAAA,QAC7G;AAEA,QAAA,OAAO,IAAA;AAAA,MACX;AAAA,KACJ;AAAA,IACA,KAAA,EAAO;AAAA,MACH,YAAY,KAAA,EAAO;AACf,QAAA,OAAO,qBAAA,CAAsB,QAAA,CAAS,KAAK,CAAA,EAAG,eAAe,aAAA,CAAc,KAAA;AAAA,MAC/E;AAAA;AACJ,GACH,CAAA;AACL;AAEO,SAAS,kBAAkB,IAAA,EAAkB;AAChD,EAAA,MAAM,EAAE,IAAA,EAAM,EAAA,EAAG,GAAI,KAAK,KAAA,CAAM,SAAA;AAEhC,EAAA,IAAI,SAAS,EAAA,EAAI;AAEjB,EAAA,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,OAAA,CAAQ,qBAAA,EAAuB,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,EAAA,EAAI,CAAC,CAAA;AACxF","file":"chunk-RQ2HHNI6.mjs","sourcesContent":["import { Plugin, PluginKey } from 'prosemirror-state';\nimport type { EditorView } from 'prosemirror-view';\nimport { Decoration, DecorationSet } from 'prosemirror-view';\nimport { textEditorClasses as classes } from '../texteditor.classes';\n\nexport const selectionHighlightKey = new PluginKey('selectionHighlight');\n\ninterface HighlightState {\n active: boolean;\n from: number;\n to: number;\n decorations: DecorationSet;\n}\n\nconst EMPTY_STATE: HighlightState = { active: false, from: -1, to: -1, decorations: DecorationSet.empty };\n\nexport function createSelectionHighlightPlugin() {\n return new Plugin({\n key: selectionHighlightKey,\n state: {\n init(): HighlightState {\n return EMPTY_STATE;\n },\n apply(tr, prev, _oldState, newState): HighlightState {\n const meta = tr.getMeta(selectionHighlightKey);\n\n if (meta?.show) {\n const { from, to } = meta;\n\n if (from === to) return EMPTY_STATE;\n\n const deco = Decoration.inline(from, to, {\n class: classes.selection\n });\n\n return { active: true, from, to, decorations: DecorationSet.create(tr.doc, [deco]) };\n }\n\n if (!prev.active) return prev;\n\n // Auto-clear: if selection collapsed (user clicked), remove decoration\n const { from, to } = newState.selection;\n\n if (from === to) {\n return EMPTY_STATE;\n }\n\n // Remap on doc change\n if (tr.docChanged) {\n const mappedFrom = tr.mapping.map(prev.from);\n const mappedTo = tr.mapping.map(prev.to);\n\n const deco = Decoration.inline(mappedFrom, mappedTo, {\n class: classes.selection\n });\n\n return { active: true, from: mappedFrom, to: mappedTo, decorations: DecorationSet.create(tr.doc, [deco]) };\n }\n\n return prev;\n }\n },\n props: {\n decorations(state) {\n return selectionHighlightKey.getState(state)?.decorations ?? DecorationSet.empty;\n }\n }\n });\n}\n\nexport function preserveSelection(view: EditorView) {\n const { from, to } = view.state.selection;\n\n if (from === to) return;\n\n view.dispatch(view.state.tr.setMeta(selectionHighlightKey, { show: true, from, to }));\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/constants.ts"],"names":[],"mappings":";AAGO,IAAM,uBAAA,GAA0B","file":"chunk-TB7ZSSR2.mjs","sourcesContent":["// Default one-click highlight color (a soft yellow). The single source of truth\n// for the highlight command, keymap shortcut, and the \"==\" markdown input rule.\n// Overridable per-editor via the `defaultHighlightColor` prop.\nexport const DEFAULT_HIGHLIGHT_COLOR = 'rgba(242, 201, 76, 0.4)';\n"]}
|