import type { JSX, ValidComponent } from "@solidjs/web";
import { dynamic } from "@solidjs/web";
import { omit } from "solid-js";
import { mergeRootProps } from "../../internals/merge-root-props";
import { resolveClassStyle } from "../../internals/resolve-class-style";
import type { BaseUIComponentProps } from "../../internals/types";
import { valueToPercent } from "../../internals/value-to-percent";
import {
type ProgressRootState,
useProgressRootContext,
} from "../progress-root-context.ts";
export interface ProgressIndicatorState extends ProgressRootState {}
export interface ProgressIndicatorProps
extends BaseUIComponentProps<"div", ProgressIndicatorState> {
/**
* Tag/component to render. Defaults to `"div"`. Replaces the
* pre-spike `render` prop (axis G).
*/
as?: ValidComponent;
}
/**
* Visualizes the completion status of the task. Renders a `
` (or `as`
* override).
*/
export function ProgressIndicator(props: ProgressIndicatorProps): JSX.Element {
const context = useProgressRootContext();
const style = (): JSX.CSSProperties | undefined => {
const v = context.value();
if (v == null || !Number.isFinite(v)) return undefined;
const pct = valueToPercent(v, context.min(), context.max());
return {
"inset-inline-start": 0,
height: "inherit",
width: `${pct}%`,
};
};
// Resolve `class`/`style` so function values (stateful styling) are invoked
// with the progress state instead of being spread to the DOM raw. The
// internal `style` (the indicator width) is merged first below, so a
// user-supplied style composes with it rather than replacing the width.
const userClassStyle = resolveClassStyle(props, () => ({
status: context.status(),
}));
const userProps = omit(props, "as", "class", "style", "attrs");
const internalSlot = {
get style(): JSX.CSSProperties | undefined {
return style();
},
get "data-indeterminate"(): "" | undefined {
return context.status() === "indeterminate" ? "" : undefined;
},
get "data-progressing"(): "" | undefined {
return context.status() === "progressing" ? "" : undefined;
},
get "data-complete"(): "" | undefined {
return context.status() === "complete" ? "" : undefined;
},
};
let merged: Record = mergeRootProps(
internalSlot,
userClassStyle,
);
merged = mergeRootProps(merged, userProps);
const Tag = dynamic(() => props.as ?? "div");
return ;
}