ui/stepper: add stepper store to hook

This commit is contained in:
Johannes Kirschbauer
2025-08-07 12:50:03 +02:00
parent 484d274c3c
commit eec55f73a2

View File

@@ -6,6 +6,7 @@ import {
Setter,
useContext,
} from "solid-js";
import { createStore, SetStoreFunction, Store } from "solid-js/store";
export interface StepBase {
id: string;
@@ -13,24 +14,39 @@ export interface StepBase {
export type Step<ExtraFields = unknown> = StepBase & ExtraFields;
export interface StepOptions<Id> {
export interface StepOptions<Id, StoreType> {
initialStep: Id;
initialStoreData?: StoreType;
}
export function createStepper<
T extends readonly Step<Extra>[],
StepId extends T[number]["id"],
Extra = unknown,
>(s: { steps: T }, stepOpts: StepOptions<StepId>): StepperReturn<T> {
StoreType extends Record<string, unknown> = Record<string, unknown>,
>(
s: { steps: T },
stepOpts: StepOptions<StepId, StoreType>,
): StepperReturn<T, T[number]["id"]> {
const [activeStep, setActiveStep] = createSignal<T[number]["id"]>(
stepOpts.initialStep,
);
const store: StoreTuple<StoreType> = createStore<StoreType>(
stepOpts.initialStoreData ?? ({} as StoreType),
);
/**
* Hooks to manage the current step in the workflow.
* It provides the active step and a function to set the active step.
*/
return {
/**
* Usage store = getStepStore<MyStoreType>(stepper);
*
* TODO: Getting type inference working is tricky. Might fix this later.
*/
_store: store as unknown as never,
activeStep,
setActiveStep,
currentStep: () => {
@@ -73,10 +89,12 @@ export function createStepper<
};
}
type StoreTuple<T> = [get: Store<T>, set: SetStoreFunction<T>];
export interface StepperReturn<
T extends readonly Step[],
StepId = T[number]["id"],
> {
_store: never;
activeStep: Accessor<StepId>;
setActiveStep: Setter<StepId>;
currentStep: () => T[number];
@@ -125,3 +143,10 @@ export function StepperProvider<
export function defineSteps<T extends readonly StepBase[]>(steps: T) {
return steps;
}
interface getStepStoreArg {
_store: never;
}
export function getStepStore<StoreType>(stepper: getStepStoreArg) {
return stepper._store as StoreTuple<StoreType>;
}