@epilot/spark-ui 1.0.0-alpha.2 → 1.0.0-alpha.3

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 (549) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +2 -0
  3. package/README.md +7 -1
  4. package/dist/chunk-aJGBMT86.cjs +29 -0
  5. package/dist/components/accordion.cjs +57 -0
  6. package/dist/components/accordion.cjs.map +1 -0
  7. package/dist/components/accordion.d.cts +45 -0
  8. package/dist/components/accordion.d.ts +45 -0
  9. package/dist/components/accordion.js +51 -0
  10. package/dist/components/accordion.js.map +1 -0
  11. package/dist/components/alert-dialog.cjs +137 -0
  12. package/dist/components/alert-dialog.cjs.map +1 -0
  13. package/dist/components/alert-dialog.d.cts +63 -0
  14. package/dist/components/alert-dialog.d.ts +63 -0
  15. package/dist/components/alert-dialog.js +123 -0
  16. package/dist/components/alert-dialog.js.map +1 -0
  17. package/dist/components/attachment.cjs +119 -0
  18. package/dist/components/attachment.cjs.map +1 -0
  19. package/dist/components/attachment.d.cts +67 -0
  20. package/dist/components/attachment.d.ts +67 -0
  21. package/dist/components/attachment.js +108 -0
  22. package/dist/components/attachment.js.map +1 -0
  23. package/dist/components/badge.cjs +20 -0
  24. package/dist/components/badge.cjs.map +1 -0
  25. package/dist/components/badge.d.cts +12 -0
  26. package/dist/components/badge.d.ts +12 -0
  27. package/dist/components/badge.js +17 -0
  28. package/dist/components/badge.js.map +1 -0
  29. package/dist/components/bar-chart.cjs +519 -0
  30. package/dist/components/bar-chart.cjs.map +1 -0
  31. package/dist/components/bar-chart.d.cts +83 -0
  32. package/dist/components/bar-chart.d.ts +83 -0
  33. package/dist/components/bar-chart.js +517 -0
  34. package/dist/components/bar-chart.js.map +1 -0
  35. package/dist/components/battery-progress-row.cjs +140 -0
  36. package/dist/components/battery-progress-row.cjs.map +1 -0
  37. package/dist/components/battery-progress-row.d.cts +78 -0
  38. package/dist/components/battery-progress-row.d.ts +78 -0
  39. package/dist/components/battery-progress-row.js +129 -0
  40. package/dist/components/battery-progress-row.js.map +1 -0
  41. package/dist/components/breadcrumbs.cjs +65 -0
  42. package/dist/components/breadcrumbs.cjs.map +1 -0
  43. package/dist/components/breadcrumbs.d.cts +44 -0
  44. package/dist/components/breadcrumbs.d.ts +44 -0
  45. package/dist/components/breadcrumbs.js +58 -0
  46. package/dist/components/breadcrumbs.js.map +1 -0
  47. package/dist/components/bubble.cjs +84 -0
  48. package/dist/components/bubble.cjs.map +1 -0
  49. package/dist/components/bubble.d.cts +41 -0
  50. package/dist/components/bubble.d.ts +41 -0
  51. package/dist/components/bubble.js +78 -0
  52. package/dist/components/bubble.js.map +1 -0
  53. package/dist/components/button.cjs +54 -0
  54. package/dist/components/button.cjs.map +1 -0
  55. package/dist/components/button.d.cts +34 -0
  56. package/dist/components/button.d.ts +34 -0
  57. package/dist/components/button.js +50 -0
  58. package/dist/components/button.js.map +1 -0
  59. package/dist/components/calendar.cjs +58 -0
  60. package/dist/components/calendar.cjs.map +1 -0
  61. package/dist/components/calendar.d.cts +17 -0
  62. package/dist/components/calendar.d.ts +17 -0
  63. package/dist/components/calendar.js +55 -0
  64. package/dist/components/calendar.js.map +1 -0
  65. package/dist/components/callout.cjs +95 -0
  66. package/dist/components/callout.cjs.map +1 -0
  67. package/dist/components/callout.d.cts +39 -0
  68. package/dist/components/callout.d.ts +39 -0
  69. package/dist/components/callout.js +88 -0
  70. package/dist/components/callout.js.map +1 -0
  71. package/dist/components/card.cjs +86 -0
  72. package/dist/components/card.cjs.map +1 -0
  73. package/dist/components/card.d.cts +28 -0
  74. package/dist/components/card.d.ts +28 -0
  75. package/dist/components/card.js +76 -0
  76. package/dist/components/card.js.map +1 -0
  77. package/dist/components/chart.cjs +93 -0
  78. package/dist/components/chart.cjs.map +1 -0
  79. package/dist/components/chart.d.cts +83 -0
  80. package/dist/components/chart.d.ts +83 -0
  81. package/dist/components/chart.js +88 -0
  82. package/dist/components/chart.js.map +1 -0
  83. package/dist/components/checkbox.cjs +37 -0
  84. package/dist/components/checkbox.cjs.map +1 -0
  85. package/dist/components/checkbox.d.cts +22 -0
  86. package/dist/components/checkbox.d.ts +22 -0
  87. package/dist/components/checkbox.js +34 -0
  88. package/dist/components/checkbox.js.map +1 -0
  89. package/dist/components/circular-gauge.cjs +74 -0
  90. package/dist/components/circular-gauge.cjs.map +1 -0
  91. package/dist/components/circular-gauge.d.cts +38 -0
  92. package/dist/components/circular-gauge.d.ts +38 -0
  93. package/dist/components/circular-gauge.js +71 -0
  94. package/dist/components/circular-gauge.js.map +1 -0
  95. package/dist/components/day-of-week-picker.cjs +123 -0
  96. package/dist/components/day-of-week-picker.cjs.map +1 -0
  97. package/dist/components/day-of-week-picker.d.cts +39 -0
  98. package/dist/components/day-of-week-picker.d.ts +39 -0
  99. package/dist/components/day-of-week-picker.js +119 -0
  100. package/dist/components/day-of-week-picker.js.map +1 -0
  101. package/dist/components/device-card.cjs +118 -0
  102. package/dist/components/device-card.cjs.map +1 -0
  103. package/dist/components/device-card.d.cts +71 -0
  104. package/dist/components/device-card.d.ts +71 -0
  105. package/dist/components/device-card.js +104 -0
  106. package/dist/components/device-card.js.map +1 -0
  107. package/dist/components/dialog.cjs +115 -0
  108. package/dist/components/dialog.cjs.map +1 -0
  109. package/dist/components/dialog.d.cts +45 -0
  110. package/dist/components/dialog.d.ts +45 -0
  111. package/dist/components/dialog.js +103 -0
  112. package/dist/components/dialog.js.map +1 -0
  113. package/dist/components/donut-chart.cjs +71 -0
  114. package/dist/components/donut-chart.cjs.map +1 -0
  115. package/dist/components/donut-chart.d.cts +22 -0
  116. package/dist/components/donut-chart.d.ts +22 -0
  117. package/dist/components/donut-chart.js +69 -0
  118. package/dist/components/donut-chart.js.map +1 -0
  119. package/dist/components/drawer.cjs +95 -0
  120. package/dist/components/drawer.cjs.map +1 -0
  121. package/dist/components/drawer.d.cts +46 -0
  122. package/dist/components/drawer.d.ts +46 -0
  123. package/dist/components/drawer.js +83 -0
  124. package/dist/components/drawer.js.map +1 -0
  125. package/dist/components/dropdown-menu.cjs +165 -0
  126. package/dist/components/dropdown-menu.cjs.map +1 -0
  127. package/dist/components/dropdown-menu.d.cts +93 -0
  128. package/dist/components/dropdown-menu.d.ts +93 -0
  129. package/dist/components/dropdown-menu.js +148 -0
  130. package/dist/components/dropdown-menu.js.map +1 -0
  131. package/dist/components/empty-state.cjs +35 -0
  132. package/dist/components/empty-state.cjs.map +1 -0
  133. package/dist/components/empty-state.d.cts +22 -0
  134. package/dist/components/empty-state.d.ts +22 -0
  135. package/dist/components/empty-state.js +33 -0
  136. package/dist/components/empty-state.js.map +1 -0
  137. package/dist/components/energy-bar-chart.cjs +23 -0
  138. package/dist/components/energy-bar-chart.cjs.map +1 -0
  139. package/dist/components/energy-bar-chart.d.cts +43 -0
  140. package/dist/components/energy-bar-chart.d.ts +43 -0
  141. package/dist/components/energy-bar-chart.js +21 -0
  142. package/dist/components/energy-bar-chart.js.map +1 -0
  143. package/dist/components/energy-breakdown.cjs +81 -0
  144. package/dist/components/energy-breakdown.cjs.map +1 -0
  145. package/dist/components/energy-breakdown.d.cts +26 -0
  146. package/dist/components/energy-breakdown.d.ts +26 -0
  147. package/dist/components/energy-breakdown.js +79 -0
  148. package/dist/components/energy-breakdown.js.map +1 -0
  149. package/dist/components/energy-history-chart.cjs +56 -0
  150. package/dist/components/energy-history-chart.cjs.map +1 -0
  151. package/dist/components/energy-history-chart.d.cts +58 -0
  152. package/dist/components/energy-history-chart.d.ts +58 -0
  153. package/dist/components/energy-history-chart.js +54 -0
  154. package/dist/components/energy-history-chart.js.map +1 -0
  155. package/dist/components/feed-in-hero.cjs +56 -0
  156. package/dist/components/feed-in-hero.cjs.map +1 -0
  157. package/dist/components/feed-in-hero.d.cts +33 -0
  158. package/dist/components/feed-in-hero.d.ts +33 -0
  159. package/dist/components/feed-in-hero.js +51 -0
  160. package/dist/components/feed-in-hero.js.map +1 -0
  161. package/dist/components/field.cjs +257 -0
  162. package/dist/components/field.cjs.map +1 -0
  163. package/dist/components/field.d.cts +104 -0
  164. package/dist/components/field.d.ts +104 -0
  165. package/dist/components/field.js +243 -0
  166. package/dist/components/field.js.map +1 -0
  167. package/dist/components/icon.cjs +35 -0
  168. package/dist/components/icon.cjs.map +1 -0
  169. package/dist/components/icon.d.cts +27 -0
  170. package/dist/components/icon.d.ts +27 -0
  171. package/dist/components/icon.js +32 -0
  172. package/dist/components/icon.js.map +1 -0
  173. package/dist/components/info-block.cjs +75 -0
  174. package/dist/components/info-block.cjs.map +1 -0
  175. package/dist/components/info-block.d.cts +20 -0
  176. package/dist/components/info-block.d.ts +20 -0
  177. package/dist/components/info-block.js +65 -0
  178. package/dist/components/info-block.js.map +1 -0
  179. package/dist/components/input-group.cjs +164 -0
  180. package/dist/components/input-group.cjs.map +1 -0
  181. package/dist/components/input-group.d.cts +32 -0
  182. package/dist/components/input-group.d.ts +32 -0
  183. package/dist/components/input-group.js +158 -0
  184. package/dist/components/input-group.js.map +1 -0
  185. package/dist/components/input-otp.cjs +113 -0
  186. package/dist/components/input-otp.cjs.map +1 -0
  187. package/dist/components/input-otp.d.cts +22 -0
  188. package/dist/components/input-otp.d.ts +22 -0
  189. package/dist/components/input-otp.js +111 -0
  190. package/dist/components/input-otp.js.map +1 -0
  191. package/dist/components/input.cjs +112 -0
  192. package/dist/components/input.cjs.map +1 -0
  193. package/dist/components/input.d.cts +21 -0
  194. package/dist/components/input.d.ts +21 -0
  195. package/dist/components/input.js +109 -0
  196. package/dist/components/input.js.map +1 -0
  197. package/dist/components/label.cjs +18 -0
  198. package/dist/components/label.cjs.map +1 -0
  199. package/dist/components/label.d.cts +10 -0
  200. package/dist/components/label.d.ts +10 -0
  201. package/dist/components/label.js +15 -0
  202. package/dist/components/label.js.map +1 -0
  203. package/dist/components/layout.cjs +15 -0
  204. package/dist/components/layout.cjs.map +1 -0
  205. package/dist/components/layout.d.cts +12 -0
  206. package/dist/components/layout.d.ts +13 -0
  207. package/dist/components/layout.js +14 -0
  208. package/dist/components/layout.js.map +1 -0
  209. package/dist/components/line-chart.cjs +310 -0
  210. package/dist/components/line-chart.cjs.map +1 -0
  211. package/dist/components/line-chart.d.cts +71 -0
  212. package/dist/components/line-chart.d.ts +71 -0
  213. package/dist/components/line-chart.js +307 -0
  214. package/dist/components/line-chart.js.map +1 -0
  215. package/dist/components/list.cjs +132 -0
  216. package/dist/components/list.cjs.map +1 -0
  217. package/dist/components/list.d.cts +72 -0
  218. package/dist/components/list.d.ts +72 -0
  219. package/dist/components/list.js +122 -0
  220. package/dist/components/list.js.map +1 -0
  221. package/dist/components/marker.cjs +52 -0
  222. package/dist/components/marker.cjs.map +1 -0
  223. package/dist/components/marker.d.cts +29 -0
  224. package/dist/components/marker.d.ts +29 -0
  225. package/dist/components/marker.js +46 -0
  226. package/dist/components/marker.js.map +1 -0
  227. package/dist/components/message-scroller.cjs +73 -0
  228. package/dist/components/message-scroller.cjs.map +1 -0
  229. package/dist/components/message-scroller.d.cts +39 -0
  230. package/dist/components/message-scroller.d.ts +39 -0
  231. package/dist/components/message-scroller.js +62 -0
  232. package/dist/components/message-scroller.js.map +1 -0
  233. package/dist/components/message.cjs +60 -0
  234. package/dist/components/message.cjs.map +1 -0
  235. package/dist/components/message.d.cts +36 -0
  236. package/dist/components/message.d.ts +36 -0
  237. package/dist/components/message.js +52 -0
  238. package/dist/components/message.js.map +1 -0
  239. package/dist/components/metering-row.cjs +43 -0
  240. package/dist/components/metering-row.cjs.map +1 -0
  241. package/dist/components/metering-row.d.cts +32 -0
  242. package/dist/components/metering-row.d.ts +32 -0
  243. package/dist/components/metering-row.js +38 -0
  244. package/dist/components/metering-row.js.map +1 -0
  245. package/dist/components/money-saved-block.cjs +87 -0
  246. package/dist/components/money-saved-block.cjs.map +1 -0
  247. package/dist/components/money-saved-block.d.cts +57 -0
  248. package/dist/components/money-saved-block.d.ts +57 -0
  249. package/dist/components/money-saved-block.js +79 -0
  250. package/dist/components/money-saved-block.js.map +1 -0
  251. package/dist/components/number-flow.cjs +44 -0
  252. package/dist/components/number-flow.cjs.map +1 -0
  253. package/dist/components/number-flow.d.cts +4 -0
  254. package/dist/components/number-flow.d.ts +4 -0
  255. package/dist/components/number-flow.js +42 -0
  256. package/dist/components/number-flow.js.map +1 -0
  257. package/dist/components/on-off-button.cjs +36 -0
  258. package/dist/components/on-off-button.cjs.map +1 -0
  259. package/dist/components/on-off-button.d.cts +20 -0
  260. package/dist/components/on-off-button.d.ts +20 -0
  261. package/dist/components/on-off-button.js +34 -0
  262. package/dist/components/on-off-button.js.map +1 -0
  263. package/dist/components/onboarding-layout.cjs +68 -0
  264. package/dist/components/onboarding-layout.cjs.map +1 -0
  265. package/dist/components/onboarding-layout.d.cts +46 -0
  266. package/dist/components/onboarding-layout.d.ts +46 -0
  267. package/dist/components/onboarding-layout.js +60 -0
  268. package/dist/components/onboarding-layout.js.map +1 -0
  269. package/dist/components/page-header.cjs +50 -0
  270. package/dist/components/page-header.cjs.map +1 -0
  271. package/dist/components/page-header.d.cts +26 -0
  272. package/dist/components/page-header.d.ts +26 -0
  273. package/dist/components/page-header.js +44 -0
  274. package/dist/components/page-header.js.map +1 -0
  275. package/dist/components/page-spinner.cjs +19 -0
  276. package/dist/components/page-spinner.cjs.map +1 -0
  277. package/dist/components/page-spinner.d.cts +14 -0
  278. package/dist/components/page-spinner.d.ts +14 -0
  279. package/dist/components/page-spinner.js +17 -0
  280. package/dist/components/page-spinner.js.map +1 -0
  281. package/dist/components/period-tabs.cjs +79 -0
  282. package/dist/components/period-tabs.cjs.map +1 -0
  283. package/dist/components/period-tabs.d.cts +51 -0
  284. package/dist/components/period-tabs.d.ts +51 -0
  285. package/dist/components/period-tabs.js +73 -0
  286. package/dist/components/period-tabs.js.map +1 -0
  287. package/dist/components/popover.cjs +62 -0
  288. package/dist/components/popover.cjs.map +1 -0
  289. package/dist/components/popover.d.cts +29 -0
  290. package/dist/components/popover.d.ts +29 -0
  291. package/dist/components/popover.js +56 -0
  292. package/dist/components/popover.js.map +1 -0
  293. package/dist/components/power-history-chart.cjs +358 -0
  294. package/dist/components/power-history-chart.cjs.map +1 -0
  295. package/dist/components/power-history-chart.d.cts +54 -0
  296. package/dist/components/power-history-chart.d.ts +54 -0
  297. package/dist/components/power-history-chart.js +355 -0
  298. package/dist/components/power-history-chart.js.map +1 -0
  299. package/dist/components/power-history.cjs +115 -0
  300. package/dist/components/power-history.cjs.map +1 -0
  301. package/dist/components/power-history.d.cts +42 -0
  302. package/dist/components/power-history.d.ts +43 -0
  303. package/dist/components/power-history.js +114 -0
  304. package/dist/components/power-history.js.map +1 -0
  305. package/dist/components/power-network.cjs +530 -0
  306. package/dist/components/power-network.cjs.map +1 -0
  307. package/dist/components/power-network.d.cts +77 -0
  308. package/dist/components/power-network.d.ts +77 -0
  309. package/dist/components/power-network.js +523 -0
  310. package/dist/components/power-network.js.map +1 -0
  311. package/dist/components/progress.cjs +34 -0
  312. package/dist/components/progress.cjs.map +1 -0
  313. package/dist/components/progress.d.cts +17 -0
  314. package/dist/components/progress.d.ts +17 -0
  315. package/dist/components/progress.js +31 -0
  316. package/dist/components/progress.js.map +1 -0
  317. package/dist/components/radio-card-group.cjs +69 -0
  318. package/dist/components/radio-card-group.cjs.map +1 -0
  319. package/dist/components/radio-card-group.d.cts +21 -0
  320. package/dist/components/radio-card-group.d.ts +21 -0
  321. package/dist/components/radio-card-group.js +65 -0
  322. package/dist/components/radio-card-group.js.map +1 -0
  323. package/dist/components/radio.cjs +34 -0
  324. package/dist/components/radio.cjs.map +1 -0
  325. package/dist/components/radio.d.cts +21 -0
  326. package/dist/components/radio.d.ts +21 -0
  327. package/dist/components/radio.js +30 -0
  328. package/dist/components/radio.js.map +1 -0
  329. package/dist/components/reparent.cjs +55 -0
  330. package/dist/components/reparent.cjs.map +1 -0
  331. package/dist/components/reparent.d.cts +29 -0
  332. package/dist/components/reparent.d.ts +29 -0
  333. package/dist/components/reparent.js +49 -0
  334. package/dist/components/reparent.js.map +1 -0
  335. package/dist/components/sankey-chart.cjs +221 -0
  336. package/dist/components/sankey-chart.cjs.map +1 -0
  337. package/dist/components/sankey-chart.d.cts +58 -0
  338. package/dist/components/sankey-chart.d.ts +58 -0
  339. package/dist/components/sankey-chart.js +218 -0
  340. package/dist/components/sankey-chart.js.map +1 -0
  341. package/dist/components/schedule-editor.cjs +82 -0
  342. package/dist/components/schedule-editor.cjs.map +1 -0
  343. package/dist/components/schedule-editor.d.cts +25 -0
  344. package/dist/components/schedule-editor.d.ts +25 -0
  345. package/dist/components/schedule-editor.js +72 -0
  346. package/dist/components/schedule-editor.js.map +1 -0
  347. package/dist/components/schedule-list.cjs +110 -0
  348. package/dist/components/schedule-list.cjs.map +1 -0
  349. package/dist/components/schedule-list.d.cts +29 -0
  350. package/dist/components/schedule-list.d.ts +29 -0
  351. package/dist/components/schedule-list.js +99 -0
  352. package/dist/components/schedule-list.js.map +1 -0
  353. package/dist/components/scroll-area.cjs +53 -0
  354. package/dist/components/scroll-area.cjs.map +1 -0
  355. package/dist/components/scroll-area.d.cts +26 -0
  356. package/dist/components/scroll-area.d.ts +26 -0
  357. package/dist/components/scroll-area.js +44 -0
  358. package/dist/components/scroll-area.js.map +1 -0
  359. package/dist/components/select.cjs +136 -0
  360. package/dist/components/select.cjs.map +1 -0
  361. package/dist/components/select.d.cts +63 -0
  362. package/dist/components/select.d.ts +63 -0
  363. package/dist/components/select.js +124 -0
  364. package/dist/components/select.js.map +1 -0
  365. package/dist/components/separator.cjs +38 -0
  366. package/dist/components/separator.cjs.map +1 -0
  367. package/dist/components/separator.d.cts +13 -0
  368. package/dist/components/separator.d.ts +13 -0
  369. package/dist/components/separator.js +35 -0
  370. package/dist/components/separator.js.map +1 -0
  371. package/dist/components/series-legend.cjs +39 -0
  372. package/dist/components/series-legend.cjs.map +1 -0
  373. package/dist/components/series-legend.d.cts +31 -0
  374. package/dist/components/series-legend.d.ts +31 -0
  375. package/dist/components/series-legend.js +37 -0
  376. package/dist/components/series-legend.js.map +1 -0
  377. package/dist/components/sheet.cjs +102 -0
  378. package/dist/components/sheet.cjs.map +1 -0
  379. package/dist/components/sheet.d.cts +46 -0
  380. package/dist/components/sheet.d.ts +46 -0
  381. package/dist/components/sheet.js +90 -0
  382. package/dist/components/sheet.js.map +1 -0
  383. package/dist/components/skeleton.cjs +24 -0
  384. package/dist/components/skeleton.cjs.map +1 -0
  385. package/dist/components/skeleton.d.cts +24 -0
  386. package/dist/components/skeleton.d.ts +24 -0
  387. package/dist/components/skeleton.js +21 -0
  388. package/dist/components/skeleton.js.map +1 -0
  389. package/dist/components/slider.cjs +276 -0
  390. package/dist/components/slider.cjs.map +1 -0
  391. package/dist/components/slider.d.cts +150 -0
  392. package/dist/components/slider.d.ts +150 -0
  393. package/dist/components/slider.js +266 -0
  394. package/dist/components/slider.js.map +1 -0
  395. package/dist/components/smart-toggle-button.cjs +28 -0
  396. package/dist/components/smart-toggle-button.cjs.map +1 -0
  397. package/dist/components/smart-toggle-button.d.cts +18 -0
  398. package/dist/components/smart-toggle-button.d.ts +18 -0
  399. package/dist/components/smart-toggle-button.js +26 -0
  400. package/dist/components/smart-toggle-button.js.map +1 -0
  401. package/dist/components/solar-forecast-chart.cjs +105 -0
  402. package/dist/components/solar-forecast-chart.cjs.map +1 -0
  403. package/dist/components/solar-forecast-chart.d.cts +66 -0
  404. package/dist/components/solar-forecast-chart.d.ts +66 -0
  405. package/dist/components/solar-forecast-chart.js +99 -0
  406. package/dist/components/solar-forecast-chart.js.map +1 -0
  407. package/dist/components/sortable-list.cjs +69 -0
  408. package/dist/components/sortable-list.cjs.map +1 -0
  409. package/dist/components/sortable-list.d.cts +46 -0
  410. package/dist/components/sortable-list.d.ts +46 -0
  411. package/dist/components/sortable-list.js +67 -0
  412. package/dist/components/sortable-list.js.map +1 -0
  413. package/dist/components/spinner.cjs +42 -0
  414. package/dist/components/spinner.cjs.map +1 -0
  415. package/dist/components/spinner.d.cts +15 -0
  416. package/dist/components/spinner.d.ts +15 -0
  417. package/dist/components/spinner.js +39 -0
  418. package/dist/components/spinner.js.map +1 -0
  419. package/dist/components/stat-card.cjs +58 -0
  420. package/dist/components/stat-card.cjs.map +1 -0
  421. package/dist/components/stat-card.d.cts +36 -0
  422. package/dist/components/stat-card.d.ts +36 -0
  423. package/dist/components/stat-card.js +50 -0
  424. package/dist/components/stat-card.js.map +1 -0
  425. package/dist/components/stepper.cjs +79 -0
  426. package/dist/components/stepper.cjs.map +1 -0
  427. package/dist/components/stepper.d.cts +33 -0
  428. package/dist/components/stepper.d.ts +33 -0
  429. package/dist/components/stepper.js +76 -0
  430. package/dist/components/stepper.js.map +1 -0
  431. package/dist/components/switch.cjs +22 -0
  432. package/dist/components/switch.cjs.map +1 -0
  433. package/dist/components/switch.d.cts +28 -0
  434. package/dist/components/switch.d.ts +28 -0
  435. package/dist/components/switch.js +20 -0
  436. package/dist/components/switch.js.map +1 -0
  437. package/dist/components/tabs.cjs +175 -0
  438. package/dist/components/tabs.cjs.map +1 -0
  439. package/dist/components/tabs.d.cts +45 -0
  440. package/dist/components/tabs.d.ts +45 -0
  441. package/dist/components/tabs.js +167 -0
  442. package/dist/components/tabs.js.map +1 -0
  443. package/dist/components/theme.cjs +6 -0
  444. package/dist/components/theme.d.cts +38 -0
  445. package/dist/components/theme.d.ts +38 -0
  446. package/dist/components/theme.js +4 -0
  447. package/dist/components/thumbnail.cjs +54 -0
  448. package/dist/components/thumbnail.cjs.map +1 -0
  449. package/dist/components/thumbnail.d.cts +34 -0
  450. package/dist/components/thumbnail.d.ts +34 -0
  451. package/dist/components/thumbnail.js +51 -0
  452. package/dist/components/thumbnail.js.map +1 -0
  453. package/dist/components/time-picker.cjs +55 -0
  454. package/dist/components/time-picker.cjs.map +1 -0
  455. package/dist/components/time-picker.d.cts +41 -0
  456. package/dist/components/time-picker.d.ts +41 -0
  457. package/dist/components/time-picker.js +51 -0
  458. package/dist/components/time-picker.js.map +1 -0
  459. package/dist/components/toast.cjs +99 -0
  460. package/dist/components/toast.cjs.map +1 -0
  461. package/dist/components/toast.d.cts +18 -0
  462. package/dist/components/toast.d.ts +18 -0
  463. package/dist/components/toast.js +95 -0
  464. package/dist/components/toast.js.map +1 -0
  465. package/dist/components/tooltip.cjs +75 -0
  466. package/dist/components/tooltip.cjs.map +1 -0
  467. package/dist/components/tooltip.d.cts +47 -0
  468. package/dist/components/tooltip.d.ts +47 -0
  469. package/dist/components/tooltip.js +67 -0
  470. package/dist/components/tooltip.js.map +1 -0
  471. package/dist/components/typography.cjs +52 -0
  472. package/dist/components/typography.cjs.map +1 -0
  473. package/dist/components/typography.d.cts +32 -0
  474. package/dist/components/typography.d.ts +32 -0
  475. package/dist/components/typography.js +45 -0
  476. package/dist/components/typography.js.map +1 -0
  477. package/dist/hooks/use-container-width.cjs +22 -0
  478. package/dist/hooks/use-container-width.cjs.map +1 -0
  479. package/dist/hooks/use-container-width.d.cts +7 -0
  480. package/dist/hooks/use-container-width.d.ts +7 -0
  481. package/dist/hooks/use-container-width.js +20 -0
  482. package/dist/hooks/use-container-width.js.map +1 -0
  483. package/dist/icons/index.cjs +7 -0
  484. package/dist/icons/index.d.cts +4 -0
  485. package/dist/icons/index.d.ts +4 -0
  486. package/dist/icons/index.js +3 -0
  487. package/dist/icons/material-symbol.cjs +105 -0
  488. package/dist/icons/material-symbol.cjs.map +1 -0
  489. package/dist/icons/material-symbol.d.cts +23 -0
  490. package/dist/icons/material-symbol.d.ts +23 -0
  491. package/dist/icons/material-symbol.js +100 -0
  492. package/dist/icons/material-symbol.js.map +1 -0
  493. package/dist/input-box-variants-BMDdwvqg.cjs +40 -0
  494. package/dist/input-box-variants-BMDdwvqg.cjs.map +1 -0
  495. package/dist/input-box-variants-Dr1K7uYE.js +28 -0
  496. package/dist/input-box-variants-Dr1K7uYE.js.map +1 -0
  497. package/dist/number-flow-DMJouddg.d.cts +15 -0
  498. package/dist/number-flow-DSbucQ_K.d.ts +15 -0
  499. package/dist/styles/index.css +223 -0
  500. package/dist/styles/internal.css +5 -0
  501. package/dist/styles/material-symbol.css +22 -0
  502. package/dist/styles/spark-default.css +883 -0
  503. package/dist/styles/theme.css +542 -0
  504. package/dist/styles/utilities.css +557 -0
  505. package/dist/theme-B3WtiByA.js +574 -0
  506. package/dist/theme-B3WtiByA.js.map +1 -0
  507. package/dist/theme-C9_OSe0S.cjs +592 -0
  508. package/dist/theme-C9_OSe0S.cjs.map +1 -0
  509. package/dist/theme-types-DoROIXpi.d.ts +30 -0
  510. package/dist/theme-types-r20EJfEC.d.cts +30 -0
  511. package/dist/tones-DjgKOX3s.d.cts +8 -0
  512. package/dist/tones-DyCkL71h.d.ts +8 -0
  513. package/dist/utils/build-sankey-nodes.cjs +59 -0
  514. package/dist/utils/build-sankey-nodes.cjs.map +1 -0
  515. package/dist/utils/build-sankey-nodes.d.cts +27 -0
  516. package/dist/utils/build-sankey-nodes.d.ts +27 -0
  517. package/dist/utils/build-sankey-nodes.js +58 -0
  518. package/dist/utils/build-sankey-nodes.js.map +1 -0
  519. package/dist/utils/chars.cjs +18 -0
  520. package/dist/utils/chars.cjs.map +1 -0
  521. package/dist/utils/chars.d.cts +10 -0
  522. package/dist/utils/chars.d.ts +10 -0
  523. package/dist/utils/chars.js +14 -0
  524. package/dist/utils/chars.js.map +1 -0
  525. package/dist/utils/cn.cjs +10 -0
  526. package/dist/utils/cn.d.cts +4 -0
  527. package/dist/utils/cn.d.ts +4 -0
  528. package/dist/utils/cn.js +3 -0
  529. package/dist/utils/date-mask.cjs +45 -0
  530. package/dist/utils/date-mask.cjs.map +1 -0
  531. package/dist/utils/date-mask.d.cts +17 -0
  532. package/dist/utils/date-mask.d.ts +17 -0
  533. package/dist/utils/date-mask.js +41 -0
  534. package/dist/utils/date-mask.js.map +1 -0
  535. package/dist/utils/format.cjs +57 -0
  536. package/dist/utils/format.cjs.map +1 -0
  537. package/dist/utils/format.d.cts +23 -0
  538. package/dist/utils/format.d.ts +23 -0
  539. package/dist/utils/format.js +47 -0
  540. package/dist/utils/format.js.map +1 -0
  541. package/package.json +78 -63
  542. package/dist/index.cjs +0 -1631
  543. package/dist/index.cjs.map +0 -1
  544. package/dist/index.css +0 -1
  545. package/dist/index.d.cts +0 -299
  546. package/dist/index.d.ts +0 -299
  547. package/dist/index.js +0 -1518
  548. package/dist/index.js.map +0 -1
  549. package/dist/styles.js +0 -1
@@ -0,0 +1,175 @@
1
+ "use client";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_chunk = require("../chunk-aJGBMT86.cjs");
4
+ const require_icons_material_symbol = require("../icons/material-symbol.cjs");
5
+ let react = require("react");
6
+ react = require_chunk.__toESM(react);
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let _base_ui_react_tabs = require("@base-ui/react/tabs");
9
+ let cnfast = require("cnfast");
10
+ //#region src/components/tabs.tsx
11
+ const useIsomorphicLayoutEffect = typeof window === "undefined" ? react.useEffect : react.useLayoutEffect;
12
+ function setRef(ref, value) {
13
+ if (typeof ref === "function") return ref(value);
14
+ if (ref) ref.current = value;
15
+ }
16
+ function composeRefs(...refs) {
17
+ return (node) => {
18
+ let hasCleanup = false;
19
+ const cleanups = refs.map((ref) => {
20
+ const cleanup = setRef(ref, node);
21
+ if (typeof cleanup === "function") hasCleanup = true;
22
+ return cleanup;
23
+ });
24
+ if (hasCleanup) return () => {
25
+ for (let i = 0; i < refs.length; i++) {
26
+ const cleanup = cleanups[i];
27
+ if (typeof cleanup === "function") cleanup();
28
+ else setRef(refs[i], null);
29
+ }
30
+ };
31
+ };
32
+ }
33
+ function Tabs(props) {
34
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_tabs.Tabs.Root, {
35
+ "data-slot": "tabs",
36
+ ...props
37
+ });
38
+ }
39
+ const REVEAL_PEEK = 40;
40
+ const WORM_MS = 210;
41
+ function TabsList({ className, style, variant = "underline", ref, ...props }) {
42
+ const resolved = variant === "pill" ? "pill" : "underline";
43
+ const wrapperRef = react.useRef(null);
44
+ const scrollerRef = react.useRef(null);
45
+ const scrollerCallbackRef = react.useMemo(() => composeRefs(scrollerRef, ref), [ref]);
46
+ useIsomorphicLayoutEffect(() => {
47
+ const wrapper = wrapperRef.current;
48
+ const scroller = scrollerRef.current;
49
+ if (!wrapper || !scroller) return;
50
+ const syncOverflow = () => {
51
+ const max = scroller.scrollWidth - scroller.clientWidth;
52
+ wrapper.toggleAttribute("data-overflow-start", scroller.scrollLeft > 2);
53
+ wrapper.toggleAttribute("data-overflow-end", scroller.scrollLeft < max - 2);
54
+ };
55
+ const reveal = (el) => {
56
+ if (typeof scroller.scrollTo !== "function") return;
57
+ const start = el.offsetLeft - REVEAL_PEEK;
58
+ const end = el.offsetLeft + el.offsetWidth + REVEAL_PEEK;
59
+ if (start < scroller.scrollLeft) scroller.scrollTo({ left: Math.max(0, start) });
60
+ else if (end > scroller.scrollLeft + scroller.clientWidth) scroller.scrollTo({ left: end - scroller.clientWidth });
61
+ };
62
+ const motionQuery = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
63
+ const setBar = (x, w) => {
64
+ scroller.style.setProperty("--tabs-indicator-x", `${x}px`);
65
+ scroller.style.setProperty("--tabs-indicator-w", `${w}px`);
66
+ };
67
+ let lastActive = null;
68
+ let mounted = false;
69
+ let wormTimer;
70
+ const measure = () => {
71
+ const active = scroller.querySelector("[data-slot=\"tabs-trigger\"][data-active]");
72
+ const changed = active !== lastActive;
73
+ if (resolved === "underline") if (!active) {
74
+ clearTimeout(wormTimer);
75
+ lastActive = null;
76
+ scroller.style.setProperty("--tabs-indicator-w", "0px");
77
+ } else if (changed && lastActive?.isConnected && mounted && !motionQuery?.matches) {
78
+ const from = Math.min(lastActive.offsetLeft, active.offsetLeft);
79
+ setBar(from, Math.max(lastActive.offsetLeft + lastActive.offsetWidth, active.offsetLeft + active.offsetWidth) - from);
80
+ clearTimeout(wormTimer);
81
+ const el = active;
82
+ wormTimer = setTimeout(() => setBar(el.offsetLeft, el.offsetWidth), WORM_MS);
83
+ } else {
84
+ clearTimeout(wormTimer);
85
+ setBar(active.offsetLeft, active.offsetWidth);
86
+ }
87
+ syncOverflow();
88
+ if (active && changed) {
89
+ reveal(active);
90
+ lastActive = active;
91
+ }
92
+ mounted = true;
93
+ };
94
+ measure();
95
+ scroller.addEventListener("scroll", syncOverflow, { passive: true });
96
+ const mo = new MutationObserver(measure);
97
+ mo.observe(scroller, {
98
+ subtree: true,
99
+ childList: true,
100
+ characterData: true,
101
+ attributeFilter: ["data-active"]
102
+ });
103
+ const ro = new ResizeObserver(measure);
104
+ ro.observe(scroller);
105
+ return () => {
106
+ scroller.removeEventListener("scroll", syncOverflow);
107
+ clearTimeout(wormTimer);
108
+ mo.disconnect();
109
+ ro.disconnect();
110
+ };
111
+ }, [resolved]);
112
+ const scrollByPage = (dir) => () => {
113
+ const scroller = scrollerRef.current;
114
+ if (typeof scroller?.scrollBy !== "function") return;
115
+ scroller.scrollBy({ left: dir * scroller.clientWidth * .6 });
116
+ };
117
+ const chevron = (dir) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
118
+ "aria-hidden": "true",
119
+ "data-slot": dir === 1 ? "tabs-scroll-next" : "tabs-scroll-prev",
120
+ onClick: scrollByPage(dir),
121
+ tabIndex: -1,
122
+ type: "button",
123
+ className: (0, cnfast.cn)("absolute top-1/2 z-1 hidden size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))] bg-[var(--color-gray-1)]/72 text-gray-a11 backdrop-blur-sm hover:text-gray-12", dir === 1 ? "right-0 group-data-[overflow-end]/tabs:flex" : "left-0 group-data-[overflow-start]/tabs:flex"),
124
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_material_symbol.MaterialSymbol, { name: dir === 1 ? "chevron_right" : "chevron_left" })
125
+ });
126
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
127
+ className: (0, cnfast.cn)("group/tabs relative inline-block max-w-full", className),
128
+ "data-slot": "tabs-list",
129
+ "data-variant": resolved,
130
+ ref: wrapperRef,
131
+ style,
132
+ children: [
133
+ chevron(-1),
134
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_tabs.Tabs.List, {
135
+ "data-slot": "tabs-scroller",
136
+ ref: scrollerCallbackRef,
137
+ className: (0, cnfast.cn)("relative no-scrollbar flex w-full items-stretch overflow-x-auto scroll-smooth motion-reduce:scroll-auto", resolved === "underline" && "gap-2", resolved === "underline" && "after:pointer-events-none after:absolute after:bottom-0 after:left-[var(--tabs-indicator-x,0px)] after:h-1 after:w-[var(--tabs-indicator-w,0px)] after:rounded-full after:bg-[var(--spark-tabs-indicator,var(--spark-indicator))] after:transition-[left,width] after:duration-200 after:ease-out after:content-[''] motion-reduce:after:transition-none", resolved === "pill" && "gap-0 rounded-md bg-gray-a3 p-1"),
138
+ ...props
139
+ }),
140
+ chevron(1)
141
+ ]
142
+ });
143
+ }
144
+ function TabsTrigger({ className, children, ...props }) {
145
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_tabs.Tabs.Tab, {
146
+ "data-slot": "tabs-trigger",
147
+ className: (0, cnfast.cn)("group/trigger inline-flex min-w-[var(--tabs-trigger-minw,0px)] shrink-0 cursor-pointer scroll-mx-10 items-center justify-center whitespace-nowrap text-gray-12 transition-colors", "data-active:text-[color:var(--spark-tabs-ink,var(--spark-a11))]", "focus-visible:ring-2 focus-visible:outline-hidden focus-visible:ring-inset", "data-disabled:pointer-events-none data-disabled:text-gray-a8", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-4", "group-data-[variant=underline]/tabs:min-h-12 group-data-[variant=underline]/tabs:px-1 group-data-[variant=underline]/tabs:text-base group-data-[variant=underline]/tabs:font-bold group-data-[variant=underline]/tabs:[--tabs-trigger-minw:5rem]", "group-data-[variant=underline]/tabs:border-b-2 group-data-[variant=underline]/tabs:border-gray-a5", "group-data-[variant=pill]/tabs:h-8 group-data-[variant=pill]/tabs:rounded-sm group-data-[variant=pill]/tabs:px-4 group-data-[variant=pill]/tabs:text-sm group-data-[variant=pill]/tabs:font-medium", "group-data-[variant=pill]/tabs:not-data-active:hover:bg-gray-a3", "group-data-[variant=pill]/tabs:data-active:bg-gray-1 group-data-[variant=pill]/tabs:data-active:shadow-sm dark:group-data-[variant=pill]/tabs:data-active:bg-gray-a4 dark:group-data-[variant=pill]/tabs:data-active:inset-ring dark:group-data-[variant=pill]/tabs:data-active:inset-ring-gray-a6", className),
148
+ ...props,
149
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
150
+ "data-slot": "tabs-trigger-inner",
151
+ className: (0, cnfast.cn)("inline-flex items-center gap-1", "group-data-[variant=underline]/tabs:rounded-md group-data-[variant=underline]/tabs:px-2 group-data-[variant=underline]/tabs:py-1 group-data-[variant=underline]/tabs:transition-colors", "group-data-[variant=underline]/tabs:group-hover/trigger:bg-gray-a3"),
152
+ children
153
+ })
154
+ });
155
+ }
156
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
157
+ const TabsTriggerUnderline = TabsTrigger;
158
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
159
+ const TabsTriggerPill = TabsTrigger;
160
+ function TabsContent({ className, ...props }) {
161
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_tabs.Tabs.Panel, {
162
+ "data-slot": "tabs-content",
163
+ className: (0, cnfast.cn)("focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:outline-hidden", className),
164
+ ...props
165
+ });
166
+ }
167
+ //#endregion
168
+ exports.Tabs = Tabs;
169
+ exports.TabsContent = TabsContent;
170
+ exports.TabsList = TabsList;
171
+ exports.TabsTrigger = TabsTrigger;
172
+ exports.TabsTriggerPill = TabsTriggerPill;
173
+ exports.TabsTriggerUnderline = TabsTriggerUnderline;
174
+
175
+ //# sourceMappingURL=tabs.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.cjs","names":["React","TabsPrimitive","MaterialSymbol"],"sources":["../../src/components/tabs.tsx"],"sourcesContent":["import { Tabs as TabsPrimitive } from '@base-ui/react/tabs'\nimport * as React from 'react'\nimport { MaterialSymbol } from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\n\n// useLayoutEffect warns during SSR; the isomorphic swap is the standard Radix idiom.\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect\n\n// Merge our internal scroller ref with a consumer-forwarded ref. Written locally\n// and React 19-correct: it propagates cleanup-returning callback refs and nulls\n// plain refs on unmount.\ntype PossibleRef<T> = React.Ref<T> | undefined\n\nfunction setRef<T>(ref: PossibleRef<T>, value: T | null) {\n if (typeof ref === 'function') return ref(value)\n if (ref) ref.current = value\n return undefined\n}\n\nfunction composeRefs<T>(...refs: PossibleRef<T>[]) {\n return (node: T) => {\n let hasCleanup = false\n const cleanups = refs.map((ref) => {\n const cleanup = setRef(ref, node)\n if (typeof cleanup === 'function') hasCleanup = true\n return cleanup\n })\n if (hasCleanup) {\n return () => {\n for (let i = 0; i < refs.length; i++) {\n const cleanup = cleanups[i]\n if (typeof cleanup === 'function') cleanup()\n else setRef(refs[i], null)\n }\n }\n }\n return undefined\n }\n}\n\ntype TabsProps = React.ComponentProps<typeof TabsPrimitive.Root>\n\nfunction Tabs(props: TabsProps) {\n return <TabsPrimitive.Root data-slot=\"tabs\" {...props} />\n}\n\ntype TabsListVariant = 'underline'\n\n/**\n * @deprecated Not part of Spark's tab design — use `'underline'`. `'pill'` (a\n * segmented control) and the old text-only `'default'` still render for\n * back-compat but are undocumented and may be removed.\n */\ntype TabsListVariantLegacy = 'default' | 'pill'\n\ntype TabsListProps = Omit<\n React.ComponentProps<typeof TabsPrimitive.List>,\n 'style'\n> & {\n /** `underline` — the Spark tab: bold label + a sliding accent bar. */\n variant?: TabsListVariant | TabsListVariantLegacy\n // style lands on the plain wrapper div, so no Base UI state-callback form\n style?: React.CSSProperties\n}\n\n// how much of a neighboring tab a scroll-into-view reveals (matches scroll-mx-10)\nconst REVEAL_PEEK = 40\n// worm indicator: the accent bar stretches across old+new, then contracts to the\n// new tab. WORM_MS must be >= the bar's CSS transition (200ms) so the stretch fully\n// settles before the contract begins — then contract sets left+width from rest in\n// one synced transition, pinning the leading edge so the motion never jiggles (a\n// contract that starts mid-stretch desyncs the two edges → wobble on big jumps).\nconst WORM_MS = 210\n\nfunction TabsList({\n className,\n style,\n variant = 'underline',\n ref,\n ...props\n}: TabsListProps) {\n // 'underline' is the only real variant. Deprecated 'pill' still renders (a\n // segmented control, kept for back-compat); anything else (incl. the old\n // text-only 'default') folds into underline.\n const resolved = variant === 'pill' ? 'pill' : 'underline'\n const wrapperRef = React.useRef<HTMLDivElement | null>(null)\n const scrollerRef = React.useRef<HTMLDivElement | null>(null)\n // stable identity (keyed on the forwarded ref) so React doesn't detach/re-attach\n // the scroller ref on every render — TabsList re-renders on each selection.\n const scrollerCallbackRef = React.useMemo(\n () => composeRefs<HTMLDivElement>(scrollerRef, ref),\n [ref],\n )\n\n // Sliding underline + overflow state + travel-into-view. The bar lives on the\n // SCROLLER (::after scrolls with the content) and follows the active trigger via\n // two measured vars; useLayoutEffect measures before paint (no flash); the\n // MutationObserver tracks selection + children + text changes; the ResizeObserver\n // re-measures on container/scroller reflow. Together they cover everything that\n // moves a tab: selection, add/remove, a counter Badge growing, and resize.\n useIsomorphicLayoutEffect(() => {\n const wrapper = wrapperRef.current\n const scroller = scrollerRef.current\n if (!wrapper || !scroller) return\n // the edge chevrons show per side while more content hides in that direction\n const syncOverflow = () => {\n // 2px epsilon absorbs sub-pixel rounding at fractional browser zoom\n // (scrollWidth/clientWidth round to int, scrollLeft is fractional). Assumes\n // LTR (scrollLeft >= 0) — Spark's tab strips are LTR.\n const max = scroller.scrollWidth - scroller.clientWidth\n wrapper.toggleAttribute('data-overflow-start', scroller.scrollLeft > 2)\n wrapper.toggleAttribute(\n 'data-overflow-end',\n scroller.scrollLeft < max - 2,\n )\n }\n // scroller-local reveal — deliberately NOT scrollIntoView, which also scrolls\n // ancestors and would yank the page when the list is half off-screen. The peek\n // keeps the neighboring tab partially visible (\"there's more here\").\n const reveal = (el: HTMLElement) => {\n // jsdom (unit tests) doesn't implement Element.scrollTo\n if (typeof scroller.scrollTo !== 'function') return\n const start = el.offsetLeft - REVEAL_PEEK\n const end = el.offsetLeft + el.offsetWidth + REVEAL_PEEK\n if (start < scroller.scrollLeft) {\n scroller.scrollTo({ left: Math.max(0, start) })\n } else if (end > scroller.scrollLeft + scroller.clientWidth) {\n scroller.scrollTo({ left: end - scroller.clientWidth })\n }\n }\n // matchMedia guarded for jsdom (unit tests); read .matches live so toggling the\n // OS reduce-motion setting mid-session takes effect on the next selection.\n const motionQuery =\n typeof window.matchMedia === 'function'\n ? window.matchMedia('(prefers-reduced-motion: reduce)')\n : null\n const setBar = (x: number, w: number) => {\n scroller.style.setProperty('--tabs-indicator-x', `${x}px`)\n scroller.style.setProperty('--tabs-indicator-w', `${w}px`)\n }\n let lastActive: HTMLElement | null = null\n let mounted = false\n let wormTimer: ReturnType<typeof setTimeout> | undefined\n const measure = () => {\n const active = scroller.querySelector<HTMLElement>(\n '[data-slot=\"tabs-trigger\"][data-active]',\n )\n const changed = active !== lastActive\n if (resolved === 'underline') {\n if (!active) {\n // no selection → collapse the bar (width 0), forget the previous tab, and\n // cancel any pending contract, so a later selection never worms from a\n // stale/removed node\n clearTimeout(wormTimer)\n lastActive = null\n scroller.style.setProperty('--tabs-indicator-w', '0px')\n } else if (\n changed &&\n lastActive?.isConnected &&\n mounted &&\n !motionQuery?.matches\n ) {\n // worm: stretch across old + new (one edge holds, the other reaches),\n // then contract to the new tab (the trailing edge catches up). The union\n // makes it direction-agnostic. isConnected guards dynamic tab removal — a\n // detached old node reports offsets of 0 and would sweep the bar from x=0.\n const from = Math.min(lastActive.offsetLeft, active.offsetLeft)\n const to = Math.max(\n lastActive.offsetLeft + lastActive.offsetWidth,\n active.offsetLeft + active.offsetWidth,\n )\n setBar(from, to - from)\n clearTimeout(wormTimer)\n const el = active\n wormTimer = setTimeout(\n () => setBar(el.offsetLeft, el.offsetWidth),\n WORM_MS,\n )\n } else {\n // first paint, reduced motion, detached previous, or a resize (same tab)\n // → settle on the active tab, no worm\n clearTimeout(wormTimer)\n setBar(active.offsetLeft, active.offsetWidth)\n }\n }\n syncOverflow()\n // travel the active tab into view on selection change — and on mount, so a\n // defaulted off-screen tab is visible. reveal() is scroller-local, so it never\n // scrolls the page/ancestors.\n if (active && changed) {\n reveal(active)\n lastActive = active\n }\n mounted = true\n }\n measure()\n scroller.addEventListener('scroll', syncOverflow, { passive: true })\n const mo = new MutationObserver(measure)\n mo.observe(scroller, {\n subtree: true,\n childList: true,\n // characterData catches a trigger's text growing (e.g. a counter Badge 9→120):\n // in overflow the scroller's border-box is pinned, so that only changes\n // scrollWidth (never reported by the ResizeObserver) yet shifts every tab.\n characterData: true,\n attributeFilter: ['data-active'],\n })\n const ro = new ResizeObserver(measure)\n ro.observe(scroller)\n return () => {\n scroller.removeEventListener('scroll', syncOverflow)\n clearTimeout(wormTimer)\n mo.disconnect()\n ro.disconnect()\n }\n }, [resolved])\n\n const scrollByPage = (dir: 1 | -1) => () => {\n const scroller = scrollerRef.current\n if (typeof scroller?.scrollBy !== 'function') return\n // behavior omitted → follows the scroller's CSS scroll-behavior (smooth,\n // motion-reduce → auto)\n scroller.scrollBy({ left: dir * scroller.clientWidth * 0.6 })\n }\n // Pointer-only affordance: keyboard users page through tabs with arrow keys\n // (focus auto-scrolls), so the chevrons are aria-hidden and out of the tab\n // order — they exist to make hidden overflow visible and clickable. They also\n // can't live INSIDE the list: role=tablist allows only tab children (ARIA),\n // and an absolute child of the scroll container would scroll away with it.\n const chevron = (dir: 1 | -1) => (\n <button\n aria-hidden=\"true\"\n data-slot={dir === 1 ? 'tabs-scroll-next' : 'tabs-scroll-prev'}\n onClick={scrollByPage(dir)}\n tabIndex={-1}\n type=\"button\"\n className={cn(\n // frosted-glass overflow indicator: a 40x40 icon button (button-aligned\n // radius) floating at the overflowing edge, vertically centered. The\n // backdrop-blur reads the tabs sliding under it, so the chevron stays\n // legible over any tab colour — no shadow needed.\n 'absolute top-1/2 z-1 hidden size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))] bg-[var(--color-gray-1)]/72 text-gray-a11 backdrop-blur-sm hover:text-gray-12',\n dir === 1\n ? 'right-0 group-data-[overflow-end]/tabs:flex'\n : 'left-0 group-data-[overflow-start]/tabs:flex',\n )}\n >\n <MaterialSymbol name={dir === 1 ? 'chevron_right' : 'chevron_left'} />\n </button>\n )\n\n return (\n // the wrapper is the public box (data-slot tabs-list, consumer className +\n // style) — group/tabs + data-variant here drive the trigger's group-data-[…]/tabs\n // styling, and data-overflow-start/end (set above) show/hide the chevrons.\n // className + style both land here so a consumer's layout (margin/width) moves\n // the whole control, not just the inner scroller (which would offset the chevrons).\n <div\n className={cn('group/tabs relative inline-block max-w-full', className)}\n data-slot=\"tabs-list\"\n data-variant={resolved}\n ref={wrapperRef}\n style={style}\n >\n {chevron(-1)}\n <TabsPrimitive.List\n data-slot=\"tabs-scroller\"\n ref={scrollerCallbackRef}\n className={cn(\n // mobile-first: scrolls horizontally when the tabs don't fit (inert\n // otherwise). `relative` makes THIS the containing block + offsetParent\n // for the sliding bar: the ::after is laid out in the scroll content, so\n // it travels with its tab, and triggers measure content-relative\n // offsetLeft. scroll-smooth makes every scroll travel — clicks/focus\n // (which honor the triggers' scroll-mx peek), the chevrons' scrollBy,\n // and the observer's reveal.\n 'relative no-scrollbar flex w-full items-stretch overflow-x-auto scroll-smooth motion-reduce:scroll-auto',\n // underline: no continuous track — each trigger carries its OWN bottom\n // rail (below), so the rails read as per-tab segments with gaps between\n // them. items-stretch keeps every trigger full height so their rails (and\n // the accent bar) line up on one baseline.\n resolved === 'underline' && 'gap-2',\n // underline: the sliding accent bar — driven by --tabs-indicator-x/-w\n // (measured above; internal vars, not theme knobs). It rides ON TOP of the\n // active tab's own rail (4px accent over the 2px neutral rail), and worms\n // between tabs. An absolute child of the scroll container scrolls with the\n // content, so it tracks its tab mid-overflow. Color = the parity token\n // --spark-indicator (step 9), HC deepens to 12.\n resolved === 'underline' &&\n \"after:pointer-events-none after:absolute after:bottom-0 after:left-[var(--tabs-indicator-x,0px)] after:h-1 after:w-[var(--tabs-indicator-w,0px)] after:rounded-full after:bg-[var(--spark-tabs-indicator,var(--spark-indicator))] after:transition-[left,width] after:duration-200 after:ease-out after:content-[''] motion-reduce:after:transition-none\",\n // pill: soft neutral track, radius follows the knob (never a full circle)\n resolved === 'pill' && 'gap-0 rounded-md bg-gray-a3 p-1',\n )}\n {...props}\n />\n {chevron(1)}\n </div>\n )\n}\n\ntype TabsTriggerProps = React.ComponentProps<typeof TabsPrimitive.Tab>\n\nfunction TabsTrigger({ className, children, ...props }: TabsTriggerProps) {\n return (\n <TabsPrimitive.Tab\n data-slot=\"tabs-trigger\"\n className={cn(\n // shared: state-driven ink — rest = full neutral (per Figma, not dimmed),\n // active = accent (HC deepens via --spark-tabs-ink). Hover is Radix-style\n // NEUTRAL in both variants (soft fill only, ink stays gray-12 until\n // selected) — berni 2026-07-06, over the Figma no-counter accent hover.\n // scroll-mx = the peek margin every scroll-into-view honors (native focus\n // scrolling included): a revealed tab always drags 40px of its neighbor in\n // group/trigger lets the inner label box react to hover ANYWHERE on the\n // full hit target (the paint shrinks, the target doesn't). min-w reads a var\n // (set per-variant below) via a PLAIN utility, so a consumer's className\n // min-w-* wins by tailwind-merge — a group-data:min-w-* would outrank it on\n // specificity (e.g. icon-only tabs that want to be narrow).\n 'group/trigger inline-flex min-w-[var(--tabs-trigger-minw,0px)] shrink-0 cursor-pointer scroll-mx-10 items-center justify-center whitespace-nowrap text-gray-12 transition-colors',\n 'data-active:text-[color:var(--spark-tabs-ink,var(--spark-a11))]',\n // inset ring: the list is a scroll container, so an outside ring would\n // be clipped at the list edge — inset keeps it fully visible (Radix idiom)\n 'focus-visible:ring-2 focus-visible:outline-hidden focus-visible:ring-inset',\n 'data-disabled:pointer-events-none data-disabled:text-gray-a8',\n '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-4',\n // underline (Figma 20-419): bold 16/24 label, 48px min height; hover fill\n // + rounding live on the INNER label box (Radix anatomy), so the trigger\n // itself carries only layout. The active bar lives on the list (it slides).\n 'group-data-[variant=underline]/tabs:min-h-12 group-data-[variant=underline]/tabs:px-1 group-data-[variant=underline]/tabs:text-base group-data-[variant=underline]/tabs:font-bold group-data-[variant=underline]/tabs:[--tabs-trigger-minw:5rem]',\n // each tab owns its bottom rail (neutral, 2px) — no continuous track. The\n // sliding accent bar (4px) rides on top of the active tab's rail.\n 'group-data-[variant=underline]/tabs:border-b-2 group-data-[variant=underline]/tabs:border-gray-a5',\n // pill: compact segmented thumb — neutral card raised off the track; the\n // thumb IS the full trigger, so its hover fill stays full-size (unlike\n // underline, where the hover is an inset label box per the Radix ref).\n // Radius is concentric with the track: rounded-md (track) − p-1 ≈ rounded-sm.\n 'group-data-[variant=pill]/tabs:h-8 group-data-[variant=pill]/tabs:rounded-sm group-data-[variant=pill]/tabs:px-4 group-data-[variant=pill]/tabs:text-sm group-data-[variant=pill]/tabs:font-medium',\n 'group-data-[variant=pill]/tabs:not-data-active:hover:bg-gray-a3',\n 'group-data-[variant=pill]/tabs:data-active:bg-gray-1 group-data-[variant=pill]/tabs:data-active:shadow-sm dark:group-data-[variant=pill]/tabs:data-active:bg-gray-a4 dark:group-data-[variant=pill]/tabs:data-active:inset-ring dark:group-data-[variant=pill]/tabs:data-active:inset-ring-gray-a6',\n className,\n )}\n {...props}\n >\n {/* the Radix two-box anatomy: the hover paints this compact label box (with\n clearance above the bar/track), not the full 48px hit target */}\n <span\n data-slot=\"tabs-trigger-inner\"\n className={cn(\n 'inline-flex items-center gap-1',\n 'group-data-[variant=underline]/tabs:rounded-md group-data-[variant=underline]/tabs:px-2 group-data-[variant=underline]/tabs:py-1 group-data-[variant=underline]/tabs:transition-colors',\n 'group-data-[variant=underline]/tabs:group-hover/trigger:bg-gray-a3',\n )}\n >\n {children}\n </span>\n </TabsPrimitive.Tab>\n )\n}\n\n/** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */\nconst TabsTriggerUnderline = TabsTrigger\n\n/** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */\nconst TabsTriggerPill = TabsTrigger\n\ntype TabsContentProps = React.ComponentProps<typeof TabsPrimitive.Panel>\n\nfunction TabsContent({ className, ...props }: TabsContentProps) {\n return (\n <TabsPrimitive.Panel\n data-slot=\"tabs-content\"\n className={cn(\n 'focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:outline-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport {\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n TabsTriggerPill,\n TabsTriggerUnderline,\n}\nexport type { TabsListProps, TabsListVariant, TabsProps, TabsTriggerProps }\n"],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
+ import * as React$1 from "react";
5
+ import { Tabs as Tabs$1 } from "@base-ui/react/tabs";
6
+
7
+ //#region src/components/tabs.d.ts
8
+ type TabsProps = React$1.ComponentProps<typeof Tabs$1.Root>;
9
+ declare function Tabs(props: TabsProps): _$react_jsx_runtime0.JSX.Element;
10
+ type TabsListVariant = 'underline';
11
+ /**
12
+ * @deprecated Not part of Spark's tab design — use `'underline'`. `'pill'` (a
13
+ * segmented control) and the old text-only `'default'` still render for
14
+ * back-compat but are undocumented and may be removed.
15
+ */
16
+ type TabsListVariantLegacy = 'default' | 'pill';
17
+ type TabsListProps = Omit<React$1.ComponentProps<typeof Tabs$1.List>, 'style'> & {
18
+ /** `underline` — the Spark tab: bold label + a sliding accent bar. */variant?: TabsListVariant | TabsListVariantLegacy;
19
+ style?: React$1.CSSProperties;
20
+ };
21
+ declare function TabsList({
22
+ className,
23
+ style,
24
+ variant,
25
+ ref,
26
+ ...props
27
+ }: TabsListProps): _$react_jsx_runtime0.JSX.Element;
28
+ type TabsTriggerProps = React$1.ComponentProps<typeof Tabs$1.Tab>;
29
+ declare function TabsTrigger({
30
+ className,
31
+ children,
32
+ ...props
33
+ }: TabsTriggerProps): _$react_jsx_runtime0.JSX.Element;
34
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
35
+ declare const TabsTriggerUnderline: typeof TabsTrigger;
36
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
37
+ declare const TabsTriggerPill: typeof TabsTrigger;
38
+ type TabsContentProps = React$1.ComponentProps<typeof Tabs$1.Panel>;
39
+ declare function TabsContent({
40
+ className,
41
+ ...props
42
+ }: TabsContentProps): _$react_jsx_runtime0.JSX.Element;
43
+ //#endregion
44
+ export { Tabs, TabsContent, TabsList, type TabsListProps, type TabsListVariant, type TabsProps, TabsTrigger, TabsTriggerPill, type TabsTriggerProps, TabsTriggerUnderline };
45
+ //# sourceMappingURL=tabs.d.cts.map
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ import * as React$1 from "react";
4
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
5
+ import { Tabs as Tabs$1 } from "@base-ui/react/tabs";
6
+
7
+ //#region src/components/tabs.d.ts
8
+ type TabsProps = React$1.ComponentProps<typeof Tabs$1.Root>;
9
+ declare function Tabs(props: TabsProps): _$react_jsx_runtime0.JSX.Element;
10
+ type TabsListVariant = 'underline';
11
+ /**
12
+ * @deprecated Not part of Spark's tab design — use `'underline'`. `'pill'` (a
13
+ * segmented control) and the old text-only `'default'` still render for
14
+ * back-compat but are undocumented and may be removed.
15
+ */
16
+ type TabsListVariantLegacy = 'default' | 'pill';
17
+ type TabsListProps = Omit<React$1.ComponentProps<typeof Tabs$1.List>, 'style'> & {
18
+ /** `underline` — the Spark tab: bold label + a sliding accent bar. */variant?: TabsListVariant | TabsListVariantLegacy;
19
+ style?: React$1.CSSProperties;
20
+ };
21
+ declare function TabsList({
22
+ className,
23
+ style,
24
+ variant,
25
+ ref,
26
+ ...props
27
+ }: TabsListProps): _$react_jsx_runtime0.JSX.Element;
28
+ type TabsTriggerProps = React$1.ComponentProps<typeof Tabs$1.Tab>;
29
+ declare function TabsTrigger({
30
+ className,
31
+ children,
32
+ ...props
33
+ }: TabsTriggerProps): _$react_jsx_runtime0.JSX.Element;
34
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
35
+ declare const TabsTriggerUnderline: typeof TabsTrigger;
36
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
37
+ declare const TabsTriggerPill: typeof TabsTrigger;
38
+ type TabsContentProps = React$1.ComponentProps<typeof Tabs$1.Panel>;
39
+ declare function TabsContent({
40
+ className,
41
+ ...props
42
+ }: TabsContentProps): _$react_jsx_runtime0.JSX.Element;
43
+ //#endregion
44
+ export { Tabs, TabsContent, TabsList, type TabsListProps, type TabsListVariant, type TabsProps, TabsTrigger, TabsTriggerPill, type TabsTriggerProps, TabsTriggerUnderline };
45
+ //# sourceMappingURL=tabs.d.ts.map
@@ -0,0 +1,167 @@
1
+ "use client";
2
+ import { cn } from "../utils/cn.js";
3
+ import { MaterialSymbol } from "../icons/material-symbol.js";
4
+ import * as React$1 from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Tabs as Tabs$1 } from "@base-ui/react/tabs";
7
+ //#region src/components/tabs.tsx
8
+ const useIsomorphicLayoutEffect = typeof window === "undefined" ? React$1.useEffect : React$1.useLayoutEffect;
9
+ function setRef(ref, value) {
10
+ if (typeof ref === "function") return ref(value);
11
+ if (ref) ref.current = value;
12
+ }
13
+ function composeRefs(...refs) {
14
+ return (node) => {
15
+ let hasCleanup = false;
16
+ const cleanups = refs.map((ref) => {
17
+ const cleanup = setRef(ref, node);
18
+ if (typeof cleanup === "function") hasCleanup = true;
19
+ return cleanup;
20
+ });
21
+ if (hasCleanup) return () => {
22
+ for (let i = 0; i < refs.length; i++) {
23
+ const cleanup = cleanups[i];
24
+ if (typeof cleanup === "function") cleanup();
25
+ else setRef(refs[i], null);
26
+ }
27
+ };
28
+ };
29
+ }
30
+ function Tabs(props) {
31
+ return /* @__PURE__ */ jsx(Tabs$1.Root, {
32
+ "data-slot": "tabs",
33
+ ...props
34
+ });
35
+ }
36
+ const REVEAL_PEEK = 40;
37
+ const WORM_MS = 210;
38
+ function TabsList({ className, style, variant = "underline", ref, ...props }) {
39
+ const resolved = variant === "pill" ? "pill" : "underline";
40
+ const wrapperRef = React$1.useRef(null);
41
+ const scrollerRef = React$1.useRef(null);
42
+ const scrollerCallbackRef = React$1.useMemo(() => composeRefs(scrollerRef, ref), [ref]);
43
+ useIsomorphicLayoutEffect(() => {
44
+ const wrapper = wrapperRef.current;
45
+ const scroller = scrollerRef.current;
46
+ if (!wrapper || !scroller) return;
47
+ const syncOverflow = () => {
48
+ const max = scroller.scrollWidth - scroller.clientWidth;
49
+ wrapper.toggleAttribute("data-overflow-start", scroller.scrollLeft > 2);
50
+ wrapper.toggleAttribute("data-overflow-end", scroller.scrollLeft < max - 2);
51
+ };
52
+ const reveal = (el) => {
53
+ if (typeof scroller.scrollTo !== "function") return;
54
+ const start = el.offsetLeft - REVEAL_PEEK;
55
+ const end = el.offsetLeft + el.offsetWidth + REVEAL_PEEK;
56
+ if (start < scroller.scrollLeft) scroller.scrollTo({ left: Math.max(0, start) });
57
+ else if (end > scroller.scrollLeft + scroller.clientWidth) scroller.scrollTo({ left: end - scroller.clientWidth });
58
+ };
59
+ const motionQuery = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
60
+ const setBar = (x, w) => {
61
+ scroller.style.setProperty("--tabs-indicator-x", `${x}px`);
62
+ scroller.style.setProperty("--tabs-indicator-w", `${w}px`);
63
+ };
64
+ let lastActive = null;
65
+ let mounted = false;
66
+ let wormTimer;
67
+ const measure = () => {
68
+ const active = scroller.querySelector("[data-slot=\"tabs-trigger\"][data-active]");
69
+ const changed = active !== lastActive;
70
+ if (resolved === "underline") if (!active) {
71
+ clearTimeout(wormTimer);
72
+ lastActive = null;
73
+ scroller.style.setProperty("--tabs-indicator-w", "0px");
74
+ } else if (changed && lastActive?.isConnected && mounted && !motionQuery?.matches) {
75
+ const from = Math.min(lastActive.offsetLeft, active.offsetLeft);
76
+ setBar(from, Math.max(lastActive.offsetLeft + lastActive.offsetWidth, active.offsetLeft + active.offsetWidth) - from);
77
+ clearTimeout(wormTimer);
78
+ const el = active;
79
+ wormTimer = setTimeout(() => setBar(el.offsetLeft, el.offsetWidth), WORM_MS);
80
+ } else {
81
+ clearTimeout(wormTimer);
82
+ setBar(active.offsetLeft, active.offsetWidth);
83
+ }
84
+ syncOverflow();
85
+ if (active && changed) {
86
+ reveal(active);
87
+ lastActive = active;
88
+ }
89
+ mounted = true;
90
+ };
91
+ measure();
92
+ scroller.addEventListener("scroll", syncOverflow, { passive: true });
93
+ const mo = new MutationObserver(measure);
94
+ mo.observe(scroller, {
95
+ subtree: true,
96
+ childList: true,
97
+ characterData: true,
98
+ attributeFilter: ["data-active"]
99
+ });
100
+ const ro = new ResizeObserver(measure);
101
+ ro.observe(scroller);
102
+ return () => {
103
+ scroller.removeEventListener("scroll", syncOverflow);
104
+ clearTimeout(wormTimer);
105
+ mo.disconnect();
106
+ ro.disconnect();
107
+ };
108
+ }, [resolved]);
109
+ const scrollByPage = (dir) => () => {
110
+ const scroller = scrollerRef.current;
111
+ if (typeof scroller?.scrollBy !== "function") return;
112
+ scroller.scrollBy({ left: dir * scroller.clientWidth * .6 });
113
+ };
114
+ const chevron = (dir) => /* @__PURE__ */ jsx("button", {
115
+ "aria-hidden": "true",
116
+ "data-slot": dir === 1 ? "tabs-scroll-next" : "tabs-scroll-prev",
117
+ onClick: scrollByPage(dir),
118
+ tabIndex: -1,
119
+ type: "button",
120
+ className: cn("absolute top-1/2 z-1 hidden size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))] bg-[var(--color-gray-1)]/72 text-gray-a11 backdrop-blur-sm hover:text-gray-12", dir === 1 ? "right-0 group-data-[overflow-end]/tabs:flex" : "left-0 group-data-[overflow-start]/tabs:flex"),
121
+ children: /* @__PURE__ */ jsx(MaterialSymbol, { name: dir === 1 ? "chevron_right" : "chevron_left" })
122
+ });
123
+ return /* @__PURE__ */ jsxs("div", {
124
+ className: cn("group/tabs relative inline-block max-w-full", className),
125
+ "data-slot": "tabs-list",
126
+ "data-variant": resolved,
127
+ ref: wrapperRef,
128
+ style,
129
+ children: [
130
+ chevron(-1),
131
+ /* @__PURE__ */ jsx(Tabs$1.List, {
132
+ "data-slot": "tabs-scroller",
133
+ ref: scrollerCallbackRef,
134
+ className: cn("relative no-scrollbar flex w-full items-stretch overflow-x-auto scroll-smooth motion-reduce:scroll-auto", resolved === "underline" && "gap-2", resolved === "underline" && "after:pointer-events-none after:absolute after:bottom-0 after:left-[var(--tabs-indicator-x,0px)] after:h-1 after:w-[var(--tabs-indicator-w,0px)] after:rounded-full after:bg-[var(--spark-tabs-indicator,var(--spark-indicator))] after:transition-[left,width] after:duration-200 after:ease-out after:content-[''] motion-reduce:after:transition-none", resolved === "pill" && "gap-0 rounded-md bg-gray-a3 p-1"),
135
+ ...props
136
+ }),
137
+ chevron(1)
138
+ ]
139
+ });
140
+ }
141
+ function TabsTrigger({ className, children, ...props }) {
142
+ return /* @__PURE__ */ jsx(Tabs$1.Tab, {
143
+ "data-slot": "tabs-trigger",
144
+ className: cn("group/trigger inline-flex min-w-[var(--tabs-trigger-minw,0px)] shrink-0 cursor-pointer scroll-mx-10 items-center justify-center whitespace-nowrap text-gray-12 transition-colors", "data-active:text-[color:var(--spark-tabs-ink,var(--spark-a11))]", "focus-visible:ring-2 focus-visible:outline-hidden focus-visible:ring-inset", "data-disabled:pointer-events-none data-disabled:text-gray-a8", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-4", "group-data-[variant=underline]/tabs:min-h-12 group-data-[variant=underline]/tabs:px-1 group-data-[variant=underline]/tabs:text-base group-data-[variant=underline]/tabs:font-bold group-data-[variant=underline]/tabs:[--tabs-trigger-minw:5rem]", "group-data-[variant=underline]/tabs:border-b-2 group-data-[variant=underline]/tabs:border-gray-a5", "group-data-[variant=pill]/tabs:h-8 group-data-[variant=pill]/tabs:rounded-sm group-data-[variant=pill]/tabs:px-4 group-data-[variant=pill]/tabs:text-sm group-data-[variant=pill]/tabs:font-medium", "group-data-[variant=pill]/tabs:not-data-active:hover:bg-gray-a3", "group-data-[variant=pill]/tabs:data-active:bg-gray-1 group-data-[variant=pill]/tabs:data-active:shadow-sm dark:group-data-[variant=pill]/tabs:data-active:bg-gray-a4 dark:group-data-[variant=pill]/tabs:data-active:inset-ring dark:group-data-[variant=pill]/tabs:data-active:inset-ring-gray-a6", className),
145
+ ...props,
146
+ children: /* @__PURE__ */ jsx("span", {
147
+ "data-slot": "tabs-trigger-inner",
148
+ className: cn("inline-flex items-center gap-1", "group-data-[variant=underline]/tabs:rounded-md group-data-[variant=underline]/tabs:px-2 group-data-[variant=underline]/tabs:py-1 group-data-[variant=underline]/tabs:transition-colors", "group-data-[variant=underline]/tabs:group-hover/trigger:bg-gray-a3"),
149
+ children
150
+ })
151
+ });
152
+ }
153
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
154
+ const TabsTriggerUnderline = TabsTrigger;
155
+ /** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */
156
+ const TabsTriggerPill = TabsTrigger;
157
+ function TabsContent({ className, ...props }) {
158
+ return /* @__PURE__ */ jsx(Tabs$1.Panel, {
159
+ "data-slot": "tabs-content",
160
+ className: cn("focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:outline-hidden", className),
161
+ ...props
162
+ });
163
+ }
164
+ //#endregion
165
+ export { Tabs, TabsContent, TabsList, TabsTrigger, TabsTriggerPill, TabsTriggerUnderline };
166
+
167
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.js","names":["React","TabsPrimitive"],"sources":["../../src/components/tabs.tsx"],"sourcesContent":["import { Tabs as TabsPrimitive } from '@base-ui/react/tabs'\nimport * as React from 'react'\nimport { MaterialSymbol } from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\n\n// useLayoutEffect warns during SSR; the isomorphic swap is the standard Radix idiom.\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect\n\n// Merge our internal scroller ref with a consumer-forwarded ref. Written locally\n// and React 19-correct: it propagates cleanup-returning callback refs and nulls\n// plain refs on unmount.\ntype PossibleRef<T> = React.Ref<T> | undefined\n\nfunction setRef<T>(ref: PossibleRef<T>, value: T | null) {\n if (typeof ref === 'function') return ref(value)\n if (ref) ref.current = value\n return undefined\n}\n\nfunction composeRefs<T>(...refs: PossibleRef<T>[]) {\n return (node: T) => {\n let hasCleanup = false\n const cleanups = refs.map((ref) => {\n const cleanup = setRef(ref, node)\n if (typeof cleanup === 'function') hasCleanup = true\n return cleanup\n })\n if (hasCleanup) {\n return () => {\n for (let i = 0; i < refs.length; i++) {\n const cleanup = cleanups[i]\n if (typeof cleanup === 'function') cleanup()\n else setRef(refs[i], null)\n }\n }\n }\n return undefined\n }\n}\n\ntype TabsProps = React.ComponentProps<typeof TabsPrimitive.Root>\n\nfunction Tabs(props: TabsProps) {\n return <TabsPrimitive.Root data-slot=\"tabs\" {...props} />\n}\n\ntype TabsListVariant = 'underline'\n\n/**\n * @deprecated Not part of Spark's tab design — use `'underline'`. `'pill'` (a\n * segmented control) and the old text-only `'default'` still render for\n * back-compat but are undocumented and may be removed.\n */\ntype TabsListVariantLegacy = 'default' | 'pill'\n\ntype TabsListProps = Omit<\n React.ComponentProps<typeof TabsPrimitive.List>,\n 'style'\n> & {\n /** `underline` — the Spark tab: bold label + a sliding accent bar. */\n variant?: TabsListVariant | TabsListVariantLegacy\n // style lands on the plain wrapper div, so no Base UI state-callback form\n style?: React.CSSProperties\n}\n\n// how much of a neighboring tab a scroll-into-view reveals (matches scroll-mx-10)\nconst REVEAL_PEEK = 40\n// worm indicator: the accent bar stretches across old+new, then contracts to the\n// new tab. WORM_MS must be >= the bar's CSS transition (200ms) so the stretch fully\n// settles before the contract begins — then contract sets left+width from rest in\n// one synced transition, pinning the leading edge so the motion never jiggles (a\n// contract that starts mid-stretch desyncs the two edges → wobble on big jumps).\nconst WORM_MS = 210\n\nfunction TabsList({\n className,\n style,\n variant = 'underline',\n ref,\n ...props\n}: TabsListProps) {\n // 'underline' is the only real variant. Deprecated 'pill' still renders (a\n // segmented control, kept for back-compat); anything else (incl. the old\n // text-only 'default') folds into underline.\n const resolved = variant === 'pill' ? 'pill' : 'underline'\n const wrapperRef = React.useRef<HTMLDivElement | null>(null)\n const scrollerRef = React.useRef<HTMLDivElement | null>(null)\n // stable identity (keyed on the forwarded ref) so React doesn't detach/re-attach\n // the scroller ref on every render — TabsList re-renders on each selection.\n const scrollerCallbackRef = React.useMemo(\n () => composeRefs<HTMLDivElement>(scrollerRef, ref),\n [ref],\n )\n\n // Sliding underline + overflow state + travel-into-view. The bar lives on the\n // SCROLLER (::after scrolls with the content) and follows the active trigger via\n // two measured vars; useLayoutEffect measures before paint (no flash); the\n // MutationObserver tracks selection + children + text changes; the ResizeObserver\n // re-measures on container/scroller reflow. Together they cover everything that\n // moves a tab: selection, add/remove, a counter Badge growing, and resize.\n useIsomorphicLayoutEffect(() => {\n const wrapper = wrapperRef.current\n const scroller = scrollerRef.current\n if (!wrapper || !scroller) return\n // the edge chevrons show per side while more content hides in that direction\n const syncOverflow = () => {\n // 2px epsilon absorbs sub-pixel rounding at fractional browser zoom\n // (scrollWidth/clientWidth round to int, scrollLeft is fractional). Assumes\n // LTR (scrollLeft >= 0) — Spark's tab strips are LTR.\n const max = scroller.scrollWidth - scroller.clientWidth\n wrapper.toggleAttribute('data-overflow-start', scroller.scrollLeft > 2)\n wrapper.toggleAttribute(\n 'data-overflow-end',\n scroller.scrollLeft < max - 2,\n )\n }\n // scroller-local reveal — deliberately NOT scrollIntoView, which also scrolls\n // ancestors and would yank the page when the list is half off-screen. The peek\n // keeps the neighboring tab partially visible (\"there's more here\").\n const reveal = (el: HTMLElement) => {\n // jsdom (unit tests) doesn't implement Element.scrollTo\n if (typeof scroller.scrollTo !== 'function') return\n const start = el.offsetLeft - REVEAL_PEEK\n const end = el.offsetLeft + el.offsetWidth + REVEAL_PEEK\n if (start < scroller.scrollLeft) {\n scroller.scrollTo({ left: Math.max(0, start) })\n } else if (end > scroller.scrollLeft + scroller.clientWidth) {\n scroller.scrollTo({ left: end - scroller.clientWidth })\n }\n }\n // matchMedia guarded for jsdom (unit tests); read .matches live so toggling the\n // OS reduce-motion setting mid-session takes effect on the next selection.\n const motionQuery =\n typeof window.matchMedia === 'function'\n ? window.matchMedia('(prefers-reduced-motion: reduce)')\n : null\n const setBar = (x: number, w: number) => {\n scroller.style.setProperty('--tabs-indicator-x', `${x}px`)\n scroller.style.setProperty('--tabs-indicator-w', `${w}px`)\n }\n let lastActive: HTMLElement | null = null\n let mounted = false\n let wormTimer: ReturnType<typeof setTimeout> | undefined\n const measure = () => {\n const active = scroller.querySelector<HTMLElement>(\n '[data-slot=\"tabs-trigger\"][data-active]',\n )\n const changed = active !== lastActive\n if (resolved === 'underline') {\n if (!active) {\n // no selection → collapse the bar (width 0), forget the previous tab, and\n // cancel any pending contract, so a later selection never worms from a\n // stale/removed node\n clearTimeout(wormTimer)\n lastActive = null\n scroller.style.setProperty('--tabs-indicator-w', '0px')\n } else if (\n changed &&\n lastActive?.isConnected &&\n mounted &&\n !motionQuery?.matches\n ) {\n // worm: stretch across old + new (one edge holds, the other reaches),\n // then contract to the new tab (the trailing edge catches up). The union\n // makes it direction-agnostic. isConnected guards dynamic tab removal — a\n // detached old node reports offsets of 0 and would sweep the bar from x=0.\n const from = Math.min(lastActive.offsetLeft, active.offsetLeft)\n const to = Math.max(\n lastActive.offsetLeft + lastActive.offsetWidth,\n active.offsetLeft + active.offsetWidth,\n )\n setBar(from, to - from)\n clearTimeout(wormTimer)\n const el = active\n wormTimer = setTimeout(\n () => setBar(el.offsetLeft, el.offsetWidth),\n WORM_MS,\n )\n } else {\n // first paint, reduced motion, detached previous, or a resize (same tab)\n // → settle on the active tab, no worm\n clearTimeout(wormTimer)\n setBar(active.offsetLeft, active.offsetWidth)\n }\n }\n syncOverflow()\n // travel the active tab into view on selection change — and on mount, so a\n // defaulted off-screen tab is visible. reveal() is scroller-local, so it never\n // scrolls the page/ancestors.\n if (active && changed) {\n reveal(active)\n lastActive = active\n }\n mounted = true\n }\n measure()\n scroller.addEventListener('scroll', syncOverflow, { passive: true })\n const mo = new MutationObserver(measure)\n mo.observe(scroller, {\n subtree: true,\n childList: true,\n // characterData catches a trigger's text growing (e.g. a counter Badge 9→120):\n // in overflow the scroller's border-box is pinned, so that only changes\n // scrollWidth (never reported by the ResizeObserver) yet shifts every tab.\n characterData: true,\n attributeFilter: ['data-active'],\n })\n const ro = new ResizeObserver(measure)\n ro.observe(scroller)\n return () => {\n scroller.removeEventListener('scroll', syncOverflow)\n clearTimeout(wormTimer)\n mo.disconnect()\n ro.disconnect()\n }\n }, [resolved])\n\n const scrollByPage = (dir: 1 | -1) => () => {\n const scroller = scrollerRef.current\n if (typeof scroller?.scrollBy !== 'function') return\n // behavior omitted → follows the scroller's CSS scroll-behavior (smooth,\n // motion-reduce → auto)\n scroller.scrollBy({ left: dir * scroller.clientWidth * 0.6 })\n }\n // Pointer-only affordance: keyboard users page through tabs with arrow keys\n // (focus auto-scrolls), so the chevrons are aria-hidden and out of the tab\n // order — they exist to make hidden overflow visible and clickable. They also\n // can't live INSIDE the list: role=tablist allows only tab children (ARIA),\n // and an absolute child of the scroll container would scroll away with it.\n const chevron = (dir: 1 | -1) => (\n <button\n aria-hidden=\"true\"\n data-slot={dir === 1 ? 'tabs-scroll-next' : 'tabs-scroll-prev'}\n onClick={scrollByPage(dir)}\n tabIndex={-1}\n type=\"button\"\n className={cn(\n // frosted-glass overflow indicator: a 40x40 icon button (button-aligned\n // radius) floating at the overflowing edge, vertically centered. The\n // backdrop-blur reads the tabs sliding under it, so the chevron stays\n // legible over any tab colour — no shadow needed.\n 'absolute top-1/2 z-1 hidden size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))] bg-[var(--color-gray-1)]/72 text-gray-a11 backdrop-blur-sm hover:text-gray-12',\n dir === 1\n ? 'right-0 group-data-[overflow-end]/tabs:flex'\n : 'left-0 group-data-[overflow-start]/tabs:flex',\n )}\n >\n <MaterialSymbol name={dir === 1 ? 'chevron_right' : 'chevron_left'} />\n </button>\n )\n\n return (\n // the wrapper is the public box (data-slot tabs-list, consumer className +\n // style) — group/tabs + data-variant here drive the trigger's group-data-[…]/tabs\n // styling, and data-overflow-start/end (set above) show/hide the chevrons.\n // className + style both land here so a consumer's layout (margin/width) moves\n // the whole control, not just the inner scroller (which would offset the chevrons).\n <div\n className={cn('group/tabs relative inline-block max-w-full', className)}\n data-slot=\"tabs-list\"\n data-variant={resolved}\n ref={wrapperRef}\n style={style}\n >\n {chevron(-1)}\n <TabsPrimitive.List\n data-slot=\"tabs-scroller\"\n ref={scrollerCallbackRef}\n className={cn(\n // mobile-first: scrolls horizontally when the tabs don't fit (inert\n // otherwise). `relative` makes THIS the containing block + offsetParent\n // for the sliding bar: the ::after is laid out in the scroll content, so\n // it travels with its tab, and triggers measure content-relative\n // offsetLeft. scroll-smooth makes every scroll travel — clicks/focus\n // (which honor the triggers' scroll-mx peek), the chevrons' scrollBy,\n // and the observer's reveal.\n 'relative no-scrollbar flex w-full items-stretch overflow-x-auto scroll-smooth motion-reduce:scroll-auto',\n // underline: no continuous track — each trigger carries its OWN bottom\n // rail (below), so the rails read as per-tab segments with gaps between\n // them. items-stretch keeps every trigger full height so their rails (and\n // the accent bar) line up on one baseline.\n resolved === 'underline' && 'gap-2',\n // underline: the sliding accent bar — driven by --tabs-indicator-x/-w\n // (measured above; internal vars, not theme knobs). It rides ON TOP of the\n // active tab's own rail (4px accent over the 2px neutral rail), and worms\n // between tabs. An absolute child of the scroll container scrolls with the\n // content, so it tracks its tab mid-overflow. Color = the parity token\n // --spark-indicator (step 9), HC deepens to 12.\n resolved === 'underline' &&\n \"after:pointer-events-none after:absolute after:bottom-0 after:left-[var(--tabs-indicator-x,0px)] after:h-1 after:w-[var(--tabs-indicator-w,0px)] after:rounded-full after:bg-[var(--spark-tabs-indicator,var(--spark-indicator))] after:transition-[left,width] after:duration-200 after:ease-out after:content-[''] motion-reduce:after:transition-none\",\n // pill: soft neutral track, radius follows the knob (never a full circle)\n resolved === 'pill' && 'gap-0 rounded-md bg-gray-a3 p-1',\n )}\n {...props}\n />\n {chevron(1)}\n </div>\n )\n}\n\ntype TabsTriggerProps = React.ComponentProps<typeof TabsPrimitive.Tab>\n\nfunction TabsTrigger({ className, children, ...props }: TabsTriggerProps) {\n return (\n <TabsPrimitive.Tab\n data-slot=\"tabs-trigger\"\n className={cn(\n // shared: state-driven ink — rest = full neutral (per Figma, not dimmed),\n // active = accent (HC deepens via --spark-tabs-ink). Hover is Radix-style\n // NEUTRAL in both variants (soft fill only, ink stays gray-12 until\n // selected) — berni 2026-07-06, over the Figma no-counter accent hover.\n // scroll-mx = the peek margin every scroll-into-view honors (native focus\n // scrolling included): a revealed tab always drags 40px of its neighbor in\n // group/trigger lets the inner label box react to hover ANYWHERE on the\n // full hit target (the paint shrinks, the target doesn't). min-w reads a var\n // (set per-variant below) via a PLAIN utility, so a consumer's className\n // min-w-* wins by tailwind-merge — a group-data:min-w-* would outrank it on\n // specificity (e.g. icon-only tabs that want to be narrow).\n 'group/trigger inline-flex min-w-[var(--tabs-trigger-minw,0px)] shrink-0 cursor-pointer scroll-mx-10 items-center justify-center whitespace-nowrap text-gray-12 transition-colors',\n 'data-active:text-[color:var(--spark-tabs-ink,var(--spark-a11))]',\n // inset ring: the list is a scroll container, so an outside ring would\n // be clipped at the list edge — inset keeps it fully visible (Radix idiom)\n 'focus-visible:ring-2 focus-visible:outline-hidden focus-visible:ring-inset',\n 'data-disabled:pointer-events-none data-disabled:text-gray-a8',\n '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-4',\n // underline (Figma 20-419): bold 16/24 label, 48px min height; hover fill\n // + rounding live on the INNER label box (Radix anatomy), so the trigger\n // itself carries only layout. The active bar lives on the list (it slides).\n 'group-data-[variant=underline]/tabs:min-h-12 group-data-[variant=underline]/tabs:px-1 group-data-[variant=underline]/tabs:text-base group-data-[variant=underline]/tabs:font-bold group-data-[variant=underline]/tabs:[--tabs-trigger-minw:5rem]',\n // each tab owns its bottom rail (neutral, 2px) — no continuous track. The\n // sliding accent bar (4px) rides on top of the active tab's rail.\n 'group-data-[variant=underline]/tabs:border-b-2 group-data-[variant=underline]/tabs:border-gray-a5',\n // pill: compact segmented thumb — neutral card raised off the track; the\n // thumb IS the full trigger, so its hover fill stays full-size (unlike\n // underline, where the hover is an inset label box per the Radix ref).\n // Radius is concentric with the track: rounded-md (track) − p-1 ≈ rounded-sm.\n 'group-data-[variant=pill]/tabs:h-8 group-data-[variant=pill]/tabs:rounded-sm group-data-[variant=pill]/tabs:px-4 group-data-[variant=pill]/tabs:text-sm group-data-[variant=pill]/tabs:font-medium',\n 'group-data-[variant=pill]/tabs:not-data-active:hover:bg-gray-a3',\n 'group-data-[variant=pill]/tabs:data-active:bg-gray-1 group-data-[variant=pill]/tabs:data-active:shadow-sm dark:group-data-[variant=pill]/tabs:data-active:bg-gray-a4 dark:group-data-[variant=pill]/tabs:data-active:inset-ring dark:group-data-[variant=pill]/tabs:data-active:inset-ring-gray-a6',\n className,\n )}\n {...props}\n >\n {/* the Radix two-box anatomy: the hover paints this compact label box (with\n clearance above the bar/track), not the full 48px hit target */}\n <span\n data-slot=\"tabs-trigger-inner\"\n className={cn(\n 'inline-flex items-center gap-1',\n 'group-data-[variant=underline]/tabs:rounded-md group-data-[variant=underline]/tabs:px-2 group-data-[variant=underline]/tabs:py-1 group-data-[variant=underline]/tabs:transition-colors',\n 'group-data-[variant=underline]/tabs:group-hover/trigger:bg-gray-a3',\n )}\n >\n {children}\n </span>\n </TabsPrimitive.Tab>\n )\n}\n\n/** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */\nconst TabsTriggerUnderline = TabsTrigger\n\n/** @deprecated Use `TabsTrigger` — it adapts to the `TabsList` variant automatically. */\nconst TabsTriggerPill = TabsTrigger\n\ntype TabsContentProps = React.ComponentProps<typeof TabsPrimitive.Panel>\n\nfunction TabsContent({ className, ...props }: TabsContentProps) {\n return (\n <TabsPrimitive.Panel\n data-slot=\"tabs-content\"\n className={cn(\n 'focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:outline-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport {\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n TabsTriggerPill,\n TabsTriggerUnderline,\n}\nexport type { TabsListProps, TabsListVariant, TabsProps, TabsTriggerProps }\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ "use client";
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
+ const require_theme = require("../theme-C9_OSe0S.cjs");
5
+ exports.Theme = require_theme.Theme;
6
+ exports.useTheme = require_theme.useTheme;
@@ -0,0 +1,38 @@
1
+ "use client";
2
+
3
+ import { a as SparkInputStyle, c as SparkRadius, d as SparkStyle, i as SparkInputColor, l as SparkScaling, n as SparkCardColor, o as SparkLabelPosition, r as SparkCardVariant, s as SparkNeutral, u as SparkSpacing } from "../theme-types-r20EJfEC.cjs";
4
+ import * as React$1 from "react";
5
+ import { useRender } from "@base-ui/react/use-render";
6
+
7
+ //#region src/lib/accent-theme.d.ts
8
+ type Appearance = 'light' | 'dark';
9
+ //#endregion
10
+ //#region src/components/theme.d.ts
11
+ interface ThemeValue {
12
+ /** Curated accent name or a custom hex. */
13
+ accentColor?: string;
14
+ /** A neutral name, or `'auto'` to pair one with the accent (Radix's `grayColor="auto"`). */
15
+ neutralColor?: SparkNeutral;
16
+ radius?: SparkRadius;
17
+ scaling?: SparkScaling;
18
+ spacing?: SparkSpacing;
19
+ styleVariant?: SparkStyle;
20
+ /** Orthogonal to `styleVariant`: shifts any style toward higher-contrast steps. */
21
+ highContrast?: boolean;
22
+ labelPosition?: SparkLabelPosition;
23
+ inputStyle?: SparkInputStyle;
24
+ inputColor?: SparkInputColor;
25
+ /** App-level default `<Card>` chrome; a per-card `variant` prop overrides it. */
26
+ cardVariant?: SparkCardVariant;
27
+ /** App-level default `<Card>` palette; a per-card `color` prop overrides it. */
28
+ cardColor?: SparkCardColor;
29
+ appearance?: Appearance;
30
+ }
31
+ /** Merged theme values from enclosing `<Theme>` providers. */
32
+ declare function useTheme(): ThemeValue;
33
+ interface ThemeProps extends useRender.ComponentProps<'div'>, ThemeValue {}
34
+ /** Optional sugar: writes the theming `data-*` attrs + accent `--spark-*` vars onto a wrapper. */
35
+ declare const Theme: React$1.ForwardRefExoticComponent<Omit<ThemeProps, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
36
+ //#endregion
37
+ export { type SparkCardColor, type SparkCardVariant, type SparkInputColor, type SparkInputStyle, type SparkLabelPosition, type SparkNeutral, type SparkRadius, type SparkScaling, type SparkSpacing, type SparkStyle, Theme, ThemeProps, ThemeValue, useTheme };
38
+ //# sourceMappingURL=theme.d.cts.map
@@ -0,0 +1,38 @@
1
+ "use client";
2
+
3
+ import { a as SparkInputStyle, c as SparkRadius, d as SparkStyle, i as SparkInputColor, l as SparkScaling, n as SparkCardColor, o as SparkLabelPosition, r as SparkCardVariant, s as SparkNeutral, u as SparkSpacing } from "../theme-types-DoROIXpi.js";
4
+ import * as React$1 from "react";
5
+ import { useRender } from "@base-ui/react/use-render";
6
+
7
+ //#region src/lib/accent-theme.d.ts
8
+ type Appearance = 'light' | 'dark';
9
+ //#endregion
10
+ //#region src/components/theme.d.ts
11
+ interface ThemeValue {
12
+ /** Curated accent name or a custom hex. */
13
+ accentColor?: string;
14
+ /** A neutral name, or `'auto'` to pair one with the accent (Radix's `grayColor="auto"`). */
15
+ neutralColor?: SparkNeutral;
16
+ radius?: SparkRadius;
17
+ scaling?: SparkScaling;
18
+ spacing?: SparkSpacing;
19
+ styleVariant?: SparkStyle;
20
+ /** Orthogonal to `styleVariant`: shifts any style toward higher-contrast steps. */
21
+ highContrast?: boolean;
22
+ labelPosition?: SparkLabelPosition;
23
+ inputStyle?: SparkInputStyle;
24
+ inputColor?: SparkInputColor;
25
+ /** App-level default `<Card>` chrome; a per-card `variant` prop overrides it. */
26
+ cardVariant?: SparkCardVariant;
27
+ /** App-level default `<Card>` palette; a per-card `color` prop overrides it. */
28
+ cardColor?: SparkCardColor;
29
+ appearance?: Appearance;
30
+ }
31
+ /** Merged theme values from enclosing `<Theme>` providers. */
32
+ declare function useTheme(): ThemeValue;
33
+ interface ThemeProps extends useRender.ComponentProps<'div'>, ThemeValue {}
34
+ /** Optional sugar: writes the theming `data-*` attrs + accent `--spark-*` vars onto a wrapper. */
35
+ declare const Theme: React$1.ForwardRefExoticComponent<Omit<ThemeProps, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
36
+ //#endregion
37
+ export { type SparkCardColor, type SparkCardVariant, type SparkInputColor, type SparkInputStyle, type SparkLabelPosition, type SparkNeutral, type SparkRadius, type SparkScaling, type SparkSpacing, type SparkStyle, Theme, ThemeProps, ThemeValue, useTheme };
38
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ "use client";
3
+ import { n as useTheme, t as Theme } from "../theme-B3WtiByA.js";
4
+ export { Theme, useTheme };