@37signals/lexxy 0.9.22 → 0.9.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/lexxy.esm.js +55 -15
  2. package/package.json +1 -1
package/dist/lexxy.esm.js CHANGED
@@ -1,7 +1,9 @@
1
1
  export { highlightCode, highlightElement } from './lexxy_helpers.esm.js';
2
2
  import DOMPurify from 'dompurify';
3
3
  import { getStyleObjectFromCSS, getCSSFromStyleObject, $getSelectionStyleValueForProperty, $ensureForwardRangeSelection, $isAtNodeEnd, $patchStyleText, $setBlocksType, $forEachSelectedTextNode } from '@lexical/selection';
4
- import { SKIP_DOM_SELECTION_TAG, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, CAN_REDO_COMMAND, $getSelection, $isRangeSelection, DecoratorNode, $createTextNode, $getRoot, $caretFromPoint, $setSelectionFromCaretRange, $getCaretRange, $normalizeCaret, $getChildCaret, $getCaretInDirection, $isParagraphNode, $isLineBreakNode, $createParagraphNode, $isElementNode, $isRootOrShadowRoot, $isRootNode, $createNodeSelection, $isDecoratorNode, $isTextNode, $getSiblingCaret, $rewindSiblingCaret, $splitAtPointCaretNext, $normalizeSelection__EXPERIMENTAL, $isChildCaret, $isTextPointCaret, $isExtendableTextPointCaret, $isSiblingCaret, $getCommonAncestor, $findMatchingParent, TextNode, createCommand, defineExtension, COMMAND_PRIORITY_EDITOR, $getEditor, $getNodeByKey, HISTORY_MERGE_TAG, SKIP_SCROLL_INTO_VIEW_TAG, $cloneWithProperties, $getNearestRootOrShadowRoot, $createRangeSelection, $setSelection, createState, COMMAND_PRIORITY_NORMAL, $getState, $setState, $hasUpdateTag, PASTE_TAG, FORMAT_TEXT_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_TAB_COMMAND, INSERT_LINE_BREAK_COMMAND, COMMAND_PRIORITY_HIGH, INSERT_PARAGRAPH_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $isNodeSelection, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ARROW_DOWN_COMMAND, DELETE_CHARACTER_COMMAND, SELECTION_CHANGE_COMMAND, CLICK_COMMAND, isDOMNode, $getNearestNodeFromDOMNode, $addUpdateTag, ElementNode, $splitNode, $getChildCaretAtIndex, $createLineBreakNode, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, PASTE_COMMAND, $onUpdate, ParagraphNode, RootNode, DRAGSTART_COMMAND, DROP_COMMAND, mergeRegister as mergeRegister$1, $createRangeSelectionFromDom, CLEAR_HISTORY_COMMAND, KEY_ENTER_COMMAND, COMMAND_PRIORITY_CRITICAL, KEY_SPACE_COMMAND, INPUT_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND } from 'lexical';
4
+ import { SKIP_DOM_SELECTION_TAG, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, CAN_REDO_COMMAND, $getSelection, $isRangeSelection, DecoratorNode, $createTextNode, defineExtension, $getRoot, $caretFromPoint, $setSelectionFromCaretRange, $getCaretRange, $normalizeCaret, $getChildCaret, $getCaretInDirection, $isParagraphNode, $isLineBreakNode, $createParagraphNode, $isElementNode, $isRootOrShadowRoot, $isRootNode, $createNodeSelection, $isDecoratorNode, $isTextNode, $getSiblingCaret, $rewindSiblingCaret, $splitAtPointCaretNext, $normalizeSelection__EXPERIMENTAL, $isChildCaret, $isTextPointCaret, $isExtendableTextPointCaret, $isSiblingCaret, $getCommonAncestor, $findMatchingParent, TextNode, createCommand, COMMAND_PRIORITY_EDITOR, $getEditor, $getNodeByKey, HISTORY_MERGE_TAG, SKIP_SCROLL_INTO_VIEW_TAG, $cloneWithProperties, $getNearestRootOrShadowRoot, $createRangeSelection, $setSelection, createState, COMMAND_PRIORITY_NORMAL, $getState, $setState, $hasUpdateTag, PASTE_TAG, FORMAT_TEXT_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_TAB_COMMAND, INSERT_LINE_BREAK_COMMAND, COMMAND_PRIORITY_HIGH, INSERT_PARAGRAPH_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $isNodeSelection, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ARROW_DOWN_COMMAND, DELETE_CHARACTER_COMMAND, SELECTION_CHANGE_COMMAND, CLICK_COMMAND, isDOMNode, $getNearestNodeFromDOMNode, $addUpdateTag, ElementNode, $splitNode, $getChildCaretAtIndex, $createLineBreakNode, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, PASTE_COMMAND, $onUpdate, ParagraphNode, RootNode, DRAGSTART_COMMAND, DROP_COMMAND, mergeRegister as mergeRegister$1, $createRangeSelectionFromDom, CLEAR_HISTORY_COMMAND, KEY_ENTER_COMMAND, COMMAND_PRIORITY_CRITICAL, KEY_SPACE_COMMAND, INPUT_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND } from 'lexical';
5
+ import * as lexical from 'lexical';
6
+ export { lexical as Lexical };
5
7
  import { LinkNode, $createAutoLinkNode, $toggleLink, $createLinkNode, $isLinkNode, AutoLinkNode } from '@lexical/link';
6
8
  import { buildEditorFromExtensions } from '@lexical/extension';
7
9
  import { ListNode, ListItemNode, $getListDepth, $isListNode, $isListItemNode, INSERT_UNORDERED_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, $createListNode, $createListItemNode, registerList } from '@lexical/list';
@@ -1509,8 +1511,11 @@ class LexxyExtension {
1509
1511
  return []
1510
1512
  }
1511
1513
 
1512
- initializeToolbar(_lexxyToolbar) {
1514
+ defineExtension(...args) {
1515
+ return defineExtension(...args)
1516
+ }
1513
1517
 
1518
+ initializeToolbar(_lexxyToolbar) {
1514
1519
  }
1515
1520
 
1516
1521
  setEditorValidity(flags, message) {
@@ -5994,16 +5999,34 @@ class Contents {
5994
5999
  return result
5995
6000
  }
5996
6001
 
5997
- // The query runs from the trigger up to the next whitespace, even when the
6002
+ // The query runs from the trigger up to the next boundary, even when the
5998
6003
  // cursor sits inside an existing word — inserting "@" before "Jack" must
5999
6004
  // filter by "Jack" rather than treating the prompt as empty.
6000
6005
  #endOffsetAt(fullText, cursorOffset) {
6001
- const whitespaceOffset = fullText.slice(cursorOffset).search(/\s/);
6002
- if (whitespaceOffset === -1) {
6003
- return fullText.length
6004
- } else {
6005
- return cursorOffset + whitespaceOffset
6006
+ for (let offset = cursorOffset; offset < fullText.length; offset++) {
6007
+ if (this.#isQueryBoundary(fullText, offset)) {
6008
+ return offset
6009
+ }
6006
6010
  }
6011
+
6012
+ return fullText.length
6013
+ }
6014
+
6015
+ // Whitespace always ends the query. Punctuation ends it too: with "@" typed
6016
+ // right before a period, extending across it would glue "." onto everything
6017
+ // typed ("B" would query "B."), matching the wrong names or nothing at all.
6018
+ // But punctuation joining two word characters is part of a name — "@" before
6019
+ // "Anne-Marie" or "O'Connor" must keep the whole name as the query.
6020
+ #isQueryBoundary(fullText, offset) {
6021
+ const character = fullText[offset];
6022
+ if (/\s/.test(character)) return true
6023
+ if (!/\p{P}/u.test(character)) return false
6024
+
6025
+ return !(this.#isWordCharacter(fullText[offset - 1]) && this.#isWordCharacter(fullText[offset + 1]))
6026
+ }
6027
+
6028
+ #isWordCharacter(character) {
6029
+ return character != null && /[\p{L}\p{N}]/u.test(character)
6007
6030
  }
6008
6031
 
6009
6032
  containsTextBackUntil(string) {
@@ -7222,9 +7245,13 @@ class TablesExtension extends LexxyExtension {
7222
7245
  }
7223
7246
  }),
7224
7247
 
7225
- // Bug fix: Prevent hardcoded background color (Lexical #8089)
7248
+ // A table in Lexxy is a Lexxy table: cell shading can't be set in the
7249
+ // editor, so any cell background only ever comes from foreign content
7250
+ // (pasted spreadsheets, loaded documents). Normalize every cell to no
7251
+ // background so it adopts the current theme. This also clears
7252
+ // Lexical's hardcoded default header background (Lexical #8089).
7226
7253
  editor.registerNodeTransform(TableCellNode, (node) => {
7227
- if (node.getBackgroundColor() === null) {
7254
+ if (node.getBackgroundColor() !== "") {
7228
7255
  node.setBackgroundColor("");
7229
7256
  }
7230
7257
  }),
@@ -10672,6 +10699,7 @@ class TableTools extends HTMLElement {
10672
10699
  connectedCallback() {
10673
10700
  this.tableController = new TableController(this.#editorElement);
10674
10701
  this.classList.add("lexxy-floating-controls");
10702
+ this.role = "toolbar";
10675
10703
 
10676
10704
  this.#setUpButtons();
10677
10705
  this.#hide();
@@ -10802,16 +10830,28 @@ class TableTools extends HTMLElement {
10802
10830
  }
10803
10831
 
10804
10832
  #registerKeyboardShortcuts() {
10805
- this.#listeners.track(this.#editor.registerCommand(KEY_DOWN_COMMAND, this.#handleAccessibilityShortcutKey, COMMAND_PRIORITY_HIGH));
10833
+ this.#listeners.track(this.#editor.registerCommand(KEY_DOWN_COMMAND, this.#focusToolbarOnShortcut, COMMAND_PRIORITY_HIGH));
10806
10834
  }
10807
10835
 
10808
- #handleAccessibilityShortcutKey = (event) => {
10809
- if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.key === "F10") {
10810
- const firstButton = this.querySelector("button, [tabindex]:not([tabindex='-1'])");
10811
- firstButton?.focus();
10836
+ #focusToolbarOnShortcut = (event) => {
10837
+ if (this.#hasSelectedTable && this.#isFocusToolbarShortcut(event)) {
10838
+ event.preventDefault();
10839
+ this.#tableToolsButtons[0]?.focus();
10840
+ return true
10841
+ } else {
10842
+ return false
10812
10843
  }
10813
10844
  }
10814
10845
 
10846
+ get #hasSelectedTable() {
10847
+ return this.tableController?.currentTableNodeKey != null
10848
+ }
10849
+
10850
+ #isFocusToolbarShortcut(event) {
10851
+ if (event.key !== "F10") return false
10852
+ return event.altKey || ((event.ctrlKey || event.metaKey) && event.shiftKey)
10853
+ }
10854
+
10815
10855
  #handleToolsKeydown = (event) => {
10816
10856
  if (event.key === "Escape") {
10817
10857
  this.#handleEscapeKey();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@37signals/lexxy",
3
- "version": "0.9.22",
3
+ "version": "0.9.23",
4
4
  "description": "Lexxy - A modern rich text editor for Rails.",
5
5
  "module": "dist/lexxy.esm.js",
6
6
  "type": "module",