{"version":3,"file":"imperative.mjs","names":[],"sources":["../../../src/base-ui/Modal/imperative.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport type { ReactNode } from 'react';\nimport { memo, useCallback, useEffect, useState, 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 {\n  ModalBackdrop,\n  ModalClose,\n  ModalContent,\n  ModalFooter,\n  ModalHeader,\n  ModalPopup,\n  ModalPortal,\n  ModalRoot,\n  ModalTitle,\n} from './atoms';\nimport { ModalContext, useModalContext } from './context';\nimport { styles } from './style';\nimport type { ImperativeModalProps, ModalConfirmConfig, ModalInstance } from './type';\n\n// --- Shared types ---\n\ntype ModalStackEntry = {\n  id: string;\n  props: ImperativeModalProps;\n};\n\n// --- Shared components (stack-independent) ---\n\nconst ModalPortalWrapper = ({\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  return createPortal(children, container);\n};\n\nconst ConfirmBody = ({ config }: { config: ModalConfirmConfig }) => {\n  const { close } = useModalContext();\n  const [loading, setLoading] = useState(false);\n\n  const { cancelText = 'Cancel', content, okButtonProps, okText = 'OK', onCancel, onOk } = config;\n\n  const { danger, className: okUserCls, ...restOkProps } = okButtonProps ?? {};\n\n  const handleCancel = useCallback(() => {\n    close();\n    onCancel?.();\n  }, [close, onCancel]);\n\n  const handleOk = useCallback(async () => {\n    if (onOk) {\n      try {\n        const result = onOk();\n        if (result && typeof (result as any).then === 'function') {\n          setLoading(true);\n          await result;\n          setLoading(false);\n        }\n      } catch {\n        setLoading(false);\n        return;\n      }\n    }\n    close();\n  }, [close, onOk]);\n\n  return (\n    <>\n      {content && <div style={{ padding: '16px 24px' }}>{content}</div>}\n      <ModalFooter>\n        <button\n          className={cx(styles.buttonBase, styles.cancelButton)}\n          type=\"button\"\n          onClick={handleCancel}\n        >\n          {cancelText}\n        </button>\n        <button\n          {...restOkProps}\n          disabled={loading}\n          type=\"button\"\n          className={cx(\n            styles.buttonBase,\n            danger ? styles.dangerOkButton : styles.okButton,\n            okUserCls,\n          )}\n          onClick={handleOk}\n        >\n          {loading && <span className={styles.loadingSpinner} />}\n          {okText}\n        </button>\n      </ModalFooter>\n    </>\n  );\n};\nConfirmBody.displayName = 'ConfirmBody';\n\n// --- Factory ---\n\nexport interface ModalHostProps {\n  root?: HTMLElement | ShadowRoot | null;\n}\n\nexport interface ModalSystem {\n  confirmModal: (config: ModalConfirmConfig) => { close: () => void; destroy: () => void };\n  createModal: (props: ImperativeModalProps) => ModalInstance;\n  ModalHost: React.FC<ModalHostProps>;\n}\n\nlet systemSeed = 0;\n\nexport function createModalSystem(): ModalSystem {\n  const systemId = systemSeed++;\n  const singletonName = systemId === 0 ? 'BaseModalHost' : `BaseModalHost-${systemId}`;\n\n  // --- Stack state (isolated per system) ---\n  let modalStack: ModalStackEntry[] = [];\n  let modalSeed = 0;\n  const listeners = new Set<() => void>();\n\n  const notify = () => listeners.forEach((l) => l());\n  const subscribe = (l: () => void) => {\n    listeners.add(l);\n    return () => listeners.delete(l);\n  };\n  const EMPTY: ModalStackEntry[] = [];\n  const getSnapshot = () => modalStack;\n  const getServerSnapshot = () => EMPTY;\n\n  // --- Stack operations ---\n\n  const updateModal = (id: string, next: Partial<ImperativeModalProps>) => {\n    let changed = false;\n    modalStack = modalStack.map((item) => {\n      if (item.id !== id) return item;\n      changed = true;\n      return { ...item, props: { ...item.props, ...next } };\n    });\n    if (changed) notify();\n  };\n\n  const closeModal = (id: string) => {\n    updateModal(id, { open: false });\n  };\n\n  const destroyModal = (id: string) => {\n    const next = modalStack.filter((item) => item.id !== id);\n    if (next.length === modalStack.length) return;\n    modalStack = next;\n    notify();\n  };\n\n  // --- Stack Item (captures operations via closure) ---\n\n  const StackItem = memo(({ entry }: { entry: ModalStackEntry }) => {\n    const { id, props } = entry;\n    const {\n      children,\n      classNames,\n      content,\n      footer,\n      maskClosable,\n      onOpenChange,\n      onOpenChangeComplete,\n      open,\n      styles: semanticStyles,\n      title,\n      width,\n    } = props;\n\n    const isOpen = open ?? true;\n\n    const handleOpenChange = useCallback(\n      (nextOpen: boolean, eventDetails?: { reason: string }) => {\n        if (!nextOpen && maskClosable === false && eventDetails?.reason === 'outside-press') return;\n        if (!nextOpen) closeModal(id);\n        onOpenChange?.(nextOpen);\n      },\n      [id, maskClosable, onOpenChange],\n    );\n\n    const handleExitComplete = useCallback(() => {\n      onOpenChangeComplete?.(false);\n      destroyModal(id);\n    }, [id, onOpenChangeComplete]);\n\n    const close = useCallback(() => closeModal(id), [id]);\n    const setCanDismissByClickOutside = useCallback(\n      (value: boolean) => updateModal(id, { maskClosable: value }),\n      [id],\n    );\n\n    const showTitle = title !== undefined && title !== false && title !== null;\n\n    return (\n      <ModalContext value={{ close, setCanDismissByClickOutside }}>\n        <ModalRoot\n          open={isOpen}\n          onExitComplete={handleExitComplete}\n          onOpenChange={handleOpenChange}\n        >\n          <ModalPortal>\n            <ModalBackdrop className={classNames?.backdrop} style={semanticStyles?.backdrop} />\n            <ModalPopup\n              className={classNames?.popup}\n              popupStyle={semanticStyles?.popup}\n              width={width}\n            >\n              {showTitle && (\n                <ModalHeader className={classNames?.header} style={semanticStyles?.header}>\n                  <ModalTitle className={classNames?.title} style={semanticStyles?.title}>\n                    {title}\n                  </ModalTitle>\n                  <ModalClose className={classNames?.close} style={semanticStyles?.close} />\n                </ModalHeader>\n              )}\n              <ModalContent className={classNames?.content} style={semanticStyles?.content}>\n                {content ?? children}\n              </ModalContent>\n              {footer}\n            </ModalPopup>\n          </ModalPortal>\n        </ModalRoot>\n      </ModalContext>\n    );\n  });\n  StackItem.displayName = 'ModalStackItem';\n\n  const StackRenderer = memo(({ stack }: { stack: ModalStackEntry[] }) => {\n    const isClient = useIsClient();\n    if (!isClient) return null;\n    return stack.map((entry) => <StackItem entry={entry} key={entry.id} />);\n  });\n  StackRenderer.displayName = 'ModalStackRenderer';\n\n  // --- ModalHost ---\n\n  const Host = ({ root }: ModalHostProps) => {\n    const stack = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n    const isClient = useIsClient();\n\n    useEffect(() => {\n      if (!isClient) return;\n      const scope = root ?? document.body;\n      return registerDevSingleton(singletonName, scope);\n    }, [isClient, root]);\n\n    if (!isClient) return null;\n    if (stack.length === 0) return null;\n\n    return (\n      <ModalPortalWrapper root={root}>\n        <StackRenderer stack={stack} />\n      </ModalPortalWrapper>\n    );\n  };\n\n  // --- createModal ---\n\n  const create = (props: ImperativeModalProps): ModalInstance => {\n    const id = `base-modal-${Date.now()}-${modalSeed++}`;\n    modalStack = [...modalStack, { id, props: { ...props, open: props.open ?? true } }];\n    notify();\n\n    return {\n      close: () => closeModal(id),\n      destroy: () => destroyModal(id),\n      setCanDismissByClickOutside: (value) => updateModal(id, { maskClosable: value }),\n      update: (nextProps) => updateModal(id, nextProps),\n    };\n  };\n\n  // --- confirmModal ---\n\n  const confirm = (config: ModalConfirmConfig) => {\n    const instance = create({\n      content: <ConfirmBody config={config} />,\n      styles: { content: { padding: 0 } },\n      title: config.title,\n      width: 420,\n    });\n\n    return {\n      close: instance.close,\n      destroy: instance.destroy,\n    };\n  };\n\n  return { ModalHost: Host, confirmModal: confirm, createModal: create };\n}\n\n// --- Default global instance (backward compatible) ---\n\nconst defaultSystem = createModalSystem();\nexport const ModalHost = defaultSystem.ModalHost;\nexport const createModal = defaultSystem.createModal;\nexport const confirmModal = defaultSystem.confirmModal;\n"],"mappings":";;;;;;;;;;;;AAmCA,MAAM,sBAAsB,EAC1B,UACA,WAII;CACJ,MAAM,aAAa,eAAe;AAElC,QAAO,aAAa,UADF,QAAQ,cAAc,SAAS,KACT;;AAG1C,MAAM,eAAe,EAAE,aAA6C;CAClE,MAAM,EAAE,UAAU,iBAAiB;CACnC,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAE7C,MAAM,EAAE,aAAa,UAAU,SAAS,eAAe,SAAS,MAAM,UAAU,SAAS;CAEzF,MAAM,EAAE,QAAQ,WAAW,WAAW,GAAG,gBAAgB,iBAAiB,EAAE;CAE5E,MAAM,eAAe,kBAAkB;AACrC,SAAO;AACP,cAAY;IACX,CAAC,OAAO,SAAS,CAAC;CAErB,MAAM,WAAW,YAAY,YAAY;AACvC,MAAI,KACF,KAAI;GACF,MAAM,SAAS,MAAM;AACrB,OAAI,UAAU,OAAQ,OAAe,SAAS,YAAY;AACxD,eAAW,KAAK;AAChB,UAAM;AACN,eAAW,MAAM;;UAEb;AACN,cAAW,MAAM;AACjB;;AAGJ,SAAO;IACN,CAAC,OAAO,KAAK,CAAC;AAEjB,QACE,qBAAA,YAAA,EAAA,UAAA,CACG,WAAW,oBAAC,OAAD;EAAK,OAAO,EAAE,SAAS,aAAa;YAAG;EAAc,CAAA,EACjE,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,UAAD;EACE,WAAW,GAAG,OAAO,YAAY,OAAO,aAAa;EACrD,MAAK;EACL,SAAS;YAER;EACM,CAAA,EACT,qBAAC,UAAD;EACE,GAAI;EACJ,UAAU;EACV,MAAK;EACL,WAAW,GACT,OAAO,YACP,SAAS,OAAO,iBAAiB,OAAO,UACxC,UACD;EACD,SAAS;YATX,CAWG,WAAW,oBAAC,QAAD,EAAM,WAAW,OAAO,gBAAkB,CAAA,EACrD,OACM;IACG,EAAA,CAAA,CACb,EAAA,CAAA;;AAGP,YAAY,cAAc;AAc1B,IAAI,aAAa;AAEjB,SAAgB,oBAAiC;CAC/C,MAAM,WAAW;CACjB,MAAM,gBAAgB,aAAa,IAAI,kBAAkB,iBAAiB;CAG1E,IAAI,aAAgC,EAAE;CACtC,IAAI,YAAY;CAChB,MAAM,4BAAY,IAAI,KAAiB;CAEvC,MAAM,eAAe,UAAU,SAAS,MAAM,GAAG,CAAC;CAClD,MAAM,aAAa,MAAkB;AACnC,YAAU,IAAI,EAAE;AAChB,eAAa,UAAU,OAAO,EAAE;;CAElC,MAAM,QAA2B,EAAE;CACnC,MAAM,oBAAoB;CAC1B,MAAM,0BAA0B;CAIhC,MAAM,eAAe,IAAY,SAAwC;EACvE,IAAI,UAAU;AACd,eAAa,WAAW,KAAK,SAAS;AACpC,OAAI,KAAK,OAAO,GAAI,QAAO;AAC3B,aAAU;AACV,UAAO;IAAE,GAAG;IAAM,OAAO;KAAE,GAAG,KAAK;KAAO,GAAG;KAAM;IAAE;IACrD;AACF,MAAI,QAAS,SAAQ;;CAGvB,MAAM,cAAc,OAAe;AACjC,cAAY,IAAI,EAAE,MAAM,OAAO,CAAC;;CAGlC,MAAM,gBAAgB,OAAe;EACnC,MAAM,OAAO,WAAW,QAAQ,SAAS,KAAK,OAAO,GAAG;AACxD,MAAI,KAAK,WAAW,WAAW,OAAQ;AACvC,eAAa;AACb,UAAQ;;CAKV,MAAM,YAAY,MAAM,EAAE,YAAwC;EAChE,MAAM,EAAE,IAAI,UAAU;EACtB,MAAM,EACJ,UACA,YACA,SACA,QACA,cACA,cACA,sBACA,MACA,QAAQ,gBACR,OACA,UACE;EAEJ,MAAM,SAAS,QAAQ;EAEvB,MAAM,mBAAmB,aACtB,UAAmB,iBAAsC;AACxD,OAAI,CAAC,YAAY,iBAAiB,SAAS,cAAc,WAAW,gBAAiB;AACrF,OAAI,CAAC,SAAU,YAAW,GAAG;AAC7B,kBAAe,SAAS;KAE1B;GAAC;GAAI;GAAc;GAAa,CACjC;EAED,MAAM,qBAAqB,kBAAkB;AAC3C,0BAAuB,MAAM;AAC7B,gBAAa,GAAG;KACf,CAAC,IAAI,qBAAqB,CAAC;EAE9B,MAAM,QAAQ,kBAAkB,WAAW,GAAG,EAAE,CAAC,GAAG,CAAC;EACrD,MAAM,8BAA8B,aACjC,UAAmB,YAAY,IAAI,EAAE,cAAc,OAAO,CAAC,EAC5D,CAAC,GAAG,CACL;EAED,MAAM,YAAY,UAAU,KAAA,KAAa,UAAU,SAAS,UAAU;AAEtE,SACE,oBAAC,cAAD;GAAc,OAAO;IAAE;IAAO;IAA6B;aACzD,oBAAC,WAAD;IACE,MAAM;IACN,gBAAgB;IAChB,cAAc;cAEd,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,eAAD;KAAe,WAAW,YAAY;KAAU,OAAO,gBAAgB;KAAY,CAAA,EACnF,qBAAC,YAAD;KACE,WAAW,YAAY;KACvB,YAAY,gBAAgB;KACrB;eAHT;MAKG,aACC,qBAAC,aAAD;OAAa,WAAW,YAAY;OAAQ,OAAO,gBAAgB;iBAAnE,CACE,oBAAC,YAAD;QAAY,WAAW,YAAY;QAAO,OAAO,gBAAgB;kBAC9D;QACU,CAAA,EACb,oBAAC,YAAD;QAAY,WAAW,YAAY;QAAO,OAAO,gBAAgB;QAAS,CAAA,CAC9D;;MAEhB,oBAAC,cAAD;OAAc,WAAW,YAAY;OAAS,OAAO,gBAAgB;iBAClE,WAAW;OACC,CAAA;MACd;MACU;OACD,EAAA,CAAA;IACJ,CAAA;GACC,CAAA;GAEjB;AACF,WAAU,cAAc;CAExB,MAAM,gBAAgB,MAAM,EAAE,YAA0C;AAEtE,MAAI,CADa,aAAa,CACf,QAAO;AACtB,SAAO,MAAM,KAAK,UAAU,oBAAC,WAAD,EAAkB,OAAwB,EAAZ,MAAM,GAAM,CAAC;GACvE;AACF,eAAc,cAAc;CAI5B,MAAM,QAAQ,EAAE,WAA2B;EACzC,MAAM,QAAQ,qBAAqB,WAAW,aAAa,kBAAkB;EAC7E,MAAM,WAAW,aAAa;AAE9B,kBAAgB;AACd,OAAI,CAAC,SAAU;AAEf,UAAO,qBAAqB,eADd,QAAQ,SAAS,KACkB;KAChD,CAAC,UAAU,KAAK,CAAC;AAEpB,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SACE,oBAAC,oBAAD;GAA0B;aACxB,oBAAC,eAAD,EAAsB,OAAS,CAAA;GACZ,CAAA;;CAMzB,MAAM,UAAU,UAA+C;EAC7D,MAAM,KAAK,cAAc,KAAK,KAAK,CAAC,GAAG;AACvC,eAAa,CAAC,GAAG,YAAY;GAAE;GAAI,OAAO;IAAE,GAAG;IAAO,MAAM,MAAM,QAAQ;IAAM;GAAE,CAAC;AACnF,UAAQ;AAER,SAAO;GACL,aAAa,WAAW,GAAG;GAC3B,eAAe,aAAa,GAAG;GAC/B,8BAA8B,UAAU,YAAY,IAAI,EAAE,cAAc,OAAO,CAAC;GAChF,SAAS,cAAc,YAAY,IAAI,UAAU;GAClD;;CAKH,MAAM,WAAW,WAA+B;EAC9C,MAAM,WAAW,OAAO;GACtB,SAAS,oBAAC,aAAD,EAAqB,QAAU,CAAA;GACxC,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,EAAE;GACnC,OAAO,OAAO;GACd,OAAO;GACR,CAAC;AAEF,SAAO;GACL,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB;;AAGH,QAAO;EAAE,WAAW;EAAM,cAAc;EAAS,aAAa;EAAQ;;AAKxE,MAAM,gBAAgB,mBAAmB;AACzC,MAAa,YAAY,cAAc;AACvC,MAAa,cAAc,cAAc;AACzC,MAAa,eAAe,cAAc"}