@yahoo/uds-mobile 2.1.0 → 2.2.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/dist/bin/generateTheme.mjs +14 -0
- package/dist/components/{Avatar.d.mts → Avatar.d.ts} +2 -2
- package/dist/components/Avatar.d.ts.map +1 -0
- package/dist/components/{Avatar.mjs → Avatar.js} +4 -4
- package/dist/components/Avatar.js.map +1 -0
- package/dist/components/{Badge.d.mts → Badge.d.ts} +3 -3
- package/dist/components/Badge.d.ts.map +1 -0
- package/dist/components/{Badge.mjs → Badge.js} +4 -4
- package/dist/components/Badge.js.map +1 -0
- package/dist/components/BlurTarget.cjs +89 -0
- package/dist/components/BlurTarget.d.cts +52 -0
- package/dist/components/BlurTarget.d.cts.map +1 -0
- package/dist/components/BlurTarget.d.ts +52 -0
- package/dist/components/BlurTarget.d.ts.map +1 -0
- package/dist/components/BlurTarget.js +88 -0
- package/dist/components/BlurTarget.js.map +1 -0
- package/dist/components/Box.cjs +117 -20
- package/dist/components/Box.d.cts +11 -1
- package/dist/components/Box.d.cts.map +1 -1
- package/dist/components/{Box.d.mts → Box.d.ts} +14 -4
- package/dist/components/{Box.d.mts.map → Box.d.ts.map} +1 -1
- package/dist/components/Box.js +228 -0
- package/dist/components/Box.js.map +1 -0
- package/dist/components/{Button.d.mts → Button.d.ts} +4 -4
- package/dist/components/Button.d.ts.map +1 -0
- package/dist/components/{Button.mjs → Button.js} +6 -6
- package/dist/components/Button.js.map +1 -0
- package/dist/components/{Checkbox.d.mts → Checkbox.d.ts} +2 -2
- package/dist/components/Checkbox.d.ts.map +1 -0
- package/dist/components/{Checkbox.mjs → Checkbox.js} +7 -7
- package/dist/components/Checkbox.js.map +1 -0
- package/dist/components/{Chip.d.mts → Chip.d.ts} +3 -3
- package/dist/components/Chip.d.ts.map +1 -0
- package/dist/components/{Chip.mjs → Chip.js} +5 -5
- package/dist/components/Chip.js.map +1 -0
- package/dist/components/{HStack.d.mts → HStack.d.ts} +2 -2
- package/dist/components/HStack.d.ts.map +1 -0
- package/dist/components/{HStack.mjs → HStack.js} +2 -2
- package/dist/components/HStack.js.map +1 -0
- package/dist/components/{Icon.d.mts → Icon.d.ts} +2 -2
- package/dist/components/Icon.d.ts.map +1 -0
- package/dist/components/{Icon.mjs → Icon.js} +1 -1
- package/dist/components/Icon.js.map +1 -0
- package/dist/components/{IconButton.d.mts → IconButton.d.ts} +4 -4
- package/dist/components/IconButton.d.ts.map +1 -0
- package/dist/components/{IconButton.mjs → IconButton.js} +5 -5
- package/dist/components/IconButton.js.map +1 -0
- package/dist/components/{IconSlot.d.mts → IconSlot.d.ts} +2 -2
- package/dist/components/IconSlot.d.ts.map +1 -0
- package/dist/components/{IconSlot.mjs → IconSlot.js} +2 -2
- package/dist/components/IconSlot.js.map +1 -0
- package/dist/components/{Image.d.mts → Image.d.ts} +2 -2
- package/dist/components/Image.d.ts.map +1 -0
- package/dist/components/{Image.mjs → Image.js} +1 -1
- package/dist/components/Image.js.map +1 -0
- package/dist/components/{Input.d.mts → Input.d.ts} +4 -4
- package/dist/components/Input.d.ts.map +1 -0
- package/dist/components/{Input.mjs → Input.js} +5 -5
- package/dist/components/Input.js.map +1 -0
- package/dist/components/{Link.d.mts → Link.d.ts} +4 -4
- package/dist/components/Link.d.ts.map +1 -0
- package/dist/components/{Link.mjs → Link.js} +2 -2
- package/dist/components/Link.js.map +1 -0
- package/dist/components/{Pressable.d.mts → Pressable.d.ts} +2 -2
- package/dist/components/Pressable.d.ts.map +1 -0
- package/dist/components/{Pressable.mjs → Pressable.js} +1 -1
- package/dist/components/Pressable.js.map +1 -0
- package/dist/components/{Radio.d.mts → Radio.d.ts} +2 -2
- package/dist/components/Radio.d.ts.map +1 -0
- package/dist/components/{Radio.mjs → Radio.js} +6 -6
- package/dist/components/Radio.js.map +1 -0
- package/dist/components/{Screen.d.mts → Screen.d.ts} +2 -2
- package/dist/components/Screen.d.ts.map +1 -0
- package/dist/components/{Screen.mjs → Screen.js} +5 -5
- package/dist/components/Screen.js.map +1 -0
- package/dist/components/{Switch.d.mts → Switch.d.ts} +3 -3
- package/dist/components/Switch.d.ts.map +1 -0
- package/dist/components/{Switch.mjs → Switch.js} +6 -6
- package/dist/components/Switch.js.map +1 -0
- package/dist/components/{Text.d.mts → Text.d.ts} +1 -1
- package/dist/components/Text.d.ts.map +1 -0
- package/dist/components/{Text.mjs → Text.js} +1 -1
- package/dist/components/Text.js.map +1 -0
- package/dist/components/{VStack.d.mts → VStack.d.ts} +2 -2
- package/dist/components/VStack.d.ts.map +1 -0
- package/dist/components/{VStack.mjs → VStack.js} +2 -2
- package/dist/components/VStack.js.map +1 -0
- package/dist/motion-tokens/dist/{index.d.mts → index.d.ts} +2 -2
- package/dist/motion-tokens/dist/index.d.ts.map +1 -0
- package/dist/motion-tokens/dist/{index.mjs → index.js} +1 -1
- package/dist/motion-tokens/dist/index.js.map +1 -0
- package/dist/{motion.d.mts → motion.d.ts} +3 -3
- package/dist/motion.d.ts.map +1 -0
- package/dist/{motion.mjs → motion.js} +2 -2
- package/dist/motion.js.map +1 -0
- package/dist/types/dist/{index.d.mts → index.d.ts} +1 -1
- package/dist/types/dist/index.d.ts.map +1 -0
- package/dist/{types.d.mts → types.d.ts} +1 -1
- package/dist/types.d.ts.map +1 -0
- package/dist/{types.mjs → types.js} +0 -1
- package/fonts/index.cjs +205 -205
- package/fonts/index.mjs +205 -205
- package/generated/unistyles.d.ts +9 -0
- package/package.json +55 -41
- package/dist/components/Avatar.d.mts.map +0 -1
- package/dist/components/Avatar.mjs.map +0 -1
- package/dist/components/Badge.d.mts.map +0 -1
- package/dist/components/Badge.mjs.map +0 -1
- package/dist/components/Box.mjs +0 -131
- package/dist/components/Box.mjs.map +0 -1
- package/dist/components/Button.d.mts.map +0 -1
- package/dist/components/Button.mjs.map +0 -1
- package/dist/components/Checkbox.d.mts.map +0 -1
- package/dist/components/Checkbox.mjs.map +0 -1
- package/dist/components/Chip.d.mts.map +0 -1
- package/dist/components/Chip.mjs.map +0 -1
- package/dist/components/HStack.d.mts.map +0 -1
- package/dist/components/HStack.mjs.map +0 -1
- package/dist/components/Icon.d.mts.map +0 -1
- package/dist/components/Icon.mjs.map +0 -1
- package/dist/components/IconButton.d.mts.map +0 -1
- package/dist/components/IconButton.mjs.map +0 -1
- package/dist/components/IconSlot.d.mts.map +0 -1
- package/dist/components/IconSlot.mjs.map +0 -1
- package/dist/components/Image.d.mts.map +0 -1
- package/dist/components/Image.mjs.map +0 -1
- package/dist/components/Input.d.mts.map +0 -1
- package/dist/components/Input.mjs.map +0 -1
- package/dist/components/Link.d.mts.map +0 -1
- package/dist/components/Link.mjs.map +0 -1
- package/dist/components/Pressable.d.mts.map +0 -1
- package/dist/components/Pressable.mjs.map +0 -1
- package/dist/components/Radio.d.mts.map +0 -1
- package/dist/components/Radio.mjs.map +0 -1
- package/dist/components/Screen.d.mts.map +0 -1
- package/dist/components/Screen.mjs.map +0 -1
- package/dist/components/Switch.d.mts.map +0 -1
- package/dist/components/Switch.mjs.map +0 -1
- package/dist/components/Text.d.mts.map +0 -1
- package/dist/components/Text.mjs.map +0 -1
- package/dist/components/VStack.d.mts.map +0 -1
- package/dist/components/VStack.mjs.map +0 -1
- package/dist/motion-tokens/dist/index.d.mts.map +0 -1
- package/dist/motion-tokens/dist/index.mjs.map +0 -1
- package/dist/motion.d.mts.map +0 -1
- package/dist/motion.mjs.map +0 -1
- package/dist/types/dist/index.d.mts.map +0 -1
- package/dist/types.d.mts.map +0 -1
|
@@ -252,6 +252,19 @@ function generateShadows(config) {
|
|
|
252
252
|
});
|
|
253
253
|
return result;
|
|
254
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Generates blur values from elevation presets.
|
|
257
|
+
* Maps elevation levels to their backgroundBlurRadius values.
|
|
258
|
+
* These can be used with BlurView intensity prop.
|
|
259
|
+
*/
|
|
260
|
+
function generateBlur(config, colorMode) {
|
|
261
|
+
const result = { none: 0 };
|
|
262
|
+
for (const [level, modePresets] of Object.entries(config.elevation)) {
|
|
263
|
+
const blurRadius = modePresets[colorMode].backgroundBlurRadius ?? 0;
|
|
264
|
+
result[`elevation-${level}`] = blurRadius;
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
255
268
|
function isElevationCustomShadows(value) {
|
|
256
269
|
return Array.isArray(value);
|
|
257
270
|
}
|
|
@@ -578,6 +591,7 @@ function generateTheme(config, colorMode) {
|
|
|
578
591
|
drop: sortKeys(boxShadows.drop),
|
|
579
592
|
inset: sortKeys(boxShadows.inset)
|
|
580
593
|
},
|
|
594
|
+
blur: sortKeys(generateBlur(config, colorMode)),
|
|
581
595
|
components: generateComponents(config, colorMode)
|
|
582
596
|
};
|
|
583
597
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { IconSlotType } from "./IconSlot.
|
|
2
|
+
import { IconSlotType } from "./IconSlot.js";
|
|
3
3
|
import * as react from "react";
|
|
4
4
|
import { View, ViewProps } from "react-native";
|
|
5
5
|
|
|
@@ -65,4 +65,4 @@ interface AvatarProps extends ViewProps {
|
|
|
65
65
|
declare const Avatar: react.ForwardRefExoticComponent<AvatarProps & react.RefAttributes<View>>;
|
|
66
66
|
//#endregion
|
|
67
67
|
export { Avatar, type AvatarProps };
|
|
68
|
-
//# sourceMappingURL=Avatar.d.
|
|
68
|
+
//# sourceMappingURL=Avatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Avatar.d.ts","names":[],"sources":["../../src/components/Avatar.tsx"],"mappings":";;;;;;;KAWK,UAAA;;KAGA,aAAA;;KAGA,oBAAA,qFAOC,IAAA;AAAA,UAEI,WAAA,SAAoB,SAAA;EAff;EAiBb,GAAA;EAdgB;EAgBhB,GAAA;EAhBgB;EAkBhB,QAAA;EAfG;EAiBH,IAAA,GAAO,UAAA;;EAEP,OAAA,GAAU,aAAA;EAZM;EAchB,IAAA,GAAO,YAAA;EAZa;EAcpB,oBAAA,GAAuB,oBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;AAAoB;;;;;;;;;;;;;;;;cAoEvC,MAAA,EAAM,KAAA,CAAA,yBAAA,CAAA,WAAA,GAAA,KAAA,CAAA,aAAA,CAAA,IAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
-
import { Box } from "./Box.
|
|
3
|
-
import { IconSlot } from "./IconSlot.
|
|
4
|
-
import { Text as Text$1 } from "./Text.
|
|
2
|
+
import { Box } from "./Box.js";
|
|
3
|
+
import { IconSlot } from "./IconSlot.js";
|
|
4
|
+
import { Text as Text$1 } from "./Text.js";
|
|
5
5
|
import { forwardRef, useState } from "react";
|
|
6
6
|
import { Image } from "react-native";
|
|
7
7
|
import { avatarStyles } from "../../generated/styles";
|
|
@@ -114,4 +114,4 @@ Avatar.displayName = "Avatar";
|
|
|
114
114
|
|
|
115
115
|
//#endregion
|
|
116
116
|
export { Avatar };
|
|
117
|
-
//# sourceMappingURL=Avatar.
|
|
117
|
+
//# sourceMappingURL=Avatar.js.map
|
|
@@ -0,0 +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 = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\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,MAAM,CACf,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;EACM;EACL,OAAO;GACL,aAAa;GACb;IAAE,YAAY;IAAU,gBAAgB;IAAU,UAAU;IAAU;GACtE;GACD;EACD,mBAAkB;EAClB,oBAAoB;EACpB,GAAI;;GAEH,aACC,oBAACA;IACC,QAAQ,EAAE,KAAK,KAAK;IACpB,OAAO;KAAE,OAAO;KAAQ,QAAQ;KAAQ;IACxC,eAAe,cAAc,KAAK;IAClC,oBAAoB;KACpB;GAGH,YACC,oBAACC;IAAK,OAAO,aAAa;IAAM,eAAe;cAC5C;KACI;GAGR,YAAY,oBAAC;IAAS,MAAM,QAAQ;IAAU,SAAQ;IAAO,OAAO,aAAa;KAAQ;;GACtF;EAER;AAEF,OAAO,cAAc"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { BadgeSize, BadgeVariant } from "../types/dist/index.
|
|
3
|
-
import { IconSlotType } from "./IconSlot.
|
|
2
|
+
import { BadgeSize, BadgeVariant } from "../types/dist/index.js";
|
|
3
|
+
import { IconSlotType } from "./IconSlot.js";
|
|
4
4
|
import * as react from "react";
|
|
5
5
|
import { Ref } from "react";
|
|
6
6
|
import { View, ViewProps } from "react-native";
|
|
@@ -58,4 +58,4 @@ interface BadgeProps extends ViewProps {
|
|
|
58
58
|
declare const Badge: react.NamedExoticComponent<BadgeProps>;
|
|
59
59
|
//#endregion
|
|
60
60
|
export { Badge, type BadgeProps };
|
|
61
|
-
//# sourceMappingURL=Badge.d.
|
|
61
|
+
//# sourceMappingURL=Badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Badge.d.ts","names":[],"sources":["../../src/components/Badge.tsx"],"mappings":";;;;;;;;UAWU,UAAA,SAAmB,SAAA;;EAE3B,OAAA,GAAU,YAAA;EAFF;EAIR,IAAA,GAAO,SAAA;;EAEP,QAAA;EAFO;EAIP,QAAA;EAIU;EAFV,SAAA,GAAY,YAAA;EAYN;EAVN,OAAA,GAAU,YAAA;EAZ0B;EAcpC,6BAAA;EAd2B;EAgB3B,mBAAA;EAdU;EAgBV,yBAAA;EAdO;EAgBP,uBAAA;EAZA;EAcA,GAAA,GAAM,GAAA,CAAI,IAAA;AAAA;;;;;;;;;;;;AAAI;;;;;;;;;;;;;;cA4BV,KAAA,EAAK,KAAA,CAAA,oBAAA,CAAA,UAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
-
import { IconSlot } from "./IconSlot.
|
|
3
|
-
import { Text } from "./Text.
|
|
4
|
-
import { HStack } from "./HStack.
|
|
2
|
+
import { IconSlot } from "./IconSlot.js";
|
|
3
|
+
import { Text } from "./Text.js";
|
|
4
|
+
import { HStack } from "./HStack.js";
|
|
5
5
|
import { memo, useMemo } from "react";
|
|
6
6
|
import { badgeStyles } from "../../generated/styles";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -75,4 +75,4 @@ Badge.displayName = "Badge";
|
|
|
75
75
|
|
|
76
76
|
//#endregion
|
|
77
77
|
export { Badge };
|
|
78
|
-
//# sourceMappingURL=Badge.
|
|
78
|
+
//# sourceMappingURL=Badge.js.map
|
|
@@ -0,0 +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;EACM;EACL,YAAW;EACX,UAAS;EACT,WAAU;EACA;EACA;EACqB;EACJ;EAE3B,OAbe,cAAc,CAAC,YAAY,MAAM,MAAM,EAAE,CAAC,OAAO,YAAY,KAAK,CAAC;EAclF,GAAI;;GAEH,aACC,oBAAC;IACC,MAAM;IACN,SAAQ;IACR,qBAAqB;IACrB,OAAO,YAAY;KACnB;GAEJ,oBAAC;IACC,eAAe;IACf,YAAW;IACU;IACrB,OAAO,YAAY;IAElB;KACI;GACN,WACC,oBAAC;IACC,MAAM;IACN,SAAQ;IACR,qBAAqB;IACrB,OAAO,YAAY;KACnB;;GAEG;EAEX;AAEF,MAAM,cAAc"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
3
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
4
|
+
let react = require("react");
|
|
5
|
+
let react_native = require("react-native");
|
|
6
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
|
+
|
|
8
|
+
//#region src/components/BlurTarget.tsx
|
|
9
|
+
let BlurTargetView = null;
|
|
10
|
+
let blurTargetLoadState = "pending";
|
|
11
|
+
const blurTargetLoadListeners = [];
|
|
12
|
+
import("expo-blur").then((mod) => {
|
|
13
|
+
BlurTargetView = mod.BlurTargetView;
|
|
14
|
+
blurTargetLoadState = "loaded";
|
|
15
|
+
blurTargetLoadListeners.forEach((cb) => cb());
|
|
16
|
+
}).catch(() => {
|
|
17
|
+
blurTargetLoadState = "failed";
|
|
18
|
+
blurTargetLoadListeners.forEach((cb) => cb());
|
|
19
|
+
});
|
|
20
|
+
/** Hook to get BlurTargetView component, re-renders when loaded */
|
|
21
|
+
function useBlurTargetView() {
|
|
22
|
+
const [, forceUpdate] = (0, react.useState)(0);
|
|
23
|
+
(0, react.useEffect)(() => {
|
|
24
|
+
if (blurTargetLoadState === "pending") {
|
|
25
|
+
const listener = () => forceUpdate((n) => n + 1);
|
|
26
|
+
blurTargetLoadListeners.push(listener);
|
|
27
|
+
return () => {
|
|
28
|
+
const idx = blurTargetLoadListeners.indexOf(listener);
|
|
29
|
+
if (idx >= 0) blurTargetLoadListeners.splice(idx, 1);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}, []);
|
|
33
|
+
return BlurTargetView;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* **🔲 Wrapper for content that can be blurred**
|
|
37
|
+
*
|
|
38
|
+
* @description
|
|
39
|
+
* When using blur effects (via the `blur` prop or elevation with blur configured),
|
|
40
|
+
* wrap the content you want to blur in this component and pass its ref to Box's `blurTarget` prop.
|
|
41
|
+
*
|
|
42
|
+
* BlurTarget handles platform differences internally - on iOS it renders children directly,
|
|
43
|
+
* on Android it wraps them in the native view required for blur to work.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
48
|
+
* import { Box, Text } from '@yahoo/uds-mobile';
|
|
49
|
+
* import { useRef } from 'react';
|
|
50
|
+
* import type { View } from 'react-native';
|
|
51
|
+
*
|
|
52
|
+
* function MyComponent() {
|
|
53
|
+
* const blurTargetRef = useRef<View>(null);
|
|
54
|
+
*
|
|
55
|
+
* return (
|
|
56
|
+
* <Box flex="1">
|
|
57
|
+
* <BlurTarget ref={blurTargetRef} fill>
|
|
58
|
+
* <Image source={backgroundImage} />
|
|
59
|
+
* </BlurTarget>
|
|
60
|
+
*
|
|
61
|
+
* <Box blur={50} blurTarget={blurTargetRef} borderRadius="lg" spacing="4">
|
|
62
|
+
* <Text>Overlay content</Text>
|
|
63
|
+
* </Box>
|
|
64
|
+
* </Box>
|
|
65
|
+
* );
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @see {@link https://docs.expo.dev/versions/latest/sdk/blur-view/} expo-blur documentation
|
|
70
|
+
*/
|
|
71
|
+
const BlurTarget = (0, react.forwardRef)(function BlurTarget({ children, fill, style }, ref) {
|
|
72
|
+
const BlurTargetViewComponent = useBlurTargetView();
|
|
73
|
+
const resolvedStyle = fill ? [react_native.StyleSheet.absoluteFill, style] : style;
|
|
74
|
+
if (react_native.Platform.OS === "android" && BlurTargetViewComponent) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlurTargetViewComponent, {
|
|
75
|
+
ref,
|
|
76
|
+
style: resolvedStyle,
|
|
77
|
+
children
|
|
78
|
+
});
|
|
79
|
+
if (resolvedStyle || ref) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
|
|
80
|
+
ref,
|
|
81
|
+
style: resolvedStyle,
|
|
82
|
+
children
|
|
83
|
+
});
|
|
84
|
+
return children;
|
|
85
|
+
});
|
|
86
|
+
BlurTarget.displayName = "BlurTarget";
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
exports.BlurTarget = BlurTarget;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
import * as react from "react";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { View, ViewStyle } from "react-native";
|
|
5
|
+
|
|
6
|
+
//#region src/components/BlurTarget.d.ts
|
|
7
|
+
interface BlurTargetProps {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
/** Fill the parent container (applies absoluteFill positioning) */
|
|
10
|
+
fill?: boolean;
|
|
11
|
+
style?: ViewStyle;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* **🔲 Wrapper for content that can be blurred**
|
|
15
|
+
*
|
|
16
|
+
* @description
|
|
17
|
+
* When using blur effects (via the `blur` prop or elevation with blur configured),
|
|
18
|
+
* wrap the content you want to blur in this component and pass its ref to Box's `blurTarget` prop.
|
|
19
|
+
*
|
|
20
|
+
* BlurTarget handles platform differences internally - on iOS it renders children directly,
|
|
21
|
+
* on Android it wraps them in the native view required for blur to work.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
26
|
+
* import { Box, Text } from '@yahoo/uds-mobile';
|
|
27
|
+
* import { useRef } from 'react';
|
|
28
|
+
* import type { View } from 'react-native';
|
|
29
|
+
*
|
|
30
|
+
* function MyComponent() {
|
|
31
|
+
* const blurTargetRef = useRef<View>(null);
|
|
32
|
+
*
|
|
33
|
+
* return (
|
|
34
|
+
* <Box flex="1">
|
|
35
|
+
* <BlurTarget ref={blurTargetRef} fill>
|
|
36
|
+
* <Image source={backgroundImage} />
|
|
37
|
+
* </BlurTarget>
|
|
38
|
+
*
|
|
39
|
+
* <Box blur={50} blurTarget={blurTargetRef} borderRadius="lg" spacing="4">
|
|
40
|
+
* <Text>Overlay content</Text>
|
|
41
|
+
* </Box>
|
|
42
|
+
* </Box>
|
|
43
|
+
* );
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @see {@link https://docs.expo.dev/versions/latest/sdk/blur-view/} expo-blur documentation
|
|
48
|
+
*/
|
|
49
|
+
declare const BlurTarget: react.ForwardRefExoticComponent<BlurTargetProps & react.RefAttributes<View | null>>;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { BlurTarget, type BlurTargetProps };
|
|
52
|
+
//# sourceMappingURL=BlurTarget.d.cts.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuCb,UAAA,EAAU,KAAA,CAAA,yBAAA,CAAA,eAAA,GAAA,KAAA,CAAA,aAAA,CAAA,IAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
import * as react from "react";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { View, ViewStyle } from "react-native";
|
|
5
|
+
|
|
6
|
+
//#region src/components/BlurTarget.d.ts
|
|
7
|
+
interface BlurTargetProps {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
/** Fill the parent container (applies absoluteFill positioning) */
|
|
10
|
+
fill?: boolean;
|
|
11
|
+
style?: ViewStyle;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* **🔲 Wrapper for content that can be blurred**
|
|
15
|
+
*
|
|
16
|
+
* @description
|
|
17
|
+
* When using blur effects (via the `blur` prop or elevation with blur configured),
|
|
18
|
+
* wrap the content you want to blur in this component and pass its ref to Box's `blurTarget` prop.
|
|
19
|
+
*
|
|
20
|
+
* BlurTarget handles platform differences internally - on iOS it renders children directly,
|
|
21
|
+
* on Android it wraps them in the native view required for blur to work.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
26
|
+
* import { Box, Text } from '@yahoo/uds-mobile';
|
|
27
|
+
* import { useRef } from 'react';
|
|
28
|
+
* import type { View } from 'react-native';
|
|
29
|
+
*
|
|
30
|
+
* function MyComponent() {
|
|
31
|
+
* const blurTargetRef = useRef<View>(null);
|
|
32
|
+
*
|
|
33
|
+
* return (
|
|
34
|
+
* <Box flex="1">
|
|
35
|
+
* <BlurTarget ref={blurTargetRef} fill>
|
|
36
|
+
* <Image source={backgroundImage} />
|
|
37
|
+
* </BlurTarget>
|
|
38
|
+
*
|
|
39
|
+
* <Box blur={50} blurTarget={blurTargetRef} borderRadius="lg" spacing="4">
|
|
40
|
+
* <Text>Overlay content</Text>
|
|
41
|
+
* </Box>
|
|
42
|
+
* </Box>
|
|
43
|
+
* );
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @see {@link https://docs.expo.dev/versions/latest/sdk/blur-view/} expo-blur documentation
|
|
48
|
+
*/
|
|
49
|
+
declare const BlurTarget: react.ForwardRefExoticComponent<BlurTargetProps & react.RefAttributes<View | null>>;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { BlurTarget, type BlurTargetProps };
|
|
52
|
+
//# sourceMappingURL=BlurTarget.d.ts.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuCb,UAAA,EAAU,KAAA,CAAA,yBAAA,CAAA,eAAA,GAAA,KAAA,CAAA,aAAA,CAAA,IAAA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
+
import { forwardRef, useEffect, useState } from "react";
|
|
3
|
+
import { Platform, StyleSheet, View } from "react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/components/BlurTarget.tsx
|
|
7
|
+
let BlurTargetView = null;
|
|
8
|
+
let blurTargetLoadState = "pending";
|
|
9
|
+
const blurTargetLoadListeners = [];
|
|
10
|
+
import("expo-blur").then((mod) => {
|
|
11
|
+
BlurTargetView = mod.BlurTargetView;
|
|
12
|
+
blurTargetLoadState = "loaded";
|
|
13
|
+
blurTargetLoadListeners.forEach((cb) => cb());
|
|
14
|
+
}).catch(() => {
|
|
15
|
+
blurTargetLoadState = "failed";
|
|
16
|
+
blurTargetLoadListeners.forEach((cb) => cb());
|
|
17
|
+
});
|
|
18
|
+
/** Hook to get BlurTargetView component, re-renders when loaded */
|
|
19
|
+
function useBlurTargetView() {
|
|
20
|
+
const [, forceUpdate] = useState(0);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (blurTargetLoadState === "pending") {
|
|
23
|
+
const listener = () => forceUpdate((n) => n + 1);
|
|
24
|
+
blurTargetLoadListeners.push(listener);
|
|
25
|
+
return () => {
|
|
26
|
+
const idx = blurTargetLoadListeners.indexOf(listener);
|
|
27
|
+
if (idx >= 0) blurTargetLoadListeners.splice(idx, 1);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}, []);
|
|
31
|
+
return BlurTargetView;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* **🔲 Wrapper for content that can be blurred**
|
|
35
|
+
*
|
|
36
|
+
* @description
|
|
37
|
+
* When using blur effects (via the `blur` prop or elevation with blur configured),
|
|
38
|
+
* wrap the content you want to blur in this component and pass its ref to Box's `blurTarget` prop.
|
|
39
|
+
*
|
|
40
|
+
* BlurTarget handles platform differences internally - on iOS it renders children directly,
|
|
41
|
+
* on Android it wraps them in the native view required for blur to work.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* import { BlurTarget } from '@yahoo/uds-mobile/BlurTarget';
|
|
46
|
+
* import { Box, Text } from '@yahoo/uds-mobile';
|
|
47
|
+
* import { useRef } from 'react';
|
|
48
|
+
* import type { View } from 'react-native';
|
|
49
|
+
*
|
|
50
|
+
* function MyComponent() {
|
|
51
|
+
* const blurTargetRef = useRef<View>(null);
|
|
52
|
+
*
|
|
53
|
+
* return (
|
|
54
|
+
* <Box flex="1">
|
|
55
|
+
* <BlurTarget ref={blurTargetRef} fill>
|
|
56
|
+
* <Image source={backgroundImage} />
|
|
57
|
+
* </BlurTarget>
|
|
58
|
+
*
|
|
59
|
+
* <Box blur={50} blurTarget={blurTargetRef} borderRadius="lg" spacing="4">
|
|
60
|
+
* <Text>Overlay content</Text>
|
|
61
|
+
* </Box>
|
|
62
|
+
* </Box>
|
|
63
|
+
* );
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @see {@link https://docs.expo.dev/versions/latest/sdk/blur-view/} expo-blur documentation
|
|
68
|
+
*/
|
|
69
|
+
const BlurTarget = forwardRef(function BlurTarget({ children, fill, style }, ref) {
|
|
70
|
+
const BlurTargetViewComponent = useBlurTargetView();
|
|
71
|
+
const resolvedStyle = fill ? [StyleSheet.absoluteFill, style] : style;
|
|
72
|
+
if (Platform.OS === "android" && BlurTargetViewComponent) return /* @__PURE__ */ jsx(BlurTargetViewComponent, {
|
|
73
|
+
ref,
|
|
74
|
+
style: resolvedStyle,
|
|
75
|
+
children
|
|
76
|
+
});
|
|
77
|
+
if (resolvedStyle || ref) return /* @__PURE__ */ jsx(View, {
|
|
78
|
+
ref,
|
|
79
|
+
style: resolvedStyle,
|
|
80
|
+
children
|
|
81
|
+
});
|
|
82
|
+
return children;
|
|
83
|
+
});
|
|
84
|
+
BlurTarget.displayName = "BlurTarget";
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
export { BlurTarget };
|
|
88
|
+
//# sourceMappingURL=BlurTarget.js.map
|
|
@@ -0,0 +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, Text } from '@yahoo/uds-mobile';\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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CT,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;EAA6B;EAA+B,OAAO;EACjE;GACuB;AAM9B,KAAI,iBAAiB,IACnB,QACE,oBAAC;EAAU;EAAK,OAAO;EACpB;GACI;AAKX,QAAO;EACP;AAEF,WAAW,cAAc"}
|
package/dist/components/Box.cjs
CHANGED
|
@@ -8,6 +8,36 @@ let react_native_unistyles = require("react-native-unistyles");
|
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
|
|
10
10
|
//#region src/components/Box.tsx
|
|
11
|
+
let BlurView = null;
|
|
12
|
+
let blurLoadState = "pending";
|
|
13
|
+
const blurLoadListeners = [];
|
|
14
|
+
import("expo-blur").then((mod) => {
|
|
15
|
+
BlurView = mod.BlurView;
|
|
16
|
+
blurLoadState = "loaded";
|
|
17
|
+
blurLoadListeners.forEach((cb) => cb());
|
|
18
|
+
}).catch(() => {
|
|
19
|
+
blurLoadState = "failed";
|
|
20
|
+
blurLoadListeners.forEach((cb) => cb());
|
|
21
|
+
});
|
|
22
|
+
/** Hook to get BlurView component, re-renders when loaded */
|
|
23
|
+
function useBlurView() {
|
|
24
|
+
const [, forceUpdate] = (0, react.useState)(0);
|
|
25
|
+
(0, react.useEffect)(() => {
|
|
26
|
+
if (blurLoadState === "pending") {
|
|
27
|
+
const listener = () => forceUpdate((n) => n + 1);
|
|
28
|
+
blurLoadListeners.push(listener);
|
|
29
|
+
return () => {
|
|
30
|
+
const idx = blurLoadListeners.indexOf(listener);
|
|
31
|
+
if (idx >= 0) blurLoadListeners.splice(idx, 1);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}, []);
|
|
35
|
+
return {
|
|
36
|
+
BlurView,
|
|
37
|
+
isLoaded: blurLoadState !== "pending",
|
|
38
|
+
isFailed: blurLoadState === "failed"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
11
41
|
/**
|
|
12
42
|
* **📦 A layout component that can be used to compose other components**
|
|
13
43
|
*
|
|
@@ -36,8 +66,39 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
36
66
|
* @see {@link HStack} for horizontal layouts
|
|
37
67
|
* @see {@link VStack} for vertical layouts
|
|
38
68
|
*/
|
|
39
|
-
const Box = (0, react.memo)(function Box({ elevation, backgroundColor, dangerouslySetBackgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, dangerouslySetBorderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, alignContent, alignItems, alignSelf, flex, flexDirection, flexGrow, flexShrink, flexWrap, justifyContent, display = "flex", overflow, spacing, spacingHorizontal, spacingVertical, spacingBottom, spacingEnd, spacingStart, spacingTop, offset, offsetVertical, offsetHorizontal, offsetBottom, offsetEnd, offsetStart, offsetTop, columnGap, rowGap, width, height, minWidth, maxWidth, minHeight, maxHeight, dropShadow, insetShadow, style, ref, ...props }) {
|
|
69
|
+
const Box = (0, react.memo)(function Box({ elevation, backgroundColor, dangerouslySetBackgroundColor, borderRadius, borderTopStartRadius, borderTopEndRadius, borderBottomStartRadius, borderBottomEndRadius, borderColor, dangerouslySetBorderColor, borderStartColor, borderEndColor, borderTopColor, borderBottomColor, borderWidth, borderVerticalWidth, borderHorizontalWidth, borderStartWidth, borderEndWidth, borderTopWidth, borderBottomWidth, alignContent, alignItems, alignSelf, flex, flexDirection, flexGrow, flexShrink, flexWrap, justifyContent, display = "flex", overflow, spacing, spacingHorizontal, spacingVertical, spacingBottom, spacingEnd, spacingStart, spacingTop, offset, offsetVertical, offsetHorizontal, offsetBottom, offsetEnd, offsetStart, offsetTop, columnGap, rowGap, width, height, minWidth, maxWidth, minHeight, maxHeight, dropShadow, insetShadow, blur, blurTarget, style, ref, ...props }) {
|
|
70
|
+
const { theme, rt } = (0, react_native_unistyles.useUnistyles)();
|
|
71
|
+
const { BlurView: BlurViewComponent, isLoaded: blurIsLoaded, isFailed: blurFailed } = useBlurView();
|
|
40
72
|
const elevationAlias = elevation !== void 0 ? `elevation-${elevation}` : void 0;
|
|
73
|
+
const blurExplicitlySet = blur !== void 0;
|
|
74
|
+
const blurIntensity = (0, react.useMemo)(() => {
|
|
75
|
+
if (blur !== void 0) return blur;
|
|
76
|
+
if (elevation === void 0 || !theme.blur) return 0;
|
|
77
|
+
const blurKey = `elevation-${elevation}`;
|
|
78
|
+
return theme.blur[blurKey] ?? 0;
|
|
79
|
+
}, [
|
|
80
|
+
blur,
|
|
81
|
+
elevation,
|
|
82
|
+
theme
|
|
83
|
+
]);
|
|
84
|
+
const hasWarnedRef = (0, react.useRef)("none");
|
|
85
|
+
(0, react.useEffect)(() => {
|
|
86
|
+
if (!__DEV__ || blurIntensity === 0 || !blurIsLoaded) return;
|
|
87
|
+
if (blurFailed && hasWarnedRef.current !== "no-expo-blur") {
|
|
88
|
+
hasWarnedRef.current = "no-expo-blur";
|
|
89
|
+
console.warn("[UDS Mobile] Box: Blur effect requested but expo-blur is not installed. ");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!blurTarget && hasWarnedRef.current !== "no-blur-target") {
|
|
93
|
+
hasWarnedRef.current = "no-blur-target";
|
|
94
|
+
console.warn("[UDS Mobile] Box: Blur effect requires a blurTarget ref. Wrap the content to blur in <BlurTarget ref={ref}> and pass the ref to blurTarget prop. See BACKGROUND_BLUR.md for details.");
|
|
95
|
+
}
|
|
96
|
+
}, [
|
|
97
|
+
blurIntensity,
|
|
98
|
+
blurTarget,
|
|
99
|
+
blurIsLoaded,
|
|
100
|
+
blurFailed
|
|
101
|
+
]);
|
|
41
102
|
const variants = {
|
|
42
103
|
backgroundColor: backgroundColor ?? elevationAlias,
|
|
43
104
|
borderRadius,
|
|
@@ -88,10 +149,35 @@ const Box = (0, react.memo)(function Box({ elevation, backgroundColor, dangerous
|
|
|
88
149
|
generated_styles.styles.useVariants(variants);
|
|
89
150
|
const effectiveDropShadow = dropShadow ?? elevationAlias;
|
|
90
151
|
const shadowStyle = effectiveDropShadow || insetShadow ? shadowSheet.shadow(effectiveDropShadow, insetShadow) : void 0;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
152
|
+
const boxStyles = (0, react.useMemo)(() => [
|
|
153
|
+
dangerouslySetBackgroundColor ? { backgroundColor: dangerouslySetBackgroundColor } : void 0,
|
|
154
|
+
dangerouslySetBorderColor ? { borderColor: dangerouslySetBorderColor } : void 0,
|
|
155
|
+
width ? { width } : void 0,
|
|
156
|
+
height ? { height } : void 0,
|
|
157
|
+
minWidth ? { minWidth } : void 0,
|
|
158
|
+
maxWidth ? { maxWidth } : void 0,
|
|
159
|
+
minHeight ? { minHeight } : void 0,
|
|
160
|
+
maxHeight ? { maxHeight } : void 0,
|
|
161
|
+
shadowStyle,
|
|
162
|
+
generated_styles.styles.foundation,
|
|
163
|
+
style
|
|
164
|
+
], [
|
|
165
|
+
dangerouslySetBackgroundColor,
|
|
166
|
+
dangerouslySetBorderColor,
|
|
167
|
+
width,
|
|
168
|
+
height,
|
|
169
|
+
minWidth,
|
|
170
|
+
maxWidth,
|
|
171
|
+
minHeight,
|
|
172
|
+
maxHeight,
|
|
173
|
+
shadowStyle,
|
|
174
|
+
generated_styles.styles.foundation,
|
|
175
|
+
style
|
|
176
|
+
]);
|
|
177
|
+
if (BlurViewComponent && (blurIntensity > 0 || blurExplicitlySet)) {
|
|
178
|
+
const isAndroid = react_native.Platform.OS === "android";
|
|
179
|
+
const blurTint = rt.themeName === "dark" ? "dark" : "light";
|
|
180
|
+
const blurStyles = isAndroid ? boxStyles : [
|
|
95
181
|
dangerouslySetBorderColor ? { borderColor: dangerouslySetBorderColor } : void 0,
|
|
96
182
|
width ? { width } : void 0,
|
|
97
183
|
height ? { height } : void 0,
|
|
@@ -100,21 +186,32 @@ const Box = (0, react.memo)(function Box({ elevation, backgroundColor, dangerous
|
|
|
100
186
|
minHeight ? { minHeight } : void 0,
|
|
101
187
|
maxHeight ? { maxHeight } : void 0,
|
|
102
188
|
shadowStyle,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
189
|
+
{
|
|
190
|
+
...generated_styles.styles.foundation,
|
|
191
|
+
backgroundColor: void 0
|
|
192
|
+
},
|
|
193
|
+
style ? Array.isArray(style) ? style.map((s) => s && typeof s === "object" ? {
|
|
194
|
+
...s,
|
|
195
|
+
backgroundColor: void 0
|
|
196
|
+
} : s) : typeof style === "object" ? {
|
|
197
|
+
...style,
|
|
198
|
+
backgroundColor: void 0
|
|
199
|
+
} : style : void 0
|
|
200
|
+
];
|
|
201
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlurViewComponent, {
|
|
202
|
+
ref,
|
|
203
|
+
intensity: isAndroid ? Math.min(blurIntensity * .4, 40) : blurIntensity,
|
|
204
|
+
tint: blurTint,
|
|
205
|
+
blurTarget: isAndroid ? blurTarget : void 0,
|
|
206
|
+
blurMethod: isAndroid ? "dimezisBlurView" : void 0,
|
|
207
|
+
style: blurStyles,
|
|
208
|
+
...props,
|
|
209
|
+
children: props.children
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
|
|
213
|
+
ref,
|
|
214
|
+
style: boxStyles,
|
|
118
215
|
...props
|
|
119
216
|
});
|
|
120
217
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { ElevationLevel } from "../types/dist/index.cjs";
|
|
3
3
|
import { SizeProps } from "../types.cjs";
|
|
4
4
|
import * as react from "react";
|
|
5
|
-
import { Ref } from "react";
|
|
5
|
+
import { Ref, RefObject } from "react";
|
|
6
6
|
import { View, ViewProps } from "react-native";
|
|
7
7
|
import { StyleProps } from "../../generated/styles";
|
|
8
8
|
|
|
@@ -59,6 +59,16 @@ interface BoxProps extends ViewProps, SizeProps {
|
|
|
59
59
|
insetShadow?: StyleProps['insetShadow'];
|
|
60
60
|
dangerouslySetBackgroundColor?: string;
|
|
61
61
|
dangerouslySetBorderColor?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Manual blur intensity (0-100). When set, renders as a BlurView.
|
|
64
|
+
* Requires `blurTarget` pointing to a BlurTarget ref wrapping the content to blur.
|
|
65
|
+
*/
|
|
66
|
+
blur?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Reference to a BlurTarget component wrapping the content to blur.
|
|
69
|
+
* Required when using `blur` prop or elevation with blur configured.
|
|
70
|
+
*/
|
|
71
|
+
blurTarget?: RefObject<View | null>;
|
|
62
72
|
}
|
|
63
73
|
/**
|
|
64
74
|
* **📦 A layout component that can be used to compose other components**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Box.d.cts","names":[],"sources":["../../src/components/Box.tsx"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Box.d.cts","names":[],"sources":["../../src/components/Box.tsx"],"mappings":";;;;;;;;;UAmDU,QAAA,SAAiB,SAAA,EAAW,SAAA;EACpC,GAAA,GAAM,GAAA,CAAI,IAAA;EACV,SAAA,GAAY,cAAA;EACZ,eAAA,GAAkB,UAAA;EAClB,YAAA,GAAe,UAAA;EACf,oBAAA,GAAuB,UAAA;EACvB,kBAAA,GAAqB,UAAA;EACrB,uBAAA,GAA0B,UAAA;EAC1B,qBAAA,GAAwB,UAAA;EACxB,WAAA,GAAc,UAAA;EACd,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EACpB,WAAA,GAAc,UAAA;EACd,mBAAA,GAAsB,UAAA;EACtB,qBAAA,GAAwB,UAAA;EACxB,gBAAA,GAAmB,UAAA;EACnB,cAAA,GAAiB,UAAA;EACjB,cAAA,GAAiB,UAAA;EACjB,iBAAA,GAAoB,UAAA;EACpB,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EACb,SAAA,GAAY,UAAA;EACZ,IAAA,GAAO,UAAA;EACP,aAAA,GAAgB,UAAA;EAChB,QAAA,GAAW,UAAA;EACX,UAAA,GAAa,UAAA;EACb,QAAA,GAAW,UAAA;EACX,cAAA,GAAiB,UAAA;EAEjB,OAAA,GAAU,UAAA;EACV,QAAA,GAAW,UAAA;EAIX,OAAA,GAAU,UAAA;EACV,iBAAA,GAAoB,UAAA;EACpB,eAAA,GAAkB,UAAA;EAClB,aAAA,GAAgB,UAAA;EAChB,UAAA,GAAa,UAAA;EACb,YAAA,GAAe,UAAA;EACf,UAAA,GAAa,UAAA;EACb,MAAA,GAAS,UAAA;EACT,cAAA,GAAiB,UAAA;EACjB,gBAAA,GAAmB,UAAA;EACnB,YAAA,GAAe,UAAA;EACf,SAAA,GAAY,UAAA;EACZ,WAAA,GAAc,UAAA;EACd,SAAA,GAAY,UAAA;EACZ,SAAA,GAAY,UAAA;EACZ,MAAA,GAAS,UAAA;EACT,UAAA,GAAa,UAAA;EACb,WAAA,GAAc,UAAA;EACd,6BAAA;EACA,yBAAA;EAJS;;;;EAST,IAAA;EA5DyB;;;;EAiEzB,UAAA,GAAa,SAAA,CAAU,IAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+BnB,GAAA,EAAG,KAAA,CAAA,oBAAA,CAAA,QAAA"}
|