@ai-matrx/kit 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/kit",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "The always-include AI Matrx kit: the little primitives every Matrx app speaks — autosave that never loses a keystroke, stale-response guards, clipboard with graceful fallbacks — one per subpath, tree-shaken to what you use.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -12,7 +12,6 @@
12
12
  "hooks",
13
13
  "autosave",
14
14
  "clipboard",
15
- "confirm-dialog",
16
15
  "toast",
17
16
  "ai-matrx",
18
17
  "url-state",
@@ -27,7 +26,8 @@
27
26
  "duration",
28
27
  "file-size",
29
28
  "escape-html",
30
- "uuid"
29
+ "uuid",
30
+ "confirm-opener"
31
31
  ],
32
32
  "repository": {
33
33
  "type": "git",
@@ -126,16 +126,6 @@
126
126
  "default": "./dist/drafts.cjs"
127
127
  }
128
128
  },
129
- "./confirm": {
130
- "import": {
131
- "types": "./dist/confirm.d.ts",
132
- "default": "./dist/confirm.js"
133
- },
134
- "require": {
135
- "types": "./dist/confirm.d.cts",
136
- "default": "./dist/confirm.cjs"
137
- }
138
- },
139
129
  "./confirm-opener": {
140
130
  "import": {
141
131
  "types": "./dist/confirm-opener.d.ts",
@@ -298,11 +288,9 @@
298
288
  }
299
289
  },
300
290
  "dependencies": {
301
- "@radix-ui/react-alert-dialog": "^1.1.23",
302
291
  "idb": "^8.0.3",
303
292
  "json5": "^2.2.3",
304
- "jsqr": "^1.4.0",
305
- "tailwind-merge": "^3.6.0"
293
+ "jsqr": "^1.4.0"
306
294
  },
307
295
  "peerDependencies": {
308
296
  "react": ">=18.0.0"
@@ -343,4 +331,4 @@
343
331
  "test:watch": "vitest",
344
332
  "verify:tarball": "node ./scripts/verify-tarball.mjs"
345
333
  }
346
- }
334
+ }
package/dist/confirm.cjs DELETED
@@ -1,353 +0,0 @@
1
- "use client";
2
- "use strict";
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __export = (target, all) => {
10
- for (var name in all)
11
- __defProp(target, name, { get: all[name], enumerable: true });
12
- };
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (let key of __getOwnPropNames(from))
16
- if (!__hasOwnProp.call(to, key) && key !== except)
17
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
- }
19
- return to;
20
- };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
-
31
- // src/confirm.ts
32
- var confirm_exports = {};
33
- __export(confirm_exports, {
34
- ConfirmDialog: () => ConfirmDialog,
35
- ConfirmDialogHost: () => ConfirmDialogHost,
36
- confirm: () => confirm
37
- });
38
- module.exports = __toCommonJS(confirm_exports);
39
-
40
- // src/confirm/opener.ts
41
- var STATE_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.kit.confirm-opener-state");
42
- function getState() {
43
- const holder = globalThis;
44
- let state = holder[STATE_SLOT];
45
- if (!state) {
46
- state = { host: null, queue: [] };
47
- holder[STATE_SLOT] = state;
48
- }
49
- return state;
50
- }
51
- function _registerHost(controller) {
52
- const state = getState();
53
- state.host = controller;
54
- while (state.queue.length > 0) {
55
- const next = state.queue.shift();
56
- controller.show(next.opts, next.resolve);
57
- }
58
- }
59
- function _unregisterHost(controller) {
60
- const state = getState();
61
- if (state.host === controller) state.host = null;
62
- }
63
- function confirm(opts) {
64
- return new Promise((resolve) => {
65
- const state = getState();
66
- if (state.host) {
67
- state.host.show(opts, resolve);
68
- } else {
69
- state.queue.push({ opts, resolve });
70
- }
71
- });
72
- }
73
-
74
- // src/confirm/host.tsx
75
- var React3 = __toESM(require("react"), 1);
76
-
77
- // src/confirm/cn.ts
78
- var import_tailwind_merge = require("tailwind-merge");
79
- function cn(...values) {
80
- return (0, import_tailwind_merge.twMerge)(values.filter(Boolean).join(" "));
81
- }
82
-
83
- // src/confirm/alert-dialog.tsx
84
- var React2 = __toESM(require("react"), 1);
85
- var AlertDialogPrimitive = __toESM(require("@radix-ui/react-alert-dialog"), 1);
86
-
87
- // src/react-tree.ts
88
- var React = __toESM(require("react"), 1);
89
- var REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal");
90
- function treeContainsComponent(node, Component) {
91
- if (node == null || typeof node === "boolean") return false;
92
- if (Array.isArray(node)) {
93
- return node.some((child) => treeContainsComponent(child, Component));
94
- }
95
- if (React.isValidElement(node)) {
96
- if (node.type === Component) return true;
97
- const props = node.props;
98
- return props.children != null ? treeContainsComponent(props.children, Component) : false;
99
- }
100
- if (typeof node === "string" || typeof node === "number") return false;
101
- if (typeof node === "object" && node.$$typeof === REACT_PORTAL_TYPE) {
102
- return treeContainsComponent(
103
- node.children,
104
- Component
105
- );
106
- }
107
- if (typeof node === "object" && Symbol.iterator in node) {
108
- return Array.from(node).some(
109
- (child) => treeContainsComponent(child, Component)
110
- );
111
- }
112
- const runtimeProcess = globalThis.process;
113
- if (runtimeProcess?.env?.NODE_ENV !== "production") {
114
- const keys = typeof node === "object" ? ` with keys {${Object.keys(node).join(", ")}}` : "";
115
- console.error(
116
- `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. React will throw 'Objects are not valid as a React child' at the real render site. Stringify it (e.g. JSON.stringify) before rendering.`,
117
- node
118
- );
119
- }
120
- return false;
121
- }
122
-
123
- // src/confirm/alert-dialog.tsx
124
- var import_jsx_runtime = require("react/jsx-runtime");
125
- var buttonBase = "inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-9 px-4 py-2";
126
- var buttonDefault = "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90";
127
- var buttonOutline = "border border-border bg-card shadow-sm hover:bg-accent hover:text-accent-foreground";
128
- var AlertDialog = AlertDialogPrimitive.Root;
129
- var AlertDialogPortal = AlertDialogPrimitive.Portal;
130
- var AlertDialogOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
131
- AlertDialogPrimitive.Overlay,
132
- {
133
- className: cn(
134
- "fixed inset-0 z-[10000] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
135
- className
136
- ),
137
- ...props,
138
- ref
139
- }
140
- ));
141
- AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
142
- var AlertDialogContentPrimitive = React2.forwardRef(({ ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDialogPrimitive.Content, { ...props, ref, "aria-modal": "true" }));
143
- AlertDialogContentPrimitive.displayName = "AlertDialogContentPrimitive";
144
- var AlertDialogDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
145
- AlertDialogPrimitive.Description,
146
- {
147
- ref,
148
- className: cn("text-sm text-muted-foreground", className),
149
- ...props
150
- }
151
- ));
152
- AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
153
- var AlertDialogContent = React2.forwardRef(({ className, children, container, ...props }, ref) => {
154
- const hasDescription = treeContainsComponent(children, AlertDialogDescription) || treeContainsComponent(children, AlertDialogPrimitive.Description);
155
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AlertDialogPortal, { container: container ?? void 0, children: [
156
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDialogOverlay, {}),
157
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
158
- AlertDialogContentPrimitive,
159
- {
160
- ref,
161
- className: cn(
162
- "fixed left-[50%] top-[50%] z-[10000] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
163
- className
164
- ),
165
- ...props,
166
- children: [
167
- !hasDescription && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDialogPrimitive.Description, { className: "sr-only", children: "Please confirm the action described in this dialog." }),
168
- children
169
- ]
170
- }
171
- )
172
- ] });
173
- });
174
- AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
175
- var AlertDialogHeader = ({
176
- className,
177
- ...props
178
- }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
179
- "div",
180
- {
181
- className: cn(
182
- "flex flex-col space-y-2 text-center sm:text-left",
183
- className
184
- ),
185
- ...props
186
- }
187
- );
188
- AlertDialogHeader.displayName = "AlertDialogHeader";
189
- var AlertDialogFooter = ({
190
- className,
191
- ...props
192
- }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
193
- "div",
194
- {
195
- className: cn(
196
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
197
- className
198
- ),
199
- ...props
200
- }
201
- );
202
- AlertDialogFooter.displayName = "AlertDialogFooter";
203
- var AlertDialogTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
204
- AlertDialogPrimitive.Title,
205
- {
206
- ref,
207
- className: cn("text-lg font-semibold", className),
208
- ...props
209
- }
210
- ));
211
- AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
212
- var AlertDialogAction = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
213
- AlertDialogPrimitive.Action,
214
- {
215
- ref,
216
- className: cn(buttonBase, buttonDefault, className),
217
- ...props
218
- }
219
- ));
220
- AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
221
- var AlertDialogCancel = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
222
- AlertDialogPrimitive.Cancel,
223
- {
224
- ref,
225
- className: cn(buttonBase, buttonOutline, "mt-2 sm:mt-0", className),
226
- ...props
227
- }
228
- ));
229
- AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
230
-
231
- // src/confirm/confirm-dialog.tsx
232
- var import_jsx_runtime2 = require("react/jsx-runtime");
233
- function SpinnerIcon({ className }) {
234
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
235
- "svg",
236
- {
237
- xmlns: "http://www.w3.org/2000/svg",
238
- width: 24,
239
- height: 24,
240
- viewBox: "0 0 24 24",
241
- fill: "none",
242
- stroke: "currentColor",
243
- strokeWidth: 2,
244
- strokeLinecap: "round",
245
- strokeLinejoin: "round",
246
- "aria-hidden": "true",
247
- className,
248
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
249
- }
250
- );
251
- }
252
- function ConfirmDialog({
253
- open,
254
- onOpenChange,
255
- title,
256
- description,
257
- content,
258
- contentClassName,
259
- confirmLabel = "Confirm",
260
- cancelLabel = "Cancel",
261
- variant = "default",
262
- busy = false,
263
- confirmDisabled = false,
264
- portalContainer,
265
- onConfirm
266
- }) {
267
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertDialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
268
- AlertDialogContent,
269
- {
270
- className: contentClassName,
271
- container: portalContainer ?? void 0,
272
- children: [
273
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(AlertDialogHeader, { children: [
274
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertDialogTitle, { children: title }),
275
- description ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertDialogDescription, { children: description }) : null
276
- ] }),
277
- content ?? null,
278
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(AlertDialogFooter, { children: [
279
- cancelLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertDialogCancel, { className: "max-lg:min-h-11", disabled: busy, children: cancelLabel }),
280
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
281
- AlertDialogAction,
282
- {
283
- disabled: busy || confirmDisabled,
284
- onClick: (event) => {
285
- event.preventDefault();
286
- void onConfirm();
287
- },
288
- className: cn(
289
- "max-lg:min-h-11",
290
- variant === "destructive" && "bg-destructive text-destructive-foreground hover:bg-destructive/90"
291
- ),
292
- children: [
293
- busy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SpinnerIcon, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
294
- confirmLabel
295
- ]
296
- }
297
- )
298
- ] })
299
- ]
300
- }
301
- ) });
302
- }
303
-
304
- // src/confirm/host.tsx
305
- var import_jsx_runtime3 = require("react/jsx-runtime");
306
- function ConfirmDialogHost() {
307
- const [active, setActive] = React3.useState(null);
308
- const [tick, setTick] = React3.useState(0);
309
- const queueRef = React3.useRef([]);
310
- React3.useEffect(() => {
311
- const controller = {
312
- show: (opts, resolve) => {
313
- queueRef.current.push({ opts, resolve });
314
- setTick((n) => n + 1);
315
- }
316
- };
317
- _registerHost(controller);
318
- return () => _unregisterHost(controller);
319
- }, []);
320
- React3.useEffect(() => {
321
- if (active === null && queueRef.current.length > 0) {
322
- setActive(queueRef.current.shift());
323
- }
324
- }, [active, tick]);
325
- const handleConfirm = React3.useCallback(() => {
326
- if (!active) return;
327
- active.resolve(true);
328
- setActive(null);
329
- }, [active]);
330
- const handleOpenChange = React3.useCallback(
331
- (open) => {
332
- if (!open && active) {
333
- active.resolve(false);
334
- setActive(null);
335
- }
336
- },
337
- [active]
338
- );
339
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
340
- ConfirmDialog,
341
- {
342
- open: !!active,
343
- onOpenChange: handleOpenChange,
344
- title: active?.opts.title ?? "",
345
- description: active?.opts.description,
346
- confirmLabel: active?.opts.confirmLabel,
347
- cancelLabel: active?.opts.cancelLabel,
348
- variant: active?.opts.variant,
349
- onConfirm: handleConfirm
350
- }
351
- );
352
- }
353
- //# sourceMappingURL=confirm.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/confirm.ts","../src/confirm/opener.ts","../src/confirm/host.tsx","../src/confirm/cn.ts","../src/confirm/alert-dialog.tsx","../src/react-tree.ts","../src/confirm/confirm-dialog.tsx"],"sourcesContent":["/**\n * @ai-matrx/kit/confirm — the confirm-dialog system. Browser dialogs are\n * banned; this is the replacement, both shapes:\n *\n * - Imperative: mount `<ConfirmDialogHost />` ONCE at app root, then from\n * anywhere: `if (!(await confirm({ title: \"Delete?\", variant: \"destructive\" }))) return;`\n * Calls queue until the host mounts; concurrent calls present sequentially.\n * - Declarative: `<ConfirmDialog open onOpenChange onConfirm ... />` inline,\n * when busy state is meaningful (a network delete holding the dialog open).\n *\n * Runtime deps of this subpath (and only this subpath's bundles):\n * `@radix-ui/react-alert-dialog` + `tailwind-merge`. Styling is the Matrx\n * Tailwind semantic-token vocabulary; hosts on other design systems override\n * via `className` / `contentClassName` (last-wins merge).\n */\nexport { confirm } from \"./confirm/opener\";\nexport type { ConfirmOptions } from \"./confirm/opener\";\nexport { ConfirmDialogHost } from \"./confirm/host\";\nexport { ConfirmDialog } from \"./confirm/confirm-dialog\";\nexport type { ConfirmDialogProps } from \"./confirm/confirm-dialog\";\n","/**\n * @ai-matrx/kit/confirm — imperative opener.\n *\n * Pure-TS imperative API for the global confirm dialog. Zero React, zero\n * dialog markup — this module is statically importable from anywhere\n * (hooks, utils, Redux thunks, async handlers, sync code, anything).\n *\n * The host (`ConfirmDialogHost`) registers a controller on mount and\n * unregisters on unmount. Calls made before the host has hydrated queue\n * up and resolve as soon as the host is alive — so a destructive action\n * triggered in the first ~50ms after page load still gets a real\n * confirmation, never a silent default-yes/no. With no host ever mounted,\n * a `confirm()` promise stays pending forever (the original's behavior —\n * it never resolves to a silent default).\n *\n * One dialog at a time: concurrent calls queue and present sequentially.\n *\n * Ported verbatim from matrx-frontend\n * `components/dialogs/confirm/confirmDialogOpener.ts`, with ONE structural\n * inversion: the host/queue state lives on `globalThis` under a\n * `Symbol.for` slot instead of module-level variables. With the package\n * built `splitting: false` in dual ESM/CJS format, this module is\n * duplicated into the root bundle and the `./confirm` bundle, and CJS/ESM\n * each instantiate their own module graph — a module-level variable would\n * silently split the host registration from the callers (the same hazard\n * `@ai-matrx/tap-target` documents for its link registry). Behavior is\n * unchanged; never \"clean this up\" into a module local.\n */\n\nimport type { ReactNode } from \"react\";\n\nexport interface ConfirmOptions {\n title: ReactNode;\n description?: ReactNode | undefined;\n confirmLabel?: string | undefined;\n /** `null` hides the cancel button (acknowledge-only dialogs). */\n cancelLabel?: string | null | undefined;\n variant?: \"default\" | \"destructive\" | undefined;\n}\n\ntype Resolver = (confirmed: boolean) => void;\n\ninterface PendingRequest {\n opts: ConfirmOptions;\n resolve: Resolver;\n}\n\ninterface HostController {\n show: (opts: ConfirmOptions, resolve: Resolver) => void;\n}\n\ninterface OpenerState {\n host: HostController | null;\n queue: PendingRequest[];\n}\n\nconst STATE_SLOT = Symbol.for(\"ai-matrx.kit.confirm-opener-state\");\n\nfunction getState(): OpenerState {\n const holder = globalThis as Record<symbol, OpenerState | undefined>;\n let state = holder[STATE_SLOT];\n if (!state) {\n state = { host: null, queue: [] };\n holder[STATE_SLOT] = state;\n }\n return state;\n}\n\n/** @internal Called by `ConfirmDialogHost` on mount. */\nexport function _registerHost(controller: HostController): void {\n const state = getState();\n state.host = controller;\n while (state.queue.length > 0) {\n const next = state.queue.shift()!;\n controller.show(next.opts, next.resolve);\n }\n}\n\n/** @internal Called by `ConfirmDialogHost` on unmount. */\nexport function _unregisterHost(controller: HostController): void {\n const state = getState();\n if (state.host === controller) state.host = null;\n}\n\n/** @internal Test-only: drop any registered host and pending queue. */\nexport function _resetConfirmOpenerState(): void {\n const state = getState();\n state.host = null;\n state.queue.length = 0;\n}\n\n/**\n * Imperative confirm. Returns a Promise that resolves `true` if the user\n * confirms, `false` if they cancel/dismiss. Replaces `window.confirm`.\n *\n * @example\n * const ok = await confirm({\n * title: \"Delete sandbox\",\n * description: \"This cannot be undone.\",\n * variant: \"destructive\",\n * confirmLabel: \"Delete\",\n * });\n * if (!ok) return;\n */\nexport function confirm(opts: ConfirmOptions): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const state = getState();\n if (state.host) {\n state.host.show(opts, resolve);\n } else {\n state.queue.push({ opts, resolve });\n }\n });\n}\n","\"use client\";\n\n/**\n * `<ConfirmDialogHost />` — render ONCE, near the root of every provider\n * tree, so the imperative `confirm()` always has a live host to dispatch to.\n * Pre-mount calls queue inside `opener.ts` and resolve as soon as the host\n * registers.\n *\n * Ported from matrx-frontend `components/dialogs/confirm/\n * {ConfirmDialogHost,ConfirmDialogHostImpl}.tsx`, with the loading seam\n * inverted: the original split shell + impl and loaded the impl via\n * `next/dynamic({ ssr: false })` to keep radix out of route entry chunks.\n * A framework-agnostic package cannot use `next/dynamic`, so the host is\n * ONE directly-imported component; hosts that want the original's\n * code-splitting lazy-load the subpath themselves, e.g.\n * `dynamic(() => import(\"@ai-matrx/kit/confirm\").then(m => m.ConfirmDialogHost), { ssr: false })`.\n * The \"host renders `<ConfirmDialogHost/>` once\" contract is unchanged.\n *\n * Imperative model: calls to `confirm(...)` from anywhere push a request\n * into a ref-backed queue; this component drains the queue one item at a\n * time and renders a `<ConfirmDialog>` for the currently-active request.\n * Resolving Promise<boolean> happens on Confirm click (true), or on\n * dismiss/cancel (false). The dialog closes immediately on click — callers\n * that need an in-dialog busy spinner during async work should use the\n * inline `<ConfirmDialog>` with the `busy` prop instead.\n */\n\nimport * as React from \"react\";\n\nimport { ConfirmDialog } from \"./confirm-dialog\";\nimport {\n _registerHost,\n _unregisterHost,\n type ConfirmOptions,\n} from \"./opener\";\n\ninterface ActiveRequest {\n opts: ConfirmOptions;\n resolve: (confirmed: boolean) => void;\n}\n\nexport function ConfirmDialogHost() {\n const [active, setActive] = React.useState<ActiveRequest | null>(null);\n const [tick, setTick] = React.useState(0);\n const queueRef = React.useRef<ActiveRequest[]>([]);\n\n // Register/unregister the controller exactly once. The controller's\n // `show` always pushes onto the queue and bumps `tick`; the drain\n // effect below picks up from there. This avoids stale-closure bugs\n // around `active`.\n React.useEffect(() => {\n const controller = {\n show: (opts: ConfirmOptions, resolve: (confirmed: boolean) => void) => {\n queueRef.current.push({ opts, resolve });\n setTick((n) => n + 1);\n },\n };\n _registerHost(controller);\n return () => _unregisterHost(controller);\n }, []);\n\n // Drain the queue whenever nothing is showing.\n React.useEffect(() => {\n if (active === null && queueRef.current.length > 0) {\n setActive(queueRef.current.shift()!);\n }\n }, [active, tick]);\n\n const handleConfirm = React.useCallback(() => {\n if (!active) return;\n active.resolve(true);\n setActive(null);\n }, [active]);\n\n const handleOpenChange = React.useCallback(\n (open: boolean) => {\n if (!open && active) {\n active.resolve(false);\n setActive(null);\n }\n },\n [active],\n );\n\n return (\n <ConfirmDialog\n open={!!active}\n onOpenChange={handleOpenChange}\n title={active?.opts.title ?? \"\"}\n description={active?.opts.description}\n confirmLabel={active?.opts.confirmLabel}\n cancelLabel={active?.opts.cancelLabel}\n variant={active?.opts.variant}\n onConfirm={handleConfirm}\n />\n );\n}\n","import { twMerge } from \"tailwind-merge\";\n\n/**\n * Tailwind-aware className merge. The original app's `cn` is\n * `twMerge(clsx(inputs))`; here `clsx` is dropped (every call site passes\n * strings / false), but `tailwind-merge` is KEPT on purpose: the public\n * `className` / `contentClassName` overrides depend on last-wins conflict\n * resolution (e.g. a host's `max-w-3xl` must beat the built-in `max-w-lg`,\n * a destructive `bg-destructive` must beat the default `bg-primary`).\n * A naive join would leave both classes applied and let stylesheet order\n * decide — a real behavior divergence from the original.\n */\nexport function cn(\n ...values: Array<string | null | undefined | false>\n): string {\n return twMerge(values.filter(Boolean).join(\" \"));\n}\n","\"use client\";\n\n/**\n * Inlined shadcn-style wrapper over `@radix-ui/react-alert-dialog` — the one\n * real runtime dependency of the `./confirm` subpath (this subpath's product\n * IS the dialog). Ported from matrx-frontend `components/ui/alert-dialog.tsx`\n * with the host-shaped seams inverted:\n *\n * - `usePopoutContainer` (window-panels popout portal retargeting) is dropped:\n * the portal targets the Radix default (`document.body`). Hosts with exotic\n * portal needs pass `container` on `AlertDialogPortal` themselves.\n * - `buttonVariants` from the design system is inlined as the exact class\n * strings the two footer buttons use (base + default + outline variants,\n * design-system `button.tsx` as of this port). No cva dependency.\n * - Styling keeps the Tailwind semantic-token classes VERBATIM (`bg-background`,\n * `text-muted-foreground`, `bg-primary`, `border-border`, ...) — the platform\n * vocabulary. Hosts on other design systems override via the `className` /\n * `contentClassName` props (classes merge last-wins via tailwind-merge).\n *\n * THE ROOT RENDERS UNCONDITIONALLY — no mount gate. Radix ids come from\n * React's SSR-stable `useId`, so there is no SSR/client id mismatch to hide\n * from (the original's D144 ruling).\n */\n\nimport * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"./cn\";\nimport { treeContainsComponent } from \"../react-tree\";\n\n/**\n * Inlined design-system button classes (base + the two variants the alert\n * dialog footer uses). Source of truth while the originals live:\n * aidream `apps/shared/design-system/src/button.tsx`.\n */\nconst buttonBase =\n \"inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-9 px-4 py-2\";\nconst buttonDefault =\n \"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90\";\nconst buttonOutline =\n \"border border-border bg-card shadow-sm hover:bg-accent hover:text-accent-foreground\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ComponentRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-[10000] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\n/**\n * Unstyled, non-portalling Content for custom AlertDialog layouts. AlertDialog\n * is always modal, so this keeps its ARIA semantics explicit and consistent.\n */\nconst AlertDialogContentPrimitive = React.forwardRef<\n React.ComponentRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ ...props }, ref) => (\n <AlertDialogPrimitive.Content {...props} ref={ref} aria-modal=\"true\" />\n));\nAlertDialogContentPrimitive.displayName = \"AlertDialogContentPrimitive\";\n\nconst AlertDialogDescription = React.forwardRef<\n React.ComponentRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ComponentRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content> & {\n /**\n * Portal target. Default (undefined): Radix's default, `document.body`.\n * Hosts with retargeting needs (e.g. a popped-out browser window whose\n * dialog must render in THAT window's document) pass the element here.\n */\n container?: HTMLElement | null | undefined;\n }\n>(({ className, children, container, ...props }, ref) => {\n const hasDescription =\n treeContainsComponent(children, AlertDialogDescription) ||\n treeContainsComponent(children, AlertDialogPrimitive.Description);\n return (\n <AlertDialogPortal container={container ?? undefined}>\n <AlertDialogOverlay />\n <AlertDialogContentPrimitive\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-[10000] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n >\n {!hasDescription && (\n <AlertDialogPrimitive.Description className=\"sr-only\">\n Please confirm the action described in this dialog.\n </AlertDialogPrimitive.Description>\n )}\n {children}\n </AlertDialogContentPrimitive>\n </AlertDialogPortal>\n );\n});\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ComponentRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ComponentRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonBase, buttonDefault, className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ComponentRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(buttonBase, buttonOutline, \"mt-2 sm:mt-0\", className)}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogContentPrimitive,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n","/**\n * @ai-matrx/kit/react-tree — safe React children-tree scanning.\n *\n * Ported from matrx-frontend `lib/react/treeContainsComponent.ts`; this\n * subpath is the ONE home of the scanner inside the kit (the `/confirm`\n * subpath's alert-dialog imports it from here — no duplicate bodies).\n *\n * Two deliberate divergences from the frontend original, both documented:\n * - the dev-mode scream checks `typeof process` first, since this package may\n * load in an unbundled browser context where `process` is undefined;\n * - a React PORTAL child (`createPortal(...)` passed as a child) is a valid\n * React child, but it is not an element, an iterable, or a primitive — the\n * original fell through to the non-renderable branch, screamed a false\n * positive in dev, and skipped the portal's content. Portals are now\n * recognized and their children traversed.\n */\n\nimport * as React from \"react\";\n\nconst REACT_PORTAL_TYPE = Symbol.for(\"react.portal\");\n\n/**\n * Returns true if `Component` appears anywhere in the React element tree under\n * `node`. Used to detect optional a11y children (e.g. DialogDescription)\n * without rendering duplicates.\n *\n * DEFENSIVE + LOUD. A non-renderable node — a plain object or function passed\n * as a React child — is a real bug: React throws \"Objects are not valid as a\n * React child\" the instant it renders one. This a11y probe must NOT be the\n * crash site. `React.Children.toArray` would throw HERE, producing a trace that\n * points at the dialog primitive instead of the component that leaked the\n * object (this misdirection has burned real debugging hours). So we walk the\n * tree by hand, SKIP any non-renderable node, and scream in dev with its keys —\n * then let React report the defect at the true render site with the offending\n * component in the stack. For every VALID tree the result is identical to the\n * old `React.Children.toArray(node).some(...)`.\n */\nexport function treeContainsComponent(\n node: React.ReactNode,\n Component: React.ElementType,\n): boolean {\n if (node == null || typeof node === \"boolean\") return false;\n\n if (Array.isArray(node)) {\n return node.some((child) => treeContainsComponent(child, Component));\n }\n\n if (React.isValidElement(node)) {\n if (node.type === Component) return true;\n const props = node.props as { children?: React.ReactNode };\n return props.children != null\n ? treeContainsComponent(props.children, Component)\n : false;\n }\n\n // Strings / numbers are valid leaf children but never the Component.\n if (typeof node === \"string\" || typeof node === \"number\") return false;\n\n // A portal is a valid child that is NOT an element: traverse its content.\n if (\n typeof node === \"object\" &&\n (node as { $$typeof?: unknown }).$$typeof === REACT_PORTAL_TYPE\n ) {\n return treeContainsComponent(\n (node as { children?: React.ReactNode }).children,\n Component,\n );\n }\n\n // Non-array iterables (Set, Map, generator) are valid React children — React\n // supports them — so traverse rather than reject.\n if (typeof node === \"object\" && Symbol.iterator in node) {\n return Array.from(node as Iterable<React.ReactNode>).some((child) =>\n treeContainsComponent(child, Component),\n );\n }\n\n // Anything else (a raw object, a function) is NOT a valid React child. React\n // will throw when it renders this; we must not throw first and hide the cause.\n const runtimeProcess = (\n globalThis as { process?: { env?: { NODE_ENV?: string } } }\n ).process;\n if (runtimeProcess?.env?.NODE_ENV !== \"production\") {\n const keys =\n typeof node === \"object\"\n ? ` with keys {${Object.keys(node).join(\", \")}}`\n : \"\";\n console.error(\n `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. ` +\n \"React will throw 'Objects are not valid as a React child' at the real render site. \" +\n \"Stringify it (e.g. JSON.stringify) before rendering.\",\n node,\n );\n }\n return false;\n}\n","\"use client\";\n\n/**\n * Declarative `<ConfirmDialog />` — drop-in replacement for `window.confirm`.\n * Ported verbatim from matrx-frontend `components/ui/confirm-dialog.tsx`;\n * the only inversion is the busy spinner: `Loader2` from lucide-react is\n * inlined as a single SVG (the `@ai-matrx/tap-target` precedent — one icon\n * does not justify an icon dependency). Path annotated below.\n *\n * Pattern: hold the pending target in state, render <ConfirmDialog />\n * once at the bottom of the component, and open it by setting the target.\n * When busy state is meaningful (e.g. a network delete that should hold the\n * dialog open with a spinner), use THIS component inline; the imperative\n * `confirm()` closes immediately on click.\n */\n\nimport * as React from \"react\";\n\nimport { cn } from \"./cn\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"./alert-dialog\";\n\n/** lucide `loader-circle` (a.k.a. `Loader2`) v1.22.0, inlined. */\nfunction SpinnerIcon({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={24}\n height={24}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className={className}\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n );\n}\n\nexport interface ConfirmDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: React.ReactNode;\n description?: React.ReactNode | undefined;\n /**\n * Rich body rendered between the header and the footer, OUTSIDE the\n * description `<p>` — use for block-level content (diffs, previews, lists)\n * that would be invalid HTML inside `description`.\n */\n content?: React.ReactNode | undefined;\n /** Extra classes for the dialog content (e.g. a wider max-w for diffs). */\n contentClassName?: string | undefined;\n confirmLabel?: string | undefined;\n /**\n * `null` hides the cancel button entirely — for acknowledge-only dialogs\n * where there is nothing to cancel. Anything else labels it.\n */\n cancelLabel?: string | null | undefined;\n variant?: \"default\" | \"destructive\" | undefined;\n busy?: boolean | undefined;\n /**\n * Blocks confirming without pretending work is in flight. For a dialog whose\n * `content` asks the user something the action cannot proceed without — the\n * choice is missing, not loading — `busy` would show a misleading spinner.\n */\n confirmDisabled?: boolean | undefined;\n /**\n * Portal target for the dialog. Default (undefined): `document.body`.\n * Hosts with portal-retargeting needs (e.g. rendering into a popped-out\n * browser window's document) inject the element here — the seam exists so\n * that concern stays host-shaped.\n */\n portalContainer?: HTMLElement | null | undefined;\n onConfirm: () => void | Promise<void>;\n}\n\n/**\n * Drop-in replacement for `window.confirm`. Use this anywhere you would\n * otherwise reach for a browser-level confirm dialog.\n */\nexport function ConfirmDialog({\n open,\n onOpenChange,\n title,\n description,\n content,\n contentClassName,\n confirmLabel = \"Confirm\",\n cancelLabel = \"Cancel\",\n variant = \"default\",\n busy = false,\n confirmDisabled = false,\n portalContainer,\n onConfirm,\n}: ConfirmDialogProps) {\n return (\n <AlertDialog open={open} onOpenChange={onOpenChange}>\n <AlertDialogContent\n className={contentClassName}\n container={portalContainer ?? undefined}\n >\n <AlertDialogHeader>\n <AlertDialogTitle>{title}</AlertDialogTitle>\n {description ? (\n <AlertDialogDescription>{description}</AlertDialogDescription>\n ) : null}\n </AlertDialogHeader>\n {content ?? null}\n <AlertDialogFooter>\n {cancelLabel === null ? null : (\n <AlertDialogCancel className=\"max-lg:min-h-11\" disabled={busy}>\n {cancelLabel}\n </AlertDialogCancel>\n )}\n <AlertDialogAction\n disabled={busy || confirmDisabled}\n onClick={(event) => {\n event.preventDefault();\n void onConfirm();\n }}\n className={cn(\n \"max-lg:min-h-11\",\n variant === \"destructive\" &&\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n )}\n >\n {busy ? <SpinnerIcon className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {confirmLabel}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n );\n}\n"],"mappings":"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","names":["React","React","import_jsx_runtime","import_jsx_runtime"]}
@@ -1,139 +0,0 @@
1
- import * as React from 'react';
2
- import { ReactNode } from 'react';
3
-
4
- /**
5
- * @ai-matrx/kit/confirm — imperative opener.
6
- *
7
- * Pure-TS imperative API for the global confirm dialog. Zero React, zero
8
- * dialog markup — this module is statically importable from anywhere
9
- * (hooks, utils, Redux thunks, async handlers, sync code, anything).
10
- *
11
- * The host (`ConfirmDialogHost`) registers a controller on mount and
12
- * unregisters on unmount. Calls made before the host has hydrated queue
13
- * up and resolve as soon as the host is alive — so a destructive action
14
- * triggered in the first ~50ms after page load still gets a real
15
- * confirmation, never a silent default-yes/no. With no host ever mounted,
16
- * a `confirm()` promise stays pending forever (the original's behavior —
17
- * it never resolves to a silent default).
18
- *
19
- * One dialog at a time: concurrent calls queue and present sequentially.
20
- *
21
- * Ported verbatim from matrx-frontend
22
- * `components/dialogs/confirm/confirmDialogOpener.ts`, with ONE structural
23
- * inversion: the host/queue state lives on `globalThis` under a
24
- * `Symbol.for` slot instead of module-level variables. With the package
25
- * built `splitting: false` in dual ESM/CJS format, this module is
26
- * duplicated into the root bundle and the `./confirm` bundle, and CJS/ESM
27
- * each instantiate their own module graph — a module-level variable would
28
- * silently split the host registration from the callers (the same hazard
29
- * `@ai-matrx/tap-target` documents for its link registry). Behavior is
30
- * unchanged; never "clean this up" into a module local.
31
- */
32
-
33
- interface ConfirmOptions {
34
- title: ReactNode;
35
- description?: ReactNode | undefined;
36
- confirmLabel?: string | undefined;
37
- /** `null` hides the cancel button (acknowledge-only dialogs). */
38
- cancelLabel?: string | null | undefined;
39
- variant?: "default" | "destructive" | undefined;
40
- }
41
- /**
42
- * Imperative confirm. Returns a Promise that resolves `true` if the user
43
- * confirms, `false` if they cancel/dismiss. Replaces `window.confirm`.
44
- *
45
- * @example
46
- * const ok = await confirm({
47
- * title: "Delete sandbox",
48
- * description: "This cannot be undone.",
49
- * variant: "destructive",
50
- * confirmLabel: "Delete",
51
- * });
52
- * if (!ok) return;
53
- */
54
- declare function confirm(opts: ConfirmOptions): Promise<boolean>;
55
-
56
- /**
57
- * `<ConfirmDialogHost />` — render ONCE, near the root of every provider
58
- * tree, so the imperative `confirm()` always has a live host to dispatch to.
59
- * Pre-mount calls queue inside `opener.ts` and resolve as soon as the host
60
- * registers.
61
- *
62
- * Ported from matrx-frontend `components/dialogs/confirm/
63
- * {ConfirmDialogHost,ConfirmDialogHostImpl}.tsx`, with the loading seam
64
- * inverted: the original split shell + impl and loaded the impl via
65
- * `next/dynamic({ ssr: false })` to keep radix out of route entry chunks.
66
- * A framework-agnostic package cannot use `next/dynamic`, so the host is
67
- * ONE directly-imported component; hosts that want the original's
68
- * code-splitting lazy-load the subpath themselves, e.g.
69
- * `dynamic(() => import("@ai-matrx/kit/confirm").then(m => m.ConfirmDialogHost), { ssr: false })`.
70
- * The "host renders `<ConfirmDialogHost/>` once" contract is unchanged.
71
- *
72
- * Imperative model: calls to `confirm(...)` from anywhere push a request
73
- * into a ref-backed queue; this component drains the queue one item at a
74
- * time and renders a `<ConfirmDialog>` for the currently-active request.
75
- * Resolving Promise<boolean> happens on Confirm click (true), or on
76
- * dismiss/cancel (false). The dialog closes immediately on click — callers
77
- * that need an in-dialog busy spinner during async work should use the
78
- * inline `<ConfirmDialog>` with the `busy` prop instead.
79
- */
80
-
81
- declare function ConfirmDialogHost(): React.JSX.Element;
82
-
83
- /**
84
- * Declarative `<ConfirmDialog />` — drop-in replacement for `window.confirm`.
85
- * Ported verbatim from matrx-frontend `components/ui/confirm-dialog.tsx`;
86
- * the only inversion is the busy spinner: `Loader2` from lucide-react is
87
- * inlined as a single SVG (the `@ai-matrx/tap-target` precedent — one icon
88
- * does not justify an icon dependency). Path annotated below.
89
- *
90
- * Pattern: hold the pending target in state, render <ConfirmDialog />
91
- * once at the bottom of the component, and open it by setting the target.
92
- * When busy state is meaningful (e.g. a network delete that should hold the
93
- * dialog open with a spinner), use THIS component inline; the imperative
94
- * `confirm()` closes immediately on click.
95
- */
96
-
97
- interface ConfirmDialogProps {
98
- open: boolean;
99
- onOpenChange: (open: boolean) => void;
100
- title: React.ReactNode;
101
- description?: React.ReactNode | undefined;
102
- /**
103
- * Rich body rendered between the header and the footer, OUTSIDE the
104
- * description `<p>` — use for block-level content (diffs, previews, lists)
105
- * that would be invalid HTML inside `description`.
106
- */
107
- content?: React.ReactNode | undefined;
108
- /** Extra classes for the dialog content (e.g. a wider max-w for diffs). */
109
- contentClassName?: string | undefined;
110
- confirmLabel?: string | undefined;
111
- /**
112
- * `null` hides the cancel button entirely — for acknowledge-only dialogs
113
- * where there is nothing to cancel. Anything else labels it.
114
- */
115
- cancelLabel?: string | null | undefined;
116
- variant?: "default" | "destructive" | undefined;
117
- busy?: boolean | undefined;
118
- /**
119
- * Blocks confirming without pretending work is in flight. For a dialog whose
120
- * `content` asks the user something the action cannot proceed without — the
121
- * choice is missing, not loading — `busy` would show a misleading spinner.
122
- */
123
- confirmDisabled?: boolean | undefined;
124
- /**
125
- * Portal target for the dialog. Default (undefined): `document.body`.
126
- * Hosts with portal-retargeting needs (e.g. rendering into a popped-out
127
- * browser window's document) inject the element here — the seam exists so
128
- * that concern stays host-shaped.
129
- */
130
- portalContainer?: HTMLElement | null | undefined;
131
- onConfirm: () => void | Promise<void>;
132
- }
133
- /**
134
- * Drop-in replacement for `window.confirm`. Use this anywhere you would
135
- * otherwise reach for a browser-level confirm dialog.
136
- */
137
- declare function ConfirmDialog({ open, onOpenChange, title, description, content, contentClassName, confirmLabel, cancelLabel, variant, busy, confirmDisabled, portalContainer, onConfirm, }: ConfirmDialogProps): React.JSX.Element;
138
-
139
- export { ConfirmDialog, ConfirmDialogHost, type ConfirmDialogProps, type ConfirmOptions, confirm };