@zag-js/tabs 0.49.0 → 0.50.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/index.d.mts CHANGED
@@ -29,7 +29,7 @@ interface PublicContext extends DirectionProperty, CommonProperties {
29
29
  /**
30
30
  * Specifies the localized strings that identifies the accessibility elements and their states
31
31
  */
32
- translations: IntlTranslations;
32
+ translations?: IntlTranslations;
33
33
  /**
34
34
  * Whether the keyboard navigation will loop from last tab to first, and vice versa.
35
35
  * @default true
@@ -51,6 +51,7 @@ interface PublicContext extends DirectionProperty, CommonProperties {
51
51
  * The activation mode of the tabs. Can be `manual` or `automatic`
52
52
  * - `manual`: Tabs are activated when clicked or press `enter` key.
53
53
  * - `automatic`: Tabs are activated when receiving focus
54
+ *
54
55
  * @default "automatic"
55
56
  */
56
57
  activationMode?: "manual" | "automatic";
@@ -62,20 +63,13 @@ interface PublicContext extends DirectionProperty, CommonProperties {
62
63
  * Callback to be called when the focused tab changes
63
64
  */
64
65
  onFocusChange?: (details: FocusChangeDetails) => void;
65
- }
66
- type UserDefinedContext = RequiredBy<PublicContext, "id">;
67
- type ComputedContext = Readonly<{
68
- /**
69
- * @computed
70
- * Whether the tab is in the horizontal orientation
71
- */
72
- isHorizontal: boolean;
73
66
  /**
74
- * @computed
75
- * Whether the tab is in the vertical orientation
67
+ * Whether the tab is composite
76
68
  */
77
- isVertical: boolean;
78
- }>;
69
+ composite: boolean;
70
+ }
71
+ type UserDefinedContext = RequiredBy<PublicContext, "id">;
72
+ type ComputedContext = Readonly<{}>;
79
73
  interface PrivateContext {
80
74
  }
81
75
  interface MachineContext extends PublicContext, ComputedContext, PrivateContext {
@@ -136,6 +130,23 @@ interface MachineApi<T extends PropTypes = PropTypes> {
136
130
  * Sets the indicator rect to the tab with the given value
137
131
  */
138
132
  setIndicatorRect(value: string): void;
133
+ /**
134
+ * Synchronizes the tab index of the content element.
135
+ * Useful when rendering tabs within a select or combobox
136
+ */
137
+ syncTabIndex(): void;
138
+ /**
139
+ * Set focus on the selected tab trigger
140
+ */
141
+ focus(): void;
142
+ /**
143
+ * Selects the next tab
144
+ */
145
+ selectNext(fromValue?: string): void;
146
+ /**
147
+ * Selects the previous tab
148
+ */
149
+ selectPrev(fromValue?: string): void;
139
150
  /**
140
151
  * Returns the state of the trigger with the given props
141
152
  */
@@ -151,8 +162,8 @@ declare function connect<T extends PropTypes>(state: State, send: Send, normaliz
151
162
 
152
163
  declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<MachineContext, MachineState, _zag_js_core.StateMachine.AnyEventObject>;
153
164
 
154
- declare const props: ("value" | "dir" | "id" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "getRootNode")[];
155
- declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "value" | "dir" | "id" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "getRootNode">];
165
+ declare const props: ("value" | "dir" | "id" | "getRootNode" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "composite")[];
166
+ declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "value" | "dir" | "id" | "getRootNode" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "composite">];
156
167
  declare const triggerProps: (keyof TriggerProps)[];
157
168
  declare const splitTriggerProps: <Props extends TriggerProps>(props: Props) => [TriggerProps, Omit<Props, keyof TriggerProps>];
158
169
  declare const contentProps: "value"[];
package/dist/index.d.ts CHANGED
@@ -29,7 +29,7 @@ interface PublicContext extends DirectionProperty, CommonProperties {
29
29
  /**
30
30
  * Specifies the localized strings that identifies the accessibility elements and their states
31
31
  */
32
- translations: IntlTranslations;
32
+ translations?: IntlTranslations;
33
33
  /**
34
34
  * Whether the keyboard navigation will loop from last tab to first, and vice versa.
35
35
  * @default true
@@ -51,6 +51,7 @@ interface PublicContext extends DirectionProperty, CommonProperties {
51
51
  * The activation mode of the tabs. Can be `manual` or `automatic`
52
52
  * - `manual`: Tabs are activated when clicked or press `enter` key.
53
53
  * - `automatic`: Tabs are activated when receiving focus
54
+ *
54
55
  * @default "automatic"
55
56
  */
56
57
  activationMode?: "manual" | "automatic";
@@ -62,20 +63,13 @@ interface PublicContext extends DirectionProperty, CommonProperties {
62
63
  * Callback to be called when the focused tab changes
63
64
  */
64
65
  onFocusChange?: (details: FocusChangeDetails) => void;
65
- }
66
- type UserDefinedContext = RequiredBy<PublicContext, "id">;
67
- type ComputedContext = Readonly<{
68
- /**
69
- * @computed
70
- * Whether the tab is in the horizontal orientation
71
- */
72
- isHorizontal: boolean;
73
66
  /**
74
- * @computed
75
- * Whether the tab is in the vertical orientation
67
+ * Whether the tab is composite
76
68
  */
77
- isVertical: boolean;
78
- }>;
69
+ composite: boolean;
70
+ }
71
+ type UserDefinedContext = RequiredBy<PublicContext, "id">;
72
+ type ComputedContext = Readonly<{}>;
79
73
  interface PrivateContext {
80
74
  }
81
75
  interface MachineContext extends PublicContext, ComputedContext, PrivateContext {
@@ -136,6 +130,23 @@ interface MachineApi<T extends PropTypes = PropTypes> {
136
130
  * Sets the indicator rect to the tab with the given value
137
131
  */
138
132
  setIndicatorRect(value: string): void;
133
+ /**
134
+ * Synchronizes the tab index of the content element.
135
+ * Useful when rendering tabs within a select or combobox
136
+ */
137
+ syncTabIndex(): void;
138
+ /**
139
+ * Set focus on the selected tab trigger
140
+ */
141
+ focus(): void;
142
+ /**
143
+ * Selects the next tab
144
+ */
145
+ selectNext(fromValue?: string): void;
146
+ /**
147
+ * Selects the previous tab
148
+ */
149
+ selectPrev(fromValue?: string): void;
139
150
  /**
140
151
  * Returns the state of the trigger with the given props
141
152
  */
@@ -151,8 +162,8 @@ declare function connect<T extends PropTypes>(state: State, send: Send, normaliz
151
162
 
152
163
  declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<MachineContext, MachineState, _zag_js_core.StateMachine.AnyEventObject>;
153
164
 
154
- declare const props: ("value" | "dir" | "id" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "getRootNode")[];
155
- declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "value" | "dir" | "id" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "getRootNode">];
165
+ declare const props: ("value" | "dir" | "id" | "getRootNode" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "composite")[];
166
+ declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "value" | "dir" | "id" | "getRootNode" | "orientation" | "ids" | "translations" | "loopFocus" | "activationMode" | "onValueChange" | "onFocusChange" | "composite">];
156
167
  declare const triggerProps: (keyof TriggerProps)[];
157
168
  declare const splitTriggerProps: <Props extends TriggerProps>(props: Props) => [TriggerProps, Omit<Props, keyof TriggerProps>];
158
169
  declare const contentProps: "value"[];
package/dist/index.js CHANGED
@@ -59,16 +59,16 @@ var dom = (0, import_dom_query.createScope)({
59
59
  const selector = `[role=tab][data-ownedby='${ownerId}']:not([disabled])`;
60
60
  return (0, import_dom_query.queryAll)(dom.getListEl(ctx), selector);
61
61
  },
62
- getFirstEl: (ctx) => (0, import_utils.first)(dom.getElements(ctx)),
63
- getLastEl: (ctx) => (0, import_utils.last)(dom.getElements(ctx)),
64
- getNextEl: (ctx, id) => (0, import_dom_query.nextById)(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
65
- getPrevEl: (ctx, id) => (0, import_dom_query.prevById)(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
66
- getActiveContentEl: (ctx) => {
62
+ getFirstTriggerEl: (ctx) => (0, import_utils.first)(dom.getElements(ctx)),
63
+ getLastTriggerEl: (ctx) => (0, import_utils.last)(dom.getElements(ctx)),
64
+ getNextTriggerEl: (ctx, id) => (0, import_dom_query.nextById)(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
65
+ getPrevTriggerEl: (ctx, id) => (0, import_dom_query.prevById)(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
66
+ getSelectedContentEl: (ctx) => {
67
67
  if (!ctx.value)
68
68
  return;
69
69
  return dom.getContentEl(ctx, ctx.value);
70
70
  },
71
- getActiveTabEl: (ctx) => {
71
+ getSelectedTriggerEl: (ctx) => {
72
72
  if (!ctx.value)
73
73
  return;
74
74
  return dom.getTriggerEl(ctx, ctx.value);
@@ -97,6 +97,10 @@ var dom = (0, import_dom_query.createScope)({
97
97
  function connect(state, send, normalize) {
98
98
  const translations = state.context.translations;
99
99
  const focused = state.matches("focused");
100
+ const isVertical = state.context.orientation === "vertical";
101
+ const isHorizontal = state.context.orientation === "horizontal";
102
+ const composite = state.context.composite;
103
+ const indicator = state.context.indicatorState;
100
104
  function getTriggerState(props2) {
101
105
  return {
102
106
  selected: state.context.value === props2.value,
@@ -117,6 +121,20 @@ function connect(state, send, normalize) {
117
121
  const id = dom.getTriggerId(state.context, value);
118
122
  send({ type: "SET_INDICATOR_RECT", id });
119
123
  },
124
+ syncTabIndex() {
125
+ send("SYNC_TAB_INDEX");
126
+ },
127
+ selectNext(fromValue) {
128
+ send({ type: "TAB_FOCUS", value: fromValue, src: "selectNext" });
129
+ send({ type: "ARROW_NEXT", src: "selectNext" });
130
+ },
131
+ selectPrev(fromValue) {
132
+ send({ type: "TAB_FOCUS", value: fromValue, src: "selectPrev" });
133
+ send({ type: "ARROW_PREV", src: "selectPrev" });
134
+ },
135
+ focus() {
136
+ dom.getSelectedTriggerEl(state.context)?.focus();
137
+ },
120
138
  getTriggerState,
121
139
  rootProps: normalize.element({
122
140
  ...parts.root.attrs,
@@ -133,25 +151,35 @@ function connect(state, send, normalize) {
133
151
  "data-focus": (0, import_dom_query2.dataAttr)(focused),
134
152
  "aria-orientation": state.context.orientation,
135
153
  "data-orientation": state.context.orientation,
136
- "aria-label": translations.listLabel,
154
+ "aria-label": translations?.listLabel,
137
155
  onKeyDown(event) {
138
156
  if (event.defaultPrevented)
139
157
  return;
140
158
  const evt = (0, import_dom_event.getNativeEvent)(event);
141
159
  if (!(0, import_dom_query2.isSelfTarget)(evt))
142
160
  return;
161
+ if (evt.isComposing)
162
+ return;
143
163
  const keyMap = {
144
164
  ArrowDown() {
145
- send("ARROW_DOWN");
165
+ if (isHorizontal)
166
+ return;
167
+ send({ type: "ARROW_NEXT", key: "ArrowDown" });
146
168
  },
147
169
  ArrowUp() {
148
- send("ARROW_UP");
170
+ if (isHorizontal)
171
+ return;
172
+ send({ type: "ARROW_PREV", key: "ArrowUp" });
149
173
  },
150
174
  ArrowLeft() {
151
- send("ARROW_LEFT");
175
+ if (isVertical)
176
+ return;
177
+ send({ type: "ARROW_PREV", key: "ArrowLeft" });
152
178
  },
153
179
  ArrowRight() {
154
- send("ARROW_RIGHT");
180
+ if (isVertical)
181
+ return;
182
+ send({ type: "ARROW_NEXT", key: "ArrowRight" });
155
183
  },
156
184
  Home() {
157
185
  send("HOME");
@@ -160,7 +188,7 @@ function connect(state, send, normalize) {
160
188
  send("END");
161
189
  },
162
190
  Enter() {
163
- send({ type: "ENTER", value: state.context.focusedValue });
191
+ send({ type: "ENTER" });
164
192
  }
165
193
  };
166
194
  let key = (0, import_dom_event.getEventKey)(event, state.context);
@@ -187,10 +215,10 @@ function connect(state, send, normalize) {
187
215
  "aria-selected": triggerState.selected,
188
216
  "data-selected": (0, import_dom_query2.dataAttr)(triggerState.selected),
189
217
  "data-focus": (0, import_dom_query2.dataAttr)(triggerState.focused),
190
- "aria-controls": dom.getContentId(state.context, value),
218
+ "aria-controls": triggerState.selected ? dom.getContentId(state.context, value) : void 0,
191
219
  "data-ownedby": dom.getListId(state.context),
192
220
  id: dom.getTriggerId(state.context, value),
193
- tabIndex: triggerState.selected ? 0 : -1,
221
+ tabIndex: triggerState.selected && composite ? 0 : -1,
194
222
  onFocus() {
195
223
  send({ type: "TAB_FOCUS", value });
196
224
  },
@@ -219,7 +247,7 @@ function connect(state, send, normalize) {
219
247
  ...parts.content.attrs,
220
248
  dir: state.context.dir,
221
249
  id: dom.getContentId(state.context, value),
222
- tabIndex: 0,
250
+ tabIndex: composite ? 0 : -1,
223
251
  "aria-labelledby": dom.getTriggerId(state.context, value),
224
252
  role: "tabpanel",
225
253
  "data-ownedby": dom.getListId(state.context),
@@ -235,16 +263,16 @@ function connect(state, send, normalize) {
235
263
  "data-orientation": state.context.orientation,
236
264
  style: {
237
265
  "--transition-property": "left, right, top, bottom, width, height",
238
- "--left": state.context.indicatorRect?.left,
239
- "--top": state.context.indicatorRect?.top,
240
- "--width": state.context.indicatorRect?.width,
241
- "--height": state.context.indicatorRect?.height,
266
+ "--left": indicator.rect?.left,
267
+ "--top": indicator.rect?.top,
268
+ "--width": indicator.rect?.width,
269
+ "--height": indicator.rect?.height,
242
270
  position: "absolute",
243
271
  willChange: "var(--transition-property)",
244
272
  transitionProperty: "var(--transition-property)",
245
- transitionDuration: state.context.canIndicatorTransition ? "var(--transition-duration, 150ms)" : "0ms",
273
+ transitionDuration: indicator.transition ? "var(--transition-duration, 150ms)" : "0ms",
246
274
  transitionTimingFunction: "var(--transition-timing-function)",
247
- [state.context.orientation === "horizontal" ? "left" : "top"]: state.context.orientation === "horizontal" ? "var(--left)" : "var(--top)"
275
+ [isHorizontal ? "left" : "top"]: isHorizontal ? "var(--left)" : "var(--top)"
248
276
  }
249
277
  })
250
278
  };
@@ -255,7 +283,6 @@ var import_core = require("@zag-js/core");
255
283
  var import_dom_event2 = require("@zag-js/dom-event");
256
284
  var import_dom_query3 = require("@zag-js/dom-query");
257
285
  var import_element_rect = require("@zag-js/element-rect");
258
- var import_tabbable = require("@zag-js/tabbable");
259
286
  var import_utils2 = require("@zag-js/utils");
260
287
  var { not } = import_core.guards;
261
288
  function machine(userContext) {
@@ -268,27 +295,18 @@ function machine(userContext) {
268
295
  orientation: "horizontal",
269
296
  activationMode: "automatic",
270
297
  value: null,
271
- focusedValue: null,
272
- indicatorRect: {
273
- left: "0px",
274
- top: "0px",
275
- width: "0px",
276
- height: "0px"
277
- },
278
- canIndicatorTransition: false,
279
- isIndicatorRendered: false,
280
298
  loopFocus: true,
281
- translations: {},
282
- ...ctx
283
- },
284
- computed: {
285
- isHorizontal: (ctx2) => ctx2.orientation === "horizontal",
286
- isVertical: (ctx2) => ctx2.orientation === "vertical"
299
+ composite: true,
300
+ ...ctx,
301
+ focusedValue: ctx.value ?? null,
302
+ indicatorState: {
303
+ rendered: false,
304
+ transition: false,
305
+ rect: { left: "0px", top: "0px", width: "0px", height: "0px" }
306
+ }
287
307
  },
288
- entry: ["checkRenderedElements", "syncIndicatorRect", "setContentTabIndex"],
289
- exit: ["cleanupObserver"],
290
308
  watch: {
291
- value: ["enableIndicatorTransition", "syncIndicatorRect", "setContentTabIndex", "clickIfLink"],
309
+ value: ["allowIndicatorTransition", "syncIndicatorRect", "syncTabIndex", "clickIfLink"],
292
310
  dir: ["syncIndicatorRect"],
293
311
  orientation: ["syncIndicatorRect"]
294
312
  },
@@ -301,22 +319,21 @@ function machine(userContext) {
301
319
  },
302
320
  SET_INDICATOR_RECT: {
303
321
  actions: "setIndicatorRect"
322
+ },
323
+ SYNC_TAB_INDEX: {
324
+ actions: "syncTabIndex"
304
325
  }
305
326
  },
327
+ created: ["syncFocusedValue"],
328
+ entry: ["checkRenderedElements", "syncIndicatorRect", "syncTabIndex"],
329
+ exit: ["cleanupObserver"],
306
330
  states: {
307
331
  idle: {
308
332
  on: {
309
- TAB_FOCUS: [
310
- {
311
- guard: "selectOnFocus",
312
- target: "focused",
313
- actions: ["setFocusedValue", "setValue"]
314
- },
315
- {
316
- target: "focused",
317
- actions: "setFocusedValue"
318
- }
319
- ],
333
+ TAB_FOCUS: {
334
+ target: "focused",
335
+ actions: "setFocusedValue"
336
+ },
320
337
  TAB_CLICK: {
321
338
  target: "focused",
322
339
  actions: ["setFocusedValue", "setValue"]
@@ -329,39 +346,49 @@ function machine(userContext) {
329
346
  target: "focused",
330
347
  actions: ["setFocusedValue", "setValue"]
331
348
  },
332
- ARROW_LEFT: {
333
- guard: "isHorizontal",
334
- actions: "focusPrevTab"
335
- },
336
- ARROW_RIGHT: {
337
- guard: "isHorizontal",
338
- actions: "focusNextTab"
339
- },
340
- ARROW_UP: {
341
- guard: "isVertical",
342
- actions: "focusPrevTab"
343
- },
344
- ARROW_DOWN: {
345
- guard: "isVertical",
346
- actions: "focusNextTab"
347
- },
348
- HOME: {
349
- actions: "focusFirstTab"
350
- },
351
- END: {
352
- actions: "focusLastTab"
353
- },
354
- ENTER: {
355
- guard: not("selectOnFocus"),
356
- actions: "setValue"
357
- },
358
- TAB_FOCUS: [
349
+ ARROW_PREV: [
350
+ {
351
+ guard: "selectOnFocus",
352
+ actions: ["focusPrevTab", "selectFocusedTab"]
353
+ },
354
+ {
355
+ actions: "focusPrevTab"
356
+ }
357
+ ],
358
+ ARROW_NEXT: [
359
+ {
360
+ guard: "selectOnFocus",
361
+ actions: ["focusNextTab", "selectFocusedTab"]
362
+ },
363
+ {
364
+ actions: "focusNextTab"
365
+ }
366
+ ],
367
+ HOME: [
368
+ {
369
+ guard: "selectOnFocus",
370
+ actions: ["focusFirstTab", "selectFocusedTab"]
371
+ },
372
+ {
373
+ actions: "focusFirstTab"
374
+ }
375
+ ],
376
+ END: [
359
377
  {
360
378
  guard: "selectOnFocus",
361
- actions: ["setFocusedValue", "setValue"]
379
+ actions: ["focusLastTab", "selectFocusedTab"]
362
380
  },
363
- { actions: "setFocusedValue" }
381
+ {
382
+ actions: "focusLastTab"
383
+ }
364
384
  ],
385
+ ENTER: {
386
+ guard: not("selectOnFocus"),
387
+ actions: "selectFocusedTab"
388
+ },
389
+ TAB_FOCUS: {
390
+ actions: ["setFocusedValue"]
391
+ },
365
392
  TAB_BLUR: {
366
393
  target: "idle",
367
394
  actions: "clearFocusedValue"
@@ -372,12 +399,22 @@ function machine(userContext) {
372
399
  },
373
400
  {
374
401
  guards: {
375
- isVertical: (ctx2) => ctx2.isVertical,
376
- isHorizontal: (ctx2) => ctx2.isHorizontal,
377
402
  selectOnFocus: (ctx2) => ctx2.activationMode === "automatic"
378
403
  },
379
404
  actions: {
405
+ syncFocusedValue(ctx2) {
406
+ if (ctx2.value != null && ctx2.focusedValue == null) {
407
+ ctx2.focusedValue = ctx2.value;
408
+ }
409
+ },
410
+ selectFocusedTab(ctx2) {
411
+ (0, import_dom_query3.raf)(() => {
412
+ set.value(ctx2, ctx2.focusedValue);
413
+ });
414
+ },
380
415
  setFocusedValue(ctx2, evt) {
416
+ if (evt.value == null)
417
+ return;
381
418
  set.focusedValue(ctx2, evt.value);
382
419
  },
383
420
  clearFocusedValue(ctx2) {
@@ -390,80 +427,95 @@ function machine(userContext) {
390
427
  set.value(ctx2, null);
391
428
  },
392
429
  focusFirstTab(ctx2) {
393
- (0, import_dom_query3.raf)(() => dom.getFirstEl(ctx2)?.focus());
430
+ (0, import_dom_query3.raf)(() => {
431
+ dom.getFirstTriggerEl(ctx2)?.focus();
432
+ });
394
433
  },
395
434
  focusLastTab(ctx2) {
396
- (0, import_dom_query3.raf)(() => dom.getLastEl(ctx2)?.focus());
435
+ (0, import_dom_query3.raf)(() => {
436
+ dom.getLastTriggerEl(ctx2)?.focus();
437
+ });
397
438
  },
398
439
  focusNextTab(ctx2) {
399
440
  if (!ctx2.focusedValue)
400
441
  return;
401
- const next = dom.getNextEl(ctx2, ctx2.focusedValue);
402
- (0, import_dom_query3.raf)(() => next?.focus());
442
+ const triggerEl = dom.getNextTriggerEl(ctx2, ctx2.focusedValue);
443
+ (0, import_dom_query3.raf)(() => {
444
+ if (ctx2.composite) {
445
+ triggerEl?.focus();
446
+ } else if (triggerEl?.dataset.value != null) {
447
+ set.focusedValue(ctx2, triggerEl.dataset.value);
448
+ }
449
+ });
403
450
  },
404
451
  focusPrevTab(ctx2) {
405
452
  if (!ctx2.focusedValue)
406
453
  return;
407
- const prev = dom.getPrevEl(ctx2, ctx2.focusedValue);
408
- (0, import_dom_query3.raf)(() => prev?.focus());
454
+ const triggerEl = dom.getPrevTriggerEl(ctx2, ctx2.focusedValue);
455
+ (0, import_dom_query3.raf)(() => {
456
+ if (ctx2.composite) {
457
+ triggerEl?.focus();
458
+ } else if (triggerEl?.dataset.value != null) {
459
+ set.focusedValue(ctx2, triggerEl.dataset.value);
460
+ }
461
+ });
409
462
  },
410
463
  checkRenderedElements(ctx2) {
411
- ctx2.isIndicatorRendered = !!dom.getIndicatorEl(ctx2);
464
+ ctx2.indicatorState.rendered = !!dom.getIndicatorEl(ctx2);
412
465
  },
413
- // if tab panel contains focusable elements, remove the tabindex attribute
414
- setContentTabIndex(ctx2) {
466
+ syncTabIndex(ctx2) {
415
467
  (0, import_dom_query3.raf)(() => {
416
- const panel = dom.getActiveContentEl(ctx2);
417
- if (!panel)
468
+ const contentEl = dom.getSelectedContentEl(ctx2);
469
+ if (!contentEl)
418
470
  return;
419
- const focusables = (0, import_tabbable.getFocusables)(panel);
471
+ const focusables = (0, import_dom_query3.getFocusables)(contentEl);
420
472
  if (focusables.length > 0) {
421
- panel.removeAttribute("tabindex");
473
+ contentEl.removeAttribute("tabindex");
422
474
  } else {
423
- panel.setAttribute("tabindex", "0");
475
+ contentEl.setAttribute("tabindex", "0");
424
476
  }
425
477
  });
426
478
  },
427
479
  cleanupObserver(ctx2) {
428
480
  ctx2.indicatorCleanup?.();
429
481
  },
430
- enableIndicatorTransition(ctx2) {
431
- ctx2.canIndicatorTransition = true;
482
+ allowIndicatorTransition(ctx2) {
483
+ ctx2.indicatorState.transition = true;
432
484
  },
433
485
  setIndicatorRect(ctx2, evt) {
434
486
  const value = evt.id ?? ctx2.value;
435
- if (!ctx2.isIndicatorRendered || !value)
487
+ if (!ctx2.indicatorState.rendered || !value)
436
488
  return;
437
- const tabEl = dom.getTriggerEl(ctx2, value);
438
- if (!tabEl)
489
+ const triggerEl = dom.getTriggerEl(ctx2, value);
490
+ if (!triggerEl)
439
491
  return;
440
- ctx2.indicatorRect = dom.getRectById(ctx2, value);
492
+ ctx2.indicatorState.rect = dom.getRectById(ctx2, value);
441
493
  (0, import_dom_query3.nextTick)(() => {
442
- ctx2.canIndicatorTransition = false;
494
+ ctx2.indicatorState.transition = false;
443
495
  });
444
496
  },
445
497
  syncIndicatorRect(ctx2) {
446
498
  ctx2.indicatorCleanup?.();
447
499
  const value = ctx2.value;
448
- if (!ctx2.isIndicatorRendered || !value)
500
+ if (!ctx2.indicatorState.rendered || !value)
449
501
  return;
450
- const tabEl = dom.getActiveTabEl(ctx2);
451
- if (!tabEl)
502
+ const triggerEl = dom.getSelectedTriggerEl(ctx2);
503
+ if (!triggerEl)
452
504
  return;
453
- ctx2.indicatorCleanup = (0, import_element_rect.trackElementRect)(tabEl, {
505
+ ctx2.indicatorCleanup = (0, import_element_rect.trackElementRect)(triggerEl, {
454
506
  getRect(el) {
455
507
  return dom.getOffsetRect(el);
456
508
  },
457
509
  onChange(rect) {
458
- ctx2.indicatorRect = dom.resolveRect(rect);
510
+ ctx2.indicatorState.rect = dom.resolveRect(rect);
459
511
  (0, import_dom_query3.nextTick)(() => {
460
- ctx2.canIndicatorTransition = false;
512
+ ctx2.indicatorState.transition = false;
461
513
  });
462
514
  }
463
515
  });
464
516
  },
465
517
  clickIfLink(ctx2) {
466
- (0, import_dom_event2.clickIfLink)(dom.getActiveTabEl(ctx2));
518
+ (0, import_dom_event2.clickIfLink)(dom.getSelectedTriggerEl(ctx2));
467
519
  }
468
520
  }
469
521
  }
@@ -501,6 +553,7 @@ var import_types = require("@zag-js/types");
501
553
  var import_utils3 = require("@zag-js/utils");
502
554
  var props = (0, import_types.createProps)()([
503
555
  "activationMode",
556
+ "composite",
504
557
  "dir",
505
558
  "getRootNode",
506
559
  "id",