onchain-lexical-instance 0.0.13 → 0.0.15

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.
@@ -21,6 +21,7 @@ var onchainLexicalMarkdown = require('onchain-lexical-markdown');
21
21
  var traversal = require('onchain-utility/traversal');
22
22
  var selection = require('@lexical/selection');
23
23
  var useLexicalNodeSelection = require('@lexical/react/useLexicalNodeSelection');
24
+ var base64 = require('onchain-utility/base64');
24
25
  var hooks = require('onchain-utility/hooks');
25
26
  var richText = require('@lexical/rich-text');
26
27
  var useLexicalEditable = require('@lexical/react/useLexicalEditable');
@@ -1143,6 +1144,26 @@ function $addInstancesNode({
1143
1144
  }
1144
1145
  }
1145
1146
  }
1147
+ function $selectDecoratorNode(node) {
1148
+ if (node) {
1149
+ const [previous, next] = [node.getPreviousSibling(), node.getNextSibling()];
1150
+ const rangeSelection = lexical.$createRangeSelection();
1151
+ if (previous) {
1152
+ const isText = lexical.$isTextNode(previous);
1153
+ rangeSelection.anchor.set(isText ? previous.getKey() : node.getParent().getKey(), isText ? previous.getTextContentSize() : node.getPreviousSiblings().length, isText ? 'text' : 'element');
1154
+ } else {
1155
+ const parent = node.getParent();
1156
+ rangeSelection.anchor.set(parent.getKey(), 0, 'element');
1157
+ }
1158
+ if (next) {
1159
+ rangeSelection.focus.set(next.getKey(), 0, lexical.$isTextNode(next) ? 'text' : 'element');
1160
+ } else {
1161
+ const parent = node.getParent();
1162
+ rangeSelection.focus.set(parent.getKey(), node.getPreviousSiblings().length + 1, 'element');
1163
+ }
1164
+ lexical.$setSelection(rangeSelection);
1165
+ }
1166
+ }
1146
1167
 
1147
1168
  /**
1148
1169
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -2671,7 +2692,7 @@ function $textNodeTransform(node, editor, tokenizer) {
2671
2692
  // if node's parent is a code node and run highlighting if so
2672
2693
  const parentNode = node.getParent();
2673
2694
  if ($isInstanceCodeNode(parentNode)) {
2674
- codeNodeTransform(parentNode, editor, tokenizer);
2695
+ codeNodeTransform(parentNode, null, tokenizer);
2675
2696
  } else if ($isInstanceCodeHighlightNode(node)) {
2676
2697
  // When code block converted into paragraph or other element
2677
2698
  // code highlight nodes converted back to normal text
@@ -2711,9 +2732,9 @@ function updateCodeGutter(node, editor) {
2711
2732
  // Especially when pasting code into CodeBlock.
2712
2733
 
2713
2734
  const nodesCurrentlyHighlighting = new Set();
2714
- function codeNodeTransform(node, editor, tokenizer) {
2735
+ function codeNodeTransform(node, editor, tokenizer, isEnforcement) {
2715
2736
  const nodeKey = node.getKey();
2716
- if (nodesCurrentlyHighlighting.has(nodeKey)) {
2737
+ if (nodesCurrentlyHighlighting.has(nodeKey) && !isEnforcement) {
2717
2738
  return;
2718
2739
  }
2719
2740
  nodesCurrentlyHighlighting.add(nodeKey);
@@ -2726,7 +2747,8 @@ function codeNodeTransform(node, editor, tokenizer) {
2726
2747
  // Using nested update call to pass `skipTransforms` since we don't want
2727
2748
  // each individual InstanceCodeHighlightNode to be transformed again as it's already
2728
2749
  // in its final state
2729
- editor.update(() => {
2750
+ // eslint-disable-next-line @lexical/rules-of-lexical
2751
+ const transform = () => {
2730
2752
  $updateAndRetainSelection(nodeKey, () => {
2731
2753
  const currentNode = lexical.$getNodeByKey(nodeKey);
2732
2754
  if (!$isInstanceCodeNode(currentNode) || !currentNode.isAttached()) {
@@ -2747,12 +2769,17 @@ function codeNodeTransform(node, editor, tokenizer) {
2747
2769
  }
2748
2770
  return false;
2749
2771
  });
2750
- }, {
2751
- onUpdate: () => {
2752
- nodesCurrentlyHighlighting.delete(nodeKey);
2753
- },
2754
- skipTransforms: true
2755
- });
2772
+ };
2773
+ if (editor) {
2774
+ editor.update(transform, {
2775
+ onUpdate: () => {
2776
+ nodesCurrentlyHighlighting.delete(nodeKey);
2777
+ },
2778
+ skipTransforms: true
2779
+ });
2780
+ } else {
2781
+ transform();
2782
+ }
2756
2783
  }
2757
2784
  function $getHighlightNodes(tokens, type) {
2758
2785
  const nodes = [];
@@ -3159,7 +3186,7 @@ function registerCodeHighlighting(editor, tokenizer) {
3159
3186
  });
3160
3187
  }, {
3161
3188
  skipInitialization: false
3162
- }), editor.registerNodeTransform(InstanceCodeNode, node => codeNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(lexical.TextNode, node => $textNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(InstanceCodeHighlightNode, node => $textNodeTransform(node, editor, tokenizer)), editor.registerCommand(lexical.KEY_TAB_COMMAND, event => {
3189
+ }), editor.registerNodeTransform(InstanceCodeNode, node => codeNodeTransform(node, null, tokenizer)), editor.registerNodeTransform(lexical.TextNode, node => $textNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(InstanceCodeHighlightNode, node => $textNodeTransform(node, editor, tokenizer)), editor.registerCommand(lexical.KEY_TAB_COMMAND, event => {
3163
3190
  const command = $handleTab(event.shiftKey);
3164
3191
  if (command === null) {
3165
3192
  return false;
@@ -22154,9 +22181,9 @@ class InstanceEquationNode extends lexical.DecoratorNode {
22154
22181
  return element;
22155
22182
  }
22156
22183
  exportDOM() {
22157
- const element = document.createElement('span');
22184
+ const element = document.createElement('equation');
22158
22185
  // Encode the equation as base64 to avoid issues with special characters
22159
- const equation = btoa(this.__equation);
22186
+ const equation = base64.toBase64UTF8(this.__equation);
22160
22187
  element.setAttribute('data-lexical-equation', equation);
22161
22188
  element.setAttribute('data-lexical-inline', `${this.__inline}`);
22162
22189
  katex.render(this.__equation, element, {
@@ -23550,6 +23577,7 @@ class InstanceListNode extends list.ListNode {
23550
23577
  createDOM(config) {
23551
23578
  const element = super.createDOM(config);
23552
23579
  setDisable(this, element);
23580
+ element.setAttribute('list-type', this.getListType());
23553
23581
  return element;
23554
23582
  }
23555
23583
  updateFromJSON(serializedNode) {
@@ -23810,7 +23838,28 @@ const InstancePlugin = props => {
23810
23838
  placeholder
23811
23839
  }), $registerInstanceHeadingNodeTransform(editor), $registerInstanceListItemInsertParagraph(editor), $registerNumberDecoratorNodeUpdate(editor), $registerNumberDecoratorDomUpdate(editor), $registerTableCommand(editor),
23812
23840
  // $selectionChange(editor, setSelectedInstance),
23813
- editor.registerCommand(lexical.DELETE_CHARACTER_COMMAND, event => {
23841
+ editor.registerCommand(lexical.SELECTION_CHANGE_COMMAND, () => {
23842
+ const selection = lexical.$getSelection();
23843
+ if (lexical.$isNodeSelection(selection)) {
23844
+ const [node] = selection.getNodes();
23845
+ if (lexical.$isDecoratorNode(node)) {
23846
+ $selectDecoratorNode(node);
23847
+ }
23848
+ }
23849
+ return false;
23850
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.CLICK_COMMAND, event => {
23851
+ if (event.target instanceof HTMLElement) {
23852
+ const decoratorRootEle = event.target.closest('[data-lexical-decorator="true"]');
23853
+ if (decoratorRootEle) {
23854
+ const key = decoratorRootEle.getAttribute('key');
23855
+ if (key) {
23856
+ const node = lexical.$getNodeByKey(key);
23857
+ $selectDecoratorNode(node);
23858
+ }
23859
+ }
23860
+ }
23861
+ return false;
23862
+ }, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.DELETE_CHARACTER_COMMAND, event => {
23814
23863
  const selection = lexical.$getSelection();
23815
23864
  if (selection) {
23816
23865
  return selection.getNodes().some(node => {
@@ -24173,15 +24222,30 @@ class InternalLinkNode extends lexical.TextDecoratorNode {
24173
24222
  super(key);
24174
24223
  this.__number = number;
24175
24224
  }
24225
+
24226
+ // get contentEditable() {
24227
+ // return 'true'
24228
+ // }
24229
+
24176
24230
  exportJSON() {
24177
24231
  return {
24178
24232
  ...super.exportJSON(),
24179
24233
  number: this.__number
24180
24234
  };
24181
24235
  }
24236
+ exportDOM(editor) {
24237
+ const element = document.createElement('section');
24238
+ element.setAttribute('internal-link', '');
24239
+ element.setAttribute('data-internal-link-number', this.__number);
24240
+ element.textContent = this.getTextContent();
24241
+ return {
24242
+ element
24243
+ };
24244
+ }
24182
24245
  createDOM(config, editor) {
24183
24246
  const span = super.createDOM(config, editor);
24184
24247
  span.setAttribute('ignoreusable', '');
24248
+ span.setAttribute('decorator', 'text');
24185
24249
  return span;
24186
24250
  }
24187
24251
  updateDOM(prevNode, dom, config) {
@@ -24193,6 +24257,16 @@ class InternalLinkNode extends lexical.TextDecoratorNode {
24193
24257
  isInline() {
24194
24258
  return true;
24195
24259
  }
24260
+ isSelected(selection) {
24261
+ return true;
24262
+ }
24263
+ getTextContent() {
24264
+ const insNode = $getInstanceNodeByNumber(this.__number);
24265
+ if (insNode) {
24266
+ return getLatestValue(insNode.__instance.value, 'insDesc') || '';
24267
+ }
24268
+ return '';
24269
+ }
24196
24270
  decorate(editor, config) {
24197
24271
  return /*#__PURE__*/jsxRuntime.jsx(InternalLinkComponent, {
24198
24272
  editor: editor,
@@ -24318,10 +24392,11 @@ function $isPageBreakNode(node) {
24318
24392
  *
24319
24393
  */
24320
24394
 
24321
- const ParametersComponent = ({
24395
+ const ParametersComponent = /*#__PURE__*/React.forwardRef(({
24322
24396
  nodeKey
24323
- }) => {
24397
+ }, ref) => {
24324
24398
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
24399
+ const spanRef = React.useRef(null);
24325
24400
  const [parameters, setParameters,, latestParameters] = hooks.useStore({
24326
24401
  number: '',
24327
24402
  value: ''
@@ -24353,10 +24428,20 @@ const ParametersComponent = ({
24353
24428
  return true;
24354
24429
  }, lexical.COMMAND_PRIORITY_EDITOR));
24355
24430
  }, []);
24431
+ React.useImperativeHandle(ref, () => {
24432
+ return {
24433
+ getValue() {
24434
+ return latestParameters.current.value;
24435
+ }
24436
+ };
24437
+ }, []);
24356
24438
  return /*#__PURE__*/jsxRuntime.jsx("span", {
24439
+ ref: spanRef,
24440
+ role: "button",
24441
+ tabIndex: 0,
24357
24442
  children: parameters.value
24358
24443
  });
24359
- };
24444
+ });
24360
24445
 
24361
24446
  /**
24362
24447
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -24371,6 +24456,8 @@ class ParametersNode extends lexical.TextDecoratorNode {
24371
24456
  static collection = new Map();
24372
24457
  /** 初始化值 */
24373
24458
 
24459
+ __ref = /*#__PURE__*/React.createRef();
24460
+
24374
24461
  /** 最新的值 */
24375
24462
  get parameters() {
24376
24463
  return ParametersNode.collection.get(this.__parameters.number) || this.__parameters;
@@ -24394,9 +24481,19 @@ class ParametersNode extends lexical.TextDecoratorNode {
24394
24481
  parameters: this.parameters
24395
24482
  };
24396
24483
  }
24484
+ exportDOM(editor) {
24485
+ const element = document.createElement('section');
24486
+ element.setAttribute('parameter', '');
24487
+ element.setAttribute('data-parameter', base64.toBase64UTF8(JSON.stringify(this.parameters)));
24488
+ element.textContent = this.parameters.value;
24489
+ return {
24490
+ element
24491
+ };
24492
+ }
24397
24493
  createDOM(config, editor) {
24398
24494
  const span = super.createDOM(config, editor);
24399
24495
  span.setAttribute('ignoreusable', '');
24496
+ span.setAttribute('key', this.getKey());
24400
24497
  return span;
24401
24498
  }
24402
24499
  updateDOM(prevNode, dom, config) {
@@ -24408,8 +24505,12 @@ class ParametersNode extends lexical.TextDecoratorNode {
24408
24505
  isInline() {
24409
24506
  return true;
24410
24507
  }
24508
+ getTextContent() {
24509
+ return this.__ref.current?.getValue() || '';
24510
+ }
24411
24511
  decorate(editor, config) {
24412
24512
  return /*#__PURE__*/jsxRuntime.jsx(ParametersComponent, {
24513
+ ref: this.__ref,
24413
24514
  nodeKey: this.getKey()
24414
24515
  });
24415
24516
  }
@@ -24421,10 +24522,6 @@ function $isParametersNode(node) {
24421
24522
  return node instanceof ParametersNode;
24422
24523
  }
24423
24524
 
24424
- // export function updateParameters(parameters: Parameters) {
24425
- // return ParametersNode.collection.set(parameters.number, parameters);
24426
- // }
24427
-
24428
24525
  /**
24429
24526
  * Copyright (c) Meta Platforms, Inc. and affiliates.
24430
24527
  *
@@ -25525,6 +25622,7 @@ exports.$nodeUpgrade = $nodeUpgrade;
25525
25622
  exports.$removeHighestEmptyListParent = $removeHighestEmptyListParent;
25526
25623
  exports.$removeList = $removeList;
25527
25624
  exports.$scrollTo = $scrollTo;
25625
+ exports.$selectDecoratorNode = $selectDecoratorNode;
25528
25626
  exports.$updateRichHistoryStateMap = $updateRichHistoryStateMap;
25529
25627
  exports.$updateRichInstanceContent = $updateRichInstanceContent;
25530
25628
  exports.$updateRichInstanceTitle = $updateRichInstanceTitle;
@@ -25567,8 +25665,10 @@ exports.PARAMETERS_UPDATE = PARAMETERS_UPDATE;
25567
25665
  exports.PageBreakNode = PageBreakNode;
25568
25666
  exports.ParametersNode = ParametersNode;
25569
25667
  exports.PlaceholderDecoratorNode = PlaceholderDecoratorNode;
25668
+ exports.PrismTokenizer = PrismTokenizer;
25570
25669
  exports.SPLIT_INSTANCE_NODE = SPLIT_INSTANCE_NODE;
25571
25670
  exports.clearCache = clearCache;
25671
+ exports.codeNodeTransform = codeNodeTransform;
25572
25672
  exports.correctedInstanceParagraph = correctedInstanceParagraph;
25573
25673
  exports.fixedAddress = fixedAddress;
25574
25674
  exports.getCachedClassNameArray = getCachedClassNameArray;
@@ -8,11 +8,11 @@
8
8
 
9
9
  import { $isCodeNode, CodeNode } from '@lexical/code';
10
10
  import { $findMatchingParent, addClassNamesToElement, mergeRegister, removeClassNamesFromElement, $getAdjacentCaret, isHTMLElement as isHTMLElement$1, IS_CHROME, $insertNodeToNearestRoot, $getNearestNodeOfType, $descendantsMatching } from '@lexical/utils';
11
- import { createCommand, ElementNode, $applyNodeReplacement, isHTMLElement, setNodeIndentFromDOM, DecoratorNode, $getEditor, $isTextNode, $createTextNode, TextNode as TextNode$1, $getSelection, $isRootOrShadowRoot, $isRootNode, $getNodeByKey, scrollIntoViewIfNeeded, $isElementNode, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, ParagraphNode, COMMAND_PRIORITY_EDITOR, $getSiblingCaret, $isTabNode, $createTabNode, $createLineBreakNode, KEY_TAB_COMMAND, COMMAND_PRIORITY_LOW, INSERT_TAB_COMMAND, $insertNodes, INDENT_CONTENT_COMMAND, OUTDENT_CONTENT_COMMAND, KEY_ARROW_UP_COMMAND, $isRangeSelection, KEY_ARROW_DOWN_COMMAND, MOVE_TO_START, MOVE_TO_END, $isLineBreakNode, $rewindSiblingCaret, $createParagraphNode, createEditor, RootNode, LineBreakNode, $isLeafNode, $setPointFromCaret, $normalizeCaret, $getChildCaret, INSERT_PARAGRAPH_COMMAND, COMMAND_PRIORITY_NORMAL, $getPreviousSelection, DELETE_CHARACTER_COMMAND, $setSelection, $createRangeSelection, exportNodeToJSON, TextDecoratorNode, COMMAND_PRIORITY_HIGH, CLICK_COMMAND, KEY_ESCAPE_COMMAND, $isNodeSelection, $createNodeSelection, DRAGSTART_COMMAND, KEY_ENTER_COMMAND } from 'lexical';
11
+ import { createCommand, ElementNode, $applyNodeReplacement, isHTMLElement, setNodeIndentFromDOM, DecoratorNode, $getEditor, $isTextNode, $createTextNode, TextNode as TextNode$1, $getSelection, $isRootOrShadowRoot, $isRootNode, $getNodeByKey, scrollIntoViewIfNeeded, $isElementNode, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, $createRangeSelection, $setSelection, ParagraphNode, COMMAND_PRIORITY_EDITOR, $getSiblingCaret, $isTabNode, $createTabNode, $createLineBreakNode, KEY_TAB_COMMAND, COMMAND_PRIORITY_LOW, INSERT_TAB_COMMAND, $insertNodes, INDENT_CONTENT_COMMAND, OUTDENT_CONTENT_COMMAND, KEY_ARROW_UP_COMMAND, $isRangeSelection, KEY_ARROW_DOWN_COMMAND, MOVE_TO_START, MOVE_TO_END, $isLineBreakNode, $rewindSiblingCaret, $createParagraphNode, createEditor, RootNode, LineBreakNode, $isLeafNode, $setPointFromCaret, $normalizeCaret, $getChildCaret, INSERT_PARAGRAPH_COMMAND, COMMAND_PRIORITY_NORMAL, $getPreviousSelection, $isNodeSelection, $isDecoratorNode, CLICK_COMMAND, DELETE_CHARACTER_COMMAND, exportNodeToJSON, TextDecoratorNode, COMMAND_PRIORITY_HIGH, KEY_ESCAPE_COMMAND, $createNodeSelection, DRAGSTART_COMMAND, KEY_ENTER_COMMAND } from 'lexical';
12
12
  import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';
13
13
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
14
14
  import * as React from 'react';
15
- import React__default, { useState, useCallback, useEffect, useMemo, useRef, Suspense } from 'react';
15
+ import React__default, { useState, useCallback, useEffect, useMemo, useRef, useImperativeHandle, Suspense } from 'react';
16
16
  import { jsxs, jsx, Fragment as Fragment$1 } from 'react/jsx-runtime';
17
17
  import { $isListNode, $isListItemNode, $createListItemNode, ListItemNode, ListNode } from '@lexical/list';
18
18
  import { TableNode, INSERT_TABLE_COMMAND, $findTableNode, PIXEL_VALUE_REG_EXP, $isTableRowNode, $createTableRowNode, $createTableCellNode, TableCellHeaderStates, $isTableSelection, $isTableCellNode } from '@lexical/table';
@@ -20,6 +20,7 @@ import { $textToRichNodes, getStorageSerializedString } from 'onchain-lexical-ma
20
20
  import { dfs as dfs$1 } from 'onchain-utility/traversal';
21
21
  import { $setBlocksType } from '@lexical/selection';
22
22
  import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
23
+ import { toBase64UTF8 } from 'onchain-utility/base64';
23
24
  import { useStore } from 'onchain-utility/hooks';
24
25
  import { HeadingNode, $isHeadingNode, $isQuoteNode, QuoteNode } from '@lexical/rich-text';
25
26
  import { useLexicalEditable } from '@lexical/react/useLexicalEditable';
@@ -1129,6 +1130,26 @@ function $addInstancesNode({
1129
1130
  }
1130
1131
  }
1131
1132
  }
1133
+ function $selectDecoratorNode(node) {
1134
+ if (node) {
1135
+ const [previous, next] = [node.getPreviousSibling(), node.getNextSibling()];
1136
+ const rangeSelection = $createRangeSelection();
1137
+ if (previous) {
1138
+ const isText = $isTextNode(previous);
1139
+ rangeSelection.anchor.set(isText ? previous.getKey() : node.getParent().getKey(), isText ? previous.getTextContentSize() : node.getPreviousSiblings().length, isText ? 'text' : 'element');
1140
+ } else {
1141
+ const parent = node.getParent();
1142
+ rangeSelection.anchor.set(parent.getKey(), 0, 'element');
1143
+ }
1144
+ if (next) {
1145
+ rangeSelection.focus.set(next.getKey(), 0, $isTextNode(next) ? 'text' : 'element');
1146
+ } else {
1147
+ const parent = node.getParent();
1148
+ rangeSelection.focus.set(parent.getKey(), node.getPreviousSiblings().length + 1, 'element');
1149
+ }
1150
+ $setSelection(rangeSelection);
1151
+ }
1152
+ }
1132
1153
 
1133
1154
  /**
1134
1155
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -2657,7 +2678,7 @@ function $textNodeTransform(node, editor, tokenizer) {
2657
2678
  // if node's parent is a code node and run highlighting if so
2658
2679
  const parentNode = node.getParent();
2659
2680
  if ($isInstanceCodeNode(parentNode)) {
2660
- codeNodeTransform(parentNode, editor, tokenizer);
2681
+ codeNodeTransform(parentNode, null, tokenizer);
2661
2682
  } else if ($isInstanceCodeHighlightNode(node)) {
2662
2683
  // When code block converted into paragraph or other element
2663
2684
  // code highlight nodes converted back to normal text
@@ -2697,9 +2718,9 @@ function updateCodeGutter(node, editor) {
2697
2718
  // Especially when pasting code into CodeBlock.
2698
2719
 
2699
2720
  const nodesCurrentlyHighlighting = new Set();
2700
- function codeNodeTransform(node, editor, tokenizer) {
2721
+ function codeNodeTransform(node, editor, tokenizer, isEnforcement) {
2701
2722
  const nodeKey = node.getKey();
2702
- if (nodesCurrentlyHighlighting.has(nodeKey)) {
2723
+ if (nodesCurrentlyHighlighting.has(nodeKey) && !isEnforcement) {
2703
2724
  return;
2704
2725
  }
2705
2726
  nodesCurrentlyHighlighting.add(nodeKey);
@@ -2712,7 +2733,8 @@ function codeNodeTransform(node, editor, tokenizer) {
2712
2733
  // Using nested update call to pass `skipTransforms` since we don't want
2713
2734
  // each individual InstanceCodeHighlightNode to be transformed again as it's already
2714
2735
  // in its final state
2715
- editor.update(() => {
2736
+ // eslint-disable-next-line @lexical/rules-of-lexical
2737
+ const transform = () => {
2716
2738
  $updateAndRetainSelection(nodeKey, () => {
2717
2739
  const currentNode = $getNodeByKey(nodeKey);
2718
2740
  if (!$isInstanceCodeNode(currentNode) || !currentNode.isAttached()) {
@@ -2733,12 +2755,17 @@ function codeNodeTransform(node, editor, tokenizer) {
2733
2755
  }
2734
2756
  return false;
2735
2757
  });
2736
- }, {
2737
- onUpdate: () => {
2738
- nodesCurrentlyHighlighting.delete(nodeKey);
2739
- },
2740
- skipTransforms: true
2741
- });
2758
+ };
2759
+ if (editor) {
2760
+ editor.update(transform, {
2761
+ onUpdate: () => {
2762
+ nodesCurrentlyHighlighting.delete(nodeKey);
2763
+ },
2764
+ skipTransforms: true
2765
+ });
2766
+ } else {
2767
+ transform();
2768
+ }
2742
2769
  }
2743
2770
  function $getHighlightNodes(tokens, type) {
2744
2771
  const nodes = [];
@@ -3145,7 +3172,7 @@ function registerCodeHighlighting(editor, tokenizer) {
3145
3172
  });
3146
3173
  }, {
3147
3174
  skipInitialization: false
3148
- }), editor.registerNodeTransform(InstanceCodeNode, node => codeNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(TextNode$1, node => $textNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(InstanceCodeHighlightNode, node => $textNodeTransform(node, editor, tokenizer)), editor.registerCommand(KEY_TAB_COMMAND, event => {
3175
+ }), editor.registerNodeTransform(InstanceCodeNode, node => codeNodeTransform(node, null, tokenizer)), editor.registerNodeTransform(TextNode$1, node => $textNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(InstanceCodeHighlightNode, node => $textNodeTransform(node, editor, tokenizer)), editor.registerCommand(KEY_TAB_COMMAND, event => {
3149
3176
  const command = $handleTab(event.shiftKey);
3150
3177
  if (command === null) {
3151
3178
  return false;
@@ -22140,9 +22167,9 @@ class InstanceEquationNode extends DecoratorNode {
22140
22167
  return element;
22141
22168
  }
22142
22169
  exportDOM() {
22143
- const element = document.createElement('span');
22170
+ const element = document.createElement('equation');
22144
22171
  // Encode the equation as base64 to avoid issues with special characters
22145
- const equation = btoa(this.__equation);
22172
+ const equation = toBase64UTF8(this.__equation);
22146
22173
  element.setAttribute('data-lexical-equation', equation);
22147
22174
  element.setAttribute('data-lexical-inline', `${this.__inline}`);
22148
22175
  katex.render(this.__equation, element, {
@@ -23536,6 +23563,7 @@ class InstanceListNode extends ListNode {
23536
23563
  createDOM(config) {
23537
23564
  const element = super.createDOM(config);
23538
23565
  setDisable(this, element);
23566
+ element.setAttribute('list-type', this.getListType());
23539
23567
  return element;
23540
23568
  }
23541
23569
  updateFromJSON(serializedNode) {
@@ -23796,7 +23824,28 @@ const InstancePlugin = props => {
23796
23824
  placeholder
23797
23825
  }), $registerInstanceHeadingNodeTransform(editor), $registerInstanceListItemInsertParagraph(editor), $registerNumberDecoratorNodeUpdate(editor), $registerNumberDecoratorDomUpdate(editor), $registerTableCommand(editor),
23798
23826
  // $selectionChange(editor, setSelectedInstance),
23799
- editor.registerCommand(DELETE_CHARACTER_COMMAND, event => {
23827
+ editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
23828
+ const selection = $getSelection();
23829
+ if ($isNodeSelection(selection)) {
23830
+ const [node] = selection.getNodes();
23831
+ if ($isDecoratorNode(node)) {
23832
+ $selectDecoratorNode(node);
23833
+ }
23834
+ }
23835
+ return false;
23836
+ }, COMMAND_PRIORITY_CRITICAL), editor.registerCommand(CLICK_COMMAND, event => {
23837
+ if (event.target instanceof HTMLElement) {
23838
+ const decoratorRootEle = event.target.closest('[data-lexical-decorator="true"]');
23839
+ if (decoratorRootEle) {
23840
+ const key = decoratorRootEle.getAttribute('key');
23841
+ if (key) {
23842
+ const node = $getNodeByKey(key);
23843
+ $selectDecoratorNode(node);
23844
+ }
23845
+ }
23846
+ }
23847
+ return false;
23848
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(DELETE_CHARACTER_COMMAND, event => {
23800
23849
  const selection = $getSelection();
23801
23850
  if (selection) {
23802
23851
  return selection.getNodes().some(node => {
@@ -24159,15 +24208,30 @@ class InternalLinkNode extends TextDecoratorNode {
24159
24208
  super(key);
24160
24209
  this.__number = number;
24161
24210
  }
24211
+
24212
+ // get contentEditable() {
24213
+ // return 'true'
24214
+ // }
24215
+
24162
24216
  exportJSON() {
24163
24217
  return {
24164
24218
  ...super.exportJSON(),
24165
24219
  number: this.__number
24166
24220
  };
24167
24221
  }
24222
+ exportDOM(editor) {
24223
+ const element = document.createElement('section');
24224
+ element.setAttribute('internal-link', '');
24225
+ element.setAttribute('data-internal-link-number', this.__number);
24226
+ element.textContent = this.getTextContent();
24227
+ return {
24228
+ element
24229
+ };
24230
+ }
24168
24231
  createDOM(config, editor) {
24169
24232
  const span = super.createDOM(config, editor);
24170
24233
  span.setAttribute('ignoreusable', '');
24234
+ span.setAttribute('decorator', 'text');
24171
24235
  return span;
24172
24236
  }
24173
24237
  updateDOM(prevNode, dom, config) {
@@ -24179,6 +24243,16 @@ class InternalLinkNode extends TextDecoratorNode {
24179
24243
  isInline() {
24180
24244
  return true;
24181
24245
  }
24246
+ isSelected(selection) {
24247
+ return true;
24248
+ }
24249
+ getTextContent() {
24250
+ const insNode = $getInstanceNodeByNumber(this.__number);
24251
+ if (insNode) {
24252
+ return getLatestValue(insNode.__instance.value, 'insDesc') || '';
24253
+ }
24254
+ return '';
24255
+ }
24182
24256
  decorate(editor, config) {
24183
24257
  return /*#__PURE__*/jsx(InternalLinkComponent, {
24184
24258
  editor: editor,
@@ -24304,10 +24378,11 @@ function $isPageBreakNode(node) {
24304
24378
  *
24305
24379
  */
24306
24380
 
24307
- const ParametersComponent = ({
24381
+ const ParametersComponent = /*#__PURE__*/React__default.forwardRef(({
24308
24382
  nodeKey
24309
- }) => {
24383
+ }, ref) => {
24310
24384
  const [editor] = useLexicalComposerContext();
24385
+ const spanRef = useRef(null);
24311
24386
  const [parameters, setParameters,, latestParameters] = useStore({
24312
24387
  number: '',
24313
24388
  value: ''
@@ -24339,10 +24414,20 @@ const ParametersComponent = ({
24339
24414
  return true;
24340
24415
  }, COMMAND_PRIORITY_EDITOR));
24341
24416
  }, []);
24417
+ useImperativeHandle(ref, () => {
24418
+ return {
24419
+ getValue() {
24420
+ return latestParameters.current.value;
24421
+ }
24422
+ };
24423
+ }, []);
24342
24424
  return /*#__PURE__*/jsx("span", {
24425
+ ref: spanRef,
24426
+ role: "button",
24427
+ tabIndex: 0,
24343
24428
  children: parameters.value
24344
24429
  });
24345
- };
24430
+ });
24346
24431
 
24347
24432
  /**
24348
24433
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -24357,6 +24442,8 @@ class ParametersNode extends TextDecoratorNode {
24357
24442
  static collection = new Map();
24358
24443
  /** 初始化值 */
24359
24444
 
24445
+ __ref = /*#__PURE__*/React__default.createRef();
24446
+
24360
24447
  /** 最新的值 */
24361
24448
  get parameters() {
24362
24449
  return ParametersNode.collection.get(this.__parameters.number) || this.__parameters;
@@ -24380,9 +24467,19 @@ class ParametersNode extends TextDecoratorNode {
24380
24467
  parameters: this.parameters
24381
24468
  };
24382
24469
  }
24470
+ exportDOM(editor) {
24471
+ const element = document.createElement('section');
24472
+ element.setAttribute('parameter', '');
24473
+ element.setAttribute('data-parameter', toBase64UTF8(JSON.stringify(this.parameters)));
24474
+ element.textContent = this.parameters.value;
24475
+ return {
24476
+ element
24477
+ };
24478
+ }
24383
24479
  createDOM(config, editor) {
24384
24480
  const span = super.createDOM(config, editor);
24385
24481
  span.setAttribute('ignoreusable', '');
24482
+ span.setAttribute('key', this.getKey());
24386
24483
  return span;
24387
24484
  }
24388
24485
  updateDOM(prevNode, dom, config) {
@@ -24394,8 +24491,12 @@ class ParametersNode extends TextDecoratorNode {
24394
24491
  isInline() {
24395
24492
  return true;
24396
24493
  }
24494
+ getTextContent() {
24495
+ return this.__ref.current?.getValue() || '';
24496
+ }
24397
24497
  decorate(editor, config) {
24398
24498
  return /*#__PURE__*/jsx(ParametersComponent, {
24499
+ ref: this.__ref,
24399
24500
  nodeKey: this.getKey()
24400
24501
  });
24401
24502
  }
@@ -24407,10 +24508,6 @@ function $isParametersNode(node) {
24407
24508
  return node instanceof ParametersNode;
24408
24509
  }
24409
24510
 
24410
- // export function updateParameters(parameters: Parameters) {
24411
- // return ParametersNode.collection.set(parameters.number, parameters);
24412
- // }
24413
-
24414
24511
  /**
24415
24512
  * Copyright (c) Meta Platforms, Inc. and affiliates.
24416
24513
  *
@@ -25434,4 +25531,4 @@ var InlineImageComponent$1 = {
25434
25531
  default: InlineImageComponent
25435
25532
  };
25436
25533
 
25437
- export { $addInstancesNode, $createBarDecoratorNode, $createCollapsibleContainerNode, $createCollapsibleContentNode, $createCollapsibleTitleNode, $createFragmentNode, $createImageNode, $createInlineImageNode, $createInstanceCodeHighlightNode, $createInstanceCodeNode, $createInstanceEquationNode, $createInstanceHeadingNode, $createInstanceHorizontalRuleNode, $createInstanceListItemNode, $createInstanceListNode, $createInstanceNode, $createInstanceParagraphNode, $createInstanceQuoteNode, $createInstanceTableNode, $createInstanceTitleNode, $createInternalLinkNode, $createKeywordNode, $createNumberDecoratorNode, $createPageBreakNode, $createParametersNode, $createPlaceholderDecoratorNode, $createTitleOnlyInstanceNode, $findNearestListItemNode, $getAllListItems, $getAnchorRootNode, $getInstanceNodeByChild, $getInstanceNodeByNumber, $getInstanceNodeKeyByNumber, $getListDepth, $getTitleNodeByChild, $getTopListNode, $handleIndent, $handleListInsertParagraph, $handleOutdent, $insertInstanceList, $isBarDecoratorNode, $isCollapsibleContainerNode, $isCollapsibleContentNode, $isCollapsibleTitleNode, $isEmptyInstanceParagraphNode, $isEmptyParagraphNode, $isImageNode, $isInInstanceTitleNode, $isInlineImageNode, $isInstanceCodeHighlightNode, $isInstanceCodeNode, $isInstanceEquationNode, $isInstanceHeadingNode, $isInstanceHorizontalRuleNode, $isInstanceListItemNode, $isInstanceListNode, $isInstanceNode, $isInstanceParagraphFormalNode, $isInstanceParagraphNode, $isInstanceQuoteNode, $isInstanceTableNode, $isInstanceTitleNode, $isInternalLinkNode, $isKeywordNode, $isLastItemInList, $isNumberDecoratorNode, $isPageBreakNode, $isParametersNode, $isPlaceholderDecoratorNode, $isRemoved, $isSelectedTitleNode, $isTextTypeNode, $nodeDowngrade, $nodeUpgrade, $removeHighestEmptyListParent, $removeList, $scrollTo, $updateRichHistoryStateMap, $updateRichInstanceContent, $updateRichInstanceTitle, $wrapInListItem, ADD_COMMENT, ADD_NEW_INSTANCE_NODE, BarDecoratorNode, COMPONENT_UPDATE, CollapsibleContainerNode, CollapsibleContentNode, CollapsibleTitleNode, DELETE_INSTANCE_NODE, DisableSelector, Fragment, INSERT_COLLAPSIBLE_COMMAND, INSERT_INS_HORIZONTAL_RULE_COMMAND, INSERT_PARAMETERS, INSTANCE_TITLE_UPDATE, ImageNode, InlineImageNode, InstanceCodeHighlightNode, InstanceCodeNode, InstanceEquationNode, InstanceHeadingNode, InstanceHorizontalRuleNode, InstanceListItemNode, InstanceListNode, InstanceNode, InstanceParagraphNode, InstanceParagraphType, InstancePlugin, InstanceQuoteNode, InstanceTableNode, InstanceTitleNode, InternalLinkNode, KeywordNode, NumberDecoratorNode, OPEN_CREATE_WINDOW, PARAMETERS_UPDATE, PageBreakNode, ParametersNode, PlaceholderDecoratorNode, SPLIT_INSTANCE_NODE, clearCache, correctedInstanceParagraph, fixedAddress, getCachedClassNameArray, getCodeLanguages, getDefaultCodeLanguage, getInstanceAttrValue, getInstanceBaseInfo, getLanguageFriendlyName, getLatestValue, getTemporaryContentText, instanceNodeMap, internalLinkNameUpdateMap, isCompleteInstance, isNestedListNode, mergeLists, mergeNextSiblingListIfSameType, nodeMoveDown, nodeMoveUp, normalizeCodeLang, numberNodeKey, paragraphSymbol, registerCodeHighlighting, setDisable, setInstanceAttrValue, setTemporaryContentText, updateChildrenListItemValue, updateRelatedInternalLink, useContentEditable };
25534
+ export { $addInstancesNode, $createBarDecoratorNode, $createCollapsibleContainerNode, $createCollapsibleContentNode, $createCollapsibleTitleNode, $createFragmentNode, $createImageNode, $createInlineImageNode, $createInstanceCodeHighlightNode, $createInstanceCodeNode, $createInstanceEquationNode, $createInstanceHeadingNode, $createInstanceHorizontalRuleNode, $createInstanceListItemNode, $createInstanceListNode, $createInstanceNode, $createInstanceParagraphNode, $createInstanceQuoteNode, $createInstanceTableNode, $createInstanceTitleNode, $createInternalLinkNode, $createKeywordNode, $createNumberDecoratorNode, $createPageBreakNode, $createParametersNode, $createPlaceholderDecoratorNode, $createTitleOnlyInstanceNode, $findNearestListItemNode, $getAllListItems, $getAnchorRootNode, $getInstanceNodeByChild, $getInstanceNodeByNumber, $getInstanceNodeKeyByNumber, $getListDepth, $getTitleNodeByChild, $getTopListNode, $handleIndent, $handleListInsertParagraph, $handleOutdent, $insertInstanceList, $isBarDecoratorNode, $isCollapsibleContainerNode, $isCollapsibleContentNode, $isCollapsibleTitleNode, $isEmptyInstanceParagraphNode, $isEmptyParagraphNode, $isImageNode, $isInInstanceTitleNode, $isInlineImageNode, $isInstanceCodeHighlightNode, $isInstanceCodeNode, $isInstanceEquationNode, $isInstanceHeadingNode, $isInstanceHorizontalRuleNode, $isInstanceListItemNode, $isInstanceListNode, $isInstanceNode, $isInstanceParagraphFormalNode, $isInstanceParagraphNode, $isInstanceQuoteNode, $isInstanceTableNode, $isInstanceTitleNode, $isInternalLinkNode, $isKeywordNode, $isLastItemInList, $isNumberDecoratorNode, $isPageBreakNode, $isParametersNode, $isPlaceholderDecoratorNode, $isRemoved, $isSelectedTitleNode, $isTextTypeNode, $nodeDowngrade, $nodeUpgrade, $removeHighestEmptyListParent, $removeList, $scrollTo, $selectDecoratorNode, $updateRichHistoryStateMap, $updateRichInstanceContent, $updateRichInstanceTitle, $wrapInListItem, ADD_COMMENT, ADD_NEW_INSTANCE_NODE, BarDecoratorNode, COMPONENT_UPDATE, CollapsibleContainerNode, CollapsibleContentNode, CollapsibleTitleNode, DELETE_INSTANCE_NODE, DisableSelector, Fragment, INSERT_COLLAPSIBLE_COMMAND, INSERT_INS_HORIZONTAL_RULE_COMMAND, INSERT_PARAMETERS, INSTANCE_TITLE_UPDATE, ImageNode, InlineImageNode, InstanceCodeHighlightNode, InstanceCodeNode, InstanceEquationNode, InstanceHeadingNode, InstanceHorizontalRuleNode, InstanceListItemNode, InstanceListNode, InstanceNode, InstanceParagraphNode, InstanceParagraphType, InstancePlugin, InstanceQuoteNode, InstanceTableNode, InstanceTitleNode, InternalLinkNode, KeywordNode, NumberDecoratorNode, OPEN_CREATE_WINDOW, PARAMETERS_UPDATE, PageBreakNode, ParametersNode, PlaceholderDecoratorNode, PrismTokenizer, SPLIT_INSTANCE_NODE, clearCache, codeNodeTransform, correctedInstanceParagraph, fixedAddress, getCachedClassNameArray, getCodeLanguages, getDefaultCodeLanguage, getInstanceAttrValue, getInstanceBaseInfo, getLanguageFriendlyName, getLatestValue, getTemporaryContentText, instanceNodeMap, internalLinkNameUpdateMap, isCompleteInstance, isNestedListNode, mergeLists, mergeNextSiblingListIfSameType, nodeMoveDown, nodeMoveUp, normalizeCodeLang, numberNodeKey, paragraphSymbol, registerCodeHighlighting, setDisable, setInstanceAttrValue, setTemporaryContentText, updateChildrenListItemValue, updateRelatedInternalLink, useContentEditable };
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "instance"
8
8
  ],
9
9
  "license": "MIT",
10
- "version": "0.0.13",
10
+ "version": "0.0.15",
11
11
  "types": "index.d.ts",
12
12
  "files": [
13
13
  "dist",
@@ -23,10 +23,10 @@
23
23
  "@lexical/table": "^0.30.0",
24
24
  "@lexical/utils": "^0.30.0",
25
25
  "lexical": "0.30.0",
26
- "onchain-lexical-context": "^0.0.12",
27
- "onchain-lexical-markdown": "^0.0.12",
28
- "onchain-lexical-ui": "^0.0.12",
29
- "onchain-utility": "^0.0.10"
26
+ "onchain-lexical-context": "^0.0.13",
27
+ "onchain-lexical-markdown": "^0.0.14",
28
+ "onchain-lexical-ui": "^0.0.13",
29
+ "onchain-utility": "^0.0.11"
30
30
  },
31
31
  "sideEffects": false,
32
32
  "exports": {
@@ -212,7 +212,7 @@ function $textNodeTransform(
212
212
  // if node's parent is a code node and run highlighting if so
213
213
  const parentNode = node.getParent();
214
214
  if ($isInstanceCodeNode(parentNode)) {
215
- codeNodeTransform(parentNode, editor, tokenizer);
215
+ codeNodeTransform(parentNode, null, tokenizer);
216
216
  } else if ($isInstanceCodeHighlightNode(node)) {
217
217
  // When code block converted into paragraph or other element
218
218
  // code highlight nodes converted back to normal text
@@ -254,14 +254,14 @@ function updateCodeGutter(node: InstanceCodeNode, editor: LexicalEditor): void {
254
254
 
255
255
  const nodesCurrentlyHighlighting = new Set();
256
256
 
257
- function codeNodeTransform(
257
+ export function codeNodeTransform(
258
258
  node: InstanceCodeNode,
259
- editor: LexicalEditor,
259
+ editor: LexicalEditor | null,
260
260
  tokenizer: Tokenizer,
261
+ isEnforcement?: boolean
261
262
  ) {
262
263
  const nodeKey = node.getKey();
263
-
264
- if (nodesCurrentlyHighlighting.has(nodeKey)) {
264
+ if (nodesCurrentlyHighlighting.has(nodeKey) && !isEnforcement) {
265
265
  return;
266
266
  }
267
267
 
@@ -275,42 +275,48 @@ function codeNodeTransform(
275
275
  // Using nested update call to pass `skipTransforms` since we don't want
276
276
  // each individual InstanceCodeHighlightNode to be transformed again as it's already
277
277
  // in its final state
278
- editor.update(
279
- () => {
280
- $updateAndRetainSelection(nodeKey, () => {
281
- const currentNode = $getNodeByKey(nodeKey);
278
+ // eslint-disable-next-line @lexical/rules-of-lexical
279
+ const transform = () => {
280
+ $updateAndRetainSelection(nodeKey, () => {
281
+ const currentNode = $getNodeByKey(nodeKey);
282
282
 
283
- if (!$isInstanceCodeNode(currentNode) || !currentNode.isAttached()) {
284
- return false;
285
- }
283
+ if (!$isInstanceCodeNode(currentNode) || !currentNode.isAttached()) {
284
+ return false;
285
+ }
286
286
 
287
- const code = currentNode.getTextContent();
288
- const tokens = tokenizer.tokenize(
289
- code,
290
- currentNode.getLanguage() || tokenizer.defaultLanguage,
291
- );
292
- const highlightNodes = $getHighlightNodes(tokens);
293
- const diffRange = getDiffRange(
294
- currentNode.getChildren(),
295
- highlightNodes,
296
- );
297
- const {from, to, nodesForReplacement} = diffRange;
298
-
299
- if (from !== to || nodesForReplacement.length) {
300
- node.splice(from, to - from, nodesForReplacement);
301
- return true;
302
- }
287
+ const code = currentNode.getTextContent();
288
+ const tokens = tokenizer.tokenize(
289
+ code,
290
+ currentNode.getLanguage() || tokenizer.defaultLanguage,
291
+ );
292
+ const highlightNodes = $getHighlightNodes(tokens);
293
+ const diffRange = getDiffRange(
294
+ currentNode.getChildren(),
295
+ highlightNodes,
296
+ );
297
+ const {from, to, nodesForReplacement} = diffRange;
303
298
 
304
- return false;
305
- });
306
- },
307
- {
308
- onUpdate: () => {
309
- nodesCurrentlyHighlighting.delete(nodeKey);
299
+ if (from !== to || nodesForReplacement.length) {
300
+ node.splice(from, to - from, nodesForReplacement);
301
+ return true;
302
+ }
303
+
304
+ return false;
305
+ });
306
+ };
307
+ if (editor) {
308
+ editor.update(transform,
309
+ {
310
+ onUpdate: () => {
311
+ nodesCurrentlyHighlighting.delete(nodeKey);
312
+ },
313
+ skipTransforms: true,
310
314
  },
311
- skipTransforms: true,
312
- },
313
- );
315
+ );
316
+ } else {
317
+ transform();
318
+ }
319
+
314
320
  }
315
321
 
316
322
  function $getHighlightNodes(
@@ -842,7 +848,7 @@ export function registerCodeHighlighting(
842
848
  {skipInitialization: false},
843
849
  ),
844
850
  editor.registerNodeTransform(InstanceCodeNode, (node) =>
845
- codeNodeTransform(node, editor, tokenizer as Tokenizer),
851
+ codeNodeTransform(node, null, tokenizer as Tokenizer),
846
852
  ),
847
853
  editor.registerNodeTransform(TextNode, (node) =>
848
854
  $textNodeTransform(node, editor, tokenizer as Tokenizer),
@@ -22,7 +22,7 @@ import {
22
22
  $createCollapsibleTitleNode,
23
23
  $isCollapsibleTitleNode,
24
24
  CollapsibleTitleNode,
25
- } from './titleNode';
25
+ } from './title';
26
26
 
27
27
  const INSERT_COLLAPSIBLE_COMMAND = createCommand<void>(
28
28
  'INSERT_COLLAPSIBLE_COMMAND',
@@ -19,6 +19,7 @@ import type {JSX} from 'react';
19
19
 
20
20
  import katex from 'katex';
21
21
  import {$applyNodeReplacement, DecoratorNode, DOMExportOutput} from 'lexical';
22
+ import { toBase64UTF8 } from 'onchain-utility/base64';
22
23
  import * as React from 'react';
23
24
 
24
25
  const EquationComponent = React.lazy(() => import('./EquationComponent'));
@@ -89,9 +90,9 @@ export class InstanceEquationNode extends DecoratorNode<JSX.Element> {
89
90
  }
90
91
 
91
92
  exportDOM(): DOMExportOutput {
92
- const element = document.createElement('span');
93
+ const element = document.createElement('equation');
93
94
  // Encode the equation as base64 to avoid issues with special characters
94
- const equation = btoa(this.__equation);
95
+ const equation = toBase64UTF8(this.__equation);
95
96
  element.setAttribute('data-lexical-equation', equation);
96
97
  element.setAttribute('data-lexical-inline', `${this.__inline}`);
97
98
  katex.render(this.__equation, element, {
package/src/index.ts CHANGED
@@ -21,7 +21,7 @@ export {
21
21
  $isInstanceCodeNode,
22
22
  InstanceCodeNode,
23
23
  } from './code';
24
- export {registerCodeHighlighting} from './code/codeHighlighter';
24
+ export {codeNodeTransform, PrismTokenizer,registerCodeHighlighting} from './code/codeHighlighter';
25
25
  export {
26
26
  $createInstanceCodeHighlightNode,
27
27
  $isInstanceCodeHighlightNode,
@@ -21,9 +21,12 @@ import {
21
21
  $createTextNode,
22
22
  $getNodeByKey,
23
23
  $getSelection,
24
+ $isDecoratorNode,
24
25
  $isElementNode,
26
+ $isNodeSelection,
25
27
  $isRangeSelection,
26
28
  $setSelection,
29
+ CLICK_COMMAND,
27
30
  COMMAND_PRIORITY_CRITICAL,
28
31
  COMMAND_PRIORITY_LOW,
29
32
  DELETE_CHARACTER_COMMAND,
@@ -31,6 +34,7 @@ import {
31
34
  exportNodeToJSON,
32
35
  INSERT_PARAGRAPH_COMMAND,
33
36
  LexicalNode,
37
+ SELECTION_CHANGE_COMMAND,
34
38
  SerializedLexicalNode,
35
39
  } from 'lexical';
36
40
  import {getStorageSerializedString} from 'onchain-lexical-markdown';
@@ -59,12 +63,18 @@ import {
59
63
  $registerInstanceParagraphNodeTransform,
60
64
  } from './paragraph';
61
65
  import {$registerInstanceHeadingNodeTransform} from './paragraph/title';
66
+ import {ParametersNode} from './parameters';
62
67
  import {
63
68
  $createInstanceTableNode,
64
69
  $isInstanceTableNode,
65
70
  $registerTableCommand,
66
71
  } from './table';
67
- import {$addInstancesNode, clearCache, setTemporaryContentText} from './utils';
72
+ import {
73
+ $addInstancesNode,
74
+ $selectDecoratorNode,
75
+ clearCache,
76
+ setTemporaryContentText,
77
+ } from './utils';
68
78
 
69
79
  export const InstancePlugin: React.FC<PluginProps> = (props) => {
70
80
  const {placeholder} = props;
@@ -79,6 +89,39 @@ export const InstancePlugin: React.FC<PluginProps> = (props) => {
79
89
  $registerNumberDecoratorDomUpdate(editor),
80
90
  $registerTableCommand(editor),
81
91
  // $selectionChange(editor, setSelectedInstance),
92
+ editor.registerCommand(
93
+ SELECTION_CHANGE_COMMAND,
94
+ () => {
95
+ const selection = $getSelection();
96
+ if ($isNodeSelection(selection)) {
97
+ const [node] = selection.getNodes();
98
+ if ($isDecoratorNode(node)) {
99
+ $selectDecoratorNode(node);
100
+ }
101
+ }
102
+ return false;
103
+ },
104
+ COMMAND_PRIORITY_CRITICAL,
105
+ ),
106
+ editor.registerCommand(
107
+ CLICK_COMMAND,
108
+ (event: MouseEvent) => {
109
+ if (event.target instanceof HTMLElement) {
110
+ const decoratorRootEle = event.target.closest(
111
+ '[data-lexical-decorator="true"]',
112
+ );
113
+ if (decoratorRootEle) {
114
+ const key = decoratorRootEle.getAttribute('key');
115
+ if (key) {
116
+ const node = $getNodeByKey<ParametersNode>(key);
117
+ $selectDecoratorNode(node);
118
+ }
119
+ }
120
+ }
121
+ return false;
122
+ },
123
+ COMMAND_PRIORITY_LOW,
124
+ ),
82
125
  editor.registerCommand(
83
126
  DELETE_CHARACTER_COMMAND,
84
127
  (event) => {
@@ -8,14 +8,18 @@
8
8
 
9
9
  import {
10
10
  $applyNodeReplacement,
11
+ BaseSelection,
12
+ DOMExportOutput,
11
13
  EditorConfig,
12
14
  LexicalEditor,
15
+ LexicalNode,
13
16
  SerializedTextDecoratorNode,
14
17
  Spread,
15
18
  TextDecoratorNode,
16
19
  } from 'lexical';
17
20
  import React from 'react';
18
21
 
22
+ import {$getInstanceNodeByNumber, getLatestValue} from '../utils';
19
23
  import InternalLinkComponent from './internalLinkComponent';
20
24
 
21
25
  export type SerializedInternalNode = Spread<
@@ -45,6 +49,10 @@ export class InternalLinkNode extends TextDecoratorNode<React.ReactNode> {
45
49
  this.__number = number;
46
50
  }
47
51
 
52
+ // get contentEditable() {
53
+ // return 'true'
54
+ // }
55
+
48
56
  exportJSON(): SerializedInternalNode {
49
57
  return {
50
58
  ...super.exportJSON(),
@@ -52,9 +60,18 @@ export class InternalLinkNode extends TextDecoratorNode<React.ReactNode> {
52
60
  };
53
61
  }
54
62
 
63
+ exportDOM(editor: LexicalEditor): DOMExportOutput {
64
+ const element = document.createElement('section');
65
+ element.setAttribute('internal-link', '');
66
+ element.setAttribute('data-internal-link-number', this.__number);
67
+ element.textContent = this.getTextContent();
68
+ return {element};
69
+ }
70
+
55
71
  createDOM(config: EditorConfig, editor?: LexicalEditor): HTMLElement {
56
72
  const span = super.createDOM(config, editor);
57
73
  span.setAttribute('ignoreusable', '');
74
+ span.setAttribute('decorator', 'text');
58
75
  return span;
59
76
  }
60
77
 
@@ -70,6 +87,18 @@ export class InternalLinkNode extends TextDecoratorNode<React.ReactNode> {
70
87
  return true;
71
88
  }
72
89
 
90
+ isSelected(selection?: null | BaseSelection): boolean {
91
+ return true;
92
+ }
93
+
94
+ getTextContent(): string {
95
+ const insNode = $getInstanceNodeByNumber(this.__number);
96
+ if (insNode) {
97
+ return getLatestValue(insNode.__instance.value, 'insDesc') || '';
98
+ }
99
+ return '';
100
+ }
101
+
73
102
  decorate(editor: LexicalEditor, config: EditorConfig): JSX.Element {
74
103
  return (
75
104
  <InternalLinkComponent
@@ -88,7 +117,7 @@ export function $createInternalLinkNode(number: string): InternalLinkNode {
88
117
  }
89
118
 
90
119
  export function $isInternalLinkNode(
91
- node: InternalLinkNode | null | undefined,
120
+ node: LexicalNode | null | undefined,
92
121
  ): node is InternalLinkNode {
93
122
  return node instanceof InternalLinkNode;
94
123
  }
package/src/list/index.ts CHANGED
@@ -82,6 +82,7 @@ export class InstanceListNode extends ListNode {
82
82
  createDOM(config: EditorConfig): HTMLElement {
83
83
  const element = super.createDOM(config);
84
84
  setDisable(this, element);
85
+ element.setAttribute('list-type', this.getListType());
85
86
  return element;
86
87
  }
87
88
 
@@ -8,16 +8,22 @@
8
8
 
9
9
  import {
10
10
  $applyNodeReplacement,
11
+ DOMConversionMap,
12
+ DOMExportOutput,
11
13
  EditorConfig,
12
14
  LexicalEditor,
13
15
  LexicalNode,
14
16
  SerializedTextDecoratorNode,
17
+ SerializedTextNode,
15
18
  Spread,
16
19
  TextDecoratorNode,
20
+ TextNode,
17
21
  } from 'lexical';
22
+ import {toBase64UTF8} from 'onchain-utility/base64';
18
23
  import React from 'react';
19
24
 
20
25
  import ParametersComponent from './parametersComponent';
26
+ import {ParametersRef} from './types';
21
27
 
22
28
  export interface Parameters {
23
29
  value: string;
@@ -38,6 +44,8 @@ export class ParametersNode extends TextDecoratorNode<React.ReactNode> {
38
44
  /** 初始化值 */
39
45
  __parameters: Parameters;
40
46
 
47
+ __ref = React.createRef<ParametersRef>();
48
+
41
49
  /** 最新的值 */
42
50
  get parameters() {
43
51
  return (
@@ -71,10 +79,18 @@ export class ParametersNode extends TextDecoratorNode<React.ReactNode> {
71
79
  parameters: this.parameters,
72
80
  };
73
81
  }
82
+ exportDOM(editor: LexicalEditor): DOMExportOutput {
83
+ const element = document.createElement('section');
84
+ element.setAttribute('parameter', '');
85
+ element.setAttribute('data-parameter', toBase64UTF8(JSON.stringify(this.parameters)));
86
+ element.textContent = this.parameters.value;
87
+ return {element};
88
+ }
74
89
 
75
90
  createDOM(config: EditorConfig, editor?: LexicalEditor): HTMLElement {
76
91
  const span = super.createDOM(config, editor);
77
92
  span.setAttribute('ignoreusable', '');
93
+ span.setAttribute('key', this.getKey());
78
94
  return span;
79
95
  }
80
96
 
@@ -90,8 +106,12 @@ export class ParametersNode extends TextDecoratorNode<React.ReactNode> {
90
106
  return true;
91
107
  }
92
108
 
109
+ getTextContent(): string {
110
+ return this.__ref.current?.getValue() || '';
111
+ }
112
+
93
113
  decorate(editor: LexicalEditor, config: EditorConfig): JSX.Element {
94
- return <ParametersComponent nodeKey={this.getKey()} />;
114
+ return <ParametersComponent ref={this.__ref} nodeKey={this.getKey()} />;
95
115
  }
96
116
  }
97
117
 
@@ -108,3 +128,30 @@ export function $isParametersNode(
108
128
  // export function updateParameters(parameters: Parameters) {
109
129
  // return ParametersNode.collection.set(parameters.number, parameters);
110
130
  // }
131
+
132
+ class TestNode extends TextNode {
133
+ static getType(): string {
134
+ return 'Parameters';
135
+ }
136
+ static clone(node: TestNode): TestNode {
137
+ return new TestNode(node.__text, node.__key);
138
+ }
139
+
140
+ static importDOM(): DOMConversionMap | null {
141
+ return TextNode.importDOM();
142
+ }
143
+
144
+ static importJSON(serializedNode: SerializedTextNode): TextNode {
145
+ return $createTestNode().updateFromJSON(serializedNode);
146
+ }
147
+ }
148
+
149
+ export function $createTestNode(text = ''): TestNode {
150
+ return $applyNodeReplacement(new TestNode(text));
151
+ }
152
+
153
+ export function $isTestNode(
154
+ node: LexicalNode | null | undefined,
155
+ ): node is TestNode {
156
+ return node instanceof TestNode;
157
+ }
@@ -10,46 +10,66 @@ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
10
10
  import {mergeRegister} from '@lexical/utils';
11
11
  import {$getNodeByKey, COMMAND_PRIORITY_EDITOR} from 'lexical';
12
12
  import {useStore} from 'onchain-utility/hooks';
13
- import {useEffect} from 'react';
13
+ import React, {useEffect, useImperativeHandle, useRef} from 'react';
14
14
 
15
15
  import {PARAMETERS_UPDATE} from '../const';
16
16
  import {$isParametersNode} from '.';
17
+ import {ParametersRef} from './types';
17
18
 
18
- const ParametersComponent = ({nodeKey}: {nodeKey: string}) => {
19
- const [editor] = useLexicalComposerContext();
20
- const [parameters, setParameters, , latestParameters] = useStore({
21
- number: '',
22
- value: '',
23
- });
24
-
25
- useEffect(() => {
26
- editor.read(() => {
27
- const node = $getNodeByKey(nodeKey);
28
- if ($isParametersNode(node)) {
29
- setParameters(node.parameters);
30
- }
19
+ const ParametersComponent = React.forwardRef<ParametersRef, {nodeKey: string}>(
20
+ ({nodeKey}, ref) => {
21
+ const [editor] = useLexicalComposerContext();
22
+ const spanRef = useRef<HTMLSpanElement>(null);
23
+ const [parameters, setParameters, , latestParameters] = useStore({
24
+ number: '',
25
+ value: '',
31
26
  });
32
- return mergeRegister(
33
- editor.registerCommand(
34
- PARAMETERS_UPDATE,
35
- ({number, value}) => {
36
- const latest = latestParameters.current;
37
- if (number !== latest.number) {
38
- return false;
39
- }
40
- const node = $getNodeByKey(nodeKey);
41
- if ($isParametersNode(node)) {
42
- setParameters({value});
43
- Object.assign(node.parameters, {value});
44
- }
45
- return true;
46
- },
47
- COMMAND_PRIORITY_EDITOR,
48
- ),
27
+
28
+ useEffect(() => {
29
+ editor.read(() => {
30
+ const node = $getNodeByKey(nodeKey);
31
+ if ($isParametersNode(node)) {
32
+ setParameters(node.parameters);
33
+ }
34
+ });
35
+ return mergeRegister(
36
+ editor.registerCommand(
37
+ PARAMETERS_UPDATE,
38
+ ({number, value}) => {
39
+ const latest = latestParameters.current;
40
+ if (number !== latest.number) {
41
+ return false;
42
+ }
43
+ const node = $getNodeByKey(nodeKey);
44
+ if ($isParametersNode(node)) {
45
+ setParameters({value});
46
+ Object.assign(node.parameters, {value});
47
+ }
48
+ return true;
49
+ },
50
+ COMMAND_PRIORITY_EDITOR,
51
+ ),
52
+ );
53
+ }, []);
54
+
55
+ useImperativeHandle(
56
+ ref,
57
+ () => {
58
+ return {
59
+ getValue() {
60
+ return latestParameters.current.value;
61
+ },
62
+ };
63
+ },
64
+ [],
49
65
  );
50
- }, []);
51
66
 
52
- return <span>{parameters.value}</span>;
53
- };
67
+ return (
68
+ <span ref={spanRef} role="button" tabIndex={0}>
69
+ {parameters.value}
70
+ </span>
71
+ );
72
+ },
73
+ );
54
74
 
55
75
  export default ParametersComponent;
@@ -0,0 +1,3 @@
1
+ export interface ParametersRef {
2
+ getValue(): string;
3
+ }
package/src/utils.ts CHANGED
@@ -15,12 +15,16 @@ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
15
15
  import {$isQuoteNode} from '@lexical/rich-text';
16
16
  import {$findMatchingParent} from '@lexical/utils';
17
17
  import {
18
+ $createRangeSelection,
18
19
  $getEditor,
19
20
  $getNodeByKey,
20
21
  $getSelection,
21
22
  $isElementNode,
22
23
  $isRootNode,
24
+ $isTextNode,
25
+ $setSelection,
23
26
  COMMAND_PRIORITY_CRITICAL,
27
+ DecoratorNode,
24
28
  type EditorThemeClasses,
25
29
  ElementNode,
26
30
  LexicalEditor,
@@ -566,3 +570,38 @@ export function $addInstancesNode({
566
570
  }
567
571
  }
568
572
  }
573
+
574
+ export function $selectDecoratorNode<T>(node?: DecoratorNode<T> | null) {
575
+ if (node) {
576
+ const [previous, next] = [node.getPreviousSibling(), node.getNextSibling()];
577
+ const rangeSelection = $createRangeSelection();
578
+ if (previous) {
579
+ const isText = $isTextNode(previous);
580
+ rangeSelection.anchor.set(
581
+ isText ? previous.getKey() : node.getParent()!.getKey(),
582
+ isText
583
+ ? previous.getTextContentSize()
584
+ : node.getPreviousSiblings().length,
585
+ isText ? 'text' : 'element',
586
+ );
587
+ } else {
588
+ const parent = node.getParent()!;
589
+ rangeSelection.anchor.set(parent.getKey(), 0, 'element');
590
+ }
591
+ if (next) {
592
+ rangeSelection.focus.set(
593
+ next.getKey(),
594
+ 0,
595
+ $isTextNode(next) ? 'text' : 'element',
596
+ );
597
+ } else {
598
+ const parent = node.getParent()!;
599
+ rangeSelection.focus.set(
600
+ parent.getKey(),
601
+ node.getPreviousSiblings().length + 1,
602
+ 'element',
603
+ );
604
+ }
605
+ $setSelection(rangeSelection);
606
+ }
607
+ }
File without changes