@yahoo/uds-mobile 2.24.0-beta.7 → 2.24.0-beta.9

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 (129) hide show
  1. package/README.md +3 -1
  2. package/dist/components/Avatar/AvatarIcon.cjs +1 -1
  3. package/dist/components/Avatar/AvatarIcon.js +1 -1
  4. package/dist/components/Avatar/AvatarIcon.js.map +1 -1
  5. package/dist/components/Avatar/AvatarImage.cjs +1 -1
  6. package/dist/components/Avatar/AvatarImage.js +1 -1
  7. package/dist/components/Avatar/AvatarImage.js.map +1 -1
  8. package/dist/components/Avatar/AvatarText.cjs +1 -1
  9. package/dist/components/Avatar/AvatarText.js +1 -1
  10. package/dist/components/Avatar/AvatarText.js.map +1 -1
  11. package/dist/components/Avatar/useAvatarFontScale.cjs +2 -2
  12. package/dist/components/Avatar/useAvatarFontScale.d.cts +1 -1
  13. package/dist/components/Avatar/useAvatarFontScale.d.ts +1 -1
  14. package/dist/components/Avatar/useAvatarFontScale.js +3 -3
  15. package/dist/components/Avatar/useAvatarFontScale.js.map +1 -1
  16. package/dist/components/Button/buttonTheme.cjs +6 -1
  17. package/dist/components/Button/buttonTheme.d.cts +3 -1
  18. package/dist/components/Button/buttonTheme.d.cts.map +1 -1
  19. package/dist/components/Button/buttonTheme.d.ts +3 -1
  20. package/dist/components/Button/buttonTheme.d.ts.map +1 -1
  21. package/dist/components/Button/buttonTheme.js +6 -2
  22. package/dist/components/Button/buttonTheme.js.map +1 -1
  23. package/dist/components/Button.cjs +5 -4
  24. package/dist/components/Button.js +6 -5
  25. package/dist/components/Button.js.map +1 -1
  26. package/dist/components/Checkbox.cjs +13 -7
  27. package/dist/components/Checkbox.d.cts.map +1 -1
  28. package/dist/components/Checkbox.d.ts.map +1 -1
  29. package/dist/components/Checkbox.js +14 -8
  30. package/dist/components/Checkbox.js.map +1 -1
  31. package/dist/components/Chip/ChipBase.cjs +2 -2
  32. package/dist/components/Chip/ChipBase.js +3 -3
  33. package/dist/components/Chip/ChipBase.js.map +1 -1
  34. package/dist/components/Icon.cjs +8 -7
  35. package/dist/components/Icon.d.cts +2 -0
  36. package/dist/components/Icon.d.cts.map +1 -1
  37. package/dist/components/Icon.d.ts +2 -0
  38. package/dist/components/Icon.d.ts.map +1 -1
  39. package/dist/components/Icon.js +9 -8
  40. package/dist/components/Icon.js.map +1 -1
  41. package/dist/components/IconButton.cjs +17 -6
  42. package/dist/components/IconButton.d.cts +6 -0
  43. package/dist/components/IconButton.d.cts.map +1 -1
  44. package/dist/components/IconButton.d.ts +6 -0
  45. package/dist/components/IconButton.d.ts.map +1 -1
  46. package/dist/components/IconButton.js +18 -7
  47. package/dist/components/IconButton.js.map +1 -1
  48. package/dist/components/Input.cjs +4 -2
  49. package/dist/components/Input.js +5 -3
  50. package/dist/components/Input.js.map +1 -1
  51. package/dist/components/InputHelpText.cjs +2 -1
  52. package/dist/components/InputHelpText.js +2 -1
  53. package/dist/components/InputHelpText.js.map +1 -1
  54. package/dist/components/Link.cjs +5 -1
  55. package/dist/components/Link.d.cts.map +1 -1
  56. package/dist/components/Link.d.ts.map +1 -1
  57. package/dist/components/Link.js +5 -1
  58. package/dist/components/Link.js.map +1 -1
  59. package/dist/components/Pagination/Pagination.cjs +1 -1
  60. package/dist/components/Pagination/Pagination.js +1 -1
  61. package/dist/components/Pagination/Pagination.js.map +1 -1
  62. package/dist/components/Pagination/PaginationEllipsis.cjs +1 -1
  63. package/dist/components/Pagination/PaginationEllipsis.js +2 -2
  64. package/dist/components/Pagination/PaginationEllipsis.js.map +1 -1
  65. package/dist/components/Pagination/paginationContext.d.cts +2 -2
  66. package/dist/components/Pagination/paginationContext.d.ts +2 -2
  67. package/dist/components/Pagination/paginationContext.js.map +1 -1
  68. package/dist/components/Pagination/usePaginationControlStyles.cjs +1 -1
  69. package/dist/components/Pagination/usePaginationControlStyles.js +2 -2
  70. package/dist/components/Pagination/usePaginationControlStyles.js.map +1 -1
  71. package/dist/components/Radio/Radio.cjs +2 -2
  72. package/dist/components/Radio/Radio.js +3 -3
  73. package/dist/components/Radio/Radio.js.map +1 -1
  74. package/dist/components/Select/Select.cjs +3 -1
  75. package/dist/components/Select/Select.js +3 -1
  76. package/dist/components/Select/Select.js.map +1 -1
  77. package/dist/components/Select/SelectItem.cjs +1 -2
  78. package/dist/components/Select/SelectItem.js +2 -3
  79. package/dist/components/Select/SelectItem.js.map +1 -1
  80. package/dist/components/Select/SelectTrigger.cjs +1 -2
  81. package/dist/components/Select/SelectTrigger.js +2 -3
  82. package/dist/components/Select/SelectTrigger.js.map +1 -1
  83. package/dist/components/Select/types.d.cts +1 -1
  84. package/dist/components/Select/types.d.ts +1 -1
  85. package/dist/components/Switch.cjs +20 -5
  86. package/dist/components/Switch.d.cts.map +1 -1
  87. package/dist/components/Switch.d.ts.map +1 -1
  88. package/dist/components/Switch.js +21 -6
  89. package/dist/components/Switch.js.map +1 -1
  90. package/dist/components/Tabs/Tab.cjs +2 -2
  91. package/dist/components/Tabs/Tab.js +3 -3
  92. package/dist/components/Tabs/Tab.js.map +1 -1
  93. package/dist/components/Text.cjs +2 -1
  94. package/dist/components/Text.d.cts.map +1 -1
  95. package/dist/components/Text.d.ts.map +1 -1
  96. package/dist/components/Text.js +2 -1
  97. package/dist/components/Text.js.map +1 -1
  98. package/dist/fontScaling/FontScalingContext.cjs +20 -3
  99. package/dist/fontScaling/FontScalingContext.d.cts +11 -3
  100. package/dist/fontScaling/FontScalingContext.d.cts.map +1 -1
  101. package/dist/fontScaling/FontScalingContext.d.ts +11 -3
  102. package/dist/fontScaling/FontScalingContext.d.ts.map +1 -1
  103. package/dist/fontScaling/FontScalingContext.js +20 -5
  104. package/dist/fontScaling/FontScalingContext.js.map +1 -1
  105. package/dist/fontScaling/androidNonlinearFontScaling.cjs +85 -9
  106. package/dist/fontScaling/androidNonlinearFontScaling.d.cts +2 -2
  107. package/dist/fontScaling/androidNonlinearFontScaling.d.cts.map +1 -1
  108. package/dist/fontScaling/androidNonlinearFontScaling.d.ts +2 -2
  109. package/dist/fontScaling/androidNonlinearFontScaling.d.ts.map +1 -1
  110. package/dist/fontScaling/androidNonlinearFontScaling.js +85 -9
  111. package/dist/fontScaling/androidNonlinearFontScaling.js.map +1 -1
  112. package/dist/fontScaling/types.d.cts +8 -7
  113. package/dist/fontScaling/types.d.cts.map +1 -1
  114. package/dist/fontScaling/types.d.ts +8 -7
  115. package/dist/fontScaling/types.d.ts.map +1 -1
  116. package/dist/fontScaling/useFontScale.cjs +21 -4
  117. package/dist/fontScaling/useFontScale.d.cts +6 -17
  118. package/dist/fontScaling/useFontScale.d.cts.map +1 -1
  119. package/dist/fontScaling/useFontScale.d.ts +6 -17
  120. package/dist/fontScaling/useFontScale.d.ts.map +1 -1
  121. package/dist/fontScaling/useFontScale.js +21 -5
  122. package/dist/fontScaling/useFontScale.js.map +1 -1
  123. package/dist/mobile/generated/fontMetrics.cjs +530 -530
  124. package/dist/mobile/generated/fontMetrics.js +530 -530
  125. package/dist/mobile/generated/fontMetrics.js.map +1 -1
  126. package/fonts/index.cjs +214 -214
  127. package/fonts/index.mjs +214 -214
  128. package/generated/fontMetrics.ts +530 -530
  129. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
- import { useFontScale } from "../fontScaling/useFontScale.js";
2
+ import { useComponentFontScale } from "../fontScaling/useFontScale.js";
3
3
  import { useMaxFontSizeMultiplier } from "../fontScaling/useMaxFontSizeMultiplier.js";
4
+ import { getSafeIconCell } from "./Button/buttonTheme.js";
4
5
  import { IconSlot } from "./IconSlot.js";
5
6
  import { FormLabel } from "./FormLabel.js";
6
7
  import { memo, useCallback, useEffect, useMemo, useState } from "react";
@@ -52,7 +53,7 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
52
53
  const isOn = isControlled ? isOnProp : internalIsOn;
53
54
  const activeVariant = isOn ? "on" : "off";
54
55
  const { theme } = useUnistyles();
55
- const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier) ?? 0;
56
+ const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
56
57
  useEffect(() => {
57
58
  const checkReducedMotion = async () => {
58
59
  setPrefersReducedMotion(await AccessibilityInfo.isReduceMotionEnabled());
@@ -79,9 +80,9 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
79
80
  variant: activeVariant
80
81
  }) ?? switchStyles;
81
82
  const labelBaseSize = resolvedSwitchStyles.text.lineHeight ?? resolvedSwitchStyles.text.fontSize;
82
- const fontScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier, typeof labelBaseSize === "number" ? labelBaseSize : void 0);
83
+ const fontScaleFactor = useComponentFontScale(resolvedMaxFontSizeMultiplier, typeof labelBaseSize === "number" ? labelBaseSize : void 0);
83
84
  const handleIconSize = resolvedSwitchStyles.handleIcon.fontSize;
84
- const handleIconScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier, typeof handleIconSize === "number" ? handleIconSize : void 0);
85
+ const handleIconScaleFactor = useComponentFontScale(resolvedMaxFontSizeMultiplier, typeof handleIconSize === "number" ? handleIconSize : void 0);
85
86
  const scaledHandleIconSize = typeof handleIconSize === "number" ? Math.round(handleIconSize * handleIconScaleFactor) : void 0;
86
87
  const scaledTrackWidth = Math.round(resolvedSwitchStyles.switch.width * fontScaleFactor);
87
88
  const scaledTrackPadding = Math.round(resolvedSwitchStyles.switch.padding * fontScaleFactor);
@@ -181,7 +182,14 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
181
182
  variant: "fill",
182
183
  dangerouslySetSize: scaledHandleIconSize,
183
184
  allowFontScaling: false,
184
- style: [resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]
185
+ style: [
186
+ resolvedSwitchStyles.handleIcon,
187
+ variantLayerStyles.handleIcon,
188
+ scaledHandleIconSize === void 0 ? void 0 : {
189
+ fontSize: scaledHandleIconSize,
190
+ lineHeight: getSafeIconCell(scaledHandleIconSize)
191
+ }
192
+ ]
185
193
  })
186
194
  }), offIcon && !isOn && /* @__PURE__ */ jsx(Animated.View, {
187
195
  style: switchStaticStyles.iconContainer,
@@ -190,7 +198,14 @@ const Switch = memo(function Switch({ isOn: isOnProp, defaultIsOn = false, onCha
190
198
  variant: "fill",
191
199
  dangerouslySetSize: scaledHandleIconSize,
192
200
  allowFontScaling: false,
193
- style: [resolvedSwitchStyles.handleIcon, variantLayerStyles.handleIcon]
201
+ style: [
202
+ resolvedSwitchStyles.handleIcon,
203
+ variantLayerStyles.handleIcon,
204
+ scaledHandleIconSize === void 0 ? void 0 : {
205
+ fontSize: scaledHandleIconSize,
206
+ lineHeight: getSafeIconCell(scaledHandleIconSize)
207
+ }
208
+ ]
194
209
  })
195
210
  })]
196
211
  })
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","names":["StyleSheet"],"sources":["../../src/components/Switch.tsx"],"sourcesContent":["import 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 resolved cap governs track, handle, travel, and label. Android may\n // resolve different nonlinear factors for the label and handle glyph.\n const resolvedMaxFontSizeMultiplier =\n useMaxFontSizeMultiplier('control', maxFontSizeMultiplier) ?? 0;\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 const labelBaseSize = resolvedSwitchStyles.text.lineHeight ?? resolvedSwitchStyles.text.fontSize;\n const fontScaleFactor = useFontScale(\n resolvedMaxFontSizeMultiplier,\n typeof labelBaseSize === 'number' ? labelBaseSize : undefined,\n );\n // Size the handle glyph from the configured size layer and the same factor\n // Android would apply to a native glyph of this size.\n const handleIconSize = resolvedSwitchStyles.handleIcon.fontSize;\n const handleIconScaleFactor = useFontScale(\n resolvedMaxFontSizeMultiplier,\n typeof handleIconSize === 'number' ? handleIconSize : undefined,\n );\n const scaledHandleIconSize =\n typeof handleIconSize === 'number'\n ? Math.round(handleIconSize * handleIconScaleFactor)\n : undefined;\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
+ {"version":3,"file":"Switch.js","names":["StyleSheet"],"sources":["../../src/components/Switch.tsx"],"sourcesContent":["import 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 { useComponentFontScale } from '../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\nimport { getSafeIconCell } from './Button/buttonTheme';\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 resolved cap governs track, handle, travel, and label. Android may\n // resolve different nonlinear factors for the label and handle glyph.\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\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 const labelBaseSize = resolvedSwitchStyles.text.lineHeight ?? resolvedSwitchStyles.text.fontSize;\n const fontScaleFactor = useComponentFontScale(\n resolvedMaxFontSizeMultiplier,\n typeof labelBaseSize === 'number' ? labelBaseSize : undefined,\n );\n // Size the handle glyph from the configured size layer and the same factor\n // Android would apply to a native glyph of this size.\n const handleIconSize = resolvedSwitchStyles.handleIcon.fontSize;\n const handleIconScaleFactor = useComponentFontScale(\n resolvedMaxFontSizeMultiplier,\n typeof handleIconSize === 'number' ? handleIconSize : undefined,\n );\n const scaledHandleIconSize =\n typeof handleIconSize === 'number'\n ? Math.round(handleIconSize * handleIconScaleFactor)\n : undefined;\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={[\n resolvedSwitchStyles.handleIcon,\n variantLayerStyles.handleIcon,\n scaledHandleIconSize === undefined\n ? undefined\n : {\n fontSize: scaledHandleIconSize,\n lineHeight: getSafeIconCell(scaledHandleIconSize),\n },\n ]}\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={[\n resolvedSwitchStyles.handleIcon,\n variantLayerStyles.handleIcon,\n scaledHandleIconSize === undefined\n ? undefined\n : {\n fontSize: scaledHandleIconSize,\n lineHeight: getSafeIconCell(scaledHandleIconSize),\n },\n ]}\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":";;;;;;;;;;;;;;AA6CA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmC3B,MAAM,SAAS,KAAK,SAAS,OAAO,EAClC,MAAM,UACN,cAAc,OACd,UACA,OACA,gBAAgB,SAChB,OAAO,MACP,QACA,SACA,WAAW,OACX,UACA,uBACA,mBACA,eAAe,OACf,KACA,GAAG,aACW;CACd,MAAM,eAAe,aAAa,KAAA;CAClC,MAAM,CAAC,cAAc,mBAAmB,SAAS,YAAY;CAC7D,MAAM,CAAC,sBAAsB,2BAA2B,SAAS,MAAM;CACvE,MAAM,OAAO,eAAe,WAAW;CACvC,MAAM,gBAAgB,OAAO,OAAO;CACpC,MAAM,EAAE,UAAU,cAAc;CAIhC,MAAM,gCAAgC,yBAAyB,WAAW,sBAAsB;CAEhG,gBAAgB;EACd,MAAM,qBAAqB,YAAY;GAErC,wBAAwB,MADY,kBAAkB,uBAAuB,CAC/B;;EAEhD,oBAAoB;EAEpB,MAAM,eAAe,kBAAkB,iBACrC,uBACA,wBACD;EACD,aAAa,aAAa,QAAQ;IACjC,EAAE,CAAC;CAGN,MAAM,oBADqB,gBAAgB,uBACI,IAAI;CAEnD,MAAM,WAAW,sBACT,WAAW,OAAO,IAAI,GAAG,EAAE,UAAU,mBAAmB,CAAC,EAC/D,CAAC,MAAM,kBAAkB,CAC1B;CAED,MAAM,cAAc,kBAAkB;EACpC,IAAI,UACF;EAGF,MAAM,WAAW,CAAC;EAElB,IAAI,CAAC,cACH,gBAAgB,SAAS;EAG3B,WAAW,SAAS;IACnB;EAAC;EAAU;EAAM;EAAc;EAAS,CAAC;CAQ5C,MAAM,uBAJsB,aAAa,YAAY;EACnD;EACA,SAAS;EACV,CAC+C,IAAI;CACpD,MAAM,gBAAgB,qBAAqB,KAAK,cAAc,qBAAqB,KAAK;CACxF,MAAM,kBAAkB,sBACtB,+BACA,OAAO,kBAAkB,WAAW,gBAAgB,KAAA,EACrD;CAGD,MAAM,iBAAiB,qBAAqB,WAAW;CACvD,MAAM,wBAAwB,sBAC5B,+BACA,OAAO,mBAAmB,WAAW,iBAAiB,KAAA,EACvD;CACD,MAAM,uBACJ,OAAO,mBAAmB,WACtB,KAAK,MAAM,iBAAiB,sBAAsB,GAClD,KAAA;CAKN,MAAM,mBAAmB,KAAK,MAAM,qBAAqB,OAAO,QAAQ,gBAAgB;CACxF,MAAM,qBAAqB,KAAK,MAAM,qBAAqB,OAAO,UAAU,gBAAgB;CAC5F,MAAM,oBAAoB,KAAK,MAAM,qBAAqB,OAAO,QAAQ,gBAAgB;CAMzF,MAAM,iBALqB,KAAK,IAC9B,GACA,mBAAmB,oBAAoB,qBAAqB,EAGrB,IAAI,YAAY,QAAQ,KAAK;CAEtE,MAAM,qBAAqB,cAAc;EACvC,MAAM,aAAa,MAAM;EACzB,MAAM,iBAA0B,UAC9B,WAAW,iCAAiC,cAAc,GAAG,MAAM;EAGrE,OAAO;GACL,QAAQ,cAAyB,SAAS;GAC1C,YAAY,cAAyB,aAAa;GAClD,QAAQ,cAAyB,SAAS;GAC1C,MAAM,cAAyB,WAAW;GAC3C;IACA,CAAC,eAAe,MAAM,CAAC;CAG1B,MAAM,uBAAuB,wBAC3B,qBAAqB,QACrB,kBACD;CAED,MAAM,qBAAqB,uBAAuB;AAChD;EACA,OAAO,EACL,iBAAiB,WAAW,qBAAqB,OAAO,EAAE,UAAU,mBAAmB,CAAC,EACzF;GACD;CAEF,MAAM,sBAAsB,uBAAuB;AACjD;EACA,OAAO,EACL,WAAW,CAAC,EAAE,YAAY,SAAS,QAAQ,gBAAgB,CAAC,EAC7D;GACD;CAEF,MAAM,YAAkC,cAChC,CAAC,qBAAqB,MAAM,mBAAmB,KAAK,EAAE,UAAU,CAAC,CAAC,EACxE,CAAC,qBAAqB,MAAM,SAAS,CACtC;CAKD,MAAM,kBAAkB,aACrB,UAAwD;EACvD,IAAI,CAAC,SAAS,oBAAoB,GAChC;EAEF,MAAM,EAAE,OAAO,QAAQ,YAAY;EACnC,OAAO,OAAO,UAAU,YAAY,OAAO,WAAW,WAClD;GACE,OAAO,KAAK,MAAM,QAAQ,gBAAgB;GAC1C,QAAQ,KAAK,MAAM,SAAS,gBAAgB;GAC5C,GAAI,OAAO,YAAY,YAAY,EACjC,SAAS,KAAK,MAAM,UAAU,gBAAgB,EAC/C;GACF,GACD,KAAA;IAEN,CAAC,gBAAgB,CAClB;CAED,MAAM,aAAmC,cACjC;EACJ,qBAAqB;EACrB,mBAAmB;EACnB,mBAAmB;EACnB,gBAAgB,qBAAqB,OAAoB;EAGzD,SAAS,OAAO,SAAS;EAC1B,EACD;EAAC,qBAAqB;EAAQ,mBAAmB;EAAQ;EAAiB;EAAmB,CAC9F;CAED,MAAM,cAAoC,cAClC;EACJ,qBAAqB;EACrB,mBAAmB;EACnB,mBAAmB;EACnB,gBAAgB,qBAAqB,OAAoB;EACzD;EACD,EACD;EAAC,qBAAqB;EAAQ,mBAAmB;EAAQ;EAAiB;EAAoB,CAC/F;CAED,MAAM,qBAAqB,OAAO,UAAU,WAAW,QAAQ,KAAA;CAC/D,MAAM,4BAA4B,qBAAqB;CAEvD,MAAM,eAAe,SACnB,oBAAC,WAAD;EACE,OAAM;EACN,SAAQ;EACD;EACG;EACV,sBAAsB;EACtB,uBAAuB;EACvB,OAAO,CAAC,qBAAqB,MAAM,mBAAmB,KAAK;EAC3D,CAAA;CAGJ,MAAM,YAAY,eAAe,EAAE,MAAM,OAAO,OAAO,OAAO,GAAG,CAAC,KAAK,CAAC;CAExE,OACE,qBAAC,WAAD;EACO;EACL,SAAS;EACC;EACV,YAAA;EACA,mBAAkB;EAClB,oBAAoB;GAAE,SAAS;GAAM;GAAU;EAC3B;EACpB,mBAAmB;EACnB,oBAAoB;EACpB,GAAI;EACJ,OAAO;YAXT;GAaG,kBAAkB,WAAW;GAE9B,oBAAC,SAAS,MAAV;IAAe,OAAO;IAAY,2BAA0B;cAC1D,qBAAC,SAAS,MAAV;KAAe,OAAO;eAAtB,CACG,UAAU,QACT,oBAAC,SAAS,MAAV;MAAe,OAAO,mBAAmB;gBACvC,oBAAC,UAAD;OACE,MAAM;OACN,SAAQ;OACR,oBAAoB;OACpB,kBAAkB;OAClB,OAAO;QACL,qBAAqB;QACrB,mBAAmB;QACnB,yBAAyB,KAAA,IACrB,KAAA,IACA;SACE,UAAU;SACV,YAAY,gBAAgB,qBAAqB;SAClD;QACN;OACD,CAAA;MACY,CAAA,EAEjB,WAAW,CAAC,QACX,oBAAC,SAAS,MAAV;MAAe,OAAO,mBAAmB;gBACvC,oBAAC,UAAD;OACE,MAAM;OACN,SAAQ;OACR,oBAAoB;OACpB,kBAAkB;OAClB,OAAO;QACL,qBAAqB;QACrB,mBAAmB;QACnB,yBAAyB,KAAA,IACrB,KAAA,IACA;SACE,UAAU;SACV,YAAY,gBAAgB,qBAAqB;SAClD;QACN;OACD,CAAA;MACY,CAAA,CAEJ;;IACF,CAAA;GAEf,kBAAkB,SAAS;GAClB;;EAEd;AAEF,OAAO,cAAc;AAErB,MAAM,qBAAqBA,aAAW,QAAQ,WAAW;CACvD,QAAQ;EACN,cAAc,MAAM,aAAa;EACjC,YAAY;EACZ,gBAAgB;EACjB;CACD,eAAe;EACb,UAAU;EACV,YAAY;EACZ,gBAAgB;EACjB;CACD,OAAO;EACL,gBAAgB;EAChB,cAAc,MAAM,aAAa;EAClC;CACD,OAAO,EAAE,gBAAuC;EAC9C,eAAe;EACf,YAAY;EACZ,WAAW;EACX,SAAS,WAAW,KAAM;EAC3B;CACF,EAAE"}
@@ -49,7 +49,7 @@ const Tab = (0, react.memo)(function Tab({ value, children, startIcon, endIcon,
49
49
  const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } = require_components_Tabs_tabsContexts.useTabSelectionContext();
50
50
  const { theme } = (0, react_native_unistyles.useUnistyles)();
51
51
  const [pressed, setPressed] = (0, react.useState)(false);
52
- const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier) ?? 0;
52
+ const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
53
53
  const selected = !disabled && selectedId === uid;
54
54
  const active = selected ? "on" : "off";
55
55
  const interaction = pressed ? "pressed" : "rest";
@@ -75,7 +75,7 @@ const Tab = (0, react.memo)(function Tab({ value, children, startIcon, endIcon,
75
75
  active,
76
76
  interaction
77
77
  ]);
78
- const fontScaleFactor = require_fontScaling_useFontScale.useFontScale(resolvedMaxFontSizeMultiplier, (typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : void 0) ?? (typeof textStyle.fontSize === "number" ? textStyle.fontSize : void 0));
78
+ const fontScaleFactor = require_fontScaling_useFontScale.useComponentFontScale(resolvedMaxFontSizeMultiplier, (typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : void 0) ?? (typeof textStyle.fontSize === "number" ? textStyle.fontSize : void 0));
79
79
  const iconStyle = (0, react.useMemo)(() => require_components_Tabs_tabTheme.getMergedTabLayerStyle(theme, visualVariant, active, "icon", interaction), [
80
80
  theme,
81
81
  visualVariant,
@@ -1,6 +1,6 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
2
  import { ResolvedControlFontScalingProvider } from "../../fontScaling/FontScalingContext.js";
3
- import { useFontScale } from "../../fontScaling/useFontScale.js";
3
+ import { useComponentFontScale } from "../../fontScaling/useFontScale.js";
4
4
  import { useMaxFontSizeMultiplier } from "../../fontScaling/useMaxFontSizeMultiplier.js";
5
5
  import { IconSlot } from "../IconSlot.js";
6
6
  import { Pressable as Pressable$1 } from "../Pressable.js";
@@ -47,7 +47,7 @@ const Tab = memo(function Tab({ value, children, startIcon, endIcon, disabled, s
47
47
  const { selectedId, setSelectedId, registerTab, unregisterTab, setTabLayout } = useTabSelectionContext();
48
48
  const { theme } = useUnistyles();
49
49
  const [pressed, setPressed] = useState(false);
50
- const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier) ?? 0;
50
+ const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
51
51
  const selected = !disabled && selectedId === uid;
52
52
  const active = selected ? "on" : "off";
53
53
  const interaction = pressed ? "pressed" : "rest";
@@ -73,7 +73,7 @@ const Tab = memo(function Tab({ value, children, startIcon, endIcon, disabled, s
73
73
  active,
74
74
  interaction
75
75
  ]);
76
- const fontScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier, (typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : void 0) ?? (typeof textStyle.fontSize === "number" ? textStyle.fontSize : void 0));
76
+ const fontScaleFactor = useComponentFontScale(resolvedMaxFontSizeMultiplier, (typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : void 0) ?? (typeof textStyle.fontSize === "number" ? textStyle.fontSize : void 0));
77
77
  const iconStyle = useMemo(() => getMergedTabLayerStyle(theme, visualVariant, active, "icon", interaction), [
78
78
  theme,
79
79
  visualVariant,
@@ -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 { ResolvedControlFontScalingProvider } from '../../fontScaling/FontScalingContext';\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 (\n <ResolvedControlFontScalingProvider maxFontSizeMultiplier={maxFontSizeMultiplier}>\n {children as ReactElement}\n </ResolvedControlFontScalingProvider>\n );\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\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 fontScaleFactor = useFontScale(\n resolvedMaxFontSizeMultiplier,\n (typeof textStyle.lineHeight === 'number' ? textStyle.lineHeight : undefined) ??\n (typeof textStyle.fontSize === 'number' ? textStyle.fontSize : undefined),\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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"}
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 { ResolvedControlFontScalingProvider } from '../../fontScaling/FontScalingContext';\nimport { useComponentFontScale } 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 (\n <ResolvedControlFontScalingProvider maxFontSizeMultiplier={maxFontSizeMultiplier}>\n {children as ReactElement}\n </ResolvedControlFontScalingProvider>\n );\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 = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\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 fontScaleFactor = useComponentFontScale(\n resolvedMaxFontSizeMultiplier,\n (typeof textStyle.lineHeight === 'number' ? textStyle.lineHeight : undefined) ??\n (typeof textStyle.fontSize === 'number' ? textStyle.fontSize : undefined),\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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"}
@@ -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_FontScalingContext = require("../fontScaling/FontScalingContext.cjs");
4
5
  const require_fontScaling_constants = require("../fontScaling/constants.cjs");
5
6
  const require_fontScaling_useMaxFontSizeMultiplier = require("../fontScaling/useMaxFontSizeMultiplier.cjs");
6
7
  let react = require("react");
@@ -57,7 +58,7 @@ const Text = (0, react.memo)(function Text({ color = "primary", variant = "body1
57
58
  const resolvedLineHeight = lineHeight === "none" ? void 0 : lineHeight ?? (hasCJKContent(children) ? void 0 : resolvedVariant);
58
59
  const resolvedLetterSpacing = letterSpacing ?? resolvedVariant;
59
60
  const baseVariant = resolvedVariant?.split("/")[0];
60
- const defaultDynamicTypeRamp = baseVariant ? require_fontScaling_constants.DEFAULT_DYNAMIC_TYPE_RAMPS[baseVariant] : void 0;
61
+ const defaultDynamicTypeRamp = require_fontScaling_FontScalingContext.useDynamicTypeRampEnabled() && baseVariant ? require_fontScaling_constants.DEFAULT_DYNAMIC_TYPE_RAMPS[baseVariant] : void 0;
61
62
  const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier(resolvedVariant, maxFontSizeMultiplier);
62
63
  generated_styles.styles.useVariants({
63
64
  color: resolvedColor,
@@ -1 +1 @@
1
- {"version":3,"file":"Text.d.cts","names":[],"sources":["../../src/components/Text.tsx"],"mappings":";;;;;;;KAWK,WAAA,GAAc,OAAA,CACjB,WAAA,CAAY,UAAA;AAAA,KAGT,eAAA,GAAkB,WAAA;AAAA,KAIlB,kBAAA;AAAA,UAuBK,SAAA,SAAkB,WAAA;;EAE1B,GAAA,GAAM,GAAA,CAAI,MAAA;EAhCV;EAkCA,KAAA,GAAQ,UAAA;EAnCgB;EAqCxB,OAAA,GAAU,eAAA;EArCO;;;;;AACK;;;EA6CtB,qBAAA;EA1CgC;EA4ChC,UAAA,GAAa,UAAA;EAxCQ;EA0CrB,QAAA,GAAW,UAAA;EA1CU;EA4CrB,UAAA,GAAa,UAAA;EArBL;EAuBR,UAAA,GAAa,UAAA;;EAEb,aAAA,GAAgB,UAAA;EAvBV;EAyBN,SAAA,GAAY,UAAA;EArBF;EAuBV,aAAA,GAAgB,UAAA;EAVL;EAYX,kBAAA,GAAqB,kBAAA;EAErB,eAAA,GAAkB,UAAA;EAElB,YAAA,GAAe,UAAA;EACf,oBAAA,GAAuB,UAAA;EACvB,kBAAA,GAAqB,UAAA;EACrB,uBAAA,GAA0B,UAAA;EAC1B,qBAAA,GAAwB,UAAA;EACxB,WAAA,GAAc,UAAA;EACd,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EACpB,WAAA,GAAc,UAAA;EACd,mBAAA,GAAsB,UAAA;EACtB,qBAAA,GAAwB,UAAA;EACxB,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EAEpB,OAAA,GAAU,UAAA;EACV,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,aAAA,GAAgB,UAAA;EAChB,UAAA,GAAa,UAAA;EACb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EAEb,MAAA,GAAS,UAAA;EACT,cAAA,GAAiB,UAAA;EACjB,gBAAA,GAAmB,UAAA;EACnB,YAAA,GAAe,UAAA;EACf,SAAA,GAAY,UAAA;EACZ,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EAEZ,UAAA,GAAa,UAAA;EAEb,aAAA,GAAgB,SAAA;EAEhB,MAAA;EACA,KAAA;EACA,SAAA;EACA,SAAA;EACA,QAAA;EACA,QAAA;EAEA,mBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiCI,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA"}
1
+ {"version":3,"file":"Text.d.cts","names":[],"sources":["../../src/components/Text.tsx"],"mappings":";;;;;;;KAYK,WAAA,GAAc,OAAA,CACjB,WAAA,CAAY,UAAA;AAAA,KAGT,eAAA,GAAkB,WAAA;AAAA,KAIlB,kBAAA;AAAA,UAuBK,SAAA,SAAkB,WAAA;;EAE1B,GAAA,GAAM,GAAA,CAAI,MAAA;EAhCV;EAkCA,KAAA,GAAQ,UAAA;EAnCgB;EAqCxB,OAAA,GAAU,eAAA;EArCO;;;;;AACK;;;EA6CtB,qBAAA;EA1CgC;EA4ChC,UAAA,GAAa,UAAA;EAxCQ;EA0CrB,QAAA,GAAW,UAAA;EA1CU;EA4CrB,UAAA,GAAa,UAAA;EArBL;EAuBR,UAAA,GAAa,UAAA;;EAEb,aAAA,GAAgB,UAAA;EAvBV;EAyBN,SAAA,GAAY,UAAA;EArBF;EAuBV,aAAA,GAAgB,UAAA;EAVL;EAYX,kBAAA,GAAqB,kBAAA;EAErB,eAAA,GAAkB,UAAA;EAElB,YAAA,GAAe,UAAA;EACf,oBAAA,GAAuB,UAAA;EACvB,kBAAA,GAAqB,UAAA;EACrB,uBAAA,GAA0B,UAAA;EAC1B,qBAAA,GAAwB,UAAA;EACxB,WAAA,GAAc,UAAA;EACd,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EACpB,WAAA,GAAc,UAAA;EACd,mBAAA,GAAsB,UAAA;EACtB,qBAAA,GAAwB,UAAA;EACxB,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EAEpB,OAAA,GAAU,UAAA;EACV,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,aAAA,GAAgB,UAAA;EAChB,UAAA,GAAa,UAAA;EACb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EAEb,MAAA,GAAS,UAAA;EACT,cAAA,GAAiB,UAAA;EACjB,gBAAA,GAAmB,UAAA;EACnB,YAAA,GAAe,UAAA;EACf,SAAA,GAAY,UAAA;EACZ,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EAEZ,UAAA,GAAa,UAAA;EAEb,aAAA,GAAgB,SAAA;EAEhB,MAAA;EACA,KAAA;EACA,SAAA;EACA,SAAA;EACA,QAAA;EACA,QAAA;EAEA,mBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiCI,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Text.d.ts","names":[],"sources":["../../src/components/Text.tsx"],"mappings":";;;;;;;KAWK,WAAA,GAAc,OAAA,CACjB,WAAA,CAAY,UAAA;AAAA,KAGT,eAAA,GAAkB,WAAA;AAAA,KAIlB,kBAAA;AAAA,UAuBK,SAAA,SAAkB,WAAA;;EAE1B,GAAA,GAAM,GAAA,CAAI,MAAA;EAhCV;EAkCA,KAAA,GAAQ,UAAA;EAnCgB;EAqCxB,OAAA,GAAU,eAAA;EArCO;;;;;AACK;;;EA6CtB,qBAAA;EA1CgC;EA4ChC,UAAA,GAAa,UAAA;EAxCQ;EA0CrB,QAAA,GAAW,UAAA;EA1CU;EA4CrB,UAAA,GAAa,UAAA;EArBL;EAuBR,UAAA,GAAa,UAAA;;EAEb,aAAA,GAAgB,UAAA;EAvBV;EAyBN,SAAA,GAAY,UAAA;EArBF;EAuBV,aAAA,GAAgB,UAAA;EAVL;EAYX,kBAAA,GAAqB,kBAAA;EAErB,eAAA,GAAkB,UAAA;EAElB,YAAA,GAAe,UAAA;EACf,oBAAA,GAAuB,UAAA;EACvB,kBAAA,GAAqB,UAAA;EACrB,uBAAA,GAA0B,UAAA;EAC1B,qBAAA,GAAwB,UAAA;EACxB,WAAA,GAAc,UAAA;EACd,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EACpB,WAAA,GAAc,UAAA;EACd,mBAAA,GAAsB,UAAA;EACtB,qBAAA,GAAwB,UAAA;EACxB,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EAEpB,OAAA,GAAU,UAAA;EACV,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,aAAA,GAAgB,UAAA;EAChB,UAAA,GAAa,UAAA;EACb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EAEb,MAAA,GAAS,UAAA;EACT,cAAA,GAAiB,UAAA;EACjB,gBAAA,GAAmB,UAAA;EACnB,YAAA,GAAe,UAAA;EACf,SAAA,GAAY,UAAA;EACZ,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EAEZ,UAAA,GAAa,UAAA;EAEb,aAAA,GAAgB,SAAA;EAEhB,MAAA;EACA,KAAA;EACA,SAAA;EACA,SAAA;EACA,QAAA;EACA,QAAA;EAEA,mBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiCI,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA"}
1
+ {"version":3,"file":"Text.d.ts","names":[],"sources":["../../src/components/Text.tsx"],"mappings":";;;;;;;KAYK,WAAA,GAAc,OAAA,CACjB,WAAA,CAAY,UAAA;AAAA,KAGT,eAAA,GAAkB,WAAA;AAAA,KAIlB,kBAAA;AAAA,UAuBK,SAAA,SAAkB,WAAA;;EAE1B,GAAA,GAAM,GAAA,CAAI,MAAA;EAhCV;EAkCA,KAAA,GAAQ,UAAA;EAnCgB;EAqCxB,OAAA,GAAU,eAAA;EArCO;;;;;AACK;;;EA6CtB,qBAAA;EA1CgC;EA4ChC,UAAA,GAAa,UAAA;EAxCQ;EA0CrB,QAAA,GAAW,UAAA;EA1CU;EA4CrB,UAAA,GAAa,UAAA;EArBL;EAuBR,UAAA,GAAa,UAAA;;EAEb,aAAA,GAAgB,UAAA;EAvBV;EAyBN,SAAA,GAAY,UAAA;EArBF;EAuBV,aAAA,GAAgB,UAAA;EAVL;EAYX,kBAAA,GAAqB,kBAAA;EAErB,eAAA,GAAkB,UAAA;EAElB,YAAA,GAAe,UAAA;EACf,oBAAA,GAAuB,UAAA;EACvB,kBAAA,GAAqB,UAAA;EACrB,uBAAA,GAA0B,UAAA;EAC1B,qBAAA,GAAwB,UAAA;EACxB,WAAA,GAAc,UAAA;EACd,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EACpB,WAAA,GAAc,UAAA;EACd,mBAAA,GAAsB,UAAA;EACtB,qBAAA,GAAwB,UAAA;EACxB,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EAEpB,OAAA,GAAU,UAAA;EACV,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,aAAA,GAAgB,UAAA;EAChB,UAAA,GAAa,UAAA;EACb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EAEb,MAAA,GAAS,UAAA;EACT,cAAA,GAAiB,UAAA;EACjB,gBAAA,GAAmB,UAAA;EACnB,YAAA,GAAe,UAAA;EACf,SAAA,GAAY,UAAA;EACZ,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EAEZ,UAAA,GAAa,UAAA;EAEb,aAAA,GAAgB,SAAA;EAEhB,MAAA;EACA,KAAA;EACA,SAAA;EACA,SAAA;EACA,QAAA;EACA,QAAA;EAEA,mBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiCI,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA"}
@@ -1,4 +1,5 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ import { useDynamicTypeRampEnabled } from "../fontScaling/FontScalingContext.js";
2
3
  import { DEFAULT_DYNAMIC_TYPE_RAMPS } from "../fontScaling/constants.js";
3
4
  import { useMaxFontSizeMultiplier } from "../fontScaling/useMaxFontSizeMultiplier.js";
4
5
  import { memo, useMemo } from "react";
@@ -55,7 +56,7 @@ const Text = memo(function Text({ color = "primary", variant = "body1", fontFami
55
56
  const resolvedLineHeight = lineHeight === "none" ? void 0 : lineHeight ?? (hasCJKContent(children) ? void 0 : resolvedVariant);
56
57
  const resolvedLetterSpacing = letterSpacing ?? resolvedVariant;
57
58
  const baseVariant = resolvedVariant?.split("/")[0];
58
- const defaultDynamicTypeRamp = baseVariant ? DEFAULT_DYNAMIC_TYPE_RAMPS[baseVariant] : void 0;
59
+ const defaultDynamicTypeRamp = useDynamicTypeRampEnabled() && baseVariant ? DEFAULT_DYNAMIC_TYPE_RAMPS[baseVariant] : void 0;
59
60
  const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier(resolvedVariant, maxFontSizeMultiplier);
60
61
  styles.useVariants({
61
62
  color: resolvedColor,
@@ -1 +1 @@
1
- {"version":3,"file":"Text.js","names":["RNText"],"sources":["../../src/components/Text.tsx"],"sourcesContent":["import type { ReactNode, Ref } from 'react';\nimport { memo, useMemo } from 'react';\nimport type { StyleProp, TextProps as RNTextProps, TextStyle } from 'react-native';\nimport { Text as RNText } from 'react-native';\n\nimport type { StyleProps } from '../../generated/styles';\nimport { styles } from '../../generated/styles';\nimport { DEFAULT_DYNAMIC_TYPE_RAMPS } from '../fontScaling/constants';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\n\n// TextVariant is a subset of fontFamily that represents typography variants\ntype TextVariant = Exclude<\n NonNullable<StyleProps['fontFamily']>,\n 'sans' | 'sans-alt' | 'serif' | 'serif-alt' | 'mono' | 'icons'\n>;\ntype TextVariantProp = TextVariant | 'inherit';\n\n// React Native text decoration line values\n// See: https://reactnative.dev/docs/text-style-props#textdecorationline\ntype TextDecorationLine = 'none' | 'underline' | 'line-through' | 'underline line-through';\n\n// Chinese/Japanese/Korean scripts: Hangul Jamo, CJK radicals + punctuation,\n// Kana, Han ideographs, Hangul syllables, compatibility ideographs, and\n// full/half-width forms.\nconst CJK_RE =\n /[\\u1100-\\u11FF\\u2E80-\\u303F\\u3040-\\u30FF\\u31C0-\\u9FFF\\uAC00-\\uD7AF\\uF900-\\uFAFF\\uFF00-\\uFFEF]/;\n\n/**\n * Detects CJK characters in string children (including strings inside a\n * children array, e.g. from `{city}` interpolation). Nested elements are not\n * inspected - a nested <Text> runs its own detection.\n */\nfunction hasCJKContent(children: ReactNode): boolean {\n if (typeof children === 'string') {\n return CJK_RE.test(children);\n }\n if (Array.isArray(children)) {\n return children.some((child) => typeof child === 'string' && CJK_RE.test(child));\n }\n return false;\n}\n\ninterface TextProps extends RNTextProps {\n /** Ref to the underlying Text element */\n ref?: Ref<RNText>;\n /** Text color from the theme palette */\n color?: StyleProps['color'] | 'inherit';\n /** Typography variant - sets fontSize, lineHeight, letterSpacing, and fontFamily together */\n variant?: TextVariantProp;\n /**\n * Caps how far this text grows with the OS text-size setting. Every text\n * variant is capped at 2x or below by default, with the largest display and\n * title variants tapering further (see DEFAULT_MAX_FONT_SIZE_MULTIPLIERS).\n * Set null to remove the cap (maps to React Native's 0, which also overrides\n * an inherited cap); inherit-variant text inherits its parent's cap.\n * Override app-wide via UDSFontScalingProvider.\n */\n maxFontSizeMultiplier?: number | null;\n /** Override the fontFamily independently */\n fontFamily?: StyleProps['fontFamily'];\n /** Override the fontSize independently */\n fontSize?: StyleProps['fontSize'];\n /** Set font weight (not derived from variant) */\n fontWeight?: StyleProps['fontWeight'];\n /** Override the lineHeight independently. Use 'none' to remove the variant lineHeight and let the font's natural line height apply */\n lineHeight?: StyleProps['lineHeight'] | 'none';\n /** Override the letterSpacing independently */\n letterSpacing?: StyleProps['letterSpacing'];\n /** Text alignment (left, center, right) */\n textAlign?: StyleProps['textAlign'];\n /** Set text transform (not derived from variant) */\n textTransform?: StyleProps['textTransform'];\n /** Text decoration (underline, line-through, etc.) */\n textDecorationLine?: TextDecorationLine;\n // Background\n backgroundColor?: StyleProps['backgroundColor'];\n // Border\n borderRadius?: StyleProps['borderRadius'];\n borderTopStartRadius?: StyleProps['borderTopStartRadius'];\n borderTopEndRadius?: StyleProps['borderTopEndRadius'];\n borderBottomStartRadius?: StyleProps['borderBottomStartRadius'];\n borderBottomEndRadius?: StyleProps['borderBottomEndRadius'];\n borderColor?: StyleProps['borderColor'];\n borderStartColor?: StyleProps['borderStartColor'];\n borderEndColor?: StyleProps['borderEndColor'];\n borderTopColor?: StyleProps['borderTopColor'];\n borderBottomColor?: StyleProps['borderBottomColor'];\n borderWidth?: StyleProps['borderWidth'];\n borderVerticalWidth?: StyleProps['borderVerticalWidth'];\n borderHorizontalWidth?: StyleProps['borderHorizontalWidth'];\n borderStartWidth?: StyleProps['borderStartWidth'];\n borderEndWidth?: StyleProps['borderEndWidth'];\n borderTopWidth?: StyleProps['borderTopWidth'];\n borderBottomWidth?: StyleProps['borderBottomWidth'];\n // Spacing\n spacing?: StyleProps['spacing'];\n spacingHorizontal?: StyleProps['spacingHorizontal'];\n spacingVertical?: StyleProps['spacingVertical'];\n spacingBottom?: StyleProps['spacingBottom'];\n spacingEnd?: StyleProps['spacingEnd'];\n spacingStart?: StyleProps['spacingStart'];\n spacingTop?: StyleProps['spacingTop'];\n // Offset\n offset?: StyleProps['offset'];\n offsetVertical?: StyleProps['offsetVertical'];\n offsetHorizontal?: StyleProps['offsetHorizontal'];\n offsetBottom?: StyleProps['offsetBottom'];\n offsetEnd?: StyleProps['offsetEnd'];\n offsetStart?: StyleProps['offsetStart'];\n offsetTop?: StyleProps['offsetTop'];\n // Flex\n flexShrink?: StyleProps['flexShrink'];\n // Vertical Alignment\n verticalAlign?: TextStyle['textAlignVertical'];\n // Size\n height?: number | `${number}%`;\n width?: number | `${number}%`;\n minHeight?: number | `${number}%`;\n maxHeight?: number | `${number}%`;\n minWidth?: number | `${number}%`;\n maxWidth?: number | `${number}%`;\n // Dangerously set props\n dangerouslySetColor?: string;\n}\n\n/**\n * **📝 A text component with UDS styling**\n *\n * @description\n * A styled text component that supports UDS typography variants and colors.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Text } from '@yahoo/uds-mobile/Text';\n *\n * <Text variant=\"body1\" color=\"primary\">Hello, World!</Text>\n * <Text variant=\"display1\" fontWeight=\"bold\">Heading</Text>\n * <Text variant=\"label1\" color=\"secondary\">Caption text</Text>\n * ```\n *\n * @usage\n * - Use variant prop to set typography (display1, body1, label1, etc.)\n * - Use color prop to set text color from the palette\n * - Use fontWeight to override the variant's default weight\n *\n * @accessibility\n * - Text is readable by screen readers by default\n * - Use appropriate variant sizes for readability\n * - Ensure sufficient color contrast with background\n *\n * @see {@link Link} for interactive text links\n */\nconst Text = memo(function Text({\n // Text-specific\n color = 'primary',\n variant = 'body1',\n fontFamily,\n fontSize,\n fontWeight,\n lineHeight,\n letterSpacing,\n maxFontSizeMultiplier,\n textAlign,\n textTransform,\n textDecorationLine,\n style,\n // Background\n backgroundColor,\n // Border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n borderColor,\n borderStartColor,\n borderEndColor,\n borderTopColor,\n borderBottomColor,\n borderWidth,\n borderVerticalWidth,\n borderHorizontalWidth,\n borderStartWidth,\n borderEndWidth,\n borderTopWidth,\n borderBottomWidth,\n // Spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n // Offset\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n // Flex\n flexShrink,\n // Vertical Alignment\n verticalAlign,\n // Size\n height,\n minHeight,\n maxHeight,\n width,\n minWidth,\n maxWidth,\n // Dangerously set props\n dangerouslySetColor,\n ref,\n children,\n // Rest\n ...props\n}: TextProps) {\n const resolvedColor = color === 'inherit' ? undefined : color;\n const resolvedVariant = variant === 'inherit' ? undefined : variant;\n const resolvedFontFamily = fontFamily ?? resolvedVariant;\n const resolvedFontSize = fontSize ?? resolvedVariant;\n // React Native clips glyphs when lineHeight is smaller than the font's\n // natural line box. CJK fallback fonts are ~1.4x taller than Latin ones, so\n // Latin-tuned variant lineHeights clip CJK text - drop the variant lineHeight\n // for CJK content so the line grows to fit.\n const resolvedLineHeight =\n lineHeight === 'none'\n ? undefined\n : (lineHeight ?? (hasCJKContent(children) ? undefined : resolvedVariant));\n const resolvedLetterSpacing = letterSpacing ?? resolvedVariant;\n const baseVariant = resolvedVariant?.split('/')[0] as TextVariant | undefined;\n const defaultDynamicTypeRamp = baseVariant ? DEFAULT_DYNAMIC_TYPE_RAMPS[baseVariant] : undefined;\n // Explicit prop wins, including explicit null (?? would swallow it).\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier(\n resolvedVariant,\n maxFontSizeMultiplier,\n );\n\n styles.useVariants({\n // Text styles\n color: resolvedColor,\n fontFamily: resolvedFontFamily,\n fontSize: resolvedFontSize,\n fontWeight,\n lineHeight: resolvedLineHeight,\n letterSpacing: resolvedLetterSpacing,\n textAlign,\n textTransform,\n // Background\n backgroundColor,\n // Border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n borderColor,\n borderStartColor,\n borderEndColor,\n borderTopColor,\n borderBottomColor,\n borderWidth,\n borderVerticalWidth,\n borderHorizontalWidth,\n borderStartWidth,\n borderEndWidth,\n borderTopWidth,\n borderBottomWidth,\n // Spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n // Offset\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n // Flex\n flexShrink,\n });\n\n // styles.foundation must be in deps - it returns a new reference when variants change.\n const computedStyle: StyleProp<TextStyle> = useMemo(\n () => [\n textDecorationLine ? { textDecorationLine } : undefined,\n dangerouslySetColor ? { color: dangerouslySetColor } : undefined,\n verticalAlign ? { textAlignVertical: verticalAlign } : undefined,\n height ? { height } : undefined,\n minHeight ? { minHeight } : undefined,\n maxHeight ? { maxHeight } : undefined,\n width ? { width } : undefined,\n minWidth ? { minWidth } : undefined,\n maxWidth ? { maxWidth } : undefined,\n styles.foundation,\n style,\n ],\n [\n textDecorationLine,\n dangerouslySetColor,\n verticalAlign,\n height,\n minHeight,\n maxHeight,\n width,\n minWidth,\n maxWidth,\n style,\n styles.foundation,\n ],\n );\n\n return (\n <RNText\n ref={ref}\n style={computedStyle}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n dynamicTypeRamp={defaultDynamicTypeRamp}\n {...props}\n >\n {children}\n </RNText>\n );\n});\n\nText.displayName = 'Text';\n\nexport { Text, type TextProps, type TextVariant };\n"],"mappings":";;;;;;;;AAwBA,MAAM,SACJ;;;;;;AAOF,SAAS,cAAc,UAA8B;CACnD,IAAI,OAAO,aAAa,UACtB,OAAO,OAAO,KAAK,SAAS;CAE9B,IAAI,MAAM,QAAQ,SAAS,EACzB,OAAO,SAAS,MAAM,UAAU,OAAO,UAAU,YAAY,OAAO,KAAK,MAAM,CAAC;CAElF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoHT,MAAM,OAAO,KAAK,SAAS,KAAK,EAE9B,QAAQ,WACR,UAAU,SACV,YACA,UACA,YACA,YACA,eACA,uBACA,WACA,eACA,oBACA,OAEA,iBAEA,cACA,sBACA,oBACA,yBACA,uBACA,aACA,kBACA,gBACA,gBACA,mBACA,aACA,qBACA,uBACA,kBACA,gBACA,gBACA,mBAEA,SACA,mBACA,iBACA,eACA,YACA,cACA,YAEA,QACA,gBACA,kBACA,cACA,WACA,aACA,WAEA,YAEA,eAEA,QACA,WACA,WACA,OACA,UACA,UAEA,qBACA,KACA,UAEA,GAAG,SACS;CACZ,MAAM,gBAAgB,UAAU,YAAY,KAAA,IAAY;CACxD,MAAM,kBAAkB,YAAY,YAAY,KAAA,IAAY;CAC5D,MAAM,qBAAqB,cAAc;CACzC,MAAM,mBAAmB,YAAY;CAKrC,MAAM,qBACJ,eAAe,SACX,KAAA,IACC,eAAe,cAAc,SAAS,GAAG,KAAA,IAAY;CAC5D,MAAM,wBAAwB,iBAAiB;CAC/C,MAAM,cAAc,iBAAiB,MAAM,IAAI,CAAC;CAChD,MAAM,yBAAyB,cAAc,2BAA2B,eAAe,KAAA;CAEvF,MAAM,gCAAgC,yBACpC,iBACA,sBACD;CAED,OAAO,YAAY;EAEjB,OAAO;EACP,YAAY;EACZ,UAAU;EACV;EACA,YAAY;EACZ,eAAe;EACf;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACD,CAAC;CAgCF,OACE,oBAACA,QAAD;EACO;EACL,OAhCwC,cACpC;GACJ,qBAAqB,EAAE,oBAAoB,GAAG,KAAA;GAC9C,sBAAsB,EAAE,OAAO,qBAAqB,GAAG,KAAA;GACvD,gBAAgB,EAAE,mBAAmB,eAAe,GAAG,KAAA;GACvD,SAAS,EAAE,QAAQ,GAAG,KAAA;GACtB,YAAY,EAAE,WAAW,GAAG,KAAA;GAC5B,YAAY,EAAE,WAAW,GAAG,KAAA;GAC5B,QAAQ,EAAE,OAAO,GAAG,KAAA;GACpB,WAAW,EAAE,UAAU,GAAG,KAAA;GAC1B,WAAW,EAAE,UAAU,GAAG,KAAA;GAC1B,OAAO;GACP;GACD,EACD;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,OAAO;GACR,CAMqB;EACpB,uBAAuB;EACvB,iBAAiB;EACjB,GAAI;EAEH;EACM,CAAA;EAEX;AAEF,KAAK,cAAc"}
1
+ {"version":3,"file":"Text.js","names":["RNText"],"sources":["../../src/components/Text.tsx"],"sourcesContent":["import type { ReactNode, Ref } from 'react';\nimport { memo, useMemo } from 'react';\nimport type { StyleProp, TextProps as RNTextProps, TextStyle } from 'react-native';\nimport { Text as RNText } from 'react-native';\n\nimport type { StyleProps } from '../../generated/styles';\nimport { styles } from '../../generated/styles';\nimport { DEFAULT_DYNAMIC_TYPE_RAMPS } from '../fontScaling/constants';\nimport { useDynamicTypeRampEnabled } from '../fontScaling/FontScalingContext';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\n\n// TextVariant is a subset of fontFamily that represents typography variants\ntype TextVariant = Exclude<\n NonNullable<StyleProps['fontFamily']>,\n 'sans' | 'sans-alt' | 'serif' | 'serif-alt' | 'mono' | 'icons'\n>;\ntype TextVariantProp = TextVariant | 'inherit';\n\n// React Native text decoration line values\n// See: https://reactnative.dev/docs/text-style-props#textdecorationline\ntype TextDecorationLine = 'none' | 'underline' | 'line-through' | 'underline line-through';\n\n// Chinese/Japanese/Korean scripts: Hangul Jamo, CJK radicals + punctuation,\n// Kana, Han ideographs, Hangul syllables, compatibility ideographs, and\n// full/half-width forms.\nconst CJK_RE =\n /[\\u1100-\\u11FF\\u2E80-\\u303F\\u3040-\\u30FF\\u31C0-\\u9FFF\\uAC00-\\uD7AF\\uF900-\\uFAFF\\uFF00-\\uFFEF]/;\n\n/**\n * Detects CJK characters in string children (including strings inside a\n * children array, e.g. from `{city}` interpolation). Nested elements are not\n * inspected - a nested <Text> runs its own detection.\n */\nfunction hasCJKContent(children: ReactNode): boolean {\n if (typeof children === 'string') {\n return CJK_RE.test(children);\n }\n if (Array.isArray(children)) {\n return children.some((child) => typeof child === 'string' && CJK_RE.test(child));\n }\n return false;\n}\n\ninterface TextProps extends RNTextProps {\n /** Ref to the underlying Text element */\n ref?: Ref<RNText>;\n /** Text color from the theme palette */\n color?: StyleProps['color'] | 'inherit';\n /** Typography variant - sets fontSize, lineHeight, letterSpacing, and fontFamily together */\n variant?: TextVariantProp;\n /**\n * Caps how far this text grows with the OS text-size setting. Every text\n * variant is capped at 2x or below by default, with the largest display and\n * title variants tapering further (see DEFAULT_MAX_FONT_SIZE_MULTIPLIERS).\n * Set null to remove the cap (maps to React Native's 0, which also overrides\n * an inherited cap); inherit-variant text inherits its parent's cap.\n * Override app-wide via UDSFontScalingProvider.\n */\n maxFontSizeMultiplier?: number | null;\n /** Override the fontFamily independently */\n fontFamily?: StyleProps['fontFamily'];\n /** Override the fontSize independently */\n fontSize?: StyleProps['fontSize'];\n /** Set font weight (not derived from variant) */\n fontWeight?: StyleProps['fontWeight'];\n /** Override the lineHeight independently. Use 'none' to remove the variant lineHeight and let the font's natural line height apply */\n lineHeight?: StyleProps['lineHeight'] | 'none';\n /** Override the letterSpacing independently */\n letterSpacing?: StyleProps['letterSpacing'];\n /** Text alignment (left, center, right) */\n textAlign?: StyleProps['textAlign'];\n /** Set text transform (not derived from variant) */\n textTransform?: StyleProps['textTransform'];\n /** Text decoration (underline, line-through, etc.) */\n textDecorationLine?: TextDecorationLine;\n // Background\n backgroundColor?: StyleProps['backgroundColor'];\n // Border\n borderRadius?: StyleProps['borderRadius'];\n borderTopStartRadius?: StyleProps['borderTopStartRadius'];\n borderTopEndRadius?: StyleProps['borderTopEndRadius'];\n borderBottomStartRadius?: StyleProps['borderBottomStartRadius'];\n borderBottomEndRadius?: StyleProps['borderBottomEndRadius'];\n borderColor?: StyleProps['borderColor'];\n borderStartColor?: StyleProps['borderStartColor'];\n borderEndColor?: StyleProps['borderEndColor'];\n borderTopColor?: StyleProps['borderTopColor'];\n borderBottomColor?: StyleProps['borderBottomColor'];\n borderWidth?: StyleProps['borderWidth'];\n borderVerticalWidth?: StyleProps['borderVerticalWidth'];\n borderHorizontalWidth?: StyleProps['borderHorizontalWidth'];\n borderStartWidth?: StyleProps['borderStartWidth'];\n borderEndWidth?: StyleProps['borderEndWidth'];\n borderTopWidth?: StyleProps['borderTopWidth'];\n borderBottomWidth?: StyleProps['borderBottomWidth'];\n // Spacing\n spacing?: StyleProps['spacing'];\n spacingHorizontal?: StyleProps['spacingHorizontal'];\n spacingVertical?: StyleProps['spacingVertical'];\n spacingBottom?: StyleProps['spacingBottom'];\n spacingEnd?: StyleProps['spacingEnd'];\n spacingStart?: StyleProps['spacingStart'];\n spacingTop?: StyleProps['spacingTop'];\n // Offset\n offset?: StyleProps['offset'];\n offsetVertical?: StyleProps['offsetVertical'];\n offsetHorizontal?: StyleProps['offsetHorizontal'];\n offsetBottom?: StyleProps['offsetBottom'];\n offsetEnd?: StyleProps['offsetEnd'];\n offsetStart?: StyleProps['offsetStart'];\n offsetTop?: StyleProps['offsetTop'];\n // Flex\n flexShrink?: StyleProps['flexShrink'];\n // Vertical Alignment\n verticalAlign?: TextStyle['textAlignVertical'];\n // Size\n height?: number | `${number}%`;\n width?: number | `${number}%`;\n minHeight?: number | `${number}%`;\n maxHeight?: number | `${number}%`;\n minWidth?: number | `${number}%`;\n maxWidth?: number | `${number}%`;\n // Dangerously set props\n dangerouslySetColor?: string;\n}\n\n/**\n * **📝 A text component with UDS styling**\n *\n * @description\n * A styled text component that supports UDS typography variants and colors.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Text } from '@yahoo/uds-mobile/Text';\n *\n * <Text variant=\"body1\" color=\"primary\">Hello, World!</Text>\n * <Text variant=\"display1\" fontWeight=\"bold\">Heading</Text>\n * <Text variant=\"label1\" color=\"secondary\">Caption text</Text>\n * ```\n *\n * @usage\n * - Use variant prop to set typography (display1, body1, label1, etc.)\n * - Use color prop to set text color from the palette\n * - Use fontWeight to override the variant's default weight\n *\n * @accessibility\n * - Text is readable by screen readers by default\n * - Use appropriate variant sizes for readability\n * - Ensure sufficient color contrast with background\n *\n * @see {@link Link} for interactive text links\n */\nconst Text = memo(function Text({\n // Text-specific\n color = 'primary',\n variant = 'body1',\n fontFamily,\n fontSize,\n fontWeight,\n lineHeight,\n letterSpacing,\n maxFontSizeMultiplier,\n textAlign,\n textTransform,\n textDecorationLine,\n style,\n // Background\n backgroundColor,\n // Border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n borderColor,\n borderStartColor,\n borderEndColor,\n borderTopColor,\n borderBottomColor,\n borderWidth,\n borderVerticalWidth,\n borderHorizontalWidth,\n borderStartWidth,\n borderEndWidth,\n borderTopWidth,\n borderBottomWidth,\n // Spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n // Offset\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n // Flex\n flexShrink,\n // Vertical Alignment\n verticalAlign,\n // Size\n height,\n minHeight,\n maxHeight,\n width,\n minWidth,\n maxWidth,\n // Dangerously set props\n dangerouslySetColor,\n ref,\n children,\n // Rest\n ...props\n}: TextProps) {\n const resolvedColor = color === 'inherit' ? undefined : color;\n const resolvedVariant = variant === 'inherit' ? undefined : variant;\n const resolvedFontFamily = fontFamily ?? resolvedVariant;\n const resolvedFontSize = fontSize ?? resolvedVariant;\n // React Native clips glyphs when lineHeight is smaller than the font's\n // natural line box. CJK fallback fonts are ~1.4x taller than Latin ones, so\n // Latin-tuned variant lineHeights clip CJK text - drop the variant lineHeight\n // for CJK content so the line grows to fit.\n const resolvedLineHeight =\n lineHeight === 'none'\n ? undefined\n : (lineHeight ?? (hasCJKContent(children) ? undefined : resolvedVariant));\n const resolvedLetterSpacing = letterSpacing ?? resolvedVariant;\n const baseVariant = resolvedVariant?.split('/')[0] as TextVariant | undefined;\n const dynamicTypeRampEnabled = useDynamicTypeRampEnabled();\n const defaultDynamicTypeRamp =\n dynamicTypeRampEnabled && baseVariant ? DEFAULT_DYNAMIC_TYPE_RAMPS[baseVariant] : undefined;\n // Explicit prop wins, including explicit null (?? would swallow it).\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier(\n resolvedVariant,\n maxFontSizeMultiplier,\n );\n\n styles.useVariants({\n // Text styles\n color: resolvedColor,\n fontFamily: resolvedFontFamily,\n fontSize: resolvedFontSize,\n fontWeight,\n lineHeight: resolvedLineHeight,\n letterSpacing: resolvedLetterSpacing,\n textAlign,\n textTransform,\n // Background\n backgroundColor,\n // Border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n borderColor,\n borderStartColor,\n borderEndColor,\n borderTopColor,\n borderBottomColor,\n borderWidth,\n borderVerticalWidth,\n borderHorizontalWidth,\n borderStartWidth,\n borderEndWidth,\n borderTopWidth,\n borderBottomWidth,\n // Spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n // Offset\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n // Flex\n flexShrink,\n });\n\n // styles.foundation must be in deps - it returns a new reference when variants change.\n const computedStyle: StyleProp<TextStyle> = useMemo(\n () => [\n textDecorationLine ? { textDecorationLine } : undefined,\n dangerouslySetColor ? { color: dangerouslySetColor } : undefined,\n verticalAlign ? { textAlignVertical: verticalAlign } : undefined,\n height ? { height } : undefined,\n minHeight ? { minHeight } : undefined,\n maxHeight ? { maxHeight } : undefined,\n width ? { width } : undefined,\n minWidth ? { minWidth } : undefined,\n maxWidth ? { maxWidth } : undefined,\n styles.foundation,\n style,\n ],\n [\n textDecorationLine,\n dangerouslySetColor,\n verticalAlign,\n height,\n minHeight,\n maxHeight,\n width,\n minWidth,\n maxWidth,\n style,\n styles.foundation,\n ],\n );\n\n return (\n <RNText\n ref={ref}\n style={computedStyle}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n dynamicTypeRamp={defaultDynamicTypeRamp}\n {...props}\n >\n {children}\n </RNText>\n );\n});\n\nText.displayName = 'Text';\n\nexport { Text, type TextProps, type TextVariant };\n"],"mappings":";;;;;;;;;AAyBA,MAAM,SACJ;;;;;;AAOF,SAAS,cAAc,UAA8B;CACnD,IAAI,OAAO,aAAa,UACtB,OAAO,OAAO,KAAK,SAAS;CAE9B,IAAI,MAAM,QAAQ,SAAS,EACzB,OAAO,SAAS,MAAM,UAAU,OAAO,UAAU,YAAY,OAAO,KAAK,MAAM,CAAC;CAElF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoHT,MAAM,OAAO,KAAK,SAAS,KAAK,EAE9B,QAAQ,WACR,UAAU,SACV,YACA,UACA,YACA,YACA,eACA,uBACA,WACA,eACA,oBACA,OAEA,iBAEA,cACA,sBACA,oBACA,yBACA,uBACA,aACA,kBACA,gBACA,gBACA,mBACA,aACA,qBACA,uBACA,kBACA,gBACA,gBACA,mBAEA,SACA,mBACA,iBACA,eACA,YACA,cACA,YAEA,QACA,gBACA,kBACA,cACA,WACA,aACA,WAEA,YAEA,eAEA,QACA,WACA,WACA,OACA,UACA,UAEA,qBACA,KACA,UAEA,GAAG,SACS;CACZ,MAAM,gBAAgB,UAAU,YAAY,KAAA,IAAY;CACxD,MAAM,kBAAkB,YAAY,YAAY,KAAA,IAAY;CAC5D,MAAM,qBAAqB,cAAc;CACzC,MAAM,mBAAmB,YAAY;CAKrC,MAAM,qBACJ,eAAe,SACX,KAAA,IACC,eAAe,cAAc,SAAS,GAAG,KAAA,IAAY;CAC5D,MAAM,wBAAwB,iBAAiB;CAC/C,MAAM,cAAc,iBAAiB,MAAM,IAAI,CAAC;CAEhD,MAAM,yBADyB,2BAEP,IAAI,cAAc,2BAA2B,eAAe,KAAA;CAEpF,MAAM,gCAAgC,yBACpC,iBACA,sBACD;CAED,OAAO,YAAY;EAEjB,OAAO;EACP,YAAY;EACZ,UAAU;EACV;EACA,YAAY;EACZ,eAAe;EACf;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACD,CAAC;CAgCF,OACE,oBAACA,QAAD;EACO;EACL,OAhCwC,cACpC;GACJ,qBAAqB,EAAE,oBAAoB,GAAG,KAAA;GAC9C,sBAAsB,EAAE,OAAO,qBAAqB,GAAG,KAAA;GACvD,gBAAgB,EAAE,mBAAmB,eAAe,GAAG,KAAA;GACvD,SAAS,EAAE,QAAQ,GAAG,KAAA;GACtB,YAAY,EAAE,WAAW,GAAG,KAAA;GAC5B,YAAY,EAAE,WAAW,GAAG,KAAA;GAC5B,QAAQ,EAAE,OAAO,GAAG,KAAA;GACpB,WAAW,EAAE,UAAU,GAAG,KAAA;GAC1B,WAAW,EAAE,UAAU,GAAG,KAAA;GAC1B,OAAO;GACP;GACD,EACD;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,OAAO;GACR,CAMqB;EACpB,uBAAuB;EACvB,iBAAiB;EACjB,GAAI;EAEH;EACM,CAAA;EAEX;AAEF,KAAK,cAAc"}
@@ -5,6 +5,15 @@ let react = require("react");
5
5
  let react_jsx_runtime = require("react/jsx-runtime");
6
6
  //#region src/fontScaling/FontScalingContext.tsx
7
7
  const FontScalingContext = (0, react.createContext)(void 0);
8
+ /** Whether UDS-added caps, ramps, and scale-aware geometry are enabled. */
9
+ function useFontScalingEnabled() {
10
+ return (0, react.useContext)(FontScalingContext)?.enabled !== false;
11
+ }
12
+ /** Whether Text should supply its variant's default iOS Dynamic Type ramp. */
13
+ function useDynamicTypeRampEnabled() {
14
+ const config = (0, react.useContext)(FontScalingContext);
15
+ return config?.enabled !== false && config?.disableDynamicTypeRamp !== true;
16
+ }
8
17
  /**
9
18
  * **🔠 Overrides UDS font-scaling caps for a subtree**
10
19
  *
@@ -33,11 +42,17 @@ const UDSFontScalingProvider = (0, react.memo)(function UDSFontScalingProvider({
33
42
  UDSFontScalingProvider.displayName = "UDSFontScalingProvider";
34
43
  /** Keeps custom UDS content inside a control on the control's resolved cap. */
35
44
  const ResolvedControlFontScalingProvider = (0, react.memo)(function ResolvedControlFontScalingProvider({ maxFontSizeMultiplier, children }) {
45
+ const parentConfig = (0, react.useContext)(FontScalingContext);
36
46
  const cap = maxFontSizeMultiplier === 0 ? null : maxFontSizeMultiplier;
37
- const config = (0, react.useMemo)(() => ({
47
+ const config = (0, react.useMemo)(() => parentConfig?.enabled === false && maxFontSizeMultiplier === void 0 ? { enabled: false } : {
38
48
  default: cap,
39
- control: cap
40
- }), [cap]);
49
+ control: cap,
50
+ disableDynamicTypeRamp: true
51
+ }, [
52
+ cap,
53
+ maxFontSizeMultiplier,
54
+ parentConfig?.enabled
55
+ ]);
41
56
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FontScalingContext.Provider, {
42
57
  value: config,
43
58
  children
@@ -48,3 +63,5 @@ ResolvedControlFontScalingProvider.displayName = "ResolvedControlFontScalingProv
48
63
  exports.FontScalingContext = FontScalingContext;
49
64
  exports.ResolvedControlFontScalingProvider = ResolvedControlFontScalingProvider;
50
65
  exports.UDSFontScalingProvider = UDSFontScalingProvider;
66
+ exports.useDynamicTypeRampEnabled = useDynamicTypeRampEnabled;
67
+ exports.useFontScalingEnabled = useFontScalingEnabled;
@@ -4,7 +4,15 @@ import * as _$react from "react";
4
4
  import { ReactNode } from "react";
5
5
 
6
6
  //#region src/fontScaling/FontScalingContext.d.ts
7
- declare const FontScalingContext: _$react.Context<FontScalingConfig | undefined>;
7
+ interface FontScalingContextValue extends FontScalingConfig {
8
+ /** Internal: bounded controls use the global curve for text, icons, and geometry. */
9
+ disableDynamicTypeRamp?: boolean;
10
+ }
11
+ declare const FontScalingContext: _$react.Context<FontScalingContextValue | undefined>;
12
+ /** Whether UDS-added caps, ramps, and scale-aware geometry are enabled. */
13
+ declare function useFontScalingEnabled(): boolean;
14
+ /** Whether Text should supply its variant's default iOS Dynamic Type ramp. */
15
+ declare function useDynamicTypeRampEnabled(): boolean;
8
16
  interface UDSFontScalingProviderProps {
9
17
  /**
10
18
  * Font-scaling caps for the subtree. Should be identity-stable (a module
@@ -35,11 +43,11 @@ interface UDSFontScalingProviderProps {
35
43
  */
36
44
  declare const UDSFontScalingProvider: _$react.NamedExoticComponent<UDSFontScalingProviderProps>;
37
45
  interface ResolvedControlFontScalingProviderProps {
38
- maxFontSizeMultiplier: number;
46
+ maxFontSizeMultiplier?: number;
39
47
  children: ReactNode;
40
48
  }
41
49
  /** Keeps custom UDS content inside a control on the control's resolved cap. */
42
50
  declare const ResolvedControlFontScalingProvider: _$react.NamedExoticComponent<ResolvedControlFontScalingProviderProps>;
43
51
  //#endregion
44
- export { FontScalingContext, ResolvedControlFontScalingProvider, UDSFontScalingProvider, type UDSFontScalingProviderProps };
52
+ export { FontScalingContext, ResolvedControlFontScalingProvider, UDSFontScalingProvider, type UDSFontScalingProviderProps, useDynamicTypeRampEnabled, useFontScalingEnabled };
45
53
  //# sourceMappingURL=FontScalingContext.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FontScalingContext.d.cts","names":[],"sources":["../../src/fontScaling/FontScalingContext.tsx"],"mappings":";;;;;;cAMM,kBAAA,EAAkB,OAAA,CAAA,OAAA,CAAA,iBAAA;AAAA,UAEd,2BAAA;;AALuC;;;;EAW/C,MAAA,EAAQ,iBAAA;EACR,QAAA,EAAU,SAAA;AAAA;;;;;;;;;AAAS;;;;;AAsBO;;;;;;cAAtB,sBAAA,EAAsB,OAAA,CAAA,oBAAA,CAAA,2BAAA;AAAA,UASlB,uCAAA;EACR,qBAAA;EACA,QAAA,EAAU,SAAA;AAAA;;cAIN,kCAAA,EAAkC,OAAA,CAAA,oBAAA,CAAA,uCAAA"}
1
+ {"version":3,"file":"FontScalingContext.d.cts","names":[],"sources":["../../src/fontScaling/FontScalingContext.tsx"],"mappings":";;;;;;UAKU,uBAAA,SAAgC,iBAAA;;EAExC,sBAAA;AAAA;AAAA,cAII,kBAAA,EAAkB,OAAA,CAAA,OAAA,CAAA,uBAAA;;iBAGf,qBAAA,CAAA;;iBAKA,yBAAA,CAAA;AAAA,UAKC,2BAAA;;;;AAbc;;EAmBtB,MAAA,EAAQ,iBAAA;EACR,QAAA,EAAU,SAAA;AAAA;AAjBkB;;;;;AAKI;;;;;;;;;;AAYb;;;;AAjBS,cAuCxB,sBAAA,EAAsB,OAAA,CAAA,oBAAA,CAAA,2BAAA;AAAA,UASlB,uCAAA;EACR,qBAAA;EACA,QAAA,EAAU,SAAA;AAAA;;cAIN,kCAAA,EAAkC,OAAA,CAAA,oBAAA,CAAA,uCAAA"}
@@ -4,7 +4,15 @@ import * as _$react from "react";
4
4
  import { ReactNode } from "react";
5
5
 
6
6
  //#region src/fontScaling/FontScalingContext.d.ts
7
- declare const FontScalingContext: _$react.Context<FontScalingConfig | undefined>;
7
+ interface FontScalingContextValue extends FontScalingConfig {
8
+ /** Internal: bounded controls use the global curve for text, icons, and geometry. */
9
+ disableDynamicTypeRamp?: boolean;
10
+ }
11
+ declare const FontScalingContext: _$react.Context<FontScalingContextValue | undefined>;
12
+ /** Whether UDS-added caps, ramps, and scale-aware geometry are enabled. */
13
+ declare function useFontScalingEnabled(): boolean;
14
+ /** Whether Text should supply its variant's default iOS Dynamic Type ramp. */
15
+ declare function useDynamicTypeRampEnabled(): boolean;
8
16
  interface UDSFontScalingProviderProps {
9
17
  /**
10
18
  * Font-scaling caps for the subtree. Should be identity-stable (a module
@@ -35,11 +43,11 @@ interface UDSFontScalingProviderProps {
35
43
  */
36
44
  declare const UDSFontScalingProvider: _$react.NamedExoticComponent<UDSFontScalingProviderProps>;
37
45
  interface ResolvedControlFontScalingProviderProps {
38
- maxFontSizeMultiplier: number;
46
+ maxFontSizeMultiplier?: number;
39
47
  children: ReactNode;
40
48
  }
41
49
  /** Keeps custom UDS content inside a control on the control's resolved cap. */
42
50
  declare const ResolvedControlFontScalingProvider: _$react.NamedExoticComponent<ResolvedControlFontScalingProviderProps>;
43
51
  //#endregion
44
- export { FontScalingContext, ResolvedControlFontScalingProvider, UDSFontScalingProvider, type UDSFontScalingProviderProps };
52
+ export { FontScalingContext, ResolvedControlFontScalingProvider, UDSFontScalingProvider, type UDSFontScalingProviderProps, useDynamicTypeRampEnabled, useFontScalingEnabled };
45
53
  //# sourceMappingURL=FontScalingContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FontScalingContext.d.ts","names":[],"sources":["../../src/fontScaling/FontScalingContext.tsx"],"mappings":";;;;;;cAMM,kBAAA,EAAkB,OAAA,CAAA,OAAA,CAAA,iBAAA;AAAA,UAEd,2BAAA;;AALuC;;;;EAW/C,MAAA,EAAQ,iBAAA;EACR,QAAA,EAAU,SAAA;AAAA;;;;;;;;;AAAS;;;;;AAsBO;;;;;;cAAtB,sBAAA,EAAsB,OAAA,CAAA,oBAAA,CAAA,2BAAA;AAAA,UASlB,uCAAA;EACR,qBAAA;EACA,QAAA,EAAU,SAAA;AAAA;;cAIN,kCAAA,EAAkC,OAAA,CAAA,oBAAA,CAAA,uCAAA"}
1
+ {"version":3,"file":"FontScalingContext.d.ts","names":[],"sources":["../../src/fontScaling/FontScalingContext.tsx"],"mappings":";;;;;;UAKU,uBAAA,SAAgC,iBAAA;;EAExC,sBAAA;AAAA;AAAA,cAII,kBAAA,EAAkB,OAAA,CAAA,OAAA,CAAA,uBAAA;;iBAGf,qBAAA,CAAA;;iBAKA,yBAAA,CAAA;AAAA,UAKC,2BAAA;;;;AAbc;;EAmBtB,MAAA,EAAQ,iBAAA;EACR,QAAA,EAAU,SAAA;AAAA;AAjBkB;;;;;AAKI;;;;;;;;;;AAYb;;;;AAjBS,cAuCxB,sBAAA,EAAsB,OAAA,CAAA,oBAAA,CAAA,2BAAA;AAAA,UASlB,uCAAA;EACR,qBAAA;EACA,QAAA,EAAU,SAAA;AAAA;;cAIN,kCAAA,EAAkC,OAAA,CAAA,oBAAA,CAAA,uCAAA"}
@@ -1,8 +1,17 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
- import { createContext, memo, useMemo } from "react";
2
+ import { createContext, memo, useContext, useMemo } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/fontScaling/FontScalingContext.tsx
5
5
  const FontScalingContext = createContext(void 0);
6
+ /** Whether UDS-added caps, ramps, and scale-aware geometry are enabled. */
7
+ function useFontScalingEnabled() {
8
+ return useContext(FontScalingContext)?.enabled !== false;
9
+ }
10
+ /** Whether Text should supply its variant's default iOS Dynamic Type ramp. */
11
+ function useDynamicTypeRampEnabled() {
12
+ const config = useContext(FontScalingContext);
13
+ return config?.enabled !== false && config?.disableDynamicTypeRamp !== true;
14
+ }
6
15
  /**
7
16
  * **🔠 Overrides UDS font-scaling caps for a subtree**
8
17
  *
@@ -31,11 +40,17 @@ const UDSFontScalingProvider = memo(function UDSFontScalingProvider({ config, ch
31
40
  UDSFontScalingProvider.displayName = "UDSFontScalingProvider";
32
41
  /** Keeps custom UDS content inside a control on the control's resolved cap. */
33
42
  const ResolvedControlFontScalingProvider = memo(function ResolvedControlFontScalingProvider({ maxFontSizeMultiplier, children }) {
43
+ const parentConfig = useContext(FontScalingContext);
34
44
  const cap = maxFontSizeMultiplier === 0 ? null : maxFontSizeMultiplier;
35
- const config = useMemo(() => ({
45
+ const config = useMemo(() => parentConfig?.enabled === false && maxFontSizeMultiplier === void 0 ? { enabled: false } : {
36
46
  default: cap,
37
- control: cap
38
- }), [cap]);
47
+ control: cap,
48
+ disableDynamicTypeRamp: true
49
+ }, [
50
+ cap,
51
+ maxFontSizeMultiplier,
52
+ parentConfig?.enabled
53
+ ]);
39
54
  return /* @__PURE__ */ jsx(FontScalingContext.Provider, {
40
55
  value: config,
41
56
  children
@@ -43,6 +58,6 @@ const ResolvedControlFontScalingProvider = memo(function ResolvedControlFontScal
43
58
  });
44
59
  ResolvedControlFontScalingProvider.displayName = "ResolvedControlFontScalingProvider";
45
60
  //#endregion
46
- export { FontScalingContext, ResolvedControlFontScalingProvider, UDSFontScalingProvider };
61
+ export { FontScalingContext, ResolvedControlFontScalingProvider, UDSFontScalingProvider, useDynamicTypeRampEnabled, useFontScalingEnabled };
47
62
 
48
63
  //# sourceMappingURL=FontScalingContext.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FontScalingContext.js","names":[],"sources":["../../src/fontScaling/FontScalingContext.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { createContext, memo, useMemo } from 'react';\n\nimport type { FontScalingConfig } from './types';\n\n// undefined = no provider mounted; built-in defaults apply.\nconst FontScalingContext = createContext<FontScalingConfig | undefined>(undefined);\n\ninterface UDSFontScalingProviderProps {\n /**\n * Font-scaling caps for the subtree. Should be identity-stable (a module\n * constant or memoized) — every UDS text element reads it from context.\n * The nearest provider wins wholesale; configs are not merged.\n */\n config: FontScalingConfig;\n children: ReactNode;\n}\n\n/**\n * **🔠 Overrides UDS font-scaling caps for a subtree**\n *\n * @description\n * Configures how UDS text and controls respond to the OS text-size setting.\n * Without a provider, built-in defaults apply (every text style is capped at\n * 2x or below, with the largest display/title tiers tapered further, and\n * control internals capped at 2x). Most apps set this once at the root via the\n * `fontScaling` prop on `UDSGestureProvider`.\n *\n * @example\n * ```tsx\n * const FONT_SCALING = { default: 2, variants: { display1: 1.75 } };\n *\n * <UDSFontScalingProvider config={FONT_SCALING}>\n * <App />\n * </UDSFontScalingProvider>\n * ```\n */\nconst UDSFontScalingProvider = memo(function UDSFontScalingProvider({\n config,\n children,\n}: UDSFontScalingProviderProps) {\n return <FontScalingContext.Provider value={config}>{children}</FontScalingContext.Provider>;\n});\n\nUDSFontScalingProvider.displayName = 'UDSFontScalingProvider';\n\ninterface ResolvedControlFontScalingProviderProps {\n maxFontSizeMultiplier: number;\n children: ReactNode;\n}\n\n/** Keeps custom UDS content inside a control on the control's resolved cap. */\nconst ResolvedControlFontScalingProvider = memo(function ResolvedControlFontScalingProvider({\n maxFontSizeMultiplier,\n children,\n}: ResolvedControlFontScalingProviderProps) {\n const cap = maxFontSizeMultiplier === 0 ? null : maxFontSizeMultiplier;\n const config = useMemo<FontScalingConfig>(() => ({ default: cap, control: cap }), [cap]);\n\n return <FontScalingContext.Provider value={config}>{children}</FontScalingContext.Provider>;\n});\n\nResolvedControlFontScalingProvider.displayName = 'ResolvedControlFontScalingProvider';\n\nexport {\n FontScalingContext,\n ResolvedControlFontScalingProvider,\n UDSFontScalingProvider,\n type UDSFontScalingProviderProps,\n};\n"],"mappings":";;;;AAMA,MAAM,qBAAqB,cAA6C,KAAA,EAAU;;;;;;;;;;;;;;;;;;;;AA+BlF,MAAM,yBAAyB,KAAK,SAAS,uBAAuB,EAClE,QACA,YAC8B;CAC9B,OAAO,oBAAC,mBAAmB,UAApB;EAA6B,OAAO;EAAS;EAAuC,CAAA;EAC3F;AAEF,uBAAuB,cAAc;;AAQrC,MAAM,qCAAqC,KAAK,SAAS,mCAAmC,EAC1F,uBACA,YAC0C;CAC1C,MAAM,MAAM,0BAA0B,IAAI,OAAO;CACjD,MAAM,SAAS,eAAkC;EAAE,SAAS;EAAK,SAAS;EAAK,GAAG,CAAC,IAAI,CAAC;CAExF,OAAO,oBAAC,mBAAmB,UAApB;EAA6B,OAAO;EAAS;EAAuC,CAAA;EAC3F;AAEF,mCAAmC,cAAc"}
1
+ {"version":3,"file":"FontScalingContext.js","names":[],"sources":["../../src/fontScaling/FontScalingContext.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { createContext, memo, useContext, useMemo } from 'react';\n\nimport type { FontScalingConfig } from './types';\n\ninterface FontScalingContextValue extends FontScalingConfig {\n /** Internal: bounded controls use the global curve for text, icons, and geometry. */\n disableDynamicTypeRamp?: boolean;\n}\n\n// undefined = no provider mounted; built-in defaults apply.\nconst FontScalingContext = createContext<FontScalingContextValue | undefined>(undefined);\n\n/** Whether UDS-added caps, ramps, and scale-aware geometry are enabled. */\nfunction useFontScalingEnabled(): boolean {\n return useContext(FontScalingContext)?.enabled !== false;\n}\n\n/** Whether Text should supply its variant's default iOS Dynamic Type ramp. */\nfunction useDynamicTypeRampEnabled(): boolean {\n const config = useContext(FontScalingContext);\n return config?.enabled !== false && config?.disableDynamicTypeRamp !== true;\n}\n\ninterface UDSFontScalingProviderProps {\n /**\n * Font-scaling caps for the subtree. Should be identity-stable (a module\n * constant or memoized) — every UDS text element reads it from context.\n * The nearest provider wins wholesale; configs are not merged.\n */\n config: FontScalingConfig;\n children: ReactNode;\n}\n\n/**\n * **🔠 Overrides UDS font-scaling caps for a subtree**\n *\n * @description\n * Configures how UDS text and controls respond to the OS text-size setting.\n * Without a provider, built-in defaults apply (every text style is capped at\n * 2x or below, with the largest display/title tiers tapered further, and\n * control internals capped at 2x). Most apps set this once at the root via the\n * `fontScaling` prop on `UDSGestureProvider`.\n *\n * @example\n * ```tsx\n * const FONT_SCALING = { default: 2, variants: { display1: 1.75 } };\n *\n * <UDSFontScalingProvider config={FONT_SCALING}>\n * <App />\n * </UDSFontScalingProvider>\n * ```\n */\nconst UDSFontScalingProvider = memo(function UDSFontScalingProvider({\n config,\n children,\n}: UDSFontScalingProviderProps) {\n return <FontScalingContext.Provider value={config}>{children}</FontScalingContext.Provider>;\n});\n\nUDSFontScalingProvider.displayName = 'UDSFontScalingProvider';\n\ninterface ResolvedControlFontScalingProviderProps {\n maxFontSizeMultiplier?: number;\n children: ReactNode;\n}\n\n/** Keeps custom UDS content inside a control on the control's resolved cap. */\nconst ResolvedControlFontScalingProvider = memo(function ResolvedControlFontScalingProvider({\n maxFontSizeMultiplier,\n children,\n}: ResolvedControlFontScalingProviderProps) {\n const parentConfig = useContext(FontScalingContext);\n const cap = maxFontSizeMultiplier === 0 ? null : maxFontSizeMultiplier;\n const config = useMemo<FontScalingContextValue>(\n () =>\n parentConfig?.enabled === false && maxFontSizeMultiplier === undefined\n ? { enabled: false }\n : { default: cap, control: cap, disableDynamicTypeRamp: true },\n [cap, maxFontSizeMultiplier, parentConfig?.enabled],\n );\n\n return <FontScalingContext.Provider value={config}>{children}</FontScalingContext.Provider>;\n});\n\nResolvedControlFontScalingProvider.displayName = 'ResolvedControlFontScalingProvider';\n\nexport {\n FontScalingContext,\n ResolvedControlFontScalingProvider,\n UDSFontScalingProvider,\n useDynamicTypeRampEnabled,\n useFontScalingEnabled,\n};\nexport type { UDSFontScalingProviderProps };\n"],"mappings":";;;;AAWA,MAAM,qBAAqB,cAAmD,KAAA,EAAU;;AAGxF,SAAS,wBAAiC;CACxC,OAAO,WAAW,mBAAmB,EAAE,YAAY;;;AAIrD,SAAS,4BAAqC;CAC5C,MAAM,SAAS,WAAW,mBAAmB;CAC7C,OAAO,QAAQ,YAAY,SAAS,QAAQ,2BAA2B;;;;;;;;;;;;;;;;;;;;;AAgCzE,MAAM,yBAAyB,KAAK,SAAS,uBAAuB,EAClE,QACA,YAC8B;CAC9B,OAAO,oBAAC,mBAAmB,UAApB;EAA6B,OAAO;EAAS;EAAuC,CAAA;EAC3F;AAEF,uBAAuB,cAAc;;AAQrC,MAAM,qCAAqC,KAAK,SAAS,mCAAmC,EAC1F,uBACA,YAC0C;CAC1C,MAAM,eAAe,WAAW,mBAAmB;CACnD,MAAM,MAAM,0BAA0B,IAAI,OAAO;CACjD,MAAM,SAAS,cAEX,cAAc,YAAY,SAAS,0BAA0B,KAAA,IACzD,EAAE,SAAS,OAAO,GAClB;EAAE,SAAS;EAAK,SAAS;EAAK,wBAAwB;EAAM,EAClE;EAAC;EAAK;EAAuB,cAAc;EAAQ,CACpD;CAED,OAAO,oBAAC,mBAAmB,UAApB;EAA6B,OAAO;EAAS;EAAuC,CAAA;EAC3F;AAEF,mCAAmC,cAAc"}