@inshapardaz/likhari-react 0.1.31 → 0.1.32-dev.273
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.
|
@@ -11,6 +11,12 @@ export interface ToolbarStyle {
|
|
|
11
11
|
bordered?: boolean;
|
|
12
12
|
/** `light` tints the active button, `filled` fills it with the accent. Default `light`. */
|
|
13
13
|
variant?: 'light' | 'filled';
|
|
14
|
+
/**
|
|
15
|
+
* Move the lowest-priority groups into a "..." menu once the toolbar no
|
|
16
|
+
* longer fits its width (UI spec §3.3). `false` keeps every group inline
|
|
17
|
+
* and lets the toolbar wrap onto as many rows as it needs. Default `true`.
|
|
18
|
+
*/
|
|
19
|
+
overflow?: boolean;
|
|
14
20
|
}
|
|
15
21
|
export interface ToolbarProps {
|
|
16
22
|
config: ResolvedEditorFeatureConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AA2CA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAgDtF,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;
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AA2CA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAgDtF,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAA6D,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAItG,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,iBAAiB,CAAC;AA8gBvD,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gCAAgC;IAChC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,aAAa,EAAE,CAAC;IACnC,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;IACnE,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,iGAAiG;IACjG,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,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,YAAY,EAAE,gBAAqB,EAAE,eAAoB,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAgB,EAAE,YAAY,EAAE,SAAiB,EAAE,aAAa,EAAE,eAAuB,EAAE,mBAAmB,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,MAAM,EAAE,EAAE,YAAY,+BAuqCrV"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Fragment, forwardRef, useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Fragment, forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Menu, Select, Toolbar as MantineToolbar } from '@mantine/core';
|
|
4
4
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
5
5
|
import { $getSelection, $isRangeSelection, $isElementNode, $setSelection, $getRoot, $selectAll, $getNearestNodeFromDOMNode, $createTextNode, KEY_MODIFIER_COMMAND, COMMAND_PRIORITY_NORMAL, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, INDENT_CONTENT_COMMAND, OUTDENT_CONTENT_COMMAND, UNDO_COMMAND, REDO_COMMAND, SELECTION_CHANGE_COMMAND, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, COMMAND_PRIORITY_LOW, } from 'lexical';
|
|
@@ -123,6 +123,15 @@ function withDividers(sections) {
|
|
|
123
123
|
.filter((section) => Boolean(section))
|
|
124
124
|
.flatMap((section, index) => (index === 0 ? [section] : [_jsx(MantineToolbar.Divider, {}, `divider-${index}`), section]));
|
|
125
125
|
}
|
|
126
|
+
const EMPTY_OVERFLOW = new Set();
|
|
127
|
+
function setsEqual(a, b) {
|
|
128
|
+
if (a.size !== b.size)
|
|
129
|
+
return false;
|
|
130
|
+
for (const v of a)
|
|
131
|
+
if (!b.has(v))
|
|
132
|
+
return false;
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
126
135
|
/** Mantine Select (combobox) for the toolbar's dropdown controls. The icon
|
|
127
136
|
* labels the control itself, since a dropdown can't show one per option in
|
|
128
137
|
* its closed state. The dropdown portals to <body>, so it is not clipped by
|
|
@@ -179,6 +188,7 @@ function PoetryMenuItems({ strings, layout, scale, centered, onAction, }) {
|
|
|
179
188
|
export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurusStores = [], onAddAutoCorrect, onSave, isDirty, showSave, findOpen = false, onToggleFind, spellOpen = false, onToggleSpell, autoCorrectOpen = false, onToggleAutoCorrect, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
180
189
|
const bordered = toolbarStyle?.bordered ?? true;
|
|
181
190
|
const variant = toolbarStyle?.variant ?? 'light';
|
|
191
|
+
const overflowEnabled = toolbarStyle?.overflow ?? true;
|
|
182
192
|
const [editor] = useLexicalComposerContext();
|
|
183
193
|
const [state, setState] = useState(INITIAL_STATE);
|
|
184
194
|
const strings = useStrings(locale);
|
|
@@ -186,6 +196,17 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
186
196
|
const [draftsOpen, setDraftsOpen] = useState(false);
|
|
187
197
|
const rtl = direction === 'rtl';
|
|
188
198
|
const ALIGN_ICONS = rtl ? ALIGN_ICONS_RTL : ALIGN_ICONS_LTR;
|
|
199
|
+
// Responsive "priority+" overflow (UI spec §3.3): the toolbar's outer
|
|
200
|
+
// container and a hidden nowrap clone (every movable group forced inline)
|
|
201
|
+
// are both measured; whenever the clone's natural width exceeds the
|
|
202
|
+
// container's available width, the lowest-priority movable groups move
|
|
203
|
+
// into the "..." menu, lowest-priority first, until what remains inline
|
|
204
|
+
// fits (or nothing is left to move). Font and insert are overflow-menu
|
|
205
|
+
// items per spec §3.1's closing note, and tools (autocorrect, spellcheck,
|
|
206
|
+
// join lines) is lower priority still, so it is first to move.
|
|
207
|
+
const toolbarContainerRef = useRef(null);
|
|
208
|
+
const toolbarMeasureRef = useRef(null);
|
|
209
|
+
const [overflowGroupKeys, setOverflowGroupKeys] = useState(EMPTY_OVERFLOW);
|
|
189
210
|
const updateToolbar = useCallback(() => {
|
|
190
211
|
editor.getEditorState().read(() => {
|
|
191
212
|
const selection = $getSelection();
|
|
@@ -506,7 +527,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
506
527
|
}
|
|
507
528
|
if (point)
|
|
508
529
|
word = $wordAtDomPoint(point.node, point.offset);
|
|
509
|
-
if (!cell && !couplet) {
|
|
530
|
+
if (!cell && !couplet && config.joinLines) {
|
|
510
531
|
menu.text = true;
|
|
511
532
|
menu.canJoin = $canJoinLines();
|
|
512
533
|
}
|
|
@@ -538,7 +559,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
538
559
|
previous?.removeEventListener('contextmenu', onContextMenu);
|
|
539
560
|
root?.addEventListener('contextmenu', onContextMenu);
|
|
540
561
|
});
|
|
541
|
-
}, [editor, config.links, config.tables, config.poetry.enabled, config.language.spellCheck, config.language.thesaurus, thesaurusStores]);
|
|
562
|
+
}, [editor, config.links, config.tables, config.poetry.enabled, config.language.spellCheck, config.language.thesaurus, config.joinLines, thesaurusStores]);
|
|
542
563
|
// Cut and copy put the selected text on the clipboard as plain text.
|
|
543
564
|
const copyOrCut = (cut) => async () => {
|
|
544
565
|
restoreSelection();
|
|
@@ -746,18 +767,72 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
746
767
|
}, { discrete: true });
|
|
747
768
|
editor.focus();
|
|
748
769
|
};
|
|
749
|
-
const toolsSection = (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [config.language.autocorrect && (_jsx(ToolbarButton, { icon: IconWand, title: strings.toolbar.autocorrect, active: autoCorrectOpen, onClick: onToggleAutoCorrect })), config.language.textCleanup && (_jsx(ToolbarButton, { icon: IconSparkles, title: strings.autoCorrect.correctDocument, onClick: () => editor.dispatchCommand(CORRECT_DOCUMENT_COMMAND, undefined) })), config.language.spellCheck && (_jsx(ToolbarButton, { icon: IconAbc, title: strings.toolbar.spellChecker, active: spellOpen, onClick: onToggleSpell })), _jsx(ToolbarButton, { icon: IconArrowsJoin, title: strings.toolbar.joinLines, disabled: !state.canJoinLines, onClick: joinLines })] }, "tools"));
|
|
770
|
+
const toolsSection = (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [config.language.autocorrect && (_jsx(ToolbarButton, { icon: IconWand, title: strings.toolbar.autocorrect, active: autoCorrectOpen, onClick: onToggleAutoCorrect })), config.language.textCleanup && (_jsx(ToolbarButton, { icon: IconSparkles, title: strings.autoCorrect.correctDocument, onClick: () => editor.dispatchCommand(CORRECT_DOCUMENT_COMMAND, undefined) })), config.language.spellCheck && (_jsx(ToolbarButton, { icon: IconAbc, title: strings.toolbar.spellChecker, active: spellOpen, onClick: onToggleSpell })), config.joinLines && (_jsx(ToolbarButton, { icon: IconArrowsJoin, title: strings.toolbar.joinLines, disabled: !state.canJoinLines, onClick: joinLines }))] }, "tools"));
|
|
750
771
|
const endSection = (drafts || config.findReplace) && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", style: { marginInlineStart: 'auto' }, children: [drafts && _jsx(ToolbarButton, { icon: IconHistory, title: strings.toolbar.drafts, onClick: () => setDraftsOpen(true) }), config.findReplace && (_jsx(ToolbarButton, { icon: IconSearch, title: strings.findReplace.toggle, active: findOpen, onClick: onToggleFind }))] }, "end"));
|
|
751
772
|
const startSections = [
|
|
752
773
|
showSave && (_jsx(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: _jsx(ToolbarButton, { icon: IconDeviceFloppy, title: strings.toolbar.save, dirty: Boolean(isDirty), onClick: onSave }) }, "save")),
|
|
753
774
|
config.history && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", 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")),
|
|
754
775
|
formatSection,
|
|
755
776
|
alignSection,
|
|
756
|
-
fontSection,
|
|
757
|
-
insertSection,
|
|
758
|
-
toolsSection,
|
|
759
777
|
];
|
|
760
|
-
|
|
778
|
+
// Lowest priority first: the first to move into the "..." menu once the
|
|
779
|
+
// toolbar stops fitting its available width.
|
|
780
|
+
const movableSections = [
|
|
781
|
+
{ key: 'tools', node: toolsSection },
|
|
782
|
+
{ key: 'font', node: fontSection },
|
|
783
|
+
{ key: 'insert', node: insertSection },
|
|
784
|
+
].filter((section) => Boolean(section.node));
|
|
785
|
+
const movableGroupKeys = useMemo(() => movableSections.map((section) => section.key).join(','), [movableSections]);
|
|
786
|
+
// Re-measure whenever the container is resized, or whenever the set of
|
|
787
|
+
// movable sections (and so the hidden clone's content) changes.
|
|
788
|
+
useLayoutEffect(() => {
|
|
789
|
+
if (!overflowEnabled) {
|
|
790
|
+
setOverflowGroupKeys((prev) => (prev.size === 0 ? prev : EMPTY_OVERFLOW));
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const container = toolbarContainerRef.current;
|
|
794
|
+
const measure = toolbarMeasureRef.current;
|
|
795
|
+
if (!container || !measure)
|
|
796
|
+
return;
|
|
797
|
+
// Rough width of the "..." button itself (icon button + its gap) —
|
|
798
|
+
// only charged against the budget once something has actually moved
|
|
799
|
+
// into it, since it isn't rendered at all otherwise.
|
|
800
|
+
const OVERFLOW_BUTTON_WIDTH = 38;
|
|
801
|
+
const recompute = () => {
|
|
802
|
+
const available = container.clientWidth;
|
|
803
|
+
const total = measure.scrollWidth;
|
|
804
|
+
if (total <= available) {
|
|
805
|
+
setOverflowGroupKeys((prev) => (prev.size === 0 ? prev : EMPTY_OVERFLOW));
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
const widths = new Map();
|
|
809
|
+
measure.querySelectorAll('[data-group-key]').forEach((el) => {
|
|
810
|
+
widths.set(el.dataset.groupKey, el.getBoundingClientRect().width);
|
|
811
|
+
});
|
|
812
|
+
let remaining = total;
|
|
813
|
+
const next = new Set();
|
|
814
|
+
for (const key of movableGroupKeys.split(',').filter(Boolean)) {
|
|
815
|
+
if (remaining <= available)
|
|
816
|
+
break;
|
|
817
|
+
const w = widths.get(key);
|
|
818
|
+
if (w === undefined)
|
|
819
|
+
continue;
|
|
820
|
+
remaining -= w;
|
|
821
|
+
next.add(key);
|
|
822
|
+
}
|
|
823
|
+
if (next.size > 0)
|
|
824
|
+
remaining += OVERFLOW_BUTTON_WIDTH;
|
|
825
|
+
setOverflowGroupKeys((prev) => (setsEqual(prev, next) ? prev : next));
|
|
826
|
+
};
|
|
827
|
+
recompute();
|
|
828
|
+
const ro = new ResizeObserver(recompute);
|
|
829
|
+
ro.observe(container);
|
|
830
|
+
ro.observe(measure);
|
|
831
|
+
return () => ro.disconnect();
|
|
832
|
+
});
|
|
833
|
+
const visibleMovable = movableSections.filter((section) => !overflowGroupKeys.has(section.key));
|
|
834
|
+
const hiddenMovable = movableSections.filter((section) => overflowGroupKeys.has(section.key));
|
|
835
|
+
return (_jsxs(MantineToolbar, { ref: toolbarContainerRef, "aria-label": strings.toolbar.ariaLabel, className: bordered ? 'likhari-toolbar' : 'likhari-toolbar likhari-toolbar--plain', withBorder: bordered, variant: variant, color: "var(--editor-accent)", children: [withDividers(startSections), visibleMovable.map((section) => (_jsxs(Fragment, { children: [_jsx(MantineToolbar.Divider, {}), section.node] }, section.key))), hiddenMovable.length > 0 && (_jsxs(_Fragment, { children: [_jsx(MantineToolbar.Divider, {}), _jsxs(Menu, { position: "bottom-end", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: "max-content", closeOnItemClick: false, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconDots, title: strings.toolbar.moreFormatting }) }), _jsx(Menu.Dropdown, { p: 6, children: _jsx(MantineToolbar, { withBorder: false, variant: variant, color: "var(--editor-accent)", style: { maxWidth: 320 }, children: withDividers(hiddenMovable.map((section) => section.node)) }) })] })] })), endSection, _jsxs(Menu, { opened: contextMenu !== null, onChange: (opened) => {
|
|
761
836
|
if (!opened)
|
|
762
837
|
setContextMenu(null);
|
|
763
838
|
}, position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 260, children: [_jsx(Menu.Target, { children: _jsx("span", { "aria-hidden": "true", style: { position: 'fixed', left: contextMenu?.x ?? -9999, top: contextMenu?.y ?? -9999, width: 1, height: 1, pointerEvents: 'none' } }) }), _jsxs(Menu.Dropdown, { children: [contextMenu?.spelling && (_jsxs(_Fragment, { children: [_jsx(Menu.Label, { children: strings.contextMenu.spelling }), contextMenu.spelling.suggestions.length === 0 && _jsx(Menu.Item, { disabled: true, children: strings.contextMenu.noSuggestions }), contextMenu.spelling.suggestions.map((suggestion) => (_jsx(Menu.Item, { onClick: () => {
|
|
@@ -787,5 +862,5 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
787
862
|
openLinkDialog();
|
|
788
863
|
}, onRemove: removeLink, strings: strings }), _jsx(Menu.Divider, {})] })), contextMenu?.table && (_jsxs(_Fragment, { children: [_jsx(TableMenuItems, { strings: strings, direction: direction, rows: contextMenu.table.rows, columns: contextMenu.table.columns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }), _jsx(Menu.Divider, {})] })), contextMenu?.poetry && (_jsxs(_Fragment, { children: [_jsx(PoetryMenuItems, { strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }), _jsx(Menu.Divider, {})] })), contextMenu?.text && (_jsxs(_Fragment, { children: [_jsx(Menu.Item, { leftSection: _jsx(IconArrowsJoin, { size: ICON_SIZE, stroke: ICON_STROKE }), disabled: !contextMenu.canJoin, onClick: runMenuAction(() => {
|
|
789
864
|
$joinSelectedLines();
|
|
790
|
-
}), children: strings.contextMenu.joinLines }), _jsx(Menu.Divider, {})] })), _jsx(Menu.Item, { leftSection: _jsx(IconCut, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void copyOrCut(true)(), children: strings.contextMenu.cut }), _jsx(Menu.Item, { leftSection: _jsx(IconCopy, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void copyOrCut(false)(), children: strings.contextMenu.copy }), _jsx(Menu.Item, { leftSection: _jsx(IconClipboard, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void paste(), children: strings.contextMenu.paste }), _jsx(Menu.Item, { leftSection: _jsx(IconSelectAll, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: runMenuAction(() => $selectAll()), children: strings.contextMenu.selectAll })] })] }), (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.columns && _jsx(LayoutDialog, { opened: layoutDialogOpen, onSubmit: insertLayout, onClose: closeLayoutDialog }), 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 })] }));
|
|
865
|
+
}), children: strings.contextMenu.joinLines }), _jsx(Menu.Divider, {})] })), _jsx(Menu.Item, { leftSection: _jsx(IconCut, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void copyOrCut(true)(), children: strings.contextMenu.cut }), _jsx(Menu.Item, { leftSection: _jsx(IconCopy, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void copyOrCut(false)(), children: strings.contextMenu.copy }), _jsx(Menu.Item, { leftSection: _jsx(IconClipboard, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void paste(), children: strings.contextMenu.paste }), _jsx(Menu.Item, { leftSection: _jsx(IconSelectAll, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: runMenuAction(() => $selectAll()), children: strings.contextMenu.selectAll })] })] }), overflowEnabled && (_jsxs(MantineToolbar, { "aria-hidden": "true", ref: toolbarMeasureRef, withBorder: bordered, variant: variant, color: "var(--editor-accent)", style: { position: 'absolute', visibility: 'hidden', pointerEvents: 'none', top: 0, left: 0, flexWrap: 'nowrap', width: 'max-content' }, children: [withDividers(startSections), movableSections.map((section) => (_jsxs(Fragment, { children: [_jsx(MantineToolbar.Divider, {}), _jsx("span", { "data-group-key": section.key, style: { display: 'inline-flex' }, children: section.node })] }, section.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.columns && _jsx(LayoutDialog, { opened: layoutDialogOpen, onSubmit: insertLayout, onClose: closeLayoutDialog }), 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 })] }));
|
|
791
866
|
}
|
package/dist/theme/editor.css
CHANGED
|
@@ -19,15 +19,25 @@
|
|
|
19
19
|
its own height so only the canvas below scrolls. */
|
|
20
20
|
.likhari-toolbar {
|
|
21
21
|
display: flex;
|
|
22
|
+
/* Containing block for the hidden width-measuring clone (Toolbar.tsx):
|
|
23
|
+
without this, its position: absolute would resolve against the
|
|
24
|
+
viewport instead, and its intentionally-unwrapped (possibly very wide)
|
|
25
|
+
content could inflate the host page's scroll area instead of being
|
|
26
|
+
clipped by .likhari-root's overflow: hidden. */
|
|
27
|
+
position: relative;
|
|
22
28
|
flex-shrink: 0;
|
|
23
29
|
align-items: center;
|
|
24
30
|
gap: 8px;
|
|
25
31
|
min-height: 46px;
|
|
26
32
|
padding: 4px 8px;
|
|
27
33
|
background: var(--editor-paper-dim);
|
|
28
|
-
/* Wrap instead of scroll
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
/* Wrap instead of scroll, once the responsive overflow (UI spec §3.3) has
|
|
35
|
+
already moved the lowest-priority groups into the "..." menu: an
|
|
36
|
+
overflow container would clip menus and grow a scrollbar, where wrapping
|
|
37
|
+
to a second row keeps every control reachable without one. This is a
|
|
38
|
+
deliberate departure from the spec's literal "horizontal scroll"
|
|
39
|
+
fallback — it only applies in the edge case where even the essential
|
|
40
|
+
groups (§3.3's mobile tier) don't fit a very narrow viewport. */
|
|
31
41
|
flex-wrap: wrap;
|
|
32
42
|
row-gap: 4px;
|
|
33
43
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inshapardaz/likhari-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.32-dev.273",
|
|
4
4
|
"description": "React implementation of the Likhari editor, built on @lexical/react.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"prepublishOnly": "npm run build"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@inshapardaz/likhari-converters": "
|
|
37
|
-
"@inshapardaz/likhari-core": "
|
|
36
|
+
"@inshapardaz/likhari-converters": "*",
|
|
37
|
+
"@inshapardaz/likhari-core": "*",
|
|
38
38
|
"@lexical/link": "^0.20.0",
|
|
39
39
|
"@lexical/list": "^0.20.0",
|
|
40
40
|
"@lexical/react": "^0.20.0",
|