diff --git a/custom-elements.json b/custom-elements.json index 22b18e27f7656352aaf25abbcd2bfda3f8779453..2ee73264d98f8fdc29d84e47a8a999079e91e0cb 100644 --- a/custom-elements.json +++ b/custom-elements.json @@ -3554,7 +3554,7 @@ }, { "kind": "javascript-module", - "path": "components/galactic/galactic.tsx", + "path": "components/galactic-menu/galactic-menu.tsx", "declarations": [ { "kind": "class", @@ -3565,24 +3565,59 @@ "kind": "field", "name": "el", "type": { - "text": "HTMLWcsGalacticElement" + "text": "HTMLWcsGalacticMenuElement" } }, { "kind": "field", - "name": "text", + "name": "showPopoverMenu", "type": { - "text": "string" + "text": "boolean" }, - "description": "Text to display in the bar" + "default": "false" }, { "kind": "field", - "name": "show", + "name": "popper", "type": { - "text": "boolean" + "text": "Instance" }, - "default": "false" + "privacy": "private" + }, + { + "kind": "field", + "name": "text", + "type": { + "text": "string" + }, + "description": "Text to be displayed in the galactic bar" + }, + { + "kind": "field", + "name": "menu", + "privacy": "private" + }, + { + "kind": "field", + "name": "tooltip", + "privacy": "private" + }, + { + "kind": "method", + "name": "onWindowClickEvent", + "parameters": [ + { + "name": "event", + "type": { + "text": "MouseEvent" + } + } + ] + }, + { + "kind": "method", + "name": "toogleMenu", + "privacy": "private" }, { "kind": "method", @@ -3603,7 +3638,7 @@ } } ], - "tagName": "wcs-galactic", + "tagName": "wcs-galactic-menu", "events": [], "customElement": true } @@ -3614,22 +3649,22 @@ "name": "Galactic", "declaration": { "name": "Galactic", - "module": "components/galactic/galactic.tsx" + "module": "components/galactic-menu/galactic-menu.tsx" } }, { "kind": "custom-element-definition", - "name": "wcs-galactic", + "name": "wcs-galactic-menu", "declaration": { "name": "Galactic", - "module": "components/galactic/galactic.tsx" + "module": "components/galactic-menu/galactic-menu.tsx" } } ] }, { "kind": "javascript-module", - "path": "components/galactic-menu/galactic-menu.tsx", + "path": "components/galactic/galactic.tsx", "declarations": [ { "kind": "class", @@ -3640,59 +3675,24 @@ "kind": "field", "name": "el", "type": { - "text": "HTMLWcsGalacticMenuElement" + "text": "HTMLWcsGalacticElement" } }, - { - "kind": "field", - "name": "showPopoverMenu", - "type": { - "text": "boolean" - }, - "default": "false" - }, - { - "kind": "field", - "name": "popper", - "type": { - "text": "Instance" - }, - "privacy": "private" - }, { "kind": "field", "name": "text", "type": { "text": "string" }, - "description": "Text to be displayed in the galactic bar" - }, - { - "kind": "field", - "name": "menu", - "privacy": "private" + "description": "Text to display in the bar" }, { "kind": "field", - "name": "tooltip", - "privacy": "private" - }, - { - "kind": "method", - "name": "onWindowClickEvent", - "parameters": [ - { - "name": "event", - "type": { - "text": "MouseEvent" - } - } - ] - }, - { - "kind": "method", - "name": "toogleMenu", - "privacy": "private" + "name": "show", + "type": { + "text": "boolean" + }, + "default": "false" }, { "kind": "method", @@ -3713,7 +3713,7 @@ } } ], - "tagName": "wcs-galactic-menu", + "tagName": "wcs-galactic", "events": [], "customElement": true } @@ -3724,15 +3724,15 @@ "name": "Galactic", "declaration": { "name": "Galactic", - "module": "components/galactic-menu/galactic-menu.tsx" + "module": "components/galactic/galactic.tsx" } }, { "kind": "custom-element-definition", - "name": "wcs-galactic-menu", + "name": "wcs-galactic", "declaration": { "name": "Galactic", - "module": "components/galactic-menu/galactic-menu.tsx" + "module": "components/galactic/galactic.tsx" } } ] @@ -8067,14 +8067,6 @@ "text": "HTMLWcsTabsElement" } }, - { - "kind": "field", - "name": "headers", - "type": { - "text": "string[]" - }, - "default": "[]" - }, { "kind": "field", "name": "currentActiveTabIndex", @@ -8112,6 +8104,11 @@ "name": "emitActiveTabChange", "privacy": "private" }, + { + "kind": "method", + "name": "updateCurrentActiveTabIndexByCSS", + "privacy": "private" + }, { "kind": "method", "name": "updateCurrentActiveIndexByTabKey", @@ -8125,10 +8122,6 @@ } ] }, - { - "kind": "method", - "name": "onTabLoaded" - }, { "kind": "method", "name": "putTabsInCorrectDivIfTheyAreNot", @@ -8152,11 +8145,6 @@ } ] }, - { - "kind": "method", - "name": "refreshHeaders", - "privacy": "private" - }, { "kind": "field", "name": "tabs", diff --git a/src/components.d.ts b/src/components.d.ts index 6647cad4cfeddc65534bb0ece0343adf4b1830f8..e7e7349d4ab6cad0a7f05181ff03f3bb69012acc 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -726,6 +726,10 @@ export namespace Components { * More content ! * * ``` + * Initial active tab will be picked using different strategy in this order: + * - `wcs-tabs` has a `selected-index` attribute + * - `wcs-tabs` has a `selected-key` attribute: First `wcs-tab` with a corresponding `item-key` attribute will be picked + * - First `wcs-tab` with an `"active"` CSS class. */ interface WcsTabs { /** @@ -1363,6 +1367,10 @@ declare global { * More content ! * * ``` + * Initial active tab will be picked using different strategy in this order: + * - `wcs-tabs` has a `selected-index` attribute + * - `wcs-tabs` has a `selected-key` attribute: First `wcs-tab` with a corresponding `item-key` attribute will be picked + * - First `wcs-tab` with an `"active"` CSS class. */ interface HTMLWcsTabsElement extends Components.WcsTabs, HTMLStencilElement { } @@ -2171,6 +2179,10 @@ declare namespace LocalJSX { * More content ! * * ``` + * Initial active tab will be picked using different strategy in this order: + * - `wcs-tabs` has a `selected-index` attribute + * - `wcs-tabs` has a `selected-key` attribute: First `wcs-tab` with a corresponding `item-key` attribute will be picked + * - First `wcs-tab` with an `"active"` CSS class. */ interface WcsTabs { /** @@ -2508,6 +2520,10 @@ declare module "@stencil/core" { * More content ! * * ``` + * Initial active tab will be picked using different strategy in this order: + * - `wcs-tabs` has a `selected-index` attribute + * - `wcs-tabs` has a `selected-key` attribute: First `wcs-tab` with a corresponding `item-key` attribute will be picked + * - First `wcs-tab` with an `"active"` CSS class. */ "wcs-tabs": LocalJSX.WcsTabs & JSXBase.HTMLAttributes; /** diff --git a/src/components/tab/readme.md b/src/components/tab/readme.md index 10ce0057a7a8f5f37fde95d5c17faa0bfcd2cccf..cd6b44b06dc8036dda523d2bbdcc5894a1f472af 100644 --- a/src/components/tab/readme.md +++ b/src/components/tab/readme.md @@ -11,7 +11,7 @@ Use this component to specify the content of a component. ## Properties | Property | Attribute | Description | Type | Default | -| --------- | ---------- | ------------------------------------------------- | -------- | ----------- | +|-----------| ---------- | ------------------------------------------------- | -------- | ----------- | | `header` | `header` | The header you want to be displayed for this tab. | `string` | `undefined` | | `itemKey` | `item-key` | | `any` | `undefined` | diff --git a/src/components/tabs/readme.md b/src/components/tabs/readme.md index 366d23ffc03454a459d193e3e5632d2b272bd584..e9359d0990b7479b602de47bbbd3cd3131d05c3a 100644 --- a/src/components/tabs/readme.md +++ b/src/components/tabs/readme.md @@ -8,6 +8,11 @@ Tabs component to switch between tab content. Use in conjuction with `wcs-tab`. +Initial active tab will be picked using different strategy in this order: +- `wcs-tabs` has a `selected-index` attribute +- `wcs-tabs` has a `selected-key` attribute: First `wcs-tab` with a corresponding `item-key` attribute will be picked +- First `wcs-tab` with an `"active"` CSS class. + ## Properties | Property | Attribute | Description | Type | Default | diff --git a/src/components/tabs/tabs.tsx b/src/components/tabs/tabs.tsx index 6ee2fbb2c856bc20a626b9a01ade62bf5b1370e4..c0116ab0cfec0402d68699830c95456354044595 100644 --- a/src/components/tabs/tabs.tsx +++ b/src/components/tabs/tabs.tsx @@ -9,7 +9,6 @@ import { Watch, h, Host, - Listen } from '@stencil/core'; import { WcsTabsAlignment, WcsTabChangeEvent } from './tabs-interface'; @@ -25,6 +24,11 @@ import { WcsTabsAlignment, WcsTabChangeEvent } from './tabs-interface'; * More content ! * * ``` + * + * Initial active tab will be picked using different strategy in this order: + * - `wcs-tabs` has a `selected-index` attribute + * - `wcs-tabs` has a `selected-key` attribute: First `wcs-tab` with a corresponding `item-key` attribute will be picked + * - First `wcs-tab` with an `"active"` CSS class. */ @Component({ tag: 'wcs-tabs', @@ -61,8 +65,6 @@ export class Tabs implements ComponentInterface { @Element() el!: HTMLWcsTabsElement; - @State() headers: string[] = []; - @State() currentActiveTabIndex = 0; @Watch('selectedIndex') @@ -77,35 +79,44 @@ export class Tabs implements ComponentInterface { private emitActiveTabChange() { this.tabChange.emit({ - tabName: this.headers[this.currentActiveTabIndex], + tabName: this.tabs[this.currentActiveTabIndex].header, tabIndex: this.currentActiveTabIndex, selectedKey: this.tabs[this.currentActiveTabIndex].itemKey }); } + private updateCurrentActiveTabIndexByCSS(){ + const index = this.tabs.findIndex(elm => elm.classList.contains('active')); + this.currentActiveTabIndex = index >= 0 ? index : 0; + } + + private cleanActiveClass(){ + this.tabs.forEach(elm => elm.classList.remove('active')); + } + private updateCurrentActiveIndexByTabKey(newValue: any) { for (let i = 0; i < this.tabs.length; i++) { const tab = this.tabs[i]; if (tab.itemKey === newValue) { this.currentActiveTabIndex = i; + break; } } } - @Listen('tabLoaded') - onTabLoaded() { - this.refreshHeaders(); - } - componentDidLoad() { this.putTabsInCorrectDivIfTheyAreNot(); - this.refreshHeaders(); + if (this.selectedIndex) { this.currentActiveTabIndex = this.selectedIndex; } if (this.selectedKey) { this.updateCurrentActiveIndexByTabKey(this.selectedKey); + } else { + this.updateCurrentActiveTabIndexByCSS(); } + this.cleanActiveClass(); + this.updateTabVisibility(); } // XXX: Firefox < 63 @@ -150,24 +161,9 @@ export class Tabs implements ComponentInterface { } } - private refreshHeaders() { - this.headers = []; - this.tabs - .forEach(x => { - this.headers.push(x.getAttribute('header')); - }); - } - private get tabs() { - const tabsEl = this.el.shadowRoot.querySelector('.wcs-tabs'); // FIXME: problem with this selector being too greedy in ff < 63 - const tabs = this.el.shadowRoot.querySelectorAll('.wcs-tabs > wcs-tab'); - - return tabs.length !== 0 - ? tabs - : tabsEl?.querySelector('slot') - ? tabsEl?.querySelector('slot')?.assignedElements() as unknown as NodeListOf - : []; + return Array.from(this.el.querySelectorAll('wcs-tab')) as unknown as HTMLWcsTabElement[]; } private selectTabAndEmitChangeEvent(index: number) { @@ -201,13 +197,13 @@ export class Tabs implements ComponentInterface { return (
- {this.headers.map((header, idx) => + {this.tabs.map((tab, idx) =>
this.selectTabAndEmitChangeEvent(idx)} onKeyDown={evt => this.handleKeyDown(evt, idx)} tabIndex={this.currentActiveTabIndex === idx ? 0 : -1} > - {header} + {tab.header}
)}
diff --git a/stories/components/tabs/tabs-documentation.md b/stories/components/tabs/tabs-documentation.md index 98b6bd40d26838546aba962499343183d3b3e4a0..222474d103eea7044c0f0dc2c2f65609b58e6d3e 100644 --- a/stories/components/tabs/tabs-documentation.md +++ b/stories/components/tabs/tabs-documentation.md @@ -1,3 +1,30 @@ +## Overview + +Tabs component to switch between tab content. +Use in conjuction with `wcs-tab`. + +Initial active tab will be picked using different strategy in this order: +- `wcs-tabs` has a `selected-index` attribute +- `wcs-tabs` has a `selected-key` attribute: First `wcs-tab` with a corresponding `item-key` attribute will be picked +- First `wcs-tab` with an `"active"` CSS class. + +## Properties + +| Property | Attribute | Description | Type | Default | +| --------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ----------- | +| `align` | `align` | Tab headers alignment. | `"center" \| "end" \| "start"` | `'start'` | +| `gutter` | `gutter` | Determines if tabs header should have a border at the bottom | `boolean` | `undefined` | +| `headersOnly` | `headers-only` | Whether to skip rendering the tabpanel with the content of the selected tab. Use this prop if you plan to separately render the tab content. | `boolean` | `false` | +| `selectedIndex` | `selected-index` | Current selected tab index. Starts at 0. | `number` | `0` | +| `selectedKey` | `selected-key` | | `any` | `undefined` | + + +## Events + +| Event | Description | Type | +| ----------- | -------------------------------------- | -------------------------------- | +| `tabChange` | Emitted when the selected tab change. | `CustomEvent` | + ## Available CSS Variables | Name | Description | diff --git a/stories/components/tabs/tabs.stories.ts b/stories/components/tabs/tabs.stories.ts index cfe032e865ebcea5c601419f80b1a954990b858c..f8add9ea802709a60a66ca09ec77713096f85811 100644 --- a/stories/components/tabs/tabs.stories.ts +++ b/stories/components/tabs/tabs.stories.ts @@ -37,7 +37,7 @@ const Template: StoryFn Premier contenu - + Deuxième contenu