@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.
@@ -1617,7 +1617,8 @@ var Dialog = ({
1617
1617
  children,
1618
1618
  ...props
1619
1619
  }) => {
1620
- const modal = props.modal ?? true;
1620
+ const isMobile = useIsMobile();
1621
+ const modal = props.modal ?? isMobile;
1621
1622
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DialogPrimitive.Root, { ...props, modal, children }) });
1622
1623
  };
1623
1624
  Dialog.displayName = "Dialog";
@@ -1663,6 +1664,11 @@ DialogContentPrimitive.displayName = "DialogContentPrimitive";
1663
1664
  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";
1664
1665
  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";
1665
1666
  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";
1667
+ var DialogWindowHandleContext = React10.createContext(null);
1668
+ var WINDOW_KEEP_VISIBLE = 80;
1669
+ function isInteractiveTarget(target) {
1670
+ return target instanceof Element && Boolean(target.closest("button, a, input, textarea, select, [role='button'], [contenteditable='true']"));
1671
+ }
1666
1672
  var DialogContent = React10.forwardRef(
1667
1673
  ({
1668
1674
  className,
@@ -1671,15 +1677,50 @@ var DialogContent = React10.forwardRef(
1671
1677
  animated = true,
1672
1678
  showCloseButton = true,
1673
1679
  container,
1680
+ dismissOnOutsideClick = false,
1681
+ onInteractOutside,
1682
+ onEscapeKeyDown,
1683
+ style,
1674
1684
  ...props
1675
1685
  }, ref) => {
1676
1686
  const isMobile = useIsMobile();
1677
1687
  const isModal = useRadixDialogModal();
1678
1688
  const injectedContainer = usePortalContainer(container);
1679
1689
  const asSheet = mobileSheet && isMobile;
1690
+ const windowed = !isModal && !asSheet;
1680
1691
  const [containerEl, setContainerEl] = React10.useState(
1681
1692
  null
1682
1693
  );
1694
+ const [offset, setOffset] = React10.useState({ x: 0, y: 0 });
1695
+ const dragRef = React10.useRef(null);
1696
+ const handle = React10.useMemo(() => {
1697
+ if (!windowed) return null;
1698
+ const clamp = (value, limit) => Math.max(-limit, Math.min(limit, value));
1699
+ return {
1700
+ onPointerDown: (event) => {
1701
+ if (event.button !== 0 || isInteractiveTarget(event.target)) return;
1702
+ dragRef.current = { x: event.clientX, y: event.clientY, baseX: offset.x, baseY: offset.y };
1703
+ event.currentTarget.setPointerCapture?.(event.pointerId);
1704
+ },
1705
+ onPointerMove: (event) => {
1706
+ const start = dragRef.current;
1707
+ if (!start) return;
1708
+ setOffset({
1709
+ x: clamp(start.baseX + event.clientX - start.x, window.innerWidth / 2 - WINDOW_KEEP_VISIBLE / 2),
1710
+ y: clamp(start.baseY + event.clientY - start.y, window.innerHeight / 2 - WINDOW_KEEP_VISIBLE / 2)
1711
+ });
1712
+ },
1713
+ onPointerUp: (event) => {
1714
+ if (!dragRef.current) return;
1715
+ dragRef.current = null;
1716
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
1717
+ },
1718
+ onPointerCancel: () => {
1719
+ dragRef.current = null;
1720
+ },
1721
+ onDoubleClick: () => setOffset({ x: 0, y: 0 })
1722
+ };
1723
+ }, [windowed, offset.x, offset.y]);
1683
1724
  const mergedRef = React10.useCallback(
1684
1725
  (node) => {
1685
1726
  setContainerEl(node);
@@ -1707,19 +1748,33 @@ var DialogContent = React10.forwardRef(
1707
1748
  // can sit beside a host's floating window manager (which starts at
1708
1749
  // z=1000); staying below that boundary makes a newly focused window
1709
1750
  // usable without coupling the two systems.
1710
- !isModal && "z-[900]"
1751
+ !isModal && "z-[900]",
1752
+ // Without an overlay the card needs its own separation from the page.
1753
+ windowed && "shadow-2xl ring-1 ring-border/60"
1711
1754
  ),
1755
+ style: windowed && (offset.x !== 0 || offset.y !== 0) ? { ...style, translate: `${offset.x}px ${offset.y}px` } : style,
1756
+ onInteractOutside: (event) => {
1757
+ onInteractOutside?.(event);
1758
+ if (windowed && !dismissOnOutsideClick) event.preventDefault();
1759
+ },
1760
+ onEscapeKeyDown: (event) => {
1761
+ onEscapeKeyDown?.(event);
1762
+ const pressedIn = event.target instanceof Node && event.target !== document.body ? event.target : document.activeElement;
1763
+ if (windowed && containerEl && !(pressedIn && containerEl.contains(pressedIn))) {
1764
+ event.preventDefault();
1765
+ }
1766
+ },
1712
1767
  ...hasDescription ? {} : { "aria-describedby": void 0 },
1713
1768
  ...props,
1714
1769
  children: [
1715
1770
  hasTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(VisuallyHidden.Root, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DialogPrimitive.Title, { children: "Dialog" }) }),
1716
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1771
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DialogWindowHandleContext.Provider, { value: handle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1717
1772
  PortalContainerProvider,
1718
1773
  {
1719
1774
  container: containerEl ?? injectedContainer ?? null,
1720
1775
  children
1721
1776
  }
1722
- ) }),
1777
+ ) }) }),
1723
1778
  showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1724
1779
  DialogPrimitive.Close,
1725
1780
  {
@@ -1742,19 +1797,28 @@ DialogContent.displayName = DialogPrimitive.Content.displayName;
1742
1797
  var DialogHeader = ({
1743
1798
  className,
1744
1799
  ...props
1745
- }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1746
- "div",
1747
- {
1748
- "data-slot": "dialog-header",
1749
- className: cn(
1750
- // DialogContent owns an absolute close control. Reserve its hit area in
1751
- // every header so trailing actions never render underneath it.
1752
- "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
1753
- className
1754
- ),
1755
- ...props
1756
- }
1757
- );
1800
+ }) => {
1801
+ const handle = React10.useContext(DialogWindowHandleContext);
1802
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1803
+ "div",
1804
+ {
1805
+ "data-slot": "dialog-header",
1806
+ ...handle ? {
1807
+ ...handle,
1808
+ "data-window-handle": "",
1809
+ title: "Drag to move \xB7 double-click to recenter"
1810
+ } : {},
1811
+ className: cn(
1812
+ // DialogContent owns an absolute close control. Reserve its hit area in
1813
+ // every header so trailing actions never render underneath it.
1814
+ "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
1815
+ handle && "cursor-grab select-none active:cursor-grabbing",
1816
+ className
1817
+ ),
1818
+ ...props
1819
+ }
1820
+ );
1821
+ };
1758
1822
  DialogHeader.displayName = "DialogHeader";
1759
1823
  var DialogFooter = ({
1760
1824
  className,
@@ -16380,7 +16444,7 @@ function SavedViewsControl({
16380
16444
  ] })
16381
16445
  ] }),
16382
16446
  dirty ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { id: unsavedChangesId, className: "sr-only", children: "This table view has unsaved changes. Open the view menu to save or update it." }) : null,
16383
- visibleError ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { role: "alert", className: "basis-full break-words text-xs text-destructive", children: visibleError }) : null,
16447
+ visibleError && !saveOpen ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { role: "alert", className: "basis-full break-words text-xs text-destructive", children: visibleError }) : null,
16384
16448
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Dialog, { open: saveOpen, onOpenChange: setSaveOpen, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(DialogContent, { children: [
16385
16449
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(DialogTitle, { children: "Save current view" }) }),
16386
16450
  visibleError ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { role: "alert", className: "text-sm text-destructive", children: visibleError }) : null,