@kedataindo/docflow-plugins 0.0.31 → 0.0.33
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/dist/index.cjs +561 -17
- package/dist/index.d.cts +50 -1
- package/dist/index.d.ts +50 -1
- package/dist/index.js +541 -5
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -39,9 +39,14 @@ __export(index_exports, {
|
|
|
39
39
|
CiteEngine: () => CiteEngine,
|
|
40
40
|
CommentMarkExtension: () => CommentMark,
|
|
41
41
|
DEFAULT_CSL_STYLE: () => DEFAULT_CSL_STYLE,
|
|
42
|
+
DateChipNode: () => DateChipNode,
|
|
43
|
+
DropdownChipNode: () => DropdownChipNode,
|
|
44
|
+
FileChipNode: () => FileChipNode,
|
|
42
45
|
FontSizeExtension: () => import_docflow_core14.FontSizeExtension,
|
|
43
46
|
FootnoteNode: () => FootnoteNode,
|
|
47
|
+
LocationChipNode: () => LocationChipNode,
|
|
44
48
|
PageBreak: () => PageBreak,
|
|
49
|
+
PeopleChipNode: () => PeopleChipNode,
|
|
45
50
|
SlashMenuExtension: () => SlashMenuExtension,
|
|
46
51
|
TocEntryNode: () => TocEntryNode,
|
|
47
52
|
TocNode: () => TocNode,
|
|
@@ -65,8 +70,10 @@ __export(index_exports, {
|
|
|
65
70
|
headingsPlugin: () => headingsPlugin,
|
|
66
71
|
highlightPlugin: () => highlightPlugin,
|
|
67
72
|
imagePlugin: () => imagePlugin,
|
|
73
|
+
insertMarkdownBlock: () => insertMarkdownBlock,
|
|
68
74
|
linkPlugin: () => linkPlugin,
|
|
69
75
|
listsPlugin: () => listsPlugin,
|
|
76
|
+
markdownToFragment: () => markdownToFragment,
|
|
70
77
|
nextCitationId: () => nextCitationId,
|
|
71
78
|
onSlashStateChange: () => onSlashStateChange,
|
|
72
79
|
pageBreakPlugin: () => pageBreakPlugin,
|
|
@@ -76,6 +83,7 @@ __export(index_exports, {
|
|
|
76
83
|
sanitizeCiteprocHtml: () => sanitizeCiteprocHtml,
|
|
77
84
|
slashMenuPlugin: () => slashMenuPlugin,
|
|
78
85
|
slashState: () => slashState,
|
|
86
|
+
smartElementsPlugin: () => smartElementsPlugin,
|
|
79
87
|
tablePlugin: () => tablePlugin,
|
|
80
88
|
textColorPlugin: () => textColorPlugin,
|
|
81
89
|
tocPlugin: () => tocPlugin
|
|
@@ -2326,11 +2334,95 @@ var citationPlugin = (0, import_docflow_core17.definePlugin)({
|
|
|
2326
2334
|
});
|
|
2327
2335
|
|
|
2328
2336
|
// src/ai.ts
|
|
2329
|
-
var
|
|
2330
|
-
var
|
|
2337
|
+
var import_core9 = require("@tiptap/core");
|
|
2338
|
+
var import_state2 = require("@tiptap/pm/state");
|
|
2331
2339
|
var import_view = require("@tiptap/pm/view");
|
|
2340
|
+
var import_tiptap_markdown = require("tiptap-markdown");
|
|
2332
2341
|
var import_docflow_core18 = require("@kedataindo/docflow-core");
|
|
2333
|
-
|
|
2342
|
+
|
|
2343
|
+
// src/markdownInsert.ts
|
|
2344
|
+
var import_core8 = require("@tiptap/core");
|
|
2345
|
+
var import_model = require("@tiptap/pm/model");
|
|
2346
|
+
var import_state = require("@tiptap/pm/state");
|
|
2347
|
+
var import_transform = require("@tiptap/pm/transform");
|
|
2348
|
+
function mdParser(editor) {
|
|
2349
|
+
const storage = editor.storage.markdown;
|
|
2350
|
+
if (!storage || typeof storage !== "object") return void 0;
|
|
2351
|
+
const parser = storage.parser;
|
|
2352
|
+
if (!parser || typeof parser !== "object" || !("parse" in parser)) return void 0;
|
|
2353
|
+
return parser;
|
|
2354
|
+
}
|
|
2355
|
+
function markdownToFragment(editor, markdown, opts) {
|
|
2356
|
+
const parser = mdParser(editor);
|
|
2357
|
+
if (!parser) return null;
|
|
2358
|
+
let html;
|
|
2359
|
+
try {
|
|
2360
|
+
html = parser.parse(markdown, { inline: opts.inline });
|
|
2361
|
+
} catch {
|
|
2362
|
+
return null;
|
|
2363
|
+
}
|
|
2364
|
+
if (typeof html !== "string") return null;
|
|
2365
|
+
const content = (0, import_core8.createNodeFromContent)(html, editor.schema, {
|
|
2366
|
+
slice: true,
|
|
2367
|
+
parseOptions: { preserveWhitespace: "full" }
|
|
2368
|
+
});
|
|
2369
|
+
if (content instanceof import_model.Fragment) return content;
|
|
2370
|
+
return import_model.Fragment.from(content);
|
|
2371
|
+
}
|
|
2372
|
+
function selectionToInsertionEnd(tr, startLen, bias) {
|
|
2373
|
+
const last = tr.steps.length - 1;
|
|
2374
|
+
if (last < startLen) return;
|
|
2375
|
+
const step = tr.steps[last];
|
|
2376
|
+
if (!(step instanceof import_transform.ReplaceStep || step instanceof import_transform.ReplaceAroundStep)) return;
|
|
2377
|
+
const map = tr.mapping.maps[last];
|
|
2378
|
+
let end = 0;
|
|
2379
|
+
map.forEach((_from, _to, _newFrom, newTo) => {
|
|
2380
|
+
if (end === 0) end = newTo;
|
|
2381
|
+
});
|
|
2382
|
+
tr.setSelection(import_state.Selection.near(tr.doc.resolve(end), bias));
|
|
2383
|
+
}
|
|
2384
|
+
function insertMarkdownBlock(editor, view, from, to, markdown) {
|
|
2385
|
+
const fragment = markdownToFragment(editor, markdown, { inline: false });
|
|
2386
|
+
if (!fragment) {
|
|
2387
|
+
view.dispatch(view.state.tr.insertText(markdown, from, to));
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
const tr = view.state.tr;
|
|
2391
|
+
let f = from;
|
|
2392
|
+
let t = to;
|
|
2393
|
+
if (f === t) {
|
|
2394
|
+
let onlyBlock = true;
|
|
2395
|
+
fragment.forEach((n) => {
|
|
2396
|
+
if (!n.isBlock) onlyBlock = false;
|
|
2397
|
+
});
|
|
2398
|
+
if (onlyBlock) {
|
|
2399
|
+
const $pos = tr.doc.resolve(f);
|
|
2400
|
+
const parent = $pos.parent;
|
|
2401
|
+
if (parent.isTextblock && !parent.type.spec.code && !parent.childCount) {
|
|
2402
|
+
f -= 1;
|
|
2403
|
+
t += 1;
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
let onlyText = true;
|
|
2408
|
+
fragment.forEach((n) => {
|
|
2409
|
+
if (!n.isText || n.marks.length > 0) onlyText = false;
|
|
2410
|
+
});
|
|
2411
|
+
if (onlyText) {
|
|
2412
|
+
let text = "";
|
|
2413
|
+
fragment.forEach((n) => {
|
|
2414
|
+
if (n.isText) text += n.text ?? "";
|
|
2415
|
+
});
|
|
2416
|
+
tr.insertText(text, f, t);
|
|
2417
|
+
} else {
|
|
2418
|
+
tr.replaceWith(f, t, fragment);
|
|
2419
|
+
}
|
|
2420
|
+
selectionToInsertionEnd(tr, 0, -1);
|
|
2421
|
+
view.dispatch(tr);
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// src/ai.ts
|
|
2425
|
+
var aiPluginKey = new import_state2.PluginKey("docflow-ai");
|
|
2334
2426
|
var CONTEXT_CHARS = 1500;
|
|
2335
2427
|
function getAIPreview(editor) {
|
|
2336
2428
|
return editor.storage.ai ? editor.storage.ai.preview ?? null : null;
|
|
@@ -2371,7 +2463,7 @@ function stopStream(editor) {
|
|
|
2371
2463
|
storage.abort?.abort();
|
|
2372
2464
|
storage.abort = null;
|
|
2373
2465
|
}
|
|
2374
|
-
var AIExtension =
|
|
2466
|
+
var AIExtension = import_core9.Extension.create({
|
|
2375
2467
|
name: "ai",
|
|
2376
2468
|
addStorage() {
|
|
2377
2469
|
return {
|
|
@@ -2467,7 +2559,12 @@ var AIExtension = import_core8.Extension.create({
|
|
|
2467
2559
|
if (!dispatch) return true;
|
|
2468
2560
|
const tr = state.tr;
|
|
2469
2561
|
if (preview.text.trim()) {
|
|
2470
|
-
|
|
2562
|
+
const fragment = markdownToFragment(editor, preview.text, { inline: true });
|
|
2563
|
+
if (fragment) {
|
|
2564
|
+
tr.replaceWith(preview.from, preview.to, fragment);
|
|
2565
|
+
} else {
|
|
2566
|
+
tr.replaceWith(preview.from, preview.to, state.schema.text(preview.text));
|
|
2567
|
+
}
|
|
2471
2568
|
}
|
|
2472
2569
|
tr.setMeta(aiPluginKey, { type: "clear" });
|
|
2473
2570
|
dispatch(tr);
|
|
@@ -2561,7 +2658,7 @@ var AIExtension = import_core8.Extension.create({
|
|
|
2561
2658
|
};
|
|
2562
2659
|
}
|
|
2563
2660
|
return [
|
|
2564
|
-
new
|
|
2661
|
+
new import_state2.Plugin({
|
|
2565
2662
|
key: aiPluginKey,
|
|
2566
2663
|
state: {
|
|
2567
2664
|
init: () => null,
|
|
@@ -2679,13 +2776,21 @@ var AIExtension = import_core8.Extension.create({
|
|
|
2679
2776
|
});
|
|
2680
2777
|
var aiPlugin = (0, import_docflow_core18.definePlugin)({
|
|
2681
2778
|
id: "ai",
|
|
2682
|
-
|
|
2779
|
+
// The `tiptap-markdown` `Markdown` extension is registered alongside AI so
|
|
2780
|
+
// that `editor.storage.markdown.parser` is available on every editor that
|
|
2781
|
+
// can stream AI content. It adds a schema-aware markdown↔HTML bridge
|
|
2782
|
+
// (markdown-it under the hood) used by the AI Insert/accept paths to turn
|
|
2783
|
+
// streamed `| col | col |` tables / `# headings` / `**bold**` into real
|
|
2784
|
+
// nodes instead of literal pipe/asterisk text. Its `insertContentAt` /
|
|
2785
|
+
// `setContent` command overrides are intentionally NOT used by the AI
|
|
2786
|
+
// paths (they force `inline:true`); see `markdownInsert.ts`.
|
|
2787
|
+
tiptapExtensions: [AIExtension, import_tiptap_markdown.Markdown.configure({ html: true, linkify: true, breaks: false })],
|
|
2683
2788
|
slashCommands: [{ name: "AI", description: "Generate text with AI", command: "aiGenerate" }]
|
|
2684
2789
|
});
|
|
2685
2790
|
|
|
2686
2791
|
// src/comment.ts
|
|
2687
|
-
var
|
|
2688
|
-
var CommentMark =
|
|
2792
|
+
var import_core10 = require("@tiptap/core");
|
|
2793
|
+
var CommentMark = import_core10.Mark.create({
|
|
2689
2794
|
name: "comment",
|
|
2690
2795
|
// Comments are inclusive (typing inside an existing comment extends
|
|
2691
2796
|
// the mark range — that's the typical inline-comment UX). Excluding
|
|
@@ -2723,10 +2828,440 @@ var commentPlugin = {
|
|
|
2723
2828
|
commands: {}
|
|
2724
2829
|
};
|
|
2725
2830
|
|
|
2726
|
-
// src/
|
|
2727
|
-
var
|
|
2728
|
-
var import_state2 = require("@tiptap/pm/state");
|
|
2831
|
+
// src/smartElements.ts
|
|
2832
|
+
var import_core11 = require("@tiptap/core");
|
|
2729
2833
|
var import_docflow_core19 = require("@kedataindo/docflow-core");
|
|
2834
|
+
function todayISO() {
|
|
2835
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2836
|
+
}
|
|
2837
|
+
function formatDate(iso) {
|
|
2838
|
+
if (!iso) return "Pick a date";
|
|
2839
|
+
const d = /* @__PURE__ */ new Date(iso + "T00:00:00");
|
|
2840
|
+
if (isNaN(d.getTime())) return "Pick a date";
|
|
2841
|
+
return d.toLocaleDateString(void 0, { month: "short", day: "numeric", year: "numeric" });
|
|
2842
|
+
}
|
|
2843
|
+
function initialOf(name) {
|
|
2844
|
+
return (name || "?").trim().charAt(0).toUpperCase() || "?";
|
|
2845
|
+
}
|
|
2846
|
+
var DEFAULT_STATUSES = ["To Do", "In Progress", "Review", "Approved"];
|
|
2847
|
+
function slugify(s) {
|
|
2848
|
+
return s.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
2849
|
+
}
|
|
2850
|
+
var DateChipNode = import_core11.Node.create({
|
|
2851
|
+
name: "dateChip",
|
|
2852
|
+
group: "inline",
|
|
2853
|
+
inline: true,
|
|
2854
|
+
selectable: true,
|
|
2855
|
+
draggable: false,
|
|
2856
|
+
atom: true,
|
|
2857
|
+
addAttributes() {
|
|
2858
|
+
return {
|
|
2859
|
+
date: {
|
|
2860
|
+
default: todayISO(),
|
|
2861
|
+
parseHTML: (el) => el.getAttribute("data-date") ?? todayISO(),
|
|
2862
|
+
renderHTML: (attrs) => ({ "data-date": attrs.date ?? "" })
|
|
2863
|
+
}
|
|
2864
|
+
};
|
|
2865
|
+
},
|
|
2866
|
+
parseHTML() {
|
|
2867
|
+
return [{ tag: 'span[data-node-type="date-chip"]' }];
|
|
2868
|
+
},
|
|
2869
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
2870
|
+
return ["span", (0, import_core11.mergeAttributes)(HTMLAttributes, {
|
|
2871
|
+
"data-node-type": "date-chip",
|
|
2872
|
+
class: "docs-chip docs-chip--date"
|
|
2873
|
+
}), formatDate(node.attrs.date)];
|
|
2874
|
+
},
|
|
2875
|
+
addNodeView() {
|
|
2876
|
+
return (props) => {
|
|
2877
|
+
let currentNode = props.node;
|
|
2878
|
+
const getPos = props.getPos;
|
|
2879
|
+
const view = props.view;
|
|
2880
|
+
const dom = document.createElement("span");
|
|
2881
|
+
dom.className = "docs-chip docs-chip--date";
|
|
2882
|
+
dom.setAttribute("data-node-type", "date-chip");
|
|
2883
|
+
dom.setAttribute("contenteditable", "false");
|
|
2884
|
+
const render = () => {
|
|
2885
|
+
if (dom.querySelector("input")) return;
|
|
2886
|
+
dom.textContent = formatDate(currentNode.attrs.date);
|
|
2887
|
+
dom.setAttribute("data-date", currentNode.attrs.date);
|
|
2888
|
+
};
|
|
2889
|
+
render();
|
|
2890
|
+
dom.addEventListener("click", (e) => {
|
|
2891
|
+
e.preventDefault();
|
|
2892
|
+
e.stopPropagation();
|
|
2893
|
+
if (dom.querySelector("input")) return;
|
|
2894
|
+
const input = document.createElement("input");
|
|
2895
|
+
input.type = "date";
|
|
2896
|
+
input.value = currentNode.attrs.date;
|
|
2897
|
+
input.className = "docs-chip-date-input";
|
|
2898
|
+
dom.replaceChildren(input);
|
|
2899
|
+
input.focus();
|
|
2900
|
+
const commit = () => {
|
|
2901
|
+
const newVal = input.value;
|
|
2902
|
+
const pos = getPos();
|
|
2903
|
+
if (typeof pos === "number") {
|
|
2904
|
+
view.dispatch(view.state.tr.setNodeMarkup(pos, void 0, { date: newVal }));
|
|
2905
|
+
}
|
|
2906
|
+
setTimeout(render, 30);
|
|
2907
|
+
};
|
|
2908
|
+
input.addEventListener("change", commit);
|
|
2909
|
+
input.addEventListener("blur", () => setTimeout(render, 30));
|
|
2910
|
+
});
|
|
2911
|
+
return {
|
|
2912
|
+
dom,
|
|
2913
|
+
update(updatedNode) {
|
|
2914
|
+
if (updatedNode.type.name !== "dateChip") return false;
|
|
2915
|
+
currentNode = updatedNode;
|
|
2916
|
+
render();
|
|
2917
|
+
return true;
|
|
2918
|
+
}
|
|
2919
|
+
};
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
});
|
|
2923
|
+
var PeopleChipNode = import_core11.Node.create({
|
|
2924
|
+
name: "peopleChip",
|
|
2925
|
+
group: "inline",
|
|
2926
|
+
inline: true,
|
|
2927
|
+
selectable: true,
|
|
2928
|
+
draggable: false,
|
|
2929
|
+
atom: true,
|
|
2930
|
+
addAttributes() {
|
|
2931
|
+
return {
|
|
2932
|
+
userId: {
|
|
2933
|
+
default: "",
|
|
2934
|
+
parseHTML: (el) => el.getAttribute("data-user-id") ?? "",
|
|
2935
|
+
renderHTML: (attrs) => attrs.userId ? { "data-user-id": attrs.userId } : {}
|
|
2936
|
+
},
|
|
2937
|
+
name: {
|
|
2938
|
+
default: "",
|
|
2939
|
+
parseHTML: (el) => el.getAttribute("data-name") ?? "",
|
|
2940
|
+
renderHTML: (attrs) => ({ "data-name": attrs.name ?? "" })
|
|
2941
|
+
}
|
|
2942
|
+
};
|
|
2943
|
+
},
|
|
2944
|
+
parseHTML() {
|
|
2945
|
+
return [{ tag: 'span[data-node-type="people-chip"]' }];
|
|
2946
|
+
},
|
|
2947
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
2948
|
+
return ["span", (0, import_core11.mergeAttributes)(HTMLAttributes, {
|
|
2949
|
+
"data-node-type": "people-chip",
|
|
2950
|
+
class: "docs-chip docs-chip--people"
|
|
2951
|
+
}), `@${node.attrs.name || "user"}`];
|
|
2952
|
+
},
|
|
2953
|
+
addNodeView() {
|
|
2954
|
+
return (props) => {
|
|
2955
|
+
let currentNode = props.node;
|
|
2956
|
+
const dom = document.createElement("span");
|
|
2957
|
+
dom.className = "docs-chip docs-chip--people";
|
|
2958
|
+
dom.setAttribute("data-node-type", "people-chip");
|
|
2959
|
+
dom.setAttribute("contenteditable", "false");
|
|
2960
|
+
const render = () => {
|
|
2961
|
+
const name = currentNode.attrs.name || "user";
|
|
2962
|
+
dom.innerHTML = "";
|
|
2963
|
+
const avatar = document.createElement("span");
|
|
2964
|
+
avatar.className = "docs-chip-avatar";
|
|
2965
|
+
avatar.textContent = initialOf(name);
|
|
2966
|
+
dom.appendChild(avatar);
|
|
2967
|
+
const label = document.createElement("span");
|
|
2968
|
+
label.className = "docs-chip-label";
|
|
2969
|
+
label.textContent = "@" + name;
|
|
2970
|
+
dom.appendChild(label);
|
|
2971
|
+
};
|
|
2972
|
+
render();
|
|
2973
|
+
return {
|
|
2974
|
+
dom,
|
|
2975
|
+
update(updatedNode) {
|
|
2976
|
+
if (updatedNode.type.name !== "peopleChip") return false;
|
|
2977
|
+
currentNode = updatedNode;
|
|
2978
|
+
render();
|
|
2979
|
+
return true;
|
|
2980
|
+
}
|
|
2981
|
+
};
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2984
|
+
});
|
|
2985
|
+
var FileChipNode = import_core11.Node.create({
|
|
2986
|
+
name: "fileChip",
|
|
2987
|
+
group: "inline",
|
|
2988
|
+
inline: true,
|
|
2989
|
+
selectable: true,
|
|
2990
|
+
draggable: false,
|
|
2991
|
+
atom: true,
|
|
2992
|
+
addAttributes() {
|
|
2993
|
+
return {
|
|
2994
|
+
fileId: {
|
|
2995
|
+
default: "",
|
|
2996
|
+
parseHTML: (el) => el.getAttribute("data-file-id") ?? "",
|
|
2997
|
+
renderHTML: (attrs) => attrs.fileId ? { "data-file-id": attrs.fileId } : {}
|
|
2998
|
+
},
|
|
2999
|
+
name: {
|
|
3000
|
+
default: "",
|
|
3001
|
+
parseHTML: (el) => el.getAttribute("data-name") ?? "",
|
|
3002
|
+
renderHTML: (attrs) => ({ "data-name": attrs.name ?? "" })
|
|
3003
|
+
}
|
|
3004
|
+
};
|
|
3005
|
+
},
|
|
3006
|
+
parseHTML() {
|
|
3007
|
+
return [{ tag: 'span[data-node-type="file-chip"]' }];
|
|
3008
|
+
},
|
|
3009
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
3010
|
+
return ["span", (0, import_core11.mergeAttributes)(HTMLAttributes, {
|
|
3011
|
+
"data-node-type": "file-chip",
|
|
3012
|
+
class: "docs-chip docs-chip--file"
|
|
3013
|
+
}), node.attrs.name || "file"];
|
|
3014
|
+
},
|
|
3015
|
+
addNodeView() {
|
|
3016
|
+
return (props) => {
|
|
3017
|
+
let currentNode = props.node;
|
|
3018
|
+
const dom = document.createElement("span");
|
|
3019
|
+
dom.className = "docs-chip docs-chip--file";
|
|
3020
|
+
dom.setAttribute("data-node-type", "file-chip");
|
|
3021
|
+
dom.setAttribute("contenteditable", "false");
|
|
3022
|
+
const render = () => {
|
|
3023
|
+
const name = currentNode.attrs.name || "Untitled file";
|
|
3024
|
+
dom.innerHTML = "";
|
|
3025
|
+
const icon = document.createElement("span");
|
|
3026
|
+
icon.className = "docs-chip-icon";
|
|
3027
|
+
icon.textContent = "\u{1F5CE}";
|
|
3028
|
+
dom.appendChild(icon);
|
|
3029
|
+
const label = document.createElement("span");
|
|
3030
|
+
label.className = "docs-chip-label";
|
|
3031
|
+
label.textContent = name;
|
|
3032
|
+
dom.appendChild(label);
|
|
3033
|
+
};
|
|
3034
|
+
render();
|
|
3035
|
+
return {
|
|
3036
|
+
dom,
|
|
3037
|
+
update(updatedNode) {
|
|
3038
|
+
if (updatedNode.type.name !== "fileChip") return false;
|
|
3039
|
+
currentNode = updatedNode;
|
|
3040
|
+
render();
|
|
3041
|
+
return true;
|
|
3042
|
+
}
|
|
3043
|
+
};
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
3046
|
+
});
|
|
3047
|
+
var DropdownChipNode = import_core11.Node.create({
|
|
3048
|
+
name: "dropdownChip",
|
|
3049
|
+
group: "inline",
|
|
3050
|
+
inline: true,
|
|
3051
|
+
selectable: true,
|
|
3052
|
+
draggable: false,
|
|
3053
|
+
atom: true,
|
|
3054
|
+
addAttributes() {
|
|
3055
|
+
return {
|
|
3056
|
+
options: {
|
|
3057
|
+
default: DEFAULT_STATUSES,
|
|
3058
|
+
parseHTML: (el) => {
|
|
3059
|
+
const raw = el.getAttribute("data-options") ?? "";
|
|
3060
|
+
const list = raw ? raw.split("|") : [];
|
|
3061
|
+
return list.length ? list : DEFAULT_STATUSES;
|
|
3062
|
+
},
|
|
3063
|
+
renderHTML: (attrs) => ({
|
|
3064
|
+
"data-options": (attrs.options ?? []).join("|")
|
|
3065
|
+
})
|
|
3066
|
+
},
|
|
3067
|
+
selected: {
|
|
3068
|
+
default: DEFAULT_STATUSES[0],
|
|
3069
|
+
parseHTML: (el) => el.getAttribute("data-selected") ?? DEFAULT_STATUSES[0],
|
|
3070
|
+
renderHTML: (attrs) => ({ "data-selected": attrs.selected ?? "" })
|
|
3071
|
+
}
|
|
3072
|
+
};
|
|
3073
|
+
},
|
|
3074
|
+
parseHTML() {
|
|
3075
|
+
return [{ tag: 'span[data-node-type="dropdown-chip"]' }];
|
|
3076
|
+
},
|
|
3077
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
3078
|
+
return ["span", (0, import_core11.mergeAttributes)(HTMLAttributes, {
|
|
3079
|
+
"data-node-type": "dropdown-chip",
|
|
3080
|
+
class: "docs-chip docs-chip--dropdown"
|
|
3081
|
+
}), node.attrs.selected || ""];
|
|
3082
|
+
},
|
|
3083
|
+
addNodeView() {
|
|
3084
|
+
return (props) => {
|
|
3085
|
+
let currentNode = props.node;
|
|
3086
|
+
const getPos = props.getPos;
|
|
3087
|
+
const view = props.view;
|
|
3088
|
+
const dom = document.createElement("span");
|
|
3089
|
+
dom.className = "docs-chip docs-chip--dropdown";
|
|
3090
|
+
dom.setAttribute("data-node-type", "dropdown-chip");
|
|
3091
|
+
dom.setAttribute("contenteditable", "false");
|
|
3092
|
+
const render = () => {
|
|
3093
|
+
const opts = currentNode.attrs.options ?? DEFAULT_STATUSES;
|
|
3094
|
+
const sel = currentNode.attrs.selected ?? (opts[0] ?? "");
|
|
3095
|
+
dom.innerHTML = "";
|
|
3096
|
+
const select = document.createElement("select");
|
|
3097
|
+
select.className = "docs-chip-select";
|
|
3098
|
+
select.addEventListener("mousedown", (e) => e.stopPropagation());
|
|
3099
|
+
for (const opt of opts) {
|
|
3100
|
+
const o = document.createElement("option");
|
|
3101
|
+
o.value = opt;
|
|
3102
|
+
o.textContent = opt;
|
|
3103
|
+
if (opt === sel) o.selected = true;
|
|
3104
|
+
select.appendChild(o);
|
|
3105
|
+
}
|
|
3106
|
+
select.addEventListener("change", () => {
|
|
3107
|
+
const pos = getPos();
|
|
3108
|
+
if (typeof pos === "number") {
|
|
3109
|
+
view.dispatch(view.state.tr.setNodeMarkup(pos, void 0, {
|
|
3110
|
+
...currentNode.attrs,
|
|
3111
|
+
selected: select.value
|
|
3112
|
+
}));
|
|
3113
|
+
}
|
|
3114
|
+
});
|
|
3115
|
+
dom.appendChild(select);
|
|
3116
|
+
};
|
|
3117
|
+
render();
|
|
3118
|
+
return {
|
|
3119
|
+
dom,
|
|
3120
|
+
update(updatedNode) {
|
|
3121
|
+
if (updatedNode.type.name !== "dropdownChip") return false;
|
|
3122
|
+
currentNode = updatedNode;
|
|
3123
|
+
render();
|
|
3124
|
+
return true;
|
|
3125
|
+
}
|
|
3126
|
+
};
|
|
3127
|
+
};
|
|
3128
|
+
}
|
|
3129
|
+
});
|
|
3130
|
+
var LocationChipNode = import_core11.Node.create({
|
|
3131
|
+
name: "locationChip",
|
|
3132
|
+
group: "inline",
|
|
3133
|
+
inline: true,
|
|
3134
|
+
selectable: true,
|
|
3135
|
+
draggable: false,
|
|
3136
|
+
atom: true,
|
|
3137
|
+
addAttributes() {
|
|
3138
|
+
return {
|
|
3139
|
+
label: {
|
|
3140
|
+
default: "",
|
|
3141
|
+
parseHTML: (el) => el.getAttribute("data-label") ?? "",
|
|
3142
|
+
renderHTML: (attrs) => ({ "data-label": attrs.label ?? "" })
|
|
3143
|
+
},
|
|
3144
|
+
lat: {
|
|
3145
|
+
default: null,
|
|
3146
|
+
parseHTML: (el) => {
|
|
3147
|
+
const v = el.getAttribute("data-lat");
|
|
3148
|
+
return v === null ? null : Number(v);
|
|
3149
|
+
},
|
|
3150
|
+
renderHTML: (attrs) => attrs.lat != null ? { "data-lat": attrs.lat } : {}
|
|
3151
|
+
},
|
|
3152
|
+
lng: {
|
|
3153
|
+
default: null,
|
|
3154
|
+
parseHTML: (el) => {
|
|
3155
|
+
const v = el.getAttribute("data-lng");
|
|
3156
|
+
return v === null ? null : Number(v);
|
|
3157
|
+
},
|
|
3158
|
+
renderHTML: (attrs) => attrs.lng != null ? { "data-lng": attrs.lng } : {}
|
|
3159
|
+
}
|
|
3160
|
+
};
|
|
3161
|
+
},
|
|
3162
|
+
parseHTML() {
|
|
3163
|
+
return [{ tag: 'span[data-node-type="location-chip"]' }];
|
|
3164
|
+
},
|
|
3165
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
3166
|
+
return ["span", (0, import_core11.mergeAttributes)(HTMLAttributes, {
|
|
3167
|
+
"data-node-type": "location-chip",
|
|
3168
|
+
class: "docs-chip docs-chip--location"
|
|
3169
|
+
}), node.attrs.label || ""];
|
|
3170
|
+
},
|
|
3171
|
+
addNodeView() {
|
|
3172
|
+
return (props) => {
|
|
3173
|
+
let currentNode = props.node;
|
|
3174
|
+
const dom = document.createElement("span");
|
|
3175
|
+
dom.className = "docs-chip docs-chip--location";
|
|
3176
|
+
dom.setAttribute("data-node-type", "location-chip");
|
|
3177
|
+
dom.setAttribute("contenteditable", "false");
|
|
3178
|
+
const render = () => {
|
|
3179
|
+
const label = currentNode.attrs.label || "Add location";
|
|
3180
|
+
dom.innerHTML = "";
|
|
3181
|
+
const icon = document.createElement("span");
|
|
3182
|
+
icon.className = "docs-chip-icon";
|
|
3183
|
+
icon.textContent = "\u{1F4CD}";
|
|
3184
|
+
dom.appendChild(icon);
|
|
3185
|
+
const lbl = document.createElement("span");
|
|
3186
|
+
lbl.className = "docs-chip-label";
|
|
3187
|
+
lbl.textContent = label;
|
|
3188
|
+
dom.appendChild(lbl);
|
|
3189
|
+
};
|
|
3190
|
+
render();
|
|
3191
|
+
return {
|
|
3192
|
+
dom,
|
|
3193
|
+
update(updatedNode) {
|
|
3194
|
+
if (updatedNode.type.name !== "locationChip") return false;
|
|
3195
|
+
currentNode = updatedNode;
|
|
3196
|
+
render();
|
|
3197
|
+
return true;
|
|
3198
|
+
}
|
|
3199
|
+
};
|
|
3200
|
+
};
|
|
3201
|
+
}
|
|
3202
|
+
});
|
|
3203
|
+
var smartElementsPlugin = (0, import_docflow_core19.definePlugin)({
|
|
3204
|
+
id: "smart-elements",
|
|
3205
|
+
tiptapExtensions: [
|
|
3206
|
+
DateChipNode,
|
|
3207
|
+
PeopleChipNode,
|
|
3208
|
+
FileChipNode,
|
|
3209
|
+
DropdownChipNode,
|
|
3210
|
+
LocationChipNode
|
|
3211
|
+
],
|
|
3212
|
+
slashCommands: [
|
|
3213
|
+
{ name: "Date", command: "insertDateChip" },
|
|
3214
|
+
{ name: "People", command: "insertPeopleChip" },
|
|
3215
|
+
{ name: "File", command: "insertFileChip" },
|
|
3216
|
+
{ name: "Dropdown", command: "insertDropdownChip" },
|
|
3217
|
+
{ name: "Location", command: "insertLocationChip" }
|
|
3218
|
+
],
|
|
3219
|
+
commands: {
|
|
3220
|
+
insertDateChip: (editor) => {
|
|
3221
|
+
return editor.chain().focus().insertContent({
|
|
3222
|
+
type: "dateChip",
|
|
3223
|
+
attrs: { date: todayISO() }
|
|
3224
|
+
}).run();
|
|
3225
|
+
},
|
|
3226
|
+
insertPeopleChip: (editor) => {
|
|
3227
|
+
const name = typeof window !== "undefined" && typeof window.prompt === "function" ? window.prompt("Enter user name:", "") ?? "" : "";
|
|
3228
|
+
if (!name.trim()) return false;
|
|
3229
|
+
const trimmed = name.trim();
|
|
3230
|
+
return editor.chain().focus().insertContent({
|
|
3231
|
+
type: "peopleChip",
|
|
3232
|
+
attrs: { userId: slugify(trimmed), name: trimmed }
|
|
3233
|
+
}).run();
|
|
3234
|
+
},
|
|
3235
|
+
insertFileChip: (editor) => {
|
|
3236
|
+
const name = typeof window !== "undefined" && typeof window.prompt === "function" ? window.prompt("Enter file/document name:", "") ?? "" : "";
|
|
3237
|
+
if (!name.trim()) return false;
|
|
3238
|
+
const trimmed = name.trim();
|
|
3239
|
+
return editor.chain().focus().insertContent({
|
|
3240
|
+
type: "fileChip",
|
|
3241
|
+
attrs: { fileId: slugify(trimmed), name: trimmed }
|
|
3242
|
+
}).run();
|
|
3243
|
+
},
|
|
3244
|
+
insertDropdownChip: (editor) => {
|
|
3245
|
+
return editor.chain().focus().insertContent({
|
|
3246
|
+
type: "dropdownChip",
|
|
3247
|
+
attrs: { options: DEFAULT_STATUSES, selected: DEFAULT_STATUSES[0] }
|
|
3248
|
+
}).run();
|
|
3249
|
+
},
|
|
3250
|
+
insertLocationChip: (editor) => {
|
|
3251
|
+
const label = typeof window !== "undefined" && typeof window.prompt === "function" ? window.prompt("Enter location name:", "") ?? "" : "";
|
|
3252
|
+
if (!label.trim()) return false;
|
|
3253
|
+
return editor.chain().focus().insertContent({
|
|
3254
|
+
type: "locationChip",
|
|
3255
|
+
attrs: { label: label.trim() }
|
|
3256
|
+
}).run();
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
});
|
|
3260
|
+
|
|
3261
|
+
// src/slashMenu.ts
|
|
3262
|
+
var import_core12 = require("@tiptap/core");
|
|
3263
|
+
var import_state3 = require("@tiptap/pm/state");
|
|
3264
|
+
var import_docflow_core20 = require("@kedataindo/docflow-core");
|
|
2730
3265
|
var slashState = {
|
|
2731
3266
|
open: false,
|
|
2732
3267
|
query: "",
|
|
@@ -2780,12 +3315,12 @@ function getRegisteredCommands() {
|
|
|
2780
3315
|
return true;
|
|
2781
3316
|
});
|
|
2782
3317
|
}
|
|
2783
|
-
var SlashMenuExtension =
|
|
3318
|
+
var SlashMenuExtension = import_core12.Extension.create({
|
|
2784
3319
|
name: "slashMenu",
|
|
2785
3320
|
addProseMirrorPlugins() {
|
|
2786
3321
|
return [
|
|
2787
|
-
new
|
|
2788
|
-
key: new
|
|
3322
|
+
new import_state3.Plugin({
|
|
3323
|
+
key: new import_state3.PluginKey("slashMenu"),
|
|
2789
3324
|
props: {
|
|
2790
3325
|
handleTextInput(view, from, _to, text) {
|
|
2791
3326
|
if (text === "/") {
|
|
@@ -2871,7 +3406,7 @@ var SlashMenuExtension = import_core10.Extension.create({
|
|
|
2871
3406
|
];
|
|
2872
3407
|
}
|
|
2873
3408
|
});
|
|
2874
|
-
var slashMenuPlugin = (0,
|
|
3409
|
+
var slashMenuPlugin = (0, import_docflow_core20.definePlugin)({
|
|
2875
3410
|
id: "slash-menu",
|
|
2876
3411
|
tiptapExtensions: [SlashMenuExtension],
|
|
2877
3412
|
hooks: {
|
|
@@ -2902,7 +3437,8 @@ var defaultPlugins = [
|
|
|
2902
3437
|
highlightPlugin,
|
|
2903
3438
|
citationPlugin,
|
|
2904
3439
|
aiPlugin,
|
|
2905
|
-
commentPlugin
|
|
3440
|
+
commentPlugin,
|
|
3441
|
+
smartElementsPlugin
|
|
2906
3442
|
];
|
|
2907
3443
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2908
3444
|
0 && (module.exports = {
|
|
@@ -2915,9 +3451,14 @@ var defaultPlugins = [
|
|
|
2915
3451
|
CiteEngine,
|
|
2916
3452
|
CommentMarkExtension,
|
|
2917
3453
|
DEFAULT_CSL_STYLE,
|
|
3454
|
+
DateChipNode,
|
|
3455
|
+
DropdownChipNode,
|
|
3456
|
+
FileChipNode,
|
|
2918
3457
|
FontSizeExtension,
|
|
2919
3458
|
FootnoteNode,
|
|
3459
|
+
LocationChipNode,
|
|
2920
3460
|
PageBreak,
|
|
3461
|
+
PeopleChipNode,
|
|
2921
3462
|
SlashMenuExtension,
|
|
2922
3463
|
TocEntryNode,
|
|
2923
3464
|
TocNode,
|
|
@@ -2941,8 +3482,10 @@ var defaultPlugins = [
|
|
|
2941
3482
|
headingsPlugin,
|
|
2942
3483
|
highlightPlugin,
|
|
2943
3484
|
imagePlugin,
|
|
3485
|
+
insertMarkdownBlock,
|
|
2944
3486
|
linkPlugin,
|
|
2945
3487
|
listsPlugin,
|
|
3488
|
+
markdownToFragment,
|
|
2946
3489
|
nextCitationId,
|
|
2947
3490
|
onSlashStateChange,
|
|
2948
3491
|
pageBreakPlugin,
|
|
@@ -2952,6 +3495,7 @@ var defaultPlugins = [
|
|
|
2952
3495
|
sanitizeCiteprocHtml,
|
|
2953
3496
|
slashMenuPlugin,
|
|
2954
3497
|
slashState,
|
|
3498
|
+
smartElementsPlugin,
|
|
2955
3499
|
tablePlugin,
|
|
2956
3500
|
textColorPlugin,
|
|
2957
3501
|
tocPlugin
|