{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "variants",
  "title": "Variant helpers",
  "description": "Classifies variant option values into display tiers from `exists` and `available`.",
  "dependencies": [
    "@channel3/sdk"
  ],
  "registryDependencies": [
    "https://ui.trychannel3.com/r/format.json"
  ],
  "files": [
    {
      "path": "registry/default/lib/variants.ts",
      "content": "import type { OptionValue, VariantOption, Variants } from \"@channel3/sdk/resources\";\nimport { isInStock } from \"@/registry/default/lib/format\";\n\n/**\n * Display tier for a variant option value. The selector renders the same\n * vocabulary regardless of dimension (size pills, color swatches, etc.).\n *\n * - `selected`   — the currently resolved value for its option.\n * - `available`  — offered on this configuration and purchasable.\n * - `outOfStock` — offered on this configuration but not currently purchasable.\n * - `notOffered` — only present on a sibling variant (`exists: false`).\n */\nexport type ValueState = \"selected\" | \"available\" | \"outOfStock\" | \"notOffered\";\n\n/**\n * Classify a variant option value for display emphasis.\n *\n * On search results `available` is `null` (stock isn't hydrated), so any value\n * that `exists` is treated as `available` until a product-detail fetch resolves\n * real stock. Values are never disabled: clicking a `notOffered` or\n * `outOfStock` value re-resolves the configuration server-side.\n */\nexport function valueState(value: OptionValue, isSelected: boolean): ValueState {\n  if (isSelected) {\n    return \"selected\";\n  }\n  if (!value.exists) {\n    return \"notOffered\";\n  }\n  if (value.available && !isInStock(value.available)) {\n    return \"outOfStock\";\n  }\n  return \"available\";\n}\n\nexport function selectionFromVariants(variants: Variants): Record<string, string> {\n  return Object.fromEntries(variants.selected.map((selected) => [selected.name, selected.label]));\n}\n\nexport function isSwatchOption(option: VariantOption): boolean {\n  return option.values.some((value) => Boolean(value.thumbnail_url));\n}\n\nexport function swatchOption(variants: Variants): VariantOption | undefined {\n  return variants.options.find(isSwatchOption);\n}\n\nexport function mergeSelection(\n  variants: Variants,\n  pending: Record<string, string>,\n): Record<string, string> {\n  return { ...selectionFromVariants(variants), ...pending };\n}\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:lib"
}
