@37signals/lexxy 0.9.13-beta → 0.9.15-alpha.1
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/README.md +0 -3
- package/dist/lexxy.esm.js +72 -25
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/lexxy.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { highlightCode } 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, $caretFromPoint, $setSelectionFromCaretRange, $getCaretRange, $normalizeCaret, $getChildCaret, $getCaretInDirection, $isParagraphNode, $isLineBreakNode, $createParagraphNode, $isElementNode, $isRootOrShadowRoot, $isRootNode, $createNodeSelection, $isDecoratorNode, $isTextNode, $getSiblingCaret, $rewindSiblingCaret, $splitAtPointCaretNext, $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, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $isNodeSelection,
|
|
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, $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, 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, PASTE_COMMAND, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, ParagraphNode, RootNode, COMMAND_PRIORITY_HIGH, DRAGSTART_COMMAND, DROP_COMMAND, INSERT_PARAGRAPH_COMMAND, mergeRegister as mergeRegister$1, CLEAR_HISTORY_COMMAND, $onUpdate, KEY_ENTER_COMMAND, COMMAND_PRIORITY_CRITICAL, KEY_SPACE_COMMAND, INPUT_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND } from 'lexical';
|
|
5
5
|
import { LinkNode, $createAutoLinkNode, $toggleLink, $createLinkNode, $isLinkNode, AutoLinkNode } from '@lexical/link';
|
|
6
6
|
import { buildEditorFromExtensions } from '@lexical/extension';
|
|
7
7
|
import { ListNode, ListItemNode, $getListDepth, INSERT_UNORDERED_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, $isListItemNode, $isListNode, registerList } from '@lexical/list';
|
|
@@ -619,14 +619,14 @@ class LexicalToolbarElement extends HTMLElement {
|
|
|
619
619
|
|
|
620
620
|
this.#setButtonPressed("bold", isBold);
|
|
621
621
|
this.#setButtonPressed("italic", isItalic);
|
|
622
|
+
this.#setButtonPressed("strikethrough", isStrikethrough);
|
|
623
|
+
this.#setButtonPressed("underline", isUnderline);
|
|
622
624
|
|
|
623
|
-
this.#setButtonPressed("format", isInHeading
|
|
625
|
+
this.#setButtonPressed("format", isInHeading);
|
|
624
626
|
this.#setButtonPressed("paragraph", !isInHeading);
|
|
625
627
|
this.#setButtonPressed("heading-large", headingTag === "h2");
|
|
626
628
|
this.#setButtonPressed("heading-medium", headingTag === "h3");
|
|
627
629
|
this.#setButtonPressed("heading-small", headingTag === "h4");
|
|
628
|
-
this.#setButtonPressed("strikethrough", isStrikethrough);
|
|
629
|
-
this.#setButtonPressed("underline", isUnderline);
|
|
630
630
|
|
|
631
631
|
this.#setButtonPressed("lists", isInList);
|
|
632
632
|
this.#setButtonPressed("unordered-list", isInList && listType === "bullet");
|
|
@@ -789,6 +789,14 @@ class LexicalToolbarElement extends HTMLElement {
|
|
|
789
789
|
${ToolbarIcons.italic}
|
|
790
790
|
</button>
|
|
791
791
|
|
|
792
|
+
<button class="lexxy-editor__toolbar-button" type="button" name="strikethrough" data-command="strikethrough" title="Strikethrough">
|
|
793
|
+
${ToolbarIcons.strikethrough}
|
|
794
|
+
</button>
|
|
795
|
+
|
|
796
|
+
<button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="underline" data-command="underline" title="Underline">
|
|
797
|
+
${ToolbarIcons.underline}
|
|
798
|
+
</button>
|
|
799
|
+
|
|
792
800
|
<lexxy-toolbar-dropdown class="lexxy-editor__toolbar-dropdown">
|
|
793
801
|
<button data-dropdown-trigger class="lexxy-editor__toolbar-button lexxy-editor__toolbar-button--chevron" type="button" name="format" title="Text formatting" aria-haspopup="menu" aria-expanded="false">
|
|
794
802
|
${ToolbarIcons.heading}
|
|
@@ -807,13 +815,6 @@ class LexicalToolbarElement extends HTMLElement {
|
|
|
807
815
|
${ToolbarIcons.h4} <span>Small Heading</span>
|
|
808
816
|
</button>
|
|
809
817
|
<div class="lexxy-editor__toolbar-separator" role="separator"></div>
|
|
810
|
-
<button type="button" name="strikethrough" data-command="strikethrough" title="Strikethrough" role="menuitem">
|
|
811
|
-
${ToolbarIcons.strikethrough} <span>Strikethrough</span>
|
|
812
|
-
</button>
|
|
813
|
-
<button type="button" name="underline" data-command="underline" title="Underline" role="menuitem">
|
|
814
|
-
${ToolbarIcons.underline} <span>Underline</span>
|
|
815
|
-
</button>
|
|
816
|
-
<div class="lexxy-editor__toolbar-separator" role="separator"></div>
|
|
817
818
|
<button type="button" name="clear-formatting" data-command="clearFormatting" title="Clear formatting" role="menuitem">
|
|
818
819
|
${ToolbarIcons.clearFormatting} <span>Clear formatting</span>
|
|
819
820
|
</button>
|
|
@@ -1526,14 +1527,15 @@ function $isShadowRoot(node) {
|
|
|
1526
1527
|
return $isElementNode(node) && $isRootOrShadowRoot(node) && !$isRootNode(node)
|
|
1527
1528
|
}
|
|
1528
1529
|
|
|
1530
|
+
function $isSafeForRoot(node) {
|
|
1531
|
+
return ($isElementNode(node) || $isDecoratorNode(node)) && !node.isParentRequired()
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1529
1534
|
function $makeSafeForRoot(node) {
|
|
1530
|
-
if ($
|
|
1531
|
-
return $wrapNodeInElement(node, $createParagraphNode)
|
|
1532
|
-
} else if (node.isParentRequired()) {
|
|
1533
|
-
const parent = node.createRequiredParent();
|
|
1534
|
-
return $wrapNodeInElement(node, parent)
|
|
1535
|
-
} else {
|
|
1535
|
+
if ($isSafeForRoot(node)) {
|
|
1536
1536
|
return node
|
|
1537
|
+
} else {
|
|
1538
|
+
return $wrapNodeInElement(node, () => node.createParentElementNode())
|
|
1537
1539
|
}
|
|
1538
1540
|
}
|
|
1539
1541
|
|
|
@@ -1648,6 +1650,39 @@ function $isListItemStructurallyEmpty(listItem) {
|
|
|
1648
1650
|
return true
|
|
1649
1651
|
}
|
|
1650
1652
|
|
|
1653
|
+
// Returns the document text up to `offset` inside `targetNode`. Non-inline
|
|
1654
|
+
// element siblings are joined with `\n\n`, matching Lexical's own
|
|
1655
|
+
// ElementNode.getTextContent behavior.
|
|
1656
|
+
function $textBeforeOffset(targetNode, offset) {
|
|
1657
|
+
const parts = [];
|
|
1658
|
+
let done = false;
|
|
1659
|
+
|
|
1660
|
+
function visit(node) {
|
|
1661
|
+
if (done) return
|
|
1662
|
+
if (node === targetNode) {
|
|
1663
|
+
parts.push(node.getTextContent().slice(0, offset));
|
|
1664
|
+
done = true;
|
|
1665
|
+
return
|
|
1666
|
+
}
|
|
1667
|
+
if ($isElementNode(node)) {
|
|
1668
|
+
const children = node.getChildren();
|
|
1669
|
+
for (let i = 0; i < children.length; i++) {
|
|
1670
|
+
visit(children[i]);
|
|
1671
|
+
if (done) return
|
|
1672
|
+
const child = children[i];
|
|
1673
|
+
if ($isElementNode(child) && !child.isInline() && i < children.length - 1) {
|
|
1674
|
+
parts.push("\n\n");
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
} else {
|
|
1678
|
+
parts.push(node.getTextContent());
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
visit($getRoot());
|
|
1683
|
+
return parts.join("")
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1651
1686
|
function isAttachmentSpacerTextNode(node, previousNode, index, childCount) {
|
|
1652
1687
|
return $isTextNode(node)
|
|
1653
1688
|
&& node.getTextContent() === " "
|
|
@@ -8551,6 +8586,9 @@ class RemoteFilterSource extends BaseSource {
|
|
|
8551
8586
|
const NOTHING_FOUND_DEFAULT_MESSAGE = "Nothing found";
|
|
8552
8587
|
const FILTER_DEBOUNCE_INTERVAL = 50;
|
|
8553
8588
|
|
|
8589
|
+
// Start of line, or after a space or newline.
|
|
8590
|
+
const DEFAULT_ONLY_AT_PATTERN = "^|[ \\n]";
|
|
8591
|
+
|
|
8554
8592
|
class LexicalPromptElement extends HTMLElement {
|
|
8555
8593
|
#globalListeners = new ListenerBin()
|
|
8556
8594
|
#popoverListeners = new ListenerBin()
|
|
@@ -8596,6 +8634,10 @@ class LexicalPromptElement extends HTMLElement {
|
|
|
8596
8634
|
return this.hasAttribute("supports-space-in-searches")
|
|
8597
8635
|
}
|
|
8598
8636
|
|
|
8637
|
+
get onlyAt() {
|
|
8638
|
+
return this.getAttribute("only-at")
|
|
8639
|
+
}
|
|
8640
|
+
|
|
8599
8641
|
get open() {
|
|
8600
8642
|
return this.popoverElement?.classList?.contains("lexxy-prompt-menu--visible")
|
|
8601
8643
|
}
|
|
@@ -8639,14 +8681,10 @@ class LexicalPromptElement extends HTMLElement {
|
|
|
8639
8681
|
if (offset >= triggerLength) {
|
|
8640
8682
|
const textBeforeCursor = fullText.slice(offset - triggerLength, offset);
|
|
8641
8683
|
|
|
8642
|
-
// Check if trigger is at the start of the text node (new line case) or preceded by space or newline
|
|
8643
8684
|
if (textBeforeCursor === this.trigger) {
|
|
8644
|
-
const
|
|
8645
|
-
|
|
8646
|
-
const charBeforeTrigger = offset > triggerLength ? fullText[offset - triggerLength - 1] : null;
|
|
8647
|
-
const isPrecededBySpaceOrNewline = charBeforeTrigger === " " || charBeforeTrigger === "\n";
|
|
8685
|
+
const textBeforeTrigger = $textBeforeOffset(node, offset - triggerLength);
|
|
8648
8686
|
|
|
8649
|
-
if (
|
|
8687
|
+
if (this.#onlyAtRegExp.test(textBeforeTrigger)) {
|
|
8650
8688
|
this.#popoverListeners.dispose();
|
|
8651
8689
|
this.#showPopover();
|
|
8652
8690
|
}
|
|
@@ -8657,7 +8695,15 @@ class LexicalPromptElement extends HTMLElement {
|
|
|
8657
8695
|
}));
|
|
8658
8696
|
}
|
|
8659
8697
|
|
|
8698
|
+
get #onlyAtRegExp() {
|
|
8699
|
+
return new RegExp(`(?:${this.onlyAt ?? DEFAULT_ONLY_AT_PATTERN})$`)
|
|
8700
|
+
}
|
|
8701
|
+
|
|
8660
8702
|
get #promptContentTypePermitted() {
|
|
8703
|
+
// `insert-editable-text` prompts never create attachments, so the
|
|
8704
|
+
// editor's attachment support and content-type allowlist don't apply.
|
|
8705
|
+
if (this.hasAttribute("insert-editable-text")) return true
|
|
8706
|
+
|
|
8661
8707
|
const el = this.#editorElement;
|
|
8662
8708
|
if (!el.supportsAttachments) {
|
|
8663
8709
|
return false
|
|
@@ -9360,6 +9406,8 @@ class TableController {
|
|
|
9360
9406
|
|
|
9361
9407
|
this.currentCellKey = cellNode?.getKey() ?? null;
|
|
9362
9408
|
this.currentTableNodeKey = tableNode?.getKey() ?? null;
|
|
9409
|
+
|
|
9410
|
+
return tableNode
|
|
9363
9411
|
}
|
|
9364
9412
|
|
|
9365
9413
|
executeTableCommand(command, customIndex = null) {
|
|
@@ -9862,9 +9910,8 @@ class TableTools extends HTMLElement {
|
|
|
9862
9910
|
|
|
9863
9911
|
#monitorForTableSelection() {
|
|
9864
9912
|
this.#listeners.track(this.#editor.registerUpdateListener(() => {
|
|
9865
|
-
this.tableController.updateSelectedTable();
|
|
9913
|
+
const tableNode = this.#editor.getRootElement() && this.tableController.updateSelectedTable();
|
|
9866
9914
|
|
|
9867
|
-
const tableNode = this.tableController.currentTableNode;
|
|
9868
9915
|
if (tableNode) {
|
|
9869
9916
|
this.#show();
|
|
9870
9917
|
} else {
|