lexical 0.32.2-nightly.20250619.0 → 0.32.2-nightly.20250623.0

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/Lexical.dev.js CHANGED
@@ -191,6 +191,7 @@ const TEXT_TYPE_TO_MODE = {
191
191
  [IS_TOKEN]: 'token'
192
192
  };
193
193
  const NODE_STATE_KEY = '$';
194
+ const PROTOTYPE_CONFIG_METHOD = '$config';
194
195
 
195
196
  /**
196
197
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -471,71 +472,42 @@ function initMutationObserver(editor) {
471
472
  });
472
473
  }
473
474
 
474
- function coerceToJSON(v) {
475
- return v;
476
- }
477
-
478
475
  /**
479
- * The return value of {@link createState}, for use with
480
- * {@link $getState} and {@link $setState}.
476
+ * Get the value type (V) from a StateConfig
481
477
  */
482
- class StateConfig {
483
- /** The string key used when serializing this state to JSON */
484
-
485
- /** The parse function from the StateValueConfig passed to createState */
486
-
487
- /**
488
- * The unparse function from the StateValueConfig passed to createState,
489
- * with a default that is simply a pass-through that assumes the value is
490
- * JSON serializable.
491
- */
492
-
493
- /**
494
- * An equality function from the StateValueConfig, with a default of
495
- * Object.is.
496
- */
497
-
498
- /**
499
- * The result of `stateValueConfig.parse(undefined)`, which is computed only
500
- * once and used as the default value. When the current value `isEqual` to
501
- * the `defaultValue`, it will not be serialized to JSON.
502
- */
503
-
504
- constructor(key, stateValueConfig) {
505
- this.key = key;
506
- this.parse = stateValueConfig.parse.bind(stateValueConfig);
507
- this.unparse = (stateValueConfig.unparse || coerceToJSON).bind(stateValueConfig);
508
- this.isEqual = (stateValueConfig.isEqual || Object.is).bind(stateValueConfig);
509
- this.defaultValue = this.parse(undefined);
510
- }
511
- }
512
478
 
513
479
  /**
514
- * For advanced use cases, using this type is not recommended unless
515
- * it is required (due to TypeScript's lack of features like
516
- * higher-kinded types).
517
- *
518
- * A {@link StateConfig} type with any key and any value that can be
519
- * used in situations where the key and value type can not be known,
520
- * such as in a generic constraint when working with a collection of
521
- * StateConfig.
522
- *
523
- * {@link StateConfigKey} and {@link StateConfigValue} will be
524
- * useful when this is used as a generic constraint.
480
+ * Get the key type (K) from a StateConfig
525
481
  */
526
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
527
482
 
528
483
  /**
529
- * Get the value type (V) from a StateConfig
484
+ * A value type, or an updater for that value type. For use with
485
+ * {@link $setState} or any user-defined wrappers around it.
530
486
  */
531
487
 
532
488
  /**
533
- * Get the key type (K) from a StateConfig
489
+ * A type alias to make it easier to define setter methods on your node class
490
+ *
491
+ * @example
492
+ * ```ts
493
+ * const fooState = createState("foo", { parse: ... });
494
+ * class MyClass extends TextNode {
495
+ * // ...
496
+ * setFoo(valueOrUpdater: StateValueOrUpdater<typeof fooState>): this {
497
+ * return $setState(this, fooState, valueOrUpdater);
498
+ * }
499
+ * }
500
+ * ```
534
501
  */
535
502
 
503
+ // eslint-disable-next-line @typescript-eslint/ban-types
504
+
505
+ /* eslint-disable @typescript-eslint/no-explicit-any */
506
+
507
+ /* eslint-enable @typescript-eslint/no-explicit-any */
508
+
536
509
  /**
537
- * A value type, or an updater for that value type. For use with
538
- * {@link $setState} or any user-defined wrappers around it.
510
+ * The NodeState JSON produced by this LexicalNode
539
511
  */
540
512
 
541
513
  /**
@@ -579,6 +551,56 @@ class StateConfig {
579
551
  * zod, valibot, ajv, Effect, TypeBox, etc. perhaps with a wrapper function.
580
552
  */
581
553
 
554
+ /**
555
+ * The return value of {@link createState}, for use with
556
+ * {@link $getState} and {@link $setState}.
557
+ */
558
+ class StateConfig {
559
+ /** The string key used when serializing this state to JSON */
560
+
561
+ /** The parse function from the StateValueConfig passed to createState */
562
+
563
+ /**
564
+ * The unparse function from the StateValueConfig passed to createState,
565
+ * with a default that is simply a pass-through that assumes the value is
566
+ * JSON serializable.
567
+ */
568
+
569
+ /**
570
+ * An equality function from the StateValueConfig, with a default of
571
+ * Object.is.
572
+ */
573
+
574
+ /**
575
+ * The result of `stateValueConfig.parse(undefined)`, which is computed only
576
+ * once and used as the default value. When the current value `isEqual` to
577
+ * the `defaultValue`, it will not be serialized to JSON.
578
+ */
579
+
580
+ constructor(key, stateValueConfig) {
581
+ this.key = key;
582
+ this.parse = stateValueConfig.parse.bind(stateValueConfig);
583
+ this.unparse = (stateValueConfig.unparse || coerceToJSON).bind(stateValueConfig);
584
+ this.isEqual = (stateValueConfig.isEqual || Object.is).bind(stateValueConfig);
585
+ this.defaultValue = this.parse(undefined);
586
+ }
587
+ }
588
+
589
+ /**
590
+ * For advanced use cases, using this type is not recommended unless
591
+ * it is required (due to TypeScript's lack of features like
592
+ * higher-kinded types).
593
+ *
594
+ * A {@link StateConfig} type with any key and any value that can be
595
+ * used in situations where the key and value type can not be known,
596
+ * such as in a generic constraint when working with a collection of
597
+ * StateConfig.
598
+ *
599
+ * {@link StateConfigKey} and {@link StateConfigValue} will be
600
+ * useful when this is used as a generic constraint.
601
+ */
602
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
603
+
582
604
  /**
583
605
  * Create a StateConfig for the given string key and StateValueConfig.
584
606
  *
@@ -596,26 +618,6 @@ function createState(key, valueConfig) {
596
618
  return new StateConfig(key, valueConfig);
597
619
  }
598
620
 
599
- /**
600
- * Given two versions of a node and a stateConfig, compare their state values
601
- * using `$getState(nodeVersion, stateConfig, 'direct')`.
602
- * If the values are equal according to `stateConfig.isEqual`, return `null`,
603
- * otherwise return `[value, prevValue]`.
604
- *
605
- * This is useful for implementing updateDOM. Note that the `'direct'`
606
- * version argument is used for both nodes.
607
- *
608
- * @param node Any LexicalNode
609
- * @param prevNode A previous version of node
610
- * @param stateConfig The configuration of the state to read
611
- * @returns `[value, prevValue]` if changed, otherwise `null`
612
- */
613
- function $getStateChange(node, prevNode, stateConfig) {
614
- const value = $getState(node, stateConfig, 'direct');
615
- const prevValue = $getState(prevNode, stateConfig, 'direct');
616
- return stateConfig.isEqual(value, prevValue) ? null : [value, prevValue];
617
- }
618
-
619
621
  /**
620
622
  * The accessor for working with node state. This will read the value for the
621
623
  * state on the given node, and will return `stateConfig.defaultValue` if the
@@ -646,20 +648,23 @@ function $getState(node, stateConfig, version = 'latest') {
646
648
  }
647
649
 
648
650
  /**
649
- * @internal
651
+ * Given two versions of a node and a stateConfig, compare their state values
652
+ * using `$getState(nodeVersion, stateConfig, 'direct')`.
653
+ * If the values are equal according to `stateConfig.isEqual`, return `null`,
654
+ * otherwise return `[value, prevValue]`.
650
655
  *
651
- * Register the config to this node's sharedConfigMap and throw an exception in
652
- * `true` when a collision is detected.
656
+ * This is useful for implementing updateDOM. Note that the `'direct'`
657
+ * version argument is used for both nodes.
658
+ *
659
+ * @param node Any LexicalNode
660
+ * @param prevNode A previous version of node
661
+ * @param stateConfig The configuration of the state to read
662
+ * @returns `[value, prevValue]` if changed, otherwise `null`
653
663
  */
654
- function $checkCollision(node, stateConfig, state) {
655
- {
656
- const collision = state.sharedConfigMap.get(stateConfig.key);
657
- if (collision !== undefined && collision !== stateConfig) {
658
- {
659
- formatDevErrorMessage(`$setState: State key collision ${JSON.stringify(stateConfig.key)} detected in ${node.constructor.name} node with type ${node.getType()} and key ${node.getKey()}. Only one StateConfig with a given key should be used on a node.`);
660
- }
661
- }
662
- }
664
+ function $getStateChange(node, prevNode, stateConfig) {
665
+ const value = $getState(node, stateConfig, 'direct');
666
+ const prevValue = $getState(prevNode, stateConfig, 'direct');
667
+ return stateConfig.isEqual(value, prevValue) ? null : [value, prevValue];
663
668
  }
664
669
 
665
670
  /**
@@ -704,6 +709,70 @@ function $setState(node, stateConfig, valueOrUpdater) {
704
709
  state.updateFromKnown(stateConfig, value);
705
710
  return writable;
706
711
  }
712
+
713
+ /**
714
+ * @internal
715
+ *
716
+ * Register the config to this node's sharedConfigMap and throw an exception in
717
+ * `true` when a collision is detected.
718
+ */
719
+ function $checkCollision(node, stateConfig, state) {
720
+ {
721
+ const collision = state.sharedNodeState.sharedConfigMap.get(stateConfig.key);
722
+ if (collision !== undefined && collision !== stateConfig) {
723
+ {
724
+ formatDevErrorMessage(`$setState: State key collision ${JSON.stringify(stateConfig.key)} detected in ${node.constructor.name} node with type ${node.getType()} and key ${node.getKey()}. Only one StateConfig with a given key should be used on a node.`);
725
+ }
726
+ }
727
+ }
728
+ }
729
+
730
+ /**
731
+ * @internal
732
+ *
733
+ * Opaque state to be stored on the editor's RegisterNode for use by NodeState
734
+ */
735
+
736
+ /**
737
+ * @internal
738
+ *
739
+ * Create the state to store on RegisteredNode
740
+ */
741
+ function createSharedNodeState(nodeConfig) {
742
+ const sharedConfigMap = new Map();
743
+ const flatKeys = new Set();
744
+ for (let klass = typeof nodeConfig === 'function' ? nodeConfig : nodeConfig.replace; klass.prototype && klass.prototype.getType !== undefined; klass = Object.getPrototypeOf(klass)) {
745
+ const {
746
+ ownNodeConfig
747
+ } = getStaticNodeConfig(klass);
748
+ if (ownNodeConfig && ownNodeConfig.stateConfigs) {
749
+ for (const requiredStateConfig of ownNodeConfig.stateConfigs) {
750
+ let stateConfig;
751
+ if ('stateConfig' in requiredStateConfig) {
752
+ stateConfig = requiredStateConfig.stateConfig;
753
+ if (requiredStateConfig.flat) {
754
+ flatKeys.add(stateConfig.key);
755
+ }
756
+ } else {
757
+ stateConfig = requiredStateConfig;
758
+ }
759
+ sharedConfigMap.set(stateConfig.key, stateConfig);
760
+ }
761
+ }
762
+ }
763
+ return {
764
+ flatKeys,
765
+ sharedConfigMap
766
+ };
767
+ }
768
+
769
+ /**
770
+ * @internal
771
+ *
772
+ * A Map of string keys to state configurations to be shared across nodes
773
+ * and/or node versions.
774
+ */
775
+
707
776
  /**
708
777
  * @internal
709
778
  */
@@ -736,8 +805,7 @@ class NodeState {
736
805
  * imported but has not been parsed yet.
737
806
  *
738
807
  * It stays here until a get state requires us to parse it, and since we
739
- * then know the value is safe we move it to knownState and garbage collect
740
- * it at the next version.
808
+ * then know the value is safe we move it to knownState.
741
809
  *
742
810
  * Note that since only string keys are used here, we can only allow this
743
811
  * state to pass-through on export or on the next version since there is
@@ -750,8 +818,9 @@ class NodeState {
750
818
  /**
751
819
  * @internal
752
820
  *
753
- * This sharedConfigMap is preserved across all versions of a given node and
754
- * remains writable. It is how keys are resolved to configuration.
821
+ * This sharedNodeState is preserved across all instances of a given
822
+ * node type in an editor and remains writable. It is how keys are resolved
823
+ * to configuration.
755
824
  */
756
825
 
757
826
  /**
@@ -764,11 +833,14 @@ class NodeState {
764
833
  /**
765
834
  * @internal
766
835
  */
767
- constructor(node, sharedConfigMap = new Map(), unknownState = undefined, knownState = new Map(), size = undefined) {
836
+ constructor(node, sharedNodeState, unknownState = undefined, knownState = new Map(), size = undefined) {
768
837
  this.node = node;
769
- this.sharedConfigMap = sharedConfigMap;
838
+ this.sharedNodeState = sharedNodeState;
770
839
  this.unknownState = unknownState;
771
840
  this.knownState = knownState;
841
+ const {
842
+ sharedConfigMap
843
+ } = this.sharedNodeState;
772
844
  const computedSize = size !== undefined ? size : computeSize(sharedConfigMap, unknownState, knownState);
773
845
  {
774
846
  if (!(size === undefined || computedSize === size)) {
@@ -783,13 +855,21 @@ class NodeState {
783
855
  this.size = computedSize;
784
856
  }
785
857
 
786
- /** @internal */
858
+ /**
859
+ * @internal
860
+ *
861
+ * Get the value from knownState, or parse it from unknownState
862
+ * if it contains the given key.
863
+ *
864
+ * Updates the sharedConfigMap when no known state is found.
865
+ * Updates unknownState and knownState when an unknownState is parsed.
866
+ */
787
867
  getValue(stateConfig) {
788
868
  const known = this.knownState.get(stateConfig);
789
869
  if (known !== undefined) {
790
870
  return known;
791
871
  }
792
- this.sharedConfigMap.set(stateConfig.key, stateConfig);
872
+ this.sharedNodeState.sharedConfigMap.set(stateConfig.key, stateConfig);
793
873
  let parsed = stateConfig.defaultValue;
794
874
  if (this.unknownState && stateConfig.key in this.unknownState) {
795
875
  const jsonValue = this.unknownState[stateConfig.key];
@@ -824,6 +904,7 @@ class NodeState {
824
904
  const state = {
825
905
  ...this.unknownState
826
906
  };
907
+ const flatState = {};
827
908
  for (const [stateConfig, v] of this.knownState) {
828
909
  if (stateConfig.isEqual(v, stateConfig.defaultValue)) {
829
910
  delete state[stateConfig.key];
@@ -831,9 +912,16 @@ class NodeState {
831
912
  state[stateConfig.key] = stateConfig.unparse(v);
832
913
  }
833
914
  }
834
- return undefinedIfEmpty(state) ? {
835
- [NODE_STATE_KEY]: state
836
- } : {};
915
+ for (const key of this.sharedNodeState.flatKeys) {
916
+ if (key in state) {
917
+ flatState[key] = state[key];
918
+ delete state[key];
919
+ }
920
+ }
921
+ if (undefinedIfEmpty(state)) {
922
+ flatState[NODE_STATE_KEY] = state;
923
+ }
924
+ return flatState;
837
925
  }
838
926
 
839
927
  /**
@@ -856,26 +944,27 @@ class NodeState {
856
944
  if (this.node === node) {
857
945
  return this;
858
946
  }
947
+ const {
948
+ sharedNodeState,
949
+ unknownState
950
+ } = this;
859
951
  const nextKnownState = new Map(this.knownState);
860
- const nextUnknownState = cloneUnknownState(this.unknownState);
861
- if (nextUnknownState) {
862
- // Garbage collection
863
- for (const stateConfig of nextKnownState.keys()) {
864
- delete nextUnknownState[stateConfig.key];
865
- }
866
- }
867
- return new NodeState(node, this.sharedConfigMap, undefinedIfEmpty(nextUnknownState), nextKnownState, this.size);
952
+ return new NodeState(node, sharedNodeState, parseAndPruneNextUnknownState(sharedNodeState.sharedConfigMap, nextKnownState, unknownState), nextKnownState, this.size);
868
953
  }
869
954
 
870
955
  /** @internal */
871
956
  updateFromKnown(stateConfig, value) {
872
957
  const key = stateConfig.key;
873
- this.sharedConfigMap.set(key, stateConfig);
958
+ this.sharedNodeState.sharedConfigMap.set(key, stateConfig);
874
959
  const {
875
960
  knownState,
876
961
  unknownState
877
962
  } = this;
878
963
  if (!(knownState.has(stateConfig) || unknownState && key in unknownState)) {
964
+ if (unknownState) {
965
+ delete unknownState[key];
966
+ this.unknownState = undefinedIfEmpty(unknownState);
967
+ }
879
968
  this.size++;
880
969
  }
881
970
  knownState.set(stateConfig, value);
@@ -896,7 +985,7 @@ class NodeState {
896
985
  * @param v The unknown value from an UnknownStateRecord
897
986
  */
898
987
  updateFromUnknown(k, v) {
899
- const stateConfig = this.sharedConfigMap.get(k);
988
+ const stateConfig = this.sharedNodeState.sharedConfigMap.get(k);
900
989
  if (stateConfig) {
901
990
  this.updateFromKnown(stateConfig, stateConfig.parse(v));
902
991
  } else {
@@ -931,15 +1020,77 @@ class NodeState {
931
1020
  // the size starts at the number of known keys
932
1021
  // and will be updated as we traverse the new state
933
1022
  this.size = knownState.size;
934
- this.unknownState = {};
1023
+ this.unknownState = undefined;
935
1024
  if (unknownState) {
936
1025
  for (const [k, v] of Object.entries(unknownState)) {
937
1026
  this.updateFromUnknown(k, v);
938
1027
  }
939
1028
  }
940
- this.unknownState = undefinedIfEmpty(this.unknownState);
941
1029
  }
942
1030
  }
1031
+
1032
+ /**
1033
+ * @internal
1034
+ *
1035
+ * Only for direct use in very advanced integrations, such as lexical-yjs.
1036
+ * Typically you would only use {@link createState}, {@link $getState}, and
1037
+ * {@link $setState}. This is effectively the preamble for {@link $setState}.
1038
+ */
1039
+ function $getWritableNodeState(node) {
1040
+ const writable = node.getWritable();
1041
+ const state = writable.__state ? writable.__state.getWritable(writable) : new NodeState(writable, $getSharedNodeState(writable));
1042
+ writable.__state = state;
1043
+ return state;
1044
+ }
1045
+
1046
+ /**
1047
+ * @internal
1048
+ *
1049
+ * Get the SharedNodeState for a node on this editor
1050
+ */
1051
+ function $getSharedNodeState(node) {
1052
+ return getRegisteredNodeOrThrow($getEditor(), node.getType()).sharedNodeState;
1053
+ }
1054
+
1055
+ /**
1056
+ * @internal
1057
+ *
1058
+ * This is used to implement LexicalNode.updateFromJSON and is
1059
+ * not intended to be exported from the package.
1060
+ *
1061
+ * @param node any LexicalNode
1062
+ * @param unknownState undefined or a serialized State
1063
+ * @returns A writable version of node, with the state set.
1064
+ */
1065
+ function $updateStateFromJSON(node, unknownState) {
1066
+ const writable = node.getWritable();
1067
+ if (unknownState || writable.__state) {
1068
+ $getWritableNodeState(node).updateFromJSON(unknownState);
1069
+ }
1070
+ return writable;
1071
+ }
1072
+
1073
+ /**
1074
+ * @internal
1075
+ *
1076
+ * Return true if the two nodes have equivalent NodeState, to be used
1077
+ * to determine when TextNode are being merged, not a lot of use cases
1078
+ * otherwise.
1079
+ */
1080
+ function nodeStatesAreEquivalent(a, b) {
1081
+ if (a === b) {
1082
+ return true;
1083
+ }
1084
+ if (a && b && a.size !== b.size) {
1085
+ return false;
1086
+ }
1087
+ const keys = new Set();
1088
+ return !(a && hasUnequalMapEntry(keys, a, b) || b && hasUnequalMapEntry(keys, b, a) || a && hasUnequalRecordEntry(keys, a, b) || b && hasUnequalRecordEntry(keys, b, a));
1089
+ }
1090
+
1091
+ /**
1092
+ * Compute the number of distinct keys that will be in a NodeState
1093
+ */
943
1094
  function computeSize(sharedConfigMap, unknownState, knownState) {
944
1095
  let size = knownState.size;
945
1096
  if (unknownState) {
@@ -954,6 +1105,8 @@ function computeSize(sharedConfigMap, unknownState, knownState) {
954
1105
  }
955
1106
 
956
1107
  /**
1108
+ * @internal
1109
+ *
957
1110
  * Return obj if it is an object with at least one property, otherwise
958
1111
  * return undefined.
959
1112
  */
@@ -967,95 +1120,93 @@ function undefinedIfEmpty(obj) {
967
1120
  }
968
1121
 
969
1122
  /**
970
- * Return undefined if unknownState is undefined or an empty object,
971
- * otherwise return a shallow clone of it.
1123
+ * @internal
1124
+ *
1125
+ * Cast the given v to unknown
972
1126
  */
973
- function cloneUnknownState(unknownState) {
974
- return undefinedIfEmpty(unknownState) && {
975
- ...unknownState
976
- };
1127
+ function coerceToJSON(v) {
1128
+ return v;
977
1129
  }
978
1130
 
979
1131
  /**
980
1132
  * @internal
981
1133
  *
982
- * Only for direct use in very advanced integrations, such as lexical-yjs.
983
- * Typically you would only use {@link createState}, {@link $getState}, and
984
- * {@link $setState}. This is effectively the preamble for {@link $setState}.
1134
+ * Parse all knowable values in an UnknownStateRecord into nextKnownState
1135
+ * and return the unparsed values in a new UnknownStateRecord. Returns
1136
+ * undefined if no unknown values remain.
985
1137
  */
986
- function $getWritableNodeState(node) {
987
- const writable = node.getWritable();
988
- const state = writable.__state ? writable.__state.getWritable(writable) : new NodeState(writable);
989
- writable.__state = state;
990
- return state;
1138
+ function parseAndPruneNextUnknownState(sharedConfigMap, nextKnownState, unknownState) {
1139
+ let nextUnknownState = undefined;
1140
+ if (unknownState) {
1141
+ for (const [k, v] of Object.entries(unknownState)) {
1142
+ const stateConfig = sharedConfigMap.get(k);
1143
+ if (stateConfig) {
1144
+ if (!nextKnownState.has(stateConfig)) {
1145
+ nextKnownState.set(stateConfig, stateConfig.parse(v));
1146
+ }
1147
+ } else {
1148
+ nextUnknownState = nextUnknownState || {};
1149
+ nextUnknownState[k] = v;
1150
+ }
1151
+ }
1152
+ }
1153
+ return nextUnknownState;
991
1154
  }
992
1155
 
993
1156
  /**
994
1157
  * @internal
995
1158
  *
996
- * This is used to implement LexicalNode.updateFromJSON and is
997
- * not intended to be exported from the package.
1159
+ * Compare each entry of sourceState.knownState that is not in keys to
1160
+ * otherState (or the default value if otherState is undefined.
1161
+ * Note that otherState will return the defaultValue as well if it
1162
+ * has never been set. Any checked entry's key will be added to keys.
998
1163
  *
999
- * @param node any LexicalNode
1000
- * @param unknownState undefined or a serialized State
1001
- * @returns A writable version of node, with the state set.
1164
+ * @returns true if any difference is found, false otherwise
1002
1165
  */
1003
- function $updateStateFromJSON(node, unknownState) {
1004
- const writable = node.getWritable();
1005
- if (unknownState || writable.__state) {
1006
- $getWritableNodeState(node).updateFromJSON(unknownState);
1166
+ function hasUnequalMapEntry(keys, sourceState, otherState) {
1167
+ for (const [stateConfig, value] of sourceState.knownState) {
1168
+ if (keys.has(stateConfig.key)) {
1169
+ continue;
1170
+ }
1171
+ keys.add(stateConfig.key);
1172
+ const otherValue = otherState ? otherState.getValue(stateConfig) : stateConfig.defaultValue;
1173
+ if (otherValue !== value && !stateConfig.isEqual(otherValue, value)) {
1174
+ return true;
1175
+ }
1007
1176
  }
1008
- return writable;
1177
+ return false;
1009
1178
  }
1010
1179
 
1011
1180
  /**
1012
1181
  * @internal
1013
1182
  *
1014
- * Return true if the two nodes have equivalent NodeState, to be used
1015
- * to determine when TextNode are being merged, not a lot of use cases
1016
- * otherwise.
1183
+ * Compare each entry of sourceState.unknownState that is not in keys to
1184
+ * otherState.unknownState (or undefined if otherState is undefined).
1185
+ * Any checked entry's key will be added to keys.
1186
+ *
1187
+ * Notably since we have already checked hasUnequalMapEntry on both sides,
1188
+ * we do not do any parsing or checking of knownState.
1189
+ *
1190
+ * @returns true if any difference is found, false otherwise
1017
1191
  */
1018
- function $nodeStatesAreEquivalent(a, b) {
1019
- if (a === b) {
1020
- return true;
1021
- }
1022
- if (a && b && a.size !== b.size) {
1023
- return false;
1024
- }
1025
- const keys = new Set();
1026
- const hasUnequalMapEntry = (sourceState, otherState) => {
1027
- for (const [stateConfig, value] of sourceState.knownState) {
1028
- if (keys.has(stateConfig.key)) {
1192
+ function hasUnequalRecordEntry(keys, sourceState, otherState) {
1193
+ const {
1194
+ unknownState
1195
+ } = sourceState;
1196
+ const otherUnknownState = otherState ? otherState.unknownState : undefined;
1197
+ if (unknownState) {
1198
+ for (const [key, value] of Object.entries(unknownState)) {
1199
+ if (keys.has(key)) {
1029
1200
  continue;
1030
1201
  }
1031
- keys.add(stateConfig.key);
1032
- const otherValue = otherState ? otherState.getValue(stateConfig) : stateConfig.defaultValue;
1033
- if (otherValue !== value && !stateConfig.isEqual(otherValue, value)) {
1202
+ keys.add(key);
1203
+ const otherValue = otherUnknownState ? otherUnknownState[key] : undefined;
1204
+ if (value !== otherValue) {
1034
1205
  return true;
1035
1206
  }
1036
1207
  }
1037
- return false;
1038
- };
1039
- const hasUnequalRecordEntry = (sourceState, otherState) => {
1040
- const {
1041
- unknownState
1042
- } = sourceState;
1043
- const otherUnknownState = otherState ? otherState.unknownState : undefined;
1044
- if (unknownState) {
1045
- for (const [key, value] of Object.entries(unknownState)) {
1046
- if (keys.has(key)) {
1047
- continue;
1048
- }
1049
- keys.add(key);
1050
- const otherValue = otherUnknownState ? otherUnknownState[key] : undefined;
1051
- if (value !== otherValue) {
1052
- return true;
1053
- }
1054
- }
1055
- }
1056
- return false;
1057
- };
1058
- return !(a && hasUnequalMapEntry(a, b) || b && hasUnequalMapEntry(b, a) || a && hasUnequalRecordEntry(a, b) || b && hasUnequalRecordEntry(b, a));
1208
+ }
1209
+ return false;
1059
1210
  }
1060
1211
 
1061
1212
  /**
@@ -1075,7 +1226,7 @@ function $canSimpleTextNodesBeMerged(node1, node2) {
1075
1226
  const node2Style = node2.__style;
1076
1227
  const node1State = node1.__state;
1077
1228
  const node2State = node2.__state;
1078
- return (node1Mode === null || node1Mode === node2Mode) && (node1Format === null || node1Format === node2Format) && (node1Style === null || node1Style === node2Style) && (node1.__state === null || node1State === node2State || $nodeStatesAreEquivalent(node1State, node2State));
1229
+ return (node1Mode === null || node1Mode === node2Mode) && (node1Format === null || node1Format === node2Format) && (node1Style === null || node1Style === node2Style) && (node1.__state === null || node1State === node2State || nodeStatesAreEquivalent(node1State, node2State));
1079
1230
  }
1080
1231
  function $mergeTextNodes(node1, node2) {
1081
1232
  const writableNode1 = node1.mergeWithSibling(node2);
@@ -2915,6 +3066,59 @@ function markCollapsedSelectionFormat(format, style, offset, key, timeStamp) {
2915
3066
  * The base type for all serialized nodes
2916
3067
  */
2917
3068
 
3069
+ /**
3070
+ * EXPERIMENTAL
3071
+ * The configuration of a node returned by LexicalNode.$config()
3072
+ *
3073
+ * @example
3074
+ * ```ts
3075
+ * class CustomText extends TextNode {
3076
+ * $config() {
3077
+ * return this.config('custom-text', {extends: TextNode}};
3078
+ * }
3079
+ * }
3080
+ * ```
3081
+ */
3082
+
3083
+ /**
3084
+ * This is the type of LexicalNode.$config() that can be
3085
+ * overridden by subclasses.
3086
+ */
3087
+
3088
+ /**
3089
+ * Used to extract the node and type from a StaticNodeConfigRecord
3090
+ */
3091
+
3092
+ /**
3093
+ * Any StaticNodeConfigValue (for generics and collections)
3094
+ */
3095
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3096
+
3097
+ /**
3098
+ * @internal
3099
+ *
3100
+ * This is the more specific type than BaseStaticNodeConfig that a subclass
3101
+ * should return from $config()
3102
+ */
3103
+
3104
+ /**
3105
+ * Extract the type from a node based on its $config
3106
+ *
3107
+ * @example
3108
+ * ```ts
3109
+ * type TextNodeType = GetStaticNodeType<TextNode>;
3110
+ * // ? 'text'
3111
+ * ```
3112
+ */
3113
+
3114
+ /**
3115
+ * The most precise type we can infer for the JSON that will
3116
+ * be produced by T.exportJSON().
3117
+ *
3118
+ * Do not use this for the return type of T.exportJSON()! It must be
3119
+ * a more generic type to be compatible with subclassing.
3120
+ */
3121
+
2918
3122
  /**
2919
3123
  * Omit the children, type, and version properties from the given SerializedLexicalNode definition.
2920
3124
  */
@@ -2959,6 +3163,14 @@ function $removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {
2959
3163
  parent.selectEnd();
2960
3164
  }
2961
3165
  }
3166
+ /**
3167
+ * An identity function that will infer the type of DOM nodes
3168
+ * based on tag names to make it easier to construct a
3169
+ * DOMConversionMap.
3170
+ */
3171
+ function buildImportMap(importMap) {
3172
+ return importMap;
3173
+ }
2962
3174
  class LexicalNode {
2963
3175
  // Allow us to look up the type including static props
2964
3176
 
@@ -3004,6 +3216,41 @@ class LexicalNode {
3004
3216
  }
3005
3217
  }
3006
3218
 
3219
+ /**
3220
+ * Override this to implement the new static node configuration protocol,
3221
+ * this method is called directly on the prototype and must not depend
3222
+ * on anything initialized in the constructor. Generally it should be
3223
+ * a trivial implementation.
3224
+ *
3225
+ * @example
3226
+ * ```ts
3227
+ * class MyNode extends TextNode {
3228
+ * $config() {
3229
+ * return this.config('my-node', {extends: TextNode});
3230
+ * }
3231
+ * }
3232
+ * ```
3233
+ */
3234
+ $config() {
3235
+ return {};
3236
+ }
3237
+
3238
+ /**
3239
+ * This is a convenience method for $config that
3240
+ * aids in type inference. See {@link LexicalNode.$config}
3241
+ * for example usage.
3242
+ */
3243
+ config(type, config) {
3244
+ const parentKlass = config.extends || Object.getPrototypeOf(this.constructor);
3245
+ Object.assign(config, {
3246
+ extends: parentKlass,
3247
+ type
3248
+ });
3249
+ return {
3250
+ [type]: config
3251
+ };
3252
+ }
3253
+
3007
3254
  /**
3008
3255
  * Perform any state updates on the clone of prevNode that are not already
3009
3256
  * handled by the constructor call in the static clone method. If you have
@@ -3929,7 +4176,7 @@ class LexicalNode {
3929
4176
  }
3930
4177
  }
3931
4178
  function errorOnTypeKlassMismatch(type, klass) {
3932
- const registeredNode = getActiveEditor()._nodes.get(type);
4179
+ const registeredNode = getRegisteredNode(getActiveEditor(), type);
3933
4180
  // Common error - split in its own invariant
3934
4181
  if (registeredNode === undefined) {
3935
4182
  {
@@ -7913,6 +8160,7 @@ function parseEditorState(serializedEditorState, editor, updateFn) {
7913
8160
  activeEditorState = editorState;
7914
8161
  isReadOnlyMode = false;
7915
8162
  activeEditor = editor;
8163
+ setPendingNodeToClone(null);
7916
8164
  try {
7917
8165
  const registeredNodes = editor._nodes;
7918
8166
  const serializedNode = serializedEditorState.root;
@@ -8284,6 +8532,7 @@ function $beginUpdate(editor, updateFn, options) {
8284
8532
  editor._updating = true;
8285
8533
  activeEditor = editor;
8286
8534
  const headless = editor._headless || editor.getRootElement() === null;
8535
+ setPendingNodeToClone(null);
8287
8536
  try {
8288
8537
  if (editorStateWasCloned) {
8289
8538
  if (headless) {
@@ -9593,6 +9842,10 @@ function $isParagraphNode(node) {
9593
9842
 
9594
9843
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
9595
9844
 
9845
+ /**
9846
+ * A LexicalNode class or LexicalNodeReplacement configuration
9847
+ */
9848
+
9596
9849
  const DEFAULT_SKIP_INITIALIZATION = false;
9597
9850
 
9598
9851
  /**
@@ -9728,40 +9981,37 @@ function createEditor(editorConfig) {
9728
9981
  replace = options.with;
9729
9982
  replaceWithKlass = options.withKlass || null;
9730
9983
  }
9984
+ const {
9985
+ ownNodeConfig
9986
+ } = getStaticNodeConfig(klass);
9731
9987
  // Ensure custom nodes implement required methods and replaceWithKlass is instance of base klass.
9732
9988
  {
9733
9989
  // ArtificialNode__DO_NOT_USE can get renamed, so we use the type
9734
- const nodeType = Object.prototype.hasOwnProperty.call(klass, 'getType') && klass.getType();
9735
9990
  const name = klass.name;
9991
+ const nodeType = hasOwn(klass, 'getType') && klass.getType();
9736
9992
  if (replaceWithKlass) {
9737
9993
  if (!(replaceWithKlass.prototype instanceof klass)) {
9738
9994
  formatDevErrorMessage(`${replaceWithKlass.name} doesn't extend the ${name}`);
9739
9995
  }
9996
+ } else if (replace) {
9997
+ console.warn(`Override for ${name} specifies 'replace' without 'withKlass'. 'withKlass' will be required in a future version.`);
9740
9998
  }
9741
9999
  if (name !== 'RootNode' && nodeType !== 'root' && nodeType !== 'artificial') {
9742
10000
  const proto = klass.prototype;
9743
10001
  ['getType', 'clone'].forEach(method => {
9744
- // eslint-disable-next-line no-prototype-builtins
9745
- if (!klass.hasOwnProperty(method)) {
10002
+ if (!hasOwn(klass, method)) {
9746
10003
  console.warn(`${name} must implement static "${method}" method`);
9747
10004
  }
9748
10005
  });
9749
- if (
9750
- // eslint-disable-next-line no-prototype-builtins
9751
- !klass.hasOwnProperty('importDOM') &&
9752
- // eslint-disable-next-line no-prototype-builtins
9753
- klass.hasOwnProperty('exportDOM')) {
10006
+ if (!hasOwn(klass, 'importDOM') && hasOwn(klass, 'exportDOM')) {
9754
10007
  console.warn(`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`);
9755
10008
  }
9756
10009
  if ($isDecoratorNode(proto)) {
9757
- // eslint-disable-next-line no-prototype-builtins
9758
- if (!proto.hasOwnProperty('decorate')) {
10010
+ if (!hasOwn(proto, 'decorate')) {
9759
10011
  console.warn(`${proto.constructor.name} must implement "decorate" method`);
9760
10012
  }
9761
10013
  }
9762
- if (
9763
- // eslint-disable-next-line no-prototype-builtins
9764
- !klass.hasOwnProperty('importJSON')) {
10014
+ if (!hasOwn(klass, 'importJSON')) {
9765
10015
  console.warn(`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`);
9766
10016
  }
9767
10017
  }
@@ -9769,6 +10019,9 @@ function createEditor(editorConfig) {
9769
10019
  const type = klass.getType();
9770
10020
  const transform = klass.transform();
9771
10021
  const transforms = new Set();
10022
+ if (ownNodeConfig && ownNodeConfig.$transform) {
10023
+ transforms.add(ownNodeConfig.$transform);
10024
+ }
9772
10025
  if (transform !== null) {
9773
10026
  transforms.add(transform);
9774
10027
  }
@@ -9777,6 +10030,7 @@ function createEditor(editorConfig) {
9777
10030
  klass,
9778
10031
  replace,
9779
10032
  replaceWithKlass,
10033
+ sharedNodeState: createSharedNodeState(nodes[i]),
9780
10034
  transforms
9781
10035
  });
9782
10036
  }
@@ -10361,14 +10615,6 @@ class LexicalEditor {
10361
10615
  * where Lexical editor state can be safely mutated.
10362
10616
  * @param updateFn - A function that has access to writable editor state.
10363
10617
  * @param options - A bag of options to control the behavior of the update.
10364
- * @param options.onUpdate - A function to run once the update is complete.
10365
- * Useful for synchronizing updates in some cases.
10366
- * @param options.skipTransforms - Setting this to true will suppress all node
10367
- * transforms for this update cycle.
10368
- * @param options.tag - A tag to identify this update, in an update listener, for instance.
10369
- * Some tags are reserved by the core and control update behavior in different ways.
10370
- * @param options.discrete - If true, prevents this update from being batched, forcing it to
10371
- * run synchronously.
10372
10618
  */
10373
10619
  update(updateFn, options) {
10374
10620
  updateEditor(this, updateFn, options);
@@ -10382,8 +10628,6 @@ class LexicalEditor {
10382
10628
  *
10383
10629
  * @param callbackFn - A function to run after the editor is focused.
10384
10630
  * @param options - A bag of options
10385
- * @param options.defaultSelection - Where to move selection when the editor is
10386
- * focused. Can be rootStart, rootEnd, or undefined. Defaults to rootEnd.
10387
10631
  */
10388
10632
  focus(callbackFn, options = {}) {
10389
10633
  const rootElement = this._rootElement;
@@ -10467,8 +10711,17 @@ class LexicalEditor {
10467
10711
  };
10468
10712
  }
10469
10713
  }
10470
- LexicalEditor.version = "0.32.2-nightly.20250619.0+dev.cjs";
10714
+ LexicalEditor.version = "0.32.2-nightly.20250623.0+dev.cjs";
10471
10715
 
10716
+ let pendingNodeToClone = null;
10717
+ function setPendingNodeToClone(pendingNode) {
10718
+ pendingNodeToClone = pendingNode;
10719
+ }
10720
+ function getPendingNodeToClone() {
10721
+ const node = pendingNodeToClone;
10722
+ pendingNodeToClone = null;
10723
+ return node;
10724
+ }
10472
10725
  let keyCounter = 1;
10473
10726
  function resetRandomKey() {
10474
10727
  keyCounter = 1;
@@ -10476,8 +10729,12 @@ function resetRandomKey() {
10476
10729
  function generateRandomKey() {
10477
10730
  return '' + keyCounter++;
10478
10731
  }
10732
+
10733
+ /**
10734
+ * @internal
10735
+ */
10479
10736
  function getRegisteredNodeOrThrow(editor, nodeType) {
10480
- const registeredNode = editor._nodes.get(nodeType);
10737
+ const registeredNode = getRegisteredNode(editor, nodeType);
10481
10738
  if (registeredNode === undefined) {
10482
10739
  {
10483
10740
  formatDevErrorMessage(`registeredNode: Type ${nodeType} not found`);
@@ -10485,6 +10742,13 @@ function getRegisteredNodeOrThrow(editor, nodeType) {
10485
10742
  }
10486
10743
  return registeredNode;
10487
10744
  }
10745
+
10746
+ /**
10747
+ * @internal
10748
+ */
10749
+ function getRegisteredNode(editor, nodeType) {
10750
+ return editor._nodes.get(nodeType);
10751
+ }
10488
10752
  const scheduleMicroTask = typeof queueMicrotask === 'function' ? queueMicrotask : fn => {
10489
10753
  // No window prefix intended (#1400)
10490
10754
  Promise.resolve().then(fn);
@@ -10610,9 +10874,11 @@ function $isLeafNode(node) {
10610
10874
  return $isTextNode(node) || $isLineBreakNode(node) || $isDecoratorNode(node);
10611
10875
  }
10612
10876
  function $setNodeKey(node, existingKey) {
10877
+ const pendingNode = getPendingNodeToClone();
10878
+ existingKey = existingKey || pendingNode && pendingNode.__key;
10613
10879
  if (existingKey != null) {
10614
10880
  {
10615
- errorOnNodeKeyConstructorMismatch(node, existingKey);
10881
+ errorOnNodeKeyConstructorMismatch(node, existingKey, pendingNode);
10616
10882
  }
10617
10883
  node.__key = existingKey;
10618
10884
  return;
@@ -10633,13 +10899,18 @@ function $setNodeKey(node, existingKey) {
10633
10899
  editor._dirtyType = HAS_DIRTY_NODES;
10634
10900
  node.__key = key;
10635
10901
  }
10636
- function errorOnNodeKeyConstructorMismatch(node, existingKey) {
10902
+ function errorOnNodeKeyConstructorMismatch(node, existingKey, pendingNode) {
10637
10903
  const editorState = internalGetActiveEditorState();
10638
10904
  if (!editorState) {
10639
10905
  // tests expect to be able to do this kind of clone without an active editor state
10640
10906
  return;
10641
10907
  }
10642
10908
  const existingNode = editorState._nodeMap.get(existingKey);
10909
+ if (pendingNode) {
10910
+ if (!(existingKey === pendingNode.__key)) {
10911
+ formatDevErrorMessage(`Lexical node with constructor ${node.constructor.name} (type ${node.getType()}) has an incorrect clone implementation, got ${String(existingKey)} for nodeKey when expecting ${pendingNode.__key}`);
10912
+ }
10913
+ }
10643
10914
  if (existingNode && existingNode.constructor !== node.constructor) {
10644
10915
  // Lifted condition to if statement because the inverted logic is a bit confusing
10645
10916
  if (node.constructor.name !== existingNode.constructor.name) {
@@ -11519,8 +11790,8 @@ function $copyNode(node) {
11519
11790
  }
11520
11791
  function $applyNodeReplacement(node) {
11521
11792
  const editor = getActiveEditor();
11522
- const nodeType = node.constructor.getType();
11523
- const registeredNode = editor._nodes.get(nodeType);
11793
+ const nodeType = node.getType();
11794
+ const registeredNode = getRegisteredNode(editor, nodeType);
11524
11795
  if (!(registeredNode !== undefined)) {
11525
11796
  formatDevErrorMessage(`$applyNodeReplacement node ${node.constructor.name} with type ${nodeType} must be registered to the editor. You can do this by passing the node class via the "nodes" array in the editor config.`);
11526
11797
  }
@@ -11844,7 +12115,7 @@ function computeTypeToNodeMap(editorState) {
11844
12115
  * do not try and use this function to duplicate or copy an existing node.
11845
12116
  *
11846
12117
  * Does not mutate the EditorState.
11847
- * @param node - The node to be cloned.
12118
+ * @param latestNode - The node to be cloned.
11848
12119
  * @returns The clone of the node.
11849
12120
  */
11850
12121
  function $cloneWithProperties(latestNode) {
@@ -11888,6 +12159,102 @@ function isDOMUnmanaged(elementDom) {
11888
12159
  return el.__lexicalUnmanaged === true;
11889
12160
  }
11890
12161
 
12162
+ /**
12163
+ * @internal
12164
+ *
12165
+ * Object.hasOwn ponyfill
12166
+ */
12167
+ function hasOwn(o, k) {
12168
+ return Object.prototype.hasOwnProperty.call(o, k);
12169
+ }
12170
+
12171
+ /** @internal */
12172
+ function isAbstractNodeClass(klass) {
12173
+ return klass === DecoratorNode || klass === ElementNode || klass === Object.getPrototypeOf(ElementNode);
12174
+ }
12175
+
12176
+ /** @internal */
12177
+ function getStaticNodeConfig(klass) {
12178
+ const nodeConfigRecord = PROTOTYPE_CONFIG_METHOD in klass.prototype ? klass.prototype[PROTOTYPE_CONFIG_METHOD]() : undefined;
12179
+ const isAbstract = isAbstractNodeClass(klass);
12180
+ const nodeType = !isAbstract && hasOwn(klass, 'getType') ? klass.getType() : undefined;
12181
+ let ownNodeConfig;
12182
+ let ownNodeType = nodeType;
12183
+ if (nodeConfigRecord) {
12184
+ if (nodeType) {
12185
+ ownNodeConfig = nodeConfigRecord[nodeType];
12186
+ } else {
12187
+ for (const [k, v] of Object.entries(nodeConfigRecord)) {
12188
+ ownNodeType = k;
12189
+ ownNodeConfig = v;
12190
+ }
12191
+ }
12192
+ }
12193
+ if (!isAbstract && ownNodeType) {
12194
+ if (!hasOwn(klass, 'getType')) {
12195
+ klass.getType = () => ownNodeType;
12196
+ }
12197
+ if (!hasOwn(klass, 'clone')) {
12198
+ {
12199
+ if (!(klass.length === 0)) {
12200
+ formatDevErrorMessage(`${klass.name} (type ${ownNodeType}) must implement a static clone method since its constructor has ${String(klass.length)} required arguments (expecting 0). Use an explicit default in the first argument of your constructor(prop: T=X, nodeKey?: NodeKey).`);
12201
+ }
12202
+ }
12203
+ klass.clone = prevNode => {
12204
+ setPendingNodeToClone(prevNode);
12205
+ return new klass();
12206
+ };
12207
+ }
12208
+ if (!hasOwn(klass, 'importJSON')) {
12209
+ {
12210
+ if (!(klass.length === 0)) {
12211
+ formatDevErrorMessage(`${klass.name} (type ${ownNodeType}) must implement a static importJSON method since its constructor has ${String(klass.length)} required arguments (expecting 0). Use an explicit default in the first argument of your constructor(prop: T=X, nodeKey?: NodeKey).`);
12212
+ }
12213
+ }
12214
+ klass.importJSON = ownNodeConfig && ownNodeConfig.$importJSON || (serializedNode => new klass().updateFromJSON(serializedNode));
12215
+ }
12216
+ if (!hasOwn(klass, 'importDOM') && ownNodeConfig) {
12217
+ const {
12218
+ importDOM
12219
+ } = ownNodeConfig;
12220
+ if (importDOM) {
12221
+ klass.importDOM = () => importDOM;
12222
+ }
12223
+ }
12224
+ }
12225
+ return {
12226
+ ownNodeConfig,
12227
+ ownNodeType
12228
+ };
12229
+ }
12230
+
12231
+ /**
12232
+ * Create an node from its class.
12233
+ *
12234
+ * Note that this will directly construct the final `withKlass` node type,
12235
+ * and will ignore the deprecated `with` functions. This allows `$create` to
12236
+ * skip any intermediate steps where the replaced node would be created and
12237
+ * then immediately discarded (once per configured replacement of that node).
12238
+ *
12239
+ * This does not support any arguments to the constructor.
12240
+ * Setters can be used to initialize your node, and they can
12241
+ * be chained. You can of course write your own mutliple-argument functions
12242
+ * to wrap that.
12243
+ *
12244
+ * @example
12245
+ * ```ts
12246
+ * function $createTokenText(text: string): TextNode {
12247
+ * return $create(TextNode).setTextContent(text).setMode('token');
12248
+ * }
12249
+ * ```
12250
+ */
12251
+ function $create(klass) {
12252
+ const editor = $getEditor();
12253
+ errorOnReadOnly();
12254
+ const registeredNode = editor.resolveRegisteredNodeAfterReplacements(editor.getRegisteredNode(klass));
12255
+ return new registeredNode.klass();
12256
+ }
12257
+
11891
12258
  /**
11892
12259
  * The direction of a caret, 'next' points towards the end of the document
11893
12260
  * and 'previous' points towards the beginning
@@ -12862,7 +13229,7 @@ function $isCaretAttached(caret) {
12862
13229
  * blocks then the remaining contents of the later block will be merged with
12863
13230
  * the earlier block.
12864
13231
  *
12865
- * @param range The range to remove text and nodes from
13232
+ * @param initialRange The range to remove text and nodes from
12866
13233
  * @param sliceMode If 'preserveEmptyTextPointCaret' it will leave an empty TextPointCaret at the anchor for insert if one exists, otherwise empty slices will be removed
12867
13234
  * @returns The new collapsed range (biased towards the earlier node)
12868
13235
  */
@@ -13136,8 +13503,9 @@ function $getChildCaretAtIndex(parent, index, direction) {
13136
13503
  * R -> P -> T1, T2
13137
13504
  * -> P2
13138
13505
  * returns T2 for node T1, P2 for node T2, and null for node P2.
13139
- * @param node LexicalNode.
13140
- * @returns An array (tuple) containing the found Lexical node and the depth difference, or null, if this node doesn't exist.
13506
+ * @param startCaret The initial caret
13507
+ * @param rootMode The root mode, 'root' ('default') or 'shadowRoot'
13508
+ * @returns An array (tuple) containing the found caret and the depth difference, or null, if this node doesn't exist.
13141
13509
  */
13142
13510
  function $getAdjacentSiblingOrParentSiblingCaret(startCaret, rootMode = 'root') {
13143
13511
  let depthDiff = 0;
@@ -13237,6 +13605,7 @@ exports.$caretRangeFromSelection = $caretRangeFromSelection;
13237
13605
  exports.$cloneWithProperties = $cloneWithProperties;
13238
13606
  exports.$comparePointCaretNext = $comparePointCaretNext;
13239
13607
  exports.$copyNode = $copyNode;
13608
+ exports.$create = $create;
13240
13609
  exports.$createLineBreakNode = $createLineBreakNode;
13241
13610
  exports.$createNodeSelection = $createNodeSelection;
13242
13611
  exports.$createParagraphNode = $createParagraphNode;
@@ -13393,8 +13762,10 @@ exports.TEXT_TYPE_TO_FORMAT = TEXT_TYPE_TO_FORMAT;
13393
13762
  exports.TabNode = TabNode;
13394
13763
  exports.TextNode = TextNode;
13395
13764
  exports.UNDO_COMMAND = UNDO_COMMAND;
13765
+ exports.buildImportMap = buildImportMap;
13396
13766
  exports.createCommand = createCommand;
13397
13767
  exports.createEditor = createEditor;
13768
+ exports.createSharedNodeState = createSharedNodeState;
13398
13769
  exports.createState = createState;
13399
13770
  exports.flipDirection = flipDirection;
13400
13771
  exports.getDOMOwnerDocument = getDOMOwnerDocument;
@@ -13403,6 +13774,8 @@ exports.getDOMSelectionFromTarget = getDOMSelectionFromTarget;
13403
13774
  exports.getDOMTextNode = getDOMTextNode;
13404
13775
  exports.getEditorPropertyFromDOMNode = getEditorPropertyFromDOMNode;
13405
13776
  exports.getNearestEditorFromDOMNode = getNearestEditorFromDOMNode;
13777
+ exports.getRegisteredNode = getRegisteredNode;
13778
+ exports.getRegisteredNodeOrThrow = getRegisteredNodeOrThrow;
13406
13779
  exports.isBlockDomNode = isBlockDomNode;
13407
13780
  exports.isCurrentlyReadOnlyMode = isCurrentlyReadOnlyMode;
13408
13781
  exports.isDOMDocumentNode = isDOMDocumentNode;