{
  "name": "Modal",
  "source": "src/components/Modal.tsx",
  "propsType": "ModalProps",
  "description": "Modal — Figma `Modal` (792:1537).\n\n`Size` x `Align`, with the sections as props rather than variants. The panel\nhugs its content at every size except `fullscreen`, which fills the viewport\nand pushes the actions to the bottom edge.\n\nRENDERS NOTHING WHEN CLOSED, and mounts into a portal when open. Both come\nfrom React Aria's `Overlay`, and both matter: a modal left in the tree while\nclosed is still focusable by keyboard, and one rendered inline inherits any\n`overflow: hidden` or stacking context from wherever it was written.\n\nThe scrim is part of this component in code, unlike in Figma — see the note\nin modal.css.",
  "import": "import { Modal } from 'ionbase-ui';",
  "status": "stable",
  "since": "0.11.0",
  "summary": "A focus-trapping dialog. Renders nothing when closed and portals when open.",
  "useWhen": [
    "the task must be completed or abandoned before anything else",
    "confirming a destructive action",
    "a short focused form that would otherwise need its own page"
  ],
  "useInstead": [
    {
      "when": "the content is supplementary and the page stays usable",
      "use": "Popover",
      "why": "a Popover does not trap focus or block the page"
    },
    {
      "when": "it is a short label for a control",
      "use": "Tooltip"
    }
  ],
  "variants": {
    "size": {
      "sm": {
        "use": "confirmations and single-question prompts"
      },
      "md": {
        "use": "the default; short forms"
      },
      "lg": {
        "use": "multi-section forms"
      },
      "fullscreen": {
        "use": "immersive tasks; fills the viewport and pins the actions to the bottom edge"
      }
    },
    "align": {
      "left": {
        "use": "the default; forms and anything the user reads"
      },
      "center": {
        "use": "single-message confirmations only"
      }
    }
  },
  "slots": {
    "footer": {
      "accepts": "Button",
      "note": "the primary action goes last, at the trailing edge"
    },
    "media": {
      "note": "rendered above the title"
    }
  },
  "a11y": {
    "role": "dialog",
    "guarantees": [
      "focus moves into the panel on open and returns to the trigger on close",
      "Escape and a scrim click both close it",
      "focus is trapped while open",
      "nothing is rendered at all while closed, so no closed-modal content is keyboard reachable"
    ],
    "requires": [
      "`title`, which provides the dialog's accessible name"
    ]
  },
  "antiPatterns": [
    {
      "dont": "rendering <Modal> only when a state flag is true",
      "do": "render it always and drive `isOpen`",
      "why": "Modal already renders nothing when closed. Wrapping it in a conditional discards the open/close transition and the focus-return behaviour."
    },
    {
      "dont": "opening a Modal from inside another Modal",
      "why": "two focus traps compete and Escape becomes ambiguous"
    },
    {
      "dont": "a destructive action as the only button, with no cancel",
      "why": "a confirmation with no way out is not a confirmation"
    }
  ],
  "stylesheet": "src/styles/modal.css",
  "tokens": [
    "--border-subtle",
    "--border-width-default",
    "--border-width-thick",
    "--font-family-sans",
    "--font-weight-regular",
    "--font-weight-semibold",
    "--icon-primary",
    "--icon-secondary",
    "--icon-size-lg",
    "--icon-size-md",
    "--ion-duration-base",
    "--ion-ease-out",
    "--ion-modal-width",
    "--ion-shadow-shadow-xl",
    "--radius-full",
    "--radius-sm",
    "--radius-xl",
    "--ring-focus",
    "--spacing-12",
    "--spacing-16",
    "--spacing-20",
    "--spacing-24",
    "--spacing-32",
    "--spacing-48",
    "--spacing-8",
    "--surface-hover",
    "--surface-overlay",
    "--surface-primary-subtle",
    "--surface-scrim",
    "--text-default",
    "--text-secondary",
    "--type-body",
    "--type-body-line-height",
    "--type-h5",
    "--type-h5-line-height"
  ],
  "props": {
    "isOpen": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Whether the modal is shown."
    },
    "onOpenChange": {
      "type": "((isOpen: boolean) => void) | undefined",
      "required": false,
      "origin": "own",
      "description": "Called with the next open state — `false` when the modal asks to close."
    },
    "size": {
      "type": "ModalSize | undefined",
      "required": false,
      "origin": "own",
      "description": "Matches the Figma `Size` variant.",
      "values": [
        "sm",
        "md",
        "lg",
        "fullscreen"
      ],
      "default": "md"
    },
    "align": {
      "type": "ModalAlign | undefined",
      "required": false,
      "origin": "own",
      "description": "Matches the Figma `Align` variant.",
      "values": [
        "left",
        "center"
      ],
      "default": "left"
    },
    "title": {
      "type": "React.ReactNode",
      "required": true,
      "origin": "own",
      "description": "Required: the dialog's accessible name, wired via `aria-labelledby`."
    },
    "description": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "Supporting copy under the title."
    },
    "media": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "The featured slot above the title — an icon or an illustration. Rendered\ninside a circular container that hugs it."
    },
    "footer": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "Action row. Right-aligned when `align=\"left\"`, centred when `\"center\"`."
    },
    "showClose": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Show the close button. Defaults to `true`.",
      "default": true
    },
    "closeLabel": {
      "type": "string | undefined",
      "required": false,
      "origin": "own",
      "description": "Accessible name for the close button.",
      "default": "Close dialog"
    },
    "children": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "Body content."
    },
    "className": {
      "type": "string | undefined",
      "required": false,
      "origin": "own"
    },
    "isDismissable": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "aria",
      "description": "Whether to close the modal when the user interacts outside it.",
      "tags": {
        "default": "false"
      }
    },
    "isKeyboardDismissDisabled": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "aria",
      "description": "Whether pressing the escape key to close the modal should be disabled.",
      "tags": {
        "default": "false"
      }
    },
    "shouldCloseOnInteractOutside": {
      "type": "((element: Element) => boolean) | undefined",
      "required": false,
      "origin": "aria",
      "description": "When user interacts with the argument element outside of the overlay ref,\nreturn true if onClose should be called.  This gives you a chance to filter\nout interaction with elements that should not dismiss the overlay.\nBy default, onClose will always be called on interaction outside the overlay ref."
    }
  },
  "propCounts": {
    "own": 12,
    "aria": 3,
    "dom": 0,
    "other": 0
  }
}
