@eventuras/scribo 0.8.3 → 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.
Files changed (164) hide show
  1. package/dist/App.d.ts +11 -0
  2. package/dist/App.d.ts.map +1 -0
  3. package/dist/MarkdownEditor.d.ts +18 -0
  4. package/dist/MarkdownEditor.d.ts.map +1 -0
  5. package/dist/MarkdownEditor2.js +111 -0
  6. package/dist/MarkdownEditor2.js.map +1 -0
  7. package/dist/MarkdownInput.d.ts +27 -0
  8. package/dist/MarkdownInput.d.ts.map +1 -0
  9. package/dist/MarkdownInput.js +57 -0
  10. package/dist/MarkdownInput.js.map +1 -0
  11. package/dist/callout.js +5 -0
  12. package/dist/context/SharedHistoryContext.d.ts +11 -0
  13. package/dist/context/SharedHistoryContext.d.ts.map +1 -0
  14. package/dist/context/SharedHistoryContext.js +12 -0
  15. package/dist/context/SharedHistoryContext.js.map +1 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/main.d.ts +5 -0
  19. package/dist/main.d.ts.map +1 -0
  20. package/dist/main.js +4 -0
  21. package/dist/nodes/EditorNodes.d.ts +4 -0
  22. package/dist/nodes/EditorNodes.d.ts.map +1 -0
  23. package/dist/nodes/EditorNodes.js +39 -0
  24. package/dist/nodes/EditorNodes.js.map +1 -0
  25. package/dist/nodes/callout/CalloutComponent.d.ts +6 -0
  26. package/dist/nodes/callout/CalloutComponent.d.ts.map +1 -0
  27. package/dist/nodes/callout/CalloutComponent.js +53 -0
  28. package/dist/nodes/callout/CalloutComponent.js.map +1 -0
  29. package/dist/nodes/callout/CalloutNode.d.ts +27 -0
  30. package/dist/nodes/callout/CalloutNode.d.ts.map +1 -0
  31. package/dist/nodes/callout/CalloutNode.js +153 -0
  32. package/dist/nodes/callout/CalloutNode.js.map +1 -0
  33. package/dist/nodes/callout/CalloutTransformer.d.ts +3 -0
  34. package/dist/nodes/callout/CalloutTransformer.d.ts.map +1 -0
  35. package/dist/nodes/callout/CalloutTransformer.js +48 -0
  36. package/dist/nodes/callout/CalloutTransformer.js.map +1 -0
  37. package/dist/nodes/callout/calloutPlugin.d.ts +3 -0
  38. package/dist/nodes/callout/calloutPlugin.d.ts.map +1 -0
  39. package/dist/nodes/callout/calloutPlugin.js +34 -0
  40. package/dist/nodes/callout/calloutPlugin.js.map +1 -0
  41. package/dist/nodes/callout/index.d.ts +6 -0
  42. package/dist/nodes/callout/index.d.ts.map +1 -0
  43. package/dist/nodes/schedule/ScheduleItemComponent.d.ts +9 -0
  44. package/dist/nodes/schedule/ScheduleItemComponent.d.ts.map +1 -0
  45. package/dist/nodes/schedule/ScheduleItemComponent.js +167 -0
  46. package/dist/nodes/schedule/ScheduleItemComponent.js.map +1 -0
  47. package/dist/nodes/schedule/ScheduleItemNode.d.ts +31 -0
  48. package/dist/nodes/schedule/ScheduleItemNode.d.ts.map +1 -0
  49. package/dist/nodes/schedule/ScheduleItemNode.js +94 -0
  50. package/dist/nodes/schedule/ScheduleItemNode.js.map +1 -0
  51. package/dist/nodes/schedule/ScheduleTransformer.d.ts +22 -0
  52. package/dist/nodes/schedule/ScheduleTransformer.d.ts.map +1 -0
  53. package/dist/nodes/schedule/ScheduleTransformer.js +60 -0
  54. package/dist/nodes/schedule/ScheduleTransformer.js.map +1 -0
  55. package/dist/nodes/schedule/index.d.ts +5 -0
  56. package/dist/nodes/schedule/index.d.ts.map +1 -0
  57. package/dist/nodes/schedule/schedulePlugin.d.ts +3 -0
  58. package/dist/nodes/schedule/schedulePlugin.d.ts.map +1 -0
  59. package/dist/nodes/schedule/schedulePlugin.js +33 -0
  60. package/dist/nodes/schedule/schedulePlugin.js.map +1 -0
  61. package/dist/plugins/AutoLinkPlugin.d.ts +3 -0
  62. package/dist/plugins/AutoLinkPlugin.d.ts.map +1 -0
  63. package/dist/plugins/AutoLinkPlugin.js +22 -0
  64. package/dist/plugins/AutoLinkPlugin.js.map +1 -0
  65. package/dist/plugins/FloatingLinkEditorPlugin.d.ts +7 -0
  66. package/dist/plugins/FloatingLinkEditorPlugin.d.ts.map +1 -0
  67. package/dist/plugins/FloatingLinkEditorPlugin2.js +302 -0
  68. package/dist/plugins/FloatingLinkEditorPlugin2.js.map +1 -0
  69. package/dist/plugins/HistoryPlugin.d.ts +26 -0
  70. package/dist/plugins/HistoryPlugin.d.ts.map +1 -0
  71. package/dist/plugins/LinkPlugin.d.ts +3 -0
  72. package/dist/plugins/LinkPlugin.d.ts.map +1 -0
  73. package/dist/plugins/LinkPlugin.js +18 -0
  74. package/dist/plugins/LinkPlugin.js.map +1 -0
  75. package/dist/plugins/ToolbarPlugin.d.ts +7 -0
  76. package/dist/plugins/ToolbarPlugin.d.ts.map +1 -0
  77. package/dist/plugins/ToolbarPlugin.js +372 -0
  78. package/dist/plugins/ToolbarPlugin.js.map +1 -0
  79. package/dist/schedule.js +4 -0
  80. package/dist/scribo.css +1977 -0
  81. package/dist/themes/EditorTheme.d.ts +4 -0
  82. package/dist/themes/EditorTheme.d.ts.map +1 -0
  83. package/dist/themes/EditorTheme2.js +107 -0
  84. package/dist/themes/EditorTheme2.js.map +1 -0
  85. package/dist/types.d.ts +26 -0
  86. package/dist/types.d.ts.map +1 -0
  87. package/dist/ui/ContentEditable.d.ts +6 -0
  88. package/dist/ui/ContentEditable.d.ts.map +1 -0
  89. package/dist/ui/ContentEditable2.js +14 -0
  90. package/dist/ui/ContentEditable2.js.map +1 -0
  91. package/dist/ui/DropDown.d.ts +18 -0
  92. package/dist/ui/DropDown.d.ts.map +1 -0
  93. package/dist/ui/DropDown.js +162 -0
  94. package/dist/ui/DropDown.js.map +1 -0
  95. package/dist/ui/Placeholder.d.ts +6 -0
  96. package/dist/ui/Placeholder.d.ts.map +1 -0
  97. package/dist/ui/Placeholder2.js +13 -0
  98. package/dist/ui/Placeholder2.js.map +1 -0
  99. package/dist/utils/environment.d.ts +24 -0
  100. package/dist/utils/environment.d.ts.map +1 -0
  101. package/dist/utils/environment.js +20 -0
  102. package/dist/utils/environment.js.map +1 -0
  103. package/dist/utils/getSelectedNode.d.ts +3 -0
  104. package/dist/utils/getSelectedNode.d.ts.map +1 -0
  105. package/dist/utils/getSelectedNode.js +23 -0
  106. package/dist/utils/getSelectedNode.js.map +1 -0
  107. package/dist/utils/setFloatingElemPosition.d.ts +2 -0
  108. package/dist/utils/setFloatingElemPosition.d.ts.map +1 -0
  109. package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts +2 -0
  110. package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts.map +1 -0
  111. package/dist/utils/setFloatingElemPositionForLinkEditor.js +33 -0
  112. package/dist/utils/setFloatingElemPositionForLinkEditor.js.map +1 -0
  113. package/dist/utils/url.d.ts +11 -0
  114. package/dist/utils/url.d.ts.map +1 -0
  115. package/dist/utils/url.js +33 -0
  116. package/dist/utils/url.js.map +1 -0
  117. package/dist/vite.svg +1 -0
  118. package/package.json +55 -38
  119. package/src/MarkdownEditor.css +61 -47
  120. package/src/MarkdownEditor.tsx +76 -29
  121. package/src/MarkdownInput.tsx +9 -10
  122. package/src/context/SharedHistoryContext.tsx +8 -16
  123. package/src/main.tsx +3 -3
  124. package/src/nodes/EditorNodes.ts +10 -10
  125. package/src/nodes/callout/Callout.css +94 -0
  126. package/src/nodes/callout/CalloutComponent.tsx +61 -0
  127. package/src/nodes/callout/CalloutNode.ts +197 -0
  128. package/src/nodes/callout/CalloutTransformer.ts +87 -0
  129. package/src/nodes/callout/calloutPlugin.ts +37 -0
  130. package/src/nodes/callout/index.ts +5 -0
  131. package/src/nodes/schedule/ScheduleItem.css +140 -0
  132. package/src/nodes/schedule/ScheduleItemComponent.tsx +195 -0
  133. package/src/nodes/schedule/ScheduleItemNode.ts +135 -0
  134. package/src/nodes/schedule/ScheduleTransformer.ts +80 -0
  135. package/src/nodes/schedule/index.ts +4 -0
  136. package/src/nodes/schedule/schedulePlugin.ts +33 -0
  137. package/src/plugins/AutoLinkPlugin.tsx +5 -10
  138. package/src/plugins/FloatingLinkEditorPlugin.tsx +42 -66
  139. package/src/plugins/HistoryPlugin.tsx +20 -30
  140. package/src/plugins/LinkPlugin.tsx +2 -3
  141. package/src/plugins/ToolbarPlugin.tsx +129 -141
  142. package/src/themes/EditorTheme.css +9 -5
  143. package/src/themes/EditorTheme.ts +89 -90
  144. package/src/types.ts +27 -0
  145. package/src/ui/ContentEditable.tsx +5 -5
  146. package/src/ui/DropDown.tsx +23 -41
  147. package/src/ui/Placeholder.tsx +21 -21
  148. package/src/utils/environment.ts +6 -12
  149. package/src/utils/getSelectedNode.ts +3 -5
  150. package/src/utils/setFloatingElemPosition.ts +2 -5
  151. package/src/utils/setFloatingElemPositionForLinkEditor.ts +1 -1
  152. package/src/utils/url.ts +4 -10
  153. package/tsconfig.json +8 -0
  154. package/CHANGELOG.md +0 -65
  155. package/README.md +0 -126
  156. package/RELEASE.md +0 -102
  157. package/eslint.config.js +0 -4
  158. package/src/App.css +0 -35
  159. package/src/App.tsx +0 -42
  160. package/src/index.tsx +0 -13
  161. package/tsconfig.node.json +0 -11
  162. package/vite.config.site.ts +0 -19
  163. package/vite.config.ts +0 -33
  164. /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,3 @@
1
+ import { MultilineElementTransformer } from '@lexical/markdown';
2
+ export declare const CALLOUT_TRANSFORMER: MultilineElementTransformer;
3
+ //# sourceMappingURL=CalloutTransformer.d.ts.map
@@ -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,3 @@
1
+ import { ScriboPlugin } from '../../types';
2
+ export declare const calloutPlugin: ScriboPlugin;
3
+ //# sourceMappingURL=calloutPlugin.d.ts.map
@@ -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"}