@ai-matrx/design-system 0.37.1 → 0.38.0

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