@cube-dev/ui-kit 0.166.0 → 0.168.0

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 (663) hide show
  1. package/README.md +4 -7
  2. package/dist/CHANGELOG.md +47 -0
  3. package/dist/README.md +4 -7
  4. package/dist/_internal/hooks/use-chained-callback.js +1 -1
  5. package/dist/_internal/hooks/use-debounced-value.js +1 -1
  6. package/dist/_internal/hooks/use-deprecation-warning.js +1 -1
  7. package/dist/_internal/hooks/use-event.js +1 -1
  8. package/dist/_internal/hooks/use-is-first-render.js +1 -1
  9. package/dist/_internal/hooks/use-sync-ref.js +1 -1
  10. package/dist/_internal/hooks/use-timer/timer.js +1 -1
  11. package/dist/_internal/hooks/use-timer/use-timer.js +1 -1
  12. package/dist/_internal/hooks/use-warn.js +1 -1
  13. package/dist/components/Block.js +1 -1
  14. package/dist/components/CollectionItem.js +1 -1
  15. package/dist/components/GlobalStyles.js +4 -4
  16. package/dist/components/GlobalStyles.js.map +1 -1
  17. package/dist/components/GridProvider.js +1 -1
  18. package/dist/components/HiddenInput.js +1 -1
  19. package/dist/components/Root.js +5 -5
  20. package/dist/components/Root.js.map +1 -1
  21. package/dist/components/actions/Action/Action.js +1 -1
  22. package/dist/components/actions/Banner/Banner.js +1 -1
  23. package/dist/components/actions/Button/Button.d.ts +0 -1
  24. package/dist/components/actions/Button/Button.js +1 -1
  25. package/dist/components/actions/ButtonGroup/ButtonGroup.js +1 -1
  26. package/dist/components/actions/ButtonSplit/ButtonSplit.js +1 -1
  27. package/dist/components/actions/ButtonSplit/context.js +1 -1
  28. package/dist/components/actions/CommandMenu/CommandMenu.js +1 -1
  29. package/dist/components/actions/CommandMenu/styled.js +1 -1
  30. package/dist/components/actions/ItemAction/ItemAction.js +1 -1
  31. package/dist/components/actions/ItemActionContext.js +1 -1
  32. package/dist/components/actions/ItemButton/ItemButton.js +1 -1
  33. package/dist/components/actions/Link/Link.js +1 -1
  34. package/dist/components/actions/Menu/Menu.js +1 -1
  35. package/dist/components/actions/Menu/MenuItem.js +1 -1
  36. package/dist/components/actions/Menu/MenuSection.js +1 -1
  37. package/dist/components/actions/Menu/MenuTrigger.js +1 -1
  38. package/dist/components/actions/Menu/SubMenuTrigger.js +1 -1
  39. package/dist/components/actions/Menu/SubmenuTriggerContext.js +1 -1
  40. package/dist/components/actions/Menu/context.js +1 -1
  41. package/dist/components/actions/Menu/styled.js +1 -1
  42. package/dist/components/actions/index.js +1 -1
  43. package/dist/components/actions/use-action.js +1 -1
  44. package/dist/components/actions/use-anchored-menu.d.ts +7 -3
  45. package/dist/components/actions/use-anchored-menu.js +17 -12
  46. package/dist/components/actions/use-anchored-menu.js.map +1 -1
  47. package/dist/components/actions/use-context-menu.d.ts +6 -3
  48. package/dist/components/actions/use-context-menu.js +25 -13
  49. package/dist/components/actions/use-context-menu.js.map +1 -1
  50. package/dist/components/content/ActiveZone/ActiveZone.js +1 -1
  51. package/dist/components/content/Alert/Alert.js +1 -1
  52. package/dist/components/content/Alert/use-alert.js +1 -1
  53. package/dist/components/content/Avatar/Avatar.js +1 -1
  54. package/dist/components/content/Badge/Badge.js +1 -1
  55. package/dist/components/content/Card/Card.js +1 -1
  56. package/dist/components/content/Content.js +1 -1
  57. package/dist/components/content/CopyPasteBlock/CopyPasteBlock.js +1 -1
  58. package/dist/components/content/CopySnippet/CopySnippet.js +1 -1
  59. package/dist/components/content/Disclosure/Disclosure.js +1 -1
  60. package/dist/components/content/Divider.js +1 -1
  61. package/dist/components/content/Footer.js +1 -1
  62. package/dist/components/content/Header.js +1 -1
  63. package/dist/components/content/HotKeys/HotKeys.js +1 -1
  64. package/dist/components/content/InfoBadge/InfoBadge.js +1 -1
  65. package/dist/components/content/InlineInput/InlineInput.js +1 -1
  66. package/dist/components/content/Item/Item.js +1 -1
  67. package/dist/components/content/ItemBadge/ItemBadge.js +1 -1
  68. package/dist/components/content/ItemCard/ItemCard.js +1 -1
  69. package/dist/components/content/Layout/GridLayout.js +1 -1
  70. package/dist/components/content/Layout/Layout.js +1 -1
  71. package/dist/components/content/Layout/LayoutBlock.js +1 -1
  72. package/dist/components/content/Layout/LayoutCenter.js +1 -1
  73. package/dist/components/content/Layout/LayoutContainer.js +1 -1
  74. package/dist/components/content/Layout/LayoutContent.js +1 -1
  75. package/dist/components/content/Layout/LayoutContext.js +1 -1
  76. package/dist/components/content/Layout/LayoutFlex.js +1 -1
  77. package/dist/components/content/Layout/LayoutFooter.js +1 -1
  78. package/dist/components/content/Layout/LayoutGrid.js +1 -1
  79. package/dist/components/content/Layout/LayoutHeader.js +1 -1
  80. package/dist/components/content/Layout/LayoutPane.js +1 -1
  81. package/dist/components/content/Layout/LayoutPanel.js +1 -1
  82. package/dist/components/content/Layout/LayoutPanelHeader.js +1 -1
  83. package/dist/components/content/Layout/LayoutToolbar.js +1 -1
  84. package/dist/components/content/Layout/hooks/useTinyScrollbar.js +1 -1
  85. package/dist/components/content/Layout/index.js +1 -1
  86. package/dist/components/content/Layout/utils.js +1 -1
  87. package/dist/components/content/Paragraph.js +1 -1
  88. package/dist/components/content/Placeholder/Placeholder.js +1 -1
  89. package/dist/components/content/PrismCode/PrismCode.js +1 -1
  90. package/dist/components/content/PrismCode/prismSetup.js +1 -1
  91. package/dist/components/content/PrismDiffCode/PrismDiffCode.js +1 -1
  92. package/dist/components/content/Result/Result.js +1 -1
  93. package/dist/components/content/Skeleton/Skeleton.js +1 -1
  94. package/dist/components/content/Tag/Tag.js +1 -1
  95. package/dist/components/content/Text.d.ts +14 -14
  96. package/dist/components/content/Text.js +1 -1
  97. package/dist/components/content/TextItem/TextItem.js +1 -1
  98. package/dist/components/content/Title.js +1 -1
  99. package/dist/components/content/Tree/Tree.js +1 -1
  100. package/dist/components/content/Tree/TreeNode.js +1 -1
  101. package/dist/components/content/Tree/styled.js +1 -1
  102. package/dist/components/content/Tree/tree-index.js +1 -1
  103. package/dist/components/content/Tree/use-checkbox-tree.js +1 -1
  104. package/dist/components/content/Tree/use-load-data.js +1 -1
  105. package/dist/components/content/highlightText.js +1 -1
  106. package/dist/components/content/use-auto-tooltip.js +1 -1
  107. package/dist/components/data/DataTable/DataTable.js +1 -1
  108. package/dist/components/data/ItemTable/ItemTable.js +1 -1
  109. package/dist/components/data/ItemTable/ItemTableBulkBar.js +1 -1
  110. package/dist/components/data/ItemTable/ItemTableDragPreview.js +1 -1
  111. package/dist/components/data/ItemTable/ItemTableFooter.js +1 -1
  112. package/dist/components/data/ItemTable/ItemTableToolbar.js +1 -1
  113. package/dist/components/data/TableBase/ColumnResizer.js +1 -1
  114. package/dist/components/data/TableBase/RowCollection.js +1 -1
  115. package/dist/components/data/TableBase/TableHeaderCell.js +1 -1
  116. package/dist/components/data/TableBase/TableRow.js +1 -1
  117. package/dist/components/data/TableBase/TableView.js +1 -1
  118. package/dist/components/data/TableBase/column-menu.js +1 -1
  119. package/dist/components/data/TableBase/column-tint.js +1 -1
  120. package/dist/components/data/TableBase/row-menu.js +1 -1
  121. package/dist/components/data/TableBase/styled.d.ts +1 -2
  122. package/dist/components/data/TableBase/styled.js +1 -1
  123. package/dist/components/data/TableBase/table-tree.js +1 -1
  124. package/dist/components/data/TableBase/types.js +1 -1
  125. package/dist/components/data/TableBase/use-cell-selection.d.ts +0 -1
  126. package/dist/components/data/TableBase/use-cell-selection.js +0 -0
  127. package/dist/components/data/TableBase/use-column-order.js +1 -1
  128. package/dist/components/data/TableBase/use-container-width.js +1 -1
  129. package/dist/components/data/TableBase/use-row-move-animation.js +1 -1
  130. package/dist/components/data/TableBase/use-scrollability.js +1 -1
  131. package/dist/components/data/TableBase/use-table-columns.js +1 -1
  132. package/dist/components/data/TableBase/use-table-search.js +1 -1
  133. package/dist/components/data/TableBase/use-table-selection.js +1 -1
  134. package/dist/components/data/TableBase/use-table-sort.js +1 -1
  135. package/dist/components/data/TableBase/use-table-sorts.js +1 -1
  136. package/dist/components/data/TableBase/use-table-storage.js +1 -1
  137. package/dist/components/data/TableBase/use-table-tree-state.js +1 -1
  138. package/dist/components/fields/Checkbox/Checkbox.js +1 -1
  139. package/dist/components/fields/Checkbox/CheckboxGroup.js +1 -1
  140. package/dist/components/fields/Checkbox/context.js +1 -1
  141. package/dist/components/fields/ColorInput/ColorInput.js +1 -1
  142. package/dist/components/fields/ColorPicker/ColorPicker.js +1 -1
  143. package/dist/components/fields/ColorSwatch/ColorSwatch.js +1 -1
  144. package/dist/components/fields/ColorSwatchGroup/ColorSwatchGroup.js +1 -1
  145. package/dist/components/fields/ComboBox/ComboBox.js +1 -1
  146. package/dist/components/fields/CommandTextArea/CommandTextArea.js +1 -1
  147. package/dist/components/fields/CommandTextArea/caretPosition.js +1 -1
  148. package/dist/components/fields/CommandTextArea/useCaretAnchor.js +1 -1
  149. package/dist/components/fields/DatePicker/DateInput.js +1 -1
  150. package/dist/components/fields/DatePicker/DateInputBase.js +1 -1
  151. package/dist/components/fields/DatePicker/DatePicker.js +1 -1
  152. package/dist/components/fields/DatePicker/DatePickerButton.js +1 -1
  153. package/dist/components/fields/DatePicker/DatePickerElement.js +1 -1
  154. package/dist/components/fields/DatePicker/DatePickerInput.js +1 -1
  155. package/dist/components/fields/DatePicker/DatePickerSegment.js +1 -1
  156. package/dist/components/fields/DatePicker/DateRangePicker.js +1 -1
  157. package/dist/components/fields/DatePicker/DateRangeSeparatedPicker.js +1 -1
  158. package/dist/components/fields/DatePicker/MonthPicker.js +1 -1
  159. package/dist/components/fields/DatePicker/PeriodPicker.js +1 -1
  160. package/dist/components/fields/DatePicker/QuarterPicker.js +1 -1
  161. package/dist/components/fields/DatePicker/TimeInput.js +1 -1
  162. package/dist/components/fields/DatePicker/WeekPicker.js +1 -1
  163. package/dist/components/fields/DatePicker/YearPicker.js +1 -1
  164. package/dist/components/fields/DatePicker/parseDate.js +1 -1
  165. package/dist/components/fields/DatePicker/period.js +1 -1
  166. package/dist/components/fields/DatePicker/props.js +1 -1
  167. package/dist/components/fields/DatePicker/utils.js +1 -1
  168. package/dist/components/fields/FileInput/FileInput.js +1 -1
  169. package/dist/components/fields/FilterListBox/FilterListBox.js +1 -1
  170. package/dist/components/fields/FilterPicker/FilterPicker.js +1 -1
  171. package/dist/components/fields/Input/Input.js +1 -1
  172. package/dist/components/fields/ListBox/DraggableListBox.js +1 -1
  173. package/dist/components/fields/ListBox/ListBox.js +1 -1
  174. package/dist/components/fields/ListBoxPopover/ListBoxPopover.js +1 -1
  175. package/dist/components/fields/ListBoxPopover/index.d.ts +0 -1
  176. package/dist/components/fields/ListBoxPopover/listNavigation.js +1 -1
  177. package/dist/components/fields/ListBoxPopover/useCompositeFocus.js +1 -1
  178. package/dist/components/fields/NumberInput/NumberInput.js +1 -1
  179. package/dist/components/fields/NumberInput/StepButton.js +1 -1
  180. package/dist/components/fields/PasswordInput/PasswordInput.js +1 -1
  181. package/dist/components/fields/Picker/Picker.js +1 -1
  182. package/dist/components/fields/RadioGroup/Radio.js +1 -1
  183. package/dist/components/fields/RadioGroup/RadioGroup.js +1 -1
  184. package/dist/components/fields/RadioGroup/context.js +1 -1
  185. package/dist/components/fields/SearchComboBox/SearchComboBox.js +1 -1
  186. package/dist/components/fields/SearchInput/SearchInput.js +1 -1
  187. package/dist/components/fields/Select/Select.js +1 -1
  188. package/dist/components/fields/Slider/Gradation.js +1 -1
  189. package/dist/components/fields/Slider/HueSlider.js +1 -1
  190. package/dist/components/fields/Slider/RangeSlider.js +1 -1
  191. package/dist/components/fields/Slider/Slider.js +1 -1
  192. package/dist/components/fields/Slider/SliderBase.js +1 -1
  193. package/dist/components/fields/Slider/SliderThumb.js +1 -1
  194. package/dist/components/fields/Slider/SliderTrack.js +1 -1
  195. package/dist/components/fields/Slider/elements.js +1 -1
  196. package/dist/components/fields/Slider/index.js +1 -1
  197. package/dist/components/fields/Switch/Switch.js +1 -1
  198. package/dist/components/fields/TextArea/TextArea.js +1 -1
  199. package/dist/components/fields/TextInput/TextInput.js +1 -1
  200. package/dist/components/fields/TextInput/TextInputBase.js +1 -1
  201. package/dist/components/fields/TextInput/useAutoSizeTextArea.js +1 -1
  202. package/dist/components/fields/TextInputMapper/TextInputMapper.js +1 -1
  203. package/dist/components/fields/color/ColorPanel.js +1 -1
  204. package/dist/components/fields/color/channels.js +1 -1
  205. package/dist/components/fields/color/color.js +1 -1
  206. package/dist/components/fields/color/context.js +1 -1
  207. package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
  208. package/dist/components/form/Form/Field.js +1 -1
  209. package/dist/components/form/Form/Form.js +1 -1
  210. package/dist/components/form/Form/ResetButton/ResetButton.js +1 -1
  211. package/dist/components/form/Form/SubmitButton/SubmitButton.js +1 -1
  212. package/dist/components/form/Form/SubmitError.js +1 -1
  213. package/dist/components/form/Form/index.js +1 -1
  214. package/dist/components/form/Form/use-field/use-field-props.js +1 -1
  215. package/dist/components/form/Form/use-field/use-field.js +1 -1
  216. package/dist/components/form/Form/use-form.js +1 -1
  217. package/dist/components/form/Form/validation.js +1 -1
  218. package/dist/components/form/Label.js +1 -1
  219. package/dist/components/form/validation/ValidationIndicator.js +1 -1
  220. package/dist/components/form/validation/resolve-validation-props.js +1 -1
  221. package/dist/components/form/validation/use-validation-props.js +1 -1
  222. package/dist/components/form/wrapper.js +1 -1
  223. package/dist/components/helpers/DisplayTransition/DisplayTransition.js +1 -1
  224. package/dist/components/helpers/IconSwitch/IconSwitch.js +1 -1
  225. package/dist/components/layout/Board/Board.d.ts +11 -5
  226. package/dist/components/layout/Board/Board.js +15 -7
  227. package/dist/components/layout/Board/Board.js.map +1 -1
  228. package/dist/components/layout/Board/BoardProvider.js +1 -1
  229. package/dist/components/layout/Board/BoardResponsive.d.ts +6 -3
  230. package/dist/components/layout/Board/BoardResponsive.js +3 -3
  231. package/dist/components/layout/Board/BoardResponsive.js.map +1 -1
  232. package/dist/components/layout/Board/Widget.d.ts +29 -1
  233. package/dist/components/layout/Board/Widget.js +5 -2
  234. package/dist/components/layout/Board/Widget.js.map +1 -1
  235. package/dist/components/layout/Board/WidgetHost.js +67 -17
  236. package/dist/components/layout/Board/WidgetHost.js.map +1 -1
  237. package/dist/components/layout/Board/board-context.js +1 -1
  238. package/dist/components/layout/Board/board-context.js.map +1 -1
  239. package/dist/components/layout/Board/board-store.js +2 -2
  240. package/dist/components/layout/Board/board-store.js.map +1 -1
  241. package/dist/components/layout/Board/grid-core/calculate.js +1 -1
  242. package/dist/components/layout/Board/grid-core/collision-modes.js +1 -1
  243. package/dist/components/layout/Board/grid-core/collision.js +1 -1
  244. package/dist/components/layout/Board/grid-core/compactors.js +1 -1
  245. package/dist/components/layout/Board/grid-core/constraints.js +1 -1
  246. package/dist/components/layout/Board/grid-core/group-move.js +1 -1
  247. package/dist/components/layout/Board/grid-core/layout.js +1 -1
  248. package/dist/components/layout/Board/grid-core/placement.js +1 -1
  249. package/dist/components/layout/Board/grid-core/sort.js +1 -1
  250. package/dist/components/layout/Board/index.d.ts +2 -1
  251. package/dist/components/layout/Board/index.js +1 -1
  252. package/dist/components/layout/Board/index.js.map +1 -1
  253. package/dist/components/layout/Board/responsive-utils.js +1 -1
  254. package/dist/components/layout/Board/use-board-layout.d.ts +26 -0
  255. package/dist/components/layout/Board/use-board-layout.js +4 -4
  256. package/dist/components/layout/Board/use-board-layout.js.map +1 -1
  257. package/dist/components/layout/Board/use-board-registry.js +4 -4
  258. package/dist/components/layout/Board/use-board-registry.js.map +1 -1
  259. package/dist/components/layout/Board/use-board-select-modifier-key.js +1 -1
  260. package/dist/components/layout/Board/use-board-selection.js +1 -1
  261. package/dist/components/layout/Flex.js +1 -1
  262. package/dist/components/layout/Flow.js +1 -1
  263. package/dist/components/layout/Grid.js +1 -1
  264. package/dist/components/layout/Panel.js +1 -1
  265. package/dist/components/layout/Prefix.js +1 -1
  266. package/dist/components/layout/ResizablePanel.js +1 -1
  267. package/dist/components/layout/Space.js +1 -1
  268. package/dist/components/layout/Suffix.js +1 -1
  269. package/dist/components/navigation/Pagination/Pagination.js +1 -1
  270. package/dist/components/navigation/Pagination/use-pagination.js +1 -1
  271. package/dist/components/navigation/Tabs/DraggableTabList.js +1 -1
  272. package/dist/components/navigation/Tabs/TabButton.js +1 -1
  273. package/dist/components/navigation/Tabs/TabDropIndicator.js +1 -1
  274. package/dist/components/navigation/Tabs/TabPanel.js +1 -1
  275. package/dist/components/navigation/Tabs/TabPicker.js +1 -1
  276. package/dist/components/navigation/Tabs/Tabs.js +1 -1
  277. package/dist/components/navigation/Tabs/TabsAction.js +1 -1
  278. package/dist/components/navigation/Tabs/TabsContext.js +1 -1
  279. package/dist/components/navigation/Tabs/popover-placement.js +1 -1
  280. package/dist/components/navigation/Tabs/styled.js +1 -1
  281. package/dist/components/navigation/Tabs/types.js +1 -1
  282. package/dist/components/navigation/Tabs/use-tab-editing.js +1 -1
  283. package/dist/components/navigation/Tabs/use-tab-indicator.js +1 -1
  284. package/dist/components/organisms/StatsCard/StatsCard.js +1 -1
  285. package/dist/components/other/Calendar/Calendar.js +1 -1
  286. package/dist/components/other/Calendar/CalendarCell.js +1 -1
  287. package/dist/components/other/Calendar/CalendarGrid.js +1 -1
  288. package/dist/components/other/Calendar/CalendarHeader.js +1 -1
  289. package/dist/components/other/Calendar/CalendarPanel.js +1 -1
  290. package/dist/components/other/Calendar/PeriodCalendar.js +1 -1
  291. package/dist/components/other/Calendar/PeriodGrid.js +1 -1
  292. package/dist/components/other/Calendar/RangeCalendar.js +1 -1
  293. package/dist/components/other/Calendar/styled.js +1 -1
  294. package/dist/components/other/CubeLogo/CubeLogo.js +1 -1
  295. package/dist/components/other/NoDataIcon/NoDataIcon.js +1 -1
  296. package/dist/components/overlays/AlertDialog/AlertDialog.js +1 -1
  297. package/dist/components/overlays/AlertDialog/AlertDialogApiProvider.js +1 -1
  298. package/dist/components/overlays/AlertDialog/AlertDialogZone.js +1 -1
  299. package/dist/components/overlays/Dialog/Dialog.js +1 -1
  300. package/dist/components/overlays/Dialog/DialogContainer.js +1 -1
  301. package/dist/components/overlays/Dialog/DialogForm.js +1 -1
  302. package/dist/components/overlays/Dialog/DialogTrigger.js +1 -1
  303. package/dist/components/overlays/Dialog/context.js +1 -1
  304. package/dist/components/overlays/Dialog/use-dialog-container.js +1 -1
  305. package/dist/components/overlays/Modal/Modal.d.ts +1 -2
  306. package/dist/components/overlays/Modal/Modal.js +1 -1
  307. package/dist/components/overlays/Modal/OpenTransitionContext.js +1 -1
  308. package/dist/components/overlays/Modal/Overlay.d.ts +0 -1
  309. package/dist/components/overlays/Modal/Overlay.js +4 -3
  310. package/dist/components/overlays/Modal/Overlay.js.map +1 -1
  311. package/dist/components/overlays/Modal/Popover.js +1 -1
  312. package/dist/components/overlays/Modal/Tray.js +1 -1
  313. package/dist/components/overlays/Modal/Underlay.js +1 -1
  314. package/dist/components/overlays/Modal/types.d.ts +0 -1
  315. package/dist/components/overlays/Notifications/Notification.js +1 -1
  316. package/dist/components/overlays/Notifications/NotificationAction.js +1 -1
  317. package/dist/components/overlays/Notifications/NotificationCard.js +1 -1
  318. package/dist/components/overlays/Notifications/NotificationContext.d.ts +0 -2
  319. package/dist/components/overlays/Notifications/NotificationContext.js +1 -1
  320. package/dist/components/overlays/Notifications/NotificationItem.js +1 -1
  321. package/dist/components/overlays/Notifications/OverlayContainer.js +1 -1
  322. package/dist/components/overlays/Notifications/OverlayProvider.js +1 -1
  323. package/dist/components/overlays/Notifications/PersistentNotificationsList.js +1 -1
  324. package/dist/components/overlays/Notifications/dismissed-storage.js +1 -1
  325. package/dist/components/overlays/Notifications/format-relative-time.js +1 -1
  326. package/dist/components/overlays/Notifications/index.js +1 -1
  327. package/dist/components/overlays/Notifications/use-notification-state.js +1 -1
  328. package/dist/components/overlays/Notifications/use-notifications.js +1 -1
  329. package/dist/components/overlays/Notifications/use-overlay-timers.js +1 -1
  330. package/dist/components/overlays/Notifications/use-persistent-notifications.js +1 -1
  331. package/dist/components/overlays/Notifications/use-persistent-state.js +1 -1
  332. package/dist/components/overlays/Notifications/use-toast-state.js +1 -1
  333. package/dist/components/overlays/Toast/ToastItem.js +1 -1
  334. package/dist/components/overlays/Toast/index.js +1 -1
  335. package/dist/components/overlays/Toast/useProgressToast.js +1 -1
  336. package/dist/components/overlays/Toast/useToast.js +1 -1
  337. package/dist/components/overlays/Tooltip/Tooltip.js +1 -1
  338. package/dist/components/overlays/Tooltip/TooltipProvider.js +1 -1
  339. package/dist/components/overlays/Tooltip/TooltipTrigger.js +1 -1
  340. package/dist/components/overlays/Tooltip/context.js +1 -1
  341. package/dist/components/portal/Portal.js +7 -5
  342. package/dist/components/portal/Portal.js.map +1 -1
  343. package/dist/components/portal/PortalProvider.js +1 -1
  344. package/dist/components/portal/index.d.ts +0 -1
  345. package/dist/components/portal/usePortal.js +1 -1
  346. package/dist/components/shared/DraggableCollection.js +1 -1
  347. package/dist/components/shared/InvalidIcon.js +1 -1
  348. package/dist/components/shared/ValidIcon.js +1 -1
  349. package/dist/components/status/LoadingAnimation/LoadingAnimation.js +1 -1
  350. package/dist/components/status/Spin/Cube.js +1 -1
  351. package/dist/components/status/Spin/InternalSpinner.js +1 -1
  352. package/dist/components/status/Spin/Spin.js +1 -1
  353. package/dist/components/status/Spin/SpinsContainer.js +1 -1
  354. package/dist/data/item-themes.js +1 -1
  355. package/dist/data/themes.js +1 -1
  356. package/dist/eslint-plugin/defaults.generated.js +21 -1
  357. package/dist/eslint-plugin/defaults.generated.js.map +1 -1
  358. package/dist/eslint-plugin/index.js +1 -1
  359. package/dist/eslint-plugin/rules/no-redundant-default-prop.js +1 -1
  360. package/dist/i18n/I18nProvider.js +1 -1
  361. package/dist/i18n/createFormatter.js +1 -1
  362. package/dist/i18n/index.js +1 -1
  363. package/dist/i18n/instance.js +1 -1
  364. package/dist/i18n/locales/de-DE/uikit.js +1 -1
  365. package/dist/i18n/locales/en-US/uikit.js +1 -1
  366. package/dist/i18n/locales/es-ES/uikit.js +1 -1
  367. package/dist/i18n/locales/es-MX/uikit.js +1 -1
  368. package/dist/i18n/locales/fr-FR/uikit.js +1 -1
  369. package/dist/i18n/locales/it-IT/uikit.js +1 -1
  370. package/dist/i18n/locales/ja-JP/uikit.js +1 -1
  371. package/dist/i18n/locales/nb-NO/uikit.js +1 -1
  372. package/dist/i18n/locales/pt-BR/uikit.js +1 -1
  373. package/dist/i18n/locales/pt-PT/uikit.js +1 -1
  374. package/dist/i18n/locales/sv-SE/uikit.js +1 -1
  375. package/dist/i18n/locales/vi-VN/uikit.js +1 -1
  376. package/dist/i18n/locales.js +1 -1
  377. package/dist/i18n/useFormatter.js +1 -1
  378. package/dist/i18n/useI18n.js +1 -1
  379. package/dist/icons/AdjustmentsHorizontalIcon.js +1 -1
  380. package/dist/icons/AdjustmentsIcon.js +1 -1
  381. package/dist/icons/AiIcon.js +1 -1
  382. package/dist/icons/AreaChartIcon.js +1 -1
  383. package/dist/icons/ArrowNarrowDownIcon.js +1 -1
  384. package/dist/icons/ArrowNarrowUpIcon.js +1 -1
  385. package/dist/icons/BackwardIcon.js +1 -1
  386. package/dist/icons/BarChartIcon.js +1 -1
  387. package/dist/icons/BellFilledIcon.js +1 -1
  388. package/dist/icons/BellIcon.js +1 -1
  389. package/dist/icons/BooleanIcon.js +1 -1
  390. package/dist/icons/CalendarEditIcon.js +1 -1
  391. package/dist/icons/CalendarIcon.js +1 -1
  392. package/dist/icons/CaretDownIcon.js +1 -1
  393. package/dist/icons/CaretUpIcon.js +1 -1
  394. package/dist/icons/ChartAreaStackedIcon.js +1 -1
  395. package/dist/icons/ChartAreaStackedPercentageIcon.js +1 -1
  396. package/dist/icons/ChartBarGroupedHorizontalIcon.js +1 -1
  397. package/dist/icons/ChartBarGroupedIcon.js +1 -1
  398. package/dist/icons/ChartBarHorizontalIcon.js +1 -1
  399. package/dist/icons/ChartBarLineIcon.js +1 -1
  400. package/dist/icons/ChartBarStackedHorizontalIcon.js +1 -1
  401. package/dist/icons/ChartBarStackedIcon.js +1 -1
  402. package/dist/icons/ChartBarStackedPercentageHorizontalIcon.js +1 -1
  403. package/dist/icons/ChartBarStackedPercentageIcon.js +1 -1
  404. package/dist/icons/ChartBoxPlot2Icon.js +1 -1
  405. package/dist/icons/ChartBoxPlotIcon.js +1 -1
  406. package/dist/icons/ChartBubbleIcon.js +1 -1
  407. package/dist/icons/ChartDonut2Icon.js +1 -1
  408. package/dist/icons/ChartFunnelIcon.js +1 -1
  409. package/dist/icons/ChartHeatmapIcon.js +1 -1
  410. package/dist/icons/ChartKPIIcon.js +1 -1
  411. package/dist/icons/ChartPie2Icon.js +1 -1
  412. package/dist/icons/ChartScatterIcon.js +1 -1
  413. package/dist/icons/CheckCircleFilledIcon.js +1 -1
  414. package/dist/icons/CheckCircleIcon.js +1 -1
  415. package/dist/icons/CheckIcon.js +1 -1
  416. package/dist/icons/CircleFilledIcon.js +1 -1
  417. package/dist/icons/ClearIcon.js +1 -1
  418. package/dist/icons/CloseCircleFilledIcon.js +1 -1
  419. package/dist/icons/CloseCircleIcon.js +1 -1
  420. package/dist/icons/CloseIcon.js +1 -1
  421. package/dist/icons/CodeIcon.js +1 -1
  422. package/dist/icons/ColumnTotalIcon.js +1 -1
  423. package/dist/icons/CopyIcon.js +1 -1
  424. package/dist/icons/CountIcon.js +1 -1
  425. package/dist/icons/CubeIcon.js +1 -1
  426. package/dist/icons/CubePauseIcon.js +1 -1
  427. package/dist/icons/CubePlayIcon.js +1 -1
  428. package/dist/icons/CurrencyDollarIcon.js +1 -1
  429. package/dist/icons/DangerIcon.js +1 -1
  430. package/dist/icons/DashboardIcon.js +1 -1
  431. package/dist/icons/DatabaseIcon.js +1 -1
  432. package/dist/icons/DecimalDecreaseIcon.js +1 -1
  433. package/dist/icons/DecimalIncreaseIcon.js +1 -1
  434. package/dist/icons/DirectionIcon.js +1 -1
  435. package/dist/icons/DonutIcon.js +1 -1
  436. package/dist/icons/DownIcon.js +1 -1
  437. package/dist/icons/EditIcon.js +1 -1
  438. package/dist/icons/ExclamationCircleFilledIcon.js +1 -1
  439. package/dist/icons/ExclamationCircleIcon.js +1 -1
  440. package/dist/icons/ExclamationIcon.js +1 -1
  441. package/dist/icons/EyeIcon.js +1 -1
  442. package/dist/icons/EyeInvisibleIcon.js +1 -1
  443. package/dist/icons/FilterIcon.js +1 -1
  444. package/dist/icons/FolderFilledIcon.js +1 -1
  445. package/dist/icons/FolderIcon.js +1 -1
  446. package/dist/icons/FolderOpenFilledIcon.js +1 -1
  447. package/dist/icons/FolderOpenIcon.js +1 -1
  448. package/dist/icons/ForwardIcon.js +1 -1
  449. package/dist/icons/GripVerticalIcon.js +1 -1
  450. package/dist/icons/HierarchyIcon.js +1 -1
  451. package/dist/icons/HierarchyOpenIcon.js +1 -1
  452. package/dist/icons/Icon.js +1 -1
  453. package/dist/icons/InfoCircleIcon.js +1 -1
  454. package/dist/icons/InfoIcon.js +1 -1
  455. package/dist/icons/KeyIcon.js +1 -1
  456. package/dist/icons/LeftIcon.js +1 -1
  457. package/dist/icons/LineChartIcon.js +1 -1
  458. package/dist/icons/LoadingIcon.js +1 -1
  459. package/dist/icons/LockFilledIcon.js +1 -1
  460. package/dist/icons/LockIcon.js +1 -1
  461. package/dist/icons/MoreIcon.js +1 -1
  462. package/dist/icons/NotAllowedIcon.js +1 -1
  463. package/dist/icons/Number123Icon.js +1 -1
  464. package/dist/icons/NumberIcon.js +1 -1
  465. package/dist/icons/PauseCircleFilledIcon.js +1 -1
  466. package/dist/icons/PauseCircleIcon.js +1 -1
  467. package/dist/icons/PauseIcon.js +1 -1
  468. package/dist/icons/PercentageIcon.js +1 -1
  469. package/dist/icons/PieChartIcon.js +1 -1
  470. package/dist/icons/PipetteIcon.js +1 -1
  471. package/dist/icons/PlayCircleIcon.js +1 -1
  472. package/dist/icons/PlayIcon.js +1 -1
  473. package/dist/icons/PlusIcon.js +1 -1
  474. package/dist/icons/ProgressBarIcon.js +1 -1
  475. package/dist/icons/ReloadIcon.js +1 -1
  476. package/dist/icons/ReportIcon.js +1 -1
  477. package/dist/icons/ReturnIcon.js +1 -1
  478. package/dist/icons/RightIcon.js +1 -1
  479. package/dist/icons/RowTotalsIcon.js +1 -1
  480. package/dist/icons/SchemeIcon.js +1 -1
  481. package/dist/icons/SearchIcon.js +1 -1
  482. package/dist/icons/SemanticQueryIcon.js +1 -1
  483. package/dist/icons/SettingsIcon.js +1 -1
  484. package/dist/icons/ShieldFilledIcon.js +1 -1
  485. package/dist/icons/ShieldIcon.js +1 -1
  486. package/dist/icons/SlashIcon.js +1 -1
  487. package/dist/icons/SparklesIcon.js +1 -1
  488. package/dist/icons/SqlIcon.js +1 -1
  489. package/dist/icons/StatsIcon.js +1 -1
  490. package/dist/icons/StopIcon.js +1 -1
  491. package/dist/icons/StringIcon.js +1 -1
  492. package/dist/icons/SubtotalsIcon.js +1 -1
  493. package/dist/icons/SwitchIcon.js +1 -1
  494. package/dist/icons/TableIcon.js +1 -1
  495. package/dist/icons/ThumbsDownIcon.js +1 -1
  496. package/dist/icons/ThumbsUpIcon.js +1 -1
  497. package/dist/icons/ThunderboltCrossedIcon.js +1 -1
  498. package/dist/icons/ThunderboltFilledIcon.js +1 -1
  499. package/dist/icons/ThunderboltIcon.js +1 -1
  500. package/dist/icons/TimeIcon.js +1 -1
  501. package/dist/icons/TrashIcon.js +1 -1
  502. package/dist/icons/UnlockIcon.js +1 -1
  503. package/dist/icons/UpIcon.js +1 -1
  504. package/dist/icons/UserGroupIcon.js +1 -1
  505. package/dist/icons/UserIcon.js +1 -1
  506. package/dist/icons/UserLockIcon.js +1 -1
  507. package/dist/icons/ViewIcon.js +1 -1
  508. package/dist/icons/WarningFilledIcon.js +1 -1
  509. package/dist/icons/WarningIcon.js +1 -1
  510. package/dist/icons/wrap-icon.js +1 -1
  511. package/dist/index.d.ts +6 -3
  512. package/dist/index.js +4 -3
  513. package/dist/index.js.map +1 -1
  514. package/dist/probe/canonicalize.js +1 -1
  515. package/dist/probe/css.js +1 -1
  516. package/dist/probe/index.js +1 -1
  517. package/dist/provider.js +1 -1
  518. package/dist/providers/TrackingProvider.js +1 -1
  519. package/dist/providers/navigationAdapter.default.js +1 -1
  520. package/dist/tokens/all-tokens.d.ts +10 -0
  521. package/dist/tokens/{index.js → all-tokens.js} +7 -25
  522. package/dist/tokens/all-tokens.js.map +1 -0
  523. package/dist/tokens/base.js +2 -1
  524. package/dist/tokens/base.js.map +1 -1
  525. package/dist/tokens/color-seed.js +1 -1
  526. package/dist/tokens/color-theme.js +1 -1
  527. package/dist/tokens/colors.js +1 -1
  528. package/dist/tokens/index.d.ts +3 -10
  529. package/dist/tokens/layout.js +1 -1
  530. package/dist/tokens/lazy-styles.js +1 -1
  531. package/dist/tokens/palette-config.js +1 -1
  532. package/dist/tokens/palette.js +1 -1
  533. package/dist/tokens/resolve.d.ts +113 -0
  534. package/dist/tokens/resolve.js +403 -0
  535. package/dist/tokens/resolve.js.map +1 -0
  536. package/dist/tokens/shadows.js +1 -1
  537. package/dist/tokens/sizes.js +1 -1
  538. package/dist/tokens/spacing.js +1 -1
  539. package/dist/tokens/typography.js +1 -1
  540. package/dist/utils/ResizeSensor.js +1 -1
  541. package/dist/utils/is-dev-env.js +1 -1
  542. package/dist/utils/modules.js +1 -1
  543. package/dist/utils/promise.js +1 -1
  544. package/dist/utils/raf.js +1 -1
  545. package/dist/utils/random.js +1 -1
  546. package/dist/utils/range.js +1 -1
  547. package/dist/utils/react/RenderCache.js +1 -1
  548. package/dist/utils/react/Slots.js +1 -1
  549. package/dist/utils/react/chain.js +1 -1
  550. package/dist/utils/react/disabledProps.js +1 -1
  551. package/dist/utils/react/forwardRefWithGenerics.js +1 -1
  552. package/dist/utils/react/index.js +1 -1
  553. package/dist/utils/react/interactions.js +1 -1
  554. package/dist/utils/react/isTextOnly.js +1 -1
  555. package/dist/utils/react/mapProps.js +1 -1
  556. package/dist/utils/react/mergeProps.js +1 -1
  557. package/dist/utils/react/nullableValue.js +1 -1
  558. package/dist/utils/react/resolveIcon.js +1 -1
  559. package/dist/utils/react/sharedStore.js +1 -1
  560. package/dist/utils/react/useBufferedValue.js +1 -1
  561. package/dist/utils/react/useCombinedRefs.js +1 -1
  562. package/dist/utils/react/useControlledFocusVisible.js +1 -1
  563. package/dist/utils/react/useEventBus.js +1 -1
  564. package/dist/utils/react/useId.js +1 -1
  565. package/dist/utils/react/useIsDarwin.js +1 -1
  566. package/dist/utils/react/useKeySymbols.js +1 -1
  567. package/dist/utils/react/useLayoutEffect.js +1 -1
  568. package/dist/utils/react/useLocalStorage.js +1 -1
  569. package/dist/utils/react/useMergeStyles.js +1 -1
  570. package/dist/utils/react/usePopoverSync.js +1 -1
  571. package/dist/utils/react/useQaProps.js +1 -1
  572. package/dist/utils/react/useViewportSize.js +1 -1
  573. package/dist/utils/react/wrapNodeIfPlain.js +1 -1
  574. package/dist/utils/selection.js +1 -1
  575. package/dist/utils/styles.js +1 -1
  576. package/dist/utils/tree.js +1 -1
  577. package/dist/utils/warnings.js +1 -1
  578. package/dist/version.js +3 -3
  579. package/docs/Colors.md +16 -40
  580. package/docs/ComplexLayout.md +8 -0
  581. package/docs/CreateComponent.md +15 -8
  582. package/docs/Introduction.md +15 -36
  583. package/docs/RenderCache.md +8 -6
  584. package/docs/Theming.md +164 -497
  585. package/docs/Usage.md +129 -138
  586. package/docs/Utilities.md +2 -2
  587. package/docs/components/CollectionItem.md +1 -0
  588. package/docs/components/actions/Banner.md +1 -0
  589. package/docs/components/actions/Button.md +8 -36
  590. package/docs/components/actions/ButtonSplit.md +2 -0
  591. package/docs/components/actions/CommandMenu.md +8 -8
  592. package/docs/components/actions/ItemButton.md +6 -20
  593. package/docs/components/actions/Link.md +10 -5
  594. package/docs/components/actions/Menu.md +24 -11
  595. package/docs/components/actions/MenuTrigger.md +3 -12
  596. package/docs/components/actions/use-anchored-menu.md +5 -5
  597. package/docs/components/actions/use-context-menu.md +11 -7
  598. package/docs/components/content/Badge.md +3 -0
  599. package/docs/components/content/HotKeys.md +21 -14
  600. package/docs/components/content/InlineInput.md +14 -14
  601. package/docs/components/content/Item.md +25 -17
  602. package/docs/components/content/ItemCard.md +1 -0
  603. package/docs/components/content/Layout.md +12 -1
  604. package/docs/components/content/PrismCode.md +13 -18
  605. package/docs/components/content/Tag.md +1 -1
  606. package/docs/components/content/TextItem.md +5 -3
  607. package/docs/components/content/Tree.md +69 -154
  608. package/docs/components/data/DataTable.md +56 -168
  609. package/docs/components/data/ItemTable.md +182 -485
  610. package/docs/components/fields/Checkbox.md +2 -0
  611. package/docs/components/fields/ColorInput.md +38 -79
  612. package/docs/components/fields/ColorPicker.md +17 -39
  613. package/docs/components/fields/ColorSwatch.md +11 -30
  614. package/docs/components/fields/ColorSwatchGroup.md +18 -42
  615. package/docs/components/fields/ComboBox.md +13 -1
  616. package/docs/components/fields/CommandTextArea.md +10 -37
  617. package/docs/components/fields/DatePicker.md +3 -0
  618. package/docs/components/fields/FileInput.md +3 -0
  619. package/docs/components/fields/FilterListBox.md +34 -14
  620. package/docs/components/fields/FilterPicker.md +33 -16
  621. package/docs/components/fields/HueSlider.md +5 -5
  622. package/docs/components/fields/ListBox.md +35 -9
  623. package/docs/components/fields/NumberInput.md +3 -0
  624. package/docs/components/fields/PasswordInput.md +3 -0
  625. package/docs/components/fields/PeriodPicker.md +7 -17
  626. package/docs/components/fields/Picker.md +54 -29
  627. package/docs/components/fields/RadioGroup.md +13 -5
  628. package/docs/components/fields/SearchComboBox.md +3 -0
  629. package/docs/components/fields/SearchInput.md +4 -2
  630. package/docs/components/fields/Select.md +23 -13
  631. package/docs/components/fields/Switch.md +3 -0
  632. package/docs/components/fields/TextInput.md +3 -0
  633. package/docs/components/fields/TextInputMapper.md +1 -2
  634. package/docs/components/form/Field.md +5 -2
  635. package/docs/components/form/Form.md +5 -0
  636. package/docs/components/form/FormInstance.md +1 -1
  637. package/docs/components/helpers/DisplayTransition.md +10 -6
  638. package/docs/components/helpers/IconSwitch.md +1 -0
  639. package/docs/components/layout/Board.md +79 -213
  640. package/docs/components/navigation/Pagination.md +36 -75
  641. package/docs/components/navigation/Tabs.md +3 -15
  642. package/docs/components/other/Calendar.md +22 -39
  643. package/docs/components/other/CubeLogo.md +1 -1
  644. package/docs/components/overlays/Dialog.md +3 -0
  645. package/docs/components/overlays/DialogContainer.md +2 -0
  646. package/docs/components/overlays/DialogForm.md +6 -2
  647. package/docs/components/overlays/DialogTrigger.md +4 -2
  648. package/docs/components/overlays/Notifications.md +7 -0
  649. package/docs/components/overlays/Toast.md +12 -8
  650. package/docs/components/overlays/Tooltip.md +7 -3
  651. package/docs/components/overlays/UseDialogContainer.md +16 -10
  652. package/docs/components/status/LoadingAnimation.md +3 -9
  653. package/docs/tasty/configuration.md +195 -15
  654. package/docs/tasty/dsl.md +40 -5
  655. package/docs/tasty/injector.md +11 -0
  656. package/docs/tasty/methodology.md +1 -1
  657. package/docs/tasty/pipeline.md +1 -4
  658. package/docs/tasty/react-api.md +1 -1
  659. package/docs/tasty/styles.md +8 -1
  660. package/package.json +4 -4
  661. package/dist/components/fields/ListBoxPopover/useCompositeFocus.d.ts +0 -2
  662. package/dist/components/portal/PortalProvider.d.ts +0 -2
  663. package/dist/tokens/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Board.js","names":["mergeProps"],"sources":["../../../../src/components/layout/Board/Board.tsx"],"sourcesContent":["import { useResizeObserver } from '@react-aria/utils';\nimport {\n AllBaseProps,\n CONTAINER_STYLES,\n ContainerStyleProps,\n filterBaseProps,\n mergeStyles,\n Styles,\n tasty,\n} from '@tenphi/tasty';\nimport {\n forwardRef,\n ReactNode,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport { useFocusWithin } from 'react-aria';\n\nimport { useEvent } from '../../../_internal/hooks';\nimport { useI18n } from '../../../i18n';\nimport { mergeProps, useCombinedRefs } from '../../../utils/react';\nimport { extractStyles } from '../../../utils/styles';\n\nimport {\n BoardEntry,\n BoardGridLinesContext,\n BoardMetrics,\n BoardMetricsContext,\n useBoardGridLines,\n useBoardHost,\n useBoardMetrics,\n useBoardRegistry,\n} from './board-context';\nimport { BoardProvider } from './BoardProvider';\nimport {\n applySizeConstraints,\n bottom,\n calcGridColWidth,\n calcGridItemPosition,\n calcWH,\n cloneLayout,\n CollisionMode,\n Compactor,\n CompactType,\n correctBounds,\n defaultConstraints,\n getAllCollisions,\n getCompactor,\n getLayoutItem,\n LayoutConstraint,\n LayoutItem,\n modifyLayout,\n Position,\n PositionParams,\n ResizeHandleAxis,\n} from './grid-core';\nimport { useBoardLayout } from './use-board-layout';\nimport { useBoardSelectModifierKey } from './use-board-select-modifier-key';\nimport { BoardSelectionMode, useBoardSelection } from './use-board-selection';\nimport { ResizePhase, WidgetHost } from './WidgetHost';\n\nimport type { BoardResizeGripPlacement, CubeBoardWidgetProps } from './Widget';\n\nconst BoardElement = tasty({\n qa: 'Board',\n styles: {\n position: 'relative',\n display: 'block',\n width: '100%',\n flexGrow: 1,\n height: 'min 0',\n fill: '#surface',\n boxSizing: 'border-box',\n // The board takes focus programmatically (never by Tab — it is `tabIndex=-1`)\n // as a parking spot: after `onWidgetsDelete` the focused widget host is\n // about to unmount, and after a marquee focus is nowhere near the board, so\n // in both cases Escape and Delete — handled here rather than on `document` —\n // would have nothing to reach. A focus ring on a parking spot is noise: it\n // announces a state the user cannot act on and did not ask for. Same reason\n // `Dialog` drops it on its own focusable container.\n outline: 0,\n // A lasso is a widget gesture, not a text gesture: without this, dragging a\n // band across the widgets paints a native text selection under it and leaves\n // stray highlighted text behind. `WidgetHost` does the same for a widget\n // drag (`'drag | resizing'`), which the marquee never goes through.\n userSelect: {\n '': 'auto',\n marquee: 'none',\n },\n },\n});\n\nconst ContentLayer = tasty({\n styles: {\n position: 'absolute',\n inset: 0,\n },\n});\n\n// The drop-slot preview. `#primary` rather than the legacy `#purple` alias -\n// same hue, current token. It has to stay distinguishable from a *selected*\n// widget (a tint + solid border + ring, see `WidgetHost`) and from a live\n// marquee (dashed), since all three can be on screen at once.\nconst PlaceholderElement = tasty({\n qa: 'BoardPlaceholder',\n styles: {\n position: 'absolute',\n top: 0,\n left: 0,\n fill: '#primary.10',\n radius: '1cr',\n border: '#primary.40',\n zIndex: 2,\n pointerEvents: 'none',\n transition: 'inset 80ms linear, width 80ms linear, height 80ms linear',\n boxSizing: 'border-box',\n },\n});\n\n// The rubber-band selection rectangle. Dashed is the discriminator: nothing else\n// on a board is dashed, and it reads as a transient lasso rather than a place\n// something is about to land. Sits above the widgets (1) and the placeholder (2).\nconst MarqueeElement = tasty({\n qa: 'BoardMarquee',\n styles: {\n position: 'absolute',\n top: 0,\n left: 0,\n fill: '#primary-accent-surface.06',\n border: '1bw dashed #primary-border',\n radius: '1cr',\n zIndex: 3,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n});\n\n// Visually-hidden live region. Selection changes are announced here because a\n// board widget cannot carry `aria-selected`: that attribute is only valid on\n// collection roles (`option`, `gridcell`, `row`, …) whose children must be\n// presentational, and widgets host arbitrary interactive content. This element\n// also owns the shared \"Selected\" hint every selected host points at via\n// `aria-describedby`.\nconst A11yLayer = tasty({\n styles: {\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: 0,\n margin: '-1px',\n overflow: 'hidden',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n },\n});\n\n// Grid overlay drawn behind the widgets. Each snap cell is painted as a faint\n// block (column stripes intersected with a row-band alpha mask); the margin gaps\n// between cells stay transparent. The element is positioned as an explicit\n// rectangle inset by the board's resolved padding and sized to the grid content\n// so the padding reads as a symmetric frame on every edge. Its size, position\n// and gradients come from the board's position params via inline `style`. The\n// fill uses the `#border` token (via its CSS var) so it adapts to the scheme.\nconst GridOverlayElement = tasty({\n qa: 'BoardGridOverlay',\n styles: {\n position: 'absolute',\n zIndex: 0,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n opacity: '.5',\n },\n});\n\nexport type BoardCompactType = 'vertical' | 'horizontal' | 'free' | null;\n\n/**\n * Payload passed to the drag/resize lifecycle callbacks. `layout` is the board's\n * current layout at the moment the callback fires, `item` is the affected item\n * (falls back to `oldItem` if the item just left this board via a cross-board\n * transfer), `oldItem` is that item as it was when the gesture started, and\n * `placeholder` is the current drop-slot preview (if any).\n *\n * The plural fields describe the whole gesture: a group drag moves every\n * selected widget at once, so `items`/`oldItems`/`placeholders` list them all,\n * grabbed widget first. An ordinary drag or a resize produces exactly one entry,\n * so `items[0] === item` and `placeholders[0] === placeholder` always hold.\n */\nexport interface BoardInteractionInfo {\n layout: LayoutItem[];\n item: LayoutItem;\n oldItem: LayoutItem;\n placeholder: LayoutItem | null;\n /** Every item in this gesture, grabbed first. */\n items: LayoutItem[];\n /** Those items as they were when the gesture started, same order. */\n oldItems: LayoutItem[];\n /** Every drop-slot preview. Empty exactly when `placeholder` is `null`. */\n placeholders: LayoutItem[];\n}\n\n/** Visibility of the internal grid-line overlay. */\nexport type BoardGridLines = boolean | 'drag' | 'any-drag';\n\n/**\n * The subset of `Board.Widget` props a `Board` can set as defaults for every\n * widget it hosts (via `widgetProps`). Excludes `id`/`children`, which are\n * per-widget. Per-widget `Board.Widget` props override these.\n */\nexport type CubeBoardWidgetDefaults = Omit<\n CubeBoardWidgetProps,\n 'id' | 'children'\n>;\n\nexport interface CubeBoardProps\n extends Omit<\n AllBaseProps,\n 'children' | 'onDragStart' | 'onDrag' | 'onResize'\n >,\n Omit<ContainerStyleProps, 'margin'> {\n /** Stable board id (used for cross-board drag). Auto-generated if omitted. */\n id?: string;\n /** Controlled layout. */\n layout?: LayoutItem[];\n /** Initial layout for uncontrolled usage. */\n defaultLayout?: LayoutItem[];\n onLayoutChange?: (layout: LayoutItem[]) => void;\n /** Called when a drag gesture starts. */\n onDragStart?: (info: BoardInteractionInfo) => void;\n /** Called on every step of a drag gesture. */\n onDrag?: (info: BoardInteractionInfo) => void;\n /** Called when a drag gesture ends (after the layout is committed). */\n onDragStop?: (info: BoardInteractionInfo) => void;\n /** Called when a resize gesture starts. */\n onResizeStart?: (info: BoardInteractionInfo) => void;\n /** Called on every step of a resize gesture. */\n onResize?: (info: BoardInteractionInfo) => void;\n /** Called when a resize gesture ends (after the layout is committed). */\n onResizeStop?: (info: BoardInteractionInfo) => void;\n /** Number of columns. @default 12 */\n cols?: number;\n /**\n * Render exactly this many rows, whatever the content needs — a fixed\n * `cols × rows` matrix rather than a grid that hugs its widgets. Implies a\n * `maxRows` of the same value, so the grid's own bounds constraint keeps every\n * drag and resize inside the matrix. Pair with `rowHeight=\"stretch\"` for a\n * matrix that fills the box it is given.\n */\n rows?: number;\n /**\n * Row height in pixels, or `'stretch'` to divide the board's own measured\n * height into its rows. `'stretch'` is what makes a fixed `rows × cols` matrix\n * fill its container: the board fills the height it is given and each cell\n * takes an equal share of it, so resizing the container resizes the cells\n * instead of adding or removing them.\n *\n * Requires {@link rows}. Without a declared row count there is no matrix to\n * fill, and dividing by the content extent instead would resize every cell\n * whenever a widget landed on a new row — so the mode does not engage and the\n * board keeps its ordinary content-hugging behaviour at the default height.\n * @default 100\n */\n rowHeight?: number | 'stretch';\n /** [horizontal, vertical] margin between widgets in pixels. @default [8, 8] */\n margin?: [number, number];\n /**\n * [horizontal, vertical] padding inside the board. Defaults to `margin`, or\n * to `[0, 0]` for an aligned nested board (`isAligned`) so its grid lines up\n * with the ancestor board's.\n */\n containerPadding?: [number, number];\n /** Maximum number of rows. @default Infinity */\n maxRows?: number;\n /**\n * Empty grid rows kept below the content. The board renders this many rows\n * taller than its widgets need, so there is always somewhere to start a\n * marquee and somewhere to drop a widget past the end — a board that hugs its\n * content has neither once the grid is full. Clamped by `maxRows`.\n * @default 0\n */\n extraRows?: number;\n /**\n * Compaction behavior. `'vertical'` / `'horizontal'` reflow widgets to remove\n * gaps; `'free'` places each widget exactly where dropped and never pushes its\n * neighbours (pair with `allowOverlap` to let widgets stack, otherwise moving\n * onto an occupied cell is blocked); `null` disables compaction but still\n * resolves collisions the legacy react-grid-layout way. @default 'vertical'\n */\n compact?: BoardCompactType;\n /** Allow widgets to overlap. @default false */\n allowOverlap?: boolean;\n /** Block movement into occupied cells instead of pushing. @default false */\n preventCollision?: boolean;\n /**\n * How to resolve a drop the grid would otherwise refuse. Only applies where a\n * collision blocks a move - `compact=\"free\"` (which prevents collisions) or an\n * explicit `preventCollision` - and never under `allowOverlap`. `'revert'`\n * snaps the widget back, `'downscale'` shrinks it into the free space at the\n * drop cell. Within this board, `'swap'` trades places with one widget - the one\n * the drop covers most - which takes the cell the drag began at (falling back to\n * `'downscale'`, then `'revert'`). For a widget arriving from another board,\n * `'swap'` never exchanges or reflows destination widgets: the anchor cell must\n * be empty, the incoming widget downscales into the room to its right/below, and\n * an invalid landing cancels the transfer. No mode ever grows a widget, an\n * in-board swap never displaces more than one widget, and a drop that spans two\n * widgets trades with one of them rather than blinking away mid-drag.\n *\n * Applies to single-widget drags. Arrow keys honour it too, but never resize\n * anything: each press is a gesture of its own, so a press that shrank a widget\n * would have nothing to restore from. A multi-widget selection still only moves\n * where it fits outright, and a resize is still blocked by a collision.\n * @default 'revert'\n */\n collisionMode?: CollisionMode;\n /** Enable dragging for all widgets. @default true */\n isDraggable?: boolean;\n /** Enable resizing for all widgets. @default true */\n isResizable?: boolean;\n /** Whether this board accepts widgets dropped from other boards. @default true */\n isDroppable?: boolean;\n /** Which resize handles to show. @default ['se'] */\n resizeHandles?: ResizeHandleAxis[];\n /**\n * Where the corner resize grips sit: `'inside'` tucks them into the widget\n * box, `'corner'` centres each one on the widget's corner so it lines up with a\n * control centred on the opposite corner. Only affects corner handles. Can be\n * overridden per widget on `Board.Widget`.\n * @default 'inside'\n */\n resizeGripPlacement?: BoardResizeGripPlacement;\n /**\n * CSS selector for elements that must not start a pointer drag (e.g. form\n * controls inside a widget: `\"input,textarea,button,a,.no-drag\"`). Does not\n * affect keyboard moves — those only run when the widget host itself is\n * focused. Can be overridden per widget on `Board.Widget`.\n */\n dragCancel?: string;\n /**\n * CSS selector for the only elements from which a pointer drag may start.\n * Can be overridden per widget on `Board.Widget`.\n */\n dragHandle?: string;\n /**\n * Show grid lines behind the widgets. `true` always shows them, `false` never,\n * `'drag'` only while *this* board is part of the active gesture - it owns the\n * drag (as its source or as the board the widget is currently over), or one of\n * its own widgets is being resized. `'any-drag'` widens that to any drag\n * anywhere under a shared `Board.Provider`, so every board advertises itself as\n * a place the widget could land.\n * @default false\n */\n showGridLines?: BoardGridLines;\n /**\n * Align this board's grid with an ancestor `Board`'s layout. Only takes\n * effect when the board is nested inside another `Board`'s widget. When set,\n * every cell matches the parent's cell size exactly: the board inherits the\n * parent's column pitch (deriving its own column count from its measured\n * width) and uses the parent's row height verbatim. It never shrinks rows to\n * fit; pair it with an `isAutoHeight` container so the widget grows to fit its\n * rows at that height. @default false\n */\n isAligned?: boolean;\n /**\n * Whether widgets can be selected, and how many at a time. `'multiple'` also\n * enables the marquee and rigid group movement: dragging any selected widget\n * moves the whole selection. @default 'none'\n */\n selectionMode?: BoardSelectionMode;\n /** Controlled selection. Keys are layout item ids (`LayoutItem.i`). */\n selectedKeys?: string[];\n /** Initial selection for uncontrolled usage. */\n defaultSelectedKeys?: string[];\n /**\n * Called when the selection changes. Keys are deduped and returned in the\n * board's layout order, never in click order.\n */\n onSelectionChange?: (keys: string[]) => void;\n /**\n * CSS selector for descendants whose clicks must never change the selection\n * (form controls, buttons, links). Mirrors `dragCancel`; can be overridden per\n * widget. Pass `''` to disable the guard entirely.\n * @default BOARD_SELECTION_CANCEL\n */\n selectionCancel?: string;\n /**\n * Draw a rubber-band (marquee) selection when a drag starts on empty board\n * space. Only meaningful with `selectionMode=\"multiple\"`.\n * @default selectionMode === 'multiple'\n */\n allowMarqueeSelection?: boolean;\n /**\n * Called when the user presses <kbd>Delete</kbd>/<kbd>Backspace</kbd> with a\n * non-empty selection, and focus is inside the board but not in an editable\n * field. Board never mutates the layout itself — removing the widgets is the\n * consumer's job. Board only handles these keys when this handler is set.\n */\n onWidgetsDelete?: (keys: string[]) => void;\n /** Grid/item layout constraints. */\n constraints?: LayoutConstraint[];\n /**\n * Explicit container width in pixels. When provided, disables automatic width\n * measurement (useful for SSR and tests).\n */\n width?: number;\n /**\n * Default props applied to every widget this board hosts. Per-widget\n * `Board.Widget` props override these. Use it to add a card border to every\n * widget (`widgetProps={{ isCard: true }}`) or set shared sizing/`styles`\n * defaults without repeating them on each `Board.Widget`.\n */\n widgetProps?: Partial<CubeBoardWidgetDefaults>;\n children?: ReactNode;\n}\n\n/**\n * Descendants whose clicks never change the selection. A widget is a large\n * surface the user also clicks to *work with*, so anything interactive inside it\n * must keep its click. `[data-no-select]` is the escape hatch for an app's own\n * custom controls.\n */\nexport const BOARD_SELECTION_CANCEL =\n 'input,textarea,select,button,a,[role=\"button\"],[role=\"menuitem\"],' +\n '[role=\"checkbox\"],[role=\"switch\"],[role=\"tab\"],[contenteditable=\"true\"],' +\n '[data-no-select]';\n\n/**\n * Row height when none is given, and the fallback a `rowHeight=\"stretch\"` board\n * uses until it has both a bounded row count and a measured height to divide.\n */\nconst DEFAULT_ROW_HEIGHT = 100;\n\n/** Manhattan distance a pointer must travel before a press becomes a marquee. */\nconst MARQUEE_THRESHOLD = 4;\n\n/** Shared empty set, so \"no pre-selection\" is a stable reference. */\nconst NO_KEYS: ReadonlySet<string> = new Set();\n\n/**\n * Whether an event landed in a text-editing context. Checking the *event target*\n * beats `document.activeElement`: it stays correct for content rendered through\n * a portal, and it cannot be fooled by focus that moved between the keystroke\n * and the handler.\n */\nfunction isEditableTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null;\n if (!el || typeof el.closest !== 'function') return false;\n\n return !!el.closest('input,textarea,select,[contenteditable=\"true\"]');\n}\n\nfunction compactTypeToCore(compact: BoardCompactType): CompactType {\n if (compact === 'free') return null;\n return compact;\n}\n\nfunction BoardInner(\n props: CubeBoardProps,\n ref: React.ForwardedRef<HTMLDivElement>,\n) {\n const {\n id: providedId,\n layout: controlledLayout,\n defaultLayout,\n onLayoutChange,\n onDragStart,\n onDrag,\n onDragStop,\n onResizeStart,\n onResize: onResizeProp,\n onResizeStop,\n cols = 12,\n rows: fixedRows,\n rowHeight = DEFAULT_ROW_HEIGHT,\n margin = [8, 8],\n containerPadding,\n maxRows: maxRowsProp,\n extraRows = 0,\n compact = 'vertical',\n allowOverlap = false,\n preventCollision = false,\n collisionMode = 'revert',\n isDraggable = true,\n isResizable = true,\n isDroppable = true,\n resizeHandles = ['se'],\n resizeGripPlacement = 'inside',\n dragCancel,\n dragHandle,\n showGridLines,\n isAligned = false,\n selectionMode = 'none',\n selectedKeys,\n defaultSelectedKeys,\n onSelectionChange,\n selectionCancel = BOARD_SELECTION_CANCEL,\n allowMarqueeSelection = selectionMode === 'multiple',\n onWidgetsDelete,\n constraints,\n width: providedWidth,\n widgetProps,\n children,\n ...otherProps\n } = props;\n\n // A fixed row count is also a hard bound: `gridBounds` clamps every drag and\n // resize against `maxRows`, so declaring `rows` is what keeps widgets inside\n // the matrix without the caller restating a per-widget `maxH`.\n const maxRows =\n maxRowsProp ?? (fixedRows != null ? Math.max(1, fixedRows) : Infinity);\n\n const registry = useBoardRegistry()!;\n const parentMetrics = useBoardMetrics();\n const host = useBoardHost();\n const inheritedGridLines = useBoardGridLines();\n const aligned = isAligned && !!parentMetrics;\n // `widgetProps` may carry container style props directly (e.g. `fill`,\n // `padding`, `radius`) alongside an explicit `styles` object, mirroring\n // `Board.Widget`. Extract them into a single style map here so those defaults\n // actually reach every widget - forwarding only `widgetProps.styles` would\n // drop the direct props. A direct prop wins over the same key in `styles`.\n const widgetPropsStyles = useMemo<Styles | undefined>(() => {\n if (!widgetProps) return undefined;\n const extracted = extractStyles(widgetProps, CONTAINER_STYLES);\n return Object.keys(extracted).length > 0 ? extracted : undefined;\n }, [widgetProps]);\n // A nested board with no explicit `showGridLines` inherits the ancestor's:\n // when the ancestor has grid lines enabled, show them here while dragging, at\n // the ancestor's own drag scope (see `BoardInheritedGridLines`).\n const effectiveShowGridLines: BoardGridLines =\n showGridLines ?? inheritedGridLines;\n const generatedId = useId();\n const boardId = providedId ?? generatedId;\n // One shared description node for every selected widget, so marking a widget\n // selected costs no per-widget DOM.\n const selectedHintId = `${generatedId}-selected`;\n const { t } = useI18n();\n\n const containerRef = useCombinedRefs(ref);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const [measuredWidth, setMeasuredWidth] = useState<number>(0);\n // Rendered height is only needed for aligned nested boards (to fit rows into\n // the space the container grants). It never drives the board's own height, so\n // measuring it cannot create a feedback loop.\n const [measuredHeight, setMeasuredHeight] = useState<number>(0);\n const width = providedWidth ?? measuredWidth;\n\n const onResizeContainer = useEvent(() => {\n const el = containerRef.current;\n if (!el) return;\n // A hidden container (e.g. the board inside an inactive tab after a\n // spring-loaded tab switch) reports 0. Keep the last non-zero measurement so\n // the board stays \"ready\" and keeps its widget hosts mounted while briefly\n // hidden. Otherwise the board would render nothing, unmounting the widget\n // that owns an in-flight drag gesture and stranding the drag (React Aria's\n // `useMove` tears down its listeners on unmount, so the drop never fires).\n const nextWidth = el.offsetWidth;\n const nextHeight = el.offsetHeight;\n if (nextWidth > 0) setMeasuredWidth(nextWidth);\n if (nextHeight > 0) setMeasuredHeight(nextHeight);\n });\n useResizeObserver({ ref: containerRef, onResize: onResizeContainer });\n useEffect(() => {\n if (providedWidth == null) {\n onResizeContainer();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [providedWidth]);\n\n const {\n layout,\n layoutRef,\n placeholders,\n placeholder,\n placeholdersRef,\n placeholderRef,\n setPlaceholders,\n applyLayout,\n } = useBoardLayout({\n layout: controlledLayout,\n defaultLayout,\n onLayoutChange,\n });\n\n // The accessible name a widget announces under. Mirrors `WidgetHost`'s own\n // fallback chain so the live region and the host never disagree.\n const getWidgetLabel = useEvent((key: string) => {\n const registration = registry.store.get(key);\n\n return registration?.['aria-label'] ?? registration?.qa ?? key;\n });\n\n // Whether a widget accepts selection at all. Every selection path resolves it\n // here — press, keyboard and marquee — so a lasso can never pick up a widget\n // that a press cannot.\n const isWidgetSelectable = (key: string) =>\n (registry.store.get(key)?.isSelectable ?? widgetProps?.isSelectable) !==\n false;\n\n const {\n selectedKeySet,\n selectedKeysRef,\n setSelection,\n select,\n clearSelection,\n announcement,\n } = useBoardSelection({\n selectionMode,\n selectedKeys,\n defaultSelectedKeys,\n onSelectionChange,\n layout,\n getLabel: getWidgetLabel,\n });\n\n const selectModifierKey = useBoardSelectModifierKey();\n\n // Re-render when any widget's registered content/config changes.\n useSyncExternalStore(registry.store.subscribe, registry.store.getVersion);\n\n // In aligned mode the board inherits the parent's gap so widget edges line up\n // with the surrounding layout; otherwise it uses its own `margin`.\n const effectiveMargin: readonly [number, number] = aligned\n ? parentMetrics!.margin\n : margin;\n // The board keeps its own padding (it sits inside the container's chrome);\n // when unspecified it defaults to the effective gap. An aligned nested board\n // is the exception: its grid origin must sit flush on the container widget's\n // edge (which already coincides with the parent's column-0 origin) so its\n // columns line up with the ancestor board's. Inheriting the gap there would\n // inset every column by one margin and break the alignment, so it defaults\n // to zero padding instead.\n const resolvedPadding: readonly [number, number] =\n containerPadding ?? (aligned ? [0, 0] : effectiveMargin);\n\n const rows = Math.max(\n bottom(layout),\n ...placeholders.map((p) => p.y + p.h),\n 0,\n );\n\n // Rows the board actually paints. `rows` stays the *content* extent — layout\n // math must not see the reserved band — while this is the extent the board\n // renders, so the band is real board surface: `ContentLayer` (inset: 0)\n // covers it, which is what lets a marquee start there and a widget be dropped\n // past the end.\n const renderedRows =\n fixedRows != null\n ? Math.max(1, fixedRows)\n : Math.min(rows + Math.max(0, extraRows), maxRows);\n\n // Derive the aligned column count so each column keeps the parent's pixel\n // pitch: as the container widget is resized, columns are added/removed rather\n // than stretched. `containerWidth` is then back-solved so `calcGridColWidth`\n // returns exactly the parent's column width.\n const parentColWidth = aligned ? parentMetrics!.colWidth : 0;\n // `width` is `offsetWidth` (an integer the browser rounds), while\n // `parentColWidth` is fractional. A container sized to exactly N parent\n // columns can therefore measure a fraction of a pixel short, so a bare\n // `Math.floor` would drop the last column and leave its space unused. Add a\n // small pixel tolerance to absorb that rounding; it only rounds up when the\n // width is within ~2px of a full column, so it can't invent a column that\n // genuinely doesn't fit.\n const ALIGN_WIDTH_TOLERANCE = 2;\n const alignedCols =\n aligned && width > 0\n ? Math.max(\n 1,\n Math.floor(\n (width -\n resolvedPadding[0] * 2 +\n effectiveMargin[0] +\n ALIGN_WIDTH_TOLERANCE) /\n (parentColWidth + effectiveMargin[0]),\n ),\n )\n : cols;\n const effectiveCols = aligned ? alignedCols : cols;\n const effectiveContainerWidth = aligned\n ? parentColWidth * effectiveCols +\n effectiveMargin[0] * Math.max(0, effectiveCols - 1) +\n resolvedPadding[0] * 2\n : width;\n\n // A stretch board divides its own measured height into its rows, so the matrix\n // fills the box it was given and resizing the container resizes the cells.\n //\n // It only does that with a DECLARED row count. Dividing by the content extent\n // instead would resize every cell whenever a widget lands on a new row, and\n // the board would still be claiming its parent's whole height to do it — so\n // without `rows` there is no matrix to fill and the board keeps its ordinary\n // content-hugging behaviour at the default row height.\n const isStretching = rowHeight === 'stretch' && fixedRows != null;\n const stretchedRowHeight =\n isStretching && measuredHeight > 0\n ? Math.max(\n 1,\n (measuredHeight -\n Math.max(0, renderedRows - 1) * effectiveMargin[1] -\n resolvedPadding[1] * 2) /\n renderedRows,\n )\n : // Not measured yet (first paint) or not a matrix at all: a real pixel\n // height keeps the board renderable rather than collapsing it.\n DEFAULT_ROW_HEIGHT;\n\n // An aligned board uses the parent's row height verbatim, so every cell is\n // exactly the parent's cell size (width already matches via the inherited\n // column pitch). It never shrinks rows to fit; pair it with an `isAutoHeight`\n // container so the widget grows to fit the rows at this height instead.\n const effectiveRowHeight = aligned\n ? parentMetrics!.rowHeight\n : rowHeight === 'stretch'\n ? stretchedRowHeight\n : rowHeight;\n\n const positionParams = useMemo<PositionParams>(\n () => ({\n margin: effectiveMargin,\n containerPadding: resolvedPadding,\n containerWidth: effectiveContainerWidth,\n cols: effectiveCols,\n rowHeight: effectiveRowHeight,\n maxRows,\n }),\n [\n effectiveMargin[0],\n effectiveMargin[1],\n resolvedPadding[0],\n resolvedPadding[1],\n effectiveContainerWidth,\n effectiveCols,\n effectiveRowHeight,\n maxRows,\n ],\n );\n\n // 'free' means no compaction (nothing is pushed up/left or recompacted) AND a\n // dragged widget never pushes or swaps its neighbours: it is placed exactly\n // where dropped. Without `allowOverlap` a move onto an occupied cell is\n // blocked (the widget stays at its last free spot); with `allowOverlap`\n // widgets may stack. The explicit `preventCollision` prop still applies to the\n // compacting modes (`vertical` / `horizontal`) and to the legacy `null` mode.\n const compactor = useMemo<Compactor>(\n () =>\n getCompactor(\n compactTypeToCore(compact),\n allowOverlap,\n compact === 'free' ? !allowOverlap : preventCollision,\n ),\n [compact, allowOverlap, preventCollision],\n );\n\n const resolvedConstraints = constraints ?? defaultConstraints;\n\n const computedHeight =\n renderedRows > 0\n ? renderedRows * effectiveRowHeight +\n Math.max(0, renderedRows - 1) * effectiveMargin[1] +\n resolvedPadding[1] * 2\n : effectiveRowHeight;\n // An aligned or stretching board fills the height the container grants it, so\n // it reports its measured height; otherwise it reports the height its content\n // needs.\n const containerHeight =\n (aligned || isStretching) && measuredHeight > 0\n ? measuredHeight\n : computedHeight;\n\n // Live refs so the stable registry entry always reads current values.\n const liveRef = useRef({\n positionParams,\n compactor,\n collisionMode,\n constraints: resolvedConstraints,\n maxRows,\n containerHeight,\n isDroppable,\n });\n liveRef.current = {\n positionParams,\n compactor,\n collisionMode,\n constraints: resolvedConstraints,\n maxRows,\n containerHeight,\n isDroppable,\n };\n\n const applyLayoutEvent = useEvent(applyLayout);\n const setPlaceholdersEvent = useEvent(setPlaceholders);\n\n const entryRef = useRef<BoardEntry | null>(null);\n if (!entryRef.current) {\n entryRef.current = {\n id: boardId,\n getContentRect: () => contentRef.current?.getBoundingClientRect() ?? null,\n getContentNode: () => contentRef.current,\n getPositionParams: () => liveRef.current.positionParams,\n getConstraints: () => liveRef.current.constraints,\n getCompactor: () => liveRef.current.compactor,\n getCollisionMode: () => liveRef.current.collisionMode,\n getMaxRows: () => liveRef.current.maxRows,\n getContainerHeight: () => liveRef.current.containerHeight,\n getLayout: () => layoutRef.current,\n // The registry reads this synchronously at drag start, so it must be the\n // ref rather than the rendered value.\n getSelectedKeys: () =>\n selectedKeysRef.current.size > 0 ? selectedKeysRef.current : null,\n applyLayout: (next, commit) => applyLayoutEvent(next, commit),\n setPlaceholders: (items) => setPlaceholdersEvent(items),\n isDroppable: () => liveRef.current.isDroppable,\n };\n }\n\n useEffect(() => {\n const entry = entryRef.current!;\n // Keep the entry's id in sync with the (possibly changed) board id before\n // registering. The previous effect's cleanup has already removed the old id,\n // so registering here keys the entry under the current id.\n entry.id = boardId;\n return registry.registerBoard(entry);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [boardId]);\n\n // When the aligned column count changes (the container was resized), reflow\n // the layout to the new width: clamp items back into bounds and recompact so\n // nothing overflows the narrower/wider grid.\n const recompactForCols = useEvent((nextCols: number) => {\n const corrected = correctBounds(cloneLayout(layoutRef.current), {\n cols: nextCols,\n });\n const compacted = [\n ...liveRef.current.compactor.compact(corrected, nextCols),\n ];\n applyLayoutEvent(compacted, true);\n });\n // `null` until the first *measured* aligned column count is established. This\n // avoids treating the initial zero-width -> measured-width transition as a\n // column-count change: a board that measures its own width (no explicit\n // `width` prop) renders first with `width === 0`, so `effectiveCols` falls\n // back to `cols` and only becomes the derived aligned count once measured.\n // Seeding the baseline on that first measured value (without committing)\n // prevents an unsolicited reflow + `onLayoutChange` before the user interacts.\n const prevAlignedColsRef = useRef<number | null>(null);\n useEffect(() => {\n if (!aligned) {\n // Re-entering aligned mode should re-seed from the next measured value.\n prevAlignedColsRef.current = null;\n return;\n }\n // Wait for a real width measurement; the fallback-`cols` value that stands\n // in before measurement is not a meaningful aligned column count.\n if (width <= 0) return;\n if (prevAlignedColsRef.current === null) {\n prevAlignedColsRef.current = effectiveCols;\n return;\n }\n if (prevAlignedColsRef.current === effectiveCols) return;\n prevAlignedColsRef.current = effectiveCols;\n recompactForCols(effectiveCols);\n }, [aligned, width, effectiveCols, recompactForCols]);\n\n // Natural height this board wants: its rows at the (parent) row height. When\n // the container is shorter than this, an `isAutoHeight` host grows to fit it\n // (aligned boards no longer shrink their rows).\n const naturalHeight =\n renderedRows > 0\n ? renderedRows * effectiveRowHeight +\n Math.max(0, renderedRows - 1) * effectiveMargin[1] +\n resolvedPadding[1] * 2\n : effectiveRowHeight;\n\n // Report this aligned board's height deficit to an auto-sizing host so the\n // host can both grow to fit and pin its resize floor. The value is signed:\n // positive when the board is squeezed (needs more height), negative when the\n // container is taller than needed (so the floor can be lowered). The host\n // never shrinks the widget on its own - it only grows and clamps resizing.\n const requestHeightDeficit = host?.requestHeightDeficit;\n useEffect(() => {\n if (!aligned || !host?.isAutoHeight || !requestHeightDeficit) return;\n if (measuredHeight <= 0) return;\n requestHeightDeficit(naturalHeight - measuredHeight);\n }, [\n aligned,\n host?.isAutoHeight,\n requestHeightDeficit,\n naturalHeight,\n measuredHeight,\n ]);\n\n // In-board resize orchestration.\n const resizeStateRef = useRef<{\n id: string;\n axis: ResizeHandleAxis;\n item: LayoutItem;\n origin: Position;\n accX: number;\n accY: number;\n } | null>(null);\n\n // Minimum rows each auto-height widget currently needs to fit its content.\n // Read during resize so a widget can never be dragged shorter than its\n // content, and used to grow the item when the content needs more room.\n const autoHeightMinRowsRef = useRef<Record<string, number>>({});\n\n const handleResize = useEvent(\n (\n id: string,\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => {\n const pp = liveRef.current.positionParams;\n\n if (phase === 'start') {\n const rawItem = getLayoutItem(layoutRef.current, id);\n if (!rawItem) return;\n // Layout-item min/max and constraints win; otherwise fall back to the\n // ones declared on the owning `Board.Widget` (and then the board-level\n // `widgetProps` defaults) so `applySizeConstraints` (via `minMaxSize`)\n // picks them up.\n const reg = registry.store.get(id);\n const item: LayoutItem = {\n ...rawItem,\n minW: rawItem.minW ?? reg?.minW ?? widgetProps?.minW,\n maxW: rawItem.maxW ?? reg?.maxW ?? widgetProps?.maxW,\n minH: rawItem.minH ?? reg?.minH ?? widgetProps?.minH,\n maxH: rawItem.maxH ?? reg?.maxH ?? widgetProps?.maxH,\n constraints:\n rawItem.constraints ?? reg?.constraints ?? widgetProps?.constraints,\n };\n resizeStateRef.current = {\n id,\n axis,\n item: { ...item },\n origin: calcGridItemPosition(pp, item.x, item.y, item.w, item.h),\n accX: 0,\n accY: 0,\n };\n setPlaceholders([{ ...item }]);\n onResizeStart?.({\n layout: layoutRef.current,\n item: { ...item },\n oldItem: { ...item },\n placeholder: { ...item },\n items: [{ ...item }],\n oldItems: [{ ...item }],\n placeholders: [{ ...item }],\n });\n return;\n }\n\n const rs = resizeStateRef.current;\n if (!rs) return;\n\n if (phase === 'end') {\n const finalLayout = [...layoutRef.current];\n applyLayout(finalLayout, true);\n setPlaceholders([]);\n const resizedItem = getLayoutItem(finalLayout, id) ?? rs.item;\n onResizeStop?.({\n layout: finalLayout,\n item: resizedItem,\n oldItem: rs.item,\n placeholder: null,\n items: [resizedItem],\n oldItems: [rs.item],\n placeholders: [],\n });\n resizeStateRef.current = null;\n return;\n }\n\n rs.accX += dx;\n rs.accY += dy;\n\n const { origin, item, axis: handle } = rs;\n let newW = origin.width;\n let newH = origin.height;\n if (handle.includes('e')) newW = origin.width + rs.accX;\n if (handle.includes('w')) newW = origin.width - rs.accX;\n if (handle.includes('s')) newH = origin.height + rs.accY;\n if (handle.includes('n')) newH = origin.height - rs.accY;\n newW = Math.max(newW, 8);\n newH = Math.max(newH, 8);\n\n const raw = calcWH(pp, newW, newH, item.x, item.y, handle);\n const constrained = applySizeConstraints(\n liveRef.current.constraints,\n item,\n raw.w,\n raw.h,\n handle,\n {\n cols: pp.cols,\n maxRows: liveRef.current.maxRows,\n containerWidth: pp.containerWidth,\n containerHeight: liveRef.current.containerHeight,\n rowHeight: pp.rowHeight,\n margin: pp.margin,\n layout: layoutRef.current,\n },\n );\n\n // An auto-height widget cannot be resized shorter than the content it\n // hosts (a nested board) currently needs, so pin its height to the floor.\n const floorRows = autoHeightMinRowsRef.current[id] ?? 0;\n const finalW = constrained.w;\n const finalH = Math.max(constrained.h, floorRows);\n\n let x = item.x;\n let y = item.y;\n if (handle.includes('w')) x = item.x + item.w - finalW;\n if (handle.includes('n')) y = item.y + item.h - finalH;\n x = Math.max(0, x);\n y = Math.max(0, y);\n\n let newItem: LayoutItem = {\n ...item,\n x,\n y,\n w: finalW,\n h: finalH,\n };\n\n // Collision-blocking modes (`free` without `allowOverlap`, or an explicit\n // `preventCollision`) run a no-op/gap-filling compactor that never\n // resolves overlaps, so a resize must be blocked here the same way the\n // drag path blocks a move (`moveElement` reverts on collision). Without\n // this, growing or moving an edge via a resize handle could push the box\n // onto an occupied cell. When the new box overlaps a neighbour, revert to\n // the last committed box for this widget so the gesture stalls at the\n // last valid size/position instead of overlapping.\n const compactor = liveRef.current.compactor;\n if (compactor.preventCollision && !compactor.allowOverlap) {\n const collides = getAllCollisions(layoutRef.current, newItem).some(\n (other) => other.i !== id,\n );\n if (collides) {\n const lastValid = getLayoutItem(layoutRef.current, id);\n if (lastValid) newItem = { ...lastValid };\n }\n }\n\n const working = modifyLayout(layoutRef.current, newItem);\n const compacted = [...compactor.compact(working, pp.cols)];\n applyLayout(compacted, false);\n const nextPlaceholder = getLayoutItem(compacted, id) ?? newItem;\n setPlaceholders([nextPlaceholder]);\n const resizedItem = getLayoutItem(compacted, id) ?? newItem;\n onResizeProp?.({\n layout: compacted,\n item: resizedItem,\n oldItem: rs.item,\n placeholder: nextPlaceholder,\n items: [resizedItem],\n oldItems: [rs.item],\n placeholders: [nextPlaceholder],\n });\n },\n );\n\n // Record an auto-height widget's needed rows. Grow the item when its content\n // needs more height (only ever increases); the stored value is also the\n // resize floor enforced in `handleResize`.\n const handleAutoHeight = useEvent((id: string, neededRows: number) => {\n autoHeightMinRowsRef.current[id] = neededRows;\n const current = getLayoutItem(layoutRef.current, id);\n if (!current || neededRows <= current.h) return;\n // While a drag or resize gesture is in flight the layout is transient - the\n // registry (drag) and `handleResize` write uncommitted previews and commit\n // only on drop / release. Growing an auto-height widget here with\n // `commit: true` would fire `onLayoutChange` mid-gesture and persist the\n // in-flight positions of the widget being moved. Skip the grow-commit; the\n // floor ref is already updated above (so `handleResize` still respects it),\n // and the deficit effect re-fires once the gesture settles.\n if (registry.dragState || resizeStateRef.current) return;\n const pp = liveRef.current.positionParams;\n const working = modifyLayout(layoutRef.current, {\n ...current,\n h: neededRows,\n });\n const compacted = [...liveRef.current.compactor.compact(working, pp.cols)];\n applyLayout(compacted, true);\n });\n\n // The dragged item captured at gesture start, so drag callbacks can report the\n // original position throughout (and after a cross-board transfer removes the\n // item from this board's layout).\n const dragOldItemRef = useRef<LayoutItem | null>(null);\n // The same, for every other member of a group drag. Empty for an ordinary\n // drag, which is what keeps `items`/`oldItems` single-entry there.\n const dragOldItemsRef = useRef<LayoutItem[]>([]);\n\n const handleDragLifecycle = useEvent((id: string, phase: ResizePhase) => {\n const currentLayout = layoutRef.current;\n const liveItem = getLayoutItem(currentLayout, id);\n\n if (phase === 'start') {\n dragOldItemRef.current = liveItem ? { ...liveItem } : null;\n // The registry has already resolved the group by the time this fires, so\n // its drag state is the authority on who is moving.\n const ds = registry.getDragState();\n dragOldItemsRef.current =\n ds && ds.itemId === id ? ds.items.map((it) => ({ ...it })) : [];\n }\n const oldItem = dragOldItemRef.current ?? liveItem;\n if (!oldItem) return;\n const item = liveItem ?? oldItem;\n\n const oldItems = dragOldItemsRef.current.length\n ? dragOldItemsRef.current\n : [oldItem];\n const items = oldItems.map(\n (old) => getLayoutItem(currentLayout, old.i) ?? old,\n );\n\n const info: BoardInteractionInfo = {\n layout: currentLayout,\n item,\n oldItem,\n // Read the live refs, not render-time state: the registry calls\n // `setPlaceholders` synchronously right before this fires, and that only\n // schedules a re-render, so `placeholders` state still holds the previous\n // value (or a stale preview after the drop clears it).\n placeholder: placeholderRef.current,\n items,\n oldItems,\n placeholders: placeholdersRef.current,\n };\n if (phase === 'start') onDragStart?.(info);\n else if (phase === 'move') onDrag?.(info);\n else {\n onDragStop?.(info);\n dragOldItemRef.current = null;\n dragOldItemsRef.current = [];\n }\n });\n\n // ---- Marquee (rubber-band) selection --------------------------------------\n //\n // Board owns this rather than exposing hooks for an app to build it, because\n // deciding which widgets a band covers needs every widget's box — and the DOM\n // is the wrong place to read them from. Widget hosts transition `inset`/`width`\n // /`height` while the board reflows, and a host being dragged is swapped for an\n // `opacity: 0` stand-in with a fixed-position clone in the overlay, so\n // `getBoundingClientRect` during a marquee returns interpolated or misleading\n // boxes. `calcGridItemPosition` derives the same rectangles exactly, from the\n // layout, with no forced reflow and no sensitivity to ancestor transforms.\n const [marqueeRect, setMarqueeRect] = useState<Position | null>(null);\n // Which widgets the band covers *right now*. Committing only on release\n // leaves the user guessing what they are about to select, so the band drives a\n // provisional state on the hosts as it grows and shrinks. The board already\n // re-renders once per pointer frame for the band itself, so this is free.\n const [preSelectedKeys, setPreSelectedKeys] =\n useState<ReadonlySet<string>>(NO_KEYS);\n // Drives `user-select: none` for the duration of the gesture. Set on press\n // rather than at the threshold, so even a press that never becomes a marquee\n // cannot start painting a text selection.\n const [isMarqueeActive, setIsMarqueeActive] = useState(false);\n\n const handleContentPointerDown = useEvent((event: React.PointerEvent) => {\n if (\n selectionMode !== 'multiple' ||\n !allowMarqueeSelection ||\n event.button !== 0 ||\n registry.dragState\n ) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n // A press on a widget selects it and arms a drag; the lasso owns empty\n // canvas only.\n if (target?.closest('[data-board-widget-host]')) return;\n if (selectionCancel && target?.closest(selectionCancel)) return;\n\n const content = contentRef.current;\n if (!content) return;\n\n // Suppress the compatibility mouse events that would begin a native text\n // selection. Safe here specifically because every case that wants default\n // behaviour — a widget, an interactive descendant — has already bailed out\n // above, and focus is placed explicitly in `finish`.\n event.preventDefault();\n setIsMarqueeActive(true);\n\n const origin = content.getBoundingClientRect();\n const startX = event.clientX;\n const startY = event.clientY;\n // Holding the modifier means \"add to what I have\"; a bare lasso replaces.\n const additive = event[selectModifierKey] || event.shiftKey;\n const base = additive ? [...selectedKeysRef.current] : [];\n let passedThreshold = false;\n\n const hitTest = (clientX: number, clientY: number) => {\n const left = Math.min(startX, clientX) - origin.left;\n const right = Math.max(startX, clientX) - origin.left;\n const top = Math.min(startY, clientY) - origin.top;\n const bottom = Math.max(startY, clientY) - origin.top;\n const next = new Set(base);\n\n for (const it of layoutRef.current) {\n if (!isWidgetSelectable(it.i)) continue;\n const pos = calcGridItemPosition(\n liveRef.current.positionParams,\n it.x,\n it.y,\n it.w,\n it.h,\n );\n if (\n pos.left < right &&\n pos.left + pos.width > left &&\n pos.top < bottom &&\n pos.top + pos.height > top\n ) {\n next.add(it.i);\n }\n }\n\n return {\n next,\n box: { left, top, width: right - left, height: bottom - top },\n };\n };\n\n // Belt and braces for the `preventDefault` above: a press that starts on\n // empty canvas and then travels into text still gets a `selectstart` in some\n // browsers, and `user-select: none` alone does not unwind a selection that is\n // already growing.\n const blockSelectStart = (e: Event) => e.preventDefault();\n\n const handleMove = (e: PointerEvent) => {\n if (\n !passedThreshold &&\n Math.abs(e.clientX - startX) + Math.abs(e.clientY - startY) <\n MARQUEE_THRESHOLD\n ) {\n return;\n }\n if (!passedThreshold) {\n // Drop a selection the user made inside this board *before* the lasso\n // started, so the band never drags a stale highlight along with it.\n // Scoped to this board: a selection anywhere else on the page is theirs.\n const selection = window.getSelection();\n const anchor = selection?.anchorNode;\n if (anchor && containerRef.current?.contains(anchor)) {\n selection?.removeAllRanges();\n }\n }\n passedThreshold = true;\n\n const { box, next } = hitTest(e.clientX, e.clientY);\n setMarqueeRect(box);\n setPreSelectedKeys(next);\n };\n\n const finish = (e: PointerEvent) => {\n window.removeEventListener('pointermove', handleMove);\n window.removeEventListener('pointerup', finish);\n window.removeEventListener('pointercancel', finish);\n window.removeEventListener('selectstart', blockSelectStart);\n setMarqueeRect(null);\n setPreSelectedKeys(NO_KEYS);\n setIsMarqueeActive(false);\n\n // One commit per gesture: `onSelectionChange` and the announcement fire on\n // release, never once per pointer frame.\n if (passedThreshold) {\n setSelection(hitTest(e.clientX, e.clientY).next);\n } else if (!additive) {\n // A plain click on empty board space clears.\n clearSelection();\n }\n // Keep focus somewhere inside the board so Escape has a handler to reach.\n containerRef.current?.focus({ preventScroll: true });\n };\n\n window.addEventListener('pointermove', handleMove);\n window.addEventListener('pointerup', finish);\n window.addEventListener('pointercancel', finish);\n window.addEventListener('selectstart', blockSelectStart);\n });\n\n const marqueeStyle = marqueeRect\n ? {\n left: `${marqueeRect.left}px`,\n top: `${marqueeRect.top}px`,\n width: `${marqueeRect.width}px`,\n height: `${marqueeRect.height}px`,\n }\n : null;\n\n // Selection is focus-like, so it does not outlive focus leaving the board.\n // Tabbing away, or clicking any focusable thing elsewhere on the page, drops\n // it — the same way a text selection or a focus ring would go.\n const { focusWithinProps: boardFocusWithinProps } = useFocusWithin({\n isDisabled: selectionMode === 'none',\n onBlurWithin: () => clearSelection(),\n });\n\n // ---- Board-level keys -----------------------------------------------------\n //\n // On the board element, never on `document`: a library-owned document listener\n // fires for keystrokes that never went near a board, and two boards on a page\n // would both react.\n const handleBoardKeyDown = useEvent((event: React.KeyboardEvent) => {\n if (selectionMode === 'none') return;\n\n const selected = selectedKeysRef.current;\n if (selected.size === 0) return;\n\n if (event.key === 'Escape') {\n // `preventDefault` only when we actually consumed the key, so an Escape\n // with nothing selected still closes an ancestor Dialog or Popover.\n event.preventDefault();\n event.stopPropagation();\n clearSelection();\n\n return;\n }\n\n if (\n (event.key === 'Delete' || event.key === 'Backspace') &&\n onWidgetsDelete &&\n !isEditableTarget(event.target)\n ) {\n event.preventDefault();\n event.stopPropagation();\n const keys = [...selected];\n clearSelection();\n onWidgetsDelete(keys);\n // The deleted widgets' hosts are about to unmount, so focus would be left\n // on a detached node. Park it on the board.\n containerRef.current?.focus({ preventScroll: true });\n }\n });\n\n const styles: Styles = extractStyles(otherProps, CONTAINER_STYLES);\n\n const dragState = registry.dragState;\n const ready = width > 0;\n\n // Gate widget position transitions off until the widgets have been painted at\n // their initial positions once. Without this, the first render animates every\n // widget sliding in from its default spot (0, 0). We render one frame with the\n // gate closed (no `inset` transition), let the browser paint, then lift it so\n // later reflows animate. A double rAF waits past the first committed paint;\n // re-arm whenever the board (re)becomes ready so a board that hides and\n // remeasures (e.g. inside a tab) re-settles too.\n const [settled, setSettled] = useState(false);\n useEffect(() => {\n if (!ready) {\n setSettled(false);\n return;\n }\n let id1 = 0;\n let id2 = 0;\n id1 = requestAnimationFrame(() => {\n id2 = requestAnimationFrame(() => setSettled(true));\n });\n return () => {\n cancelAnimationFrame(id1);\n if (id2) cancelAnimationFrame(id2);\n };\n }, [ready]);\n\n // When the widget that hosts this nested board is the one being dragged, its\n // whole content (including this board) floats as a single unit, so its own\n // grid lines add nothing but clutter. Suppress them for that drag.\n const hostWidgetIsDragging =\n !!dragState && dragState.nestedBoardIds.has(boardId);\n\n const placeholderStyles = useMemo(\n () =>\n placeholders.map((p) => {\n const pos = calcGridItemPosition(positionParams, p.x, p.y, p.w, p.h);\n\n return {\n i: p.i,\n style: {\n left: `${pos.left}px`,\n top: `${pos.top}px`,\n width: `${pos.width}px`,\n height: `${pos.height}px`,\n },\n };\n }),\n [placeholders, positionParams],\n );\n\n // Which board a drag belongs to. `registry.dragState` is one value shared by\n // every board under a `Board.Provider`, so `'drag'` has to narrow it to the\n // boards actually taking part: the source the widget came from, and the board\n // it is currently over (kept up to date by the registry as the drag crosses\n // boards). Without this, dragging on the root board lights up the grid inside\n // every nested container - noise on boards the widget cannot land in.\n const ownsDrag =\n !!dragState &&\n (dragState.sourceBoardId === boardId ||\n dragState.currentBoardId === boardId);\n\n // `placeholder` is this board's own drop-slot preview, so it covers the two\n // cases `dragState` does not: a resize (never a registry drag) and a board the\n // registry has just seeded a preview on.\n const gridLinesVisible =\n !hostWidgetIsDragging &&\n (effectiveShowGridLines === true ||\n (effectiveShowGridLines === 'drag' && (ownsDrag || !!placeholder)) ||\n (effectiveShowGridLines === 'any-drag' &&\n (!!dragState || !!placeholder)));\n const gridOverlayStyle = gridLinesVisible\n ? (() => {\n const colWidth = calcGridColWidth(positionParams);\n const rowHeightPx = positionParams.rowHeight;\n // A grid with margins has real gaps between cells, so any line-based\n // overlay either misses a cell edge (single line at the cell pitch) or\n // shows a double line in every gap (a line at both edges). Instead,\n // paint each snap cell as a faint block sized exactly `colWidth` x\n // `rowHeightPx` with the margin gaps left transparent: the blocks line\n // up 1:1 with the drop-zone placeholder and there are no lines to\n // double. Column stripes form the background; a row-band alpha mask\n // intersects them into cells.\n const pitchX = colWidth + effectiveMargin[0];\n const pitchY = rowHeightPx + effectiveMargin[1];\n // Position the overlay as an explicit rectangle inset by the board's\n // resolved padding and sized to exactly cover the grid content (cols x\n // rows). This makes the padding a symmetric frame on all four edges (the\n // previous `inset: 0` + top-left-anchored repeat left the padding\n // unvisualized on the right/bottom and inside any extra min-height) and\n // lets the cell pattern tile from the overlay's own origin.\n const padX = resolvedPadding[0];\n const padY = resolvedPadding[1];\n const gridWidth = Math.max(0, effectiveContainerWidth - padX * 2);\n // Painted over the reserved band too — grid cells are what make the\n // band read as board rather than as page background behind it.\n const gridHeight =\n renderedRows > 0\n ? renderedRows * rowHeightPx +\n (renderedRows - 1) * effectiveMargin[1]\n : 0;\n const fill = 'var(--border-color)';\n const columns = `repeating-linear-gradient(to right, ${fill} 0, ${fill} ${colWidth}px, transparent ${colWidth}px, transparent ${pitchX}px)`;\n const rowsGrad = `repeating-linear-gradient(to bottom, #000 0, #000 ${rowHeightPx}px, transparent ${rowHeightPx}px, transparent ${pitchY}px)`;\n return {\n left: `${padX}px`,\n top: `${padY}px`,\n width: `${gridWidth}px`,\n height: `${gridHeight}px`,\n backgroundImage: columns,\n backgroundPosition: '0 0',\n backgroundRepeat: 'repeat',\n maskImage: rowsGrad,\n WebkitMaskImage: rowsGrad,\n maskPosition: '0 0',\n WebkitMaskPosition: '0 0',\n maskRepeat: 'repeat',\n WebkitMaskRepeat: 'repeat',\n };\n })()\n : null;\n\n // Metrics this board exposes to any aligned boards nested inside its widgets.\n const boardMetrics = useMemo<BoardMetrics>(\n () => ({\n colWidth: calcGridColWidth(positionParams),\n rowHeight: positionParams.rowHeight,\n margin: positionParams.margin,\n containerPadding: positionParams.containerPadding,\n }),\n [positionParams],\n );\n\n return (\n <BoardMetricsContext.Provider value={boardMetrics}>\n <BoardGridLinesContext.Provider\n value={\n effectiveShowGridLines === 'any-drag'\n ? 'any-drag'\n : effectiveShowGridLines\n ? 'drag'\n : false\n }\n >\n <BoardElement\n {...mergeProps(\n filterBaseProps(otherProps, { eventProps: true }),\n boardFocusWithinProps,\n { onKeyDown: handleBoardKeyDown },\n )}\n ref={containerRef}\n styles={styles}\n // A board that owns keys needs somewhere for focus to land after a\n // marquee or a delete, so Escape always reaches `handleBoardKeyDown`.\n tabIndex={selectionMode !== 'none' ? -1 : undefined}\n data-board-id={boardId}\n // Non-aligned: use min-height (not a fixed height) so the board\n // auto-sizes to its content by default but can still grow to fill a\n // taller parent. Widgets are absolutely positioned, so growing never\n // shifts them, and the content layer (inset: 0) always covers the full\n // board -> the whole board is droppable. Aligned: omit the inline height\n // so the board fills (and is bounded by) the space the container grants,\n // which is what drives the reduced row height. Stretch: take the\n // parent's height outright, since that height is precisely what gets\n // divided into rows — a min-height derived from the board's own rows\n // would be a fixed point (it would measure back what it just asked\n // for) and the cells could never track the container.\n style={\n aligned\n ? undefined\n : isStretching\n ? { height: '100%' }\n : { minHeight: `${containerHeight}px` }\n }\n mods={{\n dragging: !!dragState,\n 'drop-target': dragState?.currentBoardId === boardId,\n marquee: isMarqueeActive,\n }}\n >\n <ContentLayer\n ref={contentRef}\n onPointerDown={handleContentPointerDown}\n >\n {ready && gridOverlayStyle ? (\n <GridOverlayElement aria-hidden=\"true\" style={gridOverlayStyle} />\n ) : null}\n {ready\n ? layout.map((item) => {\n const registration = registry.store.get(item.i);\n const widgetDraggable =\n isDraggable &&\n (registration?.isDraggable ?? widgetProps?.isDraggable) !==\n false &&\n item.isDraggable !== false &&\n !item.static;\n const widgetResizable =\n isResizable &&\n (registration?.isResizable ?? widgetProps?.isResizable) !==\n false &&\n item.isResizable !== false &&\n !item.static;\n const handles =\n item.resizeHandles ??\n registration?.resizeHandles ??\n widgetProps?.resizeHandles ??\n resizeHandles;\n const gripPlacement =\n registration?.resizeGripPlacement ??\n widgetProps?.resizeGripPlacement ??\n resizeGripPlacement;\n const widgetDragCancel =\n registration?.dragCancel ??\n widgetProps?.dragCancel ??\n dragCancel;\n const widgetDragHandle =\n registration?.dragHandle ??\n widgetProps?.dragHandle ??\n dragHandle;\n // Per-widget `isCard`/`styles` override the board-level\n // `widgetProps` defaults; `isCard` defaults to `false`\n // (borderless - widgets are always filled and rounded).\n const widgetIsCard =\n registration?.isCard ?? widgetProps?.isCard ?? false;\n const widgetHoverRing =\n registration?.hoverRing ?? widgetProps?.hoverRing ?? true;\n // Per-widget `isAutoHeight`/`qa` fall back to the board-level\n // `widgetProps` defaults (mirroring the other widget props).\n const widgetIsAutoHeight =\n registration?.isAutoHeight ??\n widgetProps?.isAutoHeight ??\n false;\n const widgetQa = registration?.qa ?? widgetProps?.qa;\n const widgetSelectable =\n selectionMode !== 'none' && isWidgetSelectable(item.i);\n const widgetSelectionCancel =\n registration?.selectionCancel ??\n widgetProps?.selectionCancel ??\n selectionCancel;\n // Merge board-level `widgetProps` styles (its `styles` object\n // plus direct style props) with the per-widget styles so\n // shared defaults survive when a widget sets even a single\n // style prop; per-widget styles win on conflicts. Only merge\n // when both exist to preserve reference stability (and avoid\n // churn) in the common single-source case.\n const widgetStyles =\n registration?.styles && widgetPropsStyles\n ? mergeStyles(widgetPropsStyles, registration.styles)\n : registration?.styles ?? widgetPropsStyles;\n\n return (\n <WidgetHost\n key={item.i}\n boardId={boardId}\n item={item}\n positionParams={positionParams}\n registration={registration}\n isCard={widgetIsCard}\n hoverRing={widgetHoverRing}\n styles={widgetStyles as Styles}\n isDraggable={widgetDraggable}\n isResizable={widgetResizable}\n resizeHandles={handles}\n resizeGripPlacement={gripPlacement}\n isAutoHeight={widgetIsAutoHeight}\n qa={widgetQa}\n dragCancel={widgetDragCancel}\n dragHandle={widgetDragHandle}\n isSelectable={widgetSelectable}\n isSelected={selectedKeySet.has(item.i)}\n isPreSelected={preSelectedKeys.has(item.i)}\n selectionCancel={widgetSelectionCancel}\n selectedHintId={selectedHintId}\n onSelect={select}\n onSelectionReset={clearSelection}\n selectModifierKey={selectModifierKey}\n registry={registry}\n dragState={dragState}\n settled={settled}\n onResize={handleResize}\n onAutoHeight={handleAutoHeight}\n onDragLifecycle={handleDragLifecycle}\n />\n );\n })\n : null}\n {placeholderStyles.map(({ i, style }) => (\n <PlaceholderElement key={i} aria-hidden=\"true\" style={style} />\n ))}\n {marqueeStyle ? (\n <MarqueeElement aria-hidden=\"true\" style={marqueeStyle} />\n ) : null}\n </ContentLayer>\n {selectionMode !== 'none' ? (\n <A11yLayer>\n <span id={selectedHintId}>{t('board.selected', 'Selected')}</span>\n <span role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {announcement}\n </span>\n </A11yLayer>\n ) : null}\n {children}\n </BoardElement>\n </BoardGridLinesContext.Provider>\n </BoardMetricsContext.Provider>\n );\n}\n\nconst BoardInnerForwarded = forwardRef(BoardInner);\n\n/**\n * A draggable and resizable widget grid. Widgets are declared with\n * `Board.Widget` and positioned via a `layout`. Wrap multiple boards in a\n * `BoardProvider` to enable dragging widgets between them.\n */\nexport const Board = forwardRef(function Board(\n props: CubeBoardProps,\n ref: React.ForwardedRef<HTMLDivElement>,\n) {\n const existingRegistry = useBoardRegistry();\n\n if (existingRegistry) {\n return <BoardInnerForwarded {...props} ref={ref} />;\n }\n\n return (\n <BoardProvider>\n <BoardInnerForwarded {...props} ref={ref} />\n </BoardProvider>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"Board.js","names":["mergeProps"],"sources":["../../../../src/components/layout/Board/Board.tsx"],"sourcesContent":["import { useResizeObserver } from '@react-aria/utils';\nimport {\n AllBaseProps,\n CONTAINER_STYLES,\n ContainerStyleProps,\n filterBaseProps,\n mergeStyles,\n Styles,\n tasty,\n} from '@tenphi/tasty';\nimport {\n forwardRef,\n ReactNode,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport { useFocusWithin } from 'react-aria';\n\nimport { useEvent } from '../../../_internal/hooks';\nimport { useI18n } from '../../../i18n';\nimport { mergeProps, useCombinedRefs } from '../../../utils/react';\nimport { extractStyles } from '../../../utils/styles';\n\nimport {\n BoardEntry,\n BoardGridLinesContext,\n BoardMetrics,\n BoardMetricsContext,\n useBoardGridLines,\n useBoardHost,\n useBoardMetrics,\n useBoardRegistry,\n} from './board-context';\nimport { BoardProvider } from './BoardProvider';\nimport {\n applySizeConstraints,\n bottom,\n calcGridColWidth,\n calcGridItemPosition,\n calcWH,\n cloneLayout,\n CollisionMode,\n Compactor,\n CompactType,\n correctBounds,\n defaultConstraints,\n getAllCollisions,\n getCompactor,\n getLayoutItem,\n LayoutConstraint,\n LayoutItem,\n modifyLayout,\n Position,\n PositionParams,\n ResizeHandleAxis,\n} from './grid-core';\nimport { useBoardLayout } from './use-board-layout';\nimport { useBoardSelectModifierKey } from './use-board-select-modifier-key';\nimport { BoardSelectionMode, useBoardSelection } from './use-board-selection';\nimport { ResizePhase, WidgetHost } from './WidgetHost';\n\nimport type { BoardLayoutChangeInfo } from './use-board-layout';\nimport type { BoardResizeGripPlacement, CubeBoardWidgetProps } from './Widget';\n\nconst BoardElement = tasty({\n qa: 'Board',\n styles: {\n position: 'relative',\n display: 'block',\n width: '100%',\n flexGrow: 1,\n height: 'min 0',\n fill: '#surface',\n boxSizing: 'border-box',\n // The board takes focus programmatically (never by Tab — it is `tabIndex=-1`)\n // as a parking spot: after `onWidgetsDelete` the focused widget host is\n // about to unmount, and after a marquee focus is nowhere near the board, so\n // in both cases Escape and Delete — handled here rather than on `document` —\n // would have nothing to reach. A focus ring on a parking spot is noise: it\n // announces a state the user cannot act on and did not ask for. Same reason\n // `Dialog` drops it on its own focusable container.\n outline: 0,\n // A lasso is a widget gesture, not a text gesture: without this, dragging a\n // band across the widgets paints a native text selection under it and leaves\n // stray highlighted text behind. `WidgetHost` does the same for a widget\n // drag (`'drag | resizing'`), which the marquee never goes through.\n userSelect: {\n '': 'auto',\n marquee: 'none',\n },\n },\n});\n\nconst ContentLayer = tasty({\n styles: {\n position: 'absolute',\n inset: 0,\n },\n});\n\n// The drop-slot preview. `#primary` rather than the legacy `#purple` alias -\n// same hue, current token. It has to stay distinguishable from a *selected*\n// widget (a tint + solid border + ring, see `WidgetHost`) and from a live\n// marquee (dashed), since all three can be on screen at once.\nconst PlaceholderElement = tasty({\n qa: 'BoardPlaceholder',\n styles: {\n position: 'absolute',\n top: 0,\n left: 0,\n fill: '#primary.10',\n radius: '1cr',\n border: '#primary.40',\n zIndex: 2,\n pointerEvents: 'none',\n transition: 'inset 80ms linear, width 80ms linear, height 80ms linear',\n boxSizing: 'border-box',\n },\n});\n\n// The rubber-band selection rectangle. Dashed is the discriminator: nothing else\n// on a board is dashed, and it reads as a transient lasso rather than a place\n// something is about to land. Sits above the widgets (1) and the placeholder (2).\nconst MarqueeElement = tasty({\n qa: 'BoardMarquee',\n styles: {\n position: 'absolute',\n top: 0,\n left: 0,\n fill: '#primary-accent-surface.06',\n border: '1bw dashed #primary-border',\n radius: '1cr',\n zIndex: 3,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n});\n\n// Visually-hidden live region. Selection changes are announced here because a\n// board widget cannot carry `aria-selected`: that attribute is only valid on\n// collection roles (`option`, `gridcell`, `row`, …) whose children must be\n// presentational, and widgets host arbitrary interactive content. This element\n// also owns the shared \"Selected\" hint every selected host points at via\n// `aria-describedby`.\nconst A11yLayer = tasty({\n styles: {\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: 0,\n margin: '-1px',\n overflow: 'hidden',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n },\n});\n\n// Grid overlay drawn behind the widgets. Each snap cell is painted as a faint\n// block (column stripes intersected with a row-band alpha mask); the margin gaps\n// between cells stay transparent. The element is positioned as an explicit\n// rectangle inset by the board's resolved padding and sized to the grid content\n// so the padding reads as a symmetric frame on every edge. Its size, position\n// and gradients come from the board's position params via inline `style`. The\n// fill uses the `#border` token (via its CSS var) so it adapts to the scheme.\nconst GridOverlayElement = tasty({\n qa: 'BoardGridOverlay',\n styles: {\n position: 'absolute',\n zIndex: 0,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n opacity: '.5',\n },\n});\n\nexport type BoardCompactType = 'vertical' | 'horizontal' | 'free' | null;\n\n/**\n * Payload passed to the drag/resize lifecycle callbacks. `layout` is the board's\n * current layout at the moment the callback fires, `item` is the affected item\n * (falls back to `oldItem` if the item just left this board via a cross-board\n * transfer), `oldItem` is that item as it was when the gesture started, and\n * `placeholder` is the current drop-slot preview (if any).\n *\n * The plural fields describe the whole gesture: a group drag moves every\n * selected widget at once, so `items`/`oldItems`/`placeholders` list them all,\n * grabbed widget first. An ordinary drag or a resize produces exactly one entry,\n * so `items[0] === item` and `placeholders[0] === placeholder` always hold.\n */\nexport interface BoardInteractionInfo {\n layout: LayoutItem[];\n item: LayoutItem;\n oldItem: LayoutItem;\n placeholder: LayoutItem | null;\n /** Every item in this gesture, grabbed first. */\n items: LayoutItem[];\n /** Those items as they were when the gesture started, same order. */\n oldItems: LayoutItem[];\n /** Every drop-slot preview. Empty exactly when `placeholder` is `null`. */\n placeholders: LayoutItem[];\n}\n\n/** Visibility of the internal grid-line overlay. */\nexport type BoardGridLines = boolean | 'drag' | 'any-drag';\n\n/**\n * The subset of `Board.Widget` props a `Board` can set as defaults for every\n * widget it hosts (via `widgetProps`). Excludes `id`/`children`, which are\n * per-widget. Per-widget `Board.Widget` props override these.\n */\nexport type CubeBoardWidgetDefaults = Omit<\n CubeBoardWidgetProps,\n 'id' | 'children'\n>;\n\nexport interface CubeBoardProps\n extends Omit<\n AllBaseProps,\n 'children' | 'onDragStart' | 'onDrag' | 'onResize'\n >,\n Omit<ContainerStyleProps, 'margin'> {\n /** Stable board id (used for cross-board drag). Auto-generated if omitted. */\n id?: string;\n /** Controlled layout. */\n layout?: LayoutItem[];\n /** Initial layout for uncontrolled usage. */\n defaultLayout?: LayoutItem[];\n onLayoutChange?: (layout: LayoutItem[], info: BoardLayoutChangeInfo) => void;\n /** Called when a drag gesture starts. */\n onDragStart?: (info: BoardInteractionInfo) => void;\n /** Called on every step of a drag gesture. */\n onDrag?: (info: BoardInteractionInfo) => void;\n /** Called when a drag gesture ends (after the layout is committed). */\n onDragStop?: (info: BoardInteractionInfo) => void;\n /** Called when a resize gesture starts. */\n onResizeStart?: (info: BoardInteractionInfo) => void;\n /** Called on every step of a resize gesture. */\n onResize?: (info: BoardInteractionInfo) => void;\n /** Called when a resize gesture ends (after the layout is committed). */\n onResizeStop?: (info: BoardInteractionInfo) => void;\n /** Number of columns. @default 12 */\n cols?: number;\n /**\n * Render exactly this many rows, whatever the content needs — a fixed\n * `cols × rows` matrix rather than a grid that hugs its widgets. Implies a\n * `maxRows` of the same value, so the grid's own bounds constraint keeps every\n * drag and resize inside the matrix. Pair with `rowHeight=\"stretch\"` for a\n * matrix that fills the box it is given.\n */\n rows?: number;\n /**\n * Row height in pixels, or `'stretch'` to divide the board's own measured\n * height into its rows. `'stretch'` is what makes a fixed `rows × cols` matrix\n * fill its container: the board fills the height it is given and each cell\n * takes an equal share of it, so resizing the container resizes the cells\n * instead of adding or removing them.\n *\n * Requires {@link rows}. Without a declared row count there is no matrix to\n * fill, and dividing by the content extent instead would resize every cell\n * whenever a widget landed on a new row — so the mode does not engage and the\n * board keeps its ordinary content-hugging behaviour at the default height.\n * @default 100\n */\n rowHeight?: number | 'stretch';\n /** [horizontal, vertical] margin between widgets in pixels. @default [8, 8] */\n margin?: [number, number];\n /**\n * [horizontal, vertical] padding inside the board. Defaults to `margin`, or\n * to `[0, 0]` for an aligned nested board (`isAligned`) so its grid lines up\n * with the ancestor board's.\n */\n containerPadding?: [number, number];\n /** Maximum number of rows. @default Infinity */\n maxRows?: number;\n /**\n * Empty grid rows kept below the content. The board renders this many rows\n * taller than its widgets need, so there is always somewhere to start a\n * marquee and somewhere to drop a widget past the end — a board that hugs its\n * content has neither once the grid is full. Clamped by `maxRows`.\n * @default 0\n */\n extraRows?: number;\n /**\n * Compaction behavior. `'vertical'` / `'horizontal'` reflow widgets to remove\n * gaps; `'free'` places each widget exactly where dropped and never pushes its\n * neighbours (pair with `allowOverlap` to let widgets stack, otherwise moving\n * onto an occupied cell is blocked); `null` disables compaction but still\n * resolves collisions the legacy react-grid-layout way. @default 'vertical'\n */\n compact?: BoardCompactType;\n /** Allow widgets to overlap. @default false */\n allowOverlap?: boolean;\n /** Block movement into occupied cells instead of pushing. @default false */\n preventCollision?: boolean;\n /**\n * How to resolve a drop the grid would otherwise refuse. Only applies where a\n * collision blocks a move - `compact=\"free\"` (which prevents collisions) or an\n * explicit `preventCollision` - and never under `allowOverlap`. `'revert'`\n * snaps the widget back, `'downscale'` shrinks it into the free space at the\n * drop cell. Within this board, `'swap'` trades places with one widget - the one\n * the drop covers most - which takes the cell the drag began at (falling back to\n * `'downscale'`, then `'revert'`). For a widget arriving from another board,\n * `'swap'` never exchanges or reflows destination widgets: the anchor cell must\n * be empty, the incoming widget downscales into the room to its right/below, and\n * an invalid landing cancels the transfer. No mode ever grows a widget, an\n * in-board swap never displaces more than one widget, and a drop that spans two\n * widgets trades with one of them rather than blinking away mid-drag.\n *\n * Applies to single-widget drags. Arrow keys honour it too, but never resize\n * anything: each press is a gesture of its own, so a press that shrank a widget\n * would have nothing to restore from. A multi-widget selection still only moves\n * where it fits outright, and a resize is still blocked by a collision.\n * @default 'revert'\n */\n collisionMode?: CollisionMode;\n /** Enable dragging for all widgets. @default true */\n isDraggable?: boolean;\n /** Enable resizing for all widgets. @default true */\n isResizable?: boolean;\n /** Whether this board accepts widgets dropped from other boards. @default true */\n isDroppable?: boolean;\n /** Which resize handles to show. @default ['se'] */\n resizeHandles?: ResizeHandleAxis[];\n /**\n * Where the corner resize grips sit: `'inside'` tucks them into the widget\n * box, `'corner'` centres each one on the widget's corner so it lines up with a\n * control centred on the opposite corner. Only affects corner handles. Can be\n * overridden per widget on `Board.Widget`.\n * @default 'inside'\n */\n resizeGripPlacement?: BoardResizeGripPlacement;\n /**\n * CSS selector for elements that must not start a pointer drag.\n *\n * Defaults to {@link BOARD_SELECTION_CANCEL} — the same set `selectionCancel`\n * uses — because a control inside a widget has to keep its own press whether\n * or not the board happens to support selection. Pass a selector of your own\n * to narrow or widen it, or `''` to let a drag start from anywhere.\n *\n * Does not affect keyboard moves — those only run when the widget host itself\n * is focused. Can be overridden per widget on `Board.Widget`.\n */\n dragCancel?: string;\n /**\n * CSS selector for the only elements from which a pointer drag may start.\n * Can be overridden per widget on `Board.Widget`.\n */\n dragHandle?: string;\n /**\n * Show grid lines behind the widgets. `true` always shows them, `false` never,\n * `'drag'` only while *this* board is part of the active gesture - it owns the\n * drag (as its source or as the board the widget is currently over), or one of\n * its own widgets is being resized. `'any-drag'` widens that to any drag\n * anywhere under a shared `Board.Provider`, so every board advertises itself as\n * a place the widget could land.\n * @default false\n */\n showGridLines?: BoardGridLines;\n /**\n * Align this board's grid with an ancestor `Board`'s layout. Only takes\n * effect when the board is nested inside another `Board`'s widget. When set,\n * every cell matches the parent's cell size exactly: the board inherits the\n * parent's column pitch (deriving its own column count from its measured\n * width) and uses the parent's row height verbatim. It never shrinks rows to\n * fit; pair it with an `isAutoHeight` container so the widget grows to fit its\n * rows at that height. @default false\n */\n isAligned?: boolean;\n /**\n * Whether widgets can be selected, and how many at a time. `'multiple'` also\n * enables the marquee and rigid group movement: dragging any selected widget\n * moves the whole selection. @default 'none'\n */\n selectionMode?: BoardSelectionMode;\n /** Controlled selection. Keys are layout item ids (`LayoutItem.i`). */\n selectedKeys?: string[];\n /** Initial selection for uncontrolled usage. */\n defaultSelectedKeys?: string[];\n /**\n * Called when the selection changes. Keys are deduped and returned in the\n * board's layout order, never in click order.\n */\n onSelectionChange?: (keys: string[]) => void;\n /**\n * CSS selector for descendants whose clicks must never change the selection\n * (form controls, buttons, links). Mirrors `dragCancel`; can be overridden per\n * widget. Pass `''` to disable the guard entirely.\n * @default BOARD_SELECTION_CANCEL\n */\n selectionCancel?: string;\n /**\n * Draw a rubber-band (marquee) selection when a drag starts on empty board\n * space. Only meaningful with `selectionMode=\"multiple\"`.\n * @default selectionMode === 'multiple'\n */\n allowMarqueeSelection?: boolean;\n /**\n * Called when the user presses <kbd>Delete</kbd>/<kbd>Backspace</kbd> with a\n * non-empty selection, and focus is inside the board but not in an editable\n * field. Board never mutates the layout itself — removing the widgets is the\n * consumer's job. Board only handles these keys when this handler is set.\n */\n onWidgetsDelete?: (keys: string[]) => void;\n /** Grid/item layout constraints. */\n constraints?: LayoutConstraint[];\n /**\n * Explicit container width in pixels. When provided, disables automatic width\n * measurement (useful for SSR and tests).\n */\n width?: number;\n /**\n * Default props applied to every widget this board hosts. Per-widget\n * `Board.Widget` props override these. Use it to add a card border to every\n * widget (`widgetProps={{ isCard: true }}`) or set shared sizing/`styles`\n * defaults without repeating them on each `Board.Widget`.\n */\n widgetProps?: Partial<CubeBoardWidgetDefaults>;\n children?: ReactNode;\n}\n\n/**\n * Descendants whose clicks never change the selection. A widget is a large\n * surface the user also clicks to *work with*, so anything interactive inside it\n * must keep its click. `[data-no-select]` is the escape hatch for an app's own\n * custom controls.\n */\nexport const BOARD_SELECTION_CANCEL =\n 'input,textarea,select,button,a,[role=\"button\"],[role=\"menuitem\"],' +\n '[role=\"checkbox\"],[role=\"switch\"],[role=\"tab\"],[contenteditable=\"true\"],' +\n '[data-no-select]';\n\n/**\n * Row height when none is given, and the fallback a `rowHeight=\"stretch\"` board\n * uses until it has both a bounded row count and a measured height to divide.\n */\nconst DEFAULT_ROW_HEIGHT = 100;\n\n/** Manhattan distance a pointer must travel before a press becomes a marquee. */\nconst MARQUEE_THRESHOLD = 4;\n\n/** Shared empty set, so \"no pre-selection\" is a stable reference. */\nconst NO_KEYS: ReadonlySet<string> = new Set();\n\n/**\n * Whether an event landed in a text-editing context. Checking the *event target*\n * beats `document.activeElement`: it stays correct for content rendered through\n * a portal, and it cannot be fooled by focus that moved between the keystroke\n * and the handler.\n */\nfunction isEditableTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null;\n if (!el || typeof el.closest !== 'function') return false;\n\n return !!el.closest('input,textarea,select,[contenteditable=\"true\"]');\n}\n\nfunction compactTypeToCore(compact: BoardCompactType): CompactType {\n if (compact === 'free') return null;\n return compact;\n}\n\nfunction BoardInner(\n props: CubeBoardProps,\n ref: React.ForwardedRef<HTMLDivElement>,\n) {\n const {\n id: providedId,\n layout: controlledLayout,\n defaultLayout,\n onLayoutChange,\n onDragStart,\n onDrag,\n onDragStop,\n onResizeStart,\n onResize: onResizeProp,\n onResizeStop,\n cols = 12,\n rows: fixedRows,\n rowHeight = DEFAULT_ROW_HEIGHT,\n margin = [8, 8],\n containerPadding,\n maxRows: maxRowsProp,\n extraRows = 0,\n compact = 'vertical',\n allowOverlap = false,\n preventCollision = false,\n collisionMode = 'revert',\n isDraggable = true,\n isResizable = true,\n isDroppable = true,\n resizeHandles = ['se'],\n resizeGripPlacement = 'inside',\n dragCancel = BOARD_SELECTION_CANCEL,\n dragHandle,\n showGridLines,\n isAligned = false,\n selectionMode = 'none',\n selectedKeys,\n defaultSelectedKeys,\n onSelectionChange,\n selectionCancel = BOARD_SELECTION_CANCEL,\n allowMarqueeSelection = selectionMode === 'multiple',\n onWidgetsDelete,\n constraints,\n width: providedWidth,\n widgetProps,\n children,\n ...otherProps\n } = props;\n\n // A fixed row count is also a hard bound: `gridBounds` clamps every drag and\n // resize against `maxRows`, so declaring `rows` is what keeps widgets inside\n // the matrix without the caller restating a per-widget `maxH`.\n const maxRows =\n maxRowsProp ?? (fixedRows != null ? Math.max(1, fixedRows) : Infinity);\n\n const registry = useBoardRegistry()!;\n const parentMetrics = useBoardMetrics();\n const host = useBoardHost();\n const inheritedGridLines = useBoardGridLines();\n const aligned = isAligned && !!parentMetrics;\n // `widgetProps` may carry container style props directly (e.g. `fill`,\n // `padding`, `radius`) alongside an explicit `styles` object, mirroring\n // `Board.Widget`. Extract them into a single style map here so those defaults\n // actually reach every widget - forwarding only `widgetProps.styles` would\n // drop the direct props. A direct prop wins over the same key in `styles`.\n const widgetPropsStyles = useMemo<Styles | undefined>(() => {\n if (!widgetProps) return undefined;\n const extracted = extractStyles(widgetProps, CONTAINER_STYLES);\n return Object.keys(extracted).length > 0 ? extracted : undefined;\n }, [widgetProps]);\n // A nested board with no explicit `showGridLines` inherits the ancestor's:\n // when the ancestor has grid lines enabled, show them here while dragging, at\n // the ancestor's own drag scope (see `BoardInheritedGridLines`).\n const effectiveShowGridLines: BoardGridLines =\n showGridLines ?? inheritedGridLines;\n const generatedId = useId();\n const boardId = providedId ?? generatedId;\n // One shared description node for every selected widget, so marking a widget\n // selected costs no per-widget DOM.\n const selectedHintId = `${generatedId}-selected`;\n const { t } = useI18n();\n\n const containerRef = useCombinedRefs(ref);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const [measuredWidth, setMeasuredWidth] = useState<number>(0);\n // Rendered height is only needed for aligned nested boards (to fit rows into\n // the space the container grants). It never drives the board's own height, so\n // measuring it cannot create a feedback loop.\n const [measuredHeight, setMeasuredHeight] = useState<number>(0);\n const width = providedWidth ?? measuredWidth;\n\n const onResizeContainer = useEvent(() => {\n const el = containerRef.current;\n if (!el) return;\n // A hidden container (e.g. the board inside an inactive tab after a\n // spring-loaded tab switch) reports 0. Keep the last non-zero measurement so\n // the board stays \"ready\" and keeps its widget hosts mounted while briefly\n // hidden. Otherwise the board would render nothing, unmounting the widget\n // that owns an in-flight drag gesture and stranding the drag (React Aria's\n // `useMove` tears down its listeners on unmount, so the drop never fires).\n const nextWidth = el.offsetWidth;\n const nextHeight = el.offsetHeight;\n if (nextWidth > 0) setMeasuredWidth(nextWidth);\n if (nextHeight > 0) setMeasuredHeight(nextHeight);\n });\n useResizeObserver({ ref: containerRef, onResize: onResizeContainer });\n useEffect(() => {\n if (providedWidth == null) {\n onResizeContainer();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [providedWidth]);\n\n const {\n layout,\n layoutRef,\n placeholders,\n placeholder,\n placeholdersRef,\n placeholderRef,\n setPlaceholders,\n applyLayout,\n } = useBoardLayout({\n layout: controlledLayout,\n defaultLayout,\n onLayoutChange,\n });\n\n // The accessible name a widget announces under. Mirrors `WidgetHost`'s own\n // fallback chain so the live region and the host never disagree.\n const getWidgetLabel = useEvent((key: string) => {\n const registration = registry.store.get(key);\n\n return registration?.['aria-label'] ?? registration?.qa ?? key;\n });\n\n // Whether a widget accepts selection at all. Every selection path resolves it\n // here — press, keyboard and marquee — so a lasso can never pick up a widget\n // that a press cannot.\n const isWidgetSelectable = (key: string) =>\n (registry.store.get(key)?.isSelectable ?? widgetProps?.isSelectable) !==\n false;\n\n const {\n selectedKeySet,\n selectedKeysRef,\n setSelection,\n select,\n clearSelection,\n announcement,\n } = useBoardSelection({\n selectionMode,\n selectedKeys,\n defaultSelectedKeys,\n onSelectionChange,\n layout,\n getLabel: getWidgetLabel,\n });\n\n const selectModifierKey = useBoardSelectModifierKey();\n\n // Re-render when any widget's registered content/config changes.\n useSyncExternalStore(registry.store.subscribe, registry.store.getVersion);\n\n // In aligned mode the board inherits the parent's gap so widget edges line up\n // with the surrounding layout; otherwise it uses its own `margin`.\n const effectiveMargin: readonly [number, number] = aligned\n ? parentMetrics!.margin\n : margin;\n // The board keeps its own padding (it sits inside the container's chrome);\n // when unspecified it defaults to the effective gap. An aligned nested board\n // is the exception: its grid origin must sit flush on the container widget's\n // edge (which already coincides with the parent's column-0 origin) so its\n // columns line up with the ancestor board's. Inheriting the gap there would\n // inset every column by one margin and break the alignment, so it defaults\n // to zero padding instead.\n const resolvedPadding: readonly [number, number] =\n containerPadding ?? (aligned ? [0, 0] : effectiveMargin);\n\n const rows = Math.max(\n bottom(layout),\n ...placeholders.map((p) => p.y + p.h),\n 0,\n );\n\n // Rows the board actually paints. `rows` stays the *content* extent — layout\n // math must not see the reserved band — while this is the extent the board\n // renders, so the band is real board surface: `ContentLayer` (inset: 0)\n // covers it, which is what lets a marquee start there and a widget be dropped\n // past the end.\n const renderedRows =\n fixedRows != null\n ? Math.max(1, fixedRows)\n : Math.min(rows + Math.max(0, extraRows), maxRows);\n\n // Derive the aligned column count so each column keeps the parent's pixel\n // pitch: as the container widget is resized, columns are added/removed rather\n // than stretched. `containerWidth` is then back-solved so `calcGridColWidth`\n // returns exactly the parent's column width.\n const parentColWidth = aligned ? parentMetrics!.colWidth : 0;\n // `width` is `offsetWidth` (an integer the browser rounds), while\n // `parentColWidth` is fractional. A container sized to exactly N parent\n // columns can therefore measure a fraction of a pixel short, so a bare\n // `Math.floor` would drop the last column and leave its space unused. Add a\n // small pixel tolerance to absorb that rounding; it only rounds up when the\n // width is within ~2px of a full column, so it can't invent a column that\n // genuinely doesn't fit.\n const ALIGN_WIDTH_TOLERANCE = 2;\n const alignedCols =\n aligned && width > 0\n ? Math.max(\n 1,\n Math.floor(\n (width -\n resolvedPadding[0] * 2 +\n effectiveMargin[0] +\n ALIGN_WIDTH_TOLERANCE) /\n (parentColWidth + effectiveMargin[0]),\n ),\n )\n : cols;\n const effectiveCols = aligned ? alignedCols : cols;\n const effectiveContainerWidth = aligned\n ? parentColWidth * effectiveCols +\n effectiveMargin[0] * Math.max(0, effectiveCols - 1) +\n resolvedPadding[0] * 2\n : width;\n\n // A stretch board divides its own measured height into its rows, so the matrix\n // fills the box it was given and resizing the container resizes the cells.\n //\n // It only does that with a DECLARED row count. Dividing by the content extent\n // instead would resize every cell whenever a widget lands on a new row, and\n // the board would still be claiming its parent's whole height to do it — so\n // without `rows` there is no matrix to fill and the board keeps its ordinary\n // content-hugging behaviour at the default row height.\n const isStretching = rowHeight === 'stretch' && fixedRows != null;\n const stretchedRowHeight =\n isStretching && measuredHeight > 0\n ? Math.max(\n 1,\n (measuredHeight -\n Math.max(0, renderedRows - 1) * effectiveMargin[1] -\n resolvedPadding[1] * 2) /\n renderedRows,\n )\n : // Not measured yet (first paint) or not a matrix at all: a real pixel\n // height keeps the board renderable rather than collapsing it.\n DEFAULT_ROW_HEIGHT;\n\n // An aligned board uses the parent's row height verbatim, so every cell is\n // exactly the parent's cell size (width already matches via the inherited\n // column pitch). It never shrinks rows to fit; pair it with an `isAutoHeight`\n // container so the widget grows to fit the rows at this height instead.\n const effectiveRowHeight = aligned\n ? parentMetrics!.rowHeight\n : rowHeight === 'stretch'\n ? stretchedRowHeight\n : rowHeight;\n\n const positionParams = useMemo<PositionParams>(\n () => ({\n margin: effectiveMargin,\n containerPadding: resolvedPadding,\n containerWidth: effectiveContainerWidth,\n cols: effectiveCols,\n rowHeight: effectiveRowHeight,\n maxRows,\n }),\n [\n effectiveMargin[0],\n effectiveMargin[1],\n resolvedPadding[0],\n resolvedPadding[1],\n effectiveContainerWidth,\n effectiveCols,\n effectiveRowHeight,\n maxRows,\n ],\n );\n\n // 'free' means no compaction (nothing is pushed up/left or recompacted) AND a\n // dragged widget never pushes or swaps its neighbours: it is placed exactly\n // where dropped. Without `allowOverlap` a move onto an occupied cell is\n // blocked (the widget stays at its last free spot); with `allowOverlap`\n // widgets may stack. The explicit `preventCollision` prop still applies to the\n // compacting modes (`vertical` / `horizontal`) and to the legacy `null` mode.\n const compactor = useMemo<Compactor>(\n () =>\n getCompactor(\n compactTypeToCore(compact),\n allowOverlap,\n compact === 'free' ? !allowOverlap : preventCollision,\n ),\n [compact, allowOverlap, preventCollision],\n );\n\n const resolvedConstraints = constraints ?? defaultConstraints;\n\n const computedHeight =\n renderedRows > 0\n ? renderedRows * effectiveRowHeight +\n Math.max(0, renderedRows - 1) * effectiveMargin[1] +\n resolvedPadding[1] * 2\n : effectiveRowHeight;\n // An aligned or stretching board fills the height the container grants it, so\n // it reports its measured height; otherwise it reports the height its content\n // needs.\n const containerHeight =\n (aligned || isStretching) && measuredHeight > 0\n ? measuredHeight\n : computedHeight;\n\n // Live refs so the stable registry entry always reads current values.\n const liveRef = useRef({\n positionParams,\n compactor,\n collisionMode,\n constraints: resolvedConstraints,\n maxRows,\n containerHeight,\n isDroppable,\n });\n liveRef.current = {\n positionParams,\n compactor,\n collisionMode,\n constraints: resolvedConstraints,\n maxRows,\n containerHeight,\n isDroppable,\n };\n\n const applyLayoutEvent = useEvent(applyLayout);\n const setPlaceholdersEvent = useEvent(setPlaceholders);\n\n const entryRef = useRef<BoardEntry | null>(null);\n if (!entryRef.current) {\n entryRef.current = {\n id: boardId,\n getContentRect: () => contentRef.current?.getBoundingClientRect() ?? null,\n getContentNode: () => contentRef.current,\n getPositionParams: () => liveRef.current.positionParams,\n getConstraints: () => liveRef.current.constraints,\n getCompactor: () => liveRef.current.compactor,\n getCollisionMode: () => liveRef.current.collisionMode,\n getMaxRows: () => liveRef.current.maxRows,\n getContainerHeight: () => liveRef.current.containerHeight,\n getLayout: () => layoutRef.current,\n // The registry reads this synchronously at drag start, so it must be the\n // ref rather than the rendered value.\n getSelectedKeys: () =>\n selectedKeysRef.current.size > 0 ? selectedKeysRef.current : null,\n applyLayout: (next, commit, reason) =>\n applyLayoutEvent(next, commit, reason),\n setPlaceholders: (items) => setPlaceholdersEvent(items),\n isDroppable: () => liveRef.current.isDroppable,\n };\n }\n\n useEffect(() => {\n const entry = entryRef.current!;\n // Keep the entry's id in sync with the (possibly changed) board id before\n // registering. The previous effect's cleanup has already removed the old id,\n // so registering here keys the entry under the current id.\n entry.id = boardId;\n return registry.registerBoard(entry);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [boardId]);\n\n // When the aligned column count changes (the container was resized), reflow\n // the layout to the new width: clamp items back into bounds and recompact so\n // nothing overflows the narrower/wider grid.\n const recompactForCols = useEvent((nextCols: number) => {\n const corrected = correctBounds(cloneLayout(layoutRef.current), {\n cols: nextCols,\n });\n const compacted = [\n ...liveRef.current.compactor.compact(corrected, nextCols),\n ];\n applyLayoutEvent(compacted, true, 'normalize');\n });\n // `null` until the first *measured* aligned column count is established. This\n // avoids treating the initial zero-width -> measured-width transition as a\n // column-count change: a board that measures its own width (no explicit\n // `width` prop) renders first with `width === 0`, so `effectiveCols` falls\n // back to `cols` and only becomes the derived aligned count once measured.\n // Seeding the baseline on that first measured value (without committing)\n // prevents an unsolicited reflow + `onLayoutChange` before the user interacts.\n const prevAlignedColsRef = useRef<number | null>(null);\n useEffect(() => {\n if (!aligned) {\n // Re-entering aligned mode should re-seed from the next measured value.\n prevAlignedColsRef.current = null;\n return;\n }\n // Wait for a real width measurement; the fallback-`cols` value that stands\n // in before measurement is not a meaningful aligned column count.\n if (width <= 0) return;\n if (prevAlignedColsRef.current === null) {\n prevAlignedColsRef.current = effectiveCols;\n return;\n }\n if (prevAlignedColsRef.current === effectiveCols) return;\n prevAlignedColsRef.current = effectiveCols;\n recompactForCols(effectiveCols);\n }, [aligned, width, effectiveCols, recompactForCols]);\n\n // Natural height this board wants: its rows at the (parent) row height. When\n // the container is shorter than this, an `isAutoHeight` host grows to fit it\n // (aligned boards no longer shrink their rows).\n const naturalHeight =\n renderedRows > 0\n ? renderedRows * effectiveRowHeight +\n Math.max(0, renderedRows - 1) * effectiveMargin[1] +\n resolvedPadding[1] * 2\n : effectiveRowHeight;\n\n // Report this aligned board's height deficit to an auto-sizing host so the\n // host can both grow to fit and pin its resize floor. The value is signed:\n // positive when the board is squeezed (needs more height), negative when the\n // container is taller than needed (so the floor can be lowered). The host\n // never shrinks the widget on its own - it only grows and clamps resizing.\n const requestHeightDeficit = host?.requestHeightDeficit;\n useEffect(() => {\n if (!aligned || !host?.isAutoHeight || !requestHeightDeficit) return;\n if (measuredHeight <= 0) return;\n requestHeightDeficit(naturalHeight - measuredHeight);\n }, [\n aligned,\n host?.isAutoHeight,\n requestHeightDeficit,\n naturalHeight,\n measuredHeight,\n ]);\n\n // In-board resize orchestration.\n const resizeStateRef = useRef<{\n id: string;\n axis: ResizeHandleAxis;\n item: LayoutItem;\n origin: Position;\n accX: number;\n accY: number;\n } | null>(null);\n\n // Minimum rows each auto-height widget currently needs to fit its content.\n // Read during resize so a widget can never be dragged shorter than its\n // content, and used to grow the item when the content needs more room.\n const autoHeightMinRowsRef = useRef<Record<string, number>>({});\n\n const handleResize = useEvent(\n (\n id: string,\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => {\n const pp = liveRef.current.positionParams;\n\n if (phase === 'start') {\n const rawItem = getLayoutItem(layoutRef.current, id);\n if (!rawItem) return;\n // Layout-item min/max and constraints win; otherwise fall back to the\n // ones declared on the owning `Board.Widget` (and then the board-level\n // `widgetProps` defaults) so `applySizeConstraints` (via `minMaxSize`)\n // picks them up.\n const reg = registry.store.get(id);\n const item: LayoutItem = {\n ...rawItem,\n minW: rawItem.minW ?? reg?.minW ?? widgetProps?.minW,\n maxW: rawItem.maxW ?? reg?.maxW ?? widgetProps?.maxW,\n minH: rawItem.minH ?? reg?.minH ?? widgetProps?.minH,\n maxH: rawItem.maxH ?? reg?.maxH ?? widgetProps?.maxH,\n constraints:\n rawItem.constraints ?? reg?.constraints ?? widgetProps?.constraints,\n };\n resizeStateRef.current = {\n id,\n axis,\n item: { ...item },\n origin: calcGridItemPosition(pp, item.x, item.y, item.w, item.h),\n accX: 0,\n accY: 0,\n };\n setPlaceholders([{ ...item }]);\n onResizeStart?.({\n layout: layoutRef.current,\n item: { ...item },\n oldItem: { ...item },\n placeholder: { ...item },\n items: [{ ...item }],\n oldItems: [{ ...item }],\n placeholders: [{ ...item }],\n });\n return;\n }\n\n const rs = resizeStateRef.current;\n if (!rs) return;\n\n if (phase === 'end') {\n const finalLayout = [...layoutRef.current];\n applyLayout(finalLayout, true, 'resize');\n setPlaceholders([]);\n const resizedItem = getLayoutItem(finalLayout, id) ?? rs.item;\n onResizeStop?.({\n layout: finalLayout,\n item: resizedItem,\n oldItem: rs.item,\n placeholder: null,\n items: [resizedItem],\n oldItems: [rs.item],\n placeholders: [],\n });\n resizeStateRef.current = null;\n return;\n }\n\n rs.accX += dx;\n rs.accY += dy;\n\n const { origin, item, axis: handle } = rs;\n let newW = origin.width;\n let newH = origin.height;\n if (handle.includes('e')) newW = origin.width + rs.accX;\n if (handle.includes('w')) newW = origin.width - rs.accX;\n if (handle.includes('s')) newH = origin.height + rs.accY;\n if (handle.includes('n')) newH = origin.height - rs.accY;\n newW = Math.max(newW, 8);\n newH = Math.max(newH, 8);\n\n const raw = calcWH(pp, newW, newH, item.x, item.y, handle);\n const constrained = applySizeConstraints(\n liveRef.current.constraints,\n item,\n raw.w,\n raw.h,\n handle,\n {\n cols: pp.cols,\n maxRows: liveRef.current.maxRows,\n containerWidth: pp.containerWidth,\n containerHeight: liveRef.current.containerHeight,\n rowHeight: pp.rowHeight,\n margin: pp.margin,\n layout: layoutRef.current,\n },\n );\n\n // An auto-height widget cannot be resized shorter than the content it\n // hosts (a nested board) currently needs, so pin its height to the floor.\n const floorRows = autoHeightMinRowsRef.current[id] ?? 0;\n const finalW = constrained.w;\n const finalH = Math.max(constrained.h, floorRows);\n\n let x = item.x;\n let y = item.y;\n if (handle.includes('w')) x = item.x + item.w - finalW;\n if (handle.includes('n')) y = item.y + item.h - finalH;\n x = Math.max(0, x);\n y = Math.max(0, y);\n\n let newItem: LayoutItem = {\n ...item,\n x,\n y,\n w: finalW,\n h: finalH,\n };\n\n // Collision-blocking modes (`free` without `allowOverlap`, or an explicit\n // `preventCollision`) run a no-op/gap-filling compactor that never\n // resolves overlaps, so a resize must be blocked here the same way the\n // drag path blocks a move (`moveElement` reverts on collision). Without\n // this, growing or moving an edge via a resize handle could push the box\n // onto an occupied cell. When the new box overlaps a neighbour, revert to\n // the last committed box for this widget so the gesture stalls at the\n // last valid size/position instead of overlapping.\n const compactor = liveRef.current.compactor;\n if (compactor.preventCollision && !compactor.allowOverlap) {\n const collides = getAllCollisions(layoutRef.current, newItem).some(\n (other) => other.i !== id,\n );\n if (collides) {\n const lastValid = getLayoutItem(layoutRef.current, id);\n if (lastValid) newItem = { ...lastValid };\n }\n }\n\n const working = modifyLayout(layoutRef.current, newItem);\n const compacted = [...compactor.compact(working, pp.cols)];\n applyLayout(compacted, false);\n const nextPlaceholder = getLayoutItem(compacted, id) ?? newItem;\n setPlaceholders([nextPlaceholder]);\n const resizedItem = getLayoutItem(compacted, id) ?? newItem;\n onResizeProp?.({\n layout: compacted,\n item: resizedItem,\n oldItem: rs.item,\n placeholder: nextPlaceholder,\n items: [resizedItem],\n oldItems: [rs.item],\n placeholders: [nextPlaceholder],\n });\n },\n );\n\n // Record an auto-height widget's needed rows. Grow the item when its content\n // needs more height (only ever increases); the stored value is also the\n // resize floor enforced in `handleResize`.\n const handleAutoHeight = useEvent((id: string, neededRows: number) => {\n autoHeightMinRowsRef.current[id] = neededRows;\n const current = getLayoutItem(layoutRef.current, id);\n if (!current || neededRows <= current.h) return;\n // While a drag or resize gesture is in flight the layout is transient - the\n // registry (drag) and `handleResize` write uncommitted previews and commit\n // only on drop / release. Growing an auto-height widget here with\n // `commit: true` would fire `onLayoutChange` mid-gesture and persist the\n // in-flight positions of the widget being moved. Skip the grow-commit; the\n // floor ref is already updated above (so `handleResize` still respects it),\n // and the deficit effect re-fires once the gesture settles.\n if (registry.dragState || resizeStateRef.current) return;\n const pp = liveRef.current.positionParams;\n const working = modifyLayout(layoutRef.current, {\n ...current,\n h: neededRows,\n });\n const compacted = [...liveRef.current.compactor.compact(working, pp.cols)];\n applyLayout(compacted, true, 'normalize');\n });\n\n // The dragged item captured at gesture start, so drag callbacks can report the\n // original position throughout (and after a cross-board transfer removes the\n // item from this board's layout).\n const dragOldItemRef = useRef<LayoutItem | null>(null);\n // The same, for every other member of a group drag. Empty for an ordinary\n // drag, which is what keeps `items`/`oldItems` single-entry there.\n const dragOldItemsRef = useRef<LayoutItem[]>([]);\n\n const handleDragLifecycle = useEvent((id: string, phase: ResizePhase) => {\n const currentLayout = layoutRef.current;\n const liveItem = getLayoutItem(currentLayout, id);\n\n if (phase === 'start') {\n dragOldItemRef.current = liveItem ? { ...liveItem } : null;\n // The registry has already resolved the group by the time this fires, so\n // its drag state is the authority on who is moving.\n const ds = registry.getDragState();\n dragOldItemsRef.current =\n ds && ds.itemId === id ? ds.items.map((it) => ({ ...it })) : [];\n }\n const oldItem = dragOldItemRef.current ?? liveItem;\n if (!oldItem) return;\n const item = liveItem ?? oldItem;\n\n const oldItems = dragOldItemsRef.current.length\n ? dragOldItemsRef.current\n : [oldItem];\n const items = oldItems.map(\n (old) => getLayoutItem(currentLayout, old.i) ?? old,\n );\n\n const info: BoardInteractionInfo = {\n layout: currentLayout,\n item,\n oldItem,\n // Read the live refs, not render-time state: the registry calls\n // `setPlaceholders` synchronously right before this fires, and that only\n // schedules a re-render, so `placeholders` state still holds the previous\n // value (or a stale preview after the drop clears it).\n placeholder: placeholderRef.current,\n items,\n oldItems,\n placeholders: placeholdersRef.current,\n };\n if (phase === 'start') onDragStart?.(info);\n else if (phase === 'move') onDrag?.(info);\n else {\n onDragStop?.(info);\n dragOldItemRef.current = null;\n dragOldItemsRef.current = [];\n }\n });\n\n // ---- Marquee (rubber-band) selection --------------------------------------\n //\n // Board owns this rather than exposing hooks for an app to build it, because\n // deciding which widgets a band covers needs every widget's box — and the DOM\n // is the wrong place to read them from. Widget hosts transition `inset`/`width`\n // /`height` while the board reflows, and a host being dragged is swapped for an\n // `opacity: 0` stand-in with a fixed-position clone in the overlay, so\n // `getBoundingClientRect` during a marquee returns interpolated or misleading\n // boxes. `calcGridItemPosition` derives the same rectangles exactly, from the\n // layout, with no forced reflow and no sensitivity to ancestor transforms.\n const [marqueeRect, setMarqueeRect] = useState<Position | null>(null);\n // Which widgets the band covers *right now*. Committing only on release\n // leaves the user guessing what they are about to select, so the band drives a\n // provisional state on the hosts as it grows and shrinks. The board already\n // re-renders once per pointer frame for the band itself, so this is free.\n const [preSelectedKeys, setPreSelectedKeys] =\n useState<ReadonlySet<string>>(NO_KEYS);\n // Drives `user-select: none` for the duration of the gesture. Set on press\n // rather than at the threshold, so even a press that never becomes a marquee\n // cannot start painting a text selection.\n const [isMarqueeActive, setIsMarqueeActive] = useState(false);\n\n const handleContentPointerDown = useEvent((event: React.PointerEvent) => {\n if (\n selectionMode !== 'multiple' ||\n !allowMarqueeSelection ||\n event.button !== 0 ||\n registry.dragState\n ) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n // A press on a widget selects it and arms a drag; the lasso owns empty\n // canvas only.\n if (target?.closest('[data-board-widget-host]')) return;\n if (selectionCancel && target?.closest(selectionCancel)) return;\n\n const content = contentRef.current;\n if (!content) return;\n\n // Suppress the compatibility mouse events that would begin a native text\n // selection. Safe here specifically because every case that wants default\n // behaviour — a widget, an interactive descendant — has already bailed out\n // above, and focus is placed explicitly in `finish`.\n event.preventDefault();\n setIsMarqueeActive(true);\n\n const origin = content.getBoundingClientRect();\n const startX = event.clientX;\n const startY = event.clientY;\n // Holding the modifier means \"add to what I have\"; a bare lasso replaces.\n const additive = event[selectModifierKey] || event.shiftKey;\n const base = additive ? [...selectedKeysRef.current] : [];\n let passedThreshold = false;\n\n const hitTest = (clientX: number, clientY: number) => {\n const left = Math.min(startX, clientX) - origin.left;\n const right = Math.max(startX, clientX) - origin.left;\n const top = Math.min(startY, clientY) - origin.top;\n const bottom = Math.max(startY, clientY) - origin.top;\n const next = new Set(base);\n\n for (const it of layoutRef.current) {\n if (!isWidgetSelectable(it.i)) continue;\n const pos = calcGridItemPosition(\n liveRef.current.positionParams,\n it.x,\n it.y,\n it.w,\n it.h,\n );\n if (\n pos.left < right &&\n pos.left + pos.width > left &&\n pos.top < bottom &&\n pos.top + pos.height > top\n ) {\n next.add(it.i);\n }\n }\n\n return {\n next,\n box: { left, top, width: right - left, height: bottom - top },\n };\n };\n\n // Belt and braces for the `preventDefault` above: a press that starts on\n // empty canvas and then travels into text still gets a `selectstart` in some\n // browsers, and `user-select: none` alone does not unwind a selection that is\n // already growing.\n const blockSelectStart = (e: Event) => e.preventDefault();\n\n const handleMove = (e: PointerEvent) => {\n if (\n !passedThreshold &&\n Math.abs(e.clientX - startX) + Math.abs(e.clientY - startY) <\n MARQUEE_THRESHOLD\n ) {\n return;\n }\n if (!passedThreshold) {\n // Drop a selection the user made inside this board *before* the lasso\n // started, so the band never drags a stale highlight along with it.\n // Scoped to this board: a selection anywhere else on the page is theirs.\n const selection = window.getSelection();\n const anchor = selection?.anchorNode;\n if (anchor && containerRef.current?.contains(anchor)) {\n selection?.removeAllRanges();\n }\n }\n passedThreshold = true;\n\n const { box, next } = hitTest(e.clientX, e.clientY);\n setMarqueeRect(box);\n setPreSelectedKeys(next);\n };\n\n const finish = (e: PointerEvent) => {\n window.removeEventListener('pointermove', handleMove);\n window.removeEventListener('pointerup', finish);\n window.removeEventListener('pointercancel', finish);\n window.removeEventListener('selectstart', blockSelectStart);\n setMarqueeRect(null);\n setPreSelectedKeys(NO_KEYS);\n setIsMarqueeActive(false);\n\n // One commit per gesture: `onSelectionChange` and the announcement fire on\n // release, never once per pointer frame.\n if (passedThreshold) {\n setSelection(hitTest(e.clientX, e.clientY).next);\n } else if (!additive) {\n // A plain click on empty board space clears.\n clearSelection();\n }\n // Keep focus somewhere inside the board so Escape has a handler to reach.\n containerRef.current?.focus({ preventScroll: true });\n };\n\n window.addEventListener('pointermove', handleMove);\n window.addEventListener('pointerup', finish);\n window.addEventListener('pointercancel', finish);\n window.addEventListener('selectstart', blockSelectStart);\n });\n\n const marqueeStyle = marqueeRect\n ? {\n left: `${marqueeRect.left}px`,\n top: `${marqueeRect.top}px`,\n width: `${marqueeRect.width}px`,\n height: `${marqueeRect.height}px`,\n }\n : null;\n\n // Selection is focus-like, so it does not outlive focus leaving the board.\n // Tabbing away, or clicking any focusable thing elsewhere on the page, drops\n // it — the same way a text selection or a focus ring would go.\n const { focusWithinProps: boardFocusWithinProps } = useFocusWithin({\n isDisabled: selectionMode === 'none',\n onBlurWithin: () => clearSelection(),\n });\n\n // ---- Board-level keys -----------------------------------------------------\n //\n // On the board element, never on `document`: a library-owned document listener\n // fires for keystrokes that never went near a board, and two boards on a page\n // would both react.\n const handleBoardKeyDown = useEvent((event: React.KeyboardEvent) => {\n if (selectionMode === 'none') return;\n\n const selected = selectedKeysRef.current;\n if (selected.size === 0) return;\n\n if (event.key === 'Escape') {\n // `preventDefault` only when we actually consumed the key, so an Escape\n // with nothing selected still closes an ancestor Dialog or Popover.\n event.preventDefault();\n event.stopPropagation();\n clearSelection();\n\n return;\n }\n\n if (\n (event.key === 'Delete' || event.key === 'Backspace') &&\n onWidgetsDelete &&\n !isEditableTarget(event.target)\n ) {\n event.preventDefault();\n event.stopPropagation();\n const keys = [...selected];\n clearSelection();\n onWidgetsDelete(keys);\n // The deleted widgets' hosts are about to unmount, so focus would be left\n // on a detached node. Park it on the board.\n containerRef.current?.focus({ preventScroll: true });\n }\n });\n\n const styles: Styles = extractStyles(otherProps, CONTAINER_STYLES);\n\n const dragState = registry.dragState;\n const ready = width > 0;\n\n // Gate widget position transitions off until the widgets have been painted at\n // their initial positions once. Without this, the first render animates every\n // widget sliding in from its default spot (0, 0). We render one frame with the\n // gate closed (no `inset` transition), let the browser paint, then lift it so\n // later reflows animate. A double rAF waits past the first committed paint;\n // re-arm whenever the board (re)becomes ready so a board that hides and\n // remeasures (e.g. inside a tab) re-settles too.\n const [settled, setSettled] = useState(false);\n useEffect(() => {\n if (!ready) {\n setSettled(false);\n return;\n }\n let id1 = 0;\n let id2 = 0;\n id1 = requestAnimationFrame(() => {\n id2 = requestAnimationFrame(() => setSettled(true));\n });\n return () => {\n cancelAnimationFrame(id1);\n if (id2) cancelAnimationFrame(id2);\n };\n }, [ready]);\n\n // When the widget that hosts this nested board is the one being dragged, its\n // whole content (including this board) floats as a single unit, so its own\n // grid lines add nothing but clutter. Suppress them for that drag.\n const hostWidgetIsDragging =\n !!dragState && dragState.nestedBoardIds.has(boardId);\n\n const placeholderStyles = useMemo(\n () =>\n placeholders.map((p) => {\n const pos = calcGridItemPosition(positionParams, p.x, p.y, p.w, p.h);\n\n return {\n i: p.i,\n style: {\n left: `${pos.left}px`,\n top: `${pos.top}px`,\n width: `${pos.width}px`,\n height: `${pos.height}px`,\n },\n };\n }),\n [placeholders, positionParams],\n );\n\n // Which board a drag belongs to. `registry.dragState` is one value shared by\n // every board under a `Board.Provider`, so `'drag'` has to narrow it to the\n // boards actually taking part: the source the widget came from, and the board\n // it is currently over (kept up to date by the registry as the drag crosses\n // boards). Without this, dragging on the root board lights up the grid inside\n // every nested container - noise on boards the widget cannot land in.\n const ownsDrag =\n !!dragState &&\n (dragState.sourceBoardId === boardId ||\n dragState.currentBoardId === boardId);\n\n // `placeholder` is this board's own drop-slot preview, so it covers the two\n // cases `dragState` does not: a resize (never a registry drag) and a board the\n // registry has just seeded a preview on.\n const gridLinesVisible =\n !hostWidgetIsDragging &&\n (effectiveShowGridLines === true ||\n (effectiveShowGridLines === 'drag' && (ownsDrag || !!placeholder)) ||\n (effectiveShowGridLines === 'any-drag' &&\n (!!dragState || !!placeholder)));\n const gridOverlayStyle = gridLinesVisible\n ? (() => {\n const colWidth = calcGridColWidth(positionParams);\n const rowHeightPx = positionParams.rowHeight;\n // A grid with margins has real gaps between cells, so any line-based\n // overlay either misses a cell edge (single line at the cell pitch) or\n // shows a double line in every gap (a line at both edges). Instead,\n // paint each snap cell as a faint block sized exactly `colWidth` x\n // `rowHeightPx` with the margin gaps left transparent: the blocks line\n // up 1:1 with the drop-zone placeholder and there are no lines to\n // double. Column stripes form the background; a row-band alpha mask\n // intersects them into cells.\n const pitchX = colWidth + effectiveMargin[0];\n const pitchY = rowHeightPx + effectiveMargin[1];\n // Position the overlay as an explicit rectangle inset by the board's\n // resolved padding and sized to exactly cover the grid content (cols x\n // rows). This makes the padding a symmetric frame on all four edges (the\n // previous `inset: 0` + top-left-anchored repeat left the padding\n // unvisualized on the right/bottom and inside any extra min-height) and\n // lets the cell pattern tile from the overlay's own origin.\n const padX = resolvedPadding[0];\n const padY = resolvedPadding[1];\n const gridWidth = Math.max(0, effectiveContainerWidth - padX * 2);\n // Painted over the reserved band too — grid cells are what make the\n // band read as board rather than as page background behind it.\n const gridHeight =\n renderedRows > 0\n ? renderedRows * rowHeightPx +\n (renderedRows - 1) * effectiveMargin[1]\n : 0;\n const fill = 'var(--border-color)';\n const columns = `repeating-linear-gradient(to right, ${fill} 0, ${fill} ${colWidth}px, transparent ${colWidth}px, transparent ${pitchX}px)`;\n const rowsGrad = `repeating-linear-gradient(to bottom, #000 0, #000 ${rowHeightPx}px, transparent ${rowHeightPx}px, transparent ${pitchY}px)`;\n return {\n left: `${padX}px`,\n top: `${padY}px`,\n width: `${gridWidth}px`,\n height: `${gridHeight}px`,\n backgroundImage: columns,\n backgroundPosition: '0 0',\n backgroundRepeat: 'repeat',\n maskImage: rowsGrad,\n WebkitMaskImage: rowsGrad,\n maskPosition: '0 0',\n WebkitMaskPosition: '0 0',\n maskRepeat: 'repeat',\n WebkitMaskRepeat: 'repeat',\n };\n })()\n : null;\n\n // Metrics this board exposes to any aligned boards nested inside its widgets.\n const boardMetrics = useMemo<BoardMetrics>(\n () => ({\n colWidth: calcGridColWidth(positionParams),\n rowHeight: positionParams.rowHeight,\n margin: positionParams.margin,\n containerPadding: positionParams.containerPadding,\n }),\n [positionParams],\n );\n\n return (\n <BoardMetricsContext.Provider value={boardMetrics}>\n <BoardGridLinesContext.Provider\n value={\n effectiveShowGridLines === 'any-drag'\n ? 'any-drag'\n : effectiveShowGridLines\n ? 'drag'\n : false\n }\n >\n <BoardElement\n {...mergeProps(\n filterBaseProps(otherProps, { eventProps: true }),\n boardFocusWithinProps,\n { onKeyDown: handleBoardKeyDown },\n )}\n ref={containerRef}\n styles={styles}\n // A board that owns keys needs somewhere for focus to land after a\n // marquee or a delete, so Escape always reaches `handleBoardKeyDown`.\n tabIndex={selectionMode !== 'none' ? -1 : undefined}\n data-board-id={boardId}\n // Non-aligned: use min-height (not a fixed height) so the board\n // auto-sizes to its content by default but can still grow to fill a\n // taller parent. Widgets are absolutely positioned, so growing never\n // shifts them, and the content layer (inset: 0) always covers the full\n // board -> the whole board is droppable. Aligned: omit the inline height\n // so the board fills (and is bounded by) the space the container grants,\n // which is what drives the reduced row height. Stretch: take the\n // parent's height outright, since that height is precisely what gets\n // divided into rows — a min-height derived from the board's own rows\n // would be a fixed point (it would measure back what it just asked\n // for) and the cells could never track the container.\n style={\n aligned\n ? undefined\n : isStretching\n ? { height: '100%' }\n : { minHeight: `${containerHeight}px` }\n }\n mods={{\n dragging: !!dragState,\n 'drop-target': dragState?.currentBoardId === boardId,\n marquee: isMarqueeActive,\n }}\n >\n <ContentLayer\n ref={contentRef}\n onPointerDown={handleContentPointerDown}\n >\n {ready && gridOverlayStyle ? (\n <GridOverlayElement aria-hidden=\"true\" style={gridOverlayStyle} />\n ) : null}\n {ready\n ? layout.map((item) => {\n const registration = registry.store.get(item.i);\n const widgetDraggable =\n isDraggable &&\n (registration?.isDraggable ?? widgetProps?.isDraggable) !==\n false &&\n item.isDraggable !== false &&\n !item.static;\n const widgetResizable =\n isResizable &&\n (registration?.isResizable ?? widgetProps?.isResizable) !==\n false &&\n item.isResizable !== false &&\n !item.static;\n const handles =\n item.resizeHandles ??\n registration?.resizeHandles ??\n widgetProps?.resizeHandles ??\n resizeHandles;\n const gripPlacement =\n registration?.resizeGripPlacement ??\n widgetProps?.resizeGripPlacement ??\n resizeGripPlacement;\n const widgetDragCancel =\n registration?.dragCancel ??\n widgetProps?.dragCancel ??\n dragCancel;\n const widgetDragHandle =\n registration?.dragHandle ??\n widgetProps?.dragHandle ??\n dragHandle;\n // Per-widget `isCard`/`styles` override the board-level\n // `widgetProps` defaults; `isCard` defaults to `false`\n // (borderless - widgets are always filled and rounded).\n const widgetIsCard =\n registration?.isCard ?? widgetProps?.isCard ?? false;\n const widgetHoverRing =\n registration?.hoverRing ?? widgetProps?.hoverRing ?? true;\n // Board-level mods merge UNDER the per-widget ones, mirroring\n // how `widgetProps.styles` merges under a widget's own styles:\n // a shared default every widget carries, which any one widget\n // can override for itself. Only allocate when both exist.\n const widgetMods =\n registration?.mods && widgetProps?.mods\n ? { ...widgetProps.mods, ...registration.mods }\n : registration?.mods ?? widgetProps?.mods;\n // Per-widget `isAutoHeight`/`qa` fall back to the board-level\n // `widgetProps` defaults (mirroring the other widget props).\n const widgetIsAutoHeight =\n registration?.isAutoHeight ??\n widgetProps?.isAutoHeight ??\n false;\n const widgetQa = registration?.qa ?? widgetProps?.qa;\n const widgetSelectable =\n selectionMode !== 'none' && isWidgetSelectable(item.i);\n const widgetSelectionCancel =\n registration?.selectionCancel ??\n widgetProps?.selectionCancel ??\n selectionCancel;\n // Merge board-level `widgetProps` styles (its `styles` object\n // plus direct style props) with the per-widget styles so\n // shared defaults survive when a widget sets even a single\n // style prop; per-widget styles win on conflicts. Only merge\n // when both exist to preserve reference stability (and avoid\n // churn) in the common single-source case.\n const widgetStyles =\n registration?.styles && widgetPropsStyles\n ? mergeStyles(widgetPropsStyles, registration.styles)\n : registration?.styles ?? widgetPropsStyles;\n\n return (\n <WidgetHost\n key={item.i}\n boardId={boardId}\n item={item}\n positionParams={positionParams}\n registration={registration}\n isCard={widgetIsCard}\n hoverRing={widgetHoverRing}\n cornerChrome={\n registration?.cornerChrome ?? widgetProps?.cornerChrome\n }\n cornerChromePlacement={\n registration?.cornerChromePlacement ??\n widgetProps?.cornerChromePlacement\n }\n mods={widgetMods}\n styles={widgetStyles as Styles}\n isDraggable={widgetDraggable}\n isResizable={widgetResizable}\n resizeHandles={handles}\n resizeGripPlacement={gripPlacement}\n isAutoHeight={widgetIsAutoHeight}\n qa={widgetQa}\n dragCancel={widgetDragCancel}\n dragHandle={widgetDragHandle}\n isSelectable={widgetSelectable}\n isSelected={selectedKeySet.has(item.i)}\n isPreSelected={preSelectedKeys.has(item.i)}\n selectionCancel={widgetSelectionCancel}\n selectedHintId={selectedHintId}\n onSelect={select}\n onSelectionReset={clearSelection}\n selectModifierKey={selectModifierKey}\n registry={registry}\n dragState={dragState}\n settled={settled}\n onResize={handleResize}\n onAutoHeight={handleAutoHeight}\n onDragLifecycle={handleDragLifecycle}\n />\n );\n })\n : null}\n {placeholderStyles.map(({ i, style }) => (\n <PlaceholderElement key={i} aria-hidden=\"true\" style={style} />\n ))}\n {marqueeStyle ? (\n <MarqueeElement aria-hidden=\"true\" style={marqueeStyle} />\n ) : null}\n </ContentLayer>\n {selectionMode !== 'none' ? (\n <A11yLayer>\n <span id={selectedHintId}>{t('board.selected', 'Selected')}</span>\n <span role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {announcement}\n </span>\n </A11yLayer>\n ) : null}\n {children}\n </BoardElement>\n </BoardGridLinesContext.Provider>\n </BoardMetricsContext.Provider>\n );\n}\n\nconst BoardInnerForwarded = forwardRef(BoardInner);\n\n/**\n * A draggable and resizable widget grid. Widgets are declared with\n * `Board.Widget` and positioned via a `layout`. Wrap multiple boards in a\n * `BoardProvider` to enable dragging widgets between them.\n */\nexport const Board = forwardRef(function Board(\n props: CubeBoardProps,\n ref: React.ForwardedRef<HTMLDivElement>,\n) {\n const existingRegistry = useBoardRegistry();\n\n if (existingRegistry) {\n return <BoardInnerForwarded {...props} ref={ref} />;\n }\n\n return (\n <BoardProvider>\n <BoardInnerForwarded {...props} ref={ref} />\n </BoardProvider>\n );\n});\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- /** @license MIT | @cube-dev/ui-kit v0.166.0 | Cube Dev Team */
1
+ /** @license MIT | @cube-dev/ui-kit v0.168.0 | Cube Dev Team */
2
2
  import { BoardDragActiveContext, BoardRegistryContext } from "./board-context.js";
3
3
  import { useBoardRegistry } from "./use-board-registry.js";
4
4
  import { tasty } from "@tenphi/tasty";
@@ -1,5 +1,6 @@
1
1
 
2
2
  import { LayoutItem } from "./grid-core/types.js";
3
+ import { BoardLayoutChangeInfo } from "./use-board-layout.js";
3
4
  import { CubeBoardProps } from "./Board.js";
4
5
  import { BreakpointCols, Breakpoints, ResponsiveLayouts } from "./responsive-utils.js";
5
6
  import * as react from "react";
@@ -15,10 +16,12 @@ interface CubeBoardResponsiveProps extends Omit<CubeBoardProps, 'layout' | 'defa
15
16
  /** Initial per-breakpoint layouts for uncontrolled usage. */
16
17
  defaultLayouts?: ResponsiveLayouts;
17
18
  /**
18
- * Called when a drag or resize is committed. Receives the active breakpoint's
19
- * layout and the full map of all breakpoint layouts.
19
+ * Called when the layout is committed. Receives the active breakpoint's
20
+ * layout, the full map of all breakpoint layouts, and why it changed — see
21
+ * {@link BoardLayoutChangeInfo}, which is what separates a user's gesture
22
+ * from the board reflowing itself.
20
23
  */
21
- onLayoutChange?: (currentLayout: LayoutItem[], allLayouts: ResponsiveLayouts) => void;
24
+ onLayoutChange?: (currentLayout: LayoutItem[], allLayouts: ResponsiveLayouts, info: BoardLayoutChangeInfo) => void;
22
25
  /** Called when the active breakpoint changes. */
23
26
  onBreakpointChange?: (breakpoint: string, cols: number) => void;
24
27
  /**
@@ -1,4 +1,4 @@
1
- /** @license MIT | @cube-dev/ui-kit v0.166.0 | Cube Dev Team */
1
+ /** @license MIT | @cube-dev/ui-kit v0.168.0 | Cube Dev Team */
2
2
  import { useCombinedRefs } from "../../../utils/react/useCombinedRefs.js";
3
3
  import { useEvent } from "../../../_internal/hooks/use-event.js";
4
4
  import { getCompactor } from "./grid-core/compactors.js";
@@ -75,14 +75,14 @@ function BoardResponsiveInner(props, ref) {
75
75
  compact,
76
76
  allowOverlap,
77
77
  preventCollision,
78
- onLayoutChange: useEvent((next) => {
78
+ onLayoutChange: useEvent((next, info) => {
79
79
  const merged = {
80
80
  ...layoutsRef.current,
81
81
  [activeBreakpoint]: next
82
82
  };
83
83
  layoutsRef.current = merged;
84
84
  if (!isControlled) setInternalLayouts(merged);
85
- onLayoutChange?.(next, merged);
85
+ onLayoutChange?.(next, merged, info);
86
86
  }),
87
87
  ...boardProps
88
88
  });
@@ -1 +1 @@
1
- {"version":3,"file":"BoardResponsive.js","names":[],"sources":["../../../../src/components/layout/Board/BoardResponsive.tsx"],"sourcesContent":["import { useResizeObserver } from '@react-aria/utils';\nimport { forwardRef, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useEvent } from '../../../_internal/hooks';\nimport { useCombinedRefs } from '../../../utils/react';\n\nimport { Board } from './Board';\nimport { Compactor, CompactType, getCompactor, LayoutItem } from './grid-core';\nimport {\n BreakpointCols,\n Breakpoints,\n findOrGenerateResponsiveLayout,\n getBreakpointFromWidth,\n getColsFromBreakpoint,\n ResponsiveLayouts,\n} from './responsive-utils';\n\nimport type { BoardCompactType, CubeBoardProps } from './Board';\n\nexport interface CubeBoardResponsiveProps\n extends Omit<\n CubeBoardProps,\n | 'layout'\n | 'defaultLayout'\n | 'cols'\n | 'onLayoutChange'\n | 'width'\n | 'breakpoints'\n > {\n /** Map of breakpoint name -> minimum container width in pixels. */\n breakpoints: Breakpoints;\n /** Map of breakpoint name -> column count. */\n cols: BreakpointCols;\n /** Controlled per-breakpoint layouts. */\n layouts?: ResponsiveLayouts;\n /** Initial per-breakpoint layouts for uncontrolled usage. */\n defaultLayouts?: ResponsiveLayouts;\n /**\n * Called when a drag or resize is committed. Receives the active breakpoint's\n * layout and the full map of all breakpoint layouts.\n */\n onLayoutChange?: (\n currentLayout: LayoutItem[],\n allLayouts: ResponsiveLayouts,\n ) => void;\n /** Called when the active breakpoint changes. */\n onBreakpointChange?: (breakpoint: string, cols: number) => void;\n /**\n * Called when the measured container width changes, with the current column\n * count for the active breakpoint. Mirrors react-grid-layout's\n * `WidthProvider` `onWidthChange`. Not fired while width is unmeasured (0) or\n * when an explicit `width` is provided.\n */\n onWidthChange?: (width: number, cols: number) => void;\n /**\n * Force a specific breakpoint regardless of the measured width (e.g. for a\n * fixed-size screenshot or PDF export).\n */\n breakpoint?: string;\n /**\n * Explicit container width in pixels. When provided, disables automatic width\n * measurement (useful for SSR, tests, and forced-size exports).\n */\n width?: number;\n}\n\nfunction compactTypeToCore(compact: BoardCompactType): CompactType {\n if (compact === 'free') return null;\n return compact;\n}\n\nfunction BoardResponsiveInner(\n props: CubeBoardResponsiveProps,\n ref: React.ForwardedRef<HTMLDivElement>,\n) {\n const {\n breakpoints,\n cols,\n layouts: controlledLayouts,\n defaultLayouts,\n onLayoutChange,\n onBreakpointChange,\n onWidthChange,\n breakpoint: forcedBreakpoint,\n width: providedWidth,\n compact = 'vertical',\n allowOverlap = false,\n preventCollision = false,\n ...boardProps\n } = props;\n\n const boardRef = useRef<HTMLDivElement | null>(null);\n const combinedRef = useCombinedRefs(ref, boardRef);\n const [measuredWidth, setMeasuredWidth] = useState(0);\n\n const onResizeElement = useEvent(() => {\n const next = boardRef.current?.offsetWidth ?? 0;\n if (next > 0) setMeasuredWidth((prev) => (prev === next ? prev : next));\n });\n useResizeObserver({ ref: boardRef, onResize: onResizeElement });\n\n const isControlled = controlledLayouts !== undefined;\n const [internalLayouts, setInternalLayouts] = useState<ResponsiveLayouts>(\n () => controlledLayouts ?? defaultLayouts ?? {},\n );\n const currentLayouts = isControlled ? controlledLayouts! : internalLayouts;\n const layoutsRef = useRef(currentLayouts);\n layoutsRef.current = currentLayouts;\n\n const widthForBreakpoint = providedWidth ?? measuredWidth;\n const activeBreakpoint =\n forcedBreakpoint ?? getBreakpointFromWidth(breakpoints, widthForBreakpoint);\n const activeCols = getColsFromBreakpoint(activeBreakpoint, cols);\n\n // Previous breakpoint, used as the preferred source when synthesizing a layout\n // for a breakpoint that has none yet.\n const lastBreakpointRef = useRef(activeBreakpoint);\n\n // This compactor is only used to synthesize a layout for a breakpoint that has\n // none yet (compaction/bounds correction), so `preventCollision` has no effect\n // here - the drag-time behavior comes from the child `Board`'s own compactor\n // (see the free-mode note in `Board.tsx`).\n const compactor = useMemo<Compactor>(\n () =>\n getCompactor(compactTypeToCore(compact), allowOverlap, preventCollision),\n [compact, allowOverlap, preventCollision],\n );\n\n // Keep a stable reference for an existing breakpoint's layout so the child\n // `Board` (which syncs controlled layout by reference) is not reset every\n // render or mid-drag. Only a genuinely missing breakpoint is synthesized.\n const currentLayout = useMemo(() => {\n const existing = currentLayouts[activeBreakpoint];\n if (existing) return existing;\n return findOrGenerateResponsiveLayout(\n currentLayouts,\n breakpoints,\n activeBreakpoint,\n lastBreakpointRef.current,\n activeCols,\n compactor,\n );\n }, [currentLayouts, breakpoints, activeBreakpoint, activeCols, compactor]);\n\n // Remember the last breakpoint (for synthesizing a missing one) and emit\n // breakpoint changes after commit, skipping the initial mount.\n const onBreakpointChangeEvent = useEvent(() =>\n onBreakpointChange?.(activeBreakpoint, activeCols),\n );\n const bpInitializedRef = useRef(false);\n useEffect(() => {\n if (!bpInitializedRef.current) {\n bpInitializedRef.current = true;\n lastBreakpointRef.current = activeBreakpoint;\n return;\n }\n onBreakpointChangeEvent();\n lastBreakpointRef.current = activeBreakpoint;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeBreakpoint]);\n\n // Report width changes (measured widths only; an explicit `width` disables\n // measurement, and an unmeasured board reports 0 which we skip).\n const onWidthChangeEvent = useEvent(() =>\n onWidthChange?.(widthForBreakpoint, activeCols),\n );\n useEffect(() => {\n if (providedWidth != null) return;\n if (measuredWidth <= 0) return;\n onWidthChangeEvent();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [measuredWidth, activeCols]);\n\n const handleLayoutChange = useEvent((next: LayoutItem[]) => {\n const merged = { ...layoutsRef.current, [activeBreakpoint]: next };\n layoutsRef.current = merged;\n if (!isControlled) setInternalLayouts(merged);\n onLayoutChange?.(next, merged);\n });\n\n return (\n <Board\n ref={combinedRef}\n layout={currentLayout}\n cols={activeCols}\n width={providedWidth}\n compact={compact}\n allowOverlap={allowOverlap}\n preventCollision={preventCollision}\n onLayoutChange={handleLayoutChange}\n {...boardProps}\n />\n );\n}\n\n/**\n * A responsive wrapper around `Board` that selects a layout and column count\n * based on the container's width (or a forced breakpoint). Mirrors the model of\n * react-grid-layout's `Responsive` + `WidthProvider`: per-breakpoint `layouts`\n * and `cols`, with `onLayoutChange` reporting both the active layout and the\n * full map.\n */\nexport const BoardResponsive = forwardRef(BoardResponsiveInner);\n"],"mappings":";;;;;;;;;;;AAkEA,SAAS,kBAAkB,SAAwC;AACjE,KAAI,YAAY,OAAQ,QAAO;AAC/B,QAAO;;AAGT,SAAS,qBACP,OACA,KACA;CACA,MAAM,EACJ,aACA,MACA,SAAS,mBACT,gBACA,gBACA,oBACA,eACA,YAAY,kBACZ,OAAO,eACP,UAAU,YACV,eAAe,OACf,mBAAmB,OACnB,GAAG,eACD;CAEJ,MAAM,WAAW,OAA8B,KAAK;CACpD,MAAM,cAAc,gBAAgB,KAAK,SAAS;CAClD,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;AAMrD,mBAAkB;EAAE,KAAK;EAAU,UAJX,eAAe;GACrC,MAAM,OAAO,SAAS,SAAS,eAAe;AAC9C,OAAI,OAAO,EAAG,mBAAkB,SAAU,SAAS,OAAO,OAAO,KAAM;IACvE;EAC4D,CAAC;CAE/D,MAAM,eAAe,sBAAsB;CAC3C,MAAM,CAAC,iBAAiB,sBAAsB,eACtC,qBAAqB,kBAAkB,EAAE,CAChD;CACD,MAAM,iBAAiB,eAAe,oBAAqB;CAC3D,MAAM,aAAa,OAAO,eAAe;AACzC,YAAW,UAAU;CAErB,MAAM,qBAAqB,iBAAiB;CAC5C,MAAM,mBACJ,oBAAoB,uBAAuB,aAAa,mBAAmB;CAC7E,MAAM,aAAa,sBAAsB,kBAAkB,KAAK;CAIhE,MAAM,oBAAoB,OAAO,iBAAiB;CAMlD,MAAM,YAAY,cAEd,aAAa,kBAAkB,QAAQ,EAAE,cAAc,iBAAiB,EAC1E;EAAC;EAAS;EAAc;EAAiB,CAC1C;CAKD,MAAM,gBAAgB,cAAc;EAClC,MAAM,WAAW,eAAe;AAChC,MAAI,SAAU,QAAO;AACrB,SAAO,+BACL,gBACA,aACA,kBACA,kBAAkB,SAClB,YACA,UACD;IACA;EAAC;EAAgB;EAAa;EAAkB;EAAY;EAAU,CAAC;CAI1E,MAAM,0BAA0B,eAC9B,qBAAqB,kBAAkB,WAAW,CACnD;CACD,MAAM,mBAAmB,OAAO,MAAM;AACtC,iBAAgB;AACd,MAAI,CAAC,iBAAiB,SAAS;AAC7B,oBAAiB,UAAU;AAC3B,qBAAkB,UAAU;AAC5B;;AAEF,2BAAyB;AACzB,oBAAkB,UAAU;IAE3B,CAAC,iBAAiB,CAAC;CAItB,MAAM,qBAAqB,eACzB,gBAAgB,oBAAoB,WAAW,CAChD;AACD,iBAAgB;AACd,MAAI,iBAAiB,KAAM;AAC3B,MAAI,iBAAiB,EAAG;AACxB,sBAAoB;IAEnB,CAAC,eAAe,WAAW,CAAC;AAS/B,QACE,oBAAC;EACC,KAAK;EACL,QAAQ;EACR,MAAM;EACN,OAAO;EACE;EACK;EACI;EAClB,gBAhBuB,UAAU,SAAuB;GAC1D,MAAM,SAAS;IAAE,GAAG,WAAW;KAAU,mBAAmB;IAAM;AAClE,cAAW,UAAU;AACrB,OAAI,CAAC,aAAc,oBAAmB,OAAO;AAC7C,oBAAiB,MAAM,OAAO;IAC9B;EAYE,GAAI;GACJ;;;;;;;;;AAWN,MAAa,kBAAkB,WAAW,qBAAqB"}
1
+ {"version":3,"file":"BoardResponsive.js","names":[],"sources":["../../../../src/components/layout/Board/BoardResponsive.tsx"],"sourcesContent":["import { useResizeObserver } from '@react-aria/utils';\nimport { forwardRef, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useEvent } from '../../../_internal/hooks';\nimport { useCombinedRefs } from '../../../utils/react';\n\nimport { Board } from './Board';\nimport { Compactor, CompactType, getCompactor, LayoutItem } from './grid-core';\nimport {\n BreakpointCols,\n Breakpoints,\n findOrGenerateResponsiveLayout,\n getBreakpointFromWidth,\n getColsFromBreakpoint,\n ResponsiveLayouts,\n} from './responsive-utils';\n\nimport type { BoardCompactType, CubeBoardProps } from './Board';\nimport type { BoardLayoutChangeInfo } from './use-board-layout';\n\nexport interface CubeBoardResponsiveProps\n extends Omit<\n CubeBoardProps,\n | 'layout'\n | 'defaultLayout'\n | 'cols'\n | 'onLayoutChange'\n | 'width'\n | 'breakpoints'\n > {\n /** Map of breakpoint name -> minimum container width in pixels. */\n breakpoints: Breakpoints;\n /** Map of breakpoint name -> column count. */\n cols: BreakpointCols;\n /** Controlled per-breakpoint layouts. */\n layouts?: ResponsiveLayouts;\n /** Initial per-breakpoint layouts for uncontrolled usage. */\n defaultLayouts?: ResponsiveLayouts;\n /**\n * Called when the layout is committed. Receives the active breakpoint's\n * layout, the full map of all breakpoint layouts, and why it changed — see\n * {@link BoardLayoutChangeInfo}, which is what separates a user's gesture\n * from the board reflowing itself.\n */\n onLayoutChange?: (\n currentLayout: LayoutItem[],\n allLayouts: ResponsiveLayouts,\n info: BoardLayoutChangeInfo,\n ) => void;\n /** Called when the active breakpoint changes. */\n onBreakpointChange?: (breakpoint: string, cols: number) => void;\n /**\n * Called when the measured container width changes, with the current column\n * count for the active breakpoint. Mirrors react-grid-layout's\n * `WidthProvider` `onWidthChange`. Not fired while width is unmeasured (0) or\n * when an explicit `width` is provided.\n */\n onWidthChange?: (width: number, cols: number) => void;\n /**\n * Force a specific breakpoint regardless of the measured width (e.g. for a\n * fixed-size screenshot or PDF export).\n */\n breakpoint?: string;\n /**\n * Explicit container width in pixels. When provided, disables automatic width\n * measurement (useful for SSR, tests, and forced-size exports).\n */\n width?: number;\n}\n\nfunction compactTypeToCore(compact: BoardCompactType): CompactType {\n if (compact === 'free') return null;\n return compact;\n}\n\nfunction BoardResponsiveInner(\n props: CubeBoardResponsiveProps,\n ref: React.ForwardedRef<HTMLDivElement>,\n) {\n const {\n breakpoints,\n cols,\n layouts: controlledLayouts,\n defaultLayouts,\n onLayoutChange,\n onBreakpointChange,\n onWidthChange,\n breakpoint: forcedBreakpoint,\n width: providedWidth,\n compact = 'vertical',\n allowOverlap = false,\n preventCollision = false,\n ...boardProps\n } = props;\n\n const boardRef = useRef<HTMLDivElement | null>(null);\n const combinedRef = useCombinedRefs(ref, boardRef);\n const [measuredWidth, setMeasuredWidth] = useState(0);\n\n const onResizeElement = useEvent(() => {\n const next = boardRef.current?.offsetWidth ?? 0;\n if (next > 0) setMeasuredWidth((prev) => (prev === next ? prev : next));\n });\n useResizeObserver({ ref: boardRef, onResize: onResizeElement });\n\n const isControlled = controlledLayouts !== undefined;\n const [internalLayouts, setInternalLayouts] = useState<ResponsiveLayouts>(\n () => controlledLayouts ?? defaultLayouts ?? {},\n );\n const currentLayouts = isControlled ? controlledLayouts! : internalLayouts;\n const layoutsRef = useRef(currentLayouts);\n layoutsRef.current = currentLayouts;\n\n const widthForBreakpoint = providedWidth ?? measuredWidth;\n const activeBreakpoint =\n forcedBreakpoint ?? getBreakpointFromWidth(breakpoints, widthForBreakpoint);\n const activeCols = getColsFromBreakpoint(activeBreakpoint, cols);\n\n // Previous breakpoint, used as the preferred source when synthesizing a layout\n // for a breakpoint that has none yet.\n const lastBreakpointRef = useRef(activeBreakpoint);\n\n // This compactor is only used to synthesize a layout for a breakpoint that has\n // none yet (compaction/bounds correction), so `preventCollision` has no effect\n // here - the drag-time behavior comes from the child `Board`'s own compactor\n // (see the free-mode note in `Board.tsx`).\n const compactor = useMemo<Compactor>(\n () =>\n getCompactor(compactTypeToCore(compact), allowOverlap, preventCollision),\n [compact, allowOverlap, preventCollision],\n );\n\n // Keep a stable reference for an existing breakpoint's layout so the child\n // `Board` (which syncs controlled layout by reference) is not reset every\n // render or mid-drag. Only a genuinely missing breakpoint is synthesized.\n const currentLayout = useMemo(() => {\n const existing = currentLayouts[activeBreakpoint];\n if (existing) return existing;\n return findOrGenerateResponsiveLayout(\n currentLayouts,\n breakpoints,\n activeBreakpoint,\n lastBreakpointRef.current,\n activeCols,\n compactor,\n );\n }, [currentLayouts, breakpoints, activeBreakpoint, activeCols, compactor]);\n\n // Remember the last breakpoint (for synthesizing a missing one) and emit\n // breakpoint changes after commit, skipping the initial mount.\n const onBreakpointChangeEvent = useEvent(() =>\n onBreakpointChange?.(activeBreakpoint, activeCols),\n );\n const bpInitializedRef = useRef(false);\n useEffect(() => {\n if (!bpInitializedRef.current) {\n bpInitializedRef.current = true;\n lastBreakpointRef.current = activeBreakpoint;\n return;\n }\n onBreakpointChangeEvent();\n lastBreakpointRef.current = activeBreakpoint;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeBreakpoint]);\n\n // Report width changes (measured widths only; an explicit `width` disables\n // measurement, and an unmeasured board reports 0 which we skip).\n const onWidthChangeEvent = useEvent(() =>\n onWidthChange?.(widthForBreakpoint, activeCols),\n );\n useEffect(() => {\n if (providedWidth != null) return;\n if (measuredWidth <= 0) return;\n onWidthChangeEvent();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [measuredWidth, activeCols]);\n\n const handleLayoutChange = useEvent(\n (next: LayoutItem[], info: BoardLayoutChangeInfo) => {\n const merged = { ...layoutsRef.current, [activeBreakpoint]: next };\n layoutsRef.current = merged;\n if (!isControlled) setInternalLayouts(merged);\n onLayoutChange?.(next, merged, info);\n },\n );\n\n return (\n <Board\n ref={combinedRef}\n layout={currentLayout}\n cols={activeCols}\n width={providedWidth}\n compact={compact}\n allowOverlap={allowOverlap}\n preventCollision={preventCollision}\n onLayoutChange={handleLayoutChange}\n {...boardProps}\n />\n );\n}\n\n/**\n * A responsive wrapper around `Board` that selects a layout and column count\n * based on the container's width (or a forced breakpoint). Mirrors the model of\n * react-grid-layout's `Responsive` + `WidthProvider`: per-breakpoint `layouts`\n * and `cols`, with `onLayoutChange` reporting both the active layout and the\n * full map.\n */\nexport const BoardResponsive = forwardRef(BoardResponsiveInner);\n"],"mappings":";;;;;;;;;;;AAsEA,SAAS,kBAAkB,SAAwC;AACjE,KAAI,YAAY,OAAQ,QAAO;AAC/B,QAAO;;AAGT,SAAS,qBACP,OACA,KACA;CACA,MAAM,EACJ,aACA,MACA,SAAS,mBACT,gBACA,gBACA,oBACA,eACA,YAAY,kBACZ,OAAO,eACP,UAAU,YACV,eAAe,OACf,mBAAmB,OACnB,GAAG,eACD;CAEJ,MAAM,WAAW,OAA8B,KAAK;CACpD,MAAM,cAAc,gBAAgB,KAAK,SAAS;CAClD,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;AAMrD,mBAAkB;EAAE,KAAK;EAAU,UAJX,eAAe;GACrC,MAAM,OAAO,SAAS,SAAS,eAAe;AAC9C,OAAI,OAAO,EAAG,mBAAkB,SAAU,SAAS,OAAO,OAAO,KAAM;IACvE;EAC4D,CAAC;CAE/D,MAAM,eAAe,sBAAsB;CAC3C,MAAM,CAAC,iBAAiB,sBAAsB,eACtC,qBAAqB,kBAAkB,EAAE,CAChD;CACD,MAAM,iBAAiB,eAAe,oBAAqB;CAC3D,MAAM,aAAa,OAAO,eAAe;AACzC,YAAW,UAAU;CAErB,MAAM,qBAAqB,iBAAiB;CAC5C,MAAM,mBACJ,oBAAoB,uBAAuB,aAAa,mBAAmB;CAC7E,MAAM,aAAa,sBAAsB,kBAAkB,KAAK;CAIhE,MAAM,oBAAoB,OAAO,iBAAiB;CAMlD,MAAM,YAAY,cAEd,aAAa,kBAAkB,QAAQ,EAAE,cAAc,iBAAiB,EAC1E;EAAC;EAAS;EAAc;EAAiB,CAC1C;CAKD,MAAM,gBAAgB,cAAc;EAClC,MAAM,WAAW,eAAe;AAChC,MAAI,SAAU,QAAO;AACrB,SAAO,+BACL,gBACA,aACA,kBACA,kBAAkB,SAClB,YACA,UACD;IACA;EAAC;EAAgB;EAAa;EAAkB;EAAY;EAAU,CAAC;CAI1E,MAAM,0BAA0B,eAC9B,qBAAqB,kBAAkB,WAAW,CACnD;CACD,MAAM,mBAAmB,OAAO,MAAM;AACtC,iBAAgB;AACd,MAAI,CAAC,iBAAiB,SAAS;AAC7B,oBAAiB,UAAU;AAC3B,qBAAkB,UAAU;AAC5B;;AAEF,2BAAyB;AACzB,oBAAkB,UAAU;IAE3B,CAAC,iBAAiB,CAAC;CAItB,MAAM,qBAAqB,eACzB,gBAAgB,oBAAoB,WAAW,CAChD;AACD,iBAAgB;AACd,MAAI,iBAAiB,KAAM;AAC3B,MAAI,iBAAiB,EAAG;AACxB,sBAAoB;IAEnB,CAAC,eAAe,WAAW,CAAC;AAW/B,QACE,oBAAC;EACC,KAAK;EACL,QAAQ;EACR,MAAM;EACN,OAAO;EACE;EACK;EACI;EAClB,gBAlBuB,UACxB,MAAoB,SAAgC;GACnD,MAAM,SAAS;IAAE,GAAG,WAAW;KAAU,mBAAmB;IAAM;AAClE,cAAW,UAAU;AACrB,OAAI,CAAC,aAAc,oBAAmB,OAAO;AAC7C,oBAAiB,MAAM,QAAQ,KAAK;IAEvC;EAYG,GAAI;GACJ;;;;;;;;;AAWN,MAAa,kBAAkB,WAAW,qBAAqB"}
@@ -17,6 +17,8 @@ import { ReactNode } from "react";
17
17
  * (`n`/`s`/`e`/`w`) always sit inside the widget.
18
18
  */
19
19
  type BoardResizeGripPlacement = 'inside' | 'corner';
20
+ /** Which corner of a widget a piece of chrome is anchored to. */
21
+ type BoardCornerPlacement = 'ne' | 'nw' | 'se' | 'sw';
20
22
  interface CubeBoardWidgetProps extends ContainerStyleProps {
21
23
  /** Unique id, must match the `i` of a layout item in a `Board`. */
22
24
  id: string;
@@ -46,6 +48,32 @@ interface CubeBoardWidgetProps extends ContainerStyleProps {
46
48
  * @default true
47
49
  */
48
50
  hoverRing?: boolean;
51
+ /**
52
+ * A control anchored to one corner of the widget and centred on it — a
53
+ * settings button, a badge, a remove affordance.
54
+ *
55
+ * Drawn in the same layer as the corner resize grips, which is the layer that
56
+ * escapes the widget's own clip. Hanging such a control off the corner from
57
+ * inside the widget gets it cropped in half by that clip, or by an ancestor's
58
+ * scroll container when the widget is in the first row. It is also outside the
59
+ * drag gesture, so a press on it can never start a drag.
60
+ */
61
+ cornerChrome?: ReactNode;
62
+ /**
63
+ * Which corner {@link cornerChrome} sits on. Pair it with a
64
+ * `resizeGripPlacement="corner"` grip on the opposite corner and the two line
65
+ * up. @default 'ne'
66
+ */
67
+ cornerChromePlacement?: BoardCornerPlacement;
68
+ /**
69
+ * App-defined modifiers for this widget, merged into the ones the board sets
70
+ * so a `styles` map can match on app state: `mods={{ editing: true }}` with
71
+ * `styles={{ shadow: { editing: '0 0 0 1bw #primary' } }}`.
72
+ *
73
+ * Board's own modifiers always win, so a custom one can never shadow
74
+ * `selected`, `drag` and the rest.
75
+ */
76
+ mods?: Record<string, boolean | string | undefined>;
49
77
  /** Minimum width in grid columns (used when the layout item omits `minW`). */
50
78
  minW?: number;
51
79
  /** Maximum width in grid columns (used when the layout item omits `maxW`). */
@@ -105,5 +133,5 @@ interface CubeBoardWidgetProps extends ContainerStyleProps {
105
133
  */
106
134
  declare function Widget(props: CubeBoardWidgetProps): null;
107
135
  //#endregion
108
- export { BoardResizeGripPlacement, CubeBoardWidgetProps, Widget };
136
+ export { BoardCornerPlacement, BoardResizeGripPlacement, CubeBoardWidgetProps, Widget };
109
137
  //# sourceMappingURL=Widget.d.ts.map
@@ -1,4 +1,4 @@
1
- /** @license MIT | @cube-dev/ui-kit v0.166.0 | Cube Dev Team */
1
+ /** @license MIT | @cube-dev/ui-kit v0.168.0 | Cube Dev Team */
2
2
  import { extractStyles } from "../../../utils/styles.js";
3
3
  import { useLayoutEffect as useLayoutEffect$1 } from "../../../utils/react/useLayoutEffect.js";
4
4
  import { useBoardRegistry } from "./board-context.js";
@@ -26,7 +26,7 @@ function shallowEqualStyles(a, b) {
26
26
  * which is what allows a widget to be transferred between boards.
27
27
  */
28
28
  function Widget(props) {
29
- const { id, children, isDraggable, isResizable, resizeHandles, resizeGripPlacement, isCard, hoverRing, minW, maxW, minH, maxH, constraints, qa, isAutoHeight, dragCancel, dragHandle, isSelectable, selectionCancel, "aria-label": ariaLabel } = props;
29
+ const { id, children, isDraggable, isResizable, resizeHandles, resizeGripPlacement, isCard, hoverRing, cornerChrome, cornerChromePlacement, mods, minW, maxW, minH, maxH, constraints, qa, isAutoHeight, dragCancel, dragHandle, isSelectable, selectionCancel, "aria-label": ariaLabel } = props;
30
30
  const registry = useBoardRegistry();
31
31
  const extractedStyles = extractStyles(props, CONTAINER_STYLES);
32
32
  const nextStyles = Object.keys(extractedStyles).length > 0 ? extractedStyles : void 0;
@@ -44,6 +44,9 @@ function Widget(props) {
44
44
  resizeGripPlacement,
45
45
  isCard,
46
46
  hoverRing,
47
+ cornerChrome,
48
+ cornerChromePlacement,
49
+ mods,
47
50
  minW,
48
51
  maxW,
49
52
  minH,