{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "questionnaire",
  "title": "Questionnaire",
  "description": "Questions asked one at a time, with choices, a freeform answer and skips, on shadcn's questionnaire.",
  "dependencies": [
    "@hugeicons/core-free-icons",
    "@hugeicons/react",
    "@shadcn/react",
    "@stylexjs/stylex"
  ],
  "registryDependencies": [
    "https://constella.aayush.cv/r/base.json",
    "https://constella.aayush.cv/r/button.json",
    "https://constella.aayush.cv/r/input.json",
    "https://constella.aayush.cv/r/kbd.json"
  ],
  "files": [
    {
      "path": "src/components/ai/questionnaire.tsx",
      "content": "\"use client\";\n\nimport { Tick02Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { Questionnaire as QuestionnairePrimitive } from \"@shadcn/react/questionnaire\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport type { ComponentProps } from \"react\";\n\nimport { buttonStyles } from \"@/components/primitives/button\";\nimport type { ButtonStyleOptions } from \"@/components/primitives/button\";\nimport { Input } from \"@/components/primitives/input\";\nimport { Kbd } from \"@/components/primitives/kbd\";\nimport type { Sx } from \"@/lib/constella/styles\";\nimport { typeStyles } from \"@/lib/constella/styles\";\nimport {\n  colors,\n  durations,\n  easings,\n  fontWeights,\n  lineHeights,\n  media,\n  motion,\n  opacities,\n  radii,\n  shadows,\n  sizes,\n  space,\n  strokes,\n} from \"@/lib/constella/tokens.stylex\";\n\ntype Styled<T> = Omit<T, \"className\" | \"style\"> & {\n  sx?: Sx;\n};\n\ntype NavigationProps<T> = Styled<T> &\n  Pick<ButtonStyleOptions, \"size\" | \"variant\">;\n\n// The primitive hides inactive items and unused buttons with `hidden`, which any `display` overrides.\nconst hidden = \":is([hidden])\";\nconst checked = \":is([data-checked] *)\";\nconst radio = \":is([data-type='radio'] *)\";\nconst invalid = \":is([data-invalid])\";\nconst disabled = \":is([data-disabled])\";\nconst firstLineInset = `calc((${lineHeights.textSm} - ${sizes.icon}) / 2)`;\nconst noDescription = \":not(:has(~ [data-slot='questionnaire-description']))\";\n\nconst styles = stylex.create({\n  root: {\n    display: \"flex\",\n    flexDirection: \"column\",\n    gap: space.md,\n    marginBlockEnd: 0,\n    marginBlockStart: 0,\n    marginInlineEnd: 0,\n    marginInlineStart: 0,\n    minWidth: 0,\n    width: \"100%\",\n  },\n  progress: {\n    color: colors.textSecondary,\n    fontVariantNumeric: \"tabular-nums\",\n    fontWeight: fontWeights.medium,\n    minHeight: lineHeights.textSm,\n  },\n  item: {\n    borderBlockStartWidth: 0,\n    borderBlockEndWidth: 0,\n    borderInlineStartWidth: 0,\n    borderInlineEndWidth: 0,\n    display: { default: \"flex\", [hidden]: \"none\" },\n    flexDirection: \"column\",\n    gap: space.md,\n    marginBlockEnd: 0,\n    marginBlockStart: 0,\n    marginInlineEnd: 0,\n    marginInlineStart: 0,\n    minWidth: 0,\n    paddingBlockStart: 0,\n    paddingBlockEnd: 0,\n    paddingInlineStart: 0,\n    paddingInlineEnd: 0,\n  },\n  // A legend sits outside the fieldset's flex gap, so it spaces itself.\n  title: {\n    color: colors.textPrimary,\n    fontWeight: fontWeights.medium,\n    marginBlockEnd: { default: space.xxs, [noDescription]: space.md },\n    paddingBlockStart: 0,\n    paddingBlockEnd: 0,\n    paddingInlineStart: 0,\n    paddingInlineEnd: 0,\n    textWrap: \"pretty\",\n  },\n  description: {\n    color: colors.textSecondary,\n    marginBlockEnd: 0,\n    marginBlockStart: 0,\n    marginInlineEnd: 0,\n    marginInlineStart: 0,\n    textWrap: \"pretty\",\n  },\n  choices: {\n    display: \"grid\",\n    gap: space.xs,\n    minWidth: 0,\n  },\n  choice: {\n    alignItems: \"flex-start\",\n    backgroundColor: {\n      default: \"transparent\",\n      \":is([data-checked])\": colors.fillSubtle,\n      [media.hover]: {\n        default: \"transparent\",\n        \":hover:not([data-disabled])\": colors.fillSubtle,\n        \":is([data-checked])\": colors.fillSubtle,\n      },\n      \":active:not([data-disabled])\": colors.fillSubtle,\n    },\n    borderBlockStartColor: {\n      default: colors.border,\n      \":is([data-checked]):not([data-invalid])\": colors.infoSolid,\n      [invalid]: colors.dangerBorder,\n    },\n    borderBlockEndColor: {\n      default: colors.border,\n      \":is([data-checked]):not([data-invalid])\": colors.infoSolid,\n      [invalid]: colors.dangerBorder,\n    },\n    borderInlineStartColor: {\n      default: colors.border,\n      \":is([data-checked]):not([data-invalid])\": colors.infoSolid,\n      [invalid]: colors.dangerBorder,\n    },\n    borderInlineEndColor: {\n      default: colors.border,\n      \":is([data-checked]):not([data-invalid])\": colors.infoSolid,\n      [invalid]: colors.dangerBorder,\n    },\n    borderStartStartRadius: radii.md,\n    borderStartEndRadius: radii.md,\n    borderEndStartRadius: radii.md,\n    borderEndEndRadius: radii.md,\n    borderBlockStartStyle: \"solid\",\n    borderBlockEndStyle: \"solid\",\n    borderInlineStartStyle: \"solid\",\n    borderInlineEndStyle: \"solid\",\n    borderBlockStartWidth: strokes.border,\n    borderBlockEndWidth: strokes.border,\n    borderInlineStartWidth: strokes.border,\n    borderInlineEndWidth: strokes.border,\n    color: colors.textPrimary,\n    cursor: { default: \"pointer\", [disabled]: \"not-allowed\" },\n    display: \"flex\",\n    gap: space.sm,\n    minWidth: 0,\n    opacity: { default: 1, [disabled]: opacities.disabled },\n    paddingBlockStart: space.sm,\n    paddingBlockEnd: space.sm,\n    paddingInlineStart: space.sm,\n    paddingInlineEnd: space.sm,\n    position: \"relative\",\n    textAlign: \"start\",\n    transitionDuration: durations.hover,\n    transitionProperty: \"background-color, border-color\",\n    transitionTimingFunction: \"ease\",\n    userSelect: \"none\",\n  },\n  choiceInput: {\n    cursor: \"inherit\",\n    height: \"100%\",\n    insetBlockStart: 0,\n    insetInlineStart: 0,\n    marginBlockEnd: 0,\n    marginBlockStart: 0,\n    marginInlineEnd: 0,\n    marginInlineStart: 0,\n    opacity: 0,\n    position: \"absolute\",\n    width: \"100%\",\n    zIndex: 1,\n  },\n  // Checkbox's box, or Radio's circle; the primitive needs a native input, so neither component fits.\n  indicator: {\n    alignItems: \"center\",\n    backgroundClip: { default: \"padding-box\", [checked]: \"border-box\" },\n    backgroundColor: {\n      default: colors.fillSubtle,\n      [checked]: colors.infoSolid,\n    },\n    borderBlockStartColor: {\n      default: colors.border,\n      [checked]: colors.infoSolid,\n    },\n    borderBlockEndColor: {\n      default: colors.border,\n      [checked]: colors.infoSolid,\n    },\n    borderInlineStartColor: {\n      default: colors.border,\n      [checked]: colors.infoSolid,\n    },\n    borderInlineEndColor: {\n      default: colors.border,\n      [checked]: colors.infoSolid,\n    },\n    borderStartStartRadius: { default: radii.xs, [radio]: radii.full },\n    borderStartEndRadius: { default: radii.xs, [radio]: radii.full },\n    borderEndStartRadius: { default: radii.xs, [radio]: radii.full },\n    borderEndEndRadius: { default: radii.xs, [radio]: radii.full },\n    borderBlockStartStyle: \"solid\",\n    borderBlockEndStyle: \"solid\",\n    borderInlineStartStyle: \"solid\",\n    borderInlineEndStyle: \"solid\",\n    borderBlockStartWidth: strokes.border,\n    borderBlockEndWidth: strokes.border,\n    borderInlineStartWidth: strokes.border,\n    borderInlineEndWidth: strokes.border,\n    boxShadow: shadows.default,\n    color: colors.infoOnSolid,\n    display: \"flex\",\n    flexShrink: 0,\n    height: sizes.icon,\n    justifyContent: \"center\",\n    marginBlockEnd: firstLineInset,\n    marginBlockStart: firstLineInset,\n    transitionDuration: durations.hover,\n    transitionProperty: \"background-color, border-color\",\n    transitionTimingFunction: \"ease\",\n    width: sizes.icon,\n  },\n  // The tick draws in from its start; unchecking is the system answering, so it's quick.\n  tick: {\n    clipPath: { default: \"inset(0 100% 0 0)\", [checked]: \"inset(0)\" },\n    display: { default: \"block\", [radio]: \"none\" },\n    opacity: { default: 0, [checked]: 1 },\n    transitionDuration: { default: durations.hover, [checked]: durations.move },\n    transitionProperty: {\n      default: \"clip-path, opacity\",\n      [media.reducedMotion]: \"opacity\",\n    },\n    transitionTimingFunction: easings.out,\n  },\n  dot: {\n    backgroundColor: colors.infoOnSolid,\n    borderStartStartRadius: radii.full,\n    borderStartEndRadius: radii.full,\n    borderEndStartRadius: radii.full,\n    borderEndEndRadius: radii.full,\n    display: { default: \"none\", [radio]: \"block\" },\n    height: `calc(${sizes.icon} / 2)`,\n    opacity: { default: 0, [checked]: 1 },\n    transform: { default: `scale(${motion.dotScale})`, [checked]: \"scale(1)\" },\n    transitionDuration: durations.popover,\n    transitionProperty: {\n      default: \"transform, opacity\",\n      [media.reducedMotion]: \"opacity\",\n    },\n    transitionTimingFunction: `${easings.overshoot}, ${easings.out}`,\n    width: `calc(${sizes.icon} / 2)`,\n  },\n  choiceLabel: {\n    display: \"flex\",\n    flexDirection: \"column\",\n    flexGrow: 1,\n    fontWeight: fontWeights.medium,\n    gap: space.xxxs,\n    minWidth: 0,\n    overflowWrap: \"anywhere\",\n  },\n  choiceDescription: {\n    color: colors.textSecondary,\n    fontWeight: fontWeights.regular,\n  },\n  shortcut: {\n    display: { default: \"inline-flex\", [hidden]: \"none\" },\n    flexShrink: 0,\n    marginInlineStart: \"auto\",\n  },\n  error: {\n    color: colors.dangerText,\n    marginBlockEnd: 0,\n    marginBlockStart: 0,\n    marginInlineEnd: 0,\n    marginInlineStart: 0,\n    overflowWrap: \"anywhere\",\n  },\n  actions: {\n    alignItems: \"center\",\n    display: \"grid\",\n    gap: space.xs,\n    gridTemplateColumns: \"minmax(0, 1fr) auto auto\",\n    justifyItems: \"start\",\n    minHeight: sizes.controlMd,\n    width: \"100%\",\n  },\n  navigation: {\n    display: { default: \"inline-flex\", [hidden]: \"none\" },\n    gridRowStart: 1,\n  },\n  previous: { gridColumnStart: 1, justifySelf: \"start\" },\n  skip: { gridColumnStart: 2, justifySelf: \"end\" },\n  forward: { gridColumnStart: 3, justifySelf: \"end\" },\n});\n\nfunction Questionnaire({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Root>>) {\n  return (\n    <QuestionnairePrimitive.Root\n      data-slot=\"questionnaire\"\n      {...props}\n      {...stylex.props(styles.root, sx)}\n    />\n  );\n}\n\nfunction QuestionnaireProgress({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Progress>>) {\n  return (\n    <QuestionnairePrimitive.Progress\n      data-slot=\"questionnaire-progress\"\n      {...props}\n      {...stylex.props([typeStyles.textSm, styles.progress], sx)}\n    />\n  );\n}\n\nfunction QuestionnaireItem({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Item>>) {\n  return (\n    <QuestionnairePrimitive.Item\n      data-slot=\"questionnaire-item\"\n      {...props}\n      {...stylex.props(styles.item, sx)}\n    />\n  );\n}\n\nfunction QuestionnaireTitle({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Title>>) {\n  return (\n    <QuestionnairePrimitive.Title\n      data-slot=\"questionnaire-title\"\n      {...props}\n      {...stylex.props([typeStyles.textBase, styles.title], sx)}\n    />\n  );\n}\n\nfunction QuestionnaireDescription({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Description>>) {\n  return (\n    <QuestionnairePrimitive.Description\n      data-slot=\"questionnaire-description\"\n      {...props}\n      {...stylex.props([typeStyles.textSm, styles.description], sx)}\n    />\n  );\n}\n\nfunction QuestionnaireChoices({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Choices>>) {\n  return (\n    <QuestionnairePrimitive.Choices\n      data-slot=\"questionnaire-choices\"\n      {...props}\n      {...stylex.props(styles.choices, sx)}\n    />\n  );\n}\n\nfunction QuestionnaireChoice({\n  children,\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Choice>>) {\n  return (\n    <QuestionnairePrimitive.Choice\n      data-slot=\"questionnaire-choice\"\n      {...props}\n      {...stylex.props([typeStyles.textSm, styles.choice], sx)}\n    >\n      <QuestionnairePrimitive.ChoiceInput\n        data-slot=\"questionnaire-choice-input\"\n        {...stylex.props(styles.choiceInput)}\n      />\n      <span\n        aria-hidden\n        data-slot=\"questionnaire-choice-indicator\"\n        {...stylex.props(styles.indicator)}\n      >\n        <HugeiconsIcon\n          aria-hidden\n          icon={Tick02Icon}\n          size={sizes.iconSm}\n          strokeWidth={Number(strokes.icon)}\n          {...stylex.props(styles.tick)}\n        />\n        <span {...stylex.props(styles.dot)} />\n      </span>\n      <QuestionnairePrimitive.ChoiceLabel\n        data-slot=\"questionnaire-choice-label\"\n        {...stylex.props(styles.choiceLabel)}\n      >\n        {children}\n      </QuestionnairePrimitive.ChoiceLabel>\n      <QuestionnairePrimitive.ChoiceShortcut\n        data-slot=\"questionnaire-choice-shortcut\"\n        render={<Kbd sx={styles.shortcut} />}\n      />\n    </QuestionnairePrimitive.Choice>\n  );\n}\n\nfunction QuestionnaireChoiceDescription({\n  sx,\n  ...props\n}: Styled<ComponentProps<\"span\">>) {\n  return (\n    <span\n      data-slot=\"questionnaire-choice-description\"\n      {...props}\n      {...stylex.props(styles.choiceDescription, sx)}\n    />\n  );\n}\n\nfunction QuestionnaireInput({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Input>>) {\n  return <QuestionnairePrimitive.Input {...props} render={<Input sx={sx} />} />;\n}\n\nfunction QuestionnaireError({\n  sx,\n  ...props\n}: Styled<ComponentProps<typeof QuestionnairePrimitive.Error>>) {\n  return (\n    <QuestionnairePrimitive.Error\n      data-slot=\"questionnaire-error\"\n      {...props}\n      {...stylex.props([typeStyles.textSm, styles.error], sx)}\n    />\n  );\n}\n\nfunction QuestionnaireActions({ sx, ...props }: Styled<ComponentProps<\"div\">>) {\n  return (\n    <div\n      data-slot=\"questionnaire-actions\"\n      {...props}\n      {...stylex.props(styles.actions, sx)}\n    />\n  );\n}\n\nfunction QuestionnairePrevious({\n  children = \"Previous\",\n  size = \"default\",\n  sx,\n  variant = \"outline\",\n  ...props\n}: NavigationProps<ComponentProps<typeof QuestionnairePrimitive.Previous>>) {\n  return (\n    <QuestionnairePrimitive.Previous\n      data-size={size}\n      data-slot=\"questionnaire-previous\"\n      data-variant={variant}\n      {...props}\n      {...stylex.props(\n        buttonStyles({ size, variant }),\n        styles.navigation,\n        styles.previous,\n        sx\n      )}\n    >\n      {children}\n    </QuestionnairePrimitive.Previous>\n  );\n}\n\nfunction QuestionnaireSkip({\n  children = \"Skip\",\n  size = \"default\",\n  sx,\n  variant = \"outline\",\n  ...props\n}: NavigationProps<ComponentProps<typeof QuestionnairePrimitive.Skip>>) {\n  return (\n    <QuestionnairePrimitive.Skip\n      data-size={size}\n      data-slot=\"questionnaire-skip\"\n      data-variant={variant}\n      {...props}\n      {...stylex.props(\n        buttonStyles({ size, variant }),\n        styles.navigation,\n        styles.skip,\n        sx\n      )}\n    >\n      {children}\n    </QuestionnairePrimitive.Skip>\n  );\n}\n\nfunction QuestionnaireNext({\n  children = \"Next\",\n  size = \"default\",\n  sx,\n  variant = \"primary\",\n  ...props\n}: NavigationProps<ComponentProps<typeof QuestionnairePrimitive.Next>>) {\n  return (\n    <QuestionnairePrimitive.Next\n      data-size={size}\n      data-slot=\"questionnaire-next\"\n      data-variant={variant}\n      {...props}\n      {...stylex.props(\n        buttonStyles({ size, variant }),\n        styles.navigation,\n        styles.forward,\n        sx\n      )}\n    >\n      {children}\n    </QuestionnairePrimitive.Next>\n  );\n}\n\nfunction QuestionnaireSubmit({\n  children = \"Submit\",\n  size = \"default\",\n  sx,\n  variant = \"primary\",\n  ...props\n}: NavigationProps<ComponentProps<typeof QuestionnairePrimitive.Submit>>) {\n  return (\n    <QuestionnairePrimitive.Submit\n      data-size={size}\n      data-slot=\"questionnaire-submit\"\n      data-variant={variant}\n      {...props}\n      {...stylex.props(\n        buttonStyles({ size, variant }),\n        styles.navigation,\n        styles.forward,\n        sx\n      )}\n    >\n      {children}\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  QuestionnaireChoiceDefinition,\n  QuestionnaireItemDefinition,\n  QuestionnaireItemStatus,\n  QuestionnaireShortcutMode,\n} from \"@shadcn/react/questionnaire\";\n",
      "type": "registry:component"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/questionnaire/index.md",
  "type": "registry:ui"
}