{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "activity-goal",
  "type": "registry:component",
  "title": "Activity goal",
  "description": "Shows a supplied activity amount and target with native progress, visible units, and distinct missing-data states.",
  "registryDependencies": [
    "https://vlak.dev/r/vlak-base.json",
    "https://vlak.dev/r/inter.json",
    "https://vlak.dev/r/vlak-lib.json"
  ],
  "dependencies": [
    "@stylexjs/stylex"
  ],
  "devDependencies": [
    "@stylexjs/babel-plugin"
  ],
  "docs": "Vlak leaves are StyleX. Compile them with @stylexjs/babel-plugin (Vite: @stylexjs/unplugin, Next: @stylexjs/nextjs-plugin). If you would rather not run a compiler, import @noorddev/vlak-react instead: it ships precompiled with one stylesheet.",
  "files": [
    {
      "path": "vlak/activity-goal.tsx",
      "content": "import * as React from \"react\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport { vlak, mq } from \"./tokens.stylex\";\nimport { rs } from \"./rs\";\n\nexport interface ActivityGoalProps extends React.HTMLAttributes<HTMLDivElement> {\n  label: React.ReactNode;\n  description?: React.ReactNode;\n  /** A supplied amount. null means no recorded amount; zero is a valid record. */\n  current: number | null;\n  /** A positive caller-owned goal. null means no goal has been set. */\n  target: number | null;\n  unit: string;\n}\n\nconst styles = stylex.create({\n  root: { display: \"grid\", gap: \"0.75rem\", minWidth: 0, color: vlak.ink },\n  label: { margin: 0, fontSize: vlak.controlFs, fontWeight: 600, lineHeight: 1.45 },\n  description: { margin: 0, color: vlak.gray, fontSize: vlak.controlFs, lineHeight: 1.45, maxWidth: \"66ch\" },\n  value: { margin: 0, fontSize: \"1.75rem\", fontWeight: 500, lineHeight: 1.2, fontVariantNumeric: \"tabular-nums\", letterSpacing: \"-0.025em\" },\n  target: { fontSize: vlak.controlFs, fontWeight: 400, color: vlak.gray, letterSpacing: \"normal\" },\n  progress: { display: \"block\", width: \"100%\", height: \"0.75rem\", accentColor: { default: vlak.ink, [mq.forcedColors]: \"Highlight\" }, borderRadius: 0 },\n});\n\n/** Progress toward a supplied activity goal, without recommended targets or scores. */\nexport const ActivityGoal = React.forwardRef<HTMLDivElement, ActivityGoalProps>(function ActivityGoal({\n  label, description, current, target, unit, className, style, \"aria-label\": ariaLabel, \"aria-labelledby\": ariaLabelledBy, \"aria-describedby\": ariaDescribedBy, ...props\n}, ref) {\n  const id = React.useId();\n  const validCurrent = current != null && Number.isFinite(current) && current >= 0;\n  const validTarget = target != null && Number.isFinite(target) && target > 0;\n  const valueText = validCurrent && validTarget ? `${current} of ${target} ${unit}` : undefined;\n  const root = rs([\"rs-activity-goal\", className], styles.root);\n  const heading = rs([\"rs-activity-goal-label\"], styles.label);\n  const copy = rs([\"rs-activity-goal-description\"], styles.description);\n  const amount = rs([\"rs-activity-goal-value\"], styles.value);\n  const goal = rs([\"rs-activity-goal-target\"], styles.target);\n  const progress = rs([\"rs-activity-goal-progress\"], styles.progress);\n  return <div {...props} ref={ref} className={root.className} style={{ ...root.style, ...style }}>\n    <p id={`${id}-label`} className={heading.className} style={heading.style}>{label}</p>\n    {description != null && <p id={`${id}-description`} className={copy.className} style={copy.style}>{description}</p>}\n    {validCurrent ? <p className={amount.className} style={amount.style}>{current} <span className={goal.className} style={goal.style}>{validTarget ? `of ${target} ${unit}` : unit}</span></p> : <p className={copy.className} style={copy.style}>{current == null ? \"No activity recorded\" : \"Activity unavailable\"}</p>}\n    {!validTarget && <p className={copy.className} style={copy.style}>{target == null ? \"No goal set\" : \"Goal unavailable\"}</p>}\n    {validCurrent && validTarget && <>\n      <progress value={Math.min(current, target)} max={target} aria-label={ariaLabel} aria-labelledby={ariaLabelledBy ?? (ariaLabel == null ? `${id}-label` : undefined)} aria-describedby={[ariaDescribedBy, description != null && `${id}-description`].filter(Boolean).join(\" \") || undefined} aria-valuetext={valueText} className={progress.className} style={progress.style}>{valueText}</progress>\n      {current >= target && <p className={copy.className} style={copy.style}>{current > target ? \"Goal exceeded\" : \"Goal reached\"}</p>}\n    </>}\n  </div>;\n});\n",
      "type": "registry:component",
      "target": "components/vlak/activity-goal.tsx"
    },
    {
      "path": "vlak/styles/activity-goal.css",
      "content": "/* ── activity-goal: generated from packages/react/src/components/activity-goal.tsx ── */\n.rs-activity-goal{display:grid;gap:0.75rem;min-width:0;color:var(--text)}\n.rs-activity-goal-label{margin:0;font-size:var(--control-fs);font-weight:600;line-height:1.45}\n.rs-activity-goal-description{margin:0;color:var(--text-secondary);font-size:var(--control-fs);line-height:1.45;max-width:66ch}\n.rs-activity-goal-value{margin:0;font-size:1.75rem;font-weight:500;line-height:1.2;font-variant-numeric:tabular-nums;letter-spacing:-0.025em}\n.rs-activity-goal-target{font-size:var(--control-fs);font-weight:400;color:var(--text-secondary);letter-spacing:normal}\n.rs-activity-goal-progress{display:block;width:100%;height:0.75rem;accent-color:var(--text);border-radius:0}\n@media (forced-colors: active){.rs-activity-goal-progress{accent-color:Highlight}}\n",
      "type": "registry:file",
      "target": "styles/vlak/activity-goal.css"
    }
  ],
  "meta": {
    "vlak": {
      "category": "health",
      "classes": [
        "rs-activity-goal",
        "rs-activity-goal-label",
        "rs-activity-goal-description",
        "rs-activity-goal-value",
        "rs-activity-goal-target",
        "rs-activity-goal-progress"
      ],
      "snippet": "<div class=\"rs-activity-goal\"><p class=\"rs-activity-goal-label\" id=\"walking-goal\">Walking</p><p class=\"rs-activity-goal-description\">Your personal goal for today</p><p class=\"rs-activity-goal-value\">24 <span class=\"rs-activity-goal-target\">of 30 min</span></p><progress class=\"rs-activity-goal-progress\" value=\"24\" max=\"30\" aria-labelledby=\"walking-goal\" aria-valuetext=\"24 of 30 min\">24 of 30 min</progress></div>",
      "cssOnly": false,
      "registryDependencies": [
        "vlak-lib"
      ],
      "aliases": [
        "ActivityGoal",
        "Activity progress",
        "Movement goal",
        "Hydration goal",
        "Step goal",
        "Wellness goal"
      ],
      "example": "import { ActivityGoal } from \"@noorddev/vlak-react\";\n\n<ActivityGoal label=\"Walking\" description=\"Your personal goal for today\" current={24} target={30} unit=\"min\" />\n<ActivityGoal label=\"Water recorded\" current={null} target={null} unit=\"ml\" />",
      "usage": {
        "use": [
          "Movement, hydration, or another activity with a caller-supplied amount, unit, and positive target.",
          "null for missing current data or an unset target; zero remains a valid recorded amount.",
          "Actual values above the target remain visible while the native bar stops at its maximum."
        ],
        "avoid": [
          "Adding default health recommendations or interpreting goal completion as a clinical outcome.",
          "An indeterminate loading state; missing data is explicitly labelled and has no progress bar."
        ]
      },
      "keyboard": [],
      "a11y": [
        "The native progress element is named by the visible label, aria-label, or aria-labelledby; aria-valuetext includes the actual amount, target, and unit.",
        "Missing, non-finite, negative amounts and non-positive targets have explicit text states and never produce a misleading bar or NaN attributes.",
        "Goal reached and goal exceeded remain text, with no color-only completion signal.",
        "The forwarded ref and native attributes reach the root div; descriptions are linked to progress."
      ]
    }
  }
}
