@teamofsilicons/silicon-ui 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +81 -2
  3. package/check.mjs +236 -0
  4. package/components/accordion/accordion.d.ts +13 -0
  5. package/components/accordion/accordion.js +35 -0
  6. package/components/accordion/accordion.module.css +15 -0
  7. package/components/action-button/action-button.d.ts +11 -0
  8. package/components/action-button/action-button.js +57 -0
  9. package/components/action-button/action-button.module.css +15 -0
  10. package/components/activity-heatmap/activity-heatmap.d.ts +37 -0
  11. package/components/activity-heatmap/activity-heatmap.js +303 -0
  12. package/components/activity-heatmap/activity-heatmap.module.css +83 -0
  13. package/components/alert/alert.d.ts +13 -0
  14. package/components/alert/alert.js +79 -0
  15. package/components/alert/alert.module.css +15 -0
  16. package/components/animated-counter/animated-counter.d.ts +13 -0
  17. package/components/animated-counter/animated-counter.js +73 -0
  18. package/components/animated-counter/animated-counter.module.css +12 -0
  19. package/components/announcement-bar/announcement-bar.d.ts +53 -0
  20. package/components/announcement-bar/announcement-bar.js +187 -0
  21. package/components/announcement-bar/announcement-bar.module.css +60 -0
  22. package/components/avatar/avatar.d.ts +8 -0
  23. package/components/avatar/avatar.js +18 -0
  24. package/components/avatar/avatar.module.css +60 -0
  25. package/components/avatar-group/avatar-group.d.ts +13 -0
  26. package/components/avatar-group/avatar-group.js +24 -0
  27. package/components/avatar-group/avatar-group.module.css +27 -0
  28. package/components/badge/badge.d.ts +10 -0
  29. package/components/badge/badge.js +66 -0
  30. package/components/badge/badge.module.css +52 -0
  31. package/components/bar-chart/bar-chart.d.ts +32 -0
  32. package/components/bar-chart/bar-chart.js +327 -0
  33. package/components/bar-chart/bar-chart.module.css +49 -0
  34. package/components/billing-toggle/billing-toggle.d.ts +35 -0
  35. package/components/billing-toggle/billing-toggle.js +83 -0
  36. package/components/billing-toggle/billing-toggle.module.css +139 -0
  37. package/components/bottom-sheet/bottom-sheet.d.ts +27 -0
  38. package/components/bottom-sheet/bottom-sheet.js +386 -0
  39. package/components/bottom-sheet/bottom-sheet.module.css +69 -0
  40. package/components/breadcrumb/breadcrumb.d.ts +13 -0
  41. package/components/breadcrumb/breadcrumb.js +19 -0
  42. package/components/breadcrumb/breadcrumb.module.css +12 -0
  43. package/components/brush-chart/brush-chart.d.ts +45 -0
  44. package/components/brush-chart/brush-chart.js +426 -0
  45. package/components/brush-chart/brush-chart.module.css +69 -0
  46. package/components/button/button.d.ts +10 -0
  47. package/components/button/button.js +97 -0
  48. package/components/button/button.module.css +39 -0
  49. package/components/button-group/button-group.d.ts +59 -0
  50. package/components/button-group/button-group.js +280 -0
  51. package/components/button-group/button-group.module.css +87 -0
  52. package/components/button-link/button-link.d.ts +24 -0
  53. package/components/button-link/button-link.js +11 -0
  54. package/components/button-link/button-link.module.css +7 -0
  55. package/components/calendar/calendar.d.ts +22 -0
  56. package/components/calendar/calendar.js +253 -0
  57. package/components/calendar/calendar.module.css +51 -0
  58. package/components/card/card.d.ts +19 -0
  59. package/components/card/card.js +108 -0
  60. package/components/card/card.module.css +51 -0
  61. package/components/card-stack/card-stack.d.ts +34 -0
  62. package/components/card-stack/card-stack.js +291 -0
  63. package/components/card-stack/card-stack.module.css +63 -0
  64. package/components/carousel/carousel.d.ts +28 -0
  65. package/components/carousel/carousel.js +332 -0
  66. package/components/carousel/carousel.module.css +42 -0
  67. package/components/chat-thread/chat-thread.d.ts +135 -0
  68. package/components/chat-thread/chat-thread.js +406 -0
  69. package/components/chat-thread/chat-thread.module.css +242 -0
  70. package/components/checkbox/checkbox.d.ts +7 -0
  71. package/components/checkbox/checkbox.js +23 -0
  72. package/components/checkbox/checkbox.module.css +15 -0
  73. package/components/chip-group/chip-group.d.ts +24 -0
  74. package/components/chip-group/chip-group.js +196 -0
  75. package/components/chip-group/chip-group.module.css +38 -0
  76. package/components/code-block/code-block.d.ts +11 -0
  77. package/components/code-block/code-block.js +133 -0
  78. package/components/code-block/code-block.module.css +43 -0
  79. package/components/color-picker/color-picker.d.ts +40 -0
  80. package/components/color-picker/color-picker.js +449 -0
  81. package/components/color-picker/color-picker.module.css +111 -0
  82. package/components/combobox/combobox.d.ts +19 -0
  83. package/components/combobox/combobox.js +167 -0
  84. package/components/combobox/combobox.module.css +28 -0
  85. package/components/command-palette/command-palette.d.ts +20 -0
  86. package/components/command-palette/command-palette.js +151 -0
  87. package/components/command-palette/command-palette.module.css +94 -0
  88. package/components/comment-thread/comment-thread.d.ts +120 -0
  89. package/components/comment-thread/comment-thread.js +343 -0
  90. package/components/comment-thread/comment-thread.module.css +195 -0
  91. package/components/confirm-morph/confirm-morph.d.ts +65 -0
  92. package/components/confirm-morph/confirm-morph.js +355 -0
  93. package/components/confirm-morph/confirm-morph.module.css +146 -0
  94. package/components/context-menu/context-menu.d.ts +18 -0
  95. package/components/context-menu/context-menu.js +148 -0
  96. package/components/context-menu/context-menu.module.css +17 -0
  97. package/components/copy-button/copy-button.d.ts +10 -0
  98. package/components/copy-button/copy-button.js +69 -0
  99. package/components/copy-button/copy-button.module.css +21 -0
  100. package/components/countdown/countdown.d.ts +31 -0
  101. package/components/countdown/countdown.js +177 -0
  102. package/components/countdown/countdown.module.css +49 -0
  103. package/components/date-picker/date-picker.d.ts +17 -0
  104. package/components/date-picker/date-picker.js +100 -0
  105. package/components/date-picker/date-picker.module.css +34 -0
  106. package/components/date-range-picker/date-range-picker.d.ts +44 -0
  107. package/components/date-range-picker/date-range-picker.js +534 -0
  108. package/components/date-range-picker/date-range-picker.module.css +214 -0
  109. package/components/dialog/dialog.d.ts +11 -0
  110. package/components/dialog/dialog.js +52 -0
  111. package/components/dialog/dialog.module.css +36 -0
  112. package/components/donut-chart/donut-chart.d.ts +46 -0
  113. package/components/donut-chart/donut-chart.js +382 -0
  114. package/components/donut-chart/donut-chart.module.css +48 -0
  115. package/components/drawer/drawer.d.ts +20 -0
  116. package/components/drawer/drawer.js +111 -0
  117. package/components/drawer/drawer.module.css +97 -0
  118. package/components/dropdown-menu/dropdown-menu.d.ts +16 -0
  119. package/components/dropdown-menu/dropdown-menu.js +39 -0
  120. package/components/dropdown-menu/dropdown-menu.module.css +38 -0
  121. package/components/elastic-slider/elastic-slider.d.ts +39 -0
  122. package/components/elastic-slider/elastic-slider.js +261 -0
  123. package/components/elastic-slider/elastic-slider.module.css +40 -0
  124. package/components/empty-state/empty-state.d.ts +12 -0
  125. package/components/empty-state/empty-state.js +69 -0
  126. package/components/empty-state/empty-state.module.css +13 -0
  127. package/components/expandable-card/expandable-card.d.ts +13 -0
  128. package/components/expandable-card/expandable-card.js +89 -0
  129. package/components/expandable-card/expandable-card.module.css +22 -0
  130. package/components/expanding-button-group/expanding-button-group.d.ts +41 -0
  131. package/components/expanding-button-group/expanding-button-group.js +258 -0
  132. package/components/expanding-button-group/expanding-button-group.module.css +44 -0
  133. package/components/expanding-search/expanding-search.d.ts +38 -0
  134. package/components/expanding-search/expanding-search.js +242 -0
  135. package/components/expanding-search/expanding-search.module.css +52 -0
  136. package/components/file-dropzone/file-dropzone.d.ts +44 -0
  137. package/components/file-dropzone/file-dropzone.js +379 -0
  138. package/components/file-dropzone/file-dropzone.module.css +115 -0
  139. package/components/file-upload/file-upload.d.ts +22 -0
  140. package/components/file-upload/file-upload.js +192 -0
  141. package/components/file-upload/file-upload.module.css +49 -0
  142. package/components/filter-toolbar/filter-toolbar.d.ts +48 -0
  143. package/components/filter-toolbar/filter-toolbar.js +446 -0
  144. package/components/filter-toolbar/filter-toolbar.module.css +70 -0
  145. package/components/floating-button-group/floating-button-group.d.ts +51 -0
  146. package/components/floating-button-group/floating-button-group.js +215 -0
  147. package/components/floating-button-group/floating-button-group.module.css +74 -0
  148. package/components/gauge/gauge.d.ts +18 -0
  149. package/components/gauge/gauge.js +101 -0
  150. package/components/gauge/gauge.module.css +22 -0
  151. package/components/hold-to-confirm/hold-to-confirm.d.ts +25 -0
  152. package/components/hold-to-confirm/hold-to-confirm.js +165 -0
  153. package/components/hold-to-confirm/hold-to-confirm.module.css +20 -0
  154. package/components/hover-card/hover-card.d.ts +38 -0
  155. package/components/hover-card/hover-card.js +145 -0
  156. package/components/hover-card/hover-card.module.css +20 -0
  157. package/components/image-compare/image-compare.d.ts +27 -0
  158. package/components/image-compare/image-compare.js +267 -0
  159. package/components/image-compare/image-compare.module.css +25 -0
  160. package/components/in-view-title/in-view-title.d.ts +17 -0
  161. package/components/in-view-title/in-view-title.js +70 -0
  162. package/components/in-view-title/in-view-title.module.css +13 -0
  163. package/components/inline-edit/inline-edit.d.ts +27 -0
  164. package/components/inline-edit/inline-edit.js +315 -0
  165. package/components/inline-edit/inline-edit.module.css +73 -0
  166. package/components/input/input.d.ts +7 -0
  167. package/components/input/input.js +60 -0
  168. package/components/input/input.module.css +22 -0
  169. package/components/json-viewer/json-viewer.d.ts +48 -0
  170. package/components/json-viewer/json-viewer.js +463 -0
  171. package/components/json-viewer/json-viewer.module.css +92 -0
  172. package/components/line-chart/line-chart.d.ts +58 -0
  173. package/components/line-chart/line-chart.js +383 -0
  174. package/components/line-chart/line-chart.module.css +60 -0
  175. package/components/mention-input/mention-input.d.ts +72 -0
  176. package/components/mention-input/mention-input.js +417 -0
  177. package/components/mention-input/mention-input.module.css +134 -0
  178. package/components/metric-card/metric-card.d.ts +8 -0
  179. package/components/metric-card/metric-card.js +44 -0
  180. package/components/metric-card/metric-card.module.css +18 -0
  181. package/components/money-input/money-input.d.ts +48 -0
  182. package/components/money-input/money-input.js +503 -0
  183. package/components/money-input/money-input.module.css +77 -0
  184. package/components/morph-select/morph-select.d.ts +50 -0
  185. package/components/morph-select/morph-select.js +395 -0
  186. package/components/morph-select/morph-select.module.css +88 -0
  187. package/components/multi-select/multi-select.d.ts +18 -0
  188. package/components/multi-select/multi-select.js +105 -0
  189. package/components/multi-select/multi-select.module.css +37 -0
  190. package/components/notification-center/notification-center.d.ts +24 -0
  191. package/components/notification-center/notification-center.js +146 -0
  192. package/components/notification-center/notification-center.module.css +79 -0
  193. package/components/number-field/number-field.d.ts +41 -0
  194. package/components/number-field/number-field.js +455 -0
  195. package/components/number-field/number-field.module.css +71 -0
  196. package/components/otp-input/otp-input.d.ts +13 -0
  197. package/components/otp-input/otp-input.js +129 -0
  198. package/components/otp-input/otp-input.module.css +28 -0
  199. package/components/pagination/pagination.d.ts +7 -0
  200. package/components/pagination/pagination.js +60 -0
  201. package/components/pagination/pagination.module.css +16 -0
  202. package/components/password-field/password-field.d.ts +14 -0
  203. package/components/password-field/password-field.js +51 -0
  204. package/components/password-field/password-field.module.css +27 -0
  205. package/components/password-strength/password-strength.d.ts +107 -0
  206. package/components/password-strength/password-strength.js +161 -0
  207. package/components/password-strength/password-strength.module.css +57 -0
  208. package/components/phone-input/phone-input.d.ts +73 -0
  209. package/components/phone-input/phone-input.js +612 -0
  210. package/components/phone-input/phone-input.module.css +98 -0
  211. package/components/popover/popover.d.ts +6 -0
  212. package/components/popover/popover.js +19 -0
  213. package/components/popover/popover.module.css +32 -0
  214. package/components/progress/progress.d.ts +8 -0
  215. package/components/progress/progress.js +42 -0
  216. package/components/progress/progress.module.css +1 -0
  217. package/components/radio-cards/radio-cards.d.ts +35 -0
  218. package/components/radio-cards/radio-cards.js +110 -0
  219. package/components/radio-cards/radio-cards.module.css +84 -0
  220. package/components/radio-group/radio-group.d.ts +13 -0
  221. package/components/radio-group/radio-group.js +55 -0
  222. package/components/radio-group/radio-group.module.css +30 -0
  223. package/components/resizable-panels/resizable-panels.d.ts +37 -0
  224. package/components/resizable-panels/resizable-panels.js +338 -0
  225. package/components/resizable-panels/resizable-panels.module.css +40 -0
  226. package/components/rich-text-editor/rich-text-editor.d.ts +55 -0
  227. package/components/rich-text-editor/rich-text-editor.js +1733 -0
  228. package/components/rich-text-editor/rich-text-editor.module.css +201 -0
  229. package/components/ridgeline/ridgeline.d.ts +37 -0
  230. package/components/ridgeline/ridgeline.js +346 -0
  231. package/components/ridgeline/ridgeline.module.css +58 -0
  232. package/components/scroll-area/scroll-area.d.ts +40 -0
  233. package/components/scroll-area/scroll-area.js +153 -0
  234. package/components/scroll-area/scroll-area.module.css +79 -0
  235. package/components/search-field/search-field.d.ts +7 -0
  236. package/components/search-field/search-field.js +20 -0
  237. package/components/search-field/search-field.module.css +17 -0
  238. package/components/segmented-control/segmented-control.d.ts +16 -0
  239. package/components/segmented-control/segmented-control.js +56 -0
  240. package/components/segmented-control/segmented-control.module.css +15 -0
  241. package/components/select/select.d.ts +15 -0
  242. package/components/select/select.js +36 -0
  243. package/components/select/select.module.css +35 -0
  244. package/components/shortcut-recorder/shortcut-recorder.d.ts +108 -0
  245. package/components/shortcut-recorder/shortcut-recorder.js +380 -0
  246. package/components/shortcut-recorder/shortcut-recorder.module.css +85 -0
  247. package/components/signature-pad/signature-pad.d.ts +72 -0
  248. package/components/signature-pad/signature-pad.js +450 -0
  249. package/components/signature-pad/signature-pad.module.css +84 -0
  250. package/components/skeleton/skeleton.d.ts +13 -0
  251. package/components/skeleton/skeleton.js +53 -0
  252. package/components/skeleton/skeleton.module.css +11 -0
  253. package/components/slider/slider.d.ts +45 -0
  254. package/components/slider/slider.js +347 -0
  255. package/components/slider/slider.module.css +45 -0
  256. package/components/slope-chart/slope-chart.d.ts +38 -0
  257. package/components/slope-chart/slope-chart.js +183 -0
  258. package/components/slope-chart/slope-chart.module.css +51 -0
  259. package/components/slot-text/slot-text.d.ts +26 -0
  260. package/components/slot-text/slot-text.js +119 -0
  261. package/components/slot-text/slot-text.module.css +19 -0
  262. package/components/sortable-data-table/sortable-data-table.d.ts +38 -0
  263. package/components/sortable-data-table/sortable-data-table.js +240 -0
  264. package/components/sortable-data-table/sortable-data-table.module.css +116 -0
  265. package/components/sparkline/sparkline.d.ts +19 -0
  266. package/components/sparkline/sparkline.js +239 -0
  267. package/components/sparkline/sparkline.module.css +26 -0
  268. package/components/split-button/split-button.d.ts +19 -0
  269. package/components/split-button/split-button.js +33 -0
  270. package/components/split-button/split-button.module.css +51 -0
  271. package/components/stepper/stepper.d.ts +36 -0
  272. package/components/stepper/stepper.js +108 -0
  273. package/components/stepper/stepper.module.css +74 -0
  274. package/components/streamgraph/streamgraph.d.ts +51 -0
  275. package/components/streamgraph/streamgraph.js +376 -0
  276. package/components/streamgraph/streamgraph.module.css +55 -0
  277. package/components/swipe-actions/swipe-actions.d.ts +35 -0
  278. package/components/swipe-actions/swipe-actions.js +330 -0
  279. package/components/swipe-actions/swipe-actions.module.css +64 -0
  280. package/components/switch/switch.d.ts +7 -0
  281. package/components/switch/switch.js +45 -0
  282. package/components/switch/switch.module.css +12 -0
  283. package/components/tabs/tabs.d.ts +8 -0
  284. package/components/tabs/tabs.js +138 -0
  285. package/components/tabs/tabs.module.css +27 -0
  286. package/components/tag-input/tag-input.d.ts +15 -0
  287. package/components/tag-input/tag-input.js +150 -0
  288. package/components/tag-input/tag-input.module.css +34 -0
  289. package/components/text-morph/text-morph.d.ts +13 -0
  290. package/components/text-morph/text-morph.js +69 -0
  291. package/components/text-morph/text-morph.module.css +8 -0
  292. package/components/text-reveal/text-reveal.d.ts +14 -0
  293. package/components/text-reveal/text-reveal.js +20 -0
  294. package/components/text-reveal/text-reveal.module.css +13 -0
  295. package/components/text-shimmer/text-shimmer.d.ts +18 -0
  296. package/components/text-shimmer/text-shimmer.js +90 -0
  297. package/components/text-shimmer/text-shimmer.module.css +9 -0
  298. package/components/textarea/textarea.d.ts +7 -0
  299. package/components/textarea/textarea.js +56 -0
  300. package/components/textarea/textarea.module.css +22 -0
  301. package/components/theme-switch/theme-switch.d.ts +11 -0
  302. package/components/theme-switch/theme-switch.js +37 -0
  303. package/components/theme-switch/theme-switch.module.css +31 -0
  304. package/components/time-picker/time-picker.d.ts +13 -0
  305. package/components/time-picker/time-picker.js +95 -0
  306. package/components/time-picker/time-picker.module.css +23 -0
  307. package/components/timeline/timeline.d.ts +47 -0
  308. package/components/timeline/timeline.js +171 -0
  309. package/components/timeline/timeline.module.css +51 -0
  310. package/components/toast/toast.d.ts +8 -0
  311. package/components/toast/toast.js +118 -0
  312. package/components/toast/toast.module.css +100 -0
  313. package/components/toast-stack/toast-stack.d.ts +57 -0
  314. package/components/toast-stack/toast-stack.js +399 -0
  315. package/components/toast-stack/toast-stack.module.css +61 -0
  316. package/components/tooltip/tooltip.d.ts +8 -0
  317. package/components/tooltip/tooltip.js +62 -0
  318. package/components/tooltip/tooltip.module.css +18 -0
  319. package/components/tree-view/tree-view.d.ts +17 -0
  320. package/components/tree-view/tree-view.js +147 -0
  321. package/components/tree-view/tree-view.module.css +22 -0
  322. package/components/treemap/treemap.d.ts +35 -0
  323. package/components/treemap/treemap.js +375 -0
  324. package/components/treemap/treemap.module.css +59 -0
  325. package/components/usage-meter/usage-meter.d.ts +24 -0
  326. package/components/usage-meter/usage-meter.js +296 -0
  327. package/components/usage-meter/usage-meter.module.css +61 -0
  328. package/components/user-menu/user-menu.d.ts +62 -0
  329. package/components/user-menu/user-menu.js +316 -0
  330. package/components/user-menu/user-menu.module.css +97 -0
  331. package/components/waffle-chart/waffle-chart.d.ts +39 -0
  332. package/components/waffle-chart/waffle-chart.js +244 -0
  333. package/components/waffle-chart/waffle-chart.module.css +52 -0
  334. package/components.json +1330 -0
  335. package/eslint.js +53 -0
  336. package/lib/escape.d.ts +19 -0
  337. package/lib/escape.js +50 -0
  338. package/lib/media.d.ts +353 -0
  339. package/lib/media.js +65 -0
  340. package/lib/menu-highlight.d.ts +28 -0
  341. package/lib/menu-highlight.js +43 -0
  342. package/lib/motion-tokens.d.ts +60 -0
  343. package/lib/motion-tokens.js +25 -0
  344. package/lib/return-focus.d.ts +9 -0
  345. package/lib/return-focus.js +53 -0
  346. package/lib/silicon-provider.d.ts +60 -0
  347. package/lib/silicon-provider.js +47 -0
  348. package/lib/use-copy-feedback.d.ts +8 -0
  349. package/lib/use-copy-feedback.js +36 -0
  350. package/lib/use-today.d.ts +2 -0
  351. package/lib/use-today.js +29 -0
  352. package/package.json +76 -4
  353. package/styles.css +218 -0
  354. package/styles.css.d.ts +1 -0
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
4
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5
+ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
6
+ import { motionTokens } from "../../lib/motion-tokens.js";
7
+ import styles from "./tooltip.module.css";
8
+ const DELAY = 250;
9
+ const SKIP_WINDOW = 300;
10
+ /* Every Tooltip brings its own provider, so the skip window is shared here: while any tooltip is open, and briefly after the last one closes, the next opens without delay or travel. */
11
+ let warm = false;
12
+ let openCount = 0;
13
+ let coolTimer = 0;
14
+ const listeners = new Set();
15
+ const warmth = {
16
+ subscribe(listener) { listeners.add(listener); return () => { listeners.delete(listener); }; },
17
+ get: () => warm,
18
+ set(next) { if (warm === next)
19
+ return; warm = next; listeners.forEach(listener => listener()); },
20
+ opened() { openCount += 1; window.clearTimeout(coolTimer); warmth.set(true); },
21
+ closed() { openCount = Math.max(0, openCount - 1); if (openCount)
22
+ return; window.clearTimeout(coolTimer); coolTimer = window.setTimeout(() => warmth.set(false), SKIP_WINDOW); },
23
+ };
24
+ /** String content crossfades when it changes while open, and the bubble springs to the new text size. */
25
+ function TooltipText({ text }) {
26
+ const reduced = useReducedMotion();
27
+ const measure = useRef(null);
28
+ const measured = useRef(null);
29
+ const [size, setSize] = useState(null);
30
+ useLayoutEffect(() => {
31
+ const node = measure.current;
32
+ if (!node)
33
+ return;
34
+ const observer = new ResizeObserver(([entry]) => {
35
+ if (!entry)
36
+ return;
37
+ const box = entry.borderBoxSize?.[0];
38
+ const current = node.textContent;
39
+ const animate = measured.current !== null && measured.current !== current;
40
+ measured.current = current;
41
+ setSize({ width: Math.ceil(box?.inlineSize ?? node.offsetWidth), height: Math.ceil(box?.blockSize ?? node.offsetHeight), animate });
42
+ });
43
+ observer.observe(node);
44
+ return () => observer.disconnect();
45
+ }, []);
46
+ return _jsxs(motion.span, { className: styles.text, initial: false, animate: size ? { width: size.width, height: size.height } : undefined, transition: size?.animate && !reduced ? motionTokens.spring.morph : { duration: 0 }, children: [_jsx("span", { ref: measure, className: styles.measure, "aria-hidden": "true", children: text }), _jsx(AnimatePresence, { mode: "popLayout", initial: false, children: _jsx(motion.span, { className: styles.line, initial: reduced ? false : { opacity: 0, y: "0.3em", filter: `blur(${motionTokens.blur.soft}px)` }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, exit: reduced ? { opacity: 0, transition: { duration: 0 } } : { opacity: 0, y: "-0.3em", filter: `blur(${motionTokens.blur.subtle}px)`, transition: { duration: motionTokens.duration.instant, ease: [...motionTokens.ease.standard] } }, transition: { duration: motionTokens.duration.standard, ease: [...motionTokens.ease.enter] }, children: text }, text) })] });
47
+ }
48
+ export function Tooltip({ content, children, side = "top" }) {
49
+ const isWarm = useSyncExternalStore(warmth.subscribe, warmth.get, () => false);
50
+ // Controlled so the instant flag lands in the same render that mounts the content (Radix reports uncontrolled changes a frame late).
51
+ const [open, setOpen] = useState(false);
52
+ const [instant, setInstant] = useState(false);
53
+ useEffect(() => {
54
+ if (!open)
55
+ return;
56
+ warmth.opened();
57
+ return warmth.closed;
58
+ }, [open]);
59
+ return _jsx(TooltipPrimitive.Provider, { delayDuration: DELAY, skipDelayDuration: 0, children: _jsxs(TooltipPrimitive.Root, { open: open, delayDuration: isWarm ? 0 : DELAY, onOpenChange: next => { if (next)
60
+ setInstant(warmth.get()); setOpen(next); }, children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: children }), _jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { className: styles.tooltip, "data-instant": instant || undefined, side: side, sideOffset: 8, collisionPadding: 12, children: typeof content === "string" || typeof content === "number" ? _jsx(TooltipText, { text: String(content) }) : content }) })] }) });
61
+ }
62
+ export default Tooltip;
@@ -0,0 +1,18 @@
1
+ .tooltip { --tooltip-y: 3px; z-index: 90; max-width: 15rem; padding: var(--space-group) var(--space-inset); border: 1px solid color-mix(in oklab, var(--background) 14%, var(--foreground)); border-radius: var(--radius-control); background: var(--foreground); color: var(--background); box-shadow: var(--shadow-raised); font-size: var(--text-sm); font-weight: 400; line-height: var(--leading-body); transform-origin: var(--radix-tooltip-content-transform-origin); transition: opacity var(--duration-fast) var(--ease-enter), transform var(--duration-fast) var(--ease-enter); }
2
+ .tooltip[data-side="bottom"] { --tooltip-y: -3px; }
3
+ /* The first tooltip waits, then rises a few pixels from its trigger. Within the skip window the next one only fades.
4
+ Transitions instead of keyframes, so returning to the trigger while it fades out reverses the fade instead of restarting it. */
5
+ @starting-style {
6
+ .tooltip[data-state$="-open"] { opacity: 0; transform: translateY(var(--tooltip-y)) scale(.97); }
7
+ .tooltip[data-instant][data-state$="-open"] { transform: none; }
8
+ }
9
+ .tooltip[data-instant][data-state$="-open"] { transition: opacity var(--duration-instant) var(--ease-standard), transform var(--duration-instant) var(--ease-standard); }
10
+ /* Radix unmounts when the exit animation ends, so a no-op keyframe times the exit while the transition does the visual work. */
11
+ .tooltip[data-state="closed"] { opacity: 0; transform: scale(.98); transition: opacity var(--duration-instant) var(--ease-standard), transform var(--duration-instant) var(--ease-standard); animation: tooltip-exit var(--duration-instant) linear both; }
12
+ .text { position: relative; display: block; overflow: clip; overflow-clip-margin: var(--space-related); }
13
+ .measure { position: absolute; top: 0; left: 0; width: max-content; max-width: calc(15rem - 2 * var(--space-inset) - 2px); visibility: hidden; pointer-events: none; }
14
+ .line { display: block; width: max-content; max-width: calc(15rem - 2 * var(--space-inset) - 2px); }
15
+ @keyframes tooltip-exit { to { --tooltip-exit: 1; } }
16
+ @media (prefers-reduced-motion: reduce) {
17
+ .tooltip, .tooltip[data-state="closed"], .tooltip[data-instant][data-state$="-open"] { transform: none; transition: opacity var(--duration-instant) var(--ease-standard); }
18
+ }
@@ -0,0 +1,17 @@
1
+ import type { ReactNode } from "react";
2
+ export interface TreeNode {
3
+ id: string;
4
+ label: string;
5
+ children?: TreeNode[];
6
+ icon?: ReactNode;
7
+ }
8
+ export interface TreeViewProps {
9
+ nodes: TreeNode[];
10
+ defaultExpandedIds?: string[];
11
+ expandedIds?: string[];
12
+ onExpandedChange?: (expandedIds: string[]) => void;
13
+ onSelect?: (node: TreeNode) => void;
14
+ "aria-label"?: string;
15
+ }
16
+ export declare function TreeView({ nodes, defaultExpandedIds, expandedIds, onExpandedChange, onSelect, "aria-label": ariaLabel }: TreeViewProps): import("react").JSX.Element;
17
+ export default TreeView;
@@ -0,0 +1,147 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId, useRef, useState } from "react";
4
+ import { ChevronRight, File, Folder, FolderOpen } from "lucide-react";
5
+ import { AnimatePresence, motion, useIsPresent, useReducedMotion } from "motion/react";
6
+ import { motionTokens } from "../../lib/motion-tokens.js";
7
+ import styles from "./tree-view.module.css";
8
+ /** A row is 36px plus the 2px gap above it; both collapse together, so nothing snaps when a row leaves. */
9
+ const rowHeight = 38;
10
+ const still = { duration: 0 };
11
+ const fadeIn = { duration: motionTokens.duration.fast, ease: [...motionTokens.ease.enter] };
12
+ const fadeOut = { duration: motionTokens.duration.instant, ease: [...motionTokens.ease.standard] };
13
+ const blur = (px) => `blur(${px}px)`;
14
+ function flatten(nodes, expanded, depth = 1, parentId) {
15
+ return nodes.flatMap((node, index) => [
16
+ { node, depth, parentId, position: index + 1, setSize: nodes.length },
17
+ ...(node.children && expanded.has(node.id) ? flatten(node.children, expanded, depth + 1, node.id) : []),
18
+ ]);
19
+ }
20
+ function fileTone(label, classNames) {
21
+ const name = label.toLowerCase();
22
+ if (name.endsWith(".tsx") || name.endsWith(".ts"))
23
+ return classNames.typescript;
24
+ if (name.endsWith(".css"))
25
+ return classNames.stylesheet;
26
+ if (name.endsWith(".md"))
27
+ return classNames.markdown;
28
+ if (name.endsWith(".json"))
29
+ return classNames.json;
30
+ return classNames.file;
31
+ }
32
+ /** Same markup with or without reduced motion, so the server render always hydrates cleanly; only the transition changes. */
33
+ function FolderIcon({ open, reduced }) {
34
+ return _jsx(AnimatePresence, { initial: false, mode: "popLayout", children: _jsx(motion.span, { className: styles.folderGlyph, initial: reduced ? false : { opacity: 0, scale: .6, filter: blur(motionTokens.blur.subtle) }, animate: { opacity: 1, scale: 1, filter: blur(0) }, exit: reduced ? { opacity: 0, transition: still } : { opacity: 0, scale: .6, filter: blur(motionTokens.blur.subtle), transition: fadeOut }, transition: reduced ? still : { ...motionTokens.spring.snappy, opacity: fadeIn, filter: fadeIn }, children: open ? _jsx(FolderOpen, { size: 16, strokeWidth: 1.7 }) : _jsx(Folder, { size: 16, strokeWidth: 1.7 }) }, open ? "open" : "closed") });
35
+ }
36
+ /**
37
+ * The selection fill glides between rows through a shared layoutId. A row that is leaving drops its fill at once: left
38
+ * in place, it held the row's exit open, so the row stayed in the tree with pointer events off and the next click on it
39
+ * after reopening its folder did nothing.
40
+ */
41
+ function Selection({ layoutId, reduced }) {
42
+ const present = useIsPresent();
43
+ if (!present)
44
+ return null;
45
+ return _jsx(motion.span, { "aria-hidden": "true", layoutId: layoutId, className: styles.selection, transition: reduced ? still : motionTokens.spring.morph });
46
+ }
47
+ export function TreeView({ nodes, defaultExpandedIds = [], expandedIds, onExpandedChange, onSelect, "aria-label": ariaLabel = "File tree" }) {
48
+ const reduced = useReducedMotion() ?? false;
49
+ const selectionLayoutId = `tree-selection-${useId()}`;
50
+ const [internalExpanded, setInternalExpanded] = useState(() => new Set(defaultExpandedIds));
51
+ const [focusedId, setFocusedId] = useState(nodes[0]?.id ?? null);
52
+ const [selectedId, setSelectedId] = useState(null);
53
+ /** The folder that opened last; its new children fade in one after another, then everything else stays still. */
54
+ const [openedId, setOpenedId] = useState(null);
55
+ const refs = useRef(new Map());
56
+ const expanded = expandedIds ? new Set(expandedIds) : internalExpanded;
57
+ const visible = flatten(nodes, expanded);
58
+ const focusableId = visible.some(({ node }) => node.id === focusedId) ? focusedId : (visible[0]?.node.id ?? null);
59
+ const openedIndex = visible.findIndex(({ node }) => node.id === openedId);
60
+ function setExpanded(next) {
61
+ if (!expandedIds)
62
+ setInternalExpanded(next);
63
+ onExpandedChange?.([...next]);
64
+ }
65
+ function toggle(node) {
66
+ if (!node.children?.length)
67
+ return;
68
+ const next = new Set(expanded);
69
+ if (next.has(node.id))
70
+ next.delete(node.id);
71
+ else {
72
+ next.add(node.id);
73
+ setOpenedId(node.id);
74
+ }
75
+ setExpanded(next);
76
+ }
77
+ function focus(id) {
78
+ setFocusedId(id);
79
+ const row = refs.current.get(id);
80
+ if (row)
81
+ row.focus();
82
+ else
83
+ requestAnimationFrame(() => refs.current.get(id)?.focus());
84
+ }
85
+ function select(node) {
86
+ setSelectedId(node.id);
87
+ onSelect?.(node);
88
+ }
89
+ function onKeyDown(event, item, index) {
90
+ const { node } = item;
91
+ if (event.key === "ArrowDown") {
92
+ event.preventDefault();
93
+ focus(visible[Math.min(index + 1, visible.length - 1)].node.id);
94
+ return;
95
+ }
96
+ if (event.key === "ArrowUp") {
97
+ event.preventDefault();
98
+ focus(visible[Math.max(index - 1, 0)].node.id);
99
+ return;
100
+ }
101
+ if (event.key === "Home") {
102
+ event.preventDefault();
103
+ focus(visible[0].node.id);
104
+ return;
105
+ }
106
+ if (event.key === "End") {
107
+ event.preventDefault();
108
+ focus(visible[visible.length - 1].node.id);
109
+ return;
110
+ }
111
+ if (event.key === "ArrowRight" && node.children?.length) {
112
+ event.preventDefault();
113
+ if (!expanded.has(node.id))
114
+ toggle(node);
115
+ else if (visible[index + 1]?.parentId === node.id)
116
+ focus(visible[index + 1].node.id);
117
+ return;
118
+ }
119
+ if (event.key === "ArrowLeft") {
120
+ event.preventDefault();
121
+ if (node.children?.length && expanded.has(node.id))
122
+ toggle(node);
123
+ else if (item.parentId)
124
+ focus(item.parentId);
125
+ return;
126
+ }
127
+ if (event.key === "Enter" || event.key === " ") {
128
+ event.preventDefault();
129
+ select(node);
130
+ if (node.children?.length)
131
+ toggle(node);
132
+ }
133
+ }
134
+ return _jsx("div", { className: styles.tree, role: "tree", "aria-label": ariaLabel, "aria-multiselectable": "false", children: _jsx(AnimatePresence, { initial: false, mode: "sync", children: visible.map((item, index) => {
135
+ const hasChildren = Boolean(item.node.children?.length);
136
+ const isExpanded = hasChildren && expanded.has(item.node.id);
137
+ const isSelected = selectedId === item.node.id;
138
+ // Only rows that mount use this delay: the space opens in one motion and the new children follow in order.
139
+ const delay = openedIndex >= 0 && index > openedIndex ? Math.min(index - openedIndex - 1, 7) * motionTokens.stagger.item : 0;
140
+ return _jsx(motion.div, { className: styles.row, layout: reduced ? false : "position", initial: reduced ? false : { height: 0, opacity: 0, x: -6, overflow: "hidden" }, animate: { height: rowHeight, opacity: 1, x: 0, pointerEvents: "auto", transitionEnd: { overflow: "visible" }, transition: reduced ? still : { height: motionTokens.spring.smooth, opacity: { ...fadeIn, delay }, x: { ...motionTokens.spring.smooth, delay } } }, exit: reduced ? { opacity: 0, transition: still } : { height: 0, opacity: 0, x: -4, overflow: "hidden", pointerEvents: "none", transition: { height: motionTokens.spring.smooth, opacity: fadeOut, x: fadeOut } }, transition: reduced ? still : { layout: motionTokens.spring.smooth }, children: _jsxs("button", { ref: element => { if (element)
141
+ refs.current.set(item.node.id, element);
142
+ else
143
+ refs.current.delete(item.node.id); }, type: "button", className: styles.item, role: "treeitem", "aria-level": item.depth, "aria-posinset": item.position, "aria-setsize": item.setSize, "aria-expanded": hasChildren ? isExpanded : undefined, "aria-selected": isSelected, tabIndex: focusableId === item.node.id ? 0 : -1, style: { "--tree-depth": item.depth }, onFocus: () => setFocusedId(item.node.id), onKeyDown: event => onKeyDown(event, item, index), onClick: () => { setFocusedId(item.node.id); select(item.node); if (hasChildren)
144
+ toggle(item.node); }, children: [isSelected && _jsx(Selection, { layoutId: selectionLayoutId, reduced: reduced }), item.depth > 1 && _jsx(motion.span, { "aria-hidden": "true", className: styles.branch, initial: reduced ? false : { opacity: 0, scaleY: 0 }, animate: { opacity: 1, scaleY: 1 }, transition: reduced ? still : { duration: motionTokens.duration.standard, ease: [...motionTokens.ease.enter], delay } }), _jsx(motion.span, { className: styles.disclosure, "aria-hidden": "true", initial: false, animate: { rotate: isExpanded ? 90 : 0 }, transition: reduced ? still : motionTokens.spring.snappy, children: hasChildren ? _jsx(ChevronRight, { size: 14, strokeWidth: 1.9 }) : null }), _jsx("span", { className: [styles.icon, hasChildren ? styles.folder : fileTone(item.node.label, styles)].join(" "), "aria-hidden": "true", children: item.node.icon ?? (hasChildren ? _jsx(FolderIcon, { open: isExpanded, reduced: reduced }) : _jsx(File, { size: 16, strokeWidth: 1.7 })) }), _jsx("span", { className: styles.label, children: item.node.label })] }) }, item.node.id);
145
+ }) }) });
146
+ }
147
+ export default TreeView;
@@ -0,0 +1,22 @@
1
+ .tree { display: block; width: 100%; min-width: 0; box-sizing: border-box; padding: 6px 8px 8px; border: 1px solid var(--border); border-radius: var(--radius-control); background: var(--surface); color: var(--foreground); overflow: hidden; }
2
+ /* Rows clip only while their height animates (Motion sets overflow), so the selection can glide between them unclipped. */
3
+ .row { position: relative; display: flow-root; min-width: 0; height: 38px; }
4
+ .item { position: relative; display: flex; width: 100%; min-width: 0; height: 36px; margin-top: 2px; align-items: center; gap: 8px; padding: 0 10px; padding-left: calc(10px + (var(--tree-depth) - 1) * 18px); border: 0; border-radius: var(--radius-detail); background: transparent; color: var(--text-secondary); font: inherit; font-size: var(--text-sm); line-height: 1; text-align: left; cursor: pointer; outline: none; transition: color var(--duration-fast) var(--ease-standard), background-color var(--duration-fast) var(--ease-standard); }
5
+ /* Selection changes color only; a heavier weight would reflow the label. */
6
+ .item[aria-selected="true"] { color: var(--foreground); }
7
+ .selection { position: absolute; inset: 0; z-index: 0; border-radius: var(--radius-detail); background: var(--surface-muted); }
8
+ .branch { position: absolute; top: 4px; bottom: 4px; left: calc(16.5px + (var(--tree-depth) - 2) * 18px); z-index: 1; width: 1px; background: var(--border); transform-origin: top; pointer-events: none; }
9
+ .disclosure, .icon, .label { position: relative; z-index: 1; }
10
+ .disclosure { display: grid; width: 14px; height: 16px; flex: 0 0 14px; place-items: center; color: var(--text-muted); }
11
+ .icon { display: grid; width: 16px; height: 16px; flex: 0 0 16px; place-items: center; color: var(--text-muted); transition: color var(--duration-fast) var(--ease-standard); }
12
+ .folder { color: var(--text-secondary); }
13
+ .item[aria-expanded="true"] .folder, .item[aria-selected="true"] .folder { color: var(--foreground); }
14
+ .folderGlyph { position: absolute; inset: 0; display: grid; place-items: center; }
15
+ .typescript { color: color-mix(in oklab, #3178c6 78%, var(--foreground)); }
16
+ .stylesheet { color: color-mix(in oklab, #8b6ace 73%, var(--foreground)); }
17
+ .markdown { color: color-mix(in oklab, #38896b 74%, var(--foreground)); }
18
+ .json { color: color-mix(in oklab, #c48637 78%, var(--foreground)); }
19
+ /* Its own line height: the row sets 1, and the clipped box (needed for the ellipsis) would cut descenders like g. */
20
+ .label { min-width: 0; overflow: hidden; line-height: 1.45; text-overflow: ellipsis; white-space: nowrap; }
21
+ @media (hover: hover) and (pointer: fine) { .item:hover { background: var(--surface-muted); color: var(--foreground); } }
22
+ @media (prefers-reduced-motion: reduce) { .item, .icon { transition: none; } }
@@ -0,0 +1,35 @@
1
+ import { type Ref } from "react";
2
+ export interface TreemapNode {
3
+ /** Stable identity, unique in the tree. A tile that survives a data change morphs to its new size. */
4
+ id: string;
5
+ label: string;
6
+ /** Leaf size. A branch's size is the sum of its children. */
7
+ value?: number;
8
+ /** Optional second measure for shading, such as growth. A branch uses the size weighted mean of its children. */
9
+ color?: number;
10
+ children?: TreemapNode[];
11
+ }
12
+ /** Use a treemap for a hierarchy of parts, such as revenue by region, country, and plan, when sizes matter more than exact comparisons. */
13
+ export interface TreemapProps {
14
+ /** The root. Its label names the whole in the first breadcrumb. */
15
+ data: TreemapNode;
16
+ /** What the whole is, such as "Revenue". Names the chart for assistive technology. */
17
+ label: string;
18
+ formatValue?: (value: number) => string;
19
+ /** Names the shading measure in the tooltip and scale, such as "Growth". Tiles take the hue of their top level branch and grow deeper with the measure. Leave it out to draw every tile at one depth. */
20
+ colorLabel?: string;
21
+ formatColor?: (value: number) => string;
22
+ /** Range of the color measure. Defaults to the range of the leaves. */
23
+ colorDomain?: [number, number];
24
+ /** Controlled id of the node that fills the view. */
25
+ focus?: string;
26
+ defaultFocus?: string;
27
+ onFocusChange?: (id: string) => void;
28
+ /** Height of the tiles in pixels. */
29
+ height?: number;
30
+ emptyLabel?: string;
31
+ ref?: Ref<HTMLElement>;
32
+ className?: string;
33
+ }
34
+ export declare function Treemap({ data, label, formatValue, colorLabel, formatColor, colorDomain, focus, defaultFocus, onFocusChange, height, emptyLabel, ref, className }: TreemapProps): import("react").JSX.Element;
35
+ export default Treemap;