{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dialog",
  "title": "Dialog",
  "description": "A centered surface over a dimmed page, for a decision that needs full attention.",
  "dependencies": [
    "@base-ui/react",
    "@hugeicons/core-free-icons",
    "@hugeicons/react",
    "@stylexjs/stylex"
  ],
  "registryDependencies": [
    "https://constella.aayush.cv/r/base.json",
    "https://constella.aayush.cv/r/button.json"
  ],
  "files": [
    {
      "path": "src/components/primitives/dialog.tsx",
      "content": "\"use client\";\n\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\";\nimport { Cancel01Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport type { ComponentProps } from \"react\";\n\nimport { Button } from \"@/components/primitives/button\";\nimport type { Sx } from \"@/lib/constella/styles\";\nimport { typeStyles } from \"@/lib/constella/styles\";\nimport {\n  blurs,\n  colors,\n  durations,\n  easings,\n  fontWeights,\n  layers,\n  media,\n  motion,\n  radii,\n  shadows,\n  sizes,\n  space,\n  strokes,\n} from \"@/lib/constella/tokens.stylex\";\n\nconst dialogSizes = [\"sm\", \"default\", \"lg\", \"full\"] as const;\n\ntype DialogSize = (typeof dialogSizes)[number];\n\ntype Styled<T> = Omit<T, \"className\" | \"style\"> & {\n  sx?: Sx;\n};\n\ntype DialogPopupProps = Styled<DialogPrimitive.Popup.Props> & {\n  size?: DialogSize;\n};\n\nconst offstage = \":is([data-starting-style], [data-ending-style])\";\nconst instant = \":is([data-skip-motion])\";\nconst withClose = \":is(:has(> [data-slot='dialog-close-button']) > *)\";\n\nconst styles = stylex.create({\n  backdrop: {\n    backdropFilter: `blur(${blurs.backdrop})`,\n    backgroundColor: colors.overlay,\n    insetBlockEnd: 0,\n    insetBlockStart: 0,\n    insetInlineEnd: 0,\n    insetInlineStart: 0,\n    opacity: { default: 1, [offstage]: 0 },\n    position: \"fixed\",\n    transitionDuration: { default: durations.dialog, [instant]: 0 },\n    transitionProperty: \"opacity\",\n    transitionTimingFunction: easings.out,\n    zIndex: layers.dialog,\n  },\n  viewport: {\n    alignItems: \"center\",\n    display: \"flex\",\n    insetBlockEnd: 0,\n    insetBlockStart: 0,\n    insetInlineEnd: 0,\n    insetInlineStart: 0,\n    justifyContent: \"center\",\n    paddingBlock: space.md,\n    paddingInlineEnd: space.md,\n    paddingInlineStart: space.md,\n    position: \"fixed\",\n    zIndex: layers.dialog,\n  },\n  popup: {\n    backgroundColor: colors.raised,\n    borderStartStartRadius: radii.xl,\n    borderStartEndRadius: radii.xl,\n    borderEndStartRadius: radii.xl,\n    borderEndEndRadius: radii.xl,\n    boxShadow: shadows.xl,\n    color: colors.textPrimary,\n    display: \"flex\",\n    flexDirection: \"column\",\n    gap: space.md,\n    maxHeight: \"100%\",\n    opacity: { default: 1, [offstage]: 0 },\n    overflowY: {\n      default: \"auto\",\n      \":has(> [data-slot='dialog-body'])\": \"hidden\",\n    },\n    paddingBlock: space.md,\n    paddingInlineEnd: space.md,\n    paddingInlineStart: space.md,\n    position: \"relative\",\n    // A parent steps back while a dialog opened from it sits on top.\n    transform: {\n      default: `translateY(calc(var(--nested-dialogs, 0) * -1 * ${space.sm})) scale(calc(1 - var(--nested-dialogs, 0) * ${motion.stackScale}))`,\n      [offstage]: `scale(${motion.dialogScale})`,\n    },\n    transitionDuration: { default: durations.dialog, [instant]: 0 },\n    transitionProperty: {\n      default: \"opacity, transform\",\n      [media.reducedMotion]: \"opacity\",\n    },\n    transitionTimingFunction: easings.out,\n    width: `min(100%, ${sizes.dialog})`,\n  },\n  sm: { width: `min(100%, ${sizes.dialogSm})` },\n  lg: { width: `min(100%, ${sizes.dialogLg})` },\n  // The viewport's padding stays around it, so it still reads as a dialog over the page.\n  full: { height: \"100%\", width: \"100%\" },\n  header: {\n    display: \"flex\",\n    flexDirection: \"column\",\n    flexShrink: 0,\n    gap: space.xxs,\n    paddingInlineEnd: {\n      default: null,\n      [withClose]: `calc(${sizes.controlSm} + ${space.xs} - ${space.md})`,\n    },\n  },\n  // Bleeds to the popup's edges so the scrollbar sits there, not beside the text.\n  body: {\n    flexGrow: 1,\n    flexShrink: 1,\n    marginInline: `calc(-1 * ${space.md})`,\n    minHeight: 0,\n    overflowY: \"auto\",\n    paddingInlineEnd: space.md,\n    paddingInlineStart: space.md,\n  },\n  // A tinted bar set into the popup's bottom edge, so the actions read as their own row.\n  footer: {\n    backgroundColor: colors.fillSubtle,\n    borderTopColor: colors.borderSubtle,\n    borderTopStyle: \"solid\",\n    borderTopWidth: strokes.border,\n    display: \"flex\",\n    flexDirection: { default: \"column-reverse\", [media.sm]: \"row\" },\n    flexShrink: 0,\n    gap: space.xs,\n    justifyContent: \"flex-end\",\n    marginBlockEnd: `calc(-1 * ${space.md})`,\n    // Pinned to the bottom when the popup is taller than its content, as at `full`.\n    marginBlockStart: \"auto\",\n    marginInline: `calc(-1 * ${space.md})`,\n    paddingBlock: space.md,\n    paddingInlineEnd: space.md,\n    paddingInlineStart: space.md,\n  },\n  title: {\n    fontWeight: fontWeights.medium,\n    marginBlockEnd: 0,\n    marginBlockStart: 0,\n    marginInline: 0,\n    // A long name or address in the title breaks rather than widening the popup.\n    overflowWrap: \"anywhere\",\n    textWrap: \"balance\",\n  },\n  description: {\n    color: colors.textSecondary,\n    marginBlockEnd: 0,\n    marginBlockStart: 0,\n    marginInline: 0,\n    overflowWrap: \"anywhere\",\n    textWrap: \"pretty\",\n  },\n  closeButton: {\n    insetBlockStart: space.xs,\n    insetInlineEnd: space.xs,\n    position: \"absolute\",\n  },\n});\n\nfunction Dialog(props: DialogPrimitive.Root.Props) {\n  return <DialogPrimitive.Root {...props} />;\n}\n\nfunction DialogTrigger({\n  sx,\n  ...props\n}: Styled<DialogPrimitive.Trigger.Props>) {\n  return (\n    <DialogPrimitive.Trigger\n      data-slot=\"dialog-trigger\"\n      {...props}\n      {...stylex.props(sx)}\n    />\n  );\n}\n\nfunction DialogPortal({ sx, ...props }: Styled<DialogPrimitive.Portal.Props>) {\n  return (\n    <DialogPrimitive.Portal\n      data-slot=\"dialog-portal\"\n      {...props}\n      {...stylex.props(sx)}\n    />\n  );\n}\n\nfunction DialogBackdrop({\n  sx,\n  ...props\n}: Styled<DialogPrimitive.Backdrop.Props>) {\n  return (\n    <DialogPrimitive.Backdrop\n      data-slot=\"dialog-backdrop\"\n      {...props}\n      {...stylex.props(styles.backdrop, sx)}\n    />\n  );\n}\n\nfunction DialogViewport({\n  sx,\n  ...props\n}: Styled<DialogPrimitive.Viewport.Props>) {\n  return (\n    <DialogPrimitive.Viewport\n      data-slot=\"dialog-viewport\"\n      {...props}\n      {...stylex.props(styles.viewport, sx)}\n    />\n  );\n}\n\n// Shared with Alert Dialog, type included, so the two never drift apart.\nconst dialogStyles = {\n  ...styles,\n  description: [typeStyles.textSm, styles.description],\n  popup: [typeStyles.textSm, styles.popup],\n  title: [typeStyles.textBase, styles.title],\n};\n\nconst sizeStyles = {\n  default: null,\n  full: styles.full,\n  lg: styles.lg,\n  sm: styles.sm,\n} satisfies Record<DialogSize, stylex.StyleXStyles | null>;\n\nfunction DialogPopup({ size = \"default\", sx, ...props }: DialogPopupProps) {\n  return (\n    <DialogPrimitive.Popup\n      data-size={size}\n      data-slot=\"dialog-popup\"\n      {...props}\n      {...stylex.props(dialogStyles.popup, sizeStyles[size], sx)}\n    />\n  );\n}\n\nfunction DialogContent(props: DialogPopupProps) {\n  return (\n    <DialogPortal>\n      <DialogBackdrop />\n      <DialogViewport>\n        <DialogPopup {...props} />\n      </DialogViewport>\n    </DialogPortal>\n  );\n}\n\nfunction DialogHeader({ sx, ...props }: Styled<ComponentProps<\"div\">>) {\n  return (\n    <div\n      data-slot=\"dialog-header\"\n      {...props}\n      {...stylex.props(styles.header, sx)}\n    />\n  );\n}\n\nfunction DialogBody({ sx, ...props }: Styled<ComponentProps<\"div\">>) {\n  return (\n    <div\n      data-slot=\"dialog-body\"\n      {...props}\n      {...stylex.props(styles.body, sx)}\n    />\n  );\n}\n\nfunction DialogFooter({ sx, ...props }: Styled<ComponentProps<\"div\">>) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      {...props}\n      {...stylex.props(styles.footer, sx)}\n    />\n  );\n}\n\nfunction DialogTitle({ sx, ...props }: Styled<DialogPrimitive.Title.Props>) {\n  return (\n    <DialogPrimitive.Title\n      data-slot=\"dialog-title\"\n      {...props}\n      {...stylex.props(dialogStyles.title, sx)}\n    />\n  );\n}\n\nfunction DialogDescription({\n  sx,\n  ...props\n}: Styled<DialogPrimitive.Description.Props>) {\n  return (\n    <DialogPrimitive.Description\n      data-slot=\"dialog-description\"\n      {...props}\n      {...stylex.props(dialogStyles.description, sx)}\n    />\n  );\n}\n\nfunction DialogClose({ sx, ...props }: Styled<DialogPrimitive.Close.Props>) {\n  return (\n    <DialogPrimitive.Close\n      data-slot=\"dialog-close\"\n      {...props}\n      {...stylex.props(sx)}\n    />\n  );\n}\n\n// The styles ride on the Button: it applies its own last, over anything Base UI merges in.\nfunction DialogCloseButton({\n  children,\n  sx,\n  ...props\n}: Omit<Styled<DialogPrimitive.Close.Props>, \"render\">) {\n  return (\n    <DialogPrimitive.Close\n      aria-label=\"Close\"\n      data-slot=\"dialog-close-button\"\n      render={\n        <Button size=\"icon-sm\" sx={[styles.closeButton, sx]} variant=\"ghost\" />\n      }\n      {...props}\n    >\n      {children ?? (\n        <HugeiconsIcon\n          aria-hidden\n          icon={Cancel01Icon}\n          size={sizes.icon}\n          strokeWidth={Number(strokes.icon)}\n        />\n      )}\n    </DialogPrimitive.Close>\n  );\n}\n\nexport {\n  Dialog,\n  DialogBackdrop,\n  DialogBody,\n  DialogClose,\n  DialogCloseButton,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogPopup,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n  DialogViewport,\n  dialogSizes,\n  dialogStyles,\n};\nexport type { DialogPopupProps, DialogSize };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/dialog/index.md",
  "type": "registry:ui"
}