{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "loading-bar",
  "title": "Loading Bar",
  "description": "A line along the window's top edge while a page loads, shown only once the load is slow.",
  "dependencies": [
    "@base-ui/react",
    "@stylexjs/stylex"
  ],
  "registryDependencies": [
    "https://constella.aayush.cv/r/base.json"
  ],
  "files": [
    {
      "path": "src/components/primitives/loading-bar.tsx",
      "content": "\"use client\";\n\nimport { Progress as ProgressPrimitive } from \"@base-ui/react/progress\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\n\nimport type { Sx } from \"@/lib/constella/styles\";\nimport {\n  colors,\n  durations,\n  easings,\n  layers,\n  media,\n  opacities,\n  strokes,\n} from \"@/lib/constella/tokens.stylex\";\n\ntype LoadingBarProps = Omit<\n  ProgressPrimitive.Root.Props,\n  \"className\" | \"style\" | \"value\"\n> & {\n  loading: boolean;\n  sx?: Sx;\n};\n\ntype Phase = \"hidden\" | \"shown\" | \"finishing\";\n\ninterface Step {\n  after: number;\n  to: Phase;\n}\n\nconst loadingDelay = Number.parseFloat(durations.loadingDelay);\nconst moveFor = Number.parseFloat(durations.move);\nconst finishFor = moveFor + Number.parseFloat(durations.popoverExit);\nconst trickleFor = Number.parseFloat(durations.trickle);\nconst reducedMotionQuery = media.reducedMotion.slice(\"@media \".length);\n\nconst steps = {\n  hidden: { idle: null, loading: { after: loadingDelay, to: \"shown\" } },\n  shown: { idle: { after: 0, to: \"finishing\" }, loading: null },\n  finishing: {\n    idle: { after: finishFor, to: \"hidden\" },\n    loading: { after: 0, to: \"shown\" },\n  },\n} satisfies Record<Phase, Record<\"idle\" | \"loading\", Step | null>>;\n\nconst trickle = [{ transform: \"scaleX(0.1)\" }, { transform: \"scaleX(0.9)\" }];\n\nconst breathe = stylex.keyframes({\n  \"50%\": { opacity: opacities.pulse },\n});\nconst finishing = \":is([data-state='finishing'])\";\nconst rtl = \":is([dir='rtl'], [dir='rtl'] *)\";\n\nconst styles = stylex.create({\n  root: {\n    height: strokes.indicator,\n    insetBlockStart: 0,\n    insetInlineStart: 0,\n    opacity: { default: 1, [finishing]: 0 },\n    pointerEvents: \"none\",\n    position: \"fixed\",\n    transitionDelay: { default: null, [finishing]: durations.move },\n    transitionDuration: { default: \"0s\", [finishing]: durations.popoverExit },\n    transitionProperty: \"opacity\",\n    transitionTimingFunction: easings.out,\n    width: \"100%\",\n    zIndex: layers.loadingBar,\n  },\n  indicator: {\n    animationDuration: {\n      default: null,\n      [media.reducedMotion]: durations.pulse,\n    },\n    animationIterationCount: {\n      default: null,\n      [media.reducedMotion]: \"infinite\",\n    },\n    animationName: { default: null, [media.reducedMotion]: breathe },\n    animationTimingFunction: {\n      default: null,\n      [media.reducedMotion]: easings.inOut,\n    },\n    backgroundColor: colors.accentSolid,\n    height: \"100%\",\n    transformOrigin: { default: \"left\", [rtl]: \"right\" },\n    width: \"100%\",\n  },\n});\n\n/** A line along the window's top edge while `loading` holds, shown only once a load outlasts `durations.loadingDelay`. */\nfunction LoadingBar({ loading, sx, ...props }: LoadingBarProps) {\n  const [phase, setPhase] = useState<Phase>(\"hidden\");\n  const indicator = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const next = steps[phase][loading ? \"loading\" : \"idle\"];\n    const timer =\n      next === null\n        ? undefined\n        : setTimeout(() => {\n            setPhase(next.to);\n          }, next.after);\n    return () => {\n      clearTimeout(timer);\n    };\n  }, [loading, phase]);\n\n  useLayoutEffect(() => {\n    const element = indicator.current;\n    if (element === null || matchMedia(reducedMotionQuery).matches) {\n      return;\n    }\n    const reached = getComputedStyle(element).transform;\n    for (const running of element.getAnimations()) {\n      running.cancel();\n    }\n    if (phase === \"shown\") {\n      element.animate(trickle, {\n        duration: trickleFor,\n        easing: easings.out,\n        fill: \"forwards\",\n      });\n    } else {\n      element.animate([{ transform: reached }, { transform: \"none\" }], {\n        duration: moveFor,\n        easing: easings.out,\n        fill: \"forwards\",\n      });\n    }\n  }, [phase]);\n\n  if (phase === \"hidden\") {\n    return null;\n  }\n  return (\n    <ProgressPrimitive.Root\n      data-slot=\"loading-bar\"\n      data-state={phase}\n      {...props}\n      value={null}\n      {...stylex.props(styles.root, sx)}\n    >\n      <ProgressPrimitive.Indicator\n        data-slot=\"loading-bar-indicator\"\n        ref={indicator}\n        {...stylex.props(styles.indicator)}\n      />\n    </ProgressPrimitive.Root>\n  );\n}\n\nexport { LoadingBar };\nexport type { LoadingBarProps };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/loading-bar/index.md",
  "type": "registry:ui"
}