@zag-js/tabs 0.52.0 → 0.54.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.mjs CHANGED
@@ -1,2 +1,555 @@
1
- import{createAnatomy}from"@zag-js/anatomy";var anatomy=createAnatomy("tabs").parts("root","list","trigger","content","indicator");var parts=anatomy.build();import{getEventKey}from"@zag-js/dom-event";import{dataAttr,isComposingEvent,isSafari,isSelfTarget}from"@zag-js/dom-query";import{createScope,itemById,nextById,prevById,queryAll}from"@zag-js/dom-query";import{first,last}from"@zag-js/utils";var dom=createScope({getRootId:ctx=>ctx.ids?.root??`tabs:${ctx.id}`,getListId:ctx=>ctx.ids?.list??`tabs:${ctx.id}:list`,getContentId:(ctx,id)=>ctx.ids?.content??`tabs:${ctx.id}:content-${id}`,getTriggerId:(ctx,id)=>ctx.ids?.trigger??`tabs:${ctx.id}:trigger-${id}`,getIndicatorId:ctx=>ctx.ids?.indicator??`tabs:${ctx.id}:indicator`,getListEl:ctx=>dom.getById(ctx,dom.getListId(ctx)),getContentEl:(ctx,id)=>dom.getById(ctx,dom.getContentId(ctx,id)),getTriggerEl:(ctx,id)=>dom.getById(ctx,dom.getTriggerId(ctx,id)),getIndicatorEl:ctx=>dom.getById(ctx,dom.getIndicatorId(ctx)),getElements:ctx=>{const ownerId=CSS.escape(dom.getListId(ctx));const selector=`[role=tab][data-ownedby='${ownerId}']:not([disabled])`;return queryAll(dom.getListEl(ctx),selector)},getFirstTriggerEl:ctx=>first(dom.getElements(ctx)),getLastTriggerEl:ctx=>last(dom.getElements(ctx)),getNextTriggerEl:(ctx,id)=>nextById(dom.getElements(ctx),dom.getTriggerId(ctx,id),ctx.loopFocus),getPrevTriggerEl:(ctx,id)=>prevById(dom.getElements(ctx),dom.getTriggerId(ctx,id),ctx.loopFocus),getSelectedContentEl:ctx=>{if(!ctx.value)return;return dom.getContentEl(ctx,ctx.value)},getSelectedTriggerEl:ctx=>{if(!ctx.value)return;return dom.getTriggerEl(ctx,ctx.value)},getOffsetRect:el=>{return{left:el?.offsetLeft??0,top:el?.offsetTop??0,width:el?.offsetWidth??0,height:el?.offsetHeight??0}},getRectById:(ctx,id)=>{const tab=itemById(dom.getElements(ctx),dom.getTriggerId(ctx,id));return dom.resolveRect(dom.getOffsetRect(tab))},resolveRect:rect=>({width:`${rect.width}px`,height:`${rect.height}px`,left:`${rect.left}px`,top:`${rect.top}px`})});function connect(state,send,normalize){const translations=state.context.translations;const focused=state.matches("focused");const isVertical=state.context.orientation==="vertical";const isHorizontal=state.context.orientation==="horizontal";const composite=state.context.composite;const indicator=state.context.indicatorState;function getTriggerState(props2){return{selected:state.context.value===props2.value,focused:state.context.focusedValue===props2.value,disabled:!!props2.disabled}}return{value:state.context.value,focusedValue:state.context.focusedValue,setValue(value){send({type:"SET_VALUE",value})},clearValue(){send({type:"CLEAR_VALUE"})},setIndicatorRect(value){const id=dom.getTriggerId(state.context,value);send({type:"SET_INDICATOR_RECT",id})},syncTabIndex(){send("SYNC_TAB_INDEX")},selectNext(fromValue){send({type:"TAB_FOCUS",value:fromValue,src:"selectNext"});send({type:"ARROW_NEXT",src:"selectNext"})},selectPrev(fromValue){send({type:"TAB_FOCUS",value:fromValue,src:"selectPrev"});send({type:"ARROW_PREV",src:"selectPrev"})},focus(){dom.getSelectedTriggerEl(state.context)?.focus()},getTriggerState,rootProps:normalize.element({...parts.root.attrs,id:dom.getRootId(state.context),"data-orientation":state.context.orientation,"data-focus":dataAttr(focused),dir:state.context.dir}),listProps:normalize.element({...parts.list.attrs,id:dom.getListId(state.context),role:"tablist",dir:state.context.dir,"data-focus":dataAttr(focused),"aria-orientation":state.context.orientation,"data-orientation":state.context.orientation,"aria-label":translations?.listLabel,onKeyDown(event){if(event.defaultPrevented)return;if(!isSelfTarget(event))return;if(isComposingEvent(event))return;const keyMap={ArrowDown(){if(isHorizontal)return;send({type:"ARROW_NEXT",key:"ArrowDown"})},ArrowUp(){if(isHorizontal)return;send({type:"ARROW_PREV",key:"ArrowUp"})},ArrowLeft(){if(isVertical)return;send({type:"ARROW_PREV",key:"ArrowLeft"})},ArrowRight(){if(isVertical)return;send({type:"ARROW_NEXT",key:"ArrowRight"})},Home(){send("HOME")},End(){send("END")},Enter(){send({type:"ENTER"})}};let key=getEventKey(event,state.context);const exec=keyMap[key];if(exec){event.preventDefault();exec(event)}}}),getTriggerProps(props2){const{value,disabled}=props2;const triggerState=getTriggerState(props2);return normalize.button({...parts.trigger.attrs,role:"tab",type:"button",disabled,dir:state.context.dir,"data-orientation":state.context.orientation,"data-disabled":dataAttr(disabled),"aria-disabled":disabled,"data-value":value,"aria-selected":triggerState.selected,"data-selected":dataAttr(triggerState.selected),"data-focus":dataAttr(triggerState.focused),"aria-controls":triggerState.selected?dom.getContentId(state.context,value):void 0,"data-ownedby":dom.getListId(state.context),id:dom.getTriggerId(state.context,value),tabIndex:triggerState.selected&&composite?0:-1,onFocus(){send({type:"TAB_FOCUS",value})},onBlur(event){const target=event.relatedTarget;if(target?.getAttribute("role")!=="tab"){send({type:"TAB_BLUR"})}},onClick(event){if(event.defaultPrevented)return;if(disabled)return;if(isSafari()){event.currentTarget.focus()}send({type:"TAB_CLICK",value})}})},getContentProps(props2){const{value}=props2;const selected=state.context.value===value;return normalize.element({...parts.content.attrs,dir:state.context.dir,id:dom.getContentId(state.context,value),tabIndex:composite?0:-1,"aria-labelledby":dom.getTriggerId(state.context,value),role:"tabpanel","data-ownedby":dom.getListId(state.context),"data-selected":dataAttr(selected),"data-orientation":state.context.orientation,hidden:!selected})},indicatorProps:normalize.element({id:dom.getIndicatorId(state.context),...parts.indicator.attrs,dir:state.context.dir,"data-orientation":state.context.orientation,style:{"--transition-property":"left, right, top, bottom, width, height","--left":indicator.rect?.left,"--top":indicator.rect?.top,"--width":indicator.rect?.width,"--height":indicator.rect?.height,position:"absolute",willChange:"var(--transition-property)",transitionProperty:"var(--transition-property)",transitionDuration:indicator.transition?"var(--transition-duration, 150ms)":"0ms",transitionTimingFunction:"var(--transition-timing-function)",[isHorizontal?"left":"top"]:isHorizontal?"var(--left)":"var(--top)"}})}}import{createMachine,guards}from"@zag-js/core";import{clickIfLink}from"@zag-js/dom-event";import{nextTick,raf,getFocusables}from"@zag-js/dom-query";import{trackElementRect}from"@zag-js/element-rect";import{compact,isEqual}from"@zag-js/utils";var{not}=guards;function machine(userContext){const ctx=compact(userContext);return createMachine({initial:"idle",context:{dir:"ltr",orientation:"horizontal",activationMode:"automatic",value:null,loopFocus:true,composite:true,...ctx,focusedValue:ctx.value??null,indicatorState:{rendered:false,transition:false,rect:{left:"0px",top:"0px",width:"0px",height:"0px"}}},watch:{value:["allowIndicatorTransition","syncIndicatorRect","syncTabIndex","clickIfLink"],dir:["syncIndicatorRect"],orientation:["syncIndicatorRect"]},on:{SET_VALUE:{actions:"setValue"},CLEAR_VALUE:{actions:"clearValue"},SET_INDICATOR_RECT:{actions:"setIndicatorRect"},SYNC_TAB_INDEX:{actions:"syncTabIndex"}},created:["syncFocusedValue"],entry:["checkRenderedElements","syncIndicatorRect","syncTabIndex"],exit:["cleanupObserver"],states:{idle:{on:{TAB_FOCUS:{target:"focused",actions:"setFocusedValue"},TAB_CLICK:{target:"focused",actions:["setFocusedValue","setValue"]}}},focused:{on:{TAB_CLICK:{target:"focused",actions:["setFocusedValue","setValue"]},ARROW_PREV:[{guard:"selectOnFocus",actions:["focusPrevTab","selectFocusedTab"]},{actions:"focusPrevTab"}],ARROW_NEXT:[{guard:"selectOnFocus",actions:["focusNextTab","selectFocusedTab"]},{actions:"focusNextTab"}],HOME:[{guard:"selectOnFocus",actions:["focusFirstTab","selectFocusedTab"]},{actions:"focusFirstTab"}],END:[{guard:"selectOnFocus",actions:["focusLastTab","selectFocusedTab"]},{actions:"focusLastTab"}],ENTER:{guard:not("selectOnFocus"),actions:"selectFocusedTab"},TAB_FOCUS:{actions:["setFocusedValue"]},TAB_BLUR:{target:"idle",actions:"clearFocusedValue"}}}}},{guards:{selectOnFocus:ctx2=>ctx2.activationMode==="automatic"},actions:{syncFocusedValue(ctx2){if(ctx2.value!=null&&ctx2.focusedValue==null){ctx2.focusedValue=ctx2.value}},selectFocusedTab(ctx2){raf(()=>{set.value(ctx2,ctx2.focusedValue)})},setFocusedValue(ctx2,evt){if(evt.value==null)return;set.focusedValue(ctx2,evt.value)},clearFocusedValue(ctx2){set.focusedValue(ctx2,null)},setValue(ctx2,evt){set.value(ctx2,evt.value)},clearValue(ctx2){set.value(ctx2,null)},focusFirstTab(ctx2){raf(()=>{dom.getFirstTriggerEl(ctx2)?.focus()})},focusLastTab(ctx2){raf(()=>{dom.getLastTriggerEl(ctx2)?.focus()})},focusNextTab(ctx2){if(!ctx2.focusedValue)return;const triggerEl=dom.getNextTriggerEl(ctx2,ctx2.focusedValue);raf(()=>{if(ctx2.composite){triggerEl?.focus()}else if(triggerEl?.dataset.value!=null){set.focusedValue(ctx2,triggerEl.dataset.value)}})},focusPrevTab(ctx2){if(!ctx2.focusedValue)return;const triggerEl=dom.getPrevTriggerEl(ctx2,ctx2.focusedValue);raf(()=>{if(ctx2.composite){triggerEl?.focus()}else if(triggerEl?.dataset.value!=null){set.focusedValue(ctx2,triggerEl.dataset.value)}})},checkRenderedElements(ctx2){ctx2.indicatorState.rendered=!!dom.getIndicatorEl(ctx2)},syncTabIndex(ctx2){raf(()=>{const contentEl=dom.getSelectedContentEl(ctx2);if(!contentEl)return;const focusables=getFocusables(contentEl);if(focusables.length>0){contentEl.removeAttribute("tabindex")}else{contentEl.setAttribute("tabindex","0")}})},cleanupObserver(ctx2){ctx2.indicatorCleanup?.()},allowIndicatorTransition(ctx2){ctx2.indicatorState.transition=true},setIndicatorRect(ctx2,evt){const value=evt.id??ctx2.value;if(!ctx2.indicatorState.rendered||!value)return;const triggerEl=dom.getTriggerEl(ctx2,value);if(!triggerEl)return;ctx2.indicatorState.rect=dom.getRectById(ctx2,value);nextTick(()=>{ctx2.indicatorState.transition=false})},syncIndicatorRect(ctx2){ctx2.indicatorCleanup?.();const value=ctx2.value;if(!ctx2.indicatorState.rendered||!value)return;const triggerEl=dom.getSelectedTriggerEl(ctx2);if(!triggerEl)return;ctx2.indicatorCleanup=trackElementRect(triggerEl,{getRect(el){return dom.getOffsetRect(el)},onChange(rect){ctx2.indicatorState.rect=dom.resolveRect(rect);nextTick(()=>{ctx2.indicatorState.transition=false})}})},clickIfLink(ctx2){clickIfLink(dom.getSelectedTriggerEl(ctx2))}}})}var invoke={change:ctx=>{if(ctx.value==null)return;ctx.onValueChange?.({value:ctx.value})},focusChange:ctx=>{if(ctx.focusedValue==null)return;ctx.onFocusChange?.({focusedValue:ctx.focusedValue})}};var set={value:(ctx,value)=>{if(isEqual(value,ctx.value))return;ctx.value=value;invoke.change(ctx)},focusedValue:(ctx,value)=>{if(isEqual(value,ctx.focusedValue))return;ctx.focusedValue=value;invoke.focusChange(ctx)}};import{createProps}from"@zag-js/types";import{createSplitProps}from"@zag-js/utils";var props=createProps()(["activationMode","composite","dir","getRootNode","id","ids","loopFocus","onFocusChange","onValueChange","orientation","translations","value"]);var splitProps=createSplitProps(props);var triggerProps=createProps()(["disabled","value"]);var splitTriggerProps=createSplitProps(triggerProps);var contentProps=createProps()(["value"]);var splitContentProps=createSplitProps(contentProps);export{anatomy,connect,contentProps,machine,props,splitContentProps,splitProps,splitTriggerProps,triggerProps};
1
+ // src/tabs.anatomy.ts
2
+ import { createAnatomy } from "@zag-js/anatomy";
3
+ var anatomy = createAnatomy("tabs").parts("root", "list", "trigger", "content", "indicator");
4
+ var parts = anatomy.build();
5
+
6
+ // src/tabs.connect.ts
7
+ import { getEventKey } from "@zag-js/dom-event";
8
+ import { dataAttr, isComposingEvent, isSafari, isSelfTarget } from "@zag-js/dom-query";
9
+
10
+ // src/tabs.dom.ts
11
+ import { createScope, itemById, nextById, prevById, queryAll } from "@zag-js/dom-query";
12
+ import { first, last } from "@zag-js/utils";
13
+ var dom = createScope({
14
+ getRootId: (ctx) => ctx.ids?.root ?? `tabs:${ctx.id}`,
15
+ getListId: (ctx) => ctx.ids?.list ?? `tabs:${ctx.id}:list`,
16
+ getContentId: (ctx, id) => ctx.ids?.content ?? `tabs:${ctx.id}:content-${id}`,
17
+ getTriggerId: (ctx, id) => ctx.ids?.trigger ?? `tabs:${ctx.id}:trigger-${id}`,
18
+ getIndicatorId: (ctx) => ctx.ids?.indicator ?? `tabs:${ctx.id}:indicator`,
19
+ getListEl: (ctx) => dom.getById(ctx, dom.getListId(ctx)),
20
+ getContentEl: (ctx, id) => dom.getById(ctx, dom.getContentId(ctx, id)),
21
+ getTriggerEl: (ctx, id) => dom.getById(ctx, dom.getTriggerId(ctx, id)),
22
+ getIndicatorEl: (ctx) => dom.getById(ctx, dom.getIndicatorId(ctx)),
23
+ getElements: (ctx) => {
24
+ const ownerId = CSS.escape(dom.getListId(ctx));
25
+ const selector = `[role=tab][data-ownedby='${ownerId}']:not([disabled])`;
26
+ return queryAll(dom.getListEl(ctx), selector);
27
+ },
28
+ getFirstTriggerEl: (ctx) => first(dom.getElements(ctx)),
29
+ getLastTriggerEl: (ctx) => last(dom.getElements(ctx)),
30
+ getNextTriggerEl: (ctx, id) => nextById(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
31
+ getPrevTriggerEl: (ctx, id) => prevById(dom.getElements(ctx), dom.getTriggerId(ctx, id), ctx.loopFocus),
32
+ getSelectedContentEl: (ctx) => {
33
+ if (!ctx.value)
34
+ return;
35
+ return dom.getContentEl(ctx, ctx.value);
36
+ },
37
+ getSelectedTriggerEl: (ctx) => {
38
+ if (!ctx.value)
39
+ return;
40
+ return dom.getTriggerEl(ctx, ctx.value);
41
+ },
42
+ getOffsetRect: (el) => {
43
+ return {
44
+ left: el?.offsetLeft ?? 0,
45
+ top: el?.offsetTop ?? 0,
46
+ width: el?.offsetWidth ?? 0,
47
+ height: el?.offsetHeight ?? 0
48
+ };
49
+ },
50
+ getRectById: (ctx, id) => {
51
+ const tab = itemById(dom.getElements(ctx), dom.getTriggerId(ctx, id));
52
+ return dom.resolveRect(dom.getOffsetRect(tab));
53
+ },
54
+ resolveRect: (rect) => ({
55
+ width: `${rect.width}px`,
56
+ height: `${rect.height}px`,
57
+ left: `${rect.left}px`,
58
+ top: `${rect.top}px`
59
+ })
60
+ });
61
+
62
+ // src/tabs.connect.ts
63
+ function connect(state, send, normalize) {
64
+ const translations = state.context.translations;
65
+ const focused = state.matches("focused");
66
+ const isVertical = state.context.orientation === "vertical";
67
+ const isHorizontal = state.context.orientation === "horizontal";
68
+ const composite = state.context.composite;
69
+ const indicator = state.context.indicatorState;
70
+ function getTriggerState(props2) {
71
+ return {
72
+ selected: state.context.value === props2.value,
73
+ focused: state.context.focusedValue === props2.value,
74
+ disabled: !!props2.disabled
75
+ };
76
+ }
77
+ return {
78
+ value: state.context.value,
79
+ focusedValue: state.context.focusedValue,
80
+ setValue(value) {
81
+ send({ type: "SET_VALUE", value });
82
+ },
83
+ clearValue() {
84
+ send({ type: "CLEAR_VALUE" });
85
+ },
86
+ setIndicatorRect(value) {
87
+ const id = dom.getTriggerId(state.context, value);
88
+ send({ type: "SET_INDICATOR_RECT", id });
89
+ },
90
+ syncTabIndex() {
91
+ send("SYNC_TAB_INDEX");
92
+ },
93
+ selectNext(fromValue) {
94
+ send({ type: "TAB_FOCUS", value: fromValue, src: "selectNext" });
95
+ send({ type: "ARROW_NEXT", src: "selectNext" });
96
+ },
97
+ selectPrev(fromValue) {
98
+ send({ type: "TAB_FOCUS", value: fromValue, src: "selectPrev" });
99
+ send({ type: "ARROW_PREV", src: "selectPrev" });
100
+ },
101
+ focus() {
102
+ dom.getSelectedTriggerEl(state.context)?.focus();
103
+ },
104
+ getRootProps() {
105
+ return normalize.element({
106
+ ...parts.root.attrs,
107
+ id: dom.getRootId(state.context),
108
+ "data-orientation": state.context.orientation,
109
+ "data-focus": dataAttr(focused),
110
+ dir: state.context.dir
111
+ });
112
+ },
113
+ getListProps() {
114
+ return normalize.element({
115
+ ...parts.list.attrs,
116
+ id: dom.getListId(state.context),
117
+ role: "tablist",
118
+ dir: state.context.dir,
119
+ "data-focus": dataAttr(focused),
120
+ "aria-orientation": state.context.orientation,
121
+ "data-orientation": state.context.orientation,
122
+ "aria-label": translations?.listLabel,
123
+ onKeyDown(event) {
124
+ if (event.defaultPrevented)
125
+ return;
126
+ if (!isSelfTarget(event))
127
+ return;
128
+ if (isComposingEvent(event))
129
+ return;
130
+ const keyMap = {
131
+ ArrowDown() {
132
+ if (isHorizontal)
133
+ return;
134
+ send({ type: "ARROW_NEXT", key: "ArrowDown" });
135
+ },
136
+ ArrowUp() {
137
+ if (isHorizontal)
138
+ return;
139
+ send({ type: "ARROW_PREV", key: "ArrowUp" });
140
+ },
141
+ ArrowLeft() {
142
+ if (isVertical)
143
+ return;
144
+ send({ type: "ARROW_PREV", key: "ArrowLeft" });
145
+ },
146
+ ArrowRight() {
147
+ if (isVertical)
148
+ return;
149
+ send({ type: "ARROW_NEXT", key: "ArrowRight" });
150
+ },
151
+ Home() {
152
+ send("HOME");
153
+ },
154
+ End() {
155
+ send("END");
156
+ },
157
+ Enter() {
158
+ send({ type: "ENTER" });
159
+ }
160
+ };
161
+ let key = getEventKey(event, state.context);
162
+ const exec = keyMap[key];
163
+ if (exec) {
164
+ event.preventDefault();
165
+ exec(event);
166
+ }
167
+ }
168
+ });
169
+ },
170
+ getTriggerState,
171
+ getTriggerProps(props2) {
172
+ const { value, disabled } = props2;
173
+ const triggerState = getTriggerState(props2);
174
+ return normalize.button({
175
+ ...parts.trigger.attrs,
176
+ role: "tab",
177
+ type: "button",
178
+ disabled,
179
+ dir: state.context.dir,
180
+ "data-orientation": state.context.orientation,
181
+ "data-disabled": dataAttr(disabled),
182
+ "aria-disabled": disabled,
183
+ "data-value": value,
184
+ "aria-selected": triggerState.selected,
185
+ "data-selected": dataAttr(triggerState.selected),
186
+ "data-focus": dataAttr(triggerState.focused),
187
+ "aria-controls": triggerState.selected ? dom.getContentId(state.context, value) : void 0,
188
+ "data-ownedby": dom.getListId(state.context),
189
+ id: dom.getTriggerId(state.context, value),
190
+ tabIndex: triggerState.selected && composite ? 0 : -1,
191
+ onFocus() {
192
+ send({ type: "TAB_FOCUS", value });
193
+ },
194
+ onBlur(event) {
195
+ const target = event.relatedTarget;
196
+ if (target?.getAttribute("role") !== "tab") {
197
+ send({ type: "TAB_BLUR" });
198
+ }
199
+ },
200
+ onClick(event) {
201
+ if (event.defaultPrevented)
202
+ return;
203
+ if (disabled)
204
+ return;
205
+ if (isSafari()) {
206
+ event.currentTarget.focus();
207
+ }
208
+ send({ type: "TAB_CLICK", value });
209
+ }
210
+ });
211
+ },
212
+ getContentProps(props2) {
213
+ const { value } = props2;
214
+ const selected = state.context.value === value;
215
+ return normalize.element({
216
+ ...parts.content.attrs,
217
+ dir: state.context.dir,
218
+ id: dom.getContentId(state.context, value),
219
+ tabIndex: composite ? 0 : -1,
220
+ "aria-labelledby": dom.getTriggerId(state.context, value),
221
+ role: "tabpanel",
222
+ "data-ownedby": dom.getListId(state.context),
223
+ "data-selected": dataAttr(selected),
224
+ "data-orientation": state.context.orientation,
225
+ hidden: !selected
226
+ });
227
+ },
228
+ getIndicatorProps() {
229
+ return normalize.element({
230
+ id: dom.getIndicatorId(state.context),
231
+ ...parts.indicator.attrs,
232
+ dir: state.context.dir,
233
+ "data-orientation": state.context.orientation,
234
+ style: {
235
+ "--transition-property": "left, right, top, bottom, width, height",
236
+ "--left": indicator.rect?.left,
237
+ "--top": indicator.rect?.top,
238
+ "--width": indicator.rect?.width,
239
+ "--height": indicator.rect?.height,
240
+ position: "absolute",
241
+ willChange: "var(--transition-property)",
242
+ transitionProperty: "var(--transition-property)",
243
+ transitionDuration: indicator.transition ? "var(--transition-duration, 150ms)" : "0ms",
244
+ transitionTimingFunction: "var(--transition-timing-function)",
245
+ [isHorizontal ? "left" : "top"]: isHorizontal ? "var(--left)" : "var(--top)"
246
+ }
247
+ });
248
+ }
249
+ };
250
+ }
251
+
252
+ // src/tabs.machine.ts
253
+ import { createMachine, guards } from "@zag-js/core";
254
+ import { clickIfLink } from "@zag-js/dom-event";
255
+ import { nextTick, raf, getFocusables } from "@zag-js/dom-query";
256
+ import { trackElementRect } from "@zag-js/element-rect";
257
+ import { compact, isEqual } from "@zag-js/utils";
258
+ var { not } = guards;
259
+ function machine(userContext) {
260
+ const ctx = compact(userContext);
261
+ return createMachine(
262
+ {
263
+ initial: "idle",
264
+ context: {
265
+ dir: "ltr",
266
+ orientation: "horizontal",
267
+ activationMode: "automatic",
268
+ value: null,
269
+ loopFocus: true,
270
+ composite: true,
271
+ ...ctx,
272
+ focusedValue: ctx.value ?? null,
273
+ indicatorState: {
274
+ rendered: false,
275
+ transition: false,
276
+ rect: { left: "0px", top: "0px", width: "0px", height: "0px" }
277
+ }
278
+ },
279
+ watch: {
280
+ value: ["allowIndicatorTransition", "syncIndicatorRect", "syncTabIndex", "clickIfLink"],
281
+ dir: ["syncIndicatorRect"],
282
+ orientation: ["syncIndicatorRect"]
283
+ },
284
+ on: {
285
+ SET_VALUE: {
286
+ actions: "setValue"
287
+ },
288
+ CLEAR_VALUE: {
289
+ actions: "clearValue"
290
+ },
291
+ SET_INDICATOR_RECT: {
292
+ actions: "setIndicatorRect"
293
+ },
294
+ SYNC_TAB_INDEX: {
295
+ actions: "syncTabIndex"
296
+ }
297
+ },
298
+ created: ["syncFocusedValue"],
299
+ entry: ["checkRenderedElements", "syncIndicatorRect", "syncTabIndex"],
300
+ exit: ["cleanupObserver"],
301
+ states: {
302
+ idle: {
303
+ on: {
304
+ TAB_FOCUS: {
305
+ target: "focused",
306
+ actions: "setFocusedValue"
307
+ },
308
+ TAB_CLICK: {
309
+ target: "focused",
310
+ actions: ["setFocusedValue", "setValue"]
311
+ }
312
+ }
313
+ },
314
+ focused: {
315
+ on: {
316
+ TAB_CLICK: {
317
+ target: "focused",
318
+ actions: ["setFocusedValue", "setValue"]
319
+ },
320
+ ARROW_PREV: [
321
+ {
322
+ guard: "selectOnFocus",
323
+ actions: ["focusPrevTab", "selectFocusedTab"]
324
+ },
325
+ {
326
+ actions: "focusPrevTab"
327
+ }
328
+ ],
329
+ ARROW_NEXT: [
330
+ {
331
+ guard: "selectOnFocus",
332
+ actions: ["focusNextTab", "selectFocusedTab"]
333
+ },
334
+ {
335
+ actions: "focusNextTab"
336
+ }
337
+ ],
338
+ HOME: [
339
+ {
340
+ guard: "selectOnFocus",
341
+ actions: ["focusFirstTab", "selectFocusedTab"]
342
+ },
343
+ {
344
+ actions: "focusFirstTab"
345
+ }
346
+ ],
347
+ END: [
348
+ {
349
+ guard: "selectOnFocus",
350
+ actions: ["focusLastTab", "selectFocusedTab"]
351
+ },
352
+ {
353
+ actions: "focusLastTab"
354
+ }
355
+ ],
356
+ ENTER: {
357
+ guard: not("selectOnFocus"),
358
+ actions: "selectFocusedTab"
359
+ },
360
+ TAB_FOCUS: {
361
+ actions: ["setFocusedValue"]
362
+ },
363
+ TAB_BLUR: {
364
+ target: "idle",
365
+ actions: "clearFocusedValue"
366
+ }
367
+ }
368
+ }
369
+ }
370
+ },
371
+ {
372
+ guards: {
373
+ selectOnFocus: (ctx2) => ctx2.activationMode === "automatic"
374
+ },
375
+ actions: {
376
+ syncFocusedValue(ctx2) {
377
+ if (ctx2.value != null && ctx2.focusedValue == null) {
378
+ ctx2.focusedValue = ctx2.value;
379
+ }
380
+ },
381
+ selectFocusedTab(ctx2) {
382
+ raf(() => {
383
+ set.value(ctx2, ctx2.focusedValue);
384
+ });
385
+ },
386
+ setFocusedValue(ctx2, evt) {
387
+ if (evt.value == null)
388
+ return;
389
+ set.focusedValue(ctx2, evt.value);
390
+ },
391
+ clearFocusedValue(ctx2) {
392
+ set.focusedValue(ctx2, null);
393
+ },
394
+ setValue(ctx2, evt) {
395
+ set.value(ctx2, evt.value);
396
+ },
397
+ clearValue(ctx2) {
398
+ set.value(ctx2, null);
399
+ },
400
+ focusFirstTab(ctx2) {
401
+ raf(() => {
402
+ dom.getFirstTriggerEl(ctx2)?.focus();
403
+ });
404
+ },
405
+ focusLastTab(ctx2) {
406
+ raf(() => {
407
+ dom.getLastTriggerEl(ctx2)?.focus();
408
+ });
409
+ },
410
+ focusNextTab(ctx2) {
411
+ if (!ctx2.focusedValue)
412
+ return;
413
+ const triggerEl = dom.getNextTriggerEl(ctx2, ctx2.focusedValue);
414
+ raf(() => {
415
+ if (ctx2.composite) {
416
+ triggerEl?.focus();
417
+ } else if (triggerEl?.dataset.value != null) {
418
+ set.focusedValue(ctx2, triggerEl.dataset.value);
419
+ }
420
+ });
421
+ },
422
+ focusPrevTab(ctx2) {
423
+ if (!ctx2.focusedValue)
424
+ return;
425
+ const triggerEl = dom.getPrevTriggerEl(ctx2, ctx2.focusedValue);
426
+ raf(() => {
427
+ if (ctx2.composite) {
428
+ triggerEl?.focus();
429
+ } else if (triggerEl?.dataset.value != null) {
430
+ set.focusedValue(ctx2, triggerEl.dataset.value);
431
+ }
432
+ });
433
+ },
434
+ checkRenderedElements(ctx2) {
435
+ ctx2.indicatorState.rendered = !!dom.getIndicatorEl(ctx2);
436
+ },
437
+ syncTabIndex(ctx2) {
438
+ raf(() => {
439
+ const contentEl = dom.getSelectedContentEl(ctx2);
440
+ if (!contentEl)
441
+ return;
442
+ const focusables = getFocusables(contentEl);
443
+ if (focusables.length > 0) {
444
+ contentEl.removeAttribute("tabindex");
445
+ } else {
446
+ contentEl.setAttribute("tabindex", "0");
447
+ }
448
+ });
449
+ },
450
+ cleanupObserver(ctx2) {
451
+ ctx2.indicatorCleanup?.();
452
+ },
453
+ allowIndicatorTransition(ctx2) {
454
+ ctx2.indicatorState.transition = true;
455
+ },
456
+ setIndicatorRect(ctx2, evt) {
457
+ const value = evt.id ?? ctx2.value;
458
+ if (!ctx2.indicatorState.rendered || !value)
459
+ return;
460
+ const triggerEl = dom.getTriggerEl(ctx2, value);
461
+ if (!triggerEl)
462
+ return;
463
+ ctx2.indicatorState.rect = dom.getRectById(ctx2, value);
464
+ nextTick(() => {
465
+ ctx2.indicatorState.transition = false;
466
+ });
467
+ },
468
+ syncIndicatorRect(ctx2) {
469
+ ctx2.indicatorCleanup?.();
470
+ const value = ctx2.value;
471
+ if (!ctx2.indicatorState.rendered || !value)
472
+ return;
473
+ const triggerEl = dom.getSelectedTriggerEl(ctx2);
474
+ if (!triggerEl)
475
+ return;
476
+ ctx2.indicatorCleanup = trackElementRect(triggerEl, {
477
+ getRect(el) {
478
+ return dom.getOffsetRect(el);
479
+ },
480
+ onChange(rect) {
481
+ ctx2.indicatorState.rect = dom.resolveRect(rect);
482
+ nextTick(() => {
483
+ ctx2.indicatorState.transition = false;
484
+ });
485
+ }
486
+ });
487
+ },
488
+ clickIfLink(ctx2) {
489
+ clickIfLink(dom.getSelectedTriggerEl(ctx2));
490
+ }
491
+ }
492
+ }
493
+ );
494
+ }
495
+ var invoke = {
496
+ change: (ctx) => {
497
+ if (ctx.value == null)
498
+ return;
499
+ ctx.onValueChange?.({ value: ctx.value });
500
+ },
501
+ focusChange: (ctx) => {
502
+ if (ctx.focusedValue == null)
503
+ return;
504
+ ctx.onFocusChange?.({ focusedValue: ctx.focusedValue });
505
+ }
506
+ };
507
+ var set = {
508
+ value: (ctx, value) => {
509
+ if (isEqual(value, ctx.value))
510
+ return;
511
+ ctx.value = value;
512
+ invoke.change(ctx);
513
+ },
514
+ focusedValue: (ctx, value) => {
515
+ if (isEqual(value, ctx.focusedValue))
516
+ return;
517
+ ctx.focusedValue = value;
518
+ invoke.focusChange(ctx);
519
+ }
520
+ };
521
+
522
+ // src/tabs.props.ts
523
+ import { createProps } from "@zag-js/types";
524
+ import { createSplitProps } from "@zag-js/utils";
525
+ var props = createProps()([
526
+ "activationMode",
527
+ "composite",
528
+ "dir",
529
+ "getRootNode",
530
+ "id",
531
+ "ids",
532
+ "loopFocus",
533
+ "onFocusChange",
534
+ "onValueChange",
535
+ "orientation",
536
+ "translations",
537
+ "value"
538
+ ]);
539
+ var splitProps = createSplitProps(props);
540
+ var triggerProps = createProps()(["disabled", "value"]);
541
+ var splitTriggerProps = createSplitProps(triggerProps);
542
+ var contentProps = createProps()(["value"]);
543
+ var splitContentProps = createSplitProps(contentProps);
544
+ export {
545
+ anatomy,
546
+ connect,
547
+ contentProps,
548
+ machine,
549
+ props,
550
+ splitContentProps,
551
+ splitProps,
552
+ splitTriggerProps,
553
+ triggerProps
554
+ };
2
555
  //# sourceMappingURL=index.mjs.map