{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sheet",
  "type": "registry:component",
  "title": "Sheet",
  "description": "Opens a focused task from a screen edge. Native dialog with platform focus handling and backdrop.",
  "registryDependencies": [
    "https://vlak.dev/r/vlak-base.json",
    "https://vlak.dev/r/inter.json",
    "https://vlak.dev/r/dialog.json",
    "https://vlak.dev/r/vlak-lib.json"
  ],
  "dependencies": [
    "@stylexjs/stylex"
  ],
  "devDependencies": [
    "@stylexjs/babel-plugin"
  ],
  "docs": "Vlak leaves are StyleX. Compile them with @stylexjs/babel-plugin (Vite: @stylexjs/unplugin, Next: @stylexjs/nextjs-plugin). If you would rather not run a compiler, import @noorddev/vlak-react instead: it ships precompiled with one stylesheet.",
  "files": [
    {
      "path": "vlak/sheet.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport { vlak, mq } from \"./tokens.stylex\";\nimport { rs } from \"./rs\";\nimport { DialogCloseButton, DialogContext, dialogStyles, useDialogPart, useNativeDialog, type NativeDialogOptions } from \"./dialog\";\n\nexport interface SheetProps\n  extends Omit<React.DialogHTMLAttributes<HTMLDialogElement>, \"open\" | \"onClose\">,\n    NativeDialogOptions {\n  side?: \"left\" | \"right\";\n}\n\nconst styles = stylex.create({\n  frame: {\n    boxSizing: \"border-box\",\n    position: \"fixed\",\n    top: 0,\n    insetInlineEnd: 0,\n    bottom: 0,\n    insetInlineStart: \"auto\",\n    margin: 0,\n    height: \"100dvh\",\n    maxHeight: \"none\",\n    width: {\n      default: \"22.5rem\",\n      [mq.phone]: \"100%\",\n    },\n    maxWidth: {\n      default: \"85vw\",\n      [mq.phone]: \"100%\",\n    },\n    borderWidth: 0,\n    borderStyle: \"solid\",\n    borderInlineStartWidth: vlak.hairline,\n    borderColor: vlak.divider,\n    borderStartStartRadius: vlak.radiusSm,\n    borderStartEndRadius: 0,\n    borderEndEndRadius: 0,\n    borderEndStartRadius: vlak.radiusSm,\n    paddingBlock: \"1.5rem\",\n    paddingInline: \"1.25rem\",\n    backgroundColor: vlak.paper,\n    color: vlak.ink,\n    boxShadow: \"none\",\n    \"::backdrop\": {\n      backgroundColor: [\"rgba(0,0,0,0.25)\", `color-mix(in srgb, ${vlak.paper} 55%, transparent)`],\n    },\n  },\n  left: {\n    insetInlineEnd: \"auto\",\n    insetInlineStart: 0,\n    borderInlineStartWidth: 0,\n    borderInlineEndWidth: vlak.hairline,\n    borderStartStartRadius: 0,\n    borderStartEndRadius: vlak.radiusSm,\n    borderEndEndRadius: vlak.radiusSm,\n    borderEndStartRadius: 0,\n    boxShadow: \"none\",\n  },\n  title: {\n    display: \"block\",\n    fontSize: {\n      default: \"0.9375rem\",\n      [mq.phone]: \"1.125rem\",\n    },\n    fontWeight: 600,\n    letterSpacing: \"-0.01em\",\n    color: vlak.ink,\n    marginTop: 0,\n    marginInlineEnd: 0,\n    marginBottom: \"0.375rem\",\n    marginInlineStart: 0,\n  },\n  body: {\n    fontSize: {\n      default: \"0.84375rem\",\n      [mq.phone]: \"1rem\",\n    },\n    lineHeight: 1.45,\n    letterSpacing: \"-0.01em\",\n    color: vlak.gray,\n    margin: 0,\n  },\n});\n\n/**\n * A native <dialog> at the screen edge. The platform provides the\n * focus trap, Escape, and the backdrop; the title names it.\n */\nexport const Sheet = React.forwardRef<HTMLDialogElement, SheetProps>(function Sheet(\n  { open, onClose, dismissable, lightDismiss, closeLabel, side = \"right\", className, style, children, ...props },\n  forwardedRef,\n) {\n  const { ref, context, dialogProps } = useNativeDialog({ open, onClose, dismissable, lightDismiss }, props, forwardedRef);\n  const sx = rs([\"rs-sheet\", side === \"left\" && \"rs-sheet-left\", className], styles.frame, side === \"left\" && styles.left);\n  const close = rs([\"rs-sheet-close\"], dialogStyles.close);\n  return (\n    <DialogContext.Provider value={context}>\n      <dialog ref={ref} {...props} {...dialogProps} className={sx.className} style={{ ...sx.style, ...style }}>\n        {closeLabel != null && (\n          <DialogCloseButton label={closeLabel} className={close.className} style={close.style} onClick={() => onClose?.()} />\n        )}\n        {children}\n      </dialog>\n    </DialogContext.Provider>\n  );\n});\n\nexport interface SheetTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {\n  as?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"span\" | \"div\";\n}\n\nexport const SheetTitle = React.forwardRef<HTMLHeadingElement, SheetTitleProps>(function SheetTitle(\n  { as: Tag = \"h2\", className, style, id, ...props },\n  ref,\n) {\n  const titleId = useDialogPart(\"title\", id);\n  const sx = rs([\"rs-sheet-title\", className], styles.title);\n  return <Tag ref={ref as React.Ref<never>} {...props} id={titleId} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const SheetBody = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(function SheetBody(\n  { className, style, id, ...props },\n  ref,\n) {\n  const bodyId = useDialogPart(\"body\", id);\n  const sx = rs([\"rs-sheet-body\", className], styles.body);\n  return <p ref={ref} {...props} id={bodyId} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n",
      "type": "registry:component",
      "target": "components/vlak/sheet.tsx"
    },
    {
      "path": "vlak/styles/sheet.css",
      "content": "/* ── sheet: generated from packages/react/src/components/sheet.tsx ── */\n.rs-sheet{box-sizing:border-box;position:fixed;top:0;inset-inline-end:0;bottom:0;inset-inline-start:auto;margin:0;height:100dvh;max-height:none;width:22.5rem;max-width:85vw;border-width:0;border-style:solid;border-inline-start-width:1px;border-color:var(--divider);border-start-start-radius:var(--radius-sm);border-start-end-radius:0;border-end-end-radius:0;border-end-start-radius:var(--radius-sm);padding-block:1.5rem;padding-inline:1.25rem;background-color:var(--bg);color:var(--text);box-shadow:none}\n.rs-sheet::backdrop{background-color:rgba(0,0,0,0.25);background-color:color-mix(in srgb, var(--bg) 55%, transparent)}\n@media (max-width: 640px){.rs-sheet{width:100%;max-width:100%}}\n.rs-sheet-left{inset-inline-end:auto;inset-inline-start:0;border-inline-start-width:0;border-inline-end-width:1px;border-start-start-radius:0;border-start-end-radius:var(--radius-sm);border-end-end-radius:var(--radius-sm);border-end-start-radius:0;box-shadow:none}\n.rs-sheet-title{display:block;font-size:0.9375rem;font-weight:600;letter-spacing:-0.01em;color:var(--text);margin-top:0;margin-inline-end:0;margin-bottom:0.375rem;margin-inline-start:0}\n@media (max-width: 640px){.rs-sheet-title{font-size:1.125rem}}\n.rs-sheet-body{font-size:0.84375rem;line-height:1.45;letter-spacing:-0.01em;color:var(--text-secondary);margin:0}\n@media (max-width: 640px){.rs-sheet-body{font-size:1rem}}\n",
      "type": "registry:file",
      "target": "styles/vlak/sheet.css"
    }
  ],
  "meta": {
    "vlak": {
      "category": "surfaces",
      "classes": [
        "rs-sheet",
        "rs-sheet-left",
        "rs-sheet-title",
        "rs-sheet-body",
        "rs-sheet-close"
      ],
      "snippet": "<dialog class=\"rs-sheet\" aria-labelledby=\"filters-title\" open><button class=\"rs-sheet-close\" type=\"button\" aria-label=\"Close\">&times;</button><h2 class=\"rs-sheet-title\" id=\"filters-title\">Filters</h2><p class=\"rs-sheet-body\">Everything narrows from here.</p></dialog>",
      "cssOnly": false,
      "registryDependencies": [
        "dialog",
        "vlak-lib"
      ],
      "aliases": [
        "Sheet",
        "Side panel",
        "Drawer",
        "Slide-over",
        "Off-canvas"
      ],
      "example": "import { useState } from \"react\";\nimport { Button, Sheet, SheetBody, SheetTitle } from \"@noorddev/vlak-react\";\n\nconst [open, setOpen] = useState(false);\n\n<Button variant=\"ghost\" onClick={() => setOpen(true)}>Filters</Button>\n<Sheet open={open} onClose={() => setOpen(false)} side=\"right\" closeLabel=\"Close\">\n  <SheetTitle>Filters</SheetTitle>\n  <SheetBody>Everything narrows from here.</SheetBody>\n</Sheet>",
      "usage": {
        "use": [
          "Filters, settings, or a detail view that slides in beside the page.",
          "side=\"left\" for navigation on phones."
        ],
        "avoid": [
          "Short decisions; use Dialog.",
          "Content that should stay open while the page is used; the sheet is modal."
        ]
      },
      "keyboard": [
        {
          "keys": "Escape",
          "does": "Calls onClose (when dismissable, the default)"
        },
        {
          "keys": "Tab, Shift + Tab",
          "does": "Cycles focus inside the sheet"
        }
      ],
      "a11y": [
        "A native modal <dialog> docked to an edge: the platform traps focus and provides the backdrop.",
        "SheetTitle names it through aria-labelledby; SheetBody describes it. Focus moves in on open and returns on close.",
        "closeLabel renders a labelled close button; lightDismiss closes on a backdrop click. The ref is forwarded to the <dialog>."
      ]
    }
  }
}
