@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.
- package/README.md +92 -0
- package/dist/_virtual/_rolldown/runtime.cjs +14 -0
- package/dist/_virtual/_rolldown/runtime.js +19 -0
- 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/jest/index.cjs +27 -0
- package/dist/jest/index.d.cts +19 -0
- package/dist/jest/index.d.cts.map +1 -0
- package/dist/jest/index.d.ts +19 -0
- package/dist/jest/index.d.ts.map +1 -0
- package/dist/jest/index.js +25 -0
- package/dist/jest/index.js.map +1 -0
- package/dist/jest/mocks/icons.cjs +56 -0
- package/dist/jest/mocks/icons.d.cts +24 -0
- package/dist/jest/mocks/icons.d.cts.map +1 -0
- package/dist/jest/mocks/icons.d.ts +24 -0
- package/dist/jest/mocks/icons.d.ts.map +1 -0
- package/dist/jest/mocks/icons.js +46 -0
- package/dist/jest/mocks/icons.js.map +1 -0
- package/dist/jest/mocks/react-native.cjs +212 -0
- package/dist/jest/mocks/react-native.d.cts +293 -0
- package/dist/jest/mocks/react-native.d.cts.map +1 -0
- package/dist/jest/mocks/react-native.d.ts +293 -0
- package/dist/jest/mocks/react-native.d.ts.map +1 -0
- package/dist/jest/mocks/react-native.js +180 -0
- package/dist/jest/mocks/react-native.js.map +1 -0
- package/dist/jest/mocks/reanimated.cjs +249 -0
- package/dist/jest/mocks/reanimated.d.cts +150 -0
- package/dist/jest/mocks/reanimated.d.cts.map +1 -0
- package/dist/jest/mocks/reanimated.d.ts +150 -0
- package/dist/jest/mocks/reanimated.d.ts.map +1 -0
- package/dist/jest/mocks/reanimated.js +210 -0
- package/dist/jest/mocks/reanimated.js.map +1 -0
- package/dist/jest/mocks/styles.cjs +327 -0
- package/dist/jest/mocks/styles.d.cts +33 -0
- package/dist/jest/mocks/styles.d.cts.map +1 -0
- package/dist/jest/mocks/styles.d.ts +33 -0
- package/dist/jest/mocks/styles.d.ts.map +1 -0
- package/dist/jest/mocks/styles.js +310 -0
- package/dist/jest/mocks/styles.js.map +1 -0
- package/dist/jest/mocks/svg.cjs +133 -0
- package/dist/jest/mocks/svg.d.cts +137 -0
- package/dist/jest/mocks/svg.d.cts.map +1 -0
- package/dist/jest/mocks/svg.d.ts +137 -0
- package/dist/jest/mocks/svg.d.ts.map +1 -0
- package/dist/jest/mocks/svg.js +100 -0
- package/dist/jest/mocks/svg.js.map +1 -0
- package/dist/jest/mocks/unistyles.cjs +143 -0
- package/dist/jest/mocks/unistyles.d.cts +197 -0
- package/dist/jest/mocks/unistyles.d.cts.map +1 -0
- package/dist/jest/mocks/unistyles.d.ts +197 -0
- package/dist/jest/mocks/unistyles.d.ts.map +1 -0
- package/dist/jest/mocks/unistyles.js +132 -0
- package/dist/jest/mocks/unistyles.js.map +1 -0
- package/dist/jest/setup.cjs +40 -0
- package/dist/jest/setup.d.cts +11 -0
- package/dist/jest/setup.d.cts.map +1 -0
- package/dist/jest/setup.d.ts +11 -0
- package/dist/jest/setup.d.ts.map +1 -0
- package/dist/jest/setup.js +39 -0
- package/dist/jest/setup.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 +65 -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
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.
|
|
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"}
|