{"version":3,"file":"BqTabs-b0BpUDTD.cjs","names":[],"sources":["../src/components/tabs/BqTabs.ts"],"sourcesContent":["/**\r\n * Tabs navigation component.\r\n * @element bq-tabs\r\n * @prop {string} active-tab - ID of active tab\r\n * @prop {string} variant    - default | pills | underline\r\n * Tabs: add elements with [data-tab-item] and id attribute; panels: [data-tab=\"<id>\"]\r\n * @fires bq-tab-change - { tabId: string }\r\n */\r\nimport type { ComponentDefinition } from '@bquery/bquery/component';\r\nimport { component, html } from '@bquery/bquery/component';\r\nimport { escapeHtml } from '@bquery/bquery/security';\r\nimport { t } from '../../i18n/index.js';\r\nimport { getBaseStyles } from '../../utils/styles.js';\r\n\r\ntype BqTabsProps = { 'active-tab': string; variant: string };\r\n\r\nfunction getAriaIdPart(tabId: string): string | null {\r\n  const trimmed = tabId.trim();\r\n  return trimmed ? encodeURIComponent(trimmed) : null;\r\n}\r\n\r\nfunction getTabButtonId(tabId: string): string | null {\r\n  const ariaIdPart = getAriaIdPart(tabId);\r\n  return ariaIdPart ? `tab-${ariaIdPart}` : null;\r\n}\r\n\r\nfunction getPanelId(tabId: string): string | null {\r\n  const ariaIdPart = getAriaIdPart(tabId);\r\n  return ariaIdPart ? `panel-${ariaIdPart}` : null;\r\n}\r\n\r\nconst definition: ComponentDefinition<BqTabsProps> = {\r\n  props: {\r\n    'active-tab': { type: String, default: '' },\r\n    variant: { type: String, default: 'default' },\r\n  },\r\n  styles: `\r\n    ${getBaseStyles()}\r\n    *, *::before, *::after { box-sizing: border-box; }\r\n    :host { display: block; }\r\n    .tabs { display: flex; flex-direction: column; }\r\n    .tablist { display: flex; gap: 0.25rem; }\r\n    .tablist[data-variant=\"default\"] { background: var(--bq-bg-subtle,#f8fafc); border-radius: var(--bq-radius-lg); padding: 0.25rem; }\r\n    .tablist[data-variant=\"underline\"] { border-bottom: 2px solid var(--bq-border-base,#e2e8f0); }\r\n    .tab {\r\n      display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;\r\n      font-size: var(--bq-font-size-sm,0.875rem); font-weight: var(--bq-font-weight-medium,500);\r\n      font-family: var(--bq-font-family-sans); cursor: pointer; background: none; border: none;\r\n      color: var(--bq-text-muted,#475569); white-space: nowrap;\r\n      transition: all var(--bq-duration-fast) var(--bq-easing-standard);\r\n    }\r\n    .tab[data-variant=\"default\"]  { padding: 0.375rem 0.875rem; border-radius: var(--bq-radius-md,0.375rem); }\r\n    .tab[data-variant=\"underline\"] { padding: 0.625rem 1rem; border-bottom: 2px solid transparent; margin-bottom: -2px; border-radius: 0; }\r\n    .tab[data-variant=\"pills\"]    { padding: 0.375rem 0.875rem; border-radius: var(--bq-radius-full,9999px); }\r\n    .tab:hover:not([disabled]):not([aria-selected=\"true\"]) { color: var(--bq-text-base,#0f172a); }\r\n    .tab[data-variant=\"default\"]:hover:not([disabled]):not([aria-selected=\"true\"]) { background: var(--bq-bg-emphasis,#e2e8f0); }\r\n    .tab[aria-selected=\"true\"][data-variant=\"default\"]   { background: var(--bq-bg-base,#fff); box-shadow: var(--bq-shadow-sm); color: var(--bq-color-primary-600,#2563eb); }\r\n    .tab[aria-selected=\"true\"][data-variant=\"underline\"] { border-bottom-color: var(--bq-color-primary-600,#2563eb); color: var(--bq-color-primary-600,#2563eb); }\r\n    .tab[aria-selected=\"true\"][data-variant=\"pills\"]     { background: var(--bq-color-primary-600,#2563eb); color: #fff; }\r\n    .tab[disabled] { opacity: 0.45; cursor: not-allowed; }\r\n    .tab:focus-visible { outline: 2px solid transparent; box-shadow: var(--bq-focus-ring); }\r\n    .panels { padding-top: var(--bq-space-4,1rem); }\r\n    @media (prefers-reduced-motion: reduce) {\r\n      .tab { transition: none; }\r\n    }\r\n  `,\r\n  connected() {\r\n    type BQEl = HTMLElement & {\r\n      setState(k: string, v: unknown): void;\r\n      getState<T>(k: string): T;\r\n    };\r\n    const self = this as unknown as BQEl &\r\n      HTMLElement &\r\n      Record<string, unknown>;\r\n\r\n    const readTabs = () => {\r\n      const items = Array.from(\r\n        (self as HTMLElement).querySelectorAll('[data-tab-item]')\r\n      ).map((el) => ({\r\n        id: el.getAttribute('id') ?? el.getAttribute('data-tab-item') ?? '',\r\n        label: el.getAttribute('label') ?? el.textContent?.trim() ?? '',\r\n        disabled: el.hasAttribute('disabled'),\r\n      }));\r\n      self.setState('tabs', items);\r\n    };\r\n    readTabs();\r\n\r\n    // MutationObserver to re-render when child items change\r\n    const obs = new MutationObserver(() => {\r\n      readTabs();\r\n      // Trigger re-render by touching an attribute\r\n      const cur = (self as HTMLElement).getAttribute('active-tab') ?? '';\r\n      (self as HTMLElement).setAttribute('active-tab', cur);\r\n    });\r\n    obs.observe(self as HTMLElement, {\r\n      childList: true,\r\n      subtree: true,\r\n      attributes: true,\r\n      attributeFilter: ['label', 'disabled', 'id'],\r\n    });\r\n    self['_obs'] = obs;\r\n\r\n    const clickH = (e: Event) => {\r\n      const btn = (e.target as Element).closest(\r\n        '[data-tab-id]'\r\n      ) as HTMLElement | null;\r\n      if (!btn || btn.hasAttribute('disabled')) return;\r\n      const tabId = btn.getAttribute('data-tab-id') ?? '';\r\n      (self as HTMLElement).setAttribute('active-tab', tabId);\r\n      (self as HTMLElement).dispatchEvent(\r\n        new CustomEvent('bq-tab-change', {\r\n          detail: { tabId },\r\n          bubbles: true,\r\n          composed: true,\r\n        })\r\n      );\r\n      updatePanels(tabId);\r\n    };\r\n    const keyH = (e: Event) => {\r\n      const ke = e as KeyboardEvent;\r\n      const shadow = (self as HTMLElement).shadowRoot;\r\n      const tablist = shadow?.querySelector('.tablist');\r\n      if (!tablist) return;\r\n      const btns = Array.from(\r\n        tablist.querySelectorAll<HTMLElement>('.tab:not([disabled])')\r\n      );\r\n      // Use shadowRoot.activeElement — document.activeElement returns the host in shadow DOM\r\n      const active = shadow?.activeElement as HTMLElement | null;\r\n      const idx = btns.findIndex((b) => b === active);\r\n      let next = -1;\r\n      if (ke.key === 'ArrowRight') next = (idx + 1) % btns.length;\r\n      if (ke.key === 'ArrowLeft') next = (idx - 1 + btns.length) % btns.length;\r\n      if (ke.key === 'Home') next = 0;\r\n      if (ke.key === 'End') next = btns.length - 1;\r\n      if (next >= 0) {\r\n        ke.preventDefault();\r\n        btns[next]?.focus();\r\n        btns[next]?.click();\r\n      }\r\n    };\r\n    const updatePanels = (activeId: string) => {\r\n      (self as HTMLElement)\r\n        .querySelectorAll<HTMLElement>('[data-tab]')\r\n        .forEach((panel) => {\r\n          panel.hidden = panel.getAttribute('data-tab') !== activeId;\r\n        });\r\n    };\r\n    self['_clickH'] = clickH;\r\n    self['_keyH'] = keyH;\r\n    (self as HTMLElement).shadowRoot?.addEventListener('click', clickH);\r\n    (self as HTMLElement).shadowRoot?.addEventListener('keydown', keyH);\r\n  },\r\n  disconnected() {\r\n    const s = this as unknown as Record<string, unknown>;\r\n    const obs = s['_obs'] as MutationObserver | undefined;\r\n    if (obs) obs.disconnect();\r\n    const ch = s['_clickH'] as EventListener | undefined;\r\n    if (ch) this.shadowRoot?.removeEventListener('click', ch);\r\n    const kh = s['_keyH'] as EventListener | undefined;\r\n    if (kh) this.shadowRoot?.removeEventListener('keydown', kh);\r\n  },\r\n  updated() {\r\n    // Sync panel visibility after each render\r\n    const active = this.getAttribute('active-tab') ?? '';\r\n    this.querySelectorAll<HTMLElement>('[data-tab]').forEach((panel) => {\r\n      const tabId = panel.getAttribute('data-tab') ?? '';\r\n      const isActive = tabId === active;\r\n      const panelId = panel.id || getPanelId(tabId);\r\n      const button = Array.from(\r\n        this.shadowRoot?.querySelectorAll<HTMLElement>('.tab[data-tab-id]') ?? []\r\n      ).find((candidate) => candidate.getAttribute('data-tab-id') === tabId);\r\n      const labelledBy = button?.id || (button ? getTabButtonId(tabId) : null);\r\n\r\n      if (panelId) {\r\n        panel.id = panelId;\r\n      }\r\n      panel.hidden = !isActive;\r\n      panel.setAttribute('role', 'tabpanel');\r\n      panel.setAttribute('tabindex', isActive ? '0' : '-1');\r\n      if (labelledBy) {\r\n        panel.setAttribute('aria-labelledby', labelledBy);\r\n      } else {\r\n        panel.removeAttribute('aria-labelledby');\r\n      }\r\n      panel.setAttribute('aria-hidden', isActive ? 'false' : 'true');\r\n      if (button) {\r\n        if (panelId) {\r\n          button.setAttribute('aria-controls', panelId);\r\n        } else {\r\n          button.removeAttribute('aria-controls');\r\n        }\r\n      }\r\n    });\r\n  },\r\n  render({ props, state }) {\r\n    const items =\r\n      (state['tabs'] as\r\n        | Array<{ id: string; label: string; disabled: boolean }>\r\n        | undefined) ?? [];\r\n    const active = props['active-tab'] || items[0]?.id || '';\r\n    const tabsHtml = items\r\n      .map((tab) => {\r\n        const buttonId = getTabButtonId(tab.id);\r\n        const panelId = getPanelId(tab.id);\r\n        return `\r\n       <button part=\"tab\" class=\"tab\" data-variant=\"${escapeHtml(props.variant)}\"\r\n        role=\"tab\" ${buttonId ? `id=\"${escapeHtml(buttonId)}\"` : ''} data-tab-id=\"${escapeHtml(tab.id)}\"\r\n        aria-selected=\"${tab.id === active ? 'true' : 'false'}\"\r\n        ${panelId ? `aria-controls=\"${escapeHtml(panelId)}\"` : ''}\r\n        tabindex=\"${tab.id === active ? '0' : '-1'}\"\r\n        ${tab.disabled ? 'disabled aria-disabled=\"true\"' : ''}\r\n      >${escapeHtml(tab.label)}</button>\r\n    `;\r\n      })\r\n      .join('');\r\n    return html`\r\n      <div class=\"tabs\" part=\"tabs\">\r\n        <div\r\n          class=\"tablist\"\r\n          part=\"tablist\"\r\n          role=\"tablist\"\r\n          aria-label=\"${t('tabs.listLabel')}\"\r\n          data-variant=\"${escapeHtml(props.variant)}\"\r\n        >\r\n          ${tabsHtml}\r\n        </div>\r\n        <div class=\"panels\" part=\"panels\"><slot></slot></div>\r\n      </div>\r\n    `;\r\n  },\r\n};\r\n\r\ncomponent<BqTabsProps>('bq-tabs', definition);\r\n"],"mappings":"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"}