@inshapardaz/likhari-react 0.1.18 → 0.1.19-dev.182

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 (41) hide show
  1. package/dist/EditorRoot.d.ts.map +1 -1
  2. package/dist/EditorRoot.js +6 -2
  3. package/dist/blocks/PoetryNode.d.ts +70 -0
  4. package/dist/blocks/PoetryNode.d.ts.map +1 -0
  5. package/dist/blocks/PoetryNode.js +198 -0
  6. package/dist/blocks/PoetryResizer.d.ts +11 -0
  7. package/dist/blocks/PoetryResizer.d.ts.map +1 -0
  8. package/dist/blocks/PoetryResizer.js +94 -0
  9. package/dist/blocks/poetryActions.d.ts +117 -0
  10. package/dist/blocks/poetryActions.d.ts.map +1 -0
  11. package/dist/blocks/poetryActions.js +481 -0
  12. package/dist/components/FindReplaceBar.d.ts +13 -0
  13. package/dist/components/FindReplaceBar.d.ts.map +1 -0
  14. package/dist/components/FindReplaceBar.js +72 -0
  15. package/dist/components/Toolbar.d.ts +4 -1
  16. package/dist/components/Toolbar.d.ts.map +1 -1
  17. package/dist/components/Toolbar.js +81 -9
  18. package/dist/find/findReplaceActions.d.ts +23 -0
  19. package/dist/find/findReplaceActions.d.ts.map +1 -0
  20. package/dist/find/findReplaceActions.js +81 -0
  21. package/dist/i18n/strings.d.ts +34 -1
  22. package/dist/i18n/strings.d.ts.map +1 -1
  23. package/dist/i18n/strings.js +99 -3
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1 -0
  27. package/dist/nodes.d.ts.map +1 -1
  28. package/dist/nodes.js +2 -0
  29. package/dist/plugins/PoetryPlugin.d.ts +19 -0
  30. package/dist/plugins/PoetryPlugin.d.ts.map +1 -0
  31. package/dist/plugins/PoetryPlugin.js +54 -0
  32. package/dist/spellcheck/dictionaries/en/LICENSE.txt +347 -0
  33. package/dist/spellcheck/dictionaries/en/index.aff +205 -0
  34. package/dist/spellcheck/dictionaries/en/index.dic +49569 -0
  35. package/dist/spellcheck/spellDictionaries.d.ts +40 -0
  36. package/dist/spellcheck/spellDictionaries.d.ts.map +1 -0
  37. package/dist/spellcheck/spellDictionaries.js +62 -0
  38. package/dist/theme/editor.css +278 -0
  39. package/dist/theme/editorTheme.d.ts.map +1 -1
  40. package/dist/theme/editorTheme.js +1 -0
  41. package/package.json +8 -6
@@ -1 +1 @@
1
- {"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAY1D,OAAO,KAAK,EAA8B,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEjF,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAAwB,KAAK,mBAAmB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAKzH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAKjE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAYhF,OAAO,EAAgC,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMnE,yEAAyE;AACzE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,YAAY,GAAG,KAAK,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,uGAAuG;IACvG,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IACrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IAClD,iBAAiB,IAAI,OAAO,CAAC;IAC7B,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAQD,eAAO,MAAM,UAAU,uGAmXrB,CAAC"}
1
+ {"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAY1D,OAAO,KAAK,EAA8B,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEjF,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAAwB,KAAK,mBAAmB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAKzH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAOjE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAahF,OAAO,EAAgC,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMnE,yEAAyE;AACzE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,YAAY,GAAG,KAAK,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,uGAAuG;IACvG,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IACrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IAClD,iBAAiB,IAAI,OAAO,CAAC;IAC7B,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAQD,eAAO,MAAM,UAAU,uGA2XrB,CAAC"}
@@ -23,7 +23,10 @@ import { LinkPastePlugin } from './plugins/LinkPastePlugin.js';
23
23
  import { PageBreakPlugin } from './plugins/PageBreakPlugin.js';
24
24
  import { LayoutPlugin } from './plugins/LayoutPlugin.js';
25
25
  import { FootnotePlugin } from './plugins/FootnotePlugin.js';
26
+ import { PoetryPlugin } from './plugins/PoetryPlugin.js';
27
+ import { PoetryResizer } from './blocks/PoetryResizer.js';
26
28
  import { DraftRestore } from './components/DraftRestore.js';
29
+ import { FindReplaceBar } from './components/FindReplaceBar.js';
27
30
  import { LeaveDialog } from './components/LeaveDialog.js';
28
31
  import { clearDraft, createDraftId, hasDraftContent, pruneDrafts, writeDraft, } from './persistence/draftStorage.js';
29
32
  import { ImageOptionsContext } from './image/ImageOptionsContext.js';
@@ -65,6 +68,7 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
65
68
  const editorStateRef = useRef(null);
66
69
  const lastSavedJsonRef = useRef(null);
67
70
  const [isDirty, setIsDirty] = useState(false);
71
+ const [findOpen, setFindOpen] = useState(false);
68
72
  const isDirtyRef = useRef(isDirty);
69
73
  isDirtyRef.current = isDirty;
70
74
  const autosaveTimerRef = useRef(null);
@@ -277,9 +281,9 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
277
281
  // rather than colliding on a shared one.
278
282
  const portalTargetId = useId();
279
283
  const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
280
- return (_jsx(EditorThemeProvider, { theme: theme, colorScheme: colorScheme, accentColor: accentColor, scopeElementId: portalTargetId, children: _jsxs("div", { className: "likhari-root", dir: dir, ref: rootElementRef, "data-document-id": documentId, style: { height: typeof height === 'number' ? `${height}px` : height }, children: [_jsx("div", { id: portalTargetId, className: "likhari-portal-target" }), _jsx(PortalTargetContext.Provider, { value: portalTargetSelector, children: _jsxs(UiStringsContext.Provider, { value: strings, children: [_jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
284
+ return (_jsx(EditorThemeProvider, { theme: theme, colorScheme: colorScheme, accentColor: accentColor, scopeElementId: portalTargetId, children: _jsxs("div", { className: "likhari-root", dir: dir, ref: rootElementRef, "data-document-id": documentId, style: { height: typeof height === 'number' ? `${height}px` : height }, children: [_jsx("div", { id: portalTargetId, className: "likhari-portal-target" }), _jsx(PortalTargetContext.Provider, { value: portalTargetSelector, children: _jsxs(UiStringsContext.Provider, { value: strings, children: [_jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, findOpen: findOpen, onToggleFind: () => setFindOpen((v) => !v), isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
281
285
  ? { currentId: draftId, maxBytes: autosaveMaxBytes, adoptOnRestore: !documentId, onRestored: handleDraftRestored }
282
- : undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, "aria-label": strings.editor.contentLabel }), placeholder: _jsx("div", { className: "likhari-placeholder", children: resolvedPlaceholder }), ErrorBoundary: LexicalErrorBoundary }) }), config.history && _jsx(HistoryPlugin, {}), (config.lists.bullet || config.lists.numbered || config.lists.check) && _jsx(ListPlugin, {}), config.lists.check && _jsx(CheckListPlugin, {}), config.links && _jsx(LinkPlugin, {}), config.links && _jsx(LinkPastePlugin, {}), config.blocks.pageBreak && _jsx(PageBreakPlugin, {}), config.columns && _jsx(LayoutPlugin, {}), config.footnotes && _jsx(FootnotePlugin, {}), config.tables && _jsx(TablePlugin, { hasCellMerge: true, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(EditorInstancePlugin, { instanceRef: editorInstanceRef }), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
286
+ : undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsxs("div", { className: "likhari-canvas-frame", children: [config.findReplace && findOpen && _jsx(FindReplaceBar, { strings: strings, dir: dir, onClose: () => setFindOpen(false) }), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, "aria-label": strings.editor.contentLabel }), placeholder: _jsx("div", { className: "likhari-placeholder", children: resolvedPlaceholder }), ErrorBoundary: LexicalErrorBoundary }) })] }), config.history && _jsx(HistoryPlugin, {}), (config.lists.bullet || config.lists.numbered || config.lists.check) && _jsx(ListPlugin, {}), config.lists.check && _jsx(CheckListPlugin, {}), config.links && _jsx(LinkPlugin, {}), config.links && _jsx(LinkPastePlugin, {}), config.blocks.pageBreak && _jsx(PageBreakPlugin, {}), config.columns && _jsx(LayoutPlugin, {}), config.footnotes && _jsx(FootnotePlugin, {}), config.poetry.enabled && _jsx(PoetryPlugin, {}), config.poetry.enabled && _jsx(PoetryResizer, {}), config.tables && _jsx(TablePlugin, { hasCellMerge: true, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(EditorInstancePlugin, { instanceRef: editorInstanceRef }), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
283
287
  handleSave();
284
288
  settleLeave(true);
285
289
  }, onSaveDraft: () => {
@@ -0,0 +1,70 @@
1
+ import { type DOMConversionMap, type DOMExportOutput, type EditorConfig, type LexicalNode, type NodeKey, type SerializedElementNode, type Spread, ElementNode } from 'lexical';
2
+ export type PoetryLayout = 'single' | 'two-column' | 'staggered';
3
+ /** Vertical space between couplets — an ordered scale the menu steps through. */
4
+ export declare const POETRY_SPACINGS: readonly ["compact", "normal", "relaxed", "loose"];
5
+ export type PoetrySpacing = (typeof POETRY_SPACINGS)[number];
6
+ export declare const DEFAULT_POETRY_SPACING: PoetrySpacing;
7
+ /** Horizontal space either side of the divider in two-column layout. */
8
+ export declare const POETRY_GUTTERS: readonly ["compact", "normal", "relaxed", "loose"];
9
+ export type PoetryGutter = (typeof POETRY_GUTTERS)[number];
10
+ export declare const DEFAULT_POETRY_GUTTER: PoetryGutter;
11
+ /** Width of each couplet box in staggered layout, as a share of the block. */
12
+ export declare const POETRY_STAGGERS: readonly ["compact", "normal", "relaxed", "loose"];
13
+ export type PoetryStagger = (typeof POETRY_STAGGERS)[number];
14
+ export declare const DEFAULT_POETRY_STAGGER: PoetryStagger;
15
+ export type SerializedPoetryBlockNode = Spread<{
16
+ layout: PoetryLayout;
17
+ width?: number;
18
+ spacing?: PoetrySpacing;
19
+ gutter?: PoetryGutter;
20
+ stagger?: PoetryStagger;
21
+ }, SerializedElementNode>;
22
+ /**
23
+ * A poetry *section*: one or more couplets (two-line verse units) sharing
24
+ * one layout — single-column stacks each couplet's two misras directly as
25
+ * paragraph children (two per couplet, in order), two-column gives each
26
+ * couplet its own LayoutContainerNode row (built on the columns primitive,
27
+ * §4.9) — see blocks/poetryActions.ts's $getCouplets for how either shape
28
+ * is read, and $setPoetryLayout/$exitPoetryOnEnter for how children are
29
+ * restructured/grown between couplets and layouts. `layout` applies to the
30
+ * whole section, not per couplet, and mutates in place via poetryActions so
31
+ * converting a section between layouts doesn't lose selection/undo
32
+ * coherence. One extensible primitive in place of four fixed templates,
33
+ * per requirements doc §4.11.
34
+ */
35
+ export declare class PoetryBlockNode extends ElementNode {
36
+ __layout: PoetryLayout;
37
+ /** User-chosen width in px (drag-resized), overriding editor.css's default
38
+ * max-width: 70%. Undefined until the user resizes it. */
39
+ __width?: number;
40
+ __spacing: PoetrySpacing;
41
+ __gutter: PoetryGutter;
42
+ __stagger: PoetryStagger;
43
+ constructor(layout?: PoetryLayout, width?: number, spacing?: PoetrySpacing, gutter?: PoetryGutter, stagger?: PoetryStagger, key?: NodeKey);
44
+ static getType(): string;
45
+ static clone(node: PoetryBlockNode): PoetryBlockNode;
46
+ getLayout(): PoetryLayout;
47
+ getWidth(): number | undefined;
48
+ setWidth(width: number | undefined): this;
49
+ /** Attribute-only — restructuring children for a layout change is
50
+ * poetryActions.ts's $setPoetryLayout, not a node method, since it needs
51
+ * $-context tree mutations beyond this node's own state. */
52
+ setLayoutAttribute(layout: PoetryLayout): this;
53
+ getSpacing(): PoetrySpacing;
54
+ setSpacing(spacing: PoetrySpacing): this;
55
+ getGutter(): PoetryGutter;
56
+ setGutter(gutter: PoetryGutter): this;
57
+ getStagger(): PoetryStagger;
58
+ setStagger(stagger: PoetryStagger): this;
59
+ static importJSON(serializedNode: SerializedPoetryBlockNode): PoetryBlockNode;
60
+ exportJSON(): SerializedPoetryBlockNode;
61
+ static importDOM(): DOMConversionMap | null;
62
+ exportDOM(): DOMExportOutput;
63
+ createDOM(config: EditorConfig): HTMLElement;
64
+ updateDOM(prevNode: PoetryBlockNode, dom: HTMLElement, config: EditorConfig): boolean;
65
+ canBeEmpty(): false;
66
+ isShadowRoot(): boolean;
67
+ }
68
+ export declare function $createPoetryBlockNode(layout?: PoetryLayout, width?: number, spacing?: PoetrySpacing, gutter?: PoetryGutter, stagger?: PoetryStagger): PoetryBlockNode;
69
+ export declare function $isPoetryBlockNode(node: LexicalNode | null | undefined): node is PoetryBlockNode;
70
+ //# sourceMappingURL=PoetryNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PoetryNode.d.ts","sourceRoot":"","sources":["../../src/blocks/PoetryNode.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,198 @@
1
+ import { addClassNamesToElement } from '@lexical/utils';
2
+ import { $applyNodeReplacement, ElementNode, } from 'lexical';
3
+ /** Vertical space between couplets — an ordered scale the menu steps through. */
4
+ export const POETRY_SPACINGS = ['compact', 'normal', 'relaxed', 'loose'];
5
+ export const DEFAULT_POETRY_SPACING = 'normal';
6
+ /** Horizontal space either side of the divider in two-column layout. */
7
+ export const POETRY_GUTTERS = ['compact', 'normal', 'relaxed', 'loose'];
8
+ export const DEFAULT_POETRY_GUTTER = 'normal';
9
+ /** Width of each couplet box in staggered layout, as a share of the block. */
10
+ export const POETRY_STAGGERS = ['compact', 'normal', 'relaxed', 'loose'];
11
+ export const DEFAULT_POETRY_STAGGER = 'normal';
12
+ const VALID_LAYOUTS = new Set(['single', 'two-column', 'staggered']);
13
+ const VALID_SPACINGS = new Set(POETRY_SPACINGS);
14
+ const VALID_GUTTERS = new Set(POETRY_GUTTERS);
15
+ const VALID_STAGGERS = new Set(POETRY_STAGGERS);
16
+ /** Poetry is always justified: `text-align-last: justify` stretches a
17
+ * one-line misra across the full column width too, not just wrapped lines,
18
+ * so every line reads edge-to-edge. */
19
+ function applyJustifyStyle(element) {
20
+ element.style.textAlign = 'justify';
21
+ element.style.textAlignLast = 'justify';
22
+ }
23
+ /** A user-dragged width overrides editor.css's default max-width: 70% —
24
+ * clearing the inline style (rather than setting it to that same 70%)
25
+ * lets the CSS default keep tracking the canvas if it's ever resized. */
26
+ function applyWidthStyle(element, width) {
27
+ if (width === undefined)
28
+ element.style.removeProperty('max-width');
29
+ else
30
+ element.style.maxWidth = `${width}px`;
31
+ }
32
+ /**
33
+ * A poetry *section*: one or more couplets (two-line verse units) sharing
34
+ * one layout — single-column stacks each couplet's two misras directly as
35
+ * paragraph children (two per couplet, in order), two-column gives each
36
+ * couplet its own LayoutContainerNode row (built on the columns primitive,
37
+ * §4.9) — see blocks/poetryActions.ts's $getCouplets for how either shape
38
+ * is read, and $setPoetryLayout/$exitPoetryOnEnter for how children are
39
+ * restructured/grown between couplets and layouts. `layout` applies to the
40
+ * whole section, not per couplet, and mutates in place via poetryActions so
41
+ * converting a section between layouts doesn't lose selection/undo
42
+ * coherence. One extensible primitive in place of four fixed templates,
43
+ * per requirements doc §4.11.
44
+ */
45
+ export class PoetryBlockNode extends ElementNode {
46
+ constructor(layout = 'single', width, spacing = DEFAULT_POETRY_SPACING, gutter = DEFAULT_POETRY_GUTTER, stagger = DEFAULT_POETRY_STAGGER, key) {
47
+ super(key);
48
+ this.__layout = layout;
49
+ this.__width = width;
50
+ this.__spacing = spacing;
51
+ this.__gutter = gutter;
52
+ this.__stagger = stagger;
53
+ }
54
+ static getType() {
55
+ return 'poetry-couplet';
56
+ }
57
+ static clone(node) {
58
+ return new PoetryBlockNode(node.__layout, node.__width, node.__spacing, node.__gutter, node.__stagger, node.__key);
59
+ }
60
+ getLayout() {
61
+ return this.getLatest().__layout;
62
+ }
63
+ getWidth() {
64
+ return this.getLatest().__width;
65
+ }
66
+ setWidth(width) {
67
+ const writable = this.getWritable();
68
+ writable.__width = width;
69
+ return writable;
70
+ }
71
+ /** Attribute-only — restructuring children for a layout change is
72
+ * poetryActions.ts's $setPoetryLayout, not a node method, since it needs
73
+ * $-context tree mutations beyond this node's own state. */
74
+ setLayoutAttribute(layout) {
75
+ const writable = this.getWritable();
76
+ writable.__layout = layout;
77
+ return writable;
78
+ }
79
+ getSpacing() {
80
+ return this.getLatest().__spacing;
81
+ }
82
+ setSpacing(spacing) {
83
+ const writable = this.getWritable();
84
+ writable.__spacing = spacing;
85
+ return writable;
86
+ }
87
+ getGutter() {
88
+ return this.getLatest().__gutter;
89
+ }
90
+ setGutter(gutter) {
91
+ const writable = this.getWritable();
92
+ writable.__gutter = gutter;
93
+ return writable;
94
+ }
95
+ getStagger() {
96
+ return this.getLatest().__stagger;
97
+ }
98
+ setStagger(stagger) {
99
+ const writable = this.getWritable();
100
+ writable.__stagger = stagger;
101
+ return writable;
102
+ }
103
+ static importJSON(serializedNode) {
104
+ return $createPoetryBlockNode(serializedNode.layout, serializedNode.width, serializedNode.spacing, serializedNode.gutter, serializedNode.stagger);
105
+ }
106
+ exportJSON() {
107
+ const width = this.getWidth();
108
+ return {
109
+ ...super.exportJSON(),
110
+ type: 'poetry-couplet',
111
+ version: 1,
112
+ layout: this.getLayout(),
113
+ spacing: this.getSpacing(),
114
+ gutter: this.getGutter(),
115
+ stagger: this.getStagger(),
116
+ ...(width !== undefined ? { width } : {}),
117
+ };
118
+ }
119
+ static importDOM() {
120
+ return {
121
+ div: (domNode) => {
122
+ const rawLayout = domNode.getAttribute('data-likhari-poetry-layout');
123
+ if (!rawLayout)
124
+ return null;
125
+ const layout = VALID_LAYOUTS.has(rawLayout) ? rawLayout : 'single';
126
+ const rawWidth = Number(domNode.getAttribute('data-likhari-poetry-width'));
127
+ const width = Number.isFinite(rawWidth) && rawWidth > 0 ? rawWidth : undefined;
128
+ const rawSpacing = domNode.getAttribute('data-likhari-poetry-spacing');
129
+ const spacing = VALID_SPACINGS.has(rawSpacing) ? rawSpacing : DEFAULT_POETRY_SPACING;
130
+ const rawGutter = domNode.getAttribute('data-likhari-poetry-gutter');
131
+ const gutter = VALID_GUTTERS.has(rawGutter) ? rawGutter : DEFAULT_POETRY_GUTTER;
132
+ const rawStagger = domNode.getAttribute('data-likhari-poetry-stagger');
133
+ const stagger = VALID_STAGGERS.has(rawStagger) ? rawStagger : DEFAULT_POETRY_STAGGER;
134
+ return { conversion: () => ({ node: $createPoetryBlockNode(layout, width, spacing, gutter, stagger) }), priority: 2 };
135
+ },
136
+ };
137
+ }
138
+ exportDOM() {
139
+ const element = document.createElement('div');
140
+ element.setAttribute('data-likhari-poetry-layout', this.getLayout());
141
+ element.setAttribute('data-likhari-poetry-spacing', this.getSpacing());
142
+ element.setAttribute('data-likhari-poetry-gutter', this.getGutter());
143
+ element.setAttribute('data-likhari-poetry-stagger', this.getStagger());
144
+ const width = this.getWidth();
145
+ if (width !== undefined)
146
+ element.setAttribute('data-likhari-poetry-width', String(width));
147
+ applyJustifyStyle(element);
148
+ applyWidthStyle(element, width);
149
+ return { element };
150
+ }
151
+ createDOM(config) {
152
+ const element = document.createElement('div');
153
+ const base = config.theme.poetry ?? 'likhari-poetry';
154
+ addClassNamesToElement(element, base, `${base}--${this.__layout}`, `${base}--spacing-${this.__spacing}`, `${base}--gutter-${this.__gutter}`, `${base}--stagger-${this.__stagger}`);
155
+ applyJustifyStyle(element);
156
+ applyWidthStyle(element, this.__width);
157
+ return element;
158
+ }
159
+ // Only ever adds/removes modifier classes, never touches the element's full
160
+ // className — the reconciler separately classList.adds the per-block ltr/rtl
161
+ // theme class (editor.css) onto this same element, and a wholesale className
162
+ // reassignment here would silently wipe it out.
163
+ updateDOM(prevNode, dom, config) {
164
+ const base = config.theme.poetry ?? 'likhari-poetry';
165
+ if (prevNode.__layout !== this.__layout) {
166
+ dom.classList.remove(`${base}--${prevNode.__layout}`);
167
+ dom.classList.add(`${base}--${this.__layout}`);
168
+ }
169
+ if (prevNode.__spacing !== this.__spacing) {
170
+ dom.classList.remove(`${base}--spacing-${prevNode.__spacing}`);
171
+ dom.classList.add(`${base}--spacing-${this.__spacing}`);
172
+ }
173
+ if (prevNode.__gutter !== this.__gutter) {
174
+ dom.classList.remove(`${base}--gutter-${prevNode.__gutter}`);
175
+ dom.classList.add(`${base}--gutter-${this.__gutter}`);
176
+ }
177
+ if (prevNode.__stagger !== this.__stagger) {
178
+ dom.classList.remove(`${base}--stagger-${prevNode.__stagger}`);
179
+ dom.classList.add(`${base}--stagger-${this.__stagger}`);
180
+ }
181
+ if (prevNode.__width !== this.__width) {
182
+ applyWidthStyle(dom, this.__width);
183
+ }
184
+ return false;
185
+ }
186
+ canBeEmpty() {
187
+ return false;
188
+ }
189
+ isShadowRoot() {
190
+ return true;
191
+ }
192
+ }
193
+ export function $createPoetryBlockNode(layout = 'single', width, spacing = DEFAULT_POETRY_SPACING, gutter = DEFAULT_POETRY_GUTTER, stagger = DEFAULT_POETRY_STAGGER) {
194
+ return $applyNodeReplacement(new PoetryBlockNode(layout, width, spacing, gutter, stagger));
195
+ }
196
+ export function $isPoetryBlockNode(node) {
197
+ return node instanceof PoetryBlockNode;
198
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A floating drag handle over the currently-active poetry couplet's
3
+ * inline-end edge, letting the user resize how wide the block reads on the
4
+ * page — "size it according to the length of the couplet" — rather than
5
+ * being stuck with editor.css's default max-width: 70%. Rendered as a
6
+ * portal into the editor's own portal-target element, never as a child of
7
+ * the couplet's own DOM, so it can't interfere with Lexical's
8
+ * reconciliation of the couplet's real (editable) children.
9
+ */
10
+ export declare function PoetryResizer(): import("react").JSX.Element | null;
11
+ //# sourceMappingURL=PoetryResizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PoetryResizer.d.ts","sourceRoot":"","sources":["../../src/blocks/PoetryResizer.tsx"],"names":[],"mappings":"AAuBA;;;;;;;;GAQG;AACH,wBAAgB,aAAa,uCAqF5B"}
@@ -0,0 +1,94 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
5
+ import { $getNodeByKey } from 'lexical';
6
+ import { usePortalTarget } from '../PortalTargetContext.js';
7
+ import { $getPoetryBlockFromSelection } from './poetryActions.js';
8
+ import { $isPoetryBlockNode } from './PoetryNode.js';
9
+ const MIN_WIDTH_PX = 160;
10
+ function measure(el) {
11
+ const box = el.getBoundingClientRect();
12
+ return { top: box.top, left: box.left, width: box.width, height: box.height, rtl: getComputedStyle(el).direction === 'rtl' };
13
+ }
14
+ /**
15
+ * A floating drag handle over the currently-active poetry couplet's
16
+ * inline-end edge, letting the user resize how wide the block reads on the
17
+ * page — "size it according to the length of the couplet" — rather than
18
+ * being stuck with editor.css's default max-width: 70%. Rendered as a
19
+ * portal into the editor's own portal-target element, never as a child of
20
+ * the couplet's own DOM, so it can't interfere with Lexical's
21
+ * reconciliation of the couplet's real (editable) children.
22
+ */
23
+ export function PoetryResizer() {
24
+ const [editor] = useLexicalComposerContext();
25
+ const portalSelector = usePortalTarget();
26
+ const [activeKey, setActiveKey] = useState(null);
27
+ const [box, setBox] = useState(null);
28
+ const dragStart = useRef(null);
29
+ useEffect(() => {
30
+ const recompute = () => {
31
+ if (dragStart.current)
32
+ return; // the pointermove handler owns `box` mid-drag
33
+ editor.getEditorState().read(() => {
34
+ const couplet = $getPoetryBlockFromSelection();
35
+ const el = couplet ? editor.getElementByKey(couplet.getKey()) : null;
36
+ if (!couplet || !el) {
37
+ setActiveKey(null);
38
+ setBox(null);
39
+ return;
40
+ }
41
+ setActiveKey(couplet.getKey());
42
+ setBox(measure(el));
43
+ });
44
+ };
45
+ recompute();
46
+ const unregister = editor.registerUpdateListener(recompute);
47
+ window.addEventListener('resize', recompute);
48
+ window.addEventListener('scroll', recompute, true);
49
+ return () => {
50
+ unregister();
51
+ window.removeEventListener('resize', recompute);
52
+ window.removeEventListener('scroll', recompute, true);
53
+ };
54
+ }, [editor]);
55
+ if (!box || !activeKey)
56
+ return null;
57
+ const onPointerDown = (event) => {
58
+ event.preventDefault();
59
+ event.currentTarget.setPointerCapture(event.pointerId);
60
+ dragStart.current = { x: event.clientX, width: box.width, rtl: box.rtl };
61
+ };
62
+ const onPointerMove = (event) => {
63
+ const start = dragStart.current;
64
+ const el = editor.getElementByKey(activeKey);
65
+ if (!start || !el)
66
+ return;
67
+ const delta = event.clientX - start.x;
68
+ const signedDelta = start.rtl ? -delta : delta;
69
+ const canvasMax = editor.getRootElement()?.clientWidth ?? start.width + signedDelta;
70
+ const width = Math.round(Math.min(Math.max(start.width + signedDelta, MIN_WIDTH_PX), canvasMax));
71
+ // Live visual feedback: the couplet is centered (margin: auto), so
72
+ // resizing it moves both edges — re-measure after mutating rather than
73
+ // computing the new position from the drag delta alone.
74
+ el.style.maxWidth = `${width}px`;
75
+ setBox(measure(el));
76
+ };
77
+ const onPointerUp = () => {
78
+ const start = dragStart.current;
79
+ dragStart.current = null;
80
+ const el = editor.getElementByKey(activeKey);
81
+ const width = el ? Math.round(el.getBoundingClientRect().width) : null;
82
+ if (start && width !== null) {
83
+ editor.update(() => {
84
+ const node = $getNodeByKey(activeKey);
85
+ if ($isPoetryBlockNode(node))
86
+ node.setWidth(width);
87
+ });
88
+ }
89
+ };
90
+ const handleX = box.rtl ? box.left : box.left + box.width;
91
+ const handle = (_jsx("div", { className: "likhari-poetry-resize-handle", style: { position: 'fixed', top: box.top, left: handleX, height: box.height }, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, role: "separator", "aria-orientation": "vertical" }));
92
+ const portalRoot = portalSelector ? document.querySelector(portalSelector) : null;
93
+ return portalRoot ? createPortal(handle, portalRoot) : handle;
94
+ }
@@ -0,0 +1,117 @@
1
+ import { type ParagraphNode } from 'lexical';
2
+ import { type PoetryBlockNode, type PoetryLayout } from './PoetryNode.js';
3
+ /** One couplet's two misra paragraphs, in order. */
4
+ export type Couplet = [ParagraphNode, ParagraphNode];
5
+ /**
6
+ * A poetry block is a *section* of one or more couplets sharing one layout
7
+ * (single-column stacks each couplet's two misras directly as paragraph
8
+ * children, two deep per couplet; two-column gives each couplet its own
9
+ * LayoutContainerNode row). This walks that structure and returns each
10
+ * couplet as a pair, in document order — the one place that knows how to
11
+ * read either shape, so nothing else needs to.
12
+ */
13
+ export declare function $getCouplets(node: PoetryBlockNode): Couplet[];
14
+ /** Every misra in the block, flattened across all its couplets — for
15
+ * operations (like $setPoetryLayout) that don't care about couplet
16
+ * boundaries, just the full set of lines. */
17
+ export declare function $getMisraParagraphs(node: PoetryBlockNode): ParagraphNode[];
18
+ /** The PoetryBlockNode the current selection is inside, or null. */
19
+ export declare function $getPoetryBlockFromSelection(): PoetryBlockNode | null;
20
+ /**
21
+ * The explicit "Insert couplet above/below" menu actions — mirrors the
22
+ * table menu's "Insert row before/after". Targets the couplet the caret is
23
+ * currently in, falling back to the block's last couplet (so the toolbar's
24
+ * always-available insert button has somewhere sensible to act on even
25
+ * without a precise caret position).
26
+ */
27
+ export declare function $insertCoupletRelativeToSelection(position: 'before' | 'after'): boolean;
28
+ /**
29
+ * Converts every couplet in the block between single-column (two stacked
30
+ * misras) and two-column (built on the columns primitive, §4.9) in place —
31
+ * pulls each couplet's two misra paragraphs out of whichever shape
32
+ * currently holds them and rebuilds the other shape around the same
33
+ * paragraph nodes, preserving couplet order, so content, selection and
34
+ * undo history all survive the conversion.
35
+ */
36
+ export declare function $setPoetryLayout(node: PoetryBlockNode, layout: PoetryLayout): void;
37
+ /** A block at the very end of the document would otherwise leave no
38
+ * editable block to click or arrow down into — appends one empty paragraph
39
+ * if the block doesn't already have a next sibling. Idempotent: once a
40
+ * sibling exists (that paragraph, or anything else), this is a no-op, so
41
+ * it's safe to call from both the insert command and a node transform that
42
+ * keeps the invariant even after later edits (e.g. deleting the trailing
43
+ * paragraph, or JSON content loaded without one). */
44
+ export declare function $ensureTrailingParagraph(node: PoetryBlockNode): void;
45
+ /**
46
+ * Inserts a poetry couplet at the caret. If the caret is already inside a
47
+ * poetry block, inserts a new couplet right after the one the caret is in
48
+ * (same as the "Insert couplet below" menu action — table-row-insert
49
+ * semantics, in its existing layout: "one poetry block can contain one or
50
+ * more couplets, in one or two column layout", so a block's layout is
51
+ * fixed once it has couplets, not chosen per couplet) and focuses its first
52
+ * misra. Otherwise creates a new block (in `layout`) with one
53
+ * couplet, after the selection's top-level element.
54
+ */
55
+ export declare function $insertPoetryCouplet(layout: PoetryLayout): boolean;
56
+ /** Removes the couplet the selection is inside. If it's the block's only
57
+ * couplet, removes the whole block (an empty poetry section serves no
58
+ * purpose) — the explicit, always-available counterpart to
59
+ * $deletePoetryOnBackspace's empty-couplet shortcut (mirrors the table
60
+ * menu's own "Delete table" action). */
61
+ export declare function $deletePoetryCouplet(): boolean;
62
+ /**
63
+ * Backspace at the start of a misra never merges it into its neighbour: the
64
+ * block's lines are paired into couplets, so merging one line away would
65
+ * shift every couplet after it (and take the previous couplet's last line
66
+ * with it). Instead, Backspace at the start of an empty couplet removes that
67
+ * couplet, and at the start of any other line it moves the caret to the end
68
+ * of the previous line. Other caret positions (deleting within text) fall
69
+ * through to normal handling.
70
+ */
71
+ export declare function $deletePoetryOnBackspace(): boolean;
72
+ /**
73
+ * Forward Delete at the end of a misra never merges the next line into it, for
74
+ * the same reason as $deletePoetryOnBackspace: the caret moves to the start of
75
+ * the next line instead. Other caret positions fall through to normal handling.
76
+ */
77
+ export declare function $deletePoetryForward(): boolean;
78
+ /**
79
+ * Enter inside a poetry block never grows a couplet past its fixed two
80
+ * misras. The block's *last* couplet being completely empty is always the
81
+ * exit trigger, regardless of which of its two (both-empty) misras the
82
+ * caret happens to be on — pressing Enter once on a non-empty last couplet
83
+ * appends a fresh empty one to continue into ("new couplet after last"),
84
+ * and pressing Enter again on that still-untouched couplet exits ("double
85
+ * enter to exit the block"): the same empty-item convention most editors
86
+ * use for lists. Outside that case: pressed in a couplet's first misra,
87
+ * Enter moves the caret to the second (already there; nothing inserted —
88
+ * this is what stops ParagraphNode's default insertNewAfter from growing
89
+ * the couplet, which would otherwise insert the new paragraph as a sibling
90
+ * of wherever the caret was, i.e. still inside the couplet); pressed in
91
+ * the last misra of a couplet that isn't the block's last, it moves to the
92
+ * next couplet's first misra.
93
+ */
94
+ export declare function $exitPoetryOnEnter(): boolean;
95
+ /** Steps the caret's poetry block one notch looser (+1) or tighter (-1) on
96
+ * the couplet-spacing scale; clamps at either end. */
97
+ export declare function $adjustPoetrySpacing(step: 1 | -1): boolean;
98
+ /** Steps the caret's two-column gutter one notch wider (+1) or narrower (-1);
99
+ * clamps at either end. */
100
+ export declare function $adjustPoetryGutter(step: 1 | -1): boolean;
101
+ /** Steps the caret's staggered couplet width one notch narrower (-1) or wider
102
+ * (+1); clamps at either end. */
103
+ export declare function $adjustPoetryStagger(step: 1 | -1): boolean;
104
+ /** Whether the couplet the caret is in is centered, or null outside a
105
+ * two-column poetry block (centering only applies there). */
106
+ export declare function $getCoupletCenteredFromSelection(): boolean | null;
107
+ /** Centers (or un-centers) the caret's couplet within a two-column block by
108
+ * rebuilding its row around the same two misra paragraphs. */
109
+ export declare function $setCoupletCentered(centered: boolean): boolean;
110
+ /** Removes the whole poetry block the caret is in, including every couplet. */
111
+ export declare function $deletePoetryBlock(): boolean;
112
+ /** Single-column blocks pair their paragraphs into couplets, so a line left
113
+ * without a partner (from pasted or imported content) would be invisible to
114
+ * the couplet logic. Give it an empty partner instead, so every line belongs
115
+ * to a couplet and can be deleted like any other. */
116
+ export declare function $completeSingleCoupletBlock(node: PoetryBlockNode): void;
117
+ //# sourceMappingURL=poetryActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poetryActions.d.ts","sourceRoot":"","sources":["../../src/blocks/poetryActions.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,oDAAoD;AACpD,MAAM,MAAM,OAAO,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAErD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,EAAE,CAqB7D;AAED;;6CAE6C;AAC7C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,EAAE,CAE1E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,eAAe,GAAG,IAAI,CAKrE;AA0DD;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAevF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAmBlF;AAED;;;;;;qDAMqD;AACrD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAEpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAiBlE;AAED;;;;wCAIwC;AACxC,wBAAgB,oBAAoB,IAAI,OAAO,CAwB9C;AAUD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAsClD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAkB9C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAgD5C;AAED;sDACsD;AACtD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAO1D;AAED;2BAC2B;AAC3B,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAOzD;AAED;iCACiC;AACjC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAO1D;AAYD;6DAC6D;AAC7D,wBAAgB,gCAAgC,IAAI,OAAO,GAAG,IAAI,CAUjE;AAED;8DAC8D;AAC9D,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAuB9D;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,OAAO,CAK5C;AAED;;;qDAGqD;AACrD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAGvE"}