@glyphjs/components 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -271,6 +271,22 @@ function ChartAccessibleTable({
271
271
  }
272
272
  );
273
273
  }
274
+ function inferAxisKeys(series, explicitX, explicitY) {
275
+ if (explicitX && explicitY) return { xKey: explicitX, yKey: explicitY };
276
+ const sample = series[0]?.data[0];
277
+ if (!sample) return { xKey: explicitX ?? "x", yKey: explicitY ?? "y" };
278
+ let inferredX;
279
+ let inferredY;
280
+ for (const [key, value] of Object.entries(sample)) {
281
+ if (!inferredX && typeof value === "string") inferredX = key;
282
+ if (!inferredY && typeof value === "number") inferredY = key;
283
+ if (inferredX && inferredY) break;
284
+ }
285
+ return {
286
+ xKey: explicitX ?? inferredX ?? "x",
287
+ yKey: explicitY ?? inferredY ?? "y"
288
+ };
289
+ }
274
290
  function computeScales(width, height, type, series, xKey, yKey, margin) {
275
291
  const innerWidth = width - margin.left - margin.right;
276
292
  const innerHeight = height - margin.top - margin.bottom;
@@ -411,9 +427,9 @@ function Chart({
411
427
  const svgRef = react.useRef(null);
412
428
  const tooltipRef = react.useRef(null);
413
429
  const [width, setWidth] = react.useState(DEFAULT_WIDTH);
430
+ const [isLoading, setIsLoading] = react.useState(true);
414
431
  const { type, series, xAxis, yAxis, legend } = data;
415
- const xKey = xAxis?.key ?? "x";
416
- const yKey = yAxis?.key ?? "y";
432
+ const { xKey, yKey } = inferAxisKeys(series, xAxis?.key, yAxis?.key);
417
433
  const height = DEFAULT_HEIGHT;
418
434
  const isCompact = containerCtx.tier === "compact";
419
435
  const margin = isCompact ? {
@@ -474,6 +490,7 @@ function Chart({
474
490
  if (legend) {
475
491
  renderLegend(sel, series, margin.left, margin.top, isCompact ? "10px" : void 0);
476
492
  }
493
+ setIsLoading(false);
477
494
  }, [
478
495
  scales,
479
496
  type,
@@ -495,6 +512,7 @@ function Chart({
495
512
  "div",
496
513
  {
497
514
  ref: containerRef,
515
+ "data-glyph-loading": isLoading || void 0,
498
516
  style: {
499
517
  position: "relative",
500
518
  width: "100%",
@@ -1356,6 +1374,13 @@ var timelineDefinition = {
1356
1374
  // src/utils/measureText.ts
1357
1375
  var measurementCache = /* @__PURE__ */ new WeakMap();
1358
1376
  function measurePlainText(text, style) {
1377
+ if (typeof document === "undefined") {
1378
+ const avgCharWidth = parseInt(style.fontSize) * 0.6;
1379
+ return {
1380
+ width: text.length * avgCharWidth,
1381
+ height: parseInt(style.fontSize) * 1.2
1382
+ };
1383
+ }
1359
1384
  const canvas = document.createElement("canvas");
1360
1385
  const ctx = canvas.getContext("2d");
1361
1386
  if (!ctx) {
@@ -1373,6 +1398,10 @@ function measurePlainText(text, style) {
1373
1398
  return { width, height };
1374
1399
  }
1375
1400
  function measureHtmlText(content, style) {
1401
+ if (typeof document === "undefined") {
1402
+ const plainText = flattenInlineNodes(content);
1403
+ return measurePlainText(plainText, style);
1404
+ }
1376
1405
  const cached = measurementCache.get(content);
1377
1406
  if (cached) {
1378
1407
  return cached;
@@ -1401,6 +1430,28 @@ function measureHtmlText(content, style) {
1401
1430
  measurementCache.set(content, dimensions);
1402
1431
  return dimensions;
1403
1432
  }
1433
+ function flattenInlineNodes(nodes) {
1434
+ return nodes.map((node) => {
1435
+ switch (node.type) {
1436
+ case "text":
1437
+ return node.value;
1438
+ case "inlineCode":
1439
+ return node.value;
1440
+ case "strong":
1441
+ case "emphasis":
1442
+ case "delete":
1443
+ return flattenInlineNodes(node.children);
1444
+ case "link":
1445
+ return flattenInlineNodes(node.children);
1446
+ case "image":
1447
+ return node.alt ?? "";
1448
+ case "break":
1449
+ return "\n";
1450
+ default:
1451
+ return "";
1452
+ }
1453
+ }).join("");
1454
+ }
1404
1455
  function inlineNodesToHtml(nodes) {
1405
1456
  return nodes.map((node) => {
1406
1457
  switch (node.type) {
@@ -1426,6 +1477,9 @@ function inlineNodesToHtml(nodes) {
1426
1477
  }).join("");
1427
1478
  }
1428
1479
  function escapeHtml(str) {
1480
+ if (typeof document === "undefined") {
1481
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1482
+ }
1429
1483
  const div = document.createElement("div");
1430
1484
  div.textContent = str;
1431
1485
  return div.innerHTML;
@@ -1632,16 +1686,16 @@ function useZoomInteraction({
1632
1686
  };
1633
1687
  }, [interactionMode, svgRef]);
1634
1688
  const zoomBehavior = react.useMemo(() => {
1635
- const zoom3 = d32__namespace.zoom().scaleExtent([0.1, 4]);
1636
- if (typeof zoom3.filter === "function") {
1637
- zoom3.filter(filterFunction);
1689
+ const zoom2 = d32__namespace.zoom().scaleExtent([0.1, 4]);
1690
+ if (typeof zoom2.filter === "function") {
1691
+ zoom2.filter(filterFunction);
1638
1692
  }
1639
- zoom3.on("zoom", (event) => {
1693
+ zoom2.on("zoom", (event) => {
1640
1694
  if (rootRef.current) {
1641
1695
  d32__namespace.select(rootRef.current).attr("transform", event.transform.toString());
1642
1696
  }
1643
1697
  });
1644
- return zoom3;
1698
+ return zoom2;
1645
1699
  }, [filterFunction, rootRef]);
1646
1700
  const handleActivate = react.useCallback(() => {
1647
1701
  if (interactionMode === "click-to-activate") {
@@ -2014,6 +2068,7 @@ function Graph({
2014
2068
  const svgRef = react.useRef(null);
2015
2069
  const rootRef = react.useRef(null);
2016
2070
  const groupIndex = react.useRef(/* @__PURE__ */ new Map());
2071
+ const [isLoading, setIsLoading] = react.useState(true);
2017
2072
  const layoutResult = react.useMemo(() => {
2018
2073
  const direction = resolveLayout(data);
2019
2074
  if (direction === "force") {
@@ -2054,9 +2109,10 @@ function Graph({
2054
2109
  if (rootElement) {
2055
2110
  rootRef.current = rootElement;
2056
2111
  }
2112
+ setIsLoading(false);
2057
2113
  }, [layoutResult, outgoingRefs, onNavigate, zoomBehavior, handleNodeClick]);
2058
2114
  const ariaLabel = `${data.type} graph with ${data.nodes.length} nodes and ${data.edges.length} edges`;
2059
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-graph-container", children: [
2115
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-graph-container", "data-glyph-loading": isLoading || void 0, children: [
2060
2116
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
2061
2117
  /* @__PURE__ */ jsxRuntime.jsx(
2062
2118
  "svg",
@@ -3799,7 +3855,7 @@ var DIRECTION_MAP = {
3799
3855
  "bottom-up": "UP"
3800
3856
  };
3801
3857
  function buildElkNode(node) {
3802
- if (node.type === "zone" && node.children?.length) {
3858
+ if (node.children?.length) {
3803
3859
  return {
3804
3860
  id: node.id,
3805
3861
  labels: [{ text: node.label }],
@@ -3843,7 +3899,7 @@ function collectNodes(elkNode, nodeMap, offsetX, offsetY, nodes, zones, depth, z
3843
3899
  const absX = offsetX + (elkNode.x ?? 0);
3844
3900
  const absY = offsetY + (elkNode.y ?? 0);
3845
3901
  const original = nodeMap.get(elkNode.id);
3846
- if (original?.type === "zone" && elkNode.children?.length) {
3902
+ if (original?.children?.length && elkNode.children?.length) {
3847
3903
  zones.push({
3848
3904
  id: elkNode.id,
3849
3905
  label: original.label,
@@ -3880,7 +3936,7 @@ function flattenNodeMap(children, map) {
3880
3936
  function buildAncestorMap(children, ancestors, map) {
3881
3937
  for (const node of children) {
3882
3938
  map.set(node.id, [...ancestors]);
3883
- if (node.type === "zone" && node.children) {
3939
+ if (node.children?.length) {
3884
3940
  buildAncestorMap(node.children, [...ancestors, node.id], map);
3885
3941
  }
3886
3942
  }
@@ -4038,7 +4094,7 @@ function getThemeVar3(container, varName, fallback) {
4038
4094
  return getComputedStyle(container).getPropertyValue(varName).trim() || fallback;
4039
4095
  }
4040
4096
  var ARROW_MARKER_ID3 = "glyph-arch-arrowhead";
4041
- function renderArchitecture(svgElement, layout) {
4097
+ function renderArchitecture(svgElement, layout, rootRef, zoomBehavior) {
4042
4098
  const svg = d32__namespace.select(svgElement);
4043
4099
  svg.selectAll("*").remove();
4044
4100
  const width = Math.max(layout.width, 200);
@@ -4051,10 +4107,12 @@ function renderArchitecture(svgElement, layout) {
4051
4107
  const nodeStrokeWidth = getThemeVar3(container, "--glyph-node-stroke-width", "1.5");
4052
4108
  const nodeFillOpacity = getThemeVar3(container, "--glyph-node-fill-opacity", "0.85");
4053
4109
  const root = svg.append("g").attr("class", "glyph-architecture-root");
4054
- const zoomBehavior = d32__namespace.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
4055
- root.attr("transform", event.transform.toString());
4056
- });
4057
- svg.call(zoomBehavior);
4110
+ if (rootRef) {
4111
+ rootRef.current = root.node();
4112
+ }
4113
+ if (zoomBehavior) {
4114
+ svg.call(zoomBehavior);
4115
+ }
4058
4116
  const sortedZones = [...layout.zones].sort((a, b) => a.depth - b.depth);
4059
4117
  const zoneGroup = root.append("g").attr("class", "glyph-architecture-zones");
4060
4118
  for (const zone of sortedZones) {
@@ -4122,10 +4180,19 @@ function renderArchitecture(svgElement, layout) {
4122
4180
  }
4123
4181
  function Architecture({
4124
4182
  data,
4125
- container
4183
+ container,
4184
+ block
4126
4185
  }) {
4127
4186
  const svgRef = react.useRef(null);
4187
+ const rootRef = react.useRef(null);
4188
+ const containerRef = react.useRef(null);
4128
4189
  const [layout, setLayout] = react.useState(null);
4190
+ const { overlayProps, zoomBehavior, zoomIn, zoomOut, resetZoom } = useZoomInteraction({
4191
+ svgRef,
4192
+ rootRef,
4193
+ interactionMode: data.interactionMode ?? "modifier-key",
4194
+ blockId: block.id
4195
+ });
4129
4196
  react.useEffect(() => {
4130
4197
  let cancelled = false;
4131
4198
  computeArchitectureLayout(data).then((result) => {
@@ -4137,67 +4204,78 @@ function Architecture({
4137
4204
  }, [data]);
4138
4205
  react.useEffect(() => {
4139
4206
  if (!svgRef.current || !layout) return;
4140
- renderArchitecture(svgRef.current, layout);
4141
- }, [layout]);
4207
+ renderArchitecture(svgRef.current, layout, rootRef, zoomBehavior);
4208
+ }, [layout, zoomBehavior]);
4142
4209
  const nodeCount = countLeafNodes(data.children);
4143
4210
  const edgeCount = data.edges.length;
4144
4211
  const ariaLabel = data.title ? `${data.title}: architecture diagram with ${nodeCount} nodes and ${edgeCount} connections` : `Architecture diagram with ${nodeCount} nodes and ${edgeCount} connections`;
4145
4212
  const flatNodes = flattenNodes(data.children);
4146
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-architecture-container", children: [
4147
- !layout && /* @__PURE__ */ jsxRuntime.jsx(
4148
- "div",
4149
- {
4150
- style: {
4151
- padding: "2rem",
4152
- textAlign: "center",
4153
- color: "var(--glyph-text-muted, #7a8599)",
4154
- fontFamily: "Inter, system-ui, sans-serif",
4155
- fontSize: "13px"
4156
- },
4157
- children: "Computing layout..."
4158
- }
4159
- ),
4160
- /* @__PURE__ */ jsxRuntime.jsx(
4161
- "svg",
4162
- {
4163
- ref: svgRef,
4164
- role: "img",
4165
- "aria-label": ariaLabel,
4166
- width: "100%",
4167
- height: "100%",
4168
- style: {
4169
- minHeight: container.tier === "compact" ? 200 : 300,
4170
- maxHeight: container.tier === "compact" ? 500 : 700,
4171
- display: layout ? "block" : "none"
4172
- }
4173
- }
4174
- ),
4175
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Architecture data", style: SR_ONLY_STYLE6, children: [
4176
- /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Architecture nodes and connections" }),
4177
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
4178
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
4179
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Zone" }),
4180
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Connections" })
4181
- ] }) }),
4182
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: flatNodes.map((node) => {
4183
- const connections = data.edges.filter((e) => e.from === node.id || e.to === node.id).map((e) => {
4184
- const target = e.from === node.id ? e.to : e.from;
4185
- const dir = e.from === node.id ? "->" : "<-";
4186
- return `${dir} ${target}${e.label ? ` (${e.label})` : ""}`;
4187
- }).join(", ");
4188
- return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
4189
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.label }),
4190
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.zone ?? "" }),
4191
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: connections })
4192
- ] }, node.id);
4193
- }) })
4194
- ] })
4195
- ] });
4213
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4214
+ "div",
4215
+ {
4216
+ ref: containerRef,
4217
+ className: "glyph-architecture-container",
4218
+ "data-glyph-loading": !layout || void 0,
4219
+ style: { position: "relative" },
4220
+ children: [
4221
+ !layout && /* @__PURE__ */ jsxRuntime.jsx(
4222
+ "div",
4223
+ {
4224
+ style: {
4225
+ padding: "2rem",
4226
+ textAlign: "center",
4227
+ color: "var(--glyph-text-muted, #7a8599)",
4228
+ fontFamily: "Inter, system-ui, sans-serif",
4229
+ fontSize: "13px"
4230
+ },
4231
+ children: "Computing layout..."
4232
+ }
4233
+ ),
4234
+ /* @__PURE__ */ jsxRuntime.jsx(
4235
+ "svg",
4236
+ {
4237
+ ref: svgRef,
4238
+ role: "img",
4239
+ "aria-label": ariaLabel,
4240
+ width: "100%",
4241
+ height: "100%",
4242
+ style: {
4243
+ minHeight: container.tier === "compact" ? 200 : 300,
4244
+ maxHeight: container.tier === "compact" ? 500 : 700,
4245
+ display: layout ? "block" : "none"
4246
+ }
4247
+ }
4248
+ ),
4249
+ layout && overlayProps && /* @__PURE__ */ jsxRuntime.jsx(InteractionOverlay, { ...overlayProps }),
4250
+ layout && data.showZoomControls !== false && /* @__PURE__ */ jsxRuntime.jsx(ZoomControls, { onZoomIn: zoomIn, onZoomOut: zoomOut, onReset: resetZoom }),
4251
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Architecture data", style: SR_ONLY_STYLE6, children: [
4252
+ /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Architecture nodes and connections" }),
4253
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
4254
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
4255
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Zone" }),
4256
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Connections" })
4257
+ ] }) }),
4258
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: flatNodes.map((node) => {
4259
+ const connections = data.edges.filter((e) => e.from === node.id || e.to === node.id).map((e) => {
4260
+ const target = e.from === node.id ? e.to : e.from;
4261
+ const dir = e.from === node.id ? "->" : "<-";
4262
+ return `${dir} ${target}${e.label ? ` (${e.label})` : ""}`;
4263
+ }).join(", ");
4264
+ return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
4265
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.label }),
4266
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: node.zone ?? "" }),
4267
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: connections })
4268
+ ] }, node.id);
4269
+ }) })
4270
+ ] })
4271
+ ]
4272
+ }
4273
+ );
4196
4274
  }
4197
4275
  function flattenNodes(children, zone) {
4198
4276
  const result = [];
4199
4277
  for (const child of children) {
4200
- if (child.type === "zone" && child.children) {
4278
+ if (child.children?.length) {
4201
4279
  result.push(...flattenNodes(child.children, child.label));
4202
4280
  } else {
4203
4281
  result.push({ id: child.id, label: child.label, zone });
@@ -4208,7 +4286,7 @@ function flattenNodes(children, zone) {
4208
4286
  function countLeafNodes(children) {
4209
4287
  let count = 0;
4210
4288
  for (const child of children) {
4211
- if (child.type === "zone" && child.children) {
4289
+ if (child.children?.length) {
4212
4290
  count += countLeafNodes(child.children);
4213
4291
  } else {
4214
4292
  count++;
@@ -5529,6 +5607,10 @@ function renderRatingGroup(items, keyPrefix) {
5529
5607
  );
5530
5608
  }) }, keyPrefix);
5531
5609
  }
5610
+ function cssEscape(value) {
5611
+ if (typeof CSS !== "undefined" && CSS.escape) return CSS.escape(value);
5612
+ return value.replace(/([^\w-])/g, "\\$1");
5613
+ }
5532
5614
  function Infographic({
5533
5615
  data,
5534
5616
  block,
@@ -5581,7 +5663,7 @@ function Infographic({
5581
5663
  borderLeft: "3px solid var(--glyph-infographic-accent, #3b82f6)",
5582
5664
  paddingLeft: "var(--glyph-spacing-sm, 0.5rem)"
5583
5665
  };
5584
- const printCss = useGrid ? `@media print { #${CSS.escape(baseId)} [data-layout="grid"] { display: grid !important; grid-template-columns: repeat(2, 1fr) !important; gap: 0.5rem !important; } #${CSS.escape(baseId)} [data-layout="grid"] > div { break-inside: avoid; } }` : "";
5666
+ const printCss = useGrid ? `@media print { #${cssEscape(baseId)} [data-layout="grid"] { display: grid !important; grid-template-columns: repeat(2, 1fr) !important; gap: 0.5rem !important; } #${cssEscape(baseId)} [data-layout="grid"] > div { break-inside: avoid; } }` : "";
5585
5667
  let progressColorOffset = 0;
5586
5668
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Infographic", style: containerStyle11, children: [
5587
5669
  printCss && /* @__PURE__ */ jsxRuntime.jsx("style", { children: printCss }),
@@ -7387,6 +7469,39 @@ var annotateDefinition = {
7387
7469
  render: Annotate
7388
7470
  };
7389
7471
 
7472
+ // src/index.ts
7473
+ var allComponentDefinitions = [
7474
+ calloutDefinition,
7475
+ chartDefinition,
7476
+ stepsDefinition,
7477
+ tableDefinition,
7478
+ tabsDefinition,
7479
+ timelineDefinition,
7480
+ graphDefinition,
7481
+ relationDefinition,
7482
+ kpiDefinition,
7483
+ accordionDefinition,
7484
+ comparisonDefinition,
7485
+ codeDiffDefinition,
7486
+ flowchartDefinition,
7487
+ fileTreeDefinition,
7488
+ sequenceDefinition,
7489
+ architectureDefinition,
7490
+ mindMapDefinition,
7491
+ equationDefinition,
7492
+ quizDefinition,
7493
+ cardDefinition,
7494
+ infographicDefinition,
7495
+ pollDefinition,
7496
+ ratingDefinition,
7497
+ rankerDefinition,
7498
+ sliderDefinition,
7499
+ matrixDefinition,
7500
+ formDefinition,
7501
+ kanbanDefinition,
7502
+ annotateDefinition
7503
+ ];
7504
+
7390
7505
  exports.Accordion = Accordion;
7391
7506
  exports.Annotate = Annotate;
7392
7507
  exports.Architecture = Architecture;
@@ -7417,6 +7532,7 @@ exports.Table = Table;
7417
7532
  exports.Tabs = Tabs;
7418
7533
  exports.Timeline = Timeline;
7419
7534
  exports.accordionDefinition = accordionDefinition;
7535
+ exports.allComponentDefinitions = allComponentDefinitions;
7420
7536
  exports.annotateDefinition = annotateDefinition;
7421
7537
  exports.architectureDefinition = architectureDefinition;
7422
7538
  exports.calloutDefinition = calloutDefinition;