@inshapardaz/likhari-react 0.1.18-dev.130 → 0.1.18-dev.134

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.
@@ -16,4 +16,14 @@ export declare function $setPoetryLayout(node: PoetryBlockNode, layout: PoetryLa
16
16
  /** Inserts a new two-misra couplet after the selection's top-level block,
17
17
  * in `layout`/`align`, and focuses its first misra. */
18
18
  export declare function $insertPoetryCouplet(layout: PoetryLayout, align: PoetryAlign): boolean;
19
+ /**
20
+ * Enter at the end of a couplet's last misra would otherwise land inside
21
+ * ParagraphNode's own insertNewAfter — which inserts the new paragraph as a
22
+ * sibling of the misra, i.e. still inside the couplet (or, for two-column,
23
+ * inside its LayoutItemNode) — trapping the caret with no way to add a line
24
+ * after the block. Handled here instead: a plain paragraph after the whole
25
+ * couplet, focused. Returns false (let normal Enter handling proceed) for
26
+ * every other caret position, including earlier in the couplet.
27
+ */
28
+ export declare function $exitPoetryOnEnter(): boolean;
19
29
  //# sourceMappingURL=poetryActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"poetryActions.d.ts","sourceRoot":"","sources":["../../src/blocks/poetryActions.ts"],"names":[],"mappings":"AACA,OAAO,EAA4E,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvH,OAAO,EAA8C,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAErI;wCACwC;AACxC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,EAAE,CAW1E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,eAAe,GAAG,IAAI,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAclF;AAED;uDACuD;AACvD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAmBtF"}
1
+ {"version":3,"file":"poetryActions.d.ts","sourceRoot":"","sources":["../../src/blocks/poetryActions.ts"],"names":[],"mappings":"AACA,OAAO,EAA4E,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvH,OAAO,EAA8C,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAErI;wCACwC;AACxC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,EAAE,CAW1E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,eAAe,GAAG,IAAI,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAclF;AAED;uDACuD;AACvD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAwBtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAoB5C"}
@@ -58,7 +58,12 @@ export function $insertPoetryCouplet(layout, align) {
58
58
  const selection = $getSelection();
59
59
  if (!$isRangeSelection(selection))
60
60
  return false;
61
- const anchorTopLevel = selection.anchor.getNode().getTopLevelElementOrThrow();
61
+ // getTopLevelElement() stops at the nearest shadow root, and a
62
+ // PoetryBlockNode is one — so from inside an existing couplet it resolves
63
+ // to the misra paragraph itself, not the couplet. Without this check, a
64
+ // second insert lands as a sibling of that misra (nested inside the first
65
+ // couplet) instead of after the couplet as a whole.
66
+ const anchorTopLevel = $getPoetryBlockFromSelection() ?? selection.anchor.getNode().getTopLevelElementOrThrow();
62
67
  const node = $createPoetryBlockNode(layout, align);
63
68
  const misraA = $createParagraphNode();
64
69
  const misraB = $createParagraphNode();
@@ -74,3 +79,33 @@ export function $insertPoetryCouplet(layout, align) {
74
79
  misraA.selectStart();
75
80
  return true;
76
81
  }
82
+ /**
83
+ * Enter at the end of a couplet's last misra would otherwise land inside
84
+ * ParagraphNode's own insertNewAfter — which inserts the new paragraph as a
85
+ * sibling of the misra, i.e. still inside the couplet (or, for two-column,
86
+ * inside its LayoutItemNode) — trapping the caret with no way to add a line
87
+ * after the block. Handled here instead: a plain paragraph after the whole
88
+ * couplet, focused. Returns false (let normal Enter handling proceed) for
89
+ * every other caret position, including earlier in the couplet.
90
+ */
91
+ export function $exitPoetryOnEnter() {
92
+ const selection = $getSelection();
93
+ if (!$isRangeSelection(selection) || !selection.isCollapsed())
94
+ return false;
95
+ const couplet = $getPoetryBlockFromSelection();
96
+ if (!couplet)
97
+ return false;
98
+ const misras = $getMisraParagraphs(couplet);
99
+ const lastMisra = misras[misras.length - 1];
100
+ if (!lastMisra)
101
+ return false;
102
+ const anchor = selection.anchor;
103
+ const lastDesc = lastMisra.getLastDescendant();
104
+ const isAtEnd = lastDesc ? anchor.key === lastDesc.getKey() && anchor.offset === lastDesc.getTextContentSize() : anchor.key === lastMisra.getKey();
105
+ if (!isAtEnd)
106
+ return false;
107
+ const paragraph = $createParagraphNode();
108
+ couplet.insertAfter(paragraph);
109
+ paragraph.select();
110
+ return true;
111
+ }
@@ -6,9 +6,12 @@ export declare const INSERT_POETRY_COUPLET_COMMAND: LexicalCommand<{
6
6
  }>;
7
7
  /**
8
8
  * Registers INSERT_POETRY_COUPLET_COMMAND (mirrors LayoutPlugin/FootnotePlugin's
9
- * shape) and a node transform that removes a couplet left with no misra
9
+ * shape), a node transform that removes a couplet left with no misra
10
10
  * content — e.g. after undo/paste leaves it structurally empty — rather
11
- * than letting an unselectable husk linger in the document.
11
+ * than letting an unselectable husk linger in the document, and a
12
+ * KEY_ENTER_COMMAND handler (above RichTextPlugin's own, which would
13
+ * otherwise trap Enter inside the couplet — see poetryActions.ts) that lets
14
+ * Enter at the end of the last misra add a paragraph after the block.
12
15
  */
13
16
  export declare function PoetryPlugin(): null;
14
17
  //# sourceMappingURL=PoetryPlugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PoetryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PoetryPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA0C,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAGtF,OAAO,EAAmB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAG5F,eAAO,MAAM,6BAA6B,EAAE,cAAc,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAEtG,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,YAAY,SAqB3B"}
1
+ {"version":3,"file":"PoetryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PoetryPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAoF,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAGhI,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;;;;;;;;GAQG;AACH,wBAAgB,YAAY,SA+B3B"}
@@ -1,16 +1,19 @@
1
1
  import { useEffect } from 'react';
2
2
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
3
- import { COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
3
+ import { COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, 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 { $insertPoetryCouplet } from '../blocks/poetryActions.js';
7
+ import { $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
11
- * shape) and a node transform that removes a couplet left with no misra
11
+ * shape), a node transform that removes a couplet left with no misra
12
12
  * content — e.g. after undo/paste leaves it structurally empty — rather
13
- * than letting an unselectable husk linger in the document.
13
+ * than letting an unselectable husk linger in the document, and a
14
+ * KEY_ENTER_COMMAND handler (above RichTextPlugin's own, which would
15
+ * otherwise trap Enter inside the couplet — see poetryActions.ts) that lets
16
+ * Enter at the end of the last misra add a paragraph after the block.
14
17
  */
15
18
  export function PoetryPlugin() {
16
19
  const [editor] = useLexicalComposerContext();
@@ -21,7 +24,14 @@ export function PoetryPlugin() {
21
24
  return mergeRegister(editor.registerCommand(INSERT_POETRY_COUPLET_COMMAND, ({ layout, align }) => $insertPoetryCouplet(layout, align), COMMAND_PRIORITY_EDITOR), editor.registerNodeTransform(PoetryBlockNode, (node) => {
22
25
  if (node.getChildrenSize() === 0)
23
26
  node.remove();
24
- }));
27
+ }), editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
28
+ if (event?.shiftKey)
29
+ return false; // Shift+Enter stays a plain line break
30
+ const handled = $exitPoetryOnEnter();
31
+ if (handled)
32
+ event?.preventDefault();
33
+ return handled;
34
+ }, COMMAND_PRIORITY_HIGH));
25
35
  }, [editor]);
26
36
  return null;
27
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inshapardaz/likhari-react",
3
- "version": "0.1.18-dev.130",
3
+ "version": "0.1.18-dev.134",
4
4
  "description": "React implementation of the Likhari editor, built on @lexical/react.",
5
5
  "license": "MIT",
6
6
  "repository": {