@yahoo/uds-mobile 2.23.3 → 2.24.0-beta.2
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/README.md +4 -12
- package/dist/bin/automated-config/dist/generated/generatedConfigs.mjs +92 -46
- package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
- package/dist/components/BottomSheet/BottomSheet.js +1 -1
- package/dist/components/Button/buttonTheme.cjs +21 -8
- package/dist/components/Button/buttonTheme.d.cts +16 -4
- package/dist/components/Button/buttonTheme.d.cts.map +1 -1
- package/dist/components/Button/buttonTheme.d.ts +16 -4
- package/dist/components/Button/buttonTheme.d.ts.map +1 -1
- package/dist/components/Button/buttonTheme.js +21 -8
- package/dist/components/Button/buttonTheme.js.map +1 -1
- package/dist/components/Button.cjs +20 -7
- package/dist/components/Button.d.cts +7 -0
- package/dist/components/Button.d.cts.map +1 -1
- package/dist/components/Button.d.ts +7 -0
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +20 -7
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Checkbox.cjs +30 -7
- package/dist/components/Checkbox.d.cts +7 -0
- package/dist/components/Checkbox.d.cts.map +1 -1
- package/dist/components/Checkbox.d.ts +7 -0
- package/dist/components/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox.js +30 -7
- package/dist/components/Checkbox.js.map +1 -1
- package/dist/components/Chip/ChipBase.cjs +23 -9
- package/dist/components/Chip/ChipBase.d.cts.map +1 -1
- package/dist/components/Chip/ChipBase.d.ts.map +1 -1
- package/dist/components/Chip/ChipBase.js +23 -9
- package/dist/components/Chip/ChipBase.js.map +1 -1
- package/dist/components/Chip/ChipDismissible.cjs +3 -1
- package/dist/components/Chip/ChipDismissible.js +3 -1
- package/dist/components/Chip/ChipDismissible.js.map +1 -1
- package/dist/components/Chip/types.d.cts +7 -0
- package/dist/components/Chip/types.d.cts.map +1 -1
- package/dist/components/Chip/types.d.ts +7 -0
- package/dist/components/Chip/types.d.ts.map +1 -1
- package/dist/components/Icon.cjs +4 -1
- package/dist/components/Icon.d.cts +9 -1
- package/dist/components/Icon.d.cts.map +1 -1
- package/dist/components/Icon.d.ts +9 -1
- package/dist/components/Icon.d.ts.map +1 -1
- package/dist/components/Icon.js +4 -1
- package/dist/components/Icon.js.map +1 -1
- package/dist/components/IconButton.js.map +1 -1
- package/dist/components/Radio/Radio.cjs +29 -11
- package/dist/components/Radio/Radio.d.cts +7 -0
- package/dist/components/Radio/Radio.d.cts.map +1 -1
- package/dist/components/Radio/Radio.d.ts +7 -0
- package/dist/components/Radio/Radio.d.ts.map +1 -1
- package/dist/components/Radio/Radio.js +29 -11
- package/dist/components/Radio/Radio.js.map +1 -1
- package/dist/components/Switch.cjs +29 -6
- package/dist/components/Switch.d.cts +7 -0
- package/dist/components/Switch.d.cts.map +1 -1
- package/dist/components/Switch.d.ts +7 -0
- package/dist/components/Switch.d.ts.map +1 -1
- package/dist/components/Switch.js +29 -6
- package/dist/components/Switch.js.map +1 -1
- package/dist/components/Tabs/Tab.cjs +12 -2
- package/dist/components/Tabs/Tab.d.cts.map +1 -1
- package/dist/components/Tabs/Tab.d.ts.map +1 -1
- package/dist/components/Tabs/Tab.js +12 -2
- package/dist/components/Tabs/Tab.js.map +1 -1
- package/dist/components/Tabs/Tabs.cjs +8 -3
- package/dist/components/Tabs/Tabs.d.cts +9 -1
- package/dist/components/Tabs/Tabs.d.cts.map +1 -1
- package/dist/components/Tabs/Tabs.d.ts +9 -1
- package/dist/components/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/Tabs/Tabs.js +8 -3
- package/dist/components/Tabs/Tabs.js.map +1 -1
- package/dist/components/Tabs/tabsContexts.d.cts +2 -0
- package/dist/components/Tabs/tabsContexts.d.cts.map +1 -1
- package/dist/components/Tabs/tabsContexts.d.ts +2 -0
- package/dist/components/Tabs/tabsContexts.d.ts.map +1 -1
- package/dist/components/Tabs/tabsContexts.js.map +1 -1
- package/dist/components/Text.cjs +4 -1
- package/dist/components/Text.d.cts +10 -2
- package/dist/components/Text.d.cts.map +1 -1
- package/dist/components/Text.d.ts +10 -2
- package/dist/components/Text.d.ts.map +1 -1
- package/dist/components/Text.js +4 -1
- package/dist/components/Text.js.map +1 -1
- package/dist/components/UDSProvider.cjs +6 -2
- package/dist/components/UDSProvider.d.cts +8 -0
- package/dist/components/UDSProvider.d.cts.map +1 -1
- package/dist/components/UDSProvider.d.ts +8 -0
- package/dist/components/UDSProvider.d.ts.map +1 -1
- package/dist/components/UDSProvider.js +6 -2
- package/dist/components/UDSProvider.js.map +1 -1
- package/dist/components/internal/Overlay/index.cjs +1 -1
- package/dist/components/internal/Overlay/index.js +1 -1
- package/dist/fontScaling/FontScalingContext.cjs +35 -0
- package/dist/fontScaling/FontScalingContext.d.cts +38 -0
- package/dist/fontScaling/FontScalingContext.d.cts.map +1 -0
- package/dist/fontScaling/FontScalingContext.d.ts +38 -0
- package/dist/fontScaling/FontScalingContext.d.ts.map +1 -0
- package/dist/fontScaling/FontScalingContext.js +34 -0
- package/dist/fontScaling/FontScalingContext.js.map +1 -0
- package/dist/fontScaling/constants.cjs +72 -0
- package/dist/fontScaling/constants.d.cts +49 -0
- package/dist/fontScaling/constants.d.cts.map +1 -0
- package/dist/fontScaling/constants.d.ts +49 -0
- package/dist/fontScaling/constants.d.ts.map +1 -0
- package/dist/fontScaling/constants.js +70 -0
- package/dist/fontScaling/constants.js.map +1 -0
- package/dist/fontScaling/index.cjs +13 -0
- package/dist/fontScaling/index.d.cts +8 -0
- package/dist/fontScaling/index.d.ts +8 -0
- package/dist/fontScaling/index.js +6 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.cjs +38 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.cts +36 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.cts.map +1 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.ts +36 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.ts.map +1 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.js +39 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.js.map +1 -0
- package/dist/fontScaling/types.cjs +1 -0
- package/dist/fontScaling/types.d.cts +51 -0
- package/dist/fontScaling/types.d.cts.map +1 -0
- package/dist/fontScaling/types.d.ts +51 -0
- package/dist/fontScaling/types.d.ts.map +1 -0
- package/dist/fontScaling/types.js +1 -0
- package/dist/fontScaling/useFontScale.cjs +32 -0
- package/dist/fontScaling/useFontScale.d.cts +18 -0
- package/dist/fontScaling/useFontScale.d.cts.map +1 -0
- package/dist/fontScaling/useFontScale.d.ts +18 -0
- package/dist/fontScaling/useFontScale.d.ts.map +1 -0
- package/dist/fontScaling/useFontScale.js +32 -0
- package/dist/fontScaling/useFontScale.js.map +1 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.cjs +24 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.cts +16 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.cts.map +1 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.ts +16 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.ts.map +1 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.js +24 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.js.map +1 -0
- package/dist/jest/mocks/react-native.cjs +19 -4
- package/dist/jest/mocks/react-native.d.cts +8 -5
- package/dist/jest/mocks/react-native.d.cts.map +1 -1
- package/dist/jest/mocks/react-native.d.ts +8 -5
- package/dist/jest/mocks/react-native.d.ts.map +1 -1
- package/dist/jest/mocks/react-native.js +18 -5
- package/dist/jest/mocks/react-native.js.map +1 -1
- package/dist/jest/mocks/styles.cjs +15 -0
- package/dist/jest/mocks/styles.d.cts.map +1 -1
- package/dist/jest/mocks/styles.d.ts.map +1 -1
- package/dist/jest/mocks/styles.js +15 -0
- package/dist/jest/mocks/styles.js.map +1 -1
- package/dist/jest/setup.cjs +4 -0
- package/dist/jest/setup.d.cts.map +1 -1
- package/dist/jest/setup.d.ts.map +1 -1
- package/dist/jest/setup.js +4 -0
- package/dist/jest/setup.js.map +1 -1
- package/dist/portal.d.cts.map +1 -1
- package/dist/portal.d.ts.map +1 -1
- package/dist/portal.js.map +1 -1
- package/dist/types/dist/index.d.cts.map +1 -1
- package/dist/types/dist/index.d.ts.map +1 -1
- package/fonts/uds-icons.ttf +0 -0
- package/generated/styles.d.ts +5 -28
- package/generated/unistyles.d.ts +0 -27
- package/package.json +11 -1
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
+
import { useMaxFontSizeMultiplier } from "../fontScaling/useMaxFontSizeMultiplier.js";
|
|
2
3
|
import { IconSlot } from "./IconSlot.js";
|
|
4
|
+
import { useFontScale } from "../fontScaling/useFontScale.js";
|
|
3
5
|
import { FormLabel } from "./FormLabel.js";
|
|
4
6
|
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
|
5
7
|
import { AccessibilityInfo, I18nManager, Platform, Pressable } from "react-native";
|
|
6
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
9
|
import { switchStyles } from "../../generated/styles";
|
|
8
10
|
import { StyleSheet as StyleSheet$1, useUnistyles } from "react-native-unistyles";
|
|
11
|
+
import { ICON_SIZE_MAP } from "@yahoo/uds-icons/tokens";
|
|
9
12
|
import Animated, { useAnimatedStyle, useDerivedValue, withTiming } from "react-native-reanimated";
|
|
10
13
|
import { useAnimatedVariantColor } from "react-native-unistyles/reanimated";
|
|
11
14
|
//#region src/components/Switch.tsx
|
|
12
|
-
const HANDLE_TRAVEL = {
|
|
13
|
-
md: 20,
|
|
14
|
-
sm: 12
|
|
15
|
-
};
|
|
16
15
|
const ANIMATION_DURATION = 120;
|
|
17
16
|
/**
|
|
18
17
|
* **Switch component for toggling options**
|
|
@@ -47,13 +46,16 @@ const ANIMATION_DURATION = 120;
|
|
|
47
46
|
* @see {@link Checkbox} for forms with submit actions
|
|
48
47
|
* @see {@link Radio} for single-select options
|
|
49
48
|
*/
|
|
50
|
-
const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onChange, label, labelPosition = "start", size = "md", onIcon, offIcon, disabled = false, required, accessibilityHint, reduceMotion = false, ref, ...viewProps }) {
|
|
49
|
+
const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onChange, label, labelPosition = "start", size = "md", onIcon, offIcon, disabled = false, required, maxFontSizeMultiplier, accessibilityHint, reduceMotion = false, ref, ...viewProps }) {
|
|
51
50
|
const isControlled = isOnProp !== void 0;
|
|
52
51
|
const [internalIsOn, setInternalIsOn] = useState(defaultIsOn);
|
|
53
52
|
const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
|
|
54
53
|
const isOn = isControlled ? isOnProp : internalIsOn;
|
|
55
54
|
const activeVariant = isOn ? "on" : "off";
|
|
56
55
|
const { theme } = useUnistyles();
|
|
56
|
+
const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier) ?? 0;
|
|
57
|
+
const fontScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier);
|
|
58
|
+
const scaledHandleIconSize = Math.round(ICON_SIZE_MAP.sm * fontScaleFactor);
|
|
57
59
|
useEffect(() => {
|
|
58
60
|
const checkReducedMotion = async () => {
|
|
59
61
|
setPrefersReducedMotion(await AccessibilityInfo.isReduceMotionEnabled());
|
|
@@ -64,7 +66,6 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
|
|
|
64
66
|
}, []);
|
|
65
67
|
const animationDuration = reduceMotion || prefersReducedMotion ? 0 : ANIMATION_DURATION;
|
|
66
68
|
const progress = useDerivedValue(() => withTiming(isOn ? 1 : 0, { duration: animationDuration }), [isOn, animationDuration]);
|
|
67
|
-
const travelDistance = HANDLE_TRAVEL[size] * (I18nManager.isRTL ? -1 : 1);
|
|
68
69
|
const handlePress = useCallback(() => {
|
|
69
70
|
if (disabled) return;
|
|
70
71
|
const newValue = !isOn;
|
|
@@ -80,6 +81,10 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
|
|
|
80
81
|
size,
|
|
81
82
|
variant: activeVariant
|
|
82
83
|
}) ?? switchStyles;
|
|
84
|
+
const scaledTrackWidth = Math.round(resolvedSwitchStyles.switch.width * fontScaleFactor);
|
|
85
|
+
const scaledTrackPadding = Math.round(resolvedSwitchStyles.switch.padding * fontScaleFactor);
|
|
86
|
+
const scaledHandleWidth = Math.round(resolvedSwitchStyles.handle.width * fontScaleFactor);
|
|
87
|
+
const travelDistance = Math.max(0, scaledTrackWidth - scaledHandleWidth - scaledTrackPadding * 2) * (I18nManager.isRTL ? -1 : 1);
|
|
83
88
|
const variantLayerStyles = useMemo(() => {
|
|
84
89
|
const components = theme.components;
|
|
85
90
|
const getLayerStyle = (layer) => components[`switch/variant/default/active/${activeVariant}/${layer}/rest`];
|
|
@@ -100,24 +105,37 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
|
|
|
100
105
|
return { transform: [{ translateX: progress.value * travelDistance }] };
|
|
101
106
|
});
|
|
102
107
|
const rootStyle = useMemo(() => [resolvedSwitchStyles.root, switchStaticStyles.root({ disabled })], [resolvedSwitchStyles.root, disabled]);
|
|
108
|
+
const scaleDimensions = useCallback((style) => {
|
|
109
|
+
if (!style || fontScaleFactor === 1) return;
|
|
110
|
+
const { width, height, padding } = style;
|
|
111
|
+
return typeof width === "number" && typeof height === "number" ? {
|
|
112
|
+
width: Math.round(width * fontScaleFactor),
|
|
113
|
+
height: Math.round(height * fontScaleFactor),
|
|
114
|
+
...typeof padding === "number" && { padding: Math.round(padding * fontScaleFactor) }
|
|
115
|
+
} : void 0;
|
|
116
|
+
}, [fontScaleFactor]);
|
|
103
117
|
const trackStyle = useMemo(() => [
|
|
104
118
|
resolvedSwitchStyles.switch,
|
|
105
119
|
switchStaticStyles.track,
|
|
106
120
|
variantLayerStyles.switch,
|
|
121
|
+
scaleDimensions(resolvedSwitchStyles.switch),
|
|
107
122
|
Platform.OS !== "web" && animatedTrackStyle
|
|
108
123
|
], [
|
|
109
124
|
resolvedSwitchStyles.switch,
|
|
110
125
|
variantLayerStyles.switch,
|
|
126
|
+
scaleDimensions,
|
|
111
127
|
animatedTrackStyle
|
|
112
128
|
]);
|
|
113
129
|
const handleStyle = useMemo(() => [
|
|
114
130
|
resolvedSwitchStyles.handle,
|
|
115
131
|
switchStaticStyles.handle,
|
|
116
132
|
variantLayerStyles.handle,
|
|
133
|
+
scaleDimensions(resolvedSwitchStyles.handle),
|
|
117
134
|
animatedHandleStyle
|
|
118
135
|
], [
|
|
119
136
|
resolvedSwitchStyles.handle,
|
|
120
137
|
variantLayerStyles.handle,
|
|
138
|
+
scaleDimensions,
|
|
121
139
|
animatedHandleStyle
|
|
122
140
|
]);
|
|
123
141
|
const accessibilityLabel = typeof label === "string" ? label : void 0;
|
|
@@ -128,6 +146,7 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
|
|
|
128
146
|
label,
|
|
129
147
|
required,
|
|
130
148
|
showRequiredAsterisk: required,
|
|
149
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
131
150
|
style: [resolvedSwitchStyles.text, variantLayerStyles.text]
|
|
132
151
|
});
|
|
133
152
|
const a11yValue = useMemo(() => ({ text: isOn ? "On" : "Off" }), [isOn]);
|
|
@@ -158,6 +177,8 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
|
|
|
158
177
|
children: /* @__PURE__ */ jsx(IconSlot, {
|
|
159
178
|
icon: onIcon,
|
|
160
179
|
variant: "fill",
|
|
180
|
+
dangerouslySetSize: scaledHandleIconSize,
|
|
181
|
+
allowFontScaling: false,
|
|
161
182
|
style: [resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]
|
|
162
183
|
})
|
|
163
184
|
}), offIcon && !isOn && /* @__PURE__ */ jsx(Animated.View, {
|
|
@@ -165,6 +186,8 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
|
|
|
165
186
|
children: /* @__PURE__ */ jsx(IconSlot, {
|
|
166
187
|
icon: offIcon,
|
|
167
188
|
variant: "fill",
|
|
189
|
+
dangerouslySetSize: scaledHandleIconSize,
|
|
190
|
+
allowFontScaling: false,
|
|
168
191
|
style: [resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]
|
|
169
192
|
})
|
|
170
193
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.js","names":["StyleSheet"],"sources":["../../src/components/Switch.tsx"],"sourcesContent":["import type { SwitchSize, UniversalSwitchProps } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\nimport type {\n AccessibilityProps,\n StyleProp,\n TextStyle,\n View,\n ViewProps,\n ViewStyle,\n} from 'react-native';\nimport { AccessibilityInfo, I18nManager, Platform, Pressable } from 'react-native';\nimport Animated, { useAnimatedStyle, useDerivedValue, withTiming } from 'react-native-reanimated';\n// eslint-disable-next-line uds/no-use-unistyles -- switch variant layers need concrete web styles\nimport { StyleSheet, useUnistyles } from 'react-native-unistyles';\nimport { useAnimatedVariantColor } from 'react-native-unistyles/reanimated';\n\nimport { switchStyles } from '../../generated/styles';\nimport { FormLabel } from './FormLabel';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\n\ninterface SwitchProps extends Omit<ViewProps, 'style'>, UniversalSwitchProps<IconSlotType> {\n /** Ref to the underlying View */\n ref?: Ref<View>;\n /** Callback when the switch value changes */\n onChange?: (value: boolean) => void;\n /** Whether the switch is disabled */\n disabled?: boolean;\n /** Whether the switch is required (shows asterisk with label) */\n required?: boolean;\n /** Accessibility hint describing what happens when activated */\n accessibilityHint?: AccessibilityProps['accessibilityHint'];\n}\n\nconst HANDLE_TRAVEL: Record<SwitchSize, number> = {\n md: 20,\n sm: 12,\n};\n\nconst ANIMATION_DURATION = 120;\n\n/**\n * **Switch component for toggling options**\n *\n * @description\n * A switch (also called a toggle) is a binary on/off input control.\n * It allows users to pick between two clearly opposite choices.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Switch } from '@yahoo/uds-mobile/Switch';\n *\n * <Switch label=\"Notifications\" />\n * <Switch isOn={enabled} onChange={setEnabled} label=\"Dark mode\" />\n * <Switch onIcon=\"Check\" offIcon=\"Cross\" label=\"Sync\" />\n * ```\n *\n * @usage\n * - Settings: For toggling preferences on/off\n * - Feature flags: For enabling/disabling features\n * - Immediate effect toggles (no submit button needed)\n *\n * @accessibility\n * - Sets `accessibilityRole=\"switch\"` automatically\n * - Announces on/off state to screen readers\n * - Respects system reduce motion preference\n * - Supports `reduceMotion` prop to disable animations\n *\n * @see {@link Checkbox} for forms with submit actions\n * @see {@link Radio} for single-select options\n */\nconst Switch = memo(function Switch({\n isOn: isOnProp,\n defaultIsOn = false,\n onChange,\n label,\n labelPosition = 'start',\n size = 'md',\n onIcon,\n offIcon,\n disabled = false,\n required,\n accessibilityHint,\n reduceMotion = false,\n ref,\n ...viewProps\n}: SwitchProps) {\n const isControlled = isOnProp !== undefined;\n const [internalIsOn, setInternalIsOn] = useState(defaultIsOn);\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);\n const isOn = isControlled ? isOnProp : internalIsOn;\n const activeVariant = isOn ? 'on' : 'off';\n const { theme } = useUnistyles();\n\n // Check system reduced motion preference\n useEffect(() => {\n const checkReducedMotion = async () => {\n const isReduceMotionEnabled = await AccessibilityInfo.isReduceMotionEnabled();\n setPrefersReducedMotion(isReduceMotionEnabled);\n };\n checkReducedMotion();\n\n const subscription = AccessibilityInfo.addEventListener(\n 'reduceMotionChanged',\n setPrefersReducedMotion,\n );\n return () => subscription.remove();\n }, []);\n\n const shouldReduceMotion = reduceMotion || prefersReducedMotion;\n const animationDuration = shouldReduceMotion ? 0 : ANIMATION_DURATION;\n\n const progress = useDerivedValue(\n () => withTiming(isOn ? 1 : 0, { duration: animationDuration }),\n [isOn, animationDuration],\n );\n\n // RTL mirrors the track layout but not transforms, so travel flips sign\n const travelDistance = HANDLE_TRAVEL[size] * (I18nManager.isRTL ? -1 : 1);\n\n const handlePress = useCallback(() => {\n if (disabled) {\n return;\n }\n\n const newValue = !isOn;\n\n if (!isControlled) {\n setInternalIsOn(newValue);\n }\n\n onChange?.(newValue);\n }, [disabled, isOn, isControlled, onChange]);\n\n // On web, useVariants returns the resolved style object instead of mutating\n // switchStyles in place.\n const variantSwitchStyles = switchStyles.useVariants({\n size,\n variant: activeVariant,\n }) as unknown as typeof switchStyles | undefined;\n const resolvedSwitchStyles = variantSwitchStyles ?? switchStyles;\n\n const variantLayerStyles = useMemo(() => {\n const components = theme.components as unknown as Record<string, Record<string, unknown>>;\n const getLayerStyle = <TStyle,>(layer: string) =>\n components[`switch/variant/default/active/${activeVariant}/${layer}/rest`] as\n | TStyle\n | undefined;\n\n return {\n handle: getLayerStyle<ViewStyle>('handle'),\n handleIcon: getLayerStyle<TextStyle>('handleIcon'),\n switch: getLayerStyle<ViewStyle>('switch'),\n text: getLayerStyle<TextStyle>('rootText'),\n };\n }, [activeVariant, theme]);\n\n // Get animated track color from design tokens (changes when variant changes)\n const trackBackgroundColor = useAnimatedVariantColor(\n resolvedSwitchStyles.switch,\n 'backgroundColor',\n );\n\n const animatedTrackStyle = useAnimatedStyle(() => {\n 'worklet';\n return {\n backgroundColor: withTiming(trackBackgroundColor.value, { duration: animationDuration }),\n };\n });\n\n const animatedHandleStyle = useAnimatedStyle(() => {\n 'worklet';\n return {\n transform: [{ translateX: progress.value * travelDistance }],\n };\n });\n\n const rootStyle: StyleProp<ViewStyle> = useMemo(\n () => [resolvedSwitchStyles.root, switchStaticStyles.root({ disabled })],\n [resolvedSwitchStyles.root, disabled],\n );\n\n const trackStyle: StyleProp<ViewStyle> = useMemo(\n () => [\n resolvedSwitchStyles.switch,\n switchStaticStyles.track,\n variantLayerStyles.switch,\n // On web, the animated variant color hook currently resolves to Unistyles'\n // black fallback, so the concrete variant layer provides the track color.\n Platform.OS !== 'web' && animatedTrackStyle,\n ],\n [resolvedSwitchStyles.switch, variantLayerStyles.switch, animatedTrackStyle],\n );\n\n const handleStyle: StyleProp<ViewStyle> = useMemo(\n () => [\n resolvedSwitchStyles.handle,\n switchStaticStyles.handle,\n variantLayerStyles.handle,\n animatedHandleStyle,\n ],\n [resolvedSwitchStyles.handle, variantLayerStyles.handle, animatedHandleStyle],\n );\n\n const accessibilityLabel = typeof label === 'string' ? label : undefined;\n const resolvedAccessibilityHint = accessibilityHint ?? 'Double tap to toggle';\n\n const labelContent = label && (\n <FormLabel\n color=\"inherit\"\n variant=\"inherit\"\n label={label}\n required={required}\n showRequiredAsterisk={required}\n style={[resolvedSwitchStyles.text, variantLayerStyles.text]}\n />\n );\n\n const a11yValue = useMemo(() => ({ text: isOn ? 'On' : 'Off' }), [isOn]);\n\n return (\n <Pressable\n ref={ref}\n onPress={handlePress}\n disabled={disabled}\n accessible\n accessibilityRole=\"switch\"\n accessibilityState={{ checked: isOn, disabled }}\n accessibilityLabel={accessibilityLabel}\n accessibilityHint={resolvedAccessibilityHint}\n accessibilityValue={a11yValue}\n {...viewProps}\n style={rootStyle}\n >\n {labelPosition === 'start' && labelContent}\n\n <Animated.View style={trackStyle} importantForAccessibility=\"no-hide-descendants\">\n <Animated.View style={handleStyle}>\n {onIcon && isOn && (\n <Animated.View style={switchStaticStyles.iconContainer}>\n <IconSlot\n icon={onIcon}\n variant=\"fill\"\n style={[resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]}\n />\n </Animated.View>\n )}\n {offIcon && !isOn && (\n <Animated.View style={switchStaticStyles.iconContainer}>\n <IconSlot\n icon={offIcon}\n variant=\"fill\"\n style={[resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]}\n />\n </Animated.View>\n )}\n </Animated.View>\n </Animated.View>\n\n {labelPosition === 'end' && labelContent}\n </Pressable>\n );\n});\n\nSwitch.displayName = 'Switch';\n\nconst switchStaticStyles = StyleSheet.create((theme) => ({\n handle: {\n borderRadius: theme.borderRadius.full,\n alignItems: 'center',\n justifyContent: 'center',\n },\n iconContainer: {\n position: 'absolute',\n alignItems: 'center',\n justifyContent: 'center',\n },\n track: {\n justifyContent: 'center',\n borderRadius: theme.borderRadius.full,\n },\n root: ({ disabled }: { disabled: boolean }) => ({\n flexDirection: 'row',\n alignItems: 'center',\n alignSelf: 'flex-start',\n opacity: disabled ? 0.5 : 1,\n }),\n}));\n\nexport { Switch, type SwitchProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Switch.js","names":["StyleSheet"],"sources":["../../src/components/Switch.tsx"],"sourcesContent":["import { ICON_SIZE_MAP } from '@yahoo/uds-icons/tokens';\nimport type { UniversalSwitchProps } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\nimport type {\n AccessibilityProps,\n StyleProp,\n TextStyle,\n View,\n ViewProps,\n ViewStyle,\n} from 'react-native';\nimport { AccessibilityInfo, I18nManager, Platform, Pressable } from 'react-native';\nimport Animated, { useAnimatedStyle, useDerivedValue, withTiming } from 'react-native-reanimated';\n// eslint-disable-next-line uds/no-use-unistyles -- switch variant layers need concrete web styles\nimport { StyleSheet, useUnistyles } from 'react-native-unistyles';\nimport { useAnimatedVariantColor } from 'react-native-unistyles/reanimated';\n\nimport { switchStyles } from '../../generated/styles';\nimport { useFontScale } from '../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\nimport { FormLabel } from './FormLabel';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\n\ninterface SwitchProps extends Omit<ViewProps, 'style'>, UniversalSwitchProps<IconSlotType> {\n /** Ref to the underlying View */\n ref?: Ref<View>;\n /** Callback when the switch value changes */\n onChange?: (value: boolean) => void;\n /** Whether the switch is disabled */\n disabled?: boolean;\n /** Whether the switch is required (shows asterisk with label) */\n required?: boolean;\n /**\n * Caps how far the track, handle, and label grow with the OS text-size\n * setting; all scale by the same factor. Set null to remove the cap;\n * override app-wide via UDSFontScalingProvider.\n * @default 2\n */\n maxFontSizeMultiplier?: number | null;\n /** Accessibility hint describing what happens when activated */\n accessibilityHint?: AccessibilityProps['accessibilityHint'];\n}\n\nconst ANIMATION_DURATION = 120;\n\n/**\n * **Switch component for toggling options**\n *\n * @description\n * A switch (also called a toggle) is a binary on/off input control.\n * It allows users to pick between two clearly opposite choices.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Switch } from '@yahoo/uds-mobile/Switch';\n *\n * <Switch label=\"Notifications\" />\n * <Switch isOn={enabled} onChange={setEnabled} label=\"Dark mode\" />\n * <Switch onIcon=\"Check\" offIcon=\"Cross\" label=\"Sync\" />\n * ```\n *\n * @usage\n * - Settings: For toggling preferences on/off\n * - Feature flags: For enabling/disabling features\n * - Immediate effect toggles (no submit button needed)\n *\n * @accessibility\n * - Sets `accessibilityRole=\"switch\"` automatically\n * - Announces on/off state to screen readers\n * - Respects system reduce motion preference\n * - Supports `reduceMotion` prop to disable animations\n *\n * @see {@link Checkbox} for forms with submit actions\n * @see {@link Radio} for single-select options\n */\nconst Switch = memo(function Switch({\n isOn: isOnProp,\n defaultIsOn = false,\n onChange,\n label,\n labelPosition = 'start',\n size = 'md',\n onIcon,\n offIcon,\n disabled = false,\n required,\n maxFontSizeMultiplier,\n accessibilityHint,\n reduceMotion = false,\n ref,\n ...viewProps\n}: SwitchProps) {\n const isControlled = isOnProp !== undefined;\n const [internalIsOn, setInternalIsOn] = useState(defaultIsOn);\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);\n const isOn = isControlled ? isOnProp : internalIsOn;\n const activeVariant = isOn ? 'on' : 'off';\n const { theme } = useUnistyles();\n\n // One capped factor governs track, handle, travel, and label.\n const resolvedMaxFontSizeMultiplier =\n useMaxFontSizeMultiplier('control', maxFontSizeMultiplier) ?? 0;\n const fontScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier);\n // Size the handle glyph from the same factor as the handle it sits in, rather\n // than letting native font scaling size it on a separate path.\n const scaledHandleIconSize = Math.round(ICON_SIZE_MAP.sm * fontScaleFactor);\n\n // Check system reduced motion preference\n useEffect(() => {\n const checkReducedMotion = async () => {\n const isReduceMotionEnabled = await AccessibilityInfo.isReduceMotionEnabled();\n setPrefersReducedMotion(isReduceMotionEnabled);\n };\n checkReducedMotion();\n\n const subscription = AccessibilityInfo.addEventListener(\n 'reduceMotionChanged',\n setPrefersReducedMotion,\n );\n return () => subscription.remove();\n }, []);\n\n const shouldReduceMotion = reduceMotion || prefersReducedMotion;\n const animationDuration = shouldReduceMotion ? 0 : ANIMATION_DURATION;\n\n const progress = useDerivedValue(\n () => withTiming(isOn ? 1 : 0, { duration: animationDuration }),\n [isOn, animationDuration],\n );\n\n const handlePress = useCallback(() => {\n if (disabled) {\n return;\n }\n\n const newValue = !isOn;\n\n if (!isControlled) {\n setInternalIsOn(newValue);\n }\n\n onChange?.(newValue);\n }, [disabled, isOn, isControlled, onChange]);\n\n // On web, useVariants returns the resolved style object instead of mutating\n // switchStyles in place.\n const variantSwitchStyles = switchStyles.useVariants({\n size,\n variant: activeVariant,\n }) as unknown as typeof switchStyles | undefined;\n const resolvedSwitchStyles = variantSwitchStyles ?? switchStyles;\n\n // Derive travel from the same rounded metrics used to render the control.\n // Scaling the token travel independently can differ by a pixel at fractional\n // font scales, leaving unequal insets at opposite ends of the track.\n const scaledTrackWidth = Math.round(resolvedSwitchStyles.switch.width * fontScaleFactor);\n const scaledTrackPadding = Math.round(resolvedSwitchStyles.switch.padding * fontScaleFactor);\n const scaledHandleWidth = Math.round(resolvedSwitchStyles.handle.width * fontScaleFactor);\n const scaledHandleTravel = Math.max(\n 0,\n scaledTrackWidth - scaledHandleWidth - scaledTrackPadding * 2,\n );\n // RTL mirrors the track layout but not transforms, so travel flips sign.\n const travelDistance = scaledHandleTravel * (I18nManager.isRTL ? -1 : 1);\n\n const variantLayerStyles = useMemo(() => {\n const components = theme.components as unknown as Record<string, Record<string, unknown>>;\n const getLayerStyle = <TStyle,>(layer: string) =>\n components[`switch/variant/default/active/${activeVariant}/${layer}/rest`] as\n TStyle | undefined;\n\n return {\n handle: getLayerStyle<ViewStyle>('handle'),\n handleIcon: getLayerStyle<TextStyle>('handleIcon'),\n switch: getLayerStyle<ViewStyle>('switch'),\n text: getLayerStyle<TextStyle>('rootText'),\n };\n }, [activeVariant, theme]);\n\n // Get animated track color from design tokens (changes when variant changes)\n const trackBackgroundColor = useAnimatedVariantColor(\n resolvedSwitchStyles.switch,\n 'backgroundColor',\n );\n\n const animatedTrackStyle = useAnimatedStyle(() => {\n 'worklet';\n return {\n backgroundColor: withTiming(trackBackgroundColor.value, { duration: animationDuration }),\n };\n });\n\n const animatedHandleStyle = useAnimatedStyle(() => {\n 'worklet';\n return {\n transform: [{ translateX: progress.value * travelDistance }],\n };\n });\n\n const rootStyle: StyleProp<ViewStyle> = useMemo(\n () => [resolvedSwitchStyles.root, switchStaticStyles.root({ disabled })],\n [resolvedSwitchStyles.root, disabled],\n );\n\n // Track and handle grow by the capped factor so the handle (and its icon)\n // stays contained. Scale the track's inset too so the derived travel lands\n // the handle at the same distance from either end.\n const scaleDimensions = useCallback(\n (style: ViewStyle | undefined): ViewStyle | undefined => {\n if (!style || fontScaleFactor === 1) {\n return undefined;\n }\n const { width, height, padding } = style;\n return typeof width === 'number' && typeof height === 'number'\n ? {\n width: Math.round(width * fontScaleFactor),\n height: Math.round(height * fontScaleFactor),\n ...(typeof padding === 'number' && {\n padding: Math.round(padding * fontScaleFactor),\n }),\n }\n : undefined;\n },\n [fontScaleFactor],\n );\n\n const trackStyle: StyleProp<ViewStyle> = useMemo(\n () => [\n resolvedSwitchStyles.switch,\n switchStaticStyles.track,\n variantLayerStyles.switch,\n scaleDimensions(resolvedSwitchStyles.switch as ViewStyle),\n // On web, the animated variant color hook currently resolves to Unistyles'\n // black fallback, so the concrete variant layer provides the track color.\n Platform.OS !== 'web' && animatedTrackStyle,\n ],\n [resolvedSwitchStyles.switch, variantLayerStyles.switch, scaleDimensions, animatedTrackStyle],\n );\n\n const handleStyle: StyleProp<ViewStyle> = useMemo(\n () => [\n resolvedSwitchStyles.handle,\n switchStaticStyles.handle,\n variantLayerStyles.handle,\n scaleDimensions(resolvedSwitchStyles.handle as ViewStyle),\n animatedHandleStyle,\n ],\n [resolvedSwitchStyles.handle, variantLayerStyles.handle, scaleDimensions, animatedHandleStyle],\n );\n\n const accessibilityLabel = typeof label === 'string' ? label : undefined;\n const resolvedAccessibilityHint = accessibilityHint ?? 'Double tap to toggle';\n\n const labelContent = label && (\n <FormLabel\n color=\"inherit\"\n variant=\"inherit\"\n label={label}\n required={required}\n showRequiredAsterisk={required}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={[resolvedSwitchStyles.text, variantLayerStyles.text]}\n />\n );\n\n const a11yValue = useMemo(() => ({ text: isOn ? 'On' : 'Off' }), [isOn]);\n\n return (\n <Pressable\n ref={ref}\n onPress={handlePress}\n disabled={disabled}\n accessible\n accessibilityRole=\"switch\"\n accessibilityState={{ checked: isOn, disabled }}\n accessibilityLabel={accessibilityLabel}\n accessibilityHint={resolvedAccessibilityHint}\n accessibilityValue={a11yValue}\n {...viewProps}\n style={rootStyle}\n >\n {labelPosition === 'start' && labelContent}\n\n <Animated.View style={trackStyle} importantForAccessibility=\"no-hide-descendants\">\n <Animated.View style={handleStyle}>\n {onIcon && isOn && (\n <Animated.View style={switchStaticStyles.iconContainer}>\n <IconSlot\n icon={onIcon}\n variant=\"fill\"\n dangerouslySetSize={scaledHandleIconSize}\n allowFontScaling={false}\n style={[resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]}\n />\n </Animated.View>\n )}\n {offIcon && !isOn && (\n <Animated.View style={switchStaticStyles.iconContainer}>\n <IconSlot\n icon={offIcon}\n variant=\"fill\"\n dangerouslySetSize={scaledHandleIconSize}\n allowFontScaling={false}\n style={[resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]}\n />\n </Animated.View>\n )}\n </Animated.View>\n </Animated.View>\n\n {labelPosition === 'end' && labelContent}\n </Pressable>\n );\n});\n\nSwitch.displayName = 'Switch';\n\nconst switchStaticStyles = StyleSheet.create((theme) => ({\n handle: {\n borderRadius: theme.borderRadius.full,\n alignItems: 'center',\n justifyContent: 'center',\n },\n iconContainer: {\n position: 'absolute',\n alignItems: 'center',\n justifyContent: 'center',\n },\n track: {\n justifyContent: 'center',\n borderRadius: theme.borderRadius.full,\n },\n root: ({ disabled }: { disabled: boolean }) => ({\n flexDirection: 'row',\n alignItems: 'center',\n alignSelf: 'flex-start',\n opacity: disabled ? 0.5 : 1,\n }),\n}));\n\nexport { Switch, type SwitchProps };\n"],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
require("../../_virtual/_rolldown/runtime.cjs");
|
|
4
|
+
const require_fontScaling_useMaxFontSizeMultiplier = require("../../fontScaling/useMaxFontSizeMultiplier.cjs");
|
|
4
5
|
const require_components_IconSlot = require("../IconSlot.cjs");
|
|
6
|
+
const require_fontScaling_useFontScale = require("../../fontScaling/useFontScale.cjs");
|
|
5
7
|
const require_components_Pressable = require("../Pressable.cjs");
|
|
6
8
|
const require_components_Tabs_tabsContexts = require("./tabsContexts.cjs");
|
|
7
9
|
const require_components_Tabs_tabTheme = require("./tabTheme.cjs");
|
|
@@ -19,9 +21,10 @@ const CLEAR_SELECTION_CHROME = {
|
|
|
19
21
|
elevation: 0,
|
|
20
22
|
boxShadow: []
|
|
21
23
|
};
|
|
22
|
-
function TabLabel({ style, children }) {
|
|
24
|
+
function TabLabel({ style, maxFontSizeMultiplier, children }) {
|
|
23
25
|
if (typeof children === "string" || typeof children === "number") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
24
26
|
style,
|
|
27
|
+
maxFontSizeMultiplier,
|
|
25
28
|
children
|
|
26
29
|
});
|
|
27
30
|
return children;
|
|
@@ -38,10 +41,12 @@ function TabLabel({ style, children }) {
|
|
|
38
41
|
const Tab = (0, react.memo)(function Tab({ value, children, startIcon, endIcon, disabled, style, ...pressableRest }) {
|
|
39
42
|
const generatedId = (0, react.useId)();
|
|
40
43
|
const uid = value ?? `uds-tab-${generatedId}`;
|
|
41
|
-
const { variant: visualVariant, reduceMotion } = require_components_Tabs_tabsContexts.useTabsVisualContext();
|
|
44
|
+
const { variant: visualVariant, reduceMotion, maxFontSizeMultiplier } = require_components_Tabs_tabsContexts.useTabsVisualContext();
|
|
42
45
|
const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } = require_components_Tabs_tabsContexts.useTabSelectionContext();
|
|
43
46
|
const { theme } = (0, react_native_unistyles.useUnistyles)();
|
|
44
47
|
const [pressed, setPressed] = (0, react.useState)(false);
|
|
48
|
+
const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier) ?? 0;
|
|
49
|
+
const fontScaleFactor = require_fontScaling_useFontScale.useFontScale(resolvedMaxFontSizeMultiplier);
|
|
45
50
|
const selected = !disabled && selectedId === uid;
|
|
46
51
|
const active = selected ? "on" : "off";
|
|
47
52
|
const interaction = pressed ? "pressed" : "rest";
|
|
@@ -102,6 +107,7 @@ const Tab = (0, react.memo)(function Tab({ value, children, startIcon, endIcon,
|
|
|
102
107
|
zIndex: 1,
|
|
103
108
|
position: "relative"
|
|
104
109
|
};
|
|
110
|
+
if (fontScaleFactor !== 1 && typeof base.height === "number") base.height = Math.round(base.height * fontScaleFactor);
|
|
105
111
|
if (selected && !reduceMotion) return {
|
|
106
112
|
...base,
|
|
107
113
|
...CLEAR_SELECTION_CHROME
|
|
@@ -109,6 +115,7 @@ const Tab = (0, react.memo)(function Tab({ value, children, startIcon, endIcon,
|
|
|
109
115
|
return base;
|
|
110
116
|
}, [
|
|
111
117
|
rootBase,
|
|
118
|
+
fontScaleFactor,
|
|
112
119
|
selected,
|
|
113
120
|
reduceMotion
|
|
114
121
|
]);
|
|
@@ -140,16 +147,19 @@ const Tab = (0, react.memo)(function Tab({ value, children, startIcon, endIcon,
|
|
|
140
147
|
startIcon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_IconSlot.IconSlot, {
|
|
141
148
|
icon: startIcon,
|
|
142
149
|
size: "sm",
|
|
150
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
143
151
|
style: iconStyle,
|
|
144
152
|
...iconColor !== void 0 ? { color: iconColor } : {}
|
|
145
153
|
}) : null,
|
|
146
154
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabLabel, {
|
|
147
155
|
style: textStyle,
|
|
156
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
148
157
|
children
|
|
149
158
|
}),
|
|
150
159
|
endIcon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_IconSlot.IconSlot, {
|
|
151
160
|
icon: endIcon,
|
|
152
161
|
size: "sm",
|
|
162
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
153
163
|
style: iconStyle,
|
|
154
164
|
...iconColor !== void 0 ? { color: iconColor } : {}
|
|
155
165
|
}) : null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tab.d.cts","names":[],"sources":["../../../src/components/Tabs/Tab.tsx"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"Tab.d.cts","names":[],"sources":["../../../src/components/Tabs/Tab.tsx"],"mappings":";;;;;;;UAmBU,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;;;;;;;;;;cAwCJ,GAAA,EAAG,OAAA,CAAA,oBAAA,CAAA,QAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tab.d.ts","names":[],"sources":["../../../src/components/Tabs/Tab.tsx"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"Tab.d.ts","names":[],"sources":["../../../src/components/Tabs/Tab.tsx"],"mappings":";;;;;;;UAmBU,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;;;;;;;;;;cAwCJ,GAAA,EAAG,OAAA,CAAA,oBAAA,CAAA,QAAA"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
+
import { useMaxFontSizeMultiplier } from "../../fontScaling/useMaxFontSizeMultiplier.js";
|
|
2
3
|
import { IconSlot } from "../IconSlot.js";
|
|
4
|
+
import { useFontScale } from "../../fontScaling/useFontScale.js";
|
|
3
5
|
import { Pressable as Pressable$1 } from "../Pressable.js";
|
|
4
6
|
import { useTabSelectionContext, useTabsVisualContext } from "./tabsContexts.js";
|
|
5
7
|
import { getMergedTabLayerStyle, getTabLayerStyle } from "./tabTheme.js";
|
|
@@ -17,9 +19,10 @@ const CLEAR_SELECTION_CHROME = {
|
|
|
17
19
|
elevation: 0,
|
|
18
20
|
boxShadow: []
|
|
19
21
|
};
|
|
20
|
-
function TabLabel({ style, children }) {
|
|
22
|
+
function TabLabel({ style, maxFontSizeMultiplier, children }) {
|
|
21
23
|
if (typeof children === "string" || typeof children === "number") return /* @__PURE__ */ jsx(Text, {
|
|
22
24
|
style,
|
|
25
|
+
maxFontSizeMultiplier,
|
|
23
26
|
children
|
|
24
27
|
});
|
|
25
28
|
return children;
|
|
@@ -36,10 +39,12 @@ function TabLabel({ style, children }) {
|
|
|
36
39
|
const Tab = memo(function Tab({ value, children, startIcon, endIcon, disabled, style, ...pressableRest }) {
|
|
37
40
|
const generatedId = useId();
|
|
38
41
|
const uid = value ?? `uds-tab-${generatedId}`;
|
|
39
|
-
const { variant: visualVariant, reduceMotion } = useTabsVisualContext();
|
|
42
|
+
const { variant: visualVariant, reduceMotion, maxFontSizeMultiplier } = useTabsVisualContext();
|
|
40
43
|
const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } = useTabSelectionContext();
|
|
41
44
|
const { theme } = useUnistyles();
|
|
42
45
|
const [pressed, setPressed] = useState(false);
|
|
46
|
+
const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier) ?? 0;
|
|
47
|
+
const fontScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier);
|
|
43
48
|
const selected = !disabled && selectedId === uid;
|
|
44
49
|
const active = selected ? "on" : "off";
|
|
45
50
|
const interaction = pressed ? "pressed" : "rest";
|
|
@@ -100,6 +105,7 @@ const Tab = memo(function Tab({ value, children, startIcon, endIcon, disabled, s
|
|
|
100
105
|
zIndex: 1,
|
|
101
106
|
position: "relative"
|
|
102
107
|
};
|
|
108
|
+
if (fontScaleFactor !== 1 && typeof base.height === "number") base.height = Math.round(base.height * fontScaleFactor);
|
|
103
109
|
if (selected && !reduceMotion) return {
|
|
104
110
|
...base,
|
|
105
111
|
...CLEAR_SELECTION_CHROME
|
|
@@ -107,6 +113,7 @@ const Tab = memo(function Tab({ value, children, startIcon, endIcon, disabled, s
|
|
|
107
113
|
return base;
|
|
108
114
|
}, [
|
|
109
115
|
rootBase,
|
|
116
|
+
fontScaleFactor,
|
|
110
117
|
selected,
|
|
111
118
|
reduceMotion
|
|
112
119
|
]);
|
|
@@ -138,16 +145,19 @@ const Tab = memo(function Tab({ value, children, startIcon, endIcon, disabled, s
|
|
|
138
145
|
startIcon ? /* @__PURE__ */ jsx(IconSlot, {
|
|
139
146
|
icon: startIcon,
|
|
140
147
|
size: "sm",
|
|
148
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
141
149
|
style: iconStyle,
|
|
142
150
|
...iconColor !== void 0 ? { color: iconColor } : {}
|
|
143
151
|
}) : null,
|
|
144
152
|
/* @__PURE__ */ jsx(TabLabel, {
|
|
145
153
|
style: textStyle,
|
|
154
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
146
155
|
children
|
|
147
156
|
}),
|
|
148
157
|
endIcon ? /* @__PURE__ */ jsx(IconSlot, {
|
|
149
158
|
icon: endIcon,
|
|
150
159
|
size: "sm",
|
|
160
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
151
161
|
style: iconStyle,
|
|
152
162
|
...iconColor !== void 0 ? { color: iconColor } : {}
|
|
153
163
|
}) : null,
|
|
@@ -1 +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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"}
|
|
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 { useFontScale } from '../../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../../fontScaling/useMaxFontSizeMultiplier';\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({\n style,\n maxFontSizeMultiplier,\n children,\n}: {\n style: TextStyle;\n maxFontSizeMultiplier: number;\n children: ReactNode;\n}) {\n if (typeof children === 'string' || typeof children === 'number') {\n return (\n <RNText style={style} maxFontSizeMultiplier={maxFontSizeMultiplier}>\n {children}\n </RNText>\n );\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, maxFontSizeMultiplier } = useTabsVisualContext();\n const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } =\n useTabSelectionContext();\n const { theme } = useUnistyles();\n const [pressed, setPressed] = useState(false);\n\n // One capped factor governs the label, icons, and the tab's fixed height.\n const resolvedMaxFontSizeMultiplier =\n useMaxFontSizeMultiplier('control', maxFontSizeMultiplier) ?? 0;\n const fontScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier);\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 // A fixed token height grows with the capped label so text never clips.\n if (fontScaleFactor !== 1 && typeof base.height === 'number') {\n base.height = Math.round(base.height * fontScaleFactor);\n }\n if (selected && !reduceMotion) {\n return { ...base, ...CLEAR_SELECTION_CHROME };\n }\n return base;\n }, [rootBase, fontScaleFactor, 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 maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={iconStyle}\n {...(iconColor !== undefined ? { color: iconColor } : {})}\n />\n ) : null}\n <TabLabel style={textStyle} maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}>\n {children}\n </TabLabel>\n {endIcon ? (\n <IconSlot\n icon={endIcon}\n size=\"sm\"\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\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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"}
|
|
@@ -30,11 +30,16 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
30
30
|
* </Tabs>
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
|
-
const Tabs = (0, react.memo)(function Tabs({ children, variant = "primary", reduceMotion = false, defaultSelectedId, selectedId, onSelectionChange }) {
|
|
33
|
+
const Tabs = (0, react.memo)(function Tabs({ children, variant = "primary", reduceMotion = false, maxFontSizeMultiplier, defaultSelectedId, selectedId, onSelectionChange }) {
|
|
34
34
|
const visual = (0, react.useMemo)(() => ({
|
|
35
35
|
variant,
|
|
36
|
-
reduceMotion
|
|
37
|
-
|
|
36
|
+
reduceMotion,
|
|
37
|
+
maxFontSizeMultiplier
|
|
38
|
+
}), [
|
|
39
|
+
variant,
|
|
40
|
+
reduceMotion,
|
|
41
|
+
maxFontSizeMultiplier
|
|
42
|
+
]);
|
|
38
43
|
const selection = require_components_Tabs_tabsContexts.useTabSelectionState({
|
|
39
44
|
defaultSelectedId,
|
|
40
45
|
selectedId,
|
|
@@ -3,7 +3,15 @@ import { UniversalTabsProps } from "../../types/dist/index.cjs";
|
|
|
3
3
|
import * as _$react from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/components/Tabs/Tabs.d.ts
|
|
6
|
-
interface TabsProps extends UniversalTabsProps {
|
|
6
|
+
interface TabsProps extends UniversalTabsProps {
|
|
7
|
+
/**
|
|
8
|
+
* Caps how far tab labels and icons grow with the OS text-size setting;
|
|
9
|
+
* tabs grow to fit. Set null to remove the cap; override app-wide via
|
|
10
|
+
* UDSFontScalingProvider.
|
|
11
|
+
* @default 2
|
|
12
|
+
*/
|
|
13
|
+
maxFontSizeMultiplier?: number | null;
|
|
14
|
+
}
|
|
7
15
|
/**
|
|
8
16
|
* **⚙️ Tabs**
|
|
9
17
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.d.cts","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"Tabs.d.cts","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"mappings":";;;;;UAKU,SAAA,SAAkB,kBAAA;;;AAL+B;;;;EAYzD,qBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cA4BI,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA"}
|
|
@@ -3,7 +3,15 @@ import { UniversalTabsProps } from "../../types/dist/index.js";
|
|
|
3
3
|
import * as _$react from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/components/Tabs/Tabs.d.ts
|
|
6
|
-
interface TabsProps extends UniversalTabsProps {
|
|
6
|
+
interface TabsProps extends UniversalTabsProps {
|
|
7
|
+
/**
|
|
8
|
+
* Caps how far tab labels and icons grow with the OS text-size setting;
|
|
9
|
+
* tabs grow to fit. Set null to remove the cap; override app-wide via
|
|
10
|
+
* UDSFontScalingProvider.
|
|
11
|
+
* @default 2
|
|
12
|
+
*/
|
|
13
|
+
maxFontSizeMultiplier?: number | null;
|
|
14
|
+
}
|
|
7
15
|
/**
|
|
8
16
|
* **⚙️ Tabs**
|
|
9
17
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.d.ts","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"Tabs.d.ts","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"mappings":";;;;;UAKU,SAAA,SAAkB,kBAAA;;;AAL+B;;;;EAYzD,qBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cA4BI,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA"}
|
|
@@ -28,11 +28,16 @@ import { jsx } from "react/jsx-runtime";
|
|
|
28
28
|
* </Tabs>
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
|
-
const Tabs = memo(function Tabs({ children, variant = "primary", reduceMotion = false, defaultSelectedId, selectedId, onSelectionChange }) {
|
|
31
|
+
const Tabs = memo(function Tabs({ children, variant = "primary", reduceMotion = false, maxFontSizeMultiplier, defaultSelectedId, selectedId, onSelectionChange }) {
|
|
32
32
|
const visual = useMemo(() => ({
|
|
33
33
|
variant,
|
|
34
|
-
reduceMotion
|
|
35
|
-
|
|
34
|
+
reduceMotion,
|
|
35
|
+
maxFontSizeMultiplier
|
|
36
|
+
}), [
|
|
37
|
+
variant,
|
|
38
|
+
reduceMotion,
|
|
39
|
+
maxFontSizeMultiplier
|
|
40
|
+
]);
|
|
36
41
|
const selection = useTabSelectionState({
|
|
37
42
|
defaultSelectedId,
|
|
38
43
|
selectedId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.js","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import type { UniversalTabsProps } from '@yahoo/uds-types';\nimport { memo, useMemo } from 'react';\n\nimport { TabSelectionContext, TabsVisualContext, useTabSelectionState } from './tabsContexts';\n\n
|
|
1
|
+
{"version":3,"file":"Tabs.js","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import type { UniversalTabsProps } from '@yahoo/uds-types';\nimport { memo, useMemo } from 'react';\n\nimport { TabSelectionContext, TabsVisualContext, useTabSelectionState } from './tabsContexts';\n\ninterface TabsProps extends UniversalTabsProps {\n /**\n * Caps how far tab labels and icons grow with the OS text-size setting;\n * tabs grow to fit. Set null to remove the cap; override app-wide via\n * UDSFontScalingProvider.\n * @default 2\n */\n maxFontSizeMultiplier?: number | null;\n}\n\n/**\n * **⚙️ Tabs**\n *\n * @description\n * Organizes content into sections with a tab list and tab panels. Supports `primary` and\n * `secondary` variants. When `reduceMotion` is false, a sliding indicator animates between\n * tabs (240ms, cubic-bezier(0.2, 0, 0, 1)) to match web UDS.\n *\n * @category Navigation\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Tabs, TabList, Tab, TabPanel } from '@yahoo/uds-mobile/Tabs';\n *\n * <Tabs variant=\"primary\" defaultSelectedId=\"home\">\n * <TabList accessibilityLabel=\"Main\">\n * <Tab value=\"home\">Home</Tab>\n * <Tab value=\"about\">About</Tab>\n * </TabList>\n * <TabPanel tabId=\"home\">Home content</TabPanel>\n * <TabPanel tabId=\"about\">About content</TabPanel>\n * </Tabs>\n * ```\n */\nconst Tabs = memo(function Tabs({\n children,\n variant = 'primary',\n reduceMotion = false,\n maxFontSizeMultiplier,\n defaultSelectedId,\n selectedId,\n onSelectionChange,\n}: TabsProps) {\n const visual = useMemo(\n () => ({ variant, reduceMotion, maxFontSizeMultiplier }),\n [variant, reduceMotion, maxFontSizeMultiplier],\n );\n const selection = useTabSelectionState({\n defaultSelectedId,\n selectedId,\n onSelectionChange,\n });\n\n return (\n <TabsVisualContext.Provider value={visual}>\n <TabSelectionContext.Provider value={selection}>{children}</TabSelectionContext.Provider>\n </TabsVisualContext.Provider>\n );\n});\n\nTabs.displayName = 'Tabs';\n\nexport { Tabs };\nexport type { TabsProps };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAM,OAAO,KAAK,SAAS,KAAK,EAC9B,UACA,UAAU,WACV,eAAe,OACf,uBACA,mBACA,YACA,qBACY;CACZ,MAAM,SAAS,eACN;EAAE;EAAS;EAAc;EAAuB,GACvD;EAAC;EAAS;EAAc;EAAsB,CAC/C;CACD,MAAM,YAAY,qBAAqB;EACrC;EACA;EACA;EACD,CAAC;CAEF,OACE,oBAAC,kBAAkB,UAAnB;EAA4B,OAAO;YACjC,oBAAC,oBAAoB,UAArB;GAA8B,OAAO;GAAY;GAAwC,CAAA;EAC9D,CAAA;EAE/B;AAEF,KAAK,cAAc"}
|
|
@@ -7,6 +7,8 @@ import { LayoutRectangle } from "react-native";
|
|
|
7
7
|
interface TabsVisualContextValue {
|
|
8
8
|
variant: UniversalTabsVariant;
|
|
9
9
|
reduceMotion: boolean;
|
|
10
|
+
/** Tabs-level font-scaling cap; undefined = resolve from the control cap. */
|
|
11
|
+
maxFontSizeMultiplier?: number | null;
|
|
10
12
|
}
|
|
11
13
|
declare const TabsVisualContext: _$react.Context<TabsVisualContextValue>;
|
|
12
14
|
declare function useTabsVisualContext(): TabsVisualContextValue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabsContexts.d.cts","names":[],"sources":["../../../src/components/Tabs/tabsContexts.tsx"],"mappings":";;;;;;UAIiB,sBAAA;EACf,OAAA,EAAS,oBAAA;EACT,YAAA;AAAA;AAAA,cAGW,iBAAA,EAAiB,OAAA,CAAA,OAAA,CAAA,sBAAA;AAAA,iBAKd,oBAAA,CAAA,GAAwB,sBAAA;AAAA,UAIvB,wBAAA;EACf,UAAA;EACA,aAAA,GAAgB,EAAA;EAChB,WAAA,GAAc,EAAA;EACd,aAAA,GAAgB,EAAA;EAChB,UAAA,EAAY,WAAA,SAAoB,eAAA;EAChC,YAAA,GAAe,EAAA,UAAY,MAAA,EAAQ,eAAA;EACnC,cAAA,GAAiB,EAAA;AAAA;AAAA,cAGN,mBAAA,EAAmB,OAAA,CAAA,OAAA,CAAA,wBAAA;AAAA,iBAEhB,sBAAA,CAAA,GAA0B,wBAAA;AAAA,iBAQ1B,oBAAA,CAAA;EACd,iBAAA;EACA,UAAA,EAAY,cAAA;EACZ;AAAA;EAEA,iBAAA;EACA,UAAA;EACA,iBAAA,IAAqB,UAAA;AAAA,IACnB,wBAAA"}
|
|
1
|
+
{"version":3,"file":"tabsContexts.d.cts","names":[],"sources":["../../../src/components/Tabs/tabsContexts.tsx"],"mappings":";;;;;;UAIiB,sBAAA;EACf,OAAA,EAAS,oBAAA;EACT,YAAA;EAFe;EAIf,qBAAA;AAAA;AAAA,cAGW,iBAAA,EAAiB,OAAA,CAAA,OAAA,CAAA,sBAAA;AAAA,iBAKd,oBAAA,CAAA,GAAwB,sBAAA;AAAA,UAIvB,wBAAA;EACf,UAAA;EACA,aAAA,GAAgB,EAAA;EAChB,WAAA,GAAc,EAAA;EACd,aAAA,GAAgB,EAAA;EAChB,UAAA,EAAY,WAAA,SAAoB,eAAA;EAChC,YAAA,GAAe,EAAA,UAAY,MAAA,EAAQ,eAAA;EACnC,cAAA,GAAiB,EAAA;AAAA;AAAA,cAGN,mBAAA,EAAmB,OAAA,CAAA,OAAA,CAAA,wBAAA;AAAA,iBAEhB,sBAAA,CAAA,GAA0B,wBAAA;AAAA,iBAQ1B,oBAAA,CAAA;EACd,iBAAA;EACA,UAAA,EAAY,cAAA;EACZ;AAAA;EAEA,iBAAA;EACA,UAAA;EACA,iBAAA,IAAqB,UAAA;AAAA,IACnB,wBAAA"}
|
|
@@ -7,6 +7,8 @@ import { LayoutRectangle } from "react-native";
|
|
|
7
7
|
interface TabsVisualContextValue {
|
|
8
8
|
variant: UniversalTabsVariant;
|
|
9
9
|
reduceMotion: boolean;
|
|
10
|
+
/** Tabs-level font-scaling cap; undefined = resolve from the control cap. */
|
|
11
|
+
maxFontSizeMultiplier?: number | null;
|
|
10
12
|
}
|
|
11
13
|
declare const TabsVisualContext: _$react.Context<TabsVisualContextValue>;
|
|
12
14
|
declare function useTabsVisualContext(): TabsVisualContextValue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabsContexts.d.ts","names":[],"sources":["../../../src/components/Tabs/tabsContexts.tsx"],"mappings":";;;;;;UAIiB,sBAAA;EACf,OAAA,EAAS,oBAAA;EACT,YAAA;AAAA;AAAA,cAGW,iBAAA,EAAiB,OAAA,CAAA,OAAA,CAAA,sBAAA;AAAA,iBAKd,oBAAA,CAAA,GAAwB,sBAAA;AAAA,UAIvB,wBAAA;EACf,UAAA;EACA,aAAA,GAAgB,EAAA;EAChB,WAAA,GAAc,EAAA;EACd,aAAA,GAAgB,EAAA;EAChB,UAAA,EAAY,WAAA,SAAoB,eAAA;EAChC,YAAA,GAAe,EAAA,UAAY,MAAA,EAAQ,eAAA;EACnC,cAAA,GAAiB,EAAA;AAAA;AAAA,cAGN,mBAAA,EAAmB,OAAA,CAAA,OAAA,CAAA,wBAAA;AAAA,iBAEhB,sBAAA,CAAA,GAA0B,wBAAA;AAAA,iBAQ1B,oBAAA,CAAA;EACd,iBAAA;EACA,UAAA,EAAY,cAAA;EACZ;AAAA;EAEA,iBAAA;EACA,UAAA;EACA,iBAAA,IAAqB,UAAA;AAAA,IACnB,wBAAA"}
|
|
1
|
+
{"version":3,"file":"tabsContexts.d.ts","names":[],"sources":["../../../src/components/Tabs/tabsContexts.tsx"],"mappings":";;;;;;UAIiB,sBAAA;EACf,OAAA,EAAS,oBAAA;EACT,YAAA;EAFe;EAIf,qBAAA;AAAA;AAAA,cAGW,iBAAA,EAAiB,OAAA,CAAA,OAAA,CAAA,sBAAA;AAAA,iBAKd,oBAAA,CAAA,GAAwB,sBAAA;AAAA,UAIvB,wBAAA;EACf,UAAA;EACA,aAAA,GAAgB,EAAA;EAChB,WAAA,GAAc,EAAA;EACd,aAAA,GAAgB,EAAA;EAChB,UAAA,EAAY,WAAA,SAAoB,eAAA;EAChC,YAAA,GAAe,EAAA,UAAY,MAAA,EAAQ,eAAA;EACnC,cAAA,GAAiB,EAAA;AAAA;AAAA,cAGN,mBAAA,EAAmB,OAAA,CAAA,OAAA,CAAA,wBAAA;AAAA,iBAEhB,sBAAA,CAAA,GAA0B,wBAAA;AAAA,iBAQ1B,oBAAA,CAAA;EACd,iBAAA;EACA,UAAA,EAAY,cAAA;EACZ;AAAA;EAEA,iBAAA;EACA,UAAA;EACA,iBAAA,IAAqB,UAAA;AAAA,IACnB,wBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabsContexts.js","names":[],"sources":["../../../src/components/Tabs/tabsContexts.tsx"],"sourcesContent":["import type { UniversalTabsVariant } from '@yahoo/uds-types';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport type { LayoutRectangle } from 'react-native';\n\nexport interface TabsVisualContextValue {\n variant: UniversalTabsVariant;\n reduceMotion: boolean;\n}\n\nexport const TabsVisualContext = createContext<TabsVisualContextValue>({\n variant: 'primary',\n reduceMotion: false,\n});\n\nexport function useTabsVisualContext(): TabsVisualContextValue {\n return useContext(TabsVisualContext);\n}\n\nexport interface TabSelectionContextValue {\n selectedId: string | null | undefined;\n setSelectedId: (id: string) => void;\n registerTab: (id: string) => void;\n unregisterTab: (id: string) => void;\n tabLayouts: ReadonlyMap<string, LayoutRectangle>;\n setTabLayout: (id: string, layout: LayoutRectangle) => void;\n clearTabLayout: (id: string) => void;\n}\n\nexport const TabSelectionContext = createContext<TabSelectionContextValue | null>(null);\n\nexport function useTabSelectionContext(): TabSelectionContextValue {\n const ctx = useContext(TabSelectionContext);\n if (!ctx) {\n throw new Error('Tab components must be used within <Tabs>');\n }\n return ctx;\n}\n\nexport function useTabSelectionState({\n defaultSelectedId,\n selectedId: selectedIdProp,\n onSelectionChange,\n}: {\n defaultSelectedId?: string;\n selectedId?: string | null;\n onSelectionChange?: (selectedId: string | null | undefined) => void;\n}): TabSelectionContextValue {\n const isControlled = selectedIdProp !== undefined;\n const [internalSelectedId, setInternalSelectedId] = useState<string | null>(\n defaultSelectedId ?? null,\n );\n const [registeredIds, setRegisteredIds] = useState<string[]>([]);\n const [tabLayouts, setTabLayouts] = useState<Map<string, LayoutRectangle>>(() => new Map());\n\n const selectedId = isControlled ? selectedIdProp : internalSelectedId;\n\n const setSelectedId = useCallback(\n (id: string) => {\n if (!isControlled) {\n setInternalSelectedId(id);\n }\n onSelectionChange?.(id);\n },\n [isControlled, onSelectionChange],\n );\n\n const registerTab = useCallback((id: string) => {\n setRegisteredIds((prev) => (prev.includes(id) ? prev : [...prev, id]));\n }, []);\n\n const unregisterTab = useCallback((id: string) => {\n setRegisteredIds((prev) => prev.filter((x) => x !== id));\n setTabLayouts((prev) => {\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n const setTabLayout = useCallback((id: string, layout: LayoutRectangle) => {\n setTabLayouts((prev) => {\n const cur = prev.get(id);\n if (\n cur &&\n cur.x === layout.x &&\n cur.y === layout.y &&\n cur.width === layout.width &&\n cur.height === layout.height\n ) {\n return prev;\n }\n const next = new Map(prev);\n next.set(id, layout);\n return next;\n });\n }, []);\n\n const clearTabLayout = useCallback((id: string) => {\n setTabLayouts((prev) => {\n if (!prev.has(id)) {\n return prev;\n }\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n useEffect(() => {\n if (isControlled || defaultSelectedId !== undefined) {\n return;\n }\n if (internalSelectedId !== null) {\n return;\n }\n if (registeredIds.length === 0) {\n return;\n }\n setInternalSelectedId(registeredIds[0]!);\n }, [isControlled, defaultSelectedId, internalSelectedId, registeredIds]);\n\n return useMemo(\n () => ({\n selectedId,\n setSelectedId,\n registerTab,\n unregisterTab,\n tabLayouts,\n setTabLayout,\n clearTabLayout,\n }),\n [\n selectedId,\n setSelectedId,\n registerTab,\n unregisterTab,\n tabLayouts,\n setTabLayout,\n clearTabLayout,\n ],\n );\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"tabsContexts.js","names":[],"sources":["../../../src/components/Tabs/tabsContexts.tsx"],"sourcesContent":["import type { UniversalTabsVariant } from '@yahoo/uds-types';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport type { LayoutRectangle } from 'react-native';\n\nexport interface TabsVisualContextValue {\n variant: UniversalTabsVariant;\n reduceMotion: boolean;\n /** Tabs-level font-scaling cap; undefined = resolve from the control cap. */\n maxFontSizeMultiplier?: number | null;\n}\n\nexport const TabsVisualContext = createContext<TabsVisualContextValue>({\n variant: 'primary',\n reduceMotion: false,\n});\n\nexport function useTabsVisualContext(): TabsVisualContextValue {\n return useContext(TabsVisualContext);\n}\n\nexport interface TabSelectionContextValue {\n selectedId: string | null | undefined;\n setSelectedId: (id: string) => void;\n registerTab: (id: string) => void;\n unregisterTab: (id: string) => void;\n tabLayouts: ReadonlyMap<string, LayoutRectangle>;\n setTabLayout: (id: string, layout: LayoutRectangle) => void;\n clearTabLayout: (id: string) => void;\n}\n\nexport const TabSelectionContext = createContext<TabSelectionContextValue | null>(null);\n\nexport function useTabSelectionContext(): TabSelectionContextValue {\n const ctx = useContext(TabSelectionContext);\n if (!ctx) {\n throw new Error('Tab components must be used within <Tabs>');\n }\n return ctx;\n}\n\nexport function useTabSelectionState({\n defaultSelectedId,\n selectedId: selectedIdProp,\n onSelectionChange,\n}: {\n defaultSelectedId?: string;\n selectedId?: string | null;\n onSelectionChange?: (selectedId: string | null | undefined) => void;\n}): TabSelectionContextValue {\n const isControlled = selectedIdProp !== undefined;\n const [internalSelectedId, setInternalSelectedId] = useState<string | null>(\n defaultSelectedId ?? null,\n );\n const [registeredIds, setRegisteredIds] = useState<string[]>([]);\n const [tabLayouts, setTabLayouts] = useState<Map<string, LayoutRectangle>>(() => new Map());\n\n const selectedId = isControlled ? selectedIdProp : internalSelectedId;\n\n const setSelectedId = useCallback(\n (id: string) => {\n if (!isControlled) {\n setInternalSelectedId(id);\n }\n onSelectionChange?.(id);\n },\n [isControlled, onSelectionChange],\n );\n\n const registerTab = useCallback((id: string) => {\n setRegisteredIds((prev) => (prev.includes(id) ? prev : [...prev, id]));\n }, []);\n\n const unregisterTab = useCallback((id: string) => {\n setRegisteredIds((prev) => prev.filter((x) => x !== id));\n setTabLayouts((prev) => {\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n const setTabLayout = useCallback((id: string, layout: LayoutRectangle) => {\n setTabLayouts((prev) => {\n const cur = prev.get(id);\n if (\n cur &&\n cur.x === layout.x &&\n cur.y === layout.y &&\n cur.width === layout.width &&\n cur.height === layout.height\n ) {\n return prev;\n }\n const next = new Map(prev);\n next.set(id, layout);\n return next;\n });\n }, []);\n\n const clearTabLayout = useCallback((id: string) => {\n setTabLayouts((prev) => {\n if (!prev.has(id)) {\n return prev;\n }\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n useEffect(() => {\n if (isControlled || defaultSelectedId !== undefined) {\n return;\n }\n if (internalSelectedId !== null) {\n return;\n }\n if (registeredIds.length === 0) {\n return;\n }\n setInternalSelectedId(registeredIds[0]!);\n }, [isControlled, defaultSelectedId, internalSelectedId, registeredIds]);\n\n return useMemo(\n () => ({\n selectedId,\n setSelectedId,\n registerTab,\n unregisterTab,\n tabLayouts,\n setTabLayout,\n clearTabLayout,\n }),\n [\n selectedId,\n setSelectedId,\n registerTab,\n unregisterTab,\n tabLayouts,\n setTabLayout,\n clearTabLayout,\n ],\n );\n}\n"],"mappings":";;;AAWA,MAAa,oBAAoB,cAAsC;CACrE,SAAS;CACT,cAAc;CACf,CAAC;AAEF,SAAgB,uBAA+C;CAC7D,OAAO,WAAW,kBAAkB;;AAatC,MAAa,sBAAsB,cAA+C,KAAK;AAEvF,SAAgB,yBAAmD;CACjE,MAAM,MAAM,WAAW,oBAAoB;CAC3C,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,4CAA4C;CAE9D,OAAO;;AAGT,SAAgB,qBAAqB,EACnC,mBACA,YAAY,gBACZ,qBAK2B;CAC3B,MAAM,eAAe,mBAAmB,KAAA;CACxC,MAAM,CAAC,oBAAoB,yBAAyB,SAClD,qBAAqB,KACtB;CACD,MAAM,CAAC,eAAe,oBAAoB,SAAmB,EAAE,CAAC;CAChE,MAAM,CAAC,YAAY,iBAAiB,+BAA6C,IAAI,KAAK,CAAC;CAE3F,MAAM,aAAa,eAAe,iBAAiB;CAEnD,MAAM,gBAAgB,aACnB,OAAe;EACd,IAAI,CAAC,cACH,sBAAsB,GAAG;EAE3B,oBAAoB,GAAG;IAEzB,CAAC,cAAc,kBAAkB,CAClC;CAED,MAAM,cAAc,aAAa,OAAe;EAC9C,kBAAkB,SAAU,KAAK,SAAS,GAAG,GAAG,OAAO,CAAC,GAAG,MAAM,GAAG,CAAE;IACrE,EAAE,CAAC;CAEN,MAAM,gBAAgB,aAAa,OAAe;EAChD,kBAAkB,SAAS,KAAK,QAAQ,MAAM,MAAM,GAAG,CAAC;EACxD,eAAe,SAAS;GACtB,MAAM,OAAO,IAAI,IAAI,KAAK;GAC1B,KAAK,OAAO,GAAG;GACf,OAAO;IACP;IACD,EAAE,CAAC;CAEN,MAAM,eAAe,aAAa,IAAY,WAA4B;EACxE,eAAe,SAAS;GACtB,MAAM,MAAM,KAAK,IAAI,GAAG;GACxB,IACE,OACA,IAAI,MAAM,OAAO,KACjB,IAAI,MAAM,OAAO,KACjB,IAAI,UAAU,OAAO,SACrB,IAAI,WAAW,OAAO,QAEtB,OAAO;GAET,MAAM,OAAO,IAAI,IAAI,KAAK;GAC1B,KAAK,IAAI,IAAI,OAAO;GACpB,OAAO;IACP;IACD,EAAE,CAAC;CAEN,MAAM,iBAAiB,aAAa,OAAe;EACjD,eAAe,SAAS;GACtB,IAAI,CAAC,KAAK,IAAI,GAAG,EACf,OAAO;GAET,MAAM,OAAO,IAAI,IAAI,KAAK;GAC1B,KAAK,OAAO,GAAG;GACf,OAAO;IACP;IACD,EAAE,CAAC;CAEN,gBAAgB;EACd,IAAI,gBAAgB,sBAAsB,KAAA,GACxC;EAEF,IAAI,uBAAuB,MACzB;EAEF,IAAI,cAAc,WAAW,GAC3B;EAEF,sBAAsB,cAAc,GAAI;IACvC;EAAC;EAAc;EAAmB;EAAoB;EAAc,CAAC;CAExE,OAAO,eACE;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF"}
|
package/dist/components/Text.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
require("../_virtual/_rolldown/runtime.cjs");
|
|
4
|
+
const require_fontScaling_useMaxFontSizeMultiplier = require("../fontScaling/useMaxFontSizeMultiplier.cjs");
|
|
4
5
|
let react = require("react");
|
|
5
6
|
let react_native = require("react-native");
|
|
6
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -47,13 +48,14 @@ function hasCJKContent(children) {
|
|
|
47
48
|
*
|
|
48
49
|
* @see {@link Link} for interactive text links
|
|
49
50
|
*/
|
|
50
|
-
const Text = (0, react.memo)(function Text({ color = "primary", variant = "body1", fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, textAlign, textTransform, textDecorationLine, style, backgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, spacing, spacingHorizontal, spacingVertical, spacingBottom, spacingEnd, spacingStart, spacingTop, offset, offsetVertical, offsetHorizontal, offsetBottom, offsetEnd, offsetStart, offsetTop, flexShrink, verticalAlign, height, minHeight, maxHeight, width, minWidth, maxWidth, dangerouslySetColor, ref, children, ...props }) {
|
|
51
|
+
const Text = (0, react.memo)(function Text({ color = "primary", variant = "body1", fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, maxFontSizeMultiplier, textAlign, textTransform, textDecorationLine, style, backgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, spacing, spacingHorizontal, spacingVertical, spacingBottom, spacingEnd, spacingStart, spacingTop, offset, offsetVertical, offsetHorizontal, offsetBottom, offsetEnd, offsetStart, offsetTop, flexShrink, verticalAlign, height, minHeight, maxHeight, width, minWidth, maxWidth, dangerouslySetColor, ref, children, ...props }) {
|
|
51
52
|
const resolvedColor = color === "inherit" ? void 0 : color;
|
|
52
53
|
const resolvedVariant = variant === "inherit" ? void 0 : variant;
|
|
53
54
|
const resolvedFontFamily = fontFamily ?? resolvedVariant;
|
|
54
55
|
const resolvedFontSize = fontSize ?? resolvedVariant;
|
|
55
56
|
const resolvedLineHeight = lineHeight === "none" ? void 0 : lineHeight ?? (hasCJKContent(children) ? void 0 : resolvedVariant);
|
|
56
57
|
const resolvedLetterSpacing = letterSpacing ?? resolvedVariant;
|
|
58
|
+
const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier(resolvedVariant, maxFontSizeMultiplier);
|
|
57
59
|
generated_styles.styles.useVariants({
|
|
58
60
|
color: resolvedColor,
|
|
59
61
|
fontFamily: resolvedFontFamily,
|
|
@@ -124,6 +126,7 @@ const Text = (0, react.memo)(function Text({ color = "primary", variant = "body1
|
|
|
124
126
|
style,
|
|
125
127
|
generated_styles.styles.foundation
|
|
126
128
|
]),
|
|
129
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
127
130
|
...props,
|
|
128
131
|
children
|
|
129
132
|
});
|