{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "label",
  "type": "registry:component",
  "title": "Label",
  "description": "The name of a field, with its required mark, a hint and an action on one line.",
  "dependencies": [
    "@base-ui/react",
    "tailwind-variants"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/panelui/label.tsx",
      "type": "registry:component",
      "target": "@components/panelui/label.tsx",
      "content": "'use client';\n\n/**\n * Label — the name of a field, and the line it sits on.\n *\n * ```tsx\n * <Label htmlFor=\"email\" required>Email</Label>\n * <Input id=\"email\" type=\"email\" required />\n *\n * <Label htmlFor=\"password\">\n *   <Label.Text>Password</Label.Text>\n *   <Label.Action><a href=\"/reset\">Forgot it?</a></Label.Action>\n * </Label>\n * ```\n *\n * ## One line, three things on it\n *\n * A field's label is rarely only its name. It says whether the field must be\n * filled, it carries a hint (a limit, a format, \"Optional\"), and it often has\n * something at the far end: a link to reset a password, a count of what is\n * left. Putting those on the label's own line, rather than in lines of their\n * own round the field, keeps a form to one row per field, and keeps the hint\n * next to the name it qualifies.\n *\n * ## The control decides, where it can\n *\n * A label wrapped round its control, such as a checkbox, reads that control's\n * state: it fades when the control is disabled and turns to the destructive\n * colour when the control is invalid, with nothing passed. A label tied to its\n * control by `htmlFor` cannot see it, so it takes `invalid` and `disabled`.\n *\n * ## It renders on the server\n *\n * The state reaches the parts through data attributes and CSS rather than\n * through context, so a label has no client JavaScript of its own.\n */\nimport type { ComponentProps } from 'react';\nimport { tv } from 'tailwind-variants';\nimport { mergeProps } from '@base-ui/react/merge-props';\nimport { useRender } from '@base-ui/react/use-render';\nimport type { ElementType as RenderElementType } from 'react';\n\n/** Draws a part as another element, or composes it with a component: `render={<a href=\"/\" />}`. */\ntype RenderProp<Tag extends RenderElementType> = { render?: useRender.ComponentProps<Tag>['render'] };\n\nconst labelVariants = tv({\n  slots: {\n    root: [\n      'group/label flex w-full min-w-0 items-center gap-2 text-sm font-medium leading-5 text-foreground select-none',\n      // A control wrapped in the label tells it how it is.\n      'has-disabled:cursor-not-allowed has-disabled:opacity-50 has-[[aria-invalid=true]]:text-destructive',\n      'data-disabled:cursor-not-allowed data-disabled:opacity-50 data-invalid:text-destructive',\n    ],\n    // The required mark is drawn after the text by CSS, so it follows the name\n    // however the label is composed, and is not read out as \"star\".\n    text: [\n      'flex min-w-0 items-baseline',\n      \"group-data-required/label:after:ms-0.5 group-data-required/label:after:text-destructive group-data-required/label:after:content-['*']\",\n    ],\n    textInner: 'min-w-0 truncate',\n    hint: [\n      'shrink-0 font-normal text-muted-foreground',\n      // An invalid field's hint is the reason, so it takes the colour too.\n      'group-data-invalid/label:text-destructive group-has-[[aria-invalid=true]]/label:text-destructive',\n    ],\n    action: [\n      'order-last ms-auto flex shrink-0 items-center gap-1.5 font-normal text-muted-foreground',\n      '[&_a]:text-foreground [&_a]:underline-offset-4 [&_a]:outline-none [&_a:hover]:underline [&_a:focus-visible]:underline',\n      'group-data-invalid/label:text-destructive',\n    ],\n  },\n});\n\nexport interface LabelProps extends ComponentProps<'label'> {\n  /**\n   * Marks the field as one that must be filled. The mark is for the eye; set\n   * `required` on the control as well, which is what a screen reader announces.\n   */\n  required?: boolean;\n  /** Shows \"Optional\" after the text, for a form where most fields are required. */\n  optional?: boolean;\n  /**\n   * Turns the label to the destructive colour. Needed when the label is tied\n   * to its control by `htmlFor`; a label wrapped round its control reads it.\n   */\n  invalid?: boolean;\n  /** Fades the label. As with `invalid`, a wrapped control is read on its own. */\n  disabled?: boolean;\n}\n\n/**\n * The label element. A string child is the label's text; for more, compose\n * `Label.Text`, `Label.Hint` and `Label.Action`.\n */\nfunction LabelRoot({\n  required = false,\n  optional = false,\n  invalid = false,\n  disabled = false,\n  className,\n  children,\n  render,\n  ...props\n}: LabelProps & RenderProp<'label'>) {\n  const slots = labelVariants();\n  const plain = typeof children === 'string' || typeof children === 'number';\n  return useRender({\n    defaultTagName: 'label',\n    render,\n    props: mergeProps(\n      {\n        'data-slot': 'label',\n        'data-required': required ? '' : undefined,\n        'data-invalid': invalid ? '' : undefined,\n        'data-disabled': disabled ? '' : undefined,\n        className: slots.root({ className }),\n        children: (\n          <>\n            {plain ? <LabelText>{children}</LabelText> : children}\n            {optional ? <LabelHint>Optional</LabelHint> : null}\n          </>\n        ),\n      },\n      props\n    ),\n  });\n}\nLabelRoot.displayName = 'Label';\n\nexport interface LabelTextProps extends ComponentProps<'span'> {}\n\n/** The field's name. It truncates rather than pushing the action off the line. */\nfunction LabelText({ className, children, render, ...props }: LabelTextProps & RenderProp<'span'>) {\n  const slots = labelVariants();\n  return useRender({\n    defaultTagName: 'span',\n    render,\n    props: mergeProps(\n      {\n        'data-slot': 'label-text',\n        className: slots.text({ className }),\n        children: (\n          <>\n            <span className={slots.textInner()}>{children}</span>\n          </>\n        ),\n      },\n      props\n    ),\n  });\n}\nLabelText.displayName = 'Label.Text';\n\nexport interface LabelHintProps extends ComponentProps<'span'> {}\n\n/**\n * A quieter word or two after the name: a limit, a format, a unit. On an\n * invalid field it takes the destructive colour, so it can say what is wrong.\n */\nfunction LabelHint({ className, render, ...props }: LabelHintProps & RenderProp<'span'>) {\n  return useRender({\n    defaultTagName: 'span',\n    render,\n    props: mergeProps({ 'data-slot': 'label-hint', className: labelVariants().hint({ className }) }, props),\n  });\n}\nLabelHint.displayName = 'Label.Hint';\n\nexport interface LabelActionProps extends ComponentProps<'span'> {}\n\n/** Pushed to the far end of the line: a link, a count, a small button. */\nfunction LabelAction({ className, render, ...props }: LabelActionProps & RenderProp<'span'>) {\n  return useRender({\n    defaultTagName: 'span',\n    render,\n    props: mergeProps({ 'data-slot': 'label-action', className: labelVariants().action({ className }) }, props),\n  });\n}\nLabelAction.displayName = 'Label.Action';\n\nexport const Label = Object.assign(LabelRoot, {\n  Text: LabelText,\n  Hint: LabelHint,\n  Action: LabelAction,\n});\n\nexport { LabelText, LabelHint, LabelAction };\n"
    }
  ]
}
