Skip to content

Commit b1caa44

Browse files
authored
* refactor: rewrite store * refactor: rewrite react * docs: add migration * refactor: accordion, angle-slider, avatar, carousel * refactor: checkbox * refactor: clipboard * refactor: types * refactor: collapsible * refactor: colorpicker * refactor: combobox * refactor: dialog * refactor: datepicker * refactor: file upload * refactor: pin input * refactor: presence * refactor: progress * refactor: qr code * refactor: more components * refactor: more components * refactor: timer * refactor: examples * refactor: tags input * refactor: tree * refactor: radio group * refactor: pagination * refactor: tour * chore: update avatar * refactor: menu * refactor: machines * refactor: toggle group * refactor: switch * refactor: signature pad * refactor: splitter * refactor: radio-group * chore: update * refactor: number input * refactor: radio group * refactor: time picker * refactor: slid * chore: fix avatar * fix: carousel * fix: react examples * fix: react examples * chore: update react examples * refactor: machines and examples * refactor: react bindings * refactor: test setup * test: fix framework tests * refactor: solid and examples * refactor: machines and solid * refactor: svelte support * refactor: vue * chore: update visualizer * chore: update combobox * chore: update deps * chore: update * chore: trim examples * refactor: preact example * fix: typecheck * fix: lint * fix: react layout effect warning * refactor: e2e tests * test: update * test: remove .only * docs: update demos * docs: fix use search * feat: add raf based timers * refactor: starter * refactor: toast, frameworks * chore: add more vue example * chore: update vue * chore: update vue * fix: issues * chore: update plop template * fix: color picker * refactor: toast examples * docs: update * fix: carousel initial page * chore: bump svelte * docs: update * docs: fix highlight * docs: fix highlight * docs: update migration guide * chore: add scripts * chore: update * fix: avatar * fix: select initial items * fix: props export * fix: collapsible * chore: rm set-collection * refactor: type comments * fix: typedocs script * chore: update attr docs * fix: types * chore: rm logs * fix: types * refactor: improve file upload directory handling * chore: rm unused * docs: add link to migration * refactor: carousel * chore: update scripts * chore: update scripts * chore: fix packaging and use client * refactor: eslint * chore: migrate eslint * fix: date range picker * chore: keep svelte examples in sync * docs: write migration guide * fix: mem leak in effect * docs: update * docs: update * docs: update * refactor: toasts * chore: update * chore: update default max toast * docs: update * chore: update types * docs: mention Key component
1 parent d05463c commit b1caa44

File tree

1,035 files changed

+31704
-31780
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,035 files changed

+31704
-31780
lines changed

.changeset/config.json

-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@
2121
"nuxt-ts",
2222
"solid-ts",
2323
"nuxt-ts",
24-
"react-19",
2524
"preact-ts",
2625
"svelte-ts",
2726
"vanilla-ts",
28-
"lit-ts",
2927
"website"
3028
]
3129
}

.changeset/poor-tips-compete.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@zag-js/core": major
3+
---
4+
5+
Rewrite machines for increased performance and initial mount time.
6+
7+
This is done by relying on native framework primitives and a reducer rather than an external store.

.xstate/clipboard.js

+84-6
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,43 @@ const {
1010
choose
1111
} = actions;
1212
const fetchMachine = createMachine({
13-
id: "clipboard",
14-
initial: "idle",
15-
context: {},
13+
props({
14+
props
15+
}) {
16+
return {
17+
timeout: 3000,
18+
defaultValue: "",
19+
...props
20+
};
21+
},
22+
initialState() {
23+
return "idle";
24+
},
25+
context({
26+
prop,
27+
bindable
28+
}) {
29+
return {
30+
value: bindable(() => ({
31+
defaultValue: prop("defaultValue"),
32+
value: prop("value"),
33+
onChange(value) {
34+
prop("onValueChange")?.({
35+
value
36+
});
37+
}
38+
}))
39+
};
40+
},
41+
watch({
42+
track,
43+
context: {},
44+
action
45+
}) {
46+
track([() => context.get("value")], () => {
47+
action(["syncInputElement"]);
48+
});
49+
},
1650
on: {
1751
"VALUE.SET": {
1852
actions: ["setValue"]
@@ -37,10 +71,11 @@ const fetchMachine = createMachine({
3771
}
3872
},
3973
copied: {
40-
after: {
41-
COPY_TIMEOUT: "idle"
42-
},
74+
effects: ["waitForTimeout"],
4375
on: {
76+
"COPY.DONE": {
77+
target: "idle"
78+
},
4479
COPY: {
4580
target: "copied",
4681
actions: ["copyToClipboard", "invokeOnCopy"]
@@ -50,6 +85,49 @@ const fetchMachine = createMachine({
5085
}
5186
}
5287
}
88+
},
89+
implementations: {
90+
effects: {
91+
waitForTimeout({
92+
prop,
93+
send
94+
}) {
95+
return setRafTimeout(() => {
96+
send({
97+
type: "COPY.DONE"
98+
});
99+
}, prop("timeout"));
100+
}
101+
},
102+
actions: {
103+
setValue({
104+
context,
105+
event
106+
}) {
107+
context.set("value", event.value);
108+
},
109+
copyToClipboard({
110+
context,
111+
scope
112+
}) {
113+
dom.writeToClipboard(scope, context.get("value"));
114+
},
115+
invokeOnCopy({
116+
prop
117+
}) {
118+
prop("onStatusChange")?.({
119+
copied: true
120+
});
121+
},
122+
syncInputElement({
123+
context,
124+
scope
125+
}) {
126+
const inputEl = dom.getInputEl(scope);
127+
if (!inputEl) return;
128+
setElementValue(inputEl, context.get("value"));
129+
}
130+
}
53131
}
54132
}, {
55133
actions: {

.xstate/editable.js

+200-6
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,53 @@ const {
1010
choose
1111
} = actions;
1212
const fetchMachine = createMachine({
13-
id: "editable",
14-
initial: ctx.edit ? "edit" : "preview",
15-
entry: ctx.edit ? ["focusInput"] : undefined,
13+
props({
14+
props
15+
}) {
16+
return {
17+
activationMode: "focus",
18+
submitMode: "both",
19+
defaultValue: "",
20+
selectOnFocus: true,
21+
...props,
22+
translations: {
23+
input: "editable input",
24+
edit: "edit",
25+
submit: "submit",
26+
cancel: "cancel",
27+
...props.translations
28+
}
29+
};
30+
},
31+
initialState({
32+
prop
33+
}) {
34+
const edit = prop("edit") || prop("defaultEdit");
35+
return edit ? "edit" : "preview";
36+
},
37+
entry: ["focusInputIfNeeded"],
1638
context: {
1739
"isEditControlled": false,
1840
"isSubmitEvent": false,
1941
"isEditControlled": false,
2042
"isEditControlled": false
2143
},
44+
watch({
45+
track,
46+
action,
47+
context,
48+
prop
49+
}) {
50+
track([() => context.get("value")], () => {
51+
action(["syncInputValue"]);
52+
});
53+
track([() => prop("edit")], () => {
54+
action(["toggleEditing"]);
55+
});
56+
},
2257
on: {
2358
"VALUE.SET": {
24-
actions: "setValue"
59+
actions: ["setValue"]
2560
}
2661
},
2762
on: {
@@ -31,7 +66,6 @@ const fetchMachine = createMachine({
3166
},
3267
states: {
3368
preview: {
34-
// https://bugzilla.mozilla.org/show_bug.cgi?id=559561
3569
entry: ["blurInputIfNeeded"],
3670
on: {
3771
"CONTROLLED.EDIT": {
@@ -48,7 +82,7 @@ const fetchMachine = createMachine({
4882
}
4983
},
5084
edit: {
51-
activities: ["trackInteractOutside"],
85+
effects: ["trackInteractOutside"],
5286
on: {
5387
"CONTROLLED.PREVIEW": [{
5488
cond: "isSubmitEvent",
@@ -74,6 +108,166 @@ const fetchMachine = createMachine({
74108
}]
75109
}
76110
}
111+
},
112+
implementations: {
113+
guards: {
114+
isEditControlled: ({
115+
prop
116+
}) => prop("edit") != undefined,
117+
isSubmitEvent: ({
118+
event
119+
}) => event.previousEvent?.type === "SUBMIT"
120+
},
121+
effects: {
122+
trackInteractOutside({
123+
send,
124+
scope,
125+
prop
126+
}) {
127+
return trackInteractOutside(dom.getInputEl(scope), {
128+
exclude(target) {
129+
const ignore = [dom.getCancelTriggerEl(scope), dom.getSubmitTriggerEl(scope)];
130+
return ignore.some(el => contains(el, target));
131+
},
132+
onFocusOutside: prop("onFocusOutside"),
133+
onPointerDownOutside: prop("onPointerDownOutside"),
134+
onInteractOutside(event) {
135+
prop("onInteractOutside")?.(event);
136+
if (event.defaultPrevented) return;
137+
const {
138+
focusable
139+
} = event.detail;
140+
send({
141+
type: computed("submitOnBlur") ? "SUBMIT" : "CANCEL",
142+
src: "interact-outside",
143+
focusable
144+
});
145+
}
146+
});
147+
}
148+
},
149+
actions: {
150+
restoreFocus({
151+
event,
152+
scope,
153+
prop
154+
}) {
155+
if (event.focusable) return;
156+
raf(() => {
157+
const finalEl = prop("finalFocusEl")?.() ?? dom.getEditTriggerEl(scope);
158+
finalEl?.focus({
159+
preventScroll: true
160+
});
161+
});
162+
},
163+
clearValue({
164+
context
165+
}) {
166+
context.set("value", "");
167+
},
168+
focusInputIfNeeded({
169+
action,
170+
prop
171+
}) {
172+
const edit = prop("edit") || prop("defaultEdit");
173+
if (!edit) return;
174+
action(["focusInput"]);
175+
},
176+
focusInput({
177+
scope,
178+
prop
179+
}) {
180+
raf(() => {
181+
const inputEl = dom.getInputEl(scope);
182+
if (!inputEl) return;
183+
if (prop("selectOnFocus")) {
184+
inputEl.select();
185+
} else {
186+
inputEl.focus({
187+
preventScroll: true
188+
});
189+
}
190+
});
191+
},
192+
invokeOnCancel({
193+
prop,
194+
context
195+
}) {
196+
const prev = context.get("previousValue");
197+
prop("onValueRevert")?.({
198+
value: prev
199+
});
200+
},
201+
invokeOnSubmit({
202+
prop,
203+
context
204+
}) {
205+
const value = context.get("value");
206+
prop("onValueCommit")?.({
207+
value
208+
});
209+
},
210+
invokeOnEdit({
211+
prop
212+
}) {
213+
prop("onEditChange")?.({
214+
edit: true
215+
});
216+
},
217+
invokeOnPreview({
218+
prop
219+
}) {
220+
prop("onEditChange")?.({
221+
edit: false
222+
});
223+
},
224+
toggleEditing({
225+
prop,
226+
send,
227+
event
228+
}) {
229+
send({
230+
type: prop("edit") ? "CONTROLLED.EDIT" : "CONTROLLED.PREVIEW",
231+
previousEvent: event
232+
});
233+
},
234+
syncInputValue({
235+
context,
236+
scope
237+
}) {
238+
const inputEl = dom.getInputEl(scope);
239+
if (!inputEl) return;
240+
setElementValue(inputEl, context.get("value"));
241+
},
242+
setValue({
243+
context,
244+
prop,
245+
event
246+
}) {
247+
const max = prop("maxLength");
248+
const current = event.value;
249+
const value = max != null ? current.slice(0, max) : current;
250+
context.set("value", value);
251+
},
252+
setPreviousValue({
253+
context
254+
}) {
255+
const value = context.get("value");
256+
context.set("previousValue", value);
257+
},
258+
revertValue({
259+
context
260+
}) {
261+
const value = context.get("previousValue");
262+
if (!value) return;
263+
context.set("value", value);
264+
},
265+
blurInputIfNeeded({
266+
scope
267+
}) {
268+
dom.getInputEl(scope)?.blur();
269+
}
270+
}
77271
}
78272
}, {
79273
actions: {

0 commit comments

Comments
 (0)