@smwb/ui-react 2.8.0 → 2.9.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 (239) hide show
  1. package/AI_LESS_OVERRIDES.md +84 -21
  2. package/AI_THEMING.md +72 -28
  3. package/README.md +654 -0
  4. package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
  5. package/dist/assets/styles/less/components/button/button.entry.css +1 -1
  6. package/dist/assets/styles/less/components/checkbox/checkbox.entry.css +1 -1
  7. package/dist/assets/styles/less/components/chip/chip.entry.css +1 -1
  8. package/dist/assets/styles/less/components/commandPalette/commandPalette.entry.css +1 -0
  9. package/dist/assets/styles/less/components/composer/composer.entry.css +1 -0
  10. package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -0
  11. package/dist/assets/styles/less/components/diffStat/diffStat.entry.css +1 -0
  12. package/dist/assets/styles/less/components/kbd/kbd.entry.css +1 -0
  13. package/dist/assets/styles/less/components/list/list.entry.css +1 -1
  14. package/dist/assets/styles/less/components/qrCode/qrCode.entry.css +1 -0
  15. package/dist/assets/styles/less/components/radioButton/radioButton.entry.css +1 -1
  16. package/dist/assets/styles/less/components/selectField/selectField.entry.css +1 -1
  17. package/dist/assets/styles/less/components/sidebar/sidebar.entry.css +1 -1
  18. package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -0
  19. package/dist/assets/styles/less/components/swimlanes/swimlanes.entry.css +1 -0
  20. package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -0
  21. package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
  22. package/dist/assets/styles/less/components/tabs/tabPanel/tabPanel.entry.css +1 -0
  23. package/dist/assets/styles/less/components/tabs/tabs.entry.css +1 -1
  24. package/dist/assets/styles/less/components/textField/textField.entry.css +1 -1
  25. package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
  26. package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
  27. package/dist/assets/styles/less/tokens.entry.css +1 -1
  28. package/dist/components/dataDisplay/chat/chat.d.ts +43 -1
  29. package/dist/components/dataDisplay/chat/chat.js +179 -150
  30. package/dist/components/dataDisplay/chat/chat.js.map +1 -1
  31. package/dist/components/dataDisplay/chat/chatComposer.d.ts +17 -0
  32. package/dist/components/dataDisplay/chat/chatComposer.js +31 -29
  33. package/dist/components/dataDisplay/chat/chatComposer.js.map +1 -1
  34. package/dist/components/dataDisplay/chat/index.d.ts +1 -1
  35. package/dist/components/dataDisplay/chat/utils.d.ts +14 -0
  36. package/dist/components/dataDisplay/chat/utils.js.map +1 -1
  37. package/dist/components/dataDisplay/dagView/dagLayout.d.ts +74 -0
  38. package/dist/components/dataDisplay/dagView/dagLayout.js +289 -0
  39. package/dist/components/dataDisplay/dagView/dagLayout.js.map +1 -0
  40. package/dist/components/dataDisplay/dagView/dagView.d.ts +157 -0
  41. package/dist/components/dataDisplay/dagView/dagView.js +543 -0
  42. package/dist/components/dataDisplay/dagView/dagView.js.map +1 -0
  43. package/dist/components/dataDisplay/dagView/index.d.ts +4 -0
  44. package/dist/components/dataDisplay/dagView/panZoom.d.ts +75 -0
  45. package/dist/components/dataDisplay/dagView/panZoom.js +171 -0
  46. package/dist/components/dataDisplay/dagView/panZoom.js.map +1 -0
  47. package/dist/components/dataDisplay/diffStat/diffStat.d.ts +54 -0
  48. package/dist/components/dataDisplay/diffStat/diffStat.js +63 -0
  49. package/dist/components/dataDisplay/diffStat/diffStat.js.map +1 -0
  50. package/dist/components/dataDisplay/diffStat/index.d.ts +2 -0
  51. package/dist/components/dataDisplay/kbd/index.d.ts +4 -0
  52. package/dist/components/dataDisplay/kbd/kbd.d.ts +40 -0
  53. package/dist/components/dataDisplay/kbd/kbd.js +27 -0
  54. package/dist/components/dataDisplay/kbd/kbd.js.map +1 -0
  55. package/dist/components/dataDisplay/kbd/kbdKeys.d.ts +18 -0
  56. package/dist/components/dataDisplay/kbd/kbdKeys.js +72 -0
  57. package/dist/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
  58. package/dist/components/dataDisplay/list/listItem.d.ts +34 -0
  59. package/dist/components/dataDisplay/list/listItem.js +47 -24
  60. package/dist/components/dataDisplay/list/listItem.js.map +1 -1
  61. package/dist/components/dataDisplay/qrCode/index.d.ts +2 -0
  62. package/dist/components/dataDisplay/qrCode/qrCode.d.ts +28 -0
  63. package/dist/components/dataDisplay/qrCode/qrCode.js +78 -0
  64. package/dist/components/dataDisplay/qrCode/qrCode.js.map +1 -0
  65. package/dist/components/dataDisplay/qrCode/qrCodePath.d.ts +7 -0
  66. package/dist/components/dataDisplay/qrCode/qrCodePath.js +20 -0
  67. package/dist/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
  68. package/dist/components/dataDisplay/statusDot/index.d.ts +2 -0
  69. package/dist/components/dataDisplay/statusDot/statusDot.d.ts +35 -0
  70. package/dist/components/dataDisplay/statusDot/statusDot.js +30 -0
  71. package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -0
  72. package/dist/components/dataDisplay/swimlanes/index.d.ts +2 -0
  73. package/dist/components/dataDisplay/swimlanes/swimlanes.d.ts +53 -0
  74. package/dist/components/dataDisplay/swimlanes/swimlanes.js +357 -0
  75. package/dist/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
  76. package/dist/components/dataDisplay/treeView/treeView.d.ts +17 -1
  77. package/dist/components/dataDisplay/treeView/treeView.js +113 -92
  78. package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
  79. package/dist/components/feedBack/modal/modal.js +84 -63
  80. package/dist/components/feedBack/modal/modal.js.map +1 -1
  81. package/dist/components/inputs/button/button.d.ts +13 -1
  82. package/dist/components/inputs/button/button.js +57 -51
  83. package/dist/components/inputs/button/button.js.map +1 -1
  84. package/dist/components/inputs/composer/composer.d.ts +149 -0
  85. package/dist/components/inputs/composer/composer.js +219 -0
  86. package/dist/components/inputs/composer/composer.js.map +1 -0
  87. package/dist/components/inputs/composer/composerFiles.d.ts +26 -0
  88. package/dist/components/inputs/composer/composerFiles.js +19 -0
  89. package/dist/components/inputs/composer/composerFiles.js.map +1 -0
  90. package/dist/components/inputs/composer/composerKeys.d.ts +29 -0
  91. package/dist/components/inputs/composer/composerKeys.js +7 -0
  92. package/dist/components/inputs/composer/composerKeys.js.map +1 -0
  93. package/dist/components/inputs/composer/index.d.ts +3 -0
  94. package/dist/components/layout/sheet/sheet.d.ts +12 -0
  95. package/dist/components/layout/sheet/sheet.js +152 -137
  96. package/dist/components/layout/sheet/sheet.js.map +1 -1
  97. package/dist/components/layout/tabGroups/index.d.ts +4 -0
  98. package/dist/components/layout/tabGroups/tabGroups.d.ts +94 -0
  99. package/dist/components/layout/tabGroups/tabGroups.js +783 -0
  100. package/dist/components/layout/tabGroups/tabGroups.js.map +1 -0
  101. package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +55 -0
  102. package/dist/components/layout/tabGroups/tabGroupsFocus.js +199 -0
  103. package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
  104. package/dist/components/layout/tabGroups/tabGroupsLayout.d.ts +250 -0
  105. package/dist/components/layout/tabGroups/tabGroupsLayout.js +497 -0
  106. package/dist/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
  107. package/dist/components/navigation/appBar/appBar.d.ts +22 -0
  108. package/dist/components/navigation/appBar/appBar.js +31 -26
  109. package/dist/components/navigation/appBar/appBar.js.map +1 -1
  110. package/dist/components/navigation/commandPalette/commandPalette.d.ts +111 -0
  111. package/dist/components/navigation/commandPalette/commandPalette.js +337 -0
  112. package/dist/components/navigation/commandPalette/commandPalette.js.map +1 -0
  113. package/dist/components/navigation/commandPalette/commandPaletteFilter.d.ts +11 -0
  114. package/dist/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
  115. package/dist/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
  116. package/dist/components/navigation/commandPalette/commandPaletteNavigation.d.ts +13 -0
  117. package/dist/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
  118. package/dist/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
  119. package/dist/components/navigation/commandPalette/commandPaletteTypes.d.ts +39 -0
  120. package/dist/components/navigation/commandPalette/index.d.ts +4 -0
  121. package/dist/components/navigation/sidebar/sidebar.d.ts +10 -0
  122. package/dist/components/navigation/sidebar/sidebar.js +61 -59
  123. package/dist/components/navigation/sidebar/sidebar.js.map +1 -1
  124. package/dist/components/navigation/tabs/index.d.ts +3 -1
  125. package/dist/components/navigation/tabs/tab/tab.d.ts +88 -1
  126. package/dist/components/navigation/tabs/tab/tab.js +121 -42
  127. package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
  128. package/dist/components/navigation/tabs/tabPanel/tabPanel.d.ts +19 -0
  129. package/dist/components/navigation/tabs/tabPanel/tabPanel.js +27 -0
  130. package/dist/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
  131. package/dist/components/navigation/tabs/tabs.d.ts +75 -5
  132. package/dist/components/navigation/tabs/tabs.js +369 -145
  133. package/dist/components/navigation/tabs/tabs.js.map +1 -1
  134. package/dist/components/navigation/tabs/tabs.utils.d.ts +20 -0
  135. package/dist/components/navigation/tabs/tabs.utils.js +11 -0
  136. package/dist/components/navigation/tabs/tabs.utils.js.map +1 -0
  137. package/dist/components/navigation/tabs/tabsContext.d.ts +11 -0
  138. package/dist/components/navigation/tabs/tabsContext.js +6 -0
  139. package/dist/components/navigation/tabs/tabsContext.js.map +1 -0
  140. package/dist/headless/components/dataDisplay/chat/chat.js +179 -150
  141. package/dist/headless/components/dataDisplay/chat/chat.js.map +1 -1
  142. package/dist/headless/components/dataDisplay/chat/chatComposer.js +31 -29
  143. package/dist/headless/components/dataDisplay/chat/chatComposer.js.map +1 -1
  144. package/dist/headless/components/dataDisplay/chat/utils.js.map +1 -1
  145. package/dist/headless/components/dataDisplay/dagView/dagLayout.js +289 -0
  146. package/dist/headless/components/dataDisplay/dagView/dagLayout.js.map +1 -0
  147. package/dist/headless/components/dataDisplay/dagView/dagView.js +541 -0
  148. package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -0
  149. package/dist/headless/components/dataDisplay/dagView/panZoom.js +171 -0
  150. package/dist/headless/components/dataDisplay/dagView/panZoom.js.map +1 -0
  151. package/dist/headless/components/dataDisplay/diffStat/diffStat.js +61 -0
  152. package/dist/headless/components/dataDisplay/diffStat/diffStat.js.map +1 -0
  153. package/dist/headless/components/dataDisplay/kbd/kbd.js +25 -0
  154. package/dist/headless/components/dataDisplay/kbd/kbd.js.map +1 -0
  155. package/dist/headless/components/dataDisplay/kbd/kbdKeys.js +72 -0
  156. package/dist/headless/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
  157. package/dist/headless/components/dataDisplay/list/listItem.js +47 -24
  158. package/dist/headless/components/dataDisplay/list/listItem.js.map +1 -1
  159. package/dist/headless/components/dataDisplay/qrCode/qrCode.js +76 -0
  160. package/dist/headless/components/dataDisplay/qrCode/qrCode.js.map +1 -0
  161. package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js +20 -0
  162. package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
  163. package/dist/headless/components/dataDisplay/statusDot/statusDot.js +28 -0
  164. package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -0
  165. package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js +355 -0
  166. package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
  167. package/dist/headless/components/dataDisplay/treeView/treeView.js +113 -92
  168. package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
  169. package/dist/headless/components/feedBack/modal/modal.js +85 -64
  170. package/dist/headless/components/feedBack/modal/modal.js.map +1 -1
  171. package/dist/headless/components/inputs/button/button.js +56 -50
  172. package/dist/headless/components/inputs/button/button.js.map +1 -1
  173. package/dist/headless/components/inputs/composer/composer.js +217 -0
  174. package/dist/headless/components/inputs/composer/composer.js.map +1 -0
  175. package/dist/headless/components/inputs/composer/composerFiles.js +19 -0
  176. package/dist/headless/components/inputs/composer/composerFiles.js.map +1 -0
  177. package/dist/headless/components/inputs/composer/composerKeys.js +7 -0
  178. package/dist/headless/components/inputs/composer/composerKeys.js.map +1 -0
  179. package/dist/headless/components/layout/sheet/sheet.js +160 -145
  180. package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
  181. package/dist/headless/components/layout/tabGroups/tabGroups.js +781 -0
  182. package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -0
  183. package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +199 -0
  184. package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
  185. package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js +497 -0
  186. package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
  187. package/dist/headless/components/navigation/appBar/appBar.js +35 -30
  188. package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
  189. package/dist/headless/components/navigation/commandPalette/commandPalette.js +335 -0
  190. package/dist/headless/components/navigation/commandPalette/commandPalette.js.map +1 -0
  191. package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
  192. package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
  193. package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
  194. package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
  195. package/dist/headless/components/navigation/sidebar/sidebar.js +56 -54
  196. package/dist/headless/components/navigation/sidebar/sidebar.js.map +1 -1
  197. package/dist/headless/components/navigation/tabs/tab/tab.js +121 -42
  198. package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
  199. package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js +25 -0
  200. package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
  201. package/dist/headless/components/navigation/tabs/tabs.js +369 -145
  202. package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
  203. package/dist/headless/components/navigation/tabs/tabs.utils.js +11 -0
  204. package/dist/headless/components/navigation/tabs/tabs.utils.js.map +1 -0
  205. package/dist/headless/components/navigation/tabs/tabsContext.js +6 -0
  206. package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -0
  207. package/dist/headless/hooks/useFocusTrap.js +24 -21
  208. package/dist/headless/hooks/useFocusTrap.js.map +1 -1
  209. package/dist/headless/hooks/useKeyboardShortcut.js +19 -0
  210. package/dist/headless/hooks/useKeyboardShortcut.js.map +1 -0
  211. package/dist/headless/index.js +360 -316
  212. package/dist/headless/index.js.map +1 -1
  213. package/dist/headless/utils/keyboardShortcut.js +49 -0
  214. package/dist/headless/utils/keyboardShortcut.js.map +1 -0
  215. package/dist/headless/utils/linkAttrs.js +13 -0
  216. package/dist/headless/utils/linkAttrs.js.map +1 -0
  217. package/dist/headless/utils/restoreFocus.js +10 -0
  218. package/dist/headless/utils/restoreFocus.js.map +1 -0
  219. package/dist/hooks/useFocusTrap.d.ts +6 -1
  220. package/dist/hooks/useFocusTrap.js +24 -21
  221. package/dist/hooks/useFocusTrap.js.map +1 -1
  222. package/dist/hooks/useKeyboardShortcut.d.ts +30 -0
  223. package/dist/hooks/useKeyboardShortcut.js +19 -0
  224. package/dist/hooks/useKeyboardShortcut.js.map +1 -0
  225. package/dist/index.cjs +3 -2
  226. package/dist/index.cjs.map +1 -1
  227. package/dist/index.d.ts +24 -3
  228. package/dist/index.js +360 -316
  229. package/dist/index.js.map +1 -1
  230. package/dist/utils/keyboardShortcut.d.ts +12 -0
  231. package/dist/utils/keyboardShortcut.js +49 -0
  232. package/dist/utils/keyboardShortcut.js.map +1 -0
  233. package/dist/utils/linkAttrs.d.ts +13 -0
  234. package/dist/utils/linkAttrs.js +13 -0
  235. package/dist/utils/linkAttrs.js.map +1 -0
  236. package/dist/utils/restoreFocus.d.ts +8 -0
  237. package/dist/utils/restoreFocus.js +10 -0
  238. package/dist/utils/restoreFocus.js.map +1 -0
  239. package/package.json +5 -3
@@ -0,0 +1,53 @@
1
+ import React from "react";
2
+ export interface SwimlanesLane {
3
+ /** Stable, unique id: keys the row, the selection and the Tab stop. */
4
+ id: string;
5
+ /** The lane's header (avatar, name, role); drawn in the fixed left column, role="rowheader". */
6
+ header: React.ReactNode;
7
+ /** The lane's content (current item, progress, last signal, budget); role="gridcell". */
8
+ content: React.ReactNode;
9
+ /** A disabled lane can be focused but not selected (aria-disabled). */
10
+ disabled?: boolean | undefined;
11
+ }
12
+ export interface SwimlanesProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSelect" | "role" | "children"> {
13
+ /** The lanes, one row each, in the order they are drawn. */
14
+ lanes: readonly SwimlanesLane[];
15
+ /** Accessible name of the grid (aria-label); `aria-labelledby` wins when given. */
16
+ label?: string | undefined;
17
+ /** The selected lane's id (controlled); null selects nothing. */
18
+ selectedId?: string | null | undefined;
19
+ /** The lane selected at first (uncontrolled). */
20
+ defaultSelectedId?: string | null | undefined;
21
+ /** A lane was selected (its id) or the selection was cleared (null). */
22
+ onSelectedChange?: ((id: string | null) => void) | undefined;
23
+ /**
24
+ * Whether lanes can be selected; true by default. False: no aria-selected, no selected look,
25
+ * and Enter, Space, Escape and a click select nothing; a `selectedId` given anyway is ignored.
26
+ */
27
+ selectable?: boolean | undefined;
28
+ /** Row height in px (every lane is this tall; virtualisation needs a fixed height). 64 by default. */
29
+ rowHeight?: number | undefined;
30
+ /** Width of the fixed header column: px or any CSS length; 240px by default from the stylesheet. */
31
+ headerWidth?: number | string | undefined;
32
+ /** Narrowest width of the content column; when the grid is narrower, it scrolls sideways. 0 by default. */
33
+ contentMinWidth?: number | string | undefined;
34
+ /**
35
+ * The grid's height (the scroller): a number of pixels or any CSS length; 480
36
+ * by default, from the stylesheet, so a height in `style` works too.
37
+ */
38
+ height?: number | string | undefined;
39
+ /** Lanes rendered above and below the visible ones. 4 by default. */
40
+ overscan?: number | undefined;
41
+ /** Shown instead of the grid when `lanes` is empty. */
42
+ emptyLabel?: React.ReactNode;
43
+ /** Test id of the root `<div>`; `swimlanes` unless given. */
44
+ "data-testid"?: string | undefined;
45
+ }
46
+ /** Row height in px when `rowHeight` is not given. */
47
+ export declare const SWIMLANES_DEFAULT_ROW_HEIGHT = 64;
48
+ /** Height in px the stylesheet gives the grid when neither `height` nor a style in the caller sets one. */
49
+ export declare const SWIMLANES_DEFAULT_HEIGHT = 480;
50
+ /** Lanes rendered above and below the visible ones when `overscan` is not given. */
51
+ export declare const SWIMLANES_DEFAULT_OVERSCAN = 4;
52
+ export declare const Swimlanes: React.ForwardRefExoticComponent<SwimlanesProps & React.RefAttributes<HTMLDivElement>>;
53
+ export default Swimlanes;
@@ -0,0 +1,357 @@
1
+ import { jsx as F, jsxs as Me } from "react/jsx-runtime";
2
+ import '../../../assets/styles/less/components/swimlanes/swimlanes.entry.css';import '../../../assets/styles/less/tokens.entry.css';/* empty css */
3
+ /* empty css */
4
+ import s from "react";
5
+ import ie from "clsx";
6
+ import { useControllableState as He } from "../../../hooks/useControllableState.js";
7
+ import { useEventCallback as Q } from "../../../hooks/useEventCallback.js";
8
+ import { useForkRef as Te } from "../../../hooks/useForkRef.js";
9
+ import { useSafeLayoutEffect as D } from "../../../hooks/useSafeLayoutEffect.js";
10
+ import { useVirtualList as Ce } from "../../../hooks/useVirtualList.js";
11
+ import { isOwnClick as Le } from "../../../utils/ownClick.js";
12
+ const ke = 64, Ke = 480, De = 4, Fe = 'a[href], button, input, select, textarea, iframe, summary, audio[controls], video[controls], [tabindex], [contenteditable]:not([contenteditable="false"])', X = (w) => typeof w == "number" ? `${w}px` : w, Ne = (w, c) => w.length === c.length && w.every((a, h) => a === c[h]);
13
+ function ze(w, c, a, h) {
14
+ const x = h.count - 1;
15
+ if (x < 0) return null;
16
+ const u = (d) => Math.min(x, Math.max(0, d)), p = (d) => d === a.index ? null : { index: d, col: a.col }, b = (d) => d === a.col ? null : { index: a.index, col: d };
17
+ if (c.ctrlKey || c.metaKey || c.altKey)
18
+ return !c.ctrlKey || c.metaKey || c.altKey ? null : w === "Home" ? p(0) : w === "End" ? p(x) : null;
19
+ switch (w) {
20
+ case "ArrowDown":
21
+ return p(u(a.index + 1));
22
+ case "ArrowUp":
23
+ return p(u(a.index - 1));
24
+ case "ArrowRight":
25
+ return b(1);
26
+ case "ArrowLeft":
27
+ return b(0);
28
+ case "Home":
29
+ return b(0);
30
+ case "End":
31
+ return b(1);
32
+ case "PageDown":
33
+ return p(u(a.index + h.pageSize));
34
+ case "PageUp":
35
+ return p(u(a.index - h.pageSize));
36
+ default:
37
+ return null;
38
+ }
39
+ }
40
+ const Oe = s.memo(function({
41
+ lane: c,
42
+ index: a,
43
+ selected: h,
44
+ selectable: x,
45
+ tabCol: u,
46
+ rowHeight: p,
47
+ handlers: b
48
+ }) {
49
+ const d = (C, M, g, L) => /* @__PURE__ */ F(
50
+ "div",
51
+ {
52
+ className: M,
53
+ role: C,
54
+ tabIndex: u === g ? 0 : -1,
55
+ onClick: (R) => b.onCellClick(R, c.id, g),
56
+ onFocus: (R) => b.onCellFocus(R, c.id, g),
57
+ children: L
58
+ }
59
+ );
60
+ return /* @__PURE__ */ Me(
61
+ "div",
62
+ {
63
+ className: ie("smwb-swimlanes__row", {
64
+ "smwb-swimlanes__row_selected": h,
65
+ "smwb-swimlanes__row_disabled": !!c.disabled
66
+ }),
67
+ role: "row",
68
+ "aria-rowindex": a + 1,
69
+ "aria-selected": x ? h : void 0,
70
+ "aria-disabled": c.disabled ? !0 : void 0,
71
+ "data-lane-id": c.id,
72
+ style: { top: a * p },
73
+ ref: (C) => {
74
+ b.registerRow(c.id, C);
75
+ },
76
+ children: [
77
+ d("rowheader", "smwb-swimlanes__header", 0, c.header),
78
+ d("gridcell", "smwb-swimlanes__content", 1, c.content)
79
+ ]
80
+ }
81
+ );
82
+ }), Xe = s.forwardRef(function(c, a) {
83
+ const {
84
+ className: h,
85
+ style: x,
86
+ lanes: u,
87
+ label: p,
88
+ selectedId: b,
89
+ defaultSelectedId: d,
90
+ onSelectedChange: C,
91
+ selectable: M = !0,
92
+ rowHeight: g = ke,
93
+ headerWidth: L,
94
+ contentMinWidth: R,
95
+ height: k,
96
+ overscan: ue = De,
97
+ emptyLabel: ae,
98
+ onScroll: B,
99
+ onKeyDown: V,
100
+ "data-testid": de = "swimlanes",
101
+ ...fe
102
+ } = c, H = s.useRef(null), j = s.useRef(null), N = s.useRef(/* @__PURE__ */ new Map()), me = Te(a, H), G = u.length === 0, y = s.useMemo(() => {
103
+ const e = /* @__PURE__ */ new Map();
104
+ return u.forEach((t, n) => {
105
+ e.has(t.id) || e.set(t.id, n);
106
+ }), e;
107
+ }, [u]), $ = s.useMemo(() => [...y.keys()], [y]), q = s.useRef($);
108
+ Ne(q.current, $) || (q.current = $);
109
+ const E = q.current, [we, Y] = He({
110
+ value: b,
111
+ defaultValue: d != null ? d : null,
112
+ onChange: C
113
+ }), _ = M ? we : null, [T, z] = s.useState(null), S = s.useMemo(() => {
114
+ if (T !== null && y.has(T.laneId)) return T;
115
+ if (_ !== null && y.has(_)) return { laneId: _, col: 0 };
116
+ const e = E[0];
117
+ return e === void 0 ? null : { laneId: e, col: 0 };
118
+ }, [T, _, y, E]), Z = s.useRef(S);
119
+ Z.current = S;
120
+ const pe = typeof k == "number" ? k : Ke, [ee, he] = s.useState(0), J = ee > 0 ? ee : pe, I = Ce({
121
+ itemCount: u.length,
122
+ itemHeight: g,
123
+ viewportHeight: J,
124
+ overscan: ue
125
+ }), P = s.useMemo(() => {
126
+ const e = /* @__PURE__ */ new Set();
127
+ for (let t = I.startIndex; t < I.endIndex; t++) e.add(t);
128
+ if (S !== null) {
129
+ const t = y.get(S.laneId);
130
+ t !== void 0 && e.add(t);
131
+ }
132
+ return [...e].sort((t, n) => t - n);
133
+ }, [I.startIndex, I.endIndex, S, y]), be = s.useMemo(() => P.map((e) => {
134
+ var t, n;
135
+ return (n = (t = u[e]) == null ? void 0 : t.id) != null ? n : "";
136
+ }).join("|"), [P, u]), f = s.useRef({
137
+ selectable: M,
138
+ selected: _,
139
+ setSelected: Y,
140
+ active: T,
141
+ viewportHeight: J,
142
+ rowHeight: g,
143
+ lanes: u,
144
+ indexById: y,
145
+ onScroll: I.onScroll
146
+ });
147
+ f.current = {
148
+ selectable: M,
149
+ selected: _,
150
+ setSelected: Y,
151
+ active: T,
152
+ viewportHeight: J,
153
+ rowHeight: g,
154
+ lanes: u,
155
+ indexById: y,
156
+ onScroll: I.onScroll
157
+ };
158
+ const ge = (e, t) => {
159
+ var o;
160
+ const n = (o = N.current.get(e)) == null ? void 0 : o.children[t];
161
+ return n instanceof HTMLElement ? n : null;
162
+ }, ye = (e) => {
163
+ const t = H.current, n = j.current;
164
+ if (t === null || n === null || !(e instanceof Element)) return null;
165
+ const o = e.getAttribute("role");
166
+ if (o !== "rowheader" && o !== "gridcell") return null;
167
+ const i = o === "rowheader" ? 0 : 1, r = e.parentElement;
168
+ if (r === null || r.parentElement !== n || n.parentElement !== t) return null;
169
+ const l = r.dataset.laneId;
170
+ return l === void 0 ? null : { laneId: l, col: i };
171
+ }, O = s.useRef(null), Se = (e) => {
172
+ const t = H.current;
173
+ if (t === null) return;
174
+ const { rowHeight: n, viewportHeight: o } = f.current, i = t.clientHeight || o, r = e * n, l = r < t.scrollTop ? r : r + n > t.scrollTop + i ? r + n - i : t.scrollTop;
175
+ l !== t.scrollTop && (t.scrollTop = l, f.current.onScroll({ currentTarget: { scrollTop: l } }));
176
+ }, ve = (e, t) => {
177
+ const n = f.current.lanes[e];
178
+ n !== void 0 && (Se(e), z({ laneId: n.id, col: t }), O.current = { laneId: n.id, col: t });
179
+ }, xe = () => {
180
+ var o;
181
+ const { rowHeight: e, viewportHeight: t } = f.current, n = ((o = H.current) == null ? void 0 : o.clientHeight) || t;
182
+ return Math.max(1, Math.floor(n / e) - 1);
183
+ }, te = (e) => {
184
+ const { selectable: t, selected: n, setSelected: o } = f.current;
185
+ if (!t) return;
186
+ const i = f.current.indexById.get(e), r = i === void 0 ? void 0 : f.current.lanes[i];
187
+ r === void 0 || r.disabled || n !== e && o(e);
188
+ }, ne = Q(
189
+ (e, t, n) => {
190
+ Le(e, e.currentTarget) && (z({ laneId: t, col: n }), te(t));
191
+ }
192
+ ), re = Q(
193
+ (e, t, n) => {
194
+ e.currentTarget.contains(e.target) && z({ laneId: t, col: n });
195
+ }
196
+ ), oe = Q((e, t) => {
197
+ t !== null ? N.current.set(e, t) : N.current.delete(e);
198
+ }), Ie = s.useMemo(
199
+ () => ({ onCellClick: ne, onCellFocus: re, registerRow: oe }),
200
+ [ne, re, oe]
201
+ ), Re = (e) => {
202
+ V == null || V(e);
203
+ const t = ye(e.target);
204
+ if (t === null) return;
205
+ const { ctrlKey: n, metaKey: o, altKey: i } = e;
206
+ if (!n && !o && !i) {
207
+ if (e.key === "Enter" || e.key === " ") {
208
+ e.preventDefault(), te(t.laneId);
209
+ return;
210
+ }
211
+ if (e.key === "Escape") {
212
+ if (f.current.selected === null) return;
213
+ e.preventDefault(), f.current.setSelected(null);
214
+ return;
215
+ }
216
+ }
217
+ const r = f.current.indexById.get(t.laneId);
218
+ if (r === void 0) return;
219
+ const l = ze(
220
+ e.key,
221
+ { ctrlKey: n, metaKey: o, altKey: i },
222
+ { index: r, col: t.col },
223
+ { count: f.current.lanes.length, pageSize: xe() }
224
+ );
225
+ l !== null && (e.preventDefault(), ve(l.index, l.col));
226
+ }, Ee = (e) => {
227
+ B == null || B(e), I.onScroll(e);
228
+ };
229
+ D(() => {
230
+ const e = H.current;
231
+ if (e === null || typeof ResizeObserver != "function") return;
232
+ const t = new ResizeObserver(() => {
233
+ he(e.clientHeight);
234
+ });
235
+ return t.observe(e), () => t.disconnect();
236
+ }, []), D(() => {
237
+ var t;
238
+ const e = O.current;
239
+ e !== null && (O.current = null, (t = ge(e.laneId, e.col)) == null || t.focus({ preventScroll: !0 }));
240
+ });
241
+ const se = s.useRef(null);
242
+ D(() => {
243
+ var v;
244
+ const e = se.current;
245
+ if (se.current = E, e === null || e === E) return;
246
+ const t = new Set(E), { selected: n, setSelected: o, active: i } = f.current, r = n !== null && !t.has(n) && e.includes(n);
247
+ if (r && o(null), i === null || t.has(i.laneId)) return;
248
+ z(null);
249
+ const l = (v = H.current) == null ? void 0 : v.ownerDocument;
250
+ if (l === void 0 || l.activeElement !== null && l.activeElement !== l.body) return;
251
+ const A = !r && n !== null && t.has(n) ? n : E[0];
252
+ A !== void 0 && (O.current = { laneId: A, col: 0 });
253
+ }, [E]);
254
+ const le = s.useRef(/* @__PURE__ */ new WeakMap()), ce = s.useRef(/* @__PURE__ */ new WeakMap()), W = s.useCallback(() => {
255
+ var o, i, r, l;
256
+ const e = (i = (o = Z.current) == null ? void 0 : o.laneId) != null ? i : null, t = le.current, n = ce.current;
257
+ for (const [A, v] of N.current)
258
+ for (const U of Array.from(v.children))
259
+ for (const m of U.querySelectorAll(Fe)) {
260
+ t.has(m) || t.set(m, m.getAttribute("tabindex")), m.getAttribute("tabindex") !== ((r = n.get(m)) != null ? r : null) && t.set(m, m.getAttribute("tabindex"));
261
+ const K = A === e ? (l = t.get(m)) != null ? l : null : "-1";
262
+ if (m.getAttribute("tabindex") === K) {
263
+ n.set(m, K);
264
+ continue;
265
+ }
266
+ K === null ? m.removeAttribute("tabindex") : m.setAttribute("tabindex", K), n.set(m, K);
267
+ }
268
+ }, []);
269
+ D(() => {
270
+ W();
271
+ }, [S, be, W]), D(() => {
272
+ const e = j.current;
273
+ if (e === null || typeof MutationObserver != "function") return;
274
+ const t = new MutationObserver((n) => {
275
+ var l;
276
+ const o = le.current, i = ce.current;
277
+ let r = !1;
278
+ for (const A of n) {
279
+ if (A.type !== "attributes") {
280
+ r = !0;
281
+ continue;
282
+ }
283
+ const v = A.target;
284
+ if (!i.has(v)) continue;
285
+ const U = v.getAttribute("tabindex");
286
+ U !== ((l = i.get(v)) != null ? l : null) && (o.set(v, U), r = !0);
287
+ }
288
+ r && W();
289
+ });
290
+ return t.observe(e, {
291
+ childList: !0,
292
+ subtree: !0,
293
+ attributes: !0,
294
+ attributeFilter: ["tabindex"]
295
+ }), () => t.disconnect();
296
+ }, [W]);
297
+ const _e = G ? {} : {
298
+ role: "grid",
299
+ "aria-rowcount": u.length,
300
+ "aria-colcount": 2,
301
+ ...p === void 0 ? {} : { "aria-label": p }
302
+ }, Ae = s.useMemo(() => {
303
+ const e = {};
304
+ k !== void 0 && (e.height = X(k));
305
+ const t = e;
306
+ return t["--smwb-swimlanes-row-height"] = `${g}px`, L !== void 0 && (t["--smwb-swimlanes-header-width"] = X(L)), R !== void 0 && (t["--smwb-swimlanes-content-min-width"] = X(R)), { ...e, ...x };
307
+ }, [k, g, L, R, x]);
308
+ return /* @__PURE__ */ F(
309
+ "div",
310
+ {
311
+ ...fe,
312
+ ref: me,
313
+ "data-testid": de,
314
+ className: ie("smwb-swimlanes", { "smwb-swimlanes_empty": G }, h),
315
+ style: Ae,
316
+ ..._e,
317
+ onScroll: Ee,
318
+ onKeyDown: Re,
319
+ children: G ? (
320
+ // No grid role and no row count: an empty grid has no rows, which fails
321
+ // the role's required children.
322
+ /* @__PURE__ */ F("div", { className: "smwb-swimlanes__empty", children: ae })
323
+ ) : /* @__PURE__ */ F(
324
+ "div",
325
+ {
326
+ className: "smwb-swimlanes__sizer",
327
+ role: "presentation",
328
+ ref: j,
329
+ style: { height: I.totalHeight },
330
+ children: P.map((e) => {
331
+ const t = u[e];
332
+ return t === void 0 ? null : /* @__PURE__ */ F(
333
+ Oe,
334
+ {
335
+ lane: t,
336
+ index: e,
337
+ selected: _ === t.id,
338
+ selectable: M,
339
+ tabCol: S !== null && S.laneId === t.id ? S.col : -1,
340
+ rowHeight: g,
341
+ handlers: Ie
342
+ },
343
+ t.id
344
+ );
345
+ })
346
+ }
347
+ )
348
+ }
349
+ );
350
+ });
351
+ export {
352
+ Ke as SWIMLANES_DEFAULT_HEIGHT,
353
+ De as SWIMLANES_DEFAULT_OVERSCAN,
354
+ ke as SWIMLANES_DEFAULT_ROW_HEIGHT,
355
+ Xe as Swimlanes
356
+ };
357
+ //# sourceMappingURL=swimlanes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swimlanes.js","sources":["../../../../src/components/dataDisplay/swimlanes/swimlanes.tsx"],"sourcesContent":["import React from \"react\";\nimport cn from \"clsx\";\nimport { useControllableState } from \"../../../hooks/useControllableState\";\nimport { useEventCallback } from \"../../../hooks/useEventCallback\";\nimport { useForkRef } from \"../../../hooks/useForkRef\";\nimport { useSafeLayoutEffect } from \"../../../hooks/useSafeLayoutEffect\";\nimport { useVirtualList } from \"../../../hooks/useVirtualList\";\nimport { isOwnClick } from \"../../../utils/ownClick\";\n\nexport interface SwimlanesLane {\n /** Stable, unique id: keys the row, the selection and the Tab stop. */\n id: string;\n /** The lane's header (avatar, name, role); drawn in the fixed left column, role=\"rowheader\". */\n header: React.ReactNode;\n /** The lane's content (current item, progress, last signal, budget); role=\"gridcell\". */\n content: React.ReactNode;\n /** A disabled lane can be focused but not selected (aria-disabled). */\n disabled?: boolean | undefined;\n}\n\nexport interface SwimlanesProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onSelect\" | \"role\" | \"children\"> {\n /** The lanes, one row each, in the order they are drawn. */\n lanes: readonly SwimlanesLane[];\n /** Accessible name of the grid (aria-label); `aria-labelledby` wins when given. */\n label?: string | undefined;\n /** The selected lane's id (controlled); null selects nothing. */\n selectedId?: string | null | undefined;\n /** The lane selected at first (uncontrolled). */\n defaultSelectedId?: string | null | undefined;\n /** A lane was selected (its id) or the selection was cleared (null). */\n onSelectedChange?: ((id: string | null) => void) | undefined;\n /**\n * Whether lanes can be selected; true by default. False: no aria-selected, no selected look,\n * and Enter, Space, Escape and a click select nothing; a `selectedId` given anyway is ignored.\n */\n selectable?: boolean | undefined;\n /** Row height in px (every lane is this tall; virtualisation needs a fixed height). 64 by default. */\n rowHeight?: number | undefined;\n /** Width of the fixed header column: px or any CSS length; 240px by default from the stylesheet. */\n headerWidth?: number | string | undefined;\n /** Narrowest width of the content column; when the grid is narrower, it scrolls sideways. 0 by default. */\n contentMinWidth?: number | string | undefined;\n /**\n * The grid's height (the scroller): a number of pixels or any CSS length; 480\n * by default, from the stylesheet, so a height in `style` works too.\n */\n height?: number | string | undefined;\n /** Lanes rendered above and below the visible ones. 4 by default. */\n overscan?: number | undefined;\n /** Shown instead of the grid when `lanes` is empty. */\n emptyLabel?: React.ReactNode;\n /** Test id of the root `<div>`; `swimlanes` unless given. */\n \"data-testid\"?: string | undefined;\n}\n\n/** Row height in px when `rowHeight` is not given. */\nexport const SWIMLANES_DEFAULT_ROW_HEIGHT = 64;\n/** Height in px the stylesheet gives the grid when neither `height` nor a style in the caller sets one. */\nexport const SWIMLANES_DEFAULT_HEIGHT = 480;\n/** Lanes rendered above and below the visible ones when `overscan` is not given. */\nexport const SWIMLANES_DEFAULT_OVERSCAN = 4;\n\n/** A cell of the grid: its lane and which of the lane's two columns it is. */\ninterface SwimlanesCell {\n laneId: string;\n /** 0 is the rowheader, 1 the gridcell. */\n col: 0 | 1;\n}\n\n/** Where the focus is, or is about to go: a lane's index and column. */\ninterface SwimlanesPosition {\n index: number;\n /** 0 is the rowheader, 1 the gridcell. */\n col: 0 | 1;\n}\n\n/** What can take focus inside a cell's own content. */\nconst INNER_FOCUSABLE =\n 'a[href], button, input, select, textarea, iframe, summary, audio[controls], video[controls], [tabindex], [contenteditable]:not([contenteditable=\"false\"])';\n\nconst cssLength = (value: number | string): string => (typeof value === \"number\" ? `${value}px` : value);\n\nconst sameList = (a: readonly string[], b: readonly string[]): boolean =>\n a.length === b.length && a.every((value, i) => value === b[i]);\n\n/**\n * Where a key moves the focus, or null when the grid leaves the key alone.\n *\n * The arrows walk the lanes and the columns without wrapping, so at an edge\n * there is nothing to do and the key is not prevented; Home and End stay in the\n * row and Ctrl+Home and Ctrl+End go to the first and last lane (the APG grid\n * model); the page keys move by the rows that fit, less one so a row of context\n * stays on screen. Any other key, and any combination with Ctrl, Cmd or Alt\n * apart from those two, belongs to the browser or to the lane's own content.\n */\nfunction swimlanesKeyTarget(\n key: string,\n mods: { ctrlKey: boolean; metaKey: boolean; altKey: boolean },\n from: SwimlanesPosition,\n context: { count: number; pageSize: number }\n): SwimlanesPosition | null {\n const last = context.count - 1;\n if (last < 0) return null;\n const clamp = (index: number): number => Math.min(last, Math.max(0, index));\n // Nothing to do when the move lands where the focus already is.\n const lane = (index: number): SwimlanesPosition | null => (index === from.index ? null : { index, col: from.col });\n const column = (col: 0 | 1): SwimlanesPosition | null => (col === from.col ? null : { index: from.index, col });\n\n if (mods.ctrlKey || mods.metaKey || mods.altKey) {\n // Ctrl+Home and Ctrl+End are the grid's; the rest are the browser's.\n if (!mods.ctrlKey || mods.metaKey || mods.altKey) return null;\n if (key === \"Home\") return lane(0);\n if (key === \"End\") return lane(last);\n return null;\n }\n\n switch (key) {\n case \"ArrowDown\":\n return lane(clamp(from.index + 1));\n case \"ArrowUp\":\n return lane(clamp(from.index - 1));\n case \"ArrowRight\":\n return column(1);\n case \"ArrowLeft\":\n return column(0);\n case \"Home\":\n return column(0);\n case \"End\":\n return column(1);\n case \"PageDown\":\n return lane(clamp(from.index + context.pageSize));\n case \"PageUp\":\n return lane(clamp(from.index - context.pageSize));\n default:\n return null;\n }\n}\n\ninterface SwimlanesRowHandlers {\n onCellClick: (event: React.MouseEvent<HTMLDivElement>, laneId: string, col: 0 | 1) => void;\n onCellFocus: (event: React.FocusEvent<HTMLDivElement>, laneId: string, col: 0 | 1) => void;\n registerRow: (laneId: string, element: HTMLElement | null) => void;\n}\n\ninterface SwimlanesRowProps {\n lane: SwimlanesLane;\n /** The lane's index in `lanes`: its `aria-rowindex` is one more, and it places the row. */\n index: number;\n selected: boolean;\n /** Whether the rows carry `aria-selected` at all. */\n selectable: boolean;\n /** The column of this row that is the grid's one Tab stop, or -1 for neither. */\n tabCol: number;\n rowHeight: number;\n handlers: SwimlanesRowHandlers;\n}\n\n/**\n * One lane: the header cell that stays put and the content cell beside it.\n * Memoised, so a scroll that leaves the window alone costs the grid one shallow\n * render of its own and no row work at all.\n */\nconst SwimlanesRow = React.memo(function SwimlanesRow({\n lane,\n index,\n selected,\n selectable,\n tabCol,\n rowHeight,\n handlers,\n}: SwimlanesRowProps): React.ReactElement {\n const cell = (\n role: \"rowheader\" | \"gridcell\",\n className: string,\n col: 0 | 1,\n content: React.ReactNode\n ): React.ReactElement => (\n <div\n className={className}\n role={role}\n tabIndex={tabCol === col ? 0 : -1}\n onClick={(event) => handlers.onCellClick(event, lane.id, col)}\n onFocus={(event) => handlers.onCellFocus(event, lane.id, col)}\n >\n {content}\n </div>\n );\n\n return (\n <div\n className={cn(\"smwb-swimlanes__row\", {\n \"smwb-swimlanes__row_selected\": selected,\n \"smwb-swimlanes__row_disabled\": Boolean(lane.disabled),\n })}\n role=\"row\"\n aria-rowindex={index + 1}\n aria-selected={selectable ? selected : undefined}\n aria-disabled={lane.disabled ? true : undefined}\n data-lane-id={lane.id}\n style={{ top: index * rowHeight }}\n ref={(element) => {\n handlers.registerRow(lane.id, element);\n }}\n >\n {cell(\"rowheader\", \"smwb-swimlanes__header\", 0, lane.header)}\n {cell(\"gridcell\", \"smwb-swimlanes__content\", 1, lane.content)}\n </div>\n );\n});\n\nexport const Swimlanes = React.forwardRef<HTMLDivElement, SwimlanesProps>(function Swimlanes(props, ref) {\n const {\n className,\n style,\n lanes,\n label,\n selectedId,\n defaultSelectedId,\n onSelectedChange,\n selectable = true,\n rowHeight = SWIMLANES_DEFAULT_ROW_HEIGHT,\n headerWidth,\n contentMinWidth,\n height,\n overscan = SWIMLANES_DEFAULT_OVERSCAN,\n emptyLabel,\n onScroll: onScrollProp,\n onKeyDown: onKeyDownProp,\n \"data-testid\": dataTestId = \"swimlanes\",\n ...rest\n } = props;\n\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n const sizerRef = React.useRef<HTMLDivElement | null>(null);\n const rowsRef = React.useRef(new Map<string, HTMLElement>());\n const forkedRef = useForkRef(ref, rootRef);\n const empty = lanes.length === 0;\n\n // ---- Lanes ----\n\n const indexById = React.useMemo(() => {\n const map = new Map<string, number>();\n lanes.forEach((lane, index) => {\n if (!map.has(lane.id)) map.set(lane.id, index);\n });\n return map;\n }, [lanes]);\n\n // A stable identity for the id list, so the removal effect below runs when the\n // lanes themselves change and not on every render of the caller.\n const nextIds = React.useMemo(() => [...indexById.keys()], [indexById]);\n const idsRef = React.useRef(nextIds);\n if (!sameList(idsRef.current, nextIds)) idsRef.current = nextIds;\n const ids = idsRef.current;\n\n // ---- Selection ----\n\n const [chosen, setSelected] = useControllableState<string | null>({\n value: selectedId,\n defaultValue: defaultSelectedId ?? null,\n onChange: onSelectedChange,\n });\n // `selectable={false}` turns the selection off: a `selectedId` given anyway\n // paints nothing, is not the Tab stop, and Escape has nothing to clear.\n const selected = selectable ? chosen : null;\n\n // ---- Focus: one Tab stop, on the last focused cell, else the selected lane, else the first ----\n\n const [active, setActive] = React.useState<SwimlanesCell | null>(null);\n const tabStop = React.useMemo<SwimlanesCell | null>(() => {\n if (active !== null && indexById.has(active.laneId)) return active;\n if (selected !== null && indexById.has(selected)) return { laneId: selected, col: 0 };\n const first = ids[0];\n return first === undefined ? null : { laneId: first, col: 0 };\n }, [active, selected, indexById, ids]);\n const tabStopRef = React.useRef(tabStop);\n tabStopRef.current = tabStop;\n\n // ---- The window ----\n\n // The server and the first client render agree: the viewport is estimated\n // from `height` until a ResizeObserver measures it after mount, and a\n // measurement of 0 (jsdom, a hidden parent) keeps the estimate.\n const estimate = typeof height === \"number\" ? height : SWIMLANES_DEFAULT_HEIGHT;\n const [measured, setMeasured] = React.useState(0);\n const viewportHeight = measured > 0 ? measured : estimate;\n\n const virtual = useVirtualList({\n itemCount: lanes.length,\n itemHeight: rowHeight,\n viewportHeight,\n overscan,\n });\n\n // The window, plus the Tab-stop lane when it lies outside: the cell that holds\n // or will receive focus always exists, so a lane focused and then scrolled\n // away with the wheel stays mounted, and keeps focus, at its own place.\n const rendered = React.useMemo(() => {\n const indexes = new Set<number>();\n for (let index = virtual.startIndex; index < virtual.endIndex; index++) indexes.add(index);\n if (tabStop !== null) {\n const stop = indexById.get(tabStop.laneId);\n if (stop !== undefined) indexes.add(stop);\n }\n return [...indexes].sort((a, b) => a - b);\n }, [virtual.startIndex, virtual.endIndex, tabStop, indexById]);\n\n const renderedKey = React.useMemo(() => rendered.map((index) => lanes[index]?.id ?? \"\").join(\"|\"), [rendered, lanes]);\n\n // ---- Current values for the stable callbacks and effects ----\n\n const latest = React.useRef({\n selectable,\n selected,\n setSelected,\n active,\n viewportHeight,\n rowHeight,\n lanes,\n indexById,\n onScroll: virtual.onScroll,\n });\n latest.current = {\n selectable,\n selected,\n setSelected,\n active,\n viewportHeight,\n rowHeight,\n lanes,\n indexById,\n onScroll: virtual.onScroll,\n };\n\n /** The cell that holds or will receive focus. */\n const cellElement = (laneId: string, col: 0 | 1): HTMLElement | null => {\n const cell = rowsRef.current.get(laneId)?.children[col];\n return cell instanceof HTMLElement ? cell : null;\n };\n\n /** The cell of this grid a key or a focus event landed in, or null. */\n const cellOfEvent = (target: EventTarget | null): SwimlanesCell | null => {\n const root = rootRef.current;\n const sizer = sizerRef.current;\n if (root === null || sizer === null || !(target instanceof Element)) return null;\n const role = target.getAttribute(\"role\");\n if (role !== \"rowheader\" && role !== \"gridcell\") return null;\n const col = role === \"rowheader\" ? 0 : 1;\n // The cell is the row's child, the row the sizer's and the sizer the root's,\n // so a grid nested in a lane's own content is not this grid's cell. Keys\n // inside a lane's content belong to that content.\n const row = target.parentElement;\n if (row === null || row.parentElement !== sizer || sizer.parentElement !== root) return null;\n const laneId = row.dataset[\"laneId\"];\n return laneId === undefined ? null : { laneId, col };\n };\n\n // ---- Moving ----\n\n const pendingFocusRef = React.useRef<SwimlanesCell | null>(null);\n\n /**\n * Brings a lane into view and moves the window with it, as SelectField's\n * virtual options do: the scroller is set and the virtual list is told in the\n * same pass, so the lane exists by the time it is focused.\n */\n const scrollLaneIntoView = (index: number): void => {\n const root = rootRef.current;\n if (root === null) return;\n const { rowHeight: itemHeight, viewportHeight: fallback } = latest.current;\n // The measured height where the DOM has one; jsdom lays nothing out.\n const viewport = root.clientHeight || fallback;\n const top = index * itemHeight;\n const scrollTop =\n top < root.scrollTop\n ? top\n : top + itemHeight > root.scrollTop + viewport\n ? top + itemHeight - viewport\n : root.scrollTop;\n if (scrollTop === root.scrollTop) return;\n root.scrollTop = scrollTop;\n latest.current.onScroll({ currentTarget: { scrollTop } });\n };\n\n const moveTo = (index: number, col: 0 | 1): void => {\n const lane = latest.current.lanes[index];\n if (lane === undefined) return;\n scrollLaneIntoView(index);\n setActive({ laneId: lane.id, col });\n // After the commit that renders the lane, so the cell is there to focus.\n pendingFocusRef.current = { laneId: lane.id, col };\n };\n\n /** How many lanes a page key moves: the rows that fit, less one for context. */\n const pageSize = (): number => {\n const { rowHeight: itemHeight, viewportHeight: fallback } = latest.current;\n const viewport = rootRef.current?.clientHeight || fallback;\n return Math.max(1, Math.floor(viewport / itemHeight) - 1);\n };\n\n const selectLane = (laneId: string): void => {\n const { selectable: canSelect, selected: chosen, setSelected: set } = latest.current;\n if (!canSelect) return;\n const index = latest.current.indexById.get(laneId);\n const lane = index === undefined ? undefined : latest.current.lanes[index];\n if (lane === undefined || lane.disabled) return;\n // An already selected lane stays selected: no toggle, and nothing is called.\n if (chosen === laneId) return;\n set(laneId);\n };\n\n const handleCellClick = useEventCallback(\n (event: React.MouseEvent<HTMLDivElement>, laneId: string, col: 0 | 1): void => {\n // A click on a control inside the lane (a button, a link) is that control's.\n if (!isOwnClick(event, event.currentTarget)) return;\n setActive({ laneId, col });\n selectLane(laneId);\n }\n );\n\n const handleCellFocus = useEventCallback(\n (event: React.FocusEvent<HTMLDivElement>, laneId: string, col: 0 | 1): void => {\n // Focus on the cell, or on a control inside it (a button the pointer\n // focused), moves the Tab stop here: the lane is then kept in the DOM, and\n // its controls get their Tab order back, wherever the window scrolls to.\n // Portalled content bubbles through the React tree, but it is not inside.\n if (!event.currentTarget.contains(event.target)) return;\n setActive({ laneId, col });\n }\n );\n\n const registerRow = useEventCallback((laneId: string, element: HTMLElement | null): void => {\n if (element !== null) rowsRef.current.set(laneId, element);\n else rowsRef.current.delete(laneId);\n });\n\n const rowHandlers = React.useMemo<SwimlanesRowHandlers>(\n () => ({ onCellClick: handleCellClick, onCellFocus: handleCellFocus, registerRow }),\n [handleCellClick, handleCellFocus, registerRow]\n );\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {\n onKeyDownProp?.(event);\n const cell = cellOfEvent(event.target);\n if (cell === null) return;\n const { ctrlKey, metaKey, altKey } = event;\n\n if (!ctrlKey && !metaKey && !altKey) {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n selectLane(cell.laneId);\n return;\n }\n if (event.key === \"Escape\") {\n // Handled only with a selection, so an enclosing dialog still gets it.\n if (latest.current.selected === null) return;\n event.preventDefault();\n latest.current.setSelected(null);\n return;\n }\n }\n\n const index = latest.current.indexById.get(cell.laneId);\n if (index === undefined) return;\n const target = swimlanesKeyTarget(\n event.key,\n { ctrlKey, metaKey, altKey },\n { index, col: cell.col },\n { count: latest.current.lanes.length, pageSize: pageSize() }\n );\n if (target === null) return;\n event.preventDefault();\n moveTo(target.index, target.col);\n };\n\n const handleScroll = (event: React.UIEvent<HTMLDivElement>): void => {\n onScrollProp?.(event);\n virtual.onScroll(event);\n };\n\n // ---- Effects ----\n\n // The measured height replaces the estimate after mount: a normal\n // post-hydration update, so the server's window and the client's first agree.\n useSafeLayoutEffect(() => {\n const root = rootRef.current;\n if (root === null || typeof ResizeObserver !== \"function\") return;\n const observer = new ResizeObserver(() => {\n setMeasured(root.clientHeight);\n });\n observer.observe(root);\n return () => observer.disconnect();\n }, []);\n\n // Focus the cell a move asked for once the DOM has it. No dependency list: it\n // runs after every commit, and there is nothing to do without a pending move.\n useSafeLayoutEffect(() => {\n const pending = pendingFocusRef.current;\n if (pending === null) return;\n pendingFocusRef.current = null;\n // Always after the scroll position is set, or the focus scrolls it again.\n cellElement(pending.laneId, pending.col)?.focus({ preventScroll: true });\n });\n\n // A lane that goes away takes its selection with it, and focus moves to the\n // new Tab stop rather than dropping to the page. Only a lane that was there\n // counts: a selection given before its lane loads is kept.\n const previousIdsRef = React.useRef<readonly string[] | null>(null);\n useSafeLayoutEffect(() => {\n const before = previousIdsRef.current;\n previousIdsRef.current = ids;\n if (before === null || before === ids) return;\n const present = new Set(ids);\n const { selected: chosen, setSelected: set, active: had } = latest.current;\n const cleared = chosen !== null && !present.has(chosen) && before.includes(chosen);\n if (cleared) set(null);\n if (had === null || present.has(had.laneId)) return;\n setActive(null);\n const doc = rootRef.current?.ownerDocument;\n if (doc === undefined || (doc.activeElement !== null && doc.activeElement !== doc.body)) return;\n // The selection is gone with its lane when it was cleared, so fall back to\n // the first lane; otherwise the selected lane is the new Tab stop.\n const stop = !cleared && chosen !== null && present.has(chosen) ? chosen : ids[0];\n if (stop !== undefined) pendingFocusRef.current = { laneId: stop, col: 0 };\n // The id list's identity changes only when the ids themselves do.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ids]);\n\n // ---- One Tab stop for the lanes' own controls ----\n\n // Focusables inside the cells of every lane but the Tab stop leave the Tab\n // order; their own tabindex comes back when their lane becomes it. Tab from\n // the active cell then walks that lane's controls and leaves the grid.\n const ownTabIndexRef = React.useRef(new WeakMap<Element, string | null>());\n const appliedTabIndexRef = React.useRef(new WeakMap<Element, string | null>());\n const syncInnerTabStops = React.useCallback((): void => {\n const stop = tabStopRef.current?.laneId ?? null;\n const own = ownTabIndexRef.current;\n const applied = appliedTabIndexRef.current;\n for (const [laneId, row] of rowsRef.current) {\n for (const cell of Array.from(row.children)) {\n for (const inner of cell.querySelectorAll(INNER_FOCUSABLE)) {\n if (!own.has(inner)) own.set(inner, inner.getAttribute(\"tabindex\"));\n // A tabindex that differs from what the component last applied is the\n // caller's new own value: this sweep runs at commit, before the\n // MutationObserver microtask sees the write, so adopt it here instead\n // of writing the stale cached value back over it.\n if (inner.getAttribute(\"tabindex\") !== (applied.get(inner) ?? null)) {\n own.set(inner, inner.getAttribute(\"tabindex\"));\n }\n const next = laneId === stop ? (own.get(inner) ?? null) : \"-1\";\n if (inner.getAttribute(\"tabindex\") === next) {\n applied.set(inner, next);\n continue;\n }\n if (next === null) inner.removeAttribute(\"tabindex\");\n else inner.setAttribute(\"tabindex\", next);\n applied.set(inner, next);\n }\n }\n }\n }, []);\n\n // Keyed on the Tab stop and on the rendered lanes, so rows mounted later by\n // scrolling are synced too. Content that changes between those is the\n // observer's job below.\n useSafeLayoutEffect(() => {\n syncInnerTabStops();\n }, [tabStop, renderedKey, syncInnerTabStops]);\n\n // Content that changes later (a button that shows up with a status) is caught\n // too, and a tabindex the app rewrites from its own render becomes the\n // element's own value instead of being fought. The component's own writes are\n // recognised by what it last applied. Set up once.\n useSafeLayoutEffect(() => {\n const sizer = sizerRef.current;\n if (sizer === null || typeof MutationObserver !== \"function\") return;\n const observer = new MutationObserver((mutations) => {\n const own = ownTabIndexRef.current;\n const applied = appliedTabIndexRef.current;\n let sync = false;\n for (const mutation of mutations) {\n if (mutation.type !== \"attributes\") {\n // Added or moved content may carry focusables the sweep has not seen.\n sync = true;\n continue;\n }\n const element = mutation.target as Element;\n if (!applied.has(element)) continue;\n const now = element.getAttribute(\"tabindex\");\n if (now === (applied.get(element) ?? null)) continue;\n own.set(element, now);\n sync = true;\n }\n if (sync) syncInnerTabStops();\n });\n observer.observe(sizer, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"tabindex\"],\n });\n return () => observer.disconnect();\n }, [syncInnerTabStops]);\n\n // ---- Render ----\n\n // The component's own attributes, after the caller's, so they win; a key that\n // is not written at all leaves the caller's value in place.\n const gridAttributes = empty\n ? {}\n : {\n role: \"grid\" as const,\n \"aria-rowcount\": lanes.length,\n \"aria-colcount\": 2,\n ...(label === undefined ? {} : { \"aria-label\": label }),\n };\n\n const rootStyle = React.useMemo((): React.CSSProperties => {\n // A key is only written when it has a value: no `undefined` reaches the DOM.\n const own: React.CSSProperties = {};\n if (height !== undefined) own.height = cssLength(height);\n const custom = own as Record<string, string>;\n custom[\"--smwb-swimlanes-row-height\"] = `${rowHeight}px`;\n if (headerWidth !== undefined) custom[\"--smwb-swimlanes-header-width\"] = cssLength(headerWidth);\n if (contentMinWidth !== undefined) custom[\"--smwb-swimlanes-content-min-width\"] = cssLength(contentMinWidth);\n return { ...own, ...style };\n }, [height, rowHeight, headerWidth, contentMinWidth, style]);\n\n return (\n <div\n {...rest}\n ref={forkedRef}\n data-testid={dataTestId}\n className={cn(\"smwb-swimlanes\", { \"smwb-swimlanes_empty\": empty }, className)}\n style={rootStyle}\n {...gridAttributes}\n onScroll={handleScroll}\n onKeyDown={handleKeyDown}\n >\n {empty ? (\n // No grid role and no row count: an empty grid has no rows, which fails\n // the role's required children.\n <div className=\"smwb-swimlanes__empty\">{emptyLabel}</div>\n ) : (\n <div\n className=\"smwb-swimlanes__sizer\"\n role=\"presentation\"\n ref={sizerRef}\n style={{ height: virtual.totalHeight }}\n >\n {rendered.map((index) => {\n const lane = lanes[index];\n if (lane === undefined) return null;\n return (\n <SwimlanesRow\n key={lane.id}\n lane={lane}\n index={index}\n selected={selected === lane.id}\n selectable={selectable}\n tabCol={tabStop !== null && tabStop.laneId === lane.id ? tabStop.col : -1}\n rowHeight={rowHeight}\n handlers={rowHandlers}\n />\n );\n })}\n </div>\n )}\n </div>\n );\n});\n\nexport default Swimlanes;\n"],"names":["SWIMLANES_DEFAULT_ROW_HEIGHT","SWIMLANES_DEFAULT_HEIGHT","SWIMLANES_DEFAULT_OVERSCAN","INNER_FOCUSABLE","cssLength","value","sameList","a","b","i","swimlanesKeyTarget","key","mods","from","context","last","clamp","index","lane","column","col","SwimlanesRow","React","selected","selectable","tabCol","rowHeight","handlers","cell","role","className","content","jsx","event","jsxs","cn","element","Swimlanes","props","ref","style","lanes","label","selectedId","defaultSelectedId","onSelectedChange","headerWidth","contentMinWidth","height","overscan","emptyLabel","onScrollProp","onKeyDownProp","dataTestId","rest","rootRef","sizerRef","rowsRef","forkedRef","useForkRef","empty","indexById","map","nextIds","idsRef","ids","chosen","setSelected","useControllableState","active","setActive","tabStop","first","tabStopRef","estimate","measured","setMeasured","viewportHeight","virtual","useVirtualList","rendered","indexes","stop","renderedKey","_b","_a","latest","cellElement","laneId","cellOfEvent","target","root","sizer","row","pendingFocusRef","scrollLaneIntoView","itemHeight","fallback","viewport","top","scrollTop","moveTo","pageSize","selectLane","canSelect","set","handleCellClick","useEventCallback","isOwnClick","handleCellFocus","registerRow","rowHandlers","handleKeyDown","ctrlKey","metaKey","altKey","handleScroll","useSafeLayoutEffect","observer","pending","previousIdsRef","before","present","had","cleared","doc","ownTabIndexRef","appliedTabIndexRef","syncInnerTabStops","own","applied","inner","_c","next","_d","mutations","sync","mutation","now","gridAttributes","rootStyle","custom"],"mappings":"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"}
@@ -29,12 +29,28 @@ export interface TreeViewProps extends Omit<React.HTMLAttributes<HTMLDivElement>
29
29
  id: string;
30
30
  selected: boolean;
31
31
  }) => void;
32
- /** Enables label click selection. */
32
+ /**
33
+ * Enables row selection: a click, Enter or Space on a row toggles its selection. The chevron and the
34
+ * Left/Right keys never change it.
35
+ */
33
36
  selectable?: boolean;
34
37
  /** Renders a checkbox per node bound to selection. */
35
38
  checkboxes?: boolean;
39
+ /**
40
+ * Whether a click, Enter or Space on a row also expands or collapses its children. The chevron and the
41
+ * Right/Left keys always do. Defaults to `true` while the tree is not `selectable` (a row has nothing else to
42
+ * do) and to `false` otherwise, so that selecting a row leaves it open or closed.
43
+ */
44
+ toggleOnRowClick?: boolean;
36
45
  /** Custom node renderer. */
37
46
  renderLabel?: (item: ITreeNodeItem, nodeId: string) => ReactNode;
47
+ /**
48
+ * Per-node actions (buttons, a menu trigger), drawn at the end of the row. They sit beside the row's
49
+ * button, not inside it, so they take their own clicks, Enter and Space, focus and accessible names.
50
+ */
51
+ renderActions?: (item: ITreeNodeItem, nodeId: string) => ReactNode;
52
+ /** Text shown while `loadChildren` is pending; "Loading…" unless given. */
53
+ loadingText?: string;
38
54
  /** Lazily resolves children the first time a node is expanded. */
39
55
  loadChildren?: (item: ITreeNodeItem, nodeId: string) => Promise<ITreeNodeItem[]>;
40
56
  /** Test id of the root `<div>`; `tree-view` unless given. */