@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,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/components/layout/tabGroups/tabGroupsFocus.ts"],
4
- "sourcesContent": ["/**\n * The Tab order of `TabGroups`, read from the DOM alone: no framework here, and the file is a\n * byte-identical copy in ui-react and ui-solid.\n *\n * The root keeps its panels in the DOM in the order they first appeared, so the DOM order of its\n * children is not the reading order; the root's `aria-owns` lists them in reading order. Inside one\n * child \u2014 a header, a panel, a separator \u2014 DOM order is reading order, so there the browser moves\n * the focus itself, with every rule of its own (a radio group is one stop, a frame is entered at\n * its first or its last stop, a shadow tree is walked in place). Only a press that would leave a\n * child is taken over: it goes to the next child in reading order, to the stop the browser would\n * pick there by the same rules. A `TabGroups` nested in a panel is that panel's content: its own\n * root answers for the moves inside it, first.\n */\n\nconst ROOT_CLASS = \"smwb-tab-groups\";\nconst GUARD_SELECTOR = \":scope > .smwb-tab-groups__focus-guard\";\nconst PANEL_END_SELECTOR = \":scope > .smwb-tab-groups__panel-end\";\nconst READING_CHILD = \".smwb-tab-groups__header, .smwb-tab-groups__panel, .smwb-tab-groups__separator\";\n\n/** What can take focus from the Tab key, as a browser decides it. */\nconst FOCUSABLE =\n 'a[href], area[href], button, input, select, textarea, iframe, summary, audio[controls], video[controls], [contenteditable]:not([contenteditable=\"false\"]), [tabindex]';\n\n/** A browser's move of the Tab key, taken over: focus `element`, then stop there (`prevent`) or let the browser go on from it. */\nexport interface TabGroupsTabMove {\n element: HTMLElement;\n prevent: boolean;\n}\n\n/** The parent of a node across a shadow root's boundary: the host. */\nfunction parentOf(node: Node): Element | null {\n if (node.parentElement) return node.parentElement;\n const parent = node.parentNode as (Node & { host?: Element }) | null;\n return parent?.nodeType === 11 && parent.host ? parent.host : null;\n}\n\nfunction elementOf(node: Node | null): Element | null {\n if (!node) return null;\n return node.nodeType === 1 ? (node as Element) : parentOf(node);\n}\n\n/** Whether `node` is `ancestor` or inside it, shadow trees included. */\nexport function containsDeep(ancestor: Node, node: Node | null): boolean {\n for (let current: Node | null = node; current; current = parentOf(current)) {\n if (current === ancestor) return true;\n }\n return false;\n}\n\n/** The element that has the focus, inside shadow trees too: where the browser's Tab starts from. */\nexport function deepActiveElement(doc: Document): Element | null {\n let active = doc.activeElement;\n while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;\n return active;\n}\n\n/** The `TabGroups` root a node is in: the nearest one around it, or the node itself when it is one. */\nexport function ownerRootOf(node: Node | null): HTMLElement | null {\n for (let current = elementOf(node); current; current = parentOf(current)) {\n if (current.classList.contains(ROOT_CLASS)) return current as HTMLElement;\n }\n return null;\n}\n\n/** The child of `root` a node is in \u2014 a header, a panel, a separator, the guard \u2014 or null. */\nexport function rootChildOf(root: Element, node: Node | null): HTMLElement | null {\n let current = elementOf(node);\n while (current && parentOf(current) !== root) current = parentOf(current);\n return current as HTMLElement | null;\n}\n\n/** The group a node is in, told by the root's own child: a nested `TabGroups`' groups are not this root's. */\nexport function ownGroupIdOf(root: Element, node: Node | null): string | null {\n return rootChildOf(root, node)?.getAttribute(\"data-group-id\") ?? null;\n}\n\n/** The root's guard, its last Tab stop, which only holds the focus on its way in or out. */\nexport function guardOf(root: HTMLElement): HTMLElement | null {\n return root.querySelector<HTMLElement>(GUARD_SELECTOR);\n}\n\n/** The root's headers, shown panels and separators in reading order, as its `aria-owns` lists them. */\nexport function readingChildren(root: HTMLElement): HTMLElement[] {\n const doc = root.ownerDocument;\n return (root.getAttribute(\"aria-owns\") ?? \"\").split(/\\s+/).flatMap((id) => {\n const element = id ? doc.getElementById(id) : null;\n return element && element.parentElement === root && !element.hidden && element.matches(READING_CHILD)\n ? [element]\n : [];\n });\n}\n\n/** Whether an element is drawn: a browser skips what is not (`display: none` from a stylesheet); jsdom draws nothing. */\nfunction isDrawn(element: Element): boolean {\n return typeof element.checkVisibility !== \"function\" || element.checkVisibility({ visibilityProperty: true });\n}\n\nfunction tabIndexOf(element: Element): number {\n const value = (element as Partial<HTMLElement>).tabIndex;\n return typeof value === \"number\" ? value : -1;\n}\n\n/** A scroller is a Tab stop of its own in Chromium when nothing inside it takes the focus. */\nfunction isScrollerStop(element: Element): boolean {\n if (element.scrollHeight <= element.clientHeight && element.scrollWidth <= element.clientWidth) return false;\n const style = element.ownerDocument.defaultView?.getComputedStyle(element);\n const scrolls = (value: string | undefined): boolean => value === \"auto\" || value === \"scroll\";\n return Boolean(style && (scrolls(style.overflowY) || scrolls(style.overflowX)) && !element.querySelector(FOCUSABLE));\n}\n\n/**\n * Whether the Tab key stops at an element, radio groups aside: focusable, in the sequence of\n * `tabindex` 0 (-1 is out of it, and above 0 the browser visits before everything else), enabled\n * and drawn \u2014 or a scroller with nothing focusable inside.\n */\nfunction isStop(element: Element): element is HTMLElement {\n if (element.matches(FOCUSABLE)) {\n if (tabIndexOf(element) !== 0 || element.matches(\":disabled\")) return false;\n if (element.localName === \"input\" && (element as HTMLInputElement).type === \"hidden\") return false;\n return isDrawn(element);\n }\n return isScrollerStop(element);\n}\n\nfunction isRadio(element: Element): element is HTMLInputElement {\n return element.localName === \"input\" && (element as HTMLInputElement).type === \"radio\";\n}\n\n/** Radios of one group: the same name (an unnamed radio is a group of its own), the same form, the same tree. */\nfunction sameGroup(a: HTMLInputElement, b: HTMLInputElement): boolean {\n return a === b || (a.name !== \"\" && a.name === b.name && a.form === b.form && a.getRootNode() === b.getRootNode());\n}\n\n/** The checked radio of a radio's group, wherever it is drawn, or null. */\nfunction checkedOf(radio: HTMLInputElement): HTMLInputElement | null {\n if (radio.checked) return radio;\n if (radio.name === \"\") return null;\n const scope = radio.form ?? (radio.getRootNode() as Document | ShadowRoot);\n const members: Element[] = radio.form ? Array.from(radio.form.elements) : Array.from(scope.querySelectorAll(\"input\"));\n return (\n members.find(\n (member): member is HTMLInputElement => isRadio(member) && member.checked && sameGroup(radio, member)\n ) ?? null\n );\n}\n\n/**\n * A radio group is one stop: its checked radio, or with none checked every radio of it (so the\n * first one going forwards, the last one going backwards), and none of the group the focus is in.\n */\nfunction isRadioStop(radio: HTMLInputElement, focused: Element | null): boolean {\n if (focused && isRadio(focused) && sameGroup(focused, radio)) return false;\n const checked = checkedOf(radio);\n return checked === null || checked === radio;\n}\n\n/** The element children a walk in the flat tree visits: a shadow root's instead of its host's, a slot's assigned ones. */\nfunction childrenOf(element: Element): Element[] {\n if (element.shadowRoot) return Array.from(element.shadowRoot.children);\n if (element.localName === \"slot\") {\n const slot = element as HTMLSlotElement;\n const assigned = typeof slot.assignedElements === \"function\" ? slot.assignedElements() : [];\n if (assigned.length > 0) return assigned;\n }\n return Array.from(element.children);\n}\n\n/** An element and everything under it in flat-tree order, without what is `hidden` or `inert`. */\nfunction* walk(element: Element): Generator<Element> {\n yield element;\n for (const child of childrenOf(element)) {\n if (!child.matches(\"[hidden], [inert]\")) yield* walk(child);\n }\n}\n\nfunction isStopFrom(element: Element, focused: Element | null): element is HTMLElement {\n return isStop(element) && (!isRadio(element) || isRadioStop(element, focused));\n}\n\n/**\n * The stop the Tab key goes to from `from` without leaving `container`, or undefined when it\n * would leave it. `past` starts after everything inside `from`, as from a nested root as a whole.\n */\nfunction stepWithin(container: Element, from: Element, step: 1 | -1, past = false): HTMLElement | undefined {\n let before: HTMLElement | undefined;\n let passed = false;\n for (const element of walk(container)) {\n if (element === from) {\n if (step < 0) return before;\n passed = true;\n continue;\n }\n if (passed && past && containsDeep(from, element)) continue;\n if (!isStopFrom(element, from)) continue;\n if (passed) return element;\n before = element;\n }\n return undefined;\n}\n\n/** The first stop inside a container (step 1) or the last one (step -1), the container itself included. */\nfunction edgeStop(container: Element, step: 1 | -1, focused: Element | null): HTMLElement | undefined {\n let last: HTMLElement | undefined;\n for (const element of walk(container)) {\n if (!isStopFrom(element, focused)) continue;\n if (step > 0) return element;\n last = element;\n }\n return last;\n}\n\n/**\n * Into the reading-order children from `index` on: the first stop of the first one that has one,\n * or going backwards the last stop. A frame that ends a panel is entered by the browser itself,\n * which lands on the frame's own last stop (whatever its origin): its panel's end marker takes the\n * focus, and the browser's move goes on from there.\n */\nfunction enter(children: HTMLElement[], index: number, step: 1 | -1, focused: Element | null): TabGroupsTabMove | null {\n for (let at = index; at >= 0 && at < children.length; at += step) {\n const child = children[at];\n const stop = child ? edgeStop(child, step, focused) : undefined;\n if (!child || !stop) continue;\n const end = stop.localName === \"iframe\" ? child.querySelector<HTMLElement>(PANEL_END_SELECTOR) : null;\n return end ? { element: end, prevent: false } : { element: stop, prevent: true };\n }\n return null;\n}\n\n/**\n * What the Tab key (step 1) or Shift+Tab (step -1) does from `from`, the focused element in\n * `root`: null when the browser's own move is right \u2014 inside a child, or out of the root before\n * its first stop. At the end of the reading order the focus leaves through the guard, and the\n * browser moves on past the root from there.\n */\nexport function tabMove(root: HTMLElement, from: Element, step: 1 | -1): TabGroupsTabMove | null {\n const guard = guardOf(root);\n const children = readingChildren(root);\n // The guard holds the focus (nothing followed a frame at the end): Shift+Tab goes back in.\n if (from === guard) return step < 0 ? enter(children, children.length - 1, -1, from) : null;\n const child = rootChildOf(root, from);\n const index = child ? children.indexOf(child) : -1;\n if (!child || index < 0 || tabIndexOf(from) > 0) return null;\n if (stepWithin(child, from, step)) return null;\n const entered = enter(children, index + step, step, from);\n if (entered) return entered;\n return step > 0 && guard ? { element: guard, prevent: false } : null;\n}\n\n/** The last stop of the reading order, where Shift+Tab from after the root goes. */\nexport function lastStopOf(root: HTMLElement): HTMLElement | undefined {\n const children = readingChildren(root);\n for (let at = children.length - 1; at >= 0; at -= 1) {\n const child = children[at];\n const stop = child ? edgeStop(child, -1, null) : undefined;\n if (stop) return stop;\n }\n return undefined;\n}\n\n/**\n * Focuses a stop that is reached backwards: a frame whose document can be read (the same origin)\n * at its own last stop, as the browser's Shift+Tab would; another frame as a whole.\n */\nexport function focusFromEnd(element: HTMLElement): void {\n if (element.localName === \"iframe\") {\n let body: HTMLElement | null | undefined;\n try {\n body = (element as HTMLIFrameElement).contentDocument?.body;\n } catch {\n body = null;\n }\n const last = body ? edgeStop(body, -1, null) : undefined;\n if (last) {\n focusFromEnd(last);\n return;\n }\n }\n element.focus();\n}\n\n/** The first stop after a whole root: on in the root around it, or in the page. */\nfunction stopAfter(root: HTMLElement): HTMLElement | undefined {\n const outer = ownerRootOf(parentOf(root));\n if (!outer) {\n const body = root.ownerDocument.body;\n return body ? stepWithin(body, root, 1, true) : undefined;\n }\n const child = rootChildOf(outer, root);\n const children = readingChildren(outer);\n const index = child ? children.indexOf(child) : -1;\n if (child && index >= 0) {\n const inside = stepWithin(child, root, 1, true);\n if (inside) return inside;\n const entered = enter(children, index + 1, 1, null);\n if (entered) return entered.element;\n }\n return stopAfter(outer);\n}\n\n/**\n * Where the focus belongs after the browser's Tab took it out of `frame`, an iframe of this root,\n * onto `landed`. Inside a frame the keys are its own, so the browser left it by DOM order: to\n * another child of the root, or to the guard, when the frame ended its child. The next child in\n * reading order takes the focus instead, or after the last one whatever follows the root; with\n * nothing there the guard holds the focus (it is returned), and the next Tab leaves the page.\n * Null when the browser's move was right.\n */\nexport function frameExitTarget(root: HTMLElement, frame: Element, landed: Element): HTMLElement | null {\n const guard = guardOf(root);\n const child = rootChildOf(root, frame);\n if (!child || (landed !== guard && rootChildOf(root, landed) === child)) return null;\n // Out of a frame backwards the browser stays in its child: the child itself is a stop before it.\n if (landed !== guard && !(frame.compareDocumentPosition(landed) & 4)) return null;\n const children = readingChildren(root);\n const index = children.indexOf(child);\n if (index < 0) return null;\n const wanted = enter(children, index + 1, 1, null)?.element ?? stopAfter(root) ?? guard;\n return wanted === landed && landed !== guard ? null : wanted;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * The Tab order of `TabGroups`, read from the DOM alone: no framework here, and the file is a\n * byte-identical copy in ui-react and ui-solid.\n *\n * The root keeps its panels in the DOM in the order they first appeared, so the DOM order of its\n * children is not the reading order; the root's `aria-owns` lists them in reading order. Inside one\n * child \u2014 a header, a panel, a separator \u2014 DOM order is reading order, so there the browser moves\n * the focus itself, with every rule of its own (a radio group is one stop, a frame is entered at\n * its first or its last stop, a shadow tree is walked in place). Only a press that would leave a\n * child is taken over: it goes to the next child in reading order, to the stop the browser would\n * pick there by the same rules. A `TabGroups` nested in a panel is that panel's content: its own\n * root answers for the moves inside it, first.\n */\n\nconst ROOT_CLASS = \"smwb-tab-groups\";\nconst GUARD_SELECTOR = \":scope > .smwb-tab-groups__focus-guard\";\nconst PANEL_END_SELECTOR = \":scope > .smwb-tab-groups__panel-end\";\nconst READING_CHILD = \".smwb-tab-groups__header, .smwb-tab-groups__panel, .smwb-tab-groups__separator\";\n\n/** What can take focus from the Tab key, as a browser decides it. */\nconst FOCUSABLE =\n 'a[href], area[href], button, input, select, textarea, iframe, summary, audio[controls], video[controls], [contenteditable]:not([contenteditable=\"false\"]), [tabindex]';\n\n/** A browser's move of the Tab key, taken over: focus `element`, then stop there (`prevent`) or let the browser go on from it. */\nexport interface TabGroupsTabMove {\n element: HTMLElement;\n prevent: boolean;\n}\n\n/** The parent of a node across a shadow root's boundary: the host. */\nfunction parentOf(node: Node): Element | null {\n if (node.parentElement) return node.parentElement;\n const parent = node.parentNode as (Node & { host?: Element }) | null;\n return parent?.nodeType === 11 && parent.host ? parent.host : null;\n}\n\nfunction elementOf(node: Node | null): Element | null {\n if (!node) return null;\n return node.nodeType === 1 ? (node as Element) : parentOf(node);\n}\n\n/** Whether `node` is `ancestor` or inside it, shadow trees included. */\nexport function containsDeep(ancestor: Node, node: Node | null): boolean {\n for (let current: Node | null = node; current; current = parentOf(current)) {\n if (current === ancestor) return true;\n }\n return false;\n}\n\n/** The element that has the focus, inside shadow trees too: where the browser's Tab starts from. */\nexport function deepActiveElement(doc: Document): Element | null {\n let active = doc.activeElement;\n while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;\n return active;\n}\n\n/** The `TabGroups` root a node is in: the nearest one around it, or the node itself when it is one. */\nexport function ownerRootOf(node: Node | null): HTMLElement | null {\n for (let current = elementOf(node); current; current = parentOf(current)) {\n if (current.classList.contains(ROOT_CLASS)) return current as HTMLElement;\n }\n return null;\n}\n\n/** The child of `root` a node is in \u2014 a header, a panel, a separator, the guard \u2014 or null. */\nexport function rootChildOf(root: Element, node: Node | null): HTMLElement | null {\n let current = elementOf(node);\n while (current && parentOf(current) !== root) current = parentOf(current);\n return current as HTMLElement | null;\n}\n\n/** The group a node is in, told by the root's own child: a nested `TabGroups`' groups are not this root's. */\nexport function ownGroupIdOf(root: Element, node: Node | null): string | null {\n return rootChildOf(root, node)?.getAttribute(\"data-group-id\") ?? null;\n}\n\n/** The root's guard, its last Tab stop, which only holds the focus on its way in or out. */\nexport function guardOf(root: HTMLElement): HTMLElement | null {\n return root.querySelector<HTMLElement>(GUARD_SELECTOR);\n}\n\n/** The root's headers, shown panels and separators in reading order, as its `aria-owns` lists them. */\nexport function readingChildren(root: HTMLElement): HTMLElement[] {\n const doc = root.ownerDocument;\n return (root.getAttribute(\"aria-owns\") ?? \"\").split(/\\s+/).flatMap((id) => {\n const element = id ? doc.getElementById(id) : null;\n return element && element.parentElement === root && !element.hidden && element.matches(READING_CHILD)\n ? [element]\n : [];\n });\n}\n\n/** Whether an element is drawn: a browser skips what is not (`display: none` from a stylesheet); jsdom draws nothing. */\nfunction isDrawn(element: Element): boolean {\n return typeof element.checkVisibility !== \"function\" || element.checkVisibility({ visibilityProperty: true });\n}\n\nfunction tabIndexOf(element: Element): number {\n const value = (element as Partial<HTMLElement>).tabIndex;\n return typeof value === \"number\" ? value : -1;\n}\n\n/** A scroller is a Tab stop of its own in Chromium when nothing inside it takes the focus. */\nfunction isScrollerStop(element: Element): boolean {\n if (element.scrollHeight <= element.clientHeight && element.scrollWidth <= element.clientWidth) return false;\n const style = element.ownerDocument.defaultView?.getComputedStyle(element);\n const scrolls = (value: string | undefined): boolean => value === \"auto\" || value === \"scroll\";\n return Boolean(style && (scrolls(style.overflowY) || scrolls(style.overflowX)) && !element.querySelector(FOCUSABLE));\n}\n\n/**\n * Whether the Tab key stops at an element, radio groups aside: focusable, in the sequence of\n * `tabindex` 0 (-1 is out of it, and above 0 the browser visits before everything else), enabled\n * and drawn \u2014 or a scroller with nothing focusable inside.\n */\nfunction isStop(element: Element): element is HTMLElement {\n if (element.matches(FOCUSABLE)) {\n if (tabIndexOf(element) !== 0 || element.matches(\":disabled\")) return false;\n if (element.localName === \"input\" && (element as HTMLInputElement).type === \"hidden\") return false;\n return isDrawn(element);\n }\n return isScrollerStop(element);\n}\n\nfunction isRadio(element: Element): element is HTMLInputElement {\n return element.localName === \"input\" && (element as HTMLInputElement).type === \"radio\";\n}\n\n/** Radios of one group: the same name (an unnamed radio is a group of its own), the same form, the same tree. */\nfunction sameGroup(a: HTMLInputElement, b: HTMLInputElement): boolean {\n return a === b || (a.name !== \"\" && a.name === b.name && a.form === b.form && a.getRootNode() === b.getRootNode());\n}\n\n/** The checked radio of a radio's group, wherever it is drawn, or null. */\nfunction checkedOf(radio: HTMLInputElement): HTMLInputElement | null {\n if (radio.checked) return radio;\n if (radio.name === \"\") return null;\n const scope = radio.form ?? (radio.getRootNode() as Document | ShadowRoot);\n const members: Element[] = radio.form ? Array.from(radio.form.elements) : Array.from(scope.querySelectorAll(\"input\"));\n return (\n members.find(\n (member): member is HTMLInputElement => isRadio(member) && member.checked && sameGroup(radio, member)\n ) ?? null\n );\n}\n\n/**\n * A radio group is one stop: its checked radio, or with none checked every radio of it (so the\n * first one going forwards, the last one going backwards), and none of the group the focus is in.\n */\nfunction isRadioStop(radio: HTMLInputElement, focused: Element | null): boolean {\n if (focused && isRadio(focused) && sameGroup(focused, radio)) return false;\n const checked = checkedOf(radio);\n return checked === null || checked === radio;\n}\n\n/** The element children a walk in the flat tree visits: a shadow root's instead of its host's, a slot's assigned ones. */\nfunction childrenOf(element: Element): Element[] {\n if (element.shadowRoot) return Array.from(element.shadowRoot.children);\n if (element.localName === \"slot\") {\n const slot = element as HTMLSlotElement;\n const assigned = typeof slot.assignedElements === \"function\" ? slot.assignedElements() : [];\n if (assigned.length > 0) return assigned;\n }\n return Array.from(element.children);\n}\n\n/** An element and everything under it in flat-tree order, without what is `hidden` or `inert`. */\nfunction* walk(element: Element): Generator<Element> {\n yield element;\n for (const child of childrenOf(element)) {\n if (!child.matches(\"[hidden], [inert]\")) yield* walk(child);\n }\n}\n\nfunction isStopFrom(element: Element, focused: Element | null): element is HTMLElement {\n return isStop(element) && (!isRadio(element) || isRadioStop(element, focused));\n}\n\n/**\n * The stop the Tab key goes to from `from` without leaving `container`, or undefined when it\n * would leave it. `past` starts after everything inside `from`, as from a nested root as a whole.\n */\nfunction stepWithin(container: Element, from: Element, step: 1 | -1, past = false): HTMLElement | undefined {\n let before: HTMLElement | undefined;\n let passed = false;\n for (const element of walk(container)) {\n if (element === from) {\n if (step < 0) return before;\n passed = true;\n continue;\n }\n if (passed && past && containsDeep(from, element)) continue;\n if (!isStopFrom(element, from)) continue;\n if (passed) return element;\n before = element;\n }\n return undefined;\n}\n\n/** The first stop inside a container (step 1) or the last one (step -1), the container itself included. */\nfunction edgeStop(container: Element, step: 1 | -1, focused: Element | null): HTMLElement | undefined {\n let last: HTMLElement | undefined;\n for (const element of walk(container)) {\n if (!isStopFrom(element, focused)) continue;\n if (step > 0) return element;\n last = element;\n }\n return last;\n}\n\n/**\n * Into the reading-order children from `index` on: the first stop of the first one that has one,\n * or going backwards the last stop. A frame that ends a panel is entered by the browser itself,\n * which lands on the frame's own last stop (whatever its origin): its panel's end marker takes the\n * focus, and the browser's move goes on from there.\n */\nfunction enter(children: HTMLElement[], index: number, step: 1 | -1, focused: Element | null): TabGroupsTabMove | null {\n for (let at = index; at >= 0 && at < children.length; at += step) {\n const child = children[at];\n const stop = child ? edgeStop(child, step, focused) : undefined;\n if (!child || !stop) continue;\n const end = stop.localName === \"iframe\" ? child.querySelector<HTMLElement>(PANEL_END_SELECTOR) : null;\n return end ? { element: end, prevent: false } : { element: stop, prevent: true };\n }\n return null;\n}\n\n/**\n * What the Tab key (step 1) or Shift+Tab (step -1) does from `from`, the focused element in\n * `root`: null when the browser's own move is right \u2014 inside a child, or out of the root before\n * its first stop. At the end of the reading order the focus leaves through the guard, and the\n * browser moves on past the root from there.\n */\nexport function tabMove(root: HTMLElement, from: Element, step: 1 | -1): TabGroupsTabMove | null {\n const guard = guardOf(root);\n const children = readingChildren(root);\n // The guard holds the focus (nothing followed a frame at the end): Shift+Tab goes back in.\n if (from === guard) return step < 0 ? enter(children, children.length - 1, -1, from) : null;\n const child = rootChildOf(root, from);\n const index = child ? children.indexOf(child) : -1;\n if (!child || index < 0 || tabIndexOf(from) > 0) return null;\n if (stepWithin(child, from, step)) return null;\n const entered = enter(children, index + step, step, from);\n if (entered) return entered;\n return step > 0 && guard ? { element: guard, prevent: false } : null;\n}\n\n/** The last stop of the reading order, where Shift+Tab from after the root goes. */\nexport function lastStopOf(root: HTMLElement): HTMLElement | undefined {\n const children = readingChildren(root);\n for (let at = children.length - 1; at >= 0; at -= 1) {\n const child = children[at];\n const stop = child ? edgeStop(child, -1, null) : undefined;\n if (stop) return stop;\n }\n return undefined;\n}\n\n/**\n * Focuses a stop that is reached backwards: a frame whose document can be read (the same origin)\n * at its own last stop, as the browser's Shift+Tab would; another frame as a whole.\n */\nexport function focusFromEnd(element: HTMLElement): void {\n if (element.localName === \"iframe\") {\n let body: HTMLElement | null | undefined;\n try {\n body = (element as HTMLIFrameElement).contentDocument?.body;\n } catch {\n body = null;\n }\n const last = body ? edgeStop(body, -1, null) : undefined;\n if (last) {\n focusFromEnd(last);\n return;\n }\n }\n element.focus();\n}\n\n/** The first stop after a whole root: on in the root around it, or in the page. */\nfunction stopAfter(root: HTMLElement): HTMLElement | undefined {\n const outer = ownerRootOf(parentOf(root));\n if (!outer) {\n const body = root.ownerDocument.body;\n return body ? stepWithin(body, root, 1, true) : undefined;\n }\n const child = rootChildOf(outer, root);\n const children = readingChildren(outer);\n const index = child ? children.indexOf(child) : -1;\n if (child && index >= 0) {\n const inside = stepWithin(child, root, 1, true);\n if (inside) return inside;\n const entered = enter(children, index + 1, 1, null);\n if (entered) return entered.element;\n }\n return stopAfter(outer);\n}\n\n/**\n * Where the focus belongs after the browser's Tab took it out of `frame`, an iframe of this root,\n * onto `landed`. Inside a frame the keys are its own, so the browser left it by DOM order: to\n * another child of the root, or to the guard, when the frame ended its child. The next child in\n * reading order takes the focus instead, or after the last one whatever follows the root; with\n * nothing there the guard holds the focus (it is returned), and the next Tab leaves the page.\n * Null when the browser's move was right.\n */\nexport function frameExitTarget(root: HTMLElement, frame: Element, landed: Element): HTMLElement | null {\n const guard = guardOf(root);\n const child = rootChildOf(root, frame);\n if (!child || (landed !== guard && rootChildOf(root, landed) === child)) return null;\n // Out of a frame backwards the browser stays in its child: the child itself is a stop before it.\n if (landed !== guard && !(frame.compareDocumentPosition(landed) & 4)) return null;\n const children = readingChildren(root);\n const index = children.indexOf(child);\n if (index < 0) return null;\n const wanted = enter(children, index + 1, 1, null)?.element ?? stopAfter(root) ?? guard;\n return wanted === landed && landed !== guard ? null : wanted;\n}\n\nconst HEADER_CLASS = \"smwb-tab-groups__header\";\nconst STRIP_CLASS = \"smwb-tab-groups__strip-actions\";\n\n/** A control of a group's `stripActions` slot that has the focus: its group and its place among the slot's stops. */\nexport interface TabGroupsSlotFocus {\n element: HTMLElement;\n group: string;\n index: number;\n}\n\n/** The root's header of a group, walked rather than selected: ids need no escaping. */\nfunction headerOf(root: HTMLElement, groupId: string): HTMLElement | null {\n for (const child of Array.from(root.children)) {\n if (child.classList.contains(HEADER_CLASS) && child.getAttribute(\"data-group-id\") === groupId) {\n return child as HTMLElement;\n }\n }\n return null;\n}\n\n/** A header's `stripActions` wrapper, one of its own children (walked too: `:scope` breaks on some ids in jsdom). */\nfunction slotOf(header: Element): Element | undefined {\n return Array.from(header.children).find((child) => child.classList.contains(STRIP_CLASS));\n}\n\n/** The Tab stops of a header's `stripActions` slot in order; none when it draws no slot. */\nfunction slotStops(header: HTMLElement): HTMLElement[] {\n const slot = slotOf(header);\n const stops: HTMLElement[] = [];\n if (!slot) return stops;\n for (const element of walk(slot)) {\n if (element !== slot && isStopFrom(element, null)) stops.push(element);\n }\n return stops;\n}\n\n/** Where a focused element is in a `stripActions` slot of this root, or null when it is in none. */\nexport function slotFocusOf(root: HTMLElement, element: HTMLElement): TabGroupsSlotFocus | null {\n const header = rootChildOf(root, element);\n const group = header?.classList.contains(HEADER_CLASS) ? header.getAttribute(\"data-group-id\") : null;\n const slot = header ? slotOf(header) : undefined;\n if (!header || group === null || group === undefined || !slot || !containsDeep(slot, element)) return null;\n const stops = slotStops(header);\n const at = stops.indexOf(element);\n // Not a stop itself (`tabindex=\"-1\"`): its place is after the stops before it.\n const index = at >= 0 ? at : stops.filter((stop) => (stop.compareDocumentPosition(element) & 4) !== 0).length;\n return { element, group, index };\n}\n\n/**\n * Where the focus goes when the slot control that had it has left the document \u2014 a split or a\n * close from the slot takes the slot away with its group, or to the group the user works in now:\n * the stop at the same place (or the last one, when there are fewer) in the slot of the control's\n * own group while that still draws one, else in the slot of the group in use, else that group's\n * selected tab.\n */\nexport function slotFocusHeir(root: HTMLElement, lost: TabGroupsSlotFocus, activeGroup: string): HTMLElement | null {\n for (const groupId of [lost.group, activeGroup]) {\n const header = headerOf(root, groupId);\n const stops = header ? slotStops(header) : [];\n if (stops.length > 0) return stops[Math.min(lost.index, stops.length - 1)] ?? null;\n }\n return headerOf(root, activeGroup)?.querySelector<HTMLElement>('[role=\"tab\"][aria-selected=\"true\"]') ?? null;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/components/navigation/appBar/appBar.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/appBar/appBar.entry.less\";\nimport { type JSX, type ParentProps, Show, children, mergeProps, splitProps } from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\n\nexport type AppBarColor = \"default\" | \"primary\" | \"secondary\" | \"error\" | \"success\" | \"warning\" | \"info\";\n\nexport interface AppBarProps extends Omit<JSX.HTMLAttributes<HTMLElement>, \"title\"> {\n dense?: boolean;\n position?: \"relative\" | \"static\" | \"absolute\" | \"sticky\" | \"fixed\";\n placement?: \"top\" | \"bottom\";\n leftContent?: JSX.Element;\n midContent?: JSX.Element;\n rightContent?: JSX.Element;\n title?: JSX.Element | string;\n /**\n * Tag the `title` is rendered in: a `div` (default) or a heading, `h1`–`h6`,\n * for the page's main heading. Only the tag changes — a heading is drawn with\n * the bar's own font size, weight and no margins, so it looks exactly like the\n * div. The heading's text is the `title` itself, so pass a string or plain\n * markup rather than a `Typography` heading.\n */\n titleAs?: \"div\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n midContentAlign?: \"middle\" | \"left\" | \"right\";\n /**\n * `window`: the bar is the title bar of a desktop app window (Electron, Tauri, an installed PWA with Window\n * Controls Overlay). The bar drags the window; buttons, links, fields and other controls in it stay clickable,\n * and room is left for the OS window buttons (`windowControls`). In a plain browser tab it looks like `default`.\n */\n variant?: \"default\" | \"window\";\n /**\n * With `variant=\"window\"`: where the OS window buttons are, so the bar's content keeps clear of them.\n * `auto` (default) takes the area from the shell's `env(titlebar-area-*)` (Window Controls Overlay, Electron\n * `titleBarOverlay`) and reserves nothing without it; `left` is macOS (traffic lights, `titleBarStyle: \"hiddenInset\"`),\n * `right` is Windows/Linux caption buttons drawn by the OS; `none` reserves nothing. The reserved width is\n * the `--smui-appBarWindowControlsWidth` custom property (64px on the left, 138px on the right by default).\n */\n windowControls?: \"auto\" | \"left\" | \"right\" | \"none\";\n /** Semantic background color. */\n color?: AppBarColor;\n /** Test id of the root (`<header>`, or `<footer>` at the bottom); `app-bar` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLElement>;\n}\n\nexport function AppBar(props: ParentProps<AppBarProps>): JSX.Element {\n const merged = mergeProps(\n {\n position: \"static\" as const,\n placement: \"top\" as const,\n midContentAlign: \"middle\" as const,\n variant: \"default\" as const,\n windowControls: \"auto\" as const,\n color: \"default\" as AppBarColor,\n },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"children\",\n \"dense\",\n \"position\",\n \"placement\",\n \"leftContent\",\n \"midContent\",\n \"midContentAlign\",\n \"variant\",\n \"windowControls\",\n \"rightContent\",\n \"title\",\n \"titleAs\",\n \"color\",\n \"ref\",\n \"data-testid\",\n ]);\n\n // Read each slot once: markup passed as a prop is created anew on every read,\n // and during hydration a copy the server never rendered has no DOM node.\n const content = children(() => local.children);\n // The title is drawn only without children, so it is read only then.\n const title = children(() => (content() ? undefined : local.title));\n\n return (\n <Dynamic\n component={local.placement === \"top\" ? \"header\" : \"footer\"}\n {...rest}\n ref={mergeRefs(local.ref)}\n data-testid={local[\"data-testid\"] ?? \"app-bar\"}\n class={cn(\n \"smwb-appbar\",\n local.class,\n `smwb-${local.position}`,\n `smwb-${local.placement}`,\n { \"smwb-dense\": local.dense },\n local.color !== \"default\" && `smwb-appbar_color-${local.color}`,\n local.variant === \"window\" && \"smwb-appbar_variant-window\",\n local.variant === \"window\" &&\n local.windowControls !== \"auto\" &&\n `smwb-appbar_window-controls-${local.windowControls}`\n )}\n >\n <Show\n when={content()}\n fallback={\n <div class=\"smwb-appbar__inner\">\n <div class=\"smwb-appbar__left\">\n <Show keyed when={title() && (local.titleAs ?? \"div\")}>\n {(tag) => {\n // Headings go through literal templates too: `Dynamic` would add a hydration level to the\n // default `div` and a trailing space to the class on the server.\n switch (tag) {\n case \"h1\":\n return <h1 class=\"smwb-appbar__left__title\">{title()}</h1>;\n case \"h2\":\n return <h2 class=\"smwb-appbar__left__title\">{title()}</h2>;\n case \"h3\":\n return <h3 class=\"smwb-appbar__left__title\">{title()}</h3>;\n case \"h4\":\n return <h4 class=\"smwb-appbar__left__title\">{title()}</h4>;\n case \"h5\":\n return <h5 class=\"smwb-appbar__left__title\">{title()}</h5>;\n case \"h6\":\n return <h6 class=\"smwb-appbar__left__title\">{title()}</h6>;\n default:\n return <div class=\"smwb-appbar__left__title\">{title()}</div>;\n }\n }}\n </Show>\n {local.leftContent}\n </div>\n <div class={cn(\"smwb-appbar__mid\", `smwb-${local.midContentAlign}`)}>{local.midContent}</div>\n <div class=\"smwb-appbar__right\">{local.rightContent}</div>\n </div>\n }\n >\n {content()}\n </Show>\n </Dynamic>\n );\n}\n\nexport default AppBar;\n"],"mappings":"AAAA,OAAO;AACP,OAAO;AACP,SAAqC,MAAM,UAAU,YAAY,kBAAkB;AACnF,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,iBAA2B;AA0C7B,SAAS,OAAO,OAA8C;AACnE,QAAM,SAAS;AAAA,IACb;AAAA,MACE,UAAU;AAAA,MACV,WAAW;AAAA,MACX,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,gBAAgB;AAAA,MAChB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACA,QAAM,CAAC,OAAO,IAAI,IAAI,WAAW,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAID,QAAM,UAAU,SAAS,MAAM,MAAM,QAAQ;AAE7C,QAAM,QAAQ,SAAS,MAAO,QAAQ,IAAI,SAAY,MAAM,KAAM;AAElE,SACE,CAAC;AAAA,IACC,WAAW,MAAM,cAAc,QAAQ,WAAW;AAAA,QAC9C;AAAA,IACJ,KAAK,UAAU,MAAM,GAAG;AAAA,IACxB,aAAa,MAAM,aAAa,KAAK;AAAA,IACrC,OAAO;AAAA,MACL;AAAA,MACA,MAAM;AAAA,MACN,QAAQ,MAAM,QAAQ;AAAA,MACtB,QAAQ,MAAM,SAAS;AAAA,MACvB,EAAE,cAAc,MAAM,MAAM;AAAA,MAC5B,MAAM,UAAU,aAAa,qBAAqB,MAAM,KAAK;AAAA,MAC7D,MAAM,YAAY,YAAY;AAAA,MAC9B,MAAM,YAAY,YAChB,MAAM,mBAAmB,UACzB,+BAA+B,MAAM,cAAc;AAAA,IACvD;AAAA,GACD;AAAA,MACC,CAAC;AAAA,IACC,MAAM,QAAQ;AAAA,IACd,UACE,CAAC,IAAI,MAAM,qBAAqB;AAAA,YAC9B,CAAC,IAAI,MAAM,oBAAoB;AAAA,cAC7B,CAAC,KAAK,MAAM,MAAM,MAAM,MAAM,MAAM,WAAW,QAAQ;AAAA,iBACpD,CAAC,QAAQ;AAGR,cAAQ,KAAK;AAAA,QACX,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV;AACE,iBAAO,CAAC,IAAI,MAAM,4BAA4B,MAAM,EAAE,EAA9C;AAAA,MACZ;AAAA,IACF,EAAE;AAAA,cACJ,EArBC,KAqBM;AAAA,eACN,MAAM,YAAY;AAAA,YACrB,EAxBC,IAwBK;AAAA,YACN,CAAC,IAAI,OAAO,GAAG,oBAAoB,QAAQ,MAAM,eAAe,EAAE,IAAI,MAAM,WAAW,EAAtF,IAA4F;AAAA,YAC7F,CAAC,IAAI,MAAM,sBAAsB,MAAM,aAAa,EAAnD,IAAyD;AAAA,UAC5D,EA5BC;AAAA,GA8BJ;AAAA,SACE,QAAQ,EAAE;AAAA,MACb,EAnCC,KAmCM;AAAA,IACT,EAtDC;AAwDL;AAEA,IAAO,iBAAQ;","names":[],"file":"appBar.jsx"}
1
+ {"version":3,"sources":["../../../../../src/components/navigation/appBar/appBar.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/appBar/appBar.entry.less\";\nimport { type JSX, type ParentProps, Show, children, mergeProps, splitProps } from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\n\nexport type AppBarColor = \"default\" | \"primary\" | \"secondary\" | \"error\" | \"success\" | \"warning\" | \"info\";\n\nexport interface AppBarProps extends Omit<JSX.HTMLAttributes<HTMLElement>, \"title\"> {\n dense?: boolean;\n position?: \"relative\" | \"static\" | \"absolute\" | \"sticky\" | \"fixed\";\n placement?: \"top\" | \"bottom\";\n leftContent?: JSX.Element;\n /**\n * Content of the middle area, e.g. a search field. The area takes only the room the title and the right group leave\n * free (`flex: 1 1 0`), so it is the first to narrow when the bar does. A direct child narrows with it (`max-width: 100%`)\n * only as far as its own content can: a control with a minimum width, or a nowrap row of buttons or tabs, keeps it and\n * runs under the right group when the title takes the whole bar, so give such content `min-width: 0` or let it shrink.\n */\n midContent?: JSX.Element;\n rightContent?: JSX.Element;\n /**\n * Title in the left group. It keeps its content size while the middle area has room to give up; when the bar is\n * narrower than the title and the right group together, a text title is cut with an ellipsis and the right group stays\n * inside the bar. The cut leaves a margin for a focus ring (`overflow: clip`), so a link or a button in the title keeps\n * its ring.\n */\n title?: JSX.Element | string;\n /**\n * Tag the `title` is rendered in: a `div` (default) or a heading, `h1`–`h6`,\n * for the page's main heading. Only the tag changes — a heading is drawn with\n * the bar's own font size, weight and no margins, so it looks exactly like the\n * div. The heading's text is the `title` itself, so pass a string or plain\n * markup rather than a `Typography` heading.\n */\n titleAs?: \"div\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n midContentAlign?: \"middle\" | \"left\" | \"right\";\n /**\n * `window`: the bar is the title bar of a desktop app window (Electron, Tauri, an installed PWA with Window\n * Controls Overlay). The bar drags the window; buttons, links, fields and other controls in it stay clickable,\n * and room is left for the OS window buttons (`windowControls`). In a plain browser tab it looks like `default`.\n */\n variant?: \"default\" | \"window\";\n /**\n * With `variant=\"window\"`: where the OS window buttons are, so the bar's content keeps clear of them.\n * `auto` (default) takes the area from the shell's `env(titlebar-area-*)` (Window Controls Overlay, Electron\n * `titleBarOverlay`) and reserves nothing without it; `left` is macOS (traffic lights, `titleBarStyle: \"hiddenInset\"`),\n * `right` is Windows/Linux caption buttons drawn by the OS; `none` reserves nothing. The reserved width is\n * the `--smui-appBarWindowControlsWidth` custom property (64px on the left, 138px on the right by default).\n */\n windowControls?: \"auto\" | \"left\" | \"right\" | \"none\";\n /** Semantic background color. */\n color?: AppBarColor;\n /** Test id of the root (`<header>`, or `<footer>` at the bottom); `app-bar` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLElement>;\n}\n\nexport function AppBar(props: ParentProps<AppBarProps>): JSX.Element {\n const merged = mergeProps(\n {\n position: \"static\" as const,\n placement: \"top\" as const,\n midContentAlign: \"middle\" as const,\n variant: \"default\" as const,\n windowControls: \"auto\" as const,\n color: \"default\" as AppBarColor,\n },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"children\",\n \"dense\",\n \"position\",\n \"placement\",\n \"leftContent\",\n \"midContent\",\n \"midContentAlign\",\n \"variant\",\n \"windowControls\",\n \"rightContent\",\n \"title\",\n \"titleAs\",\n \"color\",\n \"ref\",\n \"data-testid\",\n ]);\n\n // Read each slot once: markup passed as a prop is created anew on every read,\n // and during hydration a copy the server never rendered has no DOM node.\n const content = children(() => local.children);\n // The title is drawn only without children, so it is read only then.\n const title = children(() => (content() ? undefined : local.title));\n\n return (\n <Dynamic\n component={local.placement === \"top\" ? \"header\" : \"footer\"}\n {...rest}\n ref={mergeRefs(local.ref)}\n data-testid={local[\"data-testid\"] ?? \"app-bar\"}\n class={cn(\n \"smwb-appbar\",\n local.class,\n `smwb-${local.position}`,\n `smwb-${local.placement}`,\n { \"smwb-dense\": local.dense },\n local.color !== \"default\" && `smwb-appbar_color-${local.color}`,\n local.variant === \"window\" && \"smwb-appbar_variant-window\",\n local.variant === \"window\" &&\n local.windowControls !== \"auto\" &&\n `smwb-appbar_window-controls-${local.windowControls}`\n )}\n >\n <Show\n when={content()}\n fallback={\n <div class=\"smwb-appbar__inner\">\n <div class=\"smwb-appbar__left\">\n <Show keyed when={title() && (local.titleAs ?? \"div\")}>\n {(tag) => {\n // Headings go through literal templates too: `Dynamic` would add a hydration level to the\n // default `div` and a trailing space to the class on the server.\n switch (tag) {\n case \"h1\":\n return <h1 class=\"smwb-appbar__left__title\">{title()}</h1>;\n case \"h2\":\n return <h2 class=\"smwb-appbar__left__title\">{title()}</h2>;\n case \"h3\":\n return <h3 class=\"smwb-appbar__left__title\">{title()}</h3>;\n case \"h4\":\n return <h4 class=\"smwb-appbar__left__title\">{title()}</h4>;\n case \"h5\":\n return <h5 class=\"smwb-appbar__left__title\">{title()}</h5>;\n case \"h6\":\n return <h6 class=\"smwb-appbar__left__title\">{title()}</h6>;\n default:\n return <div class=\"smwb-appbar__left__title\">{title()}</div>;\n }\n }}\n </Show>\n {local.leftContent}\n </div>\n <div class={cn(\"smwb-appbar__mid\", `smwb-${local.midContentAlign}`)}>{local.midContent}</div>\n <div class=\"smwb-appbar__right\">{local.rightContent}</div>\n </div>\n }\n >\n {content()}\n </Show>\n </Dynamic>\n );\n}\n\nexport default AppBar;\n"],"mappings":"AAAA,OAAO;AACP,OAAO;AACP,SAAqC,MAAM,UAAU,YAAY,kBAAkB;AACnF,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,iBAA2B;AAsD7B,SAAS,OAAO,OAA8C;AACnE,QAAM,SAAS;AAAA,IACb;AAAA,MACE,UAAU;AAAA,MACV,WAAW;AAAA,MACX,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,gBAAgB;AAAA,MAChB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACA,QAAM,CAAC,OAAO,IAAI,IAAI,WAAW,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAID,QAAM,UAAU,SAAS,MAAM,MAAM,QAAQ;AAE7C,QAAM,QAAQ,SAAS,MAAO,QAAQ,IAAI,SAAY,MAAM,KAAM;AAElE,SACE,CAAC;AAAA,IACC,WAAW,MAAM,cAAc,QAAQ,WAAW;AAAA,QAC9C;AAAA,IACJ,KAAK,UAAU,MAAM,GAAG;AAAA,IACxB,aAAa,MAAM,aAAa,KAAK;AAAA,IACrC,OAAO;AAAA,MACL;AAAA,MACA,MAAM;AAAA,MACN,QAAQ,MAAM,QAAQ;AAAA,MACtB,QAAQ,MAAM,SAAS;AAAA,MACvB,EAAE,cAAc,MAAM,MAAM;AAAA,MAC5B,MAAM,UAAU,aAAa,qBAAqB,MAAM,KAAK;AAAA,MAC7D,MAAM,YAAY,YAAY;AAAA,MAC9B,MAAM,YAAY,YAChB,MAAM,mBAAmB,UACzB,+BAA+B,MAAM,cAAc;AAAA,IACvD;AAAA,GACD;AAAA,MACC,CAAC;AAAA,IACC,MAAM,QAAQ;AAAA,IACd,UACE,CAAC,IAAI,MAAM,qBAAqB;AAAA,YAC9B,CAAC,IAAI,MAAM,oBAAoB;AAAA,cAC7B,CAAC,KAAK,MAAM,MAAM,MAAM,MAAM,MAAM,WAAW,QAAQ;AAAA,iBACpD,CAAC,QAAQ;AAGR,cAAQ,KAAK;AAAA,QACX,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV,KAAK;AACH,iBAAO,CAAC,GAAG,MAAM,4BAA4B,MAAM,EAAE,EAA7C;AAAA,QACV;AACE,iBAAO,CAAC,IAAI,MAAM,4BAA4B,MAAM,EAAE,EAA9C;AAAA,MACZ;AAAA,IACF,EAAE;AAAA,cACJ,EArBC,KAqBM;AAAA,eACN,MAAM,YAAY;AAAA,YACrB,EAxBC,IAwBK;AAAA,YACN,CAAC,IAAI,OAAO,GAAG,oBAAoB,QAAQ,MAAM,eAAe,EAAE,IAAI,MAAM,WAAW,EAAtF,IAA4F;AAAA,YAC7F,CAAC,IAAI,MAAM,sBAAsB,MAAM,aAAa,EAAnD,IAAyD;AAAA,UAC5D,EA5BC;AAAA,GA8BJ;AAAA,SACE,QAAQ,EAAE;AAAA,MACb,EAnCC,KAmCM;AAAA,IACT,EAtDC;AAwDL;AAEA,IAAO,iBAAQ;","names":[],"file":"appBar.jsx"}
@@ -1,12 +1,46 @@
1
1
  import "@smwb/ui-styles/less/tokens.entry.less";
2
2
  import "@smwb/ui-styles/less/components/breadcrumbs/breadcrumbs.entry.less";
3
- import { For, Show, children as resolveChildren, mergeProps, splitProps } from "solid-js";
3
+ import {
4
+ For,
5
+ Show,
6
+ children as resolveChildren,
7
+ createSignal,
8
+ mergeProps,
9
+ splitProps
10
+ } from "solid-js";
4
11
  import cn from "clsx";
5
12
  import { createControllableState } from "../../../primitives/createControllableState";
6
13
  import { mergeRefs } from "../../../primitives/mergeRefs";
14
+ function isCut(element) {
15
+ return element.scrollWidth > element.clientWidth;
16
+ }
17
+ function Crumb(props) {
18
+ const [title, setTitle] = createSignal(void 0);
19
+ const handleMouseEnter = (event) => {
20
+ const item = event.currentTarget;
21
+ const cut = isCut(item) || Array.from(item.children).some((child) => child instanceof HTMLElement && isCut(child));
22
+ setTitle(props.noWrap && cut ? item.textContent ?? void 0 : void 0);
23
+ };
24
+ const handleMouseLeave = () => setTitle(void 0);
25
+ return <li
26
+ class="smwb-breadcrumbs__item"
27
+ title={props.noWrap ? title() : void 0}
28
+ onMouseEnter={handleMouseEnter}
29
+ onMouseLeave={handleMouseLeave}
30
+ >
31
+ {props.children}
32
+ </li>;
33
+ }
7
34
  function Breadcrumbs(props) {
8
35
  const merged = mergeProps(
9
- { separator: "/", maxItems: 8, itemsBeforeCollapse: 1, itemsAfterCollapse: 1, expandLabel: "Show path" },
36
+ {
37
+ separator: "/",
38
+ maxItems: 8,
39
+ itemsBeforeCollapse: 1,
40
+ itemsAfterCollapse: 1,
41
+ expandLabel: "Show path",
42
+ noWrap: false
43
+ },
10
44
  props
11
45
  );
12
46
  const [local, rest] = splitProps(merged, [
@@ -18,6 +52,7 @@ function Breadcrumbs(props) {
18
52
  "expanded",
19
53
  "onExpand",
20
54
  "expandLabel",
55
+ "noWrap",
21
56
  "children",
22
57
  "ref",
23
58
  "data-testid"
@@ -47,12 +82,12 @@ function Breadcrumbs(props) {
47
82
  ref={mergeRefs(local.ref)}
48
83
  data-testid={local["data-testid"] ?? "breadcrumbs"}
49
84
  aria-label={rest["aria-label"] ?? "breadcrumb"}
50
- class={cn("smwb-breadcrumbs", local.class)}
85
+ class={cn("smwb-breadcrumbs", local.noWrap && "smwb-breadcrumbs--no-wrap", local.class)}
51
86
  >
52
87
  <ol class="smwb-breadcrumbs__list">
53
88
  <For each={rendered()}>
54
89
  {(crumb, index) => <>
55
- <li class="smwb-breadcrumbs__item">{crumb}</li>
90
+ <Crumb noWrap={local.noWrap}>{crumb}</Crumb>
56
91
  <Show when={index() < rendered().length - 1}>
57
92
  <li class="smwb-breadcrumbs__separator" aria-hidden="true">
58
93
  {local.separator}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/components/navigation/breadcrumbs/breadcrumbs.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/breadcrumbs/breadcrumbs.entry.less\";\nimport { type JSX, type ParentProps, For, Show, children as resolveChildren, mergeProps, splitProps } from \"solid-js\";\nimport cn from \"clsx\";\nimport { createControllableState } from \"../../../primitives/createControllableState\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\n\nexport interface BreadcrumbsProps extends JSX.HTMLAttributes<HTMLElement> {\n /** Node placed between every crumb. */\n separator?: JSX.Element;\n /** Collapse the middle of the trail when there are more than `maxItems` crumbs. */\n maxItems?: number;\n /** How many leading crumbs to keep when collapsed. */\n itemsBeforeCollapse?: number;\n /** How many trailing crumbs to keep when collapsed. */\n itemsAfterCollapse?: number;\n /** Controlled expanded state. */\n expanded?: boolean;\n /** Fired when the user activates the expand control. */\n onExpand?: () => void;\n /** Accessible label for the expand button. */\n expandLabel?: string;\n /** Test id of the root `<nav>`; `breadcrumbs` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLElement>;\n}\n\nexport function Breadcrumbs(props: ParentProps<BreadcrumbsProps>): JSX.Element {\n const merged = mergeProps(\n { separator: \"/\" as JSX.Element, maxItems: 8, itemsBeforeCollapse: 1, itemsAfterCollapse: 1, expandLabel: \"Show path\" },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"separator\",\n \"maxItems\",\n \"itemsBeforeCollapse\",\n \"itemsAfterCollapse\",\n \"expanded\",\n \"onExpand\",\n \"expandLabel\",\n \"children\",\n \"ref\",\n \"data-testid\",\n ]);\n\n const [expanded, setExpanded] = createControllableState<boolean>({\n value: () => local.expanded,\n defaultValue: false,\n onChange: () => local.onExpand?.(),\n });\n\n const resolved = resolveChildren(() => local.children);\n const crumbs = (): unknown[] => resolved.toArray();\n\n const collapsed = (): boolean =>\n !expanded() &&\n crumbs().length > local.maxItems &&\n local.itemsBeforeCollapse + local.itemsAfterCollapse < crumbs().length;\n\n const handleExpand = (): void => setExpanded(true);\n\n const rendered = (): unknown[] => {\n const all = crumbs();\n if (!collapsed()) return all;\n return [\n ...all.slice(0, local.itemsBeforeCollapse),\n (\n <button type=\"button\" class=\"smwb-breadcrumbs__expand\" aria-label={local.expandLabel} onClick={handleExpand}>\n …\n </button>\n ),\n ...all.slice(all.length - local.itemsAfterCollapse),\n ];\n };\n\n return (\n <nav\n {...rest}\n ref={mergeRefs(local.ref)}\n data-testid={local[\"data-testid\"] ?? \"breadcrumbs\"}\n // A default the caller's own replaces, to name it in their language; an\n // explicit undefined keeps it.\n aria-label={rest[\"aria-label\"] ?? \"breadcrumb\"}\n class={cn(\"smwb-breadcrumbs\", local.class)}\n >\n <ol class=\"smwb-breadcrumbs__list\">\n <For each={rendered()}>\n {(crumb, index) => (\n <>\n <li class=\"smwb-breadcrumbs__item\">{crumb as JSX.Element}</li>\n <Show when={index() < rendered().length - 1}>\n <li class=\"smwb-breadcrumbs__separator\" aria-hidden=\"true\">\n {local.separator}\n </li>\n </Show>\n </>\n )}\n </For>\n </ol>\n </nav>\n );\n}\n\nexport default Breadcrumbs;\n"],"mappings":"AAAA,OAAO;AACP,OAAO;AACP,SAAqC,KAAK,MAAM,YAAY,iBAAiB,YAAY,kBAAkB;AAC3G,OAAO,QAAQ;AACf,SAAS,+BAA+B;AACxC,SAAS,iBAA2B;AAsB7B,SAAS,YAAY,OAAmD;AAC7E,QAAM,SAAS;AAAA,IACb,EAAE,WAAW,KAAoB,UAAU,GAAG,qBAAqB,GAAG,oBAAoB,GAAG,aAAa,YAAY;AAAA,IACtH;AAAA,EACF;AACA,QAAM,CAAC,OAAO,IAAI,IAAI,WAAW,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,CAAC,UAAU,WAAW,IAAI,wBAAiC;AAAA,IAC/D,OAAO,MAAM,MAAM;AAAA,IACnB,cAAc;AAAA,IACd,UAAU,MAAM,MAAM,WAAW;AAAA,EACnC,CAAC;AAED,QAAM,WAAW,gBAAgB,MAAM,MAAM,QAAQ;AACrD,QAAM,SAAS,MAAiB,SAAS,QAAQ;AAEjD,QAAM,YAAY,MAChB,CAAC,SAAS,KACV,OAAO,EAAE,SAAS,MAAM,YACxB,MAAM,sBAAsB,MAAM,qBAAqB,OAAO,EAAE;AAElE,QAAM,eAAe,MAAY,YAAY,IAAI;AAEjD,QAAM,WAAW,MAAiB;AAChC,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,UAAU,EAAG,QAAO;AACzB,WAAO;AAAA,MACL,GAAG,IAAI,MAAM,GAAG,MAAM,mBAAmB;AAAA,MAEvC,CAAC,OAAO,KAAK,SAAS,MAAM,2BAA2B,YAAY,MAAM,aAAa,SAAS,cAAc;AAAA;AAAA,QAE7G,EAFC;AAAA,MAIH,GAAG,IAAI,MAAM,IAAI,SAAS,MAAM,kBAAkB;AAAA,IACpD;AAAA,EACF;AAEA,SACE,CAAC;AAAA,QACK;AAAA,IACJ,KAAK,UAAU,MAAM,GAAG;AAAA,IACxB,aAAa,MAAM,aAAa,KAAK;AAAA,IAGrC,YAAY,KAAK,YAAY,KAAK;AAAA,IAClC,OAAO,GAAG,oBAAoB,MAAM,KAAK;AAAA,GAC1C;AAAA,MACC,CAAC,GAAG,MAAM,yBAAyB;AAAA,QACjC,CAAC,IAAI,MAAM,SAAS,GAAG;AAAA,WACpB,CAAC,OAAO,UACP,EAAE;AAAA,cACA,CAAC,GAAG,MAAM,0BAA0B,MAAqB,EAAxD,GAA6D;AAAA,cAC9D,CAAC,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,SAAS,GAAG;AAAA,gBAC3C,CAAC,GAAG,MAAM,8BAA8B,YAAY,OAAO;AAAA,mBACxD,MAAM,UAAU;AAAA,gBACnB,EAFC,GAEI;AAAA,cACP,EAJC,KAIM;AAAA,YACT,IACA;AAAA,QACJ,EAXC,IAWK;AAAA,MACR,EAbC,GAaI;AAAA,IACP,EAvBC;AAyBL;AAEA,IAAO,sBAAQ;","names":[],"file":"breadcrumbs.jsx"}
1
+ {"version":3,"sources":["../../../../../src/components/navigation/breadcrumbs/breadcrumbs.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/breadcrumbs/breadcrumbs.entry.less\";\nimport {\n type JSX,\n type ParentProps,\n For,\n Show,\n children as resolveChildren,\n createSignal,\n mergeProps,\n splitProps,\n} from \"solid-js\";\nimport cn from \"clsx\";\nimport { createControllableState } from \"../../../primitives/createControllableState\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\n\nexport interface BreadcrumbsProps extends JSX.HTMLAttributes<HTMLElement> {\n /** Node placed between every crumb. */\n separator?: JSX.Element;\n /** Collapse the middle of the trail when there are more than `maxItems` crumbs. */\n maxItems?: number;\n /** How many leading crumbs to keep when collapsed. */\n itemsBeforeCollapse?: number;\n /** How many trailing crumbs to keep when collapsed. */\n itemsAfterCollapse?: number;\n /** Controlled expanded state. */\n expanded?: boolean;\n /** Fired when the user activates the expand control. */\n onExpand?: () => void;\n /** Accessible label for the expand button. */\n expandLabel?: string;\n /**\n * Keep the trail on one line: the crumbs do not wrap, they shrink and cut their text with an ellipsis, the last one\n * giving way last, and a cut crumb shows its full text as a `title` on hover. Plain text and a block child (a heading,\n * `Typography`) are cut with an ellipsis; a crumb laid out as a row (an icon with a label, say) is clipped as far as\n * its own layout allows. A leading crumb is never narrower than `@breadcrumbsLeadingMinWidth`, so a one- or\n * two-letter one takes that width even when everything fits, and the last one is never narrower than\n * `@breadcrumbsLastMinWidth`: in a box smaller than those floors the trail runs past it instead of shrinking further.\n */\n noWrap?: boolean;\n /** Test id of the root `<nav>`; `breadcrumbs` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLElement>;\n}\n\n/** A box whose content runs past it: the crumb itself, or the block it holds (a heading cuts itself). */\nfunction isCut(element: HTMLElement): boolean {\n return element.scrollWidth > element.clientWidth;\n}\n\n/** One `<li>` of the trail; with `noWrap` it names itself by its full text while that text is cut. */\nfunction Crumb(props: ParentProps<{ noWrap: boolean }>): JSX.Element {\n const [title, setTitle] = createSignal<string | undefined>(undefined);\n\n // Measured on every entry: the width the crumb has changes with its container.\n const handleMouseEnter: JSX.EventHandler<HTMLLIElement, MouseEvent> = (event) => {\n const item = event.currentTarget;\n const cut = isCut(item) || Array.from(item.children).some((child) => child instanceof HTMLElement && isCut(child));\n setTitle(props.noWrap && cut ? (item.textContent ?? undefined) : undefined);\n };\n // The title is for the pointer that is over the crumb: it does not outlive it.\n const handleMouseLeave = (): void => setTitle(undefined);\n\n return (\n <li\n class=\"smwb-breadcrumbs__item\"\n title={props.noWrap ? title() : undefined}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n {props.children}\n </li>\n );\n}\n\nexport function Breadcrumbs(props: ParentProps<BreadcrumbsProps>): JSX.Element {\n const merged = mergeProps(\n {\n separator: \"/\" as JSX.Element,\n maxItems: 8,\n itemsBeforeCollapse: 1,\n itemsAfterCollapse: 1,\n expandLabel: \"Show path\",\n noWrap: false,\n },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"separator\",\n \"maxItems\",\n \"itemsBeforeCollapse\",\n \"itemsAfterCollapse\",\n \"expanded\",\n \"onExpand\",\n \"expandLabel\",\n \"noWrap\",\n \"children\",\n \"ref\",\n \"data-testid\",\n ]);\n\n const [expanded, setExpanded] = createControllableState<boolean>({\n value: () => local.expanded,\n defaultValue: false,\n onChange: () => local.onExpand?.(),\n });\n\n const resolved = resolveChildren(() => local.children);\n const crumbs = (): unknown[] => resolved.toArray();\n\n const collapsed = (): boolean =>\n !expanded() &&\n crumbs().length > local.maxItems &&\n local.itemsBeforeCollapse + local.itemsAfterCollapse < crumbs().length;\n\n const handleExpand = (): void => setExpanded(true);\n\n const rendered = (): unknown[] => {\n const all = crumbs();\n if (!collapsed()) return all;\n return [\n ...all.slice(0, local.itemsBeforeCollapse),\n (\n <button type=\"button\" class=\"smwb-breadcrumbs__expand\" aria-label={local.expandLabel} onClick={handleExpand}>\n …\n </button>\n ),\n ...all.slice(all.length - local.itemsAfterCollapse),\n ];\n };\n\n return (\n <nav\n {...rest}\n ref={mergeRefs(local.ref)}\n data-testid={local[\"data-testid\"] ?? \"breadcrumbs\"}\n // A default the caller's own replaces, to name it in their language; an\n // explicit undefined keeps it.\n aria-label={rest[\"aria-label\"] ?? \"breadcrumb\"}\n class={cn(\"smwb-breadcrumbs\", local.noWrap && \"smwb-breadcrumbs--no-wrap\", local.class)}\n >\n <ol class=\"smwb-breadcrumbs__list\">\n <For each={rendered()}>\n {(crumb, index) => (\n <>\n <Crumb noWrap={local.noWrap}>{crumb as JSX.Element}</Crumb>\n <Show when={index() < rendered().length - 1}>\n <li class=\"smwb-breadcrumbs__separator\" aria-hidden=\"true\">\n {local.separator}\n </li>\n </Show>\n </>\n )}\n </For>\n </ol>\n </nav>\n );\n}\n\nexport default Breadcrumbs;\n"],"mappings":"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","names":[],"file":"breadcrumbs.jsx"}
@@ -62,6 +62,10 @@ function Tab(props) {
62
62
  }) : () => -1;
63
63
  const icon = children(() => local.icon);
64
64
  const label = children(() => local.label);
65
+ const fitTitle = () => {
66
+ const text = label();
67
+ return ctx?.fit?.() && props.title === void 0 && typeof text === "string" && text !== "" ? text : void 0;
68
+ };
65
69
  const actionsApi = { close: (event) => close(event, "actions") };
66
70
  const actions = children(() => {
67
71
  const given = local.actions;
@@ -159,7 +163,9 @@ function Tab(props) {
159
163
  </span>
160
164
  </Show>
161
165
  <Show when={label()}>
162
- <span class="smwb-tab__text-label">{label()}</span>
166
+ <span class="smwb-tab__text-label" title={fitTitle()}>
167
+ {label()}
168
+ </span>
163
169
  </Show>
164
170
  </span>
165
171
  <Ripple actionRef={(api) => rippleActions = api} classes={{ child: "tab__ripple-child" }} />
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/components/navigation/tabs/tab/tab.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/tabs/tab/tab.entry.less\";\nimport { type JSX, type ParentProps, Show, children, createSignal, mergeProps, splitProps } from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { Ripple, type RippleActionsRef } from \"../../../base/ripple\";\nimport { Icon } from \"../../../base/icon\";\nimport { useTabsContext, type TabCloseReason } from \"../tabsContext\";\nimport { mergeRefs, type Ref } from \"../../../../primitives/mergeRefs\";\nimport { callHandler } from \"../../../../primitives/callHandler\";\n\nexport type { TabCloseReason };\n\n/** What a function given as `actions` receives. */\nexport interface TabActionsApi {\n /**\n * Ask for the tab to close, as its close button does: `onClose` is called with this event and the\n * reason \"actions\", and `Tabs` moves focus on to the neighbour once the tab goes, even though focus\n * is in a menu drawn outside the row. Call it from the item that closes the tab (\"Terminate\"), with\n * that item's event. It works on a tab that is not `closable`.\n */\n close: (event: Event) => void;\n}\n\n// `onClose` is the close button's, not the element's `close` event handler.\nexport interface TabProps extends Omit<JSX.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement>, \"onClose\"> {\n label?: JSX.Element;\n isActive?: boolean;\n /**\n * Whether the tab is the one in the page's Tab order (`tabindex` 0, the others -1). `Tabs` sets\n * it: the focused tab while focus is in the row, the selected one otherwise. On its own a tab\n * is the stop while `isActive`.\n */\n tabStop?: boolean;\n contentRef?: Ref<HTMLSpanElement>;\n /**\n * A decorative status marker drawn left of the label (a running/done/failed icon). Its\n * wrapper renders `aria-hidden=\"true\"`, so the tab's accessible name stays the label\n * alone: the icon is not announced on top of it. To have the status read out, put it\n * in the `label` itself.\n */\n icon?: JSX.Element;\n stacked?: boolean;\n /** The element to render. A tab with an `href` is an `a` unless you say otherwise. */\n tag?: string;\n /**\n * Navigation mode: where the tab goes. The tab is then a real link (`<a href role=\"tab\">`, with\n * no `target`: a tab never opens another window), so it opens in place and middle click, copy\n * link and the like work. A router takes over the plain click in `onClick` with\n * `event.preventDefault()`; `Tabs` still calls `onChange` for it. A modified or non-primary click\n * (Ctrl, Meta, Shift or Alt held, or a button other than the main one) is the browser's, as\n * \"open in a new tab\": the router must let it through, and `Tabs` does not call `onChange`.\n * The one exception is a middle press on a `closable` tab: it closes the tab instead, as in an\n * editor, and its default is prevented so nothing opens.\n */\n href?: string;\n disabled?: boolean;\n /**\n * Draw a close button after the tab, and let Delete or Backspace on the focused tab close it too\n * (Backspace because a Mac has no Delete key); the tab lists them in `aria-keyshortcuts`. A\n * middle click on the tab closes it as well (`reason` \"middleClick\"): the browser's own\n * middle-click action (autoscroll, opening a link tab in a new window) is suppressed, and the\n * click never selects. The tab does not close itself: `onClose` asks for it and the owner\n * removes the `Tab`. The button is a sibling of the tab, not inside its `role=\"tab\"`, so the\n * tab's accessible name is its label alone.\n * It is out of the Tab order (`tabindex` -1), so the row keeps one tab stop, and a press on it takes\n * no focus and never selects the tab. When the tab that has focus closes, `Tabs` moves focus to the\n * tab that takes its place (the previous one if it was last), skipping disabled tabs. A disabled tab\n * has a disabled button.\n *\n * The button stays in the accessibility tree, named by `closeLabel`: it is how a screen reader user\n * who cannot press Delete, as on a touch screen, closes the tab. It sits in the tab list beside its\n * tab, though, and ARIA 1.2 lets a `tablist` own only `tab`s: a linter that applies that strictly\n * (axe `aria-required-children`) can flag the button, and whatever `actions` holds.\n *\n * To switch it off on a tab, pass `false` rather than leaving it out: a tab given `closable` or\n * `actions` is wrapped in an item with them, a tab given neither is not, and moving between the two\n * recreates the tab and drops its focus.\n */\n closable?: boolean;\n /**\n * Asks for the tab to close, and receives what asked for it: the close button's click (`reason`\n * \"button\"), the key press of Delete or Backspace on the tab (`reason` \"key\", its default is\n * prevented), the middle press on the tab (`reason` \"middleClick\", its default is prevented too),\n * or the event passed to `close` by the tab's `actions` (`reason` \"actions\"). The owner removes\n * the `Tab`.\n */\n onClose?: (event: Event, reason: TabCloseReason) => void;\n /** Accessible label of the close button. English by default; set it to localise, or to name the tab (\"Close Terminal 1\"). */\n closeLabel?: string;\n /**\n * Content after the tab, before the close button: a trigger with a `Menu` (\"Rename\", \"Terminate\"),\n * or any control. Give a function to get `{ close }` (see `TabActionsApi`); it is called once.\n * Like the close button the content is a sibling of the tab, so it is not part of the tab's name;\n * the tab's own `ref`, `class` and handlers stay on the `role=\"tab\"` element. It stays in the\n * accessibility tree as written, inside the tab list (see `closable`).\n *\n * The row has one tab stop, so give the trigger `tabindex={-1}`. Shift+F10 or the Menu key on the\n * focused tab, which the tab lists in `aria-keyshortcuts`, focuses the first control in `actions`\n * and clicks it, unless that control says `aria-expanded=\"true\"` (it is already open). If the\n * control names its popup in `aria-controls`, the first enabled `menuitem` in that element then\n * takes focus, as the WAI-ARIA menu button pattern asks: ArrowDown moves on, Enter chooses, and\n * Escape hands focus back to the trigger. Without `aria-controls` focus stays on the trigger.\n *\n * The row clips what overflows it: draw the menu in a `Portal`, anchored to the trigger and with\n * the `id` the trigger names. A choice that removes the tab (\"Terminate\") should call `close` with\n * its event, so that `onClose` removes the tab and `Tabs` moves focus on to the neighbour; a tab\n * removed some other way leaves focus on the page.\n */\n actions?: JSX.Element | ((api: TabActionsApi) => JSX.Element);\n ref?: Ref<HTMLButtonElement | HTMLAnchorElement>;\n}\n\n/** A click that asks the browser for something else than \"go here\": a new tab, a new window, a download. */\nconst isModifiedClick = (event: MouseEvent): boolean =>\n event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;\n\nconst hasModifier = (event: KeyboardEvent): boolean => event.ctrlKey || event.metaKey || event.altKey || event.shiftKey;\n\n/** What the Menu key and Shift+F10 stand for: the actions' trigger. */\nconst ACTIONS_TRIGGER = 'button:not(:disabled), a[href], [role=\"button\"]:not([aria-disabled=\"true\"]), [tabindex]';\n\n/** The item of an opened menu that takes focus first. */\nconst FIRST_MENU_ITEM = '[role^=\"menuitem\"]:not([aria-disabled=\"true\"])';\n\n/** Focus the first item of the popup `trigger` names in `aria-controls`, if it is there. */\nconst focusPopupOf = (trigger: HTMLElement): void => {\n for (const id of trigger.getAttribute(\"aria-controls\")?.split(/\\s+/) ?? []) {\n const item = id ? trigger.ownerDocument.getElementById(id)?.querySelector<HTMLElement>(FIRST_MENU_ITEM) : null;\n if (item) {\n // The menu may not be placed yet: a scroll to it would jump to the corner it starts in.\n item.focus({ preventScroll: true });\n return;\n }\n }\n};\n\nexport function Tab(props: ParentProps<TabProps>): JSX.Element {\n const ctx = useTabsContext();\n const [root, setRoot] = createSignal<HTMLButtonElement | HTMLAnchorElement>();\n const merged = mergeProps({ isActive: false, stacked: false, closeLabel: \"Close tab\" }, props);\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"label\",\n \"isActive\",\n \"contentRef\",\n \"icon\",\n \"stacked\",\n \"tag\",\n \"href\",\n \"tabStop\",\n \"disabled\",\n // `Tabs` owns this: it is the item that drags, not the tab. The caller's value\n // is dropped, as in the React `Tab`.\n \"draggable\",\n \"closable\",\n \"onClose\",\n \"closeLabel\",\n \"actions\",\n \"id\",\n \"aria-controls\",\n // A tab opens in place: a caller's target is dropped, not passed on.\n \"target\" as keyof TabProps,\n \"onClick\",\n \"onKeyDown\",\n \"ref\",\n // The tab sets this on its root too; its own handler calls the caller's first.\n \"onPointerDown\",\n \"onMouseDown\",\n ]);\n\n // The tab's position in the tab list: it follows the tab when tabs around it\n // are added, removed or reordered.\n const index = ctx\n ? ctx.registerTab(root, {\n id: () => local.id,\n disabled: () =>\n Boolean(local.disabled) || props[\"aria-disabled\"] === true || props[\"aria-disabled\"] === \"true\",\n closable: () => Boolean(local.closable),\n requestClose: (event) => close(event, \"key\"),\n })\n : () => -1;\n\n // Read the icon and the label once: markup passed as a prop is created anew on\n // every read, and during hydration the copy made for the <Show> test has no\n // server DOM node to adopt (\"Unable to find DOM nodes for hydration key\").\n const icon = children(() => local.icon);\n const label = children(() => local.label);\n // The actions are drawn whenever they are given, so reading them here, once, is safe. A function\n // is the tab's to call, with its api: `children` would call it with nothing.\n const actionsApi: TabActionsApi = { close: (event) => close(event, \"actions\") };\n const actions = children(() => {\n const given = local.actions;\n return typeof given === \"function\" ? (given as (api: TabActionsApi) => JSX.Element)(actionsApi) : given;\n });\n const hasActions = (): boolean => actions.toArray().length > 0;\n\n let rippleActions: RippleActionsRef | undefined;\n let actionsEl: HTMLSpanElement | undefined;\n\n const active = (): boolean => (ctx ? ctx.value() === index() : local.isActive);\n\n const tag = (): string => local.tag ?? (local.href !== undefined ? \"a\" : \"button\");\n // Anything but a button is not disabled by the attribute: its clicks are swallowed here.\n const inert = (): boolean => Boolean(local.disabled) && tag() !== \"button\";\n\n const onClick: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, MouseEvent> = (event) => {\n if (inert()) {\n event.preventDefault();\n return;\n }\n // Inside Tabs too the caller's onClick runs first, then the tab list picks the tab.\n callHandler(local.onClick, event);\n // A link tab opens elsewhere on a modified click: the browser's, not a selection here.\n if (local.href !== undefined && isModifiedClick(event)) return;\n ctx?.onChange(event, index());\n };\n\n const close = (event: Event, reason: TabCloseReason): void => {\n // The row notes which tab is closing before the owner removes it.\n ctx?.closing(index(), reason);\n local.onClose?.(event, reason);\n };\n\n // A button clicks on Enter and Space by itself, a link on Enter only: Space does it here.\n const onKeyDown: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, KeyboardEvent> = (event) => {\n callHandler(local.onKeyDown, event);\n if (local.disabled || event.defaultPrevented || event.target !== event.currentTarget) return;\n if (tag() !== \"button\" && event.key === \" \") {\n event.preventDefault();\n event.currentTarget.click();\n } else if (local.closable && (event.key === \"Delete\" || event.key === \"Backspace\") && !hasModifier(event)) {\n event.preventDefault();\n close(event, \"key\");\n } else if (hasActions() && (event.key === \"ContextMenu\" || (event.key === \"F10\" && event.shiftKey))) {\n // The Menu key, or Shift+F10: the keyboard's right click. The trigger takes focus first, so\n // the menu it opens hands focus back to it on Escape.\n const trigger = actionsEl?.querySelector<HTMLElement>(ACTIONS_TRIGGER);\n if (trigger) {\n event.preventDefault();\n trigger.focus();\n // The keys mean \"open\": a menu that already is open is not toggled shut.\n if (trigger.getAttribute(\"aria-expanded\") !== \"true\") {\n trigger.click();\n }\n focusPopupOf(trigger);\n }\n }\n };\n\n const onPointerDown: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, PointerEvent> = (event) => {\n callHandler(local.onPointerDown, event);\n rippleActions?.onRipple(event);\n };\n\n // Middle click on a closable tab closes it, IDE-style: the browser's own middle-click\n // action (autoscroll, opening a link tab in a new window) is suppressed and the tab is\n // never selected. A middle click on a tab that is not closable is the browser's, untouched.\n const onMouseDown: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, MouseEvent> = (event) => {\n callHandler(local.onMouseDown, event);\n if (event.button === 1 && local.closable && !local.disabled) {\n event.preventDefault();\n close(event, \"middleClick\");\n }\n };\n\n // Inside Tabs the row decides, whatever the caller passed.\n const tabStop = (): boolean => (ctx ? ctx.tabStop(index()) : (local.tabStop ?? active()));\n\n // What the tab answers to, for assistive technology; the caller's own list is kept.\n // The chords are best-effort: browsers reserve Mod+W and Mod+Shift+[/] in a page of\n // their own tabs, and they bite only in an embedded webview.\n const keyshortcuts = (): string | undefined =>\n [\n props[\"aria-keyshortcuts\"],\n !local.disabled && local.closable ? \"Delete Backspace\" : undefined,\n !local.disabled && hasActions() ? \"Shift+F10 ContextMenu\" : undefined,\n !local.disabled && local.closable ? \"Meta+W Control+W\" : undefined,\n !local.disabled ? \"Meta+Shift+[ Control+Shift+[ Meta+Shift+] Control+Shift+]\" : undefined,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n // A tab given neither `closable` nor `actions` is the bare element, as it always was.\n const wrapped = (): boolean => local.closable !== undefined || actions() !== undefined;\n\n // Only a reorderable row makes its items draggable, and a disabled tab never — the same\n // contract as the registration's `disabled`. Rendered on the item (the wrapper, or the\n // bare tab when there is none), so `draggable` is in the server markup, as in React.\n const draggable = (): boolean | undefined =>\n ctx?.reorderable() && !local.disabled && props[\"aria-disabled\"] !== true && props[\"aria-disabled\"] !== \"true\"\n ? true\n : undefined;\n\n const renderTab = (): JSX.Element => (\n <Dynamic\n component={tag()}\n {...rest}\n ref={mergeRefs(local.ref, setRoot)}\n class={cn(\"smwb-tab\", local.class, {\n \"smwb-tab--active\": active(),\n \"smwb-tab--stacked\": local.stacked,\n \"smwb-tab--disabled\": local.disabled,\n })}\n id={local.id ?? ctx?.tabId(index())}\n aria-controls={local[\"aria-controls\"] ?? (ctx?.hasPanels() ? ctx.panelId(index()) : undefined)}\n // A disabled link has no href, so it is no link to follow or to focus.\n href={inert() ? undefined : local.href}\n draggable={wrapped() ? undefined : draggable()}\n onClick={onClick}\n onKeyDown={onKeyDown}\n onPointerDown={onPointerDown}\n onMouseDown={onMouseDown}\n // The role, the selection and the roving tabindex belong to the tab list:\n // they win over the caller's. A tab that is not disabled keeps the\n // caller's aria-disabled.\n role=\"tab\"\n aria-selected={active()}\n aria-disabled={local.disabled || undefined}\n aria-keyshortcuts={keyshortcuts()}\n tabindex={tabStop() ? 0 : -1}\n disabled={tag() === \"button\" ? local.disabled : undefined}\n >\n <span class=\"smwb-tab__content\" ref={mergeRefs(local.contentRef)}>\n <Show when={icon()}>\n <span class=\"smwb-tab__icon\" aria-hidden=\"true\">\n {icon()}\n </span>\n </Show>\n <Show when={label()}>\n <span class=\"smwb-tab__text-label\">{label()}</span>\n </Show>\n </span>\n <Ripple actionRef={(api) => (rippleActions = api)} classes={{ child: \"tab__ripple-child\" }} />\n </Dynamic>\n );\n\n return (\n <Show when={wrapped()} fallback={renderTab()}>\n <div\n class={cn(\"smwb-tab-item\", {\n \"smwb-tab-item--active\": active(),\n \"smwb-tab-item--disabled\": local.disabled,\n })}\n draggable={draggable()}\n >\n {renderTab()}\n <Show when={hasActions()}>\n <span class=\"smwb-tab__actions\" ref={actionsEl}>\n {actions()}\n </span>\n </Show>\n <Show when={local.closable}>\n <button\n type=\"button\"\n class=\"smwb-tab__close\"\n // Out of the Tab order, so the row keeps its one tab stop; Delete on the tab closes it.\n tabindex={-1}\n aria-label={local.closeLabel}\n disabled={Boolean(local.disabled)}\n // A press does not take focus from where it is: from the tab being closed, or the page.\n onMouseDown={(event) => event.preventDefault()}\n onClick={(event) => close(event, \"button\")}\n >\n <Icon name=\"close\" size={16} />\n </button>\n </Show>\n </div>\n </Show>\n );\n}\n\nexport default Tab;\n"],"mappings":"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","names":[],"file":"tab.jsx"}
1
+ {"version":3,"sources":["../../../../../../src/components/navigation/tabs/tab/tab.tsx"],"sourcesContent":["import \"@smwb/ui-styles/less/tokens.entry.less\";\nimport \"@smwb/ui-styles/less/components/tabs/tab/tab.entry.less\";\nimport { type JSX, type ParentProps, Show, children, createSignal, mergeProps, splitProps } from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { Ripple, type RippleActionsRef } from \"../../../base/ripple\";\nimport { Icon } from \"../../../base/icon\";\nimport { useTabsContext, type TabCloseReason } from \"../tabsContext\";\nimport { mergeRefs, type Ref } from \"../../../../primitives/mergeRefs\";\nimport { callHandler } from \"../../../../primitives/callHandler\";\n\nexport type { TabCloseReason };\n\n/** What a function given as `actions` receives. */\nexport interface TabActionsApi {\n /**\n * Ask for the tab to close, as its close button does: `onClose` is called with this event and the\n * reason \"actions\", and `Tabs` moves focus on to the neighbour once the tab goes, even though focus\n * is in a menu drawn outside the row. Call it from the item that closes the tab (\"Terminate\"), with\n * that item's event. It works on a tab that is not `closable`.\n */\n close: (event: Event) => void;\n}\n\n// `onClose` is the close button's, not the element's `close` event handler.\nexport interface TabProps extends Omit<JSX.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement>, \"onClose\"> {\n label?: JSX.Element;\n isActive?: boolean;\n /**\n * Whether the tab is the one in the page's Tab order (`tabindex` 0, the others -1). `Tabs` sets\n * it: the focused tab while focus is in the row, the selected one otherwise. On its own a tab\n * is the stop while `isActive`.\n */\n tabStop?: boolean;\n contentRef?: Ref<HTMLSpanElement>;\n /**\n * A decorative status marker drawn left of the label (a running/done/failed icon). Its\n * wrapper renders `aria-hidden=\"true\"`, so the tab's accessible name stays the label\n * alone: the icon is not announced on top of it. To have the status read out, put it\n * in the `label` itself.\n */\n icon?: JSX.Element;\n stacked?: boolean;\n /** The element to render. A tab with an `href` is an `a` unless you say otherwise. */\n tag?: string;\n /**\n * Navigation mode: where the tab goes. The tab is then a real link (`<a href role=\"tab\">`, with\n * no `target`: a tab never opens another window), so it opens in place and middle click, copy\n * link and the like work. A router takes over the plain click in `onClick` with\n * `event.preventDefault()`; `Tabs` still calls `onChange` for it. A modified or non-primary click\n * (Ctrl, Meta, Shift or Alt held, or a button other than the main one) is the browser's, as\n * \"open in a new tab\": the router must let it through, and `Tabs` does not call `onChange`.\n * The one exception is a middle press on a `closable` tab: it closes the tab instead, as in an\n * editor, and its default is prevented so nothing opens.\n */\n href?: string;\n disabled?: boolean;\n /**\n * Draw a close button after the tab, and let Delete or Backspace on the focused tab close it too\n * (Backspace because a Mac has no Delete key); the tab lists them in `aria-keyshortcuts`. A\n * middle click on the tab closes it as well (`reason` \"middleClick\"): the browser's own\n * middle-click action (autoscroll, opening a link tab in a new window) is suppressed, and the\n * click never selects. The tab does not close itself: `onClose` asks for it and the owner\n * removes the `Tab`. The button is a sibling of the tab, not inside its `role=\"tab\"`, so the\n * tab's accessible name is its label alone.\n * It is out of the Tab order (`tabindex` -1), so the row keeps one tab stop, and a press on it takes\n * no focus and never selects the tab. When the tab that has focus closes, `Tabs` moves focus to the\n * tab that takes its place (the previous one if it was last), skipping disabled tabs. A disabled tab\n * has a disabled button.\n *\n * The button stays in the accessibility tree, named by `closeLabel`: it is how a screen reader user\n * who cannot press Delete, as on a touch screen, closes the tab. It sits in the tab list beside its\n * tab, though, and ARIA 1.2 lets a `tablist` own only `tab`s: a linter that applies that strictly\n * (axe `aria-required-children`) can flag the button, and whatever `actions` holds.\n *\n * To switch it off on a tab, pass `false` rather than leaving it out: a tab given `closable` or\n * `actions` is wrapped in an item with them, a tab given neither is not, and moving between the two\n * recreates the tab and drops its focus.\n */\n closable?: boolean;\n /**\n * Asks for the tab to close, and receives what asked for it: the close button's click (`reason`\n * \"button\"), the key press of Delete or Backspace on the tab (`reason` \"key\", its default is\n * prevented), the middle press on the tab (`reason` \"middleClick\", its default is prevented too),\n * or the event passed to `close` by the tab's `actions` (`reason` \"actions\"). The owner removes\n * the `Tab`.\n */\n onClose?: (event: Event, reason: TabCloseReason) => void;\n /** Accessible label of the close button. English by default; set it to localise, or to name the tab (\"Close Terminal 1\"). */\n closeLabel?: string;\n /**\n * Content after the tab, before the close button: a trigger with a `Menu` (\"Rename\", \"Terminate\"),\n * or any control. Give a function to get `{ close }` (see `TabActionsApi`); it is called once.\n * Like the close button the content is a sibling of the tab, so it is not part of the tab's name;\n * the tab's own `ref`, `class` and handlers stay on the `role=\"tab\"` element. It stays in the\n * accessibility tree as written, inside the tab list (see `closable`).\n *\n * The row has one tab stop, so give the trigger `tabindex={-1}`. Shift+F10 or the Menu key on the\n * focused tab, which the tab lists in `aria-keyshortcuts`, focuses the first control in `actions`\n * and clicks it, unless that control says `aria-expanded=\"true\"` (it is already open). If the\n * control names its popup in `aria-controls`, the first enabled `menuitem` in that element then\n * takes focus, as the WAI-ARIA menu button pattern asks: ArrowDown moves on, Enter chooses, and\n * Escape hands focus back to the trigger. Without `aria-controls` focus stays on the trigger.\n *\n * The row clips what overflows it: draw the menu in a `Portal`, anchored to the trigger and with\n * the `id` the trigger names. A choice that removes the tab (\"Terminate\") should call `close` with\n * its event, so that `onClose` removes the tab and `Tabs` moves focus on to the neighbour; a tab\n * removed some other way leaves focus on the page.\n */\n actions?: JSX.Element | ((api: TabActionsApi) => JSX.Element);\n ref?: Ref<HTMLButtonElement | HTMLAnchorElement>;\n}\n\n/** A click that asks the browser for something else than \"go here\": a new tab, a new window, a download. */\nconst isModifiedClick = (event: MouseEvent): boolean =>\n event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;\n\nconst hasModifier = (event: KeyboardEvent): boolean => event.ctrlKey || event.metaKey || event.altKey || event.shiftKey;\n\n/** What the Menu key and Shift+F10 stand for: the actions' trigger. */\nconst ACTIONS_TRIGGER = 'button:not(:disabled), a[href], [role=\"button\"]:not([aria-disabled=\"true\"]), [tabindex]';\n\n/** The item of an opened menu that takes focus first. */\nconst FIRST_MENU_ITEM = '[role^=\"menuitem\"]:not([aria-disabled=\"true\"])';\n\n/** Focus the first item of the popup `trigger` names in `aria-controls`, if it is there. */\nconst focusPopupOf = (trigger: HTMLElement): void => {\n for (const id of trigger.getAttribute(\"aria-controls\")?.split(/\\s+/) ?? []) {\n const item = id ? trigger.ownerDocument.getElementById(id)?.querySelector<HTMLElement>(FIRST_MENU_ITEM) : null;\n if (item) {\n // The menu may not be placed yet: a scroll to it would jump to the corner it starts in.\n item.focus({ preventScroll: true });\n return;\n }\n }\n};\n\nexport function Tab(props: ParentProps<TabProps>): JSX.Element {\n const ctx = useTabsContext();\n const [root, setRoot] = createSignal<HTMLButtonElement | HTMLAnchorElement>();\n const merged = mergeProps({ isActive: false, stacked: false, closeLabel: \"Close tab\" }, props);\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"label\",\n \"isActive\",\n \"contentRef\",\n \"icon\",\n \"stacked\",\n \"tag\",\n \"href\",\n \"tabStop\",\n \"disabled\",\n // `Tabs` owns this: it is the item that drags, not the tab. The caller's value\n // is dropped, as in the React `Tab`.\n \"draggable\",\n \"closable\",\n \"onClose\",\n \"closeLabel\",\n \"actions\",\n \"id\",\n \"aria-controls\",\n // A tab opens in place: a caller's target is dropped, not passed on.\n \"target\" as keyof TabProps,\n \"onClick\",\n \"onKeyDown\",\n \"ref\",\n // The tab sets this on its root too; its own handler calls the caller's first.\n \"onPointerDown\",\n \"onMouseDown\",\n ]);\n\n // The tab's position in the tab list: it follows the tab when tabs around it\n // are added, removed or reordered.\n const index = ctx\n ? ctx.registerTab(root, {\n id: () => local.id,\n disabled: () =>\n Boolean(local.disabled) || props[\"aria-disabled\"] === true || props[\"aria-disabled\"] === \"true\",\n closable: () => Boolean(local.closable),\n requestClose: (event) => close(event, \"key\"),\n })\n : () => -1;\n\n // Read the icon and the label once: markup passed as a prop is created anew on\n // every read, and during hydration the copy made for the <Show> test has no\n // server DOM node to adopt (\"Unable to find DOM nodes for hydration key\").\n const icon = children(() => local.icon);\n const label = children(() => local.label);\n // A content-width row cuts a long label with an ellipsis, so a string label is its own title there\n // and the full text shows on hover. It sits on the label, not on the tab: a title on the tab is\n // read as its description, next to a name that says the same. A title the caller gave the tab is\n // the tooltip instead, and the label does not shadow it; a label that is not a string has no text\n // to give.\n const fitTitle = (): string | undefined => {\n const text = label();\n return ctx?.fit?.() && props.title === undefined && typeof text === \"string\" && text !== \"\" ? text : undefined;\n };\n // The actions are drawn whenever they are given, so reading them here, once, is safe. A function\n // is the tab's to call, with its api: `children` would call it with nothing.\n const actionsApi: TabActionsApi = { close: (event) => close(event, \"actions\") };\n const actions = children(() => {\n const given = local.actions;\n return typeof given === \"function\" ? (given as (api: TabActionsApi) => JSX.Element)(actionsApi) : given;\n });\n const hasActions = (): boolean => actions.toArray().length > 0;\n\n let rippleActions: RippleActionsRef | undefined;\n let actionsEl: HTMLSpanElement | undefined;\n\n const active = (): boolean => (ctx ? ctx.value() === index() : local.isActive);\n\n const tag = (): string => local.tag ?? (local.href !== undefined ? \"a\" : \"button\");\n // Anything but a button is not disabled by the attribute: its clicks are swallowed here.\n const inert = (): boolean => Boolean(local.disabled) && tag() !== \"button\";\n\n const onClick: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, MouseEvent> = (event) => {\n if (inert()) {\n event.preventDefault();\n return;\n }\n // Inside Tabs too the caller's onClick runs first, then the tab list picks the tab.\n callHandler(local.onClick, event);\n // A link tab opens elsewhere on a modified click: the browser's, not a selection here.\n if (local.href !== undefined && isModifiedClick(event)) return;\n ctx?.onChange(event, index());\n };\n\n const close = (event: Event, reason: TabCloseReason): void => {\n // The row notes which tab is closing before the owner removes it.\n ctx?.closing(index(), reason);\n local.onClose?.(event, reason);\n };\n\n // A button clicks on Enter and Space by itself, a link on Enter only: Space does it here.\n const onKeyDown: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, KeyboardEvent> = (event) => {\n callHandler(local.onKeyDown, event);\n if (local.disabled || event.defaultPrevented || event.target !== event.currentTarget) return;\n if (tag() !== \"button\" && event.key === \" \") {\n event.preventDefault();\n event.currentTarget.click();\n } else if (local.closable && (event.key === \"Delete\" || event.key === \"Backspace\") && !hasModifier(event)) {\n event.preventDefault();\n close(event, \"key\");\n } else if (hasActions() && (event.key === \"ContextMenu\" || (event.key === \"F10\" && event.shiftKey))) {\n // The Menu key, or Shift+F10: the keyboard's right click. The trigger takes focus first, so\n // the menu it opens hands focus back to it on Escape.\n const trigger = actionsEl?.querySelector<HTMLElement>(ACTIONS_TRIGGER);\n if (trigger) {\n event.preventDefault();\n trigger.focus();\n // The keys mean \"open\": a menu that already is open is not toggled shut.\n if (trigger.getAttribute(\"aria-expanded\") !== \"true\") {\n trigger.click();\n }\n focusPopupOf(trigger);\n }\n }\n };\n\n const onPointerDown: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, PointerEvent> = (event) => {\n callHandler(local.onPointerDown, event);\n rippleActions?.onRipple(event);\n };\n\n // Middle click on a closable tab closes it, IDE-style: the browser's own middle-click\n // action (autoscroll, opening a link tab in a new window) is suppressed and the tab is\n // never selected. A middle click on a tab that is not closable is the browser's, untouched.\n const onMouseDown: JSX.EventHandler<HTMLButtonElement | HTMLAnchorElement, MouseEvent> = (event) => {\n callHandler(local.onMouseDown, event);\n if (event.button === 1 && local.closable && !local.disabled) {\n event.preventDefault();\n close(event, \"middleClick\");\n }\n };\n\n // Inside Tabs the row decides, whatever the caller passed.\n const tabStop = (): boolean => (ctx ? ctx.tabStop(index()) : (local.tabStop ?? active()));\n\n // What the tab answers to, for assistive technology; the caller's own list is kept.\n // The chords are best-effort: browsers reserve Mod+W and Mod+Shift+[/] in a page of\n // their own tabs, and they bite only in an embedded webview.\n const keyshortcuts = (): string | undefined =>\n [\n props[\"aria-keyshortcuts\"],\n !local.disabled && local.closable ? \"Delete Backspace\" : undefined,\n !local.disabled && hasActions() ? \"Shift+F10 ContextMenu\" : undefined,\n !local.disabled && local.closable ? \"Meta+W Control+W\" : undefined,\n !local.disabled ? \"Meta+Shift+[ Control+Shift+[ Meta+Shift+] Control+Shift+]\" : undefined,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n // A tab given neither `closable` nor `actions` is the bare element, as it always was.\n const wrapped = (): boolean => local.closable !== undefined || actions() !== undefined;\n\n // Only a reorderable row makes its items draggable, and a disabled tab never — the same\n // contract as the registration's `disabled`. Rendered on the item (the wrapper, or the\n // bare tab when there is none), so `draggable` is in the server markup, as in React.\n const draggable = (): boolean | undefined =>\n ctx?.reorderable() && !local.disabled && props[\"aria-disabled\"] !== true && props[\"aria-disabled\"] !== \"true\"\n ? true\n : undefined;\n\n const renderTab = (): JSX.Element => (\n <Dynamic\n component={tag()}\n {...rest}\n ref={mergeRefs(local.ref, setRoot)}\n class={cn(\"smwb-tab\", local.class, {\n \"smwb-tab--active\": active(),\n \"smwb-tab--stacked\": local.stacked,\n \"smwb-tab--disabled\": local.disabled,\n })}\n id={local.id ?? ctx?.tabId(index())}\n aria-controls={local[\"aria-controls\"] ?? (ctx?.hasPanels() ? ctx.panelId(index()) : undefined)}\n // A disabled link has no href, so it is no link to follow or to focus.\n href={inert() ? undefined : local.href}\n draggable={wrapped() ? undefined : draggable()}\n onClick={onClick}\n onKeyDown={onKeyDown}\n onPointerDown={onPointerDown}\n onMouseDown={onMouseDown}\n // The role, the selection and the roving tabindex belong to the tab list:\n // they win over the caller's. A tab that is not disabled keeps the\n // caller's aria-disabled.\n role=\"tab\"\n aria-selected={active()}\n aria-disabled={local.disabled || undefined}\n aria-keyshortcuts={keyshortcuts()}\n tabindex={tabStop() ? 0 : -1}\n disabled={tag() === \"button\" ? local.disabled : undefined}\n >\n <span class=\"smwb-tab__content\" ref={mergeRefs(local.contentRef)}>\n <Show when={icon()}>\n <span class=\"smwb-tab__icon\" aria-hidden=\"true\">\n {icon()}\n </span>\n </Show>\n <Show when={label()}>\n <span class=\"smwb-tab__text-label\" title={fitTitle()}>\n {label()}\n </span>\n </Show>\n </span>\n <Ripple actionRef={(api) => (rippleActions = api)} classes={{ child: \"tab__ripple-child\" }} />\n </Dynamic>\n );\n\n return (\n <Show when={wrapped()} fallback={renderTab()}>\n <div\n class={cn(\"smwb-tab-item\", {\n \"smwb-tab-item--active\": active(),\n \"smwb-tab-item--disabled\": local.disabled,\n })}\n draggable={draggable()}\n >\n {renderTab()}\n <Show when={hasActions()}>\n <span class=\"smwb-tab__actions\" ref={actionsEl}>\n {actions()}\n </span>\n </Show>\n <Show when={local.closable}>\n <button\n type=\"button\"\n class=\"smwb-tab__close\"\n // Out of the Tab order, so the row keeps its one tab stop; Delete on the tab closes it.\n tabindex={-1}\n aria-label={local.closeLabel}\n disabled={Boolean(local.disabled)}\n // A press does not take focus from where it is: from the tab being closed, or the page.\n onMouseDown={(event) => event.preventDefault()}\n onClick={(event) => close(event, \"button\")}\n >\n <Icon name=\"close\" size={16} />\n </button>\n </Show>\n </div>\n </Show>\n );\n}\n\nexport default Tab;\n"],"mappings":"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","names":[],"file":"tab.jsx"}
@@ -55,6 +55,7 @@ function Tabs(props) {
55
55
  scrollButtons: false,
56
56
  overflowMenu: false,
57
57
  dense: false,
58
+ fit: false,
58
59
  orientation: "horizontal",
59
60
  scrollBackAriaLabel: "Scroll tabs back",
60
61
  scrollForwardAriaLabel: "Scroll tabs forward",
@@ -74,6 +75,7 @@ function Tabs(props) {
74
75
  "overflowMenu",
75
76
  "overflowMenuAriaLabel",
76
77
  "dense",
78
+ "fit",
77
79
  "orientation",
78
80
  "panels",
79
81
  "id",
@@ -243,7 +245,7 @@ function Tabs(props) {
243
245
  let dragSourceIndex = null;
244
246
  let draggingItem = null;
245
247
  let dropTargetItem = null;
246
- const dragItemOf = (target) => target instanceof Element ? itemOf(target) : null;
248
+ const dragItemOf = (target) => target instanceof Element && target !== tabListEl ? itemOf(target) : null;
247
249
  const clearDragMarks = () => {
248
250
  draggingItem?.classList.remove("smwb-tab-item--dragging");
249
251
  dropTargetItem?.classList.remove("smwb-tab-item--drop-target");
@@ -383,6 +385,7 @@ function Tabs(props) {
383
385
  };
384
386
  const contextValue = {
385
387
  value: () => local.value,
388
+ fit: () => local.fit,
386
389
  tabStop: (index) => stopIndex() === index,
387
390
  tabId,
388
391
  panelId,
@@ -434,6 +437,7 @@ function Tabs(props) {
434
437
  "smwb-tabs",
435
438
  {
436
439
  "smwb-tabs--dense": local.dense,
440
+ "smwb-tabs--fit": local.fit,
437
441
  "smwb-tabs--overflow-start": overflowStart(),
438
442
  "smwb-tabs--overflow-end": overflowEnd()
439
443
  },