@eocrm/design-system 0.0.0-stage → 0.6.18

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 (898) hide show
  1. package/AI-PRIMER.md +341 -0
  2. package/LICENSE +202 -0
  3. package/README.md +266 -2
  4. package/docs/components/Accordion.md +114 -0
  5. package/docs/components/AgentAvatar.md +58 -0
  6. package/docs/components/Alert.md +81 -0
  7. package/docs/components/AppLayout.md +70 -0
  8. package/docs/components/Avatar.md +49 -0
  9. package/docs/components/AvatarGroup.md +47 -0
  10. package/docs/components/Badge.md +60 -0
  11. package/docs/components/Banner.md +89 -0
  12. package/docs/components/BrandIcon.md +32 -0
  13. package/docs/components/Breadcrumb.md +72 -0
  14. package/docs/components/Button.md +107 -0
  15. package/docs/components/ButtonGroup.md +78 -0
  16. package/docs/components/Calendar.md +158 -0
  17. package/docs/components/Card.md +165 -0
  18. package/docs/components/CatalogPicker.md +83 -0
  19. package/docs/components/Chart.md +114 -0
  20. package/docs/components/ChatBubble.md +55 -0
  21. package/docs/components/ChatLauncher.md +97 -0
  22. package/docs/components/Checkbox.md +55 -0
  23. package/docs/components/CircularProgress.md +53 -0
  24. package/docs/components/Cluster.md +96 -0
  25. package/docs/components/Code.md +35 -0
  26. package/docs/components/CodeBlock.md +67 -0
  27. package/docs/components/ColorPicker.md +115 -0
  28. package/docs/components/ConfirmationPopover.md +70 -0
  29. package/docs/components/Constrain.md +39 -0
  30. package/docs/components/CurrencySelect.md +57 -0
  31. package/docs/components/CursorPagination.md +43 -0
  32. package/docs/components/DashboardCanvas.md +79 -0
  33. package/docs/components/DashboardWidget.md +131 -0
  34. package/docs/components/DataTable.md +88 -0
  35. package/docs/components/DatePicker.md +68 -0
  36. package/docs/components/DateRangePicker.md +71 -0
  37. package/docs/components/DateStrip.md +56 -0
  38. package/docs/components/DefinitionList.md +82 -0
  39. package/docs/components/Divider.md +57 -0
  40. package/docs/components/Dot.md +26 -0
  41. package/docs/components/Drawer.md +94 -0
  42. package/docs/components/DropdownMenu.md +299 -0
  43. package/docs/components/EmojiPicker.md +84 -0
  44. package/docs/components/EmptyState.md +55 -0
  45. package/docs/components/EntityChip.md +102 -0
  46. package/docs/components/ErrorState.md +72 -0
  47. package/docs/components/Field.md +91 -0
  48. package/docs/components/FileUpload.md +109 -0
  49. package/docs/components/FilterChip.md +88 -0
  50. package/docs/components/FlowCanvas.md +108 -0
  51. package/docs/components/FormRow.md +31 -0
  52. package/docs/components/FormSection.md +37 -0
  53. package/docs/components/Grid.md +103 -0
  54. package/docs/components/Highlight.md +75 -0
  55. package/docs/components/HighlightedText.md +50 -0
  56. package/docs/components/IconPicker.md +134 -0
  57. package/docs/components/IconTile.md +30 -0
  58. package/docs/components/Image.md +84 -0
  59. package/docs/components/ImageCrop.md +163 -0
  60. package/docs/components/Indent.md +31 -0
  61. package/docs/components/InlineDatePicker.md +58 -0
  62. package/docs/components/InlineDateRangePicker.md +57 -0
  63. package/docs/components/Input.md +54 -0
  64. package/docs/components/Kanban.md +122 -0
  65. package/docs/components/Kbd.md +41 -0
  66. package/docs/components/Lightbox.md +105 -0
  67. package/docs/components/Link.md +65 -0
  68. package/docs/components/LinkCard.md +41 -0
  69. package/docs/components/LiquidEditor.md +84 -0
  70. package/docs/components/List.md +68 -0
  71. package/docs/components/LiveRegion.md +29 -0
  72. package/docs/components/LocaleProvider.md +25 -0
  73. package/docs/components/Logo.md +41 -0
  74. package/docs/components/Masonry.md +48 -0
  75. package/docs/components/MediaTile.md +95 -0
  76. package/docs/components/Modal.md +107 -0
  77. package/docs/components/MoneyInput.md +62 -0
  78. package/docs/components/OptionsPicker.md +123 -0
  79. package/docs/components/OtpInput.md +65 -0
  80. package/docs/components/Page.md +35 -0
  81. package/docs/components/PageHeader.md +133 -0
  82. package/docs/components/Pagination.md +44 -0
  83. package/docs/components/Palette.md +32 -0
  84. package/docs/components/PasswordInput.md +45 -0
  85. package/docs/components/PasswordStrengthMeter.md +27 -0
  86. package/docs/components/PersonDisplay.md +153 -0
  87. package/docs/components/PhoneInput.md +54 -0
  88. package/docs/components/PillMenu.md +91 -0
  89. package/docs/components/Popover.md +127 -0
  90. package/docs/components/Progress.md +56 -0
  91. package/docs/components/QrCode.md +34 -0
  92. package/docs/components/Radio.md +37 -0
  93. package/docs/components/RadioGroup.md +56 -0
  94. package/docs/components/Rail.md +191 -0
  95. package/docs/components/RelativeDateInput.md +114 -0
  96. package/docs/components/RichText.md +44 -0
  97. package/docs/components/RichTextEditor.md +112 -0
  98. package/docs/components/Screen.md +37 -0
  99. package/docs/components/ScrollArea.md +39 -0
  100. package/docs/components/Select.md +131 -0
  101. package/docs/components/SettingRow.md +98 -0
  102. package/docs/components/Skeleton.md +68 -0
  103. package/docs/components/Slider.md +92 -0
  104. package/docs/components/SlotGrid.md +55 -0
  105. package/docs/components/SocialButton.md +31 -0
  106. package/docs/components/Sortable.md +127 -0
  107. package/docs/components/SortableGroup.md +52 -0
  108. package/docs/components/Sparkline.md +51 -0
  109. package/docs/components/Split.md +76 -0
  110. package/docs/components/Stack.md +59 -0
  111. package/docs/components/StagePath.md +66 -0
  112. package/docs/components/StatGroup.md +61 -0
  113. package/docs/components/StatTile.md +58 -0
  114. package/docs/components/Sticky.md +69 -0
  115. package/docs/components/Switch.md +89 -0
  116. package/docs/components/Table.md +184 -0
  117. package/docs/components/TableOfContents.md +76 -0
  118. package/docs/components/Tabs.md +94 -0
  119. package/docs/components/Text.md +63 -0
  120. package/docs/components/Textarea.md +59 -0
  121. package/docs/components/Thread.md +52 -0
  122. package/docs/components/TimeField.md +70 -0
  123. package/docs/components/Timeline.md +57 -0
  124. package/docs/components/Title.md +54 -0
  125. package/docs/components/ToastViewport.md +61 -0
  126. package/docs/components/Tooltip.md +63 -0
  127. package/docs/components/TopBar.md +214 -0
  128. package/docs/components/Tour.md +85 -0
  129. package/docs/components/TreeView.md +113 -0
  130. package/docs/components/VisuallyHidden.md +43 -0
  131. package/docs/components/WidgetPreview.md +54 -0
  132. package/docs/components/useBelowBreakpoint.md +11 -0
  133. package/docs/components/useMonth.md +18 -0
  134. package/docs/setup.md +51 -0
  135. package/docs/theming.md +95 -0
  136. package/docs/tokens.md +123 -0
  137. package/docs/transient-state.md +56 -0
  138. package/package.json +86 -4
  139. package/src/_meta/manifest.ts +293 -0
  140. package/src/app/AppProvider.tsx +78 -0
  141. package/src/app/index.ts +3 -0
  142. package/src/app/themeTokens.ts +95 -0
  143. package/src/calendar/dateMath.ts +114 -0
  144. package/src/calendar/formatters.ts +75 -0
  145. package/src/calendar/index.ts +39 -0
  146. package/src/calendar/types.ts +36 -0
  147. package/src/calendar/useAgenda.ts +70 -0
  148. package/src/calendar/useDay.ts +51 -0
  149. package/src/calendar/useMonth.ts +82 -0
  150. package/src/calendar/useWeek.ts +62 -0
  151. package/src/calendar/weekInfo.ts +83 -0
  152. package/src/components/Accordion/Accordion.module.scss +304 -0
  153. package/src/components/Accordion/Accordion.tokens.scss +64 -0
  154. package/src/components/Accordion/Accordion.tsx +272 -0
  155. package/src/components/Accordion/AccordionContent.tsx +36 -0
  156. package/src/components/Accordion/AccordionItem.tsx +66 -0
  157. package/src/components/Accordion/AccordionTrigger.tsx +121 -0
  158. package/src/components/Accordion/context.ts +47 -0
  159. package/src/components/Accordion/index.ts +14 -0
  160. package/src/components/Alert/Alert.module.scss +92 -0
  161. package/src/components/Alert/Alert.tokens.scss +60 -0
  162. package/src/components/Alert/Alert.tsx +136 -0
  163. package/src/components/Alert/index.ts +2 -0
  164. package/src/components/AppLayout/AppLayout.module.scss +130 -0
  165. package/src/components/AppLayout/AppLayout.tokens.scss +27 -0
  166. package/src/components/AppLayout/AppLayout.tsx +211 -0
  167. package/src/components/AppLayout/index.ts +2 -0
  168. package/src/components/Avatar/AgentAvatar.module.scss +117 -0
  169. package/src/components/Avatar/AgentAvatar.tsx +122 -0
  170. package/src/components/Avatar/Avatar.module.scss +181 -0
  171. package/src/components/Avatar/Avatar.tokens.scss +107 -0
  172. package/src/components/Avatar/Avatar.tsx +210 -0
  173. package/src/components/Avatar/AvatarGroup.module.scss +128 -0
  174. package/src/components/Avatar/AvatarGroup.tsx +119 -0
  175. package/src/components/Avatar/AvatarGroupContext.tsx +20 -0
  176. package/src/components/Avatar/index.ts +6 -0
  177. package/src/components/Badge/Badge.module.scss +124 -0
  178. package/src/components/Badge/Badge.tokens.scss +74 -0
  179. package/src/components/Badge/Badge.tsx +164 -0
  180. package/src/components/Badge/index.ts +2 -0
  181. package/src/components/Banner/Banner.module.scss +73 -0
  182. package/src/components/Banner/Banner.tokens.scss +51 -0
  183. package/src/components/Banner/Banner.tsx +138 -0
  184. package/src/components/Banner/index.ts +2 -0
  185. package/src/components/BrandIcon/BrandIcon.module.scss +5 -0
  186. package/src/components/BrandIcon/BrandIcon.tsx +99 -0
  187. package/src/components/BrandIcon/index.ts +2 -0
  188. package/src/components/Breadcrumb/Breadcrumb.module.scss +32 -0
  189. package/src/components/Breadcrumb/Breadcrumb.tokens.scss +9 -0
  190. package/src/components/Breadcrumb/Breadcrumb.tsx +146 -0
  191. package/src/components/Breadcrumb/index.ts +2 -0
  192. package/src/components/Button/Button.module.scss +167 -0
  193. package/src/components/Button/Button.tokens.scss +90 -0
  194. package/src/components/Button/Button.tsx +205 -0
  195. package/src/components/Button/index.ts +2 -0
  196. package/src/components/ButtonGroup/ButtonGroup.module.scss +134 -0
  197. package/src/components/ButtonGroup/ButtonGroup.tokens.scss +42 -0
  198. package/src/components/ButtonGroup/ButtonGroup.tsx +278 -0
  199. package/src/components/ButtonGroup/ButtonGroupItem.tsx +74 -0
  200. package/src/components/ButtonGroup/context.ts +45 -0
  201. package/src/components/ButtonGroup/index.ts +2 -0
  202. package/src/components/Calendar/AgendaView.module.scss +231 -0
  203. package/src/components/Calendar/AgendaView.tsx +214 -0
  204. package/src/components/Calendar/AllDayBand.module.scss +18 -0
  205. package/src/components/Calendar/AllDayBand.tsx +75 -0
  206. package/src/components/Calendar/Calendar.module.scss +23 -0
  207. package/src/components/Calendar/Calendar.tokens.scss +262 -0
  208. package/src/components/Calendar/Calendar.tsx +370 -0
  209. package/src/components/Calendar/DayCell.module.scss +30 -0
  210. package/src/components/Calendar/DayCell.tsx +50 -0
  211. package/src/components/Calendar/DayView.module.scss +10 -0
  212. package/src/components/Calendar/DayView.tsx +163 -0
  213. package/src/components/Calendar/EventChip.module.scss +171 -0
  214. package/src/components/Calendar/EventChip.tsx +115 -0
  215. package/src/components/Calendar/HourGrid.module.scss +123 -0
  216. package/src/components/Calendar/HourGrid.tsx +381 -0
  217. package/src/components/Calendar/MonthView.module.scss +99 -0
  218. package/src/components/Calendar/MonthView.tsx +296 -0
  219. package/src/components/Calendar/TimedEvent.module.scss +205 -0
  220. package/src/components/Calendar/TimedEvent.tsx +247 -0
  221. package/src/components/Calendar/ViewSwitcher.module.scss +3 -0
  222. package/src/components/Calendar/ViewSwitcher.tsx +47 -0
  223. package/src/components/Calendar/WeekView.module.scss +10 -0
  224. package/src/components/Calendar/WeekView.tsx +137 -0
  225. package/src/components/Calendar/eventColor.ts +60 -0
  226. package/src/components/Calendar/index.ts +18 -0
  227. package/src/components/Calendar/types.ts +451 -0
  228. package/src/components/Calendar/useEventDrag.ts +783 -0
  229. package/src/components/Calendar/utils.ts +622 -0
  230. package/src/components/Card/Card.module.scss +264 -0
  231. package/src/components/Card/Card.tokens.scss +55 -0
  232. package/src/components/Card/Card.tsx +170 -0
  233. package/src/components/Card/CardBody.tsx +45 -0
  234. package/src/components/Card/CardHeader.tsx +113 -0
  235. package/src/components/Card/CardList.tsx +24 -0
  236. package/src/components/Card/CardListRow.tsx +24 -0
  237. package/src/components/Card/index.ts +7 -0
  238. package/src/components/CatalogPicker/CatalogPicker.module.scss +193 -0
  239. package/src/components/CatalogPicker/CatalogPicker.tokens.scss +26 -0
  240. package/src/components/CatalogPicker/CatalogPicker.tsx +339 -0
  241. package/src/components/CatalogPicker/index.ts +2 -0
  242. package/src/components/Chart/Chart.module.scss +287 -0
  243. package/src/components/Chart/Chart.tokens.scss +63 -0
  244. package/src/components/Chart/Chart.tsx +607 -0
  245. package/src/components/Chart/ChartLegend.tsx +99 -0
  246. package/src/components/Chart/ChartTable.tsx +62 -0
  247. package/src/components/Chart/ChartTooltip.tsx +91 -0
  248. package/src/components/Chart/chartModel.ts +689 -0
  249. package/src/components/Chart/index.ts +2 -0
  250. package/src/components/ChatBubble/ChatBubble.module.scss +93 -0
  251. package/src/components/ChatBubble/ChatBubble.tokens.scss +17 -0
  252. package/src/components/ChatBubble/ChatBubble.tsx +61 -0
  253. package/src/components/ChatBubble/ChatBubbleList.tsx +27 -0
  254. package/src/components/ChatBubble/index.ts +3 -0
  255. package/src/components/ChatLauncher/ChatLauncher.module.scss +68 -0
  256. package/src/components/ChatLauncher/ChatLauncher.tokens.scss +27 -0
  257. package/src/components/ChatLauncher/ChatLauncher.tsx +202 -0
  258. package/src/components/ChatLauncher/index.ts +2 -0
  259. package/src/components/ChatLauncher/isAtBottom.ts +12 -0
  260. package/src/components/Checkbox/Checkbox.module.scss +147 -0
  261. package/src/components/Checkbox/Checkbox.tokens.scss +44 -0
  262. package/src/components/Checkbox/Checkbox.tsx +188 -0
  263. package/src/components/Checkbox/index.ts +2 -0
  264. package/src/components/CircularProgress/CircularProgress.module.scss +133 -0
  265. package/src/components/CircularProgress/CircularProgress.tokens.scss +40 -0
  266. package/src/components/CircularProgress/CircularProgress.tsx +139 -0
  267. package/src/components/CircularProgress/index.ts +7 -0
  268. package/src/components/Cluster/Cluster.module.scss +145 -0
  269. package/src/components/Cluster/Cluster.tokens.scss +11 -0
  270. package/src/components/Cluster/Cluster.tsx +215 -0
  271. package/src/components/Cluster/index.ts +2 -0
  272. package/src/components/Code/Code.module.scss +28 -0
  273. package/src/components/Code/Code.tokens.scss +15 -0
  274. package/src/components/Code/Code.tsx +44 -0
  275. package/src/components/Code/index.ts +2 -0
  276. package/src/components/CodeBlock/CodeBlock.module.scss +146 -0
  277. package/src/components/CodeBlock/CodeBlock.tokens.scss +27 -0
  278. package/src/components/CodeBlock/CodeBlock.tsx +274 -0
  279. package/src/components/CodeBlock/highlight.ts +179 -0
  280. package/src/components/CodeBlock/index.ts +8 -0
  281. package/src/components/CodeBlock/sampleSync.ts +42 -0
  282. package/src/components/ColorPicker/ColorPicker.module.scss +286 -0
  283. package/src/components/ColorPicker/ColorPicker.tokens.scss +60 -0
  284. package/src/components/ColorPicker/ColorPicker.tsx +367 -0
  285. package/src/components/ColorPicker/ColorPickerPanel.tsx +265 -0
  286. package/src/components/ColorPicker/SVSquare.tsx +189 -0
  287. package/src/components/ColorPicker/colorMath.ts +141 -0
  288. package/src/components/ColorPicker/index.ts +6 -0
  289. package/src/components/ConfirmationPopover/ConfirmationPopover.module.scss +39 -0
  290. package/src/components/ConfirmationPopover/ConfirmationPopover.tokens.scss +13 -0
  291. package/src/components/ConfirmationPopover/ConfirmationPopover.tsx +395 -0
  292. package/src/components/ConfirmationPopover/index.ts +2 -0
  293. package/src/components/Constrain/Constrain.module.scss +99 -0
  294. package/src/components/Constrain/Constrain.tsx +79 -0
  295. package/src/components/Constrain/index.ts +2 -0
  296. package/src/components/CurrencySelect/CurrencySelect.module.scss +7 -0
  297. package/src/components/CurrencySelect/CurrencySelect.tsx +167 -0
  298. package/src/components/CurrencySelect/index.ts +3 -0
  299. package/src/components/CursorPagination/CursorPagination.module.scss +69 -0
  300. package/src/components/CursorPagination/CursorPagination.tokens.scss +32 -0
  301. package/src/components/CursorPagination/CursorPagination.tsx +121 -0
  302. package/src/components/CursorPagination/index.ts +2 -0
  303. package/src/components/DashboardCanvas/DashboardCanvas.module.scss +360 -0
  304. package/src/components/DashboardCanvas/DashboardCanvas.tokens.scss +48 -0
  305. package/src/components/DashboardCanvas/DashboardCanvas.tsx +1270 -0
  306. package/src/components/DashboardCanvas/DashboardCanvasItem.tsx +140 -0
  307. package/src/components/DashboardCanvas/DashboardCanvasSection.tsx +174 -0
  308. package/src/components/DashboardCanvas/engine.ts +363 -0
  309. package/src/components/DashboardCanvas/index.ts +9 -0
  310. package/src/components/DashboardWidget/DashboardWidget.module.scss +100 -0
  311. package/src/components/DashboardWidget/DashboardWidget.tokens.scss +16 -0
  312. package/src/components/DashboardWidget/DashboardWidget.tsx +188 -0
  313. package/src/components/DashboardWidget/index.ts +7 -0
  314. package/src/components/DataTable/BodyRow.tsx +197 -0
  315. package/src/components/DataTable/ColumnVisibilityTrigger.module.scss +7 -0
  316. package/src/components/DataTable/ColumnVisibilityTrigger.tsx +105 -0
  317. package/src/components/DataTable/DataTable.module.scss +511 -0
  318. package/src/components/DataTable/DataTable.tokens.scss +80 -0
  319. package/src/components/DataTable/DataTable.tsx +734 -0
  320. package/src/components/DataTable/HeaderCell.module.scss +215 -0
  321. package/src/components/DataTable/HeaderCell.tsx +440 -0
  322. package/src/components/DataTable/columnShift.ts +117 -0
  323. package/src/components/DataTable/index.ts +23 -0
  324. package/src/components/DataTable/pinStyle.ts +47 -0
  325. package/src/components/DataTable/reorderColumns.ts +66 -0
  326. package/src/components/DataTable/types.ts +289 -0
  327. package/src/components/DataTable/useColumnDragShift.ts +216 -0
  328. package/src/components/DataTable/useDataTable.ts +372 -0
  329. package/src/components/DataTable/useResizeHandle.ts +97 -0
  330. package/src/components/DatePicker/DatePicker.module.scss +180 -0
  331. package/src/components/DatePicker/DatePicker.tokens.scss +152 -0
  332. package/src/components/DatePicker/DatePicker.tsx +664 -0
  333. package/src/components/DatePicker/DatePickerGrid.module.scss +172 -0
  334. package/src/components/DatePicker/DatePickerGrid.tsx +341 -0
  335. package/src/components/DatePicker/InlineDatePicker.module.scss +32 -0
  336. package/src/components/DatePicker/InlineDatePicker.tsx +201 -0
  337. package/src/components/DatePicker/index.ts +4 -0
  338. package/src/components/DatePicker/utils.ts +364 -0
  339. package/src/components/DateRangePicker/DateRangePicker.module.scss +237 -0
  340. package/src/components/DateRangePicker/DateRangePicker.tokens.scss +78 -0
  341. package/src/components/DateRangePicker/DateRangePicker.tsx +720 -0
  342. package/src/components/DateRangePicker/InlineDateRangePicker.module.scss +94 -0
  343. package/src/components/DateRangePicker/InlineDateRangePicker.tsx +376 -0
  344. package/src/components/DateRangePicker/index.ts +5 -0
  345. package/src/components/DateRangePicker/utils.ts +151 -0
  346. package/src/components/DateStrip/DateStrip.module.scss +78 -0
  347. package/src/components/DateStrip/DateStrip.tokens.scss +23 -0
  348. package/src/components/DateStrip/DateStrip.tsx +205 -0
  349. package/src/components/DateStrip/index.ts +2 -0
  350. package/src/components/DefinitionList/DefinitionList.module.scss +102 -0
  351. package/src/components/DefinitionList/DefinitionList.tokens.scss +29 -0
  352. package/src/components/DefinitionList/DefinitionList.tsx +198 -0
  353. package/src/components/DefinitionList/index.ts +9 -0
  354. package/src/components/Divider/Divider.module.scss +144 -0
  355. package/src/components/Divider/Divider.tokens.scss +21 -0
  356. package/src/components/Divider/Divider.tsx +103 -0
  357. package/src/components/Divider/index.ts +2 -0
  358. package/src/components/Dot/Dot.module.scss +40 -0
  359. package/src/components/Dot/Dot.tokens.scss +4 -0
  360. package/src/components/Dot/Dot.tsx +45 -0
  361. package/src/components/Dot/index.ts +2 -0
  362. package/src/components/Drawer/Body.tsx +23 -0
  363. package/src/components/Drawer/Close.tsx +35 -0
  364. package/src/components/Drawer/Content.tsx +93 -0
  365. package/src/components/Drawer/Drawer.module.scss +232 -0
  366. package/src/components/Drawer/Drawer.tokens.scss +38 -0
  367. package/src/components/Drawer/Drawer.tsx +23 -0
  368. package/src/components/Drawer/DrawerRoot.tsx +190 -0
  369. package/src/components/Drawer/Footer.tsx +24 -0
  370. package/src/components/Drawer/Header.tsx +64 -0
  371. package/src/components/Drawer/Overlay.tsx +82 -0
  372. package/src/components/Drawer/context.ts +44 -0
  373. package/src/components/Drawer/index.ts +12 -0
  374. package/src/components/Drawer/useDragToClose.ts +149 -0
  375. package/src/components/DropdownMenu/CheckboxItem.tsx +144 -0
  376. package/src/components/DropdownMenu/Content.tsx +419 -0
  377. package/src/components/DropdownMenu/DropdownMenu.module.scss +280 -0
  378. package/src/components/DropdownMenu/DropdownMenu.tokens.scss +88 -0
  379. package/src/components/DropdownMenu/DropdownMenu.tsx +43 -0
  380. package/src/components/DropdownMenu/Group.tsx +76 -0
  381. package/src/components/DropdownMenu/Item.tsx +148 -0
  382. package/src/components/DropdownMenu/ItemIndicator.tsx +30 -0
  383. package/src/components/DropdownMenu/Radio.tsx +178 -0
  384. package/src/components/DropdownMenu/Root.tsx +100 -0
  385. package/src/components/DropdownMenu/Sub.tsx +332 -0
  386. package/src/components/DropdownMenu/Trigger.tsx +76 -0
  387. package/src/components/DropdownMenu/context.ts +65 -0
  388. package/src/components/DropdownMenu/index.ts +20 -0
  389. package/src/components/EmojiPicker/EmojiPicker.module.scss +84 -0
  390. package/src/components/EmojiPicker/EmojiPicker.tokens.scss +24 -0
  391. package/src/components/EmojiPicker/EmojiPicker.tsx +341 -0
  392. package/src/components/EmojiPicker/emojiData.ts +245 -0
  393. package/src/components/EmojiPicker/index.ts +3 -0
  394. package/src/components/EmptyState/EmptyState.module.scss +102 -0
  395. package/src/components/EmptyState/EmptyState.tokens.scss +28 -0
  396. package/src/components/EmptyState/EmptyState.tsx +112 -0
  397. package/src/components/EmptyState/index.ts +7 -0
  398. package/src/components/EntityChip/EntityChip.module.scss +275 -0
  399. package/src/components/EntityChip/EntityChip.tokens.scss +66 -0
  400. package/src/components/EntityChip/EntityChip.tsx +649 -0
  401. package/src/components/EntityChip/index.ts +10 -0
  402. package/src/components/ErrorState/ErrorState.module.scss +105 -0
  403. package/src/components/ErrorState/ErrorState.tokens.scss +32 -0
  404. package/src/components/ErrorState/ErrorState.tsx +125 -0
  405. package/src/components/ErrorState/index.ts +8 -0
  406. package/src/components/Field/Field.module.scss +46 -0
  407. package/src/components/Field/Field.tsx +185 -0
  408. package/src/components/Field/index.ts +2 -0
  409. package/src/components/FileUpload/FileUpload.module.scss +187 -0
  410. package/src/components/FileUpload/FileUpload.tokens.scss +81 -0
  411. package/src/components/FileUpload/FileUpload.tsx +569 -0
  412. package/src/components/FileUpload/formatBytes.ts +34 -0
  413. package/src/components/FileUpload/iconForFile.ts +40 -0
  414. package/src/components/FileUpload/index.ts +2 -0
  415. package/src/components/FilterChip/FilterChip.module.scss +61 -0
  416. package/src/components/FilterChip/FilterChip.tokens.scss +25 -0
  417. package/src/components/FilterChip/FilterChip.tsx +208 -0
  418. package/src/components/FilterChip/index.ts +5 -0
  419. package/src/components/FlowCanvas/FlowCanvas.module.scss +329 -0
  420. package/src/components/FlowCanvas/FlowCanvas.tokens.scss +45 -0
  421. package/src/components/FlowCanvas/FlowCanvas.tsx +1867 -0
  422. package/src/components/FlowCanvas/FlowControls.tsx +46 -0
  423. package/src/components/FlowCanvas/FlowEdge.tsx +58 -0
  424. package/src/components/FlowCanvas/FlowNode.tsx +76 -0
  425. package/src/components/FlowCanvas/edgePath.ts +85 -0
  426. package/src/components/FlowCanvas/index.ts +4 -0
  427. package/src/components/FlowCanvas/layout.ts +148 -0
  428. package/src/components/FlowCanvas/spatialNav.ts +76 -0
  429. package/src/components/FlowCanvas/types.ts +59 -0
  430. package/src/components/FlowCanvas/useViewport.ts +122 -0
  431. package/src/components/FormRow/FormRow.module.scss +2 -0
  432. package/src/components/FormRow/FormRow.tsx +37 -0
  433. package/src/components/FormRow/index.ts +2 -0
  434. package/src/components/FormSection/FormSection.module.scss +24 -0
  435. package/src/components/FormSection/FormSection.tsx +46 -0
  436. package/src/components/FormSection/index.ts +2 -0
  437. package/src/components/Grid/Grid.module.scss +162 -0
  438. package/src/components/Grid/Grid.tokens.scss +13 -0
  439. package/src/components/Grid/Grid.tsx +226 -0
  440. package/src/components/Grid/GridItem.tsx +77 -0
  441. package/src/components/Grid/index.ts +11 -0
  442. package/src/components/Highlight/Highlight.module.scss +43 -0
  443. package/src/components/Highlight/Highlight.tokens.scss +35 -0
  444. package/src/components/Highlight/Highlight.tsx +164 -0
  445. package/src/components/Highlight/HighlightOverlay.tsx +100 -0
  446. package/src/components/Highlight/index.ts +2 -0
  447. package/src/components/HighlightedText/HighlightedText.module.scss +11 -0
  448. package/src/components/HighlightedText/HighlightedText.tokens.scss +9 -0
  449. package/src/components/HighlightedText/HighlightedText.tsx +50 -0
  450. package/src/components/HighlightedText/highlightRanges.ts +44 -0
  451. package/src/components/HighlightedText/index.ts +2 -0
  452. package/src/components/IconPicker/IconPicker.module.scss +175 -0
  453. package/src/components/IconPicker/IconPicker.tokens.scss +40 -0
  454. package/src/components/IconPicker/IconPicker.tsx +629 -0
  455. package/src/components/IconPicker/index.ts +9 -0
  456. package/src/components/IconTile/IconTile.module.scss +57 -0
  457. package/src/components/IconTile/IconTile.tokens.scss +16 -0
  458. package/src/components/IconTile/IconTile.tsx +91 -0
  459. package/src/components/IconTile/index.ts +2 -0
  460. package/src/components/Image/Image.module.scss +266 -0
  461. package/src/components/Image/Image.tokens.scss +55 -0
  462. package/src/components/Image/Image.tsx +342 -0
  463. package/src/components/Image/index.ts +2 -0
  464. package/src/components/ImageCrop/ImageCrop.module.scss +274 -0
  465. package/src/components/ImageCrop/ImageCrop.tokens.scss +33 -0
  466. package/src/components/ImageCrop/ImageCrop.tsx +542 -0
  467. package/src/components/ImageCrop/cropGeometry.ts +120 -0
  468. package/src/components/ImageCrop/extractCropBlob.ts +140 -0
  469. package/src/components/ImageCrop/index.ts +11 -0
  470. package/src/components/ImageCrop/useCropPreview.ts +161 -0
  471. package/src/components/Indent/Indent.module.scss +33 -0
  472. package/src/components/Indent/Indent.tokens.scss +10 -0
  473. package/src/components/Indent/Indent.tsx +46 -0
  474. package/src/components/Indent/index.ts +2 -0
  475. package/src/components/Input/Input.module.scss +99 -0
  476. package/src/components/Input/Input.tokens.scss +54 -0
  477. package/src/components/Input/Input.tsx +105 -0
  478. package/src/components/Input/Suggestions.tsx +260 -0
  479. package/src/components/Input/index.ts +2 -0
  480. package/src/components/Kanban/Kanban.module.scss +39 -0
  481. package/src/components/Kanban/Kanban.tokens.scss +15 -0
  482. package/src/components/Kanban/Kanban.tsx +951 -0
  483. package/src/components/Kanban/index.ts +7 -0
  484. package/src/components/Kbd/Kbd.module.scss +47 -0
  485. package/src/components/Kbd/Kbd.tokens.scss +26 -0
  486. package/src/components/Kbd/Kbd.tsx +73 -0
  487. package/src/components/Kbd/index.ts +2 -0
  488. package/src/components/Lightbox/Lightbox.module.scss +283 -0
  489. package/src/components/Lightbox/Lightbox.tokens.scss +36 -0
  490. package/src/components/Lightbox/Lightbox.tsx +506 -0
  491. package/src/components/Lightbox/index.ts +2 -0
  492. package/src/components/Link/Link.module.scss +78 -0
  493. package/src/components/Link/Link.tokens.scss +28 -0
  494. package/src/components/Link/Link.tsx +114 -0
  495. package/src/components/Link/index.ts +2 -0
  496. package/src/components/LinkCard/LinkCard.module.scss +92 -0
  497. package/src/components/LinkCard/LinkCard.tokens.scss +9 -0
  498. package/src/components/LinkCard/LinkCard.tsx +72 -0
  499. package/src/components/LinkCard/index.ts +2 -0
  500. package/src/components/LiquidEditor/AutocompleteMenu.tsx +133 -0
  501. package/src/components/LiquidEditor/HighlightLayer.tsx +53 -0
  502. package/src/components/LiquidEditor/InsertVariableMenu.tsx +81 -0
  503. package/src/components/LiquidEditor/LiquidEditor.module.scss +339 -0
  504. package/src/components/LiquidEditor/LiquidEditor.tokens.scss +81 -0
  505. package/src/components/LiquidEditor/LiquidEditor.tsx +412 -0
  506. package/src/components/LiquidEditor/PreviewPane.tsx +29 -0
  507. package/src/components/LiquidEditor/caretCoordinates.ts +97 -0
  508. package/src/components/LiquidEditor/index.ts +7 -0
  509. package/src/components/LiquidEditor/liquidFilters.ts +23 -0
  510. package/src/components/LiquidEditor/liquidTokenizer.ts +235 -0
  511. package/src/components/LiquidEditor/types.ts +101 -0
  512. package/src/components/LiquidEditor/useLiquidAutocomplete.ts +178 -0
  513. package/src/components/List/List.module.scss +105 -0
  514. package/src/components/List/List.tokens.scss +42 -0
  515. package/src/components/List/List.tsx +124 -0
  516. package/src/components/List/index.ts +9 -0
  517. package/src/components/LiveRegion/LiveRegion.module.scss +3 -0
  518. package/src/components/LiveRegion/LiveRegion.tsx +116 -0
  519. package/src/components/LiveRegion/index.ts +2 -0
  520. package/src/components/Logo/Logo.module.scss +139 -0
  521. package/src/components/Logo/Logo.tokens.scss +14 -0
  522. package/src/components/Logo/Logo.tsx +126 -0
  523. package/src/components/Logo/index.ts +2 -0
  524. package/src/components/Masonry/Masonry.module.scss +42 -0
  525. package/src/components/Masonry/Masonry.tokens.scss +8 -0
  526. package/src/components/Masonry/Masonry.tsx +136 -0
  527. package/src/components/Masonry/index.ts +2 -0
  528. package/src/components/Masonry/masonryUtils.ts +42 -0
  529. package/src/components/MediaTile/MediaTile.module.scss +183 -0
  530. package/src/components/MediaTile/MediaTile.tokens.scss +60 -0
  531. package/src/components/MediaTile/MediaTile.tsx +208 -0
  532. package/src/components/MediaTile/index.ts +8 -0
  533. package/src/components/Modal/Body.tsx +27 -0
  534. package/src/components/Modal/Close.tsx +45 -0
  535. package/src/components/Modal/Content.tsx +98 -0
  536. package/src/components/Modal/Footer.tsx +28 -0
  537. package/src/components/Modal/Header.tsx +51 -0
  538. package/src/components/Modal/Modal.module.scss +262 -0
  539. package/src/components/Modal/Modal.tokens.scss +50 -0
  540. package/src/components/Modal/Modal.tsx +23 -0
  541. package/src/components/Modal/ModalRoot.tsx +299 -0
  542. package/src/components/Modal/Overlay.tsx +101 -0
  543. package/src/components/Modal/context.ts +60 -0
  544. package/src/components/Modal/index.ts +11 -0
  545. package/src/components/MoneyInput/MoneyInput.module.scss +57 -0
  546. package/src/components/MoneyInput/MoneyInput.tsx +433 -0
  547. package/src/components/MoneyInput/index.ts +2 -0
  548. package/src/components/OptionsPicker/OptionsPicker.module.scss +216 -0
  549. package/src/components/OptionsPicker/OptionsPicker.tokens.scss +68 -0
  550. package/src/components/OptionsPicker/OptionsPicker.tsx +936 -0
  551. package/src/components/OptionsPicker/index.ts +9 -0
  552. package/src/components/OtpInput/OtpInput.module.scss +69 -0
  553. package/src/components/OtpInput/OtpInput.tokens.scss +45 -0
  554. package/src/components/OtpInput/OtpInput.tsx +368 -0
  555. package/src/components/OtpInput/index.ts +2 -0
  556. package/src/components/Page/Page.module.scss +30 -0
  557. package/src/components/Page/Page.tokens.scss +11 -0
  558. package/src/components/Page/Page.tsx +53 -0
  559. package/src/components/Page/index.ts +2 -0
  560. package/src/components/PageHeader/PageHeader.module.scss +197 -0
  561. package/src/components/PageHeader/PageHeader.tokens.scss +41 -0
  562. package/src/components/PageHeader/PageHeader.tsx +310 -0
  563. package/src/components/PageHeader/index.ts +20 -0
  564. package/src/components/Pagination/Pagination.module.scss +117 -0
  565. package/src/components/Pagination/Pagination.tokens.scss +54 -0
  566. package/src/components/Pagination/Pagination.tsx +165 -0
  567. package/src/components/Pagination/index.ts +4 -0
  568. package/src/components/Pagination/paginationRange.ts +72 -0
  569. package/src/components/PasswordInput/PasswordInput.module.scss +120 -0
  570. package/src/components/PasswordInput/PasswordInput.tokens.scss +44 -0
  571. package/src/components/PasswordInput/PasswordInput.tsx +210 -0
  572. package/src/components/PasswordInput/index.ts +2 -0
  573. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.module.scss +80 -0
  574. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tokens.scss +40 -0
  575. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tsx +96 -0
  576. package/src/components/PasswordStrengthMeter/index.ts +2 -0
  577. package/src/components/PersonDisplay/PersonDisplay.module.scss +180 -0
  578. package/src/components/PersonDisplay/PersonDisplay.tokens.scss +35 -0
  579. package/src/components/PersonDisplay/PersonDisplay.tsx +420 -0
  580. package/src/components/PersonDisplay/index.ts +10 -0
  581. package/src/components/PhoneInput/PhoneInput.module.scss +23 -0
  582. package/src/components/PhoneInput/PhoneInput.tsx +271 -0
  583. package/src/components/PhoneInput/index.ts +4 -0
  584. package/src/components/PhoneInput/phone.ts +128 -0
  585. package/src/components/PillMenu/PillMenu.module.scss +117 -0
  586. package/src/components/PillMenu/PillMenu.tokens.scss +22 -0
  587. package/src/components/PillMenu/PillMenu.tsx +324 -0
  588. package/src/components/PillMenu/index.ts +2 -0
  589. package/src/components/Popover/Anchor.tsx +37 -0
  590. package/src/components/Popover/Close.tsx +45 -0
  591. package/src/components/Popover/Content.tsx +213 -0
  592. package/src/components/Popover/Heading.tsx +33 -0
  593. package/src/components/Popover/Popover.module.scss +177 -0
  594. package/src/components/Popover/Popover.tokens.scss +22 -0
  595. package/src/components/Popover/Popover.tsx +23 -0
  596. package/src/components/Popover/PopoverRoot.tsx +75 -0
  597. package/src/components/Popover/Trigger.tsx +86 -0
  598. package/src/components/Popover/context.ts +22 -0
  599. package/src/components/Popover/index.ts +7 -0
  600. package/src/components/Progress/Progress.module.scss +110 -0
  601. package/src/components/Progress/Progress.tokens.scss +44 -0
  602. package/src/components/Progress/Progress.tsx +129 -0
  603. package/src/components/Progress/index.ts +2 -0
  604. package/src/components/QrCode/QrCode.module.scss +97 -0
  605. package/src/components/QrCode/QrCode.tokens.scss +17 -0
  606. package/src/components/QrCode/QrCode.tsx +233 -0
  607. package/src/components/QrCode/index.ts +2 -0
  608. package/src/components/QrCode/qr.ts +161 -0
  609. package/src/components/Radio/Radio.module.scss +175 -0
  610. package/src/components/Radio/Radio.tokens.scss +59 -0
  611. package/src/components/Radio/Radio.tsx +127 -0
  612. package/src/components/Radio/RadioGroup.module.scss +42 -0
  613. package/src/components/Radio/RadioGroup.tsx +120 -0
  614. package/src/components/Radio/RadioGroupContext.tsx +30 -0
  615. package/src/components/Radio/index.ts +4 -0
  616. package/src/components/Rail/Rail.module.scss +510 -0
  617. package/src/components/Rail/Rail.tokens.scss +92 -0
  618. package/src/components/Rail/Rail.tsx +287 -0
  619. package/src/components/Rail/RailCollapseToggle.tsx +57 -0
  620. package/src/components/Rail/RailFooter.tsx +17 -0
  621. package/src/components/Rail/RailGroup.tsx +728 -0
  622. package/src/components/Rail/RailGroupContext.ts +9 -0
  623. package/src/components/Rail/RailHeader.tsx +23 -0
  624. package/src/components/Rail/RailItem.tsx +119 -0
  625. package/src/components/Rail/RailSection.tsx +39 -0
  626. package/src/components/Rail/RailSpacer.tsx +19 -0
  627. package/src/components/Rail/index.ts +9 -0
  628. package/src/components/RelativeDateInput/RelativeDateInput.module.scss +15 -0
  629. package/src/components/RelativeDateInput/RelativeDateInput.tokens.scss +6 -0
  630. package/src/components/RelativeDateInput/RelativeDateInput.tsx +474 -0
  631. package/src/components/RelativeDateInput/index.ts +10 -0
  632. package/src/components/RelativeDateInput/relativeDate.ts +127 -0
  633. package/src/components/RichText/RichText.module.scss +5 -0
  634. package/src/components/RichText/RichText.tsx +70 -0
  635. package/src/components/RichText/RichTextAttachment.module.scss +82 -0
  636. package/src/components/RichText/RichTextAttachment.tsx +122 -0
  637. package/src/components/RichText/_prose.scss +79 -0
  638. package/src/components/RichText/attachmentIcon.tsx +24 -0
  639. package/src/components/RichText/engine/attachment.ts +154 -0
  640. package/src/components/RichText/engine/autolink.ts +64 -0
  641. package/src/components/RichText/engine/blockUnit.ts +174 -0
  642. package/src/components/RichText/engine/colorMarks.ts +85 -0
  643. package/src/components/RichText/engine/escape.ts +11 -0
  644. package/src/components/RichText/engine/fromHtml.ts +353 -0
  645. package/src/components/RichText/engine/fromMarkdown.ts +20 -0
  646. package/src/components/RichText/engine/inlines.ts +82 -0
  647. package/src/components/RichText/engine/listDepths.ts +32 -0
  648. package/src/components/RichText/engine/marks.ts +80 -0
  649. package/src/components/RichText/engine/mdToHtml.ts +178 -0
  650. package/src/components/RichText/engine/model.ts +157 -0
  651. package/src/components/RichText/engine/position.ts +118 -0
  652. package/src/components/RichText/engine/renderDoc.tsx +395 -0
  653. package/src/components/RichText/engine/renderLink.ts +15 -0
  654. package/src/components/RichText/engine/renderMention.ts +16 -0
  655. package/src/components/RichText/engine/safeHref.ts +22 -0
  656. package/src/components/RichText/engine/toHtml.ts +154 -0
  657. package/src/components/RichText/engine/toMarkdown.ts +97 -0
  658. package/src/components/RichText/engine/transforms.ts +434 -0
  659. package/src/components/RichText/imageMaxHeightStyle.ts +10 -0
  660. package/src/components/RichText/index.ts +31 -0
  661. package/src/components/RichTextEditor/RichTextAttachmentConfig.tsx +264 -0
  662. package/src/components/RichTextEditor/RichTextBlockControls.tsx +365 -0
  663. package/src/components/RichTextEditor/RichTextBlockMenu.tsx +162 -0
  664. package/src/components/RichTextEditor/RichTextColorMenu.tsx +115 -0
  665. package/src/components/RichTextEditor/RichTextEditor.module.scss +298 -0
  666. package/src/components/RichTextEditor/RichTextEditor.tsx +1910 -0
  667. package/src/components/RichTextEditor/RichTextImageResizer.tsx +131 -0
  668. package/src/components/RichTextEditor/RichTextLinkEditor.tsx +151 -0
  669. package/src/components/RichTextEditor/RichTextMentionMenu.tsx +99 -0
  670. package/src/components/RichTextEditor/RichTextToolbar.tsx +379 -0
  671. package/src/components/RichTextEditor/autolinkInput.ts +65 -0
  672. package/src/components/RichTextEditor/blockDrop.ts +9 -0
  673. package/src/components/RichTextEditor/blockReflow.ts +62 -0
  674. package/src/components/RichTextEditor/commands.ts +300 -0
  675. package/src/components/RichTextEditor/history.ts +93 -0
  676. package/src/components/RichTextEditor/icons.tsx +152 -0
  677. package/src/components/RichTextEditor/imageSize.ts +70 -0
  678. package/src/components/RichTextEditor/index.ts +5 -0
  679. package/src/components/RichTextEditor/input.ts +209 -0
  680. package/src/components/RichTextEditor/inputRules.ts +71 -0
  681. package/src/components/RichTextEditor/links.ts +103 -0
  682. package/src/components/RichTextEditor/mentionContext.ts +37 -0
  683. package/src/components/RichTextEditor/mentions.ts +28 -0
  684. package/src/components/RichTextEditor/preventSelectionLoss.ts +15 -0
  685. package/src/components/RichTextEditor/selection.ts +415 -0
  686. package/src/components/RichTextEditor/shortcuts.ts +44 -0
  687. package/src/components/RichTextEditor/useAnchoredFloating.ts +50 -0
  688. package/src/components/RichTextEditor/useAttachmentConfig.ts +134 -0
  689. package/src/components/RichTextEditor/useDismissOnOutsidePointerDown.ts +26 -0
  690. package/src/components/RichTextEditor/useLinkEditor.ts +107 -0
  691. package/src/components/RichTextEditor/useMention.ts +226 -0
  692. package/src/components/RichTextEditor/useOverlayRect.ts +73 -0
  693. package/src/components/RichTextEditor/useUpload.ts +246 -0
  694. package/src/components/Screen/Screen.module.scss +46 -0
  695. package/src/components/Screen/Screen.tokens.scss +20 -0
  696. package/src/components/Screen/Screen.tsx +97 -0
  697. package/src/components/Screen/index.ts +2 -0
  698. package/src/components/ScrollArea/ScrollArea.module.scss +39 -0
  699. package/src/components/ScrollArea/ScrollArea.tokens.scss +15 -0
  700. package/src/components/ScrollArea/ScrollArea.tsx +154 -0
  701. package/src/components/ScrollArea/index.ts +2 -0
  702. package/src/components/Select/Chip.tsx +45 -0
  703. package/src/components/Select/Empty.tsx +39 -0
  704. package/src/components/Select/Error.tsx +51 -0
  705. package/src/components/Select/HiddenInputs.tsx +44 -0
  706. package/src/components/Select/Listbox.tsx +557 -0
  707. package/src/components/Select/Loading.tsx +30 -0
  708. package/src/components/Select/Select.module.scss +512 -0
  709. package/src/components/Select/Select.tokens.scss +140 -0
  710. package/src/components/Select/Select.tsx +685 -0
  711. package/src/components/Select/Trigger.tsx +952 -0
  712. package/src/components/Select/context.ts +101 -0
  713. package/src/components/Select/emptyStateText.ts +19 -0
  714. package/src/components/Select/index.ts +9 -0
  715. package/src/components/Select/useSelectState.ts +157 -0
  716. package/src/components/Select/utils-types.ts +7 -0
  717. package/src/components/Select/utils.ts +122 -0
  718. package/src/components/SettingRow/SettingRow.module.scss +166 -0
  719. package/src/components/SettingRow/SettingRow.tokens.scss +37 -0
  720. package/src/components/SettingRow/SettingRow.tsx +242 -0
  721. package/src/components/SettingRow/index.ts +7 -0
  722. package/src/components/Skeleton/Skeleton.module.scss +55 -0
  723. package/src/components/Skeleton/Skeleton.tokens.scss +17 -0
  724. package/src/components/Skeleton/Skeleton.tsx +131 -0
  725. package/src/components/Skeleton/index.ts +4 -0
  726. package/src/components/Skeleton/useSkeletonVisibility.ts +95 -0
  727. package/src/components/Slider/Slider.module.scss +293 -0
  728. package/src/components/Slider/Slider.tokens.scss +98 -0
  729. package/src/components/Slider/Slider.tsx +624 -0
  730. package/src/components/Slider/index.ts +9 -0
  731. package/src/components/SlotGrid/SlotGrid.module.scss +61 -0
  732. package/src/components/SlotGrid/SlotGrid.tokens.scss +21 -0
  733. package/src/components/SlotGrid/SlotGrid.tsx +111 -0
  734. package/src/components/SlotGrid/index.ts +2 -0
  735. package/src/components/SocialButton/SocialButton.module.scss +4 -0
  736. package/src/components/SocialButton/SocialButton.tsx +40 -0
  737. package/src/components/SocialButton/index.ts +2 -0
  738. package/src/components/Sortable/Sortable.module.scss +177 -0
  739. package/src/components/Sortable/Sortable.tokens.scss +27 -0
  740. package/src/components/Sortable/Sortable.tsx +572 -0
  741. package/src/components/Sortable/containerAwareCollision.ts +125 -0
  742. package/src/components/Sortable/index.ts +13 -0
  743. package/src/components/SortableGroup/SortableGroup.module.scss +23 -0
  744. package/src/components/SortableGroup/SortableGroup.tsx +315 -0
  745. package/src/components/SortableGroup/index.ts +4 -0
  746. package/src/components/SortableGroup/moveSortableItem.ts +39 -0
  747. package/src/components/Sparkline/Sparkline.module.scss +28 -0
  748. package/src/components/Sparkline/Sparkline.tokens.scss +7 -0
  749. package/src/components/Sparkline/Sparkline.tsx +133 -0
  750. package/src/components/Sparkline/index.ts +2 -0
  751. package/src/components/Sparkline/sparklineModel.ts +119 -0
  752. package/src/components/Split/Split.module.scss +158 -0
  753. package/src/components/Split/Split.tokens.scss +10 -0
  754. package/src/components/Split/Split.tsx +231 -0
  755. package/src/components/Split/index.ts +2 -0
  756. package/src/components/Stack/Stack.module.scss +67 -0
  757. package/src/components/Stack/Stack.tokens.scss +11 -0
  758. package/src/components/Stack/Stack.tsx +100 -0
  759. package/src/components/Stack/index.ts +2 -0
  760. package/src/components/StagePath/StagePath.module.scss +255 -0
  761. package/src/components/StagePath/StagePath.tokens.scss +43 -0
  762. package/src/components/StagePath/StagePath.tsx +176 -0
  763. package/src/components/StagePath/index.ts +2 -0
  764. package/src/components/StatGroup/StatGroup.module.scss +6 -0
  765. package/src/components/StatGroup/StatGroup.tsx +70 -0
  766. package/src/components/StatGroup/StatGroupContext.ts +10 -0
  767. package/src/components/StatGroup/StatTile.module.scss +99 -0
  768. package/src/components/StatGroup/StatTile.tokens.scss +35 -0
  769. package/src/components/StatGroup/StatTile.tsx +143 -0
  770. package/src/components/StatGroup/index.ts +4 -0
  771. package/src/components/Sticky/Sticky.module.scss +98 -0
  772. package/src/components/Sticky/Sticky.tokens.scss +17 -0
  773. package/src/components/Sticky/Sticky.tsx +103 -0
  774. package/src/components/Sticky/index.ts +2 -0
  775. package/src/components/Switch/Switch.module.scss +182 -0
  776. package/src/components/Switch/Switch.tokens.scss +59 -0
  777. package/src/components/Switch/Switch.tsx +214 -0
  778. package/src/components/Switch/index.ts +2 -0
  779. package/src/components/Table/Table.module.scss +308 -0
  780. package/src/components/Table/Table.tokens.scss +79 -0
  781. package/src/components/Table/Table.tsx +381 -0
  782. package/src/components/Table/index.ts +15 -0
  783. package/src/components/TableOfContents/TableOfContents.module.scss +83 -0
  784. package/src/components/TableOfContents/TableOfContents.tokens.scss +26 -0
  785. package/src/components/TableOfContents/TableOfContents.tsx +192 -0
  786. package/src/components/TableOfContents/activeSection.ts +18 -0
  787. package/src/components/TableOfContents/index.ts +2 -0
  788. package/src/components/Tabs/Tabs.module.scss +359 -0
  789. package/src/components/Tabs/Tabs.tokens.scss +50 -0
  790. package/src/components/Tabs/Tabs.tsx +538 -0
  791. package/src/components/Tabs/index.ts +2 -0
  792. package/src/components/Text/Text.module.scss +115 -0
  793. package/src/components/Text/Text.tokens.scss +55 -0
  794. package/src/components/Text/Text.tsx +197 -0
  795. package/src/components/Text/index.ts +2 -0
  796. package/src/components/Textarea/Textarea.module.scss +94 -0
  797. package/src/components/Textarea/Textarea.tokens.scss +48 -0
  798. package/src/components/Textarea/Textarea.tsx +246 -0
  799. package/src/components/Textarea/index.ts +2 -0
  800. package/src/components/Thread/Thread.module.scss +161 -0
  801. package/src/components/Thread/Thread.tokens.scss +32 -0
  802. package/src/components/Thread/Thread.tsx +176 -0
  803. package/src/components/Thread/index.ts +2 -0
  804. package/src/components/TimeField/TimeField.module.scss +232 -0
  805. package/src/components/TimeField/TimeField.tsx +793 -0
  806. package/src/components/TimeField/index.ts +2 -0
  807. package/src/components/Timeline/Timeline.module.scss +58 -0
  808. package/src/components/Timeline/Timeline.tokens.scss +13 -0
  809. package/src/components/Timeline/Timeline.tsx +53 -0
  810. package/src/components/Timeline/index.ts +2 -0
  811. package/src/components/Title/Title.module.scss +84 -0
  812. package/src/components/Title/Title.tokens.scss +37 -0
  813. package/src/components/Title/Title.tsx +150 -0
  814. package/src/components/Title/index.ts +2 -0
  815. package/src/components/Toast/Toast.module.scss +299 -0
  816. package/src/components/Toast/Toast.tokens.scss +65 -0
  817. package/src/components/Toast/Toast.tsx +122 -0
  818. package/src/components/Toast/ToastViewport.tsx +166 -0
  819. package/src/components/Toast/api.ts +175 -0
  820. package/src/components/Toast/index.ts +5 -0
  821. package/src/components/Toast/store.ts +133 -0
  822. package/src/components/Toast/useToastTimer.ts +94 -0
  823. package/src/components/Tooltip/Tooltip.module.scss +99 -0
  824. package/src/components/Tooltip/Tooltip.tokens.scss +23 -0
  825. package/src/components/Tooltip/Tooltip.tsx +341 -0
  826. package/src/components/Tooltip/index.ts +2 -0
  827. package/src/components/TopBar/TopBar.module.scss +235 -0
  828. package/src/components/TopBar/TopBar.tokens.scss +79 -0
  829. package/src/components/TopBar/TopBar.tsx +87 -0
  830. package/src/components/TopBar/TopBarEnd.tsx +20 -0
  831. package/src/components/TopBar/TopBarIconButton.tsx +86 -0
  832. package/src/components/TopBar/TopBarSearch.tsx +319 -0
  833. package/src/components/TopBar/TopBarSearchPanel.tsx +268 -0
  834. package/src/components/TopBar/TopBarStart.tsx +20 -0
  835. package/src/components/TopBar/index.ts +11 -0
  836. package/src/components/Tour/Spotlight.tsx +121 -0
  837. package/src/components/Tour/Tour.module.scss +210 -0
  838. package/src/components/Tour/Tour.tokens.scss +58 -0
  839. package/src/components/Tour/Tour.tsx +617 -0
  840. package/src/components/Tour/index.ts +2 -0
  841. package/src/components/Tour/useTourTarget.ts +115 -0
  842. package/src/components/TreeView/TreeView.module.scss +268 -0
  843. package/src/components/TreeView/TreeView.tokens.scss +36 -0
  844. package/src/components/TreeView/TreeView.tsx +536 -0
  845. package/src/components/TreeView/index.ts +3 -0
  846. package/src/components/TreeView/treeModel.ts +224 -0
  847. package/src/components/VisuallyHidden/VisuallyHidden.module.scss +7 -0
  848. package/src/components/VisuallyHidden/VisuallyHidden.tsx +29 -0
  849. package/src/components/VisuallyHidden/index.ts +2 -0
  850. package/src/components/WidgetPreview/WidgetPreview.module.scss +11 -0
  851. package/src/components/WidgetPreview/WidgetPreview.tokens.scss +26 -0
  852. package/src/components/WidgetPreview/WidgetPreview.tsx +36 -0
  853. package/src/components/WidgetPreview/WidgetShape.module.scss +140 -0
  854. package/src/components/WidgetPreview/WidgetShape.tsx +159 -0
  855. package/src/components/WidgetPreview/index.ts +2 -0
  856. package/src/components/_internal/Trend.tsx +27 -0
  857. package/src/components/_internal/choiceTile.scss +74 -0
  858. package/src/components/_internal/collapse.scss +10 -0
  859. package/src/components/_internal/collapse.ts +58 -0
  860. package/src/components/_internal/currency.ts +257 -0
  861. package/src/components/_internal/dragAnnouncements.ts +200 -0
  862. package/src/components/_internal/fieldWiring.ts +225 -0
  863. package/src/components/_internal/gridSpan.ts +54 -0
  864. package/src/components/_internal/isoDay.ts +35 -0
  865. package/src/components/_internal/letterKey.ts +26 -0
  866. package/src/components/_internal/overlay/focusRestore.ts +21 -0
  867. package/src/components/_internal/overlay/index.ts +12 -0
  868. package/src/components/_internal/overlay/tourHold.ts +23 -0
  869. package/src/components/_internal/overlay/useFocusTrap.ts +120 -0
  870. package/src/components/_internal/overlay/useInOverlay.ts +81 -0
  871. package/src/components/_internal/overlay/useOverlayStack.ts +232 -0
  872. package/src/components/_internal/overlay/useScrollLock.ts +112 -0
  873. package/src/components/_internal/refs.ts +48 -0
  874. package/src/components/_internal/statusColor.ts +26 -0
  875. package/src/components/_internal/timeUtils.ts +23 -0
  876. package/src/components/_internal/useAsyncOptions.ts +145 -0
  877. package/src/components/_internal/useClippedTooltip.ts +50 -0
  878. package/src/components/_internal/useControllableState.ts +50 -0
  879. package/src/components.manifest.json +1141 -0
  880. package/src/hooks/useBelowBreakpoint.ts +58 -0
  881. package/src/i18n/I18nProvider.tsx +52 -0
  882. package/src/i18n/LocaleProvider.tsx +17 -0
  883. package/src/i18n/en.ts +648 -0
  884. package/src/i18n/format.ts +71 -0
  885. package/src/i18n/index.ts +13 -0
  886. package/src/i18n/messages.ts +1275 -0
  887. package/src/i18n/ru.ts +677 -0
  888. package/src/i18n/useLocale.ts +19 -0
  889. package/src/i18n/useTranslation.ts +58 -0
  890. package/src/index.ts +913 -0
  891. package/src/palette/index.ts +2 -0
  892. package/src/palette/palette.ts +108 -0
  893. package/src/styles/dark.scss +4 -0
  894. package/src/styles/global.scss +7 -0
  895. package/src/styles/mixins.scss +143 -0
  896. package/src/styles/reset.scss +78 -0
  897. package/src/styles/tokens.scss +18 -0
  898. package/src/styles/typography.scss +44 -0
@@ -0,0 +1,39 @@
1
+ # `<Constrain>` — size / flex constraint
2
+
3
+ ```tsx
4
+ <Constrain maxWidth="sm"><Input placeholder="Search…" /></Constrain>
5
+
6
+ <Constrain height="viewport-70" maxHeight="lg"><FlowCanvas /></Constrain>
7
+
8
+ <Cluster wrap={false} gap="sm">
9
+ <Constrain flex="grow"><Progress value={x} max={y} /></Constrain>
10
+ <Button>Upgrade plan</Button>
11
+ </Cluster>
12
+ ```
13
+
14
+ <!-- props:start -->
15
+
16
+ ## Props
17
+
18
+ <!-- prettier-ignore -->
19
+ | Prop | Type | Required | Description |
20
+ |---|---|---|---|
21
+ | `width` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | no | Fixed width — a named step (`xs` 200 / `sm` 320 / `md` 448 / `lg` 640 / `xl` 800px, via `--measure-*` tokens) or `'full'` (100%). |
22
+ | `minWidth` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | no | Minimum width floor — a named step or `'full'` (100%). |
23
+ | `maxWidth` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | no | Maximum width cap — the common case (e.g. a search input at `'sm'`). |
24
+ | `height` | `'viewport' \| 'viewport-70' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'xs' \| 'full'` | no | Fixed height — a named measure (same scale as the widths), `'full'` (100%), `'viewport'` (100dvh), or `'viewport-70'` (70dvh). `height="viewport-70"` with `maxHeight="lg"` makes a viewport-relative panel that never exceeds 640px. |
25
+ | `minHeight` | `'viewport' \| 'viewport-70' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'xs' \| 'full'` | no | Minimum height floor — a named measure, `'full'`, `'viewport'`, or `'viewport-70'`. |
26
+ | `maxHeight` | `'viewport' \| 'viewport-70' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'xs' \| 'full'` | no | Maximum height cap — a named measure, `'full'`, `'viewport'`, or `'viewport-70'`. |
27
+ | `flex` | `'grow' \| 'shrink' \| 'auto' \| 'none'` | no | Flex behavior as a child of a flex row/column. - `'grow'` — fill remaining space (`flex: 1 1 0`) and shrink below content width (`min-width: 0`) so a truncating child (`<Text truncate>`) can clip. To opt a `Stack`/`Cluster` into that truncating chain WITHOUT also making it fill the row, use their `minWidth0` prop instead — and note Constrain renders a `<div>`, so it is invalid inside a `<button>`/`<a>`/`<label>`, where `<Cluster as="span" minWidth0>` is the only option. - `'auto'` — size to content, may grow/shrink (`flex: 1 1 auto`). - `'shrink'` — don't grow, may shrink (`flex: 0 1 auto`, the flex default). - `'none'` — fixed, never grow/shrink (`flex: 0 0 auto`). Omit for no flex class: the element behaves as its flex container dictates. |
28
+ | `children` | `ReactNode` | yes | The content to size. Required — a Constrain with nothing inside has nothing to constrain. |
29
+ | …native | | | plus native `<div>` attributes |
30
+
31
+ <!-- props:end -->
32
+
33
+ - The one place width/height/flex sizing lives — `Stack`/`Cluster`/`Grid` are spacing-only (Rule 4). Constrain sizes its **own** box; it does not arrange children (put a `Cluster`/`Stack` inside).
34
+ - No padding/border/background — for those use `<Card>`; for a full-bleed shell use `<Screen>`.
35
+
36
+ #### Anti-patterns
37
+
38
+ - ❌ Reaching for Constrain to add `margin` / `padding`. It carries size/flex only; spacing comes from the parent layout primitive.
39
+ - ❌ Spacing or arranging children: use `<Stack>` / `<Cluster>` / `<Grid>`.
@@ -0,0 +1,57 @@
1
+ # `<CurrencySelect>`
2
+
3
+ Currency picker over the DS `Select`: you pass the ISO 4217 `currencies` to offer (required, in display order); it renders `CODE — Name` rows with localized names (`Intl.DisplayNames`). Single mode is controlled on `value: string | null` / `onChange(code | null)`; `multiple` switches to `string[]` (with `triggerDisplay` `"chips"` / `"summary"`). `currencyDisplay` sets how the SELECTED currency shows in the trigger: `"code"` (default, `EUR`), `"symbol"` (`€`) or `"both"` (`EUR €`). Search turns on automatically above 7 currencies (`searchable` overrides) and matches code, name and symbol. Invalid codes are dropped with a dev warning. `size`/`invalid`/`disabled`/`clearable`/`name` etc. pass through to `Select`.
4
+
5
+ ```tsx
6
+ const [cur, setCur] = useState<string | null>('EUR');
7
+ <CurrencySelect
8
+ currencies={['EUR', 'USD', 'GBP']}
9
+ value={cur}
10
+ onChange={setCur}
11
+ aria-label="Currency"
12
+ />;
13
+ ```
14
+
15
+ <!-- props:start -->
16
+
17
+ ## Props
18
+
19
+ <!-- prettier-ignore -->
20
+ | Prop | Type | Required | Description |
21
+ |---|---|---|---|
22
+ | `currencies` | `string[]` | yes | ISO 4217 codes to offer, in display order (e.g. `['USD', 'EUR']`). Required; there is no "all currencies" default. Invalid codes are dropped with a dev warning. |
23
+ | `currencyDisplay` | `'code' \| 'symbol' \| 'both'` | no | How the SELECTED currency renders in the trigger. Default `"code"`. - `"code"` — `EUR`. - `"symbol"` — `€`. - `"both"` — `EUR €`. Dropdown rows always read `CODE — Name` so they stay identifiable and searchable. |
24
+ | `locale` | `string` | no | BCP-47 locale for currency names and symbols. Defaults to the active i18n locale (`useLocale()`). |
25
+ | `searchable` | `boolean` | no | Show a search input. Default: on when more than 7 currencies are offered. |
26
+ | `multiple` | `false \| true` | no | Single mode (default). |
27
+ | `value` | `string \| null \| string[]` | yes | Controlled ISO code; `null` = nothing selected. |
28
+ | `onChange` | `(code: string \| null) => void \| (codes: string[]) => void` | yes | Fires with the picked code, or `null` when cleared. |
29
+ | `triggerDisplay` | `'summary' \| 'chips'` | no | How selections render in the trigger: `"chips"` (default) or `"summary"`. |
30
+ | `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`. |
31
+ | `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. |
32
+ | `open` | `boolean` | no | Controlled open state. Pair with `onOpenChange`. Omit both to let Select own its open state (the common case). |
33
+ | `defaultOpen` | `boolean` | no | Initial open state for uncontrolled usage. Defaults to `false`. |
34
+ | `onOpenChange` | `((open: boolean) => void)` | no | Fires whenever Select wants to change open state. |
35
+ | `size` | `'sm' \| 'md' \| 'lg'` | no | Trigger height + type scale. See `SelectSize`. Defaults to `'md'`. |
36
+ | `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`. |
37
+ | `placeholder` | `string` | no | Placeholder shown when nothing is selected. In searchable mode, also the input's `placeholder` until the user types. |
38
+ | `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. |
39
+ | `disabled` | `boolean` | no | Disables the trigger entirely — non-interactive, dimmed, focusable only via assistive tech. Hidden form inputs are also disabled. |
40
+ | `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. |
41
+ | `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). |
42
+ | `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. |
43
+ | `form` | `string` | no | `form` attribute forwarded to the hidden `<input>` elements. |
44
+ | `aria-label` | `string` | no | Accessible name for the trigger. Use this when a visible `<label>` is not present. Mutually exclusive with `aria-labelledby`. |
45
+ | `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). |
46
+ | `aria-describedby` | `string` | no | ID of an element that describes the trigger — e.g. an error message or helper hint paired with `invalid`. |
47
+ | …native | | | plus native HTML attributes |
48
+
49
+ <!-- props:end -->
50
+
51
+ **When NOT to use:** an amount plus its currency — use `MoneyInput`. A generic option list — use `Select`.
52
+
53
+ **Anti-patterns**
54
+
55
+ - ❌ Passing `options`, `renderOption` or `creatable` — options are derived from `currencies`.
56
+ - ❌ Expecting an "all currencies" default — `currencies` is required; an empty list renders an empty picker.
57
+ - ❌ Passing lowercase or made-up codes — they are dropped (dev warning).
@@ -0,0 +1,43 @@
1
+ # `<CursorPagination>` — prev / next for streams without total
2
+
3
+ ```tsx
4
+ <CursorPagination hasPrevious={hasPrev} hasNext={hasNext} onPrevious={loadPrev} onNext={loadNext} />
5
+
6
+ // Activity feed with reversed direction labels
7
+ <CursorPagination
8
+ hasPrevious={hasNewer}
9
+ hasNext={hasOlder}
10
+ onPrevious={loadNewer}
11
+ onNext={loadOlder}
12
+ previousLabel="Newer"
13
+ nextLabel="Older"
14
+ />
15
+ ```
16
+
17
+ <!-- props:start -->
18
+
19
+ ## Props
20
+
21
+ <!-- prettier-ignore -->
22
+ | Prop | Type | Required | Description |
23
+ |---|---|---|---|
24
+ | `hasPrevious` | `boolean` | yes | Whether a previous page exists. When `false`, the previous button is rendered as `disabled` (layout stays stable; consumer doesn't have to conditionally hide it). |
25
+ | `hasNext` | `boolean` | yes | Whether a next page exists. |
26
+ | `onPrevious` | `() => void` | yes | Called when the user clicks previous (not fired when disabled). |
27
+ | `onNext` | `() => void` | yes | Called when the user clicks next (not fired when disabled). |
28
+ | `previousLabel` | `ReactNode` | no | Label for the previous button. Defaults to the i18n value at `pagination.previous` (`'Previous'` in English). Override for domain phrasing (`'Newer'` in a reverse-chronological feed). An EMPTY string counts as unset, not as an explicit blank: this label is the button's only name source (the chevron is `aria-hidden`), so an empty one would leave the button anonymous rather than merely unlabelled. |
29
+ | `nextLabel` | `ReactNode` | no | Label for the next button. Defaults to the i18n value at `pagination.next` (`'Next'` in English). An EMPTY string counts as unset, for the same reason as `previousLabel`. |
30
+ | `size` | `'sm' \| 'md' \| 'lg'` | no | Visual size — `'sm'` / `'md'` (default) / `'lg'`. Shares the `<Pagination>` size scale so the two components match when used alongside each other. |
31
+ | `disabled` | `boolean` | no | When `true`, both buttons are disabled regardless of has-prev/-next. |
32
+ | `aria-label` | `string` | no | Accessible name for the wrapper `<nav>`. Defaults to the i18n value at `pagination.ariaLabel` (`'Pagination'` in English) when omitted OR empty — an empty string is not an explicit name, so it takes the default too. |
33
+ | …native | | | plus native HTML attributes |
34
+
35
+ <!-- props:end -->
36
+
37
+ - Two-button prev / next nav for keyset-paginated streams (activity feeds, infinite scroll, cursor-based APIs). Controlled — consumer owns the cursor + `has-prev` / `has-next` flags.
38
+ - Buttons render as native `<button disabled>` when `hasPrevious` / `hasNext` is false — no layout shift; consumer doesn't have to conditionally hide them.
39
+ - Shares the `<Pagination>` size scale (`sm` / `md` / `lg`).
40
+ - Use `<Pagination>` (numbered) when you have a known total page count. CursorPagination is for streams.
41
+
42
+ - A11y: the wrapper is `<nav aria-label="Pagination">` (overridable for disambiguation). Disabled buttons are native, so screen readers announce "dimmed" and skip them in Tab order.
43
+ - Use `<Pagination>` (numbered, with jump-to-page and progress indication) when you have a total page count.
@@ -0,0 +1,79 @@
1
+ # `<DashboardCanvas>` — 2D snap-grid dashboard
2
+
3
+ Datadog-style 2D snap-grid dashboard. `value` is `{ items: DashboardPlacement[], sections: DashboardSection[] }` — top-level items plus an ordered array of full-width collapsible sections, each with its own sub-grid on the same column count (`columns` prop, default 24 — pass `columns={12}` for layouts saved against a 12-column schema like the eocrm layout-v2 spec; placements are NOT converted between column counts). Always controlled, no uncontrolled mode: `onChange(next)` fires once per completed gesture (a drop, a resize end, a collapse toggle, a band reorder, a cross-container move) with the whole engine-computed next value; omit it for a static layout — drags still preview live but nothing persists past pointerup. `renderItem(id)` renders every item's body — including items inside a COLLAPSED section, whose body stays mounted and `inert` rather than unmounting, so a widget that fetches on mount pays that cost even while collapsed — called once more for the drag ghost mid-gesture, so keep it pure. **The grid cell is chrome-less** (no background/border/radius/shadow, no minimum height beyond its `h` row-span) — wrap the return in `<Card>` for the boxed widget look, and size the content to the cell or accept bare (dotted, in edit mode) space showing below a shorter widget. `renderSectionHeader(id)` adds small extras (a title editor, a `DropdownMenu` trigger) to the right of a section's title, in the same `Accordion.Trigger` `actions` slot as the section's own band-reorder grip handle — neither ever starts a collapse toggle or a drag. `highlightedSectionId` highlights a section's band with a ring and outward waves (scrolls it into view first, works on collapsed bands, never moves focus) — set it to the id of a section you just added and clear it in `onSectionHighlightDone`; setting the same id again after that re-triggers. `constraints` — a `Record<id, { minW?, minH?, maxH? }>` or a `(id) => constraints | undefined` function — clamps resize gestures per item; unlisted items default to `minW: 1`, `minH: 1`, no `maxH`. Section bands compose the DS `Accordion` (`type="multiple"`) for their header/chevron/panel look; edit mode (not `readOnly`, not below `stackBelow`) also shows a snap-grid of dots on each container so a drag/resize's destination cell is visible before you commit.
4
+
5
+ Gestures: drag-to-move with push-down collision + live compaction preview (dropping on the upper/lower half of another widget inserts before/after it, so stacked widgets reorder without gaps; during a move-drag each container gains trailing drop space the height of the dragged item, and the drag ghost stays inside the canvas), E/S/SE resize handles, cross-container drag (top level ↔ any expanded section), and vertical band reorder by dragging a section header. Full keyboard: Tab to an item, Enter/Space picks it up, arrows move it (crossing a container's edge moves it into the next band), Shift+arrows resize, Enter/Space drops, Escape cancels; Shift+arrows on a focused section header reorders bands.
6
+
7
+ ```tsx
8
+ const [value, setValue] = useState<DashboardCanvasValue>(initialLayout);
9
+
10
+ <DashboardCanvas
11
+ value={value}
12
+ onChange={setValue}
13
+ renderItem={(id) => <Card>{widgets[id].title}</Card>}
14
+ constraints={{ kpi: { minW: 2, maxH: 4 } }}
15
+ />;
16
+ ```
17
+
18
+ <!-- props:start -->
19
+
20
+ ## Props
21
+
22
+ <!-- prettier-ignore -->
23
+ | Prop | Type | Required | Description |
24
+ |---|---|---|---|
25
+ | `value` | `DashboardCanvasValue` | yes | The controlled layout: top-level items plus an ordered array of collapsible sections. `DashboardCanvas` never mutates this value — every change flows out through `onChange`. |
26
+ | `onChange` | `((next: DashboardCanvasValue) => void)` | no | Fires once per completed gesture — a drop, a resize end, a collapse toggle, a section reorder, or a cross-container move — with the whole next `value`. Omit for a read-only or fully static canvas; without it, drags preview live but nothing persists on drop. |
27
+ | `renderItem` | `(id: string \| number) => ReactNode` | yes | Renders the body of an item by id. Called for every item on every render — including items inside a COLLAPSED section (its body stays mounted and `inert`, not unmounted, so Accordion's own collapse animation has real content to animate) — and once more for the dragged item mid-gesture (the cursor-following ghost). Keep it pure; a widget that fetches on mount pays that cost even while its section is collapsed. The cell itself is a bare positioned box with no background/border/radius/shadow of its own and no minimum height beyond its `h` row-span — that chrome belongs here, in whatever this returns (typically a `<Card>`); size the content to the cell, or accept that a shorter widget in a taller cell shows bare (dotted, in edit mode) space below it. |
28
+ | `renderSectionHeader` | `((id: string \| number) => ReactNode)` | no | Optional extra controls in a section's header (a title editor, a `DropdownMenu` trigger) rendered by section id, to the right of the title. Keep it small — the header row is not a general-purpose toolbar. Pointer presses inside the slot never start a band-reorder drag. |
29
+ | `highlightedSectionId` | `string \| number` | no | Id of a section whose band to highlight (scrolls into view, then a ring with outward waves, same as `Highlight`) — e.g. a section the user just added. Collapsed bands highlight too. Does not move focus. Clear it in `onSectionHighlightDone`; setting the same id again after that re-triggers. |
30
+ | `onSectionHighlightDone` | `(() => void)` | no | Fires once the highlight run on `highlightedSectionId` has finished. |
31
+ | `constraints` | `DashboardCanvasConstraintsProp` | no | Per-item size constraints, consulted when clamping resize gestures. |
32
+ | `columns` | `number` | no | Column count of every container grid (top level and each section's sub-grid). All placement/resize bounds clamp against it. Minimum 1; fractional or sub-1 values are the consumer's bug, not validated. Layouts are NOT converted between column counts — a `value` saved at one `columns` renders at half width when the count doubles. Schemas written for the earlier 12-column grid (e.g. the eocrm layout-v2 spec) either pass `columns={12}` to match, or migrate their saved placements to 24. Default: `24`. |
33
+ | `stackBelow` | `'sm' \| 'md' \| 'lg'` | no | Container width at (inclusive) and below which every container grid re-templates to one column and pointer + keyboard editing turns off: `sm` 480px / `md` 640px / `lg` 768px, measured against the canvas's OWN width (container query), not the viewport. Section collapse toggles keep working at any width. Default: `'md'`. |
34
+ | `readOnly` | `boolean` | no | View-only mode: identical geometry, but no drag/resize wiring, no resize handles, and no keyboard editing — the canvas renders `value` and lets section collapse toggles keep working. The canvas also disables editing on its own, without this prop, once its own width drops to or below the `stackBelow` breakpoint (single-column stack) — `readOnly` is for a consumer-chosen view mode, the width gate is automatic. Default: `false`. |
35
+ | …native | | | plus native `<div>` attributes |
36
+
37
+ <!-- props:end -->
38
+
39
+ **Cells are SQUARE by default**: the row unit derives from the canvas's own width (`(width - (columns - 1) * gap) / columns`), so cell height == cell width at every size and the whole layout scales fluidly — override `--dashboard-canvas-row` with a fixed length for fixed-height rows (`--dashboard-canvas-row-stacked`, default 48px, is the row unit of the single-column stack, where the square unit would be uselessly tiny).
40
+
41
+ `readOnly` turns off all editing (no handles, no keyboard editing) while section collapse toggles keep working — collapse is navigation, not editing. Independent of `readOnly`, at and below the `stackBelow` breakpoint (`'sm'` 480px / `'md'` 640px, the default / `'lg'` 768px) of the canvas's OWN width (a CSS container query, not the viewport) every container automatically re-templates to one column and editing turns off the same way — a `ResizeObserver` mirrors the breakpoint so a gesture can never half-start below it.
42
+
43
+ When NOT to use: a single ordered list (priority queue, simple reordering) — use `Sortable`; fixed kanban-style columns — use `Kanban`; a free-form node/edge graph — use `FlowCanvas`. The canvas is ALWAYS a size container (named `dashboard-canvas`, unconditionally) — give it a parent with a concrete width; an intrinsic-width context (a `Cluster` item, `width: max-content`) renders it at width 0, same caveat as Grid's `collapseBelow`.
44
+
45
+ A collapsed section's band is NOT a drop target — expand it first (no hover-to-expand). Escape or a pointer cancel mid-gesture restores the current `value` without firing `onChange`.
46
+
47
+ #### Anti-patterns
48
+
49
+ - ❌ Treating `value` as uncontrolled — passing it once with no `onChange`. Drags and resizes still preview live, but nothing persists past pointerup; the next render snaps the item back to the stale `value`.
50
+ - ❌ Nesting a `DashboardCanvas` inside another one's `renderItem`: a nested canvas fights its parent for pointer capture and Escape handling.
51
+ - ❌ Expecting the grid cell to draw a card-like surface. It is chrome-less by design so widgets with transparent bodies (charts, images) don't sit inside a redundant box — wrap `renderItem`'s output in `<Card>` for the boxed look.
52
+ - ❌ Using it for a simple ordered list — see "When NOT to use" above.
53
+ - ❌ Placing it in an intrinsic-width parent (a `Split` aside's default `auto` track, a `Cluster` item): the canvas is always a size container and renders at width 0. At and below `stackBelow` pointer + keyboard editing turns off (handles hidden, items not editing-focusable).
54
+
55
+ #### More examples
56
+
57
+ ```tsx
58
+ // Persist every completed gesture: keep the canvas controlled AND save.
59
+ // Debounce / fire-and-forget is the caller's job.
60
+ const handleChange = (next: DashboardCanvasValue) => {
61
+ setValue(next);
62
+ saveDashboardLayout(dashboardId, next);
63
+ };
64
+
65
+ // Read-only record view — same value shape, no editing affordances.
66
+ <DashboardCanvas
67
+ value={savedLayout}
68
+ renderItem={(id) => <Card>{widgets[id].title}</Card>}
69
+ readOnly
70
+ />
71
+
72
+ // Constraints computed from data, e.g. locking size for chart widgets.
73
+ <DashboardCanvas
74
+ value={value}
75
+ onChange={setValue}
76
+ renderItem={(id) => <Card>{widgets[id].title}</Card>}
77
+ constraints={(id) => (widgets[id]?.kind === 'chart' ? { minW: 4, minH: 3, maxH: 6 } : undefined)}
78
+ />
79
+ ```
@@ -0,0 +1,131 @@
1
+ # `<DashboardWidget>` — card for a DashboardCanvas cell
2
+
3
+ A widget card that fills its `DashboardCanvas` cell, in five presentations: `standard`, `list`, `kpi`, `chart` and `stats`. Owns the header (title, actions), the body chrome and a variant-matched loading skeleton. The app keeps data, error state, permissions and the overflow menu.
4
+
5
+ ```tsx
6
+ import {
7
+ Card,
8
+ Chart,
9
+ DashboardCanvas,
10
+ DashboardWidget,
11
+ EmptyState,
12
+ ErrorState,
13
+ } from '@eocrm/design-system';
14
+
15
+ <DashboardCanvas
16
+ items={layout}
17
+ onItemsChange={setLayout}
18
+ renderItem={(id) => (
19
+ <DashboardWidget
20
+ variant="kpi"
21
+ title="Open deals"
22
+ actions={menu}
23
+ value="128"
24
+ trend={{ label: '+12% vs last month', direction: 'up' }}
25
+ />
26
+ )}
27
+ />;
28
+
29
+ // kpi with a trend graphic: a Sparkline child renders under value/trend
30
+ <DashboardWidget variant="kpi" title="Open deals" value="128">
31
+ <Sparkline label="Open deals per day" values={dailyCounts} />
32
+ </DashboardWidget>;
33
+
34
+ // kpi, where "up" is bad
35
+ <DashboardWidget
36
+ variant="kpi"
37
+ title="Churned accounts"
38
+ value="14"
39
+ trend={{ label: '+3 vs last month', direction: 'up', sentiment: 'negative' }}
40
+ />;
41
+
42
+ // list: Card.List bleeds edge to edge
43
+ <DashboardWidget variant="list" title="Tasks due" actions={menu} loading={isLoading}>
44
+ <Card.List>{/* rows */}</Card.List>
45
+ </DashboardWidget>;
46
+
47
+ // chart: the plot fills the cell; a note under it goes in Chart's `footnote`
48
+ <DashboardWidget variant="chart" title="Revenue">
49
+ <Chart
50
+ type="line"
51
+ label="Revenue per month"
52
+ categories={months}
53
+ series={revenue}
54
+ formatValue={formatCurrency}
55
+ footnote="3 deals in other currencies not included"
56
+ />
57
+ </DashboardWidget>;
58
+
59
+ // stats: a StatGroup KPI strip; compact padding leaves slack in a 3-row cell
60
+ <DashboardWidget variant="stats" title="Key metrics">
61
+ <StatGroup aria-label="Key metrics">{/* StatTiles */}</StatGroup>
62
+ </DashboardWidget>;
63
+
64
+ // quiet view-mode header: actions appear on hover / focus
65
+ <DashboardWidget title="Pipeline" actions={menu} actionsReveal="hover">
66
+ {/* body */}
67
+ </DashboardWidget>;
68
+
69
+ // standard (default), with error and empty states as children
70
+ <DashboardWidget title="Recent activity" loading={isLoading}>
71
+ {error ? (
72
+ <ErrorState title="Could not load" headingLevel={4} />
73
+ ) : items.length === 0 ? (
74
+ <EmptyState title="Nothing yet" />
75
+ ) : (
76
+ <Feed items={items} />
77
+ )}
78
+ </DashboardWidget>;
79
+ ```
80
+
81
+ <!-- props:start -->
82
+
83
+ ## Props
84
+
85
+ <!-- prettier-ignore -->
86
+ | Prop | Type | Required | Description |
87
+ |---|---|---|---|
88
+ | `variant` | `'standard' \| 'list' \| 'kpi' \| 'chart' \| 'stats'` | no | Presentation variant. Default `'standard'`. - `'standard'` — header (title + actions) over a padded scrolling body. Today's widget card. - `'list'` — same fixed header as `standard`; flush scrolling body so `Card.List` bleeds edge to edge. - `'kpi'` — compact muted title, a large `value`, optional `trend`; optional `children` below. No scrolling. - `'chart'` — compact header; flush non-scrolling body that fills the cell (give the plot `height: 100%`). - `'stats'` — compact header and padding over a scrolling body, for a `StatGroup` KPI strip; unlike `standard` it leaves vertical slack in a 3-row cell. |
89
+ | `title` | `ReactNode` | yes | Widget title, rendered as the heading at `headerLevel`. Required. |
90
+ | `meta` | `ReactNode` | no | Secondary, non-interactive header text such as freshness ("Updated 3 minutes ago") or status. Sits before `actions` and yields first in a narrow cell: it truncates (then hides visually, still read by screen readers) before the title shrinks, while `actions` never shrinks. Also describes the body region (`aria-describedby`) for `standard` / `list` / `stats`. Repeat it in the refresh button's tooltip if it matters when truncated. |
91
+ | `actions` | `ReactNode` | no | Header actions, e.g. the edit-mode overflow `DropdownMenu`. Never wraps. |
92
+ | `actionsReveal` | `'always' \| 'hover'` | no | When `actions` are visible. Default `'always'`. - `'always'` — always shown. - `'hover'` — dimmed to invisible until the card is hovered or holds focus (they stay in the tab order, and Tab into the card reveals them); an open menu launched from an action keeps them shown. On touch / `(hover: none)` they stay visible. They keep their layout width. |
93
+ | `headerLevel` | `'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6'` | no | Heading level of the title. Default `'h3'`. |
94
+ | `value` | `ReactNode` | no | KPI value (`variant="kpi"` only), e.g. `"128"` or a formatted currency node. |
95
+ | `trend` | `DashboardWidgetTrend` | no | KPI trend (`variant="kpi"` only). |
96
+ | `loading` | `boolean` | no | Show a variant-matched loading skeleton instead of the body (and, for kpi, instead of `value`/`trend`); title and actions stay. Adds visually hidden "Loading…" body text and `aria-busy`. Deliberately NO live region: a dashboard loads many widgets at once, so per-widget announcements would flood screen readers — announce "dashboard loaded" once at page level if needed. Default `false`. |
97
+ | `children` | `ReactNode` | no | Widget body. Pass `ErrorState` / `EmptyState` here for error and empty states. |
98
+ | …native | | | plus native `<div>` attributes |
99
+
100
+ <!-- props:end -->
101
+
102
+ - **Fills its cell.** It is a `<Card fill padding="none">`; `DashboardCanvas` sizes the cell, the widget fills it. The root is a `div` with a heading (no landmark; 20 regions on one dashboard is noise). Heading level is `headerLevel` (default `h3`).
103
+ - **Variants.** `standard`: header + padded scrolling body. `list`: same fixed header as `standard`, flush scrolling body so `Card.List` bleeds edge to edge. `kpi`: compact muted title, large `value`, optional `trend`, optional `children` below; does not scroll. `chart`: compact header, flush body that does not scroll and fills the remaining height, so give the plot `height: 100%`. `stats`: compact header and padding over a scrolling body, for a [`StatGroup`](StatGroup.md) KPI strip; scrolls only on real overflow.
104
+ - **Only `standard`, `list` and `stats` scroll.** `kpi` and `chart` bodies are non-scrolling (`Card.Body` without `scroll`).
105
+ - **`value` / `trend` are kpi only** and ignored on other variants.
106
+ - **Trend.** Direction icon plus a visually hidden "Increase / Decrease / No change" before `label`. Colour is by `sentiment`, which defaults from direction (up positive, down negative, flat neutral). Set `sentiment` explicitly when the direction is not the judgement (churn, overdue tasks up = `negative`).
107
+ - **`loading`** swaps the body (for kpi, the value and trend) for a skeleton matching the variant (standard: lines, list: rows, kpi: value + trend, chart: bars, stats: kpi shape). Title and actions stay. For `stats`, prefer `StatGroup loading` (per-tile skeletons) over widget `loading`, which shows a single kpi blob; don't set both. The skeleton is `aria-hidden`; the body instead contains visually hidden "Loading..." text and the root gets `aria-busy` as a hint.
108
+ - **No live region, on purpose.** A dashboard loads 10 to 20 widgets at once; a live region per widget would flood a screen reader. If you want an announcement, make one at page level ("Dashboard loaded") once all widgets settle. That is the app's job.
109
+ - **Error and empty states** are the app's `ErrorState` / `EmptyState`, passed as `children` (for kpi, as `value` or `children`).
110
+ - **`actions`** (e.g. an edit-mode `DropdownMenu`) sit at the header's end and never wrap.
111
+ - **`actionsReveal="hover"`** (default `'always'`) is for quiet view-mode headers: the actions are transparent until the card is hovered or holds focus (`:focus-within`, so Tab into the card reveals them), and stay shown while a menu launched from them is open. They are hidden with opacity only: they keep their layout width (the title and meta do not jump) and stay in the tab order. On touch / `(hover: none)` they are always visible.
112
+ - **`meta`** is secondary, non-interactive header text (freshness such as "Updated 3 minutes ago", or status). It sits just before `actions`, muted and on one line, and yields first in a narrow cell: it truncates with an ellipsis, then hides visually (screen readers still read it) once only a sliver is left, before the title gives up any width, while `actions` keeps its width. For `standard` / `list` / `stats` it also describes the body region (`aria-describedby`). If the text matters when truncated, repeat it in the refresh button's tooltip.
113
+
114
+ #### When NOT to use
115
+
116
+ - ❌ A generic content card outside a dashboard → `<Card>`.
117
+ - ❌ A standalone stat with no grid cell → `<Card>` with your own layout.
118
+ - ❌ A placeholder in a widget catalog → `<WidgetPreview>`.
119
+
120
+ #### Anti-patterns
121
+
122
+ - ❌ `actionsReveal="hover"` when the only way to reach an essential action is that header. Touch users see it, but mouse users get no visible cue; keep primary actions visible.
123
+ - ❌ Wrapping `DashboardWidget` in another `Card`. It already is one.
124
+ - ❌ Freshness or status text in `actions`. `actions` never shrinks, so the title gets crushed in a narrow cell; use `meta`.
125
+ - ❌ Buttons or links in `meta`. They can be truncated out of reach; controls go in `actions`.
126
+ - ❌ `standard` for a `StatGroup` KPI strip in a 3-row widget: the roomy padding leaves no slack and the strip scrolls. Use `stats`.
127
+ - ❌ Passing `value` / `trend` to `standard`, `list`, `chart` or `stats`. They are ignored; put content in `children`.
128
+ - ❌ Rendering your own `Skeleton` in `children` instead of `loading`. You lose the variant-matched shape, the hidden "Loading..." text and `aria-busy`.
129
+ - ❌ Adding a live region (`role="status"`, `aria-live`) to each widget while loading.
130
+ - ❌ Relying on direction-derived colour when up is bad. Set `sentiment`.
131
+ - ❌ A scrolling or fixed-height wrapper inside a `kpi` / `chart` body. The cell is the size; size the plot at `height: 100%`.
@@ -0,0 +1,88 @@
1
+ # `<DataTable>` — server-driven data table with column features
2
+
3
+ - The table owns its polite live region; do not wrap it in another — two regions would fire for one event.
4
+
5
+ ```tsx
6
+ const instance = useDataTable<Deal>({
7
+ data,
8
+ columns,
9
+ getRowId: (r) => r.id,
10
+ enableRowSelection: true,
11
+ sort,
12
+ onSortChange: setSort,
13
+ });
14
+
15
+ <Cluster>
16
+ <ColumnVisibilityTrigger instance={instance} />
17
+ </Cluster>
18
+ <DataTable instance={instance} aria-label="Deals" />
19
+ ```
20
+
21
+ <!-- props:start -->
22
+
23
+ ## Props
24
+
25
+ <!-- prettier-ignore -->
26
+ | Prop | Type | Required | Description |
27
+ |---|---|---|---|
28
+ | `instance` | `DataTableInstance<T>` | yes | |
29
+ | `density` | `'comfortable' \| 'dense'` | no | |
30
+ | `striped` | `boolean` | no | |
31
+ | `hover` | `boolean` | no | Hover highlight on body rows. Defaults TRUE (DataTable rows are usually interactive). |
32
+ | `bordered` | `boolean` | no | |
33
+ | `loading` | `boolean` | no | Marks the table busy. Empty tables show skeleton rows; populated tables keep their rows mounted during a refetch so focus and local row state are preserved. Defaults to `false`. Announced from a polite live region the table owns, gated on the SKELETON rather than on this prop: a load shorter than `skeletonDelay` shows nothing and so says nothing, and a refetch over rows already on screen is silent because nothing visibly changes. The resolution is announced too — "Rows loaded" or "No rows loaded". `aria-busy` is also set, but reaches no screen reader on its own. |
34
+ | `loadingRowCount` | `number` | no | Number of skeleton rows when `loading`. Defaults 10. |
35
+ | `skeletonDelay` | `number` | no | Milliseconds to wait before showing skeleton rows for an empty initial load. Defaults to `0`; fast loads that finish inside the delay never show a skeleton. |
36
+ | `skeletonMinDuration` | `number` | no | Minimum milliseconds skeleton rows remain visible after appearing. Defaults to `0`. Arriving rows and the empty state remain hidden until the visual tail finishes. `aria-busy` still follows actual `loading`, not the skeleton's visual tail. |
37
+ | `emptyState` | `ReactNode` | no | Element shown when `data` is empty and not loading. Defaults to a stock <EmptyState>. |
38
+ | `collapseBelow` | `'sm' \| 'md' \| 'lg'` | no | Stacks responsive data cells below this container-query breakpoint: `sm` (480px), `md` (640px), or `lg` (768px). Selection, expansion, sorting, row actions, and column visibility remain usable. Column sizing, pinning, and ordering state is retained, but resize/reorder controls and sticky pin presentation are unavailable while stacked and return after widening. This adds a wrapper with `container-type: inline-size`, so the breakpoint measures the table's available container width, not the viewport. Avoid an intrinsic-width parent such as `width: max-content`: inline-size containment can make the wrapper contribute zero intrinsic width there. |
39
+ | `aria-label` | `string` | no | Required for a11y when no caption is provided. |
40
+ | `caption` | `ReactNode` | no | |
41
+ | `dragWholeColumn` | `boolean` | no | Drag the whole column while reordering, not just its header cell. Default `true` — the dragged column's body cells travel with its header, and every column the drag displaces shifts its body cells too, so the header row and the body never disagree mid-drag. Costs one CSS-variable write per shifted column per frame; the cells move on the compositor, so the table body is not re-rendered during pointer movement. It does cost two full body reconciliations per drag — one at drag start, one at drag end — because the drag-active flag is component state and body rows are not memoized; that is the number to weigh for a very large table. Set `false` for the cheaper preview: only the dragged header cell follows the pointer and the body stays put until drop. Worth it for very large tables on low-end hardware, or to restore the previous behavior. Pinned columns never move under either setting — they are excluded from reordering entirely. The two settings also differ on **what a release means when no unpinned slot is under the column** — over a pinned column, or off the table entirely. Default: the drop commits the slot the preview is showing. The opt-out: the drop is discarded, because dnd-kit's own preview retracts (the header snaps back home) in that situation, and a commit would contradict it. See `docs/components/DataTable.md`, the column-drag bullet. |
42
+ | `className` | `string` | no | |
43
+
44
+ <!-- props:end -->
45
+
46
+ - Config-driven via `columns: ColumnDef<T>[]`. Each column has a stable `id` used as the key for all per-column state.
47
+ - **Column header names.** The `<th>` is named by the label span's content — the header text — so the resize handle is never folded into it. The one override: a header that renders no TEXT OF ITS OWN — a ReactNode, a render function, or `''` — is named by `visibilityLabel` when you set one. So `header: <strong>Revenue</strong>` announces "Revenue", and adding `visibilityLabel="Revenue (USD)"` makes it announce "Revenue (USD)". That is a name-vs-label mismatch, and a WCAG 2.5.3 one only when `sortable` makes the label a button — 2.5.3 is scoped to user interface components, and it is violated only when the label does not CONTAIN the visible text, so "Revenue (USD)" over "Revenue" passes. Accepted because the alternative — a runtime measurement deciding which source names the header — produced UNNAMED column headers ten separate times before it was deleted. A string header that renders text is always named by that text; `visibilityLabel` does not override it. `header: ''` is not such a string: it renders nothing, so the label wins, which is what the trailing row-actions column wants. `column.id` is used for nothing a user hears — not the header, not the drag grip, not the resize handle. What such a header announces, measured off Chromium's AX tree: an `aria-labelledby` resolving to no text is marked INVALID, not treated as a name, so naming falls through to the cell's contents — the drag grip, or under `collapseBelow` the resize handle's live pixel width. `header: ''` is special-cased to a generic "Unlabelled column" so the width cannot win; a ReactNode rendering nothing is indistinguishable from one that names itself, so it is not. Either way it is not a name you chose, so set `visibilityLabel` on every text-less header. That is a change from before the fix, where such a header WAS named — from content, which swept in the resize handle, so it announced the handle's label, `column.id` when the column had nothing better. That name was the bug, not a feature worth preserving. (The "Resize … column" wrapper came with that fix; before it the handle's label was the bare identifier.) There is no dev warning for it: nothing static can tell a node that names itself (`<strong>Revenue</strong>`) from one that does not (an icon), so a warning fired on the commonest valid shape and was removed. Give any non-text header a `visibilityLabel`.
48
+ - **Responsive rows:** `collapseBelow="sm" | "md" | "lg"` re-templates rows as labelled cards based on the DataTable container. Labels use `visibilityLabel`, then a string `header`; give non-text headers a `visibilityLabel` when a visible card label is required. Plain non-sortable string headers leave the compact strip, while React-node and render-function headers remain because they may contain controls. Sorting, selection, expansion, row actions, and `ColumnVisibilityTrigger` remain available. Column sizing, pinning, and ordering state is retained while stacked, but resize/reorder controls and sticky pin presentation are unavailable until the table widens again. Give the table concrete available width because inline-size containment has no intrinsic-width contribution.
49
+ - All state pieces (column order/sizing/visibility/pinning, row selection/expansion, sort) follow the Radix controlled/uncontrolled pattern: `value` + `onValueChange`, OR `defaultValue` only, OR neither.
50
+ - Server-driven sort/search/pagination. DataTable does NOT transform data — `data` must be the server's pre-sorted, pre-paginated slice. `onSortChange` is your trigger to refetch.
51
+ - `enableRowSelection: true` adds a leading checkbox column with select-all (indeterminate when partial). `toggleAllOnPage` ignores `pinnedRows`.
52
+ - Drag-to-reorder is keyboard-accessible (Tab to grip → Space to pick up → ←/→ to move → Space/Enter to drop → Esc to cancel). The grip is hover-revealed on desktop.
53
+ - Resize via the right-edge handle. Without `collapseBelow`, the legacy keyboard path stays on a focused sortable header label: `←`/`→` for −/+8px; Shift+`←`/`→` for ±32px. With `collapseBelow`, the wide presentation exposes a dedicated focusable resize separator with the same keys; the separator and resize interaction are unavailable while stacked and return after widening.
54
+ - `ColumnVisibilityTrigger` is the only built-in companion. For column pinning UI (Phase 2 ships state, no built-in UI), wire your own using `instance.pinColumn(id, side)`.
55
+ - **Phase 2 ships pinning rendering.** `columnPinning` now applies sticky CSS with cumulative offsets and an inside-edge shadow; `pinnedRows` renders in a separate `<tbody>` above the main body. The selection auto-column is auto-left-pinned at offset 0. Pinned columns are LOCKED in place — no drag grip, can't be reordered. Their sort still works. Declare initial pinning either on the hook (`defaultColumnPinning: { left: ['name'], right: ['actions'] }`) or directly on each column (`pin: 'left' | 'right'`); the hook prop wins when both are set. **Phase 3 ships expandable rows.** Pass `renderExpandedRow: (row) => ReactNode` to add a per-row chevron auto-column at the left edge. Clicking the chevron toggles a detail row beneath the main row, spanning all columns. ARIA-wired with `aria-expanded` + `aria-controls`. The chevron auto-column is sticky-left like the selection cell; when both are enabled, selection is first and expand is second. DataTable is now feature-complete per the original spec.
56
+ - **Cell content is single-line + ellipsized by default.** DataTable's internal table uses `table-layout: fixed` so column widths from `ColumnDef.size` (or runtime `columnSizing`) are authoritative, and every cell gets `overflow: hidden; text-overflow: ellipsis; white-space: nowrap`. Wide content truncates with `…` at the column boundary; the column does NOT expand to fit. If you need multi-line cells, render `<Table>` directly — DataTable is opinionated here so pinning offsets stay pixel-correct.
57
+ - **A column drag commits wherever the preview parked it** — however far the pointer roams, including over a pinned column or clear off the table. There is no "outside" to release into: the column is clamped to the unpinned band, so the preview is always showing a real slot and the drop honors it. This deliberately differs from `Kanban`, where releasing outside the columns cancels — there the pointer can genuinely aim somewhere else. **Escape is the only cancel.** The `dragWholeColumn={false}` opt-out is the exception: its preview is dnd-kit's own and RETRACTS (the header snaps home) when no unpinned slot is under the column, so a release there is discarded — matching what that preview shows.
58
+
59
+ **When NOT to use:**
60
+
61
+ - A static read-only table without column features — use `<Table>` directly.
62
+ - Huge datasets (10k+ rows on screen at once): rows are not virtualized, so it gets slow.
63
+ - Excel-like cell editing or cell selection — out of scope; compose it yourself.
64
+
65
+ **Anti-patterns:**
66
+
67
+ - ❌ Mutating `columns` array identity on every render. `useDataTable` captures `defaultColumnOrder` from `columns` once at mount — later identity changes don't trigger a re-derive of the default order. Use a stable reference (`useMemo` or module-level).
68
+ - ❌ Client-sorting `data` AND passing `sort` controlled. Pick one — server is the canonical source. Spinning both means rows reorder twice and ghost-rows appear during fetches. `data` is the server's pre-paginated, pre-sorted slice.
69
+ - ❌ Rolling your own column visibility UI when `ColumnVisibilityTrigger` does the job. The built-in handles the "last column" guard for you.
70
+ - ❌ Using `<Table>` directly when you want any of: ordering, sizing, visibility, selection, sort indicator wiring. Compose `<DataTable>` instead — the primitive `<Table>` is for static read-only views.
71
+ - ❌ Putting interactive controls in `renderExpandedRow` that need to participate in row selection or row click. The detail row is its own `<tr>`, not part of the main row — `onRowClick` doesn't fire from inside it (by design), and `rowSelection` only tracks main-row checkboxes.
72
+ - ⚠ Pinned rows (passed via `pinnedRows`) ALSO render a chevron when `renderExpandedRow` is set — they're expandable just like main-body rows. Decide whether your starred/anchored rows should reveal detail; if not, omit `renderExpandedRow` or filter `expandedRows` state in the consumer to ignore pinned-row ids.
73
+
74
+ #### `<ColumnVisibilityTrigger>`
75
+
76
+ Companion for `<DataTable>`: a ghost Button trigger plus a DropdownMenu of CheckboxItems, one per column where `enableHide !== false`. When only one hidable column is visible its item renders disabled, so the table can never reach a zero-column state. Pass the same `instance` to both `<DataTable>` and `<ColumnVisibilityTrigger>` so visibility state stays in sync.
77
+
78
+ ```tsx
79
+ // Custom label + right-aligned menu
80
+ <ColumnVisibilityTrigger instance={instance} label="Manage columns" align="end" />
81
+
82
+ // Icon-only trigger
83
+ <ColumnVisibilityTrigger instance={instance} label={null} />
84
+ ```
85
+
86
+ - When NOT to use: you want a different visibility UI (a settings drawer, a multi-select combobox, a Popover with column grouping) — build it against `instance.columns`, `instance.columnVisibility` and `instance.toggleColumnVisibility`; or every column has `enableHide: false` (the menu would be empty — don't render it).
87
+ - ❌ Passing a different `instance` to the trigger than to `<DataTable>`: visibility changes in one won't reflect in the other.
88
+ - ❌ Rendering it when every column has `enableHide: false` — check `instance.columns` first and suppress the trigger.
@@ -0,0 +1,68 @@
1
+ # `<DatePicker>` — single-date input + popover
2
+
3
+ ```tsx
4
+ const [value, setValue] = useState<Date | null>(null);
5
+ <DatePicker value={value} onChange={setValue} min={new Date()} />;
6
+ ```
7
+
8
+ <!-- props:start -->
9
+
10
+ ## Props
11
+
12
+ <!-- prettier-ignore -->
13
+ | Prop | Type | Required | Description |
14
+ |---|---|---|---|
15
+ | `value` | `Date \| null` | no | Selected date. `null` = no value. Pair with `onChange` for controlled use. |
16
+ | `defaultValue` | `Date \| null` | no | Initial selected date for uncontrolled use. |
17
+ | `onChange` | `((date: Date \| null) => void)` | no | Fires when the value changes. |
18
+ | `locale` | `string` | no | Override locale (otherwise reads `useLocale()`). |
19
+ | `min` | `Date` | no | Earliest selectable date (inclusive, day-granular). Gates both the grid and typed input. |
20
+ | `max` | `Date` | no | Latest selectable date (inclusive). |
21
+ | `isDateDisabled` | `((date: Date) => boolean)` | no | Per-date disable callback; applied per grid cell and to parsed typed input. |
22
+ | `clearable` | `boolean` | no | Show the ✕ clear button when a value is set. Defaults to `true`. |
23
+ | `invalid` | `boolean` | no | Toggle red border + focus ring + `aria-invalid="true"`. Pair with a visible error and `aria-describedby`. |
24
+ | `name` | `string` | no | Form name. When set, renders a hidden mirror `<input>` with the ISO date so native `<form>` submission works. |
25
+ | `size` | `'sm' \| 'md' \| 'lg'` | no | Field height + type scale. Same scale as `<Input>`. Defaults to `'md'`. Affects only the trigger row; the popover month grid is fixed-size. - `'sm'` — 24px tall. - `'md'` — 32px tall (default). - `'lg'` — 40px tall. |
26
+ | `granularity` | `'day' \| 'minute'` | no | Picker precision. - `'day'` (default) — date only; behavior unchanged from prior releases. - `'minute'` — adds a manual-entry time input below the calendar grid. The trigger text shows `HH:mm` after the date. The hidden form mirror (when `name` is set) emits ISO local datetime (`2026-05-28T14:30`). Time is preserved across date re-picks. Picking from a `null` value defaults the time to `00:00`. In `'minute'` mode picking a day keeps the popover open and moves focus to the time input; Enter there (or Escape / outside click) closes it. |
27
+ | `timeStep` | `number` | no | Minutes step for the `<TimeField>` popover and for rounding typed time input on commit. Defaults to `15`. Set `1` to disable rounding. Only meaningful when `granularity='minute'`. |
28
+ | `hourCycle` | `'12' \| '24' \| 'auto'` | no | Display cycle for the embedded `<TimeField>` + the trigger's time tail. - `'24'` — `"HH:mm"` in the trigger; 24h hour list in the time popover. - `'12'` — `"h:mm AM/PM"` in the trigger; 12h hour list + AM/PM column. - `'auto'` (default) — derives from the active locale via Intl. en-US → `'12'`; ru-RU / de-DE / fr-FR → `'24'`. Only meaningful when `granularity='minute'`. Typed input is lenient regardless of cycle — both `"14:30"` and `"2:30 PM"` parse on blur. |
29
+ | …native | | | plus native `<input>` attributes |
30
+
31
+ <!-- props:end -->
32
+
33
+ - Single-date selection (date-only by default; opt into date+time with `granularity="minute"`). Range → `<DateRangePicker>`. Year-picker — out of scope for v1.
34
+ - Looks like an `<Input>`. Click the input or press ArrowDown to open the popover. The 📅 button toggles and the ✕ button clears; clicking either never moves focus while it's in the field or the open popover, so half-typed trigger text survives the toggle and is discarded by clear. Reaching them by keyboard (Tab) leaves the input first, which commits the typed text. Toggling closed from inside the popover commits a time typed into the time input and returns focus to the input; clear from there wins over the typed time (one `onChange(null)`).
35
+ - Typed input parses on Enter, or when focus leaves the field — ArrowDown into the open calendar, an outside click, or Tabbing away (Tab from the trigger goes ✕ → 📅 → the page; the portaled calendar is reached with ArrowDown) — using the active locale: en-US `M/D/YYYY`, ru-RU `D.M.YYYY`, ja-JP `Y/M/D`. ISO `YYYY-MM-DD` is always accepted as a paste fallback. Unparseable / out-of-range / disabled input reverts to the last committed value.
36
+ - Locale-aware via `useLocale()`; override with `locale` prop. UI strings (previousMonth / nextMonth / openCalendar / clear) translate via `datePicker.*` keys — override with `<I18nProvider overrides={{ datePicker: { ... } }}>`.
37
+ - ARIA: typed input has `aria-haspopup="dialog"` + `aria-expanded`. Popover wrapper is `role="dialog"` (labelled by `aria-label={t('datePicker.openCalendar')}`); the grid inside is `role="grid"` with `role="gridcell"` buttons that carry `aria-selected` / `aria-disabled` as appropriate.
38
+ - Keyboard inside the grid: ←→↑↓ move focus by 1 day, Home/End to start/end of week, PageUp/PageDown step a month, Enter/Space selects, Escape closes and returns focus to the input. Tab / Shift+Tab out of the popover closes it and returns focus to the input (both granularities).
39
+ - **Granularity.** Pass `granularity="minute"` to add a `<TimeField>` below the calendar grid; the trigger text becomes `MM/DD/YYYY HH:mm` (24h locales) or `MM/DD/YYYY h:mm AM/PM` (12h locales) and the hidden form mirror emits ISO local datetime (`2026-05-28T14:30`). Defaults to `'day'` (backward compat — date-only). Picking a different date re-uses the existing time-of-day, so the grid feels like it "just changes the date"; picking from `null` defaults to `00:00`. Picking a day does NOT close the popover in minute mode: focus moves to the embedded time input so the time is reachable; Enter in the time input (with its clock closed) or Escape closes it and returns focus to the trigger input; an outside click closes it and leaves focus where the user clicked; Tabbing out of the popover closes it and returns focus to the trigger input, so the next Tab continues in page order. Every close path keeps a date typed into the trigger and a time typed into the time input. The `<TimeField>` accepts free text (parsed on blur / Enter via `parseTime` — both 24h and AM/PM shapes) AND a chevron-toggled popover with hour + minute (+ AM/PM in 12h mode) lists, plus a "Now" footer button. `timeStep` (default `15`, in minutes) controls the minute-list row count AND rounds typed input in the time field on commit; set `timeStep={1}` to disable rounding. The trigger text-input parses exactly as typed — `timeStep` does not round trigger input. `hourCycle` (default `'auto'`) forwards to the embedded TimeField and controls the trigger text — `'12'` / `'24'` force a cycle, `'auto'` derives from locale (en-US → 12h, ru-RU → 24h).
40
+
41
+ ```tsx
42
+ // Uncontrolled, today as the default
43
+ <DatePicker defaultValue={new Date()} onChange={(d) => console.log(d)} />
44
+
45
+ // Constrained
46
+ <DatePicker
47
+ value={value}
48
+ onChange={setValue}
49
+ min={new Date()}
50
+ isDateDisabled={(d) => d.getDay() === 0 || d.getDay() === 6}
51
+ />
52
+
53
+ // Form integration via the hidden mirror
54
+ <form action="/dates"><DatePicker name="dob" /></form>
55
+ ```
56
+
57
+ The popover is portaled into `document.body`, so it escapes overflow-hidden ancestors.
58
+
59
+ #### When NOT to use
60
+
61
+ - Datetime with seconds precision: only `granularity="minute"` is supported; compose with a separate input.
62
+ - Time-only fields (no date): out of scope.
63
+ - Free-form date strings without a clear locale: use a plain `<Input>`.
64
+
65
+ #### Anti-patterns
66
+
67
+ - ❌ Wrapping the picker in `<label htmlFor={id}>` while also passing `aria-label` — pick one. The wrapper label is preferred.
68
+ - ❌ Using `value` without `onChange` and expecting state to update on user input — the picker is fully controlled when `value` is passed.