@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.
- package/dist/EditorRoot.d.ts +60 -0
- package/dist/EditorRoot.d.ts.map +1 -1
- package/dist/EditorRoot.js +183 -10
- package/dist/components/DraftRestore.d.ts +24 -0
- package/dist/components/DraftRestore.d.ts.map +1 -0
- package/dist/components/DraftRestore.js +61 -0
- package/dist/components/DraftsDialog.d.ts +25 -0
- package/dist/components/DraftsDialog.d.ts.map +1 -0
- package/dist/components/DraftsDialog.js +66 -0
- package/dist/components/LeaveDialog.d.ts +22 -0
- package/dist/components/LeaveDialog.d.ts.map +1 -0
- package/dist/components/LeaveDialog.js +15 -0
- package/dist/components/TableDialog.d.ts +17 -0
- package/dist/components/TableDialog.d.ts.map +1 -0
- package/dist/components/TableDialog.js +33 -0
- package/dist/components/Toolbar.d.ts +4 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +110 -6
- package/dist/i18n/strings.d.ts +65 -2
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +168 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +4 -0
- package/dist/persistence/draftStorage.d.ts +55 -0
- package/dist/persistence/draftStorage.d.ts.map +1 -0
- package/dist/persistence/draftStorage.js +198 -0
- package/dist/persistence/draftUi.d.ts +9 -0
- package/dist/persistence/draftUi.d.ts.map +1 -0
- package/dist/persistence/draftUi.js +23 -0
- package/dist/table/tableActions.d.ts +21 -0
- package/dist/table/tableActions.d.ts.map +1 -0
- package/dist/table/tableActions.js +71 -0
- package/dist/theme/editor.css +111 -0
- package/dist/theme/editorTheme.d.ts.map +1 -1
- package/dist/theme/editorTheme.js +5 -0
- 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":"
|
|
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
|
-
|
|
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(
|
|
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
|
}
|
package/dist/i18n/strings.d.ts
CHANGED
|
@@ -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":"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;
|
|
1
|
+
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
|