@splunk/visualizations 28.7.0 → 28.8.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 (204) hide show
  1. package/Area.js +2 -2
  2. package/Area.js.map +2 -2
  3. package/Bar.js +2 -2
  4. package/Bar.js.map +2 -2
  5. package/Bubble.js +2 -2
  6. package/Bubble.js.map +2 -2
  7. package/CHANGELOG.external.md +26 -0
  8. package/ChoroplethSvg.js +2 -2
  9. package/ChoroplethSvg.js.map +2 -2
  10. package/Column.js +2 -2
  11. package/Column.js.map +2 -2
  12. package/Ellipse.js +2 -2
  13. package/Ellipse.js.map +2 -2
  14. package/Events.js +2 -2
  15. package/Events.js.map +2 -2
  16. package/FillerGauge.js +10 -5
  17. package/FillerGauge.js.map +2 -2
  18. package/Image.js +2 -2
  19. package/Image.js.map +2 -2
  20. package/Line.js +2 -2
  21. package/Line.js.map +2 -2
  22. package/LinkGraph.js +2 -2
  23. package/LinkGraph.js.map +2 -2
  24. package/Map.js +2 -2
  25. package/Map.js.map +2 -2
  26. package/Markdown.config.js +1 -1
  27. package/Markdown.config.js.map +1 -1
  28. package/Markdown.js +3 -3
  29. package/Markdown.js.map +2 -2
  30. package/MarkerGauge.js +10 -5
  31. package/MarkerGauge.js.map +2 -2
  32. package/NetworkGraph.js +2 -2
  33. package/NetworkGraph.js.map +2 -2
  34. package/ParallelCoordinates.js +2 -2
  35. package/ParallelCoordinates.js.map +2 -2
  36. package/Pie.js +2 -2
  37. package/Pie.js.map +2 -2
  38. package/ProcessTree.js +2 -2
  39. package/ProcessTree.js.map +2 -2
  40. package/Punchcard.js +2 -2
  41. package/Punchcard.js.map +2 -2
  42. package/Rectangle.js +2 -2
  43. package/Rectangle.js.map +2 -2
  44. package/RichText/PureRichText/Editor/EditorPanel.d.ts.map +1 -1
  45. package/RichText/PureRichText/InnerEditor.d.ts +10 -0
  46. package/RichText/PureRichText/InnerEditor.d.ts.map +1 -1
  47. package/RichText/PureRichText/PureRichText.d.ts +17 -0
  48. package/RichText/PureRichText/PureRichText.d.ts.map +1 -1
  49. package/RichText/PureRichText/PureRichTextContext.d.ts.map +1 -1
  50. package/RichText/PureRichText/hooks/useContentSave.d.ts +6 -0
  51. package/RichText/PureRichText/hooks/useContentSave.d.ts.map +1 -1
  52. package/RichText/PureRichText/hooks/useContentSync.d.ts +13 -1
  53. package/RichText/PureRichText/hooks/useContentSync.d.ts.map +1 -1
  54. package/RichText/PureRichText/hooks/useDashboardKeyboardNav.d.ts.map +1 -1
  55. package/RichText/PureRichText/hooks/useEditorSetup.d.ts.map +1 -1
  56. package/RichText/PureRichText/hooks/useFakeHighlight.d.ts +1 -16
  57. package/RichText/PureRichText/hooks/useFakeHighlight.d.ts.map +1 -1
  58. package/RichText/PureRichText/hooks/useTokenMap.d.ts +37 -35
  59. package/RichText/PureRichText/hooks/useTokenMap.d.ts.map +1 -1
  60. package/RichText/PureRichText/renderers/LeafRenderer.d.ts +0 -4
  61. package/RichText/PureRichText/renderers/LeafRenderer.d.ts.map +1 -1
  62. package/RichText/PureRichText/types.d.ts +15 -0
  63. package/RichText/PureRichText/types.d.ts.map +1 -1
  64. package/RichText/PureRichText/utils/slateUtils.d.ts.map +1 -1
  65. package/RichText/RichText.d.ts +2 -0
  66. package/RichText/RichText.d.ts.map +1 -1
  67. package/RichText/config.d.ts.map +1 -1
  68. package/RichText.config.js +14 -1
  69. package/RichText.config.js.map +2 -2
  70. package/RichText.js +733 -263
  71. package/RichText.js.map +4 -4
  72. package/Sankey.js +2 -2
  73. package/Sankey.js.map +2 -2
  74. package/Scatter.js +2 -2
  75. package/Scatter.js.map +2 -2
  76. package/SingleValue.js +2 -2
  77. package/SingleValue.js.map +2 -2
  78. package/SingleValueIcon.js +2 -2
  79. package/SingleValueIcon.js.map +2 -2
  80. package/SingleValueRadial.js +2 -2
  81. package/SingleValueRadial.js.map +2 -2
  82. package/Table/PureTable.d.ts +2 -0
  83. package/Table/PureTable.d.ts.map +1 -1
  84. package/Table/config.d.ts.map +1 -1
  85. package/Table.config.js +7 -0
  86. package/Table.config.js.map +2 -2
  87. package/Table.js +91 -9
  88. package/Table.js.map +4 -4
  89. package/Timeline/PureTimeline/PureTimeline.d.ts +6 -5
  90. package/Timeline/PureTimeline/PureTimeline.d.ts.map +1 -1
  91. package/Timeline/PureTimeline/src/CursorPlugin.d.ts +1 -0
  92. package/Timeline/PureTimeline/src/CursorPlugin.d.ts.map +1 -1
  93. package/Timeline/PureTimeline/src/TimelineLegend.d.ts +10 -7
  94. package/Timeline/PureTimeline/src/TimelineLegend.d.ts.map +1 -1
  95. package/Timeline/PureTimeline/src/TimelineTooltip.d.ts +5 -1
  96. package/Timeline/PureTimeline/src/TimelineTooltip.d.ts.map +1 -1
  97. package/Timeline/PureTimeline/src/TimelineUplot.d.ts +19 -2
  98. package/Timeline/PureTimeline/src/TimelineUplot.d.ts.map +1 -1
  99. package/Timeline/PureTimeline/src/TimelineYAxis.d.ts.map +1 -1
  100. package/Timeline/PureTimeline/src/XAxisPlugin.d.ts +1 -0
  101. package/Timeline/PureTimeline/src/XAxisPlugin.d.ts.map +1 -1
  102. package/Timeline/PureTimeline/src/utils/timelineUtils.d.ts +8 -0
  103. package/Timeline/PureTimeline/src/utils/timelineUtils.d.ts.map +1 -1
  104. package/Timeline.js +449 -211
  105. package/Timeline.js.map +4 -4
  106. package/Treemap/PureTreemap/components/PureTreemap.d.ts +42 -0
  107. package/Treemap/PureTreemap/components/PureTreemap.d.ts.map +1 -0
  108. package/Treemap/PureTreemap/components/TreemapBreadcrumb.d.ts +10 -0
  109. package/Treemap/PureTreemap/components/TreemapBreadcrumb.d.ts.map +1 -0
  110. package/Treemap/PureTreemap/components/TreemapChildCell.d.ts +28 -0
  111. package/Treemap/PureTreemap/components/TreemapChildCell.d.ts.map +1 -0
  112. package/Treemap/PureTreemap/components/TreemapHeader.d.ts +19 -0
  113. package/Treemap/PureTreemap/components/TreemapHeader.d.ts.map +1 -0
  114. package/Treemap/PureTreemap/components/TreemapHoverTarget.d.ts +17 -0
  115. package/Treemap/PureTreemap/components/TreemapHoverTarget.d.ts.map +1 -0
  116. package/Treemap/PureTreemap/components/TreemapLegend.d.ts +20 -0
  117. package/Treemap/PureTreemap/components/TreemapLegend.d.ts.map +1 -0
  118. package/Treemap/PureTreemap/components/TreemapNode.d.ts +5 -0
  119. package/Treemap/PureTreemap/components/TreemapNode.d.ts.map +1 -0
  120. package/Treemap/PureTreemap/components/TreemapParentNode.d.ts +10 -0
  121. package/Treemap/PureTreemap/components/TreemapParentNode.d.ts.map +1 -0
  122. package/Treemap/PureTreemap/components/TreemapStandaloneNode.d.ts +6 -0
  123. package/Treemap/PureTreemap/components/TreemapStandaloneNode.d.ts.map +1 -0
  124. package/Treemap/PureTreemap/components/TreemapTooltip.d.ts +17 -0
  125. package/Treemap/PureTreemap/components/TreemapTooltip.d.ts.map +1 -0
  126. package/Treemap/PureTreemap/mockdata/data.d.ts +90 -0
  127. package/Treemap/PureTreemap/mockdata/data.d.ts.map +1 -0
  128. package/Treemap/PureTreemap/utils/treemapColorUtils.d.ts +67 -0
  129. package/Treemap/PureTreemap/utils/treemapColorUtils.d.ts.map +1 -0
  130. package/Treemap/PureTreemap/utils/treemapDataColorUtils.d.ts +5 -0
  131. package/Treemap/PureTreemap/utils/treemapDataColorUtils.d.ts.map +1 -0
  132. package/Treemap/PureTreemap/utils/treemapDataUtils.d.ts +14 -0
  133. package/Treemap/PureTreemap/utils/treemapDataUtils.d.ts.map +1 -0
  134. package/Treemap/PureTreemap/utils/treemapLayout.d.ts +49 -0
  135. package/Treemap/PureTreemap/utils/treemapLayout.d.ts.map +1 -0
  136. package/Treemap/PureTreemap/utils/treemapNodeUtils.d.ts +81 -0
  137. package/Treemap/PureTreemap/utils/treemapNodeUtils.d.ts.map +1 -0
  138. package/Treemap/PureTreemap/utils/treemapTypes.d.ts +37 -0
  139. package/Treemap/PureTreemap/utils/treemapTypes.d.ts.map +1 -0
  140. package/Treemap/PureTreemap/utils/treemapUtils.d.ts +76 -0
  141. package/Treemap/PureTreemap/utils/treemapUtils.d.ts.map +1 -0
  142. package/Treemap/Treemap.d.ts +12 -0
  143. package/Treemap/Treemap.d.ts.map +1 -0
  144. package/Treemap/config.d.ts +4 -0
  145. package/Treemap/config.d.ts.map +1 -0
  146. package/Treemap/index.d.ts +3 -0
  147. package/Treemap/index.d.ts.map +1 -0
  148. package/Treemap.config.js +465 -0
  149. package/Treemap.config.js.map +7 -0
  150. package/Treemap.js +6233 -0
  151. package/Treemap.js.map +7 -0
  152. package/common/DocExampleWithVizSandbox.js.map +2 -2
  153. package/common/GaugeMajorTicks.js.map +2 -2
  154. package/common/GaugeValueMarker.js +1 -0
  155. package/common/GaugeValueMarker.js.map +2 -2
  156. package/common/OverviewDoc.js.map +2 -2
  157. package/common/docUtils.d.ts.map +1 -1
  158. package/common/docUtils.js +1 -8
  159. package/common/docUtils.js.map +2 -2
  160. package/common/gaugeUtils.d.ts.map +1 -1
  161. package/common/gaugeUtils.js +7 -3
  162. package/common/gaugeUtils.js.map +2 -2
  163. package/common/hocs/FixedSizeContainer.d.ts.map +1 -1
  164. package/common/hooks/useDynamicHeight.d.ts +67 -0
  165. package/common/hooks/useDynamicHeight.d.ts.map +1 -0
  166. package/common/interfaces/VizCategory.d.ts +2 -1
  167. package/common/interfaces/VizCategory.d.ts.map +1 -1
  168. package/common/withDashboardViz.js +2 -2
  169. package/common/withDashboardViz.js.map +2 -2
  170. package/docs-llm/INDEX.md +1 -0
  171. package/docs-llm/area/options.md +84 -84
  172. package/docs-llm/bar/options.md +77 -77
  173. package/docs-llm/bubble/options.md +51 -51
  174. package/docs-llm/choropleth-svg/options.md +5 -5
  175. package/docs-llm/column/options.md +82 -82
  176. package/docs-llm/ellipse/options.md +6 -6
  177. package/docs-llm/events/options.md +6 -6
  178. package/docs-llm/filler-gauge/options.md +16 -16
  179. package/docs-llm/image/options.md +3 -3
  180. package/docs-llm/line/options.md +82 -82
  181. package/docs-llm/link-graph/options.md +16 -16
  182. package/docs-llm/map/options.md +12 -12
  183. package/docs-llm/markdown/options.md +7 -7
  184. package/docs-llm/marker-gauge/options.md +16 -16
  185. package/docs-llm/network-graph/options.md +39 -39
  186. package/docs-llm/parallel-coordinates/options.md +4 -4
  187. package/docs-llm/pie/options.md +23 -23
  188. package/docs-llm/process-tree/options.md +22 -22
  189. package/docs-llm/punchcard/options.md +23 -23
  190. package/docs-llm/pure-rich-text/options.md +6 -5
  191. package/docs-llm/rectangle/options.md +9 -9
  192. package/docs-llm/rich-text/options.md +6 -5
  193. package/docs-llm/sankey/options.md +9 -9
  194. package/docs-llm/scatter/options.md +57 -57
  195. package/docs-llm/single-value/options.md +39 -39
  196. package/docs-llm/single-value-icon/options.md +33 -33
  197. package/docs-llm/single-value-radial/options.md +31 -31
  198. package/docs-llm/table/options.md +14 -13
  199. package/docs-llm/timeline/options.md +17 -17
  200. package/docs-llm/treemap/examples-json.md +5 -0
  201. package/docs-llm/treemap/examples-react.md +5 -0
  202. package/docs-llm/treemap/options.md +26 -0
  203. package/docs-llm/treemap/overview.md +27 -0
  204. package/package.json +28 -27
package/RichText.js CHANGED
@@ -186,6 +186,19 @@ var themes = {
186
186
  defaultBackgroundColor: () => "transparent"
187
187
  };
188
188
  var editorConfig = [
189
+ {
190
+ label: (0, i18n_exports._)("Data display"),
191
+ open: true,
192
+ layout: [
193
+ [
194
+ {
195
+ label: (0, i18n_exports._)("Preview token values"),
196
+ option: "previewTokenValues",
197
+ editor: "editor.toggle"
198
+ }
199
+ ]
200
+ ]
201
+ },
189
202
  {
190
203
  label: (0, i18n_exports._)("Color and style"),
191
204
  open: true,
@@ -261,7 +274,7 @@ var config = {
261
274
  * viz name
262
275
  */
263
276
  name: (0, i18n_exports._)("Text"),
264
- category: "Comparisons" /* COMPARISONS */,
277
+ category: "Text" /* TEXT */,
265
278
  status: "preview",
266
279
  /**
267
280
  * viz icon
@@ -672,7 +685,7 @@ var Cover = styled_components_default.div`
672
685
  bottom: 0;
673
686
  `;
674
687
  var Blocker = styled_components_default.div.attrs({
675
- "data-splunk-visualization-version": "28.7.0 - d7b18cab6"
688
+ "data-splunk-visualization-version": "28.8.0 - 633c53372"
676
689
  })`
677
690
  position: relative;
678
691
  width: 100%;
@@ -771,7 +784,7 @@ var withFixedSizeContainer = (Viz) => {
771
784
  FixSizeItem,
772
785
  {
773
786
  "data-test": "fix-size-item",
774
- "data-splunk-visualization-version": "28.7.0 - d7b18cab6",
787
+ "data-splunk-visualization-version": "28.8.0 - 633c53372",
775
788
  width,
776
789
  height,
777
790
  backgroundColor
@@ -2670,14 +2683,23 @@ var defaultImport33 = __toESM(require("@splunk/dashboard-context"));
2670
2683
  __reExport(dashboard_context_exports, require("@splunk/dashboard-context"));
2671
2684
  var dashboard_context_default = "default" in defaultImport33 ? defaultImport33.default : defaultImport33;
2672
2685
 
2686
+ // esm-externals:slate
2687
+ var slate_exports = {};
2688
+ __export(slate_exports, {
2689
+ default: () => slate_default
2690
+ });
2691
+ var defaultImport34 = __toESM(require("slate"));
2692
+ __reExport(slate_exports, require("slate"));
2693
+ var slate_default = "default" in defaultImport34 ? defaultImport34.default : defaultImport34;
2694
+
2673
2695
  // esm-externals:slate-react
2674
2696
  var slate_react_exports = {};
2675
2697
  __export(slate_react_exports, {
2676
2698
  default: () => slate_react_default
2677
2699
  });
2678
- var defaultImport34 = __toESM(require("slate-react"));
2700
+ var defaultImport35 = __toESM(require("slate-react"));
2679
2701
  __reExport(slate_react_exports, require("slate-react"));
2680
- var slate_react_default = "default" in defaultImport34 ? defaultImport34.default : defaultImport34;
2702
+ var slate_react_default = "default" in defaultImport35 ? defaultImport35.default : defaultImport35;
2681
2703
 
2682
2704
  // src/RichText/PureRichText/activeInstance.ts
2683
2705
  var activeRichTextId = null;
@@ -2734,15 +2756,6 @@ function isMouseSelecting() {
2734
2756
  return mouseSelecting;
2735
2757
  }
2736
2758
 
2737
- // esm-externals:slate
2738
- var slate_exports = {};
2739
- __export(slate_exports, {
2740
- default: () => slate_default
2741
- });
2742
- var defaultImport35 = __toESM(require("slate"));
2743
- __reExport(slate_exports, require("slate"));
2744
- var slate_default = "default" in defaultImport35 ? defaultImport35.default : defaultImport35;
2745
-
2746
2759
  // src/RichText/PureRichText/types.ts
2747
2760
  var DEFAULT_TEXT_STYLES = {
2748
2761
  bold: false,
@@ -2799,6 +2812,7 @@ __reExport(dompurify_exports, require("dompurify"));
2799
2812
  var dompurify_default = "default" in defaultImport36 ? defaultImport36.default : defaultImport36;
2800
2813
 
2801
2814
  // src/RichText/PureRichText/utils/slateUtils.ts
2815
+ var sharedDomParser = new DOMParser();
2802
2816
  function safeSelectEnd(editor) {
2803
2817
  try {
2804
2818
  const end = slate_exports.Editor.end(editor, []);
@@ -3210,7 +3224,10 @@ function slateToHtml(value) {
3210
3224
  };
3211
3225
  const serializeTextNode = (node) => {
3212
3226
  const styles = buildTextStyles(node);
3213
- let { text } = node;
3227
+ let text = node.tokenName ? `$${node.tokenName}$` : node.text;
3228
+ if (node.isEscapedDollar && (node.text === "$" || node.text === "$$")) {
3229
+ text = "$$";
3230
+ }
3214
3231
  if (!text) {
3215
3232
  return styles.length > 0 ? `<span style="${styles.join("; ")}"></span>` : "";
3216
3233
  }
@@ -3231,7 +3248,7 @@ function slateToHtml(value) {
3231
3248
  const styleAttr = buildBlockStyleAttr(element);
3232
3249
  switch (element.type) {
3233
3250
  case "paragraph":
3234
- return `<p${styleAttr}>${children || "<br>"}</p>`;
3251
+ return `<p${styleAttr}>${children || "\n"}</p>`;
3235
3252
  case "bulleted-list":
3236
3253
  return `<ul${styleAttr}>${children}</ul>`;
3237
3254
  case "numbered-list":
@@ -3258,7 +3275,23 @@ function htmlToSlate(html) {
3258
3275
  if (!html || html.trim() === "") {
3259
3276
  return EMPTY_SLATE_VALUE;
3260
3277
  }
3261
- const sanitized = dompurify_default.sanitize(html, {
3278
+ const NULL = "\0";
3279
+ const restorePlaceholderRe = new RegExp(String.raw`${NULL}RT(\d+)${NULL}`, "g");
3280
+ const escapeUnsafeAngleBrackets = (input) => {
3281
+ const placeholders = [];
3282
+ const allowedTagRegex = /<\/?(?:p|br|strong|b|em|i|u|s|strike|span|a|ul|ol|li|div|font)\b[^>]*>/gi;
3283
+ const withPlaceholders = input.replace(allowedTagRegex, (match) => {
3284
+ const index = placeholders.push(match) - 1;
3285
+ return `${NULL}RT${index}${NULL}`;
3286
+ });
3287
+ const escaped = withPlaceholders.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
3288
+ return escaped.replace(restorePlaceholderRe, (_5, index) => {
3289
+ const parsedIndex = Number.parseInt(index, 10);
3290
+ return placeholders[parsedIndex] || "";
3291
+ });
3292
+ };
3293
+ const normalizedHtml = escapeUnsafeAngleBrackets(html);
3294
+ const sanitized = dompurify_default.sanitize(normalizedHtml, {
3262
3295
  ALLOWED_TAGS: [
3263
3296
  "p",
3264
3297
  "br",
@@ -3279,8 +3312,7 @@ function htmlToSlate(html) {
3279
3312
  ],
3280
3313
  ALLOWED_ATTR: ["style", "href", "color", "face", "size"]
3281
3314
  });
3282
- const parser = new DOMParser();
3283
- const doc = parser.parseFromString(`<body>${sanitized}</body>`, "text/html");
3315
+ const doc = sharedDomParser.parseFromString(`<body>${sanitized}</body>`, "text/html");
3284
3316
  const applyMarksToChildren = (children, marks) => {
3285
3317
  return children.map((child) => {
3286
3318
  if (slate_exports.Text.isText(child)) {
@@ -3343,6 +3375,14 @@ function htmlToSlate(html) {
3343
3375
  }
3344
3376
  return children;
3345
3377
  };
3378
+ const collapseEmptyLineChildren = (children) => {
3379
+ if (children.length !== 1) return children;
3380
+ const [only] = children;
3381
+ if (slate_exports.Text.isText(only) && /^[\n\r]+$/.test(only.text)) {
3382
+ return [__spreadProps(__spreadValues({}, only), { text: "" })];
3383
+ }
3384
+ return children;
3385
+ };
3346
3386
  const handleTag = (tagName, element, children, blockStyles) => {
3347
3387
  const { align, lineHeight } = blockStyles;
3348
3388
  switch (tagName) {
@@ -3350,13 +3390,23 @@ function htmlToSlate(html) {
3350
3390
  case "div":
3351
3391
  return children;
3352
3392
  case "p":
3353
- return { type: "paragraph", align, lineHeight, children };
3393
+ return {
3394
+ type: "paragraph",
3395
+ align,
3396
+ lineHeight,
3397
+ children: collapseEmptyLineChildren(children)
3398
+ };
3354
3399
  case "ul":
3355
3400
  return { type: "bulleted-list", align, lineHeight, children };
3356
3401
  case "ol":
3357
3402
  return { type: "numbered-list", align, lineHeight, children };
3358
3403
  case "li":
3359
- return { type: "list-item", align, lineHeight, children };
3404
+ return {
3405
+ type: "list-item",
3406
+ align,
3407
+ lineHeight,
3408
+ children: collapseEmptyLineChildren(children)
3409
+ };
3360
3410
  case "a":
3361
3411
  return {
3362
3412
  type: "link",
@@ -3495,6 +3545,31 @@ function generateFormatAnnouncement(command, value) {
3495
3545
  }
3496
3546
 
3497
3547
  // src/RichText/PureRichText/PureRichTextContext.tsx
3548
+ function activeStylesEqual(a, b) {
3549
+ const keys = [
3550
+ "bold",
3551
+ "italic",
3552
+ "underline",
3553
+ "strikethrough",
3554
+ "color",
3555
+ "backgroundColor",
3556
+ "fontSize",
3557
+ "fontFamily",
3558
+ "textAlign",
3559
+ "verticalAlign",
3560
+ "lineHeight",
3561
+ "listType"
3562
+ ];
3563
+ for (const key of keys) {
3564
+ if (a[key] !== b[key]) return false;
3565
+ }
3566
+ const aMixed = a.isMixed;
3567
+ const bMixed = b.isMixed;
3568
+ if (aMixed === bMixed) return true;
3569
+ if (!aMixed || !bMixed) return false;
3570
+ const mixedKeys = ["color", "backgroundColor", "fontSize", "fontFamily", "lineHeight"];
3571
+ return mixedKeys.every((key) => aMixed[key] === bMixed[key]);
3572
+ }
3498
3573
  var PureRichTextContext = (0, react_exports.createContext)(null);
3499
3574
  function usePureRichText() {
3500
3575
  const context = (0, react_exports.useContext)(PureRichTextContext);
@@ -3610,7 +3685,7 @@ function PureRichTextProvider({
3610
3685
  if (slateStyles.isMixed && Object.keys(slateStyles.isMixed).length > 0) {
3611
3686
  newActiveStyles.isMixed = slateStyles.isMixed;
3612
3687
  }
3613
- setActiveTextStyles(newActiveStyles);
3688
+ setActiveTextStyles((prev) => activeStylesEqual(prev, newActiveStyles) ? prev : newActiveStyles);
3614
3689
  },
3615
3690
  [userDefaultStyles, resolveBooleanMark]
3616
3691
  );
@@ -4988,21 +5063,31 @@ var EditorPanel = ({
4988
5063
  anchor: linkButtonRef.current,
4989
5064
  onRequestClose: handleLinkPopoverClose
4990
5065
  },
4991
- /* @__PURE__ */ react_default.createElement(LinkPopoverContent, { ref: linkPopoverRef, onKeyDown: handleLinkKeyDown }, /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "Text", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(
4992
- Text_default,
4993
- {
4994
- value: linkText,
4995
- onChange: (_e, { value: v }) => setLinkText(v),
4996
- placeholder: "Link text"
4997
- }
4998
- )), /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "URL", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(
4999
- Text_default,
5066
+ /* @__PURE__ */ react_default.createElement(
5067
+ LinkPopoverContent,
5000
5068
  {
5001
- value: linkUrl,
5002
- onChange: (_e, { value: v }) => setLinkUrl(v),
5003
- placeholder: "https://..."
5004
- }
5005
- )), /* @__PURE__ */ react_default.createElement(Row, null, /* @__PURE__ */ react_default.createElement(Button_default, { appearance: "primary", onClick: handleLinkSave, label: "Save" }), linkIsActive && /* @__PURE__ */ react_default.createElement(Button_default, { onClick: handleLinkRemove, label: "Remove" }), /* @__PURE__ */ react_default.createElement(Button_default, { onClick: handleLinkPopoverClose, label: "Cancel" })))
5069
+ ref: linkPopoverRef,
5070
+ onKeyDown: handleLinkKeyDown,
5071
+ "data-test": "link-popover-content"
5072
+ },
5073
+ /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "Text", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(
5074
+ Text_default,
5075
+ {
5076
+ value: linkText,
5077
+ onChange: (_e, { value: v }) => setLinkText(v),
5078
+ placeholder: "Link text"
5079
+ }
5080
+ )),
5081
+ /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "URL", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(
5082
+ Text_default,
5083
+ {
5084
+ value: linkUrl,
5085
+ onChange: (_e, { value: v }) => setLinkUrl(v),
5086
+ placeholder: "https://..."
5087
+ }
5088
+ )),
5089
+ /* @__PURE__ */ react_default.createElement(Row, null, /* @__PURE__ */ react_default.createElement(Button_default, { appearance: "primary", onClick: handleLinkSave, label: "Save" }), linkIsActive && /* @__PURE__ */ react_default.createElement(Button_default, { onClick: handleLinkRemove, label: "Remove" }), /* @__PURE__ */ react_default.createElement(Button_default, { onClick: handleLinkPopoverClose, label: "Cancel" }))
5090
+ )
5006
5091
  ), /* @__PURE__ */ react_default.createElement(ControlGroup_default, { label: "Alignment", labelPosition: "top" }, /* @__PURE__ */ react_default.createElement(AlignmentSection, null, /* @__PURE__ */ react_default.createElement(HorizontalAlignmentRadioBar, null, /* @__PURE__ */ react_default.createElement(
5007
5092
  RadioBar_default,
5008
5093
  {
@@ -5318,6 +5403,9 @@ var Leaf = ({ attributes, children, leaf }) => {
5318
5403
  if (customLeaf.strikethrough) {
5319
5404
  content = /* @__PURE__ */ react_exports.createElement("s", null, content);
5320
5405
  }
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));
5408
+ }
5321
5409
  return /* @__PURE__ */ react_exports.createElement("span", __spreadProps(__spreadValues({}, attributes), { style }), content);
5322
5410
  };
5323
5411
 
@@ -5419,7 +5507,7 @@ function getTokenRangeAtPoint(e, point) {
5419
5507
  const [node, path] = slate_exports.Editor.node(e, point);
5420
5508
  if (!slate_exports.Text.isText(node)) return null;
5421
5509
  const custom = node;
5422
- if (!custom.tokenName) return null;
5510
+ if (!custom.tokenName && !custom.isEscapedDollar) return null;
5423
5511
  return {
5424
5512
  anchor: { path, offset: 0 },
5425
5513
  focus: { path, offset: custom.text.length }
@@ -5439,7 +5527,8 @@ function getAtomicRangeAtPoint(e, point) {
5439
5527
  }
5440
5528
  function isStrictlyInsideAtomic(e, point) {
5441
5529
  const [node] = slate_exports.Editor.node(e, point);
5442
- if (slate_exports.Text.isText(node) && node.tokenName) {
5530
+ const custom = node;
5531
+ if (slate_exports.Text.isText(node) && (custom.tokenName || custom.isEscapedDollar)) {
5443
5532
  return point.offset > 0 && point.offset < node.text.length;
5444
5533
  }
5445
5534
  const linkEntry = slate_exports.Editor.above(e, {
@@ -5514,11 +5603,26 @@ function expandSelectionToAtomic(e) {
5514
5603
  }
5515
5604
  }
5516
5605
  function moveCursorPastAtomicIfNeeded(e) {
5606
+ var _a;
5517
5607
  if (!e.selection || !slate_exports.Range.isCollapsed(e.selection)) return;
5518
- if (!isStrictlyInsideAtomic(e, e.selection.anchor)) return;
5519
- const after = getPointAfterAtomic(e, e.selection.anchor);
5520
- if (after) {
5521
- slate_exports.Transforms.select(e, after);
5608
+ const { anchor } = e.selection;
5609
+ const [node] = slate_exports.Editor.node(e, anchor);
5610
+ if (slate_exports.Text.isText(node) && (node.tokenName || node.isEscapedDollar)) {
5611
+ if (anchor.offset > 0 && anchor.offset < node.text.length) {
5612
+ const endPoint = { path: anchor.path, offset: node.text.length };
5613
+ e.selection = { anchor: endPoint, focus: endPoint };
5614
+ }
5615
+ const currentMarks = (_a = slate_exports.Editor.marks(e)) != null ? _a : {};
5616
+ const marksWithoutToken = __spreadValues({}, currentMarks);
5617
+ delete marksWithoutToken.tokenName;
5618
+ delete marksWithoutToken.isEscapedDollar;
5619
+ e.marks = marksWithoutToken;
5620
+ return;
5621
+ }
5622
+ if (!isStrictlyInsideAtomic(e, anchor)) return;
5623
+ const afterAtomic = getPointAfterAtomic(e, anchor);
5624
+ if (afterAtomic) {
5625
+ slate_exports.Transforms.select(e, afterAtomic);
5522
5626
  }
5523
5627
  }
5524
5628
  function tryExitEmptyListItem(e) {
@@ -5537,6 +5641,18 @@ function tryExitEmptyListItem(e) {
5537
5641
  slate_exports.Transforms.setNodes(e, { type: "paragraph" });
5538
5642
  return true;
5539
5643
  }
5644
+ function blockPathAt(ed, point) {
5645
+ const above = slate_exports.Editor.above(ed, {
5646
+ at: point,
5647
+ match: (n) => !slate_exports.Editor.isEditor(n) && slate_exports.Element.isElement(n) && slate_exports.Editor.isBlock(ed, n)
5648
+ });
5649
+ return above ? above[1] : null;
5650
+ }
5651
+ function inSameBlock(ed, a, b) {
5652
+ const pa = blockPathAt(ed, a);
5653
+ const pb = blockPathAt(ed, b);
5654
+ return pa !== null && pb !== null && slate_exports.Path.equals(pa, pb);
5655
+ }
5540
5656
  function tryDeleteAtomicBackward(ed, anchor) {
5541
5657
  if (isStrictlyInsideAtomic(ed, anchor)) {
5542
5658
  const range2 = getAtomicRangeAtPoint(ed, anchor);
@@ -5550,7 +5666,8 @@ function tryDeleteAtomicBackward(ed, anchor) {
5550
5666
  }
5551
5667
  if (currentRange) return false;
5552
5668
  const before = slate_exports.Editor.before(ed, anchor);
5553
- const prevRange = before ? getAtomicRangeAtPoint(ed, before) : null;
5669
+ if (!before || !inSameBlock(ed, anchor, before)) return false;
5670
+ const prevRange = getAtomicRangeAtPoint(ed, before);
5554
5671
  if (!prevRange) return false;
5555
5672
  slate_exports.Transforms.delete(ed, { at: prevRange });
5556
5673
  return true;
@@ -5594,7 +5711,8 @@ function tryDeleteAtomicForward(ed, anchor) {
5594
5711
  }
5595
5712
  if (fwdRange) return false;
5596
5713
  const after = slate_exports.Editor.after(ed, anchor);
5597
- const nextRange = after ? getAtomicRangeAtPoint(ed, after) : null;
5714
+ if (!after || !inSameBlock(ed, anchor, after)) return false;
5715
+ const nextRange = getAtomicRangeAtPoint(ed, after);
5598
5716
  if (!nextRange) return false;
5599
5717
  slate_exports.Transforms.delete(ed, { at: nextRange });
5600
5718
  return true;
@@ -5658,6 +5776,17 @@ function installDeleteOverrides(e) {
5658
5776
  deleteForward(unit);
5659
5777
  };
5660
5778
  }
5779
+ function installNormalizeOverride(e) {
5780
+ const { normalizeNode } = e;
5781
+ e.normalizeNode = (entry) => {
5782
+ const [node, path] = entry;
5783
+ if (slate_exports.Text.isText(node) && node.text === "" && (node.tokenName || node.isEscapedDollar)) {
5784
+ slate_exports.Transforms.unsetNodes(e, ["tokenName", "isEscapedDollar", "isRawToken"], { at: path });
5785
+ return;
5786
+ }
5787
+ normalizeNode(entry);
5788
+ };
5789
+ }
5661
5790
  function installOnChangeOverride(e, getSavedMarks, clearSavedMarks) {
5662
5791
  const { onChange } = e;
5663
5792
  e.onChange = () => {
@@ -5681,6 +5810,7 @@ function useEditorSetup(defaultTextStyleRef) {
5681
5810
  savedMarksForOnChange = slate_exports.Editor.marks(e);
5682
5811
  });
5683
5812
  installDeleteOverrides(e);
5813
+ installNormalizeOverride(e);
5684
5814
  installOnChangeOverride(
5685
5815
  e,
5686
5816
  () => savedMarksForOnChange,
@@ -5704,24 +5834,6 @@ function useInitialMarks(editor, isEditMode, defaultTextStyle) {
5704
5834
  }
5705
5835
 
5706
5836
  // src/RichText/PureRichText/hooks/useFakeHighlight.ts
5707
- function pointAbsOffset(editor, point) {
5708
- let abs = 0;
5709
- for (const [textNode, path] of slate_exports.Editor.nodes(editor, {
5710
- at: [],
5711
- match: (n) => slate_exports.Text.isText(n)
5712
- })) {
5713
- if (slate_exports.Path.equals(path, point.path)) return abs + point.offset;
5714
- abs += textNode.text.length;
5715
- }
5716
- return abs;
5717
- }
5718
- function rangeToAbsOffsets(editor, range2) {
5719
- const [start, end] = slate_exports.Range.edges(range2);
5720
- return {
5721
- absStart: pointAbsOffset(editor, start),
5722
- absEnd: pointAbsOffset(editor, end)
5723
- };
5724
- }
5725
5837
  function pointToAbsOffset(editor, point) {
5726
5838
  let offset = 0;
5727
5839
  for (const [textNode, path] of slate_exports.Editor.nodes(editor, {
@@ -5733,6 +5845,13 @@ function pointToAbsOffset(editor, point) {
5733
5845
  }
5734
5846
  return offset;
5735
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
+ }
5736
5855
  function absOffsetToPoint(editor, absOffset, isStart = false) {
5737
5856
  let seen = 0;
5738
5857
  for (const [textNode, path] of slate_exports.Editor.nodes(editor, {
@@ -5769,8 +5888,9 @@ function useFakeHighlight(editor) {
5769
5888
  }, []);
5770
5889
  const decorate = (0, react_exports.useCallback)(
5771
5890
  ([node, path]) => {
5772
- if (!fakeHighlightAbs || !slate_exports.Text.isText(node)) return [];
5773
- const { absStart, absEnd } = fakeHighlightAbs;
5891
+ const abs = fakeHighlightAbsRef.current;
5892
+ if (!abs || !slate_exports.Text.isText(node)) return [];
5893
+ const { absStart, absEnd } = abs;
5774
5894
  let nodeAbsStart = 0;
5775
5895
  for (const [n, p] of slate_exports.Editor.nodes(editor, {
5776
5896
  at: [],
@@ -5791,6 +5911,8 @@ function useFakeHighlight(editor) {
5791
5911
  }
5792
5912
  ];
5793
5913
  },
5914
+ // fakeHighlightAbs (state) triggers re-evaluation; fakeHighlightAbsRef provides the current value.
5915
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5794
5916
  [fakeHighlightAbs, editor]
5795
5917
  );
5796
5918
  return {
@@ -5802,6 +5924,140 @@ function useFakeHighlight(editor) {
5802
5924
  };
5803
5925
  }
5804
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;
6030
+ }
6031
+ function displayTextForToken(name, nameToValue) {
6032
+ const value = nameToValue == null ? void 0 : nameToValue.get(name);
6033
+ return value !== void 0 && value !== "" ? value : `$${name}$`;
6034
+ }
6035
+ function displayTextForEscapedDollar(nameToValue) {
6036
+ return nameToValue ? "$" : "$$";
6037
+ }
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;
6054
+ }
6055
+ }
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 };
6059
+ }
6060
+
5805
6061
  // src/RichText/PureRichText/hooks/useContentSync.ts
5806
6062
  function clampPoint(editor, point) {
5807
6063
  try {
@@ -5833,6 +6089,22 @@ function safeRestoreSelection(editor, selection) {
5833
6089
  }
5834
6090
  }
5835
6091
  }
6092
+ function directRestoreSelection(editor, selection) {
6093
+ try {
6094
+ if (selection) {
6095
+ editor.selection = clampSelection(editor, selection);
6096
+ } else {
6097
+ const end = slate_exports.Editor.end(editor, []);
6098
+ editor.selection = { anchor: end, focus: end };
6099
+ }
6100
+ } catch (e) {
6101
+ try {
6102
+ const end = slate_exports.Editor.end(editor, []);
6103
+ editor.selection = { anchor: end, focus: end };
6104
+ } catch (e2) {
6105
+ }
6106
+ }
6107
+ }
5836
6108
  function consumeForceSync(ref) {
5837
6109
  var _a;
5838
6110
  const value = (_a = ref == null ? void 0 : ref.current) != null ? _a : false;
@@ -5841,18 +6113,104 @@ function consumeForceSync(ref) {
5841
6113
  }
5842
6114
  return value;
5843
6115
  }
5844
- function shouldSkipSync(forceSync, richTextContent, lastEmittedHtml, recentSavesRef, hasFocusRef) {
6116
+ function shouldSkipSync(forceSync, richTextContent, recentSavesRef, isTextEditingRef) {
5845
6117
  if (forceSync) return false;
5846
6118
  if (recentSavesRef == null ? void 0 : recentSavesRef.current.has(richTextContent)) return true;
5847
- if (hasFocusRef.current) return true;
6119
+ if (isTextEditingRef.current) return true;
5848
6120
  return false;
5849
6121
  }
6122
+ function snapToTokenEdge(editor, point, isStart) {
6123
+ try {
6124
+ const [node] = slate_exports.Editor.node(editor, point);
6125
+ if (slate_exports.Text.isText(node) && node.tokenName) {
6126
+ return { path: point.path, offset: isStart ? 0 : node.text.length };
6127
+ }
6128
+ } catch (e) {
6129
+ }
6130
+ return point;
6131
+ }
6132
+ function restoreSelectionAndHighlight({
6133
+ editor,
6134
+ savedSelection,
6135
+ forceSync,
6136
+ isExternalContentChange,
6137
+ fakeHighlightAbsRef,
6138
+ hasFocusRef,
6139
+ updateFakeHighlightAbs
6140
+ }) {
6141
+ if (isExternalContentChange || forceSync) {
6142
+ if (forceSync) {
6143
+ directRestoreSelection(editor, savedSelection);
6144
+ } else {
6145
+ safeRestoreSelection(editor, savedSelection);
6146
+ }
6147
+ }
6148
+ if (fakeHighlightAbsRef.current !== null && !hasFocusRef.current && editor.selection) {
6149
+ let [start, end] = slate_exports.Range.isBackward(editor.selection) ? [editor.selection.focus, editor.selection.anchor] : [editor.selection.anchor, editor.selection.focus];
6150
+ start = snapToTokenEdge(editor, start, true);
6151
+ end = snapToTokenEdge(editor, end, false);
6152
+ updateFakeHighlightAbs({
6153
+ absStart: pointToAbsOffset(editor, start),
6154
+ absEnd: pointToAbsOffset(editor, end)
6155
+ });
6156
+ } else {
6157
+ updateFakeHighlightAbs(null);
6158
+ }
6159
+ }
5850
6160
  function findHistoryIndex(history, html) {
5851
6161
  for (let i = history.length - 1; i >= 0; i -= 1) {
5852
6162
  if (history[i].html === html) return i;
5853
6163
  }
5854
6164
  return -1;
5855
6165
  }
6166
+ function isTypingOnly(editor) {
6167
+ return editor.operations.every(
6168
+ (op) => op.type === "set_selection" || op.type === "insert_text" || op.type === "remove_text"
6169
+ );
6170
+ }
6171
+ function emitContentChange({
6172
+ editor,
6173
+ html,
6174
+ prevSelection,
6175
+ lastEmittedHtmlRef,
6176
+ emittedHistoryRef,
6177
+ historyPosRef,
6178
+ onContentChange,
6179
+ autoResolveTokensRef
6180
+ }) {
6181
+ const typing = isTypingOnly(editor);
6182
+ const hasBareToken = typing && (autoResolveTokensRef == null ? void 0 : autoResolveTokensRef.current) != null && new RegExp(TOKEN_PATTERN.source, TOKEN_PATTERN.flags).test(html);
6183
+ const pos = historyPosRef.current;
6184
+ lastEmittedHtmlRef.current = html;
6185
+ emittedHistoryRef.current = [
6186
+ ...emittedHistoryRef.current.slice(0, pos + 1),
6187
+ { html, selection: editor.selection, preSelection: prevSelection }
6188
+ ];
6189
+ historyPosRef.current = emittedHistoryRef.current.length - 1;
6190
+ onContentChange(html, hasBareToken || !typing);
6191
+ if (autoResolveTokensRef == null ? void 0 : autoResolveTokensRef.current) {
6192
+ queueMicrotask(autoResolveTokensRef.current);
6193
+ }
6194
+ }
6195
+ function cancelPendingStyleUpdate(styleUpdateRafRef) {
6196
+ if (styleUpdateRafRef.current !== null) {
6197
+ cancelAnimationFrame(styleUpdateRafRef.current);
6198
+ styleUpdateRafRef.current = null;
6199
+ }
6200
+ }
6201
+ function recomputeStylesForContentChange(styleUpdateRafRef, updateActiveStyles) {
6202
+ cancelPendingStyleUpdate(styleUpdateRafRef);
6203
+ updateActiveStyles(true);
6204
+ }
6205
+ function scheduleStylesForSelectionChange(editor, styleUpdateRafRef, updateActiveStyles) {
6206
+ if (styleUpdateRafRef.current !== null) return;
6207
+ styleUpdateRafRef.current = requestAnimationFrame(() => {
6208
+ styleUpdateRafRef.current = null;
6209
+ if (editor.selection) {
6210
+ updateActiveStyles(false);
6211
+ }
6212
+ });
6213
+ }
5856
6214
  function useContentSync({
5857
6215
  editor,
5858
6216
  initialValue,
@@ -5862,12 +6220,16 @@ function useContentSync({
5862
6220
  updateFakeHighlightAbs,
5863
6221
  fakeHighlightAbsRef,
5864
6222
  hasFocusRef,
6223
+ isTextEditingRef,
5865
6224
  lastSelectionRef,
5866
6225
  recentSavesRef,
5867
- forceNextSyncRef
6226
+ forceNextSyncRef,
6227
+ transformTreeRef,
6228
+ autoResolveTokensRef
5868
6229
  }) {
5869
6230
  const [value, setValue] = (0, react_exports.useState)(initialValue);
5870
6231
  const lastEmittedHtmlRef = (0, react_exports.useRef)(richTextContent);
6232
+ const styleUpdateRafRef = (0, react_exports.useRef)(null);
5871
6233
  const emittedHistoryRef = (0, react_exports.useRef)([
5872
6234
  { html: richTextContent, selection: null, preSelection: null }
5873
6235
  ]);
@@ -5876,21 +6238,18 @@ function useContentSync({
5876
6238
  (0, react_exports.useEffect)(() => {
5877
6239
  const initialValueChanged = initialValue !== lastInitialValueRef.current;
5878
6240
  lastInitialValueRef.current = initialValue;
5879
- if (!initialValueChanged && richTextContent === lastEmittedHtmlRef.current) return;
5880
- const forceSync = consumeForceSync(forceNextSyncRef);
5881
- if (shouldSkipSync(
5882
- forceSync,
5883
- richTextContent,
5884
- lastEmittedHtmlRef.current,
5885
- recentSavesRef,
5886
- hasFocusRef
5887
- )) {
5888
- lastEmittedHtmlRef.current = richTextContent;
6241
+ const explicitForceSync = consumeForceSync(forceNextSyncRef);
6242
+ if (!explicitForceSync && !initialValueChanged && richTextContent === lastEmittedHtmlRef.current)
5889
6243
  return;
5890
- }
5891
6244
  const history = emittedHistoryRef.current;
5892
6245
  const incomingIdx = findHistoryIndex(history, richTextContent);
5893
6246
  const isExternalContentChange = richTextContent !== lastEmittedHtmlRef.current;
6247
+ const isHistoryRevert = isExternalContentChange && incomingIdx !== -1;
6248
+ const forceSync = explicitForceSync || isHistoryRevert;
6249
+ if (shouldSkipSync(forceSync, richTextContent, recentSavesRef, isTextEditingRef)) {
6250
+ lastEmittedHtmlRef.current = richTextContent;
6251
+ return;
6252
+ }
5894
6253
  const pendingMarks = isExternalContentChange ? null : editor.marks;
5895
6254
  lastEmittedHtmlRef.current = richTextContent;
5896
6255
  if (incomingIdx !== -1) {
@@ -5898,17 +6257,32 @@ function useContentSync({
5898
6257
  }
5899
6258
  const undoneEntry = incomingIdx !== -1 ? history[incomingIdx + 1] : null;
5900
6259
  const savedSelection = (undoneEntry == null ? void 0 : undoneEntry.preSelection) || (incomingIdx !== -1 ? history[incomingIdx].selection : null) || lastSelectionRef.current;
5901
- const treeToApply = forceSync && richTextContent ? htmlToSlate(richTextContent) : initialValue;
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
+ }
5902
6267
  setValue(treeToApply);
5903
6268
  editor.children = treeToApply;
5904
6269
  editor.selection = null;
5905
- if (isExternalContentChange || forceSync) {
5906
- safeRestoreSelection(editor, savedSelection);
5907
- }
6270
+ restoreSelectionAndHighlight({
6271
+ editor,
6272
+ savedSelection,
6273
+ forceSync,
6274
+ isExternalContentChange,
6275
+ fakeHighlightAbsRef,
6276
+ hasFocusRef,
6277
+ updateFakeHighlightAbs
6278
+ });
5908
6279
  if (pendingMarks) {
5909
6280
  editor.marks = pendingMarks;
5910
6281
  }
5911
6282
  }, [initialValue, richTextContent, editor, lastSelectionRef]);
6283
+ (0, react_exports.useEffect)(() => {
6284
+ return () => cancelPendingStyleUpdate(styleUpdateRafRef);
6285
+ }, []);
5912
6286
  const handleChange = (0, react_exports.useCallback)(
5913
6287
  (newValue) => {
5914
6288
  setValue(newValue);
@@ -5920,27 +6294,28 @@ function useContentSync({
5920
6294
  if (isContentChange) {
5921
6295
  const html = slateToHtml(newValue);
5922
6296
  if (html !== lastEmittedHtmlRef.current) {
5923
- const isTypingOnly = editor.operations.every(
5924
- (op) => op.type === "set_selection" || op.type === "insert_text" || op.type === "remove_text"
5925
- );
5926
- const pos = historyPosRef.current;
5927
- lastEmittedHtmlRef.current = html;
5928
- emittedHistoryRef.current = [
5929
- ...emittedHistoryRef.current.slice(0, pos + 1),
5930
- { html, selection: editor.selection, preSelection: prevSelection }
5931
- ];
5932
- historyPosRef.current = emittedHistoryRef.current.length - 1;
5933
- onContentChange(html, !isTypingOnly);
6297
+ emitContentChange({
6298
+ editor,
6299
+ html,
6300
+ prevSelection,
6301
+ lastEmittedHtmlRef,
6302
+ emittedHistoryRef,
6303
+ historyPosRef,
6304
+ onContentChange,
6305
+ autoResolveTokensRef
6306
+ });
5934
6307
  }
5935
6308
  }
5936
6309
  if (hasFocusRef.current || editor.selection) {
5937
- updateActiveStyles(isContentChange);
5938
- }
5939
- if (isContentChange && fakeHighlightAbsRef.current && hasFocusRef.current && editor.selection) {
5940
- if (slate_exports.Range.isCollapsed(editor.selection)) {
5941
- updateFakeHighlightAbs(null);
6310
+ if (isContentChange) {
6311
+ recomputeStylesForContentChange(styleUpdateRafRef, updateActiveStyles);
6312
+ } else {
6313
+ scheduleStylesForSelectionChange(editor, styleUpdateRafRef, updateActiveStyles);
5942
6314
  }
5943
6315
  }
6316
+ if (isContentChange && fakeHighlightAbsRef.current && hasFocusRef.current && editor.selection && slate_exports.Range.isCollapsed(editor.selection)) {
6317
+ updateFakeHighlightAbs(null);
6318
+ }
5944
6319
  },
5945
6320
  [
5946
6321
  editor,
@@ -5949,10 +6324,11 @@ function useContentSync({
5949
6324
  updateFakeHighlightAbs,
5950
6325
  fakeHighlightAbsRef,
5951
6326
  hasFocusRef,
5952
- lastSelectionRef
6327
+ lastSelectionRef,
6328
+ autoResolveTokensRef
5953
6329
  ]
5954
6330
  );
5955
- return { value, handleChange };
6331
+ return { value, handleChange, lastEmittedHtmlRef };
5956
6332
  }
5957
6333
 
5958
6334
  // src/RichText/PureRichText/hooks/useKeyboardShortcuts.ts
@@ -6486,7 +6862,11 @@ var InnerEditor = ({
6486
6862
  updateActiveStylesRef,
6487
6863
  clearFakeHighlightRef,
6488
6864
  recentSavesRef,
6489
- onAnnouncement
6865
+ forceNextSyncRef: forceNextSyncRefProp,
6866
+ transformTreeRef,
6867
+ autoResolveTokensRef,
6868
+ onAnnouncement,
6869
+ onCancelPendingChanges
6490
6870
  }) => {
6491
6871
  const {
6492
6872
  setEditor,
@@ -6536,7 +6916,8 @@ var InnerEditor = ({
6536
6916
  const lastSelectionRef = (0, react_exports.useRef)(null);
6537
6917
  useEditModeEffect(editor, editableRef, isEditMode);
6538
6918
  const hasFocusRef = (0, react_exports.useRef)(false);
6539
- const forceNextSyncRef = (0, react_exports.useRef)(false);
6919
+ const localForceNextSyncRef = (0, react_exports.useRef)(false);
6920
+ const forceNextSyncRef = forceNextSyncRefProp != null ? forceNextSyncRefProp : localForceNextSyncRef;
6540
6921
  const { fakeHighlightAbsRef, updateFakeHighlight, updateFakeHighlightAbs, decorate } = useFakeHighlight(editor);
6541
6922
  const highlightDismissedRef = (0, react_exports.useRef)(false);
6542
6923
  (0, react_exports.useEffect)(() => {
@@ -6556,9 +6937,12 @@ var InnerEditor = ({
6556
6937
  updateFakeHighlightAbs,
6557
6938
  fakeHighlightAbsRef,
6558
6939
  hasFocusRef,
6940
+ isTextEditingRef,
6559
6941
  lastSelectionRef,
6560
6942
  recentSavesRef,
6561
- forceNextSyncRef
6943
+ forceNextSyncRef,
6944
+ transformTreeRef,
6945
+ autoResolveTokensRef
6562
6946
  });
6563
6947
  const stepFontSize = useStepFontSize({
6564
6948
  editor,
@@ -6657,7 +7041,7 @@ var InnerEditor = ({
6657
7041
  }
6658
7042
  const mod = event.metaKey || event.ctrlKey;
6659
7043
  if (mod && event.key.toLowerCase() === "z") {
6660
- onFocusLost == null ? void 0 : onFocusLost();
7044
+ onCancelPendingChanges == null ? void 0 : onCancelPendingChanges();
6661
7045
  forceNextSyncRef.current = true;
6662
7046
  return true;
6663
7047
  }
@@ -6665,13 +7049,14 @@ var InnerEditor = ({
6665
7049
  return void 0;
6666
7050
  },
6667
7051
  [
6668
- editor,
6669
- editableRef,
7052
+ isTextEditingRef,
6670
7053
  handleKeyboardShortcuts,
6671
7054
  onDeactivateTextEditing,
6672
- onFocusLost,
7055
+ editor,
6673
7056
  onSavePreEditSelection,
6674
- wasTextEditingRef
7057
+ wasTextEditingRef,
7058
+ onCancelPendingChanges,
7059
+ forceNextSyncRef
6675
7060
  ]
6676
7061
  );
6677
7062
  const ElementRenderer = (0, react_exports.useMemo)(
@@ -6774,132 +7159,6 @@ function useRichTextState() {
6774
7159
  };
6775
7160
  }
6776
7161
 
6777
- // src/RichText/PureRichText/hooks/useTokenMap.ts
6778
- var TOKEN_PATTERN = /\$([a-zA-Z_]\w*)\$/g;
6779
- function getVizIdFromDom(containerRef) {
6780
- var _a, _b, _c;
6781
- const vizItem = (_a = containerRef.current) == null ? void 0 : _a.closest('[data-test="viz-item"]');
6782
- return (_c = (_b = vizItem == null ? void 0 : vizItem.dataset) == null ? void 0 : _b.id) != null ? _c : null;
6783
- }
6784
- function getRawContent(api, containerRef) {
6785
- var _a, _b, _c;
6786
- if (!(api == null ? void 0 : api.getDefinition)) return null;
6787
- const vizId = getVizIdFromDom(containerRef);
6788
- if (!vizId) return null;
6789
- try {
6790
- const def = api.getDefinition();
6791
- const rawContent = (_c = (_b = (_a = def == null ? void 0 : def.visualizations) == null ? void 0 : _a[vizId]) == null ? void 0 : _b.options) == null ? void 0 : _c.richTextContent;
6792
- return typeof rawContent === "string" ? rawContent : null;
6793
- } catch (e) {
6794
- return null;
6795
- }
6796
- }
6797
- function buildTokenMap(rawContent, resolvedContent) {
6798
- const map = /* @__PURE__ */ new Map();
6799
- const tokens = [];
6800
- let match;
6801
- const re = new RegExp(TOKEN_PATTERN.source, "g");
6802
- match = re.exec(rawContent);
6803
- while (match !== null) {
6804
- tokens.push(match[1]);
6805
- match = re.exec(rawContent);
6806
- }
6807
- if (tokens.length === 0) return map;
6808
- const escapedParts = rawContent.split(TOKEN_PATTERN);
6809
- let pattern = "";
6810
- for (let i = 0; i < escapedParts.length; i += 1) {
6811
- if (i % 2 === 0) {
6812
- pattern += escapedParts[i].replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6813
- } else {
6814
- pattern += "([\\s\\S]*?)";
6815
- }
6816
- }
6817
- const fullMatch = new RegExp(`^${pattern}$`).exec(resolvedContent);
6818
- if (!fullMatch) return map;
6819
- for (let i = 0; i < tokens.length; i += 1) {
6820
- const resolved = fullMatch[i + 1];
6821
- if (resolved !== void 0) {
6822
- map.set(resolved, `$${tokens[i]}$`);
6823
- }
6824
- }
6825
- return map;
6826
- }
6827
- function restoreTokens(html, tokenMap) {
6828
- if (tokenMap.size === 0) return html;
6829
- let result = html;
6830
- const entries = [...tokenMap.entries()].filter(([resolved]) => resolved !== "").sort((a, b) => b[0].length - a[0].length);
6831
- for (const [resolved, tokenPattern] of entries) {
6832
- result = result.split(resolved).join(tokenPattern);
6833
- }
6834
- return result;
6835
- }
6836
- function wrapTokensInTree(nodes, tokenMap) {
6837
- if (tokenMap.size === 0) return nodes;
6838
- const resolvedToName = /* @__PURE__ */ new Map();
6839
- for (const [resolved, pattern] of tokenMap) {
6840
- if (resolved === "") return nodes;
6841
- const name = pattern.slice(1, -1);
6842
- resolvedToName.set(resolved, name);
6843
- }
6844
- const processNode = (node) => {
6845
- if (slate_exports.Text.isText(node)) {
6846
- return splitTextByTokens(node, resolvedToName);
6847
- }
6848
- if (slate_exports.Element.isElement(node)) {
6849
- const el = node;
6850
- return [__spreadProps(__spreadValues({}, el), { children: el.children.flatMap(processNode) })];
6851
- }
6852
- return [node];
6853
- };
6854
- return nodes.flatMap(processNode);
6855
- }
6856
- function splitTextByTokens(textNode, resolvedToName) {
6857
- const _a = textNode, { text } = _a, marks = __objRest(_a, ["text"]);
6858
- if (!text) return [textNode];
6859
- const entries = [...resolvedToName.entries()].sort((a, b) => b[0].length - a[0].length);
6860
- let earliestIdx = -1;
6861
- let matchedResolved = "";
6862
- let matchedName = "";
6863
- for (const [resolved, name] of entries) {
6864
- const idx = text.indexOf(resolved);
6865
- if (idx !== -1 && (earliestIdx === -1 || idx < earliestIdx)) {
6866
- earliestIdx = idx;
6867
- matchedResolved = resolved;
6868
- matchedName = name;
6869
- }
6870
- }
6871
- if (earliestIdx === -1) return [textNode];
6872
- const result = [];
6873
- if (earliestIdx > 0) {
6874
- result.push(__spreadValues({ text: text.slice(0, earliestIdx) }, marks));
6875
- }
6876
- result.push(__spreadProps(__spreadValues({ text: matchedResolved }, marks), { tokenName: matchedName }));
6877
- const after = text.slice(earliestIdx + matchedResolved.length);
6878
- if (after) {
6879
- const afterNode = __spreadValues({ text: after }, marks);
6880
- result.push(...splitTextByTokens(afterNode, resolvedToName));
6881
- }
6882
- return result;
6883
- }
6884
- var EMPTY_MAP = /* @__PURE__ */ new Map();
6885
- function useTokenMap(dashboardCoreApi, containerRef, resolvedContent) {
6886
- const [tokenMap, setTokenMap] = (0, react_exports.useState)(EMPTY_MAP);
6887
- (0, react_exports.useEffect)(() => {
6888
- const raw = getRawContent(dashboardCoreApi, containerRef);
6889
- if (!raw) {
6890
- setTokenMap((prev) => prev.size === 0 ? prev : EMPTY_MAP);
6891
- return;
6892
- }
6893
- const map = buildTokenMap(raw, resolvedContent);
6894
- setTokenMap(map);
6895
- }, [dashboardCoreApi, resolvedContent, containerRef]);
6896
- const restoreTokensInHtml = (0, react_exports.useMemo)(() => {
6897
- if (tokenMap.size === 0) return (html) => html;
6898
- return (html) => restoreTokens(html, tokenMap);
6899
- }, [tokenMap]);
6900
- return { restoreTokensInHtml, tokenMap };
6901
- }
6902
-
6903
7162
  // src/RichText/PureRichText/hooks/useContentSave.ts
6904
7163
  var TYPING_IDLE_MS = 300;
6905
7164
  function useContentSave({
@@ -6969,7 +7228,14 @@ function useContentSave({
6969
7228
  pendingHtmlRef.current = null;
6970
7229
  }
6971
7230
  }, [save]);
6972
- return { handleContentChange, flushPendingChanges, recentSavesRef };
7231
+ const cancelPendingChanges = (0, react_exports.useCallback)(() => {
7232
+ if (idleTimerRef.current) {
7233
+ clearTimeout(idleTimerRef.current);
7234
+ idleTimerRef.current = null;
7235
+ }
7236
+ pendingHtmlRef.current = null;
7237
+ }, []);
7238
+ return { handleContentChange, flushPendingChanges, cancelPendingChanges, recentSavesRef };
6973
7239
  }
6974
7240
 
6975
7241
  // src/RichText/PureRichText/hooks/useDashboardKeyboardNav.ts
@@ -7081,7 +7347,12 @@ function useSidebarAndEditActivation({
7081
7347
  var _a, _b;
7082
7348
  return (_b = (_a = containerRef.current) == null ? void 0 : _a.closest('[data-test="viz-item"]')) != null ? _b : null;
7083
7349
  };
7084
- const isTargetInSidebar = (target, vizItem) => !(vizItem == null ? void 0 : vizItem.contains(target)) && Boolean(
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.
7355
+ !target.closest('[data-test="link-popover-content"]') && Boolean(
7085
7356
  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]")
7086
7357
  );
7087
7358
  const handleEscapeFromSidebar = (e) => {
@@ -7201,6 +7472,152 @@ function useIsActiveRichText(id) {
7201
7472
  () => getActiveRichTextId() === id
7202
7473
  );
7203
7474
  }
7475
+ var identityRestore = (html) => html;
7476
+ function resolveTokenDisplay(args) {
7477
+ const { isEditMode, previewTokenValues, resolvedContent, rawContent } = args;
7478
+ const showResolvedTokens = !isEditMode || previewTokenValues;
7479
+ const editorSourceContent = rawContent != null ? rawContent : resolvedContent;
7480
+ return { editorSourceContent, showResolvedTokens };
7481
+ }
7482
+ function resolveFontSize(defaultTextStyles, fontSize, customFontSize) {
7483
+ if (defaultTextStyles == null ? void 0 : defaultTextStyles.fontSize) {
7484
+ const dtsFs = defaultTextStyles.fontSize;
7485
+ if (typeof dtsFs === "string" && dtsFs.endsWith("px")) {
7486
+ return { effectiveFontSize: "custom", effectiveCustomFontSize: Number.parseInt(dtsFs, 10) };
7487
+ }
7488
+ }
7489
+ return { effectiveFontSize: fontSize, effectiveCustomFontSize: customFontSize };
7490
+ }
7491
+ function handleTokenToggle(args) {
7492
+ const { editor, richTextContent, recentSavesRef, cancelPendingChanges, forceNextSyncRef } = args;
7493
+ forceNextSyncRef.current = true;
7494
+ if (!editor) return { pendingSave: null, editorSourceOverride: null };
7495
+ const currentRawHtml = slateToHtml(editor.children);
7496
+ if (currentRawHtml !== richTextContent) {
7497
+ recentSavesRef.current.add(currentRawHtml);
7498
+ }
7499
+ cancelPendingChanges();
7500
+ return {
7501
+ pendingSave: currentRawHtml === richTextContent ? null : currentRawHtml,
7502
+ editorSourceOverride: currentRawHtml
7503
+ };
7504
+ }
7505
+ function resolvePoint(editor, absOffset, isStart = false) {
7506
+ const point = absOffsetToPoint(editor, absOffset, isStart);
7507
+ if (point) return point;
7508
+ try {
7509
+ return slate_exports.Editor.end(editor, []);
7510
+ } catch (e) {
7511
+ return null;
7512
+ }
7513
+ }
7514
+ function moveCaretPastTokenIfNeeded(editor) {
7515
+ if (!editor.selection || !slate_exports.Editor.isEditor(editor)) return;
7516
+ const { anchor, focus } = editor.selection;
7517
+ const isCollapsed = anchor.offset === focus.offset && anchor.path.join(",") === focus.path.join(",");
7518
+ if (!isCollapsed) return;
7519
+ try {
7520
+ const [node] = slate_exports.Editor.node(editor, anchor);
7521
+ const custom = node;
7522
+ if (!slate_exports.Text.isText(node) || !(custom.tokenName || custom.isEscapedDollar)) return;
7523
+ const endPoint = { path: anchor.path, offset: node.text.length };
7524
+ const blockPath = anchor.path.slice(0, -1);
7525
+ const afterToken = slate_exports.Editor.after(editor, endPoint);
7526
+ const staysInBlock = afterToken && afterToken.path.length > blockPath.length && afterToken.path.slice(0, blockPath.length).join(",") === blockPath.join(",");
7527
+ editor.selection = {
7528
+ anchor: staysInBlock ? afterToken : endPoint,
7529
+ focus: staysInBlock ? afterToken : endPoint
7530
+ };
7531
+ } catch (e) {
7532
+ }
7533
+ }
7534
+ function adjustAbsOffsetForResolution(absOffset, tokenResolvedLengths) {
7535
+ let adjustment = 0;
7536
+ for (const { absStart, rawLen, resolvedLen } of tokenResolvedLengths) {
7537
+ if (absOffset > absStart + rawLen - 1) {
7538
+ adjustment += resolvedLen - rawLen;
7539
+ } else if (absOffset > absStart) {
7540
+ adjustment += resolvedLen - rawLen;
7541
+ break;
7542
+ }
7543
+ }
7544
+ return absOffset + adjustment;
7545
+ }
7546
+ function displayForToken(tokenName, nameToValue) {
7547
+ const value = nameToValue.get(tokenName);
7548
+ return value !== void 0 && value !== "" ? value : `$${tokenName}$`;
7549
+ }
7550
+ function bareTokensInPlainText(text, baseOffset, nameToValue) {
7551
+ var _a;
7552
+ const result = [];
7553
+ const re = new RegExp(TOKEN_OR_ESCAPE_PATTERN.source, "g");
7554
+ let m = re.exec(text);
7555
+ while (m !== null) {
7556
+ const rawPattern = m[0];
7557
+ const tokenName = m[1];
7558
+ const resolvedValue = tokenName === void 0 ? "$" : (_a = nameToValue.get(tokenName)) != null ? _a : rawPattern;
7559
+ result.push({
7560
+ absStart: baseOffset + m.index,
7561
+ rawLen: rawPattern.length,
7562
+ resolvedLen: resolvedValue.length
7563
+ });
7564
+ m = re.exec(text);
7565
+ }
7566
+ return result;
7567
+ }
7568
+ function bareTokensInNode(node, runningOffset, nameToValue) {
7569
+ const { text } = node;
7570
+ if (node.tokenName) {
7571
+ if (!node.isRawToken) return [];
7572
+ const target = displayForToken(node.tokenName, nameToValue);
7573
+ return [{ absStart: runningOffset, rawLen: text.length, resolvedLen: target.length }];
7574
+ }
7575
+ if (node.isEscapedDollar) {
7576
+ return text === "$$" ? [{ absStart: runningOffset, rawLen: text.length, resolvedLen: 1 }] : [];
7577
+ }
7578
+ return bareTokensInPlainText(text, runningOffset, nameToValue);
7579
+ }
7580
+ function collectBareTokens(editor, nameToValue) {
7581
+ const result = [];
7582
+ let runningOffset = 0;
7583
+ for (const [textNode] of slate_exports.Editor.nodes(editor, { at: [], match: (n) => slate_exports.Text.isText(n) })) {
7584
+ result.push(...bareTokensInNode(textNode, runningOffset, nameToValue));
7585
+ runningOffset += textNode.text.length;
7586
+ }
7587
+ return result;
7588
+ }
7589
+ function buildAutoResolveCallback(args) {
7590
+ const { slateEditorRef, nameToValue } = args;
7591
+ return () => {
7592
+ const editor = slateEditorRef.current;
7593
+ if (!editor) return;
7594
+ const bareTokenInfo = collectBareTokens(editor, nameToValue);
7595
+ if (bareTokenInfo.length === 0) return;
7596
+ const rawAnchorAbs = editor.selection ? pointToAbsOffset(editor, editor.selection.anchor) : null;
7597
+ const rawFocusAbs = editor.selection ? pointToAbsOffset(editor, editor.selection.focus) : null;
7598
+ const newTree = wrapRawTokensInTree(editor.children, nameToValue);
7599
+ const anchorAbs = rawAnchorAbs === null ? null : adjustAbsOffsetForResolution(rawAnchorAbs, bareTokenInfo);
7600
+ const focusAbs = rawFocusAbs === null ? null : adjustAbsOffsetForResolution(rawFocusAbs, bareTokenInfo);
7601
+ editor.children = newTree;
7602
+ if (anchorAbs !== null && focusAbs !== null) {
7603
+ const collapsed = anchorAbs === focusAbs;
7604
+ const anchor = resolvePoint(editor, anchorAbs, !collapsed);
7605
+ const focus = resolvePoint(editor, focusAbs, false);
7606
+ editor.selection = anchor && focus ? { anchor, focus } : null;
7607
+ } else {
7608
+ editor.selection = null;
7609
+ }
7610
+ moveCaretPastTokenIfNeeded(editor);
7611
+ const selectionAfterResolve = editor.selection;
7612
+ editor.onChange();
7613
+ if (selectionAfterResolve) {
7614
+ try {
7615
+ slate_exports.Transforms.select(editor, selectionAfterResolve);
7616
+ } catch (e) {
7617
+ }
7618
+ }
7619
+ };
7620
+ }
7204
7621
  var PureRichText = react_exports.forwardRef((props, ref) => {
7205
7622
  var _a, _b, _c, _d;
7206
7623
  const theme = (0, themes_exports.useSplunkTheme)();
@@ -7225,7 +7642,9 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7225
7642
  italic = false,
7226
7643
  underline = false,
7227
7644
  strikethrough = false,
7228
- defaultTextStyles
7645
+ defaultTextStyles,
7646
+ previewTokenValues = false,
7647
+ richTextTokenMetadata: richTextTokenMetadataProp
7229
7648
  } = props;
7230
7649
  const effectiveFontColorFromStyles = (defaultTextStyles == null ? void 0 : defaultTextStyles.color) || fontColor;
7231
7650
  const effectiveHighlightColor = (defaultTextStyles == null ? void 0 : defaultTextStyles.backgroundColor) || highlightColor;
@@ -7234,21 +7653,19 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7234
7653
  const effectiveItalic = (_b = defaultTextStyles == null ? void 0 : defaultTextStyles.italic) != null ? _b : italic;
7235
7654
  const effectiveUnderline = (_c = defaultTextStyles == null ? void 0 : defaultTextStyles.underline) != null ? _c : underline;
7236
7655
  const effectiveStrikethrough = (_d = defaultTextStyles == null ? void 0 : defaultTextStyles.strikethrough) != null ? _d : strikethrough;
7237
- let effectiveFontSize = fontSize;
7238
- let effectiveCustomFontSize = customFontSize;
7239
- if (defaultTextStyles == null ? void 0 : defaultTextStyles.fontSize) {
7240
- const dtsFs = defaultTextStyles.fontSize;
7241
- if (typeof dtsFs === "string" && dtsFs.endsWith("px")) {
7242
- effectiveCustomFontSize = parseInt(dtsFs, 10);
7243
- effectiveFontSize = "custom";
7244
- }
7245
- }
7656
+ const { effectiveFontSize, effectiveCustomFontSize } = resolveFontSize(
7657
+ defaultTextStyles,
7658
+ fontSize,
7659
+ customFontSize
7660
+ );
7246
7661
  const effectiveFontColor = effectiveFontColorFromStyles || themeTextColor;
7247
7662
  const isEditMode = mode === "edit";
7248
7663
  const containerRef = (0, react_exports.useRef)(null);
7249
7664
  const slateEditorRef = (0, react_exports.useRef)(null);
7250
7665
  const updateActiveStylesFnRef = (0, react_exports.useRef)(null);
7251
7666
  const clearFakeHighlightRef = (0, react_exports.useRef)(null);
7667
+ const forceNextSyncRef = (0, react_exports.useRef)(false);
7668
+ const transformTreeRef = (0, react_exports.useRef)(null);
7252
7669
  const setContainerRef = (0, react_exports.useCallback)(
7253
7670
  (node) => {
7254
7671
  containerRef.current = node;
@@ -7334,26 +7751,71 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7334
7751
  const borderStyle = borderConfig.style || "solid";
7335
7752
  const borderRadius = borderConfig.radius || 0;
7336
7753
  const paddingValues = parsePadding(padding);
7337
- const { restoreTokensInHtml, tokenMap } = useTokenMap(dashboardCoreApi, containerRef, richTextContent);
7338
- const { handleContentChange, flushPendingChanges, recentSavesRef } = useContentSave({
7339
- richTextContent,
7340
- onOptionsChange,
7341
- restoreTokensInHtml
7754
+ const { nameToValue, rawContent } = useTokenMap(richTextContent, richTextTokenMetadataProp);
7755
+ const { editorSourceContent, showResolvedTokens } = resolveTokenDisplay({
7756
+ isEditMode,
7757
+ previewTokenValues,
7758
+ resolvedContent: richTextContent,
7759
+ rawContent
7342
7760
  });
7761
+ const { handleContentChange, flushPendingChanges, cancelPendingChanges, recentSavesRef } = useContentSave(
7762
+ {
7763
+ richTextContent: editorSourceContent,
7764
+ onOptionsChange,
7765
+ restoreTokensInHtml: identityRestore
7766
+ }
7767
+ );
7768
+ const prevShowResolvedRef = (0, react_exports.useRef)(showResolvedTokens);
7769
+ const pendingToggleSaveRef = (0, react_exports.useRef)(null);
7770
+ let editorSourceOverride = null;
7771
+ if (prevShowResolvedRef.current !== showResolvedTokens) {
7772
+ prevShowResolvedRef.current = showResolvedTokens;
7773
+ const result = handleTokenToggle({
7774
+ editor: slateEditorRef.current,
7775
+ richTextContent,
7776
+ recentSavesRef,
7777
+ cancelPendingChanges,
7778
+ forceNextSyncRef
7779
+ });
7780
+ pendingToggleSaveRef.current = result.pendingSave;
7781
+ editorSourceOverride = result.editorSourceOverride;
7782
+ }
7783
+ (0, react_exports.useEffect)(() => {
7784
+ const html = pendingToggleSaveRef.current;
7785
+ pendingToggleSaveRef.current = null;
7786
+ if (html !== null) {
7787
+ onOptionsChange == null ? void 0 : onOptionsChange({ richTextContent: html });
7788
+ }
7789
+ }, [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;
7793
+ const prevNameToValueRef = (0, react_exports.useRef)(nameToValue);
7794
+ (0, react_exports.useEffect)(() => {
7795
+ const prev = prevNameToValueRef.current;
7796
+ prevNameToValueRef.current = nameToValue;
7797
+ if (nameToValue.size > 0 && nameToValue !== prev && autoResolveTokensRef.current) {
7798
+ autoResolveTokensRef.current();
7799
+ }
7800
+ }, [nameToValue]);
7801
+ const effectiveEditorSourceContent = editorSourceOverride != null ? editorSourceOverride : editorSourceContent;
7343
7802
  const initialValueRef = (0, react_exports.useRef)(EMPTY_SLATE_VALUE);
7803
+ const initialValueModeRef = (0, react_exports.useRef)(showResolvedTokens);
7344
7804
  const initialValue = (0, react_exports.useMemo)(() => {
7345
- if (recentSavesRef.current.has(richTextContent) || isTextEditingRef.current) {
7805
+ const modeChanged = initialValueModeRef.current !== showResolvedTokens;
7806
+ initialValueModeRef.current = showResolvedTokens;
7807
+ if (!modeChanged && (recentSavesRef.current.has(effectiveEditorSourceContent) || isTextEditingRef.current)) {
7346
7808
  return initialValueRef.current;
7347
7809
  }
7348
- if (!richTextContent) {
7810
+ if (!effectiveEditorSourceContent) {
7349
7811
  initialValueRef.current = EMPTY_SLATE_VALUE;
7350
7812
  return EMPTY_SLATE_VALUE;
7351
7813
  }
7352
- const tree = htmlToSlate(richTextContent);
7353
- const result = wrapTokensInTree(tree, tokenMap);
7814
+ const tree = htmlToSlate(effectiveEditorSourceContent);
7815
+ const result = wrapRawTokensInTree(tree, showResolvedTokens ? nameToValue : void 0);
7354
7816
  initialValueRef.current = result;
7355
7817
  return result;
7356
- }, [richTextContent, tokenMap]);
7818
+ }, [effectiveEditorSourceContent, nameToValue, showResolvedTokens]);
7357
7819
  const handleFocusGained = (0, react_exports.useCallback)(
7358
7820
  (editable, slateEditor) => {
7359
7821
  registerActiveRichText(instanceId, editable, slateEditor);
@@ -7467,7 +7929,7 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7467
7929
  safeSelectEnd(slateEditor);
7468
7930
  }
7469
7931
  },
7470
- [hasEventHandlers, isEditMode, isTextEditing, onRichtextClick]
7932
+ [activateTextEditing, hasEventHandlers, instanceId, isEditMode, isTextEditing, onRichtextClick]
7471
7933
  );
7472
7934
  return /* @__PURE__ */ react_exports.createElement(
7473
7935
  PureRichTextProvider,
@@ -7530,7 +7992,7 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7530
7992
  InnerEditor,
7531
7993
  {
7532
7994
  initialValue,
7533
- richTextContent,
7995
+ richTextContent: effectiveEditorSourceContent,
7534
7996
  isEditMode,
7535
7997
  isTextEditing,
7536
7998
  containerRef,
@@ -7538,6 +8000,7 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7538
8000
  onContentChange: handleContentChange,
7539
8001
  onFocusGained: handleFocusGained,
7540
8002
  onFocusLost: handleFocusLost,
8003
+ onCancelPendingChanges: cancelPendingChanges,
7541
8004
  richTextState,
7542
8005
  onEditorReady: (ed) => {
7543
8006
  slateEditorRef.current = ed;
@@ -7545,6 +8008,9 @@ var PureRichText = react_exports.forwardRef((props, ref) => {
7545
8008
  updateActiveStylesRef: updateActiveStylesFnRef,
7546
8009
  clearFakeHighlightRef,
7547
8010
  recentSavesRef,
8011
+ forceNextSyncRef,
8012
+ transformTreeRef,
8013
+ autoResolveTokensRef,
7548
8014
  onAnnouncement: handleAnnouncement
7549
8015
  }
7550
8016
  )
@@ -7610,7 +8076,7 @@ function buildDefaultTextStyles(pickedOptions, options) {
7610
8076
  if (pickedOptions.strikethrough) styles.strikethrough = true;
7611
8077
  return styles;
7612
8078
  }
7613
- function resolveFontSize(defaultTextStyles, pickedOptions) {
8079
+ function resolveFontSize2(defaultTextStyles, pickedOptions) {
7614
8080
  let fontSize = defaultTextStyles.fontSize || pickedOptions.fontSize;
7615
8081
  let customFontSize = defaultTextStyles.customFontSize || pickedOptions.customFontSize;
7616
8082
  if (typeof fontSize === "string" && fontSize.endsWith("px")) {
@@ -7625,16 +8091,17 @@ var computeVizProps = ({
7625
8091
  onRichtextClick,
7626
8092
  onOptionsChange,
7627
8093
  richTextContent: richTextContentProp,
7628
- hasEventHandlers = false
8094
+ hasEventHandlers = false,
8095
+ richTextTokenMetadata
7629
8096
  }) => {
7630
- var _a, _b, _c, _d, _e, _f, _g, _h;
8097
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
7631
8098
  const pickedOptions = pickValidOptions(options);
7632
8099
  const border = buildBorderConfig(pickedOptions, options);
7633
8100
  const defaultTextStyles = buildDefaultTextStyles(pickedOptions, options);
7634
8101
  const fontColor = defaultTextStyles.color || pickedOptions.fontColor;
7635
8102
  const highlightColor = defaultTextStyles.highlightColor || defaultTextStyles.backgroundColor || pickedOptions.highlightColor;
7636
8103
  const fontFamily = defaultTextStyles.fontFamily || pickedOptions.fontFamily;
7637
- const { fontSize, customFontSize } = resolveFontSize(defaultTextStyles, pickedOptions);
8104
+ const { fontSize, customFontSize } = resolveFontSize2(defaultTextStyles, pickedOptions);
7638
8105
  const bold = (_b = (_a = defaultTextStyles.bold) != null ? _a : pickedOptions.bold) != null ? _b : false;
7639
8106
  const italic = (_d = (_c = defaultTextStyles.italic) != null ? _c : pickedOptions.italic) != null ? _d : false;
7640
8107
  const underline = (_f = (_e = defaultTextStyles.underline) != null ? _e : pickedOptions.underline) != null ? _f : false;
@@ -7659,7 +8126,9 @@ var computeVizProps = ({
7659
8126
  italic,
7660
8127
  underline,
7661
8128
  strikethrough,
7662
- hasEventHandlers
8129
+ hasEventHandlers,
8130
+ previewTokenValues: (_i = pickedOptions.previewTokenValues) != null ? _i : false,
8131
+ richTextTokenMetadata
7663
8132
  };
7664
8133
  };
7665
8134
  var RichText = withDashboardViz_default({
@@ -7668,6 +8137,7 @@ var RichText = withDashboardViz_default({
7668
8137
  vizConfig: config_default,
7669
8138
  disableEditModeCover: true
7670
8139
  });
8140
+ RichText.tokenMetadataProp = "richTextTokenMetadata";
7671
8141
  var { themes: themes2 } = config_default;
7672
8142
  var config2 = config_default;
7673
8143
  var RichText_default3 = RichText;