@lofcz/platejs-core 53.1.6 → 53.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,20 @@
1
- import { Ht as BaseParagraphPlugin, at as DOMPlugin, cn as createSlatePlugin, lt as ChunkingPlugin, n as withSlate, p as isEditOnly, s as SlateExtensionPlugin, sn as getEditorPlugin$1, tn as getPluginByType, vt as getSlateClass, y as NavigationFeedbackPlugin$1, yt as getPluginNodeProps } from "../withSlate-Ck8dLhUt.js";
1
+ import { Ht as BaseParagraphPlugin, b as NavigationFeedbackPlugin$1, bt as getPluginNodeProps, cn as createSlatePlugin, n as withSlate, ot as DOMPlugin, p as isEditOnly, s as SlateExtensionPlugin, sn as getEditorPlugin$1, tn as getPluginByType, ut as ChunkingPlugin, yt as getSlateClass } from "../withSlate-NVP0S9vL.js";
2
2
  import { t as Hotkeys } from "../hotkeys-DI1HPO2Q.js";
3
- import { A as pipeInjectNodeProps, C as createStaticEditor, k as pipeDecorate, s as PlateStatic } from "../static-DAs0P1Ms.js";
4
- import { PathApi, createEditor } from "@platejs/slate";
3
+ import { A as pipeInjectNodeProps, C as createStaticEditor, k as pipeDecorate, s as PlateStatic } from "../static-KMalmfNw.js";
4
+ import { NodeApi, PathApi, createEditor } from "@platejs/slate";
5
5
  import { isDefined } from "@udecode/utils";
6
6
  import { DefaultPlaceholder, Editable, Slate, useComposing, useFocused, useReadOnly, useSelected, useSlateStatic, withReact } from "slate-react";
7
7
  import { c } from "react-compiler-runtime";
8
8
  import React, { useEffect, useId, useRef } from "react";
9
9
  import { Key, useHotkeys } from "@udecode/react-hotkeys";
10
- import { createAtomStore, useAtomStoreSet, useAtomStoreState, useAtomStoreValue, useStoreAtomState, useStoreAtomValue, useStoreAtomValue as useStoreAtomValue$1, useStoreSetAtom } from "jotai-x";
11
10
  import { atom, atom as atom$1 } from "jotai";
11
+ import { createAtomStore, useAtomStoreSet, useAtomStoreState, useAtomStoreValue, useStoreAtomState, useStoreAtomValue, useStoreAtomValue as useStoreAtomValue$1, useStoreSetAtom } from "jotai-x";
12
12
  import { createZustandStore, createZustandStore as createZustandStore$1, useStoreSelect, useStoreSelect as useStoreSelect$1, useStoreState, useStoreValue, useStoreValue as useStoreValue$1, useTracked, useTrackedStore } from "zustand-x";
13
13
  import clsx$1, { clsx } from "clsx";
14
14
  import omit from "lodash/omit.js";
15
15
  import { useDeepCompareMemo } from "use-deep-compare";
16
- import { useComposedRef, useMemoizedSelector, useStableFn } from "@udecode/react-utils";
16
+ import { useComposedRef, useStableFn } from "@udecode/react-utils";
17
+ import { createStore } from "jotai/vanilla";
17
18
  import { selectAtom } from "jotai/utils";
18
19
  import { focusAtom } from "jotai-optics";
19
20
 
@@ -583,16 +584,30 @@ const DOM_HANDLERS = [
583
584
  * `props.element.attributes` are passed into `props.attributes`. Extend the
584
585
  * class name with the node type.
585
586
  */
586
- const getRenderNodeProps = ({ attributes: nodeAttributes, disableInjectNodeProps, editor, plugin, props, readOnly }) => {
587
+ const getRenderNodeProps = ({ attributes: nodeAttributes, disableInjectNodeProps, editor, plugin, pluginContext, props, readOnly }) => {
588
+ const hasInjectNodeProps = !disableInjectNodeProps && editor.meta.pluginCache.inject.nodeProps.length > 0;
589
+ const canSkipPluginNodeProps = !hasInjectNodeProps && !plugin?.node.props && !plugin?.node.dangerouslyAllowAttributes?.length;
590
+ const resolvedPluginContext = pluginContext ? pluginContext : plugin ? getEditorPlugin(editor, plugin) : {
591
+ api: editor.api,
592
+ editor,
593
+ tf: editor.transforms
594
+ };
595
+ const { className } = props;
587
596
  let newProps = {
588
597
  ...props,
589
- ...plugin ? getEditorPlugin(editor, plugin) : {
590
- api: editor.api,
591
- editor,
592
- tf: editor.transforms
593
- }
598
+ ...resolvedPluginContext
594
599
  };
595
- const { className } = props;
600
+ if (canSkipPluginNodeProps) {
601
+ newProps = {
602
+ ...newProps,
603
+ attributes: {
604
+ ...props.attributes,
605
+ className: clsx(getSlateClass(plugin?.node.type), props.attributes?.className, className) || void 0
606
+ }
607
+ };
608
+ if (newProps.attributes?.style && Object.keys(newProps.attributes.style).length === 0) newProps.attributes.style = void 0;
609
+ return newProps;
610
+ }
596
611
  const pluginProps = getPluginNodeProps({
597
612
  attributes: nodeAttributes,
598
613
  plugin,
@@ -605,7 +620,7 @@ const getRenderNodeProps = ({ attributes: nodeAttributes, disableInjectNodeProps
605
620
  className: clsx(getSlateClass(plugin?.node.type), pluginProps.attributes?.className, className) || void 0
606
621
  }
607
622
  };
608
- if (!disableInjectNodeProps) newProps = pipeInjectNodeProps(editor, newProps, (node) => editor.api.findPath(node), readOnly);
623
+ if (hasInjectNodeProps) newProps = pipeInjectNodeProps(editor, newProps, (node) => editor.api.findPath(node), readOnly);
609
624
  if (newProps.attributes?.style && Object.keys(newProps.attributes.style).length === 0) newProps.attributes.style = void 0;
610
625
  return newProps;
611
626
  };
@@ -693,6 +708,21 @@ const pipeOnChange = (editor, value) => {
693
708
 
694
709
  //#endregion
695
710
  //#region src/react/components/plate-nodes.tsx
711
+ const VOID_HTML_TAGS = new Set([
712
+ "area",
713
+ "base",
714
+ "br",
715
+ "col",
716
+ "embed",
717
+ "hr",
718
+ "img",
719
+ "input",
720
+ "link",
721
+ "meta",
722
+ "source",
723
+ "track",
724
+ "wbr"
725
+ ]);
696
726
  const useNodeAttributes = (props, ref) => {
697
727
  const $ = c(11);
698
728
  const t0 = props.attributes;
@@ -731,81 +761,137 @@ const useNodeAttributes = (props, ref) => {
731
761
  } else t5 = $[10];
732
762
  return t5;
733
763
  };
764
+ const isHtmlVoidElementTag = (tag) => VOID_HTML_TAGS.has(tag);
765
+ const useBlockIdAttributeRef = (blockId, ref) => {
766
+ const $ = c(2);
767
+ let t0;
768
+ if ($[0] !== blockId) {
769
+ t0 = (node) => {
770
+ if (!node) return;
771
+ if (blockId) node.setAttribute("data-block-id", String(blockId));
772
+ else node.removeAttribute("data-block-id");
773
+ };
774
+ $[0] = blockId;
775
+ $[1] = t0;
776
+ } else t0 = $[1];
777
+ return useComposedRef(t0, ref);
778
+ };
734
779
  const PlateElement = React.forwardRef(function PlateElement$1(t0, ref) {
735
- const $ = c(22);
780
+ const $ = c(15);
781
+ let Tag;
736
782
  let children;
737
783
  let insetProp;
738
784
  let props;
739
785
  let t1;
740
786
  if ($[0] !== t0) {
741
- ({as: t1, children, insetProp, ...props} = t0);
787
+ const { as: t2$1, children: t3$1, insetProp: t4, ...t5 } = t0;
788
+ children = t3$1;
789
+ insetProp = t4;
790
+ props = t5;
791
+ Tag = t2$1 === void 0 ? "div" : t2$1;
792
+ t1 = props.element.id && props.editor.api.isBlock(props.element) ? props.element.id : void 0;
742
793
  $[0] = t0;
743
- $[1] = children;
744
- $[2] = insetProp;
745
- $[3] = props;
746
- $[4] = t1;
794
+ $[1] = Tag;
795
+ $[2] = children;
796
+ $[3] = insetProp;
797
+ $[4] = props;
798
+ $[5] = t1;
747
799
  } else {
748
- children = $[1];
749
- insetProp = $[2];
750
- props = $[3];
751
- t1 = $[4];
800
+ Tag = $[1];
801
+ children = $[2];
802
+ insetProp = $[3];
803
+ props = $[4];
804
+ t1 = $[5];
752
805
  }
753
- const Tag = t1 === void 0 ? "div" : t1;
754
- const attributes = useNodeAttributes(props, ref);
755
- const block = useEditorMounted() && !!props.element.id && !!props.editor.api.isBlock(props.element);
806
+ const blockIdRef = useBlockIdAttributeRef(t1, ref);
807
+ let t2;
808
+ if ($[6] !== props.attributes || $[7] !== props.className || $[8] !== props.style) {
809
+ t2 = {
810
+ attributes: props.attributes,
811
+ className: props.className,
812
+ style: props.style
813
+ };
814
+ $[6] = props.attributes;
815
+ $[7] = props.className;
816
+ $[8] = props.style;
817
+ $[9] = t2;
818
+ } else t2 = $[9];
819
+ const attributes = useNodeAttributes(t2, blockIdRef);
756
820
  const inset = insetProp ?? props.plugin?.rules.selection?.affinity === "directional";
821
+ let t3;
822
+ if ($[10] !== Tag || $[11] !== attributes || $[12] !== children || $[13] !== inset) {
823
+ t3 = /* @__PURE__ */ React.createElement(PlateElementBody, {
824
+ attributes,
825
+ inset,
826
+ tag: Tag
827
+ }, children);
828
+ $[10] = Tag;
829
+ $[11] = attributes;
830
+ $[12] = children;
831
+ $[13] = inset;
832
+ $[14] = t3;
833
+ } else t3 = $[14];
834
+ return t3;
835
+ });
836
+ function PlateElementBody(t0) {
837
+ const $ = c(17);
838
+ const { attributes, children, inset, tag: Tag } = t0;
839
+ let t1;
840
+ if ($[0] !== Tag) {
841
+ t1 = isHtmlVoidElementTag(Tag);
842
+ $[0] = Tag;
843
+ $[1] = t1;
844
+ } else t1 = $[1];
845
+ const isVoidTag = t1;
757
846
  let t2;
758
- if ($[5] !== inset) {
847
+ if ($[2] !== inset) {
759
848
  t2 = inset && /* @__PURE__ */ React.createElement(NonBreakingSpace, null);
760
- $[5] = inset;
761
- $[6] = t2;
762
- } else t2 = $[6];
763
- const t3 = attributes["data-slate-inline"];
764
- const t4 = block ? props.element.id : void 0;
765
- const t5 = attributes?.style;
766
- let t6;
767
- if ($[7] !== t5) {
768
- t6 = {
769
- position: "relative",
770
- ...t5
771
- };
772
- $[7] = t5;
773
- $[8] = t6;
774
- } else t6 = $[8];
775
- const t7 = t6;
776
- let t8;
777
- if ($[9] !== inset) {
778
- t8 = inset && /* @__PURE__ */ React.createElement(NonBreakingSpace, null);
779
- $[9] = inset;
780
- $[10] = t8;
781
- } else t8 = $[10];
782
- let t9;
783
- if ($[11] !== Tag || $[12] !== attributes || $[13] !== children || $[14] !== t3 || $[15] !== t4 || $[16] !== t7 || $[17] !== t8) {
784
- t9 = /* @__PURE__ */ React.createElement(Tag, {
849
+ $[2] = inset;
850
+ $[3] = t2;
851
+ } else t2 = $[3];
852
+ let t3;
853
+ if ($[4] !== Tag || $[5] !== attributes || $[6] !== children || $[7] !== inset || $[8] !== isVoidTag) {
854
+ t3 = isVoidTag ? /* @__PURE__ */ React.createElement("div", {
785
855
  "data-slate-node": "element",
786
- "data-slate-inline": t3,
787
- "data-block-id": t4,
856
+ "data-slate-inline": attributes["data-slate-inline"],
788
857
  ...attributes,
789
- style: t7
790
- }, children, t8);
791
- $[11] = Tag;
792
- $[12] = attributes;
793
- $[13] = children;
858
+ style: {
859
+ position: "relative",
860
+ ...attributes?.style
861
+ }
862
+ }, /* @__PURE__ */ React.createElement(Tag, { contentEditable: false }), children) : /* @__PURE__ */ React.createElement(Tag, {
863
+ "data-slate-node": "element",
864
+ "data-slate-inline": attributes["data-slate-inline"],
865
+ ...attributes,
866
+ style: {
867
+ position: "relative",
868
+ ...attributes?.style
869
+ }
870
+ }, children, inset && /* @__PURE__ */ React.createElement(NonBreakingSpace, null));
871
+ $[4] = Tag;
872
+ $[5] = attributes;
873
+ $[6] = children;
874
+ $[7] = inset;
875
+ $[8] = isVoidTag;
876
+ $[9] = t3;
877
+ } else t3 = $[9];
878
+ let t4;
879
+ if ($[10] !== inset || $[11] !== isVoidTag) {
880
+ t4 = inset && isVoidTag && /* @__PURE__ */ React.createElement(NonBreakingSpace, null);
881
+ $[10] = inset;
882
+ $[11] = isVoidTag;
883
+ $[12] = t4;
884
+ } else t4 = $[12];
885
+ let t5;
886
+ if ($[13] !== t2 || $[14] !== t3 || $[15] !== t4) {
887
+ t5 = /* @__PURE__ */ React.createElement(React.Fragment, null, t2, t3, t4);
888
+ $[13] = t2;
794
889
  $[14] = t3;
795
890
  $[15] = t4;
796
- $[16] = t7;
797
- $[17] = t8;
798
- $[18] = t9;
799
- } else t9 = $[18];
800
- let t10;
801
- if ($[19] !== t2 || $[20] !== t9) {
802
- t10 = /* @__PURE__ */ React.createElement(React.Fragment, null, t2, t9);
803
- $[19] = t2;
804
- $[20] = t9;
805
- $[21] = t10;
806
- } else t10 = $[21];
807
- return t10;
808
- });
891
+ $[16] = t5;
892
+ } else t5 = $[16];
893
+ return t5;
894
+ }
809
895
  const PlateText = React.forwardRef((t0, ref) => {
810
896
  const $ = c(8);
811
897
  let children;
@@ -909,18 +995,55 @@ const PlateLeaf = React.forwardRef((t0, ref) => {
909
995
 
910
996
  //#endregion
911
997
  //#region src/react/utils/pluginRenderLeaf.tsx
998
+ const HARD_AFFINITY_SPACE$1 = String.fromCodePoint(160);
999
+ const HARD_AFFINITY_SPACER_STYLE$1 = {
1000
+ fontSize: 0,
1001
+ lineHeight: 0
1002
+ };
1003
+ const isActiveHardAffinityBoundary$1 = (editor, text) => {
1004
+ if (!editor.api.isCollapsed()) return false;
1005
+ const focus = editor.selection?.focus;
1006
+ if (!focus) return false;
1007
+ if (NodeApi.get(editor, focus.path) !== text) return false;
1008
+ return focus.offset === 0 || focus.offset === text.text.length;
1009
+ };
1010
+ const getSimpleLeafAttributes = (props, className) => {
1011
+ const attributes = props.attributes ?? props.leaf.attributes ?? {};
1012
+ return {
1013
+ ...attributes,
1014
+ className: [className, attributes.className].filter(Boolean).join(" ") || void 0
1015
+ };
1016
+ };
912
1017
  /**
913
1018
  * Get a `Editable.renderLeaf` handler for `plugin.node.type`. If the type is
914
1019
  * equals to the slate leaf type, render `plugin.render.node`. Else, return
915
1020
  * `children`.
916
1021
  */
917
1022
  const pluginRenderLeaf = (editor, plugin) => function render(props) {
918
- const { render: { leaf: leafComponent, node } } = plugin;
919
- const { children, leaf } = props;
920
1023
  const readOnly = useReadOnly();
1024
+ const { render: { leaf: leafComponent, node } } = plugin;
1025
+ const { children, leaf, text } = props;
1026
+ const Component = leafComponent ?? node;
921
1027
  if (isEditOnly(readOnly, plugin, "render")) return children;
922
1028
  if (leaf[plugin.node.type]) {
923
- const Component = leafComponent ?? node;
1029
+ const canUseSimpleLeaf = !Component && editor.meta.pluginCache.inject.nodeProps.length === 0 && !plugin.node.props && !plugin.node.dangerouslyAllowAttributes?.length;
1030
+ if (canUseSimpleLeaf && !plugin.rules.selection?.affinity) {
1031
+ const Tag = plugin.render?.as ?? "span";
1032
+ const attributes = getSimpleLeafAttributes(props, getSlateClass(plugin.node.type) || void 0);
1033
+ return /* @__PURE__ */ React.createElement(Tag, attributes, children);
1034
+ }
1035
+ if (canUseSimpleLeaf && plugin.rules.selection?.affinity === "hard") {
1036
+ const Tag = plugin.render?.as ?? "span";
1037
+ const attributes = getSimpleLeafAttributes(props, getSlateClass(plugin.node.type) || void 0);
1038
+ if (!isActiveHardAffinityBoundary$1(editor, text)) return /* @__PURE__ */ React.createElement(Tag, attributes, children);
1039
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
1040
+ contentEditable: false,
1041
+ style: HARD_AFFINITY_SPACER_STYLE$1
1042
+ }, HARD_AFFINITY_SPACE$1), /* @__PURE__ */ React.createElement(Tag, attributes, children, /* @__PURE__ */ React.createElement("span", {
1043
+ contentEditable: false,
1044
+ style: HARD_AFFINITY_SPACER_STYLE$1
1045
+ }, HARD_AFFINITY_SPACE$1)));
1046
+ }
924
1047
  const Leaf = Component ?? PlateLeaf;
925
1048
  const ctxProps = getRenderNodeProps({
926
1049
  attributes: leaf.attributes,
@@ -940,24 +1063,96 @@ const pluginRenderLeaf = (editor, plugin) => function render(props) {
940
1063
 
941
1064
  //#endregion
942
1065
  //#region src/react/utils/pipeRenderLeaf.tsx
1066
+ const HARD_AFFINITY_SPACE = String.fromCodePoint(160);
1067
+ const HARD_AFFINITY_SPACER_STYLE = {
1068
+ fontSize: 0,
1069
+ lineHeight: 0
1070
+ };
1071
+ const isActiveHardAffinityBoundary = (editor, text) => {
1072
+ if (!editor.api.isCollapsed()) return false;
1073
+ const focus = editor.selection?.focus;
1074
+ if (!focus) return false;
1075
+ if (NodeApi.get(editor, focus.path) !== text) return false;
1076
+ return focus.offset === 0 || focus.offset === text.text.length;
1077
+ };
943
1078
  /** @see {@link RenderLeaf} */
944
1079
  const pipeRenderLeaf = (editor, renderLeafProp) => {
945
- const renderLeafs = [];
1080
+ const complexRenderLeafEntries = [];
1081
+ const complexRenderLeafEntryByKey = /* @__PURE__ */ new Map();
1082
+ const renderLeafEntries = [];
1083
+ const renderLeafEntryByKey = /* @__PURE__ */ new Map();
946
1084
  const leafPropsPlugins = [];
1085
+ const hasInjectNodeProps = editor.meta.pluginCache.inject.nodeProps.length > 0;
947
1086
  editor.meta.pluginCache.node.isLeaf.forEach((key) => {
948
1087
  const plugin = editor.getPlugin({ key });
949
- if (plugin) renderLeafs.push(pluginRenderLeaf(editor, plugin));
1088
+ if (plugin) {
1089
+ const leafKey = plugin.node.type ?? key;
1090
+ if (editor.meta.pluginCache.inject.nodeProps.length === 0 && !plugin.render?.leaf && !plugin.render?.node && !plugin.node.props && !plugin.node.dangerouslyAllowAttributes?.length && (!plugin.rules.selection?.affinity || plugin.rules.selection?.affinity === "hard")) {
1091
+ const entry = {
1092
+ className: plugin.node.type ? `slate-${plugin.node.type}` : void 0,
1093
+ editOnly: plugin.editOnly,
1094
+ key: leafKey,
1095
+ selectionAffinity: plugin.rules.selection?.affinity,
1096
+ tag: plugin.render?.as ?? "span"
1097
+ };
1098
+ renderLeafEntries.push(entry);
1099
+ renderLeafEntryByKey.set(leafKey, true);
1100
+ } else {
1101
+ const entry = {
1102
+ key: leafKey,
1103
+ renderLeaf: pluginRenderLeaf(editor, plugin)
1104
+ };
1105
+ complexRenderLeafEntries.push(entry);
1106
+ complexRenderLeafEntryByKey.set(leafKey, entry.renderLeaf);
1107
+ }
1108
+ }
950
1109
  });
951
1110
  editor.meta.pluginCache.node.leafProps.forEach((key) => {
952
1111
  const plugin = editor.getPlugin({ key });
953
1112
  if (plugin) leafPropsPlugins.push(plugin);
954
1113
  });
1114
+ if (!hasInjectNodeProps && renderLeafEntries.length === 0 && complexRenderLeafEntries.length === 0 && leafPropsPlugins.length === 0) {
1115
+ if (renderLeafProp) return renderLeafProp;
1116
+ return function render({ attributes, ...props }) {
1117
+ return /* @__PURE__ */ React.createElement("span", attributes, props.children);
1118
+ };
1119
+ }
1120
+ const canUsePlainOuterLeaf = !hasInjectNodeProps && !renderLeafProp && leafPropsPlugins.length === 0;
955
1121
  return function render({ attributes, ...props }) {
956
1122
  const readOnly = useReadOnly();
957
- renderLeafs.forEach((renderLeaf) => {
1123
+ const leaf = props.leaf;
1124
+ let hasActiveSimpleRenderLeaf = false;
1125
+ let hasActiveComplexRenderLeaf = false;
1126
+ for (const key in leaf) {
1127
+ if (!Object.hasOwn(leaf, key)) continue;
1128
+ if (!hasActiveSimpleRenderLeaf && renderLeafEntryByKey.has(key)) hasActiveSimpleRenderLeaf = true;
1129
+ if (!hasActiveComplexRenderLeaf && complexRenderLeafEntryByKey.has(key)) hasActiveComplexRenderLeaf = true;
1130
+ if (hasActiveSimpleRenderLeaf && hasActiveComplexRenderLeaf) break;
1131
+ }
1132
+ if (hasActiveSimpleRenderLeaf) for (const { className, editOnly, key, selectionAffinity, tag: Tag } of renderLeafEntries) {
1133
+ if (!leaf[key]) continue;
1134
+ if (editOnly && isEditOnly(readOnly, { editOnly }, "render")) continue;
1135
+ if (selectionAffinity === "hard") {
1136
+ if (!isActiveHardAffinityBoundary(editor, props.text)) {
1137
+ props.children = /* @__PURE__ */ React.createElement(Tag, { className }, props.children);
1138
+ continue;
1139
+ }
1140
+ props.children = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
1141
+ contentEditable: false,
1142
+ style: HARD_AFFINITY_SPACER_STYLE
1143
+ }, HARD_AFFINITY_SPACE), /* @__PURE__ */ React.createElement(Tag, { className }, props.children, /* @__PURE__ */ React.createElement("span", {
1144
+ contentEditable: false,
1145
+ style: HARD_AFFINITY_SPACER_STYLE
1146
+ }, HARD_AFFINITY_SPACE)));
1147
+ continue;
1148
+ }
1149
+ props.children = /* @__PURE__ */ React.createElement(Tag, { className }, props.children);
1150
+ }
1151
+ if (hasActiveComplexRenderLeaf) for (const { key, renderLeaf } of complexRenderLeafEntries) {
1152
+ if (!leaf[key]) continue;
958
1153
  const newChildren = renderLeaf(props);
959
1154
  if (newChildren !== void 0) props.children = newChildren;
960
- });
1155
+ }
961
1156
  leafPropsPlugins.forEach((plugin) => {
962
1157
  if (props.leaf[plugin.node.type]) {
963
1158
  const pluginLeafProps = typeof plugin.node.leafProps === "function" ? plugin.node.leafProps(props) : plugin.node.leafProps ?? {};
@@ -968,6 +1163,7 @@ const pipeRenderLeaf = (editor, renderLeafProp) => {
968
1163
  };
969
1164
  }
970
1165
  });
1166
+ if (canUsePlainOuterLeaf) return /* @__PURE__ */ React.createElement("span", attributes, props.children);
971
1167
  if (renderLeafProp) return renderLeafProp({
972
1168
  attributes,
973
1169
  ...props
@@ -986,17 +1182,30 @@ const pipeRenderLeaf = (editor, renderLeafProp) => {
986
1182
 
987
1183
  //#endregion
988
1184
  //#region src/react/utils/pluginRenderText.tsx
1185
+ const getSimpleTextAttributes = (props, className) => {
1186
+ const attributes = props.attributes ?? {};
1187
+ return {
1188
+ ...attributes,
1189
+ className: [className, attributes.className].filter(Boolean).join(" ") || void 0
1190
+ };
1191
+ };
989
1192
  /**
990
1193
  * Get a `Editable.renderText` handler for `plugin.node.type`. If the type is
991
1194
  * equals to the slate text type and isDecoration is false, render
992
1195
  * `plugin.render.node`. Else, return the default text rendering.
993
1196
  */
994
1197
  const pluginRenderText = (editor, plugin) => function render(nodeProps) {
1198
+ const readOnly = useReadOnly();
995
1199
  const { render: { node } } = plugin;
996
1200
  const { children, text } = nodeProps;
997
- const readOnly = useReadOnly();
1201
+ const textKey = plugin.node.type ?? plugin.key;
998
1202
  if (isEditOnly(readOnly, plugin, "render")) return children;
999
- if (text[plugin.node.type ?? plugin.key]) {
1203
+ if (text[textKey]) {
1204
+ if (!node && editor.meta.pluginCache.inject.nodeProps.length === 0 && !plugin.node.props && !plugin.node.dangerouslyAllowAttributes?.length) {
1205
+ const Tag = plugin.render?.as ?? "span";
1206
+ const attributes = getSimpleTextAttributes(nodeProps, getSlateClass(plugin.node.type) || void 0);
1207
+ return /* @__PURE__ */ React.createElement(Tag, attributes, children);
1208
+ }
1000
1209
  const Text = node ?? PlateText;
1001
1210
  const ctxProps = getRenderNodeProps({
1002
1211
  attributes: nodeProps.attributes,
@@ -1019,17 +1228,59 @@ const pluginRenderText = (editor, plugin) => function render(nodeProps) {
1019
1228
  /** @see {@link RenderText} */
1020
1229
  const pipeRenderText = (editor, renderTextProp) => {
1021
1230
  const renderTexts = [];
1231
+ const renderTextByKey = /* @__PURE__ */ new Map();
1232
+ const simpleRenderTexts = [];
1233
+ const simpleRenderTextByKey = /* @__PURE__ */ new Map();
1022
1234
  const textPropsPlugins = [];
1235
+ const hasInjectNodeProps = editor.meta.pluginCache.inject.nodeProps.length > 0;
1023
1236
  editor.meta.pluginList.forEach((plugin) => {
1024
- if (plugin.node.isLeaf && plugin.node.isDecoration === false) renderTexts.push(pluginRenderText(editor, plugin));
1237
+ if (plugin.node.isLeaf && plugin.node.isDecoration === false) if (!plugin.render.node && !plugin.node.component && !plugin.node.props && !plugin.node.dangerouslyAllowAttributes?.length) {
1238
+ const entry = {
1239
+ className: getSlateClass(plugin.node.type) || void 0,
1240
+ plugin,
1241
+ tag: plugin.render?.as ?? "span",
1242
+ textKey: plugin.node.type ?? plugin.key
1243
+ };
1244
+ simpleRenderTexts.push(entry);
1245
+ simpleRenderTextByKey.set(entry.textKey, true);
1246
+ } else {
1247
+ const entry = {
1248
+ renderText: pluginRenderText(editor, plugin),
1249
+ textKey: plugin.node.type ?? plugin.key
1250
+ };
1251
+ renderTexts.push(entry);
1252
+ renderTextByKey.set(entry.textKey, true);
1253
+ }
1025
1254
  if (plugin.node.textProps) textPropsPlugins.push(plugin);
1026
1255
  });
1256
+ if (!hasInjectNodeProps && simpleRenderTexts.length === 0 && renderTexts.length === 0 && textPropsPlugins.length === 0) {
1257
+ if (renderTextProp) return renderTextProp;
1258
+ return function render({ attributes, ...props }) {
1259
+ return /* @__PURE__ */ React.createElement("span", attributes, props.children);
1260
+ };
1261
+ }
1262
+ const canUsePlainOuterText = !hasInjectNodeProps && !renderTextProp && textPropsPlugins.length === 0;
1027
1263
  return function render({ attributes, ...props }) {
1028
1264
  const readOnly = useReadOnly();
1029
- renderTexts.forEach((renderText) => {
1265
+ const text = props.text;
1266
+ let hasActiveSimpleRenderText = false;
1267
+ let hasActiveRenderText = false;
1268
+ for (const textKey in text) {
1269
+ if (!Object.hasOwn(text, textKey)) continue;
1270
+ if (!hasActiveSimpleRenderText && simpleRenderTextByKey.has(textKey)) hasActiveSimpleRenderText = true;
1271
+ if (!hasActiveRenderText && renderTextByKey.has(textKey)) hasActiveRenderText = true;
1272
+ if (hasActiveSimpleRenderText && hasActiveRenderText) break;
1273
+ }
1274
+ if (hasActiveSimpleRenderText) for (const { className, plugin, tag: Tag, textKey } of simpleRenderTexts) {
1275
+ if (!text[textKey]) continue;
1276
+ if (isEditOnly(readOnly, plugin, "render")) continue;
1277
+ props.children = /* @__PURE__ */ React.createElement(Tag, { className }, props.children);
1278
+ }
1279
+ if (hasActiveRenderText) for (const { renderText, textKey } of renderTexts) {
1280
+ if (!text[textKey]) continue;
1030
1281
  const newChildren = renderText(props);
1031
1282
  if (newChildren !== void 0) props.children = newChildren;
1032
- });
1283
+ }
1033
1284
  textPropsPlugins.forEach((plugin) => {
1034
1285
  if (props.text[plugin.node.type ?? plugin.key]) {
1035
1286
  const pluginTextProps = typeof plugin.node.textProps === "function" ? plugin.node.textProps(props) : plugin.node.textProps ?? {};
@@ -1040,6 +1291,7 @@ const pipeRenderText = (editor, renderTextProp) => {
1040
1291
  };
1041
1292
  }
1042
1293
  });
1294
+ if (canUsePlainOuterText) return /* @__PURE__ */ React.createElement("span", attributes, props.children);
1043
1295
  if (renderTextProp) return renderTextProp({
1044
1296
  attributes,
1045
1297
  ...props
@@ -1147,27 +1399,17 @@ const useEditableProps = ({ disabled, readOnly, ...editableProps } = {}) => {
1147
1399
  * will not return the new path.
1148
1400
  */
1149
1401
  const useNodePath = (node) => {
1150
- const $ = c(6);
1402
+ const $ = c(3);
1151
1403
  const editor = useEditorRef();
1152
1404
  let t0;
1153
1405
  if ($[0] !== editor.api || $[1] !== node) {
1154
- t0 = () => editor.api.findPath(node);
1406
+ t0 = editor.api.findPath(node);
1155
1407
  $[0] = editor.api;
1156
1408
  $[1] = node;
1157
1409
  $[2] = t0;
1158
1410
  } else t0 = $[2];
1159
- let t1;
1160
- if ($[3] !== editor || $[4] !== node) {
1161
- t1 = [editor, node];
1162
- $[3] = editor;
1163
- $[4] = node;
1164
- $[5] = t1;
1165
- } else t1 = $[5];
1166
- return useMemoizedSelector(t0, t1, _temp);
1411
+ return t0;
1167
1412
  };
1168
- function _temp(a, b) {
1169
- return !!a && !!b && PathApi.equals(a, b);
1170
- }
1171
1413
 
1172
1414
  //#endregion
1173
1415
  //#region src/react/hooks/useSlateProps.ts
@@ -1251,44 +1493,193 @@ const useSlateProps = (t0) => {
1251
1493
  return t6;
1252
1494
  };
1253
1495
 
1254
- //#endregion
1255
- //#region src/react/stores/element/usePath.ts
1256
- /** Get the memoized path of the closest element. */
1257
- const usePath = (pluginKey) => {
1258
- const editor = useEditorRef();
1259
- const value = useAtomStoreValue(useElementStore(pluginKey), "path");
1260
- if (!value) {
1261
- editor.api.debug.warn(`usePath(${pluginKey}) hook must be used inside the node component's context`, "USE_ELEMENT_CONTEXT");
1262
- return;
1263
- }
1264
- return value;
1265
- };
1266
-
1267
1496
  //#endregion
1268
1497
  //#region src/react/stores/element/useElementStore.tsx
1269
1498
  const SCOPE_ELEMENT = "element";
1270
- const initialState = {
1499
+ const { elementStore, useElementStore: useElementStoreAtom } = createAtomStore({
1271
1500
  element: null,
1272
1501
  entry: null,
1273
1502
  path: null
1274
- };
1275
- const { ElementProvider, elementStore, useElementStore } = createAtomStore(initialState, {
1276
- effect: Effect,
1503
+ }, {
1277
1504
  name: "element",
1278
1505
  suppressWarnings: true
1279
1506
  });
1280
- function Effect() {
1281
- const $ = c(1);
1282
- const path = usePath();
1283
- if (path && PathApi.equals(path, [0])) {
1284
- let t0;
1285
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
1286
- t0 = /* @__PURE__ */ React.createElement(FirstBlockEffect, null);
1287
- $[0] = t0;
1288
- } else t0 = $[0];
1289
- return t0;
1507
+ const ElementContext = React.createContext(null);
1508
+ const ElementStoreContext = React.createContext(null);
1509
+ let currentElementContext = null;
1510
+ const syncElementStore = (store, nextState, prevState) => {
1511
+ if (!prevState || !Object.is(prevState.element, nextState.element)) store.set(elementStore.atom.element, nextState.element);
1512
+ if (!prevState || !Object.is(prevState.entry, nextState.entry)) store.set(elementStore.atom.entry, nextState.entry);
1513
+ if (!prevState || !Object.is(prevState.path, nextState.path)) store.set(elementStore.atom.path, nextState.path);
1514
+ };
1515
+ const createElementJotaiStore = (state) => {
1516
+ const store = createStore();
1517
+ syncElementStore(store, state);
1518
+ return store;
1519
+ };
1520
+ const createElementRuntimeStore = (initialState) => {
1521
+ let jotaiStore = null;
1522
+ const listeners = /* @__PURE__ */ new Set();
1523
+ let state = initialState;
1524
+ return {
1525
+ getJotaiStore: () => {
1526
+ if (!jotaiStore) jotaiStore = createElementJotaiStore(state);
1527
+ return jotaiStore;
1528
+ },
1529
+ getState: () => state,
1530
+ setState: (nextState) => {
1531
+ if (Object.is(state.element, nextState.element) && Object.is(state.entry, nextState.entry) && Object.is(state.path, nextState.path)) return;
1532
+ const prevState = state;
1533
+ state = nextState;
1534
+ if (jotaiStore) syncElementStore(jotaiStore, nextState, prevState);
1535
+ listeners.forEach((listener) => {
1536
+ listener();
1537
+ });
1538
+ },
1539
+ subscribe: (listener) => {
1540
+ listeners.add(listener);
1541
+ return () => {
1542
+ listeners.delete(listener);
1543
+ };
1544
+ }
1545
+ };
1546
+ };
1547
+ const findElementContext = (context, scope) => {
1548
+ if (!context) return null;
1549
+ if (!scope) return context;
1550
+ let current = context;
1551
+ while (current) {
1552
+ if (current.scope === scope) return current;
1553
+ current = current.parent;
1554
+ }
1555
+ return context;
1556
+ };
1557
+ const findMatchingElementContext = (context, scope) => {
1558
+ if (!context || !scope) return context;
1559
+ let current = context;
1560
+ while (current) {
1561
+ if (current.scope === scope) return current;
1562
+ current = current.parent;
1290
1563
  }
1291
1564
  return null;
1565
+ };
1566
+ const withElementContext = (context, callback) => {
1567
+ const previousContext = currentElementContext;
1568
+ const nextContext = {};
1569
+ Object.defineProperties(nextContext, Object.getOwnPropertyDescriptors(context));
1570
+ nextContext.parent = previousContext;
1571
+ currentElementContext = nextContext;
1572
+ try {
1573
+ return callback();
1574
+ } finally {
1575
+ currentElementContext = previousContext;
1576
+ }
1577
+ };
1578
+ const useElementContext = (scope) => {
1579
+ const $ = c(8);
1580
+ const context = React.useContext(ElementContext);
1581
+ let t0;
1582
+ if ($[0] !== scope) {
1583
+ t0 = findMatchingElementContext(currentElementContext, scope);
1584
+ $[0] = scope;
1585
+ $[1] = t0;
1586
+ } else t0 = $[1];
1587
+ const renderContext = t0;
1588
+ if (renderContext) return renderContext;
1589
+ let t1;
1590
+ if ($[2] !== context || $[3] !== scope) {
1591
+ t1 = findMatchingElementContext(context, scope);
1592
+ $[2] = context;
1593
+ $[3] = scope;
1594
+ $[4] = t1;
1595
+ } else t1 = $[4];
1596
+ const providerContext = t1;
1597
+ if (providerContext) return providerContext;
1598
+ if (currentElementContext) return currentElementContext;
1599
+ let t2;
1600
+ if ($[5] !== context || $[6] !== scope) {
1601
+ t2 = findElementContext(context, scope);
1602
+ $[5] = context;
1603
+ $[6] = scope;
1604
+ $[7] = t2;
1605
+ } else t2 = $[7];
1606
+ return t2;
1607
+ };
1608
+ const useElementStoreContext = (scope) => {
1609
+ const context = React.useContext(ElementStoreContext);
1610
+ if (!context) return null;
1611
+ if (!scope) return context;
1612
+ let current = context;
1613
+ while (current) {
1614
+ if (current.scope === scope) return current;
1615
+ current = current.parent;
1616
+ }
1617
+ return context;
1618
+ };
1619
+ const useElementStore = (scope) => {
1620
+ const $ = c(3);
1621
+ const context = useElementStoreContext(scope);
1622
+ let t0;
1623
+ if ($[0] !== context || $[1] !== scope) {
1624
+ t0 = context ? {
1625
+ scope,
1626
+ store: context.store
1627
+ } : scope;
1628
+ $[0] = context;
1629
+ $[1] = scope;
1630
+ $[2] = t0;
1631
+ } else t0 = $[2];
1632
+ return useElementStoreAtom(t0);
1633
+ };
1634
+ function ElementProvider({ children, path, scope, ...props }) {
1635
+ const element = props.element ?? null;
1636
+ const entry = props.entry ?? null;
1637
+ const elementPath = path ?? null;
1638
+ const [runtime] = React.useState(() => createElementRuntimeStore({
1639
+ element,
1640
+ entry,
1641
+ path: elementPath
1642
+ }));
1643
+ const parent = React.useContext(ElementContext);
1644
+ const parentStore = React.useContext(ElementStoreContext);
1645
+ const contextValue = React.useMemo(() => ({
1646
+ element,
1647
+ entry,
1648
+ parent,
1649
+ path: elementPath,
1650
+ scope
1651
+ }), [
1652
+ element,
1653
+ elementPath,
1654
+ entry,
1655
+ parent,
1656
+ scope
1657
+ ]);
1658
+ const storeContextValue = React.useMemo(() => ({
1659
+ parent: parentStore,
1660
+ runtime,
1661
+ scope,
1662
+ get store() {
1663
+ return runtime.getJotaiStore();
1664
+ }
1665
+ }), [
1666
+ parentStore,
1667
+ runtime,
1668
+ scope
1669
+ ]);
1670
+ React.useLayoutEffect(() => {
1671
+ runtime.setState({
1672
+ element,
1673
+ entry,
1674
+ path: elementPath
1675
+ });
1676
+ }, [
1677
+ element,
1678
+ elementPath,
1679
+ entry,
1680
+ runtime
1681
+ ]);
1682
+ return /* @__PURE__ */ React.createElement(ElementStoreContext.Provider, { value: storeContextValue }, /* @__PURE__ */ React.createElement(ElementContext.Provider, { value: contextValue }, path && PathApi.equals(path, [0]) ? /* @__PURE__ */ React.createElement(FirstBlockEffect, null) : null, children));
1292
1683
  }
1293
1684
  function FirstBlockEffect() {
1294
1685
  const editor = useEditorRef();
@@ -1307,18 +1698,18 @@ function FirstBlockEffect() {
1307
1698
  //#region src/react/utils/pluginRenderElement.tsx
1308
1699
  function ElementContent(t0) {
1309
1700
  const $ = c(3);
1310
- const { editor, plugin, ...t1 } = t0;
1701
+ const { editor, plugin, pluginContext, ...t1 } = t0;
1311
1702
  let props = t1;
1312
- const element = useElement();
1313
1703
  const readOnly = useReadOnly();
1314
1704
  if (isEditOnly(readOnly, plugin, "render")) return null;
1315
1705
  const { children: _children } = props;
1316
1706
  const Component = plugin.render?.node;
1317
1707
  const Element = Component ?? PlateElement;
1318
1708
  props = getRenderNodeProps({
1319
- attributes: element.attributes,
1709
+ attributes: props.element.attributes,
1320
1710
  editor,
1321
1711
  plugin,
1712
+ pluginContext,
1322
1713
  props,
1323
1714
  readOnly
1324
1715
  });
@@ -1364,13 +1755,19 @@ function ElementContent(t0) {
1364
1755
  });
1365
1756
  return component;
1366
1757
  }
1367
- function BelowRootNodes(props) {
1368
- const $ = c(6);
1758
+ function BelowRootNodes(t0) {
1759
+ const $ = c(8);
1760
+ let props;
1761
+ if ($[0] !== t0) {
1762
+ ({...props} = t0);
1763
+ $[0] = t0;
1764
+ $[1] = props;
1765
+ } else props = $[1];
1369
1766
  const editor = useEditorRef();
1370
1767
  const readOnly = useReadOnly();
1371
- let t0;
1372
- if ($[0] !== editor || $[1] !== props || $[2] !== readOnly) {
1373
- t0 = editor.meta.pluginCache.render.belowRootNodes.map((key) => {
1768
+ let t1;
1769
+ if ($[2] !== editor || $[3] !== props || $[4] !== readOnly) {
1770
+ t1 = editor.meta.pluginCache.render.belowRootNodes.map((key) => {
1374
1771
  const plugin = editor.getPlugin({ key });
1375
1772
  if (isEditOnly(readOnly, plugin, "render")) return null;
1376
1773
  const Component = plugin.render.belowRootNodes;
@@ -1379,55 +1776,338 @@ function BelowRootNodes(props) {
1379
1776
  ...props
1380
1777
  });
1381
1778
  });
1382
- $[0] = editor;
1383
- $[1] = props;
1384
- $[2] = readOnly;
1385
- $[3] = t0;
1386
- } else t0 = $[3];
1387
- let t1;
1388
- if ($[4] !== t0) {
1389
- t1 = /* @__PURE__ */ React.createElement(React.Fragment, null, t0);
1390
- $[4] = t0;
1779
+ $[2] = editor;
1780
+ $[3] = props;
1781
+ $[4] = readOnly;
1391
1782
  $[5] = t1;
1392
1783
  } else t1 = $[5];
1393
- return t1;
1784
+ let t2;
1785
+ if ($[6] !== t1) {
1786
+ t2 = /* @__PURE__ */ React.createElement(React.Fragment, null, t1);
1787
+ $[6] = t1;
1788
+ $[7] = t2;
1789
+ } else t2 = $[7];
1790
+ return t2;
1394
1791
  }
1395
1792
  /**
1396
1793
  * Get a `Editable.renderElement` handler for `plugin.node.type`. If the type is
1397
1794
  * equals to the slate element type, render `plugin.render.node`. Else, return
1398
1795
  * `undefined` so the pipeline can check the next plugin.
1399
1796
  */
1400
- const pluginRenderElement = (editor, plugin) => function render(props) {
1401
- const { element, path } = props;
1402
- return /* @__PURE__ */ React.createElement(ElementProvider, {
1403
- element,
1404
- entry: [element, path],
1405
- path,
1406
- scope: plugin.key
1407
- }, /* @__PURE__ */ React.createElement(ElementContent, {
1408
- editor,
1409
- plugin,
1410
- ...props
1411
- }));
1797
+ const pluginRenderElement = (editor, plugin) => {
1798
+ const pluginContext = getEditorPlugin(editor, plugin);
1799
+ return function render(props) {
1800
+ const { element, path } = props;
1801
+ return /* @__PURE__ */ React.createElement(ElementProvider, {
1802
+ element,
1803
+ entry: [element, path],
1804
+ path,
1805
+ scope: plugin.key
1806
+ }, /* @__PURE__ */ React.createElement(ElementContent, {
1807
+ editor,
1808
+ plugin,
1809
+ pluginContext,
1810
+ ...props
1811
+ }));
1812
+ };
1412
1813
  };
1413
1814
 
1414
1815
  //#endregion
1415
1816
  //#region src/react/utils/pipeRenderElement.tsx
1416
- /** @see {@link RenderElement} */
1417
- const pipeRenderElement = (editor, renderElementProp) => {
1418
- return function render(props) {
1419
- const readOnly = useReadOnly();
1420
- const path = useNodePath(props.element);
1421
- const plugin = getPluginByType(editor, props.element.type);
1422
- if (plugin?.node.isElement) return pluginRenderElement(editor, plugin)({
1817
+ function FastElementWithPath(t0) {
1818
+ const $ = c(16);
1819
+ const { attributes, children, editor, element, plugin } = t0;
1820
+ const path = useNodePath(element);
1821
+ let t1;
1822
+ if ($[0] !== element || $[1] !== path) {
1823
+ t1 = [element, path];
1824
+ $[0] = element;
1825
+ $[1] = path;
1826
+ $[2] = t1;
1827
+ } else t1 = $[2];
1828
+ let t2;
1829
+ if ($[3] !== attributes || $[4] !== children || $[5] !== editor || $[6] !== element || $[7] !== path || $[8] !== plugin) {
1830
+ t2 = /* @__PURE__ */ React.createElement(FastElementBody, {
1831
+ attributes,
1832
+ editor,
1833
+ element,
1834
+ path,
1835
+ plugin
1836
+ }, children);
1837
+ $[3] = attributes;
1838
+ $[4] = children;
1839
+ $[5] = editor;
1840
+ $[6] = element;
1841
+ $[7] = path;
1842
+ $[8] = plugin;
1843
+ $[9] = t2;
1844
+ } else t2 = $[9];
1845
+ let t3;
1846
+ if ($[10] !== element || $[11] !== path || $[12] !== plugin.key || $[13] !== t1 || $[14] !== t2) {
1847
+ t3 = /* @__PURE__ */ React.createElement(ElementProvider, {
1848
+ element,
1849
+ entry: t1,
1850
+ path,
1851
+ scope: plugin.key
1852
+ }, t2);
1853
+ $[10] = element;
1854
+ $[11] = path;
1855
+ $[12] = plugin.key;
1856
+ $[13] = t1;
1857
+ $[14] = t2;
1858
+ $[15] = t3;
1859
+ } else t3 = $[15];
1860
+ return t3;
1861
+ }
1862
+ function useFastInjectedAttributes({ attributes, editor, element, path, readOnly }) {
1863
+ if (editor.meta.pluginCache.inject.nodeProps.length === 0) return attributes;
1864
+ return pipeInjectNodeProps(editor, {
1865
+ attributes,
1866
+ element
1867
+ }, (node) => node === element ? path : editor.api.findPath(node), readOnly).attributes;
1868
+ }
1869
+ function FastElementBody(t0) {
1870
+ const $ = c(16);
1871
+ const { attributes, children, editor, element, path, plugin } = t0;
1872
+ const readOnly = useReadOnly();
1873
+ let t1;
1874
+ if ($[0] !== attributes || $[1] !== editor || $[2] !== element || $[3] !== path || $[4] !== readOnly) {
1875
+ t1 = {
1876
+ attributes,
1877
+ editor,
1878
+ element,
1879
+ path,
1880
+ readOnly
1881
+ };
1882
+ $[0] = attributes;
1883
+ $[1] = editor;
1884
+ $[2] = element;
1885
+ $[3] = path;
1886
+ $[4] = readOnly;
1887
+ $[5] = t1;
1888
+ } else t1 = $[5];
1889
+ const injectedAttributes = useFastInjectedAttributes(t1);
1890
+ const t2 = plugin.render?.as;
1891
+ let t3;
1892
+ if ($[6] !== children || $[7] !== editor || $[8] !== element || $[9] !== injectedAttributes || $[10] !== path || $[11] !== plugin || $[12] !== t2) {
1893
+ t3 = {
1894
+ as: t2,
1895
+ attributes: injectedAttributes,
1896
+ children,
1897
+ editor,
1898
+ element,
1899
+ path,
1900
+ plugin
1901
+ };
1902
+ $[6] = children;
1903
+ $[7] = editor;
1904
+ $[8] = element;
1905
+ $[9] = injectedAttributes;
1906
+ $[10] = path;
1907
+ $[11] = plugin;
1908
+ $[12] = t2;
1909
+ $[13] = t3;
1910
+ } else t3 = $[13];
1911
+ const t4 = t3;
1912
+ let t5;
1913
+ if ($[14] !== t4) {
1914
+ t5 = /* @__PURE__ */ React.createElement(PlateElement, t4);
1915
+ $[14] = t4;
1916
+ $[15] = t5;
1917
+ } else t5 = $[15];
1918
+ return t5;
1919
+ }
1920
+ function FastIntrinsicElement(t0) {
1921
+ const $ = c(20);
1922
+ const { attributes, blockId, children, editor, element, isVoidTag, plugin, renderBelowNodes, tag: Tag } = t0;
1923
+ const path = useNodePath(element);
1924
+ let t1;
1925
+ if ($[0] !== element || $[1] !== path) {
1926
+ t1 = [element, path];
1927
+ $[0] = element;
1928
+ $[1] = path;
1929
+ $[2] = t1;
1930
+ } else t1 = $[2];
1931
+ let t2;
1932
+ if ($[3] !== Tag || $[4] !== attributes || $[5] !== blockId || $[6] !== children || $[7] !== editor || $[8] !== element || $[9] !== isVoidTag || $[10] !== path || $[11] !== plugin || $[12] !== renderBelowNodes) {
1933
+ t2 = /* @__PURE__ */ React.createElement(FastIntrinsicElementBody, {
1934
+ attributes,
1935
+ blockId,
1936
+ editor,
1937
+ element,
1938
+ isVoidTag,
1939
+ path,
1940
+ plugin,
1941
+ renderBelowNodes,
1942
+ tag: Tag
1943
+ }, children);
1944
+ $[3] = Tag;
1945
+ $[4] = attributes;
1946
+ $[5] = blockId;
1947
+ $[6] = children;
1948
+ $[7] = editor;
1949
+ $[8] = element;
1950
+ $[9] = isVoidTag;
1951
+ $[10] = path;
1952
+ $[11] = plugin;
1953
+ $[12] = renderBelowNodes;
1954
+ $[13] = t2;
1955
+ } else t2 = $[13];
1956
+ let t3;
1957
+ if ($[14] !== element || $[15] !== path || $[16] !== plugin.key || $[17] !== t1 || $[18] !== t2) {
1958
+ t3 = /* @__PURE__ */ React.createElement(ElementProvider, {
1959
+ element,
1960
+ entry: t1,
1961
+ path,
1962
+ scope: plugin.key
1963
+ }, t2);
1964
+ $[14] = element;
1965
+ $[15] = path;
1966
+ $[16] = plugin.key;
1967
+ $[17] = t1;
1968
+ $[18] = t2;
1969
+ $[19] = t3;
1970
+ } else t3 = $[19];
1971
+ return t3;
1972
+ }
1973
+ function FastIntrinsicElementBody(t0) {
1974
+ const $ = c(27);
1975
+ const { attributes, blockId, children, editor, element, isVoidTag, path, plugin, renderBelowNodes, tag: Tag } = t0;
1976
+ const readOnly = useReadOnly();
1977
+ let t1;
1978
+ if ($[0] !== attributes || $[1] !== editor || $[2] !== element || $[3] !== path || $[4] !== readOnly) {
1979
+ t1 = {
1980
+ attributes,
1981
+ editor,
1982
+ element,
1983
+ path,
1984
+ readOnly
1985
+ };
1986
+ $[0] = attributes;
1987
+ $[1] = editor;
1988
+ $[2] = element;
1989
+ $[3] = path;
1990
+ $[4] = readOnly;
1991
+ $[5] = t1;
1992
+ } else t1 = $[5];
1993
+ const injectedAttributes = useFastInjectedAttributes(t1);
1994
+ const ref = useBlockIdAttributeRef(blockId, injectedAttributes.ref);
1995
+ let elementChildren;
1996
+ if ($[6] !== attributes || $[7] !== children || $[8] !== editor || $[9] !== element || $[10] !== path || $[11] !== plugin || $[12] !== readOnly || $[13] !== renderBelowNodes) {
1997
+ elementChildren = children;
1998
+ if (renderBelowNodes) {
1999
+ const nodeProps = {
2000
+ attributes,
2001
+ children,
2002
+ editor,
2003
+ element,
2004
+ path,
2005
+ plugin
2006
+ };
2007
+ editor.meta.pluginCache.render.belowNodes.forEach((key) => {
2008
+ const wrapperPlugin = editor.getPlugin({ key });
2009
+ if (isEditOnly(readOnly, wrapperPlugin, "render")) return;
2010
+ const hoc = wrapperPlugin.render.belowNodes({
2011
+ ...nodeProps,
2012
+ key
2013
+ });
2014
+ if (hoc) elementChildren = hoc({
2015
+ ...nodeProps,
2016
+ children: elementChildren
2017
+ });
2018
+ });
2019
+ }
2020
+ $[6] = attributes;
2021
+ $[7] = children;
2022
+ $[8] = editor;
2023
+ $[9] = element;
2024
+ $[10] = path;
2025
+ $[11] = plugin;
2026
+ $[12] = readOnly;
2027
+ $[13] = renderBelowNodes;
2028
+ $[14] = elementChildren;
2029
+ } else elementChildren = $[14];
2030
+ const t2 = injectedAttributes["data-slate-inline"];
2031
+ let t3;
2032
+ if ($[15] !== injectedAttributes.style) {
2033
+ t3 = {
2034
+ position: "relative",
2035
+ ...injectedAttributes.style
2036
+ };
2037
+ $[15] = injectedAttributes.style;
2038
+ $[16] = t3;
2039
+ } else t3 = $[16];
2040
+ const t4 = t3;
2041
+ let t5;
2042
+ if ($[17] !== injectedAttributes || $[18] !== ref || $[19] !== t2 || $[20] !== t4) {
2043
+ t5 = {
2044
+ "data-slate-inline": t2,
2045
+ "data-slate-node": "element",
2046
+ ...injectedAttributes,
2047
+ ref,
2048
+ style: t4
2049
+ };
2050
+ $[17] = injectedAttributes;
2051
+ $[18] = ref;
2052
+ $[19] = t2;
2053
+ $[20] = t4;
2054
+ $[21] = t5;
2055
+ } else t5 = $[21];
2056
+ const fastElementProps = t5;
2057
+ let t6;
2058
+ if ($[22] !== Tag || $[23] !== elementChildren || $[24] !== fastElementProps || $[25] !== isVoidTag) {
2059
+ t6 = isVoidTag ? /* @__PURE__ */ React.createElement("div", fastElementProps, /* @__PURE__ */ React.createElement(Tag, { contentEditable: false }), elementChildren) : /* @__PURE__ */ React.createElement(Tag, fastElementProps, elementChildren);
2060
+ $[22] = Tag;
2061
+ $[23] = elementChildren;
2062
+ $[24] = fastElementProps;
2063
+ $[25] = isVoidTag;
2064
+ $[26] = t6;
2065
+ } else t6 = $[26];
2066
+ return t6;
2067
+ }
2068
+ function PluginElementWithPath(t0) {
2069
+ const $ = c(5);
2070
+ const { editor, plugin, props } = t0;
2071
+ const path = useNodePath(props.element);
2072
+ let t1;
2073
+ if ($[0] !== editor || $[1] !== path || $[2] !== plugin || $[3] !== props) {
2074
+ t1 = pluginRenderElement(editor, plugin)({
1423
2075
  ...props,
1424
2076
  path
1425
2077
  });
1426
- if (renderElementProp) return renderElementProp({
2078
+ $[0] = editor;
2079
+ $[1] = path;
2080
+ $[2] = plugin;
2081
+ $[3] = props;
2082
+ $[4] = t1;
2083
+ } else t1 = $[4];
2084
+ return t1;
2085
+ }
2086
+ function RenderElementPropWithPath(t0) {
2087
+ const $ = c(4);
2088
+ const { props, renderElementProp } = t0;
2089
+ const path = useNodePath(props.element);
2090
+ let t1;
2091
+ if ($[0] !== path || $[1] !== props || $[2] !== renderElementProp) {
2092
+ t1 = renderElementProp({
1427
2093
  ...props,
1428
2094
  path
1429
2095
  });
1430
- const ctxProps = getRenderNodeProps({
2096
+ $[0] = path;
2097
+ $[1] = props;
2098
+ $[2] = renderElementProp;
2099
+ $[3] = t1;
2100
+ } else t1 = $[3];
2101
+ return t1;
2102
+ }
2103
+ function DefaultElementWithPath(t0) {
2104
+ const $ = c(20);
2105
+ const { editor, props } = t0;
2106
+ const readOnly = useReadOnly();
2107
+ const path = useNodePath(props.element);
2108
+ let t1;
2109
+ if ($[0] !== editor || $[1] !== path || $[2] !== props || $[3] !== readOnly) {
2110
+ t1 = getRenderNodeProps({
1431
2111
  disableInjectNodeProps: true,
1432
2112
  editor,
1433
2113
  props: {
@@ -1436,12 +2116,121 @@ const pipeRenderElement = (editor, renderElementProp) => {
1436
2116
  },
1437
2117
  readOnly
1438
2118
  });
1439
- return /* @__PURE__ */ React.createElement(ElementProvider, {
2119
+ $[0] = editor;
2120
+ $[1] = path;
2121
+ $[2] = props;
2122
+ $[3] = readOnly;
2123
+ $[4] = t1;
2124
+ } else t1 = $[4];
2125
+ const ctxProps = t1;
2126
+ let t2;
2127
+ if ($[5] !== ctxProps.element || $[6] !== path) {
2128
+ t2 = [ctxProps.element, path];
2129
+ $[5] = ctxProps.element;
2130
+ $[6] = path;
2131
+ $[7] = t2;
2132
+ } else t2 = $[7];
2133
+ const t3 = ctxProps.element.type ?? "default";
2134
+ let t4;
2135
+ if ($[8] !== ctxProps) {
2136
+ t4 = /* @__PURE__ */ React.createElement(BelowRootNodes, ctxProps);
2137
+ $[8] = ctxProps;
2138
+ $[9] = t4;
2139
+ } else t4 = $[9];
2140
+ let t5;
2141
+ if ($[10] !== ctxProps || $[11] !== props.children || $[12] !== t4) {
2142
+ t5 = /* @__PURE__ */ React.createElement(PlateElement, ctxProps, props.children, t4);
2143
+ $[10] = ctxProps;
2144
+ $[11] = props.children;
2145
+ $[12] = t4;
2146
+ $[13] = t5;
2147
+ } else t5 = $[13];
2148
+ let t6;
2149
+ if ($[14] !== ctxProps.element || $[15] !== path || $[16] !== t2 || $[17] !== t3 || $[18] !== t5) {
2150
+ t6 = /* @__PURE__ */ React.createElement(ElementProvider, {
1440
2151
  element: ctxProps.element,
1441
- entry: [ctxProps.element, path],
2152
+ entry: t2,
1442
2153
  path,
1443
- scope: ctxProps.element.type ?? "default"
1444
- }, /* @__PURE__ */ React.createElement(PlateElement, ctxProps, props.children, /* @__PURE__ */ React.createElement(BelowRootNodes, ctxProps)));
2154
+ scope: t3
2155
+ }, t5);
2156
+ $[14] = ctxProps.element;
2157
+ $[15] = path;
2158
+ $[16] = t2;
2159
+ $[17] = t3;
2160
+ $[18] = t5;
2161
+ $[19] = t6;
2162
+ } else t6 = $[19];
2163
+ return t6;
2164
+ }
2165
+ /** @see {@link RenderElement} */
2166
+ const pipeRenderElement = (editor, renderElementProp) => {
2167
+ const hasAboveNodes = editor.meta.pluginCache.render.aboveNodes.length > 0;
2168
+ const hasBelowRootNodes = editor.meta.pluginCache.render.belowRootNodes.length > 0;
2169
+ return function render(props) {
2170
+ const plugin = getPluginByType(editor, props.element.type);
2171
+ if (plugin?.node.isElement) {
2172
+ if (!hasAboveNodes && !hasBelowRootNodes && !plugin.render.node && !plugin.node.props && !plugin.node.dangerouslyAllowAttributes?.length) {
2173
+ const readOnly = editor.dom.readOnly;
2174
+ if (isEditOnly(readOnly, plugin, "render")) return null;
2175
+ const blockId = props.element.id && editor.api.isBlock(props.element) ? props.element.id : void 0;
2176
+ const inset = plugin.rules.selection?.affinity === "directional";
2177
+ const attributes = {
2178
+ ...props.attributes,
2179
+ className: [getSlateClass(plugin.node.type), props.attributes?.className].filter(Boolean).join(" ") || void 0
2180
+ };
2181
+ const renderAs = plugin.render?.as ?? "div";
2182
+ const isIntrinsicTag = typeof renderAs === "string";
2183
+ const Tag = renderAs;
2184
+ const isVoidTag = isIntrinsicTag && isHtmlVoidElementTag(Tag);
2185
+ const hasBelowNodeWrappers = editor.meta.pluginCache.render.belowNodes.some((key) => {
2186
+ return !isEditOnly(readOnly, editor.getPlugin({ key }), "render");
2187
+ });
2188
+ if (!inset && !hasBelowNodeWrappers && isIntrinsicTag) return /* @__PURE__ */ React.createElement(FastIntrinsicElement, {
2189
+ attributes,
2190
+ blockId,
2191
+ editor,
2192
+ element: props.element,
2193
+ isVoidTag,
2194
+ plugin,
2195
+ renderBelowNodes: false,
2196
+ tag: Tag
2197
+ }, props.children);
2198
+ if (!inset && hasBelowNodeWrappers && isIntrinsicTag) return /* @__PURE__ */ React.createElement(FastIntrinsicElement, {
2199
+ attributes,
2200
+ blockId,
2201
+ editor,
2202
+ element: props.element,
2203
+ isVoidTag,
2204
+ plugin,
2205
+ renderBelowNodes: true,
2206
+ tag: Tag
2207
+ }, props.children);
2208
+ if (!hasBelowNodeWrappers && isIntrinsicTag) return /* @__PURE__ */ React.createElement(FastElementWithPath, {
2209
+ attributes,
2210
+ editor,
2211
+ element: props.element,
2212
+ plugin
2213
+ }, props.children);
2214
+ return /* @__PURE__ */ React.createElement(PluginElementWithPath, {
2215
+ editor,
2216
+ plugin,
2217
+ props
2218
+ });
2219
+ }
2220
+ return /* @__PURE__ */ React.createElement(PluginElementWithPath, {
2221
+ editor,
2222
+ plugin,
2223
+ props
2224
+ });
2225
+ }
2226
+ if (renderElementProp) return /* @__PURE__ */ React.createElement(RenderElementPropWithPath, {
2227
+ props,
2228
+ renderElementProp
2229
+ });
2230
+ return /* @__PURE__ */ React.createElement(DefaultElementWithPath, {
2231
+ editor,
2232
+ props
2233
+ });
1445
2234
  };
1446
2235
  };
1447
2236
 
@@ -1780,7 +2569,7 @@ const useElement = (t0) => {
1780
2569
  const $ = c(1);
1781
2570
  const pluginKey = t0 === void 0 ? SCOPE_ELEMENT : t0;
1782
2571
  const editor = useEditorRef();
1783
- const value = useAtomStoreValue(useElementStore(pluginKey), "element");
2572
+ const value = useElementContext(pluginKey)?.element;
1784
2573
  if (!value) {
1785
2574
  editor.api.debug.warn(`useElement(${pluginKey}) hook must be used inside the node component's context`, "USE_ELEMENT_CONTEXT");
1786
2575
  let t1;
@@ -1796,8 +2585,62 @@ const useElement = (t0) => {
1796
2585
  //#endregion
1797
2586
  //#region src/react/stores/element/useElementSelector.ts
1798
2587
  const useElementSelector = (selector, deps, { key, equalityFn = (a, b) => a === b } = {}) => {
1799
- const selectorAtom = React.useMemo(() => selectAtom(elementStore.atom.entry, (entry, prev) => selector(entry, prev), equalityFn), deps);
1800
- return useStoreAtomValue$1(useElementStore(key), selectorAtom);
2588
+ const context = useElementStoreContext(key);
2589
+ const [memoizedSelector, memoizedEqualityFn] = React.useMemo(() => [selector, equalityFn], deps);
2590
+ const cacheRef = React.useRef({
2591
+ entry: null,
2592
+ hasValue: false,
2593
+ runtime: null,
2594
+ selector: null,
2595
+ value: void 0
2596
+ });
2597
+ const subscribe = React.useCallback((onStoreChange) => context?.runtime.subscribe(onStoreChange) ?? (() => {}), [context]);
2598
+ const getSnapshot = React.useCallback(() => {
2599
+ const runtime = context?.runtime ?? null;
2600
+ const cache = cacheRef.current;
2601
+ if (cache.runtime !== runtime || cache.selector !== memoizedSelector) {
2602
+ cache.entry = null;
2603
+ cache.hasValue = false;
2604
+ cache.runtime = runtime;
2605
+ cache.selector = memoizedSelector;
2606
+ cache.value = void 0;
2607
+ }
2608
+ const entry = runtime?.getState().entry ?? null;
2609
+ if (cache.entry === entry && cache.hasValue) return cache.value;
2610
+ if (!entry) {
2611
+ cache.entry = null;
2612
+ cache.hasValue = false;
2613
+ cache.value = void 0;
2614
+ return;
2615
+ }
2616
+ const nextValue = memoizedSelector(entry, cache.hasValue ? cache.value : void 0);
2617
+ if (cache.hasValue && memoizedEqualityFn(cache.value, nextValue)) {
2618
+ cache.entry = entry;
2619
+ return cache.value;
2620
+ }
2621
+ cache.entry = entry;
2622
+ cache.hasValue = true;
2623
+ cache.value = nextValue;
2624
+ return nextValue;
2625
+ }, [
2626
+ context,
2627
+ memoizedEqualityFn,
2628
+ memoizedSelector
2629
+ ]);
2630
+ return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
2631
+ };
2632
+
2633
+ //#endregion
2634
+ //#region src/react/stores/element/usePath.ts
2635
+ /** Get the memoized path of the closest element. */
2636
+ const usePath = (pluginKey) => {
2637
+ const editor = useEditorRef();
2638
+ const value = useElementContext(pluginKey)?.path;
2639
+ if (!value) {
2640
+ editor.api.debug.warn(`usePath(${pluginKey}) hook must be used inside the node component's context`, "USE_ELEMENT_CONTEXT");
2641
+ return;
2642
+ }
2643
+ return value;
1801
2644
  };
1802
2645
 
1803
2646
  //#endregion
@@ -2621,4 +3464,4 @@ const withHOC = (HOC, Component, hocProps, hocRef) => React.forwardRef((props, c
2621
3464
  });
2622
3465
 
2623
3466
  //#endregion
2624
- export { BLUR_EDITOR_EVENT, BelowRootNodes, ContentVisibilityChunk, DOM_HANDLERS, DefaultPlaceholder, Editable, EditorHotkeysEffect, EditorMethodsEffect, EditorRefEffect, EditorRefPluginEffect, ElementProvider, EventEditorPlugin, EventEditorStore, FOCUS_EDITOR_EVENT, GLOBAL_PLATE_SCOPE, NavigationFeedbackPlugin, PLATE_SCOPE, ParagraphPlugin, Plate, PlateContainer, PlateContent, PlateController, PlateControllerEffect, PlateElement, PlateLeaf, PlateSlate, PlateStoreProvider, PlateTest, PlateText, PlateView, ReactPlugin, SCOPE_ELEMENT, Slate, SlateReactExtensionPlugin, atom, convertDomEventToSyntheticEvent, createAtomStore, createPlateEditor, createPlateFallbackEditor, createPlatePlugin, createPlateStore, createTPlatePlugin, createZustandStore, elementStore, getEditorPlugin, getEventPlateId, getPlateCorePlugins, getPlugin, getRenderNodeProps, isEventHandled, omitPluginContext, pipeHandler, pipeOnChange, pipeRenderElement, pipeRenderLeaf, pipeRenderText, plateControllerStore, plateStore, pluginRenderElement, pluginRenderLeaf, pluginRenderText, toPlatePlugin, toTPlatePlugin, useComposing, useEditableProps, useEditorComposing, useEditorContainerRef, useEditorId, useEditorMounted, useEditorPlugin, useEditorPluginOption, useEditorPluginOptions, useEditorReadOnly, useEditorRef, useEditorScrollRef, useEditorSelection, useEditorSelector, useEditorState, useEditorValue, useEditorVersion, useElement, useElementSelector, useElementStore, useEventEditorValue, useEventPlateId, useFocusEditorEvents, useFocused, useFocusedLast, useIncrementVersion, useNavigationHighlight, useNodeAttributes, useNodePath, usePath, usePlateControllerExists, usePlateControllerLocalStore, usePlateControllerStore, usePlateEditor, usePlateLocalStore, usePlateSet, usePlateState, usePlateStore, usePlateValue, usePlateViewEditor, usePluginOption, usePluginOptions, useReadOnly, useRedecorate, useScrollRef, useSelected, useSelectionVersion, useSlateProps, useSlateStatic, useStoreAtomState, useStoreAtomValue, useStoreSelect, useStoreSetAtom, useStoreState, useStoreValue, useTracked, useTrackedStore, useValueVersion, withHOC, withPlate, withPlateReact, withReact };
3467
+ export { BLUR_EDITOR_EVENT, BelowRootNodes, ContentVisibilityChunk, DOM_HANDLERS, DefaultPlaceholder, Editable, EditorHotkeysEffect, EditorMethodsEffect, EditorRefEffect, EditorRefPluginEffect, ElementProvider, EventEditorPlugin, EventEditorStore, FOCUS_EDITOR_EVENT, FirstBlockEffect, GLOBAL_PLATE_SCOPE, NavigationFeedbackPlugin, PLATE_SCOPE, ParagraphPlugin, Plate, PlateContainer, PlateContent, PlateController, PlateControllerEffect, PlateElement, PlateLeaf, PlateSlate, PlateStoreProvider, PlateTest, PlateText, PlateView, ReactPlugin, SCOPE_ELEMENT, Slate, SlateReactExtensionPlugin, atom, convertDomEventToSyntheticEvent, createAtomStore, createPlateEditor, createPlateFallbackEditor, createPlatePlugin, createPlateStore, createTPlatePlugin, createZustandStore, elementStore, getEditorPlugin, getEventPlateId, getPlateCorePlugins, getPlugin, getRenderNodeProps, isEventHandled, isHtmlVoidElementTag, omitPluginContext, pipeHandler, pipeOnChange, pipeRenderElement, pipeRenderLeaf, pipeRenderText, plateControllerStore, plateStore, pluginRenderElement, pluginRenderLeaf, pluginRenderText, toPlatePlugin, toTPlatePlugin, useBlockIdAttributeRef, useComposing, useEditableProps, useEditorComposing, useEditorContainerRef, useEditorId, useEditorMounted, useEditorPlugin, useEditorPluginOption, useEditorPluginOptions, useEditorReadOnly, useEditorRef, useEditorScrollRef, useEditorSelection, useEditorSelector, useEditorState, useEditorValue, useEditorVersion, useElement, useElementContext, useElementSelector, useElementStore, useElementStoreContext, useEventEditorValue, useEventPlateId, useFocusEditorEvents, useFocused, useFocusedLast, useIncrementVersion, useNavigationHighlight, useNodeAttributes, useNodePath, usePath, usePlateControllerExists, usePlateControllerLocalStore, usePlateControllerStore, usePlateEditor, usePlateLocalStore, usePlateSet, usePlateState, usePlateStore, usePlateValue, usePlateViewEditor, usePluginOption, usePluginOptions, useReadOnly, useRedecorate, useScrollRef, useSelected, useSelectionVersion, useSlateProps, useSlateStatic, useStoreAtomState, useStoreAtomValue, useStoreSelect, useStoreSetAtom, useStoreState, useStoreValue, useTracked, useTrackedStore, useValueVersion, withElementContext, withHOC, withPlate, withPlateReact, withReact };