import{x as l,i as v}from"./iframe-CMPv_g6-.js";import{t as m}from"./custom-element-UsVr97OX.js";import"./preload-helper-PPVm8Dsz.js";const h=n=>{class i extends n{constructor(){super(...arguments),this._rovingIndex=0}_getRovingTargets(){return[]}_rovingFocus(t,e=!0){const o=this._getRovingTargets();if(o.length===0)return;const r=Math.max(0,Math.min(t,o.length-1));o.forEach((u,b)=>u.setAttribute("tabindex",b===r?"0":"-1")),e&&o[r]?.focus(),this._rovingIndex=r}_rovingNext(){const t=this._getRovingTargets();if(t.length===0)return;const e=this._rovingCurrentIndex(),o=e<t.length-1?e+1:0;this._rovingFocus(o)}_rovingPrev(){const t=this._getRovingTargets();if(t.length===0)return;const e=this._rovingCurrentIndex(),o=e>0?e-1:t.length-1;this._rovingFocus(o)}_rovingFirst(){this._rovingFocus(0)}_rovingLast(){const t=this._getRovingTargets();t.length>0&&this._rovingFocus(t.length-1)}_rovingCurrentIndex(){const t=document.activeElement;return this._getRovingTargets().findIndex(e=>e===t||e.contains(t))}}return i};var a=Object.freeze,x=Object.defineProperty,p=Object.getOwnPropertyDescriptor,f=(n,i,d,t)=>{for(var e=t>1?void 0:t?p(i,d):i,o=n.length-1,r;o>=0;o--)(r=n[o])&&(e=r(e)||e);return e},y=(n,i)=>a(x(n,"raw",{value:a(n.slice())})),c;const T={title:"Mixins/Roving Tabindex",tags:["autodocs"],parameters:{docs:{description:{component:`
\`RovingTabindexMixin\` provides **roving tabindex** navigation primitives for toolbar and menu components following the <a href="https://www.w3.org/WAI/ARIA/apd/practices/keyboard-interface/#kbd_roving_tabindex" target="_blank">WAI-ARIA Keyboard Interface Pattern</a>.

In a roving tabindex, only one element in the group has \`tabindex="0"\` (reachable via Tab), while all others have \`tabindex="-1"\`. Arrow keys move focus between items, wrapping at both ends.

<h3>What RovingTabindexMixin Provides</h3>

<table>
  <thead>
    <tr>
      <th>Member</th>
      <th>Type</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>_getRovingTargets()</code></td>
      <td>Method (override)</td>
      <td>Return focusable <code>HTMLElement[]</code> in navigation order. <strong>Subclass must override.</strong></td>
    </tr>
    <tr>
      <td><code>_rovingFocus(index, shouldFocus?)</code></td>
      <td>Method</td>
      <td>Set <code>tabindex="0"</code> on target at index, <code>"-1"</code> on all others. Focuses the element unless <code>shouldFocus=false</code>.</td>
    </tr>
    <tr>
      <td><code>_rovingNext()</code></td>
      <td>Method</td>
      <td>Move focus to next target (wraps to first)</td>
    </tr>
    <tr>
      <td><code>_rovingPrev()</code></td>
      <td>Method</td>
      <td>Move focus to previous target (wraps to last)</td>
    </tr>
    <tr>
      <td><code>_rovingFirst()</code></td>
      <td>Method</td>
      <td>Focus the first target</td>
    </tr>
    <tr>
      <td><code>_rovingLast()</code></td>
      <td>Method</td>
      <td>Focus the last target</td>
    </tr>
    <tr>
      <td><code>_rovingCurrentIndex()</code></td>
      <td>Method</td>
      <td>Find index of the currently focused target</td>
    </tr>
    <tr>
      <td><code>_rovingIndex</code></td>
      <td>Property</td>
      <td>Index of the last focused target</td>
    </tr>
  </tbody>
</table>

<h3>Keydown Handler is NOT Included</h3>

<p>The mixin intentionally does <strong>not</strong> install a keyboard event handler. Each component defines its own because:</p>
<ul>
  <li><strong>Toolbars</strong> use <code>ArrowRight</code>/<code>ArrowLeft</code> (horizontal) with RTL awareness</li>
  <li><strong>Menus</strong> use <code>ArrowDown</code>/<code>ArrowUp</code> (vertical) plus Enter/Space/Escape/Tab</li>
</ul>

<h3>Where It's Used</h3>
<ul>
  <li><strong>ActionBar</strong> — horizontal toolbar with ArrowRight/Left, RTL support</li>
  <li><strong>DropdownMenu</strong> — vertical menu with ArrowDown/Up, typeahead</li>
</ul>

<h3>TypeScript Usage</h3>

\`\`\`typescript
import { RovingTabindexMixin } from './RovingTabindexMixin'
import { EventEmitterMixin } from './EventEmitterMixin'
import { ReadyMixin } from './ReadyMixin'
import { LitElement } from 'lit'

class MyToolbar extends RovingTabindexMixin(EventEmitterMixin(ReadyMixin(LitElement))) {
  // 1. Override to return your focusable elements
  _getRovingTargets(): HTMLElement[] {
    return Array.from(this.querySelectorAll('button'))
  }

  // 2. Install your own keydown handler
  connectedCallback() {
    super.connectedCallback()
    this.addEventListener('keydown', this._handleKeydown)
  }

  private _handleKeydown = (e: KeyboardEvent) => {
    switch (e.key) {
      case 'ArrowRight': e.preventDefault(); this._rovingNext(); break
      case 'ArrowLeft':  e.preventDefault(); this._rovingPrev(); break
      case 'Home':       e.preventDefault(); this._rovingFirst(); break
      case 'End':        e.preventDefault(); this._rovingLast(); break
    }
  }
}
\`\`\`

<h3>Mixin Composition Order</h3>

\`\`\`typescript
class MyComponent extends RovingTabindexMixin(EventEmitterMixin(ReadyMixin(LitElement))) {}
\`\`\`
        `}}}};let g=class extends h(v){constructor(){super(...arguments),this._handleKeydown=n=>{switch(n.key){case"ArrowRight":n.preventDefault(),this._rovingNext();break;case"ArrowLeft":n.preventDefault(),this._rovingPrev();break;case"Home":n.preventDefault(),this._rovingFirst();break;case"End":n.preventDefault(),this._rovingLast();break}}}createRenderRoot(){return this}_getRovingTargets(){return Array.from(this.querySelectorAll(".roving-demo-btn"))}connectedCallback(){super.connectedCallback(),this.addEventListener("keydown",this._handleKeydown)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("keydown",this._handleKeydown)}render(){return l`
      <div role="toolbar" aria-label="Demo toolbar" style="display: flex; gap: 0.5rem;">
        <button class="roving-demo-btn btu-button btu-button-gray btu-button-md" tabindex="0">Item 1</button>
        <button class="roving-demo-btn btu-button btu-button-gray btu-button-md" tabindex="-1">Item 2</button>
        <button class="roving-demo-btn btu-button btu-button-gray btu-button-md" tabindex="-1">Item 3</button>
        <button class="roving-demo-btn btu-button btu-button-gray btu-button-md" tabindex="-1">Item 4</button>
        <button class="roving-demo-btn btu-button btu-button-gray btu-button-md" tabindex="-1">Item 5</button>
      </div>
    `}};g=f([m("roving-demo")],g);const s={render:()=>l(c||(c=y([`<div class="flex flex-col gap-4">
      <div>
        <h4 class="mb-2 font-bold">Interactive Roving Tabindex Demo</h4>
        <p class="mb-2 text-sm text-gray-600">
          Click any button below, then use <strong>Arrow Right/Left</strong> to move focus between items.
          <strong>Home</strong> and <strong>End</strong> jump to first/last. Focus wraps at both ends.
        </p>
        <p class="mb-4 text-sm text-gray-600">
          Notice only the focused button has <code>tabindex="0"</code> &mdash; pressing <strong>Tab</strong> leaves the
          toolbar entirely, and <strong>Shift+Tab</strong> returns to the last focused item.
        </p>
      </div>

      <roving-demo id="roving-demo"></roving-demo>

      <div id="roving-status" class="text-sm text-gray-500" style="font-family: monospace;"></div>

      <script>
        ;(() => {
          const demo = document.getElementById('roving-demo')
          const status = document.getElementById('roving-status')
          if (!demo || !status) return

          demo.addEventListener('focusin', () => {
            const buttons = demo.querySelectorAll('.roving-demo-btn')
            const indices = Array.from(buttons).map(b => b.getAttribute('tabindex'))
            status.textContent = 'tabindex: [' + indices.join(', ') + ']  |  _rovingIndex: ' + demo._rovingIndex
          })

          demo.addEventListener('keyup', () => {
            const buttons = demo.querySelectorAll('.roving-demo-btn')
            const indices = Array.from(buttons).map(b => b.getAttribute('tabindex'))
            status.textContent = 'tabindex: [' + indices.join(', ') + ']  |  _rovingIndex: ' + demo._rovingIndex
          })
        })()
      <\/script>
    </div>`])))};s.parameters={...s.parameters,docs:{...s.parameters?.docs,source:{originalSource:`{
  render: () => html\`<div class="flex flex-col gap-4">
      <div>
        <h4 class="mb-2 font-bold">Interactive Roving Tabindex Demo</h4>
        <p class="mb-2 text-sm text-gray-600">
          Click any button below, then use <strong>Arrow Right/Left</strong> to move focus between items.
          <strong>Home</strong> and <strong>End</strong> jump to first/last. Focus wraps at both ends.
        </p>
        <p class="mb-4 text-sm text-gray-600">
          Notice only the focused button has <code>tabindex="0"</code> &mdash; pressing <strong>Tab</strong> leaves the
          toolbar entirely, and <strong>Shift+Tab</strong> returns to the last focused item.
        </p>
      </div>

      <roving-demo id="roving-demo"></roving-demo>

      <div id="roving-status" class="text-sm text-gray-500" style="font-family: monospace;"></div>

      <script>
        ;(() => {
          const demo = document.getElementById('roving-demo')
          const status = document.getElementById('roving-status')
          if (!demo || !status) return

          demo.addEventListener('focusin', () => {
            const buttons = demo.querySelectorAll('.roving-demo-btn')
            const indices = Array.from(buttons).map(b => b.getAttribute('tabindex'))
            status.textContent = 'tabindex: [' + indices.join(', ') + ']  |  _rovingIndex: ' + demo._rovingIndex
          })

          demo.addEventListener('keyup', () => {
            const buttons = demo.querySelectorAll('.roving-demo-btn')
            const indices = Array.from(buttons).map(b => b.getAttribute('tabindex'))
            status.textContent = 'tabindex: [' + indices.join(', ') + ']  |  _rovingIndex: ' + demo._rovingIndex
          })
        })()
      <\/script>
    </div>\`
}`,...s.parameters?.docs?.source}}};const A=["RovingTabindex"];export{s as RovingTabindex,A as __namedExportsOrder,T as default};
