@yahoo/uds-mobile 2.23.3 → 2.24.0-beta.10
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 +41 -13
- package/dist/bin/automated-config/dist/generated/generatedConfigs.mjs +92 -46
- package/dist/components/Avatar/AvatarIcon.cjs +8 -2
- package/dist/components/Avatar/AvatarIcon.d.cts.map +1 -1
- package/dist/components/Avatar/AvatarIcon.d.ts.map +1 -1
- package/dist/components/Avatar/AvatarIcon.js +9 -3
- package/dist/components/Avatar/AvatarIcon.js.map +1 -1
- package/dist/components/Avatar/AvatarImage.cjs +9 -2
- package/dist/components/Avatar/AvatarImage.d.cts.map +1 -1
- package/dist/components/Avatar/AvatarImage.d.ts.map +1 -1
- package/dist/components/Avatar/AvatarImage.js +10 -3
- package/dist/components/Avatar/AvatarImage.js.map +1 -1
- package/dist/components/Avatar/AvatarText.cjs +8 -2
- package/dist/components/Avatar/AvatarText.d.cts.map +1 -1
- package/dist/components/Avatar/AvatarText.d.ts.map +1 -1
- package/dist/components/Avatar/AvatarText.js +9 -3
- package/dist/components/Avatar/AvatarText.js.map +1 -1
- package/dist/components/Avatar/types.d.cts +7 -3
- package/dist/components/Avatar/types.d.cts.map +1 -1
- package/dist/components/Avatar/types.d.ts +7 -3
- package/dist/components/Avatar/types.d.ts.map +1 -1
- package/dist/components/Avatar/useAvatarFontScale.cjs +16 -0
- package/dist/components/Avatar/useAvatarFontScale.d.cts +7 -0
- package/dist/components/Avatar/useAvatarFontScale.d.cts.map +1 -0
- package/dist/components/Avatar/useAvatarFontScale.d.ts +7 -0
- package/dist/components/Avatar/useAvatarFontScale.d.ts.map +1 -0
- package/dist/components/Avatar/useAvatarFontScale.js +16 -0
- package/dist/components/Avatar/useAvatarFontScale.js.map +1 -0
- package/dist/components/Avatar/utils.cjs +9 -6
- package/dist/components/Avatar/utils.d.cts +2 -2
- package/dist/components/Avatar/utils.d.cts.map +1 -1
- package/dist/components/Avatar/utils.d.ts +2 -2
- package/dist/components/Avatar/utils.d.ts.map +1 -1
- package/dist/components/Avatar/utils.js +9 -6
- package/dist/components/Avatar/utils.js.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
- package/dist/components/BottomSheet/BottomSheet.js +1 -1
- package/dist/components/Button/buttonTheme.cjs +31 -9
- package/dist/components/Button/buttonTheme.d.cts +24 -5
- package/dist/components/Button/buttonTheme.d.cts.map +1 -1
- package/dist/components/Button/buttonTheme.d.ts +24 -5
- package/dist/components/Button/buttonTheme.d.ts.map +1 -1
- package/dist/components/Button/buttonTheme.js +31 -10
- package/dist/components/Button/buttonTheme.js.map +1 -1
- package/dist/components/Button.cjs +35 -8
- package/dist/components/Button.d.cts +7 -0
- package/dist/components/Button.d.cts.map +1 -1
- package/dist/components/Button.d.ts +7 -0
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +35 -8
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Checkbox.cjs +42 -9
- package/dist/components/Checkbox.d.cts +7 -0
- package/dist/components/Checkbox.d.cts.map +1 -1
- package/dist/components/Checkbox.d.ts +7 -0
- package/dist/components/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox.js +42 -9
- package/dist/components/Checkbox.js.map +1 -1
- package/dist/components/Chip/ChipBase.cjs +31 -14
- package/dist/components/Chip/ChipBase.d.cts.map +1 -1
- package/dist/components/Chip/ChipBase.d.ts.map +1 -1
- package/dist/components/Chip/ChipBase.js +31 -14
- package/dist/components/Chip/ChipBase.js.map +1 -1
- package/dist/components/Chip/ChipDismissible.cjs +3 -1
- package/dist/components/Chip/ChipDismissible.js +3 -1
- package/dist/components/Chip/ChipDismissible.js.map +1 -1
- package/dist/components/Chip/types.d.cts +7 -0
- package/dist/components/Chip/types.d.cts.map +1 -1
- package/dist/components/Chip/types.d.ts +7 -0
- package/dist/components/Chip/types.d.ts.map +1 -1
- package/dist/components/Icon.cjs +24 -5
- package/dist/components/Icon.d.cts +11 -2
- package/dist/components/Icon.d.cts.map +1 -1
- package/dist/components/Icon.d.ts +11 -2
- package/dist/components/Icon.d.ts.map +1 -1
- package/dist/components/Icon.js +24 -5
- 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 +56 -18
- package/dist/components/Input.d.cts +5 -0
- package/dist/components/Input.d.cts.map +1 -1
- package/dist/components/Input.d.ts +5 -0
- package/dist/components/Input.d.ts.map +1 -1
- package/dist/components/Input.js +56 -18
- package/dist/components/Input.js.map +1 -1
- package/dist/components/InputHelpText.cjs +7 -1
- package/dist/components/InputHelpText.d.cts +2 -0
- package/dist/components/InputHelpText.d.cts.map +1 -1
- package/dist/components/InputHelpText.d.ts +2 -0
- package/dist/components/InputHelpText.d.ts.map +1 -1
- package/dist/components/InputHelpText.js +7 -1
- package/dist/components/InputHelpText.js.map +1 -1
- package/dist/components/Link.cjs +13 -1
- package/dist/components/Link.d.cts +7 -0
- package/dist/components/Link.d.cts.map +1 -1
- package/dist/components/Link.d.ts +7 -0
- package/dist/components/Link.d.ts.map +1 -1
- package/dist/components/Link.js +13 -1
- package/dist/components/Link.js.map +1 -1
- package/dist/components/Pagination/Pagination.cjs +18 -10
- package/dist/components/Pagination/Pagination.d.cts +2 -0
- package/dist/components/Pagination/Pagination.d.cts.map +1 -1
- package/dist/components/Pagination/Pagination.d.ts +2 -0
- package/dist/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/components/Pagination/Pagination.js +18 -10
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Pagination/PaginationEllipsis.cjs +8 -2
- package/dist/components/Pagination/PaginationEllipsis.d.cts.map +1 -1
- package/dist/components/Pagination/PaginationEllipsis.d.ts.map +1 -1
- package/dist/components/Pagination/PaginationEllipsis.js +9 -3
- package/dist/components/Pagination/PaginationEllipsis.js.map +1 -1
- package/dist/components/Pagination/PaginationItem.cjs +2 -1
- package/dist/components/Pagination/PaginationItem.js +2 -1
- package/dist/components/Pagination/PaginationItem.js.map +1 -1
- package/dist/components/Pagination/PaginationLink.cjs +2 -1
- package/dist/components/Pagination/PaginationLink.js +2 -1
- package/dist/components/Pagination/PaginationLink.js.map +1 -1
- package/dist/components/Pagination/PaginationNext.cjs +3 -1
- package/dist/components/Pagination/PaginationNext.js +3 -1
- package/dist/components/Pagination/PaginationNext.js.map +1 -1
- package/dist/components/Pagination/PaginationPrev.cjs +3 -1
- package/dist/components/Pagination/PaginationPrev.js +3 -1
- package/dist/components/Pagination/PaginationPrev.js.map +1 -1
- package/dist/components/Pagination/paginationContext.d.cts +2 -0
- package/dist/components/Pagination/paginationContext.d.cts.map +1 -1
- package/dist/components/Pagination/paginationContext.d.ts +2 -0
- package/dist/components/Pagination/paginationContext.d.ts.map +1 -1
- package/dist/components/Pagination/paginationContext.js.map +1 -1
- package/dist/components/Pagination/usePaginationControlStyles.cjs +8 -1
- package/dist/components/Pagination/usePaginationControlStyles.d.cts.map +1 -1
- package/dist/components/Pagination/usePaginationControlStyles.d.ts.map +1 -1
- package/dist/components/Pagination/usePaginationControlStyles.js +9 -2
- package/dist/components/Pagination/usePaginationControlStyles.js.map +1 -1
- package/dist/components/Radio/Radio.cjs +30 -11
- package/dist/components/Radio/Radio.d.cts +7 -0
- package/dist/components/Radio/Radio.d.cts.map +1 -1
- package/dist/components/Radio/Radio.d.ts +7 -0
- package/dist/components/Radio/Radio.d.ts.map +1 -1
- package/dist/components/Radio/Radio.js +30 -11
- package/dist/components/Radio/Radio.js.map +1 -1
- package/dist/components/Select/Select.cjs +29 -6
- package/dist/components/Select/Select.d.cts +2 -0
- package/dist/components/Select/Select.d.cts.map +1 -1
- package/dist/components/Select/Select.d.ts +2 -0
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +29 -6
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectContent.cjs +31 -23
- package/dist/components/Select/SelectContent.d.cts.map +1 -1
- package/dist/components/Select/SelectContent.d.ts.map +1 -1
- package/dist/components/Select/SelectContent.js +32 -24
- package/dist/components/Select/SelectContent.js.map +1 -1
- package/dist/components/Select/SelectItem.cjs +25 -15
- package/dist/components/Select/SelectItem.d.cts.map +1 -1
- package/dist/components/Select/SelectItem.d.ts.map +1 -1
- package/dist/components/Select/SelectItem.js +25 -15
- package/dist/components/Select/SelectItem.js.map +1 -1
- package/dist/components/Select/SelectTrigger.cjs +27 -13
- package/dist/components/Select/SelectTrigger.d.cts.map +1 -1
- package/dist/components/Select/SelectTrigger.d.ts.map +1 -1
- package/dist/components/Select/SelectTrigger.js +27 -13
- package/dist/components/Select/SelectTrigger.js.map +1 -1
- package/dist/components/Select/types.d.cts +2 -0
- package/dist/components/Select/types.d.cts.map +1 -1
- package/dist/components/Select/types.d.ts +2 -0
- package/dist/components/Select/types.d.ts.map +1 -1
- package/dist/components/Switch.cjs +48 -8
- package/dist/components/Switch.d.cts +7 -0
- package/dist/components/Switch.d.cts.map +1 -1
- package/dist/components/Switch.d.ts +7 -0
- package/dist/components/Switch.d.ts.map +1 -1
- package/dist/components/Switch.js +48 -8
- package/dist/components/Switch.js.map +1 -1
- package/dist/components/Tabs/Tab.cjs +17 -3
- package/dist/components/Tabs/Tab.d.cts.map +1 -1
- package/dist/components/Tabs/Tab.d.ts.map +1 -1
- package/dist/components/Tabs/Tab.js +17 -3
- package/dist/components/Tabs/Tab.js.map +1 -1
- package/dist/components/Tabs/Tabs.cjs +8 -3
- package/dist/components/Tabs/Tabs.d.cts +9 -1
- package/dist/components/Tabs/Tabs.d.cts.map +1 -1
- package/dist/components/Tabs/Tabs.d.ts +9 -1
- package/dist/components/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/Tabs/Tabs.js +8 -3
- package/dist/components/Tabs/Tabs.js.map +1 -1
- package/dist/components/Tabs/tabsContexts.d.cts +2 -0
- package/dist/components/Tabs/tabsContexts.d.cts.map +1 -1
- package/dist/components/Tabs/tabsContexts.d.ts +2 -0
- package/dist/components/Tabs/tabsContexts.d.ts.map +1 -1
- package/dist/components/Tabs/tabsContexts.js.map +1 -1
- package/dist/components/Text.cjs +9 -1
- package/dist/components/Text.d.cts +11 -2
- package/dist/components/Text.d.cts.map +1 -1
- package/dist/components/Text.d.ts +11 -2
- package/dist/components/Text.d.ts.map +1 -1
- package/dist/components/Text.js +9 -1
- package/dist/components/Text.js.map +1 -1
- package/dist/components/UDSProvider.cjs +6 -2
- package/dist/components/UDSProvider.d.cts +9 -0
- package/dist/components/UDSProvider.d.cts.map +1 -1
- package/dist/components/UDSProvider.d.ts +9 -0
- package/dist/components/UDSProvider.d.ts.map +1 -1
- package/dist/components/UDSProvider.js +6 -2
- package/dist/components/UDSProvider.js.map +1 -1
- package/dist/components/internal/Overlay/index.cjs +1 -1
- package/dist/components/internal/Overlay/index.js +1 -1
- package/dist/fontScaling/FontScalingContext.cjs +67 -0
- package/dist/fontScaling/FontScalingContext.d.cts +53 -0
- package/dist/fontScaling/FontScalingContext.d.cts.map +1 -0
- package/dist/fontScaling/FontScalingContext.d.ts +53 -0
- package/dist/fontScaling/FontScalingContext.d.ts.map +1 -0
- package/dist/fontScaling/FontScalingContext.js +63 -0
- package/dist/fontScaling/FontScalingContext.js.map +1 -0
- package/dist/fontScaling/androidNonlinearFontScaling.cjs +250 -0
- package/dist/fontScaling/androidNonlinearFontScaling.d.cts +7 -0
- package/dist/fontScaling/androidNonlinearFontScaling.d.cts.map +1 -0
- package/dist/fontScaling/androidNonlinearFontScaling.d.ts +7 -0
- package/dist/fontScaling/androidNonlinearFontScaling.d.ts.map +1 -0
- package/dist/fontScaling/androidNonlinearFontScaling.js +251 -0
- package/dist/fontScaling/androidNonlinearFontScaling.js.map +1 -0
- package/dist/fontScaling/constants.cjs +106 -0
- package/dist/fontScaling/constants.d.cts +60 -0
- package/dist/fontScaling/constants.d.cts.map +1 -0
- package/dist/fontScaling/constants.d.ts +60 -0
- package/dist/fontScaling/constants.d.ts.map +1 -0
- package/dist/fontScaling/constants.js +103 -0
- package/dist/fontScaling/constants.js.map +1 -0
- package/dist/fontScaling/index.cjs +14 -0
- package/dist/fontScaling/index.d.cts +8 -0
- package/dist/fontScaling/index.d.ts +8 -0
- package/dist/fontScaling/index.js +6 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.cjs +37 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.cts +35 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.cts.map +1 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.ts +35 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.d.ts.map +1 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.js +38 -0
- package/dist/fontScaling/resolveMaxFontSizeMultiplier.js.map +1 -0
- package/dist/fontScaling/types.cjs +1 -0
- package/dist/fontScaling/types.d.cts +54 -0
- package/dist/fontScaling/types.d.cts.map +1 -0
- package/dist/fontScaling/types.d.ts +54 -0
- package/dist/fontScaling/types.d.ts.map +1 -0
- package/dist/fontScaling/types.js +1 -0
- package/dist/fontScaling/useFontScale.cjs +58 -0
- package/dist/fontScaling/useFontScale.d.cts +12 -0
- package/dist/fontScaling/useFontScale.d.cts.map +1 -0
- package/dist/fontScaling/useFontScale.d.ts +12 -0
- package/dist/fontScaling/useFontScale.d.ts.map +1 -0
- package/dist/fontScaling/useFontScale.js +57 -0
- package/dist/fontScaling/useFontScale.js.map +1 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.cjs +24 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.cts +16 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.cts.map +1 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.ts +16 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.d.ts.map +1 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.js +24 -0
- package/dist/fontScaling/useMaxFontSizeMultiplier.js.map +1 -0
- package/dist/jest/mocks/react-native.cjs +19 -4
- package/dist/jest/mocks/react-native.d.cts +8 -5
- package/dist/jest/mocks/react-native.d.cts.map +1 -1
- package/dist/jest/mocks/react-native.d.ts +8 -5
- package/dist/jest/mocks/react-native.d.ts.map +1 -1
- package/dist/jest/mocks/react-native.js +18 -5
- package/dist/jest/mocks/react-native.js.map +1 -1
- package/dist/jest/mocks/styles.cjs +28 -1
- package/dist/jest/mocks/styles.d.cts.map +1 -1
- package/dist/jest/mocks/styles.d.ts.map +1 -1
- package/dist/jest/mocks/styles.js +28 -1
- package/dist/jest/mocks/styles.js.map +1 -1
- package/dist/jest/setup.cjs +4 -0
- package/dist/jest/setup.d.cts.map +1 -1
- package/dist/jest/setup.d.ts.map +1 -1
- package/dist/jest/setup.js +4 -0
- package/dist/jest/setup.js.map +1 -1
- package/dist/mobile/generated/fontMetrics.cjs +530 -530
- package/dist/mobile/generated/fontMetrics.js +530 -530
- package/dist/mobile/generated/fontMetrics.js.map +1 -1
- package/dist/portal.cjs +8 -2
- package/dist/portal.d.cts.map +1 -1
- package/dist/portal.d.ts.map +1 -1
- package/dist/portal.js +8 -2
- package/dist/portal.js.map +1 -1
- package/dist/types/dist/index.d.cts.map +1 -1
- package/dist/types/dist/index.d.ts.map +1 -1
- package/fonts/index.cjs +214 -214
- package/fonts/index.mjs +214 -214
- package/fonts/uds-icons.ttf +0 -0
- package/generated/fontMetrics.ts +530 -530
- package/generated/styles.d.ts +5 -28
- package/generated/unistyles.d.ts +0 -27
- package/package.json +11 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Radio.js","names":["Pressable"],"sources":["../../../src/components/Radio/Radio.tsx"],"sourcesContent":["import type { RadioVariant, UniversalRadioProps } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useCallback, useEffect, useId, useMemo, useState } from 'react';\nimport type { ViewProps } from 'react-native';\nimport { View } from 'react-native';\nimport Animated, { useAnimatedStyle, useDerivedValue, withSpring } from 'react-native-reanimated';\n\nimport { radioStyles } from '../../../generated/styles';\nimport { BUTTON_SPRING_CONFIG, SCALE_EFFECTS } from '../../motion';\nimport { FormLabel } from '../FormLabel';\nimport { Pressable } from '../Pressable';\nimport { useRadioGroupContext } from './RadioGroupContext';\n\n/* -------------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------------- */\n\n/** Derived from RadioValue - maps boolean to 'checked'/'unchecked' string literals */\ntype RadioValueState = 'checked' | 'unchecked';\n\ninterface RadioProps extends Omit<ViewProps, 'style'>, UniversalRadioProps {\n /** Ref to the underlying View */\n ref?: Ref<View>;\n /** Default checked state for uncontrolled mode */\n defaultChecked?: boolean;\n /** Whether the radio is disabled */\n disabled?: boolean;\n /** Whether the radio is required */\n required?: boolean;\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 RadioStyleVariant = 'primary' | 'secondary' | 'alert' | 'alert-secondary';\n\nconst VARIANT_ERROR_MAP: Record<RadioVariant, RadioStyleVariant> = {\n primary: 'alert',\n secondary: 'alert-secondary',\n};\n\n/* -------------------------------------------------------------------------- */\n/* Radio Component */\n/* -------------------------------------------------------------------------- */\n\n/**\n * **⚙️ A radio component**\n *\n * @description\n * A radio component allows users to select one option from a set.\n * Unlike checkbox, radio buttons cannot have multiple selected in a group,\n * allowing only one selection at a time.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Radio } from '@yahoo/uds-mobile/Radio';\n *\n * <Radio label=\"Option A\" />\n * <Radio label=\"Option B\" checked={true} onChange={setChecked} />\n * ```\n *\n * @usage\n * - Forms: For selecting a single option from multiple choices\n * - Settings: For toggling between mutually exclusive preferences\n *\n * @accessibility\n * - Sets `accessibilityRole=\"radio\"` automatically\n * - Announces checked/unchecked state\n * - Label is used as accessibility label\n * - Supports `reduceMotion` for users who prefer reduced motion\n *\n * @see {@link Checkbox} for multi-select options\n * @see {@link Switch} for binary toggles\n */\nconst Radio = memo(function Radio({\n // Radio props\n label,\n labelPosition = 'start',\n variant: variantInput,\n size: sizeInput,\n value: valueProp,\n checked: checkedProp,\n hasError: hasErrorProp,\n reduceMotion: reduceMotionProp,\n // Native props\n defaultChecked,\n disabled: disabledProp,\n required,\n onChange,\n ref,\n ...viewProps\n}: RadioProps) {\n const generatedId = useId();\n const uid = `uds-radio-${generatedId}`;\n const radioGroup = useRadioGroupContext();\n\n const disabled = Boolean(disabledProp || radioGroup?.disabled);\n const hasError = hasErrorProp ?? radioGroup?.hasError;\n const reduceMotion = reduceMotionProp ?? radioGroup?.reduceMotion;\n const size = sizeInput ?? radioGroup?.size ?? 'md';\n const variantProp = variantInput ?? radioGroup?.variant ?? 'primary';\n const value = valueProp ?? '';\n\n /* --------------------------------- State ---------------------------------- */\n const isInRadioGroup = radioGroup !== undefined;\n const isControlled = checkedProp !== undefined;\n const [internalChecked, setInternalChecked] = useState<boolean>(\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 = isInRadioGroup\n ? radioGroup.value === value\n : isControlled\n ? checkedProp\n : internalChecked;\n\n useEffect(() => {\n if (!__DEV__ || !isInRadioGroup || valueProp) {\n return;\n }\n\n console.warn(\n '[UDS Mobile] Radio: A Radio rendered inside RadioGroup requires a unique, non-empty value prop.',\n );\n }, [isInRadioGroup, valueProp]);\n\n /* ------------------------------ Derived Values ---------------------------- */\n const valueState: RadioValueState = useMemo(() => {\n return checked ? 'checked' : 'unchecked';\n }, [checked]);\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 radioAnimatedStyle = useAnimatedStyle(() => ({\n transform: [{ scale: scaleProgress.value }],\n }));\n\n /* -------------------------------- Handlers -------------------------------- */\n const handlePress = useCallback(() => {\n if (disabled) {\n return;\n }\n\n if (isInRadioGroup) {\n if (radioGroup.value === value) {\n return;\n }\n\n radioGroup.setValue(value);\n onChange?.(true);\n return;\n }\n\n const newChecked = !checked;\n\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n\n onChange?.(newChecked);\n }, [disabled, isInRadioGroup, checked, isControlled, onChange, radioGroup, value]);\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: RadioStyleVariant = hasError ? VARIANT_ERROR_MAP[variantProp] : variantProp;\n\n radioStyles.useVariants({\n size,\n variant: styleVariant, // primary, secondary, alert, alert-secondary\n value: valueState, // checked, unchecked\n pressed,\n });\n\n const rootStyle = useMemo(\n () => [radioStyles.root, { opacity: disabled ? 0.5 : 1 }],\n [radioStyles.root, disabled],\n );\n\n const radioBoxStyle = useMemo(\n () => [\n radioStyles.radio,\n {\n alignItems: 'center' as const,\n justifyContent: 'center' as const,\n borderRadius: 9999,\n },\n radioAnimatedStyle,\n ],\n [radioStyles.radio, radioAnimatedStyle],\n );\n\n // Inner circle size: fixed 8x8px to match web implementation\n const INNER_CIRCLE_SIZE = 8;\n\n const circleStyle = useMemo(\n () => [\n radioStyles.radioCircle,\n {\n width: INNER_CIRCLE_SIZE,\n height: INNER_CIRCLE_SIZE,\n borderRadius: 9999,\n },\n ],\n [radioStyles.radioCircle],\n );\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 style={radioStyles.text}\n />\n );\n }, [label, required, hasError, radioStyles.text]);\n\n const a11yState = useMemo(\n () => ({\n disabled,\n checked,\n }),\n [disabled, checked],\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=\"flex-start\"\n accessibilityRole=\"radio\"\n accessibilityState={a11yState}\n accessibilityLabel={typeof label === 'string' ? label : undefined}\n {...viewProps}\n style={rootStyle}\n >\n <Animated.View style={radioBoxStyle}>{checked && <View style={circleStyle} />}</Animated.View>\n\n {labelContent}\n </Pressable>\n );\n});\n\nRadio.displayName = 'Radio';\n\nexport { Radio, type RadioProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Radio.js","names":["Pressable"],"sources":["../../../src/components/Radio/Radio.tsx"],"sourcesContent":["import type { RadioVariant, UniversalRadioProps } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useCallback, useEffect, useId, useMemo, useState } from 'react';\nimport type { ViewProps } from 'react-native';\nimport { View } from 'react-native';\nimport Animated, { useAnimatedStyle, useDerivedValue, withSpring } from 'react-native-reanimated';\n\nimport { radioStyles } from '../../../generated/styles';\nimport { useComponentFontScale } from '../../fontScaling/useFontScale';\nimport { useMaxFontSizeMultiplier } from '../../fontScaling/useMaxFontSizeMultiplier';\nimport { BUTTON_SPRING_CONFIG, SCALE_EFFECTS } from '../../motion';\nimport { FormLabel } from '../FormLabel';\nimport { Pressable } from '../Pressable';\nimport { useRadioGroupContext } from './RadioGroupContext';\n\n/* -------------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------------- */\n\n/** Derived from RadioValue - maps boolean to 'checked'/'unchecked' string literals */\ntype RadioValueState = 'checked' | 'unchecked';\n\ninterface RadioProps extends Omit<ViewProps, 'style'>, UniversalRadioProps {\n /** Ref to the underlying View */\n ref?: Ref<View>;\n /** Default checked state for uncontrolled mode */\n defaultChecked?: boolean;\n /** Whether the radio is disabled */\n disabled?: boolean;\n /** Whether the radio is required */\n required?: boolean;\n /**\n * Caps how far the circle, dot, 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 RadioStyleVariant = 'primary' | 'secondary' | 'alert' | 'alert-secondary';\n\nconst VARIANT_ERROR_MAP: Record<RadioVariant, RadioStyleVariant> = {\n primary: 'alert',\n secondary: 'alert-secondary',\n};\n\n/* -------------------------------------------------------------------------- */\n/* Radio Component */\n/* -------------------------------------------------------------------------- */\n\n/**\n * **⚙️ A radio component**\n *\n * @description\n * A radio component allows users to select one option from a set.\n * Unlike checkbox, radio buttons cannot have multiple selected in a group,\n * allowing only one selection at a time.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Radio } from '@yahoo/uds-mobile/Radio';\n *\n * <Radio label=\"Option A\" />\n * <Radio label=\"Option B\" checked={true} onChange={setChecked} />\n * ```\n *\n * @usage\n * - Forms: For selecting a single option from multiple choices\n * - Settings: For toggling between mutually exclusive preferences\n *\n * @accessibility\n * - Sets `accessibilityRole=\"radio\"` automatically\n * - Announces checked/unchecked state\n * - Label is used as accessibility label\n * - Supports `reduceMotion` for users who prefer reduced motion\n *\n * @see {@link Checkbox} for multi-select options\n * @see {@link Switch} for binary toggles\n */\nconst Radio = memo(function Radio({\n // Radio props\n label,\n labelPosition = 'start',\n variant: variantInput,\n size: sizeInput,\n value: valueProp,\n checked: checkedProp,\n hasError: hasErrorProp,\n reduceMotion: reduceMotionProp,\n // Native props\n defaultChecked,\n disabled: disabledProp,\n required,\n maxFontSizeMultiplier,\n onChange,\n ref,\n ...viewProps\n}: RadioProps) {\n const generatedId = useId();\n const uid = `uds-radio-${generatedId}`;\n const radioGroup = useRadioGroupContext();\n\n // One resolved cap governs circle, dot, and label. Android resolves the\n // geometry from the circle's base size on its nonlinear curve.\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n\n const disabled = Boolean(disabledProp || radioGroup?.disabled);\n const hasError = hasErrorProp ?? radioGroup?.hasError;\n const reduceMotion = reduceMotionProp ?? radioGroup?.reduceMotion;\n const size = sizeInput ?? radioGroup?.size ?? 'md';\n const variantProp = variantInput ?? radioGroup?.variant ?? 'primary';\n const value = valueProp ?? '';\n\n /* --------------------------------- State ---------------------------------- */\n const isInRadioGroup = radioGroup !== undefined;\n const isControlled = checkedProp !== undefined;\n const [internalChecked, setInternalChecked] = useState<boolean>(\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 = isInRadioGroup\n ? radioGroup.value === value\n : isControlled\n ? checkedProp\n : internalChecked;\n\n useEffect(() => {\n if (!__DEV__ || !isInRadioGroup || valueProp) {\n return;\n }\n\n console.warn(\n '[UDS Mobile] Radio: A Radio rendered inside RadioGroup requires a unique, non-empty value prop.',\n );\n }, [isInRadioGroup, valueProp]);\n\n /* ------------------------------ Derived Values ---------------------------- */\n const valueState: RadioValueState = useMemo(() => {\n return checked ? 'checked' : 'unchecked';\n }, [checked]);\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 radioAnimatedStyle = useAnimatedStyle(() => ({\n transform: [{ scale: scaleProgress.value }],\n }));\n\n /* -------------------------------- Handlers -------------------------------- */\n const handlePress = useCallback(() => {\n if (disabled) {\n return;\n }\n\n if (isInRadioGroup) {\n if (radioGroup.value === value) {\n return;\n }\n\n radioGroup.setValue(value);\n onChange?.(true);\n return;\n }\n\n const newChecked = !checked;\n\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n\n onChange?.(newChecked);\n }, [disabled, isInRadioGroup, checked, isControlled, onChange, radioGroup, value]);\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: RadioStyleVariant = hasError ? VARIANT_ERROR_MAP[variantProp] : variantProp;\n\n radioStyles.useVariants({\n size,\n variant: styleVariant, // primary, secondary, alert, alert-secondary\n value: valueState, // checked, unchecked\n pressed,\n });\n\n const radioBaseSize = radioStyles.radio.width;\n const fontScaleFactor = useComponentFontScale(\n resolvedMaxFontSizeMultiplier,\n typeof radioBaseSize === 'number' ? radioBaseSize : undefined,\n );\n\n const rootStyle = useMemo(\n () => [radioStyles.root, { opacity: disabled ? 0.5 : 1 }],\n [radioStyles.root, disabled],\n );\n\n const radioBoxStyle = useMemo(() => {\n // The circle grows by the capped factor alongside its label; borderWidth\n // stays fixed (stroke weight doesn't scale in the OS's own controls).\n const { width, height } = radioStyles.radio;\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 }\n : undefined;\n\n return [\n radioStyles.radio,\n scaledBox,\n {\n alignItems: 'center' as const,\n justifyContent: 'center' as const,\n borderRadius: 9999,\n },\n radioAnimatedStyle,\n ];\n }, [radioStyles.radio, fontScaleFactor, radioAnimatedStyle]);\n\n // Inner circle size: fixed 8x8px to match web implementation\n const INNER_CIRCLE_SIZE = 8;\n\n const circleStyle = useMemo(\n () => [\n radioStyles.radioCircle,\n {\n width: Math.round(INNER_CIRCLE_SIZE * fontScaleFactor),\n height: Math.round(INNER_CIRCLE_SIZE * fontScaleFactor),\n borderRadius: 9999,\n },\n ],\n [radioStyles.radioCircle, fontScaleFactor],\n );\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 maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={radioStyles.text}\n />\n );\n }, [label, required, hasError, resolvedMaxFontSizeMultiplier, radioStyles.text]);\n\n const a11yState = useMemo(\n () => ({\n disabled,\n checked,\n }),\n [disabled, checked],\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=\"flex-start\"\n accessibilityRole=\"radio\"\n accessibilityState={a11yState}\n accessibilityLabel={typeof label === 'string' ? label : undefined}\n {...viewProps}\n style={rootStyle}\n >\n <Animated.View style={radioBoxStyle}>{checked && <View style={circleStyle} />}</Animated.View>\n\n {labelContent}\n </Pressable>\n );\n});\n\nRadio.displayName = 'Radio';\n\nexport { Radio, type RadioProps };\n"],"mappings":";;;;;;;;;;;;;;AAiDA,MAAM,oBAA6D;CACjE,SAAS;CACT,WAAW;CACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCD,MAAM,QAAQ,KAAK,SAAS,MAAM,EAEhC,OACA,gBAAgB,SAChB,SAAS,cACT,MAAM,WACN,OAAO,WACP,SAAS,aACT,UAAU,cACV,cAAc,kBAEd,gBACA,UAAU,cACV,UACA,uBACA,UACA,KACA,GAAG,aACU;CAEb,MAAM,MAAM,aADQ,OACgB;CACpC,MAAM,aAAa,sBAAsB;CAIzC,MAAM,gCAAgC,yBAAyB,WAAW,sBAAsB;CAEhG,MAAM,WAAW,QAAQ,gBAAgB,YAAY,SAAS;CAC9D,MAAM,WAAW,gBAAgB,YAAY;CAC7C,MAAM,eAAe,oBAAoB,YAAY;CACrD,MAAM,OAAO,aAAa,YAAY,QAAQ;CAC9C,MAAM,cAAc,gBAAgB,YAAY,WAAW;CAC3D,MAAM,QAAQ,aAAa;CAG3B,MAAM,iBAAiB,eAAe,KAAA;CACtC,MAAM,eAAe,gBAAgB,KAAA;CACrC,MAAM,CAAC,iBAAiB,sBAAsB,SAC5C,eAAe,cAAe,kBAAkB,MACjD;CACD,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAG7C,MAAM,UAAU,iBACZ,WAAW,UAAU,QACrB,eACE,cACA;CAEN,gBAAgB;EACd,IAAI,CAAC,WAAW,CAAC,kBAAkB,WACjC;EAGF,QAAQ,KACN,kGACD;IACA,CAAC,gBAAgB,UAAU,CAAC;CAG/B,MAAM,aAA8B,cAAc;EAChD,OAAO,UAAU,YAAY;IAC5B,CAAC,QAAQ,CAAC;CAGb,MAAM,gBAAgB,CAAC;CAGvB,MAAM,gBAAgB,sBAElB,gBACI,WAAW,UAAU,cAAc,OAAO,cAAc,MAAM,qBAAqB,GACnF,cAAc,MACpB,CAAC,SAAS,cAAc,CACzB;CAED,MAAM,qBAAqB,wBAAwB,EACjD,WAAW,CAAC,EAAE,OAAO,cAAc,OAAO,CAAC,EAC5C,EAAE;CAGH,MAAM,cAAc,kBAAkB;EACpC,IAAI,UACF;EAGF,IAAI,gBAAgB;GAClB,IAAI,WAAW,UAAU,OACvB;GAGF,WAAW,SAAS,MAAM;GAC1B,WAAW,KAAK;GAChB;;EAGF,MAAM,aAAa,CAAC;EAEpB,IAAI,CAAC,cACH,mBAAmB,WAAW;EAGhC,WAAW,WAAW;IACrB;EAAC;EAAU;EAAgB;EAAS;EAAc;EAAU;EAAY;EAAM,CAAC;CAElF,MAAM,gBAAgB,kBAAkB;EACtC,WAAW,KAAK;IACf,EAAE,CAAC;CAEN,MAAM,iBAAiB,kBAAkB;EACvC,WAAW,MAAM;IAChB,EAAE,CAAC;CAIN,MAAM,eAAkC,WAAW,kBAAkB,eAAe;CAEpF,YAAY,YAAY;EACtB;EACA,SAAS;EACT,OAAO;EACP;EACD,CAAC;CAEF,MAAM,gBAAgB,YAAY,MAAM;CACxC,MAAM,kBAAkB,sBACtB,+BACA,OAAO,kBAAkB,WAAW,gBAAgB,KAAA,EACrD;CAED,MAAM,YAAY,cACV,CAAC,YAAY,MAAM,EAAE,SAAS,WAAW,KAAM,GAAG,CAAC,EACzD,CAAC,YAAY,MAAM,SAAS,CAC7B;CAED,MAAM,gBAAgB,cAAc;EAGlC,MAAM,EAAE,OAAO,WAAW,YAAY;EACtC,MAAM,YACJ,oBAAoB,KAAK,OAAO,UAAU,YAAY,OAAO,WAAW,WACpE;GACE,OAAO,KAAK,MAAM,QAAQ,gBAAgB;GAC1C,QAAQ,KAAK,MAAM,SAAS,gBAAgB;GAC7C,GACD,KAAA;EAEN,OAAO;GACL,YAAY;GACZ;GACA;IACE,YAAY;IACZ,gBAAgB;IAChB,cAAc;IACf;GACD;GACD;IACA;EAAC,YAAY;EAAO;EAAiB;EAAmB,CAAC;CAG5D,MAAM,oBAAoB;CAE1B,MAAM,cAAc,cACZ,CACJ,YAAY,aACZ;EACE,OAAO,KAAK,MAAM,oBAAoB,gBAAgB;EACtD,QAAQ,KAAK,MAAM,oBAAoB,gBAAgB;EACvD,cAAc;EACf,CACF,EACD,CAAC,YAAY,aAAa,gBAAgB,CAC3C;CAGD,MAAM,eAAe,cAAc;EACjC,IAAI,CAAC,OACH,OAAO;EAGT,OACE,oBAAC,WAAD;GACE,OAAM;GACN,SAAQ;GACD;GACG;GACV,sBAAsB;GACZ;GACV,uBAAuB;GACvB,OAAO,YAAY;GACnB,CAAA;IAEH;EAAC;EAAO;EAAU;EAAU;EAA+B,YAAY;EAAK,CAAC;CAEhF,MAAM,YAAY,eACT;EACL;EACA;EACD,GACD,CAAC,UAAU,QAAQ,CACpB;CAGD,OACE,qBAACA,aAAD;EACO;EACL,UAAU;EACV,SAAS;EACT,WAAW;EACX,YAAY;EACF;EACV,eAAe,kBAAkB,UAAU,QAAQ;EACnD,YAAW;EACX,WAAU;EACV,mBAAkB;EAClB,oBAAoB;EACpB,oBAAoB,OAAO,UAAU,WAAW,QAAQ,KAAA;EACxD,GAAI;EACJ,OAAO;YAdT,CAgBE,oBAAC,SAAS,MAAV;GAAe,OAAO;aAAgB,WAAW,oBAAC,MAAD,EAAM,OAAO,aAAe,CAAA;GAAiB,CAAA,EAE7F,aACS;;EAEd;AAEF,MAAM,cAAc"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
require("../../_virtual/_rolldown/runtime.cjs");
|
|
4
4
|
const require_components_HStack = require("../HStack.cjs");
|
|
5
|
+
const require_fontScaling_useMaxFontSizeMultiplier = require("../../fontScaling/useMaxFontSizeMultiplier.cjs");
|
|
5
6
|
const require_components_Text = require("../Text.cjs");
|
|
6
7
|
const require_components_InputHelpText = require("../InputHelpText.cjs");
|
|
7
8
|
const require_components_VStack = require("../VStack.cjs");
|
|
@@ -35,8 +36,9 @@ let lodash_es = require("lodash-es");
|
|
|
35
36
|
* </Select>
|
|
36
37
|
* ```
|
|
37
38
|
*/
|
|
38
|
-
const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon, placeholder, size = "md", disabled, required, hasError, readOnly, width = "100%", reduceMotion = false, startIcon, endIcon, value: valueProp, defaultValue = "", onChange, children, testID }) {
|
|
39
|
+
const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon, placeholder, size = "md", disabled, required, hasError, readOnly, width = "100%", maxFontSizeMultiplier, reduceMotion = false, startIcon, endIcon, value: valueProp, defaultValue = "", onChange, children, testID }) {
|
|
39
40
|
const uid = `uds-select-${(0, react.useId)()}`;
|
|
41
|
+
const resolvedMaxFontSizeMultiplier = require_fontScaling_useMaxFontSizeMultiplier.useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
40
42
|
const triggerRef = (0, react.useRef)(null);
|
|
41
43
|
const [triggerRect, setTriggerRect] = (0, react.useState)(null);
|
|
42
44
|
const [highlightedValue, setHighlightedValue] = (0, react.useState)(null);
|
|
@@ -54,16 +56,28 @@ const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon
|
|
|
54
56
|
}
|
|
55
57
|
});
|
|
56
58
|
const registerItem = (0, react.useCallback)((itemValue, itemLabel) => {
|
|
57
|
-
|
|
58
|
-
itemsRef.current.set(itemValue,
|
|
59
|
+
const existing = itemsRef.current.get(itemValue);
|
|
60
|
+
itemsRef.current.set(itemValue, {
|
|
61
|
+
label: itemLabel,
|
|
62
|
+
registrations: (existing?.registrations ?? 0) + 1
|
|
63
|
+
});
|
|
64
|
+
if (existing?.label === itemLabel) return;
|
|
59
65
|
setItemsVersion((version) => version + 1);
|
|
60
66
|
}, []);
|
|
61
67
|
const unregisterItem = (0, react.useCallback)((itemValue) => {
|
|
62
|
-
|
|
68
|
+
const existing = itemsRef.current.get(itemValue);
|
|
69
|
+
if (!existing) return;
|
|
70
|
+
if (existing.registrations > 1) {
|
|
71
|
+
itemsRef.current.set(itemValue, {
|
|
72
|
+
...existing,
|
|
73
|
+
registrations: existing.registrations - 1
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
63
77
|
itemsRef.current.delete(itemValue);
|
|
64
78
|
setItemsVersion((version) => version + 1);
|
|
65
79
|
}, []);
|
|
66
|
-
const getItemLabel = (0, react.useCallback)((itemValue) => itemsRef.current.get(itemValue), []);
|
|
80
|
+
const getItemLabel = (0, react.useCallback)((itemValue) => itemsRef.current.get(itemValue)?.label, []);
|
|
67
81
|
const fieldContext = (0, react.useMemo)(() => ({
|
|
68
82
|
size,
|
|
69
83
|
disabled,
|
|
@@ -73,7 +87,8 @@ const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon
|
|
|
73
87
|
width,
|
|
74
88
|
reduceMotion,
|
|
75
89
|
placeholder,
|
|
76
|
-
uid
|
|
90
|
+
uid,
|
|
91
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier
|
|
77
92
|
}), [
|
|
78
93
|
disabled,
|
|
79
94
|
hasError,
|
|
@@ -81,6 +96,7 @@ const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon
|
|
|
81
96
|
readOnly,
|
|
82
97
|
reduceMotion,
|
|
83
98
|
required,
|
|
99
|
+
resolvedMaxFontSizeMultiplier,
|
|
84
100
|
size,
|
|
85
101
|
uid,
|
|
86
102
|
width
|
|
@@ -133,9 +149,13 @@ const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon
|
|
|
133
149
|
alignItems: "flex-end",
|
|
134
150
|
spacingBottom: "2",
|
|
135
151
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Text.Text, {
|
|
152
|
+
variant: "inherit",
|
|
153
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
136
154
|
style: generated_styles.inputStyles.label,
|
|
137
155
|
children: content
|
|
138
156
|
}), required && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Text.Text, {
|
|
157
|
+
variant: "inherit",
|
|
158
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
139
159
|
style: generated_styles.inputStyles.labelRequired,
|
|
140
160
|
children: "*"
|
|
141
161
|
})]
|
|
@@ -143,6 +163,7 @@ const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon
|
|
|
143
163
|
}, [
|
|
144
164
|
label,
|
|
145
165
|
required,
|
|
166
|
+
resolvedMaxFontSizeMultiplier,
|
|
146
167
|
generated_styles.inputStyles.label,
|
|
147
168
|
generated_styles.inputStyles.labelRequired
|
|
148
169
|
]);
|
|
@@ -157,6 +178,7 @@ const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon
|
|
|
157
178
|
readOnly,
|
|
158
179
|
hasError,
|
|
159
180
|
pressed: open,
|
|
181
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
160
182
|
children: content
|
|
161
183
|
});
|
|
162
184
|
}, [
|
|
@@ -166,6 +188,7 @@ const Select = (0, react.memo)(function Select({ label, helpText, helperTextIcon
|
|
|
166
188
|
helperTextIcon,
|
|
167
189
|
open,
|
|
168
190
|
readOnly,
|
|
191
|
+
resolvedMaxFontSizeMultiplier,
|
|
169
192
|
size,
|
|
170
193
|
valueState
|
|
171
194
|
]);
|
|
@@ -16,6 +16,8 @@ interface SelectProps extends Omit<UniversalSelectProps<IconSlotType>, 'width'>
|
|
|
16
16
|
onChange?: (value: string) => void;
|
|
17
17
|
/** Container width. @default '100%' */
|
|
18
18
|
width?: number | `${number}%` | '100%';
|
|
19
|
+
/** Caps text, icons, and field geometry at the control scale. Set null to remove the cap. @default 2 */
|
|
20
|
+
maxFontSizeMultiplier?: number | null;
|
|
19
21
|
children?: ReactNode;
|
|
20
22
|
testID?: string;
|
|
21
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.cts","names":[],"sources":["../../../src/components/Select/Select.tsx"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"Select.d.cts","names":[],"sources":["../../../src/components/Select/Select.tsx"],"mappings":";;;;;;;UAkBU,WAAA,SAAoB,IAAA,CAAK,oBAAA,CAAqB,YAAA;;EAEtD,WAAA;EAFQ;EAIR,KAAA;;EAEA,YAAA;EANiC;EAQjC,QAAA,IAAY,KAAA;EARgB;EAU5B,KAAA;EAVgC;EAYhC,qBAAA;EACA,QAAA,GAAW,SAAA;EACX,MAAA;AAAA;;;;;;;;;;;;AAAM;;;;;;;;;;;cAyBF,MAAA,EAAM,OAAA,CAAA,oBAAA,CAAA,WAAA"}
|
|
@@ -16,6 +16,8 @@ interface SelectProps extends Omit<UniversalSelectProps<IconSlotType>, 'width'>
|
|
|
16
16
|
onChange?: (value: string) => void;
|
|
17
17
|
/** Container width. @default '100%' */
|
|
18
18
|
width?: number | `${number}%` | '100%';
|
|
19
|
+
/** Caps text, icons, and field geometry at the control scale. Set null to remove the cap. @default 2 */
|
|
20
|
+
maxFontSizeMultiplier?: number | null;
|
|
19
21
|
children?: ReactNode;
|
|
20
22
|
testID?: string;
|
|
21
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","names":[],"sources":["../../../src/components/Select/Select.tsx"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"Select.d.ts","names":[],"sources":["../../../src/components/Select/Select.tsx"],"mappings":";;;;;;;UAkBU,WAAA,SAAoB,IAAA,CAAK,oBAAA,CAAqB,YAAA;;EAEtD,WAAA;EAFQ;EAIR,KAAA;;EAEA,YAAA;EANiC;EAQjC,QAAA,IAAY,KAAA;EARgB;EAU5B,KAAA;EAVgC;EAYhC,qBAAA;EACA,QAAA,GAAW,SAAA;EACX,MAAA;AAAA;;;;;;;;;;;;AAAM;;;;;;;;;;;cAyBF,MAAA,EAAM,OAAA,CAAA,oBAAA,CAAA,WAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
2
|
import { HStack } from "../HStack.js";
|
|
3
|
+
import { useMaxFontSizeMultiplier } from "../../fontScaling/useMaxFontSizeMultiplier.js";
|
|
3
4
|
import { Text } from "../Text.js";
|
|
4
5
|
import { InputHelpText } from "../InputHelpText.js";
|
|
5
6
|
import { VStack } from "../VStack.js";
|
|
@@ -33,8 +34,9 @@ import { isFunction } from "lodash-es";
|
|
|
33
34
|
* </Select>
|
|
34
35
|
* ```
|
|
35
36
|
*/
|
|
36
|
-
const Select = memo(function Select({ label, helpText, helperTextIcon, placeholder, size = "md", disabled, required, hasError, readOnly, width = "100%", reduceMotion = false, startIcon, endIcon, value: valueProp, defaultValue = "", onChange, children, testID }) {
|
|
37
|
+
const Select = memo(function Select({ label, helpText, helperTextIcon, placeholder, size = "md", disabled, required, hasError, readOnly, width = "100%", maxFontSizeMultiplier, reduceMotion = false, startIcon, endIcon, value: valueProp, defaultValue = "", onChange, children, testID }) {
|
|
37
38
|
const uid = `uds-select-${useId()}`;
|
|
39
|
+
const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier("control", maxFontSizeMultiplier);
|
|
38
40
|
const triggerRef = useRef(null);
|
|
39
41
|
const [triggerRect, setTriggerRect] = useState(null);
|
|
40
42
|
const [highlightedValue, setHighlightedValue] = useState(null);
|
|
@@ -52,16 +54,28 @@ const Select = memo(function Select({ label, helpText, helperTextIcon, placehold
|
|
|
52
54
|
}
|
|
53
55
|
});
|
|
54
56
|
const registerItem = useCallback((itemValue, itemLabel) => {
|
|
55
|
-
|
|
56
|
-
itemsRef.current.set(itemValue,
|
|
57
|
+
const existing = itemsRef.current.get(itemValue);
|
|
58
|
+
itemsRef.current.set(itemValue, {
|
|
59
|
+
label: itemLabel,
|
|
60
|
+
registrations: (existing?.registrations ?? 0) + 1
|
|
61
|
+
});
|
|
62
|
+
if (existing?.label === itemLabel) return;
|
|
57
63
|
setItemsVersion((version) => version + 1);
|
|
58
64
|
}, []);
|
|
59
65
|
const unregisterItem = useCallback((itemValue) => {
|
|
60
|
-
|
|
66
|
+
const existing = itemsRef.current.get(itemValue);
|
|
67
|
+
if (!existing) return;
|
|
68
|
+
if (existing.registrations > 1) {
|
|
69
|
+
itemsRef.current.set(itemValue, {
|
|
70
|
+
...existing,
|
|
71
|
+
registrations: existing.registrations - 1
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
61
75
|
itemsRef.current.delete(itemValue);
|
|
62
76
|
setItemsVersion((version) => version + 1);
|
|
63
77
|
}, []);
|
|
64
|
-
const getItemLabel = useCallback((itemValue) => itemsRef.current.get(itemValue), []);
|
|
78
|
+
const getItemLabel = useCallback((itemValue) => itemsRef.current.get(itemValue)?.label, []);
|
|
65
79
|
const fieldContext = useMemo(() => ({
|
|
66
80
|
size,
|
|
67
81
|
disabled,
|
|
@@ -71,7 +85,8 @@ const Select = memo(function Select({ label, helpText, helperTextIcon, placehold
|
|
|
71
85
|
width,
|
|
72
86
|
reduceMotion,
|
|
73
87
|
placeholder,
|
|
74
|
-
uid
|
|
88
|
+
uid,
|
|
89
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier
|
|
75
90
|
}), [
|
|
76
91
|
disabled,
|
|
77
92
|
hasError,
|
|
@@ -79,6 +94,7 @@ const Select = memo(function Select({ label, helpText, helperTextIcon, placehold
|
|
|
79
94
|
readOnly,
|
|
80
95
|
reduceMotion,
|
|
81
96
|
required,
|
|
97
|
+
resolvedMaxFontSizeMultiplier,
|
|
82
98
|
size,
|
|
83
99
|
uid,
|
|
84
100
|
width
|
|
@@ -131,9 +147,13 @@ const Select = memo(function Select({ label, helpText, helperTextIcon, placehold
|
|
|
131
147
|
alignItems: "flex-end",
|
|
132
148
|
spacingBottom: "2",
|
|
133
149
|
children: [/* @__PURE__ */ jsx(Text, {
|
|
150
|
+
variant: "inherit",
|
|
151
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
134
152
|
style: inputStyles.label,
|
|
135
153
|
children: content
|
|
136
154
|
}), required && /* @__PURE__ */ jsx(Text, {
|
|
155
|
+
variant: "inherit",
|
|
156
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
137
157
|
style: inputStyles.labelRequired,
|
|
138
158
|
children: "*"
|
|
139
159
|
})]
|
|
@@ -141,6 +161,7 @@ const Select = memo(function Select({ label, helpText, helperTextIcon, placehold
|
|
|
141
161
|
}, [
|
|
142
162
|
label,
|
|
143
163
|
required,
|
|
164
|
+
resolvedMaxFontSizeMultiplier,
|
|
144
165
|
inputStyles.label,
|
|
145
166
|
inputStyles.labelRequired
|
|
146
167
|
]);
|
|
@@ -155,6 +176,7 @@ const Select = memo(function Select({ label, helpText, helperTextIcon, placehold
|
|
|
155
176
|
readOnly,
|
|
156
177
|
hasError,
|
|
157
178
|
pressed: open,
|
|
179
|
+
maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,
|
|
158
180
|
children: content
|
|
159
181
|
});
|
|
160
182
|
}, [
|
|
@@ -164,6 +186,7 @@ const Select = memo(function Select({ label, helpText, helperTextIcon, placehold
|
|
|
164
186
|
helperTextIcon,
|
|
165
187
|
open,
|
|
166
188
|
readOnly,
|
|
189
|
+
resolvedMaxFontSizeMultiplier,
|
|
167
190
|
size,
|
|
168
191
|
valueState
|
|
169
192
|
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.js","names":[],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import type { UniversalSelectProps } from '@yahoo/uds-types';\nimport { isFunction } from 'lodash-es';\nimport type { ReactNode } from 'react';\nimport { memo, useCallback, useId, useMemo, useRef, useState } from 'react';\nimport type { View } from 'react-native';\n\nimport { inputStyles } from '../../../generated/styles';\nimport { HStack } from '../HStack';\nimport type { IconSlotType } from '../IconSlot';\nimport { InputHelpText } from '../InputHelpText';\nimport { useControllableState } from '../internal/Overlay';\nimport { Text } from '../Text';\nimport { VStack } from '../VStack';\nimport { SelectContext, SelectFieldContext } from './selectContext';\nimport { SelectTrigger } from './SelectTrigger';\nimport type { SelectContextValue, SelectFieldContextValue } from './types';\n\ninterface SelectProps extends Omit<UniversalSelectProps<IconSlotType>, 'width'> {\n /** Placeholder text shown when no value is selected. */\n placeholder?: string;\n /** Selected value for controlled usage. */\n value?: string;\n /** Initial value for uncontrolled usage. @default '' */\n defaultValue?: string;\n /** Called when the selected value changes. */\n onChange?: (value: string) => void;\n /** Container width. @default '100%' */\n width?: number | `${number}%` | '100%';\n children?: ReactNode;\n testID?: string;\n}\n\n/**\n * **⚙️ A composable Select component**\n *\n * @description\n * Select lets users pick one value from a list. Compose with `SelectContent` and\n * `SelectItem`, similar to `Tabs` with `TabList` and `Tab`.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Select, SelectContent, SelectItem } from '@yahoo/uds-mobile/Select';\n *\n * <Select label=\"Country\" placeholder=\"Select a country\" defaultValue=\"us\">\n * <SelectContent>\n * <SelectItem value=\"us\">United States</SelectItem>\n * <SelectItem value=\"ca\">Canada</SelectItem>\n * </SelectContent>\n * </Select>\n * ```\n */\nconst Select = memo(function Select({\n label,\n helpText,\n helperTextIcon,\n placeholder,\n size = 'md',\n disabled,\n required,\n hasError,\n readOnly,\n width = '100%',\n reduceMotion = false,\n startIcon,\n endIcon,\n value: valueProp,\n defaultValue = '',\n onChange,\n children,\n testID,\n}: SelectProps) {\n const generatedId = useId();\n const uid = `uds-select-${generatedId}`;\n const triggerRef = useRef<View | null>(null);\n const [triggerRect, setTriggerRect] = useState<SelectContextValue['triggerRect']>(null);\n const [highlightedValue, setHighlightedValue] = useState<string | null>(null);\n const itemsRef = useRef(new Map<string, string>());\n const [, setItemsVersion] = useState(0);\n\n const [value, setValue] = useControllableState({\n value: valueProp,\n defaultValue,\n onChange,\n });\n\n const [open, setOpen] = useControllableState({\n defaultValue: false,\n onChange: (nextOpen) => {\n if (!nextOpen) {\n setHighlightedValue(null);\n }\n },\n });\n\n const registerItem = useCallback((itemValue: string, itemLabel: string) => {\n if (itemsRef.current.get(itemValue) === itemLabel) {\n return;\n }\n\n itemsRef.current.set(itemValue, itemLabel);\n setItemsVersion((version) => version + 1);\n }, []);\n\n const unregisterItem = useCallback((itemValue: string) => {\n if (!itemsRef.current.has(itemValue)) {\n return;\n }\n\n itemsRef.current.delete(itemValue);\n setItemsVersion((version) => version + 1);\n }, []);\n\n const getItemLabel = useCallback((itemValue: string) => itemsRef.current.get(itemValue), []);\n\n const fieldContext = useMemo<SelectFieldContextValue>(\n () => ({\n size,\n disabled,\n readOnly,\n required,\n hasError,\n width,\n reduceMotion,\n placeholder,\n uid,\n }),\n [disabled, hasError, placeholder, readOnly, reduceMotion, required, size, uid, width],\n );\n\n const contextValue = useMemo<SelectContextValue>(\n () => ({\n value,\n setValue,\n open,\n setOpen,\n triggerRef,\n triggerRect,\n setTriggerRect,\n registerItem,\n unregisterItem,\n getItemLabel,\n highlightedValue,\n setHighlightedValue,\n field: fieldContext,\n reduceMotion,\n }),\n [\n fieldContext,\n getItemLabel,\n highlightedValue,\n open,\n reduceMotion,\n registerItem,\n setOpen,\n setValue,\n triggerRect,\n unregisterItem,\n value,\n ],\n );\n\n const hasValue = value.length > 0;\n const valueState = hasValue ? 'filled' : 'empty';\n\n inputStyles.useVariants({\n size,\n value: valueState,\n pressed: open,\n readonly: readOnly,\n invalid: hasError,\n });\n\n const rootStyle = useMemo(() => [{ width, opacity: disabled ? 0.5 : 1 }], [disabled, width]);\n\n const labelContent = useMemo(() => {\n if (!label) {\n return null;\n }\n\n const content = isFunction(label) ? label() : label;\n return (\n <HStack columnGap=\"1\" alignItems=\"flex-end\" spacingBottom=\"2\">\n <Text style={inputStyles.label}>{content}</Text>\n {required && <Text style={inputStyles.labelRequired}>*</Text>}\n </HStack>\n );\n }, [label, required, inputStyles.label, inputStyles.labelRequired]);\n\n const helpTextContent = useMemo(() => {\n if (!helpText) {\n return null;\n }\n\n const content = isFunction(helpText) ? helpText() : helpText;\n return (\n <InputHelpText\n startIcon={helperTextIcon}\n size={size}\n isFilled={valueState === 'filled'}\n disabled={disabled}\n readOnly={readOnly}\n hasError={hasError}\n pressed={open}\n >\n {content}\n </InputHelpText>\n );\n }, [disabled, hasError, helpText, helperTextIcon, open, readOnly, size, valueState]);\n\n return (\n <SelectContext.Provider value={contextValue}>\n <SelectFieldContext.Provider value={fieldContext}>\n <VStack testID={testID} style={rootStyle}>\n {labelContent}\n\n <SelectTrigger startIcon={startIcon} endIcon={endIcon} />\n\n {helpTextContent}\n\n {children}\n </VStack>\n </SelectFieldContext.Provider>\n </SelectContext.Provider>\n );\n});\n\nSelect.displayName = 'Select';\n\nexport { Select, type SelectProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Select.js","names":[],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import type { UniversalSelectProps } from '@yahoo/uds-types';\nimport { isFunction } from 'lodash-es';\nimport type { ReactNode } from 'react';\nimport { memo, useCallback, useId, useMemo, useRef, useState } from 'react';\nimport type { View } from 'react-native';\n\nimport { inputStyles } from '../../../generated/styles';\nimport { useMaxFontSizeMultiplier } from '../../fontScaling/useMaxFontSizeMultiplier';\nimport { HStack } from '../HStack';\nimport type { IconSlotType } from '../IconSlot';\nimport { InputHelpText } from '../InputHelpText';\nimport { useControllableState } from '../internal/Overlay';\nimport { Text } from '../Text';\nimport { VStack } from '../VStack';\nimport { SelectContext, SelectFieldContext } from './selectContext';\nimport { SelectTrigger } from './SelectTrigger';\nimport type { SelectContextValue, SelectFieldContextValue } from './types';\n\ninterface SelectProps extends Omit<UniversalSelectProps<IconSlotType>, 'width'> {\n /** Placeholder text shown when no value is selected. */\n placeholder?: string;\n /** Selected value for controlled usage. */\n value?: string;\n /** Initial value for uncontrolled usage. @default '' */\n defaultValue?: string;\n /** Called when the selected value changes. */\n onChange?: (value: string) => void;\n /** Container width. @default '100%' */\n width?: number | `${number}%` | '100%';\n /** Caps text, icons, and field geometry at the control scale. Set null to remove the cap. @default 2 */\n maxFontSizeMultiplier?: number | null;\n children?: ReactNode;\n testID?: string;\n}\n\n/**\n * **⚙️ A composable Select component**\n *\n * @description\n * Select lets users pick one value from a list. Compose with `SelectContent` and\n * `SelectItem`, similar to `Tabs` with `TabList` and `Tab`.\n *\n * @category Form\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Select, SelectContent, SelectItem } from '@yahoo/uds-mobile/Select';\n *\n * <Select label=\"Country\" placeholder=\"Select a country\" defaultValue=\"us\">\n * <SelectContent>\n * <SelectItem value=\"us\">United States</SelectItem>\n * <SelectItem value=\"ca\">Canada</SelectItem>\n * </SelectContent>\n * </Select>\n * ```\n */\nconst Select = memo(function Select({\n label,\n helpText,\n helperTextIcon,\n placeholder,\n size = 'md',\n disabled,\n required,\n hasError,\n readOnly,\n width = '100%',\n maxFontSizeMultiplier,\n reduceMotion = false,\n startIcon,\n endIcon,\n value: valueProp,\n defaultValue = '',\n onChange,\n children,\n testID,\n}: SelectProps) {\n const generatedId = useId();\n const uid = `uds-select-${generatedId}`;\n const resolvedMaxFontSizeMultiplier = useMaxFontSizeMultiplier('control', maxFontSizeMultiplier);\n const triggerRef = useRef<View | null>(null);\n const [triggerRect, setTriggerRect] = useState<SelectContextValue['triggerRect']>(null);\n const [highlightedValue, setHighlightedValue] = useState<string | null>(null);\n // Android's portal can briefly overlap the hidden registry item and its visible copy.\n // Count registrations so one copy unmounting does not erase the selected value's label.\n const itemsRef = useRef(new Map<string, { label: string; registrations: number }>());\n const [, setItemsVersion] = useState(0);\n\n const [value, setValue] = useControllableState({\n value: valueProp,\n defaultValue,\n onChange,\n });\n\n const [open, setOpen] = useControllableState({\n defaultValue: false,\n onChange: (nextOpen) => {\n if (!nextOpen) {\n setHighlightedValue(null);\n }\n },\n });\n\n const registerItem = useCallback((itemValue: string, itemLabel: string) => {\n const existing = itemsRef.current.get(itemValue);\n itemsRef.current.set(itemValue, {\n label: itemLabel,\n registrations: (existing?.registrations ?? 0) + 1,\n });\n\n if (existing?.label === itemLabel) {\n return;\n }\n\n setItemsVersion((version) => version + 1);\n }, []);\n\n const unregisterItem = useCallback((itemValue: string) => {\n const existing = itemsRef.current.get(itemValue);\n if (!existing) {\n return;\n }\n\n if (existing.registrations > 1) {\n itemsRef.current.set(itemValue, {\n ...existing,\n registrations: existing.registrations - 1,\n });\n return;\n }\n\n itemsRef.current.delete(itemValue);\n setItemsVersion((version) => version + 1);\n }, []);\n\n const getItemLabel = useCallback(\n (itemValue: string) => itemsRef.current.get(itemValue)?.label,\n [],\n );\n\n const fieldContext = useMemo<SelectFieldContextValue>(\n () => ({\n size,\n disabled,\n readOnly,\n required,\n hasError,\n width,\n reduceMotion,\n placeholder,\n uid,\n maxFontSizeMultiplier: resolvedMaxFontSizeMultiplier,\n }),\n [\n disabled,\n hasError,\n placeholder,\n readOnly,\n reduceMotion,\n required,\n resolvedMaxFontSizeMultiplier,\n size,\n uid,\n width,\n ],\n );\n\n const contextValue = useMemo<SelectContextValue>(\n () => ({\n value,\n setValue,\n open,\n setOpen,\n triggerRef,\n triggerRect,\n setTriggerRect,\n registerItem,\n unregisterItem,\n getItemLabel,\n highlightedValue,\n setHighlightedValue,\n field: fieldContext,\n reduceMotion,\n }),\n [\n fieldContext,\n getItemLabel,\n highlightedValue,\n open,\n reduceMotion,\n registerItem,\n setOpen,\n setValue,\n triggerRect,\n unregisterItem,\n value,\n ],\n );\n\n const hasValue = value.length > 0;\n const valueState = hasValue ? 'filled' : 'empty';\n\n inputStyles.useVariants({\n size,\n value: valueState,\n pressed: open,\n readonly: readOnly,\n invalid: hasError,\n });\n\n const rootStyle = useMemo(() => [{ width, opacity: disabled ? 0.5 : 1 }], [disabled, width]);\n\n const labelContent = useMemo(() => {\n if (!label) {\n return null;\n }\n\n const content = isFunction(label) ? label() : label;\n return (\n <HStack columnGap=\"1\" alignItems=\"flex-end\" spacingBottom=\"2\">\n <Text\n variant=\"inherit\"\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={inputStyles.label}\n >\n {content}\n </Text>\n {required && (\n <Text\n variant=\"inherit\"\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n style={inputStyles.labelRequired}\n >\n *\n </Text>\n )}\n </HStack>\n );\n }, [\n label,\n required,\n resolvedMaxFontSizeMultiplier,\n inputStyles.label,\n inputStyles.labelRequired,\n ]);\n\n const helpTextContent = useMemo(() => {\n if (!helpText) {\n return null;\n }\n\n const content = isFunction(helpText) ? helpText() : helpText;\n return (\n <InputHelpText\n startIcon={helperTextIcon}\n size={size}\n isFilled={valueState === 'filled'}\n disabled={disabled}\n readOnly={readOnly}\n hasError={hasError}\n pressed={open}\n maxFontSizeMultiplier={resolvedMaxFontSizeMultiplier}\n >\n {content}\n </InputHelpText>\n );\n }, [\n disabled,\n hasError,\n helpText,\n helperTextIcon,\n open,\n readOnly,\n resolvedMaxFontSizeMultiplier,\n size,\n valueState,\n ]);\n\n return (\n <SelectContext.Provider value={contextValue}>\n <SelectFieldContext.Provider value={fieldContext}>\n <VStack testID={testID} style={rootStyle}>\n {labelContent}\n\n <SelectTrigger startIcon={startIcon} endIcon={endIcon} />\n\n {helpTextContent}\n\n {children}\n </VStack>\n </SelectFieldContext.Provider>\n </SelectContext.Provider>\n );\n});\n\nSelect.displayName = 'Select';\n\nexport { Select, type SelectProps };\n"],"mappings":"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"}
|
|
@@ -31,7 +31,9 @@ const OFFSCREEN_REGISTRY_STYLE = react_native.StyleSheet.create({ registry: {
|
|
|
31
31
|
* Floating listbox container for {@link SelectItem} options.
|
|
32
32
|
*/
|
|
33
33
|
const SelectContent = (0, react.memo)(function SelectContent({ children, size: _size = "default", variant: _variant = "default", keepOpenOnInteractOutside = false, maxHeight = DEFAULT_MAX_HEIGHT, gutter = DEFAULT_OFFSET, sameWidth = true, style, testID }) {
|
|
34
|
-
const
|
|
34
|
+
const selectContext = require_components_Select_selectContext.useSelectContext();
|
|
35
|
+
const fieldContext = require_components_Select_selectContext.useSelectFieldContext();
|
|
36
|
+
const { open, setOpen, triggerRect, reduceMotion } = selectContext;
|
|
35
37
|
const [contentSize, setContentSize] = (0, react.useState)({
|
|
36
38
|
width: 0,
|
|
37
39
|
height: 0
|
|
@@ -115,28 +117,34 @@ const SelectContent = (0, react.memo)(function SelectContent({ children, size: _
|
|
|
115
117
|
open,
|
|
116
118
|
dismissible: !keepOpenOnInteractOutside,
|
|
117
119
|
onDismiss: dismiss,
|
|
118
|
-
children: () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
120
|
+
children: () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Select_selectContext.SelectContext.Provider, {
|
|
121
|
+
value: selectContext,
|
|
122
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Select_selectContext.SelectFieldContext.Provider, {
|
|
123
|
+
value: fieldContext,
|
|
124
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_reanimated.default.View, {
|
|
125
|
+
testID,
|
|
126
|
+
style: [
|
|
127
|
+
contentStyle,
|
|
128
|
+
animatedStyle,
|
|
129
|
+
{
|
|
130
|
+
overflow: "visible",
|
|
131
|
+
zIndex: 1e3
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
onLayout: handleLayout,
|
|
135
|
+
accessibilityRole: "menu",
|
|
136
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
|
|
137
|
+
style: panelStyle,
|
|
138
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.ScrollView, {
|
|
139
|
+
keyboardShouldPersistTaps: "handled",
|
|
140
|
+
nestedScrollEnabled: true,
|
|
141
|
+
style: { maxHeight },
|
|
142
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_VStack.VStack, {
|
|
143
|
+
alignItems: "stretch",
|
|
144
|
+
justifyContent: "flex-start",
|
|
145
|
+
children
|
|
146
|
+
})
|
|
147
|
+
})
|
|
140
148
|
})
|
|
141
149
|
})
|
|
142
150
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectContent.d.cts","names":[],"sources":["../../../src/components/Select/SelectContent.tsx"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"SelectContent.d.cts","names":[],"sources":["../../../src/components/Select/SelectContent.tsx"],"mappings":";;;;;;;UAwCU,kBAAA;EACR,QAAA,GAAW,SAAA;EACX,IAAA,GAAO,iBAAA;EACP,OAAA,GAAU,oBAAA;EAHgB;EAK1B,yBAAA;EAJW;EAMX,SAAA;EAJU;EAMV,MAAA;EAGQ;EADR,SAAA;EACA,KAAA,GAAQ,SAAA,CAAU,SAAA;EAClB,MAAA;AAAA;;;;;;cAQI,aAAA,EAAa,OAAA,CAAA,oBAAA,CAAA,kBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectContent.d.ts","names":[],"sources":["../../../src/components/Select/SelectContent.tsx"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"SelectContent.d.ts","names":[],"sources":["../../../src/components/Select/SelectContent.tsx"],"mappings":";;;;;;;UAwCU,kBAAA;EACR,QAAA,GAAW,SAAA;EACX,IAAA,GAAO,iBAAA;EACP,OAAA,GAAU,oBAAA;EAHgB;EAK1B,yBAAA;EAJW;EAMX,SAAA;EAJU;EAMV,MAAA;EAGQ;EADR,SAAA;EACA,KAAA,GAAQ,SAAA,CAAU,SAAA;EAClB,MAAA;AAAA;;;;;;cAQI,aAAA,EAAa,OAAA,CAAA,oBAAA,CAAA,kBAAA"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { VStack } from "../VStack.js";
|
|
3
3
|
import { useAnchoredPosition } from "../internal/Overlay/useAnchoredPosition.js";
|
|
4
4
|
import { PopoverPortalLayer } from "../Popover/PopoverPortalLayer.js";
|
|
5
|
-
import { useSelectContext } from "./selectContext.js";
|
|
5
|
+
import { SelectContext, SelectFieldContext, useSelectContext, useSelectFieldContext } from "./selectContext.js";
|
|
6
6
|
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
|
7
7
|
import { ScrollView, StyleSheet, View } from "react-native";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -28,7 +28,9 @@ const OFFSCREEN_REGISTRY_STYLE = StyleSheet.create({ registry: {
|
|
|
28
28
|
* Floating listbox container for {@link SelectItem} options.
|
|
29
29
|
*/
|
|
30
30
|
const SelectContent = memo(function SelectContent({ children, size: _size = "default", variant: _variant = "default", keepOpenOnInteractOutside = false, maxHeight = DEFAULT_MAX_HEIGHT, gutter = DEFAULT_OFFSET, sameWidth = true, style, testID }) {
|
|
31
|
-
const
|
|
31
|
+
const selectContext = useSelectContext();
|
|
32
|
+
const fieldContext = useSelectFieldContext();
|
|
33
|
+
const { open, setOpen, triggerRect, reduceMotion } = selectContext;
|
|
32
34
|
const [contentSize, setContentSize] = useState({
|
|
33
35
|
width: 0,
|
|
34
36
|
height: 0
|
|
@@ -112,28 +114,34 @@ const SelectContent = memo(function SelectContent({ children, size: _size = "def
|
|
|
112
114
|
open,
|
|
113
115
|
dismissible: !keepOpenOnInteractOutside,
|
|
114
116
|
onDismiss: dismiss,
|
|
115
|
-
children: () => /* @__PURE__ */ jsx(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
117
|
+
children: () => /* @__PURE__ */ jsx(SelectContext.Provider, {
|
|
118
|
+
value: selectContext,
|
|
119
|
+
children: /* @__PURE__ */ jsx(SelectFieldContext.Provider, {
|
|
120
|
+
value: fieldContext,
|
|
121
|
+
children: /* @__PURE__ */ jsx(Animated.View, {
|
|
122
|
+
testID,
|
|
123
|
+
style: [
|
|
124
|
+
contentStyle,
|
|
125
|
+
animatedStyle,
|
|
126
|
+
{
|
|
127
|
+
overflow: "visible",
|
|
128
|
+
zIndex: 1e3
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
onLayout: handleLayout,
|
|
132
|
+
accessibilityRole: "menu",
|
|
133
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
134
|
+
style: panelStyle,
|
|
135
|
+
children: /* @__PURE__ */ jsx(ScrollView, {
|
|
136
|
+
keyboardShouldPersistTaps: "handled",
|
|
137
|
+
nestedScrollEnabled: true,
|
|
138
|
+
style: { maxHeight },
|
|
139
|
+
children: /* @__PURE__ */ jsx(VStack, {
|
|
140
|
+
alignItems: "stretch",
|
|
141
|
+
justifyContent: "flex-start",
|
|
142
|
+
children
|
|
143
|
+
})
|
|
144
|
+
})
|
|
137
145
|
})
|
|
138
146
|
})
|
|
139
147
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectContent.js","names":["RNScrollView"],"sources":["../../../src/components/Select/SelectContent.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\nimport type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native';\nimport { ScrollView as RNScrollView, StyleSheet, View } from 'react-native';\nimport Animated, {\n Easing,\n useAnimatedStyle,\n useDerivedValue,\n withTiming,\n} from 'react-native-reanimated';\n\nimport { selectContentStyles } from '../../../generated/styles';\nimport { useAnchoredPosition } from '../internal/Overlay';\nimport { PopoverPortalLayer } from '../Popover/PopoverPortalLayer';\nimport { VStack } from '../VStack';\nimport {
|
|
1
|
+
{"version":3,"file":"SelectContent.js","names":["RNScrollView"],"sources":["../../../src/components/Select/SelectContent.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\nimport type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native';\nimport { ScrollView as RNScrollView, StyleSheet, View } from 'react-native';\nimport Animated, {\n Easing,\n useAnimatedStyle,\n useDerivedValue,\n withTiming,\n} from 'react-native-reanimated';\n\nimport { selectContentStyles } from '../../../generated/styles';\nimport { useAnchoredPosition } from '../internal/Overlay';\nimport { PopoverPortalLayer } from '../Popover/PopoverPortalLayer';\nimport { VStack } from '../VStack';\nimport {\n SelectContext,\n SelectFieldContext,\n useSelectContext,\n useSelectFieldContext,\n} from './selectContext';\nimport type { SelectContentSize, SelectContentVariant } from './types';\n\nconst DEFAULT_OFFSET = 4;\nconst DEFAULT_MAX_HEIGHT = 240;\nconst ANIMATION_DURATION = 200;\n\nconst OFFSCREEN_REGISTRY_STYLE = StyleSheet.create({\n registry: {\n position: 'absolute',\n top: 0,\n left: 0,\n width: 1,\n height: 1,\n opacity: 0,\n overflow: 'hidden',\n zIndex: -1,\n },\n});\n\ninterface SelectContentProps {\n children?: ReactNode;\n size?: SelectContentSize;\n variant?: SelectContentVariant;\n /** When true, the panel stays open when the user taps outside. */\n keepOpenOnInteractOutside?: boolean;\n /** Maximum height of the options list in pixels. @default 240 */\n maxHeight?: number;\n /** Distance between the trigger and the content panel. @default 4 */\n gutter?: number;\n /** When true, the content panel matches the trigger width. @default true */\n sameWidth?: boolean;\n style?: StyleProp<ViewStyle>;\n testID?: string;\n}\n\n/**\n * **▾ Select content panel**\n *\n * Floating listbox container for {@link SelectItem} options.\n */\nconst SelectContent = memo(function SelectContent({\n children,\n size: _size = 'default',\n variant: _variant = 'default',\n keepOpenOnInteractOutside = false,\n maxHeight = DEFAULT_MAX_HEIGHT,\n gutter = DEFAULT_OFFSET,\n sameWidth = true,\n style,\n testID,\n}: SelectContentProps) {\n const selectContext = useSelectContext();\n const fieldContext = useSelectFieldContext();\n const { open, setOpen, triggerRect, reduceMotion } = selectContext;\n const [contentSize, setContentSize] = useState({ width: 0, height: 0 });\n const [shouldRender, setShouldRender] = useState(open);\n\n const dismiss = useCallback(() => {\n if (keepOpenOnInteractOutside) {\n return;\n }\n\n setOpen(false);\n }, [keepOpenOnInteractOutside, setOpen]);\n\n const {\n contentStyle,\n anchorReady,\n maxWidth: positionedMaxWidth,\n } = useAnchoredPosition({\n triggerRect,\n contentSize,\n placement: 'bottom',\n offset: gutter,\n sameWidth,\n width: sameWidth ? 'trigger' : 'content',\n avoidCollisions: true,\n collisionPadding: 12,\n });\n\n const isPositionedOpen = open && anchorReady && contentSize.height > 0;\n const progress = useDerivedValue(\n () =>\n withTiming(isPositionedOpen ? 1 : 0, {\n duration: reduceMotion ? 0 : ANIMATION_DURATION,\n easing: Easing.out(Easing.ease),\n }),\n [isPositionedOpen, reduceMotion],\n );\n\n const animatedStyle = useAnimatedStyle(() => ({\n opacity: progress.value,\n transform: [{ scale: 0.97 + progress.value * 0.03 }, { translateY: (1 - progress.value) * 8 }],\n }));\n\n const handleLayout = useCallback((event: LayoutChangeEvent) => {\n const { width, height } = event.nativeEvent.layout;\n setContentSize({ width, height });\n }, []);\n\n useEffect(() => {\n if (open) {\n setShouldRender(true);\n return;\n }\n\n if (reduceMotion) {\n setShouldRender(false);\n setContentSize({ width: 0, height: 0 });\n return;\n }\n\n const timeout = setTimeout(() => {\n setShouldRender(false);\n setContentSize({ width: 0, height: 0 });\n }, ANIMATION_DURATION);\n\n return () => clearTimeout(timeout);\n }, [open, reduceMotion]);\n\n selectContentStyles.useVariants({});\n\n const panelStyle = useMemo(\n () =>\n StyleSheet.flatten([\n selectContentStyles.root,\n {\n maxHeight,\n maxWidth: positionedMaxWidth > 0 ? positionedMaxWidth : undefined,\n overflow: 'hidden',\n zIndex: 1,\n },\n style,\n ]) as ViewStyle,\n [maxHeight, positionedMaxWidth, selectContentStyles.root, style],\n );\n\n return (\n <>\n {!open ? (\n <View\n accessibilityElementsHidden\n importantForAccessibility=\"no-hide-descendants\"\n pointerEvents=\"none\"\n style={OFFSCREEN_REGISTRY_STYLE.registry}\n >\n {children}\n </View>\n ) : null}\n\n {open && shouldRender ? (\n <PopoverPortalLayer\n open={open}\n dismissible={!keepOpenOnInteractOutside}\n onDismiss={dismiss}\n >\n {() => (\n <SelectContext.Provider value={selectContext}>\n <SelectFieldContext.Provider value={fieldContext}>\n <Animated.View\n testID={testID}\n style={[contentStyle, animatedStyle, { overflow: 'visible', zIndex: 1000 }]}\n onLayout={handleLayout}\n accessibilityRole=\"menu\"\n >\n <View style={panelStyle}>\n <RNScrollView\n keyboardShouldPersistTaps=\"handled\"\n nestedScrollEnabled\n style={{ maxHeight }}\n >\n <VStack alignItems=\"stretch\" justifyContent=\"flex-start\">\n {children}\n </VStack>\n </RNScrollView>\n </View>\n </Animated.View>\n </SelectFieldContext.Provider>\n </SelectContext.Provider>\n )}\n </PopoverPortalLayer>\n ) : null}\n </>\n );\n});\n\nSelectContent.displayName = 'SelectContent';\n\nexport { SelectContent, type SelectContentProps };\n"],"mappings":"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"}
|