{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "baseline-status",
  "type": "registry:ui",
  "title": "Baseline Status",
  "description": "Display browser support status for web features based on the W3C WebDX Baseline specification. Includes real-time browser feature detection.",
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/new-york/ui/baseline-status.tsx",
      "content": "\"use client\"\n\nimport { CheckCircle2, XCircle } from \"lucide-react\"\nimport * as React from \"react\"\nimport {\n  type BaselineFeature,\n  type BaselineStatus as BaselineStatusType,\n  getBaselineStatus,\n  getBaselineStatusText,\n} from \"@/lib/baseline\"\nimport { cn } from \"@/lib/utils\"\n\n// ============================================================================\n// Browser Feature Detection\n// ============================================================================\n\nexport type BrowserFeature =\n  | \"view-transitions\"\n  | \"popover\"\n  | \"anchor-positioning\"\n  | \"container-queries\"\n  | \"has\"\n  | \"scroll-driven-animations\"\n  | \"text-wrap-balance\"\n  | \"text-wrap-pretty\"\n  | \"corner-shape\"\n\nfunction checkBrowserFeature(feature: BrowserFeature): boolean {\n  if (typeof document === \"undefined\" || typeof window === \"undefined\")\n    return false\n\n  switch (feature) {\n    case \"view-transitions\":\n      return \"startViewTransition\" in document\n    case \"popover\":\n      return \"popover\" in HTMLElement.prototype\n    case \"anchor-positioning\":\n      return CSS.supports(\"anchor-name\", \"--test\")\n    case \"container-queries\":\n      return CSS.supports(\"container-type\", \"inline-size\")\n    case \"has\":\n      return CSS.supports(\"selector(:has(*))\")\n    case \"scroll-driven-animations\":\n      return CSS.supports(\"animation-timeline\", \"scroll()\")\n    case \"text-wrap-balance\":\n      return CSS.supports(\"text-wrap\", \"balance\")\n    case \"text-wrap-pretty\":\n      return CSS.supports(\"text-wrap\", \"pretty\")\n    case \"corner-shape\":\n      return CSS.supports(\"corner-shape\", \"squircle\")\n    default:\n      return false\n  }\n}\n\nfunction getBrowserFeatureLabel(feature: BrowserFeature): string {\n  switch (feature) {\n    case \"view-transitions\":\n      return \"View Transitions API\"\n    case \"popover\":\n      return \"Popover API\"\n    case \"anchor-positioning\":\n      return \"CSS Anchor Positioning\"\n    case \"container-queries\":\n      return \"Container Queries\"\n    case \"has\":\n      return \":has() selector\"\n    case \"scroll-driven-animations\":\n      return \"Scroll-driven Animations\"\n    case \"text-wrap-balance\":\n      return \"text-wrap: balance\"\n    case \"text-wrap-pretty\":\n      return \"text-wrap: pretty\"\n    case \"corner-shape\":\n      return \"CSS corner-shape\"\n    default:\n      return feature\n  }\n}\n\n/**\n * Official Baseline icons from W3C WebDX Community Group\n * @see https://web-platform-dx.github.io/web-features/name-and-logo-usage-guidelines/\n * @license CC BY-ND 4.0\n */\nconst BaselineIcons = {\n  widely: (\n    <svg\n      viewBox=\"0 0 540 300\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      className=\"h-5 w-auto\"\n      aria-hidden=\"true\"\n    >\n      <path\n        d=\"M420 30L390 60L480 150L390 240L330 180L300 210L390 300L540 150L420 30Z\"\n        fill=\"#C4EED0\"\n      />\n      <path\n        d=\"M150 0L30 120L60 150L150 60L210 120L240 90L150 0Z\"\n        fill=\"#C4EED0\"\n      />\n      <path\n        d=\"M390 0L420 30L150 300L0 150L30 120L150 240L390 0Z\"\n        fill=\"#1EA446\"\n      />\n    </svg>\n  ),\n  newly: (\n    <svg\n      viewBox=\"0 0 540 300\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      className=\"h-5 w-auto\"\n      aria-hidden=\"true\"\n    >\n      <path d=\"M150 0L180 30L150 60L120 30L150 0Z\" fill=\"#A8C7FA\" />\n      <path d=\"M210 60L240 90L210 120L180 90L210 60Z\" fill=\"#A8C7FA\" />\n      <path d=\"M450 60L480 90L450 120L420 90L450 60Z\" fill=\"#A8C7FA\" />\n      <path d=\"M510 120L540 150L510 180L480 150L510 120Z\" fill=\"#A8C7FA\" />\n      <path d=\"M450 180L480 210L450 240L420 210L450 180Z\" fill=\"#A8C7FA\" />\n      <path d=\"M390 240L420 270L390 300L360 270L390 240Z\" fill=\"#A8C7FA\" />\n      <path d=\"M330 180L360 210L330 240L300 210L330 180Z\" fill=\"#A8C7FA\" />\n      <path d=\"M90 60L120 90L90 120L60 90L90 60Z\" fill=\"#A8C7FA\" />\n      <path\n        d=\"M390 0L420 30L150 300L0 150L30 120L150 240L390 0Z\"\n        fill=\"#1B6EF3\"\n      />\n    </svg>\n  ),\n  limited: (\n    <svg\n      viewBox=\"0 0 540 300\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      className=\"h-5 w-auto\"\n      aria-hidden=\"true\"\n    >\n      <path d=\"M150 0L240 90L210 120L120 30L150 0Z\" fill=\"#F09409\" />\n      <path\n        d=\"M420 30L540 150L420 270L390 240L480 150L390 60L420 30Z\"\n        fill=\"#C6C6C6\"\n      />\n      <path d=\"M330 180L300 210L390 300L420 270L330 180Z\" fill=\"#F09409\" />\n      <path\n        d=\"M120 30L150 60L60 150L150 240L120 270L0 150L120 30Z\"\n        fill=\"#C6C6C6\"\n      />\n      <path d=\"M390 0L420 30L150 300L120 270L390 0Z\" fill=\"#F09409\" />\n    </svg>\n  ),\n  no_data: (\n    <svg\n      viewBox=\"0 0 540 300\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      className=\"h-5 w-auto opacity-40\"\n      aria-hidden=\"true\"\n    >\n      <path\n        d=\"M420 30L540 150L420 270L390 240L480 150L390 60L420 30Z\"\n        fill=\"currentColor\"\n      />\n      <path\n        d=\"M120 30L150 60L60 150L150 240L120 270L0 150L120 30Z\"\n        fill=\"currentColor\"\n      />\n      <path d=\"M390 0L420 30L150 300L120 270L390 0Z\" fill=\"currentColor\" />\n    </svg>\n  ),\n}\n\nconst sizeClasses = {\n  sm: \"text-xs gap-1.5\",\n  md: \"text-sm gap-2\",\n  lg: \"text-base gap-2.5\",\n}\n\nconst iconSizeClasses = {\n  sm: \"[&_svg]:h-4\",\n  md: \"[&_svg]:h-5\",\n  lg: \"[&_svg]:h-6\",\n}\n\nexport interface BaselineStatusProps\n  extends React.HTMLAttributes<HTMLDivElement> {\n  /** Feature ID from web-features (e.g., \"scroll-snap\", \"container-queries\") */\n  featureId?: string\n  /** Direct status override (use instead of featureId for static data) */\n  status?: BaselineStatusType\n  /** Year when the feature became available */\n  year?: number\n  /** Size variant */\n  size?: \"sm\" | \"md\" | \"lg\"\n  /** Show year in the label */\n  showYear?: boolean\n  /** Show only the icon without text */\n  iconOnly?: boolean\n  /** Browser feature to check support for */\n  browserCheck?: BrowserFeature\n}\n\n/**\n * BaselineStatus displays browser support status for web features\n * based on the W3C WebDX Baseline specification.\n *\n * @see https://web.dev/baseline\n * @see https://github.com/web-platform-dx/web-features\n *\n * @example\n * // With featureId (fetches data at build time)\n * <BaselineStatus featureId=\"scroll-snap\" />\n *\n * @example\n * // With static data (no API call)\n * <BaselineStatus status=\"widely\" year={2022} />\n *\n * @example\n * // Icon only\n * <BaselineStatus featureId=\"container-queries\" iconOnly />\n */\nexport function BaselineStatus({\n  featureId,\n  status: statusProp,\n  year: yearProp,\n  size = \"md\",\n  showYear = true,\n  iconOnly = false,\n  browserCheck,\n  className,\n  ...props\n}: BaselineStatusProps) {\n  const [feature, setFeature] = React.useState<BaselineFeature | null>(\n    statusProp ? { status: statusProp, year: yearProp } : null,\n  )\n  const [isLoading, setIsLoading] = React.useState(!statusProp && !!featureId)\n  const [browserSupport, setBrowserSupport] = React.useState<boolean | null>(\n    null,\n  )\n\n  React.useEffect(() => {\n    if (statusProp || !featureId) return\n\n    let cancelled = false\n    setIsLoading(true)\n\n    getBaselineStatus(featureId).then((data) => {\n      if (!cancelled) {\n        setFeature(data)\n        setIsLoading(false)\n      }\n    })\n\n    return () => {\n      cancelled = true\n    }\n  }, [featureId, statusProp])\n\n  // Check browser support on mount\n  React.useEffect(() => {\n    if (browserCheck) {\n      setBrowserSupport(checkBrowserFeature(browserCheck))\n    }\n  }, [browserCheck])\n\n  if (isLoading) {\n    return (\n      <div\n        className={cn(\n          \"inline-flex items-center animate-pulse\",\n          sizeClasses[size],\n          className,\n        )}\n        {...props}\n      >\n        <div className=\"h-5 w-9 rounded-full bg-muted\" />\n        {!iconOnly && <div className=\"h-4 w-24 rounded bg-muted\" />}\n      </div>\n    )\n  }\n\n  const status = feature?.status ?? \"no_data\"\n  const year = showYear ? feature?.year : undefined\n  const label = getBaselineStatusText(status, year)\n  const icon = BaselineIcons[status]\n\n  // If browserCheck is provided, render combined layout\n  if (browserCheck && browserSupport !== null) {\n    const featureLabel = getBrowserFeatureLabel(browserCheck)\n\n    return (\n      <div\n        className={cn(\n          \"inline-flex flex-wrap items-center gap-3 rounded-lg border border-border/50 bg-muted/30 px-3 py-2\",\n          className,\n        )}\n        role=\"status\"\n        {...props}\n      >\n        {/* Baseline Status */}\n        <div\n          className={cn(\n            \"flex items-center\",\n            sizeClasses[size],\n            iconSizeClasses[size],\n          )}\n        >\n          {icon}\n          {!iconOnly && (\n            <span className=\"text-muted-foreground whitespace-nowrap\">\n              {label}\n            </span>\n          )}\n        </div>\n\n        {/* Browser Support Check */}\n        <div\n          className={cn(\n            \"flex items-center gap-1.5 text-sm\",\n            browserSupport\n              ? \"text-green-600 dark:text-green-400\"\n              : \"text-red-600 dark:text-red-400\",\n          )}\n        >\n          {browserSupport ? (\n            <CheckCircle2 className=\"h-4 w-4 shrink-0\" />\n          ) : (\n            <XCircle className=\"h-4 w-4 shrink-0\" />\n          )}\n          <span>\n            {browserSupport ? \"Your browser supports\" : \"Not supported:\"}{\" \"}\n            {featureLabel}\n          </span>\n        </div>\n      </div>\n    )\n  }\n\n  return (\n    <div\n      className={cn(\n        \"inline-flex items-center\",\n        sizeClasses[size],\n        iconSizeClasses[size],\n        className,\n      )}\n      role=\"status\"\n      aria-label={label}\n      {...props}\n    >\n      {icon}\n      {!iconOnly && (\n        <span className=\"text-muted-foreground whitespace-nowrap\">{label}</span>\n      )}\n    </div>\n  )\n}\n\n/**\n * Server Component wrapper for BaselineStatus\n * Use this in Server Components to fetch data at build time\n *\n * @example\n * // In a Server Component\n * const feature = await getBaselineStatus(\"scroll-snap\")\n * <BaselineStatusStatic {...feature} />\n */\nexport function BaselineStatusStatic({\n  status,\n  year,\n  size = \"md\",\n  showYear = true,\n  iconOnly = false,\n  className,\n  ...props\n}: Omit<BaselineStatusProps, \"featureId\"> & {\n  status: BaselineStatusType\n}) {\n  const label = getBaselineStatusText(status, showYear ? year : undefined)\n  const icon = BaselineIcons[status]\n\n  return (\n    <div\n      className={cn(\n        \"inline-flex items-center\",\n        sizeClasses[size],\n        iconSizeClasses[size],\n        className,\n      )}\n      role=\"status\"\n      aria-label={label}\n      {...props}\n    >\n      {icon}\n      {!iconOnly && (\n        <span className=\"text-muted-foreground whitespace-nowrap\">{label}</span>\n      )}\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "lib/baseline.ts",
      "content": "/**\n * Baseline API utility for fetching web feature browser support status\n * @see https://web.dev/baseline\n * @see https://api.webstatus.dev/v1/features/\n */\n\nconst BASELINE_API = \"https://api.webstatus.dev/v1/features\"\n\nexport type BaselineStatus = \"widely\" | \"newly\" | \"limited\" | \"no_data\"\n\nexport interface BaselineFeature {\n  status: BaselineStatus\n  lowDate?: string // \"2020-01-15\" - when feature became newly available\n  highDate?: string // \"2022-07-15\" - when feature became widely available\n  year?: number // extracted year from highDate or lowDate\n}\n\nexport interface BrowserImplementation {\n  date: string\n  status: \"available\" | \"unavailable\"\n  version: string\n}\n\nexport interface BaselineAPIResponse {\n  baseline: {\n    status: \"widely\" | \"newly\" | \"limited\"\n    low_date?: string\n    high_date?: string\n  } | null\n  browser_implementations?: Record<string, BrowserImplementation>\n  feature_id: string\n  name: string\n}\n\n/**\n * Fetches Baseline status for a web feature\n * Use this at build time or in server components for caching\n */\nexport async function getBaselineStatus(\n  featureId: string,\n): Promise<BaselineFeature> {\n  try {\n    const response = await fetch(`${BASELINE_API}/${featureId}`, {\n      next: { revalidate: 86400 }, // Cache for 24 hours\n    })\n\n    if (!response.ok) {\n      console.warn(`Baseline API: Feature \"${featureId}\" not found`)\n      return { status: \"no_data\" }\n    }\n\n    const data: BaselineAPIResponse = await response.json()\n\n    if (!data.baseline) {\n      return { status: \"no_data\" }\n    }\n\n    const { status, low_date, high_date } = data.baseline\n\n    // Extract year from the relevant date\n    const relevantDate = status === \"widely\" ? high_date : low_date\n    const year = relevantDate ? new Date(relevantDate).getFullYear() : undefined\n\n    return {\n      status,\n      lowDate: low_date,\n      highDate: high_date,\n      year,\n    }\n  } catch (error) {\n    console.error(`Baseline API error for \"${featureId}\":`, error)\n    return { status: \"no_data\" }\n  }\n}\n\n/**\n * Get display text for Baseline status\n */\nexport function getBaselineStatusText(\n  status: BaselineStatus,\n  year?: number,\n): string {\n  switch (status) {\n    case \"widely\":\n      return year ? `Widely available since ${year}` : \"Widely available\"\n    case \"newly\":\n      return year ? `Newly available since ${year}` : \"Newly available\"\n    case \"limited\":\n      return \"Limited availability\"\n    default:\n      return \"No data\"\n  }\n}\n\n/**\n * Common feature IDs for reference\n * @see https://github.com/web-platform-dx/web-features/tree/main/features\n */\nexport const FEATURE_IDS = {\n  // CSS\n  scrollSnap: \"scroll-snap\",\n  containerQueries: \"container-queries\",\n  cssGrid: \"css-grid\",\n  flexbox: \"flexbox\",\n  cssVariables: \"css-variables\",\n  anchorPositioning: \"anchor-positioning\",\n  viewTransitions: \"view-transitions\",\n  popover: \"popover\",\n\n  // JavaScript\n  promises: \"promises\",\n  asyncAwait: \"async-await\",\n  modules: \"modules\",\n\n  // APIs\n  intersectionObserver: \"intersection-observer\",\n  resizeObserver: \"resize-observer\",\n  webAnimations: \"web-animations\",\n} as const\n",
      "type": "registry:lib"
    }
  ]
}