@splunk/visualizations 28.8.0 → 28.9.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.
Files changed (273) hide show
  1. package/Area.config.js +2 -4
  2. package/Area.config.js.map +2 -2
  3. package/Area.js +245 -147
  4. package/Area.js.map +4 -4
  5. package/Bar.config.js +2 -4
  6. package/Bar.config.js.map +2 -2
  7. package/Bar.js +246 -148
  8. package/Bar.js.map +4 -4
  9. package/Bubble/Bubble.d.ts +3 -1
  10. package/Bubble/Bubble.d.ts.map +1 -1
  11. package/Bubble.js +216 -108
  12. package/Bubble.js.map +4 -4
  13. package/CHANGELOG.external.md +31 -1
  14. package/ChoroplethSvg/ChoroplethSvg.d.ts +3 -1
  15. package/ChoroplethSvg/ChoroplethSvg.d.ts.map +1 -1
  16. package/ChoroplethSvg/PureChoroplethSvg/PureChoroplethSvg.d.ts.map +1 -1
  17. package/ChoroplethSvg/PureChoroplethSvg/SvgMutator.d.ts.map +1 -1
  18. package/ChoroplethSvg.js +638 -209
  19. package/ChoroplethSvg.js.map +4 -4
  20. package/Column.config.js +2 -4
  21. package/Column.config.js.map +2 -2
  22. package/Column.js +246 -148
  23. package/Column.js.map +4 -4
  24. package/Ellipse/Ellipse.d.ts +3 -1
  25. package/Ellipse/Ellipse.d.ts.map +1 -1
  26. package/Ellipse.js +216 -105
  27. package/Ellipse.js.map +4 -4
  28. package/Events/Events.d.ts +5 -3
  29. package/Events/Events.d.ts.map +1 -1
  30. package/Events/PureEvents/FieldSummaryTooltip.d.ts.map +1 -1
  31. package/Events/PureEvents/PureEvents.d.ts +0 -1
  32. package/Events/PureEvents/PureEvents.d.ts.map +1 -1
  33. package/Events.js +270 -157
  34. package/Events.js.map +4 -4
  35. package/FillerGauge.js +243 -140
  36. package/FillerGauge.js.map +4 -4
  37. package/Image/Image.d.ts +3 -1
  38. package/Image/Image.d.ts.map +1 -1
  39. package/Image.js +217 -106
  40. package/Image.js.map +4 -4
  41. package/Line.config.js +2 -4
  42. package/Line.config.js.map +2 -2
  43. package/Line.js +246 -148
  44. package/Line.js.map +4 -4
  45. package/LinkGraph/LinkGraph.d.ts +3 -1
  46. package/LinkGraph/LinkGraph.d.ts.map +1 -1
  47. package/LinkGraph/PureLinkGraph/PureLinkGraphUtils.d.ts.map +1 -1
  48. package/LinkGraph/PureLinkGraph/components/Node.d.ts.map +1 -1
  49. package/LinkGraph.config.js +1 -1
  50. package/LinkGraph.config.js.map +2 -2
  51. package/LinkGraph.js +802 -682
  52. package/LinkGraph.js.map +4 -4
  53. package/Map/Map.d.ts +10 -9
  54. package/Map/Map.d.ts.map +1 -1
  55. package/Map/PureMap/BubbleLayer.d.ts.map +1 -1
  56. package/Map/PureMap/ClusterLayer.d.ts.map +1 -1
  57. package/Map/PureMap/MapUtils.d.ts.map +1 -1
  58. package/Map/PureMap/MarkerWrapper.d.ts.map +1 -1
  59. package/Map/PureMap/PureMap.d.ts +8 -65
  60. package/Map/PureMap/PureMap.d.ts.map +1 -1
  61. package/Map.config.js +1 -1
  62. package/Map.config.js.map +2 -2
  63. package/Map.js +363 -313
  64. package/Map.js.map +4 -4
  65. package/Markdown/Markdown.d.ts +9 -1
  66. package/Markdown/Markdown.d.ts.map +1 -1
  67. package/Markdown/config.d.ts.map +1 -1
  68. package/Markdown.config.js +5 -0
  69. package/Markdown.config.js.map +2 -2
  70. package/Markdown.js +225 -94
  71. package/Markdown.js.map +3 -3
  72. package/MarkerGauge.js +239 -134
  73. package/MarkerGauge.js.map +4 -4
  74. package/NetworkGraph/PureNetworkGraph/PureNetworkGraph.d.ts.map +1 -1
  75. package/NetworkGraph/PureNetworkGraph/components/NetworkGraphSvg.d.ts +1 -0
  76. package/NetworkGraph/PureNetworkGraph/components/NetworkGraphSvg.d.ts.map +1 -1
  77. package/NetworkGraph/PureNetworkGraph/components/Node.d.ts +1 -0
  78. package/NetworkGraph/PureNetworkGraph/components/Node.d.ts.map +1 -1
  79. package/NetworkGraph/PureNetworkGraph/utils/networkGraphUtils.d.ts +3 -5
  80. package/NetworkGraph/PureNetworkGraph/utils/networkGraphUtils.d.ts.map +1 -1
  81. package/NetworkGraph.config.js +4 -2
  82. package/NetworkGraph.config.js.map +2 -2
  83. package/NetworkGraph.js +327 -188
  84. package/NetworkGraph.js.map +4 -4
  85. package/ParallelCoordinates/ParallelCoordinates.d.ts +3 -1
  86. package/ParallelCoordinates/ParallelCoordinates.d.ts.map +1 -1
  87. package/ParallelCoordinates.js +239 -128
  88. package/ParallelCoordinates.js.map +4 -4
  89. package/Pie/config.d.ts.map +1 -1
  90. package/Pie/pieUtils.d.ts.map +1 -1
  91. package/Pie.config.js +4 -2
  92. package/Pie.config.js.map +2 -2
  93. package/Pie.js +228 -125
  94. package/Pie.js.map +3 -3
  95. package/ProcessTree/ProcessTree.d.ts +3 -1
  96. package/ProcessTree/ProcessTree.d.ts.map +1 -1
  97. package/ProcessTree/PureProcessTree/PureProcessTree.d.ts +1 -0
  98. package/ProcessTree/PureProcessTree/PureProcessTree.d.ts.map +1 -1
  99. package/ProcessTree/PureProcessTree/components/ProcessTreeLeftPanel.d.ts +1 -0
  100. package/ProcessTree/PureProcessTree/components/ProcessTreeLeftPanel.d.ts.map +1 -1
  101. package/ProcessTree/PureProcessTree/hooks/useProcessTreeGraphData.d.ts +2 -1
  102. package/ProcessTree/PureProcessTree/hooks/useProcessTreeGraphData.d.ts.map +1 -1
  103. package/ProcessTree/PureProcessTree/utils/iconLoader.d.ts +2 -0
  104. package/ProcessTree/PureProcessTree/utils/iconLoader.d.ts.map +1 -1
  105. package/ProcessTree/PureProcessTree/utils/processTreeUtils.d.ts +5 -1
  106. package/ProcessTree/PureProcessTree/utils/processTreeUtils.d.ts.map +1 -1
  107. package/ProcessTree.js +435 -192
  108. package/ProcessTree.js.map +4 -4
  109. package/Punchcard/Punchcard.d.ts +3 -1
  110. package/Punchcard/Punchcard.d.ts.map +1 -1
  111. package/Punchcard.js +238 -129
  112. package/Punchcard.js.map +4 -4
  113. package/Rectangle/Rectangle.d.ts +3 -1
  114. package/Rectangle/Rectangle.d.ts.map +1 -1
  115. package/Rectangle.js +218 -116
  116. package/Rectangle.js.map +4 -4
  117. package/RichText/PureRichText/Editor/EditorPanel.d.ts +1 -4
  118. package/RichText/PureRichText/Editor/EditorPanel.d.ts.map +1 -1
  119. package/RichText/PureRichText/Editor/hooks/useConfigPanelFocus.d.ts +14 -0
  120. package/RichText/PureRichText/Editor/hooks/useConfigPanelFocus.d.ts.map +1 -0
  121. package/RichText/PureRichText/Editor/hooks/useEditorPanelSync.d.ts +15 -0
  122. package/RichText/PureRichText/Editor/hooks/useEditorPanelSync.d.ts.map +1 -0
  123. package/RichText/PureRichText/Editor/hooks/useLinkHandlers.d.ts.map +1 -1
  124. package/RichText/PureRichText/Editor/hooks/usePortalTarget.d.ts +9 -0
  125. package/RichText/PureRichText/Editor/hooks/usePortalTarget.d.ts.map +1 -0
  126. package/RichText/PureRichText/InnerEditor.d.ts +15 -9
  127. package/RichText/PureRichText/InnerEditor.d.ts.map +1 -1
  128. package/RichText/PureRichText/PureRichText.d.ts +5 -10
  129. package/RichText/PureRichText/PureRichText.d.ts.map +1 -1
  130. package/RichText/PureRichText/PureRichTextContext.d.ts +3 -6
  131. package/RichText/PureRichText/PureRichTextContext.d.ts.map +1 -1
  132. package/RichText/PureRichText/RichTextStyles.d.ts +5 -4
  133. package/RichText/PureRichText/RichTextStyles.d.ts.map +1 -1
  134. package/RichText/PureRichText/activeInstance.d.ts +6 -7
  135. package/RichText/PureRichText/activeInstance.d.ts.map +1 -1
  136. package/RichText/PureRichText/config.d.ts.map +1 -1
  137. package/RichText/PureRichText/hooks/useContentSync.d.ts +9 -9
  138. package/RichText/PureRichText/hooks/useContentSync.d.ts.map +1 -1
  139. package/RichText/PureRichText/hooks/useDashboardKeyboardNav.d.ts +2 -7
  140. package/RichText/PureRichText/hooks/useDashboardKeyboardNav.d.ts.map +1 -1
  141. package/RichText/PureRichText/hooks/useEditorSetup.d.ts +8 -4
  142. package/RichText/PureRichText/hooks/useEditorSetup.d.ts.map +1 -1
  143. package/RichText/PureRichText/hooks/useFocusHandlers.d.ts +2 -4
  144. package/RichText/PureRichText/hooks/useFocusHandlers.d.ts.map +1 -1
  145. package/RichText/PureRichText/hooks/useKeyboardShortcuts.d.ts.map +1 -1
  146. package/RichText/PureRichText/hooks/useMouseHandlers.d.ts +3 -7
  147. package/RichText/PureRichText/hooks/useMouseHandlers.d.ts.map +1 -1
  148. package/RichText/PureRichText/hooks/useStepFontSize.d.ts +2 -2
  149. package/RichText/PureRichText/hooks/useStepLineSpacing.d.ts +2 -3
  150. package/RichText/PureRichText/hooks/useStepLineSpacing.d.ts.map +1 -1
  151. package/RichText/PureRichText/hooks/useTokenMap.d.ts +13 -24
  152. package/RichText/PureRichText/hooks/useTokenMap.d.ts.map +1 -1
  153. package/RichText/PureRichText/renderers/ElementRenderer.d.ts +2 -5
  154. package/RichText/PureRichText/renderers/ElementRenderer.d.ts.map +1 -1
  155. package/RichText/PureRichText/types.d.ts +6 -0
  156. package/RichText/PureRichText/types.d.ts.map +1 -1
  157. package/RichText/PureRichText/utils/slateUtils.d.ts +26 -2
  158. package/RichText/PureRichText/utils/slateUtils.d.ts.map +1 -1
  159. package/RichText/RichText.d.ts +3 -1
  160. package/RichText/RichText.d.ts.map +1 -1
  161. package/RichText/config.d.ts.map +1 -1
  162. package/RichText.config.js +5 -0
  163. package/RichText.config.js.map +2 -2
  164. package/RichText.js +1848 -842
  165. package/RichText.js.map +4 -4
  166. package/Sankey/PureSankey/PureSankey.d.ts +2 -0
  167. package/Sankey/PureSankey/PureSankey.d.ts.map +1 -1
  168. package/Sankey/PureSankey/SankeyLink.d.ts +3 -1
  169. package/Sankey/PureSankey/SankeyLink.d.ts.map +1 -1
  170. package/Sankey/PureSankey/SankeyNode.d.ts +5 -2
  171. package/Sankey/PureSankey/SankeyNode.d.ts.map +1 -1
  172. package/Sankey/PureSankey/SankeyUtils.d.ts.map +1 -1
  173. package/Sankey/Sankey.d.ts +3 -1
  174. package/Sankey/Sankey.d.ts.map +1 -1
  175. package/Sankey.js +508 -219
  176. package/Sankey.js.map +4 -4
  177. package/Scatter.config.js +3 -5
  178. package/Scatter.config.js.map +2 -2
  179. package/Scatter.js +244 -146
  180. package/Scatter.js.map +4 -4
  181. package/SingleValue/SingleValue.d.ts.map +1 -1
  182. package/SingleValue.js +273 -173
  183. package/SingleValue.js.map +4 -4
  184. package/SingleValueBasic.js +4 -4
  185. package/SingleValueBasic.js.map +2 -2
  186. package/SingleValueIcon/SingleValueIcon.d.ts.map +1 -1
  187. package/SingleValueIcon.js +264 -164
  188. package/SingleValueIcon.js.map +4 -4
  189. package/SingleValueRadial.js +267 -167
  190. package/SingleValueRadial.js.map +4 -4
  191. package/SparkLine/SparkLine.d.ts.map +1 -1
  192. package/SparkLine.js.map +2 -2
  193. package/Table/PureTable.d.ts.map +1 -1
  194. package/Table/Table.d.ts +2 -5
  195. package/Table/Table.d.ts.map +1 -1
  196. package/Table/hooks.d.ts.map +1 -1
  197. package/Table.config.js +1 -1
  198. package/Table.config.js.map +2 -2
  199. package/Table.js +293 -271
  200. package/Table.js.map +4 -4
  201. package/Timeline/Timeline.d.ts +3 -1
  202. package/Timeline/Timeline.d.ts.map +1 -1
  203. package/Timeline.config.js +2 -2
  204. package/Timeline.config.js.map +2 -2
  205. package/Timeline.js +266 -142
  206. package/Timeline.js.map +4 -4
  207. package/Treemap/Treemap.d.ts +3 -1
  208. package/Treemap/Treemap.d.ts.map +1 -1
  209. package/Treemap.js +263 -147
  210. package/Treemap.js.map +4 -4
  211. package/common/Charting.js +8 -10
  212. package/common/Charting.js.map +2 -2
  213. package/common/ChartingApi.d.ts.map +1 -1
  214. package/common/ChartingApi.js +5 -2
  215. package/common/ChartingApi.js.map +2 -2
  216. package/common/DocExampleWithVizSandbox.js +3 -3
  217. package/common/DocExampleWithVizSandbox.js.map +2 -2
  218. package/common/GaugeMajorTicks.js.map +2 -2
  219. package/common/GaugeValueMarker.js.map +2 -2
  220. package/common/OptionsDoc.js +1 -1
  221. package/common/OptionsDoc.js.map +2 -2
  222. package/common/OverviewDoc.js +3 -3
  223. package/common/OverviewDoc.js.map +2 -2
  224. package/common/ThemesDoc.js.map +2 -2
  225. package/common/TimeSeriesChartWrapper.js +10 -9
  226. package/common/TimeSeriesChartWrapper.js.map +2 -2
  227. package/common/chartingUtils.d.ts.map +1 -1
  228. package/common/chartingUtils.js +12 -11
  229. package/common/chartingUtils.js.map +2 -2
  230. package/common/components/IconPlaceholder.d.ts.map +1 -1
  231. package/common/docUtils.d.ts.map +1 -1
  232. package/common/docUtils.js +15 -6
  233. package/common/docUtils.js.map +2 -2
  234. package/common/editorConfig/AxesChartDataDisplay.d.ts.map +1 -1
  235. package/common/gaugeUtils.d.ts.map +1 -1
  236. package/common/gaugeUtils.js +4 -2
  237. package/common/gaugeUtils.js.map +2 -2
  238. package/common/hooks/useSorting.d.ts.map +1 -1
  239. package/common/interfaces/VizEvent.d.ts +7 -0
  240. package/common/interfaces/VizEvent.d.ts.map +1 -1
  241. package/common/utils/dataUtils.d.ts.map +1 -1
  242. package/common/utils/dataUtils.js +6 -10
  243. package/common/utils/dataUtils.js.map +2 -2
  244. package/common/utils/featureFlagUtils.js +2 -2
  245. package/common/utils/featureFlagUtils.js.map +2 -2
  246. package/common/utils/focusUtils.js +1 -1
  247. package/common/utils/focusUtils.js.map +2 -2
  248. package/common/utils/mapUtils.d.ts.map +1 -1
  249. package/common/utils/mapUtils.js +14 -18
  250. package/common/utils/mapUtils.js.map +2 -2
  251. package/common/utils/singleValueUtils.js +22 -25
  252. package/common/utils/singleValueUtils.js.map +2 -2
  253. package/common/utils/textUtils.d.ts.map +1 -1
  254. package/common/utils/textUtils.js +37 -23
  255. package/common/utils/textUtils.js.map +2 -2
  256. package/common/utils/trellisUtils.d.ts.map +1 -1
  257. package/common/utils/trellisUtils.js +18 -17
  258. package/common/utils/trellisUtils.js.map +2 -2
  259. package/common/utils/urlUtils.js.map +2 -2
  260. package/common/utils/visualizationTheme.d.ts +15 -0
  261. package/common/utils/visualizationTheme.d.ts.map +1 -0
  262. package/common/utils/visualizationTheme.js +72 -0
  263. package/common/utils/visualizationTheme.js.map +7 -0
  264. package/common/withDashboardViz.d.ts +3 -1
  265. package/common/withDashboardViz.d.ts.map +1 -1
  266. package/common/withDashboardViz.js +216 -105
  267. package/common/withDashboardViz.js.map +4 -4
  268. package/docs-llm/network-graph/options.md +2 -2
  269. package/docs-llm/pie/examples-json.md +195 -0
  270. package/docs-llm/pie/examples-react.md +123 -0
  271. package/docs-llm/pie/options.md +1 -1
  272. package/docs-llm/process-tree/options.md +3 -2
  273. package/package.json +24 -24
package/RichText.js CHANGED
@@ -288,6 +288,11 @@ var config = {
288
288
  events: {
289
289
  "richtext.click": {
290
290
  description: "triggered when user clicks on rich text area not formatted as a link"
291
+ },
292
+ "link.open": {
293
+ description: "triggered when the user activates a link; payload carries the resolved url",
294
+ // Default behavior: fires ungated by event handlers and in edit mode too.
295
+ source: "default"
291
296
  }
292
297
  },
293
298
  supports: ["dynamic-options" /* DYNAMIC_OPTIONS */, "events" /* EVENTS */],
@@ -550,7 +555,10 @@ var useSortingParams = ({ requestParams, onRequestParamsChange }) => {
550
555
  onSort = (e, { sortKey, sortDir }) => {
551
556
  if (typeof sortKey === "string") {
552
557
  const nextSortDir = (0, lodash_exports.has)(nextSortDirMap, sortDir) ? nextSortDirMap[sortDir] : "none";
553
- onRequestParamsChange(__spreadValues(__spreadValues({}, requestParams), { offset: 0, sort: { [sortKey]: nextSortDir } }));
558
+ onRequestParamsChange(__spreadProps(__spreadValues({}, requestParams), {
559
+ offset: 0,
560
+ sort: { [sortKey]: nextSortDir }
561
+ }));
554
562
  } else {
555
563
  onRequestParamsChange(requestParams);
556
564
  }
@@ -685,7 +693,7 @@ var Cover = styled_components_default.div`
685
693
  bottom: 0;
686
694
  `;
687
695
  var Blocker = styled_components_default.div.attrs({
688
- "data-splunk-visualization-version": "28.8.0 - 633c53372"
696
+ "data-splunk-visualization-version": "28.9.0 - 96b03188d"
689
697
  })`
690
698
  position: relative;
691
699
  width: 100%;
@@ -784,7 +792,7 @@ var withFixedSizeContainer = (Viz) => {
784
792
  FixSizeItem,
785
793
  {
786
794
  "data-test": "fix-size-item",
787
- "data-splunk-visualization-version": "28.8.0 - 633c53372",
795
+ "data-splunk-visualization-version": "28.9.0 - 96b03188d",
788
796
  width,
789
797
  height,
790
798
  backgroundColor
@@ -805,6 +813,14 @@ var shouldShowIconPlaceholder = (dataSources, loading = false) => {
805
813
  const noFields = fields === void 0;
806
814
  return loading || noData || noFields;
807
815
  };
816
+ var PlaceholderContainer = styled_components_default.div`
817
+ /* The inline token color wins when supported. Older browsers discard an
818
+ unsupported oklch value and retain this inherited fallback instead. */
819
+ color: ${(0, themes_exports.pick)({
820
+ dark: "#fafafa",
821
+ light: "#2c2c2c"
822
+ })};
823
+ `;
808
824
  var IconPlaceholder = (props) => {
809
825
  const {
810
826
  width = SplunkVisualization_default.defaults.width,
@@ -819,7 +835,6 @@ var IconPlaceholder = (props) => {
819
835
  style: {
820
836
  left: "50%",
821
837
  top: "50%",
822
- color: iconColor,
823
838
  opacity: 0.15,
824
839
  position: "absolute",
825
840
  transform: "translate(-50%, -50%)"
@@ -829,7 +844,14 @@ var IconPlaceholder = (props) => {
829
844
  "data-test": "icon-placeholder"
830
845
  });
831
846
  }
832
- return /* @__PURE__ */ react_exports.createElement("div", { style: { width, height, background: backgroundColor } }, content);
847
+ return /* @__PURE__ */ react_exports.createElement(
848
+ PlaceholderContainer,
849
+ {
850
+ "data-test": "icon-placeholder-container",
851
+ style: { width, height, background: backgroundColor, color: iconColor }
852
+ },
853
+ content
854
+ );
833
855
  };
834
856
  var IconPlaceholder_default = FixedSizeContainer_default(IconPlaceholder);
835
857
 
@@ -838,7 +860,7 @@ var withPlaceholder = (Visualization, useIconPlaceholder = shouldShowIconPlaceho
838
860
  const { config: config3 } = Visualization;
839
861
  const { themes: themes3 } = config3;
840
862
  const Wrapper = (props) => {
841
- var _a, _b;
863
+ var _a2, _b;
842
864
  const {
843
865
  dataSources,
844
866
  loading,
@@ -847,7 +869,7 @@ var withPlaceholder = (Visualization, useIconPlaceholder = shouldShowIconPlaceho
847
869
  width = SplunkVisualization_default.defaults.width
848
870
  } = props;
849
871
  const showPlaceholder = useIconPlaceholder(dataSources, loading, options);
850
- const icon = (_a = config3.placeholderIcon) != null ? _a : config3.icon;
872
+ const icon = (_a2 = config3.placeholderIcon) != null ? _a2 : config3.icon;
851
873
  const iconColor = variables_default.contentColorActive(props);
852
874
  const bgColorFromTheme = (0, colorUtils_exports.isColor)(options == null ? void 0 : options.backgroundColor) ? options == null ? void 0 : options.backgroundColor : (_b = themes3 == null ? void 0 : themes3.defaultBackgroundColor) == null ? void 0 : _b.call(themes3, props);
853
875
  if (config3.supports.includes("placeholder" /* PLACEHOLDER */) && showPlaceholder) {
@@ -903,7 +925,7 @@ var largestTriangleThreeBuckets = (data, threshold, preferredDownsampleIndices)
903
925
  let avgY = 0;
904
926
  let avgRangeStart = Math.floor((i + 1) * every) + 1;
905
927
  let avgRangeEnd = Math.floor((i + 2) * every) + 1;
906
- avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;
928
+ avgRangeEnd = Math.min(avgRangeEnd, dataLength);
907
929
  const avgRangeLength = avgRangeEnd - avgRangeStart;
908
930
  for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {
909
931
  avgX += Number(data[avgRangeStart][0]);
@@ -938,9 +960,9 @@ var largestTriangleThreeBuckets = (data, threshold, preferredDownsampleIndices)
938
960
  };
939
961
  var strictlyCoerceYColumn = (column, options) => {
940
962
  const isNullCoercionEnabled = options.nullValueDisplay === "zero";
941
- const canLooselyCoerceSomeValues = column.findIndex(
963
+ const canLooselyCoerceSomeValues = column.some(
942
964
  (value) => (0, numberUtils_exports.startsWithNumber)(`${value}`) || isNullCoercionEnabled && value === null
943
- ) >= 0;
965
+ );
944
966
  const coercedColumn = [];
945
967
  const canDownsampleColumn = !column.some((value) => {
946
968
  const coercedValue = Number(value);
@@ -959,7 +981,7 @@ var strictlyCoerceYColumn = (column, options) => {
959
981
  };
960
982
  var strictlyCoerceXColumn = (column, fieldType) => {
961
983
  if (fieldType === "number") {
962
- const coercedXColumn = column.map((xValue) => Number(xValue));
984
+ const coercedXColumn = column.map(Number);
963
985
  if (isColumnStrictlyIncreasing(coercedXColumn, fieldType)) {
964
986
  return coercedXColumn;
965
987
  }
@@ -972,8 +994,8 @@ var strictlyCoerceXColumn = (column, fieldType) => {
972
994
  return [];
973
995
  };
974
996
  var isDownsamplingEnabledForViz = ({ vizConfig }) => {
975
- var _a;
976
- return (_a = vizConfig.supports) == null ? void 0 : _a.includes("downsampling" /* DOWNSAMPLING */);
997
+ var _a2;
998
+ return (_a2 = vizConfig.supports) == null ? void 0 : _a2.includes("downsampling" /* DOWNSAMPLING */);
977
999
  };
978
1000
  var isColumnStrictlyIncreasing = (column, fieldType) => {
979
1001
  return column.every((value, index) => {
@@ -997,9 +1019,9 @@ var tryToCoerceAllDisplayedFields = (ds, xField, yFields, fieldTypes, options) =
997
1019
  let xColumn = [];
998
1020
  const yColumns = [];
999
1021
  const canDownsample = !ds.data.fields.some((field, index) => {
1000
- var _a;
1022
+ var _a2;
1001
1023
  const fieldName = getFieldName(field);
1002
- const fieldType = (_a = fieldTypes[index]) != null ? _a : "unknown";
1024
+ const fieldType = (_a2 = fieldTypes[index]) != null ? _a2 : "unknown";
1003
1025
  const column = ds.data.columns[index];
1004
1026
  let hasDisplayedColumnThatCantBeDownsampled = false;
1005
1027
  if (fieldName === xField) {
@@ -1041,9 +1063,9 @@ var pickIndicesFromDataSource = (ds, indices) => {
1041
1063
  });
1042
1064
  };
1043
1065
  var downsampleDataSources = ({ dataSources, threshold, options }) => {
1044
- var _a, _b, _c;
1066
+ var _a2, _b, _c;
1045
1067
  const primaryDS = dataSources == null ? void 0 : dataSources.primary;
1046
- const numPoints = (_c = (_b = (_a = primaryDS == null ? void 0 : primaryDS.data) == null ? void 0 : _a.columns[0]) == null ? void 0 : _b.length) != null ? _c : 0;
1068
+ const numPoints = (_c = (_b = (_a2 = primaryDS == null ? void 0 : primaryDS.data) == null ? void 0 : _a2.columns[0]) == null ? void 0 : _b.length) != null ? _c : 0;
1047
1069
  if (Number.isNaN(threshold) || numPoints <= threshold || threshold < 2) {
1048
1070
  return dataSources;
1049
1071
  }
@@ -1104,14 +1126,14 @@ var useGetXAndYFields = ({
1104
1126
  dataSources
1105
1127
  }) => {
1106
1128
  const { dataSourcesWithOnlyOnePoint, dataFrameWithOnlyOnePoint } = (0, react_exports.useMemo)(() => {
1107
- var _a, _b, _c;
1129
+ var _a2, _b, _c;
1108
1130
  if (!shouldEvaluateDSL) {
1109
1131
  return {
1110
1132
  dataSourcesWithOnlyOnePoint: null,
1111
1133
  dataFrameWithOnlyOnePoint: null
1112
1134
  };
1113
1135
  }
1114
- if (!((_c = (_b = (_a = dataSources == null ? void 0 : dataSources.primary) == null ? void 0 : _a.data) == null ? void 0 : _b.columns) == null ? void 0 : _c.length)) {
1136
+ if (!((_c = (_b = (_a2 = dataSources == null ? void 0 : dataSources.primary) == null ? void 0 : _a2.data) == null ? void 0 : _b.columns) == null ? void 0 : _c.length)) {
1115
1137
  return {
1116
1138
  dataSourcesWithOnlyOnePoint: null,
1117
1139
  dataFrameWithOnlyOnePoint: null
@@ -1264,10 +1286,10 @@ var FeatureFlags_default = "default" in defaultImport27 ? defaultImport27.defaul
1264
1286
 
1265
1287
  // src/common/utils/featureFlagUtils.ts
1266
1288
  var getFeatureFlag = (context, flagName) => {
1267
- if (context && Object.keys(context).find((key) => key === flagName)) {
1289
+ if (context && Object.keys(context).includes(flagName)) {
1268
1290
  return context[flagName];
1269
1291
  }
1270
- if (Object.keys(FeatureFlags_default).find((key) => key === flagName)) {
1292
+ if (Object.keys(FeatureFlags_default).includes(flagName)) {
1271
1293
  return FeatureFlags_default[flagName];
1272
1294
  }
1273
1295
  return false;
@@ -1373,16 +1395,16 @@ var triangleEventAnnotationRenderer = ({
1373
1395
  var shouldEnableSearchZoom = (eventHandlers = [], xField = "") => {
1374
1396
  const rangeSelectEventHandler = eventHandlers.find(
1375
1397
  (eventHandler) => {
1376
- var _a;
1377
- return (_a = eventHandler.options.events) == null ? void 0 : _a.includes("range.select");
1398
+ var _a2;
1399
+ return (_a2 = eventHandler.options.events) == null ? void 0 : _a2.includes("range.select");
1378
1400
  }
1379
1401
  );
1380
1402
  const xAxisIsTime = xField === "_time";
1381
1403
  return !!rangeSelectEventHandler && xAxisIsTime;
1382
1404
  };
1383
- var canvasSupportedTimeSeriesCharts = ["splunk.line", "splunk.area"];
1405
+ var canvasSupportedTimeSeriesCharts = /* @__PURE__ */ new Set(["splunk.line", "splunk.area"]);
1384
1406
  var isTimeSeriesCanvasRenderSupported = (vizConfigKey) => {
1385
- return canvasSupportedTimeSeriesCharts.includes(vizConfigKey);
1407
+ return canvasSupportedTimeSeriesCharts.has(vizConfigKey);
1386
1408
  };
1387
1409
  var filterChartDataFromInternalFields = (chartData) => {
1388
1410
  const { fields, columns } = chartData;
@@ -1398,7 +1420,7 @@ var filterChartDataFromInternalFields = (chartData) => {
1398
1420
  return { fields: filteredFields, columns: filteredColumns };
1399
1421
  };
1400
1422
  var convert2DArrayToNumbers = (arr) => {
1401
- return arr.map((subArray) => subArray.map((element) => parseFloat(element)));
1423
+ return arr.map((subArray) => subArray.map((element) => Number.parseFloat(element)));
1402
1424
  };
1403
1425
  var parseAxisValue = (val) => {
1404
1426
  if (val === void 0 || val === null || val === "auto" || val === "") {
@@ -1436,6 +1458,7 @@ var getLegend = (props) => {
1436
1458
  return (0, visualization_canvas_exports.TopLegendFactory)(__spreadValues({
1437
1459
  wrap: true
1438
1460
  }, commonLegendProps));
1461
+ // Note: By default, use right legend
1439
1462
  default:
1440
1463
  return (0, visualization_canvas_exports.SideLegendFactory)(__spreadValues({}, commonLegendProps));
1441
1464
  }
@@ -1547,7 +1570,7 @@ var getY2Scale = (field, y2fields, overlayFields) => {
1547
1570
  return assignToY2 ? "y2" : "y";
1548
1571
  };
1549
1572
  var getSeriesOverrides = (opts) => {
1550
- var _a;
1573
+ var _a2;
1551
1574
  const {
1552
1575
  yfields,
1553
1576
  y2fields,
@@ -1568,20 +1591,20 @@ var getSeriesOverrides = (opts) => {
1568
1591
  let spanGaps;
1569
1592
  if (nullValueMode === "gaps") {
1570
1593
  spanGaps = false;
1571
- } else if (nullValueMode != null) {
1572
- spanGaps = true;
1573
- } else {
1594
+ } else if (nullValueMode == null) {
1574
1595
  spanGaps = void 0;
1596
+ } else {
1597
+ spanGaps = true;
1575
1598
  }
1576
1599
  const replaceNullsWithZero = nullValueMode === "zero" ? true : void 0;
1577
1600
  const isAreaChart = type === "area";
1578
1601
  const isStacked = isAreaChart && (stackMode === "stacked" || stackMode === "stacked100");
1579
1602
  const areaFields = isAreaChart ? yfields.filter((f) => !(overlayFields == null ? void 0 : overlayFields.includes(f))) : yfields;
1580
- const overlayFieldsInOrder = (_a = overlayFields == null ? void 0 : overlayFields.filter((f) => yfields.includes(f))) != null ? _a : [];
1603
+ const overlayFieldsInOrder = (_a2 = overlayFields == null ? void 0 : overlayFields.filter((f) => yfields.includes(f))) != null ? _a2 : [];
1581
1604
  const orderedFields = isAreaChart ? [...areaFields, ...overlayFieldsInOrder] : yfields;
1582
1605
  orderedFields.forEach((field) => {
1583
- var _a2;
1584
- const isOverlay = (_a2 = overlayFields == null ? void 0 : overlayFields.includes(field)) != null ? _a2 : false;
1606
+ var _a3;
1607
+ const isOverlay = (_a3 = overlayFields == null ? void 0 : overlayFields.includes(field)) != null ? _a3 : false;
1585
1608
  const isPercent = isAreaChart && stackMode === "stacked100" && !isOverlay;
1586
1609
  const shouldHideAreaOutline = isAreaChart && showLines === false && !isOverlay;
1587
1610
  seriesConfig[field] = {
@@ -1774,11 +1797,11 @@ var handleLegendClick = (chartEvent, onClick, trellisKey, trellisSplitBy) => {
1774
1797
  }
1775
1798
  };
1776
1799
  var handleRangeSelection = (rangeEvent, onSelect, chartData, trellisKey, trellisSplitBy) => {
1777
- var _a;
1800
+ var _a2;
1778
1801
  if (!rangeEvent) {
1779
1802
  return;
1780
1803
  }
1781
- const xData = ((_a = chartData == null ? void 0 : chartData.columns) == null ? void 0 : _a[0]) || [];
1804
+ const xData = ((_a2 = chartData == null ? void 0 : chartData.columns) == null ? void 0 : _a2[0]) || [];
1782
1805
  const { startXIndex, endXIndex } = findRangeIndices(xData, rangeEvent.start, rangeEvent.end);
1783
1806
  const payload = {
1784
1807
  startXIndex,
@@ -1796,8 +1819,8 @@ var handleRangeSelection = (rangeEvent, onSelect, chartData, trellisKey, trellis
1796
1819
  }
1797
1820
  };
1798
1821
  var handleRangeZoom = (rangeEvent, onSelect, chartData, trellisKey, trellisSplitBy) => {
1799
- var _a;
1800
- const xData = ((_a = chartData == null ? void 0 : chartData.columns) == null ? void 0 : _a[0]) || [];
1822
+ var _a2;
1823
+ const xData = ((_a2 = chartData == null ? void 0 : chartData.columns) == null ? void 0 : _a2[0]) || [];
1801
1824
  const { startXIndex, endXIndex } = findRangeIndices(xData, rangeEvent.start, rangeEvent.end);
1802
1825
  const payload = {
1803
1826
  startXIndex,
@@ -1857,7 +1880,7 @@ var getYAxisTitles = ({
1857
1880
  };
1858
1881
  var TimeSeriesChartWrapper = (props) => {
1859
1882
  var _b, _c, _d;
1860
- const _a = props, {
1883
+ const _a2 = props, {
1861
1884
  width,
1862
1885
  height,
1863
1886
  chartData,
@@ -1883,7 +1906,7 @@ var TimeSeriesChartWrapper = (props) => {
1883
1906
  y2AxisLineVisibility,
1884
1907
  showYAxisWithZero: showYAxisWithZeroFromProps,
1885
1908
  showY2AxisWithZero: showY2AxisWithZeroFromProps
1886
- } = _a, otherOptions = __objRest(_a, [
1909
+ } = _a2, otherOptions = __objRest(_a2, [
1887
1910
  "width",
1888
1911
  "height",
1889
1912
  "chartData",
@@ -2002,11 +2025,11 @@ var TimeSeriesChartWrapper = (props) => {
2002
2025
  y2AxisMajorUnitFromSimpleXML,
2003
2026
  y2AxisMajorTickInterval
2004
2027
  );
2005
- const xAxisMajorTickSizeNum = xAxisMajorTickSize != null ? Number(xAxisMajorTickSize) : void 0;
2006
- const yAxisMajorTickSizeNum = yAxisMajorTickSize != null ? Number(yAxisMajorTickSize) : void 0;
2007
- const y2AxisMajorTickSizeNum = y2AxisMajorTickSize != null ? Number(y2AxisMajorTickSize) : void 0;
2008
- const yAxisMinorTickSizeNum = yAxisMinorTickSize != null ? Number(yAxisMinorTickSize) : void 0;
2009
- const y2AxisMinorTickSizeNum = y2AxisMinorTickSize != null ? Number(y2AxisMinorTickSize) : void 0;
2028
+ const xAxisMajorTickSizeNum = xAxisMajorTickSize == null ? void 0 : Number(xAxisMajorTickSize);
2029
+ const yAxisMajorTickSizeNum = yAxisMajorTickSize == null ? void 0 : Number(yAxisMajorTickSize);
2030
+ const y2AxisMajorTickSizeNum = y2AxisMajorTickSize == null ? void 0 : Number(y2AxisMajorTickSize);
2031
+ const yAxisMinorTickSizeNum = yAxisMinorTickSize == null ? void 0 : Number(yAxisMinorTickSize);
2032
+ const y2AxisMinorTickSizeNum = y2AxisMinorTickSize == null ? void 0 : Number(y2AxisMinorTickSize);
2010
2033
  const areaOpacityForCanvas = getAreaOpacityForCanvas(areaOpacity);
2011
2034
  const seriesColors = seriesColorsStr ? JSON.parse(seriesColorsStr) : void 0;
2012
2035
  const seriesColorsByField = fieldColors ? JSON.parse(fieldColors) : void 0;
@@ -2418,6 +2441,76 @@ var buildEventCallbackProps = (supportedEvents, evaluatedOptionsToUse, onEventTr
2418
2441
  });
2419
2442
  return result;
2420
2443
  };
2444
+ var buildAllEventCallbackProps = (events, evaluatedOptionsToUse, onEventTrigger, { supportsEvents, hasEventHandlers, mode }) => {
2445
+ if (!supportsEvents) return {};
2446
+ const defaultEvents = {};
2447
+ const userEvents = {};
2448
+ Object.entries(events || {}).forEach(([eventKey, eventConfig]) => {
2449
+ (eventConfig.source === "default" ? defaultEvents : userEvents)[eventKey] = eventConfig;
2450
+ });
2451
+ const userProps = hasEventHandlers && mode === "view" ? buildEventCallbackProps(userEvents, evaluatedOptionsToUse, onEventTrigger) : {};
2452
+ return __spreadValues(__spreadValues({}, userProps), buildEventCallbackProps(defaultEvents, evaluatedOptionsToUse, onEventTrigger));
2453
+ };
2454
+ var applyContextTimezone = (localeContext) => {
2455
+ if (localeContext.serializedTimezone && !moment_default.getDefaultSplunkTimezone()) {
2456
+ moment_default.setDefaultSplunkTimezone(localeContext.serializedTimezone);
2457
+ }
2458
+ };
2459
+ var getAsyncOptionsEvaluationParams = ({
2460
+ visualizationID,
2461
+ props,
2462
+ optionsToEvaluate,
2463
+ downsampledDataSources,
2464
+ vizConfig,
2465
+ bypassCloneDeepOptionScope,
2466
+ lazyLoadingDataFrame
2467
+ }) => {
2468
+ return {
2469
+ visualizationID,
2470
+ props,
2471
+ options: __spreadValues({}, optionsToEvaluate),
2472
+ dataSources: downsampledDataSources,
2473
+ theme: vizConfig.themes,
2474
+ bypassCloneDeepOptionScope,
2475
+ lazyLoadingDataFrame
2476
+ };
2477
+ };
2478
+ var evaluateOptionsSync = ({
2479
+ optionsToEvaluate,
2480
+ downsampledDataSources,
2481
+ dataSourcesInState,
2482
+ dataFramesInState,
2483
+ setDataSourcesInState,
2484
+ setDataFramesInState,
2485
+ computeDataFrames,
2486
+ featureFlagContext,
2487
+ themeFunc
2488
+ }) => {
2489
+ let dataFrames = dataFramesInState;
2490
+ if (downsampledDataSources !== dataSourcesInState) {
2491
+ setDataSourcesInState(downsampledDataSources);
2492
+ dataFrames = Options_exports.Options.dataFrameFromDataSource(
2493
+ downsampledDataSources,
2494
+ getFeatureFlag(featureFlagContext, "visualizations_lazyLoadingDataFrame")
2495
+ );
2496
+ setDataFramesInState(dataFrames);
2497
+ }
2498
+ let mergedFrames = dataFrames;
2499
+ if (computeDataFrames && dataFrames) {
2500
+ const derivedFrames = computeDataFrames({
2501
+ dataSources: downsampledDataSources,
2502
+ options: optionsToEvaluate.options
2503
+ });
2504
+ mergedFrames = __spreadValues(__spreadValues({}, dataFrames), derivedFrames);
2505
+ }
2506
+ return Options_exports.Options.evaluate(
2507
+ optionsToEvaluate,
2508
+ downsampledDataSources,
2509
+ themeFunc,
2510
+ mergedFrames,
2511
+ getFeatureFlag(featureFlagContext, "visualizations_bypassCloneDeepOptionScope")
2512
+ );
2513
+ };
2421
2514
  var withDashboardViz = (opts) => {
2422
2515
  const {
2423
2516
  ReactViz,
@@ -2433,7 +2526,7 @@ var withDashboardViz = (opts) => {
2433
2526
  const SanitizedReactViz = (0, SanitizeProps_exports.withSanitizedProps)(ReactViz);
2434
2527
  const defaultOptions = (0, JSONSchemaUtils_exports.pickFieldFromJSONSchema)(vizConfig.optionsSchema, "default");
2435
2528
  const DashboardViz = (props) => {
2436
- var _a;
2529
+ var _a2;
2437
2530
  const {
2438
2531
  mode = "view",
2439
2532
  hasEventHandlers,
@@ -2449,14 +2542,10 @@ var withDashboardViz = (opts) => {
2449
2542
  onRequestParamsChange = lodash_exports.noop
2450
2543
  } = props;
2451
2544
  const localeContext = react_exports.useContext(TimezoneContext_default);
2452
- if (localeContext.serializedTimezone) {
2453
- if (!moment_default.getDefaultSplunkTimezone()) {
2454
- moment_default.setDefaultSplunkTimezone(localeContext.serializedTimezone);
2455
- }
2456
- }
2545
+ applyContextTimezone(localeContext);
2457
2546
  const themeFunc = (themeVar) => {
2458
- var _a2, _b;
2459
- return (_b = (_a2 = vizConfig.themes)[themeVar]) == null ? void 0 : _b.call(_a2, props);
2547
+ var _a3, _b;
2548
+ return (_b = (_a3 = vizConfig.themes)[themeVar]) == null ? void 0 : _b.call(_a3, props);
2460
2549
  };
2461
2550
  const {
2462
2551
  family: currentThemeFamily,
@@ -2476,16 +2565,21 @@ var withDashboardViz = (opts) => {
2476
2565
  featureFlagContext == null ? void 0 : featureFlagContext.visualizations_enableDownsampling
2477
2566
  );
2478
2567
  const isTrellisFeatureFlagOn = Boolean(featureFlagContext == null ? void 0 : featureFlagContext.visualizations_enableTrellis);
2479
- const isTrellisOn = isTrellisFeatureFlagOn && ((_a = vizConfig == null ? void 0 : vizConfig.supports) == null ? void 0 : _a.includes("trellis" /* TRELLIS */)) && (options == null ? void 0 : options.splitByLayout) === "trellis" /* TRELLIS */;
2568
+ const isTrellisOn = isTrellisFeatureFlagOn && ((_a2 = vizConfig == null ? void 0 : vizConfig.supports) == null ? void 0 : _a2.includes("trellis" /* TRELLIS */)) && (options == null ? void 0 : options.splitByLayout) === "trellis" /* TRELLIS */;
2480
2569
  const isAcceleratedRenderFeatureFlagOn = Boolean(
2481
2570
  featureFlagContext == null ? void 0 : featureFlagContext.visualizations_enableAcceleratedRender
2482
2571
  );
2483
2572
  const isAcceleratedRenderOn = isAcceleratedRenderFeatureFlagOn && isTimeSeriesCanvasRenderSupported(vizConfig.key) && (options == null ? void 0 : options.acceleratedRender) === true;
2484
- const isMounted = react_exports.useRef(true);
2573
+ const bypassCloneDeepOptionScope = Boolean(
2574
+ getFeatureFlag(featureFlagContext, "visualizations_bypassCloneDeepOptionScope")
2575
+ );
2576
+ const lazyLoadingDataFrame = Boolean(
2577
+ getFeatureFlag(featureFlagContext, "visualizations_lazyLoadingDataFrame")
2578
+ );
2485
2579
  const optionsToEvaluate = react_exports.useMemo(() => {
2486
- var _a2;
2580
+ var _a3;
2487
2581
  const legendDisplay = turnOffLegendDisplayWhenTrellisIsOn(isTrellisOn, options);
2488
- const computedOptions = (_a2 = computeVizPropsBeforeEval(options)) != null ? _a2 : {};
2582
+ const computedOptions = (_a3 = computeVizPropsBeforeEval(options)) != null ? _a3 : {};
2489
2583
  return {
2490
2584
  context: (0, lodash_exports.defaultsDeep)({}, context, vizConfig.defaultContext),
2491
2585
  options: (0, hocUtils_exports.deepMergeWithArrayPrimitiveOverrides)(
@@ -2520,63 +2614,74 @@ var withDashboardViz = (opts) => {
2520
2614
  threshold,
2521
2615
  isDownsamplingEnabled
2522
2616
  });
2523
- evaluatedOptions = useDeepMemo(() => {
2617
+ const asyncOptionsEvaluationParams = useDeepMemo(
2618
+ () => getAsyncOptionsEvaluationParams({
2619
+ visualizationID,
2620
+ props,
2621
+ optionsToEvaluate,
2622
+ downsampledDataSources,
2623
+ vizConfig,
2624
+ bypassCloneDeepOptionScope,
2625
+ lazyLoadingDataFrame
2626
+ }),
2627
+ [
2628
+ visualizationID,
2629
+ optionsToEvaluate,
2630
+ downsampledDataSources,
2631
+ vizConfig,
2632
+ bypassCloneDeepOptionScope,
2633
+ lazyLoadingDataFrame,
2634
+ currentThemeFamily,
2635
+ currentThemeColorScheme,
2636
+ currentThemeDensity,
2637
+ localeContext.serializedTimezone
2638
+ ]
2639
+ );
2640
+ react_exports.useEffect(() => {
2641
+ if (!useAsyncEvaluatedOptions) {
2642
+ return void 0;
2643
+ }
2644
+ let ownsEvaluation = true;
2524
2645
  try {
2525
- if (useAsyncEvaluatedOptions) {
2526
- const asyncDynamicOptionsEvaluatorParams = {
2527
- visualizationID,
2528
- props,
2529
- options: optionsToEvaluate,
2530
- dataSources: downsampledDataSources,
2531
- theme: vizConfig.themes,
2532
- bypassCloneDeepOptionScope: Boolean(
2533
- getFeatureFlag(featureFlagContext, "visualizations_bypassCloneDeepOptionScope")
2534
- ),
2535
- lazyLoadingDataFrame: Boolean(
2536
- getFeatureFlag(featureFlagContext, "visualizations_lazyLoadingDataFrame")
2537
- )
2538
- };
2539
- async_dynamic_options_evaluator_default.evaluate(asyncDynamicOptionsEvaluatorParams).then((results) => {
2646
+ async_dynamic_options_evaluator_default.evaluate(asyncOptionsEvaluationParams).then((results) => {
2647
+ if (ownsEvaluation) {
2540
2648
  setEvaluatedOptionsAsync(results.results);
2541
- }).catch(() => {
2542
- if (isMounted.current) {
2543
- setUseAsyncEvaluatedOptions(false);
2544
- }
2545
- });
2546
- } else {
2547
- let dataFrames = dataFramesInState;
2548
- if (downsampledDataSources !== dataSourcesInState) {
2549
- setDataSourcesInState(downsampledDataSources);
2550
- dataFrames = Options_exports.Options.dataFrameFromDataSource(
2551
- downsampledDataSources,
2552
- getFeatureFlag(featureFlagContext, "visualizations_lazyLoadingDataFrame")
2553
- );
2554
- setDataFramesInState(dataFrames);
2555
2649
  }
2556
- let mergedFrames = dataFrames;
2557
- if (computeDataFrames && dataFrames) {
2558
- const derivedFrames = computeDataFrames({
2559
- dataSources: downsampledDataSources,
2560
- options: optionsToEvaluate.options
2561
- });
2562
- mergedFrames = __spreadValues(__spreadValues({}, dataFrames), derivedFrames);
2650
+ }).catch(() => {
2651
+ if (ownsEvaluation) {
2652
+ setUseAsyncEvaluatedOptions(false);
2563
2653
  }
2564
- const result = Options_exports.Options.evaluate(
2565
- optionsToEvaluate,
2566
- downsampledDataSources,
2567
- themeFunc,
2568
- mergedFrames,
2569
- getFeatureFlag(featureFlagContext, "visualizations_bypassCloneDeepOptionScope")
2570
- );
2571
- return result;
2654
+ });
2655
+ } catch (e) {
2656
+ setUseAsyncEvaluatedOptions(false);
2657
+ }
2658
+ return () => {
2659
+ ownsEvaluation = false;
2660
+ async_dynamic_options_evaluator_default.reset(visualizationID);
2661
+ };
2662
+ }, [asyncOptionsEvaluationParams, useAsyncEvaluatedOptions, visualizationID]);
2663
+ evaluatedOptions = useDeepMemo(() => {
2664
+ try {
2665
+ if (useAsyncEvaluatedOptions) {
2666
+ return {};
2572
2667
  }
2668
+ return evaluateOptionsSync({
2669
+ optionsToEvaluate,
2670
+ downsampledDataSources,
2671
+ dataSourcesInState,
2672
+ dataFramesInState,
2673
+ setDataSourcesInState,
2674
+ setDataFramesInState,
2675
+ computeDataFrames,
2676
+ featureFlagContext,
2677
+ themeFunc
2678
+ });
2573
2679
  } catch (e) {
2574
2680
  if (e instanceof Error) {
2575
2681
  console.error(`unexpected error evaluating options: ${e.message}`);
2576
2682
  }
2577
2683
  return {};
2578
2684
  }
2579
- return {};
2580
2685
  }, [
2581
2686
  currentThemeFamily,
2582
2687
  currentThemeColorScheme,
@@ -2586,7 +2691,7 @@ var withDashboardViz = (opts) => {
2586
2691
  localeContext.serializedTimezone,
2587
2692
  useAsyncEvaluatedOptions
2588
2693
  ]);
2589
- const evaluatedOptionsToUse = !useAsyncEvaluatedOptions ? evaluatedOptions : evaluatedOptionsAsync;
2694
+ const evaluatedOptionsToUse = useAsyncEvaluatedOptions ? evaluatedOptionsAsync : evaluatedOptions;
2590
2695
  let dataSourceMetadata = {};
2591
2696
  const OptionKey = "paginateDataSourceKey";
2592
2697
  const optsKey = (0, lodash_exports.has)(evaluatedOptionsToUse, OptionKey) && evaluatedOptionsToUse[OptionKey];
@@ -2608,7 +2713,7 @@ var withDashboardViz = (opts) => {
2608
2713
  sortParams,
2609
2714
  paginatorParams
2610
2715
  };
2611
- if (vizConfig.supports.indexOf("page-and-sort" /* PAGE_AND_SORT */) === -1 && !(0, lodash_exports.has)(dataSources, paginateDataSourceKey)) {
2716
+ if (!vizConfig.supports.includes("page-and-sort" /* PAGE_AND_SORT */) && !(0, lodash_exports.has)(dataSources, paginateDataSourceKey)) {
2612
2717
  dataSourceMetadata = {};
2613
2718
  }
2614
2719
  const clonedEvaluatedOptions = __spreadValues({}, evaluatedOptionsToUse);
@@ -2618,14 +2723,6 @@ var withDashboardViz = (opts) => {
2618
2723
  react_exports.useEffect(() => {
2619
2724
  onComputedProps(clonedEvaluatedOptions);
2620
2725
  });
2621
- react_exports.useEffect(() => {
2622
- return () => {
2623
- if (useAsyncEvaluatedOptions) {
2624
- isMounted.current = false;
2625
- async_dynamic_options_evaluator_default.reset(visualizationID);
2626
- }
2627
- };
2628
- }, []);
2629
2726
  const { requiredProps = [], supports } = vizConfig;
2630
2727
  const missing = missingKeys(requiredProps, evaluatedOptionsToUse);
2631
2728
  if (missing.length > 0 && supports.includes("placeholder" /* PLACEHOLDER */) && vizConfig.key !== "splunk.singlevalue") {
@@ -2640,7 +2737,16 @@ var withDashboardViz = (opts) => {
2640
2737
  }
2641
2738
  );
2642
2739
  }
2643
- const eventCallbackProps = hasEventHandlers && mode === "view" && vizConfig.supports.includes("events" /* EVENTS */) ? buildEventCallbackProps(vizConfig.events, evaluatedOptionsToUse, onEventTrigger) : {};
2740
+ const eventCallbackProps = buildAllEventCallbackProps(
2741
+ vizConfig.events,
2742
+ evaluatedOptionsToUse,
2743
+ onEventTrigger,
2744
+ {
2745
+ supportsEvents: vizConfig.supports.includes("events" /* EVENTS */),
2746
+ hasEventHandlers,
2747
+ mode
2748
+ }
2749
+ );
2644
2750
  const computedVizProps = computeVizProps2(__spreadProps(__spreadValues(__spreadProps(__spreadValues(__spreadValues({}, props), evaluatedOptionsToUse), {
2645
2751
  // Align option transformation with the actual renderer selected below.
2646
2752
  // This prevents canvas-only option preservation from leaking into Highcharts mode.
@@ -2668,8 +2774,9 @@ var withDashboardViz = (opts) => {
2668
2774
  onEventTrigger: SplunkVisualization_default.defaults.onEventTrigger
2669
2775
  });
2670
2776
  DashboardViz.config = vizConfig;
2671
- return (0, styled_components_exports.withTheme)(
2672
- withPlaceholder_default(withEditModeCover_default(DashboardViz, disableEditModeCover), useIconPlaceholder)
2777
+ return Object.assign(
2778
+ (0, styled_components_exports.withTheme)(withPlaceholder_default(withEditModeCover_default(DashboardViz, disableEditModeCover), useIconPlaceholder)),
2779
+ { config: vizConfig }
2673
2780
  );
2674
2781
  };
2675
2782
  var withDashboardViz_default = withDashboardViz;
@@ -2755,6 +2862,15 @@ function setMouseSelecting(value) {
2755
2862
  function isMouseSelecting() {
2756
2863
  return mouseSelecting;
2757
2864
  }
2865
+ var suppressNextEditClick = false;
2866
+ function setSuppressNextEditClick(value) {
2867
+ suppressNextEditClick = value;
2868
+ }
2869
+ function consumeSuppressNextEditClick() {
2870
+ const v = suppressNextEditClick;
2871
+ suppressNextEditClick = false;
2872
+ return v;
2873
+ }
2758
2874
 
2759
2875
  // src/RichText/PureRichText/types.ts
2760
2876
  var DEFAULT_TEXT_STYLES = {
@@ -2811,8 +2927,241 @@ var defaultImport36 = __toESM(require("dompurify"));
2811
2927
  __reExport(dompurify_exports, require("dompurify"));
2812
2928
  var dompurify_default = "default" in defaultImport36 ? defaultImport36.default : defaultImport36;
2813
2929
 
2930
+ // src/RichText/PureRichText/hooks/useTokenMap.ts
2931
+ var NAME_CHARS = String.raw` \w.-`;
2932
+ var NAMESPACE_PREFIX = `(?:[${NAME_CHARS}]+:)?`;
2933
+ var NAME = String.raw`(?:(?=[\w.-])[${NAME_CHARS}]*[\w.-])`;
2934
+ var FILTERS = String.raw`(?:\|[a-zA-Z]+)*`;
2935
+ var TOKEN_CONTENT = `${NAMESPACE_PREFIX}${NAME}${FILTERS}`;
2936
+ var TOKEN_PATTERN = new RegExp(String.raw`\$(${TOKEN_CONTENT})\$`, "g");
2937
+ var TOKEN_OR_ESCAPE_PATTERN = new RegExp(
2938
+ String.raw`\$\$|\$(${TOKEN_CONTENT})\$(?=\$${TOKEN_CONTENT}\$|\$\$|[^$]|$)`,
2939
+ "g"
2940
+ );
2941
+ function toValueString(value) {
2942
+ return value === null ? null : String(value);
2943
+ }
2944
+ function normalizeTokenMetadata(metadata, resolvedContent) {
2945
+ const nameToValue = /* @__PURE__ */ new Map();
2946
+ if (!metadata || metadata.length === 0) {
2947
+ return { nameToValue, rawContent: resolvedContent, reconciled: true };
2948
+ }
2949
+ const sorted = [...metadata].sort((a, b) => a.start - b.start);
2950
+ for (const { match, value } of sorted) {
2951
+ const strValue = toValueString(value);
2952
+ if (match !== "$$" && strValue !== null && strValue !== "") {
2953
+ nameToValue.set(match.slice(1, -1), strValue);
2954
+ }
2955
+ }
2956
+ let raw = "";
2957
+ let rawCursor = 0;
2958
+ let resolvedCursor = 0;
2959
+ for (const entry of sorted) {
2960
+ const { match, value, start, end } = entry;
2961
+ const strValue = toValueString(value);
2962
+ const literalLength = start - rawCursor;
2963
+ const expected = strValue != null ? strValue : match;
2964
+ const valuePos = resolvedCursor + literalLength;
2965
+ if (literalLength < 0 || resolvedContent.slice(valuePos, valuePos + expected.length) !== expected) {
2966
+ return { nameToValue, rawContent: resolvedContent, reconciled: false };
2967
+ }
2968
+ raw += resolvedContent.slice(resolvedCursor, valuePos);
2969
+ raw += match;
2970
+ rawCursor = end;
2971
+ resolvedCursor = valuePos + expected.length;
2972
+ }
2973
+ raw += resolvedContent.slice(resolvedCursor);
2974
+ return { nameToValue, rawContent: raw, reconciled: true };
2975
+ }
2976
+ function splitByTokenWildcards(rawContent) {
2977
+ const re = new RegExp(TOKEN_OR_ESCAPE_PATTERN.source, "g");
2978
+ const literals = [];
2979
+ let hasWildcard = false;
2980
+ let buf = "";
2981
+ let lastIndex = 0;
2982
+ let match = re.exec(rawContent);
2983
+ while (match !== null) {
2984
+ buf += rawContent.slice(lastIndex, match.index);
2985
+ if (match[1] === void 0) {
2986
+ buf += "$";
2987
+ } else {
2988
+ literals.push(buf);
2989
+ buf = "";
2990
+ hasWildcard = true;
2991
+ }
2992
+ lastIndex = match.index + match[0].length;
2993
+ match = re.exec(rawContent);
2994
+ }
2995
+ buf += rawContent.slice(lastIndex);
2996
+ literals.push(buf);
2997
+ return { literals, hasWildcard };
2998
+ }
2999
+ function isValueOnlyChange(rawContent, resolvedContent) {
3000
+ var _a2;
3001
+ const { literals, hasWildcard } = splitByTokenWildcards(rawContent);
3002
+ if (!hasWildcard) return resolvedContent === literals[0];
3003
+ const prefix = literals[0];
3004
+ const suffix = (_a2 = literals.at(-1)) != null ? _a2 : "";
3005
+ if (!resolvedContent.startsWith(prefix)) return false;
3006
+ if (!resolvedContent.endsWith(suffix)) return false;
3007
+ let cursor = prefix.length;
3008
+ const end = resolvedContent.length - suffix.length;
3009
+ if (cursor > end) return false;
3010
+ for (let i = 1; i < literals.length - 1; i += 1) {
3011
+ const chunk = literals[i];
3012
+ const idx = resolvedContent.indexOf(chunk, cursor);
3013
+ if (idx === -1 || idx + chunk.length > end) return false;
3014
+ cursor = idx + chunk.length;
3015
+ }
3016
+ return true;
3017
+ }
3018
+ function wrapTreeNodes(nodes, splitLeaf) {
3019
+ const processNode = (node) => {
3020
+ if (slate_exports.Text.isText(node)) {
3021
+ return splitLeaf(node);
3022
+ }
3023
+ if (slate_exports.Element.isElement(node)) {
3024
+ return [__spreadProps(__spreadValues({}, node), { children: node.children.flatMap(processNode) })];
3025
+ }
3026
+ return [node];
3027
+ };
3028
+ return nodes.flatMap(processNode);
3029
+ }
3030
+ function wrapRawTokensInTree(nodes, nameToValue) {
3031
+ return wrapTreeNodes(nodes, (node) => splitTextByRawTokens(node, nameToValue));
3032
+ }
3033
+ function splitTextByRawTokens(textNode, nameToValue) {
3034
+ const _a2 = textNode, {
3035
+ text,
3036
+ tokenName: existingTokenName,
3037
+ isEscapedDollar,
3038
+ isRawToken: existingIsRawToken
3039
+ } = _a2, rest = __objRest(_a2, [
3040
+ "text",
3041
+ "tokenName",
3042
+ "isEscapedDollar",
3043
+ "isRawToken"
3044
+ ]);
3045
+ const marks = __spreadValues({}, rest);
3046
+ if (!text) return [textNode];
3047
+ if (isEscapedDollar) {
3048
+ if (!/^\$+$/.test(text)) return [textNode];
3049
+ const escapeCount = existingIsRawToken ? text.length / 2 : text.length;
3050
+ return [
3051
+ __spreadProps(__spreadValues({}, textNode), {
3052
+ text: displayTextForEscapedDollar(nameToValue).repeat(escapeCount),
3053
+ isRawToken: !nameToValue
3054
+ })
3055
+ ];
3056
+ }
3057
+ if (existingTokenName) {
3058
+ const display = displayTextForToken(existingTokenName, nameToValue);
3059
+ return [__spreadProps(__spreadValues({}, textNode), { text: display, isRawToken: !nameToValue })];
3060
+ }
3061
+ const re = new RegExp(TOKEN_OR_ESCAPE_PATTERN.source, "g");
3062
+ const result = [];
3063
+ let lastIndex = 0;
3064
+ let match = re.exec(text);
3065
+ while (match !== null) {
3066
+ const startIdx = match.index;
3067
+ const fullMatch = match[0];
3068
+ const name = match[1];
3069
+ if (startIdx > lastIndex) {
3070
+ result.push(__spreadValues({ text: text.slice(lastIndex, startIdx) }, marks));
3071
+ }
3072
+ if (name === void 0) {
3073
+ result.push(__spreadProps(__spreadValues({
3074
+ text: displayTextForEscapedDollar(nameToValue)
3075
+ }, marks), {
3076
+ isEscapedDollar: true,
3077
+ isRawToken: !nameToValue
3078
+ }));
3079
+ } else {
3080
+ result.push(__spreadProps(__spreadValues({
3081
+ text: displayTextForToken(name, nameToValue)
3082
+ }, marks), {
3083
+ tokenName: name,
3084
+ isRawToken: !nameToValue
3085
+ }));
3086
+ }
3087
+ lastIndex = startIdx + fullMatch.length;
3088
+ match = re.exec(text);
3089
+ }
3090
+ if (result.length === 0) return [textNode];
3091
+ if (lastIndex < text.length) {
3092
+ result.push(__spreadValues({ text: text.slice(lastIndex) }, marks));
3093
+ }
3094
+ return result;
3095
+ }
3096
+ function displayTextForToken(name, nameToValue) {
3097
+ const value = nameToValue == null ? void 0 : nameToValue.get(name);
3098
+ return value !== void 0 && value !== "" ? value : `$${name}$`;
3099
+ }
3100
+ function displayTextForEscapedDollar(nameToValue) {
3101
+ return nameToValue ? "$" : "$$";
3102
+ }
3103
+ var EMPTY_MAP = /* @__PURE__ */ new Map();
3104
+ function useTokenMap(resolvedContent, richTextTokenMetadata) {
3105
+ var _a2, _b, _c, _d, _e;
3106
+ const contentMetadata = (_a2 = richTextTokenMetadata == null ? void 0 : richTextTokenMetadata.richTextContent) != null ? _a2 : null;
3107
+ const serialized = contentMetadata ? JSON.stringify(contentMetadata) : null;
3108
+ const resultRef = (0, react_exports.useRef)(null);
3109
+ const prevSerializedRef = (0, react_exports.useRef)(null);
3110
+ const prevResolvedRef = (0, react_exports.useRef)("");
3111
+ if (serialized !== prevSerializedRef.current || resolvedContent !== prevResolvedRef.current) {
3112
+ prevSerializedRef.current = serialized;
3113
+ prevResolvedRef.current = resolvedContent;
3114
+ if (contentMetadata) {
3115
+ const next = normalizeTokenMetadata(contentMetadata, resolvedContent);
3116
+ const canReuseStale = !next.reconciled && resultRef.current != null && isValueOnlyChange(resultRef.current.rawContent, resolvedContent);
3117
+ resultRef.current = canReuseStale ? __spreadProps(__spreadValues({}, next), { rawContent: resultRef.current.rawContent }) : next;
3118
+ } else {
3119
+ resultRef.current = null;
3120
+ }
3121
+ }
3122
+ const nameToValue = (_c = (_b = resultRef.current) == null ? void 0 : _b.nameToValue) != null ? _c : EMPTY_MAP;
3123
+ const rawContent = (_e = (_d = resultRef.current) == null ? void 0 : _d.rawContent) != null ? _e : null;
3124
+ return { nameToValue, rawContent };
3125
+ }
3126
+
2814
3127
  // src/RichText/PureRichText/utils/slateUtils.ts
2815
3128
  var sharedDomParser = new DOMParser();
3129
+ var ALLOWED_URI_SCHEMES = ["ftps?", "https?", "mailto", "tel", "callto", "sms", "cid", "xmpp", "file"];
3130
+ var ALLOWED_URI_REGEXP = new RegExp(
3131
+ String.raw`^(?:(?:${ALLOWED_URI_SCHEMES.join("|")}):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))`,
3132
+ "i"
3133
+ );
3134
+ function findInWidgetScroller(el) {
3135
+ var _a2;
3136
+ let node = (_a2 = el == null ? void 0 : el.parentElement) != null ? _a2 : null;
3137
+ while (node && node !== document.body && node !== document.documentElement) {
3138
+ const { overflowY } = globalThis.getComputedStyle(node);
3139
+ if ((overflowY === "auto" || overflowY === "scroll") && node.scrollHeight > node.clientHeight) {
3140
+ return node;
3141
+ }
3142
+ node = node.parentElement;
3143
+ }
3144
+ return null;
3145
+ }
3146
+ function editorContentOverflows(editableEl) {
3147
+ return findInWidgetScroller(editableEl) !== null;
3148
+ }
3149
+ function scrollCaretWithinEditor(editor, domRange) {
3150
+ if (isMouseSelecting()) return;
3151
+ const { selection } = editor;
3152
+ if (selection && !slate_exports.Range.isCollapsed(selection)) return;
3153
+ if (typeof domRange.getBoundingClientRect !== "function") return;
3154
+ const leafEl = domRange.startContainer.parentElement;
3155
+ const scroller = findInWidgetScroller(leafEl);
3156
+ if (!scroller) return;
3157
+ const caret = domRange.getBoundingClientRect();
3158
+ const box = scroller.getBoundingClientRect();
3159
+ if (caret.top < box.top) {
3160
+ scroller.scrollTop -= box.top - caret.top;
3161
+ } else if (caret.bottom > box.bottom) {
3162
+ scroller.scrollTop += caret.bottom - box.bottom;
3163
+ }
3164
+ }
2816
3165
  function safeSelectEnd(editor) {
2817
3166
  try {
2818
3167
  const end = slate_exports.Editor.end(editor, []);
@@ -2820,6 +3169,15 @@ function safeSelectEnd(editor) {
2820
3169
  } catch (e) {
2821
3170
  }
2822
3171
  }
3172
+ function focusSelectOutline(fromEl) {
3173
+ const selectOutline = fromEl == null ? void 0 : fromEl.closest('[data-test="select-outline"]');
3174
+ if (!selectOutline) return;
3175
+ if (!selectOutline.getAttribute("tabindex")) {
3176
+ selectOutline.setAttribute("tabindex", "-1");
3177
+ }
3178
+ selectOutline.style.outline = "none";
3179
+ selectOutline.focus({ preventScroll: true });
3180
+ }
2823
3181
  function safeDeselect(editor) {
2824
3182
  try {
2825
3183
  slate_exports.Transforms.deselect(editor);
@@ -2982,14 +3340,50 @@ function getActiveLink(editor) {
2982
3340
  function slateToPlainText(nodes) {
2983
3341
  return slate_exports.Node.string({ children: nodes });
2984
3342
  }
3343
+ function resolveUrlTokens(url, nameToValue) {
3344
+ if (!nameToValue || nameToValue.size === 0) return url;
3345
+ return url.replace(TOKEN_PATTERN, (match, name) => {
3346
+ var _a2;
3347
+ return (_a2 = nameToValue.get(name)) != null ? _a2 : match;
3348
+ });
3349
+ }
3350
+ function resolveLinkHref(url, nameToValue) {
3351
+ return normalizeUrl(resolveUrlTokens(url, nameToValue));
3352
+ }
3353
+ var DANGEROUS_URL_SCHEMES = /* @__PURE__ */ new Set(["javascript", "data", "vbscript"]);
3354
+ function isOpenableUrl(value) {
3355
+ try {
3356
+ new URL(value);
3357
+ return true;
3358
+ } catch (e) {
3359
+ return false;
3360
+ }
3361
+ }
2985
3362
  function normalizeUrl(url) {
2986
3363
  const trimmed = url.trim();
2987
3364
  if (!trimmed) return trimmed;
2988
- if (/^https?:\/\//i.test(trimmed) || /^mailto:/i.test(trimmed) || /^tel:/i.test(trimmed)) {
3365
+ const schemeMatch = /^([a-z][a-z0-9+-]*):/i.exec(trimmed);
3366
+ if (schemeMatch) {
3367
+ if (DANGEROUS_URL_SCHEMES.has(schemeMatch[1].toLowerCase())) return "";
3368
+ return trimmed;
3369
+ }
3370
+ if (/\$[^$]+\$/.test(trimmed)) {
3371
+ return trimmed;
3372
+ }
3373
+ if (/^[#?/]/.test(trimmed)) {
2989
3374
  return trimmed;
2990
3375
  }
2991
3376
  return `https://${trimmed}`;
2992
3377
  }
3378
+ function stripTokenMarks(marks) {
3379
+ if (!marks) return marks;
3380
+ const styleMarks = __spreadValues({}, marks);
3381
+ delete styleMarks.tokenName;
3382
+ delete styleMarks.tokenOccurrence;
3383
+ delete styleMarks.isRawToken;
3384
+ delete styleMarks.isEscapedDollar;
3385
+ return styleMarks;
3386
+ }
2993
3387
  function insertLink(editor, url, text) {
2994
3388
  if (isLinkActive(editor)) {
2995
3389
  unwrapLink(editor);
@@ -3000,7 +3394,7 @@ function insertLink(editor, url, text) {
3000
3394
  const isCollapsed = slate_exports.Range.isCollapsed(selection);
3001
3395
  let linkChild = { text: text || normalizedUrl };
3002
3396
  if (isCollapsed) {
3003
- const marks = slate_exports.Editor.marks(editor);
3397
+ const marks = stripTokenMarks(slate_exports.Editor.marks(editor));
3004
3398
  if (marks) {
3005
3399
  linkChild = __spreadValues(__spreadValues({}, linkChild), marks);
3006
3400
  }
@@ -3011,7 +3405,7 @@ function insertLink(editor, url, text) {
3011
3405
  children: isCollapsed ? [linkChild] : []
3012
3406
  };
3013
3407
  if (isCollapsed) {
3014
- const marksBeforeInsert = slate_exports.Editor.marks(editor);
3408
+ const marksBeforeInsert = stripTokenMarks(slate_exports.Editor.marks(editor));
3015
3409
  slate_exports.Transforms.insertNodes(editor, link);
3016
3410
  slate_exports.Transforms.move(editor, { unit: "offset" });
3017
3411
  if (marksBeforeInsert) {
@@ -3030,6 +3424,9 @@ function insertLink(editor, url, text) {
3030
3424
  anchor: { path: anchor.path, offset: anchor.offset - text.length },
3031
3425
  focus: anchor
3032
3426
  });
3427
+ slate_exports.Editor.removeMark(editor, "tokenName");
3428
+ slate_exports.Editor.removeMark(editor, "isRawToken");
3429
+ slate_exports.Editor.removeMark(editor, "isEscapedDollar");
3033
3430
  }
3034
3431
  slate_exports.Transforms.wrapNodes(editor, link, { split: true });
3035
3432
  slate_exports.Transforms.collapse(editor, { edge: "end" });
@@ -3100,11 +3497,11 @@ function getPendingMarks(editor) {
3100
3497
  }
3101
3498
  }
3102
3499
  function mergeMarks(nodeMarks, pendingMarksResult) {
3103
- var _a, _b, _c, _d;
3500
+ var _a2, _b, _c, _d;
3104
3501
  const { marks: pendingMarks, hasPendingMarks } = pendingMarksResult;
3105
3502
  const marks = __spreadValues({}, nodeMarks);
3106
3503
  if (hasPendingMarks) {
3107
- marks.bold = (_a = pendingMarks.bold) != null ? _a : false;
3504
+ marks.bold = (_a2 = pendingMarks.bold) != null ? _a2 : false;
3108
3505
  marks.italic = (_b = pendingMarks.italic) != null ? _b : false;
3109
3506
  marks.underline = (_c = pendingMarks.underline) != null ? _c : false;
3110
3507
  marks.strikethrough = (_d = pendingMarks.strikethrough) != null ? _d : false;
@@ -3225,8 +3622,9 @@ function slateToHtml(value) {
3225
3622
  const serializeTextNode = (node) => {
3226
3623
  const styles = buildTextStyles(node);
3227
3624
  let text = node.tokenName ? `$${node.tokenName}$` : node.text;
3228
- if (node.isEscapedDollar && (node.text === "$" || node.text === "$$")) {
3229
- text = "$$";
3625
+ if (node.isEscapedDollar && /^\$+$/.test(node.text)) {
3626
+ const escapeCount = node.isRawToken ? node.text.length / 2 : node.text.length;
3627
+ text = "$$".repeat(escapeCount);
3230
3628
  }
3231
3629
  if (!text) {
3232
3630
  return styles.length > 0 ? `<span style="${styles.join("; ")}"></span>` : "";
@@ -3310,7 +3708,8 @@ function htmlToSlate(html) {
3310
3708
  "div",
3311
3709
  "font"
3312
3710
  ],
3313
- ALLOWED_ATTR: ["style", "href", "color", "face", "size"]
3711
+ ALLOWED_ATTR: ["style", "href", "color", "face", "size"],
3712
+ ALLOWED_URI_REGEXP
3314
3713
  });
3315
3714
  const doc = sharedDomParser.parseFromString(`<body>${sanitized}</body>`, "text/html");
3316
3715
  const applyMarksToChildren = (children, marks) => {
@@ -3558,7 +3957,8 @@ function activeStylesEqual(a, b) {
3558
3957
  "textAlign",
3559
3958
  "verticalAlign",
3560
3959
  "lineHeight",
3561
- "listType"
3960
+ "listType",
3961
+ "isLink"
3562
3962
  ];
3563
3963
  for (const key of keys) {
3564
3964
  if (a[key] !== b[key]) return false;
@@ -3632,18 +4032,18 @@ function PureRichTextProvider({
3632
4032
  }, []);
3633
4033
  const resolveBooleanMark = (0, react_exports.useCallback)(
3634
4034
  (format, slateValue, hasAnyLeafContent, hasPendingMarks) => {
3635
- var _a;
4035
+ var _a2;
3636
4036
  if (boolMarkOverrideRef.current !== null && format in boolMarkOverrideRef.current) {
3637
4037
  return Boolean(boolMarkOverrideRef.current[format]);
3638
4038
  }
3639
4039
  if (hasAnyLeafContent || hasPendingMarks) return slateValue;
3640
- return (_a = userDefaultStyles[format]) != null ? _a : false;
4040
+ return (_a2 = userDefaultStyles[format]) != null ? _a2 : false;
3641
4041
  },
3642
4042
  [userDefaultStyles]
3643
4043
  );
3644
4044
  const updateActiveStyles = (0, react_exports.useCallback)(
3645
4045
  (isContentChange) => {
3646
- var _a, _b;
4046
+ var _a2, _b;
3647
4047
  const editor = editorRef.current;
3648
4048
  if (!(editor == null ? void 0 : editor.selection)) {
3649
4049
  return;
@@ -3674,13 +4074,14 @@ function PureRichTextProvider({
3674
4074
  hasPendingMarks
3675
4075
  ),
3676
4076
  color: slateStyles.color || userDefaultStyles.color,
3677
- backgroundColor: (_a = slateStyles.backgroundColor) != null ? _a : hasAnyLeafContent || hasPendingMarks ? null : userDefaultStyles.backgroundColor,
4077
+ backgroundColor: (_a2 = slateStyles.backgroundColor) != null ? _a2 : hasAnyLeafContent || hasPendingMarks ? null : userDefaultStyles.backgroundColor,
3678
4078
  fontSize: slateStyles.fontSize || userDefaultStyles.fontSize,
3679
4079
  fontFamily: slateStyles.fontFamily || userDefaultStyles.fontFamily,
3680
4080
  textAlign: slateStyles.textAlign || userDefaultStyles.textAlign,
3681
4081
  verticalAlign: userDefaultStyles.verticalAlign,
3682
4082
  lineHeight: slateStyles.lineHeight || userDefaultStyles.lineHeight,
3683
- listType: (_b = slateStyles.listType) != null ? _b : userDefaultStyles.listType
4083
+ listType: (_b = slateStyles.listType) != null ? _b : userDefaultStyles.listType,
4084
+ isLink: isLinkActive(editor)
3684
4085
  };
3685
4086
  if (slateStyles.isMixed && Object.keys(slateStyles.isMixed).length > 0) {
3686
4087
  newActiveStyles.isMixed = slateStyles.isMixed;
@@ -3690,13 +4091,12 @@ function PureRichTextProvider({
3690
4091
  [userDefaultStyles, resolveBooleanMark]
3691
4092
  );
3692
4093
  const toggleBooleanMark = (0, react_exports.useCallback)((editor, format) => {
3693
- var _a;
3694
4094
  toggleMark(editor, format);
3695
4095
  if (editor.selection && slate_exports.Range.isCollapsed(editor.selection)) {
3696
4096
  const editorWithMarks = editor;
3697
4097
  const internalMarks = editorWithMarks.marks;
3698
- const newValue = internalMarks !== null ? Boolean(internalMarks[format]) : false;
3699
- boolMarkOverrideRef.current = __spreadProps(__spreadValues({}, (_a = boolMarkOverrideRef.current) != null ? _a : {}), {
4098
+ const newValue = internalMarks === null ? false : Boolean(internalMarks[format]);
4099
+ boolMarkOverrideRef.current = __spreadProps(__spreadValues({}, boolMarkOverrideRef.current), {
3700
4100
  [format]: newValue
3701
4101
  });
3702
4102
  }
@@ -3738,7 +4138,7 @@ function PureRichTextProvider({
3738
4138
  );
3739
4139
  const applyFormat = (0, react_exports.useCallback)(
3740
4140
  (command, value) => {
3741
- var _a, _b;
4141
+ var _a2, _b;
3742
4142
  const editor = editorRef.current;
3743
4143
  if (!editor) return;
3744
4144
  if (!editor.selection && savedSelectionRef.current) {
@@ -3753,7 +4153,7 @@ function PureRichTextProvider({
3753
4153
  dispatchFormatCommand(editor, command, value);
3754
4154
  if (editor.selection) {
3755
4155
  savedSelectionRef.current = editor.selection;
3756
- (_a = onFormatAppliedRef.current) == null ? void 0 : _a.call(onFormatAppliedRef, editor.selection);
4156
+ (_a2 = onFormatAppliedRef.current) == null ? void 0 : _a2.call(onFormatAppliedRef, editor.selection);
3757
4157
  }
3758
4158
  updateActiveStyles();
3759
4159
  (_b = onAnnouncementRef.current) == null ? void 0 : _b.call(onAnnouncementRef, generateFormatAnnouncement(command, value));
@@ -3859,6 +4259,14 @@ function PureRichTextProvider({
3859
4259
  const editor = editorRef.current;
3860
4260
  if (!editor) return;
3861
4261
  try {
4262
+ if (!editor.selection && savedSelectionRef.current) {
4263
+ try {
4264
+ slate_exports.Transforms.select(editor, savedSelectionRef.current);
4265
+ } catch (e) {
4266
+ return;
4267
+ }
4268
+ }
4269
+ if (!editor.selection) return;
3862
4270
  unwrapLink(editor);
3863
4271
  updateActiveStyles();
3864
4272
  } catch (error) {
@@ -4473,8 +4881,8 @@ function useLinkHandlers(handlers) {
4473
4881
  }
4474
4882
  resetLinkState();
4475
4883
  setTimeout(() => {
4476
- var _a;
4477
- (_a = linkButtonRef.current) == null ? void 0 : _a.focus();
4884
+ var _a2;
4885
+ (_a2 = linkButtonRef.current) == null ? void 0 : _a2.focus();
4478
4886
  }, 0);
4479
4887
  }, [linkUrl, linkText, createOrUpdateLink, resetLinkState]);
4480
4888
  const handleLinkRemove = (0, react_exports.useCallback)(() => {
@@ -4483,13 +4891,14 @@ function useLinkHandlers(handlers) {
4483
4891
  }
4484
4892
  resetLinkState();
4485
4893
  setTimeout(() => {
4486
- var _a;
4487
- (_a = linkButtonRef.current) == null ? void 0 : _a.focus();
4894
+ var _a2;
4895
+ (_a2 = linkButtonRef.current) == null ? void 0 : _a2.focus();
4488
4896
  }, 0);
4489
4897
  }, [removeLink, resetLinkState]);
4490
4898
  const handleLinkKeyDown = (0, react_exports.useCallback)(
4491
4899
  (e) => {
4492
- if (e.key === "Enter") {
4900
+ var _a2;
4901
+ if (e.key === "Enter" && ((_a2 = e.target) == null ? void 0 : _a2.tagName) === "INPUT") {
4493
4902
  e.preventDefault();
4494
4903
  handleLinkSave();
4495
4904
  }
@@ -4499,8 +4908,8 @@ function useLinkHandlers(handlers) {
4499
4908
  e.nativeEvent.stopImmediatePropagation();
4500
4909
  resetLinkState();
4501
4910
  setTimeout(() => {
4502
- var _a;
4503
- (_a = linkButtonRef.current) == null ? void 0 : _a.focus();
4911
+ var _a3;
4912
+ (_a3 = linkButtonRef.current) == null ? void 0 : _a3.focus();
4504
4913
  }, 0);
4505
4914
  }
4506
4915
  },
@@ -4509,8 +4918,8 @@ function useLinkHandlers(handlers) {
4509
4918
  (0, react_exports.useEffect)(() => {
4510
4919
  if (!linkPopoverOpen) return void 0;
4511
4920
  const timer = setTimeout(() => {
4512
- var _a, _b;
4513
- (_b = (_a = linkPopoverRef.current) == null ? void 0 : _a.querySelector("input")) == null ? void 0 : _b.focus();
4921
+ var _a2, _b;
4922
+ (_b = (_a2 = linkPopoverRef.current) == null ? void 0 : _a2.querySelector("input")) == null ? void 0 : _b.focus();
4514
4923
  }, 50);
4515
4924
  return () => clearTimeout(timer);
4516
4925
  }, [linkPopoverOpen]);
@@ -4559,7 +4968,7 @@ function useLineSpacing(lineHeight, displayLineHeight, isLineHeightMixed, applyF
4559
4968
  }, [displayLineHeight, lineHeight, isLineHeightMixed]);
4560
4969
  const handleLineSpacingChange = (0, react_exports.useCallback)(
4561
4970
  (_e, data) => {
4562
- var _a, _b;
4971
+ var _a2, _b;
4563
4972
  const { value, reason } = data;
4564
4973
  if (value !== void 0 && value !== null) {
4565
4974
  setLineSpacingPercent(value);
@@ -4570,7 +4979,7 @@ function useLineSpacing(lineHeight, displayLineHeight, isLineHeightMixed, applyF
4570
4979
  if (reason === "stepButton" && applyFormat) {
4571
4980
  if (isLineHeightMixed && stepLineSpacing) {
4572
4981
  const target = _e == null ? void 0 : _e.currentTarget;
4573
- const testId = ((_a = target == null ? void 0 : target.getAttribute) == null ? void 0 : _a.call(target, "data-test")) || ((_b = target == null ? void 0 : target.getAttribute) == null ? void 0 : _b.call(target, "data-testid")) || "";
4982
+ const testId = ((_a2 = target == null ? void 0 : target.getAttribute) == null ? void 0 : _a2.call(target, "data-test")) || ((_b = target == null ? void 0 : target.getAttribute) == null ? void 0 : _b.call(target, "data-testid")) || "";
4574
4983
  const isDecrement = testId === "decrement" || testId.includes("down");
4575
4984
  stepLineSpacing(isDecrement ? -1 : 1);
4576
4985
  return;
@@ -4598,23 +5007,295 @@ function useLineSpacing(lineHeight, displayLineHeight, isLineHeightMixed, applyF
4598
5007
  };
4599
5008
  }
4600
5009
 
4601
- // src/RichText/PureRichText/Editor/EditorPanel.tsx
4602
- var TextAlignJustified = () => /* @__PURE__ */ react_default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ react_default.createElement(
4603
- "path",
4604
- {
4605
- d: "M3 6h18M3 10h18M3 14h18M3 18h18",
5010
+ // src/RichText/PureRichText/Editor/hooks/useConfigPanelFocus.ts
5011
+ function useConfigPanelFocus({
5012
+ isEditMode,
5013
+ isActive,
5014
+ editorContainerRef,
5015
+ wasMouseRef
5016
+ }) {
5017
+ (0, react_exports.useEffect)(() => {
5018
+ if (!isEditMode || !isActive) return void 0;
5019
+ const handleMouseDown = (e) => {
5020
+ const container = editorContainerRef.current;
5021
+ if (!container) return;
5022
+ const target = e.target;
5023
+ if (!container.contains(target)) return;
5024
+ wasMouseRef.current = true;
5025
+ const tag = target.tagName;
5026
+ if (tag !== "INPUT" && tag !== "TEXTAREA") {
5027
+ e.preventDefault();
5028
+ }
5029
+ };
5030
+ const handleKeyDown = (e) => {
5031
+ const container = editorContainerRef.current;
5032
+ if (!container) return;
5033
+ const target = e.target;
5034
+ if (container.contains(target)) {
5035
+ wasMouseRef.current = false;
5036
+ }
5037
+ };
5038
+ document.addEventListener("mousedown", handleMouseDown, true);
5039
+ document.addEventListener("keydown", handleKeyDown, true);
5040
+ return () => {
5041
+ document.removeEventListener("mousedown", handleMouseDown, true);
5042
+ document.removeEventListener("keydown", handleKeyDown, true);
5043
+ };
5044
+ }, [isEditMode, isActive, editorContainerRef, wasMouseRef]);
5045
+ (0, react_exports.useEffect)(() => {
5046
+ if (!isEditMode || !isActive) return void 0;
5047
+ const FOCUS_RING_ATTR = "data-trap-focused";
5048
+ let lastFocused = null;
5049
+ const applyFocusRing = (el) => {
5050
+ removeFocusRing();
5051
+ if (el.getAttribute("tabindex") === "-1") {
5052
+ el.setAttribute(FOCUS_RING_ATTR, "true");
5053
+ el.style.outline = "2px solid #3b82f6";
5054
+ el.style.outlineOffset = "-2px";
5055
+ el.style.position = "relative";
5056
+ el.style.zIndex = "1";
5057
+ lastFocused = el;
5058
+ }
5059
+ };
5060
+ const removeFocusRing = () => {
5061
+ if (lastFocused == null ? void 0 : lastFocused.hasAttribute(FOCUS_RING_ATTR)) {
5062
+ lastFocused.removeAttribute(FOCUS_RING_ATTR);
5063
+ lastFocused.style.outline = "";
5064
+ lastFocused.style.outlineOffset = "";
5065
+ lastFocused.style.position = "";
5066
+ lastFocused.style.zIndex = "";
5067
+ lastFocused = null;
5068
+ }
5069
+ };
5070
+ const handleBlurCleanup = () => {
5071
+ removeFocusRing();
5072
+ };
5073
+ const getFocusableElements = (panel) => {
5074
+ const selector = 'button:not([disabled]):not([aria-disabled="true"]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href]:not([disabled])';
5075
+ return Array.from(panel.querySelectorAll(selector)).filter(
5076
+ (el) => el.offsetParent !== null && el.offsetWidth > 0 && el.offsetHeight > 0
5077
+ );
5078
+ };
5079
+ const moveFocus = (e, focusable, currentIndex) => {
5080
+ const backward = e.shiftKey;
5081
+ const atBoundary = backward ? currentIndex <= 0 : currentIndex >= focusable.length - 1;
5082
+ if (atBoundary) {
5083
+ removeFocusRing();
5084
+ return;
5085
+ }
5086
+ e.preventDefault();
5087
+ const nextEl = focusable[backward ? currentIndex - 1 : currentIndex + 1];
5088
+ nextEl.focus();
5089
+ applyFocusRing(nextEl);
5090
+ };
5091
+ const handleConfigPanelKeyDown = (e) => {
5092
+ const target = e.target;
5093
+ if (e.key === "Escape") {
5094
+ removeFocusRing();
5095
+ return;
5096
+ }
5097
+ const configPanel = editorContainerRef.current;
5098
+ if (!(configPanel == null ? void 0 : configPanel.contains(target)) || e.key !== "Tab") return;
5099
+ const focusable = getFocusableElements(configPanel);
5100
+ if (focusable.length === 0) return;
5101
+ const currentIndex = focusable.indexOf(target);
5102
+ if (currentIndex === -1) {
5103
+ removeFocusRing();
5104
+ return;
5105
+ }
5106
+ moveFocus(e, focusable, currentIndex);
5107
+ };
5108
+ document.addEventListener("keydown", handleConfigPanelKeyDown, true);
5109
+ document.addEventListener("focusout", handleBlurCleanup, true);
5110
+ return () => {
5111
+ document.removeEventListener("keydown", handleConfigPanelKeyDown, true);
5112
+ document.removeEventListener("focusout", handleBlurCleanup, true);
5113
+ removeFocusRing();
5114
+ };
5115
+ }, [isEditMode, isActive, editorContainerRef]);
5116
+ }
5117
+
5118
+ // src/RichText/PureRichText/Editor/hooks/usePortalTarget.ts
5119
+ function usePortalTarget(isEditMode) {
5120
+ const portalTargetRef = (0, react_exports.useRef)(null);
5121
+ const [renderTick, forceUpdate] = (0, react_exports.useReducer)((n) => n + 1, 0);
5122
+ const portalReady = renderTick >= 0 && portalTargetRef.current !== null;
5123
+ (0, react_exports.useEffect)(() => {
5124
+ if (!isEditMode) {
5125
+ portalTargetRef.current = null;
5126
+ forceUpdate();
5127
+ return void 0;
5128
+ }
5129
+ const findTarget = () => {
5130
+ const target = getEditorPanelTarget();
5131
+ if (target && target !== portalTargetRef.current) {
5132
+ portalTargetRef.current = target;
5133
+ forceUpdate();
5134
+ }
5135
+ };
5136
+ findTarget();
5137
+ const interval = setInterval(findTarget, 100);
5138
+ return () => {
5139
+ clearInterval(interval);
5140
+ portalTargetRef.current = null;
5141
+ };
5142
+ }, [isEditMode]);
5143
+ return { portalTargetRef, portalReady };
5144
+ }
5145
+
5146
+ // src/RichText/PureRichText/Editor/hooks/useEditorPanelSync.ts
5147
+ function useEditorPanelSync({
5148
+ textAlign,
5149
+ setAlign,
5150
+ verticalAlignProp,
5151
+ setVerticalAlign,
5152
+ activeFontSize,
5153
+ fontSizeDirtyRef,
5154
+ setCurrentFontSize,
5155
+ setFontSizePreset
5156
+ }) {
5157
+ (0, react_exports.useEffect)(() => {
5158
+ if (textAlign) {
5159
+ setAlign(textAlign);
5160
+ }
5161
+ }, [textAlign, setAlign]);
5162
+ (0, react_exports.useEffect)(() => {
5163
+ setVerticalAlign(verticalAlignProp);
5164
+ }, [verticalAlignProp, setVerticalAlign]);
5165
+ (0, react_exports.useEffect)(() => {
5166
+ fontSizeDirtyRef.current = false;
5167
+ if (activeFontSize) {
5168
+ const size2 = Number.parseInt(String(activeFontSize), 10) || 14;
5169
+ setCurrentFontSize(size2);
5170
+ setFontSizePreset(getFontSizePreset(size2));
5171
+ }
5172
+ }, [activeFontSize, fontSizeDirtyRef, setCurrentFontSize, setFontSizePreset]);
5173
+ }
5174
+
5175
+ // src/RichText/PureRichText/Editor/EditorPanel.tsx
5176
+ var TextAlignJustified = () => /* @__PURE__ */ react_default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ react_default.createElement(
5177
+ "path",
5178
+ {
5179
+ d: "M3 6h18M3 10h18M3 14h18M3 18h18",
4606
5180
  stroke: "currentColor",
4607
5181
  strokeWidth: "1.5",
4608
5182
  strokeLinecap: "round"
4609
5183
  }
4610
5184
  ));
4611
5185
  var preventDefaultMouseDown = (e) => e.preventDefault();
5186
+ function handleFontSizeStep(e, val, ctx) {
5187
+ var _a2, _b;
5188
+ if (!ctx.stepFontSize) {
5189
+ if (val != null) {
5190
+ ctx.setCurrentFontSize(val);
5191
+ ctx.setFontSizePreset(getFontSizePreset(val));
5192
+ ctx.handleFormat("fontSize", `${val}px`);
5193
+ }
5194
+ return;
5195
+ }
5196
+ const target = e == null ? void 0 : e.currentTarget;
5197
+ const testId = ((_a2 = target == null ? void 0 : target.getAttribute) == null ? void 0 : _a2.call(target, "data-test")) || ((_b = target == null ? void 0 : target.getAttribute) == null ? void 0 : _b.call(target, "data-testid")) || "";
5198
+ const isDecrement = testId === "decrement" || testId.includes("down");
5199
+ ctx.stepFontSize(isDecrement ? -2 : 2);
5200
+ if (ctx.wasMouseRef.current) {
5201
+ setTimeout(() => focusActiveEditable(), 0);
5202
+ }
5203
+ }
5204
+ function handleFontSizeChange(e, val, reason, ctx) {
5205
+ if (reason === "stepButton") {
5206
+ handleFontSizeStep(e, val, ctx);
5207
+ return;
5208
+ }
5209
+ if (val != null) {
5210
+ ctx.fontSizeDirtyRef.current = true;
5211
+ ctx.setCurrentFontSize(val);
5212
+ ctx.setFontSizePreset(getFontSizePreset(val));
5213
+ }
5214
+ }
4612
5215
  var focusMixedSwatch = (selector) => {
4613
5216
  setTimeout(() => {
4614
- var _a;
4615
- (_a = document.querySelector(selector)) == null ? void 0 : _a.focus();
5217
+ var _a2;
5218
+ (_a2 = document.querySelector(selector)) == null ? void 0 : _a2.focus();
4616
5219
  }, 50);
4617
5220
  };
5221
+ function handleMixedSwatchClick(isMixed) {
5222
+ if (isMixed) focusMixedSwatch('[data-test="textbox-swatch"]');
5223
+ }
5224
+ var ALIGN_COMMANDS = {
5225
+ left: "justifyLeft",
5226
+ center: "justifyCenter",
5227
+ right: "justifyRight",
5228
+ justify: "justifyFull"
5229
+ };
5230
+ function handleAlignmentChange(newAlign, setAlign, handleFormat) {
5231
+ setAlign(newAlign);
5232
+ handleFormat(ALIGN_COMMANDS[newAlign]);
5233
+ }
5234
+ function handleFontSizePresetChange(val, ctx) {
5235
+ const preset = FONT_SIZE_OPTIONS.find((p) => p.value === val);
5236
+ if (!preset) {
5237
+ ctx.setFontSizePreset("custom");
5238
+ return;
5239
+ }
5240
+ ctx.setCurrentFontSize(Number.parseInt(preset.value, 10));
5241
+ ctx.setFontSizePreset(preset.value);
5242
+ ctx.handleFormat("fontSize", `${preset.value}px`);
5243
+ }
5244
+ function handleFontSizeArrowCapture(e, stepFontSize) {
5245
+ if (e.key !== "ArrowUp" && e.key !== "ArrowDown") return;
5246
+ e.preventDefault();
5247
+ e.stopPropagation();
5248
+ stepFontSize(e.key === "ArrowUp" ? 2 : -2);
5249
+ }
5250
+ function handleFontSizeInputKeyDown(e, ctx) {
5251
+ if (e.key !== "Enter" || !ctx.currentFontSize) return;
5252
+ e.preventDefault();
5253
+ e.stopPropagation();
5254
+ ctx.fontSizeDirtyRef.current = false;
5255
+ ctx.handleFormat("fontSize", `${ctx.currentFontSize}px`);
5256
+ }
5257
+ function handleFontSizeInputBlur(ctx) {
5258
+ if (ctx.fontSizeDirtyRef.current && ctx.currentFontSize) {
5259
+ ctx.handleFormat("fontSize", `${ctx.currentFontSize}px`);
5260
+ }
5261
+ ctx.fontSizeDirtyRef.current = false;
5262
+ }
5263
+ function handleLineSpacingKeyDown(e, ctx) {
5264
+ if (e.key === "Enter") {
5265
+ ctx.handleLineSpacingBlur();
5266
+ }
5267
+ if (!ctx.isLineHeightMixed || !ctx.stepLineSpacing) return;
5268
+ if (e.key === "ArrowUp") {
5269
+ e.preventDefault();
5270
+ ctx.stepLineSpacing(1);
5271
+ } else if (e.key === "ArrowDown") {
5272
+ e.preventDefault();
5273
+ ctx.stepLineSpacing(-1);
5274
+ }
5275
+ }
5276
+ function computeMixedDisplayStyles(activeTextStyles, fontColor) {
5277
+ var _a2;
5278
+ const isMixedStyles = activeTextStyles.isMixed || {};
5279
+ const isColorMixed = isMixedStyles.color === true;
5280
+ const isHighlightMixed = isMixedStyles.backgroundColor === true;
5281
+ const isFontSizeMixed = isMixedStyles.fontSize === true;
5282
+ const isFontFamilyMixed = isMixedStyles.fontFamily === true;
5283
+ return {
5284
+ isColorMixed,
5285
+ isHighlightMixed,
5286
+ isFontSizeMixed,
5287
+ isFontFamilyMixed,
5288
+ displayTextColor: isColorMixed ? "" : activeTextStyles.color || fontColor,
5289
+ displayHighlightColor: isHighlightMixed ? "" : (_a2 = activeTextStyles.backgroundColor) != null ? _a2 : "transparent",
5290
+ displayFontFamily: isFontFamilyMixed ? "" : activeTextStyles.fontFamily || "Splunk Data Sans"
5291
+ };
5292
+ }
5293
+ function handleResetToDefault(resetToDefault, wasMouseRef) {
5294
+ resetToDefault == null ? void 0 : resetToDefault();
5295
+ if (wasMouseRef.current) {
5296
+ setTimeout(() => focusActiveEditable(), 0);
5297
+ }
5298
+ }
4618
5299
  var EditorPanel = ({
4619
5300
  isEditMode,
4620
5301
  isActive = false,
@@ -4624,10 +5305,8 @@ var EditorPanel = ({
4624
5305
  verticalAlign: verticalAlignProp = "top",
4625
5306
  onVerticalAlignChange
4626
5307
  }) => {
4627
- var _a, _b;
4628
- const portalTargetRef = (0, react_exports.useRef)(null);
4629
- const [renderTick, forceUpdate] = react_default.useReducer((n) => n + 1, 0);
4630
- const portalReady = renderTick >= 0 && portalTargetRef.current !== null;
5308
+ var _a2, _b;
5309
+ const { portalTargetRef, portalReady } = usePortalTarget(isEditMode);
4631
5310
  const contextValue = usePureRichTextOptional();
4632
5311
  const activeTextStyles = (contextValue == null ? void 0 : contextValue.activeTextStyles) || DEFAULT_TEXT_STYLES;
4633
5312
  const applyFormat = contextValue == null ? void 0 : contextValue.applyFormat;
@@ -4644,8 +5323,8 @@ var EditorPanel = ({
4644
5323
  const [currentFontSize, setCurrentFontSize] = (0, react_exports.useState)(fontSizeProp);
4645
5324
  const [fontSizePreset, setFontSizePreset] = (0, react_exports.useState)(() => getFontSizePreset(fontSizeProp));
4646
5325
  const fontSizeDirtyRef = (0, react_exports.useRef)(false);
5326
+ const linkIsActive = (_a2 = activeTextStyles.isLink) != null ? _a2 : false;
4647
5327
  const {
4648
- linkIsActive,
4649
5328
  linkPopoverOpen,
4650
5329
  linkPopoverRef,
4651
5330
  linkText,
@@ -4680,7 +5359,7 @@ var EditorPanel = ({
4680
5359
  },
4681
5360
  [applyFormat]
4682
5361
  );
4683
- const isLineHeightMixed = ((_a = activeTextStyles.isMixed) == null ? void 0 : _a.lineHeight) === true;
5362
+ const isLineHeightMixed = ((_b = activeTextStyles.isMixed) == null ? void 0 : _b.lineHeight) === true;
4684
5363
  const {
4685
5364
  lineSpacingPercent,
4686
5365
  showMixed: showLineSpacingMixed,
@@ -4698,42 +5377,29 @@ var EditorPanel = ({
4698
5377
  (fontFamily) => handleFormat("fontName", fontFamily),
4699
5378
  [handleFormat]
4700
5379
  );
4701
- (0, react_exports.useEffect)(() => {
4702
- if (!isEditMode) {
4703
- portalTargetRef.current = null;
4704
- forceUpdate();
4705
- return void 0;
4706
- }
4707
- const findTarget = () => {
4708
- const target = getEditorPanelTarget();
4709
- if (target && target !== portalTargetRef.current) {
4710
- portalTargetRef.current = target;
4711
- forceUpdate();
4712
- }
4713
- };
4714
- findTarget();
4715
- const interval = setInterval(findTarget, 100);
4716
- return () => {
4717
- clearInterval(interval);
4718
- portalTargetRef.current = null;
4719
- };
4720
- }, [isEditMode]);
4721
- (0, react_exports.useEffect)(() => {
4722
- if (activeTextStyles.textAlign) {
4723
- setAlign(activeTextStyles.textAlign);
4724
- }
4725
- }, [activeTextStyles.textAlign]);
4726
- (0, react_exports.useEffect)(() => {
4727
- setVerticalAlign(verticalAlignProp);
4728
- }, [verticalAlignProp]);
4729
- (0, react_exports.useEffect)(() => {
4730
- fontSizeDirtyRef.current = false;
4731
- if (activeTextStyles.fontSize) {
4732
- const size2 = Number.parseInt(String(activeTextStyles.fontSize), 10) || 14;
4733
- setCurrentFontSize(size2);
4734
- setFontSizePreset(getFontSizePreset(size2));
4735
- }
4736
- }, [activeTextStyles.fontSize]);
5380
+ const onFontSizeChange = (0, react_exports.useCallback)(
5381
+ (e, { value: val, reason }) => {
5382
+ handleFontSizeChange(e, val, reason, {
5383
+ stepFontSize,
5384
+ setCurrentFontSize,
5385
+ setFontSizePreset,
5386
+ handleFormat,
5387
+ fontSizeDirtyRef,
5388
+ wasMouseRef
5389
+ });
5390
+ },
5391
+ [stepFontSize, handleFormat]
5392
+ );
5393
+ useEditorPanelSync({
5394
+ textAlign: activeTextStyles.textAlign,
5395
+ setAlign,
5396
+ verticalAlignProp,
5397
+ setVerticalAlign,
5398
+ activeFontSize: activeTextStyles.fontSize,
5399
+ fontSizeDirtyRef,
5400
+ setCurrentFontSize,
5401
+ setFontSizePreset
5402
+ });
4737
5403
  const handleVerticalAlignChange = (0, react_exports.useCallback)(
4738
5404
  (newAlign) => {
4739
5405
  setVerticalAlign(newAlign);
@@ -4741,123 +5407,16 @@ var EditorPanel = ({
4741
5407
  },
4742
5408
  [onVerticalAlignChange]
4743
5409
  );
4744
- const isMixedStyles = activeTextStyles.isMixed || {};
4745
- const isColorMixed = isMixedStyles.color === true;
4746
- const isHighlightMixed = isMixedStyles.backgroundColor === true;
4747
- const isFontSizeMixed = isMixedStyles.fontSize === true;
4748
- const isFontFamilyMixed = isMixedStyles.fontFamily === true;
4749
- const displayTextColor = isColorMixed ? "" : activeTextStyles.color || fontColor;
4750
- const displayHighlightColor = isHighlightMixed ? "" : (_b = activeTextStyles.backgroundColor) != null ? _b : "transparent";
4751
- const displayFontFamily = isFontFamilyMixed ? "" : activeTextStyles.fontFamily || "Splunk Data Sans";
5410
+ const {
5411
+ isColorMixed,
5412
+ isHighlightMixed,
5413
+ isFontSizeMixed,
5414
+ displayTextColor,
5415
+ displayHighlightColor,
5416
+ displayFontFamily
5417
+ } = computeMixedDisplayStyles(activeTextStyles, fontColor);
4752
5418
  const editorContainerRef = (0, react_exports.useRef)(null);
4753
- (0, react_exports.useEffect)(() => {
4754
- if (!isEditMode || !isActive) return void 0;
4755
- const handleMouseDown = (e) => {
4756
- const container = editorContainerRef.current;
4757
- if (!container) return;
4758
- const target = e.target;
4759
- if (!container.contains(target)) return;
4760
- wasMouseRef.current = true;
4761
- const tag = target.tagName;
4762
- if (tag !== "INPUT" && tag !== "TEXTAREA") {
4763
- e.preventDefault();
4764
- }
4765
- };
4766
- const handleKeyDown = (e) => {
4767
- const container = editorContainerRef.current;
4768
- if (!container) return;
4769
- const target = e.target;
4770
- if (container.contains(target)) {
4771
- wasMouseRef.current = false;
4772
- }
4773
- };
4774
- document.addEventListener("mousedown", handleMouseDown, true);
4775
- document.addEventListener("keydown", handleKeyDown, true);
4776
- return () => {
4777
- document.removeEventListener("mousedown", handleMouseDown, true);
4778
- document.removeEventListener("keydown", handleKeyDown, true);
4779
- };
4780
- }, [isEditMode, isActive]);
4781
- (0, react_exports.useEffect)(() => {
4782
- if (!isEditMode || !isActive) return void 0;
4783
- const FOCUS_RING_ATTR = "data-trap-focused";
4784
- let lastFocused = null;
4785
- const applyFocusRing = (el) => {
4786
- removeFocusRing();
4787
- if (el.getAttribute("tabindex") === "-1") {
4788
- el.setAttribute(FOCUS_RING_ATTR, "true");
4789
- el.style.outline = "2px solid #3b82f6";
4790
- el.style.outlineOffset = "-2px";
4791
- el.style.position = "relative";
4792
- el.style.zIndex = "1";
4793
- lastFocused = el;
4794
- }
4795
- };
4796
- const removeFocusRing = () => {
4797
- if (lastFocused == null ? void 0 : lastFocused.hasAttribute(FOCUS_RING_ATTR)) {
4798
- lastFocused.removeAttribute(FOCUS_RING_ATTR);
4799
- lastFocused.style.outline = "";
4800
- lastFocused.style.outlineOffset = "";
4801
- lastFocused.style.position = "";
4802
- lastFocused.style.zIndex = "";
4803
- lastFocused = null;
4804
- }
4805
- };
4806
- const handleBlurCleanup = () => {
4807
- removeFocusRing();
4808
- };
4809
- const getConfigPanel = () => editorContainerRef.current;
4810
- const getFocusableElements = (panel) => {
4811
- const selector = 'button:not([disabled]):not([aria-disabled="true"]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href]:not([disabled])';
4812
- return Array.from(panel.querySelectorAll(selector)).filter(
4813
- (el) => el.offsetParent !== null && el.offsetWidth > 0 && el.offsetHeight > 0
4814
- );
4815
- };
4816
- const handleConfigPanelKeyDown = (e) => {
4817
- const target = e.target;
4818
- if (e.key === "Escape") {
4819
- removeFocusRing();
4820
- return;
4821
- }
4822
- const configPanel = getConfigPanel();
4823
- if (!configPanel) return;
4824
- if (!configPanel.contains(target)) return;
4825
- if (e.key !== "Tab") return;
4826
- const focusable = getFocusableElements(configPanel);
4827
- if (focusable.length === 0) return;
4828
- const currentIndex = focusable.indexOf(target);
4829
- if (currentIndex === -1) {
4830
- removeFocusRing();
4831
- return;
4832
- }
4833
- if (e.shiftKey) {
4834
- if (currentIndex <= 0) {
4835
- removeFocusRing();
4836
- return;
4837
- }
4838
- e.preventDefault();
4839
- const nextEl = focusable[currentIndex - 1];
4840
- nextEl.focus();
4841
- applyFocusRing(nextEl);
4842
- } else {
4843
- if (currentIndex >= focusable.length - 1) {
4844
- removeFocusRing();
4845
- return;
4846
- }
4847
- e.preventDefault();
4848
- const nextEl = focusable[currentIndex + 1];
4849
- nextEl.focus();
4850
- applyFocusRing(nextEl);
4851
- }
4852
- };
4853
- document.addEventListener("keydown", handleConfigPanelKeyDown, true);
4854
- document.addEventListener("focusout", handleBlurCleanup, true);
4855
- return () => {
4856
- document.removeEventListener("keydown", handleConfigPanelKeyDown, true);
4857
- document.removeEventListener("focusout", handleBlurCleanup, true);
4858
- removeFocusRing();
4859
- };
4860
- }, [isEditMode, isActive]);
5419
+ useConfigPanelFocus({ isEditMode, isActive, editorContainerRef, wasMouseRef });
4861
5420
  if (!isEditMode) return null;
4862
5421
  const editor = /* @__PURE__ */ react_default.createElement(EditorContainer, { ref: editorContainerRef, "data-test": "editor-purerichtext-content" }, /* @__PURE__ */ react_default.createElement(FontSelector, { value: displayFontFamily, onChange: handleFontFamilyChange }), /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "Font size", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(Row, { style: { gap: "12px" } }, /* @__PURE__ */ react_default.createElement(
4863
5422
  Select_default,
@@ -4865,90 +5424,52 @@ var EditorPanel = ({
4865
5424
  value: isFontSizeMixed ? void 0 : fontSizePreset,
4866
5425
  placeholder: isFontSizeMixed ? "Mixed" : void 0,
4867
5426
  onChange: (_e, { value: val }) => {
4868
- const preset = FONT_SIZE_OPTIONS.find((p) => p.value === val);
4869
- if (preset) {
4870
- setCurrentFontSize(Number.parseInt(preset.value, 10));
4871
- setFontSizePreset(val);
4872
- handleFormat("fontSize", `${preset.value}px`);
4873
- } else {
4874
- setFontSizePreset("custom");
4875
- }
5427
+ handleFontSizePresetChange(val, {
5428
+ setCurrentFontSize,
5429
+ setFontSizePreset,
5430
+ handleFormat
5431
+ });
4876
5432
  },
4877
5433
  style: { flex: 1, minWidth: 100 }
4878
5434
  },
4879
5435
  FONT_SIZE_OPTIONS.map(({ label, value }) => /* @__PURE__ */ react_default.createElement(Select_default.Option, { key: value, label, value })),
4880
5436
  /* @__PURE__ */ react_default.createElement(Select_default.Option, { label: "Custom", value: "custom" })
4881
- ), /* @__PURE__ */ react_default.createElement("div", { style: { width: "80px", flexShrink: 0 } }, /* @__PURE__ */ react_default.createElement(
4882
- Number_default,
5437
+ ), /* @__PURE__ */ react_default.createElement(
5438
+ "div",
4883
5439
  {
4884
- "aria-label": "Font size in pixels",
4885
- value: isFontSizeMixed ? void 0 : currentFontSize,
4886
- onFocus: () => {
4887
- fontSizeDirtyRef.current = false;
4888
- },
4889
- onChange: (_e, { value: val, reason }) => {
4890
- var _a2, _b2;
4891
- if (reason === "stepButton") {
4892
- if (!stepFontSize) {
4893
- if (val != null) {
4894
- setCurrentFontSize(val);
4895
- setFontSizePreset(getFontSizePreset(val));
4896
- handleFormat("fontSize", `${val}px`);
4897
- }
4898
- return;
4899
- }
4900
- const target = _e == null ? void 0 : _e.currentTarget;
4901
- const testId = ((_a2 = target == null ? void 0 : target.getAttribute) == null ? void 0 : _a2.call(target, "data-test")) || ((_b2 = target == null ? void 0 : target.getAttribute) == null ? void 0 : _b2.call(target, "data-testid")) || "";
4902
- const isDecrement = testId === "decrement" || testId.includes("down");
4903
- stepFontSize(isDecrement ? -2 : 2);
4904
- if (wasMouseRef.current) {
4905
- setTimeout(() => {
4906
- focusActiveEditable();
4907
- }, 0);
4908
- }
4909
- return;
4910
- }
4911
- if (val != null) {
4912
- fontSizeDirtyRef.current = true;
4913
- setCurrentFontSize(val);
4914
- setFontSizePreset(getFontSizePreset(val));
4915
- }
4916
- },
4917
- onKeyDown: (e) => {
4918
- if (e.key === "Enter" && currentFontSize) {
4919
- e.preventDefault();
4920
- e.stopPropagation();
5440
+ style: { width: "80px", flexShrink: 0 },
5441
+ onKeyDownCapture: stepFontSize ? (e) => handleFontSizeArrowCapture(e, stepFontSize) : void 0
5442
+ },
5443
+ /* @__PURE__ */ react_default.createElement(
5444
+ Number_default,
5445
+ {
5446
+ "aria-label": "Font size in pixels",
5447
+ value: isFontSizeMixed ? void 0 : currentFontSize,
5448
+ onFocus: () => {
4921
5449
  fontSizeDirtyRef.current = false;
4922
- handleFormat("fontSize", `${currentFontSize}px`);
4923
- }
4924
- if (isFontSizeMixed) {
4925
- if (e.key === "ArrowUp") {
4926
- e.preventDefault();
4927
- stepFontSize == null ? void 0 : stepFontSize(2);
4928
- } else if (e.key === "ArrowDown") {
4929
- e.preventDefault();
4930
- stepFontSize == null ? void 0 : stepFontSize(-2);
4931
- }
4932
- }
4933
- },
4934
- onBlur: () => {
4935
- if (fontSizeDirtyRef.current && currentFontSize) {
4936
- handleFormat("fontSize", `${currentFontSize}px`);
4937
- }
4938
- fontSizeDirtyRef.current = false;
4939
- },
4940
- min: 8,
4941
- max: 200,
4942
- step: 1,
4943
- inline: true
4944
- }
4945
- )))), /* @__PURE__ */ react_default.createElement(ColorRow, null, /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "Font color", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(
5450
+ },
5451
+ onChange: onFontSizeChange,
5452
+ onKeyDown: (e) => {
5453
+ handleFontSizeInputKeyDown(e, {
5454
+ currentFontSize,
5455
+ fontSizeDirtyRef,
5456
+ handleFormat
5457
+ });
5458
+ },
5459
+ onBlur: () => {
5460
+ handleFontSizeInputBlur({ currentFontSize, fontSizeDirtyRef, handleFormat });
5461
+ },
5462
+ min: 8,
5463
+ max: 200,
5464
+ step: 1,
5465
+ inline: true
5466
+ }
5467
+ )
5468
+ ))), /* @__PURE__ */ react_default.createElement(ColorRow, null, /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "Font color", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(
4946
5469
  MixedColorWrapper,
4947
5470
  {
4948
5471
  $isMixed: isColorMixed,
4949
- onClick: () => {
4950
- if (isColorMixed) focusMixedSwatch('[data-test="textbox-swatch"]');
4951
- }
5472
+ onClick: () => handleMixedSwatchClick(isColorMixed)
4952
5473
  },
4953
5474
  /* @__PURE__ */ react_default.createElement(
4954
5475
  Color_default,
@@ -4963,9 +5484,7 @@ var EditorPanel = ({
4963
5484
  MixedColorWrapper,
4964
5485
  {
4965
5486
  $isMixed: isHighlightMixed,
4966
- onClick: () => {
4967
- if (isHighlightMixed) focusMixedSwatch('[data-test="textbox-swatch"]');
4968
- }
5487
+ onClick: () => handleMixedSwatchClick(isHighlightMixed)
4969
5488
  },
4970
5489
  /* @__PURE__ */ react_default.createElement(
4971
5490
  Color_default,
@@ -5045,14 +5564,7 @@ var EditorPanel = ({
5045
5564
  $isActive: false,
5046
5565
  appearance: "secondary",
5047
5566
  onMouseDown: preventDefaultMouseDown,
5048
- onClick: () => {
5049
- resetToDefault == null ? void 0 : resetToDefault();
5050
- if (wasMouseRef.current) {
5051
- setTimeout(() => {
5052
- focusActiveEditable();
5053
- }, 0);
5054
- }
5055
- },
5567
+ onClick: () => handleResetToDefault(resetToDefault, wasMouseRef),
5056
5568
  icon: /* @__PURE__ */ react_default.createElement(ArrowTurnBackLeft_default, null),
5057
5569
  "aria-label": "Reset to default"
5058
5570
  }
@@ -5093,12 +5605,7 @@ var EditorPanel = ({
5093
5605
  {
5094
5606
  value: align,
5095
5607
  onChange: (_e, { value: val }) => {
5096
- const newAlign = val;
5097
- setAlign(newAlign);
5098
- if (newAlign === "left") handleFormat("justifyLeft");
5099
- else if (newAlign === "center") handleFormat("justifyCenter");
5100
- else if (newAlign === "right") handleFormat("justifyRight");
5101
- else if (newAlign === "justify") handleFormat("justifyFull");
5608
+ handleAlignmentChange(val, setAlign, handleFormat);
5102
5609
  }
5103
5610
  },
5104
5611
  /* @__PURE__ */ react_default.createElement(
@@ -5166,18 +5673,11 @@ var EditorPanel = ({
5166
5673
  onChange: handleLineSpacingChange,
5167
5674
  onBlur: handleLineSpacingBlur,
5168
5675
  onKeyDown: (e) => {
5169
- if (e.key === "Enter") {
5170
- handleLineSpacingBlur();
5171
- }
5172
- if (isLineHeightMixed && stepLineSpacing) {
5173
- if (e.key === "ArrowUp") {
5174
- e.preventDefault();
5175
- stepLineSpacing(1);
5176
- } else if (e.key === "ArrowDown") {
5177
- e.preventDefault();
5178
- stepLineSpacing(-1);
5179
- }
5180
- }
5676
+ handleLineSpacingKeyDown(e, {
5677
+ isLineHeightMixed,
5678
+ stepLineSpacing,
5679
+ handleLineSpacingBlur
5680
+ });
5181
5681
  },
5182
5682
  min: 100,
5183
5683
  max: 300,
@@ -5192,6 +5692,17 @@ var EditorPanel = ({
5192
5692
  };
5193
5693
 
5194
5694
  // src/RichText/PureRichText/RichTextStyles.tsx
5695
+ function justifyForVerticalAlign(align) {
5696
+ switch (align) {
5697
+ case "bottom":
5698
+ return "flex-end";
5699
+ case "middle":
5700
+ return "center";
5701
+ case "top":
5702
+ default:
5703
+ return "flex-start";
5704
+ }
5705
+ }
5195
5706
  var PureRichTextContainer = styled_components_default.div`
5196
5707
  width: 100%;
5197
5708
  height: 100%;
@@ -5221,27 +5732,57 @@ var PureRichTextContainer = styled_components_default.div`
5221
5732
  ${(props) => props.$hasEventHandlers && !props.$isTextEditing && styled_components_exports.css`
5222
5733
  cursor: pointer;
5223
5734
  `}
5735
+ /* Edit-mode only: hovering a selected block's edges/padding shows grab (PowerPoint-style).
5736
+ EditorWrapper re-asserts its own cursor over the text content. */
5737
+ ${(props) => props.$isEditMode && !props.$isTextEditing && styled_components_exports.css`
5738
+ [data-selected='true'] & {
5739
+ cursor: grab;
5740
+ }
5741
+ `}
5224
5742
  `;
5225
5743
  var DrilldownButton = styled_components_default(Button_default)`
5226
5744
  ${themes_exports.mixins.skipLink()}
5227
- /**
5228
- * Override the secondary Button's transparent default so the skip-link is visible when focused.
5229
- */
5745
+ /* Override the secondary Button's transparent default so the skip-link is visible when focused. */
5230
5746
  &:not([disabled], [aria-disabled='true']) {
5231
5747
  background-color: ${themes_exports.variables.backgroundColorSection};
5232
5748
  }
5233
5749
  `;
5234
5750
  var EditorWrapper = styled_components_default.div`
5235
5751
  width: 100%;
5752
+ /* Fill the container's content box so a click anywhere over the text region enters editing, not
5753
+ just the top. Vertical alignment moves here from the container to keep text top/middle/bottom. */
5754
+ flex: 1 1 auto;
5236
5755
  min-height: 0;
5237
5756
  max-height: 100%;
5757
+ display: flex;
5758
+ flex-direction: column;
5238
5759
  overflow: auto;
5239
- cursor: ${(props) => props.$isTextEditing ? "text" : "default"};
5760
+ /* Cursor over text: editing -> text; view mode w/ interaction -> pointer; view mode plain -> text;
5761
+ edit mode not editing -> default (grab layered below when selected). */
5762
+ cursor: ${(props) => {
5763
+ if (props.$isTextEditing) return "text";
5764
+ if (props.$hasEventHandlers && !props.$isEditMode) return "pointer";
5765
+ if (!props.$isEditMode) return "text";
5766
+ return "default";
5767
+ }};
5768
+
5769
+ /* Selected in edit mode (not editing): grab cursor over the whole block including text, so it
5770
+ doesn't flip to default crossing from padding into text. View mode keeps text/pointer. */
5771
+ ${(props) => props.$isEditMode && !props.$isTextEditing && styled_components_exports.css`
5772
+ [data-selected='true'] & {
5773
+ cursor: grab;
5774
+ }
5775
+ `}
5240
5776
 
5241
5777
  /* Styling for the Slate editor */
5242
5778
  [data-slate-editor] {
5243
5779
  outline: none;
5780
+ /* Fill the stretched wrapper so a click anywhere enters editing, but keep the editable as the
5781
+ vertical-align flex column: the stretched wrapper has no free space to align short content. */
5244
5782
  min-height: 100%;
5783
+ display: flex;
5784
+ flex-direction: column;
5785
+ justify-content: ${(props) => justifyForVerticalAlign(props.$verticalAlign)};
5245
5786
  }
5246
5787
 
5247
5788
  /* Underline styling - match text color */
@@ -5306,8 +5847,179 @@ var LiveRegion = styled_components_default.div`
5306
5847
  border: 0;
5307
5848
  `;
5308
5849
 
5850
+ // src/RichText/PureRichText/utils/fontSize.ts
5851
+ var getFontSizeInPx = (fontSize, customFontSize) => {
5852
+ if (fontSize === "custom" && customFontSize) {
5853
+ return customFontSize;
5854
+ }
5855
+ return FONT_SIZE_PRESETS[fontSize || "default"];
5856
+ };
5857
+
5309
5858
  // src/RichText/PureRichText/renderers/ElementRenderer.tsx
5310
- var createElementRenderer = (isEditMode, defaultLineHeight) => {
5859
+ function isBrokenHref(href) {
5860
+ if (!href) return false;
5861
+ if (href.startsWith("/")) return false;
5862
+ return !isOpenableUrl(href);
5863
+ }
5864
+ function frameworkFlagsHref(href, onLinkOpen) {
5865
+ if (!onLinkOpen) return false;
5866
+ return !/\s/.test(href) && /^https?:\/\//i.test(href);
5867
+ }
5868
+ function frameworkHandlesHref(href) {
5869
+ if (/\s/.test(href)) return false;
5870
+ return /^https?:\/\//i.test(href) || /^\/(?!\/)/.test(href);
5871
+ }
5872
+ var _a;
5873
+ var platformString = typeof navigator !== "undefined" && (((_a = navigator.userAgentData) == null ? void 0 : _a.platform) || navigator.platform) || "";
5874
+ var isMacPlatform = /Mac|iP(hone|ad|od)/.test(platformString);
5875
+ var OVERLAY_STYLE = {
5876
+ position: "fixed",
5877
+ transform: "translateY(-100%) translateY(-6px)",
5878
+ zIndex: 2147483647,
5879
+ maxWidth: 320,
5880
+ padding: "4px 8px",
5881
+ borderRadius: 4,
5882
+ background: "#3c444d",
5883
+ color: "#fff",
5884
+ fontSize: 12,
5885
+ lineHeight: 1.4,
5886
+ overflowWrap: "anywhere",
5887
+ pointerEvents: "none",
5888
+ boxShadow: "0 2px 8px rgba(0,0,0,0.4)"
5889
+ };
5890
+ var styleBlock = { display: "block" };
5891
+ var styleBlockOpacity = { display: "block", opacity: 0.75 };
5892
+ var LinkFollowTooltip = ({
5893
+ show,
5894
+ pos,
5895
+ href
5896
+ }) => {
5897
+ const { fontFamily } = (0, themes_exports.useSplunkTheme)();
5898
+ if (!show || !pos || typeof document === "undefined") return null;
5899
+ return (0, react_dom_exports.createPortal)(
5900
+ /* @__PURE__ */ react_exports.createElement("span", { contentEditable: false, style: __spreadProps(__spreadValues({}, OVERLAY_STYLE), { top: pos.top, left: pos.left, fontFamily }) }, /* @__PURE__ */ react_exports.createElement("span", { style: styleBlock }, href), /* @__PURE__ */ react_exports.createElement("span", { style: styleBlockOpacity }, isMacPlatform ? "\u2318" : "Ctrl", "+click to open")),
5901
+ document.body
5902
+ );
5903
+ };
5904
+ var BrokenLinkNote = ({ pos, href }) => {
5905
+ const { fontFamily } = (0, themes_exports.useSplunkTheme)();
5906
+ if (!pos || typeof document === "undefined") return null;
5907
+ return (0, react_dom_exports.createPortal)(
5908
+ /* @__PURE__ */ react_exports.createElement(
5909
+ "span",
5910
+ {
5911
+ role: "alert",
5912
+ contentEditable: false,
5913
+ style: __spreadProps(__spreadValues({}, OVERLAY_STYLE), { top: pos.top, left: pos.left, fontFamily })
5914
+ },
5915
+ /* @__PURE__ */ react_exports.createElement("span", { style: styleBlock }, "This link can't be opened."),
5916
+ /* @__PURE__ */ react_exports.createElement("span", { style: styleBlockOpacity }, href)
5917
+ ),
5918
+ document.body
5919
+ );
5920
+ };
5921
+ function handleAnchorMouseDown(e, ctx) {
5922
+ if (ctx.isEditMode && !e.metaKey && !e.ctrlKey) e.preventDefault();
5923
+ }
5924
+ function handleAnchorMouseLeave(ctx) {
5925
+ if (ctx.isEditMode) ctx.hideTooltip();
5926
+ ctx.clearBrokenNote();
5927
+ }
5928
+ function handleAnchorClick(e, ctx) {
5929
+ if (ctx.isEditMode) {
5930
+ e.preventDefault();
5931
+ if (e.metaKey || e.ctrlKey) {
5932
+ e.stopPropagation();
5933
+ ctx.activateLink(e.currentTarget);
5934
+ }
5935
+ return;
5936
+ }
5937
+ e.stopPropagation();
5938
+ if (ctx.showBrokenNote || ctx.routeToFramework) {
5939
+ e.preventDefault();
5940
+ ctx.activateLink(e.currentTarget);
5941
+ }
5942
+ }
5943
+ function handleAnchorKeyDown(e, ctx) {
5944
+ if (!ctx.isEditMode && e.key === "Enter") {
5945
+ e.preventDefault();
5946
+ e.stopPropagation();
5947
+ ctx.activateLink(e.currentTarget);
5948
+ }
5949
+ }
5950
+ var LinkElement = ({ attributes, children, isEditMode, url, nameToValue, onLinkOpen }) => {
5951
+ const normalizedHref = resolveLinkHref(url, nameToValue);
5952
+ const broken = isBrokenHref(normalizedHref);
5953
+ const showBrokenNote = broken && !frameworkFlagsHref(normalizedHref, onLinkOpen);
5954
+ const routeToFramework = !!onLinkOpen && frameworkHandlesHref(normalizedHref);
5955
+ const [tooltipPos, setTooltipPos] = (0, react_exports.useState)(null);
5956
+ const [brokenPos, setBrokenPos] = (0, react_exports.useState)(null);
5957
+ const dismissTimer = (0, react_exports.useRef)();
5958
+ const flagBroken = (0, react_exports.useCallback)((el) => {
5959
+ const rect = el.getBoundingClientRect();
5960
+ setBrokenPos({ top: rect.top, left: rect.left });
5961
+ }, []);
5962
+ (0, react_exports.useEffect)(() => {
5963
+ if (!brokenPos) return void 0;
5964
+ dismissTimer.current = setTimeout(() => setBrokenPos(null), 2500);
5965
+ return () => clearTimeout(dismissTimer.current);
5966
+ }, [brokenPos]);
5967
+ const showTooltip = (0, react_exports.useCallback)((ev) => {
5968
+ const rect = ev.currentTarget.getBoundingClientRect();
5969
+ setTooltipPos({ top: rect.top, left: rect.left });
5970
+ }, []);
5971
+ const hideTooltip = (0, react_exports.useCallback)(() => setTooltipPos(null), []);
5972
+ const activateLink = (0, react_exports.useCallback)(
5973
+ (el) => {
5974
+ if (showBrokenNote) {
5975
+ flagBroken(el);
5976
+ return;
5977
+ }
5978
+ openHref(normalizedHref, onLinkOpen);
5979
+ },
5980
+ [showBrokenNote, flagBroken, normalizedHref, onLinkOpen]
5981
+ );
5982
+ const clearBrokenNote = (0, react_exports.useCallback)(() => setBrokenPos(null), []);
5983
+ const ctx = {
5984
+ isEditMode,
5985
+ showBrokenNote,
5986
+ routeToFramework,
5987
+ activateLink,
5988
+ hideTooltip,
5989
+ clearBrokenNote
5990
+ };
5991
+ return /* @__PURE__ */ react_exports.createElement(
5992
+ "a",
5993
+ __spreadProps(__spreadValues({
5994
+ href: normalizedHref,
5995
+ style: { display: "inline" }
5996
+ }, attributes), {
5997
+ target: isEditMode || routeToFramework || broken ? void 0 : "_blank",
5998
+ rel: isEditMode || routeToFramework ? void 0 : "noopener noreferrer",
5999
+ tabIndex: isEditMode ? void 0 : 0,
6000
+ onMouseDown: (e) => handleAnchorMouseDown(e, ctx),
6001
+ onMouseEnter: isEditMode ? showTooltip : void 0,
6002
+ onMouseLeave: () => handleAnchorMouseLeave(ctx),
6003
+ onClick: (e) => handleAnchorClick(e, ctx),
6004
+ onKeyDown: (e) => handleAnchorKeyDown(e, ctx)
6005
+ }),
6006
+ children,
6007
+ /* @__PURE__ */ react_exports.createElement(LinkFollowTooltip, { show: isEditMode, pos: tooltipPos, href: normalizedHref }),
6008
+ /* @__PURE__ */ react_exports.createElement(BrokenLinkNote, { pos: brokenPos, href: normalizedHref })
6009
+ );
6010
+ };
6011
+ function openHref(href, onLinkOpen) {
6012
+ if (!href) return;
6013
+ if (onLinkOpen && frameworkHandlesHref(href)) {
6014
+ onLinkOpen(href);
6015
+ return;
6016
+ }
6017
+ try {
6018
+ window.open(href, "_blank", "noopener,noreferrer");
6019
+ } catch (e) {
6020
+ }
6021
+ }
6022
+ var createElementRenderer = (isEditMode, defaultLineHeight, nameToValue, onLinkOpen) => {
5311
6023
  return function ElementRenderer({ attributes, children, element }) {
5312
6024
  const customElement = element;
5313
6025
  const baseStyle = {
@@ -5332,36 +6044,23 @@ var createElementRenderer = (isEditMode, defaultLineHeight) => {
5332
6044
  if (firstLeaf == null ? void 0 : firstLeaf.fontSize) {
5333
6045
  listItemStyle.fontSize = firstLeaf.fontSize;
5334
6046
  }
5335
- const fontSize = parseInt(String((firstLeaf == null ? void 0 : firstLeaf.fontSize) || "0"), 10);
6047
+ const fontSize = Number.parseInt(String((firstLeaf == null ? void 0 : firstLeaf.fontSize) || "0"), 10);
5336
6048
  if (customElement.align === "center" || customElement.align === "right" || fontSize > 24) {
5337
6049
  listItemStyle.listStylePosition = "inside";
5338
6050
  }
5339
6051
  return /* @__PURE__ */ react_exports.createElement("li", __spreadValues({ style: listItemStyle }, attributes), children);
5340
6052
  }
5341
6053
  case "link": {
5342
- const normalizedHref = normalizeUrl(customElement.url || "");
5343
6054
  return /* @__PURE__ */ react_exports.createElement(
5344
- "a",
5345
- __spreadProps(__spreadValues({
5346
- href: normalizedHref,
5347
- style: { display: "inline" }
5348
- }, attributes), {
5349
- target: isEditMode ? void 0 : "_blank",
5350
- rel: isEditMode ? void 0 : "noopener noreferrer",
5351
- tabIndex: isEditMode ? void 0 : 0,
5352
- onClick: (e) => {
5353
- if (isEditMode) {
5354
- e.preventDefault();
5355
- return;
5356
- }
5357
- e.stopPropagation();
5358
- },
5359
- onKeyDown: (e) => {
5360
- if (!isEditMode && e.key === "Enter") {
5361
- window.open(normalizedHref, "_blank", "noopener,noreferrer");
5362
- }
5363
- }
5364
- }),
6055
+ LinkElement,
6056
+ {
6057
+ attributes,
6058
+ element,
6059
+ isEditMode,
6060
+ url: customElement.url || "",
6061
+ nameToValue,
6062
+ onLinkOpen
6063
+ },
5365
6064
  children
5366
6065
  );
5367
6066
  }
@@ -5403,21 +6102,60 @@ var Leaf = ({ attributes, children, leaf }) => {
5403
6102
  if (customLeaf.strikethrough) {
5404
6103
  content = /* @__PURE__ */ react_exports.createElement("s", null, content);
5405
6104
  }
5406
- if (customLeaf.tokenName) {
5407
- return /* @__PURE__ */ react_exports.createElement("span", __spreadProps(__spreadValues({}, attributes), { style }), /* @__PURE__ */ react_exports.createElement("span", { "data-token-name": customLeaf.isRawToken ? customLeaf.tokenName : void 0 }, content));
6105
+ if (customLeaf.tokenName) {
6106
+ return /* @__PURE__ */ react_exports.createElement("span", __spreadProps(__spreadValues({}, attributes), { style }), /* @__PURE__ */ react_exports.createElement("span", { "data-token-name": customLeaf.isRawToken ? customLeaf.tokenName : void 0 }, content));
6107
+ }
6108
+ return /* @__PURE__ */ react_exports.createElement("span", __spreadProps(__spreadValues({}, attributes), { style }), content);
6109
+ };
6110
+
6111
+ // src/RichText/PureRichText/hooks/useEditorSetup.ts
6112
+ function pointAfterLinkInBlock(e, linkPath) {
6113
+ const blockEntry = slate_exports.Editor.above(e, {
6114
+ at: linkPath,
6115
+ match: (n) => !slate_exports.Editor.isEditor(n) && slate_exports.Element.isElement(n) && slate_exports.Editor.isBlock(e, n)
6116
+ });
6117
+ const after = slate_exports.Editor.after(e, linkPath);
6118
+ if (after && blockEntry && slate_exports.Path.isDescendant(after.path, blockEntry[1])) {
6119
+ return after;
6120
+ }
6121
+ return null;
6122
+ }
6123
+ function pointBeforeLinkInBlock(e, linkPath) {
6124
+ const blockEntry = slate_exports.Editor.above(e, {
6125
+ at: linkPath,
6126
+ match: (n) => !slate_exports.Editor.isEditor(n) && slate_exports.Element.isElement(n) && slate_exports.Editor.isBlock(e, n)
6127
+ });
6128
+ const before = slate_exports.Editor.before(e, linkPath);
6129
+ if (before && blockEntry && slate_exports.Path.isDescendant(before.path, blockEntry[1])) {
6130
+ return before;
6131
+ }
6132
+ return null;
6133
+ }
6134
+ function exitLinkStartBeforeInsert(e) {
6135
+ const { selection } = e;
6136
+ if (!selection || !slate_exports.Range.isCollapsed(selection)) return;
6137
+ const above = slate_exports.Editor.above(e, {
6138
+ match: (n) => !slate_exports.Editor.isEditor(n) && slate_exports.Element.isElement(n) && n.type === "link"
6139
+ });
6140
+ if (!above) return;
6141
+ const [, linkPath] = above;
6142
+ if (!slate_exports.Editor.isStart(e, selection.anchor, linkPath)) return;
6143
+ let before = pointBeforeLinkInBlock(e, linkPath);
6144
+ if (before) {
6145
+ const prevLink = slate_exports.Editor.above(e, {
6146
+ at: before,
6147
+ match: (n) => !slate_exports.Editor.isEditor(n) && slate_exports.Element.isElement(n) && n.type === "link"
6148
+ });
6149
+ if (prevLink) before = null;
6150
+ }
6151
+ if (!before) {
6152
+ slate_exports.Transforms.insertNodes(e, { text: "" }, { at: linkPath });
6153
+ before = pointBeforeLinkInBlock(e, slate_exports.Path.next(linkPath));
5408
6154
  }
5409
- return /* @__PURE__ */ react_exports.createElement("span", __spreadProps(__spreadValues({}, attributes), { style }), content);
5410
- };
5411
-
5412
- // src/RichText/PureRichText/utils/fontSize.ts
5413
- var getFontSizeInPx = (fontSize, customFontSize) => {
5414
- if (fontSize === "custom" && customFontSize) {
5415
- return customFontSize;
6155
+ if (before) {
6156
+ slate_exports.Transforms.select(e, before);
5416
6157
  }
5417
- return FONT_SIZE_PRESETS[fontSize || "default"];
5418
- };
5419
-
5420
- // src/RichText/PureRichText/hooks/useEditorSetup.ts
6158
+ }
5421
6159
  function exitLinkBeforeInsert(e) {
5422
6160
  const { selection } = e;
5423
6161
  if (!selection || !slate_exports.Range.isCollapsed(selection)) return;
@@ -5426,8 +6164,17 @@ function exitLinkBeforeInsert(e) {
5426
6164
  });
5427
6165
  if (!above) return;
5428
6166
  const [, linkPath] = above;
6167
+ if (slate_exports.Editor.isStart(e, selection.anchor, linkPath)) {
6168
+ exitLinkStartBeforeInsert(e);
6169
+ return;
6170
+ }
5429
6171
  if (!slate_exports.Editor.isEnd(e, selection.anchor, linkPath)) return;
5430
- const after = slate_exports.Editor.after(e, linkPath);
6172
+ let after = pointAfterLinkInBlock(e, linkPath);
6173
+ if (!after) {
6174
+ const trailingPath = slate_exports.Path.next(linkPath);
6175
+ slate_exports.Transforms.insertNodes(e, { text: "" }, { at: trailingPath });
6176
+ after = pointAfterLinkInBlock(e, linkPath);
6177
+ }
5431
6178
  if (after) {
5432
6179
  slate_exports.Transforms.select(e, after);
5433
6180
  }
@@ -5525,6 +6272,22 @@ function getLinkRangeAtPoint(e, point) {
5525
6272
  function getAtomicRangeAtPoint(e, point) {
5526
6273
  return getTokenRangeAtPoint(e, point) || getLinkRangeAtPoint(e, point);
5527
6274
  }
6275
+ function deleteAtomicRange(e, point, range2) {
6276
+ const linkEntry = slate_exports.Editor.above(e, {
6277
+ at: point,
6278
+ match: (n) => !slate_exports.Editor.isEditor(n) && slate_exports.Element.isElement(n) && n.type === "link"
6279
+ });
6280
+ if (linkEntry) {
6281
+ const [, linkPath] = linkEntry;
6282
+ const before = slate_exports.Editor.before(e, slate_exports.Editor.start(e, linkPath));
6283
+ const after = slate_exports.Editor.after(e, slate_exports.Editor.end(e, linkPath));
6284
+ if (before) slate_exports.Transforms.select(e, before);
6285
+ else if (after) slate_exports.Transforms.select(e, after);
6286
+ slate_exports.Transforms.removeNodes(e, { at: linkPath });
6287
+ return;
6288
+ }
6289
+ slate_exports.Transforms.delete(e, { at: range2 });
6290
+ }
5528
6291
  function isStrictlyInsideAtomic(e, point) {
5529
6292
  const [node] = slate_exports.Editor.node(e, point);
5530
6293
  const custom = node;
@@ -5549,16 +6312,16 @@ function getPointAfterAtomic(e, point) {
5549
6312
  });
5550
6313
  if (linkEntry) {
5551
6314
  const [, linkPath] = linkEntry;
5552
- return slate_exports.Editor.after(e, linkPath) || null;
6315
+ return pointAfterLinkInBlock(e, linkPath);
5553
6316
  }
5554
6317
  const tokenRange = getTokenRangeAtPoint(e, point);
5555
6318
  if (tokenRange) return tokenRange.focus;
5556
6319
  return null;
5557
6320
  }
5558
6321
  function getAtomicExpansion(atomicRange, isAnchorEndpoint, isBackward) {
5559
- const adjustAnchor = isAnchorEndpoint ? !isBackward : isBackward;
5560
- const target = adjustAnchor ? atomicRange.anchor : atomicRange.focus;
5561
- return { adjustAnchor, target };
6322
+ const isLeftEnd = isAnchorEndpoint ? !isBackward : isBackward;
6323
+ const target = isLeftEnd ? atomicRange.anchor : atomicRange.focus;
6324
+ return { adjustAnchor: isAnchorEndpoint, target };
5562
6325
  }
5563
6326
  function snapEndpointToAtomic(e, point, isAnchorEndpoint, anchor, focus, isBackward) {
5564
6327
  const atomicRange = getAtomicRangeAtPoint(e, point);
@@ -5603,7 +6366,7 @@ function expandSelectionToAtomic(e) {
5603
6366
  }
5604
6367
  }
5605
6368
  function moveCursorPastAtomicIfNeeded(e) {
5606
- var _a;
6369
+ var _a2;
5607
6370
  if (!e.selection || !slate_exports.Range.isCollapsed(e.selection)) return;
5608
6371
  const { anchor } = e.selection;
5609
6372
  const [node] = slate_exports.Editor.node(e, anchor);
@@ -5612,9 +6375,10 @@ function moveCursorPastAtomicIfNeeded(e) {
5612
6375
  const endPoint = { path: anchor.path, offset: node.text.length };
5613
6376
  e.selection = { anchor: endPoint, focus: endPoint };
5614
6377
  }
5615
- const currentMarks = (_a = slate_exports.Editor.marks(e)) != null ? _a : {};
6378
+ const currentMarks = (_a2 = slate_exports.Editor.marks(e)) != null ? _a2 : {};
5616
6379
  const marksWithoutToken = __spreadValues({}, currentMarks);
5617
6380
  delete marksWithoutToken.tokenName;
6381
+ delete marksWithoutToken.tokenOccurrence;
5618
6382
  delete marksWithoutToken.isEscapedDollar;
5619
6383
  e.marks = marksWithoutToken;
5620
6384
  return;
@@ -5653,23 +6417,51 @@ function inSameBlock(ed, a, b) {
5653
6417
  const pb = blockPathAt(ed, b);
5654
6418
  return pa !== null && pb !== null && slate_exports.Path.equals(pa, pb);
5655
6419
  }
6420
+ function atomicRangeBefore(ed, point) {
6421
+ const before = slate_exports.Editor.before(ed, point);
6422
+ if (!before || !inSameBlock(ed, point, before)) return null;
6423
+ const direct = getAtomicRangeAtPoint(ed, before);
6424
+ if (direct) return { range: direct, at: before };
6425
+ const [node] = slate_exports.Editor.node(ed, before.path);
6426
+ if (slate_exports.Text.isText(node) && node.text === "") {
6427
+ const prior = slate_exports.Editor.before(ed, before);
6428
+ if (prior && inSameBlock(ed, point, prior)) {
6429
+ const priorRange = getAtomicRangeAtPoint(ed, prior);
6430
+ if (priorRange) return { range: priorRange, at: prior };
6431
+ }
6432
+ }
6433
+ return null;
6434
+ }
6435
+ function atomicRangeAfter(ed, point) {
6436
+ const after = slate_exports.Editor.after(ed, point);
6437
+ if (!after || !inSameBlock(ed, point, after)) return null;
6438
+ const direct = getAtomicRangeAtPoint(ed, after);
6439
+ if (direct) return { range: direct, at: after };
6440
+ const [node] = slate_exports.Editor.node(ed, after.path);
6441
+ if (slate_exports.Text.isText(node) && node.text === "") {
6442
+ const next = slate_exports.Editor.after(ed, after);
6443
+ if (next && inSameBlock(ed, point, next)) {
6444
+ const nextRange = getAtomicRangeAtPoint(ed, next);
6445
+ if (nextRange) return { range: nextRange, at: next };
6446
+ }
6447
+ }
6448
+ return null;
6449
+ }
5656
6450
  function tryDeleteAtomicBackward(ed, anchor) {
5657
6451
  if (isStrictlyInsideAtomic(ed, anchor)) {
5658
6452
  const range2 = getAtomicRangeAtPoint(ed, anchor);
5659
- if (range2) slate_exports.Transforms.delete(ed, { at: range2 });
6453
+ if (range2) deleteAtomicRange(ed, anchor, range2);
5660
6454
  return true;
5661
6455
  }
5662
6456
  const currentRange = getAtomicRangeAtPoint(ed, anchor);
5663
6457
  if (currentRange && slate_exports.Point.equals(anchor, currentRange.focus)) {
5664
- slate_exports.Transforms.delete(ed, { at: currentRange });
6458
+ deleteAtomicRange(ed, anchor, currentRange);
5665
6459
  return true;
5666
6460
  }
5667
- if (currentRange) return false;
5668
- const before = slate_exports.Editor.before(ed, anchor);
5669
- if (!before || !inSameBlock(ed, anchor, before)) return false;
5670
- const prevRange = getAtomicRangeAtPoint(ed, before);
5671
- if (!prevRange) return false;
5672
- slate_exports.Transforms.delete(ed, { at: prevRange });
6461
+ if (currentRange && !slate_exports.Point.equals(anchor, currentRange.anchor)) return false;
6462
+ const prev = atomicRangeBefore(ed, anchor);
6463
+ if (!prev) return false;
6464
+ deleteAtomicRange(ed, prev.at, prev.range);
5673
6465
  return true;
5674
6466
  }
5675
6467
  function tryUnwrapListItem(ed, anchor) {
@@ -5701,20 +6493,18 @@ function tryUnwrapListItem(ed, anchor) {
5701
6493
  function tryDeleteAtomicForward(ed, anchor) {
5702
6494
  if (isStrictlyInsideAtomic(ed, anchor)) {
5703
6495
  const range2 = getAtomicRangeAtPoint(ed, anchor);
5704
- if (range2) slate_exports.Transforms.delete(ed, { at: range2 });
6496
+ if (range2) deleteAtomicRange(ed, anchor, range2);
5705
6497
  return true;
5706
6498
  }
5707
6499
  const fwdRange = getAtomicRangeAtPoint(ed, anchor);
5708
6500
  if (fwdRange && slate_exports.Point.equals(anchor, fwdRange.anchor)) {
5709
- slate_exports.Transforms.delete(ed, { at: fwdRange });
6501
+ deleteAtomicRange(ed, anchor, fwdRange);
5710
6502
  return true;
5711
6503
  }
5712
- if (fwdRange) return false;
5713
- const after = slate_exports.Editor.after(ed, anchor);
5714
- if (!after || !inSameBlock(ed, anchor, after)) return false;
5715
- const nextRange = getAtomicRangeAtPoint(ed, after);
5716
- if (!nextRange) return false;
5717
- slate_exports.Transforms.delete(ed, { at: nextRange });
6504
+ if (fwdRange && !slate_exports.Point.equals(anchor, fwdRange.focus)) return false;
6505
+ const next = atomicRangeAfter(ed, anchor);
6506
+ if (!next) return false;
6507
+ deleteAtomicRange(ed, next.at, next.range);
5718
6508
  return true;
5719
6509
  }
5720
6510
  function recoverStaleSelection(e) {
@@ -5739,15 +6529,27 @@ function expandAtomicPreservingMarks(e) {
5739
6529
  e.marks = savedMarks;
5740
6530
  }
5741
6531
  }
6532
+ function stripAtomicMarksInRange(e, range2) {
6533
+ slate_exports.Transforms.unsetNodes(e, ["tokenName", "tokenOccurrence", "isEscapedDollar", "isRawToken"], {
6534
+ at: range2,
6535
+ match: (n) => slate_exports.Text.isText(n) && (Boolean(n.tokenName) || Boolean(n.isEscapedDollar))
6536
+ });
6537
+ }
5742
6538
  function installInsertOverrides(e, defaultTextStyleRef, onBeforeBreak) {
5743
6539
  const { insertText, insertBreak } = e;
5744
6540
  e.insertText = (text) => {
5745
6541
  if (text && isLinkActive(e)) {
6542
+ if (e.selection && !slate_exports.Range.isCollapsed(e.selection)) {
6543
+ slate_exports.Transforms.delete(e);
6544
+ }
5746
6545
  exitLinkBeforeInsert(e);
5747
6546
  }
5748
6547
  if (text === " " && handleAutoformat(e, defaultTextStyleRef)) {
5749
6548
  return;
5750
6549
  }
6550
+ if (e.selection && !slate_exports.Range.isCollapsed(e.selection)) {
6551
+ stripAtomicMarksInRange(e, e.selection);
6552
+ }
5751
6553
  moveCursorPastAtomicIfNeeded(e);
5752
6554
  insertText(text);
5753
6555
  };
@@ -5758,6 +6560,15 @@ function installInsertOverrides(e, defaultTextStyleRef, onBeforeBreak) {
5758
6560
  insertBreak();
5759
6561
  };
5760
6562
  }
6563
+ function handleTextInsert(e, event) {
6564
+ if (event.inputType !== "insertText" || typeof event.data !== "string" || event.data === "") {
6565
+ return false;
6566
+ }
6567
+ if (!e.selection) return false;
6568
+ event.preventDefault();
6569
+ e.insertText(event.data);
6570
+ return true;
6571
+ }
5761
6572
  function installDeleteOverrides(e) {
5762
6573
  const { deleteBackward, deleteForward } = e;
5763
6574
  e.deleteBackward = (unit) => {
@@ -5776,12 +6587,62 @@ function installDeleteOverrides(e) {
5776
6587
  deleteForward(unit);
5777
6588
  };
5778
6589
  }
6590
+ function getTokenRun(children, start) {
6591
+ const first = children[start];
6592
+ if (!slate_exports.Text.isText(first) || !first.tokenName) return null;
6593
+ let end = start + 1;
6594
+ while (end < children.length) {
6595
+ const child = children[end];
6596
+ if (!slate_exports.Text.isText(child) || child.tokenName !== first.tokenName) break;
6597
+ end += 1;
6598
+ }
6599
+ return { start, end, first };
6600
+ }
6601
+ function normalizeTokenRun(e, children, path, run) {
6602
+ const { start, end, first } = run;
6603
+ if (end - start === 1) {
6604
+ if (first.tokenOccurrence === void 0) return false;
6605
+ slate_exports.Transforms.unsetNodes(e, "tokenOccurrence", { at: path.concat(start) });
6606
+ return true;
6607
+ }
6608
+ for (let index = start; index < end; index += 1) {
6609
+ const child = children[index];
6610
+ const occurrence = index - start;
6611
+ if (child.tokenOccurrence !== occurrence) {
6612
+ slate_exports.Transforms.setNodes(e, { tokenOccurrence: occurrence }, { at: path.concat(index) });
6613
+ return true;
6614
+ }
6615
+ }
6616
+ return false;
6617
+ }
6618
+ function normalizeAdjacentTokenOccurrences(e, node, path) {
6619
+ let start = 0;
6620
+ while (start < node.children.length) {
6621
+ const run = getTokenRun(node.children, start);
6622
+ if (run) {
6623
+ if (normalizeTokenRun(e, node.children, path, run)) return true;
6624
+ start = run.end;
6625
+ } else {
6626
+ start += 1;
6627
+ }
6628
+ }
6629
+ return false;
6630
+ }
5779
6631
  function installNormalizeOverride(e) {
5780
6632
  const { normalizeNode } = e;
5781
6633
  e.normalizeNode = (entry) => {
5782
6634
  const [node, path] = entry;
6635
+ if (slate_exports.Element.isElement(node) && normalizeAdjacentTokenOccurrences(e, node, path)) {
6636
+ return;
6637
+ }
5783
6638
  if (slate_exports.Text.isText(node) && node.text === "" && (node.tokenName || node.isEscapedDollar)) {
5784
- slate_exports.Transforms.unsetNodes(e, ["tokenName", "isEscapedDollar", "isRawToken"], { at: path });
6639
+ slate_exports.Transforms.unsetNodes(e, ["tokenName", "tokenOccurrence", "isEscapedDollar", "isRawToken"], {
6640
+ at: path
6641
+ });
6642
+ return;
6643
+ }
6644
+ if (slate_exports.Element.isElement(node) && node.type === "link" && slate_exports.Node.string(node) === "") {
6645
+ slate_exports.Transforms.removeNodes(e, { at: path });
5785
6646
  return;
5786
6647
  }
5787
6648
  normalizeNode(entry);
@@ -5828,234 +6689,100 @@ function useInitialMarks(editor, isEditMode, defaultTextStyle) {
5828
6689
  if (hasInitializedMarksRef.current) return;
5829
6690
  if (isEditMode && isEditorEmpty(editor)) {
5830
6691
  applyInitialMarks(editor, defaultTextStyle);
5831
- hasInitializedMarksRef.current = true;
5832
- }
5833
- }, [isEditMode, editor]);
5834
- }
5835
-
5836
- // src/RichText/PureRichText/hooks/useFakeHighlight.ts
5837
- function pointToAbsOffset(editor, point) {
5838
- let offset = 0;
5839
- for (const [textNode, path] of slate_exports.Editor.nodes(editor, {
5840
- at: [],
5841
- match: (n) => slate_exports.Text.isText(n)
5842
- })) {
5843
- if (slate_exports.Path.equals(path, point.path)) return offset + point.offset;
5844
- offset += textNode.text.length;
5845
- }
5846
- return offset;
5847
- }
5848
- function rangeToAbsOffsets(editor, range2) {
5849
- const [start, end] = slate_exports.Range.edges(range2);
5850
- return {
5851
- absStart: pointToAbsOffset(editor, start),
5852
- absEnd: pointToAbsOffset(editor, end)
5853
- };
5854
- }
5855
- function absOffsetToPoint(editor, absOffset, isStart = false) {
5856
- let seen = 0;
5857
- for (const [textNode, path] of slate_exports.Editor.nodes(editor, {
5858
- at: [],
5859
- match: (n) => slate_exports.Text.isText(n)
5860
- })) {
5861
- const len = textNode.text.length;
5862
- if (isStart ? seen + len > absOffset : seen + len >= absOffset) {
5863
- return { path, offset: absOffset - seen };
5864
- }
5865
- seen += len;
5866
- }
5867
- return null;
5868
- }
5869
- function useFakeHighlight(editor) {
5870
- const [fakeHighlightAbs, setFakeHighlightAbs] = (0, react_exports.useState)(null);
5871
- const fakeHighlightAbsRef = (0, react_exports.useRef)(null);
5872
- const updateFakeHighlight = (0, react_exports.useCallback)(
5873
- (range2) => {
5874
- if (!range2) {
5875
- fakeHighlightAbsRef.current = null;
5876
- setFakeHighlightAbs(null);
5877
- return;
5878
- }
5879
- const abs = rangeToAbsOffsets(editor, range2);
5880
- fakeHighlightAbsRef.current = abs;
5881
- setFakeHighlightAbs(abs);
5882
- },
5883
- [editor]
5884
- );
5885
- const updateFakeHighlightAbs = (0, react_exports.useCallback)((abs) => {
5886
- fakeHighlightAbsRef.current = abs;
5887
- setFakeHighlightAbs(abs);
5888
- }, []);
5889
- const decorate = (0, react_exports.useCallback)(
5890
- ([node, path]) => {
5891
- const abs = fakeHighlightAbsRef.current;
5892
- if (!abs || !slate_exports.Text.isText(node)) return [];
5893
- const { absStart, absEnd } = abs;
5894
- let nodeAbsStart = 0;
5895
- for (const [n, p] of slate_exports.Editor.nodes(editor, {
5896
- at: [],
5897
- match: (nd) => slate_exports.Text.isText(nd)
5898
- })) {
5899
- if (slate_exports.Path.equals(p, path)) break;
5900
- nodeAbsStart += n.text.length;
5901
- }
5902
- const nodeAbsEnd = nodeAbsStart + node.text.length;
5903
- const overlapStart = Math.max(absStart, nodeAbsStart);
5904
- const overlapEnd = Math.min(absEnd, nodeAbsEnd);
5905
- if (overlapStart >= overlapEnd) return [];
5906
- return [
5907
- {
5908
- anchor: { path, offset: overlapStart - nodeAbsStart },
5909
- focus: { path, offset: overlapEnd - nodeAbsStart },
5910
- fakeHighlight: true
5911
- }
5912
- ];
5913
- },
5914
- // fakeHighlightAbs (state) triggers re-evaluation; fakeHighlightAbsRef provides the current value.
5915
- // eslint-disable-next-line react-hooks/exhaustive-deps
5916
- [fakeHighlightAbs, editor]
5917
- );
5918
- return {
5919
- fakeHighlightAbs,
5920
- fakeHighlightAbsRef,
5921
- updateFakeHighlight,
5922
- updateFakeHighlightAbs,
5923
- decorate
5924
- };
5925
- }
5926
-
5927
- // src/RichText/PureRichText/hooks/useTokenMap.ts
5928
- var NAME_CHARS = String.raw` \w.-`;
5929
- var NAMESPACE_PREFIX = `(?:[${NAME_CHARS}]+:)?`;
5930
- var NAME = String.raw`(?:(?=[\w.-])[${NAME_CHARS}]*[\w.-])`;
5931
- var FILTERS = String.raw`(?:\|[a-zA-Z]+)*`;
5932
- var TOKEN_CONTENT = `${NAMESPACE_PREFIX}${NAME}${FILTERS}`;
5933
- var TOKEN_PATTERN = new RegExp(String.raw`\$(${TOKEN_CONTENT})\$`, "g");
5934
- var TOKEN_OR_ESCAPE_PATTERN = new RegExp(
5935
- String.raw`\$\$|\$(${TOKEN_CONTENT})\$(?=\$${TOKEN_CONTENT}\$|\$\$|[^$]|$)`,
5936
- "g"
5937
- );
5938
- function toValueString(value) {
5939
- return value === null ? null : String(value);
5940
- }
5941
- function normalizeTokenMetadata(metadata, resolvedContent) {
5942
- const nameToValue = /* @__PURE__ */ new Map();
5943
- if (!metadata || metadata.length === 0) {
5944
- return { nameToValue, rawContent: resolvedContent, reconciled: true };
5945
- }
5946
- const sorted = [...metadata].sort((a, b) => a.start - b.start);
5947
- for (const { match, value } of sorted) {
5948
- const strValue = toValueString(value);
5949
- if (match !== "$$" && strValue !== null && strValue !== "") {
5950
- nameToValue.set(match.slice(1, -1), strValue);
5951
- }
5952
- }
5953
- let raw = "";
5954
- let rawCursor = 0;
5955
- let resolvedCursor = 0;
5956
- for (const entry of sorted) {
5957
- const { match, value, start, end } = entry;
5958
- const strValue = toValueString(value);
5959
- const literalLength = start - rawCursor;
5960
- const expected = strValue != null ? strValue : match;
5961
- const valuePos = resolvedCursor + literalLength;
5962
- if (literalLength < 0 || resolvedContent.slice(valuePos, valuePos + expected.length) !== expected) {
5963
- return { nameToValue, rawContent: resolvedContent, reconciled: false };
5964
- }
5965
- raw += resolvedContent.slice(resolvedCursor, valuePos);
5966
- raw += match;
5967
- rawCursor = end;
5968
- resolvedCursor = valuePos + expected.length;
5969
- }
5970
- raw += resolvedContent.slice(resolvedCursor);
5971
- return { nameToValue, rawContent: raw, reconciled: true };
5972
- }
5973
- function wrapTreeNodes(nodes, splitLeaf) {
5974
- const processNode = (node) => {
5975
- if (slate_exports.Text.isText(node)) {
5976
- return splitLeaf(node);
5977
- }
5978
- if (slate_exports.Element.isElement(node)) {
5979
- return [__spreadProps(__spreadValues({}, node), { children: node.children.flatMap(processNode) })];
5980
- }
5981
- return [node];
5982
- };
5983
- return nodes.flatMap(processNode);
5984
- }
5985
- function wrapRawTokensInTree(nodes, nameToValue) {
5986
- return wrapTreeNodes(nodes, (node) => splitTextByRawTokens(node, nameToValue));
5987
- }
5988
- function splitTextByRawTokens(textNode, nameToValue) {
5989
- const _a = textNode, { text, tokenName: existingTokenName, isEscapedDollar } = _a, rest = __objRest(_a, ["text", "tokenName", "isEscapedDollar"]);
5990
- const marks = __spreadValues({}, rest);
5991
- delete marks.isRawToken;
5992
- if (!text) return [textNode];
5993
- if (isEscapedDollar) {
5994
- if (text !== "$" && text !== "$$") return [textNode];
5995
- return [__spreadProps(__spreadValues({}, textNode), { text: displayTextForEscapedDollar(nameToValue) })];
5996
- }
5997
- if (existingTokenName) {
5998
- const display = displayTextForToken(existingTokenName, nameToValue);
5999
- return [__spreadProps(__spreadValues({}, textNode), { text: display, isRawToken: !nameToValue })];
6000
- }
6001
- const re = new RegExp(TOKEN_OR_ESCAPE_PATTERN.source, "g");
6002
- const result = [];
6003
- let lastIndex = 0;
6004
- let match = re.exec(text);
6005
- while (match !== null) {
6006
- const startIdx = match.index;
6007
- const fullMatch = match[0];
6008
- const name = match[1];
6009
- if (startIdx > lastIndex) {
6010
- result.push(__spreadValues({ text: text.slice(lastIndex, startIdx) }, marks));
6011
- }
6012
- if (name === void 0) {
6013
- result.push(__spreadProps(__spreadValues({ text: displayTextForEscapedDollar(nameToValue) }, marks), { isEscapedDollar: true }));
6014
- } else {
6015
- result.push(__spreadProps(__spreadValues({
6016
- text: displayTextForToken(name, nameToValue)
6017
- }, marks), {
6018
- tokenName: name,
6019
- isRawToken: !nameToValue
6020
- }));
6021
- }
6022
- lastIndex = startIdx + fullMatch.length;
6023
- match = re.exec(text);
6024
- }
6025
- if (result.length === 0) return [textNode];
6026
- if (lastIndex < text.length) {
6027
- result.push(__spreadValues({ text: text.slice(lastIndex) }, marks));
6028
- }
6029
- return result;
6692
+ hasInitializedMarksRef.current = true;
6693
+ }
6694
+ }, [isEditMode, editor]);
6030
6695
  }
6031
- function displayTextForToken(name, nameToValue) {
6032
- const value = nameToValue == null ? void 0 : nameToValue.get(name);
6033
- return value !== void 0 && value !== "" ? value : `$${name}$`;
6696
+
6697
+ // src/RichText/PureRichText/hooks/useFakeHighlight.ts
6698
+ function pointToAbsOffset(editor, point) {
6699
+ let offset = 0;
6700
+ for (const [textNode, path] of slate_exports.Editor.nodes(editor, {
6701
+ at: [],
6702
+ match: (n) => slate_exports.Text.isText(n)
6703
+ })) {
6704
+ if (slate_exports.Path.equals(path, point.path)) return offset + point.offset;
6705
+ offset += textNode.text.length;
6706
+ }
6707
+ return offset;
6034
6708
  }
6035
- function displayTextForEscapedDollar(nameToValue) {
6036
- return nameToValue ? "$" : "$$";
6709
+ function rangeToAbsOffsets(editor, range2) {
6710
+ const [start, end] = slate_exports.Range.edges(range2);
6711
+ return {
6712
+ absStart: pointToAbsOffset(editor, start),
6713
+ absEnd: pointToAbsOffset(editor, end)
6714
+ };
6037
6715
  }
6038
- var EMPTY_MAP = /* @__PURE__ */ new Map();
6039
- function useTokenMap(resolvedContent, richTextTokenMetadata) {
6040
- var _a, _b, _c, _d, _e;
6041
- const contentMetadata = (_a = richTextTokenMetadata == null ? void 0 : richTextTokenMetadata.richTextContent) != null ? _a : null;
6042
- const serialized = contentMetadata ? JSON.stringify(contentMetadata) : null;
6043
- const resultRef = (0, react_exports.useRef)(null);
6044
- const prevSerializedRef = (0, react_exports.useRef)(null);
6045
- const prevResolvedRef = (0, react_exports.useRef)("");
6046
- if (serialized !== prevSerializedRef.current || resolvedContent !== prevResolvedRef.current) {
6047
- prevSerializedRef.current = serialized;
6048
- prevResolvedRef.current = resolvedContent;
6049
- if (contentMetadata) {
6050
- const next = normalizeTokenMetadata(contentMetadata, resolvedContent);
6051
- resultRef.current = next.reconciled || !resultRef.current ? next : __spreadProps(__spreadValues({}, next), { rawContent: resultRef.current.rawContent });
6052
- } else {
6053
- resultRef.current = null;
6716
+ function absOffsetToPoint(editor, absOffset, isStart = false) {
6717
+ let seen = 0;
6718
+ for (const [textNode, path] of slate_exports.Editor.nodes(editor, {
6719
+ at: [],
6720
+ match: (n) => slate_exports.Text.isText(n)
6721
+ })) {
6722
+ const len = textNode.text.length;
6723
+ if (isStart ? seen + len > absOffset : seen + len >= absOffset) {
6724
+ return { path, offset: absOffset - seen };
6054
6725
  }
6726
+ seen += len;
6055
6727
  }
6056
- const nameToValue = (_c = (_b = resultRef.current) == null ? void 0 : _b.nameToValue) != null ? _c : EMPTY_MAP;
6057
- const rawContent = (_e = (_d = resultRef.current) == null ? void 0 : _d.rawContent) != null ? _e : null;
6058
- return { nameToValue, rawContent };
6728
+ return null;
6729
+ }
6730
+ function useFakeHighlight(editor) {
6731
+ const [fakeHighlightAbs, setFakeHighlightAbs] = (0, react_exports.useState)(null);
6732
+ const fakeHighlightAbsRef = (0, react_exports.useRef)(null);
6733
+ const updateFakeHighlight = (0, react_exports.useCallback)(
6734
+ (range2) => {
6735
+ if (!range2) {
6736
+ fakeHighlightAbsRef.current = null;
6737
+ setFakeHighlightAbs(null);
6738
+ return;
6739
+ }
6740
+ const abs = rangeToAbsOffsets(editor, range2);
6741
+ fakeHighlightAbsRef.current = abs;
6742
+ setFakeHighlightAbs(abs);
6743
+ },
6744
+ [editor]
6745
+ );
6746
+ const updateFakeHighlightAbs = (0, react_exports.useCallback)((abs) => {
6747
+ fakeHighlightAbsRef.current = abs;
6748
+ setFakeHighlightAbs(abs);
6749
+ }, []);
6750
+ const decorate = (0, react_exports.useCallback)(
6751
+ ([node, path]) => {
6752
+ const abs = fakeHighlightAbsRef.current;
6753
+ if (!abs || !slate_exports.Text.isText(node)) return [];
6754
+ const { absStart, absEnd } = abs;
6755
+ let nodeAbsStart = 0;
6756
+ for (const [n, p] of slate_exports.Editor.nodes(editor, {
6757
+ at: [],
6758
+ match: (nd) => slate_exports.Text.isText(nd)
6759
+ })) {
6760
+ if (slate_exports.Path.equals(p, path)) break;
6761
+ nodeAbsStart += n.text.length;
6762
+ }
6763
+ const nodeAbsEnd = nodeAbsStart + node.text.length;
6764
+ const overlapStart = Math.max(absStart, nodeAbsStart);
6765
+ const overlapEnd = Math.min(absEnd, nodeAbsEnd);
6766
+ if (overlapStart >= overlapEnd) return [];
6767
+ return [
6768
+ {
6769
+ anchor: { path, offset: overlapStart - nodeAbsStart },
6770
+ focus: { path, offset: overlapEnd - nodeAbsStart },
6771
+ fakeHighlight: true
6772
+ }
6773
+ ];
6774
+ },
6775
+ // fakeHighlightAbs (state) triggers re-evaluation; fakeHighlightAbsRef provides the current value.
6776
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6777
+ [fakeHighlightAbs, editor]
6778
+ );
6779
+ return {
6780
+ fakeHighlightAbs,
6781
+ fakeHighlightAbsRef,
6782
+ updateFakeHighlight,
6783
+ updateFakeHighlightAbs,
6784
+ decorate
6785
+ };
6059
6786
  }
6060
6787
 
6061
6788
  // src/RichText/PureRichText/hooks/useContentSync.ts
@@ -6106,19 +6833,37 @@ function directRestoreSelection(editor, selection) {
6106
6833
  }
6107
6834
  }
6108
6835
  function consumeForceSync(ref) {
6109
- var _a;
6110
- const value = (_a = ref == null ? void 0 : ref.current) != null ? _a : false;
6836
+ var _a2;
6837
+ const value = (_a2 = ref == null ? void 0 : ref.current) != null ? _a2 : false;
6111
6838
  if (value && ref) {
6112
6839
  ref.current = false;
6113
6840
  }
6114
6841
  return value;
6115
6842
  }
6116
- function shouldSkipSync(forceSync, richTextContent, recentSavesRef, isTextEditingRef) {
6843
+ function shouldSkipSync(forceSync, richTextContent, recentSavesRef, isTextEditingRef, hasFocusRef) {
6117
6844
  if (forceSync) return false;
6118
6845
  if (recentSavesRef == null ? void 0 : recentSavesRef.current.has(richTextContent)) return true;
6119
- if (isTextEditingRef.current) return true;
6846
+ if (isTextEditingRef.current && hasFocusRef.current) return true;
6120
6847
  return false;
6121
6848
  }
6849
+ function shouldSkipUnchangedContent(explicitForceSync, contentMatchesLastEdit, initialValueChanged, syncInitialValueChanges) {
6850
+ return !explicitForceSync && contentMatchesLastEdit && (!initialValueChanged || !syncInitialValueChanges);
6851
+ }
6852
+ function recordSkippedExternalContent(isRecentSave, richTextContent, lastEmittedHtmlRef) {
6853
+ if (!isRecentSave) {
6854
+ lastEmittedHtmlRef.current = richTextContent;
6855
+ }
6856
+ }
6857
+ function getSavedSelection(history, incomingIdx, lastSelection) {
6858
+ var _a2;
6859
+ if (incomingIdx === -1) return lastSelection;
6860
+ return ((_a2 = history[incomingIdx + 1]) == null ? void 0 : _a2.preSelection) || history[incomingIdx].selection || lastSelection;
6861
+ }
6862
+ function getTreeToApply(forceSync, richTextContent, initialValue, transformTree) {
6863
+ if (!forceSync || !richTextContent) return initialValue;
6864
+ const parsed = htmlToSlate(richTextContent);
6865
+ return transformTree ? transformTree(parsed) : parsed;
6866
+ }
6122
6867
  function snapToTokenEdge(editor, point, isStart) {
6123
6868
  try {
6124
6869
  const [node] = slate_exports.Editor.node(editor, point);
@@ -6189,7 +6934,10 @@ function emitContentChange({
6189
6934
  historyPosRef.current = emittedHistoryRef.current.length - 1;
6190
6935
  onContentChange(html, hasBareToken || !typing);
6191
6936
  if (autoResolveTokensRef == null ? void 0 : autoResolveTokensRef.current) {
6192
- queueMicrotask(autoResolveTokensRef.current);
6937
+ queueMicrotask(() => {
6938
+ var _a2;
6939
+ return (_a2 = autoResolveTokensRef.current) == null ? void 0 : _a2.call(autoResolveTokensRef);
6940
+ });
6193
6941
  }
6194
6942
  }
6195
6943
  function cancelPendingStyleUpdate(styleUpdateRafRef) {
@@ -6225,6 +6973,7 @@ function useContentSync({
6225
6973
  recentSavesRef,
6226
6974
  forceNextSyncRef,
6227
6975
  transformTreeRef,
6976
+ syncInitialValueChanges = true,
6228
6977
  autoResolveTokensRef
6229
6978
  }) {
6230
6979
  const [value, setValue] = (0, react_exports.useState)(initialValue);
@@ -6236,18 +6985,27 @@ function useContentSync({
6236
6985
  const historyPosRef = (0, react_exports.useRef)(0);
6237
6986
  const lastInitialValueRef = (0, react_exports.useRef)(initialValue);
6238
6987
  (0, react_exports.useEffect)(() => {
6988
+ var _a2;
6239
6989
  const initialValueChanged = initialValue !== lastInitialValueRef.current;
6240
6990
  lastInitialValueRef.current = initialValue;
6241
6991
  const explicitForceSync = consumeForceSync(forceNextSyncRef);
6242
- if (!explicitForceSync && !initialValueChanged && richTextContent === lastEmittedHtmlRef.current)
6992
+ const contentMatchesLastEdit = richTextContent === lastEmittedHtmlRef.current;
6993
+ if (shouldSkipUnchangedContent(
6994
+ explicitForceSync,
6995
+ contentMatchesLastEdit,
6996
+ initialValueChanged,
6997
+ syncInitialValueChanges
6998
+ )) {
6243
6999
  return;
7000
+ }
6244
7001
  const history = emittedHistoryRef.current;
6245
7002
  const incomingIdx = findHistoryIndex(history, richTextContent);
7003
+ const isRecentSave = (_a2 = recentSavesRef == null ? void 0 : recentSavesRef.current.has(richTextContent)) != null ? _a2 : false;
6246
7004
  const isExternalContentChange = richTextContent !== lastEmittedHtmlRef.current;
6247
- const isHistoryRevert = isExternalContentChange && incomingIdx !== -1;
7005
+ const isHistoryRevert = isExternalContentChange && incomingIdx !== -1 && !isRecentSave;
6248
7006
  const forceSync = explicitForceSync || isHistoryRevert;
6249
- if (shouldSkipSync(forceSync, richTextContent, recentSavesRef, isTextEditingRef)) {
6250
- lastEmittedHtmlRef.current = richTextContent;
7007
+ if (shouldSkipSync(forceSync, richTextContent, recentSavesRef, isTextEditingRef, hasFocusRef)) {
7008
+ recordSkippedExternalContent(isRecentSave, richTextContent, lastEmittedHtmlRef);
6251
7009
  return;
6252
7010
  }
6253
7011
  const pendingMarks = isExternalContentChange ? null : editor.marks;
@@ -6255,15 +7013,13 @@ function useContentSync({
6255
7013
  if (incomingIdx !== -1) {
6256
7014
  historyPosRef.current = incomingIdx;
6257
7015
  }
6258
- const undoneEntry = incomingIdx !== -1 ? history[incomingIdx + 1] : null;
6259
- const savedSelection = (undoneEntry == null ? void 0 : undoneEntry.preSelection) || (incomingIdx !== -1 ? history[incomingIdx].selection : null) || lastSelectionRef.current;
6260
- let treeToApply;
6261
- if (forceSync && richTextContent) {
6262
- const parsed = htmlToSlate(richTextContent);
6263
- treeToApply = (transformTreeRef == null ? void 0 : transformTreeRef.current) ? transformTreeRef.current(parsed) : parsed;
6264
- } else {
6265
- treeToApply = initialValue;
6266
- }
7016
+ const savedSelection = getSavedSelection(history, incomingIdx, lastSelectionRef.current);
7017
+ const treeToApply = getTreeToApply(
7018
+ forceSync,
7019
+ richTextContent,
7020
+ initialValue,
7021
+ transformTreeRef == null ? void 0 : transformTreeRef.current
7022
+ );
6267
7023
  setValue(treeToApply);
6268
7024
  editor.children = treeToApply;
6269
7025
  editor.selection = null;
@@ -6279,7 +7035,23 @@ function useContentSync({
6279
7035
  if (pendingMarks) {
6280
7036
  editor.marks = pendingMarks;
6281
7037
  }
6282
- }, [initialValue, richTextContent, editor, lastSelectionRef]);
7038
+ if (!hasFocusRef.current) {
7039
+ editor.onChange();
7040
+ }
7041
+ }, [
7042
+ initialValue,
7043
+ richTextContent,
7044
+ editor,
7045
+ lastSelectionRef,
7046
+ hasFocusRef,
7047
+ syncInitialValueChanges,
7048
+ fakeHighlightAbsRef,
7049
+ forceNextSyncRef,
7050
+ isTextEditingRef,
7051
+ recentSavesRef,
7052
+ transformTreeRef,
7053
+ updateFakeHighlightAbs
7054
+ ]);
6283
7055
  (0, react_exports.useEffect)(() => {
6284
7056
  return () => cancelPendingStyleUpdate(styleUpdateRafRef);
6285
7057
  }, []);
@@ -6373,9 +7145,13 @@ function handleTabKey(editor, event) {
6373
7145
  const [parentListNode] = parentList;
6374
7146
  const parentListElement = parentListNode;
6375
7147
  const listType = parentListElement.type === "numbered-list" ? "numbered-list" : "bulleted-list";
6376
- slate_exports.Transforms.wrapNodes(editor, { type: listType, children: [] }, {
6377
- at: listItemPath
6378
- });
7148
+ slate_exports.Transforms.wrapNodes(
7149
+ editor,
7150
+ { type: listType, children: [] },
7151
+ {
7152
+ at: listItemPath
7153
+ }
7154
+ );
6379
7155
  }
6380
7156
  function cycleAlignment(editor, applyFormat) {
6381
7157
  const cycle = {
@@ -6517,7 +7293,7 @@ function restoreSelection(editor, fakeHighlightAbsRef, lastSelectionRef) {
6517
7293
  }
6518
7294
  function stepCollapsed(editor, delta, updateActiveStyles) {
6519
7295
  const marks = slate_exports.Editor.marks(editor);
6520
- const current = (marks == null ? void 0 : marks.fontSize) ? parseInt(String(marks.fontSize), 10) : 14;
7296
+ const current = (marks == null ? void 0 : marks.fontSize) ? Number.parseInt(String(marks.fontSize), 10) : 14;
6521
7297
  slate_exports.Editor.addMark(editor, "fontSize", `${clampFontSize(current + delta)}px`);
6522
7298
  updateActiveStyles();
6523
7299
  }
@@ -6530,7 +7306,7 @@ function collectTextEntries(editor) {
6530
7306
  match: (n) => slate_exports.Text.isText(n)
6531
7307
  })) {
6532
7308
  const fontSize = node.fontSize;
6533
- const cur = fontSize ? parseInt(fontSize, 10) : 14;
7309
+ const cur = fontSize ? Number.parseInt(fontSize, 10) : 14;
6534
7310
  const nodeStart = slate_exports.Editor.start(editor, path);
6535
7311
  const nodeEnd = slate_exports.Editor.end(editor, path);
6536
7312
  const start = slate_exports.Point.compare(nodeStart, selStart) >= 0 ? nodeStart : selStart;
@@ -6559,7 +7335,7 @@ function useStepFontSize({
6559
7335
  }) {
6560
7336
  const stepFontSize = (0, react_exports.useCallback)(
6561
7337
  (delta) => {
6562
- var _a;
7338
+ var _a2;
6563
7339
  restoreSelection(editor, fakeHighlightAbsRef, lastSelectionRef);
6564
7340
  if (!editor.selection) return;
6565
7341
  if (slate_exports.Range.isCollapsed(editor.selection)) {
@@ -6577,7 +7353,7 @@ function useStepFontSize({
6577
7353
  editor.selection = { anchor: newStart, focus: newEnd };
6578
7354
  updateActiveStyles();
6579
7355
  }
6580
- (_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
7356
+ (_a2 = globalThis.getSelection()) == null ? void 0 : _a2.removeAllRanges();
6581
7357
  },
6582
7358
  [editor, fakeHighlightAbsRef, lastSelectionRef, updateFakeHighlightAbs, updateActiveStyles]
6583
7359
  );
@@ -6610,7 +7386,7 @@ function useStepLineSpacing({
6610
7386
  }) {
6611
7387
  const stepLineSpacing = (0, react_exports.useCallback)(
6612
7388
  (delta) => {
6613
- var _a;
7389
+ var _a2;
6614
7390
  if (!editor.selection && fakeHighlightAbsRef.current) {
6615
7391
  const s = absOffsetToPoint(editor, fakeHighlightAbsRef.current.absStart, true);
6616
7392
  const e = absOffsetToPoint(editor, fakeHighlightAbsRef.current.absEnd);
@@ -6650,7 +7426,7 @@ function useStepLineSpacing({
6650
7426
  editor.selection = { anchor: newStart, focus: newEnd };
6651
7427
  updateActiveStyles();
6652
7428
  }
6653
- (_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
7429
+ (_a2 = globalThis.getSelection()) == null ? void 0 : _a2.removeAllRanges();
6654
7430
  },
6655
7431
  [editor, fakeHighlightAbsRef, lastSelectionRef, updateFakeHighlightAbs, updateActiveStyles]
6656
7432
  );
@@ -6662,8 +7438,8 @@ function useStepLineSpacing({
6662
7438
 
6663
7439
  // src/RichText/PureRichText/hooks/useFocusHandlers.ts
6664
7440
  function findConfigPanel() {
6665
- var _a;
6666
- return ((_a = document.querySelector('[data-test="editor-richTextContent"]')) == null ? void 0 : _a.closest('[class*="StyledInsetWrapper"]')) || document.querySelector('[data-test="editor-richTextContent"]') || document.querySelector('[data-test="editor-purerichtext"]') || document.querySelector('[data-test="sidebar-content"]') || null;
7441
+ var _a2;
7442
+ return ((_a2 = document.querySelector('[data-test="editor-richTextContent"]')) == null ? void 0 : _a2.closest('[class*="StyledInsetWrapper"]')) || document.querySelector('[data-test="editor-richTextContent"]') || document.querySelector('[data-test="editor-purerichtext"]') || document.querySelector('[data-test="sidebar-content"]') || null;
6667
7443
  }
6668
7444
  function isFocusInPanelUI(relatedTarget, configPanel) {
6669
7445
  if (!relatedTarget) return false;
@@ -6693,15 +7469,15 @@ function useFocusHandlers({
6693
7469
  onDeactivateTextEditing
6694
7470
  }) {
6695
7471
  const handleFocus = (0, react_exports.useCallback)(() => {
6696
- var _a, _b;
7472
+ var _a2, _b;
6697
7473
  if (wasTextEditingRef.current) {
6698
7474
  updateFakeHighlightAbs(null);
6699
7475
  wasTextEditingRef.current = false;
6700
7476
  }
6701
7477
  if (!isTextEditingRef.current) {
6702
- (_a = editableRef.current) == null ? void 0 : _a.blur();
7478
+ (_a2 = editableRef.current) == null ? void 0 : _a2.blur();
6703
7479
  safeDeselect(editor);
6704
- (_b = window.getSelection()) == null ? void 0 : _b.removeAllRanges();
7480
+ (_b = globalThis.getSelection()) == null ? void 0 : _b.removeAllRanges();
6705
7481
  return;
6706
7482
  }
6707
7483
  hasFocusRef.current = true;
@@ -6709,7 +7485,7 @@ function useFocusHandlers({
6709
7485
  }, [onFocusGained, editor, editableRef, hasFocusRef, wasTextEditingRef, updateFakeHighlightAbs]);
6710
7486
  const handleBlur = (0, react_exports.useCallback)(
6711
7487
  (e) => {
6712
- var _a, _b;
7488
+ var _a2, _b;
6713
7489
  saveSelection();
6714
7490
  hasFocusRef.current = false;
6715
7491
  const sel = editor.selection ? { anchor: __spreadValues({}, editor.selection.anchor), focus: __spreadValues({}, editor.selection.focus) } : lastSelectionRef.current;
@@ -6732,14 +7508,14 @@ function useFocusHandlers({
6732
7508
  if (canShowFakeHighlight) {
6733
7509
  updateFakeHighlight(sel);
6734
7510
  }
6735
- (_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
7511
+ (_a2 = globalThis.getSelection()) == null ? void 0 : _a2.removeAllRanges();
6736
7512
  }
6737
7513
  if (!focusStaysInPanel) {
6738
7514
  updateFakeHighlight(null);
6739
7515
  wasTextEditingRef.current = false;
6740
7516
  lastSelectionRef.current = null;
6741
7517
  safeDeselect(editor);
6742
- (_b = window.getSelection()) == null ? void 0 : _b.removeAllRanges();
7518
+ (_b = globalThis.getSelection()) == null ? void 0 : _b.removeAllRanges();
6743
7519
  onDeactivateTextEditing == null ? void 0 : onDeactivateTextEditing();
6744
7520
  }
6745
7521
  onFocusLost == null ? void 0 : onFocusLost();
@@ -6762,9 +7538,51 @@ function useFocusHandlers({
6762
7538
  }
6763
7539
 
6764
7540
  // src/RichText/PureRichText/hooks/useMouseHandlers.ts
7541
+ var MOVE_THRESHOLD = 4;
7542
+ function placeCaretAtPoint(editor, clientX, clientY, target, editableEl) {
7543
+ try {
7544
+ let domRange = null;
7545
+ const doc = document;
7546
+ if (typeof doc.caretRangeFromPoint === "function") {
7547
+ domRange = doc.caretRangeFromPoint(clientX, clientY);
7548
+ } else if (typeof doc.caretPositionFromPoint === "function") {
7549
+ const pos = doc.caretPositionFromPoint(clientX, clientY);
7550
+ if (pos) {
7551
+ const r = document.createRange();
7552
+ r.setStart(pos.offsetNode, pos.offset);
7553
+ r.collapse(true);
7554
+ domRange = r;
7555
+ }
7556
+ }
7557
+ if (domRange) {
7558
+ const sel = globalThis.getSelection();
7559
+ sel == null ? void 0 : sel.removeAllRanges();
7560
+ sel == null ? void 0 : sel.addRange(domRange);
7561
+ const point = slate_react_exports.ReactEditor.toSlatePoint(editor, [domRange.startContainer, domRange.startOffset], {
7562
+ exactMatch: false,
7563
+ suppressThrow: true
7564
+ });
7565
+ if (point) {
7566
+ slate_exports.Transforms.select(editor, point);
7567
+ return;
7568
+ }
7569
+ }
7570
+ if (target) {
7571
+ const node = slate_react_exports.ReactEditor.toSlateNode(editor, target);
7572
+ const path = slate_react_exports.ReactEditor.findPath(editor, node);
7573
+ slate_exports.Transforms.select(editor, slate_exports.Editor.start(editor, path));
7574
+ return;
7575
+ }
7576
+ } catch (e) {
7577
+ }
7578
+ if (!editorContentOverflows(editableEl != null ? editableEl : null)) {
7579
+ safeSelectEnd(editor);
7580
+ }
7581
+ }
6765
7582
  function useMouseHandlers({
6766
7583
  editor,
6767
7584
  editableRef,
7585
+ containerRef,
6768
7586
  isEditMode,
6769
7587
  isTextEditing,
6770
7588
  onActivateTextEditing,
@@ -6772,31 +7590,45 @@ function useMouseHandlers({
6772
7590
  }) {
6773
7591
  const handleMouseDown = (0, react_exports.useCallback)(
6774
7592
  (e) => {
6775
- var _a;
7593
+ var _a2, _b;
6776
7594
  if (isEditMode && !isTextEditing) {
6777
- onActivateTextEditing == null ? void 0 : onActivateTextEditing();
6778
- setMouseSelecting(true);
6779
- const onMouseUp = () => {
7595
+ const isVizSelected = ((_a2 = containerRef.current) == null ? void 0 : _a2.closest('[data-selected="true"]')) != null;
7596
+ if (isVizSelected) {
7597
+ e.stopPropagation();
7598
+ }
7599
+ setSuppressNextEditClick(false);
7600
+ const startX = e.clientX;
7601
+ const startY = e.clientY;
7602
+ const onMouseUp = (ev) => {
6780
7603
  document.removeEventListener("mouseup", onMouseUp, true);
7604
+ const moved = Math.abs(ev.clientX - startX) > MOVE_THRESHOLD || Math.abs(ev.clientY - startY) > MOVE_THRESHOLD;
7605
+ if (moved) {
7606
+ setSuppressNextEditClick(true);
7607
+ return;
7608
+ }
7609
+ onActivateTextEditing == null ? void 0 : onActivateTextEditing();
7610
+ setMouseSelecting(true);
6781
7611
  requestAnimationFrame(() => {
6782
7612
  setMouseSelecting(false);
6783
7613
  });
7614
+ const clickTarget = ev.target;
7615
+ setTimeout(() => {
7616
+ var _a3;
7617
+ (_a3 = editableRef.current) == null ? void 0 : _a3.focus({ preventScroll: true });
7618
+ placeCaretAtPoint(editor, startX, startY, clickTarget, editableRef.current);
7619
+ }, 0);
6784
7620
  };
6785
7621
  document.addEventListener("mouseup", onMouseUp, true);
6786
- setTimeout(() => {
6787
- var _a2;
6788
- (_a2 = editableRef.current) == null ? void 0 : _a2.focus({ preventScroll: true });
6789
- }, 0);
6790
7622
  return;
6791
7623
  }
6792
7624
  if (isTextEditing) {
6793
7625
  clearFakeHighlight();
6794
7626
  e.stopPropagation();
7627
+ setMouseSelecting(true);
6795
7628
  if (editor.selection && !slate_exports.Range.isCollapsed(editor.selection)) {
6796
7629
  slate_exports.Transforms.collapse(editor, { edge: "focus" });
6797
- (_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
7630
+ (_b = globalThis.getSelection()) == null ? void 0 : _b.removeAllRanges();
6798
7631
  }
6799
- setMouseSelecting(true);
6800
7632
  const onMouseUp = (ev) => {
6801
7633
  document.removeEventListener("mouseup", onMouseUp, true);
6802
7634
  ev.stopPropagation();
@@ -6807,7 +7639,15 @@ function useMouseHandlers({
6807
7639
  document.addEventListener("mouseup", onMouseUp, true);
6808
7640
  }
6809
7641
  },
6810
- [isEditMode, isTextEditing, onActivateTextEditing, editableRef, clearFakeHighlight]
7642
+ [
7643
+ editor,
7644
+ isEditMode,
7645
+ isTextEditing,
7646
+ onActivateTextEditing,
7647
+ editableRef,
7648
+ containerRef,
7649
+ clearFakeHighlight
7650
+ ]
6811
7651
  );
6812
7652
  const handleEmptySpaceClick = (0, react_exports.useCallback)(
6813
7653
  (e) => {
@@ -6816,14 +7656,14 @@ function useMouseHandlers({
6816
7656
  const target = e.target;
6817
7657
  if (target.closest("[data-slate-node]")) return;
6818
7658
  editableRef.current.focus({ preventScroll: true });
6819
- safeSelectEnd(editor);
7659
+ placeCaretAtPoint(editor, e.clientX, e.clientY, null, editableRef.current);
6820
7660
  },
6821
7661
  [isTextEditing, editor, editableRef]
6822
7662
  );
6823
7663
  const handleDragStart = (0, react_exports.useCallback)(
6824
7664
  (e) => {
7665
+ e.preventDefault();
6825
7666
  if (isEditMode) {
6826
- e.preventDefault();
6827
7667
  e.stopPropagation();
6828
7668
  }
6829
7669
  },
@@ -6836,12 +7676,12 @@ function useMouseHandlers({
6836
7676
  function useEditModeEffect(editor, editableRef, isEditMode) {
6837
7677
  const prevIsEditModeRef = (0, react_exports.useRef)(isEditMode);
6838
7678
  (0, react_exports.useEffect)(() => {
6839
- var _a;
7679
+ var _a2;
6840
7680
  const wasEditMode = prevIsEditModeRef.current;
6841
7681
  prevIsEditModeRef.current = isEditMode;
6842
7682
  if (wasEditMode && !isEditMode) {
6843
7683
  safeDeselect(editor);
6844
- (_a = editableRef.current) == null ? void 0 : _a.blur();
7684
+ (_a2 = editableRef.current) == null ? void 0 : _a2.blur();
6845
7685
  }
6846
7686
  }, [isEditMode, editor, editableRef]);
6847
7687
  }
@@ -6864,9 +7704,13 @@ var InnerEditor = ({
6864
7704
  recentSavesRef,
6865
7705
  forceNextSyncRef: forceNextSyncRefProp,
6866
7706
  transformTreeRef,
7707
+ syncInitialValueChanges,
6867
7708
  autoResolveTokensRef,
7709
+ onPasteStart,
6868
7710
  onAnnouncement,
6869
- onCancelPendingChanges
7711
+ onCancelPendingChanges,
7712
+ nameToValue,
7713
+ onLinkOpen
6870
7714
  }) => {
6871
7715
  const {
6872
7716
  setEditor,
@@ -6942,6 +7786,7 @@ var InnerEditor = ({
6942
7786
  recentSavesRef,
6943
7787
  forceNextSyncRef,
6944
7788
  transformTreeRef,
7789
+ syncInitialValueChanges,
6945
7790
  autoResolveTokensRef
6946
7791
  });
6947
7792
  const stepFontSize = useStepFontSize({
@@ -7006,7 +7851,7 @@ var InnerEditor = ({
7006
7851
  );
7007
7852
  const handleKeyDown = (0, react_exports.useCallback)(
7008
7853
  (event) => {
7009
- var _a, _b, _c;
7854
+ var _a2, _b;
7010
7855
  if (!isTextEditingRef.current) {
7011
7856
  return void 0;
7012
7857
  }
@@ -7017,18 +7862,10 @@ var InnerEditor = ({
7017
7862
  slate_exports.Transforms.deselect(editor);
7018
7863
  } catch (e) {
7019
7864
  }
7020
- (_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
7865
+ (_a2 = globalThis.getSelection()) == null ? void 0 : _a2.removeAllRanges();
7021
7866
  onDeactivateTextEditing == null ? void 0 : onDeactivateTextEditing();
7022
7867
  (_b = editableRef.current) == null ? void 0 : _b.blur();
7023
- const selectOutline = (_c = editableRef.current) == null ? void 0 : _c.closest(
7024
- '[data-test="select-outline"]'
7025
- );
7026
- if (selectOutline) {
7027
- if (!selectOutline.getAttribute("tabindex")) {
7028
- selectOutline.setAttribute("tabindex", "-1");
7029
- }
7030
- selectOutline.focus({ preventScroll: true });
7031
- }
7868
+ focusSelectOutline(editableRef.current);
7032
7869
  return void 0;
7033
7870
  }
7034
7871
  if (event.key === "Tab" && event.shiftKey) {
@@ -7060,20 +7897,32 @@ var InnerEditor = ({
7060
7897
  ]
7061
7898
  );
7062
7899
  const ElementRenderer = (0, react_exports.useMemo)(
7063
- () => createElementRenderer(isEditMode, defaultTextStyle.lineHeight || "1.5"),
7064
- [isEditMode, defaultTextStyle.lineHeight]
7900
+ () => createElementRenderer(isEditMode, defaultTextStyle.lineHeight || "1.5", nameToValue, onLinkOpen),
7901
+ [isEditMode, defaultTextStyle.lineHeight, nameToValue, onLinkOpen]
7065
7902
  );
7066
7903
  const renderElement = (0, react_exports.useCallback)(
7067
7904
  (props) => /* @__PURE__ */ react_exports.createElement(ElementRenderer, __spreadValues({}, props)),
7068
7905
  [ElementRenderer]
7069
7906
  );
7070
7907
  const renderLeaf = (0, react_exports.useCallback)((props) => /* @__PURE__ */ react_exports.createElement(Leaf, __spreadValues({}, props)), []);
7908
+ const handleDOMBeforeInput = (0, react_exports.useCallback)(
7909
+ (event) => handleTextInsert(editor, event) || void 0,
7910
+ [editor]
7911
+ );
7071
7912
  const editableStyle = {
7072
7913
  color: defaultTextStyle.color || "#ffffff",
7073
7914
  fontSize: defaultTextStyle.fontSize || "14px",
7074
7915
  fontFamily: FONT_FAMILY_WITH_FALLBACKS[defaultTextStyle.fontFamily] || defaultTextStyle.fontFamily || FONT_FAMILY_WITH_FALLBACKS["Splunk Data Sans"],
7075
- lineHeight: defaultTextStyle.lineHeight || "1.5"
7916
+ lineHeight: defaultTextStyle.lineHeight || "1.5",
7917
+ // Text I-beam only while editing; otherwise inherit from wrapper so read-only
7918
+ // viewers don't get a text cursor (pointer when an interaction is bound).
7919
+ cursor: isTextEditing ? "text" : "inherit"
7076
7920
  };
7921
+ const editorContainerStyle = __spreadValues({
7922
+ // Keep the Slate editor's percentage min-height resolvable while actively editing so
7923
+ // vertical alignment has the same full-height layout used in read-only mode.
7924
+ minHeight: "100%"
7925
+ }, isTextEditing ? {} : { caretColor: "transparent", outline: "none" });
7077
7926
  return /* @__PURE__ */ react_exports.createElement(
7078
7927
  "div",
7079
7928
  {
@@ -7081,7 +7930,8 @@ var InnerEditor = ({
7081
7930
  suppressContentEditableWarning: true,
7082
7931
  onMouseDown: handleMouseDown,
7083
7932
  onClick: handleEmptySpaceClick,
7084
- style: isTextEditing ? void 0 : { minHeight: "100%", caretColor: "transparent", outline: "none" }
7933
+ onDragStart: handleDragStart,
7934
+ style: editorContainerStyle
7085
7935
  },
7086
7936
  /* @__PURE__ */ react_exports.createElement(slate_react_exports.Slate, { editor, initialValue: value, onChange: handleChange }, /* @__PURE__ */ react_exports.createElement(
7087
7937
  slate_react_exports.Editable,
@@ -7092,9 +7942,12 @@ var InnerEditor = ({
7092
7942
  decorate,
7093
7943
  renderElement,
7094
7944
  renderLeaf,
7945
+ onDOMBeforeInput: handleDOMBeforeInput,
7946
+ scrollSelectionIntoView: scrollCaretWithinEditor,
7095
7947
  style: editableStyle,
7096
7948
  ref: editableRef,
7097
7949
  onKeyDown: handleKeyDown,
7950
+ onPaste: onPasteStart,
7098
7951
  onDragStart: handleDragStart,
7099
7952
  onFocus: handleFocus,
7100
7953
  onBlur: handleBlur,
@@ -7243,20 +8096,21 @@ function useSkipLinkAndFocusOut({
7243
8096
  isEditMode,
7244
8097
  containerRef,
7245
8098
  slateEditorRef,
8099
+ isTextEditingRef,
7246
8100
  wasTextEditingRef,
7247
8101
  clearFakeHighlightRef,
7248
8102
  deactivateTextEditing,
7249
8103
  dashboardCoreApi
7250
8104
  }) {
7251
8105
  (0, react_exports.useEffect)(() => {
7252
- var _a;
8106
+ var _a2;
7253
8107
  if (!isEditMode) return void 0;
7254
- const vizItem = (_a = containerRef.current) == null ? void 0 : _a.closest('[data-test="viz-item"]');
8108
+ const vizItem = (_a2 = containerRef.current) == null ? void 0 : _a2.closest('[data-test="viz-item"]');
7255
8109
  if (!vizItem) return void 0;
7256
8110
  const handleEscapeOnSkipLink = (configLink) => {
7257
- var _a2;
8111
+ var _a3;
7258
8112
  if (configLink) configLink.setAttribute("tabindex", "-1");
7259
- (_a2 = clearFakeHighlightRef.current) == null ? void 0 : _a2.call(clearFakeHighlightRef);
8113
+ (_a3 = clearFakeHighlightRef.current) == null ? void 0 : _a3.call(clearFakeHighlightRef);
7260
8114
  const ed = slateEditorRef.current;
7261
8115
  if (ed) {
7262
8116
  safeDeselect(ed);
@@ -7290,14 +8144,26 @@ function useSkipLinkAndFocusOut({
7290
8144
  if (actionMenuLink) actionMenuLink.setAttribute("tabindex", "-1");
7291
8145
  };
7292
8146
  const handleKeyDown = (e) => {
7293
- if (!vizItem.contains(e.target)) return;
8147
+ var _a3, _b;
7294
8148
  const target = e.target;
8149
+ if (!vizItem.contains(target)) return;
7295
8150
  const configLink = vizItem.querySelector('[data-test="skip-link-config"]');
7296
8151
  if (e.key === "Escape" && target.closest('[data-test="skip-link-config"]')) {
7297
8152
  e.preventDefault();
7298
8153
  handleEscapeOnSkipLink(configLink);
7299
8154
  return;
7300
8155
  }
8156
+ if (e.key === "Escape" && !isTextEditingRef.current) {
8157
+ const isSelected = ((_a3 = containerRef.current) == null ? void 0 : _a3.closest('[data-selected="true"]')) != null;
8158
+ if (isSelected) {
8159
+ e.preventDefault();
8160
+ (_b = document.activeElement) == null ? void 0 : _b.blur();
8161
+ if (dashboardCoreApi) {
8162
+ dashboardCoreApi.updateSelectedItems([]);
8163
+ }
8164
+ return;
8165
+ }
8166
+ }
7301
8167
  if (e.key !== "Tab") return;
7302
8168
  if (e.shiftKey) {
7303
8169
  handleShiftTab(e, target, configLink);
@@ -7344,20 +8210,17 @@ function useSidebarAndEditActivation({
7344
8210
  (0, react_exports.useEffect)(() => {
7345
8211
  if (!isEditMode) return void 0;
7346
8212
  const getOurVizItem = () => {
7347
- var _a, _b;
7348
- return (_b = (_a = containerRef.current) == null ? void 0 : _a.closest('[data-test="viz-item"]')) != null ? _b : null;
8213
+ var _a2, _b;
8214
+ return (_b = (_a2 = containerRef.current) == null ? void 0 : _a2.closest('[data-test="viz-item"]')) != null ? _b : null;
7349
8215
  };
7350
- const isTargetInSidebar = (target, vizItem) => !(vizItem == null ? void 0 : vizItem.contains(target)) && // The link popover (Cmd+K) owns its own single-press Escape handling
7351
- // (useLinkHandlers' handleLinkKeyDown); it must not be treated as
7352
- // "sidebar" here, or this capture-phase handler intercepts Escape
7353
- // first and only returns focus to the editor, requiring a second
7354
- // Escape to actually close the popover.
8216
+ const isTargetInSidebar = (target, vizItem) => !(vizItem == null ? void 0 : vizItem.contains(target)) && // The link popover (Cmd+K) owns its own Escape (useLinkHandlers); excluded here so
8217
+ // this capture handler doesn't intercept it, forcing a second Escape to close.
7355
8218
  !target.closest('[data-test="link-popover-content"]') && Boolean(
7356
8219
  target.closest('[data-test="sidebar-content"]') || target.closest('[data-test="header"]') || target.id === "configuration-back-button" || target.closest("#configuration-back-button") || target.closest('[data-test="popover"]') || target.closest("[data-test-popover-id]")
7357
8220
  );
7358
8221
  const handleEscapeFromSidebar = (e) => {
7359
- var _a, _b;
7360
- const isSelected = ((_a = containerRef.current) == null ? void 0 : _a.closest('[data-selected="true"]')) != null;
8222
+ var _a2, _b;
8223
+ const isSelected = ((_a2 = containerRef.current) == null ? void 0 : _a2.closest('[data-selected="true"]')) != null;
7361
8224
  if (!isSelected) return;
7362
8225
  e.preventDefault();
7363
8226
  e.stopImmediatePropagation();
@@ -7365,15 +8228,15 @@ function useSidebarAndEditActivation({
7365
8228
  const selToRestore = ((_b = slateEditorRef.current) == null ? void 0 : _b.selection) || richTextState.getPreEditSelection();
7366
8229
  richTextState.returnFromConfigPanel();
7367
8230
  requestAnimationFrame(() => {
7368
- var _a2, _b2;
7369
- const editable = (_a2 = containerRef.current) == null ? void 0 : _a2.querySelector("[data-slate-editor]");
8231
+ var _a3, _b2;
8232
+ const editable = (_a3 = containerRef.current) == null ? void 0 : _a3.querySelector("[data-slate-editor]");
7370
8233
  editable == null ? void 0 : editable.focus();
7371
8234
  const ed = slateEditorRef.current;
7372
8235
  if (ed && selToRestore) {
7373
8236
  try {
7374
8237
  slate_exports.Transforms.select(ed, selToRestore);
7375
8238
  const domRange = slate_react_exports.ReactEditor.toDOMRange(ed, selToRestore);
7376
- const domSel = window.getSelection();
8239
+ const domSel = globalThis.getSelection();
7377
8240
  domSel == null ? void 0 : domSel.removeAllRanges();
7378
8241
  domSel == null ? void 0 : domSel.addRange(domRange);
7379
8242
  } catch (e2) {
@@ -7387,7 +8250,7 @@ function useSidebarAndEditActivation({
7387
8250
  });
7388
8251
  };
7389
8252
  const handleSkipLinkActivate = (e) => {
7390
- var _a;
8253
+ var _a2;
7391
8254
  e.preventDefault();
7392
8255
  e.stopImmediatePropagation();
7393
8256
  registerActiveRichText(instanceId, null, slateEditorRef.current);
@@ -7402,7 +8265,7 @@ function useSidebarAndEditActivation({
7402
8265
  } catch (e2) {
7403
8266
  }
7404
8267
  }
7405
- (_a = updateActiveStylesFnRef.current) == null ? void 0 : _a.call(updateActiveStylesFnRef);
8268
+ (_a2 = updateActiveStylesFnRef.current) == null ? void 0 : _a2.call(updateActiveStylesFnRef);
7406
8269
  }
7407
8270
  richTextState.clearWasTextEditing();
7408
8271
  const configBtn = document.getElementById("configuration-back-button");
@@ -7411,7 +8274,7 @@ function useSidebarAndEditActivation({
7411
8274
  }
7412
8275
  };
7413
8276
  const handleKeyDown = (e) => {
7414
- var _a;
8277
+ var _a2;
7415
8278
  const target = e.target;
7416
8279
  const ourVizItem = getOurVizItem();
7417
8280
  if (e.key === "Escape" && isTargetInSidebar(target, ourVizItem)) {
@@ -7424,7 +8287,7 @@ function useSidebarAndEditActivation({
7424
8287
  return;
7425
8288
  }
7426
8289
  if (e.key === "Enter" && !isTextEditingRef.current) {
7427
- const isVizSelected = ((_a = containerRef.current) == null ? void 0 : _a.closest('[data-selected="true"]')) != null;
8290
+ const isVizSelected = ((_a2 = containerRef.current) == null ? void 0 : _a2.closest('[data-selected="true"]')) != null;
7428
8291
  if (!isVizSelected) return;
7429
8292
  e.preventDefault();
7430
8293
  e.stopImmediatePropagation();
@@ -7432,8 +8295,8 @@ function useSidebarAndEditActivation({
7432
8295
  }
7433
8296
  };
7434
8297
  const handleClick2 = (e) => {
7435
- var _a;
7436
- const link = (_a = e.target) == null ? void 0 : _a.closest('[data-test="skip-link-config"]');
8298
+ var _a2;
8299
+ const link = (_a2 = e.target) == null ? void 0 : _a2.closest('[data-test="skip-link-config"]');
7437
8300
  if (!link) return;
7438
8301
  const ourVizItem = getOurVizItem();
7439
8302
  if (!(ourVizItem == null ? void 0 : ourVizItem.contains(link))) return;
@@ -7457,6 +8320,7 @@ function useDashboardKeyboardNav(args) {
7457
8320
  isEditMode: args.isEditMode,
7458
8321
  containerRef: args.containerRef,
7459
8322
  slateEditorRef: args.slateEditorRef,
8323
+ isTextEditingRef: args.isTextEditingRef,
7460
8324
  wasTextEditingRef: args.wasTextEditingRef,
7461
8325
  clearFakeHighlightRef: args.clearFakeHighlightRef,
7462
8326
  deactivateTextEditing: args.richTextState.deactivateTextEditing,
@@ -7473,6 +8337,7 @@ function useIsActiveRichText(id) {
7473
8337
  );
7474
8338
  }
7475
8339
  var identityRestore = (html) => html;
8340
+ var CONTAINER_MOVE_THRESHOLD = 4;
7476
8341
  function resolveTokenDisplay(args) {
7477
8342
  const { isEditMode, previewTokenValues, resolvedContent, rawContent } = args;
7478
8343
  const showResolvedTokens = !isEditMode || previewTokenValues;
@@ -7502,6 +8367,70 @@ function handleTokenToggle(args) {
7502
8367
  editorSourceOverride: currentRawHtml
7503
8368
  };
7504
8369
  }
8370
+ var TOKEN_PASTE_SETTLE_MS = 300;
8371
+ function useTokenResolutionScheduler(resolverRef, enabled) {
8372
+ const pasteBurstRef = (0, react_exports.useRef)(false);
8373
+ const timerRef = (0, react_exports.useRef)(null);
8374
+ const hasPendingRequestRef = (0, react_exports.useRef)(false);
8375
+ const includeValueChangesRef = (0, react_exports.useRef)(false);
8376
+ const enabledRef = (0, react_exports.useRef)(enabled);
8377
+ enabledRef.current = enabled;
8378
+ const clearTimer = (0, react_exports.useCallback)(() => {
8379
+ if (timerRef.current !== null) {
8380
+ clearTimeout(timerRef.current);
8381
+ timerRef.current = null;
8382
+ }
8383
+ }, []);
8384
+ const cancelPendingResolution = (0, react_exports.useCallback)(() => {
8385
+ clearTimer();
8386
+ pasteBurstRef.current = false;
8387
+ hasPendingRequestRef.current = false;
8388
+ includeValueChangesRef.current = false;
8389
+ }, [clearTimer]);
8390
+ const flushPendingResolution = (0, react_exports.useCallback)(() => {
8391
+ var _a2;
8392
+ const shouldResolve = enabledRef.current && hasPendingRequestRef.current;
8393
+ const includeValueChanges = includeValueChangesRef.current;
8394
+ clearTimer();
8395
+ pasteBurstRef.current = false;
8396
+ hasPendingRequestRef.current = false;
8397
+ includeValueChangesRef.current = false;
8398
+ if (shouldResolve) {
8399
+ (_a2 = resolverRef.current) == null ? void 0 : _a2.call(resolverRef, includeValueChanges);
8400
+ }
8401
+ }, [clearTimer, resolverRef]);
8402
+ const restartPasteTimer = (0, react_exports.useCallback)(() => {
8403
+ clearTimer();
8404
+ timerRef.current = setTimeout(flushPendingResolution, TOKEN_PASTE_SETTLE_MS);
8405
+ }, [clearTimer, flushPendingResolution]);
8406
+ const beginPasteBurst = (0, react_exports.useCallback)(() => {
8407
+ if (!enabledRef.current) return;
8408
+ pasteBurstRef.current = true;
8409
+ restartPasteTimer();
8410
+ }, [restartPasteTimer]);
8411
+ const requestResolutionRef = (0, react_exports.useRef)(null);
8412
+ requestResolutionRef.current = enabled ? (includeValueChanges = false) => {
8413
+ var _a2;
8414
+ if (!pasteBurstRef.current) {
8415
+ (_a2 = resolverRef.current) == null ? void 0 : _a2.call(resolverRef, includeValueChanges);
8416
+ return;
8417
+ }
8418
+ hasPendingRequestRef.current = true;
8419
+ includeValueChangesRef.current || (includeValueChangesRef.current = includeValueChanges);
8420
+ restartPasteTimer();
8421
+ } : null;
8422
+ (0, react_exports.useEffect)(() => {
8423
+ if (!enabled) {
8424
+ cancelPendingResolution();
8425
+ }
8426
+ }, [cancelPendingResolution, enabled]);
8427
+ (0, react_exports.useEffect)(() => cancelPendingResolution, [cancelPendingResolution]);
8428
+ return {
8429
+ beginPasteBurst,
8430
+ flushPendingResolution,
8431
+ requestResolutionRef
8432
+ };
8433
+ }
7505
8434
  function resolvePoint(editor, absOffset, isStart = false) {
7506
8435
  const point = absOffsetToPoint(editor, absOffset, isStart);
7507
8436
  if (point) return point;
@@ -7548,14 +8477,14 @@ function displayForToken(tokenName, nameToValue) {
7548
8477
  return value !== void 0 && value !== "" ? value : `$${tokenName}$`;
7549
8478
  }
7550
8479
  function bareTokensInPlainText(text, baseOffset, nameToValue) {
7551
- var _a;
8480
+ var _a2;
7552
8481
  const result = [];
7553
8482
  const re = new RegExp(TOKEN_OR_ESCAPE_PATTERN.source, "g");
7554
8483
  let m = re.exec(text);
7555
8484
  while (m !== null) {
7556
8485
  const rawPattern = m[0];
7557
8486
  const tokenName = m[1];
7558
- const resolvedValue = tokenName === void 0 ? "$" : (_a = nameToValue.get(tokenName)) != null ? _a : rawPattern;
8487
+ const resolvedValue = tokenName === void 0 ? "$" : (_a2 = nameToValue.get(tokenName)) != null ? _a2 : rawPattern;
7559
8488
  result.push({
7560
8489
  absStart: baseOffset + m.index,
7561
8490
  rawLen: rawPattern.length,
@@ -7565,33 +8494,34 @@ function bareTokensInPlainText(text, baseOffset, nameToValue) {
7565
8494
  }
7566
8495
  return result;
7567
8496
  }
7568
- function bareTokensInNode(node, runningOffset, nameToValue) {
8497
+ function bareTokensInNode(node, runningOffset, nameToValue, includeValueChanges) {
7569
8498
  const { text } = node;
7570
8499
  if (node.tokenName) {
7571
- if (!node.isRawToken) return [];
7572
8500
  const target = displayForToken(node.tokenName, nameToValue);
8501
+ if (!node.isRawToken && !(includeValueChanges && text !== target)) return [];
7573
8502
  return [{ absStart: runningOffset, rawLen: text.length, resolvedLen: target.length }];
7574
8503
  }
7575
8504
  if (node.isEscapedDollar) {
7576
- return text === "$$" ? [{ absStart: runningOffset, rawLen: text.length, resolvedLen: 1 }] : [];
8505
+ if (!node.isRawToken || !/^\$+$/.test(text)) return [];
8506
+ return [{ absStart: runningOffset, rawLen: text.length, resolvedLen: text.length / 2 }];
7577
8507
  }
7578
8508
  return bareTokensInPlainText(text, runningOffset, nameToValue);
7579
8509
  }
7580
- function collectBareTokens(editor, nameToValue) {
8510
+ function collectBareTokens(editor, nameToValue, includeValueChanges) {
7581
8511
  const result = [];
7582
8512
  let runningOffset = 0;
7583
8513
  for (const [textNode] of slate_exports.Editor.nodes(editor, { at: [], match: (n) => slate_exports.Text.isText(n) })) {
7584
- result.push(...bareTokensInNode(textNode, runningOffset, nameToValue));
8514
+ result.push(...bareTokensInNode(textNode, runningOffset, nameToValue, includeValueChanges));
7585
8515
  runningOffset += textNode.text.length;
7586
8516
  }
7587
8517
  return result;
7588
8518
  }
7589
8519
  function buildAutoResolveCallback(args) {
7590
8520
  const { slateEditorRef, nameToValue } = args;
7591
- return () => {
8521
+ return (includeValueChanges = false) => {
7592
8522
  const editor = slateEditorRef.current;
7593
8523
  if (!editor) return;
7594
- const bareTokenInfo = collectBareTokens(editor, nameToValue);
8524
+ const bareTokenInfo = collectBareTokens(editor, nameToValue, includeValueChanges);
7595
8525
  if (bareTokenInfo.length === 0) return;
7596
8526
  const rawAnchorAbs = editor.selection ? pointToAbsOffset(editor, editor.selection.anchor) : null;
7597
8527
  const rawFocusAbs = editor.selection ? pointToAbsOffset(editor, editor.selection.focus) : null;
@@ -7619,7 +8549,7 @@ function buildAutoResolveCallback(args) {
7619
8549
  };
7620
8550
  }
7621
8551
  var PureRichText = react_exports.forwardRef((props, ref) => {
7622
- var _a, _b, _c, _d;
8552
+ var _a2, _b, _c, _d;
7623
8553
  const theme = (0, themes_exports.useSplunkTheme)();
7624
8554
  const themeTextColor = theme.contentColorDefault;
7625
8555
  const {
@@ -7637,6 +8567,7 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7637
8567
  mode = "view",
7638
8568
  onOptionsChange,
7639
8569
  onRichtextClick = lodash_exports.noop,
8570
+ onLinkOpen,
7640
8571
  hasEventHandlers = false,
7641
8572
  bold = false,
7642
8573
  italic = false,
@@ -7649,7 +8580,7 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7649
8580
  const effectiveFontColorFromStyles = (defaultTextStyles == null ? void 0 : defaultTextStyles.color) || fontColor;
7650
8581
  const effectiveHighlightColor = (defaultTextStyles == null ? void 0 : defaultTextStyles.backgroundColor) || highlightColor;
7651
8582
  const effectiveFontFamily = (defaultTextStyles == null ? void 0 : defaultTextStyles.fontFamily) || fontFamily;
7652
- const effectiveBold = (_a = defaultTextStyles == null ? void 0 : defaultTextStyles.bold) != null ? _a : bold;
8583
+ const effectiveBold = (_a2 = defaultTextStyles == null ? void 0 : defaultTextStyles.bold) != null ? _a2 : bold;
7653
8584
  const effectiveItalic = (_b = defaultTextStyles == null ? void 0 : defaultTextStyles.italic) != null ? _b : italic;
7654
8585
  const effectiveUnderline = (_c = defaultTextStyles == null ? void 0 : defaultTextStyles.underline) != null ? _c : underline;
7655
8586
  const effectiveStrikethrough = (_d = defaultTextStyles == null ? void 0 : defaultTextStyles.strikethrough) != null ? _d : strikethrough;
@@ -7658,10 +8589,16 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7658
8589
  fontSize,
7659
8590
  customFontSize
7660
8591
  );
8592
+ const handleLinkOpen = (0, react_exports.useMemo)(
8593
+ () => onLinkOpen ? (url) => onLinkOpen({ payload: { url } }) : void 0,
8594
+ [onLinkOpen]
8595
+ );
7661
8596
  const effectiveFontColor = effectiveFontColorFromStyles || themeTextColor;
7662
8597
  const isEditMode = mode === "edit";
7663
8598
  const containerRef = (0, react_exports.useRef)(null);
8599
+ const containerMouseDownRef = (0, react_exports.useRef)(null);
7664
8600
  const slateEditorRef = (0, react_exports.useRef)(null);
8601
+ const editorHasFocusRef = (0, react_exports.useRef)(false);
7665
8602
  const updateActiveStylesFnRef = (0, react_exports.useRef)(null);
7666
8603
  const clearFakeHighlightRef = (0, react_exports.useRef)(null);
7667
8604
  const forceNextSyncRef = (0, react_exports.useRef)(false);
@@ -7697,16 +8634,16 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7697
8634
  }
7698
8635
  }, [isEditMode, instanceId]);
7699
8636
  (0, react_exports.useEffect)(() => {
7700
- var _a2;
8637
+ var _a3;
7701
8638
  if (!isEditMode || isTextEditing) return void 0;
7702
8639
  const checkAndRegister = () => {
7703
- var _a3;
7704
- const isSelected = ((_a3 = containerRef.current) == null ? void 0 : _a3.closest('[data-selected="true"]')) != null;
8640
+ var _a4;
8641
+ const isSelected = ((_a4 = containerRef.current) == null ? void 0 : _a4.closest('[data-selected="true"]')) != null;
7705
8642
  if (isSelected) {
7706
8643
  registerActiveRichText(instanceId, null, slateEditorRef.current);
7707
8644
  }
7708
8645
  };
7709
- const selectedAncestor = (_a2 = containerRef.current) == null ? void 0 : _a2.closest("[data-selected]");
8646
+ const selectedAncestor = (_a3 = containerRef.current) == null ? void 0 : _a3.closest("[data-selected]");
7710
8647
  let observer = null;
7711
8648
  if (selectedAncestor) {
7712
8649
  observer = new MutationObserver(checkAndRegister);
@@ -7721,12 +8658,12 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7721
8658
  };
7722
8659
  }, [instanceId, isEditMode, isTextEditing]);
7723
8660
  (0, react_exports.useEffect)(() => {
7724
- var _a2;
8661
+ var _a3;
7725
8662
  if (!isEditMode || !isTextEditing) return void 0;
7726
- const selectedAncestor = (_a2 = containerRef.current) == null ? void 0 : _a2.closest("[data-selected]");
8663
+ const selectedAncestor = (_a3 = containerRef.current) == null ? void 0 : _a3.closest("[data-selected]");
7727
8664
  if (!selectedAncestor) return void 0;
7728
8665
  const observer = new MutationObserver(() => {
7729
- const isSelected = selectedAncestor.getAttribute("data-selected") === "true";
8666
+ const isSelected = selectedAncestor.dataset.selected === "true";
7730
8667
  if (!isSelected) {
7731
8668
  richTextState.deactivateTextEditing();
7732
8669
  }
@@ -7787,24 +8724,34 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7787
8724
  onOptionsChange == null ? void 0 : onOptionsChange({ richTextContent: html });
7788
8725
  }
7789
8726
  }, [showResolvedTokens]);
7790
- transformTreeRef.current = (tree) => wrapRawTokensInTree(tree, showResolvedTokens ? nameToValue : void 0);
7791
- const autoResolveTokensRef = (0, react_exports.useRef)(null);
7792
- autoResolveTokensRef.current = showResolvedTokens ? buildAutoResolveCallback({ slateEditorRef, nameToValue }) : null;
8727
+ transformTreeRef.current = (tree) => showResolvedTokens ? wrapRawTokensInTree(tree, nameToValue) : tree;
8728
+ const tokenResolverRef = (0, react_exports.useRef)(null);
8729
+ tokenResolverRef.current = showResolvedTokens ? buildAutoResolveCallback({ slateEditorRef, nameToValue }) : null;
8730
+ const {
8731
+ beginPasteBurst,
8732
+ flushPendingResolution,
8733
+ requestResolutionRef: autoResolveTokensRef
8734
+ } = useTokenResolutionScheduler(tokenResolverRef, showResolvedTokens);
7793
8735
  const prevNameToValueRef = (0, react_exports.useRef)(nameToValue);
8736
+ const prevEditorSourceContentRef = (0, react_exports.useRef)(editorSourceContent);
7794
8737
  (0, react_exports.useEffect)(() => {
7795
8738
  const prev = prevNameToValueRef.current;
8739
+ const tokenMapChanged = nameToValue !== prev;
8740
+ const sourceContentChanged = editorSourceContent !== prevEditorSourceContentRef.current;
7796
8741
  prevNameToValueRef.current = nameToValue;
7797
- if (nameToValue.size > 0 && nameToValue !== prev && autoResolveTokensRef.current) {
7798
- autoResolveTokensRef.current();
8742
+ prevEditorSourceContentRef.current = editorSourceContent;
8743
+ if ((tokenMapChanged || sourceContentChanged) && autoResolveTokensRef.current) {
8744
+ autoResolveTokensRef.current(tokenMapChanged);
7799
8745
  }
7800
- }, [nameToValue]);
8746
+ }, [autoResolveTokensRef, editorSourceContent, nameToValue]);
7801
8747
  const effectiveEditorSourceContent = editorSourceOverride != null ? editorSourceOverride : editorSourceContent;
8748
+ const initialValueTokenMap = showResolvedTokens ? nameToValue : null;
7802
8749
  const initialValueRef = (0, react_exports.useRef)(EMPTY_SLATE_VALUE);
7803
8750
  const initialValueModeRef = (0, react_exports.useRef)(showResolvedTokens);
7804
8751
  const initialValue = (0, react_exports.useMemo)(() => {
7805
8752
  const modeChanged = initialValueModeRef.current !== showResolvedTokens;
7806
8753
  initialValueModeRef.current = showResolvedTokens;
7807
- if (!modeChanged && (recentSavesRef.current.has(effectiveEditorSourceContent) || isTextEditingRef.current)) {
8754
+ if (!modeChanged && (recentSavesRef.current.has(effectiveEditorSourceContent) || isTextEditingRef.current && editorHasFocusRef.current)) {
7808
8755
  return initialValueRef.current;
7809
8756
  }
7810
8757
  if (!effectiveEditorSourceContent) {
@@ -7812,19 +8759,22 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7812
8759
  return EMPTY_SLATE_VALUE;
7813
8760
  }
7814
8761
  const tree = htmlToSlate(effectiveEditorSourceContent);
7815
- const result = wrapRawTokensInTree(tree, showResolvedTokens ? nameToValue : void 0);
8762
+ const result = initialValueTokenMap ? wrapRawTokensInTree(tree, initialValueTokenMap) : tree;
7816
8763
  initialValueRef.current = result;
7817
8764
  return result;
7818
- }, [effectiveEditorSourceContent, nameToValue, showResolvedTokens]);
8765
+ }, [effectiveEditorSourceContent, initialValueTokenMap, showResolvedTokens]);
7819
8766
  const handleFocusGained = (0, react_exports.useCallback)(
7820
8767
  (editable, slateEditor) => {
8768
+ editorHasFocusRef.current = true;
7821
8769
  registerActiveRichText(instanceId, editable, slateEditor);
7822
8770
  },
7823
8771
  [instanceId]
7824
8772
  );
7825
8773
  const handleFocusLost = (0, react_exports.useCallback)(() => {
8774
+ editorHasFocusRef.current = false;
8775
+ flushPendingResolution();
7826
8776
  flushPendingChanges();
7827
- }, [flushPendingChanges]);
8777
+ }, [flushPendingChanges, flushPendingResolution]);
7828
8778
  (0, react_exports.useEffect)(() => {
7829
8779
  return () => {
7830
8780
  flushPendingChanges();
@@ -7865,8 +8815,8 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7865
8815
  const activateTextEditing = (0, react_exports.useCallback)(() => {
7866
8816
  richTextState.activateTextEditing();
7867
8817
  requestAnimationFrame(() => {
7868
- var _a2;
7869
- const editable = (_a2 = containerRef.current) == null ? void 0 : _a2.querySelector("[data-slate-editor]");
8818
+ var _a3;
8819
+ const editable = (_a3 = containerRef.current) == null ? void 0 : _a3.querySelector("[data-slate-editor]");
7870
8820
  editable == null ? void 0 : editable.focus({ preventScroll: true });
7871
8821
  if (slateEditorRef.current && !slateEditorRef.current.selection) {
7872
8822
  safeSelectEnd(slateEditorRef.current);
@@ -7889,9 +8839,9 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7889
8839
  (0, react_exports.useEffect)(() => {
7890
8840
  if (!isEditMode) return void 0;
7891
8841
  const guard = (e) => {
7892
- var _a2;
8842
+ var _a3;
7893
8843
  const target = e.target;
7894
- if (!((_a2 = containerRef.current) == null ? void 0 : _a2.contains(target))) return;
8844
+ if (!((_a3 = containerRef.current) == null ? void 0 : _a3.contains(target))) return;
7895
8845
  const isVizSelected = containerRef.current.closest('[data-selected="true"]') != null;
7896
8846
  if (!isVizSelected) return;
7897
8847
  if (!isTextEditingRef.current) {
@@ -7908,28 +8858,74 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7908
8858
  document.addEventListener("mousedown", guard, true);
7909
8859
  return () => document.removeEventListener("mousedown", guard, true);
7910
8860
  }, [isEditMode]);
7911
- const handleContainerClick = (0, react_exports.useCallback)(
8861
+ const maybeActivateEditing = (0, react_exports.useCallback)(
7912
8862
  (e) => {
7913
- if (hasEventHandlers && !isEditMode) {
7914
- onRichtextClick(e);
7915
- }
7916
- if (isEditMode && !isTextEditing && containerRef.current) {
7917
- const isVizSelected = containerRef.current.closest('[data-selected="true"]') != null;
7918
- if (!isVizSelected) return;
7919
- registerActiveRichText(instanceId, null, slateEditorRef.current);
7920
- activateTextEditing();
8863
+ if (!containerRef.current) return;
8864
+ const down = containerMouseDownRef.current;
8865
+ containerMouseDownRef.current = null;
8866
+ if (down && (Math.abs(e.clientX - down.x) > CONTAINER_MOVE_THRESHOLD || Math.abs(e.clientY - down.y) > CONTAINER_MOVE_THRESHOLD)) {
7921
8867
  return;
7922
8868
  }
7923
- if (!isTextEditing || !containerRef.current || isMouseSelecting()) return;
8869
+ if (consumeSuppressNextEditClick()) return;
8870
+ if (isMouseSelecting()) return;
8871
+ const isVizSelected = containerRef.current.closest('[data-selected="true"]') != null;
8872
+ if (!isVizSelected) return;
8873
+ const wrapper = containerRef.current.querySelector("[data-richtext-editor-wrapper]");
8874
+ if (wrapper && !wrapper.contains(e.target)) return;
8875
+ registerActiveRichText(instanceId, null, slateEditorRef.current);
8876
+ activateTextEditing();
8877
+ },
8878
+ [activateTextEditing, instanceId]
8879
+ );
8880
+ const handleEditingOutsideClick = (0, react_exports.useCallback)(
8881
+ (e) => {
8882
+ var _a3;
8883
+ if (!containerRef.current) return;
7924
8884
  const editable = containerRef.current.querySelector("[data-slate-editor]");
7925
8885
  if (!editable || editable.contains(e.target)) return;
8886
+ const wrapper = containerRef.current.querySelector("[data-richtext-editor-wrapper]");
8887
+ if (wrapper && !wrapper.contains(e.target)) {
8888
+ const editorToDeselect = slateEditorRef.current;
8889
+ if (editorToDeselect) {
8890
+ try {
8891
+ slate_exports.Transforms.deselect(editorToDeselect);
8892
+ } catch (e2) {
8893
+ }
8894
+ }
8895
+ (_a3 = globalThis.getSelection()) == null ? void 0 : _a3.removeAllRanges();
8896
+ richTextState.deactivateTextEditing();
8897
+ editable.blur();
8898
+ focusSelectOutline(containerRef.current);
8899
+ return;
8900
+ }
7926
8901
  editable.focus({ preventScroll: true });
7927
8902
  const slateEditor = getActiveSlateEditor();
7928
8903
  if (slateEditor) {
7929
8904
  safeSelectEnd(slateEditor);
7930
8905
  }
7931
8906
  },
7932
- [activateTextEditing, hasEventHandlers, instanceId, isEditMode, isTextEditing, onRichtextClick]
8907
+ [richTextState]
8908
+ );
8909
+ const handleContainerClick = (0, react_exports.useCallback)(
8910
+ (e) => {
8911
+ if (hasEventHandlers && !isEditMode) {
8912
+ onRichtextClick(e);
8913
+ }
8914
+ if (isEditMode && !isTextEditing && containerRef.current) {
8915
+ maybeActivateEditing(e);
8916
+ return;
8917
+ }
8918
+ if (!isTextEditing || !containerRef.current || isMouseSelecting()) return;
8919
+ handleEditingOutsideClick(e);
8920
+ },
8921
+ [
8922
+ hasEventHandlers,
8923
+ isEditMode,
8924
+ isTextEditing,
8925
+ onRichtextClick,
8926
+ maybeActivateEditing,
8927
+ handleEditingOutsideClick
8928
+ ]
7933
8929
  );
7934
8930
  return /* @__PURE__ */ react_exports.createElement(
7935
8931
  PureRichTextProvider,
@@ -7955,12 +8951,16 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7955
8951
  $borderRadius: borderRadius,
7956
8952
  $padding: paddingValues,
7957
8953
  $isTextEditing: isTextEditing,
8954
+ $isEditMode: isEditMode,
7958
8955
  $hasEventHandlers: hasEventHandlers && !isEditMode,
7959
8956
  "data-no-drag": isTextEditing ? "true" : void 0,
7960
8957
  "data-text-editor": isTextEditing ? "true" : void 0,
7961
8958
  "data-test": "purerichtext-container",
7962
- role: !isEditMode ? "region" : void 0,
7963
- "aria-label": !isEditMode ? slateToPlainText(initialValue) || "Empty rich text" : void 0,
8959
+ role: isEditMode ? void 0 : "region",
8960
+ "aria-label": isEditMode ? void 0 : slateToPlainText(initialValue) || "Empty rich text",
8961
+ onMouseDownCapture: (e) => {
8962
+ containerMouseDownRef.current = { x: e.clientX, y: e.clientY };
8963
+ },
7964
8964
  onClick: handleContainerClick
7965
8965
  },
7966
8966
  hasEventHandlers && !isEditMode && /* @__PURE__ */ react_exports.createElement(
@@ -7980,13 +8980,15 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7980
8980
  {
7981
8981
  $isEditMode: isEditMode,
7982
8982
  $isTextEditing: isTextEditing,
8983
+ $hasEventHandlers: hasEventHandlers,
7983
8984
  $lineHeight: currentLineHeight,
8985
+ $verticalAlign: currentVerticalAlign,
7984
8986
  "data-richtext-editor-wrapper": true,
7985
- onMouseDown: isTextEditing ? (e) => {
8987
+ onMouseDown: (e) => {
7986
8988
  if (e.target === e.currentTarget) {
7987
8989
  e.stopPropagation();
7988
8990
  }
7989
- } : void 0
8991
+ }
7990
8992
  },
7991
8993
  /* @__PURE__ */ react_exports.createElement(
7992
8994
  InnerEditor,
@@ -8010,8 +9012,12 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
8010
9012
  recentSavesRef,
8011
9013
  forceNextSyncRef,
8012
9014
  transformTreeRef,
9015
+ syncInitialValueChanges: showResolvedTokens,
8013
9016
  autoResolveTokensRef,
8014
- onAnnouncement: handleAnnouncement
9017
+ onPasteStart: beginPasteBurst,
9018
+ onAnnouncement: handleAnnouncement,
9019
+ nameToValue,
9020
+ onLinkOpen: handleLinkOpen
8015
9021
  }
8016
9022
  )
8017
9023
  ),
@@ -8080,7 +9086,7 @@ function resolveFontSize2(defaultTextStyles, pickedOptions) {
8080
9086
  let fontSize = defaultTextStyles.fontSize || pickedOptions.fontSize;
8081
9087
  let customFontSize = defaultTextStyles.customFontSize || pickedOptions.customFontSize;
8082
9088
  if (typeof fontSize === "string" && fontSize.endsWith("px")) {
8083
- customFontSize = parseInt(fontSize, 10);
9089
+ customFontSize = Number.parseInt(fontSize, 10);
8084
9090
  fontSize = "custom";
8085
9091
  }
8086
9092
  return { fontSize, customFontSize };
@@ -8094,7 +9100,7 @@ var computeVizProps = ({
8094
9100
  hasEventHandlers = false,
8095
9101
  richTextTokenMetadata
8096
9102
  }) => {
8097
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
9103
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
8098
9104
  const pickedOptions = pickValidOptions(options);
8099
9105
  const border = buildBorderConfig(pickedOptions, options);
8100
9106
  const defaultTextStyles = buildDefaultTextStyles(pickedOptions, options);
@@ -8102,7 +9108,7 @@ var computeVizProps = ({
8102
9108
  const highlightColor = defaultTextStyles.highlightColor || defaultTextStyles.backgroundColor || pickedOptions.highlightColor;
8103
9109
  const fontFamily = defaultTextStyles.fontFamily || pickedOptions.fontFamily;
8104
9110
  const { fontSize, customFontSize } = resolveFontSize2(defaultTextStyles, pickedOptions);
8105
- const bold = (_b = (_a = defaultTextStyles.bold) != null ? _a : pickedOptions.bold) != null ? _b : false;
9111
+ const bold = (_b = (_a2 = defaultTextStyles.bold) != null ? _a2 : pickedOptions.bold) != null ? _b : false;
8106
9112
  const italic = (_d = (_c = defaultTextStyles.italic) != null ? _c : pickedOptions.italic) != null ? _d : false;
8107
9113
  const underline = (_f = (_e = defaultTextStyles.underline) != null ? _e : pickedOptions.underline) != null ? _f : false;
8108
9114
  const strikethrough = (_h = (_g = defaultTextStyles.strikethrough) != null ? _g : pickedOptions.strikethrough) != null ? _h : false;