@yahoo/uds-mobile 2.9.0 → 2.10.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.
Files changed (65) hide show
  1. package/README.md +1 -1
  2. package/dist/components/Tabs/Tab.cjs +174 -0
  3. package/dist/components/Tabs/Tab.d.cts +26 -0
  4. package/dist/components/Tabs/Tab.d.cts.map +1 -0
  5. package/dist/components/Tabs/Tab.d.ts +26 -0
  6. package/dist/components/Tabs/Tab.d.ts.map +1 -0
  7. package/dist/components/Tabs/Tab.js +174 -0
  8. package/dist/components/Tabs/Tab.js.map +1 -0
  9. package/dist/components/Tabs/TabList.cjs +142 -0
  10. package/dist/components/Tabs/TabList.d.cts +24 -0
  11. package/dist/components/Tabs/TabList.d.cts.map +1 -0
  12. package/dist/components/Tabs/TabList.d.ts +24 -0
  13. package/dist/components/Tabs/TabList.d.ts.map +1 -0
  14. package/dist/components/Tabs/TabList.js +141 -0
  15. package/dist/components/Tabs/TabList.js.map +1 -0
  16. package/dist/components/Tabs/TabPanel.cjs +31 -0
  17. package/dist/components/Tabs/TabPanel.d.cts +24 -0
  18. package/dist/components/Tabs/TabPanel.d.cts.map +1 -0
  19. package/dist/components/Tabs/TabPanel.d.ts +24 -0
  20. package/dist/components/Tabs/TabPanel.d.ts.map +1 -0
  21. package/dist/components/Tabs/TabPanel.js +31 -0
  22. package/dist/components/Tabs/TabPanel.js.map +1 -0
  23. package/dist/components/Tabs/Tabs.cjs +53 -0
  24. package/dist/components/Tabs/Tabs.d.cts +35 -0
  25. package/dist/components/Tabs/Tabs.d.cts.map +1 -0
  26. package/dist/components/Tabs/Tabs.d.ts +35 -0
  27. package/dist/components/Tabs/Tabs.d.ts.map +1 -0
  28. package/dist/components/Tabs/Tabs.js +53 -0
  29. package/dist/components/Tabs/Tabs.js.map +1 -0
  30. package/dist/components/Tabs/index.cjs +10 -0
  31. package/dist/components/Tabs/index.d.cts +13 -0
  32. package/dist/components/Tabs/index.d.cts.map +1 -0
  33. package/dist/components/Tabs/index.d.ts +13 -0
  34. package/dist/components/Tabs/index.d.ts.map +1 -0
  35. package/dist/components/Tabs/index.js +6 -0
  36. package/dist/components/Tabs/tabTheme.cjs +29 -0
  37. package/dist/components/Tabs/tabTheme.d.cts +23 -0
  38. package/dist/components/Tabs/tabTheme.d.cts.map +1 -0
  39. package/dist/components/Tabs/tabTheme.d.ts +23 -0
  40. package/dist/components/Tabs/tabTheme.d.ts.map +1 -0
  41. package/dist/components/Tabs/tabTheme.js +28 -0
  42. package/dist/components/Tabs/tabTheme.js.map +1 -0
  43. package/dist/components/Tabs/tabsContexts.cjs +91 -0
  44. package/dist/components/Tabs/tabsContexts.d.cts +35 -0
  45. package/dist/components/Tabs/tabsContexts.d.cts.map +1 -0
  46. package/dist/components/Tabs/tabsContexts.d.ts +35 -0
  47. package/dist/components/Tabs/tabsContexts.d.ts.map +1 -0
  48. package/dist/components/Tabs/tabsContexts.js +87 -0
  49. package/dist/components/Tabs/tabsContexts.js.map +1 -0
  50. package/dist/jest/mocks/styles.cjs +7 -0
  51. package/dist/jest/mocks/styles.d.cts +3 -2
  52. package/dist/jest/mocks/styles.d.cts.map +1 -1
  53. package/dist/jest/mocks/styles.d.ts +3 -2
  54. package/dist/jest/mocks/styles.d.ts.map +1 -1
  55. package/dist/jest/mocks/styles.js +7 -1
  56. package/dist/jest/mocks/styles.js.map +1 -1
  57. package/dist/types/dist/index.d.cts +52 -1
  58. package/dist/types/dist/index.d.cts.map +1 -1
  59. package/dist/types/dist/index.d.ts +52 -1
  60. package/dist/types/dist/index.d.ts.map +1 -1
  61. package/generated/styles.cjs +68 -0
  62. package/generated/styles.d.ts +46 -0
  63. package/generated/styles.mjs +68 -0
  64. package/generated/unistyles.d.ts +53 -0
  65. package/package.json +11 -1
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  `@yahoo/uds-mobile` brings UDS to React Native. It provides:
19
19
 
20
- - **Pre-built Components**: Avatar, Badge, Button, Checkbox, Chip, Icon, IconButton, Image, Input, Link, Radio, Switch, Text, and layout primitives (Box, VStack, HStack, Screen)
20
+ - **Pre-built Components**: Avatar, Badge, Button, Checkbox, Chip, Icon, IconButton, Image, Input, Link, Radio, Switch, Tabs, Text, and layout primitives (Box, VStack, HStack, Screen)
21
21
  - **Theming**: Full light/dark mode support with automatic system preference detection
22
22
  - **Design Token Integration**: Colors, typography, spacing, and motion configs synced from UDS tokens
23
23
  - **Animations**: Smooth, physics-based animations using Reanimated with motion parity to web
@@ -0,0 +1,174 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ require("../../_virtual/_rolldown/runtime.cjs");
4
+ const require_components_IconSlot = require("../IconSlot.cjs");
5
+ const require_components_Pressable = require("../Pressable.cjs");
6
+ const require_components_Tabs_tabsContexts = require("./tabsContexts.cjs");
7
+ const require_components_Tabs_tabTheme = require("./tabTheme.cjs");
8
+ let react = require("react");
9
+ let react_native = require("react-native");
10
+ let react_jsx_runtime = require("react/jsx-runtime");
11
+ let react_native_unistyles = require("react-native-unistyles");
12
+ //#region src/components/Tabs/Tab.tsx
13
+ const PRIMARY_TAB_UNDERLINE_HEIGHT = 2;
14
+ const CLEAR_SELECTION_CHROME = {
15
+ backgroundColor: "transparent",
16
+ borderWidth: 0,
17
+ borderColor: "transparent",
18
+ shadowOpacity: 0,
19
+ elevation: 0,
20
+ boxShadow: []
21
+ };
22
+ function TabLabel({ style, children }) {
23
+ if (typeof children === "string" || typeof children === "number") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
24
+ style,
25
+ children
26
+ });
27
+ return children;
28
+ }
29
+ /**
30
+ * **⚙️ Tab**
31
+ *
32
+ * @description
33
+ * A single selectable tab. Must be used inside {@link TabList} within {@link Tabs}.
34
+ *
35
+ * @category Navigation
36
+ * @platform mobile
37
+ */
38
+ const Tab = (0, react.memo)(function Tab({ value, children, startIcon, endIcon, disabled, style, ...pressableRest }) {
39
+ const generatedId = (0, react.useId)();
40
+ const uid = value ?? `uds-tab-${generatedId}`;
41
+ const { variant: visualVariant, reduceMotion } = require_components_Tabs_tabsContexts.useTabsVisualContext();
42
+ const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } = require_components_Tabs_tabsContexts.useTabSelectionContext();
43
+ const { theme } = (0, react_native_unistyles.useUnistyles)();
44
+ const [pressed, setPressed] = (0, react.useState)(false);
45
+ const selected = !disabled && selectedId === uid;
46
+ const active = selected ? "on" : "off";
47
+ const interaction = pressed ? "pressed" : "rest";
48
+ (0, react.useEffect)(() => {
49
+ registerTab(uid);
50
+ return () => {
51
+ unregisterTab(uid);
52
+ };
53
+ }, [
54
+ uid,
55
+ registerTab,
56
+ unregisterTab
57
+ ]);
58
+ const rootBase = (0, react.useMemo)(() => require_components_Tabs_tabTheme.getMergedTabLayerStyle(theme, visualVariant, active, "root", interaction), [
59
+ theme,
60
+ visualVariant,
61
+ active,
62
+ interaction
63
+ ]);
64
+ const textStyle = (0, react.useMemo)(() => require_components_Tabs_tabTheme.getMergedTabLayerStyle(theme, visualVariant, active, "rootText", interaction), [
65
+ theme,
66
+ visualVariant,
67
+ active,
68
+ interaction
69
+ ]);
70
+ const iconStyle = (0, react.useMemo)(() => require_components_Tabs_tabTheme.getMergedTabLayerStyle(theme, visualVariant, active, "icon", interaction), [
71
+ theme,
72
+ visualVariant,
73
+ active,
74
+ interaction
75
+ ]);
76
+ const iconColor = (() => {
77
+ const c = iconStyle?.color;
78
+ if (c === void 0 || c === null) return;
79
+ return c;
80
+ })();
81
+ /** Inactive primary tabs use transparent underline tokens on web; RN has no CSS vars for that layer. */
82
+ const showPrimaryPerTabUnderline = visualVariant === "primary" && !(selected && !reduceMotion);
83
+ const primaryUnderlineColor = (0, react.useMemo)(() => {
84
+ if (visualVariant !== "primary") return;
85
+ if (selected && reduceMotion) {
86
+ const c = require_components_Tabs_tabTheme.getTabLayerStyle(theme, "primary", "on", "rootText", "rest").color;
87
+ if (typeof c === "string") return c;
88
+ }
89
+ return "transparent";
90
+ }, [
91
+ visualVariant,
92
+ selected,
93
+ reduceMotion,
94
+ theme
95
+ ]);
96
+ const rootStyle = (0, react.useMemo)(() => {
97
+ const base = {
98
+ ...rootBase,
99
+ flexDirection: "row",
100
+ alignItems: "center",
101
+ flexShrink: 0,
102
+ zIndex: 1,
103
+ position: "relative"
104
+ };
105
+ if (selected && !reduceMotion) return {
106
+ ...base,
107
+ ...CLEAR_SELECTION_CHROME
108
+ };
109
+ return base;
110
+ }, [
111
+ rootBase,
112
+ selected,
113
+ reduceMotion
114
+ ]);
115
+ const onLayout = (0, react.useCallback)((e) => {
116
+ setTabLayout(uid, e.nativeEvent.layout);
117
+ }, [uid, setTabLayout]);
118
+ const onPress = (0, react.useCallback)(() => {
119
+ if (disabled) return;
120
+ setSelectedId(uid);
121
+ }, [
122
+ disabled,
123
+ setSelectedId,
124
+ uid
125
+ ]);
126
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_components_Pressable.Pressable, {
127
+ accessibilityRole: "tab",
128
+ accessibilityState: {
129
+ selected,
130
+ disabled: !!disabled
131
+ },
132
+ disabled,
133
+ onPress,
134
+ onPressIn: () => setPressed(true),
135
+ onPressOut: () => setPressed(false),
136
+ onLayout,
137
+ style: [rootStyle, style],
138
+ ...pressableRest,
139
+ children: [
140
+ startIcon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_IconSlot.IconSlot, {
141
+ icon: startIcon,
142
+ size: "sm",
143
+ style: iconStyle,
144
+ ...iconColor !== void 0 ? { color: iconColor } : {}
145
+ }) : null,
146
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabLabel, {
147
+ style: textStyle,
148
+ children
149
+ }),
150
+ endIcon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_IconSlot.IconSlot, {
151
+ icon: endIcon,
152
+ size: "sm",
153
+ style: iconStyle,
154
+ ...iconColor !== void 0 ? { color: iconColor } : {}
155
+ }) : null,
156
+ showPrimaryPerTabUnderline && primaryUnderlineColor && primaryUnderlineColor !== "transparent" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
157
+ accessibilityElementsHidden: true,
158
+ importantForAccessibility: "no-hide-descendants",
159
+ pointerEvents: "none",
160
+ style: {
161
+ position: "absolute",
162
+ left: 0,
163
+ right: 0,
164
+ bottom: 0,
165
+ height: PRIMARY_TAB_UNDERLINE_HEIGHT,
166
+ backgroundColor: primaryUnderlineColor
167
+ }
168
+ }) : null
169
+ ]
170
+ });
171
+ });
172
+ Tab.displayName = "Tab";
173
+ //#endregion
174
+ exports.Tab = Tab;
@@ -0,0 +1,26 @@
1
+
2
+ import { UniversalTabProps } from "../../types/dist/index.cjs";
3
+ import { IconSlotType } from "../IconSlot.cjs";
4
+ import * as _$react from "react";
5
+ import { PressableProps, ViewStyle } from "react-native";
6
+
7
+ //#region src/components/Tabs/Tab.d.ts
8
+ interface TabProps extends Omit<PressableProps, 'children' | 'style' | 'disabled' | 'onPress'>, Omit<UniversalTabProps, 'asChild' | 'className' | 'startIcon' | 'endIcon'> {
9
+ children: UniversalTabProps['children'];
10
+ startIcon?: IconSlotType;
11
+ endIcon?: IconSlotType;
12
+ style?: ViewStyle;
13
+ }
14
+ /**
15
+ * **⚙️ Tab**
16
+ *
17
+ * @description
18
+ * A single selectable tab. Must be used inside {@link TabList} within {@link Tabs}.
19
+ *
20
+ * @category Navigation
21
+ * @platform mobile
22
+ */
23
+ declare const Tab: _$react.NamedExoticComponent<TabProps>;
24
+ //#endregion
25
+ export { Tab, type TabProps };
26
+ //# sourceMappingURL=Tab.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tab.d.cts","names":[],"sources":["../../../src/components/Tabs/Tab.tsx"],"mappings":";;;;;;;UAiBU,QAAA,SAEN,IAAA,CAAK,cAAA,kDACL,IAAA,CAAK,iBAAA;EACP,QAAA,EAAU,iBAAA;EACV,SAAA,GAAY,YAAA;EACZ,OAAA,GAAU,YAAA;EACV,KAAA,GAAQ,SAAA;AAAA;;;;;;;;;;cA4BJ,GAAA,EAAG,OAAA,CAAA,oBAAA,CAAA,QAAA"}
@@ -0,0 +1,26 @@
1
+
2
+ import { UniversalTabProps } from "../../types/dist/index.js";
3
+ import { IconSlotType } from "../IconSlot.js";
4
+ import * as _$react from "react";
5
+ import { PressableProps, ViewStyle } from "react-native";
6
+
7
+ //#region src/components/Tabs/Tab.d.ts
8
+ interface TabProps extends Omit<PressableProps, 'children' | 'style' | 'disabled' | 'onPress'>, Omit<UniversalTabProps, 'asChild' | 'className' | 'startIcon' | 'endIcon'> {
9
+ children: UniversalTabProps['children'];
10
+ startIcon?: IconSlotType;
11
+ endIcon?: IconSlotType;
12
+ style?: ViewStyle;
13
+ }
14
+ /**
15
+ * **⚙️ Tab**
16
+ *
17
+ * @description
18
+ * A single selectable tab. Must be used inside {@link TabList} within {@link Tabs}.
19
+ *
20
+ * @category Navigation
21
+ * @platform mobile
22
+ */
23
+ declare const Tab: _$react.NamedExoticComponent<TabProps>;
24
+ //#endregion
25
+ export { Tab, type TabProps };
26
+ //# sourceMappingURL=Tab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tab.d.ts","names":[],"sources":["../../../src/components/Tabs/Tab.tsx"],"mappings":";;;;;;;UAiBU,QAAA,SAEN,IAAA,CAAK,cAAA,kDACL,IAAA,CAAK,iBAAA;EACP,QAAA,EAAU,iBAAA;EACV,SAAA,GAAY,YAAA;EACZ,OAAA,GAAU,YAAA;EACV,KAAA,GAAQ,SAAA;AAAA;;;;;;;;;;cA4BJ,GAAA,EAAG,OAAA,CAAA,oBAAA,CAAA,QAAA"}
@@ -0,0 +1,174 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ import { IconSlot } from "../IconSlot.js";
3
+ import { Pressable as Pressable$1 } from "../Pressable.js";
4
+ import { useTabSelectionContext, useTabsVisualContext } from "./tabsContexts.js";
5
+ import { getMergedTabLayerStyle, getTabLayerStyle } from "./tabTheme.js";
6
+ import { memo, useCallback, useEffect, useId, useMemo, useState } from "react";
7
+ import { Text, View } from "react-native";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { useUnistyles } from "react-native-unistyles";
10
+ //#region src/components/Tabs/Tab.tsx
11
+ const PRIMARY_TAB_UNDERLINE_HEIGHT = 2;
12
+ const CLEAR_SELECTION_CHROME = {
13
+ backgroundColor: "transparent",
14
+ borderWidth: 0,
15
+ borderColor: "transparent",
16
+ shadowOpacity: 0,
17
+ elevation: 0,
18
+ boxShadow: []
19
+ };
20
+ function TabLabel({ style, children }) {
21
+ if (typeof children === "string" || typeof children === "number") return /* @__PURE__ */ jsx(Text, {
22
+ style,
23
+ children
24
+ });
25
+ return children;
26
+ }
27
+ /**
28
+ * **⚙️ Tab**
29
+ *
30
+ * @description
31
+ * A single selectable tab. Must be used inside {@link TabList} within {@link Tabs}.
32
+ *
33
+ * @category Navigation
34
+ * @platform mobile
35
+ */
36
+ const Tab = memo(function Tab({ value, children, startIcon, endIcon, disabled, style, ...pressableRest }) {
37
+ const generatedId = useId();
38
+ const uid = value ?? `uds-tab-${generatedId}`;
39
+ const { variant: visualVariant, reduceMotion } = useTabsVisualContext();
40
+ const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } = useTabSelectionContext();
41
+ const { theme } = useUnistyles();
42
+ const [pressed, setPressed] = useState(false);
43
+ const selected = !disabled && selectedId === uid;
44
+ const active = selected ? "on" : "off";
45
+ const interaction = pressed ? "pressed" : "rest";
46
+ useEffect(() => {
47
+ registerTab(uid);
48
+ return () => {
49
+ unregisterTab(uid);
50
+ };
51
+ }, [
52
+ uid,
53
+ registerTab,
54
+ unregisterTab
55
+ ]);
56
+ const rootBase = useMemo(() => getMergedTabLayerStyle(theme, visualVariant, active, "root", interaction), [
57
+ theme,
58
+ visualVariant,
59
+ active,
60
+ interaction
61
+ ]);
62
+ const textStyle = useMemo(() => getMergedTabLayerStyle(theme, visualVariant, active, "rootText", interaction), [
63
+ theme,
64
+ visualVariant,
65
+ active,
66
+ interaction
67
+ ]);
68
+ const iconStyle = useMemo(() => getMergedTabLayerStyle(theme, visualVariant, active, "icon", interaction), [
69
+ theme,
70
+ visualVariant,
71
+ active,
72
+ interaction
73
+ ]);
74
+ const iconColor = (() => {
75
+ const c = iconStyle?.color;
76
+ if (c === void 0 || c === null) return;
77
+ return c;
78
+ })();
79
+ /** Inactive primary tabs use transparent underline tokens on web; RN has no CSS vars for that layer. */
80
+ const showPrimaryPerTabUnderline = visualVariant === "primary" && !(selected && !reduceMotion);
81
+ const primaryUnderlineColor = useMemo(() => {
82
+ if (visualVariant !== "primary") return;
83
+ if (selected && reduceMotion) {
84
+ const c = getTabLayerStyle(theme, "primary", "on", "rootText", "rest").color;
85
+ if (typeof c === "string") return c;
86
+ }
87
+ return "transparent";
88
+ }, [
89
+ visualVariant,
90
+ selected,
91
+ reduceMotion,
92
+ theme
93
+ ]);
94
+ const rootStyle = useMemo(() => {
95
+ const base = {
96
+ ...rootBase,
97
+ flexDirection: "row",
98
+ alignItems: "center",
99
+ flexShrink: 0,
100
+ zIndex: 1,
101
+ position: "relative"
102
+ };
103
+ if (selected && !reduceMotion) return {
104
+ ...base,
105
+ ...CLEAR_SELECTION_CHROME
106
+ };
107
+ return base;
108
+ }, [
109
+ rootBase,
110
+ selected,
111
+ reduceMotion
112
+ ]);
113
+ const onLayout = useCallback((e) => {
114
+ setTabLayout(uid, e.nativeEvent.layout);
115
+ }, [uid, setTabLayout]);
116
+ const onPress = useCallback(() => {
117
+ if (disabled) return;
118
+ setSelectedId(uid);
119
+ }, [
120
+ disabled,
121
+ setSelectedId,
122
+ uid
123
+ ]);
124
+ return /* @__PURE__ */ jsxs(Pressable$1, {
125
+ accessibilityRole: "tab",
126
+ accessibilityState: {
127
+ selected,
128
+ disabled: !!disabled
129
+ },
130
+ disabled,
131
+ onPress,
132
+ onPressIn: () => setPressed(true),
133
+ onPressOut: () => setPressed(false),
134
+ onLayout,
135
+ style: [rootStyle, style],
136
+ ...pressableRest,
137
+ children: [
138
+ startIcon ? /* @__PURE__ */ jsx(IconSlot, {
139
+ icon: startIcon,
140
+ size: "sm",
141
+ style: iconStyle,
142
+ ...iconColor !== void 0 ? { color: iconColor } : {}
143
+ }) : null,
144
+ /* @__PURE__ */ jsx(TabLabel, {
145
+ style: textStyle,
146
+ children
147
+ }),
148
+ endIcon ? /* @__PURE__ */ jsx(IconSlot, {
149
+ icon: endIcon,
150
+ size: "sm",
151
+ style: iconStyle,
152
+ ...iconColor !== void 0 ? { color: iconColor } : {}
153
+ }) : null,
154
+ showPrimaryPerTabUnderline && primaryUnderlineColor && primaryUnderlineColor !== "transparent" ? /* @__PURE__ */ jsx(View, {
155
+ accessibilityElementsHidden: true,
156
+ importantForAccessibility: "no-hide-descendants",
157
+ pointerEvents: "none",
158
+ style: {
159
+ position: "absolute",
160
+ left: 0,
161
+ right: 0,
162
+ bottom: 0,
163
+ height: PRIMARY_TAB_UNDERLINE_HEIGHT,
164
+ backgroundColor: primaryUnderlineColor
165
+ }
166
+ }) : null
167
+ ]
168
+ });
169
+ });
170
+ Tab.displayName = "Tab";
171
+ //#endregion
172
+ export { Tab };
173
+
174
+ //# sourceMappingURL=Tab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tab.js","names":["RNText","Pressable"],"sources":["../../../src/components/Tabs/Tab.tsx"],"sourcesContent":["import type { UniversalTabProps } from '@yahoo/uds-types';\nimport type { ReactElement, ReactNode } from 'react';\nimport { memo, useCallback, useEffect, useId, useMemo, useState } from 'react';\nimport type { LayoutChangeEvent, PressableProps, TextStyle, ViewStyle } from 'react-native';\nimport { Text as RNText, View } from 'react-native';\n// eslint-disable-next-line uds/no-use-unistyles -- theme.components path lookups for tab layers\nimport { useUnistyles } from 'react-native-unistyles';\n\nimport type { StyleProps } from '../../../generated/styles';\nimport type { IconSlotType } from '../IconSlot';\nimport { IconSlot } from '../IconSlot';\nimport { Pressable } from '../Pressable';\nimport { useTabSelectionContext, useTabsVisualContext } from './tabsContexts';\nimport { getMergedTabLayerStyle, getTabLayerStyle } from './tabTheme';\n\nconst PRIMARY_TAB_UNDERLINE_HEIGHT = 2;\n\ninterface TabProps\n extends\n Omit<PressableProps, 'children' | 'style' | 'disabled' | 'onPress'>,\n Omit<UniversalTabProps, 'asChild' | 'className' | 'startIcon' | 'endIcon'> {\n children: UniversalTabProps['children'];\n startIcon?: IconSlotType;\n endIcon?: IconSlotType;\n style?: ViewStyle;\n}\n\nconst CLEAR_SELECTION_CHROME: ViewStyle = {\n backgroundColor: 'transparent',\n borderWidth: 0,\n borderColor: 'transparent',\n shadowOpacity: 0,\n elevation: 0,\n boxShadow: [],\n};\n\nfunction TabLabel({ style, children }: { style: TextStyle; children: ReactNode }) {\n if (typeof children === 'string' || typeof children === 'number') {\n return <RNText style={style}>{children}</RNText>;\n }\n return children as ReactElement;\n}\n\n/**\n * **⚙️ Tab**\n *\n * @description\n * A single selectable tab. Must be used inside {@link TabList} within {@link Tabs}.\n *\n * @category Navigation\n * @platform mobile\n */\nconst Tab = memo(function Tab({\n value,\n children,\n startIcon,\n endIcon,\n disabled,\n style,\n ...pressableRest\n}: TabProps) {\n const generatedId = useId();\n const uid = value ?? `uds-tab-${generatedId}`;\n const { variant: visualVariant, reduceMotion } = useTabsVisualContext();\n const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } =\n useTabSelectionContext();\n const { theme } = useUnistyles();\n const [pressed, setPressed] = useState(false);\n\n const selected = !disabled && selectedId === uid;\n const active: 'on' | 'off' = selected ? 'on' : 'off';\n const interaction: 'rest' | 'pressed' = pressed ? 'pressed' : 'rest';\n\n useEffect(() => {\n registerTab(uid);\n return () => {\n unregisterTab(uid);\n };\n }, [uid, registerTab, unregisterTab]);\n\n const rootBase = useMemo(\n () => getMergedTabLayerStyle(theme, visualVariant, active, 'root', interaction) as ViewStyle,\n [theme, visualVariant, active, interaction],\n );\n const textStyle = useMemo(\n () =>\n getMergedTabLayerStyle(theme, visualVariant, active, 'rootText', interaction) as TextStyle,\n [theme, visualVariant, active, interaction],\n );\n const iconStyle = useMemo(\n () => getMergedTabLayerStyle(theme, visualVariant, active, 'icon', interaction) as TextStyle,\n [theme, visualVariant, active, interaction],\n );\n\n const iconColor = ((): StyleProps['color'] | undefined => {\n const c = iconStyle?.color;\n if (c === undefined || c === null) {\n return undefined;\n }\n return c as StyleProps['color'];\n })();\n\n /** Inactive primary tabs use transparent underline tokens on web; RN has no CSS vars for that layer. */\n const showPrimaryPerTabUnderline = visualVariant === 'primary' && !(selected && !reduceMotion);\n\n const primaryUnderlineColor = useMemo(() => {\n if (visualVariant !== 'primary') {\n return undefined;\n }\n if (selected && reduceMotion) {\n const onText = getTabLayerStyle(theme, 'primary', 'on', 'rootText', 'rest') as TextStyle;\n const c = onText.color;\n if (typeof c === 'string') {\n return c;\n }\n }\n return 'transparent';\n }, [visualVariant, selected, reduceMotion, theme]);\n\n const rootStyle = useMemo((): ViewStyle => {\n const base: ViewStyle = {\n ...rootBase,\n flexDirection: 'row',\n alignItems: 'center',\n flexShrink: 0,\n zIndex: 1,\n position: 'relative',\n };\n if (selected && !reduceMotion) {\n return { ...base, ...CLEAR_SELECTION_CHROME };\n }\n return base;\n }, [rootBase, selected, reduceMotion]);\n\n const onLayout = useCallback(\n (e: LayoutChangeEvent) => {\n setTabLayout(uid, e.nativeEvent.layout);\n },\n [uid, setTabLayout],\n );\n\n const onPress = useCallback(() => {\n if (disabled) {\n return;\n }\n setSelectedId(uid);\n }, [disabled, setSelectedId, uid]);\n\n return (\n <Pressable\n accessibilityRole=\"tab\"\n accessibilityState={{ selected, disabled: !!disabled }}\n disabled={disabled}\n onPress={onPress}\n onPressIn={() => setPressed(true)}\n onPressOut={() => setPressed(false)}\n onLayout={onLayout}\n style={[rootStyle, style]}\n {...pressableRest}\n >\n {startIcon ? (\n <IconSlot\n icon={startIcon}\n size=\"sm\"\n style={iconStyle}\n {...(iconColor !== undefined ? { color: iconColor } : {})}\n />\n ) : null}\n <TabLabel style={textStyle}>{children}</TabLabel>\n {endIcon ? (\n <IconSlot\n icon={endIcon}\n size=\"sm\"\n style={iconStyle}\n {...(iconColor !== undefined ? { color: iconColor } : {})}\n />\n ) : null}\n {showPrimaryPerTabUnderline &&\n primaryUnderlineColor &&\n primaryUnderlineColor !== 'transparent' ? (\n <View\n accessibilityElementsHidden\n importantForAccessibility=\"no-hide-descendants\"\n pointerEvents=\"none\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: 0,\n height: PRIMARY_TAB_UNDERLINE_HEIGHT,\n backgroundColor: primaryUnderlineColor,\n }}\n />\n ) : null}\n </Pressable>\n );\n});\n\nTab.displayName = 'Tab';\n\nexport { Tab };\nexport type { TabProps };\n"],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
4
+ const require_components_Tabs_tabsContexts = require("./tabsContexts.cjs");
5
+ const require_components_Tabs_tabTheme = require("./tabTheme.cjs");
6
+ let react = require("react");
7
+ let react_native = require("react-native");
8
+ let react_jsx_runtime = require("react/jsx-runtime");
9
+ let generated_styles = require("../../../generated/styles");
10
+ let react_native_unistyles = require("react-native-unistyles");
11
+ let react_native_reanimated = require("react-native-reanimated");
12
+ react_native_reanimated = require_runtime.__toESM(react_native_reanimated);
13
+ //#region src/components/Tabs/TabList.tsx
14
+ const TAB_INDICATOR_MS = 240;
15
+ const TAB_INDICATOR_EASING = react_native_reanimated.Easing.bezier(.2, 0, 0, 1);
16
+ const PRIMARY_SLIDE_UNDERLINE_HEIGHT = 2;
17
+ function TabListIndicator({ visualVariant, reduceMotion }) {
18
+ const { selectedId, tabLayouts } = require_components_Tabs_tabsContexts.useTabSelectionContext();
19
+ const { theme } = (0, react_native_unistyles.useUnistyles)();
20
+ const x = (0, react_native_reanimated.useSharedValue)(0);
21
+ const y = (0, react_native_reanimated.useSharedValue)(0);
22
+ const w = (0, react_native_reanimated.useSharedValue)(0);
23
+ const h = (0, react_native_reanimated.useSharedValue)(0);
24
+ const opacity = (0, react_native_reanimated.useSharedValue)(0);
25
+ (0, react.useEffect)(() => {
26
+ if (reduceMotion || !selectedId) {
27
+ opacity.value = (0, react_native_reanimated.withTiming)(0, {
28
+ duration: 120,
29
+ easing: react_native_reanimated.Easing.out(react_native_reanimated.Easing.quad)
30
+ });
31
+ return;
32
+ }
33
+ const layout = tabLayouts.get(selectedId);
34
+ if (!layout || layout.width <= 0 || layout.height <= 0) {
35
+ opacity.value = (0, react_native_reanimated.withTiming)(0, {
36
+ duration: 120,
37
+ easing: react_native_reanimated.Easing.out(react_native_reanimated.Easing.quad)
38
+ });
39
+ return;
40
+ }
41
+ const timing = {
42
+ duration: TAB_INDICATOR_MS,
43
+ easing: TAB_INDICATOR_EASING
44
+ };
45
+ x.value = (0, react_native_reanimated.withTiming)(layout.x, timing);
46
+ y.value = (0, react_native_reanimated.withTiming)(layout.y, timing);
47
+ w.value = (0, react_native_reanimated.withTiming)(layout.width, timing);
48
+ h.value = (0, react_native_reanimated.withTiming)(layout.height, timing);
49
+ opacity.value = (0, react_native_reanimated.withTiming)(1, timing);
50
+ }, [
51
+ selectedId,
52
+ tabLayouts,
53
+ reduceMotion,
54
+ x,
55
+ y,
56
+ w,
57
+ h,
58
+ opacity
59
+ ]);
60
+ const indicatorChrome = (0, react.useMemo)(() => require_components_Tabs_tabTheme.getTabLayerStyle(theme, visualVariant, "on", "root", "rest"), [theme, visualVariant]);
61
+ const primaryAccentColor = (0, react.useMemo)(() => {
62
+ const t = require_components_Tabs_tabTheme.getTabLayerStyle(theme, "primary", "on", "rootText", "rest");
63
+ return typeof t.color === "string" ? t.color : "#7d2eff";
64
+ }, [theme]);
65
+ const animatedStyle = (0, react_native_reanimated.useAnimatedStyle)(() => ({
66
+ position: "absolute",
67
+ left: x.value,
68
+ top: y.value,
69
+ width: w.value,
70
+ height: h.value,
71
+ opacity: opacity.value,
72
+ zIndex: 0,
73
+ overflow: "hidden"
74
+ }));
75
+ if (reduceMotion) return null;
76
+ /** Primary: sliding accent line at bottom (web uses underline layer, not full pill). */
77
+ if (visualVariant === "primary") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_reanimated.default.View, {
78
+ pointerEvents: "none",
79
+ style: [animatedStyle, { backgroundColor: "transparent" }],
80
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
81
+ style: {
82
+ flex: 1,
83
+ justifyContent: "flex-end"
84
+ },
85
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: {
86
+ height: PRIMARY_SLIDE_UNDERLINE_HEIGHT,
87
+ width: "100%",
88
+ backgroundColor: primaryAccentColor
89
+ } })
90
+ })
91
+ });
92
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_reanimated.default.View, {
93
+ pointerEvents: "none",
94
+ style: animatedStyle,
95
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: [indicatorChrome, { flex: 1 }] })
96
+ });
97
+ }
98
+ /**
99
+ * **⚙️ TabList**
100
+ *
101
+ * @description
102
+ * Horizontal row of {@link Tab} items. Set `scrollable` when tabs may overflow the viewport.
103
+ *
104
+ * @category Navigation
105
+ * @platform mobile
106
+ */
107
+ const TabList = (0, react.memo)(function TabList({ children, scrollable = false, style, accessibilityLabel, ...viewProps }) {
108
+ const { variant: visualVariant, reduceMotion } = require_components_Tabs_tabsContexts.useTabsVisualContext();
109
+ generated_styles.tabsStyles.useVariants({ variant: visualVariant });
110
+ const row = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
111
+ style: {
112
+ flexDirection: "row",
113
+ alignItems: "center",
114
+ position: "relative",
115
+ ...generated_styles.tabsStyles.root,
116
+ ...visualVariant === "secondary" && !scrollable ? { alignSelf: "flex-start" } : {}
117
+ },
118
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabListIndicator, {
119
+ visualVariant,
120
+ reduceMotion
121
+ }), children]
122
+ });
123
+ if (scrollable) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.ScrollView, {
124
+ horizontal: true,
125
+ showsHorizontalScrollIndicator: false,
126
+ accessibilityRole: "tablist",
127
+ accessibilityLabel,
128
+ ...viewProps,
129
+ style,
130
+ children: row
131
+ });
132
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
133
+ accessibilityRole: "tablist",
134
+ accessibilityLabel,
135
+ style,
136
+ ...viewProps,
137
+ children: row
138
+ });
139
+ });
140
+ TabList.displayName = "TabList";
141
+ //#endregion
142
+ exports.TabList = TabList;
@@ -0,0 +1,24 @@
1
+
2
+ import { UniversalTabListProps } from "../../types/dist/index.cjs";
3
+ import * as _$react from "react";
4
+ import { ViewProps, ViewStyle } from "react-native";
5
+
6
+ //#region src/components/Tabs/TabList.d.ts
7
+ /** RN View/ScrollView aria types differ from `React.AriaAttributes` on web; keep parity fields only. */
8
+ interface TabListProps extends Omit<ViewProps, 'children' | 'style'>, Pick<UniversalTabListProps, 'scrollable'> {
9
+ children: UniversalTabListProps['children'];
10
+ style?: ViewStyle;
11
+ }
12
+ /**
13
+ * **⚙️ TabList**
14
+ *
15
+ * @description
16
+ * Horizontal row of {@link Tab} items. Set `scrollable` when tabs may overflow the viewport.
17
+ *
18
+ * @category Navigation
19
+ * @platform mobile
20
+ */
21
+ declare const TabList: _$react.NamedExoticComponent<TabListProps>;
22
+ //#endregion
23
+ export { TabList, type TabListProps };
24
+ //# sourceMappingURL=TabList.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabList.d.cts","names":[],"sources":["../../../src/components/Tabs/TabList.tsx"],"mappings":";;;;;;;UAsBU,YAAA,SACA,IAAA,CAAK,SAAA,yBAAkC,IAAA,CAAK,qBAAA;EACpD,QAAA,EAAU,qBAAA;EACV,KAAA,GAAQ,SAAA;AAAA;;;;;;;;;;cAiGJ,OAAA,EAAO,OAAA,CAAA,oBAAA,CAAA,YAAA"}
@@ -0,0 +1,24 @@
1
+
2
+ import { UniversalTabListProps } from "../../types/dist/index.js";
3
+ import * as _$react from "react";
4
+ import { ViewProps, ViewStyle } from "react-native";
5
+
6
+ //#region src/components/Tabs/TabList.d.ts
7
+ /** RN View/ScrollView aria types differ from `React.AriaAttributes` on web; keep parity fields only. */
8
+ interface TabListProps extends Omit<ViewProps, 'children' | 'style'>, Pick<UniversalTabListProps, 'scrollable'> {
9
+ children: UniversalTabListProps['children'];
10
+ style?: ViewStyle;
11
+ }
12
+ /**
13
+ * **⚙️ TabList**
14
+ *
15
+ * @description
16
+ * Horizontal row of {@link Tab} items. Set `scrollable` when tabs may overflow the viewport.
17
+ *
18
+ * @category Navigation
19
+ * @platform mobile
20
+ */
21
+ declare const TabList: _$react.NamedExoticComponent<TabListProps>;
22
+ //#endregion
23
+ export { TabList, type TabListProps };
24
+ //# sourceMappingURL=TabList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabList.d.ts","names":[],"sources":["../../../src/components/Tabs/TabList.tsx"],"mappings":";;;;;;;UAsBU,YAAA,SACA,IAAA,CAAK,SAAA,yBAAkC,IAAA,CAAK,qBAAA;EACpD,QAAA,EAAU,qBAAA;EACV,KAAA,GAAQ,SAAA;AAAA;;;;;;;;;;cAiGJ,OAAA,EAAO,OAAA,CAAA,oBAAA,CAAA,YAAA"}