@glyphjs/components 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -75,7 +75,7 @@ function Callout({ data }) {
75
75
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "note", "aria-label": CALLOUT_LABELS[type], style: containerStyle11, children: [
76
76
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: iconStyle, "aria-hidden": "true", children: CALLOUT_ICONS[type] }),
77
77
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: bodyStyle3, children: [
78
- title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: titleStyle2, children: title }),
78
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: titleStyle2, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: title }) }),
79
79
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content }) })
80
80
  ] })
81
81
  ] });
@@ -87,6 +87,34 @@ var calloutDefinition = {
87
87
  schema: schemas.calloutSchema,
88
88
  render: Callout
89
89
  };
90
+
91
+ // src/utils/inlineToText.ts
92
+ function inlineToText(content) {
93
+ if (typeof content === "string") {
94
+ return content;
95
+ }
96
+ return content.map((node) => {
97
+ switch (node.type) {
98
+ case "text":
99
+ return node.value;
100
+ case "strong":
101
+ case "emphasis":
102
+ case "delete":
103
+ case "link":
104
+ return inlineToText(node.children);
105
+ case "inlineCode":
106
+ return node.value;
107
+ case "image":
108
+ return node.alt ?? "";
109
+ case "break":
110
+ return "\n";
111
+ default:
112
+ return "";
113
+ }
114
+ }).join("");
115
+ }
116
+
117
+ // src/chart/render.ts
90
118
  var DEFAULT_WIDTH = 600;
91
119
  var DEFAULT_HEIGHT = 400;
92
120
  var MARGIN = { top: 20, right: 30, bottom: 50, left: 60 };
@@ -134,7 +162,7 @@ function renderAxes(g, xScale, yScale, xAxisConfig, yAxisConfig, innerWidth, inn
134
162
  }
135
163
  xAxisG.selectAll("text, line, path").attr("fill", "var(--glyph-text, #1a2035)").attr("stroke", "var(--glyph-grid, #1a2035)");
136
164
  if (xAxisConfig?.label) {
137
- g.append("text").attr("class", "x-label").attr("x", innerWidth / 2).attr("y", innerHeight + MARGIN.bottom - 6).attr("text-anchor", "middle").attr("fill", "var(--glyph-text, #1a2035)").attr("font-size", "12px").text(xAxisConfig.label);
165
+ g.append("text").attr("class", "x-label").attr("x", innerWidth / 2).attr("y", innerHeight + MARGIN.bottom - 6).attr("text-anchor", "middle").attr("fill", "var(--glyph-text, #1a2035)").attr("font-size", "12px").text(inlineToText(xAxisConfig.label));
138
166
  }
139
167
  const yAxisG = g.append("g").attr("class", "y-axis");
140
168
  yAxisG.call(
@@ -142,7 +170,7 @@ function renderAxes(g, xScale, yScale, xAxisConfig, yAxisConfig, innerWidth, inn
142
170
  );
143
171
  yAxisG.selectAll("text, line, path").attr("fill", "var(--glyph-text, #1a2035)").attr("stroke", "var(--glyph-grid, #1a2035)");
144
172
  if (yAxisConfig?.label) {
145
- g.append("text").attr("class", "y-label").attr("transform", "rotate(-90)").attr("x", -innerHeight / 2).attr("y", -MARGIN.left + 14).attr("text-anchor", "middle").attr("fill", "var(--glyph-text, #1a2035)").attr("font-size", "12px").text(yAxisConfig.label);
173
+ g.append("text").attr("class", "y-label").attr("transform", "rotate(-90)").attr("x", -innerHeight / 2).attr("y", -MARGIN.left + 14).attr("text-anchor", "middle").attr("fill", "var(--glyph-text, #1a2035)").attr("font-size", "12px").text(inlineToText(yAxisConfig.label));
146
174
  }
147
175
  }
148
176
  function renderGridLines(g, yScale, innerWidth) {
@@ -198,7 +226,7 @@ function renderLegend(sel, series, marginLeft, marginTop, fontSize = "12px") {
198
226
  const color3 = COLOR_SCHEME[i % COLOR_SCHEME.length] ?? "var(--glyph-text, #1a2035)";
199
227
  const row = legendG.append("g").attr("transform", `translate(0,${String(i * 20)})`);
200
228
  row.append("rect").attr("width", 14).attr("height", 14).attr("fill", color3).attr("rx", 2);
201
- row.append("text").attr("x", 20).attr("y", 11).attr("fill", "var(--glyph-text, #1a2035)").attr("font-size", fontSize).text(s.name);
229
+ row.append("text").attr("x", 20).attr("y", 11).attr("fill", "var(--glyph-text, #1a2035)").attr("font-size", fontSize).text(inlineToText(s.name));
202
230
  });
203
231
  }
204
232
  function ChartAccessibleTable({
@@ -229,10 +257,10 @@ function ChartAccessibleTable({
229
257
  " chart data"
230
258
  ] }),
231
259
  series.map((s, si) => /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
232
- /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("th", { colSpan: 2, children: s.name }) }),
260
+ /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("th", { colSpan: 2, children: inlineToText(s.name) }) }),
233
261
  /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
234
- /* @__PURE__ */ jsxRuntime.jsx("th", { children: xLabel ?? xKey }),
235
- /* @__PURE__ */ jsxRuntime.jsx("th", { children: yLabel ?? yKey })
262
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: xLabel ? inlineToText(xLabel) : xKey }),
263
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: yLabel ? inlineToText(yLabel) : yKey })
236
264
  ] }),
237
265
  s.data.map((d, di) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
238
266
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: String(d[xKey] ?? "") }),
@@ -283,6 +311,7 @@ function renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideT
283
311
  const { xScale, xScalePoint, yScale, innerHeight } = scales;
284
312
  series.forEach((s, i) => {
285
313
  const color3 = COLOR_SCHEME[i % COLOR_SCHEME.length] ?? "#333";
314
+ const seriesName = inlineToText(s.name);
286
315
  switch (type) {
287
316
  case "line":
288
317
  renderLineSeries(
@@ -294,7 +323,7 @@ function renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideT
294
323
  xKey,
295
324
  color3,
296
325
  i,
297
- s.name,
326
+ seriesName,
298
327
  showTooltip,
299
328
  hideTooltip
300
329
  );
@@ -310,7 +339,7 @@ function renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideT
310
339
  innerHeight,
311
340
  color3,
312
341
  i,
313
- s.name,
342
+ seriesName,
314
343
  showTooltip,
315
344
  hideTooltip
316
345
  );
@@ -327,7 +356,7 @@ function renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideT
327
356
  i,
328
357
  series.length,
329
358
  innerHeight,
330
- s.name,
359
+ seriesName,
331
360
  showTooltip,
332
361
  hideTooltip
333
362
  );
@@ -340,7 +369,7 @@ function renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideT
340
369
  xScalePoint,
341
370
  yScale,
342
371
  scales.innerWidth,
343
- s.name,
372
+ seriesName,
344
373
  showTooltip,
345
374
  hideTooltip
346
375
  );
@@ -720,7 +749,7 @@ function TableHead({
720
749
  whiteSpace: "nowrap"
721
750
  },
722
751
  children: [
723
- col.label,
752
+ /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: col.label }),
724
753
  col.sortable ? sortIndicator(direction) : ""
725
754
  ]
726
755
  },
@@ -1046,7 +1075,7 @@ function Tabs({ data, block, onInteraction }) {
1046
1075
  outline: "revert",
1047
1076
  outlineOffset: "2px"
1048
1077
  },
1049
- children: tab.label
1078
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: tab.label })
1050
1079
  },
1051
1080
  tabId
1052
1081
  );
@@ -1072,7 +1101,7 @@ function Tabs({ data, block, onInteraction }) {
1072
1101
  color: "var(--glyph-heading, #0a0e1a)",
1073
1102
  lineHeight: 1.6
1074
1103
  },
1075
- children: tab.content
1104
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: tab.content })
1076
1105
  },
1077
1106
  panelId
1078
1107
  );
@@ -1323,6 +1352,92 @@ var timelineDefinition = {
1323
1352
  schema: schemas.timelineSchema,
1324
1353
  render: Timeline
1325
1354
  };
1355
+
1356
+ // src/utils/measureText.ts
1357
+ var measurementCache = /* @__PURE__ */ new WeakMap();
1358
+ function measurePlainText(text, style) {
1359
+ const canvas = document.createElement("canvas");
1360
+ const ctx = canvas.getContext("2d");
1361
+ if (!ctx) {
1362
+ const avgCharWidth = parseInt(style.fontSize) * 0.6;
1363
+ return {
1364
+ width: text.length * avgCharWidth,
1365
+ height: parseInt(style.fontSize) * 1.2
1366
+ };
1367
+ }
1368
+ const fontWeight = style.fontWeight ?? "normal";
1369
+ ctx.font = `${fontWeight} ${style.fontSize} ${style.fontFamily}`;
1370
+ const metrics = ctx.measureText(text);
1371
+ const width = metrics.width;
1372
+ const height = parseInt(style.fontSize) * 1.2;
1373
+ return { width, height };
1374
+ }
1375
+ function measureHtmlText(content, style) {
1376
+ const cached = measurementCache.get(content);
1377
+ if (cached) {
1378
+ return cached;
1379
+ }
1380
+ const container = document.createElement("div");
1381
+ container.style.position = "absolute";
1382
+ container.style.visibility = "hidden";
1383
+ container.style.left = "-9999px";
1384
+ container.style.top = "-9999px";
1385
+ container.style.fontSize = style.fontSize;
1386
+ container.style.fontFamily = style.fontFamily;
1387
+ container.style.fontWeight = style.fontWeight ?? "normal";
1388
+ container.style.whiteSpace = "pre-wrap";
1389
+ container.style.wordBreak = "break-word";
1390
+ if (style.maxWidth) {
1391
+ container.style.maxWidth = `${style.maxWidth}px`;
1392
+ }
1393
+ container.innerHTML = inlineNodesToHtml(content);
1394
+ document.body.appendChild(container);
1395
+ const rect = container.getBoundingClientRect();
1396
+ const dimensions = {
1397
+ width: Math.ceil(rect.width),
1398
+ height: Math.ceil(rect.height)
1399
+ };
1400
+ document.body.removeChild(container);
1401
+ measurementCache.set(content, dimensions);
1402
+ return dimensions;
1403
+ }
1404
+ function inlineNodesToHtml(nodes) {
1405
+ return nodes.map((node) => {
1406
+ switch (node.type) {
1407
+ case "text":
1408
+ return escapeHtml(node.value);
1409
+ case "strong":
1410
+ return `<strong>${inlineNodesToHtml(node.children)}</strong>`;
1411
+ case "emphasis":
1412
+ return `<em>${inlineNodesToHtml(node.children)}</em>`;
1413
+ case "delete":
1414
+ return `<del>${inlineNodesToHtml(node.children)}</del>`;
1415
+ case "inlineCode":
1416
+ return `<code>${escapeHtml(node.value)}</code>`;
1417
+ case "link":
1418
+ return `<a href="${escapeHtml(node.url)}">${inlineNodesToHtml(node.children)}</a>`;
1419
+ case "image":
1420
+ return `<img src="${escapeHtml(node.src)}" alt="${escapeHtml(node.alt ?? "")}" />`;
1421
+ case "break":
1422
+ return "<br />";
1423
+ default:
1424
+ return "";
1425
+ }
1426
+ }).join("");
1427
+ }
1428
+ function escapeHtml(str) {
1429
+ const div = document.createElement("div");
1430
+ div.textContent = str;
1431
+ return div.innerHTML;
1432
+ }
1433
+ function measureText(content, style) {
1434
+ if (typeof content === "string") {
1435
+ return measurePlainText(content, style);
1436
+ }
1437
+ return measureHtmlText(content, style);
1438
+ }
1439
+
1440
+ // src/graph/layout.ts
1326
1441
  var RANKDIR_MAP = {
1327
1442
  "top-down": "TB",
1328
1443
  "left-right": "LR",
@@ -1345,10 +1460,17 @@ function computeDagreLayout(nodes, edges, direction = "top-down") {
1345
1460
  });
1346
1461
  g.setDefaultEdgeLabel(() => ({}));
1347
1462
  for (const node of nodes) {
1463
+ const labelDimensions = measureText(node.label, {
1464
+ fontSize: "13px",
1465
+ fontFamily: "Inter, system-ui, sans-serif",
1466
+ maxWidth: 200
1467
+ });
1468
+ const nodeWidth = Math.max(120, Math.min(250, labelDimensions.width + 40));
1469
+ const nodeHeight = Math.max(40, labelDimensions.height + 20);
1348
1470
  g.setNode(node.id, {
1349
1471
  label: node.label,
1350
- width: DEFAULT_NODE_WIDTH,
1351
- height: DEFAULT_NODE_HEIGHT
1472
+ width: nodeWidth,
1473
+ height: nodeHeight
1352
1474
  });
1353
1475
  }
1354
1476
  for (const edge of edges) {
@@ -1455,6 +1577,326 @@ function computeForceLayout(nodes, edges) {
1455
1577
  height: maxY + LAYOUT_PADDING
1456
1578
  };
1457
1579
  }
1580
+ function useZoomInteraction({
1581
+ svgRef,
1582
+ rootRef,
1583
+ interactionMode
1584
+ }) {
1585
+ const [isActive, setIsActive] = react.useState(interactionMode === "always");
1586
+ const [hasAttemptedScroll, setHasAttemptedScroll] = react.useState(false);
1587
+ const containerRef = react.useRef(null);
1588
+ react.useEffect(() => {
1589
+ setIsActive(interactionMode === "always");
1590
+ setHasAttemptedScroll(false);
1591
+ }, [interactionMode]);
1592
+ const filterFunction = react.useCallback(
1593
+ (event) => {
1594
+ if (interactionMode === "always") {
1595
+ return true;
1596
+ }
1597
+ if (interactionMode === "modifier-key") {
1598
+ if (event.type === "mousedown") return true;
1599
+ if (event.type === "wheel") {
1600
+ const wheelEvent = event;
1601
+ const hasModifier = wheelEvent.altKey;
1602
+ if (!hasModifier && !hasAttemptedScroll) {
1603
+ setHasAttemptedScroll(true);
1604
+ setTimeout(() => setHasAttemptedScroll(false), 3e3);
1605
+ }
1606
+ return hasModifier;
1607
+ }
1608
+ return true;
1609
+ }
1610
+ if (interactionMode === "click-to-activate") {
1611
+ return isActive;
1612
+ }
1613
+ return true;
1614
+ },
1615
+ [interactionMode, isActive, hasAttemptedScroll]
1616
+ );
1617
+ react.useEffect(() => {
1618
+ if (interactionMode !== "modifier-key" || !svgRef.current) return;
1619
+ const svg = svgRef.current;
1620
+ const container = svg.parentElement;
1621
+ if (!container) return;
1622
+ const handleWheel = (event) => {
1623
+ const target = event.target;
1624
+ if (event.altKey && svg.contains(target)) {
1625
+ event.preventDefault();
1626
+ event.stopPropagation();
1627
+ }
1628
+ };
1629
+ container.addEventListener("wheel", handleWheel, { passive: false, capture: true });
1630
+ return () => {
1631
+ container.removeEventListener("wheel", handleWheel, { capture: true });
1632
+ };
1633
+ }, [interactionMode, svgRef]);
1634
+ const zoomBehavior = react.useMemo(() => {
1635
+ const zoom3 = d32__namespace.zoom().scaleExtent([0.1, 4]);
1636
+ if (typeof zoom3.filter === "function") {
1637
+ zoom3.filter(filterFunction);
1638
+ }
1639
+ zoom3.on("zoom", (event) => {
1640
+ if (rootRef.current) {
1641
+ d32__namespace.select(rootRef.current).attr("transform", event.transform.toString());
1642
+ }
1643
+ });
1644
+ return zoom3;
1645
+ }, [filterFunction, rootRef]);
1646
+ const handleActivate = react.useCallback(() => {
1647
+ if (interactionMode === "click-to-activate") {
1648
+ setIsActive(true);
1649
+ }
1650
+ }, [interactionMode]);
1651
+ react.useEffect(() => {
1652
+ if (interactionMode !== "click-to-activate" || !isActive) return;
1653
+ const handleKeyDown = (e) => {
1654
+ if (e.key === "Escape") {
1655
+ setIsActive(false);
1656
+ }
1657
+ };
1658
+ document.addEventListener("keydown", handleKeyDown);
1659
+ return () => document.removeEventListener("keydown", handleKeyDown);
1660
+ }, [interactionMode, isActive]);
1661
+ react.useEffect(() => {
1662
+ if (interactionMode !== "click-to-activate" || !isActive) return;
1663
+ const handleClickOutside = (e) => {
1664
+ const container = svgRef.current?.parentElement;
1665
+ if (container && !container.contains(e.target)) {
1666
+ setIsActive(false);
1667
+ }
1668
+ };
1669
+ document.addEventListener("click", handleClickOutside, true);
1670
+ return () => document.removeEventListener("click", handleClickOutside, true);
1671
+ }, [interactionMode, isActive, svgRef]);
1672
+ react.useEffect(() => {
1673
+ if (svgRef.current) {
1674
+ containerRef.current = svgRef.current.parentElement;
1675
+ }
1676
+ }, [svgRef]);
1677
+ const overlayProps = react.useMemo(() => {
1678
+ if (interactionMode === "always") return null;
1679
+ if (interactionMode === "modifier-key" && !hasAttemptedScroll) return null;
1680
+ if (interactionMode === "click-to-activate" && isActive) return null;
1681
+ return {
1682
+ mode: interactionMode,
1683
+ isActive,
1684
+ onActivate: handleActivate,
1685
+ width: "100%",
1686
+ height: "100%"
1687
+ };
1688
+ }, [interactionMode, isActive, hasAttemptedScroll, handleActivate]);
1689
+ const zoomIn = react.useCallback(() => {
1690
+ if (!svgRef.current) return;
1691
+ d32__namespace.select(svgRef.current).transition().duration(300).call(zoomBehavior.scaleBy, 1.3);
1692
+ }, [svgRef, zoomBehavior]);
1693
+ const zoomOut = react.useCallback(() => {
1694
+ if (!svgRef.current) return;
1695
+ d32__namespace.select(svgRef.current).transition().duration(300).call(zoomBehavior.scaleBy, 1 / 1.3);
1696
+ }, [svgRef, zoomBehavior]);
1697
+ const resetZoom = react.useCallback(() => {
1698
+ if (!svgRef.current) return;
1699
+ d32__namespace.select(svgRef.current).transition().duration(300).call(zoomBehavior.transform, d32__namespace.zoomIdentity);
1700
+ }, [svgRef, zoomBehavior]);
1701
+ return {
1702
+ isActive,
1703
+ overlayProps,
1704
+ zoomBehavior,
1705
+ zoomIn,
1706
+ zoomOut,
1707
+ resetZoom
1708
+ };
1709
+ }
1710
+ function InteractionOverlay({
1711
+ mode,
1712
+ isActive,
1713
+ onActivate,
1714
+ width,
1715
+ height
1716
+ }) {
1717
+ if (mode === "modifier-key") {
1718
+ return /* @__PURE__ */ jsxRuntime.jsx(
1719
+ "div",
1720
+ {
1721
+ className: "glyph-interaction-overlay",
1722
+ style: {
1723
+ ...OVERLAY_BASE_STYLE,
1724
+ width,
1725
+ height,
1726
+ pointerEvents: "none"
1727
+ },
1728
+ "aria-hidden": "true",
1729
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: TOOLTIP_STYLE, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: TOOLTIP_TEXT_STYLE, children: "Alt + scroll to zoom" }) })
1730
+ }
1731
+ );
1732
+ }
1733
+ if (mode === "click-to-activate" && !isActive) {
1734
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1735
+ /* @__PURE__ */ jsxRuntime.jsx(
1736
+ "div",
1737
+ {
1738
+ className: "glyph-interaction-overlay",
1739
+ style: {
1740
+ ...OVERLAY_BASE_STYLE,
1741
+ ...ACTIVATION_OVERLAY_STYLE,
1742
+ width,
1743
+ height
1744
+ },
1745
+ onClick: onActivate,
1746
+ role: "button",
1747
+ tabIndex: 0,
1748
+ "aria-label": "Click to activate graph interaction",
1749
+ onKeyDown: (e) => {
1750
+ if (e.key === "Enter" || e.key === " ") {
1751
+ e.preventDefault();
1752
+ onActivate();
1753
+ }
1754
+ },
1755
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: ACTIVATION_TEXT_STYLE, children: "Click to interact" })
1756
+ }
1757
+ ),
1758
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: SR_ONLY_STYLE, role: "status", "aria-live": "polite", "aria-atomic": "true", children: "Graph interaction inactive. Click to activate." })
1759
+ ] });
1760
+ }
1761
+ if (mode === "click-to-activate" && isActive) {
1762
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1763
+ /* @__PURE__ */ jsxRuntime.jsx(
1764
+ "div",
1765
+ {
1766
+ style: {
1767
+ ...OVERLAY_BASE_STYLE,
1768
+ width,
1769
+ height,
1770
+ pointerEvents: "none",
1771
+ border: "2px solid var(--glyph-interaction-active-border, #0a9d7c)",
1772
+ borderRadius: "4px"
1773
+ },
1774
+ "aria-hidden": "true"
1775
+ }
1776
+ ),
1777
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: SR_ONLY_STYLE, role: "status", "aria-live": "polite", "aria-atomic": "true", children: "Graph interaction active. Press Escape to deactivate." })
1778
+ ] });
1779
+ }
1780
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
1781
+ }
1782
+ var OVERLAY_BASE_STYLE = {
1783
+ position: "absolute",
1784
+ top: 0,
1785
+ left: 0,
1786
+ display: "flex",
1787
+ alignItems: "center",
1788
+ justifyContent: "center",
1789
+ zIndex: 10
1790
+ };
1791
+ var TOOLTIP_STYLE = {
1792
+ position: "absolute",
1793
+ bottom: "12px",
1794
+ right: "12px",
1795
+ padding: "6px 10px",
1796
+ backgroundColor: "var(--glyph-interaction-tooltip-bg, rgba(26, 32, 53, 0.9))",
1797
+ color: "var(--glyph-interaction-tooltip-text, #f4f6fa)",
1798
+ borderRadius: "4px",
1799
+ fontSize: "12px",
1800
+ fontFamily: "Inter, system-ui, sans-serif",
1801
+ fontWeight: 500,
1802
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
1803
+ pointerEvents: "none"
1804
+ };
1805
+ var TOOLTIP_TEXT_STYLE = {
1806
+ display: "flex",
1807
+ alignItems: "center",
1808
+ gap: "4px"
1809
+ };
1810
+ var ACTIVATION_OVERLAY_STYLE = {
1811
+ backgroundColor: "var(--glyph-interaction-overlay-bg, rgba(244, 246, 250, 0.8))",
1812
+ cursor: "pointer",
1813
+ transition: "background-color 0.2s ease"
1814
+ };
1815
+ var ACTIVATION_TEXT_STYLE = {
1816
+ padding: "12px 20px",
1817
+ backgroundColor: "var(--glyph-interaction-tooltip-bg, rgba(26, 32, 53, 0.9))",
1818
+ color: "var(--glyph-interaction-tooltip-text, #f4f6fa)",
1819
+ borderRadius: "6px",
1820
+ fontSize: "14px",
1821
+ fontFamily: "Inter, system-ui, sans-serif",
1822
+ fontWeight: 500,
1823
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.2)"
1824
+ };
1825
+ var SR_ONLY_STYLE = {
1826
+ position: "absolute",
1827
+ width: "1px",
1828
+ height: "1px",
1829
+ padding: 0,
1830
+ margin: "-1px",
1831
+ overflow: "hidden",
1832
+ clip: "rect(0, 0, 0, 0)",
1833
+ whiteSpace: "nowrap",
1834
+ border: 0
1835
+ };
1836
+ function ZoomControls({ onZoomIn, onZoomOut, onReset }) {
1837
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: CONTROLS_CONTAINER_STYLE, children: [
1838
+ /* @__PURE__ */ jsxRuntime.jsx(
1839
+ "button",
1840
+ {
1841
+ onClick: onZoomIn,
1842
+ style: BUTTON_STYLE,
1843
+ "aria-label": "Zoom in",
1844
+ title: "Zoom in",
1845
+ type: "button",
1846
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", children: [
1847
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "4", x2: "8", y2: "12", strokeWidth: "2" }),
1848
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "8", x2: "12", y2: "8", strokeWidth: "2" })
1849
+ ] })
1850
+ }
1851
+ ),
1852
+ /* @__PURE__ */ jsxRuntime.jsx(
1853
+ "button",
1854
+ {
1855
+ onClick: onZoomOut,
1856
+ style: BUTTON_STYLE,
1857
+ "aria-label": "Zoom out",
1858
+ title: "Zoom out",
1859
+ type: "button",
1860
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "8", x2: "12", y2: "8", strokeWidth: "2" }) })
1861
+ }
1862
+ ),
1863
+ /* @__PURE__ */ jsxRuntime.jsx(
1864
+ "button",
1865
+ {
1866
+ onClick: onReset,
1867
+ style: BUTTON_STYLE,
1868
+ "aria-label": "Reset zoom",
1869
+ title: "Reset zoom",
1870
+ type: "button",
1871
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "10", height: "10", strokeWidth: "2", rx: "1" }) })
1872
+ }
1873
+ )
1874
+ ] });
1875
+ }
1876
+ var CONTROLS_CONTAINER_STYLE = {
1877
+ position: "absolute",
1878
+ top: "12px",
1879
+ right: "12px",
1880
+ display: "flex",
1881
+ flexDirection: "column",
1882
+ gap: "4px",
1883
+ zIndex: 10
1884
+ };
1885
+ var BUTTON_STYLE = {
1886
+ width: "32px",
1887
+ height: "32px",
1888
+ padding: "0",
1889
+ display: "flex",
1890
+ alignItems: "center",
1891
+ justifyContent: "center",
1892
+ backgroundColor: "var(--glyph-surface-raised, #f4f6fa)",
1893
+ border: "1px solid var(--glyph-border, #d0d8e4)",
1894
+ borderRadius: "4px",
1895
+ color: "var(--glyph-text, #1a2035)",
1896
+ cursor: "pointer",
1897
+ transition: "all 0.2s ease",
1898
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
1899
+ };
1458
1900
  var GROUP_PALETTE = [
1459
1901
  "#00d4aa",
1460
1902
  // cyan-green
@@ -1501,7 +1943,7 @@ function getThemeVar(container, varName, fallback) {
1501
1943
  return getComputedStyle(container).getPropertyValue(varName).trim() || fallback;
1502
1944
  }
1503
1945
  var ARROW_MARKER_ID = "glyph-graph-arrowhead";
1504
- function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, onNodeClick) {
1946
+ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, zoomBehavior, onNodeClick) {
1505
1947
  const svg = d32__namespace.select(svgElement);
1506
1948
  svg.selectAll("*").remove();
1507
1949
  const width = Math.max(layout.width, 200);
@@ -1514,9 +1956,6 @@ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, o
1514
1956
  const nodeStrokeWidth = getThemeVar(container, "--glyph-node-stroke-width", "1.5");
1515
1957
  const nodeFillOpacity = getThemeVar(container, "--glyph-node-fill-opacity", "0.85");
1516
1958
  const root = svg.append("g").attr("class", "glyph-graph-root");
1517
- const zoomBehavior = d32__namespace.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
1518
- root.attr("transform", event.transform.toString());
1519
- });
1520
1959
  svg.call(zoomBehavior);
1521
1960
  const navigableNodes = /* @__PURE__ */ new Set();
1522
1961
  const refByAnchor = /* @__PURE__ */ new Map();
@@ -1534,7 +1973,7 @@ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, o
1534
1973
  if (edge.label) {
1535
1974
  const mid = edge.points[Math.floor(edge.points.length / 2)];
1536
1975
  if (mid) {
1537
- edgeG.append("text").attr("x", mid.x).attr("y", mid.y - 8).attr("text-anchor", "middle").attr("font-size", "11px").attr("fill", "var(--glyph-edge-color, #6b7a94)").text(edge.label);
1976
+ edgeG.append("text").attr("x", mid.x).attr("y", mid.y - 8).attr("text-anchor", "middle").attr("font-size", "11px").attr("fill", "var(--glyph-edge-color, #6b7a94)").text(inlineToText(edge.label));
1538
1977
  }
1539
1978
  }
1540
1979
  }
@@ -1551,7 +1990,7 @@ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, o
1551
1990
  } else {
1552
1991
  nodeG.append("rect").attr("x", nodeX).attr("y", nodeY).attr("width", node.width).attr("height", node.height).attr("rx", nodeRadius).attr("ry", nodeRadius).attr("fill", node.style?.["fill"] ?? color3).attr("stroke", node.style?.["stroke"] ?? defaultStroke).attr("stroke-width", node.style?.["stroke-width"] ?? nodeStrokeWidth).attr("opacity", nodeFillOpacity);
1553
1992
  }
1554
- nodeG.append("text").attr("x", node.x).attr("y", node.y).attr("dy", "0.35em").attr("text-anchor", "middle").attr("font-size", "13px").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-node-label-color, #fff)").attr("pointer-events", "none").text(node.label);
1993
+ nodeG.append("text").attr("x", node.x).attr("y", node.y).attr("dy", "0.35em").attr("text-anchor", "middle").attr("font-size", "13px").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-node-label-color, #fff)").attr("pointer-events", "none").text(inlineToText(node.label));
1555
1994
  if (isNavigable || onNodeClick) {
1556
1995
  nodeG.attr("cursor", "pointer");
1557
1996
  nodeG.on("click", () => {
@@ -1559,7 +1998,7 @@ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, o
1559
1998
  const ref = refByAnchor.get(node.id);
1560
1999
  if (ref) onNavigate(ref);
1561
2000
  }
1562
- onNodeClick?.(node.id, node.label);
2001
+ onNodeClick?.(node.id, inlineToText(node.label));
1563
2002
  });
1564
2003
  }
1565
2004
  }
@@ -1573,6 +2012,7 @@ function Graph({
1573
2012
  container
1574
2013
  }) {
1575
2014
  const svgRef = react.useRef(null);
2015
+ const rootRef = react.useRef(null);
1576
2016
  const groupIndex = react.useRef(/* @__PURE__ */ new Map());
1577
2017
  const layoutResult = react.useMemo(() => {
1578
2018
  const direction = resolveLayout(data);
@@ -1581,6 +2021,12 @@ function Graph({
1581
2021
  }
1582
2022
  return computeDagreLayout(data.nodes, data.edges, direction);
1583
2023
  }, [data]);
2024
+ const { overlayProps, zoomBehavior, zoomIn, zoomOut, resetZoom } = useZoomInteraction({
2025
+ svgRef,
2026
+ rootRef,
2027
+ interactionMode: data.interactionMode ?? "modifier-key",
2028
+ blockId: block.id
2029
+ });
1584
2030
  const handleNodeClick = react.useMemo(() => {
1585
2031
  if (!onInteraction) return void 0;
1586
2032
  return (nodeId, nodeLabel) => {
@@ -1601,27 +2047,36 @@ function Graph({
1601
2047
  groupIndex.current,
1602
2048
  outgoingRefs,
1603
2049
  onNavigate,
2050
+ zoomBehavior,
1604
2051
  handleNodeClick
1605
2052
  );
1606
- }, [layoutResult, outgoingRefs, onNavigate, handleNodeClick]);
2053
+ const rootElement = svgRef.current.querySelector(".glyph-graph-root");
2054
+ if (rootElement) {
2055
+ rootRef.current = rootElement;
2056
+ }
2057
+ }, [layoutResult, outgoingRefs, onNavigate, zoomBehavior, handleNodeClick]);
1607
2058
  const ariaLabel = `${data.type} graph with ${data.nodes.length} nodes and ${data.edges.length} edges`;
1608
2059
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-graph-container", children: [
1609
- /* @__PURE__ */ jsxRuntime.jsx(
1610
- "svg",
1611
- {
1612
- ref: svgRef,
1613
- role: "img",
1614
- "aria-label": ariaLabel,
1615
- width: "100%",
1616
- height: "100%",
1617
- style: {
1618
- minHeight: container.tier === "compact" ? 200 : 300,
1619
- maxHeight: container.tier === "compact" ? 500 : 700,
1620
- display: "block"
2060
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
2061
+ /* @__PURE__ */ jsxRuntime.jsx(
2062
+ "svg",
2063
+ {
2064
+ ref: svgRef,
2065
+ role: "img",
2066
+ "aria-label": ariaLabel,
2067
+ width: "100%",
2068
+ height: "100%",
2069
+ style: {
2070
+ minHeight: container.tier === "compact" ? 200 : 300,
2071
+ maxHeight: container.tier === "compact" ? 500 : 700,
2072
+ display: "block"
2073
+ }
1621
2074
  }
1622
- }
1623
- ),
1624
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Graph data", style: SR_ONLY_STYLE, children: [
2075
+ ),
2076
+ overlayProps && /* @__PURE__ */ jsxRuntime.jsx(InteractionOverlay, { ...overlayProps }),
2077
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomControls, { onZoomIn: zoomIn, onZoomOut: zoomOut, onReset: resetZoom })
2078
+ ] }),
2079
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Graph data", style: SR_ONLY_STYLE2, children: [
1625
2080
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Graph nodes and connections" }),
1626
2081
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1627
2082
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
@@ -1635,7 +2090,7 @@ function Graph({
1635
2090
  return `${dir} ${target}${e.label ? ` (${e.label})` : ""}`;
1636
2091
  }).join(", ");
1637
2092
  return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1638
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.label }),
2093
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: inlineToText(node.label) }),
1639
2094
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.group ?? "" }),
1640
2095
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: connections })
1641
2096
  ] }, node.id);
@@ -1643,7 +2098,7 @@ function Graph({
1643
2098
  ] })
1644
2099
  ] });
1645
2100
  }
1646
- var SR_ONLY_STYLE = {
2101
+ var SR_ONLY_STYLE2 = {
1647
2102
  position: "absolute",
1648
2103
  width: "1px",
1649
2104
  height: "1px",
@@ -1669,14 +2124,20 @@ var NODE_SEP2 = 60;
1669
2124
  var RANK_SEP2 = 80;
1670
2125
  var EDGE_SEP2 = 10;
1671
2126
  var LAYOUT_PADDING2 = 40;
1672
- var CHAR_WIDTH = 7.5;
1673
2127
  function computeEntitySize(entity) {
1674
2128
  const attrs = entity.attributes ?? [];
1675
2129
  const height = ENTITY_HEADER_HEIGHT + attrs.length * ENTITY_ATTR_HEIGHT + ENTITY_PADDING;
1676
- let maxTextWidth = entity.label.length * (CHAR_WIDTH + 1);
2130
+ const labelDimensions = measureText(entity.label, {
2131
+ fontSize: "14px",
2132
+ fontFamily: "Inter, system-ui, sans-serif"
2133
+ });
2134
+ let maxTextWidth = labelDimensions.width;
1677
2135
  for (const attr of attrs) {
1678
- const attrText = `${attr.name}: ${attr.type}`;
1679
- maxTextWidth = Math.max(maxTextWidth, attrText.length * CHAR_WIDTH);
2136
+ const attrNameDimensions = measureText(attr.name, {
2137
+ fontSize: "12px",
2138
+ fontFamily: "ui-monospace, monospace"
2139
+ });
2140
+ maxTextWidth = Math.max(maxTextWidth, attrNameDimensions.width + 100);
1680
2141
  }
1681
2142
  const width = Math.max(ENTITY_MIN_WIDTH, maxTextWidth + ENTITY_PADDING * 2 + 16);
1682
2143
  return { width, height };
@@ -1767,16 +2228,13 @@ function drawCrowsFoot(g, x, y, angle, symbol) {
1767
2228
  g.append("line").attr("x1", tx - Math.cos(perpAngle) * halfLen).attr("y1", ty - Math.sin(perpAngle) * halfLen).attr("x2", tx + Math.cos(perpAngle) * halfLen).attr("y2", ty + Math.sin(perpAngle) * halfLen).attr("stroke", "var(--glyph-relation-line, #6b7a94)").attr("stroke-width", "var(--glyph-node-stroke-width, 1.5)");
1768
2229
  }
1769
2230
  }
1770
- function renderRelation(svgElement, layout) {
2231
+ function renderRelation(svgElement, layout, zoomBehavior) {
1771
2232
  const svg = d32__namespace.select(svgElement);
1772
2233
  svg.selectAll("*").remove();
1773
2234
  const width = Math.max(layout.width, 200);
1774
2235
  const height = Math.max(layout.height, 200);
1775
2236
  svg.attr("viewBox", `0 0 ${width} ${height}`);
1776
2237
  const root = svg.append("g").attr("class", "glyph-relation-root");
1777
- const zoomBehavior = d32__namespace.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
1778
- root.attr("transform", event.transform.toString());
1779
- });
1780
2238
  svg.call(zoomBehavior);
1781
2239
  const entityMap = /* @__PURE__ */ new Map();
1782
2240
  for (const entity of layout.entities) {
@@ -1803,7 +2261,7 @@ function renderRelation(svgElement, layout) {
1803
2261
  if (rel.label) {
1804
2262
  const mid = rel.points[Math.floor(rel.points.length / 2)];
1805
2263
  if (mid) {
1806
- edgeG.append("text").attr("x", mid.x).attr("y", mid.y - 10).attr("text-anchor", "middle").attr("font-size", "11px").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-relation-label, #6b7a94)").text(rel.label);
2264
+ edgeG.append("text").attr("x", mid.x).attr("y", mid.y - 10).attr("text-anchor", "middle").attr("font-size", "11px").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-relation-label, #6b7a94)").text(inlineToText(rel.label));
1807
2265
  }
1808
2266
  }
1809
2267
  const pFirst = rel.points[0];
@@ -1831,7 +2289,7 @@ function renderRelation(svgElement, layout) {
1831
2289
  const headerHeight = ENTITY_HEADER_HEIGHT;
1832
2290
  entityG.append("rect").attr("x", x).attr("y", y).attr("width", entity.width).attr("height", headerHeight).attr("rx", 4).attr("ry", 4).attr("fill", "var(--glyph-relation-header-bg, #00d4aa)");
1833
2291
  entityG.append("rect").attr("x", x).attr("y", y + headerHeight - 4).attr("width", entity.width).attr("height", 4).attr("fill", "var(--glyph-relation-header-bg, #00d4aa)");
1834
- entityG.append("text").attr("x", entity.x).attr("y", y + headerHeight / 2).attr("dy", "0.35em").attr("text-anchor", "middle").attr("font-size", "13px").attr("font-weight", "bold").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-relation-header-text, #fff)").text(entity.label);
2292
+ entityG.append("text").attr("x", entity.x).attr("y", y + headerHeight / 2).attr("dy", "0.35em").attr("text-anchor", "middle").attr("font-size", "13px").attr("font-weight", "bold").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-relation-header-text, #fff)").text(inlineToText(entity.label));
1835
2293
  if (attrs.length > 0) {
1836
2294
  entityG.append("line").attr("x1", x).attr("y1", y + headerHeight).attr("x2", x + entity.width).attr("y2", y + headerHeight).attr("stroke", "var(--glyph-relation-entity-border, #a8b5c8)").attr("stroke-width", 1);
1837
2295
  }
@@ -1840,7 +2298,7 @@ function renderRelation(svgElement, layout) {
1840
2298
  if (!attr) continue;
1841
2299
  const attrY = y + headerHeight + i * ENTITY_ATTR_HEIGHT + ENTITY_ATTR_HEIGHT / 2 + 4;
1842
2300
  const textEl = entityG.append("text").attr("x", x + ENTITY_PADDING).attr("y", attrY).attr("dy", "0.35em").attr("font-size", "12px").attr("font-family", "system-ui, -apple-system, monospace").attr("fill", "var(--glyph-relation-attr-text, #1a2035)");
1843
- const nameSpan = textEl.append("tspan").text(attr.name);
2301
+ const nameSpan = textEl.append("tspan").text(inlineToText(attr.name));
1844
2302
  if (attr.primaryKey) {
1845
2303
  nameSpan.attr("font-weight", "bold").attr("text-decoration", "underline");
1846
2304
  }
@@ -1848,29 +2306,44 @@ function renderRelation(svgElement, layout) {
1848
2306
  }
1849
2307
  }
1850
2308
  }
1851
- function Relation({ data }) {
2309
+ function Relation({ data, block }) {
1852
2310
  const svgRef = react.useRef(null);
2311
+ const rootRef = react.useRef(null);
1853
2312
  const layoutResult = react.useMemo(() => {
1854
2313
  return computeRelationLayout(data);
1855
2314
  }, [data]);
2315
+ const { overlayProps, zoomBehavior, zoomIn, zoomOut, resetZoom } = useZoomInteraction({
2316
+ svgRef,
2317
+ rootRef,
2318
+ interactionMode: data.interactionMode ?? "modifier-key",
2319
+ blockId: block.id
2320
+ });
1856
2321
  react.useEffect(() => {
1857
2322
  if (!svgRef.current) return;
1858
- renderRelation(svgRef.current, layoutResult);
1859
- }, [layoutResult]);
2323
+ renderRelation(svgRef.current, layoutResult, zoomBehavior);
2324
+ const rootElement = svgRef.current.querySelector(".glyph-relation-root");
2325
+ if (rootElement) {
2326
+ rootRef.current = rootElement;
2327
+ }
2328
+ }, [layoutResult, zoomBehavior]);
1860
2329
  const ariaLabel = `Entity-relationship diagram with ${data.entities.length} entities and ${data.relationships.length} relationships`;
1861
2330
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-relation-container", children: [
1862
- /* @__PURE__ */ jsxRuntime.jsx(
1863
- "svg",
1864
- {
1865
- ref: svgRef,
1866
- role: "img",
1867
- "aria-label": ariaLabel,
1868
- width: "100%",
1869
- height: "100%",
1870
- style: { minHeight: 300, maxHeight: 700, display: "block" }
1871
- }
1872
- ),
1873
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Entity-relationship data", style: SR_ONLY_STYLE2, children: [
2331
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
2332
+ /* @__PURE__ */ jsxRuntime.jsx(
2333
+ "svg",
2334
+ {
2335
+ ref: svgRef,
2336
+ role: "img",
2337
+ "aria-label": ariaLabel,
2338
+ width: "100%",
2339
+ height: "100%",
2340
+ style: { minHeight: 300, maxHeight: 700, display: "block" }
2341
+ }
2342
+ ),
2343
+ overlayProps && /* @__PURE__ */ jsxRuntime.jsx(InteractionOverlay, { ...overlayProps }),
2344
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomControls, { onZoomIn: zoomIn, onZoomOut: zoomOut, onReset: resetZoom })
2345
+ ] }),
2346
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Entity-relationship data", style: SR_ONLY_STYLE3, children: [
1874
2347
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Entities and relationships" }),
1875
2348
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1876
2349
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Entity" }),
@@ -1885,7 +2358,7 @@ function Relation({ data }) {
1885
2358
  return `${dir} ${target} [${r.cardinality}]${r.label ? ` (${r.label})` : ""}`;
1886
2359
  }).join(", ");
1887
2360
  return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1888
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: entity.label }),
2361
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: inlineToText(entity.label) }),
1889
2362
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: attrs }),
1890
2363
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: rels })
1891
2364
  ] }, entity.id);
@@ -1893,7 +2366,7 @@ function Relation({ data }) {
1893
2366
  ] })
1894
2367
  ] });
1895
2368
  }
1896
- var SR_ONLY_STYLE2 = {
2369
+ var SR_ONLY_STYLE3 = {
1897
2370
  position: "absolute",
1898
2371
  width: "1px",
1899
2372
  height: "1px",
@@ -2423,9 +2896,9 @@ function CodeDiff({ data, block }) {
2423
2896
  }
2424
2897
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": summary, style: containerStyle11, children: [
2425
2898
  (beforeLabel || afterLabel) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: labelBarStyle, children: [
2426
- beforeLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: beforeLabel }),
2899
+ beforeLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: beforeLabel }) }),
2427
2900
  beforeLabel && afterLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2192" }),
2428
- afterLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: afterLabel })
2901
+ afterLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: afterLabel }) })
2429
2902
  ] }),
2430
2903
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("table", { role: "grid", style: tableStyle2, children: /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: diffLines.map((line6, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2431
2904
  "tr",
@@ -2529,7 +3002,7 @@ function renderNodeShape(nodeG, node, fillOpacity, strokeWidth) {
2529
3002
  }
2530
3003
  }
2531
3004
  }
2532
- function renderFlowchart(svgElement, layout) {
3005
+ function renderFlowchart(svgElement, layout, zoomBehavior) {
2533
3006
  const svg = d32__namespace.select(svgElement);
2534
3007
  svg.selectAll("*").remove();
2535
3008
  const width = Math.max(layout.width, 200);
@@ -2541,9 +3014,6 @@ function renderFlowchart(svgElement, layout) {
2541
3014
  const nodeStrokeWidth = getThemeVar2(container, "--glyph-node-stroke-width", "1.5");
2542
3015
  const nodeFillOpacity = getThemeVar2(container, "--glyph-node-fill-opacity", "0.85");
2543
3016
  const root = svg.append("g").attr("class", "glyph-flowchart-root");
2544
- const zoomBehavior = d32__namespace.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
2545
- root.attr("transform", event.transform.toString());
2546
- });
2547
3017
  svg.call(zoomBehavior);
2548
3018
  const lineGen = d32__namespace.line().x((d) => d.x).y((d) => d.y).curve(d32__namespace.curveBasis);
2549
3019
  const edgeGroup = root.append("g").attr("class", "glyph-flowchart-edges");
@@ -2553,7 +3023,7 @@ function renderFlowchart(svgElement, layout) {
2553
3023
  if (edge.label) {
2554
3024
  const mid = edge.points[Math.floor(edge.points.length / 2)];
2555
3025
  if (mid) {
2556
- edgeG.append("text").attr("x", mid.x).attr("y", mid.y - 8).attr("text-anchor", "middle").attr("font-size", "11px").attr("fill", "var(--glyph-text-muted, #6b7a94)").text(edge.label);
3026
+ edgeG.append("text").attr("x", mid.x).attr("y", mid.y - 8).attr("text-anchor", "middle").attr("font-size", "11px").attr("fill", "var(--glyph-text-muted, #6b7a94)").text(inlineToText(edge.label));
2557
3027
  }
2558
3028
  }
2559
3029
  }
@@ -2561,19 +3031,34 @@ function renderFlowchart(svgElement, layout) {
2561
3031
  for (const node of layout.nodes) {
2562
3032
  const nodeG = nodeGroup.append("g").attr("class", "glyph-flowchart-node");
2563
3033
  renderNodeShape(nodeG, node, nodeFillOpacity, nodeStrokeWidth);
2564
- nodeG.append("text").attr("x", node.x).attr("y", node.y).attr("dy", "0.35em").attr("text-anchor", "middle").attr("font-size", "13px").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-node-label-color, #fff)").attr("pointer-events", "none").text(node.label);
3034
+ nodeG.append("text").attr("x", node.x).attr("y", node.y).attr("dy", "0.35em").attr("text-anchor", "middle").attr("font-size", "13px").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-node-label-color, #fff)").attr("pointer-events", "none").text(inlineToText(node.label));
2565
3035
  }
2566
3036
  }
2567
- function Flowchart({ data, container }) {
3037
+ function Flowchart({
3038
+ data,
3039
+ block,
3040
+ container
3041
+ }) {
2568
3042
  const svgRef = react.useRef(null);
3043
+ const rootRef = react.useRef(null);
2569
3044
  const layoutResult = react.useMemo(() => computeLayout(data.nodes, data.edges, data.direction), [data]);
3045
+ const { overlayProps, zoomBehavior, zoomIn, zoomOut, resetZoom } = useZoomInteraction({
3046
+ svgRef,
3047
+ rootRef,
3048
+ interactionMode: data.interactionMode ?? "modifier-key",
3049
+ blockId: block.id
3050
+ });
2570
3051
  react.useEffect(() => {
2571
3052
  if (!svgRef.current) return;
2572
- renderFlowchart(svgRef.current, layoutResult);
2573
- }, [layoutResult]);
3053
+ renderFlowchart(svgRef.current, layoutResult, zoomBehavior);
3054
+ const rootElement = svgRef.current.querySelector(".glyph-flowchart-root");
3055
+ if (rootElement) {
3056
+ rootRef.current = rootElement;
3057
+ }
3058
+ }, [layoutResult, zoomBehavior]);
2574
3059
  const nodeCount = data.nodes.length;
2575
3060
  const edgeCount = data.edges.length;
2576
- const ariaLabel = data.title ? `${data.title}: flowchart with ${nodeCount} nodes and ${edgeCount} edges` : `Flowchart with ${nodeCount} nodes and ${edgeCount} edges`;
3061
+ const ariaLabel = data.title ? `${inlineToText(data.title)}: flowchart with ${nodeCount} nodes and ${edgeCount} edges` : `Flowchart with ${nodeCount} nodes and ${edgeCount} edges`;
2577
3062
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-flowchart-container", children: [
2578
3063
  data.title && /* @__PURE__ */ jsxRuntime.jsx(
2579
3064
  "div",
@@ -2585,25 +3070,29 @@ function Flowchart({ data, container }) {
2585
3070
  color: "var(--glyph-heading, #edf0f5)",
2586
3071
  marginBottom: "0.5rem"
2587
3072
  },
2588
- children: data.title
3073
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: data.title })
2589
3074
  }
2590
3075
  ),
2591
- /* @__PURE__ */ jsxRuntime.jsx(
2592
- "svg",
2593
- {
2594
- ref: svgRef,
2595
- role: "img",
2596
- "aria-label": ariaLabel,
2597
- width: "100%",
2598
- height: "100%",
2599
- style: {
2600
- minHeight: container.tier === "compact" ? 200 : 300,
2601
- maxHeight: container.tier === "compact" ? 500 : 700,
2602
- display: "block"
3076
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
3077
+ /* @__PURE__ */ jsxRuntime.jsx(
3078
+ "svg",
3079
+ {
3080
+ ref: svgRef,
3081
+ role: "img",
3082
+ "aria-label": ariaLabel,
3083
+ width: "100%",
3084
+ height: "100%",
3085
+ style: {
3086
+ minHeight: container.tier === "compact" ? 200 : 300,
3087
+ maxHeight: container.tier === "compact" ? 500 : 700,
3088
+ display: "block"
3089
+ }
2603
3090
  }
2604
- }
2605
- ),
2606
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Flowchart data", style: SR_ONLY_STYLE3, children: [
3091
+ ),
3092
+ overlayProps && /* @__PURE__ */ jsxRuntime.jsx(InteractionOverlay, { ...overlayProps }),
3093
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomControls, { onZoomIn: zoomIn, onZoomOut: zoomOut, onReset: resetZoom })
3094
+ ] }),
3095
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Flowchart data", style: SR_ONLY_STYLE4, children: [
2607
3096
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Flowchart nodes and connections" }),
2608
3097
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2609
3098
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
@@ -2614,10 +3103,10 @@ function Flowchart({ data, container }) {
2614
3103
  const connections = data.edges.filter((e) => e.from === node.id || e.to === node.id).map((e) => {
2615
3104
  const target = e.from === node.id ? e.to : e.from;
2616
3105
  const dir = e.from === node.id ? "->" : "<-";
2617
- return `${dir} ${target}${e.label ? ` (${e.label})` : ""}`;
3106
+ return `${dir} ${target}${e.label ? ` (${inlineToText(e.label)})` : ""}`;
2618
3107
  }).join(", ");
2619
3108
  return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2620
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.label }),
3109
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: inlineToText(node.label) }),
2621
3110
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.type }),
2622
3111
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: connections })
2623
3112
  ] }, node.id);
@@ -2625,7 +3114,7 @@ function Flowchart({ data, container }) {
2625
3114
  ] })
2626
3115
  ] });
2627
3116
  }
2628
- var SR_ONLY_STYLE3 = {
3117
+ var SR_ONLY_STYLE4 = {
2629
3118
  position: "absolute",
2630
3119
  width: "1px",
2631
3120
  height: "1px",
@@ -3039,20 +3528,24 @@ function renderActorBox(actor, cx, y, keyPrefix, width = ACTOR_WIDTH, height = A
3039
3528
  strokeWidth: 1.5
3040
3529
  }
3041
3530
  ),
3042
- /* @__PURE__ */ jsxRuntime.jsx(
3043
- "text",
3531
+ /* @__PURE__ */ jsxRuntime.jsx("foreignObject", { x: cx - width / 2, y, width, height, children: /* @__PURE__ */ jsxRuntime.jsx(
3532
+ "div",
3044
3533
  {
3045
- x: cx,
3046
- y: y + height / 2,
3047
- dy: "0.35em",
3048
- textAnchor: "middle",
3049
- fontSize,
3050
- fontFamily: "Inter, system-ui, sans-serif",
3051
- fontWeight: 600,
3052
- fill: "var(--glyph-text, #d4dae3)",
3053
- children: actor.label
3534
+ style: {
3535
+ display: "flex",
3536
+ alignItems: "center",
3537
+ justifyContent: "center",
3538
+ width: "100%",
3539
+ height: "100%",
3540
+ fontSize,
3541
+ fontFamily: "Inter, system-ui, sans-serif",
3542
+ fontWeight: 600,
3543
+ color: "var(--glyph-text, #d4dae3)",
3544
+ textAlign: "center"
3545
+ },
3546
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: actor.label })
3054
3547
  }
3055
- )
3548
+ ) })
3056
3549
  ] }, `${keyPrefix}-${actor.id}`);
3057
3550
  }
3058
3551
  function renderSelfMessage(x, y, label, idx, fontSize = "12px") {
@@ -3067,18 +3560,19 @@ function renderSelfMessage(x, y, label, idx, fontSize = "12px") {
3067
3560
  markerEnd: "url(#seq-arrow-solid)"
3068
3561
  }
3069
3562
  ),
3070
- /* @__PURE__ */ jsxRuntime.jsx(
3071
- "text",
3563
+ /* @__PURE__ */ jsxRuntime.jsx("foreignObject", { x: x + SELF_ARC_WIDTH + 6, y, width: 150, height: SELF_ARC_HEIGHT, children: /* @__PURE__ */ jsxRuntime.jsx(
3564
+ "div",
3072
3565
  {
3073
- x: x + SELF_ARC_WIDTH + 6,
3074
- y: y + SELF_ARC_HEIGHT / 2,
3075
- dy: "0.35em",
3076
- fontSize,
3077
- fontFamily: "Inter, system-ui, sans-serif",
3078
- fill: "var(--glyph-text, #d4dae3)",
3079
- children: label
3566
+ style: {
3567
+ display: "flex",
3568
+ alignItems: "center",
3569
+ fontSize,
3570
+ fontFamily: "Inter, system-ui, sans-serif",
3571
+ color: "var(--glyph-text, #d4dae3)"
3572
+ },
3573
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: label })
3080
3574
  }
3081
- )
3575
+ ) })
3082
3576
  ] }, `msg-${idx}`);
3083
3577
  }
3084
3578
  function renderStandardMessage(fromX, toX, y, label, isDashed, idx, fontSize = "12px") {
@@ -3098,18 +3592,20 @@ function renderStandardMessage(fromX, toX, y, label, isDashed, idx, fontSize = "
3098
3592
  markerEnd: `url(#${markerId})`
3099
3593
  }
3100
3594
  ),
3101
- /* @__PURE__ */ jsxRuntime.jsx(
3102
- "text",
3595
+ /* @__PURE__ */ jsxRuntime.jsx("foreignObject", { x: midX - 75, y: y - 22, width: 150, height: 20, children: /* @__PURE__ */ jsxRuntime.jsx(
3596
+ "div",
3103
3597
  {
3104
- x: midX,
3105
- y: y - 8,
3106
- textAnchor: "middle",
3107
- fontSize,
3108
- fontFamily: "Inter, system-ui, sans-serif",
3109
- fill: "var(--glyph-text, #d4dae3)",
3110
- children: label
3598
+ style: {
3599
+ display: "flex",
3600
+ justifyContent: "center",
3601
+ fontSize,
3602
+ fontFamily: "Inter, system-ui, sans-serif",
3603
+ color: "var(--glyph-text, #d4dae3)",
3604
+ textAlign: "center"
3605
+ },
3606
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: label })
3111
3607
  }
3112
- )
3608
+ ) })
3113
3609
  ] }, `msg-${idx}`);
3114
3610
  }
3115
3611
  function Sequence({ data, container }) {
@@ -3134,7 +3630,7 @@ function Sequence({ data, container }) {
3134
3630
  const firstMsgY = lifelineStartY + MSG_SPACING;
3135
3631
  const lastMsgY = firstMsgY + (messageCount - 1) * MSG_SPACING;
3136
3632
  const svgHeight = lastMsgY + BOTTOM_PADDING + effectiveActorHeight;
3137
- const ariaLabel = data.title ? `${data.title}: sequence diagram with ${actorCount} actors and ${messageCount} messages` : `Sequence diagram with ${actorCount} actors and ${messageCount} messages`;
3633
+ const ariaLabel = data.title ? `${inlineToText(data.title)}: sequence diagram with ${actorCount} actors and ${messageCount} messages` : `Sequence diagram with ${actorCount} actors and ${messageCount} messages`;
3138
3634
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-sequence-container", children: [
3139
3635
  data.title && /* @__PURE__ */ jsxRuntime.jsx(
3140
3636
  "div",
@@ -3146,7 +3642,7 @@ function Sequence({ data, container }) {
3146
3642
  color: "var(--glyph-heading, #edf0f5)",
3147
3643
  marginBottom: "0.5rem"
3148
3644
  },
3149
- children: data.title
3645
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: data.title })
3150
3646
  }
3151
3647
  ),
3152
3648
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3247,7 +3743,7 @@ function Sequence({ data, container }) {
3247
3743
  ]
3248
3744
  }
3249
3745
  ),
3250
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Sequence data", style: SR_ONLY_STYLE4, children: [
3746
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Sequence data", style: SR_ONLY_STYLE5, children: [
3251
3747
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Sequence messages in order" }),
3252
3748
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
3253
3749
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "#" }),
@@ -3261,16 +3757,16 @@ function Sequence({ data, container }) {
3261
3757
  const toActor = data.actors.find((a) => a.id === msg.to);
3262
3758
  return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
3263
3759
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: idx + 1 }),
3264
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: fromActor?.label ?? msg.from }),
3265
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: toActor?.label ?? msg.to }),
3266
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: msg.label }),
3760
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: fromActor ? inlineToText(fromActor.label) : msg.from }),
3761
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: toActor ? inlineToText(toActor.label) : msg.to }),
3762
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: inlineToText(msg.label) }),
3267
3763
  /* @__PURE__ */ jsxRuntime.jsx("td", { children: msg.type })
3268
3764
  ] }, idx);
3269
3765
  }) })
3270
3766
  ] })
3271
3767
  ] });
3272
3768
  }
3273
- var SR_ONLY_STYLE4 = {
3769
+ var SR_ONLY_STYLE5 = {
3274
3770
  position: "absolute",
3275
3771
  width: "1px",
3276
3772
  height: "1px",
@@ -3676,7 +4172,7 @@ function Architecture({
3676
4172
  }
3677
4173
  }
3678
4174
  ),
3679
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Architecture data", style: SR_ONLY_STYLE5, children: [
4175
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Architecture data", style: SR_ONLY_STYLE6, children: [
3680
4176
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Architecture nodes and connections" }),
3681
4177
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
3682
4178
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
@@ -3720,7 +4216,7 @@ function countLeafNodes(children) {
3720
4216
  }
3721
4217
  return count;
3722
4218
  }
3723
- var SR_ONLY_STYLE5 = {
4219
+ var SR_ONLY_STYLE6 = {
3724
4220
  position: "absolute",
3725
4221
  width: "1px",
3726
4222
  height: "1px",
@@ -3908,7 +4404,7 @@ function layoutTree(data) {
3908
4404
  };
3909
4405
  }
3910
4406
  function renderAccessibleList(root, children) {
3911
- return /* @__PURE__ */ jsxRuntime.jsx("ul", { style: SR_ONLY_STYLE6, role: "list", "aria-label": "Mind map structure", children: /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
4407
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { style: SR_ONLY_STYLE7, role: "list", "aria-label": "Mind map structure", children: /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
3912
4408
  root,
3913
4409
  children.length > 0 && renderAccessibleChildren(children)
3914
4410
  ] }) });
@@ -4035,7 +4531,7 @@ function MindMap({ data, container }) {
4035
4531
  renderAccessibleList(data.root, data.children)
4036
4532
  ] });
4037
4533
  }
4038
- var SR_ONLY_STYLE6 = {
4534
+ var SR_ONLY_STYLE7 = {
4039
4535
  position: "absolute",
4040
4536
  width: "1px",
4041
4537
  height: "1px",
@@ -4110,7 +4606,7 @@ function Equation({ data }) {
4110
4606
  const ariaLabel = `Equation: ${data.expression}`;
4111
4607
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyle, role: "math", "aria-label": ariaLabel, children: [
4112
4608
  error || html === "" ? /* @__PURE__ */ jsxRuntime.jsx("code", { style: fallbackStyle, children: data.expression }) : /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: html } }),
4113
- data.label !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle2, children: data.label })
4609
+ data.label !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle2, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: data.label }) })
4114
4610
  ] });
4115
4611
  }
4116
4612
  if (data.steps !== void 0 && data.steps.length > 0) {
@@ -4121,10 +4617,10 @@ function Equation({ data }) {
4121
4617
  const { html, error } = renderLatex(step.expression);
4122
4618
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: stepRowStyle, children: [
4123
4619
  error || html === "" ? /* @__PURE__ */ jsxRuntime.jsx("code", { style: fallbackStyle, children: step.expression }) : /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: html } }),
4124
- step.annotation !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { style: annotationStyle, children: step.annotation })
4620
+ step.annotation !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { style: annotationStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: step.annotation }) })
4125
4621
  ] }, idx);
4126
4622
  }) }),
4127
- data.label !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle2, children: data.label })
4623
+ data.label !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle2, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: data.label }) })
4128
4624
  ] });
4129
4625
  }
4130
4626
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: containerStyle, role: "math", "aria-label": "Empty equation", children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--glyph-text-muted, #6b7a94)" }, children: "No equation provided" }) });
@@ -6550,8 +7046,8 @@ function Kanban({
6550
7046
  style: cardStyle(isGrabbed, card.priority),
6551
7047
  onKeyDown: (e) => handleCardKeyDown(e, card.id, col.id, cardIndex),
6552
7048
  children: [
6553
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardTitleStyle, children: card.title }),
6554
- card.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardDescStyle, children: card.description }),
7049
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardTitleStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: card.title }) }),
7050
+ card.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardDescStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: card.description }) }),
6555
7051
  card.tags && card.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: tagContainerStyle, children: card.tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: tagStyle, children: tag }, tag)) })
6556
7052
  ]
6557
7053
  },