diff --git a/packages/components/src/components/tab-header/readme.md b/packages/components/src/components/tab-header/readme.md index 34d7389ef8..d2a70cb660 100644 --- a/packages/components/src/components/tab-header/readme.md +++ b/packages/components/src/components/tab-header/readme.md @@ -18,9 +18,10 @@ ## Events -| Event | Description | Type | -| -------------- | ----------- | ------------------ | -| `scale-select` | | `CustomEvent` | +| Event | Description | Type | +| ---------------- | ------------------------------------------------ | ------------------ | +| `scale-disabled` | Emitted when currently selected tab got disabled | `CustomEvent` | +| `scale-select` | Emitted on header select | `CustomEvent` | ---------------------------------------------- diff --git a/packages/components/src/components/tab-header/tab-header.tsx b/packages/components/src/components/tab-header/tab-header.tsx index 6102ce7f24..05eb9c772d 100644 --- a/packages/components/src/components/tab-header/tab-header.tsx +++ b/packages/components/src/components/tab-header/tab-header.tsx @@ -47,13 +47,16 @@ export class TabHeader { /** (optional) size */ @Prop() size?: 'small' | 'large' = 'small'; /** (optional) Whether the tab is selected */ - @Prop() selected?: boolean; + @Prop({ mutable: true }) selected?: boolean; /** (optional) Injected CSS styles */ @Prop() styles?: string; @State() hasFocus: boolean = false; + /** Emitted on header select */ @Event({ eventName: 'scale-select' }) scaleSelect: EventEmitter; + /** Emitted when currently selected tab got disabled */ + @Event({ eventName: 'scale-disabled' }) scaleDisabled: EventEmitter; @Listen('click') handleClick(event: MouseEvent) { @@ -61,28 +64,30 @@ export class TabHeader { if (this.disabled) { return; } + this.selected = true; this.scaleSelect.emit(); } @Watch('selected') selectedChanged(newValue: boolean) { - if (!this.hostElement.isConnected) { + if (!this.hostElement.isConnected || this.disabled) { return; } - if (!this.disabled) { - if (newValue === true && this.tabsHaveFocus()) { - // Having focus on the host element, and not on inner elements, - // is required because screen readers. - this.hostElement.focus(); - } - this.updateSlottedIcon(); + if (newValue) { + this.scaleSelect.emit(); + } + if (newValue && this.tabsHaveFocus()) { + // Having focus on the host element and not on inner elements is required because of screen readers + this.hostElement.focus(); } + this.updateSlottedIcon(); } @Watch('disabled') disabledChanged() { if (this.disabled) { this.selected = false; + this.scaleDisabled.emit(); } } diff --git a/packages/components/src/components/tab-nav/tab-nav.tsx b/packages/components/src/components/tab-nav/tab-nav.tsx index 9c199f36db..6d4416e32a 100644 --- a/packages/components/src/components/tab-nav/tab-nav.tsx +++ b/packages/components/src/components/tab-nav/tab-nav.tsx @@ -42,9 +42,12 @@ export class TabNav { handleSelect(event) { const nextTab = event.target as HTMLScaleTabHeaderElement; // Act only if it's a direct child - if (this.getAllEnabledTabs().includes(nextTab) && !nextTab.disabled) { - this.selectTab(nextTab); - } + this.selectNextTab(nextTab); + } + + @Listen('scale-disabled') + handleDisabledTabHeader() { + this.selectNextTab(); } @Listen('keydown') @@ -92,7 +95,7 @@ export class TabNav { customElements.whenDefined('scale-tab-header'), customElements.whenDefined('scale-tab-panel'), ]).then(() => { - this.linkPanels(); + this.linkPanelsAndSelectTab(); this.propagateSizeToTabs(); }); @@ -144,24 +147,33 @@ export class TabNav { return tabs[tabs.length - 1]; } - linkPanels() { + linkPanelsAndSelectTab() { const tabs = this.getAllTabs(); - const selectedTab = - tabs.find((x) => x.selected) || tabs.filter((x) => !x.disabled)[0]; - tabs.forEach((tab) => { const panel = tab.nextElementSibling; tab.setAttribute('aria-controls', panel.id); panel.setAttribute('aria-labelledby', tab.id); }); - this.selectTab(selectedTab); + this.selectNextTab(); } - reset() { + selectNextTab(nextTab?: HTMLScaleTabHeaderElement): void { + const tabs = this.getAllTabs(); + const tabToSelect = + (!nextTab?.disabled && nextTab) || + tabs.find((tab) => tab.selected) || + tabs.filter((tab) => !tab.disabled)[0]; + this.selectTab(tabToSelect); + } + + reset(nextTab?: HTMLScaleTabHeaderElement) { const tabs = this.getAllEnabledTabs(); + tabs.forEach((tab) => { + if (tab !== nextTab) { + tab.selected = false; + } + }); const panels = this.getAllPanels(); - - tabs.forEach((tab) => (tab.selected = false)); panels.forEach((panel) => (panel.hidden = true)); } @@ -171,10 +183,12 @@ export class TabNav { } selectTab(nextTab: HTMLScaleTabHeaderElement) { + this.reset(nextTab); + if (!nextTab.selected) { + nextTab.selected = true; + } const nextPanel = this.findPanelForTab(nextTab); - this.reset(); nextPanel.hidden = false; - nextTab.selected = true; } /** diff --git a/packages/components/src/html/tab-nav.html b/packages/components/src/html/tab-nav.html new file mode 100644 index 0000000000..781aa03b9f --- /dev/null +++ b/packages/components/src/html/tab-nav.html @@ -0,0 +1,58 @@ + + + + + + Stencil Component Starter + + + + + + + +

+ + General + + 1 Freegan kinfolk farm-to-table humblebrag cred… + + Usage + + 2 Bespoke austin pork belly yuccie pop-up. Before they sold out… + + Style + + 3 Biodiesel chia af hoodie tumeric bespoke letterpress… + + Code + + 4 Asymmetrical tattooed chia, banh mi blog microdosing… + + +

+ + + diff --git a/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue b/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue index 5459aa6c41..5313d2d49c 100644 --- a/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue +++ b/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue @@ -24,7 +24,7 @@ bitters.

- + Style @@ -55,8 +55,10 @@ export default { props: { styles: { type: String }, disabled: { type: Boolean, default: false }, + preselected: { type: Boolean, default: false }, withIcon: { type: Boolean, default: true }, size: { type: String, default: 'small' }, + small: { type: Boolean, default: false }, }, }; diff --git a/packages/storybook-vue/stories/components/tab-navigation/TabHeader.vue b/packages/storybook-vue/stories/components/tab-navigation/TabHeader.vue new file mode 100644 index 0000000000..cf8d656419 --- /dev/null +++ b/packages/storybook-vue/stories/components/tab-navigation/TabHeader.vue @@ -0,0 +1,11 @@ + diff --git a/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx b/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx index 3a09963717..bc5660a73f 100644 --- a/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx +++ b/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx @@ -6,12 +6,13 @@ import { Description, } from '@storybook/addon-docs'; import ScaleTabNav from './ScaleTabNav.vue'; +import TabHeader from './TabHeader.vue'; import TabPanel from './TabPanel.vue'; @@ -41,7 +49,7 @@ export const Template = (args, { argTypes }) => ({ components: { ScaleTabNav }, props: ScaleTabNav.props, template: ` - + `, }); @@ -123,8 +131,9 @@ export const Template = (args, { argTypes }) => ({ --color-hover: var(--telekom-color-text-and-icon-primary-hovered); --color-active: var(--telekom-color-text-and-icon-primary-pressed); --color-selected: var(--telekom-color-text-and-icon-primary-standard); - --focus-outline: var(--telekom-line-weight-highlight) solid - var(--telekom-color-functional-focus-standard); + --focus-outline: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-focus-standard + ); --spacing-right-slotted: var(--telekom-spacing-composition-space-04); --color-disabled: var(--telekom-color-text-and-icon-disabled); --radius: var(--telekom-radius-standard); @@ -200,6 +209,38 @@ For Shadow Parts, please inspect the element's #shadow. ``` +## Preselected Tab + + + + {Template.bind({})} + + + +```html + + General + + Freegan kinfolk farm-to-table humblebrag cred… + + Usage + + Bespoke austin pork belly yuccie pop-up. Before they sold out… + + Style + + Biodiesel chia af hoodie tumeric bespoke letterpress… + + Code + + Asymmetrical tattooed chia, banh mi blog microdosing… + + +``` + ## Large, Text & Icon