@reown/appkit-ui-react-native 2.0.0-alpha.3 → 2.0.0-alpha.5

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 (99) hide show
  1. package/lib/commonjs/components/wui-card/index.js +1 -3
  2. package/lib/commonjs/components/wui-card/index.js.map +1 -1
  3. package/lib/commonjs/components/wui-card/styles.js +1 -1
  4. package/lib/commonjs/components/wui-card/styles.js.map +1 -1
  5. package/lib/commonjs/components/wui-loading-hexagon/index.js +9 -6
  6. package/lib/commonjs/components/wui-loading-hexagon/index.js.map +1 -1
  7. package/lib/commonjs/components/wui-loading-spinner/index.js +7 -5
  8. package/lib/commonjs/components/wui-loading-spinner/index.js.map +1 -1
  9. package/lib/commonjs/components/wui-loading-thumbnail/index.js +25 -12
  10. package/lib/commonjs/components/wui-loading-thumbnail/index.js.map +1 -1
  11. package/lib/commonjs/components/wui-modal/index.js +28 -28
  12. package/lib/commonjs/components/wui-modal/index.js.map +1 -1
  13. package/lib/commonjs/components/wui-modal/styles.js +10 -9
  14. package/lib/commonjs/components/wui-modal/styles.js.map +1 -1
  15. package/lib/commonjs/components/wui-shimmer/index.js +92 -32
  16. package/lib/commonjs/components/wui-shimmer/index.js.map +1 -1
  17. package/lib/commonjs/composites/wui-card-select/index.js +46 -44
  18. package/lib/commonjs/composites/wui-card-select/index.js.map +1 -1
  19. package/lib/commonjs/composites/wui-card-select-loader/index.js +7 -3
  20. package/lib/commonjs/composites/wui-card-select-loader/index.js.map +1 -1
  21. package/lib/commonjs/composites/wui-qr-code/index.js +7 -3
  22. package/lib/commonjs/composites/wui-qr-code/index.js.map +1 -1
  23. package/lib/commonjs/composites/wui-token-button/index.js +1 -1
  24. package/lib/commonjs/context/ThemeContext.js +18 -16
  25. package/lib/commonjs/context/ThemeContext.js.map +1 -1
  26. package/lib/commonjs/hooks/useCustomDimensions.js +42 -0
  27. package/lib/commonjs/hooks/useCustomDimensions.js.map +1 -0
  28. package/lib/commonjs/index.js +7 -0
  29. package/lib/commonjs/index.js.map +1 -1
  30. package/lib/commonjs/utils/QRCodeUtil.js +2 -2
  31. package/lib/commonjs/utils/QRCodeUtil.js.map +1 -1
  32. package/lib/module/components/wui-card/index.js +2 -4
  33. package/lib/module/components/wui-card/index.js.map +1 -1
  34. package/lib/module/components/wui-card/styles.js +1 -1
  35. package/lib/module/components/wui-card/styles.js.map +1 -1
  36. package/lib/module/components/wui-loading-hexagon/index.js +10 -7
  37. package/lib/module/components/wui-loading-hexagon/index.js.map +1 -1
  38. package/lib/module/components/wui-loading-spinner/index.js +8 -6
  39. package/lib/module/components/wui-loading-spinner/index.js.map +1 -1
  40. package/lib/module/components/wui-loading-thumbnail/index.js +26 -13
  41. package/lib/module/components/wui-loading-thumbnail/index.js.map +1 -1
  42. package/lib/module/components/wui-modal/index.js +30 -30
  43. package/lib/module/components/wui-modal/index.js.map +1 -1
  44. package/lib/module/components/wui-modal/styles.js +10 -9
  45. package/lib/module/components/wui-modal/styles.js.map +1 -1
  46. package/lib/module/components/wui-shimmer/index.js +93 -32
  47. package/lib/module/components/wui-shimmer/index.js.map +1 -1
  48. package/lib/module/composites/wui-card-select/index.js +47 -45
  49. package/lib/module/composites/wui-card-select/index.js.map +1 -1
  50. package/lib/module/composites/wui-card-select-loader/index.js +5 -1
  51. package/lib/module/composites/wui-card-select-loader/index.js.map +1 -1
  52. package/lib/module/composites/wui-qr-code/index.js +6 -3
  53. package/lib/module/composites/wui-qr-code/index.js.map +1 -1
  54. package/lib/module/composites/wui-token-button/index.js +1 -1
  55. package/lib/module/context/ThemeContext.js +19 -17
  56. package/lib/module/context/ThemeContext.js.map +1 -1
  57. package/lib/module/hooks/useCustomDimensions.js +39 -0
  58. package/lib/module/hooks/useCustomDimensions.js.map +1 -0
  59. package/lib/module/index.js +10 -0
  60. package/lib/module/index.js.map +1 -1
  61. package/lib/module/utils/QRCodeUtil.js +3 -3
  62. package/lib/module/utils/QRCodeUtil.js.map +1 -1
  63. package/lib/typescript/components/wui-card/index.d.ts.map +1 -1
  64. package/lib/typescript/components/wui-loading-hexagon/index.d.ts.map +1 -1
  65. package/lib/typescript/components/wui-loading-spinner/index.d.ts.map +1 -1
  66. package/lib/typescript/components/wui-loading-thumbnail/index.d.ts.map +1 -1
  67. package/lib/typescript/components/wui-modal/index.d.ts.map +1 -1
  68. package/lib/typescript/components/wui-modal/styles.d.ts +9 -9
  69. package/lib/typescript/components/wui-modal/styles.d.ts.map +1 -1
  70. package/lib/typescript/components/wui-shimmer/index.d.ts +11 -3
  71. package/lib/typescript/components/wui-shimmer/index.d.ts.map +1 -1
  72. package/lib/typescript/composites/wui-card-select/index.d.ts +2 -2
  73. package/lib/typescript/composites/wui-card-select/index.d.ts.map +1 -1
  74. package/lib/typescript/composites/wui-card-select-loader/index.d.ts +3 -1
  75. package/lib/typescript/composites/wui-card-select-loader/index.d.ts.map +1 -1
  76. package/lib/typescript/composites/wui-qr-code/index.d.ts +3 -1
  77. package/lib/typescript/composites/wui-qr-code/index.d.ts.map +1 -1
  78. package/lib/typescript/context/ThemeContext.d.ts.map +1 -1
  79. package/lib/typescript/hooks/useCustomDimensions.d.ts +13 -0
  80. package/lib/typescript/hooks/useCustomDimensions.d.ts.map +1 -0
  81. package/lib/typescript/index.d.ts +6 -0
  82. package/lib/typescript/index.d.ts.map +1 -1
  83. package/package.json +5 -4
  84. package/src/components/wui-card/index.tsx +3 -5
  85. package/src/components/wui-card/styles.ts +1 -1
  86. package/src/components/wui-loading-hexagon/index.tsx +12 -10
  87. package/src/components/wui-loading-spinner/index.tsx +8 -6
  88. package/src/components/wui-loading-thumbnail/index.tsx +17 -10
  89. package/src/components/wui-modal/index.tsx +27 -28
  90. package/src/components/wui-modal/styles.ts +10 -9
  91. package/src/components/wui-shimmer/index.tsx +105 -39
  92. package/src/composites/wui-card-select/index.tsx +48 -48
  93. package/src/composites/wui-card-select-loader/index.tsx +5 -1
  94. package/src/composites/wui-qr-code/index.tsx +11 -3
  95. package/src/composites/wui-token-button/index.tsx +1 -1
  96. package/src/context/ThemeContext.tsx +17 -15
  97. package/src/hooks/useCustomDimensions.ts +41 -0
  98. package/src/index.ts +7 -0
  99. package/src/utils/QRCodeUtil.tsx +3 -3
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef, type ReactNode } from 'react';
1
+ import { useEffect, useMemo, useRef, type ReactNode } from 'react';
2
2
  import { Animated, Easing, View } from 'react-native';
3
3
  import Svg, { Path, Use } from 'react-native-svg';
4
4
  import { useTheme } from '../../hooks/useTheme';
@@ -6,6 +6,9 @@ import styles from './styles';
6
6
 
7
7
  const AnimatedUse = Animated.createAnimatedComponent(Use);
8
8
 
9
+ const HEXAGON_PATH =
10
+ 'M17.22 5.295c3.877-2.277 5.737-3.363 7.72-3.726a11.44 11.44 0 0 1 4.12 0c1.983.363 3.844 1.45 7.72 3.726l6.065 3.562c3.876 2.276 5.731 3.372 7.032 4.938a11.896 11.896 0 0 1 2.06 3.63c.683 1.928.688 4.11.688 8.663v7.124c0 4.553-.005 6.735-.688 8.664a11.896 11.896 0 0 1-2.06 3.63c-1.3 1.565-3.156 2.66-7.032 4.937l-6.065 3.563c-3.877 2.276-5.737 3.362-7.72 3.725a11.46 11.46 0 0 1-4.12 0c-1.983-.363-3.844-1.449-7.72-3.726l-6.065-3.562c-3.876-2.276-5.731-3.372-7.032-4.938a11.885 11.885 0 0 1-2.06-3.63c-.682-1.928-.688-4.11-.688-8.663v-7.124c0-4.553.006-6.735.688-8.664a11.885 11.885 0 0 1 2.06-3.63c1.3-1.565 3.156-2.66 7.032-4.937l6.065-3.562Z';
11
+
9
12
  export interface LoadingHexagonProps {
10
13
  children?: ReactNode;
11
14
  paused?: boolean;
@@ -29,20 +32,19 @@ export function LoadingHexagon({ children, paused }: LoadingHexagonProps) {
29
32
  return () => {
30
33
  loop.stop();
31
34
  };
32
- }, [spinValue]);
35
+ }, []);
33
36
 
34
- const spin = spinValue.current.interpolate({
35
- inputRange: [0, 1],
36
- outputRange: [0, -172]
37
- });
37
+ const spin = useMemo(() => {
38
+ return spinValue.current.interpolate({
39
+ inputRange: [0, 1],
40
+ outputRange: [0, -172]
41
+ });
42
+ }, []);
38
43
 
39
44
  return (
40
45
  <View style={styles.container}>
41
46
  <Svg width={120} height={120} viewBox="0 0 54 59" style={styles.loader} fill="none">
42
- <Path
43
- id="wui-loader-path"
44
- d="M17.22 5.295c3.877-2.277 5.737-3.363 7.72-3.726a11.44 11.44 0 0 1 4.12 0c1.983.363 3.844 1.45 7.72 3.726l6.065 3.562c3.876 2.276 5.731 3.372 7.032 4.938a11.896 11.896 0 0 1 2.06 3.63c.683 1.928.688 4.11.688 8.663v7.124c0 4.553-.005 6.735-.688 8.664a11.896 11.896 0 0 1-2.06 3.63c-1.3 1.565-3.156 2.66-7.032 4.937l-6.065 3.563c-3.877 2.276-5.737 3.362-7.72 3.725a11.46 11.46 0 0 1-4.12 0c-1.983-.363-3.844-1.449-7.72-3.726l-6.065-3.562c-3.876-2.276-5.731-3.372-7.032-4.938a11.885 11.885 0 0 1-2.06-3.63c-.682-1.928-.688-4.11-.688-8.663v-7.124c0-4.553.006-6.735.688-8.664a11.885 11.885 0 0 1 2.06-3.63c1.3-1.565 3.156-2.66 7.032-4.937l6.065-3.562Z"
45
- />
47
+ <Path id="wui-loader-path" d={HEXAGON_PATH} />
46
48
  <AnimatedUse
47
49
  stroke={paused ? 'transparent' : Theme['accent-100']}
48
50
  strokeDasharray="54, 118"
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef } from 'react';
1
+ import { useEffect, useMemo, useRef } from 'react';
2
2
  import { Animated, Easing, View, type StyleProp, type ViewStyle } from 'react-native';
3
3
  import Svg, { Circle } from 'react-native-svg';
4
4
  import { useTheme } from '../../hooks/useTheme';
@@ -39,12 +39,14 @@ export function LoadingSpinner({
39
39
  return () => {
40
40
  loop.stop();
41
41
  };
42
- }, [spinValue]);
42
+ }, []);
43
43
 
44
- const spin = spinValue.current.interpolate({
45
- inputRange: [0, 1],
46
- outputRange: ['0deg', '360deg']
47
- });
44
+ const spin = useMemo(() => {
45
+ return spinValue.current.interpolate({
46
+ inputRange: [0, 1],
47
+ outputRange: ['0deg', '360deg']
48
+ });
49
+ }, []);
48
50
 
49
51
  return (
50
52
  <View style={[styles.container, style]} testID={testID}>
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef, type ReactNode } from 'react';
1
+ import { useEffect, useMemo, useRef, type ReactNode } from 'react';
2
2
  import { Animated, Easing, View } from 'react-native';
3
3
  import Svg, { Rect } from 'react-native-svg';
4
4
  import { useTheme } from '../../hooks/useTheme';
@@ -38,23 +38,30 @@ export function LoadingThumbnail({
38
38
  return () => {
39
39
  loop.stop();
40
40
  };
41
- }, [spinValue]);
41
+ }, []);
42
42
 
43
- // Calculate one side of the Rectangle with borders
44
- const sideLength = rectangleSize - borderRadius * 2 + (Math.PI * borderRadius) / 2;
43
+ const { sideLength, strokeColor, containerStyle } = useMemo(() => {
44
+ const _sideLength = rectangleSize - borderRadius * 2 + (Math.PI * borderRadius) / 2;
45
+ const _strokeColor = paused ? 'transparent' : Theme['accent-100'];
46
+ const _containerStyle = { height: outerContainerSize, width: outerContainerSize };
45
47
 
46
- const spin = spinValue.current.interpolate({
47
- inputRange: [0, 1],
48
- outputRange: [0, -sideLength * 4]
49
- });
48
+ return { sideLength: _sideLength, strokeColor: _strokeColor, containerStyle: _containerStyle };
49
+ }, [rectangleSize, borderRadius, paused, Theme, outerContainerSize]);
50
+
51
+ const spin = useMemo(() => {
52
+ return spinValue.current.interpolate({
53
+ inputRange: [0, 1],
54
+ outputRange: [0, -sideLength * 4]
55
+ });
56
+ }, [sideLength]);
50
57
 
51
58
  return (
52
- <View style={[styles.container, { height: outerContainerSize, width: outerContainerSize }]}>
59
+ <View style={[styles.container, containerStyle]}>
53
60
  <Svg width={outerContainerSize} height={outerContainerSize} style={styles.loader}>
54
61
  <AnimatedRect
55
62
  height={rectangleSize}
56
63
  width={rectangleSize}
57
- stroke={paused ? 'transparent' : Theme['accent-100']}
64
+ stroke={strokeColor}
58
65
  strokeWidth={strokeWidth}
59
66
  x={strokeWidth / 2}
60
67
  y={strokeWidth / 2}
@@ -3,8 +3,9 @@ import {
3
3
  useWindowDimensions,
4
4
  Modal as RNModal,
5
5
  type ModalProps as RNModalProps,
6
- TouchableOpacity,
7
- Animated
6
+ Animated,
7
+ Pressable,
8
+ View
8
9
  } from 'react-native';
9
10
  import { useTheme } from '../../hooks/useTheme';
10
11
  import styles from './styles';
@@ -17,10 +18,11 @@ export type ModalProps = Pick<
17
18
  onBackdropPress?: () => void;
18
19
  };
19
20
 
21
+ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
22
+
20
23
  export function Modal({ visible, onBackdropPress, onRequestClose, testID, children }: ModalProps) {
21
- const Theme = useTheme();
22
24
  const { height } = useWindowDimensions();
23
-
25
+ const Theme = useTheme();
24
26
  const backdropOpacity = useRef(new Animated.Value(0)).current;
25
27
  const translateY = useRef(new Animated.Value(height)).current;
26
28
  const [showBackdrop, setShowBackdrop] = useState(false);
@@ -29,7 +31,8 @@ export function Modal({ visible, onBackdropPress, onRequestClose, testID, childr
29
31
 
30
32
  const onContentLayout = (event: any) => {
31
33
  const { height: measuredHeight } = event.nativeEvent.layout;
32
- setContentHeight(measuredHeight);
34
+
35
+ setContentHeight(measuredHeight > height ? height : measuredHeight);
33
36
  };
34
37
 
35
38
  // Handle modal visibility
@@ -109,31 +112,27 @@ export function Modal({ visible, onBackdropPress, onRequestClose, testID, childr
109
112
  }, [modalVisible, translateY, backdropOpacity, height]);
110
113
 
111
114
  return (
112
- <>
115
+ <RNModal
116
+ visible={modalVisible}
117
+ transparent
118
+ animationType="none"
119
+ statusBarTranslucent
120
+ onRequestClose={onRequestClose}
121
+ testID={testID}
122
+ >
113
123
  {showBackdrop ? (
114
- <Animated.View style={[styles.outerBackdrop, { opacity: backdropOpacity }]} />
124
+ <AnimatedPressable
125
+ style={[styles.backdrop, { opacity: backdropOpacity }]}
126
+ onPress={onBackdropPress}
127
+ />
115
128
  ) : null}
116
- <RNModal
117
- visible={modalVisible}
118
- transparent
119
- animationType="none"
120
- statusBarTranslucent
121
- onRequestClose={onRequestClose}
122
- testID={testID}
129
+ <AnimatedPressable
130
+ onPress={onBackdropPress}
131
+ style={[styles.modal, { transform: [{ translateY }] }]}
123
132
  >
124
- {showBackdrop ? (
125
- <TouchableOpacity
126
- style={styles.innerBackdropTouchable}
127
- activeOpacity={1}
128
- onPress={onBackdropPress}
129
- />
130
- ) : null}
131
- <Animated.View
132
- style={[styles.modal, { backgroundColor: Theme['bg-100'], transform: [{ translateY }] }]}
133
- >
134
- <Animated.View onLayout={onContentLayout}>{children}</Animated.View>
135
- </Animated.View>
136
- </RNModal>
137
- </>
133
+ <Animated.View onLayout={onContentLayout}>{children}</Animated.View>
134
+ <View style={[styles.bottomBackground, { backgroundColor: Theme['bg-100'] }]} />
135
+ </AnimatedPressable>
136
+ </RNModal>
138
137
  );
139
138
  }
@@ -2,18 +2,13 @@ import { StyleSheet } from 'react-native';
2
2
  import { BorderRadius } from '../../utils/ThemeUtil';
3
3
 
4
4
  export default StyleSheet.create({
5
- outerBackdrop: {
6
- position: 'absolute',
7
- top: 0,
8
- left: 0,
9
- right: 0,
10
- bottom: 0,
5
+ backdrop: {
6
+ flexGrow: 1,
11
7
  backgroundColor: 'rgba(0, 0, 0, 0.5)'
12
8
  },
13
- innerBackdropTouchable: {
14
- flexGrow: 1
15
- },
16
9
  modal: {
10
+ backgroundColor: 'transparent',
11
+ borderWidth: 0,
17
12
  borderTopLeftRadius: BorderRadius.l,
18
13
  borderTopRightRadius: BorderRadius.l,
19
14
  position: 'absolute',
@@ -21,5 +16,11 @@ export default StyleSheet.create({
21
16
  left: 0,
22
17
  right: 0,
23
18
  bottom: 0
19
+ },
20
+ bottomBackground: {
21
+ flexGrow: 1,
22
+ // workaround to fix the bottom background color
23
+ top: -2,
24
+ bottom: -20
24
25
  }
25
26
  });
@@ -1,66 +1,132 @@
1
- import { Svg, Rect } from 'react-native-svg';
2
- import { Animated, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
1
+ import { Animated, StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';
2
+ import { memo, useEffect, useRef, useState } from 'react';
3
3
  import { useTheme } from '../../hooks/useTheme';
4
4
 
5
- const AnimatedRect = Animated.createAnimatedComponent(Rect);
5
+ type PercentString = `${number}%`;
6
+ type ShimmerDimension = number | PercentString;
6
7
 
7
8
  export interface ShimmerProps {
8
- width?: number | string;
9
- height?: number | string;
9
+ width?: ShimmerDimension;
10
+ height?: ShimmerDimension;
10
11
  duration?: number;
11
12
  borderRadius?: number;
12
13
  backgroundColor?: string;
13
14
  foregroundColor?: string;
15
+ highlightWidthRatio?: number;
16
+ highlightOpacity?: number;
17
+ angle?: number; // in degrees
14
18
  style?: StyleProp<ViewStyle>;
15
19
  }
16
20
 
17
- export const Shimmer = ({
21
+ function Shimmer_({
18
22
  width = 200,
19
23
  height = 200,
20
24
  duration = 1000,
21
25
  borderRadius = 0,
22
26
  backgroundColor,
23
27
  foregroundColor,
28
+ highlightWidthRatio = 0.3,
29
+ highlightOpacity = 0.5,
30
+ angle = 20,
24
31
  style
25
- }: ShimmerProps) => {
26
- const animatedValue = new Animated.Value(0);
32
+ }: ShimmerProps) {
27
33
  const Theme = useTheme();
28
34
 
29
- const animatedProps = {
30
- fill: animatedValue.interpolate({
31
- inputRange: [0, 0.5, 1],
32
- outputRange: [
33
- backgroundColor ?? Theme['bg-200'],
34
- foregroundColor ?? Theme['bg-300'],
35
- backgroundColor ?? Theme['bg-200']
36
- ]
37
- }),
35
+ const [measuredWidth, setMeasuredWidth] = useState<number | null>(null);
36
+ const [measuredHeight, setMeasuredHeight] = useState<number | null>(null);
37
+
38
+ const translateRef = useRef(new Animated.Value(0));
39
+ const loopRef = useRef<Animated.CompositeAnimation | null>(null);
40
+
41
+ useEffect(() => {
42
+ if (!measuredWidth) {
43
+ return undefined;
44
+ }
45
+ const translateX = translateRef.current;
46
+ translateX.setValue(0);
47
+ const timing = Animated.timing(translateX, {
48
+ toValue: 1,
49
+ duration,
50
+ useNativeDriver: true
51
+ });
52
+ const loop = Animated.loop(timing);
53
+ loopRef.current = loop;
54
+
55
+ loop.start();
56
+
57
+ return () => {
58
+ loop.stop();
59
+ if (loopRef.current === loop) {
60
+ loopRef.current = null;
61
+ }
62
+ translateX.stopAnimation(() => {
63
+ translateX.setValue(0);
64
+ });
65
+ };
66
+ }, [duration, measuredWidth]);
67
+
68
+ const baseColor = backgroundColor ?? Theme['bg-200'];
69
+ const highlightColor = foregroundColor ?? Theme['bg-300'];
70
+
71
+ const onLayout = (event: any) => {
72
+ const { width: w, height: h } = event.nativeEvent.layout;
73
+ // Update measurements whenever they change to adapt to dynamic layout/orientation
74
+ if (measuredWidth == null || Math.abs(w - measuredWidth) > 0.5) {
75
+ setMeasuredWidth(w);
76
+ }
77
+ if (measuredHeight == null || Math.abs(h - measuredHeight) > 0.5) {
78
+ setMeasuredHeight(h);
79
+ }
80
+ };
81
+
82
+ // Compute animated translateX only if we have width
83
+ let animatedTranslateX: any = 0;
84
+ let bandWidth = 0;
85
+ if (measuredWidth) {
86
+ bandWidth = Math.max(8, measuredWidth * highlightWidthRatio);
87
+ const travel = measuredWidth + bandWidth * 2;
88
+ animatedTranslateX = translateRef.current.interpolate({
89
+ inputRange: [0, 1],
90
+ outputRange: [-bandWidth, travel - bandWidth]
91
+ });
92
+ }
93
+
94
+ const containerStyle: ViewStyle = {
38
95
  width,
39
96
  height,
40
- x: 0,
41
- y: 0,
42
- rx: borderRadius,
43
- ry: borderRadius
97
+ borderRadius,
98
+ overflow: 'hidden',
99
+ borderWidth: StyleSheet.hairlineWidth,
100
+ borderColor: Theme['bg-300'],
101
+ backgroundColor: baseColor
44
102
  };
45
103
 
46
- Animated.loop(
47
- Animated.timing(animatedValue, {
48
- toValue: 1,
49
- duration,
50
- useNativeDriver: false
51
- })
52
- ).start();
104
+ const bandStyle: ViewStyle = {
105
+ position: 'absolute',
106
+ top: measuredHeight ? -measuredHeight * 0.25 : 0,
107
+ bottom: measuredHeight ? -measuredHeight * 0.25 : 0,
108
+ width: bandWidth,
109
+ backgroundColor: highlightColor,
110
+ opacity: highlightOpacity
111
+ };
53
112
 
54
113
  return (
55
- <Svg
56
- width={width}
57
- height={height}
58
- style={[
59
- { borderWidth: StyleSheet.hairlineWidth, borderColor: Theme['bg-300'], borderRadius },
60
- style
61
- ]}
62
- >
63
- <AnimatedRect {...animatedProps} />
64
- </Svg>
114
+ <View onLayout={onLayout} style={[containerStyle, style]}>
115
+ {measuredWidth && measuredHeight ? (
116
+ <Animated.View
117
+ pointerEvents="none"
118
+ style={[
119
+ bandStyle,
120
+ {
121
+ transform: [{ translateX: animatedTranslateX }, { rotate: `${angle}deg` }]
122
+ }
123
+ ]}
124
+ />
125
+ ) : null}
126
+ </View>
65
127
  );
66
- };
128
+ }
129
+
130
+ export const Shimmer = memo(Shimmer_, () => {
131
+ return true;
132
+ });
@@ -1,4 +1,4 @@
1
- import { memo } from 'react';
1
+ import { memo, useMemo } from 'react';
2
2
  import { Animated, Pressable, View, type StyleProp, type ViewStyle } from 'react-native';
3
3
  import { Text } from '../../components/wui-text';
4
4
  import { IconBox } from '../wui-icon-box';
@@ -9,6 +9,7 @@ import { NetworkImage } from '../wui-network-image';
9
9
  import { WalletImage } from '../wui-wallet-image';
10
10
  import styles, { getBackgroundColor, ITEM_HEIGHT, ITEM_WIDTH } from './styles';
11
11
  import { UiUtil } from '../../utils/UiUtil';
12
+ import { FlexView } from '../../layout/wui-flex';
12
13
 
13
14
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
14
15
 
@@ -28,7 +29,7 @@ export interface CardSelectProps {
28
29
  testID?: string;
29
30
  }
30
31
 
31
- function _CardSelect({
32
+ function CardSelect_({
32
33
  name,
33
34
  type = 'wallet',
34
35
  imageSrc,
@@ -43,6 +44,7 @@ function _CardSelect({
43
44
  const Theme = useTheme();
44
45
  const normalbackgroundColor = getBackgroundColor({ selected, disabled, pressed: false });
45
46
  const pressedBackgroundColor = getBackgroundColor({ selected, disabled, pressed: true });
47
+ const Image = useMemo(() => (type === 'wallet' ? WalletImage : NetworkImage), [type]);
46
48
 
47
49
  const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
48
50
  Theme[normalbackgroundColor],
@@ -51,54 +53,52 @@ function _CardSelect({
51
53
 
52
54
  const textColor = disabled ? 'fg-300' : selected ? 'accent-100' : 'fg-100';
53
55
 
54
- const Image = type === 'wallet' ? WalletImage : NetworkImage;
55
-
56
- const templateInstalled = () => {
57
- if (!installed) return null;
58
-
59
- return (
60
- <IconBox
61
- icon="checkmark"
62
- iconSize="xs"
63
- iconColor={'success-100'}
64
- border
65
- borderSize={6}
66
- borderColor="bg-150"
67
- background
68
- backgroundColor="icon-box-bg-success-100"
69
- size="sm"
70
- style={styles.installedBox}
71
- />
72
- );
73
- };
74
-
75
56
  return (
76
- <AnimatedPressable
77
- onPress={onPress}
78
- onPressIn={setEndValue}
79
- onPressOut={setStartValue}
80
- disabled={disabled}
81
- style={[styles.container, { backgroundColor: animatedValue }, style]}
82
- testID={testID}
83
- >
84
- <View>
85
- <Image
86
- imageSrc={imageSrc}
87
- imageHeaders={imageHeaders}
88
- size="md"
89
- style={disabled ? styles.disabledImage : null}
90
- selected={selected}
91
- disabled={disabled}
92
- />
93
- {templateInstalled()}
94
- </View>
95
- <Text variant="tiny-500" color={textColor} style={styles.text} numberOfLines={1}>
96
- {UiUtil.getWalletName(name)}
97
- </Text>
98
- </AnimatedPressable>
57
+ <FlexView style={style} alignItems="center" justifyContent="center">
58
+ <AnimatedPressable
59
+ onPress={onPress}
60
+ onPressIn={setEndValue}
61
+ onPressOut={setStartValue}
62
+ disabled={disabled}
63
+ style={[styles.container, { backgroundColor: animatedValue }]}
64
+ testID={testID}
65
+ >
66
+ <View>
67
+ <Image
68
+ imageSrc={imageSrc}
69
+ imageHeaders={imageHeaders}
70
+ size="md"
71
+ style={disabled ? styles.disabledImage : null}
72
+ selected={selected}
73
+ disabled={disabled}
74
+ />
75
+ {installed ? (
76
+ <IconBox
77
+ icon="checkmark"
78
+ iconSize="xs"
79
+ iconColor={'success-100'}
80
+ border
81
+ borderSize={6}
82
+ borderColor="bg-150"
83
+ background
84
+ backgroundColor="icon-box-bg-success-100"
85
+ size="sm"
86
+ style={styles.installedBox}
87
+ />
88
+ ) : null}
89
+ </View>
90
+ <Text variant="tiny-500" color={textColor} style={styles.text} numberOfLines={1}>
91
+ {UiUtil.getWalletName(name)}
92
+ </Text>
93
+ </AnimatedPressable>
94
+ </FlexView>
99
95
  );
100
96
  }
101
97
 
102
- export const CardSelect = memo(_CardSelect, (prevProps, nextProps) => {
103
- return prevProps.name === nextProps.name;
98
+ export const CardSelect = memo(CardSelect_, (prevProps, nextProps) => {
99
+ return (
100
+ prevProps.name === nextProps.name &&
101
+ prevProps.imageSrc === nextProps.imageSrc &&
102
+ prevProps.selected === nextProps.selected
103
+ );
104
104
  });
@@ -1,3 +1,4 @@
1
+ import { memo } from 'react';
1
2
  import { type StyleProp, type ViewStyle } from 'react-native';
2
3
  import { BorderRadius, Spacing, WalletImageSize } from '../../utils/ThemeUtil';
3
4
  import { useTheme } from '../../hooks/useTheme';
@@ -11,7 +12,7 @@ export interface CardSelectLoaderProps {
11
12
  style?: StyleProp<ViewStyle>;
12
13
  }
13
14
 
14
- export function CardSelectLoader({ style }: CardSelectLoaderProps) {
15
+ export function CardSelectLoader_({ style }: CardSelectLoaderProps) {
15
16
  const Theme = useTheme();
16
17
 
17
18
  return (
@@ -34,3 +35,6 @@ export function CardSelectLoader({ style }: CardSelectLoaderProps) {
34
35
  </FlexView>
35
36
  );
36
37
  }
38
+ export const CardSelectLoader = memo(CardSelectLoader_, () => {
39
+ return true;
40
+ });
@@ -1,4 +1,4 @@
1
- import { useMemo } from 'react';
1
+ import { memo, useMemo } from 'react';
2
2
  import { View, type StyleProp, type ViewStyle } from 'react-native';
3
3
  import Svg from 'react-native-svg';
4
4
  import { Icon } from '../../components/wui-icon';
@@ -19,7 +19,7 @@ export interface QrCodeProps {
19
19
  style?: StyleProp<ViewStyle>;
20
20
  }
21
21
 
22
- export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }: QrCodeProps) {
22
+ export function QrCode_({ size, uri, imageSrc, testID, arenaClear, icon, style }: QrCodeProps) {
23
23
  const Theme = LightTheme;
24
24
  const containerPadding = Spacing.l;
25
25
  const qrSize = size - containerPadding * 2;
@@ -62,7 +62,7 @@ export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }:
62
62
  <View
63
63
  style={[
64
64
  styles.container,
65
- { width: size, backgroundColor: Theme['bg-100'], padding: containerPadding },
65
+ { width: size, backgroundColor: Theme['inverse-100'], padding: containerPadding },
66
66
  style
67
67
  ]}
68
68
  testID={testID}
@@ -76,3 +76,11 @@ export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }:
76
76
  <Shimmer width={size} height={size} borderRadius={BorderRadius.l} />
77
77
  );
78
78
  }
79
+
80
+ export const QrCode = memo(QrCode_, (prevProps, nextProps) => {
81
+ return (
82
+ prevProps.size === nextProps.size &&
83
+ prevProps.uri === nextProps.uri &&
84
+ prevProps.style === nextProps.style
85
+ );
86
+ });
@@ -28,7 +28,7 @@ export function TokenButton({
28
28
  onPress,
29
29
  style,
30
30
  disabled = false,
31
- placeholder = 'Select token',
31
+ placeholder = 'Select Token',
32
32
  chevron,
33
33
  renderClip,
34
34
  testID
@@ -1,5 +1,5 @@
1
1
  import { useColorScheme } from 'react-native';
2
- import { createContext, useContext, type ReactNode } from 'react';
2
+ import { createContext, useContext, useMemo, type ReactNode } from 'react';
3
3
  import type { ThemeMode, ThemeVariables } from '@reown/appkit-common-react-native';
4
4
 
5
5
  import { DarkTheme, LightTheme, getAccentColors } from '../utils/ThemeUtil';
@@ -18,27 +18,29 @@ interface ThemeProviderProps {
18
18
  }
19
19
 
20
20
  export function ThemeProvider({ children, themeMode, themeVariables }: ThemeProviderProps) {
21
- return (
22
- <ThemeContext.Provider value={{ themeMode, themeVariables }}>{children}</ThemeContext.Provider>
23
- );
21
+ const contextValue = useMemo(() => ({ themeMode, themeVariables }), [themeMode, themeVariables]);
22
+
23
+ return <ThemeContext.Provider value={contextValue}>{children}</ThemeContext.Provider>;
24
24
  }
25
25
 
26
26
  export function useTheme() {
27
27
  const context = useContext(ThemeContext);
28
28
  const scheme = useColorScheme();
29
29
 
30
- // If the theme mode is not set, use the system color scheme
31
- const themeMode = context?.themeMode ?? scheme;
32
- const themeVariables = context?.themeVariables ?? {};
30
+ return useMemo(() => {
31
+ // If the theme mode is not set, use the system color scheme
32
+ const themeMode = context?.themeMode ?? scheme;
33
+ const themeVariables = context?.themeVariables ?? {};
33
34
 
34
- let Theme = themeMode === 'dark' ? DarkTheme : LightTheme;
35
+ let Theme = themeMode === 'dark' ? DarkTheme : LightTheme;
35
36
 
36
- if (themeVariables.accent) {
37
- Theme = {
38
- ...Theme,
39
- ...getAccentColors(themeVariables.accent)
40
- };
41
- }
37
+ if (themeVariables.accent) {
38
+ Theme = {
39
+ ...Theme,
40
+ ...getAccentColors(themeVariables.accent)
41
+ };
42
+ }
42
43
 
43
- return Theme;
44
+ return Theme;
45
+ }, [context?.themeMode, context?.themeVariables, scheme]);
44
46
  }