@inshapardaz/likhari-react 0.1.18-dev.152 → 0.1.18-dev.156

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ import { type DOMConversionMap, type DOMExportOutput, type EditorConfig, type LexicalNode, type NodeKey, type SerializedElementNode, type Spread, ElementNode } from 'lexical';
2
+ export type SerializedPoetryCoupletNode = Spread<{
3
+ centered: boolean;
4
+ }, SerializedElementNode>;
5
+ /**
6
+ * One couplet's two misra lines, wrapped so each couplet can carry its own
7
+ * rendering override independent of its PoetryBlockNode's overall layout —
8
+ * currently just `centered` (a narrower box, centered on the page, instead
9
+ * of the block's default width): "two columns with a couplet that is
10
+ * single, aligned centered" mixes LayoutContainerNode rows (two-column
11
+ * couplets) with centered PoetryCoupletNodes in the same block, each
12
+ * couplet choosing independently.
13
+ *
14
+ * Used for single-column and alternating block layouts; a two-column
15
+ * couplet uses LayoutContainerNode instead (its own two-item row already
16
+ * gives it a natural per-couplet box, so it doesn't need this wrapper).
17
+ */
18
+ export declare class PoetryCoupletNode extends ElementNode {
19
+ __centered: boolean;
20
+ constructor(centered?: boolean, key?: NodeKey);
21
+ static getType(): string;
22
+ static clone(node: PoetryCoupletNode): PoetryCoupletNode;
23
+ getCentered(): boolean;
24
+ setCentered(centered: boolean): this;
25
+ static importJSON(serializedNode: SerializedPoetryCoupletNode): PoetryCoupletNode;
26
+ exportJSON(): SerializedPoetryCoupletNode;
27
+ static importDOM(): DOMConversionMap | null;
28
+ exportDOM(): DOMExportOutput;
29
+ createDOM(config: EditorConfig): HTMLElement;
30
+ updateDOM(prevNode: PoetryCoupletNode, dom: HTMLElement, config: EditorConfig): boolean;
31
+ canBeEmpty(): false;
32
+ canIndent(): false;
33
+ }
34
+ export declare function $createPoetryCoupletNode(centered?: boolean): PoetryCoupletNode;
35
+ export declare function $isPoetryCoupletNode(node: LexicalNode | null | undefined): node is PoetryCoupletNode;
36
+ //# sourceMappingURL=PoetryCoupletNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PoetryCoupletNode.d.ts","sourceRoot":"","sources":["../../src/blocks/PoetryCoupletNode.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,2BAA2B,GAAG,MAAM,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,EAAE,qBAAqB,CAAC,CAAC;AAE/F;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IAChD,UAAU,EAAE,OAAO,CAAC;gBAER,QAAQ,UAAQ,EAAE,GAAG,CAAC,EAAE,OAAO;IAK3C,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB;IAIxD,WAAW,IAAI,OAAO;IAItB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAMpC,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,2BAA2B,GAAG,iBAAiB;IAIjF,UAAU,IAAI,2BAA2B;IAIzC,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAU3C,SAAS,IAAI,eAAe;IAO5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAQ5C,SAAS,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO;IAQvF,UAAU,IAAI,KAAK;IAInB,SAAS,IAAI,KAAK;CAGnB;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,UAAQ,GAAG,iBAAiB,CAE5E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,iBAAiB,CAEpG"}
@@ -0,0 +1,85 @@
1
+ import { addClassNamesToElement } from '@lexical/utils';
2
+ import { $applyNodeReplacement, ElementNode, } from 'lexical';
3
+ /**
4
+ * One couplet's two misra lines, wrapped so each couplet can carry its own
5
+ * rendering override independent of its PoetryBlockNode's overall layout —
6
+ * currently just `centered` (a narrower box, centered on the page, instead
7
+ * of the block's default width): "two columns with a couplet that is
8
+ * single, aligned centered" mixes LayoutContainerNode rows (two-column
9
+ * couplets) with centered PoetryCoupletNodes in the same block, each
10
+ * couplet choosing independently.
11
+ *
12
+ * Used for single-column and alternating block layouts; a two-column
13
+ * couplet uses LayoutContainerNode instead (its own two-item row already
14
+ * gives it a natural per-couplet box, so it doesn't need this wrapper).
15
+ */
16
+ export class PoetryCoupletNode extends ElementNode {
17
+ constructor(centered = false, key) {
18
+ super(key);
19
+ this.__centered = centered;
20
+ }
21
+ static getType() {
22
+ return 'poetry-couplet';
23
+ }
24
+ static clone(node) {
25
+ return new PoetryCoupletNode(node.__centered, node.__key);
26
+ }
27
+ getCentered() {
28
+ return this.getLatest().__centered;
29
+ }
30
+ setCentered(centered) {
31
+ const writable = this.getWritable();
32
+ writable.__centered = centered;
33
+ return writable;
34
+ }
35
+ static importJSON(serializedNode) {
36
+ return $createPoetryCoupletNode(serializedNode.centered);
37
+ }
38
+ exportJSON() {
39
+ return { ...super.exportJSON(), type: 'poetry-couplet', version: 1, centered: this.getCentered() };
40
+ }
41
+ static importDOM() {
42
+ return {
43
+ div: (domNode) => {
44
+ if (!domNode.hasAttribute('data-likhari-poetry-couplet'))
45
+ return null;
46
+ const centered = domNode.getAttribute('data-likhari-poetry-couplet-centered') === 'true';
47
+ return { conversion: () => ({ node: $createPoetryCoupletNode(centered) }), priority: 2 };
48
+ },
49
+ };
50
+ }
51
+ exportDOM() {
52
+ const element = document.createElement('div');
53
+ element.setAttribute('data-likhari-poetry-couplet', '');
54
+ if (this.getCentered())
55
+ element.setAttribute('data-likhari-poetry-couplet-centered', 'true');
56
+ return { element };
57
+ }
58
+ createDOM(config) {
59
+ const element = document.createElement('div');
60
+ const base = config.theme.poetryCouplet ?? 'likhari-poetry-couplet';
61
+ addClassNamesToElement(element, base);
62
+ if (this.__centered)
63
+ element.classList.add(`${base}--centered`);
64
+ return element;
65
+ }
66
+ updateDOM(prevNode, dom, config) {
67
+ if (prevNode.__centered !== this.__centered) {
68
+ const base = config.theme.poetryCouplet ?? 'likhari-poetry-couplet';
69
+ dom.classList.toggle(`${base}--centered`, this.__centered);
70
+ }
71
+ return false;
72
+ }
73
+ canBeEmpty() {
74
+ return false;
75
+ }
76
+ canIndent() {
77
+ return false;
78
+ }
79
+ }
80
+ export function $createPoetryCoupletNode(centered = false) {
81
+ return $applyNodeReplacement(new PoetryCoupletNode(centered));
82
+ }
83
+ export function $isPoetryCoupletNode(node) {
84
+ return node instanceof PoetryCoupletNode;
85
+ }
@@ -1,10 +1,15 @@
1
1
  import { type DOMConversionMap, type DOMExportOutput, type EditorConfig, type LexicalNode, type NodeKey, type SerializedElementNode, type Spread, ElementNode } from 'lexical';
2
2
  export type PoetryLayout = 'single' | 'two-column';
3
3
  export type PoetryAlign = 'justify' | 'left' | 'right' | 'start';
4
+ /** Vertical space between couplets — an ordered scale the menu steps through. */
5
+ export declare const POETRY_SPACINGS: readonly ["compact", "normal", "relaxed", "loose"];
6
+ export type PoetrySpacing = (typeof POETRY_SPACINGS)[number];
7
+ export declare const DEFAULT_POETRY_SPACING: PoetrySpacing;
4
8
  export type SerializedPoetryBlockNode = Spread<{
5
9
  layout: PoetryLayout;
6
10
  align: PoetryAlign;
7
11
  width?: number;
12
+ spacing?: PoetrySpacing;
8
13
  }, SerializedElementNode>;
9
14
  /**
10
15
  * A poetry *section*: one or more couplets (two-line verse units) sharing
@@ -25,7 +30,8 @@ export declare class PoetryBlockNode extends ElementNode {
25
30
  /** User-chosen width in px (drag-resized), overriding editor.css's default
26
31
  * max-width: 70%. Undefined until the user resizes it. */
27
32
  __width?: number;
28
- constructor(layout?: PoetryLayout, align?: PoetryAlign, width?: number, key?: NodeKey);
33
+ __spacing: PoetrySpacing;
34
+ constructor(layout?: PoetryLayout, align?: PoetryAlign, width?: number, spacing?: PoetrySpacing, key?: NodeKey);
29
35
  static getType(): string;
30
36
  static clone(node: PoetryBlockNode): PoetryBlockNode;
31
37
  getLayout(): PoetryLayout;
@@ -36,6 +42,8 @@ export declare class PoetryBlockNode extends ElementNode {
36
42
  * poetryActions.ts's $setPoetryLayout, not a node method, since it needs
37
43
  * $-context tree mutations beyond this node's own state. */
38
44
  setLayoutAttribute(layout: PoetryLayout): this;
45
+ getSpacing(): PoetrySpacing;
46
+ setSpacing(spacing: PoetrySpacing): this;
39
47
  setAlign(align: PoetryAlign): this;
40
48
  static importJSON(serializedNode: SerializedPoetryBlockNode): PoetryBlockNode;
41
49
  exportJSON(): SerializedPoetryBlockNode;
@@ -46,6 +54,6 @@ export declare class PoetryBlockNode extends ElementNode {
46
54
  canBeEmpty(): false;
47
55
  isShadowRoot(): boolean;
48
56
  }
49
- export declare function $createPoetryBlockNode(layout?: PoetryLayout, align?: PoetryAlign, width?: number): PoetryBlockNode;
57
+ export declare function $createPoetryBlockNode(layout?: PoetryLayout, align?: PoetryAlign, width?: number, spacing?: PoetrySpacing): PoetryBlockNode;
50
58
  export declare function $isPoetryBlockNode(node: LexicalNode | null | undefined): node is PoetryBlockNode;
51
59
  //# sourceMappingURL=PoetryNode.d.ts.map
@@ -1 +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;AAwBjE,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,qBAAqB,CAAC,CAAC;AAEpI;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB;8DAC0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;gBAEL,MAAM,GAAE,YAAuB,EAAE,KAAK,GAAE,WAAuB,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;IAO1G,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,GAAG,eAAe;IAIpD,SAAS,IAAI,YAAY;IAIzB,QAAQ,IAAI,WAAW;IAIvB,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAMzC;;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;IAYvC,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAe3C,SAAS,IAAI,eAAe;IAW5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAa5C,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO;IAerF,UAAU,IAAI,KAAK;IAInB,YAAY,IAAI,OAAO;CAGxB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,GAAE,YAAuB,EAAE,KAAK,GAAE,WAAuB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe,CAEvI;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,eAAe,CAEhG"}
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;AACjE,iFAAiF;AACjF,eAAO,MAAM,eAAe,oDAAqD,CAAC;AAClF,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7D,eAAO,MAAM,sBAAsB,EAAE,aAAwB,CAAC;AAyB9D,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAC5C;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAA;CAAE,EACrF,qBAAqB,CACtB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB;8DAC0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;gBAGvB,MAAM,GAAE,YAAuB,EAC/B,KAAK,GAAE,WAAuB,EAC9B,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,GAAE,aAAsC,EAC/C,GAAG,CAAC,EAAE,OAAO;IASf,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,GAAG,eAAe;IAIpD,SAAS,IAAI,YAAY;IAIzB,QAAQ,IAAI,WAAW;IAIvB,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAMzC;;gEAE4D;IAC5D,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAM9C,UAAU,IAAI,aAAa;IAI3B,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAMxC,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAMlC,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,yBAAyB,GAAG,eAAe;IAI7E,UAAU,IAAI,yBAAyB;IAavC,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAiB3C,SAAS,IAAI,eAAe;IAY5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAa5C,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO;IAoBrF,UAAU,IAAI,KAAK;IAInB,YAAY,IAAI,OAAO;CAGxB;AAED,wBAAgB,sBAAsB,CACpC,MAAM,GAAE,YAAuB,EAC/B,KAAK,GAAE,WAAuB,EAC9B,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,GAAE,aAAsC,GAC9C,eAAe,CAEjB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,eAAe,CAEhG"}
@@ -1,7 +1,11 @@
1
1
  import { addClassNamesToElement } from '@lexical/utils';
2
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';
3
6
  const VALID_LAYOUTS = new Set(['single', 'two-column']);
4
7
  const VALID_ALIGNS = new Set(['justify', 'left', 'right', 'start']);
8
+ const VALID_SPACINGS = new Set(POETRY_SPACINGS);
5
9
  /** `text-align: justify` only stretches a line that actually wraps — a
6
10
  * misra short enough to fit on one line would otherwise just sit at its own
7
11
  * start edge instead of spreading its words across the full column width.
@@ -35,17 +39,18 @@ function applyWidthStyle(element, width) {
35
39
  * fixed templates, per requirements doc §4.11.
36
40
  */
37
41
  export class PoetryBlockNode extends ElementNode {
38
- constructor(layout = 'single', align = 'justify', width, key) {
42
+ constructor(layout = 'single', align = 'justify', width, spacing = DEFAULT_POETRY_SPACING, key) {
39
43
  super(key);
40
44
  this.__layout = layout;
41
45
  this.__align = align;
42
46
  this.__width = width;
47
+ this.__spacing = spacing;
43
48
  }
44
49
  static getType() {
45
50
  return 'poetry-couplet';
46
51
  }
47
52
  static clone(node) {
48
- return new PoetryBlockNode(node.__layout, node.__align, node.__width, node.__key);
53
+ return new PoetryBlockNode(node.__layout, node.__align, node.__width, node.__spacing, node.__key);
49
54
  }
50
55
  getLayout() {
51
56
  return this.getLatest().__layout;
@@ -69,13 +74,21 @@ export class PoetryBlockNode extends ElementNode {
69
74
  writable.__layout = layout;
70
75
  return writable;
71
76
  }
77
+ getSpacing() {
78
+ return this.getLatest().__spacing;
79
+ }
80
+ setSpacing(spacing) {
81
+ const writable = this.getWritable();
82
+ writable.__spacing = spacing;
83
+ return writable;
84
+ }
72
85
  setAlign(align) {
73
86
  const writable = this.getWritable();
74
87
  writable.__align = align;
75
88
  return writable;
76
89
  }
77
90
  static importJSON(serializedNode) {
78
- return $createPoetryBlockNode(serializedNode.layout, serializedNode.align, serializedNode.width);
91
+ return $createPoetryBlockNode(serializedNode.layout, serializedNode.align, serializedNode.width, serializedNode.spacing);
79
92
  }
80
93
  exportJSON() {
81
94
  const width = this.getWidth();
@@ -85,6 +98,7 @@ export class PoetryBlockNode extends ElementNode {
85
98
  version: 1,
86
99
  layout: this.getLayout(),
87
100
  align: this.getAlign(),
101
+ spacing: this.getSpacing(),
88
102
  ...(width !== undefined ? { width } : {}),
89
103
  };
90
104
  }
@@ -99,7 +113,9 @@ export class PoetryBlockNode extends ElementNode {
99
113
  const align = VALID_ALIGNS.has(rawAlign) ? rawAlign : 'justify';
100
114
  const rawWidth = Number(domNode.getAttribute('data-likhari-poetry-width'));
101
115
  const width = Number.isFinite(rawWidth) && rawWidth > 0 ? rawWidth : undefined;
102
- return { conversion: () => ({ node: $createPoetryBlockNode(layout, align, width) }), priority: 2 };
116
+ const rawSpacing = domNode.getAttribute('data-likhari-poetry-spacing');
117
+ const spacing = VALID_SPACINGS.has(rawSpacing) ? rawSpacing : DEFAULT_POETRY_SPACING;
118
+ return { conversion: () => ({ node: $createPoetryBlockNode(layout, align, width, spacing) }), priority: 2 };
103
119
  },
104
120
  };
105
121
  }
@@ -107,6 +123,7 @@ export class PoetryBlockNode extends ElementNode {
107
123
  const element = document.createElement('div');
108
124
  element.setAttribute('data-likhari-poetry-layout', this.getLayout());
109
125
  element.setAttribute('data-likhari-poetry-align', this.getAlign());
126
+ element.setAttribute('data-likhari-poetry-spacing', this.getSpacing());
110
127
  const width = this.getWidth();
111
128
  if (width !== undefined)
112
129
  element.setAttribute('data-likhari-poetry-width', String(width));
@@ -117,7 +134,7 @@ export class PoetryBlockNode extends ElementNode {
117
134
  createDOM(config) {
118
135
  const element = document.createElement('div');
119
136
  const base = config.theme.poetry ?? 'likhari-poetry';
120
- addClassNamesToElement(element, base, `${base}--${this.__layout}`);
137
+ addClassNamesToElement(element, base, `${base}--${this.__layout}`, `${base}--spacing-${this.__spacing}`);
121
138
  applyAlignStyle(element, this.__align);
122
139
  applyWidthStyle(element, this.__width);
123
140
  return element;
@@ -132,6 +149,11 @@ export class PoetryBlockNode extends ElementNode {
132
149
  dom.classList.remove(`${base}--${prevNode.__layout}`);
133
150
  dom.classList.add(`${base}--${this.__layout}`);
134
151
  }
152
+ if (prevNode.__spacing !== this.__spacing) {
153
+ const base = config.theme.poetry ?? 'likhari-poetry';
154
+ dom.classList.remove(`${base}--spacing-${prevNode.__spacing}`);
155
+ dom.classList.add(`${base}--spacing-${this.__spacing}`);
156
+ }
135
157
  if (prevNode.__align !== this.__align) {
136
158
  applyAlignStyle(dom, this.__align);
137
159
  }
@@ -147,8 +169,8 @@ export class PoetryBlockNode extends ElementNode {
147
169
  return true;
148
170
  }
149
171
  }
150
- export function $createPoetryBlockNode(layout = 'single', align = 'justify', width) {
151
- return $applyNodeReplacement(new PoetryBlockNode(layout, align, width));
172
+ export function $createPoetryBlockNode(layout = 'single', align = 'justify', width, spacing = DEFAULT_POETRY_SPACING) {
173
+ return $applyNodeReplacement(new PoetryBlockNode(layout, align, width, spacing));
152
174
  }
153
175
  export function $isPoetryBlockNode(node) {
154
176
  return node instanceof PoetryBlockNode;
@@ -1,5 +1,5 @@
1
1
  import { type ParagraphNode } from 'lexical';
2
- import { type PoetryAlign, type PoetryLayout, type PoetryBlockNode } from './PoetryNode.js';
2
+ import { type PoetryAlign, type PoetryBlockNode, type PoetryLayout } from './PoetryNode.js';
3
3
  /** One couplet's two misra paragraphs, in order. */
4
4
  export type Couplet = [ParagraphNode, ParagraphNode];
5
5
  /**
@@ -17,6 +17,14 @@ export declare function $getCouplets(node: PoetryBlockNode): Couplet[];
17
17
  export declare function $getMisraParagraphs(node: PoetryBlockNode): ParagraphNode[];
18
18
  /** The PoetryBlockNode the current selection is inside, or null. */
19
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;
20
28
  /**
21
29
  * Converts every couplet in the block between single-column (two stacked
22
30
  * misras) and two-column (built on the columns primitive, §4.9) in place —
@@ -36,12 +44,13 @@ export declare function $setPoetryLayout(node: PoetryBlockNode, layout: PoetryLa
36
44
  export declare function $ensureTrailingParagraph(node: PoetryBlockNode): void;
37
45
  /**
38
46
  * Inserts a poetry couplet at the caret. If the caret is already inside a
39
- * poetry block, appends a new couplet to *that* block (in its existing
40
- * layout — "one poetry block can contain one or more couplets, in one or
41
- * two column layout", so a block's layout is fixed once it has couplets,
42
- * not chosen per couplet) and focuses its first misra. Otherwise creates a
43
- * new block (in `layout`/`align`) with one couplet, after the selection's
44
- * top-level element.
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`/`align`) with one
53
+ * couplet, after the selection's top-level element.
45
54
  */
46
55
  export declare function $insertPoetryCouplet(layout: PoetryLayout, align: PoetryAlign): boolean;
47
56
  /** Removes the couplet the selection is inside. If it's the block's only
@@ -79,4 +88,7 @@ export declare function $deletePoetryOnBackspace(): boolean;
79
88
  * next couplet's first misra.
80
89
  */
81
90
  export declare function $exitPoetryOnEnter(): boolean;
91
+ /** Steps the caret's poetry block one notch looser (+1) or tighter (-1) on
92
+ * the couplet-spacing scale; clamps at either end. */
93
+ export declare function $adjustPoetrySpacing(step: 1 | -1): boolean;
82
94
  //# sourceMappingURL=poetryActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"poetryActions.d.ts","sourceRoot":"","sources":["../../src/blocks/poetryActions.ts"],"names":[],"mappings":"AACA,OAAO,EAA4F,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvI,OAAO,EAA8C,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAErI,oDAAoD;AACpD,MAAM,MAAM,OAAO,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAErD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,EAAE,CAgB7D;AAED;;6CAE6C;AAC7C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,EAAE,CAE1E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,eAAe,GAAG,IAAI,CAKrE;AA2BD;;;;;;;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;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAmBtF;AAED;;;;wCAIwC;AACxC,wBAAgB,oBAAoB,IAAI,OAAO,CAwB9C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAqClD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAgD5C"}
1
+ {"version":3,"file":"poetryActions.d.ts","sourceRoot":"","sources":["../../src/blocks/poetryActions.ts"],"names":[],"mappings":"AACA,OAAO,EAA4F,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvI,OAAO,EAIL,KAAK,WAAW,EAChB,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,CAgB7D;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,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAiBtF;AAED;;;;wCAIwC;AACxC,wBAAgB,oBAAoB,IAAI,OAAO,CAwB9C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAqClD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAgD5C;AAED;sDACsD;AACtD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAO1D"}
@@ -1,7 +1,7 @@
1
1
  import { $findMatchingParent } from '@lexical/utils';
2
2
  import { $createParagraphNode, $getSelection, $isElementNode, $isParagraphNode, $isRangeSelection } from 'lexical';
3
3
  import { $createLayoutContainerNode, $createLayoutItemNode, $isLayoutContainerNode, $isLayoutItemNode } from './LayoutNode.js';
4
- import { $createPoetryBlockNode, $isPoetryBlockNode } from './PoetryNode.js';
4
+ import { $createPoetryBlockNode, $isPoetryBlockNode, POETRY_SPACINGS, } from './PoetryNode.js';
5
5
  /**
6
6
  * A poetry block is a *section* of one or more couplets sharing one layout
7
7
  * (single-column stacks each couplet's two misras directly as paragraph
@@ -68,6 +68,63 @@ function $appendCoupletTo(node) {
68
68
  }
69
69
  return [misraA, misraB];
70
70
  }
71
+ /**
72
+ * Inserts a new, empty couplet immediately before or after an existing one —
73
+ * the table-row-insert equivalent for a poetry block ("add/remove couplets
74
+ * just like adding/removing table rows"). `existingFirstMisra` is that
75
+ * couplet's first misra, used to locate its wrapper (nothing, in single
76
+ * layout — just its two sibling paragraphs; a LayoutContainerNode row in
77
+ * two-column) so the new couplet can be spliced in at the right spot
78
+ * regardless of layout.
79
+ */
80
+ function $insertCoupletRelativeTo(existingFirstMisra, layout, position) {
81
+ const misraA = $createParagraphNode();
82
+ const misraB = $createParagraphNode();
83
+ if (layout === 'single') {
84
+ if (position === 'before') {
85
+ existingFirstMisra.insertBefore(misraA);
86
+ misraA.insertAfter(misraB);
87
+ }
88
+ else {
89
+ const existingSecondMisra = existingFirstMisra.getNextSibling() ?? existingFirstMisra;
90
+ existingSecondMisra.insertAfter(misraA);
91
+ misraA.insertAfter(misraB);
92
+ }
93
+ }
94
+ else {
95
+ const container = $findMatchingParent(existingFirstMisra, $isLayoutContainerNode);
96
+ const newContainer = $createLayoutContainerNode('repeat(2, 1fr)');
97
+ newContainer.append($createLayoutItemNode().append(misraA), $createLayoutItemNode().append(misraB));
98
+ if (position === 'before')
99
+ container.insertBefore(newContainer);
100
+ else
101
+ container.insertAfter(newContainer);
102
+ }
103
+ return [misraA, misraB];
104
+ }
105
+ /**
106
+ * The explicit "Insert couplet above/below" menu actions — mirrors the
107
+ * table menu's "Insert row before/after". Targets the couplet the caret is
108
+ * currently in, falling back to the block's last couplet (so the toolbar's
109
+ * always-available insert button has somewhere sensible to act on even
110
+ * without a precise caret position).
111
+ */
112
+ export function $insertCoupletRelativeToSelection(position) {
113
+ const block = $getPoetryBlockFromSelection();
114
+ if (!block)
115
+ return false;
116
+ const selection = $getSelection();
117
+ const couplets = $getCouplets(block);
118
+ const anchorNode = $isRangeSelection(selection) ? selection.anchor.getNode() : null;
119
+ const found = anchorNode ? $findCoupletPosition(couplets, anchorNode) : null;
120
+ const index = found ? found.coupletIndex : couplets.length - 1;
121
+ const target = couplets[index];
122
+ if (!target)
123
+ return false;
124
+ const [newA] = $insertCoupletRelativeTo(target[0], block.getLayout(), position);
125
+ newA.selectStart();
126
+ return true;
127
+ }
71
128
  /**
72
129
  * Converts every couplet in the block between single-column (two stacked
73
130
  * misras) and two-column (built on the columns primitive, §4.9) in place —
@@ -112,12 +169,13 @@ export function $ensureTrailingParagraph(node) {
112
169
  }
113
170
  /**
114
171
  * Inserts a poetry couplet at the caret. If the caret is already inside a
115
- * poetry block, appends a new couplet to *that* block (in its existing
116
- * layout — "one poetry block can contain one or more couplets, in one or
117
- * two column layout", so a block's layout is fixed once it has couplets,
118
- * not chosen per couplet) and focuses its first misra. Otherwise creates a
119
- * new block (in `layout`/`align`) with one couplet, after the selection's
120
- * top-level element.
172
+ * poetry block, inserts a new couplet right after the one the caret is in
173
+ * (same as the "Insert couplet below" menu action — table-row-insert
174
+ * semantics, in its existing layout: "one poetry block can contain one or
175
+ * more couplets, in one or two column layout", so a block's layout is
176
+ * fixed once it has couplets, not chosen per couplet) and focuses its first
177
+ * misra. Otherwise creates a new block (in `layout`/`align`) with one
178
+ * couplet, after the selection's top-level element.
121
179
  */
122
180
  export function $insertPoetryCouplet(layout, align) {
123
181
  const selection = $getSelection();
@@ -125,9 +183,7 @@ export function $insertPoetryCouplet(layout, align) {
125
183
  return false;
126
184
  const existing = $getPoetryBlockFromSelection();
127
185
  if (existing) {
128
- const [misraA] = $appendCoupletTo(existing);
129
- misraA.selectStart();
130
- return true;
186
+ return $insertCoupletRelativeToSelection('after');
131
187
  }
132
188
  const anchorTopLevel = selection.anchor.getNode().getTopLevelElementOrThrow();
133
189
  const node = $createPoetryBlockNode(layout, align);
@@ -280,3 +336,14 @@ export function $exitPoetryOnEnter() {
280
336
  newA.selectStart();
281
337
  return true;
282
338
  }
339
+ /** Steps the caret's poetry block one notch looser (+1) or tighter (-1) on
340
+ * the couplet-spacing scale; clamps at either end. */
341
+ export function $adjustPoetrySpacing(step) {
342
+ const block = $getPoetryBlockFromSelection();
343
+ if (!block)
344
+ return false;
345
+ const index = POETRY_SPACINGS.indexOf(block.getSpacing());
346
+ const next = POETRY_SPACINGS[Math.min(POETRY_SPACINGS.length - 1, Math.max(0, index + step))];
347
+ block.setSpacing(next);
348
+ return true;
349
+ }
@@ -1 +1 @@
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;AA4evD,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,+BA+jCxJ"}
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AAuEA,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;AAsfvD,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,+BA+jCxJ"}
@@ -15,7 +15,7 @@ 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
17
  import { $isPoetryBlockNode } from '../blocks/PoetryNode.js';
18
- import { $deletePoetryCouplet, $getPoetryBlockFromSelection, $setPoetryLayout } from '../blocks/poetryActions.js';
18
+ import { $adjustPoetrySpacing, $deletePoetryCouplet, $getPoetryBlockFromSelection, $insertCoupletRelativeToSelection, $setPoetryLayout, } from '../blocks/poetryActions.js';
19
19
  import { INSERT_POETRY_COUPLET_COMMAND } from '../plugins/PoetryPlugin.js';
20
20
  import { TableDialog } from './TableDialog.js';
21
21
  import { LayoutDialog } from './LayoutDialog.js';
@@ -29,7 +29,7 @@ import { CANVAS_FONT_DEFAULTS, DEFAULT_FONT_OPTIONS, FONT_SIZES_PX } from '../fo
29
29
  import { setStyleProperty } from '../utils/style.js';
30
30
  import { useStrings } from '../i18n/useStrings.js';
31
31
  import { usePortalTarget } from '../PortalTargetContext.js';
32
- 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, IconTrash, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
32
+ 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, IconArrowsMaximize, IconArrowsMinimize, IconTable, IconTableMinus, IconTrash, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
33
33
  /** Sentinel for "no inline style": Lexical returns the default it is given when
34
34
  * the selection has none, so this tells "unstyled" (show the canvas default)
35
35
  * apart from "styled with a value the dropdown doesn't list" (show nothing). */
@@ -164,7 +164,11 @@ function TableMenuItems({ strings, direction, rows, columns, canMergeCells, canU
164
164
  }
165
165
  /** The poetry couplet menu's contents — layout (single/two-column) and
166
166
  * literal alignment, both per-instance overrides (requirements doc §4.11:
167
- * "set per CoupletNode, not inherited from a document-wide setting"). */
167
+ * "set per CoupletNode, not inherited from a document-wide setting"), plus
168
+ * table-row-style structural actions (insert a couplet above/below the one
169
+ * the caret is in, delete it) — a poetry block is "one object with multiple
170
+ * couplets, add/remove like table rows", so these mirror TableMenuItems'
171
+ * own insert-before/insert-after/delete-row actions. */
168
172
  function PoetryMenuItems({ strings, alignIcons, layout, align, onAction, }) {
169
173
  const t = strings.poetryMenu;
170
174
  const a = strings.toolbar.alignOptions;
@@ -180,7 +184,7 @@ function PoetryMenuItems({ strings, alignIcons, layout, align, onAction, }) {
180
184
  const setAlign = (next) => () => {
181
185
  $getPoetryBlockFromSelection()?.setAlign(next);
182
186
  };
183
- 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'), _jsx(Menu.Divider, {}), item(IconTrash, t.deleteCouplet, $deletePoetryCouplet, false, 'red')] }));
187
+ 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'), _jsx(Menu.Divider, {}), item(IconRowInsertTop, t.insertCoupletBefore, () => $insertCoupletRelativeToSelection('before')), item(IconRowInsertBottom, t.insertCoupletAfter, () => $insertCoupletRelativeToSelection('after')), item(IconArrowsMinimize, t.tighterSpacing, () => $adjustPoetrySpacing(-1)), item(IconArrowsMaximize, t.looserSpacing, () => $adjustPoetrySpacing(1)), item(IconTrash, t.deleteCouplet, $deletePoetryCouplet, false, 'red')] }));
184
188
  }
185
189
  export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
186
190
  const [editor] = useLexicalComposerContext();
@@ -142,6 +142,10 @@ export interface Strings {
142
142
  menuLabel: string;
143
143
  singleColumn: string;
144
144
  twoColumn: string;
145
+ insertCoupletBefore: string;
146
+ insertCoupletAfter: string;
147
+ tighterSpacing: string;
148
+ looserSpacing: string;
145
149
  deleteCouplet: string;
146
150
  };
147
151
  link: {
@@ -1 +1 @@
1
- {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
@@ -125,6 +125,10 @@ const en = {
125
125
  menuLabel: 'Poetry',
126
126
  singleColumn: 'Single column',
127
127
  twoColumn: 'Two column',
128
+ insertCoupletBefore: 'Insert couplet above',
129
+ insertCoupletAfter: 'Insert couplet below',
130
+ tighterSpacing: 'Tighter couplet spacing',
131
+ looserSpacing: 'Looser couplet spacing',
128
132
  deleteCouplet: 'Delete couplet',
129
133
  },
130
134
  link: {
@@ -333,6 +337,10 @@ const ur = {
333
337
  menuLabel: 'شاعری',
334
338
  singleColumn: 'ایک کالم',
335
339
  twoColumn: 'دو کالم',
340
+ insertCoupletBefore: 'اوپر شعر شامل کریں',
341
+ insertCoupletAfter: 'نیچے شعر شامل کریں',
342
+ tighterSpacing: 'شعروں کے درمیان کم جگہ',
343
+ looserSpacing: 'شعروں کے درمیان زیادہ جگہ',
336
344
  deleteCouplet: 'شعر حذف کریں',
337
345
  },
338
346
  link: {
@@ -541,6 +549,10 @@ const paShahmukhi = {
541
549
  menuLabel: 'شاعری',
542
550
  singleColumn: 'اک کالم',
543
551
  twoColumn: 'دو کالم',
552
+ insertCoupletBefore: 'اُتے شعر شامل کرو',
553
+ insertCoupletAfter: 'ھیٹھ شعر شامل کرو',
554
+ tighterSpacing: 'شعراں وچکار گھٹ جگہ',
555
+ looserSpacing: 'شعراں وچکار ودھ جگہ',
544
556
  deleteCouplet: 'شعر مٹاؤ',
545
557
  },
546
558
  link: {
@@ -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;AAalD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAkB5C,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;AAclD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAmB5C,CAAC"}
package/dist/nodes.js CHANGED
@@ -9,6 +9,7 @@ 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
11
  import { PoetryBlockNode } from './blocks/PoetryNode.js';
12
+ import { PoetryCoupletNode } from './blocks/PoetryCoupletNode.js';
12
13
  /**
13
14
  * Node types registered on the editor at construction time. Per
14
15
  * editor-architecture-design.md §2, node registration cannot be conditional
@@ -36,4 +37,5 @@ export const EDITOR_NODES = [
36
37
  FootnoteListNode,
37
38
  FootnoteItemNode,
38
39
  PoetryBlockNode,
40
+ PoetryCoupletNode,
39
41
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"PoetryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PoetryPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAGjB,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;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,SA4C3B"}
1
+ {"version":3,"file":"PoetryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PoetryPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAIjB,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;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,SA4C3B"}
@@ -3,6 +3,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
3
3
  import { COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, KEY_BACKSPACE_COMMAND, KEY_ENTER_COMMAND, createCommand, } from 'lexical';
4
4
  import { mergeRegister } from '@lexical/utils';
5
5
  import { LayoutContainerNode, LayoutItemNode } from '../blocks/LayoutNode.js';
6
+ import { PoetryCoupletNode } from '../blocks/PoetryCoupletNode.js';
6
7
  import { PoetryBlockNode } from '../blocks/PoetryNode.js';
7
8
  import { $deletePoetryOnBackspace, $ensureTrailingParagraph, $exitPoetryOnEnter, $insertPoetryCouplet } from '../blocks/poetryActions.js';
8
9
  export const INSERT_POETRY_COUPLET_COMMAND = createCommand('INSERT_POETRY_COUPLET_COMMAND');
@@ -21,8 +22,8 @@ export const INSERT_POETRY_COUPLET_COMMAND = createCommand('INSERT_POETRY_COUPLE
21
22
  export function PoetryPlugin() {
22
23
  const [editor] = useLexicalComposerContext();
23
24
  useEffect(() => {
24
- if (!editor.hasNodes([PoetryBlockNode, LayoutContainerNode, LayoutItemNode])) {
25
- throw new Error('PoetryPlugin: PoetryBlockNode (and the columns nodes it composes) not registered on the editor');
25
+ if (!editor.hasNodes([PoetryBlockNode, PoetryCoupletNode, LayoutContainerNode, LayoutItemNode])) {
26
+ throw new Error('PoetryPlugin: PoetryBlockNode/PoetryCoupletNode (and the columns nodes two-column composes) not registered on the editor');
26
27
  }
27
28
  return mergeRegister(editor.registerCommand(INSERT_POETRY_COUPLET_COMMAND, ({ layout, align }) => $insertPoetryCouplet(layout, align), COMMAND_PRIORITY_EDITOR), editor.registerNodeTransform(PoetryBlockNode, (node) => {
28
29
  if (node.getChildrenSize() === 0) {
@@ -407,29 +407,43 @@
407
407
  /* Misra lines sit tight against each other within a couplet — the generic
408
408
  .likhari-paragraph margin would otherwise add the same gap between a
409
409
  couplet's own two lines as between separate couplets within the same
410
- block, losing the pairing entirely. Re-added below on every *second*
411
- line (nth-child(2n)) — one couplet's worth of lines — so the extra space
412
- falls after every couplet, not after every single line. */
410
+ block, losing the pairing entirely. */
413
411
  .likhari-poetry .likhari-paragraph {
414
412
  margin: 0;
415
413
  }
416
414
 
417
- .likhari-poetry--single .likhari-paragraph:nth-child(2n):not(:last-child) {
418
- margin-bottom: 1em;
415
+ /* A poetry block is "one object with multiple couplets, add/remove like
416
+ table rows" — so couplet boundaries get the same visible divider as a
417
+ table's internal row borders, not just extra space. Every couplet but
418
+ the first (nth-child(odd), since each couplet is two paragraph
419
+ children — its first misra always lands on an odd position) gets a
420
+ border-top in place of the previous couplet's margin-bottom. */
421
+ .likhari-poetry--single .likhari-paragraph:nth-child(odd):not(:first-child) {
422
+ border-top: 1px dashed var(--editor-line-strong);
423
+ margin-top: var(--poetry-couplet-gap);
424
+ padding-top: calc(var(--poetry-couplet-gap) * 0.6);
419
425
  }
420
426
 
427
+ .likhari-poetry--spacing-compact { --poetry-couplet-gap: 0.4em; }
428
+ .likhari-poetry--spacing-normal { --poetry-couplet-gap: 1em; }
429
+ .likhari-poetry--spacing-relaxed { --poetry-couplet-gap: 1.8em; }
430
+ .likhari-poetry--spacing-loose { --poetry-couplet-gap: 2.8em; }
431
+
421
432
  .likhari-poetry--two-column .likhari-layout-container {
422
433
  margin: 0;
423
- /* No grid gap — the divider below sits exactly on the track boundary, so
424
- spacing instead comes from matching padding on each side of it, which
425
- keeps the gutter visually even on both sides of the line. */
434
+ /* No grid gap — the column divider sits exactly on the track boundary,
435
+ so spacing instead comes from matching padding on each side of it,
436
+ which keeps the gutter visually even on both sides of the line. */
426
437
  gap: 0;
427
438
  }
428
439
 
429
- /* One row per couplet in two-column layout — same "extra space after every
430
- couplet" rhythm as the single-column rule above. */
431
- .likhari-poetry--two-column .likhari-layout-container:not(:last-child) {
432
- margin-bottom: 1em;
440
+ /* One row per couplet in two-column layout — same table-row-border
441
+ treatment as the single-column rule above, between couplets instead of
442
+ within one. */
443
+ .likhari-poetry--two-column .likhari-layout-container:not(:first-child) {
444
+ border-top: 1px dashed var(--editor-line-strong);
445
+ margin-top: var(--poetry-couplet-gap);
446
+ padding-top: calc(var(--poetry-couplet-gap) * 0.6);
433
447
  }
434
448
 
435
449
  .likhari-poetry--two-column .likhari-layout-item {
@@ -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,kBAgDzB,CAAC"}
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,kBAiDzB,CAAC"}
@@ -46,6 +46,7 @@ export const editorTheme = {
46
46
  footnoteList: 'likhari-footnote-list',
47
47
  footnoteItem: 'likhari-footnote-item',
48
48
  poetry: 'likhari-poetry',
49
+ poetryCouplet: 'likhari-poetry-couplet',
49
50
  table: 'likhari-table',
50
51
  tableRow: 'likhari-table-row',
51
52
  tableCell: 'likhari-table-cell',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inshapardaz/likhari-react",
3
- "version": "0.1.18-dev.152",
3
+ "version": "0.1.18-dev.156",
4
4
  "description": "React implementation of the Likhari editor, built on @lexical/react.",
5
5
  "license": "MIT",
6
6
  "repository": {