@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 @@
1
+ {"version":3,"file":"tabGroups.js","sources":["../../../../src/components/layout/tabGroups/tabGroups.tsx"],"sourcesContent":["import React from \"react\";\nimport cn from \"clsx\";\nimport Icon from \"../../base/icon/icon\";\nimport { Menu, MenuItem } from \"../../navigation/menu\";\nimport { Tab, Tabs, type TabCloseReason, type TabProps } from \"../../navigation/tabs\";\nimport { useControllableState } from \"../../../hooks/useControllableState\";\nimport { useEventCallback } from \"../../../hooks/useEventCallback\";\nimport { useForkRef } from \"../../../hooks/useForkRef\";\nimport { useId } from \"../../../hooks/useId\";\nimport { useSafeLayoutEffect } from \"../../../hooks/useSafeLayoutEffect\";\nimport { matchesKeyboardShortcut } from \"../../../utils/keyboardShortcut\";\nimport { throttle } from \"../../../utils/throttle\";\nimport {\n TAB_GROUPS_LABELS,\n adjacentGroup,\n computeTabGroupsGrid,\n createTabGroupsLayout,\n describeTabGroupsChange,\n dropZoneAt,\n findGroupOfTab,\n getGroups,\n gridTemplateColumns,\n gridTemplateRows,\n groupBodyArea,\n groupHeaderArea,\n moveTab,\n moveTabInDirection,\n removeTab,\n resizeSplit,\n selectTab,\n separatorArea,\n setActiveGroup,\n type TabGroupsChange,\n type TabGroupsDropZone,\n type TabGroupsEdge,\n type TabGroupsGroup,\n type TabGroupsLabels,\n type TabGroupsLayout,\n type TabGroupsMoveTarget,\n type TabGroupsNode,\n type TabGroupsSplit,\n} from \"./tabGroupsLayout\";\nimport {\n containsDeep,\n deepActiveElement,\n focusFromEnd,\n frameExitTarget,\n lastStopOf,\n ownGroupIdOf,\n ownerRootOf,\n tabMove,\n} from \"./tabGroupsFocus\";\n\n/** What one tab of `TabGroups` shows. The layout stores ids only; the app answers for the rest. */\nexport interface TabGroupsTab {\n /** The tab's label, as `Tab`'s own. */\n label: React.ReactNode;\n /**\n * Plain text for the announcements: what a screen reader says the tab is called. `label` when it\n * is a string, the tab id otherwise.\n */\n title?: string;\n /** Content before the label: a status marker. Decorative, as in `Tab`. */\n icon?: React.ReactNode;\n /**\n * Draw a close button and let Delete or Backspace close the tab; true by default. Pass `false`\n * to keep the tab's item wrapper — and so the same drag surface — without a close button.\n */\n closable?: boolean;\n /** Accessible label of the close button. English by default; set it to localise. */\n closeLabel?: string;\n /** Content after the tab: a trigger with a `Menu`, as `Tab`'s own `actions`. */\n actions?: TabProps[\"actions\"];\n /** Shown and focusable, but not selectable, not closable and not draggable. */\n disabled?: boolean;\n}\n\n/**\n * A container of tab groups: the area splits right or down into groups, each group is a tab row\n * with its panels, tabs move between groups by drag and drop or by keyboard, and the whole\n * arrangement is a serialisable, versioned layout.\n *\n * The layout is controlled while `layout` is given and uncontrolled otherwise (seeded from\n * `defaultLayout`); `onLayoutChange` is called in both modes with the new layout and what changed.\n * Only ids and sizes are stored: `getTab` says what a tab shows and `renderPanel` what it contains,\n * so the JSON stays small and survives a label rename. A panel is rendered from the first time its\n * tab is selected and then stays mounted while hidden, so a tab keeps its state when it moves to\n * another group. A move only changes where a panel is drawn — its node stays where it is in the\n * DOM — so its scroll, an iframe in it and the focus inside it survive the move too.\n *\n * Everything is reachable without a mouse. In a tab row: the arrows, Home and End move focus,\n * Enter or Space selects, Delete or Backspace and Mod+W close, Mod+Shift+[ and Mod+Shift+] switch\n * (all of that is `Tabs`). On the focused tab: Alt+Shift+Arrow moves it into the group that way, or\n * splits a new group there when the area ends, and Mod+Shift+ArrowLeft/Right moves it along the row.\n * Each group's actions button opens a menu with the same actions, and each separator takes the\n * arrow keys along its axis plus Home and End. Every move is announced in a status region.\n *\n * Dropping a tab on a group's body puts it in that group; dropping it within a quarter of the\n * body's edge splits a new group there. The zones are drawn while dragging.\n */\nexport interface TabGroupsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\" | \"onChange\"> {\n /**\n * The arrangement to draw: the split tree, the tabs of every group and which of them is\n * selected. Controlled while it is not `undefined` — the component then draws what it is given\n * and an owner that ignores `onLayoutChange` sees nothing move.\n */\n layout?: TabGroupsLayout | undefined;\n /** The layout of the uncontrolled mode's first render: one empty group by default. */\n defaultLayout?: TabGroupsLayout | undefined;\n /**\n * Called with the new layout and what changed (`select`, `activate`, `move`, `split`, `close`,\n * `resize`) in the controlled and the uncontrolled mode alike. Store the layout here; the\n * `change` says which of them are worth writing (an `activate` is a focus move, not an edit).\n */\n onLayoutChange?: ((layout: TabGroupsLayout, change: TabGroupsChange) => void) | undefined;\n /** What a tab shows, by its id: `undefined` draws the id as the label. */\n getTab: (tabId: string) => TabGroupsTab | undefined;\n /**\n * The content of a tab's panel, by its id. Called from the first time the tab is selected and\n * kept mounted after that, so a panel keeps its state while hidden and while its tab moves.\n */\n renderPanel: (tabId: string) => React.ReactNode;\n /**\n * Asked before a tab closes (its close button, Delete or Backspace, a middle press or its\n * `actions`), with what asked for it. Return `false` to keep the tab; anything else closes it.\n */\n onTabClose?:\n | ((tabId: string, event: React.SyntheticEvent<HTMLElement>, reason: TabCloseReason) => boolean | void)\n | undefined;\n /** Drawn, centred, when nothing is open: the only group has no tabs. */\n empty?: React.ReactNode;\n /** The smallest a group can be resized to, in px of its split; 120 by default. */\n minGroupSize?: number;\n /** A separator's arrow-key step, in percent of its split; 5 by default, as `ScreenDivider`. */\n keyboardStep?: number;\n /** Draw each group's actions button and its menu; true by default. */\n groupActions?: boolean;\n /** Compact tab rows (`Tabs`' `dense`); false by default. */\n dense?: boolean;\n /** The component's texts, to localise them. English by default. */\n labels?: Partial<TabGroupsLabels> | undefined;\n /** Base of the generated ids and the root's own id. Generated by default. */\n id?: string;\n /** Test id of the root element; \"tab-groups\" by default. */\n \"data-testid\"?: string;\n}\n\n/** The item the first focusable entry of an opened menu is looked up with, as `Tab` does. */\nconst FIRST_MENU_ITEM = '[role^=\"menuitem\"]:not([aria-disabled=\"true\"])';\n\n/** One empty group: what the uncontrolled mode starts from without a `defaultLayout`. */\nconst EMPTY_LAYOUT = createTabGroupsLayout();\n\n/** The chords `TabGroups` answers to, as `aria-keyshortcuts` lists them (`Tab` appends its own). */\nconst KEY_SHORTCUTS = [\n \"Alt+Shift+ArrowLeft\",\n \"Alt+Shift+ArrowRight\",\n \"Alt+Shift+ArrowUp\",\n \"Alt+Shift+ArrowDown\",\n \"Control+Shift+ArrowLeft\",\n \"Meta+Shift+ArrowLeft\",\n \"Control+Shift+ArrowRight\",\n \"Meta+Shift+ArrowRight\",\n].join(\" \");\n\n/** The nearest `data-group-id` at or above a node, walked rather than selected: ids need no escaping. */\nfunction groupIdOf(node: Element | null | undefined): string | null {\n let current = node ?? null;\n while (current) {\n const id = current.getAttribute(\"data-group-id\");\n if (id !== null) return id;\n current = current.parentElement;\n }\n return null;\n}\n\n/** The element a drag of this tab starts on: its item, or the tab itself when it has no controls. */\nfunction tabItemOf(tab: HTMLElement): HTMLElement {\n return tab.closest<HTMLElement>(\".smwb-tab-item\") ?? tab;\n}\n\n/**\n * The tab a drag started from, or that the pointer is over. `Tabs` puts `draggable` on the item\n * wrapper, and a browser fires `dragstart` at that source node rather than at the element under the\n * cursor, so the tab is looked for inside the item as well as among the node's ancestors: a close\n * button or an `actions` trigger is the item's child, not the tab's.\n */\nfunction tabElementOf(target: HTMLElement): HTMLElement | null {\n const item = target.closest<HTMLElement>(\".smwb-tab-item\");\n return (\n item?.querySelector<HTMLElement>('[role=\"tab\"][data-tab-id]') ??\n target.closest<HTMLElement>('[role=\"tab\"][data-tab-id]')\n );\n}\n\n/** The split with this id, if the tree has one. */\nfunction findSplit(node: TabGroupsNode, id: string): TabGroupsSplit | undefined {\n if (node.type === \"group\") return undefined;\n if (node.id === id) return node;\n for (const child of node.children) {\n const found = findSplit(child, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** The ids of the groups a node holds, in reading order. */\nfunction groupIdsOf(node: TabGroupsNode): string[] {\n return node.type === \"group\" ? [node.id] : node.children.flatMap(groupIdsOf);\n}\n\n/** Where each content track starts, in percent: `starts[i]` before track `i`, `starts[n]` at 100. */\nfunction trackStarts(tracks: readonly number[]): number[] {\n const starts: number[] = [0];\n tracks.forEach((size, index) => {\n starts[index + 1] = (starts[index] ?? 0) + size;\n });\n return starts;\n}\n\n/** A separator's value: the first of its two neighbours' share of the pair, 0–100 and rounded. */\nfunction pairValue(split: TabGroupsSplit, index: number): number {\n const first = split.sizes[index] ?? 0;\n const pair = first + (split.sizes[index + 1] ?? 0);\n return pair > 0 ? Math.round((first / pair) * 100) : 0;\n}\n\n/** Whether a group id is still in the layout: what tells a closed source group from a living one. */\nfunction hasGroup(layout: TabGroupsLayout, groupId: string): boolean {\n return getGroups(layout).some((group) => group.id === groupId);\n}\n\n/**\n * The root's children in reading order, by the key each one is looked up with: per group its\n * header and then its panels, with each separator after the subtree it follows. It is the Tab order\n * and the order assistive technology reads in, while the DOM keeps the panels where they are.\n */\nfunction readingKeys(root: TabGroupsNode): string[] {\n const keys: string[] = [];\n const walk = (node: TabGroupsNode): void => {\n if (node.type === \"group\") {\n keys.push(`h:${node.id}`, `p:${node.id}`);\n return;\n }\n node.children.forEach((child, index) => {\n walk(child);\n if (index < node.children.length - 1) keys.push(`s:${node.id}:${index}`);\n });\n };\n walk(root);\n return keys;\n}\n\n/** The two changes a move can stand for; both name the group the tab ended up in. */\ntype MoveChange = Extract<TabGroupsChange, { type: \"move\" } | { type: \"split\" }>;\n\n/**\n * The change a move stands for, read from the layouts before and after: a `split` when the tab\n * landed in a group that was not there before, a `move` otherwise (a reorder included).\n */\nfunction moveChange(\n before: TabGroupsLayout,\n after: TabGroupsLayout,\n tabId: string,\n edge: TabGroupsEdge | undefined\n): MoveChange | null {\n const from = findGroupOfTab(before, tabId);\n const to = findGroupOfTab(after, tabId);\n if (!from || !to) return null;\n const sourceClosed = !hasGroup(after, from.id);\n if (edge !== undefined && !hasGroup(before, to.id)) {\n return { type: \"split\", tab: tabId, from: from.id, to: to.id, edge, sourceClosed };\n }\n return { type: \"move\", tab: tabId, from: from.id, to: to.id, index: to.tabs.indexOf(tabId), sourceClosed };\n}\n\nexport const TabGroups = React.forwardRef<HTMLDivElement, TabGroupsProps>(function TabGroups(props, ref) {\n const {\n layout: layoutProp,\n defaultLayout,\n onLayoutChange,\n getTab,\n renderPanel,\n onTabClose,\n empty,\n minGroupSize = 120,\n keyboardStep = 5,\n groupActions = true,\n dense = false,\n labels: labelsProp,\n id: idProp,\n className,\n style,\n \"data-testid\": dataTestId = \"tab-groups\",\n // Wrapped so that the caller's handler still runs, first.\n onFocus,\n onKeyDown,\n onDragStart,\n onDragOver,\n onDrop,\n onDragEnd,\n ...rest\n } = props;\n\n const base = useId(idProp);\n const headerElementId = (groupId: string): string => `${base}-header-${encodeURIComponent(groupId)}`;\n const panelElementId = (tabId: string): string => `${base}-panel-${encodeURIComponent(tabId)}`;\n const separatorElementId = (splitId: string, index: number): string =>\n `${base}-separator-${encodeURIComponent(splitId)}-${index}`;\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n const forkedRef = useForkRef<HTMLDivElement>(ref, rootRef);\n\n const [layout, setLayout] = useControllableState<TabGroupsLayout>({\n value: layoutProp,\n defaultValue: defaultLayout ?? EMPTY_LAYOUT,\n });\n // What the next change starts from: the layout as rendered, or what a change in the same event\n // already produced, so a drop followed by `Tabs`' own report composes instead of losing the first.\n // Reset to the rendered value every render, and — while controlled — once the event is over\n // (`settle`): a change the owner did not draw is forgotten, so the next one does not report it.\n const latestRef = React.useRef(layout);\n latestRef.current = layout;\n const renderedRef = React.useRef(layout);\n renderedRef.current = layout;\n const controlledRef = React.useRef(layoutProp !== undefined);\n controlledRef.current = layoutProp !== undefined;\n const settleQueuedRef = React.useRef(false);\n\n const labels = React.useMemo<TabGroupsLabels>(() => ({ ...TAB_GROUPS_LABELS, ...labelsProp }), [labelsProp]);\n\n const [status, setStatus] = React.useState(\"\");\n // The tab to focus once a change is on screen: where the change puts it (group and index), after\n // a close the group that has to be gone, the layout the change produced (`after`), the layout drawn\n // when it was asked for and the element that had the focus then. It waits for the next layout the\n // owner draws, however late, and that layout either shows the change — the tab takes the focus —\n // or not, and focus stays where it is.\n const pendingFocusRef = React.useRef<{\n tab: string;\n group: string;\n index: number;\n gone?: string;\n after: TabGroupsLayout;\n base: TabGroupsLayout;\n from: Element | null;\n } | null>(null);\n // Every layout `commit` reported, numbered: an owner that applies them late draws them in order,\n // and one reported before the change a focus waits for is no answer to that change.\n const reportedRef = React.useRef(new WeakMap<TabGroupsLayout, number>());\n const reportCountRef = React.useRef(0);\n // The focus guard is taking the focus on its way out of the root: not a reason to send it back.\n const leavingRef = React.useRef(false);\n const guardRef = React.useRef<HTMLSpanElement | null>(null);\n // The element in the root that had the focus last, and whether a pointer press is placing the\n // focus now: what tells the browser's Tab out of an iframe from a click.\n const lastFocusRef = React.useRef<HTMLElement | null>(null);\n const pointerFocusRef = React.useRef(false);\n\n // Drag and drop: the drag that started here, the zone the pointer is over, and the row item it\n // marks. The targets render a frame after `dragstart`, since changing the DOM inside it can\n // cancel the drag in Chromium.\n const dragRef = React.useRef<{ tab: string; group: string; hadFocus: boolean } | null>(null);\n const frameRef = React.useRef<{ view: Window; id: number } | null>(null);\n const rowMarkRef = React.useRef<HTMLElement | null>(null);\n const [dragging, setDragging] = React.useState(false);\n const [dropTarget, setDropTarget] = React.useState<{ group: string; zone: TabGroupsDropZone } | null>(null);\n\n // A separator's drag: the layout and the scale it started from, so the pointer stays on the grip.\n const resizeRef = React.useRef<{\n split: string;\n index: number;\n axis: \"x\" | \"y\";\n pointerId: number;\n start: number;\n extentPx: number;\n minPercent: number;\n layout: TabGroupsLayout;\n } | null>(null);\n const [dragSeparator, setDragSeparator] = React.useState<{\n key: string;\n orientation: \"vertical\" | \"horizontal\";\n } | null>(null);\n\n // The group whose menu is open, and the button that opened it (kept through the closing fade).\n const [menuGroup, setMenuGroup] = React.useState<string | null>(null);\n const [menuAnchor, setMenuAnchor] = React.useState<HTMLElement | null>(null);\n const [menuFocusRequest, setMenuFocusRequest] = React.useState(0);\n\n const groups = React.useMemo(() => getGroups(layout), [layout]);\n const grid = React.useMemo(() => computeTabGroupsGrid(layout), [layout]);\n const groupsById = React.useMemo(() => new Map(groups.map((group) => [group.id, group])), [groups]);\n const gridGroupsById = React.useMemo(() => new Map(grid.groups.map((entry) => [entry.id, entry])), [grid]);\n const gridSeparators = React.useMemo(\n () => new Map(grid.separators.map((entry) => [`${entry.split}:${entry.index}`, entry])),\n [grid]\n );\n const columnStarts = React.useMemo(() => trackStarts(grid.columns), [grid]);\n const rowStarts = React.useMemo(() => trackStarts(grid.rows), [grid]);\n\n // Lazy keep-alive: the panels whose content is mounted. Seeded from the selected tabs, which the\n // server renders too, so hydration matches, and updated during render idempotently (StrictMode\n // renders twice): a tab selected once stays mounted, a tab that is gone is forgotten.\n const mountedRef = React.useRef<Set<string> | null>(null);\n const mounted = mountedRef.current ?? new Set<string>();\n const known = new Set<string>();\n groups.forEach((group) => group.tabs.forEach((tabId) => known.add(tabId)));\n Array.from(mounted).forEach((tabId) => {\n if (!known.has(tabId)) mounted.delete(tabId);\n });\n groups.forEach((group) => {\n if (group.active !== null) mounted.add(group.active);\n });\n mountedRef.current = mounted;\n\n // The DOM order of the panels: the order they first appeared in, a new one at the end, never\n // changed after that. A move only changes a panel's `grid-area`, so its node stays where it is —\n // putting it back into the document would reset its scroll, reload an iframe in it and blur the\n // focus inside it. Reading and Tab order come from the layout instead (`readingKeys`).\n const panelOrderRef = React.useRef<string[]>([]);\n const panelOrder = panelOrderRef.current.filter((tabId) => known.has(tabId));\n const placed = new Set(panelOrder);\n groups.forEach((group) =>\n group.tabs.forEach((tabId) => {\n if (!placed.has(tabId)) {\n placed.add(tabId);\n panelOrder.push(tabId);\n }\n })\n );\n panelOrderRef.current = panelOrder;\n const groupOfTab = new Map<string, TabGroupsGroup>();\n groups.forEach((group) => group.tabs.forEach((tabId) => groupOfTab.set(tabId, group)));\n\n /** What a tab is called in an announcement: its `title`, its label when that is text, else its id. */\n const titleOf = useEventCallback((tabId: string): string => {\n const tab = getTab(tabId);\n if (!tab) return tabId;\n if (tab.title !== undefined) return tab.title;\n return typeof tab.label === \"string\" ? tab.label : tabId;\n });\n\n /**\n * Applies a model result. The model returns the layout it was given when nothing changed, and\n * then nothing happens at all: no state, no `onLayoutChange`, no announcement, no focus move.\n */\n const commit = useEventCallback((next: TabGroupsLayout, change: TabGroupsChange): boolean => {\n if (next === latestRef.current) return false;\n latestRef.current = next;\n reportCountRef.current += 1;\n reportedRef.current.set(next, reportCountRef.current);\n setLayout(next);\n onLayoutChange?.(next, change);\n const text = describeTabGroupsChange(change, next, titleOf, labels);\n // The same text twice in a row would not be read again: a trailing no-break space alternates.\n if (text) setStatus((previous) => (previous === text ? `${text}\\u00a0` : text));\n if (controlledRef.current && !settleQueuedRef.current) {\n settleQueuedRef.current = true;\n queueMicrotask(settle);\n }\n return true;\n });\n\n /**\n * After the event that changed the layout: while controlled, what is drawn is the prop, so the\n * next change starts from it again — a change the owner did not draw by now is not reported\n * twice. The owner's own render (a React update from `onLayoutChange`) has run by then, and two\n * changes of one event — a drop and `Tabs`' report of it, a commit and the `focusin` it causes —\n * still compose. The focus move waits for the owner's next layout (`focusPending`).\n */\n const settle = useEventCallback((): void => {\n settleQueuedRef.current = false;\n if (!controlledRef.current || latestRef.current === renderedRef.current) return;\n latestRef.current = renderedRef.current;\n });\n\n /** Asks for a tab's focus once `after`, the layout a change produced, is drawn; `gone` is a closed group. */\n const armFocus = (tabId: string, after: TabGroupsLayout, gone?: string): void => {\n const group = findGroupOfTab(after, tabId);\n if (!group) return;\n const doc = rootRef.current?.ownerDocument;\n pendingFocusRef.current = {\n tab: tabId,\n group: group.id,\n index: group.tabs.indexOf(tabId),\n ...(gone === undefined ? {} : { gone }),\n after,\n base: renderedRef.current,\n from: doc ? deepActiveElement(doc) : null,\n };\n };\n\n /** Moves a tab (into a group, to an index of its row, or to an edge as a new group) and arms its focus. */\n const moveTo = useEventCallback((tabId: string, target: TabGroupsMoveTarget, focus = true): void => {\n const before = latestRef.current;\n const after = moveTab(before, tabId, target);\n const change = moveChange(before, after, tabId, target.edge);\n if (!change || !commit(after, change)) return;\n if (focus) armFocus(tabId, after);\n });\n\n /** The Alt+Shift+Arrow move: into the group that way, or a new group there. False when nothing can move. */\n const moveInDirection = useEventCallback((tabId: string, edge: TabGroupsEdge): boolean => {\n const before = latestRef.current;\n const after = moveTabInDirection(before, tabId, edge);\n if (after === before) return false;\n const change = moveChange(before, after, tabId, edge);\n if (!change || !commit(after, change)) return false;\n armFocus(tabId, after);\n return true;\n });\n\n /** The Mod+Shift+Arrow move: one place along the row, no wrap, the selection unchanged. */\n const moveInRow = useEventCallback((tabId: string, delta: -1 | 1): boolean => {\n const before = latestRef.current;\n const group = findGroupOfTab(before, tabId);\n if (!group) return false;\n const to = group.tabs.indexOf(tabId) + delta;\n if (to < 0 || to >= group.tabs.length) return false;\n const after = moveTab(before, tabId, { group: group.id, index: to });\n const change = moveChange(before, after, tabId, undefined);\n if (!change || !commit(after, change)) return false;\n armFocus(tabId, after);\n return true;\n });\n\n /** Selects a tab: what a click, Enter or Space on it asks for. */\n const select = useEventCallback((tabId: string): void => {\n const before = latestRef.current;\n const group = findGroupOfTab(before, tabId);\n if (!group) return;\n commit(selectTab(before, tabId), { type: \"select\", tab: tabId, group: group.id });\n });\n\n /**\n * Resizes a separator. `delta` is in percent of the split (±Infinity: to the limit `minPercent`\n * allows), and a pointer drag passes the layout its drag started from, so the grip stays under\n * the cursor however many frames the drag reported.\n */\n const resize = useEventCallback(\n (splitId: string, index: number, delta: number, minPercent: number, from?: TabGroupsLayout): void => {\n const before = from ?? latestRef.current;\n const after = resizeSplit(before, splitId, index, delta, minPercent);\n if (after === before) return;\n const split = findSplit(after.root, splitId);\n commit(after, { type: \"resize\", split: splitId, sizes: split ? [...split.sizes] : [] });\n }\n );\n\n /** Closes a tab, unless the app vetoes it, and moves focus on when the tab's whole group goes. */\n const requestClose = useEventCallback(\n (tabId: string, event: React.SyntheticEvent<HTMLElement>, reason: TabCloseReason): void => {\n const before = latestRef.current;\n const group = findGroupOfTab(before, tabId);\n if (!group) return;\n if (onTabClose?.(tabId, event, reason) === false) return;\n const after = removeTab(before, tabId);\n if (after === before) return;\n const groupClosed = !hasGroup(after, group.id);\n // Focus was in the group that is going, or the close came from its `actions` menu (drawn\n // outside the row): focus moves to the group that takes the space. Anywhere else it stays.\n const root = rootRef.current;\n const active = root ? deepActiveElement(root.ownerDocument) : null;\n const focusWasHere = reason === \"actions\" || (root !== null && ownGroupIdOf(root, active) === group.id);\n if (!commit(after, { type: \"close\", tab: tabId, group: group.id, groupClosed })) return;\n if (!groupClosed || !focusWasHere) return;\n const neighbourId = adjacentGroup(before, group.id);\n const neighbour = neighbourId ? getGroups(after).find((entry) => entry.id === neighbourId) : undefined;\n if (neighbour?.active) armFocus(neighbour.active, after, group.id);\n }\n );\n\n /**\n * Follows the focus. The group it is in becomes the active one: new tabs go there, and its\n * header is the marked one. A frame of this root it came out of is checked (`frameExitTarget`),\n * and the guard sends it on to the last stop when it came from after the root. A nested\n * `TabGroups` has a root of its own: its guard and its frames are not this root's.\n */\n const onRootFocus = (event: React.FocusEvent<HTMLDivElement>): void => {\n onFocus?.(event);\n const root = rootRef.current;\n if (!root) return;\n const target = event.target;\n const previous = lastFocusRef.current;\n lastFocusRef.current = ownerRootOf(target) === root ? target : null;\n if (previous?.localName === \"iframe\" && previous !== target && !pointerFocusRef.current) {\n const instead = frameExitTarget(root, previous, target);\n if (instead !== null && instead === guardRef.current) {\n // Nothing follows the root: the guard holds the focus, and the next Tab leaves the page.\n leavingRef.current = true;\n if (instead !== target) instead.focus({ preventScroll: true });\n return;\n }\n if (instead !== null) {\n instead.focus();\n return;\n }\n }\n if (target === guardRef.current) {\n onGuardFocus();\n return;\n }\n const groupId = ownGroupIdOf(root, target);\n if (!groupId || groupId === latestRef.current.activeGroup) return;\n commit(setActiveGroup(latestRef.current, groupId), { type: \"activate\", group: groupId });\n };\n\n /**\n * Keeps the Tab key in reading order (`tabMove`). Inside a header, a panel or a separator the\n * browser moves the focus itself; a press that would leave one goes to the next child in reading\n * order instead, and after the last one out through the guard. The move starts from the focused\n * element, which a nested `TabGroups` may already have moved on (to its own guard or a panel's end).\n */\n const onRootKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {\n onKeyDown?.(event);\n if (event.defaultPrevented || event.key !== \"Tab\" || event.altKey || event.ctrlKey || event.metaKey) return;\n if (event.nativeEvent.isComposing) return;\n const root = rootRef.current;\n const from = root ? deepActiveElement(root.ownerDocument) : null;\n if (!root || !from || !containsDeep(root, from)) return;\n const move = tabMove(root, from, event.shiftKey ? -1 : 1);\n if (!move) return;\n if (move.element === guardRef.current) leavingRef.current = true;\n // A move of the key's own, not the browser's way out of a frame.\n lastFocusRef.current = null;\n if (move.prevent) {\n event.preventDefault();\n move.element.focus();\n } else {\n // Not prevented: the browser's own move runs on from here.\n move.element.focus({ preventScroll: true });\n }\n };\n\n // A pointer press places the focus where it lands, iframe or not; and the focus that leaves the\n // root forgets where it was.\n React.useEffect(() => {\n const root = rootRef.current;\n const view = root?.ownerDocument.defaultView;\n if (!root || !view) return undefined;\n let timer: number | undefined;\n const onPointerDown = (): void => {\n pointerFocusRef.current = true;\n view.clearTimeout(timer);\n timer = view.setTimeout(() => {\n pointerFocusRef.current = false;\n }, 0);\n };\n const onFocusOut = (event: FocusEvent): void => {\n if (event.relatedTarget instanceof Node && !root.contains(event.relatedTarget)) lastFocusRef.current = null;\n };\n // Into an iframe the focus moves without a focus event on the iframe; the window loses it, and\n // by then the iframe is the active element. Only this root's own frames count.\n const onWindowBlur = (): void => {\n const active = root.ownerDocument.activeElement;\n if (active instanceof view.HTMLIFrameElement && ownerRootOf(active) === root) lastFocusRef.current = active;\n };\n root.addEventListener(\"pointerdown\", onPointerDown, true);\n root.addEventListener(\"focusout\", onFocusOut);\n view.addEventListener(\"blur\", onWindowBlur);\n return () => {\n view.clearTimeout(timer);\n root.removeEventListener(\"pointerdown\", onPointerDown, true);\n root.removeEventListener(\"focusout\", onFocusOut);\n view.removeEventListener(\"blur\", onWindowBlur);\n };\n }, []);\n\n /** Shift+Tab from after the root lands on the guard, its last stop: the last stop in reading order takes it. */\n const onGuardFocus = (): void => {\n const root = rootRef.current;\n if (leavingRef.current || !root) return;\n const last = lastStopOf(root);\n if (last) focusFromEnd(last);\n };\n\n /**\n * Whether the drawn layout is no answer yet to the change a focus waits for: it is the one drawn\n * when the focus was asked for, or a change reported before that one, which a late owner draws first.\n */\n const stillWaiting = (\n pending: { after: TabGroupsLayout; base: TabGroupsLayout },\n drawn: TabGroupsLayout\n ): boolean => {\n if (drawn === pending.base) return true;\n const drawnAt = reportedRef.current.get(drawn);\n const askedAt = reportedRef.current.get(pending.after);\n return drawnAt !== undefined && askedAt !== undefined && drawnAt < askedAt;\n };\n\n /**\n * The moved tab takes focus once the change is drawn: on the first layout the owner draws that\n * answers it — in the same event or later, in a transition or a timeout — and only when that\n * layout shows the change and the focus is still with the layout (or still where it was). Then\n * the request is done either way, so a change the owner never drew moves no focus later.\n */\n const focusPending = (): void => {\n const pending = pendingFocusRef.current;\n const root = rootRef.current;\n const drawn = renderedRef.current;\n if (!pending || !root || stillWaiting(pending, drawn)) return;\n const group = findGroupOfTab(drawn, pending.tab);\n if (group?.id !== pending.group || group.tabs.indexOf(pending.tab) !== pending.index) return;\n // The heir of a closed group takes the focus only once that group is gone.\n if (pending.gone !== undefined && hasGroup(drawn, pending.gone)) return;\n const node = Array.from(\n root.querySelectorAll<HTMLElement>(':scope > .smwb-tab-groups__header [role=\"tab\"][data-tab-id]')\n ).find((element) => element.getAttribute(\"data-tab-id\") === pending.tab);\n if (!node || groupIdOf(node) !== pending.group) return;\n const doc = root.ownerDocument;\n const active = deepActiveElement(doc);\n if (active === node) return;\n if (active !== null && active !== doc.body && active !== pending.from && !containsDeep(root, active)) return;\n node.focus();\n };\n\n // React puts the focus a commit started with back when the element it was on is still in the\n // document (resetAfterCommit), so the passive effect — which runs after that — asks once more,\n // and then the request is done.\n useSafeLayoutEffect(() => {\n focusPending();\n });\n\n React.useEffect(() => {\n focusPending();\n const pending = pendingFocusRef.current;\n if (pending && !stillWaiting(pending, renderedRef.current)) pendingFocusRef.current = null;\n });\n\n // A menu opened from the keyboard puts focus on its first enabled item, as the WAI-ARIA menu\n // button pattern asks; a pointer click leaves focus on the trigger.\n useSafeLayoutEffect(() => {\n if (menuFocusRequest === 0) return;\n const trigger = menuAnchor;\n for (const id of trigger?.getAttribute(\"aria-controls\")?.split(/\\s+/) ?? []) {\n const item = id ? trigger?.ownerDocument.getElementById(id)?.querySelector<HTMLElement>(FIRST_MENU_ITEM) : null;\n if (item) {\n // The menu may not be placed yet: a scroll to it would jump to the corner it starts in.\n item.focus({ preventScroll: true });\n return;\n }\n }\n }, [menuFocusRequest, menuAnchor]);\n\n // The pointer drag sets the page cursor, as `ScreenDivider` does: the grip is thin and the\n // cursor would otherwise change to whatever is under it while the drag runs.\n useSafeLayoutEffect(() => {\n if (!dragSeparator) return undefined;\n const body = document.body;\n const previous = body.style.cursor;\n body.style.cursor = dragSeparator.orientation === \"vertical\" ? \"col-resize\" : \"row-resize\";\n return () => {\n body.style.cursor = previous;\n };\n }, [dragSeparator]);\n\n // ---- Geometry ----\n\n /** The share of the root a split covers along an axis, in percent: its outermost groups' spans joined. */\n const splitExtentPercent = React.useCallback(\n (split: TabGroupsSplit, axis: \"x\" | \"y\"): number => {\n const starts = axis === \"x\" ? columnStarts : rowStarts;\n let from = Infinity;\n let to = -Infinity;\n groupIdsOf(split).forEach((id) => {\n const entry = gridGroupsById.get(id);\n if (!entry) return;\n const [a, b] = axis === \"x\" ? entry.column : entry.row;\n from = Math.min(from, starts[a] ?? 0);\n to = Math.max(to, starts[b] ?? 100);\n });\n return Number.isFinite(from) && to > from ? to - from : 100;\n },\n [columnStarts, rowStarts, gridGroupsById]\n );\n\n /**\n * What one percent of a split is worth in px, and the smallest share a group may keep there\n * (`minGroupSize` as a percent of the split): what a separator resizes by. Read from the root's\n * box, so nothing has to be measured per split — and, in jsdom, a stubbed root rect is enough.\n */\n const splitScale = React.useCallback(\n (split: TabGroupsSplit, axis: \"x\" | \"y\"): { extentPx: number; minPercent: number } => {\n const rect = rootRef.current?.getBoundingClientRect();\n const total = (axis === \"x\" ? rect?.width : rect?.height) ?? 0;\n const extentPx = (total * splitExtentPercent(split, axis)) / 100;\n return { extentPx, minPercent: extentPx > 0 ? (minGroupSize / extentPx) * 100 : 0 };\n },\n [minGroupSize, splitExtentPercent]\n );\n\n const headerStyle = React.useCallback(\n (groupId: string): React.CSSProperties | undefined => {\n const entry = gridGroupsById.get(groupId);\n return entry ? { gridArea: groupHeaderArea(entry) } : undefined;\n },\n [gridGroupsById]\n );\n\n const bodyStyle = React.useCallback(\n (groupId: string): React.CSSProperties | undefined => {\n const entry = gridGroupsById.get(groupId);\n return entry ? { gridArea: groupBodyArea(entry) } : undefined;\n },\n [gridGroupsById]\n );\n\n // ---- Separators ----\n\n const resizeThrottled = React.useMemo(\n () =>\n throttle((position: number) => {\n const drag = resizeRef.current;\n if (!drag || !(drag.extentPx > 0)) return;\n resize(drag.split, drag.index, ((position - drag.start) / drag.extentPx) * 100, drag.minPercent, drag.layout);\n }, 1000 / 60),\n [resize]\n );\n\n // A drag or a drop-target frame left running past the component would report into nothing.\n React.useEffect(\n () => () => {\n if (frameRef.current) frameRef.current.view.cancelAnimationFrame(frameRef.current.id);\n resizeThrottled.cancel();\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const onSeparatorPointerDown = (\n event: React.PointerEvent<HTMLDivElement>,\n split: TabGroupsSplit,\n index: number,\n key: string\n ): void => {\n if (event.pointerType === \"mouse\" && event.button !== 0) return;\n const orientation: \"vertical\" | \"horizontal\" = split.direction === \"row\" ? \"vertical\" : \"horizontal\";\n const axis = orientation === \"vertical\" ? \"x\" : \"y\";\n const { extentPx, minPercent } = splitScale(split, axis);\n resizeRef.current = {\n split: split.id,\n index,\n axis,\n pointerId: event.pointerId,\n start: axis === \"x\" ? event.clientX : event.clientY,\n extentPx,\n minPercent,\n layout: latestRef.current,\n };\n setDragSeparator({ key, orientation });\n const target = event.currentTarget;\n // With the pointer captured the drag keeps reporting to the grip, however fast it moves.\n if (typeof target.setPointerCapture === \"function\") {\n try {\n target.setPointerCapture(event.pointerId);\n } catch {\n // jsdom has no pointer capture, and a pointer that is already gone refuses it.\n }\n }\n };\n\n const onSeparatorPointerMove = (event: React.PointerEvent<HTMLDivElement>): void => {\n const drag = resizeRef.current;\n // Another finger on the grip does not move it.\n if (!drag || drag.pointerId !== event.pointerId) return;\n resizeThrottled(drag.axis === \"x\" ? event.clientX : event.clientY);\n };\n\n const endSeparatorDrag = (event: React.PointerEvent<HTMLDivElement>): void => {\n if (resizeRef.current?.pointerId !== event.pointerId) return;\n resizeRef.current = null;\n resizeThrottled.cancel();\n setDragSeparator(null);\n };\n\n const onSeparatorKeyDown = (\n event: React.KeyboardEvent<HTMLDivElement>,\n split: TabGroupsSplit,\n index: number\n ): void => {\n if (event.defaultPrevented) return;\n const vertical = split.direction === \"row\";\n let delta: number;\n if (event.key === (vertical ? \"ArrowLeft\" : \"ArrowUp\")) delta = -keyboardStep;\n else if (event.key === (vertical ? \"ArrowRight\" : \"ArrowDown\")) delta = keyboardStep;\n else if (event.key === \"Home\") delta = -Infinity;\n else if (event.key === \"End\") delta = Infinity;\n else return;\n event.preventDefault();\n const { minPercent } = splitScale(split, vertical ? \"x\" : \"y\");\n resize(split.id, index, delta, minPercent);\n };\n\n // ---- Drag and drop ----\n\n /** What is under the pointer during a drag: a group's tab row, a group's body, or nothing of ours. */\n const hitTest = (\n event: React.DragEvent\n ):\n | { kind: \"row\"; group: string; index: number | null; item: HTMLElement | null }\n | { kind: \"body\"; group: string; element: HTMLElement }\n | null => {\n const root = rootRef.current;\n const target = event.target as HTMLElement | null;\n // A drag of another instance's, or of a nested one: not ours to answer for.\n if (!root || !target || target.closest(\".smwb-tab-groups\") !== root) return null;\n const header = target.closest<HTMLElement>(\".smwb-tab-groups__header\");\n if (header) {\n const group = header.getAttribute(\"data-group-id\");\n if (!group) return null;\n const tabElement = tabElementOf(target);\n const overId = tabElement?.getAttribute(\"data-tab-id\") ?? null;\n const tabs = groupsById.get(group)?.tabs ?? [];\n const at = overId === null ? -1 : tabs.indexOf(overId);\n return {\n kind: \"row\",\n group,\n index: at >= 0 ? at : null,\n item: at >= 0 && tabElement ? tabItemOf(tabElement) : null,\n };\n }\n const body = target.closest<HTMLElement>(\".smwb-tab-groups__drop-target\");\n if (!body) return null;\n const group = body.getAttribute(\"data-group-id\");\n return group ? { kind: \"body\", group, element: body } : null;\n };\n\n /** The zone of a group's body the pointer is in: an edge within a quarter of it, else the centre. */\n const zoneOf = (element: HTMLElement, event: React.DragEvent): TabGroupsDropZone => {\n const rect = element.getBoundingClientRect();\n return dropZoneAt(event.clientX - rect.left, event.clientY - rect.top, rect.width, rect.height);\n };\n\n /**\n * Whether a body drop would do anything: the source group's own centre is a no-op, and so is its\n * own edge when it has one tab (a split needs a tab to leave behind). Without `preventDefault`\n * on `dragover` the cursor says \"not allowed\" and the drop does nothing.\n */\n const bodyDropAllowed = (dragGroup: string, group: string, zone: TabGroupsDropZone): boolean => {\n if (dragGroup !== group) return true;\n if (zone === \"center\") return false;\n return (groupsById.get(group)?.tabs.length ?? 0) >= 2;\n };\n\n const markRowItem = (item: HTMLElement | null): void => {\n if (rowMarkRef.current === item) return;\n rowMarkRef.current?.classList.remove(\"smwb-tab-item--drop-target\");\n rowMarkRef.current = item;\n item?.classList.add(\"smwb-tab-item--drop-target\");\n };\n\n /**\n * `Tabs` marks the item under the pointer in the row a drag started in, and keeps that mark when\n * the pointer leaves the row: over another group it would be a second, stale insertion line. It is\n * taken off while the pointer is anywhere else, and put back when the pointer returns — `Tabs`\n * marks an item again only when the item under the pointer changes.\n */\n const hideSourceRowMark = (): void => {\n const drag = dragRef.current;\n const header = Array.from(\n rootRef.current?.querySelectorAll<HTMLElement>(\":scope > .smwb-tab-groups__header\") ?? []\n ).find((element) => element.getAttribute(\"data-group-id\") === drag?.group);\n header?.querySelectorAll<HTMLElement>(\".smwb-tab-item--drop-target\").forEach((item) => {\n if (item !== rowMarkRef.current) item.classList.remove(\"smwb-tab-item--drop-target\");\n });\n };\n\n const clearDrag = (): void => {\n dragRef.current = null;\n if (frameRef.current) {\n frameRef.current.view.cancelAnimationFrame(frameRef.current.id);\n frameRef.current = null;\n }\n markRowItem(null);\n setDragging(false);\n setDropTarget(null);\n };\n\n const onRootDragStart = (event: React.DragEvent<HTMLDivElement>): void => {\n onDragStart?.(event);\n const root = rootRef.current;\n const target = event.target as HTMLElement | null;\n if (!root || !target || target.closest(\".smwb-tab-groups\") !== root) return;\n // The drag's source node is the item wrapper `Tabs` made draggable, so the tab is read from\n // inside it, not from the event target's ancestors.\n const tabElement = tabElementOf(target);\n const tabId = tabElement?.getAttribute(\"data-tab-id\");\n // A disabled tab is not draggable (`Tabs` leaves it alone), and neither is anything that is not a tab.\n if (!tabElement || !tabId || tabElement.getAttribute(\"aria-disabled\") === \"true\") return;\n const group = groupIdOf(tabElement);\n if (!group) return;\n const doc = root.ownerDocument;\n const active = doc.activeElement;\n dragRef.current = {\n tab: tabId,\n group,\n hadFocus: Boolean(active && active !== doc.body && tabItemOf(tabElement).contains(active)),\n };\n const view = doc.defaultView;\n if (!view) return;\n const id = view.requestAnimationFrame(() => {\n frameRef.current = null;\n setDragging(true);\n });\n frameRef.current = { view, id };\n };\n\n const onRootDragOver = (event: React.DragEvent<HTMLDivElement>): void => {\n onDragOver?.(event);\n if (!dragRef.current) return;\n const hit = hitTest(event);\n if (!hit) {\n markRowItem(null);\n hideSourceRowMark();\n setDropTarget(null);\n return;\n }\n if (hit.kind === \"row\") {\n // A drop on its own row is `Tabs`' (it reorders there and swallows the drop).\n if (hit.group === dragRef.current.group) {\n // Back over its own row: another row's mark goes, this one is `Tabs`' again.\n markRowItem(null);\n hit.item?.classList.add(\"smwb-tab-item--drop-target\");\n return;\n }\n hideSourceRowMark();\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = \"move\";\n setDropTarget(null);\n markRowItem(hit.item);\n return;\n }\n markRowItem(null);\n hideSourceRowMark();\n const zone = zoneOf(hit.element, event);\n // No `preventDefault` where a drop would do nothing, so the cursor says \"not allowed\".\n if (!bodyDropAllowed(dragRef.current.group, hit.group, zone)) {\n setDropTarget(null);\n return;\n }\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = \"move\";\n setDropTarget((previous) =>\n previous && previous.group === hit.group && previous.zone === zone ? previous : { group: hit.group, zone }\n );\n };\n\n const onRootDrop = (event: React.DragEvent<HTMLDivElement>): void => {\n onDrop?.(event);\n const drag = dragRef.current;\n if (!drag) return;\n // `Tabs` prevents the default of a drop on its own row: that one is its reorder, already reported.\n const hit = event.defaultPrevented ? null : hitTest(event);\n const zone = hit && hit.kind === \"body\" ? zoneOf(hit.element, event) : null;\n clearDrag();\n if (!hit) return;\n if (hit.kind === \"row\") {\n if (hit.group === drag.group) return;\n moveTo(\n drag.tab,\n hit.index === null ? { group: hit.group } : { group: hit.group, index: hit.index },\n drag.hadFocus\n );\n return;\n }\n if (!zone || !bodyDropAllowed(drag.group, hit.group, zone)) return;\n moveTo(drag.tab, zone === \"center\" ? { group: hit.group } : { group: hit.group, edge: zone }, drag.hadFocus);\n };\n\n const onRootDragEnd = (event: React.DragEvent<HTMLDivElement>): void => {\n onDragEnd?.(event);\n clearDrag();\n };\n\n // ---- Groups ----\n\n const onGroupChange = (group: TabGroupsGroup, event: React.MouseEvent<HTMLButtonElement>, index: number): void => {\n // A drop of the selected tab reports its new index through `onChange` as well; selection goes\n // by id and is already right, and that index counts the row it was dropped into.\n if (event.type === \"drop\") return;\n const tabId = group.tabs[index];\n if (tabId === undefined) return;\n select(tabId);\n };\n\n const onGroupReorder = (group: TabGroupsGroup, from: number, to: number): void => {\n const tabId = group.tabs[from];\n if (tabId === undefined) return;\n moveTo(tabId, { group: group.id, index: to }, dragRef.current?.hadFocus ?? false);\n };\n\n /** The chords of a group's header, on the tab that has focus. Best-effort, as `Tabs`' own are. */\n const onHeaderKeyDown =\n (group: TabGroupsGroup) =>\n (event: React.KeyboardEvent<HTMLDivElement>): void => {\n if (event.defaultPrevented || event.repeat || event.nativeEvent.isComposing) return;\n const target = event.target as HTMLElement | null;\n const tabElement = target?.closest<HTMLElement>('[role=\"tab\"]');\n if (!tabElement || groupIdOf(tabElement) !== group.id) return;\n if (tabElement.getAttribute(\"aria-disabled\") === \"true\") return;\n const tabId = tabElement.getAttribute(\"data-tab-id\");\n if (!tabId) return;\n const edge: TabGroupsEdge | undefined = matchesKeyboardShortcut(event, [\"Alt\", \"Shift\", \"ArrowLeft\"])\n ? \"left\"\n : matchesKeyboardShortcut(event, [\"Alt\", \"Shift\", \"ArrowRight\"])\n ? \"right\"\n : matchesKeyboardShortcut(event, [\"Alt\", \"Shift\", \"ArrowUp\"])\n ? \"top\"\n : matchesKeyboardShortcut(event, [\"Alt\", \"Shift\", \"ArrowDown\"])\n ? \"bottom\"\n : undefined;\n if (edge !== undefined) {\n // Not prevented when nothing can move: the key belongs to whatever else listens.\n if (moveInDirection(tabId, edge)) event.preventDefault();\n return;\n }\n if (matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"ArrowLeft\"])) {\n if (moveInRow(tabId, -1)) event.preventDefault();\n return;\n }\n if (matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"ArrowRight\"])) {\n if (moveInRow(tabId, 1)) event.preventDefault();\n }\n };\n\n const openMenu = (groupId: string, trigger: HTMLElement, focus: boolean): void => {\n setMenuAnchor(trigger);\n setMenuGroup(groupId);\n if (focus) setMenuFocusRequest((count) => count + 1);\n };\n\n const onTriggerClick = (groupId: string, event: React.MouseEvent<HTMLButtonElement>): void => {\n if (menuGroup === groupId) {\n setMenuGroup(null);\n return;\n }\n // A click synthesized from Enter or Space carries no detail: the keyboard opens into the menu.\n openMenu(groupId, event.currentTarget, event.detail === 0);\n };\n\n const onTriggerKeyDown = (groupId: string, event: React.KeyboardEvent<HTMLButtonElement>): void => {\n if (event.defaultPrevented || event.repeat || event.key !== \"ArrowDown\") return;\n event.preventDefault();\n openMenu(groupId, event.currentTarget, true);\n };\n\n /** The menu's entries, in the order the keyboard table lists them; each acts on the group's selected tab. */\n const menuEntries = (\n group: TabGroupsGroup,\n index: number\n ): { key: string; label: string; disabled: boolean; run: () => void }[] => {\n const active = group.active;\n const count = group.tabs.length;\n const position = active ? group.tabs.indexOf(active) : -1;\n const previous = groups[index - 1];\n const next = groups[index + 1];\n const act = (run: (tabId: string) => void) => () => {\n if (active) run(active);\n };\n return [\n {\n key: \"split-right\",\n label: labels.splitRight,\n // A split moves the group's selected tab out of it, so it takes two tabs to leave one behind.\n disabled: !active || count < 2,\n run: act((tabId) => moveTo(tabId, { group: group.id, edge: \"right\" })),\n },\n {\n key: \"split-down\",\n label: labels.splitDown,\n disabled: !active || count < 2,\n run: act((tabId) => moveTo(tabId, { group: group.id, edge: \"bottom\" })),\n },\n {\n key: \"previous-group\",\n label: labels.moveToPreviousGroup,\n disabled: !active || !previous,\n run: act((tabId) => {\n if (previous) moveTo(tabId, { group: previous.id });\n }),\n },\n {\n key: \"next-group\",\n label: labels.moveToNextGroup,\n disabled: !active || !next,\n run: act((tabId) => {\n if (next) moveTo(tabId, { group: next.id });\n }),\n },\n {\n key: \"move-left\",\n label: labels.moveLeft,\n disabled: !active || position <= 0,\n run: act((tabId) => moveInRow(tabId, -1)),\n },\n {\n key: \"move-right\",\n label: labels.moveRight,\n disabled: !active || position < 0 || position >= count - 1,\n run: act((tabId) => moveInRow(tabId, 1)),\n },\n ];\n };\n\n // ---- Render ----\n\n const renderTab = (tabId: string): React.ReactNode => {\n const tab = getTab(tabId);\n const disabled = tab?.disabled === true;\n const encoded = encodeURIComponent(tabId);\n return (\n <Tab\n key={tabId}\n id={`${base}-tab-${encoded}`}\n aria-controls={`${base}-panel-${encoded}`}\n aria-keyshortcuts={disabled ? undefined : KEY_SHORTCUTS}\n data-tab-id={tabId}\n label={tab?.label ?? tabId}\n icon={tab?.icon}\n closable={tab?.closable ?? true}\n closeLabel={tab?.closeLabel}\n actions={tab?.actions}\n disabled={tab?.disabled}\n onClose={(event, reason) => requestClose(tabId, event, reason)}\n />\n );\n };\n\n const renderHeader = (group: TabGroupsGroup, index: number): React.ReactNode => {\n const menuId = `${base}-menu-${encodeURIComponent(group.id)}`;\n const open = menuGroup === group.id;\n const activeIndex = group.active ? Math.max(0, group.tabs.indexOf(group.active)) : 0;\n return (\n <div\n key={`h:${group.id}`}\n id={headerElementId(group.id)}\n className={cn(\"smwb-tab-groups__header\", {\n \"smwb-tab-groups__header--active\": layout.activeGroup === group.id,\n })}\n data-group-id={group.id}\n style={headerStyle(group.id)}\n onKeyDown={onHeaderKeyDown(group)}\n >\n <Tabs\n className=\"smwb-tab-groups__tabs\"\n value={activeIndex}\n onChange={(event, next) => onGroupChange(group, event, next)}\n onReorder={(from, to) => onGroupReorder(group, from, to)}\n dense={dense}\n scrollable\n overflowMenu\n aria-label={labels.group(index + 1, groups.length)}\n >\n {group.tabs.map(renderTab)}\n </Tabs>\n {groupActions && (\n <>\n <button\n type=\"button\"\n className=\"smwb-tab-groups__actions-trigger\"\n aria-label={labels.groupActions}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? menuId : undefined}\n onClick={(event) => onTriggerClick(group.id, event)}\n onKeyDown={(event) => onTriggerKeyDown(group.id, event)}\n >\n <Icon name=\"more_vert\" size={20} />\n </button>\n <Menu\n id={menuId}\n anchorElement={menuAnchor}\n isOpen={open}\n onClose={() => setMenuGroup(null)}\n placement=\"bottom-end\"\n >\n {menuEntries(group, index).map((entry) => (\n <MenuItem\n key={entry.key}\n disabled={entry.disabled}\n onClick={() => {\n setMenuGroup(null);\n entry.run();\n }}\n >\n {entry.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n )}\n </div>\n );\n };\n\n const renderPanelNode = (tabId: string): React.ReactNode => {\n const group = groupOfTab.get(tabId);\n if (!group) return null;\n const encoded = encodeURIComponent(tabId);\n return (\n <div\n key={`p:${tabId}`}\n id={panelElementId(tabId)}\n className=\"smwb-tab-panel smwb-tab-groups__panel\"\n role=\"tabpanel\"\n aria-labelledby={`${base}-tab-${encoded}`}\n // A panel is a tab stop of its own, so Tab leaves the row for the content it shows.\n tabIndex={0}\n hidden={group.active !== tabId}\n data-tab-id={tabId}\n data-group-id={group.id}\n style={bodyStyle(group.id)}\n >\n {mounted.has(tabId) ? renderPanel(tabId) : null}\n {/* Where Shift+Tab enters the panel from the next child in reading order: the browser's\n own move from here lands on the panel's last stop (`tabMove`). */}\n {mounted.has(tabId) ? <span className=\"smwb-tab-groups__panel-end\" tabIndex={-1} aria-hidden=\"true\" /> : null}\n </div>\n );\n };\n\n const renderSeparator = (split: TabGroupsSplit, index: number): React.ReactNode => {\n const key = `s:${split.id}:${index}`;\n const entry = gridSeparators.get(`${split.id}:${index}`);\n const orientation = entry?.orientation ?? (split.direction === \"row\" ? \"vertical\" : \"horizontal\");\n return (\n <div\n key={key}\n id={separatorElementId(split.id, index)}\n className={cn(\"smwb-tab-groups__separator\", `smwb-tab-groups__separator--${orientation}`, {\n \"smwb-tab-groups__separator--dragging\": dragSeparator?.key === key,\n })}\n role=\"separator\"\n tabIndex={0}\n aria-orientation={orientation}\n aria-valuenow={pairValue(split, index)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={labels.resize}\n data-split-id={split.id}\n data-index={index}\n style={entry ? { gridArea: separatorArea(entry) } : undefined}\n onKeyDown={(event) => onSeparatorKeyDown(event, split, index)}\n onPointerDown={(event) => onSeparatorPointerDown(event, split, index, key)}\n onPointerMove={onSeparatorPointerMove}\n onPointerUp={endSeparatorDrag}\n onPointerCancel={endSeparatorDrag}\n />\n );\n };\n\n // The grid's children: the headers in reading order, the separators, then the panels in the\n // order they first appeared (`panelOrder`). Each is placed by its `grid-area` alone, so splitting\n // an area or moving a tab remounts nothing and moves no panel in the DOM; the keyed groups keep\n // React from reordering one list against another. Tab order and the accessibility tree follow the\n // reading order all the same: `onRootKeyDown` and the root's `aria-owns`.\n const separators: React.ReactNode[] = [];\n const collectSeparators = (node: TabGroupsNode): void => {\n if (node.type === \"group\") return;\n node.children.forEach((child, index) => {\n collectSeparators(child);\n if (index < node.children.length - 1) separators.push(renderSeparator(node, index));\n });\n };\n\n const isEmpty = groups.length === 1 && (groups[0]?.tabs.length ?? 0) === 0;\n let owns: string | undefined;\n if (!isEmpty) {\n collectSeparators(layout.root);\n owns = [\n ...readingKeys(layout.root).flatMap((key) => {\n if (key.startsWith(\"h:\")) return [headerElementId(key.slice(2))];\n if (key.startsWith(\"p:\")) return (groupsById.get(key.slice(2))?.tabs ?? []).map(panelElementId);\n const last = key.lastIndexOf(\":\");\n return [separatorElementId(key.slice(2, last), Number(key.slice(last + 1)))];\n }),\n `${base}-status`,\n ].join(\" \");\n }\n return (\n <div\n {...rest}\n id={base}\n ref={forkedRef}\n className={cn(\"smwb-tab-groups\", { \"smwb-tab-groups--split\": groups.length > 1 }, className)}\n data-testid={dataTestId}\n // The caller's style is kept; the tracks the layout needs win over it.\n style={{ ...style, gridTemplateColumns: gridTemplateColumns(grid), gridTemplateRows: gridTemplateRows(grid) }}\n aria-owns={owns}\n onFocus={onRootFocus}\n onKeyDown={onRootKeyDown}\n onDragStart={onRootDragStart}\n onDragOver={onRootDragOver}\n onDrop={onRootDrop}\n onDragEnd={onRootDragEnd}\n >\n {isEmpty ? (\n <div className=\"smwb-tab-groups__empty\">{empty}</div>\n ) : (\n <>\n <React.Fragment key=\"headers\">{groups.map(renderHeader)}</React.Fragment>\n <React.Fragment key=\"separators\">{separators}</React.Fragment>\n <React.Fragment key=\"panels\">{panelOrder.map(renderPanelNode)}</React.Fragment>\n {/* The zones a dragged tab can land in, one per group, above the panels so that an iframe\n in one cannot swallow `dragover`. Drawn only while a drag of this instance runs. */}\n <React.Fragment key=\"drop-targets\">\n {dragging &&\n groups.map((group) => {\n const zone = dropTarget?.group === group.id ? dropTarget.zone : undefined;\n return (\n <div\n key={`d:${group.id}`}\n className={cn(\"smwb-tab-groups__drop-target\", zone && `smwb-tab-groups__drop-target--${zone}`)}\n data-group-id={group.id}\n aria-hidden=\"true\"\n style={bodyStyle(group.id)}\n />\n );\n })}\n </React.Fragment>\n {/* The root's last Tab stop, which only ever holds the focus on its way in or out. */}\n <span\n ref={guardRef}\n className=\"smwb-tab-groups__focus-guard\"\n tabIndex={0}\n onBlur={() => {\n leavingRef.current = false;\n }}\n />\n </>\n )}\n <div\n id={`${base}-status`}\n className=\"smwb-tab-groups__status\"\n role=\"status\"\n aria-atomic=\"true\"\n data-testid=\"tab-groups-status\"\n >\n {status}\n </div>\n </div>\n );\n});\n"],"names":["FIRST_MENU_ITEM","EMPTY_LAYOUT","createTabGroupsLayout","KEY_SHORTCUTS","groupIdOf","node","current","id","tabItemOf","tab","_a","tabElementOf","target","item","findSplit","child","found","groupIdsOf","trackStarts","tracks","starts","size","index","pairValue","split","first","pair","_b","hasGroup","layout","groupId","getGroups","group","readingKeys","root","keys","walk","moveChange","before","after","tabId","edge","from","findGroupOfTab","to","sourceClosed","TabGroups","React","props","ref","layoutProp","defaultLayout","onLayoutChange","getTab","renderPanel","onTabClose","empty","minGroupSize","keyboardStep","groupActions","dense","labelsProp","idProp","className","style","dataTestId","onFocus","onKeyDown","onDragStart","onDragOver","onDrop","onDragEnd","rest","base","useId","headerElementId","panelElementId","separatorElementId","splitId","rootRef","forkedRef","useForkRef","setLayout","useControllableState","latestRef","renderedRef","controlledRef","settleQueuedRef","labels","TAB_GROUPS_LABELS","status","setStatus","pendingFocusRef","reportedRef","reportCountRef","leavingRef","guardRef","lastFocusRef","pointerFocusRef","dragRef","frameRef","rowMarkRef","dragging","setDragging","dropTarget","setDropTarget","resizeRef","dragSeparator","setDragSeparator","menuGroup","setMenuGroup","menuAnchor","setMenuAnchor","menuFocusRequest","setMenuFocusRequest","groups","grid","computeTabGroupsGrid","groupsById","gridGroupsById","entry","gridSeparators","columnStarts","rowStarts","mountedRef","mounted","known","panelOrderRef","panelOrder","placed","groupOfTab","titleOf","useEventCallback","commit","next","change","text","describeTabGroupsChange","previous","settle","armFocus","gone","doc","deepActiveElement","moveTo","focus","moveTab","moveInDirection","moveTabInDirection","moveInRow","delta","select","selectTab","resize","minPercent","resizeSplit","requestClose","event","reason","removeTab","groupClosed","active","focusWasHere","ownGroupIdOf","neighbourId","adjacentGroup","neighbour","onRootFocus","ownerRootOf","instead","frameExitTarget","onGuardFocus","setActiveGroup","onRootKeyDown","containsDeep","move","tabMove","view","timer","onPointerDown","onFocusOut","onWindowBlur","last","lastStopOf","stillWaiting","pending","drawn","drawnAt","askedAt","focusPending","element","useSafeLayoutEffect","trigger","_c","body","splitExtentPercent","axis","a","b","splitScale","rect","extentPx","headerStyle","groupHeaderArea","bodyStyle","groupBodyArea","resizeThrottled","throttle","position","drag","onSeparatorPointerDown","key","orientation","onSeparatorPointerMove","endSeparatorDrag","onSeparatorKeyDown","vertical","hitTest","header","tabElement","overId","tabs","at","zoneOf","dropZoneAt","bodyDropAllowed","dragGroup","zone","markRowItem","hideSourceRowMark","clearDrag","onRootDragStart","onRootDragOver","hit","onRootDrop","onRootDragEnd","onGroupChange","onGroupReorder","onHeaderKeyDown","matchesKeyboardShortcut","openMenu","count","onTriggerClick","onTriggerKeyDown","menuEntries","act","run","renderTab","disabled","encoded","jsx","Tab","renderHeader","menuId","open","activeIndex","jsxs","cn","Tabs","Fragment","Icon","Menu","MenuItem","renderPanelNode","renderSeparator","separatorArea","separators","collectSeparators","isEmpty","owns","gridTemplateColumns","gridTemplateRows"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The Tab order of `TabGroups`, read from the DOM alone: no framework here, and the file is a
3
+ * byte-identical copy in ui-react and ui-solid.
4
+ *
5
+ * The root keeps its panels in the DOM in the order they first appeared, so the DOM order of its
6
+ * children is not the reading order; the root's `aria-owns` lists them in reading order. Inside one
7
+ * child — a header, a panel, a separator — DOM order is reading order, so there the browser moves
8
+ * the focus itself, with every rule of its own (a radio group is one stop, a frame is entered at
9
+ * its first or its last stop, a shadow tree is walked in place). Only a press that would leave a
10
+ * child is taken over: it goes to the next child in reading order, to the stop the browser would
11
+ * pick there by the same rules. A `TabGroups` nested in a panel is that panel's content: its own
12
+ * root answers for the moves inside it, first.
13
+ */
14
+ /** A browser's move of the Tab key, taken over: focus `element`, then stop there (`prevent`) or let the browser go on from it. */
15
+ export interface TabGroupsTabMove {
16
+ element: HTMLElement;
17
+ prevent: boolean;
18
+ }
19
+ /** Whether `node` is `ancestor` or inside it, shadow trees included. */
20
+ export declare function containsDeep(ancestor: Node, node: Node | null): boolean;
21
+ /** The element that has the focus, inside shadow trees too: where the browser's Tab starts from. */
22
+ export declare function deepActiveElement(doc: Document): Element | null;
23
+ /** The `TabGroups` root a node is in: the nearest one around it, or the node itself when it is one. */
24
+ export declare function ownerRootOf(node: Node | null): HTMLElement | null;
25
+ /** The child of `root` a node is in — a header, a panel, a separator, the guard — or null. */
26
+ export declare function rootChildOf(root: Element, node: Node | null): HTMLElement | null;
27
+ /** The group a node is in, told by the root's own child: a nested `TabGroups`' groups are not this root's. */
28
+ export declare function ownGroupIdOf(root: Element, node: Node | null): string | null;
29
+ /** The root's guard, its last Tab stop, which only holds the focus on its way in or out. */
30
+ export declare function guardOf(root: HTMLElement): HTMLElement | null;
31
+ /** The root's headers, shown panels and separators in reading order, as its `aria-owns` lists them. */
32
+ export declare function readingChildren(root: HTMLElement): HTMLElement[];
33
+ /**
34
+ * What the Tab key (step 1) or Shift+Tab (step -1) does from `from`, the focused element in
35
+ * `root`: null when the browser's own move is right — inside a child, or out of the root before
36
+ * its first stop. At the end of the reading order the focus leaves through the guard, and the
37
+ * browser moves on past the root from there.
38
+ */
39
+ export declare function tabMove(root: HTMLElement, from: Element, step: 1 | -1): TabGroupsTabMove | null;
40
+ /** The last stop of the reading order, where Shift+Tab from after the root goes. */
41
+ export declare function lastStopOf(root: HTMLElement): HTMLElement | undefined;
42
+ /**
43
+ * Focuses a stop that is reached backwards: a frame whose document can be read (the same origin)
44
+ * at its own last stop, as the browser's Shift+Tab would; another frame as a whole.
45
+ */
46
+ export declare function focusFromEnd(element: HTMLElement): void;
47
+ /**
48
+ * Where the focus belongs after the browser's Tab took it out of `frame`, an iframe of this root,
49
+ * onto `landed`. Inside a frame the keys are its own, so the browser left it by DOM order: to
50
+ * another child of the root, or to the guard, when the frame ended its child. The next child in
51
+ * reading order takes the focus instead, or after the last one whatever follows the root; with
52
+ * nothing there the guard holds the focus (it is returned), and the next Tab leaves the page.
53
+ * Null when the browser's move was right.
54
+ */
55
+ export declare function frameExitTarget(root: HTMLElement, frame: Element, landed: Element): HTMLElement | null;
@@ -0,0 +1,199 @@
1
+ const A = "smwb-tab-groups", x = ":scope > .smwb-tab-groups__focus-guard", N = ":scope > .smwb-tab-groups__panel-end", D = ".smwb-tab-groups__header, .smwb-tab-groups__panel, .smwb-tab-groups__separator", w = 'a[href], area[href], button, input, select, textarea, iframe, summary, audio[controls], video[controls], [contenteditable]:not([contenteditable="false"]), [tabindex]';
2
+ function l(t) {
3
+ if (t.parentElement) return t.parentElement;
4
+ const n = t.parentNode;
5
+ return (n == null ? void 0 : n.nodeType) === 11 && n.host ? n.host : null;
6
+ }
7
+ function E(t) {
8
+ return t ? t.nodeType === 1 ? t : l(t) : null;
9
+ }
10
+ function C(t, n) {
11
+ for (let e = n; e; e = l(e))
12
+ if (e === t) return !0;
13
+ return !1;
14
+ }
15
+ function H(t) {
16
+ var e;
17
+ let n = t.activeElement;
18
+ for (; (e = n == null ? void 0 : n.shadowRoot) != null && e.activeElement; ) n = n.shadowRoot.activeElement;
19
+ return n;
20
+ }
21
+ function k(t) {
22
+ for (let n = E(t); n; n = l(n))
23
+ if (n.classList.contains(A)) return n;
24
+ return null;
25
+ }
26
+ function s(t, n) {
27
+ let e = E(n);
28
+ for (; e && l(e) !== t; ) e = l(e);
29
+ return e;
30
+ }
31
+ function P(t, n) {
32
+ var e, o;
33
+ return (o = (e = s(t, n)) == null ? void 0 : e.getAttribute("data-group-id")) != null ? o : null;
34
+ }
35
+ function O(t) {
36
+ return t.querySelector(x);
37
+ }
38
+ function a(t) {
39
+ var e;
40
+ const n = t.ownerDocument;
41
+ return ((e = t.getAttribute("aria-owns")) != null ? e : "").split(/\s+/).flatMap((o) => {
42
+ const r = o ? n.getElementById(o) : null;
43
+ return r && r.parentElement === t && !r.hidden && r.matches(D) ? [r] : [];
44
+ });
45
+ }
46
+ function L(t) {
47
+ return typeof t.checkVisibility != "function" || t.checkVisibility({ visibilityProperty: !0 });
48
+ }
49
+ function v(t) {
50
+ const n = t.tabIndex;
51
+ return typeof n == "number" ? n : -1;
52
+ }
53
+ function I(t) {
54
+ var o;
55
+ if (t.scrollHeight <= t.clientHeight && t.scrollWidth <= t.clientWidth) return !1;
56
+ const n = (o = t.ownerDocument.defaultView) == null ? void 0 : o.getComputedStyle(t), e = (r) => r === "auto" || r === "scroll";
57
+ return !!(n && (e(n.overflowY) || e(n.overflowX)) && !t.querySelector(w));
58
+ }
59
+ function T(t) {
60
+ return t.matches(w) ? v(t) !== 0 || t.matches(":disabled") || t.localName === "input" && t.type === "hidden" ? !1 : L(t) : I(t);
61
+ }
62
+ function h(t) {
63
+ return t.localName === "input" && t.type === "radio";
64
+ }
65
+ function S(t, n) {
66
+ return t === n || t.name !== "" && t.name === n.name && t.form === n.form && t.getRootNode() === n.getRootNode();
67
+ }
68
+ function q(t) {
69
+ var o, r;
70
+ if (t.checked) return t;
71
+ if (t.name === "") return null;
72
+ const n = (o = t.form) != null ? o : t.getRootNode();
73
+ return (r = (t.form ? Array.from(t.form.elements) : Array.from(n.querySelectorAll("input"))).find(
74
+ (i) => h(i) && i.checked && S(t, i)
75
+ )) != null ? r : null;
76
+ }
77
+ function G(t, n) {
78
+ if (n && h(n) && S(n, t)) return !1;
79
+ const e = q(t);
80
+ return e === null || e === t;
81
+ }
82
+ function B(t) {
83
+ if (t.shadowRoot) return Array.from(t.shadowRoot.children);
84
+ if (t.localName === "slot") {
85
+ const n = t, e = typeof n.assignedElements == "function" ? n.assignedElements() : [];
86
+ if (e.length > 0) return e;
87
+ }
88
+ return Array.from(t.children);
89
+ }
90
+ function* p(t) {
91
+ yield t;
92
+ for (const n of B(t))
93
+ n.matches("[hidden], [inert]") || (yield* p(n));
94
+ }
95
+ function R(t, n) {
96
+ return T(t) && (!h(t) || G(t, n));
97
+ }
98
+ function d(t, n, e, o = !1) {
99
+ let r, i = !1;
100
+ for (const u of p(t)) {
101
+ if (u === n) {
102
+ if (e < 0) return r;
103
+ i = !0;
104
+ continue;
105
+ }
106
+ if (!(i && o && C(n, u)) && R(u, n)) {
107
+ if (i) return u;
108
+ r = u;
109
+ }
110
+ }
111
+ }
112
+ function m(t, n, e) {
113
+ let o;
114
+ for (const r of p(t))
115
+ if (R(r, e)) {
116
+ if (n > 0) return r;
117
+ o = r;
118
+ }
119
+ return o;
120
+ }
121
+ function f(t, n, e, o) {
122
+ for (let r = n; r >= 0 && r < t.length; r += e) {
123
+ const i = t[r], u = i ? m(i, e, o) : void 0;
124
+ if (!i || !u) continue;
125
+ const c = u.localName === "iframe" ? i.querySelector(N) : null;
126
+ return c ? { element: c, prevent: !1 } : { element: u, prevent: !0 };
127
+ }
128
+ return null;
129
+ }
130
+ function V(t, n, e) {
131
+ const o = O(t), r = a(t);
132
+ if (n === o) return e < 0 ? f(r, r.length - 1, -1, n) : null;
133
+ const i = s(t, n), u = i ? r.indexOf(i) : -1;
134
+ if (!i || u < 0 || v(n) > 0 || d(i, n, e)) return null;
135
+ const c = f(r, u + e, e, n);
136
+ return c || (e > 0 && o ? { element: o, prevent: !1 } : null);
137
+ }
138
+ function W(t) {
139
+ const n = a(t);
140
+ for (let e = n.length - 1; e >= 0; e -= 1) {
141
+ const o = n[e], r = o ? m(o, -1, null) : void 0;
142
+ if (r) return r;
143
+ }
144
+ }
145
+ function F(t) {
146
+ var n;
147
+ if (t.localName === "iframe") {
148
+ let e;
149
+ try {
150
+ e = (n = t.contentDocument) == null ? void 0 : n.body;
151
+ } catch {
152
+ e = null;
153
+ }
154
+ const o = e ? m(e, -1, null) : void 0;
155
+ if (o) {
156
+ F(o);
157
+ return;
158
+ }
159
+ }
160
+ t.focus();
161
+ }
162
+ function _(t) {
163
+ const n = k(l(t));
164
+ if (!n) {
165
+ const i = t.ownerDocument.body;
166
+ return i ? d(i, t, 1, !0) : void 0;
167
+ }
168
+ const e = s(n, t), o = a(n), r = e ? o.indexOf(e) : -1;
169
+ if (e && r >= 0) {
170
+ const i = d(e, t, 1, !0);
171
+ if (i) return i;
172
+ const u = f(o, r + 1, 1, null);
173
+ if (u) return u.element;
174
+ }
175
+ return _(n);
176
+ }
177
+ function M(t, n, e) {
178
+ var g, y, b;
179
+ const o = O(t), r = s(t, n);
180
+ if (!r || e !== o && s(t, e) === r || e !== o && !(n.compareDocumentPosition(e) & 4)) return null;
181
+ const i = a(t), u = i.indexOf(r);
182
+ if (u < 0) return null;
183
+ const c = (b = (y = (g = f(i, u + 1, 1, null)) == null ? void 0 : g.element) != null ? y : _(t)) != null ? b : o;
184
+ return c === e && e !== o ? null : c;
185
+ }
186
+ export {
187
+ C as containsDeep,
188
+ H as deepActiveElement,
189
+ F as focusFromEnd,
190
+ M as frameExitTarget,
191
+ O as guardOf,
192
+ W as lastStopOf,
193
+ P as ownGroupIdOf,
194
+ k as ownerRootOf,
195
+ a as readingChildren,
196
+ s as rootChildOf,
197
+ V as tabMove
198
+ };
199
+ //# sourceMappingURL=tabGroupsFocus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabGroupsFocus.js","sources":["../../../../src/components/layout/tabGroups/tabGroupsFocus.ts"],"sourcesContent":["/**\n * The Tab order of `TabGroups`, read from the DOM alone: no framework here, and the file is a\n * byte-identical copy in ui-react and ui-solid.\n *\n * The root keeps its panels in the DOM in the order they first appeared, so the DOM order of its\n * children is not the reading order; the root's `aria-owns` lists them in reading order. Inside one\n * child — a header, a panel, a separator — DOM order is reading order, so there the browser moves\n * the focus itself, with every rule of its own (a radio group is one stop, a frame is entered at\n * its first or its last stop, a shadow tree is walked in place). Only a press that would leave a\n * child is taken over: it goes to the next child in reading order, to the stop the browser would\n * pick there by the same rules. A `TabGroups` nested in a panel is that panel's content: its own\n * root answers for the moves inside it, first.\n */\n\nconst ROOT_CLASS = \"smwb-tab-groups\";\nconst GUARD_SELECTOR = \":scope > .smwb-tab-groups__focus-guard\";\nconst PANEL_END_SELECTOR = \":scope > .smwb-tab-groups__panel-end\";\nconst READING_CHILD = \".smwb-tab-groups__header, .smwb-tab-groups__panel, .smwb-tab-groups__separator\";\n\n/** What can take focus from the Tab key, as a browser decides it. */\nconst FOCUSABLE =\n 'a[href], area[href], button, input, select, textarea, iframe, summary, audio[controls], video[controls], [contenteditable]:not([contenteditable=\"false\"]), [tabindex]';\n\n/** A browser's move of the Tab key, taken over: focus `element`, then stop there (`prevent`) or let the browser go on from it. */\nexport interface TabGroupsTabMove {\n element: HTMLElement;\n prevent: boolean;\n}\n\n/** The parent of a node across a shadow root's boundary: the host. */\nfunction parentOf(node: Node): Element | null {\n if (node.parentElement) return node.parentElement;\n const parent = node.parentNode as (Node & { host?: Element }) | null;\n return parent?.nodeType === 11 && parent.host ? parent.host : null;\n}\n\nfunction elementOf(node: Node | null): Element | null {\n if (!node) return null;\n return node.nodeType === 1 ? (node as Element) : parentOf(node);\n}\n\n/** Whether `node` is `ancestor` or inside it, shadow trees included. */\nexport function containsDeep(ancestor: Node, node: Node | null): boolean {\n for (let current: Node | null = node; current; current = parentOf(current)) {\n if (current === ancestor) return true;\n }\n return false;\n}\n\n/** The element that has the focus, inside shadow trees too: where the browser's Tab starts from. */\nexport function deepActiveElement(doc: Document): Element | null {\n let active = doc.activeElement;\n while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;\n return active;\n}\n\n/** The `TabGroups` root a node is in: the nearest one around it, or the node itself when it is one. */\nexport function ownerRootOf(node: Node | null): HTMLElement | null {\n for (let current = elementOf(node); current; current = parentOf(current)) {\n if (current.classList.contains(ROOT_CLASS)) return current as HTMLElement;\n }\n return null;\n}\n\n/** The child of `root` a node is in — a header, a panel, a separator, the guard — or null. */\nexport function rootChildOf(root: Element, node: Node | null): HTMLElement | null {\n let current = elementOf(node);\n while (current && parentOf(current) !== root) current = parentOf(current);\n return current as HTMLElement | null;\n}\n\n/** The group a node is in, told by the root's own child: a nested `TabGroups`' groups are not this root's. */\nexport function ownGroupIdOf(root: Element, node: Node | null): string | null {\n return rootChildOf(root, node)?.getAttribute(\"data-group-id\") ?? null;\n}\n\n/** The root's guard, its last Tab stop, which only holds the focus on its way in or out. */\nexport function guardOf(root: HTMLElement): HTMLElement | null {\n return root.querySelector<HTMLElement>(GUARD_SELECTOR);\n}\n\n/** The root's headers, shown panels and separators in reading order, as its `aria-owns` lists them. */\nexport function readingChildren(root: HTMLElement): HTMLElement[] {\n const doc = root.ownerDocument;\n return (root.getAttribute(\"aria-owns\") ?? \"\").split(/\\s+/).flatMap((id) => {\n const element = id ? doc.getElementById(id) : null;\n return element && element.parentElement === root && !element.hidden && element.matches(READING_CHILD)\n ? [element]\n : [];\n });\n}\n\n/** Whether an element is drawn: a browser skips what is not (`display: none` from a stylesheet); jsdom draws nothing. */\nfunction isDrawn(element: Element): boolean {\n return typeof element.checkVisibility !== \"function\" || element.checkVisibility({ visibilityProperty: true });\n}\n\nfunction tabIndexOf(element: Element): number {\n const value = (element as Partial<HTMLElement>).tabIndex;\n return typeof value === \"number\" ? value : -1;\n}\n\n/** A scroller is a Tab stop of its own in Chromium when nothing inside it takes the focus. */\nfunction isScrollerStop(element: Element): boolean {\n if (element.scrollHeight <= element.clientHeight && element.scrollWidth <= element.clientWidth) return false;\n const style = element.ownerDocument.defaultView?.getComputedStyle(element);\n const scrolls = (value: string | undefined): boolean => value === \"auto\" || value === \"scroll\";\n return Boolean(style && (scrolls(style.overflowY) || scrolls(style.overflowX)) && !element.querySelector(FOCUSABLE));\n}\n\n/**\n * Whether the Tab key stops at an element, radio groups aside: focusable, in the sequence of\n * `tabindex` 0 (-1 is out of it, and above 0 the browser visits before everything else), enabled\n * and drawn — or a scroller with nothing focusable inside.\n */\nfunction isStop(element: Element): element is HTMLElement {\n if (element.matches(FOCUSABLE)) {\n if (tabIndexOf(element) !== 0 || element.matches(\":disabled\")) return false;\n if (element.localName === \"input\" && (element as HTMLInputElement).type === \"hidden\") return false;\n return isDrawn(element);\n }\n return isScrollerStop(element);\n}\n\nfunction isRadio(element: Element): element is HTMLInputElement {\n return element.localName === \"input\" && (element as HTMLInputElement).type === \"radio\";\n}\n\n/** Radios of one group: the same name (an unnamed radio is a group of its own), the same form, the same tree. */\nfunction sameGroup(a: HTMLInputElement, b: HTMLInputElement): boolean {\n return a === b || (a.name !== \"\" && a.name === b.name && a.form === b.form && a.getRootNode() === b.getRootNode());\n}\n\n/** The checked radio of a radio's group, wherever it is drawn, or null. */\nfunction checkedOf(radio: HTMLInputElement): HTMLInputElement | null {\n if (radio.checked) return radio;\n if (radio.name === \"\") return null;\n const scope = radio.form ?? (radio.getRootNode() as Document | ShadowRoot);\n const members: Element[] = radio.form ? Array.from(radio.form.elements) : Array.from(scope.querySelectorAll(\"input\"));\n return (\n members.find(\n (member): member is HTMLInputElement => isRadio(member) && member.checked && sameGroup(radio, member)\n ) ?? null\n );\n}\n\n/**\n * A radio group is one stop: its checked radio, or with none checked every radio of it (so the\n * first one going forwards, the last one going backwards), and none of the group the focus is in.\n */\nfunction isRadioStop(radio: HTMLInputElement, focused: Element | null): boolean {\n if (focused && isRadio(focused) && sameGroup(focused, radio)) return false;\n const checked = checkedOf(radio);\n return checked === null || checked === radio;\n}\n\n/** The element children a walk in the flat tree visits: a shadow root's instead of its host's, a slot's assigned ones. */\nfunction childrenOf(element: Element): Element[] {\n if (element.shadowRoot) return Array.from(element.shadowRoot.children);\n if (element.localName === \"slot\") {\n const slot = element as HTMLSlotElement;\n const assigned = typeof slot.assignedElements === \"function\" ? slot.assignedElements() : [];\n if (assigned.length > 0) return assigned;\n }\n return Array.from(element.children);\n}\n\n/** An element and everything under it in flat-tree order, without what is `hidden` or `inert`. */\nfunction* walk(element: Element): Generator<Element> {\n yield element;\n for (const child of childrenOf(element)) {\n if (!child.matches(\"[hidden], [inert]\")) yield* walk(child);\n }\n}\n\nfunction isStopFrom(element: Element, focused: Element | null): element is HTMLElement {\n return isStop(element) && (!isRadio(element) || isRadioStop(element, focused));\n}\n\n/**\n * The stop the Tab key goes to from `from` without leaving `container`, or undefined when it\n * would leave it. `past` starts after everything inside `from`, as from a nested root as a whole.\n */\nfunction stepWithin(container: Element, from: Element, step: 1 | -1, past = false): HTMLElement | undefined {\n let before: HTMLElement | undefined;\n let passed = false;\n for (const element of walk(container)) {\n if (element === from) {\n if (step < 0) return before;\n passed = true;\n continue;\n }\n if (passed && past && containsDeep(from, element)) continue;\n if (!isStopFrom(element, from)) continue;\n if (passed) return element;\n before = element;\n }\n return undefined;\n}\n\n/** The first stop inside a container (step 1) or the last one (step -1), the container itself included. */\nfunction edgeStop(container: Element, step: 1 | -1, focused: Element | null): HTMLElement | undefined {\n let last: HTMLElement | undefined;\n for (const element of walk(container)) {\n if (!isStopFrom(element, focused)) continue;\n if (step > 0) return element;\n last = element;\n }\n return last;\n}\n\n/**\n * Into the reading-order children from `index` on: the first stop of the first one that has one,\n * or going backwards the last stop. A frame that ends a panel is entered by the browser itself,\n * which lands on the frame's own last stop (whatever its origin): its panel's end marker takes the\n * focus, and the browser's move goes on from there.\n */\nfunction enter(children: HTMLElement[], index: number, step: 1 | -1, focused: Element | null): TabGroupsTabMove | null {\n for (let at = index; at >= 0 && at < children.length; at += step) {\n const child = children[at];\n const stop = child ? edgeStop(child, step, focused) : undefined;\n if (!child || !stop) continue;\n const end = stop.localName === \"iframe\" ? child.querySelector<HTMLElement>(PANEL_END_SELECTOR) : null;\n return end ? { element: end, prevent: false } : { element: stop, prevent: true };\n }\n return null;\n}\n\n/**\n * What the Tab key (step 1) or Shift+Tab (step -1) does from `from`, the focused element in\n * `root`: null when the browser's own move is right — inside a child, or out of the root before\n * its first stop. At the end of the reading order the focus leaves through the guard, and the\n * browser moves on past the root from there.\n */\nexport function tabMove(root: HTMLElement, from: Element, step: 1 | -1): TabGroupsTabMove | null {\n const guard = guardOf(root);\n const children = readingChildren(root);\n // The guard holds the focus (nothing followed a frame at the end): Shift+Tab goes back in.\n if (from === guard) return step < 0 ? enter(children, children.length - 1, -1, from) : null;\n const child = rootChildOf(root, from);\n const index = child ? children.indexOf(child) : -1;\n if (!child || index < 0 || tabIndexOf(from) > 0) return null;\n if (stepWithin(child, from, step)) return null;\n const entered = enter(children, index + step, step, from);\n if (entered) return entered;\n return step > 0 && guard ? { element: guard, prevent: false } : null;\n}\n\n/** The last stop of the reading order, where Shift+Tab from after the root goes. */\nexport function lastStopOf(root: HTMLElement): HTMLElement | undefined {\n const children = readingChildren(root);\n for (let at = children.length - 1; at >= 0; at -= 1) {\n const child = children[at];\n const stop = child ? edgeStop(child, -1, null) : undefined;\n if (stop) return stop;\n }\n return undefined;\n}\n\n/**\n * Focuses a stop that is reached backwards: a frame whose document can be read (the same origin)\n * at its own last stop, as the browser's Shift+Tab would; another frame as a whole.\n */\nexport function focusFromEnd(element: HTMLElement): void {\n if (element.localName === \"iframe\") {\n let body: HTMLElement | null | undefined;\n try {\n body = (element as HTMLIFrameElement).contentDocument?.body;\n } catch {\n body = null;\n }\n const last = body ? edgeStop(body, -1, null) : undefined;\n if (last) {\n focusFromEnd(last);\n return;\n }\n }\n element.focus();\n}\n\n/** The first stop after a whole root: on in the root around it, or in the page. */\nfunction stopAfter(root: HTMLElement): HTMLElement | undefined {\n const outer = ownerRootOf(parentOf(root));\n if (!outer) {\n const body = root.ownerDocument.body;\n return body ? stepWithin(body, root, 1, true) : undefined;\n }\n const child = rootChildOf(outer, root);\n const children = readingChildren(outer);\n const index = child ? children.indexOf(child) : -1;\n if (child && index >= 0) {\n const inside = stepWithin(child, root, 1, true);\n if (inside) return inside;\n const entered = enter(children, index + 1, 1, null);\n if (entered) return entered.element;\n }\n return stopAfter(outer);\n}\n\n/**\n * Where the focus belongs after the browser's Tab took it out of `frame`, an iframe of this root,\n * onto `landed`. Inside a frame the keys are its own, so the browser left it by DOM order: to\n * another child of the root, or to the guard, when the frame ended its child. The next child in\n * reading order takes the focus instead, or after the last one whatever follows the root; with\n * nothing there the guard holds the focus (it is returned), and the next Tab leaves the page.\n * Null when the browser's move was right.\n */\nexport function frameExitTarget(root: HTMLElement, frame: Element, landed: Element): HTMLElement | null {\n const guard = guardOf(root);\n const child = rootChildOf(root, frame);\n if (!child || (landed !== guard && rootChildOf(root, landed) === child)) return null;\n // Out of a frame backwards the browser stays in its child: the child itself is a stop before it.\n if (landed !== guard && !(frame.compareDocumentPosition(landed) & 4)) return null;\n const children = readingChildren(root);\n const index = children.indexOf(child);\n if (index < 0) return null;\n const wanted = enter(children, index + 1, 1, null)?.element ?? stopAfter(root) ?? guard;\n return wanted === landed && landed !== guard ? null : wanted;\n}\n"],"names":["ROOT_CLASS","GUARD_SELECTOR","PANEL_END_SELECTOR","READING_CHILD","FOCUSABLE","parentOf","node","parent","elementOf","containsDeep","ancestor","current","deepActiveElement","doc","_a","active","ownerRootOf","rootChildOf","root","ownGroupIdOf","_b","guardOf","readingChildren","id","element","isDrawn","tabIndexOf","value","isScrollerStop","style","scrolls","isStop","isRadio","sameGroup","a","b","checkedOf","radio","scope","member","isRadioStop","focused","checked","childrenOf","slot","assigned","walk","child","isStopFrom","stepWithin","container","from","step","past","before","passed","edgeStop","last","enter","children","index","at","stop","end","tabMove","guard","entered","lastStopOf","focusFromEnd","body","stopAfter","outer","inside","frameExitTarget","frame","landed","_c","wanted"],"mappings":"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"}