@sendbird/actionbook-core 0.9.3 → 0.9.7
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.js +20 -7
- package/dist/index.js.map +1 -1
- package/dist/ui/index.d.ts +5 -1
- package/dist/ui/index.js +1045 -193
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var actionbookSchema = new Schema({
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
heading: {
|
|
17
|
-
content: "
|
|
17
|
+
content: "(text | jumpPoint | hardBreak)*",
|
|
18
18
|
group: "block",
|
|
19
19
|
attrs: { level: { default: 1 } },
|
|
20
20
|
parseDOM: [
|
|
@@ -2734,6 +2734,39 @@ var ITALIC_STAR_RE = /(?:^|[^*])\*([^*]+)\*$/;
|
|
|
2734
2734
|
var ITALIC_UNDER_RE = /(?:^|[^_])_([^_]+)_$/;
|
|
2735
2735
|
var STRIKE_RE = /(?:^|[^~])~~([^~]+)~~$/;
|
|
2736
2736
|
var CODE_RE = /(?:^|[^`])`([^`]+)`$/;
|
|
2737
|
+
function findParentList(state, pos) {
|
|
2738
|
+
const $pos = state.doc.resolve(pos);
|
|
2739
|
+
const { bulletList: blType, orderedList: olType } = actionbookSchema.nodes;
|
|
2740
|
+
for (let d = $pos.depth; d > 0; d--) {
|
|
2741
|
+
const node = $pos.node(d);
|
|
2742
|
+
if (node.type === blType || node.type === olType) {
|
|
2743
|
+
return { depth: d, node };
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
return null;
|
|
2747
|
+
}
|
|
2748
|
+
function handleListInputRule(state, start, end, listType, attrs) {
|
|
2749
|
+
const resolvePos = Math.max(start, end - 1);
|
|
2750
|
+
const parentList = findParentList(state, resolvePos);
|
|
2751
|
+
if (!parentList) return null;
|
|
2752
|
+
const $from = state.doc.resolve(resolvePos);
|
|
2753
|
+
const { depth, node: listNode } = parentList;
|
|
2754
|
+
const paraContentSize = $from.parent.content.size;
|
|
2755
|
+
const matchedLen = end - start;
|
|
2756
|
+
if (paraContentSize !== matchedLen) return null;
|
|
2757
|
+
const listStart = $from.before(depth);
|
|
2758
|
+
const listEnd = $from.after(depth);
|
|
2759
|
+
if (listNode.type === listType) {
|
|
2760
|
+
const tr = state.tr.replaceWith(listStart, listEnd, actionbookSchema.nodes.paragraph.create());
|
|
2761
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(listStart)));
|
|
2762
|
+
return tr;
|
|
2763
|
+
} else {
|
|
2764
|
+
const tr = state.tr.delete(start, end);
|
|
2765
|
+
const mappedListPos = tr.mapping.map(listStart);
|
|
2766
|
+
tr.setNodeMarkup(mappedListPos, listType, attrs ?? null);
|
|
2767
|
+
return tr;
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2737
2770
|
function markInputRule(pattern, markType, markerLen) {
|
|
2738
2771
|
return new InputRule(pattern, (state, match, start, end) => {
|
|
2739
2772
|
const textContent2 = match[1];
|
|
@@ -2798,12 +2831,30 @@ function createInputRulesPlugin() {
|
|
|
2798
2831
|
return state.tr.delete(start, end).insert(start, list);
|
|
2799
2832
|
})
|
|
2800
2833
|
);
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
wrappingInputRule(
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2834
|
+
{
|
|
2835
|
+
const blType = actionbookSchema.nodes.bulletList;
|
|
2836
|
+
const fallback = wrappingInputRule(BULLET_LIST_RE, blType);
|
|
2837
|
+
rules.push(
|
|
2838
|
+
new InputRule(BULLET_LIST_RE, (state, match, start, end) => {
|
|
2839
|
+
const toggled = handleListInputRule(state, start, end, blType);
|
|
2840
|
+
if (toggled) return toggled;
|
|
2841
|
+
const handler = fallback.handler;
|
|
2842
|
+
return handler(state, match, start, end);
|
|
2843
|
+
})
|
|
2844
|
+
);
|
|
2845
|
+
}
|
|
2846
|
+
{
|
|
2847
|
+
const olType = actionbookSchema.nodes.orderedList;
|
|
2848
|
+
const fallback = wrappingInputRule(ORDERED_LIST_RE, olType, (m) => ({ start: +m[1] }));
|
|
2849
|
+
rules.push(
|
|
2850
|
+
new InputRule(ORDERED_LIST_RE, (state, match, start, end) => {
|
|
2851
|
+
const toggled = handleListInputRule(state, start, end, olType, { start: +match[1] });
|
|
2852
|
+
if (toggled) return toggled;
|
|
2853
|
+
const handler = fallback.handler;
|
|
2854
|
+
return handler(state, match, start, end);
|
|
2855
|
+
})
|
|
2856
|
+
);
|
|
2857
|
+
}
|
|
2807
2858
|
const jumpPointType = actionbookSchema.nodes.jumpPoint;
|
|
2808
2859
|
rules.push(
|
|
2809
2860
|
new InputRule(JUMP_POINT_RE2, (state, match, start, end) => {
|
|
@@ -2816,7 +2867,12 @@ function createInputRulesPlugin() {
|
|
|
2816
2867
|
}
|
|
2817
2868
|
});
|
|
2818
2869
|
if (exists) return null;
|
|
2819
|
-
|
|
2870
|
+
const tr = state.tr.delete(start, end).insert(start, jumpPointType.create({ id }));
|
|
2871
|
+
const afterAtom = start + 1;
|
|
2872
|
+
tr.insertText(" ", afterAtom);
|
|
2873
|
+
const cursorPos = afterAtom + 1;
|
|
2874
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(Math.min(cursorPos, tr.doc.content.size))));
|
|
2875
|
+
return tr;
|
|
2820
2876
|
})
|
|
2821
2877
|
);
|
|
2822
2878
|
rules.push(markInputRule(BOLD_STAR_RE, actionbookSchema.marks.bold, 2));
|
|
@@ -2845,8 +2901,100 @@ function createHistoryPlugin() {
|
|
|
2845
2901
|
|
|
2846
2902
|
// src/ui/plugin/keymapPlugin.ts
|
|
2847
2903
|
import { baseKeymap, chainCommands, newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock, toggleMark, setBlockType, joinBackward } from "prosemirror-commands";
|
|
2904
|
+
import { TextSelection as TextSelection2 } from "prosemirror-state";
|
|
2848
2905
|
import { keymap as keymap3 } from "prosemirror-keymap";
|
|
2849
2906
|
import { liftListItem, sinkListItem, splitListItem, wrapInList } from "prosemirror-schema-list";
|
|
2907
|
+
|
|
2908
|
+
// src/ui/plugin/noteBlockPlugin.tsx
|
|
2909
|
+
import { Selection } from "prosemirror-state";
|
|
2910
|
+
var NoteBlockView = class {
|
|
2911
|
+
dom;
|
|
2912
|
+
contentDOM;
|
|
2913
|
+
constructor(_node, _view, _getPos) {
|
|
2914
|
+
this.dom = document.createElement("div");
|
|
2915
|
+
this.dom.setAttribute("data-note-block", "");
|
|
2916
|
+
this.dom.className = "ab-note-block";
|
|
2917
|
+
this.dom.style.cssText = [
|
|
2918
|
+
"position: relative",
|
|
2919
|
+
"margin: 8px 0",
|
|
2920
|
+
"padding: 16px 24px",
|
|
2921
|
+
"background: #fff",
|
|
2922
|
+
"border: 1px dashed #ccc",
|
|
2923
|
+
"border-radius: 4px",
|
|
2924
|
+
"display: flex",
|
|
2925
|
+
"flex-direction: column",
|
|
2926
|
+
"gap: 4px"
|
|
2927
|
+
].join(";");
|
|
2928
|
+
const label = document.createElement("span");
|
|
2929
|
+
label.contentEditable = "false";
|
|
2930
|
+
label.textContent = "Note";
|
|
2931
|
+
label.style.cssText = [
|
|
2932
|
+
"font-family: SF Pro Text, -apple-system, BlinkMacSystemFont, sans-serif",
|
|
2933
|
+
"display: inline-flex",
|
|
2934
|
+
"align-items: center",
|
|
2935
|
+
"justify-content: center",
|
|
2936
|
+
"align-self: flex-start",
|
|
2937
|
+
"font-size: 12px",
|
|
2938
|
+
"font-weight: 400",
|
|
2939
|
+
"font-style: normal",
|
|
2940
|
+
"line-height: 16px",
|
|
2941
|
+
"color: #858585",
|
|
2942
|
+
"background: #f7f7f7",
|
|
2943
|
+
"border: 1px solid #e0e0e0",
|
|
2944
|
+
"border-radius: 4px",
|
|
2945
|
+
"padding: 2px 4px",
|
|
2946
|
+
"user-select: none",
|
|
2947
|
+
"height: 20px"
|
|
2948
|
+
].join(";");
|
|
2949
|
+
this.dom.appendChild(label);
|
|
2950
|
+
this.contentDOM = document.createElement("div");
|
|
2951
|
+
this.contentDOM.className = "ab-note-block-content";
|
|
2952
|
+
this.contentDOM.style.cssText = [
|
|
2953
|
+
"font-size: 14px",
|
|
2954
|
+
"font-style: italic",
|
|
2955
|
+
"font-weight: 400",
|
|
2956
|
+
"line-height: 20px",
|
|
2957
|
+
"letter-spacing: -0.1px",
|
|
2958
|
+
"color: #858585"
|
|
2959
|
+
].join(";");
|
|
2960
|
+
this.dom.appendChild(this.contentDOM);
|
|
2961
|
+
}
|
|
2962
|
+
};
|
|
2963
|
+
var exitNoteBlockOnEnter = (state, dispatch) => {
|
|
2964
|
+
const { $from } = state.selection;
|
|
2965
|
+
let noteBlockDepth = -1;
|
|
2966
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
2967
|
+
if ($from.node(d).type.name === "noteBlock") {
|
|
2968
|
+
noteBlockDepth = d;
|
|
2969
|
+
break;
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
if (noteBlockDepth < 0) return false;
|
|
2973
|
+
const parentNode = $from.parent;
|
|
2974
|
+
if (parentNode.type.name !== "paragraph" || parentNode.content.size !== 0) {
|
|
2975
|
+
return false;
|
|
2976
|
+
}
|
|
2977
|
+
if (!dispatch) return true;
|
|
2978
|
+
const paragraphStart = $from.before($from.depth);
|
|
2979
|
+
const paragraphEnd = $from.after($from.depth);
|
|
2980
|
+
const tr = state.tr.delete(paragraphStart, paragraphEnd);
|
|
2981
|
+
const noteBlockEnd = tr.mapping.map($from.after(noteBlockDepth));
|
|
2982
|
+
const newParagraph = state.schema.nodes.paragraph.create();
|
|
2983
|
+
tr.insert(noteBlockEnd, newParagraph);
|
|
2984
|
+
tr.setSelection(Selection.near(tr.doc.resolve(noteBlockEnd + 1)));
|
|
2985
|
+
dispatch(tr.scrollIntoView());
|
|
2986
|
+
return true;
|
|
2987
|
+
};
|
|
2988
|
+
function createNoteBlockPlugin() {
|
|
2989
|
+
return {
|
|
2990
|
+
name: "noteBlockNodeView",
|
|
2991
|
+
nodeViews: () => ({
|
|
2992
|
+
noteBlock: (node, view, getPos) => new NoteBlockView(node, view, getPos)
|
|
2993
|
+
})
|
|
2994
|
+
};
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
// src/ui/plugin/keymapPlugin.ts
|
|
2850
2998
|
var TAB_CHAR = " ";
|
|
2851
2999
|
var { listItem, bulletList, orderedList, hardBreak, heading, paragraph, horizontalRule, blockquote } = actionbookSchema.nodes;
|
|
2852
3000
|
var { bold: boldMark, italic: italicMark, underline: underlineMark, strikethrough: strikethroughMark, code: codeMark } = actionbookSchema.marks;
|
|
@@ -2893,7 +3041,38 @@ var backspaceAfterLeafBlock = (state, dispatch) => {
|
|
|
2893
3041
|
}
|
|
2894
3042
|
return true;
|
|
2895
3043
|
};
|
|
3044
|
+
var backspaceDeleteEmptyBlock = (state, dispatch) => {
|
|
3045
|
+
const { $from } = state.selection;
|
|
3046
|
+
if (!state.selection.empty || $from.parentOffset !== 0) return false;
|
|
3047
|
+
if ($from.parent.type !== paragraph || $from.parent.content.size !== 0) return false;
|
|
3048
|
+
const deletableTypes = /* @__PURE__ */ new Set(["jinjaIfBlock", "jinjaIfBranch", "noteBlock", "blockquote"]);
|
|
3049
|
+
for (let d = $from.depth - 1; d > 0; d--) {
|
|
3050
|
+
const ancestor = $from.node(d);
|
|
3051
|
+
if (!deletableTypes.has(ancestor.type.name)) continue;
|
|
3052
|
+
if (ancestor.type.name === "jinjaIfBranch" && ancestor.childCount === 1 && ancestor.child(0).content.size === 0) {
|
|
3053
|
+
for (let dd = d - 1; dd > 0; dd--) {
|
|
3054
|
+
if ($from.node(dd).type.name === "jinjaIfBlock") {
|
|
3055
|
+
d = dd;
|
|
3056
|
+
break;
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
const blockNode = $from.node(d);
|
|
3061
|
+
const blockText = blockNode.textContent.trim();
|
|
3062
|
+
if (blockText.length > 0) return false;
|
|
3063
|
+
if (dispatch) {
|
|
3064
|
+
const blockStart = $from.before(d);
|
|
3065
|
+
const blockEnd = $from.after(d);
|
|
3066
|
+
const tr = state.tr.replaceWith(blockStart, blockEnd, paragraph.create());
|
|
3067
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(blockStart)));
|
|
3068
|
+
dispatch(tr.scrollIntoView());
|
|
3069
|
+
}
|
|
3070
|
+
return true;
|
|
3071
|
+
}
|
|
3072
|
+
return false;
|
|
3073
|
+
};
|
|
2896
3074
|
var backspaceCommand = chainCommands(
|
|
3075
|
+
backspaceDeleteEmptyBlock,
|
|
2897
3076
|
backspaceAfterList,
|
|
2898
3077
|
backspaceAfterLeafBlock,
|
|
2899
3078
|
(state, dispatch) => {
|
|
@@ -2911,8 +3090,9 @@ var backspaceCommand = chainCommands(
|
|
|
2911
3090
|
);
|
|
2912
3091
|
var tabCommand = (state, dispatch) => {
|
|
2913
3092
|
const { $from } = state.selection;
|
|
2914
|
-
if (cursorDirectlyInListItem(state)
|
|
3093
|
+
if (cursorDirectlyInListItem(state)) {
|
|
2915
3094
|
if (sinkListItem(listItem)(state, dispatch)) return true;
|
|
3095
|
+
return true;
|
|
2916
3096
|
}
|
|
2917
3097
|
if (dispatch) dispatch(state.tr.insertText(TAB_CHAR));
|
|
2918
3098
|
return true;
|
|
@@ -2929,7 +3109,68 @@ var shiftTabCommand = (state, dispatch) => {
|
|
|
2929
3109
|
}
|
|
2930
3110
|
return true;
|
|
2931
3111
|
};
|
|
3112
|
+
var blockExitEnterCount = 0;
|
|
3113
|
+
var blockExitLastTime = 0;
|
|
3114
|
+
var BLOCK_EXIT_TYPES = /* @__PURE__ */ new Set(["blockquote", "jinjaIfBranch"]);
|
|
3115
|
+
var exitBlockOnDoubleEnter = (state, dispatch) => {
|
|
3116
|
+
const { $from } = state.selection;
|
|
3117
|
+
let blockDepth = -1;
|
|
3118
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
3119
|
+
if (BLOCK_EXIT_TYPES.has($from.node(d).type.name)) {
|
|
3120
|
+
blockDepth = d;
|
|
3121
|
+
break;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
if (blockDepth < 0) {
|
|
3125
|
+
blockExitEnterCount = 0;
|
|
3126
|
+
return false;
|
|
3127
|
+
}
|
|
3128
|
+
if ($from.parent.type.name !== "paragraph" || $from.parent.content.size !== 0) {
|
|
3129
|
+
blockExitEnterCount = 0;
|
|
3130
|
+
return false;
|
|
3131
|
+
}
|
|
3132
|
+
const now = Date.now();
|
|
3133
|
+
if (now - blockExitLastTime > 2e3) blockExitEnterCount = 0;
|
|
3134
|
+
blockExitLastTime = now;
|
|
3135
|
+
blockExitEnterCount++;
|
|
3136
|
+
if (blockExitEnterCount < 2) return false;
|
|
3137
|
+
blockExitEnterCount = 0;
|
|
3138
|
+
if (!dispatch) return true;
|
|
3139
|
+
const paraStart = $from.before($from.depth);
|
|
3140
|
+
const paraEnd = $from.after($from.depth);
|
|
3141
|
+
const tr = state.tr.delete(paraStart, paraEnd);
|
|
3142
|
+
const mapped = tr.mapping.map($from.before($from.depth));
|
|
3143
|
+
const $m = tr.doc.resolve(Math.min(mapped, tr.doc.content.size));
|
|
3144
|
+
for (let d = $m.depth; d > 0; d--) {
|
|
3145
|
+
if (BLOCK_EXIT_TYPES.has($m.node(d).type.name)) {
|
|
3146
|
+
const last = $m.node(d).lastChild;
|
|
3147
|
+
if (last?.type.name === "paragraph" && last.content.size === 0) {
|
|
3148
|
+
const lastPos = $m.end(d) - last.nodeSize;
|
|
3149
|
+
tr.delete(lastPos, lastPos + last.nodeSize);
|
|
3150
|
+
}
|
|
3151
|
+
break;
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
let exitDepth = blockDepth;
|
|
3155
|
+
const blockTypeName = $from.node(blockDepth).type.name;
|
|
3156
|
+
if (blockTypeName === "jinjaIfBranch") {
|
|
3157
|
+
for (let d = blockDepth - 1; d > 0; d--) {
|
|
3158
|
+
if ($from.node(d).type.name === "jinjaIfBlock") {
|
|
3159
|
+
exitDepth = d;
|
|
3160
|
+
break;
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
const blockEnd = tr.mapping.map($from.after(exitDepth));
|
|
3165
|
+
const newPara = paragraph.create();
|
|
3166
|
+
tr.insert(blockEnd, newPara);
|
|
3167
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(blockEnd + 1)));
|
|
3168
|
+
dispatch(tr.scrollIntoView());
|
|
3169
|
+
return true;
|
|
3170
|
+
};
|
|
2932
3171
|
var enterCommand = chainCommands(
|
|
3172
|
+
exitNoteBlockOnEnter,
|
|
3173
|
+
exitBlockOnDoubleEnter,
|
|
2933
3174
|
newlineInCode,
|
|
2934
3175
|
// Split list item on Enter; lift empty list item out of list
|
|
2935
3176
|
splitListItem(listItem),
|
|
@@ -4705,6 +4946,17 @@ function analyzeJinjaBlocks(doc2) {
|
|
|
4705
4946
|
|
|
4706
4947
|
// src/tree/documentTree.ts
|
|
4707
4948
|
var MAX_DEPTH6 = 128;
|
|
4949
|
+
var END_ACTION_RESOURCE_IDS = /* @__PURE__ */ new Set([
|
|
4950
|
+
"close-happy-tiger"
|
|
4951
|
+
// PredefinedToolKey.CloseConversation
|
|
4952
|
+
]);
|
|
4953
|
+
var END_ACTION_TEXTS = /* @__PURE__ */ new Set([
|
|
4954
|
+
"end conversation",
|
|
4955
|
+
"end_conversation"
|
|
4956
|
+
]);
|
|
4957
|
+
function isEndActionTag(tagType, resourceId, text2) {
|
|
4958
|
+
return tagType === "handoff" || END_ACTION_RESOURCE_IDS.has(resourceId) || END_ACTION_TEXTS.has(text2.toLowerCase());
|
|
4959
|
+
}
|
|
4708
4960
|
function extractInlineItems(content, blockIndex) {
|
|
4709
4961
|
const items = [];
|
|
4710
4962
|
for (const node of content) {
|
|
@@ -4716,10 +4968,10 @@ function extractInlineItems(content, blockIndex) {
|
|
|
4716
4968
|
children: []
|
|
4717
4969
|
});
|
|
4718
4970
|
} else if (node.type === "resourceTag") {
|
|
4719
|
-
const
|
|
4971
|
+
const endAction = isEndActionTag(node.tagType, node.resourceId, node.text);
|
|
4720
4972
|
items.push({
|
|
4721
|
-
type:
|
|
4722
|
-
label:
|
|
4973
|
+
type: endAction ? "endAction" : "resourceTag",
|
|
4974
|
+
label: endAction ? `End ${node.text}` : node.text,
|
|
4723
4975
|
blockIndex,
|
|
4724
4976
|
children: [],
|
|
4725
4977
|
meta: { tagType: node.tagType, resourceId: node.resourceId }
|
|
@@ -4753,14 +5005,15 @@ function extractBlockItems(blocks, startIndex, depth) {
|
|
|
4753
5005
|
break;
|
|
4754
5006
|
}
|
|
4755
5007
|
case "jinjaIfBlock": {
|
|
4756
|
-
const branches = block.branches.map((branch) => {
|
|
5008
|
+
const branches = block.branches.map((branch, branchIdx) => {
|
|
4757
5009
|
const branchLabel = branch.branchType === "else" ? "ELSE" : `${branch.branchType.toUpperCase()} ${branch.condition || ""}`.trim();
|
|
4758
5010
|
const branchChildren = extractBlockItems(branch.content, blockIndex, depth + 1);
|
|
4759
5011
|
return {
|
|
4760
5012
|
type: "jinjaBranch",
|
|
4761
5013
|
label: branchLabel,
|
|
4762
5014
|
blockIndex,
|
|
4763
|
-
children: branchChildren
|
|
5015
|
+
children: branchChildren,
|
|
5016
|
+
meta: { branchIndex: branchIdx }
|
|
4764
5017
|
};
|
|
4765
5018
|
});
|
|
4766
5019
|
items.push({
|
|
@@ -4808,11 +5061,12 @@ function buildDocumentTree(doc2) {
|
|
|
4808
5061
|
const hasStructuredJinja = items.some((n) => n.type === "jinjaIf");
|
|
4809
5062
|
if (!hasStructuredJinja) {
|
|
4810
5063
|
for (const s of structures) {
|
|
4811
|
-
const branches = s.branches.map((b) => ({
|
|
5064
|
+
const branches = s.branches.map((b, branchIdx) => ({
|
|
4812
5065
|
type: "jinjaBranch",
|
|
4813
5066
|
label: b.type === "else" ? "ELSE" : `${b.type.toUpperCase()} ${b.condition || ""}`.trim(),
|
|
4814
5067
|
blockIndex: b.tagBlockIndex,
|
|
4815
|
-
children: []
|
|
5068
|
+
children: [],
|
|
5069
|
+
meta: { branchIndex: branchIdx }
|
|
4816
5070
|
}));
|
|
4817
5071
|
const jinjaNode = {
|
|
4818
5072
|
type: "jinjaIf",
|
|
@@ -4916,6 +5170,7 @@ function textToSlice(text2, view) {
|
|
|
4916
5170
|
return null;
|
|
4917
5171
|
}
|
|
4918
5172
|
}
|
|
5173
|
+
var URL_RE = /^https?:\/\/[^\s]+$/i;
|
|
4919
5174
|
function createPlugin() {
|
|
4920
5175
|
return new Plugin({
|
|
4921
5176
|
key,
|
|
@@ -4930,6 +5185,14 @@ function createPlugin() {
|
|
|
4930
5185
|
return true;
|
|
4931
5186
|
}
|
|
4932
5187
|
}
|
|
5188
|
+
if (text2 && URL_RE.test(text2.trim())) {
|
|
5189
|
+
const url = text2.trim();
|
|
5190
|
+
const linkMark2 = actionbookSchema.marks.link.create({ href: url });
|
|
5191
|
+
const textNode = actionbookSchema.text(url, [linkMark2]);
|
|
5192
|
+
const slice2 = new Slice(Fragment.from(textNode), 0, 0);
|
|
5193
|
+
view.dispatch(view.state.tr.replaceSelection(slice2));
|
|
5194
|
+
return true;
|
|
5195
|
+
}
|
|
4933
5196
|
if (!text2) return false;
|
|
4934
5197
|
const slice = textToSlice(text2, view);
|
|
4935
5198
|
if (!slice) return false;
|
|
@@ -4975,7 +5238,7 @@ function createMarkdownClipboardPlugin() {
|
|
|
4975
5238
|
}
|
|
4976
5239
|
|
|
4977
5240
|
// src/ui/plugin/jumpPointPlugin.ts
|
|
4978
|
-
import { Plugin as Plugin2, PluginKey as PluginKey2, TextSelection as
|
|
5241
|
+
import { Plugin as Plugin2, PluginKey as PluginKey2, TextSelection as TextSelection3 } from "prosemirror-state";
|
|
4979
5242
|
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
4980
5243
|
var adjacentKey = new PluginKey2("jumpPointAdjacent");
|
|
4981
5244
|
var JUMP_POINT_ADJACENT_SPEC = { jumpPointAdjacent: true };
|
|
@@ -5038,6 +5301,9 @@ function createJumpPointEditPlugin() {
|
|
|
5038
5301
|
});
|
|
5039
5302
|
if (!duplicate) {
|
|
5040
5303
|
reconvertTr.replaceWith(safeFrom, safeTo, jumpPointType.create({ id }));
|
|
5304
|
+
const mappedCursor = reconvertTr.mapping.map(cursor);
|
|
5305
|
+
const clampedCursor = Math.min(mappedCursor, reconvertTr.doc.content.size);
|
|
5306
|
+
reconvertTr.setSelection(TextSelection3.near(reconvertTr.doc.resolve(clampedCursor)));
|
|
5041
5307
|
}
|
|
5042
5308
|
}
|
|
5043
5309
|
}
|
|
@@ -5070,7 +5336,7 @@ function explodeOnBackspace(state) {
|
|
|
5070
5336
|
const rawText = `^${id}`;
|
|
5071
5337
|
const tr = state.tr.replaceWith(nodeStart, nodeEnd, state.schema.text(rawText));
|
|
5072
5338
|
const cursorPos = Math.min(nodeStart + rawText.length, tr.doc.content.size);
|
|
5073
|
-
tr.setSelection(
|
|
5339
|
+
tr.setSelection(TextSelection3.near(tr.doc.resolve(cursorPos)));
|
|
5074
5340
|
return tr;
|
|
5075
5341
|
}
|
|
5076
5342
|
function explodeOnArrowLeft(state) {
|
|
@@ -5080,7 +5346,7 @@ function explodeOnArrowLeft(state) {
|
|
|
5080
5346
|
const rawText = `^${id}^`;
|
|
5081
5347
|
const tr = state.tr.replaceWith(nodeStart, nodeEnd, state.schema.text(rawText));
|
|
5082
5348
|
const cursorPos = Math.min(nodeStart + 1 + id.length, tr.doc.content.size);
|
|
5083
|
-
tr.setSelection(
|
|
5349
|
+
tr.setSelection(TextSelection3.near(tr.doc.resolve(cursorPos)));
|
|
5084
5350
|
tr.setMeta(jumpPointEditKey, { from: nodeStart, to: nodeStart + rawText.length });
|
|
5085
5351
|
return tr;
|
|
5086
5352
|
}
|
|
@@ -5129,21 +5395,30 @@ function createJumpPointAdjacentPlugin() {
|
|
|
5129
5395
|
// src/ui/plugin/jumpPointNodeViewPlugin.tsx
|
|
5130
5396
|
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
5131
5397
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
5398
|
+
function IconDiamondAlert({ size = 12, fill = "#D9352C" }) {
|
|
5399
|
+
return /* @__PURE__ */ jsxs3("svg", { width: size, height: size, viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
5400
|
+
/* @__PURE__ */ jsx4(
|
|
5401
|
+
"path",
|
|
5402
|
+
{
|
|
5403
|
+
d: "M5.293 1.293a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1 0 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 0-1.414l4-4Z",
|
|
5404
|
+
fill
|
|
5405
|
+
}
|
|
5406
|
+
),
|
|
5407
|
+
/* @__PURE__ */ jsx4("path", { d: "M6 3.5v3", stroke: "#fff", strokeWidth: "1.2", strokeLinecap: "round" }),
|
|
5408
|
+
/* @__PURE__ */ jsx4("circle", { cx: "6", cy: "8.25", r: "0.625", fill: "#fff" })
|
|
5409
|
+
] });
|
|
5410
|
+
}
|
|
5132
5411
|
var JUMP_POINT_STYLE = {
|
|
5133
5412
|
display: "inline-flex",
|
|
5134
5413
|
alignItems: "center",
|
|
5135
5414
|
backgroundColor: "#FFF2B6",
|
|
5136
5415
|
border: "1px solid #FFC233",
|
|
5137
5416
|
color: "#AA5D04",
|
|
5138
|
-
borderRadius: "2px",
|
|
5139
|
-
padding: "2px",
|
|
5140
|
-
fontSize: "12px",
|
|
5141
|
-
lineHeight: "16px",
|
|
5142
5417
|
userSelect: "none",
|
|
5143
5418
|
cursor: "default",
|
|
5144
|
-
boxSizing: "border-box"
|
|
5145
|
-
height
|
|
5146
|
-
|
|
5419
|
+
boxSizing: "border-box"
|
|
5420
|
+
// height, padding, borderRadius, fontSize, lineHeight, overflow
|
|
5421
|
+
// are set via CSS class .ab-jump-point for heading-level overrides
|
|
5147
5422
|
};
|
|
5148
5423
|
var JUMP_POINT_ADJACENT_STYLE = {
|
|
5149
5424
|
...JUMP_POINT_STYLE,
|
|
@@ -5157,8 +5432,8 @@ var JUMP_POINT_DUPLICATE_STYLE = {
|
|
|
5157
5432
|
color: "#9D091E"
|
|
5158
5433
|
};
|
|
5159
5434
|
var LABEL_STYLE = {
|
|
5160
|
-
padding: "0 4px",
|
|
5161
5435
|
whiteSpace: "nowrap"
|
|
5436
|
+
// padding is set via CSS .ab-jp-label for heading-level overrides
|
|
5162
5437
|
};
|
|
5163
5438
|
var CLOSE_BTN_STYLE = {
|
|
5164
5439
|
display: "inline-flex",
|
|
@@ -5189,7 +5464,7 @@ var TOOLTIP_STYLE = {
|
|
|
5189
5464
|
fontSize: "14px",
|
|
5190
5465
|
lineHeight: "20px",
|
|
5191
5466
|
color: "#0D0D0D",
|
|
5192
|
-
|
|
5467
|
+
maxWidth: "240px",
|
|
5193
5468
|
zIndex: 100,
|
|
5194
5469
|
pointerEvents: "none"
|
|
5195
5470
|
};
|
|
@@ -5209,13 +5484,14 @@ function JumpPointNodeViewComponent({ node, view, getPos, decorations }) {
|
|
|
5209
5484
|
return /* @__PURE__ */ jsxs3(
|
|
5210
5485
|
"span",
|
|
5211
5486
|
{
|
|
5487
|
+
className: "ab-jump-point ab-jump-point-duplicate",
|
|
5212
5488
|
style: { ...JUMP_POINT_DUPLICATE_STYLE, position: "relative" },
|
|
5213
5489
|
id: `jp-${id}`,
|
|
5214
5490
|
onMouseEnter: () => setShowTooltip(true),
|
|
5215
5491
|
onMouseLeave: () => setShowTooltip(false),
|
|
5216
5492
|
children: [
|
|
5217
|
-
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#9D091E", style: { paddingLeft: "2px", flexShrink: 0 } }),
|
|
5218
|
-
/* @__PURE__ */ jsx4("span", { style: LABEL_STYLE, children: id }),
|
|
5493
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-icon", children: /* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#9D091E", style: { paddingLeft: "2px", flexShrink: 0 } }) }),
|
|
5494
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-label", style: LABEL_STYLE, children: id }),
|
|
5219
5495
|
/* @__PURE__ */ jsx4(
|
|
5220
5496
|
"button",
|
|
5221
5497
|
{
|
|
@@ -5225,8 +5501,8 @@ function JumpPointNodeViewComponent({ node, view, getPos, decorations }) {
|
|
|
5225
5501
|
e.stopPropagation();
|
|
5226
5502
|
handleDelete2();
|
|
5227
5503
|
},
|
|
5228
|
-
title: "Remove anchor",
|
|
5229
|
-
children: "
|
|
5504
|
+
title: "Remove duplicate anchor",
|
|
5505
|
+
children: /* @__PURE__ */ jsx4(IconDiamondAlert, { size: 12, fill: "#D9352C" })
|
|
5230
5506
|
}
|
|
5231
5507
|
),
|
|
5232
5508
|
showTooltip && /* @__PURE__ */ jsxs3("span", { style: TOOLTIP_STYLE, children: [
|
|
@@ -5239,14 +5515,14 @@ function JumpPointNodeViewComponent({ node, view, getPos, decorations }) {
|
|
|
5239
5515
|
);
|
|
5240
5516
|
}
|
|
5241
5517
|
if (isAdjacent) {
|
|
5242
|
-
return /* @__PURE__ */ jsxs3("span", { style: JUMP_POINT_ADJACENT_STYLE, id: `jp-${id}`, children: [
|
|
5243
|
-
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }),
|
|
5244
|
-
/* @__PURE__ */ jsx4("span", { style: LABEL_STYLE, children: `^${id}^` })
|
|
5518
|
+
return /* @__PURE__ */ jsxs3("span", { className: "ab-jump-point ab-jump-point-adjacent", style: JUMP_POINT_ADJACENT_STYLE, id: `jp-${id}`, children: [
|
|
5519
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-icon", children: /* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }) }),
|
|
5520
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-label", style: LABEL_STYLE, children: `^${id}^` })
|
|
5245
5521
|
] });
|
|
5246
5522
|
}
|
|
5247
|
-
return /* @__PURE__ */ jsxs3("span", { style: JUMP_POINT_STYLE, id: `jp-${id}`, children: [
|
|
5248
|
-
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }),
|
|
5249
|
-
/* @__PURE__ */ jsx4("span", { style: LABEL_STYLE, children: id })
|
|
5523
|
+
return /* @__PURE__ */ jsxs3("span", { className: "ab-jump-point", style: JUMP_POINT_STYLE, id: `jp-${id}`, children: [
|
|
5524
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-icon", children: /* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }) }),
|
|
5525
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-label", style: LABEL_STYLE, children: id })
|
|
5250
5526
|
] });
|
|
5251
5527
|
}
|
|
5252
5528
|
function createJumpPointNodeViewPlugin() {
|
|
@@ -5544,6 +5820,7 @@ function createJinjaDecorationPlugin() {
|
|
|
5544
5820
|
// src/ui/plugin/jinjaIfBlockPlugin.tsx
|
|
5545
5821
|
import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
5546
5822
|
import { createRoot as createRoot2 } from "react-dom/client";
|
|
5823
|
+
import { TextSelection as TextSelection4 } from "prosemirror-state";
|
|
5547
5824
|
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
5548
5825
|
var PLACEHOLDER_TEXT = "Describe what AI agent should do when this condition is met";
|
|
5549
5826
|
var CONDITION_PLACEHOLDER = "Write a condition in natural language";
|
|
@@ -5950,7 +6227,12 @@ function insertNewBranch(view, nodePos, branchType, condition = "") {
|
|
|
5950
6227
|
const newBranch = createBranchNode(view.state.schema, branchType, condition);
|
|
5951
6228
|
if (!newBranch) return false;
|
|
5952
6229
|
const insertPos = context.branchPos + context.branchNode.nodeSize;
|
|
5953
|
-
view.
|
|
6230
|
+
const tr = view.state.tr.insert(insertPos, newBranch);
|
|
6231
|
+
const cursorPos = insertPos + 2;
|
|
6232
|
+
if (cursorPos <= tr.doc.content.size) {
|
|
6233
|
+
tr.setSelection(TextSelection4.near(tr.doc.resolve(cursorPos)));
|
|
6234
|
+
}
|
|
6235
|
+
view.dispatch(tr.scrollIntoView());
|
|
5954
6236
|
view.focus();
|
|
5955
6237
|
return true;
|
|
5956
6238
|
}
|
|
@@ -5997,6 +6279,7 @@ function ConditionDisplay({
|
|
|
5997
6279
|
const [isEditing, setIsEditing] = useState3(false);
|
|
5998
6280
|
const [draftValue, setDraftValue] = useState3(condition);
|
|
5999
6281
|
const inputRef = useRef2(null);
|
|
6282
|
+
const autoFocusedRef = useRef2(false);
|
|
6000
6283
|
useEffect2(() => {
|
|
6001
6284
|
if (!isEditing) {
|
|
6002
6285
|
setDraftValue(condition);
|
|
@@ -6008,6 +6291,12 @@ function ConditionDisplay({
|
|
|
6008
6291
|
inputRef.current?.select();
|
|
6009
6292
|
}
|
|
6010
6293
|
}, [isEditing]);
|
|
6294
|
+
useEffect2(() => {
|
|
6295
|
+
if (editable && !condition && !autoFocusedRef.current) {
|
|
6296
|
+
autoFocusedRef.current = true;
|
|
6297
|
+
setIsEditing(true);
|
|
6298
|
+
}
|
|
6299
|
+
}, []);
|
|
6011
6300
|
if (branchType === "else") {
|
|
6012
6301
|
return /* @__PURE__ */ jsx6("span", { className: "jinja-otherwise", children: "Otherwise" });
|
|
6013
6302
|
}
|
|
@@ -6303,15 +6592,25 @@ var JinjaIfBranchView = class {
|
|
|
6303
6592
|
}
|
|
6304
6593
|
render() {
|
|
6305
6594
|
const nodePos = this.getPos();
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6595
|
+
let context = null;
|
|
6596
|
+
let lastBranch = null;
|
|
6597
|
+
if (nodePos != null) {
|
|
6598
|
+
context = getBranchContext(this.view, nodePos);
|
|
6599
|
+
lastBranch = getLastBranchOfBlock(this.view, nodePos);
|
|
6600
|
+
let branchIdx = context?.branchIndex ?? -1;
|
|
6601
|
+
if (branchIdx < 0 && this.dom.parentElement) {
|
|
6602
|
+
const siblings = this.dom.parentElement.querySelectorAll(":scope > [data-jinja-branch]");
|
|
6603
|
+
branchIdx = Array.prototype.indexOf.call(siblings, this.dom);
|
|
6604
|
+
}
|
|
6605
|
+
if (branchIdx >= 0) {
|
|
6606
|
+
this.dom.setAttribute("data-branch-index", String(branchIdx));
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6310
6609
|
const branchType = this.node.attrs.branchType;
|
|
6311
6610
|
const condition = String(this.node.attrs.condition ?? "");
|
|
6312
|
-
const isLast = lastBranch.index === context.branchIndex;
|
|
6313
|
-
const lastNonElseIdx = getLastNonElseBranchIndex(this.view, nodePos);
|
|
6314
|
-
const showAddButton = context.branchIndex === lastNonElseIdx;
|
|
6611
|
+
const isLast = context && lastBranch ? lastBranch.index === context.branchIndex : true;
|
|
6612
|
+
const lastNonElseIdx = context ? getLastNonElseBranchIndex(this.view, nodePos) : 0;
|
|
6613
|
+
const showAddButton = context ? context.branchIndex === lastNonElseIdx : true;
|
|
6315
6614
|
this.dom.classList.toggle("jinja-branch-last", isLast);
|
|
6316
6615
|
this.root.render(
|
|
6317
6616
|
/* @__PURE__ */ jsx6(
|
|
@@ -6321,16 +6620,19 @@ var JinjaIfBranchView = class {
|
|
|
6321
6620
|
condition,
|
|
6322
6621
|
editable: this.view.editable,
|
|
6323
6622
|
isLastBranch: showAddButton,
|
|
6324
|
-
hasElseBranch: getElseBranch(this.view, nodePos),
|
|
6623
|
+
hasElseBranch: context && nodePos != null ? getElseBranch(this.view, nodePos) : false,
|
|
6325
6624
|
onConditionChange: (value) => {
|
|
6326
6625
|
const currentPos = this.getPos();
|
|
6327
6626
|
if (currentPos == null) return;
|
|
6328
|
-
this.view.
|
|
6329
|
-
this.
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
)
|
|
6627
|
+
const tr = this.view.state.tr.setNodeMarkup(currentPos, void 0, {
|
|
6628
|
+
...this.node.attrs,
|
|
6629
|
+
condition: value
|
|
6630
|
+
});
|
|
6631
|
+
const contentPos = currentPos + 2;
|
|
6632
|
+
if (contentPos <= tr.doc.content.size) {
|
|
6633
|
+
tr.setSelection(TextSelection4.near(tr.doc.resolve(contentPos)));
|
|
6634
|
+
}
|
|
6635
|
+
this.view.dispatch(tr.scrollIntoView());
|
|
6334
6636
|
this.view.focus();
|
|
6335
6637
|
},
|
|
6336
6638
|
onDelete: () => {
|
|
@@ -6381,9 +6683,9 @@ function createJinjaIfBlockPlugin() {
|
|
|
6381
6683
|
|
|
6382
6684
|
// src/ui/plugin/linkPlugin.ts
|
|
6383
6685
|
import { InputRule as InputRule2, inputRules as inputRules2 } from "prosemirror-inputrules";
|
|
6384
|
-
import { Plugin as Plugin5, PluginKey as PluginKey5, TextSelection as
|
|
6385
|
-
var LINK_INPUT_RE =
|
|
6386
|
-
var LINK_FULL_RE =
|
|
6686
|
+
import { Plugin as Plugin5, PluginKey as PluginKey5, TextSelection as TextSelection5 } from "prosemirror-state";
|
|
6687
|
+
var LINK_INPUT_RE = /\\?\[([^\]]*?)\\?\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
|
|
6688
|
+
var LINK_FULL_RE = /^\\?\[([^\]]*?)\\?\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
|
|
6387
6689
|
var linkEditKey = new PluginKey5("linkEdit");
|
|
6388
6690
|
function getMarkRange($pos, type) {
|
|
6389
6691
|
const { parentOffset } = $pos;
|
|
@@ -6427,7 +6729,7 @@ function explodeLinkToRaw(state) {
|
|
|
6427
6729
|
const tr = state.tr;
|
|
6428
6730
|
tr.replaceWith(from, to, schema.text(rawText));
|
|
6429
6731
|
const newPos = Math.min(from + rawCursorOffset, tr.doc.content.size);
|
|
6430
|
-
tr.setSelection(
|
|
6732
|
+
tr.setSelection(TextSelection5.near(tr.doc.resolve(newPos)));
|
|
6431
6733
|
tr.setMeta(linkEditKey, { from, to: from + rawText.length });
|
|
6432
6734
|
return tr;
|
|
6433
6735
|
}
|
|
@@ -6440,8 +6742,8 @@ function createLinkEditPlugin() {
|
|
|
6440
6742
|
const meta = tr.getMeta(linkEditKey);
|
|
6441
6743
|
if (meta !== void 0) return { rawRange: meta };
|
|
6442
6744
|
if (prev.rawRange) {
|
|
6443
|
-
const from = tr.mapping.map(prev.rawRange.from);
|
|
6444
|
-
const to = tr.mapping.map(prev.rawRange.to);
|
|
6745
|
+
const from = tr.mapping.map(prev.rawRange.from, -1);
|
|
6746
|
+
const to = tr.mapping.map(prev.rawRange.to, -1);
|
|
6445
6747
|
if (from >= to) return { rawRange: null };
|
|
6446
6748
|
return { rawRange: { from, to } };
|
|
6447
6749
|
}
|
|
@@ -6452,7 +6754,7 @@ function createLinkEditPlugin() {
|
|
|
6452
6754
|
const pluginState = linkEditKey.getState(newState);
|
|
6453
6755
|
if (!pluginState?.rawRange) return null;
|
|
6454
6756
|
const { from, to } = pluginState.rawRange;
|
|
6455
|
-
if (newState.selection.anchor >= from && newState.selection.anchor
|
|
6757
|
+
if (newState.selection.anchor >= from && newState.selection.anchor < to) {
|
|
6456
6758
|
return null;
|
|
6457
6759
|
}
|
|
6458
6760
|
const docSize = newState.doc.content.size;
|
|
@@ -6596,12 +6898,13 @@ var STYLES = (
|
|
|
6596
6898
|
cursor: grab;
|
|
6597
6899
|
color: transparent;
|
|
6598
6900
|
border-radius: var(--ab-dh-handle-radius);
|
|
6599
|
-
transition:
|
|
6901
|
+
transition: none;
|
|
6600
6902
|
user-select: none;
|
|
6601
6903
|
pointer-events: auto;
|
|
6602
6904
|
touch-action: none;
|
|
6603
6905
|
opacity: 0;
|
|
6604
6906
|
pointer-events: none;
|
|
6907
|
+
overflow: visible;
|
|
6605
6908
|
}
|
|
6606
6909
|
.ab-drag-handle.ab-dh-active {
|
|
6607
6910
|
opacity: 1;
|
|
@@ -6612,6 +6915,72 @@ var STYLES = (
|
|
|
6612
6915
|
color: var(--ab-dh-color-visible) !important;
|
|
6613
6916
|
background: var(--ab-dh-bg-hover);
|
|
6614
6917
|
}
|
|
6918
|
+
.ab-drag-handle:hover::after {
|
|
6919
|
+
content: 'Drag to move';
|
|
6920
|
+
position: absolute;
|
|
6921
|
+
bottom: calc(100% + 4px);
|
|
6922
|
+
left: 0;
|
|
6923
|
+
background: #2e2e2e;
|
|
6924
|
+
color: #fff;
|
|
6925
|
+
font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
6926
|
+
font-size: 12px;
|
|
6927
|
+
font-weight: 400;
|
|
6928
|
+
line-height: 16px;
|
|
6929
|
+
padding: 4px 8px;
|
|
6930
|
+
border-radius: 4px;
|
|
6931
|
+
white-space: nowrap;
|
|
6932
|
+
pointer-events: none;
|
|
6933
|
+
z-index: 30;
|
|
6934
|
+
}
|
|
6935
|
+
.ab-drag-handle:hover::before {
|
|
6936
|
+
content: '';
|
|
6937
|
+
position: absolute;
|
|
6938
|
+
bottom: calc(100% + 0px);
|
|
6939
|
+
left: 8px;
|
|
6940
|
+
width: 0;
|
|
6941
|
+
height: 0;
|
|
6942
|
+
border-left: 5px solid transparent;
|
|
6943
|
+
border-right: 5px solid transparent;
|
|
6944
|
+
border-top: 5px solid #2e2e2e;
|
|
6945
|
+
pointer-events: none;
|
|
6946
|
+
z-index: 31;
|
|
6947
|
+
}
|
|
6948
|
+
.ab-drag-handle.dragging::after,
|
|
6949
|
+
.ab-drag-handle.dragging::before {
|
|
6950
|
+
display: none;
|
|
6951
|
+
}
|
|
6952
|
+
.ab-dh-menu {
|
|
6953
|
+
position: absolute;
|
|
6954
|
+
top: calc(100% + 4px);
|
|
6955
|
+
left: 0;
|
|
6956
|
+
background: #fff;
|
|
6957
|
+
border-radius: 4px;
|
|
6958
|
+
box-shadow: 0px 8px 10px 1px rgba(13,13,13,0.12), 0px 3px 14px 2px rgba(13,13,13,0.08), 0px 3px 5px -3px rgba(13,13,13,0.04);
|
|
6959
|
+
padding: 8px 0;
|
|
6960
|
+
z-index: 40;
|
|
6961
|
+
min-width: 120px;
|
|
6962
|
+
}
|
|
6963
|
+
.ab-dh-menu-item {
|
|
6964
|
+
display: flex;
|
|
6965
|
+
align-items: center;
|
|
6966
|
+
width: 100%;
|
|
6967
|
+
padding: 6px 16px;
|
|
6968
|
+
border: none;
|
|
6969
|
+
background: #fff;
|
|
6970
|
+
cursor: pointer;
|
|
6971
|
+
font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
6972
|
+
font-size: 14px;
|
|
6973
|
+
font-weight: 400;
|
|
6974
|
+
line-height: 20px;
|
|
6975
|
+
letter-spacing: -0.1px;
|
|
6976
|
+
color: #0d0d0d;
|
|
6977
|
+
white-space: nowrap;
|
|
6978
|
+
text-overflow: ellipsis;
|
|
6979
|
+
overflow: hidden;
|
|
6980
|
+
}
|
|
6981
|
+
.ab-dh-menu-item:hover {
|
|
6982
|
+
background: rgba(0,0,0,0.04);
|
|
6983
|
+
}
|
|
6615
6984
|
.ab-drag-handle:active, .ab-drag-handle.dragging {
|
|
6616
6985
|
cursor: grabbing;
|
|
6617
6986
|
color: var(--ab-dh-color-accent) !important;
|
|
@@ -6921,7 +7290,6 @@ var DragHandleController = class {
|
|
|
6921
7290
|
el.setAttribute("role", "button");
|
|
6922
7291
|
el.setAttribute("aria-roledescription", "drag handle");
|
|
6923
7292
|
el.setAttribute("aria-label", `\uBE14\uB85D ${idx + 1} \uC774\uB3D9`);
|
|
6924
|
-
el.setAttribute("title", "Drag to move");
|
|
6925
7293
|
el.setAttribute("tabindex", "-1");
|
|
6926
7294
|
el.innerHTML = GRIP_SVG;
|
|
6927
7295
|
el.style.left = `${handleLeft}px`;
|
|
@@ -6934,18 +7302,85 @@ var DragHandleController = class {
|
|
|
6934
7302
|
this.prevBlocks = newBlocks;
|
|
6935
7303
|
this.updateActiveHandle();
|
|
6936
7304
|
}
|
|
7305
|
+
activeMenu = null;
|
|
7306
|
+
activeMenuCleanup = null;
|
|
7307
|
+
dismissMenu() {
|
|
7308
|
+
if (this.activeMenu) {
|
|
7309
|
+
this.activeMenu.remove();
|
|
7310
|
+
this.activeMenu = null;
|
|
7311
|
+
}
|
|
7312
|
+
if (this.activeMenuCleanup) {
|
|
7313
|
+
this.activeMenuCleanup();
|
|
7314
|
+
this.activeMenuCleanup = null;
|
|
7315
|
+
}
|
|
7316
|
+
}
|
|
7317
|
+
showMenu(el, blockIndex) {
|
|
7318
|
+
this.dismissMenu();
|
|
7319
|
+
const menu = document.createElement("div");
|
|
7320
|
+
menu.className = "ab-dh-menu";
|
|
7321
|
+
const deleteBtn = document.createElement("button");
|
|
7322
|
+
deleteBtn.className = "ab-dh-menu-item";
|
|
7323
|
+
deleteBtn.textContent = "Delete";
|
|
7324
|
+
deleteBtn.addEventListener("mousedown", (e) => {
|
|
7325
|
+
e.preventDefault();
|
|
7326
|
+
e.stopPropagation();
|
|
7327
|
+
this.deleteBlock(blockIndex);
|
|
7328
|
+
this.dismissMenu();
|
|
7329
|
+
});
|
|
7330
|
+
menu.appendChild(deleteBtn);
|
|
7331
|
+
el.appendChild(menu);
|
|
7332
|
+
this.activeMenu = menu;
|
|
7333
|
+
const onOutside = (e) => {
|
|
7334
|
+
if (!menu.contains(e.target)) {
|
|
7335
|
+
this.dismissMenu();
|
|
7336
|
+
}
|
|
7337
|
+
};
|
|
7338
|
+
setTimeout(() => document.addEventListener("mousedown", onOutside, true), 0);
|
|
7339
|
+
this.activeMenuCleanup = () => document.removeEventListener("mousedown", onOutside, true);
|
|
7340
|
+
}
|
|
7341
|
+
deleteBlock(blockIndex) {
|
|
7342
|
+
const blocks = this.collectBlocks();
|
|
7343
|
+
if (blockIndex >= blocks.length) return;
|
|
7344
|
+
const block = blocks[blockIndex];
|
|
7345
|
+
const from = block.offset;
|
|
7346
|
+
const to = block.offset + block.nodeSize;
|
|
7347
|
+
const tr = this.view.state.tr;
|
|
7348
|
+
tr.replaceWith(from, to, this.view.state.schema.nodes.paragraph.create());
|
|
7349
|
+
this.view.dispatch(tr);
|
|
7350
|
+
this.view.focus();
|
|
7351
|
+
}
|
|
6937
7352
|
bindHandleEvents(el, index) {
|
|
6938
7353
|
let currentIndex = index;
|
|
7354
|
+
let downX = 0;
|
|
7355
|
+
let downY = 0;
|
|
7356
|
+
let didDrag = false;
|
|
7357
|
+
let menuWasOpen = false;
|
|
6939
7358
|
const onPointerDown = (e) => {
|
|
7359
|
+
if (this.activeMenu && this.activeMenu.contains(e.target)) return;
|
|
6940
7360
|
e.preventDefault();
|
|
6941
7361
|
if (!this.view.editable) return;
|
|
7362
|
+
menuWasOpen = !!this.activeMenu;
|
|
7363
|
+
this.dismissMenu();
|
|
7364
|
+
downX = e.clientX;
|
|
7365
|
+
downY = e.clientY;
|
|
7366
|
+
didDrag = false;
|
|
6942
7367
|
el.setPointerCapture(e.pointerId);
|
|
6943
7368
|
this.prevBlocks = this.collectBlocks();
|
|
6944
7369
|
this.syncHandlePositions();
|
|
6945
7370
|
this.startDrag(currentIndex, el, e);
|
|
6946
7371
|
};
|
|
6947
|
-
const onPointerMove = (e) =>
|
|
6948
|
-
|
|
7372
|
+
const onPointerMove = (e) => {
|
|
7373
|
+
if (Math.abs(e.clientX - downX) > 3 || Math.abs(e.clientY - downY) > 3) {
|
|
7374
|
+
didDrag = true;
|
|
7375
|
+
}
|
|
7376
|
+
this.onPointerMove(e);
|
|
7377
|
+
};
|
|
7378
|
+
const onPointerUp = (e) => {
|
|
7379
|
+
this.onPointerUp(e);
|
|
7380
|
+
if (!didDrag && !menuWasOpen) {
|
|
7381
|
+
this.showMenu(el, currentIndex);
|
|
7382
|
+
}
|
|
7383
|
+
};
|
|
6949
7384
|
const onLostCapture = () => this.cancelDrag();
|
|
6950
7385
|
const onPointerCancel = () => this.cancelDrag();
|
|
6951
7386
|
el.addEventListener("pointerdown", onPointerDown);
|
|
@@ -7352,150 +7787,89 @@ function createTodoNodeViewPlugin() {
|
|
|
7352
7787
|
};
|
|
7353
7788
|
}
|
|
7354
7789
|
|
|
7355
|
-
// src/ui/plugin/
|
|
7356
|
-
import {
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
"padding: 16px 24px",
|
|
7368
|
-
"background: #fff",
|
|
7369
|
-
"border: 1px dashed #ccc",
|
|
7370
|
-
"border-radius: 4px",
|
|
7371
|
-
"display: flex",
|
|
7372
|
-
"flex-direction: column",
|
|
7373
|
-
"gap: 4px"
|
|
7374
|
-
].join(";");
|
|
7375
|
-
const label = document.createElement("span");
|
|
7376
|
-
label.contentEditable = "false";
|
|
7377
|
-
label.textContent = "Note";
|
|
7378
|
-
label.style.cssText = [
|
|
7379
|
-
"display: inline-flex",
|
|
7380
|
-
"align-items: center",
|
|
7381
|
-
"justify-content: center",
|
|
7382
|
-
"align-self: flex-start",
|
|
7383
|
-
"font-size: 12px",
|
|
7384
|
-
"font-weight: 400",
|
|
7385
|
-
"font-style: normal",
|
|
7386
|
-
"line-height: 16px",
|
|
7387
|
-
"color: #858585",
|
|
7388
|
-
"background: #f7f7f7",
|
|
7389
|
-
"border: 1px solid #e0e0e0",
|
|
7390
|
-
"border-radius: 4px",
|
|
7391
|
-
"padding: 2px 4px",
|
|
7392
|
-
"user-select: none"
|
|
7393
|
-
].join(";");
|
|
7394
|
-
this.dom.appendChild(label);
|
|
7395
|
-
this.contentDOM = document.createElement("div");
|
|
7396
|
-
this.contentDOM.className = "ab-note-block-content";
|
|
7397
|
-
this.contentDOM.style.cssText = [
|
|
7398
|
-
"font-size: 14px",
|
|
7399
|
-
"font-style: italic",
|
|
7400
|
-
"font-weight: 400",
|
|
7401
|
-
"line-height: 20px",
|
|
7402
|
-
"letter-spacing: -0.1px",
|
|
7403
|
-
"color: #858585"
|
|
7404
|
-
].join(";");
|
|
7405
|
-
this.dom.appendChild(this.contentDOM);
|
|
7406
|
-
}
|
|
7407
|
-
};
|
|
7408
|
-
var emptyEnterCount = 0;
|
|
7409
|
-
var lastEnterTime = 0;
|
|
7410
|
-
var exitNoteBlockOnEnter = (state, dispatch) => {
|
|
7411
|
-
const { $from } = state.selection;
|
|
7412
|
-
let noteBlockDepth = -1;
|
|
7413
|
-
for (let d = $from.depth; d > 0; d--) {
|
|
7414
|
-
if ($from.node(d).type.name === "noteBlock") {
|
|
7415
|
-
noteBlockDepth = d;
|
|
7416
|
-
break;
|
|
7417
|
-
}
|
|
7418
|
-
}
|
|
7419
|
-
if (noteBlockDepth < 0) {
|
|
7420
|
-
emptyEnterCount = 0;
|
|
7421
|
-
return false;
|
|
7422
|
-
}
|
|
7423
|
-
const parentNode = $from.parent;
|
|
7424
|
-
if (parentNode.type.name !== "paragraph" || parentNode.content.size !== 0) {
|
|
7425
|
-
emptyEnterCount = 0;
|
|
7426
|
-
return false;
|
|
7427
|
-
}
|
|
7428
|
-
const now = Date.now();
|
|
7429
|
-
if (now - lastEnterTime > 2e3) {
|
|
7430
|
-
emptyEnterCount = 0;
|
|
7431
|
-
}
|
|
7432
|
-
lastEnterTime = now;
|
|
7433
|
-
emptyEnterCount++;
|
|
7434
|
-
if (emptyEnterCount < 2) {
|
|
7435
|
-
return false;
|
|
7790
|
+
// src/ui/plugin/placeholderPlugin.ts
|
|
7791
|
+
import { Plugin as Plugin7, PluginKey as PluginKey7 } from "prosemirror-state";
|
|
7792
|
+
import { Decoration as Decoration4, DecorationSet as DecorationSet4 } from "prosemirror-view";
|
|
7793
|
+
var PLACEHOLDER_TEXT2 = "Type to start writing, or press / to insert an action.";
|
|
7794
|
+
var pluginKey2 = new PluginKey7("placeholder");
|
|
7795
|
+
function buildDecorations4(state) {
|
|
7796
|
+
const { doc: doc2, selection } = state;
|
|
7797
|
+
if (!selection.empty) return DecorationSet4.empty;
|
|
7798
|
+
const $from = selection.$from;
|
|
7799
|
+
const parent = $from.parent;
|
|
7800
|
+
if (parent.type.name !== "paragraph" || parent.content.size !== 0) {
|
|
7801
|
+
return DecorationSet4.empty;
|
|
7436
7802
|
}
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
const tr = state.tr.delete(paragraphStart, paragraphEnd);
|
|
7442
|
-
const mappedFrom = tr.mapping.map($from.before($from.depth));
|
|
7443
|
-
const $mapped = tr.doc.resolve(Math.min(mappedFrom, tr.doc.content.size));
|
|
7444
|
-
for (let d = $mapped.depth; d > 0; d--) {
|
|
7445
|
-
if ($mapped.node(d).type.name === "noteBlock") {
|
|
7446
|
-
const lastChild = $mapped.node(d).lastChild;
|
|
7447
|
-
if (lastChild && lastChild.type.name === "paragraph" && lastChild.content.size === 0) {
|
|
7448
|
-
const lastChildPos = $mapped.end(d) - lastChild.nodeSize;
|
|
7449
|
-
tr.delete(lastChildPos, lastChildPos + lastChild.nodeSize);
|
|
7450
|
-
}
|
|
7451
|
-
break;
|
|
7803
|
+
const EXCLUDED_ANCESTORS = /* @__PURE__ */ new Set(["noteBlock", "blockquote", "jinjaIfBranch"]);
|
|
7804
|
+
for (let d = $from.depth - 1; d > 0; d--) {
|
|
7805
|
+
if (EXCLUDED_ANCESTORS.has($from.node(d).type.name)) {
|
|
7806
|
+
return DecorationSet4.empty;
|
|
7452
7807
|
}
|
|
7453
7808
|
}
|
|
7454
|
-
const
|
|
7455
|
-
const
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
return
|
|
7460
|
-
}
|
|
7461
|
-
function
|
|
7809
|
+
const pos = $from.before($from.depth);
|
|
7810
|
+
const deco = Decoration4.node(pos, pos + parent.nodeSize, {
|
|
7811
|
+
class: "ab-empty-paragraph",
|
|
7812
|
+
"data-placeholder": PLACEHOLDER_TEXT2
|
|
7813
|
+
});
|
|
7814
|
+
return DecorationSet4.create(doc2, [deco]);
|
|
7815
|
+
}
|
|
7816
|
+
function createPlaceholderPlugin() {
|
|
7462
7817
|
return {
|
|
7463
|
-
name: "
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7818
|
+
name: "placeholder",
|
|
7819
|
+
plugins: () => [
|
|
7820
|
+
new Plugin7({
|
|
7821
|
+
key: pluginKey2,
|
|
7822
|
+
state: {
|
|
7823
|
+
init(_, state) {
|
|
7824
|
+
return buildDecorations4(state);
|
|
7825
|
+
},
|
|
7826
|
+
apply(tr, oldSet, _oldState, newState) {
|
|
7827
|
+
if (tr.docChanged || tr.selectionSet) {
|
|
7828
|
+
return buildDecorations4(newState);
|
|
7829
|
+
}
|
|
7830
|
+
return oldSet;
|
|
7831
|
+
}
|
|
7832
|
+
},
|
|
7833
|
+
props: {
|
|
7834
|
+
decorations(state) {
|
|
7835
|
+
return pluginKey2.getState(state) ?? DecorationSet4.empty;
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7838
|
+
})
|
|
7839
|
+
]
|
|
7470
7840
|
};
|
|
7471
7841
|
}
|
|
7472
7842
|
|
|
7473
7843
|
// src/ui/plugin/slashCommandPlugin.ts
|
|
7474
|
-
import { Plugin as
|
|
7475
|
-
var slashCommandKey = new
|
|
7844
|
+
import { Plugin as Plugin8, PluginKey as PluginKey8 } from "prosemirror-state";
|
|
7845
|
+
var slashCommandKey = new PluginKey8("slashCommand");
|
|
7476
7846
|
var TRIGGER_RE = /(?:^|\s)(\/[^\s]*)$/;
|
|
7477
7847
|
function deriveState(state, dismissedFrom) {
|
|
7848
|
+
const inactive = { active: false, range: null, query: "", parentType: "" };
|
|
7478
7849
|
const { selection } = state;
|
|
7479
|
-
if (!selection.empty) return
|
|
7850
|
+
if (!selection.empty) return inactive;
|
|
7480
7851
|
const { $from } = selection;
|
|
7481
7852
|
const parentType = $from.parent.type.name;
|
|
7482
|
-
|
|
7853
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
7854
|
+
if ($from.node(d).type.name === "noteBlock") return inactive;
|
|
7855
|
+
}
|
|
7483
7856
|
const textBefore = $from.parent.textBetween(0, $from.parentOffset, "\n", "\0");
|
|
7484
7857
|
const match = TRIGGER_RE.exec(textBefore);
|
|
7485
|
-
if (!match) return
|
|
7858
|
+
if (!match) return inactive;
|
|
7486
7859
|
const slashText = match[1];
|
|
7487
7860
|
const slashStartInParent = textBefore.lastIndexOf(slashText);
|
|
7488
7861
|
const from = $from.start() + slashStartInParent;
|
|
7489
7862
|
const to = $from.pos;
|
|
7490
|
-
if (dismissedFrom === from) return
|
|
7863
|
+
if (dismissedFrom === from) return inactive;
|
|
7491
7864
|
return {
|
|
7492
7865
|
active: true,
|
|
7493
7866
|
range: { from, to },
|
|
7494
|
-
query: slashText.slice(1)
|
|
7867
|
+
query: slashText.slice(1),
|
|
7868
|
+
parentType
|
|
7495
7869
|
};
|
|
7496
7870
|
}
|
|
7497
7871
|
function createSlashCommandPlugin() {
|
|
7498
|
-
const plugin = new
|
|
7872
|
+
const plugin = new Plugin8({
|
|
7499
7873
|
key: slashCommandKey,
|
|
7500
7874
|
state: {
|
|
7501
7875
|
init(_, state) {
|
|
@@ -8013,6 +8387,7 @@ function DocumentTreeView({ doc: doc2, className, onNavigate }) {
|
|
|
8013
8387
|
// src/ui/components/FloatingMenu.tsx
|
|
8014
8388
|
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
|
|
8015
8389
|
import { createPortal as createPortal2 } from "react-dom";
|
|
8390
|
+
import { TextSelection as TextSelection6 } from "prosemirror-state";
|
|
8016
8391
|
import { setBlockType as setBlockType2, toggleMark as toggleMark2, wrapIn } from "prosemirror-commands";
|
|
8017
8392
|
import { wrapInList as wrapInList2 } from "prosemirror-schema-list";
|
|
8018
8393
|
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
@@ -8035,6 +8410,56 @@ function hasMark(state, type) {
|
|
|
8035
8410
|
if (empty) return false;
|
|
8036
8411
|
return state.doc.rangeHasMark(from, to, type);
|
|
8037
8412
|
}
|
|
8413
|
+
function getMarkRange2($pos, type) {
|
|
8414
|
+
const { parentOffset } = $pos;
|
|
8415
|
+
let child = $pos.parent.childAfter(parentOffset);
|
|
8416
|
+
if (parentOffset === child.offset && child.offset !== 0) {
|
|
8417
|
+
child = $pos.parent.childBefore(parentOffset);
|
|
8418
|
+
}
|
|
8419
|
+
if (!child.node) return null;
|
|
8420
|
+
const mark = child.node.marks.find((candidate) => candidate.type === type);
|
|
8421
|
+
if (!mark) return null;
|
|
8422
|
+
const parentStart = $pos.start();
|
|
8423
|
+
let { index: startIndex } = child;
|
|
8424
|
+
let startPos = parentStart + child.offset;
|
|
8425
|
+
let endIndex = startIndex + 1;
|
|
8426
|
+
let endPos = startPos + child.node.nodeSize;
|
|
8427
|
+
while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
|
|
8428
|
+
startIndex -= 1;
|
|
8429
|
+
startPos -= $pos.parent.child(startIndex).nodeSize;
|
|
8430
|
+
}
|
|
8431
|
+
while (endIndex < $pos.parent.childCount && mark.isInSet($pos.parent.child(endIndex).marks)) {
|
|
8432
|
+
endPos += $pos.parent.child(endIndex).nodeSize;
|
|
8433
|
+
endIndex += 1;
|
|
8434
|
+
}
|
|
8435
|
+
return { from: startPos, to: endPos, mark };
|
|
8436
|
+
}
|
|
8437
|
+
function getLinkAtCursor(state) {
|
|
8438
|
+
const { selection, doc: doc2 } = state;
|
|
8439
|
+
if (!selection.empty) return null;
|
|
8440
|
+
const range = getMarkRange2(doc2.resolve(selection.from), linkMark);
|
|
8441
|
+
if (!range) return null;
|
|
8442
|
+
return {
|
|
8443
|
+
href: range.mark.attrs.href || "",
|
|
8444
|
+
text: doc2.textBetween(range.from, range.to),
|
|
8445
|
+
from: range.from,
|
|
8446
|
+
to: range.to
|
|
8447
|
+
};
|
|
8448
|
+
}
|
|
8449
|
+
function normalizeLinkHref(href) {
|
|
8450
|
+
const trimmedHref = href.trim();
|
|
8451
|
+
if (!trimmedHref) return "";
|
|
8452
|
+
return trimmedHref.startsWith("#") || trimmedHref.startsWith("/") || /^https?:\/\//i.test(trimmedHref) ? trimmedHref : `https://${trimmedHref}`;
|
|
8453
|
+
}
|
|
8454
|
+
function getNonLinkMarksInRange(state, from, to) {
|
|
8455
|
+
let marks = [];
|
|
8456
|
+
state.doc.nodesBetween(from, to, (node) => {
|
|
8457
|
+
if (!node.isText) return;
|
|
8458
|
+
marks = node.marks.filter((mark) => mark.type !== linkMark);
|
|
8459
|
+
return false;
|
|
8460
|
+
});
|
|
8461
|
+
return marks;
|
|
8462
|
+
}
|
|
8038
8463
|
function activeHeadingLevel(state) {
|
|
8039
8464
|
const { $from } = state.selection;
|
|
8040
8465
|
const node = $from.parent;
|
|
@@ -8497,6 +8922,408 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
8497
8922
|
}
|
|
8498
8923
|
);
|
|
8499
8924
|
}
|
|
8925
|
+
function LinkHoverTooltip({ view, link: link2, onEdit }) {
|
|
8926
|
+
const [hover, setHover] = useState7(false);
|
|
8927
|
+
const startCoords = view.coordsAtPos(link2.from);
|
|
8928
|
+
const endCoords = view.coordsAtPos(link2.to);
|
|
8929
|
+
const anchorTop = Math.min(startCoords.top, endCoords.top);
|
|
8930
|
+
const linkLeft = Math.min(startCoords.left, endCoords.left);
|
|
8931
|
+
const linkRight = Math.max(startCoords.right, endCoords.right);
|
|
8932
|
+
const tooltipHalfW = Math.min(174, Math.max(0, (window.innerWidth - VPORT_MARGIN2 * 2) / 2));
|
|
8933
|
+
const safeCenterX = Math.max(
|
|
8934
|
+
VPORT_MARGIN2 + tooltipHalfW,
|
|
8935
|
+
Math.min((linkLeft + linkRight) / 2, window.innerWidth - VPORT_MARGIN2 - tooltipHalfW)
|
|
8936
|
+
);
|
|
8937
|
+
return createPortal2(
|
|
8938
|
+
/* @__PURE__ */ jsxs9(
|
|
8939
|
+
"div",
|
|
8940
|
+
{
|
|
8941
|
+
...{ [FLOAT_ATTR]: "" },
|
|
8942
|
+
style: {
|
|
8943
|
+
position: "fixed",
|
|
8944
|
+
left: safeCenterX,
|
|
8945
|
+
top: Math.max(64, anchorTop - 4),
|
|
8946
|
+
transform: "translate(-50%, -100%)",
|
|
8947
|
+
zIndex: 1e3,
|
|
8948
|
+
display: "flex",
|
|
8949
|
+
flexDirection: "column",
|
|
8950
|
+
alignItems: "center",
|
|
8951
|
+
animation: "ab-float-in 0.12s ease",
|
|
8952
|
+
pointerEvents: "auto"
|
|
8953
|
+
},
|
|
8954
|
+
children: [
|
|
8955
|
+
/* @__PURE__ */ jsxs9(
|
|
8956
|
+
"div",
|
|
8957
|
+
{
|
|
8958
|
+
...{ [FLOAT_ATTR]: "" },
|
|
8959
|
+
style: {
|
|
8960
|
+
display: "flex",
|
|
8961
|
+
alignItems: "center",
|
|
8962
|
+
gap: 4,
|
|
8963
|
+
minHeight: 28,
|
|
8964
|
+
maxWidth: "min(348px, calc(100vw - 16px))",
|
|
8965
|
+
padding: "6px 8px",
|
|
8966
|
+
background: "#2E2E2E",
|
|
8967
|
+
borderRadius: 4,
|
|
8968
|
+
boxSizing: "border-box"
|
|
8969
|
+
},
|
|
8970
|
+
children: [
|
|
8971
|
+
/* @__PURE__ */ jsx10(
|
|
8972
|
+
"span",
|
|
8973
|
+
{
|
|
8974
|
+
...{ [FLOAT_ATTR]: "" },
|
|
8975
|
+
style: {
|
|
8976
|
+
color: "#FFFFFF",
|
|
8977
|
+
fontSize: 12,
|
|
8978
|
+
lineHeight: "16px",
|
|
8979
|
+
fontFamily: '"SF Pro Text", "SF Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
8980
|
+
whiteSpace: "normal",
|
|
8981
|
+
wordBreak: "break-word",
|
|
8982
|
+
overflowWrap: "anywhere",
|
|
8983
|
+
maxWidth: 300
|
|
8984
|
+
},
|
|
8985
|
+
children: link2.href
|
|
8986
|
+
}
|
|
8987
|
+
),
|
|
8988
|
+
/* @__PURE__ */ jsx10(
|
|
8989
|
+
"div",
|
|
8990
|
+
{
|
|
8991
|
+
...{ [FLOAT_ATTR]: "" },
|
|
8992
|
+
style: {
|
|
8993
|
+
width: 1,
|
|
8994
|
+
height: 16,
|
|
8995
|
+
background: "#424242",
|
|
8996
|
+
flexShrink: 0
|
|
8997
|
+
}
|
|
8998
|
+
}
|
|
8999
|
+
),
|
|
9000
|
+
/* @__PURE__ */ jsx10(
|
|
9001
|
+
"button",
|
|
9002
|
+
{
|
|
9003
|
+
type: "button",
|
|
9004
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9005
|
+
onMouseDown: (e) => {
|
|
9006
|
+
e.preventDefault();
|
|
9007
|
+
onEdit(link2);
|
|
9008
|
+
},
|
|
9009
|
+
onMouseEnter: () => setHover(true),
|
|
9010
|
+
onMouseLeave: () => setHover(false),
|
|
9011
|
+
style: {
|
|
9012
|
+
...BTN_RESET2,
|
|
9013
|
+
padding: "0 2px",
|
|
9014
|
+
color: "#FFFFFF",
|
|
9015
|
+
fontSize: 12,
|
|
9016
|
+
lineHeight: "16px",
|
|
9017
|
+
fontWeight: 600,
|
|
9018
|
+
fontFamily: '"SF Pro Text", "SF Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
9019
|
+
opacity: hover ? 0.78 : 1,
|
|
9020
|
+
flexShrink: 0
|
|
9021
|
+
},
|
|
9022
|
+
children: "Edit"
|
|
9023
|
+
}
|
|
9024
|
+
)
|
|
9025
|
+
]
|
|
9026
|
+
}
|
|
9027
|
+
),
|
|
9028
|
+
/* @__PURE__ */ jsx10(
|
|
9029
|
+
"div",
|
|
9030
|
+
{
|
|
9031
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9032
|
+
style: {
|
|
9033
|
+
width: 0,
|
|
9034
|
+
height: 0,
|
|
9035
|
+
borderLeft: "6px solid transparent",
|
|
9036
|
+
borderRight: "6px solid transparent",
|
|
9037
|
+
borderTop: "6px solid #2E2E2E",
|
|
9038
|
+
marginTop: -1
|
|
9039
|
+
}
|
|
9040
|
+
}
|
|
9041
|
+
)
|
|
9042
|
+
]
|
|
9043
|
+
}
|
|
9044
|
+
),
|
|
9045
|
+
document.body
|
|
9046
|
+
);
|
|
9047
|
+
}
|
|
9048
|
+
function LinkEditDialog({ view, link: link2, onClose }) {
|
|
9049
|
+
const [textValue, setTextValue] = useState7(link2.text);
|
|
9050
|
+
const [hrefValue, setHrefValue] = useState7(link2.href);
|
|
9051
|
+
const textInputRef = useRef4(null);
|
|
9052
|
+
useEffect4(() => {
|
|
9053
|
+
setTextValue(link2.text);
|
|
9054
|
+
setHrefValue(link2.href);
|
|
9055
|
+
}, [link2.from, link2.href, link2.text, link2.to]);
|
|
9056
|
+
useEffect4(() => {
|
|
9057
|
+
setTimeout(() => textInputRef.current?.focus(), 0);
|
|
9058
|
+
}, [link2.from, link2.to]);
|
|
9059
|
+
useEffect4(() => {
|
|
9060
|
+
const onDown = (e) => {
|
|
9061
|
+
if (!e.target.closest(`[${FLOAT_ATTR}]`)) {
|
|
9062
|
+
onClose();
|
|
9063
|
+
}
|
|
9064
|
+
};
|
|
9065
|
+
document.addEventListener("mousedown", onDown, true);
|
|
9066
|
+
return () => document.removeEventListener("mousedown", onDown, true);
|
|
9067
|
+
}, [onClose]);
|
|
9068
|
+
const startCoords = view.coordsAtPos(link2.from);
|
|
9069
|
+
const endCoords = view.coordsAtPos(link2.to);
|
|
9070
|
+
const anchorTop = Math.min(startCoords.top, endCoords.top);
|
|
9071
|
+
const anchorBottom = Math.max(startCoords.bottom, endCoords.bottom);
|
|
9072
|
+
const linkLeft = Math.min(startCoords.left, endCoords.left);
|
|
9073
|
+
const linkRight = Math.max(startCoords.right, endCoords.right);
|
|
9074
|
+
const dialogW = 280;
|
|
9075
|
+
const estimatedDialogH = 188;
|
|
9076
|
+
const centerX = (linkLeft + linkRight) / 2;
|
|
9077
|
+
const left = Math.max(
|
|
9078
|
+
VPORT_MARGIN2,
|
|
9079
|
+
Math.min(centerX - dialogW / 2, window.innerWidth - dialogW - VPORT_MARGIN2)
|
|
9080
|
+
);
|
|
9081
|
+
let top = anchorTop - estimatedDialogH - 12;
|
|
9082
|
+
if (top < VPORT_MARGIN2) {
|
|
9083
|
+
top = Math.min(anchorBottom + 12, window.innerHeight - estimatedDialogH - VPORT_MARGIN2);
|
|
9084
|
+
}
|
|
9085
|
+
const finalHref = normalizeLinkHref(hrefValue);
|
|
9086
|
+
const finalText = textValue.trim() ? textValue : finalHref;
|
|
9087
|
+
const canSave = Boolean(finalHref) && (finalHref !== link2.href || finalText !== link2.text);
|
|
9088
|
+
const currentLink = () => {
|
|
9089
|
+
const activeLink = getLinkAtCursor(view.state);
|
|
9090
|
+
if (activeLink && activeLink.from === link2.from && activeLink.to === link2.to) {
|
|
9091
|
+
return activeLink;
|
|
9092
|
+
}
|
|
9093
|
+
return link2;
|
|
9094
|
+
};
|
|
9095
|
+
const saveLink = () => {
|
|
9096
|
+
const activeLink = currentLink();
|
|
9097
|
+
const nextHref = normalizeLinkHref(hrefValue);
|
|
9098
|
+
const nextText = textValue.trim() ? textValue : nextHref;
|
|
9099
|
+
if (!nextHref) return;
|
|
9100
|
+
if (nextHref === activeLink.href && nextText === activeLink.text) return;
|
|
9101
|
+
const cursorOffset = Math.max(0, view.state.selection.from - activeLink.from);
|
|
9102
|
+
const tr = view.state.tr;
|
|
9103
|
+
if (nextText === activeLink.text) {
|
|
9104
|
+
tr.removeMark(activeLink.from, activeLink.to, linkMark);
|
|
9105
|
+
tr.addMark(activeLink.from, activeLink.to, linkMark.create({ href: nextHref }));
|
|
9106
|
+
const nextCursor = Math.min(activeLink.from + cursorOffset, activeLink.to);
|
|
9107
|
+
tr.setSelection(TextSelection6.near(tr.doc.resolve(nextCursor)));
|
|
9108
|
+
} else {
|
|
9109
|
+
const preservedMarks = getNonLinkMarksInRange(view.state, activeLink.from, activeLink.to);
|
|
9110
|
+
tr.insertText(nextText, activeLink.from, activeLink.to);
|
|
9111
|
+
const nextTo = activeLink.from + nextText.length;
|
|
9112
|
+
tr.removeMark(activeLink.from, nextTo, linkMark);
|
|
9113
|
+
for (const mark of preservedMarks) {
|
|
9114
|
+
tr.addMark(activeLink.from, nextTo, mark);
|
|
9115
|
+
}
|
|
9116
|
+
tr.addMark(activeLink.from, nextTo, linkMark.create({ href: nextHref }));
|
|
9117
|
+
const nextCursor = Math.min(activeLink.from + cursorOffset, nextTo);
|
|
9118
|
+
tr.setSelection(TextSelection6.near(tr.doc.resolve(nextCursor)));
|
|
9119
|
+
}
|
|
9120
|
+
view.dispatch(tr);
|
|
9121
|
+
onClose();
|
|
9122
|
+
view.focus();
|
|
9123
|
+
};
|
|
9124
|
+
const removeLink = () => {
|
|
9125
|
+
const activeLink = currentLink();
|
|
9126
|
+
view.dispatch(view.state.tr.removeMark(activeLink.from, activeLink.to, linkMark));
|
|
9127
|
+
onClose();
|
|
9128
|
+
view.focus();
|
|
9129
|
+
};
|
|
9130
|
+
const handleKeyDown = (e) => {
|
|
9131
|
+
if (e.key === "Escape") {
|
|
9132
|
+
e.preventDefault();
|
|
9133
|
+
onClose();
|
|
9134
|
+
view.focus();
|
|
9135
|
+
return;
|
|
9136
|
+
}
|
|
9137
|
+
if (e.key === "Enter") {
|
|
9138
|
+
e.preventDefault();
|
|
9139
|
+
saveLink();
|
|
9140
|
+
}
|
|
9141
|
+
};
|
|
9142
|
+
return createPortal2(
|
|
9143
|
+
/* @__PURE__ */ jsxs9(
|
|
9144
|
+
"div",
|
|
9145
|
+
{
|
|
9146
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9147
|
+
style: {
|
|
9148
|
+
position: "fixed",
|
|
9149
|
+
left,
|
|
9150
|
+
top,
|
|
9151
|
+
zIndex: 1001,
|
|
9152
|
+
width: dialogW,
|
|
9153
|
+
display: "flex",
|
|
9154
|
+
flexDirection: "column",
|
|
9155
|
+
gap: 16,
|
|
9156
|
+
padding: 16,
|
|
9157
|
+
background: "#FFFFFF",
|
|
9158
|
+
borderRadius: 4,
|
|
9159
|
+
boxShadow: "0px 8px 10px rgba(13,13,13,0.12), 0px 3px 14px rgba(13,13,13,0.08), 0px 3px 5px rgba(13,13,13,0.04)",
|
|
9160
|
+
boxSizing: "border-box",
|
|
9161
|
+
animation: "ab-float-in 0.12s ease"
|
|
9162
|
+
},
|
|
9163
|
+
children: [
|
|
9164
|
+
/* @__PURE__ */ jsxs9("div", { ...{ [FLOAT_ATTR]: "" }, style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
9165
|
+
/* @__PURE__ */ jsxs9(
|
|
9166
|
+
"div",
|
|
9167
|
+
{
|
|
9168
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9169
|
+
style: {
|
|
9170
|
+
fontSize: 12,
|
|
9171
|
+
lineHeight: "16px",
|
|
9172
|
+
fontWeight: 600,
|
|
9173
|
+
color: "#0D0D0D"
|
|
9174
|
+
},
|
|
9175
|
+
children: [
|
|
9176
|
+
"Text ",
|
|
9177
|
+
/* @__PURE__ */ jsx10("span", { style: { color: "#858585" }, children: "(optional)" })
|
|
9178
|
+
]
|
|
9179
|
+
}
|
|
9180
|
+
),
|
|
9181
|
+
/* @__PURE__ */ jsx10(
|
|
9182
|
+
"input",
|
|
9183
|
+
{
|
|
9184
|
+
ref: textInputRef,
|
|
9185
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9186
|
+
value: textValue,
|
|
9187
|
+
onChange: (e) => setTextValue(e.target.value),
|
|
9188
|
+
onKeyDown: handleKeyDown,
|
|
9189
|
+
style: {
|
|
9190
|
+
height: 32,
|
|
9191
|
+
border: "1px solid #CCCCCC",
|
|
9192
|
+
borderRadius: 4,
|
|
9193
|
+
padding: "0 16px",
|
|
9194
|
+
fontSize: 14,
|
|
9195
|
+
color: "#0D0D0D",
|
|
9196
|
+
outline: "none",
|
|
9197
|
+
boxSizing: "border-box"
|
|
9198
|
+
}
|
|
9199
|
+
}
|
|
9200
|
+
)
|
|
9201
|
+
] }),
|
|
9202
|
+
/* @__PURE__ */ jsxs9("div", { ...{ [FLOAT_ATTR]: "" }, style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
9203
|
+
/* @__PURE__ */ jsx10(
|
|
9204
|
+
"div",
|
|
9205
|
+
{
|
|
9206
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9207
|
+
style: {
|
|
9208
|
+
fontSize: 12,
|
|
9209
|
+
lineHeight: "16px",
|
|
9210
|
+
fontWeight: 600,
|
|
9211
|
+
color: "#0D0D0D"
|
|
9212
|
+
},
|
|
9213
|
+
children: "Link"
|
|
9214
|
+
}
|
|
9215
|
+
),
|
|
9216
|
+
/* @__PURE__ */ jsx10(
|
|
9217
|
+
"input",
|
|
9218
|
+
{
|
|
9219
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9220
|
+
value: hrefValue,
|
|
9221
|
+
onChange: (e) => setHrefValue(e.target.value),
|
|
9222
|
+
onKeyDown: handleKeyDown,
|
|
9223
|
+
style: {
|
|
9224
|
+
height: 32,
|
|
9225
|
+
border: "1px solid #CCCCCC",
|
|
9226
|
+
borderRadius: 4,
|
|
9227
|
+
padding: "0 16px",
|
|
9228
|
+
fontSize: 14,
|
|
9229
|
+
color: "#0D0D0D",
|
|
9230
|
+
outline: "none",
|
|
9231
|
+
boxSizing: "border-box"
|
|
9232
|
+
}
|
|
9233
|
+
}
|
|
9234
|
+
)
|
|
9235
|
+
] }),
|
|
9236
|
+
/* @__PURE__ */ jsxs9(
|
|
9237
|
+
"div",
|
|
9238
|
+
{
|
|
9239
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9240
|
+
style: {
|
|
9241
|
+
display: "flex",
|
|
9242
|
+
alignItems: "center",
|
|
9243
|
+
justifyContent: "space-between",
|
|
9244
|
+
gap: 12
|
|
9245
|
+
},
|
|
9246
|
+
children: [
|
|
9247
|
+
/* @__PURE__ */ jsx10(
|
|
9248
|
+
"button",
|
|
9249
|
+
{
|
|
9250
|
+
type: "button",
|
|
9251
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9252
|
+
onMouseDown: (e) => {
|
|
9253
|
+
e.preventDefault();
|
|
9254
|
+
removeLink();
|
|
9255
|
+
},
|
|
9256
|
+
style: {
|
|
9257
|
+
...BTN_RESET2,
|
|
9258
|
+
fontSize: 14,
|
|
9259
|
+
lineHeight: "20px",
|
|
9260
|
+
fontWeight: 600,
|
|
9261
|
+
color: "#0D0D0D"
|
|
9262
|
+
},
|
|
9263
|
+
children: "Remove link"
|
|
9264
|
+
}
|
|
9265
|
+
),
|
|
9266
|
+
/* @__PURE__ */ jsxs9("div", { ...{ [FLOAT_ATTR]: "" }, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
9267
|
+
/* @__PURE__ */ jsx10(
|
|
9268
|
+
"button",
|
|
9269
|
+
{
|
|
9270
|
+
type: "button",
|
|
9271
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9272
|
+
onMouseDown: (e) => {
|
|
9273
|
+
e.preventDefault();
|
|
9274
|
+
onClose();
|
|
9275
|
+
view.focus();
|
|
9276
|
+
},
|
|
9277
|
+
style: {
|
|
9278
|
+
...BTN_RESET2,
|
|
9279
|
+
height: 32,
|
|
9280
|
+
padding: "0 13px",
|
|
9281
|
+
border: "1px solid #CCCCCC",
|
|
9282
|
+
borderRadius: 4,
|
|
9283
|
+
fontSize: 14,
|
|
9284
|
+
lineHeight: "20px",
|
|
9285
|
+
fontWeight: 600,
|
|
9286
|
+
color: "#0D0D0D"
|
|
9287
|
+
},
|
|
9288
|
+
children: "Cancel"
|
|
9289
|
+
}
|
|
9290
|
+
),
|
|
9291
|
+
/* @__PURE__ */ jsx10(
|
|
9292
|
+
"button",
|
|
9293
|
+
{
|
|
9294
|
+
type: "button",
|
|
9295
|
+
disabled: !canSave,
|
|
9296
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9297
|
+
onMouseDown: (e) => {
|
|
9298
|
+
e.preventDefault();
|
|
9299
|
+
if (!canSave) return;
|
|
9300
|
+
saveLink();
|
|
9301
|
+
},
|
|
9302
|
+
style: {
|
|
9303
|
+
...BTN_RESET2,
|
|
9304
|
+
height: 32,
|
|
9305
|
+
padding: "0 13px",
|
|
9306
|
+
borderRadius: 4,
|
|
9307
|
+
fontSize: 14,
|
|
9308
|
+
lineHeight: "20px",
|
|
9309
|
+
fontWeight: 600,
|
|
9310
|
+
background: canSave ? "#6210CC" : "#ECECEC",
|
|
9311
|
+
color: canSave ? "#FFFFFF" : "#A6A6A6",
|
|
9312
|
+
cursor: canSave ? "pointer" : "default"
|
|
9313
|
+
},
|
|
9314
|
+
children: "Save"
|
|
9315
|
+
}
|
|
9316
|
+
)
|
|
9317
|
+
] })
|
|
9318
|
+
]
|
|
9319
|
+
}
|
|
9320
|
+
)
|
|
9321
|
+
]
|
|
9322
|
+
}
|
|
9323
|
+
),
|
|
9324
|
+
document.body
|
|
9325
|
+
);
|
|
9326
|
+
}
|
|
8500
9327
|
var BLOCK_ITEMS = [
|
|
8501
9328
|
{
|
|
8502
9329
|
shortLabel: "\xB6",
|
|
@@ -8715,6 +9542,7 @@ function BlockMenuItem({
|
|
|
8715
9542
|
}
|
|
8716
9543
|
function FloatingMenu({ view, editorState }) {
|
|
8717
9544
|
const [showEmptyHandle, setShowEmptyHandle] = useState7(false);
|
|
9545
|
+
const [editingLink, setEditingLink] = useState7(null);
|
|
8718
9546
|
const dwellTimerRef = useRef4(null);
|
|
8719
9547
|
const lastEmptyPosRef = useRef4(null);
|
|
8720
9548
|
const [, setScrollTick] = useState7(0);
|
|
@@ -8740,9 +9568,16 @@ function FloatingMenu({ view, editorState }) {
|
|
|
8740
9568
|
`;
|
|
8741
9569
|
document.head.appendChild(style);
|
|
8742
9570
|
}, []);
|
|
9571
|
+
const emptyPos = editorState ? emptyBlockCursorPos(editorState) : null;
|
|
9572
|
+
const hasSelection = editorState ? !editorState.selection.empty : false;
|
|
9573
|
+
const linkAtCursor = editorState && !hasSelection ? getLinkAtCursor(editorState) : null;
|
|
9574
|
+
useEffect4(() => {
|
|
9575
|
+
if (!editingLink) return;
|
|
9576
|
+
if (!linkAtCursor || linkAtCursor.from !== editingLink.from || linkAtCursor.to !== editingLink.to) {
|
|
9577
|
+
setEditingLink(null);
|
|
9578
|
+
}
|
|
9579
|
+
}, [editingLink, linkAtCursor]);
|
|
8743
9580
|
if (!view || !editorState) return null;
|
|
8744
|
-
const emptyPos = emptyBlockCursorPos(editorState);
|
|
8745
|
-
const hasSelection = !editorState.selection.empty;
|
|
8746
9581
|
if (emptyPos !== lastEmptyPosRef.current) {
|
|
8747
9582
|
lastEmptyPosRef.current = emptyPos;
|
|
8748
9583
|
if (dwellTimerRef.current) {
|
|
@@ -8766,23 +9601,39 @@ function FloatingMenu({ view, editorState }) {
|
|
|
8766
9601
|
selectionRect
|
|
8767
9602
|
}
|
|
8768
9603
|
),
|
|
8769
|
-
!hasSelection &&
|
|
9604
|
+
!hasSelection && linkAtCursor && !editingLink && /* @__PURE__ */ jsx10(
|
|
9605
|
+
LinkHoverTooltip,
|
|
9606
|
+
{
|
|
9607
|
+
view,
|
|
9608
|
+
link: linkAtCursor,
|
|
9609
|
+
onEdit: (link2) => setEditingLink(link2)
|
|
9610
|
+
}
|
|
9611
|
+
),
|
|
9612
|
+
!hasSelection && editingLink && /* @__PURE__ */ jsx10(
|
|
9613
|
+
LinkEditDialog,
|
|
9614
|
+
{
|
|
9615
|
+
view,
|
|
9616
|
+
link: editingLink,
|
|
9617
|
+
onClose: () => setEditingLink(null)
|
|
9618
|
+
}
|
|
9619
|
+
),
|
|
9620
|
+
!hasSelection && !linkAtCursor && showEmptyHandle && emptyPos !== null && /* @__PURE__ */ jsx10(EmptyParaHandle, { view, cursorPos: emptyPos })
|
|
8770
9621
|
] }),
|
|
8771
9622
|
document.body
|
|
8772
9623
|
);
|
|
8773
9624
|
}
|
|
8774
9625
|
|
|
8775
9626
|
// src/ui/plugin/inlineSuggestPlugin.ts
|
|
8776
|
-
import { Plugin as
|
|
8777
|
-
import { Decoration as
|
|
8778
|
-
var inlineSuggestKey = new
|
|
9627
|
+
import { Plugin as Plugin9, PluginKey as PluginKey9 } from "prosemirror-state";
|
|
9628
|
+
import { Decoration as Decoration5, DecorationSet as DecorationSet5 } from "prosemirror-view";
|
|
9629
|
+
var inlineSuggestKey = new PluginKey9("inlineSuggest");
|
|
8779
9630
|
var DEBOUNCE_MS = 600;
|
|
8780
9631
|
function createInlineSuggestPlugin(provider, endpoint, options) {
|
|
8781
9632
|
const { onContextChange } = options ?? {};
|
|
8782
9633
|
return {
|
|
8783
9634
|
name: "inlineSuggest",
|
|
8784
9635
|
plugins: () => [
|
|
8785
|
-
new
|
|
9636
|
+
new Plugin9({
|
|
8786
9637
|
key: inlineSuggestKey,
|
|
8787
9638
|
state: {
|
|
8788
9639
|
init: () => ({ suggestion: null, anchorPos: null }),
|
|
@@ -8798,13 +9649,13 @@ function createInlineSuggestPlugin(provider, endpoint, options) {
|
|
|
8798
9649
|
props: {
|
|
8799
9650
|
decorations(state) {
|
|
8800
9651
|
const ps = inlineSuggestKey.getState(state);
|
|
8801
|
-
if (!ps?.suggestion || !state.selection.empty) return
|
|
9652
|
+
if (!ps?.suggestion || !state.selection.empty) return DecorationSet5.empty;
|
|
8802
9653
|
const ghost = document.createElement("span");
|
|
8803
9654
|
ghost.textContent = ps.suggestion;
|
|
8804
9655
|
ghost.style.cssText = "color: rgba(0,0,0,0.3); pointer-events: none; user-select: none;";
|
|
8805
9656
|
ghost.setAttribute("aria-hidden", "true");
|
|
8806
|
-
return
|
|
8807
|
-
|
|
9657
|
+
return DecorationSet5.create(state.doc, [
|
|
9658
|
+
Decoration5.widget(state.selection.from, ghost, {
|
|
8808
9659
|
side: 1,
|
|
8809
9660
|
key: "inline-suggest"
|
|
8810
9661
|
})
|
|
@@ -8959,6 +9810,7 @@ export {
|
|
|
8959
9810
|
createLinkPlugin,
|
|
8960
9811
|
createMarkdownClipboardPlugin,
|
|
8961
9812
|
createNoteBlockPlugin,
|
|
9813
|
+
createPlaceholderPlugin,
|
|
8962
9814
|
createPluginArray,
|
|
8963
9815
|
createReactNodeView,
|
|
8964
9816
|
createSlashCommandPlugin,
|