@kouji-ui/core 0.2.0 → 0.4.0

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.
@@ -0,0 +1,390 @@
1
+ import { createEditor, $insertNodes, $createParagraphNode, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, CAN_REDO_COMMAND, $getRoot, $getSelection, $isRangeSelection, FORMAT_TEXT_COMMAND, KEY_DOWN_COMMAND, COMMAND_PRIORITY_HIGH, UNDO_COMMAND, REDO_COMMAND } from 'lexical';
2
+ import { registerRichText } from '@lexical/rich-text';
3
+ import { $setBlocksType } from '@lexical/selection';
4
+ import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html';
5
+
6
+ /**
7
+ * Browser-only orchestration layer around Lexical.
8
+ *
9
+ * Loaded exclusively via a dynamic `import()` from {@link KjRichTextEditor}
10
+ * inside `afterNextRender`, so its eager imports never execute during SSR. It
11
+ * statically imports only the **base** editing packages (core `lexical`,
12
+ * `@lexical/rich-text` for `registerRichText`, `@lexical/selection`,
13
+ * `@lexical/html`). Everything else (lists, code, history, markdown, links) is
14
+ * loaded lazily and per-feature via each feature's `load()`.
15
+ *
16
+ * State is derived package-agnostically (by `node.getType()` + duck-typed
17
+ * methods) so the engine never imports a feature's package to read state.
18
+ */
19
+ /** CSS classes applied to editor nodes; styled by the components layer. */
20
+ const THEME = {
21
+ paragraph: 'kj-rte-paragraph',
22
+ heading: { h1: 'kj-rte-h1', h2: 'kj-rte-h2', h3: 'kj-rte-h3' },
23
+ quote: 'kj-rte-quote',
24
+ list: { ul: 'kj-rte-ul', ol: 'kj-rte-ol', listitem: 'kj-rte-li' },
25
+ link: 'kj-rte-link',
26
+ code: 'kj-rte-code-block',
27
+ text: {
28
+ bold: 'kj-rte-bold',
29
+ italic: 'kj-rte-italic',
30
+ underline: 'kj-rte-underline',
31
+ strikethrough: 'kj-rte-strikethrough',
32
+ code: 'kj-rte-code',
33
+ },
34
+ };
35
+ const INLINE_FORMATS = [
36
+ 'bold',
37
+ 'italic',
38
+ 'underline',
39
+ 'strikethrough',
40
+ 'code',
41
+ ];
42
+ /**
43
+ * Create and mount a Lexical editor on `root`, loading each feature's packages,
44
+ * collecting their nodes **before** `createEditor`, then registering behaviour.
45
+ * Async because feature package loading is awaited.
46
+ */
47
+ async function createRichTextEngine(root, config, callbacks) {
48
+ const features = config.features ?? [];
49
+ // Per-feature lazy package loading. Disabling a feature ⇒ its package never
50
+ // loads. Loaded in parallel; a failure is isolated to its feature.
51
+ await Promise.all(features.map(async (feature) => {
52
+ try {
53
+ await feature.load?.();
54
+ }
55
+ catch (error) {
56
+ console.error(`[KjRichTextEditor] feature "${feature.name}" load() failed`, error);
57
+ }
58
+ }));
59
+ // Collect nodes from all features (now that their packages are loaded).
60
+ const nodeSet = new Set();
61
+ for (const feature of features) {
62
+ try {
63
+ for (const node of feature.nodes?.() ?? [])
64
+ nodeSet.add(node);
65
+ }
66
+ catch (error) {
67
+ console.error(`[KjRichTextEditor] feature "${feature.name}" nodes() failed`, error);
68
+ }
69
+ }
70
+ const editor = createEditor({
71
+ namespace: config.namespace ?? 'kj-rich-text',
72
+ editable: true,
73
+ theme: THEME,
74
+ nodes: [...nodeSet],
75
+ onError: (error) => console.error('[KjRichTextEditor]', error),
76
+ });
77
+ editor.setRootElement(root);
78
+ const engine = new RichTextEngine(editor, callbacks, config);
79
+ engine.init(features);
80
+ return engine;
81
+ }
82
+ /** Handle around a mounted Lexical editor. Command methods are no-ops if destroyed. */
83
+ class RichTextEngine {
84
+ editor;
85
+ callbacks;
86
+ config;
87
+ teardowns = [];
88
+ canUndo = false;
89
+ canRedo = false;
90
+ destroyed = false;
91
+ decoratorRegistry = new Map();
92
+ mounted = new Map();
93
+ /** Shared, live context handed to features. */
94
+ context;
95
+ constructor(editor, callbacks, config) {
96
+ this.editor = editor;
97
+ this.callbacks = callbacks;
98
+ this.config = config;
99
+ const context = {
100
+ editor,
101
+ update: (fn) => this.update(fn),
102
+ read: (fn) => editor.getEditorState().read(fn),
103
+ toggleInlineFormat: (format) => this.toggleFormat(format),
104
+ setBlock: (create) => this.setBlock(create),
105
+ setParagraph: () => this.setBlock(() => $createParagraphNode()),
106
+ insertNodes: (create) => this.update(() => $insertNodes(create())),
107
+ dispatch: (command, payload) => {
108
+ editor.dispatchCommand(command, payload);
109
+ this.flush();
110
+ },
111
+ registerCommand: (command, listener, priority) => editor.registerCommand(command, listener, priority),
112
+ registerNodeTransform: (klass, listener) => editor.registerNodeTransform(klass, listener),
113
+ registerShortcut: (shortcut, run) => this.registerShortcut(shortcut, run),
114
+ undo: () => this.undo(),
115
+ redo: () => this.redo(),
116
+ focus: () => this.focus(),
117
+ openOverlay: (id, data) => this.config.onOverlayOpen?.(id, data),
118
+ closeOverlay: () => this.config.onOverlayClose?.(),
119
+ announce: (message) => this.config.onAnnounce?.(message),
120
+ };
121
+ // `state` is a live getter (reflects the current selection each read).
122
+ Object.defineProperty(context, 'state', {
123
+ get: () => this.readState(),
124
+ enumerable: true,
125
+ });
126
+ this.context = context;
127
+ }
128
+ /** @internal Register base editing, feature behaviour, listeners, decorators, seed content. */
129
+ init(features) {
130
+ // Base: rich-text editing (selection, formatting commands, paste, Enter).
131
+ this.teardowns.push(registerRichText(this.editor));
132
+ for (const feature of features) {
133
+ try {
134
+ const teardown = feature.setup?.(this.context);
135
+ if (teardown)
136
+ this.teardowns.push(teardown);
137
+ }
138
+ catch (error) {
139
+ console.error(`[KjRichTextEditor] feature "${feature.name}" setup failed`, error);
140
+ }
141
+ // Decorator components declared via createKjDecoratorNode-based features.
142
+ for (const registration of feature.decorators ?? []) {
143
+ this.decoratorRegistry.set(registration.nodeType, registration.component);
144
+ }
145
+ }
146
+ if (this.config.mount && this.decoratorRegistry.size > 0) {
147
+ this.teardowns.push(this.editor.registerDecoratorListener((decorators) => this.reconcileDecorators(decorators)));
148
+ }
149
+ this.teardowns.push(this.editor.registerCommand(CAN_UNDO_COMMAND, (payload) => {
150
+ this.canUndo = payload;
151
+ this.emitState();
152
+ return false;
153
+ }, COMMAND_PRIORITY_LOW));
154
+ this.teardowns.push(this.editor.registerCommand(CAN_REDO_COMMAND, (payload) => {
155
+ this.canRedo = payload;
156
+ this.emitState();
157
+ return false;
158
+ }, COMMAND_PRIORITY_LOW));
159
+ this.teardowns.push(this.editor.registerUpdateListener(({ editorState }) => {
160
+ editorState.read(() => {
161
+ const html = $generateHtmlFromNodes(this.editor, null);
162
+ const text = $getRoot().getTextContent();
163
+ this.callbacks.onValue({ html, text, json: editorState.toJSON() });
164
+ });
165
+ this.emitState();
166
+ }));
167
+ if (this.config.initialHtml) {
168
+ this.setHtml(this.config.initialHtml);
169
+ }
170
+ else {
171
+ this.emitState();
172
+ }
173
+ }
174
+ // -- reactive state (package-agnostic) -----------------------------------
175
+ emitState() {
176
+ if (this.destroyed)
177
+ return;
178
+ this.callbacks.onState(this.readState());
179
+ }
180
+ readState() {
181
+ const activeFormats = new Set();
182
+ let blockType = 'paragraph';
183
+ let isLink = false;
184
+ let empty = true;
185
+ this.editor.getEditorState().read(() => {
186
+ const root = $getRoot();
187
+ empty = root.getTextContent().length === 0;
188
+ const selection = $getSelection();
189
+ if (!$isRangeSelection(selection))
190
+ return;
191
+ for (const format of INLINE_FORMATS) {
192
+ if (selection.hasFormat(format))
193
+ activeFormats.add(format);
194
+ }
195
+ const anchorNode = selection.anchor.getNode();
196
+ const element = anchorNode.getKey() === 'root' ? anchorNode : anchorNode.getTopLevelElementOrThrow();
197
+ blockType = elementBlockType(element);
198
+ // Duck-typed link detection (no @lexical/link import).
199
+ isLink = selection.getNodes().some((node) => isLinkNode(node) || isLinkNode(node.getParent()));
200
+ });
201
+ return { activeFormats, blockType, canUndo: this.canUndo, canRedo: this.canRedo, isLink, empty };
202
+ }
203
+ reconcileDecorators(decorators) {
204
+ if (!this.config.mount)
205
+ return;
206
+ const liveKeys = new Set(Object.keys(decorators));
207
+ for (const [key, mounted] of this.mounted) {
208
+ if (!liveKeys.has(key)) {
209
+ mounted.destroy();
210
+ this.mounted.delete(key);
211
+ }
212
+ }
213
+ for (const key of liveKeys) {
214
+ if (this.mounted.has(key))
215
+ continue;
216
+ const node = decorators[key];
217
+ const type = node?.getType?.();
218
+ const component = type ? this.decoratorRegistry.get(type) : undefined;
219
+ if (!component)
220
+ continue;
221
+ const hostEl = this.editor.getElementByKey(key);
222
+ if (!hostEl)
223
+ continue;
224
+ const mounted = this.config.mount.mount(component, node);
225
+ hostEl.appendChild(mounted.element);
226
+ this.mounted.set(key, mounted);
227
+ }
228
+ }
229
+ // -- command mechanics ---------------------------------------------------
230
+ flush() {
231
+ this.editor.update(() => { }, { discrete: true });
232
+ }
233
+ update(fn) {
234
+ if (this.destroyed)
235
+ return;
236
+ this.editor.update(fn, { discrete: true });
237
+ }
238
+ toggleFormat(format) {
239
+ if (this.destroyed)
240
+ return;
241
+ this.editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
242
+ this.flush();
243
+ }
244
+ setBlock(create) {
245
+ this.update(() => {
246
+ const selection = $getSelection();
247
+ if ($isRangeSelection(selection)) {
248
+ // Block factories always return ElementNodes; the public ctx type is the
249
+ // broader LexicalNode for ergonomics.
250
+ $setBlocksType(selection, create);
251
+ }
252
+ });
253
+ }
254
+ registerShortcut(shortcut, run) {
255
+ const parts = shortcut.toLowerCase().split('+');
256
+ const key = parts[parts.length - 1];
257
+ const needMod = parts.includes('mod');
258
+ const needShift = parts.includes('shift');
259
+ const needAlt = parts.includes('alt');
260
+ return this.editor.registerCommand(KEY_DOWN_COMMAND, (event) => {
261
+ const mod = event.ctrlKey || event.metaKey;
262
+ if (event.key.toLowerCase() === key &&
263
+ needMod === mod &&
264
+ needShift === event.shiftKey &&
265
+ needAlt === event.altKey) {
266
+ event.preventDefault();
267
+ run();
268
+ return true;
269
+ }
270
+ return false;
271
+ }, COMMAND_PRIORITY_HIGH);
272
+ }
273
+ undo() {
274
+ if (this.destroyed)
275
+ return;
276
+ this.editor.dispatchCommand(UNDO_COMMAND, undefined);
277
+ this.flush();
278
+ }
279
+ redo() {
280
+ if (this.destroyed)
281
+ return;
282
+ this.editor.dispatchCommand(REDO_COMMAND, undefined);
283
+ this.flush();
284
+ }
285
+ focus() {
286
+ if (this.destroyed)
287
+ return;
288
+ this.editor.focus();
289
+ }
290
+ clear() {
291
+ if (this.destroyed)
292
+ return;
293
+ this.update(() => {
294
+ const root = $getRoot();
295
+ root.clear();
296
+ root.append($createParagraphNode());
297
+ });
298
+ }
299
+ setEditable(editable) {
300
+ if (this.destroyed)
301
+ return;
302
+ this.editor.setEditable(editable);
303
+ }
304
+ // -- value I/O -----------------------------------------------------------
305
+ getHtml() {
306
+ let html = '';
307
+ this.editor.getEditorState().read(() => {
308
+ html = $generateHtmlFromNodes(this.editor, null);
309
+ });
310
+ return html;
311
+ }
312
+ setHtml(html) {
313
+ if (this.destroyed)
314
+ return;
315
+ this.update(() => {
316
+ const root = $getRoot();
317
+ root.clear();
318
+ if (!html) {
319
+ root.append($createParagraphNode());
320
+ return;
321
+ }
322
+ // $generateNodesFromDOM only produces nodes for registered (active) types,
323
+ // so deserialization automatically respects the active feature/node set.
324
+ const dom = new DOMParser().parseFromString(html, 'text/html');
325
+ const nodes = $generateNodesFromDOM(this.editor, dom);
326
+ root.select();
327
+ $insertNodes(nodes);
328
+ if (root.getChildrenSize() === 0)
329
+ root.append($createParagraphNode());
330
+ });
331
+ }
332
+ getJson() {
333
+ return this.editor.getEditorState().toJSON();
334
+ }
335
+ setJson(json) {
336
+ if (this.destroyed)
337
+ return;
338
+ this.editor.setEditorState(this.editor.parseEditorState(json));
339
+ this.flush();
340
+ }
341
+ destroy() {
342
+ if (this.destroyed)
343
+ return;
344
+ this.destroyed = true;
345
+ for (const mounted of this.mounted.values()) {
346
+ try {
347
+ mounted.destroy();
348
+ }
349
+ catch {
350
+ // ignore
351
+ }
352
+ }
353
+ this.mounted.clear();
354
+ for (const teardown of this.teardowns.reverse()) {
355
+ try {
356
+ teardown();
357
+ }
358
+ catch {
359
+ // ignore teardown errors
360
+ }
361
+ }
362
+ this.teardowns = [];
363
+ this.editor.setRootElement(null);
364
+ }
365
+ }
366
+ /** Map a top-level element node to a {@link KjBlockType} via its type string. */
367
+ function elementBlockType(element) {
368
+ const el = element;
369
+ switch (el.getType()) {
370
+ case 'heading': {
371
+ const tag = el.getTag?.();
372
+ return tag === 'h1' || tag === 'h2' || tag === 'h3' ? tag : 'paragraph';
373
+ }
374
+ case 'quote':
375
+ return 'quote';
376
+ case 'code':
377
+ return 'code';
378
+ case 'list':
379
+ return el.getListType?.() === 'number' ? 'number' : 'bullet';
380
+ default:
381
+ return 'paragraph';
382
+ }
383
+ }
384
+ /** Duck-typed link-node check (avoids importing `@lexical/link`). */
385
+ function isLinkNode(node) {
386
+ return !!node && node.getType() === 'link';
387
+ }
388
+
389
+ export { RichTextEngine, createRichTextEngine };
390
+ //# sourceMappingURL=kouji-ui-core-engine-CKMr0aiZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kouji-ui-core-engine-CKMr0aiZ.mjs","sources":["../../../packages/core/src/rich-text/engine.ts"],"sourcesContent":["/**\n * Browser-only orchestration layer around Lexical.\n *\n * Loaded exclusively via a dynamic `import()` from {@link KjRichTextEditor}\n * inside `afterNextRender`, so its eager imports never execute during SSR. It\n * statically imports only the **base** editing packages (core `lexical`,\n * `@lexical/rich-text` for `registerRichText`, `@lexical/selection`,\n * `@lexical/html`). Everything else (lists, code, history, markdown, links) is\n * loaded lazily and per-feature via each feature's `load()`.\n *\n * State is derived package-agnostically (by `node.getType()` + duck-typed\n * methods) so the engine never imports a feature's package to read state.\n */\nimport {\n createEditor,\n $getRoot,\n $getSelection,\n $isRangeSelection,\n $insertNodes,\n $createParagraphNode,\n FORMAT_TEXT_COMMAND,\n UNDO_COMMAND,\n REDO_COMMAND,\n CAN_UNDO_COMMAND,\n CAN_REDO_COMMAND,\n KEY_DOWN_COMMAND,\n COMMAND_PRIORITY_LOW,\n COMMAND_PRIORITY_HIGH,\n type ElementNode,\n type Klass,\n type LexicalEditor,\n type LexicalNode,\n type NodeKey,\n type SerializedEditorState,\n type EditorThemeClasses,\n} from 'lexical';\nimport { registerRichText } from '@lexical/rich-text';\nimport { $setBlocksType } from '@lexical/selection';\nimport { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html';\nimport type { KjRichTextContext, KjRichTextFeature, KjRteShortcut } from './feature';\nimport type { KjDecoratorMountAdapter, KjMountedComponent } from './rich-text.context';\nimport type { KjBlockType, KjRichTextState, KjTextFormat } from './rich-text-editor.types';\n\n/** CSS classes applied to editor nodes; styled by the components layer. */\nconst THEME: EditorThemeClasses = {\n paragraph: 'kj-rte-paragraph',\n heading: { h1: 'kj-rte-h1', h2: 'kj-rte-h2', h3: 'kj-rte-h3' },\n quote: 'kj-rte-quote',\n list: { ul: 'kj-rte-ul', ol: 'kj-rte-ol', listitem: 'kj-rte-li' },\n link: 'kj-rte-link',\n code: 'kj-rte-code-block',\n text: {\n bold: 'kj-rte-bold',\n italic: 'kj-rte-italic',\n underline: 'kj-rte-underline',\n strikethrough: 'kj-rte-strikethrough',\n code: 'kj-rte-code',\n },\n};\n\nconst INLINE_FORMATS: readonly KjTextFormat[] = [\n 'bold',\n 'italic',\n 'underline',\n 'strikethrough',\n 'code',\n];\n\n/** Configuration for {@link createRichTextEngine}. */\nexport interface RichTextEngineConfig {\n /** Initial content as an HTML string. */\n initialHtml?: string;\n /** Active features (built-in editing lives in features too). */\n features?: readonly KjRichTextFeature[];\n /** Lexical namespace (diagnostics only). */\n namespace?: string;\n /** Adapter used to mount Angular components for decorator nodes. */\n mount?: KjDecoratorMountAdapter;\n /** Called when a feature requests an overlay. */\n onOverlayOpen?(id: string, data: unknown): void;\n /** Called when a feature closes the overlay. */\n onOverlayClose?(): void;\n /** Called to announce a message to assistive technology. */\n onAnnounce?(message: string): void;\n}\n\n/** Callbacks the engine invokes to push state/value changes to the directive. */\nexport interface RichTextEngineCallbacks {\n onState(state: KjRichTextState): void;\n onValue(value: { html: string; text: string; json: SerializedEditorState }): void;\n}\n\n/**\n * Create and mount a Lexical editor on `root`, loading each feature's packages,\n * collecting their nodes **before** `createEditor`, then registering behaviour.\n * Async because feature package loading is awaited.\n */\nexport async function createRichTextEngine(\n root: HTMLElement,\n config: RichTextEngineConfig,\n callbacks: RichTextEngineCallbacks,\n): Promise<RichTextEngine> {\n const features = config.features ?? [];\n\n // Per-feature lazy package loading. Disabling a feature ⇒ its package never\n // loads. Loaded in parallel; a failure is isolated to its feature.\n await Promise.all(\n features.map(async (feature) => {\n try {\n await feature.load?.();\n } catch (error) {\n console.error(`[KjRichTextEditor] feature \"${feature.name}\" load() failed`, error);\n }\n }),\n );\n\n // Collect nodes from all features (now that their packages are loaded).\n const nodeSet = new Set<Klass<LexicalNode>>();\n for (const feature of features) {\n try {\n for (const node of feature.nodes?.() ?? []) nodeSet.add(node);\n } catch (error) {\n console.error(`[KjRichTextEditor] feature \"${feature.name}\" nodes() failed`, error);\n }\n }\n\n const editor = createEditor({\n namespace: config.namespace ?? 'kj-rich-text',\n editable: true,\n theme: THEME,\n nodes: [...nodeSet],\n onError: (error: Error) => console.error('[KjRichTextEditor]', error),\n });\n\n editor.setRootElement(root);\n const engine = new RichTextEngine(editor, callbacks, config);\n engine.init(features);\n return engine;\n}\n\n/** Handle around a mounted Lexical editor. Command methods are no-ops if destroyed. */\nexport class RichTextEngine {\n private teardowns: Array<() => void> = [];\n private canUndo = false;\n private canRedo = false;\n private destroyed = false;\n private readonly decoratorRegistry = new Map<string, unknown>();\n private readonly mounted = new Map<NodeKey, KjMountedComponent>();\n /** Shared, live context handed to features. */\n readonly context: KjRichTextContext;\n\n constructor(\n readonly editor: LexicalEditor,\n private readonly callbacks: RichTextEngineCallbacks,\n private readonly config: RichTextEngineConfig,\n ) {\n const context: Omit<KjRichTextContext, 'state'> = {\n editor,\n update: (fn: () => void) => this.update(fn),\n read: (fn) => editor.getEditorState().read(fn),\n toggleInlineFormat: (format) => this.toggleFormat(format),\n setBlock: (create) => this.setBlock(create),\n setParagraph: () => this.setBlock(() => $createParagraphNode()),\n insertNodes: (create) => this.update(() => $insertNodes(create())),\n dispatch: (command, payload) => {\n editor.dispatchCommand(command, payload);\n this.flush();\n },\n registerCommand: (command, listener, priority) =>\n editor.registerCommand(command, listener, priority),\n registerNodeTransform: (klass, listener) => editor.registerNodeTransform(klass, listener),\n registerShortcut: (shortcut, run) => this.registerShortcut(shortcut, run),\n undo: () => this.undo(),\n redo: () => this.redo(),\n focus: () => this.focus(),\n openOverlay: (id, data) => this.config.onOverlayOpen?.(id, data),\n closeOverlay: () => this.config.onOverlayClose?.(),\n announce: (message) => this.config.onAnnounce?.(message),\n };\n // `state` is a live getter (reflects the current selection each read).\n Object.defineProperty(context, 'state', {\n get: () => this.readState(),\n enumerable: true,\n });\n this.context = context as KjRichTextContext;\n }\n\n /** @internal Register base editing, feature behaviour, listeners, decorators, seed content. */\n init(features: readonly KjRichTextFeature[]): void {\n // Base: rich-text editing (selection, formatting commands, paste, Enter).\n this.teardowns.push(registerRichText(this.editor));\n\n for (const feature of features) {\n try {\n const teardown = feature.setup?.(this.context);\n if (teardown) this.teardowns.push(teardown);\n } catch (error) {\n console.error(`[KjRichTextEditor] feature \"${feature.name}\" setup failed`, error);\n }\n // Decorator components declared via createKjDecoratorNode-based features.\n for (const registration of feature.decorators ?? []) {\n this.decoratorRegistry.set(registration.nodeType, registration.component);\n }\n }\n\n if (this.config.mount && this.decoratorRegistry.size > 0) {\n this.teardowns.push(\n this.editor.registerDecoratorListener((decorators: Record<NodeKey, unknown>) =>\n this.reconcileDecorators(decorators),\n ),\n );\n }\n\n this.teardowns.push(\n this.editor.registerCommand(\n CAN_UNDO_COMMAND,\n (payload: boolean) => {\n this.canUndo = payload;\n this.emitState();\n return false;\n },\n COMMAND_PRIORITY_LOW,\n ),\n );\n this.teardowns.push(\n this.editor.registerCommand(\n CAN_REDO_COMMAND,\n (payload: boolean) => {\n this.canRedo = payload;\n this.emitState();\n return false;\n },\n COMMAND_PRIORITY_LOW,\n ),\n );\n\n this.teardowns.push(\n this.editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n const html = $generateHtmlFromNodes(this.editor, null);\n const text = $getRoot().getTextContent();\n this.callbacks.onValue({ html, text, json: editorState.toJSON() });\n });\n this.emitState();\n }),\n );\n\n if (this.config.initialHtml) {\n this.setHtml(this.config.initialHtml);\n } else {\n this.emitState();\n }\n }\n\n // -- reactive state (package-agnostic) -----------------------------------\n\n private emitState(): void {\n if (this.destroyed) return;\n this.callbacks.onState(this.readState());\n }\n\n private readState(): KjRichTextState {\n const activeFormats = new Set<KjTextFormat>();\n let blockType: KjBlockType = 'paragraph';\n let isLink = false;\n let empty = true;\n\n this.editor.getEditorState().read(() => {\n const root = $getRoot();\n empty = root.getTextContent().length === 0;\n\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n for (const format of INLINE_FORMATS) {\n if (selection.hasFormat(format)) activeFormats.add(format);\n }\n\n const anchorNode = selection.anchor.getNode();\n const element =\n anchorNode.getKey() === 'root' ? anchorNode : anchorNode.getTopLevelElementOrThrow();\n blockType = elementBlockType(element);\n\n // Duck-typed link detection (no @lexical/link import).\n isLink = selection.getNodes().some((node) => isLinkNode(node) || isLinkNode(node.getParent()));\n });\n\n return { activeFormats, blockType, canUndo: this.canUndo, canRedo: this.canRedo, isLink, empty };\n }\n\n private reconcileDecorators(decorators: Record<NodeKey, unknown>): void {\n if (!this.config.mount) return;\n const liveKeys = new Set<NodeKey>(Object.keys(decorators) as NodeKey[]);\n for (const [key, mounted] of this.mounted) {\n if (!liveKeys.has(key)) {\n mounted.destroy();\n this.mounted.delete(key);\n }\n }\n for (const key of liveKeys) {\n if (this.mounted.has(key)) continue;\n const node = decorators[key] as { getType?: () => string } | undefined;\n const type = node?.getType?.();\n const component = type ? this.decoratorRegistry.get(type) : undefined;\n if (!component) continue;\n const hostEl = this.editor.getElementByKey(key);\n if (!hostEl) continue;\n const mounted = this.config.mount.mount(component, node);\n hostEl.appendChild(mounted.element);\n this.mounted.set(key, mounted);\n }\n }\n\n // -- command mechanics ---------------------------------------------------\n\n private flush(): void {\n this.editor.update(() => {}, { discrete: true });\n }\n\n private update(fn: () => void): void {\n if (this.destroyed) return;\n this.editor.update(fn, { discrete: true });\n }\n\n private toggleFormat(format: KjTextFormat): void {\n if (this.destroyed) return;\n this.editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);\n this.flush();\n }\n\n private setBlock(create: () => LexicalNode): void {\n this.update(() => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n // Block factories always return ElementNodes; the public ctx type is the\n // broader LexicalNode for ergonomics.\n $setBlocksType(selection, create as () => ElementNode);\n }\n });\n }\n\n private registerShortcut(shortcut: KjRteShortcut, run: () => void): () => void {\n const parts = shortcut.toLowerCase().split('+');\n const key = parts[parts.length - 1];\n const needMod = parts.includes('mod');\n const needShift = parts.includes('shift');\n const needAlt = parts.includes('alt');\n return this.editor.registerCommand(\n KEY_DOWN_COMMAND,\n (event: KeyboardEvent) => {\n const mod = event.ctrlKey || event.metaKey;\n if (\n event.key.toLowerCase() === key &&\n needMod === mod &&\n needShift === event.shiftKey &&\n needAlt === event.altKey\n ) {\n event.preventDefault();\n run();\n return true;\n }\n return false;\n },\n COMMAND_PRIORITY_HIGH,\n );\n }\n\n undo(): void {\n if (this.destroyed) return;\n this.editor.dispatchCommand(UNDO_COMMAND, undefined);\n this.flush();\n }\n\n redo(): void {\n if (this.destroyed) return;\n this.editor.dispatchCommand(REDO_COMMAND, undefined);\n this.flush();\n }\n\n focus(): void {\n if (this.destroyed) return;\n this.editor.focus();\n }\n\n clear(): void {\n if (this.destroyed) return;\n this.update(() => {\n const root = $getRoot();\n root.clear();\n root.append($createParagraphNode());\n });\n }\n\n setEditable(editable: boolean): void {\n if (this.destroyed) return;\n this.editor.setEditable(editable);\n }\n\n // -- value I/O -----------------------------------------------------------\n\n getHtml(): string {\n let html = '';\n this.editor.getEditorState().read(() => {\n html = $generateHtmlFromNodes(this.editor, null);\n });\n return html;\n }\n\n setHtml(html: string): void {\n if (this.destroyed) return;\n this.update(() => {\n const root = $getRoot();\n root.clear();\n if (!html) {\n root.append($createParagraphNode());\n return;\n }\n // $generateNodesFromDOM only produces nodes for registered (active) types,\n // so deserialization automatically respects the active feature/node set.\n const dom = new DOMParser().parseFromString(html, 'text/html');\n const nodes = $generateNodesFromDOM(this.editor, dom);\n root.select();\n $insertNodes(nodes);\n if (root.getChildrenSize() === 0) root.append($createParagraphNode());\n });\n }\n\n getJson(): SerializedEditorState {\n return this.editor.getEditorState().toJSON();\n }\n\n setJson(json: SerializedEditorState): void {\n if (this.destroyed) return;\n this.editor.setEditorState(this.editor.parseEditorState(json));\n this.flush();\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n for (const mounted of this.mounted.values()) {\n try {\n mounted.destroy();\n } catch {\n // ignore\n }\n }\n this.mounted.clear();\n for (const teardown of this.teardowns.reverse()) {\n try {\n teardown();\n } catch {\n // ignore teardown errors\n }\n }\n this.teardowns = [];\n this.editor.setRootElement(null);\n }\n}\n\n/** Map a top-level element node to a {@link KjBlockType} via its type string. */\nfunction elementBlockType(element: LexicalNode): KjBlockType {\n const el = element as unknown as {\n getType(): string;\n getTag?(): string;\n getListType?(): string;\n };\n switch (el.getType()) {\n case 'heading': {\n const tag = el.getTag?.();\n return tag === 'h1' || tag === 'h2' || tag === 'h3' ? tag : 'paragraph';\n }\n case 'quote':\n return 'quote';\n case 'code':\n return 'code';\n case 'list':\n return el.getListType?.() === 'number' ? 'number' : 'bullet';\n default:\n return 'paragraph';\n }\n}\n\n/** Duck-typed link-node check (avoids importing `@lexical/link`). */\nfunction isLinkNode(node: LexicalNode | null | undefined): boolean {\n return !!node && (node as unknown as { getType(): string }).getType() === 'link';\n}\n"],"names":[],"mappings":";;;;;AAAA;;;;;;;;;;;;AAYG;AA+BH;AACA,MAAM,KAAK,GAAuB;AAChC,IAAA,SAAS,EAAE,kBAAkB;AAC7B,IAAA,OAAO,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE;AAC9D,IAAA,KAAK,EAAE,cAAc;AACrB,IAAA,IAAI,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE;AACjE,IAAA,IAAI,EAAE,aAAa;AACnB,IAAA,IAAI,EAAE,mBAAmB;AACzB,IAAA,IAAI,EAAE;AACJ,QAAA,IAAI,EAAE,aAAa;AACnB,QAAA,MAAM,EAAE,eAAe;AACvB,QAAA,SAAS,EAAE,kBAAkB;AAC7B,QAAA,aAAa,EAAE,sBAAsB;AACrC,QAAA,IAAI,EAAE,aAAa;AACpB,KAAA;CACF;AAED,MAAM,cAAc,GAA4B;IAC9C,MAAM;IACN,QAAQ;IACR,WAAW;IACX,eAAe;IACf,MAAM;CACP;AA0BD;;;;AAIG;AACI,eAAe,oBAAoB,CACxC,IAAiB,EACjB,MAA4B,EAC5B,SAAkC,EAAA;AAElC,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE;;;AAItC,IAAA,MAAM,OAAO,CAAC,GAAG,CACf,QAAQ,CAAC,GAAG,CAAC,OAAO,OAAO,KAAI;AAC7B,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,CAAC,IAAI,IAAI;QACxB;QAAE,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,CAAA,4BAAA,EAA+B,OAAO,CAAC,IAAI,CAAA,eAAA,CAAiB,EAAE,KAAK,CAAC;QACpF;IACF,CAAC,CAAC,CACH;;AAGD,IAAA,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB;AAC7C,IAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC9B,QAAA,IAAI;YACF,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,EAAE;AAAE,gBAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAC/D;QAAE,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,CAAA,4BAAA,EAA+B,OAAO,CAAC,IAAI,CAAA,gBAAA,CAAkB,EAAE,KAAK,CAAC;QACrF;IACF;IAEA,MAAM,MAAM,GAAG,YAAY,CAAC;AAC1B,QAAA,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,cAAc;AAC7C,QAAA,QAAQ,EAAE,IAAI;AACd,QAAA,KAAK,EAAE,KAAK;AACZ,QAAA,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;AACnB,QAAA,OAAO,EAAE,CAAC,KAAY,KAAK,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC;AACtE,KAAA,CAAC;AAEF,IAAA,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC;AAC5D,IAAA,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACrB,IAAA,OAAO,MAAM;AACf;AAEA;MACa,cAAc,CAAA;AAWd,IAAA,MAAA;AACQ,IAAA,SAAA;AACA,IAAA,MAAA;IAZX,SAAS,GAAsB,EAAE;IACjC,OAAO,GAAG,KAAK;IACf,OAAO,GAAG,KAAK;IACf,SAAS,GAAG,KAAK;AACR,IAAA,iBAAiB,GAAG,IAAI,GAAG,EAAmB;AAC9C,IAAA,OAAO,GAAG,IAAI,GAAG,EAA+B;;AAExD,IAAA,OAAO;AAEhB,IAAA,WAAA,CACW,MAAqB,EACb,SAAkC,EAClC,MAA4B,EAAA;QAFpC,IAAA,CAAA,MAAM,GAAN,MAAM;QACE,IAAA,CAAA,SAAS,GAAT,SAAS;QACT,IAAA,CAAA,MAAM,GAAN,MAAM;AAEvB,QAAA,MAAM,OAAO,GAAqC;YAChD,MAAM;YACN,MAAM,EAAE,CAAC,EAAc,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAC3C,YAAA,IAAI,EAAE,CAAC,EAAE,KAAK,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,kBAAkB,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YACzD,QAAQ,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC3C,YAAA,YAAY,EAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,oBAAoB,EAAE,CAAC;AAC/D,YAAA,WAAW,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;AAClE,YAAA,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAI;AAC7B,gBAAA,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC;gBACxC,IAAI,CAAC,KAAK,EAAE;YACd,CAAC;AACD,YAAA,eAAe,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,KAC3C,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC;AACrD,YAAA,qBAAqB,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC;AACzF,YAAA,gBAAgB,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC;AACzE,YAAA,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,EAAE;AACvB,YAAA,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,EAAE;AACvB,YAAA,KAAK,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE;AACzB,YAAA,WAAW,EAAE,CAAC,EAAE,EAAE,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC;YAChE,YAAY,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI;AAClD,YAAA,QAAQ,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC;SACzD;;AAED,QAAA,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE;AACtC,YAAA,GAAG,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE;AAC3B,YAAA,UAAU,EAAE,IAAI;AACjB,SAAA,CAAC;AACF,QAAA,IAAI,CAAC,OAAO,GAAG,OAA4B;IAC7C;;AAGA,IAAA,IAAI,CAAC,QAAsC,EAAA;;AAEzC,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAElD,QAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC9B,YAAA,IAAI;gBACF,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC;AAC9C,gBAAA,IAAI,QAAQ;AAAE,oBAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC7C;YAAE,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,CAAA,4BAAA,EAA+B,OAAO,CAAC,IAAI,CAAA,cAAA,CAAgB,EAAE,KAAK,CAAC;YACnF;;YAEA,KAAK,MAAM,YAAY,IAAI,OAAO,CAAC,UAAU,IAAI,EAAE,EAAE;AACnD,gBAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,SAAS,CAAC;YAC3E;QACF;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE;YACxD,IAAI,CAAC,SAAS,CAAC,IAAI,CACjB,IAAI,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,UAAoC,KACzE,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CACrC,CACF;QACH;AAEA,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CACjB,IAAI,CAAC,MAAM,CAAC,eAAe,CACzB,gBAAgB,EAChB,CAAC,OAAgB,KAAI;AACnB,YAAA,IAAI,CAAC,OAAO,GAAG,OAAO;YACtB,IAAI,CAAC,SAAS,EAAE;AAChB,YAAA,OAAO,KAAK;AACd,QAAA,CAAC,EACD,oBAAoB,CACrB,CACF;AACD,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CACjB,IAAI,CAAC,MAAM,CAAC,eAAe,CACzB,gBAAgB,EAChB,CAAC,OAAgB,KAAI;AACnB,YAAA,IAAI,CAAC,OAAO,GAAG,OAAO;YACtB,IAAI,CAAC,SAAS,EAAE;AAChB,YAAA,OAAO,KAAK;AACd,QAAA,CAAC,EACD,oBAAoB,CACrB,CACF;AAED,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CACjB,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,EAAE,WAAW,EAAE,KAAI;AACrD,YAAA,WAAW,CAAC,IAAI,CAAC,MAAK;gBACpB,MAAM,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACtD,gBAAA,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC,cAAc,EAAE;AACxC,gBAAA,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;AACpE,YAAA,CAAC,CAAC;YACF,IAAI,CAAC,SAAS,EAAE;QAClB,CAAC,CAAC,CACH;AAED,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACvC;aAAO;YACL,IAAI,CAAC,SAAS,EAAE;QAClB;IACF;;IAIQ,SAAS,GAAA;QACf,IAAI,IAAI,CAAC,SAAS;YAAE;QACpB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IAC1C;IAEQ,SAAS,GAAA;AACf,QAAA,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgB;QAC7C,IAAI,SAAS,GAAgB,WAAW;QACxC,IAAI,MAAM,GAAG,KAAK;QAClB,IAAI,KAAK,GAAG,IAAI;QAEhB,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,MAAK;AACrC,YAAA,MAAM,IAAI,GAAG,QAAQ,EAAE;YACvB,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,KAAK,CAAC;AAE1C,YAAA,MAAM,SAAS,GAAG,aAAa,EAAE;AACjC,YAAA,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;gBAAE;AAEnC,YAAA,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE;AACnC,gBAAA,IAAI,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC;AAAE,oBAAA,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;YAC5D;YAEA,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE;AAC7C,YAAA,MAAM,OAAO,GACX,UAAU,CAAC,MAAM,EAAE,KAAK,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC,yBAAyB,EAAE;AACtF,YAAA,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC;;YAGrC,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;AAChG,QAAA,CAAC,CAAC;QAEF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;IAClG;AAEQ,IAAA,mBAAmB,CAAC,UAAoC,EAAA;AAC9D,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK;YAAE;AACxB,QAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAU,MAAM,CAAC,IAAI,CAAC,UAAU,CAAc,CAAC;QACvE,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACzC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;gBACtB,OAAO,CAAC,OAAO,EAAE;AACjB,gBAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;YAC1B;QACF;AACA,QAAA,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE;AAC1B,YAAA,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE;AAC3B,YAAA,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAA2C;AACtE,YAAA,MAAM,IAAI,GAAG,IAAI,EAAE,OAAO,IAAI;AAC9B,YAAA,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS;AACrE,YAAA,IAAI,CAAC,SAAS;gBAAE;YAChB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC;AAC/C,YAAA,IAAI,CAAC,MAAM;gBAAE;AACb,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC;AACxD,YAAA,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC;YACnC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC;QAChC;IACF;;IAIQ,KAAK,GAAA;AACX,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAK,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAClD;AAEQ,IAAA,MAAM,CAAC,EAAc,EAAA;QAC3B,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5C;AAEQ,IAAA,YAAY,CAAC,MAAoB,EAAA;QACvC,IAAI,IAAI,CAAC,SAAS;YAAE;QACpB,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACxD,IAAI,CAAC,KAAK,EAAE;IACd;AAEQ,IAAA,QAAQ,CAAC,MAAyB,EAAA;AACxC,QAAA,IAAI,CAAC,MAAM,CAAC,MAAK;AACf,YAAA,MAAM,SAAS,GAAG,aAAa,EAAE;AACjC,YAAA,IAAI,iBAAiB,CAAC,SAAS,CAAC,EAAE;;;AAGhC,gBAAA,cAAc,CAAC,SAAS,EAAE,MAA2B,CAAC;YACxD;AACF,QAAA,CAAC,CAAC;IACJ;IAEQ,gBAAgB,CAAC,QAAuB,EAAE,GAAe,EAAA;QAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/C,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QACrC,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QACzC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QACrC,OAAO,IAAI,CAAC,MAAM,CAAC,eAAe,CAChC,gBAAgB,EAChB,CAAC,KAAoB,KAAI;YACvB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO;AAC1C,YAAA,IACE,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,GAAG;AAC/B,gBAAA,OAAO,KAAK,GAAG;gBACf,SAAS,KAAK,KAAK,CAAC,QAAQ;AAC5B,gBAAA,OAAO,KAAK,KAAK,CAAC,MAAM,EACxB;gBACA,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,GAAG,EAAE;AACL,gBAAA,OAAO,IAAI;YACb;AACA,YAAA,OAAO,KAAK;QACd,CAAC,EACD,qBAAqB,CACtB;IACH;IAEA,IAAI,GAAA;QACF,IAAI,IAAI,CAAC,SAAS;YAAE;QACpB,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,YAAY,EAAE,SAAS,CAAC;QACpD,IAAI,CAAC,KAAK,EAAE;IACd;IAEA,IAAI,GAAA;QACF,IAAI,IAAI,CAAC,SAAS;YAAE;QACpB,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,YAAY,EAAE,SAAS,CAAC;QACpD,IAAI,CAAC,KAAK,EAAE;IACd;IAEA,KAAK,GAAA;QACH,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;IACrB;IAEA,KAAK,GAAA;QACH,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,MAAK;AACf,YAAA,MAAM,IAAI,GAAG,QAAQ,EAAE;YACvB,IAAI,CAAC,KAAK,EAAE;AACZ,YAAA,IAAI,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC;AACrC,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,WAAW,CAAC,QAAiB,EAAA;QAC3B,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC;IACnC;;IAIA,OAAO,GAAA;QACL,IAAI,IAAI,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,MAAK;YACrC,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAClD,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,OAAO,CAAC,IAAY,EAAA;QAClB,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,MAAK;AACf,YAAA,MAAM,IAAI,GAAG,QAAQ,EAAE;YACvB,IAAI,CAAC,KAAK,EAAE;YACZ,IAAI,CAAC,IAAI,EAAE;AACT,gBAAA,IAAI,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC;gBACnC;YACF;;;AAGA,YAAA,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC;YAC9D,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;YACrD,IAAI,CAAC,MAAM,EAAE;YACb,YAAY,CAAC,KAAK,CAAC;AACnB,YAAA,IAAI,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC;AAAE,gBAAA,IAAI,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC;AACvE,QAAA,CAAC,CAAC;IACJ;IAEA,OAAO,GAAA;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE;IAC9C;AAEA,IAAA,OAAO,CAAC,IAA2B,EAAA;QACjC,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,CAAC,KAAK,EAAE;IACd;IAEA,OAAO,GAAA;QACL,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;QACrB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE;AAC3C,YAAA,IAAI;gBACF,OAAO,CAAC,OAAO,EAAE;YACnB;AAAE,YAAA,MAAM;;YAER;QACF;AACA,QAAA,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;QACpB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE;AAC/C,YAAA,IAAI;AACF,gBAAA,QAAQ,EAAE;YACZ;AAAE,YAAA,MAAM;;YAER;QACF;AACA,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE;AACnB,QAAA,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC;IAClC;AACD;AAED;AACA,SAAS,gBAAgB,CAAC,OAAoB,EAAA;IAC5C,MAAM,EAAE,GAAG,OAIV;AACD,IAAA,QAAQ,EAAE,CAAC,OAAO,EAAE;QAClB,KAAK,SAAS,EAAE;AACd,YAAA,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,IAAI;AACzB,YAAA,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,GAAG,GAAG,GAAG,WAAW;QACzE;AACA,QAAA,KAAK,OAAO;AACV,YAAA,OAAO,OAAO;AAChB,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,MAAM;AACf,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,EAAE,CAAC,WAAW,IAAI,KAAK,QAAQ,GAAG,QAAQ,GAAG,QAAQ;AAC9D,QAAA;AACE,YAAA,OAAO,WAAW;;AAExB;AAEA;AACA,SAAS,UAAU,CAAC,IAAoC,EAAA;IACtD,OAAO,CAAC,CAAC,IAAI,IAAK,IAAyC,CAAC,OAAO,EAAE,KAAK,MAAM;AAClF;;;;"}