import { LitElement, html, css } from 'lit'; import { customElement } from 'lit/decorators.js'; import type { LitroTabItem } from './litro-tab-item.js'; /** * * Content A * Content B * * * Reads slotted elements via the slotchange event. * Renders a tab bar in Shadow DOM; clicking selects the tab. */ @customElement('litro-tabs') export class LitroTabs extends LitElement { static override properties = { _labels: { type: Array, state: true }, _selectedIndex: { type: Number, state: true }, }; static override styles = css` :host { display: block; margin: 1.5rem 0; } .tab-bar { display: flex; gap: 0; border-bottom: 2px solid var(--sl-color-border, #e8e8e8); overflow-x: auto; } .tab-btn { appearance: none; background: none; border: none; padding: 0.5rem 1rem; font: inherit; font-size: var(--sl-text-sm, 0.875rem); font-weight: 500; cursor: pointer; color: var(--sl-color-gray-4, #757575); border-bottom: 2px solid transparent; margin-bottom: -2px; white-space: nowrap; transition: color 0.15s, border-color 0.15s; } .tab-btn:hover { color: var(--sl-color-text, #23262f); } .tab-btn[aria-selected='true'] { color: var(--sl-color-accent, #7c3aed); border-bottom-color: var(--sl-color-accent, #7c3aed); } .tab-content { padding-top: 1rem; } `; _labels: string[] = []; _selectedIndex = 0; private _items(): LitroTabItem[] { const slot = this.shadowRoot?.querySelector('slot'); if (!slot) return []; return slot.assignedElements().filter( (el): el is LitroTabItem => el.tagName.toLowerCase() === 'litro-tab-item', ); } private _onSlotChange() { const items = this._items(); this._labels = items.map((item) => item.label || `Tab ${items.indexOf(item) + 1}`); this._selectIndex(this._selectedIndex < items.length ? this._selectedIndex : 0, items); } private _selectIndex(index: number, items?: LitroTabItem[]) { const all = items ?? this._items(); this._selectedIndex = index; all.forEach((item, i) => { item.selected = i === index; }); } override render() { return html`
${this._labels.map((label, i) => html` `)}
`; } } export default LitroTabs;