Skip to content

Commit f059c0f

Browse files
reset redundant files
1 parent 71e02b0 commit f059c0f

File tree

3 files changed

+54
-147
lines changed

3 files changed

+54
-147
lines changed

packages/components/src/components/post-tab-header/post-tab-header.tsx

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { checkRequiredAndType } from '@/utils';
44
import { nanoid } from 'nanoid';
55

66
/**
7-
* @slot default - Slot for the content of the tab header. Can contain text or an <a> element for navigation mode.
7+
* @slot default - Slot for the content of the tab header.
88
*/
99

1010
@Component({
@@ -16,53 +16,34 @@ export class PostTabHeader {
1616
@Element() host: HTMLPostTabHeaderElement;
1717

1818
@State() tabId: string;
19-
@State() isNavigationMode = false;
2019

2120
/**
22-
* The name of the tab, used to associate it with a tab panel or identify the active tab in navigation mode.
21+
* The name of the panel controlled by the tab header.
2322
*/
24-
@Prop({ reflect: true }) readonly name!: string;
23+
@Prop({ reflect: true }) readonly panel!: string;
2524

26-
@Watch('name')
27-
validateName() {
28-
checkRequiredAndType(this, 'name', 'string');
25+
@Watch('panel')
26+
validateFor() {
27+
checkRequiredAndType(this, 'panel', 'string');
2928
}
3029

3130
componentWillLoad() {
3231
this.tabId = `tab-${this.host.id || nanoid(6)}`;
33-
this.checkNavigationMode();
34-
}
35-
36-
componentDidLoad() {
37-
// Re-check navigation mode after content is loaded
38-
this.checkNavigationMode();
39-
}
40-
41-
private checkNavigationMode() {
42-
const hasAnchor = this.host.querySelector('a') !== null;
43-
this.isNavigationMode = hasAnchor;
44-
45-
// Expose mode to parent post-tabs via data-attribute (as per requirements)
46-
this.host.setAttribute('data-navigation-mode', this.isNavigationMode.toString());
4732
}
4833

4934
render() {
50-
const role = this.isNavigationMode ? undefined : 'tab';
51-
const ariaSelected = this.isNavigationMode ? undefined : 'false';
52-
const tabindex = this.isNavigationMode ? undefined : '-1';
53-
5435
return (
5536
<Host
5637
id={this.tabId}
57-
role={role}
38+
role="tab"
5839
data-version={version}
59-
aria-selected={ariaSelected}
60-
tabindex={tabindex}
40+
aria-selected="false"
41+
tabindex="-1"
6142
class="tab-title"
6243
slot="tabs"
6344
>
6445
<slot />
6546
</Host>
6647
);
6748
}
68-
}
49+
}

packages/components/src/components/post-tab-panel/post-tab-panel.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ export class PostTabPanel {
1818
@State() panelId: string;
1919

2020
/**
21-
* The name of the tab that this panel is associated with.
21+
* The name of the panel, used to associate it with a tab header.
2222
*/
23-
@Prop({ reflect: true }) readonly for!: string;
23+
@Prop({ reflect: true }) readonly name!: string;
2424

25-
@Watch('for')
26-
validateFor() {
27-
checkRequiredAndType(this, 'for', 'string');
25+
@Watch('name')
26+
validateName() {
27+
checkRequiredAndType(this, 'name', 'string');
2828
}
2929
componentWillLoad() {
30-
this.validateFor();
30+
this.validateName();
3131
// get the id set on the host element or use a random id by default
3232
this.panelId = `panel-${this.host.id || nanoid(6)}`;
3333
}
@@ -39,4 +39,4 @@ export class PostTabPanel {
3939
</Host>
4040
);
4141
}
42-
}
42+
}
Lines changed: 37 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Element, Event, EventEmitter, h, Host, Method, Prop, State } from '@stencil/core';
1+
import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';
22
import { version } from '@root/package.json';
33
import { fadeIn, fadeOut } from '@/animations';
44
import { componentOnReady } from '@/utils';
@@ -16,34 +16,26 @@ import { componentOnReady } from '@/utils';
1616
shadow: true,
1717
})
1818
export class PostTabs {
19-
private currentActiveTab: HTMLPostTabHeaderElement;
19+
private activeTab: HTMLPostTabHeaderElement;
2020
private showing: Animation;
2121
private hiding: Animation;
2222
private isLoaded = false;
2323

24-
@State() isNavigationMode: boolean = false;
25-
2624
private get tabs(): HTMLPostTabHeaderElement[] {
2725
return Array.from(
2826
this.host.querySelectorAll<HTMLPostTabHeaderElement>('post-tab-header'),
2927
).filter(tab => tab.closest('post-tabs') === this.host);
3028
}
3129

32-
private get panels(): HTMLPostTabPanelElement[] {
33-
return Array.from(
34-
this.host.querySelectorAll<HTMLPostTabPanelElement>('post-tab-panel'),
35-
).filter(panel => panel.closest('post-tabs') === this.host);
36-
}
37-
3830
@Element() host: HTMLPostTabsElement;
3931

4032
/**
41-
* The name of the tab that is initially active.
42-
* If not specified, it defaults to the first tab.
33+
* The name of the panel that is initially shown.
34+
* If not specified, it defaults to the panel associated with the first tab.
4335
*
4436
* **Changing this value after initialization has no effect.**
4537
*/
46-
@Prop() readonly activeTab?: string;
38+
@Prop() readonly activePanel?: HTMLPostTabPanelElement['name'];
4739

4840
/**
4941
* When set to true, this property allows the tabs container to span the
@@ -53,78 +45,45 @@ export class PostTabs {
5345

5446
/**
5547
* An event emitted after the active tab changes, when the fade in transition of its associated panel is finished.
56-
* The payload is the name of the newly active tab.
48+
* The payload is the name of the newly shown panel.
5749
*/
5850
@Event() postChange: EventEmitter<string>;
5951

6052
componentDidLoad() {
61-
this.detectMode();
6253
this.moveMisplacedTabs();
6354
this.enableTabs();
6455

65-
const initiallyActiveTab = this.activeTab || this.tabs[0]?.getAttribute('name');
66-
void this.show(initiallyActiveTab);
56+
const initiallyActivePanel = this.activePanel || this.tabs[0]?.panel;
57+
void this.show(initiallyActivePanel);
6758

6859
this.isLoaded = true;
6960
}
7061

71-
private detectMode() {
72-
// Check if any tab headers contain anchor elements (via data-attribute exposure)
73-
const hasNavigationTabs = this.tabs.some(tab =>
74-
tab.getAttribute('data-navigation-mode') === 'true'
75-
);
76-
77-
// Check if there are any panels
78-
const hasPanels = this.panels.length > 0;
79-
80-
// Validate for mixed mode (error condition)
81-
if (hasNavigationTabs && hasPanels) {
82-
console.error('PostTabs: Mixed mode detected. Cannot use both navigation mode (anchor elements) and panel mode (post-tab-panel elements) at the same time.');
83-
return;
84-
}
85-
86-
this.isNavigationMode = hasNavigationTabs;
87-
}
88-
8962
/**
9063
* Shows the panel with the given name and selects its associated tab.
91-
* In navigation mode, only updates the active tab state.
9264
* Any other panel that was previously shown becomes hidden and its associated tab is unselected.
9365
*/
9466
@Method()
95-
async show(tabName: string) {
67+
async show(panelName: string) {
9668
// do nothing if the tab is already active
97-
if (tabName === this.currentActiveTab?.getAttribute('name')) {
69+
if (panelName === this.activeTab?.panel) {
9870
return;
9971
}
10072

101-
const previousTab = this.currentActiveTab;
73+
const previousTab = this.activeTab;
10274
const newTab: HTMLPostTabHeaderElement = this.host.querySelector(
103-
`post-tab-header[name=${tabName}]`,
75+
`post-tab-header[panel=${panelName}]`,
10476
);
105-
106-
if (!newTab) {
107-
console.warn(`PostTabs: No tab found with name "${tabName}"`);
108-
return;
109-
}
110-
111-
await this.activateTab(newTab);
77+
this.activateTab(newTab);
11278

113-
// In navigation mode, we don't need to handle panels
114-
if (this.isNavigationMode) {
115-
if (this.isLoaded) this.postChange.emit(this.currentActiveTab.getAttribute('name'));
116-
return;
117-
}
118-
119-
// Panel mode logic
12079
// if a panel is currently being displayed, remove it from the view and complete the associated animation
12180
if (this.showing) {
12281
this.showing.effect['target'].style.display = 'none';
12382
this.showing.finish();
12483
}
12584

12685
// hide the currently visible panel only if no other animation is running
127-
if (previousTab && !this.showing && !this.hiding) this.hidePanel(previousTab.getAttribute('name'));
86+
if (previousTab && !this.showing && !this.hiding) this.hidePanel(previousTab.panel);
12887

12988
// wait for any hiding animation to complete before showing the selected tab
13089
if (this.hiding) await this.hiding.finished;
@@ -134,7 +93,7 @@ export class PostTabs {
13493
// wait for any display animation to complete for the returned promise to fully resolve
13594
if (this.showing) await this.showing.finished;
13695

137-
if (this.isLoaded) this.postChange.emit(this.currentActiveTab.getAttribute('name'));
96+
if (this.isLoaded) this.postChange.emit(this.activeTab.panel);
13897
}
13998

14099
private moveMisplacedTabs() {
@@ -152,29 +111,21 @@ export class PostTabs {
152111
this.tabs.forEach(async tab => {
153112
await componentOnReady(tab);
154113

155-
// Skip tab setup in navigation mode - anchors handle their own navigation
156-
if (this.isNavigationMode) {
157-
return;
158-
}
159-
160-
// Panel mode: set up tab-panel relationships
161114
// if the tab has an "aria-controls" attribute it was already linked to its panel: do nothing
162115
if (tab.getAttribute('aria-controls')) return;
163116

164-
const tabPanel = this.getPanel(tab.getAttribute('name'));
165-
if (tabPanel) {
166-
tab.setAttribute('aria-controls', tabPanel.id);
167-
tabPanel.setAttribute('aria-labelledby', tab.id);
168-
}
117+
const tabPanel = this.getPanel(tab.panel);
118+
tab.setAttribute('aria-controls', tabPanel.id);
119+
tabPanel.setAttribute('aria-labelledby', tab.id);
169120

170121
tab.addEventListener('click', () => {
171-
void this.show(tab.getAttribute('name'));
122+
void this.show(tab.panel);
172123
});
173124

174125
tab.addEventListener('keydown', (e: KeyboardEvent) => {
175126
if (e.key === 'Enter' || e.key === ' ') {
176127
e.preventDefault();
177-
void this.show(tab.getAttribute('name'));
128+
void this.show(tab.panel);
178129
}
179130
});
180131

@@ -184,37 +135,23 @@ export class PostTabs {
184135
});
185136

186137
// if the currently active tab was removed from the DOM then select the first one
187-
if (this.currentActiveTab && !this.currentActiveTab.isConnected) {
188-
void this.show(this.tabs[0]?.getAttribute('name'));
138+
if (this.activeTab && !this.activeTab.isConnected) {
139+
void this.show(this.tabs[0]?.panel);
189140
}
190141
}
191142

192-
private async activateTab(tab: HTMLPostTabHeaderElement) {
193-
// Deactivate previous tab
194-
if (this.currentActiveTab) {
195-
this.currentActiveTab.setAttribute('aria-selected', 'false');
196-
this.currentActiveTab.setAttribute('tabindex', '-1');
197-
this.currentActiveTab.classList.remove('active');
198-
199-
// Remove aria-current from previous tab's anchor (navigation mode)
200-
const previousAnchor = this.currentActiveTab.querySelector('a');
201-
if (previousAnchor) {
202-
previousAnchor.removeAttribute('aria-current');
203-
}
143+
private activateTab(tab: HTMLPostTabHeaderElement) {
144+
if (this.activeTab) {
145+
this.activeTab.setAttribute('aria-selected', 'false');
146+
this.activeTab.setAttribute('tabindex', '-1');
147+
this.activeTab.classList.remove('active');
204148
}
205149

206-
// Activate new tab
207150
tab.setAttribute('aria-selected', 'true');
208151
tab.setAttribute('tabindex', '0');
209152
tab.classList.add('active');
210-
211-
// Set aria-current on new tab's anchor (navigation mode)
212-
const newAnchor = tab.querySelector('a');
213-
if (newAnchor) {
214-
newAnchor.setAttribute('aria-current', 'page');
215-
}
216153

217-
this.currentActiveTab = tab;
154+
this.activeTab = tab;
218155
}
219156

220157
private hidePanel(panelName: HTMLPostTabPanelElement['name']) {
@@ -230,7 +167,7 @@ export class PostTabs {
230167
}
231168

232169
private showSelectedPanel() {
233-
const panel = this.getPanel(this.currentActiveTab.getAttribute('name'));
170+
const panel = this.getPanel(this.activeTab.panel);
234171
panel.style.display = 'block';
235172

236173
// prevent the initially selected panel from fading in
@@ -243,7 +180,7 @@ export class PostTabs {
243180
}
244181

245182
private getPanel(name: string): HTMLPostTabPanelElement {
246-
return this.host.querySelector(`post-tab-panel[for=${name}]`);
183+
return this.host.querySelector(`post-tab-panel[name=${name}]`);
247184
}
248185

249186
private navigateTabs(tab: HTMLPostTabHeaderElement, key: 'ArrowRight' | 'ArrowLeft') {
@@ -262,28 +199,17 @@ export class PostTabs {
262199
}
263200

264201
render() {
265-
const tabsRole = this.isNavigationMode ? undefined : 'tablist';
266-
const ariaLabel = this.isNavigationMode ? 'Tabs navigation' : undefined;
267-
268202
return (
269203
<Host data-version={version}>
270204
<div class="tabs-wrapper" part="tabs">
271-
{this.isNavigationMode ? (
272-
<nav class="tabs" role={tabsRole} aria-label={ariaLabel}>
273-
<slot name="tabs" onSlotchange={() => this.enableTabs()} />
274-
</nav>
275-
) : (
276-
<div class="tabs" role={tabsRole} aria-label={ariaLabel}>
277-
<slot name="tabs" onSlotchange={() => this.enableTabs()} />
278-
</div>
279-
)}
280-
</div>
281-
{!this.isNavigationMode && (
282-
<div class="tab-content" part="content">
283-
<slot onSlotchange={() => this.moveMisplacedTabs()} />
205+
<div class="tabs" role="tablist">
206+
<slot name="tabs" onSlotchange={() => this.enableTabs()} />
284207
</div>
285-
)}
208+
</div>
209+
<div class="tab-content" part="content">
210+
<slot onSlotchange={() => this.moveMisplacedTabs()} />
211+
</div>
286212
</Host>
287213
);
288214
}
289-
}
215+
}

0 commit comments

Comments
 (0)