@eocrm/design-system 0.0.0-stage → 0.6.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (897) hide show
  1. package/AI-PRIMER.md +341 -0
  2. package/README.md +262 -2
  3. package/docs/components/Accordion.md +114 -0
  4. package/docs/components/AgentAvatar.md +58 -0
  5. package/docs/components/Alert.md +81 -0
  6. package/docs/components/AppLayout.md +70 -0
  7. package/docs/components/Avatar.md +49 -0
  8. package/docs/components/AvatarGroup.md +47 -0
  9. package/docs/components/Badge.md +60 -0
  10. package/docs/components/Banner.md +89 -0
  11. package/docs/components/BrandIcon.md +32 -0
  12. package/docs/components/Breadcrumb.md +72 -0
  13. package/docs/components/Button.md +107 -0
  14. package/docs/components/ButtonGroup.md +78 -0
  15. package/docs/components/Calendar.md +158 -0
  16. package/docs/components/Card.md +165 -0
  17. package/docs/components/CatalogPicker.md +83 -0
  18. package/docs/components/Chart.md +114 -0
  19. package/docs/components/ChatBubble.md +55 -0
  20. package/docs/components/ChatLauncher.md +97 -0
  21. package/docs/components/Checkbox.md +55 -0
  22. package/docs/components/CircularProgress.md +53 -0
  23. package/docs/components/Cluster.md +96 -0
  24. package/docs/components/Code.md +35 -0
  25. package/docs/components/CodeBlock.md +67 -0
  26. package/docs/components/ColorPicker.md +115 -0
  27. package/docs/components/ConfirmationPopover.md +70 -0
  28. package/docs/components/Constrain.md +39 -0
  29. package/docs/components/CurrencySelect.md +57 -0
  30. package/docs/components/CursorPagination.md +43 -0
  31. package/docs/components/DashboardCanvas.md +79 -0
  32. package/docs/components/DashboardWidget.md +131 -0
  33. package/docs/components/DataTable.md +88 -0
  34. package/docs/components/DatePicker.md +68 -0
  35. package/docs/components/DateRangePicker.md +71 -0
  36. package/docs/components/DateStrip.md +56 -0
  37. package/docs/components/DefinitionList.md +82 -0
  38. package/docs/components/Divider.md +57 -0
  39. package/docs/components/Dot.md +26 -0
  40. package/docs/components/Drawer.md +94 -0
  41. package/docs/components/DropdownMenu.md +299 -0
  42. package/docs/components/EmojiPicker.md +84 -0
  43. package/docs/components/EmptyState.md +55 -0
  44. package/docs/components/EntityChip.md +102 -0
  45. package/docs/components/ErrorState.md +72 -0
  46. package/docs/components/Field.md +91 -0
  47. package/docs/components/FileUpload.md +109 -0
  48. package/docs/components/FilterChip.md +88 -0
  49. package/docs/components/FlowCanvas.md +108 -0
  50. package/docs/components/FormRow.md +31 -0
  51. package/docs/components/FormSection.md +37 -0
  52. package/docs/components/Grid.md +103 -0
  53. package/docs/components/Highlight.md +75 -0
  54. package/docs/components/HighlightedText.md +50 -0
  55. package/docs/components/IconPicker.md +134 -0
  56. package/docs/components/IconTile.md +30 -0
  57. package/docs/components/Image.md +84 -0
  58. package/docs/components/ImageCrop.md +163 -0
  59. package/docs/components/Indent.md +31 -0
  60. package/docs/components/InlineDatePicker.md +58 -0
  61. package/docs/components/InlineDateRangePicker.md +57 -0
  62. package/docs/components/Input.md +54 -0
  63. package/docs/components/Kanban.md +122 -0
  64. package/docs/components/Kbd.md +41 -0
  65. package/docs/components/Lightbox.md +105 -0
  66. package/docs/components/Link.md +65 -0
  67. package/docs/components/LinkCard.md +41 -0
  68. package/docs/components/LiquidEditor.md +84 -0
  69. package/docs/components/List.md +68 -0
  70. package/docs/components/LiveRegion.md +29 -0
  71. package/docs/components/LocaleProvider.md +25 -0
  72. package/docs/components/Logo.md +41 -0
  73. package/docs/components/Masonry.md +48 -0
  74. package/docs/components/MediaTile.md +95 -0
  75. package/docs/components/Modal.md +107 -0
  76. package/docs/components/MoneyInput.md +62 -0
  77. package/docs/components/OptionsPicker.md +123 -0
  78. package/docs/components/OtpInput.md +65 -0
  79. package/docs/components/Page.md +35 -0
  80. package/docs/components/PageHeader.md +133 -0
  81. package/docs/components/Pagination.md +44 -0
  82. package/docs/components/Palette.md +32 -0
  83. package/docs/components/PasswordInput.md +45 -0
  84. package/docs/components/PasswordStrengthMeter.md +27 -0
  85. package/docs/components/PersonDisplay.md +153 -0
  86. package/docs/components/PhoneInput.md +54 -0
  87. package/docs/components/PillMenu.md +91 -0
  88. package/docs/components/Popover.md +127 -0
  89. package/docs/components/Progress.md +56 -0
  90. package/docs/components/QrCode.md +34 -0
  91. package/docs/components/Radio.md +37 -0
  92. package/docs/components/RadioGroup.md +56 -0
  93. package/docs/components/Rail.md +191 -0
  94. package/docs/components/RelativeDateInput.md +114 -0
  95. package/docs/components/RichText.md +44 -0
  96. package/docs/components/RichTextEditor.md +112 -0
  97. package/docs/components/Screen.md +37 -0
  98. package/docs/components/ScrollArea.md +39 -0
  99. package/docs/components/Select.md +131 -0
  100. package/docs/components/SettingRow.md +98 -0
  101. package/docs/components/Skeleton.md +68 -0
  102. package/docs/components/Slider.md +92 -0
  103. package/docs/components/SlotGrid.md +55 -0
  104. package/docs/components/SocialButton.md +31 -0
  105. package/docs/components/Sortable.md +127 -0
  106. package/docs/components/SortableGroup.md +52 -0
  107. package/docs/components/Sparkline.md +51 -0
  108. package/docs/components/Split.md +76 -0
  109. package/docs/components/Stack.md +59 -0
  110. package/docs/components/StagePath.md +66 -0
  111. package/docs/components/StatGroup.md +61 -0
  112. package/docs/components/StatTile.md +58 -0
  113. package/docs/components/Sticky.md +69 -0
  114. package/docs/components/Switch.md +89 -0
  115. package/docs/components/Table.md +184 -0
  116. package/docs/components/TableOfContents.md +76 -0
  117. package/docs/components/Tabs.md +94 -0
  118. package/docs/components/Text.md +63 -0
  119. package/docs/components/Textarea.md +59 -0
  120. package/docs/components/Thread.md +52 -0
  121. package/docs/components/TimeField.md +70 -0
  122. package/docs/components/Timeline.md +57 -0
  123. package/docs/components/Title.md +54 -0
  124. package/docs/components/ToastViewport.md +61 -0
  125. package/docs/components/Tooltip.md +63 -0
  126. package/docs/components/TopBar.md +214 -0
  127. package/docs/components/Tour.md +85 -0
  128. package/docs/components/TreeView.md +113 -0
  129. package/docs/components/VisuallyHidden.md +43 -0
  130. package/docs/components/WidgetPreview.md +54 -0
  131. package/docs/components/useBelowBreakpoint.md +11 -0
  132. package/docs/components/useMonth.md +18 -0
  133. package/docs/setup.md +51 -0
  134. package/docs/theming.md +95 -0
  135. package/docs/tokens.md +123 -0
  136. package/docs/transient-state.md +56 -0
  137. package/package.json +82 -4
  138. package/src/_meta/manifest.ts +293 -0
  139. package/src/app/AppProvider.tsx +78 -0
  140. package/src/app/index.ts +3 -0
  141. package/src/app/themeTokens.ts +95 -0
  142. package/src/calendar/dateMath.ts +114 -0
  143. package/src/calendar/formatters.ts +75 -0
  144. package/src/calendar/index.ts +39 -0
  145. package/src/calendar/types.ts +36 -0
  146. package/src/calendar/useAgenda.ts +70 -0
  147. package/src/calendar/useDay.ts +51 -0
  148. package/src/calendar/useMonth.ts +82 -0
  149. package/src/calendar/useWeek.ts +62 -0
  150. package/src/calendar/weekInfo.ts +83 -0
  151. package/src/components/Accordion/Accordion.module.scss +304 -0
  152. package/src/components/Accordion/Accordion.tokens.scss +64 -0
  153. package/src/components/Accordion/Accordion.tsx +272 -0
  154. package/src/components/Accordion/AccordionContent.tsx +36 -0
  155. package/src/components/Accordion/AccordionItem.tsx +66 -0
  156. package/src/components/Accordion/AccordionTrigger.tsx +121 -0
  157. package/src/components/Accordion/context.ts +47 -0
  158. package/src/components/Accordion/index.ts +14 -0
  159. package/src/components/Alert/Alert.module.scss +92 -0
  160. package/src/components/Alert/Alert.tokens.scss +60 -0
  161. package/src/components/Alert/Alert.tsx +136 -0
  162. package/src/components/Alert/index.ts +2 -0
  163. package/src/components/AppLayout/AppLayout.module.scss +130 -0
  164. package/src/components/AppLayout/AppLayout.tokens.scss +27 -0
  165. package/src/components/AppLayout/AppLayout.tsx +211 -0
  166. package/src/components/AppLayout/index.ts +2 -0
  167. package/src/components/Avatar/AgentAvatar.module.scss +117 -0
  168. package/src/components/Avatar/AgentAvatar.tsx +122 -0
  169. package/src/components/Avatar/Avatar.module.scss +181 -0
  170. package/src/components/Avatar/Avatar.tokens.scss +107 -0
  171. package/src/components/Avatar/Avatar.tsx +210 -0
  172. package/src/components/Avatar/AvatarGroup.module.scss +128 -0
  173. package/src/components/Avatar/AvatarGroup.tsx +119 -0
  174. package/src/components/Avatar/AvatarGroupContext.tsx +20 -0
  175. package/src/components/Avatar/index.ts +6 -0
  176. package/src/components/Badge/Badge.module.scss +124 -0
  177. package/src/components/Badge/Badge.tokens.scss +74 -0
  178. package/src/components/Badge/Badge.tsx +164 -0
  179. package/src/components/Badge/index.ts +2 -0
  180. package/src/components/Banner/Banner.module.scss +73 -0
  181. package/src/components/Banner/Banner.tokens.scss +51 -0
  182. package/src/components/Banner/Banner.tsx +138 -0
  183. package/src/components/Banner/index.ts +2 -0
  184. package/src/components/BrandIcon/BrandIcon.module.scss +5 -0
  185. package/src/components/BrandIcon/BrandIcon.tsx +99 -0
  186. package/src/components/BrandIcon/index.ts +2 -0
  187. package/src/components/Breadcrumb/Breadcrumb.module.scss +32 -0
  188. package/src/components/Breadcrumb/Breadcrumb.tokens.scss +9 -0
  189. package/src/components/Breadcrumb/Breadcrumb.tsx +146 -0
  190. package/src/components/Breadcrumb/index.ts +2 -0
  191. package/src/components/Button/Button.module.scss +167 -0
  192. package/src/components/Button/Button.tokens.scss +90 -0
  193. package/src/components/Button/Button.tsx +205 -0
  194. package/src/components/Button/index.ts +2 -0
  195. package/src/components/ButtonGroup/ButtonGroup.module.scss +134 -0
  196. package/src/components/ButtonGroup/ButtonGroup.tokens.scss +42 -0
  197. package/src/components/ButtonGroup/ButtonGroup.tsx +278 -0
  198. package/src/components/ButtonGroup/ButtonGroupItem.tsx +74 -0
  199. package/src/components/ButtonGroup/context.ts +45 -0
  200. package/src/components/ButtonGroup/index.ts +2 -0
  201. package/src/components/Calendar/AgendaView.module.scss +231 -0
  202. package/src/components/Calendar/AgendaView.tsx +214 -0
  203. package/src/components/Calendar/AllDayBand.module.scss +18 -0
  204. package/src/components/Calendar/AllDayBand.tsx +75 -0
  205. package/src/components/Calendar/Calendar.module.scss +23 -0
  206. package/src/components/Calendar/Calendar.tokens.scss +262 -0
  207. package/src/components/Calendar/Calendar.tsx +370 -0
  208. package/src/components/Calendar/DayCell.module.scss +30 -0
  209. package/src/components/Calendar/DayCell.tsx +50 -0
  210. package/src/components/Calendar/DayView.module.scss +10 -0
  211. package/src/components/Calendar/DayView.tsx +163 -0
  212. package/src/components/Calendar/EventChip.module.scss +171 -0
  213. package/src/components/Calendar/EventChip.tsx +115 -0
  214. package/src/components/Calendar/HourGrid.module.scss +123 -0
  215. package/src/components/Calendar/HourGrid.tsx +381 -0
  216. package/src/components/Calendar/MonthView.module.scss +99 -0
  217. package/src/components/Calendar/MonthView.tsx +296 -0
  218. package/src/components/Calendar/TimedEvent.module.scss +205 -0
  219. package/src/components/Calendar/TimedEvent.tsx +247 -0
  220. package/src/components/Calendar/ViewSwitcher.module.scss +3 -0
  221. package/src/components/Calendar/ViewSwitcher.tsx +47 -0
  222. package/src/components/Calendar/WeekView.module.scss +10 -0
  223. package/src/components/Calendar/WeekView.tsx +137 -0
  224. package/src/components/Calendar/eventColor.ts +60 -0
  225. package/src/components/Calendar/index.ts +18 -0
  226. package/src/components/Calendar/types.ts +451 -0
  227. package/src/components/Calendar/useEventDrag.ts +783 -0
  228. package/src/components/Calendar/utils.ts +622 -0
  229. package/src/components/Card/Card.module.scss +264 -0
  230. package/src/components/Card/Card.tokens.scss +55 -0
  231. package/src/components/Card/Card.tsx +170 -0
  232. package/src/components/Card/CardBody.tsx +45 -0
  233. package/src/components/Card/CardHeader.tsx +113 -0
  234. package/src/components/Card/CardList.tsx +24 -0
  235. package/src/components/Card/CardListRow.tsx +24 -0
  236. package/src/components/Card/index.ts +7 -0
  237. package/src/components/CatalogPicker/CatalogPicker.module.scss +193 -0
  238. package/src/components/CatalogPicker/CatalogPicker.tokens.scss +26 -0
  239. package/src/components/CatalogPicker/CatalogPicker.tsx +339 -0
  240. package/src/components/CatalogPicker/index.ts +2 -0
  241. package/src/components/Chart/Chart.module.scss +287 -0
  242. package/src/components/Chart/Chart.tokens.scss +63 -0
  243. package/src/components/Chart/Chart.tsx +607 -0
  244. package/src/components/Chart/ChartLegend.tsx +99 -0
  245. package/src/components/Chart/ChartTable.tsx +62 -0
  246. package/src/components/Chart/ChartTooltip.tsx +91 -0
  247. package/src/components/Chart/chartModel.ts +689 -0
  248. package/src/components/Chart/index.ts +2 -0
  249. package/src/components/ChatBubble/ChatBubble.module.scss +93 -0
  250. package/src/components/ChatBubble/ChatBubble.tokens.scss +17 -0
  251. package/src/components/ChatBubble/ChatBubble.tsx +61 -0
  252. package/src/components/ChatBubble/ChatBubbleList.tsx +27 -0
  253. package/src/components/ChatBubble/index.ts +3 -0
  254. package/src/components/ChatLauncher/ChatLauncher.module.scss +68 -0
  255. package/src/components/ChatLauncher/ChatLauncher.tokens.scss +27 -0
  256. package/src/components/ChatLauncher/ChatLauncher.tsx +202 -0
  257. package/src/components/ChatLauncher/index.ts +2 -0
  258. package/src/components/ChatLauncher/isAtBottom.ts +12 -0
  259. package/src/components/Checkbox/Checkbox.module.scss +147 -0
  260. package/src/components/Checkbox/Checkbox.tokens.scss +44 -0
  261. package/src/components/Checkbox/Checkbox.tsx +188 -0
  262. package/src/components/Checkbox/index.ts +2 -0
  263. package/src/components/CircularProgress/CircularProgress.module.scss +133 -0
  264. package/src/components/CircularProgress/CircularProgress.tokens.scss +40 -0
  265. package/src/components/CircularProgress/CircularProgress.tsx +139 -0
  266. package/src/components/CircularProgress/index.ts +7 -0
  267. package/src/components/Cluster/Cluster.module.scss +145 -0
  268. package/src/components/Cluster/Cluster.tokens.scss +11 -0
  269. package/src/components/Cluster/Cluster.tsx +215 -0
  270. package/src/components/Cluster/index.ts +2 -0
  271. package/src/components/Code/Code.module.scss +28 -0
  272. package/src/components/Code/Code.tokens.scss +15 -0
  273. package/src/components/Code/Code.tsx +44 -0
  274. package/src/components/Code/index.ts +2 -0
  275. package/src/components/CodeBlock/CodeBlock.module.scss +146 -0
  276. package/src/components/CodeBlock/CodeBlock.tokens.scss +27 -0
  277. package/src/components/CodeBlock/CodeBlock.tsx +274 -0
  278. package/src/components/CodeBlock/highlight.ts +179 -0
  279. package/src/components/CodeBlock/index.ts +8 -0
  280. package/src/components/CodeBlock/sampleSync.ts +42 -0
  281. package/src/components/ColorPicker/ColorPicker.module.scss +286 -0
  282. package/src/components/ColorPicker/ColorPicker.tokens.scss +60 -0
  283. package/src/components/ColorPicker/ColorPicker.tsx +367 -0
  284. package/src/components/ColorPicker/ColorPickerPanel.tsx +265 -0
  285. package/src/components/ColorPicker/SVSquare.tsx +189 -0
  286. package/src/components/ColorPicker/colorMath.ts +141 -0
  287. package/src/components/ColorPicker/index.ts +6 -0
  288. package/src/components/ConfirmationPopover/ConfirmationPopover.module.scss +39 -0
  289. package/src/components/ConfirmationPopover/ConfirmationPopover.tokens.scss +13 -0
  290. package/src/components/ConfirmationPopover/ConfirmationPopover.tsx +395 -0
  291. package/src/components/ConfirmationPopover/index.ts +2 -0
  292. package/src/components/Constrain/Constrain.module.scss +99 -0
  293. package/src/components/Constrain/Constrain.tsx +79 -0
  294. package/src/components/Constrain/index.ts +2 -0
  295. package/src/components/CurrencySelect/CurrencySelect.module.scss +7 -0
  296. package/src/components/CurrencySelect/CurrencySelect.tsx +167 -0
  297. package/src/components/CurrencySelect/index.ts +3 -0
  298. package/src/components/CursorPagination/CursorPagination.module.scss +69 -0
  299. package/src/components/CursorPagination/CursorPagination.tokens.scss +32 -0
  300. package/src/components/CursorPagination/CursorPagination.tsx +121 -0
  301. package/src/components/CursorPagination/index.ts +2 -0
  302. package/src/components/DashboardCanvas/DashboardCanvas.module.scss +360 -0
  303. package/src/components/DashboardCanvas/DashboardCanvas.tokens.scss +48 -0
  304. package/src/components/DashboardCanvas/DashboardCanvas.tsx +1270 -0
  305. package/src/components/DashboardCanvas/DashboardCanvasItem.tsx +140 -0
  306. package/src/components/DashboardCanvas/DashboardCanvasSection.tsx +174 -0
  307. package/src/components/DashboardCanvas/engine.ts +363 -0
  308. package/src/components/DashboardCanvas/index.ts +9 -0
  309. package/src/components/DashboardWidget/DashboardWidget.module.scss +100 -0
  310. package/src/components/DashboardWidget/DashboardWidget.tokens.scss +16 -0
  311. package/src/components/DashboardWidget/DashboardWidget.tsx +188 -0
  312. package/src/components/DashboardWidget/index.ts +7 -0
  313. package/src/components/DataTable/BodyRow.tsx +197 -0
  314. package/src/components/DataTable/ColumnVisibilityTrigger.module.scss +7 -0
  315. package/src/components/DataTable/ColumnVisibilityTrigger.tsx +105 -0
  316. package/src/components/DataTable/DataTable.module.scss +511 -0
  317. package/src/components/DataTable/DataTable.tokens.scss +80 -0
  318. package/src/components/DataTable/DataTable.tsx +734 -0
  319. package/src/components/DataTable/HeaderCell.module.scss +215 -0
  320. package/src/components/DataTable/HeaderCell.tsx +440 -0
  321. package/src/components/DataTable/columnShift.ts +117 -0
  322. package/src/components/DataTable/index.ts +23 -0
  323. package/src/components/DataTable/pinStyle.ts +47 -0
  324. package/src/components/DataTable/reorderColumns.ts +66 -0
  325. package/src/components/DataTable/types.ts +289 -0
  326. package/src/components/DataTable/useColumnDragShift.ts +216 -0
  327. package/src/components/DataTable/useDataTable.ts +372 -0
  328. package/src/components/DataTable/useResizeHandle.ts +97 -0
  329. package/src/components/DatePicker/DatePicker.module.scss +180 -0
  330. package/src/components/DatePicker/DatePicker.tokens.scss +152 -0
  331. package/src/components/DatePicker/DatePicker.tsx +664 -0
  332. package/src/components/DatePicker/DatePickerGrid.module.scss +172 -0
  333. package/src/components/DatePicker/DatePickerGrid.tsx +341 -0
  334. package/src/components/DatePicker/InlineDatePicker.module.scss +32 -0
  335. package/src/components/DatePicker/InlineDatePicker.tsx +201 -0
  336. package/src/components/DatePicker/index.ts +4 -0
  337. package/src/components/DatePicker/utils.ts +364 -0
  338. package/src/components/DateRangePicker/DateRangePicker.module.scss +237 -0
  339. package/src/components/DateRangePicker/DateRangePicker.tokens.scss +78 -0
  340. package/src/components/DateRangePicker/DateRangePicker.tsx +720 -0
  341. package/src/components/DateRangePicker/InlineDateRangePicker.module.scss +94 -0
  342. package/src/components/DateRangePicker/InlineDateRangePicker.tsx +376 -0
  343. package/src/components/DateRangePicker/index.ts +5 -0
  344. package/src/components/DateRangePicker/utils.ts +151 -0
  345. package/src/components/DateStrip/DateStrip.module.scss +78 -0
  346. package/src/components/DateStrip/DateStrip.tokens.scss +23 -0
  347. package/src/components/DateStrip/DateStrip.tsx +205 -0
  348. package/src/components/DateStrip/index.ts +2 -0
  349. package/src/components/DefinitionList/DefinitionList.module.scss +102 -0
  350. package/src/components/DefinitionList/DefinitionList.tokens.scss +29 -0
  351. package/src/components/DefinitionList/DefinitionList.tsx +198 -0
  352. package/src/components/DefinitionList/index.ts +9 -0
  353. package/src/components/Divider/Divider.module.scss +144 -0
  354. package/src/components/Divider/Divider.tokens.scss +21 -0
  355. package/src/components/Divider/Divider.tsx +103 -0
  356. package/src/components/Divider/index.ts +2 -0
  357. package/src/components/Dot/Dot.module.scss +40 -0
  358. package/src/components/Dot/Dot.tokens.scss +4 -0
  359. package/src/components/Dot/Dot.tsx +45 -0
  360. package/src/components/Dot/index.ts +2 -0
  361. package/src/components/Drawer/Body.tsx +23 -0
  362. package/src/components/Drawer/Close.tsx +35 -0
  363. package/src/components/Drawer/Content.tsx +93 -0
  364. package/src/components/Drawer/Drawer.module.scss +232 -0
  365. package/src/components/Drawer/Drawer.tokens.scss +38 -0
  366. package/src/components/Drawer/Drawer.tsx +23 -0
  367. package/src/components/Drawer/DrawerRoot.tsx +190 -0
  368. package/src/components/Drawer/Footer.tsx +24 -0
  369. package/src/components/Drawer/Header.tsx +64 -0
  370. package/src/components/Drawer/Overlay.tsx +82 -0
  371. package/src/components/Drawer/context.ts +44 -0
  372. package/src/components/Drawer/index.ts +12 -0
  373. package/src/components/Drawer/useDragToClose.ts +149 -0
  374. package/src/components/DropdownMenu/CheckboxItem.tsx +144 -0
  375. package/src/components/DropdownMenu/Content.tsx +419 -0
  376. package/src/components/DropdownMenu/DropdownMenu.module.scss +280 -0
  377. package/src/components/DropdownMenu/DropdownMenu.tokens.scss +88 -0
  378. package/src/components/DropdownMenu/DropdownMenu.tsx +43 -0
  379. package/src/components/DropdownMenu/Group.tsx +76 -0
  380. package/src/components/DropdownMenu/Item.tsx +148 -0
  381. package/src/components/DropdownMenu/ItemIndicator.tsx +30 -0
  382. package/src/components/DropdownMenu/Radio.tsx +178 -0
  383. package/src/components/DropdownMenu/Root.tsx +100 -0
  384. package/src/components/DropdownMenu/Sub.tsx +332 -0
  385. package/src/components/DropdownMenu/Trigger.tsx +76 -0
  386. package/src/components/DropdownMenu/context.ts +65 -0
  387. package/src/components/DropdownMenu/index.ts +20 -0
  388. package/src/components/EmojiPicker/EmojiPicker.module.scss +84 -0
  389. package/src/components/EmojiPicker/EmojiPicker.tokens.scss +24 -0
  390. package/src/components/EmojiPicker/EmojiPicker.tsx +341 -0
  391. package/src/components/EmojiPicker/emojiData.ts +245 -0
  392. package/src/components/EmojiPicker/index.ts +3 -0
  393. package/src/components/EmptyState/EmptyState.module.scss +102 -0
  394. package/src/components/EmptyState/EmptyState.tokens.scss +28 -0
  395. package/src/components/EmptyState/EmptyState.tsx +112 -0
  396. package/src/components/EmptyState/index.ts +7 -0
  397. package/src/components/EntityChip/EntityChip.module.scss +275 -0
  398. package/src/components/EntityChip/EntityChip.tokens.scss +66 -0
  399. package/src/components/EntityChip/EntityChip.tsx +649 -0
  400. package/src/components/EntityChip/index.ts +10 -0
  401. package/src/components/ErrorState/ErrorState.module.scss +105 -0
  402. package/src/components/ErrorState/ErrorState.tokens.scss +32 -0
  403. package/src/components/ErrorState/ErrorState.tsx +125 -0
  404. package/src/components/ErrorState/index.ts +8 -0
  405. package/src/components/Field/Field.module.scss +46 -0
  406. package/src/components/Field/Field.tsx +185 -0
  407. package/src/components/Field/index.ts +2 -0
  408. package/src/components/FileUpload/FileUpload.module.scss +187 -0
  409. package/src/components/FileUpload/FileUpload.tokens.scss +81 -0
  410. package/src/components/FileUpload/FileUpload.tsx +569 -0
  411. package/src/components/FileUpload/formatBytes.ts +34 -0
  412. package/src/components/FileUpload/iconForFile.ts +40 -0
  413. package/src/components/FileUpload/index.ts +2 -0
  414. package/src/components/FilterChip/FilterChip.module.scss +61 -0
  415. package/src/components/FilterChip/FilterChip.tokens.scss +25 -0
  416. package/src/components/FilterChip/FilterChip.tsx +208 -0
  417. package/src/components/FilterChip/index.ts +5 -0
  418. package/src/components/FlowCanvas/FlowCanvas.module.scss +329 -0
  419. package/src/components/FlowCanvas/FlowCanvas.tokens.scss +45 -0
  420. package/src/components/FlowCanvas/FlowCanvas.tsx +1867 -0
  421. package/src/components/FlowCanvas/FlowControls.tsx +46 -0
  422. package/src/components/FlowCanvas/FlowEdge.tsx +58 -0
  423. package/src/components/FlowCanvas/FlowNode.tsx +76 -0
  424. package/src/components/FlowCanvas/edgePath.ts +85 -0
  425. package/src/components/FlowCanvas/index.ts +4 -0
  426. package/src/components/FlowCanvas/layout.ts +148 -0
  427. package/src/components/FlowCanvas/spatialNav.ts +76 -0
  428. package/src/components/FlowCanvas/types.ts +59 -0
  429. package/src/components/FlowCanvas/useViewport.ts +122 -0
  430. package/src/components/FormRow/FormRow.module.scss +2 -0
  431. package/src/components/FormRow/FormRow.tsx +37 -0
  432. package/src/components/FormRow/index.ts +2 -0
  433. package/src/components/FormSection/FormSection.module.scss +24 -0
  434. package/src/components/FormSection/FormSection.tsx +46 -0
  435. package/src/components/FormSection/index.ts +2 -0
  436. package/src/components/Grid/Grid.module.scss +162 -0
  437. package/src/components/Grid/Grid.tokens.scss +13 -0
  438. package/src/components/Grid/Grid.tsx +226 -0
  439. package/src/components/Grid/GridItem.tsx +77 -0
  440. package/src/components/Grid/index.ts +11 -0
  441. package/src/components/Highlight/Highlight.module.scss +43 -0
  442. package/src/components/Highlight/Highlight.tokens.scss +35 -0
  443. package/src/components/Highlight/Highlight.tsx +164 -0
  444. package/src/components/Highlight/HighlightOverlay.tsx +100 -0
  445. package/src/components/Highlight/index.ts +2 -0
  446. package/src/components/HighlightedText/HighlightedText.module.scss +11 -0
  447. package/src/components/HighlightedText/HighlightedText.tokens.scss +9 -0
  448. package/src/components/HighlightedText/HighlightedText.tsx +50 -0
  449. package/src/components/HighlightedText/highlightRanges.ts +44 -0
  450. package/src/components/HighlightedText/index.ts +2 -0
  451. package/src/components/IconPicker/IconPicker.module.scss +175 -0
  452. package/src/components/IconPicker/IconPicker.tokens.scss +40 -0
  453. package/src/components/IconPicker/IconPicker.tsx +629 -0
  454. package/src/components/IconPicker/index.ts +9 -0
  455. package/src/components/IconTile/IconTile.module.scss +57 -0
  456. package/src/components/IconTile/IconTile.tokens.scss +16 -0
  457. package/src/components/IconTile/IconTile.tsx +91 -0
  458. package/src/components/IconTile/index.ts +2 -0
  459. package/src/components/Image/Image.module.scss +266 -0
  460. package/src/components/Image/Image.tokens.scss +55 -0
  461. package/src/components/Image/Image.tsx +342 -0
  462. package/src/components/Image/index.ts +2 -0
  463. package/src/components/ImageCrop/ImageCrop.module.scss +274 -0
  464. package/src/components/ImageCrop/ImageCrop.tokens.scss +33 -0
  465. package/src/components/ImageCrop/ImageCrop.tsx +542 -0
  466. package/src/components/ImageCrop/cropGeometry.ts +120 -0
  467. package/src/components/ImageCrop/extractCropBlob.ts +140 -0
  468. package/src/components/ImageCrop/index.ts +11 -0
  469. package/src/components/ImageCrop/useCropPreview.ts +161 -0
  470. package/src/components/Indent/Indent.module.scss +33 -0
  471. package/src/components/Indent/Indent.tokens.scss +10 -0
  472. package/src/components/Indent/Indent.tsx +46 -0
  473. package/src/components/Indent/index.ts +2 -0
  474. package/src/components/Input/Input.module.scss +99 -0
  475. package/src/components/Input/Input.tokens.scss +54 -0
  476. package/src/components/Input/Input.tsx +105 -0
  477. package/src/components/Input/Suggestions.tsx +260 -0
  478. package/src/components/Input/index.ts +2 -0
  479. package/src/components/Kanban/Kanban.module.scss +39 -0
  480. package/src/components/Kanban/Kanban.tokens.scss +15 -0
  481. package/src/components/Kanban/Kanban.tsx +951 -0
  482. package/src/components/Kanban/index.ts +7 -0
  483. package/src/components/Kbd/Kbd.module.scss +47 -0
  484. package/src/components/Kbd/Kbd.tokens.scss +26 -0
  485. package/src/components/Kbd/Kbd.tsx +73 -0
  486. package/src/components/Kbd/index.ts +2 -0
  487. package/src/components/Lightbox/Lightbox.module.scss +283 -0
  488. package/src/components/Lightbox/Lightbox.tokens.scss +36 -0
  489. package/src/components/Lightbox/Lightbox.tsx +506 -0
  490. package/src/components/Lightbox/index.ts +2 -0
  491. package/src/components/Link/Link.module.scss +78 -0
  492. package/src/components/Link/Link.tokens.scss +28 -0
  493. package/src/components/Link/Link.tsx +114 -0
  494. package/src/components/Link/index.ts +2 -0
  495. package/src/components/LinkCard/LinkCard.module.scss +92 -0
  496. package/src/components/LinkCard/LinkCard.tokens.scss +9 -0
  497. package/src/components/LinkCard/LinkCard.tsx +72 -0
  498. package/src/components/LinkCard/index.ts +2 -0
  499. package/src/components/LiquidEditor/AutocompleteMenu.tsx +133 -0
  500. package/src/components/LiquidEditor/HighlightLayer.tsx +53 -0
  501. package/src/components/LiquidEditor/InsertVariableMenu.tsx +81 -0
  502. package/src/components/LiquidEditor/LiquidEditor.module.scss +339 -0
  503. package/src/components/LiquidEditor/LiquidEditor.tokens.scss +81 -0
  504. package/src/components/LiquidEditor/LiquidEditor.tsx +412 -0
  505. package/src/components/LiquidEditor/PreviewPane.tsx +29 -0
  506. package/src/components/LiquidEditor/caretCoordinates.ts +97 -0
  507. package/src/components/LiquidEditor/index.ts +7 -0
  508. package/src/components/LiquidEditor/liquidFilters.ts +23 -0
  509. package/src/components/LiquidEditor/liquidTokenizer.ts +235 -0
  510. package/src/components/LiquidEditor/types.ts +101 -0
  511. package/src/components/LiquidEditor/useLiquidAutocomplete.ts +178 -0
  512. package/src/components/List/List.module.scss +105 -0
  513. package/src/components/List/List.tokens.scss +42 -0
  514. package/src/components/List/List.tsx +124 -0
  515. package/src/components/List/index.ts +9 -0
  516. package/src/components/LiveRegion/LiveRegion.module.scss +3 -0
  517. package/src/components/LiveRegion/LiveRegion.tsx +116 -0
  518. package/src/components/LiveRegion/index.ts +2 -0
  519. package/src/components/Logo/Logo.module.scss +139 -0
  520. package/src/components/Logo/Logo.tokens.scss +14 -0
  521. package/src/components/Logo/Logo.tsx +126 -0
  522. package/src/components/Logo/index.ts +2 -0
  523. package/src/components/Masonry/Masonry.module.scss +42 -0
  524. package/src/components/Masonry/Masonry.tokens.scss +8 -0
  525. package/src/components/Masonry/Masonry.tsx +136 -0
  526. package/src/components/Masonry/index.ts +2 -0
  527. package/src/components/Masonry/masonryUtils.ts +42 -0
  528. package/src/components/MediaTile/MediaTile.module.scss +183 -0
  529. package/src/components/MediaTile/MediaTile.tokens.scss +60 -0
  530. package/src/components/MediaTile/MediaTile.tsx +208 -0
  531. package/src/components/MediaTile/index.ts +8 -0
  532. package/src/components/Modal/Body.tsx +27 -0
  533. package/src/components/Modal/Close.tsx +45 -0
  534. package/src/components/Modal/Content.tsx +98 -0
  535. package/src/components/Modal/Footer.tsx +28 -0
  536. package/src/components/Modal/Header.tsx +51 -0
  537. package/src/components/Modal/Modal.module.scss +262 -0
  538. package/src/components/Modal/Modal.tokens.scss +50 -0
  539. package/src/components/Modal/Modal.tsx +23 -0
  540. package/src/components/Modal/ModalRoot.tsx +299 -0
  541. package/src/components/Modal/Overlay.tsx +101 -0
  542. package/src/components/Modal/context.ts +60 -0
  543. package/src/components/Modal/index.ts +11 -0
  544. package/src/components/MoneyInput/MoneyInput.module.scss +57 -0
  545. package/src/components/MoneyInput/MoneyInput.tsx +433 -0
  546. package/src/components/MoneyInput/index.ts +2 -0
  547. package/src/components/OptionsPicker/OptionsPicker.module.scss +216 -0
  548. package/src/components/OptionsPicker/OptionsPicker.tokens.scss +68 -0
  549. package/src/components/OptionsPicker/OptionsPicker.tsx +936 -0
  550. package/src/components/OptionsPicker/index.ts +9 -0
  551. package/src/components/OtpInput/OtpInput.module.scss +69 -0
  552. package/src/components/OtpInput/OtpInput.tokens.scss +45 -0
  553. package/src/components/OtpInput/OtpInput.tsx +368 -0
  554. package/src/components/OtpInput/index.ts +2 -0
  555. package/src/components/Page/Page.module.scss +30 -0
  556. package/src/components/Page/Page.tokens.scss +11 -0
  557. package/src/components/Page/Page.tsx +53 -0
  558. package/src/components/Page/index.ts +2 -0
  559. package/src/components/PageHeader/PageHeader.module.scss +197 -0
  560. package/src/components/PageHeader/PageHeader.tokens.scss +41 -0
  561. package/src/components/PageHeader/PageHeader.tsx +310 -0
  562. package/src/components/PageHeader/index.ts +20 -0
  563. package/src/components/Pagination/Pagination.module.scss +117 -0
  564. package/src/components/Pagination/Pagination.tokens.scss +54 -0
  565. package/src/components/Pagination/Pagination.tsx +165 -0
  566. package/src/components/Pagination/index.ts +4 -0
  567. package/src/components/Pagination/paginationRange.ts +72 -0
  568. package/src/components/PasswordInput/PasswordInput.module.scss +120 -0
  569. package/src/components/PasswordInput/PasswordInput.tokens.scss +44 -0
  570. package/src/components/PasswordInput/PasswordInput.tsx +210 -0
  571. package/src/components/PasswordInput/index.ts +2 -0
  572. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.module.scss +80 -0
  573. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tokens.scss +40 -0
  574. package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tsx +96 -0
  575. package/src/components/PasswordStrengthMeter/index.ts +2 -0
  576. package/src/components/PersonDisplay/PersonDisplay.module.scss +180 -0
  577. package/src/components/PersonDisplay/PersonDisplay.tokens.scss +35 -0
  578. package/src/components/PersonDisplay/PersonDisplay.tsx +420 -0
  579. package/src/components/PersonDisplay/index.ts +10 -0
  580. package/src/components/PhoneInput/PhoneInput.module.scss +23 -0
  581. package/src/components/PhoneInput/PhoneInput.tsx +271 -0
  582. package/src/components/PhoneInput/index.ts +4 -0
  583. package/src/components/PhoneInput/phone.ts +128 -0
  584. package/src/components/PillMenu/PillMenu.module.scss +117 -0
  585. package/src/components/PillMenu/PillMenu.tokens.scss +22 -0
  586. package/src/components/PillMenu/PillMenu.tsx +324 -0
  587. package/src/components/PillMenu/index.ts +2 -0
  588. package/src/components/Popover/Anchor.tsx +37 -0
  589. package/src/components/Popover/Close.tsx +45 -0
  590. package/src/components/Popover/Content.tsx +213 -0
  591. package/src/components/Popover/Heading.tsx +33 -0
  592. package/src/components/Popover/Popover.module.scss +177 -0
  593. package/src/components/Popover/Popover.tokens.scss +22 -0
  594. package/src/components/Popover/Popover.tsx +23 -0
  595. package/src/components/Popover/PopoverRoot.tsx +75 -0
  596. package/src/components/Popover/Trigger.tsx +86 -0
  597. package/src/components/Popover/context.ts +22 -0
  598. package/src/components/Popover/index.ts +7 -0
  599. package/src/components/Progress/Progress.module.scss +110 -0
  600. package/src/components/Progress/Progress.tokens.scss +44 -0
  601. package/src/components/Progress/Progress.tsx +129 -0
  602. package/src/components/Progress/index.ts +2 -0
  603. package/src/components/QrCode/QrCode.module.scss +97 -0
  604. package/src/components/QrCode/QrCode.tokens.scss +17 -0
  605. package/src/components/QrCode/QrCode.tsx +233 -0
  606. package/src/components/QrCode/index.ts +2 -0
  607. package/src/components/QrCode/qr.ts +161 -0
  608. package/src/components/Radio/Radio.module.scss +175 -0
  609. package/src/components/Radio/Radio.tokens.scss +59 -0
  610. package/src/components/Radio/Radio.tsx +127 -0
  611. package/src/components/Radio/RadioGroup.module.scss +42 -0
  612. package/src/components/Radio/RadioGroup.tsx +120 -0
  613. package/src/components/Radio/RadioGroupContext.tsx +30 -0
  614. package/src/components/Radio/index.ts +4 -0
  615. package/src/components/Rail/Rail.module.scss +510 -0
  616. package/src/components/Rail/Rail.tokens.scss +92 -0
  617. package/src/components/Rail/Rail.tsx +287 -0
  618. package/src/components/Rail/RailCollapseToggle.tsx +57 -0
  619. package/src/components/Rail/RailFooter.tsx +17 -0
  620. package/src/components/Rail/RailGroup.tsx +728 -0
  621. package/src/components/Rail/RailGroupContext.ts +9 -0
  622. package/src/components/Rail/RailHeader.tsx +23 -0
  623. package/src/components/Rail/RailItem.tsx +119 -0
  624. package/src/components/Rail/RailSection.tsx +39 -0
  625. package/src/components/Rail/RailSpacer.tsx +19 -0
  626. package/src/components/Rail/index.ts +9 -0
  627. package/src/components/RelativeDateInput/RelativeDateInput.module.scss +15 -0
  628. package/src/components/RelativeDateInput/RelativeDateInput.tokens.scss +6 -0
  629. package/src/components/RelativeDateInput/RelativeDateInput.tsx +474 -0
  630. package/src/components/RelativeDateInput/index.ts +10 -0
  631. package/src/components/RelativeDateInput/relativeDate.ts +127 -0
  632. package/src/components/RichText/RichText.module.scss +5 -0
  633. package/src/components/RichText/RichText.tsx +70 -0
  634. package/src/components/RichText/RichTextAttachment.module.scss +82 -0
  635. package/src/components/RichText/RichTextAttachment.tsx +122 -0
  636. package/src/components/RichText/_prose.scss +79 -0
  637. package/src/components/RichText/attachmentIcon.tsx +24 -0
  638. package/src/components/RichText/engine/attachment.ts +154 -0
  639. package/src/components/RichText/engine/autolink.ts +64 -0
  640. package/src/components/RichText/engine/blockUnit.ts +174 -0
  641. package/src/components/RichText/engine/colorMarks.ts +85 -0
  642. package/src/components/RichText/engine/escape.ts +11 -0
  643. package/src/components/RichText/engine/fromHtml.ts +353 -0
  644. package/src/components/RichText/engine/fromMarkdown.ts +20 -0
  645. package/src/components/RichText/engine/inlines.ts +82 -0
  646. package/src/components/RichText/engine/listDepths.ts +32 -0
  647. package/src/components/RichText/engine/marks.ts +80 -0
  648. package/src/components/RichText/engine/mdToHtml.ts +178 -0
  649. package/src/components/RichText/engine/model.ts +157 -0
  650. package/src/components/RichText/engine/position.ts +118 -0
  651. package/src/components/RichText/engine/renderDoc.tsx +395 -0
  652. package/src/components/RichText/engine/renderLink.ts +15 -0
  653. package/src/components/RichText/engine/renderMention.ts +16 -0
  654. package/src/components/RichText/engine/safeHref.ts +22 -0
  655. package/src/components/RichText/engine/toHtml.ts +154 -0
  656. package/src/components/RichText/engine/toMarkdown.ts +97 -0
  657. package/src/components/RichText/engine/transforms.ts +434 -0
  658. package/src/components/RichText/imageMaxHeightStyle.ts +10 -0
  659. package/src/components/RichText/index.ts +31 -0
  660. package/src/components/RichTextEditor/RichTextAttachmentConfig.tsx +264 -0
  661. package/src/components/RichTextEditor/RichTextBlockControls.tsx +365 -0
  662. package/src/components/RichTextEditor/RichTextBlockMenu.tsx +162 -0
  663. package/src/components/RichTextEditor/RichTextColorMenu.tsx +115 -0
  664. package/src/components/RichTextEditor/RichTextEditor.module.scss +298 -0
  665. package/src/components/RichTextEditor/RichTextEditor.tsx +1910 -0
  666. package/src/components/RichTextEditor/RichTextImageResizer.tsx +131 -0
  667. package/src/components/RichTextEditor/RichTextLinkEditor.tsx +151 -0
  668. package/src/components/RichTextEditor/RichTextMentionMenu.tsx +99 -0
  669. package/src/components/RichTextEditor/RichTextToolbar.tsx +379 -0
  670. package/src/components/RichTextEditor/autolinkInput.ts +65 -0
  671. package/src/components/RichTextEditor/blockDrop.ts +9 -0
  672. package/src/components/RichTextEditor/blockReflow.ts +62 -0
  673. package/src/components/RichTextEditor/commands.ts +300 -0
  674. package/src/components/RichTextEditor/history.ts +93 -0
  675. package/src/components/RichTextEditor/icons.tsx +152 -0
  676. package/src/components/RichTextEditor/imageSize.ts +70 -0
  677. package/src/components/RichTextEditor/index.ts +5 -0
  678. package/src/components/RichTextEditor/input.ts +209 -0
  679. package/src/components/RichTextEditor/inputRules.ts +71 -0
  680. package/src/components/RichTextEditor/links.ts +103 -0
  681. package/src/components/RichTextEditor/mentionContext.ts +37 -0
  682. package/src/components/RichTextEditor/mentions.ts +28 -0
  683. package/src/components/RichTextEditor/preventSelectionLoss.ts +15 -0
  684. package/src/components/RichTextEditor/selection.ts +415 -0
  685. package/src/components/RichTextEditor/shortcuts.ts +44 -0
  686. package/src/components/RichTextEditor/useAnchoredFloating.ts +50 -0
  687. package/src/components/RichTextEditor/useAttachmentConfig.ts +134 -0
  688. package/src/components/RichTextEditor/useDismissOnOutsidePointerDown.ts +26 -0
  689. package/src/components/RichTextEditor/useLinkEditor.ts +107 -0
  690. package/src/components/RichTextEditor/useMention.ts +226 -0
  691. package/src/components/RichTextEditor/useOverlayRect.ts +73 -0
  692. package/src/components/RichTextEditor/useUpload.ts +246 -0
  693. package/src/components/Screen/Screen.module.scss +46 -0
  694. package/src/components/Screen/Screen.tokens.scss +20 -0
  695. package/src/components/Screen/Screen.tsx +97 -0
  696. package/src/components/Screen/index.ts +2 -0
  697. package/src/components/ScrollArea/ScrollArea.module.scss +39 -0
  698. package/src/components/ScrollArea/ScrollArea.tokens.scss +15 -0
  699. package/src/components/ScrollArea/ScrollArea.tsx +154 -0
  700. package/src/components/ScrollArea/index.ts +2 -0
  701. package/src/components/Select/Chip.tsx +45 -0
  702. package/src/components/Select/Empty.tsx +39 -0
  703. package/src/components/Select/Error.tsx +51 -0
  704. package/src/components/Select/HiddenInputs.tsx +44 -0
  705. package/src/components/Select/Listbox.tsx +557 -0
  706. package/src/components/Select/Loading.tsx +30 -0
  707. package/src/components/Select/Select.module.scss +512 -0
  708. package/src/components/Select/Select.tokens.scss +140 -0
  709. package/src/components/Select/Select.tsx +685 -0
  710. package/src/components/Select/Trigger.tsx +952 -0
  711. package/src/components/Select/context.ts +101 -0
  712. package/src/components/Select/emptyStateText.ts +19 -0
  713. package/src/components/Select/index.ts +9 -0
  714. package/src/components/Select/useSelectState.ts +157 -0
  715. package/src/components/Select/utils-types.ts +7 -0
  716. package/src/components/Select/utils.ts +122 -0
  717. package/src/components/SettingRow/SettingRow.module.scss +166 -0
  718. package/src/components/SettingRow/SettingRow.tokens.scss +37 -0
  719. package/src/components/SettingRow/SettingRow.tsx +242 -0
  720. package/src/components/SettingRow/index.ts +7 -0
  721. package/src/components/Skeleton/Skeleton.module.scss +55 -0
  722. package/src/components/Skeleton/Skeleton.tokens.scss +17 -0
  723. package/src/components/Skeleton/Skeleton.tsx +131 -0
  724. package/src/components/Skeleton/index.ts +4 -0
  725. package/src/components/Skeleton/useSkeletonVisibility.ts +95 -0
  726. package/src/components/Slider/Slider.module.scss +293 -0
  727. package/src/components/Slider/Slider.tokens.scss +98 -0
  728. package/src/components/Slider/Slider.tsx +624 -0
  729. package/src/components/Slider/index.ts +9 -0
  730. package/src/components/SlotGrid/SlotGrid.module.scss +61 -0
  731. package/src/components/SlotGrid/SlotGrid.tokens.scss +21 -0
  732. package/src/components/SlotGrid/SlotGrid.tsx +111 -0
  733. package/src/components/SlotGrid/index.ts +2 -0
  734. package/src/components/SocialButton/SocialButton.module.scss +4 -0
  735. package/src/components/SocialButton/SocialButton.tsx +40 -0
  736. package/src/components/SocialButton/index.ts +2 -0
  737. package/src/components/Sortable/Sortable.module.scss +177 -0
  738. package/src/components/Sortable/Sortable.tokens.scss +27 -0
  739. package/src/components/Sortable/Sortable.tsx +572 -0
  740. package/src/components/Sortable/containerAwareCollision.ts +125 -0
  741. package/src/components/Sortable/index.ts +13 -0
  742. package/src/components/SortableGroup/SortableGroup.module.scss +23 -0
  743. package/src/components/SortableGroup/SortableGroup.tsx +315 -0
  744. package/src/components/SortableGroup/index.ts +4 -0
  745. package/src/components/SortableGroup/moveSortableItem.ts +39 -0
  746. package/src/components/Sparkline/Sparkline.module.scss +28 -0
  747. package/src/components/Sparkline/Sparkline.tokens.scss +7 -0
  748. package/src/components/Sparkline/Sparkline.tsx +133 -0
  749. package/src/components/Sparkline/index.ts +2 -0
  750. package/src/components/Sparkline/sparklineModel.ts +119 -0
  751. package/src/components/Split/Split.module.scss +158 -0
  752. package/src/components/Split/Split.tokens.scss +10 -0
  753. package/src/components/Split/Split.tsx +231 -0
  754. package/src/components/Split/index.ts +2 -0
  755. package/src/components/Stack/Stack.module.scss +67 -0
  756. package/src/components/Stack/Stack.tokens.scss +11 -0
  757. package/src/components/Stack/Stack.tsx +100 -0
  758. package/src/components/Stack/index.ts +2 -0
  759. package/src/components/StagePath/StagePath.module.scss +255 -0
  760. package/src/components/StagePath/StagePath.tokens.scss +43 -0
  761. package/src/components/StagePath/StagePath.tsx +176 -0
  762. package/src/components/StagePath/index.ts +2 -0
  763. package/src/components/StatGroup/StatGroup.module.scss +6 -0
  764. package/src/components/StatGroup/StatGroup.tsx +70 -0
  765. package/src/components/StatGroup/StatGroupContext.ts +10 -0
  766. package/src/components/StatGroup/StatTile.module.scss +99 -0
  767. package/src/components/StatGroup/StatTile.tokens.scss +35 -0
  768. package/src/components/StatGroup/StatTile.tsx +143 -0
  769. package/src/components/StatGroup/index.ts +4 -0
  770. package/src/components/Sticky/Sticky.module.scss +98 -0
  771. package/src/components/Sticky/Sticky.tokens.scss +17 -0
  772. package/src/components/Sticky/Sticky.tsx +103 -0
  773. package/src/components/Sticky/index.ts +2 -0
  774. package/src/components/Switch/Switch.module.scss +182 -0
  775. package/src/components/Switch/Switch.tokens.scss +59 -0
  776. package/src/components/Switch/Switch.tsx +214 -0
  777. package/src/components/Switch/index.ts +2 -0
  778. package/src/components/Table/Table.module.scss +308 -0
  779. package/src/components/Table/Table.tokens.scss +79 -0
  780. package/src/components/Table/Table.tsx +381 -0
  781. package/src/components/Table/index.ts +15 -0
  782. package/src/components/TableOfContents/TableOfContents.module.scss +83 -0
  783. package/src/components/TableOfContents/TableOfContents.tokens.scss +26 -0
  784. package/src/components/TableOfContents/TableOfContents.tsx +192 -0
  785. package/src/components/TableOfContents/activeSection.ts +18 -0
  786. package/src/components/TableOfContents/index.ts +2 -0
  787. package/src/components/Tabs/Tabs.module.scss +359 -0
  788. package/src/components/Tabs/Tabs.tokens.scss +50 -0
  789. package/src/components/Tabs/Tabs.tsx +538 -0
  790. package/src/components/Tabs/index.ts +2 -0
  791. package/src/components/Text/Text.module.scss +115 -0
  792. package/src/components/Text/Text.tokens.scss +55 -0
  793. package/src/components/Text/Text.tsx +197 -0
  794. package/src/components/Text/index.ts +2 -0
  795. package/src/components/Textarea/Textarea.module.scss +94 -0
  796. package/src/components/Textarea/Textarea.tokens.scss +48 -0
  797. package/src/components/Textarea/Textarea.tsx +246 -0
  798. package/src/components/Textarea/index.ts +2 -0
  799. package/src/components/Thread/Thread.module.scss +161 -0
  800. package/src/components/Thread/Thread.tokens.scss +32 -0
  801. package/src/components/Thread/Thread.tsx +176 -0
  802. package/src/components/Thread/index.ts +2 -0
  803. package/src/components/TimeField/TimeField.module.scss +232 -0
  804. package/src/components/TimeField/TimeField.tsx +793 -0
  805. package/src/components/TimeField/index.ts +2 -0
  806. package/src/components/Timeline/Timeline.module.scss +58 -0
  807. package/src/components/Timeline/Timeline.tokens.scss +13 -0
  808. package/src/components/Timeline/Timeline.tsx +53 -0
  809. package/src/components/Timeline/index.ts +2 -0
  810. package/src/components/Title/Title.module.scss +84 -0
  811. package/src/components/Title/Title.tokens.scss +37 -0
  812. package/src/components/Title/Title.tsx +150 -0
  813. package/src/components/Title/index.ts +2 -0
  814. package/src/components/Toast/Toast.module.scss +299 -0
  815. package/src/components/Toast/Toast.tokens.scss +65 -0
  816. package/src/components/Toast/Toast.tsx +122 -0
  817. package/src/components/Toast/ToastViewport.tsx +166 -0
  818. package/src/components/Toast/api.ts +175 -0
  819. package/src/components/Toast/index.ts +5 -0
  820. package/src/components/Toast/store.ts +133 -0
  821. package/src/components/Toast/useToastTimer.ts +94 -0
  822. package/src/components/Tooltip/Tooltip.module.scss +99 -0
  823. package/src/components/Tooltip/Tooltip.tokens.scss +23 -0
  824. package/src/components/Tooltip/Tooltip.tsx +341 -0
  825. package/src/components/Tooltip/index.ts +2 -0
  826. package/src/components/TopBar/TopBar.module.scss +235 -0
  827. package/src/components/TopBar/TopBar.tokens.scss +79 -0
  828. package/src/components/TopBar/TopBar.tsx +87 -0
  829. package/src/components/TopBar/TopBarEnd.tsx +20 -0
  830. package/src/components/TopBar/TopBarIconButton.tsx +86 -0
  831. package/src/components/TopBar/TopBarSearch.tsx +319 -0
  832. package/src/components/TopBar/TopBarSearchPanel.tsx +268 -0
  833. package/src/components/TopBar/TopBarStart.tsx +20 -0
  834. package/src/components/TopBar/index.ts +11 -0
  835. package/src/components/Tour/Spotlight.tsx +121 -0
  836. package/src/components/Tour/Tour.module.scss +210 -0
  837. package/src/components/Tour/Tour.tokens.scss +58 -0
  838. package/src/components/Tour/Tour.tsx +617 -0
  839. package/src/components/Tour/index.ts +2 -0
  840. package/src/components/Tour/useTourTarget.ts +115 -0
  841. package/src/components/TreeView/TreeView.module.scss +268 -0
  842. package/src/components/TreeView/TreeView.tokens.scss +36 -0
  843. package/src/components/TreeView/TreeView.tsx +536 -0
  844. package/src/components/TreeView/index.ts +3 -0
  845. package/src/components/TreeView/treeModel.ts +224 -0
  846. package/src/components/VisuallyHidden/VisuallyHidden.module.scss +7 -0
  847. package/src/components/VisuallyHidden/VisuallyHidden.tsx +29 -0
  848. package/src/components/VisuallyHidden/index.ts +2 -0
  849. package/src/components/WidgetPreview/WidgetPreview.module.scss +11 -0
  850. package/src/components/WidgetPreview/WidgetPreview.tokens.scss +26 -0
  851. package/src/components/WidgetPreview/WidgetPreview.tsx +36 -0
  852. package/src/components/WidgetPreview/WidgetShape.module.scss +140 -0
  853. package/src/components/WidgetPreview/WidgetShape.tsx +159 -0
  854. package/src/components/WidgetPreview/index.ts +2 -0
  855. package/src/components/_internal/Trend.tsx +27 -0
  856. package/src/components/_internal/choiceTile.scss +74 -0
  857. package/src/components/_internal/collapse.scss +10 -0
  858. package/src/components/_internal/collapse.ts +58 -0
  859. package/src/components/_internal/currency.ts +257 -0
  860. package/src/components/_internal/dragAnnouncements.ts +200 -0
  861. package/src/components/_internal/fieldWiring.ts +225 -0
  862. package/src/components/_internal/gridSpan.ts +54 -0
  863. package/src/components/_internal/isoDay.ts +35 -0
  864. package/src/components/_internal/letterKey.ts +26 -0
  865. package/src/components/_internal/overlay/focusRestore.ts +21 -0
  866. package/src/components/_internal/overlay/index.ts +12 -0
  867. package/src/components/_internal/overlay/tourHold.ts +23 -0
  868. package/src/components/_internal/overlay/useFocusTrap.ts +120 -0
  869. package/src/components/_internal/overlay/useInOverlay.ts +81 -0
  870. package/src/components/_internal/overlay/useOverlayStack.ts +232 -0
  871. package/src/components/_internal/overlay/useScrollLock.ts +112 -0
  872. package/src/components/_internal/refs.ts +48 -0
  873. package/src/components/_internal/statusColor.ts +26 -0
  874. package/src/components/_internal/timeUtils.ts +23 -0
  875. package/src/components/_internal/useAsyncOptions.ts +145 -0
  876. package/src/components/_internal/useClippedTooltip.ts +50 -0
  877. package/src/components/_internal/useControllableState.ts +50 -0
  878. package/src/components.manifest.json +1141 -0
  879. package/src/hooks/useBelowBreakpoint.ts +58 -0
  880. package/src/i18n/I18nProvider.tsx +52 -0
  881. package/src/i18n/LocaleProvider.tsx +17 -0
  882. package/src/i18n/en.ts +648 -0
  883. package/src/i18n/format.ts +71 -0
  884. package/src/i18n/index.ts +13 -0
  885. package/src/i18n/messages.ts +1275 -0
  886. package/src/i18n/ru.ts +677 -0
  887. package/src/i18n/useLocale.ts +19 -0
  888. package/src/i18n/useTranslation.ts +58 -0
  889. package/src/index.ts +913 -0
  890. package/src/palette/index.ts +2 -0
  891. package/src/palette/palette.ts +108 -0
  892. package/src/styles/dark.scss +4 -0
  893. package/src/styles/global.scss +7 -0
  894. package/src/styles/mixins.scss +143 -0
  895. package/src/styles/reset.scss +78 -0
  896. package/src/styles/tokens.scss +18 -0
  897. package/src/styles/typography.scss +44 -0
@@ -0,0 +1,67 @@
1
+ # `<CodeBlock>` — highlighted, copyable code sample
2
+
3
+ ```tsx
4
+ <CodeBlock language="json" code={'{ "id": 42 }'} />;
5
+
6
+ // Persist the choice: ONE shared state for every block of the group (see below).
7
+ const [lang, setLang] = usePersistedSample('api-lang');
8
+
9
+ <CodeBlock samples={samples} activeSampleId={lang} onSampleChange={setLang} />;
10
+ ```
11
+
12
+ ```tsx
13
+ // Call once at page/layout level and pass the same pair to every block.
14
+ function usePersistedSample(storageKey: string) {
15
+ const [id, setId] = useState<string>();
16
+ // Client-only read in an effect so server and client render the same first frame.
17
+ useEffect(() => {
18
+ try {
19
+ setId(localStorage.getItem(storageKey) ?? undefined);
20
+ } catch {} // storage blocked
21
+ }, [storageKey]);
22
+ const set = (next: string) => {
23
+ setId(next);
24
+ try {
25
+ localStorage.setItem(storageKey, next);
26
+ } catch {} // storage blocked
27
+ };
28
+ return [id, set] as const;
29
+ }
30
+ ```
31
+
32
+ <!-- props:start -->
33
+
34
+ ## Props
35
+
36
+ <!-- prettier-ignore -->
37
+ | Prop | Type | Required | Description |
38
+ |---|---|---|---|
39
+ | `code` | `string` | no | Single-sample mode: the source. Ignored when `samples` is set. |
40
+ | `language` | `(string & {}) \| CodeBlockLanguage` | no | Single-sample mode: grammar for highlighting — `'json'`, `'bash'`, `'javascript'`, `'typescript'`, `'python'`, `'go'`, `'kotlin'`, `'java'`, `'csharp'` or `'rust'` (aliases `sh`, `shell`, `js`, `ts`, `py`, `golang`, `kt`, `kts`, `cs`, `c#`, `rs`). Anything else renders as plain text. |
41
+ | `title` | `string` | no | Header label in single-sample mode. Defaults to a one-item `samples` entry's `label`, else the language name (`JSON`, `Bash`…), else "Plain text". Also names the body (single-sample) or the sample tabs (multi-sample). |
42
+ | `samples` | `readonly CodeBlockSample[]` | no | Multi-sample mode: 2+ samples render as tabs. Wins over `code`/`language`. |
43
+ | `activeSampleId` | `string` | no | Controlled active sample id. Wins over `syncKey` and the user's own pick. |
44
+ | `defaultSampleId` | `string` | no | Initial sample id when uncontrolled and nothing is synced. Defaults to the first sample. |
45
+ | `onSampleChange` | `((id: string) => void)` | no | Called with the new id when the user picks a tab in THIS block (not when a synced block changes it). |
46
+ | `syncKey` | `string` | no | Blocks sharing a `syncKey` switch together: picking `py` in one selects `py` in every block with the same key that has a `py` sample. In-memory, per page load; for uncontrolled blocks (controlled blocks sharing one state don't need it). |
47
+ | `highlightLines` | `CodeBlockHighlightLines` | no | Lines to emphasise (visual only — explain the emphasis in prose). |
48
+ | `maxHeight` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | no | Caps the body height; the body scrolls inside it (it is always a focusable, named region). `xs` 200px · `sm` 320px · `md` 448px · `lg` 640px · `xl` 800px. Default: no cap. |
49
+ | `defaultWrap` | `boolean` | no | Initial state of the wrap-lines toggle. Default `false` (long lines scroll horizontally). |
50
+ | …native | | | plus native `<div>` attributes |
51
+
52
+ <!-- props:end -->
53
+
54
+ - **Languages:** `json`, `bash`, `javascript`, `typescript`, `python`, `go`, `kotlin`, `java`, `csharp`, `rust` (aliases `sh`, `shell`, `js`, `ts`, `py`, `golang`, `kt`, `kts`, `cs`, `c#`, `rs`). Unknown languages render as plain text.
55
+ - **Header label** is `title`, then the label of a one-item `samples` array, then the language name, then "Plain text".
56
+ - **Accessibility:** the code body is always keyboard-focusable. Single mode is a `role="group"` named by the header label (`title`, else the one-item sample label, else the language name, else "Plain text"); multi mode is a tabpanel labelled by its tab, and `title` names the tablist.
57
+ - **`highlightLines` is visual only.** Explain the emphasis in the surrounding prose.
58
+ - **`syncKey` is in-memory** (per page load) and is for UNCONTROLLED blocks. The library never touches storage. To persist, own the choice as ONE piece of state shared by every block of the group (the `usePersistedSample` hook above, called once at page/layout level, or React context) and give every block `activeSampleId={lang}` + `onSampleChange={setLang}`. Controlled blocks don't need `syncKey`: the shared state keeps them in step. Do NOT give each block its own `useState` plus `syncKey`: the controlled `activeSampleId` wins over `syncKey`, so return visits would leave blocks out of sync. `defaultSampleId` is only the static initial choice.
59
+ - **Sample ids** are used in DOM ids: don't put spaces in them.
60
+ - **Active sample precedence:** controlled `activeSampleId`, then `syncKey`, then the user's own pick, then `defaultSampleId`, then the first sample. An `activeSampleId` that matches no sample id falls through to the next rule.
61
+ - Renders identically on the server (SSR-safe).
62
+
63
+ #### When NOT to use
64
+
65
+ - ❌ Inline code inside a sentence: use `Code`.
66
+ - ❌ Editable code: use `LiquidEditor` / `RichTextEditor`.
67
+ - ❌ A language outside the list above and you expect colours: it renders as plain text.
@@ -0,0 +1,115 @@
1
+ # `<ColorPicker>` — controlled HEX color picker (popover + inline)
2
+
3
+ ```tsx
4
+ const [hex, setHex] = useState('#4F46E5');
5
+
6
+ // Default popover with the built-in trigger swatch:
7
+ <Field label="Brand color">
8
+ <ColorPicker value={hex} onChange={setHex} />
9
+ </Field>
10
+
11
+ // Custom trigger:
12
+ <Field label="Brand color" description="Used for campaign accents">
13
+ <ColorPicker value={hex} onChange={setHex}>
14
+ <ColorPicker.Trigger asChild>
15
+ <Button variant="secondary">Pick a color</Button>
16
+ </ColorPicker.Trigger>
17
+ </ColorPicker>
18
+ </Field>
19
+
20
+ // Inline (always-visible panel — for theme builders, settings rows):
21
+ <ColorPicker.Panel value={hex} onChange={setHex} />
22
+
23
+ // With consumer-supplied preset swatches:
24
+ <ColorPicker.Panel value={hex} onChange={setHex} presets={['#4F46E5', '#10B981', '#F59E0B', '#EF4444']} />
25
+ ```
26
+
27
+ <!-- props:start -->
28
+
29
+ ## Props
30
+
31
+ ### `ColorPickerProps`
32
+
33
+ <!-- prettier-ignore -->
34
+ | Prop | Type | Required | Description |
35
+ |---|---|---|---|
36
+ | `value` | `string` | yes | Current color as `#RRGGBB`. Controlled — required. |
37
+ | `onChange` | `(hex: string) => void` | yes | Fires per drag tick + on input change + on preset click. High frequency during drags. |
38
+ | `onChangeEnd` | `((hex: string) => void)` | no | Fires on the trailing edge of an interaction. Use for commit-style logic. |
39
+ | `presets` | `string[]` | no | Optional preset color swatches. If provided, rendered as a grid below the hue slider in the panel. |
40
+ | `disabled` | `boolean` | no | Disable interaction. Trigger doesn't open; panel is non-interactive. |
41
+ | `invalid` | `boolean` | no | Marks the focusable trigger invalid for Field composition. Default: `false`. |
42
+ | `required` | `boolean` | no | Consumed for Field composition so Field can render its visible required marker. Native buttons do not support `aria-required`, so this does not add required semantics to the trigger. Default: `false`. |
43
+ | `aria-label` | `string` | no | Accessible name for the focusable trigger. Forwarded to the default or custom trigger, not the root wrapper. On the default trigger the current value is appended (`aria-label="Accent colour"` → "Accent colour, current value #3366FF"); the popover dialog is named by the bare `aria-label`. Ignored when `aria-labelledby` is provided. An explicit name on a custom trigger child takes precedence — but an EMPTY one on that child does not, since an empty string names nothing. |
44
+ | `triggerLabel` | `string` | no | Accessible label for the default trigger. Defaults to the i18n value at `colorPicker.triggerLabel` (`'Pick a color'` in English) when omitted OR empty — an empty string is not an explicit name, so it takes the default too. Ignored when a custom trigger is provided via `<ColorPicker.Trigger>`. |
45
+ | `aria-labelledby` | `string` | no | Id(s) of element(s) that label the trigger button. Forwarded onto the focusable trigger (not the root wrapper) and takes precedence over the generated `aria-label`. Set automatically when wrapped in `<Field label>`. On the default trigger a visually hidden span holding the current HEX is appended, so the name reads e.g. "Accent colour #0052CC". The popover dialog is named by these ids alone (purpose, no value). |
46
+ | `aria-describedby` | `string` | no | Id(s) of element(s) that describe the trigger button (e.g. a Field error or helper text). Forwarded onto the focusable trigger, not the root wrapper. |
47
+ | `popoverPlacement` | `'top' \| 'top-start' \| 'top-end' \| 'bottom' \| 'bottom-start' \| 'bottom-end'` | no | Popover placement (split internally into side + align). Default `'bottom-start'`. |
48
+ | `panelFooter` | `ReactNode` | no | Optional content rendered inside the popover, below the panel (and below its presets grid, if any) — for live feedback about the color being picked, e.g. a contrast-ratio readout that updates as the user drags. Not available on the standalone `<ColorPicker.Panel>`, which has no popover to render it inside. Not an `aria-live` region by default — announcing every drag tick would be disruptive. If the footer's text should be announced as it settles, wire that up yourself (e.g. wrap it in your own `role="status"` span); that tradeoff is the consumer's call, not the picker's default. The footer is wired as the popover dialog's `aria-describedby`, so its text is read when the dialog opens. Keep it short — it is read in full. |
49
+ | `children` | `ReactNode` | no | Optional `<ColorPicker.Trigger asChild>` override for custom triggers. |
50
+ | …native | | | plus native `<div>` attributes |
51
+
52
+ ### `ColorPickerPanelProps`
53
+
54
+ <!-- prettier-ignore -->
55
+ | Prop | Type | Required | Description |
56
+ |---|---|---|---|
57
+ | `value` | `string` | yes | Current color as `#RRGGBB`. Controlled — required. |
58
+ | `onChange` | `(hex: string) => void` | yes | Fires per drag tick + on input change + on preset click. High frequency during drags. |
59
+ | `onChangeEnd` | `((hex: string) => void)` | no | Fires on the trailing edge of an interaction — pointer release on the SV pad / hue slider, blur on the HEX input, preset click. Use for commit-style logic (network calls, history snapshots). |
60
+ | `presets` | `string[]` | no | Optional preset color swatches. If provided, rendered as a grid below the hue slider. Clicking a swatch commits the color (fires both onChange and onChangeEnd). Invalid entries are silently dropped. |
61
+ | `disabled` | `boolean` | no | Disable interaction. |
62
+ | `framed` | `boolean` | no | Whether the panel draws its own chrome (border, shadow, padding, background, radius). Default `true` — the standalone `<ColorPicker.Panel>` needs that chrome to read as a discrete surface on a page. Set `false` when nesting the panel inside a container that already draws a frame — a `Popover.Content`, a `Card`, or your own bordered surface — so the two frames don't nest. `<ColorPicker>` renders its popover panel this way internally, for exactly this reason. |
63
+ | …native | | | plus native `<div>` attributes |
64
+
65
+ ### `ColorPickerTriggerProps`
66
+
67
+ <!-- prettier-ignore -->
68
+ | Prop | Type | Required | Description |
69
+ |---|---|---|---|
70
+ | `asChild` | `boolean` | no | Currently always behaves as `true` (the child is merged with trigger semantics via `<Popover.Trigger>`'s cloneElement). Reserved for a future Slot-style variant where `false` would wrap the child instead of merging. Documented for API stability. |
71
+ | `children` | `ReactNode` | yes | The element to render as the trigger. Must accept `ref`, `onClick`, `id`, and ARIA attributes so ColorPicker can connect it to Field. Explicit child ARIA naming, description, and invalid state win over the parent values; ColorPicker's public `id` still owns the label association. |
72
+
73
+ <!-- props:end -->
74
+
75
+ - **Controlled-only.** `value: string` in `#RRGGBB` form. Loose input accepted on the HEX text field (`#FFF`, `FFF`, `#ffffff`); the component always emits the canonical `#RRGGBB` (uppercase, with `#`).
76
+ - **The SV pad** is `role="application"` with an `aria-valuetext` describing the state (a 2D control has no standard ARIA pattern). Keyboard adjusts S/V by 1% per arrow, 10% with Shift. Use `<ColorPicker>` (not the Panel) when you need a compact trigger.
77
+ - **Two distribution shapes via the compound API.** `<ColorPicker>` is the popover-wrapped form-field-ready widget. `<ColorPicker.Panel>` is the same picker without the popover wrapping — drop it directly into a settings page or theme builder.
78
+ - **Default trigger** is an input-field-shaped button with a 16×16 swatch + uppercase HEX text. Override via `<ColorPicker.Trigger asChild>{customNode}</ColorPicker.Trigger>` (the child must `forwardRef` and accept `onClick` because `<Popover.Trigger>` clones it). `<ColorPicker.Trigger>` renders nothing itself; it is a marker child that `<ColorPicker>` reads from its `children`, so it only has meaning inside `<ColorPicker>`.
79
+ - **Field-ready.** `<Field label>` connects `id`, naming, description, and invalid state to either the default or custom trigger rather than the role-less picker wrapper. `required` remains a visible Field marker; native trigger buttons do not expose `aria-required` because that state is unsupported for buttons.
80
+ - **`onChange` fires per drag/zoom tick (high frequency).** Use `onChangeEnd` for commit-style logic (network calls, history snapshots) — it fires on pointer release, slider release, HEX input blur, and preset click.
81
+ - **Presets via `presets?: string[]`.** Invalid entries are dropped silently. The library doesn't ship a default palette — pass your own brand colors. Selected swatch gets an inset ring + check overlay.
82
+ - **Color math is exported.** `hexToHsv(hex)`, `hsvToHex({h,s,v})`, `normalizeHex(loose)` are usable directly for downstream theme builders, contrast calculators, etc.
83
+ - **Keyboard (SV pad)**: arrows ±1% S/V, Shift+arrow ±10%, Home/End for S=0/100, PageUp/Down for V=100/0.
84
+ - **Keyboard (hue slider)**: inherits Slider's keyboard — arrows ±1°, PgUp/Dn ±10°, Home/End for 0°/360°.
85
+ - **Popover placement** via `popoverPlacement?: 'bottom-start' | 'bottom' | 'top-start' | ...`. Default `'bottom-start'`.
86
+ - **Disabled** dims the panel, sets `aria-disabled` on the SV pad, disables the slider + input, makes presets non-interactive. Trigger doesn't open.
87
+ - **`panelFooter?: ReactNode`** — rendered inside the popover below the panel (and below presets). For live feedback about the color being picked, e.g. a contrast-ratio readout that updates as the user drags. Not available on the standalone `<ColorPicker.Panel>` (no popover to render it inside). Not an `aria-live` region by default — if the text should be announced as it changes, wrap it in your own `role="status"` span; announcing every drag tick would be disruptive by default. It IS the popover dialog's `aria-describedby`, so it's read once when the dialog opens.
88
+ - **Accessible names.** Under `<Field label>` / `aria-labelledby` the default trigger's name is the label plus the current value ("Accent colour #0052CC"). An explicit `aria-label` on the default trigger also gets the value appended ("Accent colour, current value #0052CC"). The popover dialog is named by the trigger's purpose (Field label / `aria-label` / `triggerLabel`), no value — don't add your own `Popover.Heading` via `panelFooter` to name it.
89
+ - **`<ColorPickerPanel>` (`<ColorPicker.Panel>`) takes `framed?: boolean`, default `true`.** `framed={false}` drops the panel's own chrome (border, shadow, padding, background, radius) — use it when nesting the panel inside something that already draws a frame (your own `Popover.Content`, a `Card`). `<ColorPicker>` renders its popover panel with `framed={false}` internally so the popover shows exactly one frame; a standalone `<ColorPicker.Panel>` keeps its frame by default.
90
+ - **`invalid` now paints the default trigger's border AND its focus ring**, not just `aria-invalid` — `.trigger[aria-invalid=true]` uses the same danger primitive as `Input invalid` for both: the border (`--color-picker-trigger-border-color-invalid`, same primitive as `--input-border-color-invalid`, and it survives `:hover`) and the `:focus-visible` ring (`--color-picker-trigger-ring-invalid`, same primitive as `--input-ring-invalid`, both `var(--ring-danger)`) — each reached through ColorPicker's own component token, never a direct `--input-*` read.
91
+
92
+ #### Color math API
93
+
94
+ ```ts
95
+ import { hexToHsv, hsvToHex, normalizeHex } from '@eocrm/design-system';
96
+
97
+ normalizeHex('#fff'); // '#FFFFFF'
98
+ normalizeHex('orange'); // null
99
+
100
+ hexToHsv('#FF0000'); // { h: 0, s: 100, v: 100 }
101
+ hexToHsv('not a color'); // null
102
+
103
+ hsvToHex({ h: 240, s: 100, v: 100 }); // '#0000FF'
104
+ ```
105
+
106
+ #### Hard rule
107
+
108
+ - ❌ Passing non-HEX `value` — named colors, `rgb()`, `hsl()`, alpha hex (`#RRGGBBAA`). Convert in the consumer or use the exported `normalizeHex` first. Invalid input falls back to `#000000` with a dev-only warning.
109
+ - ❌ Using `<ColorPicker.Trigger>` outside `<ColorPicker>`.
110
+ - ❌ Reaching into the picker's internal HSV state. Consumer contract is HEX-only.
111
+ - ❌ Hand-rolling a color picker per page. Use this.
112
+ - ❌ Bundling a default palette inside the consumer. Pass via `presets`.
113
+ - ❌ Calling expensive work in `onChange`. Use `onChangeEnd` (one fire per gesture).
114
+ - ❌ Wrapping a non-`forwardRef` component in `<ColorPicker.Trigger asChild>`. `<Popover.Trigger>` clones the child to inject the ref; non-forwardRef silently drops it.
115
+ - ❌ Forgetting to wire `disabled` into the consumer's custom trigger element. The picker dims its wrapper and blocks pointer events (`pointer-events: none`), but the trigger button's own disabled visuals are the consumer's responsibility.
@@ -0,0 +1,70 @@
1
+ # `<ConfirmationPopover>` — opinionated "Are you sure?" preset
2
+
3
+ ```tsx
4
+ <ConfirmationPopover
5
+ title="Delete record?"
6
+ description="This action cannot be undone."
7
+ confirmLabel="Delete"
8
+ variant="danger"
9
+ onConfirm={async () => {
10
+ await api.deleteRecord(id);
11
+ }}
12
+ >
13
+ <Button variant="danger">Delete</Button>
14
+ </ConfirmationPopover>
15
+
16
+ // Default variant: lighter-weight (archive, publish, etc.)
17
+ <ConfirmationPopover
18
+ title="Archive this contact?"
19
+ description="You can unarchive later from the archive view."
20
+ onConfirm={() => archive(id)}
21
+ >
22
+ <Button variant="secondary">Archive</Button>
23
+ </ConfirmationPopover>
24
+ ```
25
+
26
+ <!-- props:start -->
27
+
28
+ ## Props
29
+
30
+ <!-- prettier-ignore -->
31
+ | Prop | Type | Required | Description |
32
+ |---|---|---|---|
33
+ | `children` | `ReactElement<unknown, string \| JSXElementConstructor<any>>` | yes | The trigger element. Same forwardRef-required contract as `<Popover.Trigger>` — `<Button>` qualifies; a custom component without `forwardRef` does not. |
34
+ | `title` | `string` | yes | Heading text. Renders inside `<Popover.Heading>` (an `<h3>`) and wires `aria-labelledby` on the dialog automatically. |
35
+ | `description` | `ReactNode` | no | Optional body text below the title. When provided, wires `aria-describedby` so screen readers announce it. |
36
+ | `confirmLabel` | `string` | no | Confirm button label. Defaults to the i18n value at `confirmationPopover.confirm` (`'Confirm'` in English). An EMPTY string counts as unset, not as an explicit blank: this label is the confirm button's only name source (the pending spinner beside it is `aria-hidden`), so an empty one would leave the button anonymous. |
37
+ | `variant` | `'default' \| 'danger'` | no | `'danger'` makes Confirm a danger-variant button. Defaults to `'default'` (primary). |
38
+ | `onConfirm` | `() => void \| Promise<void>` | yes | Async-aware confirm handler. May return a Promise; while pending, both buttons disable, the Confirm button shows a small spinner, and Escape / click-outside dismissal is blocked. - Resolve → popover closes. - Reject → popover stays open, buttons re-enable. `onCancel` is NOT fired (the user neither confirmed nor cancelled — it's an error state owned by the consumer). The consumer is expected to surface error feedback externally (toast, inline message, etc.). ConfirmationPopover does NOT render errors. |
39
+ | `onCancel` | `(() => void)` | no | Optional. Fires on Cancel click, Escape, or click-outside dismissal. NOT fired if `onConfirm` rejects. |
40
+ | `initialFocusRef` | `RefObject<HTMLElement \| null>` | no | Direct initial focus into the panel's content instead of the default Cancel button — e.g. an `<Input>` rendered in `description` for a rename flow. When provided and its `.current` is non-null on open, the component focuses this element after the panel mounts (skipping the Cancel-focus). Tip: add `onFocus={(e) => e.currentTarget.select()}` to a text input to select its contents so the user can type/replace immediately. |
41
+ | `returnFocusRef` | `RefObject<HTMLElement \| null>` | no | Where focus goes when the popover closes. Default: back to the trigger. That default breaks whenever the trigger is gone by close time — the confirmed action deleted the row that owned it — and focus lands on `<body>`, so a keyboard user loses their place. The ref is read **at close time**, not at open time, so it may be pointed at whatever still exists once the work is done — the next row's trigger, the empty state's first button. If it is empty or its element has left the document, focus falls back to the trigger (when it still exists). It applies when the popover closes via Confirm, Cancel or Escape. An outside click never restores focus — focus stays wherever the click put it (on a control, or `<body>` for an inert area). A ref that is set statically (not only inside `onConfirm`) ALSO fires when the user closes by clicking the trigger again, pulling focus off the trigger. To return to the trigger on Cancel / toggle and only move elsewhere after a confirm, aim the ref inside `onConfirm` and clear it in `onOpenChange(true)`. If focus is already on some other live element when the popover closes, it is left alone. The target is scrolled into view with `{ block: 'nearest' }` (a no-op when it is already visible) — it may be far from where the user was. |
42
+ | `side` | `'left' \| 'right' \| 'top' \| 'bottom'` | no | Preferred side. Default `'top'` — confirmations anchor above the trigger by convention. |
43
+ | `align` | `'start' \| 'end' \| 'center'` | no | Edge alignment. Default `'center'`. |
44
+ | `sideOffset` | `number` | no | Gap in px between trigger and panel. Default `10`. |
45
+ | `open` | `boolean` | no | Controlled open state. Pair with `onOpenChange`. |
46
+ | `onOpenChange` | `((open: boolean) => void)` | no | Open-change callback. Required when `open` is provided. |
47
+ | `defaultOpen` | `boolean` | no | Default open state for uncontrolled usage. Defaults to `false`. |
48
+
49
+ <!-- props:end -->
50
+
51
+ - Built on top of `<Popover>`. Declarative: `title` / `description` / `confirmLabel` / `cancelLabel` / `variant` / `onConfirm` / `onCancel`.
52
+ - **Initial focus on Cancel** for both variants — keyboard Enter never accidentally confirms. Tab once to Confirm.
53
+ - **`initialFocusRef`** (`RefObject<HTMLElement | null>`) overrides the Cancel default: directs initial focus into the `description` content instead — e.g. an `<Input>` rendered there for a rename flow. The component focuses `initialFocusRef.current` after the panel mounts (mirrors `<Modal>`'s `initialFocusRef`). Tip: add `onFocus={(e) => e.currentTarget.select()}` to a text input so its contents are selected on open and the user can type a replacement immediately.
54
+ - **Async-aware** `onConfirm`. May return a Promise. While pending, both buttons take `aria-disabled` (NOT the native `disabled`, which would drop them from the tab order and blow away focus mid-operation), their handlers no-op, Confirm shows a spinner, the pending state is announced, and Escape / click-outside are blocked.
55
+ - **Failure mode**: on reject, popover stays open and buttons re-enable. Consumer surfaces the error externally — ConfirmationPopover does NOT render inline errors.
56
+ - **Return focus** (`returnFocusRef`): on Confirm, Cancel and Escape focus returns to `returnFocusRef` when it is connected, otherwise to the trigger. Unlike `<Modal>`, an outside click never restores focus — it stays wherever the user clicked. `returnFocusRef` is read at CLOSE time. A statically-set ref also fires when the user closes by clicking the trigger again; to apply it only after a successful confirm, set it in `onConfirm` and clear it in `onOpenChange(true)`. A named target is scrolled into view with `{ block: 'nearest' }`.
57
+ - Anchors above the trigger by default (`side="top"`).
58
+ - **From a DropdownMenu item (kebab Delete pattern).** Wrap a `<DropdownMenu.Item closeOnSelect={false}>` as the trigger — clicking anywhere on the row opens the confirmation. The menu stays open until the user dismisses it (Escape or click outside). To close the menu after the action resolves, drive `DropdownMenu`'s `open` state externally and call `setMenuOpen(false)` inside `onConfirm` — and pass `returnFocusRef={kebabTriggerRef}` (the menu's trigger), because closing the menu unmounts the item that is the popover's trigger, so focus would otherwise drop to `<body>`.
59
+
60
+ #### When NOT to use
61
+
62
+ - ❌ A multi-step flow ("type the name to confirm") → `Modal`. This is for one-tap confirmations.
63
+ - ❌ A non-blocking heads-up that needs no yes/no answer → a Toast or inline UI.
64
+
65
+ #### Anti-patterns
66
+
67
+ - ❌ A hanging-forever `onConfirm` Promise. There is no timeout; the popover stays pending indefinitely, so add a timeout / abort inside your `onConfirm` if the operation may stall.
68
+ - ❌ Expecting the rejection to render inside the popover body. Surface errors via toast or page-level UI.
69
+ - ❌ Controlled `open` while relying on pending-blocks-close. With `open` / `onOpenChange` you can force-close from outside while pending; coordinate `pending` in your own code if that matters.
70
+ - ❌ Letting a confirmed delete remove the trigger with no `returnFocusRef`: focus drops to `<body>`. Aim the ref at the next row's trigger (or the empty state) inside `onConfirm`.
@@ -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
+ ```