@ai-matrx/design-system 0.14.2 → 0.15.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +26 -0
  3. package/dist/data-table/copy-helpers.cjs +149 -0
  4. package/dist/data-table/copy-helpers.cjs.map +1 -0
  5. package/dist/data-table/copy-helpers.d.cts +31 -0
  6. package/dist/data-table/copy-helpers.d.ts +31 -0
  7. package/dist/data-table/copy-helpers.js +127 -0
  8. package/dist/data-table/copy-helpers.js.map +1 -0
  9. package/dist/data-table/copy-types.cjs +19 -0
  10. package/dist/data-table/copy-types.cjs.map +1 -0
  11. package/dist/data-table/copy-types.d.cts +137 -0
  12. package/dist/data-table/copy-types.d.ts +137 -0
  13. package/dist/data-table/copy-types.js +1 -0
  14. package/dist/data-table/copy-types.js.map +1 -0
  15. package/dist/data-table/data-row-inspector.cjs +1016 -0
  16. package/dist/data-table/data-row-inspector.cjs.map +1 -0
  17. package/dist/data-table/data-row-inspector.d.cts +34 -0
  18. package/dist/data-table/data-row-inspector.d.ts +34 -0
  19. package/dist/data-table/data-row-inspector.js +988 -0
  20. package/dist/data-table/data-row-inspector.js.map +1 -0
  21. package/dist/data-table/data-row-window.cjs +1136 -0
  22. package/dist/data-table/data-row-window.cjs.map +1 -0
  23. package/dist/data-table/data-row-window.d.cts +29 -0
  24. package/dist/data-table/data-row-window.d.ts +29 -0
  25. package/dist/data-table/data-row-window.js +1110 -0
  26. package/dist/data-table/data-row-window.js.map +1 -0
  27. package/dist/data-table/filter-engine.cjs +314 -0
  28. package/dist/data-table/filter-engine.cjs.map +1 -0
  29. package/dist/data-table/filter-engine.d.cts +35 -0
  30. package/dist/data-table/filter-engine.d.ts +35 -0
  31. package/dist/data-table/filter-engine.js +292 -0
  32. package/dist/data-table/filter-engine.js.map +1 -0
  33. package/dist/data-table/host.cjs +40 -0
  34. package/dist/data-table/host.cjs.map +1 -0
  35. package/dist/data-table/host.d.cts +73 -0
  36. package/dist/data-table/host.d.ts +73 -0
  37. package/dist/data-table/host.js +20 -0
  38. package/dist/data-table/host.js.map +1 -0
  39. package/dist/data-table/index.cjs +6865 -0
  40. package/dist/data-table/index.cjs.map +1 -0
  41. package/dist/data-table/index.d.cts +27 -0
  42. package/dist/data-table/index.d.ts +27 -0
  43. package/dist/data-table/index.js +6869 -0
  44. package/dist/data-table/index.js.map +1 -0
  45. package/dist/data-table/infer-filter.cjs +114 -0
  46. package/dist/data-table/infer-filter.cjs.map +1 -0
  47. package/dist/data-table/infer-filter.d.cts +17 -0
  48. package/dist/data-table/infer-filter.d.ts +17 -0
  49. package/dist/data-table/infer-filter.js +92 -0
  50. package/dist/data-table/infer-filter.js.map +1 -0
  51. package/dist/data-table/layered-filters.cjs +249 -0
  52. package/dist/data-table/layered-filters.cjs.map +1 -0
  53. package/dist/data-table/layered-filters.d.cts +3 -0
  54. package/dist/data-table/layered-filters.d.ts +3 -0
  55. package/dist/data-table/layered-filters.js +229 -0
  56. package/dist/data-table/layered-filters.js.map +1 -0
  57. package/dist/data-table/pagination.cjs +595 -0
  58. package/dist/data-table/pagination.cjs.map +1 -0
  59. package/dist/data-table/pagination.d.cts +34 -0
  60. package/dist/data-table/pagination.d.ts +34 -0
  61. package/dist/data-table/pagination.js +563 -0
  62. package/dist/data-table/pagination.js.map +1 -0
  63. package/dist/data-table/query-control.cjs +129 -0
  64. package/dist/data-table/query-control.cjs.map +1 -0
  65. package/dist/data-table/query-control.d.cts +32 -0
  66. package/dist/data-table/query-control.d.ts +32 -0
  67. package/dist/data-table/query-control.js +107 -0
  68. package/dist/data-table/query-control.js.map +1 -0
  69. package/dist/data-table/scroll-pagination.cjs +222 -0
  70. package/dist/data-table/scroll-pagination.cjs.map +1 -0
  71. package/dist/data-table/scroll-pagination.d.cts +37 -0
  72. package/dist/data-table/scroll-pagination.d.ts +37 -0
  73. package/dist/data-table/scroll-pagination.js +202 -0
  74. package/dist/data-table/scroll-pagination.js.map +1 -0
  75. package/dist/data-table/types.cjs +19 -0
  76. package/dist/data-table/types.cjs.map +1 -0
  77. package/dist/data-table/types.d.cts +3 -0
  78. package/dist/data-table/types.d.ts +3 -0
  79. package/dist/data-table/types.js +1 -0
  80. package/dist/data-table/types.js.map +1 -0
  81. package/dist/data-table/url-state.cjs +201 -0
  82. package/dist/data-table/url-state.cjs.map +1 -0
  83. package/dist/data-table/url-state.d.cts +33 -0
  84. package/dist/data-table/url-state.d.ts +33 -0
  85. package/dist/data-table/url-state.js +184 -0
  86. package/dist/data-table/url-state.js.map +1 -0
  87. package/dist/data-table/uuid-cell.cjs +371 -0
  88. package/dist/data-table/uuid-cell.cjs.map +1 -0
  89. package/dist/data-table/uuid-cell.d.cts +31 -0
  90. package/dist/data-table/uuid-cell.d.ts +31 -0
  91. package/dist/data-table/uuid-cell.js +345 -0
  92. package/dist/data-table/uuid-cell.js.map +1 -0
  93. package/dist/data-table/xlsx.cjs +100 -0
  94. package/dist/data-table/xlsx.cjs.map +1 -0
  95. package/dist/data-table/xlsx.d.cts +16 -0
  96. package/dist/data-table/xlsx.d.ts +16 -0
  97. package/dist/data-table/xlsx.js +70 -0
  98. package/dist/data-table/xlsx.js.map +1 -0
  99. package/dist/index.cjs +10 -6
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.d.cts +3 -4
  102. package/dist/index.d.ts +3 -4
  103. package/dist/index.js +10 -6
  104. package/dist/index.js.map +1 -1
  105. package/dist/styles.css +22 -0
  106. package/dist/types-ClaxTaXq.d.ts +798 -0
  107. package/dist/types-XXbVB1sh.d.cts +798 -0
  108. package/package.json +164 -1
@@ -0,0 +1,1016 @@
1
+ "use client";
2
+ "use strict";
3
+ "use client";
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
+
32
+ // src/data-table/DataRowInspector.tsx
33
+ var DataRowInspector_exports = {};
34
+ __export(DataRowInspector_exports, {
35
+ DataRowInspector: () => DataRowInspector
36
+ });
37
+ module.exports = __toCommonJS(DataRowInspector_exports);
38
+
39
+ // src/cn.ts
40
+ var import_clsx = require("clsx");
41
+ var import_tailwind_merge = require("tailwind-merge");
42
+ function cn(...inputs) {
43
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
44
+ }
45
+
46
+ // src/data-table/copy.tsx
47
+ var import_react3 = require("react");
48
+ var import_clipboard = require("@ai-matrx/kit/clipboard");
49
+
50
+ // src/button.tsx
51
+ var import_react_slot = require("@radix-ui/react-slot");
52
+ var import_class_variance_authority = require("class-variance-authority");
53
+ var React = __toESM(require("react"), 1);
54
+ var import_jsx_runtime = require("react/jsx-runtime");
55
+ var buttonVariants = (0, import_class_variance_authority.cva)(
56
+ "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",
57
+ {
58
+ variants: {
59
+ variant: {
60
+ default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
61
+ /**
62
+ * An explicit spelling of `default`, identical by construction. It is
63
+ * not decoration: matrx-frontend's `ButtonMine` fork carried it, ~17
64
+ * call sites say `variant="primary"`, and the alternative to keeping
65
+ * the word was a host shim translating a prop — the massage C22 bans.
66
+ */
67
+ primary: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
68
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
69
+ /** The affirmative twin of `destructive` — confirm, approve, publish. */
70
+ success: "bg-success text-success-foreground shadow-sm hover:bg-success/90",
71
+ outline: "border border-border bg-card shadow-sm hover:bg-accent hover:text-accent-foreground",
72
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
73
+ ghost: "hover:bg-accent hover:text-accent-foreground",
74
+ link: "text-primary underline-offset-4 hover:underline",
75
+ subtle: "border border-transparent bg-muted/50 text-foreground hover:border-border hover:bg-muted"
76
+ },
77
+ /**
78
+ * ONE size scale, xs → 3xl, plus the two icon boxes. The top and bottom
79
+ * of the scale came in from matrx-frontend's `ButtonMine` fork (2026-09-07):
80
+ * a dense toolbar needs `xs`, and a marketing/hero call to action needs
81
+ * `xl`+. A host that has to reach outside this scale forks the button,
82
+ * which is exactly how `ButtonMine` was born.
83
+ */
84
+ size: {
85
+ xs: "h-6 rounded-md px-1 text-xs",
86
+ sm: "h-8 rounded-md px-3 text-xs",
87
+ default: "h-9 px-4 py-2",
88
+ /** An explicit spelling of `default` (the fork's middle rung). */
89
+ md: "h-9 px-4 py-2",
90
+ lg: "h-10 rounded-md px-6",
91
+ xl: "h-12 px-8 py-3 text-base",
92
+ "2xl": "h-14 px-10 py-3 text-base",
93
+ "3xl": "h-16 px-12 py-3 text-base",
94
+ icon: "h-9 w-9",
95
+ "icon-sm": "h-7 w-7",
96
+ /** A circular icon box — an avatar-shaped control, not a square one. */
97
+ roundIcon: "h-8 w-8 rounded-full p-0"
98
+ }
99
+ },
100
+ defaultVariants: {
101
+ variant: "default",
102
+ size: "default"
103
+ }
104
+ }
105
+ );
106
+ var Button = React.forwardRef(
107
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
108
+ const Component = asChild ? import_react_slot.Slot : "button";
109
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
110
+ Component,
111
+ {
112
+ className: cn(buttonVariants({ variant, size, className })),
113
+ ref,
114
+ ...props
115
+ }
116
+ );
117
+ }
118
+ );
119
+ Button.displayName = "Button";
120
+
121
+ // src/popover.tsx
122
+ var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
123
+ var React3 = __toESM(require("react"), 1);
124
+
125
+ // src/motion.ts
126
+ var MOTION_OVERLAY = "matrx-motion-overlay";
127
+ var MOTION_DIALOG = "matrx-motion-dialog";
128
+ var MOTION_BOTTOM_SHEET = "matrx-motion-bottom-sheet";
129
+ var MOTION_POPPER = "matrx-motion-popper";
130
+ var MOTION_SHEET = {
131
+ top: "matrx-motion-sheet-top",
132
+ bottom: "matrx-motion-sheet-bottom",
133
+ left: "matrx-motion-sheet-left",
134
+ right: "matrx-motion-sheet-right",
135
+ center: "matrx-motion-sheet-center"
136
+ };
137
+ var MOTION_PULSE = "matrx-pulse";
138
+ var MOTION_SPIN = "matrx-spin";
139
+ var ALL_MOTION_CLASSES = [
140
+ MOTION_OVERLAY,
141
+ MOTION_DIALOG,
142
+ MOTION_BOTTOM_SHEET,
143
+ MOTION_POPPER,
144
+ ...Object.values(MOTION_SHEET),
145
+ MOTION_PULSE,
146
+ MOTION_SPIN
147
+ ];
148
+
149
+ // src/portal-container.tsx
150
+ var React2 = __toESM(require("react"), 1);
151
+ var import_jsx_runtime2 = require("react/jsx-runtime");
152
+ var CONTEXT_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.portal-container-context");
153
+ var contextRegistry = globalThis;
154
+ var PortalContainerContext = contextRegistry[CONTEXT_SLOT] ??= React2.createContext(void 0);
155
+ function PortalContainerProvider({
156
+ container,
157
+ children
158
+ }) {
159
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PortalContainerContext.Provider, { value: container ?? void 0, children });
160
+ }
161
+ function usePortalContainer(explicit) {
162
+ const injected = React2.useContext(PortalContainerContext);
163
+ if (explicit !== void 0) {
164
+ return explicit ?? void 0;
165
+ }
166
+ return injected ?? void 0;
167
+ }
168
+
169
+ // src/popover.tsx
170
+ var import_jsx_runtime3 = require("react/jsx-runtime");
171
+ var Popover = PopoverPrimitive.Root;
172
+ var PopoverTrigger = PopoverPrimitive.Trigger;
173
+ var PopoverContent = React3.forwardRef(
174
+ ({
175
+ className,
176
+ align = "center",
177
+ sideOffset = 4,
178
+ container,
179
+ animated = true,
180
+ ...props
181
+ }, ref) => {
182
+ const portalContainer = usePortalContainer(container);
183
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
184
+ PopoverPrimitive.Content,
185
+ {
186
+ ref,
187
+ align,
188
+ sideOffset,
189
+ className: cn(
190
+ // Cap to the viewport space Radix measured and scroll — a popover taller
191
+ // than the screen must never trap the user with unreachable content.
192
+ // z must EQUAL the dialog layer (z-[10000]), never exceed it: with equal
193
+ // z, DOM portal order decides, so a dialog opened FROM a popover stacks
194
+ // above it, and a popover opened from a dialog still stacks above the
195
+ // dialog. z-[10001] buried dialogs behind fullscreen popovers.
196
+ "z-[10000] w-72 max-h-[var(--radix-popover-content-available-height)] overflow-y-auto overscroll-contain rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
197
+ animated && MOTION_POPPER,
198
+ className
199
+ ),
200
+ ...props
201
+ }
202
+ ) });
203
+ }
204
+ );
205
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
206
+
207
+ // src/dialog.tsx
208
+ var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
209
+ var VisuallyHidden = __toESM(require("@radix-ui/react-visually-hidden"), 1);
210
+ var import_react_tree = require("@ai-matrx/kit/react-tree");
211
+ var React6 = __toESM(require("react"), 1);
212
+
213
+ // src/icons.tsx
214
+ var import_jsx_runtime4 = require("react/jsx-runtime");
215
+ function lucideProps(props) {
216
+ return {
217
+ xmlns: "http://www.w3.org/2000/svg",
218
+ viewBox: "0 0 24 24",
219
+ fill: "none",
220
+ stroke: "currentColor",
221
+ strokeWidth: 2,
222
+ strokeLinecap: "round",
223
+ strokeLinejoin: "round",
224
+ "aria-hidden": true,
225
+ ...props
226
+ };
227
+ }
228
+ function XIcon(props) {
229
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...lucideProps(props), children: [
230
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18 6 6 18" }),
231
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m6 6 12 12" })
232
+ ] });
233
+ }
234
+
235
+ // src/radix-dialog-modal-context.tsx
236
+ var React4 = __toESM(require("react"), 1);
237
+ var import_jsx_runtime5 = require("react/jsx-runtime");
238
+ var CONTEXT_SLOT2 = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.dialog-modal-context");
239
+ var contextRegistry2 = globalThis;
240
+ var RadixDialogModalContext = contextRegistry2[CONTEXT_SLOT2] ??= React4.createContext(true);
241
+ function RadixDialogModalProvider({
242
+ children,
243
+ modal
244
+ }) {
245
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RadixDialogModalContext.Provider, { value: modal, children });
246
+ }
247
+ function useRadixDialogModal() {
248
+ return React4.useContext(RadixDialogModalContext);
249
+ }
250
+
251
+ // src/use-is-mobile.ts
252
+ var React5 = __toESM(require("react"), 1);
253
+ var MOBILE_BREAKPOINT = 768;
254
+ function useIsMobile() {
255
+ const [isMobile, setIsMobile] = React5.useState(false);
256
+ const [hasMounted, setHasMounted] = React5.useState(false);
257
+ React5.useEffect(() => {
258
+ setHasMounted(true);
259
+ const onChange = () => {
260
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
261
+ };
262
+ onChange();
263
+ if (typeof window.matchMedia !== "function") {
264
+ return void 0;
265
+ }
266
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
267
+ mql.addEventListener("change", onChange);
268
+ return () => mql.removeEventListener("change", onChange);
269
+ }, []);
270
+ if (!hasMounted) {
271
+ return false;
272
+ }
273
+ return isMobile;
274
+ }
275
+
276
+ // src/dialog.tsx
277
+ var import_jsx_runtime6 = require("react/jsx-runtime");
278
+ var Dialog = ({
279
+ children,
280
+ ...props
281
+ }) => {
282
+ const modal = props.modal ?? true;
283
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogPrimitive.Root, { ...props, modal, children }) });
284
+ };
285
+ Dialog.displayName = "Dialog";
286
+ var DialogPortal = ({
287
+ container,
288
+ ...props
289
+ }) => {
290
+ const resolved = usePortalContainer(container);
291
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogPrimitive.Portal, { container: resolved ?? null, ...props });
292
+ };
293
+ DialogPortal.displayName = "DialogPortal";
294
+ var CONTEXT_SLOT3 = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.dialog-container-context");
295
+ var contextRegistry3 = globalThis;
296
+ var DialogContainerContext = contextRegistry3[CONTEXT_SLOT3] ??= React6.createContext(null);
297
+ var DialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
298
+ DialogPrimitive.Overlay,
299
+ {
300
+ ref,
301
+ "data-slot": "dialog-overlay",
302
+ className: cn(
303
+ // Page context behind the modal stays readable; separation comes from a
304
+ // light token scrim, not a blur.
305
+ "fixed inset-0 z-[10000] bg-[var(--matrx-overlay-scrim-soft)]",
306
+ MOTION_OVERLAY,
307
+ className
308
+ ),
309
+ ...props
310
+ }
311
+ ));
312
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
313
+ var DialogContentPrimitive = React6.forwardRef((props, ref) => {
314
+ const isModal = useRadixDialogModal();
315
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
316
+ DialogPrimitive.Content,
317
+ {
318
+ ...props,
319
+ ref,
320
+ "aria-modal": isModal || void 0
321
+ }
322
+ );
323
+ });
324
+ DialogContentPrimitive.displayName = "DialogContentPrimitive";
325
+ var DIALOG_DESKTOP_CLASSES = "matrx-dialog-card fixed inset-0 z-[10000] m-auto grid h-fit min-w-0 w-full max-w-lg gap-4 max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip border bg-background p-6 shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full sm:rounded-lg";
326
+ var DIALOG_MOBILE_SHEET_CLASSES = "matrx-mobile-sheet matrx-dialog-card fixed inset-x-0 bottom-0 left-0 right-0 top-auto z-[10000] flex min-w-0 flex-col w-full max-w-full max-h-[90dvh] gap-4 [--dialog-pad:1rem] overflow-x-clip border-t bg-background p-4 pb-safe shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full rounded-t-2xl rounded-b-none overflow-y-auto overscroll-contain";
327
+ var DIALOG_MOBILE_SHEET_OVERRIDE = "inset-x-0 bottom-0 left-0 right-0 top-auto translate-none w-full max-w-full max-h-[90dvh] rounded-b-none rounded-t-2xl overflow-y-auto";
328
+ var DialogContent = React6.forwardRef(
329
+ ({
330
+ className,
331
+ children,
332
+ mobileSheet = true,
333
+ animated = true,
334
+ showCloseButton = true,
335
+ container,
336
+ ...props
337
+ }, ref) => {
338
+ const isMobile = useIsMobile();
339
+ const isModal = useRadixDialogModal();
340
+ const injectedContainer = usePortalContainer(container);
341
+ const asSheet = mobileSheet && isMobile;
342
+ const [containerEl, setContainerEl] = React6.useState(
343
+ null
344
+ );
345
+ const mergedRef = React6.useCallback(
346
+ (node) => {
347
+ setContainerEl(node);
348
+ if (typeof ref === "function") ref(node);
349
+ else if (ref)
350
+ ref.current = node;
351
+ },
352
+ [ref]
353
+ );
354
+ const hasTitle = (0, import_react_tree.treeContainsComponent)(children, DialogTitle) || (0, import_react_tree.treeContainsComponent)(children, DialogPrimitive.Title);
355
+ const hasDescription = (0, import_react_tree.treeContainsComponent)(children, DialogDescription) || (0, import_react_tree.treeContainsComponent)(children, DialogPrimitive.Description);
356
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DialogPortal, { container, children: [
357
+ isModal ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogOverlay, {}) : null,
358
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
359
+ DialogContentPrimitive,
360
+ {
361
+ ref: mergedRef,
362
+ "data-slot": "dialog-content",
363
+ className: cn(
364
+ asSheet ? DIALOG_MOBILE_SHEET_CLASSES : DIALOG_DESKTOP_CLASSES,
365
+ animated && (asSheet ? MOTION_BOTTOM_SHEET : MOTION_DIALOG),
366
+ className,
367
+ asSheet && DIALOG_MOBILE_SHEET_OVERRIDE,
368
+ // A non-modal dialog is the coexistence contract for content that
369
+ // can sit beside a host's floating window manager (which starts at
370
+ // z=1000); staying below that boundary makes a newly focused window
371
+ // usable without coupling the two systems.
372
+ !isModal && "z-[900]"
373
+ ),
374
+ ...hasDescription ? {} : { "aria-describedby": void 0 },
375
+ ...props,
376
+ children: [
377
+ hasTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VisuallyHidden.Root, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogPrimitive.Title, { children: "Dialog" }) }),
378
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
379
+ PortalContainerProvider,
380
+ {
381
+ container: containerEl ?? injectedContainer ?? null,
382
+ children
383
+ }
384
+ ) }),
385
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
386
+ DialogPrimitive.Close,
387
+ {
388
+ "data-slot": "dialog-close",
389
+ "aria-label": "Close",
390
+ className: "absolute right-2 top-4 flex h-11 w-11 items-center justify-center rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground sm:right-4 lg:h-10 lg:w-10",
391
+ children: [
392
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(XIcon, { className: "h-4 w-4" }),
393
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "sr-only", children: "Close" })
394
+ ]
395
+ }
396
+ ) : null
397
+ ]
398
+ }
399
+ )
400
+ ] });
401
+ }
402
+ );
403
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
404
+ var DialogHeader = ({
405
+ className,
406
+ ...props
407
+ }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
408
+ "div",
409
+ {
410
+ "data-slot": "dialog-header",
411
+ className: cn(
412
+ // DialogContent owns an absolute close control. Reserve its hit area in
413
+ // every header so trailing actions never render underneath it.
414
+ "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
415
+ className
416
+ ),
417
+ ...props
418
+ }
419
+ );
420
+ DialogHeader.displayName = "DialogHeader";
421
+ var DialogFooter = ({
422
+ className,
423
+ ...props
424
+ }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
425
+ "div",
426
+ {
427
+ "data-slot": "dialog-footer",
428
+ className: cn(
429
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
430
+ // Ruling 3/4 — sticky to the card edges so a scrolled body never shows
431
+ // through under the actions, and safe-area padded on a phone.
432
+ //
433
+ // 🚨 THERE IS NO `mb-[…]` HERE, AND THERE MUST NEVER BE ONE AGAIN
434
+ // (0.11.3, feedback bf8fb00b). The bleed over the card's bottom padding
435
+ // used to be a NEGATIVE BLOCK MARGIN, which makes this box taller than
436
+ // the grid area the card allocates it — and `position: sticky` CLAMPS a
437
+ // box to its containing block, so the browser yanked the footer UP by
438
+ // `--dialog-pad` against the card's `gap-4` and painted 8px of opaque
439
+ // footer over the last line of the consequence, at every length. The
440
+ // card now RESERVES this footer's block size instead (`matrx-dialog-card`
441
+ // in styles.css hands over its `padding-bottom`), so the bleed costs no
442
+ // margin at all. Guard: `sticky-footer-geometry.test.tsx`.
443
+ //
444
+ // These stay UTILITIES rather than a shipped rule so a caller's
445
+ // `className` still wins through tailwind-merge — a shipped rule would
446
+ // have to be unlayered to survive Tailwind preflight (§ THE PREFLIGHT
447
+ // RULE in styles.css) and would then override every caller's padding.
448
+ "sticky bottom-0 z-10 bg-background pt-3",
449
+ "mx-[calc(var(--dialog-pad,0px)*-1)] px-[var(--dialog-pad,0px)] pb-[var(--dialog-pad,0px)]",
450
+ className
451
+ ),
452
+ ...props
453
+ }
454
+ );
455
+ DialogFooter.displayName = "DialogFooter";
456
+ var DialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
457
+ DialogPrimitive.Title,
458
+ {
459
+ ref,
460
+ "data-slot": "dialog-title",
461
+ className: cn("text-lg font-semibold leading-none tracking-tight", className),
462
+ ...props
463
+ }
464
+ ));
465
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
466
+ var DialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
467
+ DialogPrimitive.Description,
468
+ {
469
+ ref,
470
+ "data-slot": "dialog-description",
471
+ className: cn("text-sm text-muted-foreground", className),
472
+ ...props
473
+ }
474
+ ));
475
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
476
+
477
+ // src/data-table/icons.tsx
478
+ var import_jsx_runtime7 = require("react/jsx-runtime");
479
+ function Icon({ children, ...props }) {
480
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", ...props, children });
481
+ }
482
+ var Check = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m5 12 4 4L19 6" }) });
483
+ var SlidersHorizontal = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 7h16M4 17h16M9 7v0M15 17v0" }) });
484
+ var PanelRight = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Icon, { ...p, children: [
485
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }),
486
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M15 4v16" })
487
+ ] });
488
+ var ExternalLink = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M14 4h6v6M20 4l-9 9M19 13v6H5V5h6" }) });
489
+ var Copy = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Icon, { ...p, children: [
490
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
491
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3" })
492
+ ] });
493
+ var Lightbulb = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M9 18h6M10 22h4M8 14a6 6 0 1 1 8 0c-1 1-1 2-1 3H9c0-1 0-2-1-3z" }) });
494
+ var ShieldOff = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m3 3 18 18M12 3l7 3v5c0 4-3 7-7 9-4-2-7-5-7-9V6l4-2" }) });
495
+
496
+ // src/data-table/host.tsx
497
+ var import_react = require("react");
498
+ var import_jsx_runtime8 = require("react/jsx-runtime");
499
+ var HOST_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.table-host-context");
500
+ var hostRegistry = globalThis;
501
+ var HostContext = hostRegistry[HOST_SLOT] ??= (0, import_react.createContext)({});
502
+ function useMatrxDataTableHost() {
503
+ return (0, import_react.useContext)(HostContext);
504
+ }
505
+
506
+ // src/data-table/useTableNotice.tsx
507
+ var import_react2 = require("react");
508
+ var import_jsx_runtime9 = require("react/jsx-runtime");
509
+ function useTableNotice() {
510
+ const host = useMatrxDataTableHost();
511
+ const [message, setMessage] = (0, import_react2.useState)(null);
512
+ const notify = {
513
+ success(text) {
514
+ if (host.notify) host.notify.success(text);
515
+ else setMessage({ text, error: false });
516
+ },
517
+ error(text) {
518
+ if (host.notify) host.notify.error(text);
519
+ else setMessage({ text, error: true });
520
+ }
521
+ };
522
+ const notice = message ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { role: message.error ? "alert" : "status", className: message.error ? "text-xs text-destructive" : "text-xs text-muted-foreground", children: [
523
+ message.text,
524
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-label": "Dismiss notification", className: "ml-2 underline", onClick: () => setMessage(null), children: "Dismiss" })
525
+ ] }) : null;
526
+ return { notify, notice };
527
+ }
528
+
529
+ // src/data-table/copy-payload.ts
530
+ function tableAgentText(value) {
531
+ if (typeof value === "string") return value;
532
+ const attributes = Object.entries(value.attributes ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => ` ${key}="${String(entry)}"`).join("");
533
+ const context = Object.entries(value.context ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => `<${key}>${String(entry)}</${key}>`).join("\n");
534
+ const url = typeof window === "undefined" ? "" : window.location.href;
535
+ const route = typeof window === "undefined" ? "" : window.location.pathname;
536
+ return `<${value.kind}${attributes}>
537
+ <context>
538
+ <location>${value.location}</location>
539
+ ${url ? `<url>${url}</url>` : ""}
540
+ ${route ? `<route>${route}</route>` : ""}
541
+ <copied>${value.description}</copied>
542
+ <copied-at>${(/* @__PURE__ */ new Date()).toISOString()}</copied-at>
543
+ ${context}
544
+ </context>
545
+ ${value.summary ? `<summary>
546
+ ${value.summary}
547
+ </summary>
548
+ ` : ""}<data format="json">
549
+ \`\`\`json
550
+ ${JSON.stringify(value.data, null, 2)}
551
+ \`\`\`
552
+ </data>
553
+ </${value.kind}>`;
554
+ }
555
+
556
+ // src/data-table/copy.tsx
557
+ var import_jsx_runtime10 = require("react/jsx-runtime");
558
+ function resolve(value) {
559
+ return typeof value === "function" ? value() : value;
560
+ }
561
+ function download(item) {
562
+ if (!item.build) throw new Error(`No export action is available for ${item.label}.`);
563
+ const file = item.build();
564
+ const url = URL.createObjectURL(new Blob([file.content], { type: file.mime }));
565
+ try {
566
+ const link = document.createElement("a");
567
+ link.href = url;
568
+ link.download = `${item.label.replace(/[^a-z0-9]+/gi, "-")}.${file.extension}`;
569
+ document.body.append(link);
570
+ link.click();
571
+ link.remove();
572
+ } finally {
573
+ URL.revokeObjectURL(url);
574
+ }
575
+ }
576
+ function CopyButtons(props) {
577
+ const { CopyControls } = useMatrxDataTableHost();
578
+ if (CopyControls) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CopyControls, { ...props });
579
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DefaultCopyButtons, { ...props });
580
+ }
581
+ function DefaultCopyButtons({ human, agent, json, label, size = "icon", appearance = "segmented", disabled = false, stopPropagation = true, className, aiVariants = [], agentVariant, aiCustom, export: exportConfig, hide }) {
582
+ const { notify, notice } = useTableNotice();
583
+ const clipboard = (0, import_clipboard.useClipboard)({ notify: (message, kind) => notify[kind](message) });
584
+ const [busy, setBusy] = (0, import_react3.useState)(false);
585
+ const [modal, setModal] = (0, import_react3.useState)(null);
586
+ const run = async (operation) => {
587
+ if (busy) return;
588
+ setBusy(true);
589
+ try {
590
+ await operation();
591
+ } catch (error) {
592
+ notify.error(error instanceof Error ? error.message : String(error));
593
+ } finally {
594
+ setBusy(false);
595
+ }
596
+ };
597
+ const faithfulAgent = agent === void 0 ? [] : [{
598
+ id: agentVariant?.id ?? "copy-for-ai",
599
+ label: agentVariant?.label ?? "Copy for AI",
600
+ ...agentVariant?.hint === void 0 ? {} : { hint: agentVariant.hint },
601
+ section: "ai",
602
+ build: () => resolve(agent)
603
+ }];
604
+ const orderedAgent = agentVariant?.position === "last" ? [...aiVariants, ...faithfulAgent] : [...faithfulAgent, ...aiVariants];
605
+ const variants = [
606
+ ...json === void 0 ? [] : [{ id: "json", label: "Copy JSON", section: "copy", build: () => JSON.stringify(resolve(json), null, 2) }],
607
+ ...orderedAgent
608
+ ].filter((variant) => !hide?.includes(variant.section ?? "ai"));
609
+ const exports = hide?.includes("export") ? void 0 : exportConfig;
610
+ const showCustom = aiCustom && !hide?.includes("ai");
611
+ const buttonClass = `${size === "xs" ? "h-8 w-8 lg:h-5 lg:w-8" : ""} ${appearance === "bare" ? "border-0 bg-transparent shadow-none" : ""}`;
612
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: `inline-flex flex-wrap items-center gap-0.5 ${className ?? ""}`, onClick: stopPropagation ? (event) => event.stopPropagation() : void 0, children: [
613
+ human !== void 0 && !hide?.includes("copy") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "icon", className: buttonClass, disabled: disabled || busy, "aria-label": `Copy ${label}`, onClick: () => void run(() => clipboard.copyText(resolve(human), `${label} copied`)), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Copy, { className: "h-3.5 w-3.5" }) }) : null,
614
+ variants.length > 0 || showCustom || exports ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Popover, { children: [
615
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "icon", className: buttonClass, disabled: disabled || busy, "aria-label": `Copy ${label} for AI or export`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SlidersHorizontal, { className: "h-3.5 w-3.5" }) }) }),
616
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(PopoverContent, { align: "end", className: "w-64 p-1", children: [
617
+ variants.map((variant) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", disabled: busy, onClick: () => void run(async () => {
618
+ if (variant.onSelect) variant.onSelect();
619
+ else if (variant.modal) setModal(variant.id);
620
+ else if (variant.build) await clipboard.copyText(tableAgentText(await variant.build()), variant.successMessage ?? `${label} copied`);
621
+ else throw new Error(`No copy action is available for ${variant.label}.`);
622
+ }), children: variant.label }, variant.id)),
623
+ showCustom ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", onClick: () => setModal("custom"), children: aiCustom.label ?? "Custom copy\u2026" }) : null,
624
+ exports?.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", disabled: busy, onClick: () => void run(async () => {
625
+ if (item.onSelect) await item.onSelect();
626
+ else download(item);
627
+ }), children: item.label }, item.id)),
628
+ exports?.sheetRows ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", onClick: () => void run(async () => {
629
+ const rows = exports.sheetRows?.();
630
+ if (!rows) return;
631
+ const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
632
+ const value = (input) => String(input ?? "").replace(/[\t\r\n]+/g, " ");
633
+ await clipboard.copyText([keys.map(value).join(" "), ...rows.map((row) => keys.map((key) => value(row[key])).join(" "))].join("\n"), "Copied for pasting into Google Sheets");
634
+ }), children: "Copy for Google Sheets" }) : null
635
+ ] })
636
+ ] }) : null,
637
+ variants.map((variant) => variant.modal && modal === variant.id ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: variant.modal({ open: true, onOpenChange: (open) => setModal(open ? variant.id : null) }) }, variant.id) : null),
638
+ modal === "custom" && aiCustom ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CustomCopy, { source: aiCustom, onClose: () => setModal(null) }) : null,
639
+ notice
640
+ ] });
641
+ }
642
+ function CustomCopy({ source, onClose }) {
643
+ const [values, setValues] = (0, import_react3.useState)(() => Object.fromEntries(source.options.map((option) => [option.key, option.default])));
644
+ const { notify, notice } = useTableNotice();
645
+ const clipboard = (0, import_clipboard.useClipboard)({ notify: (message, kind) => notify[kind](message) });
646
+ let text = "";
647
+ let error = null;
648
+ try {
649
+ const built = source.build(values);
650
+ text = tableAgentText(source.wrap(built.text, values, built.meta));
651
+ } catch (raw) {
652
+ error = raw instanceof Error ? raw.message : String(raw);
653
+ }
654
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Dialog, { open: true, onOpenChange: (open) => {
655
+ if (!open) onClose();
656
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogContent, { children: [
657
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DialogTitle, { children: source.dialogTitle ?? "Custom copy" }) }),
658
+ source.dialogDescription ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm", children: source.dialogDescription }) : null,
659
+ source.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center justify-between gap-3 text-sm", children: [
660
+ option.label,
661
+ option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "checkbox", checked: values[option.key] === true, onChange: (e) => setValues({ ...values, [option.key]: e.target.checked }) }) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("select", { "aria-label": option.label, value: Number(values[option.key]), onChange: (e) => setValues({ ...values, [option.key]: Number(e.target.value) }), children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: choice.value, children: choice.label }, choice.value)) }) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { "aria-label": option.label, type: "range", min: 0, max: option.stops.length - 1, step: 1, value: Math.max(0, option.stops.indexOf(Number(values[option.key]))), onChange: (e) => setValues({ ...values, [option.key]: option.stops[Number(e.target.value)] ?? option.default }) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex gap-1", children: [
662
+ option.presets?.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", size: "sm", variant: "outline", onClick: () => setValues({ ...values, [option.key]: choice.value }), children: choice.label }, choice.value)),
663
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { "aria-label": option.label, type: "number", value: Number(values[option.key]), min: option.min, step: option.step, onChange: (e) => {
664
+ if (Number.isFinite(e.target.valueAsNumber)) setValues({ ...values, [option.key]: e.target.valueAsNumber });
665
+ } })
666
+ ] })
667
+ ] }, option.key)),
668
+ error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "alert", className: "text-destructive", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap text-xs", children: text }),
669
+ notice,
670
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogFooter, { children: [
671
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: onClose, children: "Close" }),
672
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", disabled: error !== null, onClick: () => void clipboard.copyText(text, "Custom copy copied"), children: "Copy" })
673
+ ] })
674
+ ] }) });
675
+ }
676
+
677
+ // src/data-table/MatrxUuidCell.tsx
678
+ var import_react4 = require("react");
679
+
680
+ // src/tooltip.tsx
681
+ var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
682
+ var React7 = __toESM(require("react"), 1);
683
+ var import_jsx_runtime11 = require("react/jsx-runtime");
684
+ var TooltipProvider = TooltipPrimitive.Provider;
685
+ var Tooltip = TooltipPrimitive.Root;
686
+ var TooltipTrigger = TooltipPrimitive.Trigger;
687
+ var TooltipContent = React7.forwardRef(({ className, sideOffset = 4, container, animated = true, ...props }, ref) => {
688
+ const resolved = usePortalContainer(container);
689
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TooltipPrimitive.Portal, { container: resolved ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
690
+ TooltipPrimitive.Content,
691
+ {
692
+ ref,
693
+ "data-slot": "tooltip-content",
694
+ sideOffset,
695
+ className: cn(
696
+ "z-[10001] overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md",
697
+ animated && MOTION_POPPER,
698
+ className
699
+ ),
700
+ ...props
701
+ }
702
+ ) });
703
+ });
704
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
705
+
706
+ // src/data-table/MatrxUuidCell.tsx
707
+ var import_jsx_runtime12 = require("react/jsx-runtime");
708
+ var SHORT_LEN = 8;
709
+ function shortUuid(id, len = SHORT_LEN) {
710
+ return id.slice(0, len);
711
+ }
712
+ async function copyText(text) {
713
+ try {
714
+ if (navigator.clipboard?.writeText) {
715
+ await navigator.clipboard.writeText(text);
716
+ return true;
717
+ }
718
+ } catch {
719
+ }
720
+ try {
721
+ const ta = document.createElement("textarea");
722
+ ta.value = text;
723
+ ta.style.position = "fixed";
724
+ ta.style.opacity = "0";
725
+ document.body.appendChild(ta);
726
+ ta.select();
727
+ const ok = document.execCommand("copy");
728
+ document.body.removeChild(ta);
729
+ return ok;
730
+ } catch {
731
+ return false;
732
+ }
733
+ }
734
+ function MatrxUuidCell({
735
+ value,
736
+ label,
737
+ onOpen,
738
+ href,
739
+ token,
740
+ forbidden = false,
741
+ className,
742
+ trailing
743
+ }) {
744
+ const { resolveEntityDoors, ResourcePeek } = useMatrxDataTableHost();
745
+ const { notify, notice } = useTableNotice();
746
+ const [copied, setCopied] = (0, import_react4.useState)(false);
747
+ const [opening, setOpening] = (0, import_react4.useState)(false);
748
+ const [peekOpen, setPeekOpen] = (0, import_react4.useState)(false);
749
+ const timer = (0, import_react4.useRef)(null);
750
+ (0, import_react4.useEffect)(
751
+ () => () => {
752
+ if (timer.current) clearTimeout(timer.current);
753
+ },
754
+ []
755
+ );
756
+ if (!value) {
757
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-muted-foreground/40", children: "\u2014" });
758
+ }
759
+ const doors = token ? resolveEntityDoors?.(token, value, href) ?? null : null;
760
+ const resolvedHref = doors?.href ?? href ?? null;
761
+ const canPeek = Boolean(doors?.canPeek) && !forbidden;
762
+ const display = shortUuid(value);
763
+ const tip = label ? `${label}: ${value}` : value;
764
+ const stop = (e) => {
765
+ e.stopPropagation();
766
+ };
767
+ const onCopy = (e) => {
768
+ stop(e);
769
+ e.preventDefault();
770
+ void copyText(value).then((ok) => {
771
+ if (!ok) {
772
+ notify?.error("Couldn't copy ID");
773
+ return;
774
+ }
775
+ setCopied(true);
776
+ if (timer.current) clearTimeout(timer.current);
777
+ timer.current = setTimeout(() => setCopied(false), 1500);
778
+ });
779
+ };
780
+ const handleOpen = async (e) => {
781
+ stop(e);
782
+ e.preventDefault();
783
+ if (!onOpen || forbidden || opening) return;
784
+ setOpening(true);
785
+ try {
786
+ const result = await onOpen(value);
787
+ if (result === "forbidden") {
788
+ notify?.error("You don't have access to open this record");
789
+ }
790
+ } catch (err) {
791
+ notify?.error(
792
+ `Couldn't open: ${err instanceof Error ? err.message : String(err)}`
793
+ );
794
+ } finally {
795
+ setOpening(false);
796
+ }
797
+ };
798
+ const idNode = (() => {
799
+ if (forbidden) {
800
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-muted-foreground/70 tabular-nums", children: [
801
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate", children: display }),
802
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShieldOff, { className: "h-3 w-3 shrink-0 opacity-60", "aria-hidden": true })
803
+ ] });
804
+ }
805
+ if (onOpen) {
806
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
807
+ "button",
808
+ {
809
+ type: "button",
810
+ "aria-label": `Open ${label ?? "record"} ${display}`,
811
+ onClick: (e) => void handleOpen(e),
812
+ disabled: opening,
813
+ className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-sky-600 hover:underline dark:text-sky-400 disabled:opacity-60",
814
+ children: [
815
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
816
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PanelRight, { className: "h-3 w-3 shrink-0 opacity-50" })
817
+ ]
818
+ }
819
+ );
820
+ }
821
+ if (resolvedHref) {
822
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
823
+ "a",
824
+ {
825
+ href: resolvedHref,
826
+ target: "_blank",
827
+ rel: "noopener noreferrer",
828
+ "aria-label": `Open ${label ?? "record"} ${display} in a new tab`,
829
+ onClick: stop,
830
+ className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-sky-600 hover:underline dark:text-sky-400",
831
+ children: [
832
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
833
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ExternalLink, { className: "h-3 w-3 shrink-0 opacity-50" })
834
+ ]
835
+ }
836
+ );
837
+ }
838
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate font-mono text-xs text-muted-foreground tabular-nums select-all", children: display });
839
+ })();
840
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
841
+ "span",
842
+ {
843
+ "data-matrx-cell-control": true,
844
+ className: cn(
845
+ "inline-flex min-w-0 max-w-full items-center gap-0.5 whitespace-nowrap",
846
+ className
847
+ ),
848
+ onClick: stop,
849
+ children: [
850
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Tooltip, { children: [
851
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "inline-flex min-w-0 max-w-full items-center", children: idNode }) }),
852
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipContent, { side: "top", className: "max-w-sm break-all font-mono", children: forbidden ? `No access \xB7 ${tip}` : tip })
853
+ ] }) }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
855
+ "button",
856
+ {
857
+ type: "button",
858
+ onClick: onCopy,
859
+ "aria-label": copied ? "Copied" : `Copy ${label ?? "id"}`,
860
+ title: `Copy ${label ?? "id"}: ${value}`,
861
+ className: cn(
862
+ "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus:outline-none",
863
+ copied && "text-primary"
864
+ ),
865
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Copy, { className: "h-3 w-3" })
866
+ }
867
+ ),
868
+ canPeek ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
869
+ "button",
870
+ {
871
+ type: "button",
872
+ onClick: (e) => {
873
+ stop(e);
874
+ setPeekOpen(true);
875
+ },
876
+ "aria-label": `Quick look at ${label ?? "record"}`,
877
+ title: `Quick look at ${label ?? "record"}`,
878
+ className: "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus:outline-none",
879
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Lightbulb, { className: "h-3 w-3" })
880
+ }
881
+ ) : null,
882
+ onOpen && resolvedHref && !forbidden ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
883
+ "a",
884
+ {
885
+ href: resolvedHref,
886
+ target: "_blank",
887
+ rel: "noopener noreferrer",
888
+ onClick: stop,
889
+ "aria-label": `Open ${label ?? "record"} in a new tab`,
890
+ title: `Open ${label ?? "record"} in a new tab`,
891
+ className: "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus:outline-none",
892
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ExternalLink, { className: "h-3 w-3" })
893
+ }
894
+ ) : null,
895
+ trailing,
896
+ notice,
897
+ canPeek && peekOpen && ResourcePeek ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
898
+ ResourcePeek,
899
+ {
900
+ kind: doors?.peekKind ?? token ?? "record",
901
+ id: value,
902
+ onClose: () => setPeekOpen(false),
903
+ ...href == null ? {} : { href }
904
+ }
905
+ ) : null
906
+ ]
907
+ }
908
+ );
909
+ }
910
+
911
+ // src/data-table/entity.ts
912
+ function isUuidValue(value) {
913
+ return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
914
+ }
915
+
916
+ // src/data-table/DataRowInspector.tsx
917
+ var import_jsx_runtime13 = require("react/jsx-runtime");
918
+ var noFieldToken = () => null;
919
+ function formatValue(value) {
920
+ if (value == null) return "\u2014";
921
+ if (typeof value === "string") return value || "\u2014";
922
+ if (typeof value === "number" || typeof value === "boolean") {
923
+ return String(value);
924
+ }
925
+ if (value instanceof Date) return value.toISOString();
926
+ try {
927
+ return JSON.stringify(value, null, 2);
928
+ } catch {
929
+ return String(value);
930
+ }
931
+ }
932
+ function isPlainObject(value) {
933
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
934
+ }
935
+ function DataRowInspector({
936
+ row,
937
+ title,
938
+ className,
939
+ fieldCopy = true,
940
+ recordKind = "record",
941
+ recordLabel,
942
+ location,
943
+ tokenForField = noFieldToken
944
+ }) {
945
+ const entries = isPlainObject(row) ? Object.entries(row) : [["value", row]];
946
+ const fieldButtons = (key, value) => fieldCopy ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute right-1 top-1 opacity-0 transition-opacity focus-within:opacity-100 group-hover/field:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
947
+ CopyButtons,
948
+ {
949
+ size: "xs",
950
+ label: recordLabel ? `${recordLabel} \xB7 ${key}` : key,
951
+ human: () => formatValue(value),
952
+ agent: () => ({
953
+ kind: `${recordKind}-field`,
954
+ location: location ?? "Data row inspector",
955
+ description: `The "${key}" field of one ${recordLabel ?? recordKind}.`,
956
+ data: { field: key, value, record: row },
957
+ attributes: { field: key }
958
+ })
959
+ }
960
+ ) }) : null;
961
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
962
+ "div",
963
+ {
964
+ className: cn("flex h-full min-h-0 flex-col overflow-hidden", className),
965
+ children: [
966
+ title ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "shrink-0 border-b border-border px-3 py-2 text-sm font-medium", children: title }) : null,
967
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-h-0 flex-1 overflow-auto p-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { className: "space-y-2", children: entries.map(([key, value]) => {
968
+ if (isUuidValue(value)) {
969
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
970
+ "div",
971
+ {
972
+ className: "group/field relative grid grid-cols-[minmax(7rem,9rem)_1fr] gap-2 rounded-md border border-border/60 bg-muted/20 px-2.5 py-2",
973
+ children: [
974
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
975
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { className: "min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
976
+ MatrxUuidCell,
977
+ {
978
+ value,
979
+ label: key,
980
+ token: tokenForField(key, row)
981
+ }
982
+ ) })
983
+ ]
984
+ },
985
+ key
986
+ );
987
+ }
988
+ const formatted = formatValue(value);
989
+ const multiline = formatted.includes("\n") || formatted.length > 80;
990
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
991
+ "div",
992
+ {
993
+ className: "group/field relative grid grid-cols-[minmax(7rem,9rem)_1fr] gap-2 rounded-md border border-border/60 bg-muted/20 py-2 pl-2.5 pr-12",
994
+ children: [
995
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
996
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
997
+ "dd",
998
+ {
999
+ className: cn(
1000
+ "min-w-0 text-sm text-foreground break-words",
1001
+ multiline && "whitespace-pre-wrap font-mono text-xs leading-relaxed"
1002
+ ),
1003
+ children: formatted
1004
+ }
1005
+ ),
1006
+ fieldButtons(key, value)
1007
+ ]
1008
+ },
1009
+ key
1010
+ );
1011
+ }) }) })
1012
+ ]
1013
+ }
1014
+ );
1015
+ }
1016
+ //# sourceMappingURL=data-row-inspector.cjs.map