@inshapardaz/likhari-react 0.1.48-dev.371 → 0.1.49-dev.391

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":"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"}
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"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"}
@@ -289,7 +289,6 @@ 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);
293
292
  const [overflowGroupKeys, setOverflowGroupKeys] = useState(EMPTY_OVERFLOW);
294
293
  const updateToolbar = useCallback(() => {
295
294
  editor.getEditorState().read(() => {
@@ -692,8 +691,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
692
691
  word = atPoint;
693
692
  }
694
693
  if (!cell && !couplet && config.joinLines) {
695
- menu.text = true;
696
- menu.canJoin = $canJoinLines();
694
+ menu.text = $canJoinLines();
697
695
  }
698
696
  }, { discrete: true });
699
697
  const language = spellCheckLanguage !== 'auto' ? spellCheckLanguage : word?.direction === 'rtl' ? 'ur' : 'en';
@@ -992,9 +990,8 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
992
990
  void wordActionAtCaret((language, word) => onAddAutoCorrect(word, language));
993
991
  };
994
992
  // Keyboard shortcuts mirroring the right-click menu: Ctrl/Cmd+Alt+J joins the
995
- // selected lines (plain Ctrl+J is already the browser's bookmarks-manager
996
- // shortcut), and Ctrl/Cmd+Alt+I/D/A act on the misspelled word at the caret the
997
- // way the menu's Ignore / Add to dictionary / Add to auto-correct items do.
993
+ // selected lines, and Ctrl/Cmd+Alt+I/D/A act on the misspelled word at the caret
994
+ // the way the menu's Ignore / Add to dictionary / Add to auto-correct items do.
998
995
  // Matched on event.code (the physical key), not event.key, so they still fire
999
996
  // while typing in Urdu or another non-Latin layout, where event.key would be
1000
997
  // whatever character that layout produces rather than "j"/"i"/"d"/"a".
@@ -1034,7 +1031,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
1034
1031
  });
1035
1032
  // The tools group is always built, even when every command in it is off, so the ribbon asks first.
1036
1033
  const hasToolsGroup = config.language.autocorrect || config.language.textCleanup || config.language.spellCheck || config.joinLines;
1037
- 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"));
1034
+ 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"));
1038
1035
  // Uniform mode's zoom: [-] 100% [+], stepping through the preset levels; the
1039
1036
  // percentage resets to 100%. Always laid out left-to-right, like a number.
1040
1037
  const showZoom = uniform && config.font.size;
@@ -1082,9 +1079,10 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
1082
1079
  const measure = toolbarMeasureRef.current;
1083
1080
  if (!container || !measure)
1084
1081
  return;
1085
- // Fallback only, in case the overflow button's own hidden measurement
1086
- // element (below) isn't mounted yet on the very first pass.
1087
- const OVERFLOW_BUTTON_FALLBACK_WIDTH = 38;
1082
+ // Rough width of the "..." button itself (icon button + its gap) —
1083
+ // only charged against the budget once something has actually moved
1084
+ // into it, since it isn't rendered at all otherwise.
1085
+ const OVERFLOW_BUTTON_WIDTH = 38;
1088
1086
  const recompute = () => {
1089
1087
  const available = container.clientWidth;
1090
1088
  const total = measure.scrollWidth;
@@ -1096,10 +1094,6 @@ 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
  });
1099
- // Measured from a real (hidden) copy of the "..." button, in the toolbar's own
1100
- // CSS, rather than guessed — only charged against the budget once something
1101
- // has actually moved into it, since it isn't rendered at all otherwise.
1102
- const overflowButtonWidth = toolbarOverflowMeasureRef.current?.scrollWidth ?? OVERFLOW_BUTTON_FALLBACK_WIDTH;
1103
1097
  let remaining = total;
1104
1098
  const next = new Set();
1105
1099
  for (const key of movableGroupKeys.split(',').filter(Boolean)) {
@@ -1112,15 +1106,13 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
1112
1106
  next.add(key);
1113
1107
  }
1114
1108
  if (next.size > 0)
1115
- remaining += overflowButtonWidth;
1109
+ remaining += OVERFLOW_BUTTON_WIDTH;
1116
1110
  setOverflowGroupKeys((prev) => (setsEqual(prev, next) ? prev : next));
1117
1111
  };
1118
1112
  recompute();
1119
1113
  const ro = new ResizeObserver(recompute);
1120
1114
  ro.observe(container);
1121
1115
  ro.observe(measure);
1122
- if (toolbarOverflowMeasureRef.current)
1123
- ro.observe(toolbarOverflowMeasureRef.current);
1124
1116
  return () => ro.disconnect();
1125
1117
  });
1126
1118
  const isVisible = (section) => !overflowGroupKeys.has(section.key);
@@ -1168,7 +1160,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
1168
1160
  }, 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: () => {
1169
1161
  restoreSelection();
1170
1162
  openLinkDialog();
1171
- }, 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", disabled: !contextMenu.canJoin, onClick: runMenuAction(() => {
1163
+ }, 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(() => {
1172
1164
  $joinSelectedLines();
1173
1165
  }), children: strings.contextMenu.joinLines })), ((contextMenu?.thesaurus && contextMenu.thesaurus.items?.length !== 0) ||
1174
1166
  contextMenu?.link !== undefined ||
@@ -1263,5 +1255,5 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
1263
1255
  setRibbonPeek(false);
1264
1256
  }, 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] }));
1265
1257
  }
1266
- 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] }));
1258
+ 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), 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)))] })), dialogsEl] }));
1267
1259
  }
@@ -1 +1 @@
1
- {"version":3,"file":"joinLinesActions.d.ts","sourceRoot":"","sources":["../../src/join/joinLinesActions.ts"],"names":[],"mappings":"AAqCA,wBAAgB,aAAa,IAAI,OAAO,CAKvC;AAiFD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CA+B5C"}
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, selection) {
32
- const [start, end] = selection.getStartEndPoints() ?? [];
31
+ function $replaceNewlinesInText(node, start, end) {
33
32
  const text = node.getTextContent();
34
- const from = start && start.key === node.getKey() ? start.offset : 0;
35
- const to = end && end.key === node.getKey() ? end.offset : text.length;
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
- const [start, end] = selection.getStartEndPoints() ?? [];
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, selection);
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
- if (end)
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
- if (start) {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inshapardaz/likhari-react",
3
- "version": "0.1.48-dev.371",
3
+ "version": "0.1.49-dev.391",
4
4
  "description": "React implementation of the Likhari editor, built on @lexical/react.",
5
5
  "license": "MIT",
6
6
  "repository": {