{"version":3,"file":"BqAccordion-C20MXNPQ.cjs","names":[],"sources":["../src/components/accordion/BqAccordion.ts"],"sourcesContent":["/**\r\n * Accordion / disclosure component.\r\n * @element bq-accordion\r\n * @prop {string}  label   - Trigger label\r\n * @prop {boolean} open    - Expanded state\r\n * @prop {boolean} disabled\r\n * @prop {string}  variant - default | bordered | flush\r\n * @slot - Accordion panel content\r\n * @fires bq-toggle - { open: boolean }\r\n */\r\nimport type { ComponentDefinition } from '@bquery/bquery/component';\r\nimport { bool, component, html } from '@bquery/bquery/component';\r\nimport { escapeHtml } from '@bquery/bquery/security';\r\nimport { getAnimationTimeoutMs, uniqueId } from '../../utils/dom.js';\r\nimport { getBaseStyles } from '../../utils/styles.js';\r\n\r\ntype BqAccordionProps = {\r\n  label: string;\r\n  open: boolean;\r\n  disabled: boolean;\r\n  variant: string;\r\n};\r\ntype BqAccordionState = { uid: string };\r\n\r\nconst DEFAULT_SLOW_DURATION = '300ms';\r\n\r\nconst definition: ComponentDefinition<BqAccordionProps, BqAccordionState> = {\r\n  props: {\r\n    label: { type: String, default: '' },\r\n    open: { type: Boolean, default: false },\r\n    disabled: { type: Boolean, default: false },\r\n    variant: { type: String, default: 'default' },\r\n  },\r\n  state: {\r\n    uid: '',\r\n  },\r\n  styles: `\r\n    ${getBaseStyles()}\r\n    *, *::before, *::after { box-sizing: border-box; }\r\n    :host { display: block; }\r\n    :host([variant=\"bordered\"]) .accordion { border: 1.5px solid var(--bq-border-base,#e2e8f0); border-radius: var(--bq-radius-lg); }\r\n    :host([variant=\"flush\"]) .accordion { border-bottom: 1px solid var(--bq-border-base,#e2e8f0); }\r\n    .accordion { font-family: var(--bq-font-family-sans); }\r\n    .trigger {\r\n      display: flex; align-items: center; justify-content: space-between;\r\n      width: 100%; padding: var(--bq-space-4,1rem); background: none; border: none;\r\n      cursor: pointer; color: var(--bq-text-base,#0f172a);\r\n      font-size: var(--bq-font-size-md,1rem); font-weight: var(--bq-font-weight-semibold,600);\r\n      font-family: inherit; text-align: left;\r\n      transition: background var(--bq-duration-fast) var(--bq-easing-standard);\r\n    }\r\n    .trigger:hover:not([disabled]) { background: var(--bq-bg-subtle,#f8fafc); }\r\n    .trigger[disabled] { opacity: 0.5; cursor: not-allowed; }\r\n    .trigger:focus-visible { outline: 2px solid transparent; box-shadow: var(--bq-focus-ring); }\r\n    .icon { flex-shrink: 0; font-size: 1rem; color: var(--bq-text-muted,#475569); transition: transform var(--bq-duration-fast) var(--bq-easing-standard); }\r\n    :host([open]:not([data-closing])) .icon { transform: rotate(180deg); }\r\n    .panel { display: grid; grid-template-rows: 0fr; overflow: hidden; }\r\n    .panel-inner { overflow: hidden; min-height: 0; padding: 0 var(--bq-space-4,1rem) var(--bq-space-4,1rem); color: var(--bq-text-muted,#475569); font-size: var(--bq-font-size-sm,0.875rem); line-height: var(--bq-line-height-relaxed,1.625); }\r\n    :host([open]:not([data-closing])) .panel { grid-template-rows: 1fr; animation: panel-open var(--bq-duration-slow,${DEFAULT_SLOW_DURATION}) var(--bq-easing-standard); }\r\n    :host([data-closing]) .panel { grid-template-rows: 1fr; animation: panel-close var(--bq-duration-slow,${DEFAULT_SLOW_DURATION}) var(--bq-easing-standard) forwards; }\r\n    @keyframes panel-open { from { grid-template-rows: 0fr; } }\r\n    @keyframes panel-close { from { grid-template-rows: 1fr; } to { grid-template-rows: 0fr; } }\r\n    @media (prefers-reduced-motion: reduce) {\r\n      .panel { animation: none !important; }\r\n      .icon { transition: none; }\r\n      .trigger { transition: none; }\r\n    }\r\n  `,\r\n  connected() {\r\n    type BQEl = HTMLElement & {\r\n      setState(k: 'uid', v: string): void;\r\n      getState<T>(k: string): T;\r\n    };\r\n\r\n    const self = this as unknown as BQEl;\r\n    const record = self as unknown as Record<string, unknown>;\r\n\r\n    if (!self.getState<string>('uid')) self.setState('uid', uniqueId('bq-acc'));\r\n\r\n    const clearCloseFallback = () => {\r\n      const timeoutId = record['_closeTimeout'] as\r\n        | ReturnType<typeof setTimeout>\r\n        | undefined;\r\n      if (timeoutId) {\r\n        clearTimeout(timeoutId);\r\n        delete record['_closeTimeout'];\r\n      }\r\n    };\r\n\r\n    const finishClose = () => {\r\n      if (!self.hasAttribute('data-closing')) return;\r\n      clearCloseFallback();\r\n      self.removeAttribute('data-closing');\r\n    };\r\n\r\n    const handler = (e: Event) => {\r\n      if (!(e.target as Element).closest('.trigger')) return;\r\n      if (self.hasAttribute('disabled') || self.hasAttribute('data-closing')) {\r\n        return;\r\n      }\r\n\r\n      const isOpen = self.hasAttribute('open');\r\n      if (isOpen) {\r\n        // Close with animation via data-closing (no re-render, CSS animation on existing DOM)\r\n        const reducedMotion = self.ownerDocument.defaultView?.matchMedia?.(\r\n          '(prefers-reduced-motion: reduce)'\r\n        )?.matches;\r\n\r\n        if (reducedMotion) {\r\n          self.removeAttribute('open');\r\n          self.dispatchEvent(\r\n            new CustomEvent('bq-toggle', {\r\n              detail: { open: false },\r\n              bubbles: true,\r\n              composed: true,\r\n            })\r\n          );\r\n          return;\r\n        }\r\n\r\n        self.setAttribute('data-closing', '');\r\n        self.removeAttribute('open');\r\n        self.dispatchEvent(\r\n          new CustomEvent('bq-toggle', {\r\n            detail: { open: false },\r\n            bubbles: true,\r\n            composed: true,\r\n          })\r\n        );\r\n        clearCloseFallback();\r\n\r\n        const panel = self.shadowRoot?.querySelector('.panel');\r\n        const timeoutMs = panel\r\n          ? getAnimationTimeoutMs(panel, DEFAULT_SLOW_DURATION)\r\n          : 0;\r\n\r\n        if (timeoutMs <= 0) {\r\n          finishClose();\r\n        } else {\r\n          record['_closeTimeout'] = setTimeout(\r\n            finishClose,\r\n            Math.ceil(timeoutMs) + 20\r\n          );\r\n        }\r\n        return;\r\n      }\r\n\r\n      // Open — setting open triggers re-render, CSS animation plays on new DOM\r\n      self.setAttribute('open', '');\r\n      self.dispatchEvent(\r\n        new CustomEvent('bq-toggle', {\r\n          detail: { open: true },\r\n          bubbles: true,\r\n          composed: true,\r\n        })\r\n      );\r\n    };\r\n\r\n    const kh = (e: Event) => {\r\n      const ke = e as KeyboardEvent;\r\n      if (\r\n        (ke.key === 'Enter' || ke.key === ' ') &&\r\n        (e.target as Element).closest('.trigger')\r\n      ) {\r\n        ke.preventDefault();\r\n        handler(e);\r\n      }\r\n    };\r\n\r\n    const ah = (e: Event) => {\r\n      const target = e.target as Element | null;\r\n      const animationName = (e as Event & { animationName?: string })\r\n        .animationName;\r\n\r\n      if (\r\n        !self.hasAttribute('data-closing') ||\r\n        !target?.classList.contains('panel') ||\r\n        animationName !== 'panel-close'\r\n      ) {\r\n        return;\r\n      }\r\n\r\n      finishClose();\r\n    };\r\n\r\n    record['_handler'] = handler;\r\n    record['_kh'] = kh;\r\n    record['_ah'] = ah;\r\n\r\n    self.shadowRoot?.addEventListener('click', handler);\r\n    self.shadowRoot?.addEventListener('keydown', kh);\r\n    self.shadowRoot?.addEventListener('animationend', ah);\r\n  },\r\n  disconnected() {\r\n    const self = this as unknown as Record<string, unknown>;\r\n    const h = self['_handler'] as EventListener | undefined;\r\n    const kh = self['_kh'] as EventListener | undefined;\r\n    const ah = self['_ah'] as EventListener | undefined;\r\n    const closeTimeout = self['_closeTimeout'] as\r\n      | ReturnType<typeof setTimeout>\r\n      | undefined;\r\n    if (h) this.shadowRoot?.removeEventListener('click', h);\r\n    if (kh) this.shadowRoot?.removeEventListener('keydown', kh);\r\n    if (ah) this.shadowRoot?.removeEventListener('animationend', ah);\r\n    if (closeTimeout) clearTimeout(closeTimeout);\r\n  },\r\n  render({ props, state }) {\r\n    const uid = state.uid || 'bq-acc';\r\n    const triggerId = `${uid}-trigger`;\r\n    const panelId = `${uid}-panel`;\r\n    return html`\r\n      <div\r\n        part=\"accordion\"\r\n        class=\"accordion\"\r\n        data-variant=\"${escapeHtml(props.variant)}\"\r\n      >\r\n        <button\r\n          part=\"trigger\"\r\n          class=\"trigger\"\r\n          type=\"button\"\r\n          id=\"${triggerId}\"\r\n          aria-expanded=\"${props.open ? 'true' : 'false'}\"\r\n          aria-controls=\"${panelId}\"\r\n          ${bool('disabled', props.disabled)}\r\n          ${props.disabled ? 'aria-disabled=\"true\"' : ''}\r\n        >\r\n          <span part=\"label\">${escapeHtml(props.label)}</span>\r\n          <span class=\"icon\" aria-hidden=\"true\">&#9662;</span>\r\n        </button>\r\n        <div\r\n          part=\"panel\"\r\n          class=\"panel\"\r\n          id=\"${panelId}\"\r\n          role=\"region\"\r\n          aria-labelledby=\"${triggerId}\"\r\n          aria-hidden=\"${!props.open ? 'true' : 'false'}\"\r\n        >\r\n          <div class=\"panel-inner\"><slot></slot></div>\r\n        </div>\r\n      </div>\r\n    `;\r\n  },\r\n};\r\n\r\ncomponent<BqAccordionProps, BqAccordionState>('bq-accordion', definition);\r\n"],"mappings":"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"}