@ai-matrx/design-system 0.37.1 → 0.38.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.
@@ -126,12 +126,14 @@ function useIsMobile() {
126
126
 
127
127
  // src/dialog.tsx
128
128
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
129
+ var DialogWindowedByDefaultContext = React4.createContext(false);
129
130
  var Dialog = ({
130
131
  children,
131
132
  ...props
132
133
  }) => {
133
- const modal = props.modal ?? true;
134
- return /* @__PURE__ */ jsx4(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ jsx4(DialogPrimitive.Root, { ...props, modal, children }) });
134
+ const isMobile = useIsMobile();
135
+ const modal = props.modal ?? isMobile;
136
+ return /* @__PURE__ */ jsx4(DialogWindowedByDefaultContext.Provider, { value: props.modal === void 0, children: /* @__PURE__ */ jsx4(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ jsx4(DialogPrimitive.Root, { ...props, modal, children }) }) });
135
137
  };
136
138
  Dialog.displayName = "Dialog";
137
139
  var DialogPortal = ({
@@ -176,6 +178,11 @@ DialogContentPrimitive.displayName = "DialogContentPrimitive";
176
178
  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";
177
179
  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";
178
180
  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";
181
+ var DialogWindowHandleContext = React4.createContext(null);
182
+ var WINDOW_KEEP_VISIBLE = 80;
183
+ function isInteractiveTarget(target) {
184
+ return target instanceof Element && Boolean(target.closest("button, a, input, textarea, select, [role='button'], [contenteditable='true']"));
185
+ }
179
186
  var DialogContent = React4.forwardRef(
180
187
  ({
181
188
  className,
@@ -184,15 +191,51 @@ var DialogContent = React4.forwardRef(
184
191
  animated = true,
185
192
  showCloseButton = true,
186
193
  container,
194
+ dismissOnOutsideClick = false,
195
+ onInteractOutside,
196
+ onEscapeKeyDown,
197
+ style,
187
198
  ...props
188
199
  }, ref) => {
189
200
  const isMobile = useIsMobile();
190
201
  const isModal = useRadixDialogModal();
191
202
  const injectedContainer = usePortalContainer(container);
192
203
  const asSheet = mobileSheet && isMobile;
204
+ const windowed = !isModal && !asSheet;
205
+ const windowedByDefault = React4.useContext(DialogWindowedByDefaultContext);
193
206
  const [containerEl, setContainerEl] = React4.useState(
194
207
  null
195
208
  );
209
+ const [offset, setOffset] = React4.useState({ x: 0, y: 0 });
210
+ const dragRef = React4.useRef(null);
211
+ const handle = React4.useMemo(() => {
212
+ if (!windowed) return null;
213
+ const clamp = (value, limit) => Math.max(-limit, Math.min(limit, value));
214
+ return {
215
+ onPointerDown: (event) => {
216
+ if (event.button !== 0 || isInteractiveTarget(event.target)) return;
217
+ dragRef.current = { x: event.clientX, y: event.clientY, baseX: offset.x, baseY: offset.y };
218
+ event.currentTarget.setPointerCapture?.(event.pointerId);
219
+ },
220
+ onPointerMove: (event) => {
221
+ const start = dragRef.current;
222
+ if (!start) return;
223
+ setOffset({
224
+ x: clamp(start.baseX + event.clientX - start.x, window.innerWidth / 2 - WINDOW_KEEP_VISIBLE / 2),
225
+ y: clamp(start.baseY + event.clientY - start.y, window.innerHeight / 2 - WINDOW_KEEP_VISIBLE / 2)
226
+ });
227
+ },
228
+ onPointerUp: (event) => {
229
+ if (!dragRef.current) return;
230
+ dragRef.current = null;
231
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
232
+ },
233
+ onPointerCancel: () => {
234
+ dragRef.current = null;
235
+ },
236
+ onDoubleClick: () => setOffset({ x: 0, y: 0 })
237
+ };
238
+ }, [windowed, offset.x, offset.y]);
196
239
  const mergedRef = React4.useCallback(
197
240
  (node) => {
198
241
  setContainerEl(node);
@@ -220,19 +263,33 @@ var DialogContent = React4.forwardRef(
220
263
  // can sit beside a host's floating window manager (which starts at
221
264
  // z=1000); staying below that boundary makes a newly focused window
222
265
  // usable without coupling the two systems.
223
- !isModal && "z-[900]"
266
+ !isModal && !windowedByDefault && "z-[900]",
267
+ // Without an overlay the card needs its own separation from the page.
268
+ windowed && "shadow-2xl ring-1 ring-border/60"
224
269
  ),
270
+ style: windowed && (offset.x !== 0 || offset.y !== 0) ? { ...style, translate: `${offset.x}px ${offset.y}px` } : style,
271
+ onInteractOutside: (event) => {
272
+ onInteractOutside?.(event);
273
+ if (windowed && !dismissOnOutsideClick) event.preventDefault();
274
+ },
275
+ onEscapeKeyDown: (event) => {
276
+ onEscapeKeyDown?.(event);
277
+ const pressedIn = event.target instanceof Node && event.target !== document.body ? event.target : document.activeElement;
278
+ if (windowed && containerEl && !(pressedIn && containerEl.contains(pressedIn))) {
279
+ event.preventDefault();
280
+ }
281
+ },
225
282
  ...hasDescription ? {} : { "aria-describedby": void 0 },
226
283
  ...props,
227
284
  children: [
228
285
  hasTitle ? null : /* @__PURE__ */ jsx4(VisuallyHidden.Root, { children: /* @__PURE__ */ jsx4(DialogPrimitive.Title, { children: "Dialog" }) }),
229
- /* @__PURE__ */ jsx4(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ jsx4(
286
+ /* @__PURE__ */ jsx4(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ jsx4(DialogWindowHandleContext.Provider, { value: handle, children: /* @__PURE__ */ jsx4(
230
287
  PortalContainerProvider,
231
288
  {
232
289
  container: containerEl ?? injectedContainer ?? null,
233
290
  children
234
291
  }
235
- ) }),
292
+ ) }) }),
236
293
  showCloseButton ? /* @__PURE__ */ jsxs2(
237
294
  DialogPrimitive.Close,
238
295
  {
@@ -255,19 +312,28 @@ DialogContent.displayName = DialogPrimitive.Content.displayName;
255
312
  var DialogHeader = ({
256
313
  className,
257
314
  ...props
258
- }) => /* @__PURE__ */ jsx4(
259
- "div",
260
- {
261
- "data-slot": "dialog-header",
262
- className: cn(
263
- // DialogContent owns an absolute close control. Reserve its hit area in
264
- // every header so trailing actions never render underneath it.
265
- "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
266
- className
267
- ),
268
- ...props
269
- }
270
- );
315
+ }) => {
316
+ const handle = React4.useContext(DialogWindowHandleContext);
317
+ return /* @__PURE__ */ jsx4(
318
+ "div",
319
+ {
320
+ "data-slot": "dialog-header",
321
+ ...handle ? {
322
+ ...handle,
323
+ "data-window-handle": "",
324
+ title: "Drag to move \xB7 double-click to recenter"
325
+ } : {},
326
+ className: cn(
327
+ // DialogContent owns an absolute close control. Reserve its hit area in
328
+ // every header so trailing actions never render underneath it.
329
+ "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
330
+ handle && "cursor-grab select-none active:cursor-grabbing",
331
+ className
332
+ ),
333
+ ...props
334
+ }
335
+ );
336
+ };
271
337
  DialogHeader.displayName = "DialogHeader";
272
338
  var DialogFooter = ({
273
339
  className,
@@ -3034,7 +3100,7 @@ function CopyButtons(props) {
3034
3100
  // src/data-table/MatrxUuidCell.tsx
3035
3101
  import {
3036
3102
  useEffect as useEffect4,
3037
- useRef as useRef4,
3103
+ useRef as useRef5,
3038
3104
  useState as useState7
3039
3105
  } from "react";
3040
3106
 
@@ -3104,7 +3170,7 @@ function MatrxUuidCell({
3104
3170
  const [copied, setCopied] = useState7(false);
3105
3171
  const [opening, setOpening] = useState7(false);
3106
3172
  const [peekOpen, setPeekOpen] = useState7(false);
3107
- const timer = useRef4(null);
3173
+ const timer = useRef5(null);
3108
3174
  useEffect4(
3109
3175
  () => () => {
3110
3176
  if (timer.current) clearTimeout(timer.current);