@hex-core/components 1.7.0 → 1.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 (94) hide show
  1. package/dist/_tsup-dts-rollup.d.ts +1561 -0
  2. package/dist/arc.d.ts +4 -0
  3. package/dist/arc.js +147 -0
  4. package/dist/arc.js.map +1 -0
  5. package/dist/audio-player.d.ts +2 -0
  6. package/dist/audio-player.js +119 -0
  7. package/dist/audio-player.js.map +1 -0
  8. package/dist/audio-waveform.d.ts +2 -0
  9. package/dist/audio-waveform.js +72 -0
  10. package/dist/audio-waveform.js.map +1 -0
  11. package/dist/canvas.d.ts +2 -0
  12. package/dist/canvas.js +73 -0
  13. package/dist/canvas.js.map +1 -0
  14. package/dist/chord.d.ts +4 -0
  15. package/dist/chord.js +230 -0
  16. package/dist/chord.js.map +1 -0
  17. package/dist/cloze.d.ts +3 -0
  18. package/dist/cloze.js +98 -0
  19. package/dist/cloze.js.map +1 -0
  20. package/dist/compare-table.d.ts +4 -0
  21. package/dist/compare-table.js +109 -0
  22. package/dist/compare-table.js.map +1 -0
  23. package/dist/deck.d.ts +3 -0
  24. package/dist/deck.js +231 -0
  25. package/dist/deck.js.map +1 -0
  26. package/dist/dendrogram.d.ts +3 -0
  27. package/dist/dendrogram.js +162 -0
  28. package/dist/dendrogram.js.map +1 -0
  29. package/dist/diagram.d.ts +2 -0
  30. package/dist/diagram.js +70 -0
  31. package/dist/diagram.js.map +1 -0
  32. package/dist/flashcard.d.ts +2 -0
  33. package/dist/flashcard.js +107 -0
  34. package/dist/flashcard.js.map +1 -0
  35. package/dist/flowchart.d.ts +4 -0
  36. package/dist/flowchart.js +275 -0
  37. package/dist/flowchart.js.map +1 -0
  38. package/dist/funnel.d.ts +3 -0
  39. package/dist/funnel.js +157 -0
  40. package/dist/funnel.js.map +1 -0
  41. package/dist/gantt.d.ts +3 -0
  42. package/dist/gantt.js +279 -0
  43. package/dist/gantt.js.map +1 -0
  44. package/dist/image-occlusion.d.ts +3 -0
  45. package/dist/image-occlusion.js +106 -0
  46. package/dist/image-occlusion.js.map +1 -0
  47. package/dist/index.d.ts +84 -0
  48. package/dist/index.js +3946 -2
  49. package/dist/index.js.map +1 -1
  50. package/dist/matrix.d.ts +3 -0
  51. package/dist/matrix.js +155 -0
  52. package/dist/matrix.js.map +1 -0
  53. package/dist/mind-map.d.ts +3 -0
  54. package/dist/mind-map.js +167 -0
  55. package/dist/mind-map.js.map +1 -0
  56. package/dist/org-chart.d.ts +3 -0
  57. package/dist/org-chart.js +215 -0
  58. package/dist/org-chart.js.map +1 -0
  59. package/dist/pyramid.d.ts +3 -0
  60. package/dist/pyramid.js +150 -0
  61. package/dist/pyramid.js.map +1 -0
  62. package/dist/quiz.d.ts +3 -0
  63. package/dist/quiz.js +128 -0
  64. package/dist/quiz.js.map +1 -0
  65. package/dist/sankey.d.ts +4 -0
  66. package/dist/sankey.js +190 -0
  67. package/dist/sankey.js.map +1 -0
  68. package/dist/schemas.d.ts +23 -0
  69. package/dist/schemas.js +2208 -1
  70. package/dist/schemas.js.map +1 -1
  71. package/dist/sequence.d.ts +4 -0
  72. package/dist/sequence.js +229 -0
  73. package/dist/sequence.js.map +1 -0
  74. package/dist/spaced-repetition.d.ts +3 -0
  75. package/dist/spaced-repetition.js +73 -0
  76. package/dist/spaced-repetition.js.map +1 -0
  77. package/dist/sunburst.d.ts +3 -0
  78. package/dist/sunburst.js +205 -0
  79. package/dist/sunburst.js.map +1 -0
  80. package/dist/terminal.d.ts +2 -0
  81. package/dist/terminal.js +153 -0
  82. package/dist/terminal.js.map +1 -0
  83. package/dist/time-axis.d.ts +3 -0
  84. package/dist/time-axis.js +233 -0
  85. package/dist/time-axis.js.map +1 -0
  86. package/dist/tool-call.js +6 -1
  87. package/dist/tool-call.js.map +1 -1
  88. package/dist/tree-map.d.ts +3 -0
  89. package/dist/tree-map.js +171 -0
  90. package/dist/tree-map.js.map +1 -0
  91. package/dist/venn.d.ts +3 -0
  92. package/dist/venn.js +196 -0
  93. package/dist/venn.js.map +1 -0
  94. package/package.json +47 -3
@@ -0,0 +1,3 @@
1
+ export { GanttTask_alias_1 as GanttTask } from './_tsup-dts-rollup.js';
2
+ export { GanttProps_alias_1 as GanttProps } from './_tsup-dts-rollup.js';
3
+ export { Gantt_alias_1 as Gantt } from './_tsup-dts-rollup.js';
package/dist/gantt.js ADDED
@@ -0,0 +1,279 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+ var HEADER_HEIGHT = 40;
11
+ var ROW_PADDING = 6;
12
+ function Gantt({
13
+ tasks,
14
+ width = 800,
15
+ rowHeight = 32,
16
+ labelMargin = 140,
17
+ tickCount = 6,
18
+ onTaskClick,
19
+ className,
20
+ ...rest
21
+ }) {
22
+ const laidOut = React.useMemo(
23
+ () => layout(tasks, width, rowHeight, labelMargin, tickCount),
24
+ [tasks, width, rowHeight, labelMargin, tickCount]
25
+ );
26
+ const totalHeight = HEADER_HEIGHT + tasks.length * rowHeight + ROW_PADDING;
27
+ const desc = `Gantt with ${tasks.length} task${tasks.length === 1 ? "" : "s"}, range ${laidOut.startLabel} to ${laidOut.endLabel}`;
28
+ const arrowId = React.useId().replace(/:/g, "-");
29
+ return /* @__PURE__ */ jsxs(
30
+ "svg",
31
+ {
32
+ ...rest,
33
+ "data-hex-gantt": true,
34
+ role: "img",
35
+ width,
36
+ height: totalHeight,
37
+ viewBox: `0 0 ${width} ${totalHeight}`,
38
+ className: cn("block", className),
39
+ children: [
40
+ /* @__PURE__ */ jsx("title", { children: "Gantt chart" }),
41
+ /* @__PURE__ */ jsx("desc", { children: desc }),
42
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
43
+ "marker",
44
+ {
45
+ id: `hex-gantt-arrow-${arrowId}`,
46
+ viewBox: "0 0 10 10",
47
+ refX: "10",
48
+ refY: "5",
49
+ markerWidth: "5",
50
+ markerHeight: "5",
51
+ orient: "auto-start-reverse",
52
+ children: /* @__PURE__ */ jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: "hsl(var(--muted-foreground))" })
53
+ }
54
+ ) }),
55
+ /* @__PURE__ */ jsxs("g", { "data-hex-gantt-axis": true, children: [
56
+ /* @__PURE__ */ jsx(
57
+ "line",
58
+ {
59
+ x1: labelMargin,
60
+ x2: width - 16,
61
+ y1: HEADER_HEIGHT - 8,
62
+ y2: HEADER_HEIGHT - 8,
63
+ stroke: "hsl(var(--muted-foreground))",
64
+ strokeWidth: 1
65
+ }
66
+ ),
67
+ laidOut.ticks.map((t, i) => /* @__PURE__ */ jsxs("g", { "data-hex-gantt-tick": true, children: [
68
+ /* @__PURE__ */ jsx(
69
+ "line",
70
+ {
71
+ x1: t.x,
72
+ x2: t.x,
73
+ y1: HEADER_HEIGHT - 8,
74
+ y2: totalHeight - 4,
75
+ stroke: "hsl(var(--muted-foreground))",
76
+ strokeOpacity: 0.15,
77
+ strokeWidth: 1
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsx(
81
+ "text",
82
+ {
83
+ x: t.x,
84
+ y: HEADER_HEIGHT - 14,
85
+ textAnchor: "middle",
86
+ fontSize: 10,
87
+ fill: "hsl(var(--muted-foreground))",
88
+ children: t.label
89
+ }
90
+ )
91
+ ] }, `tick-${i}`))
92
+ ] }),
93
+ /* @__PURE__ */ jsx("g", { "data-hex-gantt-labels": true, children: laidOut.tasks.map((t) => /* @__PURE__ */ jsx(
94
+ "text",
95
+ {
96
+ x: labelMargin - 8,
97
+ y: t.y + t.h / 2,
98
+ dy: "0.35em",
99
+ textAnchor: "end",
100
+ fontSize: 11,
101
+ fill: "hsl(var(--foreground))",
102
+ children: t.task.label
103
+ },
104
+ `label-${t.task.id}`
105
+ )) }),
106
+ /* @__PURE__ */ jsx("g", { "data-hex-gantt-deps": true, fill: "none", children: laidOut.deps.map((d) => {
107
+ const ELBOW = 8;
108
+ const needsJog = d.to.x < d.from.x + ELBOW;
109
+ const path = needsJog ? `M${d.from.x},${d.from.y} L${d.from.x + ELBOW},${d.from.y} L${d.from.x + ELBOW},${d.to.y} L${d.to.x},${d.to.y}` : `M${d.from.x},${d.from.y} L${(d.from.x + d.to.x) / 2},${d.from.y} L${(d.from.x + d.to.x) / 2},${d.to.y} L${d.to.x},${d.to.y}`;
110
+ return /* @__PURE__ */ jsx(
111
+ "path",
112
+ {
113
+ "data-hex-gantt-dep": true,
114
+ d: path,
115
+ stroke: "hsl(var(--muted-foreground))",
116
+ strokeOpacity: 0.55,
117
+ strokeWidth: 1,
118
+ markerEnd: `url(#hex-gantt-arrow-${arrowId})`
119
+ },
120
+ d.id
121
+ );
122
+ }) }),
123
+ /* @__PURE__ */ jsx("g", { "data-hex-gantt-tasks": true, children: laidOut.tasks.map((t) => {
124
+ const interactive = Boolean(onTaskClick);
125
+ const handleActivate = () => onTaskClick?.(t.task);
126
+ return /* @__PURE__ */ jsxs(
127
+ "g",
128
+ {
129
+ "data-hex-gantt-task": true,
130
+ "data-row": t.rowIndex,
131
+ role: interactive ? "button" : void 0,
132
+ tabIndex: interactive ? 0 : void 0,
133
+ "aria-label": interactive ? `${t.task.label}, ${formatDate(toDate(t.task.start))} to ${formatDate(toDate(t.task.end))}${t.task.progress != null ? `, ${Math.round((t.task.progress ?? 0) * 100)}% complete` : ""}` : void 0,
134
+ style: interactive ? { cursor: "pointer" } : void 0,
135
+ onClick: interactive ? handleActivate : void 0,
136
+ onKeyDown: interactive ? (e) => activateOnKey(e, handleActivate) : void 0,
137
+ children: [
138
+ /* @__PURE__ */ jsx(
139
+ "rect",
140
+ {
141
+ x: t.x,
142
+ y: t.y,
143
+ width: Math.max(2, t.w),
144
+ height: t.h,
145
+ rx: 4,
146
+ ry: 4,
147
+ fill: "hsl(var(--primary))",
148
+ fillOpacity: 0.25,
149
+ stroke: "hsl(var(--primary))",
150
+ strokeWidth: 1
151
+ }
152
+ ),
153
+ t.progressW > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
154
+ /* @__PURE__ */ jsx(
155
+ "rect",
156
+ {
157
+ x: t.x,
158
+ y: t.y,
159
+ width: t.progressW,
160
+ height: t.h,
161
+ rx: 4,
162
+ ry: 4,
163
+ fill: "hsl(var(--primary))",
164
+ fillOpacity: 0.7
165
+ }
166
+ ),
167
+ t.progressW < t.w - 0.5 ? /* @__PURE__ */ jsx(
168
+ "line",
169
+ {
170
+ x1: t.x + t.progressW,
171
+ x2: t.x + t.progressW,
172
+ y1: t.y,
173
+ y2: t.y + t.h,
174
+ stroke: "hsl(var(--primary))",
175
+ strokeWidth: 1
176
+ }
177
+ ) : null
178
+ ] }) : null
179
+ ]
180
+ },
181
+ t.task.id
182
+ );
183
+ }) })
184
+ ]
185
+ }
186
+ );
187
+ }
188
+ function layout(tasks, width, rowHeight, labelMargin, tickCount) {
189
+ if (tasks.length === 0) {
190
+ return { tasks: [], deps: [], ticks: [], startLabel: "\u2014", endLabel: "\u2014" };
191
+ }
192
+ const axisLeft = labelMargin;
193
+ const axisRight = width - 16;
194
+ const usable = axisRight - axisLeft;
195
+ const allTimes = tasks.flatMap((t) => [toDate(t.start).getTime(), toDate(t.end).getTime()]).filter((t) => Number.isFinite(t));
196
+ if (allTimes.length === 0) {
197
+ return { tasks: [], deps: [], ticks: [], startLabel: "\u2014", endLabel: "\u2014" };
198
+ }
199
+ const minTs = Math.min(...allTimes);
200
+ const maxTs = Math.max(...allTimes);
201
+ const span = Math.max(1, maxTs - minTs);
202
+ const tToX = (t) => axisLeft + (t - minTs) / span * usable;
203
+ const laidOutTasks = tasks.map((task, i) => {
204
+ const startTs = toDate(task.start).getTime();
205
+ const endTs = toDate(task.end).getTime();
206
+ const x = tToX(startTs);
207
+ const w = Math.max(0, tToX(endTs) - x);
208
+ const y = HEADER_HEIGHT + i * rowHeight + ROW_PADDING / 2;
209
+ const h = rowHeight - ROW_PADDING;
210
+ const progress = clamp01(task.progress ?? 0);
211
+ return {
212
+ task,
213
+ rowIndex: i,
214
+ x,
215
+ y,
216
+ w,
217
+ h,
218
+ progressW: w * progress
219
+ };
220
+ });
221
+ const byId = new Map(laidOutTasks.map((t) => [t.task.id, t]));
222
+ const deps = [];
223
+ laidOutTasks.forEach((t) => {
224
+ (t.task.dependencies ?? []).forEach((depId, k) => {
225
+ const from = byId.get(depId);
226
+ if (!from) return;
227
+ deps.push({
228
+ from: { x: from.x + from.w, y: from.y + from.h / 2 },
229
+ to: { x: t.x, y: t.y + t.h / 2 },
230
+ id: `${depId}-${t.task.id}-${k}`
231
+ });
232
+ });
233
+ });
234
+ const rawTicks = [];
235
+ for (let i = 0; i < tickCount; i++) {
236
+ const ts = minTs + i / Math.max(1, tickCount - 1) * span;
237
+ rawTicks.push({ x: tToX(ts), label: formatTick(new Date(ts), span) });
238
+ }
239
+ const ticks = rawTicks.map((t, i) => ({
240
+ x: t.x,
241
+ label: i > 0 && rawTicks[i - 1]?.label === t.label ? "" : t.label
242
+ }));
243
+ return {
244
+ tasks: laidOutTasks,
245
+ deps,
246
+ ticks,
247
+ startLabel: formatDate(new Date(minTs)),
248
+ endLabel: formatDate(new Date(maxTs))
249
+ };
250
+ }
251
+ function toDate(v) {
252
+ if (v instanceof Date) return v;
253
+ if (typeof v === "number") return new Date(v);
254
+ return new Date(v);
255
+ }
256
+ function clamp01(v) {
257
+ return v < 0 ? 0 : v > 1 ? 1 : v;
258
+ }
259
+ function formatDate(d) {
260
+ if (Number.isNaN(d.getTime())) return "\u2014";
261
+ return d.toISOString().slice(0, 10);
262
+ }
263
+ function formatTick(d, spanMs) {
264
+ if (Number.isNaN(d.getTime())) return "\u2014";
265
+ const ONE_DAY = 24 * 60 * 60 * 1e3;
266
+ if (spanMs <= 90 * ONE_DAY) return d.toISOString().slice(5, 10);
267
+ if (spanMs <= 730 * ONE_DAY) return d.toISOString().slice(0, 7);
268
+ return String(d.getUTCFullYear());
269
+ }
270
+ function activateOnKey(e, fn) {
271
+ if (e.key === "Enter" || e.key === " ") {
272
+ e.preventDefault();
273
+ fn();
274
+ }
275
+ }
276
+
277
+ export { Gantt };
278
+ //# sourceMappingURL=gantt.js.map
279
+ //# sourceMappingURL=gantt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/gantt/gantt.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;AC4DA,IAAM,aAAA,GAAgB,EAAA;AACtB,IAAM,WAAA,GAAc,CAAA;AAEpB,SAAS,KAAA,CAAM;AAAA,EACd,KAAA;AAAA,EACA,KAAA,GAAQ,GAAA;AAAA,EACR,SAAA,GAAY,EAAA;AAAA,EACZ,WAAA,GAAc,GAAA;AAAA,EACd,SAAA,GAAY,CAAA;AAAA,EACZ,WAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACJ,CAAA,EAAe;AACd,EAAA,MAAM,OAAA,GAAgB,KAAA,CAAA,OAAA;AAAA,IACrB,MAAM,MAAA,CAAO,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,aAAa,SAAS,CAAA;AAAA,IAC5D,CAAC,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,aAAa,SAAS;AAAA,GACjD;AAEA,EAAA,MAAM,WAAA,GAAc,aAAA,GAAgB,KAAA,CAAM,MAAA,GAAS,SAAA,GAAY,WAAA;AAC/D,EAAA,MAAM,IAAA,GAAO,CAAA,WAAA,EAAc,KAAA,CAAM,MAAM,QAAQ,KAAA,CAAM,MAAA,KAAW,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,QAAA,EAAW,OAAA,CAAQ,UAAU,CAAA,IAAA,EAAO,QAAQ,QAAQ,CAAA,CAAA;AAGhI,EAAA,MAAM,OAAA,GAAgB,KAAA,CAAA,KAAA,EAAM,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AAE/C,EAAA,uBACC,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAG,IAAA;AAAA,MACJ,gBAAA,EAAc,IAAA;AAAA,MACd,IAAA,EAAK,KAAA;AAAA,MACL,KAAA;AAAA,MACA,MAAA,EAAQ,WAAA;AAAA,MACR,OAAA,EAAS,CAAA,IAAA,EAAO,KAAK,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAAA,MACpC,SAAA,EAAW,EAAA,CAAG,OAAA,EAAS,SAAS,CAAA;AAAA,MAEhC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,WAAM,QAAA,EAAA,aAAA,EAAW,CAAA;AAAA,wBAClB,GAAA,CAAC,UAAM,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,4BACX,MAAA,EAAA,EACA,QAAA,kBAAA,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACA,EAAA,EAAI,mBAAmB,OAAO,CAAA,CAAA;AAAA,YAC9B,OAAA,EAAQ,WAAA;AAAA,YACR,IAAA,EAAK,IAAA;AAAA,YACL,IAAA,EAAK,GAAA;AAAA,YACL,WAAA,EAAY,GAAA;AAAA,YACZ,YAAA,EAAa,GAAA;AAAA,YACb,MAAA,EAAO,oBAAA;AAAA,YAEP,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,uBAAA,EAAwB,MAAK,8BAAA,EAA+B;AAAA;AAAA,SACrE,EACD,CAAA;AAAA,wBAEA,IAAA,CAAC,GAAA,EAAA,EAAE,qBAAA,EAAmB,IAAA,EACrB,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACA,EAAA,EAAI,WAAA;AAAA,cACJ,IAAI,KAAA,GAAQ,EAAA;AAAA,cACZ,IAAI,aAAA,GAAgB,CAAA;AAAA,cACpB,IAAI,aAAA,GAAgB,CAAA;AAAA,cACpB,MAAA,EAAO,8BAAA;AAAA,cACP,WAAA,EAAa;AAAA;AAAA,WACd;AAAA,UACC,OAAA,CAAQ,MAAM,GAAA,CAAI,CAAC,GAAG,CAAA,qBACtB,IAAA,CAAC,GAAA,EAAA,EAAoB,qBAAA,EAAmB,IAAA,EACvC,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACA,IAAI,CAAA,CAAE,CAAA;AAAA,gBACN,IAAI,CAAA,CAAE,CAAA;AAAA,gBACN,IAAI,aAAA,GAAgB,CAAA;AAAA,gBACpB,IAAI,WAAA,GAAc,CAAA;AAAA,gBAClB,MAAA,EAAO,8BAAA;AAAA,gBACP,aAAA,EAAe,IAAA;AAAA,gBACf,WAAA,EAAa;AAAA;AAAA,aACd;AAAA,4BACA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACA,GAAG,CAAA,CAAE,CAAA;AAAA,gBACL,GAAG,aAAA,GAAgB,EAAA;AAAA,gBACnB,UAAA,EAAW,QAAA;AAAA,gBACX,QAAA,EAAU,EAAA;AAAA,gBACV,IAAA,EAAK,8BAAA;AAAA,gBAEJ,QAAA,EAAA,CAAA,CAAE;AAAA;AAAA;AACJ,WAAA,EAAA,EAlBO,CAAA,KAAA,EAAQ,CAAC,CAAA,CAmBjB,CACA;AAAA,SAAA,EACF,CAAA;AAAA,wBAEA,GAAA,CAAC,OAAE,uBAAA,EAAqB,IAAA,EACtB,kBAAQ,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,qBACnB,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YAEA,GAAG,WAAA,GAAc,CAAA;AAAA,YACjB,CAAA,EAAG,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA,GAAI,CAAA;AAAA,YACf,EAAA,EAAG,QAAA;AAAA,YACH,UAAA,EAAW,KAAA;AAAA,YACX,QAAA,EAAU,EAAA;AAAA,YACV,IAAA,EAAK,wBAAA;AAAA,YAEJ,YAAE,IAAA,CAAK;AAAA,WAAA;AAAA,UARH,CAAA,MAAA,EAAS,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA;AAAA,SAUxB,CAAA,EACF,CAAA;AAAA,wBAIA,GAAA,CAAC,GAAA,EAAA,EAAE,qBAAA,EAAmB,IAAA,EAAC,IAAA,EAAK,QAC1B,QAAA,EAAA,OAAA,CAAQ,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM;AACxB,UAAA,MAAM,KAAA,GAAQ,CAAA;AACd,UAAA,MAAM,WAAW,CAAA,CAAE,EAAA,CAAG,CAAA,GAAI,CAAA,CAAE,KAAK,CAAA,GAAI,KAAA;AACrC,UAAA,MAAM,OAAO,QAAA,GACV,CAAA,CAAA,EAAI,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,IAAA,CAAK,CAAC,KAAK,CAAA,CAAE,IAAA,CAAK,CAAA,GAAI,KAAK,IAAI,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAA,EAAK,EAAE,IAAA,CAAK,CAAA,GAAI,KAAK,CAAA,CAAA,EAAI,EAAE,EAAA,CAAG,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,GAAG,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,EAAA,CAAG,CAAC,CAAA,CAAA,GAC7G,CAAA,CAAA,EAAI,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,CAAK,CAAA,GAAI,CAAA,CAAE,GAAG,CAAA,IAAK,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAC,CAAA,EAAA,EAAA,CAAM,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,CAAE,EAAA,CAAG,CAAA,IAAK,CAAC,IAAI,CAAA,CAAE,EAAA,CAAG,CAAC,CAAA,EAAA,EAAK,EAAE,EAAA,CAAG,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,GAAG,CAAC,CAAA,CAAA;AAC9H,UAAA,uBACC,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cAEA,oBAAA,EAAkB,IAAA;AAAA,cAClB,CAAA,EAAG,IAAA;AAAA,cACH,MAAA,EAAO,8BAAA;AAAA,cACP,aAAA,EAAe,IAAA;AAAA,cACf,WAAA,EAAa,CAAA;AAAA,cACb,SAAA,EAAW,wBAAwB,OAAO,CAAA,CAAA;AAAA,aAAA;AAAA,YANrC,CAAA,CAAE;AAAA,WAOR;AAAA,QAEF,CAAC,CAAA,EACF,CAAA;AAAA,wBAEA,GAAA,CAAC,OAAE,sBAAA,EAAoB,IAAA,EACrB,kBAAQ,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AACzB,UAAA,MAAM,WAAA,GAAc,QAAQ,WAAW,CAAA;AACvC,UAAA,MAAM,cAAA,GAAiB,MAAM,WAAA,GAAc,CAAA,CAAE,IAAI,CAAA;AACjD,UAAA,uBACC,IAAA;AAAA,YAAC,GAAA;AAAA,YAAA;AAAA,cAEA,qBAAA,EAAmB,IAAA;AAAA,cACnB,YAAU,CAAA,CAAE,QAAA;AAAA,cACZ,IAAA,EAAM,cAAc,QAAA,GAAW,MAAA;AAAA,cAC/B,QAAA,EAAU,cAAc,CAAA,GAAI,MAAA;AAAA,cAC5B,cACC,WAAA,GACG,CAAA,EAAG,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA,EAAA,EAAK,UAAA,CAAW,MAAA,CAAO,CAAA,CAAE,KAAK,KAAK,CAAC,CAAC,CAAA,IAAA,EAAO,UAAA,CAAW,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAC,CAAA,EAAG,CAAA,CAAE,IAAA,CAAK,QAAA,IAAY,OAAO,CAAA,EAAA,EAAK,IAAA,CAAK,KAAA,CAAA,CAAO,CAAA,CAAE,KAAK,QAAA,IAAY,CAAA,IAAK,GAAG,CAAC,CAAA,UAAA,CAAA,GAAe,EAAE,CAAA,CAAA,GACpL,MAAA;AAAA,cAEJ,KAAA,EAAO,WAAA,GAAc,EAAE,MAAA,EAAQ,WAAU,GAAI,MAAA;AAAA,cAC7C,OAAA,EAAS,cAAc,cAAA,GAAiB,MAAA;AAAA,cACxC,WAAW,WAAA,GAAc,CAAC,MAAM,aAAA,CAAc,CAAA,EAAG,cAAc,CAAA,GAAI,MAAA;AAAA,cAEnE,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACA,GAAG,CAAA,CAAE,CAAA;AAAA,oBACL,GAAG,CAAA,CAAE,CAAA;AAAA,oBACL,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAE,CAAC,CAAA;AAAA,oBACtB,QAAQ,CAAA,CAAE,CAAA;AAAA,oBACV,EAAA,EAAI,CAAA;AAAA,oBACJ,EAAA,EAAI,CAAA;AAAA,oBACJ,IAAA,EAAK,qBAAA;AAAA,oBACL,WAAA,EAAa,IAAA;AAAA,oBACb,MAAA,EAAO,qBAAA;AAAA,oBACP,WAAA,EAAa;AAAA;AAAA,iBACd;AAAA,gBACC,CAAA,CAAE,SAAA,GAAY,CAAA,mBACd,IAAA,CAAA,QAAA,EAAA,EACC,QAAA,EAAA;AAAA,kCAAA,GAAA;AAAA,oBAAC,MAAA;AAAA,oBAAA;AAAA,sBACA,GAAG,CAAA,CAAE,CAAA;AAAA,sBACL,GAAG,CAAA,CAAE,CAAA;AAAA,sBACL,OAAO,CAAA,CAAE,SAAA;AAAA,sBACT,QAAQ,CAAA,CAAE,CAAA;AAAA,sBACV,EAAA,EAAI,CAAA;AAAA,sBACJ,EAAA,EAAI,CAAA;AAAA,sBACJ,IAAA,EAAK,qBAAA;AAAA,sBACL,WAAA,EAAa;AAAA;AAAA,mBACd;AAAA,kBAIC,CAAA,CAAE,SAAA,GAAY,CAAA,CAAE,CAAA,GAAI,GAAA,mBACpB,GAAA;AAAA,oBAAC,MAAA;AAAA,oBAAA;AAAA,sBACA,EAAA,EAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,SAAA;AAAA,sBACZ,EAAA,EAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,SAAA;AAAA,sBACZ,IAAI,CAAA,CAAE,CAAA;AAAA,sBACN,EAAA,EAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA;AAAA,sBACZ,MAAA,EAAO,qBAAA;AAAA,sBACP,WAAA,EAAa;AAAA;AAAA,mBACd,GACG;AAAA,iBAAA,EACL,CAAA,GACG;AAAA;AAAA,aAAA;AAAA,YApDC,EAAE,IAAA,CAAK;AAAA,WAqDb;AAAA,QAEF,CAAC,CAAA,EACF;AAAA;AAAA;AAAA,GACD;AAEF;AAEA,SAAS,MAAA,CACR,KAAA,EACA,KAAA,EACA,SAAA,EACA,aACA,SAAA,EAOC;AACD,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAE,KAAA,EAAO,EAAC,EAAG,IAAA,EAAM,EAAC,EAAG,KAAA,EAAO,EAAC,EAAG,UAAA,EAAY,QAAA,EAAK,UAAU,QAAA,EAAI;AAAA,EACzE;AAEA,EAAA,MAAM,QAAA,GAAW,WAAA;AACjB,EAAA,MAAM,YAAY,KAAA,GAAQ,EAAA;AAC1B,EAAA,MAAM,SAAS,SAAA,GAAY,QAAA;AAM3B,EAAA,MAAM,QAAA,GAAW,KAAA,CACf,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAC,MAAA,CAAO,CAAA,CAAE,KAAK,CAAA,CAAE,OAAA,EAAQ,EAAG,MAAA,CAAO,EAAE,GAAG,CAAA,CAAE,OAAA,EAAS,CAAC,CAAA,CACnE,MAAA,CAAO,CAAC,CAAA,KAAM,MAAA,CAAO,QAAA,CAAS,CAAC,CAAC,CAAA;AAClC,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAC1B,IAAA,OAAO,EAAE,KAAA,EAAO,EAAC,EAAG,IAAA,EAAM,EAAC,EAAG,KAAA,EAAO,EAAC,EAAG,UAAA,EAAY,QAAA,EAAK,UAAU,QAAA,EAAI;AAAA,EACzE;AACA,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AAClC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AAClC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,QAAQ,KAAK,CAAA;AAEtC,EAAA,MAAM,OAAO,CAAC,CAAA,KAAc,QAAA,GAAA,CAAa,CAAA,GAAI,SAAS,IAAA,GAAQ,MAAA;AAE9D,EAAA,MAAM,YAAA,GAA8B,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,CAAA,KAAM;AAC1D,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,KAAK,EAAE,OAAA,EAAQ;AAC3C,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,GAAG,EAAE,OAAA,EAAQ;AACvC,IAAA,MAAM,CAAA,GAAI,KAAK,OAAO,CAAA;AACtB,IAAA,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAK,IAAI,CAAC,CAAA;AACrC,IAAA,MAAM,CAAA,GAAI,aAAA,GAAgB,CAAA,GAAI,SAAA,GAAY,WAAA,GAAc,CAAA;AACxD,IAAA,MAAM,IAAI,SAAA,GAAY,WAAA;AACtB,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,IAAA,CAAK,QAAA,IAAY,CAAC,CAAA;AAC3C,IAAA,OAAO;AAAA,MACN,IAAA;AAAA,MACA,QAAA,EAAU,CAAA;AAAA,MACV,CAAA;AAAA,MACA,CAAA;AAAA,MACA,CAAA;AAAA,MACA,CAAA;AAAA,MACA,WAAW,CAAA,GAAI;AAAA,KAChB;AAAA,EACD,CAAC,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,IAAA,CAAK,EAAA,EAAI,CAAC,CAAC,CAAC,CAAA;AAC5D,EAAA,MAAM,OAAmB,EAAC;AAC1B,EAAA,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA,KAAM;AAC3B,IAAA,CAAC,CAAA,CAAE,KAAK,YAAA,IAAgB,IAAI,OAAA,CAAQ,CAAC,OAAO,CAAA,KAAM;AACjD,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC3B,MAAA,IAAI,CAAC,IAAA,EAAM;AACX,MAAA,IAAA,CAAK,IAAA,CAAK;AAAA,QACT,IAAA,EAAM,EAAE,CAAA,EAAG,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,CAAA,EAAG,CAAA,EAAG,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,CAAA,GAAI,CAAA,EAAE;AAAA,QACnD,EAAA,EAAI,EAAE,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,GAAG,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA,GAAI,CAAA,EAAE;AAAA,QAC/B,EAAA,EAAI,GAAG,KAAK,CAAA,CAAA,EAAI,EAAE,IAAA,CAAK,EAAE,IAAI,CAAC,CAAA;AAAA,OAC9B,CAAA;AAAA,IACF,CAAC,CAAA;AAAA,EACF,CAAC,CAAA;AAMD,EAAA,MAAM,WAAuB,EAAC;AAC9B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,EAAW,CAAA,EAAA,EAAK;AACnC,IAAA,MAAM,EAAA,GAAK,QAAS,CAAA,GAAI,IAAA,CAAK,IAAI,CAAA,EAAG,SAAA,GAAY,CAAC,CAAA,GAAK,IAAA;AACtD,IAAA,QAAA,CAAS,IAAA,CAAK,EAAE,CAAA,EAAG,IAAA,CAAK,EAAE,CAAA,EAAG,KAAA,EAAO,UAAA,CAAW,IAAI,IAAA,CAAK,EAAE,CAAA,EAAG,IAAI,GAAG,CAAA;AAAA,EACrE;AACA,EAAA,MAAM,KAAA,GAAoB,QAAA,CAAS,GAAA,CAAI,CAAC,GAAG,CAAA,MAAO;AAAA,IACjD,GAAG,CAAA,CAAE,CAAA;AAAA,IACL,KAAA,EAAO,CAAA,GAAI,CAAA,IAAK,QAAA,CAAS,CAAA,GAAI,CAAC,CAAA,EAAG,KAAA,KAAU,CAAA,CAAE,KAAA,GAAQ,EAAA,GAAK,CAAA,CAAE;AAAA,GAC7D,CAAE,CAAA;AAEF,EAAA,OAAO;AAAA,IACN,KAAA,EAAO,YAAA;AAAA,IACP,IAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA,EAAY,UAAA,CAAW,IAAI,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,IACtC,QAAA,EAAU,UAAA,CAAW,IAAI,IAAA,CAAK,KAAK,CAAC;AAAA,GACrC;AACD;AAEA,SAAS,OAAO,CAAA,EAAiC;AAChD,EAAA,IAAI,CAAA,YAAa,MAAM,OAAO,CAAA;AAC9B,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,IAAI,KAAK,CAAC,CAAA;AAC5C,EAAA,OAAO,IAAI,KAAK,CAAC,CAAA;AAClB;AAEA,SAAS,QAAQ,CAAA,EAAmB;AACnC,EAAA,OAAO,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AAChC;AAEA,SAAS,WAAW,CAAA,EAAiB;AACpC,EAAA,IAAI,OAAO,KAAA,CAAM,CAAA,CAAE,OAAA,EAAS,GAAG,OAAO,QAAA;AACtC,EAAA,OAAO,CAAA,CAAE,WAAA,EAAY,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AACnC;AAEA,SAAS,UAAA,CAAW,GAAS,MAAA,EAAwB;AACpD,EAAA,IAAI,OAAO,KAAA,CAAM,CAAA,CAAE,OAAA,EAAS,GAAG,OAAO,QAAA;AACtC,EAAA,MAAM,OAAA,GAAU,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAI/B,EAAA,IAAI,MAAA,IAAU,KAAK,OAAA,EAAS,OAAO,EAAE,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAC9D,EAAA,IAAI,MAAA,IAAU,MAAM,OAAA,EAAS,OAAO,EAAE,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AAC9D,EAAA,OAAO,MAAA,CAAO,CAAA,CAAE,cAAA,EAAgB,CAAA;AACjC;AAEA,SAAS,aAAA,CAAc,GAAwB,EAAA,EAAsB;AACpE,EAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,OAAA,IAAW,CAAA,CAAE,QAAQ,GAAA,EAAK;AACvC,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,EAAA,EAAG;AAAA,EACJ;AACD","file":"gantt.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Gantt chart — tasks as horizontal bars across a time axis, with\n * optional dependency arrows and progress fills. Pure SVG; no heavy\n * peer dependency.\n *\n * Distinct from TimeAxis (point events) and Sequence (actor messages):\n * Gantt encodes DURATION (start → end) per task and supports task-to-\n * task dependency arrows.\n *\n * @example\n * <Gantt\n * tasks={[\n * { id: \"design\", label: \"Design\", start: \"2025-01-01\", end: \"2025-01-15\", progress: 1 },\n * { id: \"build\", label: \"Build\", start: \"2025-01-10\", end: \"2025-02-20\", progress: 0.6, dependencies: [\"design\"] },\n * { id: \"ship\", label: \"Ship\", start: \"2025-02-15\", end: \"2025-02-28\", dependencies: [\"build\"] },\n * ]}\n * />\n */\nexport type GanttTask = {\n\tid: string;\n\tlabel: string;\n\tstart: Date | string | number;\n\tend: Date | string | number;\n\t/** Optional progress 0..1; renders as a filled portion of the bar. */\n\tprogress?: number;\n\t/** Optional list of task ids this task depends on; arrow drawn from each. */\n\tdependencies?: string[];\n};\n\nexport interface GanttProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n\t/** Tasks in display order (rows top-to-bottom). */\n\ttasks: GanttTask[];\n\t/** Pixel width of the rendered SVG. Default 800. */\n\twidth?: number;\n\t/** Pixel height of each task row. Default 32. */\n\trowHeight?: number;\n\t/** Pixel reserved on the left for task labels. Default 140. */\n\tlabelMargin?: number;\n\t/** Number of axis ticks to show. Default 6. */\n\ttickCount?: number;\n\t/** Fired when a task bar is clicked. */\n\tonTaskClick?: (task: GanttTask) => void;\n}\n\ninterface LaidOutTask {\n\ttask: GanttTask;\n\trowIndex: number;\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n\tprogressW: number;\n}\n\ninterface DepArrow {\n\tfrom: { x: number; y: number };\n\tto: { x: number; y: number };\n\tid: string;\n}\n\ninterface AxisTick {\n\tx: number;\n\tlabel: string;\n}\n\nconst HEADER_HEIGHT = 40;\nconst ROW_PADDING = 6;\n\nfunction Gantt({\n\ttasks,\n\twidth = 800,\n\trowHeight = 32,\n\tlabelMargin = 140,\n\ttickCount = 6,\n\tonTaskClick,\n\tclassName,\n\t...rest\n}: GanttProps) {\n\tconst laidOut = React.useMemo(\n\t\t() => layout(tasks, width, rowHeight, labelMargin, tickCount),\n\t\t[tasks, width, rowHeight, labelMargin, tickCount],\n\t);\n\n\tconst totalHeight = HEADER_HEIGHT + tasks.length * rowHeight + ROW_PADDING;\n\tconst desc = `Gantt with ${tasks.length} task${tasks.length === 1 ? \"\" : \"s\"}, range ${laidOut.startLabel} to ${laidOut.endLabel}`;\n\t// Per-instance arrowhead marker id keeps two <Gantt> on a page\n\t// from sharing a <defs> id.\n\tconst arrowId = React.useId().replace(/:/g, \"-\");\n\n\treturn (\n\t\t<svg\n\t\t\t{...rest}\n\t\t\tdata-hex-gantt\n\t\t\trole=\"img\"\n\t\t\twidth={width}\n\t\t\theight={totalHeight}\n\t\t\tviewBox={`0 0 ${width} ${totalHeight}`}\n\t\t\tclassName={cn(\"block\", className)}\n\t\t>\n\t\t\t<title>Gantt chart</title>\n\t\t\t<desc>{desc}</desc>\n\t\t\t<defs>\n\t\t\t\t<marker\n\t\t\t\t\tid={`hex-gantt-arrow-${arrowId}`}\n\t\t\t\t\tviewBox=\"0 0 10 10\"\n\t\t\t\t\trefX=\"10\"\n\t\t\t\t\trefY=\"5\"\n\t\t\t\t\tmarkerWidth=\"5\"\n\t\t\t\t\tmarkerHeight=\"5\"\n\t\t\t\t\torient=\"auto-start-reverse\"\n\t\t\t\t>\n\t\t\t\t\t<path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"hsl(var(--muted-foreground))\" />\n\t\t\t\t</marker>\n\t\t\t</defs>\n\t\t\t{/* Axis header */}\n\t\t\t<g data-hex-gantt-axis>\n\t\t\t\t<line\n\t\t\t\t\tx1={labelMargin}\n\t\t\t\t\tx2={width - 16}\n\t\t\t\t\ty1={HEADER_HEIGHT - 8}\n\t\t\t\t\ty2={HEADER_HEIGHT - 8}\n\t\t\t\t\tstroke=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t/>\n\t\t\t\t{laidOut.ticks.map((t, i) => (\n\t\t\t\t\t<g key={`tick-${i}`} data-hex-gantt-tick>\n\t\t\t\t\t\t<line\n\t\t\t\t\t\t\tx1={t.x}\n\t\t\t\t\t\t\tx2={t.x}\n\t\t\t\t\t\t\ty1={HEADER_HEIGHT - 8}\n\t\t\t\t\t\t\ty2={totalHeight - 4}\n\t\t\t\t\t\t\tstroke=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\t\t\tstrokeOpacity={0.15}\n\t\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\tx={t.x}\n\t\t\t\t\t\t\ty={HEADER_HEIGHT - 14}\n\t\t\t\t\t\t\ttextAnchor=\"middle\"\n\t\t\t\t\t\t\tfontSize={10}\n\t\t\t\t\t\t\tfill=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t.label}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t</g>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t{/* Row labels */}\n\t\t\t<g data-hex-gantt-labels>\n\t\t\t\t{laidOut.tasks.map((t) => (\n\t\t\t\t\t<text\n\t\t\t\t\t\tkey={`label-${t.task.id}`}\n\t\t\t\t\t\tx={labelMargin - 8}\n\t\t\t\t\t\ty={t.y + t.h / 2}\n\t\t\t\t\t\tdy=\"0.35em\"\n\t\t\t\t\t\ttextAnchor=\"end\"\n\t\t\t\t\t\tfontSize={11}\n\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{t.task.label}\n\t\t\t\t\t</text>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t{/* Dependency arrows: elbow-and-jog routing — when the target\n\t\t\t task starts before (or near) the source's right edge, route\n\t\t\t out past the source first to avoid drawing through its bar. */}\n\t\t\t<g data-hex-gantt-deps fill=\"none\">\n\t\t\t\t{laidOut.deps.map((d) => {\n\t\t\t\t\tconst ELBOW = 8;\n\t\t\t\t\tconst needsJog = d.to.x < d.from.x + ELBOW;\n\t\t\t\t\tconst path = needsJog\n\t\t\t\t\t\t? `M${d.from.x},${d.from.y} L${d.from.x + ELBOW},${d.from.y} L${d.from.x + ELBOW},${d.to.y} L${d.to.x},${d.to.y}`\n\t\t\t\t\t\t: `M${d.from.x},${d.from.y} L${(d.from.x + d.to.x) / 2},${d.from.y} L${(d.from.x + d.to.x) / 2},${d.to.y} L${d.to.x},${d.to.y}`;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\tkey={d.id}\n\t\t\t\t\t\t\tdata-hex-gantt-dep\n\t\t\t\t\t\t\td={path}\n\t\t\t\t\t\t\tstroke=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\t\t\tstrokeOpacity={0.55}\n\t\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\t\tmarkerEnd={`url(#hex-gantt-arrow-${arrowId})`}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</g>\n\t\t\t{/* Task bars */}\n\t\t\t<g data-hex-gantt-tasks>\n\t\t\t\t{laidOut.tasks.map((t) => {\n\t\t\t\t\tconst interactive = Boolean(onTaskClick);\n\t\t\t\t\tconst handleActivate = () => onTaskClick?.(t.task);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<g\n\t\t\t\t\t\t\tkey={t.task.id}\n\t\t\t\t\t\t\tdata-hex-gantt-task\n\t\t\t\t\t\t\tdata-row={t.rowIndex}\n\t\t\t\t\t\t\trole={interactive ? \"button\" : undefined}\n\t\t\t\t\t\t\ttabIndex={interactive ? 0 : undefined}\n\t\t\t\t\t\t\taria-label={\n\t\t\t\t\t\t\t\tinteractive\n\t\t\t\t\t\t\t\t\t? `${t.task.label}, ${formatDate(toDate(t.task.start))} to ${formatDate(toDate(t.task.end))}${t.task.progress != null ? `, ${Math.round((t.task.progress ?? 0) * 100)}% complete` : \"\"}`\n\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstyle={interactive ? { cursor: \"pointer\" } : undefined}\n\t\t\t\t\t\t\tonClick={interactive ? handleActivate : undefined}\n\t\t\t\t\t\t\tonKeyDown={interactive ? (e) => activateOnKey(e, handleActivate) : undefined}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t\tx={t.x}\n\t\t\t\t\t\t\t\ty={t.y}\n\t\t\t\t\t\t\t\twidth={Math.max(2, t.w)}\n\t\t\t\t\t\t\t\theight={t.h}\n\t\t\t\t\t\t\t\trx={4}\n\t\t\t\t\t\t\t\try={4}\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\tfillOpacity={0.25}\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{t.progressW > 0 ? (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t\t\t\tx={t.x}\n\t\t\t\t\t\t\t\t\t\ty={t.y}\n\t\t\t\t\t\t\t\t\t\twidth={t.progressW}\n\t\t\t\t\t\t\t\t\t\theight={t.h}\n\t\t\t\t\t\t\t\t\t\trx={4}\n\t\t\t\t\t\t\t\t\t\try={4}\n\t\t\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\t\t\tfillOpacity={0.7}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t{/* Hard right-edge line keeps the progress boundary visible for\n\t\t\t\t\t\t\t\t\t color-blind viewers and on low-contrast themes. Skipped at\n\t\t\t\t\t\t\t\t\t 100% progress where it overlaps the bar's own border. */}\n\t\t\t\t\t\t\t\t\t{t.progressW < t.w - 0.5 ? (\n\t\t\t\t\t\t\t\t\t\t<line\n\t\t\t\t\t\t\t\t\t\t\tx1={t.x + t.progressW}\n\t\t\t\t\t\t\t\t\t\t\tx2={t.x + t.progressW}\n\t\t\t\t\t\t\t\t\t\t\ty1={t.y}\n\t\t\t\t\t\t\t\t\t\t\ty2={t.y + t.h}\n\t\t\t\t\t\t\t\t\t\t\tstroke=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</g>\n\t\t</svg>\n\t);\n}\n\nfunction layout(\n\ttasks: GanttTask[],\n\twidth: number,\n\trowHeight: number,\n\tlabelMargin: number,\n\ttickCount: number,\n): {\n\ttasks: LaidOutTask[];\n\tdeps: DepArrow[];\n\tticks: AxisTick[];\n\tstartLabel: string;\n\tendLabel: string;\n} {\n\tif (tasks.length === 0) {\n\t\treturn { tasks: [], deps: [], ticks: [], startLabel: \"—\", endLabel: \"—\" };\n\t}\n\n\tconst axisLeft = labelMargin;\n\tconst axisRight = width - 16;\n\tconst usable = axisRight - axisLeft;\n\n\t// Drop NaN-bearing endpoints so the axis range stays finite. Tasks with\n\t// either bound un-parseable get rendered with their own zero-width\n\t// fallback below; we still want them in the row layout, just clipped to\n\t// the axis edges.\n\tconst allTimes = tasks\n\t\t.flatMap((t) => [toDate(t.start).getTime(), toDate(t.end).getTime()])\n\t\t.filter((t) => Number.isFinite(t));\n\tif (allTimes.length === 0) {\n\t\treturn { tasks: [], deps: [], ticks: [], startLabel: \"—\", endLabel: \"—\" };\n\t}\n\tconst minTs = Math.min(...allTimes);\n\tconst maxTs = Math.max(...allTimes);\n\tconst span = Math.max(1, maxTs - minTs);\n\n\tconst tToX = (t: number) => axisLeft + ((t - minTs) / span) * usable;\n\n\tconst laidOutTasks: LaidOutTask[] = tasks.map((task, i) => {\n\t\tconst startTs = toDate(task.start).getTime();\n\t\tconst endTs = toDate(task.end).getTime();\n\t\tconst x = tToX(startTs);\n\t\tconst w = Math.max(0, tToX(endTs) - x);\n\t\tconst y = HEADER_HEIGHT + i * rowHeight + ROW_PADDING / 2;\n\t\tconst h = rowHeight - ROW_PADDING;\n\t\tconst progress = clamp01(task.progress ?? 0);\n\t\treturn {\n\t\t\ttask,\n\t\t\trowIndex: i,\n\t\t\tx,\n\t\t\ty,\n\t\t\tw,\n\t\t\th,\n\t\t\tprogressW: w * progress,\n\t\t};\n\t});\n\n\tconst byId = new Map(laidOutTasks.map((t) => [t.task.id, t]));\n\tconst deps: DepArrow[] = [];\n\tlaidOutTasks.forEach((t) => {\n\t\t(t.task.dependencies ?? []).forEach((depId, k) => {\n\t\t\tconst from = byId.get(depId);\n\t\t\tif (!from) return;\n\t\t\tdeps.push({\n\t\t\t\tfrom: { x: from.x + from.w, y: from.y + from.h / 2 },\n\t\t\t\tto: { x: t.x, y: t.y + t.h / 2 },\n\t\t\t\tid: `${depId}-${t.task.id}-${k}`,\n\t\t\t});\n\t\t});\n\t});\n\n\t// Generate ticks, then dedupe consecutive identical labels — at year-scale\n\t// or month-scale spans the formatter often emits the same string twice\n\t// (e.g. two ticks both inside January render as \"2025-01\"). Blanking the\n\t// duplicate keeps the gridline but drops the noisy repeated text.\n\tconst rawTicks: AxisTick[] = [];\n\tfor (let i = 0; i < tickCount; i++) {\n\t\tconst ts = minTs + (i / Math.max(1, tickCount - 1)) * span;\n\t\trawTicks.push({ x: tToX(ts), label: formatTick(new Date(ts), span) });\n\t}\n\tconst ticks: AxisTick[] = rawTicks.map((t, i) => ({\n\t\tx: t.x,\n\t\tlabel: i > 0 && rawTicks[i - 1]?.label === t.label ? \"\" : t.label,\n\t}));\n\n\treturn {\n\t\ttasks: laidOutTasks,\n\t\tdeps,\n\t\tticks,\n\t\tstartLabel: formatDate(new Date(minTs)),\n\t\tendLabel: formatDate(new Date(maxTs)),\n\t};\n}\n\nfunction toDate(v: Date | string | number): Date {\n\tif (v instanceof Date) return v;\n\tif (typeof v === \"number\") return new Date(v);\n\treturn new Date(v);\n}\n\nfunction clamp01(v: number): number {\n\treturn v < 0 ? 0 : v > 1 ? 1 : v;\n}\n\nfunction formatDate(d: Date): string {\n\tif (Number.isNaN(d.getTime())) return \"—\";\n\treturn d.toISOString().slice(0, 10);\n}\n\nfunction formatTick(d: Date, spanMs: number): string {\n\tif (Number.isNaN(d.getTime())) return \"—\";\n\tconst ONE_DAY = 24 * 60 * 60 * 1000;\n\t// Switch to MM-DD up to ~3 months — at 30 days the original threshold\n\t// produced \"2025-01\" / \"2025-01\" duplicates for ticks landing in the\n\t// same month. MM-DD scales to ~90 days before adjacent ticks merge.\n\tif (spanMs <= 90 * ONE_DAY) return d.toISOString().slice(5, 10); // MM-DD\n\tif (spanMs <= 730 * ONE_DAY) return d.toISOString().slice(0, 7); // YYYY-MM\n\treturn String(d.getUTCFullYear());\n}\n\nfunction activateOnKey(e: React.KeyboardEvent, fn: () => void): void {\n\tif (e.key === \"Enter\" || e.key === \" \") {\n\t\te.preventDefault();\n\t\tfn();\n\t}\n}\n\nexport { Gantt };\n"]}
@@ -0,0 +1,3 @@
1
+ export { OcclusionRegion_alias_1 as OcclusionRegion } from './_tsup-dts-rollup.js';
2
+ export { ImageOcclusionProps_alias_1 as ImageOcclusionProps } from './_tsup-dts-rollup.js';
3
+ export { ImageOcclusion_alias_1 as ImageOcclusion } from './_tsup-dts-rollup.js';
@@ -0,0 +1,106 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+ function ImageOcclusion({
11
+ src,
12
+ alt,
13
+ regions,
14
+ onRegionReveal,
15
+ className,
16
+ ...rest
17
+ }) {
18
+ const [revealed, setRevealed] = React.useState(() => /* @__PURE__ */ new Set());
19
+ const onRevealRef = React.useRef(onRegionReveal);
20
+ onRevealRef.current = onRegionReveal;
21
+ const warnedRef = React.useRef(false);
22
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
23
+ if (nodeEnv !== "production" && !warnedRef.current) {
24
+ const offender = regions.find(
25
+ (r) => r.x < 0 || r.y < 0 || r.x + r.width > 1.0001 || r.y + r.height > 1.0001
26
+ );
27
+ if (offender) {
28
+ warnedRef.current = true;
29
+ console.warn(
30
+ `[hex-core/ImageOcclusion] Region "${offender.id}" coords escape [0, 1]. Pass fractions, not pixels \u2014 e.g. x: 0.42 (not 168).`
31
+ );
32
+ }
33
+ }
34
+ const toggle = React.useCallback((id) => {
35
+ setRevealed((prev) => {
36
+ const next = new Set(prev);
37
+ if (next.has(id)) {
38
+ next.delete(id);
39
+ } else {
40
+ next.add(id);
41
+ onRevealRef.current?.(id);
42
+ }
43
+ return next;
44
+ });
45
+ }, []);
46
+ return /* @__PURE__ */ jsxs(
47
+ "div",
48
+ {
49
+ ...rest,
50
+ "data-hex-image-occlusion": true,
51
+ className: cn("relative inline-block", className),
52
+ children: [
53
+ /* @__PURE__ */ jsx(
54
+ "img",
55
+ {
56
+ src,
57
+ alt,
58
+ "data-hex-image-occlusion-img": true,
59
+ className: "block h-auto w-full select-none",
60
+ draggable: false
61
+ }
62
+ ),
63
+ /* @__PURE__ */ jsx(
64
+ "div",
65
+ {
66
+ "data-hex-image-occlusion-overlay": true,
67
+ className: "pointer-events-none absolute inset-0",
68
+ children: regions.map((r, i) => {
69
+ const isRevealed = revealed.has(r.id);
70
+ return /* @__PURE__ */ jsx(
71
+ "button",
72
+ {
73
+ type: "button",
74
+ "data-hex-image-occlusion-region": true,
75
+ "data-region-id": r.id,
76
+ "data-revealed": isRevealed,
77
+ "aria-pressed": isRevealed,
78
+ "aria-label": r.label ? isRevealed ? `Region ${i + 1} revealed: ${r.label}. Activate to hide.` : `Region ${i + 1} of ${regions.length}, hidden. Activate to reveal: ${r.label}.` : isRevealed ? `Region ${i + 1} revealed. Activate to hide.` : `Region ${i + 1} of ${regions.length}, hidden. Activate to reveal.`,
79
+ onClick: () => toggle(r.id),
80
+ className: cn(
81
+ "pointer-events-auto absolute rounded-sm border-2 border-primary/60 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
82
+ isRevealed ? "bg-transparent opacity-30 hover:opacity-60" : "bg-primary opacity-95 hover:bg-primary/90"
83
+ ),
84
+ style: {
85
+ left: `${r.x * 100}%`,
86
+ top: `${r.y * 100}%`,
87
+ width: `${r.width * 100}%`,
88
+ height: `${r.height * 100}%`,
89
+ // Explicit z-index = array index makes stacking deterministic:
90
+ // later array entries always render (and click-catch) on top.
91
+ zIndex: i
92
+ }
93
+ },
94
+ r.id
95
+ );
96
+ })
97
+ }
98
+ )
99
+ ]
100
+ }
101
+ );
102
+ }
103
+
104
+ export { ImageOcclusion };
105
+ //# sourceMappingURL=image-occlusion.js.map
106
+ //# sourceMappingURL=image-occlusion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/image-occlusion/image-occlusion.tsx"],"names":[],"mappings":"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","file":"image-occlusion.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Image occlusion — image with rectangular regions hidden behind opaque\n * overlays. Click / Enter / Space on a region reveals what's underneath.\n * Coordinates are 0–1 fractions of the rendered image so the layout\n * stays correct at any size. Pure HTML; no heavy peer.\n *\n * Common for anatomy diagrams, geographic maps, code snippets — any\n * visual where labels or sub-regions are the recall target.\n *\n * @example\n * <ImageOcclusion\n * src=\"/anatomy/heart.png\"\n * alt=\"Cross-section of a human heart\"\n * regions={[\n * { id: \"lv\", x: 0.42, y: 0.55, width: 0.18, height: 0.22, label: \"Left ventricle\" },\n * { id: \"ra\", x: 0.58, y: 0.20, width: 0.16, height: 0.18, label: \"Right atrium\" },\n * ]}\n * />\n */\nexport type OcclusionRegion = {\n\tid: string;\n\t/** All coords are 0–1 fractions of the rendered image. */\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n\tlabel?: string;\n};\n\nexport interface ImageOcclusionProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n\t/** Image source URL. */\n\tsrc: string;\n\t/** Alt text for the underlying image. */\n\talt: string;\n\t/** Rectangular regions to hide on top of the image. */\n\tregions: OcclusionRegion[];\n\t/** Fired with the region id when a region is revealed (not when hidden again). */\n\tonRegionReveal?: (id: string) => void;\n}\n\nfunction ImageOcclusion({\n\tsrc,\n\talt,\n\tregions,\n\tonRegionReveal,\n\tclassName,\n\t...rest\n}: ImageOcclusionProps) {\n\tconst [revealed, setRevealed] = React.useState<Set<string>>(() => new Set());\n\tconst onRevealRef = React.useRef(onRegionReveal);\n\tonRevealRef.current = onRegionReveal;\n\n\t// Surface mistakes early in dev when fractional coords escape [0, 1].\n\tconst warnedRef = React.useRef(false);\n\tconst nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV;\n\tif (nodeEnv !== \"production\" && !warnedRef.current) {\n\t\tconst offender = regions.find(\n\t\t\t(r) => r.x < 0 || r.y < 0 || r.x + r.width > 1.0001 || r.y + r.height > 1.0001,\n\t\t);\n\t\tif (offender) {\n\t\t\twarnedRef.current = true;\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(\n\t\t\t\t`[hex-core/ImageOcclusion] Region \"${offender.id}\" coords escape [0, 1]. Pass fractions, not pixels — e.g. x: 0.42 (not 168).`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst toggle = React.useCallback((id: string) => {\n\t\tsetRevealed((prev) => {\n\t\t\tconst next = new Set(prev);\n\t\t\tif (next.has(id)) {\n\t\t\t\tnext.delete(id);\n\t\t\t} else {\n\t\t\t\tnext.add(id);\n\t\t\t\tonRevealRef.current?.(id);\n\t\t\t}\n\t\t\treturn next;\n\t\t});\n\t}, []);\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-image-occlusion\n\t\t\tclassName={cn(\"relative inline-block\", className)}\n\t\t>\n\t\t\t<img\n\t\t\t\tsrc={src}\n\t\t\t\talt={alt}\n\t\t\t\tdata-hex-image-occlusion-img\n\t\t\t\tclassName=\"block h-auto w-full select-none\"\n\t\t\t\tdraggable={false}\n\t\t\t/>\n\t\t\t<div\n\t\t\t\tdata-hex-image-occlusion-overlay\n\t\t\t\tclassName=\"pointer-events-none absolute inset-0\"\n\t\t\t>\n\t\t\t\t{regions.map((r, i) => {\n\t\t\t\t\tconst isRevealed = revealed.has(r.id);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tkey={r.id}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tdata-hex-image-occlusion-region\n\t\t\t\t\t\t\tdata-region-id={r.id}\n\t\t\t\t\t\t\tdata-revealed={isRevealed}\n\t\t\t\t\t\t\taria-pressed={isRevealed}\n\t\t\t\t\t\t\taria-label={\n\t\t\t\t\t\t\t\tr.label\n\t\t\t\t\t\t\t\t\t? isRevealed\n\t\t\t\t\t\t\t\t\t\t? `Region ${i + 1} revealed: ${r.label}. Activate to hide.`\n\t\t\t\t\t\t\t\t\t\t: `Region ${i + 1} of ${regions.length}, hidden. Activate to reveal: ${r.label}.`\n\t\t\t\t\t\t\t\t\t: isRevealed\n\t\t\t\t\t\t\t\t\t\t? `Region ${i + 1} revealed. Activate to hide.`\n\t\t\t\t\t\t\t\t\t\t: `Region ${i + 1} of ${regions.length}, hidden. Activate to reveal.`\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tonClick={() => toggle(r.id)}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"pointer-events-auto absolute rounded-sm border-2 border-primary/60 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n\t\t\t\t\t\t\t\tisRevealed\n\t\t\t\t\t\t\t\t\t? \"bg-transparent opacity-30 hover:opacity-60\"\n\t\t\t\t\t\t\t\t\t: \"bg-primary opacity-95 hover:bg-primary/90\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tleft: `${r.x * 100}%`,\n\t\t\t\t\t\t\t\ttop: `${r.y * 100}%`,\n\t\t\t\t\t\t\t\twidth: `${r.width * 100}%`,\n\t\t\t\t\t\t\t\theight: `${r.height * 100}%`,\n\t\t\t\t\t\t\t\t// Explicit z-index = array index makes stacking deterministic:\n\t\t\t\t\t\t\t\t// later array entries always render (and click-catch) on top.\n\t\t\t\t\t\t\t\tzIndex: i,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport { ImageOcclusion };\n"]}
package/dist/index.d.ts CHANGED
@@ -300,6 +300,16 @@ export { Composer } from './_tsup-dts-rollup.js';
300
300
  export { ComposerProps } from './_tsup-dts-rollup.js';
301
301
  export { SpeechRecognition } from './_tsup-dts-rollup.js';
302
302
  export { SpeechRecognitionProps } from './_tsup-dts-rollup.js';
303
+ export { Terminal } from './_tsup-dts-rollup.js';
304
+ export { TerminalProps } from './_tsup-dts-rollup.js';
305
+ export { Canvas } from './_tsup-dts-rollup.js';
306
+ export { CanvasProps } from './_tsup-dts-rollup.js';
307
+ export { AudioPlayer } from './_tsup-dts-rollup.js';
308
+ export { AudioPlayerProps } from './_tsup-dts-rollup.js';
309
+ export { AudioWaveform } from './_tsup-dts-rollup.js';
310
+ export { AudioWaveformProps } from './_tsup-dts-rollup.js';
311
+ export { Diagram } from './_tsup-dts-rollup.js';
312
+ export { DiagramProps } from './_tsup-dts-rollup.js';
303
313
  export { LoadingIndicator } from './_tsup-dts-rollup.js';
304
314
  export { loadingIndicatorVariants } from './_tsup-dts-rollup.js';
305
315
  export { LoadingIndicatorProps } from './_tsup-dts-rollup.js';
@@ -324,4 +334,78 @@ export { Attachment } from './_tsup-dts-rollup.js';
324
334
  export { attachmentVariants } from './_tsup-dts-rollup.js';
325
335
  export { AttachmentFile } from './_tsup-dts-rollup.js';
326
336
  export { AttachmentProps } from './_tsup-dts-rollup.js';
337
+ export { MindMap } from './_tsup-dts-rollup.js';
338
+ export { MindMapNode } from './_tsup-dts-rollup.js';
339
+ export { MindMapProps } from './_tsup-dts-rollup.js';
340
+ export { TreeMap } from './_tsup-dts-rollup.js';
341
+ export { TreeMapNode } from './_tsup-dts-rollup.js';
342
+ export { TreeMapProps } from './_tsup-dts-rollup.js';
343
+ export { OrgChart } from './_tsup-dts-rollup.js';
344
+ export { OrgNode } from './_tsup-dts-rollup.js';
345
+ export { OrgChartProps } from './_tsup-dts-rollup.js';
346
+ export { Sunburst } from './_tsup-dts-rollup.js';
347
+ export { SunburstNode } from './_tsup-dts-rollup.js';
348
+ export { SunburstProps } from './_tsup-dts-rollup.js';
349
+ export { Dendrogram } from './_tsup-dts-rollup.js';
350
+ export { DendrogramNode } from './_tsup-dts-rollup.js';
351
+ export { DendrogramProps } from './_tsup-dts-rollup.js';
352
+ export { Sankey } from './_tsup-dts-rollup.js';
353
+ export { SankeyLink } from './_tsup-dts-rollup.js';
354
+ export { SankeyNode } from './_tsup-dts-rollup.js';
355
+ export { SankeyProps } from './_tsup-dts-rollup.js';
356
+ export { Funnel } from './_tsup-dts-rollup.js';
357
+ export { FunnelProps } from './_tsup-dts-rollup.js';
358
+ export { FunnelStage } from './_tsup-dts-rollup.js';
359
+ export { Pyramid } from './_tsup-dts-rollup.js';
360
+ export { PyramidProps } from './_tsup-dts-rollup.js';
361
+ export { PyramidTier } from './_tsup-dts-rollup.js';
362
+ export { Flowchart } from './_tsup-dts-rollup.js';
363
+ export { FlowchartEdge } from './_tsup-dts-rollup.js';
364
+ export { FlowchartNode } from './_tsup-dts-rollup.js';
365
+ export { FlowchartProps } from './_tsup-dts-rollup.js';
366
+ export { Venn } from './_tsup-dts-rollup.js';
367
+ export { VennProps } from './_tsup-dts-rollup.js';
368
+ export { VennSet } from './_tsup-dts-rollup.js';
369
+ export { Chord } from './_tsup-dts-rollup.js';
370
+ export { ChordHoverPayload } from './_tsup-dts-rollup.js';
371
+ export { ChordNode } from './_tsup-dts-rollup.js';
372
+ export { ChordProps } from './_tsup-dts-rollup.js';
373
+ export { Arc } from './_tsup-dts-rollup.js';
374
+ export { ArcEdge } from './_tsup-dts-rollup.js';
375
+ export { ArcNode } from './_tsup-dts-rollup.js';
376
+ export { ArcProps } from './_tsup-dts-rollup.js';
377
+ export { Matrix } from './_tsup-dts-rollup.js';
378
+ export { MatrixNode } from './_tsup-dts-rollup.js';
379
+ export { MatrixProps } from './_tsup-dts-rollup.js';
380
+ export { TimeAxis } from './_tsup-dts-rollup.js';
381
+ export { TimeAxisEvent } from './_tsup-dts-rollup.js';
382
+ export { TimeAxisProps } from './_tsup-dts-rollup.js';
383
+ export { Gantt } from './_tsup-dts-rollup.js';
384
+ export { GanttProps } from './_tsup-dts-rollup.js';
385
+ export { GanttTask } from './_tsup-dts-rollup.js';
386
+ export { Sequence } from './_tsup-dts-rollup.js';
387
+ export { SequenceActor } from './_tsup-dts-rollup.js';
388
+ export { SequenceMessage } from './_tsup-dts-rollup.js';
389
+ export { SequenceProps } from './_tsup-dts-rollup.js';
390
+ export { Flashcard } from './_tsup-dts-rollup.js';
391
+ export { FlashcardProps } from './_tsup-dts-rollup.js';
392
+ export { Cloze } from './_tsup-dts-rollup.js';
393
+ export { ClozePart } from './_tsup-dts-rollup.js';
394
+ export { ClozeProps } from './_tsup-dts-rollup.js';
395
+ export { ImageOcclusion } from './_tsup-dts-rollup.js';
396
+ export { ImageOcclusionProps } from './_tsup-dts-rollup.js';
397
+ export { OcclusionRegion } from './_tsup-dts-rollup.js';
398
+ export { Quiz } from './_tsup-dts-rollup.js';
399
+ export { QuizOption } from './_tsup-dts-rollup.js';
400
+ export { QuizProps } from './_tsup-dts-rollup.js';
401
+ export { CompareTable } from './_tsup-dts-rollup.js';
402
+ export { CompareAttribute } from './_tsup-dts-rollup.js';
403
+ export { CompareSubject } from './_tsup-dts-rollup.js';
404
+ export { CompareTableProps } from './_tsup-dts-rollup.js';
405
+ export { Deck } from './_tsup-dts-rollup.js';
406
+ export { DeckCard } from './_tsup-dts-rollup.js';
407
+ export { DeckProps } from './_tsup-dts-rollup.js';
408
+ export { SpacedRepetition } from './_tsup-dts-rollup.js';
409
+ export { SpacedRepetitionProps } from './_tsup-dts-rollup.js';
410
+ export { SrsRating } from './_tsup-dts-rollup.js';
327
411
  export { cn } from './_tsup-dts-rollup.js';