@yahoo/uds-mobile 2.9.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -24
- package/dist/components/Avatar.cjs +1 -1
- package/dist/components/Avatar.d.cts +1 -1
- package/dist/components/Avatar.d.ts +1 -1
- package/dist/components/Avatar.js +1 -1
- package/dist/components/Avatar.js.map +1 -1
- package/dist/components/Badge.cjs +1 -1
- package/dist/components/Badge.d.cts +1 -1
- package/dist/components/Badge.d.ts +1 -1
- package/dist/components/Badge.js +1 -1
- package/dist/components/Badge.js.map +1 -1
- package/dist/components/BlurTarget.cjs +2 -1
- package/dist/components/BlurTarget.d.cts +2 -1
- package/dist/components/BlurTarget.d.cts.map +1 -1
- package/dist/components/BlurTarget.d.ts +2 -1
- package/dist/components/BlurTarget.d.ts.map +1 -1
- package/dist/components/BlurTarget.js +2 -1
- package/dist/components/BlurTarget.js.map +1 -1
- package/dist/components/Box.cjs +1 -1
- package/dist/components/Box.d.cts +1 -1
- package/dist/components/Box.d.ts +1 -1
- package/dist/components/Box.js +1 -1
- package/dist/components/Box.js.map +1 -1
- package/dist/components/Button.cjs +1 -1
- package/dist/components/Button.d.cts +1 -1
- package/dist/components/Button.d.ts +1 -1
- package/dist/components/Button.js +1 -1
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Checkbox.cjs +1 -1
- package/dist/components/Checkbox.d.cts +1 -1
- package/dist/components/Checkbox.d.ts +1 -1
- package/dist/components/Checkbox.js +1 -1
- package/dist/components/Checkbox.js.map +1 -1
- package/dist/components/Chip.cjs +1 -1
- package/dist/components/Chip.d.cts +1 -1
- package/dist/components/Chip.d.ts +1 -1
- package/dist/components/Chip.js +1 -1
- package/dist/components/Chip.js.map +1 -1
- package/dist/components/Divider/Divider.cjs +103 -0
- package/dist/components/Divider/Divider.d.cts +50 -0
- package/dist/components/Divider/Divider.d.cts.map +1 -0
- package/dist/components/Divider/Divider.d.ts +50 -0
- package/dist/components/Divider/Divider.d.ts.map +1 -0
- package/dist/components/Divider/Divider.js +103 -0
- package/dist/components/Divider/Divider.js.map +1 -0
- package/dist/components/Divider/DividerLabel.cjs +37 -0
- package/dist/components/Divider/DividerLabel.d.cts +18 -0
- package/dist/components/Divider/DividerLabel.d.cts.map +1 -0
- package/dist/components/Divider/DividerLabel.d.ts +18 -0
- package/dist/components/Divider/DividerLabel.d.ts.map +1 -0
- package/dist/components/Divider/DividerLabel.js +37 -0
- package/dist/components/Divider/DividerLabel.js.map +1 -0
- package/dist/components/Divider/DividerLine.cjs +62 -0
- package/dist/components/Divider/DividerLine.d.cts +19 -0
- package/dist/components/Divider/DividerLine.d.cts.map +1 -0
- package/dist/components/Divider/DividerLine.d.ts +19 -0
- package/dist/components/Divider/DividerLine.d.ts.map +1 -0
- package/dist/components/Divider/DividerLine.js +62 -0
- package/dist/components/Divider/DividerLine.js.map +1 -0
- package/dist/components/Divider/index.cjs +8 -0
- package/dist/components/Divider/index.d.cts +6 -0
- package/dist/components/Divider/index.d.ts +6 -0
- package/dist/components/Divider/index.js +5 -0
- package/dist/components/Divider/types.cjs +1 -0
- package/dist/components/Divider/types.d.cts +35 -0
- package/dist/components/Divider/types.d.cts.map +1 -0
- package/dist/components/Divider/types.d.ts +35 -0
- package/dist/components/Divider/types.d.ts.map +1 -0
- package/dist/components/Divider/types.js +1 -0
- package/dist/components/Divider/utils.cjs +33 -0
- package/dist/components/Divider/utils.d.cts +12 -0
- package/dist/components/Divider/utils.d.cts.map +1 -0
- package/dist/components/Divider/utils.d.ts +12 -0
- package/dist/components/Divider/utils.d.ts.map +1 -0
- package/dist/components/Divider/utils.js +31 -0
- package/dist/components/Divider/utils.js.map +1 -0
- package/dist/components/HStack.cjs +1 -1
- package/dist/components/HStack.d.cts +1 -1
- package/dist/components/HStack.d.ts +1 -1
- package/dist/components/HStack.js +1 -1
- package/dist/components/HStack.js.map +1 -1
- package/dist/components/Icon.cjs +1 -1
- package/dist/components/Icon.d.cts +2 -2
- package/dist/components/Icon.d.ts +2 -2
- package/dist/components/Icon.js +1 -1
- package/dist/components/Icon.js.map +1 -1
- package/dist/components/IconButton.cjs +1 -1
- package/dist/components/IconButton.d.cts +1 -1
- package/dist/components/IconButton.d.ts +1 -1
- package/dist/components/IconButton.js +1 -1
- package/dist/components/IconButton.js.map +1 -1
- package/dist/components/IconSlot.cjs +1 -1
- package/dist/components/IconSlot.d.cts +1 -1
- package/dist/components/IconSlot.d.ts +1 -1
- package/dist/components/IconSlot.js +1 -1
- package/dist/components/IconSlot.js.map +1 -1
- package/dist/components/Image.cjs +1 -1
- package/dist/components/Image.d.cts +1 -1
- package/dist/components/Image.d.ts +1 -1
- package/dist/components/Image.js +1 -1
- package/dist/components/Image.js.map +1 -1
- package/dist/components/Input.cjs +1 -1
- package/dist/components/Input.d.cts +1 -1
- package/dist/components/Input.d.ts +1 -1
- package/dist/components/Input.js +1 -1
- package/dist/components/Input.js.map +1 -1
- package/dist/components/Link.cjs +1 -1
- package/dist/components/Link.d.cts +1 -1
- package/dist/components/Link.d.ts +1 -1
- package/dist/components/Link.js +1 -1
- package/dist/components/Link.js.map +1 -1
- package/dist/components/Pressable.cjs +1 -1
- package/dist/components/Pressable.d.cts +1 -1
- package/dist/components/Pressable.d.ts +1 -1
- package/dist/components/Pressable.js +1 -1
- package/dist/components/Pressable.js.map +1 -1
- package/dist/components/Radio.cjs +1 -1
- package/dist/components/Radio.d.cts +1 -1
- package/dist/components/Radio.d.ts +1 -1
- package/dist/components/Radio.js +1 -1
- package/dist/components/Radio.js.map +1 -1
- package/dist/components/Screen.cjs +1 -1
- package/dist/components/Screen.d.cts +1 -1
- package/dist/components/Screen.d.ts +1 -1
- package/dist/components/Screen.js +1 -1
- package/dist/components/Screen.js.map +1 -1
- package/dist/components/Switch.cjs +1 -1
- package/dist/components/Switch.d.cts +1 -1
- package/dist/components/Switch.d.ts +1 -1
- package/dist/components/Switch.js +1 -1
- package/dist/components/Switch.js.map +1 -1
- package/dist/components/Tabs/Tab.cjs +174 -0
- package/dist/components/Tabs/Tab.d.cts +26 -0
- package/dist/components/Tabs/Tab.d.cts.map +1 -0
- package/dist/components/Tabs/Tab.d.ts +26 -0
- package/dist/components/Tabs/Tab.d.ts.map +1 -0
- package/dist/components/Tabs/Tab.js +174 -0
- package/dist/components/Tabs/Tab.js.map +1 -0
- package/dist/components/Tabs/TabList.cjs +142 -0
- package/dist/components/Tabs/TabList.d.cts +24 -0
- package/dist/components/Tabs/TabList.d.cts.map +1 -0
- package/dist/components/Tabs/TabList.d.ts +24 -0
- package/dist/components/Tabs/TabList.d.ts.map +1 -0
- package/dist/components/Tabs/TabList.js +141 -0
- package/dist/components/Tabs/TabList.js.map +1 -0
- package/dist/components/Tabs/TabPanel.cjs +31 -0
- package/dist/components/Tabs/TabPanel.d.cts +24 -0
- package/dist/components/Tabs/TabPanel.d.cts.map +1 -0
- package/dist/components/Tabs/TabPanel.d.ts +24 -0
- package/dist/components/Tabs/TabPanel.d.ts.map +1 -0
- package/dist/components/Tabs/TabPanel.js +31 -0
- package/dist/components/Tabs/TabPanel.js.map +1 -0
- package/dist/components/Tabs/Tabs.cjs +53 -0
- package/dist/components/Tabs/Tabs.d.cts +35 -0
- package/dist/components/Tabs/Tabs.d.cts.map +1 -0
- package/dist/components/Tabs/Tabs.d.ts +35 -0
- package/dist/components/Tabs/Tabs.d.ts.map +1 -0
- package/dist/components/Tabs/Tabs.js +53 -0
- package/dist/components/Tabs/Tabs.js.map +1 -0
- package/dist/components/Tabs/index.cjs +10 -0
- package/dist/components/Tabs/index.d.cts +13 -0
- package/dist/components/Tabs/index.d.cts.map +1 -0
- package/dist/components/Tabs/index.d.ts +13 -0
- package/dist/components/Tabs/index.d.ts.map +1 -0
- package/dist/components/Tabs/index.js +6 -0
- package/dist/components/Tabs/tabTheme.cjs +29 -0
- package/dist/components/Tabs/tabTheme.d.cts +23 -0
- package/dist/components/Tabs/tabTheme.d.cts.map +1 -0
- package/dist/components/Tabs/tabTheme.d.ts +23 -0
- package/dist/components/Tabs/tabTheme.d.ts.map +1 -0
- package/dist/components/Tabs/tabTheme.js +28 -0
- package/dist/components/Tabs/tabTheme.js.map +1 -0
- package/dist/components/Tabs/tabsContexts.cjs +91 -0
- package/dist/components/Tabs/tabsContexts.d.cts +35 -0
- package/dist/components/Tabs/tabsContexts.d.cts.map +1 -0
- package/dist/components/Tabs/tabsContexts.d.ts +35 -0
- package/dist/components/Tabs/tabsContexts.d.ts.map +1 -0
- package/dist/components/Tabs/tabsContexts.js +87 -0
- package/dist/components/Tabs/tabsContexts.js.map +1 -0
- package/dist/components/Text.cjs +1 -1
- package/dist/components/Text.d.cts +1 -1
- package/dist/components/Text.d.ts +1 -1
- package/dist/components/Text.js +1 -1
- package/dist/components/Text.js.map +1 -1
- package/dist/components/VStack.cjs +1 -1
- package/dist/components/VStack.d.cts +1 -1
- package/dist/components/VStack.d.ts +1 -1
- package/dist/components/VStack.js +1 -1
- package/dist/components/VStack.js.map +1 -1
- package/dist/jest/mocks/styles.cjs +22 -0
- package/dist/jest/mocks/styles.d.cts +4 -2
- package/dist/jest/mocks/styles.d.cts.map +1 -1
- package/dist/jest/mocks/styles.d.ts +4 -2
- package/dist/jest/mocks/styles.d.ts.map +1 -1
- package/dist/jest/mocks/styles.js +21 -1
- package/dist/jest/mocks/styles.js.map +1 -1
- package/dist/types/dist/index.d.cts +63 -2
- package/dist/types/dist/index.d.cts.map +1 -1
- package/dist/types/dist/index.d.ts +63 -2
- package/dist/types/dist/index.d.ts.map +1 -1
- package/fonts/uds-icons.ttf +0 -0
- package/generated/styles.cjs +87 -13
- package/generated/styles.d.ts +58 -0
- package/generated/styles.mjs +87 -13
- package/generated/unistyles.d.ts +62 -9
- package/package.json +21 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
`@yahoo/uds-mobile` brings UDS to React Native. It provides:
|
|
19
19
|
|
|
20
|
-
- **Pre-built Components**: Avatar, Badge, Button, Checkbox, Chip, Icon, IconButton, Image, Input, Link, Radio, Switch, Text, and layout primitives (Box, VStack, HStack, Screen)
|
|
20
|
+
- **Pre-built Components**: Avatar, Badge, Button, Checkbox, Chip, Divider, Icon, IconButton, Image, Input, Link, Radio, Switch, Tabs, Text, and layout primitives (Box, VStack, HStack, Screen)
|
|
21
21
|
- **Theming**: Full light/dark mode support with automatic system preference detection
|
|
22
22
|
- **Design Token Integration**: Colors, typography, spacing, and motion configs synced from UDS tokens
|
|
23
23
|
- **Animations**: Smooth, physics-based animations using Reanimated with motion parity to web
|
|
@@ -327,6 +327,7 @@ const styles = StyleSheet.create((theme) => ({
|
|
|
327
327
|
| `Button` | Interactive button with variants and animations |
|
|
328
328
|
| `Checkbox` | Selectable checkbox with label |
|
|
329
329
|
| `Chip` | Compact elements for filters and selections |
|
|
330
|
+
| `Divider` | Visual separator for grouping content |
|
|
330
331
|
| `HStack` | Horizontal flex container |
|
|
331
332
|
| `Icon` | Icon rendering (font or SVG) |
|
|
332
333
|
| `IconButton` | Icon-only button |
|
|
@@ -656,29 +657,25 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the development workflow, architect
|
|
|
656
657
|
All components export their props types:
|
|
657
658
|
|
|
658
659
|
```typescript
|
|
659
|
-
import type {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
IconSlotProps,
|
|
679
|
-
IconSlotType,
|
|
680
|
-
IconName,
|
|
681
|
-
} from '@yahoo/uds-mobile';
|
|
660
|
+
import type { ButtonProps } from '@yahoo/uds-mobile/Button';
|
|
661
|
+
import type { TextProps } from '@yahoo/uds-mobile/Text';
|
|
662
|
+
import type { AvatarProps } from '@yahoo/uds-mobile/Avatar';
|
|
663
|
+
import type { BadgeProps } from '@yahoo/uds-mobile/Badge';
|
|
664
|
+
import type { CheckboxProps } from '@yahoo/uds-mobile/Checkbox';
|
|
665
|
+
import type { ChipProps } from '@yahoo/uds-mobile/Chip';
|
|
666
|
+
import type { IconProps, IconName } from '@yahoo/uds-mobile/Icon';
|
|
667
|
+
import type { IconButtonProps } from '@yahoo/uds-mobile/IconButton';
|
|
668
|
+
import type { ImageProps } from '@yahoo/uds-mobile/Image';
|
|
669
|
+
import type { InputProps } from '@yahoo/uds-mobile/Input';
|
|
670
|
+
import type { LinkProps } from '@yahoo/uds-mobile/Link';
|
|
671
|
+
import type { RadioProps } from '@yahoo/uds-mobile/Radio';
|
|
672
|
+
import type { SwitchProps } from '@yahoo/uds-mobile/Switch';
|
|
673
|
+
import type { BoxProps } from '@yahoo/uds-mobile/Box';
|
|
674
|
+
import type { VStackProps } from '@yahoo/uds-mobile/VStack';
|
|
675
|
+
import type { HStackProps } from '@yahoo/uds-mobile/HStack';
|
|
676
|
+
import type { ScreenProps } from '@yahoo/uds-mobile/Screen';
|
|
677
|
+
import type { PressableProps } from '@yahoo/uds-mobile/Pressable';
|
|
678
|
+
import type { IconSlotProps, IconSlotType } from '@yahoo/uds-mobile/IconSlot';
|
|
682
679
|
```
|
|
683
680
|
|
|
684
681
|
### Exports
|
|
@@ -691,6 +688,7 @@ import { Box } from '@yahoo/uds-mobile/Box';
|
|
|
691
688
|
import { Button } from '@yahoo/uds-mobile/Button';
|
|
692
689
|
import { Checkbox } from '@yahoo/uds-mobile/Checkbox';
|
|
693
690
|
import { Chip } from '@yahoo/uds-mobile/Chip';
|
|
691
|
+
import { Divider, DividerLabel, DividerLine } from '@yahoo/uds-mobile/Divider';
|
|
694
692
|
import { HStack } from '@yahoo/uds-mobile/HStack';
|
|
695
693
|
import { Icon, iconNames, multicolorIconNames } from '@yahoo/uds-mobile/Icon';
|
|
696
694
|
import { IconButton } from '@yahoo/uds-mobile/IconButton';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar.js","names":["RNImage","Text"],"sources":["../../src/components/Avatar.tsx"],"sourcesContent":["import { forwardRef, useState } from 'react';\nimport type { View, ViewProps } from 'react-native';\nimport { Image as RNImage } from 'react-native';\n\nimport { avatarStyles } from '../../generated/styles';\nimport { Box } from './Box';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\nimport { Text } from './Text';\n\n/** Avatar size options */\ntype AvatarSize = '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';\n\n/** Avatar variant options */\ntype AvatarVariant = 'primary' | 'secondary';\n\n/** Abbreviation strategy for generating initials */\ntype AbbreviationStrategy =\n | 'first'\n | 'last'\n | 'firstAndLast'\n | 'firstTwo'\n | 'firstThree'\n | 'firstOfEach'\n | ((name: string) => string);\n\ninterface AvatarProps extends ViewProps {\n /** Image source URL */\n src?: string;\n /** Alt text for the image, also used for generating initials */\n alt?: string;\n /** Explicit initials to display (overrides auto-generated from alt) */\n fallback?: string;\n /** Size of the avatar @default 'md' */\n size?: AvatarSize;\n /** Variant style @default 'primary' */\n variant?: AvatarVariant;\n /** Custom icon to display when no image or text fallback */\n icon?: IconSlotType;\n /** Strategy for generating initials from name @default 'firstAndLast' */\n abbreviationStrategy?: AbbreviationStrategy;\n}\n\nconst abbreviationStrategies: Record<\n Exclude<AbbreviationStrategy, (name: string) => string>,\n (initials: string[]) => string\n> = {\n first: (initials) => initials[0] ?? '',\n last: (initials) => initials[initials.length - 1] ?? '',\n firstAndLast: (initials) =>\n initials.length === 1 ? (initials[0] ?? '') : `${initials[0]}${initials[initials.length - 1]}`,\n firstTwo: (initials) => initials.slice(0, 2).join(''),\n firstThree: (initials) => initials.slice(0, 3).join(''),\n firstOfEach: (initials) => initials.join(''),\n};\n\n/** Generate initials from a name */\nfunction generateInitials(name?: string, strategy: AbbreviationStrategy = 'firstAndLast'): string {\n if (!name) {\n return '';\n }\n\n if (typeof strategy === 'function') {\n return strategy(name);\n }\n\n const words = name.trim().split(/\\s+/);\n const initials = words.map((word) => word[0]?.toUpperCase() ?? '');\n\n return abbreviationStrategies[strategy](initials);\n}\n\n/**\n * **Avatar component for user representation**\n *\n * @description\n * Displays a user avatar with image, initials fallback, or icon fallback.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Avatar } from '@yahoo/uds-mobile';\n *\n * // With image\n * <Avatar\n * src=\"https://example.com/photo.jpg\"\n * alt=\"Jane Doe\"\n * />\n *\n * // With initials fallback\n * <Avatar alt=\"Jane Doe\" />\n *\n * // With explicit initials\n * <Avatar fallback=\"JD\" />\n *\n * // With custom icon\n * <Avatar icon=\"Person\" variant=\"secondary\" />\n * ```\n *\n * @accessibility\n * - Sets `accessibilityRole=\"image\"` automatically\n * - Uses `alt` prop as accessibility label\n * - Always provide meaningful `alt` text for user identification\n *\n * @see {@link Image} for general image display\n */\nconst Avatar = forwardRef<View, AvatarProps>(function Avatar(\n {\n src,\n alt,\n fallback,\n size = 'md',\n variant = 'primary',\n icon,\n abbreviationStrategy = 'firstAndLast',\n style,\n ...props\n },\n ref,\n) {\n const [imageError, setImageError] = useState(false);\n\n const initials = fallback || generateInitials(alt, abbreviationStrategy);\n\n const hasImage = src && !imageError;\n const hasText = initials.length > 0;\n const showImage = hasImage;\n const showText = !hasImage && hasText;\n const showIcon = !hasImage && !hasText;\n\n avatarStyles.useVariants({\n size,\n ...(showImage && { image: variant }),\n ...(showText && { text: variant }),\n ...(showIcon && { icon: variant }),\n });\n\n return (\n <Box\n ref={ref}\n style={[\n avatarStyles.root,\n { alignItems: 'center', justifyContent: 'center', overflow: 'hidden' },\n style,\n ]}\n accessibilityRole=\"image\"\n accessibilityLabel={alt}\n {...props}\n >\n {showImage && (\n <RNImage\n source={{ uri: src }}\n style={{ width: '100%', height: '100%' }}\n onError={() => setImageError(true)}\n accessibilityLabel={alt}\n />\n )}\n\n {showText && (\n <Text style={avatarStyles.text} numberOfLines={1}>\n {initials}\n </Text>\n )}\n\n {showIcon && <IconSlot icon={icon ?? 'Person'} variant=\"fill\" style={avatarStyles.icon} />}\n </Box>\n );\n});\n\nAvatar.displayName = 'Avatar';\n\nexport { Avatar, type AvatarProps };\n"],"mappings":";;;;;;;;;AA2CA,MAAM,yBAGF;CACF,QAAQ,aAAa,SAAS,MAAM;CACpC,OAAO,aAAa,SAAS,SAAS,SAAS,MAAM;CACrD,eAAe,aACb,SAAS,WAAW,IAAK,SAAS,MAAM,KAAM,GAAG,SAAS,KAAK,SAAS,SAAS,SAAS;CAC5F,WAAW,aAAa,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;CACrD,aAAa,aAAa,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;CACvD,cAAc,aAAa,SAAS,KAAK,GAAG;CAC7C;;AAGD,SAAS,iBAAiB,MAAe,WAAiC,gBAAwB;AAChG,KAAI,CAAC,KACH,QAAO;AAGT,KAAI,OAAO,aAAa,WACtB,QAAO,SAAS,KAAK;CAIvB,MAAM,WADQ,KAAK,MAAM,CAAC,MAAM,MACV,CAAC,KAAK,SAAS,KAAK,IAAI,aAAa,IAAI,GAAG;AAElE,QAAO,uBAAuB,UAAU,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCnD,MAAM,SAAS,WAA8B,SAAS,OACpD,EACE,KACA,KACA,UACA,OAAO,MACP,UAAU,WACV,MACA,uBAAuB,gBACvB,OACA,GAAG,SAEL,KACA;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM;CAEnD,MAAM,WAAW,YAAY,iBAAiB,KAAK,qBAAqB;CAExE,MAAM,WAAW,OAAO,CAAC;CACzB,MAAM,UAAU,SAAS,SAAS;CAClC,MAAM,YAAY;CAClB,MAAM,WAAW,CAAC,YAAY;CAC9B,MAAM,WAAW,CAAC,YAAY,CAAC;AAE/B,cAAa,YAAY;EACvB;EACA,GAAI,aAAa,EAAE,OAAO,SAAS;EACnC,GAAI,YAAY,EAAE,MAAM,SAAS;EACjC,GAAI,YAAY,EAAE,MAAM,SAAS;EAClC,CAAC;AAEF,QACE,qBAAC,KAAD;EACO;EACL,OAAO;GACL,aAAa;GACb;IAAE,YAAY;IAAU,gBAAgB;IAAU,UAAU;IAAU;GACtE;GACD;EACD,mBAAkB;EAClB,oBAAoB;EACpB,GAAI;YATN;GAWG,aACC,oBAACA,OAAD;IACE,QAAQ,EAAE,KAAK,KAAK;IACpB,OAAO;KAAE,OAAO;KAAQ,QAAQ;KAAQ;IACxC,eAAe,cAAc,KAAK;IAClC,oBAAoB;IACpB,CAAA;GAGH,YACC,oBAACC,QAAD;IAAM,OAAO,aAAa;IAAM,eAAe;cAC5C;IACI,CAAA;GAGR,YAAY,oBAAC,UAAD;IAAU,MAAM,QAAQ;IAAU,SAAQ;IAAO,OAAO,aAAa;IAAQ,CAAA;GACtF;;EAER;AAEF,OAAO,cAAc"}
|
|
1
|
+
{"version":3,"file":"Avatar.js","names":["RNImage","Text"],"sources":["../../src/components/Avatar.tsx"],"sourcesContent":["import { forwardRef, useState } from 'react';\nimport type { View, ViewProps } from 'react-native';\nimport { Image as RNImage } from 'react-native';\n\nimport { avatarStyles } from '../../generated/styles';\nimport { Box } from './Box';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\nimport { Text } from './Text';\n\n/** Avatar size options */\ntype AvatarSize = '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';\n\n/** Avatar variant options */\ntype AvatarVariant = 'primary' | 'secondary';\n\n/** Abbreviation strategy for generating initials */\ntype AbbreviationStrategy =\n | 'first'\n | 'last'\n | 'firstAndLast'\n | 'firstTwo'\n | 'firstThree'\n | 'firstOfEach'\n | ((name: string) => string);\n\ninterface AvatarProps extends ViewProps {\n /** Image source URL */\n src?: string;\n /** Alt text for the image, also used for generating initials */\n alt?: string;\n /** Explicit initials to display (overrides auto-generated from alt) */\n fallback?: string;\n /** Size of the avatar @default 'md' */\n size?: AvatarSize;\n /** Variant style @default 'primary' */\n variant?: AvatarVariant;\n /** Custom icon to display when no image or text fallback */\n icon?: IconSlotType;\n /** Strategy for generating initials from name @default 'firstAndLast' */\n abbreviationStrategy?: AbbreviationStrategy;\n}\n\nconst abbreviationStrategies: Record<\n Exclude<AbbreviationStrategy, (name: string) => string>,\n (initials: string[]) => string\n> = {\n first: (initials) => initials[0] ?? '',\n last: (initials) => initials[initials.length - 1] ?? '',\n firstAndLast: (initials) =>\n initials.length === 1 ? (initials[0] ?? '') : `${initials[0]}${initials[initials.length - 1]}`,\n firstTwo: (initials) => initials.slice(0, 2).join(''),\n firstThree: (initials) => initials.slice(0, 3).join(''),\n firstOfEach: (initials) => initials.join(''),\n};\n\n/** Generate initials from a name */\nfunction generateInitials(name?: string, strategy: AbbreviationStrategy = 'firstAndLast'): string {\n if (!name) {\n return '';\n }\n\n if (typeof strategy === 'function') {\n return strategy(name);\n }\n\n const words = name.trim().split(/\\s+/);\n const initials = words.map((word) => word[0]?.toUpperCase() ?? '');\n\n return abbreviationStrategies[strategy](initials);\n}\n\n/**\n * **Avatar component for user representation**\n *\n * @description\n * Displays a user avatar with image, initials fallback, or icon fallback.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Avatar } from '@yahoo/uds-mobile/Avatar';\n *\n * // With image\n * <Avatar\n * src=\"https://example.com/photo.jpg\"\n * alt=\"Jane Doe\"\n * />\n *\n * // With initials fallback\n * <Avatar alt=\"Jane Doe\" />\n *\n * // With explicit initials\n * <Avatar fallback=\"JD\" />\n *\n * // With custom icon\n * <Avatar icon=\"Person\" variant=\"secondary\" />\n * ```\n *\n * @accessibility\n * - Sets `accessibilityRole=\"image\"` automatically\n * - Uses `alt` prop as accessibility label\n * - Always provide meaningful `alt` text for user identification\n *\n * @see {@link Image} for general image display\n */\nconst Avatar = forwardRef<View, AvatarProps>(function Avatar(\n {\n src,\n alt,\n fallback,\n size = 'md',\n variant = 'primary',\n icon,\n abbreviationStrategy = 'firstAndLast',\n style,\n ...props\n },\n ref,\n) {\n const [imageError, setImageError] = useState(false);\n\n const initials = fallback || generateInitials(alt, abbreviationStrategy);\n\n const hasImage = src && !imageError;\n const hasText = initials.length > 0;\n const showImage = hasImage;\n const showText = !hasImage && hasText;\n const showIcon = !hasImage && !hasText;\n\n avatarStyles.useVariants({\n size,\n ...(showImage && { image: variant }),\n ...(showText && { text: variant }),\n ...(showIcon && { icon: variant }),\n });\n\n return (\n <Box\n ref={ref}\n style={[\n avatarStyles.root,\n { alignItems: 'center', justifyContent: 'center', overflow: 'hidden' },\n style,\n ]}\n accessibilityRole=\"image\"\n accessibilityLabel={alt}\n {...props}\n >\n {showImage && (\n <RNImage\n source={{ uri: src }}\n style={{ width: '100%', height: '100%' }}\n onError={() => setImageError(true)}\n accessibilityLabel={alt}\n />\n )}\n\n {showText && (\n <Text style={avatarStyles.text} numberOfLines={1}>\n {initials}\n </Text>\n )}\n\n {showIcon && <IconSlot icon={icon ?? 'Person'} variant=\"fill\" style={avatarStyles.icon} />}\n </Box>\n );\n});\n\nAvatar.displayName = 'Avatar';\n\nexport { Avatar, type AvatarProps };\n"],"mappings":";;;;;;;;;AA2CA,MAAM,yBAGF;CACF,QAAQ,aAAa,SAAS,MAAM;CACpC,OAAO,aAAa,SAAS,SAAS,SAAS,MAAM;CACrD,eAAe,aACb,SAAS,WAAW,IAAK,SAAS,MAAM,KAAM,GAAG,SAAS,KAAK,SAAS,SAAS,SAAS;CAC5F,WAAW,aAAa,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;CACrD,aAAa,aAAa,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;CACvD,cAAc,aAAa,SAAS,KAAK,GAAG;CAC7C;;AAGD,SAAS,iBAAiB,MAAe,WAAiC,gBAAwB;AAChG,KAAI,CAAC,KACH,QAAO;AAGT,KAAI,OAAO,aAAa,WACtB,QAAO,SAAS,KAAK;CAIvB,MAAM,WADQ,KAAK,MAAM,CAAC,MAAM,MACV,CAAC,KAAK,SAAS,KAAK,IAAI,aAAa,IAAI,GAAG;AAElE,QAAO,uBAAuB,UAAU,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCnD,MAAM,SAAS,WAA8B,SAAS,OACpD,EACE,KACA,KACA,UACA,OAAO,MACP,UAAU,WACV,MACA,uBAAuB,gBACvB,OACA,GAAG,SAEL,KACA;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM;CAEnD,MAAM,WAAW,YAAY,iBAAiB,KAAK,qBAAqB;CAExE,MAAM,WAAW,OAAO,CAAC;CACzB,MAAM,UAAU,SAAS,SAAS;CAClC,MAAM,YAAY;CAClB,MAAM,WAAW,CAAC,YAAY;CAC9B,MAAM,WAAW,CAAC,YAAY,CAAC;AAE/B,cAAa,YAAY;EACvB;EACA,GAAI,aAAa,EAAE,OAAO,SAAS;EACnC,GAAI,YAAY,EAAE,MAAM,SAAS;EACjC,GAAI,YAAY,EAAE,MAAM,SAAS;EAClC,CAAC;AAEF,QACE,qBAAC,KAAD;EACO;EACL,OAAO;GACL,aAAa;GACb;IAAE,YAAY;IAAU,gBAAgB;IAAU,UAAU;IAAU;GACtE;GACD;EACD,mBAAkB;EAClB,oBAAoB;EACpB,GAAI;YATN;GAWG,aACC,oBAACA,OAAD;IACE,QAAQ,EAAE,KAAK,KAAK;IACpB,OAAO;KAAE,OAAO;KAAQ,QAAQ;KAAQ;IACxC,eAAe,cAAc,KAAK;IAClC,oBAAoB;IACpB,CAAA;GAGH,YACC,oBAACC,QAAD;IAAM,OAAO,aAAa;IAAM,eAAe;cAC5C;IACI,CAAA;GAGR,YAAY,oBAAC,UAAD;IAAU,MAAM,QAAQ;IAAU,SAAQ;IAAO,OAAO,aAAa;IAAQ,CAAA;GACtF;;EAER;AAEF,OAAO,cAAc"}
|
|
@@ -19,7 +19,7 @@ let generated_styles = require("../../generated/styles");
|
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* ```tsx
|
|
22
|
-
* import { Badge } from '@yahoo/uds-mobile';
|
|
22
|
+
* import { Badge } from '@yahoo/uds-mobile/Badge';
|
|
23
23
|
*
|
|
24
24
|
* <Badge>Label</Badge>
|
|
25
25
|
* <Badge variant="brand" size="sm">New</Badge>
|
package/dist/components/Badge.js
CHANGED
|
@@ -17,7 +17,7 @@ import { badgeStyles } from "../../generated/styles";
|
|
|
17
17
|
*
|
|
18
18
|
* @example
|
|
19
19
|
* ```tsx
|
|
20
|
-
* import { Badge } from '@yahoo/uds-mobile';
|
|
20
|
+
* import { Badge } from '@yahoo/uds-mobile/Badge';
|
|
21
21
|
*
|
|
22
22
|
* <Badge>Label</Badge>
|
|
23
23
|
* <Badge variant="brand" size="sm">New</Badge>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.js","names":[],"sources":["../../src/components/Badge.tsx"],"sourcesContent":["import type { BadgeSize, BadgeVariant } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useMemo } from 'react';\nimport type { View, ViewProps } from 'react-native';\n\nimport { badgeStyles } from '../../generated/styles';\nimport { HStack } from './HStack';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\nimport { Text } from './Text';\n\ninterface BadgeProps extends ViewProps {\n /** The visual style variant of the badge. @default 'primary' */\n variant?: BadgeVariant;\n /** The size of the badge. @default 'md' */\n size?: BadgeSize;\n /** Minimum width of the badge in pixels. */\n minWidth?: number;\n /** Maximum width of the badge in pixels. @default 200 */\n maxWidth?: number;\n /** Icon to display at the start of the badge. */\n startIcon?: IconSlotType;\n /** Icon to display at the end of the badge. */\n endIcon?: IconSlotType;\n /** Override the background color. Use sparingly. */\n dangerouslySetBackgroundColor?: string;\n /** Override the text color. Use sparingly. */\n dangerouslySetColor?: string;\n /** Override the border color. Use sparingly. */\n dangerouslySetBorderColor?: string;\n /** Override the icon color. Use sparingly. */\n dangerouslySetIconColor?: string;\n /** Ref to the underlying View component. */\n ref?: Ref<View>;\n}\n\n/**\n * **A badge component for status indicators**\n *\n * @description\n * Badges show notifications, counts, or status information on navigation items and icons.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Badge } from '@yahoo/uds-mobile';\n *\n * <Badge>Label</Badge>\n * <Badge variant=\"brand\" size=\"sm\">New</Badge>\n * <Badge variant=\"alert\" startIcon=\"Warning\">Error</Badge>\n * ```\n *\n * @accessibility\n * - Badge content is read by screen readers\n * - Use descriptive text for status indicators\n * - Consider `accessibilityLabel` for icon-only badges\n *\n * @see {@link Chip} for interactive tag-like elements\n */\nconst Badge = memo(function Badge({\n variant = 'primary',\n size = 'md',\n minWidth,\n maxWidth = 200,\n startIcon,\n endIcon,\n dangerouslySetBackgroundColor,\n dangerouslySetColor,\n dangerouslySetIconColor,\n dangerouslySetBorderColor,\n children,\n style,\n ref,\n ...rest\n}: BadgeProps) {\n badgeStyles.useVariants({ size, variant });\n const rootStyles = useMemo(() => [badgeStyles.root, style], [style, badgeStyles.root]);\n\n return (\n <HStack\n ref={ref}\n alignItems=\"center\"\n overflow=\"hidden\"\n alignSelf=\"flex-start\"\n maxWidth={maxWidth}\n minWidth={minWidth}\n dangerouslySetBackgroundColor={dangerouslySetBackgroundColor}\n dangerouslySetBorderColor={dangerouslySetBorderColor}\n // Cannot memoize - styles contain theme-reactive values\n style={rootStyles}\n {...rest}\n >\n {startIcon && (\n <IconSlot\n icon={startIcon}\n variant=\"fill\"\n dangerouslySetColor={dangerouslySetIconColor}\n style={badgeStyles.icon}\n />\n )}\n <Text\n numberOfLines={1}\n flexShrink=\"1\"\n dangerouslySetColor={dangerouslySetColor}\n style={badgeStyles.text}\n >\n {children}\n </Text>\n {endIcon && (\n <IconSlot\n icon={endIcon}\n variant=\"fill\"\n dangerouslySetColor={dangerouslySetIconColor}\n style={badgeStyles.icon}\n />\n )}\n </HStack>\n );\n});\n\nBadge.displayName = 'Badge';\n\nexport { Badge, type BadgeProps };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DA,MAAM,QAAQ,KAAK,SAAS,MAAM,EAChC,UAAU,WACV,OAAO,MACP,UACA,WAAW,KACX,WACA,SACA,+BACA,qBACA,yBACA,2BACA,UACA,OACA,KACA,GAAG,QACU;AACb,aAAY,YAAY;EAAE;EAAM;EAAS,CAAC;AAG1C,QACE,qBAAC,QAAD;EACO;EACL,YAAW;EACX,UAAS;EACT,WAAU;EACA;EACA;EACqB;EACJ;EAE3B,OAbe,cAAc,CAAC,YAAY,MAAM,MAAM,EAAE,CAAC,OAAO,YAAY,KAAK,CAahE;EACjB,GAAI;YAXN;GAaG,aACC,oBAAC,UAAD;IACE,MAAM;IACN,SAAQ;IACR,qBAAqB;IACrB,OAAO,YAAY;IACnB,CAAA;GAEJ,oBAAC,MAAD;IACE,eAAe;IACf,YAAW;IACU;IACrB,OAAO,YAAY;IAElB;IACI,CAAA;GACN,WACC,oBAAC,UAAD;IACE,MAAM;IACN,SAAQ;IACR,qBAAqB;IACrB,OAAO,YAAY;IACnB,CAAA;GAEG;;EAEX;AAEF,MAAM,cAAc"}
|
|
1
|
+
{"version":3,"file":"Badge.js","names":[],"sources":["../../src/components/Badge.tsx"],"sourcesContent":["import type { BadgeSize, BadgeVariant } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { memo, useMemo } from 'react';\nimport type { View, ViewProps } from 'react-native';\n\nimport { badgeStyles } from '../../generated/styles';\nimport { HStack } from './HStack';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\nimport { Text } from './Text';\n\ninterface BadgeProps extends ViewProps {\n /** The visual style variant of the badge. @default 'primary' */\n variant?: BadgeVariant;\n /** The size of the badge. @default 'md' */\n size?: BadgeSize;\n /** Minimum width of the badge in pixels. */\n minWidth?: number;\n /** Maximum width of the badge in pixels. @default 200 */\n maxWidth?: number;\n /** Icon to display at the start of the badge. */\n startIcon?: IconSlotType;\n /** Icon to display at the end of the badge. */\n endIcon?: IconSlotType;\n /** Override the background color. Use sparingly. */\n dangerouslySetBackgroundColor?: string;\n /** Override the text color. Use sparingly. */\n dangerouslySetColor?: string;\n /** Override the border color. Use sparingly. */\n dangerouslySetBorderColor?: string;\n /** Override the icon color. Use sparingly. */\n dangerouslySetIconColor?: string;\n /** Ref to the underlying View component. */\n ref?: Ref<View>;\n}\n\n/**\n * **A badge component for status indicators**\n *\n * @description\n * Badges show notifications, counts, or status information on navigation items and icons.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Badge } from '@yahoo/uds-mobile/Badge';\n *\n * <Badge>Label</Badge>\n * <Badge variant=\"brand\" size=\"sm\">New</Badge>\n * <Badge variant=\"alert\" startIcon=\"Warning\">Error</Badge>\n * ```\n *\n * @accessibility\n * - Badge content is read by screen readers\n * - Use descriptive text for status indicators\n * - Consider `accessibilityLabel` for icon-only badges\n *\n * @see {@link Chip} for interactive tag-like elements\n */\nconst Badge = memo(function Badge({\n variant = 'primary',\n size = 'md',\n minWidth,\n maxWidth = 200,\n startIcon,\n endIcon,\n dangerouslySetBackgroundColor,\n dangerouslySetColor,\n dangerouslySetIconColor,\n dangerouslySetBorderColor,\n children,\n style,\n ref,\n ...rest\n}: BadgeProps) {\n badgeStyles.useVariants({ size, variant });\n const rootStyles = useMemo(() => [badgeStyles.root, style], [style, badgeStyles.root]);\n\n return (\n <HStack\n ref={ref}\n alignItems=\"center\"\n overflow=\"hidden\"\n alignSelf=\"flex-start\"\n maxWidth={maxWidth}\n minWidth={minWidth}\n dangerouslySetBackgroundColor={dangerouslySetBackgroundColor}\n dangerouslySetBorderColor={dangerouslySetBorderColor}\n // Cannot memoize - styles contain theme-reactive values\n style={rootStyles}\n {...rest}\n >\n {startIcon && (\n <IconSlot\n icon={startIcon}\n variant=\"fill\"\n dangerouslySetColor={dangerouslySetIconColor}\n style={badgeStyles.icon}\n />\n )}\n <Text\n numberOfLines={1}\n flexShrink=\"1\"\n dangerouslySetColor={dangerouslySetColor}\n style={badgeStyles.text}\n >\n {children}\n </Text>\n {endIcon && (\n <IconSlot\n icon={endIcon}\n variant=\"fill\"\n dangerouslySetColor={dangerouslySetIconColor}\n style={badgeStyles.icon}\n />\n )}\n </HStack>\n );\n});\n\nBadge.displayName = 'Badge';\n\nexport { Badge, type BadgeProps };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DA,MAAM,QAAQ,KAAK,SAAS,MAAM,EAChC,UAAU,WACV,OAAO,MACP,UACA,WAAW,KACX,WACA,SACA,+BACA,qBACA,yBACA,2BACA,UACA,OACA,KACA,GAAG,QACU;AACb,aAAY,YAAY;EAAE;EAAM;EAAS,CAAC;AAG1C,QACE,qBAAC,QAAD;EACO;EACL,YAAW;EACX,UAAS;EACT,WAAU;EACA;EACA;EACqB;EACJ;EAE3B,OAbe,cAAc,CAAC,YAAY,MAAM,MAAM,EAAE,CAAC,OAAO,YAAY,KAAK,CAahE;EACjB,GAAI;YAXN;GAaG,aACC,oBAAC,UAAD;IACE,MAAM;IACN,SAAQ;IACR,qBAAqB;IACrB,OAAO,YAAY;IACnB,CAAA;GAEJ,oBAAC,MAAD;IACE,eAAe;IACf,YAAW;IACU;IACrB,OAAO,YAAY;IAElB;IACI,CAAA;GACN,WACC,oBAAC,UAAD;IACE,MAAM;IACN,SAAQ;IACR,qBAAqB;IACrB,OAAO,YAAY;IACnB,CAAA;GAEG;;EAEX;AAEF,MAAM,cAAc"}
|
|
@@ -44,7 +44,8 @@ function useBlurTargetView() {
|
|
|
44
44
|
* @example
|
|
45
45
|
* ```tsx
|
|
46
46
|
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
47
|
-
* import { Box
|
|
47
|
+
* import { Box } from '@yahoo/uds-mobile/Box';
|
|
48
|
+
import { Text } from '@yahoo/uds-mobile/Text';
|
|
48
49
|
* import { useRef } from 'react';
|
|
49
50
|
* import type { View } from 'react-native';
|
|
50
51
|
*
|
|
@@ -23,7 +23,8 @@ interface BlurTargetProps {
|
|
|
23
23
|
* @example
|
|
24
24
|
* ```tsx
|
|
25
25
|
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
26
|
-
* import { Box
|
|
26
|
+
* import { Box } from '@yahoo/uds-mobile/Box';
|
|
27
|
+
import { Text } from '@yahoo/uds-mobile/Text';
|
|
27
28
|
* import { useRef } from 'react';
|
|
28
29
|
* import type { View } from 'react-native';
|
|
29
30
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlurTarget.d.cts","names":[],"sources":["../../src/components/BlurTarget.tsx"],"mappings":";;;;;;UAkDU,eAAA;EACR,QAAA,EAAU,SAAA;EADF;EAGR,IAAA;EACA,KAAA,GAAQ,SAAA;AAAA;;;;;;;;AAAS
|
|
1
|
+
{"version":3,"file":"BlurTarget.d.cts","names":[],"sources":["../../src/components/BlurTarget.tsx"],"mappings":";;;;;;UAkDU,eAAA;EACR,QAAA,EAAU,SAAA;EADF;EAGR,IAAA;EACA,KAAA,GAAQ,SAAA;AAAA;;;;;;;;AAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCb,UAAA,EAAU,OAAA,CAAA,yBAAA,CAAA,eAAA,GAAA,OAAA,CAAA,aAAA,CAAA,IAAA"}
|
|
@@ -23,7 +23,8 @@ interface BlurTargetProps {
|
|
|
23
23
|
* @example
|
|
24
24
|
* ```tsx
|
|
25
25
|
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
26
|
-
* import { Box
|
|
26
|
+
* import { Box } from '@yahoo/uds-mobile/Box';
|
|
27
|
+
import { Text } from '@yahoo/uds-mobile/Text';
|
|
27
28
|
* import { useRef } from 'react';
|
|
28
29
|
* import type { View } from 'react-native';
|
|
29
30
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlurTarget.d.ts","names":[],"sources":["../../src/components/BlurTarget.tsx"],"mappings":";;;;;;UAkDU,eAAA;EACR,QAAA,EAAU,SAAA;EADF;EAGR,IAAA;EACA,KAAA,GAAQ,SAAA;AAAA;;;;;;;;AAAS
|
|
1
|
+
{"version":3,"file":"BlurTarget.d.ts","names":[],"sources":["../../src/components/BlurTarget.tsx"],"mappings":";;;;;;UAkDU,eAAA;EACR,QAAA,EAAU,SAAA;EADF;EAGR,IAAA;EACA,KAAA,GAAQ,SAAA;AAAA;;;;;;;;AAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCb,UAAA,EAAU,OAAA,CAAA,yBAAA,CAAA,eAAA,GAAA,OAAA,CAAA,aAAA,CAAA,IAAA"}
|
|
@@ -42,7 +42,8 @@ function useBlurTargetView() {
|
|
|
42
42
|
* @example
|
|
43
43
|
* ```tsx
|
|
44
44
|
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
45
|
-
* import { Box
|
|
45
|
+
* import { Box } from '@yahoo/uds-mobile/Box';
|
|
46
|
+
import { Text } from '@yahoo/uds-mobile/Text';
|
|
46
47
|
* import { useRef } from 'react';
|
|
47
48
|
* import type { View } from 'react-native';
|
|
48
49
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlurTarget.js","names":[],"sources":["../../src/components/BlurTarget.tsx"],"sourcesContent":["import type { ComponentType, ReactNode, RefObject } from 'react';\nimport { forwardRef, useEffect, useState } from 'react';\nimport type { StyleProp, ViewStyle } from 'react-native';\nimport { Platform, StyleSheet, View } from 'react-native';\n\n/** Props for expo-blur's BlurTargetView component */\ninterface BlurTargetViewProps {\n children?: ReactNode;\n style?: StyleProp<ViewStyle>;\n ref?: RefObject<View | null>;\n}\n\n// Optional expo-blur dependency - loaded via dynamic import for Metro compatibility\n// Metro can statically analyze import() and will include expo-blur in the bundle if installed\nlet BlurTargetView: ComponentType<BlurTargetViewProps> | null = null;\nlet blurTargetLoadState: 'pending' | 'loaded' | 'failed' = 'pending';\nconst blurTargetLoadListeners: (() => void)[] = [];\n\n// Start loading expo-blur immediately (Metro will bundle it if installed)\nimport('expo-blur')\n .then((mod) => {\n BlurTargetView = mod.BlurTargetView;\n blurTargetLoadState = 'loaded';\n blurTargetLoadListeners.forEach((cb) => cb());\n })\n .catch(() => {\n blurTargetLoadState = 'failed';\n blurTargetLoadListeners.forEach((cb) => cb());\n });\n\n/** Hook to get BlurTargetView component, re-renders when loaded */\nfunction useBlurTargetView() {\n const [, forceUpdate] = useState(0);\n\n useEffect(() => {\n if (blurTargetLoadState === 'pending') {\n const listener = () => forceUpdate((n) => n + 1);\n blurTargetLoadListeners.push(listener);\n return () => {\n const idx = blurTargetLoadListeners.indexOf(listener);\n if (idx >= 0) {\n blurTargetLoadListeners.splice(idx, 1);\n }\n };\n }\n }, []);\n\n return BlurTargetView;\n}\n\ninterface BlurTargetProps {\n children: ReactNode;\n /** Fill the parent container (applies absoluteFill positioning) */\n fill?: boolean;\n style?: ViewStyle;\n}\n\n/**\n * **🔲 Wrapper for content that can be blurred**\n *\n * @description\n * When using blur effects (via the `blur` prop or elevation with blur configured),\n * wrap the content you want to blur in this component and pass its ref to Box's `blurTarget` prop.\n *\n * BlurTarget handles platform differences internally - on iOS it renders children directly,\n * on Android it wraps them in the native view required for blur to work.\n *\n * @example\n * ```tsx\n * import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';\n * import { Box
|
|
1
|
+
{"version":3,"file":"BlurTarget.js","names":[],"sources":["../../src/components/BlurTarget.tsx"],"sourcesContent":["import type { ComponentType, ReactNode, RefObject } from 'react';\nimport { forwardRef, useEffect, useState } from 'react';\nimport type { StyleProp, ViewStyle } from 'react-native';\nimport { Platform, StyleSheet, View } from 'react-native';\n\n/** Props for expo-blur's BlurTargetView component */\ninterface BlurTargetViewProps {\n children?: ReactNode;\n style?: StyleProp<ViewStyle>;\n ref?: RefObject<View | null>;\n}\n\n// Optional expo-blur dependency - loaded via dynamic import for Metro compatibility\n// Metro can statically analyze import() and will include expo-blur in the bundle if installed\nlet BlurTargetView: ComponentType<BlurTargetViewProps> | null = null;\nlet blurTargetLoadState: 'pending' | 'loaded' | 'failed' = 'pending';\nconst blurTargetLoadListeners: (() => void)[] = [];\n\n// Start loading expo-blur immediately (Metro will bundle it if installed)\nimport('expo-blur')\n .then((mod) => {\n BlurTargetView = mod.BlurTargetView;\n blurTargetLoadState = 'loaded';\n blurTargetLoadListeners.forEach((cb) => cb());\n })\n .catch(() => {\n blurTargetLoadState = 'failed';\n blurTargetLoadListeners.forEach((cb) => cb());\n });\n\n/** Hook to get BlurTargetView component, re-renders when loaded */\nfunction useBlurTargetView() {\n const [, forceUpdate] = useState(0);\n\n useEffect(() => {\n if (blurTargetLoadState === 'pending') {\n const listener = () => forceUpdate((n) => n + 1);\n blurTargetLoadListeners.push(listener);\n return () => {\n const idx = blurTargetLoadListeners.indexOf(listener);\n if (idx >= 0) {\n blurTargetLoadListeners.splice(idx, 1);\n }\n };\n }\n }, []);\n\n return BlurTargetView;\n}\n\ninterface BlurTargetProps {\n children: ReactNode;\n /** Fill the parent container (applies absoluteFill positioning) */\n fill?: boolean;\n style?: ViewStyle;\n}\n\n/**\n * **🔲 Wrapper for content that can be blurred**\n *\n * @description\n * When using blur effects (via the `blur` prop or elevation with blur configured),\n * wrap the content you want to blur in this component and pass its ref to Box's `blurTarget` prop.\n *\n * BlurTarget handles platform differences internally - on iOS it renders children directly,\n * on Android it wraps them in the native view required for blur to work.\n *\n * @example\n * ```tsx\n * import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';\n * import { Box } from '@yahoo/uds-mobile/Box';\nimport { Text } from '@yahoo/uds-mobile/Text';\n * import { useRef } from 'react';\n * import type { View } from 'react-native';\n *\n * function MyComponent() {\n * const blurTargetRef = useRef<View>(null);\n *\n * return (\n * <Box flex=\"1\">\n * <BlurTarget ref={blurTargetRef} fill>\n * <Image source={backgroundImage} />\n * </BlurTarget>\n *\n * <Box blur={50} blurTarget={blurTargetRef} borderRadius=\"lg\" spacing=\"4\">\n * <Text>Overlay content</Text>\n * </Box>\n * </Box>\n * );\n * }\n * ```\n *\n * @see {@link https://docs.expo.dev/versions/latest/sdk/blur-view/} expo-blur documentation\n */\nconst BlurTarget = forwardRef<View | null, BlurTargetProps>(function BlurTarget(\n { children, fill, style },\n ref,\n) {\n const BlurTargetViewComponent = useBlurTargetView();\n const resolvedStyle = fill ? [StyleSheet.absoluteFill, style] : style;\n\n // On Android with expo-blur, wrap in BlurTargetView for blur to work\n if (Platform.OS === 'android' && BlurTargetViewComponent) {\n return (\n <BlurTargetViewComponent ref={ref as RefObject<View | null>} style={resolvedStyle}>\n {children}\n </BlurTargetViewComponent>\n );\n }\n\n // On iOS (or if expo-blur not installed), wrap in View if style/ref is provided\n // No special BlurTargetView needed - blur works automatically on iOS\n if (resolvedStyle || ref) {\n return (\n <View ref={ref} style={resolvedStyle}>\n {children}\n </View>\n );\n }\n\n // No wrapper needed if no style/ref\n return children;\n});\n\nBlurTarget.displayName = 'BlurTarget';\n\nexport { BlurTarget, type BlurTargetProps };\n"],"mappings":";;;;;AAcA,IAAI,iBAA4D;AAChE,IAAI,sBAAuD;AAC3D,MAAM,0BAA0C,EAAE;AAGlD,OAAO,aACJ,MAAM,QAAQ;AACb,kBAAiB,IAAI;AACrB,uBAAsB;AACtB,yBAAwB,SAAS,OAAO,IAAI,CAAC;EAC7C,CACD,YAAY;AACX,uBAAsB;AACtB,yBAAwB,SAAS,OAAO,IAAI,CAAC;EAC7C;;AAGJ,SAAS,oBAAoB;CAC3B,MAAM,GAAG,eAAe,SAAS,EAAE;AAEnC,iBAAgB;AACd,MAAI,wBAAwB,WAAW;GACrC,MAAM,iBAAiB,aAAa,MAAM,IAAI,EAAE;AAChD,2BAAwB,KAAK,SAAS;AACtC,gBAAa;IACX,MAAM,MAAM,wBAAwB,QAAQ,SAAS;AACrD,QAAI,OAAO,EACT,yBAAwB,OAAO,KAAK,EAAE;;;IAI3C,EAAE,CAAC;AAEN,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CT,MAAM,aAAa,WAAyC,SAAS,WACnE,EAAE,UAAU,MAAM,SAClB,KACA;CACA,MAAM,0BAA0B,mBAAmB;CACnD,MAAM,gBAAgB,OAAO,CAAC,WAAW,cAAc,MAAM,GAAG;AAGhE,KAAI,SAAS,OAAO,aAAa,wBAC/B,QACE,oBAAC,yBAAD;EAA8B;EAA+B,OAAO;EACjE;EACuB,CAAA;AAM9B,KAAI,iBAAiB,IACnB,QACE,oBAAC,MAAD;EAAW;EAAK,OAAO;EACpB;EACI,CAAA;AAKX,QAAO;EACP;AAEF,WAAW,cAAc"}
|
package/dist/components/Box.cjs
CHANGED
|
@@ -83,7 +83,7 @@ interface BoxProps extends ViewProps, SizeProps {
|
|
|
83
83
|
*
|
|
84
84
|
* @example
|
|
85
85
|
* ```tsx
|
|
86
|
-
* import { Box } from '@yahoo/uds-mobile';
|
|
86
|
+
* import { Box } from '@yahoo/uds-mobile/Box';
|
|
87
87
|
*
|
|
88
88
|
* <Box backgroundColor="primary" spacing="6">
|
|
89
89
|
* Any kind of content can go here!
|
package/dist/components/Box.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ interface BoxProps extends ViewProps, SizeProps {
|
|
|
83
83
|
*
|
|
84
84
|
* @example
|
|
85
85
|
* ```tsx
|
|
86
|
-
* import { Box } from '@yahoo/uds-mobile';
|
|
86
|
+
* import { Box } from '@yahoo/uds-mobile/Box';
|
|
87
87
|
*
|
|
88
88
|
* <Box backgroundColor="primary" spacing="6">
|
|
89
89
|
* Any kind of content can go here!
|
package/dist/components/Box.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Box.js","names":["StyleSheet"],"sources":["../../src/components/Box.tsx"],"sourcesContent":["import type { ElevationLevel } from '@yahoo/uds-types';\nimport type { ComponentType, Ref, RefObject } from 'react';\nimport { memo, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ViewProps } from 'react-native';\nimport { Platform, View } from 'react-native';\n// eslint-disable-next-line uds/no-use-unistyles -- blur intensity is not a style property, requires direct theme access\nimport { StyleSheet, useUnistyles } from 'react-native-unistyles';\n\nimport type { StyleProps } from '../../generated/styles';\nimport { styles } from '../../generated/styles';\nimport type { SizeProps } from '../types';\n\n// Optional expo-blur dependency - loaded via dynamic import for Metro compatibility\n// Metro can statically analyze import() and will include expo-blur in the bundle if installed\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet BlurView: ComponentType<any> | null = null;\nlet blurLoadState: 'pending' | 'loaded' | 'failed' = 'pending';\nconst blurLoadListeners: (() => void)[] = [];\n\n// Start loading expo-blur immediately (Metro will bundle it if installed)\nimport('expo-blur')\n .then((mod) => {\n BlurView = mod.BlurView;\n blurLoadState = 'loaded';\n blurLoadListeners.forEach((cb) => cb());\n })\n .catch(() => {\n blurLoadState = 'failed';\n blurLoadListeners.forEach((cb) => cb());\n });\n\n/** Hook to get BlurView component, re-renders when loaded */\nfunction useBlurView() {\n const [, forceUpdate] = useState(0);\n\n useEffect(() => {\n if (blurLoadState === 'pending') {\n const listener = () => forceUpdate((n) => n + 1);\n blurLoadListeners.push(listener);\n return () => {\n const idx = blurLoadListeners.indexOf(listener);\n if (idx >= 0) {\n blurLoadListeners.splice(idx, 1);\n }\n };\n }\n }, []);\n\n return { BlurView, isLoaded: blurLoadState !== 'pending', isFailed: blurLoadState === 'failed' };\n}\n\ninterface BoxProps extends ViewProps, SizeProps {\n ref?: Ref<View>;\n elevation?: ElevationLevel;\n backgroundColor?: StyleProps['backgroundColor'];\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 alignContent?: StyleProps['alignContent'];\n alignItems?: StyleProps['alignItems'];\n alignSelf?: StyleProps['alignSelf'];\n flex?: StyleProps['flex'];\n flexDirection?: StyleProps['flexDirection'];\n flexGrow?: StyleProps['flexGrow'];\n flexShrink?: StyleProps['flexShrink'];\n flexWrap?: StyleProps['flexWrap'];\n justifyContent?: StyleProps['justifyContent'];\n // flexBasis?: StyleProps['flexBasis'];\n display?: StyleProps['display'];\n overflow?: StyleProps['overflow'];\n // overflowX?: StyleProps['overflowX'];\n // overflowY?: StyleProps['overflowY'];\n // position?: StyleProps['position'];\n spacing?: StyleProps['spacing'];\n spacingHorizontal?: StyleProps['spacingHorizontal'];\n spacingVertical?: StyleProps['spacingVertical'];\n spacingBottom?: StyleProps['spacingBottom'];\n spacingEnd?: StyleProps['spacingEnd'];\n spacingStart?: StyleProps['spacingStart'];\n spacingTop?: StyleProps['spacingTop'];\n offset?: StyleProps['offset'];\n offsetVertical?: StyleProps['offsetVertical'];\n offsetHorizontal?: StyleProps['offsetHorizontal'];\n offsetBottom?: StyleProps['offsetBottom'];\n offsetEnd?: StyleProps['offsetEnd'];\n offsetStart?: StyleProps['offsetStart'];\n offsetTop?: StyleProps['offsetTop'];\n columnGap?: StyleProps['columnGap'];\n rowGap?: StyleProps['rowGap'];\n dropShadow?: StyleProps['dropShadow'];\n insetShadow?: StyleProps['insetShadow'];\n dangerouslySetBackgroundColor?: string;\n dangerouslySetBorderColor?: string;\n /**\n * Manual blur intensity (0-100). When set, renders as a BlurView.\n * Requires `blurTarget` pointing to a BlurTarget ref wrapping the content to blur.\n */\n blur?: number;\n /**\n * Reference to a BlurTarget component wrapping the content to blur.\n * Required when using `blur` prop or elevation with blur configured.\n */\n blurTarget?: RefObject<View | null>;\n}\n\n/**\n * **📦 A layout component that can be used to compose other components**\n *\n * @description\n * The most simple component we ship - a View. But with all the power of the UDS design system.\n * By default, `Box` is a flexbox container. When working with vertical or horizontal layouts,\n * consider using VStack or HStack respectively.\n *\n * @category Layout\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Box } from '@yahoo/uds-mobile';\n *\n * <Box backgroundColor=\"primary\" spacing=\"6\">\n * Any kind of content can go here!\n * </Box>\n * ```\n *\n * @usage\n * - Use as a container to apply padding, shapes, or other styling\n * - Use for creating card components\n * - Use HStack/VStack for directional layouts\n *\n * @see {@link HStack} for horizontal layouts\n * @see {@link VStack} for vertical layouts\n */\nconst Box = memo(function Box({\n // elevation\n elevation,\n // background\n backgroundColor,\n dangerouslySetBackgroundColor,\n // border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n borderColor,\n dangerouslySetBorderColor,\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 alignContent,\n alignItems,\n alignSelf,\n flex,\n flexDirection,\n flexGrow,\n flexShrink,\n flexWrap,\n justifyContent,\n // flexBasis,\n // layout\n display = 'flex',\n overflow,\n // overflowX,\n // overflowY,\n // position,\n // spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n columnGap,\n rowGap,\n // size\n width,\n height,\n minWidth,\n maxWidth,\n minHeight,\n maxHeight,\n // shadow\n dropShadow,\n insetShadow,\n // blur\n blur,\n blurTarget,\n // // nested border radius\n // nestedBorderRadius,\n // nestedBorderRadiusSize = nestedBorderRadius ? borderRadius : undefined,\n // nestedBorderRadiusSpacing = nestedBorderRadius ? spacing : undefined,\n // nestedBorderRadiusWidth = nestedBorderRadius ? borderWidth : undefined,\n // style - extracted to merge with variants\n style,\n ref,\n // rest\n ...props\n}: BoxProps) {\n const { theme, rt } = useUnistyles();\n const {\n BlurView: BlurViewComponent,\n isLoaded: blurIsLoaded,\n isFailed: blurFailed,\n } = useBlurView();\n const elevationAlias = elevation !== undefined ? (`elevation-${elevation}` as const) : undefined;\n\n // Track if blur prop was explicitly set (even to 0) vs derived from elevation\n const blurExplicitlySet = blur !== undefined;\n\n // Get blur intensity from manual blur prop or elevation config\n const blurIntensity = useMemo(() => {\n // Manual blur prop takes precedence (including 0)\n if (blur !== undefined) {\n return blur;\n }\n // Fall back to elevation-based blur\n if (elevation === undefined || !theme.blur) {\n return 0;\n }\n const blurKey = `elevation-${elevation}` as keyof typeof theme.blur;\n return theme.blur[blurKey] ?? 0;\n }, [blur, elevation, theme]);\n\n // Warn in development about blur issues (once per mount)\n const hasWarnedRef = useRef<'none' | 'no-expo-blur' | 'no-blur-target'>('none');\n useEffect(() => {\n if (!__DEV__ || blurIntensity === 0 || !blurIsLoaded) {\n return;\n }\n\n // Warn if expo-blur is not installed\n if (blurFailed && hasWarnedRef.current !== 'no-expo-blur') {\n hasWarnedRef.current = 'no-expo-blur';\n console.warn('[UDS Mobile] Box: Blur effect requested but expo-blur is not installed. ');\n return;\n }\n\n // Warn if blur is used without blurTarget\n if (!blurTarget && hasWarnedRef.current !== 'no-blur-target') {\n hasWarnedRef.current = 'no-blur-target';\n console.warn(\n '[UDS Mobile] Box: Blur effect requires a blurTarget ref. ' +\n 'Wrap the content to blur in <BlurTarget ref={ref}> and pass the ref to blurTarget prop. ' +\n 'See BACKGROUND_BLUR.md for details.',\n );\n }\n }, [blurIntensity, blurTarget, blurIsLoaded, blurFailed]);\n\n const variants = {\n // background\n backgroundColor: backgroundColor ?? elevationAlias,\n // border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n // nestedBorderRadius,\n // nestedBorderRadiusSize,\n // nestedBorderRadiusSpacing,\n // nestedBorderRadiusWidth,\n borderColor: borderColor ?? elevationAlias,\n borderStartColor,\n borderEndColor,\n borderTopColor,\n borderBottomColor,\n borderWidth: borderWidth ?? elevationAlias,\n borderVerticalWidth,\n borderHorizontalWidth,\n borderStartWidth,\n borderEndWidth,\n borderTopWidth,\n borderBottomWidth,\n // flex\n alignContent,\n alignItems,\n alignSelf,\n flex,\n flexDirection,\n flexGrow,\n flexShrink,\n flexWrap,\n justifyContent,\n // flexBasis,\n // layout\n display,\n overflow,\n // overflowX,\n // overflowY,\n // position,\n // spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n columnGap,\n rowGap,\n // rest\n };\n\n styles.useVariants(variants);\n\n const effectiveDropShadow = dropShadow ?? elevationAlias;\n const shadowStyle =\n effectiveDropShadow || insetShadow\n ? shadowSheet.shadow(effectiveDropShadow, insetShadow)\n : undefined;\n\n // styles.foundation must be in deps - it returns a new reference when variants change\n const boxStyles = useMemo(\n () => [\n dangerouslySetBackgroundColor\n ? { backgroundColor: dangerouslySetBackgroundColor }\n : undefined,\n dangerouslySetBorderColor ? { borderColor: dangerouslySetBorderColor } : undefined,\n width ? { width } : undefined,\n height ? { height } : undefined,\n minWidth ? { minWidth } : undefined,\n maxWidth ? { maxWidth } : undefined,\n minHeight ? { minHeight } : undefined,\n maxHeight ? { maxHeight } : undefined,\n shadowStyle,\n styles.foundation,\n style,\n ],\n [\n dangerouslySetBackgroundColor,\n dangerouslySetBorderColor,\n width,\n height,\n minWidth,\n maxWidth,\n minHeight,\n maxHeight,\n shadowStyle,\n styles.foundation,\n style,\n ],\n );\n\n // Merge variant styles with user-provided style prop\n // User styles come last so they can override variant styles if needed\n\n // If blur is configured (manual or via elevation), render BlurView instead of View\n // Note: On Android, blur requires BlurTarget setup by the developer\n // See BACKGROUND_BLUR.md for Android-specific instructions\n // When blur prop is explicitly set (even to 0), use BlurView so blur=0 is transparent, not solid\n const shouldUseBlurView = BlurViewComponent && (blurIntensity > 0 || blurExplicitlySet);\n if (shouldUseBlurView) {\n const isAndroid = Platform.OS === 'android';\n // Match blur tint to the app's theme (from unistyles runtime)\n const blurTint = rt.themeName === 'dark' ? 'dark' : 'light';\n\n // On iOS, BlurView provides its own frosted background via the tint prop.\n // We must NOT apply an opaque backgroundColor or it will cover the blur effect.\n // On Android, the blur is applied to the blurTarget, so backgroundColor is fine.\n const blurStyles = isAndroid\n ? boxStyles\n : [\n // Exclude backgroundColor for iOS - the blur tint provides the visual background\n dangerouslySetBorderColor ? { borderColor: dangerouslySetBorderColor } : undefined,\n width ? { width } : undefined,\n height ? { height } : undefined,\n minWidth ? { minWidth } : undefined,\n maxWidth ? { maxWidth } : undefined,\n minHeight ? { minHeight } : undefined,\n maxHeight ? { maxHeight } : undefined,\n shadowStyle,\n // Filter out backgroundColor from foundation styles\n {\n ...styles.foundation,\n backgroundColor: undefined,\n },\n // Also filter backgroundColor from user style if provided (handles both object and array styles)\n style\n ? Array.isArray(style)\n ? style.map((s) =>\n s && typeof s === 'object' ? { ...s, backgroundColor: undefined } : s,\n )\n : typeof style === 'object'\n ? { ...style, backgroundColor: undefined }\n : style\n : undefined,\n ];\n\n // Scale Android intensity to keep tint overlay subtle (Android overlays become\n // too opaque at high intensities). 0.4 scale maps intensity=100 to effective ~40.\n const effectiveIntensity = isAndroid ? Math.min(blurIntensity * 0.4, 40) : blurIntensity;\n\n return (\n <BlurViewComponent\n ref={ref}\n intensity={effectiveIntensity}\n tint={blurTint}\n blurTarget={isAndroid ? blurTarget : undefined}\n blurMethod={isAndroid ? 'dimezisBlurView' : undefined}\n style={blurStyles}\n {...props}\n >\n {props.children}\n </BlurViewComponent>\n );\n }\n\n // Fallback to regular View (blur not available or not requested)\n\n return <View ref={ref} style={boxStyles} {...props} />;\n});\n\nBox.displayName = 'Box';\n\n/**\n * Dynamic shadow stylesheet that merges drop and inset shadows into a single\n * boxShadow CSS string. Theme-reactive so shadows update on color mode change.\n */\nconst shadowSheet = StyleSheet.create((theme) => ({\n shadow: (drop?: string, inset?: string) => {\n const parts = [\n drop ? theme.boxShadow.drop[drop as keyof typeof theme.boxShadow.drop] : '',\n inset ? theme.boxShadow.inset[inset as keyof typeof theme.boxShadow.inset] : '',\n ].filter(Boolean);\n return parts.length > 0 ? { boxShadow: parts.join(', ') } : {};\n },\n}));\n\nexport { Box, type BoxProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Box.js","names":["StyleSheet"],"sources":["../../src/components/Box.tsx"],"sourcesContent":["import type { ElevationLevel } from '@yahoo/uds-types';\nimport type { ComponentType, Ref, RefObject } from 'react';\nimport { memo, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ViewProps } from 'react-native';\nimport { Platform, View } from 'react-native';\n// eslint-disable-next-line uds/no-use-unistyles -- blur intensity is not a style property, requires direct theme access\nimport { StyleSheet, useUnistyles } from 'react-native-unistyles';\n\nimport type { StyleProps } from '../../generated/styles';\nimport { styles } from '../../generated/styles';\nimport type { SizeProps } from '../types';\n\n// Optional expo-blur dependency - loaded via dynamic import for Metro compatibility\n// Metro can statically analyze import() and will include expo-blur in the bundle if installed\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet BlurView: ComponentType<any> | null = null;\nlet blurLoadState: 'pending' | 'loaded' | 'failed' = 'pending';\nconst blurLoadListeners: (() => void)[] = [];\n\n// Start loading expo-blur immediately (Metro will bundle it if installed)\nimport('expo-blur')\n .then((mod) => {\n BlurView = mod.BlurView;\n blurLoadState = 'loaded';\n blurLoadListeners.forEach((cb) => cb());\n })\n .catch(() => {\n blurLoadState = 'failed';\n blurLoadListeners.forEach((cb) => cb());\n });\n\n/** Hook to get BlurView component, re-renders when loaded */\nfunction useBlurView() {\n const [, forceUpdate] = useState(0);\n\n useEffect(() => {\n if (blurLoadState === 'pending') {\n const listener = () => forceUpdate((n) => n + 1);\n blurLoadListeners.push(listener);\n return () => {\n const idx = blurLoadListeners.indexOf(listener);\n if (idx >= 0) {\n blurLoadListeners.splice(idx, 1);\n }\n };\n }\n }, []);\n\n return { BlurView, isLoaded: blurLoadState !== 'pending', isFailed: blurLoadState === 'failed' };\n}\n\ninterface BoxProps extends ViewProps, SizeProps {\n ref?: Ref<View>;\n elevation?: ElevationLevel;\n backgroundColor?: StyleProps['backgroundColor'];\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 alignContent?: StyleProps['alignContent'];\n alignItems?: StyleProps['alignItems'];\n alignSelf?: StyleProps['alignSelf'];\n flex?: StyleProps['flex'];\n flexDirection?: StyleProps['flexDirection'];\n flexGrow?: StyleProps['flexGrow'];\n flexShrink?: StyleProps['flexShrink'];\n flexWrap?: StyleProps['flexWrap'];\n justifyContent?: StyleProps['justifyContent'];\n // flexBasis?: StyleProps['flexBasis'];\n display?: StyleProps['display'];\n overflow?: StyleProps['overflow'];\n // overflowX?: StyleProps['overflowX'];\n // overflowY?: StyleProps['overflowY'];\n // position?: StyleProps['position'];\n spacing?: StyleProps['spacing'];\n spacingHorizontal?: StyleProps['spacingHorizontal'];\n spacingVertical?: StyleProps['spacingVertical'];\n spacingBottom?: StyleProps['spacingBottom'];\n spacingEnd?: StyleProps['spacingEnd'];\n spacingStart?: StyleProps['spacingStart'];\n spacingTop?: StyleProps['spacingTop'];\n offset?: StyleProps['offset'];\n offsetVertical?: StyleProps['offsetVertical'];\n offsetHorizontal?: StyleProps['offsetHorizontal'];\n offsetBottom?: StyleProps['offsetBottom'];\n offsetEnd?: StyleProps['offsetEnd'];\n offsetStart?: StyleProps['offsetStart'];\n offsetTop?: StyleProps['offsetTop'];\n columnGap?: StyleProps['columnGap'];\n rowGap?: StyleProps['rowGap'];\n dropShadow?: StyleProps['dropShadow'];\n insetShadow?: StyleProps['insetShadow'];\n dangerouslySetBackgroundColor?: string;\n dangerouslySetBorderColor?: string;\n /**\n * Manual blur intensity (0-100). When set, renders as a BlurView.\n * Requires `blurTarget` pointing to a BlurTarget ref wrapping the content to blur.\n */\n blur?: number;\n /**\n * Reference to a BlurTarget component wrapping the content to blur.\n * Required when using `blur` prop or elevation with blur configured.\n */\n blurTarget?: RefObject<View | null>;\n}\n\n/**\n * **📦 A layout component that can be used to compose other components**\n *\n * @description\n * The most simple component we ship - a View. But with all the power of the UDS design system.\n * By default, `Box` is a flexbox container. When working with vertical or horizontal layouts,\n * consider using VStack or HStack respectively.\n *\n * @category Layout\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Box } from '@yahoo/uds-mobile/Box';\n *\n * <Box backgroundColor=\"primary\" spacing=\"6\">\n * Any kind of content can go here!\n * </Box>\n * ```\n *\n * @usage\n * - Use as a container to apply padding, shapes, or other styling\n * - Use for creating card components\n * - Use HStack/VStack for directional layouts\n *\n * @see {@link HStack} for horizontal layouts\n * @see {@link VStack} for vertical layouts\n */\nconst Box = memo(function Box({\n // elevation\n elevation,\n // background\n backgroundColor,\n dangerouslySetBackgroundColor,\n // border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n borderColor,\n dangerouslySetBorderColor,\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 alignContent,\n alignItems,\n alignSelf,\n flex,\n flexDirection,\n flexGrow,\n flexShrink,\n flexWrap,\n justifyContent,\n // flexBasis,\n // layout\n display = 'flex',\n overflow,\n // overflowX,\n // overflowY,\n // position,\n // spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n columnGap,\n rowGap,\n // size\n width,\n height,\n minWidth,\n maxWidth,\n minHeight,\n maxHeight,\n // shadow\n dropShadow,\n insetShadow,\n // blur\n blur,\n blurTarget,\n // // nested border radius\n // nestedBorderRadius,\n // nestedBorderRadiusSize = nestedBorderRadius ? borderRadius : undefined,\n // nestedBorderRadiusSpacing = nestedBorderRadius ? spacing : undefined,\n // nestedBorderRadiusWidth = nestedBorderRadius ? borderWidth : undefined,\n // style - extracted to merge with variants\n style,\n ref,\n // rest\n ...props\n}: BoxProps) {\n const { theme, rt } = useUnistyles();\n const {\n BlurView: BlurViewComponent,\n isLoaded: blurIsLoaded,\n isFailed: blurFailed,\n } = useBlurView();\n const elevationAlias = elevation !== undefined ? (`elevation-${elevation}` as const) : undefined;\n\n // Track if blur prop was explicitly set (even to 0) vs derived from elevation\n const blurExplicitlySet = blur !== undefined;\n\n // Get blur intensity from manual blur prop or elevation config\n const blurIntensity = useMemo(() => {\n // Manual blur prop takes precedence (including 0)\n if (blur !== undefined) {\n return blur;\n }\n // Fall back to elevation-based blur\n if (elevation === undefined || !theme.blur) {\n return 0;\n }\n const blurKey = `elevation-${elevation}` as keyof typeof theme.blur;\n return theme.blur[blurKey] ?? 0;\n }, [blur, elevation, theme]);\n\n // Warn in development about blur issues (once per mount)\n const hasWarnedRef = useRef<'none' | 'no-expo-blur' | 'no-blur-target'>('none');\n useEffect(() => {\n if (!__DEV__ || blurIntensity === 0 || !blurIsLoaded) {\n return;\n }\n\n // Warn if expo-blur is not installed\n if (blurFailed && hasWarnedRef.current !== 'no-expo-blur') {\n hasWarnedRef.current = 'no-expo-blur';\n console.warn('[UDS Mobile] Box: Blur effect requested but expo-blur is not installed. ');\n return;\n }\n\n // Warn if blur is used without blurTarget\n if (!blurTarget && hasWarnedRef.current !== 'no-blur-target') {\n hasWarnedRef.current = 'no-blur-target';\n console.warn(\n '[UDS Mobile] Box: Blur effect requires a blurTarget ref. ' +\n 'Wrap the content to blur in <BlurTarget ref={ref}> and pass the ref to blurTarget prop. ' +\n 'See BACKGROUND_BLUR.md for details.',\n );\n }\n }, [blurIntensity, blurTarget, blurIsLoaded, blurFailed]);\n\n const variants = {\n // background\n backgroundColor: backgroundColor ?? elevationAlias,\n // border\n borderRadius,\n borderTopStartRadius,\n borderTopEndRadius,\n borderBottomStartRadius,\n borderBottomEndRadius,\n // nestedBorderRadius,\n // nestedBorderRadiusSize,\n // nestedBorderRadiusSpacing,\n // nestedBorderRadiusWidth,\n borderColor: borderColor ?? elevationAlias,\n borderStartColor,\n borderEndColor,\n borderTopColor,\n borderBottomColor,\n borderWidth: borderWidth ?? elevationAlias,\n borderVerticalWidth,\n borderHorizontalWidth,\n borderStartWidth,\n borderEndWidth,\n borderTopWidth,\n borderBottomWidth,\n // flex\n alignContent,\n alignItems,\n alignSelf,\n flex,\n flexDirection,\n flexGrow,\n flexShrink,\n flexWrap,\n justifyContent,\n // flexBasis,\n // layout\n display,\n overflow,\n // overflowX,\n // overflowY,\n // position,\n // spacing\n spacing,\n spacingHorizontal,\n spacingVertical,\n spacingBottom,\n spacingEnd,\n spacingStart,\n spacingTop,\n offset,\n offsetVertical,\n offsetHorizontal,\n offsetBottom,\n offsetEnd,\n offsetStart,\n offsetTop,\n columnGap,\n rowGap,\n // rest\n };\n\n styles.useVariants(variants);\n\n const effectiveDropShadow = dropShadow ?? elevationAlias;\n const shadowStyle =\n effectiveDropShadow || insetShadow\n ? shadowSheet.shadow(effectiveDropShadow, insetShadow)\n : undefined;\n\n // styles.foundation must be in deps - it returns a new reference when variants change\n const boxStyles = useMemo(\n () => [\n dangerouslySetBackgroundColor\n ? { backgroundColor: dangerouslySetBackgroundColor }\n : undefined,\n dangerouslySetBorderColor ? { borderColor: dangerouslySetBorderColor } : undefined,\n width ? { width } : undefined,\n height ? { height } : undefined,\n minWidth ? { minWidth } : undefined,\n maxWidth ? { maxWidth } : undefined,\n minHeight ? { minHeight } : undefined,\n maxHeight ? { maxHeight } : undefined,\n shadowStyle,\n styles.foundation,\n style,\n ],\n [\n dangerouslySetBackgroundColor,\n dangerouslySetBorderColor,\n width,\n height,\n minWidth,\n maxWidth,\n minHeight,\n maxHeight,\n shadowStyle,\n styles.foundation,\n style,\n ],\n );\n\n // Merge variant styles with user-provided style prop\n // User styles come last so they can override variant styles if needed\n\n // If blur is configured (manual or via elevation), render BlurView instead of View\n // Note: On Android, blur requires BlurTarget setup by the developer\n // See BACKGROUND_BLUR.md for Android-specific instructions\n // When blur prop is explicitly set (even to 0), use BlurView so blur=0 is transparent, not solid\n const shouldUseBlurView = BlurViewComponent && (blurIntensity > 0 || blurExplicitlySet);\n if (shouldUseBlurView) {\n const isAndroid = Platform.OS === 'android';\n // Match blur tint to the app's theme (from unistyles runtime)\n const blurTint = rt.themeName === 'dark' ? 'dark' : 'light';\n\n // On iOS, BlurView provides its own frosted background via the tint prop.\n // We must NOT apply an opaque backgroundColor or it will cover the blur effect.\n // On Android, the blur is applied to the blurTarget, so backgroundColor is fine.\n const blurStyles = isAndroid\n ? boxStyles\n : [\n // Exclude backgroundColor for iOS - the blur tint provides the visual background\n dangerouslySetBorderColor ? { borderColor: dangerouslySetBorderColor } : undefined,\n width ? { width } : undefined,\n height ? { height } : undefined,\n minWidth ? { minWidth } : undefined,\n maxWidth ? { maxWidth } : undefined,\n minHeight ? { minHeight } : undefined,\n maxHeight ? { maxHeight } : undefined,\n shadowStyle,\n // Filter out backgroundColor from foundation styles\n {\n ...styles.foundation,\n backgroundColor: undefined,\n },\n // Also filter backgroundColor from user style if provided (handles both object and array styles)\n style\n ? Array.isArray(style)\n ? style.map((s) =>\n s && typeof s === 'object' ? { ...s, backgroundColor: undefined } : s,\n )\n : typeof style === 'object'\n ? { ...style, backgroundColor: undefined }\n : style\n : undefined,\n ];\n\n // Scale Android intensity to keep tint overlay subtle (Android overlays become\n // too opaque at high intensities). 0.4 scale maps intensity=100 to effective ~40.\n const effectiveIntensity = isAndroid ? Math.min(blurIntensity * 0.4, 40) : blurIntensity;\n\n return (\n <BlurViewComponent\n ref={ref}\n intensity={effectiveIntensity}\n tint={blurTint}\n blurTarget={isAndroid ? blurTarget : undefined}\n blurMethod={isAndroid ? 'dimezisBlurView' : undefined}\n style={blurStyles}\n {...props}\n >\n {props.children}\n </BlurViewComponent>\n );\n }\n\n // Fallback to regular View (blur not available or not requested)\n\n return <View ref={ref} style={boxStyles} {...props} />;\n});\n\nBox.displayName = 'Box';\n\n/**\n * Dynamic shadow stylesheet that merges drop and inset shadows into a single\n * boxShadow CSS string. Theme-reactive so shadows update on color mode change.\n */\nconst shadowSheet = StyleSheet.create((theme) => ({\n shadow: (drop?: string, inset?: string) => {\n const parts = [\n drop ? theme.boxShadow.drop[drop as keyof typeof theme.boxShadow.drop] : '',\n inset ? theme.boxShadow.inset[inset as keyof typeof theme.boxShadow.inset] : '',\n ].filter(Boolean);\n return parts.length > 0 ? { boxShadow: parts.join(', ') } : {};\n },\n}));\n\nexport { Box, type BoxProps };\n"],"mappings":"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"}
|
|
@@ -64,7 +64,7 @@ function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
|
64
64
|
*
|
|
65
65
|
* @example
|
|
66
66
|
* ```tsx
|
|
67
|
-
* import { Button } from '@yahoo/uds-mobile';
|
|
67
|
+
* import { Button } from '@yahoo/uds-mobile/Button';
|
|
68
68
|
*
|
|
69
69
|
* <Button onPress={() => console.log('pressed')}>Save</Button>
|
|
70
70
|
* <Button variant="secondary">Cancel</Button>
|
|
@@ -48,7 +48,7 @@ interface ButtonProps extends Omit<PressableProps$1, 'children' | 'disabled'> {
|
|
|
48
48
|
*
|
|
49
49
|
* @example
|
|
50
50
|
* ```tsx
|
|
51
|
-
* import { Button } from '@yahoo/uds-mobile';
|
|
51
|
+
* import { Button } from '@yahoo/uds-mobile/Button';
|
|
52
52
|
*
|
|
53
53
|
* <Button onPress={() => console.log('pressed')}>Save</Button>
|
|
54
54
|
* <Button variant="secondary">Cancel</Button>
|
|
@@ -48,7 +48,7 @@ interface ButtonProps extends Omit<PressableProps$1, 'children' | 'disabled'> {
|
|
|
48
48
|
*
|
|
49
49
|
* @example
|
|
50
50
|
* ```tsx
|
|
51
|
-
* import { Button } from '@yahoo/uds-mobile';
|
|
51
|
+
* import { Button } from '@yahoo/uds-mobile/Button';
|
|
52
52
|
*
|
|
53
53
|
* <Button onPress={() => console.log('pressed')}>Save</Button>
|
|
54
54
|
* <Button variant="secondary">Cancel</Button>
|
|
@@ -61,7 +61,7 @@ function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
|
61
61
|
*
|
|
62
62
|
* @example
|
|
63
63
|
* ```tsx
|
|
64
|
-
* import { Button } from '@yahoo/uds-mobile';
|
|
64
|
+
* import { Button } from '@yahoo/uds-mobile/Button';
|
|
65
65
|
*
|
|
66
66
|
* <Button onPress={() => console.log('pressed')}>Save</Button>
|
|
67
67
|
* <Button variant="secondary">Cancel</Button>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","names":["Text"],"sources":["../../src/components/Button.tsx"],"sourcesContent":["import type { ButtonSize, ButtonVariantFlat, IconSize, IconVariant } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { isValidElement, memo, useCallback, useMemo, useState } from 'react';\nimport type { View } from 'react-native';\nimport { ActivityIndicator } from 'react-native';\nimport Animated, {\n Easing,\n interpolate,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n withSpring,\n withTiming,\n} from 'react-native-reanimated';\nimport { useAnimatedTheme } from 'react-native-unistyles/reanimated';\n\nimport { buttonStyles } from '../../generated/styles';\nimport { BUTTON_SPRING_CONFIG, SCALE_EFFECTS } from '../motion';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\nimport type { PressableProps } from './Pressable';\nimport { AnimatedPressable } from './Pressable';\nimport { Text } from './Text';\n\n/* -------------------------------------------------------------------------- */\n/* Animation Helpers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Interpolates a boxShadow string by scaling the alpha of all colors.\n * This allows smooth fade-in/out of shadows.\n */\nfunction interpolateShadowAlpha(shadow: string | undefined, alpha: number): string {\n 'worklet';\n if (!shadow) {\n return '';\n }\n if (alpha >= 1) {\n return shadow;\n }\n if (alpha <= 0) {\n return '';\n }\n\n return shadow.replace(/rgba\\(([^,]+),\\s*([^,]+),\\s*([^,]+),\\s*([^)]+)\\)/g, (_, r, g, b, a) => {\n const newAlpha = parseFloat(a) * alpha;\n return `rgba(${r}, ${g}, ${b}, ${newAlpha.toFixed(3)})`;\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Animated Icon Slot */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Animated wrapper for icon/loading content.\n * Matches web Button icon animation: scale 0.7→1, opacity 0→1, width 0→auto\n * Uses staggered animation: opacity waits until halfway through width animation.\n */\nfunction AnimatedIconSlot({\n children,\n visible,\n iconSize,\n gap,\n}: {\n children: React.ReactNode;\n visible: boolean;\n iconSize: number;\n gap: number;\n}) {\n // Use useDerivedValue instead of useEffect + useSharedValue\n // This is the idiomatic Reanimated pattern for deriving animated values from React state\n const progress = useDerivedValue(\n () => withSpring(visible ? 1 : 0, BUTTON_SPRING_CONFIG),\n [visible],\n );\n\n const animatedStyle = useAnimatedStyle(() => {\n // Total width includes icon + gap when visible\n const totalWidth = iconSize + gap;\n const width = interpolate(progress.value, [0, 1], [0, totalWidth]);\n\n // Staggered animation: opacity starts at 50% of width animation\n // On enter: width expands first, then icon fades in\n // On exit: icon fades out first, then width collapses\n const opacity = interpolate(progress.value, [0.5, 1], [0, 1], 'clamp');\n const scale = interpolate(progress.value, [0.5, 1], [0.7, 1], 'clamp');\n\n return {\n width,\n opacity,\n transform: [{ scale }],\n overflow: 'hidden' as const,\n };\n });\n\n return <Animated.View style={animatedStyle}>{children}</Animated.View>;\n}\n\n// function LoadingIcon({ size, variant }: { size: ButtonSize, variant: ButtonVariantFlat }) {\n// const { theme } = useUnistyles();\n// const themeKey = `buttonVariant${variantToCapitalMap[variant]}IconRest` as const;\n// const iconSize = theme.components.buttonSizeLgIconRest.fontSize;\n// return <ActivityIndicator size={iconSize} color={theme.colors.text.primary} />;\n// }\n\n/* -------------------------------------------------------------------------- */\n/* Button Props */\n/* -------------------------------------------------------------------------- */\n\ninterface ButtonProps extends Omit<PressableProps, 'children' | 'disabled'> {\n /** The visual style variant of the button @default 'primary' */\n variant?: ButtonVariantFlat;\n /** The size of the button @default 'md' */\n size?: ButtonSize;\n /** The icon style variant @default 'outline' */\n iconVariant?: IconVariant;\n /** Icon displayed before the button label */\n startIcon?: IconSlotType;\n /** Icon displayed after the button label */\n endIcon?: IconSlotType;\n /** Shows a loading spinner and disables the button */\n loading?: boolean;\n /** Whether the button is disabled */\n disabled?: boolean;\n /** Button label content */\n children?: React.ReactNode;\n /**\n * Disable motion effects (scale on press, icon animations)\n * @default false\n */\n disableEffects?: boolean;\n /** Ref to the underlying View */\n ref?: Ref<View>;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Button Component */\n/* -------------------------------------------------------------------------- */\n\n/**\n * **🖲️ A button element that can be used to trigger an action**\n *\n * @description\n * A button is a fundamental component used to trigger an action or event.\n * Buttons are interactive elements that users can click, tap, or otherwise\n * engage with to submit forms, open dialogues, or perform any other interaction.\n *\n * Features animated scale effect on press and smooth icon transitions matching\n * the web UDS Button behavior.\n *\n * @category Interactive\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Button } from '@yahoo/uds-mobile';\n *\n * <Button onPress={() => console.log('pressed')}>Save</Button>\n * <Button variant=\"secondary\">Cancel</Button>\n * <Button startIcon=\"Add\" variant=\"brand\">Add Item</Button>\n * <Button loading>Saving...</Button>\n * ```\n *\n * @accessibility\n * - Sets `accessibilityRole=\"button\"` automatically\n * - Announces loading state to screen readers\n * - Use `accessibilityLabel` for icon-only buttons\n *\n * @see {@link IconButton} for icon-only buttons\n * @see {@link Link} for navigation actions\n */\nconst Button = memo(function Button({\n variant = 'primary',\n size = 'md',\n iconVariant = 'outline',\n startIcon,\n endIcon,\n loading,\n disabled,\n width: _width,\n children,\n style,\n accessibilityLabel,\n accessibilityHint,\n disableEffects = false,\n onPressIn,\n onPressOut,\n ref,\n ...props\n}: ButtonProps) {\n const shouldAnimate = !disableEffects;\n\n /* --------------------------------- State ---------------------------------- */\n const [pressed, setPressed] = useState(false);\n\n buttonStyles.useVariants({ size, variant, disabled, pressed });\n\n // Get gap and icon size from current variant styles\n const buttonGap = buttonStyles.root.gap;\n const iconSize = buttonStyles.icon.fontSize;\n\n // Get animated theme for boxShadow (useAnimatedVariantColor doesn't support non-color props)\n const animatedTheme = useAnimatedTheme();\n\n /* ------------------------------- Animation -------------------------------- */\n const scale = useSharedValue<number>(SCALE_EFFECTS.none);\n\n const handlePressIn = useCallback(\n (event: Parameters<NonNullable<PressableProps['onPressIn']>>[0]) => {\n setPressed(true);\n if (shouldAnimate) {\n scale.value = withSpring(SCALE_EFFECTS.down, BUTTON_SPRING_CONFIG);\n }\n onPressIn?.(event);\n },\n [shouldAnimate, scale, onPressIn],\n );\n\n const handlePressOut = useCallback(\n (event: Parameters<NonNullable<PressableProps['onPressOut']>>[0]) => {\n setPressed(false);\n if (shouldAnimate) {\n scale.value = withSpring(SCALE_EFFECTS.none, BUTTON_SPRING_CONFIG);\n }\n onPressOut?.(event);\n },\n [shouldAnimate, scale, onPressOut],\n );\n\n /* -------------------------------- Content --------------------------------- */\n const childrenNode =\n children &&\n (isValidElement(children) ? (\n children\n ) : (\n <Text numberOfLines={1} textAlign=\"center\" style={buttonStyles.text}>\n {children}\n </Text>\n ));\n\n const a11yState = useMemo(() => ({ disabled, busy: loading }), [disabled, loading]);\n\n /* --------------------------------- Styles --------------------------------- */\n // Animate pressed state for shadow (0 = rest, 1 = pressed)\n const pressProgress = useDerivedValue(\n () => withTiming(pressed ? 1 : 0, { duration: 220, easing: Easing.bezier(0, 0, 0.2, 1) }),\n [pressed],\n );\n\n // Animate using Unistyles' variant color system + boxShadow from theme\n const animatedStyles = useAnimatedStyle(() => {\n // Get boxShadow from theme using flattened path (no camelCase conversion needed!)\n const components = animatedTheme.value.components;\n const buttonVariantPath = `button/variant/${variant}/root/pressed` as const;\n const shadowPressed = components[buttonVariantPath]?.boxShadow;\n\n return {\n transform: [{ scale: scale.value }],\n // Only animate shadow if the theme defines one for this variant\n ...(shadowPressed && {\n boxShadow: interpolateShadowAlpha(shadowPressed, pressProgress.value),\n }),\n };\n });\n\n // Determine what should be visible in start slot\n const showLoading = !!loading;\n const showStartIcon = !!startIcon && !loading;\n const showEndIcon = !!endIcon && !loading;\n\n const iconSizeToken = (buttonStyles.icon.iconSizeToken as IconSize) ?? 'sm';\n\n // Start slot: either loading spinner or start icon\n const startContent = (\n <AnimatedIconSlot visible={showLoading || showStartIcon} iconSize={iconSize} gap={buttonGap}>\n {showLoading ? (\n <ActivityIndicator size={buttonStyles.icon.fontSize} color={buttonStyles.icon.color} />\n ) : (\n <IconSlot\n icon={startIcon}\n size={iconSizeToken}\n variant={iconVariant}\n style={buttonStyles.icon}\n />\n )}\n </AnimatedIconSlot>\n );\n\n // End slot: only end icon (no loading here)\n const endContent = (\n <AnimatedIconSlot visible={showEndIcon} iconSize={iconSize} gap={buttonGap}>\n <IconSlot\n icon={endIcon}\n size={iconSizeToken}\n variant={iconVariant}\n style={buttonStyles.icon}\n />\n </AnimatedIconSlot>\n );\n\n const rootStyles = useMemo(\n () => [\n buttonStyles.root,\n animatedStyles,\n typeof style === 'function' ? style({ pressed }) : style,\n ],\n [buttonStyles.root, animatedStyles, style, pressed],\n );\n\n /* --------------------------------- Render --------------------------------- */\n return (\n <AnimatedPressable\n ref={ref}\n disabled={disabled}\n onPressIn={handlePressIn}\n onPressOut={handlePressOut}\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"center\"\n overflow=\"hidden\"\n accessibilityLabel={loading ? `${accessibilityLabel ?? ''}, loading` : accessibilityLabel}\n accessibilityHint={accessibilityHint}\n accessibilityRole=\"button\"\n accessibilityState={a11yState}\n alignContent=\"center\"\n style={rootStyles}\n {...props}\n >\n {startContent}\n {childrenNode}\n {endContent}\n </AnimatedPressable>\n );\n});\n\nButton.displayName = 'Button';\n\nexport { Button, type ButtonProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Button.js","names":["Text"],"sources":["../../src/components/Button.tsx"],"sourcesContent":["import type { ButtonSize, ButtonVariantFlat, IconSize, IconVariant } from '@yahoo/uds-types';\nimport type { Ref } from 'react';\nimport { isValidElement, memo, useCallback, useMemo, useState } from 'react';\nimport type { View } from 'react-native';\nimport { ActivityIndicator } from 'react-native';\nimport Animated, {\n Easing,\n interpolate,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n withSpring,\n withTiming,\n} from 'react-native-reanimated';\nimport { useAnimatedTheme } from 'react-native-unistyles/reanimated';\n\nimport { buttonStyles } from '../../generated/styles';\nimport { BUTTON_SPRING_CONFIG, SCALE_EFFECTS } from '../motion';\nimport type { IconSlotType } from './IconSlot';\nimport { IconSlot } from './IconSlot';\nimport type { PressableProps } from './Pressable';\nimport { AnimatedPressable } from './Pressable';\nimport { Text } from './Text';\n\n/* -------------------------------------------------------------------------- */\n/* Animation Helpers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Interpolates a boxShadow string by scaling the alpha of all colors.\n * This allows smooth fade-in/out of shadows.\n */\nfunction interpolateShadowAlpha(shadow: string | undefined, alpha: number): string {\n 'worklet';\n if (!shadow) {\n return '';\n }\n if (alpha >= 1) {\n return shadow;\n }\n if (alpha <= 0) {\n return '';\n }\n\n return shadow.replace(/rgba\\(([^,]+),\\s*([^,]+),\\s*([^,]+),\\s*([^)]+)\\)/g, (_, r, g, b, a) => {\n const newAlpha = parseFloat(a) * alpha;\n return `rgba(${r}, ${g}, ${b}, ${newAlpha.toFixed(3)})`;\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Animated Icon Slot */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Animated wrapper for icon/loading content.\n * Matches web Button icon animation: scale 0.7→1, opacity 0→1, width 0→auto\n * Uses staggered animation: opacity waits until halfway through width animation.\n */\nfunction AnimatedIconSlot({\n children,\n visible,\n iconSize,\n gap,\n}: {\n children: React.ReactNode;\n visible: boolean;\n iconSize: number;\n gap: number;\n}) {\n // Use useDerivedValue instead of useEffect + useSharedValue\n // This is the idiomatic Reanimated pattern for deriving animated values from React state\n const progress = useDerivedValue(\n () => withSpring(visible ? 1 : 0, BUTTON_SPRING_CONFIG),\n [visible],\n );\n\n const animatedStyle = useAnimatedStyle(() => {\n // Total width includes icon + gap when visible\n const totalWidth = iconSize + gap;\n const width = interpolate(progress.value, [0, 1], [0, totalWidth]);\n\n // Staggered animation: opacity starts at 50% of width animation\n // On enter: width expands first, then icon fades in\n // On exit: icon fades out first, then width collapses\n const opacity = interpolate(progress.value, [0.5, 1], [0, 1], 'clamp');\n const scale = interpolate(progress.value, [0.5, 1], [0.7, 1], 'clamp');\n\n return {\n width,\n opacity,\n transform: [{ scale }],\n overflow: 'hidden' as const,\n };\n });\n\n return <Animated.View style={animatedStyle}>{children}</Animated.View>;\n}\n\n// function LoadingIcon({ size, variant }: { size: ButtonSize, variant: ButtonVariantFlat }) {\n// const { theme } = useUnistyles();\n// const themeKey = `buttonVariant${variantToCapitalMap[variant]}IconRest` as const;\n// const iconSize = theme.components.buttonSizeLgIconRest.fontSize;\n// return <ActivityIndicator size={iconSize} color={theme.colors.text.primary} />;\n// }\n\n/* -------------------------------------------------------------------------- */\n/* Button Props */\n/* -------------------------------------------------------------------------- */\n\ninterface ButtonProps extends Omit<PressableProps, 'children' | 'disabled'> {\n /** The visual style variant of the button @default 'primary' */\n variant?: ButtonVariantFlat;\n /** The size of the button @default 'md' */\n size?: ButtonSize;\n /** The icon style variant @default 'outline' */\n iconVariant?: IconVariant;\n /** Icon displayed before the button label */\n startIcon?: IconSlotType;\n /** Icon displayed after the button label */\n endIcon?: IconSlotType;\n /** Shows a loading spinner and disables the button */\n loading?: boolean;\n /** Whether the button is disabled */\n disabled?: boolean;\n /** Button label content */\n children?: React.ReactNode;\n /**\n * Disable motion effects (scale on press, icon animations)\n * @default false\n */\n disableEffects?: boolean;\n /** Ref to the underlying View */\n ref?: Ref<View>;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Button Component */\n/* -------------------------------------------------------------------------- */\n\n/**\n * **🖲️ A button element that can be used to trigger an action**\n *\n * @description\n * A button is a fundamental component used to trigger an action or event.\n * Buttons are interactive elements that users can click, tap, or otherwise\n * engage with to submit forms, open dialogues, or perform any other interaction.\n *\n * Features animated scale effect on press and smooth icon transitions matching\n * the web UDS Button behavior.\n *\n * @category Interactive\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Button } from '@yahoo/uds-mobile/Button';\n *\n * <Button onPress={() => console.log('pressed')}>Save</Button>\n * <Button variant=\"secondary\">Cancel</Button>\n * <Button startIcon=\"Add\" variant=\"brand\">Add Item</Button>\n * <Button loading>Saving...</Button>\n * ```\n *\n * @accessibility\n * - Sets `accessibilityRole=\"button\"` automatically\n * - Announces loading state to screen readers\n * - Use `accessibilityLabel` for icon-only buttons\n *\n * @see {@link IconButton} for icon-only buttons\n * @see {@link Link} for navigation actions\n */\nconst Button = memo(function Button({\n variant = 'primary',\n size = 'md',\n iconVariant = 'outline',\n startIcon,\n endIcon,\n loading,\n disabled,\n width: _width,\n children,\n style,\n accessibilityLabel,\n accessibilityHint,\n disableEffects = false,\n onPressIn,\n onPressOut,\n ref,\n ...props\n}: ButtonProps) {\n const shouldAnimate = !disableEffects;\n\n /* --------------------------------- State ---------------------------------- */\n const [pressed, setPressed] = useState(false);\n\n buttonStyles.useVariants({ size, variant, disabled, pressed });\n\n // Get gap and icon size from current variant styles\n const buttonGap = buttonStyles.root.gap;\n const iconSize = buttonStyles.icon.fontSize;\n\n // Get animated theme for boxShadow (useAnimatedVariantColor doesn't support non-color props)\n const animatedTheme = useAnimatedTheme();\n\n /* ------------------------------- Animation -------------------------------- */\n const scale = useSharedValue<number>(SCALE_EFFECTS.none);\n\n const handlePressIn = useCallback(\n (event: Parameters<NonNullable<PressableProps['onPressIn']>>[0]) => {\n setPressed(true);\n if (shouldAnimate) {\n scale.value = withSpring(SCALE_EFFECTS.down, BUTTON_SPRING_CONFIG);\n }\n onPressIn?.(event);\n },\n [shouldAnimate, scale, onPressIn],\n );\n\n const handlePressOut = useCallback(\n (event: Parameters<NonNullable<PressableProps['onPressOut']>>[0]) => {\n setPressed(false);\n if (shouldAnimate) {\n scale.value = withSpring(SCALE_EFFECTS.none, BUTTON_SPRING_CONFIG);\n }\n onPressOut?.(event);\n },\n [shouldAnimate, scale, onPressOut],\n );\n\n /* -------------------------------- Content --------------------------------- */\n const childrenNode =\n children &&\n (isValidElement(children) ? (\n children\n ) : (\n <Text numberOfLines={1} textAlign=\"center\" style={buttonStyles.text}>\n {children}\n </Text>\n ));\n\n const a11yState = useMemo(() => ({ disabled, busy: loading }), [disabled, loading]);\n\n /* --------------------------------- Styles --------------------------------- */\n // Animate pressed state for shadow (0 = rest, 1 = pressed)\n const pressProgress = useDerivedValue(\n () => withTiming(pressed ? 1 : 0, { duration: 220, easing: Easing.bezier(0, 0, 0.2, 1) }),\n [pressed],\n );\n\n // Animate using Unistyles' variant color system + boxShadow from theme\n const animatedStyles = useAnimatedStyle(() => {\n // Get boxShadow from theme using flattened path (no camelCase conversion needed!)\n const components = animatedTheme.value.components;\n const buttonVariantPath = `button/variant/${variant}/root/pressed` as const;\n const shadowPressed = components[buttonVariantPath]?.boxShadow;\n\n return {\n transform: [{ scale: scale.value }],\n // Only animate shadow if the theme defines one for this variant\n ...(shadowPressed && {\n boxShadow: interpolateShadowAlpha(shadowPressed, pressProgress.value),\n }),\n };\n });\n\n // Determine what should be visible in start slot\n const showLoading = !!loading;\n const showStartIcon = !!startIcon && !loading;\n const showEndIcon = !!endIcon && !loading;\n\n const iconSizeToken = (buttonStyles.icon.iconSizeToken as IconSize) ?? 'sm';\n\n // Start slot: either loading spinner or start icon\n const startContent = (\n <AnimatedIconSlot visible={showLoading || showStartIcon} iconSize={iconSize} gap={buttonGap}>\n {showLoading ? (\n <ActivityIndicator size={buttonStyles.icon.fontSize} color={buttonStyles.icon.color} />\n ) : (\n <IconSlot\n icon={startIcon}\n size={iconSizeToken}\n variant={iconVariant}\n style={buttonStyles.icon}\n />\n )}\n </AnimatedIconSlot>\n );\n\n // End slot: only end icon (no loading here)\n const endContent = (\n <AnimatedIconSlot visible={showEndIcon} iconSize={iconSize} gap={buttonGap}>\n <IconSlot\n icon={endIcon}\n size={iconSizeToken}\n variant={iconVariant}\n style={buttonStyles.icon}\n />\n </AnimatedIconSlot>\n );\n\n const rootStyles = useMemo(\n () => [\n buttonStyles.root,\n animatedStyles,\n typeof style === 'function' ? style({ pressed }) : style,\n ],\n [buttonStyles.root, animatedStyles, style, pressed],\n );\n\n /* --------------------------------- Render --------------------------------- */\n return (\n <AnimatedPressable\n ref={ref}\n disabled={disabled}\n onPressIn={handlePressIn}\n onPressOut={handlePressOut}\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"center\"\n overflow=\"hidden\"\n accessibilityLabel={loading ? `${accessibilityLabel ?? ''}, loading` : accessibilityLabel}\n accessibilityHint={accessibilityHint}\n accessibilityRole=\"button\"\n accessibilityState={a11yState}\n alignContent=\"center\"\n style={rootStyles}\n {...props}\n >\n {startContent}\n {childrenNode}\n {endContent}\n </AnimatedPressable>\n );\n});\n\nButton.displayName = 'Button';\n\nexport { Button, type ButtonProps };\n"],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ const VARIANT_ERROR_MAP = {
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```tsx
|
|
33
|
-
* import { Checkbox } from '@yahoo/uds-mobile';
|
|
33
|
+
* import { Checkbox } from '@yahoo/uds-mobile/Checkbox';
|
|
34
34
|
*
|
|
35
35
|
* <Checkbox label="Agree to terms" />
|
|
36
36
|
* <Checkbox label="Subscribe" checked={true} onChange={setChecked} />
|
|
@@ -30,7 +30,7 @@ interface CheckboxProps extends Omit<ViewProps, 'style'>, UniversalCheckboxProps
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```tsx
|
|
33
|
-
* import { Checkbox } from '@yahoo/uds-mobile';
|
|
33
|
+
* import { Checkbox } from '@yahoo/uds-mobile/Checkbox';
|
|
34
34
|
*
|
|
35
35
|
* <Checkbox label="Agree to terms" />
|
|
36
36
|
* <Checkbox label="Subscribe" checked={true} onChange={setChecked} />
|
|
@@ -30,7 +30,7 @@ interface CheckboxProps extends Omit<ViewProps, 'style'>, UniversalCheckboxProps
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```tsx
|
|
33
|
-
* import { Checkbox } from '@yahoo/uds-mobile';
|
|
33
|
+
* import { Checkbox } from '@yahoo/uds-mobile/Checkbox';
|
|
34
34
|
*
|
|
35
35
|
* <Checkbox label="Agree to terms" />
|
|
36
36
|
* <Checkbox label="Subscribe" checked={true} onChange={setChecked} />
|
|
@@ -27,7 +27,7 @@ const VARIANT_ERROR_MAP = {
|
|
|
27
27
|
*
|
|
28
28
|
* @example
|
|
29
29
|
* ```tsx
|
|
30
|
-
* import { Checkbox } from '@yahoo/uds-mobile';
|
|
30
|
+
* import { Checkbox } from '@yahoo/uds-mobile/Checkbox';
|
|
31
31
|
*
|
|
32
32
|
* <Checkbox label="Agree to terms" />
|
|
33
33
|
* <Checkbox label="Subscribe" checked={true} onChange={setChecked} />
|