@eventuras/scribo 0.8.2 → 0.10.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +11 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/MarkdownEditor.d.ts +18 -0
- package/dist/MarkdownEditor.d.ts.map +1 -0
- package/dist/MarkdownEditor2.js +111 -0
- package/dist/MarkdownEditor2.js.map +1 -0
- package/dist/MarkdownInput.d.ts +27 -0
- package/dist/MarkdownInput.d.ts.map +1 -0
- package/dist/MarkdownInput.js +57 -0
- package/dist/MarkdownInput.js.map +1 -0
- package/dist/callout.js +5 -0
- package/dist/context/SharedHistoryContext.d.ts +11 -0
- package/dist/context/SharedHistoryContext.d.ts.map +1 -0
- package/dist/context/SharedHistoryContext.js +12 -0
- package/dist/context/SharedHistoryContext.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/main.d.ts +5 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +4 -0
- package/dist/nodes/EditorNodes.d.ts +4 -0
- package/dist/nodes/EditorNodes.d.ts.map +1 -0
- package/dist/nodes/EditorNodes.js +39 -0
- package/dist/nodes/EditorNodes.js.map +1 -0
- package/dist/nodes/callout/CalloutComponent.d.ts +6 -0
- package/dist/nodes/callout/CalloutComponent.d.ts.map +1 -0
- package/dist/nodes/callout/CalloutComponent.js +53 -0
- package/dist/nodes/callout/CalloutComponent.js.map +1 -0
- package/dist/nodes/callout/CalloutNode.d.ts +27 -0
- package/dist/nodes/callout/CalloutNode.d.ts.map +1 -0
- package/dist/nodes/callout/CalloutNode.js +153 -0
- package/dist/nodes/callout/CalloutNode.js.map +1 -0
- package/dist/nodes/callout/CalloutTransformer.d.ts +3 -0
- package/dist/nodes/callout/CalloutTransformer.d.ts.map +1 -0
- package/dist/nodes/callout/CalloutTransformer.js +48 -0
- package/dist/nodes/callout/CalloutTransformer.js.map +1 -0
- package/dist/nodes/callout/calloutPlugin.d.ts +3 -0
- package/dist/nodes/callout/calloutPlugin.d.ts.map +1 -0
- package/dist/nodes/callout/calloutPlugin.js +34 -0
- package/dist/nodes/callout/calloutPlugin.js.map +1 -0
- package/dist/nodes/callout/index.d.ts +6 -0
- package/dist/nodes/callout/index.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleItemComponent.d.ts +9 -0
- package/dist/nodes/schedule/ScheduleItemComponent.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleItemComponent.js +167 -0
- package/dist/nodes/schedule/ScheduleItemComponent.js.map +1 -0
- package/dist/nodes/schedule/ScheduleItemNode.d.ts +31 -0
- package/dist/nodes/schedule/ScheduleItemNode.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleItemNode.js +94 -0
- package/dist/nodes/schedule/ScheduleItemNode.js.map +1 -0
- package/dist/nodes/schedule/ScheduleTransformer.d.ts +22 -0
- package/dist/nodes/schedule/ScheduleTransformer.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleTransformer.js +60 -0
- package/dist/nodes/schedule/ScheduleTransformer.js.map +1 -0
- package/dist/nodes/schedule/index.d.ts +5 -0
- package/dist/nodes/schedule/index.d.ts.map +1 -0
- package/dist/nodes/schedule/schedulePlugin.d.ts +3 -0
- package/dist/nodes/schedule/schedulePlugin.d.ts.map +1 -0
- package/dist/nodes/schedule/schedulePlugin.js +33 -0
- package/dist/nodes/schedule/schedulePlugin.js.map +1 -0
- package/dist/plugins/AutoLinkPlugin.d.ts +3 -0
- package/dist/plugins/AutoLinkPlugin.d.ts.map +1 -0
- package/dist/plugins/AutoLinkPlugin.js +22 -0
- package/dist/plugins/AutoLinkPlugin.js.map +1 -0
- package/dist/plugins/FloatingLinkEditorPlugin.d.ts +7 -0
- package/dist/plugins/FloatingLinkEditorPlugin.d.ts.map +1 -0
- package/dist/plugins/FloatingLinkEditorPlugin2.js +302 -0
- package/dist/plugins/FloatingLinkEditorPlugin2.js.map +1 -0
- package/dist/plugins/HistoryPlugin.d.ts +26 -0
- package/dist/plugins/HistoryPlugin.d.ts.map +1 -0
- package/dist/plugins/LinkPlugin.d.ts +3 -0
- package/dist/plugins/LinkPlugin.d.ts.map +1 -0
- package/dist/plugins/LinkPlugin.js +18 -0
- package/dist/plugins/LinkPlugin.js.map +1 -0
- package/dist/plugins/ToolbarPlugin.d.ts +7 -0
- package/dist/plugins/ToolbarPlugin.d.ts.map +1 -0
- package/dist/plugins/ToolbarPlugin.js +372 -0
- package/dist/plugins/ToolbarPlugin.js.map +1 -0
- package/dist/schedule.js +4 -0
- package/dist/scribo.css +1977 -0
- package/dist/themes/EditorTheme.d.ts +4 -0
- package/dist/themes/EditorTheme.d.ts.map +1 -0
- package/dist/themes/EditorTheme2.js +107 -0
- package/dist/themes/EditorTheme2.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/ui/ContentEditable.d.ts +6 -0
- package/dist/ui/ContentEditable.d.ts.map +1 -0
- package/dist/ui/ContentEditable2.js +14 -0
- package/dist/ui/ContentEditable2.js.map +1 -0
- package/dist/ui/DropDown.d.ts +18 -0
- package/dist/ui/DropDown.d.ts.map +1 -0
- package/dist/ui/DropDown.js +162 -0
- package/dist/ui/DropDown.js.map +1 -0
- package/dist/ui/Placeholder.d.ts +6 -0
- package/dist/ui/Placeholder.d.ts.map +1 -0
- package/dist/ui/Placeholder2.js +13 -0
- package/dist/ui/Placeholder2.js.map +1 -0
- package/dist/utils/environment.d.ts +24 -0
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/utils/environment.js +20 -0
- package/dist/utils/environment.js.map +1 -0
- package/dist/utils/getSelectedNode.d.ts +3 -0
- package/dist/utils/getSelectedNode.d.ts.map +1 -0
- package/dist/utils/getSelectedNode.js +23 -0
- package/dist/utils/getSelectedNode.js.map +1 -0
- package/dist/utils/setFloatingElemPosition.d.ts +2 -0
- package/dist/utils/setFloatingElemPosition.d.ts.map +1 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts +2 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts.map +1 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.js +33 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.js.map +1 -0
- package/dist/utils/url.d.ts +11 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +33 -0
- package/dist/utils/url.js.map +1 -0
- package/dist/vite.svg +1 -0
- package/package.json +57 -39
- package/src/MarkdownEditor.css +130 -27
- package/src/MarkdownEditor.tsx +82 -31
- package/src/MarkdownInput.tsx +9 -10
- package/src/context/SharedHistoryContext.tsx +8 -16
- package/src/main.tsx +3 -3
- package/src/nodes/EditorNodes.ts +10 -10
- package/src/nodes/callout/Callout.css +94 -0
- package/src/nodes/callout/CalloutComponent.tsx +61 -0
- package/src/nodes/callout/CalloutNode.ts +197 -0
- package/src/nodes/callout/CalloutTransformer.ts +87 -0
- package/src/nodes/callout/calloutPlugin.ts +37 -0
- package/src/nodes/callout/index.ts +5 -0
- package/src/nodes/schedule/ScheduleItem.css +140 -0
- package/src/nodes/schedule/ScheduleItemComponent.tsx +195 -0
- package/src/nodes/schedule/ScheduleItemNode.ts +135 -0
- package/src/nodes/schedule/ScheduleTransformer.ts +80 -0
- package/src/nodes/schedule/index.ts +4 -0
- package/src/nodes/schedule/schedulePlugin.ts +33 -0
- package/src/plugins/AutoLinkPlugin.tsx +5 -10
- package/src/plugins/FloatingLinkEditorPlugin.tsx +42 -66
- package/src/plugins/HistoryPlugin.tsx +20 -30
- package/src/plugins/LinkPlugin.tsx +2 -3
- package/src/plugins/ToolbarPlugin.tsx +129 -141
- package/src/themes/EditorTheme.css +82 -62
- package/src/themes/EditorTheme.ts +89 -90
- package/src/types.ts +27 -0
- package/src/ui/ContentEditable.tsx +5 -5
- package/src/ui/DropDown.tsx +23 -41
- package/src/ui/Placeholder.tsx +21 -21
- package/src/utils/environment.ts +6 -12
- package/src/utils/getSelectedNode.ts +3 -5
- package/src/utils/setFloatingElemPosition.ts +2 -5
- package/src/utils/setFloatingElemPositionForLinkEditor.ts +1 -1
- package/src/utils/url.ts +4 -10
- package/tsconfig.json +8 -0
- package/CHANGELOG.md +0 -59
- package/README.md +0 -126
- package/RELEASE.md +0 -102
- package/eslint.config.js +0 -4
- package/src/App.css +0 -35
- package/src/App.tsx +0 -42
- package/src/index.tsx +0 -13
- package/tsconfig.node.json +0 -11
- package/vite.config.site.ts +0 -19
- package/vite.config.ts +0 -33
- /package/{src → dist}/vite-env.d.ts +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { $applyNodeReplacement, $createParagraphNode, ElementNode } from "lexical";
|
|
2
|
+
//#region src/nodes/callout/CalloutNode.ts
|
|
3
|
+
var CALLOUT_TYPES = [
|
|
4
|
+
"NOTE",
|
|
5
|
+
"TIP",
|
|
6
|
+
"IMPORTANT",
|
|
7
|
+
"WARNING",
|
|
8
|
+
"CAUTION"
|
|
9
|
+
];
|
|
10
|
+
var CALLOUT_ICONS = {
|
|
11
|
+
NOTE: "ℹ️",
|
|
12
|
+
TIP: "💡",
|
|
13
|
+
IMPORTANT: "❗",
|
|
14
|
+
WARNING: "⚠️",
|
|
15
|
+
CAUTION: "🔴"
|
|
16
|
+
};
|
|
17
|
+
var CalloutNode = class CalloutNode extends ElementNode {
|
|
18
|
+
__calloutType;
|
|
19
|
+
static getType() {
|
|
20
|
+
return "callout";
|
|
21
|
+
}
|
|
22
|
+
static clone(node) {
|
|
23
|
+
return new CalloutNode(node.__calloutType, node.__key);
|
|
24
|
+
}
|
|
25
|
+
constructor(calloutType = "NOTE", key) {
|
|
26
|
+
super(key);
|
|
27
|
+
this.__calloutType = calloutType;
|
|
28
|
+
}
|
|
29
|
+
getCalloutType() {
|
|
30
|
+
return this.getLatest().__calloutType;
|
|
31
|
+
}
|
|
32
|
+
setCalloutType(calloutType) {
|
|
33
|
+
const self = this.getWritable();
|
|
34
|
+
self.__calloutType = calloutType;
|
|
35
|
+
}
|
|
36
|
+
createDOM() {
|
|
37
|
+
const wrapper = document.createElement("div");
|
|
38
|
+
wrapper.dataset.calloutKey = this.__key;
|
|
39
|
+
this._applyDOMClass(wrapper);
|
|
40
|
+
const toolbar = document.createElement("div");
|
|
41
|
+
toolbar.className = "callout-toolbar";
|
|
42
|
+
toolbar.contentEditable = "false";
|
|
43
|
+
const icon = document.createElement("span");
|
|
44
|
+
icon.className = "callout-toolbar-icon";
|
|
45
|
+
icon.textContent = CALLOUT_ICONS[this.__calloutType];
|
|
46
|
+
toolbar.appendChild(icon);
|
|
47
|
+
const select = document.createElement("select");
|
|
48
|
+
select.className = "callout-toolbar-type";
|
|
49
|
+
select.setAttribute("aria-label", "Callout type");
|
|
50
|
+
for (const type of CALLOUT_TYPES) {
|
|
51
|
+
const option = document.createElement("option");
|
|
52
|
+
option.value = type;
|
|
53
|
+
option.textContent = type.charAt(0) + type.slice(1).toLowerCase();
|
|
54
|
+
if (type === this.__calloutType) option.selected = true;
|
|
55
|
+
select.appendChild(option);
|
|
56
|
+
}
|
|
57
|
+
select.addEventListener("change", () => {
|
|
58
|
+
wrapper.dispatchEvent(new CustomEvent("callout-type-change", {
|
|
59
|
+
bubbles: true,
|
|
60
|
+
detail: {
|
|
61
|
+
nodeKey: wrapper.dataset.calloutKey,
|
|
62
|
+
calloutType: select.value
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
toolbar.appendChild(select);
|
|
67
|
+
const removeBtn = document.createElement("button");
|
|
68
|
+
removeBtn.type = "button";
|
|
69
|
+
removeBtn.className = "callout-toolbar-remove";
|
|
70
|
+
removeBtn.textContent = "×";
|
|
71
|
+
removeBtn.title = "Remove callout";
|
|
72
|
+
removeBtn.setAttribute("aria-label", "Remove callout");
|
|
73
|
+
removeBtn.addEventListener("click", () => {
|
|
74
|
+
wrapper.dispatchEvent(new CustomEvent("callout-remove", {
|
|
75
|
+
bubbles: true,
|
|
76
|
+
detail: { nodeKey: wrapper.dataset.calloutKey }
|
|
77
|
+
}));
|
|
78
|
+
});
|
|
79
|
+
toolbar.appendChild(removeBtn);
|
|
80
|
+
wrapper.appendChild(toolbar);
|
|
81
|
+
return wrapper;
|
|
82
|
+
}
|
|
83
|
+
_applyDOMClass(dom) {
|
|
84
|
+
dom.className = `callout-editor callout-editor--${this.__calloutType.toLowerCase()}`;
|
|
85
|
+
}
|
|
86
|
+
updateDOM(prevNode, dom) {
|
|
87
|
+
if (prevNode.__calloutType !== this.__calloutType) {
|
|
88
|
+
this._applyDOMClass(dom);
|
|
89
|
+
const icon = dom.querySelector(".callout-toolbar-icon");
|
|
90
|
+
if (icon) icon.textContent = CALLOUT_ICONS[this.__calloutType];
|
|
91
|
+
const select = dom.querySelector(".callout-toolbar-type");
|
|
92
|
+
if (select) select.value = this.__calloutType;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
exportDOM() {
|
|
97
|
+
const el = document.createElement("blockquote");
|
|
98
|
+
el.dataset.calloutType = this.__calloutType;
|
|
99
|
+
el.className = `callout callout--${this.__calloutType.toLowerCase()}`;
|
|
100
|
+
return { element: el };
|
|
101
|
+
}
|
|
102
|
+
static importDOM() {
|
|
103
|
+
return { blockquote: (node) => {
|
|
104
|
+
const type = node.dataset.calloutType;
|
|
105
|
+
if (!type || !CALLOUT_TYPES.includes(type)) return null;
|
|
106
|
+
return {
|
|
107
|
+
conversion: () => ({ node: $createCalloutNode(type) }),
|
|
108
|
+
priority: 1
|
|
109
|
+
};
|
|
110
|
+
} };
|
|
111
|
+
}
|
|
112
|
+
static importJSON(json) {
|
|
113
|
+
return $createCalloutNode(json.calloutType);
|
|
114
|
+
}
|
|
115
|
+
exportJSON() {
|
|
116
|
+
return {
|
|
117
|
+
...super.exportJSON(),
|
|
118
|
+
type: "callout",
|
|
119
|
+
calloutType: this.__calloutType
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
canIndent() {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
collapseAtStart() {
|
|
126
|
+
const children = this.getChildren();
|
|
127
|
+
if (this.getParent()) for (const child of children) this.insertBefore(child);
|
|
128
|
+
this.remove();
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
insertNewAfter() {
|
|
132
|
+
const lastChild = this.getLastChild();
|
|
133
|
+
if (lastChild?.getTextContent() === "") {
|
|
134
|
+
const p = $createParagraphNode();
|
|
135
|
+
this.insertAfter(p);
|
|
136
|
+
lastChild.remove();
|
|
137
|
+
return p;
|
|
138
|
+
}
|
|
139
|
+
const p = $createParagraphNode();
|
|
140
|
+
this.append(p);
|
|
141
|
+
return p;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
function $createCalloutNode(calloutType = "NOTE") {
|
|
145
|
+
return $applyNodeReplacement(new CalloutNode(calloutType));
|
|
146
|
+
}
|
|
147
|
+
function $isCalloutNode(node) {
|
|
148
|
+
return node instanceof CalloutNode;
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
export { $createCalloutNode, $isCalloutNode, CALLOUT_TYPES, CalloutNode };
|
|
152
|
+
|
|
153
|
+
//# sourceMappingURL=CalloutNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalloutNode.js","names":[],"sources":["../../../src/nodes/callout/CalloutNode.ts"],"sourcesContent":["import {\n $applyNodeReplacement,\n $createParagraphNode,\n type DOMConversionMap,\n type DOMExportOutput,\n ElementNode,\n type LexicalNode,\n type NodeKey,\n type SerializedElementNode,\n type Spread,\n} from 'lexical';\n\nexport const CALLOUT_TYPES = ['NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION'] as const;\nexport type CalloutType = (typeof CALLOUT_TYPES)[number];\n\nconst CALLOUT_ICONS: Record<CalloutType, string> = {\n NOTE: 'ℹ️',\n TIP: '💡',\n IMPORTANT: '❗',\n WARNING: '⚠️',\n CAUTION: '🔴',\n};\n\nexport type SerializedCalloutNode = Spread<{ calloutType: CalloutType }, SerializedElementNode>;\n\nexport class CalloutNode extends ElementNode {\n __calloutType: CalloutType;\n\n static getType(): string {\n return 'callout';\n }\n\n static clone(node: CalloutNode): CalloutNode {\n return new CalloutNode(node.__calloutType, node.__key);\n }\n\n constructor(calloutType: CalloutType = 'NOTE', key?: NodeKey) {\n super(key);\n this.__calloutType = calloutType;\n }\n\n getCalloutType(): CalloutType {\n return this.getLatest().__calloutType;\n }\n\n setCalloutType(calloutType: CalloutType): void {\n const self = this.getWritable();\n self.__calloutType = calloutType;\n }\n\n // --- DOM ---\n\n createDOM(): HTMLElement {\n const wrapper = document.createElement('div');\n wrapper.dataset.calloutKey = this.__key;\n this._applyDOMClass(wrapper);\n\n // Non-editable toolbar\n const toolbar = document.createElement('div');\n toolbar.className = 'callout-toolbar';\n toolbar.contentEditable = 'false';\n\n const icon = document.createElement('span');\n icon.className = 'callout-toolbar-icon';\n icon.textContent = CALLOUT_ICONS[this.__calloutType];\n toolbar.appendChild(icon);\n\n const select = document.createElement('select');\n select.className = 'callout-toolbar-type';\n select.setAttribute('aria-label', 'Callout type');\n for (const type of CALLOUT_TYPES) {\n const option = document.createElement('option');\n option.value = type;\n option.textContent = type.charAt(0) + type.slice(1).toLowerCase();\n if (type === this.__calloutType) option.selected = true;\n select.appendChild(option);\n }\n select.addEventListener('change', () => {\n wrapper.dispatchEvent(\n new CustomEvent('callout-type-change', {\n bubbles: true,\n detail: { nodeKey: wrapper.dataset.calloutKey, calloutType: select.value },\n })\n );\n });\n toolbar.appendChild(select);\n\n const removeBtn = document.createElement('button');\n removeBtn.type = 'button';\n removeBtn.className = 'callout-toolbar-remove';\n removeBtn.textContent = '×';\n removeBtn.title = 'Remove callout';\n removeBtn.setAttribute('aria-label', 'Remove callout');\n removeBtn.addEventListener('click', () => {\n wrapper.dispatchEvent(\n new CustomEvent('callout-remove', {\n bubbles: true,\n detail: { nodeKey: wrapper.dataset.calloutKey },\n })\n );\n });\n toolbar.appendChild(removeBtn);\n\n wrapper.appendChild(toolbar);\n return wrapper;\n }\n\n private _applyDOMClass(dom: HTMLElement): void {\n dom.className = `callout-editor callout-editor--${this.__calloutType.toLowerCase()}`;\n }\n\n updateDOM(prevNode: CalloutNode, dom: HTMLElement): boolean {\n if (prevNode.__calloutType !== this.__calloutType) {\n this._applyDOMClass(dom);\n const icon = dom.querySelector('.callout-toolbar-icon');\n if (icon) icon.textContent = CALLOUT_ICONS[this.__calloutType];\n const select = dom.querySelector('.callout-toolbar-type') as HTMLSelectElement | null;\n if (select) select.value = this.__calloutType;\n }\n return false;\n }\n\n exportDOM(): DOMExportOutput {\n const el = document.createElement('blockquote');\n el.dataset.calloutType = this.__calloutType;\n el.className = `callout callout--${this.__calloutType.toLowerCase()}`;\n return { element: el };\n }\n\n static importDOM(): DOMConversionMap | null {\n return {\n blockquote: (node: HTMLElement) => {\n const type = node.dataset.calloutType;\n if (!type || !CALLOUT_TYPES.includes(type as CalloutType)) return null;\n return {\n conversion: () => ({\n node: $createCalloutNode(type as CalloutType),\n }),\n priority: 1,\n };\n },\n };\n }\n\n // --- Serialization ---\n\n static importJSON(json: SerializedCalloutNode): CalloutNode {\n return $createCalloutNode(json.calloutType);\n }\n\n exportJSON(): SerializedCalloutNode {\n return {\n ...super.exportJSON(),\n type: 'callout',\n calloutType: this.__calloutType,\n };\n }\n\n // --- Behavior ---\n\n canIndent(): boolean {\n return false;\n }\n\n collapseAtStart(): boolean {\n const children = this.getChildren();\n const parent = this.getParent();\n if (parent) {\n for (const child of children) {\n this.insertBefore(child);\n }\n }\n this.remove();\n return true;\n }\n\n insertNewAfter(): ElementNode {\n const lastChild = this.getLastChild();\n if (lastChild?.getTextContent() === '') {\n const p = $createParagraphNode();\n this.insertAfter(p);\n lastChild.remove();\n return p;\n }\n const p = $createParagraphNode();\n this.append(p);\n return p;\n }\n}\n\nexport function $createCalloutNode(calloutType: CalloutType = 'NOTE'): CalloutNode {\n return $applyNodeReplacement(new CalloutNode(calloutType));\n}\n\nexport function $isCalloutNode(node: LexicalNode | null | undefined): node is CalloutNode {\n return node instanceof CalloutNode;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalloutTransformer.d.ts","sourceRoot":"","sources":["../../../src/nodes/callout/CalloutTransformer.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,2BAA2B,EAEjC,MAAM,mBAAmB,CAAC;AAyB3B,eAAO,MAAM,mBAAmB,EAAE,2BAyDjC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { $createCalloutNode, $isCalloutNode, CALLOUT_TYPES, CalloutNode } from "./CalloutNode.js";
|
|
2
|
+
import { $convertFromMarkdownString, TRANSFORMERS } from "@lexical/markdown";
|
|
3
|
+
import { $createParagraphNode } from "lexical";
|
|
4
|
+
//#region src/nodes/callout/CalloutTransformer.ts
|
|
5
|
+
/**
|
|
6
|
+
* GitHub-flavored callout syntax:
|
|
7
|
+
*
|
|
8
|
+
* ```markdown
|
|
9
|
+
* > [!NOTE]
|
|
10
|
+
* > Content line 1 with **bold** and [links](url)
|
|
11
|
+
* > Content line 2
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Supports: NOTE, TIP, IMPORTANT, WARNING, CAUTION
|
|
15
|
+
*/
|
|
16
|
+
var CALLOUT_START_REGEX = /^>\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*$/;
|
|
17
|
+
var BLOCKQUOTE_LINE_REGEX = /^>\s?(.*)$/;
|
|
18
|
+
var CALLOUT_TRANSFORMER = {
|
|
19
|
+
type: "multiline-element",
|
|
20
|
+
dependencies: [CalloutNode],
|
|
21
|
+
regExpStart: CALLOUT_START_REGEX,
|
|
22
|
+
regExpEnd: {
|
|
23
|
+
regExp: /^(?!>\s?)/,
|
|
24
|
+
optional: true
|
|
25
|
+
},
|
|
26
|
+
export: (node, exportChildren) => {
|
|
27
|
+
if (!$isCalloutNode(node)) return null;
|
|
28
|
+
return `> [!${node.getCalloutType()}]\n${exportChildren(node).split("\n").map((line) => `> ${line}`).join("\n")}`;
|
|
29
|
+
},
|
|
30
|
+
replace: (parentNode, _children, startMatch, _endMatch, linesInBetween, isImport) => {
|
|
31
|
+
const calloutType = startMatch[1];
|
|
32
|
+
if (!CALLOUT_TYPES.includes(calloutType)) return false;
|
|
33
|
+
const innerMarkdown = (linesInBetween ?? []).map((line) => {
|
|
34
|
+
const match = line.match(BLOCKQUOTE_LINE_REGEX);
|
|
35
|
+
return match ? match[1] ?? "" : null;
|
|
36
|
+
}).filter((line) => line !== null).join("\n").trim();
|
|
37
|
+
const calloutNode = $createCalloutNode(calloutType);
|
|
38
|
+
if (innerMarkdown) $convertFromMarkdownString(innerMarkdown, TRANSFORMERS, calloutNode);
|
|
39
|
+
if (calloutNode.getChildrenSize() === 0) calloutNode.append($createParagraphNode());
|
|
40
|
+
if (isImport) parentNode.append(calloutNode);
|
|
41
|
+
else parentNode.replace(calloutNode);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { CALLOUT_TRANSFORMER };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=CalloutTransformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalloutTransformer.js","names":[],"sources":["../../../src/nodes/callout/CalloutTransformer.ts"],"sourcesContent":["import {\n $convertFromMarkdownString,\n type MultilineElementTransformer,\n TRANSFORMERS,\n} from '@lexical/markdown';\nimport { $createParagraphNode } from 'lexical';\n\nimport {\n $createCalloutNode,\n $isCalloutNode,\n CALLOUT_TYPES,\n CalloutNode,\n type CalloutType,\n} from './CalloutNode';\n\n/**\n * GitHub-flavored callout syntax:\n *\n * ```markdown\n * > [!NOTE]\n * > Content line 1 with **bold** and [links](url)\n * > Content line 2\n * ```\n *\n * Supports: NOTE, TIP, IMPORTANT, WARNING, CAUTION\n */\nconst CALLOUT_START_REGEX = /^>\\s*\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\]\\s*$/;\nconst BLOCKQUOTE_LINE_REGEX = /^>\\s?(.*)$/;\n\nexport const CALLOUT_TRANSFORMER: MultilineElementTransformer = {\n type: 'multiline-element',\n dependencies: [CalloutNode],\n\n regExpStart: CALLOUT_START_REGEX,\n\n regExpEnd: {\n regExp: /^(?!>\\s?)/, // Ends when a line doesn't start with >\n optional: true,\n },\n\n export: (node, exportChildren) => {\n if (!$isCalloutNode(node)) return null;\n\n const calloutType = node.getCalloutType();\n const childContent = exportChildren(node);\n const lines = childContent.split('\\n');\n const quoted = lines.map((line) => `> ${line}`).join('\\n');\n return `> [!${calloutType}]\\n${quoted}`;\n },\n\n replace: (parentNode, _children, startMatch, _endMatch, linesInBetween, isImport) => {\n const calloutType = startMatch[1] as CalloutType;\n if (!CALLOUT_TYPES.includes(calloutType)) return false;\n\n // Strip blockquote prefixes to get plain markdown content\n const contentLines = (linesInBetween ?? [])\n .map((line) => {\n const match = line.match(BLOCKQUOTE_LINE_REGEX);\n return match ? (match[1] ?? '') : null;\n })\n .filter((line): line is string => line !== null);\n\n const innerMarkdown = contentLines.join('\\n').trim();\n\n const calloutNode = $createCalloutNode(calloutType);\n\n if (innerMarkdown) {\n // Parse inner markdown directly into calloutNode to avoid corrupting\n // the outer root state with a global root.clear()\n $convertFromMarkdownString(innerMarkdown, TRANSFORMERS, calloutNode);\n }\n\n // Ensure at least one empty paragraph for editing\n if (calloutNode.getChildrenSize() === 0) {\n calloutNode.append($createParagraphNode());\n }\n\n // On import, parentNode is the RootNode (which can't be replaced — Lexical #53).\n // On keyboard-shortcut, parentNode is a ParagraphNode we should replace.\n if (isImport) {\n parentNode.append(calloutNode);\n } else {\n parentNode.replace(calloutNode);\n }\n return true;\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,IAAM,sBAAsB;AAC5B,IAAM,wBAAwB;AAE9B,IAAa,sBAAmD;CAC9D,MAAM;CACN,cAAc,CAAC,WAAW;CAE1B,aAAa;CAEb,WAAW;EACT,QAAQ;EACR,UAAU;CACZ;CAEA,SAAS,MAAM,mBAAmB;EAChC,IAAI,CAAC,eAAe,IAAI,GAAG,OAAO;EAMlC,OAAO,OAJa,KAAK,eAIX,EAAY,KAHL,eAAe,IACtB,CAAA,CAAa,MAAM,IAClB,CAAA,CAAM,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC,KAAK,IACtB;CACjC;CAEA,UAAU,YAAY,WAAW,YAAY,WAAW,gBAAgB,aAAa;EACnF,MAAM,cAAc,WAAW;EAC/B,IAAI,CAAC,cAAc,SAAS,WAAW,GAAG,OAAO;EAUjD,MAAM,iBAPgB,kBAAkB,CAAC,EAAA,CACtC,KAAK,SAAS;GACb,MAAM,QAAQ,KAAK,MAAM,qBAAqB;GAC9C,OAAO,QAAS,MAAM,MAAM,KAAM;EACpC,CAAC,CAAC,CACD,QAAQ,SAAyB,SAAS,IAEvB,CAAA,CAAa,KAAK,IAAI,CAAC,CAAC,KAAK;EAEnD,MAAM,cAAc,mBAAmB,WAAW;EAElD,IAAI,eAGF,2BAA2B,eAAe,cAAc,WAAW;EAIrE,IAAI,YAAY,gBAAgB,MAAM,GACpC,YAAY,OAAO,qBAAqB,CAAC;EAK3C,IAAI,UACF,WAAW,OAAO,WAAW;OAE7B,WAAW,QAAQ,WAAW;EAEhC,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calloutPlugin.d.ts","sourceRoot":"","sources":["../../../src/nodes/callout/calloutPlugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,eAAO,MAAM,aAAa,EAAE,YA4B3B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { $createCalloutNode, CalloutNode } from "./CalloutNode.js";
|
|
2
|
+
import { CalloutPlugin } from "./CalloutComponent.js";
|
|
3
|
+
import { CALLOUT_TRANSFORMER } from "./CalloutTransformer.js";
|
|
4
|
+
import { $createParagraphNode, $getSelection, $isRangeSelection } from "lexical";
|
|
5
|
+
import { $findMatchingParent } from "@lexical/utils";
|
|
6
|
+
//#region src/nodes/callout/calloutPlugin.ts
|
|
7
|
+
var calloutPlugin = {
|
|
8
|
+
name: "callout",
|
|
9
|
+
nodes: [CalloutNode],
|
|
10
|
+
transformers: [CALLOUT_TRANSFORMER],
|
|
11
|
+
editorPlugins: [CalloutPlugin],
|
|
12
|
+
toolbarButtons: [{
|
|
13
|
+
key: "callout",
|
|
14
|
+
label: "Callout",
|
|
15
|
+
iconClass: "alert",
|
|
16
|
+
onSelect: (editor) => {
|
|
17
|
+
editor.update(() => {
|
|
18
|
+
const selection = $getSelection();
|
|
19
|
+
if (!$isRangeSelection(selection)) return;
|
|
20
|
+
const anchor = selection.anchor.getNode();
|
|
21
|
+
const topLevel = $findMatchingParent(anchor, (n) => n.getParent()?.getType() === "root") ?? anchor;
|
|
22
|
+
const calloutNode = $createCalloutNode("NOTE");
|
|
23
|
+
const p = $createParagraphNode();
|
|
24
|
+
calloutNode.append(p);
|
|
25
|
+
topLevel.insertAfter(calloutNode);
|
|
26
|
+
p.selectEnd();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}]
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { calloutPlugin };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=calloutPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calloutPlugin.js","names":[],"sources":["../../../src/nodes/callout/calloutPlugin.ts"],"sourcesContent":["import { $findMatchingParent } from '@lexical/utils';\nimport { $createParagraphNode, $getSelection, $isRangeSelection } from 'lexical';\n\nimport type { ScriboPlugin } from '../../types';\nimport { CalloutPlugin } from './CalloutComponent';\nimport { $createCalloutNode, CalloutNode } from './CalloutNode';\nimport { CALLOUT_TRANSFORMER } from './CalloutTransformer';\n\nexport const calloutPlugin: ScriboPlugin = {\n name: 'callout',\n nodes: [CalloutNode],\n transformers: [CALLOUT_TRANSFORMER],\n editorPlugins: [CalloutPlugin],\n toolbarButtons: [\n {\n key: 'callout',\n label: 'Callout',\n iconClass: 'alert',\n onSelect: (editor) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n const anchor = selection.anchor.getNode();\n const topLevel =\n $findMatchingParent(anchor, (n) => n.getParent()?.getType() === 'root') ?? anchor;\n\n const calloutNode = $createCalloutNode('NOTE');\n const p = $createParagraphNode();\n calloutNode.append(p);\n topLevel.insertAfter(calloutNode);\n p.selectEnd();\n });\n },\n },\n ],\n};\n"],"mappings":";;;;;;AAQA,IAAa,gBAA8B;CACzC,MAAM;CACN,OAAO,CAAC,WAAW;CACnB,cAAc,CAAC,mBAAmB;CAClC,eAAe,CAAC,aAAa;CAC7B,gBAAgB,CACd;EACE,KAAK;EACL,OAAO;EACP,WAAW;EACX,WAAW,WAAW;GACpB,OAAO,aAAa;IAClB,MAAM,YAAY,cAAc;IAChC,IAAI,CAAC,kBAAkB,SAAS,GAAG;IAEnC,MAAM,SAAS,UAAU,OAAO,QAAQ;IACxC,MAAM,WACJ,oBAAoB,SAAS,MAAM,EAAE,UAAU,CAAC,EAAE,QAAQ,MAAM,MAAM,KAAK;IAE7E,MAAM,cAAc,mBAAmB,MAAM;IAC7C,MAAM,IAAI,qBAAqB;IAC/B,YAAY,OAAO,CAAC;IACpB,SAAS,YAAY,WAAW;IAChC,EAAE,UAAU;GACd,CAAC;EACH;CACF,CACF;AACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CalloutPlugin } from './CalloutComponent';
|
|
2
|
+
export type { CalloutType, SerializedCalloutNode } from './CalloutNode';
|
|
3
|
+
export { $createCalloutNode, $isCalloutNode, CALLOUT_TYPES, CalloutNode } from './CalloutNode';
|
|
4
|
+
export { CALLOUT_TRANSFORMER } from './CalloutTransformer';
|
|
5
|
+
export { calloutPlugin } from './calloutPlugin';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/nodes/callout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NodeKey } from 'lexical';
|
|
2
|
+
import { ScheduleItemData } from './ScheduleItemNode';
|
|
3
|
+
interface ScheduleItemComponentProps {
|
|
4
|
+
nodeKey: NodeKey;
|
|
5
|
+
data: ScheduleItemData;
|
|
6
|
+
}
|
|
7
|
+
export declare const ScheduleItemComponent: ({ nodeKey, data }: ScheduleItemComponentProps) => import("react").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=ScheduleItemComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleItemComponent.d.ts","sourceRoot":"","sources":["../../../src/nodes/schedule/ScheduleItemComponent.tsx"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,CAAC;AAG5B,OAAO,EAAuC,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAG5E,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAE5B,UAAU,0BAA0B;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED,eAAO,MAAM,qBAAqB,GAAI,mBAAmB,0BAA0B,gCAiLlF,CAAC"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { $createScheduleItemNode, $isScheduleItemNode } from "./ScheduleItemNode.js";
|
|
3
|
+
import { $createParagraphNode, $getNodeByKey } from "lexical";
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
7
|
+
import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
|
|
8
|
+
//#region src/nodes/schedule/ScheduleItemComponent.tsx
|
|
9
|
+
var ScheduleItemComponent = ({ nodeKey, data }) => {
|
|
10
|
+
const [editor] = useLexicalComposerContext();
|
|
11
|
+
const [isSelected, _setSelected, _clearSelection] = useLexicalNodeSelection(nodeKey);
|
|
12
|
+
const [localData, setLocalData] = useState(data);
|
|
13
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
14
|
+
const [isLast, setIsLast] = useState(false);
|
|
15
|
+
const timeRef = useRef(null);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setLocalData(data);
|
|
18
|
+
}, [data]);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
return editor.registerUpdateListener(() => {
|
|
21
|
+
editor.getEditorState().read(() => {
|
|
22
|
+
const node = $getNodeByKey(nodeKey);
|
|
23
|
+
if (!node) return;
|
|
24
|
+
const next = node.getNextSibling();
|
|
25
|
+
setIsLast(!next || !$isScheduleItemNode(next));
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}, [editor, nodeKey]);
|
|
29
|
+
const updateNode = useCallback((updated) => {
|
|
30
|
+
editor.update(() => {
|
|
31
|
+
const node = $getNodeByKey(nodeKey);
|
|
32
|
+
if ($isScheduleItemNode(node)) node.setData(updated);
|
|
33
|
+
});
|
|
34
|
+
}, [editor, nodeKey]);
|
|
35
|
+
const handleChange = (field, value) => {
|
|
36
|
+
const nextRaw = {
|
|
37
|
+
...localData,
|
|
38
|
+
time: field === "time" ? value : localData.time,
|
|
39
|
+
title: field === "title" ? value : localData.title,
|
|
40
|
+
speaker: field === "speaker" ? value || void 0 : localData.speaker,
|
|
41
|
+
description: field === "description" ? value || void 0 : localData.description
|
|
42
|
+
};
|
|
43
|
+
const persisted = {
|
|
44
|
+
...nextRaw,
|
|
45
|
+
time: nextRaw.time.trim()
|
|
46
|
+
};
|
|
47
|
+
setLocalData(nextRaw);
|
|
48
|
+
updateNode(persisted);
|
|
49
|
+
};
|
|
50
|
+
const insertAfter = () => {
|
|
51
|
+
editor.update(() => {
|
|
52
|
+
const node = $getNodeByKey(nodeKey);
|
|
53
|
+
if (!node) return;
|
|
54
|
+
const newNode = $createScheduleItemNode({
|
|
55
|
+
time: "",
|
|
56
|
+
title: ""
|
|
57
|
+
});
|
|
58
|
+
node.insertAfter(newNode);
|
|
59
|
+
newNode.selectEnd();
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const removeNode = () => {
|
|
63
|
+
editor.update(() => {
|
|
64
|
+
const node = $getNodeByKey(nodeKey);
|
|
65
|
+
if (!node) return;
|
|
66
|
+
const next = node.getNextSibling();
|
|
67
|
+
const prev = node.getPreviousSibling();
|
|
68
|
+
if (!next && !prev) {
|
|
69
|
+
const p = $createParagraphNode();
|
|
70
|
+
node.replace(p);
|
|
71
|
+
p.selectEnd();
|
|
72
|
+
} else node.remove();
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const handleDragStart = (e) => {
|
|
76
|
+
e.dataTransfer.setData("text/plain", nodeKey);
|
|
77
|
+
e.dataTransfer.effectAllowed = "move";
|
|
78
|
+
setIsDragging(true);
|
|
79
|
+
};
|
|
80
|
+
const handleDragEnd = () => setIsDragging(false);
|
|
81
|
+
const handleDragOver = (e) => {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
e.dataTransfer.dropEffect = "move";
|
|
84
|
+
};
|
|
85
|
+
const handleDrop = (e) => {
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
const sourceKey = e.dataTransfer.getData("text/plain");
|
|
88
|
+
if (!sourceKey || sourceKey === nodeKey) return;
|
|
89
|
+
editor.update(() => {
|
|
90
|
+
const sourceNode = $getNodeByKey(sourceKey);
|
|
91
|
+
const targetNode = $getNodeByKey(nodeKey);
|
|
92
|
+
if (!sourceNode || !targetNode || !$isScheduleItemNode(sourceNode)) return;
|
|
93
|
+
targetNode.insertBefore(sourceNode);
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
97
|
+
className: "schedule-item-wrapper",
|
|
98
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
99
|
+
role: "group",
|
|
100
|
+
"aria-label": "Schedule item",
|
|
101
|
+
className: `schedule-item-editor ${isSelected ? "schedule-item-editor--selected" : ""} ${isDragging ? "schedule-item-editor--dragging" : ""}`,
|
|
102
|
+
onDragOver: handleDragOver,
|
|
103
|
+
onDrop: handleDrop,
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ jsx("button", {
|
|
106
|
+
type: "button",
|
|
107
|
+
className: "schedule-item-drag",
|
|
108
|
+
draggable: true,
|
|
109
|
+
onDragStart: handleDragStart,
|
|
110
|
+
onDragEnd: handleDragEnd,
|
|
111
|
+
title: "Drag to reorder",
|
|
112
|
+
"aria-label": "Drag to reorder",
|
|
113
|
+
children: "⠿"
|
|
114
|
+
}),
|
|
115
|
+
/* @__PURE__ */ jsx("input", {
|
|
116
|
+
ref: timeRef,
|
|
117
|
+
className: "schedule-item-time",
|
|
118
|
+
type: "text",
|
|
119
|
+
value: localData.time,
|
|
120
|
+
onChange: (e) => handleChange("time", e.target.value),
|
|
121
|
+
placeholder: "09:00–10:00",
|
|
122
|
+
size: 13
|
|
123
|
+
}),
|
|
124
|
+
/* @__PURE__ */ jsx("input", {
|
|
125
|
+
className: "schedule-item-title",
|
|
126
|
+
type: "text",
|
|
127
|
+
value: localData.title,
|
|
128
|
+
onChange: (e) => handleChange("title", e.target.value),
|
|
129
|
+
placeholder: "Title"
|
|
130
|
+
}),
|
|
131
|
+
/* @__PURE__ */ jsx("input", {
|
|
132
|
+
className: "schedule-item-speaker",
|
|
133
|
+
type: "text",
|
|
134
|
+
value: localData.speaker ?? "",
|
|
135
|
+
onChange: (e) => handleChange("speaker", e.target.value),
|
|
136
|
+
placeholder: "Speaker"
|
|
137
|
+
}),
|
|
138
|
+
/* @__PURE__ */ jsx("input", {
|
|
139
|
+
className: "schedule-item-description",
|
|
140
|
+
type: "text",
|
|
141
|
+
value: localData.description ?? "",
|
|
142
|
+
onChange: (e) => handleChange("description", e.target.value),
|
|
143
|
+
placeholder: "Description"
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ jsx("button", {
|
|
146
|
+
type: "button",
|
|
147
|
+
className: "schedule-item-remove",
|
|
148
|
+
onClick: removeNode,
|
|
149
|
+
title: "Remove item",
|
|
150
|
+
"aria-label": "Remove schedule item",
|
|
151
|
+
children: "×"
|
|
152
|
+
})
|
|
153
|
+
]
|
|
154
|
+
}), isLast && /* @__PURE__ */ jsx("button", {
|
|
155
|
+
type: "button",
|
|
156
|
+
className: "schedule-item-add",
|
|
157
|
+
onClick: insertAfter,
|
|
158
|
+
title: "Add item",
|
|
159
|
+
"aria-label": "Add schedule item",
|
|
160
|
+
children: "+"
|
|
161
|
+
})]
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
//#endregion
|
|
165
|
+
export { ScheduleItemComponent };
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=ScheduleItemComponent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleItemComponent.js","names":[],"sources":["../../../src/nodes/schedule/ScheduleItemComponent.tsx"],"sourcesContent":["import './ScheduleItem.css';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';\nimport { $createParagraphNode, $getNodeByKey, type NodeKey } from 'lexical';\nimport { type DragEvent, useCallback, useEffect, useRef, useState } from 'react';\n\nimport {\n $createScheduleItemNode,\n $isScheduleItemNode,\n type ScheduleItemData,\n} from './ScheduleItemNode';\n\ninterface ScheduleItemComponentProps {\n nodeKey: NodeKey;\n data: ScheduleItemData;\n}\n\nexport const ScheduleItemComponent = ({ nodeKey, data }: ScheduleItemComponentProps) => {\n const [editor] = useLexicalComposerContext();\n const [isSelected, _setSelected, _clearSelection] = useLexicalNodeSelection(nodeKey);\n const [localData, setLocalData] = useState(data);\n const [isDragging, setIsDragging] = useState(false);\n const [isLast, setIsLast] = useState(false);\n const timeRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n setLocalData(data);\n }, [data]);\n\n // Check if this is the last schedule item (show + button only on last)\n useEffect(() => {\n return editor.registerUpdateListener(() => {\n editor.getEditorState().read(() => {\n const node = $getNodeByKey(nodeKey);\n if (!node) return;\n const next = node.getNextSibling();\n setIsLast(!next || !$isScheduleItemNode(next));\n });\n });\n }, [editor, nodeKey]);\n\n const updateNode = useCallback(\n (updated: ScheduleItemData) => {\n editor.update(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isScheduleItemNode(node)) {\n node.setData(updated);\n }\n });\n },\n [editor, nodeKey]\n );\n\n const handleChange = (field: keyof ScheduleItemData, value: string) => {\n const nextRaw: ScheduleItemData = {\n ...localData,\n time: field === 'time' ? value : localData.time,\n title: field === 'title' ? value : localData.title,\n speaker: field === 'speaker' ? value || undefined : localData.speaker,\n description: field === 'description' ? value || undefined : localData.description,\n };\n const persisted: ScheduleItemData = {\n ...nextRaw,\n time: nextRaw.time.trim(),\n };\n\n setLocalData(nextRaw);\n updateNode(persisted);\n };\n\n const insertAfter = () => {\n editor.update(() => {\n const node = $getNodeByKey(nodeKey);\n if (!node) return;\n const newNode = $createScheduleItemNode({ time: '', title: '' });\n node.insertAfter(newNode);\n newNode.selectEnd();\n });\n };\n\n const removeNode = () => {\n editor.update(() => {\n const node = $getNodeByKey(nodeKey);\n if (!node) return;\n const next = node.getNextSibling();\n const prev = node.getPreviousSibling();\n if (!next && !prev) {\n const p = $createParagraphNode();\n node.replace(p);\n p.selectEnd();\n } else {\n node.remove();\n }\n });\n };\n\n const handleDragStart = (e: DragEvent) => {\n e.dataTransfer.setData('text/plain', nodeKey);\n e.dataTransfer.effectAllowed = 'move';\n setIsDragging(true);\n };\n\n const handleDragEnd = () => setIsDragging(false);\n\n const handleDragOver = (e: DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n };\n\n const handleDrop = (e: DragEvent) => {\n e.preventDefault();\n const sourceKey = e.dataTransfer.getData('text/plain');\n if (!sourceKey || sourceKey === nodeKey) return;\n editor.update(() => {\n const sourceNode = $getNodeByKey(sourceKey);\n const targetNode = $getNodeByKey(nodeKey);\n if (!sourceNode || !targetNode || !$isScheduleItemNode(sourceNode)) return;\n targetNode.insertBefore(sourceNode);\n });\n };\n\n return (\n <div className=\"schedule-item-wrapper\">\n <div\n role=\"group\"\n aria-label=\"Schedule item\"\n className={`schedule-item-editor ${isSelected ? 'schedule-item-editor--selected' : ''} ${isDragging ? 'schedule-item-editor--dragging' : ''}`}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n >\n <button\n type=\"button\"\n className=\"schedule-item-drag\"\n draggable\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n title=\"Drag to reorder\"\n aria-label=\"Drag to reorder\"\n >\n ⠿\n </button>\n <input\n ref={timeRef}\n className=\"schedule-item-time\"\n type=\"text\"\n value={localData.time}\n onChange={(e) => handleChange('time', e.target.value)}\n placeholder=\"09:00–10:00\"\n size={13}\n />\n <input\n className=\"schedule-item-title\"\n type=\"text\"\n value={localData.title}\n onChange={(e) => handleChange('title', e.target.value)}\n placeholder=\"Title\"\n />\n <input\n className=\"schedule-item-speaker\"\n type=\"text\"\n value={localData.speaker ?? ''}\n onChange={(e) => handleChange('speaker', e.target.value)}\n placeholder=\"Speaker\"\n />\n <input\n className=\"schedule-item-description\"\n type=\"text\"\n value={localData.description ?? ''}\n onChange={(e) => handleChange('description', e.target.value)}\n placeholder=\"Description\"\n />\n <button\n type=\"button\"\n className=\"schedule-item-remove\"\n onClick={removeNode}\n title=\"Remove item\"\n aria-label=\"Remove schedule item\"\n >\n ×\n </button>\n </div>\n {isLast && (\n <button\n type=\"button\"\n className=\"schedule-item-add\"\n onClick={insertAfter}\n title=\"Add item\"\n aria-label=\"Add schedule item\"\n >\n +\n </button>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DecoratorNode, DOMConversionMap, DOMExportOutput, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from 'lexical';
|
|
2
|
+
import { ReactElement } from 'react';
|
|
3
|
+
export interface ScheduleItemData {
|
|
4
|
+
time: string;
|
|
5
|
+
title: string;
|
|
6
|
+
speaker?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
export type SerializedScheduleItemNode = Spread<{
|
|
10
|
+
data: ScheduleItemData;
|
|
11
|
+
}, SerializedLexicalNode>;
|
|
12
|
+
export declare class ScheduleItemNode extends DecoratorNode<ReactElement> {
|
|
13
|
+
__data: ScheduleItemData;
|
|
14
|
+
static getType(): string;
|
|
15
|
+
static clone(node: ScheduleItemNode): ScheduleItemNode;
|
|
16
|
+
constructor(data: ScheduleItemData, key?: NodeKey);
|
|
17
|
+
getData(): ScheduleItemData;
|
|
18
|
+
setData(data: ScheduleItemData): void;
|
|
19
|
+
createDOM(): HTMLElement;
|
|
20
|
+
updateDOM(): boolean;
|
|
21
|
+
static importDOM(): DOMConversionMap | null;
|
|
22
|
+
exportDOM(): DOMExportOutput;
|
|
23
|
+
static importJSON(json: SerializedScheduleItemNode): ScheduleItemNode;
|
|
24
|
+
exportJSON(): SerializedScheduleItemNode;
|
|
25
|
+
getTextContent(): string;
|
|
26
|
+
isInline(): boolean;
|
|
27
|
+
decorate(): ReactElement;
|
|
28
|
+
}
|
|
29
|
+
export declare function $createScheduleItemNode(data: ScheduleItemData): ScheduleItemNode;
|
|
30
|
+
export declare function $isScheduleItemNode(node: LexicalNode | null | undefined): node is ScheduleItemNode;
|
|
31
|
+
//# sourceMappingURL=ScheduleItemNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleItemNode.d.ts","sourceRoot":"","sources":["../../../src/nodes/schedule/ScheduleItemNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,qBAAqB,EAC1B,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAIzD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,0BAA0B,GAAG,MAAM,CAAC;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,EAAE,qBAAqB,CAAC,CAAC;AAEnG,qBAAa,gBAAiB,SAAQ,aAAa,CAAC,YAAY,CAAC;IAC/D,MAAM,EAAE,gBAAgB,CAAC;IAEzB,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,gBAAgB,GAAG,gBAAgB;gBAI1C,IAAI,EAAE,gBAAgB,EAAE,GAAG,CAAC,EAAE,OAAO;IAKjD,OAAO,IAAI,gBAAgB;IAI3B,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAOrC,SAAS,IAAI,WAAW;IAMxB,SAAS,IAAI,OAAO;IAIpB,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAoB3C,SAAS,IAAI,eAAe;IAY5B,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,0BAA0B,GAAG,gBAAgB;IAIrE,UAAU,IAAI,0BAA0B;IAUxC,cAAc,IAAI,MAAM;IAMxB,QAAQ,IAAI,OAAO;IAMnB,QAAQ,IAAI,YAAY;CAMzB;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,CAEhF;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACnC,IAAI,IAAI,gBAAgB,CAE1B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ScheduleItemComponent } from "./ScheduleItemComponent.js";
|
|
2
|
+
import { $applyNodeReplacement, DecoratorNode } from "lexical";
|
|
3
|
+
import { createElement } from "react";
|
|
4
|
+
//#region src/nodes/schedule/ScheduleItemNode.ts
|
|
5
|
+
var ScheduleItemNode = class ScheduleItemNode extends DecoratorNode {
|
|
6
|
+
__data;
|
|
7
|
+
static getType() {
|
|
8
|
+
return "schedule-item";
|
|
9
|
+
}
|
|
10
|
+
static clone(node) {
|
|
11
|
+
return new ScheduleItemNode({ ...node.__data }, node.__key);
|
|
12
|
+
}
|
|
13
|
+
constructor(data, key) {
|
|
14
|
+
super(key);
|
|
15
|
+
this.__data = data;
|
|
16
|
+
}
|
|
17
|
+
getData() {
|
|
18
|
+
return this.getLatest().__data;
|
|
19
|
+
}
|
|
20
|
+
setData(data) {
|
|
21
|
+
const self = this.getWritable();
|
|
22
|
+
self.__data = data;
|
|
23
|
+
}
|
|
24
|
+
createDOM() {
|
|
25
|
+
const div = document.createElement("div");
|
|
26
|
+
div.className = "schedule-item";
|
|
27
|
+
return div;
|
|
28
|
+
}
|
|
29
|
+
updateDOM() {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
static importDOM() {
|
|
33
|
+
return { div: (node) => {
|
|
34
|
+
if (!node.classList.contains("schedule-item")) return null;
|
|
35
|
+
return {
|
|
36
|
+
conversion: () => {
|
|
37
|
+
return { node: $createScheduleItemNode({
|
|
38
|
+
time: node.dataset.time ?? "",
|
|
39
|
+
title: node.dataset.title ?? "",
|
|
40
|
+
speaker: node.dataset.speaker || void 0,
|
|
41
|
+
description: node.dataset.description || void 0
|
|
42
|
+
}) };
|
|
43
|
+
},
|
|
44
|
+
priority: 1
|
|
45
|
+
};
|
|
46
|
+
} };
|
|
47
|
+
}
|
|
48
|
+
exportDOM() {
|
|
49
|
+
const el = document.createElement("div");
|
|
50
|
+
el.className = "schedule-item";
|
|
51
|
+
el.dataset.time = this.__data.time;
|
|
52
|
+
el.dataset.title = this.__data.title;
|
|
53
|
+
if (this.__data.speaker) el.dataset.speaker = this.__data.speaker;
|
|
54
|
+
if (this.__data.description) el.dataset.description = this.__data.description;
|
|
55
|
+
return { element: el };
|
|
56
|
+
}
|
|
57
|
+
static importJSON(json) {
|
|
58
|
+
return $createScheduleItemNode(json.data);
|
|
59
|
+
}
|
|
60
|
+
exportJSON() {
|
|
61
|
+
return {
|
|
62
|
+
...super.exportJSON(),
|
|
63
|
+
type: "schedule-item",
|
|
64
|
+
data: this.__data
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
getTextContent() {
|
|
68
|
+
const { time, title, speaker, description } = this.__data;
|
|
69
|
+
return `${time} ${[
|
|
70
|
+
title,
|
|
71
|
+
speaker,
|
|
72
|
+
description
|
|
73
|
+
].filter(Boolean).join(" | ")}`;
|
|
74
|
+
}
|
|
75
|
+
isInline() {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
decorate() {
|
|
79
|
+
return createElement(ScheduleItemComponent, {
|
|
80
|
+
nodeKey: this.__key,
|
|
81
|
+
data: this.__data
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function $createScheduleItemNode(data) {
|
|
86
|
+
return $applyNodeReplacement(new ScheduleItemNode(data));
|
|
87
|
+
}
|
|
88
|
+
function $isScheduleItemNode(node) {
|
|
89
|
+
return node instanceof ScheduleItemNode;
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { $createScheduleItemNode, $isScheduleItemNode, ScheduleItemNode };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=ScheduleItemNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleItemNode.js","names":[],"sources":["../../../src/nodes/schedule/ScheduleItemNode.ts"],"sourcesContent":["import {\n $applyNodeReplacement,\n DecoratorNode,\n type DOMConversionMap,\n type DOMExportOutput,\n type LexicalNode,\n type NodeKey,\n type SerializedLexicalNode,\n type Spread,\n} from 'lexical';\nimport { createElement, type ReactElement } from 'react';\n\nimport { ScheduleItemComponent } from './ScheduleItemComponent';\n\nexport interface ScheduleItemData {\n time: string;\n title: string;\n speaker?: string;\n description?: string;\n}\n\nexport type SerializedScheduleItemNode = Spread<{ data: ScheduleItemData }, SerializedLexicalNode>;\n\nexport class ScheduleItemNode extends DecoratorNode<ReactElement> {\n __data: ScheduleItemData;\n\n static getType(): string {\n return 'schedule-item';\n }\n\n static clone(node: ScheduleItemNode): ScheduleItemNode {\n return new ScheduleItemNode({ ...node.__data }, node.__key);\n }\n\n constructor(data: ScheduleItemData, key?: NodeKey) {\n super(key);\n this.__data = data;\n }\n\n getData(): ScheduleItemData {\n return this.getLatest().__data;\n }\n\n setData(data: ScheduleItemData): void {\n const self = this.getWritable();\n self.__data = data;\n }\n\n // --- DOM ---\n\n createDOM(): HTMLElement {\n const div = document.createElement('div');\n div.className = 'schedule-item';\n return div;\n }\n\n updateDOM(): boolean {\n return false;\n }\n\n static importDOM(): DOMConversionMap | null {\n return {\n div: (node: HTMLElement) => {\n if (!node.classList.contains('schedule-item')) return null;\n return {\n conversion: () => {\n const data = {\n time: node.dataset.time ?? '',\n title: node.dataset.title ?? '',\n speaker: node.dataset.speaker || undefined,\n description: node.dataset.description || undefined,\n };\n return { node: $createScheduleItemNode(data) };\n },\n priority: 1,\n };\n },\n };\n }\n\n exportDOM(): DOMExportOutput {\n const el = document.createElement('div');\n el.className = 'schedule-item';\n el.dataset.time = this.__data.time;\n el.dataset.title = this.__data.title;\n if (this.__data.speaker) el.dataset.speaker = this.__data.speaker;\n if (this.__data.description) el.dataset.description = this.__data.description;\n return { element: el };\n }\n\n // --- Serialization ---\n\n static importJSON(json: SerializedScheduleItemNode): ScheduleItemNode {\n return $createScheduleItemNode(json.data);\n }\n\n exportJSON(): SerializedScheduleItemNode {\n return {\n ...super.exportJSON(),\n type: 'schedule-item',\n data: this.__data,\n };\n }\n\n // --- Text ---\n\n getTextContent(): string {\n const { time, title, speaker, description } = this.__data;\n const parts = [title, speaker, description].filter(Boolean);\n return `${time} ${parts.join(' | ')}`;\n }\n\n isInline(): boolean {\n return false;\n }\n\n // --- Decorator (React rendering is handled by the component) ---\n\n decorate(): ReactElement {\n return createElement(ScheduleItemComponent, {\n nodeKey: this.__key,\n data: this.__data,\n });\n }\n}\n\nexport function $createScheduleItemNode(data: ScheduleItemData): ScheduleItemNode {\n return $applyNodeReplacement(new ScheduleItemNode(data));\n}\n\nexport function $isScheduleItemNode(\n node: LexicalNode | null | undefined\n): node is ScheduleItemNode {\n return node instanceof ScheduleItemNode;\n}\n"],"mappings":";;;;AAuBA,IAAa,mBAAb,MAAa,yBAAyB,cAA4B;CAChE;CAEA,OAAO,UAAkB;EACvB,OAAO;CACT;CAEA,OAAO,MAAM,MAA0C;EACrD,OAAO,IAAI,iBAAiB,EAAE,GAAG,KAAK,OAAO,GAAG,KAAK,KAAK;CAC5D;CAEA,YAAY,MAAwB,KAAe;EACjD,MAAM,GAAG;EACT,KAAK,SAAS;CAChB;CAEA,UAA4B;EAC1B,OAAO,KAAK,UAAU,CAAC,CAAC;CAC1B;CAEA,QAAQ,MAA8B;EACpC,MAAM,OAAO,KAAK,YAAY;EAC9B,KAAK,SAAS;CAChB;CAIA,YAAyB;EACvB,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,YAAY;EAChB,OAAO;CACT;CAEA,YAAqB;EACnB,OAAO;CACT;CAEA,OAAO,YAAqC;EAC1C,OAAO,EACL,MAAM,SAAsB;GAC1B,IAAI,CAAC,KAAK,UAAU,SAAS,eAAe,GAAG,OAAO;GACtD,OAAO;IACL,kBAAkB;KAOhB,OAAO,EAAE,MAAM,wBAAwB;MALrC,MAAM,KAAK,QAAQ,QAAQ;MAC3B,OAAO,KAAK,QAAQ,SAAS;MAC7B,SAAS,KAAK,QAAQ,WAAW,KAAA;MACjC,aAAa,KAAK,QAAQ,eAAe,KAAA;KAEJ,CAAI,EAAE;IAC/C;IACA,UAAU;GACZ;EACF,EACF;CACF;CAEA,YAA6B;EAC3B,MAAM,KAAK,SAAS,cAAc,KAAK;EACvC,GAAG,YAAY;EACf,GAAG,QAAQ,OAAO,KAAK,OAAO;EAC9B,GAAG,QAAQ,QAAQ,KAAK,OAAO;EAC/B,IAAI,KAAK,OAAO,SAAS,GAAG,QAAQ,UAAU,KAAK,OAAO;EAC1D,IAAI,KAAK,OAAO,aAAa,GAAG,QAAQ,cAAc,KAAK,OAAO;EAClE,OAAO,EAAE,SAAS,GAAG;CACvB;CAIA,OAAO,WAAW,MAAoD;EACpE,OAAO,wBAAwB,KAAK,IAAI;CAC1C;CAEA,aAAyC;EACvC,OAAO;GACL,GAAG,MAAM,WAAW;GACpB,MAAM;GACN,MAAM,KAAK;EACb;CACF;CAIA,iBAAyB;EACvB,MAAM,EAAE,MAAM,OAAO,SAAS,gBAAgB,KAAK;EAEnD,OAAO,GAAG,KAAK,GADD;GAAC;GAAO;GAAS;EAAW,CAAC,CAAC,OAAO,OACjC,CAAA,CAAM,KAAK,KAAK;CACpC;CAEA,WAAoB;EAClB,OAAO;CACT;CAIA,WAAyB;EACvB,OAAO,cAAc,uBAAuB;GAC1C,SAAS,KAAK;GACd,MAAM,KAAK;EACb,CAAC;CACH;AACF;AAEA,SAAgB,wBAAwB,MAA0C;CAChF,OAAO,sBAAsB,IAAI,iBAAiB,IAAI,CAAC;AACzD;AAEA,SAAgB,oBACd,MAC0B;CAC1B,OAAO,gBAAgB;AACzB"}
|