@eocrm/design-system 0.0.0-stage → 0.6.17

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 (897) hide show
  1. package/AI-PRIMER.md +341 -0
  2. package/README.md +262 -2
  3. package/docs/components/Accordion.md +114 -0
  4. package/docs/components/AgentAvatar.md +58 -0
  5. package/docs/components/Alert.md +81 -0
  6. package/docs/components/AppLayout.md +70 -0
  7. package/docs/components/Avatar.md +49 -0
  8. package/docs/components/AvatarGroup.md +47 -0
  9. package/docs/components/Badge.md +60 -0
  10. package/docs/components/Banner.md +89 -0
  11. package/docs/components/BrandIcon.md +32 -0
  12. package/docs/components/Breadcrumb.md +72 -0
  13. package/docs/components/Button.md +107 -0
  14. package/docs/components/ButtonGroup.md +78 -0
  15. package/docs/components/Calendar.md +158 -0
  16. package/docs/components/Card.md +165 -0
  17. package/docs/components/CatalogPicker.md +83 -0
  18. package/docs/components/Chart.md +114 -0
  19. package/docs/components/ChatBubble.md +55 -0
  20. package/docs/components/ChatLauncher.md +97 -0
  21. package/docs/components/Checkbox.md +55 -0
  22. package/docs/components/CircularProgress.md +53 -0
  23. package/docs/components/Cluster.md +96 -0
  24. package/docs/components/Code.md +35 -0
  25. package/docs/components/CodeBlock.md +67 -0
  26. package/docs/components/ColorPicker.md +115 -0
  27. package/docs/components/ConfirmationPopover.md +70 -0
  28. package/docs/components/Constrain.md +39 -0
  29. package/docs/components/CurrencySelect.md +57 -0
  30. package/docs/components/CursorPagination.md +43 -0
  31. package/docs/components/DashboardCanvas.md +79 -0
  32. package/docs/components/DashboardWidget.md +131 -0
  33. package/docs/components/DataTable.md +88 -0
  34. package/docs/components/DatePicker.md +68 -0
  35. package/docs/components/DateRangePicker.md +71 -0
  36. package/docs/components/DateStrip.md +56 -0
  37. package/docs/components/DefinitionList.md +82 -0
  38. package/docs/components/Divider.md +57 -0
  39. package/docs/components/Dot.md +26 -0
  40. package/docs/components/Drawer.md +94 -0
  41. package/docs/components/DropdownMenu.md +299 -0
  42. package/docs/components/EmojiPicker.md +84 -0
  43. package/docs/components/EmptyState.md +55 -0
  44. package/docs/components/EntityChip.md +102 -0
  45. package/docs/components/ErrorState.md +72 -0
  46. package/docs/components/Field.md +91 -0
  47. package/docs/components/FileUpload.md +109 -0
  48. package/docs/components/FilterChip.md +88 -0
  49. package/docs/components/FlowCanvas.md +108 -0
  50. package/docs/components/FormRow.md +31 -0
  51. package/docs/components/FormSection.md +37 -0
  52. package/docs/components/Grid.md +103 -0
  53. package/docs/components/Highlight.md +75 -0
  54. package/docs/components/HighlightedText.md +50 -0
  55. package/docs/components/IconPicker.md +134 -0
  56. package/docs/components/IconTile.md +30 -0
  57. package/docs/components/Image.md +84 -0
  58. package/docs/components/ImageCrop.md +163 -0
  59. package/docs/components/Indent.md +31 -0
  60. package/docs/components/InlineDatePicker.md +58 -0
  61. package/docs/components/InlineDateRangePicker.md +57 -0
  62. package/docs/components/Input.md +54 -0
  63. package/docs/components/Kanban.md +122 -0
  64. package/docs/components/Kbd.md +41 -0
  65. package/docs/components/Lightbox.md +105 -0
  66. package/docs/components/Link.md +65 -0
  67. package/docs/components/LinkCard.md +41 -0
  68. package/docs/components/LiquidEditor.md +84 -0
  69. package/docs/components/List.md +68 -0
  70. package/docs/components/LiveRegion.md +29 -0
  71. package/docs/components/LocaleProvider.md +25 -0
  72. package/docs/components/Logo.md +41 -0
  73. package/docs/components/Masonry.md +48 -0
  74. package/docs/components/MediaTile.md +95 -0
  75. package/docs/components/Modal.md +107 -0
  76. package/docs/components/MoneyInput.md +62 -0
  77. package/docs/components/OptionsPicker.md +123 -0
  78. package/docs/components/OtpInput.md +65 -0
  79. package/docs/components/Page.md +35 -0
  80. package/docs/components/PageHeader.md +133 -0
  81. package/docs/components/Pagination.md +44 -0
  82. package/docs/components/Palette.md +32 -0
  83. package/docs/components/PasswordInput.md +45 -0
  84. package/docs/components/PasswordStrengthMeter.md +27 -0
  85. package/docs/components/PersonDisplay.md +153 -0
  86. package/docs/components/PhoneInput.md +54 -0
  87. package/docs/components/PillMenu.md +91 -0
  88. package/docs/components/Popover.md +127 -0
  89. package/docs/components/Progress.md +56 -0
  90. package/docs/components/QrCode.md +34 -0
  91. package/docs/components/Radio.md +37 -0
  92. package/docs/components/RadioGroup.md +56 -0
  93. package/docs/components/Rail.md +191 -0
  94. package/docs/components/RelativeDateInput.md +114 -0
  95. package/docs/components/RichText.md +44 -0
  96. package/docs/components/RichTextEditor.md +112 -0
  97. package/docs/components/Screen.md +37 -0
  98. package/docs/components/ScrollArea.md +39 -0
  99. package/docs/components/Select.md +131 -0
  100. package/docs/components/SettingRow.md +98 -0
  101. package/docs/components/Skeleton.md +68 -0
  102. package/docs/components/Slider.md +92 -0
  103. package/docs/components/SlotGrid.md +55 -0
  104. package/docs/components/SocialButton.md +31 -0
  105. package/docs/components/Sortable.md +127 -0
  106. package/docs/components/SortableGroup.md +52 -0
  107. package/docs/components/Sparkline.md +51 -0
  108. package/docs/components/Split.md +76 -0
  109. package/docs/components/Stack.md +59 -0
  110. package/docs/components/StagePath.md +66 -0
  111. package/docs/components/StatGroup.md +61 -0
  112. package/docs/components/StatTile.md +58 -0
  113. package/docs/components/Sticky.md +69 -0
  114. package/docs/components/Switch.md +89 -0
  115. package/docs/components/Table.md +184 -0
  116. package/docs/components/TableOfContents.md +76 -0
  117. package/docs/components/Tabs.md +94 -0
  118. package/docs/components/Text.md +63 -0
  119. package/docs/components/Textarea.md +59 -0
  120. package/docs/components/Thread.md +52 -0
  121. package/docs/components/TimeField.md +70 -0
  122. package/docs/components/Timeline.md +57 -0
  123. package/docs/components/Title.md +54 -0
  124. package/docs/components/ToastViewport.md +61 -0
  125. package/docs/components/Tooltip.md +63 -0
  126. package/docs/components/TopBar.md +214 -0
  127. package/docs/components/Tour.md +85 -0
  128. package/docs/components/TreeView.md +113 -0
  129. package/docs/components/VisuallyHidden.md +43 -0
  130. package/docs/components/WidgetPreview.md +54 -0
  131. package/docs/components/useBelowBreakpoint.md +11 -0
  132. package/docs/components/useMonth.md +18 -0
  133. package/docs/setup.md +51 -0
  134. package/docs/theming.md +95 -0
  135. package/docs/tokens.md +123 -0
  136. package/docs/transient-state.md +56 -0
  137. package/package.json +82 -4
  138. package/src/_meta/manifest.ts +293 -0
  139. package/src/app/AppProvider.tsx +78 -0
  140. package/src/app/index.ts +3 -0
  141. package/src/app/themeTokens.ts +95 -0
  142. package/src/calendar/dateMath.ts +114 -0
  143. package/src/calendar/formatters.ts +75 -0
  144. package/src/calendar/index.ts +39 -0
  145. package/src/calendar/types.ts +36 -0
  146. package/src/calendar/useAgenda.ts +70 -0
  147. package/src/calendar/useDay.ts +51 -0
  148. package/src/calendar/useMonth.ts +82 -0
  149. package/src/calendar/useWeek.ts +62 -0
  150. package/src/calendar/weekInfo.ts +83 -0
  151. package/src/components/Accordion/Accordion.module.scss +304 -0
  152. package/src/components/Accordion/Accordion.tokens.scss +64 -0
  153. package/src/components/Accordion/Accordion.tsx +272 -0
  154. package/src/components/Accordion/AccordionContent.tsx +36 -0
  155. package/src/components/Accordion/AccordionItem.tsx +66 -0
  156. package/src/components/Accordion/AccordionTrigger.tsx +121 -0
  157. package/src/components/Accordion/context.ts +47 -0
  158. package/src/components/Accordion/index.ts +14 -0
  159. package/src/components/Alert/Alert.module.scss +92 -0
  160. package/src/components/Alert/Alert.tokens.scss +60 -0
  161. package/src/components/Alert/Alert.tsx +136 -0
  162. package/src/components/Alert/index.ts +2 -0
  163. package/src/components/AppLayout/AppLayout.module.scss +130 -0
  164. package/src/components/AppLayout/AppLayout.tokens.scss +27 -0
  165. package/src/components/AppLayout/AppLayout.tsx +211 -0
  166. package/src/components/AppLayout/index.ts +2 -0
  167. package/src/components/Avatar/AgentAvatar.module.scss +117 -0
  168. package/src/components/Avatar/AgentAvatar.tsx +122 -0
  169. package/src/components/Avatar/Avatar.module.scss +181 -0
  170. package/src/components/Avatar/Avatar.tokens.scss +107 -0
  171. package/src/components/Avatar/Avatar.tsx +210 -0
  172. package/src/components/Avatar/AvatarGroup.module.scss +128 -0
  173. package/src/components/Avatar/AvatarGroup.tsx +119 -0
  174. package/src/components/Avatar/AvatarGroupContext.tsx +20 -0
  175. package/src/components/Avatar/index.ts +6 -0
  176. package/src/components/Badge/Badge.module.scss +124 -0
  177. package/src/components/Badge/Badge.tokens.scss +74 -0
  178. package/src/components/Badge/Badge.tsx +164 -0
  179. package/src/components/Badge/index.ts +2 -0
  180. package/src/components/Banner/Banner.module.scss +73 -0
  181. package/src/components/Banner/Banner.tokens.scss +51 -0
  182. package/src/components/Banner/Banner.tsx +138 -0
  183. package/src/components/Banner/index.ts +2 -0
  184. package/src/components/BrandIcon/BrandIcon.module.scss +5 -0
  185. package/src/components/BrandIcon/BrandIcon.tsx +99 -0
  186. package/src/components/BrandIcon/index.ts +2 -0
  187. package/src/components/Breadcrumb/Breadcrumb.module.scss +32 -0
  188. package/src/components/Breadcrumb/Breadcrumb.tokens.scss +9 -0
  189. package/src/components/Breadcrumb/Breadcrumb.tsx +146 -0
  190. package/src/components/Breadcrumb/index.ts +2 -0
  191. package/src/components/Button/Button.module.scss +167 -0
  192. package/src/components/Button/Button.tokens.scss +90 -0
  193. package/src/components/Button/Button.tsx +205 -0
  194. package/src/components/Button/index.ts +2 -0
  195. package/src/components/ButtonGroup/ButtonGroup.module.scss +134 -0
  196. package/src/components/ButtonGroup/ButtonGroup.tokens.scss +42 -0
  197. package/src/components/ButtonGroup/ButtonGroup.tsx +278 -0
  198. package/src/components/ButtonGroup/ButtonGroupItem.tsx +74 -0
  199. package/src/components/ButtonGroup/context.ts +45 -0
  200. package/src/components/ButtonGroup/index.ts +2 -0
  201. package/src/components/Calendar/AgendaView.module.scss +231 -0
  202. package/src/components/Calendar/AgendaView.tsx +214 -0
  203. package/src/components/Calendar/AllDayBand.module.scss +18 -0
  204. package/src/components/Calendar/AllDayBand.tsx +75 -0
  205. package/src/components/Calendar/Calendar.module.scss +23 -0
  206. package/src/components/Calendar/Calendar.tokens.scss +262 -0
  207. package/src/components/Calendar/Calendar.tsx +370 -0
  208. package/src/components/Calendar/DayCell.module.scss +30 -0
  209. package/src/components/Calendar/DayCell.tsx +50 -0
  210. package/src/components/Calendar/DayView.module.scss +10 -0
  211. package/src/components/Calendar/DayView.tsx +163 -0
  212. package/src/components/Calendar/EventChip.module.scss +171 -0
  213. package/src/components/Calendar/EventChip.tsx +115 -0
  214. package/src/components/Calendar/HourGrid.module.scss +123 -0
  215. package/src/components/Calendar/HourGrid.tsx +381 -0
  216. package/src/components/Calendar/MonthView.module.scss +99 -0
  217. package/src/components/Calendar/MonthView.tsx +296 -0
  218. package/src/components/Calendar/TimedEvent.module.scss +205 -0
  219. package/src/components/Calendar/TimedEvent.tsx +247 -0
  220. package/src/components/Calendar/ViewSwitcher.module.scss +3 -0
  221. package/src/components/Calendar/ViewSwitcher.tsx +47 -0
  222. package/src/components/Calendar/WeekView.module.scss +10 -0
  223. package/src/components/Calendar/WeekView.tsx +137 -0
  224. package/src/components/Calendar/eventColor.ts +60 -0
  225. package/src/components/Calendar/index.ts +18 -0
  226. package/src/components/Calendar/types.ts +451 -0
  227. package/src/components/Calendar/useEventDrag.ts +783 -0
  228. package/src/components/Calendar/utils.ts +622 -0
  229. package/src/components/Card/Card.module.scss +264 -0
  230. package/src/components/Card/Card.tokens.scss +55 -0
  231. package/src/components/Card/Card.tsx +170 -0
  232. package/src/components/Card/CardBody.tsx +45 -0
  233. package/src/components/Card/CardHeader.tsx +113 -0
  234. package/src/components/Card/CardList.tsx +24 -0
  235. package/src/components/Card/CardListRow.tsx +24 -0
  236. package/src/components/Card/index.ts +7 -0
  237. package/src/components/CatalogPicker/CatalogPicker.module.scss +193 -0
  238. package/src/components/CatalogPicker/CatalogPicker.tokens.scss +26 -0
  239. package/src/components/CatalogPicker/CatalogPicker.tsx +339 -0
  240. package/src/components/CatalogPicker/index.ts +2 -0
  241. package/src/components/Chart/Chart.module.scss +287 -0
  242. package/src/components/Chart/Chart.tokens.scss +63 -0
  243. package/src/components/Chart/Chart.tsx +607 -0
  244. package/src/components/Chart/ChartLegend.tsx +99 -0
  245. package/src/components/Chart/ChartTable.tsx +62 -0
  246. package/src/components/Chart/ChartTooltip.tsx +91 -0
  247. package/src/components/Chart/chartModel.ts +689 -0
  248. package/src/components/Chart/index.ts +2 -0
  249. package/src/components/ChatBubble/ChatBubble.module.scss +93 -0
  250. package/src/components/ChatBubble/ChatBubble.tokens.scss +17 -0
  251. package/src/components/ChatBubble/ChatBubble.tsx +61 -0
  252. package/src/components/ChatBubble/ChatBubbleList.tsx +27 -0
  253. package/src/components/ChatBubble/index.ts +3 -0
  254. package/src/components/ChatLauncher/ChatLauncher.module.scss +68 -0
  255. package/src/components/ChatLauncher/ChatLauncher.tokens.scss +27 -0
  256. package/src/components/ChatLauncher/ChatLauncher.tsx +202 -0
  257. package/src/components/ChatLauncher/index.ts +2 -0
  258. package/src/components/ChatLauncher/isAtBottom.ts +12 -0
  259. package/src/components/Checkbox/Checkbox.module.scss +147 -0
  260. package/src/components/Checkbox/Checkbox.tokens.scss +44 -0
  261. package/src/components/Checkbox/Checkbox.tsx +188 -0
  262. package/src/components/Checkbox/index.ts +2 -0
  263. package/src/components/CircularProgress/CircularProgress.module.scss +133 -0
  264. package/src/components/CircularProgress/CircularProgress.tokens.scss +40 -0
  265. package/src/components/CircularProgress/CircularProgress.tsx +139 -0
  266. package/src/components/CircularProgress/index.ts +7 -0
  267. package/src/components/Cluster/Cluster.module.scss +145 -0
  268. package/src/components/Cluster/Cluster.tokens.scss +11 -0
  269. package/src/components/Cluster/Cluster.tsx +215 -0
  270. package/src/components/Cluster/index.ts +2 -0
  271. package/src/components/Code/Code.module.scss +28 -0
  272. package/src/components/Code/Code.tokens.scss +15 -0
  273. package/src/components/Code/Code.tsx +44 -0
  274. package/src/components/Code/index.ts +2 -0
  275. package/src/components/CodeBlock/CodeBlock.module.scss +146 -0
  276. package/src/components/CodeBlock/CodeBlock.tokens.scss +27 -0
  277. package/src/components/CodeBlock/CodeBlock.tsx +274 -0
  278. package/src/components/CodeBlock/highlight.ts +179 -0
  279. package/src/components/CodeBlock/index.ts +8 -0
  280. package/src/components/CodeBlock/sampleSync.ts +42 -0
  281. package/src/components/ColorPicker/ColorPicker.module.scss +286 -0
  282. package/src/components/ColorPicker/ColorPicker.tokens.scss +60 -0
  283. package/src/components/ColorPicker/ColorPicker.tsx +367 -0
  284. package/src/components/ColorPicker/ColorPickerPanel.tsx +265 -0
  285. package/src/components/ColorPicker/SVSquare.tsx +189 -0
  286. package/src/components/ColorPicker/colorMath.ts +141 -0
  287. package/src/components/ColorPicker/index.ts +6 -0
  288. package/src/components/ConfirmationPopover/ConfirmationPopover.module.scss +39 -0
  289. package/src/components/ConfirmationPopover/ConfirmationPopover.tokens.scss +13 -0
  290. package/src/components/ConfirmationPopover/ConfirmationPopover.tsx +395 -0
  291. package/src/components/ConfirmationPopover/index.ts +2 -0
  292. package/src/components/Constrain/Constrain.module.scss +99 -0
  293. package/src/components/Constrain/Constrain.tsx +79 -0
  294. package/src/components/Constrain/index.ts +2 -0
  295. package/src/components/CurrencySelect/CurrencySelect.module.scss +7 -0
  296. package/src/components/CurrencySelect/CurrencySelect.tsx +167 -0
  297. package/src/components/CurrencySelect/index.ts +3 -0
  298. package/src/components/CursorPagination/CursorPagination.module.scss +69 -0
  299. package/src/components/CursorPagination/CursorPagination.tokens.scss +32 -0
  300. package/src/components/CursorPagination/CursorPagination.tsx +121 -0
  301. package/src/components/CursorPagination/index.ts +2 -0
  302. package/src/components/DashboardCanvas/DashboardCanvas.module.scss +360 -0
  303. package/src/components/DashboardCanvas/DashboardCanvas.tokens.scss +48 -0
  304. package/src/components/DashboardCanvas/DashboardCanvas.tsx +1270 -0
  305. package/src/components/DashboardCanvas/DashboardCanvasItem.tsx +140 -0
  306. package/src/components/DashboardCanvas/DashboardCanvasSection.tsx +174 -0
  307. package/src/components/DashboardCanvas/engine.ts +363 -0
  308. package/src/components/DashboardCanvas/index.ts +9 -0
  309. package/src/components/DashboardWidget/DashboardWidget.module.scss +100 -0
  310. package/src/components/DashboardWidget/DashboardWidget.tokens.scss +16 -0
  311. package/src/components/DashboardWidget/DashboardWidget.tsx +188 -0
  312. package/src/components/DashboardWidget/index.ts +7 -0
  313. package/src/components/DataTable/BodyRow.tsx +197 -0
  314. package/src/components/DataTable/ColumnVisibilityTrigger.module.scss +7 -0
  315. package/src/components/DataTable/ColumnVisibilityTrigger.tsx +105 -0
  316. package/src/components/DataTable/DataTable.module.scss +511 -0
  317. package/src/components/DataTable/DataTable.tokens.scss +80 -0
  318. package/src/components/DataTable/DataTable.tsx +734 -0
  319. package/src/components/DataTable/HeaderCell.module.scss +215 -0
  320. package/src/components/DataTable/HeaderCell.tsx +440 -0
  321. package/src/components/DataTable/columnShift.ts +117 -0
  322. package/src/components/DataTable/index.ts +23 -0
  323. package/src/components/DataTable/pinStyle.ts +47 -0
  324. package/src/components/DataTable/reorderColumns.ts +66 -0
  325. package/src/components/DataTable/types.ts +289 -0
  326. package/src/components/DataTable/useColumnDragShift.ts +216 -0
  327. package/src/components/DataTable/useDataTable.ts +372 -0
  328. package/src/components/DataTable/useResizeHandle.ts +97 -0
  329. package/src/components/DatePicker/DatePicker.module.scss +180 -0
  330. package/src/components/DatePicker/DatePicker.tokens.scss +152 -0
  331. package/src/components/DatePicker/DatePicker.tsx +664 -0
  332. package/src/components/DatePicker/DatePickerGrid.module.scss +172 -0
  333. package/src/components/DatePicker/DatePickerGrid.tsx +341 -0
  334. package/src/components/DatePicker/InlineDatePicker.module.scss +32 -0
  335. package/src/components/DatePicker/InlineDatePicker.tsx +201 -0
  336. package/src/components/DatePicker/index.ts +4 -0
  337. package/src/components/DatePicker/utils.ts +364 -0
  338. package/src/components/DateRangePicker/DateRangePicker.module.scss +237 -0
  339. package/src/components/DateRangePicker/DateRangePicker.tokens.scss +78 -0
  340. package/src/components/DateRangePicker/DateRangePicker.tsx +720 -0
  341. package/src/components/DateRangePicker/InlineDateRangePicker.module.scss +94 -0
  342. package/src/components/DateRangePicker/InlineDateRangePicker.tsx +376 -0
  343. package/src/components/DateRangePicker/index.ts +5 -0
  344. package/src/components/DateRangePicker/utils.ts +151 -0
  345. package/src/components/DateStrip/DateStrip.module.scss +78 -0
  346. package/src/components/DateStrip/DateStrip.tokens.scss +23 -0
  347. package/src/components/DateStrip/DateStrip.tsx +205 -0
  348. package/src/components/DateStrip/index.ts +2 -0
  349. package/src/components/DefinitionList/DefinitionList.module.scss +102 -0
  350. package/src/components/DefinitionList/DefinitionList.tokens.scss +29 -0
  351. package/src/components/DefinitionList/DefinitionList.tsx +198 -0
  352. package/src/components/DefinitionList/index.ts +9 -0
  353. package/src/components/Divider/Divider.module.scss +144 -0
  354. package/src/components/Divider/Divider.tokens.scss +21 -0
  355. package/src/components/Divider/Divider.tsx +103 -0
  356. package/src/components/Divider/index.ts +2 -0
  357. package/src/components/Dot/Dot.module.scss +40 -0
  358. package/src/components/Dot/Dot.tokens.scss +4 -0
  359. package/src/components/Dot/Dot.tsx +45 -0
  360. package/src/components/Dot/index.ts +2 -0
  361. package/src/components/Drawer/Body.tsx +23 -0
  362. package/src/components/Drawer/Close.tsx +35 -0
  363. package/src/components/Drawer/Content.tsx +93 -0
  364. package/src/components/Drawer/Drawer.module.scss +232 -0
  365. package/src/components/Drawer/Drawer.tokens.scss +38 -0
  366. package/src/components/Drawer/Drawer.tsx +23 -0
  367. package/src/components/Drawer/DrawerRoot.tsx +190 -0
  368. package/src/components/Drawer/Footer.tsx +24 -0
  369. package/src/components/Drawer/Header.tsx +64 -0
  370. package/src/components/Drawer/Overlay.tsx +82 -0
  371. package/src/components/Drawer/context.ts +44 -0
  372. package/src/components/Drawer/index.ts +12 -0
  373. package/src/components/Drawer/useDragToClose.ts +149 -0
  374. package/src/components/DropdownMenu/CheckboxItem.tsx +144 -0
  375. package/src/components/DropdownMenu/Content.tsx +419 -0
  376. package/src/components/DropdownMenu/DropdownMenu.module.scss +280 -0
  377. package/src/components/DropdownMenu/DropdownMenu.tokens.scss +88 -0
  378. package/src/components/DropdownMenu/DropdownMenu.tsx +43 -0
  379. package/src/components/DropdownMenu/Group.tsx +76 -0
  380. package/src/components/DropdownMenu/Item.tsx +148 -0
  381. package/src/components/DropdownMenu/ItemIndicator.tsx +30 -0
  382. package/src/components/DropdownMenu/Radio.tsx +178 -0
  383. package/src/components/DropdownMenu/Root.tsx +100 -0
  384. package/src/components/DropdownMenu/Sub.tsx +332 -0
  385. package/src/components/DropdownMenu/Trigger.tsx +76 -0
  386. package/src/components/DropdownMenu/context.ts +65 -0
  387. package/src/components/DropdownMenu/index.ts +20 -0
  388. package/src/components/EmojiPicker/EmojiPicker.module.scss +84 -0
  389. package/src/components/EmojiPicker/EmojiPicker.tokens.scss +24 -0
  390. package/src/components/EmojiPicker/EmojiPicker.tsx +341 -0
  391. package/src/components/EmojiPicker/emojiData.ts +245 -0
  392. package/src/components/EmojiPicker/index.ts +3 -0
  393. package/src/components/EmptyState/EmptyState.module.scss +102 -0
  394. package/src/components/EmptyState/EmptyState.tokens.scss +28 -0
  395. package/src/components/EmptyState/EmptyState.tsx +112 -0
  396. package/src/components/EmptyState/index.ts +7 -0
  397. package/src/components/EntityChip/EntityChip.module.scss +275 -0
  398. package/src/components/EntityChip/EntityChip.tokens.scss +66 -0
  399. package/src/components/EntityChip/EntityChip.tsx +649 -0
  400. package/src/components/EntityChip/index.ts +10 -0
  401. package/src/components/ErrorState/ErrorState.module.scss +105 -0
  402. package/src/components/ErrorState/ErrorState.tokens.scss +32 -0
  403. package/src/components/ErrorState/ErrorState.tsx +125 -0
  404. package/src/components/ErrorState/index.ts +8 -0
  405. package/src/components/Field/Field.module.scss +46 -0
  406. package/src/components/Field/Field.tsx +185 -0
  407. package/src/components/Field/index.ts +2 -0
  408. package/src/components/FileUpload/FileUpload.module.scss +187 -0
  409. package/src/components/FileUpload/FileUpload.tokens.scss +81 -0
  410. package/src/components/FileUpload/FileUpload.tsx +569 -0
  411. package/src/components/FileUpload/formatBytes.ts +34 -0
  412. package/src/components/FileUpload/iconForFile.ts +40 -0
  413. package/src/components/FileUpload/index.ts +2 -0
  414. package/src/components/FilterChip/FilterChip.module.scss +61 -0
  415. package/src/components/FilterChip/FilterChip.tokens.scss +25 -0
  416. package/src/components/FilterChip/FilterChip.tsx +208 -0
  417. package/src/components/FilterChip/index.ts +5 -0
  418. package/src/components/FlowCanvas/FlowCanvas.module.scss +329 -0
  419. package/src/components/FlowCanvas/FlowCanvas.tokens.scss +45 -0
  420. package/src/components/FlowCanvas/FlowCanvas.tsx +1867 -0
  421. package/src/components/FlowCanvas/FlowControls.tsx +46 -0
  422. package/src/components/FlowCanvas/FlowEdge.tsx +58 -0
  423. package/src/components/FlowCanvas/FlowNode.tsx +76 -0
  424. package/src/components/FlowCanvas/edgePath.ts +85 -0
  425. package/src/components/FlowCanvas/index.ts +4 -0
  426. package/src/components/FlowCanvas/layout.ts +148 -0
  427. package/src/components/FlowCanvas/spatialNav.ts +76 -0
  428. package/src/components/FlowCanvas/types.ts +59 -0
  429. package/src/components/FlowCanvas/useViewport.ts +122 -0
  430. package/src/components/FormRow/FormRow.module.scss +2 -0
  431. package/src/components/FormRow/FormRow.tsx +37 -0
  432. package/src/components/FormRow/index.ts +2 -0
  433. package/src/components/FormSection/FormSection.module.scss +24 -0
  434. package/src/components/FormSection/FormSection.tsx +46 -0
  435. package/src/components/FormSection/index.ts +2 -0
  436. package/src/components/Grid/Grid.module.scss +162 -0
  437. package/src/components/Grid/Grid.tokens.scss +13 -0
  438. package/src/components/Grid/Grid.tsx +226 -0
  439. package/src/components/Grid/GridItem.tsx +77 -0
  440. package/src/components/Grid/index.ts +11 -0
  441. package/src/components/Highlight/Highlight.module.scss +43 -0
  442. package/src/components/Highlight/Highlight.tokens.scss +35 -0
  443. package/src/components/Highlight/Highlight.tsx +164 -0
  444. package/src/components/Highlight/HighlightOverlay.tsx +100 -0
  445. package/src/components/Highlight/index.ts +2 -0
  446. package/src/components/HighlightedText/HighlightedText.module.scss +11 -0
  447. package/src/components/HighlightedText/HighlightedText.tokens.scss +9 -0
  448. package/src/components/HighlightedText/HighlightedText.tsx +50 -0
  449. package/src/components/HighlightedText/highlightRanges.ts +44 -0
  450. package/src/components/HighlightedText/index.ts +2 -0
  451. package/src/components/IconPicker/IconPicker.module.scss +175 -0
  452. package/src/components/IconPicker/IconPicker.tokens.scss +40 -0
  453. package/src/components/IconPicker/IconPicker.tsx +629 -0
  454. package/src/components/IconPicker/index.ts +9 -0
  455. package/src/components/IconTile/IconTile.module.scss +57 -0
  456. package/src/components/IconTile/IconTile.tokens.scss +16 -0
  457. package/src/components/IconTile/IconTile.tsx +91 -0
  458. package/src/components/IconTile/index.ts +2 -0
  459. package/src/components/Image/Image.module.scss +266 -0
  460. package/src/components/Image/Image.tokens.scss +55 -0
  461. package/src/components/Image/Image.tsx +342 -0
  462. package/src/components/Image/index.ts +2 -0
  463. package/src/components/ImageCrop/ImageCrop.module.scss +274 -0
  464. package/src/components/ImageCrop/ImageCrop.tokens.scss +33 -0
  465. package/src/components/ImageCrop/ImageCrop.tsx +542 -0
  466. package/src/components/ImageCrop/cropGeometry.ts +120 -0
  467. package/src/components/ImageCrop/extractCropBlob.ts +140 -0
  468. package/src/components/ImageCrop/index.ts +11 -0
  469. package/src/components/ImageCrop/useCropPreview.ts +161 -0
  470. package/src/components/Indent/Indent.module.scss +33 -0
  471. package/src/components/Indent/Indent.tokens.scss +10 -0
  472. package/src/components/Indent/Indent.tsx +46 -0
  473. package/src/components/Indent/index.ts +2 -0
  474. package/src/components/Input/Input.module.scss +99 -0
  475. package/src/components/Input/Input.tokens.scss +54 -0
  476. package/src/components/Input/Input.tsx +105 -0
  477. package/src/components/Input/Suggestions.tsx +260 -0
  478. package/src/components/Input/index.ts +2 -0
  479. package/src/components/Kanban/Kanban.module.scss +39 -0
  480. package/src/components/Kanban/Kanban.tokens.scss +15 -0
  481. package/src/components/Kanban/Kanban.tsx +951 -0
  482. package/src/components/Kanban/index.ts +7 -0
  483. package/src/components/Kbd/Kbd.module.scss +47 -0
  484. package/src/components/Kbd/Kbd.tokens.scss +26 -0
  485. package/src/components/Kbd/Kbd.tsx +73 -0
  486. package/src/components/Kbd/index.ts +2 -0
  487. package/src/components/Lightbox/Lightbox.module.scss +283 -0
  488. package/src/components/Lightbox/Lightbox.tokens.scss +36 -0
  489. package/src/components/Lightbox/Lightbox.tsx +506 -0
  490. package/src/components/Lightbox/index.ts +2 -0
  491. package/src/components/Link/Link.module.scss +78 -0
  492. package/src/components/Link/Link.tokens.scss +28 -0
  493. package/src/components/Link/Link.tsx +114 -0
  494. package/src/components/Link/index.ts +2 -0
  495. package/src/components/LinkCard/LinkCard.module.scss +92 -0
  496. package/src/components/LinkCard/LinkCard.tokens.scss +9 -0
  497. package/src/components/LinkCard/LinkCard.tsx +72 -0
  498. package/src/components/LinkCard/index.ts +2 -0
  499. package/src/components/LiquidEditor/AutocompleteMenu.tsx +133 -0
  500. package/src/components/LiquidEditor/HighlightLayer.tsx +53 -0
  501. package/src/components/LiquidEditor/InsertVariableMenu.tsx +81 -0
  502. package/src/components/LiquidEditor/LiquidEditor.module.scss +339 -0
  503. package/src/components/LiquidEditor/LiquidEditor.tokens.scss +81 -0
  504. package/src/components/LiquidEditor/LiquidEditor.tsx +412 -0
  505. package/src/components/LiquidEditor/PreviewPane.tsx +29 -0
  506. package/src/components/LiquidEditor/caretCoordinates.ts +97 -0
  507. package/src/components/LiquidEditor/index.ts +7 -0
  508. package/src/components/LiquidEditor/liquidFilters.ts +23 -0
  509. package/src/components/LiquidEditor/liquidTokenizer.ts +235 -0
  510. package/src/components/LiquidEditor/types.ts +101 -0
  511. package/src/components/LiquidEditor/useLiquidAutocomplete.ts +178 -0
  512. package/src/components/List/List.module.scss +105 -0
  513. package/src/components/List/List.tokens.scss +42 -0
  514. package/src/components/List/List.tsx +124 -0
  515. package/src/components/List/index.ts +9 -0
  516. package/src/components/LiveRegion/LiveRegion.module.scss +3 -0
  517. package/src/components/LiveRegion/LiveRegion.tsx +116 -0
  518. package/src/components/LiveRegion/index.ts +2 -0
  519. package/src/components/Logo/Logo.module.scss +139 -0
  520. package/src/components/Logo/Logo.tokens.scss +14 -0
  521. package/src/components/Logo/Logo.tsx +126 -0
  522. package/src/components/Logo/index.ts +2 -0
  523. package/src/components/Masonry/Masonry.module.scss +42 -0
  524. package/src/components/Masonry/Masonry.tokens.scss +8 -0
  525. package/src/components/Masonry/Masonry.tsx +136 -0
  526. package/src/components/Masonry/index.ts +2 -0
  527. package/src/components/Masonry/masonryUtils.ts +42 -0
  528. package/src/components/MediaTile/MediaTile.module.scss +183 -0
  529. package/src/components/MediaTile/MediaTile.tokens.scss +60 -0
  530. package/src/components/MediaTile/MediaTile.tsx +208 -0
  531. package/src/components/MediaTile/index.ts +8 -0
  532. package/src/components/Modal/Body.tsx +27 -0
  533. package/src/components/Modal/Close.tsx +45 -0
  534. package/src/components/Modal/Content.tsx +98 -0
  535. package/src/components/Modal/Footer.tsx +28 -0
  536. package/src/components/Modal/Header.tsx +51 -0
  537. package/src/components/Modal/Modal.module.scss +262 -0
  538. package/src/components/Modal/Modal.tokens.scss +50 -0
  539. package/src/components/Modal/Modal.tsx +23 -0
  540. package/src/components/Modal/ModalRoot.tsx +299 -0
  541. package/src/components/Modal/Overlay.tsx +101 -0
  542. package/src/components/Modal/context.ts +60 -0
  543. package/src/components/Modal/index.ts +11 -0
  544. package/src/components/MoneyInput/MoneyInput.module.scss +57 -0
  545. package/src/components/MoneyInput/MoneyInput.tsx +433 -0
  546. package/src/components/MoneyInput/index.ts +2 -0
  547. package/src/components/OptionsPicker/OptionsPicker.module.scss +216 -0
  548. package/src/components/OptionsPicker/OptionsPicker.tokens.scss +68 -0
  549. package/src/components/OptionsPicker/OptionsPicker.tsx +936 -0
  550. package/src/components/OptionsPicker/index.ts +9 -0
  551. package/src/components/OtpInput/OtpInput.module.scss +69 -0
  552. package/src/components/OtpInput/OtpInput.tokens.scss +45 -0
  553. package/src/components/OtpInput/OtpInput.tsx +368 -0
  554. package/src/components/OtpInput/index.ts +2 -0
  555. package/src/components/Page/Page.module.scss +30 -0
  556. package/src/components/Page/Page.tokens.scss +11 -0
  557. package/src/components/Page/Page.tsx +53 -0
  558. package/src/components/Page/index.ts +2 -0
  559. package/src/components/PageHeader/PageHeader.module.scss +197 -0
  560. package/src/components/PageHeader/PageHeader.tokens.scss +41 -0
  561. package/src/components/PageHeader/PageHeader.tsx +310 -0
  562. package/src/components/PageHeader/index.ts +20 -0
  563. package/src/components/Pagination/Pagination.module.scss +117 -0
  564. package/src/components/Pagination/Pagination.tokens.scss +54 -0
  565. package/src/components/Pagination/Pagination.tsx +165 -0
  566. package/src/components/Pagination/index.ts +4 -0
  567. package/src/components/Pagination/paginationRange.ts +72 -0
  568. package/src/components/PasswordInput/PasswordInput.module.scss +120 -0
  569. package/src/components/PasswordInput/PasswordInput.tokens.scss +44 -0
  570. package/src/components/PasswordInput/PasswordInput.tsx +210 -0
  571. package/src/components/PasswordInput/index.ts +2 -0
  572. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.module.scss +80 -0
  573. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tokens.scss +40 -0
  574. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tsx +96 -0
  575. package/src/components/PasswordStrengthMeter/index.ts +2 -0
  576. package/src/components/PersonDisplay/PersonDisplay.module.scss +180 -0
  577. package/src/components/PersonDisplay/PersonDisplay.tokens.scss +35 -0
  578. package/src/components/PersonDisplay/PersonDisplay.tsx +420 -0
  579. package/src/components/PersonDisplay/index.ts +10 -0
  580. package/src/components/PhoneInput/PhoneInput.module.scss +23 -0
  581. package/src/components/PhoneInput/PhoneInput.tsx +271 -0
  582. package/src/components/PhoneInput/index.ts +4 -0
  583. package/src/components/PhoneInput/phone.ts +128 -0
  584. package/src/components/PillMenu/PillMenu.module.scss +117 -0
  585. package/src/components/PillMenu/PillMenu.tokens.scss +22 -0
  586. package/src/components/PillMenu/PillMenu.tsx +324 -0
  587. package/src/components/PillMenu/index.ts +2 -0
  588. package/src/components/Popover/Anchor.tsx +37 -0
  589. package/src/components/Popover/Close.tsx +45 -0
  590. package/src/components/Popover/Content.tsx +213 -0
  591. package/src/components/Popover/Heading.tsx +33 -0
  592. package/src/components/Popover/Popover.module.scss +177 -0
  593. package/src/components/Popover/Popover.tokens.scss +22 -0
  594. package/src/components/Popover/Popover.tsx +23 -0
  595. package/src/components/Popover/PopoverRoot.tsx +75 -0
  596. package/src/components/Popover/Trigger.tsx +86 -0
  597. package/src/components/Popover/context.ts +22 -0
  598. package/src/components/Popover/index.ts +7 -0
  599. package/src/components/Progress/Progress.module.scss +110 -0
  600. package/src/components/Progress/Progress.tokens.scss +44 -0
  601. package/src/components/Progress/Progress.tsx +129 -0
  602. package/src/components/Progress/index.ts +2 -0
  603. package/src/components/QrCode/QrCode.module.scss +97 -0
  604. package/src/components/QrCode/QrCode.tokens.scss +17 -0
  605. package/src/components/QrCode/QrCode.tsx +233 -0
  606. package/src/components/QrCode/index.ts +2 -0
  607. package/src/components/QrCode/qr.ts +161 -0
  608. package/src/components/Radio/Radio.module.scss +175 -0
  609. package/src/components/Radio/Radio.tokens.scss +59 -0
  610. package/src/components/Radio/Radio.tsx +127 -0
  611. package/src/components/Radio/RadioGroup.module.scss +42 -0
  612. package/src/components/Radio/RadioGroup.tsx +120 -0
  613. package/src/components/Radio/RadioGroupContext.tsx +30 -0
  614. package/src/components/Radio/index.ts +4 -0
  615. package/src/components/Rail/Rail.module.scss +510 -0
  616. package/src/components/Rail/Rail.tokens.scss +92 -0
  617. package/src/components/Rail/Rail.tsx +287 -0
  618. package/src/components/Rail/RailCollapseToggle.tsx +57 -0
  619. package/src/components/Rail/RailFooter.tsx +17 -0
  620. package/src/components/Rail/RailGroup.tsx +728 -0
  621. package/src/components/Rail/RailGroupContext.ts +9 -0
  622. package/src/components/Rail/RailHeader.tsx +23 -0
  623. package/src/components/Rail/RailItem.tsx +119 -0
  624. package/src/components/Rail/RailSection.tsx +39 -0
  625. package/src/components/Rail/RailSpacer.tsx +19 -0
  626. package/src/components/Rail/index.ts +9 -0
  627. package/src/components/RelativeDateInput/RelativeDateInput.module.scss +15 -0
  628. package/src/components/RelativeDateInput/RelativeDateInput.tokens.scss +6 -0
  629. package/src/components/RelativeDateInput/RelativeDateInput.tsx +474 -0
  630. package/src/components/RelativeDateInput/index.ts +10 -0
  631. package/src/components/RelativeDateInput/relativeDate.ts +127 -0
  632. package/src/components/RichText/RichText.module.scss +5 -0
  633. package/src/components/RichText/RichText.tsx +70 -0
  634. package/src/components/RichText/RichTextAttachment.module.scss +82 -0
  635. package/src/components/RichText/RichTextAttachment.tsx +122 -0
  636. package/src/components/RichText/_prose.scss +79 -0
  637. package/src/components/RichText/attachmentIcon.tsx +24 -0
  638. package/src/components/RichText/engine/attachment.ts +154 -0
  639. package/src/components/RichText/engine/autolink.ts +64 -0
  640. package/src/components/RichText/engine/blockUnit.ts +174 -0
  641. package/src/components/RichText/engine/colorMarks.ts +85 -0
  642. package/src/components/RichText/engine/escape.ts +11 -0
  643. package/src/components/RichText/engine/fromHtml.ts +353 -0
  644. package/src/components/RichText/engine/fromMarkdown.ts +20 -0
  645. package/src/components/RichText/engine/inlines.ts +82 -0
  646. package/src/components/RichText/engine/listDepths.ts +32 -0
  647. package/src/components/RichText/engine/marks.ts +80 -0
  648. package/src/components/RichText/engine/mdToHtml.ts +178 -0
  649. package/src/components/RichText/engine/model.ts +157 -0
  650. package/src/components/RichText/engine/position.ts +118 -0
  651. package/src/components/RichText/engine/renderDoc.tsx +395 -0
  652. package/src/components/RichText/engine/renderLink.ts +15 -0
  653. package/src/components/RichText/engine/renderMention.ts +16 -0
  654. package/src/components/RichText/engine/safeHref.ts +22 -0
  655. package/src/components/RichText/engine/toHtml.ts +154 -0
  656. package/src/components/RichText/engine/toMarkdown.ts +97 -0
  657. package/src/components/RichText/engine/transforms.ts +434 -0
  658. package/src/components/RichText/imageMaxHeightStyle.ts +10 -0
  659. package/src/components/RichText/index.ts +31 -0
  660. package/src/components/RichTextEditor/RichTextAttachmentConfig.tsx +264 -0
  661. package/src/components/RichTextEditor/RichTextBlockControls.tsx +365 -0
  662. package/src/components/RichTextEditor/RichTextBlockMenu.tsx +162 -0
  663. package/src/components/RichTextEditor/RichTextColorMenu.tsx +115 -0
  664. package/src/components/RichTextEditor/RichTextEditor.module.scss +298 -0
  665. package/src/components/RichTextEditor/RichTextEditor.tsx +1910 -0
  666. package/src/components/RichTextEditor/RichTextImageResizer.tsx +131 -0
  667. package/src/components/RichTextEditor/RichTextLinkEditor.tsx +151 -0
  668. package/src/components/RichTextEditor/RichTextMentionMenu.tsx +99 -0
  669. package/src/components/RichTextEditor/RichTextToolbar.tsx +379 -0
  670. package/src/components/RichTextEditor/autolinkInput.ts +65 -0
  671. package/src/components/RichTextEditor/blockDrop.ts +9 -0
  672. package/src/components/RichTextEditor/blockReflow.ts +62 -0
  673. package/src/components/RichTextEditor/commands.ts +300 -0
  674. package/src/components/RichTextEditor/history.ts +93 -0
  675. package/src/components/RichTextEditor/icons.tsx +152 -0
  676. package/src/components/RichTextEditor/imageSize.ts +70 -0
  677. package/src/components/RichTextEditor/index.ts +5 -0
  678. package/src/components/RichTextEditor/input.ts +209 -0
  679. package/src/components/RichTextEditor/inputRules.ts +71 -0
  680. package/src/components/RichTextEditor/links.ts +103 -0
  681. package/src/components/RichTextEditor/mentionContext.ts +37 -0
  682. package/src/components/RichTextEditor/mentions.ts +28 -0
  683. package/src/components/RichTextEditor/preventSelectionLoss.ts +15 -0
  684. package/src/components/RichTextEditor/selection.ts +415 -0
  685. package/src/components/RichTextEditor/shortcuts.ts +44 -0
  686. package/src/components/RichTextEditor/useAnchoredFloating.ts +50 -0
  687. package/src/components/RichTextEditor/useAttachmentConfig.ts +134 -0
  688. package/src/components/RichTextEditor/useDismissOnOutsidePointerDown.ts +26 -0
  689. package/src/components/RichTextEditor/useLinkEditor.ts +107 -0
  690. package/src/components/RichTextEditor/useMention.ts +226 -0
  691. package/src/components/RichTextEditor/useOverlayRect.ts +73 -0
  692. package/src/components/RichTextEditor/useUpload.ts +246 -0
  693. package/src/components/Screen/Screen.module.scss +46 -0
  694. package/src/components/Screen/Screen.tokens.scss +20 -0
  695. package/src/components/Screen/Screen.tsx +97 -0
  696. package/src/components/Screen/index.ts +2 -0
  697. package/src/components/ScrollArea/ScrollArea.module.scss +39 -0
  698. package/src/components/ScrollArea/ScrollArea.tokens.scss +15 -0
  699. package/src/components/ScrollArea/ScrollArea.tsx +154 -0
  700. package/src/components/ScrollArea/index.ts +2 -0
  701. package/src/components/Select/Chip.tsx +45 -0
  702. package/src/components/Select/Empty.tsx +39 -0
  703. package/src/components/Select/Error.tsx +51 -0
  704. package/src/components/Select/HiddenInputs.tsx +44 -0
  705. package/src/components/Select/Listbox.tsx +557 -0
  706. package/src/components/Select/Loading.tsx +30 -0
  707. package/src/components/Select/Select.module.scss +512 -0
  708. package/src/components/Select/Select.tokens.scss +140 -0
  709. package/src/components/Select/Select.tsx +685 -0
  710. package/src/components/Select/Trigger.tsx +952 -0
  711. package/src/components/Select/context.ts +101 -0
  712. package/src/components/Select/emptyStateText.ts +19 -0
  713. package/src/components/Select/index.ts +9 -0
  714. package/src/components/Select/useSelectState.ts +157 -0
  715. package/src/components/Select/utils-types.ts +7 -0
  716. package/src/components/Select/utils.ts +122 -0
  717. package/src/components/SettingRow/SettingRow.module.scss +166 -0
  718. package/src/components/SettingRow/SettingRow.tokens.scss +37 -0
  719. package/src/components/SettingRow/SettingRow.tsx +242 -0
  720. package/src/components/SettingRow/index.ts +7 -0
  721. package/src/components/Skeleton/Skeleton.module.scss +55 -0
  722. package/src/components/Skeleton/Skeleton.tokens.scss +17 -0
  723. package/src/components/Skeleton/Skeleton.tsx +131 -0
  724. package/src/components/Skeleton/index.ts +4 -0
  725. package/src/components/Skeleton/useSkeletonVisibility.ts +95 -0
  726. package/src/components/Slider/Slider.module.scss +293 -0
  727. package/src/components/Slider/Slider.tokens.scss +98 -0
  728. package/src/components/Slider/Slider.tsx +624 -0
  729. package/src/components/Slider/index.ts +9 -0
  730. package/src/components/SlotGrid/SlotGrid.module.scss +61 -0
  731. package/src/components/SlotGrid/SlotGrid.tokens.scss +21 -0
  732. package/src/components/SlotGrid/SlotGrid.tsx +111 -0
  733. package/src/components/SlotGrid/index.ts +2 -0
  734. package/src/components/SocialButton/SocialButton.module.scss +4 -0
  735. package/src/components/SocialButton/SocialButton.tsx +40 -0
  736. package/src/components/SocialButton/index.ts +2 -0
  737. package/src/components/Sortable/Sortable.module.scss +177 -0
  738. package/src/components/Sortable/Sortable.tokens.scss +27 -0
  739. package/src/components/Sortable/Sortable.tsx +572 -0
  740. package/src/components/Sortable/containerAwareCollision.ts +125 -0
  741. package/src/components/Sortable/index.ts +13 -0
  742. package/src/components/SortableGroup/SortableGroup.module.scss +23 -0
  743. package/src/components/SortableGroup/SortableGroup.tsx +315 -0
  744. package/src/components/SortableGroup/index.ts +4 -0
  745. package/src/components/SortableGroup/moveSortableItem.ts +39 -0
  746. package/src/components/Sparkline/Sparkline.module.scss +28 -0
  747. package/src/components/Sparkline/Sparkline.tokens.scss +7 -0
  748. package/src/components/Sparkline/Sparkline.tsx +133 -0
  749. package/src/components/Sparkline/index.ts +2 -0
  750. package/src/components/Sparkline/sparklineModel.ts +119 -0
  751. package/src/components/Split/Split.module.scss +158 -0
  752. package/src/components/Split/Split.tokens.scss +10 -0
  753. package/src/components/Split/Split.tsx +231 -0
  754. package/src/components/Split/index.ts +2 -0
  755. package/src/components/Stack/Stack.module.scss +67 -0
  756. package/src/components/Stack/Stack.tokens.scss +11 -0
  757. package/src/components/Stack/Stack.tsx +100 -0
  758. package/src/components/Stack/index.ts +2 -0
  759. package/src/components/StagePath/StagePath.module.scss +255 -0
  760. package/src/components/StagePath/StagePath.tokens.scss +43 -0
  761. package/src/components/StagePath/StagePath.tsx +176 -0
  762. package/src/components/StagePath/index.ts +2 -0
  763. package/src/components/StatGroup/StatGroup.module.scss +6 -0
  764. package/src/components/StatGroup/StatGroup.tsx +70 -0
  765. package/src/components/StatGroup/StatGroupContext.ts +10 -0
  766. package/src/components/StatGroup/StatTile.module.scss +99 -0
  767. package/src/components/StatGroup/StatTile.tokens.scss +35 -0
  768. package/src/components/StatGroup/StatTile.tsx +143 -0
  769. package/src/components/StatGroup/index.ts +4 -0
  770. package/src/components/Sticky/Sticky.module.scss +98 -0
  771. package/src/components/Sticky/Sticky.tokens.scss +17 -0
  772. package/src/components/Sticky/Sticky.tsx +103 -0
  773. package/src/components/Sticky/index.ts +2 -0
  774. package/src/components/Switch/Switch.module.scss +182 -0
  775. package/src/components/Switch/Switch.tokens.scss +59 -0
  776. package/src/components/Switch/Switch.tsx +214 -0
  777. package/src/components/Switch/index.ts +2 -0
  778. package/src/components/Table/Table.module.scss +308 -0
  779. package/src/components/Table/Table.tokens.scss +79 -0
  780. package/src/components/Table/Table.tsx +381 -0
  781. package/src/components/Table/index.ts +15 -0
  782. package/src/components/TableOfContents/TableOfContents.module.scss +83 -0
  783. package/src/components/TableOfContents/TableOfContents.tokens.scss +26 -0
  784. package/src/components/TableOfContents/TableOfContents.tsx +192 -0
  785. package/src/components/TableOfContents/activeSection.ts +18 -0
  786. package/src/components/TableOfContents/index.ts +2 -0
  787. package/src/components/Tabs/Tabs.module.scss +359 -0
  788. package/src/components/Tabs/Tabs.tokens.scss +50 -0
  789. package/src/components/Tabs/Tabs.tsx +538 -0
  790. package/src/components/Tabs/index.ts +2 -0
  791. package/src/components/Text/Text.module.scss +115 -0
  792. package/src/components/Text/Text.tokens.scss +55 -0
  793. package/src/components/Text/Text.tsx +197 -0
  794. package/src/components/Text/index.ts +2 -0
  795. package/src/components/Textarea/Textarea.module.scss +94 -0
  796. package/src/components/Textarea/Textarea.tokens.scss +48 -0
  797. package/src/components/Textarea/Textarea.tsx +246 -0
  798. package/src/components/Textarea/index.ts +2 -0
  799. package/src/components/Thread/Thread.module.scss +161 -0
  800. package/src/components/Thread/Thread.tokens.scss +32 -0
  801. package/src/components/Thread/Thread.tsx +176 -0
  802. package/src/components/Thread/index.ts +2 -0
  803. package/src/components/TimeField/TimeField.module.scss +232 -0
  804. package/src/components/TimeField/TimeField.tsx +793 -0
  805. package/src/components/TimeField/index.ts +2 -0
  806. package/src/components/Timeline/Timeline.module.scss +58 -0
  807. package/src/components/Timeline/Timeline.tokens.scss +13 -0
  808. package/src/components/Timeline/Timeline.tsx +53 -0
  809. package/src/components/Timeline/index.ts +2 -0
  810. package/src/components/Title/Title.module.scss +84 -0
  811. package/src/components/Title/Title.tokens.scss +37 -0
  812. package/src/components/Title/Title.tsx +150 -0
  813. package/src/components/Title/index.ts +2 -0
  814. package/src/components/Toast/Toast.module.scss +299 -0
  815. package/src/components/Toast/Toast.tokens.scss +65 -0
  816. package/src/components/Toast/Toast.tsx +122 -0
  817. package/src/components/Toast/ToastViewport.tsx +166 -0
  818. package/src/components/Toast/api.ts +175 -0
  819. package/src/components/Toast/index.ts +5 -0
  820. package/src/components/Toast/store.ts +133 -0
  821. package/src/components/Toast/useToastTimer.ts +94 -0
  822. package/src/components/Tooltip/Tooltip.module.scss +99 -0
  823. package/src/components/Tooltip/Tooltip.tokens.scss +23 -0
  824. package/src/components/Tooltip/Tooltip.tsx +341 -0
  825. package/src/components/Tooltip/index.ts +2 -0
  826. package/src/components/TopBar/TopBar.module.scss +235 -0
  827. package/src/components/TopBar/TopBar.tokens.scss +79 -0
  828. package/src/components/TopBar/TopBar.tsx +87 -0
  829. package/src/components/TopBar/TopBarEnd.tsx +20 -0
  830. package/src/components/TopBar/TopBarIconButton.tsx +86 -0
  831. package/src/components/TopBar/TopBarSearch.tsx +319 -0
  832. package/src/components/TopBar/TopBarSearchPanel.tsx +268 -0
  833. package/src/components/TopBar/TopBarStart.tsx +20 -0
  834. package/src/components/TopBar/index.ts +11 -0
  835. package/src/components/Tour/Spotlight.tsx +121 -0
  836. package/src/components/Tour/Tour.module.scss +210 -0
  837. package/src/components/Tour/Tour.tokens.scss +58 -0
  838. package/src/components/Tour/Tour.tsx +617 -0
  839. package/src/components/Tour/index.ts +2 -0
  840. package/src/components/Tour/useTourTarget.ts +115 -0
  841. package/src/components/TreeView/TreeView.module.scss +268 -0
  842. package/src/components/TreeView/TreeView.tokens.scss +36 -0
  843. package/src/components/TreeView/TreeView.tsx +536 -0
  844. package/src/components/TreeView/index.ts +3 -0
  845. package/src/components/TreeView/treeModel.ts +224 -0
  846. package/src/components/VisuallyHidden/VisuallyHidden.module.scss +7 -0
  847. package/src/components/VisuallyHidden/VisuallyHidden.tsx +29 -0
  848. package/src/components/VisuallyHidden/index.ts +2 -0
  849. package/src/components/WidgetPreview/WidgetPreview.module.scss +11 -0
  850. package/src/components/WidgetPreview/WidgetPreview.tokens.scss +26 -0
  851. package/src/components/WidgetPreview/WidgetPreview.tsx +36 -0
  852. package/src/components/WidgetPreview/WidgetShape.module.scss +140 -0
  853. package/src/components/WidgetPreview/WidgetShape.tsx +159 -0
  854. package/src/components/WidgetPreview/index.ts +2 -0
  855. package/src/components/_internal/Trend.tsx +27 -0
  856. package/src/components/_internal/choiceTile.scss +74 -0
  857. package/src/components/_internal/collapse.scss +10 -0
  858. package/src/components/_internal/collapse.ts +58 -0
  859. package/src/components/_internal/currency.ts +257 -0
  860. package/src/components/_internal/dragAnnouncements.ts +200 -0
  861. package/src/components/_internal/fieldWiring.ts +225 -0
  862. package/src/components/_internal/gridSpan.ts +54 -0
  863. package/src/components/_internal/isoDay.ts +35 -0
  864. package/src/components/_internal/letterKey.ts +26 -0
  865. package/src/components/_internal/overlay/focusRestore.ts +21 -0
  866. package/src/components/_internal/overlay/index.ts +12 -0
  867. package/src/components/_internal/overlay/tourHold.ts +23 -0
  868. package/src/components/_internal/overlay/useFocusTrap.ts +120 -0
  869. package/src/components/_internal/overlay/useInOverlay.ts +81 -0
  870. package/src/components/_internal/overlay/useOverlayStack.ts +232 -0
  871. package/src/components/_internal/overlay/useScrollLock.ts +112 -0
  872. package/src/components/_internal/refs.ts +48 -0
  873. package/src/components/_internal/statusColor.ts +26 -0
  874. package/src/components/_internal/timeUtils.ts +23 -0
  875. package/src/components/_internal/useAsyncOptions.ts +145 -0
  876. package/src/components/_internal/useClippedTooltip.ts +50 -0
  877. package/src/components/_internal/useControllableState.ts +50 -0
  878. package/src/components.manifest.json +1141 -0
  879. package/src/hooks/useBelowBreakpoint.ts +58 -0
  880. package/src/i18n/I18nProvider.tsx +52 -0
  881. package/src/i18n/LocaleProvider.tsx +17 -0
  882. package/src/i18n/en.ts +648 -0
  883. package/src/i18n/format.ts +71 -0
  884. package/src/i18n/index.ts +13 -0
  885. package/src/i18n/messages.ts +1275 -0
  886. package/src/i18n/ru.ts +677 -0
  887. package/src/i18n/useLocale.ts +19 -0
  888. package/src/i18n/useTranslation.ts +58 -0
  889. package/src/index.ts +913 -0
  890. package/src/palette/index.ts +2 -0
  891. package/src/palette/palette.ts +108 -0
  892. package/src/styles/dark.scss +4 -0
  893. package/src/styles/global.scss +7 -0
  894. package/src/styles/mixins.scss +143 -0
  895. package/src/styles/reset.scss +78 -0
  896. package/src/styles/tokens.scss +18 -0
  897. package/src/styles/typography.scss +44 -0
@@ -0,0 +1,37 @@
1
+ # `<Screen>` — full-bleed / centered screen layout
2
+
3
+ ```tsx
4
+ // Standalone (full viewport) — auth / 404 / error
5
+ <Screen
6
+ backdrop="accent"
7
+ header={<Link to="/">← Home</Link>}
8
+ footer={<Cluster gap="lg"><Link>Privacy</Link><Link>Terms</Link></Cluster>}
9
+ >
10
+ <ErrorState title="Page not found" actions={<Button>Go home</Button>} />
11
+ </Screen>
12
+
13
+ // In-app variant — fills the shell content area instead of the viewport
14
+ <Screen fill="block">
15
+ <ErrorState title="Page not found" />
16
+ </Screen>
17
+ ```
18
+
19
+ <!-- props:start -->
20
+
21
+ ## Props
22
+
23
+ <!-- prettier-ignore -->
24
+ | Prop | Type | Required | Description |
25
+ |---|---|---|---|
26
+ | `children` | `ReactNode` | yes | The centered main content. |
27
+ | `header` | `ReactNode` | no | Pinned-top slot — a back link, wordmark, etc. Omit for none. |
28
+ | `footer` | `ReactNode` | no | Pinned-bottom slot — legal / footer links. Omit for none. |
29
+ | `fill` | `'viewport' \| 'block'` | no | Screen height. Defaults to `'viewport'`. - `'viewport'` — `min-height: 100vh`; a true standalone page (login, standalone 404 / error). - `'block'` — fills its container instead of the viewport; use when the Screen is embedded inside the app shell's content area (the in-app 404 / error variants). |
30
+ | `backdrop` | `'none' \| 'plain' \| 'accent' \| 'danger'` | no | Backdrop behind the content. Defaults to `'none'` (transparent — inherits the surface; use with `fill="block"` inside the shell). - `'plain'` — solid subtle surface. - `'accent'` — accent-tinted radial (the login backdrop). - `'danger'` — danger-tinted radial (standalone error screen). |
31
+ | `align` | `'center' \| 'start'` | no | Vertical placement of the main content. Defaults to `'center'`. |
32
+ | …native | | | plus native `<div>` attributes |
33
+
34
+ <!-- props:end -->
35
+
36
+ - Page-root layout for **chromeless** screens that render outside the app shell (sign-in, 404, error, onboarding). Three slots: pinned `header`, centered `children` (main), pinned `footer`.
37
+ - Layout-owning primitive (the `<Page>` / `<Rail>` exception to "no layout properties"). Don't nest inside `<Page>` or another `<Screen>`. For a normal in-shell page use `<Page>`; to center a small element use `<Cluster>` / `<Stack>`.
@@ -0,0 +1,39 @@
1
+ # `<ScrollArea>` — height-capped vertical scroll region
2
+
3
+ ```tsx
4
+ <ScrollArea maxHeight="md" aria-label="Notifications">
5
+ <Stack gap="xs">{rows}</Stack>
6
+ </ScrollArea>
7
+ ```
8
+
9
+ <!-- props:start -->
10
+
11
+ ## Props
12
+
13
+ <!-- prettier-ignore -->
14
+ | Prop | Type | Required | Description |
15
+ |---|---|---|---|
16
+ | `maxHeight` | `ScrollAreaMaxHeight` | no | Caps the area's height; past it, the content scrolls vertically. - `'sm'` — 240px. A short list inside a form or a card. - `'md'` — 400px. A popover feed (notifications, activity). - `'lg'` — 560px. A tall panel body. - `number` — px, for a one-off (`maxHeight={320}`). Prefer the scale. - `string` — any CSS length (`'50vh'`). Omitted: no cap of its own. The area fills the height its parent gives it, which is right as the flexible child of a bounded flex column. |
17
+ | …native | | | plus native `<div>` attributes |
18
+
19
+ <!-- props:end -->
20
+
21
+ - Pads its content by the focus-ring extent (4px) so focused children's rings aren't clipped.
22
+ - **Keyboard:** named (`aria-label` / `aria-labelledby`), it is always a `role="region"` landmark. It is a tab stop (`tabIndex=0`) only while it overflows AND holds nothing focusable (a dev warning fires if that happens unnamed). A feed of links adds no tab stop. Name the ones worth landmark navigation (feeds, logs), not decorative ones.
23
+ - **In a Popover** it's what caps the popover at the viewport: the popover becomes a flex column where only the ScrollArea shrinks, so a header above it stays put. Keep it a direct child of `Popover.Content`, or inside one wrapper element that is a direct child (`Content > Stack > ScrollArea`). That one wrapper must lay its children out as a column: a `<Stack>`, or a plain element (div/form/Card), which the popover lays out as a column. A row wrapper such as `<Cluster>` is not supported (the popover caps but the feed overflows it) — put the ScrollArea in a Stack instead. Deeper nesting leaves the popover uncapped.
24
+ - Not for whole-page scroll (AppLayout owns it), a Card body (`<Card fill>` + `<Card.Body scroll>`), or horizontal scrolling (wider content is clipped — wrap long lines). Don't nest them.
25
+
26
+ ```tsx
27
+ // Plain-text log: overflowing with nothing focusable, so it becomes a named tab stop by itself.
28
+ <ScrollArea maxHeight="sm" aria-label="Import log">
29
+ <Stack gap="xs">{lines.map((line, i) => <Text key={i} size="sm">{line}</Text>)}</Stack>
30
+ </ScrollArea>
31
+
32
+ // One-off height — prefer the scale.
33
+ <ScrollArea maxHeight={320} aria-label="Members">{members}</ScrollArea>
34
+ ```
35
+
36
+ **Anti-patterns**
37
+
38
+ - A plain `overflow: auto` div via `className` instead: it loses the keyboard tab stop, the popover viewport cap, and overscroll containment.
39
+ - Plain-text content with no `aria-label` / `aria-labelledby`: it becomes an unnamed tab stop.
@@ -0,0 +1,131 @@
1
+ # `<Select>` — value picker (single, multi, searchable, async, creatable)
2
+
3
+ ```tsx
4
+ // Form field — single:
5
+ <Select
6
+ options={statuses}
7
+ value={status}
8
+ onChange={(v) => setStatus(v as Status)}
9
+ placeholder="Pick a status"
10
+ />
11
+
12
+ // Table filter — multi, summary:
13
+ <Select
14
+ multiple
15
+ triggerDisplay="summary"
16
+ searchable
17
+ options={owners}
18
+ value={selectedOwners}
19
+ onChange={(v) => setSelectedOwners(v as string[])}
20
+ placeholder="Filter by owner"
21
+ />
22
+
23
+ // Tag input — multi, chips, creatable:
24
+ <Select
25
+ multiple
26
+ searchable
27
+ creatable
28
+ options={existingTags}
29
+ value={tags}
30
+ onChange={(v) => setTags(v as string[])}
31
+ onCreate={api.tags.create}
32
+ placeholder="Add tags…"
33
+ />
34
+
35
+ // Async with custom row render:
36
+ <Select
37
+ searchable
38
+ loadOptions={async (q, signal) => {
39
+ const users = await api.searchUsers(q, { signal });
40
+ return users.map((u) => ({ value: u.id, label: u.name, data: u }));
41
+ }}
42
+ renderOption={(opt) => (
43
+ <Cluster gap="sm">
44
+ <Avatar name={opt.label} src={opt.data?.avatarUrl} size="sm" />
45
+ <span>{opt.label}</span>
46
+ </Cluster>
47
+ )}
48
+ value={assigneeId}
49
+ onChange={(id) => setAssigneeId(id as string)}
50
+ />
51
+ ```
52
+
53
+ **Option descriptions.** `SelectOption.description` renders as a muted second line under the label in the default row and becomes the option's accessible description (the name stays the label). It is also matched by the searchable filter. A `renderOption` replaces the default label/description layout.
54
+
55
+ **Panel width.** The option panel is never narrower than the trigger and grows to fit its widest option, up to `--select-listbox-max-width` (20rem) and the viewport. Labels wrap only past that cap. While the panel is open it never shrinks, so filtering doesn't make it jump. A narrow trigger is fine: don't widen it just to stop options wrapping. Height caps at `--select-listbox-max-height` (320px) or the space available in the viewport. The panel is portalled to `<body>`, so override either token at `:root` or through `AppProvider`'s `tokens` / `darkTokens` (see `docs/setup.md`). Setting it on a wrapper around the Select does not reach the panel.
56
+
57
+ <!-- props:start -->
58
+
59
+ ## Props
60
+
61
+ <!-- prettier-ignore -->
62
+ | Prop | Type | Required | Description |
63
+ |---|---|---|---|
64
+ | `id` | `string` | no | Placed on the combobox trigger (the `<button>` / `<input>`), not the wrapper div, so a `<label for>` — Field / SettingRow wire one — focuses the control when clicked. Default: a generated id. Target the wrapper by `className` or a `data-*` attribute, not `#id`. |
65
+ | `options` | `SelectOptions<T>` | no | Sync options — flat list or list of groups. Ignored when `loadOptions` is provided (dev warning fires if both are non-empty). For grouped input, every element must carry an `options` field; mixing flat options with groups at the same level is not supported. |
66
+ | `loadOptions` | `((query: string, signal: AbortSignal) => Promise<SelectOptions<T>>)` | no | Async fetcher that returns the options for a given query. When set, the Select switches to async mode: the local substring filter is bypassed (the server filters), loading/error/empty rows replace the listbox body, and `options` is ignored (with a dev warning). The `signal` argument is aborted whenever a newer query supersedes this one — wire it through to `fetch` to cancel in-flight requests. |
67
+ | `loadOnOpen` | `boolean` | no | When `true` (default), defers the first `loadOptions` call until the user opens the listbox. Set to `false` to fetch eagerly on mount. |
68
+ | `searchDebounceMs` | `number` | no | Debounce window (ms) between the last query keystroke and the next `loadOptions` call. Default `250`. |
69
+ | `multiple` | `boolean` | no | Enables multi-select. `value` / `defaultValue` become `string[]` and `onChange` emits arrays. Picking a row toggles it in/out of the selection instead of replacing-and-closing. |
70
+ | `triggerDisplay` | `'chips' \| 'summary'` | no | How the trigger renders the selected value(s) in multi mode. Ignored in single mode. See `SelectTriggerDisplay`. Defaults to `'chips'`. Use `'summary'` for table-filter UIs where chips would crowd the toolbar. |
71
+ | `searchable` | `boolean` | no | Renders the trigger as a combobox text input with substring filtering over the (sync) options. In async mode the filter is delegated to the server. Required by `creatable`. |
72
+ | `selectOnOpen` | `boolean` | no | When the searchable combobox opens, select the current text so the user can immediately type to replace it (type-to-search). Default `false`. Only affects the single searchable trigger. |
73
+ | `creatable` | `boolean` | no | Adds a "+ Create <query>" row when the trimmed query has no exact label match. Activating it fires `onCreate(label)` and folds the new value into the selection. Requires `searchable` (throws in dev otherwise). |
74
+ | `onCreate` | `((label: string) => void)` | no | Fires when the user activates the "+ Create" row (creatable mode). The trimmed query string is passed as `label`. After this fires, the Select also calls `onChange` with the new value: in single mode the value replaces the current selection and the listbox closes; in multi mode the value is appended to the current selection and the query is cleared. Consumers typically use this hook to persist the new option upstream (e.g. POST to a backend) and reconcile their `options` array. |
75
+ | `value` | `string \| string[]` | no | Controlled selection. `string` in single mode, `string[]` in multi. Provide alongside `onChange` to drive the value externally. `''` is NOT reserved for "nothing selected". If your `options` contain an option whose `value` is `''` — the common "one sentinel row plus N catalog ids" shape — that option renders and selects like any other, and the trigger shows its label. "Nothing selected" means simply "the value matches no option", which is what an untouched Select resolves to when the list has no `''` row. |
76
+ | `defaultValue` | `string \| string[]` | no | Initial selection for uncontrolled usage. `string` in single mode, `string[]` in multi. Ignored when `value` is provided. |
77
+ | `onChange` | `((value: string \| string[], option: SelectOption<T> \| SelectOption<T>[] \| null) => void)` | no | Fires when the selection changes. The first argument is the next value (`string` in single mode, `string[]` in multi). The second argument is the matched `SelectOption` (single), the matched array (multi), or `null` when the selection clears in single mode. For creatable rows not present in `options`, a synthetic `{ value, label: value }` is supplied. The match is a lookup, not an emptiness test: an emitted `''` yields the matching `SelectOption` when your `options` contain a `value: ''` row, and `null` only when they don't (a genuine clear). |
78
+ | `open` | `boolean` | no | Controlled open state. Pair with `onOpenChange`. Omit both to let Select own its open state (the common case). |
79
+ | `defaultOpen` | `boolean` | no | Initial open state for uncontrolled usage. Defaults to `false`. |
80
+ | `onOpenChange` | `((open: boolean) => void)` | no | Fires whenever Select wants to change open state. |
81
+ | `size` | `'sm' \| 'md' \| 'lg'` | no | Trigger height + type scale. See `SelectSize`. Defaults to `'md'`. |
82
+ | `invalid` | `boolean` | no | Marks the trigger as invalid — applies the error border + sets `aria-invalid="true"`. Pair with an external error message linked via `aria-describedby`. |
83
+ | `placeholder` | `string` | no | Placeholder shown when nothing is selected. In searchable mode, also the input's `placeholder` until the user types. |
84
+ | `clearable` | `boolean` | no | Shows a `✕` button in the trigger that clears the selection. Opt-in: defaults to `false`. Always forced `false` when `disabled` or `readOnly`. "Clear" means "reset to the empty value" (`''` / `[]`), so the button only appears when the current value differs from that. A Select whose selected option IS `value: ''` is already at the cleared value and shows no ✕; a value matching no option (a stale id) does show one. |
85
+ | `disabled` | `boolean` | no | Disables the trigger entirely — non-interactive, dimmed, focusable only via assistive tech. Hidden form inputs are also disabled. |
86
+ | `readOnly` | `boolean` | no | Read-only — trigger is focusable but cannot open or change the selection. Useful for displaying a value inside a form that's not yet editable. |
87
+ | `name` | `string` | no | Name attribute for native form submission. In multi mode, one hidden `<input>` per selected value is emitted (so `FormData.getAll(name)` returns the array). |
88
+ | `required` | `boolean` | no | Marks the field as required. The trigger exposes `aria-required="true"` to assistive technology. Hidden inputs still serialize named values, but they do not participate in native constraint validation; validate the selection in your form layer. |
89
+ | `form` | `string` | no | `form` attribute forwarded to the hidden `<input>` elements. |
90
+ | `renderOption` | `((opt: SelectOption<T>, state: { active: boolean; selected: boolean; }) => ReactNode)` | no | Custom renderer for a row inside the listbox. Receives the option and its current `{ active, selected }` state (active = keyboard-focused row, selected = part of the current value). The returned node replaces the default label / description layout — chrome (padding, background, `aria-*`) stays. |
91
+ | `renderValue` | `((opt: SelectOption<T>) => ReactNode)` | no | Custom renderer for the selected value inside the single-mode trigger. Ignored in multi mode (see `renderTag`). |
92
+ | `renderTag` | `((opt: SelectOption<T>, remove: () => void) => ReactNode)` | no | Custom renderer for a chip inside the multi-mode `chips` trigger. Receives the option and a `remove` callback that deselects it. Ignored in single mode and in `triggerDisplay='summary'`. |
93
+ | `renderEmpty` | `((query: string) => ReactNode)` | no | Custom empty-state renderer. Fires when the filtered listbox has no rows. Receives the current trimmed query for use in messages like "No matches for 'foo'". |
94
+ | `renderLoading` | `(() => ReactNode)` | no | Custom loading-state renderer for async mode. |
95
+ | `renderError` | `((err: Error, retry: () => void) => ReactNode)` | no | Custom error-state renderer for async mode. Receives the thrown `Error` and a `retry` callback that re-invokes `loadOptions` with the current query. |
96
+ | `aria-label` | `string` | no | Accessible name for the trigger. Use this when a visible `<label>` is not present. Mutually exclusive with `aria-labelledby`. |
97
+ | `aria-labelledby` | `string` | no | ID of an element that labels the trigger. Use when the label is a sibling node (e.g. a `<Field>` label). |
98
+ | `aria-describedby` | `string` | no | ID of an element that describes the trigger — e.g. an error message or helper hint paired with `invalid`. |
99
+ | …native | | | plus native `<div>` attributes |
100
+
101
+ <!-- props:end -->
102
+
103
+ - One generalist; the mode matrix is `multiple` × `triggerDisplay: 'chips' | 'summary'` × `searchable`.
104
+ - **Async**: pass `loadOptions(query, signal)`; debounce and `AbortSignal` cancellation are built in — do NOT debounce externally.
105
+ - **Tag input pattern** = `multiple + searchable + creatable + triggerDisplay='chips'`. There is no separate `<Tags>` component.
106
+ - **`''` is a normal option value, not a reserved "unset" sentinel.** The "one sentinel row plus N catalog ids" shape works directly — no `"__default__"` workaround:
107
+
108
+ ```tsx
109
+ <Select
110
+ options={[
111
+ { value: '', label: 'Use the default scheme' },
112
+ { value: 'scheme-a', label: 'Scheme A' },
113
+ ]}
114
+ value={boundSchemeId ?? ''}
115
+ onChange={(v) => setBoundSchemeId(v === '' ? null : (v as string))}
116
+ />
117
+ ```
118
+
119
+ The trigger shows "Use the default scheme" (not a blank or the placeholder), and `onChange` hands you that row's `SelectOption`. "Nothing selected" is resolved by lookup — the value matches no option — so a Select with no `''` row still shows its placeholder at `value=""`. Corollary for `clearable`: ✕ means "reset to the empty value", so it is hidden when the selected option already IS `value: ''`, and shown for a stale value that matches nothing.
120
+
121
+ - For **action menus** (Edit/Delete/Duplicate buttons), use `<DropdownMenu>` — Select is for value selection, not actions.
122
+ - For **free-form text**, use `<Input>`. Select always picks from a (possibly async) set.
123
+ - Don't reach for `triggerDisplay='summary'` for tag input — chips communicate the active filter set at a glance.
124
+
125
+ **Keyboard / ARIA:** implements the WAI-ARIA combobox 1.2 pattern with a `role="listbox"` popup: Arrow keys, Home/End, typeahead, Enter/Space to select, Escape to dismiss. In chips mode, Backspace on an empty input removes the trailing chip; chip-to-chip arrow navigation (ArrowLeft from the empty input into the chips, ArrowLeft/Right cycling them) is not implemented.
126
+
127
+ **Anti-patterns**
128
+
129
+ - For yes/no/maybe with strong defaults, use `<Tabs>` or radio buttons.
130
+ - Embedding stale-closure logic in `loadOptions`: the fetcher runs on every debounced query, so read fresh props from a stable reference (e.g. `useCallback`) instead of capturing values that drift.
131
+ - `triggerDisplay='summary'` collapses the active set into a comma-joined line and has no per-item remove affordance; chips do.
@@ -0,0 +1,98 @@
1
+ # `<SettingRow>` — one row of a settings screen
2
+
3
+ ```tsx
4
+ <SettingRow.List dividers labelWidth="18rem">
5
+ <SettingRow
6
+ label="Seats"
7
+ labelAdornment={
8
+ <Badge tone="neutral" size="sm">
9
+ From plan
10
+ </Badge>
11
+ }
12
+ description="Member seats included for this tenant"
13
+ controlWidth="xs"
14
+ trailing={
15
+ <Constrain width="xs">
16
+ <Select options={modes} value={mode} onChange={setMode} />
17
+ </Constrain>
18
+ }
19
+ footer={
20
+ <Constrain maxWidth="sm">
21
+ <Progress value={used} max={included} aria-label="Seats usage" />
22
+ </Constrain>
23
+ }
24
+ >
25
+ <Input type="number" />
26
+ </SettingRow>
27
+ </SettingRow.List>
28
+ ```
29
+
30
+ <!-- props:start -->
31
+
32
+ ## Props
33
+
34
+ ### `SettingRowProps`
35
+
36
+ <!-- prettier-ignore -->
37
+ | Prop | Type | Required | Description |
38
+ |---|---|---|---|
39
+ | `label` | `ReactNode` | yes | Label text. Renders a `<label htmlFor>` that names the control. Required — an empty or falsy value (e.g. `0`, `''`, `[]`, `<></>`) renders no `<label>` at all; see the anti-pattern below. |
40
+ | `labelAdornment` | `ReactNode` | no | Badges / chips on the label line, rendered as a SIBLING of the `<label>`. Deliberately outside it: label content becomes the control's accessible name, so a provenance badge placed inside makes the input announce "Seats From plan". |
41
+ | `description` | `ReactNode` | no | Helper text under the label, in the label column. Linked via `aria-describedby`. |
42
+ | `controlWidth` | `'auto' \| 'xs' \| 'sm' \| 'md'` | no | Width of the control only — `trailing` is not sized by it. Default `'auto'` — the control's intrinsic width. Every row using the same step gets the same control width (capped at the column, so a narrow container still shrinks it), which is what keeps controls aligned down a `<SettingRow.List>`. Intended for controls that stretch to `width: 100%` (`Input`, `Select`); a fixed-size control (`Switch`) does not grow — the slot just reserves the width. `trailing` stays on the control's line only while both fit: in a narrow column a wide step (`'md'`) plus `trailing` can wrap `trailing` onto a second line. Use a smaller step if that matters. |
43
+ | `trailing` | `ReactNode` | no | Content after the control on the same line — a mode select, a state badge, a reset button. `controlWidth` does NOT apply here — it only sizes the main control. A control that sizes itself to `width: 100%` (`Select`, `Input`, `Textarea`) fills the ENTIRE trailing group and pushes any other adornment onto a second line; wrap it in `<Constrain width="xs">` (or another named step) to size it instead. Plain truthiness check: an empty array or fragment still renders an empty wrapper (a stray gap) — pass `undefined` for "none". |
44
+ | `footer` | `ReactNode` | no | Block under the control column — a usage meter, a caveat, a preview. Fills the control column's full width; cap a meter with `<Constrain>` — safe here, `footer` is not the wired child. |
45
+ | `error` | `ReactNode` | no | Error message. Takes over `aria-describedby` and flips the control to `invalid`. Unlike `<Field>`, the `description` stays VISIBLE alongside it — the two sit in different columns, so an invalid value is no reason to remove the explanation of what the setting is. **Not announced, deliberately** — `aria-describedby` is read on focus, so the form owns the submit-time summary. Same reasoning as `<Field error>`. |
46
+ | `required` | `boolean` | no | Marks the row required: shows `*` and injects `required` onto the control. |
47
+ | `id` | `string` | no | Explicit control id. The row owns the id by default so the label always matches. |
48
+ | `children` | `ReactNode \| ((field: FieldRenderProps) => ReactNode)` | yes | A single control element (auto-wired) or a render-prop `(field) => ReactNode`. |
49
+ | …native | | | plus native `<div>` attributes |
50
+
51
+ ### `SettingRowListProps`
52
+
53
+ <!-- prettier-ignore -->
54
+ | Prop | Type | Required | Description |
55
+ |---|---|---|---|
56
+ | `labelWidth` | `string` | no | CSS length for the label column, shared by every row in the list (e.g. `'18rem'`, `'240px'`). Default `'16rem'` via the `--setting-row-label-width` token. A LENGTH, not `max-content` — rows align because they each resolve the same value, with no subgrid. |
57
+ | `dividers` | `boolean` | no | 1px border between rows. Default `false`, matching `<DefinitionList>`. |
58
+ | `spacing` | `'sm' \| 'md' \| 'lg'` | no | Vertical padding per row. Default `'md'`. |
59
+ | `collapseBelow` | `false \| 'sm' \| 'md' \| 'lg'` | no | Container width at or below which each row stacks its label column above its control column. `'sm'` 480px / `'md'` 640px / `'lg'` 768px, measured against the LIST's own box (a container query, like `<Grid>` and `<Split>`). Default `'sm'`. Pass `false` to opt out of containment entirely — e.g. inside a shrink-to-fit parent (a `width: max-content` flex item, an inline-block, a table cell), where `container-type: inline-size` would otherwise zero the List's intrinsic-width contribution. See the anti-pattern below. |
60
+ | `children` | `ReactNode` | yes | The rows. |
61
+ | …native | | | plus native `<div>` attributes |
62
+
63
+ <!-- props:end -->
64
+
65
+ - Label (+ `labelAdornment`) and `description` in a shared LEFT column; control (+ `trailing`) and `footer` in the right. Wiring is `<Field>`'s — same `id` / `aria-labelledby` / `aria-describedby` / `invalid`, same render-prop `field` object.
66
+ - ❌ Don't wrap the control in `<Constrain>` to cap it, use `controlWidth` — `Constrain` becomes the element the row wires, silently stripping the control's `id` and `aria-*`.
67
+ - ❌ Mixing control sizes in one row — a `size="sm"` adornment beside a default-`md` control renders two different heights on the same line.
68
+ - `<SettingRow.List>` owns the shared label column (`labelWidth`, default `16rem`), `spacing` (`sm`/`md`/`lg`, default `md`), `dividers` (default `false`) and `collapseBelow` (`sm`/`md`/`lg`, default `'sm'` — a container query on the list's own box that stacks each row; pass `false` to opt out of containment entirely). **Collapse only works inside a List** — a standalone `<SettingRow>` never stacks at any width.
69
+ - ❌ A `SettingRow.List` inside a shrink-to-fit parent (a `width: max-content` flex item, an inline-block, a table cell) with the default `collapseBelow` — the List is a size container by default, so its intrinsic-width contribution is zero and it collapses. Pass `collapseBelow={false}` there.
70
+ - ❌ Read-only key/value → `<DefinitionList>`. ❌ An ordinary form field → `<Field>`. ❌ `margin` on a row to space rows → that is the List.
71
+
72
+ ```tsx
73
+ // A plain setting — no adornments:
74
+ <SettingRow label="Default currency" description="Currency preselected for new records">
75
+ <Select options={currencies} value={currency} onChange={setCurrency} />
76
+ </SettingRow>
77
+
78
+ // Render-prop for a wrapped or native control:
79
+ <SettingRow label="Webhook URL" error={errors.url}>
80
+ {(field) => <input type="url" {...field} />}
81
+ </SettingRow>
82
+ ```
83
+
84
+ **Alignment:** rows align because the label column is a length shared via `--setting-row-label-width`; set it once on `<SettingRow.List>` (`labelWidth`), never on individual rows.
85
+
86
+ **When NOT to use**
87
+
88
+ - A form field in a normal form: use `<Field>`; the shared label column is wrong for a two-up `<FormRow>`.
89
+ - A single self-labelling `<Checkbox>` / `<Switch>`: put it in a `<Cluster>`, or pass it as the row's control with the row's `label` as the only label (don't double-label).
90
+ - Grouping rows under a heading: use `<FormSection>`, which can wrap a `<SettingRow.List>`.
91
+
92
+ **Anti-patterns**
93
+
94
+ - A badge inside `label` instead of `labelAdornment`: it joins the control's accessible name.
95
+ - A bare `<Cluster justify="between">` or packed-left `<Cluster>` for a settings row: the first flings the control to the far edge of a wide card, the second leaves every row's control at a different x.
96
+ - A `<Stack>` of rows with ad-hoc `gap` instead of `<SettingRow.List>`: no shared label-column owner and no divider rhythm.
97
+ - Absent-value semantics: `label` / `error` / `description` treat `0`, `NaN`, `false`, `''`, an empty array and an empty fragment as ABSENT, so `description={remaining}` with `remaining === 0` or `error={errors.map(...)}` with no errors renders nothing (no `<label>`, no description, no error, no `invalid` flip). A labelless control falls back to its own `aria-label`, or is unnamed. A real but visually empty node (`label={<span />}`, `label=" "`) or an empty one-shot iterator (`Map.prototype.values()`, a generator) counts as present.
98
+ - An absent `label` also removes the `required` `*` marker (it lives inside the `<label>`): `<SettingRow label={0} required>` shows no `*`.
@@ -0,0 +1,68 @@
1
+ # `<Skeleton>` — loading placeholder
2
+
3
+ ```tsx
4
+ <Skeleton width={120} /> // text line
5
+ <Skeleton variant="circular" width={32} /> // avatar
6
+ <Skeleton variant="rectangular" width="100%" height={120} /> // image
7
+ <Skeleton loading={isFetching} delay={200} minDuration={300} /> // no flash
8
+ ```
9
+
10
+ <!-- props:start -->
11
+
12
+ ## Props
13
+
14
+ <!-- prettier-ignore -->
15
+ | Prop | Type | Required | Description |
16
+ |---|---|---|---|
17
+ | `variant` | `'text' \| 'circular' \| 'rectangular'` | no | Shape preset. Defaults to `'text'`. - `'text'` — inline-block; `height` defaults to `1em` so it sits on text baselines. Use inside paragraphs / labels for word-shaped placeholders. - `'circular'` — `border-radius: 50%`; when only one of `width`/`height` is set, the other matches (square). Avatar / icon placeholder. - `'rectangular'` — block, small radius. Image / card / button placeholder. |
18
+ | `width` | `string \| number` | no | Explicit width. Number → px, string → as-is (e.g., `'60%'`, `'12rem'`). |
19
+ | `height` | `string \| number` | no | Explicit height. Number → px, string → as-is. Defaults: `text` → `1em`, `circular` → matches `width` (square), `rectangular` → no default (consumer must size). |
20
+ | `animation` | `'pulse' \| 'none'` | no | Animation. Defaults to `'pulse'`. - `'pulse'` — opacity 1 → 0.6 → 1, 1.5s ease-in-out infinite. - `'none'` — static. Use when stacking many skeletons to avoid motion overload. Regardless of this prop, animation is suppressed when the user has `prefers-reduced-motion: reduce`. |
21
+ | `loading` | `boolean` | no | Whether the loading placeholder is needed. Defaults to `true`. Keep Skeleton mounted and drive this prop when using `minDuration`, so the component can finish its visibility window after loading completes. |
22
+ | `delay` | `number` | no | Milliseconds to wait before rendering the placeholder. Defaults to `0`. A load that finishes inside this window never displays the Skeleton. |
23
+ | `minDuration` | `number` | no | Minimum milliseconds to remain visible after the placeholder renders. Defaults to `0`. Prevents a Skeleton that appears just after `delay` from disappearing again within a frame or two. |
24
+ | …native | | | plus native `<span>` attributes |
25
+
26
+ <!-- props:end -->
27
+
28
+ For a mutually exclusive placeholder/content branch, use the public timing hook:
29
+
30
+ ```tsx
31
+ const showPlaceholder = useSkeletonVisibility(isFetching, {
32
+ delay: 200,
33
+ minDuration: 300,
34
+ });
35
+
36
+ return showPlaceholder ? (
37
+ <Skeleton variant="rectangular" width="100%" height={120} />
38
+ ) : isFetching ? null : (
39
+ <ContactList contacts={contacts} />
40
+ );
41
+ ```
42
+
43
+ - Three variants: `text` (default, inline, `height=1em`), `circular` (avatar / icon, square when only one dim set), `rectangular` (image / card / button, block).
44
+ - Timed visibility: keep Skeleton mounted, drive `loading`, and use `delay` to suppress fast-load flashes plus `minDuration` to prevent a just-shown placeholder from vanishing immediately. All three preserve legacy behavior by default (`loading=true`, both durations `0`). Do not conditionally unmount a timed Skeleton — unmounting bypasses `minDuration`.
45
+ - `useSkeletonVisibility(loading, { delay, minDuration })` exposes the same timing semantics for composite components that must choose between placeholder and content. During the delay it returns `false`, so guard the content branch with `loading` when stale content must not render.
46
+ - Pulse is **automatically suppressed** when the user has `prefers-reduced-motion: reduce`.
47
+ - `aria-hidden='true'` by default — Skeleton is decorative. Communicate "loading" from a parent live region you own. Note `aria-busy` alone on the section will NOT do it — no mainstream screen reader speaks it on a non-live element; pair it with `role="status"` and text that changes. Skeleton is one of the few components where announcing is genuinely yours, because it has no state of its own to describe.
48
+ - Composes — for a list-row placeholder, render `<Skeleton variant='circular' />` + 2–3 text skeletons + a button-shaped rectangular in a Cluster.
49
+ - Use `<EmptyState>` for "nothing here yet" — Skeleton implies "loading," not "empty."
50
+
51
+ ```tsx
52
+ // List-row loading: avatar + two text lines + button
53
+ <Cluster gap="md" align="center">
54
+ <Skeleton variant="circular" width={32} />
55
+ <Stack gap="xs" style={{ flex: 1 }}>
56
+ <Skeleton width="60%" />
57
+ <Skeleton width="40%" />
58
+ </Stack>
59
+ <Skeleton variant="rectangular" width={80} height={32} />
60
+ </Cluster>
61
+ ```
62
+
63
+ **Anti-patterns**
64
+
65
+ - Wrapping real content in a Skeleton: it is a leaf, don't pass children.
66
+ - Omitting all dimensions on `rectangular`: with no `width` / `height` the box has zero size and renders invisibly. Always size it.
67
+ - Showing an immediate placeholder for loads that resolve quickly: use `delay` so fast loads never display it.
68
+ - Conditionally unmounting a timed Skeleton (`{loading && <Skeleton minDuration={300} />}`): React removes it before the minimum can finish. Keep it mounted and pass `loading={loading}`.
@@ -0,0 +1,92 @@
1
+ # `<Slider>` — controlled slider (single + range, horizontal + vertical)
2
+
3
+ ```tsx
4
+ <Slider value={zoom} min={1} max={3} step={0.1} onChange={(v) => setZoom(v as number)} aria-label="Zoom" />
5
+
6
+ <Slider
7
+ value={price} // tuple → range mode
8
+ min={0} max={100000} step={1000}
9
+ label={(v) => `$${v.toLocaleString()}`}
10
+ onChange={(v) => setPrice(v as [number, number])}
11
+ aria-label="Price range"
12
+ />
13
+
14
+ <Slider
15
+ value={volume}
16
+ orientation="vertical"
17
+ marks={[0, 25, 50, 75, 100]}
18
+ onChange={(v) => setVolume(v as number)}
19
+ />
20
+ ```
21
+
22
+ <!-- props:start -->
23
+
24
+ ## Props
25
+
26
+ <!-- prettier-ignore -->
27
+ | Prop | Type | Required | Description |
28
+ |---|---|---|---|
29
+ | `invalid` | `boolean` | no | Marks each thumb `aria-invalid` for Field / SettingRow composition. Default: `false`. |
30
+ | `required` | `boolean` | no | Consumed for Field / SettingRow composition (they render the visible required marker). `role="slider"` does not support `aria-required` and a slider always has a value, so nothing is forwarded. |
31
+ | `value` | `SliderValue` | yes | Current value. A single `number` for one-thumb mode; a `[min, max]` tuple for two-thumb (range) mode. The component type-discriminates internally. Required — Slider is controlled-only. |
32
+ | `onChange` | `(value: SliderValue) => void` | yes | Called on every thumb-drag tick (high frequency). For server-side or expensive update logic, prefer `onChangeEnd` or debounce in the consumer. The argument has the same shape as `value`: `number` for single, `[number, number]` for range. |
33
+ | `onChangeEnd` | `((value: SliderValue) => void)` | no | Called once when the user "commits" a value change — at pointerup after a drag, or at blur after keyboard-nav that actually changed the value. Does NOT fire on Tab-in / Tab-out without any value change. Use for committing the value to a server or running an expensive recalculation. Receives the final value with the same shape as `value`. |
34
+ | `min` | `number` | no | Minimum allowed value (inclusive). Default `0`. |
35
+ | `max` | `number` | no | Maximum allowed value (inclusive). Default `100`. |
36
+ | `step` | `number` | no | Step granularity. Default `1`. Use fractional steps (e.g. `0.1`) for zoom / opacity-style controls. Values are snapped to `min + (n * step)`. |
37
+ | `marks` | `number[] \| SliderMark[]` | no | Tick marks. Pass `number[]` for auto-labeled ticks (label = value) or `SliderMark[]` for custom labels (label = ReactNode). Marks render under the track (horizontal) or to the right (vertical). |
38
+ | `label` | `boolean \| ((value: number) => ReactNode)` | no | Value bubble on the thumb. - `false` (default) — no bubble. - `true` — show the current value (formatted via `toString()`) on hover / focus / drag. Auto-hides otherwise. - `(value: number) => ReactNode` — custom formatter. For range mode, the formatter is called once per thumb. |
39
+ | `thumbLabels` | `readonly [string, string]` | no | Explicit accessible names for the minimum and maximum thumbs in range mode. These win over a root `aria-label` or `aria-labelledby`; use them when the thumbs need domain-specific names such as `['Start date', 'End date']`. When an entry is omitted OR empty — an empty string is not an explicit name — that thumb falls back to a root label suffixed with the localized “minimum” or “maximum” name. The two entries are resolved independently, so `['', 'End date']` names only the maximum thumb. |
40
+ | `size` | `'sm' \| 'md' \| 'lg'` | no | Track + thumb sizing. Defaults to `'md'`. - `sm` — 4px track, 14px thumb. - `md` — 6px track, 18px thumb (default). - `lg` — 8px track, 22px thumb. |
41
+ | `tone` | `'default' \| 'success' \| 'warning' \| 'danger'` | no | Fill color tone (the track segment between min and value). Defaults to `'default'` (accent). State-coded `success` / `warning` / `danger` for threshold-style sliders (e.g. disk usage approaching capacity). |
42
+ | `orientation` | `'horizontal' \| 'vertical'` | no | Orientation. Defaults to `'horizontal'`. Vertical defaults to 200px tall; override via `style={{ height }}`. |
43
+ | `disabled` | `boolean` | no | Disabled state. Defaults to `false`. Thumbs become non-interactive (`tabIndex=-1`, `aria-disabled`, `pointer-events: none`, `cursor: not-allowed`). |
44
+ | `name` | `string` | no | Native form-input name. When set, a hidden `<input>` (or two for range, with `-min`/`-max` suffixes) is rendered with the current value(s) so the slider works inside uncontrolled HTML forms without consumer JS serialization. When the slider is `disabled`, the hidden input(s) are NOT rendered so the form does not submit a stale disabled value. |
45
+ | …native | | | plus native `<div>` attributes |
46
+
47
+ <!-- props:end -->
48
+
49
+ - **Controlled-only.** Always pass `value` + `onChange`. No `defaultValue`. Same architecture as FileUpload, Progress, and the rest of the controlled primitives.
50
+ - **`value: number | [number, number]`** — discriminated union. `number` for single-thumb; tuple for range (two-thumb). `onChange` mirrors the shape.
51
+ - **Range thumb names:** every range thumb must have a distinct accessible name. A root `aria-label="Price range"` produces “Price range, minimum” and “Price range, maximum” (localized); a root `aria-labelledby` is preserved and gets an appended localized suffix. Use `thumbLabels={['Lowest price', 'Highest price']}` when the names are domain-specific — explicit tuple labels win.
52
+ - **`onChange` fires per pointer-move tick (high frequency).** Debounce in the consumer OR use `onChangeEnd` (fires at pointerup, or at blur when the value actually changed) for server-state / expensive logic.
53
+
54
+ #### Keyboard
55
+
56
+ - Arrow Left/Down: `-step`. Arrow Right/Up: `+step`.
57
+ - Page Down/Up: `-10×step` / `+10×step`.
58
+ - Home / End: jump to `min` / `max`.
59
+ - All keys respect range-mode clamping (`value[0] ≤ value[1]`). `onChange` per key. `onChangeEnd` fires on blur ONLY if the value actually changed during the focus session — Tab-in / Tab-out without any nav does NOT fire.
60
+
61
+ #### Hard rule
62
+
63
+ - ❌ Raw `<input type="range">` — can't do range mode, doesn't theme cleanly across browsers. Use `<Slider>`.
64
+ - ❌ Hand-rolling drag math per page. The pointer / keyboard handling is non-trivial; the primitive owns it.
65
+ - ❌ Hitting a network endpoint inside `onChange` — fires on every pointer-move tick. Use `onChangeEnd` or debounce.
66
+ - ❌ `<Slider role="region">` — `role="slider"` is locked on each thumb. The TypeScript `Omit` prevents the root override.
67
+ - ❌ Passing `value[0] > value[1]` in range mode. The component clamps but the inverted tuple is a consumer bug — fix the state shape.
68
+
69
+ Custom-painted rather than wrapping `<input type="range">`, because range mode needs two thumbs.
70
+
71
+ ```tsx
72
+ // Tone-coded threshold (disk usage approaching capacity):
73
+ <Slider
74
+ value={usage}
75
+ tone={usage > 90 ? 'danger' : usage > 75 ? 'warning' : 'default'}
76
+ onChange={(v) => setUsage(v as number)}
77
+ label
78
+ />
79
+
80
+ // Form submission via `name` — renders hidden inputs the form picks up:
81
+ <form action="/api/settings" method="post">
82
+ <Slider name="brightness" value={brightness} onChange={setB} />
83
+ <button type="submit">Save</button>
84
+ </form>
85
+ ```
86
+
87
+ **When NOT to use**
88
+
89
+ - Binary state: use `<Switch>` or `<Checkbox>`.
90
+ - Pick one of a small enumerated set: use `<RadioGroup>` or `<Select>`.
91
+ - Continuous colour picking: that is a colour picker (not yet shipped).
92
+ - Server-bound expensive updates on every move tick: use `onChangeEnd` or debounce.
@@ -0,0 +1,55 @@
1
+ # `<SlotGrid>` — grouped time-slot tiles
2
+
3
+ ```tsx
4
+ <SlotGrid
5
+ groups={[
6
+ {
7
+ label: 'Morning',
8
+ slots: [
9
+ { key: '09:00', label: '9:00' },
10
+ { key: '09:30', label: '9:30' },
11
+ ],
12
+ },
13
+ { label: 'Afternoon', slots: [{ key: '14:00', label: '14:00' }] },
14
+ ]}
15
+ value={slot}
16
+ onChange={setSlot}
17
+ empty={<Text tone="muted">No times this day — try another.</Text>} // optional
18
+ />
19
+ ```
20
+
21
+ <!-- props:start -->
22
+
23
+ ## Props
24
+
25
+ <!-- prettier-ignore -->
26
+ | Prop | Type | Required | Description |
27
+ |---|---|---|---|
28
+ | `groups` | `SlotGridGroup[]` | yes | Groups in display order. |
29
+ | `value` | `string \| null` | yes | Selected slot `key`, or `null`. A key not in `groups` checks nothing. |
30
+ | `onChange` | `(key: string) => void` | yes | Called with the chosen slot's `key`. Controlled — update `value` yourself. |
31
+ | `empty` | `ReactNode` | no | Shown when no group has any slot. Default: the localized "No available times". |
32
+ | `titleOrder` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | no | Heading level of each group label. Default `3`. |
33
+ | `name` | `string` | no | Radio group `name` (also submitted with a form). Default: a generated id. |
34
+ | `invalid` | `boolean` | no | Marks the group `aria-invalid` (the radios themselves do not support it). Field / SettingRow inject it. Default: `false`. |
35
+ | `required` | `boolean` | no | Native `required` on the radios (the group then fails form validation until one is chosen). Field / SettingRow inject it; it used to land on the root as a stray attribute. |
36
+ | …native | | | plus native `<div>` attributes |
37
+
38
+ <!-- props:end -->
39
+
40
+ - Slot `label`s are yours, formatted in the business's timezone. `key` is what `onChange` returns; keep it unique across ALL groups (one exclusive choice).
41
+ - Native radios with one `name`: one Tab stop for the whole grid, arrows move AND select in reading order (↓ goes to the next slot, not the one below). Tiles are `role="radio"` named by their label; each group is a `<fieldset>` named by its heading (`titleOrder`, default 3).
42
+ - Groups with no slots are skipped; if none has slots, `empty` renders (default: localized "No available times").
43
+ - The root is `role="group"`: in `<Field>` / `<SettingRow>` the row label names it and the error describes it; `invalid` → `aria-invalid` on the group, `required` → native `required` on the radios.
44
+ - 6 columns, 3 when the grid's own width ≤ 48rem (container query).
45
+ - ❌ No per-slot `disabled` — pass only bookable slots. ❌ Don't wrap it in your own `role="radiogroup"`.
46
+ - ❌ In an intrinsic-width context (`Split`'s default `auto` aside track, a `Cluster` item, `width: max-content`) it renders at width 0 — `container-type: inline-size` zeroes its intrinsic-width contribution; give the parent a concrete width (e.g. `asideWidth` on a Split). It is also the containing block for absolutely-positioned descendants (layout containment).
47
+ - When NOT to use: free-form time → `<TimeField>`; a handful of options → `<ButtonGroup value>` / `<RadioGroup>`.
48
+
49
+ ```tsx
50
+ // Booking time step: DateStrip picks the day, SlotGrid the time.
51
+ <Stack gap="lg">
52
+ <DateStrip days={week} value={day} onChange={setDay} onPrevious={prev} onNext={next} />
53
+ <SlotGrid groups={slotsFor(day)} value={slot} onChange={setSlot} />
54
+ </Stack>
55
+ ```
@@ -0,0 +1,31 @@
1
+ # `<SocialButton>` — provider sign-in button
2
+
3
+ ```tsx
4
+ <SocialButton provider="google" label="Continue with Google" onClick={signIn} />
5
+ ```
6
+
7
+ <!-- props:start -->
8
+
9
+ ## Props
10
+
11
+ <!-- prettier-ignore -->
12
+ | Prop | Type | Required | Description |
13
+ |---|---|---|---|
14
+ | `provider` | `'google' \| 'yandex'` | yes | Which provider's brand mark to show. Tied to `<BrandIcon>`'s set, so it grows as BrandIcon does (today: `'google'` / `'yandex'`). |
15
+ | `label` | `ReactNode` | yes | The button text — e.g. `"Continue with Google"`. Required (consumer-supplied). |
16
+ | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'danger-outline' \| 'success'` | no | Button variant; the values are Button's. Defaults to `secondary`, not Button's `primary`. |
17
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | no | Control height (matches the shared `--size-*` scale used by Input and Avatar). - `xs` (20px) — icon-only or very dense inline actions (row controls, chip-adjacent buttons). Pass `aria-label` when icon-only. Below WCAG 2.5.5 Level AAA touch-target guidance; reserve for desktop-first surfaces. - `sm` (24px) — dense toolbars, tables, inline actions. - `md` (32px, default) — most contexts. - `lg` (40px) — marketing-style empty states or emphasized primary actions. |
18
+ | `as` | `"button"` | no | Render a different element — the case that matters is `as="a"` with `href`, for a link that must LOOK like a button (an external console, a download, an IdP hand-off). The element named here is what actually renders, and its own attributes are typed: `href` is REQUIRED when `as="a"` (an anchor without one is neither focusable nor a link) and rejected otherwise; `target`/`rel`/`download` come through. Never navigate from `onClick`. Reach for `<Link>` first. `<Link>` is link-SHAPED navigation — inline text in a sentence, a table cell, a breadcrumb. `<Button as="a">` is for a destination that sits in a row of buttons and must carry their weight. Either way the element is a real anchor, so assistive tech announces a link and the browser gives middle-click, "open in new tab", and the status bar preview — none of which a `<button onClick={() => navigate()}>` has. `type="button"` is emitted only for a real `<button>`; an anchor never gets it. Everything else — variant, size, `iconOnly`, `selected`, the focus ring — is unchanged. Default: `'button'`. |
19
+ | …native | | | plus native HTML attributes |
20
+
21
+ <!-- props:end -->
22
+
23
+ - A `<Button>` with the provider's `<BrandIcon>` mark + `label`. Spreads Button props (`onClick`, `size`, `disabled`, …); width comes from the parent.
24
+ - The mark is decorative — `label` is the accessible name. For a non-SSO icon button use `<Button>` + a lucide icon.
25
+
26
+ ```tsx
27
+ <Stack gap="sm">
28
+ <SocialButton provider="google" label="Continue with Google" onClick={signInWithGoogle} />
29
+ <SocialButton provider="yandex" label="Continue with Yandex" onClick={signInWithYandex} />
30
+ </Stack>
31
+ ```