{"version":3,"sources":["../src/dialog/dialog.tsx"],"names":["Root","usePermissions","resolvePermissions","useAudit","evaluatePermission","CANONICAL_ACTIONS","jsx","RadixDialog","Trigger","forwardRef","Portal","Overlay","Content","Title","Description","Close","resolveMessage"],"mappings":"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","file":"dialog.cjs","sourcesContent":["/**\n * Dialog — headless primitive wrapping Radix Dialog.\n *\n * Radix's Dialog is best-in-class for focus trap, portal, scroll lock,\n * and `aria-modal` semantics (ARCHITECTURE §6). We wrap thinly:\n *   - Permission gating on <Root> (canView=false → primitive returns null)\n *   - Audit events on open / close\n *   - `data-oshon-primitive=\"dialog-*\"` styling hooks for Phase 4\n *   - i18n-ready `messages` prop on <Close> (for the \"Close\" aria-label)\n *\n * \"use client\" is mandatory here — Radix primitives use hooks + DOM APIs\n * internally, so our wrapper inherits the client boundary. See\n * `docs/adr/primitives/002-dialog-radix-wrap.md`.\n */\n\n'use client';\n\nimport * as RadixDialog from '@radix-ui/react-dialog';\nimport { forwardRef } from 'react';\nimport type {\n  ComponentPropsWithoutRef,\n  ElementRef,\n  ReactNode,\n} from 'react';\nimport {\n  evaluatePermission,\n  resolvePermissions,\n  usePermissions,\n  useAudit,\n  type PermissionContext,\n} from '../context.js';\nimport { CANONICAL_ACTIONS } from '../actions.js';\nimport { resolveMessage, type MessageBag } from '../i18n.js';\n\n// ────────────────────────────────────────────────────────────────────────────\n// Root\n\nexport interface DialogRootProps\n  extends Omit<RadixDialog.DialogProps, 'onOpenChange'> {\n  /**\n   * Called whenever the dialog's open state changes. The primitive fires\n   * `dialog:open` / `dialog:close` audit events automatically before\n   * this callback runs — consumers receive the same notification either\n   * way.\n   */\n  onOpenChange?: (open: boolean) => void;\n  /**\n   * Per-instance permission override. Merges over the ambient\n   * `PermissionContext` (ARCHITECTURE §10). The primitive queries\n   * `can('view', resource, attrs)` on mount; denied + `mode='hidden'`\n   * returns `null`. Denied + `'disabled'` or `'readOnly'` still returns\n   * `null` for a dialog (there is no useful visible-but-non-interactive\n   * state for a modal) and emits a `permission:denied` audit.\n   */\n  permissions?: Partial<PermissionContext>;\n  /**\n   * Resource name passed to `permissions.can('view', resource, attrs)`.\n   * Default `'dialog'`. Override for specific semantics like\n   * `resource=\"record:delete-confirmation\"`.\n   */\n  resource?: string;\n  /** Attribute bag for attribute-based access control. */\n  permissionAttrs?: Record<string, unknown>;\n  children: ReactNode;\n}\n\n/**\n * Dialog root. Controls open state, gates on permissions, and fires\n * audit events. Must wrap every other `Dialog.*` sub-component.\n */\nfunction Root({\n  children,\n  open,\n  defaultOpen,\n  onOpenChange,\n  permissions,\n  resource = 'dialog',\n  permissionAttrs,\n  modal,\n}: DialogRootProps) {\n  const context = usePermissions();\n  const effective = resolvePermissions(permissions, context);\n  const emit = useAudit();\n\n  const { granted, denyReason } = evaluatePermission(\n    effective,\n    'view',\n    resource,\n    permissionAttrs,\n  );\n\n  if (!granted) {\n    // A dialog with no content can't render \"readOnly\" usefully, so we\n    // hide under any deny mode — but still emit the denial so governance\n    // can surface over-/under-permissive flows.\n    emit({\n      component: 'dialog',\n      action: CANONICAL_ACTIONS.PERMISSION_DENIED,\n      permissionResult: 'denied',\n      ...(denyReason ? { denyReason } : {}),\n      details: { attemptedAction: 'view', resource },\n    });\n    return null;\n  }\n\n  const handleOpenChange = (next: boolean) => {\n    emit({\n      component: 'dialog',\n      action: next ? CANONICAL_ACTIONS.DIALOG_OPEN : CANONICAL_ACTIONS.DIALOG_CLOSE,\n      permissionResult: 'granted',\n    });\n    onOpenChange?.(next);\n  };\n\n  return (\n    <RadixDialog.Root\n      open={open}\n      defaultOpen={defaultOpen}\n      onOpenChange={handleOpenChange}\n      modal={modal}\n    >\n      {children}\n    </RadixDialog.Root>\n  );\n}\nRoot.displayName = 'Dialog.Root';\n\n// ────────────────────────────────────────────────────────────────────────────\n// Trigger\n\nexport type DialogTriggerProps = ComponentPropsWithoutRef<typeof RadixDialog.Trigger>;\n\nconst Trigger = forwardRef<\n  ElementRef<typeof RadixDialog.Trigger>,\n  DialogTriggerProps\n>(function DialogTrigger(props, ref) {\n  return (\n    <RadixDialog.Trigger\n      ref={ref}\n      data-oshon-primitive=\"dialog-trigger\"\n      {...props}\n    />\n  );\n});\n\n// ────────────────────────────────────────────────────────────────────────────\n// Portal\n\nexport type DialogPortalProps = RadixDialog.DialogPortalProps;\n\n/**\n * Portal. Radix handles the portal container itself; we pass through.\n */\nfunction Portal(props: DialogPortalProps) {\n  return <RadixDialog.Portal {...props} />;\n}\nPortal.displayName = 'Dialog.Portal';\n\n// ────────────────────────────────────────────────────────────────────────────\n// Overlay\n\nexport type DialogOverlayProps = ComponentPropsWithoutRef<typeof RadixDialog.Overlay>;\n\nconst Overlay = forwardRef<\n  ElementRef<typeof RadixDialog.Overlay>,\n  DialogOverlayProps\n>(function DialogOverlay(props, ref) {\n  return (\n    <RadixDialog.Overlay\n      ref={ref}\n      data-oshon-primitive=\"dialog-overlay\"\n      {...props}\n    />\n  );\n});\n\n// ────────────────────────────────────────────────────────────────────────────\n// Content\n\nexport type DialogContentProps = ComponentPropsWithoutRef<typeof RadixDialog.Content>;\n\n/**\n * Content. Radix provides focus trap, scroll lock, ESC-to-close,\n * `aria-modal`, and `role=\"dialog\"` — we add only the styling hook.\n */\nconst Content = forwardRef<\n  ElementRef<typeof RadixDialog.Content>,\n  DialogContentProps\n>(function DialogContent(props, ref) {\n  return (\n    <RadixDialog.Content\n      ref={ref}\n      data-oshon-primitive=\"dialog-content\"\n      {...props}\n    />\n  );\n});\n\n// ────────────────────────────────────────────────────────────────────────────\n// Title\n\nexport type DialogTitleProps = ComponentPropsWithoutRef<typeof RadixDialog.Title>;\n\nconst Title = forwardRef<\n  ElementRef<typeof RadixDialog.Title>,\n  DialogTitleProps\n>(function DialogTitle(props, ref) {\n  return (\n    <RadixDialog.Title\n      ref={ref}\n      data-oshon-primitive=\"dialog-title\"\n      {...props}\n    />\n  );\n});\n\n// ────────────────────────────────────────────────────────────────────────────\n// Description\n\nexport type DialogDescriptionProps = ComponentPropsWithoutRef<typeof RadixDialog.Description>;\n\nconst Description = forwardRef<\n  ElementRef<typeof RadixDialog.Description>,\n  DialogDescriptionProps\n>(function DialogDescription(props, ref) {\n  return (\n    <RadixDialog.Description\n      ref={ref}\n      data-oshon-primitive=\"dialog-description\"\n      {...props}\n    />\n  );\n});\n\n// ────────────────────────────────────────────────────────────────────────────\n// Close\n\nexport interface DialogCloseProps\n  extends ComponentPropsWithoutRef<typeof RadixDialog.Close> {\n  /**\n   * i18n message bag. Reads `close` key for the default aria-label when\n   * the consumer renders an icon-only close button.\n   */\n  messages?: MessageBag;\n}\n\nconst Close = forwardRef<\n  ElementRef<typeof RadixDialog.Close>,\n  DialogCloseProps\n>(function DialogClose({ messages, 'aria-label': ariaLabel, children, ...rest }, ref) {\n  // Only fall back to the \"close\" message when there's no visible text\n  // label (icon-only close button). If consumers render `<Close>Cancel</Close>`\n  // the button's text content is its accessible name — overriding aria-label\n  // would shadow it and break `getByRole('button', { name: 'Cancel' })`.\n  const resolvedLabel =\n    ariaLabel ??\n    (children == null\n      ? resolveMessage(messages, 'close', 'Close')\n      : undefined);\n  return (\n    <RadixDialog.Close\n      ref={ref}\n      data-oshon-primitive=\"dialog-close\"\n      aria-label={resolvedLabel}\n      {...rest}\n    >\n      {children}\n    </RadixDialog.Close>\n  );\n});\n\n// ────────────────────────────────────────────────────────────────────────────\n// Compound export\n\n/**\n * Compound Dialog primitive. Use as:\n *\n *   <Dialog.Root>\n *     <Dialog.Trigger>Open</Dialog.Trigger>\n *     <Dialog.Portal>\n *       <Dialog.Overlay />\n *       <Dialog.Content>\n *         <Dialog.Title>Confirm</Dialog.Title>\n *         <Dialog.Description>Are you sure?</Dialog.Description>\n *         <Dialog.Close>Cancel</Dialog.Close>\n *       </Dialog.Content>\n *     </Dialog.Portal>\n *   </Dialog.Root>\n */\nexport const Dialog = {\n  Root,\n  Trigger,\n  Portal,\n  Overlay,\n  Content,\n  Title,\n  Description,\n  Close,\n};\n\nexport type DialogProps = DialogRootProps;\n"]}