@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,72 @@
1
+ # `<Breadcrumb>` — navigation trail
2
+
3
+ Compound (Breadcrumb.Item) navigation breadcrumb. Last child is auto-marked as the current page (`<span aria-current="page">`); non-last items are muted Links. Default separator is a ChevronRight icon.
4
+
5
+ ```tsx
6
+ import { Breadcrumb, Link } from '@eocrm/design-system';
7
+ import { Link as RouterLink } from 'react-router-dom';
8
+
9
+ <Breadcrumb>
10
+ <Breadcrumb.Item as={RouterLink} to="/mockups">Mockups</Breadcrumb.Item>
11
+ <Breadcrumb.Item as={RouterLink} to="/mockups/contacts">Contacts</Breadcrumb.Item>
12
+ <Breadcrumb.Item>Acme Corp</Breadcrumb.Item> {/* auto-current */}
13
+ </Breadcrumb>
14
+
15
+ // Custom separator
16
+ <Breadcrumb separator={<Slash size={12} />}>
17
+ <Breadcrumb.Item as={RouterLink} to="/a">A</Breadcrumb.Item>
18
+ <Breadcrumb.Item>B</Breadcrumb.Item>
19
+ </Breadcrumb>
20
+
21
+ // External crumb (default <a>)
22
+ <Breadcrumb>
23
+ <Breadcrumb.Item href="https://docs.example.com">Docs</Breadcrumb.Item>
24
+ <Breadcrumb.Item>This page</Breadcrumb.Item>
25
+ </Breadcrumb>
26
+ ```
27
+
28
+ <!-- props:start -->
29
+
30
+ ## Props
31
+
32
+ ### `BreadcrumbProps`
33
+
34
+ <!-- prettier-ignore -->
35
+ | Prop | Type | Required | Description |
36
+ |---|---|---|---|
37
+ | `children` | `ReactNode` | yes | One or more `<Breadcrumb.Item>` children. The component injects the separator between items and auto-marks the last child as current (renders as `<span aria-current="page">` instead of a link). |
38
+ | `separator` | `ReactNode` | no | Custom separator between items. Defaults to a small `<ChevronRight>` lucide icon. The separator renders inside a `<span aria-hidden="true">` wrapper automatically. |
39
+ | `ariaLabel` | `string` | no | Visible label for the `<nav>` element. Defaults to the i18n value at `breadcrumb.ariaLabel` (`'Breadcrumb'` in English) when omitted OR empty — an empty string is not an explicit name, so it takes the default too. Override when multiple breadcrumb instances coexist on the same page. |
40
+ | `className` | `string` | no | Pass-through className applied to the `<nav>` wrapper. |
41
+
42
+ ### `BreadcrumbItemProps`
43
+
44
+ <!-- prettier-ignore -->
45
+ | Prop | Type | Required | Description |
46
+ |---|---|---|---|
47
+ | `as` | `ElementType` | no | |
48
+ | `current` | `boolean` | no | Mark this item as the current page. Forced to `true` automatically for the last child of `<Breadcrumb>` (auto-current). When `true`, the item renders as `<span aria-current="page">` and ignores all link-related props (`as`, `to`, `href`, etc.). |
49
+ | `children` | `ReactNode` | no | |
50
+ | `className` | `string` | no | |
51
+ | …native | | | plus native attributes of the `as` element (default `<a>`) |
52
+
53
+ <!-- props:end -->
54
+
55
+ - **Compound API** — wrap each crumb in `<Breadcrumb.Item>`.
56
+ - **Auto-current** — last child gets `aria-current="page"` and renders as `<span>`. Override with explicit `current` prop.
57
+ - **Item is polymorphic** — same `as` pattern as Link. It is not `forwardRef`-wrapped because the return shape varies (`<span>` for current, `<Link>` for non-current); for a ref to a specific crumb, render the underlying link manually inside an Item, or use Link directly.
58
+ - Separated by a customizable icon in an `<ol>` inside the `<nav>`.
59
+ - **Default separator** is `<ChevronRight size={14} />`. Override via the `separator` prop.
60
+ - **`<nav aria-label="Breadcrumb">` wrapper** — semantic landmark, AT-friendly.
61
+
62
+ #### When NOT to use
63
+
64
+ - ❌ Horizontal nav of equal-importance siblings → `<Tabs>` or `<ButtonGroup>`.
65
+ - ❌ Step-by-step progress → a dedicated Stepper (not shipped).
66
+ - ❌ Single-page apps with no parent hierarchy — omit Breadcrumb entirely.
67
+
68
+ #### Anti-patterns
69
+
70
+ - ❌ Making the current page clickable. Current items are non-link by design.
71
+ - ❌ Long trails (5+ levels) — wrap and become illegible.
72
+ - ❌ Building your own `<nav>` + chevron pattern. Use Breadcrumb.
@@ -0,0 +1,107 @@
1
+ # `<Button>` — action triggers
2
+
3
+ ```tsx
4
+ <Button onClick={save}>Save</Button>
5
+ <Button variant="danger" size="sm">Delete</Button>
6
+ <Button variant="secondary" disabled>Cancel</Button>
7
+ <Button
8
+ variant="secondary"
9
+ size="sm"
10
+ selected={ownerApplied}
11
+ aria-pressed={ownerApplied}
12
+ onClick={() => setOwnerApplied((value) => !value)}
13
+ >
14
+ Owner: {ownerLabel}
15
+ </Button>
16
+
17
+ // Icon-only square button (20×20 at xs, 32×32 at md); aria-label is the accessible name
18
+ <Button size="xs" variant="ghost" iconOnly aria-label="Remove">
19
+ <X size={12} />
20
+ </Button>
21
+
22
+ // Destination that must look like a button: a real <a>; rel="noreferrer" belongs with target="_blank"
23
+ <Button as="a" href={idpConsoleUrl} target="_blank" rel="noreferrer" variant="secondary">
24
+ Open identity console
25
+ </Button>
26
+
27
+ // Form footer
28
+ <Cluster justify="end" gap="sm">
29
+ <Button variant="secondary">Cancel</Button>
30
+ <Button type="submit">Save</Button>
31
+ </Cluster>
32
+
33
+ // Status quick actions painted like the status pill they set. `noShow` / `completed`
34
+ // are your status records, each with a `color: PaletteColor` that also feeds the
35
+ // PillMenuOption, so a tenant recolouring a status recolours its button too.
36
+ <Cluster gap="sm">
37
+ <PillMenu current={current} options={statuses} onSelect={setStatusId} />
38
+ <Button size="sm" color={noShow.color} onClick={() => setStatusId(noShow.id)}>No show</Button>
39
+ <Button size="sm" color={completed.color} onClick={() => setStatusId(completed.id)}>Completed</Button>
40
+ </Cluster>
41
+ ```
42
+
43
+ <!-- props:start -->
44
+
45
+ ## Props
46
+
47
+ <!-- prettier-ignore -->
48
+ | Prop | Type | Required | Description |
49
+ |---|---|---|---|
50
+ | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'danger-outline' \| 'success'` | no | Visual variant. - `primary` (default) — the section's main action. Use **one** per page section. - `secondary` — supporting actions like "Cancel", "Export", "Filter". - `ghost` — tertiary actions in dense UIs (toolbar buttons, row actions). - `danger` — destructive operations only (Delete, Revoke, Remove). Pair with a confirmation if irreversible. - `danger-outline` — a destructive action that must not dominate: surface fill, danger text and border. For a Remove repeated on every row, or a destructive action beside a primary one. Use filled `danger` for the confirm step itself. - `success` — **transient confirmation only**, not an initial state. Flip to `success` for ~1.5s after an action resolves (Save → "Saved!"), then flip back. Never render a button as `success` on mount — it has no action-intent meaning, only post-action feedback. See the `@example` below for the timer pattern. |
51
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | no | Control height (matches the shared `--size-*` scale used by Input and Avatar). - `xs` (20px) — icon-only or very dense inline actions (row controls, chip-adjacent buttons). Pass `aria-label` when icon-only. Below WCAG 2.5.5 Level AAA touch-target guidance; reserve for desktop-first surfaces. - `sm` (24px) — dense toolbars, tables, inline actions. - `md` (32px, default) — most contexts. - `lg` (40px) — marketing-style empty states or emphasized primary actions. |
52
+ | `iconOnly` | `boolean` | no | Render the button as a square icon-only target — `aspect-ratio` is forced to 1 so width tracks the size's `height` token (`xs` → 20×20, `sm` → 24×24, `md` → 32×32, `lg` → 40×40) and `padding` is tightened to a small inset (4px) so the icon has breathing room without changing the outer shape. **Always pass `aria-label`** when `iconOnly` is set, otherwise the button has no accessible name. Pass a single icon as `children`. Use for inline density (row controls, chip-adjacent actions, toolbar affordances). For an icon + short text label, leave `iconOnly` off — the button will lay out as a normal rectangle with the existing gap. |
53
+ | `selected` | `boolean` | no | Controlled persistent paint for an applied filter or toolbar value. Selected paint applies only to `secondary` and `ghost` Buttons; `primary`, `danger`, and `success` retain their intent paint. This prop is visual only and does not add toggle-button semantics. Pass native `aria-pressed` explicitly only when activating the Button itself toggles the selected state; menu and disclosure triggers keep their own semantics. The consumer owns the state. Not for transient success feedback or for mutually exclusive `<ButtonGroup>` choices. Defaults to `undefined` (not selected). |
54
+ | `color` | `PaletteColor` | no | Paint the button with a palette color's soft pair (`--color-palette-<color>-bg` fill, `-fg` text) — the same pair a palette-colored `<PillMenu>` or `<Badge color>` uses, in both themes. For a quick action that moves a record to a status and must look like that status's pill (amber "No show" beside an amber status PillMenu). Not a decorative stand-in for `danger`/`success`: palette colors carry no meaning. When set it wins over `variant` and `selected` (like `<Badge color>` over `tone`). Hover/pressed darken via `filter: brightness()`. Defaults to `undefined` (use `variant`). |
55
+ | `as` | `ElementType` | no | Render a different element — the case that matters is `as="a"` with `href`, for a link that must LOOK like a button (an external console, a download, an IdP hand-off). The element named here is what actually renders, and its own attributes are typed: `href` is REQUIRED when `as="a"` (an anchor without one is neither focusable nor a link) and rejected otherwise; `target`/`rel`/`download` come through. Never navigate from `onClick`. Reach for `<Link>` first. `<Link>` is link-SHAPED navigation — inline text in a sentence, a table cell, a breadcrumb. `<Button as="a">` is for a destination that sits in a row of buttons and must carry their weight. Either way the element is a real anchor, so assistive tech announces a link and the browser gives middle-click, "open in new tab", and the status bar preview — none of which a `<button onClick={() => navigate()}>` has. `type="button"` is emitted only for a real `<button>`; an anchor never gets it. Everything else — variant, size, `iconOnly`, `selected`, the focus ring — is unchanged. Default: `'button'`. |
56
+ | …native | | | plus native attributes of the `as` element (default `<button>`) |
57
+
58
+ <!-- props:end -->
59
+
60
+ - Always renders `<button type="button">` unless you pass `type="submit"` — or unless you pass `as`. It won't submit ancestor forms by default.
61
+ - `aria-disabled="true"` keeps an unavailable action focusable (so keyboard users can discover it and its explanation) with the unavailable visual treatment, but does not set native `disabled` or prevent events: the consumer's handler must suppress activation while it is unavailable.
62
+ - `variant="success"` is a **transient confirmation state**, not an action intent. Flip to it for ~1.5s after the action resolves, then flip back to `primary`. The timer is the consumer's responsibility — Button stays stateless. Never render a button as `success` on initial mount. Track the timer in a `useRef` and clear on unmount + on rapid re-clicks so the flash doesn't outlive the component or get cut short.
63
+
64
+ ```tsx
65
+ const [saved, setSaved] = useState(false);
66
+ const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
67
+ useEffect(
68
+ () => () => {
69
+ if (timerRef.current) clearTimeout(timerRef.current);
70
+ },
71
+ [],
72
+ );
73
+ const handleSave = async () => {
74
+ await save();
75
+ if (timerRef.current) clearTimeout(timerRef.current);
76
+ setSaved(true);
77
+ timerRef.current = setTimeout(() => setSaved(false), 1500);
78
+ };
79
+ <Button variant={saved ? 'success' : 'primary'} onClick={handleSave}>
80
+ {saved ? 'Saved!' : 'Save'}
81
+ </Button>;
82
+ ```
83
+
84
+ #### When NOT to use
85
+
86
+ - ❌ Navigation in running text, a table cell, or a breadcrumb → `<Link>`.
87
+ - ❌ Toggle state (on/off) → `Switch` or `Checkbox`, not a Button with internal state.
88
+ - ❌ Mutually exclusive choices → `<ButtonGroup>`, which supplies the group-level selection semantics.
89
+ - ❌ A clickable table row → make the row itself the interactive surface; don't nest a button.
90
+ - ❌ Decorative color for an ordinary action → `variant`. `color` is only for an action that must match a palette-colored `<PillMenu>` / `<Badge color>` (a status or category it sets); resolve it from the same source as that pill so a recolored status carries its button along.
91
+ - On touch-first surfaces prefer `size="sm"` or larger: `xs` (20px×~28px, or 20×20 with `iconOnly`) is below WCAG 2.5.5 Level AAA touch-target guidance (24×24); acceptable here because the CRM is desktop-first.
92
+
93
+ #### Anti-patterns
94
+
95
+ - ❌ Two `variant="primary"` Buttons in the same section. Pick one; others are `secondary`.
96
+ - ❌ `<Button style={{ marginLeft: 'auto' }}>` — wrap in `<Cluster justify="end">` (or `justify="between"` with a sibling) instead.
97
+ - ❌ Overriding padding/height via `className`. A different visual size is a missing variant: request it.
98
+ - ❌ `variant="ghost"` for the page's primary action. Users won't discover it.
99
+ - ❌ `<Button variant="success">Save</Button>` on initial mount. Start as `primary` and flip to `success` after the action resolves.
100
+ - ❌ `<Button color="red">Delete</Button>` or `color="green"` for a confirm. Palette colors carry no meaning; destructive is `variant="danger"`, post-action feedback is `variant="success"`.
101
+ - ❌ `<Button color="amber" variant="secondary">`. `color` wins over `variant` (and `selected`), so the `variant` is dead code — pass one or the other.
102
+ - ❌ `size="xs"` for the primary or most prominent action. `xs` is for inline density, not emphasis; reach for `md` or `lg`.
103
+ - ❌ `<Button iconOnly><X /></Button>` without `aria-label`: screen readers announce nothing.
104
+ - ❌ Assuming `selected` adds toggle semantics. It is paint only; pass `aria-pressed` explicitly when activating the Button toggles that state, and not on menu or disclosure triggers.
105
+ - ❌ Assuming `aria-disabled="true"` blocks activation. It preserves native focusability and pointer events; guard your handler.
106
+ - ❌ `<Button onClick={() => (window.location.href = url)}>` for navigation: it announces as a button, with no middle-click, no open-in-new-tab and no status-bar preview. Use `<Button as="a" href={url}>`.
107
+ - ❌ `<Button as="a">` with no `href`, for a click handler you wanted to look like a link. An anchor without one is neither focusable nor activatable; the type requires `href` whenever `as="a"`, so this does not compile.
@@ -0,0 +1,78 @@
1
+ # `<ButtonGroup>` — joined Buttons + segmented control
2
+
3
+ ```tsx
4
+ // Visual mode — joined Buttons, no shared state.
5
+ <ButtonGroup aria-label="Edit actions">
6
+ <Button>Cut</Button>
7
+ <Button>Copy</Button>
8
+ <Button>Paste</Button>
9
+ </ButtonGroup>
10
+
11
+ // Segmented mode — single-select toggle group.
12
+ <ButtonGroup value={view} onValueChange={setView} aria-label="View mode">
13
+ <ButtonGroup.Item value="grid">Grid</ButtonGroup.Item>
14
+ <ButtonGroup.Item value="list">List</ButtonGroup.Item>
15
+ <ButtonGroup.Item value="calendar">Calendar</ButtonGroup.Item>
16
+ </ButtonGroup>
17
+
18
+ // Size propagation: group-level size flows to children, per-child override wins
19
+ <ButtonGroup size="sm">
20
+ <Button>Cut</Button>
21
+ <Button>Copy</Button>
22
+ <Button size="md">Paste</Button>
23
+ </ButtonGroup>
24
+ ```
25
+
26
+ <!-- props:start -->
27
+
28
+ ## Props
29
+
30
+ ### `ButtonGroupProps`
31
+
32
+ <!-- prettier-ignore -->
33
+ | Prop | Type | Required | Description |
34
+ |---|---|---|---|
35
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | no | Size propagated to children. Per-child `size` (Button or Item) wins when explicitly set. In visual mode this happens via cloneElement on Button children. In segmented mode, `<ButtonGroup.Item>` reads from context. |
36
+ | `disabled` | `boolean` | no | Disabled state for the whole group. In segmented mode this is authoritative (all items become aria-disabled, clicks no-op). In visual mode this is a no-op — pass `disabled` per `<Button>` instead. |
37
+ | `invalid` | `boolean` | no | Segmented mode: `aria-invalid` on the radiogroup. Visual mode: consumed and ignored. Field / SettingRow inject it — it used to leak onto the group div as a stray attribute. Default: `false`. |
38
+ | `required` | `boolean` | no | Segmented mode: `aria-required` on the radiogroup. Visual mode: consumed and ignored. Field / SettingRow inject it. Default: `false`. |
39
+ | `className` | `string` | no | |
40
+ | `style` | `CSSProperties` | no | |
41
+ | `value` | `string` | no | Visual mode marker. Never set; absence flips to visual. |
42
+ | `onValueChange` | `(next: string) => void` | no | Fired when a different Item is selected. Consumers wanting literal-union narrowing can cast the setter: `onValueChange={(v) => setView(v as 'grid' \| 'list')}`. |
43
+ | `aria-label` | `string` | no | Accessible name for the group landmark. Optional but recommended. |
44
+ | …native | | | plus native HTML attributes |
45
+
46
+ ### `ButtonGroupItemProps`
47
+
48
+ <!-- prettier-ignore -->
49
+ | Prop | Type | Required | Description |
50
+ |---|---|---|---|
51
+ | `value` | `string` | yes | Value emitted to `onValueChange` when this item is selected. |
52
+ | `disabled` | `boolean` | no | Per-item disabled. Group-level disabled is OR-merged. |
53
+ | `className` | `string` | no | className merges onto the rendered <button>. |
54
+ | `aria-label` | `string` | no | Accessible name for the radio, when the visible text is an abbreviation (`S` / `M` / `L` → "Small tiles"). Start it with the visible text where you can ("S, small tiles") so voice-control users can say what they see (WCAG 2.5.3). Omit it when `children` already reads as a full name. |
55
+ | `aria-describedby` | `string` | no | id(s) of element(s) describing the option — forwarded to the radio. |
56
+ | `children` | `ReactNode` | yes | |
57
+
58
+ <!-- props:end -->
59
+
60
+ - **Mode detection** is by props: with `value` + `onValueChange` you get segmented; without, you get visual joining. Visual mode joins `<Button>` children with shared borders and outer-only rounded corners (toolbar action groups); segmented mode is a single-select radiogroup (view-mode toggles, timeframe filters). A discriminated union enforces "`value` AND `onValueChange` together OR neither".
61
+ - **`<ButtonGroup.Item>`** (segmented only) renders `<button role="radio">` with roving tabindex and `aria-checked` driven by the parent's `value`. Using it in visual mode (no `value` on the parent) throws at render time: it has no group to belong to, by design.
62
+ - **Abbreviated options** (`S` / `M` / `L`) take `aria-label` on the Item, forwarded to the radio: `<ButtonGroup.Item value="s" aria-label="S, small tiles">S</ButtonGroup.Item>`. Start the name with the visible text (WCAG 2.5.3); don't hide the letter and add visually-hidden text instead. `aria-describedby` is forwarded too.
63
+ - **Children differ by mode.** Visual: `<Button>` children. Segmented: `<ButtonGroup.Item>` children. Mixing the two is undefined behavior.
64
+ - **Size propagation** — `size` on the group propagates to children. Per-child override wins.
65
+ - **Segmented height = Button height** — the segmented TRACK (not each item) is the `--size-*` height, so a `size="md"` segmented control lines up with a `size="md"` Button. Items render at that height minus the track padding on both sides.
66
+ - **Keyboard nav (segmented only)** — Arrow keys move selection + focus; Home / End jump to ends; Tab moves IN/OUT of the group on the currently-selected item. Disabled items are skipped.
67
+ - **ARIA** — visual mode is `role="group"`; segmented mode is `role="radiogroup"` (requires `aria-label`).
68
+
69
+ **Anti-patterns:**
70
+
71
+ - ❌ Mixing visual `<Button>` children with `<ButtonGroup.Item>` in the same ButtonGroup — undefined behavior.
72
+ - ❌ Using ButtonGroup as a routing tab strip. That's what `<Tabs>` is for.
73
+ - ❌ Passing only `value` (no `onValueChange`) or only `onValueChange` (no `value`) — a type error, and broken at runtime too.
74
+ - ❌ Wrapping a `<ButtonGroup.Item>` in a user component. The parent focuses items on Arrow nav, which depends on them being direct children.
75
+ - ❌ Using it for non-button content groupings. Use `<Cluster>` or `<Stack>`.
76
+ - ❌ Multi-select via clever workarounds. Compose Checkboxes for that.
77
+
78
+ **See also:** `<Tabs>` for routing-style content switching, `<Radio>` for vertical radio lists.
@@ -0,0 +1,158 @@
1
+ # `<Calendar>` — month / week / day / agenda views
2
+
3
+ ```tsx
4
+ // Uncontrolled
5
+ <Calendar events={events} defaultView="week" />;
6
+
7
+ // Controlled cursor + view
8
+ const [cursor, setCursor] = useState(new Date());
9
+ const [view, setView] = useState<CalendarView>('month');
10
+ <Calendar
11
+ value={cursor}
12
+ onChange={setCursor}
13
+ view={view}
14
+ onViewChange={setView}
15
+ events={events}
16
+ onEventClick={(e) => openDetail(e)}
17
+ />;
18
+ ```
19
+
20
+ <!-- props:start -->
21
+
22
+ ## Props
23
+
24
+ <!-- prettier-ignore -->
25
+ | Prop | Type | Required | Description |
26
+ |---|---|---|---|
27
+ | `events` | `readonly CalendarEvent[]` | no | Events to display. |
28
+ | `view` | `'month' \| 'week' \| 'day' \| 'agenda'` | no | Active view (controlled). Pair with `onViewChange`. |
29
+ | `defaultView` | `'month' \| 'week' \| 'day' \| 'agenda'` | no | Initial view (uncontrolled). Defaults to `'month'`. |
30
+ | `onViewChange` | `((view: CalendarView) => void)` | no | Fires when the user clicks the view switcher. |
31
+ | `value` | `Date` | no | Navigation cursor (controlled). |
32
+ | `defaultValue` | `Date` | no | Initial cursor (uncontrolled). Defaults to `new Date()`. |
33
+ | `onChange` | `((date: Date) => void)` | no | Fires on prev/next/today/keyboard navigation. |
34
+ | `onDayClick` | `((date: Date) => void)` | no | Fires when the user clicks a day cell's empty space. - Month view: empty space in a day cell, the "+N more" overflow chip, or keyboard activation (Enter/Space) on a focused cell. - Week/Day view: empty hour-grid space inside that day's column — **mouse click only**. There is no keyboard equivalent in v3; consumers needing keyboard activation in week/day should surface their detail UI through the focusable event chips (which fire `onEventClick`). |
35
+ | `onEventClick` | `((event: CalendarEvent) => void)` | no | Fires when the user clicks an event chip. |
36
+ | `locale` | `string` | no | Override locale. Defaults to `useLocale()`. |
37
+ | `weekStartsOn` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6` | no | Override locale-derived first day of week. |
38
+ | `maxLanesPerWeek` | `number` | no | Lane cap per week (month view). Default 3. Events beyond it collapse into a "+N more" chip; clicking it fires `onDayClick(date)`. |
39
+ | `hourRange` | `[number, number]` | no | Hour range shown in week/day views (inclusive start, exclusive end). Defaults to `[7, 19]` (7am–7pm). Hours outside this range are NOT rendered (no row in the grid). |
40
+ | `hourRowHeight` | `number` | no | Pixel height per hour row in week/day views. Default 48. |
41
+ | `resources` | `readonly CalendarResource[]` | no | Split `view="day"` into one column per bookable subject — practitioner, chair, room, bay — all sharing a single time axis and a single scroll container. This is the "resource day view" of scheduling products. Events are routed by `CalendarEvent.resourceId`. A timed event whose `resourceId` matches nothing (or is absent) lands in a trailing "unassigned" column, which is only rendered when such an event exists. All-day events without a `resourceId` are day-wide and span every column. Ignored by month, week and agenda views — those have their own column meaning. Don't approximate it with N side-by-side `<Calendar view="day">` in a `Split`: each brings its own header, gutter and scroll, so they drift. |
42
+ | `backgroundIntervals` | `readonly CalendarBackgroundInterval[]` | no | Availability underlay for week/day views: non-interactive bands painted behind the events, distinguishing "closed" from "open and free". "Open and busy" already reads from the event blocks themselves. An interval list rather than a weekly-hours object, because working hours vary by day (a lunch break), by date (a holiday, a short day) and by column (per-practitioner shifts). Bands take no part in the event collision cascade and never intercept clicks — `onDayClick` still fires through them. Every interval is clipped to each column's own date, so a week view needs one interval per day rather than one that all seven columns share. |
43
+ | `onEventMove` | `((event: CalendarEvent, next: CalendarEventMove) => CalendarDropResult)` | no | Enables drag-to-reschedule in week/day views. Called on drop with the proposed placement; the event's duration is preserved. **Nothing moves until you commit it.** `events` stays the source of truth — apply the change to your own state to make it stick. To refuse a drop (the server rejects overlaps, out-of-hours bookings, …) return `false`, or a promise that resolves `false` or rejects: the block snaps back and the preview is discarded. Prefer `canDropEvent` for rules you can evaluate synchronously — it refuses the drop *during* the drag, so the user sees it before releasing. Omit to keep today's read-only behaviour. |
44
+ | `onEventResize` | `((event: CalendarEvent, next: CalendarEventResize) => CalendarDropResult)` | no | Enables drag-to-resize in week/day views (a handle on the block's bottom edge). `startsAt` is unchanged; only `endsAt` moves. Same commit and rejection semantics as `onEventMove`. |
45
+ | `canDropEvent` | `((event: CalendarEvent, next: CalendarDropCandidate) => boolean)` | no | Synchronous veto, evaluated continuously while dragging. Return `false` and the placement renders as a refused drop and is never proposed to `onEventMove` / `onEventResize`. Use for rules you can check locally (opening hours, overlaps within the loaded event set); use the handler's own return value for rules only the server can settle. `next.mode` says which gesture is being judged, and narrows the payload: `'move'` carries the target `resourceId`, `'resize'` cannot change the column so it doesn't. Rules like "shortening is always fine, relocating needs approval" are otherwise inexpressible — the predicate fires while the pointer is still at the origin, where both gestures report the event's own start. Note that `backgroundIntervals` does NOT gate drops. Shading a slot closed is presentation; enforcing it is this predicate's job. Derive both from one source so they cannot drift. |
46
+ | `dragSnapMinutes` | `number` | no | Snap granularity for drags, in minutes. Default 15 — a drag lands on a quarter-hour boundary rather than an arbitrary pixel offset. Also the step size for the keyboard equivalent (Alt + arrow keys). Values below 1 (including 0 and negatives) are treated as 1 minute. |
47
+ | `renderEvent` | `RenderEvent` | no | Optional custom renderer for the inner content of every event chip across views (month chips, week/day timed blocks, all-day band chips). The returned ReactNode replaces the default `<time> · <title>` markup inside the chip's button wrapper — the wrapper still handles tone background, click, tooltip, and (for timed blocks) absolute positioning. To override colors, return content with inline styling that fills the wrapper (e.g., `position: absolute; inset: 0; background: <color>`). The `ctx` argument carries view-aware metadata: `view`, `asAllDay`, `continuesLeft`/`continuesRight` (multi-day), `timeLabel`, `duration`. |
48
+ | …native | | | plus native `<div>` attributes |
49
+
50
+ <!-- props:end -->
51
+
52
+ - Four views: `'month'` (continuous event bars across the grid), `'week'` (7 columns × hour rows + all-day band), `'day'` (single column × hour rows), `'agenda'` (chronological list of the cursor's current week, grouped by day with empty days hidden).
53
+ - Events are `{ id, title, startsAt, endsAt?, tone?, color?, allDay?, resourceId? }`. Multi-day events render as continuous bars in both the month grid and the week/day all-day band. `resourceId` routes a timed event to its column in the resource day view and is ignored by every other view.
54
+ - **Two colour axes, and they do not compete.** `tone` is _semantic_ — what STATE the event is in: `neutral` (default) / `accent` / `success` / `warning` / `danger`. `color` is _identity_ — WHICH category it belongs to, as one of the 30 `PaletteColor`s. Use `color` when your events belong to a colour-bearing category the tenant chose (an appointment type, a calendar, a resource class).
55
+ - With **no** `color`, tone paints the whole block exactly as it always has, and `allDay: true` renders as a tone-filled band (no time prefix). With `color` set, `color` takes the fill (palette tint background, saturated palette colour for text and border) and a non-`neutral` `tone` moves to a saturated stripe down the event's **leading edge** — so a category-coloured event can still show a state that must not be missed. There is no precedence rule to remember because the axes occupy different pixels.
56
+
57
+ ```tsx
58
+ // Category only — a clean single colour.
59
+ { id: '1', title: 'Consultation', startsAt, color: 'violet' }
60
+ // Category AND state — violet block, danger stripe. Both readable.
61
+ { id: '2', title: 'Consultation', startsAt, color: 'violet', tone: 'danger' }
62
+ ```
63
+
64
+ Don't map categories onto tones instead: tones are semantic and finite, two categories would collide on one tone, and the result is wrong in both directions — a `danger` chip that is merely a category, and a genuinely urgent event that looks like one.
65
+
66
+ - **This is the opposite of `Badge`**, where `color` takes precedence over `tone` and the tone is discarded. Calendar renders both, because a calendar tone can carry states closer to safety than decoration (a masked hour, a released slot) and dropping one would make a free hour read as a booked one. Don't carry the Badge rule across.
67
+ - **Both axes are visual only** — neither sets ARIA, and a 3px band is not an accessible signal (same contract as `Badge`). If a state must reach assistive tech, keep it in the event `title`. And pick category colours that contrast with the tones you use — measured RGB distance between the band colour and the category's own saturated colour — grouped by tone and ordered within each group: `success` + `mint` (11) / `emerald` (15) / `teal` (35) / `green` (41); `danger` + `red` (17) / `coral` (44); `warning` + `orange` (16) / `coral` (25) / `red` (43) / `amber` (44); `accent` + `blue` (40). Read it as a threshold, not a ranking. The worst pair is `success` + `mint` at 11, and anything under ~20 is effectively invisible at the rendered 4px (a 3px band plus the 1px border in the same colour; the agenda row has no border, so 3px there); the low 20s are detectable side-by-side but unreliable alone, and the low 40s are where this list stops rather than where the problem does. These moved (`success` + `mint` 18 → 11, `danger` + `red` 36 → 17) when those tones were raised to clear WCAG AA; `Calendar.collisions.test.ts` recomputes the list from the shipped tokens. Nothing enforces this — keep the state in the title too when a tenant's category colour collides.
68
+
69
+ - In the **agenda** view the row is never filled (a tint would clash with the today-group accent and the hover background), so `color` sets the leading dot and `tone` still gets the edge stripe.
70
+ - A coloured **all-day** chip uses the same palette tint as a timed one rather than the tone-filled treatment: the palette ships a `bg`/`fg` pair, and a filled variant would mean inventing 30 more tokens and asserting contrast at 12px for each. **The visible consequence:** a coloured all-day event renders at _timed-chip weight_ — same tint, same border, only the time prefix missing — so in a band that mixes coloured and uncoloured all-day events, the coloured ones read lighter. Colour the whole category or none of it if that bothers you.
71
+ - On a multi-day bar the band repeats on **every** segment, including ones that continue from a previous week. It marks the event's state, not its start.
72
+ - Controlled cursor via `value` / `onChange`, or uncontrolled via `defaultValue`. Controlled view via `view` / `onViewChange`, or uncontrolled via `defaultView`.
73
+ - Overlapping timed events in week/day views render as a Google-Calendar-style cascade: each lane is offset to the right by a small constant step but every block extends to the column's right edge, with later lanes overlaying earlier ones via `z-index`. Hovering or keyboard-focusing a block lifts it to full width on top of all neighbours. A horizontal "now" line marks the current time in today's column.
74
+ - Locale-aware via `useLocale()`; override with `locale` prop. UI strings (`today`, `viewMonth`, etc.) come from the i18n provider (`useTranslation`) — override them with `<I18nProvider overrides={{ calendar: { today: '…' } }}>`. There is no `labels` prop. For Russian copy and dates: `<I18nProvider locale="ru"><Calendar locale="ru-RU" … /></I18nProvider>`.
75
+ - Read-mostly **by default**: `onDayClick` and `onEventClick` callbacks; opt into editing by wiring `onEventMove` / `onEventResize` (see _Drag to move and resize_ below). `onDayClick` fires across all views — month-cell click, "+N more" chip, keyboard activation (Enter/Space) on a focused cell, and (in week/day views) clicks on the empty hour-grid space of a day column. No built-in popover or modal — wire your own detail UI.
76
+ - ARIA: month view is `role="grid" aria-readonly="true"`; arrow keys move focus, PageUp/PageDown navigates months, Enter/Space calls `onDayClick`. Week/day views are also `role="grid"` with `role="row"` + `role="columnheader"` headers and standard sequential tab order for event blocks — `aria-readonly="true"` there too, until a drag handler is wired (see below). Agenda view exposes the visible week as `role="list"` with each day group as a `role="listitem"` and the day label as an `<h3>` heading inside — screen readers announce the date grouping before reading each event row. **Known v3 gap:** in week/day views, `onDayClick` on empty hour-grid space is **mouse-only** (no keyboard equivalent). Consumers needing keyboard activation should drive their detail UI through the focusable event chips via `onEventClick`.
77
+
78
+ #### Resource columns — one day, N lanes
79
+
80
+ ```tsx
81
+ <Calendar
82
+ view="day"
83
+ events={appointments} // each carries resourceId
84
+ resources={[
85
+ { id: 'ana', label: 'Ana' },
86
+ { id: 'ben', label: 'Ben' },
87
+ ]}
88
+ />
89
+ ```
90
+
91
+ - Routing is by `CalendarEvent.resourceId`. A **timed** event whose `resourceId` matches nothing (or is absent) lands in a trailing **Unassigned** column, which is only rendered when at least one such event exists. An **all-day** event with no `resourceId` is day-wide and spans every column; with one, it pins to that column.
92
+ - Two bookings at the same hour in _different_ columns are not a collision — each takes lane 0 and full column width. The cascade still applies within one column.
93
+ - Month, week and agenda views ignore `resources` — their columns already mean something else.
94
+
95
+ #### Availability underlay — shade closed time, tint free time
96
+
97
+ ```tsx
98
+ <Calendar
99
+ view="day"
100
+ events={appointments}
101
+ resources={resources}
102
+ backgroundIntervals={[
103
+ { startsAt: at(7, 0), endsAt: at(9, 0), resourceId: 'ana', tone: 'unavailable' },
104
+ { startsAt: at(9, 0), endsAt: at(17, 0), resourceId: 'ana', tone: 'available' },
105
+ ]}
106
+ />
107
+ ```
108
+
109
+ - A booking calendar has three states and `hourRange` alone expresses none of them: **closed** (rendered but greyed), **busy** (an event covers it — already works), **free** (clickable). `backgroundIntervals` paints the first and third behind the events.
110
+ - An interval list, not a weekly-hours object, because working hours vary by day (a lunch break), by date (a holiday, a short day) and by column (per-practitioner shifts).
111
+ - `tone`: `'unavailable'` (default) shades; `'available'` tints. `resourceId` restricts the band to one resource column and is ignored in week view (and in a resource-less day view).
112
+ - **Intervals are always clipped to each column's own date**, `resourceId` or not. Shading 08:00–09:00 across a week takes seven intervals, one per day — a single interval does not span the columns.
113
+ - Bands render beneath events, take no part in the collision cascade, are `aria-hidden`, and are `pointer-events: none` — `onDayClick` still fires through them. Intervals are clipped to each column's day and to `hourRange`; ones that fall entirely outside are dropped.
114
+ - Don't fake this with all-day events — that pollutes the `events` array you also read back.
115
+ - **The underlay is paint, not policy.** Bands never gate drops — `backgroundIntervals` and `canDropEvent` are independent, and shading a slot closed does not stop a drag landing in it. A screen that shades shifts _and_ enables drag must express the same rule twice: once as intervals to draw it, once in `canDropEvent` to enforce it. Derive both from one source so they cannot drift.
116
+
117
+ #### Drag to move and resize
118
+
119
+ ```tsx
120
+ <Calendar
121
+ view="day"
122
+ events={appointments}
123
+ resources={resources}
124
+ dragSnapMinutes={15}
125
+ canDropEvent={(ev, next) => isWithinOpeningHours(next)}
126
+ onEventMove={async (ev, next) => {
127
+ const ok = await api.reschedule(ev.id, next);
128
+ if (!ok) return false; // rejected → the block snaps back
129
+ setAppointments((prev) => applyMove(prev, ev.id, next));
130
+ }}
131
+ onEventResize={(ev, next) => setAppointments((p) => applyResize(p, ev.id, next))}
132
+ />
133
+ ```
134
+
135
+ - Both handlers are optional and additive — omit them and the calendar behaves exactly as before (read-only). `onEventMove` makes blocks draggable; `onEventResize` adds a handle on the block's bottom edge.
136
+ - **A drop is proposed, never applied.** `events` stays the source of truth: commit the change to your own state or the block snaps back. `next` is `{ startsAt, endsAt, resourceId? }` for a move (duration preserved; `resourceId` is the column it landed on) and `{ startsAt, endsAt }` for a resize (`startsAt` unchanged).
137
+ - **Two ways to refuse a drop.** `canDropEvent` is a synchronous predicate evaluated _continuously during_ the drag — the placement renders as refused for as long as the pointer rests on it, and never reaches the handler. Its `next.mode` says which gesture is being judged and narrows the payload (`'move'` carries the target `resourceId`; `'resize'` can't change the column, so it doesn't), which is what makes rules like "shortening is fine, relocating needs approval" expressible. The handler itself can return `false`, or a promise resolving `false` or rejecting, for rules only the server can settle; that verdict is announced in the live region rather than styled (the gesture is over by then), and the preview is held until the promise settles so an accepted drop doesn't flash back mid-request.
138
+ - Dragging sideways crosses columns: another weekday in week view, another resource lane in the resource day view.
139
+ - **Keyboard equivalent**, so rescheduling isn't mouse-only: on a focused block, `Alt`+`↑`/`↓` moves by one snap step, `Alt`+`←`/`→` moves a column, `Alt`+`Shift`+`↑`/`↓` changes the end time. Every block carries the full shortcut list as its `aria-describedby` description — it has to live on the blocks, since `role="grid"` here is not focusable and a description there would never be announced — and an assertive live region names the event and reports each proposed slot, each refusal, and each gesture that was already at the edge of what the bounds allow. With a drag handler wired, the grid drops `aria-readonly`.
140
+ - **Bounds.** One rule governs both gestures: **the allowed range always contains where the event already is**, so a bound can refuse to move something further but never moves it the opposite way. Within that, a move keeps the start inside the visible `hourRange` — an unclamped upward drag would project into the previous calendar day — while the end runs past it freely, so an overnight booking keeps its duration; and a resize may grow or shrink the event by at most a day per gesture — the bound is on the CHANGE, not the absolute duration, so a multi-day booking stays adjustable — which lets an event be extended past midnight while stopping a runaway pointer delta rolling through whole dates. An event that already starts before `hourRange` (its block renders clipped at the top) is _not_ pulled into the window.
141
+ - A gesture the bounds refuse outright proposes nothing: the handler is not called (it is typically an API write) and the live region says the event cannot move further.
142
+ - Every time comes from the `CalendarEvent`, never from the rendered block — the layout clips a block that ends on a later day, so it is shorter than the event it represents.
143
+ - **A move preserves ELAPSED duration**, not the row count. The two differ only on a daylight-saving day, where the grid necessarily draws wall-clock rows (01:00–05:00 occupies four rows though three hours pass) while a booking is its real duration — a 30-minute appointment takes 30 real minutes on any day of the year. This is also why a drop onto the skipped hour can't come back zero-length.
144
+ - **Known gaps.** `onDayClick` still reports only a date, so in a resource day view it cannot say which column a free slot belongs to. After a keyboard column move, the block re-parents into the new column and loses focus, so nudges can't be chained. `touch-action: none` on a movable block means a touch that starts on an event drags it rather than scrolling the grid. Resource columns are `1fr` with no minimum width, so a dozen lanes squash rather than scroll — the all-day band lays itself out separately and would drift out of alignment if only the hour grid could scroll.
145
+ - The click that terminates a drag is swallowed, so `onEventClick` doesn't fire on a reschedule. A plain click still opens your detail UI.
146
+ - Drag-to-**create** (dragging empty grid space to draft a new event) is still out of scope — use `onDayClick` plus your own form.
147
+
148
+ #### When NOT to use
149
+
150
+ - ❌ Single-date or date-range selection → `<DatePicker>` / `<DateRangePicker>`.
151
+ - ❌ Drag-to-create (see above).
152
+
153
+ #### Anti-patterns
154
+
155
+ - ❌ Mounting `<Calendar>` with no `events` AND no `onDayClick`: the grid is fully inert.
156
+ - ❌ Pre-grouping events by day in the consumer. Pass the flat array; the layout algorithms group and lane internally.
157
+ - ❌ Treating `onEventMove` as the thing that moves the event. It proposes; your state disposes, and not committing means the block snaps back.
158
+ - ❌ Faking the availability underlay with all-day events, or approximating resource columns with N side-by-side day calendars (see above). Use `backgroundIntervals` and `resources`.
@@ -0,0 +1,165 @@
1
+ # `<Card>` — bordered container
2
+
3
+ - `fill` makes the Card fill a definite-height parent (`height: 100%`) and
4
+ applies `min-width: 0` so it can shrink inside narrow Grid, Sortable, and
5
+ DashboardCanvas cells. When a direct `Card.Body` is present, it also creates
6
+ Card's internal column/min-height chain. It does not create a height by
7
+ itself; bound the parent (for example with `Constrain height`) when needed.
8
+
9
+ ```tsx
10
+ <Card padding="md">
11
+ <Stack gap="md">...</Stack>
12
+ </Card>
13
+
14
+ // Tone-coded stat card — 3px left-edge stripe in the tone color:
15
+ <Card padding="md" tone="accent">Open deals</Card>
16
+ ```
17
+
18
+ <!-- props:start -->
19
+
20
+ ## Props
21
+
22
+ ### `CardProps`
23
+
24
+ <!-- prettier-ignore -->
25
+ | Prop | Type | Required | Description |
26
+ |---|---|---|---|
27
+ | `padding` | `'none' \| 'sm' \| 'md' \| 'lg'` | no | Inner padding. - `none` — use when the card contains a table or list that should bleed edge-to-edge; inner sections manage their own padding. - `sm` (12px) — dense info cards. - `md` (16px) — default for plain-content cards. - `lg` (24px) — emphasis cards, marketing-style panels. When omitted, defaults to `'md'` for plain content, or `'none'` when the card contains compound subcomponents (`Card.Header` / `Card.Body` / `Card.List` / `Card.ListRow`) so its sections bleed to the card edge automatically. Pass an explicit value to override the auto-detect. **Detection is shallow:** only direct children are inspected. Fragments (`<>...</>`) are transparent — the detection recurses into them, so conditional renders that wrap compound children in a Fragment still trigger the auto-detect. But wrapping a `Card.Header` in any other element (`<div>`, `<Stack>`, etc.) defeats the heuristic — pass `padding="none"` explicitly in that case. |
28
+ | `tone` | `'accent' \| 'info' \| 'success' \| 'warning' \| 'danger'` | no | Optional left-edge tone stripe (3px). Useful for "stat card" / "status card" patterns where one card in a row needs visual emphasis. Default: no stripe (the card keeps its standard bordered look). Uses the same tone vocabulary as `Alert`: `accent` / `info` / `success` / `warning` / `danger`. |
29
+ | `overflow` | `'hidden' \| 'visible'` | no | How the card clips its children at the rounded border. - `hidden` (default) — children are clipped to the rounded border. This prevents the visible seam that appears at the corners when a child has square corners (Table's internal scroll wrapper, images, full-bleed media). Overlays in this library (DropdownMenu, Tooltip, Popover, Drawer, Modal) portal to `document.body` and are NOT clipped by this. Focus rings are NOT exempt: an `outline` is clipped by an ancestor's overflow, so a focusable flush against the card edge loses that band — draw its ring inset by passing `$offset: calc(-1 * var(--ring-offset))` to the `focus-ring` mixin, not a separate `outline-offset` after the `@include` (a `structure.test.ts` gate fails the build on that shape). - `visible` — opt out of clipping. Use when a direct child needs to overhang the card edge — decorative badges that protrude from a corner, hover-lift transforms whose shadow extends past the card border, etc. |
30
+ | `fill` | `boolean` | no | Fill the containing block's height and allow the Card to shrink within a narrow grid cell. Use in stretched Grid, Sortable, or DashboardCanvas cells whose wrapper already has a definite height. When a direct `Card.Body` child is present, `fill` also establishes Card's internal column and minimum-height chain; add `scroll` to the Body to keep a sibling Header fixed above a scrolling content region. Defaults to `false`. |
31
+ | …native | | | plus native `<div>` attributes |
32
+
33
+ ### `CardBodyProps`
34
+
35
+ <!-- prettier-ignore -->
36
+ | Prop | Type | Required | Description |
37
+ |---|---|---|---|
38
+ | `scroll` | `boolean` | no | Makes the body the flexible vertical scroll region of a `fill` Card while sibling `Card.Header` content stays fixed. The Card's parent must provide a definite height. Defaults to `false`. |
39
+ | …native | | | plus native `<div>` attributes |
40
+
41
+ ### `CardHeaderProps`
42
+
43
+ <!-- prettier-ignore -->
44
+ | Prop | Type | Required | Description |
45
+ |---|---|---|---|
46
+ | `headerLevel` | `'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6'` | no | Heading level for the title text. Defaults to `'h3'` (assumes the page has an h1/h2 above). Override when this section sits beneath an h1 directly (`headerLevel="h2"`) or further nested (`headerLevel="h4"`). |
47
+ | `surface` | `'default' \| 'subtle'` | no | `'subtle'` paints the header on a tinted (sunken) surface, for a nested editable sub-section inside a `Card.Body` (e.g. a condition group). Defaults to `'default'`. |
48
+ | `controls` | `ReactNode` | no | Optional interactive slot right after the title (e.g. a `ButtonGroup` mode switch). Rendered outside the heading, so it is not part of the heading's name. Order: title, controls, meta, action. Controls never shrink: on a wide header the title ellipsizes down to a short minimum width; on a narrow header (under ~360px of content) the controls wrap onto a second row under the title, which keeps the first row with meta and action. Keep titles short, or pass a `title` attribute for long ones. |
49
+ | `action` | `ReactNode` | no | Optional right-aligned slot — typically a `<Link>` or `<Button>` that lets the user navigate to a full list or take a section-level action. Rendered inside a `<span>` that never shrinks or wraps (flex-shrink: 0; with `meta` or `controls`, min-width: max-content). Beside `controls` it is the removal/section action of a nested sub-group (e.g. a ghost delete button), right-aligned after any meta. |
50
+ | `meta` | `ReactNode` | no | Optional secondary, non-interactive text beside the title — freshness ("Updated 3 minutes ago") or status. Muted and single-line; sits just before `action` and is the first thing to give way at narrow widths: it truncates with an ellipsis before the title gives up any width, while `action` keeps its width. In a `fill` Card (which needs a parent of definite width) it is also visually hidden, still read by screen readers, once only a sliver would show. Not part of the heading's name. Put controls in `controls` or `action`, never here. `false` and `''` count as no meta. |
51
+ | `children` | `ReactNode` | yes | Title content. Becomes the inner text of the heading element. Typically a plain string, but can contain inline elements if needed. |
52
+ | …native | | | plus native `<div>` attributes |
53
+
54
+ ### `CardListProps`
55
+
56
+ <!-- prettier-ignore -->
57
+ | Prop | Type | Required | Description |
58
+ |---|---|---|---|
59
+ | `children` | `ReactNode` | yes | Row items — typically `<Card.ListRow>` elements. |
60
+ | …native | | | plus native `<ul>` attributes |
61
+
62
+ ### `CardListRowProps`
63
+
64
+ <!-- prettier-ignore -->
65
+ | Prop | Type | Required | Description |
66
+ |---|---|---|---|
67
+ | `children` | `ReactNode` | yes | Row content — typically a `<Stack>` or `<Cluster>` of text and metadata. |
68
+ | …native | | | plus native `<li>` attributes |
69
+
70
+ <!-- props:end -->
71
+
72
+ ```tsx
73
+ // Fixed header + scrolling body in a definite-height dashboard cell.
74
+ <Constrain height="sm">
75
+ <Card fill>
76
+ <Card.Header>Pipeline</Card.Header>
77
+ <Card.Body scroll>
78
+ <Stack gap="sm">...</Stack>
79
+ </Card.Body>
80
+ </Card>
81
+ </Constrain>
82
+ ```
83
+
84
+ ```tsx
85
+ // Compound API — section card with header + list (Dashboard's "Deals needing attention" pattern).
86
+ // No `padding` prop needed — Card auto-detects compound children and defaults to padding="none".
87
+ <Card>
88
+ <Card.Header
89
+ action={
90
+ <Link as={RouterLink} to="/deals">
91
+ View all
92
+ </Link>
93
+ }
94
+ >
95
+ Deals needing attention
96
+ </Card.Header>
97
+ <Card.List>
98
+ {deals.map((d) => (
99
+ <Card.ListRow key={d.id}>
100
+ <Stack gap="xs">
101
+ <span>{d.title}</span>
102
+ <span>{d.company}</span>
103
+ </Stack>
104
+ <Avatar name={d.owner} size="sm" />
105
+ </Card.ListRow>
106
+ ))}
107
+ </Card.List>
108
+ </Card>
109
+ ```
110
+
111
+ - **Compound API** — `Card.Header` / `Card.Body` / `Card.List` / `Card.ListRow` for section-card patterns. Drop `padding="none"` — the parent Card auto-detects compound children.
112
+ - `Card.Header`: title row (`h3` by default, override via `headerLevel`) with optional right-aligned `action` slot and bottom-border separator. Optional `meta` is muted secondary text (freshness, status) just before `action`; at narrow widths it truncates before the title shrinks (in a `fill` Card it then hides visually, staying readable by screen readers), and `action` never shrinks. Keep controls out of `meta`. With `controls` the order is title · controls … meta · action: controls and `action` never shrink, meta truncates first, and `action` stays right-aligned.
113
+ - With `controls`, the title stays on one line. On a wide header it ellipsizes down to a short minimum width rather than pushing the controls out; on a narrow header (under ~360px of content) the controls wrap onto a second row under the title, and the first row keeps title · meta · action. For long titles beside `controls`, pass a `title` attribute so the full text stays reachable (`<Card.Header controls={…}><span title={name}>{name}</span></Card.Header>`), or keep titles short.
114
+ - `Card.Body`: padded `<div>` content section. Add `scroll` beneath a Header in a `fill` Card to make Body the flexible vertical scroll region while Header stays fixed. Card intentionally owns this layout because it relates only its own compound pieces; the parent still owns the Card's definite outer height. `scroll` also sets `tabIndex={0}`, because a scroll container with no focusable descendant is unreachable by keyboard (axe `scrollable-region-focusable`) — pair it with `role="group"` and an `aria-label` when the content is worth naming, and pass `tabIndex={-1}` to opt out if the body already contains something focusable.
115
+ - `Card.List`: semantic `<ul>` with list-reset styling — screen readers announce "list with N items".
116
+ - `Card.ListRow`: `<li>` with padded content and bottom dividing border; last-child border suppressed automatically.
117
+ - **Never nest Card in Card** — except an editable, repeatable sub-group (e.g. a condition group) inside a `Card.Body`, using `Card.Header surface="subtle"`; never for display-only content or as a layout wrapper. `controls` holds the sub-section's inline controls and `action` its remove button:
118
+
119
+ ```tsx
120
+ <Card>
121
+ <Card.Header>Rules</Card.Header>
122
+ <Card.Body>
123
+ <Card>
124
+ <Card.Header
125
+ surface="subtle"
126
+ controls={
127
+ <ButtonGroup value={mode} onValueChange={setMode} aria-label="Match">
128
+ <ButtonGroup.Item value="all">Match all</ButtonGroup.Item>
129
+ <ButtonGroup.Item value="any">Match any</ButtonGroup.Item>
130
+ </ButtonGroup>
131
+ }
132
+ action={
133
+ <Button iconOnly variant="ghost" aria-label="Delete group">
134
+ <X size={12} />
135
+ </Button>
136
+ }
137
+ >
138
+ Group
139
+ </Card.Header>
140
+ <Card.Body>…conditions…</Card.Body>
141
+ </Card>
142
+ </Card.Body>
143
+ </Card>
144
+ ```
145
+
146
+ - `Card.Header` sits flush with the card edge inside `<Card padding="none">`. It renders a `<div>` holding the heading element plus an optional `<span>` wrapping `action` (with `meta`, a muted `<span>` between them and the header switches to a grid). With `controls`, the header is an inline-size container holding one inner `<div>` grid of four items — heading · controls `<span>` · meta (or an empty spacer) · action (or an empty placeholder) — so `action` stays right-aligned; a container query moves the controls to a second row when the header is narrow. The containment means a controls header contributes no intrinsic width, so give its Card a definite width (any block parent does). Under an `h1` with no `h2` above, pass `headerLevel="h2"`.
147
+ - `Card.List` / `Card.ListRow`: row dividers use a `:last-child` selector to suppress the final bottom border. Fragments are transparent, but wrapping rows in an extra `<div>` or other element breaks the match and leaves a stray divider on the last row. Render rows as direct children (or via `.map`).
148
+ - `Card.Body` keeps `scroll` for a bounded `fill` Card (Grid, Sortable or DashboardCanvas cell); for page-level scrolling let the page or `AppLayout` own the scroll area. Keep it a direct child of Card (Fragments are transparent) so Card can detect the compound structure.
149
+
150
+ #### When NOT to use
151
+
152
+ - ❌ Inside another Card, except the editable sub-group exception above (`Card.Header surface="subtle"` in a `Card.Body`). Never as the only child of another Card, or as a layout primitive (use `Stack` / `Cluster` / `Grid`). Card is for semantic grouping.
153
+ - ❌ For every container. If the page looks like a deck of cards, nothing is visually grouped.
154
+ - ❌ `Card.Body` outside a Card. It owns padding and sizing only as part of Card's compound structure.
155
+
156
+ #### Anti-patterns
157
+
158
+ - ❌ `<Card style={{ padding: 20 }}>`: use `padding`. A missing value is a token/scale conversation.
159
+ - ❌ `<Card style={{ overflow: 'visible' }}>`: use `<Card overflow="visible">`.
160
+ - ❌ `<Card style={{ height: '100%' }}>`: use `<Card fill>`, which also applies the shrink-safe minimum width for narrow grid cells.
161
+ - ❌ Hand-rolling a flex column and scrolling body in a Card, or consumer CSS for `flex: 1`, `min-height: 0` or `overflow-y: auto`. Use `<Card fill>` with `<Card.Body scroll>`.
162
+ - ❌ Expecting `scroll` to create a height. The Card's parent must provide a definite height; `fill` carries that bound into the body.
163
+ - ❌ Hover shadows to make Cards "interactive". If the whole card is clickable, that's a different component (`LinkCard`).
164
+ - ❌ Hand-rolling a left stripe via `className` / `style`. Use `tone`; it reserves the border-left space so layout never shifts.
165
+ - ❌ Hand-rolling `.cardHeader` / `.list` / `.listRow` SCSS. Use the compound API.