Skip to content

Commit

Permalink
Tabs: move selected state management to pharos-tabs (#468)
Browse files Browse the repository at this point in the history
* fix: tab event

* fix: update selected tab via parent

* fix(tabs): update property and attribute selectors

* fix(tabs): default to selected, then selected-tab, then 0

* fix(tabs): selected-tab already defaults to 0

* fix(tabs): select initial tab panel

* fix(tabs): only trigger event if tab not selected

* fix(tabs): update test

* fix(tabs): add pharos-tabs-tab-selected event

* fix(tabs): fire tab selected in updated)

* chore: add changeset

* Update packages/pharos/src/components/tabs/pharos-tabs.ts

Co-authored-by: Dane Hillard <github@danehillard.com>

Co-authored-by: Mike Iden <mike.iden@ithaka.org>
Co-authored-by: Dane Hillard <github@danehillard.com>
  • Loading branch information
3 people committed Jan 23, 2023
1 parent eaa514f commit 1913341
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/perfect-cycles-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ithaka/pharos': major
---

pharos-tab `selected` has been deprecated, see new property for pharos-tabs `selected-tab`
7 changes: 3 additions & 4 deletions packages/pharos/src/components/tabs/pharos-tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ export class PharosTab extends PharosElement {
if (changedProperties.has('selected')) {
this._focused = this.selected;
this.setAttribute('aria-selected', this.selected ? 'true' : 'false');
if (this.selected) {
this._triggerSelectedEvent();
}
}

if (changedProperties.has('_focused')) {
Expand All @@ -63,7 +60,9 @@ export class PharosTab extends PharosElement {
}

private _handleClick(): void {
this._triggerSelectedEvent();
if (!this.selected) {
this._triggerSelectedEvent();
}
}

protected override render(): TemplateResult {
Expand Down
4 changes: 2 additions & 2 deletions packages/pharos/src/components/tabs/pharos-tabs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ describe('pharos-tabs', () => {
`);

componentLastTabSelected = await fixture(html`
<pharos-tabs>
<pharos-tabs selected-tab="2">
<pharos-tab id="tab-4" data-panel-id="panel-4">Tab 1</pharos-tab>
<pharos-tab id="tab-5" data-panel-id="panel-5">Tab 2</pharos-tab>
<pharos-tab id="tab-6" data-panel-id="panel-6" selected>Tab 3</pharos-tab>
<pharos-tab id="tab-6" data-panel-id="panel-6">Tab 3</pharos-tab>
<pharos-tab-panel id="panel-4" slot="panel">Panel 1</pharos-tab-panel>
<pharos-tab-panel id="panel-5" slot="panel">Panel 2</pharos-tab-panel>
<pharos-tab-panel id="panel-6" slot="panel">Panel 3</pharos-tab-panel>
Expand Down
47 changes: 39 additions & 8 deletions packages/pharos/src/components/tabs/pharos-tabs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PharosElement } from '../base/pharos-element';
import { html } from 'lit';
import type { TemplateResult, CSSResultArray } from 'lit';
import type { TemplateResult, CSSResultArray, PropertyValues } from 'lit';
import { property, query, queryAssignedElements, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { tabsStyles } from './pharos-tabs.css';
Expand All @@ -20,6 +20,8 @@ const _allTabPanelsSelector = '[data-pharos-component="PharosTabPanel"]';
* @slot - Contains the tabs.
* @slot panel - Contains the panel to be shown for a tab.
*
* @fires pharos-tabs-tab-selected - Fires when the tab is selected.
*
*/
export class PharosTabs extends PharosElement {
/**
Expand All @@ -29,6 +31,13 @@ export class PharosTabs extends PharosElement {
@property({ type: Boolean, reflect: true, attribute: 'panel-separator' })
public panelSeparator = false;

/**
* The 0-based index of the tab that is initially selected.
* @attr selected-tab
*/
@property({ type: Number, reflect: true, attribute: 'selected-tab' })
public selectedTab = 0;

@query('.tab__list')
private _tabList!: HTMLElement;

Expand All @@ -41,9 +50,6 @@ export class PharosTabs extends PharosElement {
@queryAssignedElements({ selector: _allTabsSelector })
private _tabs!: NodeListOf<PharosTab>;

@queryAssignedElements({ selector: `${_allTabsSelector}[selected]` })
private _selectedTabs!: NodeListOf<PharosTab>;

public static override get styles(): CSSResultArray {
return [tabsStyles];
}
Expand All @@ -68,6 +74,19 @@ export class PharosTabs extends PharosElement {
this._watchResize();
}

protected override async updated(changedProperties: PropertyValues): Promise<void> {
if (changedProperties.has('selectedTab') && this._tabs[this.selectedTab]) {
const details = {
bubbles: true,
composed: true,
detail: this._tabs[this.selectedTab],
};
this.dispatchEvent(new CustomEvent('pharos-tabs-tab-selected', details));

this._handleTabSelected(this._tabs[this.selectedTab]);
}
}

private _tabOverflowObserver!: IntersectionObserver;
private _tabListResizeObserver!: ResizeObserver;

Expand Down Expand Up @@ -102,7 +121,7 @@ export class PharosTabs extends PharosElement {
this._tabListResizeObserver = new ResizeObserver((entries) => {
entries.forEach((entry) => {
if (entry.target === this._tabList) {
this._makeTabVisible(this._selectedTabs[0]);
this._makeTabVisible(this._tabs[this.selectedTab]);
}
});
});
Expand All @@ -116,9 +135,16 @@ export class PharosTabs extends PharosElement {
}

private _selectInitialTab(): void {
const selected: PharosTab | null = this.querySelector(`${_allTabsSelector}[selected]`);
const selectedTab: PharosTab = selected || this._tabs[0];
this._handleTabSelected(selectedTab);
const selectedTab: PharosTab = this._tabs[this.selectedTab];
selectedTab.selected = true;
this._makeTabVisible(selectedTab);

const selectedPanel: PharosTabPanel | null = this.querySelector(
`${_allTabPanelsSelector}[id="${selectedTab.getAttribute('aria-controls')}"]`
);
if (selectedPanel) {
selectedPanel.selected = true;
}
}

private _queryPanelByTab(tab: PharosTab): PharosTabPanel | null {
Expand All @@ -127,7 +153,12 @@ export class PharosTabs extends PharosElement {
return this.querySelector(`#${panelId}`);
}

private _findTabIndex(tabToFind: PharosTab): number {
return Array.from(this._tabs).findIndex((tab: PharosTab) => tab.id === tabToFind.id);
}

private _handleTabSelected(selectedTab: PharosTab): void {
this.selectedTab = this._findTabIndex(selectedTab);
selectedTab.selected = true;
this._makeTabVisible(selectedTab);

Expand Down
22 changes: 12 additions & 10 deletions packages/pharos/src/components/tabs/pharos-tabs.wc.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ export const Base = {
export const Events = {
render: () =>
html`
<pharos-tabs @pharos-tab-selected="${(e) => action('Selected')(e.target.id)}">
<pharos-tab id="tab-1" data-panel-id="panel-1">Tab 1</pharos-tab>
<pharos-tab id="tab-2" data-panel-id="panel-2">Tab 2</pharos-tab>
<pharos-tab id="tab-3" data-panel-id="panel-3" selected>Tab 3</pharos-tab>
<pharos-tab-panel id="panel-1" slot="panel">Panel 1</pharos-tab-panel>
<pharos-tab-panel id="panel-2" slot="panel">Panel 2</pharos-tab-panel>
<pharos-tab-panel id="panel-3" slot="panel">Panel 3</pharos-tab-panel>
</pharos-tabs>
<div @pharos-tabs-tab-selected="${(e) => action('Selected')(e.detail.id)}">
<pharos-tabs selected-tab="2">
<pharos-tab id="tab-1" data-panel-id="panel-1">Tab 1</pharos-tab>
<pharos-tab id="tab-2" data-panel-id="panel-2">Tab 2</pharos-tab>
<pharos-tab id="tab-3" data-panel-id="panel-3">Tab 3</pharos-tab>
<pharos-tab-panel id="panel-1" slot="panel">Panel 1</pharos-tab-panel>
<pharos-tab-panel id="panel-2" slot="panel">Panel 2</pharos-tab-panel>
<pharos-tab-panel id="panel-3" slot="panel">Panel 3</pharos-tab-panel>
</pharos-tabs>
</div>
`,
parameters: { options: { selectedPanel: 'addon-controls' } },
};
Expand Down Expand Up @@ -85,14 +87,14 @@ export const PanelSeparator = {
export const HorizontalScrolling = {
render: () =>
html`
<pharos-tabs panel-separator style="width: 100%">
<pharos-tabs selected-tab="6" panel-separator style="width: 100%">
<pharos-tab id="tab-1" data-panel-id="panel-1">Tab 1</pharos-tab>
<pharos-tab id="tab-2" data-panel-id="panel-2">Tab 2</pharos-tab>
<pharos-tab id="tab-3" data-panel-id="panel-3">Tab 3</pharos-tab>
<pharos-tab id="tab-4" data-panel-id="panel-4">Tab 4</pharos-tab>
<pharos-tab id="tab-5" data-panel-id="panel-5">Tab 5</pharos-tab>
<pharos-tab id="tab-6" data-panel-id="panel-6">Tab 6</pharos-tab>
<pharos-tab id="tab-7" data-panel-id="panel-7" selected>Tab 7</pharos-tab>
<pharos-tab id="tab-7" data-panel-id="panel-7">Tab 7</pharos-tab>
<pharos-tab id="tab-8" data-panel-id="panel-8">Tab 8</pharos-tab>
<pharos-tab id="tab-9" data-panel-id="panel-9">Tab 9</pharos-tab>
<pharos-tab-panel id="panel-1" slot="panel"
Expand Down

0 comments on commit 1913341

Please sign in to comment.