{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "progress",
  "title": "Progress",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-angular/components/progress/progress.component.ts",
      "content": "import { Component, Input, ChangeDetectionStrategy } from '@angular/core'\nimport { cn } from '@/lib/utils'\n\nexport type ProgressState = 'indeterminate' | 'complete' | 'loading'\n\n/**\n * Angular port of UIPKGE Progress (React `Progress` = Radix `Progress.Root` + `Indicator`).\n * The host is the progressbar root (role, aria-value*, aria-valuetext, data-state /\n * data-value / data-max like Radix); the inner indicator is translated by the clamped value.\n * Out-of-range values clamp to [0, 100] so the indicator cannot overshoot the track, and an\n * unlabelled bar falls back to aria-label=\"Progress\".\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-progress, [ui-progress]',\n  standalone: true,\n  host: {\n    '[attr.data-uipkge]': '\"\"',\n    '[attr.data-slot]': '\"progress\"',\n    '[attr.role]': '\"progressbar\"',\n    '[attr.aria-label]': 'resolvedAriaLabel',\n    '[attr.aria-labelledby]': 'ariaLabelledby ?? null',\n    '[attr.aria-valuemin]': '0',\n    '[attr.aria-valuemax]': 'max',\n    '[attr.aria-valuenow]': 'clampedValue',\n    '[attr.aria-valuetext]': 'valueText',\n    '[attr.data-state]': 'state',\n    '[attr.data-value]': 'clampedValue',\n    '[attr.data-max]': 'max',\n    '[class]': 'hostClass',\n  },\n  template: `\n    <div\n      data-uipkge=\"\"\n      data-slot=\"progress-indicator\"\n      [attr.data-state]=\"state\"\n      [attr.data-value]=\"clampedValue\"\n      [attr.data-max]=\"max\"\n      class=\"bg-primary h-full w-full flex-1 transition-transform duration-500 ease-out motion-reduce:transition-none\"\n      [style.transform]=\"'translateX(-' + (100 - clampedValue) + '%)'\"\n    ></div>\n  `,\n})\nexport class UiProgressComponent {\n  @Input() value: number | null | undefined = 0\n  @Input() max = 100\n  @Input('aria-label') ariaLabel?: string\n  @Input('aria-labelledby') ariaLabelledby?: string\n  @Input('class') className?: string\n\n  get clampedValue(): number {\n    return Math.min(100, Math.max(0, this.value ?? 0))\n  }\n\n  /** Radix `getProgressState`: complete when value reaches max, loading otherwise. */\n  get state(): ProgressState {\n    return this.clampedValue === this.max ? 'complete' : 'loading'\n  }\n\n  /** Radix default `getValueLabel`. */\n  get valueText(): string {\n    return `${Math.round((this.clampedValue / this.max) * 100)}%`\n  }\n\n  get resolvedAriaLabel(): string | null {\n    if (this.ariaLabel !== undefined) return this.ariaLabel\n    return this.ariaLabelledby !== undefined ? null : 'Progress'\n  }\n\n  get hostClass(): string {\n    return cn('block bg-primary/20 relative h-2 w-full overflow-hidden rounded-full', this.className)\n  }\n}\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/progress/progress.component.ts"
    },
    {
      "path": "packages/registry-angular/components/progress/index.ts",
      "content": "export { UiProgressComponent } from './progress.component'\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/progress/index.ts"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Linear progress bar (Radix Progress semantics): role=\"progressbar\" with aria-value* / aria-valuetext, data-state loading | complete, a value clamped to 0–100, and an aria-label fallback when unlabelled.",
  "categories": [
    "feedback"
  ]
}