@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.
- package/README.md +3 -1
- package/dist/components/Avatar/AvatarIcon.cjs +1 -1
- package/dist/components/Avatar/AvatarIcon.js +1 -1
- package/dist/components/Avatar/AvatarIcon.js.map +1 -1
- package/dist/components/Avatar/AvatarImage.cjs +1 -1
- package/dist/components/Avatar/AvatarImage.js +1 -1
- package/dist/components/Avatar/AvatarImage.js.map +1 -1
- package/dist/components/Avatar/AvatarText.cjs +1 -1
- package/dist/components/Avatar/AvatarText.js +1 -1
- package/dist/components/Avatar/AvatarText.js.map +1 -1
- package/dist/components/Avatar/useAvatarFontScale.cjs +2 -2
- package/dist/components/Avatar/useAvatarFontScale.d.cts +1 -1
- package/dist/components/Avatar/useAvatarFontScale.d.ts +1 -1
- package/dist/components/Avatar/useAvatarFontScale.js +3 -3
- package/dist/components/Avatar/useAvatarFontScale.js.map +1 -1
- package/dist/components/Button/buttonTheme.cjs +6 -1
- package/dist/components/Button/buttonTheme.d.cts +3 -1
- package/dist/components/Button/buttonTheme.d.cts.map +1 -1
- package/dist/components/Button/buttonTheme.d.ts +3 -1
- package/dist/components/Button/buttonTheme.d.ts.map +1 -1
- package/dist/components/Button/buttonTheme.js +6 -2
- package/dist/components/Button/buttonTheme.js.map +1 -1
- package/dist/components/Button.cjs +5 -4
- package/dist/components/Button.js +6 -5
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Checkbox.cjs +13 -7
- package/dist/components/Checkbox.d.cts.map +1 -1
- package/dist/components/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox.js +14 -8
- package/dist/components/Checkbox.js.map +1 -1
- package/dist/components/Chip/ChipBase.cjs +2 -2
- package/dist/components/Chip/ChipBase.js +3 -3
- package/dist/components/Chip/ChipBase.js.map +1 -1
- package/dist/components/Icon.cjs +8 -7
- package/dist/components/Icon.d.cts +2 -0
- package/dist/components/Icon.d.cts.map +1 -1
- package/dist/components/Icon.d.ts +2 -0
- package/dist/components/Icon.d.ts.map +1 -1
- package/dist/components/Icon.js +9 -8
- package/dist/components/Icon.js.map +1 -1
- package/dist/components/IconButton.cjs +17 -6
- package/dist/components/IconButton.d.cts +6 -0
- package/dist/components/IconButton.d.cts.map +1 -1
- package/dist/components/IconButton.d.ts +6 -0
- package/dist/components/IconButton.d.ts.map +1 -1
- package/dist/components/IconButton.js +18 -7
- package/dist/components/IconButton.js.map +1 -1
- package/dist/components/Input.cjs +4 -2
- package/dist/components/Input.js +5 -3
- package/dist/components/Input.js.map +1 -1
- package/dist/components/InputHelpText.cjs +2 -1
- package/dist/components/InputHelpText.js +2 -1
- package/dist/components/InputHelpText.js.map +1 -1
- package/dist/components/Link.cjs +5 -1
- package/dist/components/Link.d.cts.map +1 -1
- package/dist/components/Link.d.ts.map +1 -1
- package/dist/components/Link.js +5 -1
- package/dist/components/Link.js.map +1 -1
- package/dist/components/Pagination/Pagination.cjs +1 -1
- package/dist/components/Pagination/Pagination.js +1 -1
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Pagination/PaginationEllipsis.cjs +1 -1
- package/dist/components/Pagination/PaginationEllipsis.js +2 -2
- package/dist/components/Pagination/PaginationEllipsis.js.map +1 -1
- package/dist/components/Pagination/paginationContext.d.cts +2 -2
- package/dist/components/Pagination/paginationContext.d.ts +2 -2
- package/dist/components/Pagination/paginationContext.js.map +1 -1
- package/dist/components/Pagination/usePaginationControlStyles.cjs +1 -1
- package/dist/components/Pagination/usePaginationControlStyles.js +2 -2
- package/dist/components/Pagination/usePaginationControlStyles.js.map +1 -1
- package/dist/components/Radio/Radio.cjs +2 -2
- package/dist/components/Radio/Radio.js +3 -3
- package/dist/components/Radio/Radio.js.map +1 -1
- package/dist/components/Select/Select.cjs +3 -1
- package/dist/components/Select/Select.js +3 -1
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectItem.cjs +1 -2
- package/dist/components/Select/SelectItem.js +2 -3
- package/dist/components/Select/SelectItem.js.map +1 -1
- package/dist/components/Select/SelectTrigger.cjs +1 -2
- package/dist/components/Select/SelectTrigger.js +2 -3
- package/dist/components/Select/SelectTrigger.js.map +1 -1
- package/dist/components/Select/types.d.cts +1 -1
- package/dist/components/Select/types.d.ts +1 -1
- package/dist/components/Switch.cjs +20 -5
- package/dist/components/Switch.d.cts.map +1 -1
- package/dist/components/Switch.d.ts.map +1 -1
- package/dist/components/Switch.js +21 -6
- package/dist/components/Switch.js.map +1 -1
- package/dist/components/Tabs/Tab.cjs +2 -2
- package/dist/components/Tabs/Tab.js +3 -3
- package/dist/components/Tabs/Tab.js.map +1 -1
- package/dist/components/Text.cjs +2 -1
- package/dist/components/Text.d.cts.map +1 -1
- package/dist/components/Text.d.ts.map +1 -1
- package/dist/components/Text.js +2 -1
- package/dist/components/Text.js.map +1 -1
- package/dist/fontScaling/FontScalingContext.cjs +20 -3
- package/dist/fontScaling/FontScalingContext.d.cts +11 -3
- package/dist/fontScaling/FontScalingContext.d.cts.map +1 -1
- package/dist/fontScaling/FontScalingContext.d.ts +11 -3
- package/dist/fontScaling/FontScalingContext.d.ts.map +1 -1
- package/dist/fontScaling/FontScalingContext.js +20 -5
- package/dist/fontScaling/FontScalingContext.js.map +1 -1
- package/dist/fontScaling/androidNonlinearFontScaling.cjs +85 -9
- package/dist/fontScaling/androidNonlinearFontScaling.d.cts +2 -2
- package/dist/fontScaling/androidNonlinearFontScaling.d.cts.map +1 -1
- package/dist/fontScaling/androidNonlinearFontScaling.d.ts +2 -2
- package/dist/fontScaling/androidNonlinearFontScaling.d.ts.map +1 -1
- package/dist/fontScaling/androidNonlinearFontScaling.js +85 -9
- package/dist/fontScaling/androidNonlinearFontScaling.js.map +1 -1
- package/dist/fontScaling/types.d.cts +8 -7
- package/dist/fontScaling/types.d.cts.map +1 -1
- package/dist/fontScaling/types.d.ts +8 -7
- package/dist/fontScaling/types.d.ts.map +1 -1
- package/dist/fontScaling/useFontScale.cjs +21 -4
- package/dist/fontScaling/useFontScale.d.cts +6 -17
- package/dist/fontScaling/useFontScale.d.cts.map +1 -1
- package/dist/fontScaling/useFontScale.d.ts +6 -17
- package/dist/fontScaling/useFontScale.d.ts.map +1 -1
- package/dist/fontScaling/useFontScale.js +21 -5
- package/dist/fontScaling/useFontScale.js.map +1 -1
- package/dist/mobile/generated/fontMetrics.cjs +530 -530
- package/dist/mobile/generated/fontMetrics.js +530 -530
- package/dist/mobile/generated/fontMetrics.js.map +1 -1
- package/fonts/index.cjs +214 -214
- package/fonts/index.mjs +214 -214
- package/generated/fontMetrics.ts +530 -530
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.d.ts","names":[],"sources":["../../src/components/Checkbox.tsx"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"Checkbox.d.ts","names":[],"sources":["../../src/components/Checkbox.tsx"],"mappings":";;;;;;;UAuBU,aAAA,SAAsB,IAAA,CAAK,SAAA,YAAqB,sBAAA;;EAExD,GAAA,GAAM,GAAA,CAAI,IAAA;EAFF;EAIR,cAAA;;EAEA,QAAA;EAJU;EAMV,QAAA;EAR8B;;;;;;EAe9B,qBAAA;EAbA;EAeA,QAAA,IAAY,OAAA;AAAA;;;;;;;;;AAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;cAqDxB,QAAA,EAAQ,OAAA,CAAA,oBAAA,CAAA,aAAA"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
2
|
import { SCALE_EFFECTS } from "../motion-tokens/dist/index.js";
|
|
3
3
|
import { BUTTON_SPRING_CONFIG } from "../motion.js";
|
|
4
|
-
import {
|
|
4
|
+
import { useComponentFontScale } from "../fontScaling/useFontScale.js";
|
|
5
5
|
import { useMaxFontSizeMultiplier } from "../fontScaling/useMaxFontSizeMultiplier.js";
|
|
6
|
+
import { getSafeIconCell } from "./Button/buttonTheme.js";
|
|
6
7
|
import { Icon } from "./Icon.js";
|
|
7
8
|
import { Pressable } from "./Pressable.js";
|
|
8
9
|
import { FormLabel } from "./FormLabel.js";
|
|
@@ -52,7 +53,7 @@ const VARIANT_ERROR_MAP = {
|
|
|
52
53
|
*/
|
|
53
54
|
const Checkbox = memo(function Checkbox({ label, labelPosition = "start", variant: variantProp = "primary", size = "md", checked: checkedProp, hasError, reduceMotion, defaultChecked, disabled, required, maxFontSizeMultiplier, onChange, ref, ...viewProps }) {
|
|
54
55
|
const uid = `uds-checkbox-${useId()}`;
|
|
55
|
-
const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier)
|
|
56
|
+
const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
56
57
|
const isControlled = checkedProp !== void 0;
|
|
57
58
|
const [internalChecked, setInternalChecked] = useState(isControlled ? checkedProp : defaultChecked ?? false);
|
|
58
59
|
const [pressed, setPressed] = useState(false);
|
|
@@ -92,9 +93,10 @@ const Checkbox = memo(function Checkbox({ label, labelPosition = "start", varian
|
|
|
92
93
|
pressed
|
|
93
94
|
});
|
|
94
95
|
const boxBaseSize = checkboxStyles.checkbox.width;
|
|
95
|
-
const fontScaleFactor =
|
|
96
|
-
const markScaleFactor =
|
|
96
|
+
const fontScaleFactor = useComponentFontScale(resolvedMaxFontSizeMultiplier, typeof boxBaseSize === "number" ? boxBaseSize : void 0);
|
|
97
|
+
const markScaleFactor = useComponentFontScale(resolvedMaxFontSizeMultiplier, ICON_SIZE_MAP.sm);
|
|
97
98
|
const scaledMarkSize = Math.round(ICON_SIZE_MAP.sm * markScaleFactor);
|
|
99
|
+
const hasScaledLayout = fontScaleFactor !== 1;
|
|
98
100
|
const rootStyle = useMemo(() => [checkboxStyles.root, { opacity: disabled ? .5 : 1 }], [checkboxStyles.root, disabled]);
|
|
99
101
|
const checkboxBoxStyle = useMemo(() => {
|
|
100
102
|
const { width, height, borderRadius } = checkboxStyles.checkbox;
|
|
@@ -126,7 +128,7 @@ const Checkbox = memo(function Checkbox({ label, labelPosition = "start", varian
|
|
|
126
128
|
required,
|
|
127
129
|
showRequiredAsterisk: required,
|
|
128
130
|
hasError,
|
|
129
|
-
flexShrink: "1",
|
|
131
|
+
flexShrink: hasScaledLayout ? "1" : void 0,
|
|
130
132
|
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
131
133
|
style: checkboxStyles.text
|
|
132
134
|
});
|
|
@@ -134,6 +136,7 @@ const Checkbox = memo(function Checkbox({ label, labelPosition = "start", varian
|
|
|
134
136
|
label,
|
|
135
137
|
required,
|
|
136
138
|
hasError,
|
|
139
|
+
hasScaledLayout,
|
|
137
140
|
resolvedMaxFontSizeMultiplier,
|
|
138
141
|
checkboxStyles.text
|
|
139
142
|
]);
|
|
@@ -150,8 +153,8 @@ const Checkbox = memo(function Checkbox({ label, labelPosition = "start", varian
|
|
|
150
153
|
disabled,
|
|
151
154
|
flexDirection: labelPosition === "start" ? "row" : "row-reverse",
|
|
152
155
|
alignItems: "center",
|
|
153
|
-
alignSelf: "stretch",
|
|
154
|
-
minHeight: 52,
|
|
156
|
+
alignSelf: hasScaledLayout ? "stretch" : "flex-start",
|
|
157
|
+
minHeight: hasScaledLayout ? 52 : void 0,
|
|
155
158
|
accessibilityRole: "checkbox",
|
|
156
159
|
accessibilityState: a11yState,
|
|
157
160
|
accessibilityLabel: typeof label === "string" ? label : void 0,
|
|
@@ -164,7 +167,10 @@ const Checkbox = memo(function Checkbox({ label, labelPosition = "start", varian
|
|
|
164
167
|
size: "sm",
|
|
165
168
|
dangerouslySetSize: scaledMarkSize,
|
|
166
169
|
allowFontScaling: false,
|
|
167
|
-
style: checkboxStyles.checkboxIcon
|
|
170
|
+
style: [checkboxStyles.checkboxIcon, markScaleFactor !== 1 ? {
|
|
171
|
+
fontSize: scaledMarkSize,
|
|
172
|
+
lineHeight: getSafeIconCell(scaledMarkSize)
|
|
173
|
+
} : void 0]
|
|
168
174
|
})
|
|
169
175
|
}), labelContent]
|
|
170
176
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","names":[],"sources":["../../src/components/Checkbox.tsx"],"sourcesContent":["import { ICON_SIZE_MAP } from '@yahoo/uds-icons/tokens';\nimport type { CheckboxValue, CheckboxVariant, UniversalCheckboxProps } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useCallback, useId, useMemo, useState } from 'react';\nimport type { View, ViewProps } from 'react-native';\nimport Animated, { useAnimatedStyle, useDerivedValue, withSpring } from 'react-native-reanimated';\n\nimport { checkboxStyles } from '../../generated/styles';\nimport { useFontScale } from '../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\nimport { BUTTON_SPRING_CONFIG, SCALE_EFFECTS } from '../motion';\nimport { FormLabel } from './FormLabel';\nimport { Icon } from './Icon';\nimport { Pressable } from './Pressable';\n\n/* -------------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------------- */\n\n/** Derived from CheckboxValue - maps boolean to 'checked'/'unchecked' string literals */\ntype CheckboxValueState = Exclude<CheckboxValue, boolean> | 'checked' | 'unchecked';\n\ninterface CheckboxProps extends Omit<ViewProps, 'style'>, UniversalCheckboxProps {\n /** Ref to the underlying View */\n ref?: Ref<View>;\n /** Default checked state for uncontrolled mode */\n defaultChecked?: boolean;\n /** Whether the checkbox is disabled */\n disabled?: boolean;\n /** Whether the checkbox is required */\n required?: boolean;\n /**\n * Caps how far the box, checkmark, and label grow with the OS text-size\n * setting; all three 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 /** Callback fired when the checked state changes */\n onChange?: (checked: boolean) => void;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Variant Mapping */\n/* -------------------------------------------------------------------------- */\n\n/** All style variants available in the generated styles (includes error variants) */\ntype CheckboxStyleVariant = 'primary' | 'secondary' | 'alert' | 'alert-secondary';\n\nconst VARIANT_ERROR_MAP: Record<CheckboxVariant, CheckboxStyleVariant> = {\n primary: 'alert',\n secondary: 'alert-secondary',\n};\n\n/* -------------------------------------------------------------------------- */\n/* Checkbox Component */\n/* -------------------------------------------------------------------------- */\n\n/**\n * **⚙️ A checkbox component**\n *\n * @description\n * A checkbox component allows users to select one or multiple options from a set.\n * It represents a binary state, typically as checked or unchecked, and optionally\n * includes a third \"indeterminate\" state to indicate partial selection.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Checkbox } from '@yahoo/uds-mobile/Checkbox';\n *\n * <Checkbox label=\"Agree to terms\" />\n * <Checkbox label=\"Subscribe\" checked={true} onChange={setChecked} />\n * <Checkbox label=\"Partial\" checked=\"indeterminate\" />\n * ```\n *\n * @usage\n * - Forms: For selecting options\n * - Settings: For toggling preferences\n * - Filters: For multi-select filtering\n *\n * @accessibility\n * - Sets `accessibilityRole=\"checkbox\"` automatically\n * - Announces checked/unchecked/mixed state\n * - Label is used as accessibility label\n * - Supports `reduceMotion` for users who prefer reduced motion\n *\n * @see {@link Radio} for single-select options\n * @see {@link Switch} for binary toggles\n */\nconst Checkbox = memo(function Checkbox({\n // Checkbox props\n label,\n labelPosition = 'start',\n variant: variantProp = 'primary',\n size = 'md',\n checked: checkedProp,\n hasError,\n reduceMotion,\n // Native props\n defaultChecked,\n disabled,\n required,\n maxFontSizeMultiplier,\n onChange,\n ref,\n ...viewProps\n}: CheckboxProps) {\n const generatedId = useId();\n const uid = `uds-checkbox-${generatedId}`;\n\n // One resolved cap governs box, checkmark, and label. Android may resolve a\n // slightly different nonlinear factor for each base size.\n const resolvedMaxFontSizeMultiplier =\n useMaxFontSizeMultiplier('control', maxFontSizeMultiplier) ?? 0;\n\n /* --------------------------------- State ---------------------------------- */\n const isControlled = checkedProp !== undefined;\n const [internalChecked, setInternalChecked] = useState<CheckboxValue>(\n isControlled ? checkedProp : (defaultChecked ?? false),\n );\n const [pressed, setPressed] = useState(false);\n\n // Use controlled value if provided, otherwise use internal state\n const checked = isControlled ? checkedProp : internalChecked;\n\n /* ------------------------------ Derived Values ---------------------------- */\n const valueState: CheckboxValueState = useMemo(() => {\n if (checked === 'indeterminate') {\n return 'indeterminate';\n }\n return checked ? 'checked' : 'unchecked';\n }, [checked]);\n\n const iconName = valueState === 'indeterminate' ? 'Minus' : 'Check';\n const showIcon = valueState !== 'unchecked';\n\n /* -------------------------------- Animation ------------------------------- */\n const shouldAnimate = !reduceMotion;\n\n // Scale animation for press feedback (disabled when reduceMotion is true)\n const scaleProgress = useDerivedValue(\n () =>\n shouldAnimate\n ? withSpring(pressed ? SCALE_EFFECTS.down : SCALE_EFFECTS.none, BUTTON_SPRING_CONFIG)\n : SCALE_EFFECTS.none, // No scale effect when reduceMotion is true\n [pressed, shouldAnimate],\n );\n\n const checkboxAnimatedStyle = useAnimatedStyle(() => ({\n transform: [{ scale: scaleProgress.value }],\n }));\n\n /* -------------------------------- Handlers -------------------------------- */\n const handlePress = useCallback(() => {\n if (disabled) {\n return;\n }\n\n const newChecked = checked === 'indeterminate' ? true : !checked;\n\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n\n onChange?.(newChecked);\n }, [disabled, checked, isControlled, onChange]);\n\n const handlePressIn = useCallback(() => {\n setPressed(true);\n }, []);\n\n const handlePressOut = useCallback(() => {\n setPressed(false);\n }, []);\n\n /* --------------------------------- Styles --------------------------------- */\n // Compute the style variant (primary/secondary maps to alert variants when hasError)\n const styleVariant: CheckboxStyleVariant = hasError\n ? VARIANT_ERROR_MAP[variantProp]\n : variantProp;\n\n checkboxStyles.useVariants({\n size,\n variant: styleVariant, // primary, secondary, alert, alert-secondary\n value: valueState, // checked, unchecked, indeterminate\n disabled,\n pressed,\n });\n\n const boxBaseSize = checkboxStyles.checkbox.width;\n const fontScaleFactor = useFontScale(\n resolvedMaxFontSizeMultiplier,\n typeof boxBaseSize === 'number' ? boxBaseSize : undefined,\n );\n // The check/minus glyph is drawn at the 'sm' icon size; use its own native\n // Android curve before disabling native scaling on the manually-sized glyph.\n const markScaleFactor = useFontScale(resolvedMaxFontSizeMultiplier, ICON_SIZE_MAP.sm);\n const scaledMarkSize = Math.round(ICON_SIZE_MAP.sm * markScaleFactor);\n\n const rootStyle = useMemo(\n () => [checkboxStyles.root, { opacity: disabled ? 0.5 : 1 }],\n [checkboxStyles.root, disabled],\n );\n\n const checkboxBoxStyle = useMemo(() => {\n // The box grows by the capped factor to keep containing the checkmark.\n // borderWidth stays fixed (stroke weight doesn't scale in the OS's own\n // controls either).\n const { width, height, borderRadius } = checkboxStyles.checkbox;\n const scaledBox =\n fontScaleFactor !== 1 && typeof width === 'number' && typeof height === 'number'\n ? {\n width: Math.round(width * fontScaleFactor),\n height: Math.round(height * fontScaleFactor),\n ...(typeof borderRadius === 'number' && {\n borderRadius: Math.round(borderRadius * fontScaleFactor),\n }),\n }\n : undefined;\n\n return [\n checkboxStyles.checkbox,\n scaledBox,\n { alignItems: 'center' as const, justifyContent: 'center' as const },\n checkboxAnimatedStyle,\n ];\n }, [checkboxStyles.checkbox, fontScaleFactor, checkboxAnimatedStyle]);\n\n /* ---------------------------- Render Helpers ------------------------------ */\n const labelContent = useMemo(() => {\n if (!label) {\n return null;\n }\n\n return (\n <FormLabel\n color=\"inherit\"\n variant=\"inherit\"\n label={label}\n required={required}\n showRequiredAsterisk={required}\n hasError={hasError}\n flexShrink=\"1\"\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={checkboxStyles.text}\n />\n );\n }, [label, required, hasError, resolvedMaxFontSizeMultiplier, checkboxStyles.text]);\n\n const a11yState = useMemo(\n () => ({\n disabled,\n checked:\n valueState === 'checked'\n ? true\n : valueState === 'indeterminate'\n ? ('mixed' as const)\n : false,\n }),\n [disabled, valueState],\n );\n\n /* --------------------------------- Render --------------------------------- */\n return (\n <Pressable\n ref={ref}\n nativeID={uid}\n onPress={handlePress}\n onPressIn={handlePressIn}\n onPressOut={handlePressOut}\n disabled={disabled}\n flexDirection={labelPosition === 'start' ? 'row' : 'row-reverse'}\n alignItems=\"center\"\n alignSelf=\"stretch\"\n minHeight={52}\n accessibilityRole=\"checkbox\"\n accessibilityState={a11yState}\n accessibilityLabel={typeof label === 'string' ? label : undefined}\n {...viewProps}\n style={rootStyle}\n >\n <Animated.View style={checkboxBoxStyle}>\n {showIcon && (\n <Icon\n name={iconName}\n size=\"sm\"\n // Size the mark from the same factor that scaled the box, with\n // native scaling off: letting the box scale in JS while the glyph\n // scaled natively left the two to round independently (and to\n // disagree outright under Android's non-linear scaling), which\n // drifted the mark off-centre as sizes grew.\n dangerouslySetSize={scaledMarkSize}\n allowFontScaling={false}\n style={checkboxStyles.checkboxIcon}\n />\n )}\n </Animated.View>\n\n {labelContent}\n </Pressable>\n );\n});\n\nCheckbox.displayName = 'Checkbox';\n\nexport { Checkbox, type CheckboxProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Checkbox.js","names":[],"sources":["../../src/components/Checkbox.tsx"],"sourcesContent":["import { ICON_SIZE_MAP } from '@yahoo/uds-icons/tokens';\nimport type { CheckboxValue, CheckboxVariant, UniversalCheckboxProps } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useCallback, useId, useMemo, useState } from 'react';\nimport type { View, ViewProps } from 'react-native';\nimport Animated, { useAnimatedStyle, useDerivedValue, withSpring } from 'react-native-reanimated';\n\nimport { checkboxStyles } from '../../generated/styles';\nimport { useComponentFontScale } from '../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\nimport { BUTTON_SPRING_CONFIG, SCALE_EFFECTS } from '../motion';\nimport { getSafeIconCell } from './Button/buttonTheme';\nimport { FormLabel } from './FormLabel';\nimport { Icon } from './Icon';\nimport { Pressable } from './Pressable';\n\n/* -------------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------------- */\n\n/** Derived from CheckboxValue - maps boolean to 'checked'/'unchecked' string literals */\ntype CheckboxValueState = Exclude<CheckboxValue, boolean> | 'checked' | 'unchecked';\n\ninterface CheckboxProps extends Omit<ViewProps, 'style'>, UniversalCheckboxProps {\n /** Ref to the underlying View */\n ref?: Ref<View>;\n /** Default checked state for uncontrolled mode */\n defaultChecked?: boolean;\n /** Whether the checkbox is disabled */\n disabled?: boolean;\n /** Whether the checkbox is required */\n required?: boolean;\n /**\n * Caps how far the box, checkmark, and label grow with the OS text-size\n * setting; all three 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 /** Callback fired when the checked state changes */\n onChange?: (checked: boolean) => void;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Variant Mapping */\n/* -------------------------------------------------------------------------- */\n\n/** All style variants available in the generated styles (includes error variants) */\ntype CheckboxStyleVariant = 'primary' | 'secondary' | 'alert' | 'alert-secondary';\n\nconst VARIANT_ERROR_MAP: Record<CheckboxVariant, CheckboxStyleVariant> = {\n primary: 'alert',\n secondary: 'alert-secondary',\n};\n\n/* -------------------------------------------------------------------------- */\n/* Checkbox Component */\n/* -------------------------------------------------------------------------- */\n\n/**\n * **⚙️ A checkbox component**\n *\n * @description\n * A checkbox component allows users to select one or multiple options from a set.\n * It represents a binary state, typically as checked or unchecked, and optionally\n * includes a third \"indeterminate\" state to indicate partial selection.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Checkbox } from '@yahoo/uds-mobile/Checkbox';\n *\n * <Checkbox label=\"Agree to terms\" />\n * <Checkbox label=\"Subscribe\" checked={true} onChange={setChecked} />\n * <Checkbox label=\"Partial\" checked=\"indeterminate\" />\n * ```\n *\n * @usage\n * - Forms: For selecting options\n * - Settings: For toggling preferences\n * - Filters: For multi-select filtering\n *\n * @accessibility\n * - Sets `accessibilityRole=\"checkbox\"` automatically\n * - Announces checked/unchecked/mixed state\n * - Label is used as accessibility label\n * - Supports `reduceMotion` for users who prefer reduced motion\n *\n * @see {@link Radio} for single-select options\n * @see {@link Switch} for binary toggles\n */\nconst Checkbox = memo(function Checkbox({\n // Checkbox props\n label,\n labelPosition = 'start',\n variant: variantProp = 'primary',\n size = 'md',\n checked: checkedProp,\n hasError,\n reduceMotion,\n // Native props\n defaultChecked,\n disabled,\n required,\n maxFontSizeMultiplier,\n onChange,\n ref,\n ...viewProps\n}: CheckboxProps) {\n const generatedId = useId();\n const uid = `uds-checkbox-${generatedId}`;\n\n // One resolved cap governs box, checkmark, and label. Android may resolve a\n // slightly different nonlinear factor for each base size.\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n\n /* --------------------------------- State ---------------------------------- */\n const isControlled = checkedProp !== undefined;\n const [internalChecked, setInternalChecked] = useState<CheckboxValue>(\n isControlled ? checkedProp : (defaultChecked ?? false),\n );\n const [pressed, setPressed] = useState(false);\n\n // Use controlled value if provided, otherwise use internal state\n const checked = isControlled ? checkedProp : internalChecked;\n\n /* ------------------------------ Derived Values ---------------------------- */\n const valueState: CheckboxValueState = useMemo(() => {\n if (checked === 'indeterminate') {\n return 'indeterminate';\n }\n return checked ? 'checked' : 'unchecked';\n }, [checked]);\n\n const iconName = valueState === 'indeterminate' ? 'Minus' : 'Check';\n const showIcon = valueState !== 'unchecked';\n\n /* -------------------------------- Animation ------------------------------- */\n const shouldAnimate = !reduceMotion;\n\n // Scale animation for press feedback (disabled when reduceMotion is true)\n const scaleProgress = useDerivedValue(\n () =>\n shouldAnimate\n ? withSpring(pressed ? SCALE_EFFECTS.down : SCALE_EFFECTS.none, BUTTON_SPRING_CONFIG)\n : SCALE_EFFECTS.none, // No scale effect when reduceMotion is true\n [pressed, shouldAnimate],\n );\n\n const checkboxAnimatedStyle = useAnimatedStyle(() => ({\n transform: [{ scale: scaleProgress.value }],\n }));\n\n /* -------------------------------- Handlers -------------------------------- */\n const handlePress = useCallback(() => {\n if (disabled) {\n return;\n }\n\n const newChecked = checked === 'indeterminate' ? true : !checked;\n\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n\n onChange?.(newChecked);\n }, [disabled, checked, isControlled, onChange]);\n\n const handlePressIn = useCallback(() => {\n setPressed(true);\n }, []);\n\n const handlePressOut = useCallback(() => {\n setPressed(false);\n }, []);\n\n /* --------------------------------- Styles --------------------------------- */\n // Compute the style variant (primary/secondary maps to alert variants when hasError)\n const styleVariant: CheckboxStyleVariant = hasError\n ? VARIANT_ERROR_MAP[variantProp]\n : variantProp;\n\n checkboxStyles.useVariants({\n size,\n variant: styleVariant, // primary, secondary, alert, alert-secondary\n value: valueState, // checked, unchecked, indeterminate\n disabled,\n pressed,\n });\n\n const boxBaseSize = checkboxStyles.checkbox.width;\n const fontScaleFactor = useComponentFontScale(\n resolvedMaxFontSizeMultiplier,\n typeof boxBaseSize === 'number' ? boxBaseSize : undefined,\n );\n // The check/minus glyph is drawn at the 'sm' icon size; use its own native\n // Android curve before disabling native scaling on the manually-sized glyph.\n const markScaleFactor = useComponentFontScale(resolvedMaxFontSizeMultiplier, ICON_SIZE_MAP.sm);\n const scaledMarkSize = Math.round(ICON_SIZE_MAP.sm * markScaleFactor);\n const hasScaledLayout = fontScaleFactor !== 1;\n\n const rootStyle = useMemo(\n () => [checkboxStyles.root, { opacity: disabled ? 0.5 : 1 }],\n [checkboxStyles.root, disabled],\n );\n\n const checkboxBoxStyle = useMemo(() => {\n // The box grows by the capped factor to keep containing the checkmark.\n // borderWidth stays fixed (stroke weight doesn't scale in the OS's own\n // controls either).\n const { width, height, borderRadius } = checkboxStyles.checkbox;\n const scaledBox =\n fontScaleFactor !== 1 && typeof width === 'number' && typeof height === 'number'\n ? {\n width: Math.round(width * fontScaleFactor),\n height: Math.round(height * fontScaleFactor),\n ...(typeof borderRadius === 'number' && {\n borderRadius: Math.round(borderRadius * fontScaleFactor),\n }),\n }\n : undefined;\n\n return [\n checkboxStyles.checkbox,\n scaledBox,\n { alignItems: 'center' as const, justifyContent: 'center' as const },\n checkboxAnimatedStyle,\n ];\n }, [checkboxStyles.checkbox, fontScaleFactor, checkboxAnimatedStyle]);\n\n /* ---------------------------- Render Helpers ------------------------------ */\n const labelContent = useMemo(() => {\n if (!label) {\n return null;\n }\n\n return (\n <FormLabel\n color=\"inherit\"\n variant=\"inherit\"\n label={label}\n required={required}\n showRequiredAsterisk={required}\n hasError={hasError}\n flexShrink={hasScaledLayout ? '1' : undefined}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={checkboxStyles.text}\n />\n );\n }, [\n label,\n required,\n hasError,\n hasScaledLayout,\n resolvedMaxFontSizeMultiplier,\n checkboxStyles.text,\n ]);\n\n const a11yState = useMemo(\n () => ({\n disabled,\n checked:\n valueState === 'checked'\n ? true\n : valueState === 'indeterminate'\n ? ('mixed' as const)\n : false,\n }),\n [disabled, valueState],\n );\n\n /* --------------------------------- Render --------------------------------- */\n return (\n <Pressable\n ref={ref}\n nativeID={uid}\n onPress={handlePress}\n onPressIn={handlePressIn}\n onPressOut={handlePressOut}\n disabled={disabled}\n flexDirection={labelPosition === 'start' ? 'row' : 'row-reverse'}\n alignItems=\"center\"\n alignSelf={hasScaledLayout ? 'stretch' : 'flex-start'}\n minHeight={hasScaledLayout ? 52 : undefined}\n accessibilityRole=\"checkbox\"\n accessibilityState={a11yState}\n accessibilityLabel={typeof label === 'string' ? label : undefined}\n {...viewProps}\n style={rootStyle}\n >\n <Animated.View style={checkboxBoxStyle}>\n {showIcon && (\n <Icon\n name={iconName}\n size=\"sm\"\n // Size the mark from the same factor that scaled the box, with\n // native scaling off: letting the box scale in JS while the glyph\n // scaled natively left the two to round independently (and to\n // disagree outright under Android's non-linear scaling), which\n // drifted the mark off-centre as sizes grew.\n dangerouslySetSize={scaledMarkSize}\n allowFontScaling={false}\n style={[\n checkboxStyles.checkboxIcon,\n markScaleFactor !== 1\n ? {\n fontSize: scaledMarkSize,\n lineHeight: getSafeIconCell(scaledMarkSize),\n }\n : undefined,\n ]}\n />\n )}\n </Animated.View>\n\n {labelContent}\n </Pressable>\n );\n});\n\nCheckbox.displayName = 'Checkbox';\n\nexport { Checkbox, type CheckboxProps };\n"],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ const ChipBase = (0, react.memo)(function ChipBase({ kind, toggleState = DEFAULT
|
|
|
19
19
|
const { theme } = (0, react_native_unistyles.useUnistyles)();
|
|
20
20
|
const [pressed, setPressed] = (0, react.useState)(false);
|
|
21
21
|
const interactionState = pressed ? "pressed" : "rest";
|
|
22
|
-
const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier)
|
|
22
|
+
const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
23
23
|
const rootLayerStyle = (0, react.useMemo)(() => require_components_Chip_chipTheme.getMergedChipLayerStyle(theme, kind, variant, size, toggleState, "root", interactionState), [
|
|
24
24
|
interactionState,
|
|
25
25
|
kind,
|
|
@@ -36,7 +36,7 @@ const ChipBase = (0, react.memo)(function ChipBase({ kind, toggleState = DEFAULT
|
|
|
36
36
|
toggleState,
|
|
37
37
|
variant
|
|
38
38
|
]);
|
|
39
|
-
const fontScaleFactor = require_fontScaling_useFontScale.
|
|
39
|
+
const fontScaleFactor = require_fontScaling_useFontScale.useComponentFontScale(resolvedMaxFontSizeMultiplier, (typeof textLayerStyle.lineHeight === "number" ? textLayerStyle.lineHeight : void 0) ?? (typeof textLayerStyle.fontSize === "number" ? textLayerStyle.fontSize : void 0));
|
|
40
40
|
const rootStyle = (0, react.useMemo)(() => {
|
|
41
41
|
const scaledLayer = fontScaleFactor !== 1 && typeof rootLayerStyle.height === "number" ? { height: Math.round(rootLayerStyle.height * fontScaleFactor) } : void 0;
|
|
42
42
|
const resolvedMaxWidth = maxWidth === 200 ? Math.round(maxWidth * fontScaleFactor) : maxWidth;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
-
import {
|
|
2
|
+
import { useComponentFontScale } from "../../fontScaling/useFontScale.js";
|
|
3
3
|
import { useMaxFontSizeMultiplier } from "../../fontScaling/useMaxFontSizeMultiplier.js";
|
|
4
4
|
import { IconSlot } from "../IconSlot.js";
|
|
5
5
|
import { Text as Text$1 } from "../Text.js";
|
|
@@ -17,7 +17,7 @@ const ChipBase = memo(function ChipBase({ kind, toggleState = DEFAULT_TOGGLE_STA
|
|
|
17
17
|
const { theme } = useUnistyles();
|
|
18
18
|
const [pressed, setPressed] = useState(false);
|
|
19
19
|
const interactionState = pressed ? "pressed" : "rest";
|
|
20
|
-
const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier)
|
|
20
|
+
const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
21
21
|
const rootLayerStyle = useMemo(() => getMergedChipLayerStyle(theme, kind, variant, size, toggleState, "root", interactionState), [
|
|
22
22
|
interactionState,
|
|
23
23
|
kind,
|
|
@@ -34,7 +34,7 @@ const ChipBase = memo(function ChipBase({ kind, toggleState = DEFAULT_TOGGLE_STA
|
|
|
34
34
|
toggleState,
|
|
35
35
|
variant
|
|
36
36
|
]);
|
|
37
|
-
const fontScaleFactor =
|
|
37
|
+
const fontScaleFactor = useComponentFontScale(resolvedMaxFontSizeMultiplier, (typeof textLayerStyle.lineHeight === "number" ? textLayerStyle.lineHeight : void 0) ?? (typeof textLayerStyle.fontSize === "number" ? textLayerStyle.fontSize : void 0));
|
|
38
38
|
const rootStyle = useMemo(() => {
|
|
39
39
|
const scaledLayer = fontScaleFactor !== 1 && typeof rootLayerStyle.height === "number" ? { height: Math.round(rootLayerStyle.height * fontScaleFactor) } : void 0;
|
|
40
40
|
const resolvedMaxWidth = maxWidth === 200 ? Math.round(maxWidth * fontScaleFactor) : maxWidth;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChipBase.js","names":["Text"],"sources":["../../../src/components/Chip/ChipBase.tsx"],"sourcesContent":["import { memo, useMemo, useState } from 'react';\nimport type { StyleProp, TextStyle, ViewStyle } from 'react-native';\nimport { Pressable, StyleSheet, View } from 'react-native';\n// eslint-disable-next-line uds/no-use-unistyles -- chip toggle styles need variant + active token lookups\nimport { useUnistyles } from 'react-native-unistyles';\n\nimport {
|
|
1
|
+
{"version":3,"file":"ChipBase.js","names":["Text"],"sources":["../../../src/components/Chip/ChipBase.tsx"],"sourcesContent":["import { memo, useMemo, useState } from 'react';\nimport type { StyleProp, TextStyle, ViewStyle } from 'react-native';\nimport { Pressable, StyleSheet, View } from 'react-native';\n// eslint-disable-next-line uds/no-use-unistyles -- chip toggle styles need variant + active token lookups\nimport { useUnistyles } from 'react-native-unistyles';\n\nimport { useComponentFontScale } from '../../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../../fontScaling/useMaxFontSizeMultiplier';\nimport { IconSlot } from '../IconSlot';\nimport { Text } from '../Text';\nimport { getMergedChipLayerStyle } from './chipTheme';\nimport type { ChipBaseProps, ChipInteractionState, ChipSize, ChipVariant } from './types';\n\nconst DEFAULT_CHIP_SIZE: ChipSize = 'md';\nconst DEFAULT_CHIP_VARIANT: ChipVariant = 'primary';\nconst DEFAULT_MAX_WIDTH = 200;\nconst DEFAULT_TOGGLE_STATE = 'off';\n\nconst ChipBase = memo(function ChipBase({\n kind,\n toggleState = DEFAULT_TOGGLE_STATE,\n variant = DEFAULT_CHIP_VARIANT,\n size = DEFAULT_CHIP_SIZE,\n minWidth,\n maxWidth = DEFAULT_MAX_WIDTH,\n startIcon,\n endIcon,\n endContent,\n disabled = false,\n pressable = false,\n maxFontSizeMultiplier,\n onPress,\n accessibilityRole,\n accessibilityState,\n children,\n style,\n ref,\n ...viewProps\n}: ChipBaseProps) {\n const { theme } = useUnistyles();\n const [pressed, setPressed] = useState(false);\n const interactionState: ChipInteractionState = pressed ? 'pressed' : 'rest';\n\n // One capped factor governs the label, icons, and the chip's fixed height.\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n const rootLayerStyle = useMemo(\n () =>\n getMergedChipLayerStyle(\n theme,\n kind,\n variant,\n size,\n toggleState,\n 'root',\n interactionState,\n ) as ViewStyle,\n [interactionState, kind, size, theme, toggleState, variant],\n );\n const textLayerStyle = useMemo(\n () =>\n getMergedChipLayerStyle(\n theme,\n kind,\n variant,\n size,\n toggleState,\n 'rootText',\n interactionState,\n ) as TextStyle,\n [interactionState, kind, size, theme, toggleState, variant],\n );\n const fontScaleFactor = useComponentFontScale(\n resolvedMaxFontSizeMultiplier,\n (typeof textLayerStyle.lineHeight === 'number' ? textLayerStyle.lineHeight : undefined) ??\n (typeof textLayerStyle.fontSize === 'number' ? textLayerStyle.fontSize : undefined),\n );\n\n const rootStyle = useMemo<StyleProp<ViewStyle>>(() => {\n // The chip's fixed height grows with its capped content; the default max\n // width grows too so capped labels don't truncate earlier than today. An\n // explicit maxWidth/minWidth from the consumer is respected as-is.\n const scaledLayer =\n fontScaleFactor !== 1 && typeof rootLayerStyle.height === 'number'\n ? { height: Math.round(rootLayerStyle.height * fontScaleFactor) }\n : undefined;\n const resolvedMaxWidth =\n maxWidth === DEFAULT_MAX_WIDTH ? Math.round(maxWidth * fontScaleFactor) : maxWidth;\n\n return [\n chipStaticStyles.root,\n rootLayerStyle,\n scaledLayer,\n minWidth === undefined ? undefined : { minWidth },\n resolvedMaxWidth === undefined ? undefined : { maxWidth: resolvedMaxWidth },\n disabled ? chipStaticStyles.disabled : undefined,\n style,\n ];\n }, [disabled, fontScaleFactor, maxWidth, minWidth, rootLayerStyle, style]);\n\n const textStyle = useMemo<StyleProp<TextStyle>>(\n () => [chipStaticStyles.text, textLayerStyle],\n [textLayerStyle],\n );\n\n const iconStyle = useMemo<StyleProp<TextStyle>>(\n () =>\n getMergedChipLayerStyle(\n theme,\n kind,\n variant,\n size,\n toggleState,\n 'icon',\n interactionState,\n ) as TextStyle,\n [interactionState, kind, size, theme, toggleState, variant],\n );\n\n const content = (\n <>\n {startIcon ? (\n <IconSlot\n icon={startIcon}\n variant=\"fill\"\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={iconStyle}\n />\n ) : null}\n <Text\n color=\"inherit\"\n variant=\"inherit\"\n numberOfLines={1}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={textStyle}\n >\n {children}\n </Text>\n {endContent ??\n (endIcon ? (\n <IconSlot\n icon={endIcon}\n variant=\"fill\"\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={iconStyle}\n />\n ) : null)}\n </>\n );\n\n if (pressable) {\n return (\n <Pressable\n ref={ref}\n accessibilityRole={accessibilityRole}\n accessibilityState={{ disabled, ...accessibilityState }}\n disabled={disabled}\n onPress={disabled ? undefined : onPress}\n onPressIn={() => setPressed(true)}\n onPressOut={() => setPressed(false)}\n {...viewProps}\n style={rootStyle}\n >\n {content}\n </Pressable>\n );\n }\n\n return (\n <View\n ref={ref}\n accessibilityRole={accessibilityRole}\n accessibilityState={{ disabled, ...accessibilityState }}\n {...viewProps}\n style={rootStyle}\n >\n {content}\n </View>\n );\n});\n\nChipBase.displayName = 'ChipBase';\n\nconst chipStaticStyles = StyleSheet.create({\n disabled: {\n opacity: 0.5,\n },\n root: {\n alignItems: 'center',\n alignSelf: 'flex-start',\n flexDirection: 'row',\n overflow: 'hidden',\n },\n text: {\n flexShrink: 1,\n textAlign: 'center',\n },\n});\n\nexport { ChipBase, DEFAULT_CHIP_SIZE, DEFAULT_CHIP_VARIANT, DEFAULT_MAX_WIDTH };\n"],"mappings":"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"}
|
package/dist/components/Icon.cjs
CHANGED
|
@@ -25,13 +25,13 @@ const DEFAULT_PROPS = {
|
|
|
25
25
|
* Uses useUnistyles() for reactive theme access - isolated here so
|
|
26
26
|
* glyph-based icons don't pay the hook overhead.
|
|
27
27
|
*/
|
|
28
|
-
const MulticolorIcon = (0, react.memo)(function MulticolorIcon({ name, size = DEFAULT_PROPS.size, flexShrink = DEFAULT_PROPS.flexShrink, backgroundColor, dangerouslySetSize, maxFontSizeMultiplier, allowFontScaling = true, accessible, accessibilityElementsHidden, accessibilityHint, accessibilityLabel = name, accessibilityRole = "image", accessibilityState, accessibilityValue, importantForAccessibility, testID }) {
|
|
28
|
+
const MulticolorIcon = (0, react.memo)(function MulticolorIcon({ name, size = DEFAULT_PROPS.size, flexShrink = DEFAULT_PROPS.flexShrink, backgroundColor, dangerouslySetSize, maxFontSizeMultiplier, inheritFontScaling = false, allowFontScaling = true, accessible, accessibilityElementsHidden, accessibilityHint, accessibilityLabel = name, accessibilityRole = "image", accessibilityState, accessibilityValue, importantForAccessibility, testID }) {
|
|
29
29
|
const { rt } = (0, react_native_unistyles.useUnistyles)();
|
|
30
30
|
const colorScheme = rt.themeName === "dark" ? "dark" : "light";
|
|
31
31
|
const pixelSize = _yahoo_uds_icons_tokens.ICON_SIZE_MAP[size];
|
|
32
32
|
const baseSize = dangerouslySetSize ?? pixelSize;
|
|
33
|
-
const
|
|
34
|
-
const fontScaleFactor = require_fontScaling_useFontScale.
|
|
33
|
+
const controlMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
34
|
+
const fontScaleFactor = require_fontScaling_useFontScale.useComponentFontScale(allowFontScaling ? inheritFontScaling && maxFontSizeMultiplier === void 0 ? void 0 : controlMaxFontSizeMultiplier : 1, baseSize);
|
|
35
35
|
const renderedSize = Math.round(baseSize * fontScaleFactor);
|
|
36
36
|
const svgKey = `${name}-${colorScheme}-${pixelSize}`;
|
|
37
37
|
const svgContent = _yahoo_uds_icons_svgMap.svgMap[svgKey];
|
|
@@ -62,9 +62,10 @@ const MulticolorIcon = (0, react.memo)(function MulticolorIcon({ name, size = DE
|
|
|
62
62
|
})
|
|
63
63
|
});
|
|
64
64
|
});
|
|
65
|
-
const OutlineOrFillIcon = (0, react.memo)(function OutlineOrFillIcon({ name, size = DEFAULT_PROPS.size, color = DEFAULT_PROPS.color, variant = DEFAULT_PROPS.variant, backgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, flexShrink = "0", spacingStart, spacingEnd, spacingTop, spacingBottom, spacingHorizontal, spacingVertical, spacing, offsetStart, offsetEnd, offsetTop, offsetBottom, offsetHorizontal, offsetVertical, offset, dangerouslySetColor, dangerouslySetSize, maxFontSizeMultiplier, style, ref, ...props }) {
|
|
65
|
+
const OutlineOrFillIcon = (0, react.memo)(function OutlineOrFillIcon({ name, size = DEFAULT_PROPS.size, color = DEFAULT_PROPS.color, variant = DEFAULT_PROPS.variant, backgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, flexShrink = "0", spacingStart, spacingEnd, spacingTop, spacingBottom, spacingHorizontal, spacingVertical, spacing, offsetStart, offsetEnd, offsetTop, offsetBottom, offsetHorizontal, offsetVertical, offset, dangerouslySetColor, dangerouslySetSize, maxFontSizeMultiplier, inheritFontScaling = false, style, ref, ...props }) {
|
|
66
66
|
const pixelSize = _yahoo_uds_icons_tokens.ICON_SIZE_MAP[size];
|
|
67
|
-
const
|
|
67
|
+
const controlMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
68
|
+
const resolvedMaxFontSizeMultiplier = inheritFontScaling && maxFontSizeMultiplier === void 0 ? void 0 : controlMaxFontSizeMultiplier;
|
|
68
69
|
generated_styles.styles.useVariants({
|
|
69
70
|
color,
|
|
70
71
|
backgroundColor,
|
|
@@ -115,12 +116,12 @@ const OutlineOrFillIcon = (0, react.memo)(function OutlineOrFillIcon({ name, siz
|
|
|
115
116
|
lineHeight: require_components_Button_buttonTheme.getSafeIconCell(pixelSize)
|
|
116
117
|
},
|
|
117
118
|
generated_styles.styles.foundation,
|
|
118
|
-
style,
|
|
119
119
|
dangerouslySetColor ? { color: dangerouslySetColor } : void 0,
|
|
120
120
|
dangerouslySetSize ? {
|
|
121
121
|
fontSize: dangerouslySetSize,
|
|
122
122
|
lineHeight: require_components_Button_buttonTheme.getSafeIconCell(dangerouslySetSize)
|
|
123
|
-
} : void 0
|
|
123
|
+
} : void 0,
|
|
124
|
+
style
|
|
124
125
|
], [
|
|
125
126
|
dangerouslySetColor,
|
|
126
127
|
dangerouslySetSize,
|
|
@@ -27,6 +27,8 @@ interface IconProps extends Omit<TextProps, 'style'> {
|
|
|
27
27
|
* @default 2
|
|
28
28
|
*/
|
|
29
29
|
maxFontSizeMultiplier?: number | null;
|
|
30
|
+
/** @internal Inherit a containing Text node's scaling when no cap is supplied. */
|
|
31
|
+
inheritFontScaling?: boolean;
|
|
30
32
|
backgroundColor?: StyleProps['backgroundColor'];
|
|
31
33
|
borderRadius?: StyleProps['borderRadius'];
|
|
32
34
|
borderTopStartRadius?: StyleProps['borderTopStartRadius'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.d.cts","names":[],"sources":["../../src/components/Icon.tsx"],"mappings":";;;;;;;;;;KAqCK,QAAA,GAAW,SAAA,GAAY,YAAA;AAAA,UAElB,SAAA,SAAkB,IAAA,CAAK,SAAA;;EAE/B,GAAA,GAAM,GAAA,CAAI,IAAA;EAJC;EAMX,IAAA,EAAM,QAAA;EANQ;EAQd,IAAA,GAAO,QAAA;EANC;EAQR,KAAA,GAAQ,UAAA;;EAER,OAAA,GAAU,WAAA;EARA;;;;;;EAeV,qBAAA;EAEA,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,UAAA,GAAa,UAAA;EAEb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EACb,UAAA,GAAa,UAAA;EACb,aAAA,GAAgB,UAAA;EAChB,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,OAAA,GAAU,UAAA;EAEV,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EACZ,SAAA,GAAY,UAAA;EACZ,YAAA,GAAe,UAAA;EACf,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,MAAA,GAAS,UAAA;
|
|
1
|
+
{"version":3,"file":"Icon.d.cts","names":[],"sources":["../../src/components/Icon.tsx"],"mappings":";;;;;;;;;;KAqCK,QAAA,GAAW,SAAA,GAAY,YAAA;AAAA,UAElB,SAAA,SAAkB,IAAA,CAAK,SAAA;;EAE/B,GAAA,GAAM,GAAA,CAAI,IAAA;EAJC;EAMX,IAAA,EAAM,QAAA;EANQ;EAQd,IAAA,GAAO,QAAA;EANC;EAQR,KAAA,GAAQ,UAAA;;EAER,OAAA,GAAU,WAAA;EARA;;;;;;EAeV,qBAAA;EAMe;EAJf,kBAAA;EAEA,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,UAAA,GAAa,UAAA;EAEb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EACb,UAAA,GAAa,UAAA;EACb,aAAA,GAAgB,UAAA;EAChB,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,OAAA,GAAU,UAAA;EAEV,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EACZ,SAAA,GAAY,UAAA;EACZ,YAAA,GAAe,UAAA;EACf,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,MAAA,GAAS,UAAA;EAzDqB;EA2D9B,mBAAA;EA3D0B;EA6D1B,kBAAA;EA3DA;EA6DA,KAAA,GAAQ,SAAA,CAAU,SAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8Pd,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA;AAAA,cAaG,SAAA;AAAA,cACA,mBAAA"}
|
|
@@ -27,6 +27,8 @@ interface IconProps extends Omit<TextProps, 'style'> {
|
|
|
27
27
|
* @default 2
|
|
28
28
|
*/
|
|
29
29
|
maxFontSizeMultiplier?: number | null;
|
|
30
|
+
/** @internal Inherit a containing Text node's scaling when no cap is supplied. */
|
|
31
|
+
inheritFontScaling?: boolean;
|
|
30
32
|
backgroundColor?: StyleProps['backgroundColor'];
|
|
31
33
|
borderRadius?: StyleProps['borderRadius'];
|
|
32
34
|
borderTopStartRadius?: StyleProps['borderTopStartRadius'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.d.ts","names":[],"sources":["../../src/components/Icon.tsx"],"mappings":";;;;;;;;;;KAqCK,QAAA,GAAW,SAAA,GAAY,YAAA;AAAA,UAElB,SAAA,SAAkB,IAAA,CAAK,SAAA;;EAE/B,GAAA,GAAM,GAAA,CAAI,IAAA;EAJC;EAMX,IAAA,EAAM,QAAA;EANQ;EAQd,IAAA,GAAO,QAAA;EANC;EAQR,KAAA,GAAQ,UAAA;;EAER,OAAA,GAAU,WAAA;EARA;;;;;;EAeV,qBAAA;EAEA,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,UAAA,GAAa,UAAA;EAEb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EACb,UAAA,GAAa,UAAA;EACb,aAAA,GAAgB,UAAA;EAChB,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,OAAA,GAAU,UAAA;EAEV,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EACZ,SAAA,GAAY,UAAA;EACZ,YAAA,GAAe,UAAA;EACf,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,MAAA,GAAS,UAAA;
|
|
1
|
+
{"version":3,"file":"Icon.d.ts","names":[],"sources":["../../src/components/Icon.tsx"],"mappings":";;;;;;;;;;KAqCK,QAAA,GAAW,SAAA,GAAY,YAAA;AAAA,UAElB,SAAA,SAAkB,IAAA,CAAK,SAAA;;EAE/B,GAAA,GAAM,GAAA,CAAI,IAAA;EAJC;EAMX,IAAA,EAAM,QAAA;EANQ;EAQd,IAAA,GAAO,QAAA;EANC;EAQR,KAAA,GAAQ,UAAA;;EAER,OAAA,GAAU,WAAA;EARA;;;;;;EAeV,qBAAA;EAMe;EAJf,kBAAA;EAEA,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,UAAA,GAAa,UAAA;EAEb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EACb,UAAA,GAAa,UAAA;EACb,aAAA,GAAgB,UAAA;EAChB,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,OAAA,GAAU,UAAA;EAEV,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EACZ,SAAA,GAAY,UAAA;EACZ,YAAA,GAAe,UAAA;EACf,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,MAAA,GAAS,UAAA;EAzDqB;EA2D9B,mBAAA;EA3D0B;EA6D1B,kBAAA;EA3DA;EA6DA,KAAA,GAAQ,SAAA,CAAU,SAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8Pd,IAAA,EAAI,OAAA,CAAA,oBAAA,CAAA,SAAA;AAAA,cAaG,SAAA;AAAA,cACA,mBAAA"}
|
package/dist/components/Icon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
-
import {
|
|
2
|
+
import { useComponentFontScale } from "../fontScaling/useFontScale.js";
|
|
3
3
|
import { useMaxFontSizeMultiplier } from "../fontScaling/useMaxFontSizeMultiplier.js";
|
|
4
4
|
import { getSafeIconCell } from "./Button/buttonTheme.js";
|
|
5
5
|
import { memo, useMemo } from "react";
|
|
@@ -23,13 +23,13 @@ const DEFAULT_PROPS = {
|
|
|
23
23
|
* Uses useUnistyles() for reactive theme access - isolated here so
|
|
24
24
|
* glyph-based icons don't pay the hook overhead.
|
|
25
25
|
*/
|
|
26
|
-
const MulticolorIcon = memo(function MulticolorIcon({ name, size = DEFAULT_PROPS.size, flexShrink = DEFAULT_PROPS.flexShrink, backgroundColor, dangerouslySetSize, maxFontSizeMultiplier, allowFontScaling = true, accessible, accessibilityElementsHidden, accessibilityHint, accessibilityLabel = name, accessibilityRole = "image", accessibilityState, accessibilityValue, importantForAccessibility, testID }) {
|
|
26
|
+
const MulticolorIcon = memo(function MulticolorIcon({ name, size = DEFAULT_PROPS.size, flexShrink = DEFAULT_PROPS.flexShrink, backgroundColor, dangerouslySetSize, maxFontSizeMultiplier, inheritFontScaling = false, allowFontScaling = true, accessible, accessibilityElementsHidden, accessibilityHint, accessibilityLabel = name, accessibilityRole = "image", accessibilityState, accessibilityValue, importantForAccessibility, testID }) {
|
|
27
27
|
const { rt } = useUnistyles();
|
|
28
28
|
const colorScheme = rt.themeName === "dark" ? "dark" : "light";
|
|
29
29
|
const pixelSize = ICON_SIZE_MAP[size];
|
|
30
30
|
const baseSize = dangerouslySetSize ?? pixelSize;
|
|
31
|
-
const
|
|
32
|
-
const fontScaleFactor =
|
|
31
|
+
const controlMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
32
|
+
const fontScaleFactor = useComponentFontScale(allowFontScaling ? inheritFontScaling && maxFontSizeMultiplier === void 0 ? void 0 : controlMaxFontSizeMultiplier : 1, baseSize);
|
|
33
33
|
const renderedSize = Math.round(baseSize * fontScaleFactor);
|
|
34
34
|
const svgKey = `${name}-${colorScheme}-${pixelSize}`;
|
|
35
35
|
const svgContent = svgMap[svgKey];
|
|
@@ -60,9 +60,10 @@ const MulticolorIcon = memo(function MulticolorIcon({ name, size = DEFAULT_PROPS
|
|
|
60
60
|
})
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
|
-
const OutlineOrFillIcon = memo(function OutlineOrFillIcon({ name, size = DEFAULT_PROPS.size, color = DEFAULT_PROPS.color, variant = DEFAULT_PROPS.variant, backgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, flexShrink = "0", spacingStart, spacingEnd, spacingTop, spacingBottom, spacingHorizontal, spacingVertical, spacing, offsetStart, offsetEnd, offsetTop, offsetBottom, offsetHorizontal, offsetVertical, offset, dangerouslySetColor, dangerouslySetSize, maxFontSizeMultiplier, style, ref, ...props }) {
|
|
63
|
+
const OutlineOrFillIcon = memo(function OutlineOrFillIcon({ name, size = DEFAULT_PROPS.size, color = DEFAULT_PROPS.color, variant = DEFAULT_PROPS.variant, backgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, flexShrink = "0", spacingStart, spacingEnd, spacingTop, spacingBottom, spacingHorizontal, spacingVertical, spacing, offsetStart, offsetEnd, offsetTop, offsetBottom, offsetHorizontal, offsetVertical, offset, dangerouslySetColor, dangerouslySetSize, maxFontSizeMultiplier, inheritFontScaling = false, style, ref, ...props }) {
|
|
64
64
|
const pixelSize = ICON_SIZE_MAP[size];
|
|
65
|
-
const
|
|
65
|
+
const controlMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
66
|
+
const resolvedMaxFontSizeMultiplier = inheritFontScaling && maxFontSizeMultiplier === void 0 ? void 0 : controlMaxFontSizeMultiplier;
|
|
66
67
|
styles.useVariants({
|
|
67
68
|
color,
|
|
68
69
|
backgroundColor,
|
|
@@ -113,12 +114,12 @@ const OutlineOrFillIcon = memo(function OutlineOrFillIcon({ name, size = DEFAULT
|
|
|
113
114
|
lineHeight: getSafeIconCell(pixelSize)
|
|
114
115
|
},
|
|
115
116
|
styles.foundation,
|
|
116
|
-
style,
|
|
117
117
|
dangerouslySetColor ? { color: dangerouslySetColor } : void 0,
|
|
118
118
|
dangerouslySetSize ? {
|
|
119
119
|
fontSize: dangerouslySetSize,
|
|
120
120
|
lineHeight: getSafeIconCell(dangerouslySetSize)
|
|
121
|
-
} : void 0
|
|
121
|
+
} : void 0,
|
|
122
|
+
style
|
|
122
123
|
], [
|
|
123
124
|
dangerouslySetColor,
|
|
124
125
|
dangerouslySetSize,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.js","names":[],"sources":["../../src/components/Icon.tsx"],"sourcesContent":["import type { GlyphName } from '@yahoo/uds-icons/glyphMap';\nimport { glyphMap, glyphNames } from '@yahoo/uds-icons/glyphMap';\nimport type { SvgGlyphKey, SvgGlyphName } from '@yahoo/uds-icons/svgMap';\nimport { svgGlyphNames, svgMap } from '@yahoo/uds-icons/svgMap';\nimport { ICON_SIZE_MAP } from '@yahoo/uds-icons/tokens';\nimport type { IconSize, IconVariant } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useMemo } from 'react';\nimport type {\n StyleProp,\n Text as RNText,\n TextProps as RNTextProps,\n TextStyle,\n ViewProps,\n} from 'react-native';\nimport { Text, View } from 'react-native';\nimport { SvgXml } from 'react-native-svg';\n// eslint-disable-next-line uds/no-use-unistyles\nimport { useUnistyles } from 'react-native-unistyles';\n\nimport type { StyleProps } from '../../generated/styles';\nimport { styles } from '../../generated/styles';\nimport { useFontScale } from '../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\nimport { getSafeIconCell } from './Button/buttonTheme';\n\nconst DEFAULT_PROPS = {\n size: 'md',\n color: 'primary',\n variant: 'outline',\n flexShrink: '0',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Icon Props */\n/* -------------------------------------------------------------------------- */\n\ntype IconName = GlyphName | SvgGlyphName;\n\ninterface IconProps extends Omit<RNTextProps, 'style'> {\n /** Ref to the underlying Text element */\n ref?: Ref<RNText>;\n /** The icon name */\n name: IconName;\n /** Icon size */\n size?: IconSize;\n /** Icon color */\n color?: StyleProps['color'];\n /** Icon variant (outline, fill, multicolor) */\n variant?: IconVariant;\n /**\n * Caps how far the icon grows with the OS text-size setting. Applies to both\n * font glyphs and multicolor SVGs. Set null to remove the cap; override\n * app-wide via UDSFontScalingProvider.\n * @default 2\n */\n maxFontSizeMultiplier?: number | null;\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 // Flex\n flexShrink?: StyleProps['flexShrink'];\n // Spacing\n spacingStart?: StyleProps['spacingStart'];\n spacingEnd?: StyleProps['spacingEnd'];\n spacingTop?: StyleProps['spacingTop'];\n spacingBottom?: StyleProps['spacingBottom'];\n spacingHorizontal?: StyleProps['spacingHorizontal'];\n spacingVertical?: StyleProps['spacingVertical'];\n spacing?: StyleProps['spacing'];\n // Offset\n offsetStart?: StyleProps['offsetStart'];\n offsetEnd?: StyleProps['offsetEnd'];\n offsetTop?: StyleProps['offsetTop'];\n offsetBottom?: StyleProps['offsetBottom'];\n offsetHorizontal?: StyleProps['offsetHorizontal'];\n offsetVertical?: StyleProps['offsetVertical'];\n offset?: StyleProps['offset'];\n /** Icon color override */\n dangerouslySetColor?: string;\n /** Icon font size override */\n dangerouslySetSize?: number;\n /** Optional style override */\n style?: StyleProp<TextStyle>;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Multicolor Icon */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Separate component for multicolor SVG icons.\n * Uses useUnistyles() for reactive theme access - isolated here so\n * glyph-based icons don't pay the hook overhead.\n */\nconst MulticolorIcon = memo(function MulticolorIcon({\n name,\n size = DEFAULT_PROPS.size,\n flexShrink = DEFAULT_PROPS.flexShrink,\n backgroundColor,\n dangerouslySetSize,\n maxFontSizeMultiplier,\n allowFontScaling = true,\n accessible,\n accessibilityElementsHidden,\n accessibilityHint,\n accessibilityLabel = name,\n accessibilityRole = 'image',\n accessibilityState,\n accessibilityValue,\n importantForAccessibility,\n testID,\n}: Omit<IconProps, 'variant'>) {\n // Reactive theme subscription - only multicolor icons need this\n const { rt } = useUnistyles();\n const colorScheme = rt.themeName === 'dark' ? 'dark' : 'light';\n\n const pixelSize = ICON_SIZE_MAP[size];\n const baseSize = dangerouslySetSize ?? pixelSize;\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n const fontScaleFactor = useFontScale(\n allowFontScaling ? resolvedMaxFontSizeMultiplier : 1,\n baseSize,\n );\n const renderedSize = Math.round(baseSize * fontScaleFactor);\n const svgKey = `${name}-${colorScheme}-${pixelSize}` as SvgGlyphKey;\n const svgContent = svgMap[svgKey];\n\n if (!svgContent) {\n console.warn(`Multicolor icon \"${svgKey}\" not found`);\n return null;\n }\n\n styles.useVariants({\n flexShrink,\n backgroundColor,\n });\n\n return (\n <View\n accessible={accessible}\n accessibilityElementsHidden={accessibilityElementsHidden}\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n accessibilityState={accessibilityState}\n accessibilityValue={accessibilityValue}\n importantForAccessibility={importantForAccessibility}\n testID={testID}\n style={styles.foundation as ViewProps['style']}\n >\n <SvgXml\n xml={svgContent}\n width={renderedSize}\n height={renderedSize}\n viewBox={`0 0 ${pixelSize} ${pixelSize}`}\n />\n </View>\n );\n});\n\nconst OutlineOrFillIcon = memo(function OutlineOrFillIcon({\n name,\n size = DEFAULT_PROPS.size,\n color = DEFAULT_PROPS.color,\n variant = DEFAULT_PROPS.variant,\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 // Flex\n flexShrink = '0',\n // Spacing\n spacingStart,\n spacingEnd,\n spacingTop,\n spacingBottom,\n spacingHorizontal,\n spacingVertical,\n spacing,\n // Offset\n offsetStart,\n offsetEnd,\n offsetTop,\n offsetBottom,\n offsetHorizontal,\n offsetVertical,\n offset,\n // Dangerously set props\n dangerouslySetColor,\n dangerouslySetSize,\n maxFontSizeMultiplier,\n style,\n ref,\n ...props\n}: Omit<IconProps, 'variant'> & { variant?: 'outline' | 'fill' }) {\n const pixelSize = ICON_SIZE_MAP[size];\n // Native scales fontSize and lineHeight together under the cap, so the\n // glyph cell grows proportionally; glyph selection stays at pixelSize.\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n // Glyph-based icons - no useUnistyles needed, styles.useVariants is reactive\n styles.useVariants({\n color,\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 // Flex\n flexShrink,\n // Spacing\n spacingStart,\n spacingEnd,\n spacingTop,\n spacingBottom,\n spacingHorizontal,\n spacingVertical,\n spacing,\n // Offset\n offsetStart,\n offsetEnd,\n offsetTop,\n offsetBottom,\n offsetHorizontal,\n offsetVertical,\n offset,\n });\n const glyphName = `${name}-${variant}-${pixelSize}`;\n const glyph = (glyphMap as Record<string, string>)[glyphName];\n const textStyles: StyleProp<TextStyle> = useMemo(\n () => [\n {\n fontFamily: 'uds-icons',\n textAlign: 'center',\n textAlignVertical: 'center',\n fontSize: pixelSize,\n lineHeight: getSafeIconCell(pixelSize),\n },\n styles.foundation,\n style,\n dangerouslySetColor ? { color: dangerouslySetColor } : undefined,\n dangerouslySetSize\n ? {\n fontSize: dangerouslySetSize,\n lineHeight: getSafeIconCell(dangerouslySetSize),\n }\n : undefined,\n ],\n [dangerouslySetColor, dangerouslySetSize, style, styles.foundation, pixelSize],\n );\n\n return (\n <Text\n ref={ref}\n accessibilityRole=\"image\"\n accessibilityLabel={name}\n style={textStyles}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n {...props}\n >\n {glyph}\n </Text>\n );\n});\n\n/**\n * **🎨 An icon component using UDS icon fonts and multicolor SVGs**\n *\n * @description\n * Renders icons from the UDS icon library. Supports multiple variants\n * (outline, fill, multicolor) and sizes.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Icon } from '@yahoo/uds-mobile/Icon';\n *\n * <Icon name=\"ChevronRight\" size=\"md\" color=\"primary\" />\n * <Icon name=\"Star\" variant=\"fill\" color=\"accent\" />\n * <Icon name=\"Yahoo\" variant=\"multicolor\" />\n * ```\n *\n * @usage\n * - Use name prop to specify the icon\n * - Use variant prop for outline/fill/multicolor\n * - Use size prop for icon size (xs, sm, md, lg, xl)\n *\n * @accessibility\n * - Sets `accessibilityRole=\"image\"` automatically\n * - Icon name is used as accessibility label\n * - For decorative icons, set `accessibilityElementsHidden`\n *\n * @see {@link IconButton} for clickable icons\n * @see {@link IconSlot} for flexible icon rendering in components\n */\nconst Icon = memo(function Icon({ variant, ...props }: IconProps) {\n // Delegate to MulticolorIcon for SVG-based icons (has its own useUnistyles)\n if (variant === 'multicolor') {\n return <MulticolorIcon {...props} />;\n }\n\n return <OutlineOrFillIcon variant={variant} {...props} />;\n});\n\nIcon.displayName = 'Icon';\n\nexport { Icon };\nexport type { IconName, IconProps };\nexport const iconNames = glyphNames;\nexport const multicolorIconNames = svgGlyphNames;\n"],"mappings":";;;;;;;;;;;;;;AA0BA,MAAM,gBAAgB;CACpB,MAAM;CACN,OAAO;CACP,SAAS;CACT,YAAY;CACb;;;;;;AAiFD,MAAM,iBAAiB,KAAK,SAAS,eAAe,EAClD,MACA,OAAO,cAAc,MACrB,aAAa,cAAc,YAC3B,iBACA,oBACA,uBACA,mBAAmB,MACnB,YACA,6BACA,mBACA,qBAAqB,MACrB,oBAAoB,SACpB,oBACA,oBACA,2BACA,UAC6B;CAE7B,MAAM,EAAE,OAAO,cAAc;CAC7B,MAAM,cAAc,GAAG,cAAc,SAAS,SAAS;CAEvD,MAAM,YAAY,cAAc;CAChC,MAAM,WAAW,sBAAsB;CACvC,MAAM,gCAAgC,yBAAyB,WAAW,sBAAsB;CAChG,MAAM,kBAAkB,aACtB,mBAAmB,gCAAgC,GACnD,SACD;CACD,MAAM,eAAe,KAAK,MAAM,WAAW,gBAAgB;CAC3D,MAAM,SAAS,GAAG,KAAK,GAAG,YAAY,GAAG;CACzC,MAAM,aAAa,OAAO;CAE1B,IAAI,CAAC,YAAY;EACf,QAAQ,KAAK,oBAAoB,OAAO,aAAa;EACrD,OAAO;;CAGT,OAAO,YAAY;EACjB;EACA;EACD,CAAC;CAEF,OACE,oBAAC,MAAD;EACc;EACiB;EACV;EACC;EACD;EACC;EACA;EACO;EACnB;EACR,OAAO,OAAO;YAEd,oBAAC,QAAD;GACE,KAAK;GACL,OAAO;GACP,QAAQ;GACR,SAAS,OAAO,UAAU,GAAG;GAC7B,CAAA;EACG,CAAA;EAET;AAEF,MAAM,oBAAoB,KAAK,SAAS,kBAAkB,EACxD,MACA,OAAO,cAAc,MACrB,QAAQ,cAAc,OACtB,UAAU,cAAc,SAExB,iBAEA,cACA,sBACA,oBACA,yBACA,uBACA,aACA,kBACA,gBACA,gBACA,mBACA,aACA,qBACA,uBACA,kBACA,gBACA,gBACA,mBAEA,aAAa,KAEb,cACA,YACA,YACA,eACA,mBACA,iBACA,SAEA,aACA,WACA,WACA,cACA,kBACA,gBACA,QAEA,qBACA,oBACA,uBACA,OACA,KACA,GAAG,SAC6D;CAChE,MAAM,YAAY,cAAc;CAGhC,MAAM,gCAAgC,yBAAyB,WAAW,sBAAsB;CAEhG,OAAO,YAAY;EACjB;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CAEF,MAAM,QAAS,SAAoC,GAD9B,KAAK,GAAG,QAAQ,GAAG;CAwBxC,OACE,oBAAC,MAAD;EACO;EACL,mBAAkB;EAClB,oBAAoB;EACpB,OA3BqC,cACjC;GACJ;IACE,YAAY;IACZ,WAAW;IACX,mBAAmB;IACnB,UAAU;IACV,YAAY,gBAAgB,UAAU;IACvC;GACD,OAAO;GACP;GACA,sBAAsB,EAAE,OAAO,qBAAqB,GAAG,KAAA;GACvD,qBACI;IACE,UAAU;IACV,YAAY,gBAAgB,mBAAmB;IAChD,GACD,KAAA;GACL,EACD;GAAC;GAAqB;GAAoB;GAAO,OAAO;GAAY;GAAU,CAQ3D;EACjB,uBAAuB;EACvB,GAAI;YAEH;EACI,CAAA;EAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCF,MAAM,OAAO,KAAK,SAAS,KAAK,EAAE,SAAS,GAAG,SAAoB;CAEhE,IAAI,YAAY,cACd,OAAO,oBAAC,gBAAD,EAAgB,GAAI,OAAS,CAAA;CAGtC,OAAO,oBAAC,mBAAD;EAA4B;EAAS,GAAI;EAAS,CAAA;EACzD;AAEF,KAAK,cAAc;AAInB,MAAa,YAAY;AACzB,MAAa,sBAAsB"}
|
|
1
|
+
{"version":3,"file":"Icon.js","names":[],"sources":["../../src/components/Icon.tsx"],"sourcesContent":["import type { GlyphName } from '@yahoo/uds-icons/glyphMap';\nimport { glyphMap, glyphNames } from '@yahoo/uds-icons/glyphMap';\nimport type { SvgGlyphKey, SvgGlyphName } from '@yahoo/uds-icons/svgMap';\nimport { svgGlyphNames, svgMap } from '@yahoo/uds-icons/svgMap';\nimport { ICON_SIZE_MAP } from '@yahoo/uds-icons/tokens';\nimport type { IconSize, IconVariant } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useMemo } from 'react';\nimport type {\n StyleProp,\n Text as RNText,\n TextProps as RNTextProps,\n TextStyle,\n ViewProps,\n} from 'react-native';\nimport { Text, View } from 'react-native';\nimport { SvgXml } from 'react-native-svg';\n// eslint-disable-next-line uds/no-use-unistyles\nimport { useUnistyles } from 'react-native-unistyles';\n\nimport type { StyleProps } from '../../generated/styles';\nimport { styles } from '../../generated/styles';\nimport { useComponentFontScale } from '../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../fontScaling/useMaxFontSizeMultiplier';\nimport { getSafeIconCell } from './Button/buttonTheme';\n\nconst DEFAULT_PROPS = {\n size: 'md',\n color: 'primary',\n variant: 'outline',\n flexShrink: '0',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Icon Props */\n/* -------------------------------------------------------------------------- */\n\ntype IconName = GlyphName | SvgGlyphName;\n\ninterface IconProps extends Omit<RNTextProps, 'style'> {\n /** Ref to the underlying Text element */\n ref?: Ref<RNText>;\n /** The icon name */\n name: IconName;\n /** Icon size */\n size?: IconSize;\n /** Icon color */\n color?: StyleProps['color'];\n /** Icon variant (outline, fill, multicolor) */\n variant?: IconVariant;\n /**\n * Caps how far the icon grows with the OS text-size setting. Applies to both\n * font glyphs and multicolor SVGs. Set null to remove the cap; override\n * app-wide via UDSFontScalingProvider.\n * @default 2\n */\n maxFontSizeMultiplier?: number | null;\n /** @internal Inherit a containing Text node's scaling when no cap is supplied. */\n inheritFontScaling?: boolean;\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 // Flex\n flexShrink?: StyleProps['flexShrink'];\n // Spacing\n spacingStart?: StyleProps['spacingStart'];\n spacingEnd?: StyleProps['spacingEnd'];\n spacingTop?: StyleProps['spacingTop'];\n spacingBottom?: StyleProps['spacingBottom'];\n spacingHorizontal?: StyleProps['spacingHorizontal'];\n spacingVertical?: StyleProps['spacingVertical'];\n spacing?: StyleProps['spacing'];\n // Offset\n offsetStart?: StyleProps['offsetStart'];\n offsetEnd?: StyleProps['offsetEnd'];\n offsetTop?: StyleProps['offsetTop'];\n offsetBottom?: StyleProps['offsetBottom'];\n offsetHorizontal?: StyleProps['offsetHorizontal'];\n offsetVertical?: StyleProps['offsetVertical'];\n offset?: StyleProps['offset'];\n /** Icon color override */\n dangerouslySetColor?: string;\n /** Icon font size override */\n dangerouslySetSize?: number;\n /** Optional style override */\n style?: StyleProp<TextStyle>;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Multicolor Icon */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Separate component for multicolor SVG icons.\n * Uses useUnistyles() for reactive theme access - isolated here so\n * glyph-based icons don't pay the hook overhead.\n */\nconst MulticolorIcon = memo(function MulticolorIcon({\n name,\n size = DEFAULT_PROPS.size,\n flexShrink = DEFAULT_PROPS.flexShrink,\n backgroundColor,\n dangerouslySetSize,\n maxFontSizeMultiplier,\n inheritFontScaling = false,\n allowFontScaling = true,\n accessible,\n accessibilityElementsHidden,\n accessibilityHint,\n accessibilityLabel = name,\n accessibilityRole = 'image',\n accessibilityState,\n accessibilityValue,\n importantForAccessibility,\n testID,\n}: Omit<IconProps, 'variant'>) {\n // Reactive theme subscription - only multicolor icons need this\n const { rt } = useUnistyles();\n const colorScheme = rt.themeName === 'dark' ? 'dark' : 'light';\n\n const pixelSize = ICON_SIZE_MAP[size];\n const baseSize = dangerouslySetSize ?? pixelSize;\n const controlMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n const resolvedMaxFontSizeMultiplier =\n inheritFontScaling && maxFontSizeMultiplier === undefined\n ? undefined\n : controlMaxFontSizeMultiplier;\n const fontScaleFactor = useComponentFontScale(\n allowFontScaling ? resolvedMaxFontSizeMultiplier : 1,\n baseSize,\n );\n const renderedSize = Math.round(baseSize * fontScaleFactor);\n const svgKey = `${name}-${colorScheme}-${pixelSize}` as SvgGlyphKey;\n const svgContent = svgMap[svgKey];\n\n if (!svgContent) {\n console.warn(`Multicolor icon \"${svgKey}\" not found`);\n return null;\n }\n\n styles.useVariants({\n flexShrink,\n backgroundColor,\n });\n\n return (\n <View\n accessible={accessible}\n accessibilityElementsHidden={accessibilityElementsHidden}\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n accessibilityState={accessibilityState}\n accessibilityValue={accessibilityValue}\n importantForAccessibility={importantForAccessibility}\n testID={testID}\n style={styles.foundation as ViewProps['style']}\n >\n <SvgXml\n xml={svgContent}\n width={renderedSize}\n height={renderedSize}\n viewBox={`0 0 ${pixelSize} ${pixelSize}`}\n />\n </View>\n );\n});\n\nconst OutlineOrFillIcon = memo(function OutlineOrFillIcon({\n name,\n size = DEFAULT_PROPS.size,\n color = DEFAULT_PROPS.color,\n variant = DEFAULT_PROPS.variant,\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 // Flex\n flexShrink = '0',\n // Spacing\n spacingStart,\n spacingEnd,\n spacingTop,\n spacingBottom,\n spacingHorizontal,\n spacingVertical,\n spacing,\n // Offset\n offsetStart,\n offsetEnd,\n offsetTop,\n offsetBottom,\n offsetHorizontal,\n offsetVertical,\n offset,\n // Dangerously set props\n dangerouslySetColor,\n dangerouslySetSize,\n maxFontSizeMultiplier,\n inheritFontScaling = false,\n style,\n ref,\n ...props\n}: Omit<IconProps, 'variant'> & { variant?: 'outline' | 'fill' }) {\n const pixelSize = ICON_SIZE_MAP[size];\n // Native scales fontSize and lineHeight together under the cap, so the\n // glyph cell grows proportionally; glyph selection stays at pixelSize.\n const controlMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n const resolvedMaxFontSizeMultiplier =\n inheritFontScaling && maxFontSizeMultiplier === undefined\n ? undefined\n : controlMaxFontSizeMultiplier;\n // Glyph-based icons - no useUnistyles needed, styles.useVariants is reactive\n styles.useVariants({\n color,\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 // Flex\n flexShrink,\n // Spacing\n spacingStart,\n spacingEnd,\n spacingTop,\n spacingBottom,\n spacingHorizontal,\n spacingVertical,\n spacing,\n // Offset\n offsetStart,\n offsetEnd,\n offsetTop,\n offsetBottom,\n offsetHorizontal,\n offsetVertical,\n offset,\n });\n const glyphName = `${name}-${variant}-${pixelSize}`;\n const glyph = (glyphMap as Record<string, string>)[glyphName];\n const textStyles: StyleProp<TextStyle> = useMemo(\n () => [\n {\n fontFamily: 'uds-icons',\n textAlign: 'center',\n textAlignVertical: 'center',\n fontSize: pixelSize,\n lineHeight: getSafeIconCell(pixelSize),\n },\n styles.foundation,\n dangerouslySetColor ? { color: dangerouslySetColor } : undefined,\n dangerouslySetSize\n ? {\n fontSize: dangerouslySetSize,\n lineHeight: getSafeIconCell(dangerouslySetSize),\n }\n : undefined,\n style,\n ],\n [dangerouslySetColor, dangerouslySetSize, style, styles.foundation, pixelSize],\n );\n\n return (\n <Text\n ref={ref}\n accessibilityRole=\"image\"\n accessibilityLabel={name}\n style={textStyles}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n {...props}\n >\n {glyph}\n </Text>\n );\n});\n\n/**\n * **🎨 An icon component using UDS icon fonts and multicolor SVGs**\n *\n * @description\n * Renders icons from the UDS icon library. Supports multiple variants\n * (outline, fill, multicolor) and sizes.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Icon } from '@yahoo/uds-mobile/Icon';\n *\n * <Icon name=\"ChevronRight\" size=\"md\" color=\"primary\" />\n * <Icon name=\"Star\" variant=\"fill\" color=\"accent\" />\n * <Icon name=\"Yahoo\" variant=\"multicolor\" />\n * ```\n *\n * @usage\n * - Use name prop to specify the icon\n * - Use variant prop for outline/fill/multicolor\n * - Use size prop for icon size (xs, sm, md, lg, xl)\n *\n * @accessibility\n * - Sets `accessibilityRole=\"image\"` automatically\n * - Icon name is used as accessibility label\n * - For decorative icons, set `accessibilityElementsHidden`\n *\n * @see {@link IconButton} for clickable icons\n * @see {@link IconSlot} for flexible icon rendering in components\n */\nconst Icon = memo(function Icon({ variant, ...props }: IconProps) {\n // Delegate to MulticolorIcon for SVG-based icons (has its own useUnistyles)\n if (variant === 'multicolor') {\n return <MulticolorIcon {...props} />;\n }\n\n return <OutlineOrFillIcon variant={variant} {...props} />;\n});\n\nIcon.displayName = 'Icon';\n\nexport { Icon };\nexport type { IconName, IconProps };\nexport const iconNames = glyphNames;\nexport const multicolorIconNames = svgGlyphNames;\n"],"mappings":"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"}
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
require("../_virtual/_rolldown/runtime.cjs");
|
|
4
4
|
const require_index = require("../motion-tokens/dist/index.cjs");
|
|
5
5
|
const require_motion = require("../motion.cjs");
|
|
6
|
+
const require_fontScaling_useFontScale = require("../fontScaling/useFontScale.cjs");
|
|
7
|
+
const require_fontScaling_useMaxFontSizeMultiplier = require("../fontScaling/useMaxFontSizeMultiplier.cjs");
|
|
6
8
|
const require_components_Button_buttonTheme = require("./Button/buttonTheme.cjs");
|
|
7
9
|
const require_components_Icon = require("./Icon.cjs");
|
|
8
10
|
const require_components_Pressable = require("./Pressable.cjs");
|
|
@@ -56,12 +58,22 @@ function interpolateShadowAlpha(shadow, alpha) {
|
|
|
56
58
|
* @see {@link Button} for buttons with text labels
|
|
57
59
|
* @see {@link Icon} for non-interactive icons
|
|
58
60
|
*/
|
|
59
|
-
const IconButton = (0, react.memo)(function IconButton({ name, variant = "primary", size = "md", iconVariant = "outline", iconColor, loading, disabled, style, accessibilityLabel, accessibilityHint, disableEffects = false, onPressIn, onPressOut, ref, ...props }) {
|
|
61
|
+
const IconButton = (0, react.memo)(function IconButton({ name, variant = "primary", size = "md", iconVariant = "outline", iconColor, loading, disabled, style, accessibilityLabel, accessibilityHint, disableEffects = false, maxFontSizeMultiplier, onPressIn, onPressOut, ref, ...props }) {
|
|
60
62
|
const isDisabled = disabled || loading;
|
|
61
63
|
const shouldAnimate = !disableEffects && !isDisabled;
|
|
62
64
|
const shouldAnimateVariantColors = react_native.Platform.OS !== "web";
|
|
63
65
|
const { theme } = (0, react_native_unistyles.useUnistyles)();
|
|
64
|
-
const
|
|
66
|
+
const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
67
|
+
const [pressed, setPressed] = (0, react.useState)(false);
|
|
68
|
+
const resolvedIconButtonStyles = generated_styles.iconButtonStyles.useVariants({ size }) ?? generated_styles.iconButtonStyles;
|
|
69
|
+
const iconBaseSize = (0, react.useMemo)(() => require_components_Button_buttonTheme.getIconButtonIconSize(theme, size), [theme, size]);
|
|
70
|
+
const iconScaleFactor = require_fontScaling_useFontScale.useComponentFontScale(resolvedMaxFontSizeMultiplier, iconBaseSize);
|
|
71
|
+
const { minHeight, iconCellHeight, paddingVertical, hasExplicitHeight } = (0, react.useMemo)(() => require_components_Button_buttonTheme.getIconButtonControlMetrics(theme, size, iconScaleFactor), [
|
|
72
|
+
theme,
|
|
73
|
+
size,
|
|
74
|
+
iconScaleFactor
|
|
75
|
+
]);
|
|
76
|
+
const scaledIconSize = Math.round(iconBaseSize * iconScaleFactor);
|
|
65
77
|
const controlDimensions = hasExplicitHeight ? {
|
|
66
78
|
height: "auto",
|
|
67
79
|
width: "auto",
|
|
@@ -72,8 +84,6 @@ const IconButton = (0, react.memo)(function IconButton({ name, variant = "primar
|
|
|
72
84
|
minHeight,
|
|
73
85
|
paddingVertical
|
|
74
86
|
};
|
|
75
|
-
const [pressed, setPressed] = (0, react.useState)(false);
|
|
76
|
-
const resolvedIconButtonStyles = generated_styles.iconButtonStyles.useVariants({ size }) ?? generated_styles.iconButtonStyles;
|
|
77
87
|
const resolvedButtonStyles = generated_styles.buttonStyles.useVariants({
|
|
78
88
|
variant,
|
|
79
89
|
disabled: isDisabled,
|
|
@@ -151,7 +161,7 @@ const IconButton = (0, react.memo)(function IconButton({ name, variant = "primar
|
|
|
151
161
|
],
|
|
152
162
|
...props,
|
|
153
163
|
children: loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.ActivityIndicator, {
|
|
154
|
-
size:
|
|
164
|
+
size: scaledIconSize,
|
|
155
165
|
color: resolvedIconColor ?? resolvedButtonStyles.icon.color
|
|
156
166
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Icon.Icon, {
|
|
157
167
|
name,
|
|
@@ -161,7 +171,8 @@ const IconButton = (0, react.memo)(function IconButton({ name, variant = "primar
|
|
|
161
171
|
resolvedButtonStyles.icon,
|
|
162
172
|
{ lineHeight: iconCellHeight }
|
|
163
173
|
],
|
|
164
|
-
dangerouslySetColor: resolvedIconColor
|
|
174
|
+
dangerouslySetColor: resolvedIconColor,
|
|
175
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier
|
|
165
176
|
})
|
|
166
177
|
});
|
|
167
178
|
});
|
|
@@ -26,6 +26,12 @@ interface IconButtonProps extends Omit<PressableProps$1, 'children'> {
|
|
|
26
26
|
* @default false
|
|
27
27
|
*/
|
|
28
28
|
disableEffects?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Caps how far the icon and control grow with the OS text-size setting.
|
|
31
|
+
* Set null to remove the cap; override app-wide via UDSFontScalingProvider.
|
|
32
|
+
* @default 2
|
|
33
|
+
*/
|
|
34
|
+
maxFontSizeMultiplier?: number | null;
|
|
29
35
|
/** Ref to the underlying View */
|
|
30
36
|
ref?: Ref<View>;
|
|
31
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.d.cts","names":[],"sources":["../../src/components/IconButton.tsx"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"IconButton.d.cts","names":[],"sources":["../../src/components/IconButton.tsx"],"mappings":";;;;;;;;;;UAsDU,eAAA,SAAwB,IAAA,CAAK,gBAAA;;EAErC,IAAA,EAAM,QAAA;EAFE;EAIR,OAAA,GAAU,iBAAA;;EAEV,IAAA,GAAO,cAAA;EAJD;EAMN,WAAA,GAAc,WAAA;EAFP;EAIP,SAAA,GAAY,UAAA;EAAA;EAEZ,OAAA;EAaM;;;;EARN,cAAA;EAjBqC;;;;;EAuBrC,qBAAA;EAjBO;EAmBP,GAAA,GAAM,GAAA,CAAI,IAAA;AAAA;;;;;;;;;;;AAAI;;;;;;;;;;;;;;;;;;;;;;;cAwCV,UAAA,EAAU,OAAA,CAAA,oBAAA,CAAA,eAAA"}
|
|
@@ -26,6 +26,12 @@ interface IconButtonProps extends Omit<PressableProps$1, 'children'> {
|
|
|
26
26
|
* @default false
|
|
27
27
|
*/
|
|
28
28
|
disableEffects?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Caps how far the icon and control grow with the OS text-size setting.
|
|
31
|
+
* Set null to remove the cap; override app-wide via UDSFontScalingProvider.
|
|
32
|
+
* @default 2
|
|
33
|
+
*/
|
|
34
|
+
maxFontSizeMultiplier?: number | null;
|
|
29
35
|
/** Ref to the underlying View */
|
|
30
36
|
ref?: Ref<View>;
|
|
31
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.d.ts","names":[],"sources":["../../src/components/IconButton.tsx"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"IconButton.d.ts","names":[],"sources":["../../src/components/IconButton.tsx"],"mappings":";;;;;;;;;;UAsDU,eAAA,SAAwB,IAAA,CAAK,gBAAA;;EAErC,IAAA,EAAM,QAAA;EAFE;EAIR,OAAA,GAAU,iBAAA;;EAEV,IAAA,GAAO,cAAA;EAJD;EAMN,WAAA,GAAc,WAAA;EAFP;EAIP,SAAA,GAAY,UAAA;EAAA;EAEZ,OAAA;EAaM;;;;EARN,cAAA;EAjBqC;;;;;EAuBrC,qBAAA;EAjBO;EAmBP,GAAA,GAAM,GAAA,CAAI,IAAA;AAAA;;;;;;;;;;;AAAI;;;;;;;;;;;;;;;;;;;;;;;cAwCV,UAAA,EAAU,OAAA,CAAA,oBAAA,CAAA,eAAA"}
|