{"version":3,"file":"imperative.mjs","names":[],"sources":["../../src/Modal/imperative.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { memo, useEffect, useSyncExternalStore } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useIsClient } from '@/hooks/useIsClient';\nimport { useAppElement } from '@/ThemeProvider';\nimport { registerDevSingleton } from '@/utils/devSingleton';\n\nimport { ModalStackItem } from './ModalStackItem';\nimport { RawModalStackItem } from './RawModalStackItem';\nimport type {\n  ImperativeModalProps,\n  ModalInstance,\n  RawModalComponent,\n  RawModalComponentProps,\n  RawModalInstance,\n  RawModalKeyOptions,\n  RawModalOptions,\n} from './type';\n\ntype ModalStackItemBase = {\n  id: string;\n};\n\ntype ModalStackItemModal = ModalStackItemBase & {\n  kind: 'modal';\n  props: ImperativeModalProps;\n};\n\ntype ModalStackItemRaw = ModalStackItemBase & {\n  component: RawModalComponent;\n  kind: 'raw';\n  open: boolean;\n  options?: RawModalOptions<PropertyKey, PropertyKey>;\n  props: Record<string, unknown>;\n};\n\ntype TModalStackItem = ModalStackItemModal | ModalStackItemRaw;\n\ntype ModalStackProps = {\n  stack: TModalStackItem[];\n};\n\nexport type ModalHostProps = {\n  root?: HTMLElement | ShadowRoot | null;\n};\n\nlet modalStack: TModalStackItem[] = [];\nlet modalSeed = 0;\nconst listeners = new Set<() => void>();\nconst rawDestroyTimers = new Map<string, number>();\n\nconst notify = () => {\n  listeners.forEach((listener) => listener());\n};\n\nconst subscribe = (listener: () => void) => {\n  listeners.add(listener);\n  return () => listeners.delete(listener);\n};\n\nconst EMPTY_STACK: TModalStackItem[] = [];\nconst getSnapshot = () => modalStack;\nconst getServerSnapshot = () => EMPTY_STACK;\n\nconst ModalPortal = ({\n  children,\n  root,\n}: {\n  children: ReactNode;\n  root?: HTMLElement | ShadowRoot | null;\n}) => {\n  const appElement = useAppElement();\n  const container = root ?? appElement ?? document.body;\n\n  return createPortal(children, container);\n};\n\nconst updateModal = (id: string, nextProps: Partial<ImperativeModalProps>) => {\n  let changed = false;\n  modalStack = modalStack.map((item) => {\n    if (item.id !== id) return item;\n    if (item.kind !== 'modal') return item;\n    changed = true;\n    return {\n      ...item,\n      props: { ...item.props, ...nextProps },\n    };\n  });\n\n  if (changed) notify();\n};\n\nconst updateRawProps = (id: string, nextProps: Record<string, unknown>) => {\n  let changed = false;\n  modalStack = modalStack.map((item) => {\n    if (item.id !== id) return item;\n    if (item.kind !== 'raw') return item;\n    changed = true;\n    return {\n      ...item,\n      props: { ...item.props, ...nextProps },\n    };\n  });\n\n  if (changed) notify();\n};\n\nconst setRawOpen = (id: string, open: boolean) => {\n  let changed = false;\n  modalStack = modalStack.map((item) => {\n    if (item.id !== id) return item;\n    if (item.kind !== 'raw') return item;\n    if (item.open === open) return item;\n    changed = true;\n    return { ...item, open };\n  });\n\n  if (open) {\n    const timer = rawDestroyTimers.get(id);\n    if (timer) {\n      clearTimeout(timer);\n      rawDestroyTimers.delete(id);\n    }\n  }\n\n  if (changed) notify();\n};\n\nconst closeModal = (id: string) => {\n  const target = modalStack.find((item) => item.id === id);\n  if (!target) return;\n\n  if (target.kind === 'modal') {\n    updateModal(id, { open: false });\n    return;\n  }\n\n  setRawOpen(id, false);\n\n  const shouldDestroy = target.options?.destroyOnClose ?? true;\n  if (!shouldDestroy) return;\n\n  const delay = target.options?.destroyDelay ?? 200;\n  const existing = rawDestroyTimers.get(id);\n  if (existing) clearTimeout(existing);\n  const timer = window.setTimeout(() => {\n    rawDestroyTimers.delete(id);\n\n    destroyModal(id);\n  }, delay);\n  rawDestroyTimers.set(id, timer);\n};\n\nconst destroyModal = (id: string) => {\n  const timer = rawDestroyTimers.get(id);\n  if (timer) {\n    clearTimeout(timer);\n    rawDestroyTimers.delete(id);\n  }\n  const nextStack = modalStack.filter((item) => item.id !== id);\n  if (nextStack.length === modalStack.length) return;\n  modalStack = nextStack;\n  notify();\n};\n\nconst ModalStack = memo(({ stack }: ModalStackProps) => {\n  const isClient = useIsClient();\n  if (!isClient) return null;\n  return stack.map((item) => {\n    if (item.kind === 'modal') {\n      return (\n        <ModalStackItem\n          id={item.id}\n          key={item.id}\n          props={item.props}\n          onClose={closeModal}\n          onDestroy={destroyModal}\n          onUpdate={updateModal}\n        />\n      );\n    }\n\n    return (\n      <RawModalStackItem\n        component={item.component}\n        id={item.id}\n        key={item.id}\n        open={item.open}\n        options={item.options}\n        props={item.props}\n        onClose={closeModal}\n        onUpdate={updateRawProps}\n      />\n    );\n  });\n});\n\nModalStack.displayName = 'ModalStack';\n\nexport const ModalHost = ({ root }: ModalHostProps) => {\n  const stack = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n  const isClient = useIsClient();\n\n  useEffect(() => {\n    if (!isClient) return;\n    // Enforce singleton per portal root (dev-only).\n    const scope = root ?? document.body;\n    return registerDevSingleton('ModalHost', scope);\n  }, [isClient, root]);\n\n  if (!isClient) return null;\n  if (stack.length === 0) return null;\n\n  return (\n    <ModalPortal root={root}>\n      <ModalStack stack={stack} />\n    </ModalPortal>\n  );\n};\n\nexport const createModal = (props: ImperativeModalProps): ModalInstance => {\n  const id = `modal-${Date.now()}-${modalSeed++}`;\n  modalStack = [\n    ...modalStack,\n    { id, kind: 'modal', props: { ...props, open: props.open ?? true } },\n  ];\n  notify();\n\n  return {\n    close: () => closeModal(id),\n    destroy: () => destroyModal(id),\n    setCanDismissByClickOutside: (value) => updateModal(id, { mask: { closable: value } }),\n    update: (nextProps) => updateModal(id, nextProps),\n  };\n};\n\nexport function createRawModal<P extends RawModalComponentProps>(\n  component: RawModalComponent<P>,\n  props: Omit<P, 'open' | 'onClose'>,\n  options?: RawModalOptions,\n): RawModalInstance<P>;\n\nexport function createRawModal<P, OpenKey extends keyof P, CloseKey extends keyof P>(\n  component: RawModalComponent<P>,\n  props: Omit<P, OpenKey | CloseKey>,\n  options: RawModalKeyOptions<OpenKey, CloseKey>,\n): RawModalInstance<P, OpenKey, CloseKey>;\n\nexport function createRawModal<P, OpenKey extends keyof P, CloseKey extends keyof P>(\n  component: RawModalComponent<P>,\n  props: Omit<P, OpenKey | CloseKey>,\n  options?: RawModalOptions<OpenKey, CloseKey>,\n): RawModalInstance<P, OpenKey, CloseKey> {\n  const id = `modal-${Date.now()}-${modalSeed++}`;\n  modalStack = [\n    ...modalStack,\n    {\n      component,\n      id,\n      kind: 'raw',\n      open: true,\n      options,\n      props: props as Record<string, unknown>,\n    },\n  ];\n  notify();\n\n  return {\n    close: () => closeModal(id),\n    destroy: () => destroyModal(id),\n    setCanDismissByClickOutside: (value) => updateRawProps(id, { mask: { closable: value } }),\n    update: (nextProps) => updateRawProps(id, nextProps as Record<string, unknown>),\n  };\n}\n"],"mappings":"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"}