{"version":3,"file":"accordion-item.cjs","names":[],"sources":["../src/disclosure/accordion-item/accordion-item.ts"],"sourcesContent":["import { define, getHost, html, inject, onMounted, prop, ref, useEmit, watchEffect } from '@vielzeug/ore';\n\nimport type { ComponentSize, SurfaceVariant } from '../../types';\n\nimport '../../content/icon/icon';\nimport { elementDirection } from '../../core/direction';\nimport { disablableBundle } from '../../shared';\nimport { coarsePointerMixin } from '../../styles';\nimport { ACCORDION_CTX } from '../accordion/accordion';\nimport styles from './accordion-item.css?inline';\n\n/** Accordion item component properties */\n\nexport type OreAccordionItemEvents = {\n  collapse: { expanded: boolean; item: HTMLElement };\n  expand: { expanded: boolean; item: HTMLElement };\n};\n\nexport type OreAccordionItemProps = {\n  /** Disable accordion item interaction */\n  disabled?: boolean;\n  /** Whether the item is expanded/open */\n  expanded?: boolean;\n  /** Item size */\n  size?: ComponentSize;\n  /** Visual style variant */\n  variant?: SurfaceVariant;\n};\n\n/**\n * An individual accordion item with expand/collapse functionality using native details/summary.\n *\n * @element ore-accordion-item\n *\n * @attr {boolean} expanded - Whether the item is expanded/open\n * @attr {boolean} disabled - Disable accordion item interaction\n * @attr {string} size - Item size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'glass' | 'frost'\n *\n * @fires expand - Emitted when item expands. detail: { expanded: boolean; item: HTMLElement }\n * @fires collapse - Emitted when item collapses. detail: { expanded: boolean; item: HTMLElement }\n *\n * @slot prefix - Content before the title (e.g., icons)\n * @slot title - Main accordion item title\n * @slot subtitle - Optional subtitle text\n * @slot suffix - Content after the title (e.g., badges)\n * @slot - Accordion item content (shown when expanded)\n *\n * @cssprop --accordion-item-bg - Background color\n * @cssprop --accordion-item-hover-bg - Background color on hover\n * @cssprop --accordion-item-border-color - Border color\n * @cssprop --accordion-item-title-color - Title text color\n * @cssprop --accordion-item-subtitle-color - Subtitle text color\n * @cssprop --accordion-item-body-color - Body text color\n * @cssprop --accordion-item-radius - Border radius\n * @cssprop --accordion-item-transition - Transition duration\n * @cssprop --accordion-item-title - Title font size\n * @cssprop --accordion-item-subtitle-size - Subtitle font size\n * @cssprop --accordion-item-body - Body font size\n * @cssprop --accordion-item-details-padding - Summary/header padding\n * @cssprop --accordion-item-summary-padding - Content padding\n *\n * @part item - Item root element.\n * @part summary - Summary trigger row.\n * @part header - Header container.\n * @part title - Title text element.\n * @part subtitle - Subtitle text element.\n * @part content - Content container.\n * @example\n * ```html\n * <ore-accordion-item><span slot=\"title\">Click to expand</span><p>Content</p></ore-accordion-item>\n * <ore-accordion-item expanded variant=\"bordered\"><span slot=\"title\">Title</span><p>Content</p></ore-accordion-item>\n * ```\n */\n\nexport const ACCORDION_ITEM_TAG = 'ore-accordion-item' as const;\ndefine<OreAccordionItemProps>(ACCORDION_ITEM_TAG, {\n  props: {\n    ...disablableBundle,\n    expanded: prop.bool(false),\n    size: prop.string<ComponentSize>(),\n    variant: prop.string<SurfaceVariant>(),\n  },\n\n  setup(props) {\n    const el = getHost();\n    const emit = useEmit<OreAccordionItemEvents>();\n    const watch = watchEffect;\n\n    // Inherit size/variant from a parent ore-accordion when present.\n    const accordionCtx = inject(ACCORDION_CTX);\n\n    if (accordionCtx) {\n      watch(() => {\n        const size = accordionCtx.size.value;\n        const variant = accordionCtx.variant.value;\n\n        if (size !== undefined) el.setAttribute('size', size);\n\n        if (variant !== undefined) el.setAttribute('variant', variant);\n      });\n    }\n\n    const titleId = 'accordion-item-title';\n    const detailsRef = ref<HTMLDetailsElement>();\n    const summaryRef = ref<HTMLElement>();\n    let isAnimating = false;\n\n    const openItem = () => {\n      const details = detailsRef.value;\n\n      if (!details || details.open) return;\n\n      details.classList.add('opening');\n      details.open = true;\n\n      el.toggleAttribute('expanded', true);\n      emit('expand', { expanded: true, item: el });\n\n      requestAnimationFrame(() => {\n        const inner = details.querySelector<HTMLElement>('.content-inner');\n\n        if (!inner) {\n          details.classList.remove('opening');\n          isAnimating = false;\n\n          return;\n        }\n\n        const onDone = () => {\n          details.classList.remove('opening');\n          isAnimating = false;\n        };\n        const transitions = inner.getAnimations?.().filter((a) => a instanceof CSSTransition) ?? [];\n\n        if (transitions.length > 0) {\n          Promise.allSettled(transitions.map((a) => a.finished)).then(onDone);\n        } else {\n          onDone();\n        }\n      });\n    };\n\n    const closeItem = () => {\n      const details = detailsRef.value;\n\n      if (!details?.open || isAnimating) return;\n\n      isAnimating = true;\n\n      details.classList.add('closing');\n\n      const inner = details.querySelector<HTMLElement>('.content-inner');\n      const onDone = () => {\n        details.classList.remove('closing');\n        details.open = false;\n        el.toggleAttribute('expanded', false);\n        emit('collapse', { expanded: false, item: el });\n        isAnimating = false;\n      };\n\n      if (inner) {\n        const transitions = inner.getAnimations?.().filter((a) => a instanceof CSSTransition) ?? [];\n\n        if (transitions.length > 0) {\n          Promise.allSettled(transitions.map((a) => a.finished)).then(onDone);\n        } else {\n          onDone();\n        }\n      } else {\n        onDone();\n      }\n    };\n\n    let touchHandled = false;\n    let touchStartY = 0;\n\n    const toggleDetails = () => {\n      if (props.disabled.value) return;\n\n      const details = detailsRef.value;\n\n      if (!details) return;\n\n      if (details.open) {\n        closeItem();\n      } else {\n        openItem();\n      }\n    };\n\n    const handleSummaryTouchStart = (e: TouchEvent) => {\n      touchStartY = e.touches[0]?.clientY ?? 0;\n    };\n\n    const handleSummaryTouchEnd = (e: TouchEvent) => {\n      const dy = Math.abs((e.changedTouches[0]?.clientY ?? 0) - touchStartY);\n\n      if (dy > 10) return;\n\n      e.preventDefault();\n      touchHandled = true;\n      toggleDetails();\n    };\n\n    const handleSummaryClick = (e: Event) => {\n      if (touchHandled) {\n        touchHandled = false;\n        e.preventDefault();\n\n        return;\n      }\n\n      e.preventDefault();\n      toggleDetails();\n    };\n\n    const handleToggle = () => {\n      // Only fires for programmatic open/close (e.g. from accordion parent)\n      const isOpen = detailsRef.value?.open ?? false;\n      const wasExpanded = Boolean(props.expanded.value);\n\n      if (isOpen && !wasExpanded) {\n        el.toggleAttribute('expanded', true);\n        emit('expand', { expanded: true, item: el });\n      } else if (!isOpen && wasExpanded) {\n        el.toggleAttribute('expanded', false);\n        emit('collapse', { expanded: false, item: el });\n      }\n    };\n\n    onMounted(() => {\n      const details = detailsRef.value;\n      const summary = summaryRef.value;\n\n      if (!details || !summary) return;\n\n      // Detect RTL so plain CSS classes can target it (see `elementDirection` for the\n      // ancestor-dir / computed-style resolution rule).\n      const checkRTL = () => {\n        details.classList.toggle('rtl', elementDirection(el) === 'rtl');\n      };\n\n      // Check initially\n      checkRTL();\n\n      // Re-check when `dir` changes on this element's own ancestor chain (not the whole\n      // document — `elementDirection` only ever looks at `el`'s ancestors, so that's all we\n      // need to watch).\n      const observer = new MutationObserver((mutations) => {\n        const dirChanged = mutations.some((m) => m.attributeName === 'dir');\n\n        if (dirChanged) {\n          checkRTL();\n        }\n      });\n\n      for (let ancestor: Element | null = el; ancestor; ancestor = ancestor.parentElement) {\n        observer.observe(ancestor, { attributeFilter: ['dir'], attributes: true });\n      }\n\n      details.addEventListener('toggle', handleToggle);\n      summary.addEventListener('touchstart', handleSummaryTouchStart, { passive: true });\n      summary.addEventListener('touchend', handleSummaryTouchEnd, { passive: false });\n      summary.addEventListener('click', handleSummaryClick);\n\n      return () => {\n        observer.disconnect();\n        details.removeEventListener('toggle', handleToggle);\n        summary.removeEventListener('touchstart', handleSummaryTouchStart);\n        summary.removeEventListener('touchend', handleSummaryTouchEnd);\n        summary.removeEventListener('click', handleSummaryClick);\n      };\n    });\n\n    return html`\n      <details part=\"item\" ?open=\"${props.expanded}\" ref=\"${detailsRef}\">\n        <summary\n          part=\"summary\"\n          aria-expanded=\"${() => String(props.expanded.value)}\"\n          aria-disabled=\"${() => (props.disabled.value ? 'true' : 'false')}\"\n          tabindex=\"${() => (props.disabled.value ? '-1' : null)}\"\n          ref=\"${summaryRef}\">\n          <slot name=\"prefix\"></slot>\n          <div class=\"header-content\" part=\"header\">\n            <span class=\"title\" part=\"title\" id=\"${titleId}\">\n              <slot name=\"title\"></slot>\n            </span>\n            <span class=\"subtitle\" part=\"subtitle\">\n              <slot name=\"subtitle\"></slot>\n            </span>\n          </div>\n          <slot name=\"suffix\"></slot>\n          <ore-icon class=\"chevron\" name=\"chevron-down\" size=\"20\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n        </summary>\n        <div class=\"content-wrapper\" part=\"content\" role=\"region\" aria-labelledby=\"${titleId}\">\n          <div class=\"content-inner\">\n            <slot></slot>\n          </div>\n        </div>\n      </details>\n    `;\n  },\n\n  styles: [coarsePointerMixin, styles],\n});\n"],"mappings":"iUA2EA,IAAa,EAAqB,sBAClC,EAAA,EAAA,OAAA,CAA8B,EAAoB,CAChD,MAAO,CACL,GAAG,EAAA,iBACH,SAAU,EAAA,KAAK,KAAK,EAAK,EACzB,KAAM,EAAA,KAAK,OAAsB,EACjC,QAAS,EAAA,KAAK,OAAuB,CACvC,EAEA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,GAAA,EAAO,EAAA,QAAA,CAAgC,EACvC,EAAQ,EAAA,YAGR,GAAA,EAAe,EAAA,OAAA,CAAO,EAAA,aAAa,EAErC,GACF,MAAY,CACV,IAAM,EAAO,EAAa,KAAK,MACzB,EAAU,EAAa,QAAQ,MAEjC,IAAS,IAAA,IAAW,EAAG,aAAa,OAAQ,CAAI,EAEhD,IAAY,IAAA,IAAW,EAAG,aAAa,UAAW,CAAO,CAC/D,CAAC,EAGH,IAAM,EAAU,uBACV,GAAA,EAAa,EAAA,IAAA,CAAwB,EACrC,GAAA,EAAa,EAAA,IAAA,CAAiB,EAChC,EAAc,GAEZ,MAAiB,CACrB,IAAM,EAAU,EAAW,MAEvB,CAAC,GAAW,EAAQ,OAExB,EAAQ,UAAU,IAAI,SAAS,EAC/B,EAAQ,KAAO,GAEf,EAAG,gBAAgB,WAAY,EAAI,EACnC,EAAK,SAAU,CAAE,SAAU,GAAM,KAAM,CAAG,CAAC,EAE3C,0BAA4B,CAC1B,IAAM,EAAQ,EAAQ,cAA2B,gBAAgB,EAEjE,GAAI,CAAC,EAAO,CACV,EAAQ,UAAU,OAAO,SAAS,EAClC,EAAc,GAEd,MACF,CAEA,IAAM,MAAe,CACnB,EAAQ,UAAU,OAAO,SAAS,EAClC,EAAc,EAChB,EACM,EAAc,EAAM,gBAAgB,CAAC,CAAC,OAAQ,GAAM,aAAa,aAAa,GAAK,CAAC,EAEtF,EAAY,OAAS,EACvB,QAAQ,WAAW,EAAY,IAAK,GAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAM,EAElE,EAAO,CAEX,CAAC,EACH,EAEM,MAAkB,CACtB,IAAM,EAAU,EAAW,MAE3B,GAAI,CAAC,GAAS,MAAQ,EAAa,OAEnC,EAAc,GAEd,EAAQ,UAAU,IAAI,SAAS,EAE/B,IAAM,EAAQ,EAAQ,cAA2B,gBAAgB,EAC3D,MAAe,CACnB,EAAQ,UAAU,OAAO,SAAS,EAClC,EAAQ,KAAO,GACf,EAAG,gBAAgB,WAAY,EAAK,EACpC,EAAK,WAAY,CAAE,SAAU,GAAO,KAAM,CAAG,CAAC,EAC9C,EAAc,EAChB,EAEA,GAAI,EAAO,CACT,IAAM,EAAc,EAAM,gBAAgB,CAAC,CAAC,OAAQ,GAAM,aAAa,aAAa,GAAK,CAAC,EAEtF,EAAY,OAAS,EACvB,QAAQ,WAAW,EAAY,IAAK,GAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAM,EAElE,EAAO,CAEX,MACE,EAAO,CAEX,EAEI,EAAe,GACf,EAAc,EAEZ,MAAsB,CAC1B,GAAI,EAAM,SAAS,MAAO,OAE1B,IAAM,EAAU,EAAW,MAEtB,IAED,EAAQ,KACV,EAAU,EAEV,EAAS,EAEb,EAEM,EAA2B,GAAkB,CACjD,EAAc,EAAE,QAAQ,EAAE,EAAE,SAAW,CACzC,EAEM,EAAyB,GAAkB,CACpC,KAAK,KAAK,EAAE,eAAe,EAAE,EAAE,SAAW,GAAK,CAEtD,EAAK,KAET,EAAE,eAAe,EACjB,EAAe,GACf,EAAc,EAChB,EAEM,EAAsB,GAAa,CACvC,GAAI,EAAc,CAChB,EAAe,GACf,EAAE,eAAe,EAEjB,MACF,CAEA,EAAE,eAAe,EACjB,EAAc,CAChB,EAEM,MAAqB,CAEzB,IAAM,EAAS,EAAW,OAAO,MAAQ,GACnC,EAAc,EAAQ,EAAM,SAAS,MAEvC,GAAU,CAAC,GACb,EAAG,gBAAgB,WAAY,EAAI,EACnC,EAAK,SAAU,CAAE,SAAU,GAAM,KAAM,CAAG,CAAC,GAClC,CAAC,GAAU,IACpB,EAAG,gBAAgB,WAAY,EAAK,EACpC,EAAK,WAAY,CAAE,SAAU,GAAO,KAAM,CAAG,CAAC,EAElD,EA8CA,OA5CA,EAAA,EAAA,UAAA,KAAgB,CACd,IAAM,EAAU,EAAW,MACrB,EAAU,EAAW,MAE3B,GAAI,CAAC,GAAW,CAAC,EAAS,OAI1B,IAAM,MAAiB,CACrB,EAAQ,UAAU,OAAO,MAAO,EAAA,iBAAiB,CAAE,IAAM,KAAK,CAChE,EAGA,EAAS,EAKT,IAAM,EAAW,IAAI,iBAAkB,GAAc,CAChC,EAAU,KAAM,GAAM,EAAE,gBAAkB,KAEzD,GACF,EAAS,CAEb,CAAC,EAED,IAAK,IAAI,EAA2B,EAAI,EAAU,EAAW,EAAS,cACpE,EAAS,QAAQ,EAAU,CAAE,gBAAiB,CAAC,KAAK,EAAG,WAAY,EAAK,CAAC,EAQ3E,OALA,EAAQ,iBAAiB,SAAU,CAAY,EAC/C,EAAQ,iBAAiB,aAAc,EAAyB,CAAE,QAAS,EAAK,CAAC,EACjF,EAAQ,iBAAiB,WAAY,EAAuB,CAAE,QAAS,EAAM,CAAC,EAC9E,EAAQ,iBAAiB,QAAS,CAAkB,MAEvC,CACX,EAAS,WAAW,EACpB,EAAQ,oBAAoB,SAAU,CAAY,EAClD,EAAQ,oBAAoB,aAAc,CAAuB,EACjE,EAAQ,oBAAoB,WAAY,CAAqB,EAC7D,EAAQ,oBAAoB,QAAS,CAAkB,CACzD,CACF,CAAC,EAEM,EAAA,IAAI;oCACqB,EAAM,SAAS,SAAS,EAAW;;;+BAGtC,OAAO,EAAM,SAAS,KAAK,EAAE;+BAC5B,EAAM,SAAS,MAAQ,OAAS,QAAS;0BAC9C,EAAM,SAAS,MAAQ,KAAO,KAAM;iBAChD,EAAW;;;mDAGuB,EAAQ;;;;;;;;;;qFAU0B,EAAQ;;;;;;KAO3F,EAEA,OAAQ,CAAC,EAAA,mBAAoB,EAAA,OAAM,CACrC,CAAC"}