@sableui/react 0.6.2 → 0.7.1

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 (642) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +315 -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 +203 -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 +34 -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 +618 -34
  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 +30 -8
  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 +24 -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 +215 -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.d.ts +7 -1
  566. package/dist/presets/index.js +53 -185
  567. package/dist/styles.css +118 -3
  568. package/dist/{theme-provider-kQszHYji.d.ts → theme-provider-S0NVJs2Y.d.ts} +6 -1
  569. package/dist/{chunk-NETUFI34.js → themes/_contract.js} +14 -2
  570. package/dist/themes/atelier/index.js +17 -1
  571. package/dist/themes/contrast.js +288 -0
  572. package/dist/themes/ember/ember.css +6 -6
  573. package/dist/themes/ember/index.js +16 -1
  574. package/dist/themes/index.d.ts +1 -1
  575. package/dist/themes/index.js +3 -8
  576. package/dist/themes/meridian/index.js +16 -1
  577. package/dist/themes/poppy/index.js +17 -1
  578. package/dist/themes/prism/index.js +17 -1
  579. package/dist/themes/prism/prism.css +2 -2
  580. package/dist/themes/registry.js +59 -0
  581. package/dist/themes/sable/index.js +16 -1
  582. package/dist/{chunk-EFLC4NA3.js → themes/theme-provider.js} +38 -54
  583. package/dist/themes/verdant/index.js +17 -1
  584. package/llms/blocks/media-player-block.md +20 -7
  585. package/llms/blocks/product-card-block.md +6 -4
  586. package/llms/blocks/task-list-block.md +1 -1
  587. package/llms/blocks/traffic-sources-block.md +1 -1
  588. package/llms/blocks/traffic-trend-block.md +5 -3
  589. package/llms/blocks/verify-code-block.md +1 -1
  590. package/llms/components/app-shell.md +5 -2
  591. package/llms/components/avatar.md +25 -3
  592. package/llms/components/button.md +20 -1
  593. package/llms/components/card.md +1 -1
  594. package/llms/components/disclosure-picker.md +168 -0
  595. package/llms/components/font-picker.md +104 -0
  596. package/llms/components/media-image.md +98 -0
  597. package/llms/components/media-tile.md +143 -0
  598. package/llms/components/page-header.md +6 -5
  599. package/llms/components/pie-chart.md +2 -2
  600. package/llms/components/radial-chart.md +1 -1
  601. package/llms/components/section-header.md +144 -0
  602. package/llms/components/sheet.md +10 -0
  603. package/llms/components/sidebar.md +4 -3
  604. package/llms/components/slider.md +14 -2
  605. package/llms/components/theme-selector.md +44 -4
  606. package/llms/components/tree.md +3 -3
  607. package/llms/layout/grid.md +24 -3
  608. package/llms/layout/region.md +16 -3
  609. package/llms/patterns/dashboard-page.md +3 -6
  610. package/llms/patterns/feed-page.md +4 -4
  611. package/llms/patterns/list-detail-page.md +1 -0
  612. package/llms/patterns/settings-page.md +2 -5
  613. package/llms/reference/utilities.md +84 -4
  614. package/llms/tasks/building-a-page.md +34 -3
  615. package/llms/tasks/converting-an-app.md +14 -4
  616. package/llms/tasks/creating-a-preset.md +4 -1
  617. package/llms/tasks/reviewing-a-design.md +19 -0
  618. package/llms/tasks/using-presets.md +19 -0
  619. package/llms-full.txt +1066 -78
  620. package/llms.txt +26 -9
  621. package/package.json +1 -1
  622. package/registry.json +2342 -164
  623. package/scripts/agent-setup.mjs +90 -0
  624. package/scripts/design-presets.mjs +59 -6
  625. package/scripts/grade.mjs +195 -29
  626. package/scripts/lint-rules.mjs +486 -10
  627. package/scripts/review-evidence.mjs +28 -1
  628. package/skills/sable/SKILL.md +67 -24
  629. package/targets/ios.json +45 -0
  630. package/dist/chunk-3IWZYBGH.js +0 -398
  631. package/dist/chunk-7MG4SHYX.js +0 -15
  632. package/dist/chunk-7QSDYBXO.js +0 -7421
  633. package/dist/chunk-ADLLDWLW.js +0 -15
  634. package/dist/chunk-C4Z3CF54.js +0 -15
  635. package/dist/chunk-EDXLM7YL.js +0 -5078
  636. package/dist/chunk-EHH4MHO6.js +0 -14
  637. package/dist/chunk-K7RUHUGC.js +0 -14
  638. package/dist/chunk-KO3NAEBF.js +0 -15
  639. package/dist/chunk-L4IEIQQA.js +0 -14
  640. package/dist/chunk-QJ6FWTUG.js +0 -40
  641. package/dist/chunk-VVW4UCDI.js +0 -4908
  642. package/dist/chunk-XAZGMY73.js +0 -187
@@ -0,0 +1,13 @@
1
+ // src/components/file-dropzone/index.ts
2
+ import {
3
+ FileDropzone,
4
+ formatFileSize
5
+ } from "./file-dropzone.js";
6
+ import { fileDropzoneVariants } from "./file-dropzone.variants.js";
7
+ import { fileDropzoneMeta } from "./file-dropzone.meta.js";
8
+ export {
9
+ FileDropzone,
10
+ fileDropzoneMeta,
11
+ fileDropzoneVariants,
12
+ formatFileSize
13
+ };
@@ -0,0 +1,77 @@
1
+ "use client";
2
+
3
+ // src/components/font-picker/font-picker.tsx
4
+ import { useEffect, useMemo, useState } from "react";
5
+ import {
6
+ DisclosurePicker,
7
+ DisclosurePickerEmpty,
8
+ DisclosurePickerList,
9
+ DisclosurePickerOption,
10
+ DisclosurePickerPanel,
11
+ DisclosurePickerTrigger
12
+ } from "../disclosure-picker/disclosure-picker.js";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ var faceOf = (font) => font.stack ?? `"${font.family}"`;
15
+ function FontPicker({
16
+ value,
17
+ onValueChange,
18
+ fonts,
19
+ options = [],
20
+ label,
21
+ listLabel = "Font",
22
+ searchable = true,
23
+ searchLabel = "Search fonts",
24
+ loadFont,
25
+ open: openProp,
26
+ defaultOpen = false,
27
+ onOpenChange,
28
+ ...props
29
+ }) {
30
+ const [query, setQuery] = useState("");
31
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
32
+ const open = openProp ?? uncontrolledOpen;
33
+ const setOpen = (next) => {
34
+ if (openProp === void 0) setUncontrolledOpen(next);
35
+ onOpenChange?.(next);
36
+ };
37
+ useEffect(() => {
38
+ if (open && loadFont) for (const font of fonts) loadFont(font, "preview");
39
+ }, [open, fonts, loadFont]);
40
+ const chosenFont = fonts.find((font) => font.family === value);
41
+ useEffect(() => {
42
+ if (chosenFont && loadFont) loadFont(chosenFont, "use");
43
+ }, [chosenFont, loadFont]);
44
+ const q = query.trim().toLowerCase();
45
+ const shownFonts = useMemo(
46
+ () => q ? fonts.filter((font) => font.family.toLowerCase().includes(q) || font.note?.toLowerCase().includes(q)) : fonts,
47
+ [fonts, q]
48
+ );
49
+ const shownOptions = q ? options.filter((option) => option.label.toLowerCase().includes(q)) : options;
50
+ const chosenOption = options.find((option) => option.value === value);
51
+ const current = chosenOption ? chosenOption.valueLabel ?? chosenOption.label : value;
52
+ const currentFace = chosenOption ? void 0 : chosenFont ? faceOf(chosenFont) : `"${value}"`;
53
+ return /* @__PURE__ */ jsxs(DisclosurePicker, { open, onOpenChange: setOpen, ...props, children: [
54
+ /* @__PURE__ */ jsx(DisclosurePickerTrigger, { label, children: /* @__PURE__ */ jsx("span", { style: { fontFamily: currentFace }, children: current }) }),
55
+ /* @__PURE__ */ jsxs(
56
+ DisclosurePickerPanel,
57
+ {
58
+ search: searchable ? { value: query, onValueChange: setQuery, placeholder: `Search ${fonts.length} fonts`, label: searchLabel } : void 0,
59
+ children: [
60
+ shownOptions.length + shownFonts.length > 0 ? /* @__PURE__ */ jsxs(DisclosurePickerList, { "aria-label": listLabel, value, onValueChange, children: [
61
+ shownOptions.map((option) => /* @__PURE__ */ jsx(DisclosurePickerOption, { value: option.value, children: option.label }, option.value)),
62
+ shownFonts.map((font) => /* @__PURE__ */ jsx(DisclosurePickerOption, { value: font.family, note: font.note, children: /* @__PURE__ */ jsx("span", { style: { fontFamily: faceOf(font) }, children: font.family }) }, font.family))
63
+ ] }) : null,
64
+ shownFonts.length === 0 && q ? /* @__PURE__ */ jsxs(DisclosurePickerEmpty, { children: [
65
+ "No fonts match \u201C",
66
+ query,
67
+ "\u201D."
68
+ ] }) : null
69
+ ]
70
+ }
71
+ )
72
+ ] });
73
+ }
74
+ FontPicker.displayName = "FontPicker";
75
+ export {
76
+ FontPicker
77
+ };
@@ -0,0 +1,119 @@
1
+ // src/components/font-picker/font-picker.meta.ts
2
+ var fontPickerMeta = {
3
+ name: "FontPicker",
4
+ summary: "A DisclosurePicker for a typeface: the row names the chosen family in its own face and opens in place into a searchable list of families, each drawn in itself. The app supplies the families and loads the faces; Sable bundles no catalog.",
5
+ status: "stable",
6
+ keywords: ["font picker", "typeface", "font family", "font selector", "typography", "google fonts", "inspector", "customizer"],
7
+ usage: {
8
+ description: "Use FontPicker wherever someone chooses a typeface for a role (body, headings, code) in a panel that shows the result: a theme editor, a document inspector, a brand customizer. It is a DisclosurePicker, so the list opens beneath the row rather than over the preview; arrow keys walk the families (each drawn in its own face) without applying or loading anything, and Enter, Space or a click picks one, loads it and closes the row.",
9
+ bestPractices: [
10
+ {
11
+ guidance: "do",
12
+ description: 'Pass `loadFont` and load faces lazily: `"preview"` fires for every family when the list opens (load just the glyphs of its name \u2014 Google Fonts\' `text=` parameter makes a 20-font list cost a few KB), `"use"` for the chosen one (load its real weights). Make it idempotent and define it once, outside render.'
13
+ },
14
+ {
15
+ guidance: "do",
16
+ description: 'Put non-font choices \u2014 "Preset (Figtree)", "Same as body" \u2014 in `options`, with a short `valueLabel` for the row. They list first and render in the app\'s face, so they never read as a family.'
17
+ },
18
+ {
19
+ guidance: "do",
20
+ description: 'Give each row a role `label` ("Body", "Headings", "Mono") and stack them; the caption column aligns. Control `open` from the parent so only one list is open at a time.'
21
+ },
22
+ {
23
+ guidance: "dont",
24
+ description: "Leave search on for a short curated list \u2014 under a dozen families, pass `searchable={false}`. Search is on by default because font lists are usually long."
25
+ },
26
+ {
27
+ guidance: "dont",
28
+ description: "Use a Select of family names for this. A popup covers the text it changes, and a family name set in the app's face says nothing about the face."
29
+ }
30
+ ]
31
+ },
32
+ related: { components: ["DisclosurePicker", "ThemeSelector", "Select", "Combobox"] },
33
+ props: [
34
+ { name: "value", type: "string", description: "The chosen family, or the value of one of `options`." },
35
+ {
36
+ name: "onValueChange",
37
+ type: "(value: string) => void",
38
+ description: "Called once a family (or option) is picked \u2014 Enter, Space or a click \u2014 and only when it differs from `value`; the row then closes. Arrow keys and type-ahead only move focus; Escape closes without a pick."
39
+ },
40
+ { name: "fonts", type: "readonly { family: string; note?: string; stack?: string }[]", description: 'The families to offer, in order. `note` is a muted annotation (searched too); `stack` the CSS font-family to draw it in (default `"<family>"`).' },
41
+ {
42
+ name: "options",
43
+ type: "readonly { value: string; label: string; valueLabel?: string }[]",
44
+ default: "[]",
45
+ description: "Non-font choices listed above the fonts, in the app's face. `valueLabel` is what the row shows while it is chosen."
46
+ },
47
+ { name: "label", type: "ReactNode", description: "The row's leading caption \u2014 the role the font plays." },
48
+ { name: "listLabel", type: "string", default: '"Font"', description: "Accessible name of the list." },
49
+ {
50
+ name: "searchable",
51
+ type: "boolean",
52
+ default: "true",
53
+ description: "A search field above the list, filtering by family and note. Pass false for a short curated list (under a dozen)."
54
+ },
55
+ { name: "searchLabel", type: "string", default: '"Search fonts"', description: "Accessible name of the search field." },
56
+ {
57
+ name: "loadFont",
58
+ type: '(font, purpose: "preview" | "use") => void',
59
+ description: 'Loads a face on demand: "preview" for every family when the list opens, "use" for the chosen one once it is picked (never while the list is only being walked). Receives your own font objects. Idempotent.'
60
+ },
61
+ { name: "open", type: "boolean", description: "Controlled open state, as DisclosurePicker. Control it to keep one of several rows open at a time." },
62
+ { name: "defaultOpen", type: "boolean", default: "false", description: "Uncontrolled initial open state." },
63
+ { name: "onOpenChange", type: "(open: boolean) => void", description: "Called with the next open state." },
64
+ { name: "size", type: '"md" | "xs"', default: '"md"', description: "md for a settings column; xs for the property-grid rung (see DisclosurePicker)." }
65
+ ],
66
+ tokensUsed: ["foreground", "muted-foreground", "popover", "hairline", "panel-field", "ring"],
67
+ a11y: [
68
+ "Inherits DisclosurePicker: a button trigger with aria-expanded/controls whose name is the caption plus the family; a listbox named by `listLabel`, aria-selected on the chosen family.",
69
+ "Keyboard open focuses the search field; ArrowDown steps from it into the list (ArrowUp from the first option steps back); arrows, Home/End and type-ahead move without applying; Enter or Space picks and closes; Escape clears the query, then closes without a pick and returns focus to the row.",
70
+ "Each family is set in its own face, but its name is still plain text, so a screen reader reads the name, not the glyphs."
71
+ ],
72
+ motion: [
73
+ { slot: "arrival", recipe: "none", part: "root", why: "A property row is present from first paint." },
74
+ { slot: "response", recipe: "motion-interactive", part: "Trigger", why: "Inherited from DisclosurePicker: the hover step says the value row opens." },
75
+ { slot: "transition", recipe: "motion-disclosure", part: "Panel", why: "Inherited from DisclosurePicker: the list grows in place, tying the panel's movement to this row." },
76
+ { slot: "activity", recipe: "none", part: "root", why: "Faces load in the background and swap in when ready; the names are legible in the fallback meanwhile, so there is nothing to wait on." }
77
+ ],
78
+ examples: [
79
+ {
80
+ label: "Body font with lazy loading",
81
+ code: `const FONTS = [
82
+ { family: "Inter", note: "Neutral, dense UI" },
83
+ { family: "Figtree", note: "Friendly geometric" },
84
+ { family: "Fraunces", note: "Soft, wonky serif", stack: '"Fraunces", serif' },
85
+ ]
86
+ // Your loader; Sable never fetches fonts itself.
87
+ const loadFont = (font: { family: string }, purpose: "preview" | "use") => {
88
+ const id = \`font-\${purpose}-\${font.family}\`
89
+ if (document.getElementById(id)) return
90
+ const link = Object.assign(document.createElement("link"), { id, rel: "stylesheet" })
91
+ const family = font.family.replace(/ /g, "+")
92
+ link.href = purpose === "preview"
93
+ ? \`https://fonts.googleapis.com/css2?family=\${family}&text=\${encodeURIComponent(font.family)}\`
94
+ : \`https://fonts.googleapis.com/css2?family=\${family}:wght@400..700&display=swap\`
95
+ document.head.appendChild(link)
96
+ }
97
+ const [family, setFamily] = useState("Inter")
98
+ <FontPicker label="Body" listLabel="Body font" value={family} onValueChange={setFamily} fonts={FONTS} loadFont={loadFont} searchable={false} />`
99
+ },
100
+ {
101
+ label: "With a preset option, one row of several",
102
+ code: `const [open, setOpen] = useState<string | null>(null)
103
+ const [body, setBody] = useState("theme")
104
+ <FontPicker
105
+ label="Body"
106
+ listLabel="Body font"
107
+ value={body}
108
+ onValueChange={setBody}
109
+ options={[{ value: "theme", label: "Preset (Figtree)", valueLabel: "Figtree" }]}
110
+ fonts={[{ family: "Inter" }, { family: "Figtree" }, { family: "Geist" }]}
111
+ open={open === "body"}
112
+ onOpenChange={(next) => setOpen(next ? "body" : null)}
113
+ />`
114
+ }
115
+ ]
116
+ };
117
+ export {
118
+ fontPickerMeta
119
+ };
@@ -0,0 +1,7 @@
1
+ // src/components/font-picker/index.ts
2
+ import { FontPicker } from "./font-picker.js";
3
+ import { fontPickerMeta } from "./font-picker.meta.js";
4
+ export {
5
+ FontPicker,
6
+ fontPickerMeta
7
+ };
@@ -0,0 +1,145 @@
1
+ "use client";
2
+
3
+ // src/components/form/form.tsx
4
+ import { Field as BaseField } from "@base-ui/react/field";
5
+ import { Form as BaseForm } from "@base-ui/react/form";
6
+ import {
7
+ Children,
8
+ cloneElement,
9
+ useId,
10
+ useRef
11
+ } from "react";
12
+ import { cn } from "../../lib/cn.js";
13
+ import { Label } from "../label/index.js";
14
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
+ function Form({
16
+ className,
17
+ onSubmit,
18
+ onFormSubmit,
19
+ noValidate,
20
+ ...props
21
+ }) {
22
+ const blockedRef = useRef(false);
23
+ const handleSubmit = (event) => {
24
+ blockedRef.current = false;
25
+ const form = event.currentTarget;
26
+ if (!noValidate && !form.checkValidity()) {
27
+ event.preventDefault();
28
+ blockedRef.current = true;
29
+ form.reportValidity();
30
+ return;
31
+ }
32
+ onSubmit?.(event);
33
+ };
34
+ return /* @__PURE__ */ jsx(
35
+ BaseForm,
36
+ {
37
+ className: cn("flex flex-col gap-6", className),
38
+ onSubmit: handleSubmit,
39
+ onFormSubmit: onFormSubmit ? (values, details) => {
40
+ if (!blockedRef.current) onFormSubmit(values, details);
41
+ } : void 0,
42
+ ...props
43
+ }
44
+ );
45
+ }
46
+ Form.displayName = "Form";
47
+ function Field({
48
+ label,
49
+ description,
50
+ error,
51
+ required,
52
+ disabled,
53
+ name,
54
+ validate,
55
+ validationMode,
56
+ validationDebounceTime,
57
+ orientation = "vertical",
58
+ className,
59
+ children
60
+ }) {
61
+ const generatedId = useId();
62
+ const child = Children.only(children);
63
+ const controlId = child.props.id ?? generatedId;
64
+ const descId = description ? `${controlId}-description` : void 0;
65
+ const errId = `${controlId}-error`;
66
+ const hasError = error != null && error !== false && error !== "";
67
+ const labelNode = label ? /* @__PURE__ */ jsxs(
68
+ BaseField.Label,
69
+ {
70
+ htmlFor: controlId,
71
+ render: /* @__PURE__ */ jsx(Label, {}),
72
+ className: "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
73
+ children: [
74
+ label,
75
+ required ? /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "text-destructive", children: [
76
+ " ",
77
+ "*"
78
+ ] }) : null
79
+ ]
80
+ }
81
+ ) : null;
82
+ const control = /* @__PURE__ */ jsx(BaseField.Validity, { children: ({ validity }) => {
83
+ const errorShown = hasError || validity.valid === false;
84
+ const describedBy = [child.props["aria-describedby"], descId, errorShown ? errId : null].filter(Boolean).join(" ") || void 0;
85
+ return cloneElement(child, {
86
+ id: controlId,
87
+ ...describedBy ? { "aria-describedby": describedBy } : null,
88
+ ...hasError ? { "aria-invalid": true } : null,
89
+ ...required != null ? { required } : null,
90
+ ...disabled ? { disabled: true } : null
91
+ });
92
+ } });
93
+ const descriptionNode = description ? /* @__PURE__ */ jsx(
94
+ BaseField.Description,
95
+ {
96
+ id: descId,
97
+ className: "text-body-sm text-muted-foreground",
98
+ children: description
99
+ }
100
+ ) : null;
101
+ const errorNode = /* @__PURE__ */ jsx(
102
+ BaseField.Error,
103
+ {
104
+ id: errId,
105
+ className: "text-body-sm text-destructive",
106
+ ...hasError ? { match: true, children: error } : null
107
+ }
108
+ );
109
+ return /* @__PURE__ */ jsx(
110
+ BaseField.Root,
111
+ {
112
+ className: cn("flex flex-col gap-1.5", className),
113
+ invalid: hasError || void 0,
114
+ disabled,
115
+ name,
116
+ validate,
117
+ validationMode,
118
+ validationDebounceTime,
119
+ children: orientation === "horizontal" ? (
120
+ // Control beside a text column. The control sits in a box one LABEL
121
+ // line tall (`h-[1lh]` in the label's own type step), so it centres
122
+ // on the first line and stays there when the label wraps. Helper and
123
+ // error text live in the label's column, not under the control.
124
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
125
+ /* @__PURE__ */ jsx("div", { className: "flex h-[1lh] shrink-0 items-center text-label-lg", children: control }),
126
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
127
+ labelNode,
128
+ descriptionNode,
129
+ errorNode
130
+ ] })
131
+ ] })
132
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
133
+ labelNode,
134
+ control,
135
+ descriptionNode,
136
+ errorNode
137
+ ] })
138
+ }
139
+ );
140
+ }
141
+ Field.displayName = "Field";
142
+ export {
143
+ Field,
144
+ Form
145
+ };
@@ -0,0 +1,142 @@
1
+ // src/components/form/form.meta.ts
2
+ var formMeta = {
3
+ name: "Form",
4
+ summary: "A styled <form> plus Field \u2014 the form orchestration layer, built on Base UI Form and Field. Field wires a label, control, helper text, and error message together with correct a11y (htmlFor, aria-labelledby, aria-describedby, aria-invalid, required) automatically, around any Sable control. Validation-library-agnostic: pass each Field an error string, or let Form check native constraints and Field validate functions on submit.",
5
+ keywords: [
6
+ "form",
7
+ "field",
8
+ "label",
9
+ "validation",
10
+ "error",
11
+ "required",
12
+ "settings",
13
+ "input"
14
+ ],
15
+ usage: {
16
+ description: "Use Form and Field as the default wrapper for Sable form controls. Field owns the label, description, required state, and error wiring so agents do not hand-roll inconsistent label/input relationships.",
17
+ bestPractices: [
18
+ {
19
+ guidance: "do",
20
+ description: "Wrap each control in Field unless a specialized component already owns its label and error semantics."
21
+ },
22
+ {
23
+ guidance: "do",
24
+ description: "Use Field error for validation messages so aria-invalid and aria-describedby are wired together."
25
+ },
26
+ {
27
+ guidance: "do",
28
+ description: 'For built-in checks, put required / type="email" / minLength on the control (or a validate function on Field) inside a Form: on submit the message appears under the field and the first invalid control is focused. Pass server errors to Form errors, keyed by Field name.'
29
+ },
30
+ {
31
+ guidance: "do",
32
+ description: "Use horizontal Field orientation only for one-line boolean controls like Checkbox, Switch, or Radio."
33
+ },
34
+ {
35
+ guidance: "dont",
36
+ description: "Use placeholder text as the only label. A visible label should identify the field."
37
+ },
38
+ {
39
+ guidance: "dont",
40
+ description: "Wrap multiple controls in one Field. Field expects a single child control and wires that one control (an Input or Textarea nested in a wrapper is still found through context)."
41
+ }
42
+ ],
43
+ anatomy: [
44
+ {
45
+ name: "Form",
46
+ required: true,
47
+ description: "The native form element (Base UI Form) with vertical field spacing; validates its Fields on submit."
48
+ },
49
+ {
50
+ name: "Field",
51
+ required: true,
52
+ description: "The label/control/helper/error wrapper for one control."
53
+ },
54
+ {
55
+ name: "Control",
56
+ required: true,
57
+ description: "The single Sable control. Base UI-backed controls register with Field through context; the child is also cloned with the same wiring."
58
+ },
59
+ {
60
+ name: "Error",
61
+ required: false,
62
+ description: "Validation copy associated with the control: the error prop when set, otherwise the Base UI validation message (native constraint, validate function, or Form errors)."
63
+ }
64
+ ]
65
+ },
66
+ related: {
67
+ components: ["Input", "Textarea", "Select", "Checkbox", "Switch", "Button"],
68
+ patterns: ["SettingsPage", "AuthPage"]
69
+ },
70
+ status: "stable",
71
+ props: [
72
+ {
73
+ name: "Form",
74
+ type: '{ validationMode?: "onSubmit" | "onBlur" | "onChange"; errors?: Record<string, string | string[]>; onFormSubmit?: (values, details) => void; actionsRef?: RefObject<Form.Actions> } + ComponentPropsWithRef<"form">',
75
+ description: 'A <form> laid out as a vertical column with comfortable field spacing (override with className, e.g. gap-4). On submit it validates every Field (native constraints plus Field validate), shows each message under its field, focuses the first invalid control, and only then calls onSubmit. validationMode defaults to "onSubmit" (then live re-validation on change). errors shows external (e.g. server) messages keyed by Field name and clears one when its field is edited. onFormSubmit receives the named Field values and prevents the native submit. A control outside any Field is still checked by the browser before onSubmit runs; pass noValidate to skip that.'
76
+ },
77
+ {
78
+ name: "validationMode",
79
+ type: '"onSubmit" | "onBlur" | "onChange"',
80
+ default: '"onSubmit"',
81
+ description: "When Fields validate. After the first submit, fields re-check as the user edits. A Field's own validationMode wins."
82
+ },
83
+ {
84
+ name: "errors",
85
+ type: "Record<string, string | string[]>",
86
+ description: "External (e.g. server) messages keyed by Field name, shown under that field. Each clears when its field is edited."
87
+ },
88
+ {
89
+ name: "onFormSubmit",
90
+ type: "(values: Record<string, unknown>, details) => void",
91
+ description: "Called with the named Field values after validation passes; prevents the native submit."
92
+ },
93
+ {
94
+ name: "actionsRef",
95
+ type: "RefObject<{ validate(name?: string): void }>",
96
+ description: "Imperative handle to validate every field, or one by name."
97
+ }
98
+ ],
99
+ subcomponents: [
100
+ {
101
+ name: "Field",
102
+ type: '{ label?: ReactNode; description?: ReactNode; error?: ReactNode; required?: boolean; disabled?: boolean; name?: string; validate?: (value, formValues) => string | string[] | null | Promise<\u2026>; validationMode?: "onSubmit" | "onBlur" | "onChange"; validationDebounceTime?: number; orientation?: "vertical" | "horizontal"; className?: string; children: ReactElement }',
103
+ description: `Wraps a single control element (e.g. <Input />) on Base UI Field and wires label (htmlFor + aria-labelledby), helper text and error (aria-describedby), aria-invalid, and required onto it automatically. Base UI-backed controls (Input, Textarea, Select, Combobox, NumberField, Checkbox, Switch, Slider, OtpField\u2026) register through context; the child is also cloned so plain elements keep the same wiring. error renders a destructive message and takes precedence; without it the slot shows Base UI's validation message when the field fails (native constraint, validate, or Form errors). required adds the native attribute plus a visual asterisk (defaults to false). disabled disables the control and dims the label. name keys the field in Form errors / onFormSubmit. validationMode overrides the Form's. orientation defaults to "vertical" (label \u2192 control); "horizontal" places control then label inline for a single checkbox / switch / radio \u2014 the control centres on the label's first line (it stays there when the label wraps) and description/error sit in the label's column. The root, label, description, error and control carry data-invalid / data-valid, data-touched, data-dirty, data-filled, data-focused and data-disabled for state styling.`
104
+ }
105
+ ],
106
+ tokensUsed: ["muted-foreground", "destructive"],
107
+ a11y: [
108
+ "Field auto-wires label htmlFor \u2194 control id, aria-describedby (description + error), and aria-invalid \u2014 so the label, helper, and error are all announced for the control.",
109
+ "required adds the native `required` attribute (not just a visual asterisk); the asterisk is aria-hidden.",
110
+ "Error text is associated via aria-describedby and reinforced by the destructive color, not color alone.",
111
+ "Inside Form, a failed submit focuses the first invalid control and shows its message inline instead of a browser bubble."
112
+ ],
113
+ examples: [
114
+ {
115
+ label: "Text field",
116
+ code: `<Field label="Email" description="We'll never share it." required><Input type="email" /></Field>`
117
+ },
118
+ {
119
+ label: "Field with an error",
120
+ code: '<Field label="Password" error="Must be at least 8 characters."><Input type="password" /></Field>'
121
+ },
122
+ {
123
+ label: "Validated on submit",
124
+ code: '<Form onSubmit={handleSubmit}><Field label="Handle" required validate={(value) => String(value).length < 3 ? "At least 3 characters." : null}><Input name="handle" /></Field><Button type="submit">Claim</Button></Form>'
125
+ },
126
+ {
127
+ label: "Server errors",
128
+ code: '<Form errors={serverErrors}><Field label="Email" name="email"><Input type="email" /></Field></Form>'
129
+ },
130
+ {
131
+ label: "Form",
132
+ code: '<Form onSubmit={handleSubmit}><Field label="Name"><Input /></Field><Field label="Subscribe" orientation="horizontal"><Checkbox /></Field><Button type="submit">Save</Button></Form>'
133
+ },
134
+ {
135
+ label: "Settings form",
136
+ code: '<Form onSubmit={handleSubmit}><Field label="Display name" description="Shown on your profile."><Input defaultValue="Nova Reed" /></Field><Field label="Visibility"><Select defaultValue="public"><SelectTrigger /><SelectContent><SelectItem value="public">Public</SelectItem><SelectItem value="private">Private</SelectItem></SelectContent></Select></Field><Button type="submit">Save changes</Button></Form>'
137
+ }
138
+ ]
139
+ };
140
+ export {
141
+ formMeta
142
+ };
@@ -0,0 +1,11 @@
1
+ // src/components/form/index.ts
2
+ import {
3
+ Form,
4
+ Field
5
+ } from "./form.js";
6
+ import { formMeta } from "./form.meta.js";
7
+ export {
8
+ Field,
9
+ Form,
10
+ formMeta
11
+ };
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ // src/components/gliding-highlight/gliding-highlight.tsx
4
+ import { useLayoutEffect, useRef } from "react";
5
+ import { cn } from "../../lib/cn.js";
6
+ import { HighlightGlide } from "../../lib/highlight-glide.js";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ function GlidingHighlight({
9
+ active,
10
+ orientation: _orientation,
11
+ children,
12
+ className,
13
+ highlightClassName,
14
+ ...props
15
+ }) {
16
+ const ref = useRef(null);
17
+ useLayoutEffect(() => {
18
+ const root = ref.current;
19
+ if (!root) return;
20
+ const items = Array.from(root.children).filter((el) => !el.hasAttribute("data-highlight-glide"));
21
+ items.forEach((el, i) => {
22
+ if (i === active) el.setAttribute("data-highlighted", "");
23
+ else el.removeAttribute("data-highlighted");
24
+ });
25
+ });
26
+ return /* @__PURE__ */ jsxs(
27
+ "div",
28
+ {
29
+ ref,
30
+ className: cn("relative [&>*:not([data-highlight-glide])]:relative", className),
31
+ ...props,
32
+ children: [
33
+ /* @__PURE__ */ jsx(
34
+ HighlightGlide,
35
+ {
36
+ className: cn(
37
+ "rounded-[var(--sable-frame-inner-radius,var(--radius-sm))] bg-accent",
38
+ highlightClassName
39
+ )
40
+ }
41
+ ),
42
+ children
43
+ ]
44
+ }
45
+ );
46
+ }
47
+ GlidingHighlight.displayName = "GlidingHighlight";
48
+ export {
49
+ GlidingHighlight
50
+ };