{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "questionnaire",
  "title": "Questionnaire",
  "description": "A step-by-step form that moves between questions with a sense of direction, shows real progress and answers from the keyboard.",
  "dependencies": [
    "@shadcn/react@0.3.1",
    "@tabler/icons-react",
    "class-variance-authority",
    "cn"
  ],
  "registryDependencies": [
    "https://hextaui.com/r/theme.json",
    "https://hextaui.com/r/button.json",
    "https://hextaui.com/r/input.json",
    "https://hextaui.com/r/kbd.json",
    "https://hextaui.com/r/motion.json",
    "https://hextaui.com/r/number-flow.json"
  ],
  "files": [
    {
      "path": "components/ui/questionnaire.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Questionnaire as QuestionnairePrimitive } from \"@shadcn/react/questionnaire\"\nimport { IconCheck } from \"@tabler/icons-react\"\nimport { type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\n\nimport { buttonVariants } from \"@/components/ui/button\"\nimport { inputVariants } from \"@/components/ui/input\"\nimport { Kbd } from \"@/components/ui/kbd\"\nimport { NumberFlow } from \"@/components/ui/number-flow\"\nimport { easeOut, prefersReducedMotion } from \"@/lib/motion\"\n\ntype QuestionnaireTransition = \"slide\" | \"lift\"\n\nconst itemSelector = \"[data-slot=questionnaire-item]\"\n\nfunction ownItems(form: HTMLFormElement) {\n  return Array.from(form.querySelectorAll<HTMLElement>(itemSelector)).filter(\n    (item) => item.closest(\"form\") === form\n  )\n}\n\nfunction activeItem(form: HTMLFormElement) {\n  return ownItems(form).find((item) => item.hasAttribute(\"data-active\")) ?? null\n}\n\nconst leavingProperties = [\n  \"display\",\n  \"position\",\n  \"top\",\n  \"left\",\n  \"width\",\n  \"pointer-events\",\n]\n\nfunction releaseLeaving(item: HTMLElement) {\n  for (const property of leavingProperties) {\n    item.style.removeProperty(property)\n  }\n  item.removeAttribute(\"aria-hidden\")\n  item.removeAttribute(\"data-leaving\")\n}\n\nfunction releaseEntering(item: HTMLElement) {\n  item.style.removeProperty(\"overflow\")\n  item.style.removeProperty(\"overflow-clip-margin\")\n}\n\nfunction useQuestionTransition(\n  formRef: React.RefObject<HTMLFormElement | null>,\n  transition: QuestionnaireTransition,\n  onActivate: (item: HTMLElement) => void\n) {\n  const onActivateRef = React.useRef(onActivate)\n\n  React.useLayoutEffect(() => {\n    onActivateRef.current = onActivate\n  })\n\n  React.useLayoutEffect(() => {\n    const form = formRef.current\n    if (!form || typeof MutationObserver === \"undefined\") {\n      return\n    }\n\n    let active = activeItem(form)\n    if (active) {\n      onActivateRef.current(active)\n    }\n    const animations = new Set<Animation>()\n    const leaving = new Set<HTMLElement>()\n    const entering = new Set<HTMLElement>()\n\n    const settle = () => {\n      for (const animation of animations) {\n        animation.cancel()\n      }\n      animations.clear()\n      leaving.forEach(releaseLeaving)\n      leaving.clear()\n      entering.forEach(releaseEntering)\n      entering.clear()\n    }\n\n    const track = (animation: Animation, done: () => void) => {\n      animations.add(animation)\n      animation.onfinish = () => {\n        animations.delete(animation)\n        done()\n      }\n    }\n\n    const update = () => {\n      const next = activeItem(form)\n      if (next === active) {\n        return\n      }\n      const previous = active\n      active = next\n      settle()\n      if (next) {\n        onActivateRef.current(next)\n      }\n      if (\n        !previous ||\n        !next ||\n        !previous.isConnected ||\n        prefersReducedMotion() ||\n        typeof next.animate !== \"function\"\n      ) {\n        return\n      }\n\n      previous.style.setProperty(\"display\", \"flex\", \"important\")\n      previous.setAttribute(\"aria-hidden\", \"true\")\n      previous.setAttribute(\"data-leaving\", \"\")\n      const from = previous.getBoundingClientRect().height\n      previous.style.setProperty(\"position\", \"absolute\")\n      previous.style.setProperty(\"pointer-events\", \"none\")\n      const to = next.getBoundingClientRect().height\n      previous.style.setProperty(\"top\", `${next.offsetTop}px`)\n      previous.style.setProperty(\"left\", `${next.offsetLeft}px`)\n      previous.style.setProperty(\"width\", `${next.offsetWidth}px`)\n      leaving.add(previous)\n\n      const forward = Boolean(\n        previous.compareDocumentPosition(next) &\n        Node.DOCUMENT_POSITION_FOLLOWING\n      )\n      const rtl = getComputedStyle(form).direction === \"rtl\"\n      const lift = transition === \"lift\"\n      const distance = (lift ? 14 : 28) * (forward ? 1 : -1)\n      const offset = (amount: number) =>\n        lift\n          ? `translate3d(0, ${amount}px, 0)`\n          : `translate3d(${rtl ? -amount : amount}px, 0, 0)`\n\n      const exit = previous.animate(\n        [\n          { opacity: 1, transform: \"none\", filter: \"blur(0px)\" },\n          {\n            opacity: 0,\n            transform: offset(-distance),\n            filter: lift ? \"blur(2px)\" : \"blur(0px)\",\n          },\n        ],\n        {\n          duration: 180,\n          easing: \"cubic-bezier(0.4, 0, 1, 1)\",\n          fill: \"forwards\",\n        }\n      )\n      track(exit, () => {\n        leaving.delete(previous)\n        exit.cancel()\n        releaseLeaving(previous)\n      })\n\n      const enter = next.animate(\n        [\n          {\n            opacity: 0,\n            transform: offset(distance),\n            filter: lift ? \"blur(2px)\" : \"blur(0px)\",\n          },\n          { opacity: 1, transform: \"none\", filter: \"blur(0px)\" },\n        ],\n        { duration: 340, delay: 50, easing: easeOut, fill: \"backwards\" }\n      )\n      track(enter, () => undefined)\n\n      if (Math.abs(from - to) >= 1) {\n        next.style.setProperty(\"overflow\", \"clip\")\n        next.style.setProperty(\"overflow-clip-margin\", \"8px\")\n        entering.add(next)\n        const grow = next.animate(\n          [{ height: `${from}px` }, { height: `${to}px` }],\n          { duration: 340, easing: easeOut }\n        )\n        track(grow, () => {\n          entering.delete(next)\n          releaseEntering(next)\n        })\n      }\n    }\n\n    const observer = new MutationObserver(update)\n    observer.observe(form, {\n      subtree: true,\n      childList: true,\n      attributes: true,\n      attributeFilter: [\"data-active\"],\n    })\n    return () => {\n      observer.disconnect()\n      settle()\n    }\n  }, [formRef, transition])\n}\n\nfunction restartAttribute(element: Element, name: string) {\n  element.removeAttribute(name)\n  void (element as HTMLElement).offsetWidth\n  element.setAttribute(name, \"\")\n}\n\ntype QuestionnaireProps = React.ComponentProps<\n  typeof QuestionnairePrimitive.Root\n> & {\n  transition?: QuestionnaireTransition\n  autoAdvance?: boolean\n}\n\nfunction Questionnaire({\n  className,\n  transition = \"slide\",\n  autoAdvance = false,\n  onKeyDown,\n  onKeyDownCapture,\n  onKeyUp,\n  onClick,\n  onChange,\n  onMouseDown,\n  ref,\n  ...props\n}: QuestionnaireProps) {\n  const formRef = React.useRef<HTMLFormElement | null>(null)\n  const answeredOnArrival = React.useRef(new WeakMap<HTMLElement, boolean>())\n  const advanceTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n\n  const cancelAdvance = () => {\n    if (advanceTimer.current) {\n      clearTimeout(advanceTimer.current)\n      advanceTimer.current = null\n    }\n  }\n\n  useQuestionTransition(formRef, transition, (item) => {\n    cancelAdvance()\n    answeredOnArrival.current.set(\n      item,\n      item.getAttribute(\"data-status\") !== \"unanswered\"\n    )\n  })\n\n  React.useEffect(() => cancelAdvance, [])\n\n  const setRef = React.useCallback(\n    (node: HTMLFormElement | null) => {\n      formRef.current = node\n      if (typeof ref === \"function\") {\n        return ref(node)\n      }\n      if (ref) {\n        ref.current = node\n      }\n      return undefined\n    },\n    [ref]\n  )\n\n  const shakeIfInvalid = () => {\n    requestAnimationFrame(() => {\n      const form = formRef.current\n      const item = form ? activeItem(form) : null\n      if (item?.hasAttribute(\"data-invalid\") && !prefersReducedMotion()) {\n        restartAttribute(item, \"data-shake\")\n      }\n    })\n  }\n\n  const shortcutFor = (key: string) => {\n    const form = formRef.current\n    const item = form ? activeItem(form) : null\n    if (!item || key.length !== 1) {\n      return null\n    }\n    return item.querySelector<HTMLElement>(\n      `kbd[data-shortcut=\"${CSS.escape(key.toUpperCase())}\"]`\n    )\n  }\n\n  const handleKeys = (event: React.KeyboardEvent<HTMLFormElement>) => {\n    const form = formRef.current\n    const item = form ? activeItem(form) : null\n    if (!form || !item || event.defaultPrevented || event.altKey) {\n      return\n    }\n    const target = event.target as HTMLElement\n    const typing = target.matches(\n      \"input:not([type=radio]):not([type=checkbox]), textarea, select, [contenteditable=true]\"\n    )\n    if (event.metaKey || event.ctrlKey) {\n      if (event.key === \"Enter\") {\n        shakeIfInvalid()\n      }\n      return\n    }\n    const take = () => {\n      event.preventDefault()\n      event.stopPropagation()\n    }\n    const answers = Array.from(\n      item.querySelectorAll<HTMLElement>(\n        \"input[type=radio]:not(:disabled), input[type=checkbox]:not(:disabled), [data-slot=questionnaire-input]:not(:disabled)\"\n      )\n    )\n    const index = answers.indexOf(target)\n    const visible = (slot: string) =>\n      form.querySelector<HTMLElement>(`[data-slot=${slot}][data-visible]`)\n    const advance = () => {\n      const before = document.activeElement as HTMLElement | null\n      ;(\n        visible(\"questionnaire-next\") ?? visible(\"questionnaire-submit\")\n      )?.click()\n      requestAnimationFrame(() => {\n        if (\n          before &&\n          before !== document.activeElement &&\n          item.contains(before) &&\n          activeItem(form) === item &&\n          item.hasAttribute(\"data-invalid\")\n        ) {\n          before.focus()\n        }\n      })\n    }\n\n    switch (event.key) {\n      case \"ArrowDown\":\n      case \"ArrowUp\": {\n        if (target.tagName === \"TEXTAREA\" || answers.length === 0) {\n          return\n        }\n        take()\n        const step = event.key === \"ArrowDown\" ? 1 : -1\n        const next =\n          index === -1\n            ? step === 1\n              ? 0\n              : answers.length - 1\n            : Math.min(answers.length - 1, Math.max(0, index + step))\n        answers[next]?.focus()\n        return\n      }\n      case \"Home\":\n      case \"End\": {\n        if (typing || answers.length === 0) {\n          return\n        }\n        take()\n        answers[event.key === \"Home\" ? 0 : answers.length - 1]?.focus()\n        return\n      }\n      case \"ArrowLeft\":\n      case \"ArrowRight\": {\n        if (typing) {\n          return\n        }\n        take()\n        const rtl = getComputedStyle(form).direction === \"rtl\"\n        const forward = (event.key === \"ArrowRight\") !== rtl\n        if (event.repeat) {\n          return\n        }\n        if (forward) {\n          advance()\n        } else {\n          visible(\"questionnaire-previous\")?.click()\n        }\n        return\n      }\n      case \"Enter\": {\n        if (target.closest(\"button, a, textarea\")) {\n          return\n        }\n        take()\n        if (event.repeat) {\n          return\n        }\n        const input = target as HTMLInputElement\n        if (input.type === \"radio\" && !input.checked) {\n          input.click()\n          cancelAdvance()\n          setTimeout(advance, 0)\n          return\n        }\n        advance()\n        return\n      }\n      case \"Escape\": {\n        if (typing) {\n          take()\n          item.focus()\n        }\n        return\n      }\n    }\n  }\n\n  return (\n    <QuestionnairePrimitive.Root\n      ref={setRef}\n      data-slot=\"questionnaire\"\n      data-transition={transition}\n      className={cn(\n        \"group/questionnaire relative flex w-full min-w-0 flex-col gap-5\",\n        className\n      )}\n      onKeyDownCapture={(event) => {\n        onKeyDownCapture?.(event)\n        handleKeys(event)\n      }}\n      onMouseDown={(event) => {\n        onMouseDown?.(event)\n        const form = formRef.current\n        const item = form ? activeItem(form) : null\n        const target = event.target as HTMLElement\n        if (\n          !event.defaultPrevented &&\n          event.button === 0 &&\n          item &&\n          !item.contains(target) &&\n          !target.closest(\n            \"input, textarea, select, button, a, label, [contenteditable=true]\"\n          )\n        ) {\n          event.preventDefault()\n          item.focus({ preventScroll: true })\n        }\n      }}\n      onKeyDown={(event) => {\n        onKeyDown?.(event)\n        const target = event.target as HTMLElement\n        const typing = target.matches(\n          \"input:not([type=radio]):not([type=checkbox]), textarea, select\"\n        )\n        if (!typing && !event.metaKey && !event.ctrlKey && !event.altKey) {\n          shortcutFor(event.key)?.setAttribute(\"data-pressed\", \"\")\n        }\n      }}\n      onKeyUp={(event) => {\n        onKeyUp?.(event)\n        shortcutFor(event.key)?.removeAttribute(\"data-pressed\")\n      }}\n      onClick={(event) => {\n        onClick?.(event)\n        if (\n          (event.target as Element).closest(\n            \"[data-slot=questionnaire-next], [data-slot=questionnaire-submit]\"\n          )\n        ) {\n          cancelAdvance()\n          shakeIfInvalid()\n        }\n      }}\n      onChange={(event) => {\n        onChange?.(event)\n        cancelAdvance()\n        const input = event.target as unknown as HTMLInputElement\n        const form = formRef.current\n        const item = input.closest<HTMLElement>(itemSelector)\n        if (\n          !autoAdvance ||\n          !form ||\n          input.type !== \"radio\" ||\n          !input.checked ||\n          !item ||\n          item !== activeItem(form) ||\n          answeredOnArrival.current.get(item)\n        ) {\n          return\n        }\n        advanceTimer.current = setTimeout(() => {\n          advanceTimer.current = null\n          if (activeItem(form) !== item || !input.checked) {\n            return\n          }\n          form\n            .querySelector<HTMLElement>(\n              \"[data-slot=questionnaire-next][data-visible]\"\n            )\n            ?.click()\n        }, 350)\n      }}\n      {...props}\n    />\n  )\n}\n\ntype Segment = { status: string; active: boolean; invalid: boolean }\n\nfunction readSegments(form: HTMLFormElement): Segment[] {\n  return ownItems(form)\n    .filter((item) => !item.hasAttribute(\"disabled\"))\n    .map((item) => ({\n      status: item.getAttribute(\"data-status\") ?? \"unanswered\",\n      active: item.hasAttribute(\"data-active\"),\n      invalid: item.hasAttribute(\"data-invalid\"),\n    }))\n}\n\nfunction useSegments(ref: React.RefObject<HTMLElement | null>) {\n  const [segments, setSegments] = React.useState<Segment[] | null>(null)\n\n  React.useEffect(() => {\n    const form = ref.current?.closest(\"form\")\n    if (!form || typeof MutationObserver === \"undefined\") {\n      return\n    }\n    let last = \"\"\n    const read = () => {\n      const next = readSegments(form)\n      const key = JSON.stringify(next)\n      if (key !== last) {\n        last = key\n        setSegments(next)\n      }\n    }\n    read()\n    const observer = new MutationObserver(read)\n    observer.observe(form, {\n      subtree: true,\n      childList: true,\n      attributes: true,\n      attributeFilter: [\n        \"data-status\",\n        \"data-active\",\n        \"data-invalid\",\n        \"disabled\",\n      ],\n    })\n    return () => observer.disconnect()\n  }, [ref])\n\n  return segments\n}\n\ntype QuestionnaireProgressProps = React.ComponentProps<\n  typeof QuestionnairePrimitive.Progress\n> & {\n  variant?: \"segments\" | \"bar\"\n}\n\nfunction QuestionnaireProgress({\n  className,\n  variant = \"segments\",\n  ref,\n  ...props\n}: QuestionnaireProgressProps) {\n  const ownRef = React.useRef<HTMLDivElement | null>(null)\n  const segments = useSegments(ownRef)\n\n  const setRef = React.useCallback(\n    (node: HTMLDivElement | null) => {\n      ownRef.current = node\n      if (typeof ref === \"function\") {\n        return ref(node)\n      }\n      if (ref) {\n        ref.current = node\n      }\n      return undefined\n    },\n    [ref]\n  )\n\n  return (\n    <QuestionnairePrimitive.Progress\n      ref={setRef}\n      data-slot=\"questionnaire-progress\"\n      data-variant={variant}\n      className={cn(\"flex w-full min-w-0 items-center gap-3\", className)}\n      render={(renderProps, state) => {\n        const list =\n          segments && segments.length === state.total\n            ? segments\n            : Array.from({ length: state.total }, (_, index) => ({\n                status: index < state.current - 1 ? \"answered\" : \"unanswered\",\n                active: index === state.current - 1,\n                invalid: false,\n              }))\n        const done = list.filter((item) => item.status !== \"unanswered\").length\n        return (\n          <div {...renderProps}>\n            {variant === \"segments\" ? (\n              <span\n                aria-hidden=\"true\"\n                data-slot=\"questionnaire-progress-track\"\n                className=\"flex h-1 min-w-0 flex-1 gap-1\"\n              >\n                {list.map((segment, index) => (\n                  <span\n                    key={index}\n                    data-slot=\"questionnaire-progress-segment\"\n                    data-status={segment.status}\n                    data-active={segment.active ? \"\" : undefined}\n                    data-invalid={segment.invalid ? \"\" : undefined}\n                    className=\"relative min-w-0 flex-1 overflow-hidden rounded-full bg-muted transition-colors duration-300 data-invalid:bg-destructive/30 motion-reduce:transition-none data-active:bg-primary/20\"\n                  >\n                    <span className=\"absolute inset-0 origin-left scale-x-0 rounded-full bg-primary transition-[scale,background-color] duration-500 ease-out-quint in-data-[status=answered]:scale-x-100 in-data-[status=skipped]:scale-x-100 in-data-[status=skipped]:bg-muted-foreground/30 motion-reduce:transition-none rtl:origin-right\" />\n                  </span>\n                ))}\n              </span>\n            ) : (\n              <span\n                aria-hidden=\"true\"\n                data-slot=\"questionnaire-progress-track\"\n                className=\"relative h-1 min-w-0 flex-1 overflow-hidden rounded-full bg-muted\"\n              >\n                <span\n                  style={\n                    {\n                      \"--questionnaire-progress\":\n                        state.total > 0 ? done / state.total : 0,\n                    } as React.CSSProperties\n                  }\n                  className=\"absolute inset-0 origin-left scale-x-(--questionnaire-progress) rounded-full bg-primary transition-[scale] duration-500 ease-out-quint motion-reduce:transition-none rtl:origin-right\"\n                />\n              </span>\n            )}\n            <span\n              aria-hidden=\"true\"\n              data-slot=\"questionnaire-progress-label\"\n              className=\"shrink-0 text-xs font-medium text-muted-foreground tabular-nums\"\n            >\n              <span dir=\"ltr\" className=\"inline-flex gap-1\">\n                <NumberFlow value={state.current} />\n                <span className=\"text-muted-foreground/60\">/</span>\n                {state.total}\n              </span>\n            </span>\n            <span className=\"sr-only\">\n              {renderProps.children as React.ReactNode}\n            </span>\n          </div>\n        )\n      }}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireItem({\n  className,\n  onAnimationEnd,\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Item>) {\n  return (\n    <QuestionnairePrimitive.Item\n      data-slot=\"questionnaire-item\"\n      className={cn(\n        \"flex min-w-0 flex-col gap-4 border-0 p-0 outline-none focus-visible:outline-hidden data-shake:motion-safe:animate-button-shake\",\n        className\n      )}\n      onAnimationEnd={(event) => {\n        onAnimationEnd?.(event)\n        if (event.target === event.currentTarget) {\n          event.currentTarget.removeAttribute(\"data-shake\")\n        }\n      }}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Title>) {\n  return (\n    <QuestionnairePrimitive.Title\n      data-slot=\"questionnaire-title\"\n      className={cn(\n        \"mb-1.5 text-base leading-snug font-medium text-pretty wrap-break-word [&:not(:has(~[data-slot=questionnaire-description]))]:mb-4\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Description>) {\n  return (\n    <QuestionnairePrimitive.Description\n      data-slot=\"questionnaire-description\"\n      className={cn(\n        \"text-sm text-pretty wrap-break-word text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireChoices({\n  className,\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Choices>) {\n  return (\n    <QuestionnairePrimitive.Choices\n      data-slot=\"questionnaire-choices\"\n      className={cn(\"grid min-w-0 gap-2\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireChoice({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Choice>) {\n  return (\n    <QuestionnairePrimitive.Choice\n      data-slot=\"questionnaire-choice\"\n      className={cn(\n        \"group/questionnaire-choice relative flex min-h-11 min-w-0 cursor-pointer items-center gap-3 rounded-lg bg-background px-3 py-2.5 text-start text-sm inset-ring-(length:--hairline) inset-ring-border transition-[background-color,box-shadow,scale] duration-150 ease-out-cubic select-none has-data-[slot=questionnaire-choice-description]:items-start has-[>input:focus-visible]:ring-3 has-[>input:focus-visible]:ring-focus-ring has-[>input:focus-visible]:inset-ring-ring data-invalid:inset-ring-destructive/60 motion-safe:active:scale-[0.99] motion-reduce:transition-none dark:bg-input/20 forced-colors:border data-checked:bg-muted/70 data-checked:inset-ring-foreground/20 dark:data-checked:bg-muted data-disabled:pointer-events-none data-disabled:opacity-50 [@media(hover:hover)]:hover:bg-muted/50\",\n        className\n      )}\n      {...props}\n    >\n      <QuestionnairePrimitive.ChoiceInput\n        data-slot=\"questionnaire-choice-input\"\n        className=\"absolute inset-0 z-1 size-full cursor-pointer appearance-none rounded-[inherit] opacity-0 outline-none focus-visible:outline-hidden\"\n      />\n      <span\n        aria-hidden=\"true\"\n        data-slot=\"questionnaire-choice-indicator\"\n        className=\"relative flex size-4 shrink-0 items-center justify-center rounded-full bg-background inset-ring-(length:--hairline) inset-ring-input transition-[background-color,box-shadow] duration-150 group-has-data-[slot=questionnaire-choice-description]/questionnaire-choice:mt-0.5 group-data-invalid/questionnaire-choice:inset-ring-destructive group-data-[type=checkbox]/questionnaire-choice:rounded-[4px] group-data-checked/questionnaire-choice:bg-primary group-data-checked/questionnaire-choice:text-primary-foreground group-data-checked/questionnaire-choice:inset-ring-primary dark:bg-input/30 dark:group-data-checked/questionnaire-choice:bg-primary forced-colors:border\"\n      >\n        <span className=\"size-1.5 scale-0 rounded-full bg-current transition-[scale] duration-300 ease-spring group-data-[type=checkbox]/questionnaire-choice:hidden group-data-checked/questionnaire-choice:scale-100 motion-reduce:transition-none\" />\n        <IconCheck\n          stroke={3}\n          className=\"hidden size-3 opacity-0 group-data-[type=checkbox]/questionnaire-choice:block group-data-checked/questionnaire-choice:opacity-100 motion-safe:group-data-checked/questionnaire-choice:animate-checkbox-draw motion-safe:group-data-checked/questionnaire-choice:[stroke-dasharray:22] motion-safe:group-data-checked/questionnaire-choice:[stroke-dashoffset:22]\"\n        />\n      </span>\n      <QuestionnairePrimitive.ChoiceLabel\n        data-slot=\"questionnaire-choice-label\"\n        className=\"flex min-w-0 flex-1 flex-col gap-0.5 leading-snug wrap-break-word\"\n      >\n        {children}\n      </QuestionnairePrimitive.ChoiceLabel>\n      <QuestionnairePrimitive.ChoiceShortcut\n        data-slot=\"questionnaire-choice-shortcut\"\n        render={<Kbd />}\n        className=\"opacity-50 transition-opacity duration-200 group-focus-within/questionnaire:opacity-100 group-has-data-[slot=questionnaire-choice-description]/questionnaire-choice:mt-px pointer-coarse:hidden\"\n      />\n    </QuestionnairePrimitive.Choice>\n  )\n}\n\nfunction QuestionnaireChoiceDescription({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"questionnaire-choice-description\"\n      className={cn(\"text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireInput({\n  className,\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Input>) {\n  return (\n    <QuestionnairePrimitive.Input\n      data-slot=\"questionnaire-input\"\n      className={cn(\n        inputVariants({ size: \"default\" }),\n        \"h-11 sm:h-10\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireError({\n  className,\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Error>) {\n  return (\n    <QuestionnairePrimitive.Error\n      data-slot=\"questionnaire-error\"\n      className={cn(\n        \"-mt-1 text-sm text-destructive motion-safe:animate-in motion-safe:animation-duration-200 motion-safe:fade-in-0 motion-safe:slide-in-from-top-1\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction QuestionnaireActions({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"questionnaire-actions\"\n      className={cn(\n        \"grid w-full min-w-0 grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-2\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\ntype NavigationProps = Pick<\n  VariantProps<typeof buttonVariants>,\n  \"size\" | \"variant\"\n>\n\nconst navigationClassName = \"pointer-coarse:h-11\"\n\nfunction QuestionnairePrevious({\n  children,\n  className,\n  size = \"default\",\n  variant = \"ghost\",\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Previous> &\n  NavigationProps) {\n  return (\n    <QuestionnairePrimitive.Previous\n      data-slot=\"questionnaire-previous\"\n      className={cn(\n        buttonVariants({ size, variant }),\n        navigationClassName,\n        \"col-start-1 row-start-1 justify-self-start\",\n        className\n      )}\n      {...props}\n    >\n      {children ?? \"Previous\"}\n    </QuestionnairePrimitive.Previous>\n  )\n}\n\nfunction QuestionnaireSkip({\n  children,\n  className,\n  size = \"default\",\n  variant = \"ghost\",\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Skip> & NavigationProps) {\n  return (\n    <QuestionnairePrimitive.Skip\n      data-slot=\"questionnaire-skip\"\n      className={cn(\n        buttonVariants({ size, variant }),\n        navigationClassName,\n        \"col-start-2 row-start-1 text-muted-foreground\",\n        className\n      )}\n      {...props}\n    >\n      {children ?? \"Skip\"}\n    </QuestionnairePrimitive.Skip>\n  )\n}\n\nfunction QuestionnaireNext({\n  children,\n  className,\n  size = \"default\",\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Next> & NavigationProps) {\n  return (\n    <QuestionnairePrimitive.Next\n      data-slot=\"questionnaire-next\"\n      className={cn(\n        buttonVariants({ size, variant }),\n        navigationClassName,\n        \"col-start-3 row-start-1 min-w-20 justify-self-end\",\n        className\n      )}\n      {...props}\n    >\n      {children ?? \"Next\"}\n    </QuestionnairePrimitive.Next>\n  )\n}\n\nfunction QuestionnaireSubmit({\n  children,\n  className,\n  size = \"default\",\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof QuestionnairePrimitive.Submit> &\n  NavigationProps) {\n  return (\n    <QuestionnairePrimitive.Submit\n      data-slot=\"questionnaire-submit\"\n      className={cn(\n        buttonVariants({ size, variant }),\n        navigationClassName,\n        \"col-start-3 row-start-1 min-w-20 justify-self-end\",\n        className\n      )}\n      {...props}\n    >\n      {children ?? \"Submit\"}\n    </QuestionnairePrimitive.Submit>\n  )\n}\n\nexport {\n  Questionnaire,\n  QuestionnaireActions,\n  QuestionnaireChoice,\n  QuestionnaireChoiceDescription,\n  QuestionnaireChoices,\n  QuestionnaireDescription,\n  QuestionnaireError,\n  QuestionnaireInput,\n  QuestionnaireItem,\n  QuestionnaireNext,\n  QuestionnairePrevious,\n  QuestionnaireProgress,\n  QuestionnaireSkip,\n  QuestionnaireSubmit,\n  QuestionnaireTitle,\n}\nexport type {\n  QuestionnaireProgressProps,\n  QuestionnaireProps,\n  QuestionnaireTransition,\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}