{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "glass-surface",
  "title": "Glass Surface",
  "description": "The glass material on its own, with the backdrop Android blurs: Liquid Glass on iOS 26 and later, a lit blur elsewhere.",
  "dependencies": [
    "expo-blur",
    "expo-glass-effect"
  ],
  "registryDependencies": [
    "@glassyui-native/glass-provider"
  ],
  "files": [
    {
      "path": "registry/glassyui-native/glass-surface.tsx",
      "content": "import { BlurView } from 'expo-blur';\nimport { GlassView } from 'expo-glass-effect';\nimport { Children, forwardRef } from 'react';\nimport { Platform, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { useGlassBackdrop } from './glass-backdrop';\nimport { useGlassTheme } from './glass-provider';\nimport { resolveGlassMaterial } from './lib/material';\nimport { GLASS_RADIUS } from './lib/tokens';\n\nexport type SurfacePreset = 'subtle' | 'standard' | 'prominent' | 'control' | 'overlay';\n\nexport type SurfaceElevation = 'none' | 'base' | 'raised';\n\nexport type GlassSurfaceProps = ViewProps & {\n  /** Floating glass casts a shadow; glass set into a layout does not. Defaults to base. */\n  elevation?: SurfaceElevation;\n  /**\n   * How much frost: subtle shows the most of what lies behind, prominent the least. Overlay is\n   * for floating layers such as dialogs and menus: its denser tint keeps text at 4.5:1 over any\n   * backdrop.\n   */\n  preset?: SurfacePreset;\n  /**\n   * Colours the glass, as the prominent button's blue does. Use an opaque colour. Where the glass\n   * is a blur, the tint covers 92% of it, so white text on a tint that holds 4.5:1 alone still\n   * does over a white backdrop.\n   */\n  tint?: string;\n};\n\n// How strongly each preset blurs where the system's glass is unavailable. On the web these\n// land on the same blur radii as the CSS glass.\nconst BLUR_INTENSITY: Record<SurfacePreset, number> = {\n  subtle: 40,\n  control: 50,\n  standard: 70,\n  prominent: 90,\n  overlay: 90,\n};\n\nlet warnedAboutAndroidBackdrop = false;\n\n/**\n * The glass material on its own. iOS 26 and later draw the system's Liquid Glass; earlier iOS,\n * Android and the web blur what lies behind and light the rim; Reduce Transparency turns the\n * glass opaque. Text children are set in the theme's ink.\n */\nexport const GlassSurface = forwardRef<View, GlassSurfaceProps>(\n  ({ children, elevation = 'base', preset = 'standard', style, tint, ...rest }, ref) => {\n    const { colors, preferences } = useGlassTheme();\n    const backdrop = useGlassBackdrop();\n    const material = resolveGlassMaterial(preferences.reduceTransparency);\n    const radius = StyleSheet.flatten(style)?.borderRadius ?? GLASS_RADIUS.md;\n    const corners = { borderRadius: radius, borderCurve: 'continuous' } as const;\n    const blurTarget = backdrop?.target ?? undefined;\n\n    if (\n      Platform.OS === 'android' &&\n      material === 'blur' &&\n      !backdrop &&\n      !warnedAboutAndroidBackdrop\n    ) {\n      warnedAboutAndroidBackdrop = true;\n      console.warn(\n        'Glassy UI: Android blurs only what sits inside a GlassBackdrop. Glass outside one is a translucent tint.',\n      );\n    }\n\n    return (\n      <View\n        ref={ref}\n        style={[\n          corners,\n          elevation !== 'none' && {\n            boxShadow: elevation === 'raised' ? colors.shadowRaised : colors.shadow,\n          },\n          style,\n        ]}\n        {...rest}\n      >\n        {material === 'liquid' ? (\n          <GlassView\n            style={[StyleSheet.absoluteFill, corners, styles.layer]}\n            colorScheme={preferences.theme}\n            glassEffectStyle={preset === 'subtle' ? 'clear' : 'regular'}\n            tintColor={\n              tint ?? (preferences.mode === 'tinted' ? colors.glassFill.tinted : undefined)\n            }\n          />\n        ) : null}\n        {material === 'blur' ? (\n          <View style={[StyleSheet.absoluteFill, corners, styles.layer, styles.clip]}>\n            <BlurView\n              style={StyleSheet.absoluteFill}\n              intensity={BLUR_INTENSITY[preset]}\n              tint={\n                preferences.theme === 'dark'\n                  ? 'systemUltraThinMaterialDark'\n                  : 'systemUltraThinMaterialLight'\n              }\n              blurMethod={blurTarget ? 'dimezisBlurViewSdk31Plus' : 'none'}\n              blurTarget={blurTarget}\n            />\n            <View\n              style={[\n                StyleSheet.absoluteFill,\n                tint\n                  ? { backgroundColor: tint, opacity: 0.92 }\n                  : {\n                      backgroundColor:\n                        preset === 'overlay'\n                          ? colors.overlaySurface\n                          : colors.glassFill[preferences.mode],\n                    },\n              ]}\n            />\n            <View\n              style={[\n                StyleSheet.absoluteFill,\n                corners,\n                {\n                  boxShadow: `inset 0px 1px 0px ${colors.rimHighlight}, inset 0px 0px 0px 1px ${colors.rim}`,\n                },\n              ]}\n            />\n          </View>\n        ) : null}\n        {material === 'solid' ? (\n          <View\n            style={[\n              StyleSheet.absoluteFill,\n              corners,\n              styles.layer,\n              {\n                backgroundColor: tint ?? colors.opaqueSurface,\n                borderColor: colors.border,\n                borderWidth: StyleSheet.hairlineWidth,\n              },\n            ]}\n          />\n        ) : null}\n        {Children.map(children, (child) =>\n          // Children.map yields null, elements or text; only text needs a Text to render in.\n          child === null || child instanceof Object ? (\n            child\n          ) : (\n            <Text style={{ color: tint ? colors.accentForeground : colors.foreground }}>\n              {child}\n            </Text>\n          ),\n        )}\n      </View>\n    );\n  },\n);\n\nGlassSurface.displayName = 'GlassSurface';\n\nconst styles = StyleSheet.create({\n  clip: { overflow: 'hidden' },\n  layer: { pointerEvents: 'none' },\n});\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-surface.tsx"
    },
    {
      "path": "registry/glassyui-native/glass-backdrop.tsx",
      "content": "import { BlurTargetView } from 'expo-blur';\nimport {\n  createContext,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  type ReactNode,\n  type RefObject,\n} from 'react';\nimport { StyleSheet, View, type ViewProps } from 'react-native';\n\ntype BackdropTarget = {\n  /** The view Android blurs, once it has mounted. */\n  target: RefObject<View | null> | null;\n};\n\nconst BackdropContext = createContext<BackdropTarget | null>(null);\n\n/** The nearest GlassBackdrop, or null when glass sits outside one. */\nexport function useGlassBackdrop() {\n  return useContext(BackdropContext);\n}\n\nexport type GlassBackdropProps = ViewProps & {\n  /** What the glass sits over: a wallpaper, a photo or the screen's own content. */\n  backdrop: ReactNode;\n};\n\n/**\n * Lays its children over `backdrop`. iOS and the web blur whatever lies behind glass; Android can\n * only blur a view marked for it, so glass in the children blurs this backdrop there. Glass\n * outside any GlassBackdrop shows on Android as a translucent tint without blur.\n */\nexport function GlassBackdrop({ backdrop, children, ...rest }: GlassBackdropProps) {\n  const targetRef = useRef<View | null>(null);\n  const [target, setTarget] = useState<RefObject<View | null> | null>(null);\n\n  // Android's blur reads its target when it mounts or when the target object changes, so the\n  // glass gets a fresh object once the backdrop exists.\n  useEffect(() => {\n    setTarget({ current: targetRef.current });\n  }, []);\n\n  const value = useMemo(() => ({ target }), [target]);\n\n  return (\n    <View {...rest}>\n      <BlurTargetView ref={targetRef} style={StyleSheet.absoluteFill}>\n        {backdrop}\n      </BlurTargetView>\n      <BackdropContext.Provider value={value}>{children}</BackdropContext.Provider>\n    </View>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/glassyui/glass-backdrop.tsx"
    },
    {
      "path": "registry/glassyui-native/lib/material.ts",
      "content": "import { isGlassEffectAPIAvailable, isLiquidGlassAvailable } from 'expo-glass-effect';\n\n/**\n * How glass is drawn: the system's own Liquid Glass on iOS 26 and later, a blur of what lies\n * behind on earlier iOS, Android and the web, or an opaque fill under Reduce Transparency.\n */\nexport type GlassMaterial = 'liquid' | 'blur' | 'solid';\n\n// Both checks return false off iOS. The second guards early iOS 26 builds that lack the API.\nconst systemGlass = isLiquidGlassAvailable() && isGlassEffectAPIAvailable();\n\nexport function resolveGlassMaterial(reduceTransparency: boolean): GlassMaterial {\n  if (reduceTransparency) return 'solid';\n\n  return systemGlass ? 'liquid' : 'blur';\n}\n",
      "type": "registry:lib",
      "target": "components/glassyui/lib/material.ts"
    }
  ],
  "type": "registry:ui"
}