@zag-js/tabs 0.7.0 → 0.8.0
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/{chunk-PH44XJ2S.mjs → chunk-N5FVPJXW.mjs} +56 -25
- package/dist/{chunk-FPHYRUCF.mjs → chunk-N7U3IQEQ.mjs} +9 -3
- package/dist/{chunk-OUTOSCZW.mjs → chunk-SVFEUEGP.mjs} +22 -17
- package/dist/index.js +85 -43
- package/dist/index.mjs +3 -3
- package/dist/tabs.connect.d.ts +4 -0
- package/dist/tabs.connect.js +30 -19
- package/dist/tabs.connect.mjs +2 -2
- package/dist/tabs.dom.d.ts +13 -7
- package/dist/tabs.dom.js +22 -17
- package/dist/tabs.dom.mjs +1 -1
- package/dist/tabs.machine.js +77 -41
- package/dist/tabs.machine.mjs +2 -2
- package/package.json +4 -3
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dom
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SVFEUEGP.mjs";
|
|
4
4
|
|
|
5
5
|
// src/tabs.machine.ts
|
|
6
6
|
import { createMachine, guards } from "@zag-js/core";
|
|
7
7
|
import { nextTick, raf } from "@zag-js/dom-query";
|
|
8
|
+
import { trackElementRect } from "@zag-js/element-rect";
|
|
8
9
|
import { getFocusables } from "@zag-js/tabbable";
|
|
9
10
|
import { compact } from "@zag-js/utils";
|
|
10
11
|
var { not } = guards;
|
|
@@ -21,7 +22,7 @@ function machine(userContext) {
|
|
|
21
22
|
focusedValue: null,
|
|
22
23
|
previousValues: [],
|
|
23
24
|
indicatorRect: { left: "0px", top: "0px", width: "0px", height: "0px" },
|
|
24
|
-
|
|
25
|
+
canIndicatorTransition: false,
|
|
25
26
|
isIndicatorRendered: false,
|
|
26
27
|
loop: true,
|
|
27
28
|
translations: {},
|
|
@@ -32,10 +33,18 @@ function machine(userContext) {
|
|
|
32
33
|
isVertical: (ctx2) => ctx2.orientation === "vertical"
|
|
33
34
|
},
|
|
34
35
|
created: ["setPrevSelectedTabs"],
|
|
36
|
+
entry: ["checkRenderedElements", "syncIndicatorRect", "setContentTabIndex"],
|
|
37
|
+
exit: ["cleanupObserver"],
|
|
35
38
|
watch: {
|
|
36
39
|
focusedValue: "invokeOnFocus",
|
|
37
|
-
value: [
|
|
38
|
-
|
|
40
|
+
value: [
|
|
41
|
+
"enableIndicatorTransition",
|
|
42
|
+
"invokeOnChange",
|
|
43
|
+
"setPrevSelectedTabs",
|
|
44
|
+
"syncIndicatorRect",
|
|
45
|
+
"setContentTabIndex"
|
|
46
|
+
],
|
|
47
|
+
dir: ["syncIndicatorRect"]
|
|
39
48
|
},
|
|
40
49
|
on: {
|
|
41
50
|
SET_VALUE: {
|
|
@@ -43,9 +52,11 @@ function machine(userContext) {
|
|
|
43
52
|
},
|
|
44
53
|
CLEAR_VALUE: {
|
|
45
54
|
actions: "clearValue"
|
|
55
|
+
},
|
|
56
|
+
SET_INDICATOR_RECT: {
|
|
57
|
+
actions: "setIndicatorRect"
|
|
46
58
|
}
|
|
47
59
|
},
|
|
48
|
-
entry: ["checkRenderedElements", "setIndicatorRect", "setContentTabIndex"],
|
|
49
60
|
states: {
|
|
50
61
|
idle: {
|
|
51
62
|
on: {
|
|
@@ -126,9 +137,6 @@ function machine(userContext) {
|
|
|
126
137
|
clearValue(ctx2) {
|
|
127
138
|
ctx2.value = null;
|
|
128
139
|
},
|
|
129
|
-
invokeOnDelete(ctx2, evt) {
|
|
130
|
-
ctx2.onDelete?.({ value: evt.value });
|
|
131
|
-
},
|
|
132
140
|
focusFirstTab(ctx2) {
|
|
133
141
|
raf(() => dom.getFirstEl(ctx2)?.focus());
|
|
134
142
|
},
|
|
@@ -147,24 +155,9 @@ function machine(userContext) {
|
|
|
147
155
|
const prev = dom.getPrevEl(ctx2, ctx2.focusedValue);
|
|
148
156
|
raf(() => prev?.focus());
|
|
149
157
|
},
|
|
150
|
-
setIndicatorRect(ctx2) {
|
|
151
|
-
nextTick(() => {
|
|
152
|
-
if (!ctx2.isIndicatorRendered || !ctx2.value)
|
|
153
|
-
return;
|
|
154
|
-
ctx2.indicatorRect = dom.getRectById(ctx2, ctx2.value);
|
|
155
|
-
if (ctx2.hasMeasuredRect)
|
|
156
|
-
return;
|
|
157
|
-
nextTick(() => {
|
|
158
|
-
ctx2.hasMeasuredRect = true;
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
},
|
|
162
158
|
checkRenderedElements(ctx2) {
|
|
163
159
|
ctx2.isIndicatorRendered = !!dom.getIndicatorEl(ctx2);
|
|
164
160
|
},
|
|
165
|
-
clearMeasured(ctx2) {
|
|
166
|
-
ctx2.hasMeasuredRect = false;
|
|
167
|
-
},
|
|
168
161
|
invokeOnChange(ctx2) {
|
|
169
162
|
ctx2.onChange?.({ value: ctx2.value });
|
|
170
163
|
},
|
|
@@ -173,7 +166,7 @@ function machine(userContext) {
|
|
|
173
166
|
},
|
|
174
167
|
setPrevSelectedTabs(ctx2) {
|
|
175
168
|
if (ctx2.value != null) {
|
|
176
|
-
ctx2.previousValues = pushUnique(
|
|
169
|
+
ctx2.previousValues = pushUnique(ctx2.previousValues, ctx2.value);
|
|
177
170
|
}
|
|
178
171
|
},
|
|
179
172
|
// if tab panel contains focusable elements, remove the tabindex attribute
|
|
@@ -189,13 +182,51 @@ function machine(userContext) {
|
|
|
189
182
|
panel.setAttribute("tabindex", "0");
|
|
190
183
|
}
|
|
191
184
|
});
|
|
185
|
+
},
|
|
186
|
+
cleanupObserver(ctx2) {
|
|
187
|
+
ctx2.indicatorCleanup?.();
|
|
188
|
+
},
|
|
189
|
+
enableIndicatorTransition(ctx2) {
|
|
190
|
+
ctx2.canIndicatorTransition = true;
|
|
191
|
+
},
|
|
192
|
+
setIndicatorRect(ctx2, evt) {
|
|
193
|
+
const value = evt.id ?? ctx2.value;
|
|
194
|
+
if (!ctx2.isIndicatorRendered || !value)
|
|
195
|
+
return;
|
|
196
|
+
const tabEl = dom.getTriggerEl(ctx2, value);
|
|
197
|
+
if (!tabEl)
|
|
198
|
+
return;
|
|
199
|
+
ctx2.indicatorRect = dom.getRectById(ctx2, value);
|
|
200
|
+
nextTick(() => {
|
|
201
|
+
ctx2.canIndicatorTransition = false;
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
syncIndicatorRect(ctx2) {
|
|
205
|
+
ctx2.indicatorCleanup?.();
|
|
206
|
+
const value = ctx2.value;
|
|
207
|
+
if (!ctx2.isIndicatorRendered || !value)
|
|
208
|
+
return;
|
|
209
|
+
const tabEl = dom.getActiveTabEl(ctx2);
|
|
210
|
+
if (!tabEl)
|
|
211
|
+
return;
|
|
212
|
+
ctx2.indicatorCleanup = trackElementRect(tabEl, {
|
|
213
|
+
getRect(el) {
|
|
214
|
+
return dom.getOffsetRect(el);
|
|
215
|
+
},
|
|
216
|
+
onChange(rect) {
|
|
217
|
+
ctx2.indicatorRect = dom.resolveRect(rect, ctx2.orientation);
|
|
218
|
+
nextTick(() => {
|
|
219
|
+
ctx2.canIndicatorTransition = false;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
});
|
|
192
223
|
}
|
|
193
224
|
}
|
|
194
225
|
}
|
|
195
226
|
);
|
|
196
227
|
}
|
|
197
228
|
function pushUnique(arr, value) {
|
|
198
|
-
const newArr = arr.slice();
|
|
229
|
+
const newArr = Array.from(arr).slice();
|
|
199
230
|
const index = newArr.indexOf(value);
|
|
200
231
|
if (index > -1) {
|
|
201
232
|
newArr.splice(index, 1);
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-S2KW2DT4.mjs";
|
|
4
4
|
import {
|
|
5
5
|
dom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SVFEUEGP.mjs";
|
|
7
7
|
|
|
8
8
|
// src/tabs.connect.ts
|
|
9
9
|
import { getEventKey } from "@zag-js/dom-event";
|
|
@@ -36,6 +36,12 @@ function connect(state, send, normalize) {
|
|
|
36
36
|
clearValue() {
|
|
37
37
|
send({ type: "CLEAR_VALUE" });
|
|
38
38
|
},
|
|
39
|
+
/**
|
|
40
|
+
* Sets the indicator rect to the tab with the given id.
|
|
41
|
+
*/
|
|
42
|
+
setIndicatorRect(id) {
|
|
43
|
+
send({ type: "SET_INDICATOR_RECT", id });
|
|
44
|
+
},
|
|
39
45
|
rootProps: normalize.element({
|
|
40
46
|
...parts.root.attrs,
|
|
41
47
|
id: dom.getRootId(state.context),
|
|
@@ -142,12 +148,12 @@ function connect(state, send, normalize) {
|
|
|
142
148
|
...parts.indicator.attrs,
|
|
143
149
|
"data-orientation": state.context.orientation,
|
|
144
150
|
style: {
|
|
145
|
-
"--transition-duration": "
|
|
151
|
+
"--transition-duration": "150ms",
|
|
146
152
|
"--transition-property": "left, right, top, bottom, width, height",
|
|
147
153
|
position: "absolute",
|
|
148
154
|
willChange: "var(--transition-property)",
|
|
149
155
|
transitionProperty: "var(--transition-property)",
|
|
150
|
-
transitionDuration: state.context.
|
|
156
|
+
transitionDuration: state.context.canIndicatorTransition ? "var(--transition-duration)" : "0ms",
|
|
151
157
|
transitionTimingFunction: "var(--transition-timing-function)",
|
|
152
158
|
...state.context.indicatorRect
|
|
153
159
|
}
|
|
@@ -24,26 +24,31 @@ var dom = createScope({
|
|
|
24
24
|
getActiveContentEl: (ctx) => {
|
|
25
25
|
if (!ctx.value)
|
|
26
26
|
return;
|
|
27
|
-
|
|
28
|
-
return dom.getById(ctx, id);
|
|
27
|
+
return dom.getContentEl(ctx, ctx.value);
|
|
29
28
|
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
getActiveTabEl: (ctx) => {
|
|
30
|
+
if (!ctx.value)
|
|
31
|
+
return;
|
|
32
|
+
return dom.getTriggerEl(ctx, ctx.value);
|
|
33
|
+
},
|
|
34
|
+
getOffsetRect: (el) => {
|
|
35
|
+
return {
|
|
36
|
+
left: el?.offsetLeft ?? 0,
|
|
37
|
+
top: el?.offsetTop ?? 0,
|
|
38
|
+
width: el?.offsetWidth ?? 0,
|
|
39
|
+
height: el?.offsetHeight ?? 0
|
|
36
40
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
},
|
|
42
|
+
getRectById: (ctx, id) => {
|
|
43
|
+
const tab = itemById(dom.getElements(ctx), dom.getTriggerId(ctx, id));
|
|
44
|
+
return dom.resolveRect(dom.getOffsetRect(tab), ctx.orientation);
|
|
45
|
+
},
|
|
46
|
+
resolveRect(rect, orientation) {
|
|
47
|
+
const prop = orientation === "vertical" ? "height" : "width";
|
|
44
48
|
return {
|
|
45
|
-
left: `${
|
|
46
|
-
|
|
49
|
+
left: `${rect.left}px`,
|
|
50
|
+
top: `${rect.top}px`,
|
|
51
|
+
[prop]: `${rect[prop]}px`
|
|
47
52
|
};
|
|
48
53
|
}
|
|
49
54
|
});
|
package/dist/index.js
CHANGED
|
@@ -61,26 +61,31 @@ var dom = (0, import_dom_query.createScope)({
|
|
|
61
61
|
getActiveContentEl: (ctx) => {
|
|
62
62
|
if (!ctx.value)
|
|
63
63
|
return;
|
|
64
|
-
|
|
65
|
-
return dom.getById(ctx, id);
|
|
64
|
+
return dom.getContentEl(ctx, ctx.value);
|
|
66
65
|
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
getActiveTabEl: (ctx) => {
|
|
67
|
+
if (!ctx.value)
|
|
68
|
+
return;
|
|
69
|
+
return dom.getTriggerEl(ctx, ctx.value);
|
|
70
|
+
},
|
|
71
|
+
getOffsetRect: (el) => {
|
|
72
|
+
return {
|
|
73
|
+
left: el?.offsetLeft ?? 0,
|
|
74
|
+
top: el?.offsetTop ?? 0,
|
|
75
|
+
width: el?.offsetWidth ?? 0,
|
|
76
|
+
height: el?.offsetHeight ?? 0
|
|
73
77
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
},
|
|
79
|
+
getRectById: (ctx, id) => {
|
|
80
|
+
const tab = (0, import_dom_query.itemById)(dom.getElements(ctx), dom.getTriggerId(ctx, id));
|
|
81
|
+
return dom.resolveRect(dom.getOffsetRect(tab), ctx.orientation);
|
|
82
|
+
},
|
|
83
|
+
resolveRect(rect, orientation) {
|
|
84
|
+
const prop = orientation === "vertical" ? "height" : "width";
|
|
81
85
|
return {
|
|
82
|
-
left: `${
|
|
83
|
-
|
|
86
|
+
left: `${rect.left}px`,
|
|
87
|
+
top: `${rect.top}px`,
|
|
88
|
+
[prop]: `${rect[prop]}px`
|
|
84
89
|
};
|
|
85
90
|
}
|
|
86
91
|
});
|
|
@@ -114,6 +119,12 @@ function connect(state, send, normalize) {
|
|
|
114
119
|
clearValue() {
|
|
115
120
|
send({ type: "CLEAR_VALUE" });
|
|
116
121
|
},
|
|
122
|
+
/**
|
|
123
|
+
* Sets the indicator rect to the tab with the given id.
|
|
124
|
+
*/
|
|
125
|
+
setIndicatorRect(id) {
|
|
126
|
+
send({ type: "SET_INDICATOR_RECT", id });
|
|
127
|
+
},
|
|
117
128
|
rootProps: normalize.element({
|
|
118
129
|
...parts.root.attrs,
|
|
119
130
|
id: dom.getRootId(state.context),
|
|
@@ -220,12 +231,12 @@ function connect(state, send, normalize) {
|
|
|
220
231
|
...parts.indicator.attrs,
|
|
221
232
|
"data-orientation": state.context.orientation,
|
|
222
233
|
style: {
|
|
223
|
-
"--transition-duration": "
|
|
234
|
+
"--transition-duration": "150ms",
|
|
224
235
|
"--transition-property": "left, right, top, bottom, width, height",
|
|
225
236
|
position: "absolute",
|
|
226
237
|
willChange: "var(--transition-property)",
|
|
227
238
|
transitionProperty: "var(--transition-property)",
|
|
228
|
-
transitionDuration: state.context.
|
|
239
|
+
transitionDuration: state.context.canIndicatorTransition ? "var(--transition-duration)" : "0ms",
|
|
229
240
|
transitionTimingFunction: "var(--transition-timing-function)",
|
|
230
241
|
...state.context.indicatorRect
|
|
231
242
|
}
|
|
@@ -236,6 +247,7 @@ function connect(state, send, normalize) {
|
|
|
236
247
|
// src/tabs.machine.ts
|
|
237
248
|
var import_core = require("@zag-js/core");
|
|
238
249
|
var import_dom_query3 = require("@zag-js/dom-query");
|
|
250
|
+
var import_element_rect = require("@zag-js/element-rect");
|
|
239
251
|
var import_tabbable = require("@zag-js/tabbable");
|
|
240
252
|
var import_utils2 = require("@zag-js/utils");
|
|
241
253
|
var { not } = import_core.guards;
|
|
@@ -252,7 +264,7 @@ function machine(userContext) {
|
|
|
252
264
|
focusedValue: null,
|
|
253
265
|
previousValues: [],
|
|
254
266
|
indicatorRect: { left: "0px", top: "0px", width: "0px", height: "0px" },
|
|
255
|
-
|
|
267
|
+
canIndicatorTransition: false,
|
|
256
268
|
isIndicatorRendered: false,
|
|
257
269
|
loop: true,
|
|
258
270
|
translations: {},
|
|
@@ -263,10 +275,18 @@ function machine(userContext) {
|
|
|
263
275
|
isVertical: (ctx2) => ctx2.orientation === "vertical"
|
|
264
276
|
},
|
|
265
277
|
created: ["setPrevSelectedTabs"],
|
|
278
|
+
entry: ["checkRenderedElements", "syncIndicatorRect", "setContentTabIndex"],
|
|
279
|
+
exit: ["cleanupObserver"],
|
|
266
280
|
watch: {
|
|
267
281
|
focusedValue: "invokeOnFocus",
|
|
268
|
-
value: [
|
|
269
|
-
|
|
282
|
+
value: [
|
|
283
|
+
"enableIndicatorTransition",
|
|
284
|
+
"invokeOnChange",
|
|
285
|
+
"setPrevSelectedTabs",
|
|
286
|
+
"syncIndicatorRect",
|
|
287
|
+
"setContentTabIndex"
|
|
288
|
+
],
|
|
289
|
+
dir: ["syncIndicatorRect"]
|
|
270
290
|
},
|
|
271
291
|
on: {
|
|
272
292
|
SET_VALUE: {
|
|
@@ -274,9 +294,11 @@ function machine(userContext) {
|
|
|
274
294
|
},
|
|
275
295
|
CLEAR_VALUE: {
|
|
276
296
|
actions: "clearValue"
|
|
297
|
+
},
|
|
298
|
+
SET_INDICATOR_RECT: {
|
|
299
|
+
actions: "setIndicatorRect"
|
|
277
300
|
}
|
|
278
301
|
},
|
|
279
|
-
entry: ["checkRenderedElements", "setIndicatorRect", "setContentTabIndex"],
|
|
280
302
|
states: {
|
|
281
303
|
idle: {
|
|
282
304
|
on: {
|
|
@@ -357,9 +379,6 @@ function machine(userContext) {
|
|
|
357
379
|
clearValue(ctx2) {
|
|
358
380
|
ctx2.value = null;
|
|
359
381
|
},
|
|
360
|
-
invokeOnDelete(ctx2, evt) {
|
|
361
|
-
ctx2.onDelete?.({ value: evt.value });
|
|
362
|
-
},
|
|
363
382
|
focusFirstTab(ctx2) {
|
|
364
383
|
(0, import_dom_query3.raf)(() => dom.getFirstEl(ctx2)?.focus());
|
|
365
384
|
},
|
|
@@ -378,24 +397,9 @@ function machine(userContext) {
|
|
|
378
397
|
const prev = dom.getPrevEl(ctx2, ctx2.focusedValue);
|
|
379
398
|
(0, import_dom_query3.raf)(() => prev?.focus());
|
|
380
399
|
},
|
|
381
|
-
setIndicatorRect(ctx2) {
|
|
382
|
-
(0, import_dom_query3.nextTick)(() => {
|
|
383
|
-
if (!ctx2.isIndicatorRendered || !ctx2.value)
|
|
384
|
-
return;
|
|
385
|
-
ctx2.indicatorRect = dom.getRectById(ctx2, ctx2.value);
|
|
386
|
-
if (ctx2.hasMeasuredRect)
|
|
387
|
-
return;
|
|
388
|
-
(0, import_dom_query3.nextTick)(() => {
|
|
389
|
-
ctx2.hasMeasuredRect = true;
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
},
|
|
393
400
|
checkRenderedElements(ctx2) {
|
|
394
401
|
ctx2.isIndicatorRendered = !!dom.getIndicatorEl(ctx2);
|
|
395
402
|
},
|
|
396
|
-
clearMeasured(ctx2) {
|
|
397
|
-
ctx2.hasMeasuredRect = false;
|
|
398
|
-
},
|
|
399
403
|
invokeOnChange(ctx2) {
|
|
400
404
|
ctx2.onChange?.({ value: ctx2.value });
|
|
401
405
|
},
|
|
@@ -404,7 +408,7 @@ function machine(userContext) {
|
|
|
404
408
|
},
|
|
405
409
|
setPrevSelectedTabs(ctx2) {
|
|
406
410
|
if (ctx2.value != null) {
|
|
407
|
-
ctx2.previousValues = pushUnique(
|
|
411
|
+
ctx2.previousValues = pushUnique(ctx2.previousValues, ctx2.value);
|
|
408
412
|
}
|
|
409
413
|
},
|
|
410
414
|
// if tab panel contains focusable elements, remove the tabindex attribute
|
|
@@ -420,13 +424,51 @@ function machine(userContext) {
|
|
|
420
424
|
panel.setAttribute("tabindex", "0");
|
|
421
425
|
}
|
|
422
426
|
});
|
|
427
|
+
},
|
|
428
|
+
cleanupObserver(ctx2) {
|
|
429
|
+
ctx2.indicatorCleanup?.();
|
|
430
|
+
},
|
|
431
|
+
enableIndicatorTransition(ctx2) {
|
|
432
|
+
ctx2.canIndicatorTransition = true;
|
|
433
|
+
},
|
|
434
|
+
setIndicatorRect(ctx2, evt) {
|
|
435
|
+
const value = evt.id ?? ctx2.value;
|
|
436
|
+
if (!ctx2.isIndicatorRendered || !value)
|
|
437
|
+
return;
|
|
438
|
+
const tabEl = dom.getTriggerEl(ctx2, value);
|
|
439
|
+
if (!tabEl)
|
|
440
|
+
return;
|
|
441
|
+
ctx2.indicatorRect = dom.getRectById(ctx2, value);
|
|
442
|
+
(0, import_dom_query3.nextTick)(() => {
|
|
443
|
+
ctx2.canIndicatorTransition = false;
|
|
444
|
+
});
|
|
445
|
+
},
|
|
446
|
+
syncIndicatorRect(ctx2) {
|
|
447
|
+
ctx2.indicatorCleanup?.();
|
|
448
|
+
const value = ctx2.value;
|
|
449
|
+
if (!ctx2.isIndicatorRendered || !value)
|
|
450
|
+
return;
|
|
451
|
+
const tabEl = dom.getActiveTabEl(ctx2);
|
|
452
|
+
if (!tabEl)
|
|
453
|
+
return;
|
|
454
|
+
ctx2.indicatorCleanup = (0, import_element_rect.trackElementRect)(tabEl, {
|
|
455
|
+
getRect(el) {
|
|
456
|
+
return dom.getOffsetRect(el);
|
|
457
|
+
},
|
|
458
|
+
onChange(rect) {
|
|
459
|
+
ctx2.indicatorRect = dom.resolveRect(rect, ctx2.orientation);
|
|
460
|
+
(0, import_dom_query3.nextTick)(() => {
|
|
461
|
+
ctx2.canIndicatorTransition = false;
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
});
|
|
423
465
|
}
|
|
424
466
|
}
|
|
425
467
|
}
|
|
426
468
|
);
|
|
427
469
|
}
|
|
428
470
|
function pushUnique(arr, value) {
|
|
429
|
-
const newArr = arr.slice();
|
|
471
|
+
const newArr = Array.from(arr).slice();
|
|
430
472
|
const index = newArr.indexOf(value);
|
|
431
473
|
if (index > -1) {
|
|
432
474
|
newArr.splice(index, 1);
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
connect
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-N7U3IQEQ.mjs";
|
|
4
4
|
import {
|
|
5
5
|
anatomy
|
|
6
6
|
} from "./chunk-S2KW2DT4.mjs";
|
|
7
7
|
import {
|
|
8
8
|
machine
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-N5FVPJXW.mjs";
|
|
10
|
+
import "./chunk-SVFEUEGP.mjs";
|
|
11
11
|
export {
|
|
12
12
|
anatomy,
|
|
13
13
|
connect,
|
package/dist/tabs.connect.d.ts
CHANGED
|
@@ -23,6 +23,10 @@ declare function connect<T extends PropTypes>(state: State, send: Send, normaliz
|
|
|
23
23
|
* Clears the value of the tabs.
|
|
24
24
|
*/
|
|
25
25
|
clearValue(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Sets the indicator rect to the tab with the given id.
|
|
28
|
+
*/
|
|
29
|
+
setIndicatorRect(id: string | null | undefined): void;
|
|
26
30
|
rootProps: T["element"];
|
|
27
31
|
tablistProps: T["element"];
|
|
28
32
|
getTriggerProps(props: TabProps): T["button"];
|
package/dist/tabs.connect.js
CHANGED
|
@@ -57,26 +57,31 @@ var dom = (0, import_dom_query.createScope)({
|
|
|
57
57
|
getActiveContentEl: (ctx) => {
|
|
58
58
|
if (!ctx.value)
|
|
59
59
|
return;
|
|
60
|
-
|
|
61
|
-
return dom.getById(ctx, id);
|
|
60
|
+
return dom.getContentEl(ctx, ctx.value);
|
|
62
61
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
getActiveTabEl: (ctx) => {
|
|
63
|
+
if (!ctx.value)
|
|
64
|
+
return;
|
|
65
|
+
return dom.getTriggerEl(ctx, ctx.value);
|
|
66
|
+
},
|
|
67
|
+
getOffsetRect: (el) => {
|
|
68
|
+
return {
|
|
69
|
+
left: el?.offsetLeft ?? 0,
|
|
70
|
+
top: el?.offsetTop ?? 0,
|
|
71
|
+
width: el?.offsetWidth ?? 0,
|
|
72
|
+
height: el?.offsetHeight ?? 0
|
|
69
73
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
},
|
|
75
|
+
getRectById: (ctx, id) => {
|
|
76
|
+
const tab = (0, import_dom_query.itemById)(dom.getElements(ctx), dom.getTriggerId(ctx, id));
|
|
77
|
+
return dom.resolveRect(dom.getOffsetRect(tab), ctx.orientation);
|
|
78
|
+
},
|
|
79
|
+
resolveRect(rect, orientation) {
|
|
80
|
+
const prop = orientation === "vertical" ? "height" : "width";
|
|
77
81
|
return {
|
|
78
|
-
left: `${
|
|
79
|
-
|
|
82
|
+
left: `${rect.left}px`,
|
|
83
|
+
top: `${rect.top}px`,
|
|
84
|
+
[prop]: `${rect[prop]}px`
|
|
80
85
|
};
|
|
81
86
|
}
|
|
82
87
|
});
|
|
@@ -110,6 +115,12 @@ function connect(state, send, normalize) {
|
|
|
110
115
|
clearValue() {
|
|
111
116
|
send({ type: "CLEAR_VALUE" });
|
|
112
117
|
},
|
|
118
|
+
/**
|
|
119
|
+
* Sets the indicator rect to the tab with the given id.
|
|
120
|
+
*/
|
|
121
|
+
setIndicatorRect(id) {
|
|
122
|
+
send({ type: "SET_INDICATOR_RECT", id });
|
|
123
|
+
},
|
|
113
124
|
rootProps: normalize.element({
|
|
114
125
|
...parts.root.attrs,
|
|
115
126
|
id: dom.getRootId(state.context),
|
|
@@ -216,12 +227,12 @@ function connect(state, send, normalize) {
|
|
|
216
227
|
...parts.indicator.attrs,
|
|
217
228
|
"data-orientation": state.context.orientation,
|
|
218
229
|
style: {
|
|
219
|
-
"--transition-duration": "
|
|
230
|
+
"--transition-duration": "150ms",
|
|
220
231
|
"--transition-property": "left, right, top, bottom, width, height",
|
|
221
232
|
position: "absolute",
|
|
222
233
|
willChange: "var(--transition-property)",
|
|
223
234
|
transitionProperty: "var(--transition-property)",
|
|
224
|
-
transitionDuration: state.context.
|
|
235
|
+
transitionDuration: state.context.canIndicatorTransition ? "var(--transition-duration)" : "0ms",
|
|
225
236
|
transitionTimingFunction: "var(--transition-timing-function)",
|
|
226
237
|
...state.context.indicatorRect
|
|
227
238
|
}
|
package/dist/tabs.connect.mjs
CHANGED
package/dist/tabs.dom.d.ts
CHANGED
|
@@ -38,16 +38,22 @@ declare const dom: {
|
|
|
38
38
|
getNextEl: (ctx: MachineContext, id: string) => HTMLElement;
|
|
39
39
|
getPrevEl: (ctx: MachineContext, id: string) => HTMLElement | null;
|
|
40
40
|
getActiveContentEl: (ctx: MachineContext) => HTMLElement | null | undefined;
|
|
41
|
+
getActiveTabEl: (ctx: MachineContext) => HTMLElement | null | undefined;
|
|
42
|
+
getOffsetRect: (el: HTMLElement | undefined) => {
|
|
43
|
+
left: number;
|
|
44
|
+
top: number;
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
};
|
|
41
48
|
getRectById: (ctx: MachineContext, id: string) => {
|
|
49
|
+
[x: string]: string;
|
|
50
|
+
left: string;
|
|
42
51
|
top: string;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} | {
|
|
52
|
+
};
|
|
53
|
+
resolveRect(rect: Record<"width" | "height" | "left" | "top", number>, orientation?: "horizontal" | "vertical"): {
|
|
54
|
+
[x: string]: string;
|
|
47
55
|
left: string;
|
|
48
|
-
|
|
49
|
-
top?: undefined;
|
|
50
|
-
height?: undefined;
|
|
56
|
+
top: string;
|
|
51
57
|
};
|
|
52
58
|
};
|
|
53
59
|
|
package/dist/tabs.dom.js
CHANGED
|
@@ -48,26 +48,31 @@ var dom = (0, import_dom_query.createScope)({
|
|
|
48
48
|
getActiveContentEl: (ctx) => {
|
|
49
49
|
if (!ctx.value)
|
|
50
50
|
return;
|
|
51
|
-
|
|
52
|
-
return dom.getById(ctx, id);
|
|
51
|
+
return dom.getContentEl(ctx, ctx.value);
|
|
53
52
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
getActiveTabEl: (ctx) => {
|
|
54
|
+
if (!ctx.value)
|
|
55
|
+
return;
|
|
56
|
+
return dom.getTriggerEl(ctx, ctx.value);
|
|
57
|
+
},
|
|
58
|
+
getOffsetRect: (el) => {
|
|
59
|
+
return {
|
|
60
|
+
left: el?.offsetLeft ?? 0,
|
|
61
|
+
top: el?.offsetTop ?? 0,
|
|
62
|
+
width: el?.offsetWidth ?? 0,
|
|
63
|
+
height: el?.offsetHeight ?? 0
|
|
60
64
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
},
|
|
66
|
+
getRectById: (ctx, id) => {
|
|
67
|
+
const tab = (0, import_dom_query.itemById)(dom.getElements(ctx), dom.getTriggerId(ctx, id));
|
|
68
|
+
return dom.resolveRect(dom.getOffsetRect(tab), ctx.orientation);
|
|
69
|
+
},
|
|
70
|
+
resolveRect(rect, orientation) {
|
|
71
|
+
const prop = orientation === "vertical" ? "height" : "width";
|
|
68
72
|
return {
|
|
69
|
-
left: `${
|
|
70
|
-
|
|
73
|
+
left: `${rect.left}px`,
|
|
74
|
+
top: `${rect.top}px`,
|
|
75
|
+
[prop]: `${rect[prop]}px`
|
|
71
76
|
};
|
|
72
77
|
}
|
|
73
78
|
});
|
package/dist/tabs.dom.mjs
CHANGED
package/dist/tabs.machine.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(tabs_machine_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(tabs_machine_exports);
|
|
26
26
|
var import_core = require("@zag-js/core");
|
|
27
27
|
var import_dom_query2 = require("@zag-js/dom-query");
|
|
28
|
+
var import_element_rect = require("@zag-js/element-rect");
|
|
28
29
|
var import_tabbable = require("@zag-js/tabbable");
|
|
29
30
|
var import_utils2 = require("@zag-js/utils");
|
|
30
31
|
|
|
@@ -54,26 +55,31 @@ var dom = (0, import_dom_query.createScope)({
|
|
|
54
55
|
getActiveContentEl: (ctx) => {
|
|
55
56
|
if (!ctx.value)
|
|
56
57
|
return;
|
|
57
|
-
|
|
58
|
-
return dom.getById(ctx, id);
|
|
58
|
+
return dom.getContentEl(ctx, ctx.value);
|
|
59
59
|
},
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
getActiveTabEl: (ctx) => {
|
|
61
|
+
if (!ctx.value)
|
|
62
|
+
return;
|
|
63
|
+
return dom.getTriggerEl(ctx, ctx.value);
|
|
64
|
+
},
|
|
65
|
+
getOffsetRect: (el) => {
|
|
66
|
+
return {
|
|
67
|
+
left: el?.offsetLeft ?? 0,
|
|
68
|
+
top: el?.offsetTop ?? 0,
|
|
69
|
+
width: el?.offsetWidth ?? 0,
|
|
70
|
+
height: el?.offsetHeight ?? 0
|
|
66
71
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
},
|
|
73
|
+
getRectById: (ctx, id) => {
|
|
74
|
+
const tab = (0, import_dom_query.itemById)(dom.getElements(ctx), dom.getTriggerId(ctx, id));
|
|
75
|
+
return dom.resolveRect(dom.getOffsetRect(tab), ctx.orientation);
|
|
76
|
+
},
|
|
77
|
+
resolveRect(rect, orientation) {
|
|
78
|
+
const prop = orientation === "vertical" ? "height" : "width";
|
|
74
79
|
return {
|
|
75
|
-
left: `${
|
|
76
|
-
|
|
80
|
+
left: `${rect.left}px`,
|
|
81
|
+
top: `${rect.top}px`,
|
|
82
|
+
[prop]: `${rect[prop]}px`
|
|
77
83
|
};
|
|
78
84
|
}
|
|
79
85
|
});
|
|
@@ -93,7 +99,7 @@ function machine(userContext) {
|
|
|
93
99
|
focusedValue: null,
|
|
94
100
|
previousValues: [],
|
|
95
101
|
indicatorRect: { left: "0px", top: "0px", width: "0px", height: "0px" },
|
|
96
|
-
|
|
102
|
+
canIndicatorTransition: false,
|
|
97
103
|
isIndicatorRendered: false,
|
|
98
104
|
loop: true,
|
|
99
105
|
translations: {},
|
|
@@ -104,10 +110,18 @@ function machine(userContext) {
|
|
|
104
110
|
isVertical: (ctx2) => ctx2.orientation === "vertical"
|
|
105
111
|
},
|
|
106
112
|
created: ["setPrevSelectedTabs"],
|
|
113
|
+
entry: ["checkRenderedElements", "syncIndicatorRect", "setContentTabIndex"],
|
|
114
|
+
exit: ["cleanupObserver"],
|
|
107
115
|
watch: {
|
|
108
116
|
focusedValue: "invokeOnFocus",
|
|
109
|
-
value: [
|
|
110
|
-
|
|
117
|
+
value: [
|
|
118
|
+
"enableIndicatorTransition",
|
|
119
|
+
"invokeOnChange",
|
|
120
|
+
"setPrevSelectedTabs",
|
|
121
|
+
"syncIndicatorRect",
|
|
122
|
+
"setContentTabIndex"
|
|
123
|
+
],
|
|
124
|
+
dir: ["syncIndicatorRect"]
|
|
111
125
|
},
|
|
112
126
|
on: {
|
|
113
127
|
SET_VALUE: {
|
|
@@ -115,9 +129,11 @@ function machine(userContext) {
|
|
|
115
129
|
},
|
|
116
130
|
CLEAR_VALUE: {
|
|
117
131
|
actions: "clearValue"
|
|
132
|
+
},
|
|
133
|
+
SET_INDICATOR_RECT: {
|
|
134
|
+
actions: "setIndicatorRect"
|
|
118
135
|
}
|
|
119
136
|
},
|
|
120
|
-
entry: ["checkRenderedElements", "setIndicatorRect", "setContentTabIndex"],
|
|
121
137
|
states: {
|
|
122
138
|
idle: {
|
|
123
139
|
on: {
|
|
@@ -198,9 +214,6 @@ function machine(userContext) {
|
|
|
198
214
|
clearValue(ctx2) {
|
|
199
215
|
ctx2.value = null;
|
|
200
216
|
},
|
|
201
|
-
invokeOnDelete(ctx2, evt) {
|
|
202
|
-
ctx2.onDelete?.({ value: evt.value });
|
|
203
|
-
},
|
|
204
217
|
focusFirstTab(ctx2) {
|
|
205
218
|
(0, import_dom_query2.raf)(() => dom.getFirstEl(ctx2)?.focus());
|
|
206
219
|
},
|
|
@@ -219,24 +232,9 @@ function machine(userContext) {
|
|
|
219
232
|
const prev = dom.getPrevEl(ctx2, ctx2.focusedValue);
|
|
220
233
|
(0, import_dom_query2.raf)(() => prev?.focus());
|
|
221
234
|
},
|
|
222
|
-
setIndicatorRect(ctx2) {
|
|
223
|
-
(0, import_dom_query2.nextTick)(() => {
|
|
224
|
-
if (!ctx2.isIndicatorRendered || !ctx2.value)
|
|
225
|
-
return;
|
|
226
|
-
ctx2.indicatorRect = dom.getRectById(ctx2, ctx2.value);
|
|
227
|
-
if (ctx2.hasMeasuredRect)
|
|
228
|
-
return;
|
|
229
|
-
(0, import_dom_query2.nextTick)(() => {
|
|
230
|
-
ctx2.hasMeasuredRect = true;
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
},
|
|
234
235
|
checkRenderedElements(ctx2) {
|
|
235
236
|
ctx2.isIndicatorRendered = !!dom.getIndicatorEl(ctx2);
|
|
236
237
|
},
|
|
237
|
-
clearMeasured(ctx2) {
|
|
238
|
-
ctx2.hasMeasuredRect = false;
|
|
239
|
-
},
|
|
240
238
|
invokeOnChange(ctx2) {
|
|
241
239
|
ctx2.onChange?.({ value: ctx2.value });
|
|
242
240
|
},
|
|
@@ -245,7 +243,7 @@ function machine(userContext) {
|
|
|
245
243
|
},
|
|
246
244
|
setPrevSelectedTabs(ctx2) {
|
|
247
245
|
if (ctx2.value != null) {
|
|
248
|
-
ctx2.previousValues = pushUnique(
|
|
246
|
+
ctx2.previousValues = pushUnique(ctx2.previousValues, ctx2.value);
|
|
249
247
|
}
|
|
250
248
|
},
|
|
251
249
|
// if tab panel contains focusable elements, remove the tabindex attribute
|
|
@@ -261,13 +259,51 @@ function machine(userContext) {
|
|
|
261
259
|
panel.setAttribute("tabindex", "0");
|
|
262
260
|
}
|
|
263
261
|
});
|
|
262
|
+
},
|
|
263
|
+
cleanupObserver(ctx2) {
|
|
264
|
+
ctx2.indicatorCleanup?.();
|
|
265
|
+
},
|
|
266
|
+
enableIndicatorTransition(ctx2) {
|
|
267
|
+
ctx2.canIndicatorTransition = true;
|
|
268
|
+
},
|
|
269
|
+
setIndicatorRect(ctx2, evt) {
|
|
270
|
+
const value = evt.id ?? ctx2.value;
|
|
271
|
+
if (!ctx2.isIndicatorRendered || !value)
|
|
272
|
+
return;
|
|
273
|
+
const tabEl = dom.getTriggerEl(ctx2, value);
|
|
274
|
+
if (!tabEl)
|
|
275
|
+
return;
|
|
276
|
+
ctx2.indicatorRect = dom.getRectById(ctx2, value);
|
|
277
|
+
(0, import_dom_query2.nextTick)(() => {
|
|
278
|
+
ctx2.canIndicatorTransition = false;
|
|
279
|
+
});
|
|
280
|
+
},
|
|
281
|
+
syncIndicatorRect(ctx2) {
|
|
282
|
+
ctx2.indicatorCleanup?.();
|
|
283
|
+
const value = ctx2.value;
|
|
284
|
+
if (!ctx2.isIndicatorRendered || !value)
|
|
285
|
+
return;
|
|
286
|
+
const tabEl = dom.getActiveTabEl(ctx2);
|
|
287
|
+
if (!tabEl)
|
|
288
|
+
return;
|
|
289
|
+
ctx2.indicatorCleanup = (0, import_element_rect.trackElementRect)(tabEl, {
|
|
290
|
+
getRect(el) {
|
|
291
|
+
return dom.getOffsetRect(el);
|
|
292
|
+
},
|
|
293
|
+
onChange(rect) {
|
|
294
|
+
ctx2.indicatorRect = dom.resolveRect(rect, ctx2.orientation);
|
|
295
|
+
(0, import_dom_query2.nextTick)(() => {
|
|
296
|
+
ctx2.canIndicatorTransition = false;
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
});
|
|
264
300
|
}
|
|
265
301
|
}
|
|
266
302
|
}
|
|
267
303
|
);
|
|
268
304
|
}
|
|
269
305
|
function pushUnique(arr, value) {
|
|
270
|
-
const newArr = arr.slice();
|
|
306
|
+
const newArr = Array.from(arr).slice();
|
|
271
307
|
const index = newArr.indexOf(value);
|
|
272
308
|
if (index > -1) {
|
|
273
309
|
newArr.splice(index, 1);
|
package/dist/tabs.machine.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zag-js/tabs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Core logic for the tabs widget implemented as a state machine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"js",
|
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@zag-js/anatomy": "0.1.4",
|
|
30
30
|
"@zag-js/dom-query": "0.1.4",
|
|
31
|
-
"@zag-js/dom-event": "0.
|
|
32
|
-
"@zag-js/
|
|
31
|
+
"@zag-js/dom-event": "0.8.0",
|
|
32
|
+
"@zag-js/element-rect": "0.8.0",
|
|
33
|
+
"@zag-js/tabbable": "0.8.0",
|
|
33
34
|
"@zag-js/utils": "0.3.4",
|
|
34
35
|
"@zag-js/core": "0.7.0",
|
|
35
36
|
"@zag-js/types": "0.5.0"
|