@zag-js/steps 0.82.2 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _zag_js_anatomy from '@zag-js/anatomy';
2
- import { RequiredBy, PropTypes, DirectionProperty, CommonProperties, NormalizeProps } from '@zag-js/types';
2
+ import { DirectionProperty, CommonProperties, PropTypes, RequiredBy, NormalizeProps } from '@zag-js/types';
3
3
  import * as _zag_js_core from '@zag-js/core';
4
- import { Machine, StateMachine } from '@zag-js/core';
4
+ import { Service, Machine, EventObject } from '@zag-js/core';
5
5
 
6
6
  declare const anatomy: _zag_js_anatomy.AnatomyInstance<"root" | "list" | "item" | "trigger" | "indicator" | "separator" | "content" | "nextTrigger" | "prevTrigger" | "progress">;
7
7
 
@@ -14,19 +14,24 @@ interface ElementIds {
14
14
  triggerId?(index: number): string;
15
15
  contentId?(index: number): string;
16
16
  }
17
- interface PublicContext extends DirectionProperty, CommonProperties {
17
+ interface StepsProps extends DirectionProperty, CommonProperties {
18
18
  /**
19
19
  * The custom ids for the stepper elements
20
20
  */
21
21
  ids?: ElementIds | undefined;
22
22
  /**
23
- * The current value of the stepper
23
+ * The controlled value of the stepper
24
24
  */
25
- step: number;
25
+ step?: number | undefined;
26
+ /**
27
+ * The initial value of the stepper when rendered.
28
+ * Use when you don't need to control the value of the stepper.
29
+ */
30
+ defaultStep?: number | undefined;
26
31
  /**
27
32
  * Callback to be called when the value changes
28
33
  */
29
- onStepChange?(details: StepChangeDetails): void;
34
+ onStepChange?: ((details: StepChangeDetails) => void) | undefined;
30
35
  /**
31
36
  * Callback to be called when a step is completed
32
37
  */
@@ -37,14 +42,17 @@ interface PublicContext extends DirectionProperty, CommonProperties {
37
42
  linear?: boolean | undefined;
38
43
  /**
39
44
  * The orientation of the stepper
45
+ * @default "horizontal"
40
46
  */
41
47
  orientation?: "horizontal" | "vertical" | undefined;
42
48
  /**
43
49
  * The total number of steps
44
50
  */
45
- count: number;
51
+ count?: number | undefined;
46
52
  }
53
+ type PropsWithDefault = "orientation" | "linear" | "count";
47
54
  interface PrivateContext {
55
+ step: number;
48
56
  }
49
57
  type ComputedContext = Readonly<{
50
58
  percent: number;
@@ -52,15 +60,18 @@ type ComputedContext = Readonly<{
52
60
  hasPrevStep: boolean;
53
61
  completed: boolean;
54
62
  }>;
55
- type UserDefinedContext = RequiredBy<PublicContext, "id">;
56
- interface MachineContext extends PublicContext, PrivateContext, ComputedContext {
57
- }
58
- interface MachineState {
59
- value: "idle";
63
+ interface StepsSchema {
64
+ props: RequiredBy<StepsProps, PropsWithDefault>;
65
+ context: PrivateContext;
66
+ computed: ComputedContext;
67
+ state: "idle";
68
+ event: EventObject;
69
+ action: string;
70
+ effect: string;
71
+ guard: string;
60
72
  }
61
- type State = StateMachine.State<MachineContext, MachineState>;
62
- type Send = StateMachine.Send<StateMachine.AnyEventObject>;
63
- type Service = Machine<MachineContext, MachineState, StateMachine.AnyEventObject>;
73
+ type StepsService = Service<StepsSchema>;
74
+ type StepsMachine = Machine<StepsSchema>;
64
75
  interface ItemProps {
65
76
  index: number;
66
77
  }
@@ -74,7 +85,7 @@ interface ItemState {
74
85
  last: boolean;
75
86
  first: boolean;
76
87
  }
77
- interface MachineApi<T extends PropTypes = PropTypes> {
88
+ interface StepsApi<T extends PropTypes = PropTypes> {
78
89
  /**
79
90
  * The value of the stepper.
80
91
  */
@@ -131,11 +142,11 @@ interface MachineApi<T extends PropTypes = PropTypes> {
131
142
  getSeparatorProps(props: ItemProps): T["element"];
132
143
  }
133
144
 
134
- declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T>;
145
+ declare function connect<T extends PropTypes>(service: StepsService, normalize: NormalizeProps<T>): StepsApi<T>;
135
146
 
136
- declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<MachineContext, MachineState, _zag_js_core.StateMachine.AnyEventObject>;
147
+ declare const machine: _zag_js_core.Machine<StepsSchema>;
137
148
 
138
- declare const props: ("linear" | "step" | "dir" | "id" | "orientation" | "getRootNode" | "ids" | "onStepChange" | "onStepComplete" | "count")[];
139
- declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "linear" | "step" | "dir" | "id" | "orientation" | "getRootNode" | "ids" | "onStepChange" | "onStepComplete" | "count">];
149
+ declare const props: (keyof StepsProps)[];
150
+ declare const splitProps: <Props extends Partial<StepsProps>>(props: Props) => [Partial<StepsProps>, Omit<Props, keyof StepsProps>];
140
151
 
141
- export { type MachineApi as Api, type UserDefinedContext as Context, type ElementIds, type ItemProps, type ItemState, type Service, type StepChangeDetails, anatomy, connect, machine, props, splitProps };
152
+ export { type StepsApi as Api, type ElementIds, type ItemProps, type ItemState, type StepsMachine as Machine, type StepsProps as Props, type StepsService as Service, type StepChangeDetails, anatomy, connect, machine, props, splitProps };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _zag_js_anatomy from '@zag-js/anatomy';
2
- import { RequiredBy, PropTypes, DirectionProperty, CommonProperties, NormalizeProps } from '@zag-js/types';
2
+ import { DirectionProperty, CommonProperties, PropTypes, RequiredBy, NormalizeProps } from '@zag-js/types';
3
3
  import * as _zag_js_core from '@zag-js/core';
4
- import { Machine, StateMachine } from '@zag-js/core';
4
+ import { Service, Machine, EventObject } from '@zag-js/core';
5
5
 
6
6
  declare const anatomy: _zag_js_anatomy.AnatomyInstance<"root" | "list" | "item" | "trigger" | "indicator" | "separator" | "content" | "nextTrigger" | "prevTrigger" | "progress">;
7
7
 
@@ -14,19 +14,24 @@ interface ElementIds {
14
14
  triggerId?(index: number): string;
15
15
  contentId?(index: number): string;
16
16
  }
17
- interface PublicContext extends DirectionProperty, CommonProperties {
17
+ interface StepsProps extends DirectionProperty, CommonProperties {
18
18
  /**
19
19
  * The custom ids for the stepper elements
20
20
  */
21
21
  ids?: ElementIds | undefined;
22
22
  /**
23
- * The current value of the stepper
23
+ * The controlled value of the stepper
24
24
  */
25
- step: number;
25
+ step?: number | undefined;
26
+ /**
27
+ * The initial value of the stepper when rendered.
28
+ * Use when you don't need to control the value of the stepper.
29
+ */
30
+ defaultStep?: number | undefined;
26
31
  /**
27
32
  * Callback to be called when the value changes
28
33
  */
29
- onStepChange?(details: StepChangeDetails): void;
34
+ onStepChange?: ((details: StepChangeDetails) => void) | undefined;
30
35
  /**
31
36
  * Callback to be called when a step is completed
32
37
  */
@@ -37,14 +42,17 @@ interface PublicContext extends DirectionProperty, CommonProperties {
37
42
  linear?: boolean | undefined;
38
43
  /**
39
44
  * The orientation of the stepper
45
+ * @default "horizontal"
40
46
  */
41
47
  orientation?: "horizontal" | "vertical" | undefined;
42
48
  /**
43
49
  * The total number of steps
44
50
  */
45
- count: number;
51
+ count?: number | undefined;
46
52
  }
53
+ type PropsWithDefault = "orientation" | "linear" | "count";
47
54
  interface PrivateContext {
55
+ step: number;
48
56
  }
49
57
  type ComputedContext = Readonly<{
50
58
  percent: number;
@@ -52,15 +60,18 @@ type ComputedContext = Readonly<{
52
60
  hasPrevStep: boolean;
53
61
  completed: boolean;
54
62
  }>;
55
- type UserDefinedContext = RequiredBy<PublicContext, "id">;
56
- interface MachineContext extends PublicContext, PrivateContext, ComputedContext {
57
- }
58
- interface MachineState {
59
- value: "idle";
63
+ interface StepsSchema {
64
+ props: RequiredBy<StepsProps, PropsWithDefault>;
65
+ context: PrivateContext;
66
+ computed: ComputedContext;
67
+ state: "idle";
68
+ event: EventObject;
69
+ action: string;
70
+ effect: string;
71
+ guard: string;
60
72
  }
61
- type State = StateMachine.State<MachineContext, MachineState>;
62
- type Send = StateMachine.Send<StateMachine.AnyEventObject>;
63
- type Service = Machine<MachineContext, MachineState, StateMachine.AnyEventObject>;
73
+ type StepsService = Service<StepsSchema>;
74
+ type StepsMachine = Machine<StepsSchema>;
64
75
  interface ItemProps {
65
76
  index: number;
66
77
  }
@@ -74,7 +85,7 @@ interface ItemState {
74
85
  last: boolean;
75
86
  first: boolean;
76
87
  }
77
- interface MachineApi<T extends PropTypes = PropTypes> {
88
+ interface StepsApi<T extends PropTypes = PropTypes> {
78
89
  /**
79
90
  * The value of the stepper.
80
91
  */
@@ -131,11 +142,11 @@ interface MachineApi<T extends PropTypes = PropTypes> {
131
142
  getSeparatorProps(props: ItemProps): T["element"];
132
143
  }
133
144
 
134
- declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T>;
145
+ declare function connect<T extends PropTypes>(service: StepsService, normalize: NormalizeProps<T>): StepsApi<T>;
135
146
 
136
- declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<MachineContext, MachineState, _zag_js_core.StateMachine.AnyEventObject>;
147
+ declare const machine: _zag_js_core.Machine<StepsSchema>;
137
148
 
138
- declare const props: ("linear" | "step" | "dir" | "id" | "orientation" | "getRootNode" | "ids" | "onStepChange" | "onStepComplete" | "count")[];
139
- declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "linear" | "step" | "dir" | "id" | "orientation" | "getRootNode" | "ids" | "onStepChange" | "onStepComplete" | "count">];
149
+ declare const props: (keyof StepsProps)[];
150
+ declare const splitProps: <Props extends Partial<StepsProps>>(props: Props) => [Partial<StepsProps>, Omit<Props, keyof StepsProps>];
140
151
 
141
- export { type MachineApi as Api, type UserDefinedContext as Context, type ElementIds, type ItemProps, type ItemState, type Service, type StepChangeDetails, anatomy, connect, machine, props, splitProps };
152
+ export { type StepsApi as Api, type ElementIds, type ItemProps, type ItemState, type StepsMachine as Machine, type StepsProps as Props, type StepsService as Service, type StepChangeDetails, anatomy, connect, machine, props, splitProps };
package/dist/index.js CHANGED
@@ -20,23 +20,24 @@ var anatomy = anatomy$1.createAnatomy("steps").parts(
20
20
  "progress"
21
21
  );
22
22
  var parts = anatomy.build();
23
- var dom = domQuery.createScope({
24
- getRootId: (ctx) => ctx.ids?.root ?? `steps:${ctx.id}`,
25
- getListId: (ctx) => ctx.ids?.list ?? `steps:${ctx.id}:list`,
26
- getTriggerId: (ctx, index) => ctx.ids?.triggerId?.(index) ?? `steps:${ctx.id}:trigger:${index}`,
27
- getContentId: (ctx, index) => ctx.ids?.contentId?.(index) ?? `steps:${ctx.id}:content:${index}`
28
- });
23
+
24
+ // src/steps.dom.ts
25
+ var getRootId = (ctx) => ctx.ids?.root ?? `steps:${ctx.id}`;
26
+ var getListId = (ctx) => ctx.ids?.list ?? `steps:${ctx.id}:list`;
27
+ var getTriggerId = (ctx, index) => ctx.ids?.triggerId?.(index) ?? `steps:${ctx.id}:trigger:${index}`;
28
+ var getContentId = (ctx, index) => ctx.ids?.contentId?.(index) ?? `steps:${ctx.id}:content:${index}`;
29
29
 
30
30
  // src/steps.connect.ts
31
- function connect(state, send, normalize) {
32
- const step = state.context.step;
33
- const count = state.context.count;
34
- const percent = state.context.percent;
35
- const hasNextStep = state.context.hasNextStep;
36
- const hasPrevStep = state.context.hasPrevStep;
31
+ function connect(service, normalize) {
32
+ const { context, send, computed, prop, scope } = service;
33
+ const step = context.get("step");
34
+ const count = prop("count");
35
+ const percent = computed("percent");
36
+ const hasNextStep = computed("hasNextStep");
37
+ const hasPrevStep = computed("hasPrevStep");
37
38
  const getItemState = (props2) => ({
38
- triggerId: dom.getTriggerId(state.context, props2.index),
39
- contentId: dom.getContentId(state.context, props2.index),
39
+ triggerId: getTriggerId(scope, props2.index),
40
+ contentId: getContentId(scope, props2.index),
40
41
  current: props2.index === step,
41
42
  completed: props2.index < step,
42
43
  incomplete: props2.index > step,
@@ -62,7 +63,7 @@ function connect(state, send, normalize) {
62
63
  percent,
63
64
  hasNextStep,
64
65
  hasPrevStep,
65
- isCompleted: state.context.completed,
66
+ isCompleted: computed("completed"),
66
67
  goToNextStep,
67
68
  goToPrevStep,
68
69
  resetStep,
@@ -71,34 +72,34 @@ function connect(state, send, normalize) {
71
72
  getRootProps() {
72
73
  return normalize.element({
73
74
  ...parts.root.attrs,
74
- id: dom.getRootId(state.context),
75
- dir: state.context.dir,
76
- "data-orientation": state.context.orientation,
75
+ id: getRootId(scope),
76
+ dir: prop("dir"),
77
+ "data-orientation": prop("orientation"),
77
78
  style: {
78
79
  "--percent": `${percent}%`
79
80
  }
80
81
  });
81
82
  },
82
83
  getListProps() {
83
- const arr = utils.fromLength(state.context.count);
84
- const triggerIds = arr.map((_, index) => dom.getTriggerId(state.context, index));
84
+ const arr = utils.fromLength(count);
85
+ const triggerIds = arr.map((_, index) => getTriggerId(scope, index));
85
86
  return normalize.element({
86
87
  ...parts.list.attrs,
87
- dir: state.context.dir,
88
- id: dom.getListId(state.context),
88
+ dir: prop("dir"),
89
+ id: getListId(scope),
89
90
  role: "tablist",
90
91
  "aria-owns": triggerIds.join(" "),
91
- "aria-orientation": state.context.orientation,
92
- "data-orientation": state.context.orientation
92
+ "aria-orientation": prop("orientation"),
93
+ "data-orientation": prop("orientation")
93
94
  });
94
95
  },
95
96
  getItemProps(props2) {
96
97
  const itemState = getItemState(props2);
97
98
  return normalize.element({
98
99
  ...parts.item.attrs,
99
- dir: state.context.dir,
100
+ dir: prop("dir"),
100
101
  "aria-current": itemState.current ? "step" : void 0,
101
- "data-orientation": state.context.orientation
102
+ "data-orientation": prop("orientation")
102
103
  });
103
104
  },
104
105
  getTriggerProps(props2) {
@@ -107,18 +108,18 @@ function connect(state, send, normalize) {
107
108
  ...parts.trigger.attrs,
108
109
  id: itemState.triggerId,
109
110
  role: "tab",
110
- dir: state.context.dir,
111
- tabIndex: !state.context.linear || itemState.current ? 0 : -1,
111
+ dir: prop("dir"),
112
+ tabIndex: !prop("linear") || itemState.current ? 0 : -1,
112
113
  "aria-selected": itemState.current,
113
114
  "aria-controls": itemState.contentId,
114
115
  "data-state": itemState.current ? "open" : "closed",
115
- "data-orientation": state.context.orientation,
116
+ "data-orientation": prop("orientation"),
116
117
  "data-complete": domQuery.dataAttr(itemState.completed),
117
118
  "data-current": domQuery.dataAttr(itemState.current),
118
119
  "data-incomplete": domQuery.dataAttr(itemState.incomplete),
119
120
  onClick(event) {
120
121
  if (event.defaultPrevented) return;
121
- if (state.context.linear) return;
122
+ if (prop("linear")) return;
122
123
  send({ type: "STEP.SET", value: props2.index, src: "trigger.click" });
123
124
  }
124
125
  });
@@ -127,13 +128,13 @@ function connect(state, send, normalize) {
127
128
  const itemState = getItemState(props2);
128
129
  return normalize.element({
129
130
  ...parts.content.attrs,
130
- dir: state.context.dir,
131
+ dir: prop("dir"),
131
132
  id: itemState.contentId,
132
133
  role: "tabpanel",
133
134
  tabIndex: 0,
134
135
  hidden: !itemState.current,
135
136
  "data-state": itemState.current ? "open" : "closed",
136
- "data-orientation": state.context.orientation,
137
+ "data-orientation": prop("orientation"),
137
138
  "aria-labelledby": itemState.triggerId
138
139
  });
139
140
  },
@@ -141,7 +142,7 @@ function connect(state, send, normalize) {
141
142
  const itemState = getItemState(props2);
142
143
  return normalize.element({
143
144
  ...parts.indicator.attrs,
144
- dir: state.context.dir,
145
+ dir: prop("dir"),
145
146
  "aria-hidden": true,
146
147
  "data-complete": domQuery.dataAttr(itemState.completed),
147
148
  "data-current": domQuery.dataAttr(itemState.current),
@@ -152,8 +153,8 @@ function connect(state, send, normalize) {
152
153
  const itemState = getItemState(props2);
153
154
  return normalize.element({
154
155
  ...parts.separator.attrs,
155
- dir: state.context.dir,
156
- "data-orientation": state.context.orientation,
156
+ dir: prop("dir"),
157
+ "data-orientation": prop("orientation"),
157
158
  "data-complete": domQuery.dataAttr(itemState.completed),
158
159
  "data-current": domQuery.dataAttr(itemState.current),
159
160
  "data-incomplete": domQuery.dataAttr(itemState.incomplete)
@@ -162,7 +163,7 @@ function connect(state, send, normalize) {
162
163
  getNextTriggerProps() {
163
164
  return normalize.button({
164
165
  ...parts.nextTrigger.attrs,
165
- dir: state.context.dir,
166
+ dir: prop("dir"),
166
167
  type: "button",
167
168
  disabled: !hasNextStep,
168
169
  onClick(event) {
@@ -173,7 +174,7 @@ function connect(state, send, normalize) {
173
174
  },
174
175
  getPrevTriggerProps() {
175
176
  return normalize.button({
176
- dir: state.context.dir,
177
+ dir: prop("dir"),
177
178
  ...parts.prevTrigger.attrs,
178
179
  type: "button",
179
180
  disabled: !hasPrevStep,
@@ -185,7 +186,7 @@ function connect(state, send, normalize) {
185
186
  },
186
187
  getProgressProps() {
187
188
  return normalize.element({
188
- dir: state.context.dir,
189
+ dir: prop("dir"),
189
190
  ...parts.progress.attrs,
190
191
  role: "progressbar",
191
192
  "aria-valuenow": percent,
@@ -197,79 +198,85 @@ function connect(state, send, normalize) {
197
198
  }
198
199
  };
199
200
  }
200
- function machine(userContext) {
201
- const ctx = utils.compact(userContext);
202
- return core.createMachine(
203
- {
204
- id: "steps",
205
- initial: "idle",
206
- context: {
207
- step: 0,
208
- count: 1,
209
- linear: false,
210
- orientation: "horizontal",
211
- ...ctx
212
- },
213
- computed: {
214
- percent: (ctx2) => ctx2.step / ctx2.count * 100,
215
- hasNextStep: (ctx2) => ctx2.step < ctx2.count,
216
- hasPrevStep: (ctx2) => ctx2.step > 0,
217
- completed: (ctx2) => ctx2.step === ctx2.count
218
- },
219
- states: {
220
- idle: {
221
- on: {
222
- "STEP.SET": {
223
- actions: "setStep"
224
- },
225
- "STEP.NEXT": {
226
- actions: "goToNextStep"
227
- },
228
- "STEP.PREV": {
229
- actions: "goToPrevStep"
230
- },
231
- "STEP.RESET": {
232
- actions: "resetStep"
233
- }
201
+ var machine = core.createMachine({
202
+ props({ props: props2 }) {
203
+ return {
204
+ defaultStep: 0,
205
+ count: 1,
206
+ linear: false,
207
+ orientation: "horizontal",
208
+ ...props2
209
+ };
210
+ },
211
+ context({ prop, bindable, getComputed }) {
212
+ return {
213
+ step: bindable(() => ({
214
+ defaultValue: prop("defaultStep"),
215
+ value: prop("step"),
216
+ onChange(value) {
217
+ const computed = getComputed();
218
+ prop("onStepChange")?.({ step: value });
219
+ if (computed("completed")) {
220
+ prop("onStepComplete")?.();
234
221
  }
235
222
  }
236
- }
237
- },
238
- {
239
- actions: {
240
- goToNextStep(ctx2) {
241
- const value = Math.min(ctx2.step + 1, ctx2.count);
242
- set.value(ctx2, value);
223
+ }))
224
+ };
225
+ },
226
+ computed: {
227
+ percent: ({ context, prop }) => context.get("step") / prop("count") * 100,
228
+ hasNextStep: ({ context, prop }) => context.get("step") < prop("count"),
229
+ hasPrevStep: ({ context }) => context.get("step") > 0,
230
+ completed: ({ context, prop }) => context.get("step") === prop("count")
231
+ },
232
+ initialState() {
233
+ return "idle";
234
+ },
235
+ entry: ["validateStep"],
236
+ states: {
237
+ idle: {
238
+ on: {
239
+ "STEP.SET": {
240
+ actions: ["setStep"]
243
241
  },
244
- goToPrevStep(ctx2) {
245
- const value = Math.max(ctx2.step - 1, 0);
246
- set.value(ctx2, value);
242
+ "STEP.NEXT": {
243
+ actions: ["goToNextStep"]
247
244
  },
248
- resetStep(ctx2) {
249
- set.value(ctx2, 0);
245
+ "STEP.PREV": {
246
+ actions: ["goToPrevStep"]
250
247
  },
251
- setStep(ctx2, evt) {
252
- set.value(ctx2, evt.value);
248
+ "STEP.RESET": {
249
+ actions: ["resetStep"]
253
250
  }
254
251
  }
255
252
  }
256
- );
257
- }
258
- var validateStep = (ctx, step) => {
259
- if (!utils.isValueWithinRange(step, 0, ctx.count)) {
260
- throw new RangeError(`[zag-js/steps] step index ${step} is out of bounds`);
261
- }
262
- };
263
- var set = {
264
- value(ctx, step) {
265
- if (utils.isEqual(ctx.step, step)) return;
266
- validateStep(ctx, step);
267
- ctx.step = step;
268
- ctx.onStepChange?.({ step });
269
- if (ctx.completed) {
270
- ctx.onStepComplete?.();
253
+ },
254
+ implementations: {
255
+ actions: {
256
+ goToNextStep({ context, prop }) {
257
+ const value = Math.min(context.get("step") + 1, prop("count"));
258
+ context.set("step", value);
259
+ },
260
+ goToPrevStep({ context }) {
261
+ const value = Math.max(context.get("step") - 1, 0);
262
+ context.set("step", value);
263
+ },
264
+ resetStep({ context }) {
265
+ context.set("step", 0);
266
+ },
267
+ setStep({ context, event }) {
268
+ context.set("step", event.value);
269
+ },
270
+ validateStep({ context, prop }) {
271
+ validateStep(prop("count"), context.get("step"));
272
+ }
271
273
  }
272
274
  }
275
+ });
276
+ var validateStep = (count, step) => {
277
+ if (!utils.isValueWithinRange(step, 0, count)) {
278
+ throw new RangeError(`[zag-js/steps] step index ${step} is out of bounds`);
279
+ }
273
280
  };
274
281
  var props = types.createProps()([
275
282
  "count",
@@ -281,7 +288,8 @@ var props = types.createProps()([
281
288
  "onStepChange",
282
289
  "onStepComplete",
283
290
  "orientation",
284
- "step"
291
+ "step",
292
+ "defaultStep"
285
293
  ]);
286
294
  var splitProps = utils.createSplitProps(props);
287
295
 
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createAnatomy } from '@zag-js/anatomy';
2
- import { createScope, dataAttr } from '@zag-js/dom-query';
3
- import { createSplitProps, fromLength, compact, isEqual, isValueWithinRange } from '@zag-js/utils';
2
+ import { dataAttr } from '@zag-js/dom-query';
3
+ import { isValueWithinRange, createSplitProps, fromLength } from '@zag-js/utils';
4
4
  import { createMachine } from '@zag-js/core';
5
5
  import { createProps } from '@zag-js/types';
6
6
 
@@ -18,23 +18,24 @@ var anatomy = createAnatomy("steps").parts(
18
18
  "progress"
19
19
  );
20
20
  var parts = anatomy.build();
21
- var dom = createScope({
22
- getRootId: (ctx) => ctx.ids?.root ?? `steps:${ctx.id}`,
23
- getListId: (ctx) => ctx.ids?.list ?? `steps:${ctx.id}:list`,
24
- getTriggerId: (ctx, index) => ctx.ids?.triggerId?.(index) ?? `steps:${ctx.id}:trigger:${index}`,
25
- getContentId: (ctx, index) => ctx.ids?.contentId?.(index) ?? `steps:${ctx.id}:content:${index}`
26
- });
21
+
22
+ // src/steps.dom.ts
23
+ var getRootId = (ctx) => ctx.ids?.root ?? `steps:${ctx.id}`;
24
+ var getListId = (ctx) => ctx.ids?.list ?? `steps:${ctx.id}:list`;
25
+ var getTriggerId = (ctx, index) => ctx.ids?.triggerId?.(index) ?? `steps:${ctx.id}:trigger:${index}`;
26
+ var getContentId = (ctx, index) => ctx.ids?.contentId?.(index) ?? `steps:${ctx.id}:content:${index}`;
27
27
 
28
28
  // src/steps.connect.ts
29
- function connect(state, send, normalize) {
30
- const step = state.context.step;
31
- const count = state.context.count;
32
- const percent = state.context.percent;
33
- const hasNextStep = state.context.hasNextStep;
34
- const hasPrevStep = state.context.hasPrevStep;
29
+ function connect(service, normalize) {
30
+ const { context, send, computed, prop, scope } = service;
31
+ const step = context.get("step");
32
+ const count = prop("count");
33
+ const percent = computed("percent");
34
+ const hasNextStep = computed("hasNextStep");
35
+ const hasPrevStep = computed("hasPrevStep");
35
36
  const getItemState = (props2) => ({
36
- triggerId: dom.getTriggerId(state.context, props2.index),
37
- contentId: dom.getContentId(state.context, props2.index),
37
+ triggerId: getTriggerId(scope, props2.index),
38
+ contentId: getContentId(scope, props2.index),
38
39
  current: props2.index === step,
39
40
  completed: props2.index < step,
40
41
  incomplete: props2.index > step,
@@ -60,7 +61,7 @@ function connect(state, send, normalize) {
60
61
  percent,
61
62
  hasNextStep,
62
63
  hasPrevStep,
63
- isCompleted: state.context.completed,
64
+ isCompleted: computed("completed"),
64
65
  goToNextStep,
65
66
  goToPrevStep,
66
67
  resetStep,
@@ -69,34 +70,34 @@ function connect(state, send, normalize) {
69
70
  getRootProps() {
70
71
  return normalize.element({
71
72
  ...parts.root.attrs,
72
- id: dom.getRootId(state.context),
73
- dir: state.context.dir,
74
- "data-orientation": state.context.orientation,
73
+ id: getRootId(scope),
74
+ dir: prop("dir"),
75
+ "data-orientation": prop("orientation"),
75
76
  style: {
76
77
  "--percent": `${percent}%`
77
78
  }
78
79
  });
79
80
  },
80
81
  getListProps() {
81
- const arr = fromLength(state.context.count);
82
- const triggerIds = arr.map((_, index) => dom.getTriggerId(state.context, index));
82
+ const arr = fromLength(count);
83
+ const triggerIds = arr.map((_, index) => getTriggerId(scope, index));
83
84
  return normalize.element({
84
85
  ...parts.list.attrs,
85
- dir: state.context.dir,
86
- id: dom.getListId(state.context),
86
+ dir: prop("dir"),
87
+ id: getListId(scope),
87
88
  role: "tablist",
88
89
  "aria-owns": triggerIds.join(" "),
89
- "aria-orientation": state.context.orientation,
90
- "data-orientation": state.context.orientation
90
+ "aria-orientation": prop("orientation"),
91
+ "data-orientation": prop("orientation")
91
92
  });
92
93
  },
93
94
  getItemProps(props2) {
94
95
  const itemState = getItemState(props2);
95
96
  return normalize.element({
96
97
  ...parts.item.attrs,
97
- dir: state.context.dir,
98
+ dir: prop("dir"),
98
99
  "aria-current": itemState.current ? "step" : void 0,
99
- "data-orientation": state.context.orientation
100
+ "data-orientation": prop("orientation")
100
101
  });
101
102
  },
102
103
  getTriggerProps(props2) {
@@ -105,18 +106,18 @@ function connect(state, send, normalize) {
105
106
  ...parts.trigger.attrs,
106
107
  id: itemState.triggerId,
107
108
  role: "tab",
108
- dir: state.context.dir,
109
- tabIndex: !state.context.linear || itemState.current ? 0 : -1,
109
+ dir: prop("dir"),
110
+ tabIndex: !prop("linear") || itemState.current ? 0 : -1,
110
111
  "aria-selected": itemState.current,
111
112
  "aria-controls": itemState.contentId,
112
113
  "data-state": itemState.current ? "open" : "closed",
113
- "data-orientation": state.context.orientation,
114
+ "data-orientation": prop("orientation"),
114
115
  "data-complete": dataAttr(itemState.completed),
115
116
  "data-current": dataAttr(itemState.current),
116
117
  "data-incomplete": dataAttr(itemState.incomplete),
117
118
  onClick(event) {
118
119
  if (event.defaultPrevented) return;
119
- if (state.context.linear) return;
120
+ if (prop("linear")) return;
120
121
  send({ type: "STEP.SET", value: props2.index, src: "trigger.click" });
121
122
  }
122
123
  });
@@ -125,13 +126,13 @@ function connect(state, send, normalize) {
125
126
  const itemState = getItemState(props2);
126
127
  return normalize.element({
127
128
  ...parts.content.attrs,
128
- dir: state.context.dir,
129
+ dir: prop("dir"),
129
130
  id: itemState.contentId,
130
131
  role: "tabpanel",
131
132
  tabIndex: 0,
132
133
  hidden: !itemState.current,
133
134
  "data-state": itemState.current ? "open" : "closed",
134
- "data-orientation": state.context.orientation,
135
+ "data-orientation": prop("orientation"),
135
136
  "aria-labelledby": itemState.triggerId
136
137
  });
137
138
  },
@@ -139,7 +140,7 @@ function connect(state, send, normalize) {
139
140
  const itemState = getItemState(props2);
140
141
  return normalize.element({
141
142
  ...parts.indicator.attrs,
142
- dir: state.context.dir,
143
+ dir: prop("dir"),
143
144
  "aria-hidden": true,
144
145
  "data-complete": dataAttr(itemState.completed),
145
146
  "data-current": dataAttr(itemState.current),
@@ -150,8 +151,8 @@ function connect(state, send, normalize) {
150
151
  const itemState = getItemState(props2);
151
152
  return normalize.element({
152
153
  ...parts.separator.attrs,
153
- dir: state.context.dir,
154
- "data-orientation": state.context.orientation,
154
+ dir: prop("dir"),
155
+ "data-orientation": prop("orientation"),
155
156
  "data-complete": dataAttr(itemState.completed),
156
157
  "data-current": dataAttr(itemState.current),
157
158
  "data-incomplete": dataAttr(itemState.incomplete)
@@ -160,7 +161,7 @@ function connect(state, send, normalize) {
160
161
  getNextTriggerProps() {
161
162
  return normalize.button({
162
163
  ...parts.nextTrigger.attrs,
163
- dir: state.context.dir,
164
+ dir: prop("dir"),
164
165
  type: "button",
165
166
  disabled: !hasNextStep,
166
167
  onClick(event) {
@@ -171,7 +172,7 @@ function connect(state, send, normalize) {
171
172
  },
172
173
  getPrevTriggerProps() {
173
174
  return normalize.button({
174
- dir: state.context.dir,
175
+ dir: prop("dir"),
175
176
  ...parts.prevTrigger.attrs,
176
177
  type: "button",
177
178
  disabled: !hasPrevStep,
@@ -183,7 +184,7 @@ function connect(state, send, normalize) {
183
184
  },
184
185
  getProgressProps() {
185
186
  return normalize.element({
186
- dir: state.context.dir,
187
+ dir: prop("dir"),
187
188
  ...parts.progress.attrs,
188
189
  role: "progressbar",
189
190
  "aria-valuenow": percent,
@@ -195,79 +196,85 @@ function connect(state, send, normalize) {
195
196
  }
196
197
  };
197
198
  }
198
- function machine(userContext) {
199
- const ctx = compact(userContext);
200
- return createMachine(
201
- {
202
- id: "steps",
203
- initial: "idle",
204
- context: {
205
- step: 0,
206
- count: 1,
207
- linear: false,
208
- orientation: "horizontal",
209
- ...ctx
210
- },
211
- computed: {
212
- percent: (ctx2) => ctx2.step / ctx2.count * 100,
213
- hasNextStep: (ctx2) => ctx2.step < ctx2.count,
214
- hasPrevStep: (ctx2) => ctx2.step > 0,
215
- completed: (ctx2) => ctx2.step === ctx2.count
216
- },
217
- states: {
218
- idle: {
219
- on: {
220
- "STEP.SET": {
221
- actions: "setStep"
222
- },
223
- "STEP.NEXT": {
224
- actions: "goToNextStep"
225
- },
226
- "STEP.PREV": {
227
- actions: "goToPrevStep"
228
- },
229
- "STEP.RESET": {
230
- actions: "resetStep"
231
- }
199
+ var machine = createMachine({
200
+ props({ props: props2 }) {
201
+ return {
202
+ defaultStep: 0,
203
+ count: 1,
204
+ linear: false,
205
+ orientation: "horizontal",
206
+ ...props2
207
+ };
208
+ },
209
+ context({ prop, bindable, getComputed }) {
210
+ return {
211
+ step: bindable(() => ({
212
+ defaultValue: prop("defaultStep"),
213
+ value: prop("step"),
214
+ onChange(value) {
215
+ const computed = getComputed();
216
+ prop("onStepChange")?.({ step: value });
217
+ if (computed("completed")) {
218
+ prop("onStepComplete")?.();
232
219
  }
233
220
  }
234
- }
235
- },
236
- {
237
- actions: {
238
- goToNextStep(ctx2) {
239
- const value = Math.min(ctx2.step + 1, ctx2.count);
240
- set.value(ctx2, value);
221
+ }))
222
+ };
223
+ },
224
+ computed: {
225
+ percent: ({ context, prop }) => context.get("step") / prop("count") * 100,
226
+ hasNextStep: ({ context, prop }) => context.get("step") < prop("count"),
227
+ hasPrevStep: ({ context }) => context.get("step") > 0,
228
+ completed: ({ context, prop }) => context.get("step") === prop("count")
229
+ },
230
+ initialState() {
231
+ return "idle";
232
+ },
233
+ entry: ["validateStep"],
234
+ states: {
235
+ idle: {
236
+ on: {
237
+ "STEP.SET": {
238
+ actions: ["setStep"]
241
239
  },
242
- goToPrevStep(ctx2) {
243
- const value = Math.max(ctx2.step - 1, 0);
244
- set.value(ctx2, value);
240
+ "STEP.NEXT": {
241
+ actions: ["goToNextStep"]
245
242
  },
246
- resetStep(ctx2) {
247
- set.value(ctx2, 0);
243
+ "STEP.PREV": {
244
+ actions: ["goToPrevStep"]
248
245
  },
249
- setStep(ctx2, evt) {
250
- set.value(ctx2, evt.value);
246
+ "STEP.RESET": {
247
+ actions: ["resetStep"]
251
248
  }
252
249
  }
253
250
  }
254
- );
255
- }
256
- var validateStep = (ctx, step) => {
257
- if (!isValueWithinRange(step, 0, ctx.count)) {
258
- throw new RangeError(`[zag-js/steps] step index ${step} is out of bounds`);
259
- }
260
- };
261
- var set = {
262
- value(ctx, step) {
263
- if (isEqual(ctx.step, step)) return;
264
- validateStep(ctx, step);
265
- ctx.step = step;
266
- ctx.onStepChange?.({ step });
267
- if (ctx.completed) {
268
- ctx.onStepComplete?.();
251
+ },
252
+ implementations: {
253
+ actions: {
254
+ goToNextStep({ context, prop }) {
255
+ const value = Math.min(context.get("step") + 1, prop("count"));
256
+ context.set("step", value);
257
+ },
258
+ goToPrevStep({ context }) {
259
+ const value = Math.max(context.get("step") - 1, 0);
260
+ context.set("step", value);
261
+ },
262
+ resetStep({ context }) {
263
+ context.set("step", 0);
264
+ },
265
+ setStep({ context, event }) {
266
+ context.set("step", event.value);
267
+ },
268
+ validateStep({ context, prop }) {
269
+ validateStep(prop("count"), context.get("step"));
270
+ }
269
271
  }
270
272
  }
273
+ });
274
+ var validateStep = (count, step) => {
275
+ if (!isValueWithinRange(step, 0, count)) {
276
+ throw new RangeError(`[zag-js/steps] step index ${step} is out of bounds`);
277
+ }
271
278
  };
272
279
  var props = createProps()([
273
280
  "count",
@@ -279,7 +286,8 @@ var props = createProps()([
279
286
  "onStepChange",
280
287
  "onStepComplete",
281
288
  "orientation",
282
- "step"
289
+ "step",
290
+ "defaultStep"
283
291
  ]);
284
292
  var splitProps = createSplitProps(props);
285
293
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/steps",
3
- "version": "0.82.2",
3
+ "version": "1.0.1",
4
4
  "description": "Core logic for the steps widget implemented as a state machine",
5
5
  "keywords": [
6
6
  "js",
@@ -27,11 +27,11 @@
27
27
  "url": "https://github.com/chakra-ui/zag/issues"
28
28
  },
29
29
  "dependencies": {
30
- "@zag-js/anatomy": "0.82.2",
31
- "@zag-js/core": "0.82.2",
32
- "@zag-js/dom-query": "0.82.2",
33
- "@zag-js/utils": "0.82.2",
34
- "@zag-js/types": "0.82.2"
30
+ "@zag-js/anatomy": "1.0.1",
31
+ "@zag-js/core": "1.0.1",
32
+ "@zag-js/dom-query": "1.0.1",
33
+ "@zag-js/utils": "1.0.1",
34
+ "@zag-js/types": "1.0.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "clean-package": "2.2.0"
@@ -41,9 +41,14 @@
41
41
  "types": "dist/index.d.ts",
42
42
  "exports": {
43
43
  ".": {
44
- "types": "./dist/index.d.ts",
45
- "import": "./dist/index.mjs",
46
- "require": "./dist/index.js"
44
+ "import": {
45
+ "types": "./dist/index.d.mts",
46
+ "default": "./dist/index.mjs"
47
+ },
48
+ "require": {
49
+ "types": "./dist/index.d.ts",
50
+ "default": "./dist/index.js"
51
+ }
47
52
  },
48
53
  "./package.json": "./package.json"
49
54
  },