@tamagui/tabs 1.88.12 → 1.89.0-1706308641099

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.
@@ -0,0 +1,271 @@
1
+ import { composeRefs } from "@tamagui/compose-refs";
2
+ import { isWeb } from "@tamagui/constants";
3
+ import { getButtonSized } from "@tamagui/get-button-sized";
4
+ import { Group, useGroupItem } from "@tamagui/group";
5
+ import { composeEventHandlers, withStaticProperties } from "@tamagui/helpers";
6
+ import { RovingFocusGroup } from "@tamagui/roving-focus";
7
+ import { SizableStack, ThemeableStack } from "@tamagui/stacks";
8
+ import { useControllableState } from "@tamagui/use-controllable-state";
9
+ import { useDirection } from "@tamagui/use-direction";
10
+ import { Theme, createStyledContext, styled, useEvent } from "@tamagui/web";
11
+ import * as React from "react";
12
+ import { jsx } from "react/jsx-runtime";
13
+ const TABS_CONTEXT = "TabsContext",
14
+ TAB_LIST_NAME = "TabsList",
15
+ TabsListFrame = styled(Group, {
16
+ name: TAB_LIST_NAME
17
+ }),
18
+ TabsList = TabsListFrame.extractable(React.forwardRef((props, forwardedRef) => {
19
+ const {
20
+ __scopeTabs,
21
+ loop = !0,
22
+ children,
23
+ ...listProps
24
+ } = props,
25
+ context = useTabsContext(__scopeTabs);
26
+ return /* @__PURE__ */jsx(RovingFocusGroup, {
27
+ __scopeRovingFocusGroup: __scopeTabs || TABS_CONTEXT,
28
+ orientation: context.orientation,
29
+ dir: context.dir,
30
+ loop,
31
+ children: /* @__PURE__ */jsx(TabsListFrame, {
32
+ role: "tablist",
33
+ "aria-orientation": context.orientation,
34
+ ref: forwardedRef,
35
+ orientation: context.orientation,
36
+ ...listProps,
37
+ children
38
+ })
39
+ });
40
+ }));
41
+ TabsList.displayName = TAB_LIST_NAME;
42
+ const TRIGGER_NAME = "TabsTrigger",
43
+ TabsTriggerFrame = styled(ThemeableStack, {
44
+ name: TRIGGER_NAME,
45
+ tag: "button",
46
+ justifyContent: "center",
47
+ alignItems: "center",
48
+ flexWrap: "nowrap",
49
+ flexDirection: "row",
50
+ cursor: "pointer",
51
+ userSelect: "none",
52
+ variants: {
53
+ size: {
54
+ "...size": getButtonSized
55
+ },
56
+ disabled: {
57
+ true: {
58
+ pointerEvents: "none"
59
+ }
60
+ },
61
+ active: {
62
+ true: {
63
+ hoverStyle: {
64
+ backgroundColor: "$background"
65
+ },
66
+ focusStyle: {
67
+ backgroundColor: "$background"
68
+ }
69
+ }
70
+ },
71
+ unstyled: {
72
+ false: {
73
+ backgroundColor: "$background",
74
+ pressStyle: {
75
+ backgroundColor: "$backgroundPress"
76
+ },
77
+ hoverStyle: {
78
+ backgroundColor: "$backgroundHover"
79
+ },
80
+ focusStyle: {
81
+ backgroundColor: "$backgroundFocus"
82
+ }
83
+ }
84
+ }
85
+ },
86
+ defaultVariants: {
87
+ unstyled: process.env.TAMAGUI_HEADLESS === "1"
88
+ }
89
+ }),
90
+ TabsTrigger = TabsTriggerFrame.extractable(React.forwardRef((props, forwardedRef) => {
91
+ const {
92
+ __scopeTabs,
93
+ value,
94
+ disabled = !1,
95
+ onInteraction,
96
+ ...triggerProps
97
+ } = props,
98
+ context = useTabsContext(__scopeTabs),
99
+ triggerId = makeTriggerId(context.baseId, value),
100
+ contentId = makeContentId(context.baseId, value),
101
+ isSelected = value === context.value,
102
+ [layout, setLayout] = React.useState(null),
103
+ triggerRef = React.useRef(null),
104
+ groupItemProps = useGroupItem({
105
+ disabled: !!disabled
106
+ });
107
+ return React.useEffect(() => (context.registerTrigger(), () => context.unregisterTrigger()), []), React.useEffect(() => {
108
+ if (!triggerRef.current || !isWeb) return;
109
+ function getTriggerSize() {
110
+ triggerRef.current && setLayout({
111
+ width: triggerRef.current.offsetWidth,
112
+ height: triggerRef.current.offsetHeight,
113
+ x: triggerRef.current.offsetLeft,
114
+ y: triggerRef.current.offsetTop
115
+ });
116
+ }
117
+ getTriggerSize();
118
+ const observer = new ResizeObserver(getTriggerSize);
119
+ return observer.observe(triggerRef.current), () => {
120
+ triggerRef.current && observer.unobserve(triggerRef.current);
121
+ };
122
+ }, [context.triggersCount]), React.useEffect(() => {
123
+ isSelected && layout && onInteraction?.("select", layout);
124
+ }, [isSelected, value, layout]), /* @__PURE__ */jsx(Theme, {
125
+ name: isSelected ? "active" : null,
126
+ forceClassName: !0,
127
+ children: /* @__PURE__ */jsx(RovingFocusGroup.Item, {
128
+ __scopeRovingFocusGroup: __scopeTabs || TABS_CONTEXT,
129
+ asChild: !0,
130
+ focusable: !disabled,
131
+ active: isSelected,
132
+ children: /* @__PURE__ */jsx(TabsTriggerFrame, {
133
+ onLayout: event => {
134
+ isWeb || setLayout(event.nativeEvent.layout);
135
+ },
136
+ onHoverIn: composeEventHandlers(props.onHoverIn, () => {
137
+ layout && onInteraction?.("hover", layout);
138
+ }),
139
+ onHoverOut: composeEventHandlers(props.onHoverOut, () => {
140
+ onInteraction?.("hover", null);
141
+ }),
142
+ role: "tab",
143
+ "aria-selected": isSelected,
144
+ "aria-controls": contentId,
145
+ "data-state": isSelected ? "active" : "inactive",
146
+ "data-disabled": disabled ? "" : void 0,
147
+ disabled,
148
+ id: triggerId,
149
+ size: context.size,
150
+ ...groupItemProps,
151
+ ...triggerProps,
152
+ ref: composeRefs(forwardedRef, triggerRef),
153
+ onPress: composeEventHandlers(props.onPress ?? void 0, event => {
154
+ const webChecks = !isWeb || event.button === 0 && event.ctrlKey === !1;
155
+ !disabled && !isSelected && webChecks ? context.onChange(value) : event.preventDefault();
156
+ }),
157
+ ...(isWeb && {
158
+ type: "button",
159
+ onKeyDown: composeEventHandlers(props.onKeyDown, event => {
160
+ [" ", "Enter"].includes(event.key) && (context.onChange(value), event.preventDefault());
161
+ }),
162
+ onFocus: composeEventHandlers(props.onFocus, event => {
163
+ layout && onInteraction?.("focus", layout);
164
+ const isAutomaticActivation = context.activationMode !== "manual";
165
+ !isSelected && !disabled && isAutomaticActivation && context.onChange(value);
166
+ }),
167
+ onBlur: composeEventHandlers(props.onFocus, () => {
168
+ onInteraction?.("focus", null);
169
+ })
170
+ })
171
+ })
172
+ })
173
+ });
174
+ }));
175
+ TabsTrigger.displayName = TRIGGER_NAME;
176
+ const CONTENT_NAME = "TabsContent",
177
+ TabsContentFrame = styled(ThemeableStack, {
178
+ name: CONTENT_NAME
179
+ }),
180
+ TabsContent = TabsContentFrame.styleable(function (props, forwardedRef) {
181
+ const {
182
+ __scopeTabs,
183
+ value,
184
+ forceMount,
185
+ children,
186
+ ...contentProps
187
+ } = props,
188
+ context = useTabsContext(__scopeTabs),
189
+ isSelected = value === context.value,
190
+ show = forceMount || isSelected,
191
+ triggerId = makeTriggerId(context.baseId, value),
192
+ contentId = makeContentId(context.baseId, value);
193
+ return show ? /* @__PURE__ */jsx(TabsContentFrame, {
194
+ "data-state": isSelected ? "active" : "inactive",
195
+ "data-orientation": context.orientation,
196
+ role: "tabpanel",
197
+ "aria-labelledby": triggerId,
198
+ hidden: !show,
199
+ id: contentId,
200
+ tabIndex: 0,
201
+ ...contentProps,
202
+ ref: forwardedRef,
203
+ children
204
+ }, value) : null;
205
+ }),
206
+ TABS_NAME = "Tabs",
207
+ {
208
+ Provider: TabsProvider,
209
+ useStyledContext: useTabsContext
210
+ } = createStyledContext(),
211
+ TabsFrame = styled(SizableStack, {
212
+ name: TABS_NAME
213
+ }),
214
+ TabsComponent = TabsFrame.styleable((props, forwardedRef) => {
215
+ const {
216
+ __scopeTabs,
217
+ value: valueProp,
218
+ onValueChange,
219
+ defaultValue,
220
+ orientation = "horizontal",
221
+ dir,
222
+ activationMode = "automatic",
223
+ size = "$true",
224
+ ...tabsProps
225
+ } = props,
226
+ direction = useDirection(dir),
227
+ [value, setValue] = useControllableState({
228
+ prop: valueProp,
229
+ onChange: onValueChange,
230
+ defaultProp: defaultValue ?? ""
231
+ }),
232
+ [triggersCount, setTriggersCount] = React.useState(0),
233
+ registerTrigger = useEvent(() => setTriggersCount(v => v + 1)),
234
+ unregisterTrigger = useEvent(() => setTriggersCount(v => v - 1));
235
+ return /* @__PURE__ */jsx(TabsProvider, {
236
+ scope: __scopeTabs,
237
+ baseId: React.useId(),
238
+ value,
239
+ onChange: setValue,
240
+ orientation,
241
+ dir: direction,
242
+ activationMode,
243
+ size,
244
+ registerTrigger,
245
+ triggersCount,
246
+ unregisterTrigger,
247
+ children: /* @__PURE__ */jsx(TabsFrame, {
248
+ direction,
249
+ "data-orientation": orientation,
250
+ ...tabsProps,
251
+ ref: forwardedRef
252
+ })
253
+ });
254
+ }),
255
+ Tabs = withStaticProperties(TabsComponent, {
256
+ List: TabsList,
257
+ /**
258
+ * @deprecated Use Tabs.Tab instead
259
+ */
260
+ Trigger: TabsTrigger,
261
+ Tab: TabsTrigger,
262
+ Content: TabsContent
263
+ });
264
+ Tabs.displayName = TABS_NAME;
265
+ function makeTriggerId(baseId, value) {
266
+ return `${baseId}-trigger-${value}`;
267
+ }
268
+ function makeContentId(baseId, value) {
269
+ return `${baseId}-content-${value}`;
270
+ }
271
+ export { Tabs };
@@ -0,0 +1 @@
1
+ export * from "./Tabs.mjs";
@@ -0,0 +1,271 @@
1
+ import { composeRefs } from "@tamagui/compose-refs";
2
+ import { isWeb } from "@tamagui/constants";
3
+ import { getButtonSized } from "@tamagui/get-button-sized";
4
+ import { Group, useGroupItem } from "@tamagui/group";
5
+ import { composeEventHandlers, withStaticProperties } from "@tamagui/helpers";
6
+ import { RovingFocusGroup } from "@tamagui/roving-focus";
7
+ import { SizableStack, ThemeableStack } from "@tamagui/stacks";
8
+ import { useControllableState } from "@tamagui/use-controllable-state";
9
+ import { useDirection } from "@tamagui/use-direction";
10
+ import { Theme, createStyledContext, styled, useEvent } from "@tamagui/web";
11
+ import * as React from "react";
12
+ import { jsx } from "react/jsx-runtime";
13
+ const TABS_CONTEXT = "TabsContext",
14
+ TAB_LIST_NAME = "TabsList",
15
+ TabsListFrame = styled(Group, {
16
+ name: TAB_LIST_NAME
17
+ }),
18
+ TabsList = TabsListFrame.extractable(React.forwardRef((props, forwardedRef) => {
19
+ const {
20
+ __scopeTabs,
21
+ loop = !0,
22
+ children,
23
+ ...listProps
24
+ } = props,
25
+ context = useTabsContext(__scopeTabs);
26
+ return /* @__PURE__ */jsx(RovingFocusGroup, {
27
+ __scopeRovingFocusGroup: __scopeTabs || TABS_CONTEXT,
28
+ orientation: context.orientation,
29
+ dir: context.dir,
30
+ loop,
31
+ children: /* @__PURE__ */jsx(TabsListFrame, {
32
+ role: "tablist",
33
+ "aria-orientation": context.orientation,
34
+ ref: forwardedRef,
35
+ orientation: context.orientation,
36
+ ...listProps,
37
+ children
38
+ })
39
+ });
40
+ }));
41
+ TabsList.displayName = TAB_LIST_NAME;
42
+ const TRIGGER_NAME = "TabsTrigger",
43
+ TabsTriggerFrame = styled(ThemeableStack, {
44
+ name: TRIGGER_NAME,
45
+ tag: "button",
46
+ justifyContent: "center",
47
+ alignItems: "center",
48
+ flexWrap: "nowrap",
49
+ flexDirection: "row",
50
+ cursor: "pointer",
51
+ userSelect: "none",
52
+ variants: {
53
+ size: {
54
+ "...size": getButtonSized
55
+ },
56
+ disabled: {
57
+ true: {
58
+ pointerEvents: "none"
59
+ }
60
+ },
61
+ active: {
62
+ true: {
63
+ hoverStyle: {
64
+ backgroundColor: "$background"
65
+ },
66
+ focusStyle: {
67
+ backgroundColor: "$background"
68
+ }
69
+ }
70
+ },
71
+ unstyled: {
72
+ false: {
73
+ backgroundColor: "$background",
74
+ pressStyle: {
75
+ backgroundColor: "$backgroundPress"
76
+ },
77
+ hoverStyle: {
78
+ backgroundColor: "$backgroundHover"
79
+ },
80
+ focusStyle: {
81
+ backgroundColor: "$backgroundFocus"
82
+ }
83
+ }
84
+ }
85
+ },
86
+ defaultVariants: {
87
+ unstyled: process.env.TAMAGUI_HEADLESS === "1"
88
+ }
89
+ }),
90
+ TabsTrigger = TabsTriggerFrame.extractable(React.forwardRef((props, forwardedRef) => {
91
+ const {
92
+ __scopeTabs,
93
+ value,
94
+ disabled = !1,
95
+ onInteraction,
96
+ ...triggerProps
97
+ } = props,
98
+ context = useTabsContext(__scopeTabs),
99
+ triggerId = makeTriggerId(context.baseId, value),
100
+ contentId = makeContentId(context.baseId, value),
101
+ isSelected = value === context.value,
102
+ [layout, setLayout] = React.useState(null),
103
+ triggerRef = React.useRef(null),
104
+ groupItemProps = useGroupItem({
105
+ disabled: !!disabled
106
+ });
107
+ return React.useEffect(() => (context.registerTrigger(), () => context.unregisterTrigger()), []), React.useEffect(() => {
108
+ if (!triggerRef.current || !isWeb) return;
109
+ function getTriggerSize() {
110
+ triggerRef.current && setLayout({
111
+ width: triggerRef.current.offsetWidth,
112
+ height: triggerRef.current.offsetHeight,
113
+ x: triggerRef.current.offsetLeft,
114
+ y: triggerRef.current.offsetTop
115
+ });
116
+ }
117
+ getTriggerSize();
118
+ const observer = new ResizeObserver(getTriggerSize);
119
+ return observer.observe(triggerRef.current), () => {
120
+ triggerRef.current && observer.unobserve(triggerRef.current);
121
+ };
122
+ }, [context.triggersCount]), React.useEffect(() => {
123
+ isSelected && layout && onInteraction?.("select", layout);
124
+ }, [isSelected, value, layout]), /* @__PURE__ */jsx(Theme, {
125
+ name: isSelected ? "active" : null,
126
+ forceClassName: !0,
127
+ children: /* @__PURE__ */jsx(RovingFocusGroup.Item, {
128
+ __scopeRovingFocusGroup: __scopeTabs || TABS_CONTEXT,
129
+ asChild: !0,
130
+ focusable: !disabled,
131
+ active: isSelected,
132
+ children: /* @__PURE__ */jsx(TabsTriggerFrame, {
133
+ onLayout: event => {
134
+ isWeb || setLayout(event.nativeEvent.layout);
135
+ },
136
+ onHoverIn: composeEventHandlers(props.onHoverIn, () => {
137
+ layout && onInteraction?.("hover", layout);
138
+ }),
139
+ onHoverOut: composeEventHandlers(props.onHoverOut, () => {
140
+ onInteraction?.("hover", null);
141
+ }),
142
+ role: "tab",
143
+ "aria-selected": isSelected,
144
+ "aria-controls": contentId,
145
+ "data-state": isSelected ? "active" : "inactive",
146
+ "data-disabled": disabled ? "" : void 0,
147
+ disabled,
148
+ id: triggerId,
149
+ size: context.size,
150
+ ...groupItemProps,
151
+ ...triggerProps,
152
+ ref: composeRefs(forwardedRef, triggerRef),
153
+ onPress: composeEventHandlers(props.onPress ?? void 0, event => {
154
+ const webChecks = !isWeb || event.button === 0 && event.ctrlKey === !1;
155
+ !disabled && !isSelected && webChecks ? context.onChange(value) : event.preventDefault();
156
+ }),
157
+ ...(isWeb && {
158
+ type: "button",
159
+ onKeyDown: composeEventHandlers(props.onKeyDown, event => {
160
+ [" ", "Enter"].includes(event.key) && (context.onChange(value), event.preventDefault());
161
+ }),
162
+ onFocus: composeEventHandlers(props.onFocus, event => {
163
+ layout && onInteraction?.("focus", layout);
164
+ const isAutomaticActivation = context.activationMode !== "manual";
165
+ !isSelected && !disabled && isAutomaticActivation && context.onChange(value);
166
+ }),
167
+ onBlur: composeEventHandlers(props.onFocus, () => {
168
+ onInteraction?.("focus", null);
169
+ })
170
+ })
171
+ })
172
+ })
173
+ });
174
+ }));
175
+ TabsTrigger.displayName = TRIGGER_NAME;
176
+ const CONTENT_NAME = "TabsContent",
177
+ TabsContentFrame = styled(ThemeableStack, {
178
+ name: CONTENT_NAME
179
+ }),
180
+ TabsContent = TabsContentFrame.styleable(function (props, forwardedRef) {
181
+ const {
182
+ __scopeTabs,
183
+ value,
184
+ forceMount,
185
+ children,
186
+ ...contentProps
187
+ } = props,
188
+ context = useTabsContext(__scopeTabs),
189
+ isSelected = value === context.value,
190
+ show = forceMount || isSelected,
191
+ triggerId = makeTriggerId(context.baseId, value),
192
+ contentId = makeContentId(context.baseId, value);
193
+ return show ? /* @__PURE__ */jsx(TabsContentFrame, {
194
+ "data-state": isSelected ? "active" : "inactive",
195
+ "data-orientation": context.orientation,
196
+ role: "tabpanel",
197
+ "aria-labelledby": triggerId,
198
+ hidden: !show,
199
+ id: contentId,
200
+ tabIndex: 0,
201
+ ...contentProps,
202
+ ref: forwardedRef,
203
+ children
204
+ }, value) : null;
205
+ }),
206
+ TABS_NAME = "Tabs",
207
+ {
208
+ Provider: TabsProvider,
209
+ useStyledContext: useTabsContext
210
+ } = createStyledContext(),
211
+ TabsFrame = styled(SizableStack, {
212
+ name: TABS_NAME
213
+ }),
214
+ TabsComponent = TabsFrame.styleable((props, forwardedRef) => {
215
+ const {
216
+ __scopeTabs,
217
+ value: valueProp,
218
+ onValueChange,
219
+ defaultValue,
220
+ orientation = "horizontal",
221
+ dir,
222
+ activationMode = "automatic",
223
+ size = "$true",
224
+ ...tabsProps
225
+ } = props,
226
+ direction = useDirection(dir),
227
+ [value, setValue] = useControllableState({
228
+ prop: valueProp,
229
+ onChange: onValueChange,
230
+ defaultProp: defaultValue ?? ""
231
+ }),
232
+ [triggersCount, setTriggersCount] = React.useState(0),
233
+ registerTrigger = useEvent(() => setTriggersCount(v => v + 1)),
234
+ unregisterTrigger = useEvent(() => setTriggersCount(v => v - 1));
235
+ return /* @__PURE__ */jsx(TabsProvider, {
236
+ scope: __scopeTabs,
237
+ baseId: React.useId(),
238
+ value,
239
+ onChange: setValue,
240
+ orientation,
241
+ dir: direction,
242
+ activationMode,
243
+ size,
244
+ registerTrigger,
245
+ triggersCount,
246
+ unregisterTrigger,
247
+ children: /* @__PURE__ */jsx(TabsFrame, {
248
+ direction,
249
+ "data-orientation": orientation,
250
+ ...tabsProps,
251
+ ref: forwardedRef
252
+ })
253
+ });
254
+ }),
255
+ Tabs = withStaticProperties(TabsComponent, {
256
+ List: TabsList,
257
+ /**
258
+ * @deprecated Use Tabs.Tab instead
259
+ */
260
+ Trigger: TabsTrigger,
261
+ Tab: TabsTrigger,
262
+ Content: TabsContent
263
+ });
264
+ Tabs.displayName = TABS_NAME;
265
+ function makeTriggerId(baseId, value) {
266
+ return `${baseId}-trigger-${value}`;
267
+ }
268
+ function makeContentId(baseId, value) {
269
+ return `${baseId}-content-${value}`;
270
+ }
271
+ export { Tabs };
@@ -0,0 +1 @@
1
+ export * from "./Tabs.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/tabs",
3
- "version": "1.88.12",
3
+ "version": "1.89.0-1706308641099",
4
4
  "sideEffects": false,
5
5
  "source": "src/index.ts",
6
6
  "types": "./types/index.d.ts",
@@ -30,24 +30,24 @@
30
30
  }
31
31
  },
32
32
  "dependencies": {
33
- "@tamagui/compose-refs": "1.88.12",
34
- "@tamagui/constants": "1.88.12",
35
- "@tamagui/create-context": "1.88.12",
36
- "@tamagui/get-button-sized": "1.88.12",
37
- "@tamagui/group": "1.88.12",
38
- "@tamagui/helpers": "1.88.12",
39
- "@tamagui/roving-focus": "1.88.12",
40
- "@tamagui/stacks": "1.88.12",
41
- "@tamagui/use-controllable-state": "1.88.12",
42
- "@tamagui/use-direction": "1.88.12",
43
- "@tamagui/web": "1.88.12"
33
+ "@tamagui/compose-refs": "1.89.0-1706308641099",
34
+ "@tamagui/constants": "1.89.0-1706308641099",
35
+ "@tamagui/create-context": "1.89.0-1706308641099",
36
+ "@tamagui/get-button-sized": "1.89.0-1706308641099",
37
+ "@tamagui/group": "1.89.0-1706308641099",
38
+ "@tamagui/helpers": "1.89.0-1706308641099",
39
+ "@tamagui/roving-focus": "1.89.0-1706308641099",
40
+ "@tamagui/stacks": "1.89.0-1706308641099",
41
+ "@tamagui/use-controllable-state": "1.89.0-1706308641099",
42
+ "@tamagui/use-direction": "1.89.0-1706308641099",
43
+ "@tamagui/web": "1.89.0-1706308641099"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react": "*",
47
47
  "react-dom": "*"
48
48
  },
49
49
  "devDependencies": {
50
- "@tamagui/build": "1.88.12",
50
+ "@tamagui/build": "1.89.0-1706308641099",
51
51
  "react": "^18.2.0",
52
52
  "react-dom": "^18.2.0"
53
53
  },