@sendbird/actionbook-core 0.9.3 → 0.9.8
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 +1161 -195
- 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,64 @@ 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
|
+
var NOOP = /* @__PURE__ */ Symbol("noop");
|
|
2749
|
+
function handleListInputRule(state, start, end, listType, attrs) {
|
|
2750
|
+
const resolvePos = Math.max(start, end - 1);
|
|
2751
|
+
const parentList = findParentList(state, resolvePos);
|
|
2752
|
+
if (!parentList) return null;
|
|
2753
|
+
const $from = state.doc.resolve(resolvePos);
|
|
2754
|
+
const { depth: listDepth, node: listNode } = parentList;
|
|
2755
|
+
const paraContentSize = $from.parent.content.size;
|
|
2756
|
+
const matchedLen = end - start;
|
|
2757
|
+
if (paraContentSize !== matchedLen) return null;
|
|
2758
|
+
if (listNode.type === listType) {
|
|
2759
|
+
return NOOP;
|
|
2760
|
+
}
|
|
2761
|
+
const { listItem: liType } = actionbookSchema.nodes;
|
|
2762
|
+
const tr = state.tr.delete(start, end);
|
|
2763
|
+
const $pos = tr.doc.resolve(tr.mapping.map(resolvePos));
|
|
2764
|
+
let liDepth = -1;
|
|
2765
|
+
for (let d = $pos.depth; d > 0; d--) {
|
|
2766
|
+
if ($pos.node(d).type === liType) {
|
|
2767
|
+
liDepth = d;
|
|
2768
|
+
break;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
if (liDepth < 0) return null;
|
|
2772
|
+
const parentListAfterDelete = $pos.node(liDepth - 1);
|
|
2773
|
+
const liIndex = $pos.index(liDepth - 1);
|
|
2774
|
+
const liNode = parentListAfterDelete.child(liIndex);
|
|
2775
|
+
const parentListStart = $pos.before(liDepth - 1);
|
|
2776
|
+
const parentListEnd = $pos.after(liDepth - 1);
|
|
2777
|
+
const fragments = [];
|
|
2778
|
+
if (liIndex > 0) {
|
|
2779
|
+
const beforeItems = [];
|
|
2780
|
+
for (let i = 0; i < liIndex; i++) beforeItems.push(parentListAfterDelete.child(i));
|
|
2781
|
+
fragments.push(parentListAfterDelete.type.create(parentListAfterDelete.attrs, beforeItems));
|
|
2782
|
+
}
|
|
2783
|
+
fragments.push(listType.create(attrs ?? null, liNode));
|
|
2784
|
+
if (liIndex < parentListAfterDelete.childCount - 1) {
|
|
2785
|
+
const afterItems = [];
|
|
2786
|
+
for (let i = liIndex + 1; i < parentListAfterDelete.childCount; i++) {
|
|
2787
|
+
afterItems.push(parentListAfterDelete.child(i));
|
|
2788
|
+
}
|
|
2789
|
+
fragments.push(parentListAfterDelete.type.create(parentListAfterDelete.attrs, afterItems));
|
|
2790
|
+
}
|
|
2791
|
+
tr.replaceWith(parentListStart, parentListEnd, fragments);
|
|
2792
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(tr.mapping.map(start))));
|
|
2793
|
+
return tr;
|
|
2794
|
+
}
|
|
2737
2795
|
function markInputRule(pattern, markType, markerLen) {
|
|
2738
2796
|
return new InputRule(pattern, (state, match, start, end) => {
|
|
2739
2797
|
const textContent2 = match[1];
|
|
@@ -2798,12 +2856,32 @@ function createInputRulesPlugin() {
|
|
|
2798
2856
|
return state.tr.delete(start, end).insert(start, list);
|
|
2799
2857
|
})
|
|
2800
2858
|
);
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
wrappingInputRule(
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2859
|
+
{
|
|
2860
|
+
const blType = actionbookSchema.nodes.bulletList;
|
|
2861
|
+
const fallback = wrappingInputRule(BULLET_LIST_RE, blType);
|
|
2862
|
+
rules.push(
|
|
2863
|
+
new InputRule(BULLET_LIST_RE, (state, match, start, end) => {
|
|
2864
|
+
const result = handleListInputRule(state, start, end, blType);
|
|
2865
|
+
if (result === NOOP) return null;
|
|
2866
|
+
if (result) return result;
|
|
2867
|
+
const handler = fallback.handler;
|
|
2868
|
+
return handler(state, match, start, end);
|
|
2869
|
+
})
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
{
|
|
2873
|
+
const olType = actionbookSchema.nodes.orderedList;
|
|
2874
|
+
const fallback = wrappingInputRule(ORDERED_LIST_RE, olType, (m) => ({ start: +m[1] }));
|
|
2875
|
+
rules.push(
|
|
2876
|
+
new InputRule(ORDERED_LIST_RE, (state, match, start, end) => {
|
|
2877
|
+
const result = handleListInputRule(state, start, end, olType, { start: +match[1] });
|
|
2878
|
+
if (result === NOOP) return null;
|
|
2879
|
+
if (result) return result;
|
|
2880
|
+
const handler = fallback.handler;
|
|
2881
|
+
return handler(state, match, start, end);
|
|
2882
|
+
})
|
|
2883
|
+
);
|
|
2884
|
+
}
|
|
2807
2885
|
const jumpPointType = actionbookSchema.nodes.jumpPoint;
|
|
2808
2886
|
rules.push(
|
|
2809
2887
|
new InputRule(JUMP_POINT_RE2, (state, match, start, end) => {
|
|
@@ -2816,7 +2894,12 @@ function createInputRulesPlugin() {
|
|
|
2816
2894
|
}
|
|
2817
2895
|
});
|
|
2818
2896
|
if (exists) return null;
|
|
2819
|
-
|
|
2897
|
+
const tr = state.tr.delete(start, end).insert(start, jumpPointType.create({ id }));
|
|
2898
|
+
const afterAtom = start + 1;
|
|
2899
|
+
tr.insertText(" ", afterAtom);
|
|
2900
|
+
const cursorPos = afterAtom + 1;
|
|
2901
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(Math.min(cursorPos, tr.doc.content.size))));
|
|
2902
|
+
return tr;
|
|
2820
2903
|
})
|
|
2821
2904
|
);
|
|
2822
2905
|
rules.push(markInputRule(BOLD_STAR_RE, actionbookSchema.marks.bold, 2));
|
|
@@ -2845,8 +2928,100 @@ function createHistoryPlugin() {
|
|
|
2845
2928
|
|
|
2846
2929
|
// src/ui/plugin/keymapPlugin.ts
|
|
2847
2930
|
import { baseKeymap, chainCommands, newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock, toggleMark, setBlockType, joinBackward } from "prosemirror-commands";
|
|
2931
|
+
import { TextSelection as TextSelection2 } from "prosemirror-state";
|
|
2848
2932
|
import { keymap as keymap3 } from "prosemirror-keymap";
|
|
2849
2933
|
import { liftListItem, sinkListItem, splitListItem, wrapInList } from "prosemirror-schema-list";
|
|
2934
|
+
|
|
2935
|
+
// src/ui/plugin/noteBlockPlugin.tsx
|
|
2936
|
+
import { Selection } from "prosemirror-state";
|
|
2937
|
+
var NoteBlockView = class {
|
|
2938
|
+
dom;
|
|
2939
|
+
contentDOM;
|
|
2940
|
+
constructor(_node, _view, _getPos) {
|
|
2941
|
+
this.dom = document.createElement("div");
|
|
2942
|
+
this.dom.setAttribute("data-note-block", "");
|
|
2943
|
+
this.dom.className = "ab-note-block";
|
|
2944
|
+
this.dom.style.cssText = [
|
|
2945
|
+
"position: relative",
|
|
2946
|
+
"margin: 8px 0",
|
|
2947
|
+
"padding: 16px 24px",
|
|
2948
|
+
"background: #fff",
|
|
2949
|
+
"border: 1px dashed #ccc",
|
|
2950
|
+
"border-radius: 4px",
|
|
2951
|
+
"display: flex",
|
|
2952
|
+
"flex-direction: column",
|
|
2953
|
+
"gap: 4px"
|
|
2954
|
+
].join(";");
|
|
2955
|
+
const label = document.createElement("span");
|
|
2956
|
+
label.contentEditable = "false";
|
|
2957
|
+
label.textContent = "Note";
|
|
2958
|
+
label.style.cssText = [
|
|
2959
|
+
"font-family: SF Pro Text, -apple-system, BlinkMacSystemFont, sans-serif",
|
|
2960
|
+
"display: inline-flex",
|
|
2961
|
+
"align-items: center",
|
|
2962
|
+
"justify-content: center",
|
|
2963
|
+
"align-self: flex-start",
|
|
2964
|
+
"font-size: 12px",
|
|
2965
|
+
"font-weight: 400",
|
|
2966
|
+
"font-style: normal",
|
|
2967
|
+
"line-height: 16px",
|
|
2968
|
+
"color: #858585",
|
|
2969
|
+
"background: #f7f7f7",
|
|
2970
|
+
"border: 1px solid #e0e0e0",
|
|
2971
|
+
"border-radius: 4px",
|
|
2972
|
+
"padding: 2px 4px",
|
|
2973
|
+
"user-select: none",
|
|
2974
|
+
"height: 20px"
|
|
2975
|
+
].join(";");
|
|
2976
|
+
this.dom.appendChild(label);
|
|
2977
|
+
this.contentDOM = document.createElement("div");
|
|
2978
|
+
this.contentDOM.className = "ab-note-block-content";
|
|
2979
|
+
this.contentDOM.style.cssText = [
|
|
2980
|
+
"font-size: 14px",
|
|
2981
|
+
"font-style: italic",
|
|
2982
|
+
"font-weight: 400",
|
|
2983
|
+
"line-height: 20px",
|
|
2984
|
+
"letter-spacing: -0.1px",
|
|
2985
|
+
"color: #858585"
|
|
2986
|
+
].join(";");
|
|
2987
|
+
this.dom.appendChild(this.contentDOM);
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
var exitNoteBlockOnEnter = (state, dispatch) => {
|
|
2991
|
+
const { $from } = state.selection;
|
|
2992
|
+
let noteBlockDepth = -1;
|
|
2993
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
2994
|
+
if ($from.node(d).type.name === "noteBlock") {
|
|
2995
|
+
noteBlockDepth = d;
|
|
2996
|
+
break;
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
if (noteBlockDepth < 0) return false;
|
|
3000
|
+
const parentNode = $from.parent;
|
|
3001
|
+
if (parentNode.type.name !== "paragraph" || parentNode.content.size !== 0) {
|
|
3002
|
+
return false;
|
|
3003
|
+
}
|
|
3004
|
+
if (!dispatch) return true;
|
|
3005
|
+
const paragraphStart = $from.before($from.depth);
|
|
3006
|
+
const paragraphEnd = $from.after($from.depth);
|
|
3007
|
+
const tr = state.tr.delete(paragraphStart, paragraphEnd);
|
|
3008
|
+
const noteBlockEnd = tr.mapping.map($from.after(noteBlockDepth));
|
|
3009
|
+
const newParagraph = state.schema.nodes.paragraph.create();
|
|
3010
|
+
tr.insert(noteBlockEnd, newParagraph);
|
|
3011
|
+
tr.setSelection(Selection.near(tr.doc.resolve(noteBlockEnd + 1)));
|
|
3012
|
+
dispatch(tr.scrollIntoView());
|
|
3013
|
+
return true;
|
|
3014
|
+
};
|
|
3015
|
+
function createNoteBlockPlugin() {
|
|
3016
|
+
return {
|
|
3017
|
+
name: "noteBlockNodeView",
|
|
3018
|
+
nodeViews: () => ({
|
|
3019
|
+
noteBlock: (node, view, getPos) => new NoteBlockView(node, view, getPos)
|
|
3020
|
+
})
|
|
3021
|
+
};
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
// src/ui/plugin/keymapPlugin.ts
|
|
2850
3025
|
var TAB_CHAR = " ";
|
|
2851
3026
|
var { listItem, bulletList, orderedList, hardBreak, heading, paragraph, horizontalRule, blockquote } = actionbookSchema.nodes;
|
|
2852
3027
|
var { bold: boldMark, italic: italicMark, underline: underlineMark, strikethrough: strikethroughMark, code: codeMark } = actionbookSchema.marks;
|
|
@@ -2893,7 +3068,101 @@ var backspaceAfterLeafBlock = (state, dispatch) => {
|
|
|
2893
3068
|
}
|
|
2894
3069
|
return true;
|
|
2895
3070
|
};
|
|
3071
|
+
var backspaceDeleteEmptyBlock = (state, dispatch) => {
|
|
3072
|
+
const { $from } = state.selection;
|
|
3073
|
+
if (!state.selection.empty || $from.parentOffset !== 0) return false;
|
|
3074
|
+
if ($from.parent.type !== paragraph || $from.parent.content.size !== 0) return false;
|
|
3075
|
+
const deletableTypes = /* @__PURE__ */ new Set(["jinjaIfBlock", "jinjaIfBranch", "noteBlock", "blockquote"]);
|
|
3076
|
+
for (let d = $from.depth - 1; d > 0; d--) {
|
|
3077
|
+
const ancestor = $from.node(d);
|
|
3078
|
+
if (!deletableTypes.has(ancestor.type.name)) continue;
|
|
3079
|
+
if (ancestor.type.name === "jinjaIfBranch" && ancestor.childCount === 1 && ancestor.child(0).content.size === 0) {
|
|
3080
|
+
for (let dd = d - 1; dd > 0; dd--) {
|
|
3081
|
+
if ($from.node(dd).type.name === "jinjaIfBlock") {
|
|
3082
|
+
d = dd;
|
|
3083
|
+
break;
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
const blockNode = $from.node(d);
|
|
3088
|
+
const blockText = blockNode.textContent.trim();
|
|
3089
|
+
if (blockText.length > 0) return false;
|
|
3090
|
+
if (dispatch) {
|
|
3091
|
+
const blockStart = $from.before(d);
|
|
3092
|
+
const blockEnd = $from.after(d);
|
|
3093
|
+
const tr = state.tr.replaceWith(blockStart, blockEnd, paragraph.create());
|
|
3094
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(blockStart)));
|
|
3095
|
+
dispatch(tr.scrollIntoView());
|
|
3096
|
+
}
|
|
3097
|
+
return true;
|
|
3098
|
+
}
|
|
3099
|
+
return false;
|
|
3100
|
+
};
|
|
3101
|
+
var joinListItemBackward = (state, dispatch) => {
|
|
3102
|
+
const { $from } = state.selection;
|
|
3103
|
+
if (!state.selection.empty) return false;
|
|
3104
|
+
if ($from.parentOffset !== 0) return false;
|
|
3105
|
+
if (!cursorDirectlyInListItem(state)) return false;
|
|
3106
|
+
if ($from.index($from.depth - 1) !== 0) return false;
|
|
3107
|
+
const liDepth = $from.depth - 1;
|
|
3108
|
+
const listDepth = liDepth - 1;
|
|
3109
|
+
if (listDepth < 0) return false;
|
|
3110
|
+
const listNode = $from.node(listDepth);
|
|
3111
|
+
if (listNode.type !== bulletList && listNode.type !== orderedList) return false;
|
|
3112
|
+
const liIndex = $from.index(listDepth);
|
|
3113
|
+
if (liIndex > 0) {
|
|
3114
|
+
if (dispatch) {
|
|
3115
|
+
const joinPos = $from.before(liDepth);
|
|
3116
|
+
const tr = state.tr.join(joinPos);
|
|
3117
|
+
const mappedPos = tr.mapping.map(joinPos);
|
|
3118
|
+
if (tr.doc.resolve(mappedPos).nodeBefore?.isTextblock && tr.doc.resolve(mappedPos).nodeAfter?.isTextblock) {
|
|
3119
|
+
tr.join(mappedPos);
|
|
3120
|
+
}
|
|
3121
|
+
dispatch(tr.scrollIntoView());
|
|
3122
|
+
}
|
|
3123
|
+
return true;
|
|
3124
|
+
}
|
|
3125
|
+
const listStart = $from.before(listDepth);
|
|
3126
|
+
const parentOfList = $from.node(listDepth - 1);
|
|
3127
|
+
const listIndexInParent = $from.index(listDepth - 1);
|
|
3128
|
+
if (listIndexInParent > 0) {
|
|
3129
|
+
const prevBlock = parentOfList.child(listIndexInParent - 1);
|
|
3130
|
+
if (prevBlock.isTextblock) {
|
|
3131
|
+
if (dispatch) {
|
|
3132
|
+
const liNode = listNode.child(0);
|
|
3133
|
+
const firstPara = liNode.firstChild;
|
|
3134
|
+
const liStart = $from.before(liDepth);
|
|
3135
|
+
const liEnd = $from.after(liDepth);
|
|
3136
|
+
const tr = state.tr;
|
|
3137
|
+
if (listNode.childCount === 1) {
|
|
3138
|
+
tr.delete(listStart, $from.after(listDepth));
|
|
3139
|
+
} else {
|
|
3140
|
+
tr.delete(liStart, liEnd);
|
|
3141
|
+
}
|
|
3142
|
+
const prevBlockEnd = tr.mapping.map(listStart) - 1;
|
|
3143
|
+
if (firstPara.content.size > 0) {
|
|
3144
|
+
tr.insert(prevBlockEnd, firstPara.content);
|
|
3145
|
+
}
|
|
3146
|
+
if (liNode.childCount > 1) {
|
|
3147
|
+
const nestedContent = [];
|
|
3148
|
+
for (let i = 1; i < liNode.childCount; i++) {
|
|
3149
|
+
nestedContent.push(liNode.child(i));
|
|
3150
|
+
}
|
|
3151
|
+
const insertPos = tr.mapping.map(listStart);
|
|
3152
|
+
for (const node of nestedContent) {
|
|
3153
|
+
tr.insert(insertPos, node);
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(prevBlockEnd)));
|
|
3157
|
+
dispatch(tr.scrollIntoView());
|
|
3158
|
+
}
|
|
3159
|
+
return true;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
return liftListItem(listItem)(state, dispatch);
|
|
3163
|
+
};
|
|
2896
3164
|
var backspaceCommand = chainCommands(
|
|
3165
|
+
backspaceDeleteEmptyBlock,
|
|
2897
3166
|
backspaceAfterList,
|
|
2898
3167
|
backspaceAfterLeafBlock,
|
|
2899
3168
|
(state, dispatch) => {
|
|
@@ -2903,7 +3172,13 @@ var backspaceCommand = chainCommands(
|
|
|
2903
3172
|
if ($from.parent.type === heading) {
|
|
2904
3173
|
return setBlockType(paragraph)(state, dispatch);
|
|
2905
3174
|
}
|
|
3175
|
+
return false;
|
|
3176
|
+
},
|
|
3177
|
+
joinListItemBackward,
|
|
3178
|
+
(state, dispatch) => {
|
|
2906
3179
|
if (!cursorDirectlyInListItem(state)) return false;
|
|
3180
|
+
const { $from } = state.selection;
|
|
3181
|
+
if ($from.parentOffset !== 0) return false;
|
|
2907
3182
|
if ($from.index($from.depth - 1) !== 0) return false;
|
|
2908
3183
|
return liftListItem(listItem)(state, dispatch);
|
|
2909
3184
|
},
|
|
@@ -2911,8 +3186,9 @@ var backspaceCommand = chainCommands(
|
|
|
2911
3186
|
);
|
|
2912
3187
|
var tabCommand = (state, dispatch) => {
|
|
2913
3188
|
const { $from } = state.selection;
|
|
2914
|
-
if (cursorDirectlyInListItem(state)
|
|
3189
|
+
if (cursorDirectlyInListItem(state)) {
|
|
2915
3190
|
if (sinkListItem(listItem)(state, dispatch)) return true;
|
|
3191
|
+
return true;
|
|
2916
3192
|
}
|
|
2917
3193
|
if (dispatch) dispatch(state.tr.insertText(TAB_CHAR));
|
|
2918
3194
|
return true;
|
|
@@ -2929,7 +3205,86 @@ var shiftTabCommand = (state, dispatch) => {
|
|
|
2929
3205
|
}
|
|
2930
3206
|
return true;
|
|
2931
3207
|
};
|
|
3208
|
+
var blockExitEnterCount = 0;
|
|
3209
|
+
var blockExitLastTime = 0;
|
|
3210
|
+
var BLOCK_EXIT_TYPES = /* @__PURE__ */ new Set(["blockquote", "jinjaIfBranch"]);
|
|
3211
|
+
var exitBlockOnDoubleEnter = (state, dispatch) => {
|
|
3212
|
+
const { $from } = state.selection;
|
|
3213
|
+
let blockDepth = -1;
|
|
3214
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
3215
|
+
if (BLOCK_EXIT_TYPES.has($from.node(d).type.name)) {
|
|
3216
|
+
blockDepth = d;
|
|
3217
|
+
break;
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
if (blockDepth < 0) {
|
|
3221
|
+
blockExitEnterCount = 0;
|
|
3222
|
+
return false;
|
|
3223
|
+
}
|
|
3224
|
+
if ($from.parent.type.name !== "paragraph" || $from.parent.content.size !== 0) {
|
|
3225
|
+
blockExitEnterCount = 0;
|
|
3226
|
+
return false;
|
|
3227
|
+
}
|
|
3228
|
+
const now = Date.now();
|
|
3229
|
+
if (now - blockExitLastTime > 2e3) blockExitEnterCount = 0;
|
|
3230
|
+
blockExitLastTime = now;
|
|
3231
|
+
blockExitEnterCount++;
|
|
3232
|
+
if (blockExitEnterCount < 2) return false;
|
|
3233
|
+
blockExitEnterCount = 0;
|
|
3234
|
+
if (!dispatch) return true;
|
|
3235
|
+
const paraStart = $from.before($from.depth);
|
|
3236
|
+
const paraEnd = $from.after($from.depth);
|
|
3237
|
+
const tr = state.tr.delete(paraStart, paraEnd);
|
|
3238
|
+
const mapped = tr.mapping.map($from.before($from.depth));
|
|
3239
|
+
const $m = tr.doc.resolve(Math.min(mapped, tr.doc.content.size));
|
|
3240
|
+
for (let d = $m.depth; d > 0; d--) {
|
|
3241
|
+
if (BLOCK_EXIT_TYPES.has($m.node(d).type.name)) {
|
|
3242
|
+
const last = $m.node(d).lastChild;
|
|
3243
|
+
if (last?.type.name === "paragraph" && last.content.size === 0) {
|
|
3244
|
+
const lastPos = $m.end(d) - last.nodeSize;
|
|
3245
|
+
tr.delete(lastPos, lastPos + last.nodeSize);
|
|
3246
|
+
}
|
|
3247
|
+
break;
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
let exitDepth = blockDepth;
|
|
3251
|
+
const blockTypeName = $from.node(blockDepth).type.name;
|
|
3252
|
+
if (blockTypeName === "jinjaIfBranch") {
|
|
3253
|
+
for (let d = blockDepth - 1; d > 0; d--) {
|
|
3254
|
+
if ($from.node(d).type.name === "jinjaIfBlock") {
|
|
3255
|
+
exitDepth = d;
|
|
3256
|
+
break;
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
const blockEnd = tr.mapping.map($from.after(exitDepth));
|
|
3261
|
+
const newPara = paragraph.create();
|
|
3262
|
+
tr.insert(blockEnd, newPara);
|
|
3263
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(blockEnd + 1)));
|
|
3264
|
+
dispatch(tr.scrollIntoView());
|
|
3265
|
+
return true;
|
|
3266
|
+
};
|
|
3267
|
+
var exitCodeBlockOnEnter = (state, dispatch) => {
|
|
3268
|
+
const { $from } = state.selection;
|
|
3269
|
+
if ($from.parent.type.name !== "codeBlock") return false;
|
|
3270
|
+
const codeBlock = $from.parent;
|
|
3271
|
+
const text2 = codeBlock.textContent;
|
|
3272
|
+
if ($from.parentOffset !== text2.length) return false;
|
|
3273
|
+
if (!text2.endsWith("\n")) return false;
|
|
3274
|
+
if (dispatch) {
|
|
3275
|
+
const codeBlockPos = $from.before($from.depth);
|
|
3276
|
+
const tr = state.tr.delete($from.pos - 1, $from.pos);
|
|
3277
|
+
const blockEnd = tr.mapping.map(codeBlockPos + codeBlock.nodeSize);
|
|
3278
|
+
tr.insert(blockEnd, paragraph.create());
|
|
3279
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(blockEnd + 1)));
|
|
3280
|
+
dispatch(tr.scrollIntoView());
|
|
3281
|
+
}
|
|
3282
|
+
return true;
|
|
3283
|
+
};
|
|
2932
3284
|
var enterCommand = chainCommands(
|
|
3285
|
+
exitNoteBlockOnEnter,
|
|
3286
|
+
exitBlockOnDoubleEnter,
|
|
3287
|
+
exitCodeBlockOnEnter,
|
|
2933
3288
|
newlineInCode,
|
|
2934
3289
|
// Split list item on Enter; lift empty list item out of list
|
|
2935
3290
|
splitListItem(listItem),
|
|
@@ -4705,6 +5060,17 @@ function analyzeJinjaBlocks(doc2) {
|
|
|
4705
5060
|
|
|
4706
5061
|
// src/tree/documentTree.ts
|
|
4707
5062
|
var MAX_DEPTH6 = 128;
|
|
5063
|
+
var END_ACTION_RESOURCE_IDS = /* @__PURE__ */ new Set([
|
|
5064
|
+
"close-happy-tiger"
|
|
5065
|
+
// PredefinedToolKey.CloseConversation
|
|
5066
|
+
]);
|
|
5067
|
+
var END_ACTION_TEXTS = /* @__PURE__ */ new Set([
|
|
5068
|
+
"end conversation",
|
|
5069
|
+
"end_conversation"
|
|
5070
|
+
]);
|
|
5071
|
+
function isEndActionTag(tagType, resourceId, text2) {
|
|
5072
|
+
return tagType === "handoff" || END_ACTION_RESOURCE_IDS.has(resourceId) || END_ACTION_TEXTS.has(text2.toLowerCase());
|
|
5073
|
+
}
|
|
4708
5074
|
function extractInlineItems(content, blockIndex) {
|
|
4709
5075
|
const items = [];
|
|
4710
5076
|
for (const node of content) {
|
|
@@ -4716,10 +5082,10 @@ function extractInlineItems(content, blockIndex) {
|
|
|
4716
5082
|
children: []
|
|
4717
5083
|
});
|
|
4718
5084
|
} else if (node.type === "resourceTag") {
|
|
4719
|
-
const
|
|
5085
|
+
const endAction = isEndActionTag(node.tagType, node.resourceId, node.text);
|
|
4720
5086
|
items.push({
|
|
4721
|
-
type:
|
|
4722
|
-
label:
|
|
5087
|
+
type: endAction ? "endAction" : "resourceTag",
|
|
5088
|
+
label: endAction ? `End ${node.text}` : node.text,
|
|
4723
5089
|
blockIndex,
|
|
4724
5090
|
children: [],
|
|
4725
5091
|
meta: { tagType: node.tagType, resourceId: node.resourceId }
|
|
@@ -4753,14 +5119,15 @@ function extractBlockItems(blocks, startIndex, depth) {
|
|
|
4753
5119
|
break;
|
|
4754
5120
|
}
|
|
4755
5121
|
case "jinjaIfBlock": {
|
|
4756
|
-
const branches = block.branches.map((branch) => {
|
|
5122
|
+
const branches = block.branches.map((branch, branchIdx) => {
|
|
4757
5123
|
const branchLabel = branch.branchType === "else" ? "ELSE" : `${branch.branchType.toUpperCase()} ${branch.condition || ""}`.trim();
|
|
4758
5124
|
const branchChildren = extractBlockItems(branch.content, blockIndex, depth + 1);
|
|
4759
5125
|
return {
|
|
4760
5126
|
type: "jinjaBranch",
|
|
4761
5127
|
label: branchLabel,
|
|
4762
5128
|
blockIndex,
|
|
4763
|
-
children: branchChildren
|
|
5129
|
+
children: branchChildren,
|
|
5130
|
+
meta: { branchIndex: branchIdx }
|
|
4764
5131
|
};
|
|
4765
5132
|
});
|
|
4766
5133
|
items.push({
|
|
@@ -4808,11 +5175,12 @@ function buildDocumentTree(doc2) {
|
|
|
4808
5175
|
const hasStructuredJinja = items.some((n) => n.type === "jinjaIf");
|
|
4809
5176
|
if (!hasStructuredJinja) {
|
|
4810
5177
|
for (const s of structures) {
|
|
4811
|
-
const branches = s.branches.map((b) => ({
|
|
5178
|
+
const branches = s.branches.map((b, branchIdx) => ({
|
|
4812
5179
|
type: "jinjaBranch",
|
|
4813
5180
|
label: b.type === "else" ? "ELSE" : `${b.type.toUpperCase()} ${b.condition || ""}`.trim(),
|
|
4814
5181
|
blockIndex: b.tagBlockIndex,
|
|
4815
|
-
children: []
|
|
5182
|
+
children: [],
|
|
5183
|
+
meta: { branchIndex: branchIdx }
|
|
4816
5184
|
}));
|
|
4817
5185
|
const jinjaNode = {
|
|
4818
5186
|
type: "jinjaIf",
|
|
@@ -4916,6 +5284,7 @@ function textToSlice(text2, view) {
|
|
|
4916
5284
|
return null;
|
|
4917
5285
|
}
|
|
4918
5286
|
}
|
|
5287
|
+
var URL_RE = /^https?:\/\/[^\s]+$/i;
|
|
4919
5288
|
function createPlugin() {
|
|
4920
5289
|
return new Plugin({
|
|
4921
5290
|
key,
|
|
@@ -4930,6 +5299,14 @@ function createPlugin() {
|
|
|
4930
5299
|
return true;
|
|
4931
5300
|
}
|
|
4932
5301
|
}
|
|
5302
|
+
if (text2 && URL_RE.test(text2.trim())) {
|
|
5303
|
+
const url = text2.trim();
|
|
5304
|
+
const linkMark2 = actionbookSchema.marks.link.create({ href: url });
|
|
5305
|
+
const textNode = actionbookSchema.text(url, [linkMark2]);
|
|
5306
|
+
const slice2 = new Slice(Fragment.from(textNode), 0, 0);
|
|
5307
|
+
view.dispatch(view.state.tr.replaceSelection(slice2));
|
|
5308
|
+
return true;
|
|
5309
|
+
}
|
|
4933
5310
|
if (!text2) return false;
|
|
4934
5311
|
const slice = textToSlice(text2, view);
|
|
4935
5312
|
if (!slice) return false;
|
|
@@ -4975,7 +5352,7 @@ function createMarkdownClipboardPlugin() {
|
|
|
4975
5352
|
}
|
|
4976
5353
|
|
|
4977
5354
|
// src/ui/plugin/jumpPointPlugin.ts
|
|
4978
|
-
import { Plugin as Plugin2, PluginKey as PluginKey2, TextSelection as
|
|
5355
|
+
import { Plugin as Plugin2, PluginKey as PluginKey2, TextSelection as TextSelection3 } from "prosemirror-state";
|
|
4979
5356
|
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
4980
5357
|
var adjacentKey = new PluginKey2("jumpPointAdjacent");
|
|
4981
5358
|
var JUMP_POINT_ADJACENT_SPEC = { jumpPointAdjacent: true };
|
|
@@ -5038,6 +5415,9 @@ function createJumpPointEditPlugin() {
|
|
|
5038
5415
|
});
|
|
5039
5416
|
if (!duplicate) {
|
|
5040
5417
|
reconvertTr.replaceWith(safeFrom, safeTo, jumpPointType.create({ id }));
|
|
5418
|
+
const mappedCursor = reconvertTr.mapping.map(cursor);
|
|
5419
|
+
const clampedCursor = Math.min(mappedCursor, reconvertTr.doc.content.size);
|
|
5420
|
+
reconvertTr.setSelection(TextSelection3.near(reconvertTr.doc.resolve(clampedCursor)));
|
|
5041
5421
|
}
|
|
5042
5422
|
}
|
|
5043
5423
|
}
|
|
@@ -5070,7 +5450,7 @@ function explodeOnBackspace(state) {
|
|
|
5070
5450
|
const rawText = `^${id}`;
|
|
5071
5451
|
const tr = state.tr.replaceWith(nodeStart, nodeEnd, state.schema.text(rawText));
|
|
5072
5452
|
const cursorPos = Math.min(nodeStart + rawText.length, tr.doc.content.size);
|
|
5073
|
-
tr.setSelection(
|
|
5453
|
+
tr.setSelection(TextSelection3.near(tr.doc.resolve(cursorPos)));
|
|
5074
5454
|
return tr;
|
|
5075
5455
|
}
|
|
5076
5456
|
function explodeOnArrowLeft(state) {
|
|
@@ -5080,7 +5460,7 @@ function explodeOnArrowLeft(state) {
|
|
|
5080
5460
|
const rawText = `^${id}^`;
|
|
5081
5461
|
const tr = state.tr.replaceWith(nodeStart, nodeEnd, state.schema.text(rawText));
|
|
5082
5462
|
const cursorPos = Math.min(nodeStart + 1 + id.length, tr.doc.content.size);
|
|
5083
|
-
tr.setSelection(
|
|
5463
|
+
tr.setSelection(TextSelection3.near(tr.doc.resolve(cursorPos)));
|
|
5084
5464
|
tr.setMeta(jumpPointEditKey, { from: nodeStart, to: nodeStart + rawText.length });
|
|
5085
5465
|
return tr;
|
|
5086
5466
|
}
|
|
@@ -5129,21 +5509,30 @@ function createJumpPointAdjacentPlugin() {
|
|
|
5129
5509
|
// src/ui/plugin/jumpPointNodeViewPlugin.tsx
|
|
5130
5510
|
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
5131
5511
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
5512
|
+
function IconDiamondAlert({ size = 12, fill = "#D9352C" }) {
|
|
5513
|
+
return /* @__PURE__ */ jsxs3("svg", { width: size, height: size, viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
5514
|
+
/* @__PURE__ */ jsx4(
|
|
5515
|
+
"path",
|
|
5516
|
+
{
|
|
5517
|
+
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",
|
|
5518
|
+
fill
|
|
5519
|
+
}
|
|
5520
|
+
),
|
|
5521
|
+
/* @__PURE__ */ jsx4("path", { d: "M6 3.5v3", stroke: "#fff", strokeWidth: "1.2", strokeLinecap: "round" }),
|
|
5522
|
+
/* @__PURE__ */ jsx4("circle", { cx: "6", cy: "8.25", r: "0.625", fill: "#fff" })
|
|
5523
|
+
] });
|
|
5524
|
+
}
|
|
5132
5525
|
var JUMP_POINT_STYLE = {
|
|
5133
5526
|
display: "inline-flex",
|
|
5134
5527
|
alignItems: "center",
|
|
5135
5528
|
backgroundColor: "#FFF2B6",
|
|
5136
5529
|
border: "1px solid #FFC233",
|
|
5137
5530
|
color: "#AA5D04",
|
|
5138
|
-
borderRadius: "2px",
|
|
5139
|
-
padding: "2px",
|
|
5140
|
-
fontSize: "12px",
|
|
5141
|
-
lineHeight: "16px",
|
|
5142
5531
|
userSelect: "none",
|
|
5143
5532
|
cursor: "default",
|
|
5144
|
-
boxSizing: "border-box"
|
|
5145
|
-
height
|
|
5146
|
-
|
|
5533
|
+
boxSizing: "border-box"
|
|
5534
|
+
// height, padding, borderRadius, fontSize, lineHeight, overflow
|
|
5535
|
+
// are set via CSS class .ab-jump-point for heading-level overrides
|
|
5147
5536
|
};
|
|
5148
5537
|
var JUMP_POINT_ADJACENT_STYLE = {
|
|
5149
5538
|
...JUMP_POINT_STYLE,
|
|
@@ -5157,8 +5546,8 @@ var JUMP_POINT_DUPLICATE_STYLE = {
|
|
|
5157
5546
|
color: "#9D091E"
|
|
5158
5547
|
};
|
|
5159
5548
|
var LABEL_STYLE = {
|
|
5160
|
-
padding: "0 4px",
|
|
5161
5549
|
whiteSpace: "nowrap"
|
|
5550
|
+
// padding is set via CSS .ab-jp-label for heading-level overrides
|
|
5162
5551
|
};
|
|
5163
5552
|
var CLOSE_BTN_STYLE = {
|
|
5164
5553
|
display: "inline-flex",
|
|
@@ -5189,7 +5578,7 @@ var TOOLTIP_STYLE = {
|
|
|
5189
5578
|
fontSize: "14px",
|
|
5190
5579
|
lineHeight: "20px",
|
|
5191
5580
|
color: "#0D0D0D",
|
|
5192
|
-
|
|
5581
|
+
maxWidth: "240px",
|
|
5193
5582
|
zIndex: 100,
|
|
5194
5583
|
pointerEvents: "none"
|
|
5195
5584
|
};
|
|
@@ -5209,13 +5598,14 @@ function JumpPointNodeViewComponent({ node, view, getPos, decorations }) {
|
|
|
5209
5598
|
return /* @__PURE__ */ jsxs3(
|
|
5210
5599
|
"span",
|
|
5211
5600
|
{
|
|
5601
|
+
className: "ab-jump-point ab-jump-point-duplicate",
|
|
5212
5602
|
style: { ...JUMP_POINT_DUPLICATE_STYLE, position: "relative" },
|
|
5213
5603
|
id: `jp-${id}`,
|
|
5214
5604
|
onMouseEnter: () => setShowTooltip(true),
|
|
5215
5605
|
onMouseLeave: () => setShowTooltip(false),
|
|
5216
5606
|
children: [
|
|
5217
|
-
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#9D091E", style: { paddingLeft: "2px", flexShrink: 0 } }),
|
|
5218
|
-
/* @__PURE__ */ jsx4("span", { style: LABEL_STYLE, children: id }),
|
|
5607
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-icon", children: /* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#9D091E", style: { paddingLeft: "2px", flexShrink: 0 } }) }),
|
|
5608
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-label", style: LABEL_STYLE, children: id }),
|
|
5219
5609
|
/* @__PURE__ */ jsx4(
|
|
5220
5610
|
"button",
|
|
5221
5611
|
{
|
|
@@ -5225,8 +5615,8 @@ function JumpPointNodeViewComponent({ node, view, getPos, decorations }) {
|
|
|
5225
5615
|
e.stopPropagation();
|
|
5226
5616
|
handleDelete2();
|
|
5227
5617
|
},
|
|
5228
|
-
title: "Remove anchor",
|
|
5229
|
-
children: "
|
|
5618
|
+
title: "Remove duplicate anchor",
|
|
5619
|
+
children: /* @__PURE__ */ jsx4(IconDiamondAlert, { size: 12, fill: "#D9352C" })
|
|
5230
5620
|
}
|
|
5231
5621
|
),
|
|
5232
5622
|
showTooltip && /* @__PURE__ */ jsxs3("span", { style: TOOLTIP_STYLE, children: [
|
|
@@ -5239,14 +5629,14 @@ function JumpPointNodeViewComponent({ node, view, getPos, decorations }) {
|
|
|
5239
5629
|
);
|
|
5240
5630
|
}
|
|
5241
5631
|
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}^` })
|
|
5632
|
+
return /* @__PURE__ */ jsxs3("span", { className: "ab-jump-point ab-jump-point-adjacent", style: JUMP_POINT_ADJACENT_STYLE, id: `jp-${id}`, children: [
|
|
5633
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-icon", children: /* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }) }),
|
|
5634
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-label", style: LABEL_STYLE, children: `^${id}^` })
|
|
5245
5635
|
] });
|
|
5246
5636
|
}
|
|
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 })
|
|
5637
|
+
return /* @__PURE__ */ jsxs3("span", { className: "ab-jump-point", style: JUMP_POINT_STYLE, id: `jp-${id}`, children: [
|
|
5638
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-icon", children: /* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }) }),
|
|
5639
|
+
/* @__PURE__ */ jsx4("span", { className: "ab-jp-label", style: LABEL_STYLE, children: id })
|
|
5250
5640
|
] });
|
|
5251
5641
|
}
|
|
5252
5642
|
function createJumpPointNodeViewPlugin() {
|
|
@@ -5544,6 +5934,7 @@ function createJinjaDecorationPlugin() {
|
|
|
5544
5934
|
// src/ui/plugin/jinjaIfBlockPlugin.tsx
|
|
5545
5935
|
import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
5546
5936
|
import { createRoot as createRoot2 } from "react-dom/client";
|
|
5937
|
+
import { TextSelection as TextSelection4 } from "prosemirror-state";
|
|
5547
5938
|
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
5548
5939
|
var PLACEHOLDER_TEXT = "Describe what AI agent should do when this condition is met";
|
|
5549
5940
|
var CONDITION_PLACEHOLDER = "Write a condition in natural language";
|
|
@@ -5950,7 +6341,12 @@ function insertNewBranch(view, nodePos, branchType, condition = "") {
|
|
|
5950
6341
|
const newBranch = createBranchNode(view.state.schema, branchType, condition);
|
|
5951
6342
|
if (!newBranch) return false;
|
|
5952
6343
|
const insertPos = context.branchPos + context.branchNode.nodeSize;
|
|
5953
|
-
view.
|
|
6344
|
+
const tr = view.state.tr.insert(insertPos, newBranch);
|
|
6345
|
+
const cursorPos = insertPos + 2;
|
|
6346
|
+
if (cursorPos <= tr.doc.content.size) {
|
|
6347
|
+
tr.setSelection(TextSelection4.near(tr.doc.resolve(cursorPos)));
|
|
6348
|
+
}
|
|
6349
|
+
view.dispatch(tr.scrollIntoView());
|
|
5954
6350
|
view.focus();
|
|
5955
6351
|
return true;
|
|
5956
6352
|
}
|
|
@@ -5997,6 +6393,7 @@ function ConditionDisplay({
|
|
|
5997
6393
|
const [isEditing, setIsEditing] = useState3(false);
|
|
5998
6394
|
const [draftValue, setDraftValue] = useState3(condition);
|
|
5999
6395
|
const inputRef = useRef2(null);
|
|
6396
|
+
const autoFocusedRef = useRef2(false);
|
|
6000
6397
|
useEffect2(() => {
|
|
6001
6398
|
if (!isEditing) {
|
|
6002
6399
|
setDraftValue(condition);
|
|
@@ -6008,6 +6405,12 @@ function ConditionDisplay({
|
|
|
6008
6405
|
inputRef.current?.select();
|
|
6009
6406
|
}
|
|
6010
6407
|
}, [isEditing]);
|
|
6408
|
+
useEffect2(() => {
|
|
6409
|
+
if (editable && !condition && !autoFocusedRef.current) {
|
|
6410
|
+
autoFocusedRef.current = true;
|
|
6411
|
+
setIsEditing(true);
|
|
6412
|
+
}
|
|
6413
|
+
}, []);
|
|
6011
6414
|
if (branchType === "else") {
|
|
6012
6415
|
return /* @__PURE__ */ jsx6("span", { className: "jinja-otherwise", children: "Otherwise" });
|
|
6013
6416
|
}
|
|
@@ -6197,7 +6600,7 @@ function JinjaBranchHeader({
|
|
|
6197
6600
|
) : null
|
|
6198
6601
|
] }) : null
|
|
6199
6602
|
] }),
|
|
6200
|
-
isLastBranch ? /* @__PURE__ */ jsx6("div", { className: "jinja-add-footer", children: /* @__PURE__ */ jsx6("div", { className: "jinja-add-footer-col", children: /* @__PURE__ */ jsxs5("div", { className: "jinja-add-footer-actions", ref: footerRef, children: [
|
|
6603
|
+
isLastBranch && editable ? /* @__PURE__ */ jsx6("div", { className: "jinja-add-footer", children: /* @__PURE__ */ jsx6("div", { className: "jinja-add-footer-col", children: /* @__PURE__ */ jsxs5("div", { className: "jinja-add-footer-actions", ref: footerRef, children: [
|
|
6201
6604
|
/* @__PURE__ */ jsx6(
|
|
6202
6605
|
"button",
|
|
6203
6606
|
{
|
|
@@ -6303,15 +6706,25 @@ var JinjaIfBranchView = class {
|
|
|
6303
6706
|
}
|
|
6304
6707
|
render() {
|
|
6305
6708
|
const nodePos = this.getPos();
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6709
|
+
let context = null;
|
|
6710
|
+
let lastBranch = null;
|
|
6711
|
+
if (nodePos != null) {
|
|
6712
|
+
context = getBranchContext(this.view, nodePos);
|
|
6713
|
+
lastBranch = getLastBranchOfBlock(this.view, nodePos);
|
|
6714
|
+
let branchIdx = context?.branchIndex ?? -1;
|
|
6715
|
+
if (branchIdx < 0 && this.dom.parentElement) {
|
|
6716
|
+
const siblings = this.dom.parentElement.querySelectorAll(":scope > [data-jinja-branch]");
|
|
6717
|
+
branchIdx = Array.prototype.indexOf.call(siblings, this.dom);
|
|
6718
|
+
}
|
|
6719
|
+
if (branchIdx >= 0) {
|
|
6720
|
+
this.dom.setAttribute("data-branch-index", String(branchIdx));
|
|
6721
|
+
}
|
|
6722
|
+
}
|
|
6310
6723
|
const branchType = this.node.attrs.branchType;
|
|
6311
6724
|
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;
|
|
6725
|
+
const isLast = context && lastBranch ? lastBranch.index === context.branchIndex : true;
|
|
6726
|
+
const lastNonElseIdx = context ? getLastNonElseBranchIndex(this.view, nodePos) : 0;
|
|
6727
|
+
const showAddButton = context ? context.branchIndex === lastNonElseIdx : true;
|
|
6315
6728
|
this.dom.classList.toggle("jinja-branch-last", isLast);
|
|
6316
6729
|
this.root.render(
|
|
6317
6730
|
/* @__PURE__ */ jsx6(
|
|
@@ -6321,16 +6734,19 @@ var JinjaIfBranchView = class {
|
|
|
6321
6734
|
condition,
|
|
6322
6735
|
editable: this.view.editable,
|
|
6323
6736
|
isLastBranch: showAddButton,
|
|
6324
|
-
hasElseBranch: getElseBranch(this.view, nodePos),
|
|
6737
|
+
hasElseBranch: context && nodePos != null ? getElseBranch(this.view, nodePos) : false,
|
|
6325
6738
|
onConditionChange: (value) => {
|
|
6326
6739
|
const currentPos = this.getPos();
|
|
6327
6740
|
if (currentPos == null) return;
|
|
6328
|
-
this.view.
|
|
6329
|
-
this.
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
)
|
|
6741
|
+
const tr = this.view.state.tr.setNodeMarkup(currentPos, void 0, {
|
|
6742
|
+
...this.node.attrs,
|
|
6743
|
+
condition: value
|
|
6744
|
+
});
|
|
6745
|
+
const contentPos = currentPos + 2;
|
|
6746
|
+
if (contentPos <= tr.doc.content.size) {
|
|
6747
|
+
tr.setSelection(TextSelection4.near(tr.doc.resolve(contentPos)));
|
|
6748
|
+
}
|
|
6749
|
+
this.view.dispatch(tr.scrollIntoView());
|
|
6334
6750
|
this.view.focus();
|
|
6335
6751
|
},
|
|
6336
6752
|
onDelete: () => {
|
|
@@ -6359,7 +6775,7 @@ var JinjaIfBranchView = class {
|
|
|
6359
6775
|
return target != null && this.headerContainer.contains(target);
|
|
6360
6776
|
}
|
|
6361
6777
|
ignoreMutation(mutation) {
|
|
6362
|
-
return this.headerContainer.contains(mutation.target);
|
|
6778
|
+
return mutation.target === this.dom || this.headerContainer.contains(mutation.target);
|
|
6363
6779
|
}
|
|
6364
6780
|
destroy() {
|
|
6365
6781
|
if (this._onSiblingsChanged) {
|
|
@@ -6381,9 +6797,9 @@ function createJinjaIfBlockPlugin() {
|
|
|
6381
6797
|
|
|
6382
6798
|
// src/ui/plugin/linkPlugin.ts
|
|
6383
6799
|
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 =
|
|
6800
|
+
import { Plugin as Plugin5, PluginKey as PluginKey5, TextSelection as TextSelection5 } from "prosemirror-state";
|
|
6801
|
+
var LINK_INPUT_RE = /\\?\[([^\]]*?)\\?\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
|
|
6802
|
+
var LINK_FULL_RE = /^\\?\[([^\]]*?)\\?\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
|
|
6387
6803
|
var linkEditKey = new PluginKey5("linkEdit");
|
|
6388
6804
|
function getMarkRange($pos, type) {
|
|
6389
6805
|
const { parentOffset } = $pos;
|
|
@@ -6427,7 +6843,7 @@ function explodeLinkToRaw(state) {
|
|
|
6427
6843
|
const tr = state.tr;
|
|
6428
6844
|
tr.replaceWith(from, to, schema.text(rawText));
|
|
6429
6845
|
const newPos = Math.min(from + rawCursorOffset, tr.doc.content.size);
|
|
6430
|
-
tr.setSelection(
|
|
6846
|
+
tr.setSelection(TextSelection5.near(tr.doc.resolve(newPos)));
|
|
6431
6847
|
tr.setMeta(linkEditKey, { from, to: from + rawText.length });
|
|
6432
6848
|
return tr;
|
|
6433
6849
|
}
|
|
@@ -6440,8 +6856,8 @@ function createLinkEditPlugin() {
|
|
|
6440
6856
|
const meta = tr.getMeta(linkEditKey);
|
|
6441
6857
|
if (meta !== void 0) return { rawRange: meta };
|
|
6442
6858
|
if (prev.rawRange) {
|
|
6443
|
-
const from = tr.mapping.map(prev.rawRange.from);
|
|
6444
|
-
const to = tr.mapping.map(prev.rawRange.to);
|
|
6859
|
+
const from = tr.mapping.map(prev.rawRange.from, -1);
|
|
6860
|
+
const to = tr.mapping.map(prev.rawRange.to, -1);
|
|
6445
6861
|
if (from >= to) return { rawRange: null };
|
|
6446
6862
|
return { rawRange: { from, to } };
|
|
6447
6863
|
}
|
|
@@ -6452,7 +6868,7 @@ function createLinkEditPlugin() {
|
|
|
6452
6868
|
const pluginState = linkEditKey.getState(newState);
|
|
6453
6869
|
if (!pluginState?.rawRange) return null;
|
|
6454
6870
|
const { from, to } = pluginState.rawRange;
|
|
6455
|
-
if (newState.selection.anchor >= from && newState.selection.anchor
|
|
6871
|
+
if (newState.selection.anchor >= from && newState.selection.anchor < to) {
|
|
6456
6872
|
return null;
|
|
6457
6873
|
}
|
|
6458
6874
|
const docSize = newState.doc.content.size;
|
|
@@ -6596,12 +7012,13 @@ var STYLES = (
|
|
|
6596
7012
|
cursor: grab;
|
|
6597
7013
|
color: transparent;
|
|
6598
7014
|
border-radius: var(--ab-dh-handle-radius);
|
|
6599
|
-
transition:
|
|
7015
|
+
transition: none;
|
|
6600
7016
|
user-select: none;
|
|
6601
7017
|
pointer-events: auto;
|
|
6602
7018
|
touch-action: none;
|
|
6603
7019
|
opacity: 0;
|
|
6604
7020
|
pointer-events: none;
|
|
7021
|
+
overflow: visible;
|
|
6605
7022
|
}
|
|
6606
7023
|
.ab-drag-handle.ab-dh-active {
|
|
6607
7024
|
opacity: 1;
|
|
@@ -6612,6 +7029,72 @@ var STYLES = (
|
|
|
6612
7029
|
color: var(--ab-dh-color-visible) !important;
|
|
6613
7030
|
background: var(--ab-dh-bg-hover);
|
|
6614
7031
|
}
|
|
7032
|
+
.ab-drag-handle:hover::after {
|
|
7033
|
+
content: 'Drag to move';
|
|
7034
|
+
position: absolute;
|
|
7035
|
+
bottom: calc(100% + 4px);
|
|
7036
|
+
left: 0;
|
|
7037
|
+
background: #2e2e2e;
|
|
7038
|
+
color: #fff;
|
|
7039
|
+
font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
7040
|
+
font-size: 12px;
|
|
7041
|
+
font-weight: 400;
|
|
7042
|
+
line-height: 16px;
|
|
7043
|
+
padding: 4px 8px;
|
|
7044
|
+
border-radius: 4px;
|
|
7045
|
+
white-space: nowrap;
|
|
7046
|
+
pointer-events: none;
|
|
7047
|
+
z-index: 30;
|
|
7048
|
+
}
|
|
7049
|
+
.ab-drag-handle:hover::before {
|
|
7050
|
+
content: '';
|
|
7051
|
+
position: absolute;
|
|
7052
|
+
bottom: calc(100% + 0px);
|
|
7053
|
+
left: 8px;
|
|
7054
|
+
width: 0;
|
|
7055
|
+
height: 0;
|
|
7056
|
+
border-left: 5px solid transparent;
|
|
7057
|
+
border-right: 5px solid transparent;
|
|
7058
|
+
border-top: 5px solid #2e2e2e;
|
|
7059
|
+
pointer-events: none;
|
|
7060
|
+
z-index: 31;
|
|
7061
|
+
}
|
|
7062
|
+
.ab-drag-handle.dragging::after,
|
|
7063
|
+
.ab-drag-handle.dragging::before {
|
|
7064
|
+
display: none;
|
|
7065
|
+
}
|
|
7066
|
+
.ab-dh-menu {
|
|
7067
|
+
position: absolute;
|
|
7068
|
+
top: calc(100% + 4px);
|
|
7069
|
+
left: 0;
|
|
7070
|
+
background: #fff;
|
|
7071
|
+
border-radius: 4px;
|
|
7072
|
+
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);
|
|
7073
|
+
padding: 8px 0;
|
|
7074
|
+
z-index: 40;
|
|
7075
|
+
min-width: 120px;
|
|
7076
|
+
}
|
|
7077
|
+
.ab-dh-menu-item {
|
|
7078
|
+
display: flex;
|
|
7079
|
+
align-items: center;
|
|
7080
|
+
width: 100%;
|
|
7081
|
+
padding: 6px 16px;
|
|
7082
|
+
border: none;
|
|
7083
|
+
background: #fff;
|
|
7084
|
+
cursor: pointer;
|
|
7085
|
+
font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
7086
|
+
font-size: 14px;
|
|
7087
|
+
font-weight: 400;
|
|
7088
|
+
line-height: 20px;
|
|
7089
|
+
letter-spacing: -0.1px;
|
|
7090
|
+
color: #0d0d0d;
|
|
7091
|
+
white-space: nowrap;
|
|
7092
|
+
text-overflow: ellipsis;
|
|
7093
|
+
overflow: hidden;
|
|
7094
|
+
}
|
|
7095
|
+
.ab-dh-menu-item:hover {
|
|
7096
|
+
background: rgba(0,0,0,0.04);
|
|
7097
|
+
}
|
|
6615
7098
|
.ab-drag-handle:active, .ab-drag-handle.dragging {
|
|
6616
7099
|
cursor: grabbing;
|
|
6617
7100
|
color: var(--ab-dh-color-accent) !important;
|
|
@@ -6921,7 +7404,6 @@ var DragHandleController = class {
|
|
|
6921
7404
|
el.setAttribute("role", "button");
|
|
6922
7405
|
el.setAttribute("aria-roledescription", "drag handle");
|
|
6923
7406
|
el.setAttribute("aria-label", `\uBE14\uB85D ${idx + 1} \uC774\uB3D9`);
|
|
6924
|
-
el.setAttribute("title", "Drag to move");
|
|
6925
7407
|
el.setAttribute("tabindex", "-1");
|
|
6926
7408
|
el.innerHTML = GRIP_SVG;
|
|
6927
7409
|
el.style.left = `${handleLeft}px`;
|
|
@@ -6934,18 +7416,85 @@ var DragHandleController = class {
|
|
|
6934
7416
|
this.prevBlocks = newBlocks;
|
|
6935
7417
|
this.updateActiveHandle();
|
|
6936
7418
|
}
|
|
7419
|
+
activeMenu = null;
|
|
7420
|
+
activeMenuCleanup = null;
|
|
7421
|
+
dismissMenu() {
|
|
7422
|
+
if (this.activeMenu) {
|
|
7423
|
+
this.activeMenu.remove();
|
|
7424
|
+
this.activeMenu = null;
|
|
7425
|
+
}
|
|
7426
|
+
if (this.activeMenuCleanup) {
|
|
7427
|
+
this.activeMenuCleanup();
|
|
7428
|
+
this.activeMenuCleanup = null;
|
|
7429
|
+
}
|
|
7430
|
+
}
|
|
7431
|
+
showMenu(el, blockIndex) {
|
|
7432
|
+
this.dismissMenu();
|
|
7433
|
+
const menu = document.createElement("div");
|
|
7434
|
+
menu.className = "ab-dh-menu";
|
|
7435
|
+
const deleteBtn = document.createElement("button");
|
|
7436
|
+
deleteBtn.className = "ab-dh-menu-item";
|
|
7437
|
+
deleteBtn.textContent = "Delete";
|
|
7438
|
+
deleteBtn.addEventListener("mousedown", (e) => {
|
|
7439
|
+
e.preventDefault();
|
|
7440
|
+
e.stopPropagation();
|
|
7441
|
+
this.deleteBlock(blockIndex);
|
|
7442
|
+
this.dismissMenu();
|
|
7443
|
+
});
|
|
7444
|
+
menu.appendChild(deleteBtn);
|
|
7445
|
+
el.appendChild(menu);
|
|
7446
|
+
this.activeMenu = menu;
|
|
7447
|
+
const onOutside = (e) => {
|
|
7448
|
+
if (!menu.contains(e.target)) {
|
|
7449
|
+
this.dismissMenu();
|
|
7450
|
+
}
|
|
7451
|
+
};
|
|
7452
|
+
setTimeout(() => document.addEventListener("mousedown", onOutside, true), 0);
|
|
7453
|
+
this.activeMenuCleanup = () => document.removeEventListener("mousedown", onOutside, true);
|
|
7454
|
+
}
|
|
7455
|
+
deleteBlock(blockIndex) {
|
|
7456
|
+
const blocks = this.collectBlocks();
|
|
7457
|
+
if (blockIndex >= blocks.length) return;
|
|
7458
|
+
const block = blocks[blockIndex];
|
|
7459
|
+
const from = block.offset;
|
|
7460
|
+
const to = block.offset + block.nodeSize;
|
|
7461
|
+
const tr = this.view.state.tr;
|
|
7462
|
+
tr.replaceWith(from, to, this.view.state.schema.nodes.paragraph.create());
|
|
7463
|
+
this.view.dispatch(tr);
|
|
7464
|
+
this.view.focus();
|
|
7465
|
+
}
|
|
6937
7466
|
bindHandleEvents(el, index) {
|
|
6938
7467
|
let currentIndex = index;
|
|
7468
|
+
let downX = 0;
|
|
7469
|
+
let downY = 0;
|
|
7470
|
+
let didDrag = false;
|
|
7471
|
+
let menuWasOpen = false;
|
|
6939
7472
|
const onPointerDown = (e) => {
|
|
7473
|
+
if (this.activeMenu && this.activeMenu.contains(e.target)) return;
|
|
6940
7474
|
e.preventDefault();
|
|
6941
7475
|
if (!this.view.editable) return;
|
|
7476
|
+
menuWasOpen = !!this.activeMenu;
|
|
7477
|
+
this.dismissMenu();
|
|
7478
|
+
downX = e.clientX;
|
|
7479
|
+
downY = e.clientY;
|
|
7480
|
+
didDrag = false;
|
|
6942
7481
|
el.setPointerCapture(e.pointerId);
|
|
6943
7482
|
this.prevBlocks = this.collectBlocks();
|
|
6944
7483
|
this.syncHandlePositions();
|
|
6945
7484
|
this.startDrag(currentIndex, el, e);
|
|
6946
7485
|
};
|
|
6947
|
-
const onPointerMove = (e) =>
|
|
6948
|
-
|
|
7486
|
+
const onPointerMove = (e) => {
|
|
7487
|
+
if (Math.abs(e.clientX - downX) > 3 || Math.abs(e.clientY - downY) > 3) {
|
|
7488
|
+
didDrag = true;
|
|
7489
|
+
}
|
|
7490
|
+
this.onPointerMove(e);
|
|
7491
|
+
};
|
|
7492
|
+
const onPointerUp = (e) => {
|
|
7493
|
+
this.onPointerUp(e);
|
|
7494
|
+
if (!didDrag && !menuWasOpen) {
|
|
7495
|
+
this.showMenu(el, currentIndex);
|
|
7496
|
+
}
|
|
7497
|
+
};
|
|
6949
7498
|
const onLostCapture = () => this.cancelDrag();
|
|
6950
7499
|
const onPointerCancel = () => this.cancelDrag();
|
|
6951
7500
|
el.addEventListener("pointerdown", onPointerDown);
|
|
@@ -7352,150 +7901,89 @@ function createTodoNodeViewPlugin() {
|
|
|
7352
7901
|
};
|
|
7353
7902
|
}
|
|
7354
7903
|
|
|
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;
|
|
7904
|
+
// src/ui/plugin/placeholderPlugin.ts
|
|
7905
|
+
import { Plugin as Plugin7, PluginKey as PluginKey7 } from "prosemirror-state";
|
|
7906
|
+
import { Decoration as Decoration4, DecorationSet as DecorationSet4 } from "prosemirror-view";
|
|
7907
|
+
var PLACEHOLDER_TEXT2 = "Type to start writing, or press / to insert an action.";
|
|
7908
|
+
var pluginKey2 = new PluginKey7("placeholder");
|
|
7909
|
+
function buildDecorations4(state) {
|
|
7910
|
+
const { doc: doc2, selection } = state;
|
|
7911
|
+
if (!selection.empty) return DecorationSet4.empty;
|
|
7912
|
+
const $from = selection.$from;
|
|
7913
|
+
const parent = $from.parent;
|
|
7914
|
+
if (parent.type.name !== "paragraph" || parent.content.size !== 0) {
|
|
7915
|
+
return DecorationSet4.empty;
|
|
7436
7916
|
}
|
|
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;
|
|
7917
|
+
const EXCLUDED_ANCESTORS = /* @__PURE__ */ new Set(["noteBlock", "blockquote", "jinjaIfBranch"]);
|
|
7918
|
+
for (let d = $from.depth - 1; d > 0; d--) {
|
|
7919
|
+
if (EXCLUDED_ANCESTORS.has($from.node(d).type.name)) {
|
|
7920
|
+
return DecorationSet4.empty;
|
|
7452
7921
|
}
|
|
7453
7922
|
}
|
|
7454
|
-
const
|
|
7455
|
-
const
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
return
|
|
7460
|
-
}
|
|
7461
|
-
function
|
|
7923
|
+
const pos = $from.before($from.depth);
|
|
7924
|
+
const deco = Decoration4.node(pos, pos + parent.nodeSize, {
|
|
7925
|
+
class: "ab-empty-paragraph",
|
|
7926
|
+
"data-placeholder": PLACEHOLDER_TEXT2
|
|
7927
|
+
});
|
|
7928
|
+
return DecorationSet4.create(doc2, [deco]);
|
|
7929
|
+
}
|
|
7930
|
+
function createPlaceholderPlugin() {
|
|
7462
7931
|
return {
|
|
7463
|
-
name: "
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7932
|
+
name: "placeholder",
|
|
7933
|
+
plugins: () => [
|
|
7934
|
+
new Plugin7({
|
|
7935
|
+
key: pluginKey2,
|
|
7936
|
+
state: {
|
|
7937
|
+
init(_, state) {
|
|
7938
|
+
return buildDecorations4(state);
|
|
7939
|
+
},
|
|
7940
|
+
apply(tr, oldSet, _oldState, newState) {
|
|
7941
|
+
if (tr.docChanged || tr.selectionSet) {
|
|
7942
|
+
return buildDecorations4(newState);
|
|
7943
|
+
}
|
|
7944
|
+
return oldSet;
|
|
7945
|
+
}
|
|
7946
|
+
},
|
|
7947
|
+
props: {
|
|
7948
|
+
decorations(state) {
|
|
7949
|
+
return pluginKey2.getState(state) ?? DecorationSet4.empty;
|
|
7950
|
+
}
|
|
7951
|
+
}
|
|
7952
|
+
})
|
|
7953
|
+
]
|
|
7470
7954
|
};
|
|
7471
7955
|
}
|
|
7472
7956
|
|
|
7473
7957
|
// src/ui/plugin/slashCommandPlugin.ts
|
|
7474
|
-
import { Plugin as
|
|
7475
|
-
var slashCommandKey = new
|
|
7958
|
+
import { Plugin as Plugin8, PluginKey as PluginKey8 } from "prosemirror-state";
|
|
7959
|
+
var slashCommandKey = new PluginKey8("slashCommand");
|
|
7476
7960
|
var TRIGGER_RE = /(?:^|\s)(\/[^\s]*)$/;
|
|
7477
7961
|
function deriveState(state, dismissedFrom) {
|
|
7962
|
+
const inactive = { active: false, range: null, query: "", parentType: "" };
|
|
7478
7963
|
const { selection } = state;
|
|
7479
|
-
if (!selection.empty) return
|
|
7964
|
+
if (!selection.empty) return inactive;
|
|
7480
7965
|
const { $from } = selection;
|
|
7481
7966
|
const parentType = $from.parent.type.name;
|
|
7482
|
-
|
|
7967
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
7968
|
+
if ($from.node(d).type.name === "noteBlock") return inactive;
|
|
7969
|
+
}
|
|
7483
7970
|
const textBefore = $from.parent.textBetween(0, $from.parentOffset, "\n", "\0");
|
|
7484
7971
|
const match = TRIGGER_RE.exec(textBefore);
|
|
7485
|
-
if (!match) return
|
|
7972
|
+
if (!match) return inactive;
|
|
7486
7973
|
const slashText = match[1];
|
|
7487
7974
|
const slashStartInParent = textBefore.lastIndexOf(slashText);
|
|
7488
7975
|
const from = $from.start() + slashStartInParent;
|
|
7489
7976
|
const to = $from.pos;
|
|
7490
|
-
if (dismissedFrom === from) return
|
|
7977
|
+
if (dismissedFrom === from) return inactive;
|
|
7491
7978
|
return {
|
|
7492
7979
|
active: true,
|
|
7493
7980
|
range: { from, to },
|
|
7494
|
-
query: slashText.slice(1)
|
|
7981
|
+
query: slashText.slice(1),
|
|
7982
|
+
parentType
|
|
7495
7983
|
};
|
|
7496
7984
|
}
|
|
7497
7985
|
function createSlashCommandPlugin() {
|
|
7498
|
-
const plugin = new
|
|
7986
|
+
const plugin = new Plugin8({
|
|
7499
7987
|
key: slashCommandKey,
|
|
7500
7988
|
state: {
|
|
7501
7989
|
init(_, state) {
|
|
@@ -8013,6 +8501,7 @@ function DocumentTreeView({ doc: doc2, className, onNavigate }) {
|
|
|
8013
8501
|
// src/ui/components/FloatingMenu.tsx
|
|
8014
8502
|
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
|
|
8015
8503
|
import { createPortal as createPortal2 } from "react-dom";
|
|
8504
|
+
import { TextSelection as TextSelection6 } from "prosemirror-state";
|
|
8016
8505
|
import { setBlockType as setBlockType2, toggleMark as toggleMark2, wrapIn } from "prosemirror-commands";
|
|
8017
8506
|
import { wrapInList as wrapInList2 } from "prosemirror-schema-list";
|
|
8018
8507
|
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
@@ -8035,6 +8524,56 @@ function hasMark(state, type) {
|
|
|
8035
8524
|
if (empty) return false;
|
|
8036
8525
|
return state.doc.rangeHasMark(from, to, type);
|
|
8037
8526
|
}
|
|
8527
|
+
function getMarkRange2($pos, type) {
|
|
8528
|
+
const { parentOffset } = $pos;
|
|
8529
|
+
let child = $pos.parent.childAfter(parentOffset);
|
|
8530
|
+
if (parentOffset === child.offset && child.offset !== 0) {
|
|
8531
|
+
child = $pos.parent.childBefore(parentOffset);
|
|
8532
|
+
}
|
|
8533
|
+
if (!child.node) return null;
|
|
8534
|
+
const mark = child.node.marks.find((candidate) => candidate.type === type);
|
|
8535
|
+
if (!mark) return null;
|
|
8536
|
+
const parentStart = $pos.start();
|
|
8537
|
+
let { index: startIndex } = child;
|
|
8538
|
+
let startPos = parentStart + child.offset;
|
|
8539
|
+
let endIndex = startIndex + 1;
|
|
8540
|
+
let endPos = startPos + child.node.nodeSize;
|
|
8541
|
+
while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
|
|
8542
|
+
startIndex -= 1;
|
|
8543
|
+
startPos -= $pos.parent.child(startIndex).nodeSize;
|
|
8544
|
+
}
|
|
8545
|
+
while (endIndex < $pos.parent.childCount && mark.isInSet($pos.parent.child(endIndex).marks)) {
|
|
8546
|
+
endPos += $pos.parent.child(endIndex).nodeSize;
|
|
8547
|
+
endIndex += 1;
|
|
8548
|
+
}
|
|
8549
|
+
return { from: startPos, to: endPos, mark };
|
|
8550
|
+
}
|
|
8551
|
+
function getLinkAtCursor(state) {
|
|
8552
|
+
const { selection, doc: doc2 } = state;
|
|
8553
|
+
if (!selection.empty) return null;
|
|
8554
|
+
const range = getMarkRange2(doc2.resolve(selection.from), linkMark);
|
|
8555
|
+
if (!range) return null;
|
|
8556
|
+
return {
|
|
8557
|
+
href: range.mark.attrs.href || "",
|
|
8558
|
+
text: doc2.textBetween(range.from, range.to),
|
|
8559
|
+
from: range.from,
|
|
8560
|
+
to: range.to
|
|
8561
|
+
};
|
|
8562
|
+
}
|
|
8563
|
+
function normalizeLinkHref(href) {
|
|
8564
|
+
const trimmedHref = href.trim();
|
|
8565
|
+
if (!trimmedHref) return "";
|
|
8566
|
+
return trimmedHref.startsWith("#") || trimmedHref.startsWith("/") || /^https?:\/\//i.test(trimmedHref) ? trimmedHref : `https://${trimmedHref}`;
|
|
8567
|
+
}
|
|
8568
|
+
function getNonLinkMarksInRange(state, from, to) {
|
|
8569
|
+
let marks = [];
|
|
8570
|
+
state.doc.nodesBetween(from, to, (node) => {
|
|
8571
|
+
if (!node.isText) return;
|
|
8572
|
+
marks = node.marks.filter((mark) => mark.type !== linkMark);
|
|
8573
|
+
return false;
|
|
8574
|
+
});
|
|
8575
|
+
return marks;
|
|
8576
|
+
}
|
|
8038
8577
|
function activeHeadingLevel(state) {
|
|
8039
8578
|
const { $from } = state.selection;
|
|
8040
8579
|
const node = $from.parent;
|
|
@@ -8497,6 +9036,408 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
8497
9036
|
}
|
|
8498
9037
|
);
|
|
8499
9038
|
}
|
|
9039
|
+
function LinkHoverTooltip({ view, link: link2, onEdit }) {
|
|
9040
|
+
const [hover, setHover] = useState7(false);
|
|
9041
|
+
const startCoords = view.coordsAtPos(link2.from);
|
|
9042
|
+
const endCoords = view.coordsAtPos(link2.to);
|
|
9043
|
+
const anchorTop = Math.min(startCoords.top, endCoords.top);
|
|
9044
|
+
const linkLeft = Math.min(startCoords.left, endCoords.left);
|
|
9045
|
+
const linkRight = Math.max(startCoords.right, endCoords.right);
|
|
9046
|
+
const tooltipHalfW = Math.min(174, Math.max(0, (window.innerWidth - VPORT_MARGIN2 * 2) / 2));
|
|
9047
|
+
const safeCenterX = Math.max(
|
|
9048
|
+
VPORT_MARGIN2 + tooltipHalfW,
|
|
9049
|
+
Math.min((linkLeft + linkRight) / 2, window.innerWidth - VPORT_MARGIN2 - tooltipHalfW)
|
|
9050
|
+
);
|
|
9051
|
+
return createPortal2(
|
|
9052
|
+
/* @__PURE__ */ jsxs9(
|
|
9053
|
+
"div",
|
|
9054
|
+
{
|
|
9055
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9056
|
+
style: {
|
|
9057
|
+
position: "fixed",
|
|
9058
|
+
left: safeCenterX,
|
|
9059
|
+
top: Math.max(64, anchorTop - 4),
|
|
9060
|
+
transform: "translate(-50%, -100%)",
|
|
9061
|
+
zIndex: 1e3,
|
|
9062
|
+
display: "flex",
|
|
9063
|
+
flexDirection: "column",
|
|
9064
|
+
alignItems: "center",
|
|
9065
|
+
animation: "ab-float-in 0.12s ease",
|
|
9066
|
+
pointerEvents: "auto"
|
|
9067
|
+
},
|
|
9068
|
+
children: [
|
|
9069
|
+
/* @__PURE__ */ jsxs9(
|
|
9070
|
+
"div",
|
|
9071
|
+
{
|
|
9072
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9073
|
+
style: {
|
|
9074
|
+
display: "flex",
|
|
9075
|
+
alignItems: "center",
|
|
9076
|
+
gap: 4,
|
|
9077
|
+
minHeight: 28,
|
|
9078
|
+
maxWidth: "min(348px, calc(100vw - 16px))",
|
|
9079
|
+
padding: "6px 8px",
|
|
9080
|
+
background: "#2E2E2E",
|
|
9081
|
+
borderRadius: 4,
|
|
9082
|
+
boxSizing: "border-box"
|
|
9083
|
+
},
|
|
9084
|
+
children: [
|
|
9085
|
+
/* @__PURE__ */ jsx10(
|
|
9086
|
+
"span",
|
|
9087
|
+
{
|
|
9088
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9089
|
+
style: {
|
|
9090
|
+
color: "#FFFFFF",
|
|
9091
|
+
fontSize: 12,
|
|
9092
|
+
lineHeight: "16px",
|
|
9093
|
+
fontFamily: '"SF Pro Text", "SF Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
9094
|
+
whiteSpace: "normal",
|
|
9095
|
+
wordBreak: "break-word",
|
|
9096
|
+
overflowWrap: "anywhere",
|
|
9097
|
+
maxWidth: 300
|
|
9098
|
+
},
|
|
9099
|
+
children: link2.href
|
|
9100
|
+
}
|
|
9101
|
+
),
|
|
9102
|
+
/* @__PURE__ */ jsx10(
|
|
9103
|
+
"div",
|
|
9104
|
+
{
|
|
9105
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9106
|
+
style: {
|
|
9107
|
+
width: 1,
|
|
9108
|
+
height: 16,
|
|
9109
|
+
background: "#424242",
|
|
9110
|
+
flexShrink: 0
|
|
9111
|
+
}
|
|
9112
|
+
}
|
|
9113
|
+
),
|
|
9114
|
+
/* @__PURE__ */ jsx10(
|
|
9115
|
+
"button",
|
|
9116
|
+
{
|
|
9117
|
+
type: "button",
|
|
9118
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9119
|
+
onMouseDown: (e) => {
|
|
9120
|
+
e.preventDefault();
|
|
9121
|
+
onEdit(link2);
|
|
9122
|
+
},
|
|
9123
|
+
onMouseEnter: () => setHover(true),
|
|
9124
|
+
onMouseLeave: () => setHover(false),
|
|
9125
|
+
style: {
|
|
9126
|
+
...BTN_RESET2,
|
|
9127
|
+
padding: "0 2px",
|
|
9128
|
+
color: "#FFFFFF",
|
|
9129
|
+
fontSize: 12,
|
|
9130
|
+
lineHeight: "16px",
|
|
9131
|
+
fontWeight: 600,
|
|
9132
|
+
fontFamily: '"SF Pro Text", "SF Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
9133
|
+
opacity: hover ? 0.78 : 1,
|
|
9134
|
+
flexShrink: 0
|
|
9135
|
+
},
|
|
9136
|
+
children: "Edit"
|
|
9137
|
+
}
|
|
9138
|
+
)
|
|
9139
|
+
]
|
|
9140
|
+
}
|
|
9141
|
+
),
|
|
9142
|
+
/* @__PURE__ */ jsx10(
|
|
9143
|
+
"div",
|
|
9144
|
+
{
|
|
9145
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9146
|
+
style: {
|
|
9147
|
+
width: 0,
|
|
9148
|
+
height: 0,
|
|
9149
|
+
borderLeft: "6px solid transparent",
|
|
9150
|
+
borderRight: "6px solid transparent",
|
|
9151
|
+
borderTop: "6px solid #2E2E2E",
|
|
9152
|
+
marginTop: -1
|
|
9153
|
+
}
|
|
9154
|
+
}
|
|
9155
|
+
)
|
|
9156
|
+
]
|
|
9157
|
+
}
|
|
9158
|
+
),
|
|
9159
|
+
document.body
|
|
9160
|
+
);
|
|
9161
|
+
}
|
|
9162
|
+
function LinkEditDialog({ view, link: link2, onClose }) {
|
|
9163
|
+
const [textValue, setTextValue] = useState7(link2.text);
|
|
9164
|
+
const [hrefValue, setHrefValue] = useState7(link2.href);
|
|
9165
|
+
const textInputRef = useRef4(null);
|
|
9166
|
+
useEffect4(() => {
|
|
9167
|
+
setTextValue(link2.text);
|
|
9168
|
+
setHrefValue(link2.href);
|
|
9169
|
+
}, [link2.from, link2.href, link2.text, link2.to]);
|
|
9170
|
+
useEffect4(() => {
|
|
9171
|
+
setTimeout(() => textInputRef.current?.focus(), 0);
|
|
9172
|
+
}, [link2.from, link2.to]);
|
|
9173
|
+
useEffect4(() => {
|
|
9174
|
+
const onDown = (e) => {
|
|
9175
|
+
if (!e.target.closest(`[${FLOAT_ATTR}]`)) {
|
|
9176
|
+
onClose();
|
|
9177
|
+
}
|
|
9178
|
+
};
|
|
9179
|
+
document.addEventListener("mousedown", onDown, true);
|
|
9180
|
+
return () => document.removeEventListener("mousedown", onDown, true);
|
|
9181
|
+
}, [onClose]);
|
|
9182
|
+
const startCoords = view.coordsAtPos(link2.from);
|
|
9183
|
+
const endCoords = view.coordsAtPos(link2.to);
|
|
9184
|
+
const anchorTop = Math.min(startCoords.top, endCoords.top);
|
|
9185
|
+
const anchorBottom = Math.max(startCoords.bottom, endCoords.bottom);
|
|
9186
|
+
const linkLeft = Math.min(startCoords.left, endCoords.left);
|
|
9187
|
+
const linkRight = Math.max(startCoords.right, endCoords.right);
|
|
9188
|
+
const dialogW = 280;
|
|
9189
|
+
const estimatedDialogH = 188;
|
|
9190
|
+
const centerX = (linkLeft + linkRight) / 2;
|
|
9191
|
+
const left = Math.max(
|
|
9192
|
+
VPORT_MARGIN2,
|
|
9193
|
+
Math.min(centerX - dialogW / 2, window.innerWidth - dialogW - VPORT_MARGIN2)
|
|
9194
|
+
);
|
|
9195
|
+
let top = anchorTop - estimatedDialogH - 12;
|
|
9196
|
+
if (top < VPORT_MARGIN2) {
|
|
9197
|
+
top = Math.min(anchorBottom + 12, window.innerHeight - estimatedDialogH - VPORT_MARGIN2);
|
|
9198
|
+
}
|
|
9199
|
+
const finalHref = normalizeLinkHref(hrefValue);
|
|
9200
|
+
const finalText = textValue.trim() ? textValue : finalHref;
|
|
9201
|
+
const canSave = Boolean(finalHref) && (finalHref !== link2.href || finalText !== link2.text);
|
|
9202
|
+
const currentLink = () => {
|
|
9203
|
+
const activeLink = getLinkAtCursor(view.state);
|
|
9204
|
+
if (activeLink && activeLink.from === link2.from && activeLink.to === link2.to) {
|
|
9205
|
+
return activeLink;
|
|
9206
|
+
}
|
|
9207
|
+
return link2;
|
|
9208
|
+
};
|
|
9209
|
+
const saveLink = () => {
|
|
9210
|
+
const activeLink = currentLink();
|
|
9211
|
+
const nextHref = normalizeLinkHref(hrefValue);
|
|
9212
|
+
const nextText = textValue.trim() ? textValue : nextHref;
|
|
9213
|
+
if (!nextHref) return;
|
|
9214
|
+
if (nextHref === activeLink.href && nextText === activeLink.text) return;
|
|
9215
|
+
const cursorOffset = Math.max(0, view.state.selection.from - activeLink.from);
|
|
9216
|
+
const tr = view.state.tr;
|
|
9217
|
+
if (nextText === activeLink.text) {
|
|
9218
|
+
tr.removeMark(activeLink.from, activeLink.to, linkMark);
|
|
9219
|
+
tr.addMark(activeLink.from, activeLink.to, linkMark.create({ href: nextHref }));
|
|
9220
|
+
const nextCursor = Math.min(activeLink.from + cursorOffset, activeLink.to);
|
|
9221
|
+
tr.setSelection(TextSelection6.near(tr.doc.resolve(nextCursor)));
|
|
9222
|
+
} else {
|
|
9223
|
+
const preservedMarks = getNonLinkMarksInRange(view.state, activeLink.from, activeLink.to);
|
|
9224
|
+
tr.insertText(nextText, activeLink.from, activeLink.to);
|
|
9225
|
+
const nextTo = activeLink.from + nextText.length;
|
|
9226
|
+
tr.removeMark(activeLink.from, nextTo, linkMark);
|
|
9227
|
+
for (const mark of preservedMarks) {
|
|
9228
|
+
tr.addMark(activeLink.from, nextTo, mark);
|
|
9229
|
+
}
|
|
9230
|
+
tr.addMark(activeLink.from, nextTo, linkMark.create({ href: nextHref }));
|
|
9231
|
+
const nextCursor = Math.min(activeLink.from + cursorOffset, nextTo);
|
|
9232
|
+
tr.setSelection(TextSelection6.near(tr.doc.resolve(nextCursor)));
|
|
9233
|
+
}
|
|
9234
|
+
view.dispatch(tr);
|
|
9235
|
+
onClose();
|
|
9236
|
+
view.focus();
|
|
9237
|
+
};
|
|
9238
|
+
const removeLink = () => {
|
|
9239
|
+
const activeLink = currentLink();
|
|
9240
|
+
view.dispatch(view.state.tr.removeMark(activeLink.from, activeLink.to, linkMark));
|
|
9241
|
+
onClose();
|
|
9242
|
+
view.focus();
|
|
9243
|
+
};
|
|
9244
|
+
const handleKeyDown = (e) => {
|
|
9245
|
+
if (e.key === "Escape") {
|
|
9246
|
+
e.preventDefault();
|
|
9247
|
+
onClose();
|
|
9248
|
+
view.focus();
|
|
9249
|
+
return;
|
|
9250
|
+
}
|
|
9251
|
+
if (e.key === "Enter") {
|
|
9252
|
+
e.preventDefault();
|
|
9253
|
+
saveLink();
|
|
9254
|
+
}
|
|
9255
|
+
};
|
|
9256
|
+
return createPortal2(
|
|
9257
|
+
/* @__PURE__ */ jsxs9(
|
|
9258
|
+
"div",
|
|
9259
|
+
{
|
|
9260
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9261
|
+
style: {
|
|
9262
|
+
position: "fixed",
|
|
9263
|
+
left,
|
|
9264
|
+
top,
|
|
9265
|
+
zIndex: 1001,
|
|
9266
|
+
width: dialogW,
|
|
9267
|
+
display: "flex",
|
|
9268
|
+
flexDirection: "column",
|
|
9269
|
+
gap: 16,
|
|
9270
|
+
padding: 16,
|
|
9271
|
+
background: "#FFFFFF",
|
|
9272
|
+
borderRadius: 4,
|
|
9273
|
+
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)",
|
|
9274
|
+
boxSizing: "border-box",
|
|
9275
|
+
animation: "ab-float-in 0.12s ease"
|
|
9276
|
+
},
|
|
9277
|
+
children: [
|
|
9278
|
+
/* @__PURE__ */ jsxs9("div", { ...{ [FLOAT_ATTR]: "" }, style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
9279
|
+
/* @__PURE__ */ jsxs9(
|
|
9280
|
+
"div",
|
|
9281
|
+
{
|
|
9282
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9283
|
+
style: {
|
|
9284
|
+
fontSize: 12,
|
|
9285
|
+
lineHeight: "16px",
|
|
9286
|
+
fontWeight: 600,
|
|
9287
|
+
color: "#0D0D0D"
|
|
9288
|
+
},
|
|
9289
|
+
children: [
|
|
9290
|
+
"Text ",
|
|
9291
|
+
/* @__PURE__ */ jsx10("span", { style: { color: "#858585" }, children: "(optional)" })
|
|
9292
|
+
]
|
|
9293
|
+
}
|
|
9294
|
+
),
|
|
9295
|
+
/* @__PURE__ */ jsx10(
|
|
9296
|
+
"input",
|
|
9297
|
+
{
|
|
9298
|
+
ref: textInputRef,
|
|
9299
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9300
|
+
value: textValue,
|
|
9301
|
+
onChange: (e) => setTextValue(e.target.value),
|
|
9302
|
+
onKeyDown: handleKeyDown,
|
|
9303
|
+
style: {
|
|
9304
|
+
height: 32,
|
|
9305
|
+
border: "1px solid #CCCCCC",
|
|
9306
|
+
borderRadius: 4,
|
|
9307
|
+
padding: "0 16px",
|
|
9308
|
+
fontSize: 14,
|
|
9309
|
+
color: "#0D0D0D",
|
|
9310
|
+
outline: "none",
|
|
9311
|
+
boxSizing: "border-box"
|
|
9312
|
+
}
|
|
9313
|
+
}
|
|
9314
|
+
)
|
|
9315
|
+
] }),
|
|
9316
|
+
/* @__PURE__ */ jsxs9("div", { ...{ [FLOAT_ATTR]: "" }, style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
9317
|
+
/* @__PURE__ */ jsx10(
|
|
9318
|
+
"div",
|
|
9319
|
+
{
|
|
9320
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9321
|
+
style: {
|
|
9322
|
+
fontSize: 12,
|
|
9323
|
+
lineHeight: "16px",
|
|
9324
|
+
fontWeight: 600,
|
|
9325
|
+
color: "#0D0D0D"
|
|
9326
|
+
},
|
|
9327
|
+
children: "Link"
|
|
9328
|
+
}
|
|
9329
|
+
),
|
|
9330
|
+
/* @__PURE__ */ jsx10(
|
|
9331
|
+
"input",
|
|
9332
|
+
{
|
|
9333
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9334
|
+
value: hrefValue,
|
|
9335
|
+
onChange: (e) => setHrefValue(e.target.value),
|
|
9336
|
+
onKeyDown: handleKeyDown,
|
|
9337
|
+
style: {
|
|
9338
|
+
height: 32,
|
|
9339
|
+
border: "1px solid #CCCCCC",
|
|
9340
|
+
borderRadius: 4,
|
|
9341
|
+
padding: "0 16px",
|
|
9342
|
+
fontSize: 14,
|
|
9343
|
+
color: "#0D0D0D",
|
|
9344
|
+
outline: "none",
|
|
9345
|
+
boxSizing: "border-box"
|
|
9346
|
+
}
|
|
9347
|
+
}
|
|
9348
|
+
)
|
|
9349
|
+
] }),
|
|
9350
|
+
/* @__PURE__ */ jsxs9(
|
|
9351
|
+
"div",
|
|
9352
|
+
{
|
|
9353
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9354
|
+
style: {
|
|
9355
|
+
display: "flex",
|
|
9356
|
+
alignItems: "center",
|
|
9357
|
+
justifyContent: "space-between",
|
|
9358
|
+
gap: 12
|
|
9359
|
+
},
|
|
9360
|
+
children: [
|
|
9361
|
+
/* @__PURE__ */ jsx10(
|
|
9362
|
+
"button",
|
|
9363
|
+
{
|
|
9364
|
+
type: "button",
|
|
9365
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9366
|
+
onMouseDown: (e) => {
|
|
9367
|
+
e.preventDefault();
|
|
9368
|
+
removeLink();
|
|
9369
|
+
},
|
|
9370
|
+
style: {
|
|
9371
|
+
...BTN_RESET2,
|
|
9372
|
+
fontSize: 14,
|
|
9373
|
+
lineHeight: "20px",
|
|
9374
|
+
fontWeight: 600,
|
|
9375
|
+
color: "#0D0D0D"
|
|
9376
|
+
},
|
|
9377
|
+
children: "Remove link"
|
|
9378
|
+
}
|
|
9379
|
+
),
|
|
9380
|
+
/* @__PURE__ */ jsxs9("div", { ...{ [FLOAT_ATTR]: "" }, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
9381
|
+
/* @__PURE__ */ jsx10(
|
|
9382
|
+
"button",
|
|
9383
|
+
{
|
|
9384
|
+
type: "button",
|
|
9385
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9386
|
+
onMouseDown: (e) => {
|
|
9387
|
+
e.preventDefault();
|
|
9388
|
+
onClose();
|
|
9389
|
+
view.focus();
|
|
9390
|
+
},
|
|
9391
|
+
style: {
|
|
9392
|
+
...BTN_RESET2,
|
|
9393
|
+
height: 32,
|
|
9394
|
+
padding: "0 13px",
|
|
9395
|
+
border: "1px solid #CCCCCC",
|
|
9396
|
+
borderRadius: 4,
|
|
9397
|
+
fontSize: 14,
|
|
9398
|
+
lineHeight: "20px",
|
|
9399
|
+
fontWeight: 600,
|
|
9400
|
+
color: "#0D0D0D"
|
|
9401
|
+
},
|
|
9402
|
+
children: "Cancel"
|
|
9403
|
+
}
|
|
9404
|
+
),
|
|
9405
|
+
/* @__PURE__ */ jsx10(
|
|
9406
|
+
"button",
|
|
9407
|
+
{
|
|
9408
|
+
type: "button",
|
|
9409
|
+
disabled: !canSave,
|
|
9410
|
+
...{ [FLOAT_ATTR]: "" },
|
|
9411
|
+
onMouseDown: (e) => {
|
|
9412
|
+
e.preventDefault();
|
|
9413
|
+
if (!canSave) return;
|
|
9414
|
+
saveLink();
|
|
9415
|
+
},
|
|
9416
|
+
style: {
|
|
9417
|
+
...BTN_RESET2,
|
|
9418
|
+
height: 32,
|
|
9419
|
+
padding: "0 13px",
|
|
9420
|
+
borderRadius: 4,
|
|
9421
|
+
fontSize: 14,
|
|
9422
|
+
lineHeight: "20px",
|
|
9423
|
+
fontWeight: 600,
|
|
9424
|
+
background: canSave ? "#6210CC" : "#ECECEC",
|
|
9425
|
+
color: canSave ? "#FFFFFF" : "#A6A6A6",
|
|
9426
|
+
cursor: canSave ? "pointer" : "default"
|
|
9427
|
+
},
|
|
9428
|
+
children: "Save"
|
|
9429
|
+
}
|
|
9430
|
+
)
|
|
9431
|
+
] })
|
|
9432
|
+
]
|
|
9433
|
+
}
|
|
9434
|
+
)
|
|
9435
|
+
]
|
|
9436
|
+
}
|
|
9437
|
+
),
|
|
9438
|
+
document.body
|
|
9439
|
+
);
|
|
9440
|
+
}
|
|
8500
9441
|
var BLOCK_ITEMS = [
|
|
8501
9442
|
{
|
|
8502
9443
|
shortLabel: "\xB6",
|
|
@@ -8715,6 +9656,7 @@ function BlockMenuItem({
|
|
|
8715
9656
|
}
|
|
8716
9657
|
function FloatingMenu({ view, editorState }) {
|
|
8717
9658
|
const [showEmptyHandle, setShowEmptyHandle] = useState7(false);
|
|
9659
|
+
const [editingLink, setEditingLink] = useState7(null);
|
|
8718
9660
|
const dwellTimerRef = useRef4(null);
|
|
8719
9661
|
const lastEmptyPosRef = useRef4(null);
|
|
8720
9662
|
const [, setScrollTick] = useState7(0);
|
|
@@ -8740,9 +9682,16 @@ function FloatingMenu({ view, editorState }) {
|
|
|
8740
9682
|
`;
|
|
8741
9683
|
document.head.appendChild(style);
|
|
8742
9684
|
}, []);
|
|
9685
|
+
const emptyPos = editorState ? emptyBlockCursorPos(editorState) : null;
|
|
9686
|
+
const hasSelection = editorState ? !editorState.selection.empty : false;
|
|
9687
|
+
const linkAtCursor = editorState && !hasSelection ? getLinkAtCursor(editorState) : null;
|
|
9688
|
+
useEffect4(() => {
|
|
9689
|
+
if (!editingLink) return;
|
|
9690
|
+
if (!linkAtCursor || linkAtCursor.from !== editingLink.from || linkAtCursor.to !== editingLink.to) {
|
|
9691
|
+
setEditingLink(null);
|
|
9692
|
+
}
|
|
9693
|
+
}, [editingLink, linkAtCursor]);
|
|
8743
9694
|
if (!view || !editorState) return null;
|
|
8744
|
-
const emptyPos = emptyBlockCursorPos(editorState);
|
|
8745
|
-
const hasSelection = !editorState.selection.empty;
|
|
8746
9695
|
if (emptyPos !== lastEmptyPosRef.current) {
|
|
8747
9696
|
lastEmptyPosRef.current = emptyPos;
|
|
8748
9697
|
if (dwellTimerRef.current) {
|
|
@@ -8766,23 +9715,39 @@ function FloatingMenu({ view, editorState }) {
|
|
|
8766
9715
|
selectionRect
|
|
8767
9716
|
}
|
|
8768
9717
|
),
|
|
8769
|
-
!hasSelection &&
|
|
9718
|
+
!hasSelection && linkAtCursor && !editingLink && /* @__PURE__ */ jsx10(
|
|
9719
|
+
LinkHoverTooltip,
|
|
9720
|
+
{
|
|
9721
|
+
view,
|
|
9722
|
+
link: linkAtCursor,
|
|
9723
|
+
onEdit: (link2) => setEditingLink(link2)
|
|
9724
|
+
}
|
|
9725
|
+
),
|
|
9726
|
+
!hasSelection && editingLink && /* @__PURE__ */ jsx10(
|
|
9727
|
+
LinkEditDialog,
|
|
9728
|
+
{
|
|
9729
|
+
view,
|
|
9730
|
+
link: editingLink,
|
|
9731
|
+
onClose: () => setEditingLink(null)
|
|
9732
|
+
}
|
|
9733
|
+
),
|
|
9734
|
+
!hasSelection && !linkAtCursor && showEmptyHandle && emptyPos !== null && /* @__PURE__ */ jsx10(EmptyParaHandle, { view, cursorPos: emptyPos })
|
|
8770
9735
|
] }),
|
|
8771
9736
|
document.body
|
|
8772
9737
|
);
|
|
8773
9738
|
}
|
|
8774
9739
|
|
|
8775
9740
|
// src/ui/plugin/inlineSuggestPlugin.ts
|
|
8776
|
-
import { Plugin as
|
|
8777
|
-
import { Decoration as
|
|
8778
|
-
var inlineSuggestKey = new
|
|
9741
|
+
import { Plugin as Plugin9, PluginKey as PluginKey9 } from "prosemirror-state";
|
|
9742
|
+
import { Decoration as Decoration5, DecorationSet as DecorationSet5 } from "prosemirror-view";
|
|
9743
|
+
var inlineSuggestKey = new PluginKey9("inlineSuggest");
|
|
8779
9744
|
var DEBOUNCE_MS = 600;
|
|
8780
9745
|
function createInlineSuggestPlugin(provider, endpoint, options) {
|
|
8781
9746
|
const { onContextChange } = options ?? {};
|
|
8782
9747
|
return {
|
|
8783
9748
|
name: "inlineSuggest",
|
|
8784
9749
|
plugins: () => [
|
|
8785
|
-
new
|
|
9750
|
+
new Plugin9({
|
|
8786
9751
|
key: inlineSuggestKey,
|
|
8787
9752
|
state: {
|
|
8788
9753
|
init: () => ({ suggestion: null, anchorPos: null }),
|
|
@@ -8798,13 +9763,13 @@ function createInlineSuggestPlugin(provider, endpoint, options) {
|
|
|
8798
9763
|
props: {
|
|
8799
9764
|
decorations(state) {
|
|
8800
9765
|
const ps = inlineSuggestKey.getState(state);
|
|
8801
|
-
if (!ps?.suggestion || !state.selection.empty) return
|
|
9766
|
+
if (!ps?.suggestion || !state.selection.empty) return DecorationSet5.empty;
|
|
8802
9767
|
const ghost = document.createElement("span");
|
|
8803
9768
|
ghost.textContent = ps.suggestion;
|
|
8804
9769
|
ghost.style.cssText = "color: rgba(0,0,0,0.3); pointer-events: none; user-select: none;";
|
|
8805
9770
|
ghost.setAttribute("aria-hidden", "true");
|
|
8806
|
-
return
|
|
8807
|
-
|
|
9771
|
+
return DecorationSet5.create(state.doc, [
|
|
9772
|
+
Decoration5.widget(state.selection.from, ghost, {
|
|
8808
9773
|
side: 1,
|
|
8809
9774
|
key: "inline-suggest"
|
|
8810
9775
|
})
|
|
@@ -8959,6 +9924,7 @@ export {
|
|
|
8959
9924
|
createLinkPlugin,
|
|
8960
9925
|
createMarkdownClipboardPlugin,
|
|
8961
9926
|
createNoteBlockPlugin,
|
|
9927
|
+
createPlaceholderPlugin,
|
|
8962
9928
|
createPluginArray,
|
|
8963
9929
|
createReactNodeView,
|
|
8964
9930
|
createSlashCommandPlugin,
|