@vllnt/ui 0.2.0 → 0.2.1-canary.06f0e84

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 (202) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/README.md +27 -12
  3. package/dist/components/activity-log/activity-log.js +1 -0
  4. package/dist/components/agent-activity/agent-activity.js +311 -0
  5. package/dist/components/agent-activity/index.js +18 -0
  6. package/dist/components/ai-artifact/ai-artifact.js +422 -0
  7. package/dist/components/ai-artifact/index.js +24 -0
  8. package/dist/components/ai-sidebar/ai-sidebar.js +254 -0
  9. package/dist/components/ai-sidebar/index.js +22 -0
  10. package/dist/components/alert-pulse/alert-pulse.js +93 -0
  11. package/dist/components/alert-pulse/index.js +6 -0
  12. package/dist/components/anchor-port/anchor-port.js +51 -0
  13. package/dist/components/anchor-port/index.js +4 -0
  14. package/dist/components/animated-text/animated-text.js +1 -0
  15. package/dist/components/auto-reload/auto-reload.js +367 -0
  16. package/dist/components/auto-reload/index.js +6 -0
  17. package/dist/components/banner/banner.js +155 -0
  18. package/dist/components/banner/index.js +10 -0
  19. package/dist/components/bottom-activity-strip/bottom-activity-strip.js +91 -0
  20. package/dist/components/bottom-activity-strip/index.js +6 -0
  21. package/dist/components/bottom-bar/bottom-bar.js +25 -0
  22. package/dist/components/bottom-bar/index.js +4 -0
  23. package/dist/components/canvas-shell/canvas-foundation-demo.js +183 -0
  24. package/dist/components/canvas-shell/canvas-shell-route-config.js +0 -0
  25. package/dist/components/canvas-shell/canvas-shell.js +261 -0
  26. package/dist/components/canvas-shell/index.js +4 -0
  27. package/dist/components/canvas-view/canvas-view.js +461 -0
  28. package/dist/components/canvas-view/index.js +6 -0
  29. package/dist/components/chart/area-chart.js +1 -0
  30. package/dist/components/chart/line-chart.js +1 -0
  31. package/dist/components/chat-dock-section/chat-dock-section.js +56 -0
  32. package/dist/components/chat-dock-section/index.js +6 -0
  33. package/dist/components/checklist/checklist.js +7 -0
  34. package/dist/components/checklist/index.js +3 -1
  35. package/dist/components/choropleth-map/choropleth-map.js +373 -0
  36. package/dist/components/choropleth-map/index.js +10 -0
  37. package/dist/components/chronological-timeline/chronological-timeline.js +337 -0
  38. package/dist/components/chronological-timeline/index.js +8 -0
  39. package/dist/components/civilization-card/civilization-card.js +258 -0
  40. package/dist/components/civilization-card/index.js +8 -0
  41. package/dist/components/combobox/combobox.js +44 -20
  42. package/dist/components/comment-pin/comment-pin.js +104 -0
  43. package/dist/components/comment-pin/index.js +6 -0
  44. package/dist/components/connector-edge/connector-edge.js +66 -0
  45. package/dist/components/connector-edge/index.js +6 -0
  46. package/dist/components/context-lens/context-lens.js +98 -0
  47. package/dist/components/context-lens/index.js +6 -0
  48. package/dist/components/conversation-thread/conversation-thread.js +348 -0
  49. package/dist/components/conversation-thread/index.js +20 -0
  50. package/dist/components/copy-button/copy-button.js +189 -0
  51. package/dist/components/copy-button/index.js +8 -0
  52. package/dist/components/curriculum/curriculum.js +349 -0
  53. package/dist/components/curriculum/index.js +10 -0
  54. package/dist/components/data-list/data-list.js +1 -0
  55. package/dist/components/document-sibling-nav/document-sibling-nav.js +111 -0
  56. package/dist/components/document-sibling-nav/index.js +8 -0
  57. package/dist/components/edge-label/edge-label.js +26 -0
  58. package/dist/components/edge-label/index.js +4 -0
  59. package/dist/components/empty-state/empty-state.js +93 -0
  60. package/dist/components/empty-state/index.js +8 -0
  61. package/dist/components/era-comparison/era-comparison.js +198 -0
  62. package/dist/components/era-comparison/index.js +16 -0
  63. package/dist/components/floating-toolbar/floating-toolbar.js +66 -0
  64. package/dist/components/floating-toolbar/index.js +6 -0
  65. package/dist/components/follow-mode/follow-mode.js +89 -0
  66. package/dist/components/follow-mode/index.js +6 -0
  67. package/dist/components/form/form.js +432 -0
  68. package/dist/components/form/index.js +20 -0
  69. package/dist/components/gantt-chart/gantt-chart.js +331 -0
  70. package/dist/components/gantt-chart/index.js +6 -0
  71. package/dist/components/geography-quiz-map/geography-quiz-map.js +343 -0
  72. package/dist/components/geography-quiz-map/index.js +12 -0
  73. package/dist/components/glass-panel/glass-panel.js +21 -0
  74. package/dist/components/glass-panel/index.js +4 -0
  75. package/dist/components/globe-3d/globe-3d.js +417 -0
  76. package/dist/components/globe-3d/index.js +10 -0
  77. package/dist/components/group-hull/group-hull.js +29 -0
  78. package/dist/components/group-hull/index.js +4 -0
  79. package/dist/components/handoff-beacon/handoff-beacon.js +78 -0
  80. package/dist/components/handoff-beacon/index.js +6 -0
  81. package/dist/components/heat-map-overlay/heat-map-overlay.js +215 -0
  82. package/dist/components/heat-map-overlay/index.js +6 -0
  83. package/dist/components/heat-overlay/heat-overlay.js +92 -0
  84. package/dist/components/heat-overlay/index.js +6 -0
  85. package/dist/components/historic-timeline/historic-timeline.js +342 -0
  86. package/dist/components/historic-timeline/index.js +6 -0
  87. package/dist/components/historical-figure-card/historical-figure-card.js +273 -0
  88. package/dist/components/historical-figure-card/index.js +6 -0
  89. package/dist/components/index.js +568 -1
  90. package/dist/components/infinite-plane/index.js +6 -0
  91. package/dist/components/infinite-plane/infinite-plane.js +75 -0
  92. package/dist/components/interactive-timeline/index.js +16 -0
  93. package/dist/components/interactive-timeline/interactive-timeline.js +708 -0
  94. package/dist/components/jarvis-dock/index.js +6 -0
  95. package/dist/components/jarvis-dock/jarvis-dock.js +98 -0
  96. package/dist/components/kbd/index.js +5 -0
  97. package/dist/components/kbd/kbd.js +117 -0
  98. package/dist/components/knowledge-check/index.js +6 -0
  99. package/dist/components/knowledge-check/knowledge-check.js +448 -0
  100. package/dist/components/left-rail/index.js +4 -0
  101. package/dist/components/left-rail/left-rail.js +25 -0
  102. package/dist/components/live-cursor/index.js +6 -0
  103. package/dist/components/live-cursor/live-cursor.js +62 -0
  104. package/dist/components/map-2d/index.js +20 -0
  105. package/dist/components/map-2d/map-2d.js +455 -0
  106. package/dist/components/map-timeline/index.js +16 -0
  107. package/dist/components/map-timeline/map-timeline.js +506 -0
  108. package/dist/components/metric-cluster/index.js +6 -0
  109. package/dist/components/metric-cluster/metric-cluster.js +96 -0
  110. package/dist/components/mini-map-panel/index.js +6 -0
  111. package/dist/components/mini-map-panel/mini-map-panel.js +74 -0
  112. package/dist/components/model-comparison/index.js +12 -0
  113. package/dist/components/model-comparison/model-comparison.js +211 -0
  114. package/dist/components/multi-select/index.js +6 -0
  115. package/dist/components/multi-select/multi-select.js +258 -0
  116. package/dist/components/multi-select-lasso/index.js +6 -0
  117. package/dist/components/multi-select-lasso/multi-select-lasso.js +76 -0
  118. package/dist/components/newsletter-signup/index.js +8 -0
  119. package/dist/components/newsletter-signup/newsletter-signup.js +269 -0
  120. package/dist/components/object-card/index.js +6 -0
  121. package/dist/components/object-card/object-card.js +126 -0
  122. package/dist/components/object-handle/index.js +4 -0
  123. package/dist/components/object-handle/object-handle.js +38 -0
  124. package/dist/components/object-inspector/index.js +6 -0
  125. package/dist/components/object-inspector/object-inspector.js +136 -0
  126. package/dist/components/overview-board/index.js +8 -0
  127. package/dist/components/overview-board/overview-board.js +127 -0
  128. package/dist/components/parallel-timeline/index.js +6 -0
  129. package/dist/components/parallel-timeline/parallel-timeline.js +251 -0
  130. package/dist/components/playback-ghost/index.js +6 -0
  131. package/dist/components/playback-ghost/playback-ghost.js +83 -0
  132. package/dist/components/policy-delivery-panel/index.js +6 -0
  133. package/dist/components/policy-delivery-panel/policy-delivery-panel.js +99 -0
  134. package/dist/components/presence-stack/index.js +6 -0
  135. package/dist/components/presence-stack/presence-stack.js +108 -0
  136. package/dist/components/presence-sync-indicator/index.js +6 -0
  137. package/dist/components/presence-sync-indicator/presence-sync-indicator.js +73 -0
  138. package/dist/components/pricing-table/index.js +8 -0
  139. package/dist/components/pricing-table/pricing-table.js +247 -0
  140. package/dist/components/primary-source-viewer/index.js +26 -0
  141. package/dist/components/primary-source-viewer/primary-source-viewer.js +439 -0
  142. package/dist/components/progress-tracker/index.js +20 -0
  143. package/dist/components/progress-tracker/progress-tracker.js +527 -0
  144. package/dist/components/prompt-templates/index.js +6 -0
  145. package/dist/components/prompt-templates/prompt-templates.js +403 -0
  146. package/dist/components/property-section/index.js +6 -0
  147. package/dist/components/property-section/property-section.js +101 -0
  148. package/dist/components/relationship-inspector/index.js +6 -0
  149. package/dist/components/relationship-inspector/relationship-inspector.js +102 -0
  150. package/dist/components/right-dock/index.js +4 -0
  151. package/dist/components/right-dock/right-dock.js +28 -0
  152. package/dist/components/route-map/index.js +6 -0
  153. package/dist/components/route-map/route-map.js +339 -0
  154. package/dist/components/routing-assignment-panel/index.js +6 -0
  155. package/dist/components/routing-assignment-panel/routing-assignment-panel.js +122 -0
  156. package/dist/components/run-timeline/index.js +6 -0
  157. package/dist/components/run-timeline/run-timeline.js +221 -0
  158. package/dist/components/runtime-overview-panel/index.js +6 -0
  159. package/dist/components/runtime-overview-panel/runtime-overview-panel.js +89 -0
  160. package/dist/components/segmented-control/index.js +12 -0
  161. package/dist/components/segmented-control/segmented-control.js +61 -0
  162. package/dist/components/selection-halo/index.js +6 -0
  163. package/dist/components/selection-halo/selection-halo.js +72 -0
  164. package/dist/components/selection-presence/index.js +6 -0
  165. package/dist/components/selection-presence/selection-presence.js +50 -0
  166. package/dist/components/snap-guides/index.js +6 -0
  167. package/dist/components/snap-guides/snap-guides.js +45 -0
  168. package/dist/components/spinner/unicode-spinner.js +1 -0
  169. package/dist/components/state-badge-overlay/index.js +6 -0
  170. package/dist/components/state-badge-overlay/state-badge-overlay.js +90 -0
  171. package/dist/components/sticky-metric/index.js +6 -0
  172. package/dist/components/sticky-metric/sticky-metric.js +83 -0
  173. package/dist/components/story-map/index.js +8 -0
  174. package/dist/components/story-map/story-map.js +414 -0
  175. package/dist/components/tags-input/index.js +4 -0
  176. package/dist/components/tags-input/tags-input.js +178 -0
  177. package/dist/components/thread-bubble/index.js +6 -0
  178. package/dist/components/thread-bubble/thread-bubble.js +85 -0
  179. package/dist/components/threshold-ring/index.js +6 -0
  180. package/dist/components/threshold-ring/threshold-ring.js +160 -0
  181. package/dist/components/timeline/index.js +12 -0
  182. package/dist/components/timeline/timeline.js +239 -0
  183. package/dist/components/timeline-scrubber/index.js +6 -0
  184. package/dist/components/timeline-scrubber/timeline-scrubber.js +179 -0
  185. package/dist/components/top-bar/index.js +4 -0
  186. package/dist/components/top-bar/top-bar.js +31 -0
  187. package/dist/components/transaction-list/index.js +14 -0
  188. package/dist/components/transaction-list/transaction-list.js +226 -0
  189. package/dist/components/tree-view/index.js +6 -0
  190. package/dist/components/tree-view/tree-view.js +298 -0
  191. package/dist/components/usage-breakdown/usage-breakdown.js +1 -0
  192. package/dist/components/viewport-bookmarks/index.js +6 -0
  193. package/dist/components/viewport-bookmarks/viewport-bookmarks.js +116 -0
  194. package/dist/components/workspace-switcher/index.js +6 -0
  195. package/dist/components/workspace-switcher/workspace-switcher.js +61 -0
  196. package/dist/components/world-breadcrumbs/index.js +6 -0
  197. package/dist/components/world-breadcrumbs/world-breadcrumbs.js +114 -0
  198. package/dist/components/zoom-hud/index.js +4 -0
  199. package/dist/components/zoom-hud/zoom-hud.js +61 -0
  200. package/dist/index.d.ts +7906 -225
  201. package/dist/index.js +3 -1
  202. package/package.json +9 -5
@@ -0,0 +1,215 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef,
5
+ useId,
6
+ useMemo
7
+ } from "react";
8
+ import { cn } from "../../lib/utils";
9
+ const VIEWBOX_WIDTH = 1e3;
10
+ const VIEWBOX_HEIGHT = 500;
11
+ const DEFAULT_GRADIENT = {
12
+ 0.2: "rgba(0, 0, 255, 0.6)",
13
+ 0.5: "rgba(0, 255, 0, 0.7)",
14
+ 0.8: "rgba(255, 165, 0, 0.85)",
15
+ 1: "rgba(255, 0, 0, 0.95)"
16
+ };
17
+ const DEFAULT_LABELS = {
18
+ region: "Heat map"
19
+ };
20
+ function projectEquirectangular(lng, lat) {
21
+ const x = (lng + 180) / 360 * VIEWBOX_WIDTH;
22
+ const y = (90 - lat) / 180 * VIEWBOX_HEIGHT;
23
+ return { x, y };
24
+ }
25
+ function clamp(value, min, max) {
26
+ return Math.min(Math.max(value, min), max);
27
+ }
28
+ function gradientStops(gradient) {
29
+ return Object.entries(gradient).map(([key, value]) => ({ color: value, offset: Number.parseFloat(key) })).sort((a, b) => a.offset - b.offset);
30
+ }
31
+ function projectPoints(points) {
32
+ return points.map((point) => {
33
+ const { x, y } = projectEquirectangular(point.lng, point.lat);
34
+ return {
35
+ raw: point,
36
+ weight: clamp(point.weight ?? 1, 0, 1),
37
+ x,
38
+ y
39
+ };
40
+ });
41
+ }
42
+ function HeatBlob({ gradientId, point, radius }) {
43
+ const blobRadius = Math.max(2, radius * (0.4 + 0.6 * point.weight));
44
+ return /* @__PURE__ */ jsx(
45
+ "circle",
46
+ {
47
+ cx: point.x,
48
+ cy: point.y,
49
+ "data-point-id": point.raw.id,
50
+ "data-weight": point.weight,
51
+ fill: `url(#${gradientId})`,
52
+ opacity: point.weight,
53
+ r: blobRadius
54
+ }
55
+ );
56
+ }
57
+ function GradientDefs({
58
+ blurId,
59
+ gradient,
60
+ gradientId
61
+ }) {
62
+ const stops = gradientStops(gradient);
63
+ return /* @__PURE__ */ jsxs("defs", { children: [
64
+ /* @__PURE__ */ jsx("radialGradient", { cx: "50%", cy: "50%", id: gradientId, r: "50%", children: stops.map((stop) => /* @__PURE__ */ jsx(
65
+ "stop",
66
+ {
67
+ offset: `${(stop.offset * 100).toString()}%`,
68
+ stopColor: stop.color
69
+ },
70
+ stop.offset
71
+ )) }),
72
+ /* @__PURE__ */ jsx("filter", { id: blurId, children: /* @__PURE__ */ jsx("feGaussianBlur", { stdDeviation: 12 }) })
73
+ ] });
74
+ }
75
+ function DataSummary({ data, titleId }) {
76
+ return /* @__PURE__ */ jsxs("div", { "aria-labelledby": titleId, className: "sr-only", role: "region", children: [
77
+ /* @__PURE__ */ jsx("h3", { id: titleId, children: "Heat map data summary" }),
78
+ /* @__PURE__ */ jsxs("p", { children: [
79
+ data.length.toString(),
80
+ " point",
81
+ data.length === 1 ? "" : "s",
82
+ " plotted on the heat map."
83
+ ] }),
84
+ /* @__PURE__ */ jsx("ul", { children: data.map((point) => /* @__PURE__ */ jsx("li", { children: `${point.lat.toString()}, ${point.lng.toString()}: weight ${(point.weight ?? 1).toString()}` }, point.id)) })
85
+ ] });
86
+ }
87
+ function Stage({
88
+ backdrop,
89
+ backdropAlt,
90
+ blur,
91
+ blurId,
92
+ data,
93
+ gradient,
94
+ gradientId,
95
+ opacity,
96
+ radius
97
+ }) {
98
+ return /* @__PURE__ */ jsxs(
99
+ "svg",
100
+ {
101
+ "aria-hidden": "true",
102
+ className: "block h-full w-full",
103
+ preserveAspectRatio: "xMidYMid meet",
104
+ viewBox: `0 0 ${VIEWBOX_WIDTH.toString()} ${VIEWBOX_HEIGHT.toString()}`,
105
+ children: [
106
+ /* @__PURE__ */ jsx(
107
+ GradientDefs,
108
+ {
109
+ blurId,
110
+ gradient,
111
+ gradientId
112
+ }
113
+ ),
114
+ /* @__PURE__ */ jsx(
115
+ "rect",
116
+ {
117
+ className: "fill-muted",
118
+ height: VIEWBOX_HEIGHT,
119
+ width: VIEWBOX_WIDTH,
120
+ x: "0",
121
+ y: "0"
122
+ }
123
+ ),
124
+ backdrop ? /* @__PURE__ */ jsx(
125
+ "image",
126
+ {
127
+ "aria-label": backdropAlt,
128
+ height: VIEWBOX_HEIGHT,
129
+ href: backdrop,
130
+ preserveAspectRatio: "xMidYMid slice",
131
+ width: VIEWBOX_WIDTH,
132
+ x: "0",
133
+ y: "0"
134
+ }
135
+ ) : null,
136
+ /* @__PURE__ */ jsx(
137
+ "g",
138
+ {
139
+ "data-heat-layer": true,
140
+ filter: blur > 0 ? `url(#${blurId})` : void 0,
141
+ opacity,
142
+ children: data.map((point) => /* @__PURE__ */ jsx(
143
+ HeatBlob,
144
+ {
145
+ gradientId,
146
+ point,
147
+ radius
148
+ },
149
+ point.raw.id
150
+ ))
151
+ }
152
+ )
153
+ ]
154
+ }
155
+ );
156
+ }
157
+ const HeatMapOverlay = forwardRef(
158
+ (props, ref) => {
159
+ const {
160
+ backdrop,
161
+ backdropAlt,
162
+ blur = 12,
163
+ children,
164
+ className,
165
+ data,
166
+ gradient = DEFAULT_GRADIENT,
167
+ labels,
168
+ opacity = 0.7,
169
+ radius = 30,
170
+ ...rest
171
+ } = props;
172
+ const titleId = useId();
173
+ const gradientId = useId();
174
+ const blurId = useId();
175
+ const resolvedLabels = useMemo(
176
+ () => ({ ...DEFAULT_LABELS, ...labels }),
177
+ [labels]
178
+ );
179
+ const projected = useMemo(() => projectPoints(data), [data]);
180
+ return /* @__PURE__ */ jsxs(
181
+ "section",
182
+ {
183
+ "aria-label": resolvedLabels.region,
184
+ className: cn(
185
+ "relative aspect-[2/1] w-full overflow-hidden rounded-2xl border bg-background text-foreground",
186
+ className
187
+ ),
188
+ ref,
189
+ ...rest,
190
+ children: [
191
+ /* @__PURE__ */ jsx(
192
+ Stage,
193
+ {
194
+ backdrop,
195
+ backdropAlt,
196
+ blur,
197
+ blurId,
198
+ data: projected,
199
+ gradient,
200
+ gradientId,
201
+ opacity,
202
+ radius
203
+ }
204
+ ),
205
+ children ? /* @__PURE__ */ jsx("div", { className: "absolute bottom-3 left-3 z-10 max-w-xs rounded-md border bg-background/95 px-3 py-2 text-xs text-foreground shadow-sm backdrop-blur", children }) : null,
206
+ /* @__PURE__ */ jsx(DataSummary, { data, titleId })
207
+ ]
208
+ }
209
+ );
210
+ }
211
+ );
212
+ HeatMapOverlay.displayName = "HeatMapOverlay";
213
+ export {
214
+ HeatMapOverlay
215
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ HeatMapOverlay
3
+ } from "./heat-map-overlay";
4
+ export {
5
+ HeatMapOverlay
6
+ };
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { forwardRef, useId } from "react";
4
+ import { cn } from "../../lib/utils";
5
+ const TONE_FILL = {
6
+ cool: "fill-blue-500",
7
+ danger: "fill-red-500",
8
+ neutral: "fill-foreground",
9
+ warn: "fill-amber-500"
10
+ };
11
+ const DEFAULT_LABELS = {
12
+ region: "Heat overlay"
13
+ };
14
+ const clamp01 = (v) => {
15
+ if (v < 0) {
16
+ return 0;
17
+ }
18
+ if (v > 1) {
19
+ return 1;
20
+ }
21
+ return v;
22
+ };
23
+ const HeatBlob = (props) => {
24
+ const { defaultTone, gradientId, intensity, point } = props;
25
+ const weight = clamp01(point.weight);
26
+ const tone = point.tone ?? defaultTone;
27
+ return /* @__PURE__ */ jsx(
28
+ "circle",
29
+ {
30
+ className: cn("mix-blend-multiply", TONE_FILL[tone]),
31
+ cx: point.x,
32
+ cy: point.y,
33
+ "data-heat-point": point.id,
34
+ "data-heat-tone": tone,
35
+ fill: `url(#${gradientId})`,
36
+ fillOpacity: weight * 0.6,
37
+ r: Math.max(8, intensity * weight)
38
+ }
39
+ );
40
+ };
41
+ const HeatOverlay = forwardRef(
42
+ (props, ref) => {
43
+ const {
44
+ className,
45
+ defaultTone = "warn",
46
+ intensity = 48,
47
+ labels,
48
+ points,
49
+ ...rest
50
+ } = props;
51
+ const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
52
+ const gradientId = useId();
53
+ if (points.length === 0) {
54
+ return null;
55
+ }
56
+ return /* @__PURE__ */ jsxs(
57
+ "svg",
58
+ {
59
+ "aria-label": resolvedLabels.region,
60
+ className: cn(
61
+ "pointer-events-none absolute inset-0 z-10 h-full w-full",
62
+ className
63
+ ),
64
+ "data-heat-overlay": true,
65
+ ref,
66
+ role: "img",
67
+ ...rest,
68
+ children: [
69
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("radialGradient", { cx: "50%", cy: "50%", id: gradientId, r: "50%", children: [
70
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "currentColor", stopOpacity: "1" }),
71
+ /* @__PURE__ */ jsx("stop", { offset: "70%", stopColor: "currentColor", stopOpacity: "0.4" }),
72
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "currentColor", stopOpacity: "0" })
73
+ ] }) }),
74
+ points.map((point) => /* @__PURE__ */ jsx(
75
+ HeatBlob,
76
+ {
77
+ defaultTone,
78
+ gradientId,
79
+ intensity,
80
+ point
81
+ },
82
+ point.id
83
+ ))
84
+ ]
85
+ }
86
+ );
87
+ }
88
+ );
89
+ HeatOverlay.displayName = "HeatOverlay";
90
+ export {
91
+ HeatOverlay
92
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ HeatOverlay
3
+ } from "./heat-overlay";
4
+ export {
5
+ HeatOverlay
6
+ };
@@ -0,0 +1,342 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef,
5
+ useMemo
6
+ } from "react";
7
+ import { cn } from "../../lib/utils";
8
+ const DEFAULT_TICK_COUNT = 8;
9
+ const COLOR_PALETTE = {
10
+ amber: {
11
+ band: "bg-amber-500/15",
12
+ chip: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
13
+ marker: "border-amber-500 bg-amber-500"
14
+ },
15
+ blue: {
16
+ band: "bg-blue-500/15",
17
+ chip: "bg-blue-500/15 text-blue-700 dark:text-blue-300",
18
+ marker: "border-blue-500 bg-blue-500"
19
+ },
20
+ emerald: {
21
+ band: "bg-emerald-500/15",
22
+ chip: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
23
+ marker: "border-emerald-500 bg-emerald-500"
24
+ },
25
+ neutral: {
26
+ band: "bg-muted",
27
+ chip: "bg-muted text-muted-foreground",
28
+ marker: "border-muted-foreground bg-muted-foreground"
29
+ },
30
+ purple: {
31
+ band: "bg-purple-500/15",
32
+ chip: "bg-purple-500/15 text-purple-700 dark:text-purple-300",
33
+ marker: "border-purple-500 bg-purple-500"
34
+ },
35
+ red: {
36
+ band: "bg-red-500/15",
37
+ chip: "bg-red-500/15 text-red-700 dark:text-red-300",
38
+ marker: "border-red-500 bg-red-500"
39
+ },
40
+ rose: {
41
+ band: "bg-rose-500/15",
42
+ chip: "bg-rose-500/15 text-rose-700 dark:text-rose-300",
43
+ marker: "border-rose-500 bg-rose-500"
44
+ }
45
+ };
46
+ const DEFAULT_LABELS = {
47
+ region: "Historic timeline"
48
+ };
49
+ function clamp(value, min, max) {
50
+ return Math.min(Math.max(value, min), max);
51
+ }
52
+ function formatYear(year) {
53
+ if (year < 0) return `${Math.abs(year).toString()} BCE`;
54
+ return `${year.toString()} CE`;
55
+ }
56
+ function yearToPercent(year, start, end) {
57
+ const span = end - start;
58
+ if (span <= 0) return 0;
59
+ return clamp((year - start) / span * 100, 0, 100);
60
+ }
61
+ function buildTicks(start, end, count) {
62
+ const safeCount = Math.max(2, count);
63
+ const span = end - start;
64
+ if (span <= 0) return [];
65
+ const step = span / (safeCount - 1);
66
+ return Array.from({ length: safeCount }).map((_, index) => {
67
+ const year = Math.round(start + step * index);
68
+ return {
69
+ label: formatYear(year),
70
+ offset: yearToPercent(year, start, end)
71
+ };
72
+ });
73
+ }
74
+ function resolveCategoryColor(categoryId, categories) {
75
+ if (!categoryId) return "neutral";
76
+ const match = categories.find((category) => category.id === categoryId);
77
+ return match?.color ?? "neutral";
78
+ }
79
+ function Axis({ ticks }) {
80
+ return /* @__PURE__ */ jsx(
81
+ "div",
82
+ {
83
+ "aria-hidden": "true",
84
+ className: "relative h-7 border-b border-border text-[10px] font-medium uppercase tracking-wide text-muted-foreground",
85
+ children: ticks.map((tick) => /* @__PURE__ */ jsx(
86
+ "span",
87
+ {
88
+ className: "absolute top-1 -translate-x-1/2",
89
+ style: { left: `${tick.offset.toString()}%` },
90
+ children: tick.label
91
+ },
92
+ tick.label
93
+ ))
94
+ }
95
+ );
96
+ }
97
+ function EraBands({ endYear, eras, startYear }) {
98
+ if (eras.length === 0) return null;
99
+ return /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0", children: eras.map((era) => {
100
+ const left = yearToPercent(era.startYear, startYear, endYear);
101
+ const right = yearToPercent(era.endYear, startYear, endYear);
102
+ const width = Math.max(0, right - left);
103
+ if (width <= 0) return null;
104
+ const palette = COLOR_PALETTE[era.color ?? "neutral"];
105
+ return /* @__PURE__ */ jsx(
106
+ "div",
107
+ {
108
+ className: cn("absolute inset-y-0", palette.band),
109
+ "data-era-id": era.id,
110
+ style: {
111
+ left: `${left.toString()}%`,
112
+ width: `${width.toString()}%`
113
+ }
114
+ },
115
+ era.id
116
+ );
117
+ }) });
118
+ }
119
+ function EraLabels({ endYear, eras, startYear }) {
120
+ if (eras.length === 0) return null;
121
+ return /* @__PURE__ */ jsx("div", { className: "relative flex h-6 border-b border-border", children: eras.map((era) => {
122
+ const left = yearToPercent(era.startYear, startYear, endYear);
123
+ const right = yearToPercent(era.endYear, startYear, endYear);
124
+ const width = Math.max(0, right - left);
125
+ if (width <= 0) return null;
126
+ const palette = COLOR_PALETTE[era.color ?? "neutral"];
127
+ return /* @__PURE__ */ jsx(
128
+ "span",
129
+ {
130
+ className: cn(
131
+ "absolute top-1 truncate rounded px-1 text-[10px] font-semibold uppercase tracking-wide",
132
+ palette.chip
133
+ ),
134
+ style: {
135
+ left: `${left.toString()}%`,
136
+ width: `${width.toString()}%`
137
+ },
138
+ children: era.name
139
+ },
140
+ `${era.id}-label`
141
+ );
142
+ }) });
143
+ }
144
+ function PeriodLane({
145
+ categories,
146
+ endYear,
147
+ periods,
148
+ startYear
149
+ }) {
150
+ if (periods.length === 0) return null;
151
+ return /* @__PURE__ */ jsx("div", { className: "relative flex h-7 items-center border-b border-border/60", children: periods.map((period) => {
152
+ const left = yearToPercent(period.startYear, startYear, endYear);
153
+ const right = yearToPercent(period.endYear, startYear, endYear);
154
+ const width = Math.max(0, right - left);
155
+ if (width <= 0) return null;
156
+ const color = resolveCategoryColor(period.category, categories);
157
+ const palette = COLOR_PALETTE[color];
158
+ const titleText = typeof period.title === "string" ? period.title : "";
159
+ return /* @__PURE__ */ jsx(
160
+ "div",
161
+ {
162
+ "aria-label": titleText ? `${titleText}, ${formatYear(period.startYear)} \u2013 ${formatYear(period.endYear)}` : void 0,
163
+ className: cn(
164
+ "absolute top-1 flex h-5 items-center overflow-hidden rounded-sm px-1 text-[10px] font-medium",
165
+ palette.chip
166
+ ),
167
+ "data-period-id": period.id,
168
+ style: {
169
+ left: `${left.toString()}%`,
170
+ width: `${width.toString()}%`
171
+ },
172
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: period.title })
173
+ },
174
+ period.id
175
+ );
176
+ }) });
177
+ }
178
+ function EventMarker({
179
+ categories,
180
+ endYear,
181
+ event,
182
+ startYear
183
+ }) {
184
+ if (event.year < startYear || event.year > endYear) return null;
185
+ const left = yearToPercent(event.year, startYear, endYear);
186
+ const color = resolveCategoryColor(event.category, categories);
187
+ const palette = COLOR_PALETTE[color];
188
+ const titleText = typeof event.title === "string" ? event.title : "";
189
+ const ariaLabel = titleText ? `${titleText}, ${formatYear(event.year)}` : void 0;
190
+ return /* @__PURE__ */ jsxs(
191
+ "div",
192
+ {
193
+ "aria-label": ariaLabel,
194
+ className: "absolute top-1/2 z-10 -translate-x-1/2 -translate-y-1/2",
195
+ "data-event-id": event.id,
196
+ "data-event-year": event.year,
197
+ style: { left: `${left.toString()}%` },
198
+ children: [
199
+ /* @__PURE__ */ jsx(
200
+ "div",
201
+ {
202
+ "aria-hidden": "true",
203
+ className: cn(
204
+ "h-3 w-3 rounded-full border-2 ring-2 ring-background",
205
+ palette.marker
206
+ )
207
+ }
208
+ ),
209
+ /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 top-4 w-44 -translate-x-1/2 text-center", children: [
210
+ event.href ? /* @__PURE__ */ jsx(
211
+ "a",
212
+ {
213
+ className: "block truncate text-xs font-medium text-foreground underline-offset-4 hover:underline",
214
+ href: event.href,
215
+ children: event.title
216
+ }
217
+ ) : /* @__PURE__ */ jsx("p", { className: "truncate text-xs font-medium text-foreground", children: event.title }),
218
+ /* @__PURE__ */ jsxs("p", { className: "truncate text-[10px] text-muted-foreground", children: [
219
+ formatYear(event.year),
220
+ event.description ? /* @__PURE__ */ jsxs("span", { children: [
221
+ " \xB7 ",
222
+ event.description
223
+ ] }) : null
224
+ ] })
225
+ ] })
226
+ ]
227
+ }
228
+ );
229
+ }
230
+ function EventLane({
231
+ categories,
232
+ endYear,
233
+ events,
234
+ startYear
235
+ }) {
236
+ return /* @__PURE__ */ jsxs("div", { className: "relative h-20", children: [
237
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-border" }),
238
+ events.map((event) => /* @__PURE__ */ jsx(
239
+ EventMarker,
240
+ {
241
+ categories,
242
+ endYear,
243
+ event,
244
+ startYear
245
+ },
246
+ event.id
247
+ ))
248
+ ] });
249
+ }
250
+ function Legend({ categories }) {
251
+ if (categories.length === 0) return null;
252
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 border-t border-border px-3 py-2 text-xs", children: categories.map((category) => {
253
+ const palette = COLOR_PALETTE[category.color ?? "neutral"];
254
+ return /* @__PURE__ */ jsxs(
255
+ "span",
256
+ {
257
+ className: cn(
258
+ "inline-flex items-center gap-1 rounded-full px-2 py-0.5",
259
+ palette.chip
260
+ ),
261
+ "data-category-id": category.id,
262
+ children: [
263
+ /* @__PURE__ */ jsx(
264
+ "span",
265
+ {
266
+ "aria-hidden": "true",
267
+ className: cn("h-2 w-2 rounded-full", palette.marker)
268
+ }
269
+ ),
270
+ category.label
271
+ ]
272
+ },
273
+ category.id
274
+ );
275
+ }) });
276
+ }
277
+ const HistoricTimeline = forwardRef(
278
+ (props, ref) => {
279
+ const {
280
+ categories = [],
281
+ className,
282
+ endYear,
283
+ eras = [],
284
+ events = [],
285
+ labels,
286
+ periods = [],
287
+ startYear,
288
+ tickCount = DEFAULT_TICK_COUNT,
289
+ ...rest
290
+ } = props;
291
+ const resolvedLabels = useMemo(
292
+ () => ({ ...DEFAULT_LABELS, ...labels }),
293
+ [labels]
294
+ );
295
+ const ticks = useMemo(
296
+ () => buildTicks(startYear, endYear, tickCount),
297
+ [endYear, startYear, tickCount]
298
+ );
299
+ return /* @__PURE__ */ jsxs(
300
+ "section",
301
+ {
302
+ "aria-label": resolvedLabels.region,
303
+ className: cn(
304
+ "flex w-full flex-col overflow-hidden rounded-2xl border bg-background text-foreground",
305
+ className
306
+ ),
307
+ ref,
308
+ ...rest,
309
+ children: [
310
+ /* @__PURE__ */ jsx(Axis, { ticks }),
311
+ /* @__PURE__ */ jsx(EraLabels, { endYear, eras, startYear }),
312
+ /* @__PURE__ */ jsx(
313
+ PeriodLane,
314
+ {
315
+ categories,
316
+ endYear,
317
+ periods,
318
+ startYear
319
+ }
320
+ ),
321
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
322
+ /* @__PURE__ */ jsx(EraBands, { endYear, eras, startYear }),
323
+ /* @__PURE__ */ jsx(
324
+ EventLane,
325
+ {
326
+ categories,
327
+ endYear,
328
+ events,
329
+ startYear
330
+ }
331
+ )
332
+ ] }),
333
+ /* @__PURE__ */ jsx(Legend, { categories })
334
+ ]
335
+ }
336
+ );
337
+ }
338
+ );
339
+ HistoricTimeline.displayName = "HistoricTimeline";
340
+ export {
341
+ HistoricTimeline
342
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ HistoricTimeline
3
+ } from "./historic-timeline";
4
+ export {
5
+ HistoricTimeline
6
+ };