@smwb/ui-solid 1.0.0 → 2.1.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 (213) hide show
  1. package/README.md +115 -0
  2. package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
  3. package/dist/assets/styles/less/components/avatar/avatar.entry.css +1 -1
  4. package/dist/assets/styles/less/components/badge/badge.entry.css +1 -1
  5. package/dist/assets/styles/less/components/breadcrumbs/breadcrumbs.entry.css +1 -1
  6. package/dist/assets/styles/less/components/button/button.entry.css +1 -1
  7. package/dist/assets/styles/less/components/buttonGroup/buttonGroup.entry.css +1 -1
  8. package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -1
  9. package/dist/assets/styles/less/components/meter/meter.entry.css +1 -1
  10. package/dist/assets/styles/less/components/screenDivider/screenDivider.entry.css +1 -1
  11. package/dist/assets/styles/less/components/sheet/sheet.entry.css +1 -1
  12. package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -1
  13. package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -1
  14. package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
  15. package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
  16. package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
  17. package/dist/assets/styles/less/tokens.entry.css +1 -1
  18. package/dist/components/dataDisplay/avatar/avatar.d.ts +5 -2
  19. package/dist/components/dataDisplay/avatar/avatar.js +9 -9
  20. package/dist/components/dataDisplay/avatar/avatar.js.map +1 -1
  21. package/dist/components/dataDisplay/badge/badge.d.ts +2 -1
  22. package/dist/components/dataDisplay/badge/badge.js.map +1 -1
  23. package/dist/components/dataDisplay/chart/chart.d.ts +16 -8
  24. package/dist/components/dataDisplay/chart/chartFull.d.ts +14 -0
  25. package/dist/components/dataDisplay/chart/core.d.ts +19 -0
  26. package/dist/components/dataDisplay/chart/index.d.ts +1 -1
  27. package/dist/components/dataDisplay/dagView/dagView.d.ts +4 -0
  28. package/dist/components/dataDisplay/dagView/dagView.js +124 -123
  29. package/dist/components/dataDisplay/dagView/dagView.js.map +1 -1
  30. package/dist/components/dataDisplay/dagView/index.d.ts +1 -1
  31. package/dist/components/dataDisplay/meter/index.d.ts +1 -1
  32. package/dist/components/dataDisplay/meter/meter.d.ts +14 -0
  33. package/dist/components/dataDisplay/meter/meter.js +32 -30
  34. package/dist/components/dataDisplay/meter/meter.js.map +1 -1
  35. package/dist/components/dataDisplay/statusDot/index.d.ts +1 -1
  36. package/dist/components/dataDisplay/statusDot/statusDot.d.ts +10 -1
  37. package/dist/components/dataDisplay/statusDot/statusDot.js +20 -11
  38. package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -1
  39. package/dist/components/dataDisplay/treeView/treeView.d.ts +18 -2
  40. package/dist/components/dataDisplay/treeView/treeView.js +140 -121
  41. package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
  42. package/dist/components/inputs/button/button.d.ts +7 -0
  43. package/dist/components/inputs/button/button.js +57 -51
  44. package/dist/components/inputs/button/button.js.map +1 -1
  45. package/dist/components/inputs/toggle/toggle.d.ts +6 -0
  46. package/dist/components/inputs/toggle/toggle.js +23 -23
  47. package/dist/components/inputs/toggle/toggle.js.map +1 -1
  48. package/dist/components/layout/appLayout/appLayout.d.ts +6 -1
  49. package/dist/components/layout/appLayout/appLayout.js +49 -42
  50. package/dist/components/layout/appLayout/appLayout.js.map +1 -1
  51. package/dist/components/layout/screenDivider/screenDivider.d.ts +12 -0
  52. package/dist/components/layout/screenDivider/screenDivider.js +87 -46
  53. package/dist/components/layout/screenDivider/screenDivider.js.map +1 -1
  54. package/dist/components/layout/sheet/sheet.d.ts +11 -0
  55. package/dist/components/layout/sheet/sheet.js +122 -102
  56. package/dist/components/layout/sheet/sheet.js.map +1 -1
  57. package/dist/components/layout/tabGroups/index.d.ts +1 -1
  58. package/dist/components/layout/tabGroups/tabGroups.d.ts +44 -1
  59. package/dist/components/layout/tabGroups/tabGroups.js +500 -460
  60. package/dist/components/layout/tabGroups/tabGroups.js.map +1 -1
  61. package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +16 -0
  62. package/dist/components/layout/tabGroups/tabGroupsFocus.js +102 -70
  63. package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -1
  64. package/dist/components/navigation/appBar/appBar.d.ts +12 -0
  65. package/dist/components/navigation/appBar/appBar.js.map +1 -1
  66. package/dist/components/navigation/breadcrumbs/breadcrumbs.d.ts +9 -0
  67. package/dist/components/navigation/breadcrumbs/breadcrumbs.js +47 -31
  68. package/dist/components/navigation/breadcrumbs/breadcrumbs.js.map +1 -1
  69. package/dist/components/navigation/tabs/tab/tab.js +71 -68
  70. package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
  71. package/dist/components/navigation/tabs/tabs.d.ts +15 -1
  72. package/dist/components/navigation/tabs/tabs.js +19 -16
  73. package/dist/components/navigation/tabs/tabs.js.map +1 -1
  74. package/dist/components/navigation/tabs/tabsContext.d.ts +2 -0
  75. package/dist/components/navigation/tabs/tabsContext.js.map +1 -1
  76. package/dist/headless/components/dataDisplay/avatar/avatar.js +9 -9
  77. package/dist/headless/components/dataDisplay/avatar/avatar.js.map +1 -1
  78. package/dist/headless/components/dataDisplay/badge/badge.js.map +1 -1
  79. package/dist/headless/components/dataDisplay/dagView/dagView.js +133 -132
  80. package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -1
  81. package/dist/headless/components/dataDisplay/meter/meter.js +32 -30
  82. package/dist/headless/components/dataDisplay/meter/meter.js.map +1 -1
  83. package/dist/headless/components/dataDisplay/statusDot/statusDot.js +19 -10
  84. package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -1
  85. package/dist/headless/components/dataDisplay/treeView/treeView.js +139 -120
  86. package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
  87. package/dist/headless/components/inputs/button/button.js +57 -51
  88. package/dist/headless/components/inputs/button/button.js.map +1 -1
  89. package/dist/headless/components/inputs/toggle/toggle.js +23 -23
  90. package/dist/headless/components/inputs/toggle/toggle.js.map +1 -1
  91. package/dist/headless/components/layout/appLayout/appLayout.js +52 -45
  92. package/dist/headless/components/layout/appLayout/appLayout.js.map +1 -1
  93. package/dist/headless/components/layout/screenDivider/screenDivider.js +88 -47
  94. package/dist/headless/components/layout/screenDivider/screenDivider.js.map +1 -1
  95. package/dist/headless/components/layout/sheet/sheet.js +124 -104
  96. package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
  97. package/dist/headless/components/layout/tabGroups/tabGroups.js +500 -460
  98. package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -1
  99. package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +102 -70
  100. package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -1
  101. package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
  102. package/dist/headless/components/navigation/breadcrumbs/breadcrumbs.js +46 -30
  103. package/dist/headless/components/navigation/breadcrumbs/breadcrumbs.js.map +1 -1
  104. package/dist/headless/components/navigation/tabs/tab/tab.js +70 -67
  105. package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
  106. package/dist/headless/components/navigation/tabs/tabs.js +19 -16
  107. package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
  108. package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -1
  109. package/dist/headless/primitives/publishHeaderOffset.js +19 -0
  110. package/dist/headless/primitives/publishHeaderOffset.js.map +1 -0
  111. package/dist/headless/source/components/dataDisplay/avatar/avatar.jsx +1 -0
  112. package/dist/headless/source/components/dataDisplay/avatar/avatar.jsx.map +1 -1
  113. package/dist/headless/source/components/dataDisplay/badge/badge.jsx.map +1 -1
  114. package/dist/headless/source/components/dataDisplay/chart/chart.jsx +14 -12
  115. package/dist/headless/source/components/dataDisplay/chart/chart.jsx.map +1 -1
  116. package/dist/headless/source/components/dataDisplay/chart/chartFull.js +12 -0
  117. package/dist/headless/source/components/dataDisplay/chart/chartFull.js.map +7 -0
  118. package/dist/headless/source/components/dataDisplay/chart/core.js +11 -0
  119. package/dist/headless/source/components/dataDisplay/chart/core.js.map +7 -0
  120. package/dist/headless/source/components/dataDisplay/chart/index.js +1 -1
  121. package/dist/headless/source/components/dataDisplay/chart/index.js.map +1 -1
  122. package/dist/headless/source/components/dataDisplay/dagView/dagView.jsx +2 -1
  123. package/dist/headless/source/components/dataDisplay/dagView/dagView.jsx.map +1 -1
  124. package/dist/headless/source/components/dataDisplay/dagView/index.js.map +2 -2
  125. package/dist/headless/source/components/dataDisplay/meter/index.js.map +1 -1
  126. package/dist/headless/source/components/dataDisplay/meter/meter.jsx +14 -2
  127. package/dist/headless/source/components/dataDisplay/meter/meter.jsx.map +1 -1
  128. package/dist/headless/source/components/dataDisplay/statusDot/index.js.map +1 -1
  129. package/dist/headless/source/components/dataDisplay/statusDot/statusDot.jsx +13 -1
  130. package/dist/headless/source/components/dataDisplay/statusDot/statusDot.jsx.map +1 -1
  131. package/dist/headless/source/components/dataDisplay/treeView/treeView.jsx +16 -3
  132. package/dist/headless/source/components/dataDisplay/treeView/treeView.jsx.map +1 -1
  133. package/dist/headless/source/components/inputs/button/button.jsx +26 -1
  134. package/dist/headless/source/components/inputs/button/button.jsx.map +1 -1
  135. package/dist/headless/source/components/inputs/toggle/toggle.jsx +9 -2
  136. package/dist/headless/source/components/inputs/toggle/toggle.jsx.map +1 -1
  137. package/dist/headless/source/components/layout/appLayout/appLayout.jsx +14 -2
  138. package/dist/headless/source/components/layout/appLayout/appLayout.jsx.map +1 -1
  139. package/dist/headless/source/components/layout/screenDivider/screenDivider.jsx +102 -18
  140. package/dist/headless/source/components/layout/screenDivider/screenDivider.jsx.map +1 -1
  141. package/dist/headless/source/components/layout/sheet/sheet.jsx +14 -1
  142. package/dist/headless/source/components/layout/sheet/sheet.jsx.map +1 -1
  143. package/dist/headless/source/components/layout/tabGroups/index.js.map +1 -1
  144. package/dist/headless/source/components/layout/tabGroups/tabGroups.jsx +55 -1
  145. package/dist/headless/source/components/layout/tabGroups/tabGroups.jsx.map +1 -1
  146. package/dist/headless/source/components/layout/tabGroups/tabGroupsFocus.js +42 -0
  147. package/dist/headless/source/components/layout/tabGroups/tabGroupsFocus.js.map +2 -2
  148. package/dist/headless/source/components/navigation/appBar/appBar.jsx.map +1 -1
  149. package/dist/headless/source/components/navigation/breadcrumbs/breadcrumbs.jsx +39 -4
  150. package/dist/headless/source/components/navigation/breadcrumbs/breadcrumbs.jsx.map +1 -1
  151. package/dist/headless/source/components/navigation/tabs/tab/tab.jsx +7 -1
  152. package/dist/headless/source/components/navigation/tabs/tab/tab.jsx.map +1 -1
  153. package/dist/headless/source/components/navigation/tabs/tabs.jsx +5 -1
  154. package/dist/headless/source/components/navigation/tabs/tabs.jsx.map +1 -1
  155. package/dist/headless/source/components/navigation/tabs/tabsContext.js.map +2 -2
  156. package/dist/headless/source/index.js +8 -1
  157. package/dist/headless/source/index.js.map +2 -2
  158. package/dist/headless/source/primitives/publishHeaderOffset.js +34 -0
  159. package/dist/headless/source/primitives/publishHeaderOffset.js.map +7 -0
  160. package/dist/index.d.ts +5 -5
  161. package/dist/primitives/publishHeaderOffset.d.ts +7 -0
  162. package/dist/primitives/publishHeaderOffset.js +19 -0
  163. package/dist/primitives/publishHeaderOffset.js.map +1 -0
  164. package/dist/source/components/dataDisplay/avatar/avatar.jsx +1 -0
  165. package/dist/source/components/dataDisplay/avatar/avatar.jsx.map +1 -1
  166. package/dist/source/components/dataDisplay/badge/badge.jsx.map +1 -1
  167. package/dist/source/components/dataDisplay/chart/chart.jsx +14 -12
  168. package/dist/source/components/dataDisplay/chart/chart.jsx.map +1 -1
  169. package/dist/source/components/dataDisplay/chart/chartFull.js +12 -0
  170. package/dist/source/components/dataDisplay/chart/chartFull.js.map +7 -0
  171. package/dist/source/components/dataDisplay/chart/core.js +11 -0
  172. package/dist/source/components/dataDisplay/chart/core.js.map +7 -0
  173. package/dist/source/components/dataDisplay/chart/index.js +1 -1
  174. package/dist/source/components/dataDisplay/chart/index.js.map +1 -1
  175. package/dist/source/components/dataDisplay/dagView/dagView.jsx +2 -1
  176. package/dist/source/components/dataDisplay/dagView/dagView.jsx.map +1 -1
  177. package/dist/source/components/dataDisplay/dagView/index.js.map +2 -2
  178. package/dist/source/components/dataDisplay/meter/index.js.map +1 -1
  179. package/dist/source/components/dataDisplay/meter/meter.jsx +14 -2
  180. package/dist/source/components/dataDisplay/meter/meter.jsx.map +1 -1
  181. package/dist/source/components/dataDisplay/statusDot/index.js.map +1 -1
  182. package/dist/source/components/dataDisplay/statusDot/statusDot.jsx +13 -1
  183. package/dist/source/components/dataDisplay/statusDot/statusDot.jsx.map +1 -1
  184. package/dist/source/components/dataDisplay/treeView/treeView.jsx +16 -3
  185. package/dist/source/components/dataDisplay/treeView/treeView.jsx.map +1 -1
  186. package/dist/source/components/inputs/button/button.jsx +26 -1
  187. package/dist/source/components/inputs/button/button.jsx.map +1 -1
  188. package/dist/source/components/inputs/toggle/toggle.jsx +9 -2
  189. package/dist/source/components/inputs/toggle/toggle.jsx.map +1 -1
  190. package/dist/source/components/layout/appLayout/appLayout.jsx +14 -2
  191. package/dist/source/components/layout/appLayout/appLayout.jsx.map +1 -1
  192. package/dist/source/components/layout/screenDivider/screenDivider.jsx +102 -18
  193. package/dist/source/components/layout/screenDivider/screenDivider.jsx.map +1 -1
  194. package/dist/source/components/layout/sheet/sheet.jsx +14 -1
  195. package/dist/source/components/layout/sheet/sheet.jsx.map +1 -1
  196. package/dist/source/components/layout/tabGroups/index.js.map +1 -1
  197. package/dist/source/components/layout/tabGroups/tabGroups.jsx +55 -1
  198. package/dist/source/components/layout/tabGroups/tabGroups.jsx.map +1 -1
  199. package/dist/source/components/layout/tabGroups/tabGroupsFocus.js +42 -0
  200. package/dist/source/components/layout/tabGroups/tabGroupsFocus.js.map +2 -2
  201. package/dist/source/components/navigation/appBar/appBar.jsx.map +1 -1
  202. package/dist/source/components/navigation/breadcrumbs/breadcrumbs.jsx +39 -4
  203. package/dist/source/components/navigation/breadcrumbs/breadcrumbs.jsx.map +1 -1
  204. package/dist/source/components/navigation/tabs/tab/tab.jsx +7 -1
  205. package/dist/source/components/navigation/tabs/tab/tab.jsx.map +1 -1
  206. package/dist/source/components/navigation/tabs/tabs.jsx +5 -1
  207. package/dist/source/components/navigation/tabs/tabs.jsx.map +1 -1
  208. package/dist/source/components/navigation/tabs/tabsContext.js.map +2 -2
  209. package/dist/source/index.js +8 -1
  210. package/dist/source/index.js.map +2 -2
  211. package/dist/source/primitives/publishHeaderOffset.js +34 -0
  212. package/dist/source/primitives/publishHeaderOffset.js.map +7 -0
  213. package/package.json +9 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/components/layout/tabGroups/tabGroups.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/tabGroups/tabGroups.entry.less\";\nimport {\n type JSX,\n For,\n Show,\n children as resolveChildren,\n createComputed,\n createEffect,\n createMemo,\n createRenderEffect,\n createSignal,\n createUniqueId,\n mapArray,\n on,\n onCleanup,\n onMount,\n splitProps,\n} from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { Tabs } from \"../../navigation/tabs/tabs\";\nimport { Tab } from \"../../navigation/tabs/tab/tab\";\nimport type { TabCloseReason, TabProps } from \"../../navigation/tabs/tab/tab\";\nimport { Menu } from \"../../navigation/menu/menu\";\nimport { MenuItem } from \"../../navigation/menu/menuItem\";\nimport { Icon } from \"../../base/icon\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\nimport { createControllableState } from \"../../../primitives/createControllableState\";\nimport { callHandler } from \"../../../primitives/callHandler\";\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 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/**\n * What a tab of `TabGroups` shows, answered by the app through `getTab`. Only the tab's id lives in\n * the layout, so a stored arrangement survives renames and carries no content.\n */\nexport interface TabGroupsTab {\n /** The tab's label. A tab id the app does not know is drawn as the id itself. */\n label: JSX.Element;\n /**\n * Plain text for the announcements and for a screen reader that cannot read the label (markup,\n * an icon). `label` when it is a string, else the tab id.\n */\n title?: string | undefined;\n /** An icon drawn before the label. */\n icon?: JSX.Element;\n /**\n * Draw a close button and let Delete or Backspace close the tab: true by default. `false` keeps\n * the tab's item wrapper, so every tab has the same drag surface.\n */\n closable?: boolean | undefined;\n /** Accessible label of the tab's close button (\"Close Terminal 1\"). */\n closeLabel?: string | undefined;\n /** Content after the tab, as `Tab`'s `actions`: a trigger with a `Menu`, or any control. */\n actions?: TabProps[\"actions\"];\n /** Greys the tab out: it cannot be selected, moved or dragged. */\n disabled?: boolean | undefined;\n}\n\nexport interface TabGroupsProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"children\" | \"onChange\" | \"id\"> {\n /**\n * The arrangement to draw: the split tree, every group's tabs and the selected one. Controlled\n * while it is not `undefined` — the component then only reports changes through\n * `onLayoutChange` and draws what the owner gives back.\n */\n layout?: TabGroupsLayout | undefined;\n /** The arrangement to start from while uncontrolled: one empty group by default. */\n defaultLayout?: TabGroupsLayout | undefined;\n /**\n * Called with the layout after a change and with what happened, in both the controlled and the\n * uncontrolled mode. A controlled owner that does not apply the change simply sees nothing move.\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. It is called the first time the tab is selected and\n * the panel stays mounted from then on, hidden while another tab is shown and kept through a\n * move to another group: a form keeps what was typed, a terminal its scrollback. Its node stays\n * where it is in the DOM, so an iframe in it does not reload either.\n */\n renderPanel: (tabId: string) => JSX.Element;\n /**\n * Asked before a tab closes, with what asked for it (its close button, Delete or Backspace, a\n * middle click, its `actions`). Return `false` to keep the tab.\n */\n onTabClose?: ((tabId: string, event: Event, reason: TabCloseReason) => boolean | void) | undefined;\n /** Drawn, centred, when the only group has no tabs left. */\n empty?: JSX.Element;\n /** The smallest a group can be resized to, in px of its split; 120 by default. */\n minGroupSize?: number | undefined;\n /** The arrow-key step of a separator, in percent of its split; 5 by default. */\n keyboardStep?: number | undefined;\n /** Draw each group's actions button and menu; true by default. */\n groupActions?: boolean | undefined;\n /** Compact tab rows, as `Tabs`' `dense`; false by default. */\n dense?: boolean | undefined;\n /** The texts of the component: its menus, labels and announcements. English by default. */\n labels?: Partial<TabGroupsLabels> | undefined;\n /** Base of the generated ids and the id of the root element. Generated by default. */\n id?: string | undefined;\n /** Test id of the root element; `tab-groups` unless given. */\n \"data-testid\"?: string | undefined;\n /** Class of the root element, added to the component's own. */\n class?: string | undefined;\n /** Inline style of the root element; the component's `grid-template-*` win over it. */\n style?: JSX.HTMLAttributes<HTMLDivElement>[\"style\"];\n /** The root element. */\n ref?: Ref<HTMLDivElement>;\n}\n\n/** The chords a group's tabs answer to, as `aria-keyshortcuts` lists them. */\nconst CHORD_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 keys that move a tab to the group (or the new group) at that edge. */\nconst DIRECTION_CHORDS: [TabGroupsEdge, string[]][] = [\n [\"left\", [\"Alt\", \"Shift\", \"ArrowLeft\"]],\n [\"right\", [\"Alt\", \"Shift\", \"ArrowRight\"]],\n [\"top\", [\"Alt\", \"Shift\", \"ArrowUp\"]],\n [\"bottom\", [\"Alt\", \"Shift\", \"ArrowDown\"]],\n];\n\n/** The item of an opened menu that takes focus first (as `Tab`'s actions look for it). */\nconst FIRST_MENU_ITEM = '[role^=\"menuitem\"]:not([aria-disabled=\"true\"])';\n\n/** What a group's actions menu can do; every item acts on the group's selected tab. */\ntype MenuAction = \"splitRight\" | \"splitDown\" | \"previous\" | \"next\" | \"left\" | \"right\";\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 an event landed on. `Tabs` makes the item wrapper draggable, so a real drag reports the\n * wrapper — not the tab — as its target: the tab is then found inside it, and an event on the tab\n * or on its label is still resolved by walking up.\n */\nfunction tabElementOf(target: Element | null): HTMLElement | null {\n if (!target) return null;\n const direct = target.closest<HTMLElement>('[role=\"tab\"]');\n if (direct) return direct;\n const item = target.closest<HTMLElement>(\".smwb-tab-item\");\n return item?.querySelector<HTMLElement>('[role=\"tab\"]') ?? null;\n}\n\n/** The split node with this id, if the tree has one. */\nfunction findSplitNode(root: TabGroupsNode, id: string): TabGroupsSplit | undefined {\n if (root.type === \"group\") return undefined;\n if (root.id === id) return root;\n for (const child of root.children) {\n const found = findSplitNode(child, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** The ids of the groups a node holds. */\nfunction groupIdsOf(node: TabGroupsNode): string[] {\n return node.type === \"group\" ? [node.id] : node.children.flatMap(groupIdsOf);\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/**\n * Puts the root's headers, separators and panels at its start, in the given order, moving none\n * that can stay. Solid's list diff may take a kept node out and put it back, and a browser treats\n * that as a removal: a focused tab in a header blurs to nowhere and a scrolled tab row goes back\n * to its start. So the nodes already in order among themselves stay where they are (the longest\n * such run, always including the one that holds the focus), and only the others are inserted, or\n * moved, around them. `previous` is what was placed before: the nodes of it that are gone go.\n */\nfunction placeChildren(parent: HTMLElement, next: readonly HTMLElement[], previous: readonly HTMLElement[]): void {\n const wanted = new Set<Element>(next);\n previous.forEach((node) => {\n if (!wanted.has(node) && node.parentNode === parent) node.remove();\n });\n const children = Array.from(parent.children);\n const position = new Map<Element, number>();\n children.forEach((child, at) => position.set(child, at));\n\n const active = parent.ownerDocument.activeElement;\n const focused = active === null ? -1 : next.findIndex((node) => node.contains(active));\n const focusedAt = focused < 0 ? undefined : position.get(next[focused]!);\n // The nodes already in the root, in their new order; with a focused one, only those that can\n // stay on the same side of it as before.\n const kept: number[] = [];\n next.forEach((node, i) => {\n const at = position.get(node);\n if (at === undefined) return;\n if (focusedAt !== undefined && i !== focused && i < focused !== at < focusedAt) return;\n kept.push(at);\n });\n // The longest run of them in ascending place stays put (a few dozen nodes, so quadratic is fine).\n const length = kept.map(() => 1);\n const before = kept.map(() => -1);\n let best = -1;\n kept.forEach((at, k) => {\n for (let j = 0; j < k; j++) {\n if (kept[j]! < at && length[j]! + 1 > length[k]!) {\n length[k] = length[j]! + 1;\n before[k] = j;\n }\n }\n if (best < 0 || length[k]! > length[best]!) best = k;\n });\n const stays = new Set<number>();\n for (let k = best; k >= 0; k = before[k]!) stays.add(kept[k]!);\n\n // The last node goes after the last one that stays — or, with none staying, at the root's start,\n // before what Solid draws there (the empty state, the drop targets, the guard, the status).\n let anchor: Node | null = stays.size > 0 ? children[Math.max(...stays)]!.nextSibling : parent.firstChild;\n for (let i = next.length - 1; i >= 0; i--) {\n const node = next[i]!;\n const at = position.get(node);\n if (at === undefined || !stays.has(at)) parent.insertBefore(node, anchor);\n anchor = node;\n }\n}\n\n/** The tabs the layout shows: one per group. */\nfunction selectedTabsOf(layout: TabGroupsLayout): string[] {\n return getGroups(layout)\n .map((group) => group.active)\n .filter((tab): tab is string => tab !== null);\n}\n\n/**\n * Tab groups in a split area: one component draws every group, each a tab row with its panels.\n *\n * The area splits right or down into groups, a tab moves to another group by drag and drop or by\n * keyboard, dropping it on a group's edge makes a new group there, and closing a group's last tab\n * closes the group and collapses its split. The whole arrangement is a serialisable, versioned\n * `layout` (`layout` / `defaultLayout` / `onLayoutChange`) that an app stores as JSON;\n * `tabGroupsLayout.parseTabGroupsLayout` reads one back, and `tabGroupsLayout.addTab` /\n * `syncTabs` keep it in step with the tabs the app has open.\n *\n * Everything is drawn on one CSS grid whose children are a flat, keyed list, so restructuring the\n * tree re-places nodes instead of remounting them, and a panel's node never moves: it keeps its\n * state, its scroll and the focus inside it when its tab moves to another group or the area splits.\n *\n * Without a mouse: Alt+Shift+Arrow moves the focused tab to the group that way (splitting there\n * when the area ends), Mod+Shift+ArrowLeft/Right moves it along its row, each group's actions\n * button opens a menu of the same actions, and each separator resizes with the arrow keys, Home\n * and End. Every move is announced in a polite status region.\n */\nexport function TabGroups(props: TabGroupsProps): JSX.Element {\n const [local, rest] = splitProps(props, [\n \"class\",\n \"style\",\n \"id\",\n \"data-testid\",\n \"ref\",\n \"layout\",\n \"defaultLayout\",\n \"onLayoutChange\",\n \"getTab\",\n \"renderPanel\",\n \"onTabClose\",\n \"empty\",\n \"minGroupSize\",\n \"keyboardStep\",\n \"groupActions\",\n \"dense\",\n \"labels\",\n // Wrapped so that the caller's handler still runs, first.\n \"onDragStart\",\n \"onDragOver\",\n \"onDrop\",\n \"onDragEnd\",\n \"onFocusIn\",\n \"onKeyDown\",\n ]);\n\n const generatedId = createUniqueId();\n const base = (): string => local.id ?? generatedId;\n const encode = (id: string): string => encodeURIComponent(id);\n const tabElementId = (tabId: string): string => `${base()}-tab-${encode(tabId)}`;\n const panelElementId = (tabId: string): string => `${base()}-panel-${encode(tabId)}`;\n const menuElementId = (groupId: string): string => `${base()}-menu-${encode(groupId)}`;\n const headerElementId = (groupId: string): string => `${base()}-header-${encode(groupId)}`;\n const separatorElementId = (splitId: string, index: number): string =>\n `${base()}-separator-${encode(splitId)}-${index}`;\n const statusElementId = (): string => `${base()}-status`;\n\n const minGroupSize = (): number => local.minGroupSize ?? 120;\n const keyboardStep = (): number => local.keyboardStep ?? 5;\n const withGroupActions = (): boolean => local.groupActions !== false;\n const labels = createMemo(\n (): TabGroupsLabels => ({\n ...TAB_GROUPS_LABELS,\n ...local.labels,\n })\n );\n\n // The library's controlled-state rule: controlled while `layout` is not undefined, own state\n // while it is. `latest` is the layout the next change is computed from, so two changes in one\n // event (a drop and the selection that follows it, a chord and the focus it moves) compose\n // instead of the second overwriting the first. It is reset to the drawn value whenever that\n // changes and — while controlled — once the event is over (`settle`): a change the owner did\n // not draw is forgotten, so the next one neither reports it nor reads its rows.\n const [layout, setLayout] = createControllableState<TabGroupsLayout>({\n value: () => local.layout,\n defaultValue: local.defaultLayout ?? createTabGroupsLayout(),\n });\n let latest: TabGroupsLayout = layout();\n createComputed(() => {\n latest = layout();\n });\n\n const grid = createMemo(() => computeTabGroupsGrid(layout()));\n const groups = createMemo(() => getGroups(layout()));\n const groupCount = createMemo(() => groups().length);\n const hasSplit = createMemo(() => groups().length > 1);\n const selectedTabs = createMemo(() => new Set(selectedTabsOf(layout())));\n const groupOfTab = createMemo(() => {\n const map = new Map<string, string>();\n getGroups(layout()).forEach((group) => group.tabs.forEach((tab) => map.set(tab, group.id)));\n return map;\n });\n const groupById = (value: TabGroupsLayout, groupId: string): TabGroupsGroup | undefined =>\n getGroups(value).find((group) => group.id === groupId);\n const indexOfGroup = (groupId: string): number => groups().findIndex((group) => group.id === groupId);\n\n // Nothing open: the one group has no tabs, so the `empty` slot takes the area.\n const isEmpty = createMemo((): boolean => {\n const list = groups();\n return list.length === 1 && (list[0]?.tabs.length ?? 0) === 0;\n });\n\n // The grid's children, each placed by its `grid-area` alone: the headers in reading order, the\n // separators, then the panels in the order they first appeared — a new one at the end, never\n // reordered. A move only changes a panel's `grid-area`, so its node stays where it is: putting it\n // back into the document would reset its scroll, reload an iframe in it and blur the focus inside\n // it. Tab order and the accessibility tree follow the reading order (`onRootKeyDown`, `aria-owns`),\n // and no header or separator that keeps its place among the others is moved either (`placeChildren`).\n const groupIds = createMemo((): string[] => groups().map((group) => group.id));\n const separatorKeys = createMemo((): string[] => readingKeys(layout().root).filter((key) => key.startsWith(\"s:\")));\n const panelOrder = createMemo<string[]>((previous) => {\n const alive = groupOfTab();\n const order = previous.filter((tab) => alive.has(tab));\n const placed = new Set(order);\n groups().forEach((group) =>\n group.tabs.forEach((tab) => {\n if (placed.has(tab)) return;\n placed.add(tab);\n order.push(tab);\n })\n );\n return order.length === previous.length && order.every((tab, index) => tab === previous[index]) ? previous : order;\n }, []);\n const owns = createMemo((): string | undefined => {\n if (isEmpty()) return undefined;\n const value = layout();\n return [\n ...readingKeys(value.root).flatMap((key) => {\n if (key.startsWith(\"h:\")) return [headerElementId(key.slice(2))];\n if (key.startsWith(\"p:\")) return (groupById(value, 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 statusElementId(),\n ].join(\" \");\n });\n\n // The panels that stay mounted: the selected tabs of the layout drawn now (the same set on the\n // server and the client), plus every tab that was selected before, minus the closed ones.\n const [mountedTabs, setMountedTabs] = createSignal<Set<string>>(new Set(selectedTabsOf(layout())));\n if (!isServer) {\n createEffect(() => {\n const value = layout();\n const alive = new Set<string>();\n getGroups(value).forEach((group) => group.tabs.forEach((tab) => alive.add(tab)));\n const selected = selectedTabsOf(value);\n setMountedTabs((prev) => {\n const next = new Set<string>();\n let changed = false;\n prev.forEach((tab) => {\n if (alive.has(tab)) next.add(tab);\n else changed = true;\n });\n selected.forEach((tab) => {\n if (!next.has(tab)) {\n next.add(tab);\n changed = true;\n }\n });\n return changed || next.size !== prev.size ? next : prev;\n });\n });\n }\n\n const [status, setStatus] = createSignal(\"\");\n const [openMenu, setOpenMenu] = createSignal<string | null>(null);\n const [dragging, setDragging] = createSignal(false);\n const [dropGroup, setDropGroup] = createSignal<string | null>(null);\n const [dropZone, setDropZone] = createSignal<TabGroupsDropZone | null>(null);\n const [draggingSeparator, setDraggingSeparator] = createSignal<{\n key: string;\n orientation: \"vertical\" | \"horizontal\";\n } | null>(null);\n\n let rootEl: HTMLDivElement | undefined;\n let guardEl: HTMLSpanElement | undefined;\n // The tab to focus once its move has been drawn: a keyboard chord, a menu action, a drop of a\n // tab that had focus, or the group that takes the space of a closed one (D9) — which is then\n // `gone`, and has to be gone from the drawn layout before the focus moves. It waits for the next\n // layout the owner draws that answers the change (`after`; `base` is the one drawn when it was\n // asked for), however late, and that layout either shows the change (the tab in `group` at\n // `index`) or not; `from` had the focus then.\n let pendingFocus: {\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 reported = new WeakMap<TabGroupsLayout, number>();\n let reportCount = 0;\n let settleQueued = false;\n // The focus guard is taking the focus on its way out of the root: not a reason to send it back.\n let leaving = false;\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 let lastFocus: Element | null = null;\n let pointerFocus = false;\n\n const announce = (next: TabGroupsLayout, change: TabGroupsChange): void => {\n const text = describeTabGroupsChange(change, next, tabTitle, labels());\n if (text === \"\") return;\n // The same text twice in a row is not read again: a trailing no-break space makes it new.\n setStatus((prev) => (prev.replace(/\\u00a0+$/, \"\") === text ? `${text}\\u00a0` : text));\n };\n\n /** Asks for a tab's focus once `next`, the layout a change produced, is drawn; `gone` is a closed group. */\n const armFocus = (tabId: string, next: TabGroupsLayout, gone?: string): void => {\n const group = findGroupOfTab(next, tabId);\n if (!group) return;\n pendingFocus = {\n tab: tabId,\n group: group.id,\n index: group.tabs.indexOf(tabId),\n ...(gone === undefined ? {} : { gone }),\n after: next,\n base: layout(),\n from: rootEl ? deepActiveElement(rootEl.ownerDocument) : null,\n };\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 = reported.get(drawn);\n const askedAt = reported.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 — and only when that layout shows the change and the\n * focus is still with the layout (or still where it was). Then the request is done either way,\n * so a change the owner never drew moves no focus later.\n */\n const focusPending = (): void => {\n const pending = pendingFocus;\n const drawn = layout();\n if (!pending || stillWaiting(pending, drawn)) return;\n const doc = rootEl?.ownerDocument;\n const group = findGroupOfTab(drawn, pending.tab);\n const shown =\n group?.id === pending.group &&\n group.tabs.indexOf(pending.tab) === pending.index &&\n (pending.gone === undefined || !groupById(drawn, pending.gone));\n const element = shown ? doc?.getElementById(tabElementId(pending.tab)) : null;\n // Drawn, but not in the document yet (an update still running): the effect after it asks again.\n if (shown && (!element || groupIdOf(element) !== pending.group)) return;\n pendingFocus = null;\n if (!element || !rootEl || !doc) return;\n const active = deepActiveElement(doc);\n if (active === element) return;\n if (active !== null && active !== doc.body && active !== pending.from && !containsDeep(rootEl, active)) return;\n element.focus();\n };\n\n const commit = (next: TabGroupsLayout, change: TabGroupsChange): void => {\n if (next === latest) return;\n latest = next;\n reportCount += 1;\n reported.set(next, reportCount);\n setLayout(() => next);\n local.onLayoutChange?.(next, change);\n announce(next, change);\n focusPending();\n if (local.layout !== undefined && !settleQueued) {\n settleQueued = true;\n queueMicrotask(settle);\n }\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. Two changes of one event — a drop and `Tabs`' report of it, a commit and the `focusin`\n * it causes — still compose. The focus move waits for the owner's next layout (`focusPending`).\n */\n const settle = (): void => {\n settleQueued = false;\n if (local.layout === undefined || latest === layout()) return;\n latest = layout();\n };\n\n // An owner that applies a change later than the event (a timeout) draws it here.\n if (!isServer) {\n createEffect(\n on(\n layout,\n () => {\n focusPending();\n },\n { defer: true }\n )\n );\n }\n\n const tabTitle = (tabId: string): string => {\n const meta = local.getTab(tabId);\n if (!meta) return tabId;\n if (meta.title !== undefined) return meta.title;\n return typeof meta.label === \"string\" ? meta.label : tabId;\n };\n\n /** What `moveTab` did, told from the two layouts: a reorder, a move or a split. */\n const commitMove = (\n next: TabGroupsLayout,\n before: TabGroupsLayout,\n tabId: string,\n from: string,\n options: { edge?: TabGroupsEdge | undefined; focus?: boolean | undefined } = {}\n ): void => {\n if (next === before) return;\n const to = findGroupOfTab(next, tabId)?.id;\n const target = to !== undefined ? groupById(next, to) : undefined;\n if (!to || !target) return;\n const sourceClosed = !getGroups(next).some((group) => group.id === from);\n const existed = getGroups(before).some((group) => group.id === to);\n const change: TabGroupsChange =\n options.edge !== undefined && !existed\n ? { type: \"split\", tab: tabId, from, to, edge: options.edge, sourceClosed }\n : { type: \"move\", tab: tabId, from, to, index: target.tabs.indexOf(tabId), sourceClosed };\n if (options.focus) armFocus(tabId, next);\n commit(next, change);\n };\n\n // ── The tab rows ──────────────────────────────────────────────────────────\n\n const onRowChange =\n (groupId: string) =>\n (event: MouseEvent & { currentTarget: HTMLElement; target: Element }, index: number): void => {\n // A drop of the selected tab reports its new index through `onChange` as well; the selection\n // is by id and already right, so the index — counted before the move — is not read.\n if (event.type === \"drop\") return;\n const current = latest;\n const group = groupById(current, groupId);\n const tabId = group?.tabs[index];\n if (!group || tabId === undefined) return;\n commit(selectTab(current, tabId), { type: \"select\", tab: tabId, group: groupId });\n };\n\n const onRowReorder =\n (groupId: string) =>\n (from: number, to: number): void => {\n const current = latest;\n const group = groupById(current, groupId);\n const tabId = group?.tabs[from];\n if (!group || tabId === undefined) return;\n // A reorder is a move within the row: the selection stays, and the tab that had the focus\n // keeps it (Tabs puts it back itself, this is the same request for a move it cannot see).\n commitMove(moveTab(current, tabId, { group: groupId, index: to }), current, tabId, groupId, {\n focus: dragState?.hadFocus ?? false,\n });\n };\n\n const requestClose = (tabId: string, event: Event, reason: TabCloseReason): void => {\n const current = latest;\n const group = findGroupOfTab(current, tabId);\n if (!group) return;\n if (local.onTabClose?.(tabId, event, reason) === false) return;\n const next = removeTab(current, tabId);\n if (next === current) return;\n const groupClosed = !getGroups(next).some((candidate) => candidate.id === group.id);\n // A group that goes with its last tab takes the focus with it: the group that fills the space\n // gets it, but only when the focus was in the group that went (or the close came from its\n // `actions` menu, drawn outside it). Anywhere else the focus stays where it is. A tab that\n // leaves its group alive is Tabs' own focus move.\n const root = rootEl;\n const active = root ? deepActiveElement(root.ownerDocument) : null;\n const focusWasHere = reason === \"actions\" || (root !== undefined && ownGroupIdOf(root, active) === group.id);\n const heir = groupClosed && focusWasHere ? adjacentGroup(current, group.id) : undefined;\n if (heir !== undefined) {\n const heirTab = groupById(next, heir)?.active;\n if (heirTab) armFocus(heirTab, next, group.id);\n }\n commit(next, { type: \"close\", tab: tabId, group: group.id, groupClosed });\n };\n\n // The chords sit on the header, where they catch the key that bubbles up from the tab; the row's\n // own keys (arrows, Enter, Delete, Mod+W, Mod+Shift+[/]) are Tabs' and run first.\n const onHeaderKeyDown =\n (groupId: string) =>\n (event: KeyboardEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (event.defaultPrevented || event.repeat || event.isComposing) return;\n const target = event.target;\n if (!(target instanceof Element)) return;\n const tabEl = target.closest<HTMLElement>('[role=\"tab\"]');\n if (!tabEl || groupIdOf(tabEl) !== groupId) return;\n if (tabEl.getAttribute(\"aria-disabled\") === \"true\") return;\n const tabId = tabEl.getAttribute(\"data-tab-id\");\n if (!tabId) return;\n const current = latest;\n const group = groupById(current, groupId);\n if (!group) return;\n\n for (const [edge, keys] of DIRECTION_CHORDS) {\n if (!matchesKeyboardShortcut(event, keys)) continue;\n const next = moveTabInDirection(current, tabId, edge);\n // Nothing to do (the area ends here and the tab is alone): the key is left alone too.\n if (next === current) return;\n event.preventDefault();\n commitMove(next, current, tabId, groupId, { edge, focus: true });\n return;\n }\n const shift = matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"ArrowLeft\"])\n ? -1\n : matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"ArrowRight\"])\n ? 1\n : 0;\n if (shift === 0) return;\n const from = group.tabs.indexOf(tabId);\n const to = from + shift;\n if (from < 0 || to < 0 || to >= group.tabs.length) return;\n event.preventDefault();\n commitMove(moveTab(current, tabId, { group: groupId, index: to }), current, tabId, groupId, {\n focus: true,\n });\n };\n\n // ── The group actions menu ────────────────────────────────────────────────\n\n const focusFirstMenuItem = (groupId: string): void => {\n const doc = rootEl?.ownerDocument;\n const item = doc?.getElementById(menuElementId(groupId))?.querySelector<HTMLElement>(FIRST_MENU_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 };\n\n const openGroupMenu = (groupId: string, byKeyboard: boolean): void => {\n setOpenMenu(groupId);\n if (byKeyboard) focusFirstMenuItem(groupId);\n };\n\n /** A click on the trigger of an open menu closes it; a synthesized one (Enter, Space) opens into the menu. */\n const onTriggerClick = (groupId: string, event: MouseEvent & { currentTarget: HTMLButtonElement }): void => {\n if (openMenu() === groupId) {\n setOpenMenu(null);\n return;\n }\n openGroupMenu(groupId, event.detail === 0);\n };\n\n const onTriggerKeyDown = (groupId: string, event: KeyboardEvent & { currentTarget: HTMLButtonElement }): void => {\n if (event.defaultPrevented || event.repeat || event.key !== \"ArrowDown\") return;\n event.preventDefault();\n openGroupMenu(groupId, true);\n };\n\n const canSplit = (groupId: string): boolean => {\n const group = groupById(layout(), groupId);\n return Boolean(group && group.active !== null && group.tabs.length >= 2);\n };\n\n const siblingGroup = (groupId: string, delta: -1 | 1): string | undefined => {\n const list = groups();\n return list[indexOfGroup(groupId) + delta]?.id;\n };\n\n const canMoveToSibling = (groupId: string, delta: -1 | 1): boolean => {\n const group = groupById(layout(), groupId);\n return Boolean(group && group.active !== null && siblingGroup(groupId, delta) !== undefined);\n };\n\n const canShift = (groupId: string, delta: -1 | 1): boolean => {\n const group = groupById(layout(), groupId);\n if (!group || group.active === null) return false;\n const to = group.tabs.indexOf(group.active) + delta;\n return to >= 0 && to < group.tabs.length;\n };\n\n const runMenuAction = (groupId: string, action: MenuAction): void => {\n // Closed first: the menu hands the focus it holds back to the trigger, and the move that\n // follows then takes it on to the tab (D9.2).\n setOpenMenu(null);\n const current = latest;\n const group = groupById(current, groupId);\n const tabId = group?.active;\n if (!group || !tabId) return;\n if (action === \"splitRight\" || action === \"splitDown\") {\n const edge: TabGroupsEdge = action === \"splitRight\" ? \"right\" : \"bottom\";\n commitMove(moveTab(current, tabId, { group: groupId, edge }), current, tabId, groupId, {\n edge,\n focus: true,\n });\n return;\n }\n if (action === \"previous\" || action === \"next\") {\n const to = siblingGroup(groupId, action === \"previous\" ? -1 : 1);\n if (!to) return;\n commitMove(moveTab(current, tabId, { group: to }), current, tabId, groupId, { focus: true });\n return;\n }\n const from = group.tabs.indexOf(tabId);\n const to = from + (action === \"left\" ? -1 : 1);\n if (from < 0 || to < 0 || to >= group.tabs.length) return;\n commitMove(moveTab(current, tabId, { group: groupId, index: to }), current, tabId, groupId, {\n focus: true,\n });\n };\n\n // ── The separators ────────────────────────────────────────────────────────\n\n /** The split's extent along the axis it divides, in percent of the root. */\n const splitExtentPercent = (splitId: string): number => {\n const value = layout();\n const node = findSplitNode(value.root, splitId);\n if (!node) return 0;\n const held = new Set(groupIdsOf(node));\n const entries = grid().groups.filter((entry) => held.has(entry.id));\n if (entries.length === 0) return 0;\n const tracks = node.direction === \"row\" ? grid().columns : grid().rows;\n let from = Number.POSITIVE_INFINITY;\n let to = Number.NEGATIVE_INFINITY;\n entries.forEach((entry) => {\n const span = node.direction === \"row\" ? entry.column : entry.row;\n from = Math.min(from, span[0]);\n to = Math.max(to, span[1]);\n });\n let total = 0;\n for (let index = from; index < to; index += 1) total += tracks[index] ?? 0;\n return total;\n };\n\n /** The same extent in px, measured on the root; 0 when there is nothing to measure. */\n const splitExtentPx = (splitId: string): number => {\n const rect = rootEl?.getBoundingClientRect();\n const node = findSplitNode(layout().root, splitId);\n if (!rect || !node) return 0;\n const axis = node.direction === \"row\" ? rect.width : rect.height;\n return (axis * splitExtentPercent(splitId)) / 100;\n };\n\n /** `minGroupSize` in percent of the split: what `resizeSplit` keeps on both sides. */\n const minSizePercent = (extentPx: number): number => (extentPx > 0 ? (minGroupSize() / extentPx) * 100 : 0);\n\n const resizeChange = (next: TabGroupsLayout, splitId: string): TabGroupsChange => {\n const node = findSplitNode(next.root, splitId);\n return { type: \"resize\", split: splitId, sizes: node ? [...node.sizes] : [] };\n };\n\n const resizeBy = (splitId: string, index: number, delta: number, min: number): void => {\n const current = latest;\n const next = resizeSplit(current, splitId, index, delta, min);\n if (next === current) return;\n commit(next, resizeChange(next, splitId));\n };\n\n const onSeparatorKeyDown =\n (splitId: string, index: number, orientation: \"vertical\" | \"horizontal\") =>\n (event: KeyboardEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (event.defaultPrevented) return;\n const vertical = orientation === \"vertical\";\n const backwards = event.key === (vertical ? \"ArrowLeft\" : \"ArrowUp\");\n const forwards = event.key === (vertical ? \"ArrowRight\" : \"ArrowDown\");\n const limit = event.key === \"Home\" || event.key === \"End\";\n if (!backwards && !forwards && !limit) return;\n event.preventDefault();\n // Home and End go to the limits `minGroupSize` leaves, as ±Infinity asks `resizeSplit` for.\n const delta = limit\n ? event.key === \"Home\"\n ? Number.NEGATIVE_INFINITY\n : Number.POSITIVE_INFINITY\n : backwards\n ? -keyboardStep()\n : keyboardStep();\n resizeBy(splitId, index, delta, minSizePercent(splitExtentPx(splitId)));\n };\n\n // A pointer drag: captured on the separator, throttled to 60fps, and always computed from the\n // layout the drag started at, so the group follows the pointer instead of drifting with it.\n type SeparatorDrag = {\n key: string;\n split: string;\n index: number;\n orientation: \"vertical\" | \"horizontal\";\n pointerId: number;\n start: number;\n extentPx: number;\n min: number;\n layout: TabGroupsLayout;\n };\n let separatorDrag: SeparatorDrag | null = null;\n const coordinate = (event: PointerEvent, orientation: \"vertical\" | \"horizontal\"): number =>\n orientation === \"vertical\" ? event.clientX : event.clientY;\n\n const applySeparatorDrag = (position: number): void => {\n const drag = separatorDrag;\n if (!drag) return;\n const deltaPx = position - drag.start;\n const delta = drag.extentPx > 0 ? (deltaPx / drag.extentPx) * 100 : 0;\n const next = resizeSplit(drag.layout, drag.split, drag.index, delta, drag.min);\n if (next === latest) return;\n commit(next, resizeChange(next, drag.split));\n };\n const throttledSeparatorDrag = throttle(applySeparatorDrag, 1000 / 60);\n\n onCleanup(() => throttledSeparatorDrag.cancel());\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 if (!isServer) {\n createEffect(() => {\n const drag = draggingSeparator();\n if (!drag) return;\n const body = document.body;\n const previous = body.style.cursor;\n body.style.cursor = drag.orientation === \"vertical\" ? \"col-resize\" : \"row-resize\";\n onCleanup(() => {\n body.style.cursor = previous;\n });\n });\n }\n\n const onSeparatorPointerDown =\n (key: string, splitId: string, index: number, orientation: \"vertical\" | \"horizontal\") =>\n (event: PointerEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (isServer || (event.pointerType === \"mouse\" && event.button !== 0)) return;\n const extentPx = splitExtentPx(splitId);\n separatorDrag = {\n key,\n split: splitId,\n index,\n orientation,\n pointerId: event.pointerId,\n start: coordinate(event, orientation),\n extentPx,\n min: minSizePercent(extentPx),\n layout: latest,\n };\n setDraggingSeparator({ key, orientation });\n // With the pointer captured the drag keeps reporting to the grip, however fast it moves.\n const target = event.currentTarget;\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 =\n (orientation: \"vertical\" | \"horizontal\") =>\n (event: PointerEvent & { currentTarget: HTMLElement; target: Element }): void => {\n const drag = separatorDrag;\n if (!drag || drag.pointerId !== event.pointerId) return;\n throttledSeparatorDrag(coordinate(event, orientation));\n };\n\n const onSeparatorPointerUp =\n (orientation: \"vertical\" | \"horizontal\") =>\n (event: PointerEvent & { currentTarget: HTMLElement; target: Element }): void => {\n const drag = separatorDrag;\n if (!drag || drag.pointerId !== event.pointerId) return;\n // The last position, unthrottled: the drag ends where the pointer is, not where the last\n // throttled tick left it.\n throttledSeparatorDrag.cancel();\n applySeparatorDrag(coordinate(event, orientation));\n separatorDrag = null;\n setDraggingSeparator(null);\n if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n // ── Drag and drop ─────────────────────────────────────────────────────────\n\n // A drag this instance started: its tab, the group it left and whether the tab had the focus\n // (which is where the focus goes back to after the drop). Drags from anywhere else — a file, a\n // link, another TabGroups — are left alone.\n let dragState: { tab: string; group: string; hadFocus: boolean } | null = null;\n let markedItem: HTMLElement | null = null;\n let dropTargetsFrame: number | undefined;\n\n onCleanup(() => {\n if (dropTargetsFrame !== undefined) cancelAnimationFrame(dropTargetsFrame);\n });\n\n const markRowItem = (item: HTMLElement | null): void => {\n if (markedItem === item) return;\n markedItem?.classList.remove(\"smwb-tab-item--drop-target\");\n markedItem = 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 group = dragState?.group;\n const header = Array.from(rootEl?.querySelectorAll<HTMLElement>(\":scope > .smwb-tab-groups__header\") ?? []).find(\n (element) => element.getAttribute(\"data-group-id\") === group\n );\n header?.querySelectorAll<HTMLElement>(\".smwb-tab-item--drop-target\").forEach((item) => {\n if (item !== markedItem) item.classList.remove(\"smwb-tab-item--drop-target\");\n });\n };\n\n const clearDropState = (): void => {\n dragState = null;\n if (dropTargetsFrame !== undefined) {\n cancelAnimationFrame(dropTargetsFrame);\n dropTargetsFrame = undefined;\n }\n markRowItem(null);\n setDropGroup(null);\n setDropZone(null);\n setDragging(false);\n };\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 target: Element | null\n ):\n | { kind: \"row\"; group: string; index: number | null; item: HTMLElement | null }\n | { kind: \"body\"; group: string; element: HTMLElement }\n | null => {\n // A drag of another instance's, or of a nested one: not ours to answer for.\n if (!rootEl || !target || target.closest(\".smwb-tab-groups\") !== rootEl) return null;\n const headerEl = target.closest<HTMLElement>(\".smwb-tab-groups__header\");\n if (headerEl) {\n const group = headerEl.getAttribute(\"data-group-id\");\n if (!group) return null;\n const tabEl = tabElementOf(target);\n const overId = tabEl?.getAttribute(\"data-tab-id\");\n const tabs = groupById(latest, group)?.tabs ?? [];\n const at = overId ? tabs.indexOf(overId) : -1;\n return {\n kind: \"row\",\n group,\n index: at >= 0 ? at : null,\n item: at >= 0 && tabEl ? tabItemOf(tabEl) : 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: 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 (groupById(latest, group)?.tabs.length ?? 0) >= 2;\n };\n\n const onRootDragStart = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDragStart, event);\n if (isServer) return;\n const target = event.target;\n if (!(target instanceof Element) || !rootEl || target.closest(\".smwb-tab-groups\") !== rootEl) return;\n // The drag starts on the draggable item wrapper, so the tab is looked for inside it too.\n const tabEl = tabElementOf(target);\n const tabId = tabEl?.getAttribute(\"data-tab-id\");\n // A disabled tab is not draggable (`Tabs` leaves it alone), and neither is anything but a tab.\n if (!tabEl || !tabId || tabEl.getAttribute(\"aria-disabled\") === \"true\") return;\n const group = groupIdOf(tabEl);\n if (!group) return;\n const doc = rootEl.ownerDocument;\n const active = doc.activeElement;\n dragState = {\n tab: tabId,\n group,\n hadFocus: Boolean(active && active !== doc.body && tabItemOf(tabEl).contains(active)),\n };\n // A frame later: changing the DOM inside `dragstart` can cancel the drag in Chromium.\n const view = doc.defaultView;\n if (!view) return;\n dropTargetsFrame = view.requestAnimationFrame(() => {\n dropTargetsFrame = undefined;\n setDragging(true);\n });\n };\n\n const onRootDragOver = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDragOver, event);\n const state = dragState;\n if (!state) return;\n const hit = hitTest(event.target);\n if (!hit) {\n markRowItem(null);\n hideSourceRowMark();\n setDropGroup(null);\n setDropZone(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 === state.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 setDropGroup(null);\n setDropZone(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(state.group, hit.group, zone)) {\n setDropGroup(null);\n setDropZone(null);\n return;\n }\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = \"move\";\n setDropGroup(hit.group);\n setDropZone(zone);\n };\n\n const onRootDrop = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDrop, event);\n const state = dragState;\n if (!state) 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.target);\n const zone = hit && hit.kind === \"body\" ? zoneOf(hit.element, event) : null;\n clearDropState();\n if (!hit) return;\n if (hit.kind === \"row\") {\n if (hit.group === state.group) return;\n const target = hit.index === null ? { group: hit.group } : { group: hit.group, index: hit.index };\n commitMove(moveTab(latest, state.tab, target), latest, state.tab, state.group, {\n focus: state.hadFocus,\n });\n return;\n }\n if (!zone || !bodyDropAllowed(state.group, hit.group, zone)) return;\n const target = zone === \"center\" ? { group: hit.group } : { group: hit.group, edge: zone };\n commitMove(moveTab(latest, state.tab, target), latest, state.tab, state.group, {\n edge: zone === \"center\" ? undefined : zone,\n focus: state.hadFocus,\n });\n };\n\n const onRootDragEnd = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDragEnd, event);\n clearDropState();\n };\n\n /**\n * Follows the focus. The group it is in becomes the active one: new tabs open where the user is\n * (D9.6), and its header is the marked one. A frame of this root it came out of is checked\n * (`frameExitTarget`), and the guard sends it on to the last stop when it came from after the\n * root. A nested `TabGroups` has a root of its own: its guard and its frames are not this root's.\n */\n const onRootFocusIn = (event: FocusEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onFocusIn, event);\n const root = rootEl;\n const target = event.target;\n if (!root || !(target instanceof HTMLElement)) return;\n const previous = lastFocus;\n lastFocus = ownerRootOf(target) === root ? target : null;\n if (previous instanceof HTMLElement && previous.localName === \"iframe\" && previous !== target && !pointerFocus) {\n const instead = frameExitTarget(root, previous, target);\n if (instead !== null && instead === guardEl) {\n // Nothing follows the root: the guard holds the focus, and the next Tab leaves the page.\n leaving = 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 === guardEl) {\n onGuardFocus();\n return;\n }\n const groupId = ownGroupIdOf(root, target);\n if (!groupId || latest.activeGroup === groupId) return;\n commit(setActiveGroup(latest, 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: KeyboardEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onKeyDown, event);\n if (event.defaultPrevented || event.key !== \"Tab\" || event.altKey || event.ctrlKey || event.metaKey) return;\n if (event.isComposing) return;\n const root = rootEl;\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 === guardEl) leaving = true;\n // A move of the key's own, not the browser's way out of a frame.\n lastFocus = 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 onMount(() => {\n const root = rootEl;\n const view = root?.ownerDocument.defaultView;\n if (!root || !view) return;\n let timer: number | undefined;\n const onPointerDown = (): void => {\n pointerFocus = true;\n view.clearTimeout(timer);\n timer = view.setTimeout(() => {\n pointerFocus = false;\n }, 0);\n };\n const onFocusOut = (event: FocusEvent): void => {\n if (event.relatedTarget instanceof Node && !root.contains(event.relatedTarget)) lastFocus = 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) lastFocus = active;\n };\n root.addEventListener(\"pointerdown\", onPointerDown, true);\n root.addEventListener(\"focusout\", onFocusOut);\n view.addEventListener(\"blur\", onWindowBlur);\n onCleanup(() => {\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 if (leaving || !rootEl) return;\n const last = lastStopOf(rootEl);\n if (last) focusFromEnd(last);\n };\n\n // ── The grid ──────────────────────────────────────────────────────────────\n\n const rootStyle = (): JSX.CSSProperties | string | undefined =>\n mergeStyle(local.style, {\n \"grid-template-columns\": gridTemplateColumns(grid()),\n \"grid-template-rows\": gridTemplateRows(grid()),\n });\n\n const headerArea = (groupId: string): string => {\n const placed = grid().groups.find((entry) => entry.id === groupId);\n return placed ? groupHeaderArea(placed) : \"auto\";\n };\n\n const bodyArea = (tabId: string): string => {\n const groupId = groupOfTab().get(tabId);\n const placed = groupId === undefined ? undefined : grid().groups.find((entry) => entry.id === groupId);\n return placed ? groupBodyArea(placed) : \"auto\";\n };\n\n const separatorEntry = (splitId: string, index: number) =>\n grid().separators.find((entry) => entry.split === splitId && entry.index === index);\n\n /** The share of the pair the separator's first neighbour holds, as `aria-valuenow` reads it. */\n const separatorValue = (splitId: string, index: number): number => {\n const node = findSplitNode(layout().root, splitId);\n if (!node) return 0;\n const first = node.sizes[index] ?? 0;\n const pair = first + (node.sizes[index + 1] ?? 0);\n return pair > 0 ? Math.round((first / pair) * 100) : 0;\n };\n\n const dropTargetClass = (groupId: string): string | undefined => {\n const zone = dropGroup() === groupId ? dropZone() : null;\n return zone ? `smwb-tab-groups__drop-target--${zone}` : undefined;\n };\n\n const emptySlot = resolveChildren(() => local.empty);\n\n // ── The keyed children ────────────────────────────────────────────────────\n\n const renderTab = (groupId: string, tabId: string): JSX.Element => {\n const meta = () => local.getTab(tabId);\n const closable = createMemo(() => meta()?.closable !== false);\n // `exactOptionalPropertyTypes`: a prop with no value is left out rather than set to undefined.\n const optional = createMemo(() => {\n const given = meta();\n const extra: Partial<TabProps> = {};\n if (given?.disabled) extra.disabled = true;\n if (given?.closeLabel !== undefined) extra.closeLabel = given.closeLabel;\n if (given?.actions !== undefined) extra.actions = given.actions;\n return extra;\n });\n const shortcuts = createMemo(() => (meta()?.disabled ? undefined : CHORD_SHORTCUTS));\n return (\n <Tab\n {...optional()}\n id={tabElementId(tabId)}\n aria-controls={panelElementId(tabId)}\n data-tab-id={tabId}\n aria-keyshortcuts={shortcuts()}\n label={meta()?.label ?? tabId}\n icon={meta()?.icon}\n closable={closable()}\n onClose={(event, reason) => requestClose(tabId, event, reason)}\n />\n );\n };\n\n const renderHeader = (groupId: string): JSX.Element => {\n const [anchor, setAnchor] = createSignal<HTMLButtonElement | null>(null);\n const group = (): TabGroupsGroup | undefined => groupById(layout(), groupId);\n const tabs = (): string[] => group()?.tabs ?? [];\n const value = (): number => {\n const active = group()?.active;\n if (active === null || active === undefined) return 0;\n const index = tabs().indexOf(active);\n return index < 0 ? 0 : index;\n };\n return (\n <div\n class={cn(\"smwb-tab-groups__header\", {\n \"smwb-tab-groups__header--active\": layout().activeGroup === groupId,\n })}\n id={headerElementId(groupId)}\n data-group-id={groupId}\n style={{ \"grid-area\": headerArea(groupId) }}\n onKeyDown={onHeaderKeyDown(groupId)}\n >\n <Tabs\n class=\"smwb-tab-groups__tabs\"\n value={value()}\n onChange={onRowChange(groupId)}\n onReorder={onRowReorder(groupId)}\n aria-label={labels().group(indexOfGroup(groupId) + 1, groupCount())}\n scrollable\n overflowMenu\n dense={local.dense === true}\n >\n <For each={tabs()}>{(tabId) => renderTab(groupId, tabId)}</For>\n </Tabs>\n <Show when={withGroupActions()}>\n <button\n type=\"button\"\n class=\"smwb-tab-groups__actions-trigger\"\n aria-label={labels().groupActions}\n aria-haspopup=\"menu\"\n aria-expanded={openMenu() === groupId}\n aria-controls={openMenu() === groupId ? menuElementId(groupId) : undefined}\n ref={(el) => setAnchor(() => el)}\n onClick={(event) => onTriggerClick(groupId, event)}\n onKeyDown={(event) => onTriggerKeyDown(groupId, event)}\n >\n <Icon name=\"more_vert\" size={20} />\n </button>\n <Menu\n id={menuElementId(groupId)}\n anchorElement={anchor()}\n isOpen={openMenu() === groupId}\n onClose={() => setOpenMenu(null)}\n placement=\"bottom-end\"\n >\n <MenuItem disabled={!canSplit(groupId)} onClick={() => runMenuAction(groupId, \"splitRight\")}>\n {labels().splitRight}\n </MenuItem>\n <MenuItem disabled={!canSplit(groupId)} onClick={() => runMenuAction(groupId, \"splitDown\")}>\n {labels().splitDown}\n </MenuItem>\n <MenuItem disabled={!canMoveToSibling(groupId, -1)} onClick={() => runMenuAction(groupId, \"previous\")}>\n {labels().moveToPreviousGroup}\n </MenuItem>\n <MenuItem disabled={!canMoveToSibling(groupId, 1)} onClick={() => runMenuAction(groupId, \"next\")}>\n {labels().moveToNextGroup}\n </MenuItem>\n <MenuItem disabled={!canShift(groupId, -1)} onClick={() => runMenuAction(groupId, \"left\")}>\n {labels().moveLeft}\n </MenuItem>\n <MenuItem disabled={!canShift(groupId, 1)} onClick={() => runMenuAction(groupId, \"right\")}>\n {labels().moveRight}\n </MenuItem>\n </Menu>\n </Show>\n </div>\n );\n };\n\n const renderPanelItem = (tabId: string): JSX.Element => {\n // Whether this tab's content is mounted, as a boolean memo: the `Show` below must not run again\n // when another tab mounts, or the panel's content would be created anew and lose its state.\n const mounted = createMemo(() => mountedTabs().has(tabId));\n const selected = createMemo(() => selectedTabs().has(tabId));\n const groupId = createMemo(() => groupOfTab().get(tabId) ?? \"\");\n return (\n <div\n class=\"smwb-tab-panel smwb-tab-groups__panel\"\n role=\"tabpanel\"\n id={panelElementId(tabId)}\n aria-labelledby={tabElementId(tabId)}\n tabindex={0}\n hidden={selected() ? undefined : true}\n data-tab-id={tabId}\n data-group-id={groupId()}\n style={{ \"grid-area\": bodyArea(tabId) }}\n >\n <Show when={mounted()}>\n {local.renderPanel(tabId)}\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 <span class=\"smwb-tab-groups__panel-end\" tabindex={-1} aria-hidden=\"true\" />\n </Show>\n </div>\n );\n };\n\n const renderSeparatorItem = (key: string, splitId: string, index: number): JSX.Element => {\n const entry = () => separatorEntry(splitId, index);\n const orientation = (): \"vertical\" | \"horizontal\" => entry()?.orientation ?? \"vertical\";\n const area = (): string => {\n const placed = entry();\n return placed ? separatorArea(placed) : \"auto\";\n };\n return (\n <div\n class={cn(\"smwb-tab-groups__separator\", `smwb-tab-groups__separator--${orientation()}`, {\n \"smwb-tab-groups__separator--dragging\": draggingSeparator()?.key === key,\n })}\n id={separatorElementId(splitId, index)}\n role=\"separator\"\n tabindex={0}\n aria-orientation={orientation()}\n aria-valuenow={separatorValue(splitId, index)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={labels().resize}\n data-split-id={splitId}\n data-index={index}\n style={{ \"grid-area\": area() }}\n onKeyDown={onSeparatorKeyDown(splitId, index, orientation())}\n onPointerDown={onSeparatorPointerDown(key, splitId, index, orientation())}\n onPointerMove={onSeparatorPointerMove(orientation())}\n onPointerUp={onSeparatorPointerUp(orientation())}\n onPointerCancel={onSeparatorPointerUp(orientation())}\n />\n );\n };\n\n const renderSeparatorKey = (key: string): JSX.Element => {\n const last = key.lastIndexOf(\":\");\n return renderSeparatorItem(key, key.slice(2, last), Number(key.slice(last + 1)));\n };\n\n // The headers, separators and panels: each made once per key and disposed when its key goes. The\n // client places them into the root itself (`placeChildren`), the server prints them in that order,\n // and hydration finds them in place.\n const headerNodes = createMemo(mapArray(() => (isEmpty() ? [] : groupIds()), renderHeader));\n const separatorNodes = createMemo(mapArray(() => (isEmpty() ? [] : separatorKeys()), renderSeparatorKey));\n const panelNodes = createMemo(mapArray(() => (isEmpty() ? [] : panelOrder()), renderPanelItem));\n const childNodes = createMemo(() => [...headerNodes(), ...separatorNodes(), ...panelNodes()]);\n\n return (\n <div\n {...rest}\n ref={mergeRefs(local.ref, (el) => {\n rootEl = el;\n if (isServer) return;\n createRenderEffect<HTMLElement[]>((previous) => {\n const next = childNodes() as HTMLElement[];\n placeChildren(el, next, previous);\n return next;\n }, []);\n })}\n id={base()}\n class={cn(\"smwb-tab-groups\", { \"smwb-tab-groups--split\": hasSplit() }, local.class)}\n style={rootStyle()}\n data-testid={local[\"data-testid\"] ?? \"tab-groups\"}\n aria-owns={owns()}\n onKeyDown={onRootKeyDown}\n onDragStart={onRootDragStart}\n onDragOver={onRootDragOver}\n onDrop={onRootDrop}\n onDragEnd={onRootDragEnd}\n onFocusIn={onRootFocusIn}\n >\n {isServer ? childNodes() : undefined}\n <Show when={isEmpty()}>\n <div class=\"smwb-tab-groups__empty\">{emptySlot()}</div>\n </Show>\n <Show when={dragging()}>\n <For each={grid().groups}>\n {(placed) => (\n <div\n class={cn(\"smwb-tab-groups__drop-target\", dropTargetClass(placed.id))}\n data-group-id={placed.id}\n aria-hidden=\"true\"\n style={{ \"grid-area\": groupBodyArea(placed) }}\n />\n )}\n </For>\n </Show>\n <Show when={!isEmpty()}>\n {/* The root's last Tab stop, which only ever holds the focus on its way in or out. */}\n <span\n ref={(el) => (guardEl = el)}\n class=\"smwb-tab-groups__focus-guard\"\n tabindex={0}\n onBlur={() => {\n leaving = false;\n }}\n />\n </Show>\n <div\n id={statusElementId()}\n class=\"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\nexport default TabGroups;\n"],"mappings":"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","names":["to","group","target"],"file":"tabGroups.jsx"}
1
+ {"version":3,"sources":["../../../../../src/components/layout/tabGroups/tabGroups.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/tabGroups/tabGroups.entry.less\";\nimport {\n type JSX,\n For,\n Show,\n children as resolveChildren,\n createComputed,\n createEffect,\n createMemo,\n createRenderEffect,\n createSignal,\n createUniqueId,\n mapArray,\n on,\n onCleanup,\n onMount,\n splitProps,\n} from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { Tabs } from \"../../navigation/tabs/tabs\";\nimport { Tab } from \"../../navigation/tabs/tab/tab\";\nimport type { TabCloseReason, TabProps } from \"../../navigation/tabs/tab/tab\";\nimport { Menu } from \"../../navigation/menu/menu\";\nimport { MenuItem } from \"../../navigation/menu/menuItem\";\nimport { Icon } from \"../../base/icon\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\nimport { createControllableState } from \"../../../primitives/createControllableState\";\nimport { callHandler } from \"../../../primitives/callHandler\";\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 TabGroupsNode,\n type TabGroupsSplit,\n} from \"./tabGroupsLayout\";\nimport {\n containsDeep,\n deepActiveElement,\n focusFromEnd,\n frameExitTarget,\n lastStopOf,\n ownGroupIdOf,\n ownerRootOf,\n slotFocusHeir,\n slotFocusOf,\n tabMove,\n type TabGroupsSlotFocus,\n} from \"./tabGroupsFocus\";\n\n/**\n * What a tab of `TabGroups` shows, answered by the app through `getTab`. Only the tab's id lives in\n * the layout, so a stored arrangement survives renames and carries no content.\n */\nexport interface TabGroupsTab {\n /** The tab's label. A tab id the app does not know is drawn as the id itself. */\n label: JSX.Element;\n /**\n * Plain text for the announcements and for a screen reader that cannot read the label (markup,\n * an icon). `label` when it is a string, else the tab id. With `fit` it is also the tab's `title`, the\n * tooltip of a label that is not a string; a string label is its own tooltip, so leave `title` out for it.\n */\n title?: string | undefined;\n /** An icon drawn before the label. */\n icon?: JSX.Element;\n /**\n * Draw a close button and let Delete or Backspace close the tab: true by default. `false` keeps\n * the tab's item wrapper, so every tab has the same drag surface.\n */\n closable?: boolean | undefined;\n /** Accessible label of the tab's close button (\"Close Terminal 1\"). */\n closeLabel?: string | undefined;\n /** Content after the tab, as `Tab`'s `actions`: a trigger with a `Menu`, or any control. */\n actions?: TabProps[\"actions\"];\n /** Greys the tab out: it cannot be selected, moved or dragged. */\n disabled?: boolean | undefined;\n}\n\n/**\n * What `stripActions` is asked about: the group whose tab row the content goes into. The fields\n * are getters that always give the current value (see `stripActions`).\n */\nexport interface TabGroupsStripGroup {\n /** The group's place among the groups in reading order, from 0. */\n readonly index: number;\n /** How many groups there are. */\n readonly count: number;\n /** Whether this is the group in use, the one the user works in (the header marked when there are two groups or more). */\n readonly active: boolean;\n}\n\nexport interface TabGroupsProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"children\" | \"onChange\" | \"id\"> {\n /**\n * The arrangement to draw: the split tree, every group's tabs and the selected one. Controlled\n * while it is not `undefined` — the component then only reports changes through\n * `onLayoutChange` and draws what the owner gives back.\n */\n layout?: TabGroupsLayout | undefined;\n /** The arrangement to start from while uncontrolled: one empty group by default. */\n defaultLayout?: TabGroupsLayout | undefined;\n /**\n * Called with the layout after a change and with what happened, in both the controlled and the\n * uncontrolled mode. A controlled owner that does not apply the change simply sees nothing move.\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. It is called the first time the tab is selected and\n * the panel stays mounted from then on, hidden while another tab is shown and kept through a\n * move to another group: a form keeps what was typed, a terminal its scrollback. Its node stays\n * where it is in the DOM, so an iframe in it does not reload either.\n */\n renderPanel: (tabId: string) => JSX.Element;\n /**\n * Asked before a tab closes, with what asked for it (its close button, Delete or Backspace, a\n * middle click, its `actions`). Return `false` to keep the tab.\n */\n onTabClose?: ((tabId: string, event: Event, reason: TabCloseReason) => boolean | void) | undefined;\n /** Drawn, centred, when the only group has no tabs left. */\n empty?: JSX.Element;\n /** The smallest a group can be resized to, in px of its split; 120 by default. */\n minGroupSize?: number | undefined;\n /** The arrow-key step of a separator, in percent of its split; 5 by default. */\n keyboardStep?: number | undefined;\n /** Draw each group's actions button and menu; true by default. */\n groupActions?: boolean | undefined;\n /**\n * Content at the end of a group's tab row, before the group's actions button: buttons that act on\n * the group (\"new terminal\", \"split\"). Called for every group with `{ index, count, active }`:\n * its place from 0, how many groups there are and whether it is the one in use, so the app can\n * return content for some groups only; `null`, `undefined`, `false` or an empty fragment draws\n * nothing, not even a wrapper. The tabs scroll beside it while the content stays in view; in a\n * header too narrow for both, the tabs give way first, then the content is clipped at its end, and\n * the group's actions button stays. It comes after the tabs in the Tab order, and the tab row's\n * arrow keys neither enter it nor read the keys pressed in it.\n *\n * The function runs once per header, and the group's fields are getters, read like props: read\n * in the content (`<Show when={group.active}>`, `{group.count}`) they update it in place, so its\n * nodes, their state and the focus stay; read in the function's body (`group.active ? … : null`)\n * they make it run again, with new content, when that value changes. Read the layout itself in\n * the handlers.\n *\n * A slot control that has the focus when a change takes it out of the document (a split or a\n * close from the slot, the slot going to the group in use) hands the focus on: to the control at\n * the same place in its group's slot, else in the slot of the group in use (the last one when\n * there are fewer), else to that group's selected tab.\n */\n stripActions?: ((group: TabGroupsStripGroup) => JSX.Element) | undefined;\n /** Compact tab rows, as `Tabs`' `dense`; false by default. */\n dense?: boolean | undefined;\n /**\n * Content-width tabs, as `Tabs`' `fit`; false by default. Each tab is as wide as its marker,\n * label and close button, between `--smui-tabFitMinWidth` and `--smui-tabFitMaxWidth`, and what is\n * left of the header stays empty: `stripActions` and the group's actions button keep the end of\n * it. A long label is cut with an ellipsis and shows its text as a tooltip: a string label is its\n * own, and the tab's `title` is the tooltip of a label that is not a string.\n */\n fit?: boolean | undefined;\n /** The texts of the component: its menus, labels and announcements. English by default. */\n labels?: Partial<TabGroupsLabels> | undefined;\n /** Base of the generated ids and the id of the root element. Generated by default. */\n id?: string | undefined;\n /** Test id of the root element; `tab-groups` unless given. */\n \"data-testid\"?: string | undefined;\n /** Class of the root element, added to the component's own. */\n class?: string | undefined;\n /** Inline style of the root element; the component's `grid-template-*` win over it. */\n style?: JSX.HTMLAttributes<HTMLDivElement>[\"style\"];\n /** The root element. */\n ref?: Ref<HTMLDivElement>;\n}\n\n/** The chords a group's tabs answer to, as `aria-keyshortcuts` lists them. */\nconst CHORD_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 keys that move a tab to the group (or the new group) at that edge. */\nconst DIRECTION_CHORDS: [TabGroupsEdge, string[]][] = [\n [\"left\", [\"Alt\", \"Shift\", \"ArrowLeft\"]],\n [\"right\", [\"Alt\", \"Shift\", \"ArrowRight\"]],\n [\"top\", [\"Alt\", \"Shift\", \"ArrowUp\"]],\n [\"bottom\", [\"Alt\", \"Shift\", \"ArrowDown\"]],\n];\n\n/** Whether a resolved child draws anything: `null`, `undefined`, booleans and an empty string do not. */\nconst present = (node: unknown): boolean => node != null && typeof node !== \"boolean\" && node !== \"\";\n\n/** The item of an opened menu that takes focus first (as `Tab`'s actions look for it). */\nconst FIRST_MENU_ITEM = '[role^=\"menuitem\"]:not([aria-disabled=\"true\"])';\n\n/** What a group's actions menu can do; every item acts on the group's selected tab. */\ntype MenuAction = \"splitRight\" | \"splitDown\" | \"previous\" | \"next\" | \"left\" | \"right\";\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 an event landed on. `Tabs` makes the item wrapper draggable, so a real drag reports the\n * wrapper — not the tab — as its target: the tab is then found inside it, and an event on the tab\n * or on its label is still resolved by walking up.\n */\nfunction tabElementOf(target: Element | null): HTMLElement | null {\n if (!target) return null;\n const direct = target.closest<HTMLElement>('[role=\"tab\"]');\n if (direct) return direct;\n const item = target.closest<HTMLElement>(\".smwb-tab-item\");\n return item?.querySelector<HTMLElement>('[role=\"tab\"]') ?? null;\n}\n\n/** The split node with this id, if the tree has one. */\nfunction findSplitNode(root: TabGroupsNode, id: string): TabGroupsSplit | undefined {\n if (root.type === \"group\") return undefined;\n if (root.id === id) return root;\n for (const child of root.children) {\n const found = findSplitNode(child, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** The ids of the groups a node holds. */\nfunction groupIdsOf(node: TabGroupsNode): string[] {\n return node.type === \"group\" ? [node.id] : node.children.flatMap(groupIdsOf);\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/**\n * Puts the root's headers, separators and panels at its start, in the given order, moving none\n * that can stay. Solid's list diff may take a kept node out and put it back, and a browser treats\n * that as a removal: a focused tab in a header blurs to nowhere and a scrolled tab row goes back\n * to its start. So the nodes already in order among themselves stay where they are (the longest\n * such run, always including the one that holds the focus), and only the others are inserted, or\n * moved, around them. `previous` is what was placed before: the nodes of it that are gone go.\n */\nfunction placeChildren(parent: HTMLElement, next: readonly HTMLElement[], previous: readonly HTMLElement[]): void {\n const wanted = new Set<Element>(next);\n previous.forEach((node) => {\n if (!wanted.has(node) && node.parentNode === parent) node.remove();\n });\n const children = Array.from(parent.children);\n const position = new Map<Element, number>();\n children.forEach((child, at) => position.set(child, at));\n\n const active = parent.ownerDocument.activeElement;\n const focused = active === null ? -1 : next.findIndex((node) => node.contains(active));\n const focusedAt = focused < 0 ? undefined : position.get(next[focused]!);\n // The nodes already in the root, in their new order; with a focused one, only those that can\n // stay on the same side of it as before.\n const kept: number[] = [];\n next.forEach((node, i) => {\n const at = position.get(node);\n if (at === undefined) return;\n if (focusedAt !== undefined && i !== focused && i < focused !== at < focusedAt) return;\n kept.push(at);\n });\n // The longest run of them in ascending place stays put (a few dozen nodes, so quadratic is fine).\n const length = kept.map(() => 1);\n const before = kept.map(() => -1);\n let best = -1;\n kept.forEach((at, k) => {\n for (let j = 0; j < k; j++) {\n if (kept[j]! < at && length[j]! + 1 > length[k]!) {\n length[k] = length[j]! + 1;\n before[k] = j;\n }\n }\n if (best < 0 || length[k]! > length[best]!) best = k;\n });\n const stays = new Set<number>();\n for (let k = best; k >= 0; k = before[k]!) stays.add(kept[k]!);\n\n // The last node goes after the last one that stays — or, with none staying, at the root's start,\n // before what Solid draws there (the empty state, the drop targets, the guard, the status).\n let anchor: Node | null = stays.size > 0 ? children[Math.max(...stays)]!.nextSibling : parent.firstChild;\n for (let i = next.length - 1; i >= 0; i--) {\n const node = next[i]!;\n const at = position.get(node);\n if (at === undefined || !stays.has(at)) parent.insertBefore(node, anchor);\n anchor = node;\n }\n}\n\n/** The tabs the layout shows: one per group. */\nfunction selectedTabsOf(layout: TabGroupsLayout): string[] {\n return getGroups(layout)\n .map((group) => group.active)\n .filter((tab): tab is string => tab !== null);\n}\n\n/**\n * Tab groups in a split area: one component draws every group, each a tab row with its panels.\n *\n * The area splits right or down into groups, a tab moves to another group by drag and drop or by\n * keyboard, dropping it on a group's edge makes a new group there, and closing a group's last tab\n * closes the group and collapses its split. The whole arrangement is a serialisable, versioned\n * `layout` (`layout` / `defaultLayout` / `onLayoutChange`) that an app stores as JSON;\n * `tabGroupsLayout.parseTabGroupsLayout` reads one back, and `tabGroupsLayout.addTab` /\n * `syncTabs` keep it in step with the tabs the app has open.\n *\n * Everything is drawn on one CSS grid whose children are a flat, keyed list, so restructuring the\n * tree re-places nodes instead of remounting them, and a panel's node never moves: it keeps its\n * state, its scroll and the focus inside it when its tab moves to another group or the area splits.\n *\n * Without a mouse: Alt+Shift+Arrow moves the focused tab to the group that way (splitting there\n * when the area ends), Mod+Shift+ArrowLeft/Right moves it along its row, each group's actions\n * button opens a menu of the same actions, and each separator resizes with the arrow keys, Home\n * and End. Every move is announced in a polite status region.\n */\nexport function TabGroups(props: TabGroupsProps): JSX.Element {\n const [local, rest] = splitProps(props, [\n \"class\",\n \"style\",\n \"id\",\n \"data-testid\",\n \"ref\",\n \"layout\",\n \"defaultLayout\",\n \"onLayoutChange\",\n \"getTab\",\n \"renderPanel\",\n \"onTabClose\",\n \"empty\",\n \"minGroupSize\",\n \"keyboardStep\",\n \"groupActions\",\n \"stripActions\",\n \"dense\",\n \"fit\",\n \"labels\",\n // Wrapped so that the caller's handler still runs, first.\n \"onDragStart\",\n \"onDragOver\",\n \"onDrop\",\n \"onDragEnd\",\n \"onFocusIn\",\n \"onKeyDown\",\n ]);\n\n const generatedId = createUniqueId();\n const base = (): string => local.id ?? generatedId;\n const encode = (id: string): string => encodeURIComponent(id);\n const tabElementId = (tabId: string): string => `${base()}-tab-${encode(tabId)}`;\n const panelElementId = (tabId: string): string => `${base()}-panel-${encode(tabId)}`;\n const menuElementId = (groupId: string): string => `${base()}-menu-${encode(groupId)}`;\n const headerElementId = (groupId: string): string => `${base()}-header-${encode(groupId)}`;\n const separatorElementId = (splitId: string, index: number): string =>\n `${base()}-separator-${encode(splitId)}-${index}`;\n const statusElementId = (): string => `${base()}-status`;\n\n const minGroupSize = (): number => local.minGroupSize ?? 120;\n const keyboardStep = (): number => local.keyboardStep ?? 5;\n const withGroupActions = (): boolean => local.groupActions !== false;\n const labels = createMemo(\n (): TabGroupsLabels => ({\n ...TAB_GROUPS_LABELS,\n ...local.labels,\n })\n );\n\n // The library's controlled-state rule: controlled while `layout` is not undefined, own state\n // while it is. `latest` is the layout the next change is computed from, so two changes in one\n // event (a drop and the selection that follows it, a chord and the focus it moves) compose\n // instead of the second overwriting the first. It is reset to the drawn value whenever that\n // changes and — while controlled — once the event is over (`settle`): a change the owner did\n // not draw is forgotten, so the next one neither reports it nor reads its rows.\n const [layout, setLayout] = createControllableState<TabGroupsLayout>({\n value: () => local.layout,\n defaultValue: local.defaultLayout ?? createTabGroupsLayout(),\n });\n let latest: TabGroupsLayout = layout();\n createComputed(() => {\n latest = layout();\n });\n\n const grid = createMemo(() => computeTabGroupsGrid(layout()));\n const groups = createMemo(() => getGroups(layout()));\n const groupCount = createMemo(() => groups().length);\n const hasSplit = createMemo(() => groups().length > 1);\n const selectedTabs = createMemo(() => new Set(selectedTabsOf(layout())));\n const groupOfTab = createMemo(() => {\n const map = new Map<string, string>();\n getGroups(layout()).forEach((group) => group.tabs.forEach((tab) => map.set(tab, group.id)));\n return map;\n });\n const groupById = (value: TabGroupsLayout, groupId: string): TabGroupsGroup | undefined =>\n getGroups(value).find((group) => group.id === groupId);\n const indexOfGroup = (groupId: string): number => groups().findIndex((group) => group.id === groupId);\n\n // Nothing open: the one group has no tabs, so the `empty` slot takes the area.\n const isEmpty = createMemo((): boolean => {\n const list = groups();\n return list.length === 1 && (list[0]?.tabs.length ?? 0) === 0;\n });\n\n // The grid's children, each placed by its `grid-area` alone: the headers in reading order, the\n // separators, then the panels in the order they first appeared — a new one at the end, never\n // reordered. A move only changes a panel's `grid-area`, so its node stays where it is: putting it\n // back into the document would reset its scroll, reload an iframe in it and blur the focus inside\n // it. Tab order and the accessibility tree follow the reading order (`onRootKeyDown`, `aria-owns`),\n // and no header or separator that keeps its place among the others is moved either (`placeChildren`).\n const groupIds = createMemo((): string[] => groups().map((group) => group.id));\n const separatorKeys = createMemo((): string[] => readingKeys(layout().root).filter((key) => key.startsWith(\"s:\")));\n const panelOrder = createMemo<string[]>((previous) => {\n const alive = groupOfTab();\n const order = previous.filter((tab) => alive.has(tab));\n const placed = new Set(order);\n groups().forEach((group) =>\n group.tabs.forEach((tab) => {\n if (placed.has(tab)) return;\n placed.add(tab);\n order.push(tab);\n })\n );\n return order.length === previous.length && order.every((tab, index) => tab === previous[index]) ? previous : order;\n }, []);\n const owns = createMemo((): string | undefined => {\n if (isEmpty()) return undefined;\n const value = layout();\n return [\n ...readingKeys(value.root).flatMap((key) => {\n if (key.startsWith(\"h:\")) return [headerElementId(key.slice(2))];\n if (key.startsWith(\"p:\")) return (groupById(value, 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 statusElementId(),\n ].join(\" \");\n });\n\n // The panels that stay mounted: the selected tabs of the layout drawn now (the same set on the\n // server and the client), plus every tab that was selected before, minus the closed ones.\n const [mountedTabs, setMountedTabs] = createSignal<Set<string>>(new Set(selectedTabsOf(layout())));\n if (!isServer) {\n createEffect(() => {\n const value = layout();\n const alive = new Set<string>();\n getGroups(value).forEach((group) => group.tabs.forEach((tab) => alive.add(tab)));\n const selected = selectedTabsOf(value);\n setMountedTabs((prev) => {\n const next = new Set<string>();\n let changed = false;\n prev.forEach((tab) => {\n if (alive.has(tab)) next.add(tab);\n else changed = true;\n });\n selected.forEach((tab) => {\n if (!next.has(tab)) {\n next.add(tab);\n changed = true;\n }\n });\n return changed || next.size !== prev.size ? next : prev;\n });\n });\n }\n\n const [status, setStatus] = createSignal(\"\");\n const [openMenu, setOpenMenu] = createSignal<string | null>(null);\n const [dragging, setDragging] = createSignal(false);\n const [dropGroup, setDropGroup] = createSignal<string | null>(null);\n const [dropZone, setDropZone] = createSignal<TabGroupsDropZone | null>(null);\n const [draggingSeparator, setDraggingSeparator] = createSignal<{\n key: string;\n orientation: \"vertical\" | \"horizontal\";\n } | null>(null);\n\n let rootEl: HTMLDivElement | undefined;\n let guardEl: HTMLSpanElement | undefined;\n // The tab to focus once its move has been drawn: a keyboard chord, a menu action, a drop of a\n // tab that had focus, or the group that takes the space of a closed one (D9) — which is then\n // `gone`, and has to be gone from the drawn layout before the focus moves. It waits for the next\n // layout the owner draws that answers the change (`after`; `base` is the one drawn when it was\n // asked for), however late, and that layout either shows the change (the tab in `group` at\n // `index`) or not; `from` had the focus then.\n let pendingFocus: {\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 reported = new WeakMap<TabGroupsLayout, number>();\n let reportCount = 0;\n let settleQueued = false;\n // The focus guard is taking the focus on its way out of the root: not a reason to send it back.\n let leaving = false;\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 let lastFocus: Element | null = null;\n let pointerFocus = false;\n // The `stripActions` control that has the focus, and where it is: a change that takes it out of\n // the document would drop the focus to the page, so its heir takes it (`restoreSlotFocus`).\n let slotFocus: TabGroupsSlotFocus | null = null;\n\n const announce = (next: TabGroupsLayout, change: TabGroupsChange): void => {\n const text = describeTabGroupsChange(change, next, tabTitle, labels());\n if (text === \"\") return;\n // The same text twice in a row is not read again: a trailing no-break space makes it new.\n setStatus((prev) => (prev.replace(/\\u00a0+$/, \"\") === text ? `${text}\\u00a0` : text));\n };\n\n /** Asks for a tab's focus once `next`, the layout a change produced, is drawn; `gone` is a closed group. */\n const armFocus = (tabId: string, next: TabGroupsLayout, gone?: string): void => {\n const group = findGroupOfTab(next, tabId);\n if (!group) return;\n pendingFocus = {\n tab: tabId,\n group: group.id,\n index: group.tabs.indexOf(tabId),\n ...(gone === undefined ? {} : { gone }),\n after: next,\n base: layout(),\n from: rootEl ? deepActiveElement(rootEl.ownerDocument) : null,\n };\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 = reported.get(drawn);\n const askedAt = reported.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 — and only when that layout shows the change and the\n * focus is still with the layout (or still where it was). Then the request is done either way,\n * so a change the owner never drew moves no focus later.\n */\n const focusPending = (): void => {\n const pending = pendingFocus;\n const drawn = layout();\n if (!pending || stillWaiting(pending, drawn)) return;\n const doc = rootEl?.ownerDocument;\n const group = findGroupOfTab(drawn, pending.tab);\n const shown =\n group?.id === pending.group &&\n group.tabs.indexOf(pending.tab) === pending.index &&\n (pending.gone === undefined || !groupById(drawn, pending.gone));\n const element = shown ? doc?.getElementById(tabElementId(pending.tab)) : null;\n // Drawn, but not in the document yet (an update still running): the effect after it asks again.\n if (shown && (!element || groupIdOf(element) !== pending.group)) return;\n pendingFocus = null;\n if (!element || !rootEl || !doc) return;\n const active = deepActiveElement(doc);\n if (active === element) return;\n if (active !== null && active !== doc.body && active !== pending.from && !containsDeep(rootEl, active)) return;\n element.focus();\n };\n\n /**\n * The slot control that had the focus left the document with a change: the focus, which fell to\n * the page, goes to its heir (`slotFocusHeir`). Nothing moves when it is somewhere else by now.\n */\n const restoreSlotFocus = (): void => {\n const lost = slotFocus;\n if (!lost || !rootEl || lost.element.isConnected) return;\n slotFocus = null;\n const doc = rootEl.ownerDocument;\n const active = deepActiveElement(doc);\n if (active !== null && active !== doc.body) return;\n slotFocusHeir(rootEl, lost, layout().activeGroup)?.focus();\n };\n\n /**\n * The record of the slot control that had the focus is forgotten once the control is gone: a\n * change of the layout asks this before it draws, so a control that left by itself (an app hid\n * its button) is not one the change took away, and its heir does not pull the focus from the page.\n */\n const forgetGoneSlotFocus = (): void => {\n if (slotFocus && !slotFocus.element.isConnected) slotFocus = null;\n };\n\n const commit = (next: TabGroupsLayout, change: TabGroupsChange): void => {\n if (next === latest) return;\n latest = next;\n reportCount += 1;\n reported.set(next, reportCount);\n setLayout(() => next);\n local.onLayoutChange?.(next, change);\n announce(next, change);\n focusPending();\n if (local.layout !== undefined && !settleQueued) {\n settleQueued = true;\n queueMicrotask(settle);\n }\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. Two changes of one event — a drop and `Tabs`' report of it, a commit and the `focusin`\n * it causes — still compose. The focus move waits for the owner's next layout (`focusPending`).\n */\n const settle = (): void => {\n settleQueued = false;\n if (local.layout === undefined || latest === layout()) return;\n latest = layout();\n };\n\n // An owner that applies a change later than the event (a timeout) draws it here.\n if (!isServer) {\n // Before the DOM follows the layout (computeds run ahead of the render effects), so a control\n // that the change itself takes away is still in the document here.\n createComputed(() => {\n layout();\n forgetGoneSlotFocus();\n });\n createEffect(\n on(\n layout,\n () => {\n focusPending();\n restoreSlotFocus();\n },\n { defer: true }\n )\n );\n }\n\n const tabTitle = (tabId: string): string => {\n const meta = local.getTab(tabId);\n if (!meta) return tabId;\n if (meta.title !== undefined) return meta.title;\n return typeof meta.label === \"string\" ? meta.label : tabId;\n };\n\n /** What `moveTab` did, told from the two layouts: a reorder, a move or a split. */\n const commitMove = (\n next: TabGroupsLayout,\n before: TabGroupsLayout,\n tabId: string,\n from: string,\n options: { edge?: TabGroupsEdge | undefined; focus?: boolean | undefined } = {}\n ): void => {\n if (next === before) return;\n const to = findGroupOfTab(next, tabId)?.id;\n const target = to !== undefined ? groupById(next, to) : undefined;\n if (!to || !target) return;\n const sourceClosed = !getGroups(next).some((group) => group.id === from);\n const existed = getGroups(before).some((group) => group.id === to);\n const change: TabGroupsChange =\n options.edge !== undefined && !existed\n ? { type: \"split\", tab: tabId, from, to, edge: options.edge, sourceClosed }\n : { type: \"move\", tab: tabId, from, to, index: target.tabs.indexOf(tabId), sourceClosed };\n if (options.focus) armFocus(tabId, next);\n commit(next, change);\n };\n\n // ── The tab rows ──────────────────────────────────────────────────────────\n\n const onRowChange =\n (groupId: string) =>\n (event: MouseEvent & { currentTarget: HTMLElement; target: Element }, index: number): void => {\n // A drop of the selected tab reports its new index through `onChange` as well; the selection\n // is by id and already right, so the index — counted before the move — is not read.\n if (event.type === \"drop\") return;\n const current = latest;\n const group = groupById(current, groupId);\n const tabId = group?.tabs[index];\n if (!group || tabId === undefined) return;\n commit(selectTab(current, tabId), { type: \"select\", tab: tabId, group: groupId });\n };\n\n const onRowReorder =\n (groupId: string) =>\n (from: number, to: number): void => {\n const current = latest;\n const group = groupById(current, groupId);\n const tabId = group?.tabs[from];\n if (!group || tabId === undefined) return;\n // A reorder is a move within the row: the selection stays, and the tab that had the focus\n // keeps it (Tabs puts it back itself, this is the same request for a move it cannot see).\n commitMove(moveTab(current, tabId, { group: groupId, index: to }), current, tabId, groupId, {\n focus: dragState?.hadFocus ?? false,\n });\n };\n\n const requestClose = (tabId: string, event: Event, reason: TabCloseReason): void => {\n const current = latest;\n const group = findGroupOfTab(current, tabId);\n if (!group) return;\n if (local.onTabClose?.(tabId, event, reason) === false) return;\n const next = removeTab(current, tabId);\n if (next === current) return;\n const groupClosed = !getGroups(next).some((candidate) => candidate.id === group.id);\n // A group that goes with its last tab takes the focus with it: the group that fills the space\n // gets it, but only when the focus was in the group that went (or the close came from its\n // `actions` menu, drawn outside it). Anywhere else the focus stays where it is. A tab that\n // leaves its group alive is Tabs' own focus move.\n const root = rootEl;\n const active = root ? deepActiveElement(root.ownerDocument) : null;\n const focusWasHere = reason === \"actions\" || (root !== undefined && ownGroupIdOf(root, active) === group.id);\n const heir = groupClosed && focusWasHere ? adjacentGroup(current, group.id) : undefined;\n if (heir !== undefined) {\n const heirTab = groupById(next, heir)?.active;\n if (heirTab) armFocus(heirTab, next, group.id);\n }\n commit(next, { type: \"close\", tab: tabId, group: group.id, groupClosed });\n };\n\n // The chords sit on the header, where they catch the key that bubbles up from the tab; the row's\n // own keys (arrows, Enter, Delete, Mod+W, Mod+Shift+[/]) are Tabs' and run first.\n const onHeaderKeyDown =\n (groupId: string) =>\n (event: KeyboardEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (event.defaultPrevented || event.repeat || event.isComposing) return;\n const target = event.target;\n if (!(target instanceof Element)) return;\n const tabEl = target.closest<HTMLElement>('[role=\"tab\"]');\n if (!tabEl || groupIdOf(tabEl) !== groupId) return;\n if (tabEl.getAttribute(\"aria-disabled\") === \"true\") return;\n const tabId = tabEl.getAttribute(\"data-tab-id\");\n if (!tabId) return;\n const current = latest;\n const group = groupById(current, groupId);\n if (!group) return;\n\n for (const [edge, keys] of DIRECTION_CHORDS) {\n if (!matchesKeyboardShortcut(event, keys)) continue;\n const next = moveTabInDirection(current, tabId, edge);\n // Nothing to do (the area ends here and the tab is alone): the key is left alone too.\n if (next === current) return;\n event.preventDefault();\n commitMove(next, current, tabId, groupId, { edge, focus: true });\n return;\n }\n const shift = matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"ArrowLeft\"])\n ? -1\n : matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"ArrowRight\"])\n ? 1\n : 0;\n if (shift === 0) return;\n const from = group.tabs.indexOf(tabId);\n const to = from + shift;\n if (from < 0 || to < 0 || to >= group.tabs.length) return;\n event.preventDefault();\n commitMove(moveTab(current, tabId, { group: groupId, index: to }), current, tabId, groupId, {\n focus: true,\n });\n };\n\n // ── The group actions menu ────────────────────────────────────────────────\n\n const focusFirstMenuItem = (groupId: string): void => {\n const doc = rootEl?.ownerDocument;\n const item = doc?.getElementById(menuElementId(groupId))?.querySelector<HTMLElement>(FIRST_MENU_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 };\n\n const openGroupMenu = (groupId: string, byKeyboard: boolean): void => {\n setOpenMenu(groupId);\n if (byKeyboard) focusFirstMenuItem(groupId);\n };\n\n /** A click on the trigger of an open menu closes it; a synthesized one (Enter, Space) opens into the menu. */\n const onTriggerClick = (groupId: string, event: MouseEvent & { currentTarget: HTMLButtonElement }): void => {\n if (openMenu() === groupId) {\n setOpenMenu(null);\n return;\n }\n openGroupMenu(groupId, event.detail === 0);\n };\n\n const onTriggerKeyDown = (groupId: string, event: KeyboardEvent & { currentTarget: HTMLButtonElement }): void => {\n if (event.defaultPrevented || event.repeat || event.key !== \"ArrowDown\") return;\n event.preventDefault();\n openGroupMenu(groupId, true);\n };\n\n const canSplit = (groupId: string): boolean => {\n const group = groupById(layout(), groupId);\n return Boolean(group && group.active !== null && group.tabs.length >= 2);\n };\n\n const siblingGroup = (groupId: string, delta: -1 | 1): string | undefined => {\n const list = groups();\n return list[indexOfGroup(groupId) + delta]?.id;\n };\n\n const canMoveToSibling = (groupId: string, delta: -1 | 1): boolean => {\n const group = groupById(layout(), groupId);\n return Boolean(group && group.active !== null && siblingGroup(groupId, delta) !== undefined);\n };\n\n const canShift = (groupId: string, delta: -1 | 1): boolean => {\n const group = groupById(layout(), groupId);\n if (!group || group.active === null) return false;\n const to = group.tabs.indexOf(group.active) + delta;\n return to >= 0 && to < group.tabs.length;\n };\n\n const runMenuAction = (groupId: string, action: MenuAction): void => {\n // Closed first: the menu hands the focus it holds back to the trigger, and the move that\n // follows then takes it on to the tab (D9.2).\n setOpenMenu(null);\n const current = latest;\n const group = groupById(current, groupId);\n const tabId = group?.active;\n if (!group || !tabId) return;\n if (action === \"splitRight\" || action === \"splitDown\") {\n const edge: TabGroupsEdge = action === \"splitRight\" ? \"right\" : \"bottom\";\n commitMove(moveTab(current, tabId, { group: groupId, edge }), current, tabId, groupId, {\n edge,\n focus: true,\n });\n return;\n }\n if (action === \"previous\" || action === \"next\") {\n const to = siblingGroup(groupId, action === \"previous\" ? -1 : 1);\n if (!to) return;\n commitMove(moveTab(current, tabId, { group: to }), current, tabId, groupId, { focus: true });\n return;\n }\n const from = group.tabs.indexOf(tabId);\n const to = from + (action === \"left\" ? -1 : 1);\n if (from < 0 || to < 0 || to >= group.tabs.length) return;\n commitMove(moveTab(current, tabId, { group: groupId, index: to }), current, tabId, groupId, {\n focus: true,\n });\n };\n\n // ── The separators ────────────────────────────────────────────────────────\n\n /** The split's extent along the axis it divides, in percent of the root. */\n const splitExtentPercent = (splitId: string): number => {\n const value = layout();\n const node = findSplitNode(value.root, splitId);\n if (!node) return 0;\n const held = new Set(groupIdsOf(node));\n const entries = grid().groups.filter((entry) => held.has(entry.id));\n if (entries.length === 0) return 0;\n const tracks = node.direction === \"row\" ? grid().columns : grid().rows;\n let from = Number.POSITIVE_INFINITY;\n let to = Number.NEGATIVE_INFINITY;\n entries.forEach((entry) => {\n const span = node.direction === \"row\" ? entry.column : entry.row;\n from = Math.min(from, span[0]);\n to = Math.max(to, span[1]);\n });\n let total = 0;\n for (let index = from; index < to; index += 1) total += tracks[index] ?? 0;\n return total;\n };\n\n /** The same extent in px, measured on the root; 0 when there is nothing to measure. */\n const splitExtentPx = (splitId: string): number => {\n const rect = rootEl?.getBoundingClientRect();\n const node = findSplitNode(layout().root, splitId);\n if (!rect || !node) return 0;\n const axis = node.direction === \"row\" ? rect.width : rect.height;\n return (axis * splitExtentPercent(splitId)) / 100;\n };\n\n /** `minGroupSize` in percent of the split: what `resizeSplit` keeps on both sides. */\n const minSizePercent = (extentPx: number): number => (extentPx > 0 ? (minGroupSize() / extentPx) * 100 : 0);\n\n const resizeChange = (next: TabGroupsLayout, splitId: string): TabGroupsChange => {\n const node = findSplitNode(next.root, splitId);\n return { type: \"resize\", split: splitId, sizes: node ? [...node.sizes] : [] };\n };\n\n const resizeBy = (splitId: string, index: number, delta: number, min: number): void => {\n const current = latest;\n const next = resizeSplit(current, splitId, index, delta, min);\n if (next === current) return;\n commit(next, resizeChange(next, splitId));\n };\n\n const onSeparatorKeyDown =\n (splitId: string, index: number, orientation: \"vertical\" | \"horizontal\") =>\n (event: KeyboardEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (event.defaultPrevented) return;\n const vertical = orientation === \"vertical\";\n const backwards = event.key === (vertical ? \"ArrowLeft\" : \"ArrowUp\");\n const forwards = event.key === (vertical ? \"ArrowRight\" : \"ArrowDown\");\n const limit = event.key === \"Home\" || event.key === \"End\";\n if (!backwards && !forwards && !limit) return;\n event.preventDefault();\n // Home and End go to the limits `minGroupSize` leaves, as ±Infinity asks `resizeSplit` for.\n const delta = limit\n ? event.key === \"Home\"\n ? Number.NEGATIVE_INFINITY\n : Number.POSITIVE_INFINITY\n : backwards\n ? -keyboardStep()\n : keyboardStep();\n resizeBy(splitId, index, delta, minSizePercent(splitExtentPx(splitId)));\n };\n\n // A pointer drag: captured on the separator, throttled to 60fps, and always computed from the\n // layout the drag started at, so the group follows the pointer instead of drifting with it.\n type SeparatorDrag = {\n key: string;\n split: string;\n index: number;\n orientation: \"vertical\" | \"horizontal\";\n pointerId: number;\n start: number;\n extentPx: number;\n min: number;\n layout: TabGroupsLayout;\n };\n let separatorDrag: SeparatorDrag | null = null;\n const coordinate = (event: PointerEvent, orientation: \"vertical\" | \"horizontal\"): number =>\n orientation === \"vertical\" ? event.clientX : event.clientY;\n\n const applySeparatorDrag = (position: number): void => {\n const drag = separatorDrag;\n if (!drag) return;\n const deltaPx = position - drag.start;\n const delta = drag.extentPx > 0 ? (deltaPx / drag.extentPx) * 100 : 0;\n const next = resizeSplit(drag.layout, drag.split, drag.index, delta, drag.min);\n if (next === latest) return;\n commit(next, resizeChange(next, drag.split));\n };\n const throttledSeparatorDrag = throttle(applySeparatorDrag, 1000 / 60);\n\n onCleanup(() => throttledSeparatorDrag.cancel());\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 if (!isServer) {\n createEffect(() => {\n const drag = draggingSeparator();\n if (!drag) return;\n const body = document.body;\n const previous = body.style.cursor;\n body.style.cursor = drag.orientation === \"vertical\" ? \"col-resize\" : \"row-resize\";\n onCleanup(() => {\n body.style.cursor = previous;\n });\n });\n }\n\n const onSeparatorPointerDown =\n (key: string, splitId: string, index: number, orientation: \"vertical\" | \"horizontal\") =>\n (event: PointerEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (isServer || (event.pointerType === \"mouse\" && event.button !== 0)) return;\n const extentPx = splitExtentPx(splitId);\n separatorDrag = {\n key,\n split: splitId,\n index,\n orientation,\n pointerId: event.pointerId,\n start: coordinate(event, orientation),\n extentPx,\n min: minSizePercent(extentPx),\n layout: latest,\n };\n setDraggingSeparator({ key, orientation });\n // With the pointer captured the drag keeps reporting to the grip, however fast it moves.\n const target = event.currentTarget;\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 =\n (orientation: \"vertical\" | \"horizontal\") =>\n (event: PointerEvent & { currentTarget: HTMLElement; target: Element }): void => {\n const drag = separatorDrag;\n if (!drag || drag.pointerId !== event.pointerId) return;\n throttledSeparatorDrag(coordinate(event, orientation));\n };\n\n const onSeparatorPointerUp =\n (orientation: \"vertical\" | \"horizontal\") =>\n (event: PointerEvent & { currentTarget: HTMLElement; target: Element }): void => {\n const drag = separatorDrag;\n if (!drag || drag.pointerId !== event.pointerId) return;\n // The last position, unthrottled: the drag ends where the pointer is, not where the last\n // throttled tick left it.\n throttledSeparatorDrag.cancel();\n applySeparatorDrag(coordinate(event, orientation));\n separatorDrag = null;\n setDraggingSeparator(null);\n if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n // ── Drag and drop ─────────────────────────────────────────────────────────\n\n // A drag this instance started: its tab, the group it left and whether the tab had the focus\n // (which is where the focus goes back to after the drop). Drags from anywhere else — a file, a\n // link, another TabGroups — are left alone.\n let dragState: { tab: string; group: string; hadFocus: boolean } | null = null;\n let markedItem: HTMLElement | null = null;\n let dropTargetsFrame: number | undefined;\n\n onCleanup(() => {\n if (dropTargetsFrame !== undefined) cancelAnimationFrame(dropTargetsFrame);\n });\n\n const markRowItem = (item: HTMLElement | null): void => {\n if (markedItem === item) return;\n markedItem?.classList.remove(\"smwb-tab-item--drop-target\");\n markedItem = 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 group = dragState?.group;\n const header = Array.from(rootEl?.querySelectorAll<HTMLElement>(\":scope > .smwb-tab-groups__header\") ?? []).find(\n (element) => element.getAttribute(\"data-group-id\") === group\n );\n header?.querySelectorAll<HTMLElement>(\".smwb-tab-item--drop-target\").forEach((item) => {\n if (item !== markedItem) item.classList.remove(\"smwb-tab-item--drop-target\");\n });\n };\n\n const clearDropState = (): void => {\n dragState = null;\n if (dropTargetsFrame !== undefined) {\n cancelAnimationFrame(dropTargetsFrame);\n dropTargetsFrame = undefined;\n }\n markRowItem(null);\n setDropGroup(null);\n setDropZone(null);\n setDragging(false);\n };\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 target: Element | null\n ):\n | { kind: \"row\"; group: string; index: number | null; item: HTMLElement | null }\n | { kind: \"body\"; group: string; element: HTMLElement }\n | null => {\n // A drag of another instance's, or of a nested one: not ours to answer for.\n if (!rootEl || !target || target.closest(\".smwb-tab-groups\") !== rootEl) return null;\n const headerEl = target.closest<HTMLElement>(\".smwb-tab-groups__header\");\n if (headerEl) {\n const group = headerEl.getAttribute(\"data-group-id\");\n if (!group) return null;\n const tabEl = tabElementOf(target);\n const overId = tabEl?.getAttribute(\"data-tab-id\");\n const tabs = groupById(latest, group)?.tabs ?? [];\n const at = overId ? tabs.indexOf(overId) : -1;\n return {\n kind: \"row\",\n group,\n index: at >= 0 ? at : null,\n item: at >= 0 && tabEl ? tabItemOf(tabEl) : 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: 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 (groupById(latest, group)?.tabs.length ?? 0) >= 2;\n };\n\n const onRootDragStart = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDragStart, event);\n if (isServer) return;\n const target = event.target;\n if (!(target instanceof Element) || !rootEl || target.closest(\".smwb-tab-groups\") !== rootEl) return;\n // The drag starts on the draggable item wrapper, so the tab is looked for inside it too.\n const tabEl = tabElementOf(target);\n const tabId = tabEl?.getAttribute(\"data-tab-id\");\n // A disabled tab is not draggable (`Tabs` leaves it alone), and neither is anything but a tab.\n if (!tabEl || !tabId || tabEl.getAttribute(\"aria-disabled\") === \"true\") return;\n const group = groupIdOf(tabEl);\n if (!group) return;\n const doc = rootEl.ownerDocument;\n const active = doc.activeElement;\n dragState = {\n tab: tabId,\n group,\n hadFocus: Boolean(active && active !== doc.body && tabItemOf(tabEl).contains(active)),\n };\n // A frame later: changing the DOM inside `dragstart` can cancel the drag in Chromium.\n const view = doc.defaultView;\n if (!view) return;\n dropTargetsFrame = view.requestAnimationFrame(() => {\n dropTargetsFrame = undefined;\n setDragging(true);\n });\n };\n\n const onRootDragOver = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDragOver, event);\n const state = dragState;\n if (!state) return;\n const hit = hitTest(event.target);\n if (!hit) {\n markRowItem(null);\n hideSourceRowMark();\n setDropGroup(null);\n setDropZone(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 === state.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 setDropGroup(null);\n setDropZone(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(state.group, hit.group, zone)) {\n setDropGroup(null);\n setDropZone(null);\n return;\n }\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = \"move\";\n setDropGroup(hit.group);\n setDropZone(zone);\n };\n\n const onRootDrop = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDrop, event);\n const state = dragState;\n if (!state) 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.target);\n const zone = hit && hit.kind === \"body\" ? zoneOf(hit.element, event) : null;\n clearDropState();\n if (!hit) return;\n if (hit.kind === \"row\") {\n if (hit.group === state.group) return;\n const target = hit.index === null ? { group: hit.group } : { group: hit.group, index: hit.index };\n commitMove(moveTab(latest, state.tab, target), latest, state.tab, state.group, {\n focus: state.hadFocus,\n });\n return;\n }\n if (!zone || !bodyDropAllowed(state.group, hit.group, zone)) return;\n const target = zone === \"center\" ? { group: hit.group } : { group: hit.group, edge: zone };\n commitMove(moveTab(latest, state.tab, target), latest, state.tab, state.group, {\n edge: zone === \"center\" ? undefined : zone,\n focus: state.hadFocus,\n });\n };\n\n const onRootDragEnd = (event: DragEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onDragEnd, event);\n clearDropState();\n };\n\n /**\n * Follows the focus. The group it is in becomes the active one: new tabs open where the user is\n * (D9.6), and its header is the marked one. A frame of this root it came out of is checked\n * (`frameExitTarget`), and the guard sends it on to the last stop when it came from after the\n * root. A nested `TabGroups` has a root of its own: its guard and its frames are not this root's.\n */\n const onRootFocusIn = (event: FocusEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onFocusIn, event);\n const root = rootEl;\n const target = event.target;\n if (!root || !(target instanceof HTMLElement)) return;\n const previous = lastFocus;\n lastFocus = ownerRootOf(target) === root ? target : null;\n slotFocus = lastFocus === null ? null : slotFocusOf(root, target);\n if (previous instanceof HTMLElement && previous.localName === \"iframe\" && previous !== target && !pointerFocus) {\n const instead = frameExitTarget(root, previous, target);\n if (instead !== null && instead === guardEl) {\n // Nothing follows the root: the guard holds the focus, and the next Tab leaves the page.\n leaving = 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 === guardEl) {\n onGuardFocus();\n return;\n }\n const groupId = ownGroupIdOf(root, target);\n if (!groupId || latest.activeGroup === groupId) return;\n commit(setActiveGroup(latest, 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: KeyboardEvent & { currentTarget: HTMLDivElement; target: Element }): void => {\n callHandler(local.onKeyDown, event);\n if (event.defaultPrevented || event.key !== \"Tab\" || event.altKey || event.ctrlKey || event.metaKey) return;\n if (event.isComposing) return;\n const root = rootEl;\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 === guardEl) leaving = true;\n // A move of the key's own, not the browser's way out of a frame.\n lastFocus = 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 onMount(() => {\n const root = rootEl;\n const view = root?.ownerDocument.defaultView;\n if (!root || !view) return;\n let timer: number | undefined;\n const onPointerDown = (): void => {\n pointerFocus = true;\n view.clearTimeout(timer);\n timer = view.setTimeout(() => {\n pointerFocus = false;\n }, 0);\n };\n const onFocusOut = (event: FocusEvent): void => {\n if (event.relatedTarget instanceof Node && !root.contains(event.relatedTarget)) {\n lastFocus = null;\n slotFocus = null;\n return;\n }\n // To nowhere: a blur (a click on the page, the window left) forgets the slot control; its\n // removal (Chromium blurs an element it removes) does not, as that is what the heir is for.\n const lost = slotFocus;\n if (event.relatedTarget === null && lost?.element === event.target) {\n queueMicrotask(() => {\n if (slotFocus === lost && lost.element.isConnected) slotFocus = null;\n });\n }\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) lastFocus = active;\n };\n root.addEventListener(\"pointerdown\", onPointerDown, true);\n root.addEventListener(\"focusout\", onFocusOut);\n view.addEventListener(\"blur\", onWindowBlur);\n onCleanup(() => {\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 if (leaving || !rootEl) return;\n const last = lastStopOf(rootEl);\n if (last) focusFromEnd(last);\n };\n\n // ── The grid ──────────────────────────────────────────────────────────────\n\n const rootStyle = (): JSX.CSSProperties | string | undefined =>\n mergeStyle(local.style, {\n \"grid-template-columns\": gridTemplateColumns(grid()),\n \"grid-template-rows\": gridTemplateRows(grid()),\n });\n\n const headerArea = (groupId: string): string => {\n const placed = grid().groups.find((entry) => entry.id === groupId);\n return placed ? groupHeaderArea(placed) : \"auto\";\n };\n\n const bodyArea = (tabId: string): string => {\n const groupId = groupOfTab().get(tabId);\n const placed = groupId === undefined ? undefined : grid().groups.find((entry) => entry.id === groupId);\n return placed ? groupBodyArea(placed) : \"auto\";\n };\n\n const separatorEntry = (splitId: string, index: number) =>\n grid().separators.find((entry) => entry.split === splitId && entry.index === index);\n\n /** The share of the pair the separator's first neighbour holds, as `aria-valuenow` reads it. */\n const separatorValue = (splitId: string, index: number): number => {\n const node = findSplitNode(layout().root, splitId);\n if (!node) return 0;\n const first = node.sizes[index] ?? 0;\n const pair = first + (node.sizes[index + 1] ?? 0);\n return pair > 0 ? Math.round((first / pair) * 100) : 0;\n };\n\n const dropTargetClass = (groupId: string): string | undefined => {\n const zone = dropGroup() === groupId ? dropZone() : null;\n return zone ? `smwb-tab-groups__drop-target--${zone}` : undefined;\n };\n\n const emptySlot = resolveChildren(() => local.empty);\n\n // ── The keyed children ────────────────────────────────────────────────────\n\n const renderTab = (groupId: string, tabId: string): JSX.Element => {\n const meta = () => local.getTab(tabId);\n const closable = createMemo(() => meta()?.closable !== false);\n // `exactOptionalPropertyTypes`: a prop with no value is left out rather than set to undefined.\n const optional = createMemo(() => {\n const given = meta();\n const extra: Partial<TabProps> = {};\n if (given?.disabled) extra.disabled = true;\n if (given?.closeLabel !== undefined) extra.closeLabel = given.closeLabel;\n if (given?.actions !== undefined) extra.actions = given.actions;\n // Only a content-width row cuts labels, so only there is the text a tooltip.\n if (local.fit === true && given?.title !== undefined) extra.title = given.title;\n return extra;\n });\n const shortcuts = createMemo(() => (meta()?.disabled ? undefined : CHORD_SHORTCUTS));\n return (\n <Tab\n {...optional()}\n id={tabElementId(tabId)}\n aria-controls={panelElementId(tabId)}\n data-tab-id={tabId}\n aria-keyshortcuts={shortcuts()}\n label={meta()?.label ?? tabId}\n icon={meta()?.icon}\n closable={closable()}\n onClose={(event, reason) => requestClose(tabId, event, reason)}\n />\n );\n };\n\n const renderHeader = (groupId: string): JSX.Element => {\n const [anchor, setAnchor] = createSignal<HTMLButtonElement | null>(null);\n const group = (): TabGroupsGroup | undefined => groupById(layout(), groupId);\n const tabs = (): string[] => group()?.tabs ?? [];\n const value = (): number => {\n const active = group()?.active;\n if (active === null || active === undefined) return 0;\n const index = tabs().indexOf(active);\n return index < 0 ? 0 : index;\n };\n // The strip slot is read here, once, where the header is drawn, and its wrapper only when it\n // holds something. The group is passed with getters: the app's function runs again only when a\n // value it read in its body changes, and what it reads in its content updates in place.\n const stripIndex = createMemo(() => indexOfGroup(groupId));\n const stripActive = createMemo(() => layout().activeGroup === groupId);\n const stripGroup: TabGroupsStripGroup = {\n get index() {\n return stripIndex();\n },\n get count() {\n return groupCount();\n },\n get active() {\n return stripActive();\n },\n };\n const strip = resolveChildren(() => local.stripActions?.(stripGroup));\n const hasStrip = (): boolean => strip.toArray().some(present);\n return (\n <div\n class={cn(\"smwb-tab-groups__header\", {\n \"smwb-tab-groups__header--active\": layout().activeGroup === groupId,\n })}\n id={headerElementId(groupId)}\n data-group-id={groupId}\n style={{ \"grid-area\": headerArea(groupId) }}\n onKeyDown={onHeaderKeyDown(groupId)}\n >\n <Tabs\n class=\"smwb-tab-groups__tabs\"\n value={value()}\n onChange={onRowChange(groupId)}\n onReorder={onRowReorder(groupId)}\n aria-label={labels().group(indexOfGroup(groupId) + 1, groupCount())}\n scrollable\n overflowMenu\n dense={local.dense === true}\n fit={local.fit === true}\n >\n <For each={tabs()}>{(tabId) => renderTab(groupId, tabId)}</For>\n </Tabs>\n <Show when={hasStrip()}>\n <div class=\"smwb-tab-groups__strip-actions\">{strip()}</div>\n </Show>\n <Show when={withGroupActions()}>\n <button\n type=\"button\"\n class=\"smwb-tab-groups__actions-trigger\"\n aria-label={labels().groupActions}\n aria-haspopup=\"menu\"\n aria-expanded={openMenu() === groupId}\n aria-controls={openMenu() === groupId ? menuElementId(groupId) : undefined}\n ref={(el) => setAnchor(() => el)}\n onClick={(event) => onTriggerClick(groupId, event)}\n onKeyDown={(event) => onTriggerKeyDown(groupId, event)}\n >\n <Icon name=\"more_vert\" size={20} />\n </button>\n <Menu\n id={menuElementId(groupId)}\n anchorElement={anchor()}\n isOpen={openMenu() === groupId}\n onClose={() => setOpenMenu(null)}\n placement=\"bottom-end\"\n >\n <MenuItem disabled={!canSplit(groupId)} onClick={() => runMenuAction(groupId, \"splitRight\")}>\n {labels().splitRight}\n </MenuItem>\n <MenuItem disabled={!canSplit(groupId)} onClick={() => runMenuAction(groupId, \"splitDown\")}>\n {labels().splitDown}\n </MenuItem>\n <MenuItem disabled={!canMoveToSibling(groupId, -1)} onClick={() => runMenuAction(groupId, \"previous\")}>\n {labels().moveToPreviousGroup}\n </MenuItem>\n <MenuItem disabled={!canMoveToSibling(groupId, 1)} onClick={() => runMenuAction(groupId, \"next\")}>\n {labels().moveToNextGroup}\n </MenuItem>\n <MenuItem disabled={!canShift(groupId, -1)} onClick={() => runMenuAction(groupId, \"left\")}>\n {labels().moveLeft}\n </MenuItem>\n <MenuItem disabled={!canShift(groupId, 1)} onClick={() => runMenuAction(groupId, \"right\")}>\n {labels().moveRight}\n </MenuItem>\n </Menu>\n </Show>\n </div>\n );\n };\n\n const renderPanelItem = (tabId: string): JSX.Element => {\n // Whether this tab's content is mounted, as a boolean memo: the `Show` below must not run again\n // when another tab mounts, or the panel's content would be created anew and lose its state.\n const mounted = createMemo(() => mountedTabs().has(tabId));\n const selected = createMemo(() => selectedTabs().has(tabId));\n const groupId = createMemo(() => groupOfTab().get(tabId) ?? \"\");\n return (\n <div\n class=\"smwb-tab-panel smwb-tab-groups__panel\"\n role=\"tabpanel\"\n id={panelElementId(tabId)}\n aria-labelledby={tabElementId(tabId)}\n tabindex={0}\n hidden={selected() ? undefined : true}\n data-tab-id={tabId}\n data-group-id={groupId()}\n style={{ \"grid-area\": bodyArea(tabId) }}\n >\n <Show when={mounted()}>\n {local.renderPanel(tabId)}\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 <span class=\"smwb-tab-groups__panel-end\" tabindex={-1} aria-hidden=\"true\" />\n </Show>\n </div>\n );\n };\n\n const renderSeparatorItem = (key: string, splitId: string, index: number): JSX.Element => {\n const entry = () => separatorEntry(splitId, index);\n const orientation = (): \"vertical\" | \"horizontal\" => entry()?.orientation ?? \"vertical\";\n const area = (): string => {\n const placed = entry();\n return placed ? separatorArea(placed) : \"auto\";\n };\n return (\n <div\n class={cn(\"smwb-tab-groups__separator\", `smwb-tab-groups__separator--${orientation()}`, {\n \"smwb-tab-groups__separator--dragging\": draggingSeparator()?.key === key,\n })}\n id={separatorElementId(splitId, index)}\n role=\"separator\"\n tabindex={0}\n aria-orientation={orientation()}\n aria-valuenow={separatorValue(splitId, index)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={labels().resize}\n data-split-id={splitId}\n data-index={index}\n style={{ \"grid-area\": area() }}\n onKeyDown={onSeparatorKeyDown(splitId, index, orientation())}\n onPointerDown={onSeparatorPointerDown(key, splitId, index, orientation())}\n onPointerMove={onSeparatorPointerMove(orientation())}\n onPointerUp={onSeparatorPointerUp(orientation())}\n onPointerCancel={onSeparatorPointerUp(orientation())}\n />\n );\n };\n\n const renderSeparatorKey = (key: string): JSX.Element => {\n const last = key.lastIndexOf(\":\");\n return renderSeparatorItem(key, key.slice(2, last), Number(key.slice(last + 1)));\n };\n\n // The headers, separators and panels: each made once per key and disposed when its key goes. The\n // client places them into the root itself (`placeChildren`), the server prints them in that order,\n // and hydration finds them in place.\n const headerNodes = createMemo(mapArray(() => (isEmpty() ? [] : groupIds()), renderHeader));\n const separatorNodes = createMemo(mapArray(() => (isEmpty() ? [] : separatorKeys()), renderSeparatorKey));\n const panelNodes = createMemo(mapArray(() => (isEmpty() ? [] : panelOrder()), renderPanelItem));\n const childNodes = createMemo(() => [...headerNodes(), ...separatorNodes(), ...panelNodes()]);\n\n return (\n <div\n {...rest}\n ref={mergeRefs(local.ref, (el) => {\n rootEl = el;\n if (isServer) return;\n createRenderEffect<HTMLElement[]>((previous) => {\n const next = childNodes() as HTMLElement[];\n placeChildren(el, next, previous);\n return next;\n }, []);\n })}\n id={base()}\n class={cn(\"smwb-tab-groups\", { \"smwb-tab-groups--split\": hasSplit() }, local.class)}\n style={rootStyle()}\n data-testid={local[\"data-testid\"] ?? \"tab-groups\"}\n aria-owns={owns()}\n onKeyDown={onRootKeyDown}\n onDragStart={onRootDragStart}\n onDragOver={onRootDragOver}\n onDrop={onRootDrop}\n onDragEnd={onRootDragEnd}\n onFocusIn={onRootFocusIn}\n >\n {isServer ? childNodes() : undefined}\n <Show when={isEmpty()}>\n <div class=\"smwb-tab-groups__empty\">{emptySlot()}</div>\n </Show>\n <Show when={dragging()}>\n <For each={grid().groups}>\n {(placed) => (\n <div\n class={cn(\"smwb-tab-groups__drop-target\", dropTargetClass(placed.id))}\n data-group-id={placed.id}\n aria-hidden=\"true\"\n style={{ \"grid-area\": groupBodyArea(placed) }}\n />\n )}\n </For>\n </Show>\n <Show when={!isEmpty()}>\n {/* The root's last Tab stop, which only ever holds the focus on its way in or out. */}\n <span\n ref={(el) => (guardEl = el)}\n class=\"smwb-tab-groups__focus-guard\"\n tabindex={0}\n onBlur={() => {\n leaving = false;\n }}\n />\n </Show>\n <div\n id={statusElementId()}\n class=\"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\nexport default TabGroups;\n"],"mappings":"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","names":["to","group","target"],"file":"tabGroups.jsx"}
@@ -206,6 +206,46 @@ function frameExitTarget(root, frame, landed) {
206
206
  const wanted = enter(children, index + 1, 1, null)?.element ?? stopAfter(root) ?? guard;
207
207
  return wanted === landed && landed !== guard ? null : wanted;
208
208
  }
209
+ const HEADER_CLASS = "smwb-tab-groups__header";
210
+ const STRIP_CLASS = "smwb-tab-groups__strip-actions";
211
+ function headerOf(root, groupId) {
212
+ for (const child of Array.from(root.children)) {
213
+ if (child.classList.contains(HEADER_CLASS) && child.getAttribute("data-group-id") === groupId) {
214
+ return child;
215
+ }
216
+ }
217
+ return null;
218
+ }
219
+ function slotOf(header) {
220
+ return Array.from(header.children).find((child) => child.classList.contains(STRIP_CLASS));
221
+ }
222
+ function slotStops(header) {
223
+ const slot = slotOf(header);
224
+ const stops = [];
225
+ if (!slot) return stops;
226
+ for (const element of walk(slot)) {
227
+ if (element !== slot && isStopFrom(element, null)) stops.push(element);
228
+ }
229
+ return stops;
230
+ }
231
+ function slotFocusOf(root, element) {
232
+ const header = rootChildOf(root, element);
233
+ const group = header?.classList.contains(HEADER_CLASS) ? header.getAttribute("data-group-id") : null;
234
+ const slot = header ? slotOf(header) : void 0;
235
+ if (!header || group === null || group === void 0 || !slot || !containsDeep(slot, element)) return null;
236
+ const stops = slotStops(header);
237
+ const at = stops.indexOf(element);
238
+ const index = at >= 0 ? at : stops.filter((stop) => (stop.compareDocumentPosition(element) & 4) !== 0).length;
239
+ return { element, group, index };
240
+ }
241
+ function slotFocusHeir(root, lost, activeGroup) {
242
+ for (const groupId of [lost.group, activeGroup]) {
243
+ const header = headerOf(root, groupId);
244
+ const stops = header ? slotStops(header) : [];
245
+ if (stops.length > 0) return stops[Math.min(lost.index, stops.length - 1)] ?? null;
246
+ }
247
+ return headerOf(root, activeGroup)?.querySelector('[role="tab"][aria-selected="true"]') ?? null;
248
+ }
209
249
  export {
210
250
  containsDeep,
211
251
  deepActiveElement,
@@ -217,6 +257,8 @@ export {
217
257
  ownerRootOf,
218
258
  readingChildren,
219
259
  rootChildOf,
260
+ slotFocusHeir,
261
+ slotFocusOf,
220
262
  tabMove
221
263
  };
222
264
  //# sourceMappingURL=tabGroupsFocus.js.map