@inshapardaz/likhari-react 0.1.8 → 0.1.9-dev.96

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.
Files changed (38) hide show
  1. package/dist/EditorRoot.d.ts +60 -0
  2. package/dist/EditorRoot.d.ts.map +1 -1
  3. package/dist/EditorRoot.js +183 -10
  4. package/dist/components/DraftRestore.d.ts +24 -0
  5. package/dist/components/DraftRestore.d.ts.map +1 -0
  6. package/dist/components/DraftRestore.js +61 -0
  7. package/dist/components/DraftsDialog.d.ts +25 -0
  8. package/dist/components/DraftsDialog.d.ts.map +1 -0
  9. package/dist/components/DraftsDialog.js +66 -0
  10. package/dist/components/LeaveDialog.d.ts +22 -0
  11. package/dist/components/LeaveDialog.d.ts.map +1 -0
  12. package/dist/components/LeaveDialog.js +15 -0
  13. package/dist/components/TableDialog.d.ts +17 -0
  14. package/dist/components/TableDialog.d.ts.map +1 -0
  15. package/dist/components/TableDialog.js +33 -0
  16. package/dist/components/Toolbar.d.ts +4 -1
  17. package/dist/components/Toolbar.d.ts.map +1 -1
  18. package/dist/components/Toolbar.js +110 -6
  19. package/dist/i18n/strings.d.ts +65 -2
  20. package/dist/i18n/strings.d.ts.map +1 -1
  21. package/dist/i18n/strings.js +168 -3
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/nodes.d.ts.map +1 -1
  25. package/dist/nodes.js +4 -0
  26. package/dist/persistence/draftStorage.d.ts +55 -0
  27. package/dist/persistence/draftStorage.d.ts.map +1 -0
  28. package/dist/persistence/draftStorage.js +198 -0
  29. package/dist/persistence/draftUi.d.ts +9 -0
  30. package/dist/persistence/draftUi.d.ts.map +1 -0
  31. package/dist/persistence/draftUi.js +23 -0
  32. package/dist/table/tableActions.d.ts +21 -0
  33. package/dist/table/tableActions.d.ts.map +1 -0
  34. package/dist/table/tableActions.js +71 -0
  35. package/dist/theme/editor.css +111 -0
  36. package/dist/theme/editorTheme.d.ts.map +1 -1
  37. package/dist/theme/editorTheme.js +5 -0
  38. package/package.json +2 -1
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { Button, Checkbox, Group, Modal, NumberInput } from '@mantine/core';
4
+ import { useUiStrings } from '../i18n/useStrings.js';
5
+ import { usePortalTarget } from '../PortalTargetContext.js';
6
+ const MIN_DIMENSION = 1;
7
+ const MAX_DIMENSION = 20;
8
+ const DEFAULT_ROWS = 3;
9
+ const DEFAULT_COLUMNS = 3;
10
+ /**
11
+ * Insert-table dialog: rows x columns and an optional header row. Cell
12
+ * merge/split is intentionally not offered anywhere in this dialog or the
13
+ * table it creates — see the comment on `TablePlugin` in `EditorRoot.tsx`.
14
+ */
15
+ export function TableDialog({ opened, onSubmit, onClose }) {
16
+ const strings = useUiStrings();
17
+ const portalTarget = usePortalTarget();
18
+ const [rows, setRows] = useState(DEFAULT_ROWS);
19
+ const [columns, setColumns] = useState(DEFAULT_COLUMNS);
20
+ const [headerRow, setHeaderRow] = useState(true);
21
+ useEffect(() => {
22
+ if (!opened)
23
+ return;
24
+ setRows(DEFAULT_ROWS);
25
+ setColumns(DEFAULT_COLUMNS);
26
+ setHeaderRow(true);
27
+ }, [opened]);
28
+ const handleSubmit = (e) => {
29
+ e.preventDefault();
30
+ onSubmit({ rows, columns, headerRow });
31
+ };
32
+ return (_jsx(Modal, { opened: opened, onClose: onClose, title: strings.tableDialog.title, centered: true, size: "sm", portalProps: { target: portalTarget }, children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsxs(Group, { grow: true, align: "flex-end", children: [_jsx(NumberInput, { label: strings.tableDialog.rows, min: MIN_DIMENSION, max: MAX_DIMENSION, value: rows, onChange: (v) => setRows(typeof v === 'number' ? v : DEFAULT_ROWS), "data-autofocus": true }), _jsx(NumberInput, { label: strings.tableDialog.columns, min: MIN_DIMENSION, max: MAX_DIMENSION, value: columns, onChange: (v) => setColumns(typeof v === 'number' ? v : DEFAULT_COLUMNS) })] }), _jsx(Checkbox, { mt: "sm", label: strings.tableDialog.headerRow, checked: headerRow, onChange: (e) => setHeaderRow(e.currentTarget.checked) }), _jsxs(Group, { justify: "flex-end", gap: "xs", mt: "md", children: [_jsx(Button, { variant: "default", onClick: onClose, children: strings.common.cancel }), _jsx(Button, { type: "submit", children: strings.common.insert })] })] }) }));
33
+ }
@@ -1,3 +1,4 @@
1
+ import { type DraftsToolbarOptions } from './DraftsDialog.js';
1
2
  import type { ResolvedEditorFeatureConfig } from '@inshapardaz/likhari-core';
2
3
  import { type FontOption } from '../fonts/index.js';
3
4
  import type { Locale } from '../i18n/strings.js';
@@ -12,6 +13,8 @@ export interface ToolbarProps {
12
13
  direction?: 'ltr' | 'rtl';
13
14
  /** UI locale — picks the translated strings for labels, tooltips and menu items. */
14
15
  locale?: Locale;
16
+ /** Autosave drafts: when set, the toolbar offers a Drafts button that lists and restores them. */
17
+ drafts?: DraftsToolbarOptions;
15
18
  }
16
- export declare function Toolbar({ config, onSave, isDirty, showSave, fontOptions, direction, locale }: ToolbarProps): import("react").JSX.Element;
19
+ export declare function Toolbar({ config, onSave, isDirty, showSave, fontOptions, direction, locale, drafts }: ToolbarProps): import("react").JSX.Element;
17
20
  //# sourceMappingURL=Toolbar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AA4CA,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;AAqUvD,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;CACjB;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,EAAE,YAAY,+BA8wBhJ"}
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AAsDA,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;AA8YvD,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,+BAo6BxJ"}
@@ -8,16 +8,21 @@ import { $createParagraphNode } from 'lexical';
8
8
  import { $createHeadingNode, $createQuoteNode, $isHeadingNode, $isQuoteNode } from '@lexical/rich-text';
9
9
  import { $isListNode, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, } from '@lexical/list';
10
10
  import { $findMatchingParent, $insertNodeToNearestRoot } from '@lexical/utils';
11
+ import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode';
11
12
  import { ImageDialog } from '../image/ImageDialog.js';
12
13
  import { $createImageNode } from '../image/ImageNode.js';
14
+ import { TableDialog } from './TableDialog.js';
15
+ import { $getTableCellNodeFromLexicalNode, $isTableSelection, INSERT_TABLE_COMMAND } from '@lexical/table';
16
+ import { $deleteTable, $deleteTableColumns, $deleteTableRows, $getTableSelectionSize, $insertTableColumns, $insertTableRows, } from '../table/tableActions.js';
13
17
  import { $createLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
14
18
  import { LinkDialog } from './LinkDialog.js';
19
+ import { DraftsDialog } from './DraftsDialog.js';
15
20
  import { normalizeLinkUrl } from '../utils/linkUrl.js';
16
21
  import { CANVAS_FONT_DEFAULTS, DEFAULT_FONT_OPTIONS, FONT_SIZES_PX } from '../fonts/index.js';
17
22
  import { setStyleProperty } from '../utils/style.js';
18
23
  import { useStrings } from '../i18n/useStrings.js';
19
24
  import { usePortalTarget } from '../PortalTargetContext.js';
20
- import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconBold, IconClearFormatting, IconDeviceFloppy, IconDots, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
25
+ 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, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconTable, IconTableMinus, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
21
26
  /** Sentinel for "no inline style": Lexical returns the default it is given when
22
27
  * the selection has none, so this tells "unstyled" (show the canvas default)
23
28
  * apart from "styled with a value the dropdown doesn't list" (show nothing). */
@@ -31,6 +36,9 @@ const INITIAL_STATE = {
31
36
  fontSize: UNSET_STYLE,
32
37
  isLink: false,
33
38
  linkUrl: '',
39
+ inTable: false,
40
+ tableRows: 1,
41
+ tableColumns: 1,
34
42
  canUndo: false,
35
43
  canRedo: false,
36
44
  };
@@ -119,11 +127,27 @@ function LinkMenuItems({ url, onEdit, onRemove, strings }) {
119
127
  // Not a URL the editor would accept (e.g. loaded from a document): show it, don't make it clickable.
120
128
  _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 })] }));
121
129
  }
122
- export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en' }) {
130
+ /** The table actions menu's contents — shared by the toolbar button and the
131
+ * right-click menu. Each acts on the selected cell, or on every row/column a
132
+ * multi-cell selection covers. */
133
+ function TableMenuItems({ strings, direction, rows, columns, onAction, }) {
134
+ const t = strings.tableMenu;
135
+ // "Before" is the start side, which is on the right in an RTL table.
136
+ const rtl = direction === 'rtl';
137
+ const manyRows = rows > 1;
138
+ const manyColumns = columns > 1;
139
+ const item = (icon, label, action, color) => {
140
+ const Icon = icon;
141
+ return (_jsx(Menu.Item, { color: color, leftSection: _jsx(Icon, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onAction(action), children: label }));
142
+ };
143
+ 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')] }));
144
+ }
145
+ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
123
146
  const [editor] = useLexicalComposerContext();
124
147
  const [state, setState] = useState(INITIAL_STATE);
125
148
  const strings = useStrings(locale);
126
149
  const portalTarget = usePortalTarget();
150
+ const [draftsOpen, setDraftsOpen] = useState(false);
127
151
  // Responsive "priority+" overflow: the toolbar's outer container and a
128
152
  // hidden nowrap clone (rendered with every movable group forced inline)
129
153
  // are both measured; whenever the clone's natural width exceeds the
@@ -136,9 +160,17 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
136
160
  const updateToolbar = useCallback(() => {
137
161
  editor.getEditorState().read(() => {
138
162
  const selection = $getSelection();
163
+ // A selection of several table cells isn't a range selection.
164
+ if ($isTableSelection(selection)) {
165
+ const { rows, columns } = $getTableSelectionSize();
166
+ setState((s) => ({ ...s, inTable: true, tableRows: rows, tableColumns: columns }));
167
+ return;
168
+ }
139
169
  if (!$isRangeSelection(selection))
140
170
  return;
141
171
  const anchorNode = selection.anchor.getNode();
172
+ const inTable = $getTableCellNodeFromLexicalNode(anchorNode) !== null;
173
+ const tableSize = inTable ? $getTableSelectionSize() : { rows: 1, columns: 1 };
142
174
  const element = anchorNode.getKey() === 'root' ? anchorNode : (anchorNode.getTopLevelElement() ?? anchorNode);
143
175
  const listParent = $findMatchingParent(anchorNode, $isListNode);
144
176
  const listType = listParent && $isListNode(listParent) ? listParent.getListType() : null;
@@ -174,6 +206,9 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
174
206
  fontSize,
175
207
  isLink,
176
208
  linkUrl,
209
+ inTable,
210
+ tableRows: tableSize.rows,
211
+ tableColumns: tableSize.columns,
177
212
  }));
178
213
  });
179
214
  }, [editor]);
@@ -273,6 +308,26 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
273
308
  });
274
309
  closeImageDialog();
275
310
  };
311
+ const [tableDialogOpen, setTableDialogOpen] = useState(false);
312
+ const openTableDialog = () => {
313
+ snapshotSelection();
314
+ setTableDialogOpen(true);
315
+ };
316
+ const closeTableDialog = () => {
317
+ setTableDialogOpen(false);
318
+ editor.focus();
319
+ };
320
+ const insertTable = ({ rows, columns, headerRow }) => {
321
+ const saved = menuSelectionRef.current;
322
+ if (saved)
323
+ editor.update(() => $setSelection(saved.clone()), { discrete: true });
324
+ editor.dispatchCommand(INSERT_TABLE_COMMAND, {
325
+ rows: String(rows),
326
+ columns: String(columns),
327
+ includeHeaders: { rows: headerRow, columns: false },
328
+ });
329
+ closeTableDialog();
330
+ };
276
331
  /** Applies a font property per `config.font.scope`: to the selection, to
277
332
  * every text node in the document, or (for 'both') to the selection when
278
333
  * there is a range and to the whole document when there isn't. */
@@ -366,6 +421,50 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
366
421
  root?.addEventListener('contextmenu', onContextMenu);
367
422
  });
368
423
  }, [editor, config.links]);
424
+ // Table actions. The menu takes focus, so the selection is snapshotted when it
425
+ // opens and restored before an action runs.
426
+ const runTableAction = (action) => () => {
427
+ restoreSelection();
428
+ editor.update(action);
429
+ editor.focus();
430
+ };
431
+ // Right-clicking a table cell opens the same actions at the pointer.
432
+ const [tableContext, setTableContext] = useState(null);
433
+ useEffect(() => {
434
+ if (!config.tables)
435
+ return;
436
+ const onContextMenu = (event) => {
437
+ if (event.defaultPrevented)
438
+ return; // a link inside the cell already took it
439
+ const cellElement = event.target?.closest?.('td, th');
440
+ if (!cellElement)
441
+ return;
442
+ let handled = false;
443
+ editor.update(() => {
444
+ const node = $getNearestNodeFromDOMNode(cellElement);
445
+ const cell = node ? $getTableCellNodeFromLexicalNode(node) : null;
446
+ if (!cell)
447
+ return;
448
+ handled = true;
449
+ const selection = $getSelection();
450
+ // Keep a multi-cell selection that includes this cell, so "insert
451
+ // rows" / "delete columns" act on everything selected.
452
+ const insideSelection = $isTableSelection(selection) && selection.getNodes().some((n) => n.getKey() === cell.getKey());
453
+ if (!insideSelection)
454
+ cell.selectEnd();
455
+ }, { discrete: true });
456
+ if (!handled)
457
+ return;
458
+ event.preventDefault();
459
+ snapshotSelectionRef.current();
460
+ const size = editor.getEditorState().read($getTableSelectionSize);
461
+ setTableContext({ x: event.clientX, y: event.clientY, rows: size.rows, columns: size.columns });
462
+ };
463
+ return editor.registerRootListener((root, previous) => {
464
+ previous?.removeEventListener('contextmenu', onContextMenu);
465
+ root?.addEventListener('contextmenu', onContextMenu);
466
+ });
467
+ }, [editor, config.tables]);
369
468
  // Ctrl/Cmd+K opens the link dialog.
370
469
  useEffect(() => {
371
470
  if (!config.links)
@@ -426,7 +525,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
426
525
  const showFormattingGroup = headingLevels.length > 0 || config.lists.bullet || config.lists.numbered || config.lists.check || config.blocks.quote;
427
526
  const showInlineGroup = fmt.bold || fmt.italic || fmt.underline;
428
527
  const showAlignGroup = config.alignment.start || config.alignment.center || config.alignment.justify || config.alignment.left || config.alignment.right;
429
- const showStubInsertGroup = config.images.linked || config.images.embedded || config.poetry.enabled;
528
+ const showStubInsertGroup = config.images.linked || config.images.embedded || config.tables || config.blocks.horizontalRule || config.poetry.enabled;
430
529
  const showLanguageGroup = config.language.autocorrect || config.language.textCleanup || config.language.spellCheck;
431
530
  // The "script & cleanup" and "indent/outdent" groups (UI spec §3.3) render
432
531
  // as normal inline toolbar groups whenever there's room, and only move
@@ -584,6 +683,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
584
683
  // the toolbar's own layout width.
585
684
  const fixedGroups = [
586
685
  showSave && (_jsx("div", { className: "likhari-toolbar-group", children: _jsx(ToolbarButton, { icon: IconDeviceFloppy, title: strings.toolbar.save, dirty: Boolean(isDirty), onClick: onSave }) }, "save")),
686
+ drafts && (_jsx("div", { className: "likhari-toolbar-group", children: _jsx(ToolbarButton, { icon: IconHistory, title: strings.toolbar.drafts, onClick: () => setDraftsOpen(true) }) }, "drafts")),
587
687
  config.history && (_jsxs("div", { className: "likhari-toolbar-group", children: [_jsx(ToolbarButton, { icon: IconArrowBackUp, title: strings.toolbar.undo, disabled: !state.canUndo, onClick: () => editor.dispatchCommand(UNDO_COMMAND, undefined) }), _jsx(ToolbarButton, { icon: IconArrowForwardUp, title: strings.toolbar.redo, disabled: !state.canRedo, onClick: () => editor.dispatchCommand(REDO_COMMAND, undefined) })] }, "history")),
588
688
  showFormattingGroup && (_jsx("div", { className: "likhari-toolbar-group", children: _jsx(ToolbarSelect, { icon: IconPilcrow, label: strings.toolbar.formattingLabel, width: 148, value: formattingValue, data: formattingOptions, comingSoon: strings.toolbar.comingSoon, renderOption: iconOptionRenderer(FORMATTING_ICONS, IconPilcrow), onChange: withRefocus((v) => applyFormatting(v)) }) }, "formatting")),
589
689
  showInlineGroup && (_jsxs("div", { className: "likhari-toolbar-group", children: [fmt.bold && (_jsx(ToolbarButton, { icon: IconBold, title: strings.toolbar.bold, active: state.activeFormats.has('bold'), onClick: () => formatText('bold') })), fmt.italic && (_jsx(ToolbarButton, { icon: IconItalic, title: strings.toolbar.italic, active: state.activeFormats.has('italic'), onClick: () => formatText('italic') })), fmt.underline && (_jsx(ToolbarButton, { icon: IconUnderline, title: strings.toolbar.underline, active: state.activeFormats.has('underline'), onClick: () => formatText('underline') }))] }, "inline")),
@@ -595,7 +695,8 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
595
695
  restoreSelection();
596
696
  openLinkDialog();
597
697
  }, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog })) }, "link")),
598
- 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.poetry.enabled && _jsx(StubButton, { icon: IconFeather, title: strings.toolbar.poetryBlocks, comingSoon: strings.toolbar.comingSoon })] }, "stubInsert")),
698
+ 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")),
699
+ 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")),
599
700
  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")),
600
701
  ];
601
702
  return (_jsxs("div", { className: "likhari-toolbar", role: "toolbar", "aria-label": strings.toolbar.ariaLabel, ref: toolbarContainerRef, children: [fixedGroups, movableGroups
@@ -608,7 +709,10 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
608
709
  }, 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: () => {
609
710
  restoreSelection();
610
711
  openLinkDialog();
611
- }, onRemove: removeLink, strings: strings }) })] })), _jsxs("div", { "aria-hidden": "true", ref: toolbarMeasureRef, style: {
712
+ }, onRemove: removeLink, strings: strings }) })] })), config.tables && (_jsxs(Menu, { opened: tableContext !== null, onChange: (opened) => {
713
+ if (!opened)
714
+ setTableContext(null);
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: 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: {
612
716
  position: 'absolute',
613
717
  visibility: 'hidden',
614
718
  pointerEvents: 'none',
@@ -617,5 +721,5 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
617
721
  display: 'flex',
618
722
  flexWrap: 'nowrap',
619
723
  gap: 8,
620
- }, children: [fixedGroups, movableGroups.map((group) => (_jsx(MovableGroupButtons, { group: group }, group.key)))] }), (config.images.linked || config.images.embedded) && (_jsx(ImageDialog, { mode: "insert", opened: imageDialogOpen, onSubmit: insertImage, onClose: closeImageDialog })), config.links && (_jsx(LinkDialog, { opened: linkDialogOpen, initialUrl: state.linkUrl, showTextField: linkNeedsText, onSubmit: applyLink, onRemove: state.isLink ? removeLink : undefined, onClose: closeLinkDialog }))] }));
724
+ }, children: [fixedGroups, movableGroups.map((group) => (_jsx(MovableGroupButtons, { group: group }, group.key)))] }), (config.images.linked || config.images.embedded) && (_jsx(ImageDialog, { mode: "insert", opened: imageDialogOpen, onSubmit: insertImage, onClose: closeImageDialog })), config.tables && _jsx(TableDialog, { opened: tableDialogOpen, onSubmit: insertTable, onClose: closeTableDialog }), config.links && (_jsx(LinkDialog, { opened: linkDialogOpen, initialUrl: state.linkUrl, showTextField: linkNeedsText, onSubmit: applyLink, onRemove: state.isLink ? removeLink : undefined, onClose: closeLinkDialog })), drafts && _jsx(DraftsDialog, { opened: draftsOpen, locale: locale, onClose: () => setDraftsOpen(false), ...drafts })] }));
621
725
  }
@@ -13,8 +13,6 @@ export interface Strings {
13
13
  placeholder: string;
14
14
  /** aria-label on the contenteditable itself. */
15
15
  contentLabel: string;
16
- /** window.confirm() prompt shown by EditorRef.confirmDiscard() when there are unsaved changes. */
17
- confirmDiscard: string;
18
16
  };
19
17
  common: {
20
18
  cancel: string;
@@ -25,6 +23,8 @@ export interface Strings {
25
23
  /** aria-label on the toolbar's own role="toolbar" container. */
26
24
  ariaLabel: string;
27
25
  save: string;
26
+ /** Opens the list of autosaved drafts. */
27
+ drafts: string;
28
28
  undo: string;
29
29
  redo: string;
30
30
  formattingLabel: string;
@@ -38,8 +38,12 @@ export interface Strings {
38
38
  noMatch: string;
39
39
  alignment: string;
40
40
  linkOptions: string;
41
+ /** Toolbar button (shown while the caret is in a table) that opens the table actions menu. */
42
+ tableOptions: string;
41
43
  insertLink: string;
42
44
  insertImage: string;
45
+ insertTable: string;
46
+ insertHorizontalRule: string;
43
47
  poetryBlocks: string;
44
48
  comingSoon: (label: string) => string;
45
49
  autocorrect: string;
@@ -72,6 +76,59 @@ export interface Strings {
72
76
  right: string;
73
77
  };
74
78
  };
79
+ /** The popup `EditorRef.confirmDiscard()` shows when the user is about to leave with unsaved changes (lexical-editor-spec.md §6.4). */
80
+ leaveDialog: {
81
+ title: string;
82
+ message: string;
83
+ save: string;
84
+ saveDraft: string;
85
+ discard: string;
86
+ /** Shown when a draft could not be stored (document too large, or storage unavailable). */
87
+ saveDraftFailed: string;
88
+ };
89
+ /** Autosave drafts (lexical-editor-spec.md §6.2): the restore banner and the drafts list dialog. */
90
+ drafts: {
91
+ /** Banner shown when a newer unsaved draft of this document is found; `when` is a formatted date/time. */
92
+ bannerMessage: (when: string) => string;
93
+ restore: string;
94
+ ignore: string;
95
+ remove: string;
96
+ dialogTitle: string;
97
+ intro: string;
98
+ empty: string;
99
+ /** Shown for a draft with no text (e.g. only an image). */
100
+ noText: string;
101
+ thisDocument: string;
102
+ untitled: string;
103
+ documentLabel: (id: string) => string;
104
+ earlierUntitled: string;
105
+ earlierVersionOf: (id: string) => string;
106
+ savedAt: (when: string) => string;
107
+ size: (kb: number) => string;
108
+ replacePrompt: string;
109
+ replace: string;
110
+ deletePrompt: string;
111
+ delete: string;
112
+ close: string;
113
+ };
114
+ /** The table actions menu (toolbar button and right-click on a cell). */
115
+ tableMenu: {
116
+ menuLabel: string;
117
+ insertRowBefore: string;
118
+ insertRowAfter: string;
119
+ insertColumnBefore: string;
120
+ insertColumnAfter: string;
121
+ deleteRow: string;
122
+ deleteColumn: string;
123
+ deleteTable: string;
124
+ /** Plural forms, used when the selection spans several rows or columns. */
125
+ insertRowsBefore: string;
126
+ insertRowsAfter: string;
127
+ insertColumnsBefore: string;
128
+ insertColumnsAfter: string;
129
+ deleteRows: string;
130
+ deleteColumns: string;
131
+ };
75
132
  link: {
76
133
  menuLabel: string;
77
134
  noUrl: string;
@@ -88,6 +145,12 @@ export interface Strings {
88
145
  invalidUrl: string;
89
146
  apply: string;
90
147
  };
148
+ tableDialog: {
149
+ title: string;
150
+ rows: string;
151
+ columns: string;
152
+ headerRow: string;
153
+ };
91
154
  imageDialog: {
92
155
  titleInsert: string;
93
156
  titleEdit: 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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"}