@inshapardaz/likhari-react 0.1.9-dev.94 → 0.1.9-dev.99

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.
@@ -1 +1 @@
1
- {"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"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"}
@@ -19,6 +19,7 @@ import { EditorThemeProvider } from './theme/EditorThemeProvider.js';
19
19
  import { Toolbar } from './components/Toolbar.js';
20
20
  import { injectUrduWebFontsCss } from './fonts/index.js';
21
21
  import { LinkPastePlugin } from './plugins/LinkPastePlugin.js';
22
+ import { PageBreakPlugin } from './plugins/PageBreakPlugin.js';
22
23
  import { DraftRestore } from './components/DraftRestore.js';
23
24
  import { LeaveDialog } from './components/LeaveDialog.js';
24
25
  import { clearDraft, createDraftId, hasDraftContent, pruneDrafts, writeDraft, } from './persistence/draftStorage.js';
@@ -267,7 +268,7 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
267
268
  const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
268
269
  return (_jsx(EditorThemeProvider, { theme: theme, colorScheme: colorScheme, accentColor: accentColor, scopeElementId: portalTargetId, children: _jsxs("div", { className: "likhari-root", dir: dir, ref: rootElementRef, "data-document-id": documentId, style: { height: typeof height === 'number' ? `${height}px` : height }, children: [_jsx("div", { id: portalTargetId, className: "likhari-portal-target" }), _jsx(PortalTargetContext.Provider, { value: portalTargetSelector, children: _jsxs(UiStringsContext.Provider, { value: strings, children: [_jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
269
270
  ? { currentId: draftId, maxBytes: autosaveMaxBytes, adoptOnRestore: !documentId, onRestored: handleDraftRestored }
270
- : undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, "aria-label": strings.editor.contentLabel }), placeholder: _jsx("div", { className: "likhari-placeholder", children: resolvedPlaceholder }), ErrorBoundary: LexicalErrorBoundary }) }), config.history && _jsx(HistoryPlugin, {}), (config.lists.bullet || config.lists.numbered || config.lists.check) && _jsx(ListPlugin, {}), config.lists.check && _jsx(CheckListPlugin, {}), config.links && _jsx(LinkPlugin, {}), config.links && _jsx(LinkPastePlugin, {}), config.tables && _jsx(TablePlugin, { hasCellMerge: false, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
271
+ : undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, "aria-label": strings.editor.contentLabel }), placeholder: _jsx("div", { className: "likhari-placeholder", children: resolvedPlaceholder }), ErrorBoundary: LexicalErrorBoundary }) }), config.history && _jsx(HistoryPlugin, {}), (config.lists.bullet || config.lists.numbered || config.lists.check) && _jsx(ListPlugin, {}), config.lists.check && _jsx(CheckListPlugin, {}), config.links && _jsx(LinkPlugin, {}), config.links && _jsx(LinkPastePlugin, {}), config.blocks.pageBreak && _jsx(PageBreakPlugin, {}), config.tables && _jsx(TablePlugin, { hasCellMerge: false, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
271
272
  handleSave();
272
273
  settleLeave(true);
273
274
  }, onSaveDraft: () => {
@@ -0,0 +1,30 @@
1
+ import { type ReactElement } from 'react';
2
+ import { DecoratorNode, type DOMConversionMap, type DOMExportOutput, type EditorConfig, type LexicalCommand, type LexicalNode, type SerializedLexicalNode } from 'lexical';
3
+ export declare const INSERT_PAGE_BREAK_COMMAND: LexicalCommand<void>;
4
+ export type SerializedPageBreakNode = SerializedLexicalNode;
5
+ /**
6
+ * A manual page break — a print/paginated-export concept with no native
7
+ * Lexical node (lexical-editor-spec.md §4.3/§4.6). Renders as a visible
8
+ * dashed marker while editing, and as `page-break-after: always` both live
9
+ * (a print stylesheet, editor.css) and in exported HTML (`exportDOM`).
10
+ *
11
+ * Mirrors @lexical/react's HorizontalRuleNode pattern: `createDOM` returns
12
+ * the actual visible element (the click target `PageBreakComponent` wires
13
+ * selection/delete against), rather than `decorate()` rendering visuals.
14
+ */
15
+ export declare class PageBreakNode extends DecoratorNode<ReactElement> {
16
+ static getType(): string;
17
+ static clone(node: PageBreakNode): PageBreakNode;
18
+ static importJSON(): PageBreakNode;
19
+ exportJSON(): SerializedPageBreakNode;
20
+ static importDOM(): DOMConversionMap | null;
21
+ exportDOM(): DOMExportOutput;
22
+ createDOM(config: EditorConfig): HTMLElement;
23
+ getTextContent(): string;
24
+ isInline(): false;
25
+ updateDOM(): boolean;
26
+ decorate(): import("react").JSX.Element;
27
+ }
28
+ export declare function $createPageBreakNode(): PageBreakNode;
29
+ export declare function $isPageBreakNode(node: LexicalNode | null | undefined): node is PageBreakNode;
30
+ //# sourceMappingURL=PageBreakNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageBreakNode.d.ts","sourceRoot":"","sources":["../../src/blocks/PageBreakNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAKlE,OAAO,EAOL,aAAa,EAGb,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,KAAK,qBAAqB,EAC3B,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,yBAAyB,EAAE,cAAc,CAAC,IAAI,CAA8C,CAAC;AAE1G,MAAM,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AA6D5D;;;;;;;;;GASG;AACH,qBAAa,aAAc,SAAQ,aAAa,CAAC,YAAY,CAAC;IAC5D,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa;IAIhD,MAAM,CAAC,UAAU,IAAI,aAAa;IAIlC,UAAU,IAAI,uBAAuB;IAIrC,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAS3C,SAAS,IAAI,eAAe;IAO5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAM5C,cAAc,IAAI,MAAM;IAIxB,QAAQ,IAAI,KAAK;IAIjB,SAAS,IAAI,OAAO;IAIpB,QAAQ;CAGT;AAED,wBAAgB,oBAAoB,IAAI,aAAa,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,aAAa,CAE5F"}
@@ -0,0 +1,112 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect } from 'react';
3
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
4
+ import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
5
+ import { addClassNamesToElement, mergeRegister, removeClassNamesFromElement } from '@lexical/utils';
6
+ import { useUiStrings } from '../i18n/useStrings.js';
7
+ import { $applyNodeReplacement, $getSelection, $isNodeSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, createCommand, DecoratorNode, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, } from 'lexical';
8
+ export const INSERT_PAGE_BREAK_COMMAND = createCommand('INSERT_PAGE_BREAK_COMMAND');
9
+ const SELECTED_CLASS_NAME = 'likhari-page-break-selected';
10
+ function PageBreakComponent({ nodeKey }) {
11
+ const [editor] = useLexicalComposerContext();
12
+ const strings = useUiStrings();
13
+ const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
14
+ const onDelete = useCallback((event) => {
15
+ const selection = $getSelection();
16
+ if (isSelected && $isNodeSelection(selection)) {
17
+ event.preventDefault();
18
+ editor.update(() => {
19
+ selection.getNodes().forEach((node) => {
20
+ if ($isPageBreakNode(node))
21
+ node.remove();
22
+ });
23
+ });
24
+ }
25
+ return false;
26
+ }, [editor, isSelected]);
27
+ useEffect(() => {
28
+ return mergeRegister(editor.registerCommand(CLICK_COMMAND, (event) => {
29
+ const element = editor.getElementByKey(nodeKey);
30
+ // The marker is made of child spans (the label and two lines), so a
31
+ // click almost never lands on the outer element itself.
32
+ if (!element || !element.contains(event.target))
33
+ return false;
34
+ if (!event.shiftKey)
35
+ clearSelection();
36
+ setSelected(!isSelected);
37
+ return true;
38
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW));
39
+ }, [clearSelection, editor, isSelected, nodeKey, onDelete, setSelected]);
40
+ useEffect(() => {
41
+ const element = editor.getElementByKey(nodeKey);
42
+ if (!element)
43
+ return;
44
+ if (isSelected)
45
+ addClassNamesToElement(element, SELECTED_CLASS_NAME);
46
+ else
47
+ removeClassNamesFromElement(element, SELECTED_CLASS_NAME);
48
+ }, [editor, isSelected, nodeKey]);
49
+ return (_jsxs(_Fragment, { children: [_jsx("span", { className: "likhari-page-break-line", "aria-hidden": "true" }), _jsx("span", { className: "likhari-page-break-label", children: strings.editor.pageBreakLabel }), _jsx("span", { className: "likhari-page-break-line", "aria-hidden": "true" })] }));
50
+ }
51
+ /**
52
+ * A manual page break — a print/paginated-export concept with no native
53
+ * Lexical node (lexical-editor-spec.md §4.3/§4.6). Renders as a visible
54
+ * dashed marker while editing, and as `page-break-after: always` both live
55
+ * (a print stylesheet, editor.css) and in exported HTML (`exportDOM`).
56
+ *
57
+ * Mirrors @lexical/react's HorizontalRuleNode pattern: `createDOM` returns
58
+ * the actual visible element (the click target `PageBreakComponent` wires
59
+ * selection/delete against), rather than `decorate()` rendering visuals.
60
+ */
61
+ export class PageBreakNode extends DecoratorNode {
62
+ static getType() {
63
+ return 'page-break';
64
+ }
65
+ static clone(node) {
66
+ return new PageBreakNode(node.__key);
67
+ }
68
+ static importJSON() {
69
+ return $createPageBreakNode();
70
+ }
71
+ exportJSON() {
72
+ return { type: 'page-break', version: 1 };
73
+ }
74
+ static importDOM() {
75
+ return {
76
+ div: (domNode) => {
77
+ if (!domNode.hasAttribute('data-likhari-page-break'))
78
+ return null;
79
+ return { conversion: () => ({ node: $createPageBreakNode() }), priority: 2 };
80
+ },
81
+ };
82
+ }
83
+ exportDOM() {
84
+ const element = document.createElement('div');
85
+ element.setAttribute('data-likhari-page-break', '');
86
+ element.style.pageBreakAfter = 'always';
87
+ return { element };
88
+ }
89
+ createDOM(config) {
90
+ const element = document.createElement('div');
91
+ addClassNamesToElement(element, config.theme.pageBreak ?? 'likhari-page-break');
92
+ return element;
93
+ }
94
+ getTextContent() {
95
+ return '\n';
96
+ }
97
+ isInline() {
98
+ return false;
99
+ }
100
+ updateDOM() {
101
+ return false;
102
+ }
103
+ decorate() {
104
+ return _jsx(PageBreakComponent, { nodeKey: this.__key });
105
+ }
106
+ }
107
+ export function $createPageBreakNode() {
108
+ return $applyNodeReplacement(new PageBreakNode());
109
+ }
110
+ export function $isPageBreakNode(node) {
111
+ return node instanceof PageBreakNode;
112
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AA8CA,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;AAwUvD,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,+BAszBxJ"}
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AAuDA,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;AA+YvD,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,+BAg7BxJ"}
@@ -11,8 +11,10 @@ import { $findMatchingParent, $insertNodeToNearestRoot } from '@lexical/utils';
11
11
  import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode';
12
12
  import { ImageDialog } from '../image/ImageDialog.js';
13
13
  import { $createImageNode } from '../image/ImageNode.js';
14
+ import { INSERT_PAGE_BREAK_COMMAND } from '../blocks/PageBreakNode.js';
14
15
  import { TableDialog } from './TableDialog.js';
15
- import { INSERT_TABLE_COMMAND } from '@lexical/table';
16
+ import { $getTableCellNodeFromLexicalNode, $isTableSelection, INSERT_TABLE_COMMAND } from '@lexical/table';
17
+ import { $deleteTable, $deleteTableColumns, $deleteTableRows, $getTableSelectionSize, $insertTableColumns, $insertTableRows, } from '../table/tableActions.js';
16
18
  import { $createLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
17
19
  import { LinkDialog } from './LinkDialog.js';
18
20
  import { DraftsDialog } from './DraftsDialog.js';
@@ -21,7 +23,7 @@ import { CANVAS_FONT_DEFAULTS, DEFAULT_FONT_OPTIONS, FONT_SIZES_PX } from '../fo
21
23
  import { setStyleProperty } from '../utils/style.js';
22
24
  import { useStrings } from '../i18n/useStrings.js';
23
25
  import { usePortalTarget } from '../PortalTargetContext.js';
24
- 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, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSeparatorHorizontal, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconTable, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
26
+ 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, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconTable, IconTableMinus, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
25
27
  /** Sentinel for "no inline style": Lexical returns the default it is given when
26
28
  * the selection has none, so this tells "unstyled" (show the canvas default)
27
29
  * apart from "styled with a value the dropdown doesn't list" (show nothing). */
@@ -35,6 +37,9 @@ const INITIAL_STATE = {
35
37
  fontSize: UNSET_STYLE,
36
38
  isLink: false,
37
39
  linkUrl: '',
40
+ inTable: false,
41
+ tableRows: 1,
42
+ tableColumns: 1,
38
43
  canUndo: false,
39
44
  canRedo: false,
40
45
  };
@@ -123,6 +128,21 @@ function LinkMenuItems({ url, onEdit, onRemove, strings }) {
123
128
  // Not a URL the editor would accept (e.g. loaded from a document): show it, don't make it clickable.
124
129
  _jsx(Menu.Item, { disabled: true, title: url, className: "likhari-link-menu-url", children: url || strings.link.noUrl })), _jsx(Menu.Item, { leftSection: _jsx(IconPencil, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onEdit, children: strings.link.editLink }), _jsx(Menu.Item, { color: "red", leftSection: _jsx(IconLinkOff, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onRemove, children: strings.link.removeLink })] }));
125
130
  }
131
+ /** The table actions menu's contents — shared by the toolbar button and the
132
+ * right-click menu. Each acts on the selected cell, or on every row/column a
133
+ * multi-cell selection covers. */
134
+ function TableMenuItems({ strings, direction, rows, columns, onAction, }) {
135
+ const t = strings.tableMenu;
136
+ // "Before" is the start side, which is on the right in an RTL table.
137
+ const rtl = direction === 'rtl';
138
+ const manyRows = rows > 1;
139
+ const manyColumns = columns > 1;
140
+ const item = (icon, label, action, color) => {
141
+ const Icon = icon;
142
+ return (_jsx(Menu.Item, { color: color, leftSection: _jsx(Icon, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onAction(action), children: label }));
143
+ };
144
+ 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)), _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')] }));
145
+ }
126
146
  export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
127
147
  const [editor] = useLexicalComposerContext();
128
148
  const [state, setState] = useState(INITIAL_STATE);
@@ -141,9 +161,17 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
141
161
  const updateToolbar = useCallback(() => {
142
162
  editor.getEditorState().read(() => {
143
163
  const selection = $getSelection();
164
+ // A selection of several table cells isn't a range selection.
165
+ if ($isTableSelection(selection)) {
166
+ const { rows, columns } = $getTableSelectionSize();
167
+ setState((s) => ({ ...s, inTable: true, tableRows: rows, tableColumns: columns }));
168
+ return;
169
+ }
144
170
  if (!$isRangeSelection(selection))
145
171
  return;
146
172
  const anchorNode = selection.anchor.getNode();
173
+ const inTable = $getTableCellNodeFromLexicalNode(anchorNode) !== null;
174
+ const tableSize = inTable ? $getTableSelectionSize() : { rows: 1, columns: 1 };
147
175
  const element = anchorNode.getKey() === 'root' ? anchorNode : (anchorNode.getTopLevelElement() ?? anchorNode);
148
176
  const listParent = $findMatchingParent(anchorNode, $isListNode);
149
177
  const listType = listParent && $isListNode(listParent) ? listParent.getListType() : null;
@@ -179,6 +207,9 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
179
207
  fontSize,
180
208
  isLink,
181
209
  linkUrl,
210
+ inTable,
211
+ tableRows: tableSize.rows,
212
+ tableColumns: tableSize.columns,
182
213
  }));
183
214
  });
184
215
  }, [editor]);
@@ -391,6 +422,50 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
391
422
  root?.addEventListener('contextmenu', onContextMenu);
392
423
  });
393
424
  }, [editor, config.links]);
425
+ // Table actions. The menu takes focus, so the selection is snapshotted when it
426
+ // opens and restored before an action runs.
427
+ const runTableAction = (action) => () => {
428
+ restoreSelection();
429
+ editor.update(action);
430
+ editor.focus();
431
+ };
432
+ // Right-clicking a table cell opens the same actions at the pointer.
433
+ const [tableContext, setTableContext] = useState(null);
434
+ useEffect(() => {
435
+ if (!config.tables)
436
+ return;
437
+ const onContextMenu = (event) => {
438
+ if (event.defaultPrevented)
439
+ return; // a link inside the cell already took it
440
+ const cellElement = event.target?.closest?.('td, th');
441
+ if (!cellElement)
442
+ return;
443
+ let handled = false;
444
+ editor.update(() => {
445
+ const node = $getNearestNodeFromDOMNode(cellElement);
446
+ const cell = node ? $getTableCellNodeFromLexicalNode(node) : null;
447
+ if (!cell)
448
+ return;
449
+ handled = true;
450
+ const selection = $getSelection();
451
+ // Keep a multi-cell selection that includes this cell, so "insert
452
+ // rows" / "delete columns" act on everything selected.
453
+ const insideSelection = $isTableSelection(selection) && selection.getNodes().some((n) => n.getKey() === cell.getKey());
454
+ if (!insideSelection)
455
+ cell.selectEnd();
456
+ }, { discrete: true });
457
+ if (!handled)
458
+ return;
459
+ event.preventDefault();
460
+ snapshotSelectionRef.current();
461
+ const size = editor.getEditorState().read($getTableSelectionSize);
462
+ setTableContext({ x: event.clientX, y: event.clientY, rows: size.rows, columns: size.columns });
463
+ };
464
+ return editor.registerRootListener((root, previous) => {
465
+ previous?.removeEventListener('contextmenu', onContextMenu);
466
+ root?.addEventListener('contextmenu', onContextMenu);
467
+ });
468
+ }, [editor, config.tables]);
394
469
  // Ctrl/Cmd+K opens the link dialog.
395
470
  useEffect(() => {
396
471
  if (!config.links)
@@ -451,7 +526,12 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
451
526
  const showFormattingGroup = headingLevels.length > 0 || config.lists.bullet || config.lists.numbered || config.lists.check || config.blocks.quote;
452
527
  const showInlineGroup = fmt.bold || fmt.italic || fmt.underline;
453
528
  const showAlignGroup = config.alignment.start || config.alignment.center || config.alignment.justify || config.alignment.left || config.alignment.right;
454
- const showStubInsertGroup = config.images.linked || config.images.embedded || config.tables || config.blocks.horizontalRule || config.poetry.enabled;
529
+ const showStubInsertGroup = config.images.linked ||
530
+ config.images.embedded ||
531
+ config.tables ||
532
+ config.blocks.horizontalRule ||
533
+ config.blocks.pageBreak ||
534
+ config.poetry.enabled;
455
535
  const showLanguageGroup = config.language.autocorrect || config.language.textCleanup || config.language.spellCheck;
456
536
  // The "script & cleanup" and "indent/outdent" groups (UI spec §3.3) render
457
537
  // as normal inline toolbar groups whenever there's room, and only move
@@ -621,7 +701,8 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
621
701
  restoreSelection();
622
702
  openLinkDialog();
623
703
  }, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog })) }, "link")),
624
- 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.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.poetry.enabled && _jsx(StubButton, { icon: IconFeather, title: strings.toolbar.poetryBlocks, comingSoon: strings.toolbar.comingSoon })] }, "stubInsert")),
704
+ 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.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.poetry.enabled && _jsx(StubButton, { icon: IconFeather, title: strings.toolbar.poetryBlocks, comingSoon: strings.toolbar.comingSoon })] }, "stubInsert")),
705
+ 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, onAction: runTableAction }) })] }) }, "tableActions")),
625
706
  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")),
626
707
  ];
627
708
  return (_jsxs("div", { className: "likhari-toolbar", role: "toolbar", "aria-label": strings.toolbar.ariaLabel, ref: toolbarContainerRef, children: [fixedGroups, movableGroups
@@ -634,7 +715,10 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
634
715
  }, 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: linkContext?.x ?? -9999, top: linkContext?.y ?? -9999, width: 1, height: 1, pointerEvents: 'none' } }) }), _jsx(Menu.Dropdown, { children: _jsx(LinkMenuItems, { url: linkContext?.url ?? '', onEdit: () => {
635
716
  restoreSelection();
636
717
  openLinkDialog();
637
- }, onRemove: removeLink, strings: strings }) })] })), _jsxs("div", { "aria-hidden": "true", ref: toolbarMeasureRef, style: {
718
+ }, onRemove: removeLink, strings: strings }) })] })), config.tables && (_jsxs(Menu, { opened: tableContext !== null, onChange: (opened) => {
719
+ if (!opened)
720
+ setTableContext(null);
721
+ }, 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, onAction: runTableAction }) })] })), _jsxs("div", { "aria-hidden": "true", ref: toolbarMeasureRef, style: {
638
722
  position: 'absolute',
639
723
  visibility: 'hidden',
640
724
  pointerEvents: 'none',
@@ -13,6 +13,8 @@ export interface Strings {
13
13
  placeholder: string;
14
14
  /** aria-label on the contenteditable itself. */
15
15
  contentLabel: string;
16
+ /** Label shown on a page-break marker's dashed line while editing. */
17
+ pageBreakLabel: string;
16
18
  };
17
19
  common: {
18
20
  cancel: string;
@@ -38,8 +40,11 @@ export interface Strings {
38
40
  noMatch: string;
39
41
  alignment: string;
40
42
  linkOptions: string;
43
+ /** Toolbar button (shown while the caret is in a table) that opens the table actions menu. */
44
+ tableOptions: string;
41
45
  insertLink: string;
42
46
  insertImage: string;
47
+ insertPageBreak: string;
43
48
  insertTable: string;
44
49
  insertHorizontalRule: string;
45
50
  poetryBlocks: string;
@@ -109,6 +114,24 @@ export interface Strings {
109
114
  delete: string;
110
115
  close: string;
111
116
  };
117
+ /** The table actions menu (toolbar button and right-click on a cell). */
118
+ tableMenu: {
119
+ menuLabel: string;
120
+ insertRowBefore: string;
121
+ insertRowAfter: string;
122
+ insertColumnBefore: string;
123
+ insertColumnAfter: string;
124
+ deleteRow: string;
125
+ deleteColumn: string;
126
+ deleteTable: string;
127
+ /** Plural forms, used when the selection spans several rows or columns. */
128
+ insertRowsBefore: string;
129
+ insertRowsAfter: string;
130
+ insertColumnsBefore: string;
131
+ insertColumnsAfter: string;
132
+ deleteRows: string;
133
+ deleteColumns: string;
134
+ };
112
135
  link: {
113
136
  menuLabel: string;
114
137
  noUrl: string;
@@ -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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"}
@@ -8,6 +8,7 @@ const en = {
8
8
  editor: {
9
9
  placeholder: 'Start writing…',
10
10
  contentLabel: 'Editor content',
11
+ pageBreakLabel: 'Page break',
11
12
  },
12
13
  common: {
13
14
  cancel: 'Cancel',
@@ -31,8 +32,10 @@ const en = {
31
32
  noMatch: 'No match',
32
33
  alignment: 'Alignment',
33
34
  linkOptions: 'Link options',
35
+ tableOptions: 'Table options',
34
36
  insertLink: 'Insert link (Ctrl+K)',
35
37
  insertImage: 'Insert image',
38
+ insertPageBreak: 'Insert page break',
36
39
  insertTable: 'Insert table',
37
40
  insertHorizontalRule: 'Insert horizontal rule',
38
41
  poetryBlocks: 'Poetry blocks',
@@ -97,6 +100,22 @@ const en = {
97
100
  delete: 'Delete',
98
101
  close: 'Close',
99
102
  },
103
+ tableMenu: {
104
+ menuLabel: 'Table',
105
+ insertRowBefore: 'Insert row before',
106
+ insertRowAfter: 'Insert row after',
107
+ insertColumnBefore: 'Insert column before',
108
+ insertColumnAfter: 'Insert column after',
109
+ deleteRow: 'Delete row',
110
+ deleteColumn: 'Delete column',
111
+ deleteTable: 'Delete table',
112
+ insertRowsBefore: 'Insert rows before',
113
+ insertRowsAfter: 'Insert rows after',
114
+ insertColumnsBefore: 'Insert columns before',
115
+ insertColumnsAfter: 'Insert columns after',
116
+ deleteRows: 'Delete rows',
117
+ deleteColumns: 'Delete columns',
118
+ },
100
119
  link: {
101
120
  menuLabel: 'Link',
102
121
  noUrl: '(no URL)',
@@ -182,6 +201,7 @@ const ur = {
182
201
  editor: {
183
202
  placeholder: 'لکھنا شروع کریں…',
184
203
  contentLabel: 'ایڈیٹر کا مواد',
204
+ pageBreakLabel: 'صفحے کی تقسیم',
185
205
  },
186
206
  common: {
187
207
  cancel: 'منسوخ کریں',
@@ -205,8 +225,10 @@ const ur = {
205
225
  noMatch: 'کوئی مماثلت نہیں',
206
226
  alignment: 'سیدھ',
207
227
  linkOptions: 'لنک کے اختیارات',
228
+ tableOptions: 'جدول کے اختیارات',
208
229
  insertLink: 'لنک شامل کریں (Ctrl+K)',
209
230
  insertImage: 'تصویر شامل کریں',
231
+ insertPageBreak: 'صفحے کی تقسیم شامل کریں',
210
232
  insertTable: 'جدول شامل کریں',
211
233
  insertHorizontalRule: 'افقی لکیر شامل کریں',
212
234
  poetryBlocks: 'شاعری کے بلاکس',
@@ -271,6 +293,22 @@ const ur = {
271
293
  delete: 'حذف کریں',
272
294
  close: 'بند کریں',
273
295
  },
296
+ tableMenu: {
297
+ menuLabel: 'جدول',
298
+ insertRowBefore: 'پہلے قطار شامل کریں',
299
+ insertRowAfter: 'بعد میں قطار شامل کریں',
300
+ insertColumnBefore: 'پہلے کالم شامل کریں',
301
+ insertColumnAfter: 'بعد میں کالم شامل کریں',
302
+ deleteRow: 'قطار حذف کریں',
303
+ deleteColumn: 'کالم حذف کریں',
304
+ deleteTable: 'جدول حذف کریں',
305
+ insertRowsBefore: 'پہلے قطاریں شامل کریں',
306
+ insertRowsAfter: 'بعد میں قطاریں شامل کریں',
307
+ insertColumnsBefore: 'پہلے کالمز شامل کریں',
308
+ insertColumnsAfter: 'بعد میں کالمز شامل کریں',
309
+ deleteRows: 'قطاریں حذف کریں',
310
+ deleteColumns: 'کالمز حذف کریں',
311
+ },
274
312
  link: {
275
313
  menuLabel: 'لنک',
276
314
  noUrl: '(کوئی یو آر ایل نہیں)',
@@ -356,6 +394,7 @@ const paShahmukhi = {
356
394
  editor: {
357
395
  placeholder: 'لکھنا شروع کرو…',
358
396
  contentLabel: 'ایڈیٹر دی سامگری',
397
+ pageBreakLabel: 'صفحے دی ونڈ',
359
398
  },
360
399
  common: {
361
400
  cancel: 'رد کرو',
@@ -379,8 +418,10 @@ const paShahmukhi = {
379
418
  noMatch: 'کوئی نئیں ملیا',
380
419
  alignment: 'سیدھ',
381
420
  linkOptions: 'لنک دے اختیار',
421
+ tableOptions: 'ٹیبل دے اختیار',
382
422
  insertLink: 'لنک پاؤ (Ctrl+K)',
383
423
  insertImage: 'تصویر پاؤ',
424
+ insertPageBreak: 'صفحے دی ونڈ پاؤ',
384
425
  insertTable: 'ٹیبل پاؤ',
385
426
  insertHorizontalRule: 'لیٹی لکیر پاؤ',
386
427
  poetryBlocks: 'شاعری بلاک',
@@ -445,6 +486,22 @@ const paShahmukhi = {
445
486
  delete: 'مٹاؤ',
446
487
  close: 'بند کرو',
447
488
  },
489
+ tableMenu: {
490
+ menuLabel: 'ٹیبل',
491
+ insertRowBefore: 'پہلاں قطار پاؤ',
492
+ insertRowAfter: 'بعد وچ قطار پاؤ',
493
+ insertColumnBefore: 'پہلاں کالم پاؤ',
494
+ insertColumnAfter: 'بعد وچ کالم پاؤ',
495
+ deleteRow: 'قطار مٹاؤ',
496
+ deleteColumn: 'کالم مٹاؤ',
497
+ deleteTable: 'ٹیبل مٹاؤ',
498
+ insertRowsBefore: 'پہلاں قطاراں پاؤ',
499
+ insertRowsAfter: 'بعد وچ قطاراں پاؤ',
500
+ insertColumnsBefore: 'پہلاں کالماں پاؤ',
501
+ insertColumnsAfter: 'بعد وچ کالماں پاؤ',
502
+ deleteRows: 'قطاراں مٹاؤ',
503
+ deleteColumns: 'کالماں مٹاؤ',
504
+ },
448
505
  link: {
449
506
  menuLabel: 'لنک',
450
507
  noUrl: '(کوئی یو آر ایل نئیں)',
@@ -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;AAQlD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAW5C,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;AASlD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAY5C,CAAC"}
package/dist/nodes.js CHANGED
@@ -4,6 +4,7 @@ import { LinkNode } from '@lexical/link';
4
4
  import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';
5
5
  import { TableCellNode, TableNode, TableRowNode } from '@lexical/table';
6
6
  import { ImageNode } from './image/ImageNode.js';
7
+ import { PageBreakNode } from './blocks/PageBreakNode.js';
7
8
  /**
8
9
  * Node types registered on the editor at construction time. Per
9
10
  * editor-architecture-design.md §2, node registration cannot be conditional
@@ -24,4 +25,5 @@ export const EDITOR_NODES = [
24
25
  TableRowNode,
25
26
  TableCellNode,
26
27
  ImageNode,
28
+ PageBreakNode,
27
29
  ];
@@ -0,0 +1,3 @@
1
+ /** Registers INSERT_PAGE_BREAK_COMMAND — mirrors @lexical/react's own HorizontalRulePlugin. */
2
+ export declare function PageBreakPlugin(): null;
3
+ //# sourceMappingURL=PageBreakPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageBreakPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PageBreakPlugin.tsx"],"names":[],"mappings":"AAMA,+FAA+F;AAC/F,wBAAgB,eAAe,SAiB9B"}
@@ -0,0 +1,19 @@
1
+ import { useEffect } from 'react';
2
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
3
+ import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR } from 'lexical';
4
+ import { $insertNodeToNearestRoot } from '@lexical/utils';
5
+ import { $createPageBreakNode, INSERT_PAGE_BREAK_COMMAND } from '../blocks/PageBreakNode.js';
6
+ /** Registers INSERT_PAGE_BREAK_COMMAND — mirrors @lexical/react's own HorizontalRulePlugin. */
7
+ export function PageBreakPlugin() {
8
+ const [editor] = useLexicalComposerContext();
9
+ useEffect(() => {
10
+ return editor.registerCommand(INSERT_PAGE_BREAK_COMMAND, () => {
11
+ const selection = $getSelection();
12
+ if (!$isRangeSelection(selection))
13
+ return false;
14
+ $insertNodeToNearestRoot($createPageBreakNode());
15
+ return true;
16
+ }, COMMAND_PRIORITY_EDITOR);
17
+ }, [editor]);
18
+ return null;
19
+ }
@@ -0,0 +1,21 @@
1
+ /** How many rows and columns the selection spans (1 × 1 for a caret in a cell, 0 × 0 outside a table). */
2
+ export declare function $getTableSelectionSize(): {
3
+ rows: number;
4
+ columns: number;
5
+ };
6
+ /**
7
+ * Inserts as many rows as the selection spans, before its first row or after
8
+ * its last. Lexical's own insert works from the selection's focus cell and adds
9
+ * one row, so with several rows selected it would land mid-selection.
10
+ */
11
+ export declare function $insertTableRows(insertAfter: boolean): void;
12
+ /** Like $insertTableRows, for columns. "Before" is the column index below the
13
+ * first selected one (the right-hand side in a right-to-left table). */
14
+ export declare function $insertTableColumns(insertAfter: boolean): void;
15
+ /** Deletes every row the selection touches (Lexical handles a multi-cell selection). */
16
+ export declare function $deleteTableRows(): void;
17
+ /** Deletes every column the selection touches. */
18
+ export declare function $deleteTableColumns(): void;
19
+ /** Removes the whole table the selection is in. */
20
+ export declare function $deleteTable(): void;
21
+ //# sourceMappingURL=tableActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tableActions.d.ts","sourceRoot":"","sources":["../../src/table/tableActions.ts"],"names":[],"mappings":"AA2BA,0GAA0G;AAC1G,wBAAgB,sBAAsB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAS1E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAS3D;AAED;wEACwE;AACxE,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAQ9D;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,kDAAkD;AAClD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,mDAAmD;AACnD,wBAAgB,YAAY,IAAI,IAAI,CAInC"}
@@ -0,0 +1,71 @@
1
+ import { $deleteTableColumn__EXPERIMENTAL, $deleteTableRow__EXPERIMENTAL, $getTableCellNodeFromLexicalNode, $getTableColumnIndexFromTableCellNode, $getTableNodeFromLexicalNodeOrThrow, $getTableRowIndexFromTableCellNode, $insertTableColumn__EXPERIMENTAL, $insertTableRow__EXPERIMENTAL, $isTableCellNode, $isTableSelection, } from '@lexical/table';
2
+ import { $getSelection, $isRangeSelection } from 'lexical';
3
+ /** Table cells the selection covers: the caret's own cell, or every cell of a
4
+ * multi-cell selection. Empty when the selection isn't in a table. */
5
+ function $selectedCells() {
6
+ const selection = $getSelection();
7
+ if ($isTableSelection(selection))
8
+ return selection.getNodes().filter($isTableCellNode);
9
+ if ($isRangeSelection(selection)) {
10
+ const cell = $getTableCellNodeFromLexicalNode(selection.anchor.getNode());
11
+ return cell ? [cell] : [];
12
+ }
13
+ return [];
14
+ }
15
+ /** How many rows and columns the selection spans (1 × 1 for a caret in a cell, 0 × 0 outside a table). */
16
+ export function $getTableSelectionSize() {
17
+ const cells = $selectedCells();
18
+ if (cells.length === 0)
19
+ return { rows: 0, columns: 0 };
20
+ const rows = cells.map($getTableRowIndexFromTableCellNode);
21
+ const columns = cells.map($getTableColumnIndexFromTableCellNode);
22
+ return {
23
+ rows: Math.max(...rows) - Math.min(...rows) + 1,
24
+ columns: Math.max(...columns) - Math.min(...columns) + 1,
25
+ };
26
+ }
27
+ /**
28
+ * Inserts as many rows as the selection spans, before its first row or after
29
+ * its last. Lexical's own insert works from the selection's focus cell and adds
30
+ * one row, so with several rows selected it would land mid-selection.
31
+ */
32
+ export function $insertTableRows(insertAfter) {
33
+ const cells = $selectedCells();
34
+ if (cells.length === 0)
35
+ return;
36
+ const rows = cells.map($getTableRowIndexFromTableCellNode);
37
+ const first = Math.min(...rows);
38
+ const last = Math.max(...rows);
39
+ // Park the caret in a cell on the edge row; every insert then lands right next to it.
40
+ cells[rows.indexOf(insertAfter ? last : first)].selectEnd();
41
+ for (let i = 0; i <= last - first; i++)
42
+ $insertTableRow__EXPERIMENTAL(insertAfter);
43
+ }
44
+ /** Like $insertTableRows, for columns. "Before" is the column index below the
45
+ * first selected one (the right-hand side in a right-to-left table). */
46
+ export function $insertTableColumns(insertAfter) {
47
+ const cells = $selectedCells();
48
+ if (cells.length === 0)
49
+ return;
50
+ const columns = cells.map($getTableColumnIndexFromTableCellNode);
51
+ const first = Math.min(...columns);
52
+ const last = Math.max(...columns);
53
+ cells[columns.indexOf(insertAfter ? last : first)].selectEnd();
54
+ for (let i = 0; i <= last - first; i++)
55
+ $insertTableColumn__EXPERIMENTAL(insertAfter);
56
+ }
57
+ /** Deletes every row the selection touches (Lexical handles a multi-cell selection). */
58
+ export function $deleteTableRows() {
59
+ $deleteTableRow__EXPERIMENTAL();
60
+ }
61
+ /** Deletes every column the selection touches. */
62
+ export function $deleteTableColumns() {
63
+ $deleteTableColumn__EXPERIMENTAL();
64
+ }
65
+ /** Removes the whole table the selection is in. */
66
+ export function $deleteTable() {
67
+ const selection = $getSelection();
68
+ const anchor = $isRangeSelection(selection) || $isTableSelection(selection) ? selection.anchor.getNode() : null;
69
+ if (anchor)
70
+ $getTableNodeFromLexicalNodeOrThrow(anchor).remove();
71
+ }
@@ -51,6 +51,12 @@
51
51
  pointer-events: none;
52
52
  }
53
53
 
54
+ /* pointer-events is inherited, so without this every menu, dropdown and dialog
55
+ portaled into the (pointer-transparent) anchor would be unclickable. */
56
+ .likhari-portal-target > * {
57
+ pointer-events: auto;
58
+ }
59
+
54
60
  .likhari-toolbar-group {
55
61
  display: flex;
56
62
  align-items: center;
@@ -253,6 +259,45 @@
253
259
  margin: 1.5em 0;
254
260
  }
255
261
 
262
+ /* Page break — a print/export concept with no visual meaning while editing
263
+ on screen, so it gets its own clearly-labeled dashed marker rather than
264
+ masquerading as a horizontal rule. The actual page-break behavior only
265
+ takes effect when printing (lexical-editor-spec.md §4.3/§4.6). */
266
+ .likhari-page-break {
267
+ display: flex;
268
+ align-items: center;
269
+ gap: 8px;
270
+ margin: 1.5em 0;
271
+ font-size: 12px;
272
+ cursor: default;
273
+ }
274
+
275
+ .likhari-page-break-line {
276
+ flex: 1 1 auto;
277
+ border-top: 1px dashed var(--editor-line);
278
+ }
279
+
280
+ .likhari-page-break-label {
281
+ color: var(--editor-ink-soft);
282
+ white-space: nowrap;
283
+ }
284
+
285
+ .likhari-page-break-selected {
286
+ outline: 2px solid var(--editor-accent);
287
+ outline-offset: 2px;
288
+ border-radius: 4px;
289
+ }
290
+
291
+ @media print {
292
+ .likhari-page-break {
293
+ page-break-after: always;
294
+ /* Hide the on-screen marker itself when actually printing — the
295
+ browser's own pagination (triggered by page-break-after) is what
296
+ matters there, not the editing-time label. */
297
+ visibility: hidden;
298
+ }
299
+ }
300
+
256
301
  /* Tables — cell merge/split is deliberately out of scope for now (a flagged
257
302
  open risk, lexical-editor-spec.md §12 item 3, needing its own scope
258
303
  decision); TablePlugin is configured with hasCellMerge={false} to keep
@@ -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,kBAmCzB,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,kBAoCzB,CAAC"}
@@ -33,6 +33,7 @@ export const editorTheme = {
33
33
  },
34
34
  hr: 'likhari-hr',
35
35
  image: 'likhari-image-block',
36
+ pageBreak: 'likhari-page-break',
36
37
  table: 'likhari-table',
37
38
  tableRow: 'likhari-table-row',
38
39
  tableCell: 'likhari-table-cell',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inshapardaz/likhari-react",
3
- "version": "0.1.9-dev.94",
3
+ "version": "0.1.9-dev.99",
4
4
  "description": "React implementation of the Likhari editor, built on @lexical/react.",
5
5
  "license": "MIT",
6
6
  "repository": {