@smwb/ui-solid 2.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.
- package/README.md +115 -0
- package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
- package/dist/assets/styles/less/components/avatar/avatar.entry.css +1 -1
- package/dist/assets/styles/less/components/breadcrumbs/breadcrumbs.entry.css +1 -1
- package/dist/assets/styles/less/components/button/button.entry.css +1 -1
- package/dist/assets/styles/less/components/buttonGroup/buttonGroup.entry.css +1 -1
- package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -1
- package/dist/assets/styles/less/components/meter/meter.entry.css +1 -1
- package/dist/assets/styles/less/components/screenDivider/screenDivider.entry.css +1 -1
- package/dist/assets/styles/less/components/sheet/sheet.entry.css +1 -1
- package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -1
- package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -1
- package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
- package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
- package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
- package/dist/assets/styles/less/tokens.entry.css +1 -1
- package/dist/components/dataDisplay/avatar/avatar.d.ts +5 -2
- package/dist/components/dataDisplay/avatar/avatar.js +9 -9
- package/dist/components/dataDisplay/avatar/avatar.js.map +1 -1
- package/dist/components/dataDisplay/chart/chart.d.ts +16 -8
- package/dist/components/dataDisplay/chart/chartFull.d.ts +14 -0
- package/dist/components/dataDisplay/chart/core.d.ts +19 -0
- package/dist/components/dataDisplay/chart/index.d.ts +1 -1
- package/dist/components/dataDisplay/dagView/dagView.d.ts +4 -0
- package/dist/components/dataDisplay/dagView/dagView.js +124 -123
- package/dist/components/dataDisplay/dagView/dagView.js.map +1 -1
- package/dist/components/dataDisplay/dagView/index.d.ts +1 -1
- package/dist/components/dataDisplay/meter/index.d.ts +1 -1
- package/dist/components/dataDisplay/meter/meter.d.ts +14 -0
- package/dist/components/dataDisplay/meter/meter.js +32 -30
- package/dist/components/dataDisplay/meter/meter.js.map +1 -1
- package/dist/components/dataDisplay/statusDot/index.d.ts +1 -1
- package/dist/components/dataDisplay/statusDot/statusDot.d.ts +10 -1
- package/dist/components/dataDisplay/statusDot/statusDot.js +20 -11
- package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -1
- package/dist/components/dataDisplay/treeView/treeView.d.ts +18 -2
- package/dist/components/dataDisplay/treeView/treeView.js +140 -121
- package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/components/inputs/button/button.d.ts +7 -0
- package/dist/components/inputs/button/button.js +57 -51
- package/dist/components/inputs/button/button.js.map +1 -1
- package/dist/components/inputs/toggle/toggle.d.ts +6 -0
- package/dist/components/inputs/toggle/toggle.js +23 -23
- package/dist/components/inputs/toggle/toggle.js.map +1 -1
- package/dist/components/layout/appLayout/appLayout.d.ts +6 -1
- package/dist/components/layout/appLayout/appLayout.js +49 -42
- package/dist/components/layout/appLayout/appLayout.js.map +1 -1
- package/dist/components/layout/screenDivider/screenDivider.d.ts +12 -0
- package/dist/components/layout/screenDivider/screenDivider.js +87 -46
- package/dist/components/layout/screenDivider/screenDivider.js.map +1 -1
- package/dist/components/layout/sheet/sheet.d.ts +11 -0
- package/dist/components/layout/sheet/sheet.js +122 -102
- package/dist/components/layout/sheet/sheet.js.map +1 -1
- package/dist/components/layout/tabGroups/index.d.ts +1 -1
- package/dist/components/layout/tabGroups/tabGroups.d.ts +44 -1
- package/dist/components/layout/tabGroups/tabGroups.js +500 -460
- package/dist/components/layout/tabGroups/tabGroups.js.map +1 -1
- package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +16 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js +102 -70
- package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -1
- package/dist/components/navigation/appBar/appBar.d.ts +12 -0
- package/dist/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/components/navigation/breadcrumbs/breadcrumbs.d.ts +9 -0
- package/dist/components/navigation/breadcrumbs/breadcrumbs.js +47 -31
- package/dist/components/navigation/breadcrumbs/breadcrumbs.js.map +1 -1
- package/dist/components/navigation/tabs/tab/tab.js +71 -68
- package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/components/navigation/tabs/tabs.d.ts +11 -0
- package/dist/components/navigation/tabs/tabs.js +19 -16
- package/dist/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/components/navigation/tabs/tabsContext.d.ts +2 -0
- package/dist/components/navigation/tabs/tabsContext.js.map +1 -1
- package/dist/headless/components/dataDisplay/avatar/avatar.js +9 -9
- package/dist/headless/components/dataDisplay/avatar/avatar.js.map +1 -1
- package/dist/headless/components/dataDisplay/dagView/dagView.js +133 -132
- package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -1
- package/dist/headless/components/dataDisplay/meter/meter.js +32 -30
- package/dist/headless/components/dataDisplay/meter/meter.js.map +1 -1
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js +19 -10
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -1
- package/dist/headless/components/dataDisplay/treeView/treeView.js +139 -120
- package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/headless/components/inputs/button/button.js +57 -51
- package/dist/headless/components/inputs/button/button.js.map +1 -1
- package/dist/headless/components/inputs/toggle/toggle.js +23 -23
- package/dist/headless/components/inputs/toggle/toggle.js.map +1 -1
- package/dist/headless/components/layout/appLayout/appLayout.js +52 -45
- package/dist/headless/components/layout/appLayout/appLayout.js.map +1 -1
- package/dist/headless/components/layout/screenDivider/screenDivider.js +88 -47
- package/dist/headless/components/layout/screenDivider/screenDivider.js.map +1 -1
- package/dist/headless/components/layout/sheet/sheet.js +124 -104
- package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
- package/dist/headless/components/layout/tabGroups/tabGroups.js +500 -460
- package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -1
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +102 -70
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -1
- package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/headless/components/navigation/breadcrumbs/breadcrumbs.js +46 -30
- package/dist/headless/components/navigation/breadcrumbs/breadcrumbs.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tab/tab.js +70 -67
- package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabs.js +19 -16
- package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -1
- package/dist/headless/primitives/publishHeaderOffset.js +19 -0
- package/dist/headless/primitives/publishHeaderOffset.js.map +1 -0
- package/dist/headless/source/components/dataDisplay/avatar/avatar.jsx +1 -0
- package/dist/headless/source/components/dataDisplay/avatar/avatar.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/chart/chart.jsx +14 -12
- package/dist/headless/source/components/dataDisplay/chart/chart.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/chart/chartFull.js +12 -0
- package/dist/headless/source/components/dataDisplay/chart/chartFull.js.map +7 -0
- package/dist/headless/source/components/dataDisplay/chart/core.js +11 -0
- package/dist/headless/source/components/dataDisplay/chart/core.js.map +7 -0
- package/dist/headless/source/components/dataDisplay/chart/index.js +1 -1
- package/dist/headless/source/components/dataDisplay/chart/index.js.map +1 -1
- package/dist/headless/source/components/dataDisplay/dagView/dagView.jsx +2 -1
- package/dist/headless/source/components/dataDisplay/dagView/dagView.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/dagView/index.js.map +2 -2
- package/dist/headless/source/components/dataDisplay/meter/index.js.map +1 -1
- package/dist/headless/source/components/dataDisplay/meter/meter.jsx +14 -2
- package/dist/headless/source/components/dataDisplay/meter/meter.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/statusDot/index.js.map +1 -1
- package/dist/headless/source/components/dataDisplay/statusDot/statusDot.jsx +13 -1
- package/dist/headless/source/components/dataDisplay/statusDot/statusDot.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/treeView/treeView.jsx +16 -3
- package/dist/headless/source/components/dataDisplay/treeView/treeView.jsx.map +1 -1
- package/dist/headless/source/components/inputs/button/button.jsx +26 -1
- package/dist/headless/source/components/inputs/button/button.jsx.map +1 -1
- package/dist/headless/source/components/inputs/toggle/toggle.jsx +9 -2
- package/dist/headless/source/components/inputs/toggle/toggle.jsx.map +1 -1
- package/dist/headless/source/components/layout/appLayout/appLayout.jsx +14 -2
- package/dist/headless/source/components/layout/appLayout/appLayout.jsx.map +1 -1
- package/dist/headless/source/components/layout/screenDivider/screenDivider.jsx +102 -18
- package/dist/headless/source/components/layout/screenDivider/screenDivider.jsx.map +1 -1
- package/dist/headless/source/components/layout/sheet/sheet.jsx +14 -1
- package/dist/headless/source/components/layout/sheet/sheet.jsx.map +1 -1
- package/dist/headless/source/components/layout/tabGroups/index.js.map +1 -1
- package/dist/headless/source/components/layout/tabGroups/tabGroups.jsx +55 -1
- package/dist/headless/source/components/layout/tabGroups/tabGroups.jsx.map +1 -1
- package/dist/headless/source/components/layout/tabGroups/tabGroupsFocus.js +42 -0
- package/dist/headless/source/components/layout/tabGroups/tabGroupsFocus.js.map +2 -2
- package/dist/headless/source/components/navigation/appBar/appBar.jsx.map +1 -1
- package/dist/headless/source/components/navigation/breadcrumbs/breadcrumbs.jsx +39 -4
- package/dist/headless/source/components/navigation/breadcrumbs/breadcrumbs.jsx.map +1 -1
- package/dist/headless/source/components/navigation/tabs/tab/tab.jsx +7 -1
- package/dist/headless/source/components/navigation/tabs/tab/tab.jsx.map +1 -1
- package/dist/headless/source/components/navigation/tabs/tabs.jsx +5 -1
- package/dist/headless/source/components/navigation/tabs/tabs.jsx.map +1 -1
- package/dist/headless/source/components/navigation/tabs/tabsContext.js.map +2 -2
- package/dist/headless/source/index.js +8 -1
- package/dist/headless/source/index.js.map +2 -2
- package/dist/headless/source/primitives/publishHeaderOffset.js +34 -0
- package/dist/headless/source/primitives/publishHeaderOffset.js.map +7 -0
- package/dist/index.d.ts +5 -5
- package/dist/primitives/publishHeaderOffset.d.ts +7 -0
- package/dist/primitives/publishHeaderOffset.js +19 -0
- package/dist/primitives/publishHeaderOffset.js.map +1 -0
- package/dist/source/components/dataDisplay/avatar/avatar.jsx +1 -0
- package/dist/source/components/dataDisplay/avatar/avatar.jsx.map +1 -1
- package/dist/source/components/dataDisplay/chart/chart.jsx +14 -12
- package/dist/source/components/dataDisplay/chart/chart.jsx.map +1 -1
- package/dist/source/components/dataDisplay/chart/chartFull.js +12 -0
- package/dist/source/components/dataDisplay/chart/chartFull.js.map +7 -0
- package/dist/source/components/dataDisplay/chart/core.js +11 -0
- package/dist/source/components/dataDisplay/chart/core.js.map +7 -0
- package/dist/source/components/dataDisplay/chart/index.js +1 -1
- package/dist/source/components/dataDisplay/chart/index.js.map +1 -1
- package/dist/source/components/dataDisplay/dagView/dagView.jsx +2 -1
- package/dist/source/components/dataDisplay/dagView/dagView.jsx.map +1 -1
- package/dist/source/components/dataDisplay/dagView/index.js.map +2 -2
- package/dist/source/components/dataDisplay/meter/index.js.map +1 -1
- package/dist/source/components/dataDisplay/meter/meter.jsx +14 -2
- package/dist/source/components/dataDisplay/meter/meter.jsx.map +1 -1
- package/dist/source/components/dataDisplay/statusDot/index.js.map +1 -1
- package/dist/source/components/dataDisplay/statusDot/statusDot.jsx +13 -1
- package/dist/source/components/dataDisplay/statusDot/statusDot.jsx.map +1 -1
- package/dist/source/components/dataDisplay/treeView/treeView.jsx +16 -3
- package/dist/source/components/dataDisplay/treeView/treeView.jsx.map +1 -1
- package/dist/source/components/inputs/button/button.jsx +26 -1
- package/dist/source/components/inputs/button/button.jsx.map +1 -1
- package/dist/source/components/inputs/toggle/toggle.jsx +9 -2
- package/dist/source/components/inputs/toggle/toggle.jsx.map +1 -1
- package/dist/source/components/layout/appLayout/appLayout.jsx +14 -2
- package/dist/source/components/layout/appLayout/appLayout.jsx.map +1 -1
- package/dist/source/components/layout/screenDivider/screenDivider.jsx +102 -18
- package/dist/source/components/layout/screenDivider/screenDivider.jsx.map +1 -1
- package/dist/source/components/layout/sheet/sheet.jsx +14 -1
- package/dist/source/components/layout/sheet/sheet.jsx.map +1 -1
- package/dist/source/components/layout/tabGroups/index.js.map +1 -1
- package/dist/source/components/layout/tabGroups/tabGroups.jsx +55 -1
- package/dist/source/components/layout/tabGroups/tabGroups.jsx.map +1 -1
- package/dist/source/components/layout/tabGroups/tabGroupsFocus.js +42 -0
- package/dist/source/components/layout/tabGroups/tabGroupsFocus.js.map +2 -2
- package/dist/source/components/navigation/appBar/appBar.jsx.map +1 -1
- package/dist/source/components/navigation/breadcrumbs/breadcrumbs.jsx +39 -4
- package/dist/source/components/navigation/breadcrumbs/breadcrumbs.jsx.map +1 -1
- package/dist/source/components/navigation/tabs/tab/tab.jsx +7 -1
- package/dist/source/components/navigation/tabs/tab/tab.jsx.map +1 -1
- package/dist/source/components/navigation/tabs/tabs.jsx +5 -1
- package/dist/source/components/navigation/tabs/tabs.jsx.map +1 -1
- package/dist/source/components/navigation/tabs/tabsContext.js.map +2 -2
- package/dist/source/index.js +8 -1
- package/dist/source/index.js.map +2 -2
- package/dist/source/primitives/publishHeaderOffset.js +34 -0
- package/dist/source/primitives/publishHeaderOffset.js.map +7 -0
- package/package.json +9 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","sources":["../../../../../src/components/navigation/tabs/tabs.tsx"],"sourcesContent":["import {\n type Accessor,\n type JSX,\n type ParentProps,\n For,\n Show,\n children,\n createComputed,\n createEffect,\n createMemo,\n createSignal,\n createUniqueId,\n mergeProps,\n on,\n onCleanup,\n onMount,\n splitProps,\n} from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { debounce } from \"../../../utils/debounce\";\nimport { animate } from \"../../../utils/animate\";\nimport { matchesKeyboardShortcut } from \"../../../utils/keyboardShortcut\";\nimport { TabsContext, type TabInfo, type TabsContextValue } from \"./tabsContext\";\nimport { Tab } from \"./tab/tab\";\nimport { getHiddenIndexes } from \"./tabs.utils\";\nimport { Menu } from \"../menu\";\nimport { MenuItem } from \"../menu/menuItem\";\nimport { Icon } from \"../../base/icon\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { createRovingTabIndex } from \"../../../primitives/createRovingTabIndex\";\n\n/**\n * Tabs follow the WAI-ARIA tabs pattern with manual activation. The selected tab is the row's one\n * tab stop (`tabindex` 0, the others -1). The arrow keys along the row's `orientation` move focus to\n * the next or the previous tab (wrapping at the ends), Home and End to the first and the last one;\n * disabled tabs are skipped. Enter or Space then selects the focused tab, as a click does:\n * `onChange` is called for it, with the key's click. Moving focus changes nothing by itself, so a\n * row of link tabs does not navigate as the arrows pass them. Tab leaves the row for what follows\n * it, the selected `TabPanel` first when `panels` are given.\n *\n * A `Tab` can be `closable` and take `actions`; they sit beside the tab and out of the Tab order.\n * Delete on the focused tab, its close button or its `actions` (through `close`) ask `onClose` to\n * close it, and when it goes, focus moves to the tab that takes its place instead of falling to the\n * page. A middle click on a closable tab closes it too.\n *\n * With `onReorder` the row's tabs drag onto one another to reorder: `onReorder(from, to)` reports\n * the drop and the owner moves the tabs; dropping the selected tab reports its new index through\n * `onChange` as well, so the selection follows the moved tab. With `overflowMenu` a scrollable\n * row that overflows gains\n * a trigger beside it listing the clipped tabs. The chords Mod+W (close the focused closable tab)\n * and Mod+Shift+[ / Mod+Shift+] (switch to the previous / next tab) are handled on the row, as\n * best-effort: a browser of its own tabs reserves them.\n */\nexport interface TabsProps {\n /**\n * Index of the selected tab: its position in the row. Tabs count in the order they\n * render, so a tab behind a `<Show>` that is off takes no index, and tabs added,\n * removed or reordered count by their new place.\n */\n value: number;\n /**\n * Called with the index of the clicked tab, counted as for `value`. A tab chosen from the keyboard\n * (Enter or Space on the focused tab) calls it with that click too. A modified or non-primary\n * click (Ctrl, Meta, Shift or Alt held, or a button other than the main one) on a link tab\n * (`Tab` with `href`) is the browser's, as \"open in a new tab\": it does not call `onChange`.\n */\n onChange: (event: MouseEvent & { currentTarget: HTMLElement; target: Element }, index: number) => void;\n /**\n * Which way the tabs run. It sets `aria-orientation` on the tab list and picks the arrow keys that\n * move between tabs: Left and Right when horizontal, Up and Down when vertical. The styles draw\n * a horizontal row; a vertical list is yours to lay out.\n */\n orientation?: \"horizontal\" | \"vertical\";\n /**\n * The content of the tabs: `TabPanel`s, rendered after the tab row. With them each tab gets\n * `aria-controls` its panel and each panel `aria-labelledby` its tab. Without them the tabs link\n * to nothing, as before. Give a panel to every tab: a tab whose panel is left out still names it.\n * A `TabPanel` placed anywhere else is not linked to the tabs and is always shown.\n */\n panels?: JSX.Element;\n /**\n * Base of the ids that link tabs and panels: tab `n` is `{id}-tab-{n}`, its panel `{id}-panel-{n}`.\n * It is also the id of the root element. A generated one by default.\n */\n id?: string;\n /** Draw the indicator as wide as the selected tab's label rather than the whole tab. */\n indicatorContent?: boolean;\n /**\n * Let the tab row scroll sideways instead of clipping it. The edge beyond which\n * more tabs are hidden fades out.\n */\n scrollable?: boolean;\n /**\n * With `scrollable`: buttons at both ends that scroll the row while it overflows. They are for\n * the pointer and stay out of the Tab order: the arrow keys reach every tab and scroll it into\n * view.\n */\n scrollButtons?: boolean;\n /**\n * Present ⇒ the row is reorderable by dragging a tab onto another (pointer-only; there is no\n * keyboard reorder). `Tabs` does not move the tabs itself: it reports the drag with\n * `onReorder(from, to)` — indexes counted as for `value` — and the owner reorders its state.\n * The tabs keep their focus through a reorder; when the moved tab is the selected one,\n * `onChange` reports its new index too, so a controlled owner keeps it selected. That `onChange`\n * carries the drop's own event standing in for the click's: the index argument is authoritative —\n * `currentTarget` is the scroll area the drop delegates to, not the tab.\n */\n onReorder?: (from: number, to: number) => void;\n /**\n * With `scrollable`: when the row overflows, a trigger button is rendered beside the scroller\n * (in the scroll buttons' spot) that opens a menu of the tabs the viewport clips — any clipped\n * part beyond a 1px tolerance counts. Each entry shows the tab's icon and label, the selected one is marked\n * `aria-current=\"true\"`, and choosing one calls `onChange` for it and scrolls it into view.\n * The trigger appears only after the browser has measured an overflow, so the server markup\n * shows none.\n */\n overflowMenu?: boolean;\n /** Accessible label of the overflow-menu trigger. English by default; set it to localise. */\n overflowMenuAriaLabel?: string;\n /**\n * Compact tabs: a shorter row — `--smui-tabDenseHeight` (36px) — with labels as written (no\n * capitals, no letter spacing) and less padding.\n */\n dense?: boolean;\n /** Accessible label of the button that scrolls back. */\n scrollBackAriaLabel?: string;\n /** Accessible label of the button that scrolls forward. */\n scrollForwardAriaLabel?: string;\n class?: string;\n children?: JSX.Element;\n \"aria-label\"?: string;\n ref?: Ref<HTMLDivElement>;\n}\n\ninterface IndicatorStyle {\n root: { left?: number; width?: number };\n content?: { width: number };\n}\n\nconst VIEW_NEXT_TAB_PX = 40;\n/** A scroll button moves the row by this share of its visible width. */\nconst SCROLL_PAGE = 0.8;\n\n/** What Tabs knows of each of its tabs. */\ninterface Registration extends TabInfo {\n index: Accessor<number>;\n}\n\n/**\n * The tab list's children, resolved once, with their elements reported in order\n * whenever they change. It renders inside the context provider, so the tabs it\n * creates find their Tabs.\n */\nfunction TabListItems(props: { children?: JSX.Element; onItems: (items: Element[]) => void }): JSX.Element {\n const resolved = children(() => props.children);\n if (!isServer) {\n createComputed(() => props.onItems(resolved.toArray().filter((node) => node instanceof Element)));\n }\n return <>{resolved()}</>;\n}\n\n/**\n * The `panels`, resolved once, inside the context provider so that the panels find their Tabs, and\n * before the tab row renders so that the tabs know whether they control anything. It draws\n * nothing itself: Tabs places what it reports after the row.\n */\nfunction PanelsResolver(props: {\n children?: JSX.Element;\n onPanels: (panels: JSX.Element, has: boolean) => void;\n}): null {\n const resolved = children(() => props.children);\n createComputed(() =>\n props.onPanels(\n resolved(),\n resolved.toArray().some((node) => node != null && node !== false && node !== \"\")\n )\n );\n return null;\n}\n\nexport function Tabs(props: ParentProps<TabsProps>): JSX.Element {\n const merged = mergeProps(\n {\n indicatorContent: false,\n scrollable: false,\n scrollButtons: false,\n overflowMenu: false,\n dense: false,\n orientation: \"horizontal\" as const,\n scrollBackAriaLabel: \"Scroll tabs back\",\n scrollForwardAriaLabel: \"Scroll tabs forward\",\n overflowMenuAriaLabel: \"More tabs\",\n },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"children\",\n \"onChange\",\n \"value\",\n \"indicatorContent\",\n \"scrollable\",\n \"scrollButtons\",\n \"onReorder\",\n \"overflowMenu\",\n \"overflowMenuAriaLabel\",\n \"dense\",\n \"orientation\",\n \"panels\",\n \"id\",\n \"scrollBackAriaLabel\",\n \"scrollForwardAriaLabel\",\n \"aria-label\",\n \"ref\",\n ]);\n\n const generatedId = createUniqueId();\n const baseId = (): string => local.id ?? generatedId;\n const [registrations, setRegistrations] = createSignal<Registration[]>([]);\n // A tab's own id is the one its panel is labelled by.\n const tabId = (index: number): string =>\n registrations()\n .find((registration) => registration.index() === index)\n ?.id() ?? `${baseId()}-tab-${index}`;\n const panelId = (index: number): string => `${baseId()}-panel-${index}`;\n const [panels, setPanels] = createSignal<JSX.Element>();\n const [hasPanels, setHasPanels] = createSignal(false);\n // The tab that has focus while focus is in the tab list: it is the row's tab stop then, so\n // Tab from there leaves the row instead of landing on the selected tab again.\n const [focusedIndex, setFocusedIndex] = createSignal<number | null>(null);\n\n const [mounted, setMounted] = createSignal(false);\n const [indicatorStyle, setIndicatorStyle] = createSignal<IndicatorStyle>({ root: {} });\n // Whether tabs are hidden past the start / the end of a scrollable row. Only\n // measured in the browser, so the server markup shows neither.\n const [overflowStart, setOverflowStart] = createSignal(false);\n const [overflowEnd, setOverflowEnd] = createSignal(false);\n // The indexes of the tabs the scroller's viewport clips: what the overflow menu lists.\n // Empty on the server and until the first measurement, like the overflow state.\n const [hiddenIndexes, setHiddenIndexes] = createSignal<number[]>([]);\n // The overflow-menu trigger and its menu, composed here when `overflowMenu` is on.\n const [overflowOpen, setOverflowOpen] = createSignal(false);\n let overflowTriggerEl: HTMLButtonElement | undefined;\n\n let tabsEl: HTMLDivElement | undefined;\n let tabListEl: HTMLDivElement | undefined;\n // The tab the user asked to close while it, or something beside it, had focus: its item, which\n // goes with it, and its place. If it goes while focus is lost with it, focus moves on to a neighbour.\n let closingTab: { item: Element; index: number } | null = null;\n // The tab list's elements in order, known once its children have resolved in\n // the browser. Before that, and on the server, a tab's index is the order it\n // was created in, which is its order in the markup.\n const [items, setItems] = createSignal<Element[]>();\n let created = 0;\n\n const getTabsMeta = () => {\n let tabsMeta: { clientWidth: number; scrollLeft: number; left: number; right: number } | undefined;\n if (tabsEl) {\n const rect = tabsEl.getBoundingClientRect();\n tabsMeta = { clientWidth: tabsEl.clientWidth, scrollLeft: tabsEl.scrollLeft, left: rect.left, right: rect.right };\n }\n let tabMeta: DOMRect | null = null;\n let tabContentMeta: DOMRect | null = null;\n if (tabsEl && tabListEl && tabListEl.children.length > 0) {\n const tab = tabListEl.children[local.value];\n tabMeta = tab ? tab.getBoundingClientRect() : null;\n if (local.indicatorContent) {\n tabContentMeta = tab?.querySelector(\".smwb-tab__content\")?.getBoundingClientRect() ?? null;\n }\n }\n return { tabsMeta, tabMeta, tabContentMeta };\n };\n\n const updateIndicatorState = (): void => {\n const { tabsMeta, tabMeta, tabContentMeta } = getTabsMeta();\n let startValue = 0;\n if (tabMeta && tabsMeta) {\n startValue = tabMeta.left - tabsMeta.left + tabsMeta.scrollLeft;\n }\n const next: IndicatorStyle = { root: { left: startValue, width: tabMeta ? tabMeta.width : 0 } };\n if (local.indicatorContent && tabContentMeta) {\n next.content = { width: tabContentMeta.width };\n }\n const prev = indicatorStyle();\n if (prev.root.left === undefined || prev.root.width === undefined) {\n setIndicatorStyle(next);\n return;\n }\n const dStart = Math.abs((prev.root.left ?? 0) - (next.root.left ?? 0));\n const dSize = Math.abs((prev.root.width ?? 0) - (next.root.width ?? 0));\n if (dStart >= 1 || dSize >= 1) {\n setIndicatorStyle(next);\n }\n };\n\n const updateOverflow = (): void => {\n if (!tabsEl || !local.scrollable) {\n setOverflowStart(false);\n setOverflowEnd(false);\n setHiddenIndexes((prev) => (prev.length === 0 ? prev : []));\n return;\n }\n const max = tabsEl.scrollWidth - tabsEl.clientWidth;\n setOverflowStart(tabsEl.scrollLeft > 1);\n setOverflowEnd(tabsEl.scrollLeft < max - 1);\n // Which tabs the viewport clips, measured the same way: the scroller is `position: relative`,\n // so a tab's `offsetLeft` is its place in the row's content. Only the menu needs the list,\n // so nothing is measured without it. Kept by identity when unchanged, because this runs on\n // every scroll tick.\n const hidden = local.overflowMenu\n ? getHiddenIndexes(\n tabListEl\n ? Array.from(tabListEl.children).map((child) => {\n const item = child as HTMLElement;\n return { offsetLeft: item.offsetLeft, offsetWidth: item.offsetWidth };\n })\n : [],\n tabsEl.scrollLeft,\n tabsEl.clientWidth\n )\n : [];\n setHiddenIndexes((prev) =>\n prev.length === hidden.length && prev.every((index, at) => index === hidden[at]) ? prev : hidden\n );\n };\n\n const scroll = (scrollValue: number): void => {\n if (!tabsEl) return;\n animate(tabsEl, \"scrollLeft\", scrollValue, { duration: 300 });\n };\n\n const scrollByPage = (direction: -1 | 1): void => {\n if (!tabsEl) return;\n scroll(tabsEl.scrollLeft + direction * tabsEl.clientWidth * SCROLL_PAGE);\n };\n\n const scrollIndexIntoView = (index: number): void => {\n if (!tabsEl || !tabListEl) return;\n const tab = tabListEl.children[index];\n if (!tab) return;\n const tabsRect = tabsEl.getBoundingClientRect();\n const tabRect = tab.getBoundingClientRect();\n if (tabRect.left < tabsRect.left) {\n scroll(tabsEl.scrollLeft + (tabRect.left - tabsRect.left) - VIEW_NEXT_TAB_PX);\n } else if (tabRect.right > tabsRect.right) {\n scroll(tabsEl.scrollLeft + (tabRect.right - tabsRect.right) + VIEW_NEXT_TAB_PX);\n }\n };\n\n const scrollSelectedIntoView = (): void => {\n scrollIndexIntoView(local.value);\n };\n\n onMount(() => setMounted(true));\n\n // Re-measure when the active value or the tabs change (and on mount).\n createEffect(\n on([() => local.value, items], () => {\n updateIndicatorState();\n updateOverflow();\n })\n );\n\n // Keep the indicator and the overflow state in sync with resizes: of the\n // window, of the row, and of each tab (a label can grow with its data).\n onMount(() => {\n const onResize = debounce(() => {\n updateIndicatorState();\n updateOverflow();\n }, 166);\n const view = tabsEl?.ownerDocument.defaultView;\n view?.addEventListener(\"resize\", onResize);\n tabsEl?.addEventListener(\"scroll\", updateOverflow, { passive: true });\n let resizeObserver: ResizeObserver | undefined;\n if (typeof ResizeObserver !== \"undefined\" && tabListEl) {\n resizeObserver = new ResizeObserver(onResize);\n if (tabsEl) resizeObserver.observe(tabsEl);\n Array.from(tabListEl.children).forEach((child) => resizeObserver?.observe(child));\n }\n updateOverflow();\n onCleanup(() => {\n onResize.cancel();\n view?.removeEventListener(\"resize\", onResize);\n tabsEl?.removeEventListener(\"scroll\", updateOverflow);\n resizeObserver?.disconnect();\n });\n });\n\n // Scroll the selected tab into view when the indicator moves.\n createEffect(() => {\n indicatorStyle();\n scrollSelectedIntoView();\n });\n\n // The tabs in the DOM, by what they are: their indexes are the ones `value` counts.\n const getTabNodes = (): HTMLElement[] => Array.from(tabListEl?.querySelectorAll<HTMLElement>('[role=\"tab\"]') ?? []);\n // A tab with a close button or actions sits in an item with them: focus on any of it is focus on the tab.\n const itemOf = (tab: HTMLElement): HTMLElement => tab.closest<HTMLElement>(\".smwb-tab-item\") ?? tab;\n const indexOfFocus = (target: Node | null | undefined): number =>\n target ? getTabNodes().findIndex((node) => itemOf(node).contains(target)) : -1;\n const isNodeDisabled = (node: HTMLElement | undefined): boolean =>\n !node || node.getAttribute(\"aria-disabled\") === \"true\" || (node as HTMLButtonElement).disabled === true;\n\n // The selected tab is the stop; a value that points at no tab leaves the first one, and a\n // disabled one, which cannot take focus, leaves the first tab that can.\n const selectedStop = (): number => {\n const count = items()?.length;\n const candidate = count === undefined || (local.value >= 0 && local.value < count) ? local.value : 0;\n const list = registrations();\n if (!list.some((registration) => registration.index() === candidate && registration.disabled())) return candidate;\n const enabled = list\n .filter((registration) => !registration.disabled())\n .map((registration) => registration.index())\n .filter((index) => index >= 0);\n return enabled.length > 0 ? Math.min(...enabled) : candidate;\n };\n const stopIndex = (): number => focusedIndex() ?? selectedStop();\n\n const onRovingKeyDown = createRovingTabIndex({\n count: () => getTabNodes().length,\n activeIndex: stopIndex,\n get orientation() {\n return local.orientation;\n },\n onMove: (next) => getTabNodes()[next]?.focus(),\n isDisabled: (index) => isNodeDisabled(getTabNodes()[index]),\n });\n\n // Drag-to-reorder (with `onReorder`): the drag's source and drop target are the tab items,\n // tracked here on the row; Tabs only reports `onReorder(from, to)` — and, when the moved tab\n // is the selected one, its new index through `onChange` — and keeps the tabs' focus alone;\n // the owner moves the tabs in its state.\n // Only while `onReorder` is given do the items carry `draggable`, and a disabled tab\n // never: the attribute is rendered declaratively by each `Tab` on its item (the wrapper,\n // or the bare tab when there is none), so it is part of the server markup — as in React.\n let dragSourceIndex: number | null = null;\n let draggingItem: HTMLElement | null = null;\n let dropTargetItem: HTMLElement | null = null;\n const dragItemOf = (target: EventTarget | null): HTMLElement | null =>\n target instanceof Element ? itemOf(target as HTMLElement) : null;\n const clearDragMarks = (): void => {\n draggingItem?.classList.remove(\"smwb-tab-item--dragging\");\n dropTargetItem?.classList.remove(\"smwb-tab-item--drop-target\");\n draggingItem = null;\n dropTargetItem = null;\n };\n\n const onItemDragStart: JSX.EventHandler<HTMLDivElement, DragEvent> = (event) => {\n if (!local.onReorder) return;\n const item = dragItemOf(event.target);\n if (!item) return;\n const index = indexOfFocus(item);\n if (index < 0 || isNodeDisabled(getTabNodes()[index])) return;\n dragSourceIndex = index;\n draggingItem = item;\n item.classList.add(\"smwb-tab-item--dragging\");\n // Firefox wants the drag given something to carry.\n event.dataTransfer?.setData(\"text/plain\", String(index));\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = \"move\";\n }\n };\n\n const onItemDragOver: JSX.EventHandler<HTMLDivElement, DragEvent> = (event) => {\n if (dragSourceIndex === null || !local.onReorder) return;\n const item = dragItemOf(event.target);\n if (!item) return;\n // Without it the drop is not allowed here.\n event.preventDefault();\n if (item === dropTargetItem) return;\n dropTargetItem?.classList.remove(\"smwb-tab-item--drop-target\");\n dropTargetItem = item;\n item.classList.add(\"smwb-tab-item--drop-target\");\n };\n\n const onItemDrop: JSX.EventHandler<HTMLDivElement, DragEvent> = (event) => {\n if (dragSourceIndex === null) return;\n const from = dragSourceIndex;\n dragSourceIndex = null;\n const to = indexOfFocus(dragItemOf(event.target));\n // Read before the drop is reported: the owner may answer `onReorder` synchronously and move\n // `value` with the tab, and moving a node in the DOM loses the focus in some environments.\n const sourceItem = draggingItem;\n const wasSelected = from === local.value;\n const doc = sourceItem?.ownerDocument;\n const hadFocus = Boolean(sourceItem && doc?.activeElement && sourceItem.contains(doc.activeElement));\n clearDragMarks();\n event.preventDefault();\n if (to >= 0 && to !== from) {\n local.onReorder?.(from, to);\n // The selection belongs to the tab: when the moved tab is the selected one, report its\n // new index as a click would, so a controlled owner moves the value with the tab. The\n // drop's event stands in for the click's, as the overflow menu's choice does.\n if (wasSelected) {\n local.onChange(event as unknown as MouseEvent & { currentTarget: HTMLElement; target: Element }, to);\n }\n // The focus belongs to the tab too: put it back on the moved tab when it had it. The\n // check that the node landed at `to` keeps this honest when the owner reorders later.\n if (hadFocus) {\n const moved = getTabNodes()[to];\n if (moved && itemOf(moved) === sourceItem) moved.focus();\n }\n }\n };\n\n const onItemDragEnd: JSX.EventHandler<HTMLDivElement, DragEvent> = () => {\n dragSourceIndex = null;\n clearDragMarks();\n };\n\n // Select the enabled tab `delta` places from the focused one, wrapping at the ends and\n // skipping disabled tabs: as Enter or Space would, through a synthesized click on the tab.\n const switchByChord = (event: KeyboardEvent & { target: Element }, delta: -1 | 1): void => {\n const nodes = getTabNodes();\n const from = indexOfFocus(event.target);\n if (from < 0 || nodes.length === 0) return;\n for (let step = 1; step <= nodes.length; step += 1) {\n const next = (from + delta * step + nodes.length) % nodes.length;\n const node = nodes[next];\n if (node && !isNodeDisabled(node)) {\n node.focus();\n node.click();\n return;\n }\n }\n };\n\n const onTabListKeyDown = (event: KeyboardEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (event.defaultPrevented) return;\n // The tabs' chords, ahead of the \"chords belong to the browser\" guard below. They are\n // best-effort: a browser of its own tabs reserves Mod+W and Mod+Shift+[/], and they\n // bite only in an embedded webview.\n if ((event.ctrlKey || event.metaKey) && !event.altKey && indexOfFocus(event.target) >= 0) {\n const index = indexOfFocus(event.target);\n const registration = registrations().find((candidate) => candidate.index() === index);\n if (matchesKeyboardShortcut(event, [\"Mod\", \"W\"])) {\n if (registration && !registration.disabled() && registration.closable()) {\n event.preventDefault();\n registration.requestClose(event);\n }\n return;\n }\n if (matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"[\"])) {\n event.preventDefault();\n switchByChord(event, -1);\n return;\n }\n if (matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"]\"])) {\n event.preventDefault();\n switchByChord(event, 1);\n return;\n }\n }\n // Chords belong to the browser; a handler that took the key first keeps it.\n if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return;\n if (!event.target.closest('[role=\"tab\"]')) return;\n onRovingKeyDown(event);\n };\n\n // Focus can leave the row without a focusout: the focused tab is removed, and the browser moves\n // focus to the body. The row keeps the focused tab as its stop only while focus is in it, on\n // the tab that has it now (tabs before it may have come or gone).\n createEffect(\n on(\n items,\n () => {\n const doc = tabListEl?.ownerDocument;\n const closing = closingTab;\n if (doc && closing && !closing.item.isConnected) {\n closingTab = null;\n // A tab the user closed took the focus with it: the tab that takes its place gets it (the\n // previous one if it was last), the nearest that is not disabled. Focus that went anywhere\n // else meanwhile stays there.\n if (!doc.activeElement || doc.activeElement === doc.body) {\n const nodes = getTabNodes();\n const from = Math.min(closing.index, nodes.length - 1);\n const candidates = [...nodes.keys()].filter((index) => !isNodeDisabled(nodes[index]));\n const target = candidates.find((index) => index >= from) ?? candidates[candidates.length - 1];\n if (target !== undefined) {\n nodes[target]?.focus();\n setFocusedIndex(target);\n return;\n }\n }\n }\n if (focusedIndex() === null) return;\n const index = indexOfFocus(doc?.activeElement);\n setFocusedIndex(index >= 0 ? index : null);\n },\n { defer: true }\n )\n );\n\n const onTabListFocusIn = (event: FocusEvent): void => {\n const index = indexOfFocus(event.target as Node);\n if (index >= 0) setFocusedIndex(index);\n if (closingTab && !closingTab.item.contains(event.target as Node)) closingTab = null;\n };\n\n const onTabListFocusOut = (event: FocusEvent & { currentTarget: HTMLElement }): void => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {\n setFocusedIndex(null);\n // Chromium fires this too as the focused tab is removed, just before it goes, and the removal\n // is what the marker is for: it stays until the effect that follows the removal has used it.\n // One still standing once the current task's microtasks run was a real blur: that close no\n // longer takes the focus anywhere.\n queueMicrotask(() => {\n if (closingTab?.item.isConnected) closingTab = null;\n });\n }\n };\n\n const contextValue: TabsContextValue = {\n value: () => local.value,\n tabStop: (index) => stopIndex() === index,\n tabId,\n panelId,\n hasPanels,\n reorderable: () => local.onReorder !== undefined,\n onChange: local.onChange,\n closing: (index, reason) => {\n const tab = getTabNodes()[index];\n const active = tab?.ownerDocument.activeElement;\n // Focus in the item is focus on the tab. A close from the tab's own `actions` is the user's\n // wherever focus is: it is in the menu then, which is drawn outside the row.\n const focused = reason === \"actions\" || Boolean(active && tab && itemOf(tab).contains(active));\n closingTab = tab && focused ? { item: itemOf(tab), index } : null;\n },\n registerTab: (element, info) => {\n const order = created++;\n const index = createMemo(() => {\n const list = items();\n if (!list) return order;\n const el = element();\n return el ? list.findIndex((item) => item.contains(el)) : -1;\n });\n const registration: Registration = { ...info, index };\n setRegistrations((list) => [...list, registration]);\n onCleanup(() => setRegistrations((list) => list.filter((item) => item !== registration)));\n return index;\n },\n };\n\n const showScrollButtons = (): boolean =>\n local.scrollable && local.scrollButtons && (overflowStart() || overflowEnd());\n\n // The overflow menu's trigger appears only once the browser has measured a clipped tab,\n // so the server markup — and the first client render — shows none.\n const showOverflowTrigger = (): boolean =>\n local.scrollable && local.overflowMenu && hiddenIndexes().length > 0;\n\n // The menu lists what the viewport clips; each entry shows a copy of the tab's icon and\n // label (the live nodes belong to the row, so they are cloned into the entry, not moved),\n // kept in step with the tab while the menu is open.\n const overflowItemIcon = (node: HTMLElement | undefined): Element | undefined =>\n node?.querySelector(\".smwb-tab__icon\") ?? undefined;\n const overflowItemLabel = (node: HTMLElement | undefined): string =>\n node?.querySelector(\".smwb-tab__text-label\")?.textContent ?? \"\";\n const cloneIconInto = (el: HTMLElement, node: HTMLElement | undefined): void => {\n const source = overflowItemIcon(node);\n if (!source) return;\n Array.from(source.childNodes).forEach((child) => el.appendChild(child.cloneNode(true)));\n };\n\n const chooseOverflowItem = (\n event: MouseEvent & { currentTarget: HTMLLIElement; target: Element },\n index: number\n ): void => {\n setOverflowOpen(false);\n local.onChange(event, index);\n scrollIndexIntoView(index);\n };\n\n return (\n <TabsContext.Provider value={contextValue}>\n <PanelsResolver onPanels={(resolved, has) => (setPanels(() => resolved), setHasPanels(has))}>\n {local.panels}\n </PanelsResolver>\n <div\n {...rest}\n id={local.id}\n class={cn(\n \"smwb-tabs\",\n {\n \"smwb-tabs--dense\": local.dense,\n \"smwb-tabs--overflow-start\": overflowStart(),\n \"smwb-tabs--overflow-end\": overflowEnd(),\n },\n local.class\n )}\n ref={mergeRefs(local.ref)}\n >\n <Show when={showScrollButtons()}>\n <button\n type=\"button\"\n class=\"smwb-tabs__scroll-button smwb-tabs__scroll-button--start\"\n aria-label={local.scrollBackAriaLabel}\n disabled={!overflowStart()}\n tabindex={-1}\n onClick={() => scrollByPage(-1)}\n >\n <Icon name=\"chevron_left\" size={20} />\n </button>\n </Show>\n {/* The scroller's class is static so it is on the element from the start:\n a ref on Tabs can find the row by class right away. */}\n <div\n class=\"smwb-tabs__scroller\"\n classList={{ \"smwb-tabs__scroller--scrollable\": local.scrollable }}\n ref={(el) => (tabsEl = el)}\n >\n <div\n class=\"smwb-tabs__scroll-area\"\n ref={(el) => (tabListEl = el)}\n role=\"tablist\"\n aria-label={local[\"aria-label\"]}\n aria-orientation={local.orientation}\n onKeyDown={onTabListKeyDown}\n onFocusIn={onTabListFocusIn}\n onFocusOut={onTabListFocusOut}\n onDragStart={onItemDragStart}\n onDragOver={onItemDragOver}\n onDrop={onItemDrop}\n onDragEnd={onItemDragEnd}\n >\n <TabListItems onItems={setItems}>{local.children}</TabListItems>\n </div>\n <Show when={mounted()}>\n <span\n class=\"smwb-tabs__indicator\"\n style={{\n left: `${indicatorStyle().root.left ?? 0}px`,\n width: `${indicatorStyle().root.width ?? 0}px`,\n }}\n >\n <span\n class=\"smwb-tabs__indicator-content\"\n style={indicatorStyle().content ? { width: `${indicatorStyle().content?.width ?? 0}px` } : {}}\n />\n </span>\n </Show>\n </div>\n <Show when={showScrollButtons()}>\n <button\n type=\"button\"\n class=\"smwb-tabs__scroll-button smwb-tabs__scroll-button--end\"\n aria-label={local.scrollForwardAriaLabel}\n disabled={!overflowEnd()}\n tabindex={-1}\n onClick={() => scrollByPage(1)}\n >\n <Icon name=\"chevron_right\" size={20} />\n </button>\n </Show>\n <Show when={showOverflowTrigger()}>\n <button\n type=\"button\"\n class=\"smwb-tabs__overflow-trigger\"\n aria-haspopup=\"menu\"\n aria-expanded={overflowOpen()}\n aria-label={local.overflowMenuAriaLabel}\n tabindex={-1}\n ref={(el) => (overflowTriggerEl = el)}\n onClick={() => setOverflowOpen((open) => !open)}\n >\n <Icon name=\"more_horiz\" size={20} />\n </button>\n <Menu\n anchorElement={overflowTriggerEl ?? null}\n isOpen={overflowOpen()}\n onClose={() => setOverflowOpen(false)}\n placement=\"bottom-end\"\n >\n <For each={hiddenIndexes()}>\n {(index) => {\n // The entry mirrors the tab it stands for. Solid children resolve to DOM, not to\n // prop objects, so the tab's own node is the source for the label and the icon;\n // a MutationObserver keeps the entry in step with renames and re-icons while the\n // menu is open. Disabled follows the tab's registration, as in the row's other\n // disabled bookkeeping, so a tab that flips `disabled` in place greys its entry out.\n //\n // Which node that is cannot be settled once, when the entry is drawn: an owner that\n // keys its list by value replaces the tab's node when its label changes, while the\n // clipped set — and so this entry — keeps its identity. `items` and `registrations`\n // are what announce the row moving, and the effect below reads the node from the row\n // when it runs, which is after Solid has landed that move in the DOM; a node sampled\n // earlier, into a memo or into a const, is the detached one by then.\n const nodeNow = (): HTMLElement | undefined => getTabNodes()[index];\n // What the row shows at this index as the entry is drawn, so its first paint is not\n // an empty entry; the effect below keeps it current from then on.\n const drawn = nodeNow();\n const [label, setLabel] = createSignal(overflowItemLabel(drawn));\n const [hasIcon, setHasIcon] = createSignal(Boolean(overflowItemIcon(drawn)));\n const disabled = createMemo(() => {\n const registration = registrations().find((candidate) => candidate.index() === index);\n return registration ? registration.disabled() : isNodeDisabled(nodeNow());\n });\n let iconEl: HTMLSpanElement | undefined;\n // The node the entry's content was last taken from: the icon span copies from it\n // when it is drawn, which is after the sync that asked for it.\n let shownNode = drawn;\n const syncIcon = (node: HTMLElement | undefined): void => {\n shownNode = node;\n const source = overflowItemIcon(node);\n setHasIcon(Boolean(source));\n if (iconEl && source) {\n iconEl.textContent = \"\";\n cloneIconInto(iconEl, node);\n }\n };\n createEffect(\n on([items, registrations], () => {\n const node = nodeNow();\n setLabel(overflowItemLabel(node));\n syncIcon(node);\n const item = node ? itemOf(node) : null;\n const view = item?.ownerDocument.defaultView;\n if (!item || !view || typeof view.MutationObserver === \"undefined\") return;\n const observer = new view.MutationObserver(() => {\n setLabel(overflowItemLabel(node));\n syncIcon(node);\n });\n observer.observe(item, { subtree: true, childList: true, characterData: true });\n onCleanup(() => observer.disconnect());\n })\n );\n return (\n <MenuItem\n disabled={disabled()}\n aria-current={index === local.value ? \"true\" : undefined}\n onClick={(event) => chooseOverflowItem(event, index)}\n >\n <Show when={hasIcon()}>\n <span\n class=\"smwb-tab__icon\"\n aria-hidden=\"true\"\n ref={(el) => {\n iconEl = el;\n // The span is drawn by the flag the sync above sets, so it is born after\n // that sync: it copies the icon of the node the entry last followed.\n if (overflowItemIcon(shownNode)) cloneIconInto(el, shownNode);\n }}\n />\n </Show>\n <span class=\"smwb-tab__text-label\">{label()}</span>\n </MenuItem>\n );\n }}\n </For>\n </Menu>\n </Show>\n </div>\n {panels()}\n </TabsContext.Provider>\n );\n}\n\nexport { Tab };\nexport type { TabProps, TabActionsApi, TabCloseReason } from \"./tab/tab\";\nexport default Tabs;\n"],"names":["VIEW_NEXT_TAB_PX","SCROLL_PAGE","TabListItems","props","resolved","children","isServer","createComputed","onItems","toArray","filter","node","Element","_$memo","PanelsResolver","onPanels","some","Tabs","merged","mergeProps","indicatorContent","scrollable","scrollButtons","overflowMenu","dense","orientation","scrollBackAriaLabel","scrollForwardAriaLabel","overflowMenuAriaLabel","local","rest","splitProps","generatedId","createUniqueId","baseId","id","registrations","setRegistrations","createSignal","tabId","index","find","registration","panelId","panels","setPanels","hasPanels","setHasPanels","focusedIndex","setFocusedIndex","mounted","setMounted","indicatorStyle","setIndicatorStyle","root","overflowStart","setOverflowStart","overflowEnd","setOverflowEnd","hiddenIndexes","setHiddenIndexes","overflowOpen","setOverflowOpen","overflowTriggerEl","tabsEl","tabListEl","closingTab","items","setItems","created","getTabsMeta","tabsMeta","rect","getBoundingClientRect","clientWidth","scrollLeft","left","right","tabMeta","tabContentMeta","length","tab","value","querySelector","updateIndicatorState","startValue","next","width","content","prev","undefined","dStart","Math","abs","dSize","updateOverflow","max","scrollWidth","hidden","getHiddenIndexes","Array","from","map","child","item","offsetLeft","offsetWidth","every","at","scroll","scrollValue","animate","duration","scrollByPage","direction","scrollIndexIntoView","tabsRect","tabRect","scrollSelectedIntoView","onMount","createEffect","on","onResize","debounce","view","ownerDocument","defaultView","addEventListener","passive","resizeObserver","ResizeObserver","observe","forEach","onCleanup","cancel","removeEventListener","disconnect","getTabNodes","querySelectorAll","itemOf","closest","indexOfFocus","target","findIndex","contains","isNodeDisabled","getAttribute","disabled","selectedStop","count","candidate","list","enabled","min","stopIndex","onRovingKeyDown","createRovingTabIndex","activeIndex","onMove","focus","isDisabled","dragSourceIndex","draggingItem","dropTargetItem","dragItemOf","clearDragMarks","classList","remove","onItemDragStart","event","onReorder","add","dataTransfer","setData","String","effectAllowed","onItemDragOver","preventDefault","onItemDrop","to","sourceItem","wasSelected","doc","hadFocus","Boolean","activeElement","onChange","moved","onItemDragEnd","switchByChord","delta","nodes","step","click","onTabListKeyDown","defaultPrevented","ctrlKey","metaKey","altKey","matchesKeyboardShortcut","closable","requestClose","shiftKey","closing","isConnected","body","candidates","keys","defer","onTabListFocusIn","onTabListFocusOut","currentTarget","relatedTarget","queueMicrotask","contextValue","tabStop","reorderable","reason","active","focused","registerTab","element","info","order","createMemo","el","showScrollButtons","showOverflowTrigger","overflowItemIcon","overflowItemLabel","textContent","cloneIconInto","source","childNodes","appendChild","cloneNode","chooseOverflowItem","_$createComponent","TabsContext","Provider","has","_el$","_tmpl$5","_el$3","firstChild","_el$4","_ref$","mergeRefs","ref","_$use","_$spread","_$mergeProps","cn","class","_$insert","Show","when","_el$2","_tmpl$","$$click","Icon","name","size","_$effect","_p$","_v$","_v$2","e","_$setAttribute","t","$$focusout","$$focusin","$$keydown","_el$5","_tmpl$2","_el$6","_v$3","_v$4","_v$5","_$setStyleProperty","a","_$style","_el$7","_tmpl$3","_v$6","_v$7","_el$8","_tmpl$4","open","_v$8","_v$9","Menu","anchorElement","isOpen","onClose","placement","For","each","nodeNow","drawn","label","setLabel","hasIcon","setHasIcon","iconEl","shownNode","syncIcon","MutationObserver","observer","subtree","childList","characterData","MenuItem","onClick","_el$9","_tmpl$6","_el$0","_tmpl$7","_v$0","_v$1","_v$10","toggle","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tabs.js","sources":["../../../../../src/components/navigation/tabs/tabs.tsx"],"sourcesContent":["import {\n type Accessor,\n type JSX,\n type ParentProps,\n For,\n Show,\n children,\n createComputed,\n createEffect,\n createMemo,\n createSignal,\n createUniqueId,\n mergeProps,\n on,\n onCleanup,\n onMount,\n splitProps,\n} from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { debounce } from \"../../../utils/debounce\";\nimport { animate } from \"../../../utils/animate\";\nimport { matchesKeyboardShortcut } from \"../../../utils/keyboardShortcut\";\nimport { TabsContext, type TabInfo, type TabsContextValue } from \"./tabsContext\";\nimport { Tab } from \"./tab/tab\";\nimport { getHiddenIndexes } from \"./tabs.utils\";\nimport { Menu } from \"../menu\";\nimport { MenuItem } from \"../menu/menuItem\";\nimport { Icon } from \"../../base/icon\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { createRovingTabIndex } from \"../../../primitives/createRovingTabIndex\";\n\n/**\n * Tabs follow the WAI-ARIA tabs pattern with manual activation. The selected tab is the row's one\n * tab stop (`tabindex` 0, the others -1). The arrow keys along the row's `orientation` move focus to\n * the next or the previous tab (wrapping at the ends), Home and End to the first and the last one;\n * disabled tabs are skipped. Enter or Space then selects the focused tab, as a click does:\n * `onChange` is called for it, with the key's click. Moving focus changes nothing by itself, so a\n * row of link tabs does not navigate as the arrows pass them. Tab leaves the row for what follows\n * it, the selected `TabPanel` first when `panels` are given.\n *\n * A `Tab` can be `closable` and take `actions`; they sit beside the tab and out of the Tab order.\n * Delete on the focused tab, its close button or its `actions` (through `close`) ask `onClose` to\n * close it, and when it goes, focus moves to the tab that takes its place instead of falling to the\n * page. A middle click on a closable tab closes it too.\n *\n * With `onReorder` the row's tabs drag onto one another to reorder: `onReorder(from, to)` reports\n * the drop and the owner moves the tabs; dropping the selected tab reports its new index through\n * `onChange` as well, so the selection follows the moved tab. With `overflowMenu` a scrollable\n * row that overflows gains\n * a trigger beside it listing the clipped tabs. The chords Mod+W (close the focused closable tab)\n * and Mod+Shift+[ / Mod+Shift+] (switch to the previous / next tab) are handled on the row, as\n * best-effort: a browser of its own tabs reserves them.\n */\nexport interface TabsProps {\n /**\n * Index of the selected tab: its position in the row. Tabs count in the order they\n * render, so a tab behind a `<Show>` that is off takes no index, and tabs added,\n * removed or reordered count by their new place.\n */\n value: number;\n /**\n * Called with the index of the clicked tab, counted as for `value`. A tab chosen from the keyboard\n * (Enter or Space on the focused tab) calls it with that click too. A modified or non-primary\n * click (Ctrl, Meta, Shift or Alt held, or a button other than the main one) on a link tab\n * (`Tab` with `href`) is the browser's, as \"open in a new tab\": it does not call `onChange`.\n */\n onChange: (event: MouseEvent & { currentTarget: HTMLElement; target: Element }, index: number) => void;\n /**\n * Which way the tabs run. It sets `aria-orientation` on the tab list and picks the arrow keys that\n * move between tabs: Left and Right when horizontal, Up and Down when vertical. The styles draw\n * a horizontal row; a vertical list is yours to lay out.\n */\n orientation?: \"horizontal\" | \"vertical\";\n /**\n * The content of the tabs: `TabPanel`s, rendered after the tab row. With them each tab gets\n * `aria-controls` its panel and each panel `aria-labelledby` its tab. Without them the tabs link\n * to nothing, as before. Give a panel to every tab: a tab whose panel is left out still names it.\n * A `TabPanel` placed anywhere else is not linked to the tabs and is always shown.\n */\n panels?: JSX.Element;\n /**\n * Base of the ids that link tabs and panels: tab `n` is `{id}-tab-{n}`, its panel `{id}-panel-{n}`.\n * It is also the id of the root element. A generated one by default.\n */\n id?: string;\n /** Draw the indicator as wide as the selected tab's label rather than the whole tab. */\n indicatorContent?: boolean;\n /**\n * Let the tab row scroll sideways instead of clipping it. The edge beyond which\n * more tabs are hidden fades out.\n */\n scrollable?: boolean;\n /**\n * With `scrollable`: buttons at both ends that scroll the row while it overflows. They are for\n * the pointer and stay out of the Tab order: the arrow keys reach every tab and scroll it into\n * view.\n */\n scrollButtons?: boolean;\n /**\n * Present ⇒ the row is reorderable by dragging a tab onto another (pointer-only; there is no\n * keyboard reorder). `Tabs` does not move the tabs itself: it reports the drag with\n * `onReorder(from, to)` — indexes counted as for `value` — and the owner reorders its state.\n * The tabs keep their focus through a reorder; when the moved tab is the selected one,\n * `onChange` reports its new index too, so a controlled owner keeps it selected. That `onChange`\n * carries the drop's own event standing in for the click's: the index argument is authoritative —\n * `currentTarget` is the scroll area the drop delegates to, not the tab.\n */\n onReorder?: (from: number, to: number) => void;\n /**\n * With `scrollable`: when the row overflows, a trigger button is rendered beside the scroller\n * (in the scroll buttons' spot) that opens a menu of the tabs the viewport clips — any clipped\n * part beyond a 1px tolerance counts. Each entry shows the tab's icon and label, the selected one is marked\n * `aria-current=\"true\"`, and choosing one calls `onChange` for it and scrolls it into view.\n * The trigger appears only after the browser has measured an overflow, so the server markup\n * shows none.\n */\n overflowMenu?: boolean;\n /** Accessible label of the overflow-menu trigger. English by default; set it to localise. */\n overflowMenuAriaLabel?: string;\n /**\n * Compact tabs: a shorter row — `--smui-tabDenseHeight` (36px) — with labels as written (no\n * capitals, no letter spacing) and less padding.\n */\n dense?: boolean;\n /**\n * Content-width tabs: each tab is as wide as what it holds (marker, label, close button) and the\n * row does not stretch them, so what is left of the row stays empty; a plain row shares its whole\n * width between its tabs. A tab stays between `--smui-tabFitMinWidth` (80px) and\n * `--smui-tabFitMaxWidth` (256px), set in the theme; a longer label is cut with an ellipsis, and a\n * string `label` is also the label's `title`, so the full text shows on hover (a `Tab` whose label\n * is not a string takes a `title` of its own, which is the tooltip of the whole tab). The indicator, `scrollable`, `scrollButtons`, the\n * overflow menu and the close button need nothing more. Dropping a dragged tab on the row's empty\n * part does nothing.\n */\n fit?: boolean;\n /** Accessible label of the button that scrolls back. */\n scrollBackAriaLabel?: string;\n /** Accessible label of the button that scrolls forward. */\n scrollForwardAriaLabel?: string;\n class?: string;\n children?: JSX.Element;\n \"aria-label\"?: string;\n ref?: Ref<HTMLDivElement>;\n}\n\ninterface IndicatorStyle {\n root: { left?: number; width?: number };\n content?: { width: number };\n}\n\nconst VIEW_NEXT_TAB_PX = 40;\n/** A scroll button moves the row by this share of its visible width. */\nconst SCROLL_PAGE = 0.8;\n\n/** What Tabs knows of each of its tabs. */\ninterface Registration extends TabInfo {\n index: Accessor<number>;\n}\n\n/**\n * The tab list's children, resolved once, with their elements reported in order\n * whenever they change. It renders inside the context provider, so the tabs it\n * creates find their Tabs.\n */\nfunction TabListItems(props: { children?: JSX.Element; onItems: (items: Element[]) => void }): JSX.Element {\n const resolved = children(() => props.children);\n if (!isServer) {\n createComputed(() => props.onItems(resolved.toArray().filter((node) => node instanceof Element)));\n }\n return <>{resolved()}</>;\n}\n\n/**\n * The `panels`, resolved once, inside the context provider so that the panels find their Tabs, and\n * before the tab row renders so that the tabs know whether they control anything. It draws\n * nothing itself: Tabs places what it reports after the row.\n */\nfunction PanelsResolver(props: {\n children?: JSX.Element;\n onPanels: (panels: JSX.Element, has: boolean) => void;\n}): null {\n const resolved = children(() => props.children);\n createComputed(() =>\n props.onPanels(\n resolved(),\n resolved.toArray().some((node) => node != null && node !== false && node !== \"\")\n )\n );\n return null;\n}\n\nexport function Tabs(props: ParentProps<TabsProps>): JSX.Element {\n const merged = mergeProps(\n {\n indicatorContent: false,\n scrollable: false,\n scrollButtons: false,\n overflowMenu: false,\n dense: false,\n fit: false,\n orientation: \"horizontal\" as const,\n scrollBackAriaLabel: \"Scroll tabs back\",\n scrollForwardAriaLabel: \"Scroll tabs forward\",\n overflowMenuAriaLabel: \"More tabs\",\n },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"children\",\n \"onChange\",\n \"value\",\n \"indicatorContent\",\n \"scrollable\",\n \"scrollButtons\",\n \"onReorder\",\n \"overflowMenu\",\n \"overflowMenuAriaLabel\",\n \"dense\",\n \"fit\",\n \"orientation\",\n \"panels\",\n \"id\",\n \"scrollBackAriaLabel\",\n \"scrollForwardAriaLabel\",\n \"aria-label\",\n \"ref\",\n ]);\n\n const generatedId = createUniqueId();\n const baseId = (): string => local.id ?? generatedId;\n const [registrations, setRegistrations] = createSignal<Registration[]>([]);\n // A tab's own id is the one its panel is labelled by.\n const tabId = (index: number): string =>\n registrations()\n .find((registration) => registration.index() === index)\n ?.id() ?? `${baseId()}-tab-${index}`;\n const panelId = (index: number): string => `${baseId()}-panel-${index}`;\n const [panels, setPanels] = createSignal<JSX.Element>();\n const [hasPanels, setHasPanels] = createSignal(false);\n // The tab that has focus while focus is in the tab list: it is the row's tab stop then, so\n // Tab from there leaves the row instead of landing on the selected tab again.\n const [focusedIndex, setFocusedIndex] = createSignal<number | null>(null);\n\n const [mounted, setMounted] = createSignal(false);\n const [indicatorStyle, setIndicatorStyle] = createSignal<IndicatorStyle>({ root: {} });\n // Whether tabs are hidden past the start / the end of a scrollable row. Only\n // measured in the browser, so the server markup shows neither.\n const [overflowStart, setOverflowStart] = createSignal(false);\n const [overflowEnd, setOverflowEnd] = createSignal(false);\n // The indexes of the tabs the scroller's viewport clips: what the overflow menu lists.\n // Empty on the server and until the first measurement, like the overflow state.\n const [hiddenIndexes, setHiddenIndexes] = createSignal<number[]>([]);\n // The overflow-menu trigger and its menu, composed here when `overflowMenu` is on.\n const [overflowOpen, setOverflowOpen] = createSignal(false);\n let overflowTriggerEl: HTMLButtonElement | undefined;\n\n let tabsEl: HTMLDivElement | undefined;\n let tabListEl: HTMLDivElement | undefined;\n // The tab the user asked to close while it, or something beside it, had focus: its item, which\n // goes with it, and its place. If it goes while focus is lost with it, focus moves on to a neighbour.\n let closingTab: { item: Element; index: number } | null = null;\n // The tab list's elements in order, known once its children have resolved in\n // the browser. Before that, and on the server, a tab's index is the order it\n // was created in, which is its order in the markup.\n const [items, setItems] = createSignal<Element[]>();\n let created = 0;\n\n const getTabsMeta = () => {\n let tabsMeta: { clientWidth: number; scrollLeft: number; left: number; right: number } | undefined;\n if (tabsEl) {\n const rect = tabsEl.getBoundingClientRect();\n tabsMeta = { clientWidth: tabsEl.clientWidth, scrollLeft: tabsEl.scrollLeft, left: rect.left, right: rect.right };\n }\n let tabMeta: DOMRect | null = null;\n let tabContentMeta: DOMRect | null = null;\n if (tabsEl && tabListEl && tabListEl.children.length > 0) {\n const tab = tabListEl.children[local.value];\n tabMeta = tab ? tab.getBoundingClientRect() : null;\n if (local.indicatorContent) {\n tabContentMeta = tab?.querySelector(\".smwb-tab__content\")?.getBoundingClientRect() ?? null;\n }\n }\n return { tabsMeta, tabMeta, tabContentMeta };\n };\n\n const updateIndicatorState = (): void => {\n const { tabsMeta, tabMeta, tabContentMeta } = getTabsMeta();\n let startValue = 0;\n if (tabMeta && tabsMeta) {\n startValue = tabMeta.left - tabsMeta.left + tabsMeta.scrollLeft;\n }\n const next: IndicatorStyle = { root: { left: startValue, width: tabMeta ? tabMeta.width : 0 } };\n if (local.indicatorContent && tabContentMeta) {\n next.content = { width: tabContentMeta.width };\n }\n const prev = indicatorStyle();\n if (prev.root.left === undefined || prev.root.width === undefined) {\n setIndicatorStyle(next);\n return;\n }\n const dStart = Math.abs((prev.root.left ?? 0) - (next.root.left ?? 0));\n const dSize = Math.abs((prev.root.width ?? 0) - (next.root.width ?? 0));\n if (dStart >= 1 || dSize >= 1) {\n setIndicatorStyle(next);\n }\n };\n\n const updateOverflow = (): void => {\n if (!tabsEl || !local.scrollable) {\n setOverflowStart(false);\n setOverflowEnd(false);\n setHiddenIndexes((prev) => (prev.length === 0 ? prev : []));\n return;\n }\n const max = tabsEl.scrollWidth - tabsEl.clientWidth;\n setOverflowStart(tabsEl.scrollLeft > 1);\n setOverflowEnd(tabsEl.scrollLeft < max - 1);\n // Which tabs the viewport clips, measured the same way: the scroller is `position: relative`,\n // so a tab's `offsetLeft` is its place in the row's content. Only the menu needs the list,\n // so nothing is measured without it. Kept by identity when unchanged, because this runs on\n // every scroll tick.\n const hidden = local.overflowMenu\n ? getHiddenIndexes(\n tabListEl\n ? Array.from(tabListEl.children).map((child) => {\n const item = child as HTMLElement;\n return { offsetLeft: item.offsetLeft, offsetWidth: item.offsetWidth };\n })\n : [],\n tabsEl.scrollLeft,\n tabsEl.clientWidth\n )\n : [];\n setHiddenIndexes((prev) =>\n prev.length === hidden.length && prev.every((index, at) => index === hidden[at]) ? prev : hidden\n );\n };\n\n const scroll = (scrollValue: number): void => {\n if (!tabsEl) return;\n animate(tabsEl, \"scrollLeft\", scrollValue, { duration: 300 });\n };\n\n const scrollByPage = (direction: -1 | 1): void => {\n if (!tabsEl) return;\n scroll(tabsEl.scrollLeft + direction * tabsEl.clientWidth * SCROLL_PAGE);\n };\n\n const scrollIndexIntoView = (index: number): void => {\n if (!tabsEl || !tabListEl) return;\n const tab = tabListEl.children[index];\n if (!tab) return;\n const tabsRect = tabsEl.getBoundingClientRect();\n const tabRect = tab.getBoundingClientRect();\n if (tabRect.left < tabsRect.left) {\n scroll(tabsEl.scrollLeft + (tabRect.left - tabsRect.left) - VIEW_NEXT_TAB_PX);\n } else if (tabRect.right > tabsRect.right) {\n scroll(tabsEl.scrollLeft + (tabRect.right - tabsRect.right) + VIEW_NEXT_TAB_PX);\n }\n };\n\n const scrollSelectedIntoView = (): void => {\n scrollIndexIntoView(local.value);\n };\n\n onMount(() => setMounted(true));\n\n // Re-measure when the active value or the tabs change (and on mount).\n createEffect(\n on([() => local.value, items], () => {\n updateIndicatorState();\n updateOverflow();\n })\n );\n\n // Keep the indicator and the overflow state in sync with resizes: of the\n // window, of the row, and of each tab (a label can grow with its data).\n onMount(() => {\n const onResize = debounce(() => {\n updateIndicatorState();\n updateOverflow();\n }, 166);\n const view = tabsEl?.ownerDocument.defaultView;\n view?.addEventListener(\"resize\", onResize);\n tabsEl?.addEventListener(\"scroll\", updateOverflow, { passive: true });\n let resizeObserver: ResizeObserver | undefined;\n if (typeof ResizeObserver !== \"undefined\" && tabListEl) {\n resizeObserver = new ResizeObserver(onResize);\n if (tabsEl) resizeObserver.observe(tabsEl);\n Array.from(tabListEl.children).forEach((child) => resizeObserver?.observe(child));\n }\n updateOverflow();\n onCleanup(() => {\n onResize.cancel();\n view?.removeEventListener(\"resize\", onResize);\n tabsEl?.removeEventListener(\"scroll\", updateOverflow);\n resizeObserver?.disconnect();\n });\n });\n\n // Scroll the selected tab into view when the indicator moves.\n createEffect(() => {\n indicatorStyle();\n scrollSelectedIntoView();\n });\n\n // The tabs in the DOM, by what they are: their indexes are the ones `value` counts.\n const getTabNodes = (): HTMLElement[] => Array.from(tabListEl?.querySelectorAll<HTMLElement>('[role=\"tab\"]') ?? []);\n // A tab with a close button or actions sits in an item with them: focus on any of it is focus on the tab.\n const itemOf = (tab: HTMLElement): HTMLElement => tab.closest<HTMLElement>(\".smwb-tab-item\") ?? tab;\n const indexOfFocus = (target: Node | null | undefined): number =>\n target ? getTabNodes().findIndex((node) => itemOf(node).contains(target)) : -1;\n const isNodeDisabled = (node: HTMLElement | undefined): boolean =>\n !node || node.getAttribute(\"aria-disabled\") === \"true\" || (node as HTMLButtonElement).disabled === true;\n\n // The selected tab is the stop; a value that points at no tab leaves the first one, and a\n // disabled one, which cannot take focus, leaves the first tab that can.\n const selectedStop = (): number => {\n const count = items()?.length;\n const candidate = count === undefined || (local.value >= 0 && local.value < count) ? local.value : 0;\n const list = registrations();\n if (!list.some((registration) => registration.index() === candidate && registration.disabled())) return candidate;\n const enabled = list\n .filter((registration) => !registration.disabled())\n .map((registration) => registration.index())\n .filter((index) => index >= 0);\n return enabled.length > 0 ? Math.min(...enabled) : candidate;\n };\n const stopIndex = (): number => focusedIndex() ?? selectedStop();\n\n const onRovingKeyDown = createRovingTabIndex({\n count: () => getTabNodes().length,\n activeIndex: stopIndex,\n get orientation() {\n return local.orientation;\n },\n onMove: (next) => getTabNodes()[next]?.focus(),\n isDisabled: (index) => isNodeDisabled(getTabNodes()[index]),\n });\n\n // Drag-to-reorder (with `onReorder`): the drag's source and drop target are the tab items,\n // tracked here on the row; Tabs only reports `onReorder(from, to)` — and, when the moved tab\n // is the selected one, its new index through `onChange` — and keeps the tabs' focus alone;\n // the owner moves the tabs in its state.\n // Only while `onReorder` is given do the items carry `draggable`, and a disabled tab\n // never: the attribute is rendered declaratively by each `Tab` on its item (the wrapper,\n // or the bare tab when there is none), so it is part of the server markup — as in React.\n let dragSourceIndex: number | null = null;\n let draggingItem: HTMLElement | null = null;\n let dropTargetItem: HTMLElement | null = null;\n // The tab list itself is no item: a content-width row leaves an empty part past its last tab, and\n // the drag marks nothing there and drops nothing.\n const dragItemOf = (target: EventTarget | null): HTMLElement | null =>\n target instanceof Element && target !== tabListEl ? itemOf(target as HTMLElement) : null;\n const clearDragMarks = (): void => {\n draggingItem?.classList.remove(\"smwb-tab-item--dragging\");\n dropTargetItem?.classList.remove(\"smwb-tab-item--drop-target\");\n draggingItem = null;\n dropTargetItem = null;\n };\n\n const onItemDragStart: JSX.EventHandler<HTMLDivElement, DragEvent> = (event) => {\n if (!local.onReorder) return;\n const item = dragItemOf(event.target);\n if (!item) return;\n const index = indexOfFocus(item);\n if (index < 0 || isNodeDisabled(getTabNodes()[index])) return;\n dragSourceIndex = index;\n draggingItem = item;\n item.classList.add(\"smwb-tab-item--dragging\");\n // Firefox wants the drag given something to carry.\n event.dataTransfer?.setData(\"text/plain\", String(index));\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = \"move\";\n }\n };\n\n const onItemDragOver: JSX.EventHandler<HTMLDivElement, DragEvent> = (event) => {\n if (dragSourceIndex === null || !local.onReorder) return;\n const item = dragItemOf(event.target);\n if (!item) return;\n // Without it the drop is not allowed here.\n event.preventDefault();\n if (item === dropTargetItem) return;\n dropTargetItem?.classList.remove(\"smwb-tab-item--drop-target\");\n dropTargetItem = item;\n item.classList.add(\"smwb-tab-item--drop-target\");\n };\n\n const onItemDrop: JSX.EventHandler<HTMLDivElement, DragEvent> = (event) => {\n if (dragSourceIndex === null) return;\n const from = dragSourceIndex;\n dragSourceIndex = null;\n const to = indexOfFocus(dragItemOf(event.target));\n // Read before the drop is reported: the owner may answer `onReorder` synchronously and move\n // `value` with the tab, and moving a node in the DOM loses the focus in some environments.\n const sourceItem = draggingItem;\n const wasSelected = from === local.value;\n const doc = sourceItem?.ownerDocument;\n const hadFocus = Boolean(sourceItem && doc?.activeElement && sourceItem.contains(doc.activeElement));\n clearDragMarks();\n event.preventDefault();\n if (to >= 0 && to !== from) {\n local.onReorder?.(from, to);\n // The selection belongs to the tab: when the moved tab is the selected one, report its\n // new index as a click would, so a controlled owner moves the value with the tab. The\n // drop's event stands in for the click's, as the overflow menu's choice does.\n if (wasSelected) {\n local.onChange(event as unknown as MouseEvent & { currentTarget: HTMLElement; target: Element }, to);\n }\n // The focus belongs to the tab too: put it back on the moved tab when it had it. The\n // check that the node landed at `to` keeps this honest when the owner reorders later.\n if (hadFocus) {\n const moved = getTabNodes()[to];\n if (moved && itemOf(moved) === sourceItem) moved.focus();\n }\n }\n };\n\n const onItemDragEnd: JSX.EventHandler<HTMLDivElement, DragEvent> = () => {\n dragSourceIndex = null;\n clearDragMarks();\n };\n\n // Select the enabled tab `delta` places from the focused one, wrapping at the ends and\n // skipping disabled tabs: as Enter or Space would, through a synthesized click on the tab.\n const switchByChord = (event: KeyboardEvent & { target: Element }, delta: -1 | 1): void => {\n const nodes = getTabNodes();\n const from = indexOfFocus(event.target);\n if (from < 0 || nodes.length === 0) return;\n for (let step = 1; step <= nodes.length; step += 1) {\n const next = (from + delta * step + nodes.length) % nodes.length;\n const node = nodes[next];\n if (node && !isNodeDisabled(node)) {\n node.focus();\n node.click();\n return;\n }\n }\n };\n\n const onTabListKeyDown = (event: KeyboardEvent & { currentTarget: HTMLElement; target: Element }): void => {\n if (event.defaultPrevented) return;\n // The tabs' chords, ahead of the \"chords belong to the browser\" guard below. They are\n // best-effort: a browser of its own tabs reserves Mod+W and Mod+Shift+[/], and they\n // bite only in an embedded webview.\n if ((event.ctrlKey || event.metaKey) && !event.altKey && indexOfFocus(event.target) >= 0) {\n const index = indexOfFocus(event.target);\n const registration = registrations().find((candidate) => candidate.index() === index);\n if (matchesKeyboardShortcut(event, [\"Mod\", \"W\"])) {\n if (registration && !registration.disabled() && registration.closable()) {\n event.preventDefault();\n registration.requestClose(event);\n }\n return;\n }\n if (matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"[\"])) {\n event.preventDefault();\n switchByChord(event, -1);\n return;\n }\n if (matchesKeyboardShortcut(event, [\"Mod\", \"Shift\", \"]\"])) {\n event.preventDefault();\n switchByChord(event, 1);\n return;\n }\n }\n // Chords belong to the browser; a handler that took the key first keeps it.\n if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return;\n if (!event.target.closest('[role=\"tab\"]')) return;\n onRovingKeyDown(event);\n };\n\n // Focus can leave the row without a focusout: the focused tab is removed, and the browser moves\n // focus to the body. The row keeps the focused tab as its stop only while focus is in it, on\n // the tab that has it now (tabs before it may have come or gone).\n createEffect(\n on(\n items,\n () => {\n const doc = tabListEl?.ownerDocument;\n const closing = closingTab;\n if (doc && closing && !closing.item.isConnected) {\n closingTab = null;\n // A tab the user closed took the focus with it: the tab that takes its place gets it (the\n // previous one if it was last), the nearest that is not disabled. Focus that went anywhere\n // else meanwhile stays there.\n if (!doc.activeElement || doc.activeElement === doc.body) {\n const nodes = getTabNodes();\n const from = Math.min(closing.index, nodes.length - 1);\n const candidates = [...nodes.keys()].filter((index) => !isNodeDisabled(nodes[index]));\n const target = candidates.find((index) => index >= from) ?? candidates[candidates.length - 1];\n if (target !== undefined) {\n nodes[target]?.focus();\n setFocusedIndex(target);\n return;\n }\n }\n }\n if (focusedIndex() === null) return;\n const index = indexOfFocus(doc?.activeElement);\n setFocusedIndex(index >= 0 ? index : null);\n },\n { defer: true }\n )\n );\n\n const onTabListFocusIn = (event: FocusEvent): void => {\n const index = indexOfFocus(event.target as Node);\n if (index >= 0) setFocusedIndex(index);\n if (closingTab && !closingTab.item.contains(event.target as Node)) closingTab = null;\n };\n\n const onTabListFocusOut = (event: FocusEvent & { currentTarget: HTMLElement }): void => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {\n setFocusedIndex(null);\n // Chromium fires this too as the focused tab is removed, just before it goes, and the removal\n // is what the marker is for: it stays until the effect that follows the removal has used it.\n // One still standing once the current task's microtasks run was a real blur: that close no\n // longer takes the focus anywhere.\n queueMicrotask(() => {\n if (closingTab?.item.isConnected) closingTab = null;\n });\n }\n };\n\n const contextValue: TabsContextValue = {\n value: () => local.value,\n fit: () => local.fit,\n tabStop: (index) => stopIndex() === index,\n tabId,\n panelId,\n hasPanels,\n reorderable: () => local.onReorder !== undefined,\n onChange: local.onChange,\n closing: (index, reason) => {\n const tab = getTabNodes()[index];\n const active = tab?.ownerDocument.activeElement;\n // Focus in the item is focus on the tab. A close from the tab's own `actions` is the user's\n // wherever focus is: it is in the menu then, which is drawn outside the row.\n const focused = reason === \"actions\" || Boolean(active && tab && itemOf(tab).contains(active));\n closingTab = tab && focused ? { item: itemOf(tab), index } : null;\n },\n registerTab: (element, info) => {\n const order = created++;\n const index = createMemo(() => {\n const list = items();\n if (!list) return order;\n const el = element();\n return el ? list.findIndex((item) => item.contains(el)) : -1;\n });\n const registration: Registration = { ...info, index };\n setRegistrations((list) => [...list, registration]);\n onCleanup(() => setRegistrations((list) => list.filter((item) => item !== registration)));\n return index;\n },\n };\n\n const showScrollButtons = (): boolean =>\n local.scrollable && local.scrollButtons && (overflowStart() || overflowEnd());\n\n // The overflow menu's trigger appears only once the browser has measured a clipped tab,\n // so the server markup — and the first client render — shows none.\n const showOverflowTrigger = (): boolean =>\n local.scrollable && local.overflowMenu && hiddenIndexes().length > 0;\n\n // The menu lists what the viewport clips; each entry shows a copy of the tab's icon and\n // label (the live nodes belong to the row, so they are cloned into the entry, not moved),\n // kept in step with the tab while the menu is open.\n const overflowItemIcon = (node: HTMLElement | undefined): Element | undefined =>\n node?.querySelector(\".smwb-tab__icon\") ?? undefined;\n const overflowItemLabel = (node: HTMLElement | undefined): string =>\n node?.querySelector(\".smwb-tab__text-label\")?.textContent ?? \"\";\n const cloneIconInto = (el: HTMLElement, node: HTMLElement | undefined): void => {\n const source = overflowItemIcon(node);\n if (!source) return;\n Array.from(source.childNodes).forEach((child) => el.appendChild(child.cloneNode(true)));\n };\n\n const chooseOverflowItem = (\n event: MouseEvent & { currentTarget: HTMLLIElement; target: Element },\n index: number\n ): void => {\n setOverflowOpen(false);\n local.onChange(event, index);\n scrollIndexIntoView(index);\n };\n\n return (\n <TabsContext.Provider value={contextValue}>\n <PanelsResolver onPanels={(resolved, has) => (setPanels(() => resolved), setHasPanels(has))}>\n {local.panels}\n </PanelsResolver>\n <div\n {...rest}\n id={local.id}\n class={cn(\n \"smwb-tabs\",\n {\n \"smwb-tabs--dense\": local.dense,\n \"smwb-tabs--fit\": local.fit,\n \"smwb-tabs--overflow-start\": overflowStart(),\n \"smwb-tabs--overflow-end\": overflowEnd(),\n },\n local.class\n )}\n ref={mergeRefs(local.ref)}\n >\n <Show when={showScrollButtons()}>\n <button\n type=\"button\"\n class=\"smwb-tabs__scroll-button smwb-tabs__scroll-button--start\"\n aria-label={local.scrollBackAriaLabel}\n disabled={!overflowStart()}\n tabindex={-1}\n onClick={() => scrollByPage(-1)}\n >\n <Icon name=\"chevron_left\" size={20} />\n </button>\n </Show>\n {/* The scroller's class is static so it is on the element from the start:\n a ref on Tabs can find the row by class right away. */}\n <div\n class=\"smwb-tabs__scroller\"\n classList={{ \"smwb-tabs__scroller--scrollable\": local.scrollable }}\n ref={(el) => (tabsEl = el)}\n >\n <div\n class=\"smwb-tabs__scroll-area\"\n ref={(el) => (tabListEl = el)}\n role=\"tablist\"\n aria-label={local[\"aria-label\"]}\n aria-orientation={local.orientation}\n onKeyDown={onTabListKeyDown}\n onFocusIn={onTabListFocusIn}\n onFocusOut={onTabListFocusOut}\n onDragStart={onItemDragStart}\n onDragOver={onItemDragOver}\n onDrop={onItemDrop}\n onDragEnd={onItemDragEnd}\n >\n <TabListItems onItems={setItems}>{local.children}</TabListItems>\n </div>\n <Show when={mounted()}>\n <span\n class=\"smwb-tabs__indicator\"\n style={{\n left: `${indicatorStyle().root.left ?? 0}px`,\n width: `${indicatorStyle().root.width ?? 0}px`,\n }}\n >\n <span\n class=\"smwb-tabs__indicator-content\"\n style={indicatorStyle().content ? { width: `${indicatorStyle().content?.width ?? 0}px` } : {}}\n />\n </span>\n </Show>\n </div>\n <Show when={showScrollButtons()}>\n <button\n type=\"button\"\n class=\"smwb-tabs__scroll-button smwb-tabs__scroll-button--end\"\n aria-label={local.scrollForwardAriaLabel}\n disabled={!overflowEnd()}\n tabindex={-1}\n onClick={() => scrollByPage(1)}\n >\n <Icon name=\"chevron_right\" size={20} />\n </button>\n </Show>\n <Show when={showOverflowTrigger()}>\n <button\n type=\"button\"\n class=\"smwb-tabs__overflow-trigger\"\n aria-haspopup=\"menu\"\n aria-expanded={overflowOpen()}\n aria-label={local.overflowMenuAriaLabel}\n tabindex={-1}\n ref={(el) => (overflowTriggerEl = el)}\n onClick={() => setOverflowOpen((open) => !open)}\n >\n <Icon name=\"more_horiz\" size={20} />\n </button>\n <Menu\n anchorElement={overflowTriggerEl ?? null}\n isOpen={overflowOpen()}\n onClose={() => setOverflowOpen(false)}\n placement=\"bottom-end\"\n >\n <For each={hiddenIndexes()}>\n {(index) => {\n // The entry mirrors the tab it stands for. Solid children resolve to DOM, not to\n // prop objects, so the tab's own node is the source for the label and the icon;\n // a MutationObserver keeps the entry in step with renames and re-icons while the\n // menu is open. Disabled follows the tab's registration, as in the row's other\n // disabled bookkeeping, so a tab that flips `disabled` in place greys its entry out.\n //\n // Which node that is cannot be settled once, when the entry is drawn: an owner that\n // keys its list by value replaces the tab's node when its label changes, while the\n // clipped set — and so this entry — keeps its identity. `items` and `registrations`\n // are what announce the row moving, and the effect below reads the node from the row\n // when it runs, which is after Solid has landed that move in the DOM; a node sampled\n // earlier, into a memo or into a const, is the detached one by then.\n const nodeNow = (): HTMLElement | undefined => getTabNodes()[index];\n // What the row shows at this index as the entry is drawn, so its first paint is not\n // an empty entry; the effect below keeps it current from then on.\n const drawn = nodeNow();\n const [label, setLabel] = createSignal(overflowItemLabel(drawn));\n const [hasIcon, setHasIcon] = createSignal(Boolean(overflowItemIcon(drawn)));\n const disabled = createMemo(() => {\n const registration = registrations().find((candidate) => candidate.index() === index);\n return registration ? registration.disabled() : isNodeDisabled(nodeNow());\n });\n let iconEl: HTMLSpanElement | undefined;\n // The node the entry's content was last taken from: the icon span copies from it\n // when it is drawn, which is after the sync that asked for it.\n let shownNode = drawn;\n const syncIcon = (node: HTMLElement | undefined): void => {\n shownNode = node;\n const source = overflowItemIcon(node);\n setHasIcon(Boolean(source));\n if (iconEl && source) {\n iconEl.textContent = \"\";\n cloneIconInto(iconEl, node);\n }\n };\n createEffect(\n on([items, registrations], () => {\n const node = nodeNow();\n setLabel(overflowItemLabel(node));\n syncIcon(node);\n const item = node ? itemOf(node) : null;\n const view = item?.ownerDocument.defaultView;\n if (!item || !view || typeof view.MutationObserver === \"undefined\") return;\n const observer = new view.MutationObserver(() => {\n setLabel(overflowItemLabel(node));\n syncIcon(node);\n });\n observer.observe(item, { subtree: true, childList: true, characterData: true });\n onCleanup(() => observer.disconnect());\n })\n );\n return (\n <MenuItem\n disabled={disabled()}\n aria-current={index === local.value ? \"true\" : undefined}\n onClick={(event) => chooseOverflowItem(event, index)}\n >\n <Show when={hasIcon()}>\n <span\n class=\"smwb-tab__icon\"\n aria-hidden=\"true\"\n ref={(el) => {\n iconEl = el;\n // The span is drawn by the flag the sync above sets, so it is born after\n // that sync: it copies the icon of the node the entry last followed.\n if (overflowItemIcon(shownNode)) cloneIconInto(el, shownNode);\n }}\n />\n </Show>\n <span class=\"smwb-tab__text-label\">{label()}</span>\n </MenuItem>\n );\n }}\n </For>\n </Menu>\n </Show>\n </div>\n {panels()}\n </TabsContext.Provider>\n );\n}\n\nexport { Tab };\nexport type { TabProps, TabActionsApi, TabCloseReason } from \"./tab/tab\";\nexport default Tabs;\n"],"names":["VIEW_NEXT_TAB_PX","SCROLL_PAGE","TabListItems","props","resolved","children","isServer","createComputed","onItems","toArray","filter","node","Element","_$memo","PanelsResolver","onPanels","some","Tabs","merged","mergeProps","indicatorContent","scrollable","scrollButtons","overflowMenu","dense","fit","orientation","scrollBackAriaLabel","scrollForwardAriaLabel","overflowMenuAriaLabel","local","rest","splitProps","generatedId","createUniqueId","baseId","id","registrations","setRegistrations","createSignal","tabId","index","find","registration","panelId","panels","setPanels","hasPanels","setHasPanels","focusedIndex","setFocusedIndex","mounted","setMounted","indicatorStyle","setIndicatorStyle","root","overflowStart","setOverflowStart","overflowEnd","setOverflowEnd","hiddenIndexes","setHiddenIndexes","overflowOpen","setOverflowOpen","overflowTriggerEl","tabsEl","tabListEl","closingTab","items","setItems","created","getTabsMeta","tabsMeta","rect","getBoundingClientRect","clientWidth","scrollLeft","left","right","tabMeta","tabContentMeta","length","tab","value","querySelector","updateIndicatorState","startValue","next","width","content","prev","undefined","dStart","Math","abs","dSize","updateOverflow","max","scrollWidth","hidden","getHiddenIndexes","Array","from","map","child","item","offsetLeft","offsetWidth","every","at","scroll","scrollValue","animate","duration","scrollByPage","direction","scrollIndexIntoView","tabsRect","tabRect","scrollSelectedIntoView","onMount","createEffect","on","onResize","debounce","view","ownerDocument","defaultView","addEventListener","passive","resizeObserver","ResizeObserver","observe","forEach","onCleanup","cancel","removeEventListener","disconnect","getTabNodes","querySelectorAll","itemOf","closest","indexOfFocus","target","findIndex","contains","isNodeDisabled","getAttribute","disabled","selectedStop","count","candidate","list","enabled","min","stopIndex","onRovingKeyDown","createRovingTabIndex","activeIndex","onMove","focus","isDisabled","dragSourceIndex","draggingItem","dropTargetItem","dragItemOf","clearDragMarks","classList","remove","onItemDragStart","event","onReorder","add","dataTransfer","setData","String","effectAllowed","onItemDragOver","preventDefault","onItemDrop","to","sourceItem","wasSelected","doc","hadFocus","Boolean","activeElement","onChange","moved","onItemDragEnd","switchByChord","delta","nodes","step","click","onTabListKeyDown","defaultPrevented","ctrlKey","metaKey","altKey","matchesKeyboardShortcut","closable","requestClose","shiftKey","closing","isConnected","body","candidates","keys","defer","onTabListFocusIn","onTabListFocusOut","currentTarget","relatedTarget","queueMicrotask","contextValue","tabStop","reorderable","reason","active","focused","registerTab","element","info","order","createMemo","el","showScrollButtons","showOverflowTrigger","overflowItemIcon","overflowItemLabel","textContent","cloneIconInto","source","childNodes","appendChild","cloneNode","chooseOverflowItem","_$createComponent","TabsContext","Provider","has","_el$","_tmpl$5","_el$3","firstChild","_el$4","_ref$","mergeRefs","ref","_$use","_$spread","_$mergeProps","cn","class","_$insert","Show","when","_el$2","_tmpl$","$$click","Icon","name","size","_$effect","_p$","_v$","_v$2","e","_$setAttribute","t","$$focusout","$$focusin","$$keydown","_el$5","_tmpl$2","_el$6","_v$3","_v$4","_v$5","_$setStyleProperty","a","_$style","_el$7","_tmpl$3","_v$6","_v$7","_el$8","_tmpl$4","open","_v$8","_v$9","Menu","anchorElement","isOpen","onClose","placement","For","each","nodeNow","drawn","label","setLabel","hasIcon","setHasIcon","iconEl","shownNode","syncIcon","MutationObserver","observer","subtree","childList","characterData","MenuItem","onClick","_el$9","_tmpl$6","_el$0","_tmpl$7","_v$0","_v$1","_v$10","toggle","_$delegateEvents"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabsContext.js","sources":["../../../../../src/components/navigation/tabs/tabsContext.ts"],"sourcesContent":["import { type Accessor, createContext, useContext } from \"solid-js\";\n\n/** What asked for a tab to close: its close button, Delete or Backspace on it, its `actions`, or a middle click. */\nexport type TabCloseReason = \"button\" | \"key\" | \"actions\" | \"middleClick\";\n\n/** What a Tab tells its Tabs about itself, read when the Tabs needs it. */\nexport interface TabInfo {\n /** The tab's own `id`, if the caller gave one: the panel is labelled by it. */\n id: Accessor<string | undefined>;\n /** Whether the tab is disabled, so it cannot be the row's tab stop. */\n disabled: Accessor<boolean>;\n /** Whether the tab is `closable`: Mod+W on the focused tab asks to close it. */\n closable: Accessor<boolean>;\n /** Ask the tab to close with this event and the reason \"key\", as its own Delete handling would. */\n requestClose: (event: Event) => void;\n}\n\nexport interface TabsContextValue {\n value: Accessor<number>;\n onChange: (event: MouseEvent & { currentTarget: HTMLElement; target: Element }, index: number) => void;\n /**\n * Each Tab registers on setup with its root element (set once it renders) and\n * gets back its index: its position in the tab list, which follows the tab when\n * tabs are added, removed or reordered.\n */\n /** Whether the tab at `index` is the row's tab stop: the focused tab while focus is in the row, else the selected one. */\n tabStop: (index: number) => boolean;\n /** The id of the tab at `index`, its own if it has one: the one the panel at that index is labelled by. */\n tabId: (index: number) => string;\n /** The id of the panel at `index`: the one the tab at that index controls. */\n panelId: (index: number) => string;\n /** Whether the Tabs were given `panels`, so that its tabs control something. */\n hasPanels: Accessor<boolean>;\n /** Whether the row is reorderable (`onReorder` given): a tab's item is the drag surface then. */\n reorderable: Accessor<boolean>;\n registerTab: (element: Accessor<Element | undefined>, info: TabInfo) => Accessor<number>;\n /**\n * The tab at `index` is being closed by the user (its Delete key, its close button, its\n * `actions` or a middle click):\n * if focus is in it, or the close came from its actions, whose menu is drawn elsewhere, focus moves\n * to a neighbour when it goes, instead of falling to the page.\n */\n closing: (index: number, reason: TabCloseReason) => void;\n}\n\nexport const TabsContext = createContext<TabsContextValue>();\n\nexport const useTabsContext = (): TabsContextValue | undefined => useContext(TabsContext);\n"],"names":["TabsContext","createContext","useTabsContext","useContext"],"mappings":";
|
|
1
|
+
{"version":3,"file":"tabsContext.js","sources":["../../../../../src/components/navigation/tabs/tabsContext.ts"],"sourcesContent":["import { type Accessor, createContext, useContext } from \"solid-js\";\n\n/** What asked for a tab to close: its close button, Delete or Backspace on it, its `actions`, or a middle click. */\nexport type TabCloseReason = \"button\" | \"key\" | \"actions\" | \"middleClick\";\n\n/** What a Tab tells its Tabs about itself, read when the Tabs needs it. */\nexport interface TabInfo {\n /** The tab's own `id`, if the caller gave one: the panel is labelled by it. */\n id: Accessor<string | undefined>;\n /** Whether the tab is disabled, so it cannot be the row's tab stop. */\n disabled: Accessor<boolean>;\n /** Whether the tab is `closable`: Mod+W on the focused tab asks to close it. */\n closable: Accessor<boolean>;\n /** Ask the tab to close with this event and the reason \"key\", as its own Delete handling would. */\n requestClose: (event: Event) => void;\n}\n\nexport interface TabsContextValue {\n value: Accessor<number>;\n /** Whether the row is content-width (`fit`): a tab's label may be cut, so its text is the tab's title. */\n fit?: Accessor<boolean>;\n onChange: (event: MouseEvent & { currentTarget: HTMLElement; target: Element }, index: number) => void;\n /**\n * Each Tab registers on setup with its root element (set once it renders) and\n * gets back its index: its position in the tab list, which follows the tab when\n * tabs are added, removed or reordered.\n */\n /** Whether the tab at `index` is the row's tab stop: the focused tab while focus is in the row, else the selected one. */\n tabStop: (index: number) => boolean;\n /** The id of the tab at `index`, its own if it has one: the one the panel at that index is labelled by. */\n tabId: (index: number) => string;\n /** The id of the panel at `index`: the one the tab at that index controls. */\n panelId: (index: number) => string;\n /** Whether the Tabs were given `panels`, so that its tabs control something. */\n hasPanels: Accessor<boolean>;\n /** Whether the row is reorderable (`onReorder` given): a tab's item is the drag surface then. */\n reorderable: Accessor<boolean>;\n registerTab: (element: Accessor<Element | undefined>, info: TabInfo) => Accessor<number>;\n /**\n * The tab at `index` is being closed by the user (its Delete key, its close button, its\n * `actions` or a middle click):\n * if focus is in it, or the close came from its actions, whose menu is drawn elsewhere, focus moves\n * to a neighbour when it goes, instead of falling to the page.\n */\n closing: (index: number, reason: TabCloseReason) => void;\n}\n\nexport const TabsContext = createContext<TabsContextValue>();\n\nexport const useTabsContext = (): TabsContextValue | undefined => useContext(TabsContext);\n"],"names":["TabsContext","createContext","useTabsContext","useContext"],"mappings":";AA+CO,MAAMA,IAAcC,EAAA,GAEdC,IAAiB,MAAoCC,EAAWH,CAAW;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const r = "--smui-sheet-offset-top", s = [], c = () => {
|
|
2
|
+
const t = document.documentElement, e = s[s.length - 1];
|
|
3
|
+
e ? t.style.setProperty(r, e.height) : t.style.removeProperty(r);
|
|
4
|
+
}, p = (t) => {
|
|
5
|
+
const e = { height: "" }, o = () => {
|
|
6
|
+
e.height = `${t.getBoundingClientRect().height}px`, c();
|
|
7
|
+
};
|
|
8
|
+
s.push(e), o();
|
|
9
|
+
const n = typeof ResizeObserver > "u" ? void 0 : new ResizeObserver(o);
|
|
10
|
+
return n?.observe(t), () => {
|
|
11
|
+
n?.disconnect();
|
|
12
|
+
const i = s.indexOf(e);
|
|
13
|
+
i !== -1 && s.splice(i, 1), c();
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
p as publishHeaderOffset
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=publishHeaderOffset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publishHeaderOffset.js","sources":["../../../src/primitives/publishHeaderOffset.ts"],"sourcesContent":["/** The page-level variable a `Sheet` reads for the gap above its panel and its scrim. */\nconst OFFSET_VAR = \"--smui-sheet-offset-top\";\n\ninterface PublishedHeader {\n height: string;\n}\n\n/** The headers publishing right now, oldest first: the newest one owns the variable. */\nconst published: PublishedHeader[] = [];\n\nconst apply = (): void => {\n const root = document.documentElement;\n const top = published[published.length - 1];\n if (top) {\n root.style.setProperty(OFFSET_VAR, top.height);\n } else {\n root.style.removeProperty(OFFSET_VAR);\n }\n};\n\n/**\n * Publishes the height of a pinned header as `--smui-sheet-offset-top` on the document element, where a `Sheet`\n * (drawn in a portal on `body`, outside the layout) inherits it, and keeps it current as the header resizes.\n * With several headers at once the most recent one wins, and when it goes the one before it takes over again.\n * Returns a function that withdraws this header; the variable is removed once none is left.\n */\nexport const publishHeaderOffset = (header: HTMLElement): (() => void) => {\n const entry: PublishedHeader = { height: \"\" };\n const measure = (): void => {\n entry.height = `${header.getBoundingClientRect().height}px`;\n apply();\n };\n published.push(entry);\n measure();\n const observer = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(measure);\n observer?.observe(header);\n return () => {\n observer?.disconnect();\n const index = published.indexOf(entry);\n if (index !== -1) {\n published.splice(index, 1);\n }\n apply();\n };\n};\n"],"names":["OFFSET_VAR","published","apply","root","top","publishHeaderOffset","header","entry","measure","observer","index"],"mappings":"AACA,MAAMA,IAAa,2BAObC,IAA+B,CAAA,GAE/BC,IAAQ,MAAY;AACxB,QAAMC,IAAO,SAAS,iBAChBC,IAAMH,EAAUA,EAAU,SAAS,CAAC;AAC1C,EAAIG,IACFD,EAAK,MAAM,YAAYH,GAAYI,EAAI,MAAM,IAE7CD,EAAK,MAAM,eAAeH,CAAU;AAExC,GAQaK,IAAsB,CAACC,MAAsC;AACxE,QAAMC,IAAyB,EAAE,QAAQ,GAAA,GACnCC,IAAU,MAAY;AAC1B,IAAAD,EAAM,SAAS,GAAGD,EAAO,sBAAA,EAAwB,MAAM,MACvDJ,EAAA;AAAA,EACF;AACA,EAAAD,EAAU,KAAKM,CAAK,GACpBC,EAAA;AACA,QAAMC,IAAW,OAAO,iBAAmB,MAAc,SAAY,IAAI,eAAeD,CAAO;AAC/F,SAAAC,GAAU,QAAQH,CAAM,GACjB,MAAM;AACX,IAAAG,GAAU,WAAA;AACV,UAAMC,IAAQT,EAAU,QAAQM,CAAK;AACrC,IAAIG,MAAU,MACZT,EAAU,OAAOS,GAAO,CAAC,GAE3BR,EAAA;AAAA,EACF;AACF;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/components/dataDisplay/avatar/avatar.tsx"],"sourcesContent":["import {\n type JSX,\n type ParentProps,\n Show,\n children as resolveChildren,\n createSignal,\n mergeProps,\n splitProps,\n} from \"solid-js\";\nimport cn from \"clsx\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { callHandler } from \"../../../primitives/callHandler\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\n\nexport type AvatarSize = \"small\" | \"medium\" | \"large\";\n\nexport interface AvatarProps extends JSX.HTMLAttributes<HTMLDivElement> {\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/components/dataDisplay/avatar/avatar.tsx"],"sourcesContent":["import {\n type JSX,\n type ParentProps,\n Show,\n children as resolveChildren,\n createSignal,\n mergeProps,\n splitProps,\n} from \"solid-js\";\nimport cn from \"clsx\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { callHandler } from \"../../../primitives/callHandler\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\n\nexport type AvatarSize = \"small\" | \"medium\" | \"large\";\n\nexport interface AvatarProps extends JSX.HTMLAttributes<HTMLDivElement> {\n /**\n * Image source. Falls back to children (initials / icon) on error or when absent. While the image is shown the\n * avatar paints no background under it, so a transparent PNG/SVG shows what is behind the avatar.\n */\n src?: string | undefined;\n alt?: string | undefined;\n /** Preset size or an explicit pixel value. */\n size?: AvatarSize | number;\n variant?: \"circular\" | \"rounded\" | \"square\";\n /** Background color for the fallback (initials / icon); not painted under an image. */\n color?: string;\n /** Extra attributes forwarded to the underlying <img> (srcSet, loading…). */\n imgProps?: JSX.ImgHTMLAttributes<HTMLImageElement>;\n /** Test id of the root `<div>`; `avatar` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLDivElement>;\n}\n\nconst isPresetSize = (size: AvatarSize | number): size is AvatarSize => typeof size === \"string\";\n\nexport function Avatar(props: ParentProps<AvatarProps>): JSX.Element {\n const merged = mergeProps({ size: \"medium\" as AvatarSize | number, variant: \"circular\" as const }, props);\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"src\",\n \"alt\",\n \"size\",\n \"variant\",\n \"color\",\n \"style\",\n \"imgProps\",\n \"children\",\n \"ref\",\n \"data-testid\",\n ]);\n\n const [imgFailed, setImgFailed] = createSignal(false);\n const showImage = (): boolean => Boolean(local.src) && !imgFailed();\n\n const inlineStyle = (): JSX.CSSProperties | string | undefined => {\n const size = local.size;\n return mergeStyle(local.style, {\n ...(isPresetSize(size) ? {} : { width: `${size}px`, height: `${size}px`, \"font-size\": `${size / 2.5}px` }),\n ...(local.color && !showImage() ? { \"background-color\": local.color } : {}),\n });\n };\n\n return (\n <div\n {...rest}\n ref={mergeRefs(local.ref)}\n data-testid={local[\"data-testid\"] ?? \"avatar\"}\n class={cn(\n \"smwb-avatar\",\n `smwb-avatar_${local.variant}`,\n isPresetSize(local.size) ? `smwb-avatar_${local.size}` : undefined,\n showImage() ? \"smwb-avatar_image\" : undefined,\n local.class\n )}\n style={inlineStyle()}\n >\n <Show\n when={showImage()}\n fallback={\n <span class=\"smwb-avatar__fallback\" role=\"img\" aria-label={local.alt}>\n {local.children}\n </span>\n }\n >\n <img\n {...(local.imgProps ?? {})}\n class={cn(\"smwb-avatar__img\", local.imgProps?.class)}\n src={local.src}\n alt={local.alt}\n onError={(event) => {\n setImgFailed(true);\n callHandler(local.imgProps?.onError, event);\n }}\n />\n </Show>\n </div>\n );\n}\n\nexport interface AvatarGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {\n /** Maximum avatars to show before collapsing the rest into a \"+N\" surplus. */\n max?: number;\n /** Override the total count used for the surplus label (defaults to children count). */\n total?: number;\n /** Click handler for the \"+N\" surplus chip. */\n onSurplusClick?: () => void;\n /** Accessible name of the \"+N\" surplus chip. */\n surplusAriaLabel?: (count: number) => string;\n /** Size of the \"+N\" surplus chip: match the avatars in the group. */\n size?: AvatarSize | number;\n /** Test id of the root `<div>`; `avatar-group` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLDivElement>;\n}\n\nexport function AvatarGroup(props: ParentProps<AvatarGroupProps>): JSX.Element {\n const merged = mergeProps(\n { max: 5, surplusAriaLabel: (count: number) => `${count} more` },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"max\",\n \"total\",\n \"onSurplusClick\",\n \"surplusAriaLabel\",\n \"size\",\n \"children\",\n \"ref\",\n \"data-testid\",\n ]);\n\n const resolved = resolveChildren(() => local.children);\n const items = (): unknown[] => resolved.toArray();\n const totalCount = (): number => local.total ?? items().length;\n const clampedMax = (): number => Math.max(local.max, 1);\n const visible = (): unknown[] => items().slice(0, clampedMax());\n const hidden = (): unknown[] => items().slice(clampedMax());\n const surplus = (): number => totalCount() - visible().length;\n\n // In order, the first avatar first; the \"+N\" chip ends the row.\n return (\n <div\n {...rest}\n ref={mergeRefs(local.ref)}\n data-testid={local[\"data-testid\"] ?? \"avatar-group\"}\n class={cn(\"smwb-avatar-group\", local.class)}\n >\n {visible() as JSX.Element}\n <Show when={surplus() > 0}>\n <Avatar\n class=\"smwb-avatar-group__surplus\"\n size={local.size ?? \"medium\"}\n alt={local.surplusAriaLabel(surplus())}\n onClick={local.onSurplusClick}\n style={local.onSurplusClick ? { cursor: \"pointer\" } : undefined}\n >\n {`+${surplus()}`}\n </Avatar>\n </Show>\n {/* Avatars past max are created with the rest (the children resolve at\n once), so they are rendered, hidden: a server that left them out would\n leave the browser without nodes to hydrate them from. */}\n <Show when={hidden().length > 0}>\n <span class=\"smwb-avatar-group__hidden\" hidden>\n {hidden() as JSX.Element}\n </span>\n </Show>\n </div>\n );\n}\n\nexport default Avatar;\n"],"mappings":"AAAA;AAAA,EAGE;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAO,QAAQ;AACf,SAAS,iBAA2B;AACpC,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAuB3B,MAAM,eAAe,CAAC,SAAkD,OAAO,SAAS;AAEjF,SAAS,OAAO,OAA8C;AACnE,QAAM,SAAS,WAAW,EAAE,MAAM,UAAiC,SAAS,WAAoB,GAAG,KAAK;AACxG,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,WAAW,YAAY,IAAI,aAAa,KAAK;AACpD,QAAM,YAAY,MAAe,QAAQ,MAAM,GAAG,KAAK,CAAC,UAAU;AAElE,QAAM,cAAc,MAA8C;AAChE,UAAM,OAAO,MAAM;AACnB,WAAO,WAAW,MAAM,OAAO;AAAA,MAC7B,GAAI,aAAa,IAAI,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,MAAM,QAAQ,GAAG,IAAI,MAAM,aAAa,GAAG,OAAO,GAAG,KAAK;AAAA,MACxG,GAAI,MAAM,SAAS,CAAC,UAAU,IAAI,EAAE,oBAAoB,MAAM,MAAM,IAAI,CAAC;AAAA,IAC3E,CAAC;AAAA,EACH;AAEA,SACE,CAAC;AAAA,QACK;AAAA,IACJ,KAAK,UAAU,MAAM,GAAG;AAAA,IACxB,aAAa,MAAM,aAAa,KAAK;AAAA,IACrC,OAAO;AAAA,MACL;AAAA,MACA,eAAe,MAAM,OAAO;AAAA,MAC5B,aAAa,MAAM,IAAI,IAAI,eAAe,MAAM,IAAI,KAAK;AAAA,MACzD,UAAU,IAAI,sBAAsB;AAAA,MACpC,MAAM;AAAA,IACR;AAAA,IACA,OAAO,YAAY;AAAA,GACpB;AAAA,MACC,CAAC;AAAA,IACC,MAAM,UAAU;AAAA,IAChB,UACE,CAAC,KAAK,MAAM,wBAAwB,KAAK,MAAM,YAAY,MAAM,KAAK;AAAA,aACnE,MAAM,SAAS;AAAA,UAClB,EAFC;AAAA,GAIJ;AAAA,QACC,CAAC;AAAA,QACM,MAAM,YAAY,CAAC;AAAA,IACxB,OAAO,GAAG,oBAAoB,MAAM,UAAU,KAAK;AAAA,IACnD,KAAK,MAAM;AAAA,IACX,KAAK,MAAM;AAAA,IACX,SAAS,CAAC,UAAU;AAClB,mBAAa,IAAI;AACjB,kBAAY,MAAM,UAAU,SAAS,KAAK;AAAA,IAC5C;AAAA,EACF,EAAE;AAAA,MACJ,EAlBC,KAkBM;AAAA,IACT,EAhCC;AAkCL;AAkBO,SAAS,YAAY,OAAmD;AAC7E,QAAM,SAAS;AAAA,IACb,EAAE,KAAK,GAAG,kBAAkB,CAAC,UAAkB,GAAG,KAAK,QAAQ;AAAA,IAC/D;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,EACF,CAAC;AAED,QAAM,WAAW,gBAAgB,MAAM,MAAM,QAAQ;AACrD,QAAM,QAAQ,MAAiB,SAAS,QAAQ;AAChD,QAAM,aAAa,MAAc,MAAM,SAAS,MAAM,EAAE;AACxD,QAAM,aAAa,MAAc,KAAK,IAAI,MAAM,KAAK,CAAC;AACtD,QAAM,UAAU,MAAiB,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;AAC9D,QAAM,SAAS,MAAiB,MAAM,EAAE,MAAM,WAAW,CAAC;AAC1D,QAAM,UAAU,MAAc,WAAW,IAAI,QAAQ,EAAE;AAGvD,SACE,CAAC;AAAA,QACK;AAAA,IACJ,KAAK,UAAU,MAAM,GAAG;AAAA,IACxB,aAAa,MAAM,aAAa,KAAK;AAAA,IACrC,OAAO,GAAG,qBAAqB,MAAM,KAAK;AAAA,GAC3C;AAAA,OACE,QAAQ,EAAiB;AAAA,MAC1B,CAAC,KAAK,MAAM,QAAQ,IAAI,GAAG;AAAA,QACzB,CAAC;AAAA,IACC,MAAM;AAAA,IACN,MAAM,MAAM,QAAQ;AAAA,IACpB,KAAK,MAAM,iBAAiB,QAAQ,CAAC;AAAA,IACrC,SAAS,MAAM;AAAA,IACf,OAAO,MAAM,iBAAiB,EAAE,QAAQ,UAAU,IAAI;AAAA,GACvD;AAAA,WACE,IAAI,QAAQ,CAAC,GAAG;AAAA,QACnB,EARC,OAQQ;AAAA,MACX,EAVC,KAUM;AAAA;AAAA;AAAA;AAAA;AAAA,GAGsD;AAAA,MAC7D,CAAC,KAAK,MAAM,OAAO,EAAE,SAAS,GAAG;AAAA,QAC/B,CAAC,KAAK,MAAM,4BAA4B,OAAO;AAAA,WAC5C,OAAO,EAAiB;AAAA,QAC3B,EAFC,KAEM;AAAA,MACT,EAJC,KAIM;AAAA,IACT,EA1BC;AA4BL;AAEA,IAAO,iBAAQ;","names":[],"file":"avatar.jsx"}
|
|
@@ -14,8 +14,7 @@ import { mergeRefs } from "../../../primitives/mergeRefs";
|
|
|
14
14
|
import { mergeStyle } from "../../../primitives/mergeStyle";
|
|
15
15
|
import { chartTheme, readChartPalette, samePalette } from "./chartTheme";
|
|
16
16
|
const cssLength = (value) => typeof value === "number" ? `${value}px` : value;
|
|
17
|
-
|
|
18
|
-
function Chart(props) {
|
|
17
|
+
function ChartCore(props) {
|
|
19
18
|
const merged = mergeProps({ height: 240, renderer: "canvas" }, props);
|
|
20
19
|
const [local, rest] = splitProps(merged, [
|
|
21
20
|
"class",
|
|
@@ -128,13 +127,18 @@ function Chart(props) {
|
|
|
128
127
|
frame = requestAnimationFrame(onResize);
|
|
129
128
|
}) : void 0;
|
|
130
129
|
resizeObserver?.observe(canvas);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
const load = local.loader;
|
|
131
|
+
if (typeof load === "function") {
|
|
132
|
+
load().then(
|
|
133
|
+
(loaded) => {
|
|
134
|
+
module = loaded;
|
|
135
|
+
start();
|
|
136
|
+
},
|
|
137
|
+
(error) => console.error("[smwb] Chart: ECharts did not load.", error)
|
|
138
|
+
);
|
|
139
|
+
} else {
|
|
140
|
+
console.error("[smwb] Chart: no loader. Pass `loader`, a function that returns ECharts.");
|
|
141
|
+
}
|
|
138
142
|
onCleanup(() => {
|
|
139
143
|
disposed = true;
|
|
140
144
|
themeObserver.disconnect();
|
|
@@ -161,9 +165,7 @@ function Chart(props) {
|
|
|
161
165
|
</Show>
|
|
162
166
|
</div>;
|
|
163
167
|
}
|
|
164
|
-
var chart_default = Chart;
|
|
165
168
|
export {
|
|
166
|
-
|
|
167
|
-
chart_default as default
|
|
169
|
+
ChartCore
|
|
168
170
|
};
|
|
169
171
|
//# sourceMappingURL=chart.jsx.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/components/dataDisplay/chart/chart.tsx"],"sourcesContent":["import {\n type JSX,\n Show,\n createEffect,\n createSignal,\n mergeProps,\n onCleanup,\n onMount,\n splitProps,\n untrack,\n} from \"solid-js\";\nimport cn from \"clsx\";\nimport { Skeleton } from \"../../feedBack/skeleton\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\nimport { type ChartOption, type ChartPalette, chartTheme, readChartPalette, samePalette } from \"./chartTheme\";\n\n/** What an ECharts event hands its handler: the item under the pointer. */\nexport interface ChartEventParams {\n componentType?: string;\n seriesType?: string;\n seriesIndex?: number;\n seriesName?: string;\n name?: string;\n dataIndex?: number;\n data?: unknown;\n value?: unknown;\n [key: string]: unknown;\n}\n\n/** The part of an ECharts instance the chart uses; `onReady` hands over the instance itself. */\nexport interface ChartInstance {\n setOption(option: ChartOption, opts?: { notMerge?: boolean }): void;\n resize(): void;\n on(eventName: string, handler: (params: ChartEventParams) => void): void;\n dispose(): void;\n /** ECharts 6 switches the theme in place; with ECharts 5 the chart is created anew. */\n setTheme?(theme: object): void;\n}\n\n/** What `loader` resolves to: `echarts`, or `echarts/core` with the charts you use registered. */\nexport interface ChartModule {\n init(dom: HTMLElement, theme?: object | string | null, opts?: { renderer?: \"canvas\" | \"svg\" }): ChartInstance;\n}\n\nexport interface ChartProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"onClick\"> {\n /** What the chart shows: its accessible name. */\n label: string;\n /** The chart in words, for screen readers; it is there before the chart draws, and on the server. */\n summary?: string;\n /**\n * The ECharts option, or a function of the theme's palette that returns it.\n * It is applied whole whenever it or the theme changes.\n */\n option: ChartOption | ((palette: ChartPalette) => ChartOption);\n /** The chart's height: a number of pixels or any CSS length; 240 by default. It fills the width. */\n height?: number | string;\n /**\n * Loads ECharts in the browser: `import(\"echarts\")` by default, the whole\n * library. For a smaller bundle pass `() => import(\"./my-echarts\")`, a module\n * that registers only the charts you use with `echarts/core`.\n */\n loader?: () => Promise<ChartModule>;\n /** How ECharts draws: \"canvas\" (default) or \"svg\". Read once, when the chart is created. */\n renderer?: \"canvas\" | \"svg\";\n /** A click on an item: a bar, a point, a node. */\n onClick?: (params: ChartEventParams) => void;\n /** The ECharts instance, once it has drawn — for other events and actions. Called again if a theme change re-creates it. */\n onReady?: (chart: ChartInstance) => void;\n /** Test id of the root `<div>`; `chart` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLDivElement>;\n}\n\nconst cssLength = (value: number | string): string => (typeof value === \"number\" ? `${value}px` : value);\n\nconst loadECharts = (): Promise<ChartModule> => import(\"echarts\") as unknown as Promise<ChartModule>;\n\n/**\n * An ECharts chart in the theme's palette. On the server, and until ECharts\n * loads in the browser, a skeleton of the same size stands in its place, so\n * the page does not jump; the chart follows theme switches and its box's size.\n */\nexport function Chart(props: ChartProps): JSX.Element {\n const merged = mergeProps({ height: 240 as number | string, renderer: \"canvas\" as \"canvas\" | \"svg\" }, props);\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"style\",\n \"label\",\n \"summary\",\n \"option\",\n \"height\",\n \"loader\",\n \"renderer\",\n \"onClick\",\n \"onReady\",\n \"ref\",\n \"data-testid\",\n ]);\n\n let root!: HTMLDivElement;\n let canvas!: HTMLDivElement;\n const [palette, setPalette] = createSignal<ChartPalette>();\n const [ready, setReady] = createSignal(false);\n let module: ChartModule | undefined;\n let instance: ChartInstance | undefined;\n let themed: ChartPalette | undefined;\n let announced: ChartInstance | undefined;\n let pending = false;\n\n const hasSize = (): boolean => canvas.clientWidth > 0 && canvas.clientHeight > 0;\n const optionFor = (colours: ChartPalette): ChartOption =>\n typeof local.option === \"function\" ? local.option(colours) : local.option;\n\n const create = (loaded: ChartModule, colours: ChartPalette): ChartInstance => {\n const created = loaded.init(canvas, chartTheme(colours), { renderer: local.renderer });\n created.on(\"click\", (params) => local.onClick?.(params));\n themed = colours;\n return created;\n };\n\n // Not at zero size (a hidden tab, a collapsed panel): there the graph of\n // ECharts 6.1 inverts a degenerate matrix and throws. The option waits for\n // the chart to get a size, and a failed redraw is caught up on the next one.\n const draw = (option: ChartOption): void => {\n if (!instance) return;\n if (!hasSize()) {\n pending = true;\n return;\n }\n pending = false;\n try {\n instance.setOption(option, { notMerge: true });\n } catch (error) {\n console.error(\"[smwb] Chart: the option did not draw.\", error);\n }\n };\n\n const retheme = (colours: ChartPalette): void => {\n if (!instance || !module || (themed && samePalette(themed, colours))) return;\n if (typeof instance.setTheme === \"function\") {\n try {\n instance.setTheme(chartTheme(colours));\n } catch (error) {\n console.error(\"[smwb] Chart: the theme did not apply.\", error);\n }\n themed = colours;\n } else {\n instance.dispose();\n instance = create(module, colours);\n }\n };\n\n createEffect(() => {\n const colours = palette();\n if (!ready() || !colours || !instance) return;\n retheme(colours);\n draw(optionFor(colours));\n const current = instance;\n if (current && announced !== current) {\n announced = current;\n untrack(() => local.onReady?.(current));\n }\n });\n\n onMount(() => {\n let disposed = false;\n const refresh = (): void => {\n const next = readChartPalette(root);\n const current = untrack(palette);\n if (!current || !samePalette(current, next)) setPalette(next);\n };\n refresh();\n\n // The theme switches by an attribute on <html> (data-theme, a class) or\n // with the system setting.\n const themeObserver = new MutationObserver(() => requestAnimationFrame(refresh));\n themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-theme\", \"class\", \"style\"],\n });\n const media =\n typeof window.matchMedia === \"function\" ? window.matchMedia(\"(prefers-color-scheme: dark)\") : undefined;\n media?.addEventListener(\"change\", refresh);\n\n // The palette is read again here, not taken from mount: a theme set after\n // the chart mounted would otherwise show for a frame in the old colours.\n const start = (): void => {\n if (disposed || instance || !module || !hasSize()) return;\n const colours = readChartPalette(root);\n const current = untrack(palette);\n if (!current || !samePalette(current, colours)) setPalette(colours);\n instance = create(module, colours);\n setReady(true);\n };\n\n const onResize = (): void => {\n if (!hasSize()) return;\n if (!instance) {\n start();\n return;\n }\n try {\n instance.resize();\n } catch {\n // It catches up on the next resize.\n }\n const colours = untrack(palette);\n if (pending && colours) draw(untrack(() => optionFor(colours)));\n };\n // In the next frame, not in the observer's callback: drawing there resizes\n // what it observes, and the browser reports a ResizeObserver loop.\n let frame = 0;\n const resizeObserver =\n typeof ResizeObserver === \"function\"\n ? new ResizeObserver(() => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(onResize);\n })\n : undefined;\n resizeObserver?.observe(canvas);\n\n (local.loader ?? loadECharts)().then(\n (loaded) => {\n module = loaded;\n start();\n },\n (error: unknown) => console.error(\"[smwb] Chart: ECharts did not load.\", error)\n );\n\n onCleanup(() => {\n disposed = true;\n themeObserver.disconnect();\n media?.removeEventListener(\"change\", refresh);\n resizeObserver?.disconnect();\n cancelAnimationFrame(frame);\n instance?.dispose();\n instance = undefined;\n });\n });\n\n return (\n <div\n data-testid={local[\"data-testid\"] ?? \"chart\"}\n {...rest}\n ref={mergeRefs(local.ref, (el) => (root = el))}\n class={cn(\"smwb-chart\", local.class)}\n style={mergeStyle(local.style, { height: cssLength(local.height) })}\n >\n <div ref={canvas} class=\"smwb-chart__canvas\" role=\"img\" aria-label={local.label} />\n <Show when={!ready()}>\n <Skeleton class=\"smwb-chart__skeleton\" variant=\"rounded\" width=\"100%\" height=\"100%\" />\n </Show>\n <Show when={local.summary}>\n <p class=\"smwb-chart__summary\">{local.summary}</p>\n </Show>\n </div>\n );\n}\n\nexport default Chart;\n"],"mappings":"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","names":[],"file":"chart.jsx"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/components/dataDisplay/chart/chart.tsx"],"sourcesContent":["import {\n type JSX,\n Show,\n createEffect,\n createSignal,\n mergeProps,\n onCleanup,\n onMount,\n splitProps,\n untrack,\n} from \"solid-js\";\nimport cn from \"clsx\";\nimport { Skeleton } from \"../../feedBack/skeleton\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\nimport { type ChartOption, type ChartPalette, chartTheme, readChartPalette, samePalette } from \"./chartTheme\";\n\n/** What an ECharts event hands its handler: the item under the pointer. */\nexport interface ChartEventParams {\n componentType?: string;\n seriesType?: string;\n seriesIndex?: number;\n seriesName?: string;\n name?: string;\n dataIndex?: number;\n data?: unknown;\n value?: unknown;\n [key: string]: unknown;\n}\n\n/** The part of an ECharts instance the chart uses; `onReady` hands over the instance itself. */\nexport interface ChartInstance {\n setOption(option: ChartOption, opts?: { notMerge?: boolean }): void;\n resize(): void;\n on(eventName: string, handler: (params: ChartEventParams) => void): void;\n dispose(): void;\n /** ECharts 6 switches the theme in place; with ECharts 5 the chart is created anew. */\n setTheme?(theme: object): void;\n}\n\n/** What `loader` resolves to: `echarts`, or `echarts/core` with the charts you use registered. */\nexport interface ChartModule {\n init(dom: HTMLElement, theme?: object | string | null, opts?: { renderer?: \"canvas\" | \"svg\" }): ChartInstance;\n}\n\nexport interface ChartProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"onClick\"> {\n /** What the chart shows: its accessible name. */\n label: string;\n /** The chart in words, for screen readers; it is there before the chart draws, and on the server. */\n summary?: string;\n /**\n * The ECharts option, or a function of the theme's palette that returns it.\n * It is applied whole whenever it or the theme changes.\n */\n option: ChartOption | ((palette: ChartPalette) => ChartOption);\n /** The chart's height: a number of pixels or any CSS length; 240 by default. It fills the width. */\n height?: number | string;\n /**\n * Loads ECharts in the browser. Optional in `@smwb/ui-solid/chart`, where\n * `import(\"echarts\")` — the whole library — is the default; required in\n * `@smwb/ui-solid/chart/core`, which has no default and so never puts the\n * whole library in your bundle. For a smaller bundle pass\n * `() => import(\"./my-echarts\")`, a module that registers only the charts\n * you use with `echarts/core`.\n */\n loader?: () => Promise<ChartModule>;\n /** How ECharts draws: \"canvas\" (default) or \"svg\". Read once, when the chart is created. */\n renderer?: \"canvas\" | \"svg\";\n /** A click on an item: a bar, a point, a node. */\n onClick?: (params: ChartEventParams) => void;\n /** The ECharts instance, once it has drawn — for other events and actions. Called again if a theme change re-creates it. */\n onReady?: (chart: ChartInstance) => void;\n /** Test id of the root `<div>`; `chart` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLDivElement>;\n}\n\nconst cssLength = (value: number | string): string => (typeof value === \"number\" ? `${value}px` : value);\n\n/**\n * An ECharts chart in the theme's palette, loaded by the `loader` it is given\n * and by nothing else: this module never reaches `echarts`, so a bundler that\n * follows it finds no copy of the whole library. The `chart` entry puts the\n * default loader on top (`chartFull.ts`); the `chart/core` entry is this\n * component as it is, with `loader` required (`core.ts`).\n *\n * On the server, and until ECharts loads in the browser, a skeleton of the same\n * size stands in its place, so the page does not jump; the chart follows theme\n * switches and its box's size.\n */\nexport function ChartCore(props: ChartProps): JSX.Element {\n const merged = mergeProps({ height: 240 as number | string, renderer: \"canvas\" as \"canvas\" | \"svg\" }, props);\n const [local, rest] = splitProps(merged, [\n \"class\",\n \"style\",\n \"label\",\n \"summary\",\n \"option\",\n \"height\",\n \"loader\",\n \"renderer\",\n \"onClick\",\n \"onReady\",\n \"ref\",\n \"data-testid\",\n ]);\n\n let root!: HTMLDivElement;\n let canvas!: HTMLDivElement;\n const [palette, setPalette] = createSignal<ChartPalette>();\n const [ready, setReady] = createSignal(false);\n let module: ChartModule | undefined;\n let instance: ChartInstance | undefined;\n let themed: ChartPalette | undefined;\n let announced: ChartInstance | undefined;\n let pending = false;\n\n const hasSize = (): boolean => canvas.clientWidth > 0 && canvas.clientHeight > 0;\n const optionFor = (colours: ChartPalette): ChartOption =>\n typeof local.option === \"function\" ? local.option(colours) : local.option;\n\n const create = (loaded: ChartModule, colours: ChartPalette): ChartInstance => {\n const created = loaded.init(canvas, chartTheme(colours), { renderer: local.renderer });\n created.on(\"click\", (params) => local.onClick?.(params));\n themed = colours;\n return created;\n };\n\n // Not at zero size (a hidden tab, a collapsed panel): there the graph of\n // ECharts 6.1 inverts a degenerate matrix and throws. The option waits for\n // the chart to get a size, and a failed redraw is caught up on the next one.\n const draw = (option: ChartOption): void => {\n if (!instance) return;\n if (!hasSize()) {\n pending = true;\n return;\n }\n pending = false;\n try {\n instance.setOption(option, { notMerge: true });\n } catch (error) {\n console.error(\"[smwb] Chart: the option did not draw.\", error);\n }\n };\n\n const retheme = (colours: ChartPalette): void => {\n if (!instance || !module || (themed && samePalette(themed, colours))) return;\n if (typeof instance.setTheme === \"function\") {\n try {\n instance.setTheme(chartTheme(colours));\n } catch (error) {\n console.error(\"[smwb] Chart: the theme did not apply.\", error);\n }\n themed = colours;\n } else {\n instance.dispose();\n instance = create(module, colours);\n }\n };\n\n createEffect(() => {\n const colours = palette();\n if (!ready() || !colours || !instance) return;\n retheme(colours);\n draw(optionFor(colours));\n const current = instance;\n if (current && announced !== current) {\n announced = current;\n untrack(() => local.onReady?.(current));\n }\n });\n\n onMount(() => {\n let disposed = false;\n const refresh = (): void => {\n const next = readChartPalette(root);\n const current = untrack(palette);\n if (!current || !samePalette(current, next)) setPalette(next);\n };\n refresh();\n\n // The theme switches by an attribute on <html> (data-theme, a class) or\n // with the system setting.\n const themeObserver = new MutationObserver(() => requestAnimationFrame(refresh));\n themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-theme\", \"class\", \"style\"],\n });\n const media =\n typeof window.matchMedia === \"function\" ? window.matchMedia(\"(prefers-color-scheme: dark)\") : undefined;\n media?.addEventListener(\"change\", refresh);\n\n // The palette is read again here, not taken from mount: a theme set after\n // the chart mounted would otherwise show for a frame in the old colours.\n const start = (): void => {\n if (disposed || instance || !module || !hasSize()) return;\n const colours = readChartPalette(root);\n const current = untrack(palette);\n if (!current || !samePalette(current, colours)) setPalette(colours);\n instance = create(module, colours);\n setReady(true);\n };\n\n const onResize = (): void => {\n if (!hasSize()) return;\n if (!instance) {\n start();\n return;\n }\n try {\n instance.resize();\n } catch {\n // It catches up on the next resize.\n }\n const colours = untrack(palette);\n if (pending && colours) draw(untrack(() => optionFor(colours)));\n };\n // In the next frame, not in the observer's callback: drawing there resizes\n // what it observes, and the browser reports a ResizeObserver loop.\n let frame = 0;\n const resizeObserver =\n typeof ResizeObserver === \"function\"\n ? new ResizeObserver(() => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(onResize);\n })\n : undefined;\n resizeObserver?.observe(canvas);\n\n // The type asks for a loader in `chart/core`; a caller without types still\n // gets the skeleton and a message, not an error thrown out of onMount.\n const load = local.loader;\n if (typeof load === \"function\") {\n load().then(\n (loaded) => {\n module = loaded;\n start();\n },\n (error: unknown) => console.error(\"[smwb] Chart: ECharts did not load.\", error)\n );\n } else {\n console.error(\"[smwb] Chart: no loader. Pass `loader`, a function that returns ECharts.\");\n }\n\n onCleanup(() => {\n disposed = true;\n themeObserver.disconnect();\n media?.removeEventListener(\"change\", refresh);\n resizeObserver?.disconnect();\n cancelAnimationFrame(frame);\n instance?.dispose();\n instance = undefined;\n });\n });\n\n return (\n <div\n data-testid={local[\"data-testid\"] ?? \"chart\"}\n {...rest}\n ref={mergeRefs(local.ref, (el) => (root = el))}\n class={cn(\"smwb-chart\", local.class)}\n style={mergeStyle(local.style, { height: cssLength(local.height) })}\n >\n <div ref={canvas} class=\"smwb-chart__canvas\" role=\"img\" aria-label={local.label} />\n <Show when={!ready()}>\n <Skeleton class=\"smwb-chart__skeleton\" variant=\"rounded\" width=\"100%\" height=\"100%\" />\n </Show>\n <Show when={local.summary}>\n <p class=\"smwb-chart__summary\">{local.summary}</p>\n </Show>\n </div>\n );\n}\n"],"mappings":"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","names":[],"file":"chart.jsx"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createComponent, mergeProps } from "solid-js";
|
|
2
|
+
import { ChartCore } from "./chart";
|
|
3
|
+
const loadFullECharts = () => import("echarts");
|
|
4
|
+
function Chart(props) {
|
|
5
|
+
return createComponent(ChartCore, mergeProps({ loader: loadFullECharts }, props));
|
|
6
|
+
}
|
|
7
|
+
var chartFull_default = Chart;
|
|
8
|
+
export {
|
|
9
|
+
Chart,
|
|
10
|
+
chartFull_default as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=chartFull.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/components/dataDisplay/chart/chartFull.ts"],
|
|
4
|
+
"sourcesContent": ["import { type JSX, createComponent, mergeProps } from \"solid-js\";\nimport { ChartCore, type ChartModule, type ChartProps } from \"./chart\";\n\n// The only place in the chart's modules that reaches \"echarts\": a bundler that\n// finds this import emits a chunk with the whole library, used or not. The\n// `chart/core` entry never imports this file.\nconst loadFullECharts = (): Promise<ChartModule> => import(\"echarts\") as unknown as Promise<ChartModule>;\n\n/**\n * An ECharts chart in the theme's palette. Without a `loader` it loads the\n * whole of `echarts`, which makes the bundler emit a chunk with the whole\n * library; to build without that chunk import `Chart` from\n * `@smwb/ui-solid/chart/core` and give it a `loader` of your own.\n *\n * On the server, and until ECharts loads in the browser, a skeleton of the same\n * size stands in its place, so the page does not jump; the chart follows theme\n * switches and its box's size.\n */\nexport function Chart(props: ChartProps): JSX.Element {\n // A `loader` that is not given (or is undefined) leaves the default in place.\n return createComponent(ChartCore, mergeProps({ loader: loadFullECharts }, props));\n}\n\nexport default Chart;\n"],
|
|
5
|
+
"mappings": "AAAA,SAAmB,iBAAiB,kBAAkB;AACtD,SAAS,iBAAoD;AAK7D,MAAM,kBAAkB,MAA4B,OAAO,SAAS;AAY7D,SAAS,MAAM,OAAgC;AAEpD,SAAO,gBAAgB,WAAW,WAAW,EAAE,QAAQ,gBAAgB,GAAG,KAAK,CAAC;AAClF;AAEA,IAAO,oBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChartCore } from "./chart";
|
|
2
|
+
const Chart = ChartCore;
|
|
3
|
+
var core_default = Chart;
|
|
4
|
+
import { chartTheme, readChartPalette } from "./chartTheme";
|
|
5
|
+
export {
|
|
6
|
+
Chart,
|
|
7
|
+
chartTheme,
|
|
8
|
+
core_default as default,
|
|
9
|
+
readChartPalette
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/components/dataDisplay/chart/core.ts"],
|
|
4
|
+
"sourcesContent": ["// The `@smwb/ui-solid/chart/core` entry: the chart with no default loader.\n// Nothing here reaches `echarts` at run time, so an app that gives `Chart` its\n// own `loader` (a module built on `echarts/core`) gets no copy of the whole\n// library in its bundle.\nimport type { JSX } from \"solid-js\";\nimport { ChartCore, type ChartModule, type ChartProps as ChartPropsWithDefaultLoader } from \"./chart\";\n\n/** The props of `Chart`, with `loader` required: there is no default to fall back on. */\nexport type ChartProps = Omit<ChartPropsWithDefaultLoader, \"loader\"> & {\n /**\n * Loads ECharts in the browser: `() => import(\"./my-echarts\")`, a module that\n * registers only the charts you use with `echarts/core` and exports its `init`.\n */\n loader: () => Promise<ChartModule>;\n};\n\n/**\n * An ECharts chart in the theme's palette, with no built-in ECharts: `loader`\n * is required, and the whole library is never part of your bundle.\n */\nexport const Chart: (props: ChartProps) => JSX.Element = ChartCore;\n\nexport default Chart;\nexport type { ChartEventParams, ChartInstance, ChartModule } from \"./chart\";\nexport { chartTheme, readChartPalette } from \"./chartTheme\";\nexport type { ChartOption, ChartPalette } from \"./chartTheme\";\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,iBAAmF;AAerF,MAAM,QAA4C;AAEzD,IAAO,eAAQ;AAEf,SAAS,YAAY,wBAAwB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|