package.dist.index.mjs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of steps Show documentation
Show all versions of steps Show documentation
Core logic for the steps widget implemented as a state machine
The newest version!
import { createAnatomy } from '@zag-js/anatomy';
import { createScope, dataAttr } from '@zag-js/dom-query';
import { createSplitProps, fromLength, compact, isEqual } from '@zag-js/utils';
import { createMachine } from '@zag-js/core';
import { createProps } from '@zag-js/types';
// src/steps.anatomy.ts
var anatomy = createAnatomy("steps").parts(
"root",
"list",
"item",
"trigger",
"indicator",
"separator",
"content",
"nextTrigger",
"prevTrigger",
"progress"
);
var parts = anatomy.build();
var dom = createScope({
getRootId: (ctx) => ctx.ids?.root ?? `steps:${ctx.id}`,
getListId: (ctx) => ctx.ids?.list ?? `steps:${ctx.id}:list`,
getTriggerId: (ctx, index) => ctx.ids?.triggerId?.(index) ?? `steps:${ctx.id}:trigger:${index}`,
getContentId: (ctx, index) => ctx.ids?.contentId?.(index) ?? `steps:${ctx.id}:content:${index}`
});
// src/steps.connect.ts
function connect(state, send, normalize) {
const step = state.context.step;
const count = state.context.count;
const percent = state.context.percent;
const hasNextStep = state.context.hasNextStep;
const hasPrevStep = state.context.hasPrevStep;
const getItemState = (props2) => ({
triggerId: dom.getTriggerId(state.context, props2.index),
contentId: dom.getContentId(state.context, props2.index),
current: props2.index === step,
completed: props2.index < step,
incomplete: props2.index > step,
index: props2.index,
first: props2.index === 0,
last: props2.index === count - 1
});
const goToNextStep = () => {
send({ type: "STEP.NEXT", src: "next.trigger.click" });
};
const goToPrevStep = () => {
send({ type: "STEP.PREV", src: "prev.trigger.click" });
};
const resetStep = () => {
send({ type: "STEP.RESET", src: "reset.trigger.click" });
};
const setStep = (value) => {
send({ type: "STEP.SET", value, src: "api.setValue" });
};
return {
value: step,
count,
percent,
hasNextStep,
hasPrevStep,
goToNextStep,
goToPrevStep,
resetStep,
getItemState,
setStep,
getRootProps() {
return normalize.element({
...parts.root.attrs,
id: dom.getRootId(state.context),
dir: state.context.dir,
"data-orientation": state.context.orientation,
style: {
"--percent": `${percent}%`
}
});
},
getListProps() {
const arr = fromLength(state.context.count);
const triggerIds = arr.map((_, index) => dom.getTriggerId(state.context, index));
return normalize.element({
...parts.list.attrs,
dir: state.context.dir,
id: dom.getListId(state.context),
role: "tablist",
"aria-owns": triggerIds.join(" "),
"aria-orientation": state.context.orientation,
"data-orientation": state.context.orientation
});
},
getItemProps(props2) {
const itemState = getItemState(props2);
return normalize.element({
...parts.item.attrs,
dir: state.context.dir,
"aria-current": itemState.current ? "step" : void 0,
"data-orientation": state.context.orientation
});
},
getTriggerProps(props2) {
const itemState = getItemState(props2);
return normalize.button({
...parts.trigger.attrs,
id: itemState.triggerId,
role: "tab",
dir: state.context.dir,
tabIndex: !state.context.linear || itemState.current ? 0 : -1,
"aria-selected": itemState.current,
"aria-controls": itemState.contentId,
"data-state": itemState.current ? "open" : "closed",
"data-orientation": state.context.orientation,
"data-complete": dataAttr(itemState.completed),
"data-current": dataAttr(itemState.current),
"data-incomplete": dataAttr(itemState.incomplete),
onClick(event) {
if (event.defaultPrevented) return;
if (state.context.linear) return;
send({ type: "STEP.SET", value: props2.index, src: "trigger.click" });
}
});
},
getContentProps(props2) {
const itemState = getItemState(props2);
return normalize.element({
...parts.content.attrs,
dir: state.context.dir,
id: itemState.contentId,
role: "tabpanel",
tabIndex: 0,
hidden: !itemState.current,
"data-state": itemState.current ? "open" : "closed",
"data-orientation": state.context.orientation,
"aria-labelledby": itemState.triggerId
});
},
getIndicatorProps(props2) {
const itemState = getItemState(props2);
return normalize.element({
...parts.indicator.attrs,
dir: state.context.dir,
"aria-hidden": true,
"data-complete": dataAttr(itemState.completed),
"data-current": dataAttr(itemState.current),
"data-incomplete": dataAttr(itemState.incomplete)
});
},
getSeparatorProps(props2) {
const itemState = getItemState(props2);
return normalize.element({
...parts.separator.attrs,
dir: state.context.dir,
"data-orientation": state.context.orientation,
"data-complete": dataAttr(itemState.completed),
"data-current": dataAttr(itemState.current),
"data-incomplete": dataAttr(itemState.incomplete)
});
},
getNextTriggerProps() {
return normalize.button({
...parts.nextTrigger.attrs,
dir: state.context.dir,
type: "button",
disabled: !hasNextStep,
onClick(event) {
if (event.defaultPrevented) return;
goToNextStep();
}
});
},
getPrevTriggerProps() {
return normalize.button({
dir: state.context.dir,
...parts.prevTrigger.attrs,
type: "button",
disabled: !hasPrevStep,
onClick(event) {
if (event.defaultPrevented) return;
goToPrevStep();
}
});
},
getProgressProps() {
return normalize.element({
dir: state.context.dir,
...parts.progress.attrs,
role: "progressbar",
"aria-valuenow": percent,
"aria-valuemin": 0,
"aria-valuemax": 100,
"aria-valuetext": `${percent}% complete`,
"data-complete": dataAttr(percent === 100)
});
}
};
}
function machine(userContext) {
const ctx = compact(userContext);
return createMachine(
{
id: "steps",
initial: "idle",
context: {
step: 0,
count: 1,
linear: false,
orientation: "horizontal",
...ctx
},
computed: {
percent: (ctx2) => ctx2.step / ctx2.count * 100,
hasNextStep: (ctx2) => ctx2.step < ctx2.count,
hasPrevStep: (ctx2) => ctx2.step > 0
},
states: {
idle: {
on: {
"STEP.SET": {
actions: "setStep"
},
"STEP.NEXT": {
actions: "goToNextStep"
},
"STEP.PREV": {
actions: "goToPrevStep"
},
"STEP.RESET": {
actions: "resetStep"
}
}
}
}
},
{
actions: {
goToNextStep(ctx2) {
const value = Math.min(ctx2.step + 1, ctx2.count);
set.value(ctx2, value);
},
goToPrevStep(ctx2) {
const value = Math.max(ctx2.step - 1, 0);
set.value(ctx2, value);
},
resetStep(ctx2) {
set.value(ctx2, 0);
},
setStep(ctx2, event) {
const value = event.value;
const inRange = value >= 0 && value < ctx2.count;
if (!inRange) throw new RangeError(`Index ${value} is out of bounds`);
set.value(ctx2, value);
}
}
}
);
}
var set = {
value(ctx, step) {
if (isEqual(ctx.step, step)) return;
ctx.step = step;
ctx.onStepChange?.({ step });
}
};
var props = createProps()([
"count",
"dir",
"getRootNode",
"id",
"ids",
"linear",
"onStepChange",
"onStepComplete",
"orientation",
"step"
]);
var splitProps = createSplitProps(props);
export { anatomy, connect, machine, props, splitProps };
© 2015 - 2025 Weber Informatics LLC | Privacy Policy