@inshapardaz/likhari-react 0.1.49 → 0.1.51
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":"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;AAmDtF,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAkF,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAI1I,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -289,6 +289,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
289
289
|
// join lines) is lower priority still, so it is first to move.
|
|
290
290
|
const toolbarContainerRef = useRef(null);
|
|
291
291
|
const toolbarMeasureRef = useRef(null);
|
|
292
|
+
const toolbarOverflowMeasureRef = useRef(null);
|
|
292
293
|
const [overflowGroupKeys, setOverflowGroupKeys] = useState(EMPTY_OVERFLOW);
|
|
293
294
|
const updateToolbar = useCallback(() => {
|
|
294
295
|
editor.getEditorState().read(() => {
|
|
@@ -691,8 +692,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
691
692
|
word = atPoint;
|
|
692
693
|
}
|
|
693
694
|
if (!cell && !couplet && config.joinLines) {
|
|
694
|
-
menu.text =
|
|
695
|
-
menu.canJoin = $canJoinLines();
|
|
695
|
+
menu.text = $canJoinLines();
|
|
696
696
|
}
|
|
697
697
|
}, { discrete: true });
|
|
698
698
|
const language = spellCheckLanguage !== 'auto' ? spellCheckLanguage : word?.direction === 'rtl' ? 'ur' : 'en';
|
|
@@ -991,9 +991,8 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
991
991
|
void wordActionAtCaret((language, word) => onAddAutoCorrect(word, language));
|
|
992
992
|
};
|
|
993
993
|
// Keyboard shortcuts mirroring the right-click menu: Ctrl/Cmd+Alt+J joins the
|
|
994
|
-
// selected lines
|
|
995
|
-
//
|
|
996
|
-
// way the menu's Ignore / Add to dictionary / Add to auto-correct items do.
|
|
994
|
+
// selected lines, and Ctrl/Cmd+Alt+I/D/A act on the misspelled word at the caret
|
|
995
|
+
// the way the menu's Ignore / Add to dictionary / Add to auto-correct items do.
|
|
997
996
|
// Matched on event.code (the physical key), not event.key, so they still fire
|
|
998
997
|
// while typing in Urdu or another non-Latin layout, where event.key would be
|
|
999
998
|
// whatever character that layout produces rather than "j"/"i"/"d"/"a".
|
|
@@ -1033,7 +1032,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1033
1032
|
});
|
|
1034
1033
|
// The tools group is always built, even when every command in it is off, so the ribbon asks first.
|
|
1035
1034
|
const hasToolsGroup = config.language.autocorrect || config.language.textCleanup || config.language.spellCheck || config.joinLines;
|
|
1036
|
-
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,
|
|
1035
|
+
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 && state.canJoinLines && (_jsx(ToolbarButton, { icon: IconArrowsJoin, title: strings.toolbar.joinLines, onClick: joinLines }))] }, "tools"));
|
|
1037
1036
|
// Uniform mode's zoom: [-] 100% [+], stepping through the preset levels; the
|
|
1038
1037
|
// percentage resets to 100%. Always laid out left-to-right, like a number.
|
|
1039
1038
|
const showZoom = uniform && config.font.size;
|
|
@@ -1081,10 +1080,9 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1081
1080
|
const measure = toolbarMeasureRef.current;
|
|
1082
1081
|
if (!container || !measure)
|
|
1083
1082
|
return;
|
|
1084
|
-
//
|
|
1085
|
-
//
|
|
1086
|
-
|
|
1087
|
-
const OVERFLOW_BUTTON_WIDTH = 38;
|
|
1083
|
+
// Fallback only, in case the overflow button's own hidden measurement
|
|
1084
|
+
// element (below) isn't mounted yet on the very first pass.
|
|
1085
|
+
const OVERFLOW_BUTTON_FALLBACK_WIDTH = 38;
|
|
1088
1086
|
const recompute = () => {
|
|
1089
1087
|
const available = container.clientWidth;
|
|
1090
1088
|
const total = measure.scrollWidth;
|
|
@@ -1096,6 +1094,10 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1096
1094
|
measure.querySelectorAll('[data-group-key]').forEach((el) => {
|
|
1097
1095
|
widths.set(el.dataset.groupKey, el.getBoundingClientRect().width);
|
|
1098
1096
|
});
|
|
1097
|
+
// Measured from a real (hidden) copy of the "..." button, in the toolbar's own
|
|
1098
|
+
// CSS, rather than guessed — only charged against the budget once something
|
|
1099
|
+
// has actually moved into it, since it isn't rendered at all otherwise.
|
|
1100
|
+
const overflowButtonWidth = toolbarOverflowMeasureRef.current?.scrollWidth ?? OVERFLOW_BUTTON_FALLBACK_WIDTH;
|
|
1099
1101
|
let remaining = total;
|
|
1100
1102
|
const next = new Set();
|
|
1101
1103
|
for (const key of movableGroupKeys.split(',').filter(Boolean)) {
|
|
@@ -1108,13 +1110,15 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1108
1110
|
next.add(key);
|
|
1109
1111
|
}
|
|
1110
1112
|
if (next.size > 0)
|
|
1111
|
-
remaining +=
|
|
1113
|
+
remaining += overflowButtonWidth;
|
|
1112
1114
|
setOverflowGroupKeys((prev) => (setsEqual(prev, next) ? prev : next));
|
|
1113
1115
|
};
|
|
1114
1116
|
recompute();
|
|
1115
1117
|
const ro = new ResizeObserver(recompute);
|
|
1116
1118
|
ro.observe(container);
|
|
1117
1119
|
ro.observe(measure);
|
|
1120
|
+
if (toolbarOverflowMeasureRef.current)
|
|
1121
|
+
ro.observe(toolbarOverflowMeasureRef.current);
|
|
1118
1122
|
return () => ro.disconnect();
|
|
1119
1123
|
});
|
|
1120
1124
|
const isVisible = (section) => !overflowGroupKeys.has(section.key);
|
|
@@ -1162,7 +1166,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1162
1166
|
}, children: synonym }, synonym)))] })] })), contextMenu?.link !== undefined && (_jsxs(Menu.Sub, { ...CONTEXT_SUBMENU_PROPS, children: [_jsx(Menu.Sub.Target, { children: _jsx(Menu.Sub.Item, { leftSection: _jsx(IconLink, { size: ICON_SIZE, stroke: ICON_STROKE }), children: strings.link.menuLabel }) }), _jsx(Menu.Sub.Dropdown, { children: _jsx(LinkMenuItems, { mode: "submenu", url: contextMenu.link, onEdit: () => {
|
|
1163
1167
|
restoreSelection();
|
|
1164
1168
|
openLinkDialog();
|
|
1165
|
-
}, onRemove: removeLink, strings: strings }) })] })), contextMenu?.table && (_jsx(TableMenuItems, { mode: "icons", strings: strings, direction: direction, rows: contextMenu.table.rows, columns: contextMenu.table.columns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction })), contextMenu?.poetry && (_jsx(PoetryMenuItems, { mode: "icons", strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction })), contextMenu?.text && (_jsx(Menu.Item, { leftSection: _jsx(IconArrowsJoin, { size: ICON_SIZE, stroke: ICON_STROKE }), rightSection: _jsx(ShortcutHint, { keys: "Ctrl+Alt+J" }), "aria-keyshortcuts": "Control+Alt+J",
|
|
1169
|
+
}, onRemove: removeLink, strings: strings }) })] })), contextMenu?.table && (_jsx(TableMenuItems, { mode: "icons", strings: strings, direction: direction, rows: contextMenu.table.rows, columns: contextMenu.table.columns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction })), contextMenu?.poetry && (_jsx(PoetryMenuItems, { mode: "icons", strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction })), contextMenu?.text && (_jsx(Menu.Item, { leftSection: _jsx(IconArrowsJoin, { size: ICON_SIZE, stroke: ICON_STROKE }), rightSection: _jsx(ShortcutHint, { keys: "Ctrl+Alt+J" }), "aria-keyshortcuts": "Control+Alt+J", onClick: runMenuAction(() => {
|
|
1166
1170
|
$joinSelectedLines();
|
|
1167
1171
|
}), children: strings.contextMenu.joinLines })), ((contextMenu?.thesaurus && contextMenu.thesaurus.items?.length !== 0) ||
|
|
1168
1172
|
contextMenu?.link !== undefined ||
|
|
@@ -1257,5 +1261,5 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1257
1261
|
setRibbonPeek(false);
|
|
1258
1262
|
}, children: _jsx(MantineToolbar, { "aria-label": strings.toolbar.ariaLabel, className: bordered ? 'likhari-toolbar likhari-ribbon-panel' : 'likhari-toolbar likhari-toolbar--plain likhari-ribbon-panel', withBorder: bordered, variant: variant, color: "var(--editor-accent)", children: withDividers(activeTab.groups) }) })), contextMenuEl, dialogsEl] }));
|
|
1259
1263
|
}
|
|
1260
|
-
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, { opened: overflowMenuOpen, onChange: handleOverflowMenuChange, position: "bottom-end", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: "max-content", closeOnItemClick: false, 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)) }) })] })] })), _jsx("span", { "aria-hidden": "true", style: { flex: '1 1 auto' } }), visibleEnd.map((section) => section.node), contextMenuEl, 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),
|
|
1264
|
+
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, { opened: overflowMenuOpen, onChange: handleOverflowMenuChange, position: "bottom-end", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: "max-content", closeOnItemClick: false, 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)) }) })] })] })), _jsx("span", { "aria-hidden": "true", style: { flex: '1 1 auto' } }), visibleEnd.map((section) => section.node), contextMenuEl, overflowEnabled && (_jsxs(MantineToolbar, { "aria-hidden": "true", ref: toolbarMeasureRef, className: bordered ? 'likhari-toolbar' : 'likhari-toolbar likhari-toolbar--plain', 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), mainMovable.map((section) => (_jsxs(Fragment, { children: [_jsx(MantineToolbar.Divider, {}), _jsx("span", { "data-group-key": section.key, style: { display: 'inline-flex' }, children: section.node })] }, section.key))), endMovable.map((section) => (_jsx("span", { "data-group-key": section.key, style: { display: 'inline-flex' }, children: section.node }, section.key)))] })), overflowEnabled && (_jsxs(MantineToolbar, { "aria-hidden": "true", ref: toolbarOverflowMeasureRef, className: bordered ? 'likhari-toolbar' : 'likhari-toolbar likhari-toolbar--plain', withBorder: bordered, variant: variant, color: "var(--editor-accent)", style: { position: 'absolute', visibility: 'hidden', pointerEvents: 'none', top: 0, left: 0, width: 'max-content' }, children: [_jsx(MantineToolbar.Divider, {}), _jsx(ToolbarButton, { icon: IconDots, title: "Toolbar overflow measurement" })] })), dialogsEl] }));
|
|
1261
1265
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"joinLinesActions.d.ts","sourceRoot":"","sources":["../../src/join/joinLinesActions.ts"],"names":[],"mappings":"AAqCA,wBAAgB,aAAa,IAAI,OAAO,CAKvC;
|
|
1
|
+
{"version":3,"file":"joinLinesActions.d.ts","sourceRoot":"","sources":["../../src/join/joinLinesActions.ts"],"names":[],"mappings":"AAqCA,wBAAgB,aAAa,IAAI,OAAO,CAKvC;AAgFD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAgC5C"}
|
|
@@ -28,11 +28,10 @@ export function $canJoinLines() {
|
|
|
28
28
|
return selection.getNodes().some($isLineBreakNode) || $textNodesWithNewlines(selection).length > 0;
|
|
29
29
|
}
|
|
30
30
|
/** Replaces the newlines in the selected part of a text node, each by one space (none if one is already there). */
|
|
31
|
-
function $replaceNewlinesInText(node,
|
|
32
|
-
const [start, end] = selection.getStartEndPoints() ?? [];
|
|
31
|
+
function $replaceNewlinesInText(node, start, end) {
|
|
33
32
|
const text = node.getTextContent();
|
|
34
|
-
const from = start
|
|
35
|
-
const to = end
|
|
33
|
+
const from = start.key === node.getKey() ? start.offset : 0;
|
|
34
|
+
const to = end.key === node.getKey() ? end.offset : text.length;
|
|
36
35
|
const joined = text.slice(from, to).replace(/[ \t]*\r?\n[ \t]*/g, ' ');
|
|
37
36
|
node.setTextContent(text.slice(0, from) + joined + text.slice(to));
|
|
38
37
|
}
|
|
@@ -126,27 +125,26 @@ export function $joinSelectedLines() {
|
|
|
126
125
|
const textsWithNewlines = $textNodesWithNewlines(selection);
|
|
127
126
|
if (paragraphs.length < 2 && lineBreaks.length === 0 && textsWithNewlines.length === 0)
|
|
128
127
|
return false;
|
|
129
|
-
|
|
128
|
+
// RangeSelection's anchor/focus track drag direction, not document order (and
|
|
129
|
+
// getStartEndPoints() returns them as-is, anchor first) — reorder them so "start"/"end"
|
|
130
|
+
// below always mean "earlier"/"later" in the document, regardless of which way the user
|
|
131
|
+
// dragged, or Shift+arrow'd, the selection. Getting this wrong silently skips the tail
|
|
132
|
+
// split below (sweeping unselected content into the join) for any backward selection.
|
|
133
|
+
const [start, end] = selection.isBackward() ? [selection.focus, selection.anchor] : [selection.anchor, selection.focus];
|
|
130
134
|
for (const lineBreak of lineBreaks)
|
|
131
135
|
$replaceBreakWithSpace(lineBreak);
|
|
132
136
|
for (const textNode of textsWithNewlines)
|
|
133
|
-
$replaceNewlinesInText(textNode,
|
|
137
|
+
$replaceNewlinesInText(textNode, start, end);
|
|
134
138
|
const [target, ...rest] = paragraphs;
|
|
135
139
|
if (!target)
|
|
136
140
|
return false;
|
|
137
141
|
const lastParagraph = paragraphs[paragraphs.length - 1];
|
|
138
|
-
|
|
139
|
-
$splitUnselectedTail(lastParagraph, end);
|
|
142
|
+
$splitUnselectedTail(lastParagraph, end);
|
|
140
143
|
for (const paragraph of rest)
|
|
141
144
|
$appendParagraph(target, paragraph);
|
|
142
145
|
// Keep the caret where the selection began, rather than at the end of everything
|
|
143
146
|
// just joined — useful on its own, and essential when many lines were joined at
|
|
144
147
|
// once, where "the end" could otherwise land far past where the user was working.
|
|
145
|
-
|
|
146
|
-
start.getNode().select(start.offset, start.offset);
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
target.selectEnd();
|
|
150
|
-
}
|
|
148
|
+
start.getNode().select(start.offset, start.offset);
|
|
151
149
|
return true;
|
|
152
150
|
}
|