{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sheet",
  "title": "Sheet",
  "description": "bottom sheet shell",
  "dependencies": [
    "lucide-react-native@^1.21.0",
    "react-native-safe-area-context@~5.7.0"
  ],
  "registryDependencies": [
    "@kit-native/icon",
    "@kit-native/lib-haptics",
    "@kit-native/lib-reduced-motion",
    "@kit-native/lib-theme",
    "@kit-native/lib-utils",
    "@kit-native/text"
  ],
  "files": [
    {
      "path": "components/kit/sheet.tsx",
      "content": "import { Icon } from '@/components/ui/icon';\nimport { Text } from '@/components/ui/text';\nimport { haptic } from '@/lib/haptics';\nimport { TOKENS } from '@/lib/theme';\nimport { cn } from '@/lib/utils';\nimport { useMotion } from '@/lib/reduced-motion';\nimport { CheckIcon, type LucideIcon } from 'lucide-react-native';\nimport * as React from 'react';\nimport { Animated, Easing, Modal, Pressable, ScrollView, View } from 'react-native';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\n\ntype SheetProps = {\n  open: boolean;\n  onClose: () => void;\n  title?: string;\n  description?: string;\n  children: React.ReactNode;\n  /** Extra classes for the panel. */\n  className?: string;\n};\n\n/**\n * Bottom sheet shell: scrim + slide-up panel + drag handle. Scrolls, capped at 85% height.\n * Base for OptionSheet and ActionSheet; use directly for custom content.\n */\nexport function Sheet({ open, onClose, title, description, children, className }: SheetProps) {\n  const insets = useSafeAreaInsets();\n  const [translateY] = React.useState(() => new Animated.Value(400));\n  const motion = useMotion();\n\n  React.useEffect(() => {\n    if (!open) return;\n    translateY.setValue(400);\n    Animated.timing(translateY, {\n      toValue: 0,\n      duration: motion(TOKENS.duration.slow),\n      easing: Easing.out(Easing.cubic),\n      useNativeDriver: true,\n    }).start();\n  }, [open, translateY, motion]);\n\n  return (\n    <Modal visible={open} transparent animationType=\"fade\" statusBarTranslucent onRequestClose={onClose}>\n      <View className=\"flex-1 justify-end\">\n        <Pressable className=\"absolute inset-0 bg-black/50\" onPress={onClose} accessibilityRole=\"button\" accessibilityLabel=\"Close\" />\n        {/* The surface lives on a plain View: NativeWind classNames are dropped on\n            Animated.View on web, which left the panel transparent in the preview. */}\n        <Animated.View style={{ maxHeight: '85%', transform: [{ translateY }] }}>\n          <View\n            className={cn('bg-card rounded-t-2xl', className)}\n            style={{ paddingBottom: Math.max(insets.bottom, 16) }}>\n            <View className=\"items-center pb-3 pt-3\">\n              <View className=\"bg-border h-1 w-9 rounded-full\" />\n            </View>\n            {title || description ? (\n              <View className=\"gap-0.5 px-5 pb-3\">\n                {title ? <Text variant=\"large\" className=\"font-heading\">{title}</Text> : null}\n                {description ? <Text className=\"text-muted-foreground text-sm\">{description}</Text> : null}\n              </View>\n            ) : null}\n            <ScrollView bounces={false} keyboardShouldPersistTaps=\"handled\">\n              {children}\n            </ScrollView>\n          </View>\n        </Animated.View>\n      </View>\n    </Modal>\n  );\n}\n\nexport type SheetOption<T extends string> = { value: T; label: string; description?: string; icon?: LucideIcon };\n\ntype OptionSheetProps<T extends string> = {\n  open: boolean;\n  onClose: () => void;\n  title: string;\n  options: readonly SheetOption<T>[];\n  value?: T;\n  onChange: (value: T) => void;\n};\n\n/** Pick one of N values; closes on selection. */\nexport function OptionSheet<T extends string>({ open, onClose, title, options, value, onChange }: OptionSheetProps<T>) {\n  return (\n    <Sheet open={open} onClose={onClose} title={title}>\n      {options.map((o, i) => {\n        const selected = o.value === value;\n        return (\n          <Pressable\n            key={o.value}\n            accessibilityRole=\"button\"\n            accessibilityState={{ selected }}\n            // aria-pressed is web-only (react-native-web drops accessibilityState, and a button may not carry aria-selected).\n            aria-pressed={selected}\n            onPress={() => {\n              haptic('selection');\n              onChange(o.value);\n              onClose();\n            }}\n            className={cn('min-h-14 flex-row items-center gap-3 px-5 py-3 active:bg-accent', i < options.length - 1 && 'border-border border-b')}>\n            {o.icon ? <Icon as={o.icon} size={20} className=\"text-muted-foreground\" /> : null}\n            <View className=\"flex-1\">\n              <Text className={cn(selected ? 'font-semibold' : 'font-normal')}>{o.label}</Text>\n              {o.description ? <Text className=\"text-muted-foreground text-sm\">{o.description}</Text> : null}\n            </View>\n            {selected ? <Icon as={CheckIcon} size={20} className=\"text-primary\" /> : null}\n          </Pressable>\n        );\n      })}\n    </Sheet>\n  );\n}\n\nexport type ActionSheetItem = { label: string; icon?: LucideIcon; destructive?: boolean; disabled?: boolean; onPress: () => void };\n\ntype ActionSheetProps = {\n  open: boolean;\n  onClose: () => void;\n  title?: string;\n  description?: string;\n  items: ActionSheetItem[];\n  cancelLabel?: string;\n};\n\n/** A list of actions (share, edit, delete…) plus Cancel. Each row fires its own callback. */\nexport function ActionSheet({ open, onClose, title, description, items, cancelLabel = 'Cancel' }: ActionSheetProps) {\n  return (\n    <Sheet open={open} onClose={onClose} title={title} description={description}>\n      {items.map((item, i) => (\n        <Pressable\n          key={item.label}\n          accessibilityRole=\"button\"\n          disabled={item.disabled}\n          onPress={() => {\n            haptic(item.destructive ? 'heavy' : 'selection');\n            item.onPress();\n            onClose();\n          }}\n          className={cn('min-h-14 flex-row items-center gap-3 px-5 py-3 active:bg-accent', i < items.length - 1 && 'border-border border-b', item.disabled && 'opacity-40')}>\n          {item.icon ? <Icon as={item.icon} size={20} className={item.destructive ? 'text-destructive' : 'text-foreground'} /> : null}\n          <Text className={cn('flex-1', item.destructive && 'text-destructive')}>{item.label}</Text>\n        </Pressable>\n      ))}\n      <Pressable accessibilityRole=\"button\" onPress={onClose} className=\"bg-muted mx-5 mt-3 h-control items-center justify-center rounded-lg active:opacity-70\">\n        <Text className=\"font-semibold\">{cancelLabel}</Text>\n      </Pressable>\n    </Sheet>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/kit/sheet.tsx"
    }
  ],
  "meta": {
    "exports": [
      "Sheet"
    ],
    "api": "<Sheet open onClose title? description?>{children}</Sheet>"
  },
  "docs": "Run `npx expo install --fix` afterwards so Expo SDK packages match your SDK. Needs the kit theme (`@kit-native/theme`) and `KitThemeProvider` from `@kit-native/lib-theme-context` at the root.",
  "categories": [
    "overlays"
  ],
  "type": "registry:component"
}