{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "take-a-number",
  "title": "Take a number",
  "description": "A ticket dispenser and a Now Serving sign: your place in the queue is the number in your hand. For support queues, waitlists and jobs waiting their turn.",
  "dependencies": [
    "@base-ui/react",
    "cn"
  ],
  "registryDependencies": [
    "https://bevel-ui.vercel.app/r/bevel.json",
    "https://bevel-ui.vercel.app/r/number-wheel.json"
  ],
  "files": [
    {
      "path": "registry/bevel/ui/take-a-number.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cn } from \"cn\"\nimport { NumberWheel } from \"@/components/ui/number-wheel\"\n\ntype TakeANumberContextValue = {\n  serving: number\n  ticket: number | null\n  statusId: string\n}\n\nconst TakeANumberContext = React.createContext<TakeANumberContextValue | null>(null)\n\nfunction useTakeANumber() {\n  const context = React.useContext(TakeANumberContext)\n  if (!context) throw new Error(\"TakeANumber parts must be inside <TakeANumber>\")\n  return context\n}\n\nconst ticketFormat: Intl.NumberFormatOptions = { minimumIntegerDigits: 2, useGrouping: false }\n\ntype TakeANumberProps = React.ComponentProps<\"div\"> & {\n  /** The number being served now. */\n  serving: number\n  /** The number in your hand, or null before you take one. */\n  ticket: number | null\n}\n\n/**\n * A take-a-number queue: a Now Serving sign and a ticket dispenser. Your\n * place is the number you hold. Give it an aria-label.\n */\nfunction TakeANumber({ className, serving, ticket, children, ...props }: TakeANumberProps) {\n  const statusId = React.useId()\n  const context = React.useMemo(() => ({ serving, ticket, statusId }), [serving, ticket, statusId])\n  return (\n    <TakeANumberContext value={context}>\n      <div\n        role=\"group\"\n        data-slot=\"take-a-number\"\n        data-turn={ticket === serving ? \"\" : undefined}\n        className={cn(\"flex w-full max-w-md flex-col items-center gap-5\", className)}\n        {...props}\n      >\n        {children}\n      </div>\n    </TakeANumberContext>\n  )\n}\n\n/** The Now Serving sign. Its drums roll to each new number. */\nfunction TakeANumberSign({ className, ...props }: React.ComponentProps<\"div\">) {\n  const { serving, ticket } = useTakeANumber()\n  return (\n    <div\n      data-slot=\"take-a-number-sign\"\n      className={cn(\n        \"bevel-plastic flex items-center gap-4 rounded-(--bevel-radius-md) px-5 py-3 text-(--take-a-number-foreground)\",\n        className\n      )}\n      {...props}\n    >\n      <p className=\"flex flex-col text-(length:--bevel-fine) font-black tracking-(--bevel-tracking-label) uppercase leading-tight\">\n        <span>Now</span>\n        <span>serving</span>\n      </p>\n      <NumberWheel value={serving} format={ticketFormat} tone=\"black\" className=\"text-(length:--bevel-amount)\" />\n      <span\n        aria-hidden\n        className={cn(\n          \"size-2.5 rounded-full transition-opacity duration-(--bevel-duration-small) motion-reduce:transition-none\",\n          ticket === serving ? \"bevel-led\" : \"bg-(--bevel-shade-strong)\"\n        )}\n      />\n    </div>\n  )\n}\n\n/** The dispenser. Taking a number tears a ticket off the roll; you hold one at a time. */\nfunction TakeANumberDispenser({ className, children = \"Take a number\", ...props }: ButtonPrimitive.Props) {\n  const { ticket, statusId } = useTakeANumber()\n  return (\n    <div data-slot=\"take-a-number-dispenser\" className=\"flex items-end gap-4\">\n      <div className=\"flex flex-col items-center\">\n        <span aria-hidden className=\"bevel-plastic relative z-10 flex h-14 w-20 items-end justify-center rounded-t-full pb-2\">\n          <span className=\"h-1.5 w-12 rounded-full bg-(--bevel-material-recess) shadow-(--bevel-depth-recessed)\" />\n        </span>\n        {/* The next ticket, hanging from the slot. */}\n        <span aria-hidden className=\"bevel-paper -mt-2 h-4 w-10 rounded-b-(--bevel-radius-xs)\" />\n        <ButtonPrimitive\n          disabled={ticket !== null}\n          focusableWhenDisabled\n          aria-describedby={statusId}\n          className={cn(\n            \"bevel-raised mt-3 h-10 rounded-(--bevel-radius-sm) px-4 text-sm font-semibold text-(--take-a-number-foreground) outline-none\",\n            \"transition-[translate,box-shadow] duration-(--bevel-duration-press) ease-(--bevel-ease-out) active:translate-y-0.5 active:bevel-pressed motion-reduce:transition-none\",\n            \"focus-visible:ring-3 focus-visible:ring-ring/60 data-disabled:cursor-not-allowed data-disabled:opacity-50\",\n            className\n          )}\n          {...props}\n        >\n          {children}\n        </ButtonPrimitive>\n      </div>\n      {ticket !== null && (\n        <span\n          key={ticket}\n          data-slot=\"take-a-number-ticket\"\n          className={cn(\n            \"bevel-paper mb-12 flex w-20 flex-col items-center px-1 text-center rounded-(--bevel-radius-xs) border-y-2 border-dashed border-(--bevel-paper-rule) py-2\",\n            \"transition-[translate,opacity] duration-(--bevel-duration-move) ease-(--bevel-ease-out) starting:-translate-y-(--bevel-lift) starting:opacity-0 motion-reduce:transition-none\"\n          )}\n        >\n          <span className=\"text-(length:--bevel-fine) font-bold tracking-(--bevel-tracking-label) uppercase\">Your number</span>\n          <span className=\"font-mono text-2xl font-bold tabular-nums\">\n            {ticket.toLocaleString(\"en-US\", ticketFormat)}\n          </span>\n        </span>\n      )}\n    </div>\n  )\n}\n\n/** Where you stand, in words. Announced when the number being served changes. */\nfunction TakeANumberStatus({ className, ...props }: React.ComponentProps<\"p\">) {\n  const { serving, ticket, statusId } = useTakeANumber()\n  const ahead = ticket === null ? 0 : ticket - serving\n  const message =\n    ticket === null\n      ? `Now serving ${serving}. Take a number to join the queue.`\n      : ahead > 0\n        ? `Now serving ${serving}. You're ${ticket}: ${ahead} ahead of you.`\n        : ahead === 0\n          ? `Now serving ${serving}. It's your turn.`\n          : `Number ${ticket} has been served.`\n  return (\n    <p\n      id={statusId}\n      role=\"status\"\n      data-slot=\"take-a-number-status\"\n      className={cn(\"text-center text-sm text-muted-foreground in-data-turn:font-semibold in-data-turn:text-foreground\", className)}\n      {...props}\n    >\n      {message}\n    </p>\n  )\n}\n\nexport { TakeANumber, TakeANumberSign, TakeANumberDispenser, TakeANumberStatus }\nexport type { TakeANumberProps }\n",
      "type": "registry:ui"
    }
  ],
  "css": {
    ":root": {
      "--take-a-number-red": "oklch(0.55 0.2 27)",
      "--take-a-number-red-edge": "oklch(0.38 0.15 27)",
      "--take-a-number-foreground": "oklch(0.97 0.01 90)",
      "--take-a-number-turn": "oklch(0.8 0.17 150)"
    },
    "[data-slot=\"take-a-number-sign\"], [data-slot=\"take-a-number-dispenser\"]": {
      "--bevel-material": "var(--take-a-number-red)",
      "--bevel-material-edge": "var(--take-a-number-red-edge)",
      "--bevel-material-recess": "oklch(0.16 0.01 260)",
      "--bevel-led": "var(--take-a-number-turn)"
    }
  },
  "categories": [
    "coordination"
  ],
  "type": "registry:ui"
}