{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "core-control-label",
  "type": "registry:ui",
  "title": "Control Label",
  "description": "A shared caption/readout wrapper with optional bounded text fitting, narrow typography and ellipsis inside a designer-owned width.",
  "dependencies": [
    "maruaudio@>=0.0.3 <0.1.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/ui/control-label.tsx",
      "content": "/**\n * Source: https://maru.audio/ui-kit/control-label\n * Copyright © [Maru](https://maru.audio)\n *\n * Maru UI Kit — https://maru.audio/ui-kit\n *\n * Installed from the Maru UI registry. This file is yours now: edit it\n * freely, it will not be overwritten unless you re-run the add command.\n *\n * Keep this item’s companion files and CSS imports together. Dependencies\n * declared by the registry are installed with the source.\n */\n/**\n * The caption and readout that sit around a control.\n *\n * Pulled out so Knob, Fader and XYPad label themselves identically, and so a\n * custom control you write yourself lands in the same visual rhythm.\n */\n\nimport { useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from \"react\"\nimport type { ComponentProps, CSSProperties, ReactNode } from \"react\"\nimport { controlValueCandidates, formatControlValueLabel, splitFormattedValue } from \"maruaudio/ui/shared/format\"\nimport { token } from \"maruaudio/ui/shared/theme\"\nimport { fitControlLabel, type ControlLabelFit } from \"maruaudio/ui/shared/control-label-fit\"\n\nconst useBrowserLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect\n\nexport interface ControlTextBoundaryProps extends ComponentProps<\"span\"> {\n  /** Fit plain text within readable bounds; long strings still ellipsize. */\n  compressible?: boolean\n  /** A condensed treatment of the inherited font, without loading another font. */\n  narrow?: boolean\n}\n\n/**\n * Default text boundary for control captions and readouts. The containing\n * layout supplies the available width; these rules keep text inside it.\n */\nexport const CONTROL_TEXT_BOUNDARY_STYLE: CSSProperties = {\n  display: \"block\",\n  boxSizing: \"border-box\",\n  maxWidth: \"100%\",\n  minWidth: 0,\n  overflow: \"hidden\",\n  textOverflow: \"ellipsis\",\n  whiteSpace: \"nowrap\",\n}\n\n/** Apply the shared truncation boundary while allowing a control to style it. */\nexport function controlTextBoundaryStyle(\n  style?: CSSProperties\n): CSSProperties {\n  return { ...CONTROL_TEXT_BOUNDARY_STYLE, ...style }\n}\n\n/**\n * A bounded single-line text span for control labels, values, and other small\n * control UI. Place it inside a width-constrained parent; it will truncate\n * instead of widening that parent.\n */\nexport function ControlTextBoundary({\n  style,\n  children,\n  compressible = false,\n  narrow = false,\n  ...props\n}: ControlTextBoundaryProps) {\n  const text = typeof children === \"string\" || typeof children === \"number\" ? String(children) : null\n  if (text !== null && (compressible || narrow)) {\n    return <FittedControlText {...props} style={style} compressible={compressible} narrow={narrow} text={text} />\n  }\n  return <span {...props} style={controlTextBoundaryStyle(style)}>{children}</span>\n}\n\n/** Measuring an uncompressed probe avoids resize loops and also catches font changes. */\nfunction FittedControlText({ text, compressible, narrow, style, ref, ...props }: Omit<ControlTextBoundaryProps, \"children\"> & { text: string }) {\n  const boundary = useRef<HTMLSpanElement>(null)\n  const probe = useRef<HTMLSpanElement>(null)\n  useImperativeHandle(ref, () => boundary.current!, [])\n  const [fit, setFit] = useState<ControlLabelFit>(() => fitControlLabel({ availableWidth: 0, textWidth: 0, characters: 0, narrow }))\n  useBrowserLayoutEffect(() => {\n    const element = boundary.current\n    const measure = probe.current\n    if (!element || !measure) return\n    const view = element.ownerDocument.defaultView\n    if (!view) return\n    const update = () => {\n      const css = view.getComputedStyle(element)\n      // Layout pixels, not transformed viewport pixels: zoomed module faces fit identically.\n      const width = element.clientWidth - (parseFloat(css.paddingLeft) || 0) - (parseFloat(css.paddingRight) || 0)\n      const next = fitControlLabel({\n        availableWidth: compressible ? Math.max(0, width - 1) : 0,\n        textWidth: measure.scrollWidth,\n        characters: Array.from(text).length,\n        letterSpacing: parseFloat(css.letterSpacing) || 0,\n        narrow,\n      })\n      setFit((previous) => Object.keys(next).every((key) => previous[key as keyof ControlLabelFit] === next[key as keyof ControlLabelFit]) ? previous : next)\n    }\n    update()\n    const observer = typeof view.ResizeObserver === \"function\" ? new view.ResizeObserver(update) : undefined\n    observer?.observe(element)\n    observer?.observe(measure)\n    element.ownerDocument.fonts?.addEventListener(\"loadingdone\", update)\n    return () => {\n      observer?.disconnect()\n      element.ownerDocument.fonts?.removeEventListener(\"loadingdone\", update)\n    }\n  }, [text, compressible, narrow, style, props.className])\n  return (\n    <span {...props} ref={boundary} data-control-label-fit={fit.truncated ? \"ellipsis\" : \"fit\"}\n      style={{ ...controlTextBoundaryStyle(style), position: style?.position ?? \"relative\" }}>\n      <span ref={probe} aria-hidden=\"true\" style={{ position: \"absolute\", visibility: \"hidden\", pointerEvents: \"none\", width: \"max-content\", maxWidth: \"none\", whiteSpace: \"pre\", letterSpacing: 0, insetInlineStart: 0, top: 0 }}>{text}</span>\n      <span data-control-label-text=\"\" style={{ display: \"block\", width: `${100 / fit.widthScale}%`, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", fontSize: `${fit.fontScale}em`, letterSpacing: fit.letterSpacing, transform: `scaleX(${fit.widthScale})`, transformOrigin: \"left center\" }}>{text}</span>\n    </span>\n  )\n}\n\nexport interface ControlLabelProps {\n  /** Caption above the control, e.g. \"Cutoff\". */\n  label?: ReactNode\n  /** Formatted readout below the control, e.g. \"2.18 kHz\". */\n  value?: ReactNode\n  /** The control itself. */\n  children: ReactNode\n  /** Horizontal layout puts the caption to the left instead of above. */\n  orientation?: \"vertical\" | \"horizontal\"\n  /** Width applied to the wrapper — keeps a row of knobs on a tidy grid. */\n  width?: number | string\n  style?: CSSProperties\n  className?: string\n  /** Wired to the control's `aria-labelledby`. */\n  labelId?: string\n  compressible?: boolean\n  narrow?: boolean\n}\n\nexport function ControlLabel({\n  label,\n  value,\n  children,\n  orientation = \"vertical\",\n  width,\n  style,\n  className,\n  labelId,\n  compressible = false,\n  narrow = false,\n}: ControlLabelProps) {\n  const vertical = orientation === \"vertical\"\n\n  return (\n    <div\n      className={className}\n      style={{\n        display: \"flex\",\n        flexDirection: vertical ? \"column\" : \"row\",\n        alignItems: \"center\",\n        justifyContent: vertical ? \"flex-start\" : \"space-between\",\n        gap: vertical ? 6 : 10,\n        boxSizing: \"border-box\",\n        minWidth: 0,\n        width,\n        fontFamily: token.font,\n        ...style,\n      }}\n    >\n      {label !== undefined && label !== null && (\n        <ControlTextBoundary\n          compressible={compressible}\n          narrow={narrow}\n          id={labelId}\n          style={{\n            fontSize: 10,\n            fontWeight: 600,\n            letterSpacing: \"0.08em\",\n            textTransform: \"uppercase\",\n            color: token.textMuted,\n            order: vertical ? 0 : -1,\n          }}\n        >\n          {label}\n        </ControlTextBoundary>\n      )}\n\n      {children}\n\n      {value !== undefined && value !== null && (\n        <ControlTextBoundary\n          style={{\n            fontFamily: token.fontMono,\n            fontSize: 11,\n            fontVariantNumeric: \"tabular-nums\",\n            color: token.text,\n          }}\n        >\n          {value}\n        </ControlTextBoundary>\n      )}\n    </div>\n  )\n}\n\n/** Shared numeric/unit typography. Omitting unitSize preserves the whole string. */\nexport function FormattedControlValue({\n  formatted: source, unitSize, unitStyle, fit = false,\n}: {\n  formatted: string\n  unitSize?: CSSProperties[\"fontSize\"]\n  unitStyle?: CSSProperties\n  /** Reduce numeric precision to fit the actual slot before clipping the number. */\n  fit?: boolean\n}) {\n  const formatted = formatControlValueLabel(source)\n  if (fit) return <FittedControlValue formatted={formatted} unitSize={unitSize} unitStyle={unitStyle} />\n  if (unitSize === undefined) return <>{formatted}</>\n  const parts = splitFormattedValue(formatted)\n  return (\n    <span data-uikit-formatted-value style={{ display: \"inline-flex\", alignItems: \"flex-start\", gap: \"0.12em\" }}>\n      <span>{parts.value}</span>\n      {parts.unit && <span data-uikit-value-unit style={{ fontSize: unitSize, lineHeight: 1.4, ...unitStyle }}>{parts.unit}</span>}\n    </span>\n  )\n}\n\n/** Measure real glyphs in layout pixels, including custom fonts and unit sizes. */\nfunction FittedControlValue({ formatted, unitSize, unitStyle }: {\n  formatted: string\n  unitSize?: CSSProperties[\"fontSize\"]\n  unitStyle?: CSSProperties\n}) {\n  const boundary = useRef<HTMLSpanElement>(null)\n  const [selection, setSelection] = useState({ formatted, index: 0, clipped: false, fontScale: 1 })\n  const candidates = controlValueCandidates(formatted)\n  const index = selection.formatted === formatted ? selection.index : 0\n  const clipped = selection.formatted === formatted && selection.clipped\n  const fontScale = selection.formatted === formatted ? selection.fontScale : 1\n  useBrowserLayoutEffect(() => {\n    const element = boundary.current\n    const view = element?.ownerDocument.defaultView\n    if (!element || !view) return\n    const probes = Array.from(element.querySelectorAll<HTMLElement>(\"[data-value-probe]\"))\n    const update = () => {\n      const width = element.clientWidth\n      if (width <= 0) return\n      const fitting = probes.findIndex((probe) => probe.scrollWidth <= width)\n      const index = fitting < 0 ? probes.length - 1 : fitting\n      // Retain readable, fixed-precision numbers before clipping. Probes stay\n      // at the inherited font size so this cannot feed back into measurement.\n      const numericWithUnit = splitFormattedValue(formatted).unit !== undefined\n      const fontScale = fitting < 0 && numericWithUnit\n        ? Math.max(0.85, Math.min(1, width / probes[index].scrollWidth)) : 1\n      const next = { formatted, index, fontScale, clipped: probes[index].scrollWidth * fontScale > width }\n      setSelection((previous) => previous.formatted === next.formatted && previous.index === next.index && previous.clipped === next.clipped && previous.fontScale === next.fontScale ? previous : next)\n    }\n    update()\n    const observer = typeof view.ResizeObserver === \"function\" ? new view.ResizeObserver(update) : undefined\n    observer?.observe(element)\n    probes.forEach((probe) => observer?.observe(probe))\n    element.ownerDocument.fonts?.addEventListener(\"loadingdone\", update)\n    return () => {\n      observer?.disconnect()\n      element.ownerDocument.fonts?.removeEventListener(\"loadingdone\", update)\n    }\n  }, [formatted, unitSize, unitStyle])\n  const parts = splitFormattedValue(candidates[index])\n  return (\n    <span ref={boundary} data-uikit-value-fit style={{ display: \"block\", position: \"relative\", minWidth: 0, maxWidth: \"100%\", fontVariantNumeric: \"tabular-nums\", whiteSpace: \"nowrap\" }}>\n      {candidates.map((candidate) => (\n        <span key={candidate} data-value-probe aria-hidden=\"true\" style={{ position: \"absolute\", visibility: \"hidden\", pointerEvents: \"none\", width: \"max-content\", whiteSpace: \"pre\", insetInlineStart: 0, top: 0 }}>\n          <FormattedControlValue formatted={candidate} unitSize={unitSize} unitStyle={unitStyle} />\n        </span>\n      ))}\n      <span aria-label={formatted} style={fontScale === 1 ? undefined : clipped\n        ? { fontSize: `${fontScale}em` }\n        : { display: \"inline-block\", transform: `scale(${fontScale})`, transformOrigin: \"center center\" }}>\n        {clipped && parts.unit ? (\n          <span style={{ display: \"flex\", justifyContent: \"center\", alignItems: \"baseline\", gap: \"0.12em\" }}>\n            <span style={{ minWidth: 0, overflow: \"hidden\", textOverflow: \"ellipsis\" }}>{parts.value}</span>\n            <span data-uikit-value-unit style={{ flexShrink: 0, fontSize: unitSize, ...unitStyle }}>{parts.unit}</span>\n          </span>\n        ) : <FormattedControlValue formatted={candidates[index]} unitSize={unitSize} unitStyle={unitStyle} />}\n      </span>\n    </span>\n  )\n}\n",
      "type": "registry:component",
      "target": "@ui/control-label.tsx"
    }
  ]
}
