---
// Interactive island template. Use ONLY when the component genuinely needs
// client-side behaviour, and write the justification in your PR description.
//
// Islands are LEAVES. Do not wrap static children that could have been
// server-rendered — hydrate the tab panel, not the page.
//
// Hydration preference, in order:
//   (none) → client:visible → client:idle → client:load
//
// Usage:  <Island client:visible items={items} />

interface Props {
  items: { id: string; label: string; body: string }[];
  initialId?: string;
}

const { items, initialId = items[0]?.id } = Astro.props;
---

<div class="island" data-initial={initialId}>
  <div class="tabs" role="tablist" aria-label="Sections">
    {
      items.map((item) => (
        <button
          role="tab"
          id={`tab-${item.id}`}
          aria-controls={`panel-${item.id}`}
          aria-selected={item.id === initialId}
          data-tab={item.id}
        >
          {item.label}
        </button>
      ))
    }
  </div>
  {
    items.map((item) => (
      <div
        role="tabpanel"
        id={`panel-${item.id}`}
        aria-labelledby={`tab-${item.id}`}
        data-panel={item.id}
        hidden={item.id !== initialId}
      >
        {item.body}
      </div>
    ))
  }
</div>

<script>
  // Scoped to this island's own root so multiple instances never collide.
  document.querySelectorAll<HTMLElement>('.island').forEach((root) => {
    const tabs = root.querySelectorAll<HTMLButtonElement>('[data-tab]');
    const select = (id: string) => {
      tabs.forEach((tab) => tab.setAttribute('aria-selected', String(tab.dataset.tab === id)));
      root.querySelectorAll<HTMLElement>('[data-panel]').forEach((panel) => {
        panel.hidden = panel.dataset.panel !== id;
      });
    };
    tabs.forEach((tab) => tab.addEventListener('click', () => select(tab.dataset.tab!)));

    // Arrow-key navigation is required for role="tablist" — see
    // .agents/rules/accessibility.md
    root.querySelector('[role="tablist"]')?.addEventListener('keydown', (event) => {
      const key = (event as KeyboardEvent).key;
      if (key !== 'ArrowRight' && key !== 'ArrowLeft') return;
      const list = [...tabs];
      const current = list.findIndex((tab) => tab.getAttribute('aria-selected') === 'true');
      const next = list[(current + (key === 'ArrowRight' ? 1 : -1) + list.length) % list.length];
      select(next.dataset.tab!);
      next.focus();
    });
  });
</script>

<style>
  .tabs {
    display: grid;
    gap: 8px;
  }

  button {
    padding: 12px;
    color: var(--ink);
    background: transparent;
    border: 1px solid var(--line);
    text-align: left;
    cursor: pointer;
    /* transform/opacity only — never animate layout properties */
    transition: background 180ms cubic-bezier(0.2, 0, 0, 1);
  }

  button[aria-selected='true'] {
    color: var(--paper);
    background: var(--ink);
  }

  button:focus-visible {
    outline: 3px solid var(--red);
    outline-offset: 2px;
  }

  @media (prefers-reduced-motion: reduce) {
    button {
      transition-duration: 0.01ms;
    }
  }
</style>
