Skip to content

Commit

Permalink
fix(tab-nav): fixes preselect logic in tabs with disabled attribute (#…
Browse files Browse the repository at this point in the history
…2320)

* fix: fixes disabled tabs in preselect issue and adds preselected tab in tab-nav storybook
  • Loading branch information
tshimber authored Oct 29, 2024
1 parent 4c45650 commit bd30a6f
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 31 deletions.
7 changes: 4 additions & 3 deletions packages/components/src/components/tab-header/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@

## Events

| Event | Description | Type |
| -------------- | ----------- | ------------------ |
| `scale-select` | | `CustomEvent<any>` |
| Event | Description | Type |
| ---------------- | ------------------------------------------------ | ------------------ |
| `scale-disabled` | Emitted when currently selected tab got disabled | `CustomEvent<any>` |
| `scale-select` | Emitted on header select | `CustomEvent<any>` |


----------------------------------------------
Expand Down
23 changes: 14 additions & 9 deletions packages/components/src/components/tab-header/tab-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,42 +47,47 @@ 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) {
event.stopPropagation();
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();
}
}

Expand Down
42 changes: 28 additions & 14 deletions packages/components/src/components/tab-nav/tab-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -92,7 +95,7 @@ export class TabNav {
customElements.whenDefined('scale-tab-header'),
customElements.whenDefined('scale-tab-panel'),
]).then(() => {
this.linkPanels();
this.linkPanelsAndSelectTab();
this.propagateSizeToTabs();
});

Expand Down Expand Up @@ -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));
}

Expand All @@ -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;
}

/**
Expand Down
58 changes: 58 additions & 0 deletions packages/components/src/html/tab-nav.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0"
/>
<title>Stencil Component Starter</title>

<script type="module" src="/build/scale-components.esm.js"></script>
<link rel="stylesheet" href="/build/scale-components.css" />
<style type="text/css" media="screen, print">
html {
margin: 0;
padding: 0;
}

body {
margin: 0;
padding: 4rem;
}
</style>
</head>

<body>
<p>
<scale-tab-nav>
<scale-tab-header slot="tab">General</scale-tab-header>
<scale-tab-panel slot="panel">
1 Freegan kinfolk farm-to-table humblebrag cred…
</scale-tab-panel>
<scale-tab-header slot="tab">Usage</scale-tab-header>
<scale-tab-panel slot="panel">
2 Bespoke austin pork belly yuccie pop-up. Before they sold out…
</scale-tab-panel>
<scale-tab-header slot="tab">Style</scale-tab-header>
<scale-tab-panel slot="panel">
3 Biodiesel chia af hoodie tumeric bespoke letterpress…
</scale-tab-panel>
<scale-tab-header slot="tab">Code</scale-tab-header>
<scale-tab-panel slot="panel">
4 Asymmetrical tattooed chia, banh mi blog microdosing…
</scale-tab-panel>
</scale-tab-nav>
</p>
</body>
<script>
setTimeout(() => {
let tabs = document.querySelectorAll('scale-tab-header');
tabs[0].disabled = true;
}, 2000);
setTimeout(() => {
let tabs = document.querySelectorAll('scale-tab-header');
tabs[3].selected = true;
}, 4000);
</script>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
bitters.
</p>
</scale-tab-panel>
<scale-tab-header slot="tab">
<scale-tab-header :selected="preselected ? true : false" slot="tab">
<scale-icon-content-heart v-if="withIcon" /> Style
</scale-tab-header>
<scale-tab-panel slot="panel">
Expand Down Expand Up @@ -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 },
},
};
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script>
export default {
name: 'Tab Header',
props: {
styles: { type: String },
disabled: { type: Boolean, default: 'false' },
selected: { type: Boolean, default: 'false' },
size: { type: ['large', 'small'], default: 'small' },
},
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -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';

<Meta
title="Components/Tab Navigation"
component={ScaleTabNav}
subcomponents={{ 'Scale Tab Panel': TabPanel }}
subcomponents={{ 'Scale Tab Header': TabHeader, 'Scale Tab Panel': TabPanel }}
argTypes={{
styles: {
table: {
Expand All @@ -34,14 +35,21 @@ import TabPanel from './TabPanel.vue';
description: `(optional) DEPRECATED - size should replace small`,
control: { type: null },
},
preselected: {
table: {
disable: true,
},
description: '',
control: { type: null },
},
}}
/>

export const Template = (args, { argTypes }) => ({
components: { ScaleTabNav },
props: ScaleTabNav.props,
template: `
<scale-tab-nav :disabled="disabled ? true : false" :size="size" :with-icon="withIcon"></scale-tab-nav>
<scale-tab-nav :disabled="disabled ? true : false" :preselected="preselected ? true : false" :size="size" :with-icon="withIcon"></scale-tab-nav>
`,
});

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -200,6 +209,38 @@ For Shadow Parts, please inspect the element's #shadow.
</scale-tab-nav>
```

## Preselected Tab

<Canvas withSource="none">
<Story
name="Preselected Tab"
args={{ preselected: true, withIcon: false, size: 'small' }}
>
{Template.bind({})}
</Story>
</Canvas>

```html
<scale-tab-nav>
<scale-tab-header slot="tab">General</scale-tab-header>
<scale-tab-panel slot="panel">
Freegan kinfolk farm-to-table humblebrag cred…
</scale-tab-panel>
<scale-tab-header slot="tab">Usage</scale-tab-header>
<scale-tab-panel slot="panel">
Bespoke austin pork belly yuccie pop-up. Before they sold out…
</scale-tab-panel>
<scale-tab-header selected slot="tab">Style</scale-tab-header>
<scale-tab-panel slot="panel">
Biodiesel chia af hoodie tumeric bespoke letterpress…
</scale-tab-panel>
<scale-tab-header slot="tab">Code</scale-tab-header>
<scale-tab-panel slot="panel">
Asymmetrical tattooed chia, banh mi blog microdosing…
</scale-tab-panel>
</scale-tab-nav>
```

## Large, Text & Icon

<Canvas withSource="none">
Expand Down

0 comments on commit bd30a6f

Please sign in to comment.