@sableui/react 0.6.1 → 0.7.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 (633) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +285 -0
  3. package/CONTRIBUTING.md +16 -10
  4. package/DESIGN.md +3 -3
  5. package/README.md +3 -3
  6. package/bin/sable-lint.mjs +18 -0
  7. package/bin/sable.mjs +470 -62
  8. package/dist/blocks/api-keys-block.js +44 -0
  9. package/dist/blocks/api-keys-block.meta.js +21 -0
  10. package/dist/blocks/chat-thread-block.js +17 -0
  11. package/dist/blocks/chat-thread-block.meta.js +20 -0
  12. package/dist/blocks/command-palette-block.js +24 -0
  13. package/dist/blocks/command-palette-block.meta.js +21 -0
  14. package/dist/blocks/cta-band-block.js +27 -0
  15. package/dist/blocks/cta-band-block.meta.js +20 -0
  16. package/dist/blocks/danger-zone-block.js +39 -0
  17. package/dist/blocks/danger-zone-block.meta.js +21 -0
  18. package/dist/blocks/device-comparison-block.js +69 -0
  19. package/dist/blocks/device-comparison-block.meta.js +21 -0
  20. package/dist/blocks/event-card-block.js +40 -0
  21. package/dist/blocks/event-card-block.meta.js +21 -0
  22. package/dist/blocks/faq-block.js +38 -0
  23. package/dist/blocks/faq-block.meta.js +20 -0
  24. package/dist/blocks/feature-grid-block.js +38 -0
  25. package/dist/blocks/feature-grid-block.meta.js +21 -0
  26. package/dist/blocks/feedback-form-block.js +30 -0
  27. package/dist/blocks/feedback-form-block.meta.js +21 -0
  28. package/dist/blocks/goal-progress-block.js +24 -0
  29. package/dist/blocks/goal-progress-block.meta.js +21 -0
  30. package/dist/blocks/hero-block.js +33 -0
  31. package/dist/blocks/hero-block.meta.js +21 -0
  32. package/dist/blocks/index.js +162 -1964
  33. package/dist/blocks/invite-team-block.js +36 -0
  34. package/dist/blocks/invite-team-block.meta.js +20 -0
  35. package/dist/blocks/invoice-history-block.js +41 -0
  36. package/dist/blocks/invoice-history-block.meta.js +21 -0
  37. package/dist/blocks/kpi-sparkline-block.js +29 -0
  38. package/dist/blocks/kpi-sparkline-block.meta.js +20 -0
  39. package/dist/blocks/media-player-block.js +68 -0
  40. package/dist/blocks/media-player-block.meta.js +21 -0
  41. package/dist/blocks/newsletter-block.js +35 -0
  42. package/dist/blocks/newsletter-block.meta.js +21 -0
  43. package/dist/blocks/not-found-block.js +27 -0
  44. package/dist/blocks/not-found-block.meta.js +20 -0
  45. package/dist/blocks/notification-list-block.js +32 -0
  46. package/dist/blocks/notification-list-block.meta.js +21 -0
  47. package/dist/blocks/notification-settings-block.js +25 -0
  48. package/dist/blocks/notification-settings-block.meta.js +20 -0
  49. package/dist/blocks/order-tracking-block.js +26 -0
  50. package/dist/blocks/order-tracking-block.meta.js +20 -0
  51. package/dist/blocks/pricing-card-block.js +46 -0
  52. package/dist/blocks/pricing-card-block.meta.js +21 -0
  53. package/dist/blocks/pricing-table-block.js +88 -0
  54. package/dist/blocks/pricing-table-block.meta.js +20 -0
  55. package/dist/blocks/product-card-block.js +26 -0
  56. package/dist/blocks/product-card-block.meta.js +21 -0
  57. package/dist/blocks/profile-card-block.js +58 -0
  58. package/dist/blocks/profile-card-block.meta.js +21 -0
  59. package/dist/blocks/profile-form-block.js +70 -0
  60. package/dist/blocks/profile-form-block.meta.js +21 -0
  61. package/dist/blocks/revenue-breakdown-block.js +38 -0
  62. package/dist/blocks/revenue-breakdown-block.meta.js +21 -0
  63. package/dist/blocks/sign-in-block.js +38 -0
  64. package/dist/blocks/sign-in-block.meta.js +21 -0
  65. package/dist/blocks/sign-up-block.js +48 -0
  66. package/dist/blocks/sign-up-block.meta.js +21 -0
  67. package/dist/blocks/site-footer-block.js +54 -0
  68. package/dist/blocks/site-footer-block.meta.js +20 -0
  69. package/dist/blocks/stat-row-block.js +28 -0
  70. package/dist/blocks/stat-row-block.meta.js +21 -0
  71. package/dist/blocks/steps-block.js +37 -0
  72. package/dist/blocks/steps-block.meta.js +20 -0
  73. package/dist/blocks/task-list-block.js +52 -0
  74. package/dist/blocks/task-list-block.meta.js +21 -0
  75. package/dist/blocks/team-members-block.js +49 -0
  76. package/dist/blocks/team-members-block.meta.js +21 -0
  77. package/dist/blocks/testimonial-block.js +49 -0
  78. package/dist/blocks/testimonial-block.meta.js +20 -0
  79. package/dist/blocks/traffic-sources-block.js +39 -0
  80. package/dist/blocks/traffic-sources-block.meta.js +21 -0
  81. package/dist/blocks/traffic-trend-block.js +61 -0
  82. package/dist/blocks/traffic-trend-block.meta.js +21 -0
  83. package/dist/blocks/upload-list-block.js +39 -0
  84. package/dist/blocks/upload-list-block.meta.js +21 -0
  85. package/dist/blocks/verify-code-block.js +28 -0
  86. package/dist/blocks/verify-code-block.meta.js +21 -0
  87. package/dist/blocks/wallet-block.js +48 -0
  88. package/dist/blocks/wallet-block.meta.js +21 -0
  89. package/dist/components/accordion/accordion.js +63 -0
  90. package/dist/components/accordion/accordion.meta.js +155 -0
  91. package/dist/components/accordion/index.js +15 -0
  92. package/dist/components/app-header/app-header.js +30 -0
  93. package/dist/components/app-header/app-header.meta.js +88 -0
  94. package/dist/components/app-header/index.js +7 -0
  95. package/dist/components/app-shell/app-shell-dock.js +37 -0
  96. package/dist/components/app-shell/app-shell.js +67 -0
  97. package/dist/components/app-shell/app-shell.meta.js +176 -0
  98. package/dist/components/app-shell/index.js +7 -0
  99. package/dist/components/area-chart/area-chart.js +10 -0
  100. package/dist/components/area-chart/area-chart.meta.js +218 -0
  101. package/dist/components/area-chart/index.js +7 -0
  102. package/dist/components/attachment/attachment.js +176 -0
  103. package/dist/components/attachment/attachment.meta.js +179 -0
  104. package/dist/components/attachment/attachment.variants.js +47 -0
  105. package/dist/components/attachment/index.js +7 -0
  106. package/dist/components/avatar/avatar.js +192 -0
  107. package/dist/components/avatar/avatar.meta.js +233 -0
  108. package/dist/components/avatar/avatar.variants.js +44 -0
  109. package/dist/components/avatar/index.js +22 -0
  110. package/dist/components/badge/badge.js +26 -0
  111. package/dist/components/badge/badge.meta.js +171 -0
  112. package/dist/components/badge/badge.variants.js +103 -0
  113. package/dist/components/badge/index.js +11 -0
  114. package/dist/components/banner/banner.js +76 -0
  115. package/dist/components/banner/banner.meta.js +172 -0
  116. package/dist/components/banner/banner.variants.js +44 -0
  117. package/dist/components/banner/index.js +9 -0
  118. package/dist/components/bar-chart/bar-chart.js +10 -0
  119. package/dist/components/bar-chart/bar-chart.meta.js +245 -0
  120. package/dist/components/bar-chart/index.js +7 -0
  121. package/dist/components/bottom-nav/bottom-nav.js +63 -0
  122. package/dist/components/bottom-nav/bottom-nav.meta.js +95 -0
  123. package/dist/components/bottom-nav/index.js +11 -0
  124. package/dist/components/breadcrumbs/breadcrumbs.js +90 -0
  125. package/dist/components/breadcrumbs/breadcrumbs.meta.js +111 -0
  126. package/dist/components/breadcrumbs/index.js +17 -0
  127. package/dist/components/browser/browser.js +39 -0
  128. package/dist/components/browser/browser.meta.js +80 -0
  129. package/dist/components/browser/index.js +7 -0
  130. package/dist/components/bubble/bubble.js +110 -0
  131. package/dist/components/bubble/bubble.meta.js +158 -0
  132. package/dist/components/bubble/bubble.variants.js +90 -0
  133. package/dist/components/bubble/index.js +13 -0
  134. package/dist/components/button/button.js +87 -0
  135. package/dist/components/button/button.meta.js +302 -0
  136. package/dist/components/button/button.variants.js +137 -0
  137. package/dist/components/button/index.js +9 -0
  138. package/dist/components/calendar/calendar.js +89 -0
  139. package/dist/components/calendar/calendar.meta.js +136 -0
  140. package/dist/components/calendar/index.js +7 -0
  141. package/dist/components/card/card.js +200 -0
  142. package/dist/components/card/card.meta.js +212 -0
  143. package/dist/components/card/index.js +23 -0
  144. package/dist/components/carousel/carousel.js +428 -0
  145. package/dist/components/carousel/carousel.meta.js +100 -0
  146. package/dist/components/carousel/index.js +7 -0
  147. package/dist/components/chat-composer/chat-composer.js +174 -0
  148. package/dist/components/chat-composer/chat-composer.meta.js +241 -0
  149. package/dist/components/chat-composer/chat-composer.variants.js +17 -0
  150. package/dist/components/chat-composer/index.js +7 -0
  151. package/dist/components/checkbox/checkbox-mark.js +28 -0
  152. package/dist/components/checkbox/checkbox.js +30 -0
  153. package/dist/components/checkbox/checkbox.meta.js +127 -0
  154. package/dist/components/checkbox/index.js +7 -0
  155. package/dist/components/checkbox-card/checkbox-card.js +94 -0
  156. package/dist/components/checkbox-card/checkbox-card.meta.js +154 -0
  157. package/dist/components/checkbox-card/checkbox-card.variants.js +43 -0
  158. package/dist/components/checkbox-card/index.js +11 -0
  159. package/dist/components/code/code.js +19 -0
  160. package/dist/components/code/code.meta.js +71 -0
  161. package/dist/components/code/index.js +7 -0
  162. package/dist/components/code-block/code-block.js +84 -0
  163. package/dist/components/code-block/code-block.meta.js +103 -0
  164. package/dist/components/code-block/index.js +8 -0
  165. package/dist/components/collapsible/collapsible.js +38 -0
  166. package/dist/components/collapsible/collapsible.meta.js +117 -0
  167. package/dist/components/collapsible/index.js +15 -0
  168. package/dist/components/color-field/color-field.js +293 -0
  169. package/dist/components/color-field/color-field.meta.js +142 -0
  170. package/dist/components/color-field/color.js +69 -0
  171. package/dist/components/color-field/index.js +15 -0
  172. package/dist/components/combobox/combobox.js +486 -0
  173. package/dist/components/combobox/combobox.meta.js +217 -0
  174. package/dist/components/combobox/index.js +37 -0
  175. package/dist/components/command-menu/command-menu-trigger.js +122 -0
  176. package/dist/components/command-menu/command-menu.js +433 -0
  177. package/dist/components/command-menu/command-menu.meta.js +279 -0
  178. package/dist/components/command-menu/index.js +21 -0
  179. package/dist/components/context-card/context-card.js +62 -0
  180. package/dist/components/context-card/context-card.meta.js +106 -0
  181. package/dist/components/context-card/index.js +17 -0
  182. package/dist/components/context-menu/context-menu.js +92 -0
  183. package/dist/components/context-menu/context-menu.meta.js +138 -0
  184. package/dist/components/context-menu/index.js +23 -0
  185. package/dist/components/data-table/data-table.js +142 -0
  186. package/dist/components/data-table/data-table.meta.js +146 -0
  187. package/dist/components/data-table/index.js +9 -0
  188. package/dist/components/date-picker/date-picker.js +196 -0
  189. package/dist/components/date-picker/date-picker.meta.js +164 -0
  190. package/dist/components/date-picker/index.js +7 -0
  191. package/dist/components/date-tile/date-tile.js +29 -0
  192. package/dist/components/date-tile/date-tile.meta.js +72 -0
  193. package/dist/components/date-tile/index.js +7 -0
  194. package/dist/components/destructive-action-modal/destructive-action-modal.js +130 -0
  195. package/dist/components/destructive-action-modal/destructive-action-modal.meta.js +136 -0
  196. package/dist/components/destructive-action-modal/index.js +9 -0
  197. package/dist/components/dialog/dialog.js +207 -0
  198. package/dist/components/dialog/dialog.meta.js +239 -0
  199. package/dist/components/dialog/index.js +45 -0
  200. package/dist/components/disclosure-picker/disclosure-picker.js +417 -0
  201. package/dist/components/disclosure-picker/disclosure-picker.meta.js +213 -0
  202. package/dist/components/disclosure-picker/index.js +21 -0
  203. package/dist/components/empty-state/empty-state.js +52 -0
  204. package/dist/components/empty-state/empty-state.meta.js +158 -0
  205. package/dist/components/empty-state/index.js +7 -0
  206. package/dist/components/entity/entity.js +70 -0
  207. package/dist/components/entity/entity.meta.js +108 -0
  208. package/dist/components/entity/entity.variants.js +16 -0
  209. package/dist/components/entity/index.js +7 -0
  210. package/dist/components/feedback/feedback.js +93 -0
  211. package/dist/components/feedback/feedback.meta.js +109 -0
  212. package/dist/components/feedback/index.js +7 -0
  213. package/dist/components/fieldset/fieldset.js +80 -0
  214. package/dist/components/fieldset/fieldset.meta.js +160 -0
  215. package/dist/components/fieldset/index.js +17 -0
  216. package/dist/components/file-dropzone/file-dropzone.js +193 -0
  217. package/dist/components/file-dropzone/file-dropzone.meta.js +210 -0
  218. package/dist/components/file-dropzone/file-dropzone.variants.js +26 -0
  219. package/dist/components/file-dropzone/index.js +13 -0
  220. package/dist/components/font-picker/font-picker.js +77 -0
  221. package/dist/components/font-picker/font-picker.meta.js +119 -0
  222. package/dist/components/font-picker/index.js +7 -0
  223. package/dist/components/form/form.js +145 -0
  224. package/dist/components/form/form.meta.js +142 -0
  225. package/dist/components/form/index.js +11 -0
  226. package/dist/components/gliding-highlight/gliding-highlight.js +50 -0
  227. package/dist/components/gliding-highlight/gliding-highlight.meta.js +135 -0
  228. package/dist/components/gliding-highlight/index.js +9 -0
  229. package/dist/components/gradient-art/gradient-art.js +168 -0
  230. package/dist/components/gradient-art/gradient-art.meta.js +81 -0
  231. package/dist/components/gradient-art/index.js +7 -0
  232. package/dist/components/gradient-art/renderer.js +336 -0
  233. package/dist/components/inline-status/index.js +7 -0
  234. package/dist/components/inline-status/inline-status.js +33 -0
  235. package/dist/components/inline-status/inline-status.meta.js +83 -0
  236. package/dist/components/inline-status/inline-status.variants.js +18 -0
  237. package/dist/components/input/index.js +7 -0
  238. package/dist/components/input/input.js +33 -0
  239. package/dist/components/input/input.meta.js +155 -0
  240. package/dist/components/kbd/index.js +8 -0
  241. package/dist/components/kbd/kbd.js +54 -0
  242. package/dist/components/kbd/kbd.meta.js +95 -0
  243. package/dist/components/label/index.js +7 -0
  244. package/dist/components/label/label.js +51 -0
  245. package/dist/components/label/label.meta.js +98 -0
  246. package/dist/components/line-chart/index.js +7 -0
  247. package/dist/components/line-chart/line-chart.js +10 -0
  248. package/dist/components/line-chart/line-chart.meta.js +222 -0
  249. package/dist/components/marker/index.js +7 -0
  250. package/dist/components/marker/marker.js +39 -0
  251. package/dist/components/marker/marker.meta.js +132 -0
  252. package/dist/components/marker/marker.variants.js +25 -0
  253. package/dist/components/marquee/index.js +7 -0
  254. package/dist/components/marquee/marquee.js +146 -0
  255. package/dist/components/marquee/marquee.meta.js +106 -0
  256. package/dist/components/media-image/index.js +7 -0
  257. package/dist/components/media-image/media-image.js +56 -0
  258. package/dist/components/media-image/media-image.meta.js +92 -0
  259. package/dist/components/media-tile/index.js +7 -0
  260. package/dist/components/media-tile/media-tile.js +135 -0
  261. package/dist/components/media-tile/media-tile.meta.js +133 -0
  262. package/dist/components/media-tile/media-tile.variants.js +48 -0
  263. package/dist/components/menu/index.js +33 -0
  264. package/dist/components/menu/menu.js +168 -0
  265. package/dist/components/menu/menu.meta.js +176 -0
  266. package/dist/components/message/index.js +7 -0
  267. package/dist/components/message/message.js +83 -0
  268. package/dist/components/message/message.meta.js +150 -0
  269. package/dist/components/message/message.variants.js +41 -0
  270. package/dist/components/message-scroller/index.js +9 -0
  271. package/dist/components/message-scroller/message-scroller.js +300 -0
  272. package/dist/components/message-scroller/message-scroller.meta.js +172 -0
  273. package/dist/components/meter/index.js +20 -0
  274. package/dist/components/meter/meter.js +112 -0
  275. package/dist/components/meter/meter.meta.js +227 -0
  276. package/dist/components/meter/meter.variants.js +61 -0
  277. package/dist/components/middle-truncate/index.js +7 -0
  278. package/dist/components/middle-truncate/middle-truncate.js +28 -0
  279. package/dist/components/middle-truncate/middle-truncate.meta.js +77 -0
  280. package/dist/components/note/index.js +9 -0
  281. package/dist/components/note/note.js +73 -0
  282. package/dist/components/note/note.meta.js +112 -0
  283. package/dist/components/note/note.variants.js +22 -0
  284. package/dist/components/notification-badge/index.js +15 -0
  285. package/dist/components/notification-badge/notification-badge.js +48 -0
  286. package/dist/components/notification-badge/notification-badge.meta.js +107 -0
  287. package/dist/components/notification-badge/notification-badge.variants.js +57 -0
  288. package/dist/components/number-field/index.js +7 -0
  289. package/dist/components/number-field/number-field.js +70 -0
  290. package/dist/components/number-field/number-field.meta.js +109 -0
  291. package/dist/components/otp-field/index.js +7 -0
  292. package/dist/components/otp-field/otp-field.js +70 -0
  293. package/dist/components/otp-field/otp-field.meta.js +197 -0
  294. package/dist/components/overflow-menu/index.js +7 -0
  295. package/dist/components/overflow-menu/overflow-menu.js +26 -0
  296. package/dist/components/overflow-menu/overflow-menu.meta.js +100 -0
  297. package/dist/components/page-header/index.js +7 -0
  298. package/dist/components/page-header/page-header.js +34 -0
  299. package/dist/components/page-header/page-header.meta.js +104 -0
  300. package/dist/components/page-loader/index.js +7 -0
  301. package/dist/components/page-loader/page-loader.js +37 -0
  302. package/dist/components/page-loader/page-loader.meta.js +85 -0
  303. package/dist/components/pagination/index.js +7 -0
  304. package/dist/components/pagination/pagination.js +105 -0
  305. package/dist/components/pagination/pagination.meta.js +141 -0
  306. package/dist/components/panel-group/index.js +10 -0
  307. package/dist/components/panel-group/panel-group.js +168 -0
  308. package/dist/components/panel-group/panel-group.meta.js +153 -0
  309. package/dist/components/panel-section/index.js +9 -0
  310. package/dist/components/panel-section/panel-section.js +115 -0
  311. package/dist/components/panel-section/panel-section.meta.js +156 -0
  312. package/dist/components/phone/index.js +7 -0
  313. package/dist/components/phone/phone.js +50 -0
  314. package/dist/{chunk-KFZ43RKU.js → components/phone/phone.meta.js} +3 -50
  315. package/dist/{chunk-NEQNXI2G.js → components/phone/status-icons.js} +4 -4
  316. package/dist/components/pie-chart/index.js +7 -0
  317. package/dist/components/pie-chart/pie-chart.js +191 -0
  318. package/dist/components/pie-chart/pie-chart.meta.js +210 -0
  319. package/dist/components/pill/index.js +9 -0
  320. package/dist/components/pill/pill.js +24 -0
  321. package/dist/components/pill/pill.meta.js +108 -0
  322. package/dist/components/pill/pill.variants.js +65 -0
  323. package/dist/components/popover/index.js +23 -0
  324. package/dist/components/popover/popover.js +100 -0
  325. package/dist/components/popover/popover.meta.js +136 -0
  326. package/dist/components/progress/index.js +19 -0
  327. package/dist/components/progress/progress.js +70 -0
  328. package/dist/components/progress/progress.meta.js +171 -0
  329. package/dist/components/progress/progress.variants.js +17 -0
  330. package/dist/components/radar-chart/index.js +7 -0
  331. package/dist/components/radar-chart/radar-chart.js +161 -0
  332. package/dist/components/radar-chart/radar-chart.meta.js +204 -0
  333. package/dist/components/radial-chart/index.js +7 -0
  334. package/dist/components/radial-chart/radial-chart.js +175 -0
  335. package/dist/components/radial-chart/radial-chart.meta.js +216 -0
  336. package/dist/components/radio/index.js +8 -0
  337. package/dist/components/radio/radio.js +39 -0
  338. package/dist/components/radio/radio.meta.js +104 -0
  339. package/dist/components/radio-card/index.js +7 -0
  340. package/dist/components/radio-card/radio-card.js +81 -0
  341. package/dist/components/radio-card/radio-card.meta.js +144 -0
  342. package/dist/components/radio-card/radio-card.variants.js +43 -0
  343. package/dist/components/relative-time/index.js +7 -0
  344. package/dist/components/relative-time/relative-time.js +47 -0
  345. package/dist/components/relative-time/relative-time.meta.js +77 -0
  346. package/dist/components/scroller/index.js +7 -0
  347. package/dist/components/scroller/scroller.js +111 -0
  348. package/dist/components/scroller/scroller.meta.js +118 -0
  349. package/dist/components/scrub-field/index.js +7 -0
  350. package/dist/components/scrub-field/scrub-field.js +124 -0
  351. package/dist/components/scrub-field/scrub-field.meta.js +139 -0
  352. package/dist/components/search-input/index.js +7 -0
  353. package/dist/components/search-input/search-input.js +91 -0
  354. package/dist/components/search-input/search-input.meta.js +129 -0
  355. package/dist/components/section-header/index.js +7 -0
  356. package/dist/components/section-header/section-header.js +39 -0
  357. package/dist/components/section-header/section-header.meta.js +174 -0
  358. package/dist/components/segmented-bar/index.js +14 -0
  359. package/dist/components/segmented-bar/segmented-bar.js +26 -0
  360. package/dist/components/segmented-bar/segmented-bar.meta.js +108 -0
  361. package/dist/components/segmented-bar/segmented-bar.variants.js +39 -0
  362. package/dist/components/select/index.js +25 -0
  363. package/dist/components/select/select.js +191 -0
  364. package/dist/components/select/select.meta.js +189 -0
  365. package/dist/components/separator/index.js +7 -0
  366. package/dist/components/separator/separator.js +42 -0
  367. package/dist/components/separator/separator.meta.js +84 -0
  368. package/dist/components/settings-menu/index.js +11 -0
  369. package/dist/components/settings-menu/settings-menu.js +101 -0
  370. package/dist/components/settings-menu/settings-menu.meta.js +177 -0
  371. package/dist/components/settings-menu/settings-menu.variants.js +15 -0
  372. package/dist/components/sheet/index.js +29 -0
  373. package/dist/components/sheet/sheet.js +121 -0
  374. package/dist/components/sheet/sheet.meta.js +167 -0
  375. package/dist/components/sheet/sheet.variants.js +21 -0
  376. package/dist/components/show-more/index.js +7 -0
  377. package/dist/components/show-more/show-more.js +87 -0
  378. package/dist/components/show-more/show-more.meta.js +79 -0
  379. package/dist/components/side-nav/index.js +13 -0
  380. package/dist/components/side-nav/side-nav.js +75 -0
  381. package/dist/components/side-nav/side-nav.meta.js +139 -0
  382. package/dist/components/side-nav/side-nav.variants.js +33 -0
  383. package/dist/components/sidebar/index.js +21 -0
  384. package/dist/components/sidebar/sidebar.js +196 -0
  385. package/dist/components/sidebar/sidebar.meta.js +118 -0
  386. package/dist/components/skeleton/index.js +7 -0
  387. package/dist/components/skeleton/skeleton.js +16 -0
  388. package/dist/components/skeleton/skeleton.meta.js +90 -0
  389. package/dist/components/slider/index.js +21 -0
  390. package/dist/components/slider/slider.js +115 -0
  391. package/dist/components/slider/slider.meta.js +214 -0
  392. package/dist/components/sparkline/index.js +7 -0
  393. package/dist/components/sparkline/sparkline.js +84 -0
  394. package/dist/components/sparkline/sparkline.meta.js +147 -0
  395. package/dist/components/spinner/index.js +7 -0
  396. package/dist/components/spinner/spinner.js +59 -0
  397. package/dist/components/spinner/spinner.meta.js +118 -0
  398. package/dist/components/status-bar/index.js +9 -0
  399. package/dist/components/status-bar/status-bar.js +40 -0
  400. package/dist/components/status-bar/status-bar.meta.js +117 -0
  401. package/dist/components/status-dot/index.js +9 -0
  402. package/dist/components/status-dot/status-dot.js +40 -0
  403. package/dist/components/status-dot/status-dot.meta.js +113 -0
  404. package/dist/components/status-dot/status-dot.variants.js +28 -0
  405. package/dist/components/stepper/index.js +17 -0
  406. package/dist/components/stepper/stepper.js +161 -0
  407. package/dist/components/stepper/stepper.meta.js +190 -0
  408. package/dist/components/stepper/stepper.variants.js +72 -0
  409. package/dist/components/streaming-text/index.js +7 -0
  410. package/dist/components/streaming-text/streaming-text.js +55 -0
  411. package/dist/components/streaming-text/streaming-text.meta.js +147 -0
  412. package/dist/components/switch/index.js +7 -0
  413. package/dist/components/switch/switch.js +26 -0
  414. package/dist/components/switch/switch.meta.js +133 -0
  415. package/dist/components/table/index.js +23 -0
  416. package/dist/components/table/table.js +117 -0
  417. package/dist/components/table/table.meta.js +143 -0
  418. package/dist/components/tabs/index.js +17 -0
  419. package/dist/components/tabs/tabs.js +58 -0
  420. package/dist/components/tabs/tabs.meta.js +120 -0
  421. package/dist/components/textarea/index.js +7 -0
  422. package/dist/components/textarea/textarea.js +38 -0
  423. package/dist/components/textarea/textarea.meta.js +117 -0
  424. package/dist/components/theme-selector/index.js +11 -0
  425. package/dist/components/theme-selector/theme-selector.js +145 -0
  426. package/dist/components/theme-selector/theme-selector.meta.js +181 -0
  427. package/dist/components/theme-switcher/index.js +7 -0
  428. package/dist/components/theme-switcher/theme-switcher.js +106 -0
  429. package/dist/components/theme-switcher/theme-switcher.meta.js +99 -0
  430. package/dist/components/thinking-orb/index.js +9 -0
  431. package/dist/components/thinking-orb/thinking-orb.js +126 -0
  432. package/dist/components/thinking-orb/thinking-orb.meta.js +142 -0
  433. package/dist/components/thinking-orb/thinking-orb.render.js +252 -0
  434. package/dist/components/toast/index.js +29 -0
  435. package/dist/components/toast/toast.js +254 -0
  436. package/dist/components/toast/toast.meta.js +261 -0
  437. package/dist/components/toggle/index.js +13 -0
  438. package/dist/components/toggle/toggle.js +51 -0
  439. package/dist/components/toggle/toggle.meta.js +129 -0
  440. package/dist/components/toolbar/index.js +27 -0
  441. package/dist/components/toolbar/toolbar.js +80 -0
  442. package/dist/components/toolbar/toolbar.meta.js +272 -0
  443. package/dist/components/toolbar/toolbar.variants.js +16 -0
  444. package/dist/components/tooltip/index.js +21 -0
  445. package/dist/components/tooltip/tooltip.js +74 -0
  446. package/dist/components/tooltip/tooltip.meta.js +156 -0
  447. package/dist/components/tree/index.js +12 -0
  448. package/dist/components/tree/tree.js +364 -0
  449. package/dist/components/tree/tree.meta.js +334 -0
  450. package/dist/components/video/index.js +7 -0
  451. package/dist/components/video/video.js +59 -0
  452. package/dist/components/video/video.meta.js +81 -0
  453. package/dist/components/workspace/index.js +9 -0
  454. package/dist/components/workspace/workspace.js +79 -0
  455. package/dist/components/workspace/workspace.meta.js +183 -0
  456. package/dist/foundations/accessibility.js +107 -0
  457. package/dist/foundations/index.js +25 -792
  458. package/dist/foundations/motion.js +135 -0
  459. package/dist/foundations/scrolling.js +62 -0
  460. package/dist/foundations/shape.js +113 -0
  461. package/dist/foundations/spacing.js +121 -0
  462. package/dist/foundations/surfaces.js +107 -0
  463. package/dist/foundations/types.js +0 -0
  464. package/dist/foundations/typography.js +152 -0
  465. package/dist/icon/Icon.js +30 -0
  466. package/dist/icon/IconProvider.js +27 -0
  467. package/dist/icon/compose.js +13 -0
  468. package/dist/icon/index.d.ts +13 -5
  469. package/dist/icon/index.js +13 -2
  470. package/dist/icon/registry.js +0 -0
  471. package/dist/icon-sets/brands.generated.js +123 -0
  472. package/dist/icon-sets/brands.js +10 -123
  473. package/dist/icon-sets/reicon.d.ts +3 -1
  474. package/dist/icon-sets/reicon.js +209 -1
  475. package/dist/index.d.ts +611 -33
  476. package/dist/index.js +211 -11351
  477. package/dist/ios/chrome.js +36 -0
  478. package/dist/ios/index.js +19 -315
  479. package/dist/ios/liquid-glass.js +103 -0
  480. package/dist/ios/native-app.js +46 -0
  481. package/dist/ios/navigation.js +63 -0
  482. package/dist/ios/phone-frame.js +64 -0
  483. package/dist/ios/preview-theme.js +83 -0
  484. package/dist/ios/preview.js +10 -137
  485. package/dist/ios/sheet.js +85 -0
  486. package/dist/ios/theme.js +19 -0
  487. package/dist/layout/AspectBox.js +27 -0
  488. package/dist/layout/Bleed.js +15 -0
  489. package/dist/layout/Center.js +21 -0
  490. package/dist/layout/Columns.js +70 -0
  491. package/dist/layout/Grid.js +50 -0
  492. package/dist/layout/GridOverlay.js +41 -0
  493. package/dist/layout/Page.js +11 -0
  494. package/dist/layout/Region.js +39 -0
  495. package/dist/layout/Row.js +45 -0
  496. package/dist/layout/SafeArea.js +26 -0
  497. package/dist/layout/Spacer.js +9 -0
  498. package/dist/layout/SplitPane.js +55 -0
  499. package/dist/layout/Stack.js +42 -0
  500. package/dist/layout/_responsive.js +16 -0
  501. package/dist/layout/_safeArea.js +18 -0
  502. package/dist/layout/index.d.ts +25 -6
  503. package/dist/layout/index.js +14 -2
  504. package/dist/lib/anchored-scroll.js +7 -0
  505. package/dist/lib/bleed.js +7 -0
  506. package/dist/lib/chart/cartesian.js +365 -0
  507. package/dist/lib/chart/chart-frame.js +163 -0
  508. package/dist/lib/chart/chart-legend.js +13 -0
  509. package/dist/lib/chart/chart-tooltip.js +38 -0
  510. package/dist/lib/chart/format.js +19 -0
  511. package/dist/lib/chart/geometry.js +114 -0
  512. package/dist/lib/chart/motion.js +34 -0
  513. package/dist/lib/chart/scale.js +72 -0
  514. package/dist/lib/chart/types.js +45 -0
  515. package/dist/lib/chart/use-arrival.js +41 -0
  516. package/dist/{chunk-SRQWQUTW.js → lib/cn.js} +5 -5
  517. package/dist/lib/component-guidance.js +210 -0
  518. package/dist/lib/density.js +54 -0
  519. package/dist/lib/field-shell.js +11 -0
  520. package/dist/lib/glyphs.js +9 -0
  521. package/dist/lib/heading-row.js +36 -0
  522. package/dist/lib/highlight-glide.js +84 -0
  523. package/dist/lib/hit-target.js +5 -0
  524. package/dist/lib/meta.js +0 -0
  525. package/dist/lib/portal-theme-scope.js +74 -0
  526. package/dist/{chunk-FKZXAFIY.js → lib/presentation.js} +8 -3
  527. package/dist/lib/refs.js +14 -0
  528. package/dist/lib/scrub-gesture.js +50 -0
  529. package/dist/lib/segmented.js +13 -0
  530. package/dist/lib/selection-card.js +41 -0
  531. package/dist/lib/status-tone.js +13 -0
  532. package/dist/lib/taxonomy.js +214 -0
  533. package/dist/lib/trim-label.js +20 -0
  534. package/dist/lib/use-copy.js +27 -0
  535. package/dist/lib/use-edge-fade.js +32 -0
  536. package/dist/lib/use-isomorphic-layout-effect.js +8 -0
  537. package/dist/lib/use-resize-observer.js +18 -0
  538. package/dist/lib/use-scroll-activity.js +52 -0
  539. package/dist/lib/use-wheel-to-horizontal.js +65 -0
  540. package/dist/motion/MotionProvider.js +75 -0
  541. package/dist/motion/Presence.js +112 -0
  542. package/dist/motion/Reveal.js +42 -0
  543. package/dist/motion/TextReveal.js +61 -0
  544. package/dist/motion/index.js +24 -0
  545. package/dist/motion/useInView.js +36 -0
  546. package/dist/motion/useReducedMotion.js +25 -0
  547. package/dist/motion/viewTransition.js +47 -0
  548. package/dist/patterns/auth-page.js +90 -0
  549. package/dist/patterns/auth-page.meta.js +27 -0
  550. package/dist/patterns/brand-landing-page.js +341 -0
  551. package/dist/patterns/brand-landing-page.meta.js +28 -0
  552. package/dist/patterns/chat-panel.js +185 -0
  553. package/dist/patterns/chat-panel.meta.js +31 -0
  554. package/dist/patterns/dashboard-page.js +332 -0
  555. package/dist/patterns/dashboard-page.meta.js +29 -0
  556. package/dist/patterns/feed-page.js +205 -0
  557. package/dist/patterns/feed-page.meta.js +25 -0
  558. package/dist/patterns/index.js +34 -2140
  559. package/dist/patterns/landing-page.js +356 -0
  560. package/dist/patterns/landing-page.meta.js +26 -0
  561. package/dist/patterns/list-detail-page.js +373 -0
  562. package/dist/patterns/list-detail-page.meta.js +24 -0
  563. package/dist/patterns/settings-page.js +268 -0
  564. package/dist/patterns/settings-page.meta.js +27 -0
  565. package/dist/presets/index.js +43 -185
  566. package/dist/styles.css +118 -3
  567. package/dist/{theme-provider-kQszHYji.d.ts → theme-provider-S0NVJs2Y.d.ts} +6 -1
  568. package/dist/{chunk-NETUFI34.js → themes/_contract.js} +14 -2
  569. package/dist/themes/atelier/index.js +17 -1
  570. package/dist/themes/contrast.js +288 -0
  571. package/dist/themes/ember/ember.css +6 -6
  572. package/dist/themes/ember/index.js +16 -1
  573. package/dist/themes/index.d.ts +1 -1
  574. package/dist/themes/index.js +3 -8
  575. package/dist/themes/meridian/index.js +16 -1
  576. package/dist/themes/poppy/index.js +17 -1
  577. package/dist/themes/prism/index.js +17 -1
  578. package/dist/themes/prism/prism.css +2 -2
  579. package/dist/themes/registry.js +59 -0
  580. package/dist/themes/sable/index.js +16 -1
  581. package/dist/{chunk-EFLC4NA3.js → themes/theme-provider.js} +38 -54
  582. package/dist/themes/verdant/index.js +17 -1
  583. package/llms/blocks/media-player-block.md +20 -7
  584. package/llms/blocks/product-card-block.md +6 -4
  585. package/llms/blocks/task-list-block.md +1 -1
  586. package/llms/blocks/verify-code-block.md +1 -1
  587. package/llms/components/app-shell.md +5 -2
  588. package/llms/components/avatar.md +25 -3
  589. package/llms/components/button.md +20 -1
  590. package/llms/components/card.md +1 -1
  591. package/llms/components/disclosure-picker.md +168 -0
  592. package/llms/components/font-picker.md +104 -0
  593. package/llms/components/media-image.md +98 -0
  594. package/llms/components/media-tile.md +143 -0
  595. package/llms/components/page-header.md +6 -5
  596. package/llms/components/section-header.md +144 -0
  597. package/llms/components/sheet.md +10 -0
  598. package/llms/components/sidebar.md +4 -3
  599. package/llms/components/slider.md +14 -2
  600. package/llms/components/theme-selector.md +44 -4
  601. package/llms/components/tree.md +3 -3
  602. package/llms/layout/grid.md +24 -3
  603. package/llms/patterns/dashboard-page.md +3 -6
  604. package/llms/patterns/feed-page.md +4 -4
  605. package/llms/patterns/list-detail-page.md +1 -0
  606. package/llms/patterns/settings-page.md +2 -5
  607. package/llms/reference/utilities.md +84 -4
  608. package/llms/tasks/converting-an-app.md +14 -4
  609. package/llms/tasks/reviewing-a-design.md +15 -0
  610. package/llms-full.txt +981 -65
  611. package/llms.txt +27 -10
  612. package/package.json +1 -1
  613. package/registry.json +2324 -171
  614. package/scripts/agent-setup.mjs +90 -0
  615. package/scripts/design-presets.mjs +46 -4
  616. package/scripts/grade.mjs +195 -29
  617. package/scripts/lint-rules.mjs +486 -10
  618. package/scripts/review-evidence.mjs +28 -1
  619. package/skills/sable/SKILL.md +56 -22
  620. package/targets/ios.json +45 -0
  621. package/dist/chunk-3IWZYBGH.js +0 -398
  622. package/dist/chunk-7MG4SHYX.js +0 -15
  623. package/dist/chunk-7QSDYBXO.js +0 -7421
  624. package/dist/chunk-ADLLDWLW.js +0 -15
  625. package/dist/chunk-C4Z3CF54.js +0 -15
  626. package/dist/chunk-EDXLM7YL.js +0 -5078
  627. package/dist/chunk-EHH4MHO6.js +0 -14
  628. package/dist/chunk-K7RUHUGC.js +0 -14
  629. package/dist/chunk-KO3NAEBF.js +0 -15
  630. package/dist/chunk-L4IEIQQA.js +0 -14
  631. package/dist/chunk-QJ6FWTUG.js +0 -40
  632. package/dist/chunk-VVW4UCDI.js +0 -4908
  633. package/dist/chunk-XAZGMY73.js +0 -187
@@ -0,0 +1,38 @@
1
+ // src/components/textarea/textarea.tsx
2
+ import { Field as BaseField } from "@base-ui/react/field";
3
+ import { cn } from "../../lib/cn.js";
4
+ import { FIELD_INVALID, FIELD_SHELL, MOBILE_FIELD_TIER } from "../../lib/field-shell.js";
5
+ import { useDensity, useTypeTier } from "../../lib/density.js";
6
+ import { jsx } from "react/jsx-runtime";
7
+ function Textarea({
8
+ autoResize,
9
+ className,
10
+ ref,
11
+ ...props
12
+ }) {
13
+ const tier = useTypeTier();
14
+ const density = useDensity();
15
+ return /* @__PURE__ */ jsx(
16
+ BaseField.Control,
17
+ {
18
+ ref,
19
+ render: /* @__PURE__ */ jsx("textarea", {}),
20
+ className: cn(
21
+ "flex min-h-20 w-full p-3 text-foreground",
22
+ // The shell Input wears too — lib/field-shell. Hand-copied, this had
23
+ // already lost the invalid ring Input shows on focus.
24
+ FIELD_SHELL,
25
+ FIELD_INVALID,
26
+ autoResize && "field-sizing-content resize-none",
27
+ tier.body,
28
+ density === "comfortable" && MOBILE_FIELD_TIER,
29
+ className
30
+ ),
31
+ ...props
32
+ }
33
+ );
34
+ }
35
+ Textarea.displayName = "Textarea";
36
+ export {
37
+ Textarea
38
+ };
@@ -0,0 +1,117 @@
1
+ // src/components/textarea/textarea.meta.ts
2
+ var textareaMeta = {
3
+ name: "Textarea",
4
+ summary: "Styled native multi-line text control. Soft-square, card surface, --ring focus, and an aria-invalid destructive error state.",
5
+ status: "stable",
6
+ keywords: [
7
+ "textarea",
8
+ "multi line input",
9
+ "form",
10
+ "text"
11
+ ],
12
+ usage: {
13
+ description: "Use Textarea for multi-line freeform text entry such as notes, descriptions, or messages.",
14
+ bestPractices: [
15
+ {
16
+ guidance: "do",
17
+ description: "Use labels, helper text, and character limits when expectations are specific."
18
+ },
19
+ {
20
+ guidance: "do",
21
+ description: "Size it to the expected amount of input without making the page feel blocked."
22
+ },
23
+ {
24
+ guidance: "do",
25
+ description: "Keep a focusable field at 16px or larger on mobile. iOS Safari zooms the whole page when a focused textarea computes under 16px and never zooms back out. Textarea handles this itself \u2014 below the sm breakpoint it renders text-body-lg (17px) and returns to text-body-md at sm and up. Build a custom field the same way: a second paired tier under a max-sm: variant, never a hand-set font-size."
26
+ },
27
+ {
28
+ guidance: "dont",
29
+ description: "Do not override the type with a page tier below 16px (text-body-md, text-body-sm) without a >=16px mobile arm \u2014 that reintroduces the iOS focus zoom."
30
+ },
31
+ {
32
+ guidance: "dont",
33
+ description: "Do not use Textarea for short single-line values; use Input."
34
+ },
35
+ {
36
+ guidance: "dont",
37
+ description: "Do not leave it at the default height for long-form input. A two-row textarea for a paragraph forces the user to write through a letterbox."
38
+ }
39
+ ]
40
+ },
41
+ related: {
42
+ components: [
43
+ "Input",
44
+ "Form",
45
+ "Label"
46
+ ]
47
+ },
48
+ props: [
49
+ {
50
+ name: "aria-invalid",
51
+ type: "boolean",
52
+ description: "When true, swaps the input border to the destructive token to signal a validation error."
53
+ },
54
+ {
55
+ name: "disabled",
56
+ type: "boolean",
57
+ default: "false",
58
+ description: "Dims the control to 50% and blocks pointer interaction."
59
+ },
60
+ {
61
+ name: "rows",
62
+ type: "number",
63
+ description: "Native textarea row count. The floor is min-h-20 on the spacing scale, so it moves with density."
64
+ },
65
+ {
66
+ name: "autoResize",
67
+ type: "boolean",
68
+ default: "false",
69
+ description: "Grows to fit content via CSS field-sizing: content (no JS). The min-height stays the floor; browsers without field-sizing fall back to the fixed min-height."
70
+ },
71
+ {
72
+ name: "...props",
73
+ type: 'ComponentPropsWithRef<"textarea">',
74
+ description: "All native textarea attributes (value, placeholder, onChange, name, ref, \u2026)."
75
+ }
76
+ ],
77
+ tokensUsed: [
78
+ "input",
79
+ "card",
80
+ "foreground",
81
+ "muted-foreground",
82
+ "ring",
83
+ "destructive"
84
+ ],
85
+ a11y: [
86
+ "Renders a native <textarea> \u2014 label association, keyboard, and screen-reader semantics come for free.",
87
+ "Renders through Base UI's Field.Control: inside a Field it picks up the label, description, error and validity wiring from context.",
88
+ "Pair with a <label htmlFor> (or aria-label) for an accessible name.",
89
+ "Set aria-invalid and reference an error message via aria-describedby to announce validation failures.",
90
+ "Focus-visible draws a 2px ring in the --ring token."
91
+ ],
92
+ examples: [
93
+ {
94
+ label: "Default",
95
+ code: '<Textarea placeholder="Write a caption\u2026" />'
96
+ },
97
+ {
98
+ label: "With rows",
99
+ code: '<Textarea rows={6} placeholder="Tell the story behind this edition\u2026" />'
100
+ },
101
+ {
102
+ label: "Auto-resize",
103
+ code: '<Textarea autoResize placeholder="Grows as you type\u2026" />'
104
+ },
105
+ {
106
+ label: "Invalid",
107
+ code: '<Textarea aria-invalid defaultValue="Too long" />'
108
+ },
109
+ {
110
+ label: "Disabled",
111
+ code: '<Textarea disabled defaultValue="Captions lock once the edition is minted." />'
112
+ }
113
+ ]
114
+ };
115
+ export {
116
+ textareaMeta
117
+ };
@@ -0,0 +1,11 @@
1
+ // src/components/theme-selector/index.ts
2
+ import {
3
+ ThemeSelector,
4
+ ThemePreview
5
+ } from "./theme-selector.js";
6
+ import { themeSelectorMeta } from "./theme-selector.meta.js";
7
+ export {
8
+ ThemePreview,
9
+ ThemeSelector,
10
+ themeSelectorMeta
11
+ };
@@ -0,0 +1,145 @@
1
+ // src/components/theme-selector/theme-selector.tsx
2
+ import { Radio as RadioBase } from "@base-ui/react/radio";
3
+ import { Icon } from "../../icon/index.js";
4
+ import { cn } from "../../lib/cn.js";
5
+ import { RadioGroup } from "../radio/radio.js";
6
+ import {
7
+ defaultThemeId,
8
+ featuredThemeManifests
9
+ } from "../../themes/registry.js";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ function themeCaption(theme, defaultId) {
12
+ if (theme.id === defaultId) return "Default";
13
+ if (theme.modes.length === 1) {
14
+ const mode = theme.modes[0];
15
+ return `${mode[0].toUpperCase()}${mode.slice(1)} only`;
16
+ }
17
+ return null;
18
+ }
19
+ function ThemePreview({ theme, mode = theme.defaultMode, size = "md" }) {
20
+ const face = { fontFamily: theme.fonts.display ?? theme.fonts.sans };
21
+ return /* @__PURE__ */ jsx("span", { className: "contents [--picker-u:var(--picker-option-u,var(--spacing))]", children: /* @__PURE__ */ jsx(
22
+ "span",
23
+ {
24
+ "data-sable-theme": theme.id,
25
+ "aria-hidden": true,
26
+ className: cn(
27
+ mode,
28
+ "shrink-0 overflow-hidden border border-border bg-background text-foreground",
29
+ // Sized in the APP's spacing unit (--picker-u, resolved on the option):
30
+ // inside this scope `h-16` meant the previewed theme's unit, and themes
31
+ // set different ones, so Prism's tile came out shorter than Poppy's and
32
+ // the names below no longer lined up.
33
+ size === "md" ? [
34
+ "grid h-[calc(var(--picker-u)*16)] w-full grid-cols-[1fr_auto] gap-[calc(var(--picker-u)*2)] rounded-md p-[calc(var(--picker-u)*2)]",
35
+ // The selection outline, in the APP's ink: --picker-* are resolved on
36
+ // the option, outside this scope, so they arrive as the app's colours.
37
+ // (A list row shows selection with its own fill instead.)
38
+ "outline-offset-2 motion-interactive",
39
+ "group-hover:outline-1 group-hover:outline-[color-mix(in_oklab,var(--picker-ink)_35%,transparent)]",
40
+ "group-aria-checked:outline-2 group-aria-checked:outline-(--picker-ink)",
41
+ "group-focus-visible:outline-2 group-focus-visible:outline-(--picker-focus)"
42
+ ] : "flex h-[calc(var(--picker-u)*6)] w-[calc(var(--picker-u)*11)] items-center justify-between gap-[calc(var(--picker-u)*1)] rounded-xs px-[calc(var(--picker-u)*1.5)]"
43
+ ),
44
+ children: size === "md" ? /* @__PURE__ */ jsxs(Fragment, { children: [
45
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col justify-between", children: [
46
+ /* @__PURE__ */ jsx("span", { className: "text-title-lg leading-none", style: face, children: "Aa" }),
47
+ /* @__PURE__ */ jsx("span", { className: "h-[calc(var(--picker-u)*3.5)] w-[calc(var(--picker-u)*10)] rounded-[calc(var(--button-radius,9999px)*0.35)] bg-primary" })
48
+ ] }),
49
+ /* @__PURE__ */ jsxs("span", { className: "flex w-[calc(var(--picker-u)*11)] flex-col justify-end gap-[calc(var(--picker-u)*1)] rounded-[calc(var(--radius-lg)*0.4)] border border-border bg-card p-[calc(var(--picker-u)*1.5)]", children: [
50
+ /* @__PURE__ */ jsx("span", { className: "h-[calc(var(--picker-u)*1)] w-full rounded-full bg-foreground/70" }),
51
+ /* @__PURE__ */ jsx("span", { className: "h-[calc(var(--picker-u)*1)] w-2/3 rounded-full bg-muted-foreground/40" })
52
+ ] })
53
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
54
+ /* @__PURE__ */ jsx("span", { className: "text-caption leading-none", style: face, children: "Aa" }),
55
+ /* @__PURE__ */ jsx("span", { className: "h-[calc(var(--picker-u)*2)] w-[calc(var(--picker-u)*3.5)] rounded-[calc(var(--button-radius,9999px)*0.2)] bg-primary" })
56
+ ] })
57
+ }
58
+ ) });
59
+ }
60
+ var PICKER_INK = "[--picker-ink:var(--foreground)] [--picker-focus:var(--ring)] [--picker-option-u:var(--spacing)]";
61
+ function ThemeSelector({
62
+ value,
63
+ onValueChange,
64
+ themes = featuredThemeManifests,
65
+ mode,
66
+ label = "Design theme",
67
+ layout = "cards",
68
+ className,
69
+ ref,
70
+ ...props
71
+ }) {
72
+ if (layout === "list") {
73
+ return /* @__PURE__ */ jsx(
74
+ RadioGroup,
75
+ {
76
+ ref,
77
+ "aria-label": label,
78
+ value,
79
+ onValueChange: (next) => onValueChange(next),
80
+ className: cn("relative flex flex-col gap-0.5", className),
81
+ ...props,
82
+ children: themes.map((theme) => /* @__PURE__ */ jsxs(
83
+ RadioBase.Root,
84
+ {
85
+ value: theme.id,
86
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
87
+ nativeButton: true,
88
+ className: cn(
89
+ // sable-frame-inner: concentric inside a sable-frame host (a frame-styled
90
+ // popover, a docked panel); the theme's small radius anywhere else.
91
+ "group flex h-(--control-sm) w-full items-center gap-2 px-1.5 text-start motion-interactive sable-frame-inner",
92
+ PICKER_INK,
93
+ // Menu / Select rows' fills and ink, so a theme list beside a
94
+ // menu reads as the same kind of row.
95
+ "hover:bg-accent hover:text-accent-foreground focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring",
96
+ "aria-checked:bg-accent aria-checked:text-accent-foreground"
97
+ ),
98
+ children: [
99
+ /* @__PURE__ */ jsx(ThemePreview, { theme, mode: mode ?? theme.defaultMode, size: "sm" }),
100
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-ui-md", children: theme.label }),
101
+ /* @__PURE__ */ jsx(Icon, { name: "check", className: "shrink-0 text-xs text-primary opacity-0 motion-interactive group-aria-checked:opacity-100" })
102
+ ]
103
+ },
104
+ theme.id
105
+ ))
106
+ }
107
+ );
108
+ }
109
+ return /* @__PURE__ */ jsx(
110
+ RadioGroup,
111
+ {
112
+ ref,
113
+ "aria-label": label,
114
+ value,
115
+ onValueChange: (next) => onValueChange(next),
116
+ className: cn("relative grid grid-cols-[repeat(auto-fill,minmax(--spacing(32),1fr))] gap-x-3 gap-y-4", className),
117
+ ...props,
118
+ children: themes.map((theme) => {
119
+ const caption = themeCaption(theme, defaultThemeId);
120
+ return /* @__PURE__ */ jsxs(
121
+ RadioBase.Root,
122
+ {
123
+ value: theme.id,
124
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
125
+ nativeButton: true,
126
+ className: cn("group flex min-w-0 flex-col gap-2 text-start focus-visible:outline-none", PICKER_INK),
127
+ children: [
128
+ /* @__PURE__ */ jsx(ThemePreview, { theme, mode: mode ?? theme.defaultMode, size: "md" }),
129
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-baseline gap-1.5", children: [
130
+ /* @__PURE__ */ jsx("span", { className: "truncate text-label-md text-muted-foreground motion-interactive group-hover:text-foreground group-aria-checked:text-foreground", children: theme.label }),
131
+ caption ? /* @__PURE__ */ jsx("span", { className: "shrink-0 truncate text-caption text-muted-foreground", children: caption }) : null
132
+ ] })
133
+ ]
134
+ },
135
+ theme.id
136
+ );
137
+ })
138
+ }
139
+ );
140
+ }
141
+ ThemeSelector.displayName = "ThemeSelector";
142
+ export {
143
+ ThemePreview,
144
+ ThemeSelector
145
+ };
@@ -0,0 +1,181 @@
1
+ // src/components/theme-selector/theme-selector.meta.ts
2
+ var themeSelectorMeta = {
3
+ name: "ThemeSelector",
4
+ summary: "A presentational radiogroup for choosing a Sable design theme from theme manifests \u2014 tiles that draw each theme as a miniature of its own interface (its colours, type and corner shape) for a settings page, or compact rows for tool chrome. Pair it with useSableTheme().themeId and setThemeId when the app uses SableThemeProvider.",
5
+ status: "stable",
6
+ // keywords and related were inherited from lib/component-guidance.ts until that
7
+ // entry was removed as dead code. They belong here now: the fall-through is
8
+ // per-field (`meta.keywords ?? metaGuidance.keywords`), so deleting the central
9
+ // entry drops every field the meta does not state itself.
10
+ keywords: ["theme selector", "theme", "appearance", "skin", "design theme", "preset"],
11
+ related: { components: ["ThemeSwitcher", "Popover", "RadioCard"] },
12
+ usage: {
13
+ description: 'Use ThemeSelector wherever a person picks a theme. The default `cards` layout is page-register furniture: a miniature of each theme\'s interface (its background, "Aa" in its display face, a card, and a primary button in its own corner shape), with the name and a caption only where one distinguishes it (the default theme, or a single-mode theme). Use `layout="list"` in tool chrome, a popover, or any docked panel \u2014 five cards is the wrong object for a 256px surface, however it is sized. For colour mode (light/dark/system) use ThemeSwitcher, which is a segmented control and belongs in chrome as-is.',
14
+ bestPractices: [
15
+ {
16
+ guidance: "do",
17
+ description: 'Use layout="list" in a popover, a menu, or a docked panel. Rows sit on the --control-sm ladder and still show a small tile of each theme, so the choice stays visible rather than described. Rows take `sable-frame-inner`, so host the list in a sable-frame (`sable-frame sable-surface sable-surface-popover sable-frame-popover` \u2014 PopoverContent is not one; give it that class list, or its p-4 leaves the rows unnested) and their corners nest concentrically.'
18
+ },
19
+ {
20
+ guidance: "do",
21
+ description: "Pass mode={useSableTheme().mode} so every preview renders in the colour mode actually in use, rather than in each theme's manifest default."
22
+ },
23
+ {
24
+ guidance: "do",
25
+ description: 'Use ThemeSelector when switching is free: it is a radio group, so arrow keys check the next theme and onValueChange fires on every press \u2014 the page restyles as you go, which is the point of a live theme switcher. When a switch has a cost (it opens a "discard changes?" confirm, loads fonts, or resets other settings), use a DisclosurePicker list instead, with a `ThemePreview size="sm"` as each option\'s `media`: arrows only move there, and Enter, Space or a click commits.'
26
+ },
27
+ {
28
+ guidance: "do",
29
+ description: "Load each theme's fonts in the host app. Every card carries a type specimen in that theme's own face so people can compare typography as well as color. A theme whose fonts are not loaded falls back to system-ui, and its specimen stops telling the truth."
30
+ },
31
+ {
32
+ guidance: "dont",
33
+ description: 'Add a viewport breakpoint to force a column count \u2014 `className="sm:grid-cols-1"` or similar. `sm:` keys off the VIEWPORT, not this component\'s container, so on a wide screen it does nothing for a narrow parent. The cards grid already reflows on its own width via auto-fit.'
34
+ },
35
+ {
36
+ guidance: "dont",
37
+ description: "Put the cards layout in workspace chrome. It was built for a settings page; in a 256px popover the cards clip their labels to a single character and grow to roughly twice their intended height."
38
+ },
39
+ {
40
+ // Recovered from lib/component-guidance.ts, whose entry for this
41
+ // component was silently shadowed the moment this `usage` block was
42
+ // added — `meta.usage ?? metaGuidance.usage` means the meta wins whole,
43
+ // so a partial override destroys whatever it does not restate.
44
+ guidance: "dont",
45
+ description: "Use ThemeSelector for light / dark / system colour mode. That is ThemeSwitcher \u2014 a segmented control. This picks the design theme, which is a different axis entirely, and the two are frequently confused."
46
+ }
47
+ ],
48
+ anatomy: [
49
+ {
50
+ name: "ThemeSelector",
51
+ required: true,
52
+ description: "The radiogroup of themes, as cards or list rows."
53
+ },
54
+ {
55
+ name: "ThemePreview",
56
+ required: false,
57
+ description: "The tile each option draws, exported for showing a theme outside the picker \u2014 the row naming the current theme, or the `media` of each option in a commit-on-Enter DisclosurePicker list."
58
+ }
59
+ ]
60
+ },
61
+ props: [
62
+ {
63
+ name: "value",
64
+ type: "ThemeId",
65
+ description: "The currently selected Sable design theme id."
66
+ },
67
+ {
68
+ name: "onValueChange",
69
+ type: "(themeId: ThemeId) => void",
70
+ description: "Called with the next design theme id when an option is chosen."
71
+ },
72
+ {
73
+ name: "themes",
74
+ type: "readonly ThemeManifest[]",
75
+ default: "themeManifests",
76
+ description: "Theme manifests to render. Defaults to Sable's built-in themes."
77
+ },
78
+ {
79
+ name: "mode",
80
+ type: '"light" | "dark"',
81
+ description: "Preview mode for each theme's tile. Pass useSableTheme().mode to match the current color mode; omitted cards use their manifest defaultMode."
82
+ },
83
+ {
84
+ name: "label",
85
+ type: "string",
86
+ default: '"Design theme"',
87
+ description: "Accessible label for the radiogroup."
88
+ },
89
+ {
90
+ name: "layout",
91
+ type: '"cards" | "list"',
92
+ default: '"cards"',
93
+ description: 'Presentation. "cards" is the page-register picker (~144px per card); "list" is one compact --control-sm row per theme, for chrome and popovers. A presentation variant, not a size \u2014 "list" is not "cards, smaller" \u2014 which is why it is a prop rather than a density scope.'
94
+ },
95
+ {
96
+ name: "className",
97
+ type: "string",
98
+ description: "Merged onto the outer radiogroup grid."
99
+ }
100
+ ],
101
+ subcomponents: [
102
+ {
103
+ name: "ThemePreview",
104
+ type: '{ theme: ThemeManifest; mode?: "light" | "dark"; size?: "md" | "sm" }',
105
+ description: `The tile each option draws: the theme as a miniature of itself (background, "Aa" in its display face, a card, a primary button in its own corner shape), in its own scope. Exported for anywhere that shows a theme outside the picker, e.g. a row naming the current preset, or each option of a DisclosurePicker list where a pick has a cost. Sized in the caller's spacing unit, so it lines up with the row it sits in.`
106
+ }
107
+ ],
108
+ tokensUsed: [
109
+ "input",
110
+ "card",
111
+ "border",
112
+ "background",
113
+ "primary",
114
+ "primary-foreground",
115
+ "accent",
116
+ "muted",
117
+ "muted-foreground",
118
+ "ring"
119
+ ],
120
+ a11y: [
121
+ 'The container is role="radiogroup" with an aria-label; each card is a role="radio" button with aria-checked reflecting the selected theme.',
122
+ "Standard radio keyboard: arrow keys move the check \u2014 calling onValueChange on each press \u2014 and Space checks the focused option. That instant switching is right for a free, reversible choice; where a switch has a cost, use a DisclosurePicker list (a listbox: arrows move, Enter commits) with ThemePreview tiles instead.",
123
+ "Focus-visible draws a 2px ring on the focused card.",
124
+ "The selected card wears the shared selection-card checked ring (the same as RadioCard and CheckboxCard), a muted fill and a check icon, so selection does not rely on colour alone.",
125
+ "Presentational only: it does not change the document theme; pass useSableTheme().setThemeId or apply the change in onValueChange."
126
+ ],
127
+ examples: [
128
+ {
129
+ label: "When a switch has a cost: a DisclosurePicker list of ThemePreview tiles",
130
+ code: `// Arrows move; Enter, Space or a click commits \u2014 so whatever the switch costs
131
+ // (a confirm, a font load, a reset) happens once, on the pick.
132
+ const { themeId, setThemeId, themes, mode } = useSableTheme()
133
+ const current = themes.find((theme) => theme.id === themeId)
134
+ <DisclosurePicker>
135
+ <DisclosurePickerTrigger aria-label={\`Theme: \${current?.label}\`} media={current ? <ThemePreview theme={current} mode={mode} size="sm" /> : null}>
136
+ {current?.label}
137
+ </DisclosurePickerTrigger>
138
+ <DisclosurePickerPanel>
139
+ <DisclosurePickerList aria-label="Theme" value={themeId} onValueChange={setThemeId}>
140
+ {themes.map((theme) => (
141
+ <DisclosurePickerOption key={theme.id} value={theme.id} media={<ThemePreview theme={theme} mode={mode} size="sm" />}>
142
+ {theme.label}
143
+ </DisclosurePickerOption>
144
+ ))}
145
+ </DisclosurePickerList>
146
+ </DisclosurePickerPanel>
147
+ </DisclosurePicker>`
148
+ },
149
+ {
150
+ label: "With SableThemeProvider",
151
+ code: "const { themeId, setThemeId, themes, mode } = useSableTheme()\n<ThemeSelector value={themeId} onValueChange={setThemeId} themes={themes} mode={mode} />"
152
+ },
153
+ {
154
+ label: "Controlled",
155
+ code: 'const [themeId, setThemeId] = useState<ThemeId>("sable")\n<ThemeSelector value={themeId} onValueChange={setThemeId} />'
156
+ },
157
+ {
158
+ label: "In chrome \u2014 a popover or a docked panel",
159
+ code: `// Five 144px cards is the wrong object for a 256px surface. Rows are.
160
+ <PopoverContent align="end" className="w-64 p-3">
161
+ <ThemeSwitcher value={preference} onValueChange={setPreference} />
162
+ <ThemeSelector layout="list" value={themeId} onValueChange={setThemeId} mode={mode} />
163
+ </PopoverContent>`
164
+ },
165
+ {
166
+ label: "Do not reach for a viewport breakpoint",
167
+ code: `// \u2717 \`sm:\` keys off the VIEWPORT, not this component's container. On a wide
168
+ // screen it does nothing at all for a narrow parent \u2014 and this exact
169
+ // workaround, once documented here, is how the cards layout ended up in a
170
+ // 256px popover clipping "Default" to "D".
171
+ <ThemeSelector className="sm:grid-cols-1" value={themeId} onValueChange={setThemeId} />
172
+
173
+ // \u2713 The cards grid already reflows on its own width (auto-fit, 9rem tracks).
174
+ // For a genuinely narrow surface, change the presentation instead.
175
+ <ThemeSelector layout="list" value={themeId} onValueChange={setThemeId} />`
176
+ }
177
+ ]
178
+ };
179
+ export {
180
+ themeSelectorMeta
181
+ };
@@ -0,0 +1,7 @@
1
+ // src/components/theme-switcher/index.ts
2
+ import { ThemeSwitcher } from "./theme-switcher.js";
3
+ import { themeSwitcherMeta } from "./theme-switcher.meta.js";
4
+ export {
5
+ ThemeSwitcher,
6
+ themeSwitcherMeta
7
+ };
@@ -0,0 +1,106 @@
1
+ "use client";
2
+
3
+ // src/components/theme-switcher/theme-switcher.tsx
4
+ import { Radio as RadioBase } from "@base-ui/react/radio";
5
+ import { Icon } from "../../icon/index.js";
6
+ import { cn } from "../../lib/cn.js";
7
+ import {
8
+ SEGMENTED_INNER_RADIUS,
9
+ SEGMENTED_ITEM,
10
+ SEGMENTED_STEP,
11
+ SEGMENTED_TRACK
12
+ } from "../../lib/segmented.js";
13
+ import { RadioGroup } from "../radio/radio.js";
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ var OPTIONS = [
16
+ { value: "light", icon: "sun", label: "Light" },
17
+ { value: "dark", icon: "moon", label: "Dark" },
18
+ { value: "system", icon: "desktop", label: "System" }
19
+ ];
20
+ function ThemeSwitcher({
21
+ value,
22
+ onValueChange,
23
+ label = "Theme",
24
+ className,
25
+ ref,
26
+ ...props
27
+ }) {
28
+ const activeIndex = OPTIONS.findIndex((o) => o.value === value);
29
+ return /* @__PURE__ */ jsxs(
30
+ RadioGroup,
31
+ {
32
+ ref,
33
+ "aria-label": label,
34
+ value,
35
+ onValueChange: (next) => onValueChange(next),
36
+ className: cn(
37
+ // `w-fit` as well as `inline-flex`, and it is load-bearing: `display`
38
+ // does not protect a flex ITEM. In any `flex flex-col` parent — the most
39
+ // ordinary way to stack a label above a control — `align-items: stretch`
40
+ // overrides the intrinsic width, and because the three buttons stay a
41
+ // fixed size-7 you get a full-width capsule with the icons stranded at
42
+ // the left. A segmented control of fixed-size options must never stretch.
43
+ // Pass `className="w-full"` if you genuinely want it to.
44
+ // `flex-row` overrides RadioGroup's stacked default.
45
+ // The shared segmented track (lib/segmented), also ToggleGroup's
46
+ // appearance="segmented".
47
+ SEGMENTED_TRACK,
48
+ className
49
+ ),
50
+ ...props,
51
+ children: [
52
+ /* @__PURE__ */ jsx(
53
+ "span",
54
+ {
55
+ "aria-hidden": true,
56
+ className: cn(
57
+ "pointer-events-none absolute start-0.5 top-0.5 size-7 bg-accent transition-[translate,opacity] duration-(--motion-duration-base) ease-emphasized",
58
+ SEGMENTED_INNER_RADIUS,
59
+ "[translate:calc(var(--segment-index)*var(--segment-step))_0] rtl:[translate:calc(var(--segment-index)*var(--segment-step)*-1)_0]",
60
+ activeIndex < 0 && "opacity-0"
61
+ ),
62
+ style: {
63
+ "--segment-index": Math.max(activeIndex, 0),
64
+ "--segment-step": SEGMENTED_STEP
65
+ }
66
+ }
67
+ ),
68
+ OPTIONS.map((option) => {
69
+ const checked = option.value === value;
70
+ return /* @__PURE__ */ jsx(
71
+ RadioBase.Root,
72
+ {
73
+ value: option.value,
74
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
75
+ nativeButton: true,
76
+ "aria-label": option.label,
77
+ title: option.label,
78
+ className: cn(
79
+ SEGMENTED_ITEM,
80
+ // The checked icon sits on the bg-accent pill, so its ink must be
81
+ // accent-foreground — legible on a saturated accent (a saturated theme accent)
82
+ // and identical to foreground for neutral accents.
83
+ "aria-checked:text-accent-foreground aria-checked:hover:text-accent-foreground"
84
+ ),
85
+ children: /* @__PURE__ */ jsx(
86
+ Icon,
87
+ {
88
+ name: option.icon,
89
+ className: cn(
90
+ "text-sm transition-transform duration-(--motion-duration-base) ease-spring",
91
+ checked && "scale-110"
92
+ )
93
+ }
94
+ )
95
+ },
96
+ option.value
97
+ );
98
+ })
99
+ ]
100
+ }
101
+ );
102
+ }
103
+ ThemeSwitcher.displayName = "ThemeSwitcher";
104
+ export {
105
+ ThemeSwitcher
106
+ };