{
  "$schema": "https://cubixflow.ir/schema/registry-item.json",
  "name": "credit-card",
  "type": "registry:ui",
  "title": "Credit Card",
  "description": "A labeled credit card number field with four separate 4-digit inputs. Values always display as Persian digits.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/cubix/credit-card.tsx",
      "type": "registry:ui",
      "target": "components/cubix/credit-card.tsx",
      "content": "\"use client\"\n\n/*\n  Cubix Credit Card - labeled four-group card number field specialized from Text Field.\n\n  Four numeric segments with - separators. Values always display as Persian\n  digits. inputMode is locked to numeric. Weight 400 and tracking-normal keep\n  IRANSans XV readable in fixed-height controls. The control row is dir=ltr so\n  groups follow international card order inside RTL pages.\n*/\nimport * as React from \"react\"\nimport { Field as FieldPrimitive } from \"@base-ui/react/field\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst creditCardControlVariants = cva(\n  \"group/credit-card-control relative flex w-full min-w-0 items-center outline-none\",\n  {\n    variants: {\n      size: {\n        default: \"gap-2\",\n        lg: \"gap-2.5\",\n      },\n    },\n    defaultVariants: {\n      size: \"default\",\n    },\n  }\n)\n\nconst creditCardSegmentVariants = cva(\n  \"w-full min-w-0 flex-1 rounded-lg border border-input bg-transparent text-center font-normal leading-none tracking-normal text-foreground tabular-nums transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-primary focus-visible:ring-3 focus-visible:ring-primary/20 focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:border-transparent disabled:bg-muted disabled:text-muted-foreground disabled:placeholder:text-muted-foreground aria-invalid:border-destructive aria-invalid:ring-0 aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-muted dark:aria-invalid:border-destructive/50 dark:aria-invalid:focus-visible:border-destructive/50\",\n  {\n    variants: {\n      size: {\n        default: \"h-10 px-2 text-label md:text-label leading-none\",\n        lg: \"h-12 px-2.5 text-label md:text-label leading-none\",\n      },\n    },\n    defaultVariants: {\n      size: \"default\",\n    },\n  }\n)\n\ntype CreditCardSize = NonNullable<\n  VariantProps<typeof creditCardControlVariants>[\"size\"]\n>\n\ntype CreditCardPart = \"group1\" | \"group2\" | \"group3\" | \"group4\"\n\ntype CreditCardParts = {\n  group1: string\n  group2: string\n  group3: string\n  group4: string\n}\n\ntype CreditCardStore = {\n  parts: CreditCardParts\n  setPart: (part: CreditCardPart, digits: string) => void\n  setParts: (parts: CreditCardParts) => void\n}\n\nconst CreditCardSizeContext = React.createContext<CreditCardSize>(\"default\")\nconst CreditCardStoreContext = React.createContext<CreditCardStore | null>(null)\n\ntype CreditCardContextValue = {\n  size: CreditCardSize\n  disabled?: boolean\n  invalid?: boolean\n}\n\nconst CreditCardContext = React.createContext<CreditCardContextValue | null>(\n  null\n)\n\nconst PERSIAN_DIGITS = \"۰۱۲۳۴۵۶۷۸۹\"\nconst ARABIC_DIGITS = \"٠١٢٣٤٥٦٧٨٩\"\nconst DIGIT_CHAR = /[\\d۰-۹٠-٩]/\nconst ALLOWED_INSERT = /^[\\d۰-۹٠-٩]+$/\nconst SEGMENT_LENGTH = 4\nconst MAX_LENGTH: Record<CreditCardPart, number> = {\n  group1: SEGMENT_LENGTH,\n  group2: SEGMENT_LENGTH,\n  group3: SEGMENT_LENGTH,\n  group4: SEGMENT_LENGTH,\n}\nconst PART_ORDER: CreditCardPart[] = [\"group1\", \"group2\", \"group3\", \"group4\"]\nconst PART_SLOT: Record<CreditCardPart, string> = {\n  group1: \"credit-card-group-1\",\n  group2: \"credit-card-group-2\",\n  group3: \"credit-card-group-3\",\n  group4: \"credit-card-group-4\",\n}\nconst PART_LABEL: Record<CreditCardPart, string> = {\n  group1: \"رقم‌های ۱ تا ۴\",\n  group2: \"رقم‌های ۵ تا ۸\",\n  group3: \"رقم‌های ۹ تا ۱۲\",\n  group4: \"رقم‌های ۱۳ تا ۱۶\",\n}\nconst PART_PLACEHOLDER: Record<CreditCardPart, string> = {\n  group1: \"\",\n  group2: \"\",\n  group3: \"\",\n  group4: \"\",\n}\nconst PART_AUTOCOMPLETE: Record<CreditCardPart, string> = {\n  group1: \"cc-number\",\n  group2: \"cc-number\",\n  group3: \"cc-number\",\n  group4: \"cc-number\",\n}\n\n/** Six-digit BIN prefixes for Iranian issuer cards (شبا / شتاب). */\nconst CREDIT_CARD_BANK_BINS: Record<string, string> = {\n  \"636795\": \"بانک مرکزی\",\n  \"636797\": \"بانک مرکزی\",\n  \"603799\": \"بانک ملی\",\n  \"170019\": \"بانک ملی\",\n  \"589210\": \"بانک سپه\",\n  \"604932\": \"بانک سپه\",\n  \"627381\": \"بانک سپه\",\n  \"639599\": \"بانک سپه\",\n  \"636949\": \"بانک سپه\",\n  \"639370\": \"بانک سپه\",\n  \"505801\": \"بانک سپه\",\n  \"603769\": \"بانک صادرات\",\n  \"903769\": \"بانک صادرات\",\n  \"610433\": \"بانک ملت\",\n  \"991975\": \"بانک ملت\",\n  \"627353\": \"بانک تجارت\",\n  \"585983\": \"بانک تجارت\",\n  \"628023\": \"بانک مسکن\",\n  \"603770\": \"بانک کشاورزی\",\n  \"639217\": \"بانک کشاورزی\",\n  \"589463\": \"بانک رفاه کارگران\",\n  \"627760\": \"پست بانک\",\n  \"502908\": \"بانک توسعه تعاون\",\n  \"627648\": \"بانک توسعه صادرات\",\n  \"207177\": \"بانک توسعه صادرات\",\n  \"627961\": \"بانک صنعت و معدن\",\n  \"606373\": \"بانک قرض‌الحسنه مهر ایران\",\n  \"504172\": \"بانک قرض‌الحسنه رسالت\",\n  \"628157\": \"موسسه اعتباری ملل\",\n  \"606256\": \"موسسه اعتباری ملل\",\n  \"622106\": \"بانک پارسیان\",\n  \"627884\": \"بانک پارسیان\",\n  \"639194\": \"بانک پارسیان\",\n  \"502229\": \"بانک پاسارگاد\",\n  \"639347\": \"بانک پاسارگاد\",\n  \"621986\": \"بانک سامان\",\n  \"627412\": \"بانک اقتصاد نوین\",\n  \"636214\": \"بانک آینده\",\n  \"502806\": \"بانک شهر\",\n  \"504706\": \"بانک شهر\",\n  \"502938\": \"بانک دی\",\n  \"639346\": \"بانک سینا\",\n  \"639607\": \"بانک سرمایه\",\n  \"505416\": \"بانک گردشگری\",\n  \"505426\": \"بانک گردشگری\",\n  \"505785\": \"بانک ایران زمین\",\n  \"627488\": \"بانک کارآفرین\",\n  \"502910\": \"بانک کارآفرین\",\n  \"585947\": \"بانک خاورمیانه\",\n}\n\nfunction toLatinDigits(value: string) {\n  return value\n    .replace(/[۰-۹]/g, (digit) => String(PERSIAN_DIGITS.indexOf(digit)))\n    .replace(/[٠-٩]/g, (digit) => String(ARABIC_DIGITS.indexOf(digit)))\n}\n\nfunction toPersianDigits(value: string) {\n  return toLatinDigits(value).replace(\n    /\\d/g,\n    (digit) => PERSIAN_DIGITS[Number(digit)] ?? digit\n  )\n}\n\nfunction extractDigits(value: string) {\n  return toLatinDigits(value).replace(/\\D/g, \"\")\n}\n\nfunction formatSegmentDigits(digits: string, maxLength: number) {\n  const clipped = extractDigits(digits).slice(0, maxLength)\n  return clipped ? toPersianDigits(clipped) : \"\"\n}\n\nfunction emptyParts(): CreditCardParts {\n  return { group1: \"\", group2: \"\", group3: \"\", group4: \"\" }\n}\n\nfunction parseCreditCardValue(value: string): CreditCardParts {\n  const normalized = value.trim()\n  if (!normalized) return emptyParts()\n\n  const separators = normalized.split(/[/\\-.\\s]+/).filter(Boolean)\n  if (separators.length >= 4) {\n    return {\n      group1: extractDigits(separators[0] ?? \"\").slice(0, SEGMENT_LENGTH),\n      group2: extractDigits(separators[1] ?? \"\").slice(0, SEGMENT_LENGTH),\n      group3: extractDigits(separators[2] ?? \"\").slice(0, SEGMENT_LENGTH),\n      group4: extractDigits(separators[3] ?? \"\").slice(0, SEGMENT_LENGTH),\n    }\n  }\n\n  const digits = extractDigits(normalized).slice(0, 16)\n  return {\n    group1: digits.slice(0, 4),\n    group2: digits.slice(4, 8),\n    group3: digits.slice(8, 12),\n    group4: digits.slice(12, 16),\n  }\n}\n\nfunction formatCreditCardValue(\n  value: string | CreditCardParts | null | undefined\n) {\n  const parts =\n    value == null\n      ? emptyParts()\n      : typeof value === \"string\"\n        ? parseCreditCardValue(value)\n        : {\n            group1: extractDigits(value.group1).slice(0, SEGMENT_LENGTH),\n            group2: extractDigits(value.group2).slice(0, SEGMENT_LENGTH),\n            group3: extractDigits(value.group3).slice(0, SEGMENT_LENGTH),\n            group4: extractDigits(value.group4).slice(0, SEGMENT_LENGTH),\n          }\n\n  if (!parts.group1 && !parts.group2 && !parts.group3 && !parts.group4) {\n    return \"\"\n  }\n  return PART_ORDER.map((part) =>\n    parts[part] ? toPersianDigits(parts[part]) : \"\"\n  ).join(\"-\")\n}\n\nfunction getCreditCardBankName(\n  value: string | CreditCardParts | null | undefined\n) {\n  if (value == null) return null\n  const parts =\n    typeof value === \"string\" ? parseCreditCardValue(value) : value\n  const digits = PART_ORDER.map((part) => extractDigits(parts[part] ?? \"\")).join(\n    \"\"\n  )\n  if (digits.length < 6) return null\n  const bin = digits.slice(0, 6)\n  return CREDIT_CARD_BANK_BINS[bin] ?? null\n}\n\nfunction setNativeInputValue(input: HTMLInputElement, next: string) {\n  const descriptor = Object.getOwnPropertyDescriptor(\n    HTMLInputElement.prototype,\n    \"value\"\n  )\n  descriptor?.set?.call(input, next)\n  input.dispatchEvent(new Event(\"input\", { bubbles: true }))\n  input.dispatchEvent(new Event(\"change\", { bubbles: true }))\n}\n\nfunction focusSegment(\n  control: Element | null,\n  part: CreditCardPart,\n  options?: { select?: boolean }\n) {\n  const input = control?.querySelector<HTMLInputElement>(\n    `[data-slot=${PART_SLOT[part]}]`\n  )\n  if (!input || input.disabled || input.readOnly) return\n  input.focus()\n  if (options?.select) {\n    input.select()\n  } else {\n    const end = input.value.length\n    input.setSelectionRange(end, end)\n  }\n}\n\nfunction CreditCardStoreProvider({\n  children,\n}: {\n  children: React.ReactNode\n}) {\n  const [parts, setPartsState] = React.useState<CreditCardParts>(emptyParts)\n  const setPart = React.useCallback((part: CreditCardPart, digits: string) => {\n    setPartsState((prev) => ({\n      ...prev,\n      [part]: extractDigits(digits).slice(0, MAX_LENGTH[part]),\n    }))\n  }, [])\n  const setParts = React.useCallback((next: CreditCardParts) => {\n    setPartsState({\n      group1: extractDigits(next.group1).slice(0, SEGMENT_LENGTH),\n      group2: extractDigits(next.group2).slice(0, SEGMENT_LENGTH),\n      group3: extractDigits(next.group3).slice(0, SEGMENT_LENGTH),\n      group4: extractDigits(next.group4).slice(0, SEGMENT_LENGTH),\n    })\n  }, [])\n  const store = React.useMemo(\n    () => ({ parts, setPart, setParts }),\n    [parts, setPart, setParts]\n  )\n\n  return (\n    <CreditCardStoreContext.Provider value={store}>\n      {children}\n    </CreditCardStoreContext.Provider>\n  )\n}\n\nfunction CreditCard({\n  className,\n  size = \"default\",\n  name,\n  children,\n  disabled,\n  invalid,\n  ...props\n}: Omit<React.ComponentProps<typeof FieldPrimitive.Root>, \"size\"> & {\n  size?: CreditCardSize\n  name?: string\n}) {\n  return (\n    <CreditCardStoreProvider>\n      <CreditCardContext.Provider value={{ size, disabled, invalid }}>\n        <CreditCardSizeContext.Provider value={size}>\n          <FieldPrimitive.Root\n            data-slot=\"credit-card\"\n            data-size={size}\n            disabled={disabled}\n            invalid={invalid}\n            className={cn(\n              \"group/credit-card flex w-full min-w-0 flex-col gap-2 data-disabled:cursor-not-allowed data-disabled:opacity-70\",\n              className\n            )}\n            {...props}\n          >\n            {name ? <CreditCardHiddenInput name={name} /> : null}\n            {children}\n          </FieldPrimitive.Root>\n        </CreditCardSizeContext.Provider>\n      </CreditCardContext.Provider>\n    </CreditCardStoreProvider>\n  )\n}\n\nfunction CreditCardHiddenInput({ name }: { name: string }) {\n  const store = React.useContext(CreditCardStoreContext)\n  const value = store ? formatCreditCardValue(store.parts) : \"\"\n\n  return <input type=\"hidden\" name={name} value={value} readOnly />\n}\n\nfunction CreditCardLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof FieldPrimitive.Label>) {\n  return (\n    <FieldPrimitive.Label\n      data-slot=\"credit-card-label\"\n      className={cn(\n        \"flex w-fit items-center gap-2 text-label leading-none font-normal text-foreground select-none group-data-disabled/credit-card:cursor-not-allowed group-data-disabled/credit-card:text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CreditCardControl({\n  className,\n  size: sizeProp,\n  onClick,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  size?: CreditCardSize\n}) {\n  const rootSize = React.useContext(CreditCardContext)?.size\n  const contextSize = React.useContext(CreditCardSizeContext)\n  const size = sizeProp ?? rootSize ?? contextSize\n\n  return (\n    <div\n      data-slot=\"credit-card-control\"\n      data-size={size}\n      dir=\"ltr\"\n      className={cn(creditCardControlVariants({ size }), className)}\n      onClick={(event) => {\n        onClick?.(event)\n        if (event.defaultPrevented) return\n        if ((event.target as HTMLElement).closest(\"button,a,input,textarea\")) {\n          return\n        }\n        const first = event.currentTarget.querySelector<HTMLInputElement>(\n          \"[data-slot=credit-card-group-1]\"\n        )\n        const target =\n          first && !first.value\n            ? first\n            : event.currentTarget.querySelector<HTMLInputElement>(\n                \"[data-credit-card-segment]:not([disabled])\"\n              )\n        if (!target || target.disabled || target.readOnly) return\n        target.focus()\n      }}\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n\nfunction CreditCardSeparator({\n  className,\n  children = \"-\",\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"credit-card-separator\"\n      aria-hidden=\"true\"\n      className={cn(\n        \"shrink-0 select-none text-label font-normal text-muted-foreground group-data-disabled/credit-card:cursor-not-allowed\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </span>\n  )\n}\n\nfunction CreditCardSegment({\n  part,\n  className,\n  size: sizeProp,\n  disabled,\n  autoComplete,\n  \"aria-label\": ariaLabel,\n  \"aria-invalid\": ariaInvalid,\n  placeholder,\n  onBeforeInput,\n  onPaste,\n  onInput,\n  onKeyDown,\n  defaultValue,\n  value,\n  ...props\n}: Omit<\n  React.ComponentProps<\"input\">,\n  \"size\" | \"type\" | \"inputMode\" | \"spellCheck\" | \"maxLength\"\n> & {\n  part: CreditCardPart\n  size?: CreditCardSize\n}) {\n  const ctx = React.useContext(CreditCardContext)\n  const contextSize = React.useContext(CreditCardSizeContext)\n  const size = sizeProp ?? ctx?.size ?? contextSize\n  const store = React.useContext(CreditCardStoreContext)\n  const isInvalid = ariaInvalid ?? ctx?.invalid\n  const maxLength = MAX_LENGTH[part]\n  const persianDefault =\n    defaultValue === undefined\n      ? undefined\n      : formatSegmentDigits(String(defaultValue), maxLength)\n  const persianValue =\n    value === undefined\n      ? undefined\n      : formatSegmentDigits(String(value), maxLength)\n\n  const setPart = store?.setPart\n  const setParts = store?.setParts\n\n  React.useLayoutEffect(() => {\n    if (value === undefined) return\n    setPart?.(part, extractDigits(String(persianValue ?? \"\")))\n  }, [value, persianValue, part, setPart])\n\n  React.useLayoutEffect(() => {\n    if (value !== undefined) return\n    setPart?.(part, extractDigits(String(persianDefault ?? \"\")))\n  }, [value, persianDefault, part, setPart])\n\n  const applyValue = (\n    input: HTMLInputElement,\n    rawDigits: string,\n    options?: { advance?: boolean }\n  ) => {\n    const nextDigits = extractDigits(rawDigits).slice(0, maxLength)\n    const next = nextDigits ? toPersianDigits(nextDigits) : \"\"\n    setPart?.(part, nextDigits)\n    if (next !== input.value) {\n      setNativeInputValue(input, next)\n    }\n    if (options?.advance && nextDigits.length >= maxLength) {\n      const index = PART_ORDER.indexOf(part)\n      const nextPart = PART_ORDER[index + 1]\n      if (nextPart) {\n        focusSegment(\n          input.closest(\"[data-slot=credit-card-control]\"),\n          nextPart,\n          { select: true }\n        )\n      }\n    }\n  }\n\n  return (\n    <input\n      data-slot={PART_SLOT[part]}\n      data-credit-card-segment=\"\"\n      data-size={size}\n      data-part={part}\n      aria-label={ariaLabel ?? PART_LABEL[part]}\n      placeholder={placeholder ?? PART_PLACEHOLDER[part]}\n      className={cn(creditCardSegmentVariants({ size }), className)}\n      {...props}\n      disabled={disabled ?? ctx?.disabled}\n      aria-invalid={isInvalid || undefined}\n      type=\"text\"\n      inputMode=\"numeric\"\n      size={1}\n      autoComplete={autoComplete ?? PART_AUTOCOMPLETE[part]}\n      spellCheck={false}\n      maxLength={maxLength}\n      defaultValue={persianDefault}\n      value={persianValue}\n      onBeforeInput={(event) => {\n        onBeforeInput?.(event)\n        if (event.defaultPrevented) return\n        if (typeof event.data !== \"string\" || event.data.length === 0) return\n        if (event.data === \"/\" || event.data === \"-\" || event.data === \".\") {\n          event.preventDefault()\n          const index = PART_ORDER.indexOf(part)\n          const nextPart = PART_ORDER[index + 1]\n          if (nextPart) {\n            focusSegment(\n              event.currentTarget.closest(\"[data-slot=credit-card-control]\"),\n              nextPart,\n              { select: true }\n            )\n          }\n          return\n        }\n        if (!ALLOWED_INSERT.test(event.data)) {\n          event.preventDefault()\n          return\n        }\n        const input = event.currentTarget\n        const start = input.selectionStart ?? input.value.length\n        const end = input.selectionEnd ?? input.value.length\n        const insert = extractDigits(event.data)\n        if (!insert) {\n          event.preventDefault()\n          return\n        }\n        event.preventDefault()\n        const current = extractDigits(input.value)\n        const nextDigits = (\n          current.slice(0, countDigitsBefore(input.value, start)) +\n          insert +\n          current.slice(countDigitsBefore(input.value, end))\n        ).slice(0, maxLength)\n        applyValue(input, nextDigits, { advance: true })\n      }}\n      onPaste={(event) => {\n        onPaste?.(event)\n        if (event.defaultPrevented) return\n        const text = event.clipboardData?.getData(\"text\") ?? \"\"\n        if (!text) return\n        event.preventDefault()\n        const parsed = parseCreditCardValue(text)\n        const hasMultiple =\n          Boolean(parsed.group1 && parsed.group2) ||\n          text.includes(\"-\") ||\n          text.includes(\" \") ||\n          extractDigits(text).length > maxLength\n\n        const input = event.currentTarget\n        const control = input.closest(\"[data-slot=credit-card-control]\")\n\n        if (hasMultiple && setParts) {\n          setParts(parsed)\n          for (const nextPart of PART_ORDER) {\n            const segment = control?.querySelector<HTMLInputElement>(\n              `[data-slot=${PART_SLOT[nextPart]}]`\n            )\n            if (!segment) continue\n            const next = formatSegmentDigits(\n              parsed[nextPart],\n              MAX_LENGTH[nextPart]\n            )\n            if (next !== segment.value) setNativeInputValue(segment, next)\n          }\n          const focusPart =\n            parsed.group4.length >= SEGMENT_LENGTH\n              ? \"group4\"\n              : parsed.group3.length >= SEGMENT_LENGTH\n                ? \"group4\"\n                : parsed.group2.length >= SEGMENT_LENGTH\n                  ? \"group3\"\n                  : parsed.group1.length >= SEGMENT_LENGTH\n                    ? \"group2\"\n                    : \"group1\"\n          focusSegment(control, focusPart)\n          return\n        }\n\n        applyValue(input, extractDigits(text), { advance: true })\n      }}\n      onInput={(event) => {\n        onInput?.(event)\n        if (event.defaultPrevented) return\n        const input = event.currentTarget\n        if (value !== undefined) {\n          setPart?.(part, extractDigits(input.value))\n          return\n        }\n        applyValue(input, input.value, { advance: true })\n      }}\n      onKeyDown={(event) => {\n        onKeyDown?.(event)\n        if (event.defaultPrevented) return\n        if (event.key !== \"Backspace\") return\n        const input = event.currentTarget\n        const start = input.selectionStart ?? 0\n        const end = input.selectionEnd ?? 0\n        if (input.value.length > 0 && (start !== 0 || end !== 0)) return\n        if (start !== end) return\n        const index = PART_ORDER.indexOf(part)\n        const prevPart = PART_ORDER[index - 1]\n        if (!prevPart) return\n        event.preventDefault()\n        focusSegment(\n          input.closest(\"[data-slot=credit-card-control]\"),\n          prevPart\n        )\n      }}\n    />\n  )\n}\n\nfunction countDigitsBefore(value: string, caret: number) {\n  let count = 0\n  const end = Math.max(0, Math.min(caret, value.length))\n  for (let index = 0; index < end; index += 1) {\n    if (DIGIT_CHAR.test(value[index] ?? \"\")) count += 1\n  }\n  return count\n}\n\nfunction CreditCardGroup1(\n  props: Omit<React.ComponentProps<typeof CreditCardSegment>, \"part\">\n) {\n  return <CreditCardSegment part=\"group1\" {...props} />\n}\n\nfunction CreditCardGroup2(\n  props: Omit<React.ComponentProps<typeof CreditCardSegment>, \"part\">\n) {\n  return <CreditCardSegment part=\"group2\" {...props} />\n}\n\nfunction CreditCardGroup3(\n  props: Omit<React.ComponentProps<typeof CreditCardSegment>, \"part\">\n) {\n  return <CreditCardSegment part=\"group3\" {...props} />\n}\n\nfunction CreditCardGroup4(\n  props: Omit<React.ComponentProps<typeof CreditCardSegment>, \"part\">\n) {\n  return <CreditCardSegment part=\"group4\" {...props} />\n}\n\nfunction CreditCardDescription({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof FieldPrimitive.Description>) {\n  const store = React.useContext(CreditCardStoreContext)\n  const bankName = store ? getCreditCardBankName(store.parts) : null\n  const content = bankName ?? children\n\n  if (content == null || content === false) {\n    return null\n  }\n\n  return (\n    <FieldPrimitive.Description\n      data-slot=\"credit-card-description\"\n      className={cn(\n        \"m-0 text-caption font-normal text-muted-foreground group-data-disabled/credit-card:cursor-not-allowed\",\n        className\n      )}\n      {...props}\n    >\n      {content}\n    </FieldPrimitive.Description>\n  )\n}\n\nfunction CreditCardError({\n  className,\n  children,\n  match,\n  ...props\n}: React.ComponentProps<typeof FieldPrimitive.Error>) {\n  return (\n    <FieldPrimitive.Validity>\n      {(validity) => {\n        const isInvalid = validity.validity.valid === false\n        if (!isInvalid && match !== true) {\n          return null\n        }\n\n        return (\n          <FieldPrimitive.Error\n            data-slot=\"credit-card-error\"\n            match={match ?? true}\n            className={cn(\n              \"m-0 text-caption font-normal text-destructive\",\n              className\n            )}\n            {...props}\n          >\n            {children}\n          </FieldPrimitive.Error>\n        )\n      }}\n    </FieldPrimitive.Validity>\n  )\n}\n\nexport {\n  CreditCard,\n  CreditCardLabel,\n  CreditCardControl,\n  CreditCardGroup1,\n  CreditCardGroup2,\n  CreditCardGroup3,\n  CreditCardGroup4,\n  CreditCardSeparator,\n  CreditCardDescription,\n  CreditCardError,\n  formatCreditCardValue,\n  parseCreditCardValue,\n  getCreditCardBankName,\n  creditCardControlVariants,\n  creditCardSegmentVariants,\n}\nexport type { CreditCardParts, CreditCardPart }\n"
    }
  ]
}

