@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,783 @@
1
+ import {
2
+ useCallback,
3
+ useEffect,
4
+ useRef,
5
+ useState,
6
+ type MutableRefObject,
7
+ type PointerEvent,
8
+ } from 'react';
9
+ import { startOfDay } from '../../calendar/dateMath';
10
+ import type {
11
+ CalendarDropCandidate,
12
+ CalendarDropResult,
13
+ CalendarEvent,
14
+ CalendarEventMove,
15
+ CalendarEventResize,
16
+ TimedEventBlock,
17
+ } from './types';
18
+ import type { HourGridColumnRef } from './utils';
19
+
20
+ /** Which gesture a drag represents. */
21
+ export type DragMode = 'move' | 'resize';
22
+
23
+ /**
24
+ * The live, uncommitted placement of the block being dragged.
25
+ *
26
+ * `startMinutes` / `endMinutes` are grid coordinates for rendering; `startsAt`
27
+ * / `endsAt` are the projected instants the consumer will be offered. They are
28
+ * computed together so the block's rendered position, its visible time label,
29
+ * and the payload can never disagree.
30
+ */
31
+ export interface DragPreview {
32
+ /** `CalendarEvent.id` of the block being dragged. */
33
+ eventId: string;
34
+ mode: DragMode;
35
+ /** Column the block currently hovers over — may differ from where it started. */
36
+ columnIndex: number;
37
+ /** Minutes from `hourRange[0] * 60`. May sit outside the visible window (see `project`). */
38
+ startMinutes: number;
39
+ /** Minutes from `hourRange[0] * 60`. May sit outside the visible window (see `project`). */
40
+ endMinutes: number;
41
+ /** Projected start instant — `startsAt` of the proposal. */
42
+ startsAt: Date;
43
+ /** Projected end instant — `endsAt` of the proposal. */
44
+ endsAt: Date;
45
+ /** `canDropEvent` refused this placement — styled as a refused drop while the pointer rests on it. */
46
+ invalid: boolean;
47
+ /** The bounds moved the requested value — the gesture asked to go further than it may. */
48
+ clamped: boolean;
49
+ }
50
+
51
+ /** Pixels the pointer must travel before a press becomes a drag rather than a click. */
52
+ const DRAG_THRESHOLD_PX = 3;
53
+
54
+ /**
55
+ * What the grid should announce in its live region. The hook reports the
56
+ * placement and the outcome; the caller owns the wording, because formatting a
57
+ * time is locale work and every user-facing string has to come from i18n.
58
+ */
59
+ export interface DragAnnouncement {
60
+ /** The event being dragged — every message names it, as the rest of the library's drag a11y does. */
61
+ event: CalendarEvent;
62
+ mode: DragMode;
63
+ startsAt: Date;
64
+ endsAt: Date;
65
+ /** The placement was refused — by `canDropEvent` mid-drag, or by the handler on drop. */
66
+ refused: boolean;
67
+ /** The gesture asked to go further than the grid allows, so nothing changed. */
68
+ atEdge: boolean;
69
+ /** The gesture ended exactly where it started — nothing refused it, it simply moved nothing. */
70
+ unchanged: boolean;
71
+ /** The gesture was abandoned (pointer cancelled, window blurred) and proposed nothing. */
72
+ cancelled: boolean;
73
+ /** Monotonic, so an identical message still re-announces. */
74
+ seq: number;
75
+ }
76
+
77
+ export interface UseEventDragArgs {
78
+ /** The grid's columns, in render order. */
79
+ columns: readonly HourGridColumnRef[];
80
+ /** Pixel height of one hour row — the px↔minutes conversion factor. */
81
+ hourRowHeight: number;
82
+ /** Inclusive start, exclusive end of the visible hour range. */
83
+ hourRange: readonly [number, number];
84
+ /** Snap granularity in minutes. Values below 1 are treated as 1. */
85
+ snapMinutes: number;
86
+ /** Live DOM nodes of the day columns, for pointer hit-testing. */
87
+ columnElements: MutableRefObject<(HTMLElement | null)[]>;
88
+ onEventMove?: (event: CalendarEvent, next: CalendarEventMove) => CalendarDropResult;
89
+ onEventResize?: (event: CalendarEvent, next: CalendarEventResize) => CalendarDropResult;
90
+ canDropEvent?: (event: CalendarEvent, next: CalendarDropCandidate) => boolean;
91
+ }
92
+
93
+ export interface UseEventDragResult {
94
+ /** The in-flight placement, or `null` when nothing is being dragged. */
95
+ preview: DragPreview | null;
96
+ /** Latest thing worth announcing, or `null` before any gesture. */
97
+ announcement: DragAnnouncement | null;
98
+ /** True while a drag gesture owns the pointer. */
99
+ dragging: boolean;
100
+ /** Whether this grid accepts move gestures at all. */
101
+ canMove: boolean;
102
+ /** Whether this grid accepts resize gestures at all. */
103
+ canResize: boolean;
104
+ /** Begin a pointer drag from a `pointerdown` on a block (or its resize handle). */
105
+ startPointerDrag: (block: TimedEventBlock, mode: DragMode, e: PointerEvent) => void;
106
+ /** Keyboard equivalent: nudge a block by whole snap steps and/or whole columns. */
107
+ nudge: (
108
+ block: TimedEventBlock,
109
+ delta: { mode: DragMode; steps: number; columns?: number },
110
+ ) => void;
111
+ /** True when the click that follows the drag we just finished must be swallowed. */
112
+ consumeClickSuppression: () => boolean;
113
+ /** Clear a stale suppression flag at the start of any fresh press. */
114
+ resetClickSuppression: () => void;
115
+ }
116
+
117
+ /**
118
+ * The gesture's semantic starting point, captured once when it begins.
119
+ *
120
+ * This exists to keep `TimedEventBlock` out of the projection entirely. A
121
+ * block carries *render* coordinates: `endMinutes` is clipped to the bottom of
122
+ * the column for anything ending on a later day (`layoutEventsForHourGrid`),
123
+ * and reading it for a semantic decision is what produced every drag bug this
124
+ * component has had — a truncated overnight booking, a reversed gesture, a
125
+ * no-op guard that could never match. The frame is derived from the
126
+ * `CalendarEvent`, so clipping cannot leak into a proposal.
127
+ *
128
+ * Invariant for everything below: the controller reads `frame`, never `block`.
129
+ */
130
+ interface DragFrame {
131
+ event: CalendarEvent;
132
+ /** Column the gesture started in. */
133
+ columnIndex: number;
134
+ /** Minutes from `hourRange[0] * 60` to the event's real start. May be negative. */
135
+ startMinutes: number;
136
+ /**
137
+ * Minutes from `hourRange[0] * 60` to the event's real end, in WALL-CLOCK
138
+ * minutes. Never clipped. This is grid geometry — it is what the block's
139
+ * height is drawn from and what the bounds and the no-op check compare.
140
+ */
141
+ endMinutes: number;
142
+ /**
143
+ * ELAPSED milliseconds between the event's start and end.
144
+ *
145
+ * Kept separately from the wall-clock span because on a daylight-saving day
146
+ * the two genuinely differ, and each is right for a different job: the grid
147
+ * draws wall-clock (01:00–05:00 occupies four rows even though only three
148
+ * hours pass), while a booking IS its elapsed time — a 30-minute
149
+ * appointment takes 30 real minutes on any day of the year. The proposal
150
+ * therefore preserves this, not the row count.
151
+ */
152
+ durationMs: number;
153
+ }
154
+
155
+ /** A Date on `day`'s calendar date, at `minutes` past local midnight. */
156
+ function dateAtMinutes(day: Date, minutes: number): Date {
157
+ const d = startOfDay(day);
158
+ // Wall-clock arithmetic, and it rolls past 24:00 into the next day — which
159
+ // is what an overnight booking needs.
160
+ d.setMinutes(d.getMinutes() + minutes);
161
+ return d;
162
+ }
163
+
164
+ /** Round to the nearest multiple of `snap` (always >= 1 so this can't divide by zero). */
165
+ function snapTo(minutes: number, snap: number): number {
166
+ return Math.round(minutes / snap) * snap;
167
+ }
168
+
169
+ function clamp(value: number, min: number, max: number): number {
170
+ return Math.min(Math.max(value, min), max);
171
+ }
172
+
173
+ /** Capture the semantic frame for a gesture on `block`. */
174
+ function frameOf(block: TimedEventBlock, baseMinutes: number): DragFrame {
175
+ const { event } = block;
176
+ const start = event.startsAt;
177
+ const startMinutes = start.getHours() * 60 + start.getMinutes() - baseMinutes;
178
+ const end = event.endsAt ?? event.startsAt;
179
+ // Wall-clock, NOT elapsed: `dateAtMinutes` projects in wall-clock minutes,
180
+ // so an elapsed-ms duration disagrees with it by an hour either side of a
181
+ // daylight-saving transition — proposing a resize that changes nothing, or
182
+ // a move that silently loses an hour.
183
+ const dayDiff = Math.round(
184
+ (startOfDay(end).getTime() - startOfDay(start).getTime()) / 86_400_000,
185
+ );
186
+ const startWall = start.getHours() * 60 + start.getMinutes();
187
+ const endWall = end.getHours() * 60 + end.getMinutes();
188
+ const wallMinutes = Math.max(0, dayDiff * 24 * 60 + (endWall - startWall));
189
+ return {
190
+ event,
191
+ columnIndex: block.dayIndex,
192
+ startMinutes,
193
+ endMinutes: startMinutes + wallMinutes,
194
+ durationMs: Math.max(0, end.getTime() - start.getTime()),
195
+ };
196
+ }
197
+
198
+ interface ProjectionConfig {
199
+ columns: readonly HourGridColumnRef[];
200
+ baseMinutes: number;
201
+ visibleMinutes: number;
202
+ snap: number;
203
+ }
204
+
205
+ /**
206
+ * Turn a raw target (in grid minutes) into a fully-resolved preview: snapped,
207
+ * bounded, and projected to real instants.
208
+ *
209
+ * **One invariant governs both bounds: the allowed range always contains the
210
+ * value the gesture started from.** That is what keeps a clamp honest — it can
211
+ * refuse to move further, but it can never move the event in the direction
212
+ * opposite to the one the user asked for. Without it, an event already sitting
213
+ * outside the window (clipped at the top of the grid, or ending after
214
+ * midnight) gets yanked *into* the window by a gesture that asked to push it
215
+ * further out.
216
+ *
217
+ * Within that invariant:
218
+ * - a move keeps the start inside the visible window, because an unclamped
219
+ * upward drag goes negative and projects back into the previous calendar
220
+ * day — a proposal for a date the pointer never visited. The end is free to
221
+ * fall outside; an overnight booking must keep its duration.
222
+ * - a resize may grow the event by at most a day per gesture, which stops a
223
+ * runaway pointer delta rolling through whole dates while leaving every
224
+ * duration — including a multi-day one — reachable.
225
+ */
226
+ function project(
227
+ frame: DragFrame,
228
+ mode: DragMode,
229
+ columnIndex: number,
230
+ target: number,
231
+ cfg: ProjectionConfig,
232
+ /** Skip snapping — the caller already decided the exact target (a pure column change). */
233
+ presnapped = false,
234
+ ): DragPreview {
235
+ const column = cfg.columns[columnIndex] ?? cfg.columns[frame.columnIndex];
236
+ const duration = frame.endMinutes - frame.startMinutes;
237
+
238
+ if (mode === 'move') {
239
+ const requested = presnapped ? target : snapTo(target, cfg.snap);
240
+ const startMinutes = clamp(
241
+ requested,
242
+ Math.min(0, frame.startMinutes),
243
+ Math.max(cfg.visibleMinutes - cfg.snap, frame.startMinutes),
244
+ );
245
+ const movedStart = dateAtMinutes(column.date, cfg.baseMinutes + startMinutes);
246
+ return {
247
+ eventId: frame.event.id,
248
+ mode,
249
+ columnIndex,
250
+ startMinutes,
251
+ endMinutes: startMinutes + duration,
252
+ clamped: startMinutes !== requested,
253
+ startsAt: movedStart,
254
+ // Offset from the projected START by the event's ELAPSED duration, not
255
+ // recomputed from midnight in wall-clock minutes. Recomputing collapses
256
+ // on a spring-forward day — 02:00 and 03:00 are the same instant, so a
257
+ // 60-minute booking dragged onto the skipped hour came back with
258
+ // `endsAt === startsAt`, a zero-length proposal.
259
+ endsAt: new Date(movedStart.getTime() + frame.durationMs),
260
+ invalid: false,
261
+ };
262
+ }
263
+
264
+ // Resize leaves the start alone — including when it sits above the visible
265
+ // window (an event that began before `hourRange`).
266
+ //
267
+ // The ceiling bounds the CHANGE (a day's growth per gesture), not the
268
+ // absolute duration. An absolute cap collapses onto the current end for
269
+ // anything already that long, which — combined with the no-op check in
270
+ // `commit` — silently swallows every attempt to lengthen a multi-day event.
271
+ const startMinutes = frame.startMinutes;
272
+ const requested = presnapped ? target : snapTo(target, cfg.snap);
273
+ const endMinutes = clamp(
274
+ requested,
275
+ // Symmetrical with the ceiling: a gesture may shrink by at most a day too,
276
+ // so a runaway delta can't collapse a three-day booking to 15 minutes.
277
+ Math.max(Math.min(startMinutes + cfg.snap, frame.endMinutes), frame.endMinutes - 24 * 60),
278
+ frame.endMinutes + 24 * 60,
279
+ );
280
+ return {
281
+ eventId: frame.event.id,
282
+ mode,
283
+ columnIndex,
284
+ startMinutes,
285
+ endMinutes,
286
+ clamped: endMinutes !== requested,
287
+ startsAt: frame.event.startsAt,
288
+ endsAt: dateAtMinutes(column.date, cfg.baseMinutes + endMinutes),
289
+ invalid: false,
290
+ };
291
+ }
292
+
293
+ /** Duck-typed thenable check — a consumer may return a non-native promise. */
294
+ function isThenable(value: unknown): value is Promise<void | boolean> {
295
+ return (
296
+ typeof value === 'object' &&
297
+ value !== null &&
298
+ typeof (value as { then?: unknown }).then === 'function'
299
+ );
300
+ }
301
+
302
+ /**
303
+ * Pointer + keyboard drag controller for the hour grid's timed blocks.
304
+ *
305
+ * Hand-rolled on pointer events rather than built on `@dnd-kit`: the gesture
306
+ * is a continuous px→minutes projection onto one shared time axis, not a
307
+ * sortable list reorder, so the sensor/collision machinery would be pure
308
+ * overhead here.
309
+ *
310
+ * The consumer stays the source of truth. A drop is *proposed*, never
311
+ * applied: `canDropEvent` vetoes it live during the gesture, and the preview
312
+ * renders refused for as long as the pointer sits on a refused slot.
313
+ * `onEventMove` / `onEventResize` can also veto on release, by returning
314
+ * `false` or a promise that resolves `false` or rejects; that verdict is
315
+ * announced in the live region rather than styled, because by then the
316
+ * gesture is over and the preview is being discarded either way. The block's
317
+ * resting position always comes from `events`, so an accepted drop only moves
318
+ * anything because the consumer commits it. Nothing here mutates the event.
319
+ */
320
+ export function useEventDrag({
321
+ columns,
322
+ hourRowHeight,
323
+ hourRange,
324
+ snapMinutes,
325
+ columnElements,
326
+ onEventMove,
327
+ onEventResize,
328
+ canDropEvent,
329
+ }: UseEventDragArgs): UseEventDragResult {
330
+ const [preview, setPreview] = useState<DragPreview | null>(null);
331
+ const [dragging, setDragging] = useState(false);
332
+ const [announcement, setAnnouncement] = useState<DragAnnouncement | null>(null);
333
+ const seqRef = useRef(0);
334
+
335
+ const announce = useCallback(
336
+ (
337
+ event: CalendarEvent,
338
+ p: DragPreview,
339
+ opts: { refused?: boolean; atEdge?: boolean; unchanged?: boolean; cancelled?: boolean } = {},
340
+ ) => {
341
+ seqRef.current += 1;
342
+ setAnnouncement({
343
+ event,
344
+ mode: p.mode,
345
+ startsAt: p.startsAt,
346
+ endsAt: p.endsAt,
347
+ refused: opts.refused ?? false,
348
+ atEdge: opts.atEdge ?? false,
349
+ unchanged: opts.unchanged ?? false,
350
+ cancelled: opts.cancelled ?? false,
351
+ seq: seqRef.current,
352
+ });
353
+ },
354
+ [],
355
+ );
356
+
357
+ const canMove = onEventMove !== undefined;
358
+ const canResize = onEventResize !== undefined;
359
+ const snap = Math.max(1, Math.round(snapMinutes));
360
+ const baseMinutes = hourRange[0] * 60;
361
+ const visibleMinutes = Math.max(0, (hourRange[1] - hourRange[0]) * 60);
362
+
363
+ // Mutable gesture bookkeeping. Kept in a ref (not state) so the window
364
+ // listeners below can be registered exactly once per gesture instead of
365
+ // re-subscribing on every pointermove.
366
+ const gestureRef = useRef<{
367
+ token: number;
368
+ frame: DragFrame;
369
+ mode: DragMode;
370
+ pointerId: number;
371
+ originX: number;
372
+ originY: number;
373
+ moved: boolean;
374
+ } | null>(null);
375
+ const previewRef = useRef<DragPreview | null>(null);
376
+ const suppressClickRef = useRef(false);
377
+ // Monotonic gesture id. A settling async commit from gesture N must not tear
378
+ // down gesture N+1 that the user has already started.
379
+ const tokenRef = useRef(0);
380
+
381
+ // Latest props, read by the window listeners without re-subscribing. Synced
382
+ // in an effect so the values the listeners see are always ones that actually
383
+ // committed.
384
+ const latest = useRef({
385
+ columns,
386
+ hourRowHeight,
387
+ baseMinutes,
388
+ visibleMinutes,
389
+ snap,
390
+ canDropEvent,
391
+ columnElements,
392
+ });
393
+ useEffect(() => {
394
+ latest.current = {
395
+ columns,
396
+ hourRowHeight,
397
+ baseMinutes,
398
+ visibleMinutes,
399
+ snap,
400
+ canDropEvent,
401
+ columnElements,
402
+ };
403
+ });
404
+
405
+ const setPreviewBoth = useCallback((next: DragPreview | null) => {
406
+ previewRef.current = next;
407
+ setPreview(next);
408
+ }, []);
409
+
410
+ /**
411
+ * Mark the click that follows a gesture as one to swallow.
412
+ *
413
+ * Only pointer-derived clicks ever consume this (see `HourGrid`): a keyboard
414
+ * activation produces a click with no preceding `pointerdown`, so nothing
415
+ * would reset the flag and a gesture abandoned without a pointerup would
416
+ * silently eat the user's next Enter press.
417
+ */
418
+ const armClickSuppression = useCallback(() => {
419
+ suppressClickRef.current = true;
420
+ }, []);
421
+
422
+ const cfg = useCallback(
423
+ (): ProjectionConfig => ({
424
+ columns: latest.current.columns,
425
+ baseMinutes: latest.current.baseMinutes,
426
+ visibleMinutes: latest.current.visibleMinutes,
427
+ snap: latest.current.snap,
428
+ }),
429
+ [],
430
+ );
431
+
432
+ const toPayload = useCallback((p: DragPreview): CalendarEventMove => {
433
+ const column = latest.current.columns[p.columnIndex];
434
+ return {
435
+ startsAt: p.startsAt,
436
+ endsAt: p.endsAt,
437
+ resourceId: column?.resourceId ?? undefined,
438
+ };
439
+ }, []);
440
+
441
+ const validate = useCallback(
442
+ (p: DragPreview, frame: DragFrame): boolean => {
443
+ const check = latest.current.canDropEvent;
444
+ if (!check) return true;
445
+ const move = toPayload(p);
446
+ // A resize can't change the column, so the candidate it offers doesn't
447
+ // carry a `resourceId` the consumer might read and act on.
448
+ const candidate: CalendarDropCandidate =
449
+ p.mode === 'move'
450
+ ? { mode: 'move', ...move }
451
+ : {
452
+ mode: 'resize',
453
+ startsAt: move.startsAt,
454
+ endsAt: move.endsAt,
455
+ // The lane it is in, not a lane it is moving to.
456
+ resourceId: move.resourceId,
457
+ };
458
+ return check(frame.event, candidate);
459
+ },
460
+ [toPayload],
461
+ );
462
+
463
+ /**
464
+ * End the live gesture. Always runs to completion for the gesture that owns
465
+ * the pointer — never token-guarded, because leaving `gestureRef` populated
466
+ * is what strands the hook: `dragging` stays true, the window listeners stay
467
+ * subscribed, and `nudge` refuses to start because it thinks a drag is live.
468
+ */
469
+ const endGesture = useCallback(() => {
470
+ gestureRef.current = null;
471
+ setDragging(false);
472
+ }, []);
473
+
474
+ /**
475
+ * Drop the preview — but only if a newer gesture has not already taken over.
476
+ * This IS token-guarded: a settling async commit from gesture N must not
477
+ * wipe the preview gesture N+1 is currently drawing.
478
+ */
479
+ const clearPreview = useCallback(
480
+ (token: number) => {
481
+ if (token !== tokenRef.current) return;
482
+ setPreviewBoth(null);
483
+ },
484
+ [setPreviewBoth],
485
+ );
486
+
487
+ const finish = useCallback(
488
+ (token: number) => {
489
+ endGesture();
490
+ clearPreview(token);
491
+ },
492
+ [endGesture, clearPreview],
493
+ );
494
+
495
+ /**
496
+ * A gesture thrown away rather than committed. The live region was narrating
497
+ * a specific new time as the user dragged; leaving that as the last thing
498
+ * announced tells a screen-reader user the event moved when it did not.
499
+ */
500
+ const abandon = useCallback(
501
+ (g: { frame: DragFrame; moved: boolean }) => {
502
+ const p = previewRef.current;
503
+ if (g.moved && p) announce(g.frame.event, p, { cancelled: true });
504
+ },
505
+ [announce],
506
+ );
507
+
508
+ const commit = useCallback(
509
+ (p: DragPreview, frame: DragFrame, token: number) => {
510
+ // The gesture asked for something the bounds refused, so the proposal is
511
+ // identical to where the event already is. Say so, and do NOT call the
512
+ // handler — the documented consumer shape is an API write, and a drag
513
+ // that moved nothing must not fire one.
514
+ //
515
+ // Lives here rather than on the keyboard path so pointer drags get it
516
+ // too: a fully-clamped drag is just as much a no-op as a clamped nudge.
517
+ const currentEnd = frame.event.endsAt ?? frame.event.startsAt;
518
+ const sameInstants =
519
+ p.startsAt.getTime() === frame.event.startsAt.getTime() &&
520
+ p.endsAt.getTime() === currentEnd.getTime();
521
+ const sameCoordinates =
522
+ p.startMinutes === frame.startMinutes && p.endMinutes === frame.endMinutes;
523
+ // Both checks, because they catch different things. Coordinates catch a
524
+ // clamped gesture; instants catch one whose grid coordinates moved but
525
+ // whose projection landed back on the very same moment — which is what a
526
+ // daylight-saving collapse does, and it would otherwise fire the
527
+ // consumer's API write proposing the value the event already has.
528
+ if ((sameInstants || sameCoordinates) && p.columnIndex === frame.columnIndex) {
529
+ // Two different things end up here. `clamped` means the bounds refused
530
+ // to go further; otherwise the user simply released where they
531
+ // started, and telling them they "cannot move any further" would be
532
+ // nonsense.
533
+ announce(frame.event, p, p.clamped ? { atEdge: true } : { unchanged: true });
534
+ finish(token);
535
+ return;
536
+ }
537
+ // A refused placement never reaches the consumer.
538
+ if (!validate(p, frame)) {
539
+ announce(frame.event, p, { refused: true });
540
+ finish(token);
541
+ return;
542
+ }
543
+ const payload = toPayload(p);
544
+ const result: CalendarDropResult =
545
+ p.mode === 'move'
546
+ ? onEventMove?.(frame.event, payload)
547
+ : onEventResize?.(frame.event, { startsAt: payload.startsAt, endsAt: payload.endsAt });
548
+
549
+ if (isThenable(result)) {
550
+ // Hold the preview until the consumer's async verdict lands, so an
551
+ // accepted drop doesn't flash back to its old slot while the request
552
+ // is in flight. The gesture itself is over.
553
+ endGesture();
554
+ result.then(
555
+ (verdict) => {
556
+ // Guarded on the token: a verdict that lands after the user has
557
+ // begun another gesture must not narrate the old placement over
558
+ // the new one.
559
+ if (token === tokenRef.current)
560
+ announce(frame.event, p, { refused: verdict === false });
561
+ clearPreview(token);
562
+ },
563
+ () => {
564
+ if (token === tokenRef.current) announce(frame.event, p, { refused: true });
565
+ clearPreview(token);
566
+ },
567
+ );
568
+ return;
569
+ }
570
+ announce(frame.event, p, { refused: result === false });
571
+ finish(token);
572
+ },
573
+ [validate, toPayload, onEventMove, onEventResize, finish, endGesture, clearPreview, announce],
574
+ );
575
+
576
+ const startPointerDrag = useCallback(
577
+ (block: TimedEventBlock, mode: DragMode, e: PointerEvent) => {
578
+ if (mode === 'move' && !canMove) return;
579
+ if (mode === 'resize' && !canResize) return;
580
+ // Primary button only — a right-click must not start a reschedule.
581
+ if (e.button !== 0) return;
582
+ e.stopPropagation();
583
+ suppressClickRef.current = false;
584
+ // A fresh press starts from the event's real position — never from a
585
+ // preview left behind by a previous gesture whose async commit has not
586
+ // settled yet.
587
+ setPreviewBoth(null);
588
+ tokenRef.current += 1;
589
+ gestureRef.current = {
590
+ token: tokenRef.current,
591
+ frame: frameOf(block, latest.current.baseMinutes),
592
+ mode,
593
+ pointerId: e.pointerId,
594
+ originX: e.clientX,
595
+ originY: e.clientY,
596
+ moved: false,
597
+ };
598
+ setDragging(true);
599
+ },
600
+ [canMove, canResize, setPreviewBoth],
601
+ );
602
+
603
+ // One subscription per gesture. Listening on `window` (rather than relying
604
+ // on pointer capture alone) keeps the drag alive when the pointer leaves
605
+ // the grid — including drops outside it, which simply resolve to the last
606
+ // valid column.
607
+ useEffect(() => {
608
+ if (!dragging) return;
609
+
610
+ const handleMove = (e: globalThis.PointerEvent) => {
611
+ const g = gestureRef.current;
612
+ if (!g || e.pointerId !== g.pointerId) return;
613
+ const dy = e.clientY - g.originY;
614
+ const dx = e.clientX - g.originX;
615
+ if (!g.moved && Math.abs(dy) < DRAG_THRESHOLD_PX && Math.abs(dx) < DRAG_THRESHOLD_PX) return;
616
+ g.moved = true;
617
+
618
+ const { hourRowHeight: rowH, columns: cols, columnElements: els } = latest.current;
619
+ const rawDelta = (dy / rowH) * 60;
620
+
621
+ let columnIndex = previewRef.current?.columnIndex ?? g.frame.columnIndex;
622
+ if (g.mode === 'move') {
623
+ // Hit-test the columns horizontally so a drag can cross into another
624
+ // day (week view) or another resource lane (resource day view).
625
+ const hit = els.current.findIndex((el) => {
626
+ if (!el) return false;
627
+ const r = el.getBoundingClientRect();
628
+ // A zero-width rect means the element has no layout to hit-test
629
+ // against; treating that as "no hit" keeps the column stable.
630
+ if (r.width === 0) return false;
631
+ return e.clientX >= r.left && e.clientX < r.right;
632
+ });
633
+ if (hit !== -1) columnIndex = hit;
634
+ }
635
+ if (columnIndex < 0 || columnIndex >= cols.length) columnIndex = g.frame.columnIndex;
636
+
637
+ const target =
638
+ g.mode === 'move' ? g.frame.startMinutes + rawDelta : g.frame.endMinutes + rawDelta;
639
+ const next = project(g.frame, g.mode, columnIndex, target, cfg());
640
+ next.invalid = !validate(next, g.frame);
641
+ const prev = previewRef.current;
642
+ setPreviewBoth(next);
643
+ // Announce only when the proposed slot actually changed — snapping makes
644
+ // that discrete, so this is one message per slot rather than per pixel.
645
+ if (
646
+ !prev ||
647
+ prev.startMinutes !== next.startMinutes ||
648
+ prev.endMinutes !== next.endMinutes ||
649
+ prev.columnIndex !== next.columnIndex ||
650
+ prev.invalid !== next.invalid
651
+ ) {
652
+ announce(g.frame.event, next, { refused: next.invalid });
653
+ }
654
+ };
655
+
656
+ const handleUp = (e: globalThis.PointerEvent) => {
657
+ const g = gestureRef.current;
658
+ if (!g || e.pointerId !== g.pointerId) return;
659
+ const p = previewRef.current;
660
+ if (!g.moved || !p) {
661
+ // A press that never crossed the threshold is a click, not a drag.
662
+ finish(g.token);
663
+ return;
664
+ }
665
+ // The click event that follows this pointerup would otherwise open the
666
+ // consumer's detail UI — or, if the pointer ended over the column
667
+ // background rather than the block, create a booking at that slot.
668
+ armClickSuppression();
669
+ commit(p, g.frame, g.token);
670
+ };
671
+
672
+ const handleCancel = (e: globalThis.PointerEvent) => {
673
+ const g = gestureRef.current;
674
+ if (!g || e.pointerId !== g.pointerId) return;
675
+ // Pointer cancellation (a system gesture taking over, the element being
676
+ // removed) discards the drag without proposing anything. Say so: the
677
+ // last thing announced was a specific new time, and leaving that
678
+ // standing tells a screen-reader user the event moved when it didn't.
679
+ abandon(g);
680
+ finish(g.token);
681
+ };
682
+
683
+ // Last-resort recovery. There is no pointer capture here, so a `pointerup`
684
+ // delivered to another document — an alt-tab mid-drag, a devtools
685
+ // detach — never reaches us, and the gesture would otherwise stay live
686
+ // forever, taking the keyboard path down with it.
687
+ const handleBlur = () => {
688
+ const g = gestureRef.current;
689
+ if (!g) return;
690
+ // Arm the suppression the same way `handleUp` does. Without it the
691
+ // `pointerup` that follows finds no gesture, its `click` reaches the
692
+ // column, and the consumer's "create a booking here" UI opens at the
693
+ // spot the user was dragging to. Unlike `handleUp` there is no
694
+ // guarantee a click ever arrives to consume the flag, so it is armed
695
+ // with an expiry — see `armClickSuppression`.
696
+ if (g.moved) armClickSuppression();
697
+ abandon(g);
698
+ finish(g.token);
699
+ };
700
+
701
+ window.addEventListener('pointermove', handleMove);
702
+ window.addEventListener('pointerup', handleUp);
703
+ window.addEventListener('pointercancel', handleCancel);
704
+ window.addEventListener('blur', handleBlur);
705
+ return () => {
706
+ window.removeEventListener('pointermove', handleMove);
707
+ window.removeEventListener('pointerup', handleUp);
708
+ window.removeEventListener('pointercancel', handleCancel);
709
+ window.removeEventListener('blur', handleBlur);
710
+ };
711
+ }, [
712
+ dragging,
713
+ commit,
714
+ finish,
715
+ setPreviewBoth,
716
+ validate,
717
+ cfg,
718
+ announce,
719
+ abandon,
720
+ armClickSuppression,
721
+ ]);
722
+
723
+ const nudge = useCallback(
724
+ (block: TimedEventBlock, delta: { mode: DragMode; steps: number; columns?: number }) => {
725
+ if (delta.mode === 'move' && !canMove) return;
726
+ if (delta.mode === 'resize' && !canResize) return;
727
+ // A pointer gesture already owns the hook (pointerdown focused the
728
+ // block, so a keypress can land mid-drag). Bumping the token here would
729
+ // orphan that gesture: its pointerup would no-op and leave the grid
730
+ // stuck in the dragging state.
731
+ if (gestureRef.current) return;
732
+
733
+ const frame = frameOf(block, latest.current.baseMinutes);
734
+ const step = latest.current.snap;
735
+ const columnIndex = clamp(
736
+ frame.columnIndex + (delta.columns ?? 0),
737
+ 0,
738
+ Math.max(0, latest.current.columns.length - 1),
739
+ );
740
+
741
+ // A pure column change must not also re-snap the time — moving a 09:07
742
+ // booking to the next lane should leave it at 09:07.
743
+ const base = delta.mode === 'move' ? frame.startMinutes : frame.endMinutes;
744
+ const pureColumnChange = delta.steps === 0;
745
+ const target = pureColumnChange ? base : snapTo(base, step) + delta.steps * step;
746
+ // `presnapped` for a pure column change, or `project` would re-snap the
747
+ // untouched time and quietly drag a 09:07 booking to 09:00.
748
+ const next = project(frame, delta.mode, columnIndex, target, cfg(), pureColumnChange);
749
+
750
+ tokenRef.current += 1;
751
+ // `commit` owns the no-op check, so a clamped nudge and a clamped drag
752
+ // report identically.
753
+ commit(next, frame, tokenRef.current);
754
+ },
755
+ [canMove, canResize, commit, cfg],
756
+ );
757
+
758
+ const consumeClickSuppression = useCallback(() => {
759
+ const was = suppressClickRef.current;
760
+ suppressClickRef.current = false;
761
+ return was;
762
+ }, []);
763
+
764
+ // A drop released outside the grid produces no click at all, so the flag
765
+ // would otherwise survive to swallow the next genuine one. Every fresh
766
+ // press clears it — including presses that start no gesture (a plain click,
767
+ // or a press on a block in a resize-only grid).
768
+ const resetClickSuppression = useCallback(() => {
769
+ suppressClickRef.current = false;
770
+ }, []);
771
+
772
+ return {
773
+ preview,
774
+ announcement,
775
+ dragging,
776
+ canMove,
777
+ canResize,
778
+ startPointerDrag,
779
+ nudge,
780
+ consumeClickSuppression,
781
+ resetClickSuppression,
782
+ };
783
+ }