@inshapardaz/likhari-react 0.1.17 → 0.1.18-dev.126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EditorRoot.d.ts.map +1 -1
- package/dist/EditorRoot.js +2 -1
- package/dist/blocks/PoetryNode.d.ts +42 -0
- package/dist/blocks/PoetryNode.d.ts.map +1 -0
- package/dist/blocks/PoetryNode.js +106 -0
- package/dist/blocks/poetryActions.d.ts +19 -0
- package/dist/blocks/poetryActions.d.ts.map +1 -0
- package/dist/blocks/poetryActions.js +76 -0
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +40 -8
- package/dist/i18n/strings.d.ts +8 -1
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +21 -3
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +2 -0
- package/dist/plugins/PoetryPlugin.d.ts +14 -0
- package/dist/plugins/PoetryPlugin.d.ts.map +1 -0
- package/dist/plugins/PoetryPlugin.js +27 -0
- package/dist/theme/editor.css +28 -0
- package/dist/theme/editorTheme.d.ts.map +1 -1
- package/dist/theme/editorTheme.js +1 -0
- package/package.json +1 -1
package/dist/EditorRoot.d.ts.map
CHANGED
|
@@ -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;
|
|
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;AAMjE,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,uGAoXrB,CAAC"}
|
package/dist/EditorRoot.js
CHANGED
|
@@ -23,6 +23,7 @@ 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';
|
|
26
27
|
import { DraftRestore } from './components/DraftRestore.js';
|
|
27
28
|
import { LeaveDialog } from './components/LeaveDialog.js';
|
|
28
29
|
import { clearDraft, createDraftId, hasDraftContent, pruneDrafts, writeDraft, } from './persistence/draftStorage.js';
|
|
@@ -279,7 +280,7 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
279
280
|
const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
|
|
280
281
|
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
|
|
281
282
|
? { 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: () => {
|
|
283
|
+
: 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.poetry.enabled && _jsx(PoetryPlugin, {}), 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
284
|
handleSave();
|
|
284
285
|
settleLeave(true);
|
|
285
286
|
}, onSaveDraft: () => {
|
|
@@ -0,0 +1,42 @@
|
|
|
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';
|
|
3
|
+
export type PoetryAlign = 'justify' | 'left' | 'right' | 'start';
|
|
4
|
+
export type SerializedPoetryBlockNode = Spread<{
|
|
5
|
+
layout: PoetryLayout;
|
|
6
|
+
align: PoetryAlign;
|
|
7
|
+
}, SerializedElementNode>;
|
|
8
|
+
/**
|
|
9
|
+
* A couplet (two-line verse unit), the one extensible primitive requirements
|
|
10
|
+
* doc §4.11 recommends in place of four fixed templates. `layout` picks
|
|
11
|
+
* single-column (two stacked misras) vs. two-column (built on the columns
|
|
12
|
+
* primitive, §4.9 — see blocks/poetryActions.ts for how children are
|
|
13
|
+
* restructured between the two); `align` is a literal per-instance override,
|
|
14
|
+
* independent of the document's own alignment setting (architecture doc
|
|
15
|
+
* §3.1). Both mutate in place via poetryActions so converting a couplet
|
|
16
|
+
* between layouts doesn't lose selection/undo coherence.
|
|
17
|
+
*/
|
|
18
|
+
export declare class PoetryBlockNode extends ElementNode {
|
|
19
|
+
__layout: PoetryLayout;
|
|
20
|
+
__align: PoetryAlign;
|
|
21
|
+
constructor(layout?: PoetryLayout, align?: PoetryAlign, key?: NodeKey);
|
|
22
|
+
static getType(): string;
|
|
23
|
+
static clone(node: PoetryBlockNode): PoetryBlockNode;
|
|
24
|
+
getLayout(): PoetryLayout;
|
|
25
|
+
getAlign(): PoetryAlign;
|
|
26
|
+
/** Attribute-only — restructuring children for a layout change is
|
|
27
|
+
* poetryActions.ts's $setPoetryLayout, not a node method, since it needs
|
|
28
|
+
* $-context tree mutations beyond this node's own state. */
|
|
29
|
+
setLayoutAttribute(layout: PoetryLayout): this;
|
|
30
|
+
setAlign(align: PoetryAlign): this;
|
|
31
|
+
static importJSON(serializedNode: SerializedPoetryBlockNode): PoetryBlockNode;
|
|
32
|
+
exportJSON(): SerializedPoetryBlockNode;
|
|
33
|
+
static importDOM(): DOMConversionMap | null;
|
|
34
|
+
exportDOM(): DOMExportOutput;
|
|
35
|
+
createDOM(config: EditorConfig): HTMLElement;
|
|
36
|
+
updateDOM(prevNode: PoetryBlockNode, dom: HTMLElement, config: EditorConfig): boolean;
|
|
37
|
+
canBeEmpty(): false;
|
|
38
|
+
isShadowRoot(): boolean;
|
|
39
|
+
}
|
|
40
|
+
export declare function $createPoetryBlockNode(layout?: PoetryLayout, align?: PoetryAlign): PoetryBlockNode;
|
|
41
|
+
export declare function $isPoetryBlockNode(node: LexicalNode | null | undefined): node is PoetryBlockNode;
|
|
42
|
+
//# sourceMappingURL=PoetryNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PoetryNode.d.ts","sourceRoot":"","sources":["../../src/blocks/PoetryNode.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,qBAAqB,EAC1B,KAAK,MAAM,EACX,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAC;AACnD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAKjE,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,EAAE,qBAAqB,CAAC,CAAC;AAEpH;;;;;;;;;GASG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;gBAET,MAAM,GAAE,YAAuB,EAAE,KAAK,GAAE,WAAuB,EAAE,GAAG,CAAC,EAAE,OAAO;IAM1F,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,GAAG,eAAe;IAIpD,SAAS,IAAI,YAAY;IAIzB,QAAQ,IAAI,WAAW;IAIvB;;gEAE4D;IAC5D,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAM9C,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAMlC,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,yBAAyB,GAAG,eAAe;IAI7E,UAAU,IAAI,yBAAyB;IAIvC,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAa3C,SAAS,IAAI,eAAe;IAQ5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAY5C,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO;IAYrF,UAAU,IAAI,KAAK;IAInB,YAAY,IAAI,OAAO;CAGxB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,GAAE,YAAuB,EAAE,KAAK,GAAE,WAAuB,GAAG,eAAe,CAEvH;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,eAAe,CAEhG"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { addClassNamesToElement } from '@lexical/utils';
|
|
2
|
+
import { $applyNodeReplacement, ElementNode, } from 'lexical';
|
|
3
|
+
const VALID_LAYOUTS = new Set(['single', 'two-column']);
|
|
4
|
+
const VALID_ALIGNS = new Set(['justify', 'left', 'right', 'start']);
|
|
5
|
+
/**
|
|
6
|
+
* A couplet (two-line verse unit), the one extensible primitive requirements
|
|
7
|
+
* doc §4.11 recommends in place of four fixed templates. `layout` picks
|
|
8
|
+
* single-column (two stacked misras) vs. two-column (built on the columns
|
|
9
|
+
* primitive, §4.9 — see blocks/poetryActions.ts for how children are
|
|
10
|
+
* restructured between the two); `align` is a literal per-instance override,
|
|
11
|
+
* independent of the document's own alignment setting (architecture doc
|
|
12
|
+
* §3.1). Both mutate in place via poetryActions so converting a couplet
|
|
13
|
+
* between layouts doesn't lose selection/undo coherence.
|
|
14
|
+
*/
|
|
15
|
+
export class PoetryBlockNode extends ElementNode {
|
|
16
|
+
constructor(layout = 'single', align = 'justify', key) {
|
|
17
|
+
super(key);
|
|
18
|
+
this.__layout = layout;
|
|
19
|
+
this.__align = align;
|
|
20
|
+
}
|
|
21
|
+
static getType() {
|
|
22
|
+
return 'poetry-couplet';
|
|
23
|
+
}
|
|
24
|
+
static clone(node) {
|
|
25
|
+
return new PoetryBlockNode(node.__layout, node.__align, node.__key);
|
|
26
|
+
}
|
|
27
|
+
getLayout() {
|
|
28
|
+
return this.getLatest().__layout;
|
|
29
|
+
}
|
|
30
|
+
getAlign() {
|
|
31
|
+
return this.getLatest().__align;
|
|
32
|
+
}
|
|
33
|
+
/** Attribute-only — restructuring children for a layout change is
|
|
34
|
+
* poetryActions.ts's $setPoetryLayout, not a node method, since it needs
|
|
35
|
+
* $-context tree mutations beyond this node's own state. */
|
|
36
|
+
setLayoutAttribute(layout) {
|
|
37
|
+
const writable = this.getWritable();
|
|
38
|
+
writable.__layout = layout;
|
|
39
|
+
return writable;
|
|
40
|
+
}
|
|
41
|
+
setAlign(align) {
|
|
42
|
+
const writable = this.getWritable();
|
|
43
|
+
writable.__align = align;
|
|
44
|
+
return writable;
|
|
45
|
+
}
|
|
46
|
+
static importJSON(serializedNode) {
|
|
47
|
+
return $createPoetryBlockNode(serializedNode.layout, serializedNode.align);
|
|
48
|
+
}
|
|
49
|
+
exportJSON() {
|
|
50
|
+
return { ...super.exportJSON(), type: 'poetry-couplet', version: 1, layout: this.getLayout(), align: this.getAlign() };
|
|
51
|
+
}
|
|
52
|
+
static importDOM() {
|
|
53
|
+
return {
|
|
54
|
+
div: (domNode) => {
|
|
55
|
+
const rawLayout = domNode.getAttribute('data-likhari-poetry-layout');
|
|
56
|
+
if (!rawLayout)
|
|
57
|
+
return null;
|
|
58
|
+
const layout = VALID_LAYOUTS.has(rawLayout) ? rawLayout : 'single';
|
|
59
|
+
const rawAlign = domNode.getAttribute('data-likhari-poetry-align') ?? 'justify';
|
|
60
|
+
const align = VALID_ALIGNS.has(rawAlign) ? rawAlign : 'justify';
|
|
61
|
+
return { conversion: () => ({ node: $createPoetryBlockNode(layout, align) }), priority: 2 };
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
exportDOM() {
|
|
66
|
+
const element = document.createElement('div');
|
|
67
|
+
element.setAttribute('data-likhari-poetry-layout', this.getLayout());
|
|
68
|
+
element.setAttribute('data-likhari-poetry-align', this.getAlign());
|
|
69
|
+
element.style.textAlign = this.getAlign();
|
|
70
|
+
return { element };
|
|
71
|
+
}
|
|
72
|
+
createDOM(config) {
|
|
73
|
+
const element = document.createElement('div');
|
|
74
|
+
const base = config.theme.poetry ?? 'likhari-poetry';
|
|
75
|
+
addClassNamesToElement(element, base, `${base}--${this.__layout}`);
|
|
76
|
+
element.style.textAlign = this.__align;
|
|
77
|
+
return element;
|
|
78
|
+
}
|
|
79
|
+
// Only ever adds/removes the layout modifier class, never touches the
|
|
80
|
+
// element's full className — the reconciler separately classList.adds the
|
|
81
|
+
// per-block ltr/rtl theme class (editor.css) onto this same element, and
|
|
82
|
+
// a wholesale className reassignment here would silently wipe it out.
|
|
83
|
+
updateDOM(prevNode, dom, config) {
|
|
84
|
+
if (prevNode.__layout !== this.__layout) {
|
|
85
|
+
const base = config.theme.poetry ?? 'likhari-poetry';
|
|
86
|
+
dom.classList.remove(`${base}--${prevNode.__layout}`);
|
|
87
|
+
dom.classList.add(`${base}--${this.__layout}`);
|
|
88
|
+
}
|
|
89
|
+
if (prevNode.__align !== this.__align) {
|
|
90
|
+
dom.style.textAlign = this.__align;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
canBeEmpty() {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
isShadowRoot() {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function $createPoetryBlockNode(layout = 'single', align = 'justify') {
|
|
102
|
+
return $applyNodeReplacement(new PoetryBlockNode(layout, align));
|
|
103
|
+
}
|
|
104
|
+
export function $isPoetryBlockNode(node) {
|
|
105
|
+
return node instanceof PoetryBlockNode;
|
|
106
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ParagraphNode } from 'lexical';
|
|
2
|
+
import { type PoetryAlign, type PoetryLayout, type PoetryBlockNode } from './PoetryNode.js';
|
|
3
|
+
/** The couplet's two misra paragraphs, in document order, regardless of
|
|
4
|
+
* which layout currently holds them. */
|
|
5
|
+
export declare function $getMisraParagraphs(node: PoetryBlockNode): ParagraphNode[];
|
|
6
|
+
/** The PoetryBlockNode the current selection is inside, or null. */
|
|
7
|
+
export declare function $getPoetryBlockFromSelection(): PoetryBlockNode | null;
|
|
8
|
+
/**
|
|
9
|
+
* Converts a couplet between single-column (two stacked misras) and
|
|
10
|
+
* two-column (built on the columns primitive, §4.9) in place — pulls the
|
|
11
|
+
* two misra paragraphs out of whichever shape currently holds them and
|
|
12
|
+
* rebuilds the other shape around the same paragraph nodes, so content,
|
|
13
|
+
* selection and undo history all survive the conversion.
|
|
14
|
+
*/
|
|
15
|
+
export declare function $setPoetryLayout(node: PoetryBlockNode, layout: PoetryLayout): void;
|
|
16
|
+
/** Inserts a new two-misra couplet after the selection's top-level block,
|
|
17
|
+
* in `layout`/`align`, and focuses its first misra. */
|
|
18
|
+
export declare function $insertPoetryCouplet(layout: PoetryLayout, align: PoetryAlign): boolean;
|
|
19
|
+
//# 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,EAA4E,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvH,OAAO,EAA8C,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAErI;wCACwC;AACxC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,EAAE,CAW1E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,eAAe,GAAG,IAAI,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAclF;AAED;uDACuD;AACvD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAmBtF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { $findMatchingParent } from '@lexical/utils';
|
|
2
|
+
import { $createParagraphNode, $getSelection, $isParagraphNode, $isRangeSelection } from 'lexical';
|
|
3
|
+
import { $createLayoutContainerNode, $createLayoutItemNode, $isLayoutContainerNode, $isLayoutItemNode } from './LayoutNode.js';
|
|
4
|
+
import { $createPoetryBlockNode, $isPoetryBlockNode } from './PoetryNode.js';
|
|
5
|
+
/** The couplet's two misra paragraphs, in document order, regardless of
|
|
6
|
+
* which layout currently holds them. */
|
|
7
|
+
export function $getMisraParagraphs(node) {
|
|
8
|
+
if (node.getLayout() === 'single') {
|
|
9
|
+
return node.getChildren().filter($isParagraphNode);
|
|
10
|
+
}
|
|
11
|
+
const container = node.getChildren().find($isLayoutContainerNode);
|
|
12
|
+
if (!container)
|
|
13
|
+
return [];
|
|
14
|
+
return container
|
|
15
|
+
.getChildren()
|
|
16
|
+
.filter($isLayoutItemNode)
|
|
17
|
+
.map((item) => item.getFirstChild())
|
|
18
|
+
.filter($isParagraphNode);
|
|
19
|
+
}
|
|
20
|
+
/** The PoetryBlockNode the current selection is inside, or null. */
|
|
21
|
+
export function $getPoetryBlockFromSelection() {
|
|
22
|
+
const selection = $getSelection();
|
|
23
|
+
if (!$isRangeSelection(selection))
|
|
24
|
+
return null;
|
|
25
|
+
const match = $findMatchingParent(selection.anchor.getNode(), $isPoetryBlockNode);
|
|
26
|
+
return match ?? null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Converts a couplet between single-column (two stacked misras) and
|
|
30
|
+
* two-column (built on the columns primitive, §4.9) in place — pulls the
|
|
31
|
+
* two misra paragraphs out of whichever shape currently holds them and
|
|
32
|
+
* rebuilds the other shape around the same paragraph nodes, so content,
|
|
33
|
+
* selection and undo history all survive the conversion.
|
|
34
|
+
*/
|
|
35
|
+
export function $setPoetryLayout(node, layout) {
|
|
36
|
+
if (node.getLayout() === layout)
|
|
37
|
+
return;
|
|
38
|
+
const misras = $getMisraParagraphs(node);
|
|
39
|
+
for (const misra of misras)
|
|
40
|
+
misra.remove();
|
|
41
|
+
for (const leftover of node.getChildren())
|
|
42
|
+
leftover.remove();
|
|
43
|
+
if (layout === 'single') {
|
|
44
|
+
for (const misra of misras)
|
|
45
|
+
node.append(misra);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const container = $createLayoutContainerNode('repeat(2, 1fr)');
|
|
49
|
+
for (const misra of misras)
|
|
50
|
+
container.append($createLayoutItemNode().append(misra));
|
|
51
|
+
node.append(container);
|
|
52
|
+
}
|
|
53
|
+
node.setLayoutAttribute(layout);
|
|
54
|
+
}
|
|
55
|
+
/** Inserts a new two-misra couplet after the selection's top-level block,
|
|
56
|
+
* in `layout`/`align`, and focuses its first misra. */
|
|
57
|
+
export function $insertPoetryCouplet(layout, align) {
|
|
58
|
+
const selection = $getSelection();
|
|
59
|
+
if (!$isRangeSelection(selection))
|
|
60
|
+
return false;
|
|
61
|
+
const anchorTopLevel = selection.anchor.getNode().getTopLevelElementOrThrow();
|
|
62
|
+
const node = $createPoetryBlockNode(layout, align);
|
|
63
|
+
const misraA = $createParagraphNode();
|
|
64
|
+
const misraB = $createParagraphNode();
|
|
65
|
+
if (layout === 'single') {
|
|
66
|
+
node.append(misraA, misraB);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const container = $createLayoutContainerNode('repeat(2, 1fr)');
|
|
70
|
+
container.append($createLayoutItemNode().append(misraA), $createLayoutItemNode().append(misraB));
|
|
71
|
+
node.append(container);
|
|
72
|
+
}
|
|
73
|
+
anchorTopLevel.insertAfter(node);
|
|
74
|
+
misraA.selectStart();
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AAiEA,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAA6D,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAItG,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,iBAAiB,CAAC;AAwevD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,wFAAwF;IACxF,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,MAAM,EAAE,EAAE,YAAY,+BAugCxJ"}
|
|
@@ -14,6 +14,8 @@ import { $createImageNode } from '../image/ImageNode.js';
|
|
|
14
14
|
import { INSERT_PAGE_BREAK_COMMAND } from '../blocks/PageBreakNode.js';
|
|
15
15
|
import { INSERT_LAYOUT_COMMAND } from '../blocks/LayoutNode.js';
|
|
16
16
|
import { INSERT_FOOTNOTE_COMMAND } from '../blocks/FootnoteNode.js';
|
|
17
|
+
import { $getPoetryBlockFromSelection, $setPoetryLayout } from '../blocks/poetryActions.js';
|
|
18
|
+
import { INSERT_POETRY_COUPLET_COMMAND } from '../plugins/PoetryPlugin.js';
|
|
17
19
|
import { TableDialog } from './TableDialog.js';
|
|
18
20
|
import { LayoutDialog } from './LayoutDialog.js';
|
|
19
21
|
import { $getTableCellNodeFromLexicalNode, $isTableSelection, INSERT_TABLE_COMMAND } from '@lexical/table';
|
|
@@ -26,7 +28,7 @@ import { CANVAS_FONT_DEFAULTS, DEFAULT_FONT_OPTIONS, FONT_SIZES_PX } from '../fo
|
|
|
26
28
|
import { setStyleProperty } from '../utils/style.js';
|
|
27
29
|
import { useStrings } from '../i18n/useStrings.js';
|
|
28
30
|
import { usePortalTarget } from '../PortalTargetContext.js';
|
|
29
|
-
import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconBold, IconClearFormatting, IconDeviceFloppy, IconDots, IconHistory, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPageBreak, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSeparatorHorizontal, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconArrowMergeBoth, IconArrowsSplit2, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconColumns, IconNumber1Small, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconTable, IconTableMinus, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
|
|
31
|
+
import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconBold, IconClearFormatting, IconDeviceFloppy, IconDots, IconHistory, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPageBreak, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSeparatorHorizontal, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconArrowMergeBoth, IconArrowsSplit2, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconColumns, IconColumns1, IconColumns2, IconNumber1Small, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconTable, IconTableMinus, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
|
|
30
32
|
/** Sentinel for "no inline style": Lexical returns the default it is given when
|
|
31
33
|
* the selection has none, so this tells "unstyled" (show the canvas default)
|
|
32
34
|
* apart from "styled with a value the dropdown doesn't list" (show nothing). */
|
|
@@ -45,6 +47,9 @@ const INITIAL_STATE = {
|
|
|
45
47
|
tableColumns: 1,
|
|
46
48
|
canMergeCells: false,
|
|
47
49
|
canUnmergeCell: false,
|
|
50
|
+
inPoetry: false,
|
|
51
|
+
poetryLayout: 'single',
|
|
52
|
+
poetryAlign: 'justify',
|
|
48
53
|
canUndo: false,
|
|
49
54
|
canRedo: false,
|
|
50
55
|
};
|
|
@@ -156,6 +161,26 @@ function TableMenuItems({ strings, direction, rows, columns, canMergeCells, canU
|
|
|
156
161
|
};
|
|
157
162
|
return (_jsxs(_Fragment, { children: [_jsx(Menu.Label, { children: t.menuLabel }), item(IconRowInsertTop, manyRows ? t.insertRowsBefore : t.insertRowBefore, () => $insertTableRows(false)), item(IconRowInsertBottom, manyRows ? t.insertRowsAfter : t.insertRowAfter, () => $insertTableRows(true)), item(rtl ? IconColumnInsertRight : IconColumnInsertLeft, manyColumns ? t.insertColumnsBefore : t.insertColumnBefore, () => $insertTableColumns(false)), item(rtl ? IconColumnInsertLeft : IconColumnInsertRight, manyColumns ? t.insertColumnsAfter : t.insertColumnAfter, () => $insertTableColumns(true)), (canMergeCells || canUnmergeCell) && _jsx(Menu.Divider, {}), canMergeCells && item(IconArrowMergeBoth, t.mergeCells, $mergeTableCells), canUnmergeCell && item(IconArrowsSplit2, t.unmergeCell, $unmergeTableCell), _jsx(Menu.Divider, {}), item(IconRowRemove, manyRows ? t.deleteRows : t.deleteRow, $deleteTableRows), item(IconColumnRemove, manyColumns ? t.deleteColumns : t.deleteColumn, $deleteTableColumns), item(IconTableMinus, t.deleteTable, $deleteTable, 'red')] }));
|
|
158
163
|
}
|
|
164
|
+
/** The poetry couplet menu's contents — layout (single/two-column) and
|
|
165
|
+
* literal alignment, both per-instance overrides (requirements doc §4.11:
|
|
166
|
+
* "set per CoupletNode, not inherited from a document-wide setting"). */
|
|
167
|
+
function PoetryMenuItems({ strings, alignIcons, layout, align, onAction, }) {
|
|
168
|
+
const t = strings.poetryMenu;
|
|
169
|
+
const a = strings.toolbar.alignOptions;
|
|
170
|
+
const item = (icon, label, action, active) => {
|
|
171
|
+
const Icon = icon;
|
|
172
|
+
return (_jsx(Menu.Item, { disabled: active, leftSection: _jsx(Icon, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onAction(action), children: label }));
|
|
173
|
+
};
|
|
174
|
+
const setLayout = (next) => () => {
|
|
175
|
+
const node = $getPoetryBlockFromSelection();
|
|
176
|
+
if (node)
|
|
177
|
+
$setPoetryLayout(node, next);
|
|
178
|
+
};
|
|
179
|
+
const setAlign = (next) => () => {
|
|
180
|
+
$getPoetryBlockFromSelection()?.setAlign(next);
|
|
181
|
+
};
|
|
182
|
+
return (_jsxs(_Fragment, { children: [_jsx(Menu.Label, { children: t.menuLabel }), item(IconColumns1, t.singleColumn, setLayout('single'), layout === 'single'), item(IconColumns2, t.twoColumn, setLayout('two-column'), layout === 'two-column'), _jsx(Menu.Divider, {}), item(alignIcons.justify ?? IconAlignJustified, a.justify, setAlign('justify'), align === 'justify'), item(alignIcons.start ?? IconAlignLeft, a.start, setAlign('start'), align === 'start'), item(IconAlignLeft, a.left, setAlign('left'), align === 'left'), item(IconAlignRight, a.right, setAlign('right'), align === 'right')] }));
|
|
183
|
+
}
|
|
159
184
|
export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
160
185
|
const [editor] = useLexicalComposerContext();
|
|
161
186
|
const [state, setState] = useState(INITIAL_STATE);
|
|
@@ -180,7 +205,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
180
205
|
if ($isTableSelection(selection)) {
|
|
181
206
|
const { rows, columns } = $getTableSelectionSize();
|
|
182
207
|
const canMergeCells = $canMergeSelectedCells();
|
|
183
|
-
setState((s) => ({ ...s, inTable: true, tableRows: rows, tableColumns: columns, canMergeCells, canUnmergeCell: false }));
|
|
208
|
+
setState((s) => ({ ...s, inTable: true, tableRows: rows, tableColumns: columns, canMergeCells, canUnmergeCell: false, inPoetry: false }));
|
|
184
209
|
return;
|
|
185
210
|
}
|
|
186
211
|
if (!$isRangeSelection(selection))
|
|
@@ -189,6 +214,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
189
214
|
const inTable = $getTableCellNodeFromLexicalNode(anchorNode) !== null;
|
|
190
215
|
const tableSize = inTable ? $getTableSelectionSize() : { rows: 1, columns: 1 };
|
|
191
216
|
const canUnmergeCell = inTable && $canUnmergeSelectedCell();
|
|
217
|
+
const poetryBlock = $getPoetryBlockFromSelection();
|
|
192
218
|
const element = anchorNode.getKey() === 'root' ? anchorNode : (anchorNode.getTopLevelElement() ?? anchorNode);
|
|
193
219
|
const listParent = $findMatchingParent(anchorNode, $isListNode);
|
|
194
220
|
const listType = listParent && $isListNode(listParent) ? listParent.getListType() : null;
|
|
@@ -214,6 +240,8 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
214
240
|
// Lexical's read/update context has already closed, so any $-prefixed
|
|
215
241
|
// node method (getFormatType() included) must not be deferred into it.
|
|
216
242
|
const elementFormat = ($isElementNode(element) ? element.getFormatType() : 'start') || 'start';
|
|
243
|
+
const poetryLayout = poetryBlock?.getLayout();
|
|
244
|
+
const poetryAlign = poetryBlock?.getAlign();
|
|
217
245
|
setState((s) => ({
|
|
218
246
|
...s,
|
|
219
247
|
blockType,
|
|
@@ -229,6 +257,9 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
229
257
|
tableColumns: tableSize.columns,
|
|
230
258
|
canMergeCells: false,
|
|
231
259
|
canUnmergeCell,
|
|
260
|
+
inPoetry: poetryBlock !== null,
|
|
261
|
+
poetryLayout: poetryLayout ?? s.poetryLayout,
|
|
262
|
+
poetryAlign: poetryAlign ?? s.poetryAlign,
|
|
232
263
|
}));
|
|
233
264
|
});
|
|
234
265
|
}, [editor]);
|
|
@@ -457,9 +488,9 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
457
488
|
root?.addEventListener('contextmenu', onContextMenu);
|
|
458
489
|
});
|
|
459
490
|
}, [editor, config.links]);
|
|
460
|
-
// Table actions. The menu takes focus, so the
|
|
461
|
-
// opens and restored before an action runs.
|
|
462
|
-
const
|
|
491
|
+
// Table/poetry contextual-menu actions. The menu takes focus, so the
|
|
492
|
+
// selection is snapshotted when it opens and restored before an action runs.
|
|
493
|
+
const runMenuAction = (action) => () => {
|
|
463
494
|
restoreSelection();
|
|
464
495
|
editor.update(action);
|
|
465
496
|
editor.focus();
|
|
@@ -740,8 +771,9 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
740
771
|
restoreSelection();
|
|
741
772
|
openLinkDialog();
|
|
742
773
|
}, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog })) }, "link")),
|
|
743
|
-
showStubInsertGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [(config.images.linked || config.images.embedded) && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.blocks.pageBreak && (_jsx(ToolbarButton, { icon: IconPageBreak, title: strings.toolbar.insertPageBreak, onClick: () => editor.dispatchCommand(INSERT_PAGE_BREAK_COMMAND, undefined) })), config.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), config.columns && _jsx(ToolbarButton, { icon: IconColumns, title: strings.toolbar.insertColumns, onClick: openLayoutDialog }), config.footnotes && (_jsx(ToolbarButton, { icon: IconNumber1Small, title: strings.toolbar.insertFootnote, onClick: () => editor.dispatchCommand(INSERT_FOOTNOTE_COMMAND, undefined) })), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.poetry.enabled && _jsx(
|
|
744
|
-
config.tables && state.inTable && (_jsx("div", { className: "likhari-toolbar-group", children: _jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx("button", { type: "button", className: "likhari-toolbar-button", "data-active": "true", "aria-pressed": "true", "aria-haspopup": "menu", "aria-label": strings.toolbar.tableOptions, title: strings.toolbar.tableOptions, onMouseDown: (e) => e.preventDefault(), children: _jsx(IconTableOptions, { size: ICON_SIZE, stroke: ICON_STROKE }) }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: state.tableRows, columns: state.tableColumns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction:
|
|
774
|
+
showStubInsertGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [(config.images.linked || config.images.embedded) && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.blocks.pageBreak && (_jsx(ToolbarButton, { icon: IconPageBreak, title: strings.toolbar.insertPageBreak, onClick: () => editor.dispatchCommand(INSERT_PAGE_BREAK_COMMAND, undefined) })), config.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), config.columns && _jsx(ToolbarButton, { icon: IconColumns, title: strings.toolbar.insertColumns, onClick: openLayoutDialog }), config.footnotes && (_jsx(ToolbarButton, { icon: IconNumber1Small, title: strings.toolbar.insertFootnote, onClick: () => editor.dispatchCommand(INSERT_FOOTNOTE_COMMAND, undefined) })), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.poetry.enabled && locale !== 'en' && (_jsx(ToolbarButton, { icon: IconFeather, title: strings.toolbar.insertPoetryCouplet, onClick: () => editor.dispatchCommand(INSERT_POETRY_COUPLET_COMMAND, { layout: config.poetry.defaultLayout, align: 'justify' }) }))] }, "stubInsert")),
|
|
775
|
+
config.tables && state.inTable && (_jsx("div", { className: "likhari-toolbar-group", children: _jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx("button", { type: "button", className: "likhari-toolbar-button", "data-active": "true", "aria-pressed": "true", "aria-haspopup": "menu", "aria-label": strings.toolbar.tableOptions, title: strings.toolbar.tableOptions, onMouseDown: (e) => e.preventDefault(), children: _jsx(IconTableOptions, { size: ICON_SIZE, stroke: ICON_STROKE }) }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: state.tableRows, columns: state.tableColumns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }) })] }) }, "tableActions")),
|
|
776
|
+
config.poetry.enabled && state.inPoetry && (_jsx("div", { className: "likhari-toolbar-group", children: _jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx("button", { type: "button", className: "likhari-toolbar-button", "data-active": "true", "aria-pressed": "true", "aria-haspopup": "menu", "aria-label": strings.toolbar.poetryOptions, title: strings.toolbar.poetryOptions, onMouseDown: (e) => e.preventDefault(), children: _jsx(IconFeather, { size: ICON_SIZE, stroke: ICON_STROKE }) }) }), _jsx(Menu.Dropdown, { children: _jsx(PoetryMenuItems, { strings: strings, alignIcons: ALIGN_ICONS, layout: state.poetryLayout, align: state.poetryAlign, onAction: runMenuAction }) })] }) }, "poetryActions")),
|
|
745
777
|
showLanguageGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [config.language.autocorrect && _jsx(StubButton, { icon: IconWand, title: strings.toolbar.autocorrect, comingSoon: strings.toolbar.comingSoon }), config.language.textCleanup && _jsx(StubButton, { icon: IconSparkles, title: strings.toolbar.textCleanup, comingSoon: strings.toolbar.comingSoon }), config.language.spellCheck && _jsx(StubButton, { icon: IconAbc, title: strings.toolbar.spellChecker, comingSoon: strings.toolbar.comingSoon })] }, "language")),
|
|
746
778
|
];
|
|
747
779
|
return (_jsxs("div", { className: "likhari-toolbar", role: "toolbar", "aria-label": strings.toolbar.ariaLabel, ref: toolbarContainerRef, children: [fixedGroups, movableGroups
|
|
@@ -757,7 +789,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
757
789
|
}, onRemove: removeLink, strings: strings }) })] })), config.tables && (_jsxs(Menu, { opened: tableContext !== null, onChange: (opened) => {
|
|
758
790
|
if (!opened)
|
|
759
791
|
setTableContext(null);
|
|
760
|
-
}, position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, children: [_jsx(Menu.Target, { children: _jsx("span", { "aria-hidden": "true", style: { position: 'fixed', left: tableContext?.x ?? -9999, top: tableContext?.y ?? -9999, width: 1, height: 1, pointerEvents: 'none' } }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: tableContext?.rows ?? 1, columns: tableContext?.columns ?? 1, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction:
|
|
792
|
+
}, position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, children: [_jsx(Menu.Target, { children: _jsx("span", { "aria-hidden": "true", style: { position: 'fixed', left: tableContext?.x ?? -9999, top: tableContext?.y ?? -9999, width: 1, height: 1, pointerEvents: 'none' } }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: tableContext?.rows ?? 1, columns: tableContext?.columns ?? 1, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }) })] })), _jsxs("div", { "aria-hidden": "true", ref: toolbarMeasureRef, style: {
|
|
761
793
|
position: 'absolute',
|
|
762
794
|
visibility: 'hidden',
|
|
763
795
|
pointerEvents: 'none',
|
package/dist/i18n/strings.d.ts
CHANGED
|
@@ -42,14 +42,16 @@ export interface Strings {
|
|
|
42
42
|
linkOptions: string;
|
|
43
43
|
/** Toolbar button (shown while the caret is in a table) that opens the table actions menu. */
|
|
44
44
|
tableOptions: string;
|
|
45
|
+
/** Toolbar button (shown while the caret is in a couplet) that opens the poetry layout/alignment menu. */
|
|
46
|
+
poetryOptions: string;
|
|
45
47
|
insertLink: string;
|
|
46
48
|
insertImage: string;
|
|
47
49
|
insertPageBreak: string;
|
|
48
50
|
insertTable: string;
|
|
49
51
|
insertColumns: string;
|
|
50
52
|
insertFootnote: string;
|
|
53
|
+
insertPoetryCouplet: string;
|
|
51
54
|
insertHorizontalRule: string;
|
|
52
|
-
poetryBlocks: string;
|
|
53
55
|
comingSoon: (label: string) => string;
|
|
54
56
|
autocorrect: string;
|
|
55
57
|
textCleanup: string;
|
|
@@ -136,6 +138,11 @@ export interface Strings {
|
|
|
136
138
|
mergeCells: string;
|
|
137
139
|
unmergeCell: string;
|
|
138
140
|
};
|
|
141
|
+
poetryMenu: {
|
|
142
|
+
menuLabel: string;
|
|
143
|
+
singleColumn: string;
|
|
144
|
+
twoColumn: string;
|
|
145
|
+
};
|
|
139
146
|
link: {
|
|
140
147
|
menuLabel: string;
|
|
141
148
|
noUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;+DAC+D;AAC/D,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,cAAc,CAAC;AAElD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE;QACN,mGAAmG;QACnG,WAAW,EAAE,MAAM,CAAC;QACpB,gDAAgD;QAChD,YAAY,EAAE,MAAM,CAAC;QACrB,sEAAsE;QACtE,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,MAAM,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QACP,gEAAgE;QAChE,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,0CAA0C;QAC1C,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,QAAQ,EAAE,MAAM,CAAC;QACjB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,8FAA8F;QAC9F,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,
|
|
1
|
+
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/strings.js
CHANGED
|
@@ -33,14 +33,15 @@ const en = {
|
|
|
33
33
|
alignment: 'Alignment',
|
|
34
34
|
linkOptions: 'Link options',
|
|
35
35
|
tableOptions: 'Table options',
|
|
36
|
+
poetryOptions: 'Poetry options',
|
|
36
37
|
insertLink: 'Insert link (Ctrl+K)',
|
|
37
38
|
insertImage: 'Insert image',
|
|
38
39
|
insertPageBreak: 'Insert page break',
|
|
39
40
|
insertTable: 'Insert table',
|
|
40
41
|
insertColumns: 'Insert columns',
|
|
41
42
|
insertFootnote: 'Insert footnote',
|
|
43
|
+
insertPoetryCouplet: 'Insert poetry couplet',
|
|
42
44
|
insertHorizontalRule: 'Insert horizontal rule',
|
|
43
|
-
poetryBlocks: 'Poetry blocks',
|
|
44
45
|
comingSoon: (label) => `${label} (coming soon)`,
|
|
45
46
|
autocorrect: 'Auto-correct',
|
|
46
47
|
textCleanup: 'Text cleanup',
|
|
@@ -120,6 +121,11 @@ const en = {
|
|
|
120
121
|
mergeCells: 'Merge cells',
|
|
121
122
|
unmergeCell: 'Unmerge cell',
|
|
122
123
|
},
|
|
124
|
+
poetryMenu: {
|
|
125
|
+
menuLabel: 'Poetry',
|
|
126
|
+
singleColumn: 'Single column',
|
|
127
|
+
twoColumn: 'Two column',
|
|
128
|
+
},
|
|
123
129
|
link: {
|
|
124
130
|
menuLabel: 'Link',
|
|
125
131
|
noUrl: '(no URL)',
|
|
@@ -234,14 +240,15 @@ const ur = {
|
|
|
234
240
|
alignment: 'سیدھ',
|
|
235
241
|
linkOptions: 'لنک کے اختیارات',
|
|
236
242
|
tableOptions: 'جدول کے اختیارات',
|
|
243
|
+
poetryOptions: 'شاعری کے اختیارات',
|
|
237
244
|
insertLink: 'لنک شامل کریں (Ctrl+K)',
|
|
238
245
|
insertImage: 'تصویر شامل کریں',
|
|
239
246
|
insertPageBreak: 'صفحے کی تقسیم شامل کریں',
|
|
240
247
|
insertTable: 'جدول شامل کریں',
|
|
241
248
|
insertColumns: 'کالم شامل کریں',
|
|
242
249
|
insertFootnote: 'فٹ نوٹ شامل کریں',
|
|
250
|
+
insertPoetryCouplet: 'شعر شامل کریں',
|
|
243
251
|
insertHorizontalRule: 'افقی لکیر شامل کریں',
|
|
244
|
-
poetryBlocks: 'شاعری کے بلاکس',
|
|
245
252
|
comingSoon: (label) => `${label} (جلد آ رہا ہے)`,
|
|
246
253
|
autocorrect: 'خودکار تصحیح',
|
|
247
254
|
textCleanup: 'متن کی صفائی',
|
|
@@ -321,6 +328,11 @@ const ur = {
|
|
|
321
328
|
mergeCells: 'خانے ضم کریں',
|
|
322
329
|
unmergeCell: 'خانہ الگ کریں',
|
|
323
330
|
},
|
|
331
|
+
poetryMenu: {
|
|
332
|
+
menuLabel: 'شاعری',
|
|
333
|
+
singleColumn: 'ایک کالم',
|
|
334
|
+
twoColumn: 'دو کالم',
|
|
335
|
+
},
|
|
324
336
|
link: {
|
|
325
337
|
menuLabel: 'لنک',
|
|
326
338
|
noUrl: '(کوئی یو آر ایل نہیں)',
|
|
@@ -435,14 +447,15 @@ const paShahmukhi = {
|
|
|
435
447
|
alignment: 'سیدھ',
|
|
436
448
|
linkOptions: 'لنک دے اختیار',
|
|
437
449
|
tableOptions: 'ٹیبل دے اختیار',
|
|
450
|
+
poetryOptions: 'شاعری دے اختیار',
|
|
438
451
|
insertLink: 'لنک پاؤ (Ctrl+K)',
|
|
439
452
|
insertImage: 'تصویر پاؤ',
|
|
440
453
|
insertPageBreak: 'صفحے دی ونڈ پاؤ',
|
|
441
454
|
insertTable: 'ٹیبل پاؤ',
|
|
442
455
|
insertColumns: 'کالم پاؤ',
|
|
443
456
|
insertFootnote: 'فٹ نوٹ پاؤ',
|
|
457
|
+
insertPoetryCouplet: 'شعر پاؤ',
|
|
444
458
|
insertHorizontalRule: 'لیٹی لکیر پاؤ',
|
|
445
|
-
poetryBlocks: 'شاعری بلاک',
|
|
446
459
|
comingSoon: (label) => `${label} (چھیتی آ رہا اے)`,
|
|
447
460
|
autocorrect: 'خودکار درستی',
|
|
448
461
|
textCleanup: 'متن دی صفائی',
|
|
@@ -522,6 +535,11 @@ const paShahmukhi = {
|
|
|
522
535
|
mergeCells: 'خانے رلاؤ',
|
|
523
536
|
unmergeCell: 'خانہ الگ کرو',
|
|
524
537
|
},
|
|
538
|
+
poetryMenu: {
|
|
539
|
+
menuLabel: 'شاعری',
|
|
540
|
+
singleColumn: 'اک کالم',
|
|
541
|
+
twoColumn: 'دو کالم',
|
|
542
|
+
},
|
|
525
543
|
link: {
|
|
526
544
|
menuLabel: 'لنک',
|
|
527
545
|
noUrl: '(کوئی یو آر ایل نئیں)',
|
package/dist/nodes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../src/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../src/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAalD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAkB5C,CAAC"}
|
package/dist/nodes.js
CHANGED
|
@@ -8,6 +8,7 @@ import { PageBreakNode } from './blocks/PageBreakNode.js';
|
|
|
8
8
|
import { LayoutContainerNode, LayoutItemNode } from './blocks/LayoutNode.js';
|
|
9
9
|
import { FootnoteReferenceNode } from './blocks/FootnoteNode.js';
|
|
10
10
|
import { FootnoteItemNode, FootnoteListNode } from './blocks/FootnoteListNode.js';
|
|
11
|
+
import { PoetryBlockNode } from './blocks/PoetryNode.js';
|
|
11
12
|
/**
|
|
12
13
|
* Node types registered on the editor at construction time. Per
|
|
13
14
|
* editor-architecture-design.md §2, node registration cannot be conditional
|
|
@@ -34,4 +35,5 @@ export const EDITOR_NODES = [
|
|
|
34
35
|
FootnoteReferenceNode,
|
|
35
36
|
FootnoteListNode,
|
|
36
37
|
FootnoteItemNode,
|
|
38
|
+
PoetryBlockNode,
|
|
37
39
|
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type LexicalCommand } from 'lexical';
|
|
2
|
+
import { type PoetryAlign, type PoetryLayout } from '../blocks/PoetryNode.js';
|
|
3
|
+
export declare const INSERT_POETRY_COUPLET_COMMAND: LexicalCommand<{
|
|
4
|
+
layout: PoetryLayout;
|
|
5
|
+
align: PoetryAlign;
|
|
6
|
+
}>;
|
|
7
|
+
/**
|
|
8
|
+
* Registers INSERT_POETRY_COUPLET_COMMAND (mirrors LayoutPlugin/FootnotePlugin's
|
|
9
|
+
* shape) and a node transform that removes a couplet left with no misra
|
|
10
|
+
* content — e.g. after undo/paste leaves it structurally empty — rather
|
|
11
|
+
* than letting an unselectable husk linger in the document.
|
|
12
|
+
*/
|
|
13
|
+
export declare function PoetryPlugin(): null;
|
|
14
|
+
//# sourceMappingURL=PoetryPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PoetryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PoetryPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA0C,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAGtF,OAAO,EAAmB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAG5F,eAAO,MAAM,6BAA6B,EAAE,cAAc,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAEtG,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,YAAY,SAqB3B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
+
import { COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
|
|
4
|
+
import { mergeRegister } from '@lexical/utils';
|
|
5
|
+
import { LayoutContainerNode, LayoutItemNode } from '../blocks/LayoutNode.js';
|
|
6
|
+
import { PoetryBlockNode } from '../blocks/PoetryNode.js';
|
|
7
|
+
import { $insertPoetryCouplet } from '../blocks/poetryActions.js';
|
|
8
|
+
export const INSERT_POETRY_COUPLET_COMMAND = createCommand('INSERT_POETRY_COUPLET_COMMAND');
|
|
9
|
+
/**
|
|
10
|
+
* Registers INSERT_POETRY_COUPLET_COMMAND (mirrors LayoutPlugin/FootnotePlugin's
|
|
11
|
+
* shape) and a node transform that removes a couplet left with no misra
|
|
12
|
+
* content — e.g. after undo/paste leaves it structurally empty — rather
|
|
13
|
+
* than letting an unselectable husk linger in the document.
|
|
14
|
+
*/
|
|
15
|
+
export function PoetryPlugin() {
|
|
16
|
+
const [editor] = useLexicalComposerContext();
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!editor.hasNodes([PoetryBlockNode, LayoutContainerNode, LayoutItemNode])) {
|
|
19
|
+
throw new Error('PoetryPlugin: PoetryBlockNode (and the columns nodes it composes) not registered on the editor');
|
|
20
|
+
}
|
|
21
|
+
return mergeRegister(editor.registerCommand(INSERT_POETRY_COUPLET_COMMAND, ({ layout, align }) => $insertPoetryCouplet(layout, align), COMMAND_PRIORITY_EDITOR), editor.registerNodeTransform(PoetryBlockNode, (node) => {
|
|
22
|
+
if (node.getChildrenSize() === 0)
|
|
23
|
+
node.remove();
|
|
24
|
+
}));
|
|
25
|
+
}, [editor]);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
package/dist/theme/editor.css
CHANGED
|
@@ -374,6 +374,34 @@
|
|
|
374
374
|
content: '[' counter(likhari-footnote-item) '] ';
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
+
/* Poetry couplets (lexical-editor-spec.md §4.11, editor-ui-design-spec.md §4).
|
|
378
|
+
Own type scale and spacing, distinct from body text — the .likhari-ltr/
|
|
379
|
+
.likhari-rtl per-block classes (above) already switch font-family for this
|
|
380
|
+
element same as any other block; these rules layer poetry's own size/
|
|
381
|
+
line-height/gap on top, combined with those same classes. */
|
|
382
|
+
.likhari-poetry {
|
|
383
|
+
margin: 0 0 1.4em 0;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.likhari-poetry.likhari-ltr {
|
|
387
|
+
font-size: 15px;
|
|
388
|
+
line-height: 1.6;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.likhari-poetry.likhari-rtl {
|
|
392
|
+
font-size: 20px;
|
|
393
|
+
line-height: 2.1;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.likhari-poetry--two-column .likhari-layout-container {
|
|
397
|
+
margin: 0;
|
|
398
|
+
gap: 16px;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.likhari-poetry--two-column .likhari-layout-item {
|
|
402
|
+
text-align: inherit;
|
|
403
|
+
}
|
|
404
|
+
|
|
377
405
|
.likhari-table {
|
|
378
406
|
border-collapse: collapse;
|
|
379
407
|
margin: 1em 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editorTheme.d.ts","sourceRoot":"","sources":["../../src/theme/editorTheme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"editorTheme.d.ts","sourceRoot":"","sources":["../../src/theme/editorTheme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,kBAgDzB,CAAC"}
|
|
@@ -45,6 +45,7 @@ export const editorTheme = {
|
|
|
45
45
|
footnoteReference: 'likhari-footnote-ref',
|
|
46
46
|
footnoteList: 'likhari-footnote-list',
|
|
47
47
|
footnoteItem: 'likhari-footnote-item',
|
|
48
|
+
poetry: 'likhari-poetry',
|
|
48
49
|
table: 'likhari-table',
|
|
49
50
|
tableRow: 'likhari-table-row',
|
|
50
51
|
tableCell: 'likhari-table-cell',
|