@particle-network/ui-native 0.0.2

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 (168) hide show
  1. package/README.md +57 -0
  2. package/dist/components/ProgressWrapper/index.d.ts +35 -0
  3. package/dist/components/ProgressWrapper/index.js +120 -0
  4. package/dist/components/Text/index.d.ts +2 -0
  5. package/dist/components/Text/index.js +2 -0
  6. package/dist/components/Text/text.d.ts +4 -0
  7. package/dist/components/Text/text.js +196 -0
  8. package/dist/components/Text/text.types.d.ts +109 -0
  9. package/dist/components/Text/text.types.js +77 -0
  10. package/dist/components/UXButton/button.d.ts +3 -0
  11. package/dist/components/UXButton/button.js +74 -0
  12. package/dist/components/UXButton/button.styles.d.ts +53 -0
  13. package/dist/components/UXButton/button.styles.js +157 -0
  14. package/dist/components/UXButton/button.types.d.ts +18 -0
  15. package/dist/components/UXButton/button.types.js +0 -0
  16. package/dist/components/UXButton/index.d.ts +2 -0
  17. package/dist/components/UXButton/index.js +1 -0
  18. package/dist/components/UXCheckbox/checkbox-group.d.ts +8 -0
  19. package/dist/components/UXCheckbox/checkbox-group.js +30 -0
  20. package/dist/components/UXCheckbox/checkbox.d.ts +10 -0
  21. package/dist/components/UXCheckbox/checkbox.js +78 -0
  22. package/dist/components/UXCheckbox/context.d.ts +8 -0
  23. package/dist/components/UXCheckbox/context.js +8 -0
  24. package/dist/components/UXCheckbox/index.d.ts +4 -0
  25. package/dist/components/UXCheckbox/index.js +3 -0
  26. package/dist/components/UXCheckbox/types.d.ts +6 -0
  27. package/dist/components/UXCheckbox/types.js +0 -0
  28. package/dist/components/UXChip/chip.d.ts +3 -0
  29. package/dist/components/UXChip/chip.js +48 -0
  30. package/dist/components/UXChip/index.d.ts +2 -0
  31. package/dist/components/UXChip/index.js +1 -0
  32. package/dist/components/UXChip/styles.d.ts +24 -0
  33. package/dist/components/UXChip/styles.js +70 -0
  34. package/dist/components/UXChip/types.d.ts +11 -0
  35. package/dist/components/UXChip/types.js +0 -0
  36. package/dist/components/UXDivider/index.d.ts +8 -0
  37. package/dist/components/UXDivider/index.js +34 -0
  38. package/dist/components/UXHint/index.d.ts +7 -0
  39. package/dist/components/UXHint/index.js +19 -0
  40. package/dist/components/UXModal/index.d.ts +24 -0
  41. package/dist/components/UXModal/index.js +271 -0
  42. package/dist/components/UXPressable/index.d.ts +4 -0
  43. package/dist/components/UXPressable/index.js +36 -0
  44. package/dist/components/UXRadio/context.d.ts +7 -0
  45. package/dist/components/UXRadio/context.js +10 -0
  46. package/dist/components/UXRadio/index.d.ts +2 -0
  47. package/dist/components/UXRadio/index.js +2 -0
  48. package/dist/components/UXRadio/radio-group.d.ts +5 -0
  49. package/dist/components/UXRadio/radio-group.js +21 -0
  50. package/dist/components/UXRadio/radio.d.ts +5 -0
  51. package/dist/components/UXRadio/radio.js +67 -0
  52. package/dist/components/UXRadio/types.d.ts +10 -0
  53. package/dist/components/UXRadio/types.js +0 -0
  54. package/dist/components/UXSwitch/index.d.ts +2 -0
  55. package/dist/components/UXSwitch/index.js +1 -0
  56. package/dist/components/UXSwitch/styles.d.ts +16 -0
  57. package/dist/components/UXSwitch/styles.js +58 -0
  58. package/dist/components/UXSwitch/switch.d.ts +3 -0
  59. package/dist/components/UXSwitch/switch.js +103 -0
  60. package/dist/components/UXSwitch/types.d.ts +11 -0
  61. package/dist/components/UXSwitch/types.js +0 -0
  62. package/dist/components/UXTabs/context.d.ts +5 -0
  63. package/dist/components/UXTabs/context.js +8 -0
  64. package/dist/components/UXTabs/index.d.ts +4 -0
  65. package/dist/components/UXTabs/index.js +3 -0
  66. package/dist/components/UXTabs/styles.d.ts +30 -0
  67. package/dist/components/UXTabs/styles.js +191 -0
  68. package/dist/components/UXTabs/tab.d.ts +3 -0
  69. package/dist/components/UXTabs/tab.js +55 -0
  70. package/dist/components/UXTabs/tabs.d.ts +3 -0
  71. package/dist/components/UXTabs/tabs.js +66 -0
  72. package/dist/components/UXTabs/types.d.ts +23 -0
  73. package/dist/components/UXTabs/types.js +0 -0
  74. package/dist/components/UXTooltip/index.d.ts +6 -0
  75. package/dist/components/UXTooltip/index.js +32 -0
  76. package/dist/components/UXTouchableOpacity/index.d.ts +4 -0
  77. package/dist/components/UXTouchableOpacity/index.js +24 -0
  78. package/dist/components/index.d.ts +22 -0
  79. package/dist/components/index.js +22 -0
  80. package/dist/components/input/index.d.ts +3 -0
  81. package/dist/components/input/index.js +2 -0
  82. package/dist/components/input/input.d.ts +3 -0
  83. package/dist/components/input/input.js +138 -0
  84. package/dist/components/input/number-input.d.ts +3 -0
  85. package/dist/components/input/number-input.js +231 -0
  86. package/dist/components/input/styles.d.ts +31 -0
  87. package/dist/components/input/styles.js +102 -0
  88. package/dist/components/input/types.d.ts +61 -0
  89. package/dist/components/input/types.js +0 -0
  90. package/dist/components/layout/Box/box.d.ts +12 -0
  91. package/dist/components/layout/Box/box.js +89 -0
  92. package/dist/components/layout/Box/index.d.ts +3 -0
  93. package/dist/components/layout/Box/index.js +2 -0
  94. package/dist/components/layout/Box/useBox.style.d.ts +3 -0
  95. package/dist/components/layout/Box/useBox.style.js +141 -0
  96. package/dist/components/layout/Box/useBox.type.d.ts +292 -0
  97. package/dist/components/layout/Box/useBox.type.js +0 -0
  98. package/dist/components/layout/Center.d.ts +5 -0
  99. package/dist/components/layout/Center.js +10 -0
  100. package/dist/components/layout/Circle.d.ts +7 -0
  101. package/dist/components/layout/Circle.js +14 -0
  102. package/dist/components/layout/Flex/flex.d.ts +6 -0
  103. package/dist/components/layout/Flex/flex.js +33 -0
  104. package/dist/components/layout/Flex/index.d.ts +4 -0
  105. package/dist/components/layout/Flex/index.js +3 -0
  106. package/dist/components/layout/Flex/useFlex.style.d.ts +3 -0
  107. package/dist/components/layout/Flex/useFlex.style.js +122 -0
  108. package/dist/components/layout/Flex/useFlex.type.d.ts +65 -0
  109. package/dist/components/layout/Flex/useFlex.type.js +0 -0
  110. package/dist/components/layout/Flex/useFlexBox.style.d.ts +134 -0
  111. package/dist/components/layout/Flex/useFlexBox.style.js +26 -0
  112. package/dist/components/layout/HStack.d.ts +5 -0
  113. package/dist/components/layout/HStack.js +11 -0
  114. package/dist/components/layout/Square.d.ts +9 -0
  115. package/dist/components/layout/Square.js +14 -0
  116. package/dist/components/layout/VStack.d.ts +5 -0
  117. package/dist/components/layout/VStack.js +14 -0
  118. package/dist/hooks/index.d.ts +5 -0
  119. package/dist/hooks/index.js +5 -0
  120. package/dist/hooks/useColors.d.ts +7 -0
  121. package/dist/hooks/useColors.js +18 -0
  122. package/dist/hooks/useKeyboard.d.ts +4 -0
  123. package/dist/hooks/useKeyboard.js +29 -0
  124. package/dist/hooks/useRadius.d.ts +7 -0
  125. package/dist/hooks/useRadius.js +16 -0
  126. package/dist/hooks/useSpacing.d.ts +7 -0
  127. package/dist/hooks/useSpacing.js +16 -0
  128. package/dist/hooks/useTheme.d.ts +5 -0
  129. package/dist/hooks/useTheme.js +6 -0
  130. package/dist/icons/CheckboxOffIcon.d.ts +4 -0
  131. package/dist/icons/CheckboxOffIcon.js +21 -0
  132. package/dist/icons/CheckboxOnIcon.d.ts +4 -0
  133. package/dist/icons/CheckboxOnIcon.js +26 -0
  134. package/dist/icons/DotIcon.d.ts +4 -0
  135. package/dist/icons/DotIcon.js +23 -0
  136. package/dist/icons/QuestionIcon.d.ts +4 -0
  137. package/dist/icons/QuestionIcon.js +30 -0
  138. package/dist/icons/RadioOffIcon.d.ts +4 -0
  139. package/dist/icons/RadioOffIcon.js +22 -0
  140. package/dist/icons/RadioOnIcon.d.ts +4 -0
  141. package/dist/icons/RadioOnIcon.js +42 -0
  142. package/dist/icons/types.d.ts +6 -0
  143. package/dist/icons/types.js +0 -0
  144. package/dist/index.d.ts +5 -0
  145. package/dist/index.js +4 -0
  146. package/dist/provider/ThemeContext.d.ts +3 -0
  147. package/dist/provider/ThemeContext.js +15 -0
  148. package/dist/provider/ThemeProvider.d.ts +10 -0
  149. package/dist/provider/ThemeProvider.js +31 -0
  150. package/dist/provider/index.d.ts +2 -0
  151. package/dist/provider/index.js +2 -0
  152. package/dist/theme/colors.d.ts +6 -0
  153. package/dist/theme/colors.js +17 -0
  154. package/dist/theme/index.d.ts +7 -0
  155. package/dist/theme/index.js +16 -0
  156. package/dist/theme/opacity.d.ts +2 -0
  157. package/dist/theme/opacity.js +3 -0
  158. package/dist/theme/radius.d.ts +3 -0
  159. package/dist/theme/radius.js +10 -0
  160. package/dist/theme/spacing.d.ts +3 -0
  161. package/dist/theme/spacing.js +10 -0
  162. package/dist/types/index.d.ts +1 -0
  163. package/dist/types/index.js +0 -0
  164. package/dist/types/theme.d.ts +17 -0
  165. package/dist/types/theme.js +0 -0
  166. package/dist/utils/triggerHapticFeedback.d.ts +5 -0
  167. package/dist/utils/triggerHapticFeedback.js +16 -0
  168. package/package.json +110 -0
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { ScrollView, type StyleProp, type ViewStyle } from 'react-native';
3
+ export interface UXModalProps {
4
+ modalName?: string;
5
+ style?: StyleProp<ViewStyle>;
6
+ contentStyle?: StyleProp<ViewStyle>;
7
+ isOpen: boolean;
8
+ title?: React.ReactNode;
9
+ titleAlign?: 'left' | 'center';
10
+ footer?: React.ReactNode;
11
+ tip?: React.ReactNode;
12
+ onClose?: () => void;
13
+ onVisibleChange?: (visible: boolean) => void;
14
+ children: React.ReactNode;
15
+ disableCloseBySwipe?: boolean;
16
+ closeByLineOnly?: boolean;
17
+ wrapPortal?: boolean;
18
+ /**
19
+ * 键盘避开区域
20
+ * 如果想要遮挡 footer 则选择 content
21
+ */
22
+ keyboardAvoidPosition?: 'container' | 'content';
23
+ }
24
+ export declare const UXModal: React.ForwardRefExoticComponent<UXModalProps & React.RefAttributes<ScrollView>>;
@@ -0,0 +1,271 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import react, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { Animated, Dimensions, PanResponder, Platform, ScrollView, StyleSheet } from "react-native";
4
+ import { Modal, Portal } from "react-native-paper";
5
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
6
+ import { ms } from "react-native-size-matters";
7
+ import { Box, Circle, Flex, HStack, Text, VStack } from "../index.js";
8
+ import { useColors, useKeyboard } from "../../hooks/index.js";
9
+ const { height } = Dimensions.get('window');
10
+ const UXModal = /*#__PURE__*/ forwardRef((props, scrollViewRef)=>{
11
+ const { style, contentStyle, isOpen, title, titleAlign = 'left', onClose, onVisibleChange, children, disableCloseBySwipe, closeByLineOnly, wrapPortal, footer, modalName, tip, keyboardAvoidPosition = 'container' } = props;
12
+ const { getColor } = useColors();
13
+ const insets = useSafeAreaInsets();
14
+ const { keyboardHeight } = useKeyboard();
15
+ const translateY = useRef(new Animated.Value(height)).current;
16
+ const scrollOffset = useRef(0);
17
+ const [touchStartY, setTouchStartY] = useState(0);
18
+ const [isDragging, setIsDragging] = useState(false);
19
+ const [modalHeight, setModalHeight] = useState(0);
20
+ const [footerHeight, setFooterHeight] = useState(0);
21
+ const isAndroid = 'android' === Platform.OS;
22
+ const onDismiss = useCallback(()=>{
23
+ if (onClose) onClose();
24
+ else if (onVisibleChange) onVisibleChange(false);
25
+ translateY.setValue(height);
26
+ }, [
27
+ onClose,
28
+ onVisibleChange
29
+ ]);
30
+ useEffect(()=>{
31
+ if (isOpen && modalName) console.log('BottomModal:', modalName);
32
+ }, [
33
+ isOpen,
34
+ modalName
35
+ ]);
36
+ useEffect(()=>{
37
+ if (isOpen) Animated.spring(translateY, {
38
+ toValue: 0,
39
+ useNativeDriver: !isAndroid,
40
+ damping: 500,
41
+ mass: 3,
42
+ stiffness: 1000
43
+ }).start();
44
+ else Animated.timing(translateY, {
45
+ toValue: height,
46
+ duration: 200,
47
+ useNativeDriver: !isAndroid
48
+ }).start();
49
+ }, [
50
+ isOpen,
51
+ height,
52
+ translateY
53
+ ]);
54
+ const panResponder = PanResponder.create({
55
+ onStartShouldSetPanResponder: ()=>false,
56
+ onMoveShouldSetPanResponder: (_, gestureState)=>Math.abs(gestureState.dy) > Math.abs(gestureState.dx) && scrollOffset.current <= 0 && gestureState.dy > 0,
57
+ onPanResponderMove: (_, gestureState)=>{
58
+ if (gestureState.dy > 0) translateY.setValue(gestureState.dy);
59
+ },
60
+ onPanResponderRelease: (_, gestureState)=>{
61
+ if (gestureState.dy > 100) Animated.timing(translateY, {
62
+ toValue: height,
63
+ duration: 200,
64
+ useNativeDriver: !isAndroid
65
+ }).start(()=>{
66
+ onDismiss();
67
+ });
68
+ else Animated.spring(translateY, {
69
+ toValue: 0,
70
+ useNativeDriver: !isAndroid
71
+ }).start();
72
+ }
73
+ });
74
+ const handleScroll = useCallback((event)=>{
75
+ scrollOffset.current = event.nativeEvent.contentOffset.y;
76
+ }, []);
77
+ const onTouchStartSideLine = useCallback((event)=>{
78
+ setTouchStartY(event.nativeEvent.pageY);
79
+ setIsDragging(true);
80
+ }, []);
81
+ const onTouchMoveSideLine = useCallback((event)=>{
82
+ if (!isDragging) return;
83
+ const currentY = event.nativeEvent.pageY;
84
+ const deltaY = currentY - touchStartY;
85
+ if (deltaY > 0) translateY.setValue(deltaY);
86
+ }, [
87
+ isDragging,
88
+ touchStartY,
89
+ translateY
90
+ ]);
91
+ const onTouchEndSideLine = useCallback((event)=>{
92
+ if (!isDragging) return;
93
+ const currentY = event.nativeEvent.pageY;
94
+ const deltaY = currentY - touchStartY;
95
+ const threshold = 0.1 * modalHeight;
96
+ if (deltaY > threshold) Animated.timing(translateY, {
97
+ toValue: height,
98
+ duration: 200,
99
+ useNativeDriver: !isAndroid
100
+ }).start(()=>{
101
+ onDismiss();
102
+ });
103
+ else Animated.spring(translateY, {
104
+ toValue: 0,
105
+ useNativeDriver: !isAndroid
106
+ }).start();
107
+ setIsDragging(false);
108
+ }, [
109
+ isDragging,
110
+ touchStartY,
111
+ modalHeight,
112
+ height,
113
+ translateY,
114
+ onDismiss
115
+ ]);
116
+ const keyboardAvoidValue = useMemo(()=>{
117
+ const containerValue = 'container' === keyboardAvoidPosition ? Math.max(insets.bottom, ms(32), keyboardHeight) : Math.max(insets.bottom, ms(32));
118
+ const contentValue = 'content' === keyboardAvoidPosition && keyboardHeight > 0 ? keyboardHeight - footerHeight - Math.max(insets.bottom, ms(32)) : 0;
119
+ return {
120
+ containerValue,
121
+ contentValue
122
+ };
123
+ }, [
124
+ keyboardAvoidPosition,
125
+ insets.bottom,
126
+ keyboardHeight,
127
+ footerHeight
128
+ ]);
129
+ const styles = StyleSheet.create({
130
+ modalContainer: {
131
+ margin: 0,
132
+ justifyContent: 'flex-end',
133
+ position: 'absolute',
134
+ bottom: 0,
135
+ left: 0,
136
+ right: 0
137
+ },
138
+ modal: {
139
+ marginBottom: 0,
140
+ marginTop: 0,
141
+ backgroundColor: 'transparent'
142
+ },
143
+ container: {
144
+ paddingHorizontal: ms(14),
145
+ borderTopLeftRadius: 24,
146
+ borderTopRightRadius: 24,
147
+ flex: 1,
148
+ gap: ms(20),
149
+ backgroundColor: getColor('overlay'),
150
+ maxHeight: isAndroid ? height : height - insets.top,
151
+ transform: [
152
+ {
153
+ translateY
154
+ }
155
+ ],
156
+ paddingBottom: keyboardAvoidValue.containerValue
157
+ },
158
+ content: {
159
+ marginBottom: keyboardAvoidValue.contentValue
160
+ },
161
+ tip: {
162
+ flex: 1,
163
+ flexShrink: 1,
164
+ flexWrap: 'wrap'
165
+ }
166
+ });
167
+ const Wrapper = useMemo(()=>wrapPortal ? Portal : react.Fragment, [
168
+ wrapPortal
169
+ ]);
170
+ return /*#__PURE__*/ jsx(Wrapper, {
171
+ children: /*#__PURE__*/ jsx(Modal, {
172
+ dismissable: true,
173
+ dismissableBackButton: true,
174
+ contentContainerStyle: styles.modalContainer,
175
+ style: [
176
+ styles.modal,
177
+ style
178
+ ],
179
+ theme: {
180
+ colors: {
181
+ backdrop: 'rgba(0, 0, 0, 0.8)'
182
+ }
183
+ },
184
+ visible: isOpen,
185
+ onDismiss: onDismiss,
186
+ children: /*#__PURE__*/ jsxs(Animated.View, {
187
+ style: styles.container,
188
+ onLayout: (event)=>{
189
+ setModalHeight(event.nativeEvent.layout.height);
190
+ },
191
+ ...!disableCloseBySwipe && !closeByLineOnly ? panResponder.panHandlers : {},
192
+ children: [
193
+ /*#__PURE__*/ jsx(HStack, {
194
+ fullWidth: true,
195
+ hitSlop: {
196
+ top: 20,
197
+ bottom: 20,
198
+ left: 0,
199
+ right: 0
200
+ },
201
+ justify: "center",
202
+ mt: 10,
203
+ onTouchEnd: onTouchEndSideLine,
204
+ onTouchMove: onTouchMoveSideLine,
205
+ onTouchStart: onTouchStartSideLine,
206
+ children: /*#__PURE__*/ jsx(Box, {
207
+ bg: "tertiary",
208
+ h: 4,
209
+ radius: "full",
210
+ w: 40
211
+ })
212
+ }),
213
+ title ? /*#__PURE__*/ jsx(Flex, {
214
+ fullWidth: true,
215
+ justify: 'center' === titleAlign ? 'center' : 'start',
216
+ mt: -4,
217
+ children: 'string' == typeof title ? /*#__PURE__*/ jsx(Text, {
218
+ h3: true,
219
+ children: title
220
+ }) : title
221
+ }) : null,
222
+ /*#__PURE__*/ jsx(ScrollView, {
223
+ ref: scrollViewRef,
224
+ bounces: false,
225
+ scrollEventThrottle: 16,
226
+ showsHorizontalScrollIndicator: false,
227
+ showsVerticalScrollIndicator: false,
228
+ style: [
229
+ styles.content,
230
+ contentStyle
231
+ ],
232
+ onScroll: handleScroll,
233
+ children: children
234
+ }),
235
+ /*#__PURE__*/ jsxs(VStack, {
236
+ fullWidth: true,
237
+ gap: "lg",
238
+ onLayout: (event)=>{
239
+ setFooterHeight(event.nativeEvent.layout.height);
240
+ },
241
+ children: [
242
+ footer ? /*#__PURE__*/ jsx(VStack, {
243
+ fullWidth: true,
244
+ gap: "lg",
245
+ children: footer
246
+ }) : null,
247
+ tip ? /*#__PURE__*/ jsxs(Flex, {
248
+ gap: 8,
249
+ children: [
250
+ /*#__PURE__*/ jsx(Circle, {
251
+ bg: "secondary",
252
+ mt: 5,
253
+ size: 5
254
+ }),
255
+ /*#__PURE__*/ jsx(Text, {
256
+ body2: true,
257
+ color: "secondary",
258
+ style: styles.tip,
259
+ children: tip
260
+ })
261
+ ]
262
+ }) : null
263
+ ]
264
+ })
265
+ ]
266
+ })
267
+ })
268
+ });
269
+ });
270
+ UXModal.displayName = 'UXModal';
271
+ export { UXModal };
@@ -0,0 +1,4 @@
1
+ import type { PressableProps, View } from 'react-native';
2
+ import { type UseBoxProps, type UseFlexProps } from '..';
3
+ export type UXPressableProps = PressableProps & UseBoxProps & UseFlexProps;
4
+ export declare const UXPressable: import("react").ForwardRefExoticComponent<PressableProps & UseBoxProps & UseFlexProps & import("react").RefAttributes<View>>;
@@ -0,0 +1,36 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef, useCallback } from "react";
3
+ import { Pressable } from "react-native";
4
+ import useDebounceFn from "ahooks/es/useDebounceFn";
5
+ import { useFlexBoxStyle } from "../index.js";
6
+ const UXPressable = /*#__PURE__*/ forwardRef(({ style, onPress, ...props }, ref)=>{
7
+ const { run } = useDebounceFn(onPress || (()=>null), {
8
+ wait: 300,
9
+ leading: true,
10
+ trailing: false
11
+ });
12
+ const boxFlexStyle = useFlexBoxStyle(props);
13
+ const pressableStyle = useCallback(({ pressed })=>{
14
+ if ('function' == typeof style) return [
15
+ boxFlexStyle,
16
+ style({
17
+ pressed
18
+ })
19
+ ];
20
+ return [
21
+ boxFlexStyle,
22
+ style
23
+ ];
24
+ }, [
25
+ boxFlexStyle,
26
+ style
27
+ ]);
28
+ return /*#__PURE__*/ jsx(Pressable, {
29
+ ref: ref,
30
+ style: pressableStyle,
31
+ onPress: run,
32
+ ...props
33
+ });
34
+ });
35
+ UXPressable.displayName = 'UXPressable';
36
+ export { UXPressable };
@@ -0,0 +1,7 @@
1
+ import type { UXRadioCommonProps } from './types';
2
+ type RadioGroupContextType = Omit<UXRadioCommonProps, 'children' | 'value'> & {
3
+ selectedValue: UXRadioCommonProps['value'];
4
+ };
5
+ export declare const RadioGroupContext: import("react").Context<RadioGroupContextType>;
6
+ export declare const useRadioGroup: () => RadioGroupContextType;
7
+ export {};
@@ -0,0 +1,10 @@
1
+ import { createContext, useContext } from "react";
2
+ const RadioGroupContext = createContext({
3
+ selectedValue: '',
4
+ onValueChange: ()=>null
5
+ });
6
+ const useRadioGroup = ()=>{
7
+ const context = useContext(RadioGroupContext);
8
+ return context;
9
+ };
10
+ export { RadioGroupContext, useRadioGroup };
@@ -0,0 +1,2 @@
1
+ export * from './radio';
2
+ export * from './radio-group';
@@ -0,0 +1,2 @@
1
+ export * from "./radio.js";
2
+ export * from "./radio-group.js";
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { type FlexProps } from '..';
3
+ import type { UXRadioCommonProps } from './types';
4
+ export type UXRadioGroupProps = UXRadioCommonProps & FlexProps;
5
+ export declare const UXRadioGroup: React.FC<UXRadioGroupProps>;
@@ -0,0 +1,21 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import "react";
3
+ import { Flex } from "../index.js";
4
+ import { RadioGroupContext } from "./context.js";
5
+ const UXRadioGroup = ({ value = '', onValueChange, color, size, isDisabled, children, gap = 8, ...props })=>/*#__PURE__*/ jsx(RadioGroupContext.Provider, {
6
+ value: {
7
+ size,
8
+ isDisabled,
9
+ color,
10
+ selectedValue: value,
11
+ onValueChange
12
+ },
13
+ children: /*#__PURE__*/ jsx(Flex, {
14
+ direction: "col",
15
+ gap: gap,
16
+ ...props,
17
+ children: children
18
+ })
19
+ });
20
+ UXRadioGroup.displayName = 'UXRadioGroup';
21
+ export { UXRadioGroup };
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { type FlexProps } from '..';
3
+ import type { UXRadioCommonProps } from './types';
4
+ export type UXRadioProps = Omit<UXRadioCommonProps, 'onValueChange'> & FlexProps;
5
+ export declare const UXRadio: React.FC<UXRadioProps>;
@@ -0,0 +1,67 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { Pressable } from "react-native";
4
+ import { ms } from "react-native-size-matters";
5
+ import { Flex, Text } from "../index.js";
6
+ import RadioOffIcon from "../../icons/RadioOffIcon.js";
7
+ import RadioOnIcon from "../../icons/RadioOnIcon.js";
8
+ import { disabledOpacity } from "../../theme/index.js";
9
+ import { useRadioGroup } from "./context.js";
10
+ const UXRadio = ({ size, color, children, value, isDisabled, ...props })=>{
11
+ const groupContext = useRadioGroup();
12
+ const { selectedValue, size: groupSize, color: groupColor, onValueChange, isDisabled: groupIsDisabled } = groupContext;
13
+ const isSelected = selectedValue === value;
14
+ const radioColor = color || groupColor || 'primary';
15
+ const radioSize = size || groupSize || 'md';
16
+ const radioIsDisabled = isDisabled || groupIsDisabled;
17
+ const handleSelectChange = ()=>{
18
+ onValueChange(value);
19
+ };
20
+ const iconSize = useMemo(()=>{
21
+ if ('sm' === radioSize) return ms(10);
22
+ if ('lg' === radioSize) return ms(14);
23
+ return ms(12);
24
+ }, [
25
+ radioSize
26
+ ]);
27
+ const labelVariant = useMemo(()=>{
28
+ if ('sm' === radioSize) return 'body3';
29
+ if ('lg' === radioSize) return 'body1';
30
+ return 'body2';
31
+ }, [
32
+ radioSize
33
+ ]);
34
+ const gap = useMemo(()=>{
35
+ if ('sm' === radioSize) return 6;
36
+ return 8;
37
+ }, [
38
+ radioSize
39
+ ]);
40
+ return /*#__PURE__*/ jsx(Pressable, {
41
+ disabled: radioIsDisabled,
42
+ style: {
43
+ opacity: radioIsDisabled ? disabledOpacity : 1
44
+ },
45
+ onPress: handleSelectChange,
46
+ children: /*#__PURE__*/ jsxs(Flex, {
47
+ gap: gap,
48
+ items: "center",
49
+ ...props,
50
+ children: [
51
+ isSelected ? /*#__PURE__*/ jsx(RadioOnIcon, {
52
+ color: radioColor,
53
+ size: iconSize
54
+ }) : /*#__PURE__*/ jsx(RadioOffIcon, {
55
+ color: "secondary",
56
+ size: iconSize
57
+ }),
58
+ 'string' == typeof children ? /*#__PURE__*/ jsx(Text, {
59
+ variant: labelVariant,
60
+ children: children
61
+ }) : children
62
+ ]
63
+ })
64
+ });
65
+ };
66
+ UXRadio.displayName = 'UXRadio';
67
+ export { UXRadio };
@@ -0,0 +1,10 @@
1
+ import type React from 'react';
2
+ import type { UXForegroundColor } from '@particle-network/ui-shared';
3
+ export interface UXRadioCommonProps {
4
+ color?: UXForegroundColor;
5
+ size?: 'sm' | 'md' | 'lg';
6
+ isDisabled?: boolean;
7
+ value: string;
8
+ onValueChange: (value: string) => void;
9
+ children: React.ReactNode;
10
+ }
File without changes
@@ -0,0 +1,2 @@
1
+ export * from './switch';
2
+ export type * from './types';
@@ -0,0 +1 @@
1
+ export * from "./switch.js";
@@ -0,0 +1,16 @@
1
+ import type { UXSwitchProps } from './types';
2
+ export declare const useStyles: ({ size, isSelected }: UXSwitchProps) => {
3
+ track: {
4
+ width: number;
5
+ height: number;
6
+ borderRadius: number;
7
+ justifyContent: "center";
8
+ };
9
+ thumb: {
10
+ backgroundColor: string;
11
+ width: number;
12
+ height: number;
13
+ borderRadius: number;
14
+ elevation: number;
15
+ };
16
+ };
@@ -0,0 +1,58 @@
1
+ import { useEffect, useMemo, useRef } from "react";
2
+ import { Animated, StyleSheet } from "react-native";
3
+ import { ms } from "react-native-size-matters";
4
+ const useStyles = ({ size = 'md', isSelected = false })=>{
5
+ const animatedValue = useRef(new Animated.Value(isSelected ? 1 : 0)).current;
6
+ useEffect(()=>{
7
+ Animated.timing(animatedValue, {
8
+ toValue: isSelected ? 1 : 0,
9
+ duration: 200,
10
+ useNativeDriver: false
11
+ }).start();
12
+ }, [
13
+ isSelected,
14
+ animatedValue
15
+ ]);
16
+ const height = useMemo(()=>{
17
+ if ('sm' === size) return ms(12);
18
+ if ('lg' === size) return ms(20);
19
+ return ms(14);
20
+ }, [
21
+ size
22
+ ]);
23
+ const width = useMemo(()=>{
24
+ if ('sm' === size) return ms(20);
25
+ if ('lg' === size) return ms(34);
26
+ return ms(24);
27
+ }, [
28
+ size
29
+ ]);
30
+ const thumbSize = useMemo(()=>{
31
+ if ('sm' === size) return ms(8);
32
+ if ('lg' === size) return ms(14);
33
+ return ms(10);
34
+ }, [
35
+ size
36
+ ]);
37
+ const styles = useMemo(()=>StyleSheet.create({
38
+ track: {
39
+ width,
40
+ height,
41
+ borderRadius: height / 2,
42
+ justifyContent: 'center'
43
+ },
44
+ thumb: {
45
+ backgroundColor: 'white',
46
+ width: thumbSize,
47
+ height: thumbSize,
48
+ borderRadius: thumbSize / 2,
49
+ elevation: 2
50
+ }
51
+ }), [
52
+ width,
53
+ height,
54
+ thumbSize
55
+ ]);
56
+ return styles;
57
+ };
58
+ export { useStyles };
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import type { UXSwitchProps } from './types';
3
+ export declare const UXSwitch: React.FC<UXSwitchProps>;
@@ -0,0 +1,103 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { Animated } from "react-native";
4
+ import { ms } from "react-native-size-matters";
5
+ import useUpdateEffect from "ahooks/es/useUpdateEffect";
6
+ import { Text, UXTouchableOpacity } from "../index.js";
7
+ import { useColors } from "../../hooks/index.js";
8
+ import { disabledOpacity } from "../../theme/index.js";
9
+ import { useStyles } from "./styles.js";
10
+ const UXSwitch = (props)=>{
11
+ const { color = 'primary', size = 'md', defaultSelected = false, isSelected: isSelectedProps = false, onValueChange, isReadOnly, isDisabled, children, ...flexProps } = props;
12
+ const [isSelected, setIsSelected] = useState(isSelectedProps || defaultSelected);
13
+ useUpdateEffect(()=>{
14
+ setIsSelected(isSelectedProps);
15
+ }, [
16
+ isSelectedProps
17
+ ]);
18
+ const { getColor } = useColors();
19
+ const styles = useStyles(props);
20
+ const gap = useMemo(()=>{
21
+ if ('sm' === size) return ms(6);
22
+ return ms(8);
23
+ }, [
24
+ size
25
+ ]);
26
+ const labelVariant = useMemo(()=>{
27
+ if ('sm' === size) return 'body3Bold';
28
+ if ('lg' === size) return 'body1Bold';
29
+ return 'body2Bold';
30
+ }, [
31
+ size
32
+ ]);
33
+ const animatedValue = useRef(new Animated.Value(isSelected ? 1 : 0)).current;
34
+ useEffect(()=>{
35
+ Animated.timing(animatedValue, {
36
+ toValue: isSelected ? 1 : 0,
37
+ duration: 200,
38
+ useNativeDriver: false
39
+ }).start();
40
+ }, [
41
+ isSelected,
42
+ animatedValue
43
+ ]);
44
+ const thumbTranslateX = useMemo(()=>{
45
+ const padding = 'lg' === size ? ms(3) : ms(2);
46
+ return animatedValue.interpolate({
47
+ inputRange: [
48
+ 0,
49
+ 1
50
+ ],
51
+ outputRange: [
52
+ padding,
53
+ styles.track.width - styles.thumb.width - padding
54
+ ]
55
+ });
56
+ }, [
57
+ animatedValue,
58
+ styles,
59
+ size
60
+ ]);
61
+ const handlePress = ()=>{
62
+ if (isReadOnly || isDisabled) return;
63
+ setIsSelected(!isSelected);
64
+ onValueChange?.(!isSelected);
65
+ };
66
+ return /*#__PURE__*/ jsxs(UXTouchableOpacity, {
67
+ activeOpacity: 0.8,
68
+ disabled: isDisabled || isReadOnly,
69
+ gap: gap,
70
+ items: "center",
71
+ opacity: isDisabled ? disabledOpacity : 1,
72
+ onPress: handlePress,
73
+ ...flexProps,
74
+ children: [
75
+ /*#__PURE__*/ jsx(Animated.View, {
76
+ style: [
77
+ styles.track,
78
+ {
79
+ backgroundColor: isSelected ? getColor(color) : getColor('tertiary')
80
+ }
81
+ ],
82
+ children: /*#__PURE__*/ jsx(Animated.View, {
83
+ style: [
84
+ styles.thumb,
85
+ {
86
+ transform: [
87
+ {
88
+ translateX: thumbTranslateX
89
+ }
90
+ ]
91
+ }
92
+ ]
93
+ })
94
+ }),
95
+ 'string' == typeof children ? /*#__PURE__*/ jsx(Text, {
96
+ variant: labelVariant,
97
+ children: children
98
+ }) : children
99
+ ]
100
+ });
101
+ };
102
+ UXSwitch.displayName = 'UXSwitch';
103
+ export { UXSwitch };