@inshapardaz/likhari-react 0.1.18-dev.158 → 0.1.18-dev.162
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/blocks/PoetryNode.d.ts +24 -13
- package/dist/blocks/PoetryNode.d.ts.map +1 -1
- package/dist/blocks/PoetryNode.js +64 -43
- package/dist/blocks/poetryActions.d.ts +35 -12
- package/dist/blocks/poetryActions.d.ts.map +1 -1
- package/dist/blocks/poetryActions.js +175 -43
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +22 -22
- package/dist/i18n/strings.d.ts +8 -0
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +24 -0
- package/dist/plugins/PoetryPlugin.d.ts +1 -2
- package/dist/plugins/PoetryPlugin.d.ts.map +1 -1
- package/dist/plugins/PoetryPlugin.js +9 -3
- package/dist/theme/editor.css +48 -2
- package/package.json +1 -1
|
@@ -1,15 +1,23 @@
|
|
|
1
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';
|
|
2
|
+
export type PoetryLayout = 'single' | 'two-column' | 'staggered';
|
|
4
3
|
/** Vertical space between couplets — an ordered scale the menu steps through. */
|
|
5
4
|
export declare const POETRY_SPACINGS: readonly ["compact", "normal", "relaxed", "loose"];
|
|
6
5
|
export type PoetrySpacing = (typeof POETRY_SPACINGS)[number];
|
|
7
6
|
export declare const DEFAULT_POETRY_SPACING: PoetrySpacing;
|
|
7
|
+
/** Horizontal space either side of the divider in two-column layout. */
|
|
8
|
+
export declare const POETRY_GUTTERS: readonly ["compact", "normal", "relaxed", "loose"];
|
|
9
|
+
export type PoetryGutter = (typeof POETRY_GUTTERS)[number];
|
|
10
|
+
export declare const DEFAULT_POETRY_GUTTER: PoetryGutter;
|
|
11
|
+
/** Width of each couplet box in staggered layout, as a share of the block. */
|
|
12
|
+
export declare const POETRY_STAGGERS: readonly ["compact", "normal", "relaxed", "loose"];
|
|
13
|
+
export type PoetryStagger = (typeof POETRY_STAGGERS)[number];
|
|
14
|
+
export declare const DEFAULT_POETRY_STAGGER: PoetryStagger;
|
|
8
15
|
export type SerializedPoetryBlockNode = Spread<{
|
|
9
16
|
layout: PoetryLayout;
|
|
10
|
-
align: PoetryAlign;
|
|
11
17
|
width?: number;
|
|
12
18
|
spacing?: PoetrySpacing;
|
|
19
|
+
gutter?: PoetryGutter;
|
|
20
|
+
stagger?: PoetryStagger;
|
|
13
21
|
}, SerializedElementNode>;
|
|
14
22
|
/**
|
|
15
23
|
* A poetry *section*: one or more couplets (two-line verse units) sharing
|
|
@@ -18,24 +26,24 @@ export type SerializedPoetryBlockNode = Spread<{
|
|
|
18
26
|
* couplet its own LayoutContainerNode row (built on the columns primitive,
|
|
19
27
|
* §4.9) — see blocks/poetryActions.ts's $getCouplets for how either shape
|
|
20
28
|
* is read, and $setPoetryLayout/$exitPoetryOnEnter for how children are
|
|
21
|
-
* restructured/grown between couplets and layouts. `layout`
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
29
|
+
* restructured/grown between couplets and layouts. `layout` applies to the
|
|
30
|
+
* whole section, not per couplet, and mutates in place via poetryActions so
|
|
31
|
+
* converting a section between layouts doesn't lose selection/undo
|
|
32
|
+
* coherence. One extensible primitive in place of four fixed templates,
|
|
33
|
+
* per requirements doc §4.11.
|
|
26
34
|
*/
|
|
27
35
|
export declare class PoetryBlockNode extends ElementNode {
|
|
28
36
|
__layout: PoetryLayout;
|
|
29
|
-
__align: PoetryAlign;
|
|
30
37
|
/** User-chosen width in px (drag-resized), overriding editor.css's default
|
|
31
38
|
* max-width: 70%. Undefined until the user resizes it. */
|
|
32
39
|
__width?: number;
|
|
33
40
|
__spacing: PoetrySpacing;
|
|
34
|
-
|
|
41
|
+
__gutter: PoetryGutter;
|
|
42
|
+
__stagger: PoetryStagger;
|
|
43
|
+
constructor(layout?: PoetryLayout, width?: number, spacing?: PoetrySpacing, gutter?: PoetryGutter, stagger?: PoetryStagger, key?: NodeKey);
|
|
35
44
|
static getType(): string;
|
|
36
45
|
static clone(node: PoetryBlockNode): PoetryBlockNode;
|
|
37
46
|
getLayout(): PoetryLayout;
|
|
38
|
-
getAlign(): PoetryAlign;
|
|
39
47
|
getWidth(): number | undefined;
|
|
40
48
|
setWidth(width: number | undefined): this;
|
|
41
49
|
/** Attribute-only — restructuring children for a layout change is
|
|
@@ -44,7 +52,10 @@ export declare class PoetryBlockNode extends ElementNode {
|
|
|
44
52
|
setLayoutAttribute(layout: PoetryLayout): this;
|
|
45
53
|
getSpacing(): PoetrySpacing;
|
|
46
54
|
setSpacing(spacing: PoetrySpacing): this;
|
|
47
|
-
|
|
55
|
+
getGutter(): PoetryGutter;
|
|
56
|
+
setGutter(gutter: PoetryGutter): this;
|
|
57
|
+
getStagger(): PoetryStagger;
|
|
58
|
+
setStagger(stagger: PoetryStagger): this;
|
|
48
59
|
static importJSON(serializedNode: SerializedPoetryBlockNode): PoetryBlockNode;
|
|
49
60
|
exportJSON(): SerializedPoetryBlockNode;
|
|
50
61
|
static importDOM(): DOMConversionMap | null;
|
|
@@ -54,6 +65,6 @@ export declare class PoetryBlockNode extends ElementNode {
|
|
|
54
65
|
canBeEmpty(): false;
|
|
55
66
|
isShadowRoot(): boolean;
|
|
56
67
|
}
|
|
57
|
-
export declare function $createPoetryBlockNode(layout?: PoetryLayout,
|
|
68
|
+
export declare function $createPoetryBlockNode(layout?: PoetryLayout, width?: number, spacing?: PoetrySpacing, gutter?: PoetryGutter, stagger?: PoetryStagger): PoetryBlockNode;
|
|
58
69
|
export declare function $isPoetryBlockNode(node: LexicalNode | null | undefined): node is PoetryBlockNode;
|
|
59
70
|
//# 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;
|
|
1
|
+
{"version":3,"file":"PoetryNode.d.ts","sourceRoot":"","sources":["../../src/blocks/PoetryNode.tsx"],"names":[],"mappings":"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"}
|
|
@@ -3,18 +3,22 @@ import { $applyNodeReplacement, ElementNode, } from 'lexical';
|
|
|
3
3
|
/** Vertical space between couplets — an ordered scale the menu steps through. */
|
|
4
4
|
export const POETRY_SPACINGS = ['compact', 'normal', 'relaxed', 'loose'];
|
|
5
5
|
export const DEFAULT_POETRY_SPACING = 'normal';
|
|
6
|
-
|
|
7
|
-
const
|
|
6
|
+
/** Horizontal space either side of the divider in two-column layout. */
|
|
7
|
+
export const POETRY_GUTTERS = ['compact', 'normal', 'relaxed', 'loose'];
|
|
8
|
+
export const DEFAULT_POETRY_GUTTER = 'normal';
|
|
9
|
+
/** Width of each couplet box in staggered layout, as a share of the block. */
|
|
10
|
+
export const POETRY_STAGGERS = ['compact', 'normal', 'relaxed', 'loose'];
|
|
11
|
+
export const DEFAULT_POETRY_STAGGER = 'normal';
|
|
12
|
+
const VALID_LAYOUTS = new Set(['single', 'two-column', 'staggered']);
|
|
8
13
|
const VALID_SPACINGS = new Set(POETRY_SPACINGS);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
element.style.
|
|
17
|
-
element.style.textAlignLast = align === 'justify' ? 'justify' : '';
|
|
14
|
+
const VALID_GUTTERS = new Set(POETRY_GUTTERS);
|
|
15
|
+
const VALID_STAGGERS = new Set(POETRY_STAGGERS);
|
|
16
|
+
/** Poetry is always justified: `text-align-last: justify` stretches a
|
|
17
|
+
* one-line misra across the full column width too, not just wrapped lines,
|
|
18
|
+
* so every line reads edge-to-edge. */
|
|
19
|
+
function applyJustifyStyle(element) {
|
|
20
|
+
element.style.textAlign = 'justify';
|
|
21
|
+
element.style.textAlignLast = 'justify';
|
|
18
22
|
}
|
|
19
23
|
/** A user-dragged width overrides editor.css's default max-width: 70% —
|
|
20
24
|
* clearing the inline style (rather than setting it to that same 70%)
|
|
@@ -32,32 +36,30 @@ function applyWidthStyle(element, width) {
|
|
|
32
36
|
* couplet its own LayoutContainerNode row (built on the columns primitive,
|
|
33
37
|
* §4.9) — see blocks/poetryActions.ts's $getCouplets for how either shape
|
|
34
38
|
* is read, and $setPoetryLayout/$exitPoetryOnEnter for how children are
|
|
35
|
-
* restructured/grown between couplets and layouts. `layout`
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
39
|
+
* restructured/grown between couplets and layouts. `layout` applies to the
|
|
40
|
+
* whole section, not per couplet, and mutates in place via poetryActions so
|
|
41
|
+
* converting a section between layouts doesn't lose selection/undo
|
|
42
|
+
* coherence. One extensible primitive in place of four fixed templates,
|
|
43
|
+
* per requirements doc §4.11.
|
|
40
44
|
*/
|
|
41
45
|
export class PoetryBlockNode extends ElementNode {
|
|
42
|
-
constructor(layout = 'single',
|
|
46
|
+
constructor(layout = 'single', width, spacing = DEFAULT_POETRY_SPACING, gutter = DEFAULT_POETRY_GUTTER, stagger = DEFAULT_POETRY_STAGGER, key) {
|
|
43
47
|
super(key);
|
|
44
48
|
this.__layout = layout;
|
|
45
|
-
this.__align = align;
|
|
46
49
|
this.__width = width;
|
|
47
50
|
this.__spacing = spacing;
|
|
51
|
+
this.__gutter = gutter;
|
|
52
|
+
this.__stagger = stagger;
|
|
48
53
|
}
|
|
49
54
|
static getType() {
|
|
50
55
|
return 'poetry-couplet';
|
|
51
56
|
}
|
|
52
57
|
static clone(node) {
|
|
53
|
-
return new PoetryBlockNode(node.__layout, node.
|
|
58
|
+
return new PoetryBlockNode(node.__layout, node.__width, node.__spacing, node.__gutter, node.__stagger, node.__key);
|
|
54
59
|
}
|
|
55
60
|
getLayout() {
|
|
56
61
|
return this.getLatest().__layout;
|
|
57
62
|
}
|
|
58
|
-
getAlign() {
|
|
59
|
-
return this.getLatest().__align;
|
|
60
|
-
}
|
|
61
63
|
getWidth() {
|
|
62
64
|
return this.getLatest().__width;
|
|
63
65
|
}
|
|
@@ -82,13 +84,24 @@ export class PoetryBlockNode extends ElementNode {
|
|
|
82
84
|
writable.__spacing = spacing;
|
|
83
85
|
return writable;
|
|
84
86
|
}
|
|
85
|
-
|
|
87
|
+
getGutter() {
|
|
88
|
+
return this.getLatest().__gutter;
|
|
89
|
+
}
|
|
90
|
+
setGutter(gutter) {
|
|
91
|
+
const writable = this.getWritable();
|
|
92
|
+
writable.__gutter = gutter;
|
|
93
|
+
return writable;
|
|
94
|
+
}
|
|
95
|
+
getStagger() {
|
|
96
|
+
return this.getLatest().__stagger;
|
|
97
|
+
}
|
|
98
|
+
setStagger(stagger) {
|
|
86
99
|
const writable = this.getWritable();
|
|
87
|
-
writable.
|
|
100
|
+
writable.__stagger = stagger;
|
|
88
101
|
return writable;
|
|
89
102
|
}
|
|
90
103
|
static importJSON(serializedNode) {
|
|
91
|
-
return $createPoetryBlockNode(serializedNode.layout, serializedNode.
|
|
104
|
+
return $createPoetryBlockNode(serializedNode.layout, serializedNode.width, serializedNode.spacing, serializedNode.gutter, serializedNode.stagger);
|
|
92
105
|
}
|
|
93
106
|
exportJSON() {
|
|
94
107
|
const width = this.getWidth();
|
|
@@ -97,8 +110,9 @@ export class PoetryBlockNode extends ElementNode {
|
|
|
97
110
|
type: 'poetry-couplet',
|
|
98
111
|
version: 1,
|
|
99
112
|
layout: this.getLayout(),
|
|
100
|
-
align: this.getAlign(),
|
|
101
113
|
spacing: this.getSpacing(),
|
|
114
|
+
gutter: this.getGutter(),
|
|
115
|
+
stagger: this.getStagger(),
|
|
102
116
|
...(width !== undefined ? { width } : {}),
|
|
103
117
|
};
|
|
104
118
|
}
|
|
@@ -109,53 +123,60 @@ export class PoetryBlockNode extends ElementNode {
|
|
|
109
123
|
if (!rawLayout)
|
|
110
124
|
return null;
|
|
111
125
|
const layout = VALID_LAYOUTS.has(rawLayout) ? rawLayout : 'single';
|
|
112
|
-
const rawAlign = domNode.getAttribute('data-likhari-poetry-align') ?? 'justify';
|
|
113
|
-
const align = VALID_ALIGNS.has(rawAlign) ? rawAlign : 'justify';
|
|
114
126
|
const rawWidth = Number(domNode.getAttribute('data-likhari-poetry-width'));
|
|
115
127
|
const width = Number.isFinite(rawWidth) && rawWidth > 0 ? rawWidth : undefined;
|
|
116
128
|
const rawSpacing = domNode.getAttribute('data-likhari-poetry-spacing');
|
|
117
129
|
const spacing = VALID_SPACINGS.has(rawSpacing) ? rawSpacing : DEFAULT_POETRY_SPACING;
|
|
118
|
-
|
|
130
|
+
const rawGutter = domNode.getAttribute('data-likhari-poetry-gutter');
|
|
131
|
+
const gutter = VALID_GUTTERS.has(rawGutter) ? rawGutter : DEFAULT_POETRY_GUTTER;
|
|
132
|
+
const rawStagger = domNode.getAttribute('data-likhari-poetry-stagger');
|
|
133
|
+
const stagger = VALID_STAGGERS.has(rawStagger) ? rawStagger : DEFAULT_POETRY_STAGGER;
|
|
134
|
+
return { conversion: () => ({ node: $createPoetryBlockNode(layout, width, spacing, gutter, stagger) }), priority: 2 };
|
|
119
135
|
},
|
|
120
136
|
};
|
|
121
137
|
}
|
|
122
138
|
exportDOM() {
|
|
123
139
|
const element = document.createElement('div');
|
|
124
140
|
element.setAttribute('data-likhari-poetry-layout', this.getLayout());
|
|
125
|
-
element.setAttribute('data-likhari-poetry-align', this.getAlign());
|
|
126
141
|
element.setAttribute('data-likhari-poetry-spacing', this.getSpacing());
|
|
142
|
+
element.setAttribute('data-likhari-poetry-gutter', this.getGutter());
|
|
143
|
+
element.setAttribute('data-likhari-poetry-stagger', this.getStagger());
|
|
127
144
|
const width = this.getWidth();
|
|
128
145
|
if (width !== undefined)
|
|
129
146
|
element.setAttribute('data-likhari-poetry-width', String(width));
|
|
130
|
-
|
|
147
|
+
applyJustifyStyle(element);
|
|
131
148
|
applyWidthStyle(element, width);
|
|
132
149
|
return { element };
|
|
133
150
|
}
|
|
134
151
|
createDOM(config) {
|
|
135
152
|
const element = document.createElement('div');
|
|
136
153
|
const base = config.theme.poetry ?? 'likhari-poetry';
|
|
137
|
-
addClassNamesToElement(element, base, `${base}--${this.__layout}`, `${base}--spacing-${this.__spacing}`);
|
|
138
|
-
|
|
154
|
+
addClassNamesToElement(element, base, `${base}--${this.__layout}`, `${base}--spacing-${this.__spacing}`, `${base}--gutter-${this.__gutter}`, `${base}--stagger-${this.__stagger}`);
|
|
155
|
+
applyJustifyStyle(element);
|
|
139
156
|
applyWidthStyle(element, this.__width);
|
|
140
157
|
return element;
|
|
141
158
|
}
|
|
142
|
-
// Only ever adds/removes
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
//
|
|
159
|
+
// Only ever adds/removes modifier classes, never touches the element's full
|
|
160
|
+
// className — the reconciler separately classList.adds the per-block ltr/rtl
|
|
161
|
+
// theme class (editor.css) onto this same element, and a wholesale className
|
|
162
|
+
// reassignment here would silently wipe it out.
|
|
146
163
|
updateDOM(prevNode, dom, config) {
|
|
164
|
+
const base = config.theme.poetry ?? 'likhari-poetry';
|
|
147
165
|
if (prevNode.__layout !== this.__layout) {
|
|
148
|
-
const base = config.theme.poetry ?? 'likhari-poetry';
|
|
149
166
|
dom.classList.remove(`${base}--${prevNode.__layout}`);
|
|
150
167
|
dom.classList.add(`${base}--${this.__layout}`);
|
|
151
168
|
}
|
|
152
169
|
if (prevNode.__spacing !== this.__spacing) {
|
|
153
|
-
const base = config.theme.poetry ?? 'likhari-poetry';
|
|
154
170
|
dom.classList.remove(`${base}--spacing-${prevNode.__spacing}`);
|
|
155
171
|
dom.classList.add(`${base}--spacing-${this.__spacing}`);
|
|
156
172
|
}
|
|
157
|
-
if (prevNode.
|
|
158
|
-
|
|
173
|
+
if (prevNode.__gutter !== this.__gutter) {
|
|
174
|
+
dom.classList.remove(`${base}--gutter-${prevNode.__gutter}`);
|
|
175
|
+
dom.classList.add(`${base}--gutter-${this.__gutter}`);
|
|
176
|
+
}
|
|
177
|
+
if (prevNode.__stagger !== this.__stagger) {
|
|
178
|
+
dom.classList.remove(`${base}--stagger-${prevNode.__stagger}`);
|
|
179
|
+
dom.classList.add(`${base}--stagger-${this.__stagger}`);
|
|
159
180
|
}
|
|
160
181
|
if (prevNode.__width !== this.__width) {
|
|
161
182
|
applyWidthStyle(dom, this.__width);
|
|
@@ -169,8 +190,8 @@ export class PoetryBlockNode extends ElementNode {
|
|
|
169
190
|
return true;
|
|
170
191
|
}
|
|
171
192
|
}
|
|
172
|
-
export function $createPoetryBlockNode(layout = 'single',
|
|
173
|
-
return $applyNodeReplacement(new PoetryBlockNode(layout,
|
|
193
|
+
export function $createPoetryBlockNode(layout = 'single', width, spacing = DEFAULT_POETRY_SPACING, gutter = DEFAULT_POETRY_GUTTER, stagger = DEFAULT_POETRY_STAGGER) {
|
|
194
|
+
return $applyNodeReplacement(new PoetryBlockNode(layout, width, spacing, gutter, stagger));
|
|
174
195
|
}
|
|
175
196
|
export function $isPoetryBlockNode(node) {
|
|
176
197
|
return node instanceof PoetryBlockNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ParagraphNode } from 'lexical';
|
|
2
|
-
import { type
|
|
2
|
+
import { 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
|
/**
|
|
@@ -49,10 +49,10 @@ export declare function $ensureTrailingParagraph(node: PoetryBlockNode): void;
|
|
|
49
49
|
* semantics, in its existing layout: "one poetry block can contain one or
|
|
50
50
|
* more couplets, in one or two column layout", so a block's layout is
|
|
51
51
|
* fixed once it has couplets, not chosen per couplet) and focuses its first
|
|
52
|
-
* misra. Otherwise creates a new block (in `layout
|
|
52
|
+
* misra. Otherwise creates a new block (in `layout`) with one
|
|
53
53
|
* couplet, after the selection's top-level element.
|
|
54
54
|
*/
|
|
55
|
-
export declare function $insertPoetryCouplet(layout: PoetryLayout
|
|
55
|
+
export declare function $insertPoetryCouplet(layout: PoetryLayout): boolean;
|
|
56
56
|
/** Removes the couplet the selection is inside. If it's the block's only
|
|
57
57
|
* couplet, removes the whole block (an empty poetry section serves no
|
|
58
58
|
* purpose) — the explicit, always-available counterpart to
|
|
@@ -60,17 +60,21 @@ export declare function $insertPoetryCouplet(layout: PoetryLayout, align: Poetry
|
|
|
60
60
|
* menu's own "Delete table" action). */
|
|
61
61
|
export declare function $deletePoetryCouplet(): boolean;
|
|
62
62
|
/**
|
|
63
|
-
* Backspace at the
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* other caret position, including a non-empty couplet, so normal Backspace
|
|
71
|
-
* handling (e.g. deleting within text) proceeds.
|
|
63
|
+
* Backspace at the start of a misra never merges it into its neighbour: the
|
|
64
|
+
* block's lines are paired into couplets, so merging one line away would
|
|
65
|
+
* shift every couplet after it (and take the previous couplet's last line
|
|
66
|
+
* with it). Instead, Backspace at the start of an empty couplet removes that
|
|
67
|
+
* couplet, and at the start of any other line it moves the caret to the end
|
|
68
|
+
* of the previous line. Other caret positions (deleting within text) fall
|
|
69
|
+
* through to normal handling.
|
|
72
70
|
*/
|
|
73
71
|
export declare function $deletePoetryOnBackspace(): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Forward Delete at the end of a misra never merges the next line into it, for
|
|
74
|
+
* the same reason as $deletePoetryOnBackspace: the caret moves to the start of
|
|
75
|
+
* the next line instead. Other caret positions fall through to normal handling.
|
|
76
|
+
*/
|
|
77
|
+
export declare function $deletePoetryForward(): boolean;
|
|
74
78
|
/**
|
|
75
79
|
* Enter inside a poetry block never grows a couplet past its fixed two
|
|
76
80
|
* misras. The block's *last* couplet being completely empty is always the
|
|
@@ -91,4 +95,23 @@ export declare function $exitPoetryOnEnter(): boolean;
|
|
|
91
95
|
/** Steps the caret's poetry block one notch looser (+1) or tighter (-1) on
|
|
92
96
|
* the couplet-spacing scale; clamps at either end. */
|
|
93
97
|
export declare function $adjustPoetrySpacing(step: 1 | -1): boolean;
|
|
98
|
+
/** Steps the caret's two-column gutter one notch wider (+1) or narrower (-1);
|
|
99
|
+
* clamps at either end. */
|
|
100
|
+
export declare function $adjustPoetryGutter(step: 1 | -1): boolean;
|
|
101
|
+
/** Steps the caret's staggered couplet width one notch narrower (-1) or wider
|
|
102
|
+
* (+1); clamps at either end. */
|
|
103
|
+
export declare function $adjustPoetryStagger(step: 1 | -1): boolean;
|
|
104
|
+
/** Whether the couplet the caret is in is centered, or null outside a
|
|
105
|
+
* two-column poetry block (centering only applies there). */
|
|
106
|
+
export declare function $getCoupletCenteredFromSelection(): boolean | null;
|
|
107
|
+
/** Centers (or un-centers) the caret's couplet within a two-column block by
|
|
108
|
+
* rebuilding its row around the same two misra paragraphs. */
|
|
109
|
+
export declare function $setCoupletCentered(centered: boolean): boolean;
|
|
110
|
+
/** Removes the whole poetry block the caret is in, including every couplet. */
|
|
111
|
+
export declare function $deletePoetryBlock(): boolean;
|
|
112
|
+
/** Single-column blocks pair their paragraphs into couplets, so a line left
|
|
113
|
+
* without a partner (from pasted or imported content) would be invisible to
|
|
114
|
+
* the couplet logic. Give it an empty partner instead, so every line belongs
|
|
115
|
+
* to a couplet and can be deleted like any other. */
|
|
116
|
+
export declare function $completeSingleCoupletBlock(node: PoetryBlockNode): void;
|
|
94
117
|
//# sourceMappingURL=poetryActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poetryActions.d.ts","sourceRoot":"","sources":["../../src/blocks/poetryActions.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"poetryActions.d.ts","sourceRoot":"","sources":["../../src/blocks/poetryActions.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,oDAAoD;AACpD,MAAM,MAAM,OAAO,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAErD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,EAAE,CAqB7D;AAED;;6CAE6C;AAC7C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,EAAE,CAE1E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,eAAe,GAAG,IAAI,CAKrE;AA0DD;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAevF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAmBlF;AAED;;;;;;qDAMqD;AACrD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAEpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAiBlE;AAED;;;;wCAIwC;AACxC,wBAAgB,oBAAoB,IAAI,OAAO,CAwB9C;AAUD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAsClD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAkB9C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAgD5C;AAED;sDACsD;AACtD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAO1D;AAED;2BAC2B;AAC3B,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAOzD;AAED;iCACiC;AACjC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAO1D;AAYD;6DAC6D;AAC7D,wBAAgB,gCAAgC,IAAI,OAAO,GAAG,IAAI,CAUjE;AAED;8DAC8D;AAC9D,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAuB9D;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,OAAO,CAK5C;AAED;;;qDAGqD;AACrD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAGvE"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $findMatchingParent } from '@lexical/utils';
|
|
2
|
-
import { $createParagraphNode, $getSelection, $isElementNode, $isParagraphNode, $isRangeSelection } from 'lexical';
|
|
2
|
+
import { $createParagraphNode, $getSelection, $isElementNode, $isParagraphNode, $isRangeSelection, } from 'lexical';
|
|
3
3
|
import { $createLayoutContainerNode, $createLayoutItemNode, $isLayoutContainerNode, $isLayoutItemNode } from './LayoutNode.js';
|
|
4
|
-
import { $createPoetryBlockNode, $isPoetryBlockNode, POETRY_SPACINGS, } from './PoetryNode.js';
|
|
4
|
+
import { $createPoetryBlockNode, $isPoetryBlockNode, POETRY_GUTTERS, POETRY_SPACINGS, POETRY_STAGGERS, } 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
|
|
@@ -11,7 +11,7 @@ import { $createPoetryBlockNode, $isPoetryBlockNode, POETRY_SPACINGS, } from './
|
|
|
11
11
|
* read either shape, so nothing else needs to.
|
|
12
12
|
*/
|
|
13
13
|
export function $getCouplets(node) {
|
|
14
|
-
if (node.getLayout()
|
|
14
|
+
if (node.getLayout() !== 'two-column') {
|
|
15
15
|
const paragraphs = node.getChildren().filter($isParagraphNode);
|
|
16
16
|
const couplets = [];
|
|
17
17
|
for (let i = 0; i + 1 < paragraphs.length; i += 2)
|
|
@@ -22,6 +22,12 @@ export function $getCouplets(node) {
|
|
|
22
22
|
const couplets = [];
|
|
23
23
|
for (const container of containers) {
|
|
24
24
|
const items = container.getChildren().filter($isLayoutItemNode);
|
|
25
|
+
if (items.length === 1) {
|
|
26
|
+
const [a, b] = items[0].getChildren();
|
|
27
|
+
if ($isParagraphNode(a) && $isParagraphNode(b))
|
|
28
|
+
couplets.push([a, b]);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
25
31
|
const a = items[0]?.getFirstChild();
|
|
26
32
|
const b = items[1]?.getFirstChild();
|
|
27
33
|
if ($isParagraphNode(a) && $isParagraphNode(b))
|
|
@@ -58,7 +64,7 @@ function $findCoupletPosition(couplets, target) {
|
|
|
58
64
|
function $appendCoupletTo(node) {
|
|
59
65
|
const misraA = $createParagraphNode();
|
|
60
66
|
const misraB = $createParagraphNode();
|
|
61
|
-
if (node.getLayout()
|
|
67
|
+
if (node.getLayout() !== 'two-column') {
|
|
62
68
|
node.append(misraA, misraB);
|
|
63
69
|
}
|
|
64
70
|
else {
|
|
@@ -80,7 +86,7 @@ function $appendCoupletTo(node) {
|
|
|
80
86
|
function $insertCoupletRelativeTo(existingFirstMisra, layout, position) {
|
|
81
87
|
const misraA = $createParagraphNode();
|
|
82
88
|
const misraB = $createParagraphNode();
|
|
83
|
-
if (layout
|
|
89
|
+
if (layout !== 'two-column') {
|
|
84
90
|
if (position === 'before') {
|
|
85
91
|
existingFirstMisra.insertBefore(misraA);
|
|
86
92
|
misraA.insertAfter(misraB);
|
|
@@ -143,7 +149,7 @@ export function $setPoetryLayout(node, layout) {
|
|
|
143
149
|
}
|
|
144
150
|
for (const leftover of node.getChildren())
|
|
145
151
|
leftover.remove();
|
|
146
|
-
if (layout
|
|
152
|
+
if (layout !== 'two-column') {
|
|
147
153
|
for (const [a, b] of couplets)
|
|
148
154
|
node.append(a, b);
|
|
149
155
|
}
|
|
@@ -174,10 +180,10 @@ export function $ensureTrailingParagraph(node) {
|
|
|
174
180
|
* semantics, in its existing layout: "one poetry block can contain one or
|
|
175
181
|
* more couplets, in one or two column layout", so a block's layout is
|
|
176
182
|
* fixed once it has couplets, not chosen per couplet) and focuses its first
|
|
177
|
-
* misra. Otherwise creates a new block (in `layout
|
|
183
|
+
* misra. Otherwise creates a new block (in `layout`) with one
|
|
178
184
|
* couplet, after the selection's top-level element.
|
|
179
185
|
*/
|
|
180
|
-
export function $insertPoetryCouplet(layout
|
|
186
|
+
export function $insertPoetryCouplet(layout) {
|
|
181
187
|
const selection = $getSelection();
|
|
182
188
|
if (!$isRangeSelection(selection))
|
|
183
189
|
return false;
|
|
@@ -186,7 +192,7 @@ export function $insertPoetryCouplet(layout, align) {
|
|
|
186
192
|
return $insertCoupletRelativeToSelection('after');
|
|
187
193
|
}
|
|
188
194
|
const anchorTopLevel = selection.anchor.getNode().getTopLevelElementOrThrow();
|
|
189
|
-
const node = $createPoetryBlockNode(layout
|
|
195
|
+
const node = $createPoetryBlockNode(layout);
|
|
190
196
|
const [misraA] = $appendCoupletTo(node);
|
|
191
197
|
anchorTopLevel.insertAfter(node);
|
|
192
198
|
$ensureTrailingParagraph(node);
|
|
@@ -223,16 +229,23 @@ export function $deletePoetryCouplet() {
|
|
|
223
229
|
}
|
|
224
230
|
return true;
|
|
225
231
|
}
|
|
232
|
+
/** Whether a point sits at the very start (or, with `atEnd`, very end) of a paragraph. */
|
|
233
|
+
function $isPointAt(paragraph, point, atEnd) {
|
|
234
|
+
if (point.key === paragraph.getKey())
|
|
235
|
+
return point.offset === (atEnd ? paragraph.getChildrenSize() : 0);
|
|
236
|
+
const edge = atEnd ? paragraph.getLastDescendant() : paragraph.getFirstDescendant();
|
|
237
|
+
if (point.getNode() !== edge)
|
|
238
|
+
return false;
|
|
239
|
+
return point.offset === (atEnd ? point.getNode().getTextContent().length : 0);
|
|
240
|
+
}
|
|
226
241
|
/**
|
|
227
|
-
* Backspace at the
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
* other caret position, including a non-empty couplet, so normal Backspace
|
|
235
|
-
* handling (e.g. deleting within text) proceeds.
|
|
242
|
+
* Backspace at the start of a misra never merges it into its neighbour: the
|
|
243
|
+
* block's lines are paired into couplets, so merging one line away would
|
|
244
|
+
* shift every couplet after it (and take the previous couplet's last line
|
|
245
|
+
* with it). Instead, Backspace at the start of an empty couplet removes that
|
|
246
|
+
* couplet, and at the start of any other line it moves the caret to the end
|
|
247
|
+
* of the previous line. Other caret positions (deleting within text) fall
|
|
248
|
+
* through to normal handling.
|
|
236
249
|
*/
|
|
237
250
|
export function $deletePoetryOnBackspace() {
|
|
238
251
|
const selection = $getSelection();
|
|
@@ -242,35 +255,60 @@ export function $deletePoetryOnBackspace() {
|
|
|
242
255
|
if (!block)
|
|
243
256
|
return false;
|
|
244
257
|
const couplets = $getCouplets(block);
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
if (!position || position.misraIndex !== 0)
|
|
248
|
-
return false;
|
|
249
|
-
const [firstMisra] = couplets[position.coupletIndex];
|
|
250
|
-
const anchor = selection.anchor;
|
|
251
|
-
const isAtStart = anchor.key === firstMisra.getKey() && anchor.offset === 0;
|
|
252
|
-
if (!isAtStart)
|
|
258
|
+
const position = $findCoupletPosition(couplets, selection.anchor.getNode());
|
|
259
|
+
if (!position)
|
|
253
260
|
return false;
|
|
254
|
-
const
|
|
255
|
-
|
|
261
|
+
const { coupletIndex, misraIndex } = position;
|
|
262
|
+
const [a, b] = couplets[coupletIndex];
|
|
263
|
+
const misra = couplets[coupletIndex][misraIndex];
|
|
264
|
+
if (!$isPointAt(misra, selection.anchor, false))
|
|
256
265
|
return false;
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
previous
|
|
266
|
+
if (a.isEmpty() && b.isEmpty()) {
|
|
267
|
+
if (couplets.length <= 1) {
|
|
268
|
+
const previous = block.getPreviousSibling();
|
|
269
|
+
block.remove();
|
|
270
|
+
if ($isElementNode(previous))
|
|
271
|
+
previous.selectEnd();
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
const container = $findMatchingParent(a, $isLayoutContainerNode);
|
|
275
|
+
if (container)
|
|
276
|
+
container.remove();
|
|
277
|
+
else {
|
|
278
|
+
a.remove();
|
|
279
|
+
b.remove();
|
|
280
|
+
}
|
|
281
|
+
const remaining = $getCouplets(block);
|
|
282
|
+
const previousCouplet = remaining[coupletIndex - 1] ?? remaining[0];
|
|
283
|
+
previousCouplet?.[1].selectEnd();
|
|
262
284
|
return true;
|
|
263
285
|
}
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
286
|
+
const previousLine = misraIndex === 1 ? a : couplets[coupletIndex - 1]?.[1];
|
|
287
|
+
previousLine?.selectEnd();
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Forward Delete at the end of a misra never merges the next line into it, for
|
|
292
|
+
* the same reason as $deletePoetryOnBackspace: the caret moves to the start of
|
|
293
|
+
* the next line instead. Other caret positions fall through to normal handling.
|
|
294
|
+
*/
|
|
295
|
+
export function $deletePoetryForward() {
|
|
296
|
+
const selection = $getSelection();
|
|
297
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed())
|
|
298
|
+
return false;
|
|
299
|
+
const block = $getPoetryBlockFromSelection();
|
|
300
|
+
if (!block)
|
|
301
|
+
return false;
|
|
302
|
+
const couplets = $getCouplets(block);
|
|
303
|
+
const position = $findCoupletPosition(couplets, selection.anchor.getNode());
|
|
304
|
+
if (!position)
|
|
305
|
+
return false;
|
|
306
|
+
const { coupletIndex, misraIndex } = position;
|
|
307
|
+
const misra = couplets[coupletIndex][misraIndex];
|
|
308
|
+
if (!$isPointAt(misra, selection.anchor, true))
|
|
309
|
+
return false;
|
|
310
|
+
const nextLine = misraIndex === 0 ? couplets[coupletIndex][1] : couplets[coupletIndex + 1]?.[0];
|
|
311
|
+
nextLine?.selectStart();
|
|
274
312
|
return true;
|
|
275
313
|
}
|
|
276
314
|
/**
|
|
@@ -347,3 +385,97 @@ export function $adjustPoetrySpacing(step) {
|
|
|
347
385
|
block.setSpacing(next);
|
|
348
386
|
return true;
|
|
349
387
|
}
|
|
388
|
+
/** Steps the caret's two-column gutter one notch wider (+1) or narrower (-1);
|
|
389
|
+
* clamps at either end. */
|
|
390
|
+
export function $adjustPoetryGutter(step) {
|
|
391
|
+
const block = $getPoetryBlockFromSelection();
|
|
392
|
+
if (!block)
|
|
393
|
+
return false;
|
|
394
|
+
const index = POETRY_GUTTERS.indexOf(block.getGutter());
|
|
395
|
+
const next = POETRY_GUTTERS[Math.min(POETRY_GUTTERS.length - 1, Math.max(0, index + step))];
|
|
396
|
+
block.setGutter(next);
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
/** Steps the caret's staggered couplet width one notch narrower (-1) or wider
|
|
400
|
+
* (+1); clamps at either end. */
|
|
401
|
+
export function $adjustPoetryStagger(step) {
|
|
402
|
+
const block = $getPoetryBlockFromSelection();
|
|
403
|
+
if (!block)
|
|
404
|
+
return false;
|
|
405
|
+
const index = POETRY_STAGGERS.indexOf(block.getStagger());
|
|
406
|
+
const next = POETRY_STAGGERS[Math.min(POETRY_STAGGERS.length - 1, Math.max(0, index + step))];
|
|
407
|
+
block.setStagger(next);
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
/** A centered couplet is a two-column row holding both misras in one item
|
|
411
|
+
* (a single-item row), rather than one item per misra. */
|
|
412
|
+
function $isCoupletRowCentered(row) {
|
|
413
|
+
return row.getChildren().filter($isLayoutItemNode).length === 1;
|
|
414
|
+
}
|
|
415
|
+
function $findCoupletRow(couplet) {
|
|
416
|
+
return $findMatchingParent(couplet[0], $isLayoutContainerNode);
|
|
417
|
+
}
|
|
418
|
+
/** Whether the couplet the caret is in is centered, or null outside a
|
|
419
|
+
* two-column poetry block (centering only applies there). */
|
|
420
|
+
export function $getCoupletCenteredFromSelection() {
|
|
421
|
+
const block = $getPoetryBlockFromSelection();
|
|
422
|
+
if (!block || block.getLayout() !== 'two-column')
|
|
423
|
+
return null;
|
|
424
|
+
const selection = $getSelection();
|
|
425
|
+
if (!$isRangeSelection(selection))
|
|
426
|
+
return null;
|
|
427
|
+
const couplets = $getCouplets(block);
|
|
428
|
+
const position = $findCoupletPosition(couplets, selection.anchor.getNode());
|
|
429
|
+
if (!position)
|
|
430
|
+
return null;
|
|
431
|
+
const row = $findCoupletRow(couplets[position.coupletIndex]);
|
|
432
|
+
return row ? $isCoupletRowCentered(row) : false;
|
|
433
|
+
}
|
|
434
|
+
/** Centers (or un-centers) the caret's couplet within a two-column block by
|
|
435
|
+
* rebuilding its row around the same two misra paragraphs. */
|
|
436
|
+
export function $setCoupletCentered(centered) {
|
|
437
|
+
const block = $getPoetryBlockFromSelection();
|
|
438
|
+
if (!block || block.getLayout() !== 'two-column')
|
|
439
|
+
return false;
|
|
440
|
+
const selection = $getSelection();
|
|
441
|
+
if (!$isRangeSelection(selection))
|
|
442
|
+
return false;
|
|
443
|
+
const couplets = $getCouplets(block);
|
|
444
|
+
const position = $findCoupletPosition(couplets, selection.anchor.getNode());
|
|
445
|
+
if (!position)
|
|
446
|
+
return false;
|
|
447
|
+
const couplet = couplets[position.coupletIndex];
|
|
448
|
+
const row = $findCoupletRow(couplet);
|
|
449
|
+
if (!row || $isCoupletRowCentered(row) === centered)
|
|
450
|
+
return true;
|
|
451
|
+
const [a, b] = couplet;
|
|
452
|
+
const newRow = $createLayoutContainerNode(centered ? '1fr' : 'repeat(2, 1fr)');
|
|
453
|
+
if (centered) {
|
|
454
|
+
newRow.append($createLayoutItemNode().append(a, b));
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
newRow.append($createLayoutItemNode().append(a), $createLayoutItemNode().append(b));
|
|
458
|
+
}
|
|
459
|
+
row.insertAfter(newRow);
|
|
460
|
+
row.remove();
|
|
461
|
+
a.selectStart();
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
/** Removes the whole poetry block the caret is in, including every couplet. */
|
|
465
|
+
export function $deletePoetryBlock() {
|
|
466
|
+
const block = $getPoetryBlockFromSelection();
|
|
467
|
+
if (!block)
|
|
468
|
+
return false;
|
|
469
|
+
block.remove();
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
/** Single-column blocks pair their paragraphs into couplets, so a line left
|
|
473
|
+
* without a partner (from pasted or imported content) would be invisible to
|
|
474
|
+
* the couplet logic. Give it an empty partner instead, so every line belongs
|
|
475
|
+
* to a couplet and can be deleted like any other. */
|
|
476
|
+
export function $completeSingleCoupletBlock(node) {
|
|
477
|
+
if (node.getLayout() === 'two-column')
|
|
478
|
+
return;
|
|
479
|
+
if (node.getChildrenSize() % 2 === 1)
|
|
480
|
+
node.append($createParagraphNode());
|
|
481
|
+
}
|
|
@@ -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":"AAqFA,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;AA8gBvD,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,+BAmkCxJ"}
|
|
@@ -14,8 +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 { $isPoetryBlockNode } from '../blocks/PoetryNode.js';
|
|
18
|
-
import { $adjustPoetrySpacing, $deletePoetryCouplet, $getPoetryBlockFromSelection, $insertCoupletRelativeToSelection, $setPoetryLayout, } from '../blocks/poetryActions.js';
|
|
17
|
+
import { $isPoetryBlockNode, POETRY_GUTTERS, POETRY_SPACINGS, POETRY_STAGGERS, } from '../blocks/PoetryNode.js';
|
|
18
|
+
import { $adjustPoetryGutter, $getCoupletCenteredFromSelection, $setCoupletCentered, $adjustPoetryStagger, $adjustPoetrySpacing, $deletePoetryBlock, $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, IconArrowsMaximize, IconArrowsMinimize, 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, IconArrowsShuffle, 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). */
|
|
@@ -50,7 +50,8 @@ const INITIAL_STATE = {
|
|
|
50
50
|
canUnmergeCell: false,
|
|
51
51
|
inPoetry: false,
|
|
52
52
|
poetryLayout: 'single',
|
|
53
|
-
|
|
53
|
+
poetryScale: { spacing: 'normal', gutter: 'normal', stagger: 'normal' },
|
|
54
|
+
poetryCentered: false,
|
|
54
55
|
canUndo: false,
|
|
55
56
|
canRedo: false,
|
|
56
57
|
};
|
|
@@ -162,16 +163,14 @@ function TableMenuItems({ strings, direction, rows, columns, canMergeCells, canU
|
|
|
162
163
|
};
|
|
163
164
|
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')] }));
|
|
164
165
|
}
|
|
165
|
-
/**
|
|
166
|
-
*
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
function PoetryMenuItems({ strings, alignIcons, layout, align, onAction, }) {
|
|
166
|
+
/** Whether a one-notch step from `value` stays on the scale — a step that
|
|
167
|
+
* would fall off either end is disabled rather than silently clamped. */
|
|
168
|
+
function canStep(scale, value, step) {
|
|
169
|
+
const next = scale.indexOf(value) + step;
|
|
170
|
+
return next >= 0 && next < scale.length;
|
|
171
|
+
}
|
|
172
|
+
function PoetryMenuItems({ strings, layout, scale, centered, onAction, }) {
|
|
173
173
|
const t = strings.poetryMenu;
|
|
174
|
-
const a = strings.toolbar.alignOptions;
|
|
175
174
|
const item = (icon, label, action, active = false, color) => {
|
|
176
175
|
const Icon = icon;
|
|
177
176
|
return (_jsx(Menu.Item, { color: color, disabled: active, leftSection: _jsx(Icon, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onAction(action), children: label }));
|
|
@@ -181,10 +180,7 @@ function PoetryMenuItems({ strings, alignIcons, layout, align, onAction, }) {
|
|
|
181
180
|
if (node)
|
|
182
181
|
$setPoetryLayout(node, next);
|
|
183
182
|
};
|
|
184
|
-
|
|
185
|
-
$getPoetryBlockFromSelection()?.setAlign(next);
|
|
186
|
-
};
|
|
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')] }));
|
|
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'), item(IconArrowsShuffle, t.staggered, setLayout('staggered'), layout === 'staggered'), _jsx(Menu.Divider, {}), _jsx(Menu.Divider, {}), item(IconRowInsertTop, t.insertCoupletBefore, () => $insertCoupletRelativeToSelection('before')), item(IconRowInsertBottom, t.insertCoupletAfter, () => $insertCoupletRelativeToSelection('after')), item(IconArrowsMinimize, t.tighterSpacing, () => $adjustPoetrySpacing(-1), !canStep(POETRY_SPACINGS, scale.spacing, -1)), item(IconArrowsMaximize, t.looserSpacing, () => $adjustPoetrySpacing(1), !canStep(POETRY_SPACINGS, scale.spacing, 1)), layout === 'staggered' && (_jsxs(_Fragment, { children: [item(IconArrowsMinimize, t.narrowerCouplets, () => $adjustPoetryStagger(-1), !canStep(POETRY_STAGGERS, scale.stagger, -1)), item(IconArrowsMaximize, t.widerCouplets, () => $adjustPoetryStagger(1), !canStep(POETRY_STAGGERS, scale.stagger, 1))] })), layout === 'two-column' && (_jsxs(_Fragment, { children: [item(IconAlignCenter, centered ? t.uncenterCouplet : t.centerCouplet, () => $setCoupletCentered(!centered)), item(IconColumns2, t.narrowerGutter, () => $adjustPoetryGutter(-1), !canStep(POETRY_GUTTERS, scale.gutter, -1)), item(IconColumns2, t.widerGutter, () => $adjustPoetryGutter(1), !canStep(POETRY_GUTTERS, scale.gutter, 1))] })), item(IconTrash, t.deleteCouplet, $deletePoetryCouplet, false, 'red'), item(IconTrash, t.deletePoetry, $deletePoetryBlock, false, 'red')] }));
|
|
188
184
|
}
|
|
189
185
|
export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
190
186
|
const [editor] = useLexicalComposerContext();
|
|
@@ -246,7 +242,10 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
246
242
|
// node method (getFormatType() included) must not be deferred into it.
|
|
247
243
|
const elementFormat = ($isElementNode(element) ? element.getFormatType() : 'start') || 'start';
|
|
248
244
|
const poetryLayout = poetryBlock?.getLayout();
|
|
249
|
-
const
|
|
245
|
+
const poetryCentered = $getCoupletCenteredFromSelection();
|
|
246
|
+
const poetryScale = poetryBlock
|
|
247
|
+
? { spacing: poetryBlock.getSpacing(), gutter: poetryBlock.getGutter(), stagger: poetryBlock.getStagger() }
|
|
248
|
+
: null;
|
|
250
249
|
setState((s) => ({
|
|
251
250
|
...s,
|
|
252
251
|
blockType,
|
|
@@ -264,7 +263,8 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
264
263
|
canUnmergeCell,
|
|
265
264
|
inPoetry: poetryBlock !== null,
|
|
266
265
|
poetryLayout: poetryLayout ?? s.poetryLayout,
|
|
267
|
-
|
|
266
|
+
poetryScale: poetryScale ?? s.poetryScale,
|
|
267
|
+
poetryCentered: poetryCentered ?? false,
|
|
268
268
|
}));
|
|
269
269
|
});
|
|
270
270
|
}, [editor]);
|
|
@@ -808,9 +808,9 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
808
808
|
restoreSelection();
|
|
809
809
|
openLinkDialog();
|
|
810
810
|
}, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog })) }, "link")),
|
|
811
|
-
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
|
|
811
|
+
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 }) }))] }, "stubInsert")),
|
|
812
812
|
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")),
|
|
813
|
-
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,
|
|
813
|
+
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, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }) })] }) }, "poetryActions")),
|
|
814
814
|
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")),
|
|
815
815
|
];
|
|
816
816
|
return (_jsxs("div", { className: "likhari-toolbar", role: "toolbar", "aria-label": strings.toolbar.ariaLabel, ref: toolbarContainerRef, children: [fixedGroups, movableGroups
|
|
@@ -829,7 +829,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
829
829
|
}, 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 }) })] })), config.poetry.enabled && (_jsxs(Menu, { opened: poetryContext !== null, onChange: (opened) => {
|
|
830
830
|
if (!opened)
|
|
831
831
|
setPoetryContext(null);
|
|
832
|
-
}, position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, children: [_jsx(Menu.Target, { children: _jsx("span", { "aria-hidden": "true", style: { position: 'fixed', left: poetryContext?.x ?? -9999, top: poetryContext?.y ?? -9999, width: 1, height: 1, pointerEvents: 'none' } }) }), _jsx(Menu.Dropdown, { children: _jsx(PoetryMenuItems, { strings: strings,
|
|
832
|
+
}, position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, children: [_jsx(Menu.Target, { children: _jsx("span", { "aria-hidden": "true", style: { position: 'fixed', left: poetryContext?.x ?? -9999, top: poetryContext?.y ?? -9999, width: 1, height: 1, pointerEvents: 'none' } }) }), _jsx(Menu.Dropdown, { children: _jsx(PoetryMenuItems, { strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }) })] })), _jsxs("div", { "aria-hidden": "true", ref: toolbarMeasureRef, style: {
|
|
833
833
|
position: 'absolute',
|
|
834
834
|
visibility: 'hidden',
|
|
835
835
|
pointerEvents: 'none',
|
package/dist/i18n/strings.d.ts
CHANGED
|
@@ -142,11 +142,19 @@ export interface Strings {
|
|
|
142
142
|
menuLabel: string;
|
|
143
143
|
singleColumn: string;
|
|
144
144
|
twoColumn: string;
|
|
145
|
+
staggered: string;
|
|
146
|
+
narrowerCouplets: string;
|
|
147
|
+
widerCouplets: string;
|
|
145
148
|
insertCoupletBefore: string;
|
|
146
149
|
insertCoupletAfter: string;
|
|
150
|
+
centerCouplet: string;
|
|
151
|
+
uncenterCouplet: string;
|
|
147
152
|
tighterSpacing: string;
|
|
148
153
|
looserSpacing: string;
|
|
154
|
+
narrowerGutter: string;
|
|
155
|
+
widerGutter: string;
|
|
149
156
|
deleteCouplet: string;
|
|
157
|
+
deletePoetry: string;
|
|
150
158
|
};
|
|
151
159
|
link: {
|
|
152
160
|
menuLabel: 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,0GAA0G;QAC1G,aAAa,EAAE,MAAM,CAAC;QACtB,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,mBAAmB,EAAE,MAAM,CAAC;QAC5B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;QACtC,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,iBAAiB,EAAE;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;YACnC,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC;YACnB,QAAQ,EAAE,MAAM,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;QACF,YAAY,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,GAAG,EAAE,MAAM,CAAC;YACZ,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;KACH,CAAC;IACF,uIAAuI;IACvI,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,2FAA2F;QAC3F,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,oGAAoG;IACpG,MAAM,EAAE;QACN,0GAA0G;QAC1G,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;QACxC,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,2DAA2D;QAC3D,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;QACtC,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;QACzC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;QAClC,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;QAC7B,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,yEAAyE;IACzE,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,2EAA2E;QAC3E,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,UAAU,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;
|
|
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
|
@@ -125,11 +125,19 @@ const en = {
|
|
|
125
125
|
menuLabel: 'Poetry',
|
|
126
126
|
singleColumn: 'Single column',
|
|
127
127
|
twoColumn: 'Two column',
|
|
128
|
+
staggered: 'Alternating sides',
|
|
129
|
+
narrowerCouplets: 'Narrower couplets',
|
|
130
|
+
widerCouplets: 'Wider couplets',
|
|
128
131
|
insertCoupletBefore: 'Insert couplet above',
|
|
129
132
|
insertCoupletAfter: 'Insert couplet below',
|
|
133
|
+
centerCouplet: 'Center this couplet',
|
|
134
|
+
uncenterCouplet: 'Un-center this couplet',
|
|
130
135
|
tighterSpacing: 'Tighter couplet spacing',
|
|
131
136
|
looserSpacing: 'Looser couplet spacing',
|
|
137
|
+
narrowerGutter: 'Narrower gutter',
|
|
138
|
+
widerGutter: 'Wider gutter',
|
|
132
139
|
deleteCouplet: 'Delete couplet',
|
|
140
|
+
deletePoetry: 'Delete poetry',
|
|
133
141
|
},
|
|
134
142
|
link: {
|
|
135
143
|
menuLabel: 'Link',
|
|
@@ -337,11 +345,19 @@ const ur = {
|
|
|
337
345
|
menuLabel: 'شاعری',
|
|
338
346
|
singleColumn: 'ایک کالم',
|
|
339
347
|
twoColumn: 'دو کالم',
|
|
348
|
+
staggered: 'کالم متبادل',
|
|
349
|
+
narrowerCouplets: 'شعر کی چوڑائی کم',
|
|
350
|
+
widerCouplets: 'شعر کی چوڑائی زیادہ',
|
|
340
351
|
insertCoupletBefore: 'اوپر شعر شامل کریں',
|
|
341
352
|
insertCoupletAfter: 'نیچے شعر شامل کریں',
|
|
353
|
+
centerCouplet: 'یہ شعر وسط میں رکھیں',
|
|
354
|
+
uncenterCouplet: 'وسط میں رکھنا ختم کریں',
|
|
342
355
|
tighterSpacing: 'شعروں کے درمیان کم جگہ',
|
|
343
356
|
looserSpacing: 'شعروں کے درمیان زیادہ جگہ',
|
|
357
|
+
narrowerGutter: 'کالمز کے درمیان کم جگہ',
|
|
358
|
+
widerGutter: 'کالمز کے درمیان زیادہ جگہ',
|
|
344
359
|
deleteCouplet: 'شعر حذف کریں',
|
|
360
|
+
deletePoetry: 'پوری شاعری حذف کریں',
|
|
345
361
|
},
|
|
346
362
|
link: {
|
|
347
363
|
menuLabel: 'لنک',
|
|
@@ -549,11 +565,19 @@ const paShahmukhi = {
|
|
|
549
565
|
menuLabel: 'شاعری',
|
|
550
566
|
singleColumn: 'اک کالم',
|
|
551
567
|
twoColumn: 'دو کالم',
|
|
568
|
+
staggered: 'وارو وار پاسے',
|
|
569
|
+
narrowerCouplets: 'شعر دی چوڑائی گھٹ',
|
|
570
|
+
widerCouplets: 'شعر دی چوڑائی ودھ',
|
|
552
571
|
insertCoupletBefore: 'اُتے شعر شامل کرو',
|
|
553
572
|
insertCoupletAfter: 'ھیٹھ شعر شامل کرو',
|
|
573
|
+
centerCouplet: 'ایہ شعر وچکار رکھو',
|
|
574
|
+
uncenterCouplet: 'وچکار رکھنا بند کرو',
|
|
554
575
|
tighterSpacing: 'شعراں وچکار گھٹ جگہ',
|
|
555
576
|
looserSpacing: 'شعراں وچکار ودھ جگہ',
|
|
577
|
+
narrowerGutter: 'کالماں وچکار گھٹ جگہ',
|
|
578
|
+
widerGutter: 'کالماں وچکار ودھ جگہ',
|
|
556
579
|
deleteCouplet: 'شعر مٹاؤ',
|
|
580
|
+
deletePoetry: 'ساری شاعری مٹاؤ',
|
|
557
581
|
},
|
|
558
582
|
link: {
|
|
559
583
|
menuLabel: 'لنک',
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type LexicalCommand } from 'lexical';
|
|
2
|
-
import { type
|
|
2
|
+
import { type PoetryLayout } from '../blocks/PoetryNode.js';
|
|
3
3
|
export declare const INSERT_POETRY_COUPLET_COMMAND: LexicalCommand<{
|
|
4
4
|
layout: PoetryLayout;
|
|
5
|
-
align: PoetryAlign;
|
|
6
5
|
}>;
|
|
7
6
|
/**
|
|
8
7
|
* Registers INSERT_POETRY_COUPLET_COMMAND (mirrors LayoutPlugin/FootnotePlugin's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PoetryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PoetryPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"PoetryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PoetryPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAU1E,eAAO,MAAM,6BAA6B,EAAE,cAAc,CAAC;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAElF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,SAsD3B"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
-
import { COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, KEY_BACKSPACE_COMMAND, KEY_ENTER_COMMAND, createCommand, } from 'lexical';
|
|
3
|
+
import { COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, createCommand, } from 'lexical';
|
|
4
4
|
import { mergeRegister } from '@lexical/utils';
|
|
5
5
|
import { LayoutContainerNode, LayoutItemNode } from '../blocks/LayoutNode.js';
|
|
6
6
|
import { PoetryBlockNode } from '../blocks/PoetryNode.js';
|
|
7
|
-
import { $deletePoetryOnBackspace, $ensureTrailingParagraph, $exitPoetryOnEnter, $insertPoetryCouplet } from '../blocks/poetryActions.js';
|
|
7
|
+
import { $deletePoetryForward, $deletePoetryOnBackspace, $ensureTrailingParagraph, $completeSingleCoupletBlock, $exitPoetryOnEnter, $insertPoetryCouplet, } from '../blocks/poetryActions.js';
|
|
8
8
|
export const INSERT_POETRY_COUPLET_COMMAND = createCommand('INSERT_POETRY_COUPLET_COMMAND');
|
|
9
9
|
/**
|
|
10
10
|
* Registers INSERT_POETRY_COUPLET_COMMAND (mirrors LayoutPlugin/FootnotePlugin's
|
|
@@ -24,11 +24,12 @@ export function PoetryPlugin() {
|
|
|
24
24
|
if (!editor.hasNodes([PoetryBlockNode, LayoutContainerNode, LayoutItemNode])) {
|
|
25
25
|
throw new Error('PoetryPlugin: PoetryBlockNode (and the columns nodes it composes) not registered on the editor');
|
|
26
26
|
}
|
|
27
|
-
return mergeRegister(editor.registerCommand(INSERT_POETRY_COUPLET_COMMAND, ({ layout
|
|
27
|
+
return mergeRegister(editor.registerCommand(INSERT_POETRY_COUPLET_COMMAND, ({ layout }) => $insertPoetryCouplet(layout), COMMAND_PRIORITY_EDITOR), editor.registerNodeTransform(PoetryBlockNode, (node) => {
|
|
28
28
|
if (node.getChildrenSize() === 0) {
|
|
29
29
|
node.remove();
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
+
$completeSingleCoupletBlock(node);
|
|
32
33
|
$ensureTrailingParagraph(node);
|
|
33
34
|
}), editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
34
35
|
if (event?.shiftKey)
|
|
@@ -42,6 +43,11 @@ export function PoetryPlugin() {
|
|
|
42
43
|
if (handled)
|
|
43
44
|
event?.preventDefault();
|
|
44
45
|
return handled;
|
|
46
|
+
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_DELETE_COMMAND, (event) => {
|
|
47
|
+
const handled = $deletePoetryForward();
|
|
48
|
+
if (handled)
|
|
49
|
+
event?.preventDefault();
|
|
50
|
+
return handled;
|
|
45
51
|
}, COMMAND_PRIORITY_HIGH));
|
|
46
52
|
}, [editor]);
|
|
47
53
|
return null;
|
package/dist/theme/editor.css
CHANGED
|
@@ -429,6 +429,40 @@
|
|
|
429
429
|
.likhari-poetry--spacing-relaxed { --poetry-couplet-gap: 1.8em; }
|
|
430
430
|
.likhari-poetry--spacing-loose { --poetry-couplet-gap: 2.8em; }
|
|
431
431
|
|
|
432
|
+
.likhari-poetry--gutter-compact { --poetry-gutter: 8px; }
|
|
433
|
+
.likhari-poetry--gutter-normal { --poetry-gutter: 20px; }
|
|
434
|
+
.likhari-poetry--gutter-relaxed { --poetry-gutter: 32px; }
|
|
435
|
+
.likhari-poetry--gutter-loose { --poetry-gutter: 48px; }
|
|
436
|
+
|
|
437
|
+
.likhari-poetry--stagger-compact { --poetry-stagger-width: 50%; }
|
|
438
|
+
.likhari-poetry--stagger-normal { --poetry-stagger-width: 65%; }
|
|
439
|
+
.likhari-poetry--stagger-relaxed { --poetry-stagger-width: 75%; }
|
|
440
|
+
.likhari-poetry--stagger-loose { --poetry-stagger-width: 85%; }
|
|
441
|
+
|
|
442
|
+
/* Staggered: couplets are the same flat misra paragraphs as single column,
|
|
443
|
+
but each couplet's two misras are placed in a 65%-wide box that alternates
|
|
444
|
+
sides — the first couplet pushed to the start edge, the next to the end
|
|
445
|
+
edge, and so on. Logical properties keep the alternation mirrored for RTL. */
|
|
446
|
+
.likhari-poetry--staggered .likhari-paragraph {
|
|
447
|
+
width: var(--poetry-stagger-width, 65%);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.likhari-poetry--staggered .likhari-paragraph:nth-child(4n+1),
|
|
451
|
+
.likhari-poetry--staggered .likhari-paragraph:nth-child(4n+2) {
|
|
452
|
+
margin-inline-end: auto;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.likhari-poetry--staggered .likhari-paragraph:nth-child(4n+3),
|
|
456
|
+
.likhari-poetry--staggered .likhari-paragraph:nth-child(4n+4) {
|
|
457
|
+
margin-inline-start: auto;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.likhari-poetry--staggered .likhari-paragraph:nth-child(odd):not(:first-child) {
|
|
461
|
+
border-top: 1px dashed var(--editor-line-strong);
|
|
462
|
+
margin-top: var(--poetry-couplet-gap);
|
|
463
|
+
padding-top: calc(var(--poetry-couplet-gap) * 0.6);
|
|
464
|
+
}
|
|
465
|
+
|
|
432
466
|
.likhari-poetry--two-column .likhari-layout-container {
|
|
433
467
|
margin: 0;
|
|
434
468
|
/* No grid gap — the column divider sits exactly on the track boundary,
|
|
@@ -450,15 +484,27 @@
|
|
|
450
484
|
text-align: inherit;
|
|
451
485
|
}
|
|
452
486
|
|
|
487
|
+
/* A centered couplet: a two-column row holding one item (see poetryActions.ts's
|
|
488
|
+
$setCoupletCentered) — narrowed to the middle of the block, with no column
|
|
489
|
+
divider or gutter since there's only one column. */
|
|
490
|
+
.likhari-poetry--two-column > .likhari-layout-container:has(> .likhari-layout-item:only-child) {
|
|
491
|
+
width: 60%;
|
|
492
|
+
margin-inline: auto;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.likhari-poetry--two-column .likhari-layout-item:only-child {
|
|
496
|
+
padding-inline-end: 0;
|
|
497
|
+
}
|
|
498
|
+
|
|
453
499
|
.likhari-poetry--two-column .likhari-layout-item:first-child {
|
|
454
|
-
padding-inline-end: 20px;
|
|
500
|
+
padding-inline-end: var(--poetry-gutter, 20px);
|
|
455
501
|
}
|
|
456
502
|
|
|
457
503
|
/* A visible divider between misra columns, same dashed language as the
|
|
458
504
|
couplet's own border — matches a table's internal cell borders. */
|
|
459
505
|
.likhari-poetry--two-column .likhari-layout-item:not(:first-child) {
|
|
460
506
|
border-inline-start: 1px dashed var(--editor-line-strong);
|
|
461
|
-
padding-inline-start: 20px;
|
|
507
|
+
padding-inline-start: var(--poetry-gutter, 20px);
|
|
462
508
|
}
|
|
463
509
|
|
|
464
510
|
/* PoetryResizer.tsx's drag handle — portaled to a fixed position over the
|