{
  "name": "ProgressBar",
  "source": "src/components/ProgressBar.tsx",
  "propsType": "ProgressBarProps",
  "description": "ProgressBar — a determinate or indeterminate measure of work.\n\nDETERMINATE AND INDETERMINATE ARE THE SAME COMPONENT ON PURPOSE\n\nWork that starts unmeasurable and becomes measurable is the common case — a\nupload that does not know its size until the first chunk lands. Splitting\nthem into two components would make that transition a swap, which remounts\nthe node and loses the live region with it.\n\nOmitting `value` is what makes it indeterminate. `aria-valuenow` is then\nomitted too, which is exactly what the ARIA spec asks for and is the detail\nhand-rolled progress bars get wrong most often — a bar reporting\n`aria-valuenow=\"0\"` forever tells a screen reader the work is stuck at zero,\nnot that it is unmeasured.\n\nWHY `label` IS REQUIRED\n\n`role=\"progressbar\"` announces a number. Without a name the user hears \"42\npercent\" with no indication of what is at 42 percent, which is worse than\nsilence because it sounds like information.",
  "import": "import { ProgressBar } from 'ionbase-ui';",
  "status": "stable",
  "summary": "A determinate or indeterminate measure of work, with the name of the work attached. Omitting `value` is what makes it indeterminate.",
  "useWhen": [
    "work reports a fraction complete — an upload, an import, a multi-step job",
    "work will become measurable but is not yet, and the bar should not remount when it does",
    "a quota or usage figure is better read as a bar than a number"
  ],
  "useInstead": [
    {
      "when": "the wait is short and unmeasurable",
      "use": "Spinner",
      "why": "an indeterminate bar occupies a block of layout to say what a spinner says inline"
    },
    {
      "when": "the region is being replaced by content",
      "use": "Skeleton"
    },
    {
      "when": "measurable progress has to fit a square or a line of text — a header's status, a table cell",
      "use": "ProgressRing",
      "why": "a bar needs a row's width to be read; a ring holds the same fraction in the space of an icon"
    }
  ],
  "variants": {
    "intent": {
      "primary": {
        "use": "the default — work proceeding normally"
      },
      "success": {
        "use": "work that finished, where the bar stays on screen as a record"
      },
      "warning": {
        "use": "a quota approaching its limit",
        "note": "warning describes the VALUE, not a failure of the bar"
      },
      "error": {
        "use": "a quota exceeded, or a job that failed part-way",
        "note": "the bar is still reporting correctly — reserve this for the measured thing being bad"
      }
    },
    "size": {
      "sm": {
        "use": "inside a row or a dense table cell"
      },
      "md": {
        "use": "the default"
      }
    }
  },
  "a11y": {
    "requires": [
      "`label` — it is required, because role=\"progressbar\" announces a number and a number with no noun sounds like information while carrying none",
      "`valueText` when a percentage is not what a person wants read aloud — \"3 of 12 files\""
    ],
    "notes": [
      "indeterminate omits aria-valuenow entirely, as the ARIA spec asks; a bar reporting aria-valuenow=0 forever says the work is stuck rather than unmeasured",
      "value is clamped to 0..max, so a caller cannot render a bar past its own end"
    ]
  },
  "antiPatterns": [
    {
      "dont": "<ProgressBar label=\"Loading\" value={0} /> while the total is unknown",
      "do": "<ProgressBar label=\"Loading\" />",
      "why": "value={0} announces \"0 percent\" indefinitely. Omitting value is how you say \"not measurable yet\""
    },
    {
      "dont": "swapping a Spinner for a ProgressBar once the size is known",
      "do": "one ProgressBar, with `value` appearing when it becomes known",
      "why": "the swap remounts the node and takes the live region with it, so the transition is silent to a screen reader"
    },
    {
      "dont": "intent=\"error\" because the request failed",
      "do": "leave the bar and put the failure in an Alert",
      "why": "intent describes the value being measured. A failed request is not a red measurement, it is a different message"
    }
  ],
  "stylesheet": "src/styles/progress-bar.css",
  "tokens": [
    "--border-width-default",
    "--font-family-sans",
    "--ion-duration-base",
    "--ion-duration-cycle",
    "--ion-duration-slow",
    "--ion-ease-in-out",
    "--ion-ease-out",
    "--ion-progress-bar-fill",
    "--ion-progress-bar-height",
    "--ion-progress-bar-pct",
    "--radius-full",
    "--spacing-4",
    "--spacing-8",
    "--surface-error",
    "--surface-muted",
    "--surface-primary",
    "--surface-success",
    "--surface-warning",
    "--text-default",
    "--text-secondary",
    "--type-body-sm",
    "--type-body-sm-line-height"
  ],
  "props": {
    "label": {
      "type": "string",
      "required": true,
      "origin": "own",
      "description": "What is progressing. Required — a bare bar announces a number and no noun."
    },
    "value": {
      "type": "number | undefined",
      "required": false,
      "origin": "own",
      "description": "0 to `max`. Omit for an indeterminate bar."
    },
    "max": {
      "type": "number | undefined",
      "required": false,
      "origin": "own",
      "description": "Defaults to 100."
    },
    "intent": {
      "type": "ProgressBarIntent | undefined",
      "required": false,
      "origin": "own",
      "values": [
        "primary",
        "success",
        "warning",
        "error"
      ]
    },
    "size": {
      "type": "ProgressBarSize | undefined",
      "required": false,
      "origin": "own",
      "values": [
        "sm",
        "md"
      ]
    },
    "isLabelVisible": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Show the label as text above the track."
    },
    "isValueVisible": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Show the percentage beside the label. Determinate bars only."
    },
    "valueText": {
      "type": "string | undefined",
      "required": false,
      "origin": "own",
      "description": "Spoken instead of the percentage — \"3 of 12 files\". A percentage is rarely\nthe thing a person wants read aloud."
    }
  },
  "propCounts": {
    "own": 8,
    "aria": 0,
    "dom": 277,
    "other": 0
  }
}
