@adobe/spectrum-wc-core 0.4.0-snapshot-test.20260714143259
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 +39 -0
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/decorate.js +9 -0
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/defineProperty.js +12 -0
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/toPrimitive.js +14 -0
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/toPropertyKey.js +9 -0
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/typeof.js +11 -0
- package/dist/components/accordion/Accordion.base.d.ts +61 -0
- package/dist/components/accordion/Accordion.base.js +71 -0
- package/dist/components/accordion/Accordion.base.js.map +1 -0
- package/dist/components/accordion/Accordion.types.d.ts +22 -0
- package/dist/components/accordion/Accordion.types.js +21 -0
- package/dist/components/accordion/Accordion.types.js.map +1 -0
- package/dist/components/accordion/AccordionItem.base.d.ts +86 -0
- package/dist/components/accordion/AccordionItem.base.js +90 -0
- package/dist/components/accordion/AccordionItem.base.js.map +1 -0
- package/dist/components/accordion/index.d.ts +14 -0
- package/dist/components/accordion/index.js +4 -0
- package/dist/components/action-button/ActionButton.types.d.ts +15 -0
- package/dist/components/action-button/ActionButton.types.js +12 -0
- package/dist/components/action-button/ActionButton.types.js.map +1 -0
- package/dist/components/action-button/index.d.ts +12 -0
- package/dist/components/action-button/index.js +2 -0
- package/dist/components/alert-banner/AlertBanner.base.d.ts +36 -0
- package/dist/components/alert-banner/AlertBanner.base.js +56 -0
- package/dist/components/alert-banner/AlertBanner.base.js.map +1 -0
- package/dist/components/alert-banner/AlertBanner.types.d.ts +13 -0
- package/dist/components/alert-banner/AlertBanner.types.js +10 -0
- package/dist/components/alert-banner/AlertBanner.types.js.map +1 -0
- package/dist/components/alert-banner/index.d.ts +13 -0
- package/dist/components/alert-banner/index.js +3 -0
- package/dist/components/asset/Asset.base.d.ts +22 -0
- package/dist/components/asset/Asset.base.js +25 -0
- package/dist/components/asset/Asset.base.js.map +1 -0
- package/dist/components/asset/Asset.types.d.ts +13 -0
- package/dist/components/asset/Asset.types.js +6 -0
- package/dist/components/asset/Asset.types.js.map +1 -0
- package/dist/components/asset/index.d.ts +13 -0
- package/dist/components/asset/index.js +3 -0
- package/dist/components/avatar/Avatar.base.d.ts +53 -0
- package/dist/components/avatar/Avatar.base.js +56 -0
- package/dist/components/avatar/Avatar.base.js.map +1 -0
- package/dist/components/avatar/Avatar.types.d.ts +19 -0
- package/dist/components/avatar/Avatar.types.js +24 -0
- package/dist/components/avatar/Avatar.types.js.map +1 -0
- package/dist/components/avatar/index.d.ts +13 -0
- package/dist/components/avatar/index.js +3 -0
- package/dist/components/badge/Badge.base.d.ts +98 -0
- package/dist/components/badge/Badge.base.js +44 -0
- package/dist/components/badge/Badge.base.js.map +1 -0
- package/dist/components/badge/Badge.types.d.ts +21 -0
- package/dist/components/badge/Badge.types.js +43 -0
- package/dist/components/badge/Badge.types.js.map +1 -0
- package/dist/components/badge/index.d.ts +13 -0
- package/dist/components/badge/index.js +3 -0
- package/dist/components/button/Button.base.d.ts +99 -0
- package/dist/components/button/Button.base.js +75 -0
- package/dist/components/button/Button.base.js.map +1 -0
- package/dist/components/button/Button.types.d.ts +19 -0
- package/dist/components/button/Button.types.js +16 -0
- package/dist/components/button/Button.types.js.map +1 -0
- package/dist/components/button/index.d.ts +13 -0
- package/dist/components/button/index.js +3 -0
- package/dist/components/button-group/ButtonGroup.base.d.ts +89 -0
- package/dist/components/button-group/ButtonGroup.base.js +53 -0
- package/dist/components/button-group/ButtonGroup.base.js.map +1 -0
- package/dist/components/button-group/ButtonGroup.types.d.ts +17 -0
- package/dist/components/button-group/ButtonGroup.types.js +15 -0
- package/dist/components/button-group/ButtonGroup.types.js.map +1 -0
- package/dist/components/button-group/index.d.ts +13 -0
- package/dist/components/button-group/index.js +3 -0
- package/dist/components/card/Card.base.d.ts +123 -0
- package/dist/components/card/Card.base.js +75 -0
- package/dist/components/card/Card.base.js.map +1 -0
- package/dist/components/card/Card.types.d.ts +17 -0
- package/dist/components/card/Card.types.js +21 -0
- package/dist/components/card/Card.types.js.map +1 -0
- package/dist/components/card/index.d.ts +13 -0
- package/dist/components/card/index.js +3 -0
- package/dist/components/color-handle/ColorHandle.base.d.ts +51 -0
- package/dist/components/color-handle/ColorHandle.base.js +39 -0
- package/dist/components/color-handle/ColorHandle.base.js.map +1 -0
- package/dist/components/color-handle/ColorHandle.types.d.ts +30 -0
- package/dist/components/color-handle/color-contrast.d.ts +55 -0
- package/dist/components/color-handle/color-contrast.js +49 -0
- package/dist/components/color-handle/color-contrast.js.map +1 -0
- package/dist/components/color-handle/index.d.ts +14 -0
- package/dist/components/color-handle/index.js +3 -0
- package/dist/components/color-loupe/ColorLoupe.base.d.ts +26 -0
- package/dist/components/color-loupe/ColorLoupe.base.js +17 -0
- package/dist/components/color-loupe/ColorLoupe.base.js.map +1 -0
- package/dist/components/color-loupe/index.d.ts +12 -0
- package/dist/components/color-loupe/index.js +2 -0
- package/dist/components/divider/Divider.base.d.ts +43 -0
- package/dist/components/divider/Divider.base.js +37 -0
- package/dist/components/divider/Divider.base.js.map +1 -0
- package/dist/components/divider/Divider.types.d.ts +15 -0
- package/dist/components/divider/Divider.types.js +10 -0
- package/dist/components/divider/Divider.types.js.map +1 -0
- package/dist/components/divider/index.d.ts +13 -0
- package/dist/components/divider/index.js +3 -0
- package/dist/components/icon/Icon.base.d.ts +32 -0
- package/dist/components/icon/Icon.base.js +35 -0
- package/dist/components/icon/Icon.base.js.map +1 -0
- package/dist/components/icon/Icon.types.d.ts +13 -0
- package/dist/components/icon/Icon.types.js +12 -0
- package/dist/components/icon/Icon.types.js.map +1 -0
- package/dist/components/icon/index.d.ts +13 -0
- package/dist/components/icon/index.js +3 -0
- package/dist/components/illustrated-message/IllustratedMessage.base.d.ts +46 -0
- package/dist/components/illustrated-message/IllustratedMessage.base.js +46 -0
- package/dist/components/illustrated-message/IllustratedMessage.base.js.map +1 -0
- package/dist/components/illustrated-message/IllustratedMessage.types.d.ts +15 -0
- package/dist/components/illustrated-message/IllustratedMessage.types.js +10 -0
- package/dist/components/illustrated-message/IllustratedMessage.types.js.map +1 -0
- package/dist/components/illustrated-message/index.d.ts +13 -0
- package/dist/components/illustrated-message/index.js +3 -0
- package/dist/components/meter/Meter.base.d.ts +40 -0
- package/dist/components/meter/Meter.base.js +30 -0
- package/dist/components/meter/Meter.base.js.map +1 -0
- package/dist/components/meter/Meter.types.d.ts +13 -0
- package/dist/components/meter/Meter.types.js +11 -0
- package/dist/components/meter/Meter.types.js.map +1 -0
- package/dist/components/meter/index.d.ts +13 -0
- package/dist/components/meter/index.js +3 -0
- package/dist/components/popover/Popover.base.d.ts +223 -0
- package/dist/components/popover/Popover.base.js +270 -0
- package/dist/components/popover/Popover.base.js.map +1 -0
- package/dist/components/popover/Popover.types.d.ts +39 -0
- package/dist/components/popover/Popover.types.js +24 -0
- package/dist/components/popover/Popover.types.js.map +1 -0
- package/dist/components/popover/index.d.ts +13 -0
- package/dist/components/popover/index.js +3 -0
- package/dist/components/progress-circle/ProgressCircle.base.d.ts +91 -0
- package/dist/components/progress-circle/ProgressCircle.base.js +73 -0
- package/dist/components/progress-circle/ProgressCircle.base.js.map +1 -0
- package/dist/components/progress-circle/ProgressCircle.types.d.ts +15 -0
- package/dist/components/progress-circle/ProgressCircle.types.js +10 -0
- package/dist/components/progress-circle/ProgressCircle.types.js.map +1 -0
- package/dist/components/progress-circle/index.d.ts +13 -0
- package/dist/components/progress-circle/index.js +3 -0
- package/dist/components/status-light/StatusLight.base.d.ts +65 -0
- package/dist/components/status-light/StatusLight.base.js +29 -0
- package/dist/components/status-light/StatusLight.base.js.map +1 -0
- package/dist/components/status-light/StatusLight.types.d.ts +19 -0
- package/dist/components/status-light/StatusLight.types.js +32 -0
- package/dist/components/status-light/StatusLight.types.js.map +1 -0
- package/dist/components/status-light/index.d.ts +13 -0
- package/dist/components/status-light/index.js +3 -0
- package/dist/components/tabs/Tab.base.d.ts +49 -0
- package/dist/components/tabs/Tab.base.js +39 -0
- package/dist/components/tabs/Tab.base.js.map +1 -0
- package/dist/components/tabs/Tab.types.d.ts +17 -0
- package/dist/components/tabs/TabPanel.base.d.ts +49 -0
- package/dist/components/tabs/TabPanel.base.js +36 -0
- package/dist/components/tabs/TabPanel.base.js.map +1 -0
- package/dist/components/tabs/TabPanel.types.d.ts +17 -0
- package/dist/components/tabs/Tabs.base.d.ts +235 -0
- package/dist/components/tabs/Tabs.base.js +225 -0
- package/dist/components/tabs/Tabs.base.js.map +1 -0
- package/dist/components/tabs/Tabs.types.d.ts +55 -0
- package/dist/components/tabs/Tabs.types.js +6 -0
- package/dist/components/tabs/Tabs.types.js.map +1 -0
- package/dist/components/tabs/index.d.ts +17 -0
- package/dist/components/tabs/index.js +5 -0
- package/dist/components/tooltip/Tooltip.base.d.ts +154 -0
- package/dist/components/tooltip/Tooltip.base.js +163 -0
- package/dist/components/tooltip/Tooltip.base.js.map +1 -0
- package/dist/components/tooltip/Tooltip.types.d.ts +18 -0
- package/dist/components/tooltip/Tooltip.types.js +15 -0
- package/dist/components/tooltip/Tooltip.types.js.map +1 -0
- package/dist/components/tooltip/index.d.ts +13 -0
- package/dist/components/tooltip/index.js +3 -0
- package/dist/controllers/color-controller/index.d.ts +12 -0
- package/dist/controllers/color-controller/index.js +1 -0
- package/dist/controllers/color-controller/src/color-controller.d.ts +226 -0
- package/dist/controllers/color-controller/src/color-controller.js +252 -0
- package/dist/controllers/color-controller/src/color-controller.js.map +1 -0
- package/dist/controllers/focusgroup-navigation-controller/index.d.ts +12 -0
- package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.d.ts +477 -0
- package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.js +342 -0
- package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.js.map +1 -0
- package/dist/controllers/hover-controller/index.d.ts +12 -0
- package/dist/controllers/hover-controller/src/hover-controller.d.ts +118 -0
- package/dist/controllers/hover-controller/src/hover-controller.js +90 -0
- package/dist/controllers/hover-controller/src/hover-controller.js.map +1 -0
- package/dist/controllers/index.d.ts +20 -0
- package/dist/controllers/index.js +11 -0
- package/dist/controllers/language-resolution.d.ts +87 -0
- package/dist/controllers/language-resolution.js +56 -0
- package/dist/controllers/language-resolution.js.map +1 -0
- package/dist/controllers/page-scroll-lock.d.ts +20 -0
- package/dist/controllers/page-scroll-lock.js +30 -0
- package/dist/controllers/page-scroll-lock.js.map +1 -0
- package/dist/controllers/placement-controller/index.d.ts +12 -0
- package/dist/controllers/placement-controller/index.js +3 -0
- package/dist/controllers/placement-controller/src/fallback-placements.d.ts +9 -0
- package/dist/controllers/placement-controller/src/fallback-placements.js +71 -0
- package/dist/controllers/placement-controller/src/fallback-placements.js.map +1 -0
- package/dist/controllers/placement-controller/src/placement-controller.d.ts +152 -0
- package/dist/controllers/placement-controller/src/placement-controller.js +129 -0
- package/dist/controllers/placement-controller/src/placement-controller.js.map +1 -0
- package/dist/controllers/placement-controller/src/placement-conversion.d.ts +35 -0
- package/dist/controllers/placement-controller/src/placement-conversion.js +54 -0
- package/dist/controllers/placement-controller/src/placement-conversion.js.map +1 -0
- package/dist/controllers/placement-controller/src/types.d.ts +128 -0
- package/dist/controllers/placement-controller/src/types.js +29 -0
- package/dist/controllers/placement-controller/src/types.js.map +1 -0
- package/dist/controllers/slot-attribute-propagation/index.d.ts +12 -0
- package/dist/controllers/slot-attribute-propagation/src/slot-attribute-propagation-controller.d.ts +55 -0
- package/dist/controllers/slot-attribute-propagation/src/slot-attribute-propagation-controller.js +32 -0
- package/dist/controllers/slot-attribute-propagation/src/slot-attribute-propagation-controller.js.map +1 -0
- package/dist/element/define-element.d.ts +16 -0
- package/dist/element/define-element.js +8 -0
- package/dist/element/define-element.js.map +1 -0
- package/dist/element/index.d.ts +14 -0
- package/dist/element/index.js +4 -0
- package/dist/element/spectrum-element.d.ts +26 -0
- package/dist/element/spectrum-element.js +66 -0
- package/dist/element/spectrum-element.js.map +1 -0
- package/dist/element/version.d.ts +19 -0
- package/dist/element/version.js +6 -0
- package/dist/element/version.js.map +1 -0
- package/dist/mixins/disabled-mixin.d.ts +30 -0
- package/dist/mixins/disabled-mixin.js +27 -0
- package/dist/mixins/disabled-mixin.js.map +1 -0
- package/dist/mixins/index.d.ts +17 -0
- package/dist/mixins/index.js +6 -0
- package/dist/mixins/linear-progress-mixin.d.ts +42 -0
- package/dist/mixins/linear-progress-mixin.js +111 -0
- package/dist/mixins/linear-progress-mixin.js.map +1 -0
- package/dist/mixins/observe-slot-presence.d.ts +12 -0
- package/dist/mixins/observe-slot-presence.js +40 -0
- package/dist/mixins/observe-slot-presence.js.map +1 -0
- package/dist/mixins/observe-slot-text.d.ts +11 -0
- package/dist/mixins/observe-slot-text.js +60 -0
- package/dist/mixins/observe-slot-text.js.map +1 -0
- package/dist/mixins/sized-mixin.d.ts +21 -0
- package/dist/mixins/sized-mixin.js +42 -0
- package/dist/mixins/sized-mixin.js.map +1 -0
- package/dist/utils/actual-placement.d.ts +10 -0
- package/dist/utils/actual-placement.js +8 -0
- package/dist/utils/actual-placement.js.map +1 -0
- package/dist/utils/capitalize.d.ts +26 -0
- package/dist/utils/capitalize.js +8 -0
- package/dist/utils/capitalize.js.map +1 -0
- package/dist/utils/deep-contains.d.ts +26 -0
- package/dist/utils/deep-contains.js +14 -0
- package/dist/utils/deep-contains.js.map +1 -0
- package/dist/utils/dismissible-stack.d.ts +26 -0
- package/dist/utils/dismissible-stack.js +16 -0
- package/dist/utils/dismissible-stack.js.map +1 -0
- package/dist/utils/focusable-selectors.d.ts +43 -0
- package/dist/utils/focusable-selectors.js +18 -0
- package/dist/utils/focusable-selectors.js.map +1 -0
- package/dist/utils/get-active-element.d.ts +31 -0
- package/dist/utils/get-active-element.js +11 -0
- package/dist/utils/get-active-element.js.map +1 -0
- package/dist/utils/get-label-from-slot.d.ts +12 -0
- package/dist/utils/get-label-from-slot.js +10 -0
- package/dist/utils/get-label-from-slot.js.map +1 -0
- package/dist/utils/index.d.ts +20 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/resolve-trigger.d.ts +42 -0
- package/dist/utils/resolve-trigger.js +23 -0
- package/dist/utils/resolve-trigger.js.map +1 -0
- package/dist/utils/transition.d.ts +53 -0
- package/dist/utils/transition.js +26 -0
- package/dist/utils/transition.js.map +1 -0
- package/package.json +400 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { PropertyValues } from 'lit';
|
|
2
|
+
import { SpectrumElement } from '../../element/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Base class for a tab panel that displays content associated with
|
|
5
|
+
* a tab.
|
|
6
|
+
*
|
|
7
|
+
* Manages visibility, ARIA hidden state, tabindex, and the
|
|
8
|
+
* focus-in/out behavior that prevents Tab-key trapping inside panel
|
|
9
|
+
* content.
|
|
10
|
+
*
|
|
11
|
+
* In 1st-gen, `slot="tab-panel"` was
|
|
12
|
+
* assigned programmatically in `firstUpdated` so consumers never
|
|
13
|
+
* wrote it in markup. This behavior is preserved in 2nd-gen.
|
|
14
|
+
*
|
|
15
|
+
* The panel removes its own
|
|
16
|
+
* `tabindex` on `focusin` so that Tab presses inside the panel
|
|
17
|
+
* move to the next interactive element rather than being trapped.
|
|
18
|
+
* On `focusout`, `tabindex` is restored so the panel remains
|
|
19
|
+
* focusable from the tablist.
|
|
20
|
+
*
|
|
21
|
+
* @slot - Content displayed when the associated tab is selected
|
|
22
|
+
*/
|
|
23
|
+
export declare abstract class TabPanelBase extends SpectrumElement {
|
|
24
|
+
/**
|
|
25
|
+
* Whether this panel is currently visible (its associated tab is
|
|
26
|
+
* selected). Managed by the parent `swc-tabs` — consumers should
|
|
27
|
+
* not set this directly.
|
|
28
|
+
*/
|
|
29
|
+
selected: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Unique identifier linking this panel to its corresponding tab.
|
|
32
|
+
* Must match the `tab-id` attribute on the associated `swc-tab`.
|
|
33
|
+
*/
|
|
34
|
+
tabId: string;
|
|
35
|
+
/**
|
|
36
|
+
* Removes the panel's `tabindex` while focus is inside the panel
|
|
37
|
+
* so that Tab presses navigate to the next interactive element
|
|
38
|
+
* rather than the panel container itself.
|
|
39
|
+
*/
|
|
40
|
+
protected handleFocusin(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Restores `tabindex` when focus leaves the panel so the panel
|
|
43
|
+
* remains directly focusable from the tablist via Tab key.
|
|
44
|
+
*/
|
|
45
|
+
protected handleFocusout(): void;
|
|
46
|
+
protected firstUpdated(_changes: PropertyValues): void;
|
|
47
|
+
protected updated(changes: PropertyValues): void;
|
|
48
|
+
private syncVisibility;
|
|
49
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { __decorate as e } from "../../_virtual/_@oxc-project_runtime@0.124.0/helpers/decorate.js";
|
|
2
|
+
import { property as t } from "lit/decorators.js";
|
|
3
|
+
import { SpectrumElement as n } from "@adobe/spectrum-wc-core/element/index.js";
|
|
4
|
+
//#region components/tabs/TabPanel.base.ts
|
|
5
|
+
var r = 0, i = class extends n {
|
|
6
|
+
constructor(...e) {
|
|
7
|
+
super(...e), this.selected = !1, this.tabId = "";
|
|
8
|
+
}
|
|
9
|
+
handleFocusin() {
|
|
10
|
+
this.removeAttribute("tabindex");
|
|
11
|
+
}
|
|
12
|
+
handleFocusout() {
|
|
13
|
+
this.tabIndex = this.selected ? 0 : -1;
|
|
14
|
+
}
|
|
15
|
+
firstUpdated(e) {
|
|
16
|
+
super.firstUpdated(e), this.slot = "tab-panel", this.setAttribute("role", "tabpanel"), this.tabIndex = 0, this.hasAttribute("id") || (this.id = `swc-tab-panel-${r++}`);
|
|
17
|
+
}
|
|
18
|
+
updated(e) {
|
|
19
|
+
super.updated(e), e.has("selected") && this.syncVisibility();
|
|
20
|
+
}
|
|
21
|
+
syncVisibility() {
|
|
22
|
+
this.selected ? (this.removeAttribute("aria-hidden"), this.tabIndex = 0) : (this.setAttribute("aria-hidden", "true"), this.tabIndex = -1);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
e([t({
|
|
26
|
+
type: Boolean,
|
|
27
|
+
reflect: !0
|
|
28
|
+
})], i.prototype, "selected", void 0), e([t({
|
|
29
|
+
type: String,
|
|
30
|
+
reflect: !0,
|
|
31
|
+
attribute: "tab-id"
|
|
32
|
+
})], i.prototype, "tabId", void 0);
|
|
33
|
+
//#endregion
|
|
34
|
+
export { i as TabPanelBase };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=TabPanel.base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabPanel.base.js","names":[],"sources":["../../../components/tabs/TabPanel.base.ts"],"sourcesContent":["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nimport { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\n\nlet panelIdCounter = 0;\n\n/**\n * Base class for a tab panel that displays content associated with\n * a tab.\n *\n * Manages visibility, ARIA hidden state, tabindex, and the\n * focus-in/out behavior that prevents Tab-key trapping inside panel\n * content.\n *\n * In 1st-gen, `slot=\"tab-panel\"` was\n * assigned programmatically in `firstUpdated` so consumers never\n * wrote it in markup. This behavior is preserved in 2nd-gen.\n *\n * The panel removes its own\n * `tabindex` on `focusin` so that Tab presses inside the panel\n * move to the next interactive element rather than being trapped.\n * On `focusout`, `tabindex` is restored so the panel remains\n * focusable from the tablist.\n *\n * @slot - Content displayed when the associated tab is selected\n */\nexport abstract class TabPanelBase extends SpectrumElement {\n // ──────────────────\n // SHARED API\n // ──────────────────\n\n /**\n * Whether this panel is currently visible (its associated tab is\n * selected). Managed by the parent `swc-tabs` — consumers should\n * not set this directly.\n */\n @property({ type: Boolean, reflect: true })\n public selected = false;\n\n /**\n * Unique identifier linking this panel to its corresponding tab.\n * Must match the `tab-id` attribute on the associated `swc-tab`.\n */\n @property({ type: String, reflect: true, attribute: 'tab-id' })\n public tabId = '';\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n /**\n * Removes the panel's `tabindex` while focus is inside the panel\n * so that Tab presses navigate to the next interactive element\n * rather than the panel container itself.\n */\n protected handleFocusin(): void {\n this.removeAttribute('tabindex');\n }\n\n /**\n * Restores `tabindex` when focus leaves the panel so the panel\n * remains directly focusable from the tablist via Tab key.\n */\n protected handleFocusout(): void {\n this.tabIndex = this.selected ? 0 : -1;\n }\n\n protected override firstUpdated(_changes: PropertyValues): void {\n super.firstUpdated(_changes);\n\n this.slot = 'tab-panel';\n this.setAttribute('role', 'tabpanel');\n this.tabIndex = 0;\n\n if (!this.hasAttribute('id')) {\n this.id = `swc-tab-panel-${panelIdCounter++}`;\n }\n }\n\n protected override updated(changes: PropertyValues): void {\n super.updated(changes);\n\n if (changes.has('selected')) {\n this.syncVisibility();\n }\n }\n\n private syncVisibility(): void {\n if (this.selected) {\n this.removeAttribute('aria-hidden');\n this.tabIndex = 0;\n } else {\n this.setAttribute('aria-hidden', 'true');\n this.tabIndex = -1;\n }\n }\n}\n"],"mappings":";;;;AAgBA,IAAI,IAAiB,GAsBC,IAAtB,cAA2C,EAAgB;;+BAWvC,iBAOH;;CAWf,gBAAgC;AAC9B,OAAK,gBAAgB,WAAW;;CAOlC,iBAAiC;AAC/B,OAAK,WAAW,KAAK,WAAW,IAAI;;CAGtC,aAAgC,GAAgC;AAO9D,EANA,MAAM,aAAa,EAAS,EAE5B,KAAK,OAAO,aACZ,KAAK,aAAa,QAAQ,WAAW,EACrC,KAAK,WAAW,GAEX,KAAK,aAAa,KAAK,KAC1B,KAAK,KAAK,iBAAiB;;CAI/B,QAA2B,GAA+B;AAGxD,EAFA,MAAM,QAAQ,EAAQ,EAElB,EAAQ,IAAI,WAAW,IACzB,KAAK,gBAAgB;;CAIzB,iBAA+B;AAC7B,EAAI,KAAK,YACP,KAAK,gBAAgB,cAAc,EACnC,KAAK,WAAW,MAEhB,KAAK,aAAa,eAAe,OAAO,EACxC,KAAK,WAAW;;;GAzDnB,EAAS;CAAE,MAAM;CAAS,SAAS;CAAM,CAAC,CAAA,EAAA,EAAA,WAAA,YAAA,KAAA,EAAA,KAO1C,EAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,WAAW;CAAU,CAAC,CAAA,EAAA,EAAA,WAAA,SAAA,KAAA,EAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Reserved for future tab-panel-specific type definitions.
|
|
14
|
+
* The file is scaffolded now so imports are stable when implementation
|
|
15
|
+
* work begins.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { PropertyValues } from 'lit';
|
|
2
|
+
import { SpectrumElement } from '../../element/index.js';
|
|
3
|
+
import { KeyboardActivation, TabDensity, TabsDirection } from './Tabs.types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Base class for a tabbed interface container.
|
|
6
|
+
*
|
|
7
|
+
* Manages selection state, tab/panel association, ARIA wiring,
|
|
8
|
+
* keyboard navigation, and event dispatching. Concrete classes
|
|
9
|
+
* supply the stylesheet, render template, and visual behaviors
|
|
10
|
+
* such as the selection indicator.
|
|
11
|
+
*
|
|
12
|
+
* Public API follows the Spectrum 2 / Spectrum Design–aligned surface
|
|
13
|
+
* from the tabs migration plan: `keyboard-activation` and `density`
|
|
14
|
+
* instead of legacy `auto`, `compact`, `quiet`, `emphasized`, and
|
|
15
|
+
* t-shirt `size` attributes.
|
|
16
|
+
*
|
|
17
|
+
* @slot - Tab items (elements with `role="tab"`)
|
|
18
|
+
* @slot tab-panel - Tab panel content (elements with `role="tabpanel"`)
|
|
19
|
+
*
|
|
20
|
+
* @fires change - The selected tab has changed. Cancelable —
|
|
21
|
+
* calling `preventDefault()` reverts the selection.
|
|
22
|
+
*/
|
|
23
|
+
export declare abstract class TabsBase extends SpectrumElement {
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*
|
|
27
|
+
* Valid direction values for validation and CEM/stories.
|
|
28
|
+
*/
|
|
29
|
+
static readonly VALID_DIRECTIONS: readonly TabsDirection[];
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
static readonly VALID_KEYBOARD_ACTIVATIONS: readonly KeyboardActivation[];
|
|
34
|
+
/**
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
static readonly VALID_DENSITIES: readonly TabDensity[];
|
|
38
|
+
/**
|
|
39
|
+
* Whether selection follows keyboard focus (`automatic`, default) or the
|
|
40
|
+
* user must press Enter or Space to activate (`manual`). Prefer `manual`
|
|
41
|
+
* when tab panels are expensive to render or not fully present in the DOM.
|
|
42
|
+
*
|
|
43
|
+
* @see https://w3c.github.io/aria-practices/#kbd_selection_follows_focus
|
|
44
|
+
*/
|
|
45
|
+
get keyboardActivation(): KeyboardActivation;
|
|
46
|
+
set keyboardActivation(value: string);
|
|
47
|
+
/** @internal */
|
|
48
|
+
private _keyboardActivation;
|
|
49
|
+
/**
|
|
50
|
+
* Layout density: `regular` (default) or `compact` (reduced tab spacing).
|
|
51
|
+
*/
|
|
52
|
+
get density(): TabDensity;
|
|
53
|
+
set density(value: string);
|
|
54
|
+
/** @internal */
|
|
55
|
+
private _density;
|
|
56
|
+
/**
|
|
57
|
+
* The layout direction of the tab list.
|
|
58
|
+
*
|
|
59
|
+
* **Breaking change:** `'vertical-right'` is no longer supported.
|
|
60
|
+
* Use `'vertical'` instead.
|
|
61
|
+
*
|
|
62
|
+
* @default 'horizontal'
|
|
63
|
+
*/
|
|
64
|
+
get direction(): TabsDirection;
|
|
65
|
+
set direction(value: TabsDirection);
|
|
66
|
+
/** @internal */
|
|
67
|
+
private _direction;
|
|
68
|
+
/**
|
|
69
|
+
* Whether the entire tab list is disabled. When `true`,
|
|
70
|
+
* `aria-disabled="true"` is applied to the tablist element and
|
|
71
|
+
* all interaction is suppressed.
|
|
72
|
+
*/
|
|
73
|
+
disabled: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Accessible label for the tablist. Rendered as `aria-label` on the
|
|
76
|
+
* element with `role="tablist"` in the concrete template.
|
|
77
|
+
*/
|
|
78
|
+
accessibleLabel: string;
|
|
79
|
+
/**
|
|
80
|
+
* The `tab-id` of the currently selected tab. Setting this property
|
|
81
|
+
* updates which tab appears selected and which panel is visible.
|
|
82
|
+
*/
|
|
83
|
+
selected: string;
|
|
84
|
+
/** @internal */
|
|
85
|
+
private static readonly INDICATOR_BASE_SIZE;
|
|
86
|
+
/**
|
|
87
|
+
* @internal
|
|
88
|
+
*
|
|
89
|
+
* Inline style applied to the selection indicator element.
|
|
90
|
+
* Computed from the selected tab's position and dimensions.
|
|
91
|
+
*/
|
|
92
|
+
protected selectionIndicatorStyle: string;
|
|
93
|
+
/**
|
|
94
|
+
* @internal
|
|
95
|
+
*
|
|
96
|
+
* Suppresses the transition on the very first indicator placement
|
|
97
|
+
* so it doesn't animate from the origin.
|
|
98
|
+
*/
|
|
99
|
+
protected shouldAnimate: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* @internal
|
|
102
|
+
*
|
|
103
|
+
* Cached list of tab elements managed by this container. Updated
|
|
104
|
+
* via `handleTabSlotChange`.
|
|
105
|
+
*/
|
|
106
|
+
private _tabs;
|
|
107
|
+
/**
|
|
108
|
+
* Whether an assigned node is treated as a tab. `role="tab"` is set in
|
|
109
|
+
* each tab's `firstUpdated`, so `slotchange` may run before that — accept
|
|
110
|
+
* known tab host tag names so the tab list and selection indicator sync.
|
|
111
|
+
*/
|
|
112
|
+
private static isTabSlotNode;
|
|
113
|
+
/**
|
|
114
|
+
* Called by the concrete class when the default slot's content
|
|
115
|
+
* changes. Rebuilds the internal tab list and syncs selection
|
|
116
|
+
* state.
|
|
117
|
+
*/
|
|
118
|
+
protected handleTabSlotChange(event: Event): void;
|
|
119
|
+
/**
|
|
120
|
+
* Called by the concrete class when the `tab-panel` slot's content
|
|
121
|
+
* changes. Wires up `aria-controls` / `aria-labelledby` between
|
|
122
|
+
* each tab and its panel.
|
|
123
|
+
*/
|
|
124
|
+
protected handlePanelSlotChange(event: Event): void;
|
|
125
|
+
/**
|
|
126
|
+
* Click handler bound to the tablist wrapper in the concrete
|
|
127
|
+
* template. Activates the clicked tab.
|
|
128
|
+
*/
|
|
129
|
+
protected handleClick(event: Event): void;
|
|
130
|
+
/**
|
|
131
|
+
* Full keyboard handler per WAI-ARIA APG Tabs pattern.
|
|
132
|
+
*
|
|
133
|
+
* **Horizontal:** Left/Right navigate; Up/Down ignored.
|
|
134
|
+
* **Vertical:** Up/Down navigate; Left/Right ignored.
|
|
135
|
+
* **RTL:** Left/Right swap in `dir="rtl"`.
|
|
136
|
+
* **Wrapping:** Navigation wraps from last to first and vice versa.
|
|
137
|
+
* **Disabled tabs:** Disabled tabs receive focus via arrows but
|
|
138
|
+
* are not activatable by Enter/Space.
|
|
139
|
+
* **Automatic activation:** When `keyboard-activation` is `automatic`,
|
|
140
|
+
* selection follows focus on arrow key navigation.
|
|
141
|
+
* **Home/End:** Jump to first/last tab.
|
|
142
|
+
*/
|
|
143
|
+
protected handleKeyDown(event: KeyboardEvent): void;
|
|
144
|
+
/**
|
|
145
|
+
* Maps a keyboard code to a navigation delta (+1 or -1) based
|
|
146
|
+
* on orientation and text direction. Returns `null` when the key
|
|
147
|
+
* does not apply to the current orientation.
|
|
148
|
+
*/
|
|
149
|
+
private getNavigationDelta;
|
|
150
|
+
/**
|
|
151
|
+
* Moves focus by `delta` positions from the currently focused tab,
|
|
152
|
+
* wrapping around the list. All tabs (including disabled) receive
|
|
153
|
+
* focus per APG. In automatic activation mode, the newly focused tab
|
|
154
|
+
* is also selected.
|
|
155
|
+
*/
|
|
156
|
+
private focusByDelta;
|
|
157
|
+
/**
|
|
158
|
+
* Focuses the tab at the given index and, when in automatic
|
|
159
|
+
* activation mode, also selects it. Selection runs before `focus()`
|
|
160
|
+
* so `change` listeners observe the updated value before focus moves.
|
|
161
|
+
*/
|
|
162
|
+
private focusTabAtIndex;
|
|
163
|
+
/**
|
|
164
|
+
* Wraps an index into the valid range `[0, tabs.length)`.
|
|
165
|
+
*/
|
|
166
|
+
private wrapIndex;
|
|
167
|
+
/**
|
|
168
|
+
* Updates roving tabindex so only the given tab has
|
|
169
|
+
* `tabindex="0"` and all others have `tabindex="-1"`.
|
|
170
|
+
*/
|
|
171
|
+
private setRovingTabindex;
|
|
172
|
+
/**
|
|
173
|
+
* Attempts to select the given tab element. Dispatches a cancelable
|
|
174
|
+
* `change` event — if the consumer calls `preventDefault()`, the
|
|
175
|
+
* selection reverts to the previous value.
|
|
176
|
+
*/
|
|
177
|
+
private selectTarget;
|
|
178
|
+
/**
|
|
179
|
+
* Synchronizes the `selected` attribute and roving tabindex on
|
|
180
|
+
* each child tab to match the container's `selected` value.
|
|
181
|
+
* Ensures at least one tab has `tabindex="0"` for Tab-key entry
|
|
182
|
+
* when the container is not disabled. When the container is
|
|
183
|
+
* disabled, all tabs get `tabindex="-1"` to prevent Tab-key
|
|
184
|
+
* entry into the tab list.
|
|
185
|
+
*/
|
|
186
|
+
private updateCheckedState;
|
|
187
|
+
/**
|
|
188
|
+
* Wires up cross-element ARIA relationships between tabs and
|
|
189
|
+
* panels. Each tab gets `aria-controls` pointing at its panel's
|
|
190
|
+
* `id`, and each panel gets `aria-labelledby` pointing at its
|
|
191
|
+
* tab's `id`.
|
|
192
|
+
*/
|
|
193
|
+
private managePanels;
|
|
194
|
+
/**
|
|
195
|
+
* @internal
|
|
196
|
+
*
|
|
197
|
+
* Recalculates the selection indicator's position and size based
|
|
198
|
+
* on the currently selected tab element. Uses CSS transforms for
|
|
199
|
+
* smooth animation between tab positions.
|
|
200
|
+
*
|
|
201
|
+
* The indicator is a fixed-size element (100px base) that gets
|
|
202
|
+
* `scaleX`/`scaleY` to match the selected tab's width/height,
|
|
203
|
+
* and `translateX`/`translateY` to match its offset position.
|
|
204
|
+
*/
|
|
205
|
+
protected updateSelectionIndicator: () => Promise<void>;
|
|
206
|
+
/** @internal */
|
|
207
|
+
private _resizeObserver?;
|
|
208
|
+
/**
|
|
209
|
+
* @internal
|
|
210
|
+
*
|
|
211
|
+
* Watches for `dir` attribute changes so the indicator recalculates
|
|
212
|
+
* when writing direction flips at runtime. `getComputedStyle` in
|
|
213
|
+
* `updateSelectionIndicator` resolves inherited direction correctly,
|
|
214
|
+
* but nothing else observes it: a `dir` flip on the document root or
|
|
215
|
+
* an ancestor doesn't resize this element, so the `ResizeObserver`
|
|
216
|
+
* below won't catch it. Mirrors the `dir`-watching pattern in
|
|
217
|
+
* `placement-controller.ts`.
|
|
218
|
+
*/
|
|
219
|
+
private _directionObserver?;
|
|
220
|
+
protected willUpdate(changes: PropertyValues): void;
|
|
221
|
+
connectedCallback(): void;
|
|
222
|
+
disconnectedCallback(): void;
|
|
223
|
+
/**
|
|
224
|
+
* Focuses the selected tab, or the first tab when none is selected yet.
|
|
225
|
+
* Slotted tabs live in the light DOM; this is more reliable than relying
|
|
226
|
+
* only on shadow `delegatesFocus` across browsers and test harnesses.
|
|
227
|
+
*/
|
|
228
|
+
focus(options?: FocusOptions): void;
|
|
229
|
+
protected firstUpdated(changes: PropertyValues): void;
|
|
230
|
+
/**
|
|
231
|
+
* Waits for all child tab elements to finish their update cycle
|
|
232
|
+
* before resolving so layout-dependent callers see stable geometry.
|
|
233
|
+
*/
|
|
234
|
+
getUpdateComplete(): Promise<boolean>;
|
|
235
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { __decorate as e } from "../../_virtual/_@oxc-project_runtime@0.124.0/helpers/decorate.js";
|
|
2
|
+
import { KEYBOARD_ACTIVATIONS as t, KEYBOARD_ACTIVATION_DEFAULT as n, TABS_DEFAULT_DIRECTION as r, TABS_DIRECTIONS as i, TAB_DENSITIES as a, TAB_DENSITY_DEFAULT as o } from "./Tabs.types.js";
|
|
3
|
+
import { property as s, state as c } from "lit/decorators.js";
|
|
4
|
+
import { SpectrumElement as l } from "@adobe/spectrum-wc-core/element/index.js";
|
|
5
|
+
//#region components/tabs/Tabs.base.ts
|
|
6
|
+
var u, d = class e extends l {
|
|
7
|
+
constructor(...t) {
|
|
8
|
+
super(...t), this._keyboardActivation = n, this._density = o, this._direction = r, this.disabled = !1, this.accessibleLabel = "", this.selected = "", this.selectionIndicatorStyle = "", this.shouldAnimate = !1, this._tabs = [], this.updateSelectionIndicator = async () => {
|
|
9
|
+
var t, n;
|
|
10
|
+
let r = this._tabs.find((e) => e.selected);
|
|
11
|
+
if (!r) {
|
|
12
|
+
this.selectionIndicatorStyle = "transform: translateX(0px) scaleX(0) scaleY(0)";
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let i = (t = this.renderRoot) == null ? void 0 : t.querySelector(".tablist");
|
|
16
|
+
if (!i) return;
|
|
17
|
+
await Promise.all([(n = r.updateComplete) == null ? Promise.resolve() : n, document.fonts ? document.fonts.ready : Promise.resolve()]);
|
|
18
|
+
let a = r.getBoundingClientRect(), o = i.getBoundingClientRect();
|
|
19
|
+
this._direction === "horizontal" ? this.selectionIndicatorStyle = `transform: translateX(${getComputedStyle(this).direction === "rtl" ? a.right - o.right : a.left - o.left}px) scaleX(${a.width / e.INDICATOR_BASE_SIZE})` : this.selectionIndicatorStyle = `transform: translateY(${a.top - o.top}px) scaleY(${a.height / e.INDICATOR_BASE_SIZE})`, this.shouldAnimate || (await this.updateComplete, this.shouldAnimate = !0);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
get keyboardActivation() {
|
|
23
|
+
return this._keyboardActivation;
|
|
24
|
+
}
|
|
25
|
+
set keyboardActivation(e) {
|
|
26
|
+
var r;
|
|
27
|
+
let i = t.includes(e);
|
|
28
|
+
!i && (r = window.__swc) != null && r.DEBUG && window.__swc.warn(this, `<${this.localName}> expects "keyboard-activation" to be one of:`, "https://opensource.adobe.com/spectrum-web-components/components/tabs/", { issues: [...t] });
|
|
29
|
+
let a = i ? e : n;
|
|
30
|
+
if (this._keyboardActivation === a) return;
|
|
31
|
+
let o = this._keyboardActivation;
|
|
32
|
+
this._keyboardActivation = a, this.requestUpdate("keyboardActivation", o);
|
|
33
|
+
}
|
|
34
|
+
get density() {
|
|
35
|
+
return this._density;
|
|
36
|
+
}
|
|
37
|
+
set density(e) {
|
|
38
|
+
var t;
|
|
39
|
+
let n = a.includes(e);
|
|
40
|
+
!n && (t = window.__swc) != null && t.DEBUG && window.__swc.warn(this, `<${this.localName}> expects "density" to be one of:`, "https://opensource.adobe.com/spectrum-web-components/components/tabs/", { issues: [...a] });
|
|
41
|
+
let r = n ? e : o;
|
|
42
|
+
if (this._density === r) return;
|
|
43
|
+
let i = this._density;
|
|
44
|
+
this._density = r, this.requestUpdate("density", i);
|
|
45
|
+
}
|
|
46
|
+
get direction() {
|
|
47
|
+
return this._direction;
|
|
48
|
+
}
|
|
49
|
+
set direction(e) {
|
|
50
|
+
var t;
|
|
51
|
+
let n = i.includes(e);
|
|
52
|
+
!n && (t = window.__swc) != null && t.DEBUG && window.__swc.warn(this, `<${this.localName}> expects the "direction" attribute to be one of the following:`, "https://opensource.adobe.com/spectrum-web-components/components/tabs/", { issues: [...i] });
|
|
53
|
+
let a = n ? e : r;
|
|
54
|
+
if (this._direction === a) return;
|
|
55
|
+
let o = this._direction;
|
|
56
|
+
this._direction = a, this.requestUpdate("direction", o);
|
|
57
|
+
}
|
|
58
|
+
static isTabSlotNode(e) {
|
|
59
|
+
return e instanceof HTMLElement ? e.getAttribute("role") === "tab" ? !0 : e.localName === "swc-tab" : !1;
|
|
60
|
+
}
|
|
61
|
+
handleTabSlotChange(t) {
|
|
62
|
+
this._tabs = t.target.assignedElements().filter(e.isTabSlotNode), this.updateCheckedState(), this.updateSelectionIndicator();
|
|
63
|
+
}
|
|
64
|
+
handlePanelSlotChange(e) {
|
|
65
|
+
let t = e.target.assignedElements();
|
|
66
|
+
this.managePanels(t);
|
|
67
|
+
}
|
|
68
|
+
handleClick(e) {
|
|
69
|
+
if (this.disabled) return;
|
|
70
|
+
let t = e.composedPath().find((e) => e.parentElement === this);
|
|
71
|
+
!t || t.disabled || this.selectTarget(t);
|
|
72
|
+
}
|
|
73
|
+
handleKeyDown(e) {
|
|
74
|
+
if (this.disabled) return;
|
|
75
|
+
let { code: t } = e;
|
|
76
|
+
if (t === "Enter" || t === "Space") {
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
let t = e.target;
|
|
79
|
+
t && !t.disabled && this.selectTarget(t);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
let n = this.getNavigationDelta(t);
|
|
83
|
+
if (n !== null) {
|
|
84
|
+
e.preventDefault(), this.focusByDelta(n);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (t === "Home") {
|
|
88
|
+
e.preventDefault(), this.focusTabAtIndex(0);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (t === "End") {
|
|
92
|
+
e.preventDefault(), this.focusTabAtIndex(this._tabs.length - 1);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
getNavigationDelta(e) {
|
|
97
|
+
let t = this.dir === "rtl";
|
|
98
|
+
return this._direction === "horizontal" ? e === "ArrowRight" ? t ? -1 : 1 : e === "ArrowLeft" ? t ? 1 : -1 : null : e === "ArrowDown" ? 1 : e === "ArrowUp" ? -1 : null;
|
|
99
|
+
}
|
|
100
|
+
focusByDelta(e) {
|
|
101
|
+
if (!this._tabs.length) return;
|
|
102
|
+
let t = this.getRootNode(), n = this._tabs.indexOf(t.activeElement), r = n === -1 ? 0 : n, i = this.wrapIndex(r + e);
|
|
103
|
+
this.focusTabAtIndex(i);
|
|
104
|
+
}
|
|
105
|
+
focusTabAtIndex(e) {
|
|
106
|
+
if (!this._tabs.length) return;
|
|
107
|
+
let t = this.wrapIndex(e), n = this._tabs[t];
|
|
108
|
+
n && (this._keyboardActivation === "automatic" && !n.disabled && this.selectTarget(n), this.setRovingTabindex(n), n.focus());
|
|
109
|
+
}
|
|
110
|
+
wrapIndex(e) {
|
|
111
|
+
let t = this._tabs.length;
|
|
112
|
+
return (e % t + t) % t;
|
|
113
|
+
}
|
|
114
|
+
setRovingTabindex(e) {
|
|
115
|
+
for (let t of this._tabs) t.tabIndex = t === e ? 0 : -1;
|
|
116
|
+
}
|
|
117
|
+
selectTarget(e) {
|
|
118
|
+
let t = e.tabId;
|
|
119
|
+
if (!t) return;
|
|
120
|
+
let n = this.selected;
|
|
121
|
+
this.selected = t, this.dispatchEvent(new Event("change", { cancelable: !0 })) || (this.selected = n);
|
|
122
|
+
}
|
|
123
|
+
updateCheckedState() {
|
|
124
|
+
let e = !1;
|
|
125
|
+
for (let e of this._tabs) e.selected = !1;
|
|
126
|
+
if (this.selected) {
|
|
127
|
+
let t = this._tabs.find((e) => e.tabId === this.selected);
|
|
128
|
+
t ? (t.selected = !0, this.disabled || (this.setRovingTabindex(t), e = !0)) : this.selected = "";
|
|
129
|
+
}
|
|
130
|
+
if (this.disabled) for (let e of this._tabs) e.tabIndex = -1;
|
|
131
|
+
else !e && this._tabs.length && (this._tabs[0].tabIndex = 0);
|
|
132
|
+
}
|
|
133
|
+
managePanels(e) {
|
|
134
|
+
for (let t of e) {
|
|
135
|
+
let { tabId: e, id: n } = t, r = this.querySelector(`[role="tab"][tab-id="${e}"]`);
|
|
136
|
+
r && (r.setAttribute("aria-controls", n), t.setAttribute("aria-labelledby", r.id)), t.selected = e === this.selected;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
willUpdate(e) {
|
|
140
|
+
if (!this.hasUpdated) {
|
|
141
|
+
let e = this.querySelector(":scope > [selected]");
|
|
142
|
+
e && this.selectTarget(e);
|
|
143
|
+
}
|
|
144
|
+
if (super.willUpdate(e), e.has("selected")) {
|
|
145
|
+
this._tabs.length && this.updateCheckedState();
|
|
146
|
+
let t = e.get("selected");
|
|
147
|
+
if (t) {
|
|
148
|
+
let e = this.querySelector(`[role="tabpanel"][tab-id="${t}"]`);
|
|
149
|
+
e && (e.selected = !1);
|
|
150
|
+
}
|
|
151
|
+
let n = this.querySelector(`[role="tabpanel"][tab-id="${this.selected}"]`);
|
|
152
|
+
n && (n.selected = !0), this.updateSelectionIndicator();
|
|
153
|
+
}
|
|
154
|
+
e.has("disabled") && this._tabs.length && this.updateCheckedState(), e.has("direction") && this.updateSelectionIndicator();
|
|
155
|
+
}
|
|
156
|
+
connectedCallback() {
|
|
157
|
+
super.connectedCallback(), window.addEventListener("resize", this.updateSelectionIndicator), "fonts" in document && document.fonts.addEventListener("loadingdone", this.updateSelectionIndicator), this._resizeObserver = new ResizeObserver(() => {
|
|
158
|
+
this.updateSelectionIndicator();
|
|
159
|
+
}), this._resizeObserver.observe(this), this._directionObserver = new MutationObserver(() => {
|
|
160
|
+
this.updateSelectionIndicator();
|
|
161
|
+
});
|
|
162
|
+
let e = (e) => {
|
|
163
|
+
if (e) {
|
|
164
|
+
var t;
|
|
165
|
+
(t = this._directionObserver) == null || t.observe(e, {
|
|
166
|
+
attributes: !0,
|
|
167
|
+
attributeFilter: ["dir"]
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
e(this.ownerDocument.documentElement), e(this.closest("[dir]"));
|
|
172
|
+
}
|
|
173
|
+
disconnectedCallback() {
|
|
174
|
+
var e, t;
|
|
175
|
+
window.removeEventListener("resize", this.updateSelectionIndicator), "fonts" in document && document.fonts.removeEventListener("loadingdone", this.updateSelectionIndicator), (e = this._resizeObserver) == null || e.disconnect(), this._resizeObserver = void 0, (t = this._directionObserver) == null || t.disconnect(), this._directionObserver = void 0, super.disconnectedCallback();
|
|
176
|
+
}
|
|
177
|
+
focus(e) {
|
|
178
|
+
if (this.disabled) return;
|
|
179
|
+
let t = this._tabs.find((e) => e.selected);
|
|
180
|
+
if (t) {
|
|
181
|
+
t.focus(e);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (this._tabs.length) {
|
|
185
|
+
this._tabs[0].focus(e);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
super.focus(e);
|
|
189
|
+
}
|
|
190
|
+
firstUpdated(e) {
|
|
191
|
+
var t;
|
|
192
|
+
super.firstUpdated(e), this.hasAttribute("direction") || this.setAttribute("direction", this.direction), (t = window.__swc) != null && t.DEBUG && !this.accessibleLabel && window.__swc.warn(this, `<${this.localName}> requires an "accessible-label" attribute to provide an accessible name for the tablist.`, "https://opensource.adobe.com/spectrum-web-components/components/tabs/", {
|
|
193
|
+
type: "accessibility",
|
|
194
|
+
level: "high"
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
async getUpdateComplete() {
|
|
198
|
+
let e = await super.getUpdateComplete(), t = [...this.children].map((e) => "updateComplete" in e ? e.updateComplete : Promise.resolve(!0));
|
|
199
|
+
return await Promise.all(t), e;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
u = d, u.VALID_DIRECTIONS = i, u.VALID_KEYBOARD_ACTIVATIONS = t, u.VALID_DENSITIES = a, u.INDICATOR_BASE_SIZE = 100, e([s({
|
|
203
|
+
type: String,
|
|
204
|
+
reflect: !0,
|
|
205
|
+
attribute: "keyboard-activation"
|
|
206
|
+
})], d.prototype, "keyboardActivation", null), e([s({
|
|
207
|
+
type: String,
|
|
208
|
+
reflect: !0
|
|
209
|
+
})], d.prototype, "density", null), e([s({
|
|
210
|
+
type: String,
|
|
211
|
+
reflect: !0
|
|
212
|
+
})], d.prototype, "direction", null), e([s({
|
|
213
|
+
type: Boolean,
|
|
214
|
+
reflect: !0
|
|
215
|
+
})], d.prototype, "disabled", void 0), e([s({
|
|
216
|
+
type: String,
|
|
217
|
+
attribute: "accessible-label"
|
|
218
|
+
})], d.prototype, "accessibleLabel", void 0), e([s({
|
|
219
|
+
type: String,
|
|
220
|
+
reflect: !0
|
|
221
|
+
})], d.prototype, "selected", void 0), e([c()], d.prototype, "selectionIndicatorStyle", void 0), e([c()], d.prototype, "shouldAnimate", void 0);
|
|
222
|
+
//#endregion
|
|
223
|
+
export { d as TabsBase };
|
|
224
|
+
|
|
225
|
+
//# sourceMappingURL=Tabs.base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.base.js","names":[],"sources":["../../../components/tabs/Tabs.base.ts"],"sourcesContent":["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nimport { PropertyValues } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\n\nimport {\n KEYBOARD_ACTIVATION_DEFAULT,\n KEYBOARD_ACTIVATIONS,\n type KeyboardActivation,\n TAB_DENSITIES,\n TAB_DENSITY_DEFAULT,\n type TabDensity,\n type TabLike,\n type TabPanelLike,\n TABS_DEFAULT_DIRECTION,\n TABS_DIRECTIONS,\n type TabsDirection,\n} from './Tabs.types.js';\n\n/**\n * Base class for a tabbed interface container.\n *\n * Manages selection state, tab/panel association, ARIA wiring,\n * keyboard navigation, and event dispatching. Concrete classes\n * supply the stylesheet, render template, and visual behaviors\n * such as the selection indicator.\n *\n * Public API follows the Spectrum 2 / Spectrum Design–aligned surface\n * from the tabs migration plan: `keyboard-activation` and `density`\n * instead of legacy `auto`, `compact`, `quiet`, `emphasized`, and\n * t-shirt `size` attributes.\n *\n * @slot - Tab items (elements with `role=\"tab\"`)\n * @slot tab-panel - Tab panel content (elements with `role=\"tabpanel\"`)\n *\n * @fires change - The selected tab has changed. Cancelable —\n * calling `preventDefault()` reverts the selection.\n */\nexport abstract class TabsBase extends SpectrumElement {\n // ─────────────────────────\n // SHARED API\n // ─────────────────────────\n\n /**\n * @internal\n *\n * Valid direction values for validation and CEM/stories.\n */\n static readonly VALID_DIRECTIONS: readonly TabsDirection[] = TABS_DIRECTIONS;\n\n /**\n * @internal\n */\n static readonly VALID_KEYBOARD_ACTIVATIONS: readonly KeyboardActivation[] =\n KEYBOARD_ACTIVATIONS;\n\n /**\n * @internal\n */\n static readonly VALID_DENSITIES: readonly TabDensity[] = TAB_DENSITIES;\n\n /**\n * Whether selection follows keyboard focus (`automatic`, default) or the\n * user must press Enter or Space to activate (`manual`). Prefer `manual`\n * when tab panels are expensive to render or not fully present in the DOM.\n *\n * @see https://w3c.github.io/aria-practices/#kbd_selection_follows_focus\n */\n @property({ type: String, reflect: true, attribute: 'keyboard-activation' })\n public get keyboardActivation(): KeyboardActivation {\n return this._keyboardActivation;\n }\n\n public set keyboardActivation(value: string) {\n const isValid = (KEYBOARD_ACTIVATIONS as readonly string[]).includes(value);\n\n if (!isValid && window.__swc?.DEBUG) {\n window.__swc.warn(\n this,\n `<${this.localName}> expects \"keyboard-activation\" to be one of:`,\n 'https://opensource.adobe.com/spectrum-web-components/components/tabs/',\n { issues: [...KEYBOARD_ACTIVATIONS] }\n );\n }\n\n const valid = isValid\n ? (value as KeyboardActivation)\n : KEYBOARD_ACTIVATION_DEFAULT;\n\n if (this._keyboardActivation === valid) {\n return;\n }\n\n const old = this._keyboardActivation;\n this._keyboardActivation = valid;\n this.requestUpdate('keyboardActivation', old);\n }\n\n /** @internal */\n private _keyboardActivation: KeyboardActivation = KEYBOARD_ACTIVATION_DEFAULT;\n\n /**\n * Layout density: `regular` (default) or `compact` (reduced tab spacing).\n */\n @property({ type: String, reflect: true })\n public get density(): TabDensity {\n return this._density;\n }\n\n public set density(value: string) {\n const isValid = (TAB_DENSITIES as readonly string[]).includes(value);\n\n if (!isValid && window.__swc?.DEBUG) {\n window.__swc.warn(\n this,\n `<${this.localName}> expects \"density\" to be one of:`,\n 'https://opensource.adobe.com/spectrum-web-components/components/tabs/',\n { issues: [...TAB_DENSITIES] }\n );\n }\n\n const valid = isValid ? (value as TabDensity) : TAB_DENSITY_DEFAULT;\n\n if (this._density === valid) {\n return;\n }\n\n const old = this._density;\n this._density = valid;\n this.requestUpdate('density', old);\n }\n\n /** @internal */\n private _density: TabDensity = TAB_DENSITY_DEFAULT;\n\n /**\n * The layout direction of the tab list.\n *\n * **Breaking change:** `'vertical-right'` is no longer supported.\n * Use `'vertical'` instead.\n *\n * @default 'horizontal'\n */\n @property({ type: String, reflect: true })\n public get direction(): TabsDirection {\n return this._direction;\n }\n\n public set direction(value: TabsDirection) {\n const isValid = (TABS_DIRECTIONS as readonly string[]).includes(value);\n\n if (!isValid && window.__swc?.DEBUG) {\n window.__swc.warn(\n this,\n `<${this.localName}> expects the \"direction\" attribute to be one of the following:`,\n 'https://opensource.adobe.com/spectrum-web-components/components/tabs/',\n {\n issues: [...TABS_DIRECTIONS],\n }\n );\n }\n\n const validDirection = isValid\n ? (value as TabsDirection)\n : TABS_DEFAULT_DIRECTION;\n\n if (this._direction === validDirection) {\n return;\n }\n\n const oldDirection = this._direction;\n this._direction = validDirection;\n this.requestUpdate('direction', oldDirection);\n }\n\n /** @internal */\n private _direction: TabsDirection = TABS_DEFAULT_DIRECTION;\n\n /**\n * Whether the entire tab list is disabled. When `true`,\n * `aria-disabled=\"true\"` is applied to the tablist element and\n * all interaction is suppressed.\n */\n @property({ type: Boolean, reflect: true })\n public disabled = false;\n\n /**\n * Accessible label for the tablist. Rendered as `aria-label` on the\n * element with `role=\"tablist\"` in the concrete template.\n */\n @property({ type: String, attribute: 'accessible-label' })\n public accessibleLabel = '';\n\n /**\n * The `tab-id` of the currently selected tab. Setting this property\n * updates which tab appears selected and which panel is visible.\n */\n @property({ type: String, reflect: true })\n public selected = '';\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n /** @internal */\n private static readonly INDICATOR_BASE_SIZE = 100;\n\n /**\n * @internal\n *\n * Inline style applied to the selection indicator element.\n * Computed from the selected tab's position and dimensions.\n */\n @state()\n protected selectionIndicatorStyle = '';\n\n /**\n * @internal\n *\n * Suppresses the transition on the very first indicator placement\n * so it doesn't animate from the origin.\n */\n @state()\n protected shouldAnimate = false;\n\n /**\n * @internal\n *\n * Cached list of tab elements managed by this container. Updated\n * via `handleTabSlotChange`.\n */\n private _tabs: TabLike[] = [];\n\n /**\n * Whether an assigned node is treated as a tab. `role=\"tab\"` is set in\n * each tab's `firstUpdated`, so `slotchange` may run before that — accept\n * known tab host tag names so the tab list and selection indicator sync.\n */\n private static isTabSlotNode(el: Element): el is TabLike {\n if (!(el instanceof HTMLElement)) {\n return false;\n }\n if (el.getAttribute('role') === 'tab') {\n return true;\n }\n return el.localName === 'swc-tab';\n }\n\n /**\n * Called by the concrete class when the default slot's content\n * changes. Rebuilds the internal tab list and syncs selection\n * state.\n */\n protected handleTabSlotChange(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n this._tabs = slot\n .assignedElements()\n .filter(TabsBase.isTabSlotNode) as TabLike[];\n this.updateCheckedState();\n this.updateSelectionIndicator();\n }\n\n /**\n * Called by the concrete class when the `tab-panel` slot's content\n * changes. Wires up `aria-controls` / `aria-labelledby` between\n * each tab and its panel.\n */\n protected handlePanelSlotChange(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n const panels = slot.assignedElements() as TabPanelLike[];\n this.managePanels(panels);\n }\n\n /**\n * Click handler bound to the tablist wrapper in the concrete\n * template. Activates the clicked tab.\n */\n protected handleClick(event: Event): void {\n if (this.disabled) {\n return;\n }\n\n const target = event\n .composedPath()\n .find((el) => (el as TabLike).parentElement === this) as\n | TabLike\n | undefined;\n\n if (!target || target.disabled) {\n return;\n }\n\n this.selectTarget(target);\n }\n\n /**\n * Full keyboard handler per WAI-ARIA APG Tabs pattern.\n *\n * **Horizontal:** Left/Right navigate; Up/Down ignored.\n * **Vertical:** Up/Down navigate; Left/Right ignored.\n * **RTL:** Left/Right swap in `dir=\"rtl\"`.\n * **Wrapping:** Navigation wraps from last to first and vice versa.\n * **Disabled tabs:** Disabled tabs receive focus via arrows but\n * are not activatable by Enter/Space.\n * **Automatic activation:** When `keyboard-activation` is `automatic`,\n * selection follows focus on arrow key navigation.\n * **Home/End:** Jump to first/last tab.\n */\n protected handleKeyDown(event: KeyboardEvent): void {\n if (this.disabled) {\n return;\n }\n\n const { code } = event;\n\n if (code === 'Enter' || code === 'Space') {\n event.preventDefault();\n const target = event.target as TabLike | null;\n if (target && !target.disabled) {\n this.selectTarget(target);\n }\n return;\n }\n\n const delta = this.getNavigationDelta(code);\n if (delta !== null) {\n event.preventDefault();\n this.focusByDelta(delta);\n return;\n }\n\n if (code === 'Home') {\n event.preventDefault();\n this.focusTabAtIndex(0);\n return;\n }\n\n if (code === 'End') {\n event.preventDefault();\n this.focusTabAtIndex(this._tabs.length - 1);\n return;\n }\n }\n\n /**\n * Maps a keyboard code to a navigation delta (+1 or -1) based\n * on orientation and text direction. Returns `null` when the key\n * does not apply to the current orientation.\n */\n private getNavigationDelta(code: string): number | null {\n const isRtl = this.dir === 'rtl';\n\n if (this._direction === 'horizontal') {\n if (code === 'ArrowRight') {\n return isRtl ? -1 : 1;\n }\n if (code === 'ArrowLeft') {\n return isRtl ? 1 : -1;\n }\n return null;\n }\n\n // Vertical: Up/Down navigate; Left/Right have no effect.\n if (code === 'ArrowDown') {\n return 1;\n }\n if (code === 'ArrowUp') {\n return -1;\n }\n return null;\n }\n\n /**\n * Moves focus by `delta` positions from the currently focused tab,\n * wrapping around the list. All tabs (including disabled) receive\n * focus per APG. In automatic activation mode, the newly focused tab\n * is also selected.\n */\n private focusByDelta(delta: number): void {\n if (!this._tabs.length) {\n return;\n }\n\n const root = this.getRootNode() as Document | ShadowRoot;\n const current = this._tabs.indexOf(root.activeElement as TabLike);\n const start = current === -1 ? 0 : current;\n const nextIndex = this.wrapIndex(start + delta);\n\n this.focusTabAtIndex(nextIndex);\n }\n\n /**\n * Focuses the tab at the given index and, when in automatic\n * activation mode, also selects it. Selection runs before `focus()`\n * so `change` listeners observe the updated value before focus moves.\n */\n private focusTabAtIndex(index: number): void {\n if (!this._tabs.length) {\n return;\n }\n\n const clamped = this.wrapIndex(index);\n const tab = this._tabs[clamped];\n if (!tab) {\n return;\n }\n\n if (this._keyboardActivation === 'automatic' && !tab.disabled) {\n this.selectTarget(tab);\n }\n\n this.setRovingTabindex(tab);\n tab.focus();\n }\n\n /**\n * Wraps an index into the valid range `[0, tabs.length)`.\n */\n private wrapIndex(index: number): number {\n const len = this._tabs.length;\n return ((index % len) + len) % len;\n }\n\n /**\n * Updates roving tabindex so only the given tab has\n * `tabindex=\"0\"` and all others have `tabindex=\"-1\"`.\n */\n private setRovingTabindex(activeTab: TabLike): void {\n for (const tab of this._tabs) {\n tab.tabIndex = tab === activeTab ? 0 : -1;\n }\n }\n\n /**\n * Attempts to select the given tab element. Dispatches a cancelable\n * `change` event — if the consumer calls `preventDefault()`, the\n * selection reverts to the previous value.\n */\n private selectTarget(target: TabLike): void {\n const id = target.tabId;\n if (!id) {\n return;\n }\n\n const previous = this.selected;\n this.selected = id;\n\n const applyDefault = this.dispatchEvent(\n new Event('change', {\n cancelable: true,\n })\n );\n\n if (!applyDefault) {\n this.selected = previous;\n }\n }\n\n /**\n * Synchronizes the `selected` attribute and roving tabindex on\n * each child tab to match the container's `selected` value.\n * Ensures at least one tab has `tabindex=\"0\"` for Tab-key entry\n * when the container is not disabled. When the container is\n * disabled, all tabs get `tabindex=\"-1\"` to prevent Tab-key\n * entry into the tab list.\n */\n private updateCheckedState(): void {\n let hasTabStop = false;\n\n for (const tab of this._tabs) {\n tab.selected = false;\n }\n\n if (this.selected) {\n const currentTab = this._tabs.find((el) => el.tabId === this.selected);\n\n if (currentTab) {\n currentTab.selected = true;\n if (!this.disabled) {\n this.setRovingTabindex(currentTab);\n hasTabStop = true;\n }\n } else {\n this.selected = '';\n }\n }\n\n if (this.disabled) {\n for (const tab of this._tabs) {\n tab.tabIndex = -1;\n }\n } else if (!hasTabStop && this._tabs.length) {\n this._tabs[0].tabIndex = 0;\n }\n }\n\n /**\n * Wires up cross-element ARIA relationships between tabs and\n * panels. Each tab gets `aria-controls` pointing at its panel's\n * `id`, and each panel gets `aria-labelledby` pointing at its\n * tab's `id`.\n */\n private managePanels(panels: TabPanelLike[]): void {\n for (const panel of panels) {\n const { tabId, id } = panel;\n const tab = this.querySelector(`[role=\"tab\"][tab-id=\"${tabId}\"]`);\n\n if (tab) {\n tab.setAttribute('aria-controls', id);\n panel.setAttribute('aria-labelledby', tab.id);\n }\n\n panel.selected = tabId === this.selected;\n }\n }\n\n // ───────────────────────────────────\n // SELECTION INDICATOR\n // ───────────────────────────────────\n\n /**\n * @internal\n *\n * Recalculates the selection indicator's position and size based\n * on the currently selected tab element. Uses CSS transforms for\n * smooth animation between tab positions.\n *\n * The indicator is a fixed-size element (100px base) that gets\n * `scaleX`/`scaleY` to match the selected tab's width/height,\n * and `translateX`/`translateY` to match its offset position.\n */\n protected updateSelectionIndicator = async (): Promise<void> => {\n const selectedElement = this._tabs.find((el) => el.selected);\n if (!selectedElement) {\n this.selectionIndicatorStyle =\n 'transform: translateX(0px) scaleX(0) scaleY(0)';\n return;\n }\n\n const tablist = this.renderRoot?.querySelector('.tablist');\n if (!tablist) {\n return;\n }\n\n await Promise.all([\n (selectedElement as HTMLElement & { updateComplete?: Promise<boolean> })\n .updateComplete ?? Promise.resolve(),\n document.fonts ? document.fonts.ready : Promise.resolve(),\n ]);\n\n const tabRect = selectedElement.getBoundingClientRect();\n const listRect = tablist.getBoundingClientRect();\n\n if (this._direction === 'horizontal') {\n const isRtl = getComputedStyle(this).direction === 'rtl';\n const offset = isRtl\n ? tabRect.right - listRect.right\n : tabRect.left - listRect.left;\n const scale = tabRect.width / TabsBase.INDICATOR_BASE_SIZE;\n this.selectionIndicatorStyle = `transform: translateX(${offset}px) scaleX(${scale})`;\n } else {\n const top = tabRect.top - listRect.top;\n const scale = tabRect.height / TabsBase.INDICATOR_BASE_SIZE;\n this.selectionIndicatorStyle = `transform: translateY(${top}px) scaleY(${scale})`;\n }\n\n if (!this.shouldAnimate) {\n await this.updateComplete;\n this.shouldAnimate = true;\n }\n };\n\n /** @internal */\n private _resizeObserver?: ResizeObserver;\n\n /**\n * @internal\n *\n * Watches for `dir` attribute changes so the indicator recalculates\n * when writing direction flips at runtime. `getComputedStyle` in\n * `updateSelectionIndicator` resolves inherited direction correctly,\n * but nothing else observes it: a `dir` flip on the document root or\n * an ancestor doesn't resize this element, so the `ResizeObserver`\n * below won't catch it. Mirrors the `dir`-watching pattern in\n * `placement-controller.ts`.\n */\n private _directionObserver?: MutationObserver;\n\n // ───────────────────────────────────\n // LIFECYCLE\n // ───────────────────────────────────\n\n protected override willUpdate(changes: PropertyValues): void {\n if (!this.hasUpdated) {\n const selectedChild = this.querySelector(\n ':scope > [selected]'\n ) as TabLike | null;\n\n if (selectedChild) {\n this.selectTarget(selectedChild);\n }\n }\n\n super.willUpdate(changes);\n\n if (changes.has('selected')) {\n if (this._tabs.length) {\n this.updateCheckedState();\n }\n\n const previousValue = changes.get('selected') as string | undefined;\n if (previousValue) {\n const previous = this.querySelector(\n `[role=\"tabpanel\"][tab-id=\"${previousValue}\"]`\n ) as TabPanelLike | null;\n\n if (previous) {\n previous.selected = false;\n }\n }\n\n const next = this.querySelector(\n `[role=\"tabpanel\"][tab-id=\"${this.selected}\"]`\n ) as TabPanelLike | null;\n\n if (next) {\n next.selected = true;\n }\n\n this.updateSelectionIndicator();\n }\n\n if (changes.has('disabled') && this._tabs.length) {\n this.updateCheckedState();\n }\n\n if (changes.has('direction')) {\n this.updateSelectionIndicator();\n }\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('resize', this.updateSelectionIndicator);\n if ('fonts' in document) {\n document.fonts.addEventListener(\n 'loadingdone',\n this.updateSelectionIndicator\n );\n }\n this._resizeObserver = new ResizeObserver(() => {\n this.updateSelectionIndicator();\n });\n this._resizeObserver.observe(this);\n\n this._directionObserver = new MutationObserver(() => {\n this.updateSelectionIndicator();\n });\n const observeDir = (node: Element | null | undefined) => {\n if (node) {\n this._directionObserver?.observe(node, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n }\n };\n observeDir(this.ownerDocument.documentElement);\n observeDir(this.closest('[dir]'));\n }\n\n public override disconnectedCallback(): void {\n window.removeEventListener('resize', this.updateSelectionIndicator);\n if ('fonts' in document) {\n document.fonts.removeEventListener(\n 'loadingdone',\n this.updateSelectionIndicator\n );\n }\n this._resizeObserver?.disconnect();\n this._resizeObserver = undefined;\n this._directionObserver?.disconnect();\n this._directionObserver = undefined;\n super.disconnectedCallback();\n }\n\n /**\n * Focuses the selected tab, or the first tab when none is selected yet.\n * Slotted tabs live in the light DOM; this is more reliable than relying\n * only on shadow `delegatesFocus` across browsers and test harnesses.\n */\n public override focus(options?: FocusOptions): void {\n if (this.disabled) {\n return;\n }\n\n const selectedTab = this._tabs.find((tab) => tab.selected);\n if (selectedTab) {\n (selectedTab as HTMLElement).focus(options);\n return;\n }\n\n if (this._tabs.length) {\n (this._tabs[0] as HTMLElement).focus(options);\n return;\n }\n\n super.focus(options);\n }\n\n protected override firstUpdated(changes: PropertyValues): void {\n super.firstUpdated(changes);\n\n if (!this.hasAttribute('direction')) {\n this.setAttribute('direction', this.direction);\n }\n\n if (window.__swc?.DEBUG && !this.accessibleLabel) {\n window.__swc.warn(\n this,\n `<${this.localName}> requires an \"accessible-label\" attribute to provide an accessible name for the tablist.`,\n 'https://opensource.adobe.com/spectrum-web-components/components/tabs/',\n { type: 'accessibility', level: 'high' }\n );\n }\n }\n\n /**\n * Waits for all child tab elements to finish their update cycle\n * before resolving so layout-dependent callers see stable geometry.\n */\n public override async getUpdateComplete(): Promise<boolean> {\n const complete = await super.getUpdateComplete();\n\n const children = [...this.children] as HTMLElement[];\n const childUpdates = children.map((child) => {\n if ('updateComplete' in child) {\n return (child as unknown as { updateComplete: Promise<boolean> })\n .updateComplete;\n }\n return Promise.resolve(true);\n });\n\n await Promise.all(childUpdates);\n return complete;\n }\n}\n"],"mappings":"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"}
|