{"version":3,"file":"popover.cjs","names":[],"sources":["../src/overlay/popover/popover.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\nimport {\n  bind,\n  createStableId,\n  define,\n  getHost,\n  html,\n  onCleanup,\n  onMounted,\n  prop,\n  useEmit,\n  useSlots,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport { type OverlayOpenChangeDetail, parseStringTriggers } from '../../core';\nimport { disablableBundle } from '../../shared';\nimport { reducedMotionMixin } from '../../styles';\nimport { useFloatingTrigger } from '../shared/use-floating-trigger';\nimport styles from './popover.css?inline';\n\nexport type PopoverTrigger = 'click' | 'focus' | 'hover';\n\nconst PANEL_OFFSET = 8;\nconst VALID_TRIGGERS = new Set<PopoverTrigger>(['click', 'focus', 'hover']);\nconst DEFAULT_POPOVER_TRIGGERS: PopoverTrigger[] = ['click'];\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n  value == null ? undefined : value === '' || value === 'true';\n\nconst normalizeTriggers = (value: unknown): PopoverTrigger[] =>\n  parseStringTriggers(String(value ?? ''), VALID_TRIGGERS, DEFAULT_POPOVER_TRIGGERS);\n\nexport type OrePopoverEvents = {\n  'open-change': OverlayOpenChangeDetail;\n};\n\n/** Popover component properties */\nexport type OrePopoverProps = {\n  /** Initial uncontrolled open state. Ignored when `open` is set. */\n  'default-open'?: boolean;\n  /** Disable the popover */\n  disabled?: boolean;\n  /** Accessible label for the panel */\n  label?: string;\n  /** Gap between trigger and panel in px */\n  offset?: number;\n  /** Controlled open state */\n  open?: boolean;\n  /** Preferred placement relative to the trigger */\n  placement?: Placement;\n  /** Which trigger(s) open/close the popover */\n  trigger?: string;\n};\n\n/**\n * A floating panel anchored to a trigger element.\n *\n * @element ore-popover\n * @attr {string} placement - Preferred placement (default: 'bottom')\n * @attr {string} trigger - 'click' | 'hover' | 'focus' (default: 'click')\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {number} offset - Gap in px (default: 8)\n * @attr {boolean} disabled - Disables the popover\n * @attr {string} label - aria-label on the panel\n * @fires open-change - When the panel state changes. detail: { open, reason }\n * @slot - The trigger element\n * @slot content - Panel content\n * @part panel - Panel container.\n *\n * @example\n * ```html\n * <ore-popover placement=\"bottom\" trigger=\"click\">\n *   <ore-button>Open info</ore-button>\n *   <div slot=\"content\">\n *     <p>Popover body content goes here.</p>\n *   </div>\n * </ore-popover>\n * ```\n */\nexport const POPOVER_TAG = 'ore-popover' as const;\ndefine<OrePopoverProps>(POPOVER_TAG, {\n  props: {\n    ...disablableBundle,\n    'default-open': prop.bool(false),\n    label: prop.string(),\n    offset: prop.number(PANEL_OFFSET),\n    open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n    placement: prop.oneOf(\n      [\n        'bottom',\n        'bottom-end',\n        'bottom-start',\n        'left',\n        'left-end',\n        'left-start',\n        'right',\n        'right-end',\n        'right-start',\n        'top',\n        'top-end',\n        'top-start',\n      ] as const,\n      'bottom',\n    ),\n    trigger: prop.string('click'),\n  },\n  setup(props) {\n    const el = getHost();\n    const emit = useEmit<OrePopoverEvents>();\n    const slots = useSlots();\n\n    const shadowRoot = el.shadowRoot;\n    const isDisabled = computed(() => Boolean(props.disabled.value));\n    const panelId = createStableId('popover');\n    const triggers = computed<PopoverTrigger[]>(() => normalizeTriggers(props.trigger.value));\n    let panelEl: HTMLElement | null = null;\n\n    const floating = useFloatingTrigger({\n      bindTriggerAria: (triggerEl) =>\n        bind(\n          {\n            aria: {\n              controls: () => panelId,\n              disabled: () => String(isDisabled.value),\n              expanded: () => String(floating.visible.value),\n              haspopup: 'dialog',\n            },\n          },\n          { target: triggerEl },\n        ),\n      defaultOpen: props['default-open'],\n      disabled: isDisabled,\n      getHost: () => el,\n      getPanel: () => panelEl,\n      offset: props.offset,\n      onCleanup,\n      onClose: (reason) => emit('open-change', { open: false, reason }),\n      onOpen: (reason) => emit('open-change', { open: true, reason }),\n      openProp: props.open as typeof props.open & { value: boolean | undefined },\n      placement: computed(() => props.placement.value as Placement),\n      slot: () => shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])') ?? null,\n      slotElements: slots.elements(),\n      triggers,\n    });\n\n    onMounted(() => floating.mount());\n\n    return html`\n      <slot></slot>\n      <div\n        class=\"panel\"\n        part=\"panel\"\n        id=\"${panelId}\"\n        role=\"dialog\"\n        aria-modal=\"false\"\n        popover=\"manual\"\n        aria-label=\"${props.label}\"\n        aria-hidden=\"${() => String(!floating.visible.value)}\"\n        ref=${(ref: HTMLElement) => {\n          panelEl = ref;\n        }}>\n        <slot name=\"content\"></slot>\n      </div>\n    `;\n  },\n  styles: [reducedMotionMixin, styles],\n});\n"],"mappings":"oWAuBA,IAAM,EAAe,EACf,EAAiB,IAAI,IAAoB,CAAC,QAAS,QAAS,OAAO,CAAC,EACpE,EAA6C,CAAC,OAAO,EAErD,EAAqB,GACzB,GAAS,KAAO,IAAA,GAAY,IAAU,IAAM,IAAU,OAElD,EAAqB,GACzB,EAAA,oBAAoB,OAAO,GAAS,EAAE,EAAG,EAAgB,CAAwB,EAkDtE,EAAc,eAC3B,EAAA,EAAA,OAAA,CAAwB,EAAa,CACnC,MAAO,CACL,GAAG,EAAA,iBACH,eAAgB,EAAA,KAAK,KAAK,EAAK,EAC/B,MAAO,EAAA,KAAK,OAAO,EACnB,OAAQ,EAAA,KAAK,OAAO,CAAY,EAChC,KAAM,CAAE,QAAS,IAAA,GAAkC,MAAO,CAAkB,EAC5E,UAAW,EAAA,KAAK,MACd,CACE,SACA,aACA,eACA,OACA,WACA,aACA,QACA,YACA,cACA,MACA,UACA,WACF,EACA,QACF,EACA,QAAS,EAAA,KAAK,OAAO,OAAO,CAC9B,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,GAAA,EAAO,EAAA,QAAA,CAA0B,EACjC,GAAA,EAAQ,EAAA,SAAA,CAAS,EAEjB,EAAa,EAAG,WAChB,GAAA,EAAa,EAAA,SAAA,KAAe,EAAQ,EAAM,SAAS,KAAM,EACzD,GAAA,EAAU,EAAA,eAAA,CAAe,SAAS,EAClC,GAAA,EAAW,EAAA,SAAA,KAAiC,EAAkB,EAAM,QAAQ,KAAK,CAAC,EACpF,EAA8B,KAE5B,EAAW,EAAA,mBAAmB,CAClC,gBAAkB,IAAA,EAChB,EAAA,KAAA,CACE,CACE,KAAM,CACJ,aAAgB,EAChB,aAAgB,OAAO,EAAW,KAAK,EACvC,aAAgB,OAAO,EAAS,QAAQ,KAAK,EAC7C,SAAU,QACZ,CACF,EACA,CAAE,OAAQ,CAAU,CACtB,EACF,YAAa,EAAM,gBACnB,SAAU,EACV,YAAe,EACf,aAAgB,EAChB,OAAQ,EAAM,OACd,UAAA,EAAA,UACA,QAAU,GAAW,EAAK,cAAe,CAAE,KAAM,GAAO,QAAO,CAAC,EAChE,OAAS,GAAW,EAAK,cAAe,CAAE,KAAM,GAAM,QAAO,CAAC,EAC9D,SAAU,EAAM,KAChB,WAAA,EAAW,EAAA,SAAA,KAAe,EAAM,UAAU,KAAkB,EAC5D,SAAY,GAAY,cAA+B,kBAAkB,GAAK,KAC9E,aAAc,EAAM,SAAS,EAC7B,UACF,CAAC,EAID,OAFA,EAAA,EAAA,UAAA,KAAgB,EAAS,MAAM,CAAC,EAEzB,EAAA,IAAI;;;;;cAKD,EAAQ;;;;sBAIA,EAAM,MAAM;2BACL,OAAO,CAAC,EAAS,QAAQ,KAAK,EAAE;cAC9C,GAAqB,CAC1B,EAAU,CACZ,EAAE;;;KAIR,EACA,OAAQ,CAAC,EAAA,mBAAoB,EAAA,OAAM,CACrC,CAAC"}