{"version":3,"file":"drawer.cjs","names":[],"sources":["../src/overlay/drawer/drawer.ts"],"sourcesContent":["import { createPanGesture, type PanAxis, type PanGesture, type PanGestureEndDetail } from '@vielzeug/gesture';\nimport {\n  createStableId,\n  define,\n  getHost,\n  html,\n  onCleanup,\n  onEvent,\n  onMounted,\n  prop,\n  ref,\n  useEmit,\n  useSlots,\n} from '@vielzeug/ore';\nimport { signal } from '@vielzeug/ripple';\n\nimport type { OverlayOpenChangeDetail } from '../../core';\nimport '../../content/icon/icon';\nimport { coarsePointerMixin, forcedColorsMixin, reducedMotionMixin } from '../../styles';\nimport { useDialogControl } from '../shared/use-dialog';\nimport styles from './drawer.css?inline';\n\ntype DrawerPlacement = 'left' | 'right' | 'top' | 'bottom';\ntype DrawerSize = 'sm' | 'lg' | 'full';\ntype DrawerBackdrop = 'opaque' | 'blur' | 'transparent';\ntype DrawerDragHandlePlacement = 'outside' | 'inset';\ntype DrawerSwipeConfig = {\n  axis: PanAxis;\n  closingDistance: (distance: number) => number;\n  translate: (distance: number) => string;\n};\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n  value == null ? undefined : value === '' || value === 'true';\n\nconst drawerSwipeConfig: Record<DrawerPlacement, DrawerSwipeConfig> = {\n  bottom: {\n    axis: 'y',\n    closingDistance: (distance) => Math.max(0, distance),\n    translate: (distance) => `translateY(${distance}px)`,\n  },\n  left: {\n    axis: 'x',\n    closingDistance: (distance) => Math.max(0, -distance),\n    translate: (distance) => `translateX(${distance}px)`,\n  },\n  right: {\n    axis: 'x',\n    closingDistance: (distance) => Math.max(0, distance),\n    translate: (distance) => `translateX(${distance}px)`,\n  },\n  top: {\n    axis: 'y',\n    closingDistance: (distance) => Math.max(0, -distance),\n    translate: (distance) => `translateY(${distance}px)`,\n  },\n};\n\n/** Element interface exposing the imperative API for `ore-drawer`. */\nexport interface DrawerElement extends HTMLElement, Omit<OreDrawerProps, 'title'> {\n  /** Programmatically close the drawer with the exit animation. */\n  hide(): void;\n  /** Programmatically open the drawer. Equivalent to setting `open`. */\n  show(): void;\n}\n\n/** Drawer component properties */\n\nexport type OreDrawerEvents = {\n  'open-change': OverlayOpenChangeDetail;\n};\n\nexport type OreDrawerProps = {\n  /** Backdrop style — 'opaque' (default), 'blur', or 'transparent' */\n  backdrop?: DrawerBackdrop;\n  /** Initial uncontrolled open state. Ignored when `open` is set. */\n  'default-open'?: boolean;\n  /** Show the close (×) button in the header (default: true) */\n  dismissible?: boolean;\n  /** Drag handle position used for swipe-to-close gestures */\n  'drag-handle-placement'?: DrawerDragHandlePlacement;\n  /**\n   * CSS selector for the element inside the drawer that should receive focus on open.\n   * Defaults to native dialog focus management (first focusable element).\n   * @example '#submit-btn' | 'input[name=\"email\"]'\n   */\n  'initial-focus'?: string;\n  /**\n   * Invisible accessible label for the dialog (`aria-label`).\n   * Use when the drawer has no visible title (e.g. image-only content).\n   * When omitted, `aria-labelledby` points to the visible header title instead.\n   */\n  label?: string;\n  /** Controlled open state */\n  open?: boolean;\n  /** When true, backdrop clicks do not close the drawer (default: false) */\n  persistent?: boolean;\n  /** Side from which the drawer slides in */\n  placement?: DrawerPlacement;\n  /**\n   * When true (default), focus returns to the triggering element after the drawer closes.\n   * Set to false to manage focus manually.\n   */\n  'return-focus'?: boolean;\n  /** Drawer width/height preset */\n  size?: DrawerSize;\n  /**\n   * Visible title text rendered inside the header.\n   * Used as the dialog's accessible label via `aria-labelledby` when `label` is not set.\n   */\n  title?: string;\n};\n\n/**\n * A panel that slides in from any edge of the screen, built on the native `<dialog>` element.\n *\n * @element ore-drawer\n *\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} placement - 'left' | 'right' (default) | 'top' | 'bottom'\n * @attr {string} size - 'sm' | 'lg' | 'full'\n * @attr {string} title - Visible header title text\n * @attr {string} label - Invisible aria-label (for drawers without a visible title)\n * @attr {boolean} dismissible - Show the close (×) button (default: true)\n * @attr {string} drag-handle-placement - 'outside' (default) | 'inset'\n * @attr {string} backdrop - Backdrop style: 'opaque' (default) | 'blur' | 'transparent'\n * @attr {boolean} persistent - Prevent backdrop-click from closing (default: false)\n *\n * @fires open-change - When the drawer state changes. detail: { open, reason }\n *\n * @slot header - Drawer header content\n * @slot - Main body content\n * @slot footer - Drawer footer content\n *\n * @cssprop --drawer-backdrop-bg - Backdrop background color\n * @cssprop --drawer-bg - Panel background color\n * @cssprop --drawer-size - Panel width (horizontal) or height (vertical)\n * @cssprop --drawer-shadow - Panel box-shadow\n * @cssprop --drawer-panel-blur - Panel backdrop blur amount\n *\n * @part drag-handle - Drawer drag handle.\n * @part panel - Panel container.\n * @part header - Header container.\n * @part close-btn - Close button.\n * @part body - Body content container.\n * @part footer - Footer container.\n * @example\n * ```html\n * <!-- With visible title -->\n * <ore-drawer open title=\"Settings\" placement=\"right\">\n *   <p>Settings content here.</p>\n * </ore-drawer>\n *\n * <!-- With custom header slot -->\n * <ore-drawer open placement=\"right\">\n *   <span slot=\"header\">Settings</span>\n *   <p>Settings content here.</p>\n * </ore-drawer>\n * ```\n */\n\nexport const DRAWER_TAG = 'ore-drawer' as const;\ndefine<OreDrawerProps>(DRAWER_TAG, {\n  props: {\n    backdrop: prop.string<DrawerBackdrop>(),\n    'default-open': prop.bool(false),\n    dismissible: prop.bool(true),\n    'drag-handle-placement': prop.oneOf(['outside', 'inset'] as const, 'outside'),\n    'initial-focus': prop.string(),\n    label: prop.string(),\n    open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n    persistent: prop.bool(false),\n    placement: prop.oneOf(['left', 'right', 'top', 'bottom'] as const, 'right'),\n    'return-focus': prop.bool(true),\n    size: prop.string<DrawerSize>(),\n    title: prop.string(),\n  },\n  setup(props) {\n    const el = getHost();\n    const emit = useEmit<OreDrawerEvents>();\n    const slots = useSlots();\n\n    const drawerLabelId = createStableId('drawer-label');\n    const dialogRef = ref<HTMLDialogElement>();\n    const panelRef = ref<HTMLDivElement>();\n\n    // Drag-to-close state\n    const isSwipeClosing = signal(false);\n    let swipe: PanGesture | undefined;\n    let swipeCloseTimer: ReturnType<typeof setTimeout> | undefined;\n\n    const getHeaderText = () => props.label.value ?? props.title.value ?? '';\n    const hasHeaderTitle = () => slots.has('header').value || !!getHeaderText();\n\n    // Header is visible when there is slot content, a text label, or a close button.\n    const hasHeader = () => hasHeaderTitle() || props.dismissible.value;\n    const hasFooter = () => slots.has('footer').value;\n\n    const getPlacement = (): DrawerPlacement => props.placement.value || 'right';\n\n    const getSwipeConfig = (): DrawerSwipeConfig => drawerSwipeConfig[getPlacement()];\n\n    const getSnapThreshold = (panel: HTMLElement, axis: PanAxis) => {\n      const panelSize = axis === 'x' ? panel.offsetWidth : panel.offsetHeight;\n\n      return Math.min(96, Math.max(36, panelSize * 0.18));\n    };\n\n    const shouldCommitSwipeClose = (distance: number, threshold: number) => {\n      return getSwipeConfig().closingDistance(distance) >= threshold;\n    };\n\n    const finalizeSwipeClose = (panel: HTMLElement) => {\n      if (!isSwipeClosing.value) return;\n\n      if (swipeCloseTimer) {\n        clearTimeout(swipeCloseTimer);\n        swipeCloseTimer = undefined;\n      }\n\n      const dialog = dialogRef.value;\n\n      if (!dialog) {\n        isSwipeClosing.value = false;\n\n        return;\n      }\n\n      dialog.style.transition = 'none';\n      panel.style.opacity = '0';\n      panel.style.visibility = 'hidden';\n      void dialog.offsetWidth;\n\n      requestClose('swipe');\n    };\n\n    const startSwipeClose = (panel: HTMLElement, swipe: DrawerSwipeConfig, committedDistance: number) => {\n      if (isSwipeClosing.value) return;\n\n      isSwipeClosing.value = true;\n\n      const panelSize = swipe.axis === 'x' ? panel.offsetWidth : panel.offsetHeight;\n      // Preserve overshoot so closing continues from the dragged position instead of snapping back.\n      const exitDistance =\n        committedDistance >= 0 ? Math.max(committedDistance, panelSize) : Math.min(committedDistance, -panelSize);\n      const exitTransform = swipe.translate(exitDistance);\n\n      // Commit the current drag position first so the magnetic snap continues\n      // from the finger instead of jumping back to rest.\n      panel.style.transition = 'transform 180ms cubic-bezier(0.2, 0.9, 0.2, 1), opacity 180ms ease-out';\n      void panel.offsetWidth;\n\n      const onExitTransitionEnd = (ev: TransitionEvent) => {\n        if (ev.target !== panel || ev.propertyName !== 'transform') return;\n\n        panel.removeEventListener('transitionend', onExitTransitionEnd);\n        finalizeSwipeClose(panel);\n      };\n\n      panel.addEventListener('transitionend', onExitTransitionEnd);\n\n      const durationMs = parseFloat(getComputedStyle(panel).transitionDuration) * 1000;\n\n      swipeCloseTimer = setTimeout(() => {\n        panel.removeEventListener('transitionend', onExitTransitionEnd);\n        finalizeSwipeClose(panel);\n      }, durationMs + 50);\n\n      panel.style.transform = exitTransform;\n      panel.style.opacity = '0.2';\n    };\n\n    const resetPanelDragStyles = (panel: HTMLElement) => {\n      if (swipeCloseTimer) {\n        clearTimeout(swipeCloseTimer);\n        swipeCloseTimer = undefined;\n      }\n\n      // Re-enable transitions so the snap-back or exit animates.\n      panel.style.transition = '';\n      panel.style.transform = '';\n      panel.style.opacity = '';\n      panel.style.visibility = '';\n      isSwipeClosing.value = false;\n    };\n\n    const handleSwipeEnd = ({ distance, reason }: PanGestureEndDetail): void => {\n      const panel = panelRef.value;\n\n      if (!panel) return;\n\n      const threshold = getSnapThreshold(panel, getSwipeConfig().axis);\n\n      if (reason === 'release' && shouldCommitSwipeClose(distance, threshold)) {\n        startSwipeClose(panel, getSwipeConfig(), distance);\n\n        return;\n      }\n\n      resetPanelDragStyles(panel);\n    };\n\n    // ────────────────────────────────────────────────────────────────\n    // Overlay State Management\n    // ────────────────────────────────────────────────────────────────\n\n    const { closeWithAnimation, handleCancel, overlay, requestClose, watchOpenProp } = useDialogControl({\n      beforeOpen: (dialog) => {\n        // Clear any inline drag styles from a previous swipe-close so the CSS\n        // entry animation starts from the correct base state.\n        const panel = panelRef.value;\n\n        if (panel) resetPanelDragStyles(panel);\n\n        void dialog;\n      },\n      closeRequestDetail: (_reason) => ({ placement: props.placement.value ?? 'right' }),\n      defaultOpen: props['default-open'],\n      dialogRef,\n      getPanelEl: () => panelRef.value,\n      host: el,\n      initialFocus: props['initial-focus'],\n      isPersistent: () => Boolean(props.persistent.value),\n      onCleanup,\n      onEvent,\n      onNativeClose: (reason) => {\n        const panelEl = panelRef.value;\n\n        // For swipe-close, keep the panel hidden and off-screen until the next\n        // open cycle — resetting inline styles during native close can produce\n        // a visible frame at the rest position on some browsers.\n        if (panelEl && reason !== 'swipe') resetPanelDragStyles(panelEl);\n\n        const dialog = dialogRef.value;\n\n        if (dialog) dialog.style.transition = '';\n\n        emit('open-change', { open: false, reason });\n      },\n      onOpen: (reason) => emit('open-change', { open: true, reason }),\n      openProp: props.open,\n      performClose: (dialog, reason) => {\n        if (reason === 'swipe') {\n          dialog.close();\n        } else {\n          closeWithAnimation();\n        }\n      },\n      returnFocus: props['return-focus'],\n    });\n\n    const handleCloseButtonClick = () => {\n      requestClose('trigger');\n    };\n\n    // ────────────────────────────────────────────────────────────────\n    // Lifecycle: Setup Drawer Integration\n    // ────────────────────────────────────────────────────────────────\n\n    onMounted(() => {\n      const dialog = dialogRef.value;\n\n      if (!dialog) return;\n\n      // Expose imperative API\n      const drawerEl = el as DrawerElement;\n\n      drawerEl.show = () => {\n        overlay.open('programmatic');\n      };\n\n      drawerEl.hide = () => {\n        overlay.close('programmatic');\n      };\n\n      // ────────────────────────────────────────────────────────────\n      // Event Handlers: Cancel, Backdrop Click\n      // ────────────────────────────────────────────────────────────\n      // `handleCancel` (Escape via the native `cancel` event) is provided by\n      // `useDialogControl` above — drawer only needs its own backdrop-click\n      // handler since it has swipe-to-dismiss logic the shared dialog helper\n      // doesn't know about.\n\n      const handleBackdropClick = (e: MouseEvent) => {\n        if (props.persistent.value) return;\n\n        if (swipe?.active || isSwipeClosing.value) return;\n\n        if (e.target !== dialog) return; // Click inside panel\n\n        requestClose('outsideClick');\n      };\n\n      watchOpenProp();\n\n      onEvent(dialog, 'cancel', handleCancel);\n      onEvent(dialog, 'click', handleBackdropClick);\n\n      // Drag-to-close handlers — scoped to the handle element only so interactions\n      // with panel content don't accidentally start a drag.\n      const panel = panelRef.value;\n      const dragHandleEl = panel?.querySelector<HTMLElement>('[part=\"drag-handle\"]');\n\n      if (dragHandleEl) {\n        swipe = createPanGesture(dragHandleEl, {\n          axis: () => getSwipeConfig().axis,\n          disabled: () => isSwipeClosing.value,\n          onEnd: handleSwipeEnd,\n          onMove: ({ distance }) => {\n            const currentPanel = panelRef.value;\n\n            if (!currentPanel) return;\n\n            const swipeConfig = getSwipeConfig();\n            const threshold = getSnapThreshold(currentPanel, swipeConfig.axis);\n            const closingDistance = swipeConfig.closingDistance(distance);\n            const progress = Math.min(closingDistance / threshold, 1);\n\n            currentPanel.style.transition = 'none';\n            currentPanel.style.transform = swipeConfig.translate(distance);\n            currentPanel.style.opacity = String(1 - progress * 0.4);\n          },\n        });\n      }\n\n      return () => {\n        swipe?.dispose();\n        swipe = undefined;\n        overlay.dispose();\n      };\n    });\n\n    return html`\n      <dialog\n        ref=${dialogRef}\n        aria-modal=\"true\"\n        aria-label=\"${() => props.label.value ?? null}\"\n        aria-labelledby=\"${() => (!props.label.value ? drawerLabelId : null)}\">\n        <div class=\"panel\" part=\"panel\" ref=${panelRef}>\n          <div class=\"drag-handle\" part=\"drag-handle\" aria-label=\"Drag to close\" role=\"button\"></div>\n          <div class=\"header\" part=\"header\" ?hidden=${() => !hasHeader()}>\n            <span class=\"header-title\" id=\"${drawerLabelId}\" ?hidden=${() => !hasHeaderTitle()}>\n              <slot name=\"header\">${() => getHeaderText()}</slot>\n            </span>\n            <button\n              class=\"close-btn\"\n              part=\"close-btn\"\n              type=\"button\"\n              aria-label=\"Close\"\n              ?hidden=${() => !props.dismissible.value}\n              @click=${handleCloseButtonClick}>\n              <ore-icon name=\"x\" size=\"16\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n            </button>\n          </div>\n          <div class=\"body\" part=\"body\">\n            <slot></slot>\n          </div>\n          <div class=\"footer\" part=\"footer\" ?hidden=${() => !hasFooter()}>\n            <slot name=\"footer\"></slot>\n          </div>\n        </div>\n      </dialog>\n    `;\n  },\n  styles: [forcedColorsMixin, coarsePointerMixin, reducedMotionMixin, styles],\n});\n"],"mappings":"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"}