{"version":3,"file":"solid.mjs","names":["items: PortalItem[]","item: PortalItem","contextValue: DialogContextValue"],"sources":["../src/solid.tsx"],"sourcesContent":["/** @jsxImportSource @opentui/solid */\n\nimport {\n  BoxRenderable,\n  type KeyEvent,\n  type RenderContext,\n} from \"@opentui/core\";\nimport {\n  createComponent,\n  Portal,\n  useKeyboard,\n  useRenderer,\n  useTerminalDimensions,\n} from \"@opentui/solid\";\nimport {\n  type Accessor,\n  createContext,\n  createEffect,\n  createMemo,\n  createSignal,\n  For,\n  type JSX,\n  onCleanup,\n  type ParentProps,\n  useContext,\n} from \"solid-js\";\nimport { JSX_CONTENT_KEY } from \"./constants\";\nimport { DialogManager } from \"./manager\";\nimport type {\n  AlertContext,\n  ChoiceContext,\n  ConfirmContext,\n  DialogState,\n  PromptContext,\n} from \"./prompts\";\nimport { DialogContainerRenderable } from \"./renderables\";\nimport type {\n  BaseAlertOptions,\n  BaseChoiceOptions,\n  BaseConfirmOptions,\n  BaseDialogActions,\n  BasePromptOptions,\n  Dialog,\n  DialogContainerOptions,\n  DialogId,\n  DialogShowOptions,\n  DialogToClose,\n  InternalDialog,\n  InternalDialogShowOptions,\n} from \"./types\";\n\n/** Function returning JSX. Required because Solid JSX is eagerly evaluated. */\nexport type ContentAccessor = () => JSX.Element;\n\ninterface DialogWithJsx extends InternalDialog {\n  [JSX_CONTENT_KEY]?: ContentAccessor;\n}\n\n/** Internal type for show options that include JSX bridging keys */\ninterface DialogShowOptionsWithJsx extends InternalDialogShowOptions {\n  [JSX_CONTENT_KEY]?: ContentAccessor;\n}\n\ninterface PortalItem {\n  id: string | number;\n  contentAccessor: ContentAccessor;\n  mount: BoxRenderable;\n}\n\nexport interface ShowOptions extends Omit<DialogShowOptions, \"content\"> {\n  /** Must be a function returning JSX: `() => <text>Hi</text>` */\n  content: ContentAccessor;\n}\n\n// ============================================================================\n// Solid Prompt Types\n// ============================================================================\n// These extend the generic base types with Solid-specific content signatures.\n\n/** Content factory for prompt dialogs. */\ntype PromptContent<T> = (ctx: PromptContext<T>) => ContentAccessor;\n\n/** Content factory for confirm dialogs. */\ntype ConfirmContent = (ctx: ConfirmContext) => ContentAccessor;\n\n/** Content factory for alert dialogs. */\ntype AlertContent = (ctx: AlertContext) => ContentAccessor;\n\n/** Content factory for choice dialogs. */\ntype ChoiceContent<K> = (ctx: ChoiceContext<K>) => ContentAccessor;\n\n/**\n * Options for a generic prompt dialog.\n * @template T The type of value the prompt resolves to.\n */\nexport interface PromptOptions<T>\n  extends BasePromptOptions<T, PromptContent<T>> {}\n\n/**\n * Options for a confirm dialog.\n */\nexport interface ConfirmOptions extends BaseConfirmOptions<ConfirmContent> {}\n\n/**\n * Options for an alert dialog.\n */\nexport interface AlertOptions extends BaseAlertOptions<AlertContent> {}\n\n/**\n * Options for a choice dialog.\n * @template K The type of keys for the available choices.\n */\nexport interface ChoiceOptions<K>\n  extends BaseChoiceOptions<ChoiceContent<K>, K> {}\n\n/**\n * Dialog actions for showing, closing, and managing dialogs.\n * Extends BaseDialogActions with async prompt methods.\n */\nexport interface DialogActions extends BaseDialogActions<ShowOptions> {\n  /** Show a generic prompt dialog and wait for a response. */\n  prompt: <T>(options: PromptOptions<T>) => Promise<T | undefined>;\n  /** Show a confirmation dialog and wait for the user to confirm or cancel. */\n  confirm: (options: ConfirmOptions) => Promise<boolean>;\n  /** Show an alert dialog and wait for the user to dismiss it. */\n  alert: (options: AlertOptions) => Promise<void>;\n  /** Show a choice dialog and wait for the user to select an option. */\n  choice: <K>(options: ChoiceOptions<K>) => Promise<K | undefined>;\n}\n\ninterface DialogContextValue {\n  manager: DialogManager;\n  dialogs: Accessor<readonly Dialog[]>;\n}\n\nconst DialogContext = createContext<DialogContextValue>();\n\nconst createPlaceholderContent = () => (ctx: RenderContext) =>\n  new BoxRenderable(ctx, { id: \"~jsx-placeholder\" });\n\n/**\n * Helper to build dialog show options for Solid adapter.\n * Handles both direct show/replace calls and async prompt methods.\n * Includes validation for ContentAccessor.\n *\n * @param content - ContentAccessor or (ctx) => ContentAccessor\n * @param rest - Dialog options excluding content\n * @param ctx - Optional context for async prompts (prompt, confirm, alert, choice)\n */\nfunction buildShowOptions(\n  content: ContentAccessor,\n  rest: Omit<DialogShowOptions, \"content\">,\n): DialogShowOptionsWithJsx;\nfunction buildShowOptions<TCtx>(\n  content: (ctx: TCtx) => ContentAccessor,\n  rest: Omit<DialogShowOptions, \"content\">,\n  ctx: TCtx,\n): DialogShowOptionsWithJsx;\nfunction buildShowOptions(\n  content: ContentAccessor | ((...args: unknown[]) => unknown),\n  rest: Omit<DialogShowOptions, \"content\">,\n  ctx?: unknown,\n): DialogShowOptionsWithJsx {\n  const contentAccessor =\n    ctx !== undefined\n      ? (content as (ctx: unknown) => ContentAccessor)(ctx)\n      : (content as ContentAccessor);\n\n  validateContentAccessor(contentAccessor);\n\n  return {\n    ...rest,\n    content: createPlaceholderContent(),\n    [JSX_CONTENT_KEY]: contentAccessor,\n  } as DialogShowOptionsWithJsx;\n}\n\nfunction validateContentAccessor(\n  content: unknown,\n): asserts content is ContentAccessor {\n  if (typeof content !== \"function\") {\n    throw new Error(\n      `[@opentui-ui/dialog/solid] Invalid content type: expected a function returning JSX, but received ${typeof content}.\\n\\n` +\n        `Solid.js JSX is eagerly evaluated, so you must wrap content in a function:\\n\\n` +\n        `  // CORRECT\\n` +\n        `  dialog.show({ content: () => <text>Hello</text> })\\n\\n` +\n        `  // WRONG - JSX evaluated immediately, before dialog context exists\\n` +\n        `  dialog.show({ content: <text>Hello</text> })\\n\\n` +\n        `See: https://github.com/msmps/opentui-ui for more information.`,\n    );\n  }\n}\n\nfunction useDialogContext(): DialogContextValue {\n  const ctx = useContext(DialogContext);\n\n  if (!ctx) {\n    throw new Error(\n      \"useDialog/useDialogState must be used within a DialogProvider.\\n\\n\" +\n        \"Wrap your app with <DialogProvider>:\\n\\n\" +\n        \"  import { DialogProvider } from '@opentui-ui/dialog/solid';\\n\\n\" +\n        \"  function App() {\\n\" +\n        \"    return (\\n\" +\n        \"      <DialogProvider>\\n\" +\n        \"        <YourContent />\\n\" +\n        \"      </DialogProvider>\\n\" +\n        \"    );\\n\" +\n        \"  }\",\n    );\n  }\n\n  return ctx;\n}\n\n/**\n * Access dialog actions within a DialogProvider.\n *\n * For reactive state, use `useDialogState()` instead.\n *\n * @example\n * ```tsx\n * const dialog = useDialog();\n *\n * // Show a dialog (content must be a function returning JSX)\n * dialog.show({ content: () => <text>Hello</text> });\n *\n * // Close the top dialog\n * dialog.close();\n *\n * // Close a specific dialog\n * dialog.close(dialogId);\n *\n * // Close all dialogs\n * dialog.closeAll();\n * ```\n */\nexport function useDialog(): DialogActions {\n  const { manager } = useDialogContext();\n\n  return {\n    show: (options: ShowOptions) => {\n      const { content, ...rest } = options;\n      return manager.show(buildShowOptions(content, rest));\n    },\n\n    close: (id?: DialogId) => manager.close(id),\n    closeAll: () => manager.closeAll(),\n\n    replace: (options: ShowOptions) => {\n      const { content, ...rest } = options;\n      return manager.replace(buildShowOptions(content, rest));\n    },\n\n    // =====================================================================\n    // Async Prompt Methods (delegate to manager with factory pattern)\n    // =====================================================================\n\n    prompt: <T,>(options: PromptOptions<T>): Promise<T | undefined> => {\n      const { content, fallback, ...rest } = options;\n      return manager.prompt<T>((ctx) => ({\n        ...buildShowOptions(content, rest, ctx),\n        fallback,\n      }));\n    },\n\n    confirm: (options: ConfirmOptions): Promise<boolean> => {\n      const { content, fallback, ...rest } = options;\n      return manager.confirm((ctx) => ({\n        ...buildShowOptions(content, rest, ctx),\n        fallback,\n      }));\n    },\n\n    alert: (options: AlertOptions): Promise<void> => {\n      const { content, ...rest } = options;\n      return manager.alert((ctx) => buildShowOptions(content, rest, ctx));\n    },\n\n    choice: <K,>(options: ChoiceOptions<K>): Promise<K | undefined> => {\n      const { content, fallback, ...rest } = options;\n      return manager.choice<K>((ctx) => ({\n        ...buildShowOptions(content, rest, ctx),\n        fallback,\n      }));\n    },\n  };\n}\n\n/**\n * Subscribe to reactive dialog state with a selector.\n *\n * Returns an accessor that tracks in effects/memos. The selector\n * is called inside a memo, so only the selected value is tracked.\n *\n * @example\n * ```tsx\n * // Subscribe to specific state - returns an accessor\n * const isOpen = useDialogState(s => s.isOpen);\n * const count = useDialogState(s => s.count);\n * const topDialog = useDialogState(s => s.topDialog);\n * const dialogs = useDialogState(s => s.dialogs);\n *\n * // Use in effects - tracks automatically\n * createEffect(() => {\n *   if (isOpen()) {\n *     console.log(`${count()} dialog(s) open`);\n *   }\n * });\n *\n * // Use in JSX - tracks automatically\n * <Show when={isOpen()}>\n *   <text>{count()} dialogs open</text>\n * </Show>\n * ```\n */\nexport function useDialogState<T>(\n  selector: (state: DialogState) => T,\n): Accessor<T> {\n  const { dialogs } = useDialogContext();\n\n  return createMemo(() => {\n    const d = dialogs();\n    const state: DialogState = {\n      isOpen: d.length > 0,\n      dialogs: d,\n      topDialog: d.length > 0 ? d[d.length - 1] : undefined,\n      count: d.length,\n    };\n    return selector(state);\n  });\n}\n\n/**\n * A keyboard hook for dialog content that only fires when the dialog is topmost.\n *\n * This prevents keyboard events from affecting stacked dialogs that are not focused.\n * Use this instead of `useKeyboard` inside dialog content components.\n *\n * @param handler - Keyboard event handler (only called when dialog is topmost)\n * @param dialogId - The dialog's ID from context (e.g., `ctx.dialogId`)\n *\n * @example\n * ```tsx\n * function DeleteConfirmDialog(props: ConfirmContext) {\n *   useDialogKeyboard((key) => {\n *     if (key.name === \"return\") props.resolve(true);\n *     if (key.name === \"escape\") props.resolve(false);\n *   }, props.dialogId);\n *\n *   return () => <text>Press Enter to confirm</text>;\n * }\n * ```\n */\nexport function useDialogKeyboard(\n  handler: (key: KeyEvent) => void | Promise<void>,\n  dialogId: DialogId,\n): void {\n  const isTopmost = useDialogState((s) => s.topDialog?.id === dialogId);\n\n  useKeyboard((key) => {\n    if (isTopmost()) {\n      handler(key);\n    }\n  });\n}\n\nexport interface DialogProviderProps extends DialogContainerOptions {}\n\n/**\n * Provides dialog functionality to children via useDialog() and useDialogState() hooks.\n *\n * @example\n * ```tsx\n * <DialogProvider size=\"medium\">\n *   <App />\n * </DialogProvider>\n * ```\n */\nexport function DialogProvider(props: ParentProps<DialogProviderProps>) {\n  const renderer = useRenderer();\n  const dimensions = useTerminalDimensions();\n\n  const manager = new DialogManager(renderer);\n\n  const container = new DialogContainerRenderable(renderer, {\n    manager,\n    size: props.size,\n    dialogOptions: props.dialogOptions,\n    sizePresets: props.sizePresets,\n    closeOnEscape: props.closeOnEscape,\n    closeOnClickOutside: props.closeOnClickOutside,\n    backdropColor: props.backdropColor,\n    backdropOpacity: props.backdropOpacity,\n    unstyled: props.unstyled,\n  });\n  renderer.root.add(container);\n\n  // Reactive signal for dialog state - drives both useDialogState() reactivity and portal rendering\n  const [dialogs, setDialogs] = createSignal<readonly Dialog[]>([]);\n\n  let disposed = false;\n\n  // Cache maintains stable references for <For> to preserve component state\n  const portalItemCache = new Map<string | number, PortalItem>();\n\n  // Bridge renderable layer to Solid's reactive system\n  const unsubscribe = manager.subscribe((_data: Dialog | DialogToClose) => {\n    queueMicrotask(() => {\n      if (!disposed) {\n        setDialogs(manager.getDialogs());\n      }\n    });\n  });\n\n  onCleanup(() => {\n    disposed = true;\n    unsubscribe();\n    portalItemCache.clear();\n    container.destroyRecursively();\n    renderer.root.remove(container.id);\n    manager.destroy();\n  });\n\n  createEffect(() => {\n    const dims = dimensions();\n    container.updateDimensions(dims.width);\n  });\n\n  const portalItems = createMemo((): PortalItem[] => {\n    // Track dialogs signal to update when dialogs change\n    dialogs();\n\n    const items: PortalItem[] = [];\n    const dialogRenderables = container.getDialogRenderables();\n\n    for (const [id, dialogRenderable] of dialogRenderables) {\n      const dialogWithJsx = dialogRenderable.dialog as DialogWithJsx;\n      const contentAccessor = dialogWithJsx[JSX_CONTENT_KEY];\n\n      if (contentAccessor !== undefined) {\n        const cached = portalItemCache.get(id);\n        const shouldUpdateCachedItem =\n          !cached || cached.mount !== dialogRenderable;\n\n        const item: PortalItem = shouldUpdateCachedItem\n          ? { id, contentAccessor, mount: dialogRenderable }\n          : cached;\n\n        if (shouldUpdateCachedItem) {\n          portalItemCache.set(id, item);\n        }\n\n        items.push(item);\n      }\n    }\n\n    return items;\n  });\n\n  createEffect(() => {\n    // Track dialogs signal to clean cache when dialogs close\n    dialogs();\n\n    const dialogRenderables = container.getDialogRenderables();\n    const activeIds = new Set(dialogRenderables.keys());\n\n    for (const id of portalItemCache.keys()) {\n      if (!activeIds.has(id)) {\n        portalItemCache.delete(id);\n      }\n    }\n  });\n\n  // Context value includes both manager and reactive dialogs signal\n  const contextValue: DialogContextValue = { manager, dialogs };\n\n  // TODO! Refactor to JSX once @opentui/solid 'jsx' exports are fixed!\n  return createComponent(DialogContext.Provider, {\n    value: contextValue,\n    get children() {\n      return [\n        // original {props.children}\n        props.children,\n\n        createComponent(For, {\n          get each() {\n            return portalItems();\n          },\n          children: (item: PortalItem) =>\n            createComponent(Portal, {\n              mount: item.mount,\n              get children() {\n                return item.contentAccessor();\n              },\n            }),\n        }),\n      ];\n    },\n  });\n}\n\n// =============================================================================\n// Re-exports for convenience\n// =============================================================================\n\nexport type {\n  AlertContext,\n  ChoiceContext,\n  ConfirmContext,\n  DialogState,\n  PromptContext,\n} from \"./prompts\";\nexport { type DialogTheme, themes } from \"./themes\";\nexport type {\n  DialogContainerOptions,\n  DialogId,\n  DialogSize,\n  DialogStyle,\n} from \"./types\";\n"],"mappings":"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"}