{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "meter",
  "title": "Meter",
  "description": "A bounded reading: your figure in large italic above a dimension line, one accent index locating it between its limits. Space remains space; nothing fills it in.",
  "registryDependencies": [
    "https://thedirectors.agency/ui/r/0nlytype.json"
  ],
  "files": [
    {
      "path": "registry/0nlytype/ui/meter.tsx",
      "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype MeterProps = Omit<React.ComponentProps<\"meter\">, \"children\" | \"value\" | \"min\" | \"max\"> & {\n  /** What is measured. The native label names the meter. */\n  label: React.ReactNode\n  value: number\n  min?: number\n  max?: number\n  /** Written as supplied: \" GB\" with its space, \"%\" without. */\n  unit?: string\n  /** The same formatter sets the reading and both ends of the scale. */\n  format?: (value: number) => string\n  /** Context for the reading, also attached to the native meter. */\n  note?: React.ReactNode\n}\n\nconst number = new Intl.NumberFormat(\"en-GB\", { maximumFractionDigits: 2 })\n\n/** A bounded reading, not work in progress. The index is exact; the italic figure stays inside the measure. */\nfunction Meter({ label, value, min = 0, max = 100, unit = \"\", format = (n) => number.format(n), note, id, className, style, hidden, dir, lang, \"aria-describedby\": describedBy, \"aria-valuetext\": valueText, ...props }: MeterProps) {\n  const generated = React.useId()\n  const meterId = id ?? generated\n  if (![value, min, max, max - min].every(Number.isFinite) || max <= min)\n    throw new RangeError(\"Meter needs a finite value and a finite range with max greater than min\")\n  // Match the native meter's clamping, so its spoken value and its visible index always agree.\n  const reading = Math.min(max, Math.max(min, value))\n  const p = (reading - min) / (max - min)\n  const figure = format(reading)\n  const text = `${figure}${unit}`\n  const noteId = note != null ? `${meterId}-note` : undefined\n  const description = [describedBy, noteId].filter(Boolean).join(\" \") || undefined\n  return (\n    <div data-slot=\"meter\" className={cn(\"ot-meter\", className)} style={{ \"--ot-meter-p\": p, \"--ot-meter-length\": Math.max(1, [...figure].length), \"--ot-meter-unit-length\": [...unit].length, ...style } as React.CSSProperties} hidden={hidden} dir={dir} lang={lang}>\n      <label data-slot=\"meter-label\" className=\"ot-meter-label\" htmlFor={meterId}>{label}</label>\n      <div data-slot=\"meter-scale\" className=\"ot-meter-scale\" aria-hidden=\"true\">\n        <span data-slot=\"meter-reading\" className=\"ot-meter-reading\"><bdi dir=\"ltr\"><span className=\"ot-yours\">{figure}</span><small>{unit}</small></bdi></span>\n        <span data-slot=\"meter-rule\" className=\"ot-meter-rule\"><i data-slot=\"meter-index\" className=\"ot-meter-index\" /></span>\n        <span data-slot=\"meter-limits\" className=\"ot-meter-ends\"><bdi dir=\"ltr\" data-slot=\"meter-min\">{format(min)}{unit}</bdi><bdi dir=\"ltr\" data-slot=\"meter-max\">{format(max)}{unit}</bdi></span>\n      </div>\n      <meter {...props} data-slot=\"meter-native\" className=\"ot-sr\" id={meterId} value={reading} min={min} max={max} aria-valuetext={valueText ?? text} aria-describedby={description} />\n      {note != null ? <p data-slot=\"meter-note\" className=\"ot-meter-note\" id={noteId}>{note}</p> : null}\n    </div>\n  )\n}\n\nexport { Meter, type MeterProps }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/0nlytype/styles/meter.css",
      "content": "@layer components {\n  /* Paul Rand's dimension lines: a precise index, with the measured figure above it and the limits below.\n     The space on either side shares what the figure leaves, so it fits at both ends in either writing direction. */\n  @property --ot-meter-p { syntax: \"<number>\"; inherits: true; initial-value: 0; }\n  .ot-meter { --ot-meter-p: 0; --ot-meter-length: 1; --ot-meter-unit-length: 0; min-inline-size: 0; inline-size: 100%; container-type: inline-size; overflow-wrap: anywhere; transition: --ot-meter-p var(--ot-moderato) var(--ot-breath); }\n  .ot-meter-label { display: block; font-size: var(--ot-pp); line-height: var(--ot-pp-lh); letter-spacing: var(--ot-pp-tr); color: var(--ot-graphite); }\n  .ot-meter-scale { margin-block-start: var(--ot-space-3); }\n  .ot-meter-reading {\n    display: flex; min-inline-size: 0;\n    font-size: clamp(var(--ot-mf), calc(100cqi / (var(--ot-meter-length) * 0.75 + var(--ot-meter-unit-length) * 0.2)), var(--ot-ff)); line-height: 1.2; letter-spacing: var(--ot-ff-tr); color: var(--ot-ink);\n    overflow-wrap: anywhere; font-variant-numeric: tabular-nums lining-nums;\n  }\n  .ot-meter-reading::before, .ot-meter-reading::after { content: \"\"; flex: var(--ot-meter-p) 0 0px; }\n  .ot-meter-reading::after { flex-grow: calc(1 - var(--ot-meter-p)); }\n  .ot-meter-reading > bdi { min-inline-size: 0; max-inline-size: 100%; }\n  .ot-meter-reading small { font-size: var(--ot-pp); line-height: var(--ot-pp-lh); letter-spacing: var(--ot-pp-tr); white-space: pre-wrap; }\n  .ot-meter-rule { position: relative; display: block; margin-block-start: var(--ot-space-4); border-block-start: var(--ot-hairline) solid var(--ot-rule-strong); }\n  .ot-meter-rule::before, .ot-meter-rule::after { content: \"\"; position: absolute; inset-block-start: -5px; block-size: 9px; border-inline-start: var(--ot-hairline) solid var(--ot-rule-strong); }\n  .ot-meter-rule::before { inset-inline-start: 0; }\n  .ot-meter-rule::after { inset-inline-end: 0; }\n  .ot-meter-index {\n    position: absolute; inset-block-start: calc(-1 * var(--ot-space-3)); inset-inline-start: calc(var(--ot-meter-p) * (100% - var(--ot-stroke)));\n    block-size: calc(var(--ot-space-3) * 2); border-inline-start: var(--ot-stroke) solid var(--ot-accent);\n  }\n  .ot-meter-ends { display: flex; justify-content: space-between; gap: var(--ot-space-4); padding-block-start: var(--ot-space-4); font-size: var(--ot-pp); line-height: var(--ot-pp-lh); letter-spacing: var(--ot-pp-tr); color: var(--ot-pencil); }\n  .ot-meter-ends > bdi { min-inline-size: 0; overflow-wrap: anywhere; }\n  .ot-meter-ends > bdi:last-child { text-align: end; }\n  .ot-meter-note { margin-block-start: var(--ot-space-3); font-size: var(--ot-pp); line-height: var(--ot-pp-lh); color: var(--ot-graphite); }\n  @media (prefers-reduced-motion: reduce) { .ot-meter { transition: none; } }\n  @media (forced-colors: active) { .ot-meter-index { border-color: Highlight; } }\n}\n",
      "type": "registry:file",
      "target": "styles/0nlytype/meter.css"
    }
  ],
  "css": {
    "@import \"../styles/0nlytype/meter.css\"": {}
  },
  "meta": {
    "movement": "X",
    "underneath": "native",
    "contract": "ot-meter"
  },
  "type": "registry:ui"
}
