@yahoo/uds-mobile 2.1.0 → 2.3.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.
Files changed (207) hide show
  1. package/README.md +92 -0
  2. package/dist/_virtual/_rolldown/runtime.cjs +14 -0
  3. package/dist/_virtual/_rolldown/runtime.js +19 -0
  4. package/dist/bin/generateTheme.mjs +14 -0
  5. package/dist/components/{Avatar.d.mts → Avatar.d.ts} +2 -2
  6. package/dist/components/Avatar.d.ts.map +1 -0
  7. package/dist/components/{Avatar.mjs → Avatar.js} +4 -4
  8. package/dist/components/Avatar.js.map +1 -0
  9. package/dist/components/{Badge.d.mts → Badge.d.ts} +3 -3
  10. package/dist/components/Badge.d.ts.map +1 -0
  11. package/dist/components/{Badge.mjs → Badge.js} +4 -4
  12. package/dist/components/Badge.js.map +1 -0
  13. package/dist/components/BlurTarget.cjs +89 -0
  14. package/dist/components/BlurTarget.d.cts +52 -0
  15. package/dist/components/BlurTarget.d.cts.map +1 -0
  16. package/dist/components/BlurTarget.d.ts +52 -0
  17. package/dist/components/BlurTarget.d.ts.map +1 -0
  18. package/dist/components/BlurTarget.js +88 -0
  19. package/dist/components/BlurTarget.js.map +1 -0
  20. package/dist/components/Box.cjs +117 -20
  21. package/dist/components/Box.d.cts +11 -1
  22. package/dist/components/Box.d.cts.map +1 -1
  23. package/dist/components/{Box.d.mts → Box.d.ts} +14 -4
  24. package/dist/components/{Box.d.mts.map → Box.d.ts.map} +1 -1
  25. package/dist/components/Box.js +228 -0
  26. package/dist/components/Box.js.map +1 -0
  27. package/dist/components/{Button.d.mts → Button.d.ts} +4 -4
  28. package/dist/components/Button.d.ts.map +1 -0
  29. package/dist/components/{Button.mjs → Button.js} +6 -6
  30. package/dist/components/Button.js.map +1 -0
  31. package/dist/components/{Checkbox.d.mts → Checkbox.d.ts} +2 -2
  32. package/dist/components/Checkbox.d.ts.map +1 -0
  33. package/dist/components/{Checkbox.mjs → Checkbox.js} +7 -7
  34. package/dist/components/Checkbox.js.map +1 -0
  35. package/dist/components/{Chip.d.mts → Chip.d.ts} +3 -3
  36. package/dist/components/Chip.d.ts.map +1 -0
  37. package/dist/components/{Chip.mjs → Chip.js} +5 -5
  38. package/dist/components/Chip.js.map +1 -0
  39. package/dist/components/{HStack.d.mts → HStack.d.ts} +2 -2
  40. package/dist/components/HStack.d.ts.map +1 -0
  41. package/dist/components/{HStack.mjs → HStack.js} +2 -2
  42. package/dist/components/HStack.js.map +1 -0
  43. package/dist/components/{Icon.d.mts → Icon.d.ts} +2 -2
  44. package/dist/components/Icon.d.ts.map +1 -0
  45. package/dist/components/{Icon.mjs → Icon.js} +1 -1
  46. package/dist/components/Icon.js.map +1 -0
  47. package/dist/components/{IconButton.d.mts → IconButton.d.ts} +4 -4
  48. package/dist/components/IconButton.d.ts.map +1 -0
  49. package/dist/components/{IconButton.mjs → IconButton.js} +5 -5
  50. package/dist/components/IconButton.js.map +1 -0
  51. package/dist/components/{IconSlot.d.mts → IconSlot.d.ts} +2 -2
  52. package/dist/components/IconSlot.d.ts.map +1 -0
  53. package/dist/components/{IconSlot.mjs → IconSlot.js} +2 -2
  54. package/dist/components/IconSlot.js.map +1 -0
  55. package/dist/components/{Image.d.mts → Image.d.ts} +2 -2
  56. package/dist/components/Image.d.ts.map +1 -0
  57. package/dist/components/{Image.mjs → Image.js} +1 -1
  58. package/dist/components/Image.js.map +1 -0
  59. package/dist/components/{Input.d.mts → Input.d.ts} +4 -4
  60. package/dist/components/Input.d.ts.map +1 -0
  61. package/dist/components/{Input.mjs → Input.js} +5 -5
  62. package/dist/components/Input.js.map +1 -0
  63. package/dist/components/{Link.d.mts → Link.d.ts} +4 -4
  64. package/dist/components/Link.d.ts.map +1 -0
  65. package/dist/components/{Link.mjs → Link.js} +2 -2
  66. package/dist/components/Link.js.map +1 -0
  67. package/dist/components/{Pressable.d.mts → Pressable.d.ts} +2 -2
  68. package/dist/components/Pressable.d.ts.map +1 -0
  69. package/dist/components/{Pressable.mjs → Pressable.js} +1 -1
  70. package/dist/components/Pressable.js.map +1 -0
  71. package/dist/components/{Radio.d.mts → Radio.d.ts} +2 -2
  72. package/dist/components/Radio.d.ts.map +1 -0
  73. package/dist/components/{Radio.mjs → Radio.js} +6 -6
  74. package/dist/components/Radio.js.map +1 -0
  75. package/dist/components/{Screen.d.mts → Screen.d.ts} +2 -2
  76. package/dist/components/Screen.d.ts.map +1 -0
  77. package/dist/components/{Screen.mjs → Screen.js} +5 -5
  78. package/dist/components/Screen.js.map +1 -0
  79. package/dist/components/{Switch.d.mts → Switch.d.ts} +3 -3
  80. package/dist/components/Switch.d.ts.map +1 -0
  81. package/dist/components/{Switch.mjs → Switch.js} +6 -6
  82. package/dist/components/Switch.js.map +1 -0
  83. package/dist/components/{Text.d.mts → Text.d.ts} +1 -1
  84. package/dist/components/Text.d.ts.map +1 -0
  85. package/dist/components/{Text.mjs → Text.js} +1 -1
  86. package/dist/components/Text.js.map +1 -0
  87. package/dist/components/{VStack.d.mts → VStack.d.ts} +2 -2
  88. package/dist/components/VStack.d.ts.map +1 -0
  89. package/dist/components/{VStack.mjs → VStack.js} +2 -2
  90. package/dist/components/VStack.js.map +1 -0
  91. package/dist/jest/index.cjs +27 -0
  92. package/dist/jest/index.d.cts +19 -0
  93. package/dist/jest/index.d.cts.map +1 -0
  94. package/dist/jest/index.d.ts +19 -0
  95. package/dist/jest/index.d.ts.map +1 -0
  96. package/dist/jest/index.js +25 -0
  97. package/dist/jest/index.js.map +1 -0
  98. package/dist/jest/mocks/icons.cjs +56 -0
  99. package/dist/jest/mocks/icons.d.cts +24 -0
  100. package/dist/jest/mocks/icons.d.cts.map +1 -0
  101. package/dist/jest/mocks/icons.d.ts +24 -0
  102. package/dist/jest/mocks/icons.d.ts.map +1 -0
  103. package/dist/jest/mocks/icons.js +46 -0
  104. package/dist/jest/mocks/icons.js.map +1 -0
  105. package/dist/jest/mocks/react-native.cjs +212 -0
  106. package/dist/jest/mocks/react-native.d.cts +293 -0
  107. package/dist/jest/mocks/react-native.d.cts.map +1 -0
  108. package/dist/jest/mocks/react-native.d.ts +293 -0
  109. package/dist/jest/mocks/react-native.d.ts.map +1 -0
  110. package/dist/jest/mocks/react-native.js +180 -0
  111. package/dist/jest/mocks/react-native.js.map +1 -0
  112. package/dist/jest/mocks/reanimated.cjs +249 -0
  113. package/dist/jest/mocks/reanimated.d.cts +150 -0
  114. package/dist/jest/mocks/reanimated.d.cts.map +1 -0
  115. package/dist/jest/mocks/reanimated.d.ts +150 -0
  116. package/dist/jest/mocks/reanimated.d.ts.map +1 -0
  117. package/dist/jest/mocks/reanimated.js +210 -0
  118. package/dist/jest/mocks/reanimated.js.map +1 -0
  119. package/dist/jest/mocks/styles.cjs +327 -0
  120. package/dist/jest/mocks/styles.d.cts +33 -0
  121. package/dist/jest/mocks/styles.d.cts.map +1 -0
  122. package/dist/jest/mocks/styles.d.ts +33 -0
  123. package/dist/jest/mocks/styles.d.ts.map +1 -0
  124. package/dist/jest/mocks/styles.js +310 -0
  125. package/dist/jest/mocks/styles.js.map +1 -0
  126. package/dist/jest/mocks/svg.cjs +133 -0
  127. package/dist/jest/mocks/svg.d.cts +137 -0
  128. package/dist/jest/mocks/svg.d.cts.map +1 -0
  129. package/dist/jest/mocks/svg.d.ts +137 -0
  130. package/dist/jest/mocks/svg.d.ts.map +1 -0
  131. package/dist/jest/mocks/svg.js +100 -0
  132. package/dist/jest/mocks/svg.js.map +1 -0
  133. package/dist/jest/mocks/unistyles.cjs +143 -0
  134. package/dist/jest/mocks/unistyles.d.cts +197 -0
  135. package/dist/jest/mocks/unistyles.d.cts.map +1 -0
  136. package/dist/jest/mocks/unistyles.d.ts +197 -0
  137. package/dist/jest/mocks/unistyles.d.ts.map +1 -0
  138. package/dist/jest/mocks/unistyles.js +132 -0
  139. package/dist/jest/mocks/unistyles.js.map +1 -0
  140. package/dist/jest/setup.cjs +40 -0
  141. package/dist/jest/setup.d.cts +11 -0
  142. package/dist/jest/setup.d.cts.map +1 -0
  143. package/dist/jest/setup.d.ts +11 -0
  144. package/dist/jest/setup.d.ts.map +1 -0
  145. package/dist/jest/setup.js +39 -0
  146. package/dist/jest/setup.js.map +1 -0
  147. package/dist/motion-tokens/dist/{index.d.mts → index.d.ts} +2 -2
  148. package/dist/motion-tokens/dist/index.d.ts.map +1 -0
  149. package/dist/motion-tokens/dist/{index.mjs → index.js} +1 -1
  150. package/dist/motion-tokens/dist/index.js.map +1 -0
  151. package/dist/{motion.d.mts → motion.d.ts} +3 -3
  152. package/dist/motion.d.ts.map +1 -0
  153. package/dist/{motion.mjs → motion.js} +2 -2
  154. package/dist/motion.js.map +1 -0
  155. package/dist/types/dist/{index.d.mts → index.d.ts} +1 -1
  156. package/dist/types/dist/index.d.ts.map +1 -0
  157. package/dist/{types.d.mts → types.d.ts} +1 -1
  158. package/dist/types.d.ts.map +1 -0
  159. package/dist/{types.mjs → types.js} +0 -1
  160. package/fonts/index.cjs +205 -205
  161. package/fonts/index.mjs +205 -205
  162. package/generated/unistyles.d.ts +9 -0
  163. package/package.json +65 -41
  164. package/dist/components/Avatar.d.mts.map +0 -1
  165. package/dist/components/Avatar.mjs.map +0 -1
  166. package/dist/components/Badge.d.mts.map +0 -1
  167. package/dist/components/Badge.mjs.map +0 -1
  168. package/dist/components/Box.mjs +0 -131
  169. package/dist/components/Box.mjs.map +0 -1
  170. package/dist/components/Button.d.mts.map +0 -1
  171. package/dist/components/Button.mjs.map +0 -1
  172. package/dist/components/Checkbox.d.mts.map +0 -1
  173. package/dist/components/Checkbox.mjs.map +0 -1
  174. package/dist/components/Chip.d.mts.map +0 -1
  175. package/dist/components/Chip.mjs.map +0 -1
  176. package/dist/components/HStack.d.mts.map +0 -1
  177. package/dist/components/HStack.mjs.map +0 -1
  178. package/dist/components/Icon.d.mts.map +0 -1
  179. package/dist/components/Icon.mjs.map +0 -1
  180. package/dist/components/IconButton.d.mts.map +0 -1
  181. package/dist/components/IconButton.mjs.map +0 -1
  182. package/dist/components/IconSlot.d.mts.map +0 -1
  183. package/dist/components/IconSlot.mjs.map +0 -1
  184. package/dist/components/Image.d.mts.map +0 -1
  185. package/dist/components/Image.mjs.map +0 -1
  186. package/dist/components/Input.d.mts.map +0 -1
  187. package/dist/components/Input.mjs.map +0 -1
  188. package/dist/components/Link.d.mts.map +0 -1
  189. package/dist/components/Link.mjs.map +0 -1
  190. package/dist/components/Pressable.d.mts.map +0 -1
  191. package/dist/components/Pressable.mjs.map +0 -1
  192. package/dist/components/Radio.d.mts.map +0 -1
  193. package/dist/components/Radio.mjs.map +0 -1
  194. package/dist/components/Screen.d.mts.map +0 -1
  195. package/dist/components/Screen.mjs.map +0 -1
  196. package/dist/components/Switch.d.mts.map +0 -1
  197. package/dist/components/Switch.mjs.map +0 -1
  198. package/dist/components/Text.d.mts.map +0 -1
  199. package/dist/components/Text.mjs.map +0 -1
  200. package/dist/components/VStack.d.mts.map +0 -1
  201. package/dist/components/VStack.mjs.map +0 -1
  202. package/dist/motion-tokens/dist/index.d.mts.map +0 -1
  203. package/dist/motion-tokens/dist/index.mjs.map +0 -1
  204. package/dist/motion.d.mts.map +0 -1
  205. package/dist/motion.mjs.map +0 -1
  206. package/dist/types/dist/index.d.mts.map +0 -1
  207. package/dist/types.d.mts.map +0 -1
package/README.md CHANGED
@@ -9,6 +9,7 @@
9
9
  - [Icons](#icons)
10
10
  - [Fonts](#fonts)
11
11
  - [CLI](#cli)
12
+ - [Testing](#testing)
12
13
  - [Contributing](#contributing)
13
14
  - [API Reference](#api-reference)
14
15
 
@@ -553,6 +554,97 @@ export const breakpoints = {
553
554
  };
554
555
  ```
555
556
 
557
+ ## Testing
558
+
559
+ ### Jest Setup
560
+
561
+ UDS Mobile ships Jest mocks for native dependencies that don't work in Jest/JSDOM, allowing **real UDS components** to be tested without native module errors. This approach ensures your tests validate actual component behavior.
562
+
563
+ #### Quick Start
564
+
565
+ Add the setup file to your Jest config:
566
+
567
+ ```js
568
+ // jest.config.js
569
+ module.exports = {
570
+ preset: 'react-native',
571
+ setupFilesAfterEnv: ['@yahoo/uds-mobile/jest'],
572
+ transformIgnorePatterns: [
573
+ 'node_modules/(?!(@yahoo/uds-mobile|@yahoo/uds-icons|react-native|@react-native)/)',
574
+ ],
575
+ };
576
+ ```
577
+
578
+ Or import manually in your setup file:
579
+
580
+ ```js
581
+ // jest.setup.js
582
+ import '@yahoo/uds-mobile/jest';
583
+ ```
584
+
585
+ #### What Gets Mocked
586
+
587
+ The setup automatically mocks these native dependencies:
588
+
589
+ | Package | What's Mocked |
590
+ | ------------------------- | ----------------------------------------------------------------------------------- |
591
+ | `react-native-unistyles` | `useUnistyles()`, `StyleSheet.create()`, `UnistylesRuntime` |
592
+ | `react-native-reanimated` | Animated components, hooks (`useSharedValue`, `useAnimatedStyle`), timing functions |
593
+ | `react-native-svg` | `SvgXml`, SVG shape components |
594
+ | `@yahoo/uds-icons` | `glyphMap`, `svgMap`, `ICON_SIZE_MAP` |
595
+
596
+ #### Example Test
597
+
598
+ ```tsx
599
+ import { render, fireEvent } from '@testing-library/react-native';
600
+ import { Button } from '@yahoo/uds-mobile/Button';
601
+ import { Text } from '@yahoo/uds-mobile/Text';
602
+ import { VStack } from '@yahoo/uds-mobile/VStack';
603
+
604
+ test('renders button with text and handles press', () => {
605
+ const onPress = jest.fn();
606
+
607
+ const { getByRole, getByText } = render(
608
+ <VStack>
609
+ <Button variant="primary" onPress={onPress}>
610
+ Save
611
+ </Button>
612
+ </VStack>,
613
+ );
614
+
615
+ expect(getByText('Save')).toBeTruthy();
616
+
617
+ fireEvent.press(getByRole('button'));
618
+ expect(onPress).toHaveBeenCalled();
619
+ });
620
+ ```
621
+
622
+ #### Benefits
623
+
624
+ - **Real component testing**: Tests validate actual component behavior, not stubs
625
+ - **No native module errors**: Required native dependencies are properly mocked
626
+ - **Zero configuration**: Just add the setup file and transformIgnorePatterns
627
+ - **Catches regressions**: Tests break when component behavior changes
628
+
629
+ #### Manual Mock Access
630
+
631
+ If you need to customize mocks, individual modules are exported:
632
+
633
+ ```js
634
+ import { mocks } from '@yahoo/uds-mobile/jest';
635
+
636
+ // Override a specific mock
637
+ jest.mock('react-native-unistyles', () => ({
638
+ ...mocks.unistyles,
639
+ useUnistyles: () => ({
640
+ theme: {
641
+ /* custom theme */
642
+ },
643
+ rt: { themeName: 'dark' },
644
+ }),
645
+ }));
646
+ ```
647
+
556
648
  ## Contributing
557
649
 
558
650
  See [CONTRIBUTING.md](./CONTRIBUTING.md) for the development workflow, architecture details, and internal documentation.
@@ -6,6 +6,19 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __exportAll = (all, no_symbols) => {
10
+ let target = {};
11
+ for (var name in all) {
12
+ __defProp(target, name, {
13
+ get: all[name],
14
+ enumerable: true
15
+ });
16
+ }
17
+ if (!no_symbols) {
18
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
19
+ }
20
+ return target;
21
+ };
9
22
  var __copyProps = (to, from, except, desc) => {
10
23
  if (from && typeof from === "object" || typeof from === "function") {
11
24
  for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
@@ -27,4 +40,5 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
40
 
28
41
  //#endregion
29
42
 
43
+ exports.__exportAll = __exportAll;
30
44
  exports.__toESM = __toESM;
@@ -0,0 +1,19 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ //#region \0rolldown/runtime.js
3
+ var __defProp = Object.defineProperty;
4
+ var __exportAll = (all, no_symbols) => {
5
+ let target = {};
6
+ for (var name in all) {
7
+ __defProp(target, name, {
8
+ get: all[name],
9
+ enumerable: true
10
+ });
11
+ }
12
+ if (!no_symbols) {
13
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
14
+ }
15
+ return target;
16
+ };
17
+
18
+ //#endregion
19
+ export { __exportAll };
@@ -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.mjs";
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.mts.map
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.mjs";
3
- import { IconSlot } from "./IconSlot.mjs";
4
- import { Text as Text$1 } from "./Text.mjs";
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.mjs.map
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.mjs";
3
- import { IconSlotType } from "./IconSlot.mjs";
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.mts.map
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.mjs";
3
- import { Text } from "./Text.mjs";
4
- import { HStack } from "./HStack.mjs";
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.mjs.map
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"}