@spatika/react 1.1.0 → 1.3.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 (311) hide show
  1. package/AGENTS.md +71 -0
  2. package/README.md +4 -3
  3. package/dist/composites/Card.d.ts +7 -1
  4. package/dist/composites/Card.d.ts.map +1 -1
  5. package/dist/composites/Card.js +10 -0
  6. package/dist/composites/ChartDataGrid.d.ts +33 -0
  7. package/dist/composites/ChartDataGrid.d.ts.map +1 -0
  8. package/dist/composites/ChartDataGrid.js +77 -0
  9. package/dist/composites/CoverHero.d.ts +1 -1
  10. package/dist/composites/CoverHero.d.ts.map +1 -1
  11. package/dist/composites/CoverHero.js +2 -2
  12. package/dist/composites/EntityMediaCard.d.ts +1 -1
  13. package/dist/composites/EntityMediaCard.d.ts.map +1 -1
  14. package/dist/composites/EntityMediaCard.js +12 -4
  15. package/dist/composites/EventCalendar.d.ts +72 -0
  16. package/dist/composites/EventCalendar.d.ts.map +1 -0
  17. package/dist/composites/EventCalendar.js +371 -0
  18. package/dist/composites/EventEditor.d.ts +22 -0
  19. package/dist/composites/EventEditor.d.ts.map +1 -0
  20. package/dist/composites/EventEditor.js +86 -0
  21. package/dist/composites/EventTimeline.d.ts +29 -0
  22. package/dist/composites/EventTimeline.d.ts.map +1 -0
  23. package/dist/composites/EventTimeline.js +186 -0
  24. package/dist/composites/MapChart.d.ts +24 -0
  25. package/dist/composites/MapChart.d.ts.map +1 -0
  26. package/dist/composites/MapChart.js +58 -0
  27. package/dist/composites/ProfileHero.d.ts +6 -4
  28. package/dist/composites/ProfileHero.d.ts.map +1 -1
  29. package/dist/composites/ProfileHero.js +8 -8
  30. package/dist/composites/ScatterWebGL.d.ts +22 -0
  31. package/dist/composites/ScatterWebGL.d.ts.map +1 -0
  32. package/dist/composites/ScatterWebGL.js +45 -0
  33. package/dist/composites/SiteFooter.d.ts +1 -1
  34. package/dist/composites/SiteFooter.js +1 -1
  35. package/dist/composites/SiteNav.d.ts +7 -2
  36. package/dist/composites/SiteNav.d.ts.map +1 -1
  37. package/dist/composites/SiteNav.js +9 -5
  38. package/dist/composites/StatCard.d.ts +2 -1
  39. package/dist/composites/StatCard.d.ts.map +1 -1
  40. package/dist/composites/StatCard.js +3 -3
  41. package/dist/composites/StatusDot.d.ts +1 -1
  42. package/dist/composites/Wordmark.d.ts +2 -2
  43. package/dist/composites/Wordmark.d.ts.map +1 -1
  44. package/dist/composites/cartesian-charts.d.ts +138 -0
  45. package/dist/composites/cartesian-charts.d.ts.map +1 -0
  46. package/dist/composites/cartesian-charts.js +401 -0
  47. package/dist/composites/chart-composition.d.ts +139 -0
  48. package/dist/composites/chart-composition.d.ts.map +1 -0
  49. package/dist/composites/chart-composition.js +486 -0
  50. package/dist/composites/chart-ui.d.ts +83 -0
  51. package/dist/composites/chart-ui.d.ts.map +1 -0
  52. package/dist/composites/chart-ui.js +108 -0
  53. package/dist/composites/charts-3d.d.ts +37 -0
  54. package/dist/composites/charts-3d.d.ts.map +1 -0
  55. package/dist/composites/charts-3d.js +121 -0
  56. package/dist/composites/flow-charts.d.ts +89 -0
  57. package/dist/composites/flow-charts.d.ts.map +1 -0
  58. package/dist/composites/flow-charts.js +186 -0
  59. package/dist/composites/radial-charts.d.ts +109 -0
  60. package/dist/composites/radial-charts.d.ts.map +1 -0
  61. package/dist/composites/radial-charts.js +176 -0
  62. package/dist/composites/scheduler-ui.d.ts +44 -0
  63. package/dist/composites/scheduler-ui.d.ts.map +1 -0
  64. package/dist/composites/scheduler-ui.js +71 -0
  65. package/dist/index.d.ts +68 -7
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +58 -7
  68. package/dist/lib/chart-export.d.ts +10 -0
  69. package/dist/lib/chart-export.d.ts.map +1 -0
  70. package/dist/lib/chart-export.js +102 -0
  71. package/dist/lib/charts.d.ts +235 -0
  72. package/dist/lib/charts.d.ts.map +1 -0
  73. package/dist/lib/charts.js +744 -0
  74. package/dist/lib/geo.d.ts +39 -0
  75. package/dist/lib/geo.d.ts.map +1 -0
  76. package/dist/lib/geo.js +101 -0
  77. package/dist/lib/iso.d.ts +21 -0
  78. package/dist/lib/iso.d.ts.map +1 -0
  79. package/dist/lib/iso.js +56 -0
  80. package/dist/lib/rrule.d.ts +20 -0
  81. package/dist/lib/rrule.d.ts.map +1 -0
  82. package/dist/lib/rrule.js +236 -0
  83. package/dist/lib/scheduler.d.ts +156 -0
  84. package/dist/lib/scheduler.d.ts.map +1 -0
  85. package/dist/lib/scheduler.js +502 -0
  86. package/dist/lib/webgl-scatter.d.ts +44 -0
  87. package/dist/lib/webgl-scatter.d.ts.map +1 -0
  88. package/dist/lib/webgl-scatter.js +185 -0
  89. package/dist/primitives/Accordion.d.ts +44 -20
  90. package/dist/primitives/Accordion.d.ts.map +1 -1
  91. package/dist/primitives/Accordion.js +82 -22
  92. package/dist/primitives/AppBar.d.ts +13 -0
  93. package/dist/primitives/AppBar.d.ts.map +1 -0
  94. package/dist/primitives/AppBar.js +27 -0
  95. package/dist/primitives/Autocomplete.d.ts +28 -0
  96. package/dist/primitives/Autocomplete.d.ts.map +1 -0
  97. package/dist/primitives/Autocomplete.js +118 -0
  98. package/dist/primitives/Avatar.d.ts +13 -1
  99. package/dist/primitives/Avatar.d.ts.map +1 -1
  100. package/dist/primitives/Avatar.js +17 -2
  101. package/dist/primitives/Backdrop.d.ts +17 -0
  102. package/dist/primitives/Backdrop.d.ts.map +1 -0
  103. package/dist/primitives/Backdrop.js +17 -0
  104. package/dist/primitives/BottomNavigation.d.ts +23 -0
  105. package/dist/primitives/BottomNavigation.d.ts.map +1 -0
  106. package/dist/primitives/BottomNavigation.js +30 -0
  107. package/dist/primitives/ButtonBase.d.ts +14 -0
  108. package/dist/primitives/ButtonBase.d.ts.map +1 -0
  109. package/dist/primitives/ButtonBase.js +13 -0
  110. package/dist/primitives/ButtonGroup.d.ts +25 -0
  111. package/dist/primitives/ButtonGroup.d.ts.map +1 -0
  112. package/dist/primitives/ButtonGroup.js +44 -0
  113. package/dist/primitives/CircularProgress.d.ts +16 -0
  114. package/dist/primitives/CircularProgress.d.ts.map +1 -0
  115. package/dist/primitives/CircularProgress.js +17 -0
  116. package/dist/primitives/ClickAwayListener.d.ts +16 -0
  117. package/dist/primitives/ClickAwayListener.d.ts.map +1 -0
  118. package/dist/primitives/ClickAwayListener.js +33 -0
  119. package/dist/primitives/Collapse.d.ts +19 -0
  120. package/dist/primitives/Collapse.d.ts.map +1 -0
  121. package/dist/primitives/Collapse.js +14 -0
  122. package/dist/primitives/Container.d.ts +13 -0
  123. package/dist/primitives/Container.d.ts.map +1 -0
  124. package/dist/primitives/Container.js +26 -0
  125. package/dist/primitives/Fab.d.ts +22 -0
  126. package/dist/primitives/Fab.d.ts.map +1 -0
  127. package/dist/primitives/Fab.js +42 -0
  128. package/dist/primitives/FormControl.d.ts +27 -0
  129. package/dist/primitives/FormControl.d.ts.map +1 -0
  130. package/dist/primitives/FormControl.js +24 -0
  131. package/dist/primitives/FormControlLabel.d.ts +18 -0
  132. package/dist/primitives/FormControlLabel.d.ts.map +1 -0
  133. package/dist/primitives/FormControlLabel.js +19 -0
  134. package/dist/primitives/Grid.d.ts +32 -0
  135. package/dist/primitives/Grid.d.ts.map +1 -0
  136. package/dist/primitives/Grid.js +50 -0
  137. package/dist/primitives/IconButton.d.ts +22 -0
  138. package/dist/primitives/IconButton.d.ts.map +1 -0
  139. package/dist/primitives/IconButton.js +39 -0
  140. package/dist/primitives/ImageList.d.ts +31 -0
  141. package/dist/primitives/ImageList.d.ts.map +1 -0
  142. package/dist/primitives/ImageList.js +33 -0
  143. package/dist/primitives/InputAdornment.d.ts +28 -0
  144. package/dist/primitives/InputAdornment.d.ts.map +1 -0
  145. package/dist/primitives/InputAdornment.js +13 -0
  146. package/dist/primitives/Link.d.ts +17 -0
  147. package/dist/primitives/Link.d.ts.map +1 -0
  148. package/dist/primitives/Link.js +29 -0
  149. package/dist/primitives/List.d.ts +41 -0
  150. package/dist/primitives/List.d.ts.map +1 -0
  151. package/dist/primitives/List.js +22 -0
  152. package/dist/primitives/Masonry.d.ts +14 -0
  153. package/dist/primitives/Masonry.d.ts.map +1 -0
  154. package/dist/primitives/Masonry.js +15 -0
  155. package/dist/primitives/Menu.d.ts +28 -0
  156. package/dist/primitives/Menu.d.ts.map +1 -0
  157. package/dist/primitives/Menu.js +54 -0
  158. package/dist/primitives/MobileStepper.d.ts +15 -0
  159. package/dist/primitives/MobileStepper.d.ts.map +1 -0
  160. package/dist/primitives/MobileStepper.js +8 -0
  161. package/dist/primitives/Modal.d.ts +18 -0
  162. package/dist/primitives/Modal.d.ts.map +1 -0
  163. package/dist/primitives/Modal.js +29 -0
  164. package/dist/primitives/NoSsr.d.ts +15 -0
  165. package/dist/primitives/NoSsr.d.ts.map +1 -0
  166. package/dist/primitives/NoSsr.js +19 -0
  167. package/dist/primitives/Paper.d.ts +22 -0
  168. package/dist/primitives/Paper.d.ts.map +1 -0
  169. package/dist/primitives/Paper.js +33 -0
  170. package/dist/primitives/Progress.d.ts +6 -2
  171. package/dist/primitives/Progress.d.ts.map +1 -1
  172. package/dist/primitives/Progress.js +8 -3
  173. package/dist/primitives/Snackbar.d.ts +23 -0
  174. package/dist/primitives/Snackbar.d.ts.map +1 -0
  175. package/dist/primitives/Snackbar.js +33 -0
  176. package/dist/primitives/SpeedDial.d.ts +26 -0
  177. package/dist/primitives/SpeedDial.d.ts.map +1 -0
  178. package/dist/primitives/SpeedDial.js +26 -0
  179. package/dist/primitives/Stack.d.ts +15 -0
  180. package/dist/primitives/Stack.d.ts.map +1 -0
  181. package/dist/primitives/Stack.js +45 -0
  182. package/dist/primitives/StarRating.d.ts +19 -1
  183. package/dist/primitives/StarRating.d.ts.map +1 -1
  184. package/dist/primitives/StarRating.js +36 -6
  185. package/dist/primitives/Stepper.d.ts +36 -0
  186. package/dist/primitives/Stepper.d.ts.map +1 -0
  187. package/dist/primitives/Stepper.js +53 -0
  188. package/dist/primitives/TablePagination.d.ts +16 -0
  189. package/dist/primitives/TablePagination.d.ts.map +1 -0
  190. package/dist/primitives/TablePagination.js +12 -0
  191. package/dist/primitives/TextField.d.ts +24 -0
  192. package/dist/primitives/TextField.d.ts.map +1 -0
  193. package/dist/primitives/TextField.js +19 -0
  194. package/dist/primitives/TextareaAutosize.d.ts +11 -0
  195. package/dist/primitives/TextareaAutosize.d.ts.map +1 -0
  196. package/dist/primitives/TextareaAutosize.js +26 -0
  197. package/dist/primitives/ToggleButton.d.ts +28 -0
  198. package/dist/primitives/ToggleButton.d.ts.map +1 -0
  199. package/dist/primitives/ToggleButton.js +56 -0
  200. package/dist/primitives/TransferList.d.ts +21 -0
  201. package/dist/primitives/TransferList.d.ts.map +1 -0
  202. package/dist/primitives/TransferList.js +40 -0
  203. package/dist/primitives/Typography.d.ts +23 -0
  204. package/dist/primitives/Typography.d.ts.map +1 -0
  205. package/dist/primitives/Typography.js +69 -0
  206. package/dist/primitives/transitions.d.ts +29 -0
  207. package/dist/primitives/transitions.d.ts.map +1 -0
  208. package/dist/primitives/transitions.js +52 -0
  209. package/package.json +28 -4
  210. package/skills/spatika-ui/SKILL.md +96 -0
  211. package/src/composites/Card.tsx +51 -1
  212. package/src/composites/ChartDataGrid.test.tsx +57 -0
  213. package/src/composites/ChartDataGrid.tsx +196 -0
  214. package/src/composites/CoverHero.test.tsx +38 -0
  215. package/src/composites/CoverHero.tsx +29 -22
  216. package/src/composites/EntityMediaCard.test.tsx +58 -0
  217. package/src/composites/EntityMediaCard.tsx +31 -13
  218. package/src/composites/EventCalendar.tsx +1030 -0
  219. package/src/composites/EventEditor.tsx +268 -0
  220. package/src/composites/EventTimeline.tsx +366 -0
  221. package/src/composites/MapChart.test.tsx +39 -0
  222. package/src/composites/MapChart.tsx +130 -0
  223. package/src/composites/ProfileHero.test.tsx +33 -0
  224. package/src/composites/ProfileHero.tsx +96 -79
  225. package/src/composites/ScatterWebGL.test.tsx +25 -0
  226. package/src/composites/ScatterWebGL.tsx +79 -0
  227. package/src/composites/SiteFooter.test.tsx +37 -0
  228. package/src/composites/SiteFooter.tsx +1 -1
  229. package/src/composites/SiteNav.test.tsx +46 -0
  230. package/src/composites/SiteNav.tsx +14 -4
  231. package/src/composites/StatCard.test.tsx +30 -0
  232. package/src/composites/StatCard.tsx +4 -0
  233. package/src/composites/Wordmark.test.tsx +23 -0
  234. package/src/composites/Wordmark.tsx +2 -2
  235. package/src/composites/cartesian-charts.test.tsx +52 -0
  236. package/src/composites/cartesian-charts.tsx +1287 -0
  237. package/src/composites/chart-composition.test.tsx +53 -0
  238. package/src/composites/chart-composition.tsx +898 -0
  239. package/src/composites/chart-ui.tsx +328 -0
  240. package/src/composites/charts-3d.test.tsx +25 -0
  241. package/src/composites/charts-3d.tsx +318 -0
  242. package/src/composites/charts.test.tsx +254 -0
  243. package/src/composites/chrome.test.tsx +29 -0
  244. package/src/composites/flow-charts.test.tsx +79 -0
  245. package/src/composites/flow-charts.tsx +607 -0
  246. package/src/composites/marketing.test.tsx +38 -34
  247. package/src/composites/radial-charts.test.tsx +74 -0
  248. package/src/composites/radial-charts.tsx +617 -0
  249. package/src/composites/scheduler-ui.tsx +306 -0
  250. package/src/composites/scheduler.test.tsx +280 -0
  251. package/src/index.test.ts +26 -0
  252. package/src/index.ts +287 -5
  253. package/src/lib/chart-export.test.ts +20 -0
  254. package/src/lib/chart-export.ts +99 -0
  255. package/src/lib/charts-platform.test.ts +93 -0
  256. package/src/lib/charts.test.ts +132 -0
  257. package/src/lib/charts.ts +1021 -0
  258. package/src/lib/geo.test.ts +42 -0
  259. package/src/lib/geo.ts +138 -0
  260. package/src/lib/iso.test.ts +22 -0
  261. package/src/lib/iso.ts +102 -0
  262. package/src/lib/rrule.test.ts +53 -0
  263. package/src/lib/rrule.ts +281 -0
  264. package/src/lib/scheduler.test.ts +199 -0
  265. package/src/lib/scheduler.ts +693 -0
  266. package/src/lib/tokens.test.ts +2 -2
  267. package/src/lib/webgl-scatter.test.ts +36 -0
  268. package/src/lib/webgl-scatter.ts +230 -0
  269. package/src/primitives/Accordion.tsx +218 -63
  270. package/src/primitives/AppBar.tsx +39 -0
  271. package/src/primitives/Autocomplete.tsx +236 -0
  272. package/src/primitives/Avatar.tsx +52 -1
  273. package/src/primitives/Backdrop.tsx +48 -0
  274. package/src/primitives/BottomNavigation.tsx +102 -0
  275. package/src/primitives/ButtonBase.tsx +34 -0
  276. package/src/primitives/ButtonGroup.tsx +90 -0
  277. package/src/primitives/CircularProgress.tsx +104 -0
  278. package/src/primitives/ClickAwayListener.tsx +46 -0
  279. package/src/primitives/Collapse.tsx +39 -0
  280. package/src/primitives/Container.tsx +40 -0
  281. package/src/primitives/Fab.tsx +62 -0
  282. package/src/primitives/FormControl.tsx +90 -0
  283. package/src/primitives/FormControlLabel.tsx +51 -0
  284. package/src/primitives/Grid.tsx +101 -0
  285. package/src/primitives/IconButton.tsx +59 -0
  286. package/src/primitives/ImageList.test.tsx +48 -0
  287. package/src/primitives/ImageList.tsx +112 -0
  288. package/src/primitives/InputAdornment.tsx +86 -0
  289. package/src/primitives/Link.tsx +48 -0
  290. package/src/primitives/List.tsx +121 -0
  291. package/src/primitives/Masonry.tsx +32 -0
  292. package/src/primitives/Menu.tsx +112 -0
  293. package/src/primitives/MobileStepper.tsx +64 -0
  294. package/src/primitives/Modal.tsx +70 -0
  295. package/src/primitives/NoSsr.tsx +28 -0
  296. package/src/primitives/Paper.tsx +55 -0
  297. package/src/primitives/Progress.tsx +25 -7
  298. package/src/primitives/Snackbar.tsx +83 -0
  299. package/src/primitives/SpeedDial.tsx +110 -0
  300. package/src/primitives/Stack.tsx +88 -0
  301. package/src/primitives/StarRating.tsx +87 -28
  302. package/src/primitives/Stepper.tsx +184 -0
  303. package/src/primitives/TablePagination.tsx +58 -0
  304. package/src/primitives/TextField.tsx +105 -0
  305. package/src/primitives/TextareaAutosize.tsx +49 -0
  306. package/src/primitives/ToggleButton.tsx +148 -0
  307. package/src/primitives/TransferList.tsx +110 -0
  308. package/src/primitives/Typography.tsx +90 -0
  309. package/src/primitives/mui-more.test.tsx +76 -0
  310. package/src/primitives/mui.test.tsx +134 -0
  311. package/src/primitives/transitions.tsx +120 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Raw WebGL scatter renderer — no three.js.
3
+ * Canvas sits behind SVG axes; hit-testing stays on the CPU.
4
+ */
5
+ export const WEBGL_AUTO_THRESHOLD = 2000;
6
+ export function shouldUseWebGL(renderer, pointCount) {
7
+ if (renderer === "webgl")
8
+ return true;
9
+ if (renderer === "auto")
10
+ return pointCount >= WEBGL_AUTO_THRESHOLD;
11
+ return false;
12
+ }
13
+ export function parseCssColor(css) {
14
+ const hex = css.trim();
15
+ const hexMatch = /^#([0-9a-f]{3,8})$/i.exec(hex);
16
+ if (hexMatch) {
17
+ let h = hexMatch[1];
18
+ if (h.length === 3 || h.length === 4)
19
+ h = [...h].map((c) => c + c).join("");
20
+ const n = Number.parseInt(h.slice(0, 6), 16);
21
+ const a = h.length === 8 ? Number.parseInt(h.slice(6, 8), 16) / 255 : 1;
22
+ return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255, a];
23
+ }
24
+ const rgb = /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*([\d.]+))?\s*\)$/i.exec(hex);
25
+ if (rgb) {
26
+ return [
27
+ Number(rgb[1]) / 255,
28
+ Number(rgb[2]) / 255,
29
+ Number(rgb[3]) / 255,
30
+ rgb[4] != null ? Number(rgb[4]) : 1,
31
+ ];
32
+ }
33
+ return null;
34
+ }
35
+ export function resolveCssColor(color, el) {
36
+ const parsed = parseCssColor(color);
37
+ if (parsed)
38
+ return parsed;
39
+ if (typeof document === "undefined" || !el)
40
+ return [0.35, 0.55, 0.95, 1];
41
+ const probe = document.createElement("span");
42
+ probe.style.color = color;
43
+ probe.style.position = "absolute";
44
+ probe.style.pointerEvents = "none";
45
+ probe.style.opacity = "0";
46
+ el.appendChild(probe);
47
+ const computed = getComputedStyle(probe).color;
48
+ probe.remove();
49
+ return parseCssColor(computed) ?? [0.35, 0.55, 0.95, 1];
50
+ }
51
+ export function nearestScatterHit(candidates, px, py, pad = 4) {
52
+ let best = null;
53
+ let bestDist = Infinity;
54
+ for (const item of candidates) {
55
+ const dx = item.x - px;
56
+ const dy = item.y - py;
57
+ const dist = Math.hypot(dx, dy);
58
+ if (dist <= item.r + pad && dist < bestDist) {
59
+ best = item;
60
+ bestDist = dist;
61
+ }
62
+ }
63
+ return best;
64
+ }
65
+ export function svgPointerPosition(svg, clientX, clientY, width, height) {
66
+ const bounds = svg.getBoundingClientRect();
67
+ const w = bounds.width || width;
68
+ const h = bounds.height || height;
69
+ return {
70
+ x: ((clientX - bounds.left) / w) * width,
71
+ y: ((clientY - bounds.top) / h) * height,
72
+ };
73
+ }
74
+ const VS = `
75
+ attribute vec2 a_position;
76
+ attribute float a_size;
77
+ uniform vec2 u_resolution;
78
+ uniform float u_dpr;
79
+ void main() {
80
+ vec2 zeroToOne = a_position / u_resolution;
81
+ vec2 clip = zeroToOne * 2.0 - 1.0;
82
+ gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
83
+ gl_PointSize = max(1.0, a_size * u_dpr);
84
+ }
85
+ `;
86
+ const FS = `
87
+ precision mediump float;
88
+ uniform vec4 u_color;
89
+ void main() {
90
+ vec2 c = gl_PointCoord - vec2(0.5);
91
+ if (dot(c, c) > 0.25) discard;
92
+ gl_FragColor = u_color;
93
+ }
94
+ `;
95
+ function compile(gl, type, source) {
96
+ const shader = gl.createShader(type);
97
+ if (!shader)
98
+ return null;
99
+ gl.shaderSource(shader, source);
100
+ gl.compileShader(shader);
101
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
102
+ gl.deleteShader(shader);
103
+ return null;
104
+ }
105
+ return shader;
106
+ }
107
+ export function createScatterGL(canvas) {
108
+ const gl = canvas.getContext("webgl", {
109
+ alpha: true,
110
+ antialias: true,
111
+ premultipliedAlpha: true,
112
+ });
113
+ if (!gl)
114
+ return null;
115
+ const vs = compile(gl, gl.VERTEX_SHADER, VS);
116
+ const fs = compile(gl, gl.FRAGMENT_SHADER, FS);
117
+ if (!vs || !fs)
118
+ return null;
119
+ const program = gl.createProgram();
120
+ if (!program)
121
+ return null;
122
+ gl.attachShader(program, vs);
123
+ gl.attachShader(program, fs);
124
+ gl.linkProgram(program);
125
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS))
126
+ return null;
127
+ const buffer = gl.createBuffer();
128
+ if (!buffer)
129
+ return null;
130
+ gl.enable(gl.BLEND);
131
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
132
+ return {
133
+ gl,
134
+ program,
135
+ buffer,
136
+ aPosition: gl.getAttribLocation(program, "a_position"),
137
+ aSize: gl.getAttribLocation(program, "a_size"),
138
+ uResolution: gl.getUniformLocation(program, "u_resolution"),
139
+ uDpr: gl.getUniformLocation(program, "u_dpr"),
140
+ uColor: gl.getUniformLocation(program, "u_color"),
141
+ };
142
+ }
143
+ export function drawScatterGL(gpu, canvas, width, height, series) {
144
+ const dpr = typeof window !== "undefined" ? Math.min(window.devicePixelRatio || 1, 2) : 1;
145
+ const pixelW = Math.max(1, Math.round(width * dpr));
146
+ const pixelH = Math.max(1, Math.round(height * dpr));
147
+ if (canvas.width !== pixelW)
148
+ canvas.width = pixelW;
149
+ if (canvas.height !== pixelH)
150
+ canvas.height = pixelH;
151
+ canvas.style.width = `${width}px`;
152
+ canvas.style.height = `${height}px`;
153
+ const { gl } = gpu;
154
+ gl.viewport(0, 0, pixelW, pixelH);
155
+ gl.clearColor(0, 0, 0, 0);
156
+ gl.clear(gl.COLOR_BUFFER_BIT);
157
+ gl.useProgram(gpu.program);
158
+ gl.uniform2f(gpu.uResolution, width, height);
159
+ gl.uniform1f(gpu.uDpr, dpr);
160
+ gl.bindBuffer(gl.ARRAY_BUFFER, gpu.buffer);
161
+ const stride = 3 * 4;
162
+ for (const item of series) {
163
+ if (!item.positions.length)
164
+ continue;
165
+ const data = new Float32Array(item.positions.length * 3);
166
+ item.positions.forEach((point, i) => {
167
+ data[i * 3] = point.x;
168
+ data[i * 3 + 1] = point.y;
169
+ data[i * 3 + 2] = point.size;
170
+ });
171
+ gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);
172
+ gl.enableVertexAttribArray(gpu.aPosition);
173
+ gl.vertexAttribPointer(gpu.aPosition, 2, gl.FLOAT, false, stride, 0);
174
+ gl.enableVertexAttribArray(gpu.aSize);
175
+ gl.vertexAttribPointer(gpu.aSize, 1, gl.FLOAT, false, stride, 8);
176
+ const [r, g, b, a] = resolveCssColor(item.color, canvas.parentElement ?? canvas);
177
+ gl.uniform4f(gpu.uColor, r, g, b, a);
178
+ gl.drawArrays(gl.POINTS, 0, item.positions.length);
179
+ }
180
+ }
181
+ export function destroyScatterGL(gpu) {
182
+ const { gl } = gpu;
183
+ gl.deleteBuffer(gpu.buffer);
184
+ gl.deleteProgram(gpu.program);
185
+ }
@@ -1,24 +1,48 @@
1
1
  import * as React from "react";
2
- declare function Accordion({ type, defaultValue, className, children, }: {
3
- type?: "single" | "multiple";
2
+ type AccordionType = "single" | "multiple";
3
+ export type AccordionProps = Omit<React.ComponentPropsWithoutRef<"div">, "onChange"> & {
4
+ type?: AccordionType;
5
+ value?: string | string[];
4
6
  defaultValue?: string | string[];
5
- className?: string;
6
- children: React.ReactNode;
7
- }): React.JSX.Element;
8
- declare function AccordionItem({ value, className, children, }: {
7
+ onValueChange?: (value: string | string[]) => void;
8
+ disabled?: boolean;
9
+ /** Remove the gap between items and stack them as a single surface. */
10
+ disableGutters?: boolean;
11
+ };
12
+ declare function Accordion({ type, value: valueProp, defaultValue, onValueChange, disabled, disableGutters, className, children, ...props }: AccordionProps): React.JSX.Element;
13
+ declare namespace Accordion {
14
+ var displayName: string;
15
+ }
16
+ export type AccordionItemProps = React.ComponentPropsWithoutRef<"div"> & {
9
17
  value: string;
10
- className?: string;
11
- children: React.ReactNode;
12
- }): React.JSX.Element;
13
- declare function AccordionTrigger({ value, className, children, }: {
14
- value: string;
15
- className?: string;
16
- children: React.ReactNode;
17
- }): React.JSX.Element;
18
- declare function AccordionContent({ value, className, children, }: {
19
- value: string;
20
- className?: string;
21
- children: React.ReactNode;
22
- }): React.JSX.Element | null;
23
- export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
18
+ disabled?: boolean;
19
+ };
20
+ declare function AccordionItem({ value, disabled, className, children, ...props }: AccordionItemProps): React.JSX.Element;
21
+ declare namespace AccordionItem {
22
+ var displayName: string;
23
+ }
24
+ export type AccordionTriggerProps = React.ComponentPropsWithoutRef<"button"> & {
25
+ /** @deprecated Prefer wrapping with AccordionItem — value is inherited. */
26
+ value?: string;
27
+ };
28
+ declare function AccordionTrigger({ value: valueProp, className, children, onClick, ...props }: AccordionTriggerProps): React.JSX.Element;
29
+ declare namespace AccordionTrigger {
30
+ var displayName: string;
31
+ }
32
+ export type AccordionContentProps = React.ComponentPropsWithoutRef<"div"> & {
33
+ /** @deprecated Prefer wrapping with AccordionItem — value is inherited. */
34
+ value?: string;
35
+ };
36
+ declare function AccordionContent({ value: valueProp, className, children, ...props }: AccordionContentProps): React.JSX.Element;
37
+ declare namespace AccordionContent {
38
+ var displayName: string;
39
+ }
40
+ declare function AccordionActions({ className, ...props }: React.ComponentPropsWithoutRef<"div">): React.JSX.Element;
41
+ declare namespace AccordionActions {
42
+ var displayName: string;
43
+ }
44
+ /** MUI-compatible aliases. */
45
+ declare const AccordionSummary: typeof AccordionTrigger;
46
+ declare const AccordionDetails: typeof AccordionContent;
47
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent, AccordionActions, AccordionSummary, AccordionDetails, };
24
48
  //# sourceMappingURL=Accordion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../src/primitives/Accordion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B,iBAAS,SAAS,CAAC,EACjB,IAAe,EACf,YAAY,EACZ,SAAS,EACT,QAAQ,GACT,EAAE;IACD,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,qBAqBA;AAED,iBAAS,aAAa,CAAC,EACrB,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,qBAUA;AAED,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,qBAoBA;AAED,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,4BAQA;AAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../src/primitives/Accordion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,KAAK,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAC;AAiC3C,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IACrF,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAOF,iBAAS,SAAS,CAAC,EACjB,IAAe,EACf,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,aAAa,EACb,QAAgB,EAChB,cAAsB,EACtB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,qBAkChB;kBA5CQ,SAAS;;;AA+ClB,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,GAAG;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,iBAAS,aAAa,CAAC,EACrB,KAAK,EACL,QAAgB,EAChB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,kBAAkB,qBAmCpB;kBAzCQ,aAAa;;;AA4CtB,MAAM,MAAM,qBAAqB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IAC7E,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EAAE,SAAS,EAChB,SAAS,EACT,QAAQ,EACR,OAAO,EACP,GAAG,KAAK,EACT,EAAE,qBAAqB,qBA2CvB;kBAjDQ,gBAAgB;;;AAoDzB,MAAM,MAAM,qBAAqB,GAAG,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,GAAG;IAC1E,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EAAE,SAAS,EAChB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,qBAAqB,qBAsBvB;kBA3BQ,gBAAgB;;;AA8BzB,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,qBAWvF;kBAXQ,gBAAgB;;;AAczB,8BAA8B;AAC9B,QAAA,MAAM,gBAAgB,yBAAmB,CAAC;AAC1C,QAAA,MAAM,gBAAgB,yBAAmB,CAAC;AAE1C,OAAO,EACL,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,CAAC"}
@@ -1,37 +1,97 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { ChevronDown } from "lucide-react";
4
+ import { useControllableState } from "../lib/use-controllable-state";
4
5
  import { cn } from "../lib/cn";
6
+ import { Collapse } from "./Collapse";
5
7
  const AccordionContext = React.createContext(null);
6
- function Accordion({ type = "single", defaultValue, className, children, }) {
7
- const initial = Array.isArray(defaultValue)
8
- ? defaultValue
9
- : defaultValue
10
- ? [defaultValue]
11
- : [];
12
- const [open, setOpen] = React.useState(initial);
8
+ const AccordionItemContext = React.createContext(null);
9
+ function useAccordion(component) {
10
+ const ctx = React.useContext(AccordionContext);
11
+ if (!ctx)
12
+ throw new Error(`${component} must be used within <Accordion>`);
13
+ return ctx;
14
+ }
15
+ function useAccordionItem(component) {
16
+ const ctx = React.useContext(AccordionItemContext);
17
+ if (!ctx)
18
+ throw new Error(`${component} must be used within <AccordionItem>`);
19
+ return ctx;
20
+ }
21
+ function toArray(value) {
22
+ if (value == null || value === "")
23
+ return [];
24
+ return Array.isArray(value) ? value : [value];
25
+ }
26
+ function Accordion({ type = "single", value: valueProp, defaultValue, onValueChange, disabled = false, disableGutters = false, className, children, ...props }) {
27
+ const [open = [], setOpen] = useControllableState({
28
+ prop: valueProp === undefined ? undefined : toArray(valueProp),
29
+ defaultProp: toArray(defaultValue),
30
+ onChange: (next) => {
31
+ onValueChange?.(type === "single" ? (next[0] ?? "") : next);
32
+ },
33
+ });
13
34
  const toggle = (id) => {
35
+ if (disabled)
36
+ return;
14
37
  setOpen((prev) => {
15
- const isOpen = prev.includes(id);
38
+ const current = prev ?? [];
39
+ const isOpen = current.includes(id);
16
40
  if (type === "single")
17
41
  return isOpen ? [] : [id];
18
- return isOpen ? prev.filter((x) => x !== id) : [...prev, id];
42
+ return isOpen ? current.filter((x) => x !== id) : [...current, id];
19
43
  });
20
44
  };
21
- return (_jsx(AccordionContext.Provider, { value: { open, toggle, type }, children: _jsx("div", { "data-slot": "accordion", className: cn("space-y-2", className), children: children }) }));
45
+ return (_jsx(AccordionContext.Provider, { value: { open: open ?? [], toggle, type, disabled, disableGutters }, children: _jsx("div", { "data-slot": "accordion", "data-disabled": disabled ? "" : undefined, "data-gutters": disableGutters ? "false" : "true", className: cn(disableGutters ? "overflow-hidden rounded-xl" : "space-y-2", className), ...props, children: children }) }));
22
46
  }
23
- function AccordionItem({ value, className, children, }) {
24
- return (_jsx("div", { "data-slot": "accordion-item", "data-value": value, className: cn("overflow-hidden rounded-xl border border-border/40 bg-card/40", className), children: children }));
47
+ Accordion.displayName = "Accordion";
48
+ function AccordionItem({ value, disabled = false, className, children, ...props }) {
49
+ const accordion = useAccordion("AccordionItem");
50
+ const reactId = React.useId();
51
+ const expanded = accordion.open.includes(value);
52
+ const isDisabled = disabled || accordion.disabled;
53
+ return (_jsx(AccordionItemContext.Provider, { value: {
54
+ value,
55
+ disabled: isDisabled,
56
+ expanded,
57
+ triggerId: `${reactId}-trigger`,
58
+ contentId: `${reactId}-content`,
59
+ }, children: _jsx("div", { "data-slot": "accordion-item", "data-value": value, "data-state": expanded ? "open" : "closed", "data-disabled": isDisabled ? "" : undefined, className: cn("overflow-hidden border-border/40 bg-card/40", accordion.disableGutters
60
+ ? "border-x border-b first:rounded-t-xl first:border-t last:rounded-b-xl"
61
+ : "rounded-xl border", isDisabled && "pointer-events-none opacity-50", className), ...props, children: children }) }));
25
62
  }
26
- function AccordionTrigger({ value, className, children, }) {
27
- const ctx = React.useContext(AccordionContext);
28
- const isOpen = ctx?.open.includes(value);
29
- return (_jsxs("button", { type: "button", "data-slot": "accordion-trigger", "aria-expanded": isOpen, className: cn("flex w-full items-center justify-between gap-2 px-4 py-3 text-left text-sm font-bold", className), onClick: () => ctx?.toggle(value), children: [children, _jsx(ChevronDown, { className: cn("size-4 shrink-0 transition-transform", isOpen && "rotate-180") })] }));
63
+ AccordionItem.displayName = "AccordionItem";
64
+ function AccordionTrigger({ value: valueProp, className, children, onClick, ...props }) {
65
+ const accordion = useAccordion("AccordionTrigger");
66
+ const item = React.useContext(AccordionItemContext);
67
+ const value = valueProp ?? item?.value;
68
+ if (!value)
69
+ throw new Error("AccordionTrigger requires AccordionItem or a value prop");
70
+ const expanded = item?.expanded ?? accordion.open.includes(value);
71
+ const disabled = item?.disabled ?? accordion.disabled;
72
+ return (_jsx("h3", { className: "m-0", children: _jsxs("button", { type: "button", id: item?.triggerId, "data-slot": "accordion-trigger", "data-state": expanded ? "open" : "closed", "aria-expanded": expanded, "aria-controls": item?.contentId, disabled: disabled, className: cn("flex w-full items-center justify-between gap-2 px-4 py-3 text-left text-sm font-bold outline-none transition-colors", "hover:bg-muted/30 focus-visible:ring-ring/50 focus-visible:ring-[3px]", "disabled:cursor-not-allowed", className), onClick: (event) => {
73
+ onClick?.(event);
74
+ if (event.defaultPrevented || disabled)
75
+ return;
76
+ accordion.toggle(value);
77
+ }, ...props, children: [children, _jsx(ChevronDown, { "aria-hidden": true, className: cn("size-4 shrink-0 text-muted-foreground transition-transform duration-300", expanded && "rotate-180") })] }) }));
30
78
  }
31
- function AccordionContent({ value, className, children, }) {
32
- const ctx = React.useContext(AccordionContext);
33
- if (!ctx?.open.includes(value))
34
- return null;
35
- return (_jsx("div", { "data-slot": "accordion-content", className: cn("border-t border-border/30 px-4 py-3 text-sm", className), children: children }));
79
+ AccordionTrigger.displayName = "AccordionTrigger";
80
+ function AccordionContent({ value: valueProp, className, children, ...props }) {
81
+ const accordion = useAccordion("AccordionContent");
82
+ const item = React.useContext(AccordionItemContext);
83
+ const value = valueProp ?? item?.value;
84
+ if (!value)
85
+ throw new Error("AccordionContent requires AccordionItem or a value prop");
86
+ const expanded = item?.expanded ?? accordion.open.includes(value);
87
+ return (_jsx(Collapse, { in: expanded, children: _jsx("div", { id: item?.contentId, role: "region", "aria-labelledby": item?.triggerId, "data-slot": "accordion-content", className: cn("border-t border-border/30 px-4 py-3 text-sm", className), ...props, children: children }) }));
88
+ }
89
+ AccordionContent.displayName = "AccordionContent";
90
+ function AccordionActions({ className, ...props }) {
91
+ return (_jsx("div", { "data-slot": "accordion-actions", className: cn("flex flex-wrap items-center justify-end gap-2 border-t border-border/30 px-4 py-2.5", className), ...props }));
36
92
  }
37
- export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
93
+ AccordionActions.displayName = "AccordionActions";
94
+ /** MUI-compatible aliases. */
95
+ const AccordionSummary = AccordionTrigger;
96
+ const AccordionDetails = AccordionContent;
97
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent, AccordionActions, AccordionSummary, AccordionDetails, };
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const appBarVariants: (props?: ({
4
+ position?: "fixed" | "relative" | "static" | "sticky" | null | undefined;
5
+ color?: "transparent" | "default" | "primary" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ export type AppBarProps = Omit<React.ComponentPropsWithoutRef<"header">, "color"> & VariantProps<typeof appBarVariants>;
8
+ declare function AppBar({ className, position, color, ...props }: AppBarProps): React.JSX.Element;
9
+ declare namespace AppBar {
10
+ var displayName: string;
11
+ }
12
+ export { AppBar, appBarVariants };
13
+ //# sourceMappingURL=AppBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppBar.d.ts","sourceRoot":"","sources":["../../src/primitives/AppBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,QAAA,MAAM,cAAc;;;8EAkBlB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,GAC/E,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtC,iBAAS,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,qBAQpE;kBARQ,MAAM;;;AAWf,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import { cn } from "../lib/cn";
4
+ const appBarVariants = cva("z-40 flex w-full items-center border-b border-border/50", {
5
+ variants: {
6
+ position: {
7
+ static: "relative",
8
+ sticky: "sticky top-0",
9
+ fixed: "fixed inset-x-0 top-0",
10
+ relative: "relative",
11
+ },
12
+ color: {
13
+ default: "glass-header text-foreground",
14
+ primary: "bg-primary text-primary-foreground border-transparent",
15
+ transparent: "border-transparent bg-transparent",
16
+ },
17
+ },
18
+ defaultVariants: {
19
+ position: "sticky",
20
+ color: "default",
21
+ },
22
+ });
23
+ function AppBar({ className, position, color, ...props }) {
24
+ return (_jsx("header", { "data-slot": "app-bar", className: cn(appBarVariants({ position, color }), className), ...props }));
25
+ }
26
+ AppBar.displayName = "AppBar";
27
+ export { AppBar, appBarVariants };
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ export type AutocompleteOption = {
3
+ label: string;
4
+ value: string;
5
+ disabled?: boolean;
6
+ };
7
+ export type AutocompleteProps = Omit<React.ComponentPropsWithoutRef<"div">, "onChange" | "defaultValue"> & {
8
+ options: Array<string | AutocompleteOption>;
9
+ value?: string | string[] | null;
10
+ defaultValue?: string | string[] | null;
11
+ onChange?: (value: string | string[] | null, option?: AutocompleteOption | AutocompleteOption[] | null) => void;
12
+ multiple?: boolean;
13
+ freeSolo?: boolean;
14
+ label?: React.ReactNode;
15
+ placeholder?: string;
16
+ disabled?: boolean;
17
+ fullWidth?: boolean;
18
+ noOptionsText?: string;
19
+ };
20
+ /**
21
+ * Filterable combobox. Supports single, multiple, and free-solo entry.
22
+ */
23
+ declare function Autocomplete({ options: optionsProp, value: valueProp, defaultValue, onChange, multiple, freeSolo, label, placeholder, disabled, fullWidth, noOptionsText, className, id, ...props }: AutocompleteProps): React.JSX.Element;
24
+ declare namespace Autocomplete {
25
+ var displayName: string;
26
+ }
27
+ export { Autocomplete };
28
+ //# sourceMappingURL=Autocomplete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Autocomplete.d.ts","sourceRoot":"","sources":["../../src/primitives/Autocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAQF,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,EACrC,UAAU,GAAG,cAAc,CAC5B,GAAG;IACF,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC;IAC5C,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAChH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAOF;;GAEG;AACH,iBAAS,YAAY,CAAC,EACpB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,QAAQ,EACR,QAAgB,EAChB,QAAgB,EAChB,KAAK,EACL,WAAuB,EACvB,QAAQ,EACR,SAAS,EACT,aAA4B,EAC5B,SAAS,EACT,EAAE,EACF,GAAG,KAAK,EACT,EAAE,iBAAiB,qBA4KnB;kBA3LQ,YAAY;;;AA8LrB,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { Check, ChevronsUpDown, X } from "lucide-react";
4
+ import { useControllableState } from "../lib/use-controllable-state";
5
+ import { useDismissable } from "../lib/use-dismissable";
6
+ import { cn } from "../lib/cn";
7
+ import { Input } from "./Input";
8
+ import { Label } from "./Label";
9
+ function normalizeOptions(options) {
10
+ return options.map((option) => typeof option === "string" ? { label: option, value: option } : option);
11
+ }
12
+ function asList(value) {
13
+ if (value == null || value === "")
14
+ return [];
15
+ return Array.isArray(value) ? value : [value];
16
+ }
17
+ /**
18
+ * Filterable combobox. Supports single, multiple, and free-solo entry.
19
+ */
20
+ function Autocomplete({ options: optionsProp, value: valueProp, defaultValue, onChange, multiple = false, freeSolo = false, label, placeholder = "Search…", disabled, fullWidth, noOptionsText = "No options", className, id, ...props }) {
21
+ const autoId = React.useId();
22
+ const fieldId = id ?? autoId;
23
+ const options = React.useMemo(() => normalizeOptions(optionsProp), [optionsProp]);
24
+ const [value, setValue] = useControllableState({
25
+ prop: valueProp,
26
+ defaultProp: defaultValue ?? (multiple ? [] : null),
27
+ onChange: (next) => {
28
+ const list = asList(next);
29
+ const matched = options.filter((opt) => list.includes(opt.value));
30
+ onChange?.(next, multiple ? matched : (matched[0] ?? null));
31
+ },
32
+ });
33
+ const selected = asList(value);
34
+ const [query, setQuery] = React.useState("");
35
+ const [open, setOpen] = React.useState(false);
36
+ const [highlight, setHighlight] = React.useState(0);
37
+ const rootRef = React.useRef(null);
38
+ const listRef = React.useRef(null);
39
+ const filtered = options.filter((opt) => {
40
+ if (multiple && selected.includes(opt.value) && !query)
41
+ return true;
42
+ return opt.label.toLowerCase().includes(query.toLowerCase());
43
+ });
44
+ useDismissable({
45
+ enabled: open,
46
+ onDismiss: () => setOpen(false),
47
+ refs: [rootRef, listRef],
48
+ });
49
+ const commit = (next) => {
50
+ if (disabled)
51
+ return;
52
+ if (multiple) {
53
+ const list = selected.includes(next)
54
+ ? selected.filter((item) => item !== next)
55
+ : [...selected, next];
56
+ setValue(list);
57
+ setQuery("");
58
+ }
59
+ else {
60
+ setValue(next);
61
+ setQuery("");
62
+ setOpen(false);
63
+ }
64
+ };
65
+ const display = multiple
66
+ ? query
67
+ : open
68
+ ? query
69
+ : (options.find((opt) => opt.value === selected[0])?.label ?? selected[0] ?? "");
70
+ return (_jsxs("div", { ref: rootRef, "data-slot": "autocomplete", className: cn("relative", fullWidth && "w-full", className), ...props, children: [label ? _jsx(Label, { htmlFor: fieldId, children: label }) : null, _jsxs("div", { className: cn("mt-1.5 flex min-h-9 flex-wrap items-center gap-1 rounded-md border border-input bg-input-background px-2 py-1", "focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]", disabled && "opacity-50"), children: [multiple
71
+ ? selected.map((item) => {
72
+ const opt = options.find((option) => option.value === item);
73
+ return (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border border-border/50 bg-muted/50 px-2 py-0.5 text-xs font-bold", children: [opt?.label ?? item, _jsx("button", { type: "button", "aria-label": `Remove ${opt?.label ?? item}`, className: "text-muted-foreground hover:text-foreground", onClick: () => commit(item), children: _jsx(X, { className: "size-3" }) })] }, item));
74
+ })
75
+ : null, _jsx(Input, { id: fieldId, disabled: disabled, role: "combobox", "aria-expanded": open, "aria-autocomplete": "list", placeholder: selected.length && multiple ? undefined : placeholder, value: multiple ? query : display, className: "h-7 min-w-16 flex-1 border-0 bg-transparent px-1 shadow-none focus-visible:ring-0", onFocus: () => {
76
+ setOpen(true);
77
+ if (!multiple) {
78
+ const current = options.find((opt) => opt.value === selected[0])?.label ?? selected[0] ?? "";
79
+ setQuery(current);
80
+ }
81
+ }, onChange: (event) => {
82
+ setQuery(event.target.value);
83
+ setOpen(true);
84
+ setHighlight(0);
85
+ if (!multiple && !freeSolo) {
86
+ /* keep typing local until a selection is committed */
87
+ }
88
+ }, onKeyDown: (event) => {
89
+ if (event.key === "ArrowDown") {
90
+ event.preventDefault();
91
+ setOpen(true);
92
+ setHighlight((index) => Math.min(filtered.length - 1, index + 1));
93
+ }
94
+ else if (event.key === "ArrowUp") {
95
+ event.preventDefault();
96
+ setHighlight((index) => Math.max(0, index - 1));
97
+ }
98
+ else if (event.key === "Enter") {
99
+ event.preventDefault();
100
+ const hit = filtered[highlight];
101
+ if (hit)
102
+ commit(hit.value);
103
+ else if (freeSolo && query.trim())
104
+ commit(query.trim());
105
+ }
106
+ else if (event.key === "Escape") {
107
+ setOpen(false);
108
+ }
109
+ else if (event.key === "Backspace" && multiple && !query && selected.length) {
110
+ commit(selected[selected.length - 1]);
111
+ }
112
+ } }), _jsx(ChevronsUpDown, { className: "size-3.5 shrink-0 text-muted-foreground" })] }), open ? (_jsx("div", { ref: listRef, role: "listbox", "data-slot": "autocomplete-list", className: "glass-menu absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-xl border border-border/50 p-1 shadow-xl", children: filtered.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: noOptionsText })) : (filtered.map((opt, index) => {
113
+ const active = selected.includes(opt.value);
114
+ return (_jsxs("button", { type: "button", role: "option", "aria-selected": active, disabled: opt.disabled, className: cn("flex w-full items-center justify-between rounded-lg px-3 py-2 text-left text-sm font-medium", index === highlight ? "bg-muted/60" : "hover:bg-muted/40", opt.disabled && "opacity-40"), onMouseEnter: () => setHighlight(index), onClick: () => commit(opt.value), children: [opt.label, active ? _jsx(Check, { className: "size-3.5 text-primary" }) : null] }, opt.value));
115
+ })) })) : null] }));
116
+ }
117
+ Autocomplete.displayName = "Autocomplete";
118
+ export { Autocomplete };
@@ -11,5 +11,17 @@ declare function InitialsAvatar({ name, className, textClassName, }: {
11
11
  className?: string;
12
12
  textClassName?: string;
13
13
  }): React.JSX.Element;
14
- export { Avatar, AvatarImage, AvatarFallback, InitialsAvatar };
14
+ export type AvatarGroupProps = React.ComponentPropsWithoutRef<"div"> & {
15
+ max?: number;
16
+ total?: number;
17
+ spacing?: "sm" | "md" | "lg";
18
+ };
19
+ /**
20
+ * Overlapping avatar stack with an overflow count.
21
+ */
22
+ declare function AvatarGroup({ max, total, spacing, className, children, ...props }: AvatarGroupProps): React.JSX.Element;
23
+ declare namespace AvatarGroup {
24
+ var displayName: string;
25
+ }
26
+ export { Avatar, AvatarImage, AvatarFallback, InitialsAvatar, AvatarGroup };
15
27
  //# sourceMappingURL=Avatar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/primitives/Avatar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,QAAA,MAAM,MAAM,sKA6BV,CAAC;AAGH,QAAA,MAAM,WAAW,4KAsCf,CAAC;AAGH,QAAA,MAAM,cAAc,sKAoBlB,CAAC;AAGH;;;GAGG;AACH,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,SAAS,EACT,aAAa,GACd,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,qBAcA;AAED,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/primitives/Avatar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,QAAA,MAAM,MAAM,sKA6BV,CAAC;AAGH,QAAA,MAAM,WAAW,4KAsCf,CAAC;AAGH,QAAA,MAAM,cAAc,sKAoBlB,CAAC;AAGH;;;GAGG;AACH,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,SAAS,EACT,aAAa,GACd,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,qBAcA;AAED,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,GAAG;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC9B,CAAC;AAQF;;GAEG;AACH,iBAAS,WAAW,CAAC,EACnB,GAAO,EACP,KAAK,EACL,OAAc,EACd,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,gBAAgB,qBA0BlB;kBAjCQ,WAAW;;;AAoCpB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { getAvatarColor, getInitials } from "../lib/avatar-utils";
4
4
  import { cn } from "../lib/cn";
@@ -49,4 +49,19 @@ function InitialsAvatar({ name, className, textClassName, }) {
49
49
  const initials = getInitials(n) || "?";
50
50
  return (_jsx("div", { className: cn("relative flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full text-white", getAvatarColor(n), className), children: _jsx("span", { className: cn("leading-none", textClassName), children: initials }) }));
51
51
  }
52
- export { Avatar, AvatarImage, AvatarFallback, InitialsAvatar };
52
+ const spacingClass = {
53
+ sm: "-space-x-1",
54
+ md: "-space-x-2",
55
+ lg: "-space-x-3",
56
+ };
57
+ /**
58
+ * Overlapping avatar stack with an overflow count.
59
+ */
60
+ function AvatarGroup({ max = 5, total, spacing = "md", className, children, ...props }) {
61
+ const avatars = React.Children.toArray(children);
62
+ const extra = Math.max(0, (total ?? avatars.length) - max);
63
+ const shown = extra > 0 ? avatars.slice(0, max) : avatars;
64
+ return (_jsxs("div", { "data-slot": "avatar-group", className: cn("flex items-center [&_[data-slot=avatar]]:ring-2 [&_[data-slot=avatar]]:ring-background", spacingClass[spacing], className), ...props, children: [shown, extra > 0 ? (_jsxs("span", { "data-slot": "avatar-group-surplus", className: "relative z-[1] flex size-10 shrink-0 items-center justify-center rounded-full border-2 border-background bg-muted text-xs font-bold text-muted-foreground", children: ["+", extra] })) : null] }));
65
+ }
66
+ AvatarGroup.displayName = "AvatarGroup";
67
+ export { Avatar, AvatarImage, AvatarFallback, InitialsAvatar, AvatarGroup };