@sendbird/actionbook-core 0.7.3 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/README.md +2 -2
- package/dist/index.d.ts +37 -3
- package/dist/index.js +484 -33
- package/dist/index.js.map +1 -1
- package/dist/{types-rEXLrfo_.d.ts → types-DK_GhIWZ.d.ts} +17 -5
- package/dist/ui/index.d.ts +50 -8
- package/dist/ui/index.js +2523 -495
- package/dist/ui/index.js.map +1 -1
- package/package.json +5 -5
package/dist/ui/index.js
CHANGED
|
@@ -89,6 +89,24 @@ var actionbookSchema = new Schema({
|
|
|
89
89
|
},
|
|
90
90
|
defining: true
|
|
91
91
|
},
|
|
92
|
+
codeBlock: {
|
|
93
|
+
content: "text*",
|
|
94
|
+
group: "block",
|
|
95
|
+
code: true,
|
|
96
|
+
defining: true,
|
|
97
|
+
marks: "",
|
|
98
|
+
attrs: { language: { default: null } },
|
|
99
|
+
parseDOM: [{
|
|
100
|
+
tag: "pre",
|
|
101
|
+
preserveWhitespace: "full",
|
|
102
|
+
getAttrs(dom) {
|
|
103
|
+
return { language: dom.getAttribute("data-language") || null };
|
|
104
|
+
}
|
|
105
|
+
}],
|
|
106
|
+
toDOM(node) {
|
|
107
|
+
return ["pre", { "data-language": node.attrs.language || void 0 }, ["code", 0]];
|
|
108
|
+
}
|
|
109
|
+
},
|
|
92
110
|
horizontalRule: {
|
|
93
111
|
group: "block",
|
|
94
112
|
parseDOM: [{ tag: "hr" }],
|
|
@@ -96,6 +114,61 @@ var actionbookSchema = new Schema({
|
|
|
96
114
|
return ["hr"];
|
|
97
115
|
}
|
|
98
116
|
},
|
|
117
|
+
// ── Jinja conditional block ──
|
|
118
|
+
jinjaIfBlock: {
|
|
119
|
+
content: "jinjaIfBranch+",
|
|
120
|
+
group: "block",
|
|
121
|
+
isolating: true,
|
|
122
|
+
defining: true,
|
|
123
|
+
parseDOM: [{ tag: "div[data-jinja-if-block]" }],
|
|
124
|
+
toDOM() {
|
|
125
|
+
return ["div", { "data-jinja-if-block": "", class: "jinja-if-block" }, 0];
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
jinjaIfBranch: {
|
|
129
|
+
content: "block+",
|
|
130
|
+
isolating: true,
|
|
131
|
+
defining: true,
|
|
132
|
+
attrs: {
|
|
133
|
+
branchType: { default: "if" },
|
|
134
|
+
// 'if' | 'elif' | 'else'
|
|
135
|
+
condition: { default: "" }
|
|
136
|
+
},
|
|
137
|
+
parseDOM: [
|
|
138
|
+
{
|
|
139
|
+
tag: "div[data-jinja-branch]",
|
|
140
|
+
getAttrs(dom) {
|
|
141
|
+
const el = dom;
|
|
142
|
+
return {
|
|
143
|
+
branchType: el.getAttribute("data-branch-type") || "if",
|
|
144
|
+
condition: el.getAttribute("data-condition") || ""
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
toDOM(node) {
|
|
150
|
+
return [
|
|
151
|
+
"div",
|
|
152
|
+
{
|
|
153
|
+
"data-jinja-branch": "",
|
|
154
|
+
"data-branch-type": node.attrs.branchType,
|
|
155
|
+
"data-condition": node.attrs.condition,
|
|
156
|
+
class: `jinja-branch jinja-branch-${node.attrs.branchType}`
|
|
157
|
+
},
|
|
158
|
+
0
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
noteBlock: {
|
|
163
|
+
content: "block+",
|
|
164
|
+
group: "block",
|
|
165
|
+
defining: true,
|
|
166
|
+
isolating: true,
|
|
167
|
+
parseDOM: [{ tag: "div[data-note-block]" }],
|
|
168
|
+
toDOM() {
|
|
169
|
+
return ["div", { "data-note-block": "", class: "ab-note-block" }, 0];
|
|
170
|
+
}
|
|
171
|
+
},
|
|
99
172
|
// ── Table nodes ──
|
|
100
173
|
table: {
|
|
101
174
|
content: "tableRow+",
|
|
@@ -489,6 +562,12 @@ function IconTimeDiff({ size = 16, fill = "currentColor", style }) {
|
|
|
489
562
|
}
|
|
490
563
|
);
|
|
491
564
|
}
|
|
565
|
+
function IconStop({ size = 16, fill = "currentColor", style }) {
|
|
566
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 8 8", width: size, height: size, fill: "none", style, children: [
|
|
567
|
+
/* @__PURE__ */ jsx("path", { d: "M5.4375 3.375L2.0625 3.375V4.125L5.4375 4.125V3.375Z", fill }),
|
|
568
|
+
/* @__PURE__ */ jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M3.75 7.5C5.82107 7.5 7.5 5.82107 7.5 3.75C7.5 1.67893 5.82107 0 3.75 0C1.67893 0 0 1.67893 0 3.75C0 5.82107 1.67893 7.5 3.75 7.5ZM6.75 3.75C6.75 5.40685 5.40685 6.75 3.75 6.75C2.09315 6.75 0.75 5.40685 0.75 3.75C0.75 2.09315 2.09315 0.75 3.75 0.75C5.40685 0.75 6.75 2.09315 6.75 3.75Z", fill })
|
|
569
|
+
] });
|
|
570
|
+
}
|
|
492
571
|
function IconAnchor({ size = 16, fill = "currentColor", style }) {
|
|
493
572
|
return /* @__PURE__ */ jsxs(
|
|
494
573
|
"svg",
|
|
@@ -727,21 +806,24 @@ var ReactNodeViewImpl = class {
|
|
|
727
806
|
dom;
|
|
728
807
|
root;
|
|
729
808
|
component;
|
|
809
|
+
wrapper;
|
|
730
810
|
_node;
|
|
731
811
|
_view;
|
|
732
812
|
_getPos;
|
|
733
813
|
_selected = false;
|
|
734
814
|
_decorations = [];
|
|
735
|
-
constructor(node, view, getPos, options) {
|
|
815
|
+
constructor(node, view, getPos, decorations, options) {
|
|
736
816
|
this._node = node;
|
|
737
817
|
this._view = view;
|
|
738
818
|
this._getPos = getPos;
|
|
819
|
+
this._decorations = decorations;
|
|
739
820
|
this.component = options.component;
|
|
821
|
+
this.wrapper = options.wrapper;
|
|
740
822
|
const tag = options.as ?? (options.inline !== false ? "span" : "div");
|
|
741
823
|
this.dom = document.createElement(tag);
|
|
742
824
|
if (options.inline !== false) {
|
|
743
|
-
this.dom.style.display = "inline
|
|
744
|
-
this.dom.style.verticalAlign = "
|
|
825
|
+
this.dom.style.display = "inline";
|
|
826
|
+
this.dom.style.verticalAlign = "baseline";
|
|
745
827
|
}
|
|
746
828
|
if (options.className) {
|
|
747
829
|
this.dom.className = options.className;
|
|
@@ -750,14 +832,15 @@ var ReactNodeViewImpl = class {
|
|
|
750
832
|
this.render();
|
|
751
833
|
}
|
|
752
834
|
render() {
|
|
835
|
+
const element = createElement(this.component, {
|
|
836
|
+
node: this._node,
|
|
837
|
+
view: this._view,
|
|
838
|
+
getPos: this._getPos,
|
|
839
|
+
selected: this._selected,
|
|
840
|
+
decorations: this._decorations
|
|
841
|
+
});
|
|
753
842
|
this.root.render(
|
|
754
|
-
createElement(this.
|
|
755
|
-
node: this._node,
|
|
756
|
-
view: this._view,
|
|
757
|
-
getPos: this._getPos,
|
|
758
|
-
selected: this._selected,
|
|
759
|
-
decorations: this._decorations
|
|
760
|
-
})
|
|
843
|
+
this.wrapper ? createElement(this.wrapper, null, element) : element
|
|
761
844
|
);
|
|
762
845
|
}
|
|
763
846
|
update(node, decorations, _innerDecorations) {
|
|
@@ -786,7 +869,7 @@ var ReactNodeViewImpl = class {
|
|
|
786
869
|
}
|
|
787
870
|
};
|
|
788
871
|
function createReactNodeView(options) {
|
|
789
|
-
return (node, view, getPos) => new ReactNodeViewImpl(node, view, getPos, options);
|
|
872
|
+
return (node, view, getPos, decorations) => new ReactNodeViewImpl(node, view, getPos, decorations, options);
|
|
790
873
|
}
|
|
791
874
|
|
|
792
875
|
// src/ui/hooks/useEditorView.ts
|
|
@@ -795,9 +878,19 @@ import { EditorState } from "prosemirror-state";
|
|
|
795
878
|
import { EditorView } from "prosemirror-view";
|
|
796
879
|
import { Node as PMNode } from "prosemirror-model";
|
|
797
880
|
|
|
881
|
+
// src/ast/types.ts
|
|
882
|
+
var RESOURCE_TAG_TYPES = ["tool", "manual", "agent_message_template", "handoff", "time_diff", "time_difference"];
|
|
883
|
+
|
|
798
884
|
// src/compat/prosemirror.ts
|
|
799
885
|
var MAX_DEPTH = 128;
|
|
800
886
|
var ALLOWED_URL_PROTOCOLS = /^(https?:|mailto:|tel:|#|\/)/i;
|
|
887
|
+
var LIST_TYPES = /* @__PURE__ */ new Set(["bulletList", "orderedList"]);
|
|
888
|
+
function isLooseList(items) {
|
|
889
|
+
return items.some((li) => {
|
|
890
|
+
const nonListBlocks = li.content.filter((b) => !LIST_TYPES.has(b.type));
|
|
891
|
+
return nonListBlocks.length > 1;
|
|
892
|
+
});
|
|
893
|
+
}
|
|
801
894
|
function convertPMMark(mark) {
|
|
802
895
|
switch (mark.type) {
|
|
803
896
|
case "bold":
|
|
@@ -836,12 +929,17 @@ function convertPMInline(node, depth) {
|
|
|
836
929
|
}
|
|
837
930
|
case "inlineToolTag": {
|
|
838
931
|
const attrs = node.attrs ?? {};
|
|
932
|
+
const tagType = attrs.type ?? "tool";
|
|
933
|
+
const text2 = attrs.text ?? "";
|
|
934
|
+
if (!RESOURCE_TAG_TYPES.includes(tagType)) {
|
|
935
|
+
return text2 ? [{ type: "text", text: text2 }] : [];
|
|
936
|
+
}
|
|
839
937
|
return [
|
|
840
938
|
{
|
|
841
939
|
type: "resourceTag",
|
|
842
|
-
tagType
|
|
940
|
+
tagType,
|
|
843
941
|
resourceId: attrs.resourceId ?? "",
|
|
844
|
-
text:
|
|
942
|
+
text: text2
|
|
845
943
|
}
|
|
846
944
|
];
|
|
847
945
|
}
|
|
@@ -872,20 +970,27 @@ function convertPMBlock(node, depth = 0) {
|
|
|
872
970
|
const level = node.attrs?.level ?? 1;
|
|
873
971
|
return [{ type: "heading", level, content: children.flatMap((c) => convertPMInline(c, depth + 1)) }];
|
|
874
972
|
}
|
|
875
|
-
case "bulletList":
|
|
973
|
+
case "bulletList": {
|
|
974
|
+
const items = children.map((c) => convertPMListItem(c, depth + 1));
|
|
975
|
+
const spread = isLooseList(items);
|
|
876
976
|
return [
|
|
877
977
|
{
|
|
878
978
|
type: "bulletList",
|
|
879
|
-
|
|
979
|
+
...spread ? { spread: true } : {},
|
|
980
|
+
content: items.map((li) => spread ? { ...li, spread: true } : li)
|
|
880
981
|
}
|
|
881
982
|
];
|
|
983
|
+
}
|
|
882
984
|
case "orderedList": {
|
|
883
985
|
const start = node.attrs?.start ?? 1;
|
|
986
|
+
const items = children.map((c) => convertPMListItem(c, depth + 1));
|
|
987
|
+
const spread = isLooseList(items);
|
|
884
988
|
return [
|
|
885
989
|
{
|
|
886
990
|
type: "orderedList",
|
|
887
991
|
start,
|
|
888
|
-
|
|
992
|
+
...spread ? { spread: true } : {},
|
|
993
|
+
content: items.map((li) => spread ? { ...li, spread: true } : li)
|
|
889
994
|
}
|
|
890
995
|
];
|
|
891
996
|
}
|
|
@@ -896,6 +1001,12 @@ function convertPMBlock(node, depth = 0) {
|
|
|
896
1001
|
return [{ type: "blockquote", content: children.flatMap((c) => convertPMBlock(c, depth + 1)) }];
|
|
897
1002
|
case "horizontalRule":
|
|
898
1003
|
return [{ type: "horizontalRule" }];
|
|
1004
|
+
case "codeBlock": {
|
|
1005
|
+
const textContent2 = children.map((c) => c.text ?? "").join("");
|
|
1006
|
+
return [{ type: "codeBlock", content: textContent2, ...node.attrs?.language ? { language: node.attrs.language } : {} }];
|
|
1007
|
+
}
|
|
1008
|
+
case "noteBlock":
|
|
1009
|
+
return [{ type: "noteBlock", content: children.flatMap((c) => convertPMBlock(c, depth + 1)) }];
|
|
899
1010
|
case "table": {
|
|
900
1011
|
const rows = children.map((rowNode) => {
|
|
901
1012
|
const cells = (rowNode.content ?? []).map((cellNode) => {
|
|
@@ -912,6 +1023,22 @@ function convertPMBlock(node, depth = 0) {
|
|
|
912
1023
|
});
|
|
913
1024
|
return [{ type: "table", content: rows }];
|
|
914
1025
|
}
|
|
1026
|
+
case "jinjaIfBlock": {
|
|
1027
|
+
const branches = children.map((branchNode) => {
|
|
1028
|
+
const branchType = branchNode.attrs?.branchType ?? "if";
|
|
1029
|
+
const condition = branchNode.attrs?.condition;
|
|
1030
|
+
const branchContent = (branchNode.content ?? []).flatMap((c) => convertPMBlock(c, depth + 2));
|
|
1031
|
+
return {
|
|
1032
|
+
branchType,
|
|
1033
|
+
...branchType !== "else" && condition ? { condition } : {},
|
|
1034
|
+
content: branchContent
|
|
1035
|
+
};
|
|
1036
|
+
});
|
|
1037
|
+
if (branches.length === 0) return [];
|
|
1038
|
+
return [{ type: "jinjaIfBlock", branches }];
|
|
1039
|
+
}
|
|
1040
|
+
case "jinjaIfBranch":
|
|
1041
|
+
return children.flatMap((c) => convertPMBlock(c, depth + 1));
|
|
915
1042
|
default:
|
|
916
1043
|
if (children.length > 0) {
|
|
917
1044
|
return children.flatMap((c) => convertPMBlock(c, depth + 1));
|
|
@@ -923,11 +1050,11 @@ function convertPMListItem(node, depth = 0) {
|
|
|
923
1050
|
if (depth > MAX_DEPTH) return { type: "listItem", content: [{ type: "paragraph", content: [] }] };
|
|
924
1051
|
const children = node.content ?? [];
|
|
925
1052
|
const content = children.flatMap((c) => convertPMBlock(c, depth + 1));
|
|
926
|
-
const checked = node.attrs?.checked;
|
|
927
1053
|
const base = {
|
|
928
1054
|
type: "listItem",
|
|
929
1055
|
content: content.length > 0 ? content : [{ type: "paragraph", content: [] }]
|
|
930
1056
|
};
|
|
1057
|
+
const checked = node.attrs?.checked;
|
|
931
1058
|
if (typeof checked === "boolean") {
|
|
932
1059
|
base.checked = checked;
|
|
933
1060
|
}
|
|
@@ -1491,7 +1618,7 @@ function listItemWithTaskListItem(node, parent, state, info) {
|
|
|
1491
1618
|
|
|
1492
1619
|
// src/markdown/plugins/resourceTag.ts
|
|
1493
1620
|
var RESOURCE_TAG_RE = /\{\{([^:}]+):([^:}]*):([^}]+)\}\}/g;
|
|
1494
|
-
var VALID_TYPES = /* @__PURE__ */ new Set(["tool", "manual", "agent_message_template", "handoff", "time_diff"]);
|
|
1621
|
+
var VALID_TYPES = /* @__PURE__ */ new Set(["tool", "manual", "agent_message_template", "handoff", "end_call", "time_diff"]);
|
|
1495
1622
|
function splitTextWithResourceTags(text2) {
|
|
1496
1623
|
const results = [];
|
|
1497
1624
|
let lastIndex = 0;
|
|
@@ -1654,10 +1781,11 @@ function convertBlock(node, depth = 0) {
|
|
|
1654
1781
|
case "list": {
|
|
1655
1782
|
const list = node;
|
|
1656
1783
|
const items = list.children.map((li) => convertListItem(li, depth + 1));
|
|
1784
|
+
const spread = list.spread ?? false;
|
|
1657
1785
|
if (list.ordered) {
|
|
1658
|
-
return [{ type: "orderedList", start: list.start ?? 1, content: items }];
|
|
1786
|
+
return [{ type: "orderedList", start: list.start ?? 1, spread, content: items }];
|
|
1659
1787
|
}
|
|
1660
|
-
return [{ type: "bulletList", content: items }];
|
|
1788
|
+
return [{ type: "bulletList", spread, content: items }];
|
|
1661
1789
|
}
|
|
1662
1790
|
case "blockquote": {
|
|
1663
1791
|
const bq = node;
|
|
@@ -1666,6 +1794,10 @@ function convertBlock(node, depth = 0) {
|
|
|
1666
1794
|
}
|
|
1667
1795
|
case "thematicBreak":
|
|
1668
1796
|
return [{ type: "horizontalRule" }];
|
|
1797
|
+
case "code": {
|
|
1798
|
+
const codeNode = node;
|
|
1799
|
+
return [{ type: "codeBlock", content: codeNode.value, ...codeNode.lang ? { language: codeNode.lang } : {} }];
|
|
1800
|
+
}
|
|
1669
1801
|
case "jinjaIfBlockMdast": {
|
|
1670
1802
|
const jNode = node;
|
|
1671
1803
|
const branches = jNode.branches.map((b) => ({
|
|
@@ -1706,7 +1838,11 @@ function convertBlock(node, depth = 0) {
|
|
|
1706
1838
|
function convertListItem(node, depth = 0) {
|
|
1707
1839
|
if (depth > MAX_DEPTH2) throw new DepthError(depth);
|
|
1708
1840
|
const content = node.children.flatMap((child) => convertBlock(child, depth + 1));
|
|
1709
|
-
const base = {
|
|
1841
|
+
const base = {
|
|
1842
|
+
type: "listItem",
|
|
1843
|
+
spread: node.spread ?? false,
|
|
1844
|
+
content: content.length > 0 ? content : [{ type: "paragraph", content: [] }]
|
|
1845
|
+
};
|
|
1710
1846
|
if (typeof node.checked === "boolean") {
|
|
1711
1847
|
return { ...base, checked: node.checked };
|
|
1712
1848
|
}
|
|
@@ -1805,31 +1941,39 @@ function blockToMdast(node, depth = 0) {
|
|
|
1805
1941
|
return [{ type: "paragraph", children: node.content.flatMap((c) => inlineToMdast(c, depth + 1)) }];
|
|
1806
1942
|
case "heading":
|
|
1807
1943
|
return [{ type: "heading", depth: node.level, children: node.content.flatMap((c) => inlineToMdast(c, depth + 1)) }];
|
|
1808
|
-
case "bulletList":
|
|
1944
|
+
case "bulletList": {
|
|
1945
|
+
const items = node.content.map((li) => listItemToMdast(li, depth + 1));
|
|
1809
1946
|
return [
|
|
1810
1947
|
{
|
|
1811
1948
|
type: "list",
|
|
1812
1949
|
ordered: false,
|
|
1813
|
-
spread: false,
|
|
1814
|
-
children:
|
|
1950
|
+
spread: node.spread ?? false,
|
|
1951
|
+
children: items
|
|
1815
1952
|
}
|
|
1816
1953
|
];
|
|
1817
|
-
|
|
1954
|
+
}
|
|
1955
|
+
case "orderedList": {
|
|
1956
|
+
const items = node.content.map((li) => listItemToMdast(li, depth + 1));
|
|
1818
1957
|
return [
|
|
1819
1958
|
{
|
|
1820
1959
|
type: "list",
|
|
1821
1960
|
ordered: true,
|
|
1822
1961
|
start: node.start,
|
|
1823
|
-
spread: false,
|
|
1824
|
-
children:
|
|
1962
|
+
spread: node.spread ?? false,
|
|
1963
|
+
children: items
|
|
1825
1964
|
}
|
|
1826
1965
|
];
|
|
1966
|
+
}
|
|
1827
1967
|
case "listItem":
|
|
1828
1968
|
return listItemToMdast(node, depth).children.flatMap((child) => [child]);
|
|
1829
1969
|
case "blockquote":
|
|
1830
1970
|
return [{ type: "blockquote", children: node.content.flatMap((c) => blockToMdast(c, depth + 1)) }];
|
|
1831
1971
|
case "horizontalRule":
|
|
1832
1972
|
return [{ type: "thematicBreak" }];
|
|
1973
|
+
case "codeBlock": {
|
|
1974
|
+
const cb = node;
|
|
1975
|
+
return [{ type: "code", value: cb.content, ...cb.language ? { lang: cb.language } : {} }];
|
|
1976
|
+
}
|
|
1833
1977
|
case "jinjaIfBlock": {
|
|
1834
1978
|
const jNode = node;
|
|
1835
1979
|
const result = [];
|
|
@@ -1853,14 +1997,18 @@ function blockToMdast(node, depth = 0) {
|
|
|
1853
1997
|
}));
|
|
1854
1998
|
return [{ type: "table", children: rows }];
|
|
1855
1999
|
}
|
|
2000
|
+
case "noteBlock":
|
|
2001
|
+
return [];
|
|
1856
2002
|
}
|
|
1857
2003
|
}
|
|
1858
2004
|
function listItemToMdast(node, depth = 0) {
|
|
1859
2005
|
if (depth > MAX_DEPTH2) throw new DepthError(depth);
|
|
2006
|
+
const children = node.content.flatMap((child) => blockToMdast(child, depth + 1));
|
|
2007
|
+
const isSpread = node.spread ?? false;
|
|
1860
2008
|
const result = {
|
|
1861
2009
|
type: "listItem",
|
|
1862
|
-
spread:
|
|
1863
|
-
children
|
|
2010
|
+
spread: isSpread,
|
|
2011
|
+
children
|
|
1864
2012
|
};
|
|
1865
2013
|
if (typeof node.checked === "boolean") {
|
|
1866
2014
|
result.checked = node.checked;
|
|
@@ -1893,12 +2041,20 @@ function textHandler(node, parent, state, info) {
|
|
|
1893
2041
|
state.unsafe = originalUnsafe;
|
|
1894
2042
|
return result;
|
|
1895
2043
|
}
|
|
2044
|
+
function linkHandler(node, parent, state, info) {
|
|
2045
|
+
const childrenText = state.containerPhrasing(node, { ...info, before: "[", after: "]" });
|
|
2046
|
+
const url = node.url ?? "";
|
|
2047
|
+
const title = node.title;
|
|
2048
|
+
const titlePart = title ? ` "${title.replace(/"/g, '\\"')}"` : "";
|
|
2049
|
+
return `[${childrenText}](${url}${titlePart})`;
|
|
2050
|
+
}
|
|
1896
2051
|
function serializeToMarkdown(doc2) {
|
|
1897
2052
|
const mdastTree = toMdast(doc2);
|
|
1898
|
-
const
|
|
2053
|
+
const raw = toMarkdown(mdastTree, {
|
|
1899
2054
|
bullet: "-",
|
|
1900
2055
|
rule: "-",
|
|
1901
2056
|
listItemIndent: "one",
|
|
2057
|
+
incrementListMarker: true,
|
|
1902
2058
|
emphasis: "*",
|
|
1903
2059
|
strong: "*",
|
|
1904
2060
|
resourceLink: true,
|
|
@@ -1910,11 +2066,13 @@ function serializeToMarkdown(doc2) {
|
|
|
1910
2066
|
],
|
|
1911
2067
|
handlers: {
|
|
1912
2068
|
text: textHandler,
|
|
2069
|
+
link: linkHandler,
|
|
1913
2070
|
...resourceTagToMarkdown().handlers,
|
|
1914
2071
|
...jumpPointToMarkdown().handlers
|
|
1915
2072
|
},
|
|
1916
2073
|
extensions: [gfmNoAutolinkToMarkdown()]
|
|
1917
2074
|
});
|
|
2075
|
+
let result = raw.replace(/^(\s*)\\>/gm, "$1>").replace(/(\S) *>/g, (match, pre) => `${pre} >`).replace(/\\\[([^\]]*)\]/g, "\\[$1\\]").replace(/ /g, " ");
|
|
1918
2076
|
return result;
|
|
1919
2077
|
}
|
|
1920
2078
|
|
|
@@ -1996,24 +2154,26 @@ function convertInline2(node) {
|
|
|
1996
2154
|
return assertNever(node);
|
|
1997
2155
|
}
|
|
1998
2156
|
}
|
|
1999
|
-
|
|
2000
|
-
function convertBlockToArray(node, listDepth = 0) {
|
|
2157
|
+
function convertBlockToArray(node) {
|
|
2001
2158
|
if (node.type === "jinjaIfBlock") {
|
|
2002
|
-
|
|
2003
|
-
const result = [];
|
|
2004
|
-
for (const branch of jNode.branches) {
|
|
2005
|
-
const tagText = branch.branchType === "else" ? "{% else %}" : `{% ${branch.branchType} ${branch.condition ?? ""} %}`.trim();
|
|
2006
|
-
result.push({ type: "paragraph", content: [{ type: "text", text: tagText }] });
|
|
2007
|
-
for (const child of branch.content) {
|
|
2008
|
-
result.push(...convertBlockToArray(child, listDepth));
|
|
2009
|
-
}
|
|
2010
|
-
}
|
|
2011
|
-
result.push({ type: "paragraph", content: [{ type: "text", text: "{% endif %}" }] });
|
|
2012
|
-
return result;
|
|
2159
|
+
return [convertJinjaIfBlock(node)];
|
|
2013
2160
|
}
|
|
2014
|
-
return [convertBlock2(node
|
|
2161
|
+
return [convertBlock2(node)];
|
|
2162
|
+
}
|
|
2163
|
+
function convertJinjaIfBlock(node) {
|
|
2164
|
+
return {
|
|
2165
|
+
type: "jinjaIfBlock",
|
|
2166
|
+
content: node.branches.map((branch) => ({
|
|
2167
|
+
type: "jinjaIfBranch",
|
|
2168
|
+
attrs: {
|
|
2169
|
+
branchType: branch.branchType,
|
|
2170
|
+
condition: branch.condition ?? ""
|
|
2171
|
+
},
|
|
2172
|
+
content: branch.content.length > 0 ? branch.content.flatMap(convertBlockToArray) : [{ type: "paragraph", content: [] }]
|
|
2173
|
+
}))
|
|
2174
|
+
};
|
|
2015
2175
|
}
|
|
2016
|
-
function convertBlock2(node
|
|
2176
|
+
function convertBlock2(node) {
|
|
2017
2177
|
switch (node.type) {
|
|
2018
2178
|
case "paragraph":
|
|
2019
2179
|
return {
|
|
@@ -2026,29 +2186,21 @@ function convertBlock2(node, listDepth = 0) {
|
|
|
2026
2186
|
attrs: { level: node.level },
|
|
2027
2187
|
content: node.content.flatMap(convertInlineToArray)
|
|
2028
2188
|
};
|
|
2029
|
-
case "bulletList":
|
|
2030
|
-
if (listDepth >= MAX_LIST_DEPTH) {
|
|
2031
|
-
return flattenListToBlock(node);
|
|
2032
|
-
}
|
|
2189
|
+
case "bulletList":
|
|
2033
2190
|
return {
|
|
2034
2191
|
type: "bulletList",
|
|
2035
|
-
content: node.content.map(
|
|
2192
|
+
content: node.content.map(convertBlock2)
|
|
2036
2193
|
};
|
|
2037
|
-
|
|
2038
|
-
case "orderedList": {
|
|
2039
|
-
if (listDepth >= MAX_LIST_DEPTH) {
|
|
2040
|
-
return flattenListToBlock(node);
|
|
2041
|
-
}
|
|
2194
|
+
case "orderedList":
|
|
2042
2195
|
return {
|
|
2043
2196
|
type: "orderedList",
|
|
2044
2197
|
attrs: { start: node.start },
|
|
2045
|
-
content: node.content.map(
|
|
2198
|
+
content: node.content.map(convertBlock2)
|
|
2046
2199
|
};
|
|
2047
|
-
}
|
|
2048
2200
|
case "listItem": {
|
|
2049
2201
|
const result = {
|
|
2050
2202
|
type: "listItem",
|
|
2051
|
-
content: node.content.flatMap(
|
|
2203
|
+
content: node.content.flatMap(convertBlockToArray)
|
|
2052
2204
|
};
|
|
2053
2205
|
if (node.checked != null) {
|
|
2054
2206
|
result.attrs = { checked: node.checked };
|
|
@@ -2058,10 +2210,23 @@ function convertBlock2(node, listDepth = 0) {
|
|
|
2058
2210
|
case "blockquote":
|
|
2059
2211
|
return {
|
|
2060
2212
|
type: "blockquote",
|
|
2061
|
-
content: node.content.flatMap(
|
|
2213
|
+
content: node.content.flatMap(convertBlockToArray)
|
|
2062
2214
|
};
|
|
2063
2215
|
case "horizontalRule":
|
|
2064
2216
|
return { type: "horizontalRule" };
|
|
2217
|
+
case "codeBlock": {
|
|
2218
|
+
const cb = node;
|
|
2219
|
+
return {
|
|
2220
|
+
type: "codeBlock",
|
|
2221
|
+
attrs: { language: cb.language ?? null },
|
|
2222
|
+
content: cb.content ? [{ type: "text", text: cb.content }] : void 0
|
|
2223
|
+
};
|
|
2224
|
+
}
|
|
2225
|
+
case "noteBlock":
|
|
2226
|
+
return {
|
|
2227
|
+
type: "noteBlock",
|
|
2228
|
+
content: node.content.flatMap(convertBlockToArray)
|
|
2229
|
+
};
|
|
2065
2230
|
case "table":
|
|
2066
2231
|
return {
|
|
2067
2232
|
type: "table",
|
|
@@ -2073,53 +2238,16 @@ function convertBlock2(node, listDepth = 0) {
|
|
|
2073
2238
|
}))
|
|
2074
2239
|
}))
|
|
2075
2240
|
};
|
|
2076
|
-
case "jinjaIfBlock":
|
|
2077
|
-
|
|
2078
|
-
const result = [];
|
|
2079
|
-
for (const branch of jNode.branches) {
|
|
2080
|
-
const tagText = branch.branchType === "else" ? "{% else %}" : `{% ${branch.branchType} ${branch.condition ?? ""} %}`.trim();
|
|
2081
|
-
result.push({ type: "paragraph", content: [{ type: "text", text: tagText }] });
|
|
2082
|
-
for (const child of branch.content) {
|
|
2083
|
-
result.push(...convertBlockToArray(child, listDepth));
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
result.push({ type: "paragraph", content: [{ type: "text", text: "{% endif %}" }] });
|
|
2087
|
-
return result[0] ?? { type: "paragraph", content: [] };
|
|
2088
|
-
}
|
|
2241
|
+
case "jinjaIfBlock":
|
|
2242
|
+
return convertJinjaIfBlock(node);
|
|
2089
2243
|
default:
|
|
2090
2244
|
return assertNever(node);
|
|
2091
2245
|
}
|
|
2092
2246
|
}
|
|
2093
|
-
function flattenListToBlock(node) {
|
|
2094
|
-
const paragraphs = [];
|
|
2095
|
-
function extractInlines(n) {
|
|
2096
|
-
switch (n.type) {
|
|
2097
|
-
case "paragraph":
|
|
2098
|
-
case "heading":
|
|
2099
|
-
paragraphs.push({
|
|
2100
|
-
type: "paragraph",
|
|
2101
|
-
content: n.content.flatMap(convertInlineToArray)
|
|
2102
|
-
});
|
|
2103
|
-
break;
|
|
2104
|
-
case "listItem":
|
|
2105
|
-
case "blockquote":
|
|
2106
|
-
for (const child of n.content) extractInlines(child);
|
|
2107
|
-
break;
|
|
2108
|
-
case "bulletList":
|
|
2109
|
-
case "orderedList":
|
|
2110
|
-
for (const item of n.content) extractInlines(item);
|
|
2111
|
-
break;
|
|
2112
|
-
default:
|
|
2113
|
-
break;
|
|
2114
|
-
}
|
|
2115
|
-
}
|
|
2116
|
-
extractInlines(node);
|
|
2117
|
-
return paragraphs.length > 0 ? paragraphs[0] : { type: "paragraph", content: [] };
|
|
2118
|
-
}
|
|
2119
2247
|
function toProseMirrorJSON(doc2) {
|
|
2120
2248
|
return {
|
|
2121
2249
|
type: "doc",
|
|
2122
|
-
content: doc2.content.flatMap(
|
|
2250
|
+
content: doc2.content.flatMap(convertBlockToArray)
|
|
2123
2251
|
};
|
|
2124
2252
|
}
|
|
2125
2253
|
function astNodesToJSONContent(nodes) {
|
|
@@ -2143,16 +2271,30 @@ function pmDocToAST(pmDoc) {
|
|
|
2143
2271
|
return fromProseMirrorJSON(json);
|
|
2144
2272
|
}
|
|
2145
2273
|
function useEditorView(config) {
|
|
2146
|
-
const viewRef = useRef(null);
|
|
2147
2274
|
const viewInstanceRef = useRef(null);
|
|
2275
|
+
const containerRef = useRef(null);
|
|
2148
2276
|
const [, forceUpdate] = useState(0);
|
|
2149
2277
|
const configRef = useRef(config);
|
|
2150
2278
|
configRef.current = config;
|
|
2151
2279
|
useEffect(() => {
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2280
|
+
return () => {
|
|
2281
|
+
viewInstanceRef.current?.destroy();
|
|
2282
|
+
viewInstanceRef.current = null;
|
|
2283
|
+
};
|
|
2284
|
+
}, []);
|
|
2285
|
+
const viewRef = useCallback((container) => {
|
|
2286
|
+
if (container === containerRef.current) return;
|
|
2287
|
+
if (viewInstanceRef.current) {
|
|
2288
|
+
viewInstanceRef.current.destroy();
|
|
2289
|
+
viewInstanceRef.current = null;
|
|
2290
|
+
}
|
|
2291
|
+
containerRef.current = container;
|
|
2292
|
+
if (!container) {
|
|
2293
|
+
forceUpdate((n) => n + 1);
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
const { pmPlugins, nodeViews } = createPluginArray(configRef.current.plugins ?? []);
|
|
2297
|
+
const state = docToState(configRef.current.content, pmPlugins);
|
|
2156
2298
|
const view = new EditorView(container, {
|
|
2157
2299
|
state,
|
|
2158
2300
|
nodeViews,
|
|
@@ -2169,10 +2311,6 @@ function useEditorView(config) {
|
|
|
2169
2311
|
});
|
|
2170
2312
|
viewInstanceRef.current = view;
|
|
2171
2313
|
forceUpdate((n) => n + 1);
|
|
2172
|
-
return () => {
|
|
2173
|
-
view.destroy();
|
|
2174
|
-
viewInstanceRef.current = null;
|
|
2175
|
-
};
|
|
2176
2314
|
}, []);
|
|
2177
2315
|
const getAST = useCallback(() => {
|
|
2178
2316
|
const view = viewInstanceRef.current;
|
|
@@ -2190,6 +2328,7 @@ function useEditorView(config) {
|
|
|
2190
2328
|
const pmJSON = toProseMirrorJSON(doc2);
|
|
2191
2329
|
const pmDoc = PMNode.fromJSON(actionbookSchema, pmJSON);
|
|
2192
2330
|
const tr = view.state.tr.replaceWith(0, view.state.doc.content.size, pmDoc.content);
|
|
2331
|
+
tr.setMeta("addToHistory", false);
|
|
2193
2332
|
view.dispatch(tr);
|
|
2194
2333
|
}, []);
|
|
2195
2334
|
const focus = useCallback(() => {
|
|
@@ -2199,9 +2338,11 @@ function useEditorView(config) {
|
|
|
2199
2338
|
viewInstanceRef.current?.destroy();
|
|
2200
2339
|
viewInstanceRef.current = null;
|
|
2201
2340
|
}, []);
|
|
2341
|
+
const getView = useCallback(() => viewInstanceRef.current, []);
|
|
2202
2342
|
return {
|
|
2203
2343
|
viewRef,
|
|
2204
2344
|
view: viewInstanceRef.current,
|
|
2345
|
+
getView,
|
|
2205
2346
|
getAST,
|
|
2206
2347
|
getMarkdown,
|
|
2207
2348
|
setContent,
|
|
@@ -2211,10 +2352,15 @@ function useEditorView(config) {
|
|
|
2211
2352
|
}
|
|
2212
2353
|
|
|
2213
2354
|
// src/ui/plugin/inputRulesPlugin.ts
|
|
2214
|
-
import { InputRule, wrappingInputRule } from "prosemirror-inputrules";
|
|
2355
|
+
import { InputRule, textblockTypeInputRule, wrappingInputRule } from "prosemirror-inputrules";
|
|
2356
|
+
import { TextSelection } from "prosemirror-state";
|
|
2357
|
+
var HEADING_RE = /^(#{1,6})\s$/;
|
|
2358
|
+
var BLOCKQUOTE_RE = /^\s*>\s$/;
|
|
2359
|
+
var CODE_BLOCK_RE = /^```([a-zA-Z0-9]*)$/;
|
|
2360
|
+
var HR_RE = /^([-*_])\1{2,}$/;
|
|
2215
2361
|
var BULLET_LIST_RE = /^\s*([-*])\s$/;
|
|
2216
2362
|
var ORDERED_LIST_RE = /^(\d+)\.\s$/;
|
|
2217
|
-
var JUMP_POINT_RE2 = /\^([A-Za-z_]
|
|
2363
|
+
var JUMP_POINT_RE2 = /\^([A-Za-z_]+)\^$/;
|
|
2218
2364
|
var BOLD_STAR_RE = /(?:^|[^*])\*\*([^*]+)\*\*$/;
|
|
2219
2365
|
var BOLD_UNDER_RE = /(?:^|[^_])__([^_]+)__$/;
|
|
2220
2366
|
var ITALIC_STAR_RE = /(?:^|[^*])\*([^*]+)\*$/;
|
|
@@ -2225,11 +2371,14 @@ function markInputRule(pattern, markType, markerLen) {
|
|
|
2225
2371
|
return new InputRule(pattern, (state, match, start, end) => {
|
|
2226
2372
|
const textContent2 = match[1];
|
|
2227
2373
|
const fullMatch = match[0];
|
|
2228
|
-
const
|
|
2374
|
+
const markedLength = markerLen * 2 + textContent2.length;
|
|
2375
|
+
const prefixLen = fullMatch.length - markedLength;
|
|
2376
|
+
const deleteFrom = start + prefixLen;
|
|
2229
2377
|
const tr = state.tr;
|
|
2230
|
-
tr.delete(
|
|
2378
|
+
tr.delete(deleteFrom, end);
|
|
2231
2379
|
const textNode = state.schema.text(textContent2, [markType.create()]);
|
|
2232
|
-
tr.insert(
|
|
2380
|
+
tr.insert(deleteFrom, textNode);
|
|
2381
|
+
tr.removeStoredMark(markType);
|
|
2233
2382
|
return tr;
|
|
2234
2383
|
});
|
|
2235
2384
|
}
|
|
@@ -2238,12 +2387,41 @@ function createInputRulesPlugin() {
|
|
|
2238
2387
|
name: "inputRules",
|
|
2239
2388
|
inputRules: () => {
|
|
2240
2389
|
const rules = [];
|
|
2241
|
-
rules.push(wrappingInputRule(BULLET_LIST_RE, actionbookSchema.nodes.bulletList));
|
|
2242
2390
|
rules.push(
|
|
2243
|
-
|
|
2244
|
-
|
|
2391
|
+
textblockTypeInputRule(HEADING_RE, actionbookSchema.nodes.heading, (match) => ({
|
|
2392
|
+
level: match[1].length
|
|
2245
2393
|
}))
|
|
2246
2394
|
);
|
|
2395
|
+
rules.push(wrappingInputRule(BLOCKQUOTE_RE, actionbookSchema.nodes.blockquote));
|
|
2396
|
+
rules.push(
|
|
2397
|
+
new InputRule(CODE_BLOCK_RE, (state, match, start, end) => {
|
|
2398
|
+
const language = match[1] || null;
|
|
2399
|
+
const $start = state.doc.resolve(start);
|
|
2400
|
+
const blockStart = $start.before($start.depth);
|
|
2401
|
+
const blockEnd = $start.after($start.depth);
|
|
2402
|
+
const tr = state.tr;
|
|
2403
|
+
tr.replaceWith(
|
|
2404
|
+
blockStart,
|
|
2405
|
+
blockEnd,
|
|
2406
|
+
actionbookSchema.nodes.codeBlock.create({ language })
|
|
2407
|
+
);
|
|
2408
|
+
return tr;
|
|
2409
|
+
})
|
|
2410
|
+
);
|
|
2411
|
+
rules.push(
|
|
2412
|
+
new InputRule(HR_RE, (state, _match, start, end) => {
|
|
2413
|
+
const { horizontalRule: hrType, paragraph: pType } = actionbookSchema.nodes;
|
|
2414
|
+
const $start = state.doc.resolve(start);
|
|
2415
|
+
const blockStart = $start.before($start.depth);
|
|
2416
|
+
const blockEnd = $start.after($start.depth);
|
|
2417
|
+
const tr = state.tr;
|
|
2418
|
+
tr.replaceWith(blockStart, blockEnd, [hrType.create(), pType.create()]);
|
|
2419
|
+
tr.setSelection(
|
|
2420
|
+
TextSelection.near(tr.doc.resolve(blockStart + hrType.createAndFill().nodeSize + 1))
|
|
2421
|
+
);
|
|
2422
|
+
return tr;
|
|
2423
|
+
})
|
|
2424
|
+
);
|
|
2247
2425
|
rules.push(
|
|
2248
2426
|
new InputRule(/^\s*[-*]\s\[([ xX])\]\s$/, (state, match, start, end) => {
|
|
2249
2427
|
const checked = match[1] !== " ";
|
|
@@ -2253,6 +2431,12 @@ function createInputRulesPlugin() {
|
|
|
2253
2431
|
return state.tr.delete(start, end).insert(start, list);
|
|
2254
2432
|
})
|
|
2255
2433
|
);
|
|
2434
|
+
rules.push(wrappingInputRule(BULLET_LIST_RE, actionbookSchema.nodes.bulletList));
|
|
2435
|
+
rules.push(
|
|
2436
|
+
wrappingInputRule(ORDERED_LIST_RE, actionbookSchema.nodes.orderedList, (match) => ({
|
|
2437
|
+
start: +match[1]
|
|
2438
|
+
}))
|
|
2439
|
+
);
|
|
2256
2440
|
const jumpPointType = actionbookSchema.nodes.jumpPoint;
|
|
2257
2441
|
rules.push(
|
|
2258
2442
|
new InputRule(JUMP_POINT_RE2, (state, match, start, end) => {
|
|
@@ -2279,24 +2463,85 @@ function createInputRulesPlugin() {
|
|
|
2279
2463
|
};
|
|
2280
2464
|
}
|
|
2281
2465
|
|
|
2466
|
+
// src/ui/plugin/historyPlugin.ts
|
|
2467
|
+
import { history, undo, redo } from "prosemirror-history";
|
|
2468
|
+
import { keymap as keymap2 } from "prosemirror-keymap";
|
|
2469
|
+
function createHistoryPlugin() {
|
|
2470
|
+
return {
|
|
2471
|
+
name: "history",
|
|
2472
|
+
plugins: () => [
|
|
2473
|
+
history(),
|
|
2474
|
+
keymap2({ "Mod-z": undo, "Mod-Shift-z": redo, "Mod-y": redo })
|
|
2475
|
+
]
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2282
2479
|
// src/ui/plugin/keymapPlugin.ts
|
|
2283
|
-
import { chainCommands, newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock, toggleMark } from "prosemirror-commands";
|
|
2480
|
+
import { baseKeymap, chainCommands, newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock, toggleMark, setBlockType, joinBackward } from "prosemirror-commands";
|
|
2481
|
+
import { keymap as keymap3 } from "prosemirror-keymap";
|
|
2284
2482
|
import { liftListItem, sinkListItem, splitListItem, wrapInList } from "prosemirror-schema-list";
|
|
2285
2483
|
var TAB_CHAR = " ";
|
|
2286
|
-
var { listItem, bulletList, orderedList, hardBreak } = actionbookSchema.nodes;
|
|
2484
|
+
var { listItem, bulletList, orderedList, hardBreak, heading, paragraph, horizontalRule, blockquote } = actionbookSchema.nodes;
|
|
2287
2485
|
var { bold: boldMark, italic: italicMark, underline: underlineMark, strikethrough: strikethroughMark, code: codeMark } = actionbookSchema.marks;
|
|
2288
2486
|
function cursorDirectlyInListItem(state) {
|
|
2289
2487
|
const { $from } = state.selection;
|
|
2290
2488
|
return $from.depth >= 2 && $from.node($from.depth - 1).type === listItem;
|
|
2291
2489
|
}
|
|
2292
|
-
var
|
|
2490
|
+
var backspaceAfterList = (state, dispatch) => {
|
|
2293
2491
|
const { $from } = state.selection;
|
|
2294
2492
|
if (!state.selection.empty) return false;
|
|
2295
2493
|
if ($from.parentOffset !== 0) return false;
|
|
2296
|
-
if (
|
|
2297
|
-
if ($from.
|
|
2298
|
-
|
|
2494
|
+
if ($from.parent.type !== paragraph) return false;
|
|
2495
|
+
if ($from.parent.content.size !== 0) return false;
|
|
2496
|
+
const parentDepth = $from.depth - 1;
|
|
2497
|
+
if (parentDepth < 0) return false;
|
|
2498
|
+
const indexInParent = $from.index(parentDepth);
|
|
2499
|
+
if (indexInParent === 0) return false;
|
|
2500
|
+
const prevNode = $from.node(parentDepth).child(indexInParent - 1);
|
|
2501
|
+
const isList = prevNode.type === bulletList || prevNode.type === orderedList;
|
|
2502
|
+
if (!isList) return false;
|
|
2503
|
+
if (dispatch) {
|
|
2504
|
+
const from = $from.before($from.depth);
|
|
2505
|
+
const to = $from.after($from.depth);
|
|
2506
|
+
const tr = state.tr.delete(from, to);
|
|
2507
|
+
dispatch(tr.scrollIntoView());
|
|
2508
|
+
}
|
|
2509
|
+
return true;
|
|
2510
|
+
};
|
|
2511
|
+
var backspaceAfterLeafBlock = (state, dispatch) => {
|
|
2512
|
+
const { $from } = state.selection;
|
|
2513
|
+
if (!state.selection.empty) return false;
|
|
2514
|
+
if ($from.parentOffset !== 0) return false;
|
|
2515
|
+
if ($from.parent.type !== paragraph) return false;
|
|
2516
|
+
if ($from.parent.content.size !== 0) return false;
|
|
2517
|
+
const parentDepth = $from.depth - 1;
|
|
2518
|
+
if (parentDepth < 0) return false;
|
|
2519
|
+
const indexInParent = $from.index(parentDepth);
|
|
2520
|
+
if (indexInParent === 0) return false;
|
|
2521
|
+
const prevNode = $from.node(parentDepth).child(indexInParent - 1);
|
|
2522
|
+
if (prevNode.type !== horizontalRule) return false;
|
|
2523
|
+
if (dispatch) {
|
|
2524
|
+
const hrPos = $from.posAtIndex(indexInParent - 1, parentDepth);
|
|
2525
|
+
dispatch(state.tr.delete(hrPos, hrPos + prevNode.nodeSize).scrollIntoView());
|
|
2526
|
+
}
|
|
2527
|
+
return true;
|
|
2299
2528
|
};
|
|
2529
|
+
var backspaceCommand = chainCommands(
|
|
2530
|
+
backspaceAfterList,
|
|
2531
|
+
backspaceAfterLeafBlock,
|
|
2532
|
+
(state, dispatch) => {
|
|
2533
|
+
const { $from } = state.selection;
|
|
2534
|
+
if (!state.selection.empty) return false;
|
|
2535
|
+
if ($from.parentOffset !== 0) return false;
|
|
2536
|
+
if ($from.parent.type === heading) {
|
|
2537
|
+
return setBlockType(paragraph)(state, dispatch);
|
|
2538
|
+
}
|
|
2539
|
+
if (!cursorDirectlyInListItem(state)) return false;
|
|
2540
|
+
if ($from.index($from.depth - 1) !== 0) return false;
|
|
2541
|
+
return liftListItem(listItem)(state, dispatch);
|
|
2542
|
+
},
|
|
2543
|
+
joinBackward
|
|
2544
|
+
);
|
|
2300
2545
|
var tabCommand = (state, dispatch) => {
|
|
2301
2546
|
const { $from } = state.selection;
|
|
2302
2547
|
if (cursorDirectlyInListItem(state) && $from.parentOffset === 0) {
|
|
@@ -2349,12 +2594,13 @@ function createKeymapPlugin() {
|
|
|
2349
2594
|
"Mod-e": toggleMark(codeMark),
|
|
2350
2595
|
"Mod-Shift-7": wrapInList(bulletList),
|
|
2351
2596
|
"Mod-Shift-8": wrapInList(orderedList)
|
|
2352
|
-
})
|
|
2597
|
+
}),
|
|
2598
|
+
plugins: () => [keymap3(baseKeymap)]
|
|
2353
2599
|
};
|
|
2354
2600
|
}
|
|
2355
2601
|
|
|
2356
2602
|
// src/ui/plugin/markdownClipboard.ts
|
|
2357
|
-
import { Fragment, Slice } from "prosemirror-model";
|
|
2603
|
+
import { DOMParser as ProseMirrorDOMParser, Fragment, Slice } from "prosemirror-model";
|
|
2358
2604
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
2359
2605
|
|
|
2360
2606
|
// src/ast/traverse.ts
|
|
@@ -2370,6 +2616,7 @@ function getChildren(node) {
|
|
|
2370
2616
|
case "doc":
|
|
2371
2617
|
case "blockquote":
|
|
2372
2618
|
case "listItem":
|
|
2619
|
+
case "noteBlock":
|
|
2373
2620
|
return node.content;
|
|
2374
2621
|
case "paragraph":
|
|
2375
2622
|
case "heading":
|
|
@@ -3841,6 +4088,23 @@ var gfmNoAutolinkFromMarkdown = () => [
|
|
|
3841
4088
|
gfmTaskListItemFromMarkdown()
|
|
3842
4089
|
];
|
|
3843
4090
|
var MAX_DEPTH5 = 128;
|
|
4091
|
+
var BRACKET_LINK_RE = /\[([^\]]+)\]\(([^)]*\s[^)]*)\)/g;
|
|
4092
|
+
function splitTextWithBracketLinks(value) {
|
|
4093
|
+
const results = [];
|
|
4094
|
+
let lastIndex = 0;
|
|
4095
|
+
for (const m of value.matchAll(BRACKET_LINK_RE)) {
|
|
4096
|
+
const idx = m.index;
|
|
4097
|
+
if (idx > lastIndex) results.push({ type: "text", value: value.slice(lastIndex, idx) });
|
|
4098
|
+
results.push({
|
|
4099
|
+
type: "link",
|
|
4100
|
+
url: m[2],
|
|
4101
|
+
children: [{ type: "text", value: m[1] }]
|
|
4102
|
+
});
|
|
4103
|
+
lastIndex = idx + m[0].length;
|
|
4104
|
+
}
|
|
4105
|
+
if (lastIndex < value.length) results.push({ type: "text", value: value.slice(lastIndex) });
|
|
4106
|
+
return results;
|
|
4107
|
+
}
|
|
3844
4108
|
function combinedTokensFromMarkdown(node, depth = 0) {
|
|
3845
4109
|
if (depth > MAX_DEPTH5) return;
|
|
3846
4110
|
if (!node.children) return;
|
|
@@ -3852,13 +4116,20 @@ function combinedTokensFromMarkdown(node, depth = 0) {
|
|
|
3852
4116
|
for (const child of node.children) {
|
|
3853
4117
|
const c = child;
|
|
3854
4118
|
if (c.type === "text") {
|
|
3855
|
-
const
|
|
3856
|
-
for (const
|
|
3857
|
-
if (
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
}
|
|
3861
|
-
|
|
4119
|
+
const afterLinks = splitTextWithBracketLinks(child.value);
|
|
4120
|
+
for (const linkPart of afterLinks) {
|
|
4121
|
+
if (linkPart.type !== "text") {
|
|
4122
|
+
newChildren.push(linkPart);
|
|
4123
|
+
continue;
|
|
4124
|
+
}
|
|
4125
|
+
const afterResourceTags = splitTextWithResourceTags(linkPart.value);
|
|
4126
|
+
for (const part of afterResourceTags) {
|
|
4127
|
+
if (part.type === "text") {
|
|
4128
|
+
const afterJumpPoints = splitTextWithJumpPoints(part.value);
|
|
4129
|
+
newChildren.push(...afterJumpPoints);
|
|
4130
|
+
} else {
|
|
4131
|
+
newChildren.push(part);
|
|
4132
|
+
}
|
|
3862
4133
|
}
|
|
3863
4134
|
}
|
|
3864
4135
|
} else {
|
|
@@ -4065,77 +4336,479 @@ function analyzeJinjaBlocks(doc2) {
|
|
|
4065
4336
|
});
|
|
4066
4337
|
}
|
|
4067
4338
|
|
|
4068
|
-
// src/
|
|
4069
|
-
var
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4339
|
+
// src/jinja/conditionHighlighter.ts
|
|
4340
|
+
var KEYWORDS = {
|
|
4341
|
+
and: "AND",
|
|
4342
|
+
or: "OR",
|
|
4343
|
+
not: "NOT",
|
|
4344
|
+
in: "IN",
|
|
4345
|
+
is: "IS",
|
|
4346
|
+
True: "BOOL",
|
|
4347
|
+
False: "BOOL",
|
|
4348
|
+
true: "BOOL",
|
|
4349
|
+
false: "BOOL",
|
|
4350
|
+
None: "NONE",
|
|
4351
|
+
null: "NONE"
|
|
4352
|
+
};
|
|
4353
|
+
var CATEGORY_BY_TYPE = {
|
|
4354
|
+
STRING: "value",
|
|
4355
|
+
NUMBER: "value",
|
|
4356
|
+
BOOL: "value",
|
|
4357
|
+
NONE: "value",
|
|
4358
|
+
IDENT: "variable",
|
|
4359
|
+
AND: "operator",
|
|
4360
|
+
OR: "operator",
|
|
4361
|
+
NOT: "operator",
|
|
4362
|
+
IN: "operator",
|
|
4363
|
+
IS: "operator",
|
|
4364
|
+
EQ: "operator",
|
|
4365
|
+
NEQ: "operator",
|
|
4366
|
+
LT: "operator",
|
|
4367
|
+
GT: "operator",
|
|
4368
|
+
LTE: "operator",
|
|
4369
|
+
GTE: "operator",
|
|
4370
|
+
LPAREN: "punctuation",
|
|
4371
|
+
RPAREN: "punctuation"
|
|
4372
|
+
};
|
|
4373
|
+
var NEGATIVE_NUMBER_PRECEDERS = /* @__PURE__ */ new Set([
|
|
4374
|
+
"AND",
|
|
4375
|
+
"OR",
|
|
4376
|
+
"NOT",
|
|
4377
|
+
"IN",
|
|
4378
|
+
"IS",
|
|
4379
|
+
"EQ",
|
|
4380
|
+
"NEQ",
|
|
4381
|
+
"LT",
|
|
4382
|
+
"GT",
|
|
4383
|
+
"LTE",
|
|
4384
|
+
"GTE",
|
|
4385
|
+
"LPAREN"
|
|
4386
|
+
]);
|
|
4387
|
+
function canStartNegativeNumber(tokens) {
|
|
4388
|
+
if (tokens.length === 0) {
|
|
4389
|
+
return true;
|
|
4390
|
+
}
|
|
4391
|
+
const previous = tokens[tokens.length - 1];
|
|
4392
|
+
return NEGATIVE_NUMBER_PRECEDERS.has(previous.type);
|
|
4393
|
+
}
|
|
4394
|
+
function finalizeTokens(input, rawTokens) {
|
|
4395
|
+
const highlighted = [];
|
|
4396
|
+
for (let i = 0; i < rawTokens.length; i++) {
|
|
4397
|
+
const token = rawTokens[i];
|
|
4398
|
+
const next = rawTokens[i + 1];
|
|
4399
|
+
if (token.type === "IS" && next?.type === "NOT") {
|
|
4400
|
+
highlighted.push({
|
|
4401
|
+
text: input.slice(token.start, next.end),
|
|
4402
|
+
start: token.start,
|
|
4403
|
+
end: next.end,
|
|
4404
|
+
category: "operator"
|
|
4405
|
+
});
|
|
4406
|
+
i++;
|
|
4407
|
+
continue;
|
|
4408
|
+
}
|
|
4409
|
+
highlighted.push({
|
|
4410
|
+
text: token.text,
|
|
4411
|
+
start: token.start,
|
|
4412
|
+
end: token.end,
|
|
4413
|
+
category: CATEGORY_BY_TYPE[token.type]
|
|
4080
4414
|
});
|
|
4081
|
-
const astNodes = parseFragment(deduped);
|
|
4082
|
-
const pmJSONNodes = astNodesToJSONContent(astNodes);
|
|
4083
|
-
const pmNodes = pmJSONNodes.map((json) => actionbookSchema.nodeFromJSON(json));
|
|
4084
|
-
const fragment = Fragment.fromArray(pmNodes);
|
|
4085
|
-
const openDepth = pmJSONNodes.length === 1 && pmJSONNodes[0].type === "paragraph" ? 1 : 0;
|
|
4086
|
-
return new Slice(fragment, openDepth, openDepth);
|
|
4087
|
-
} catch {
|
|
4088
|
-
return null;
|
|
4089
4415
|
}
|
|
4416
|
+
return highlighted;
|
|
4090
4417
|
}
|
|
4091
|
-
function
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
return new Slice(Fragment.from(textNode), 0, 0);
|
|
4418
|
+
function tokenizeCondition(input) {
|
|
4419
|
+
const rawTokens = [];
|
|
4420
|
+
let i = 0;
|
|
4421
|
+
while (i < input.length) {
|
|
4422
|
+
const char = input[i];
|
|
4423
|
+
if (/\s/.test(char)) {
|
|
4424
|
+
i++;
|
|
4425
|
+
continue;
|
|
4426
|
+
}
|
|
4427
|
+
if (char === '"' || char === "'") {
|
|
4428
|
+
const start = i;
|
|
4429
|
+
const quote = char;
|
|
4430
|
+
i++;
|
|
4431
|
+
while (i < input.length) {
|
|
4432
|
+
if (input[i] === "\\" && i + 1 < input.length) {
|
|
4433
|
+
i += 2;
|
|
4434
|
+
continue;
|
|
4109
4435
|
}
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
slice.content.forEach((node) => jsonNodes.push(node.toJSON()));
|
|
4120
|
-
const doc2 = fromProseMirrorJSON({ type: "doc", content: jsonNodes });
|
|
4121
|
-
return serializeFragment(doc2.content);
|
|
4122
|
-
} catch {
|
|
4123
|
-
return "";
|
|
4436
|
+
if (input[i] === quote) {
|
|
4437
|
+
i++;
|
|
4438
|
+
rawTokens.push({
|
|
4439
|
+
type: "STRING",
|
|
4440
|
+
text: input.slice(start, i),
|
|
4441
|
+
start,
|
|
4442
|
+
end: i
|
|
4443
|
+
});
|
|
4444
|
+
break;
|
|
4124
4445
|
}
|
|
4446
|
+
i++;
|
|
4447
|
+
}
|
|
4448
|
+
if (rawTokens[rawTokens.length - 1]?.start !== start) {
|
|
4449
|
+
return finalizeTokens(input, rawTokens);
|
|
4125
4450
|
}
|
|
4451
|
+
continue;
|
|
4126
4452
|
}
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
}
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4453
|
+
if (/[0-9]/.test(char) || char === "-" && i + 1 < input.length && /[0-9]/.test(input[i + 1]) && canStartNegativeNumber(rawTokens)) {
|
|
4454
|
+
const start = i;
|
|
4455
|
+
if (input[i] === "-") {
|
|
4456
|
+
i++;
|
|
4457
|
+
}
|
|
4458
|
+
while (i < input.length && /[0-9]/.test(input[i])) {
|
|
4459
|
+
i++;
|
|
4460
|
+
}
|
|
4461
|
+
if (i < input.length && input[i] === ".") {
|
|
4462
|
+
i++;
|
|
4463
|
+
while (i < input.length && /[0-9]/.test(input[i])) {
|
|
4464
|
+
i++;
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
rawTokens.push({
|
|
4468
|
+
type: "NUMBER",
|
|
4469
|
+
text: input.slice(start, i),
|
|
4470
|
+
start,
|
|
4471
|
+
end: i
|
|
4472
|
+
});
|
|
4473
|
+
continue;
|
|
4474
|
+
}
|
|
4475
|
+
if (/[a-zA-Z_]/.test(char)) {
|
|
4476
|
+
const start = i;
|
|
4477
|
+
i++;
|
|
4478
|
+
while (i < input.length && /[a-zA-Z0-9_.]/.test(input[i])) {
|
|
4479
|
+
i++;
|
|
4480
|
+
}
|
|
4481
|
+
const text2 = input.slice(start, i);
|
|
4482
|
+
rawTokens.push({
|
|
4483
|
+
type: KEYWORDS[text2] ?? "IDENT",
|
|
4484
|
+
text: text2,
|
|
4485
|
+
start,
|
|
4486
|
+
end: i
|
|
4487
|
+
});
|
|
4488
|
+
continue;
|
|
4489
|
+
}
|
|
4490
|
+
if (i + 1 < input.length) {
|
|
4491
|
+
const twoChar = input.slice(i, i + 2);
|
|
4492
|
+
if (twoChar === "==") {
|
|
4493
|
+
rawTokens.push({ type: "EQ", text: twoChar, start: i, end: i + 2 });
|
|
4494
|
+
i += 2;
|
|
4495
|
+
continue;
|
|
4496
|
+
}
|
|
4497
|
+
if (twoChar === "!=") {
|
|
4498
|
+
rawTokens.push({ type: "NEQ", text: twoChar, start: i, end: i + 2 });
|
|
4499
|
+
i += 2;
|
|
4500
|
+
continue;
|
|
4501
|
+
}
|
|
4502
|
+
if (twoChar === "<=") {
|
|
4503
|
+
rawTokens.push({ type: "LTE", text: twoChar, start: i, end: i + 2 });
|
|
4504
|
+
i += 2;
|
|
4505
|
+
continue;
|
|
4506
|
+
}
|
|
4507
|
+
if (twoChar === ">=") {
|
|
4508
|
+
rawTokens.push({ type: "GTE", text: twoChar, start: i, end: i + 2 });
|
|
4509
|
+
i += 2;
|
|
4510
|
+
continue;
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4513
|
+
if (char === "<") {
|
|
4514
|
+
rawTokens.push({ type: "LT", text: char, start: i, end: i + 1 });
|
|
4515
|
+
i++;
|
|
4516
|
+
continue;
|
|
4517
|
+
}
|
|
4518
|
+
if (char === ">") {
|
|
4519
|
+
rawTokens.push({ type: "GT", text: char, start: i, end: i + 1 });
|
|
4520
|
+
i++;
|
|
4521
|
+
continue;
|
|
4522
|
+
}
|
|
4523
|
+
if (char === "(") {
|
|
4524
|
+
rawTokens.push({ type: "LPAREN", text: char, start: i, end: i + 1 });
|
|
4525
|
+
i++;
|
|
4526
|
+
continue;
|
|
4527
|
+
}
|
|
4528
|
+
if (char === ")") {
|
|
4529
|
+
rawTokens.push({ type: "RPAREN", text: char, start: i, end: i + 1 });
|
|
4530
|
+
i++;
|
|
4531
|
+
continue;
|
|
4532
|
+
}
|
|
4533
|
+
return finalizeTokens(input, rawTokens);
|
|
4534
|
+
}
|
|
4535
|
+
return finalizeTokens(input, rawTokens);
|
|
4536
|
+
}
|
|
4537
|
+
|
|
4538
|
+
// src/tree/documentTree.ts
|
|
4539
|
+
var MAX_DEPTH6 = 128;
|
|
4540
|
+
function extractInlineItems(content, blockIndex) {
|
|
4541
|
+
const items = [];
|
|
4542
|
+
for (const node of content) {
|
|
4543
|
+
if (node.type === "jumpPoint") {
|
|
4544
|
+
items.push({
|
|
4545
|
+
type: "jumpPoint",
|
|
4546
|
+
label: node.id,
|
|
4547
|
+
blockIndex,
|
|
4548
|
+
children: []
|
|
4549
|
+
});
|
|
4550
|
+
} else if (node.type === "resourceTag") {
|
|
4551
|
+
const isEndAction = node.tagType === "handoff";
|
|
4552
|
+
items.push({
|
|
4553
|
+
type: isEndAction ? "endAction" : "resourceTag",
|
|
4554
|
+
label: isEndAction ? `End ${node.text}` : node.text,
|
|
4555
|
+
blockIndex,
|
|
4556
|
+
children: [],
|
|
4557
|
+
meta: { tagType: node.tagType, resourceId: node.resourceId }
|
|
4558
|
+
});
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
return items;
|
|
4562
|
+
}
|
|
4563
|
+
function extractBlockItems(blocks, startIndex, depth) {
|
|
4564
|
+
if (depth > MAX_DEPTH6) return [];
|
|
4565
|
+
const items = [];
|
|
4566
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
4567
|
+
const block = blocks[i];
|
|
4568
|
+
const blockIndex = startIndex + i;
|
|
4569
|
+
switch (block.type) {
|
|
4570
|
+
case "heading": {
|
|
4571
|
+
const label = textContent(block) || `Heading ${block.level}`;
|
|
4572
|
+
const inlineItems = extractInlineItems(block.content, blockIndex);
|
|
4573
|
+
items.push({
|
|
4574
|
+
type: "heading",
|
|
4575
|
+
label,
|
|
4576
|
+
blockIndex,
|
|
4577
|
+
children: inlineItems,
|
|
4578
|
+
meta: { level: block.level }
|
|
4579
|
+
});
|
|
4580
|
+
break;
|
|
4581
|
+
}
|
|
4582
|
+
case "paragraph": {
|
|
4583
|
+
const inlineItems = extractInlineItems(block.content, blockIndex);
|
|
4584
|
+
items.push(...inlineItems);
|
|
4585
|
+
break;
|
|
4586
|
+
}
|
|
4587
|
+
case "jinjaIfBlock": {
|
|
4588
|
+
const branches = block.branches.map((branch) => {
|
|
4589
|
+
const branchLabel = branch.branchType === "else" ? "ELSE" : `${branch.branchType.toUpperCase()} ${branch.condition || ""}`.trim();
|
|
4590
|
+
const branchChildren = extractBlockItems(branch.content, blockIndex, depth + 1);
|
|
4591
|
+
return {
|
|
4592
|
+
type: "jinjaBranch",
|
|
4593
|
+
label: branchLabel,
|
|
4594
|
+
blockIndex,
|
|
4595
|
+
children: branchChildren
|
|
4596
|
+
};
|
|
4597
|
+
});
|
|
4598
|
+
items.push({
|
|
4599
|
+
type: "jinjaIf",
|
|
4600
|
+
label: "Jinja if",
|
|
4601
|
+
blockIndex,
|
|
4602
|
+
children: branches
|
|
4603
|
+
});
|
|
4604
|
+
break;
|
|
4605
|
+
}
|
|
4606
|
+
case "noteBlock": {
|
|
4607
|
+
const noteContent = textContent(block);
|
|
4608
|
+
items.push({
|
|
4609
|
+
type: "noteBlock",
|
|
4610
|
+
label: noteContent ? `Note: ${noteContent.slice(0, 30)}` : "Note",
|
|
4611
|
+
blockIndex,
|
|
4612
|
+
children: []
|
|
4613
|
+
});
|
|
4614
|
+
break;
|
|
4615
|
+
}
|
|
4616
|
+
case "bulletList":
|
|
4617
|
+
case "orderedList": {
|
|
4618
|
+
for (const li of block.content) {
|
|
4619
|
+
const childItems = extractBlockItems(li.content, blockIndex, depth + 1);
|
|
4620
|
+
items.push(...childItems);
|
|
4621
|
+
}
|
|
4622
|
+
break;
|
|
4623
|
+
}
|
|
4624
|
+
case "blockquote": {
|
|
4625
|
+
const childItems = extractBlockItems(block.content, blockIndex, depth + 1);
|
|
4626
|
+
items.push(...childItems);
|
|
4627
|
+
break;
|
|
4628
|
+
}
|
|
4629
|
+
default:
|
|
4630
|
+
break;
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
return items;
|
|
4634
|
+
}
|
|
4635
|
+
function buildDocumentTree(doc2) {
|
|
4636
|
+
const items = extractBlockItems(doc2.content, 0, 0);
|
|
4637
|
+
try {
|
|
4638
|
+
const structures = analyzeJinjaBlocks(doc2);
|
|
4639
|
+
if (structures.length > 0) {
|
|
4640
|
+
const hasStructuredJinja = items.some((n) => n.type === "jinjaIf");
|
|
4641
|
+
if (!hasStructuredJinja) {
|
|
4642
|
+
for (const s of structures) {
|
|
4643
|
+
const branches = s.branches.map((b) => ({
|
|
4644
|
+
type: "jinjaBranch",
|
|
4645
|
+
label: b.type === "else" ? "ELSE" : `${b.type.toUpperCase()} ${b.condition || ""}`.trim(),
|
|
4646
|
+
blockIndex: b.tagBlockIndex,
|
|
4647
|
+
children: []
|
|
4648
|
+
}));
|
|
4649
|
+
const jinjaNode = {
|
|
4650
|
+
type: "jinjaIf",
|
|
4651
|
+
label: "Jinja if",
|
|
4652
|
+
blockIndex: s.ifTagBlockIndex,
|
|
4653
|
+
children: branches
|
|
4654
|
+
};
|
|
4655
|
+
let inserted = false;
|
|
4656
|
+
for (let i = 0; i < items.length; i++) {
|
|
4657
|
+
if (items[i].blockIndex > s.ifTagBlockIndex) {
|
|
4658
|
+
items.splice(i, 0, jinjaNode);
|
|
4659
|
+
inserted = true;
|
|
4660
|
+
break;
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
if (!inserted) items.push(jinjaNode);
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
} catch {
|
|
4668
|
+
}
|
|
4669
|
+
return items;
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
// src/ui/plugin/markdownClipboard.ts
|
|
4673
|
+
var key = new PluginKey("markdownClipboard");
|
|
4674
|
+
var MAX_PASTE_LIST_DEPTH = 3;
|
|
4675
|
+
var MAX_FLATTEN_DEPTH = 128;
|
|
4676
|
+
function flattenDeepLists(node, listDepth = 0, _recurseDepth = 0) {
|
|
4677
|
+
if (_recurseDepth > MAX_FLATTEN_DEPTH) return node;
|
|
4678
|
+
const isList = node.type.name === "bulletList" || node.type.name === "orderedList";
|
|
4679
|
+
const currentDepth = isList ? listDepth + 1 : listDepth;
|
|
4680
|
+
if (isList && currentDepth >= MAX_PASTE_LIST_DEPTH) {
|
|
4681
|
+
const flatItems = [];
|
|
4682
|
+
node.forEach((li) => {
|
|
4683
|
+
const nonListBlocks = [];
|
|
4684
|
+
li.forEach((block) => {
|
|
4685
|
+
if (block.type.name !== "bulletList" && block.type.name !== "orderedList") {
|
|
4686
|
+
nonListBlocks.push(block);
|
|
4687
|
+
}
|
|
4688
|
+
});
|
|
4689
|
+
if (nonListBlocks.length > 0) {
|
|
4690
|
+
flatItems.push(li.type.create(li.attrs, nonListBlocks));
|
|
4691
|
+
}
|
|
4692
|
+
});
|
|
4693
|
+
if (flatItems.length === 0) return node;
|
|
4694
|
+
return node.copy(Fragment.fromArray(flatItems));
|
|
4695
|
+
}
|
|
4696
|
+
const children = [];
|
|
4697
|
+
let changed = false;
|
|
4698
|
+
node.forEach((child) => {
|
|
4699
|
+
const flattened = flattenDeepLists(child, currentDepth, _recurseDepth + 1);
|
|
4700
|
+
if (flattened !== child) changed = true;
|
|
4701
|
+
children.push(flattened);
|
|
4702
|
+
});
|
|
4703
|
+
if (!changed) return node;
|
|
4704
|
+
return node.copy(Fragment.fromArray(children));
|
|
4705
|
+
}
|
|
4706
|
+
function htmlToSlice(html) {
|
|
4707
|
+
if (typeof document === "undefined") return null;
|
|
4708
|
+
try {
|
|
4709
|
+
const domParser = new DOMParser();
|
|
4710
|
+
const parsed = domParser.parseFromString(html, "text/html");
|
|
4711
|
+
const body = parsed.body;
|
|
4712
|
+
if (!body || !body.childNodes.length) return null;
|
|
4713
|
+
const pmParser = ProseMirrorDOMParser.fromSchema(actionbookSchema);
|
|
4714
|
+
const doc2 = pmParser.parse(body);
|
|
4715
|
+
const flattened = flattenDeepLists(doc2);
|
|
4716
|
+
const content = flattened.content;
|
|
4717
|
+
let hasContent = false;
|
|
4718
|
+
content.forEach((node) => {
|
|
4719
|
+
if (node.type.name !== "paragraph" || node.content.size > 0) {
|
|
4720
|
+
hasContent = true;
|
|
4721
|
+
}
|
|
4722
|
+
});
|
|
4723
|
+
if (!hasContent) return null;
|
|
4724
|
+
const openDepth = content.childCount === 1 && content.firstChild?.type.name === "paragraph" ? 1 : 0;
|
|
4725
|
+
return new Slice(content, openDepth, openDepth);
|
|
4726
|
+
} catch {
|
|
4727
|
+
return null;
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
function textToSlice(text2, view) {
|
|
4731
|
+
try {
|
|
4732
|
+
const existingIds = /* @__PURE__ */ new Set();
|
|
4733
|
+
view.state.doc.descendants((node) => {
|
|
4734
|
+
if (node.type.name === "jumpPoint") existingIds.add(node.attrs.id);
|
|
4735
|
+
});
|
|
4736
|
+
const deduped = text2.replace(/\^([A-Za-z_][A-Za-z0-9_]*)\^/gm, (match, id) => {
|
|
4737
|
+
if (existingIds.has(id)) return id;
|
|
4738
|
+
existingIds.add(id);
|
|
4739
|
+
return match;
|
|
4740
|
+
});
|
|
4741
|
+
const astNodes = parseFragment(deduped);
|
|
4742
|
+
const pmJSONNodes = astNodesToJSONContent(astNodes);
|
|
4743
|
+
const pmNodes = pmJSONNodes.map((json) => actionbookSchema.nodeFromJSON(json));
|
|
4744
|
+
const fragment = Fragment.fromArray(pmNodes);
|
|
4745
|
+
const openDepth = pmJSONNodes.length === 1 && pmJSONNodes[0].type === "paragraph" ? 1 : 0;
|
|
4746
|
+
return new Slice(fragment, openDepth, openDepth);
|
|
4747
|
+
} catch {
|
|
4748
|
+
return null;
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
function createPlugin() {
|
|
4752
|
+
return new Plugin({
|
|
4753
|
+
key,
|
|
4754
|
+
props: {
|
|
4755
|
+
handlePaste(view, event) {
|
|
4756
|
+
const html = event.clipboardData?.getData("text/html");
|
|
4757
|
+
const text2 = event.clipboardData?.getData("text/plain");
|
|
4758
|
+
if (html) {
|
|
4759
|
+
const htmlSlice = htmlToSlice(html);
|
|
4760
|
+
if (htmlSlice) {
|
|
4761
|
+
view.dispatch(view.state.tr.replaceSelection(htmlSlice));
|
|
4762
|
+
return true;
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
if (!text2) return false;
|
|
4766
|
+
const slice = textToSlice(text2, view);
|
|
4767
|
+
if (!slice) return false;
|
|
4768
|
+
view.dispatch(view.state.tr.replaceSelection(slice));
|
|
4769
|
+
return true;
|
|
4770
|
+
},
|
|
4771
|
+
clipboardTextParser(text2, _$context, _plain, view) {
|
|
4772
|
+
if (!text2) return Slice.empty;
|
|
4773
|
+
const slice = textToSlice(text2, view);
|
|
4774
|
+
if (!slice) {
|
|
4775
|
+
const textNode = actionbookSchema.text(text2);
|
|
4776
|
+
return new Slice(Fragment.from(textNode), 0, 0);
|
|
4777
|
+
}
|
|
4778
|
+
return slice;
|
|
4779
|
+
},
|
|
4780
|
+
// Transform pasted HTML: keep structure but flatten deep lists
|
|
4781
|
+
// to prevent Chrome contentEditable hanging
|
|
4782
|
+
transformPasted(slice) {
|
|
4783
|
+
const nodes = [];
|
|
4784
|
+
slice.content.forEach((node) => {
|
|
4785
|
+
nodes.push(flattenDeepLists(node));
|
|
4786
|
+
});
|
|
4787
|
+
return new Slice(Fragment.fromArray(nodes), slice.openStart, slice.openEnd);
|
|
4788
|
+
},
|
|
4789
|
+
clipboardTextSerializer(slice) {
|
|
4790
|
+
try {
|
|
4791
|
+
const jsonNodes = [];
|
|
4792
|
+
slice.content.forEach((node) => jsonNodes.push(node.toJSON()));
|
|
4793
|
+
const doc2 = fromProseMirrorJSON({ type: "doc", content: jsonNodes });
|
|
4794
|
+
return serializeFragment(doc2.content);
|
|
4795
|
+
} catch {
|
|
4796
|
+
return "";
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
}
|
|
4800
|
+
});
|
|
4801
|
+
}
|
|
4802
|
+
function createMarkdownClipboardPlugin() {
|
|
4803
|
+
return {
|
|
4804
|
+
name: "markdownClipboard",
|
|
4805
|
+
plugins: () => [createPlugin()]
|
|
4806
|
+
};
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
// src/ui/plugin/jumpPointPlugin.ts
|
|
4810
|
+
import { Plugin as Plugin2, PluginKey as PluginKey2, TextSelection as TextSelection2 } from "prosemirror-state";
|
|
4811
|
+
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
4139
4812
|
var adjacentKey = new PluginKey2("jumpPointAdjacent");
|
|
4140
4813
|
var JUMP_POINT_ADJACENT_SPEC = { jumpPointAdjacent: true };
|
|
4141
4814
|
function buildDecorations(state) {
|
|
@@ -4205,8 +4878,15 @@ function createJumpPointEditPlugin() {
|
|
|
4205
4878
|
}
|
|
4206
4879
|
});
|
|
4207
4880
|
}
|
|
4208
|
-
function
|
|
4881
|
+
function jumpPointAtOrBefore(state) {
|
|
4209
4882
|
const { selection } = state;
|
|
4883
|
+
if ("node" in selection) {
|
|
4884
|
+
const node = selection.node;
|
|
4885
|
+
if (node?.type?.name === "jumpPoint") {
|
|
4886
|
+
return { id: node.attrs.id, nodeStart: selection.from, nodeEnd: selection.to };
|
|
4887
|
+
}
|
|
4888
|
+
return null;
|
|
4889
|
+
}
|
|
4210
4890
|
if (!selection.empty) return null;
|
|
4211
4891
|
const { $from } = selection;
|
|
4212
4892
|
const nodeBefore = $from.nodeBefore;
|
|
@@ -4216,23 +4896,23 @@ function jumpPointBefore(state) {
|
|
|
4216
4896
|
return { id: nodeBefore.attrs.id, nodeStart, nodeEnd };
|
|
4217
4897
|
}
|
|
4218
4898
|
function explodeOnBackspace(state) {
|
|
4219
|
-
const info =
|
|
4899
|
+
const info = jumpPointAtOrBefore(state);
|
|
4220
4900
|
if (!info) return null;
|
|
4221
4901
|
const { id, nodeStart, nodeEnd } = info;
|
|
4222
4902
|
const rawText = `^${id}`;
|
|
4223
4903
|
const tr = state.tr.replaceWith(nodeStart, nodeEnd, state.schema.text(rawText));
|
|
4224
4904
|
const cursorPos = Math.min(nodeStart + rawText.length, tr.doc.content.size);
|
|
4225
|
-
tr.setSelection(
|
|
4905
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(cursorPos)));
|
|
4226
4906
|
return tr;
|
|
4227
4907
|
}
|
|
4228
4908
|
function explodeOnArrowLeft(state) {
|
|
4229
|
-
const info =
|
|
4909
|
+
const info = jumpPointAtOrBefore(state);
|
|
4230
4910
|
if (!info) return null;
|
|
4231
4911
|
const { id, nodeStart, nodeEnd } = info;
|
|
4232
4912
|
const rawText = `^${id}^`;
|
|
4233
4913
|
const tr = state.tr.replaceWith(nodeStart, nodeEnd, state.schema.text(rawText));
|
|
4234
4914
|
const cursorPos = Math.min(nodeStart + 1 + id.length, tr.doc.content.size);
|
|
4235
|
-
tr.setSelection(
|
|
4915
|
+
tr.setSelection(TextSelection2.near(tr.doc.resolve(cursorPos)));
|
|
4236
4916
|
tr.setMeta(jumpPointEditKey, { from: nodeStart, to: nodeStart + rawText.length });
|
|
4237
4917
|
return tr;
|
|
4238
4918
|
}
|
|
@@ -4279,6 +4959,7 @@ function createJumpPointAdjacentPlugin() {
|
|
|
4279
4959
|
}
|
|
4280
4960
|
|
|
4281
4961
|
// src/ui/plugin/jumpPointNodeViewPlugin.tsx
|
|
4962
|
+
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
4282
4963
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4283
4964
|
var JUMP_POINT_STYLE = {
|
|
4284
4965
|
display: "inline-flex",
|
|
@@ -4286,31 +4967,118 @@ var JUMP_POINT_STYLE = {
|
|
|
4286
4967
|
backgroundColor: "#FFF2B6",
|
|
4287
4968
|
border: "1px solid #FFC233",
|
|
4288
4969
|
color: "#AA5D04",
|
|
4289
|
-
borderRadius: "
|
|
4290
|
-
padding: "
|
|
4291
|
-
fontSize: "
|
|
4292
|
-
lineHeight:
|
|
4970
|
+
borderRadius: "2px",
|
|
4971
|
+
padding: "2px",
|
|
4972
|
+
fontSize: "12px",
|
|
4973
|
+
lineHeight: "16px",
|
|
4293
4974
|
userSelect: "none",
|
|
4294
4975
|
cursor: "default",
|
|
4295
|
-
boxSizing: "border-box"
|
|
4976
|
+
boxSizing: "border-box",
|
|
4977
|
+
height: "20px",
|
|
4978
|
+
overflow: "hidden"
|
|
4296
4979
|
};
|
|
4297
4980
|
var JUMP_POINT_ADJACENT_STYLE = {
|
|
4298
4981
|
...JUMP_POINT_STYLE,
|
|
4299
4982
|
backgroundColor: "#FFE680",
|
|
4300
4983
|
borderColor: "#FF9500"
|
|
4301
4984
|
};
|
|
4302
|
-
|
|
4985
|
+
var JUMP_POINT_DUPLICATE_STYLE = {
|
|
4986
|
+
...JUMP_POINT_STYLE,
|
|
4987
|
+
backgroundColor: "#FFD9DD",
|
|
4988
|
+
borderColor: "#D9352C",
|
|
4989
|
+
color: "#9D091E"
|
|
4990
|
+
};
|
|
4991
|
+
var LABEL_STYLE = {
|
|
4992
|
+
padding: "0 4px",
|
|
4993
|
+
whiteSpace: "nowrap"
|
|
4994
|
+
};
|
|
4995
|
+
var CLOSE_BTN_STYLE = {
|
|
4996
|
+
display: "inline-flex",
|
|
4997
|
+
alignItems: "center",
|
|
4998
|
+
justifyContent: "center",
|
|
4999
|
+
width: "16px",
|
|
5000
|
+
height: "16px",
|
|
5001
|
+
padding: 0,
|
|
5002
|
+
border: "none",
|
|
5003
|
+
background: "transparent",
|
|
5004
|
+
cursor: "pointer",
|
|
5005
|
+
borderRadius: "1px",
|
|
5006
|
+
flexShrink: 0,
|
|
5007
|
+
color: "inherit",
|
|
5008
|
+
fontSize: "10px",
|
|
5009
|
+
lineHeight: 1
|
|
5010
|
+
};
|
|
5011
|
+
var TOOLTIP_STYLE = {
|
|
5012
|
+
position: "absolute",
|
|
5013
|
+
bottom: "calc(100% + 8px)",
|
|
5014
|
+
left: "50%",
|
|
5015
|
+
transform: "translateX(-50%)",
|
|
5016
|
+
backgroundColor: "#fff",
|
|
5017
|
+
border: "1px solid #CCC",
|
|
5018
|
+
borderRadius: "4px",
|
|
5019
|
+
boxShadow: "0 8px 10px rgba(13,13,13,0.12), 0 3px 14px rgba(13,13,13,0.08), 0 3px 5px rgba(13,13,13,0.04)",
|
|
5020
|
+
padding: "16px 20px",
|
|
5021
|
+
fontSize: "14px",
|
|
5022
|
+
lineHeight: "20px",
|
|
5023
|
+
color: "#0D0D0D",
|
|
5024
|
+
whiteSpace: "nowrap",
|
|
5025
|
+
zIndex: 100,
|
|
5026
|
+
pointerEvents: "none"
|
|
5027
|
+
};
|
|
5028
|
+
function JumpPointNodeViewComponent({ node, view, getPos, decorations }) {
|
|
4303
5029
|
const id = node.attrs.id;
|
|
4304
5030
|
const isAdjacent = decorations?.some((d) => d.spec?.jumpPointAdjacent === true) ?? false;
|
|
5031
|
+
const isDuplicate = decorations?.some((d) => d.spec?.jumpPointDuplicate === true) ?? false;
|
|
5032
|
+
const [showTooltip, setShowTooltip] = useState2(false);
|
|
5033
|
+
const handleDelete2 = useCallback2(() => {
|
|
5034
|
+
const pos = getPos();
|
|
5035
|
+
if (pos == null) return;
|
|
5036
|
+
const tr = view.state.tr.delete(pos, pos + node.nodeSize);
|
|
5037
|
+
view.dispatch(tr);
|
|
5038
|
+
view.focus();
|
|
5039
|
+
}, [view, getPos, node.nodeSize]);
|
|
5040
|
+
if (isDuplicate) {
|
|
5041
|
+
return /* @__PURE__ */ jsxs3(
|
|
5042
|
+
"span",
|
|
5043
|
+
{
|
|
5044
|
+
style: { ...JUMP_POINT_DUPLICATE_STYLE, position: "relative" },
|
|
5045
|
+
id: `jp-${id}`,
|
|
5046
|
+
onMouseEnter: () => setShowTooltip(true),
|
|
5047
|
+
onMouseLeave: () => setShowTooltip(false),
|
|
5048
|
+
children: [
|
|
5049
|
+
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#9D091E", style: { paddingLeft: "2px", flexShrink: 0 } }),
|
|
5050
|
+
/* @__PURE__ */ jsx4("span", { style: LABEL_STYLE, children: id }),
|
|
5051
|
+
/* @__PURE__ */ jsx4(
|
|
5052
|
+
"button",
|
|
5053
|
+
{
|
|
5054
|
+
style: CLOSE_BTN_STYLE,
|
|
5055
|
+
onMouseDown: (e) => {
|
|
5056
|
+
e.preventDefault();
|
|
5057
|
+
e.stopPropagation();
|
|
5058
|
+
handleDelete2();
|
|
5059
|
+
},
|
|
5060
|
+
title: "Remove anchor",
|
|
5061
|
+
children: "\u2715"
|
|
5062
|
+
}
|
|
5063
|
+
),
|
|
5064
|
+
showTooltip && /* @__PURE__ */ jsxs3("span", { style: TOOLTIP_STYLE, children: [
|
|
5065
|
+
"\u201C",
|
|
5066
|
+
id,
|
|
5067
|
+
"\u201D is already used as an anchor"
|
|
5068
|
+
] })
|
|
5069
|
+
]
|
|
5070
|
+
}
|
|
5071
|
+
);
|
|
5072
|
+
}
|
|
4305
5073
|
if (isAdjacent) {
|
|
4306
5074
|
return /* @__PURE__ */ jsxs3("span", { style: JUMP_POINT_ADJACENT_STYLE, id: `jp-${id}`, children: [
|
|
4307
|
-
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: {
|
|
4308
|
-
`^${id}^`
|
|
5075
|
+
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }),
|
|
5076
|
+
/* @__PURE__ */ jsx4("span", { style: LABEL_STYLE, children: `^${id}^` })
|
|
4309
5077
|
] });
|
|
4310
5078
|
}
|
|
4311
5079
|
return /* @__PURE__ */ jsxs3("span", { style: JUMP_POINT_STYLE, id: `jp-${id}`, children: [
|
|
4312
|
-
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: {
|
|
4313
|
-
id
|
|
5080
|
+
/* @__PURE__ */ jsx4(IconAnchor, { size: 12, fill: "#AA5D04", style: { paddingLeft: "2px", flexShrink: 0 } }),
|
|
5081
|
+
/* @__PURE__ */ jsx4("span", { style: LABEL_STYLE, children: id })
|
|
4314
5082
|
] });
|
|
4315
5083
|
}
|
|
4316
5084
|
function createJumpPointNodeViewPlugin() {
|
|
@@ -4322,6 +5090,105 @@ function createJumpPointNodeViewPlugin() {
|
|
|
4322
5090
|
};
|
|
4323
5091
|
}
|
|
4324
5092
|
|
|
5093
|
+
// src/ui/plugin/jumpPointValidationPlugin.ts
|
|
5094
|
+
import { Plugin as Plugin3, PluginKey as PluginKey3 } from "prosemirror-state";
|
|
5095
|
+
import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "prosemirror-view";
|
|
5096
|
+
var pluginKey = new PluginKey3("jumpPointValidation");
|
|
5097
|
+
function collectJumpPointIds(state) {
|
|
5098
|
+
const ids = /* @__PURE__ */ new Set();
|
|
5099
|
+
state.doc.descendants((node) => {
|
|
5100
|
+
if (node.type.name === "jumpPoint") {
|
|
5101
|
+
ids.add(node.attrs.id);
|
|
5102
|
+
}
|
|
5103
|
+
});
|
|
5104
|
+
return ids;
|
|
5105
|
+
}
|
|
5106
|
+
function findDuplicatePositions(state) {
|
|
5107
|
+
const idCount = /* @__PURE__ */ new Map();
|
|
5108
|
+
const nodes = [];
|
|
5109
|
+
state.doc.descendants((node, pos) => {
|
|
5110
|
+
if (node.type.name === "jumpPoint") {
|
|
5111
|
+
const id = node.attrs.id;
|
|
5112
|
+
idCount.set(id, (idCount.get(id) ?? 0) + 1);
|
|
5113
|
+
nodes.push({ id, pos, size: node.nodeSize });
|
|
5114
|
+
}
|
|
5115
|
+
});
|
|
5116
|
+
return nodes.filter((n) => (idCount.get(n.id) ?? 0) > 1);
|
|
5117
|
+
}
|
|
5118
|
+
function findBrokenAnchorRefs(state, existingIds) {
|
|
5119
|
+
const broken = [];
|
|
5120
|
+
const linkMarkType = state.schema.marks.link;
|
|
5121
|
+
if (!linkMarkType) return broken;
|
|
5122
|
+
state.doc.descendants((node, pos) => {
|
|
5123
|
+
if (!node.isText) return;
|
|
5124
|
+
const linkMark2 = node.marks.find((m) => m.type === linkMarkType);
|
|
5125
|
+
if (!linkMark2) return;
|
|
5126
|
+
const href = linkMark2.attrs.href;
|
|
5127
|
+
if (!href || !href.startsWith("#")) return;
|
|
5128
|
+
const refId = href.slice(1);
|
|
5129
|
+
if (refId && !existingIds.has(refId)) {
|
|
5130
|
+
broken.push({ from: pos, to: pos + node.nodeSize, refId });
|
|
5131
|
+
}
|
|
5132
|
+
});
|
|
5133
|
+
return broken;
|
|
5134
|
+
}
|
|
5135
|
+
function hasDuplicateJumpPoints(state) {
|
|
5136
|
+
return findDuplicatePositions(state).length > 0;
|
|
5137
|
+
}
|
|
5138
|
+
function hasBrokenAnchorRefs(state) {
|
|
5139
|
+
const ids = collectJumpPointIds(state);
|
|
5140
|
+
return findBrokenAnchorRefs(state, ids).length > 0;
|
|
5141
|
+
}
|
|
5142
|
+
function createJumpPointValidationPlugin() {
|
|
5143
|
+
return {
|
|
5144
|
+
name: "jumpPointValidation",
|
|
5145
|
+
plugins: () => [
|
|
5146
|
+
new Plugin3({
|
|
5147
|
+
key: pluginKey,
|
|
5148
|
+
state: {
|
|
5149
|
+
init(_, state) {
|
|
5150
|
+
return buildDecorations2(state);
|
|
5151
|
+
},
|
|
5152
|
+
apply(tr, oldSet, _oldState, newState) {
|
|
5153
|
+
if (tr.docChanged) {
|
|
5154
|
+
return buildDecorations2(newState);
|
|
5155
|
+
}
|
|
5156
|
+
return oldSet.map(tr.mapping, tr.doc);
|
|
5157
|
+
}
|
|
5158
|
+
},
|
|
5159
|
+
props: {
|
|
5160
|
+
decorations(state) {
|
|
5161
|
+
return pluginKey.getState(state) ?? DecorationSet2.empty;
|
|
5162
|
+
}
|
|
5163
|
+
}
|
|
5164
|
+
})
|
|
5165
|
+
]
|
|
5166
|
+
};
|
|
5167
|
+
}
|
|
5168
|
+
function buildDecorations2(state) {
|
|
5169
|
+
const decos = [];
|
|
5170
|
+
const duplicates = findDuplicatePositions(state);
|
|
5171
|
+
for (const { pos, size } of duplicates) {
|
|
5172
|
+
decos.push(
|
|
5173
|
+
Decoration2.node(pos, pos + size, { class: "jump-point-duplicate" }, { jumpPointDuplicate: true })
|
|
5174
|
+
);
|
|
5175
|
+
}
|
|
5176
|
+
const existingIds = collectJumpPointIds(state);
|
|
5177
|
+
const brokenRefs = findBrokenAnchorRefs(state, existingIds);
|
|
5178
|
+
for (const { from, to, refId } of brokenRefs) {
|
|
5179
|
+
decos.push(
|
|
5180
|
+
Decoration2.inline(from, to, {
|
|
5181
|
+
class: "broken-anchor-ref",
|
|
5182
|
+
"data-broken-ref": refId,
|
|
5183
|
+
title: `Anchor "${refId}" no longer exists`,
|
|
5184
|
+
style: "color: #D9352C; text-decoration-color: #D9352C;"
|
|
5185
|
+
})
|
|
5186
|
+
);
|
|
5187
|
+
}
|
|
5188
|
+
if (decos.length === 0) return DecorationSet2.empty;
|
|
5189
|
+
return DecorationSet2.create(state.doc, decos);
|
|
5190
|
+
}
|
|
5191
|
+
|
|
4325
5192
|
// src/ui/plugin/inlineToolTagNodeViewPlugin.tsx
|
|
4326
5193
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
4327
5194
|
var RESOURCE_TAG_COLORS2 = {
|
|
@@ -4340,9 +5207,12 @@ var RESOURCE_TAG_ICONS2 = {
|
|
|
4340
5207
|
time_diff: IconTimeDiff
|
|
4341
5208
|
};
|
|
4342
5209
|
var DEFAULT_ICON = IconTool;
|
|
5210
|
+
var RESOURCE_ID_OVERRIDES = {
|
|
5211
|
+
"close-happy-tiger": { color: "#0D0D0D", icon: IconStop }
|
|
5212
|
+
};
|
|
4343
5213
|
var OUTER_STYLE = {
|
|
4344
5214
|
display: "inline-flex",
|
|
4345
|
-
padding: "
|
|
5215
|
+
padding: "2px",
|
|
4346
5216
|
border: "1px solid #CCCCCC",
|
|
4347
5217
|
borderRadius: "2px",
|
|
4348
5218
|
alignItems: "center",
|
|
@@ -4362,16 +5232,19 @@ var ICON_BLOCK_BASE = {
|
|
|
4362
5232
|
};
|
|
4363
5233
|
var LABEL_BASE = {
|
|
4364
5234
|
padding: "0 4px",
|
|
4365
|
-
fontSize: "
|
|
4366
|
-
lineHeight:
|
|
5235
|
+
fontSize: "12px",
|
|
5236
|
+
lineHeight: "16px",
|
|
4367
5237
|
userSelect: "none"
|
|
4368
5238
|
};
|
|
4369
|
-
function InlineToolTagNodeViewComponent({ node }) {
|
|
5239
|
+
function InlineToolTagNodeViewComponent({ node, selected }) {
|
|
4370
5240
|
const type = node.attrs.type;
|
|
4371
5241
|
const text2 = node.attrs.text;
|
|
4372
|
-
const
|
|
4373
|
-
const
|
|
4374
|
-
|
|
5242
|
+
const resourceId = node.attrs.resourceId;
|
|
5243
|
+
const override = RESOURCE_ID_OVERRIDES[resourceId];
|
|
5244
|
+
const color = override?.color ?? RESOURCE_TAG_COLORS2[type] ?? DEFAULT_COLOR;
|
|
5245
|
+
const Icon = override?.icon ?? RESOURCE_TAG_ICONS2[type] ?? DEFAULT_ICON;
|
|
5246
|
+
const style = selected ? { ...OUTER_STYLE, boxShadow: `inset 0 0 0 1px ${color}` } : OUTER_STYLE;
|
|
5247
|
+
return /* @__PURE__ */ jsxs4("span", { style, "data-type": type, "data-resource-id": node.attrs.resourceId, children: [
|
|
4375
5248
|
/* @__PURE__ */ jsx5("span", { style: { ...ICON_BLOCK_BASE, backgroundColor: color }, children: /* @__PURE__ */ jsx5(Icon, { size: 9, fill: "white" }) }),
|
|
4376
5249
|
/* @__PURE__ */ jsx5("span", { style: { ...LABEL_BASE, color }, children: text2 })
|
|
4377
5250
|
] });
|
|
@@ -4386,9 +5259,9 @@ function createInlineToolTagNodeViewPlugin() {
|
|
|
4386
5259
|
}
|
|
4387
5260
|
|
|
4388
5261
|
// src/ui/plugin/jinjaDecoration.ts
|
|
4389
|
-
import { Plugin as
|
|
4390
|
-
import { Decoration as
|
|
4391
|
-
var jinjaPluginKey = new
|
|
5262
|
+
import { Plugin as Plugin4, PluginKey as PluginKey4 } from "prosemirror-state";
|
|
5263
|
+
import { Decoration as Decoration3, DecorationSet as DecorationSet3 } from "prosemirror-view";
|
|
5264
|
+
var jinjaPluginKey = new PluginKey4("jinjaDecoration");
|
|
4392
5265
|
var JINJA_TAG_RE = /\{%\s*(if|elif|else|endif)\s*([^%]*?)\s*%\}/g;
|
|
4393
5266
|
function getBlockPositions(doc2) {
|
|
4394
5267
|
const blocks = [];
|
|
@@ -4410,90 +5283,940 @@ function addInlineChipDecorations(doc2, decorations) {
|
|
|
4410
5283
|
const to = from + match[0].length;
|
|
4411
5284
|
const keyword = match[1];
|
|
4412
5285
|
decorations.push(
|
|
4413
|
-
|
|
5286
|
+
Decoration3.inline(from, to, {
|
|
4414
5287
|
class: `jinja-chip jinja-chip-${keyword}`
|
|
4415
5288
|
})
|
|
4416
5289
|
);
|
|
4417
5290
|
}
|
|
4418
5291
|
});
|
|
4419
5292
|
}
|
|
4420
|
-
function addStructureBorderDecorations(doc2, blocks, decorations) {
|
|
4421
|
-
const json = doc2.toJSON();
|
|
4422
|
-
let ast;
|
|
4423
|
-
try {
|
|
4424
|
-
ast = fromProseMirrorJSON(json);
|
|
4425
|
-
} catch {
|
|
4426
|
-
return;
|
|
5293
|
+
function addStructureBorderDecorations(doc2, blocks, decorations) {
|
|
5294
|
+
const json = doc2.toJSON();
|
|
5295
|
+
let ast;
|
|
5296
|
+
try {
|
|
5297
|
+
ast = fromProseMirrorJSON(json);
|
|
5298
|
+
} catch {
|
|
5299
|
+
return;
|
|
5300
|
+
}
|
|
5301
|
+
const structures = analyzeJinjaBlocks(ast);
|
|
5302
|
+
for (const structure of structures) {
|
|
5303
|
+
const blockBranchType = /* @__PURE__ */ new Map();
|
|
5304
|
+
for (const branch of structure.branches) {
|
|
5305
|
+
blockBranchType.set(branch.tagBlockIndex, branch.type);
|
|
5306
|
+
for (let i = branch.blockStartIndex; i < branch.blockEndIndex; i++) {
|
|
5307
|
+
if (!blockBranchType.has(i)) {
|
|
5308
|
+
blockBranchType.set(i, branch.type);
|
|
5309
|
+
}
|
|
5310
|
+
}
|
|
5311
|
+
}
|
|
5312
|
+
const lastBranch = structure.branches[structure.branches.length - 1];
|
|
5313
|
+
if (lastBranch && !blockBranchType.has(structure.endifTagBlockIndex)) {
|
|
5314
|
+
blockBranchType.set(structure.endifTagBlockIndex, lastBranch.type);
|
|
5315
|
+
}
|
|
5316
|
+
const first = structure.ifTagBlockIndex;
|
|
5317
|
+
const last = structure.endifTagBlockIndex;
|
|
5318
|
+
for (let i = first; i <= last; i++) {
|
|
5319
|
+
const block = blocks[i];
|
|
5320
|
+
if (!block) continue;
|
|
5321
|
+
const branchType = blockBranchType.get(i) || "if";
|
|
5322
|
+
const prevType = i > first ? blockBranchType.get(i - 1) : void 0;
|
|
5323
|
+
const nextType = i < last ? blockBranchType.get(i + 1) : void 0;
|
|
5324
|
+
const classes = ["jinja-bar", `jinja-bar-${branchType}`];
|
|
5325
|
+
if (i === first || prevType !== branchType) classes.push("jinja-bar-first");
|
|
5326
|
+
if (i === last || nextType !== branchType) classes.push("jinja-bar-last");
|
|
5327
|
+
decorations.push(Decoration3.node(block.from, block.to, { class: classes.join(" ") }));
|
|
5328
|
+
}
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5331
|
+
function hasJinjaTags(doc2) {
|
|
5332
|
+
let found = false;
|
|
5333
|
+
doc2.descendants((node) => {
|
|
5334
|
+
if (found) return false;
|
|
5335
|
+
if (node.isText && node.text.includes("{%")) {
|
|
5336
|
+
found = true;
|
|
5337
|
+
return false;
|
|
5338
|
+
}
|
|
5339
|
+
});
|
|
5340
|
+
return found;
|
|
5341
|
+
}
|
|
5342
|
+
function buildDecorations3(doc2) {
|
|
5343
|
+
if (!hasJinjaTags(doc2)) return DecorationSet3.empty;
|
|
5344
|
+
const blocks = getBlockPositions(doc2);
|
|
5345
|
+
const decorations = [];
|
|
5346
|
+
addInlineChipDecorations(doc2, decorations);
|
|
5347
|
+
addStructureBorderDecorations(doc2, blocks, decorations);
|
|
5348
|
+
if (decorations.length === 0) return DecorationSet3.empty;
|
|
5349
|
+
return DecorationSet3.create(doc2, decorations);
|
|
5350
|
+
}
|
|
5351
|
+
function createJinjaDecorationPlugin() {
|
|
5352
|
+
return {
|
|
5353
|
+
name: "jinjaDecoration",
|
|
5354
|
+
plugins: () => [
|
|
5355
|
+
new Plugin4({
|
|
5356
|
+
key: jinjaPluginKey,
|
|
5357
|
+
state: {
|
|
5358
|
+
init(_, state) {
|
|
5359
|
+
return buildDecorations3(state.doc);
|
|
5360
|
+
},
|
|
5361
|
+
apply(tr, oldDecos) {
|
|
5362
|
+
if (!tr.docChanged) return oldDecos;
|
|
5363
|
+
return buildDecorations3(tr.doc);
|
|
5364
|
+
}
|
|
5365
|
+
},
|
|
5366
|
+
props: {
|
|
5367
|
+
decorations(state) {
|
|
5368
|
+
return jinjaPluginKey.getState(state);
|
|
5369
|
+
}
|
|
5370
|
+
}
|
|
5371
|
+
})
|
|
5372
|
+
]
|
|
5373
|
+
};
|
|
5374
|
+
}
|
|
5375
|
+
|
|
5376
|
+
// src/ui/plugin/jinjaIfBlockPlugin.tsx
|
|
5377
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
5378
|
+
import { createRoot as createRoot2 } from "react-dom/client";
|
|
5379
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
5380
|
+
var PLACEHOLDER_TEXT = "Describe what AI agent should do when this condition is met";
|
|
5381
|
+
var CONDITION_PLACEHOLDER = "Write a condition in natural language";
|
|
5382
|
+
var STYLE_ID = "ab-jinja-if-block-styles";
|
|
5383
|
+
var JINJA_STYLES = `
|
|
5384
|
+
.jinja-if-block {
|
|
5385
|
+
margin: 8px 0;
|
|
5386
|
+
}
|
|
5387
|
+
|
|
5388
|
+
.jinja-branch {
|
|
5389
|
+
position: relative;
|
|
5390
|
+
display: grid;
|
|
5391
|
+
grid-template-areas:
|
|
5392
|
+
"header"
|
|
5393
|
+
"body"
|
|
5394
|
+
"footer";
|
|
5395
|
+
gap: 0;
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5398
|
+
.jinja-branch-controls {
|
|
5399
|
+
display: contents;
|
|
5400
|
+
}
|
|
5401
|
+
|
|
5402
|
+
.jinja-branch-header {
|
|
5403
|
+
grid-area: header;
|
|
5404
|
+
display: flex;
|
|
5405
|
+
align-items: center;
|
|
5406
|
+
gap: 12px;
|
|
5407
|
+
padding: 8px;
|
|
5408
|
+
border: 1px solid #E0E0E0;
|
|
5409
|
+
border-radius: 4px;
|
|
5410
|
+
background: #FFFFFF;
|
|
5411
|
+
}
|
|
5412
|
+
|
|
5413
|
+
.jinja-branch-badge {
|
|
5414
|
+
display: inline-flex;
|
|
5415
|
+
align-items: center;
|
|
5416
|
+
justify-content: center;
|
|
5417
|
+
height: 32px;
|
|
5418
|
+
padding: 0 8px;
|
|
5419
|
+
border-radius: 4px;
|
|
5420
|
+
font-family: "Roboto Mono", monospace;
|
|
5421
|
+
font-size: 13px;
|
|
5422
|
+
font-weight: 700;
|
|
5423
|
+
line-height: 20px;
|
|
5424
|
+
letter-spacing: -0.3px;
|
|
5425
|
+
white-space: nowrap;
|
|
5426
|
+
flex-shrink: 0;
|
|
5427
|
+
}
|
|
5428
|
+
|
|
5429
|
+
.jinja-branch-badge-if,
|
|
5430
|
+
.jinja-branch-badge-elif {
|
|
5431
|
+
background: #E7F1FF;
|
|
5432
|
+
color: #0D0D0D;
|
|
5433
|
+
}
|
|
5434
|
+
|
|
5435
|
+
.jinja-branch-badge-else {
|
|
5436
|
+
background: #F7F7F7;
|
|
5437
|
+
color: #424242;
|
|
5438
|
+
}
|
|
5439
|
+
|
|
5440
|
+
.jinja-branch-condition {
|
|
5441
|
+
flex: 1;
|
|
5442
|
+
min-width: 0;
|
|
5443
|
+
display: flex;
|
|
5444
|
+
flex-wrap: wrap;
|
|
5445
|
+
gap: 8px;
|
|
5446
|
+
align-items: center;
|
|
5447
|
+
width: 100%;
|
|
5448
|
+
padding: 0;
|
|
5449
|
+
margin: 0;
|
|
5450
|
+
background: transparent;
|
|
5451
|
+
border: none;
|
|
5452
|
+
color: #0D0D0D;
|
|
5453
|
+
cursor: text;
|
|
5454
|
+
text-align: left;
|
|
5455
|
+
font-family: "Roboto Mono", monospace;
|
|
5456
|
+
font-size: 13px;
|
|
5457
|
+
line-height: 20px;
|
|
5458
|
+
letter-spacing: -0.3px;
|
|
5459
|
+
white-space: nowrap;
|
|
5460
|
+
}
|
|
5461
|
+
|
|
5462
|
+
.jinja-branch-condition:focus-visible,
|
|
5463
|
+
.jinja-ghost-btn:focus-visible,
|
|
5464
|
+
.jinja-popup-item:focus-visible {
|
|
5465
|
+
outline: 2px solid rgba(98, 16, 204, 0.28);
|
|
5466
|
+
outline-offset: 2px;
|
|
5467
|
+
}
|
|
5468
|
+
|
|
5469
|
+
.jinja-condition-placeholder {
|
|
5470
|
+
color: #A6A6A6;
|
|
5471
|
+
font-family: "Roboto Mono", monospace;
|
|
5472
|
+
font-size: 13px;
|
|
5473
|
+
line-height: 20px;
|
|
5474
|
+
letter-spacing: -0.3px;
|
|
5475
|
+
}
|
|
5476
|
+
|
|
5477
|
+
.jinja-token-variable {
|
|
5478
|
+
color: #4141B2;
|
|
5479
|
+
}
|
|
5480
|
+
|
|
5481
|
+
.jinja-token-operator {
|
|
5482
|
+
color: #858585;
|
|
5483
|
+
}
|
|
5484
|
+
|
|
5485
|
+
.jinja-token-value {
|
|
5486
|
+
color: #0D0D0D;
|
|
5487
|
+
}
|
|
5488
|
+
|
|
5489
|
+
.jinja-token-punctuation {
|
|
5490
|
+
color: #858585;
|
|
5491
|
+
}
|
|
5492
|
+
|
|
5493
|
+
.jinja-otherwise {
|
|
5494
|
+
flex: 1;
|
|
5495
|
+
color: #858585;
|
|
5496
|
+
font-family: "Roboto Mono", monospace;
|
|
5497
|
+
font-size: 13px;
|
|
5498
|
+
line-height: 20px;
|
|
5499
|
+
letter-spacing: -0.3px;
|
|
5500
|
+
}
|
|
5501
|
+
|
|
5502
|
+
.jinja-branch-actions,
|
|
5503
|
+
.jinja-add-footer-actions {
|
|
5504
|
+
position: relative;
|
|
5505
|
+
display: inline-flex;
|
|
5506
|
+
align-items: center;
|
|
5507
|
+
}
|
|
5508
|
+
|
|
5509
|
+
.jinja-branch-body {
|
|
5510
|
+
grid-area: body;
|
|
5511
|
+
display: flex;
|
|
5512
|
+
gap: 12px;
|
|
5513
|
+
padding: 0 8px;
|
|
5514
|
+
min-height: 52px;
|
|
5515
|
+
}
|
|
5516
|
+
|
|
5517
|
+
.jinja-branch-divider-col {
|
|
5518
|
+
width: 32px;
|
|
5519
|
+
flex-shrink: 0;
|
|
5520
|
+
display: flex;
|
|
5521
|
+
align-items: stretch;
|
|
5522
|
+
justify-content: center;
|
|
5523
|
+
}
|
|
5524
|
+
|
|
5525
|
+
.jinja-branch-divider {
|
|
5526
|
+
width: 1px;
|
|
5527
|
+
background: #E0E0E0;
|
|
5528
|
+
}
|
|
5529
|
+
|
|
5530
|
+
/* L-shaped divider for the last branch (ELSE) */
|
|
5531
|
+
.jinja-branch-last .jinja-branch-divider-col {
|
|
5532
|
+
align-items: flex-start;
|
|
5533
|
+
padding-left: 16px;
|
|
5534
|
+
}
|
|
5535
|
+
|
|
5536
|
+
.jinja-branch-last .jinja-branch-divider {
|
|
5537
|
+
width: 16px;
|
|
5538
|
+
height: 28px;
|
|
5539
|
+
background: none;
|
|
5540
|
+
border-left: 1px solid #E0E0E0;
|
|
5541
|
+
border-bottom: 1px solid #E0E0E0;
|
|
5542
|
+
border-bottom-left-radius: 8px;
|
|
5543
|
+
}
|
|
5544
|
+
|
|
5545
|
+
.jinja-branch-content {
|
|
5546
|
+
position: relative;
|
|
5547
|
+
flex: 1;
|
|
5548
|
+
min-width: 0;
|
|
5549
|
+
padding: 16px 0;
|
|
5550
|
+
}
|
|
5551
|
+
|
|
5552
|
+
.jinja-branch-content.jinja-branch-content-empty::before {
|
|
5553
|
+
content: attr(data-placeholder);
|
|
5554
|
+
position: absolute;
|
|
5555
|
+
top: 16px;
|
|
5556
|
+
left: 0;
|
|
5557
|
+
color: #A6A6A6;
|
|
5558
|
+
font-size: 14px;
|
|
5559
|
+
line-height: 20px;
|
|
5560
|
+
pointer-events: none;
|
|
5561
|
+
}
|
|
5562
|
+
|
|
5563
|
+
.jinja-add-footer {
|
|
5564
|
+
grid-area: footer;
|
|
5565
|
+
display: flex;
|
|
5566
|
+
padding: 8px;
|
|
5567
|
+
}
|
|
5568
|
+
|
|
5569
|
+
.jinja-add-footer .jinja-add-footer-col {
|
|
5570
|
+
width: 32px;
|
|
5571
|
+
flex-shrink: 0;
|
|
5572
|
+
display: flex;
|
|
5573
|
+
align-items: center;
|
|
5574
|
+
justify-content: center;
|
|
5575
|
+
}
|
|
5576
|
+
|
|
5577
|
+
.jinja-ghost-btn {
|
|
5578
|
+
width: 24px;
|
|
5579
|
+
height: 24px;
|
|
5580
|
+
display: inline-flex;
|
|
5581
|
+
align-items: center;
|
|
5582
|
+
justify-content: center;
|
|
5583
|
+
padding: 0;
|
|
5584
|
+
border: none;
|
|
5585
|
+
border-radius: 4px;
|
|
5586
|
+
background: transparent;
|
|
5587
|
+
color: #858585;
|
|
5588
|
+
cursor: pointer;
|
|
5589
|
+
}
|
|
5590
|
+
|
|
5591
|
+
.jinja-ghost-btn:hover:not(:disabled) {
|
|
5592
|
+
background: rgba(13, 13, 13, 0.04);
|
|
5593
|
+
}
|
|
5594
|
+
|
|
5595
|
+
.jinja-ghost-btn:disabled {
|
|
5596
|
+
opacity: 0.45;
|
|
5597
|
+
cursor: default;
|
|
5598
|
+
}
|
|
5599
|
+
|
|
5600
|
+
.jinja-popup-menu {
|
|
5601
|
+
position: absolute;
|
|
5602
|
+
z-index: 20;
|
|
5603
|
+
min-width: 200px;
|
|
5604
|
+
padding: 8px 0;
|
|
5605
|
+
background: #FFFFFF;
|
|
5606
|
+
border-radius: 4px;
|
|
5607
|
+
box-shadow: 0px 8px 10px 0px rgba(13,13,13,0.12), 0px 3px 14px 0px rgba(13,13,13,0.08), 0px 3px 5px 0px rgba(13,13,13,0.04);
|
|
5608
|
+
}
|
|
5609
|
+
|
|
5610
|
+
.jinja-popup-item {
|
|
5611
|
+
width: 100%;
|
|
5612
|
+
display: block;
|
|
5613
|
+
padding: 6px 16px;
|
|
5614
|
+
border: none;
|
|
5615
|
+
background: transparent;
|
|
5616
|
+
color: #0D0D0D;
|
|
5617
|
+
text-align: left;
|
|
5618
|
+
cursor: pointer;
|
|
5619
|
+
font-size: 14px;
|
|
5620
|
+
line-height: 20px;
|
|
5621
|
+
letter-spacing: -0.1px;
|
|
5622
|
+
}
|
|
5623
|
+
|
|
5624
|
+
.jinja-popup-item:hover:not(:disabled) {
|
|
5625
|
+
background: rgba(13, 13, 13, 0.04);
|
|
5626
|
+
}
|
|
5627
|
+
|
|
5628
|
+
.jinja-popup-item:disabled {
|
|
5629
|
+
color: #A6A6A6;
|
|
5630
|
+
cursor: default;
|
|
5631
|
+
}
|
|
5632
|
+
|
|
5633
|
+
.jinja-condition-input {
|
|
5634
|
+
width: 100%;
|
|
5635
|
+
min-width: 0;
|
|
5636
|
+
padding: 0;
|
|
5637
|
+
margin: 0;
|
|
5638
|
+
border: none;
|
|
5639
|
+
outline: none;
|
|
5640
|
+
background: transparent;
|
|
5641
|
+
color: #0D0D0D;
|
|
5642
|
+
caret-color: #6210CC;
|
|
5643
|
+
font-family: "Roboto Mono", monospace;
|
|
5644
|
+
font-size: 13px;
|
|
5645
|
+
line-height: 20px;
|
|
5646
|
+
letter-spacing: -0.3px;
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5649
|
+
.jinja-condition-input::placeholder {
|
|
5650
|
+
color: #A6A6A6;
|
|
5651
|
+
}
|
|
5652
|
+
`;
|
|
5653
|
+
var StyleManager = class {
|
|
5654
|
+
static refCount = 0;
|
|
5655
|
+
static styleEl = null;
|
|
5656
|
+
static acquire() {
|
|
5657
|
+
if (this.refCount++ > 0) return;
|
|
5658
|
+
const existing = document.getElementById(STYLE_ID);
|
|
5659
|
+
if (existing instanceof HTMLStyleElement) {
|
|
5660
|
+
this.styleEl = existing;
|
|
5661
|
+
return;
|
|
5662
|
+
}
|
|
5663
|
+
this.styleEl = document.createElement("style");
|
|
5664
|
+
this.styleEl.id = STYLE_ID;
|
|
5665
|
+
this.styleEl.textContent = JINJA_STYLES;
|
|
5666
|
+
document.head.appendChild(this.styleEl);
|
|
5667
|
+
}
|
|
5668
|
+
static release() {
|
|
5669
|
+
if (this.refCount === 0) return;
|
|
5670
|
+
if (--this.refCount > 0) return;
|
|
5671
|
+
if (this.styleEl?.parentNode) {
|
|
5672
|
+
this.styleEl.remove();
|
|
5673
|
+
}
|
|
5674
|
+
this.styleEl = null;
|
|
5675
|
+
}
|
|
5676
|
+
};
|
|
5677
|
+
function getBranchContext(view, nodePos) {
|
|
5678
|
+
try {
|
|
5679
|
+
const { doc: doc2 } = view.state;
|
|
5680
|
+
const resolved = doc2.resolve(nodePos);
|
|
5681
|
+
let blockDepth = -1;
|
|
5682
|
+
for (let depth = resolved.depth; depth >= 0; depth--) {
|
|
5683
|
+
if (resolved.node(depth).type.name === "jinjaIfBlock") {
|
|
5684
|
+
blockDepth = depth;
|
|
5685
|
+
break;
|
|
5686
|
+
}
|
|
5687
|
+
}
|
|
5688
|
+
if (blockDepth < 0) {
|
|
5689
|
+
return null;
|
|
5690
|
+
}
|
|
5691
|
+
const blockNode = resolved.node(blockDepth);
|
|
5692
|
+
const blockPos = blockDepth === 0 ? 0 : resolved.before(blockDepth);
|
|
5693
|
+
let branchOffset = blockPos + 1;
|
|
5694
|
+
for (let index = 0; index < blockNode.childCount; index++) {
|
|
5695
|
+
const branchNode = blockNode.child(index);
|
|
5696
|
+
if (branchOffset === nodePos) {
|
|
5697
|
+
return {
|
|
5698
|
+
blockNode,
|
|
5699
|
+
blockPos,
|
|
5700
|
+
branchNode,
|
|
5701
|
+
branchPos: branchOffset,
|
|
5702
|
+
branchIndex: index
|
|
5703
|
+
};
|
|
5704
|
+
}
|
|
5705
|
+
branchOffset += branchNode.nodeSize;
|
|
5706
|
+
}
|
|
5707
|
+
} catch {
|
|
5708
|
+
return null;
|
|
5709
|
+
}
|
|
5710
|
+
return null;
|
|
5711
|
+
}
|
|
5712
|
+
function isBranchBodyEmpty(node) {
|
|
5713
|
+
if (node.childCount !== 1) return false;
|
|
5714
|
+
const firstChild = node.firstChild;
|
|
5715
|
+
return firstChild?.type.name === "paragraph" && firstChild.content.size === 0;
|
|
5716
|
+
}
|
|
5717
|
+
function isBranchNode(node) {
|
|
5718
|
+
return node?.type.name === "jinjaIfBranch";
|
|
5719
|
+
}
|
|
5720
|
+
function createBranchNode(schema, branchType, condition) {
|
|
5721
|
+
const branchNodeType = schema.nodes.jinjaIfBranch;
|
|
5722
|
+
const paragraphNode = schema.nodes.paragraph?.createAndFill();
|
|
5723
|
+
if (!branchNodeType || !paragraphNode) {
|
|
5724
|
+
return null;
|
|
5725
|
+
}
|
|
5726
|
+
return branchNodeType.create(
|
|
5727
|
+
{
|
|
5728
|
+
branchType,
|
|
5729
|
+
condition: branchType === "else" ? "" : condition
|
|
5730
|
+
},
|
|
5731
|
+
paragraphNode
|
|
5732
|
+
);
|
|
5733
|
+
}
|
|
5734
|
+
function getLastBranchOfBlock(view, nodePos) {
|
|
5735
|
+
const context = getBranchContext(view, nodePos);
|
|
5736
|
+
if (!context || context.blockNode.childCount === 0) {
|
|
5737
|
+
return null;
|
|
5738
|
+
}
|
|
5739
|
+
const index = context.blockNode.childCount - 1;
|
|
5740
|
+
return {
|
|
5741
|
+
index,
|
|
5742
|
+
node: context.blockNode.child(index)
|
|
5743
|
+
};
|
|
5744
|
+
}
|
|
5745
|
+
function getLastNonElseBranchIndex(view, nodePos) {
|
|
5746
|
+
const context = getBranchContext(view, nodePos);
|
|
5747
|
+
if (!context) return -1;
|
|
5748
|
+
for (let i = context.blockNode.childCount - 1; i >= 0; i--) {
|
|
5749
|
+
if (context.blockNode.child(i).attrs.branchType !== "else") return i;
|
|
5750
|
+
}
|
|
5751
|
+
return -1;
|
|
5752
|
+
}
|
|
5753
|
+
function getElseBranch(view, nodePos) {
|
|
5754
|
+
const context = getBranchContext(view, nodePos);
|
|
5755
|
+
if (!context) return false;
|
|
5756
|
+
for (let index = 0; index < context.blockNode.childCount; index++) {
|
|
5757
|
+
if (context.blockNode.child(index).attrs.branchType === "else") {
|
|
5758
|
+
return true;
|
|
5759
|
+
}
|
|
5760
|
+
}
|
|
5761
|
+
return false;
|
|
5762
|
+
}
|
|
5763
|
+
function deleteBlock(view, blockPos) {
|
|
5764
|
+
const blockNode = view.state.doc.nodeAt(blockPos);
|
|
5765
|
+
if (blockNode?.type.name !== "jinjaIfBlock") {
|
|
5766
|
+
return false;
|
|
5767
|
+
}
|
|
5768
|
+
view.dispatch(view.state.tr.delete(blockPos, blockPos + blockNode.nodeSize).scrollIntoView());
|
|
5769
|
+
view.focus();
|
|
5770
|
+
return true;
|
|
5771
|
+
}
|
|
5772
|
+
function insertNewBranch(view, nodePos, branchType, condition = "") {
|
|
5773
|
+
const context = getBranchContext(view, nodePos);
|
|
5774
|
+
if (!context) return false;
|
|
5775
|
+
if (context.branchNode.attrs.branchType === "else") return false;
|
|
5776
|
+
const lastBranch = getLastBranchOfBlock(view, nodePos);
|
|
5777
|
+
if (!lastBranch) return false;
|
|
5778
|
+
if (branchType === "else") {
|
|
5779
|
+
if (getElseBranch(view, nodePos)) return false;
|
|
5780
|
+
if (lastBranch.index !== context.branchIndex) return false;
|
|
5781
|
+
}
|
|
5782
|
+
const newBranch = createBranchNode(view.state.schema, branchType, condition);
|
|
5783
|
+
if (!newBranch) return false;
|
|
5784
|
+
const insertPos = context.branchPos + context.branchNode.nodeSize;
|
|
5785
|
+
view.dispatch(view.state.tr.insert(insertPos, newBranch).scrollIntoView());
|
|
5786
|
+
view.focus();
|
|
5787
|
+
return true;
|
|
5788
|
+
}
|
|
5789
|
+
function deleteBranch(view, nodePos, branchType) {
|
|
5790
|
+
const context = getBranchContext(view, nodePos);
|
|
5791
|
+
if (!context) return false;
|
|
5792
|
+
if (branchType === "if") {
|
|
5793
|
+
if (context.blockNode.childCount === 1) {
|
|
5794
|
+
return deleteBlock(view, context.blockPos);
|
|
5795
|
+
}
|
|
5796
|
+
const nextBranch = context.blockNode.child(context.branchIndex + 1);
|
|
5797
|
+
const promotedCondition = typeof nextBranch.attrs.condition === "string" ? nextBranch.attrs.condition : "";
|
|
5798
|
+
const tr = view.state.tr.delete(context.branchPos, context.branchPos + context.branchNode.nodeSize);
|
|
5799
|
+
tr.setNodeMarkup(context.branchPos, void 0, {
|
|
5800
|
+
...nextBranch.attrs,
|
|
5801
|
+
branchType: "if",
|
|
5802
|
+
condition: promotedCondition
|
|
5803
|
+
});
|
|
5804
|
+
view.dispatch(tr.scrollIntoView());
|
|
5805
|
+
view.focus();
|
|
5806
|
+
return true;
|
|
5807
|
+
}
|
|
5808
|
+
view.dispatch(view.state.tr.delete(context.branchPos, context.branchPos + context.branchNode.nodeSize).scrollIntoView());
|
|
5809
|
+
view.focus();
|
|
5810
|
+
return true;
|
|
5811
|
+
}
|
|
5812
|
+
function renderCondition(condition) {
|
|
5813
|
+
const tokens = tokenizeCondition(condition);
|
|
5814
|
+
const rendered = [];
|
|
5815
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
5816
|
+
const token = tokens[index];
|
|
5817
|
+
rendered.push(
|
|
5818
|
+
/* @__PURE__ */ jsx6("span", { className: `jinja-token-${token.category}`, children: token.text }, `token-${index}-${token.start}`)
|
|
5819
|
+
);
|
|
5820
|
+
}
|
|
5821
|
+
return rendered;
|
|
5822
|
+
}
|
|
5823
|
+
function ConditionDisplay({
|
|
5824
|
+
branchType,
|
|
5825
|
+
condition,
|
|
5826
|
+
editable = true,
|
|
5827
|
+
onConditionChange
|
|
5828
|
+
}) {
|
|
5829
|
+
const [isEditing, setIsEditing] = useState3(false);
|
|
5830
|
+
const [draftValue, setDraftValue] = useState3(condition);
|
|
5831
|
+
const inputRef = useRef2(null);
|
|
5832
|
+
useEffect2(() => {
|
|
5833
|
+
if (!isEditing) {
|
|
5834
|
+
setDraftValue(condition);
|
|
5835
|
+
}
|
|
5836
|
+
}, [condition, isEditing]);
|
|
5837
|
+
useEffect2(() => {
|
|
5838
|
+
if (isEditing) {
|
|
5839
|
+
inputRef.current?.focus();
|
|
5840
|
+
inputRef.current?.select();
|
|
5841
|
+
}
|
|
5842
|
+
}, [isEditing]);
|
|
5843
|
+
if (branchType === "else") {
|
|
5844
|
+
return /* @__PURE__ */ jsx6("span", { className: "jinja-otherwise", children: "Otherwise" });
|
|
5845
|
+
}
|
|
5846
|
+
const commit = () => {
|
|
5847
|
+
setIsEditing(false);
|
|
5848
|
+
if (draftValue !== condition) {
|
|
5849
|
+
onConditionChange(draftValue);
|
|
5850
|
+
}
|
|
5851
|
+
};
|
|
5852
|
+
const cancel = () => {
|
|
5853
|
+
setDraftValue(condition);
|
|
5854
|
+
setIsEditing(false);
|
|
5855
|
+
};
|
|
5856
|
+
if (isEditing && editable) {
|
|
5857
|
+
return /* @__PURE__ */ jsx6(
|
|
5858
|
+
"input",
|
|
5859
|
+
{
|
|
5860
|
+
ref: inputRef,
|
|
5861
|
+
className: "jinja-condition-input",
|
|
5862
|
+
value: draftValue,
|
|
5863
|
+
placeholder: CONDITION_PLACEHOLDER,
|
|
5864
|
+
onChange: (event) => setDraftValue(event.target.value),
|
|
5865
|
+
onBlur: commit,
|
|
5866
|
+
onKeyDown: (event) => {
|
|
5867
|
+
if (event.key === "Enter") {
|
|
5868
|
+
event.preventDefault();
|
|
5869
|
+
commit();
|
|
5870
|
+
}
|
|
5871
|
+
if (event.key === "Escape") {
|
|
5872
|
+
event.preventDefault();
|
|
5873
|
+
cancel();
|
|
5874
|
+
}
|
|
5875
|
+
}
|
|
5876
|
+
}
|
|
5877
|
+
);
|
|
5878
|
+
}
|
|
5879
|
+
return /* @__PURE__ */ jsx6(
|
|
5880
|
+
"button",
|
|
5881
|
+
{
|
|
5882
|
+
type: "button",
|
|
5883
|
+
className: "jinja-branch-condition",
|
|
5884
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
5885
|
+
onClick: () => {
|
|
5886
|
+
if (editable) {
|
|
5887
|
+
setDraftValue(condition);
|
|
5888
|
+
setIsEditing(true);
|
|
5889
|
+
}
|
|
5890
|
+
},
|
|
5891
|
+
children: condition.length > 0 ? renderCondition(condition) : /* @__PURE__ */ jsx6("span", { className: "jinja-condition-placeholder", children: CONDITION_PLACEHOLDER })
|
|
5892
|
+
}
|
|
5893
|
+
);
|
|
5894
|
+
}
|
|
5895
|
+
function BranchPopupMenu({ items, position }) {
|
|
5896
|
+
return /* @__PURE__ */ jsx6(
|
|
5897
|
+
"div",
|
|
5898
|
+
{
|
|
5899
|
+
className: "jinja-popup-menu",
|
|
5900
|
+
style: {
|
|
5901
|
+
top: position.top,
|
|
5902
|
+
left: position.left,
|
|
5903
|
+
right: position.right
|
|
5904
|
+
},
|
|
5905
|
+
role: "menu",
|
|
5906
|
+
children: items.map((item) => /* @__PURE__ */ jsx6(
|
|
5907
|
+
"button",
|
|
5908
|
+
{
|
|
5909
|
+
type: "button",
|
|
5910
|
+
className: "jinja-popup-item",
|
|
5911
|
+
disabled: item.disabled,
|
|
5912
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
5913
|
+
onClick: () => {
|
|
5914
|
+
if (!item.disabled) {
|
|
5915
|
+
item.onSelect();
|
|
5916
|
+
}
|
|
5917
|
+
},
|
|
5918
|
+
role: "menuitem",
|
|
5919
|
+
children: item.label
|
|
5920
|
+
},
|
|
5921
|
+
item.label
|
|
5922
|
+
))
|
|
5923
|
+
}
|
|
5924
|
+
);
|
|
5925
|
+
}
|
|
5926
|
+
function JinjaBranchHeader({
|
|
5927
|
+
branchType,
|
|
5928
|
+
condition,
|
|
5929
|
+
editable = true,
|
|
5930
|
+
onConditionChange,
|
|
5931
|
+
onDelete,
|
|
5932
|
+
onAddBranch,
|
|
5933
|
+
isLastBranch,
|
|
5934
|
+
hasElseBranch
|
|
5935
|
+
}) {
|
|
5936
|
+
const [menuSource, setMenuSource] = useState3(null);
|
|
5937
|
+
const kebabRef = useRef2(null);
|
|
5938
|
+
const footerRef = useRef2(null);
|
|
5939
|
+
useEffect2(() => {
|
|
5940
|
+
if (!menuSource) return;
|
|
5941
|
+
const handlePointerDown = (event) => {
|
|
5942
|
+
const target = event.target;
|
|
5943
|
+
if (!target) return;
|
|
5944
|
+
if (kebabRef.current?.contains(target) || footerRef.current?.contains(target)) {
|
|
5945
|
+
return;
|
|
5946
|
+
}
|
|
5947
|
+
setMenuSource(null);
|
|
5948
|
+
};
|
|
5949
|
+
const handleKeyDown = (event) => {
|
|
5950
|
+
if (event.key === "Escape") {
|
|
5951
|
+
setMenuSource(null);
|
|
5952
|
+
}
|
|
5953
|
+
};
|
|
5954
|
+
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
5955
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
5956
|
+
return () => {
|
|
5957
|
+
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
5958
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
5959
|
+
};
|
|
5960
|
+
}, [menuSource]);
|
|
5961
|
+
const menuItems = [];
|
|
5962
|
+
const isOnlyIfBranch = branchType === "if" && isLastBranch && !hasElseBranch;
|
|
5963
|
+
const canAddElif = editable && branchType !== "else" && (branchType === "elif" || isLastBranch);
|
|
5964
|
+
const canAddElse = editable && branchType !== "else" && isLastBranch && !hasElseBranch;
|
|
5965
|
+
if (canAddElif) {
|
|
5966
|
+
menuItems.push({
|
|
5967
|
+
label: "Else if",
|
|
5968
|
+
onSelect: () => onAddBranch("elif")
|
|
5969
|
+
});
|
|
5970
|
+
}
|
|
5971
|
+
if (canAddElse) {
|
|
5972
|
+
menuItems.push({
|
|
5973
|
+
label: "Else",
|
|
5974
|
+
onSelect: () => onAddBranch("else")
|
|
5975
|
+
});
|
|
5976
|
+
}
|
|
5977
|
+
if (editable) {
|
|
5978
|
+
menuItems.push({
|
|
5979
|
+
label: isOnlyIfBranch ? "Delete all" : "Delete",
|
|
5980
|
+
onSelect: onDelete
|
|
5981
|
+
});
|
|
5982
|
+
}
|
|
5983
|
+
const canOpenFooterMenu = editable && isLastBranch && branchType !== "else";
|
|
5984
|
+
const isMenuOpen = (source) => menuSource === source && menuItems.length > 0;
|
|
5985
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
5986
|
+
/* @__PURE__ */ jsxs5("div", { className: "jinja-branch-header", children: [
|
|
5987
|
+
/* @__PURE__ */ jsx6("span", { className: `jinja-branch-badge jinja-branch-badge-${branchType}`, children: branchType === "elif" ? "ELSE IF" : branchType.toUpperCase() }),
|
|
5988
|
+
/* @__PURE__ */ jsx6(
|
|
5989
|
+
ConditionDisplay,
|
|
5990
|
+
{
|
|
5991
|
+
branchType,
|
|
5992
|
+
condition,
|
|
5993
|
+
editable,
|
|
5994
|
+
onConditionChange
|
|
5995
|
+
}
|
|
5996
|
+
),
|
|
5997
|
+
editable ? /* @__PURE__ */ jsxs5("div", { className: "jinja-branch-actions", ref: kebabRef, children: [
|
|
5998
|
+
/* @__PURE__ */ jsx6(
|
|
5999
|
+
"button",
|
|
6000
|
+
{
|
|
6001
|
+
type: "button",
|
|
6002
|
+
className: "jinja-ghost-btn",
|
|
6003
|
+
"aria-label": `${branchType} branch options`,
|
|
6004
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
6005
|
+
onClick: () => {
|
|
6006
|
+
if (menuItems.length > 0) {
|
|
6007
|
+
setMenuSource((current) => current === "kebab" ? null : "kebab");
|
|
6008
|
+
}
|
|
6009
|
+
},
|
|
6010
|
+
children: /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: [
|
|
6011
|
+
/* @__PURE__ */ jsx6("circle", { cx: "8", cy: "3", r: "1.5" }),
|
|
6012
|
+
/* @__PURE__ */ jsx6("circle", { cx: "8", cy: "8", r: "1.5" }),
|
|
6013
|
+
/* @__PURE__ */ jsx6("circle", { cx: "8", cy: "13", r: "1.5" })
|
|
6014
|
+
] })
|
|
6015
|
+
}
|
|
6016
|
+
),
|
|
6017
|
+
isMenuOpen("kebab") ? /* @__PURE__ */ jsx6(
|
|
6018
|
+
BranchPopupMenu,
|
|
6019
|
+
{
|
|
6020
|
+
position: { top: 28, right: 0 },
|
|
6021
|
+
items: menuItems.map((item) => ({
|
|
6022
|
+
...item,
|
|
6023
|
+
onSelect: () => {
|
|
6024
|
+
setMenuSource(null);
|
|
6025
|
+
item.onSelect();
|
|
6026
|
+
}
|
|
6027
|
+
}))
|
|
6028
|
+
}
|
|
6029
|
+
) : null
|
|
6030
|
+
] }) : null
|
|
6031
|
+
] }),
|
|
6032
|
+
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: [
|
|
6033
|
+
/* @__PURE__ */ jsx6(
|
|
6034
|
+
"button",
|
|
6035
|
+
{
|
|
6036
|
+
type: "button",
|
|
6037
|
+
className: "jinja-ghost-btn",
|
|
6038
|
+
"aria-label": "Add branch",
|
|
6039
|
+
disabled: !canOpenFooterMenu,
|
|
6040
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
6041
|
+
onClick: () => {
|
|
6042
|
+
if (canOpenFooterMenu && menuItems.length > 0) {
|
|
6043
|
+
setMenuSource((current) => current === "footer" ? null : "footer");
|
|
6044
|
+
}
|
|
6045
|
+
},
|
|
6046
|
+
children: /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [
|
|
6047
|
+
/* @__PURE__ */ jsx6("line", { x1: "8", y1: "3", x2: "8", y2: "13" }),
|
|
6048
|
+
/* @__PURE__ */ jsx6("line", { x1: "3", y1: "8", x2: "13", y2: "8" })
|
|
6049
|
+
] })
|
|
6050
|
+
}
|
|
6051
|
+
),
|
|
6052
|
+
isMenuOpen("footer") ? /* @__PURE__ */ jsx6(
|
|
6053
|
+
BranchPopupMenu,
|
|
6054
|
+
{
|
|
6055
|
+
position: { top: 28, left: 0 },
|
|
6056
|
+
items: menuItems.filter((item) => item.label === "Else if" || item.label === "Else").map((item) => ({
|
|
6057
|
+
...item,
|
|
6058
|
+
onSelect: () => {
|
|
6059
|
+
setMenuSource(null);
|
|
6060
|
+
item.onSelect();
|
|
6061
|
+
}
|
|
6062
|
+
}))
|
|
6063
|
+
}
|
|
6064
|
+
) : null
|
|
6065
|
+
] }) }) }) : null
|
|
6066
|
+
] });
|
|
6067
|
+
}
|
|
6068
|
+
var JinjaIfBlockView = class {
|
|
6069
|
+
dom;
|
|
6070
|
+
contentDOM;
|
|
6071
|
+
constructor() {
|
|
6072
|
+
this.dom = document.createElement("div");
|
|
6073
|
+
this.dom.className = "jinja-if-block";
|
|
6074
|
+
this.dom.setAttribute("data-jinja-if-block", "");
|
|
6075
|
+
this.contentDOM = this.dom;
|
|
6076
|
+
requestAnimationFrame(() => this.notifyChildren());
|
|
6077
|
+
}
|
|
6078
|
+
notifyChildren() {
|
|
6079
|
+
this.dom.querySelectorAll(".jinja-branch").forEach((el) => {
|
|
6080
|
+
el.dispatchEvent(new CustomEvent("jinja-siblings-changed", { bubbles: false }));
|
|
6081
|
+
});
|
|
4427
6082
|
}
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
blockBranchType.set(branch.tagBlockIndex, branch.type);
|
|
4433
|
-
for (let i = branch.blockStartIndex; i < branch.blockEndIndex; i++) {
|
|
4434
|
-
if (!blockBranchType.has(i)) {
|
|
4435
|
-
blockBranchType.set(i, branch.type);
|
|
4436
|
-
}
|
|
4437
|
-
}
|
|
4438
|
-
}
|
|
4439
|
-
const lastBranch = structure.branches[structure.branches.length - 1];
|
|
4440
|
-
if (lastBranch && !blockBranchType.has(structure.endifTagBlockIndex)) {
|
|
4441
|
-
blockBranchType.set(structure.endifTagBlockIndex, lastBranch.type);
|
|
4442
|
-
}
|
|
4443
|
-
const first = structure.ifTagBlockIndex;
|
|
4444
|
-
const last = structure.endifTagBlockIndex;
|
|
4445
|
-
for (let i = first; i <= last; i++) {
|
|
4446
|
-
const block = blocks[i];
|
|
4447
|
-
if (!block) continue;
|
|
4448
|
-
const branchType = blockBranchType.get(i) || "if";
|
|
4449
|
-
const prevType = i > first ? blockBranchType.get(i - 1) : void 0;
|
|
4450
|
-
const nextType = i < last ? blockBranchType.get(i + 1) : void 0;
|
|
4451
|
-
const classes = ["jinja-bar", `jinja-bar-${branchType}`];
|
|
4452
|
-
if (i === first || prevType !== branchType) classes.push("jinja-bar-first");
|
|
4453
|
-
if (i === last || nextType !== branchType) classes.push("jinja-bar-last");
|
|
4454
|
-
decorations.push(Decoration2.node(block.from, block.to, { class: classes.join(" ") }));
|
|
4455
|
-
}
|
|
6083
|
+
update(node) {
|
|
6084
|
+
if (node.type.name !== "jinjaIfBlock") return false;
|
|
6085
|
+
requestAnimationFrame(() => this.notifyChildren());
|
|
6086
|
+
return true;
|
|
4456
6087
|
}
|
|
4457
|
-
}
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
6088
|
+
};
|
|
6089
|
+
var JinjaIfBranchView = class {
|
|
6090
|
+
dom;
|
|
6091
|
+
contentDOM;
|
|
6092
|
+
headerContainer;
|
|
6093
|
+
root;
|
|
6094
|
+
node;
|
|
6095
|
+
view;
|
|
6096
|
+
getPos;
|
|
6097
|
+
constructor(node, view, getPos) {
|
|
6098
|
+
this.node = node;
|
|
6099
|
+
this.view = view;
|
|
6100
|
+
this.getPos = getPos;
|
|
6101
|
+
StyleManager.acquire();
|
|
6102
|
+
this.dom = document.createElement("div");
|
|
6103
|
+
this.headerContainer = document.createElement("div");
|
|
6104
|
+
const body = document.createElement("div");
|
|
6105
|
+
const dividerColumn = document.createElement("div");
|
|
6106
|
+
const divider = document.createElement("div");
|
|
6107
|
+
this.dom.appendChild(this.headerContainer);
|
|
6108
|
+
this.dom.appendChild(body);
|
|
6109
|
+
this.headerContainer.className = "jinja-branch-controls";
|
|
6110
|
+
this.headerContainer.contentEditable = "false";
|
|
6111
|
+
body.className = "jinja-branch-body";
|
|
6112
|
+
dividerColumn.className = "jinja-branch-divider-col";
|
|
6113
|
+
dividerColumn.contentEditable = "false";
|
|
6114
|
+
divider.className = "jinja-branch-divider";
|
|
6115
|
+
dividerColumn.appendChild(divider);
|
|
6116
|
+
this.contentDOM = document.createElement("div");
|
|
6117
|
+
this.contentDOM.className = "jinja-branch-content";
|
|
6118
|
+
this.contentDOM.setAttribute("data-placeholder", PLACEHOLDER_TEXT);
|
|
6119
|
+
body.appendChild(dividerColumn);
|
|
6120
|
+
body.appendChild(this.contentDOM);
|
|
6121
|
+
this.root = createRoot2(this.headerContainer);
|
|
6122
|
+
this._onSiblingsChanged = () => this.render();
|
|
6123
|
+
this.dom.addEventListener("jinja-siblings-changed", this._onSiblingsChanged);
|
|
6124
|
+
this.syncDOM();
|
|
6125
|
+
this.render();
|
|
6126
|
+
}
|
|
6127
|
+
_onSiblingsChanged = null;
|
|
6128
|
+
syncDOM() {
|
|
6129
|
+
const branchType = this.node.attrs.branchType;
|
|
6130
|
+
this.dom.className = `jinja-branch jinja-branch-${branchType}`;
|
|
6131
|
+
this.dom.setAttribute("data-jinja-branch", "");
|
|
6132
|
+
this.dom.setAttribute("data-branch-type", branchType);
|
|
6133
|
+
this.dom.setAttribute("data-condition", String(this.node.attrs.condition ?? ""));
|
|
6134
|
+
this.contentDOM.classList.toggle("jinja-branch-content-empty", isBranchBodyEmpty(this.node));
|
|
6135
|
+
}
|
|
6136
|
+
render() {
|
|
6137
|
+
const nodePos = this.getPos();
|
|
6138
|
+
if (nodePos == null) return;
|
|
6139
|
+
const lastBranch = getLastBranchOfBlock(this.view, nodePos);
|
|
6140
|
+
const context = getBranchContext(this.view, nodePos);
|
|
6141
|
+
if (!lastBranch || !context) return;
|
|
6142
|
+
const branchType = this.node.attrs.branchType;
|
|
6143
|
+
const condition = String(this.node.attrs.condition ?? "");
|
|
6144
|
+
const isLast = lastBranch.index === context.branchIndex;
|
|
6145
|
+
const lastNonElseIdx = getLastNonElseBranchIndex(this.view, nodePos);
|
|
6146
|
+
const showAddButton = context.branchIndex === lastNonElseIdx;
|
|
6147
|
+
this.dom.classList.toggle("jinja-branch-last", isLast);
|
|
6148
|
+
this.root.render(
|
|
6149
|
+
/* @__PURE__ */ jsx6(
|
|
6150
|
+
JinjaBranchHeader,
|
|
6151
|
+
{
|
|
6152
|
+
branchType,
|
|
6153
|
+
condition,
|
|
6154
|
+
editable: this.view.editable,
|
|
6155
|
+
isLastBranch: showAddButton,
|
|
6156
|
+
hasElseBranch: getElseBranch(this.view, nodePos),
|
|
6157
|
+
onConditionChange: (value) => {
|
|
6158
|
+
const currentPos = this.getPos();
|
|
6159
|
+
if (currentPos == null) return;
|
|
6160
|
+
this.view.dispatch(
|
|
6161
|
+
this.view.state.tr.setNodeMarkup(currentPos, void 0, {
|
|
6162
|
+
...this.node.attrs,
|
|
6163
|
+
condition: value
|
|
6164
|
+
})
|
|
6165
|
+
);
|
|
6166
|
+
this.view.focus();
|
|
4475
6167
|
},
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
6168
|
+
onDelete: () => {
|
|
6169
|
+
const currentPos = this.getPos();
|
|
6170
|
+
if (currentPos == null) return;
|
|
6171
|
+
deleteBranch(this.view, currentPos, branchType);
|
|
6172
|
+
},
|
|
6173
|
+
onAddBranch: (nextBranchType) => {
|
|
6174
|
+
const currentPos = this.getPos();
|
|
6175
|
+
if (currentPos == null) return;
|
|
6176
|
+
insertNewBranch(this.view, currentPos, nextBranchType, "");
|
|
4484
6177
|
}
|
|
4485
6178
|
}
|
|
4486
|
-
|
|
4487
|
-
|
|
6179
|
+
)
|
|
6180
|
+
);
|
|
6181
|
+
}
|
|
6182
|
+
update(node) {
|
|
6183
|
+
if (!isBranchNode(node)) return false;
|
|
6184
|
+
this.node = node;
|
|
6185
|
+
this.syncDOM();
|
|
6186
|
+
this.render();
|
|
6187
|
+
return true;
|
|
6188
|
+
}
|
|
6189
|
+
stopEvent(event) {
|
|
6190
|
+
const target = event.target;
|
|
6191
|
+
return target != null && this.headerContainer.contains(target);
|
|
6192
|
+
}
|
|
6193
|
+
ignoreMutation(mutation) {
|
|
6194
|
+
return this.headerContainer.contains(mutation.target);
|
|
6195
|
+
}
|
|
6196
|
+
destroy() {
|
|
6197
|
+
if (this._onSiblingsChanged) {
|
|
6198
|
+
this.dom.removeEventListener("jinja-siblings-changed", this._onSiblingsChanged);
|
|
6199
|
+
}
|
|
6200
|
+
StyleManager.release();
|
|
6201
|
+
setTimeout(() => this.root.unmount(), 0);
|
|
6202
|
+
}
|
|
6203
|
+
};
|
|
6204
|
+
function createJinjaIfBlockPlugin() {
|
|
6205
|
+
return {
|
|
6206
|
+
name: "jinjaIfBlock",
|
|
6207
|
+
nodeViews: () => ({
|
|
6208
|
+
jinjaIfBlock: (() => new JinjaIfBlockView()),
|
|
6209
|
+
jinjaIfBranch: ((node, view, getPos) => new JinjaIfBranchView(node, view, getPos))
|
|
6210
|
+
})
|
|
4488
6211
|
};
|
|
4489
6212
|
}
|
|
4490
6213
|
|
|
4491
6214
|
// src/ui/plugin/linkPlugin.ts
|
|
4492
6215
|
import { InputRule as InputRule2, inputRules as inputRules2 } from "prosemirror-inputrules";
|
|
4493
|
-
import { Plugin as
|
|
6216
|
+
import { Plugin as Plugin5, PluginKey as PluginKey5, TextSelection as TextSelection3 } from "prosemirror-state";
|
|
4494
6217
|
var LINK_INPUT_RE = /\[([^\]]*)\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
|
|
4495
6218
|
var LINK_FULL_RE = /^\[([^\]]*)\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
|
|
4496
|
-
var linkEditKey = new
|
|
6219
|
+
var linkEditKey = new PluginKey5("linkEdit");
|
|
4497
6220
|
function getMarkRange($pos, type) {
|
|
4498
6221
|
const { parentOffset } = $pos;
|
|
4499
6222
|
let child = $pos.parent.childAfter(parentOffset);
|
|
@@ -4536,12 +6259,12 @@ function explodeLinkToRaw(state) {
|
|
|
4536
6259
|
const tr = state.tr;
|
|
4537
6260
|
tr.replaceWith(from, to, schema.text(rawText));
|
|
4538
6261
|
const newPos = Math.min(from + rawCursorOffset, tr.doc.content.size);
|
|
4539
|
-
tr.setSelection(
|
|
6262
|
+
tr.setSelection(TextSelection3.near(tr.doc.resolve(newPos)));
|
|
4540
6263
|
tr.setMeta(linkEditKey, { from, to: from + rawText.length });
|
|
4541
6264
|
return tr;
|
|
4542
6265
|
}
|
|
4543
6266
|
function createLinkEditPlugin() {
|
|
4544
|
-
return new
|
|
6267
|
+
return new Plugin5({
|
|
4545
6268
|
key: linkEditKey,
|
|
4546
6269
|
state: {
|
|
4547
6270
|
init: () => ({ rawRange: null }),
|
|
@@ -4611,8 +6334,8 @@ function createLinkInputRule() {
|
|
|
4611
6334
|
);
|
|
4612
6335
|
}
|
|
4613
6336
|
function createLinkClickPlugin() {
|
|
4614
|
-
return new
|
|
4615
|
-
key: new
|
|
6337
|
+
return new Plugin5({
|
|
6338
|
+
key: new PluginKey5("linkClick"),
|
|
4616
6339
|
props: {
|
|
4617
6340
|
handleDOMEvents: {
|
|
4618
6341
|
click: (_view, event) => {
|
|
@@ -4664,8 +6387,8 @@ function createLinkPlugin() {
|
|
|
4664
6387
|
}
|
|
4665
6388
|
|
|
4666
6389
|
// src/ui/plugin/dragHandlePlugin.ts
|
|
4667
|
-
import { Plugin as
|
|
4668
|
-
var PLUGIN_KEY = new
|
|
6390
|
+
import { Plugin as Plugin6, PluginKey as PluginKey6 } from "prosemirror-state";
|
|
6391
|
+
var PLUGIN_KEY = new PluginKey6("dragHandle");
|
|
4669
6392
|
var GRIP_SVG = `<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
4670
6393
|
<circle cx="4" cy="2.5" r="1.2"/><circle cx="8" cy="2.5" r="1.2"/>
|
|
4671
6394
|
<circle cx="4" cy="6" r="1.2"/><circle cx="8" cy="6" r="1.2"/>
|
|
@@ -4682,11 +6405,11 @@ var STYLES = (
|
|
|
4682
6405
|
--ab-dh-color-idle: transparent;
|
|
4683
6406
|
--ab-dh-color-hover: #c4c4c4;
|
|
4684
6407
|
--ab-dh-color-visible: #8b8b8b;
|
|
4685
|
-
--ab-dh-color-accent:
|
|
4686
|
-
--ab-dh-bg-hover: rgba(
|
|
4687
|
-
--ab-dh-bg-active: rgba(
|
|
6408
|
+
--ab-dh-color-accent: rgba(1,156,110,0.8);
|
|
6409
|
+
--ab-dh-bg-hover: rgba(13,13,13,0.04);
|
|
6410
|
+
--ab-dh-bg-active: rgba(13,13,13,0.04);
|
|
4688
6411
|
--ab-dh-dragging-opacity: 0.4;
|
|
4689
|
-
--ab-dh-handle-size:
|
|
6412
|
+
--ab-dh-handle-size: 24px;
|
|
4690
6413
|
--ab-dh-handle-radius: 4px;
|
|
4691
6414
|
--ab-dh-transition-duration: 0.15s;
|
|
4692
6415
|
|
|
@@ -4703,15 +6426,19 @@ var STYLES = (
|
|
|
4703
6426
|
align-items: center;
|
|
4704
6427
|
justify-content: center;
|
|
4705
6428
|
cursor: grab;
|
|
4706
|
-
color:
|
|
6429
|
+
color: transparent;
|
|
4707
6430
|
border-radius: var(--ab-dh-handle-radius);
|
|
4708
|
-
transition: color var(--ab-dh-transition-duration), background var(--ab-dh-transition-duration);
|
|
6431
|
+
transition: color var(--ab-dh-transition-duration), background var(--ab-dh-transition-duration), opacity var(--ab-dh-transition-duration);
|
|
4709
6432
|
user-select: none;
|
|
4710
6433
|
pointer-events: auto;
|
|
4711
6434
|
touch-action: none;
|
|
6435
|
+
opacity: 0;
|
|
6436
|
+
pointer-events: none;
|
|
4712
6437
|
}
|
|
4713
|
-
.ab-drag-handle
|
|
4714
|
-
|
|
6438
|
+
.ab-drag-handle.ab-dh-active {
|
|
6439
|
+
opacity: 1;
|
|
6440
|
+
pointer-events: auto;
|
|
6441
|
+
color: var(--ab-dh-color-visible);
|
|
4715
6442
|
}
|
|
4716
6443
|
.ab-drag-handle:hover {
|
|
4717
6444
|
color: var(--ab-dh-color-visible) !important;
|
|
@@ -4725,18 +6452,20 @@ var STYLES = (
|
|
|
4725
6452
|
.ab-drop-indicator {
|
|
4726
6453
|
position: absolute;
|
|
4727
6454
|
left: 0; right: 0;
|
|
4728
|
-
height:
|
|
4729
|
-
background:
|
|
4730
|
-
border
|
|
6455
|
+
height: 4px;
|
|
6456
|
+
background: rgba(1,156,110,0.4);
|
|
6457
|
+
border: 1px solid rgba(1,156,110,0.6);
|
|
6458
|
+
border-radius: 12px;
|
|
4731
6459
|
pointer-events: none;
|
|
4732
6460
|
z-index: 20;
|
|
6461
|
+
box-sizing: border-box;
|
|
4733
6462
|
transition: top 60ms ease-out;
|
|
4734
6463
|
}
|
|
4735
6464
|
.ab-block-dragging {
|
|
4736
6465
|
opacity: var(--ab-dh-dragging-opacity, 0.4);
|
|
4737
6466
|
}
|
|
4738
6467
|
@keyframes ab-block-flash {
|
|
4739
|
-
from { background: rgba(
|
|
6468
|
+
from { background: rgba(1,156,110,0.08); }
|
|
4740
6469
|
to { background: transparent; }
|
|
4741
6470
|
}
|
|
4742
6471
|
.ab-block-just-moved {
|
|
@@ -4753,7 +6482,7 @@ var STYLES = (
|
|
|
4753
6482
|
}
|
|
4754
6483
|
`
|
|
4755
6484
|
);
|
|
4756
|
-
var
|
|
6485
|
+
var StyleManager2 = class {
|
|
4757
6486
|
static refCount = 0;
|
|
4758
6487
|
static sheet = null;
|
|
4759
6488
|
static styleEl = null;
|
|
@@ -4880,7 +6609,7 @@ var DragHandleController = class {
|
|
|
4880
6609
|
globalCleanup = null;
|
|
4881
6610
|
constructor(view) {
|
|
4882
6611
|
this.view = view;
|
|
4883
|
-
|
|
6612
|
+
StyleManager2.acquire();
|
|
4884
6613
|
const parent = view.dom.parentNode;
|
|
4885
6614
|
const pos = getComputedStyle(parent).position;
|
|
4886
6615
|
if (pos === "static" || pos === "") parent.style.position = "relative";
|
|
@@ -4892,23 +6621,25 @@ var DragHandleController = class {
|
|
|
4892
6621
|
this.liveRegion.setAttribute("aria-live", "assertive");
|
|
4893
6622
|
this.liveRegion.setAttribute("aria-atomic", "true");
|
|
4894
6623
|
parent.appendChild(this.liveRegion);
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
};
|
|
4898
|
-
const onLeave = () => {
|
|
4899
|
-
if (!this.drag) delete this.layer.dataset.hover;
|
|
4900
|
-
};
|
|
4901
|
-
parent.addEventListener("mouseenter", onEnter);
|
|
4902
|
-
parent.addEventListener("mouseleave", onLeave);
|
|
4903
|
-
this.hoverBound = { enter: onEnter, leave: onLeave };
|
|
6624
|
+
this.hoverBound = { enter: () => {
|
|
6625
|
+
}, leave: () => {
|
|
6626
|
+
} };
|
|
4904
6627
|
this.scrollContainer = this.findScrollContainer(view.dom);
|
|
4905
6628
|
this.scrollContainer.addEventListener("scroll", this.onScroll, { passive: true });
|
|
4906
6629
|
this.resizeObserver = new ResizeObserver(() => this.scheduleUpdate());
|
|
4907
6630
|
this.resizeObserver.observe(view.dom);
|
|
6631
|
+
if (!view.editable) {
|
|
6632
|
+
this.layer.style.display = "none";
|
|
6633
|
+
}
|
|
4908
6634
|
this.rebuildHandles();
|
|
4909
6635
|
}
|
|
4910
6636
|
update(view, prevState) {
|
|
4911
6637
|
this.view = view;
|
|
6638
|
+
if (!view.editable) {
|
|
6639
|
+
this.layer.style.display = "none";
|
|
6640
|
+
return;
|
|
6641
|
+
}
|
|
6642
|
+
this.layer.style.display = "";
|
|
4912
6643
|
if (this.drag) {
|
|
4913
6644
|
this.pendingUpdate = true;
|
|
4914
6645
|
return;
|
|
@@ -4916,6 +6647,21 @@ var DragHandleController = class {
|
|
|
4916
6647
|
if (!view.state.doc.eq(prevState.doc)) {
|
|
4917
6648
|
this.scheduleUpdate();
|
|
4918
6649
|
}
|
|
6650
|
+
if (!view.state.selection.eq(prevState.selection) || !view.state.doc.eq(prevState.doc)) {
|
|
6651
|
+
this.updateActiveHandle();
|
|
6652
|
+
}
|
|
6653
|
+
}
|
|
6654
|
+
/** Show only the handle for the block containing the cursor. */
|
|
6655
|
+
updateActiveHandle() {
|
|
6656
|
+
const { $from } = this.view.state.selection;
|
|
6657
|
+
const cursorBlockOffset = $from.start(1) - 1;
|
|
6658
|
+
for (const h of this.handles) {
|
|
6659
|
+
if (h.block.offset === cursorBlockOffset) {
|
|
6660
|
+
h.el.classList.add("ab-dh-active");
|
|
6661
|
+
} else {
|
|
6662
|
+
h.el.classList.remove("ab-dh-active");
|
|
6663
|
+
}
|
|
6664
|
+
}
|
|
4919
6665
|
}
|
|
4920
6666
|
destroy() {
|
|
4921
6667
|
this.cancelDrag();
|
|
@@ -4938,7 +6684,7 @@ var DragHandleController = class {
|
|
|
4938
6684
|
}
|
|
4939
6685
|
this.liveRegion.remove();
|
|
4940
6686
|
this.layer.remove();
|
|
4941
|
-
|
|
6687
|
+
StyleManager2.release();
|
|
4942
6688
|
}
|
|
4943
6689
|
// ── Private: update pipeline ──
|
|
4944
6690
|
scheduleUpdate() {
|
|
@@ -5007,6 +6753,7 @@ var DragHandleController = class {
|
|
|
5007
6753
|
el.setAttribute("role", "button");
|
|
5008
6754
|
el.setAttribute("aria-roledescription", "drag handle");
|
|
5009
6755
|
el.setAttribute("aria-label", `\uBE14\uB85D ${idx + 1} \uC774\uB3D9`);
|
|
6756
|
+
el.setAttribute("title", "Drag to move");
|
|
5010
6757
|
el.setAttribute("tabindex", "-1");
|
|
5011
6758
|
el.innerHTML = GRIP_SVG;
|
|
5012
6759
|
el.style.left = `${handleLeft}px`;
|
|
@@ -5017,6 +6764,7 @@ var DragHandleController = class {
|
|
|
5017
6764
|
}
|
|
5018
6765
|
this.handles = newHandles;
|
|
5019
6766
|
this.prevBlocks = newBlocks;
|
|
6767
|
+
this.updateActiveHandle();
|
|
5020
6768
|
}
|
|
5021
6769
|
bindHandleEvents(el, index) {
|
|
5022
6770
|
let currentIndex = index;
|
|
@@ -5087,7 +6835,8 @@ var DragHandleController = class {
|
|
|
5087
6835
|
pointerId: e.pointerId,
|
|
5088
6836
|
startX: e.clientX,
|
|
5089
6837
|
startY: e.clientY,
|
|
5090
|
-
activated: false
|
|
6838
|
+
activated: false,
|
|
6839
|
+
ghost: null
|
|
5091
6840
|
};
|
|
5092
6841
|
this.addGlobalDragListeners(e.pointerId);
|
|
5093
6842
|
}
|
|
@@ -5096,6 +6845,22 @@ var DragHandleController = class {
|
|
|
5096
6845
|
this.drag.activated = true;
|
|
5097
6846
|
this.drag.handle.classList.add("dragging");
|
|
5098
6847
|
this.drag.blockDom.classList.add("ab-block-dragging");
|
|
6848
|
+
const blockRect = this.drag.blockDom.getBoundingClientRect();
|
|
6849
|
+
const ghost = this.drag.blockDom.cloneNode(true);
|
|
6850
|
+
ghost.className = "ab-drag-ghost";
|
|
6851
|
+
ghost.style.cssText = `
|
|
6852
|
+
position: fixed;
|
|
6853
|
+
top: ${blockRect.top}px;
|
|
6854
|
+
left: ${blockRect.left}px;
|
|
6855
|
+
width: ${blockRect.width}px;
|
|
6856
|
+
opacity: 0.4;
|
|
6857
|
+
pointer-events: none;
|
|
6858
|
+
z-index: 9999;
|
|
6859
|
+
transition: none;
|
|
6860
|
+
`;
|
|
6861
|
+
document.body.appendChild(ghost);
|
|
6862
|
+
this.drag.ghost = ghost;
|
|
6863
|
+
this.drag._ghostOffsetY = this.drag.startY - blockRect.top;
|
|
5099
6864
|
const parent = this.view.dom.parentNode;
|
|
5100
6865
|
this.dropIndicator = document.createElement("div");
|
|
5101
6866
|
this.dropIndicator.className = "ab-drop-indicator";
|
|
@@ -5135,6 +6900,10 @@ var DragHandleController = class {
|
|
|
5135
6900
|
this.activateDrag();
|
|
5136
6901
|
}
|
|
5137
6902
|
this.drag.pointerY = e.clientY;
|
|
6903
|
+
if (this.drag.ghost) {
|
|
6904
|
+
const offsetY = this.drag._ghostOffsetY ?? 0;
|
|
6905
|
+
this.drag.ghost.style.top = `${e.clientY - offsetY}px`;
|
|
6906
|
+
}
|
|
5138
6907
|
this.updateDropTarget();
|
|
5139
6908
|
}
|
|
5140
6909
|
updateDropTarget() {
|
|
@@ -5206,6 +6975,10 @@ var DragHandleController = class {
|
|
|
5206
6975
|
this.cleaningUp = true;
|
|
5207
6976
|
this.drag.handle.classList.remove("dragging");
|
|
5208
6977
|
this.drag.blockDom.classList.remove("ab-block-dragging");
|
|
6978
|
+
if (this.drag.ghost) {
|
|
6979
|
+
this.drag.ghost.remove();
|
|
6980
|
+
this.drag.ghost = null;
|
|
6981
|
+
}
|
|
5209
6982
|
try {
|
|
5210
6983
|
this.drag.handle.releasePointerCapture(this.drag.pointerId);
|
|
5211
6984
|
} catch {
|
|
@@ -5289,7 +7062,7 @@ function createDragHandlePlugin() {
|
|
|
5289
7062
|
plugins: () => {
|
|
5290
7063
|
let controller = null;
|
|
5291
7064
|
return [
|
|
5292
|
-
new
|
|
7065
|
+
new Plugin6({
|
|
5293
7066
|
key: PLUGIN_KEY,
|
|
5294
7067
|
view(editorView) {
|
|
5295
7068
|
controller = new DragHandleController(editorView);
|
|
@@ -5411,9 +7184,58 @@ function createTodoNodeViewPlugin() {
|
|
|
5411
7184
|
};
|
|
5412
7185
|
}
|
|
5413
7186
|
|
|
7187
|
+
// src/ui/plugin/noteBlockPlugin.tsx
|
|
7188
|
+
var NoteBlockView = class {
|
|
7189
|
+
dom;
|
|
7190
|
+
contentDOM;
|
|
7191
|
+
constructor(_node, _view, _getPos) {
|
|
7192
|
+
this.dom = document.createElement("div");
|
|
7193
|
+
this.dom.setAttribute("data-note-block", "");
|
|
7194
|
+
this.dom.className = "ab-note-block";
|
|
7195
|
+
this.dom.style.cssText = `
|
|
7196
|
+
position: relative;
|
|
7197
|
+
margin: 8px 0;
|
|
7198
|
+
padding: 12px 16px 12px 16px;
|
|
7199
|
+
background: rgba(0, 0, 0, 0.015);
|
|
7200
|
+
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
|
7201
|
+
color: #999;
|
|
7202
|
+
font-style: italic;
|
|
7203
|
+
`;
|
|
7204
|
+
const label = document.createElement("span");
|
|
7205
|
+
label.contentEditable = "false";
|
|
7206
|
+
label.textContent = "Note";
|
|
7207
|
+
label.style.cssText = `
|
|
7208
|
+
display: inline-block;
|
|
7209
|
+
font-size: 11px;
|
|
7210
|
+
font-weight: 600;
|
|
7211
|
+
font-style: normal;
|
|
7212
|
+
color: #aaa;
|
|
7213
|
+
background: rgba(0, 0, 0, 0.03);
|
|
7214
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
7215
|
+
border-radius: 3px;
|
|
7216
|
+
padding: 1px 6px;
|
|
7217
|
+
margin-bottom: 6px;
|
|
7218
|
+
user-select: none;
|
|
7219
|
+
line-height: 1.4;
|
|
7220
|
+
`;
|
|
7221
|
+
this.dom.appendChild(label);
|
|
7222
|
+
this.contentDOM = document.createElement("div");
|
|
7223
|
+
this.contentDOM.className = "ab-note-block-content";
|
|
7224
|
+
this.dom.appendChild(this.contentDOM);
|
|
7225
|
+
}
|
|
7226
|
+
};
|
|
7227
|
+
function createNoteBlockPlugin() {
|
|
7228
|
+
return {
|
|
7229
|
+
name: "noteBlockNodeView",
|
|
7230
|
+
nodeViews: () => ({
|
|
7231
|
+
noteBlock: (node, view, getPos) => new NoteBlockView(node, view, getPos)
|
|
7232
|
+
})
|
|
7233
|
+
};
|
|
7234
|
+
}
|
|
7235
|
+
|
|
5414
7236
|
// src/ui/plugin/slashCommandPlugin.ts
|
|
5415
|
-
import { Plugin as
|
|
5416
|
-
var slashCommandKey = new
|
|
7237
|
+
import { Plugin as Plugin7, PluginKey as PluginKey7 } from "prosemirror-state";
|
|
7238
|
+
var slashCommandKey = new PluginKey7("slashCommand");
|
|
5417
7239
|
var TRIGGER_RE = /(?:^|\s)(\/[^\s]*)$/;
|
|
5418
7240
|
function deriveState(state, dismissedFrom) {
|
|
5419
7241
|
const { selection } = state;
|
|
@@ -5436,7 +7258,7 @@ function deriveState(state, dismissedFrom) {
|
|
|
5436
7258
|
};
|
|
5437
7259
|
}
|
|
5438
7260
|
function createSlashCommandPlugin() {
|
|
5439
|
-
const plugin = new
|
|
7261
|
+
const plugin = new Plugin7({
|
|
5440
7262
|
key: slashCommandKey,
|
|
5441
7263
|
state: {
|
|
5442
7264
|
init(_, state) {
|
|
@@ -5480,17 +7302,37 @@ function createSlashCommandPlugin() {
|
|
|
5480
7302
|
}
|
|
5481
7303
|
|
|
5482
7304
|
// src/ui/components/SlashCommandMenu.tsx
|
|
5483
|
-
import { useEffect as
|
|
7305
|
+
import React4, { useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as useState4 } from "react";
|
|
5484
7306
|
import { createPortal } from "react-dom";
|
|
5485
|
-
import { jsx as
|
|
7307
|
+
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
5486
7308
|
function filterItems(items, query) {
|
|
5487
7309
|
if (!query) return items;
|
|
5488
|
-
const
|
|
5489
|
-
|
|
5490
|
-
|
|
7310
|
+
const colonIdx = query.indexOf(":");
|
|
7311
|
+
const searchPart = colonIdx >= 0 ? query.slice(colonIdx + 1).trim() : query;
|
|
7312
|
+
if (!searchPart) return items;
|
|
7313
|
+
const words = searchPart.toLowerCase().split(/\s+/);
|
|
7314
|
+
const filtered = items.filter(
|
|
7315
|
+
({ title, description }) => {
|
|
7316
|
+
const hay = (title + " " + (description ?? "")).toLowerCase();
|
|
7317
|
+
return words.every((w) => hay.includes(w));
|
|
7318
|
+
}
|
|
5491
7319
|
);
|
|
5492
|
-
|
|
5493
|
-
|
|
7320
|
+
return filtered.length > 0 ? filtered : items;
|
|
7321
|
+
}
|
|
7322
|
+
var SCROLLBAR_STYLE_ID = "ab-slash-menu-scrollbar";
|
|
7323
|
+
function injectScrollbarStyle() {
|
|
7324
|
+
if (document.getElementById(SCROLLBAR_STYLE_ID)) return;
|
|
7325
|
+
const style = document.createElement("style");
|
|
7326
|
+
style.id = SCROLLBAR_STYLE_ID;
|
|
7327
|
+
style.textContent = `
|
|
7328
|
+
.ab-slash-menu::-webkit-scrollbar { width: 6px; }
|
|
7329
|
+
.ab-slash-menu::-webkit-scrollbar-track { background: transparent; }
|
|
7330
|
+
.ab-slash-menu::-webkit-scrollbar-thumb { background: #c4c4c4; border-radius: 3px; }
|
|
7331
|
+
.ab-slash-menu::-webkit-scrollbar-thumb:hover { background: #999; }
|
|
7332
|
+
`;
|
|
7333
|
+
document.head.appendChild(style);
|
|
7334
|
+
}
|
|
7335
|
+
var POPUP_SHADOW = "0 8px 10px rgba(13,13,13,0.12), 0 3px 14px rgba(13,13,13,0.08), 0 3px 5px rgba(13,13,13,0.04)";
|
|
5494
7336
|
var BTN_RESET = {
|
|
5495
7337
|
border: "none",
|
|
5496
7338
|
padding: 0,
|
|
@@ -5503,26 +7345,29 @@ var BTN_RESET = {
|
|
|
5503
7345
|
width: "100%"
|
|
5504
7346
|
};
|
|
5505
7347
|
var VPORT_MARGIN = 8;
|
|
5506
|
-
var MENU_WIDTH =
|
|
5507
|
-
var MAX_MENU_H =
|
|
7348
|
+
var MENU_WIDTH = 440;
|
|
7349
|
+
var MAX_MENU_H = 400;
|
|
5508
7350
|
function SlashCommandMenu({ view, editorState, items }) {
|
|
5509
|
-
const [selectedIndex, setSelectedIndex] =
|
|
5510
|
-
const listRef =
|
|
7351
|
+
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
7352
|
+
const listRef = useRef3(null);
|
|
7353
|
+
useLayoutEffect(() => {
|
|
7354
|
+
injectScrollbarStyle();
|
|
7355
|
+
}, []);
|
|
5511
7356
|
const pluginState = editorState ? slashCommandKey.getState(editorState) : void 0;
|
|
5512
7357
|
const active = pluginState?.active ?? false;
|
|
5513
7358
|
const range = pluginState?.range ?? null;
|
|
5514
7359
|
const query = pluginState?.query ?? "";
|
|
5515
7360
|
const filtered = filterItems(items, query);
|
|
5516
|
-
|
|
7361
|
+
useEffect3(() => {
|
|
5517
7362
|
setSelectedIndex(0);
|
|
5518
7363
|
}, [query, active]);
|
|
5519
|
-
|
|
7364
|
+
useEffect3(() => {
|
|
5520
7365
|
const list = listRef.current;
|
|
5521
7366
|
if (!list) return;
|
|
5522
|
-
const item = list.
|
|
7367
|
+
const item = list.querySelector(`[data-slash-index="${selectedIndex}"]`);
|
|
5523
7368
|
item?.scrollIntoView({ block: "nearest" });
|
|
5524
7369
|
}, [selectedIndex]);
|
|
5525
|
-
|
|
7370
|
+
useEffect3(() => {
|
|
5526
7371
|
if (!active || !view) return;
|
|
5527
7372
|
const onKeyDown = (e) => {
|
|
5528
7373
|
if (e.key === "ArrowDown") {
|
|
@@ -5558,9 +7403,10 @@ function SlashCommandMenu({ view, editorState, items }) {
|
|
|
5558
7403
|
top = coords.top - MAX_MENU_H - 4;
|
|
5559
7404
|
}
|
|
5560
7405
|
return createPortal(
|
|
5561
|
-
/* @__PURE__ */
|
|
7406
|
+
/* @__PURE__ */ jsx7(
|
|
5562
7407
|
"div",
|
|
5563
7408
|
{
|
|
7409
|
+
className: "ab-slash-menu",
|
|
5564
7410
|
style: {
|
|
5565
7411
|
position: "fixed",
|
|
5566
7412
|
top,
|
|
@@ -5568,14 +7414,16 @@ function SlashCommandMenu({ view, editorState, items }) {
|
|
|
5568
7414
|
width: MENU_WIDTH,
|
|
5569
7415
|
maxHeight: MAX_MENU_H,
|
|
5570
7416
|
overflowY: "auto",
|
|
7417
|
+
scrollbarWidth: "thin",
|
|
7418
|
+
scrollbarColor: "#c4c4c4 transparent",
|
|
5571
7419
|
background: "#fff",
|
|
5572
|
-
borderRadius:
|
|
7420
|
+
borderRadius: 4,
|
|
5573
7421
|
boxShadow: POPUP_SHADOW,
|
|
5574
|
-
padding:
|
|
7422
|
+
padding: "8px 0",
|
|
5575
7423
|
zIndex: 1100,
|
|
5576
7424
|
animation: "ab-float-in 0.12s ease"
|
|
5577
7425
|
},
|
|
5578
|
-
children: /* @__PURE__ */
|
|
7426
|
+
children: /* @__PURE__ */ jsx7("div", { ref: listRef, children: filtered.length === 0 ? /* @__PURE__ */ jsx7(
|
|
5579
7427
|
"div",
|
|
5580
7428
|
{
|
|
5581
7429
|
style: {
|
|
@@ -5585,101 +7433,104 @@ function SlashCommandMenu({ view, editorState, items }) {
|
|
|
5585
7433
|
},
|
|
5586
7434
|
children: "No results"
|
|
5587
7435
|
}
|
|
5588
|
-
) : filtered.map((item, i) =>
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
7436
|
+
) : filtered.map((item, i) => {
|
|
7437
|
+
const prevGroup = i > 0 ? filtered[i - 1].group : void 0;
|
|
7438
|
+
const showGroupHeader = item.group && item.group !== prevGroup;
|
|
7439
|
+
return /* @__PURE__ */ jsxs6(React4.Fragment, { children: [
|
|
7440
|
+
showGroupHeader && /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7441
|
+
i > 0 && /* @__PURE__ */ jsx7("div", { style: { height: 1, background: "rgba(0,0,0,0.06)", margin: "4px 10px" } }),
|
|
7442
|
+
/* @__PURE__ */ jsx7(
|
|
7443
|
+
"div",
|
|
7444
|
+
{
|
|
7445
|
+
style: {
|
|
7446
|
+
padding: "8px 16px 4px",
|
|
7447
|
+
fontSize: 13,
|
|
7448
|
+
fontWeight: 400,
|
|
7449
|
+
color: "#5e5e5e"
|
|
7450
|
+
},
|
|
7451
|
+
children: item.group
|
|
7452
|
+
}
|
|
7453
|
+
)
|
|
7454
|
+
] }),
|
|
7455
|
+
/* @__PURE__ */ jsx7(
|
|
7456
|
+
SlashMenuItem,
|
|
7457
|
+
{
|
|
7458
|
+
item,
|
|
7459
|
+
index: i,
|
|
7460
|
+
selected: i === selectedIndex,
|
|
7461
|
+
onMouseEnter: () => setSelectedIndex(i),
|
|
7462
|
+
onMouseDown: (e) => {
|
|
7463
|
+
e.preventDefault();
|
|
7464
|
+
if (range) {
|
|
7465
|
+
item.command({ view, range });
|
|
7466
|
+
view.focus();
|
|
7467
|
+
}
|
|
7468
|
+
}
|
|
5599
7469
|
}
|
|
5600
|
-
|
|
5601
|
-
},
|
|
5602
|
-
|
|
5603
|
-
)) })
|
|
7470
|
+
)
|
|
7471
|
+
] }, item.id ?? item.title);
|
|
7472
|
+
}) })
|
|
5604
7473
|
}
|
|
5605
7474
|
),
|
|
5606
7475
|
document.body
|
|
5607
7476
|
);
|
|
5608
7477
|
}
|
|
5609
|
-
function SlashMenuItem({ item, selected, onMouseEnter, onMouseDown }) {
|
|
5610
|
-
return /* @__PURE__ */
|
|
7478
|
+
function SlashMenuItem({ item, index, selected, onMouseEnter, onMouseDown }) {
|
|
7479
|
+
return /* @__PURE__ */ jsxs6(
|
|
5611
7480
|
"button",
|
|
5612
7481
|
{
|
|
7482
|
+
"data-slash-index": index,
|
|
5613
7483
|
style: {
|
|
5614
7484
|
...BTN_RESET,
|
|
5615
7485
|
display: "flex",
|
|
5616
7486
|
alignItems: "center",
|
|
5617
|
-
gap:
|
|
5618
|
-
padding: "
|
|
5619
|
-
|
|
5620
|
-
background: selected ? "rgba(99,102,241,0.07)" : "transparent",
|
|
7487
|
+
gap: 12,
|
|
7488
|
+
padding: "6px 16px",
|
|
7489
|
+
background: selected ? "rgba(13,13,13,0.04)" : "transparent",
|
|
5621
7490
|
transition: "background 0.08s"
|
|
5622
7491
|
},
|
|
5623
7492
|
onMouseEnter,
|
|
5624
7493
|
onMouseDown,
|
|
5625
7494
|
children: [
|
|
5626
|
-
item.icon !== void 0 && /* @__PURE__ */
|
|
7495
|
+
item.icon !== void 0 && /* @__PURE__ */ jsx7("span", { style: { flexShrink: 0, display: "flex", alignItems: "center" }, children: item.icon }),
|
|
7496
|
+
/* @__PURE__ */ jsx7(
|
|
5627
7497
|
"span",
|
|
5628
7498
|
{
|
|
5629
7499
|
style: {
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
background: "rgba(0,0,0,0.04)",
|
|
5638
|
-
fontSize: 13,
|
|
5639
|
-
fontWeight: 700,
|
|
5640
|
-
color: "#6366f1",
|
|
5641
|
-
fontFamily: "monospace"
|
|
7500
|
+
fontSize: 14,
|
|
7501
|
+
fontWeight: 400,
|
|
7502
|
+
color: "#0d0d0d",
|
|
7503
|
+
whiteSpace: "nowrap",
|
|
7504
|
+
overflow: "hidden",
|
|
7505
|
+
textOverflow: "ellipsis",
|
|
7506
|
+
minWidth: 0
|
|
5642
7507
|
},
|
|
5643
|
-
children: item.
|
|
7508
|
+
children: item.title
|
|
5644
7509
|
}
|
|
5645
7510
|
),
|
|
5646
|
-
/* @__PURE__ */
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
item.description && /* @__PURE__ */ jsx6(
|
|
5662
|
-
"span",
|
|
5663
|
-
{
|
|
5664
|
-
style: {
|
|
5665
|
-
fontSize: 11,
|
|
5666
|
-
color: "#9ca3af",
|
|
5667
|
-
whiteSpace: "nowrap",
|
|
5668
|
-
overflow: "hidden",
|
|
5669
|
-
textOverflow: "ellipsis"
|
|
5670
|
-
},
|
|
5671
|
-
children: item.description
|
|
5672
|
-
}
|
|
5673
|
-
)
|
|
5674
|
-
] })
|
|
7511
|
+
/* @__PURE__ */ jsx7("span", { style: { flex: 1 } }),
|
|
7512
|
+
(item.description || item.shortcut) && /* @__PURE__ */ jsx7(
|
|
7513
|
+
"span",
|
|
7514
|
+
{
|
|
7515
|
+
style: {
|
|
7516
|
+
fontSize: 12,
|
|
7517
|
+
color: "#5e5e5e",
|
|
7518
|
+
whiteSpace: "nowrap",
|
|
7519
|
+
flexShrink: 0,
|
|
7520
|
+
textAlign: "right",
|
|
7521
|
+
fontFamily: item.shortcut ? "monospace" : "inherit"
|
|
7522
|
+
},
|
|
7523
|
+
children: item.shortcut ?? item.description
|
|
7524
|
+
}
|
|
7525
|
+
)
|
|
5675
7526
|
]
|
|
5676
7527
|
}
|
|
5677
7528
|
);
|
|
5678
7529
|
}
|
|
5679
7530
|
|
|
5680
7531
|
// src/ui/components/JinjaTreeView.tsx
|
|
5681
|
-
import { useState as
|
|
5682
|
-
import { jsx as
|
|
7532
|
+
import { useState as useState5 } from "react";
|
|
7533
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5683
7534
|
var BRANCH_COLORS = {
|
|
5684
7535
|
if: "#6366f1",
|
|
5685
7536
|
elif: "#f59e0b",
|
|
@@ -5699,21 +7550,21 @@ function BranchNode({
|
|
|
5699
7550
|
const blockCount = branch.blockEndIndex - branch.blockStartIndex;
|
|
5700
7551
|
const preview = getBlockPreview(doc2, branch.blockStartIndex, branch.blockEndIndex);
|
|
5701
7552
|
const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
|
|
5702
|
-
return /* @__PURE__ */
|
|
5703
|
-
/* @__PURE__ */
|
|
7553
|
+
return /* @__PURE__ */ jsxs7("div", { className: "jinja-tree-branch", children: [
|
|
7554
|
+
/* @__PURE__ */ jsxs7("span", { className: "jinja-tree-connector", children: [
|
|
5704
7555
|
connector,
|
|
5705
7556
|
" "
|
|
5706
7557
|
] }),
|
|
5707
|
-
/* @__PURE__ */
|
|
7558
|
+
/* @__PURE__ */ jsxs7("span", { className: "jinja-tree-badge", style: { color, borderColor: color }, children: [
|
|
5708
7559
|
"[",
|
|
5709
7560
|
branch.type,
|
|
5710
7561
|
"]"
|
|
5711
7562
|
] }),
|
|
5712
|
-
branch.condition && /* @__PURE__ */
|
|
7563
|
+
branch.condition && /* @__PURE__ */ jsxs7("span", { className: "jinja-tree-condition", children: [
|
|
5713
7564
|
" ",
|
|
5714
7565
|
branch.condition
|
|
5715
7566
|
] }),
|
|
5716
|
-
/* @__PURE__ */
|
|
7567
|
+
/* @__PURE__ */ jsxs7("span", { className: "jinja-tree-meta", children: [
|
|
5717
7568
|
" ",
|
|
5718
7569
|
blockCount,
|
|
5719
7570
|
" block",
|
|
@@ -5723,23 +7574,23 @@ function BranchNode({
|
|
|
5723
7574
|
] });
|
|
5724
7575
|
}
|
|
5725
7576
|
function StructureNode({ structure, doc: doc2 }) {
|
|
5726
|
-
const [expanded, setExpanded] =
|
|
7577
|
+
const [expanded, setExpanded] = useState5(true);
|
|
5727
7578
|
const firstBranch = structure.branches[0];
|
|
5728
7579
|
const label = firstBranch?.condition ? `if ${firstBranch.condition}` : "if";
|
|
5729
|
-
return /* @__PURE__ */
|
|
5730
|
-
/* @__PURE__ */
|
|
7580
|
+
return /* @__PURE__ */ jsxs7("div", { className: "jinja-tree-structure", children: [
|
|
7581
|
+
/* @__PURE__ */ jsxs7(
|
|
5731
7582
|
"button",
|
|
5732
7583
|
{
|
|
5733
7584
|
className: "jinja-tree-toggle",
|
|
5734
7585
|
onClick: () => setExpanded(!expanded),
|
|
5735
7586
|
type: "button",
|
|
5736
7587
|
children: [
|
|
5737
|
-
/* @__PURE__ */
|
|
5738
|
-
/* @__PURE__ */
|
|
7588
|
+
/* @__PURE__ */ jsx8("span", { className: "jinja-tree-arrow", children: expanded ? "\u25BC" : "\u25B6" }),
|
|
7589
|
+
/* @__PURE__ */ jsx8("span", { className: "jinja-tree-label", children: label })
|
|
5739
7590
|
]
|
|
5740
7591
|
}
|
|
5741
7592
|
),
|
|
5742
|
-
expanded && /* @__PURE__ */
|
|
7593
|
+
expanded && /* @__PURE__ */ jsx8("div", { className: "jinja-tree-branches", children: structure.branches.map((branch, i) => /* @__PURE__ */ jsx8(
|
|
5743
7594
|
BranchNode,
|
|
5744
7595
|
{
|
|
5745
7596
|
branch,
|
|
@@ -5753,16 +7604,182 @@ function StructureNode({ structure, doc: doc2 }) {
|
|
|
5753
7604
|
function JinjaTreeView({ doc: doc2, className }) {
|
|
5754
7605
|
const structures = analyzeJinjaBlocks(doc2);
|
|
5755
7606
|
if (structures.length === 0) return null;
|
|
5756
|
-
return /* @__PURE__ */
|
|
7607
|
+
return /* @__PURE__ */ jsx8("div", { className: `jinja-tree ${className || ""}`, children: structures.map((structure) => /* @__PURE__ */ jsx8(StructureNode, { structure, doc: doc2 }, structure.id)) });
|
|
7608
|
+
}
|
|
7609
|
+
|
|
7610
|
+
// src/ui/components/DocumentTreeView.tsx
|
|
7611
|
+
import { useState as useState6 } from "react";
|
|
7612
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
7613
|
+
var ICONS = {
|
|
7614
|
+
heading: "H",
|
|
7615
|
+
jumpPoint: "\u2299",
|
|
7616
|
+
jinjaIf: "\u2325",
|
|
7617
|
+
jinjaBranch: "\u2387",
|
|
7618
|
+
resourceTag: "\u229B",
|
|
7619
|
+
noteBlock: "\u270D",
|
|
7620
|
+
endAction: "\u2192"
|
|
7621
|
+
};
|
|
7622
|
+
var COLORS = {
|
|
7623
|
+
heading: "#333",
|
|
7624
|
+
jumpPoint: "#d97706",
|
|
7625
|
+
jinjaIf: "#6366f1",
|
|
7626
|
+
jinjaBranch: "#8b5cf6",
|
|
7627
|
+
resourceTag: "#059669",
|
|
7628
|
+
noteBlock: "#999",
|
|
7629
|
+
endAction: "#059669"
|
|
7630
|
+
};
|
|
7631
|
+
function TreeNodeItem({
|
|
7632
|
+
node,
|
|
7633
|
+
onNavigate,
|
|
7634
|
+
depth,
|
|
7635
|
+
selectedPath,
|
|
7636
|
+
onSelect,
|
|
7637
|
+
path
|
|
7638
|
+
}) {
|
|
7639
|
+
const [collapsed, setCollapsed] = useState6(false);
|
|
7640
|
+
const hasChildren = node.children.length > 0;
|
|
7641
|
+
const icon = ICONS[node.type] || "\u2022";
|
|
7642
|
+
const color = COLORS[node.type] || "#666";
|
|
7643
|
+
const isSelected = selectedPath === path;
|
|
7644
|
+
const headingLevel = node.meta?.level;
|
|
7645
|
+
const headingLabel = headingLevel ? `H${headingLevel}` : icon;
|
|
7646
|
+
return /* @__PURE__ */ jsxs8("div", { style: { paddingLeft: depth > 0 ? 16 : 0 }, children: [
|
|
7647
|
+
/* @__PURE__ */ jsxs8(
|
|
7648
|
+
"div",
|
|
7649
|
+
{
|
|
7650
|
+
className: "doc-tree-node",
|
|
7651
|
+
style: {
|
|
7652
|
+
display: "flex",
|
|
7653
|
+
alignItems: "center",
|
|
7654
|
+
gap: 6,
|
|
7655
|
+
padding: "3px 6px",
|
|
7656
|
+
borderRadius: 4,
|
|
7657
|
+
cursor: onNavigate ? "pointer" : "default",
|
|
7658
|
+
fontSize: 13,
|
|
7659
|
+
lineHeight: "1.5",
|
|
7660
|
+
background: isSelected ? "rgba(99, 102, 241, 0.1)" : "transparent",
|
|
7661
|
+
transition: "background 0.12s ease"
|
|
7662
|
+
},
|
|
7663
|
+
onClick: (e) => {
|
|
7664
|
+
e.stopPropagation();
|
|
7665
|
+
if (hasChildren) setCollapsed(!collapsed);
|
|
7666
|
+
onSelect(path);
|
|
7667
|
+
onNavigate?.(node.blockIndex);
|
|
7668
|
+
},
|
|
7669
|
+
onMouseEnter: (e) => {
|
|
7670
|
+
if (!isSelected) e.currentTarget.style.background = "#f3f4f6";
|
|
7671
|
+
},
|
|
7672
|
+
onMouseLeave: (e) => {
|
|
7673
|
+
if (!isSelected) e.currentTarget.style.background = "transparent";
|
|
7674
|
+
},
|
|
7675
|
+
children: [
|
|
7676
|
+
hasChildren && /* @__PURE__ */ jsx9(
|
|
7677
|
+
"span",
|
|
7678
|
+
{
|
|
7679
|
+
style: {
|
|
7680
|
+
width: 14,
|
|
7681
|
+
textAlign: "center",
|
|
7682
|
+
fontSize: 10,
|
|
7683
|
+
color: "#999",
|
|
7684
|
+
flexShrink: 0,
|
|
7685
|
+
userSelect: "none"
|
|
7686
|
+
},
|
|
7687
|
+
children: collapsed ? "\u25B8" : "\u25BE"
|
|
7688
|
+
}
|
|
7689
|
+
),
|
|
7690
|
+
!hasChildren && /* @__PURE__ */ jsx9("span", { style: { width: 14, flexShrink: 0 } }),
|
|
7691
|
+
/* @__PURE__ */ jsx9(
|
|
7692
|
+
"span",
|
|
7693
|
+
{
|
|
7694
|
+
style: {
|
|
7695
|
+
display: "inline-flex",
|
|
7696
|
+
alignItems: "center",
|
|
7697
|
+
justifyContent: "center",
|
|
7698
|
+
width: 22,
|
|
7699
|
+
height: 18,
|
|
7700
|
+
borderRadius: 3,
|
|
7701
|
+
fontSize: 10,
|
|
7702
|
+
fontWeight: 700,
|
|
7703
|
+
color: isSelected ? "#6366f1" : color,
|
|
7704
|
+
background: isSelected ? "rgba(99, 102, 241, 0.15)" : `${color}11`,
|
|
7705
|
+
border: `1px solid ${isSelected ? "rgba(99, 102, 241, 0.3)" : `${color}33`}`,
|
|
7706
|
+
flexShrink: 0
|
|
7707
|
+
},
|
|
7708
|
+
children: node.type === "heading" ? headingLabel : icon
|
|
7709
|
+
}
|
|
7710
|
+
),
|
|
7711
|
+
/* @__PURE__ */ jsx9(
|
|
7712
|
+
"span",
|
|
7713
|
+
{
|
|
7714
|
+
style: {
|
|
7715
|
+
overflow: "hidden",
|
|
7716
|
+
textOverflow: "ellipsis",
|
|
7717
|
+
whiteSpace: "nowrap",
|
|
7718
|
+
color: isSelected ? "#6366f1" : node.type === "noteBlock" ? "#999" : node.type === "endAction" ? "#059669" : "#333",
|
|
7719
|
+
fontStyle: node.type === "noteBlock" ? "italic" : "normal",
|
|
7720
|
+
fontWeight: isSelected ? 600 : node.type === "heading" && headingLevel && headingLevel <= 2 ? 600 : 400
|
|
7721
|
+
},
|
|
7722
|
+
children: node.label
|
|
7723
|
+
}
|
|
7724
|
+
),
|
|
7725
|
+
node.meta?.tagType != null && /* @__PURE__ */ jsx9(
|
|
7726
|
+
"span",
|
|
7727
|
+
{
|
|
7728
|
+
style: {
|
|
7729
|
+
fontSize: 10,
|
|
7730
|
+
padding: "1px 5px",
|
|
7731
|
+
borderRadius: 999,
|
|
7732
|
+
background: node.type === "endAction" ? "rgba(5, 150, 105, 0.1)" : "rgba(0, 0, 0, 0.04)",
|
|
7733
|
+
color: node.type === "endAction" ? "#059669" : "#999",
|
|
7734
|
+
fontWeight: 500
|
|
7735
|
+
},
|
|
7736
|
+
children: String(node.meta.tagType)
|
|
7737
|
+
}
|
|
7738
|
+
)
|
|
7739
|
+
]
|
|
7740
|
+
}
|
|
7741
|
+
),
|
|
7742
|
+
hasChildren && !collapsed && /* @__PURE__ */ jsx9("div", { children: node.children.map((child, i) => /* @__PURE__ */ jsx9(
|
|
7743
|
+
TreeNodeItem,
|
|
7744
|
+
{
|
|
7745
|
+
node: child,
|
|
7746
|
+
onNavigate,
|
|
7747
|
+
depth: depth + 1,
|
|
7748
|
+
selectedPath,
|
|
7749
|
+
onSelect,
|
|
7750
|
+
path: `${path}/${i}`
|
|
7751
|
+
},
|
|
7752
|
+
`${child.type}-${child.blockIndex}-${i}`
|
|
7753
|
+
)) })
|
|
7754
|
+
] });
|
|
7755
|
+
}
|
|
7756
|
+
function DocumentTreeView({ doc: doc2, className, onNavigate }) {
|
|
7757
|
+
const tree = buildDocumentTree(doc2);
|
|
7758
|
+
const [selectedPath, setSelectedPath] = useState6(null);
|
|
7759
|
+
if (tree.length === 0) {
|
|
7760
|
+
return /* @__PURE__ */ jsx9("div", { className, style: { color: "#999", fontSize: 13, padding: 16 }, children: "No document structure to display." });
|
|
7761
|
+
}
|
|
7762
|
+
return /* @__PURE__ */ jsx9("div", { className, style: { padding: "8px 0", fontFamily: "Inter, sans-serif" }, children: tree.map((node, i) => /* @__PURE__ */ jsx9(
|
|
7763
|
+
TreeNodeItem,
|
|
7764
|
+
{
|
|
7765
|
+
node,
|
|
7766
|
+
onNavigate,
|
|
7767
|
+
depth: 0,
|
|
7768
|
+
selectedPath,
|
|
7769
|
+
onSelect: setSelectedPath,
|
|
7770
|
+
path: `${i}`
|
|
7771
|
+
},
|
|
7772
|
+
`${node.type}-${node.blockIndex}-${i}`
|
|
7773
|
+
)) });
|
|
5757
7774
|
}
|
|
5758
7775
|
|
|
5759
7776
|
// src/ui/components/FloatingMenu.tsx
|
|
5760
|
-
import { useCallback as
|
|
7777
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
|
|
5761
7778
|
import { createPortal as createPortal2 } from "react-dom";
|
|
5762
|
-
import { setBlockType, toggleMark as toggleMark2, wrapIn } from "prosemirror-commands";
|
|
7779
|
+
import { setBlockType as setBlockType2, toggleMark as toggleMark2, wrapIn } from "prosemirror-commands";
|
|
5763
7780
|
import { wrapInList as wrapInList2 } from "prosemirror-schema-list";
|
|
5764
|
-
import { Fragment as
|
|
5765
|
-
var { paragraph:
|
|
7781
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
7782
|
+
var { paragraph: paragraph3, heading: heading3, bulletList: bulletList3, orderedList: orderedList3, blockquote: blockquote3 } = actionbookSchema.nodes;
|
|
5766
7783
|
var {
|
|
5767
7784
|
bold: bold2,
|
|
5768
7785
|
italic: italic2,
|
|
@@ -5784,7 +7801,7 @@ function hasMark(state, type) {
|
|
|
5784
7801
|
function activeHeadingLevel(state) {
|
|
5785
7802
|
const { $from } = state.selection;
|
|
5786
7803
|
const node = $from.parent;
|
|
5787
|
-
if (node.type ===
|
|
7804
|
+
if (node.type === heading3) return node.attrs.level;
|
|
5788
7805
|
return null;
|
|
5789
7806
|
}
|
|
5790
7807
|
function activeListType(state) {
|
|
@@ -5818,7 +7835,7 @@ function currentBlockLabel(state) {
|
|
|
5818
7835
|
if (lt === "ordered") return "1. List";
|
|
5819
7836
|
const { $from } = state.selection;
|
|
5820
7837
|
for (let d = $from.depth; d > 0; d--) {
|
|
5821
|
-
if ($from.node(d).type ===
|
|
7838
|
+
if ($from.node(d).type === blockquote3) return "Quote";
|
|
5822
7839
|
}
|
|
5823
7840
|
return "Text";
|
|
5824
7841
|
}
|
|
@@ -5827,7 +7844,7 @@ function emptyBlockCursorPos(state) {
|
|
|
5827
7844
|
if (!selection.empty) return null;
|
|
5828
7845
|
const { $from } = selection;
|
|
5829
7846
|
const parent = $from.parent;
|
|
5830
|
-
if ((parent.type ===
|
|
7847
|
+
if ((parent.type === paragraph3 || parent.type === heading3) && parent.content.size === 0) {
|
|
5831
7848
|
return selection.from;
|
|
5832
7849
|
}
|
|
5833
7850
|
return null;
|
|
@@ -5849,8 +7866,8 @@ var BTN_RESET2 = {
|
|
|
5849
7866
|
lineHeight: 1
|
|
5850
7867
|
};
|
|
5851
7868
|
function TBtn({ children, active, title, onMouseDown, style }) {
|
|
5852
|
-
const [hover, setHover] =
|
|
5853
|
-
return /* @__PURE__ */
|
|
7869
|
+
const [hover, setHover] = useState7(false);
|
|
7870
|
+
return /* @__PURE__ */ jsx10(
|
|
5854
7871
|
"button",
|
|
5855
7872
|
{
|
|
5856
7873
|
...{ [FLOAT_ATTR]: "" },
|
|
@@ -5881,13 +7898,13 @@ function TBtn({ children, active, title, onMouseDown, style }) {
|
|
|
5881
7898
|
);
|
|
5882
7899
|
}
|
|
5883
7900
|
function Divider() {
|
|
5884
|
-
return /* @__PURE__ */
|
|
7901
|
+
return /* @__PURE__ */ jsx10("div", { style: { width: 1, height: 18, background: "rgba(0,0,0,0.07)", margin: "0 2px", flexShrink: 0 } });
|
|
5885
7902
|
}
|
|
5886
7903
|
function BlockTypeDropdown({ view, state, label }) {
|
|
5887
|
-
const [open, setOpen] =
|
|
5888
|
-
const btnRef =
|
|
5889
|
-
const [hover, setHover] =
|
|
5890
|
-
|
|
7904
|
+
const [open, setOpen] = useState7(false);
|
|
7905
|
+
const btnRef = useRef4(null);
|
|
7906
|
+
const [hover, setHover] = useState7(false);
|
|
7907
|
+
useEffect4(() => {
|
|
5891
7908
|
if (!open) return;
|
|
5892
7909
|
const onDown = (e) => {
|
|
5893
7910
|
if (!e.target.closest(`[${FLOAT_ATTR}]`)) {
|
|
@@ -5901,19 +7918,19 @@ function BlockTypeDropdown({ view, state, label }) {
|
|
|
5901
7918
|
const listType = activeListType(state);
|
|
5902
7919
|
const items = [
|
|
5903
7920
|
{ label: "Text", shortLabel: "\xB6", active: !headingLevel && !listType, run: () => {
|
|
5904
|
-
|
|
7921
|
+
setBlockType2(paragraph3)(view.state, view.dispatch);
|
|
5905
7922
|
view.focus();
|
|
5906
7923
|
} },
|
|
5907
7924
|
{ label: "Heading 1", shortLabel: "H1", active: headingLevel === 1, run: () => {
|
|
5908
|
-
|
|
7925
|
+
setBlockType2(heading3, { level: 1 })(view.state, view.dispatch);
|
|
5909
7926
|
view.focus();
|
|
5910
7927
|
} },
|
|
5911
7928
|
{ label: "Heading 2", shortLabel: "H2", active: headingLevel === 2, run: () => {
|
|
5912
|
-
|
|
7929
|
+
setBlockType2(heading3, { level: 2 })(view.state, view.dispatch);
|
|
5913
7930
|
view.focus();
|
|
5914
7931
|
} },
|
|
5915
7932
|
{ label: "Heading 3", shortLabel: "H3", active: headingLevel === 3, run: () => {
|
|
5916
|
-
|
|
7933
|
+
setBlockType2(heading3, { level: 3 })(view.state, view.dispatch);
|
|
5917
7934
|
view.focus();
|
|
5918
7935
|
} },
|
|
5919
7936
|
{ label: "Bullet List", shortLabel: "\u2022", active: listType === "bullet", run: () => {
|
|
@@ -5935,13 +7952,17 @@ function BlockTypeDropdown({ view, state, label }) {
|
|
|
5935
7952
|
view.focus();
|
|
5936
7953
|
} },
|
|
5937
7954
|
{ label: "Quote", shortLabel: ">", active: false, run: () => {
|
|
5938
|
-
|
|
7955
|
+
const { $from } = view.state.selection;
|
|
7956
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
7957
|
+
if ($from.node(d).type.name === "listItem") return;
|
|
7958
|
+
}
|
|
7959
|
+
wrapIn(blockquote3)(view.state, view.dispatch);
|
|
5939
7960
|
view.focus();
|
|
5940
7961
|
} }
|
|
5941
7962
|
];
|
|
5942
7963
|
const btnRect = btnRef.current?.getBoundingClientRect();
|
|
5943
|
-
return /* @__PURE__ */
|
|
5944
|
-
/* @__PURE__ */
|
|
7964
|
+
return /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
7965
|
+
/* @__PURE__ */ jsxs9(
|
|
5945
7966
|
"button",
|
|
5946
7967
|
{
|
|
5947
7968
|
ref: btnRef,
|
|
@@ -5969,12 +7990,12 @@ function BlockTypeDropdown({ view, state, label }) {
|
|
|
5969
7990
|
},
|
|
5970
7991
|
children: [
|
|
5971
7992
|
label,
|
|
5972
|
-
/* @__PURE__ */
|
|
7993
|
+
/* @__PURE__ */ jsx10("span", { style: { fontSize: 8, opacity: 0.6 }, children: "\u25BE" })
|
|
5973
7994
|
]
|
|
5974
7995
|
}
|
|
5975
7996
|
),
|
|
5976
7997
|
open && btnRect && createPortal2(
|
|
5977
|
-
/* @__PURE__ */
|
|
7998
|
+
/* @__PURE__ */ jsx10(
|
|
5978
7999
|
"div",
|
|
5979
8000
|
{
|
|
5980
8001
|
...{ [FLOAT_ATTR]: "" },
|
|
@@ -5990,7 +8011,7 @@ function BlockTypeDropdown({ view, state, label }) {
|
|
|
5990
8011
|
minWidth: 168,
|
|
5991
8012
|
animation: "ab-float-in 0.12s ease"
|
|
5992
8013
|
},
|
|
5993
|
-
children: items.map((item) => /* @__PURE__ */
|
|
8014
|
+
children: items.map((item) => /* @__PURE__ */ jsx10(DropdownItem, { item, onRun: () => setOpen(false) }, item.label))
|
|
5994
8015
|
}
|
|
5995
8016
|
),
|
|
5996
8017
|
document.body
|
|
@@ -5998,8 +8019,8 @@ function BlockTypeDropdown({ view, state, label }) {
|
|
|
5998
8019
|
] });
|
|
5999
8020
|
}
|
|
6000
8021
|
function DropdownItem({ item, onRun }) {
|
|
6001
|
-
const [hover, setHover] =
|
|
6002
|
-
return /* @__PURE__ */
|
|
8022
|
+
const [hover, setHover] = useState7(false);
|
|
8023
|
+
return /* @__PURE__ */ jsxs9(
|
|
6003
8024
|
"button",
|
|
6004
8025
|
{
|
|
6005
8026
|
...{ [FLOAT_ATTR]: "" },
|
|
@@ -6026,16 +8047,16 @@ function DropdownItem({ item, onRun }) {
|
|
|
6026
8047
|
transition: "background 0.1s"
|
|
6027
8048
|
},
|
|
6028
8049
|
children: [
|
|
6029
|
-
/* @__PURE__ */
|
|
8050
|
+
/* @__PURE__ */ jsx10("span", { style: { width: 24, flexShrink: 0, textAlign: "center", fontWeight: 700, fontSize: 12, fontFamily: "monospace", color: "#6366f1" }, children: item.shortLabel }),
|
|
6030
8051
|
item.label
|
|
6031
8052
|
]
|
|
6032
8053
|
}
|
|
6033
8054
|
);
|
|
6034
8055
|
}
|
|
6035
8056
|
function SelectionToolbar({ view, state, selectionRect }) {
|
|
6036
|
-
const [linkMode, setLinkMode] =
|
|
6037
|
-
const [linkHref, setLinkHref] =
|
|
6038
|
-
const inputRef =
|
|
8057
|
+
const [linkMode, setLinkMode] = useState7(false);
|
|
8058
|
+
const [linkHref, setLinkHref] = useState7("");
|
|
8059
|
+
const inputRef = useRef4(null);
|
|
6039
8060
|
const isBold = hasMark(state, bold2);
|
|
6040
8061
|
const isItalic = hasMark(state, italic2);
|
|
6041
8062
|
const isUnderline = hasMark(state, underline2);
|
|
@@ -6050,7 +8071,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6050
8071
|
if (top < VPORT_MARGIN2) top = selectionRect.bottom + TOOLBAR_GAP;
|
|
6051
8072
|
left = Math.max(VPORT_MARGIN2, Math.min(left, window.innerWidth - toolbarW - VPORT_MARGIN2));
|
|
6052
8073
|
top = Math.max(VPORT_MARGIN2, Math.min(top, window.innerHeight - toolbarH - VPORT_MARGIN2));
|
|
6053
|
-
const run =
|
|
8074
|
+
const run = useCallback3(
|
|
6054
8075
|
(cmd) => {
|
|
6055
8076
|
cmd(view.state, view.dispatch);
|
|
6056
8077
|
view.focus();
|
|
@@ -6087,10 +8108,10 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6087
8108
|
view.dispatch(view.state.tr.removeMark(from, to, linkMark));
|
|
6088
8109
|
view.focus();
|
|
6089
8110
|
};
|
|
6090
|
-
return /* @__PURE__ */
|
|
8111
|
+
return /* @__PURE__ */ jsx10(
|
|
6091
8112
|
"div",
|
|
6092
8113
|
{
|
|
6093
|
-
...{ [FLOAT_ATTR]: "" },
|
|
8114
|
+
...{ [FLOAT_ATTR]: "selection-toolbar" },
|
|
6094
8115
|
style: {
|
|
6095
8116
|
position: "fixed",
|
|
6096
8117
|
left,
|
|
@@ -6110,9 +8131,9 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6110
8131
|
},
|
|
6111
8132
|
children: linkMode ? (
|
|
6112
8133
|
/* ── Link input mode ── */
|
|
6113
|
-
/* @__PURE__ */
|
|
6114
|
-
/* @__PURE__ */
|
|
6115
|
-
/* @__PURE__ */
|
|
8134
|
+
/* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
8135
|
+
/* @__PURE__ */ jsx10("span", { style: { fontSize: 13, color: "#9ca3af", paddingLeft: 4, flexShrink: 0 }, children: "\u2197" }),
|
|
8136
|
+
/* @__PURE__ */ jsx10(
|
|
6116
8137
|
"input",
|
|
6117
8138
|
{
|
|
6118
8139
|
ref: inputRef,
|
|
@@ -6143,7 +8164,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6143
8164
|
}
|
|
6144
8165
|
}
|
|
6145
8166
|
),
|
|
6146
|
-
/* @__PURE__ */
|
|
8167
|
+
/* @__PURE__ */ jsx10(
|
|
6147
8168
|
TBtn,
|
|
6148
8169
|
{
|
|
6149
8170
|
title: "Apply (Enter)",
|
|
@@ -6155,7 +8176,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6155
8176
|
children: "\u21B5"
|
|
6156
8177
|
}
|
|
6157
8178
|
),
|
|
6158
|
-
/* @__PURE__ */
|
|
8179
|
+
/* @__PURE__ */ jsx10(
|
|
6159
8180
|
TBtn,
|
|
6160
8181
|
{
|
|
6161
8182
|
title: "Cancel (Esc)",
|
|
@@ -6171,8 +8192,8 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6171
8192
|
] })
|
|
6172
8193
|
) : (
|
|
6173
8194
|
/* ── Normal toolbar mode ── */
|
|
6174
|
-
/* @__PURE__ */
|
|
6175
|
-
/* @__PURE__ */
|
|
8195
|
+
/* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
8196
|
+
/* @__PURE__ */ jsx10(
|
|
6176
8197
|
TBtn,
|
|
6177
8198
|
{
|
|
6178
8199
|
active: isBold,
|
|
@@ -6182,7 +8203,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6182
8203
|
children: "B"
|
|
6183
8204
|
}
|
|
6184
8205
|
),
|
|
6185
|
-
/* @__PURE__ */
|
|
8206
|
+
/* @__PURE__ */ jsx10(
|
|
6186
8207
|
TBtn,
|
|
6187
8208
|
{
|
|
6188
8209
|
active: isItalic,
|
|
@@ -6192,7 +8213,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6192
8213
|
children: "I"
|
|
6193
8214
|
}
|
|
6194
8215
|
),
|
|
6195
|
-
/* @__PURE__ */
|
|
8216
|
+
/* @__PURE__ */ jsx10(
|
|
6196
8217
|
TBtn,
|
|
6197
8218
|
{
|
|
6198
8219
|
active: isUnderline,
|
|
@@ -6202,7 +8223,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6202
8223
|
children: "U"
|
|
6203
8224
|
}
|
|
6204
8225
|
),
|
|
6205
|
-
/* @__PURE__ */
|
|
8226
|
+
/* @__PURE__ */ jsx10(
|
|
6206
8227
|
TBtn,
|
|
6207
8228
|
{
|
|
6208
8229
|
active: isStrike,
|
|
@@ -6212,7 +8233,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6212
8233
|
children: "S"
|
|
6213
8234
|
}
|
|
6214
8235
|
),
|
|
6215
|
-
/* @__PURE__ */
|
|
8236
|
+
/* @__PURE__ */ jsx10(
|
|
6216
8237
|
TBtn,
|
|
6217
8238
|
{
|
|
6218
8239
|
active: isCode,
|
|
@@ -6222,7 +8243,7 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6222
8243
|
children: "`\xB7`"
|
|
6223
8244
|
}
|
|
6224
8245
|
),
|
|
6225
|
-
/* @__PURE__ */
|
|
8246
|
+
/* @__PURE__ */ jsx10(
|
|
6226
8247
|
TBtn,
|
|
6227
8248
|
{
|
|
6228
8249
|
active: isLink,
|
|
@@ -6232,8 +8253,8 @@ function SelectionToolbar({ view, state, selectionRect }) {
|
|
|
6232
8253
|
children: "\u2197"
|
|
6233
8254
|
}
|
|
6234
8255
|
),
|
|
6235
|
-
/* @__PURE__ */
|
|
6236
|
-
/* @__PURE__ */
|
|
8256
|
+
/* @__PURE__ */ jsx10(Divider, {}),
|
|
8257
|
+
/* @__PURE__ */ jsx10(BlockTypeDropdown, { view, state, label: blockLabel })
|
|
6237
8258
|
] })
|
|
6238
8259
|
)
|
|
6239
8260
|
}
|
|
@@ -6244,7 +8265,7 @@ var BLOCK_ITEMS = [
|
|
|
6244
8265
|
shortLabel: "\xB6",
|
|
6245
8266
|
label: "Text",
|
|
6246
8267
|
run: (v) => {
|
|
6247
|
-
|
|
8268
|
+
setBlockType2(paragraph3)(v.state, v.dispatch);
|
|
6248
8269
|
v.focus();
|
|
6249
8270
|
}
|
|
6250
8271
|
},
|
|
@@ -6252,7 +8273,7 @@ var BLOCK_ITEMS = [
|
|
|
6252
8273
|
shortLabel: "H1",
|
|
6253
8274
|
label: "Heading 1",
|
|
6254
8275
|
run: (v) => {
|
|
6255
|
-
|
|
8276
|
+
setBlockType2(heading3, { level: 1 })(v.state, v.dispatch);
|
|
6256
8277
|
v.focus();
|
|
6257
8278
|
}
|
|
6258
8279
|
},
|
|
@@ -6260,7 +8281,7 @@ var BLOCK_ITEMS = [
|
|
|
6260
8281
|
shortLabel: "H2",
|
|
6261
8282
|
label: "Heading 2",
|
|
6262
8283
|
run: (v) => {
|
|
6263
|
-
|
|
8284
|
+
setBlockType2(heading3, { level: 2 })(v.state, v.dispatch);
|
|
6264
8285
|
v.focus();
|
|
6265
8286
|
}
|
|
6266
8287
|
},
|
|
@@ -6268,7 +8289,7 @@ var BLOCK_ITEMS = [
|
|
|
6268
8289
|
shortLabel: "H3",
|
|
6269
8290
|
label: "Heading 3",
|
|
6270
8291
|
run: (v) => {
|
|
6271
|
-
|
|
8292
|
+
setBlockType2(heading3, { level: 3 })(v.state, v.dispatch);
|
|
6272
8293
|
v.focus();
|
|
6273
8294
|
}
|
|
6274
8295
|
},
|
|
@@ -6303,7 +8324,7 @@ var BLOCK_ITEMS = [
|
|
|
6303
8324
|
shortLabel: "\u275D",
|
|
6304
8325
|
label: "Quote",
|
|
6305
8326
|
run: (v) => {
|
|
6306
|
-
wrapIn(
|
|
8327
|
+
wrapIn(blockquote3)(v.state, v.dispatch);
|
|
6307
8328
|
v.focus();
|
|
6308
8329
|
}
|
|
6309
8330
|
},
|
|
@@ -6323,7 +8344,7 @@ var BLOCK_ITEMS = [
|
|
|
6323
8344
|
}
|
|
6324
8345
|
];
|
|
6325
8346
|
function EmptyParaHandle({ view, cursorPos }) {
|
|
6326
|
-
const [menuOpen, setMenuOpen] =
|
|
8347
|
+
const [menuOpen, setMenuOpen] = useState7(false);
|
|
6327
8348
|
const coords = view.coordsAtPos(cursorPos);
|
|
6328
8349
|
const lineH = Math.max(coords.bottom - coords.top, 18);
|
|
6329
8350
|
const btnSize = 22;
|
|
@@ -6331,7 +8352,7 @@ function EmptyParaHandle({ view, cursorPos }) {
|
|
|
6331
8352
|
const btnTop = coords.top + (lineH - btnSize) / 2;
|
|
6332
8353
|
const menuLeft = Math.max(VPORT_MARGIN2, btnLeft);
|
|
6333
8354
|
const menuTop = btnTop + btnSize + 4;
|
|
6334
|
-
|
|
8355
|
+
useEffect4(() => {
|
|
6335
8356
|
if (!menuOpen) return;
|
|
6336
8357
|
const onDown = (e) => {
|
|
6337
8358
|
if (!e.target.closest(`[${FLOAT_ATTR}]`)) {
|
|
@@ -6341,8 +8362,8 @@ function EmptyParaHandle({ view, cursorPos }) {
|
|
|
6341
8362
|
document.addEventListener("mousedown", onDown, true);
|
|
6342
8363
|
return () => document.removeEventListener("mousedown", onDown, true);
|
|
6343
8364
|
}, [menuOpen]);
|
|
6344
|
-
return /* @__PURE__ */
|
|
6345
|
-
/* @__PURE__ */
|
|
8365
|
+
return /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
8366
|
+
/* @__PURE__ */ jsx10(
|
|
6346
8367
|
"button",
|
|
6347
8368
|
{
|
|
6348
8369
|
...{ [FLOAT_ATTR]: "" },
|
|
@@ -6374,7 +8395,7 @@ function EmptyParaHandle({ view, cursorPos }) {
|
|
|
6374
8395
|
children: "+"
|
|
6375
8396
|
}
|
|
6376
8397
|
),
|
|
6377
|
-
menuOpen && /* @__PURE__ */
|
|
8398
|
+
menuOpen && /* @__PURE__ */ jsx10(
|
|
6378
8399
|
"div",
|
|
6379
8400
|
{
|
|
6380
8401
|
...{ [FLOAT_ATTR]: "" },
|
|
@@ -6390,7 +8411,7 @@ function EmptyParaHandle({ view, cursorPos }) {
|
|
|
6390
8411
|
minWidth: 168,
|
|
6391
8412
|
animation: "ab-float-in 0.12s ease"
|
|
6392
8413
|
},
|
|
6393
|
-
children: BLOCK_ITEMS.map((item) => /* @__PURE__ */
|
|
8414
|
+
children: BLOCK_ITEMS.map((item) => /* @__PURE__ */ jsx10(
|
|
6394
8415
|
BlockMenuItem,
|
|
6395
8416
|
{
|
|
6396
8417
|
item,
|
|
@@ -6408,8 +8429,8 @@ function BlockMenuItem({
|
|
|
6408
8429
|
view,
|
|
6409
8430
|
onRun
|
|
6410
8431
|
}) {
|
|
6411
|
-
const [hover, setHover] =
|
|
6412
|
-
return /* @__PURE__ */
|
|
8432
|
+
const [hover, setHover] = useState7(false);
|
|
8433
|
+
return /* @__PURE__ */ jsxs9(
|
|
6413
8434
|
"button",
|
|
6414
8435
|
{
|
|
6415
8436
|
...{ [FLOAT_ATTR]: "" },
|
|
@@ -6435,7 +8456,7 @@ function BlockMenuItem({
|
|
|
6435
8456
|
transition: "background 0.1s"
|
|
6436
8457
|
},
|
|
6437
8458
|
children: [
|
|
6438
|
-
/* @__PURE__ */
|
|
8459
|
+
/* @__PURE__ */ jsx10(
|
|
6439
8460
|
"span",
|
|
6440
8461
|
{
|
|
6441
8462
|
style: {
|
|
@@ -6456,11 +8477,11 @@ function BlockMenuItem({
|
|
|
6456
8477
|
);
|
|
6457
8478
|
}
|
|
6458
8479
|
function FloatingMenu({ view, editorState }) {
|
|
6459
|
-
const [showEmptyHandle, setShowEmptyHandle] =
|
|
6460
|
-
const dwellTimerRef =
|
|
6461
|
-
const lastEmptyPosRef =
|
|
6462
|
-
const [, setScrollTick] =
|
|
6463
|
-
|
|
8480
|
+
const [showEmptyHandle, setShowEmptyHandle] = useState7(false);
|
|
8481
|
+
const dwellTimerRef = useRef4(null);
|
|
8482
|
+
const lastEmptyPosRef = useRef4(null);
|
|
8483
|
+
const [, setScrollTick] = useState7(0);
|
|
8484
|
+
useEffect4(() => {
|
|
6464
8485
|
const editorDom = view?.dom;
|
|
6465
8486
|
if (!editorDom) return;
|
|
6466
8487
|
const container = editorDom.closest(".editor-shell") ?? editorDom.parentElement;
|
|
@@ -6469,7 +8490,7 @@ function FloatingMenu({ view, editorState }) {
|
|
|
6469
8490
|
container.addEventListener("scroll", onScroll, { passive: true });
|
|
6470
8491
|
return () => container.removeEventListener("scroll", onScroll);
|
|
6471
8492
|
}, [view]);
|
|
6472
|
-
|
|
8493
|
+
useEffect4(() => {
|
|
6473
8494
|
const id = "ab-float-keyframes";
|
|
6474
8495
|
if (document.getElementById(id)) return;
|
|
6475
8496
|
const style = document.createElement("style");
|
|
@@ -6499,8 +8520,8 @@ function FloatingMenu({ view, editorState }) {
|
|
|
6499
8520
|
}
|
|
6500
8521
|
const selectionRect = hasSelection ? getSelectionDOMRect() : null;
|
|
6501
8522
|
return createPortal2(
|
|
6502
|
-
/* @__PURE__ */
|
|
6503
|
-
hasSelection && selectionRect && /* @__PURE__ */
|
|
8523
|
+
/* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
8524
|
+
hasSelection && selectionRect && /* @__PURE__ */ jsx10(
|
|
6504
8525
|
SelectionToolbar,
|
|
6505
8526
|
{
|
|
6506
8527
|
view,
|
|
@@ -6508,23 +8529,23 @@ function FloatingMenu({ view, editorState }) {
|
|
|
6508
8529
|
selectionRect
|
|
6509
8530
|
}
|
|
6510
8531
|
),
|
|
6511
|
-
!hasSelection && showEmptyHandle && emptyPos !== null && /* @__PURE__ */
|
|
8532
|
+
!hasSelection && showEmptyHandle && emptyPos !== null && /* @__PURE__ */ jsx10(EmptyParaHandle, { view, cursorPos: emptyPos })
|
|
6512
8533
|
] }),
|
|
6513
8534
|
document.body
|
|
6514
8535
|
);
|
|
6515
8536
|
}
|
|
6516
8537
|
|
|
6517
8538
|
// src/ui/plugin/inlineSuggestPlugin.ts
|
|
6518
|
-
import { Plugin as
|
|
6519
|
-
import { Decoration as
|
|
6520
|
-
var inlineSuggestKey = new
|
|
8539
|
+
import { Plugin as Plugin8, PluginKey as PluginKey8 } from "prosemirror-state";
|
|
8540
|
+
import { Decoration as Decoration4, DecorationSet as DecorationSet4 } from "prosemirror-view";
|
|
8541
|
+
var inlineSuggestKey = new PluginKey8("inlineSuggest");
|
|
6521
8542
|
var DEBOUNCE_MS = 600;
|
|
6522
8543
|
function createInlineSuggestPlugin(provider, endpoint, options) {
|
|
6523
8544
|
const { onContextChange } = options ?? {};
|
|
6524
8545
|
return {
|
|
6525
8546
|
name: "inlineSuggest",
|
|
6526
8547
|
plugins: () => [
|
|
6527
|
-
new
|
|
8548
|
+
new Plugin8({
|
|
6528
8549
|
key: inlineSuggestKey,
|
|
6529
8550
|
state: {
|
|
6530
8551
|
init: () => ({ suggestion: null, anchorPos: null }),
|
|
@@ -6540,13 +8561,13 @@ function createInlineSuggestPlugin(provider, endpoint, options) {
|
|
|
6540
8561
|
props: {
|
|
6541
8562
|
decorations(state) {
|
|
6542
8563
|
const ps = inlineSuggestKey.getState(state);
|
|
6543
|
-
if (!ps?.suggestion || !state.selection.empty) return
|
|
8564
|
+
if (!ps?.suggestion || !state.selection.empty) return DecorationSet4.empty;
|
|
6544
8565
|
const ghost = document.createElement("span");
|
|
6545
8566
|
ghost.textContent = ps.suggestion;
|
|
6546
8567
|
ghost.style.cssText = "color: rgba(0,0,0,0.3); pointer-events: none; user-select: none;";
|
|
6547
8568
|
ghost.setAttribute("aria-hidden", "true");
|
|
6548
|
-
return
|
|
6549
|
-
|
|
8569
|
+
return DecorationSet4.create(state.doc, [
|
|
8570
|
+
Decoration4.widget(state.selection.from, ghost, {
|
|
6550
8571
|
side: 1,
|
|
6551
8572
|
key: "inline-suggest"
|
|
6552
8573
|
})
|
|
@@ -6677,6 +8698,7 @@ function createInlineSuggestPlugin(provider, endpoint, options) {
|
|
|
6677
8698
|
}
|
|
6678
8699
|
export {
|
|
6679
8700
|
ActionbookRenderer,
|
|
8701
|
+
DocumentTreeView,
|
|
6680
8702
|
EditorShell,
|
|
6681
8703
|
FloatingMenu,
|
|
6682
8704
|
JUMP_POINT_ADJACENT_SPEC,
|
|
@@ -6687,19 +8709,25 @@ export {
|
|
|
6687
8709
|
convertBlock2 as convertBlock,
|
|
6688
8710
|
convertInline2 as convertInline,
|
|
6689
8711
|
createDragHandlePlugin,
|
|
8712
|
+
createHistoryPlugin,
|
|
6690
8713
|
createInlineSuggestPlugin,
|
|
6691
8714
|
createInlineToolTagNodeViewPlugin,
|
|
6692
8715
|
createInputRulesPlugin,
|
|
6693
8716
|
createJinjaDecorationPlugin,
|
|
8717
|
+
createJinjaIfBlockPlugin,
|
|
6694
8718
|
createJumpPointAdjacentPlugin,
|
|
6695
8719
|
createJumpPointNodeViewPlugin,
|
|
8720
|
+
createJumpPointValidationPlugin,
|
|
6696
8721
|
createKeymapPlugin,
|
|
6697
8722
|
createLinkPlugin,
|
|
6698
8723
|
createMarkdownClipboardPlugin,
|
|
8724
|
+
createNoteBlockPlugin,
|
|
6699
8725
|
createPluginArray,
|
|
6700
8726
|
createReactNodeView,
|
|
6701
8727
|
createSlashCommandPlugin,
|
|
6702
8728
|
createTodoNodeViewPlugin,
|
|
8729
|
+
hasBrokenAnchorRefs,
|
|
8730
|
+
hasDuplicateJumpPoints,
|
|
6703
8731
|
inlineSuggestKey,
|
|
6704
8732
|
slashCommandKey,
|
|
6705
8733
|
toProseMirrorJSON,
|