@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,37 @@
|
|
|
1
|
+
// src/plugins/mentionController.ts
|
|
2
|
+
function createMentionController(opts) {
|
|
3
|
+
let items = [];
|
|
4
|
+
let active = false;
|
|
5
|
+
let token = 0;
|
|
6
|
+
return {
|
|
7
|
+
async onUpdate(update) {
|
|
8
|
+
const t = ++token;
|
|
9
|
+
if (!update.active) {
|
|
10
|
+
active = false;
|
|
11
|
+
items = [];
|
|
12
|
+
opts.emit(update);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!active) {
|
|
16
|
+
const handler = opts.getHandler();
|
|
17
|
+
if (handler) {
|
|
18
|
+
const fetched = await handler();
|
|
19
|
+
if (t !== token) return;
|
|
20
|
+
items = fetched;
|
|
21
|
+
}
|
|
22
|
+
active = true;
|
|
23
|
+
}
|
|
24
|
+
const field = opts.getFilterField();
|
|
25
|
+
const filtered = update.text ? items.filter((item) => {
|
|
26
|
+
if (!item || typeof item !== "object") return false;
|
|
27
|
+
return String(item[field] || "").toLowerCase().includes(update.text.toLowerCase());
|
|
28
|
+
}) : items;
|
|
29
|
+
if (t !== token) return;
|
|
30
|
+
opts.emit({ ...update, items: filtered });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { createMentionController };
|
|
36
|
+
//# sourceMappingURL=chunk-GGPBV4BM.mjs.map
|
|
37
|
+
//# sourceMappingURL=chunk-GGPBV4BM.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/mentionController.ts"],"names":[],"mappings":";AAaO,SAAS,wBAAwB,IAAA,EAAgC;AACpE,EAAA,IAAI,QAAmB,EAAC;AACxB,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,IAAI,KAAA,GAAQ,CAAA;AAEZ,EAAA,OAAO;AAAA,IACH,MAAM,SAAS,MAAA,EAAsC;AACjD,MAAA,MAAM,IAAI,EAAE,KAAA;AAEZ,MAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAChB,QAAA,MAAA,GAAS,KAAA;AACT,QAAA,KAAA,GAAQ,EAAC;AACT,QAAA,IAAA,CAAK,KAAK,MAAM,CAAA;AAEhB,QAAA;AAAA,MACJ;AAEA,MAAA,IAAI,CAAC,MAAA,EAAQ;AACT,QAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAEhC,QAAA,IAAI,OAAA,EAAS;AACT,UAAA,MAAM,OAAA,GAAU,MAAM,OAAA,EAAQ;AAE9B,UAAA,IAAI,MAAM,KAAA,EAAO;AAEjB,UAAA,KAAA,GAAQ,OAAA;AAAA,QACZ;AAEA,QAAA,MAAA,GAAS,IAAA;AAAA,MACb;AAEA,MAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,EAAe;AAClC,MAAA,MAAM,WAAW,MAAA,CAAO,IAAA,GAClB,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAS;AACnB,QAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,KAAA;AAE9C,QAAA,OAAO,MAAA,CAAQ,IAAA,CAAiC,KAAK,CAAA,IAAK,EAAE,CAAA,CACvD,WAAA,EAAY,CACZ,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,WAAA,EAAa,CAAA;AAAA,MAC3C,CAAC,CAAA,GACD,KAAA;AAEN,MAAA,IAAI,MAAM,KAAA,EAAO;AAEjB,MAAA,IAAA,CAAK,KAAK,EAAE,GAAG,MAAA,EAAQ,KAAA,EAAO,UAAU,CAAA;AAAA,IAC5C;AAAA,GACJ;AACJ","file":"chunk-GGPBV4BM.mjs","sourcesContent":["export interface MentionUpdate {\n active: boolean;\n text: string;\n}\n\nexport interface MentionControllerOptions {\n getHandler: () => (() => unknown[] | Promise<unknown[]>) | undefined;\n getFilterField: () => string;\n emit: (update: MentionUpdate & { items?: unknown[] }) => void;\n}\n\n// Race-safe mention state machine: fetches items once per @-session, drops stale\n// fetches, and never leaves the list permanently empty after a superseded fetch.\nexport function createMentionController(opts: MentionControllerOptions) {\n let items: unknown[] = [];\n let active = false;\n let token = 0;\n\n return {\n async onUpdate(update: MentionUpdate): Promise<void> {\n const t = ++token;\n\n if (!update.active) {\n active = false;\n items = [];\n opts.emit(update);\n\n return;\n }\n\n if (!active) {\n const handler = opts.getHandler();\n\n if (handler) {\n const fetched = await handler();\n\n if (t !== token) return;\n\n items = fetched;\n }\n\n active = true;\n }\n\n const field = opts.getFilterField();\n const filtered = update.text\n ? items.filter((item) => {\n if (!item || typeof item !== 'object') return false;\n\n return String((item as Record<string, unknown>)[field] || '')\n .toLowerCase()\n .includes(update.text.toLowerCase());\n })\n : items;\n\n if (t !== token) return;\n\n opts.emit({ ...update, items: filtered });\n }\n };\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/texteditor.constants.ts
|
|
2
|
+
var KB = 1024;
|
|
3
|
+
var MB = KB * 1024;
|
|
4
|
+
var TEXT_EDITOR_FILE_SIZE = {
|
|
5
|
+
ONE_MB: 1 * MB,
|
|
6
|
+
TWO_MB: 2 * MB,
|
|
7
|
+
THREE_MB: 3 * MB,
|
|
8
|
+
FOUR_MB: 4 * MB,
|
|
9
|
+
FIVE_MB: 5 * MB,
|
|
10
|
+
SIX_MB: 6 * MB,
|
|
11
|
+
SEVEN_MB: 7 * MB,
|
|
12
|
+
EIGHT_MB: 8 * MB,
|
|
13
|
+
NINE_MB: 9 * MB,
|
|
14
|
+
TEN_MB: 10 * MB,
|
|
15
|
+
TWENTY_FIVE_MB: 25 * MB,
|
|
16
|
+
FIFTY_MB: 50 * MB
|
|
17
|
+
};
|
|
18
|
+
var TEXT_EDITOR_ALLOWED_TYPES = {
|
|
19
|
+
IMAGES_ANY: "image/*",
|
|
20
|
+
IMAGES_COMMON: "image/jpeg,image/png,image/gif,image/webp",
|
|
21
|
+
DOCUMENTS_OFFICE: ".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.csv,.zip",
|
|
22
|
+
DOCUMENTS_PDF_ONLY: ".pdf"
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export { TEXT_EDITOR_ALLOWED_TYPES, TEXT_EDITOR_FILE_SIZE };
|
|
26
|
+
//# sourceMappingURL=chunk-H3RFOYCT.mjs.map
|
|
27
|
+
//# sourceMappingURL=chunk-H3RFOYCT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/texteditor.constants.ts"],"names":[],"mappings":";AAOA,IAAM,EAAA,GAAK,IAAA;AACX,IAAM,KAAK,EAAA,GAAK,IAAA;AAMT,IAAM,qBAAA,GAAwB;AAAA,EACjC,QAAQ,CAAA,GAAI,EAAA;AAAA,EACZ,QAAQ,CAAA,GAAI,EAAA;AAAA,EACZ,UAAU,CAAA,GAAI,EAAA;AAAA,EACd,SAAS,CAAA,GAAI,EAAA;AAAA,EACb,SAAS,CAAA,GAAI,EAAA;AAAA,EACb,QAAQ,CAAA,GAAI,EAAA;AAAA,EACZ,UAAU,CAAA,GAAI,EAAA;AAAA,EACd,UAAU,CAAA,GAAI,EAAA;AAAA,EACd,SAAS,CAAA,GAAI,EAAA;AAAA,EACb,QAAQ,EAAA,GAAK,EAAA;AAAA,EACb,gBAAgB,EAAA,GAAK,EAAA;AAAA,EACrB,UAAU,EAAA,GAAK;AACnB;AAMO,IAAM,yBAAA,GAA4B;AAAA,EACrC,UAAA,EAAY,SAAA;AAAA,EACZ,aAAA,EAAe,2CAAA;AAAA,EACf,gBAAA,EAAkB,sDAAA;AAAA,EAClB,kBAAA,EAAoB;AACxB","file":"chunk-H3RFOYCT.mjs","sourcesContent":["/**\n * Public, named constants — exported from `@primeui/texteditor-core` and\n * re-exported by every framework adapter. Demos and customer code should\n * use these instead of inline magic numbers so call sites stay readable\n * and the units of measure are obvious from the identifier.\n */\n\nconst KB = 1024;\nconst MB = KB * 1024;\n\n/**\n * File-size constants in bytes. Use these for `:maxFileSize` on\n * `<TextEditor.ImageUpload>` and `<TextEditor.DocumentUpload>`.\n */\nexport const TEXT_EDITOR_FILE_SIZE = {\n ONE_MB: 1 * MB,\n TWO_MB: 2 * MB,\n THREE_MB: 3 * MB,\n FOUR_MB: 4 * MB,\n FIVE_MB: 5 * MB,\n SIX_MB: 6 * MB,\n SEVEN_MB: 7 * MB,\n EIGHT_MB: 8 * MB,\n NINE_MB: 9 * MB,\n TEN_MB: 10 * MB,\n TWENTY_FIVE_MB: 25 * MB,\n FIFTY_MB: 50 * MB\n} as const;\n\n/**\n * Default upload allow-lists. Override these per-instance via\n * `:allowedTypes` when the application has stricter or laxer rules.\n */\nexport const TEXT_EDITOR_ALLOWED_TYPES = {\n IMAGES_ANY: 'image/*',\n IMAGES_COMMON: 'image/jpeg,image/png,image/gif,image/webp',\n DOCUMENTS_OFFICE: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.csv,.zip',\n DOCUMENTS_PDF_ONLY: '.pdf'\n} as const;\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getSelectionPosition } from './chunk-72T5I4O4.mjs';
|
|
2
|
+
import { Plugin } from 'prosemirror-state';
|
|
3
|
+
|
|
4
|
+
function createContextToolbarPlugin(callbacks) {
|
|
5
|
+
return new Plugin({
|
|
6
|
+
props: {
|
|
7
|
+
handleDOMEvents: {
|
|
8
|
+
keyup(view) {
|
|
9
|
+
if (view.state.selection.empty) return false;
|
|
10
|
+
const position = getSelectionPosition(view);
|
|
11
|
+
if (position) {
|
|
12
|
+
callbacks.onRequest(position);
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { createContextToolbarPlugin };
|
|
22
|
+
//# sourceMappingURL=chunk-IUQKSDKG.mjs.map
|
|
23
|
+
//# sourceMappingURL=chunk-IUQKSDKG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/contextToolbar.ts"],"names":[],"mappings":";;;AAQO,SAAS,2BAA2B,SAAA,EAAoC;AAC3E,EAAA,OAAO,IAAI,MAAA,CAAO;AAAA,IACd,KAAA,EAAO;AAAA,MACH,eAAA,EAAiB;AAAA,QACb,MAAM,IAAA,EAAM;AACR,UAAA,IAAI,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,KAAA,EAAO,OAAO,KAAA;AAEvC,UAAA,MAAM,QAAA,GAAW,qBAAqB,IAAI,CAAA;AAE1C,UAAA,IAAI,QAAA,EAAU;AACV,YAAA,SAAA,CAAU,UAAU,QAAQ,CAAA;AAAA,UAChC;AAEA,UAAA,OAAO,KAAA;AAAA,QACX;AAAA;AACJ;AACJ,GACH,CAAA;AACL","file":"chunk-IUQKSDKG.mjs","sourcesContent":["import { Plugin } from 'prosemirror-state';\nimport type { CaretPosition } from '@primeui/texteditor-types';\nimport { getSelectionPosition } from '../state/selection';\n\ninterface ContextToolbarCallbacks {\n onRequest: (position: CaretPosition) => void;\n}\n\nexport function createContextToolbarPlugin(callbacks: ContextToolbarCallbacks) {\n return new Plugin({\n props: {\n handleDOMEvents: {\n keyup(view) {\n if (view.state.selection.empty) return false;\n\n const position = getSelectionPosition(view);\n\n if (position) {\n callbacks.onRequest(position);\n }\n\n return false;\n }\n }\n }\n });\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export { __export };
|
|
8
|
+
//# sourceMappingURL=chunk-J5LGTIGS.mjs.map
|
|
9
|
+
//# sourceMappingURL=chunk-J5LGTIGS.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-J5LGTIGS.mjs"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { textEditorClasses } from './chunk-GG56GLXC.mjs';
|
|
2
|
+
import { Fragment } from 'prosemirror-model';
|
|
3
|
+
import { PluginKey, Plugin, TextSelection } from 'prosemirror-state';
|
|
4
|
+
import { DecorationSet, Decoration } from 'prosemirror-view';
|
|
5
|
+
|
|
6
|
+
var slashPluginKey = new PluginKey("slashCommands");
|
|
7
|
+
function getCaretCoords(view, pos) {
|
|
8
|
+
const coords = view.coordsAtPos(pos);
|
|
9
|
+
return {
|
|
10
|
+
top: coords.top,
|
|
11
|
+
left: coords.left,
|
|
12
|
+
bottom: coords.bottom,
|
|
13
|
+
height: coords.bottom - coords.top,
|
|
14
|
+
width: 0
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function findSlashTrigger(doc, cursorPos) {
|
|
18
|
+
const $pos = doc.resolve(cursorPos);
|
|
19
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
20
|
+
const name = $pos.node(depth).type.name;
|
|
21
|
+
if (name === "blockquote" || name === "code_block") return -1;
|
|
22
|
+
}
|
|
23
|
+
const parentOffset = $pos.parentOffset;
|
|
24
|
+
const parentText = $pos.parent.textBetween(0, parentOffset, void 0, "\uFFFC");
|
|
25
|
+
for (let i = parentText.length - 1; i >= 0; i--) {
|
|
26
|
+
const char = parentText[i];
|
|
27
|
+
if (char === " " || char === "\n" || char === "\xA0") return -1;
|
|
28
|
+
if (char === "/") {
|
|
29
|
+
if (i === 0 || parentText[i - 1] === " " || parentText[i - 1] === "\n" || parentText[i - 1] === "\xA0") {
|
|
30
|
+
return $pos.start() + i;
|
|
31
|
+
}
|
|
32
|
+
return -1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return -1;
|
|
36
|
+
}
|
|
37
|
+
function createSlashPlugin(callbacks) {
|
|
38
|
+
let activated = false;
|
|
39
|
+
return new Plugin({
|
|
40
|
+
key: slashPluginKey,
|
|
41
|
+
props: {
|
|
42
|
+
handleDOMEvents: {
|
|
43
|
+
keydown(view, event) {
|
|
44
|
+
if (event.key === "Escape" && activated) {
|
|
45
|
+
activated = false;
|
|
46
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
47
|
+
view.dispatch(view.state.tr);
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
},
|
|
51
|
+
blur(view) {
|
|
52
|
+
if (activated) {
|
|
53
|
+
activated = false;
|
|
54
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
55
|
+
view.dispatch(view.state.tr);
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
handleTextInput(_view, _from, _to, text) {
|
|
61
|
+
if (text.endsWith("/")) {
|
|
62
|
+
activated = true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
},
|
|
66
|
+
decorations(state) {
|
|
67
|
+
if (!activated) return DecorationSet.empty;
|
|
68
|
+
const { from } = state.selection;
|
|
69
|
+
const triggerPos = findSlashTrigger(state.doc, from);
|
|
70
|
+
if (triggerPos < 0) return DecorationSet.empty;
|
|
71
|
+
const hasFilterText = from > triggerPos + 1;
|
|
72
|
+
const attrs = {
|
|
73
|
+
class: textEditorClasses.slashTyping,
|
|
74
|
+
"data-slash-query": "true"
|
|
75
|
+
};
|
|
76
|
+
if (!hasFilterText && callbacks.placeholder) {
|
|
77
|
+
attrs["data-placeholder"] = callbacks.placeholder;
|
|
78
|
+
}
|
|
79
|
+
const deco = Decoration.inline(triggerPos, from, attrs);
|
|
80
|
+
return DecorationSet.create(state.doc, [deco]);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
view() {
|
|
84
|
+
return {
|
|
85
|
+
update(view) {
|
|
86
|
+
if (!activated) return;
|
|
87
|
+
const { from, to } = view.state.selection;
|
|
88
|
+
if (from !== to) {
|
|
89
|
+
activated = false;
|
|
90
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const triggerPos = findSlashTrigger(view.state.doc, from);
|
|
94
|
+
if (triggerPos >= 0) {
|
|
95
|
+
const text = from > triggerPos + 1 ? view.state.doc.textBetween(triggerPos + 1, from, void 0, "\uFFFC") : "";
|
|
96
|
+
callbacks.onUpdate({
|
|
97
|
+
active: true,
|
|
98
|
+
text,
|
|
99
|
+
position: getCaretCoords(view, triggerPos)
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
activated = false;
|
|
103
|
+
callbacks.onUpdate({ active: false, text: "", position: null });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function executeSlashCommandInline(view, callback) {
|
|
111
|
+
const { from } = view.state.selection;
|
|
112
|
+
const triggerPos = findSlashTrigger(view.state.doc, from);
|
|
113
|
+
if (triggerPos < 0) return;
|
|
114
|
+
const tr = view.state.tr.delete(triggerPos, from);
|
|
115
|
+
view.dispatch(tr);
|
|
116
|
+
view.focus();
|
|
117
|
+
callback();
|
|
118
|
+
}
|
|
119
|
+
function executeSlashCommand(view, callback) {
|
|
120
|
+
const { from } = view.state.selection;
|
|
121
|
+
const triggerPos = findSlashTrigger(view.state.doc, from);
|
|
122
|
+
if (triggerPos < 0) return;
|
|
123
|
+
const $pos = view.state.doc.resolve(triggerPos);
|
|
124
|
+
const topNode = $pos.node(1);
|
|
125
|
+
const slashLength = from - triggerPos;
|
|
126
|
+
const isEmptyParagraph = topNode.type.name === "paragraph" && topNode.content.size === slashLength;
|
|
127
|
+
if (isEmptyParagraph) {
|
|
128
|
+
const tr = view.state.tr.delete(triggerPos, from);
|
|
129
|
+
view.dispatch(tr);
|
|
130
|
+
view.focus();
|
|
131
|
+
callback();
|
|
132
|
+
} else if ($pos.depth > 1) {
|
|
133
|
+
const topNode2 = $pos.node(1);
|
|
134
|
+
const topPos = $pos.before(1);
|
|
135
|
+
const topEnd = $pos.after(1);
|
|
136
|
+
const itemIndex = $pos.index(1);
|
|
137
|
+
const itemCount = topNode2.childCount;
|
|
138
|
+
const currentItem = topNode2.child(itemIndex);
|
|
139
|
+
const currentItemEmpty = currentItem.textContent.length === slashLength;
|
|
140
|
+
const schema = view.state.schema;
|
|
141
|
+
const tr = view.state.tr;
|
|
142
|
+
const nodes = [];
|
|
143
|
+
const beforeCount = currentItemEmpty ? itemIndex : itemIndex + 1;
|
|
144
|
+
if (beforeCount > 0) {
|
|
145
|
+
const beforeItems = [];
|
|
146
|
+
for (let i = 0; i < beforeCount; i++) {
|
|
147
|
+
const item = topNode2.child(i);
|
|
148
|
+
if (i === itemIndex && !currentItemEmpty) {
|
|
149
|
+
const firstChild = item.firstChild;
|
|
150
|
+
if (firstChild && firstChild.isTextblock) {
|
|
151
|
+
const trimmed = firstChild.cut(0, Math.max(0, firstChild.content.size - slashLength));
|
|
152
|
+
const rest = [];
|
|
153
|
+
item.forEach((c, _o, ci) => {
|
|
154
|
+
if (ci > 0) rest.push(c);
|
|
155
|
+
});
|
|
156
|
+
beforeItems.push(item.copy(Fragment.from([trimmed, ...rest])));
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
beforeItems.push(item);
|
|
161
|
+
}
|
|
162
|
+
nodes.push(topNode2.type.create(topNode2.attrs, beforeItems));
|
|
163
|
+
}
|
|
164
|
+
const newParagraph = schema.nodes.paragraph.create();
|
|
165
|
+
nodes.push(newParagraph);
|
|
166
|
+
const afterStart = currentItemEmpty ? itemIndex + 1 : itemIndex + 1;
|
|
167
|
+
if (afterStart < itemCount) {
|
|
168
|
+
const afterItems = [];
|
|
169
|
+
for (let i = afterStart; i < itemCount; i++) {
|
|
170
|
+
afterItems.push(topNode2.child(i));
|
|
171
|
+
}
|
|
172
|
+
nodes.push(topNode2.type.create(topNode2.attrs, afterItems));
|
|
173
|
+
}
|
|
174
|
+
tr.replaceWith(topPos, topEnd, nodes);
|
|
175
|
+
let cursorPos = topPos;
|
|
176
|
+
if (beforeCount > 0) {
|
|
177
|
+
cursorPos += nodes[0].nodeSize;
|
|
178
|
+
}
|
|
179
|
+
cursorPos += 1;
|
|
180
|
+
tr.setSelection(TextSelection.create(tr.doc, cursorPos));
|
|
181
|
+
view.dispatch(tr);
|
|
182
|
+
view.focus();
|
|
183
|
+
callback();
|
|
184
|
+
} else {
|
|
185
|
+
const tr = view.state.tr.delete(triggerPos, from);
|
|
186
|
+
const topBlockEnd = tr.mapping.map($pos.end(1));
|
|
187
|
+
const paragraph = view.state.schema.nodes.paragraph.create();
|
|
188
|
+
tr.insert(topBlockEnd + 1, paragraph);
|
|
189
|
+
tr.setSelection(TextSelection.create(tr.doc, topBlockEnd + 2));
|
|
190
|
+
view.dispatch(tr);
|
|
191
|
+
view.focus();
|
|
192
|
+
callback();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export { createSlashPlugin, executeSlashCommand, executeSlashCommandInline, slashPluginKey };
|
|
197
|
+
//# sourceMappingURL=chunk-KNZAMA6H.mjs.map
|
|
198
|
+
//# sourceMappingURL=chunk-KNZAMA6H.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/slashCommands.ts"],"names":["topNode"],"mappings":"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","file":"chunk-KNZAMA6H.mjs","sourcesContent":["import type { CaretPosition } from '@primeui/texteditor-types';\nimport { Fragment, type Node as PMNode } from 'prosemirror-model';\nimport { Plugin, PluginKey, TextSelection } 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 slashPluginKey = new PluginKey('slashCommands');\n\nexport interface SlashUpdate {\n active: boolean;\n text: string;\n position: CaretPosition | null;\n}\n\ninterface SlashPluginOptions {\n onUpdate: (update: SlashUpdate) => void;\n placeholder?: string;\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 findSlashTrigger(doc: PMNode, cursorPos: number): number {\n const $pos = doc.resolve(cursorPos);\n\n // Don't activate inside blockquotes or code blocks\n for (let depth = $pos.depth; depth > 0; depth--) {\n const name = $pos.node(depth).type.name;\n\n if (name === 'blockquote' || name === 'code_block') return -1;\n }\n\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 slash command\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 createSlashPlugin(callbacks: SlashPluginOptions) {\n let activated = false;\n\n return new Plugin({\n key: slashPluginKey,\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 decorations(state) {\n if (!activated) return DecorationSet.empty;\n\n const { from } = state.selection;\n const triggerPos = findSlashTrigger(state.doc, from);\n\n if (triggerPos < 0) return DecorationSet.empty;\n\n const hasFilterText = from > triggerPos + 1;\n const attrs: Record<string, string> = {\n class: classes.slashTyping,\n 'data-slash-query': 'true'\n };\n\n if (!hasFilterText && callbacks.placeholder) {\n attrs['data-placeholder'] = callbacks.placeholder;\n }\n\n const deco = Decoration.inline(triggerPos, from, attrs);\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 = findSlashTrigger(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 * Execute an inline slash command: remove the '/query' text and run the callback in place.\n * Does not create a new block — stays in the current block.\n */\nexport function executeSlashCommandInline(view: EditorView, callback: () => void) {\n const { from } = view.state.selection;\n const triggerPos = findSlashTrigger(view.state.doc, from);\n\n if (triggerPos < 0) return;\n\n const tr = view.state.tr.delete(triggerPos, from);\n\n view.dispatch(tr);\n view.focus();\n callback();\n}\n\n/**\n * Execute a slash command.\n * - Empty paragraph: delete '/query' and convert in place (Notion behavior).\n * - Any other case: create a new block after the current one and convert that.\n */\nexport function executeSlashCommand(view: EditorView, callback: () => void) {\n const { from } = view.state.selection;\n const triggerPos = findSlashTrigger(view.state.doc, from);\n\n if (triggerPos < 0) return;\n\n const $pos = view.state.doc.resolve(triggerPos);\n const topNode = $pos.node(1);\n const slashLength = from - triggerPos;\n const isEmptyParagraph = topNode.type.name === 'paragraph' && topNode.content.size === slashLength;\n\n if (isEmptyParagraph) {\n // Empty paragraph with only '/query' — delete and convert in place\n const tr = view.state.tr.delete(triggerPos, from);\n\n view.dispatch(tr);\n view.focus();\n callback();\n } else if ($pos.depth > 1) {\n // Nested block (list/blockquote) — split around the current item\n const topNode = $pos.node(1);\n const topPos = $pos.before(1);\n const topEnd = $pos.after(1);\n const itemIndex = $pos.index(1);\n const itemCount = topNode.childCount;\n const currentItem = topNode.child(itemIndex);\n const currentItemEmpty = currentItem.textContent.length === slashLength;\n\n const schema = view.state.schema;\n const tr = view.state.tr;\n const nodes: PMNode[] = [];\n\n // Items before (and including current if it has other content) → keep as a list\n const beforeCount = currentItemEmpty ? itemIndex : itemIndex + 1;\n\n if (beforeCount > 0) {\n const beforeItems: PMNode[] = [];\n\n for (let i = 0; i < beforeCount; i++) {\n const item = topNode.child(i);\n\n // The current (non-empty) item keeps its content but must shed the\n // trailing \"/query\" trigger text, which otherwise leaks into the list.\n if (i === itemIndex && !currentItemEmpty) {\n const firstChild = item.firstChild;\n\n if (firstChild && firstChild.isTextblock) {\n const trimmed = firstChild.cut(0, Math.max(0, firstChild.content.size - slashLength));\n const rest: PMNode[] = [];\n\n item.forEach((c, _o, ci) => {\n if (ci > 0) rest.push(c);\n });\n beforeItems.push(item.copy(Fragment.from([trimmed, ...rest])));\n\n continue;\n }\n }\n\n beforeItems.push(item);\n }\n\n nodes.push(topNode.type.create(topNode.attrs, beforeItems));\n }\n\n // New paragraph for the slash command\n const newParagraph = schema.nodes.paragraph.create();\n\n nodes.push(newParagraph);\n\n // Items after the current item → keep as a list\n const afterStart = currentItemEmpty ? itemIndex + 1 : itemIndex + 1;\n\n if (afterStart < itemCount) {\n const afterItems: PMNode[] = [];\n\n for (let i = afterStart; i < itemCount; i++) {\n afterItems.push(topNode.child(i));\n }\n\n nodes.push(topNode.type.create(topNode.attrs, afterItems));\n }\n\n // Replace the entire list with the split parts\n tr.replaceWith(topPos, topEnd, nodes);\n\n // Find the new paragraph position and place cursor there\n let cursorPos = topPos;\n\n if (beforeCount > 0) {\n cursorPos += nodes[0].nodeSize;\n }\n\n cursorPos += 1; // inside the new paragraph\n\n tr.setSelection(TextSelection.create(tr.doc, cursorPos));\n view.dispatch(tr);\n view.focus();\n callback();\n } else {\n // Top-level non-empty block — create a new block after\n const tr = view.state.tr.delete(triggerPos, from);\n const topBlockEnd = tr.mapping.map($pos.end(1));\n const paragraph = view.state.schema.nodes.paragraph.create();\n\n tr.insert(topBlockEnd + 1, paragraph);\n tr.setSelection(TextSelection.create(tr.doc, topBlockEnd + 2));\n view.dispatch(tr);\n view.focus();\n callback();\n }\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/utils/url.ts
|
|
2
|
+
function sanitizeTextAttr(value) {
|
|
3
|
+
if (value == null) return null;
|
|
4
|
+
return value.replace(/[<>]/g, "");
|
|
5
|
+
}
|
|
6
|
+
var SAFE_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
7
|
+
var IGNORED_CHARS = new RegExp("[\0- \x7F\u200B-\u200F\u2028\u2029\uFEFF]", "g");
|
|
8
|
+
function sanitizeUrl(url) {
|
|
9
|
+
if (url == null) return null;
|
|
10
|
+
const stripped = url.replace(IGNORED_CHARS, "");
|
|
11
|
+
if (stripped === "") return null;
|
|
12
|
+
const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(stripped);
|
|
13
|
+
if (!schemeMatch) return stripped;
|
|
14
|
+
const protocol = `${schemeMatch[1].toLowerCase()}:`;
|
|
15
|
+
return SAFE_PROTOCOLS.includes(protocol) ? stripped : null;
|
|
16
|
+
}
|
|
17
|
+
function sanitizeImageUrl(url) {
|
|
18
|
+
if (url == null) return null;
|
|
19
|
+
const stripped = url.replace(IGNORED_CHARS, "");
|
|
20
|
+
if (/^data:image\/(png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\s]+$/i.test(stripped)) return stripped;
|
|
21
|
+
if (/^data:/i.test(stripped)) return null;
|
|
22
|
+
return sanitizeUrl(url);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { sanitizeImageUrl, sanitizeTextAttr, sanitizeUrl };
|
|
26
|
+
//# sourceMappingURL=chunk-MNKMKFLQ.mjs.map
|
|
27
|
+
//# sourceMappingURL=chunk-MNKMKFLQ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/url.ts"],"names":[],"mappings":";AACO,SAAS,iBAAiB,KAAA,EAAiD;AAC9E,EAAA,IAAI,KAAA,IAAS,MAAM,OAAO,IAAA;AAE1B,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AACpC;AAGA,IAAM,iBAAiB,CAAC,OAAA,EAAS,QAAA,EAAU,SAAA,EAAW,QAAQ,MAAM,CAAA;AAGpE,IAAM,aAAA,GAAgB,IAAI,MAAA,CAAO,2CAAA,EAAwD,GAAG,CAAA;AAGrF,SAAS,YAAY,GAAA,EAA+C;AACvE,EAAA,IAAI,GAAA,IAAO,MAAM,OAAO,IAAA;AAExB,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAE9C,EAAA,IAAI,QAAA,KAAa,IAAI,OAAO,IAAA;AAE5B,EAAA,MAAM,WAAA,GAAc,wBAAA,CAAyB,IAAA,CAAK,QAAQ,CAAA;AAE1D,EAAA,IAAI,CAAC,aAAa,OAAO,QAAA;AAEzB,EAAA,MAAM,WAAW,CAAA,EAAG,WAAA,CAAY,CAAC,CAAA,CAAE,aAAa,CAAA,CAAA,CAAA;AAEhD,EAAA,OAAO,cAAA,CAAe,QAAA,CAAS,QAAQ,CAAA,GAAI,QAAA,GAAW,IAAA;AAC1D;AAGO,SAAS,iBAAiB,GAAA,EAA+C;AAC5E,EAAA,IAAI,GAAA,IAAO,MAAM,OAAO,IAAA;AAExB,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAI9C,EAAA,IAAI,oEAAA,CAAqE,IAAA,CAAK,QAAQ,CAAA,EAAG,OAAO,QAAA;AAChG,EAAA,IAAI,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA,EAAG,OAAO,IAAA;AAErC,EAAA,OAAO,YAAY,GAAG,CAAA;AAC1B","file":"chunk-MNKMKFLQ.mjs","sourcesContent":["// Strip <> from a free-text attribute (alt, mention label/id).\nexport function sanitizeTextAttr(value: string | null | undefined): string | null {\n if (value == null) return null;\n\n return value.replace(/[<>]/g, '');\n}\n\n// URL scheme allowlist shared by link getAttrs/toDOM and the link commands.\nconst SAFE_PROTOCOLS = ['http:', 'https:', 'mailto:', 'tel:', 'ftp:'];\n\n// eslint-disable-next-line no-control-regex\nconst IGNORED_CHARS = new RegExp('[\\u0000-\\u0020\\u007f\\u200b-\\u200f\\u2028\\u2029\\ufeff]', 'g');\n\n// Returns a safe href, or null for a disallowed scheme. Relative/fragment URLs are allowed.\nexport function sanitizeUrl(url: string | null | undefined): string | null {\n if (url == null) return null;\n\n const stripped = url.replace(IGNORED_CHARS, '');\n\n if (stripped === '') return null;\n\n const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(stripped);\n\n if (!schemeMatch) return stripped;\n\n const protocol = `${schemeMatch[1].toLowerCase()}:`;\n\n return SAFE_PROTOCOLS.includes(protocol) ? stripped : null;\n}\n\n// Like sanitizeUrl but also allows data:image/* (raster only; svg excluded).\nexport function sanitizeImageUrl(url: string | null | undefined): string | null {\n if (url == null) return null;\n\n const stripped = url.replace(IGNORED_CHARS, '');\n\n // Allow only well-formed base64 raster data URIs; reject svg and any\n // malformed/foreign data:image body (e.g. data:image/png,<svg ...>).\n if (/^data:image\\/(png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\\s]+$/i.test(stripped)) return stripped;\n if (/^data:/i.test(stripped)) return null;\n\n return sanitizeUrl(url);\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Plugin } from 'prosemirror-state';
|
|
2
|
+
import { columnResizingPluginKey, tableNodeTypes, TableMap } from 'prosemirror-tables';
|
|
3
|
+
|
|
4
|
+
// src/plugins/columnWidthPin.ts
|
|
5
|
+
function createColumnWidthPinPlugin() {
|
|
6
|
+
let view = null;
|
|
7
|
+
return new Plugin({
|
|
8
|
+
view(editorView) {
|
|
9
|
+
view = editorView;
|
|
10
|
+
return {
|
|
11
|
+
destroy() {
|
|
12
|
+
view = null;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
appendTransaction(transactions, _oldState, newState) {
|
|
17
|
+
const startedResize = transactions.some((tr2) => tr2.getMeta(columnResizingPluginKey)?.setDragging);
|
|
18
|
+
if (!startedResize || !view) return null;
|
|
19
|
+
const tableType = tableNodeTypes(newState.schema).table;
|
|
20
|
+
const tr = newState.tr;
|
|
21
|
+
let changed = false;
|
|
22
|
+
newState.doc.descendants((node, pos) => {
|
|
23
|
+
if (node.type !== tableType) return false;
|
|
24
|
+
if (pinTable(node, pos, view, tr)) changed = true;
|
|
25
|
+
return false;
|
|
26
|
+
});
|
|
27
|
+
return changed ? tr : null;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function pinTable(table, tablePos, view, tr) {
|
|
32
|
+
const map = TableMap.get(table);
|
|
33
|
+
const start = tablePos + 1;
|
|
34
|
+
let changed = false;
|
|
35
|
+
for (let col = 0; col < map.width; col++) {
|
|
36
|
+
const cellRel = map.map[col];
|
|
37
|
+
const cell = table.nodeAt(cellRel);
|
|
38
|
+
if (!cell || (cell.attrs.colspan ?? 1) !== 1) continue;
|
|
39
|
+
if (cell.attrs.colwidth && cell.attrs.colwidth[0]) continue;
|
|
40
|
+
const dom = view.nodeDOM(start + cellRel);
|
|
41
|
+
const width = dom?.getBoundingClientRect().width;
|
|
42
|
+
if (width && width > 0) {
|
|
43
|
+
tr.setNodeAttribute(start + cellRel, "colwidth", [Math.round(width)]);
|
|
44
|
+
changed = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return changed;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { createColumnWidthPinPlugin };
|
|
51
|
+
//# sourceMappingURL=chunk-MWT5PK3Z.mjs.map
|
|
52
|
+
//# sourceMappingURL=chunk-MWT5PK3Z.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/columnWidthPin.ts"],"names":["tr"],"mappings":";;;;AAOO,SAAS,0BAAA,GAA6B;AACzC,EAAA,IAAI,IAAA,GAA0B,IAAA;AAE9B,EAAA,OAAO,IAAI,MAAA,CAAO;AAAA,IACd,KAAK,UAAA,EAAY;AACb,MAAA,IAAA,GAAO,UAAA;AAEP,MAAA,OAAO;AAAA,QACH,OAAA,GAAU;AACN,UAAA,IAAA,GAAO,IAAA;AAAA,QACX;AAAA,OACJ;AAAA,IACJ,CAAA;AAAA,IACA,iBAAA,CAAkB,YAAA,EAAc,SAAA,EAAW,QAAA,EAAU;AAEjD,MAAA,MAAM,aAAA,GAAgB,aAAa,IAAA,CAAK,CAACA,QAAOA,GAAAA,CAAG,OAAA,CAAQ,uBAAuB,CAAA,EAAG,WAAW,CAAA;AAEhG,MAAA,IAAI,CAAC,aAAA,IAAiB,CAAC,IAAA,EAAM,OAAO,IAAA;AAEpC,MAAA,MAAM,SAAA,GAAY,cAAA,CAAe,QAAA,CAAS,MAAM,CAAA,CAAE,KAAA;AAClD,MAAA,MAAM,KAAK,QAAA,CAAS,EAAA;AACpB,MAAA,IAAI,OAAA,GAAU,KAAA;AAEd,MAAA,QAAA,CAAS,GAAA,CAAI,WAAA,CAAY,CAAC,IAAA,EAAM,GAAA,KAAQ;AACpC,QAAA,IAAI,IAAA,CAAK,IAAA,KAAS,SAAA,EAAW,OAAO,KAAA;AAEpC,QAAA,IAAI,SAAS,IAAA,EAAM,GAAA,EAAK,IAAA,EAAO,EAAE,GAAG,OAAA,GAAU,IAAA;AAE9C,QAAA,OAAO,KAAA;AAAA,MACX,CAAC,CAAA;AAED,MAAA,OAAO,UAAU,EAAA,GAAK,IAAA;AAAA,IAC1B;AAAA,GACH,CAAA;AACL;AAGA,SAAS,QAAA,CAAS,KAAA,EAAa,QAAA,EAAkB,IAAA,EAAkB,EAAA,EAA0B;AACzF,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AAC9B,EAAA,MAAM,QAAQ,QAAA,GAAW,CAAA;AACzB,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,GAAM,GAAA,CAAI,OAAO,GAAA,EAAA,EAAO;AACtC,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAC3B,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA;AAEjC,IAAA,IAAI,CAAC,IAAA,IAAA,CAAS,IAAA,CAAK,KAAA,CAAM,OAAA,IAAW,OAAO,CAAA,EAAG;AAC9C,IAAA,IAAI,KAAK,KAAA,CAAM,QAAA,IAAY,KAAK,KAAA,CAAM,QAAA,CAAS,CAAC,CAAA,EAAG;AAEnD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,KAAA,GAAQ,OAAO,CAAA;AACxC,IAAA,MAAM,KAAA,GAAQ,GAAA,EAAK,qBAAA,EAAsB,CAAE,KAAA;AAE3C,IAAA,IAAI,KAAA,IAAS,QAAQ,CAAA,EAAG;AACpB,MAAA,EAAA,CAAG,gBAAA,CAAiB,QAAQ,OAAA,EAAS,UAAA,EAAY,CAAC,IAAA,CAAK,KAAA,CAAM,KAAK,CAAC,CAAC,CAAA;AACpE,MAAA,OAAA,GAAU,IAAA;AAAA,IACd;AAAA,EACJ;AAEA,EAAA,OAAO,OAAA;AACX","file":"chunk-MWT5PK3Z.mjs","sourcesContent":["import type { Node } from 'prosemirror-model';\nimport { Plugin, type Transaction } from 'prosemirror-state';\nimport type { EditorView } from 'prosemirror-view';\nimport { columnResizingPluginKey, TableMap, tableNodeTypes } from 'prosemirror-tables';\n\n// On resize start, pin every unsized column to its rendered width so only the\n// dragged column changes (otherwise unsized columns jump to defaultCellMinWidth).\nexport function createColumnWidthPinPlugin() {\n let view: EditorView | null = null;\n\n return new Plugin({\n view(editorView) {\n view = editorView;\n\n return {\n destroy() {\n view = null;\n }\n };\n },\n appendTransaction(transactions, _oldState, newState) {\n // The columnResizing plugin sets `setDragging` meta on mousedown.\n const startedResize = transactions.some((tr) => tr.getMeta(columnResizingPluginKey)?.setDragging);\n\n if (!startedResize || !view) return null;\n\n const tableType = tableNodeTypes(newState.schema).table;\n const tr = newState.tr;\n let changed = false;\n\n newState.doc.descendants((node, pos) => {\n if (node.type !== tableType) return false;\n\n if (pinTable(node, pos, view!, tr)) changed = true;\n\n return false; // tables don't nest\n });\n\n return changed ? tr : null;\n }\n });\n}\n\n/** Pin each unsized, single-column cell of a table to its rendered width. */\nfunction pinTable(table: Node, tablePos: number, view: EditorView, tr: Transaction): boolean {\n const map = TableMap.get(table);\n const start = tablePos + 1;\n let changed = false;\n\n for (let col = 0; col < map.width; col++) {\n const cellRel = map.map[col]; // first row's cell in this column\n const cell = table.nodeAt(cellRel);\n\n if (!cell || (cell.attrs.colspan ?? 1) !== 1) continue;\n if (cell.attrs.colwidth && cell.attrs.colwidth[0]) continue;\n\n const dom = view.nodeDOM(start + cellRel) as HTMLElement | null;\n const width = dom?.getBoundingClientRect().width;\n\n if (width && width > 0) {\n tr.setNodeAttribute(start + cellRel, 'colwidth', [Math.round(width)]);\n changed = true;\n }\n }\n\n return changed;\n}\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { textEditorClasses } from './chunk-GG56GLXC.mjs';
|
|
2
|
+
import { Plugin } from 'prosemirror-state';
|
|
3
|
+
import { DecorationSet, Decoration } from 'prosemirror-view';
|
|
4
|
+
|
|
5
|
+
function createPlaceholderPlugin(options) {
|
|
6
|
+
return new Plugin({
|
|
7
|
+
props: {
|
|
8
|
+
decorations(state) {
|
|
9
|
+
const text = options.text();
|
|
10
|
+
if (!text) return DecorationSet.empty;
|
|
11
|
+
const { doc, selection } = state;
|
|
12
|
+
if (options.blockMode) {
|
|
13
|
+
const decorations = [];
|
|
14
|
+
const { $from } = selection;
|
|
15
|
+
const addPlaceholderWidget = (insidePos) => {
|
|
16
|
+
const widget = Decoration.widget(
|
|
17
|
+
insidePos,
|
|
18
|
+
() => {
|
|
19
|
+
const span = document.createElement("span");
|
|
20
|
+
span.className = textEditorClasses.blockPlaceholder;
|
|
21
|
+
span.textContent = text;
|
|
22
|
+
return span;
|
|
23
|
+
},
|
|
24
|
+
{ side: -1 }
|
|
25
|
+
);
|
|
26
|
+
decorations.push(widget);
|
|
27
|
+
};
|
|
28
|
+
const compoundTypes = ["bullet_list", "ordered_list", "blockquote"];
|
|
29
|
+
doc.forEach((node, pos) => {
|
|
30
|
+
const isFocused = $from.pos >= pos && $from.pos <= pos + node.nodeSize;
|
|
31
|
+
if (!isFocused) return;
|
|
32
|
+
if (node.isTextblock && node.content.size === 0) {
|
|
33
|
+
addPlaceholderWidget(pos + 1);
|
|
34
|
+
} else if (compoundTypes.includes(node.type.name) && node.firstChild) {
|
|
35
|
+
let child = node.firstChild;
|
|
36
|
+
let childPos = pos + 1;
|
|
37
|
+
while (child && !child.isTextblock) {
|
|
38
|
+
childPos += 1;
|
|
39
|
+
child = child.firstChild;
|
|
40
|
+
}
|
|
41
|
+
if (child?.isTextblock && child.content.size === 0) {
|
|
42
|
+
addPlaceholderWidget(childPos + 1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return decorations.length > 0 ? DecorationSet.create(doc, decorations) : DecorationSet.empty;
|
|
47
|
+
}
|
|
48
|
+
if (doc.childCount > 1) return DecorationSet.empty;
|
|
49
|
+
const firstChild = doc.firstChild;
|
|
50
|
+
if (!firstChild || firstChild.type.name !== "paragraph" || firstChild.content.size > 0) {
|
|
51
|
+
return DecorationSet.empty;
|
|
52
|
+
}
|
|
53
|
+
const decoration = Decoration.node(0, firstChild.nodeSize, {
|
|
54
|
+
class: textEditorClasses.placeholder,
|
|
55
|
+
"data-placeholder": text
|
|
56
|
+
});
|
|
57
|
+
return DecorationSet.create(doc, [decoration]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { createPlaceholderPlugin };
|
|
64
|
+
//# sourceMappingURL=chunk-NWRVBNBW.mjs.map
|
|
65
|
+
//# sourceMappingURL=chunk-NWRVBNBW.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/placeholder.ts"],"names":[],"mappings":"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","file":"chunk-NWRVBNBW.mjs","sourcesContent":["import { Plugin } from 'prosemirror-state';\nimport { Decoration, DecorationSet } from 'prosemirror-view';\nimport { textEditorClasses as classes } from '../texteditor.classes';\n\ninterface PlaceholderOptions {\n text: () => string | null | undefined;\n blockMode?: boolean;\n}\n\nexport function createPlaceholderPlugin(options: PlaceholderOptions) {\n return new Plugin({\n props: {\n decorations(state) {\n const text = options.text();\n\n if (!text) return DecorationSet.empty;\n\n const { doc, selection } = state;\n\n if (options.blockMode) {\n // Block mode: show placeholder widget inside the focused empty block\n const decorations: Decoration[] = [];\n const { $from } = selection;\n\n // Find the position inside the empty textblock to place the widget\n const addPlaceholderWidget = (insidePos: number) => {\n const widget = Decoration.widget(\n insidePos,\n () => {\n const span = document.createElement('span');\n\n span.className = classes.blockPlaceholder;\n span.textContent = text!;\n\n return span;\n },\n { side: -1 }\n );\n\n decorations.push(widget);\n };\n\n const compoundTypes = ['bullet_list', 'ordered_list', 'blockquote'];\n\n doc.forEach((node, pos) => {\n // Only show on the focused block\n const isFocused = $from.pos >= pos && $from.pos <= pos + node.nodeSize;\n\n if (!isFocused) return;\n\n if (node.isTextblock && node.content.size === 0) {\n // Direct textblock (paragraph, heading, code_block)\n addPlaceholderWidget(pos + 1);\n } else if (compoundTypes.includes(node.type.name) && node.firstChild) {\n // Lists/blockquote — find the innermost empty textblock\n let child = node.firstChild;\n let childPos = pos + 1;\n\n while (child && !child.isTextblock) {\n childPos += 1;\n child = child.firstChild!;\n }\n\n if (child?.isTextblock && child.content.size === 0) {\n addPlaceholderWidget(childPos + 1);\n }\n }\n });\n\n return decorations.length > 0 ? DecorationSet.create(doc, decorations) : DecorationSet.empty;\n }\n\n // Simple mode: only show when document is empty (single empty paragraph)\n if (doc.childCount > 1) return DecorationSet.empty;\n\n const firstChild = doc.firstChild;\n\n if (!firstChild || firstChild.type.name !== 'paragraph' || firstChild.content.size > 0) {\n return DecorationSet.empty;\n }\n\n const decoration = Decoration.node(0, firstChild.nodeSize, {\n class: classes.placeholder,\n 'data-placeholder': text\n });\n\n return DecorationSet.create(doc, [decoration]);\n }\n }\n });\n}\n"]}
|