@particle-network/ui-native 0.4.2-beta.9 → 0.5.1-beta.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.
@@ -14,6 +14,7 @@ const useStyles = (props)=>{
14
14
  sm: ms(buttonConfig.size.sm),
15
15
  md: ms(buttonConfig.size.md),
16
16
  lg: ms(buttonConfig.size.lg),
17
+ xl: ms(buttonConfig.size.xl),
17
18
  auto: void 0
18
19
  }), [
19
20
  buttonConfig?.size,
@@ -24,6 +25,7 @@ const useStyles = (props)=>{
24
25
  sm: ms(buttonConfig.fontSize.sm),
25
26
  md: ms(buttonConfig.fontSize.md),
26
27
  lg: ms(buttonConfig.fontSize.lg),
28
+ xl: ms(buttonConfig.fontSize.xl),
27
29
  auto: ms(buttonConfig.fontSize.md)
28
30
  }), [
29
31
  ms,
@@ -33,7 +35,8 @@ const useStyles = (props)=>{
33
35
  xs: ms(14),
34
36
  sm: ms(16),
35
37
  md: ms(18),
36
- lg: ms(24),
38
+ lg: ms(20),
39
+ xl: ms(24),
37
40
  auto: ms(16)
38
41
  }), [
39
42
  ms
@@ -42,14 +45,16 @@ const useStyles = (props)=>{
42
45
  xs: 'xs',
43
46
  sm: 'sm',
44
47
  md: 'sm',
45
- lg: 'md',
48
+ lg: 8,
49
+ xl: 'md',
46
50
  auto: 'sm'
47
51
  };
48
52
  const paddingMap = useMemo(()=>({
49
53
  xs: ms(10),
50
54
  sm: ms(14),
51
55
  md: ms(14),
52
- lg: ms(14)
56
+ lg: ms(14),
57
+ xl: ms(14)
53
58
  }), [
54
59
  ms
55
60
  ]);
@@ -13,7 +13,8 @@ export interface UXButtonProps extends Omit<UXPressableProps, 'style' | 'disable
13
13
  * | xs | 20 | 36 |
14
14
  * | sm | 24 | 40 |
15
15
  * | md | 30 | 44 |
16
- * | lg | 44 | 48 |
16
+ * | lg | 36 | 46 |
17
+ * | xl | 44 | 48 |
17
18
  *
18
19
  * fontSize
19
20
  * | size | ux | street |
@@ -21,9 +22,10 @@ export interface UXButtonProps extends Omit<UXPressableProps, 'style' | 'disable
21
22
  * | xs | 11 | 12 |
22
23
  * | sm | 10 | 14 |
23
24
  * | md | 12 | 16 |
24
- * | lg | 16 | 18 |
25
+ * | lg | 14 | 16 |
26
+ * | xl | 16 | 18 |
25
27
  */
26
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'auto';
28
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'auto';
27
29
  variant?: 'solid' | 'bordered' | 'flat' | 'text' | 'light';
28
30
  radius?: UXRadius;
29
31
  isDisabled?: boolean;
@@ -0,0 +1,7 @@
1
+ export declare const THUMB_SIZE = 12;
2
+ export declare const THUMB_INNER_SIZE = 8;
3
+ export declare const TRACK_HEIGHT = 2;
4
+ export declare const MARK_SIZE = 4;
5
+ export declare const TOOLTIP_ARROW_SIZE = 6;
6
+ export declare const TOOLTIP_MARGIN_BOTTOM = 4;
7
+ export declare const LABEL_WIDTH = 40;
@@ -0,0 +1,8 @@
1
+ const THUMB_SIZE = 12;
2
+ const THUMB_INNER_SIZE = 8;
3
+ const TRACK_HEIGHT = 2;
4
+ const MARK_SIZE = 4;
5
+ const TOOLTIP_ARROW_SIZE = 6;
6
+ const TOOLTIP_MARGIN_BOTTOM = 4;
7
+ const LABEL_WIDTH = 40;
8
+ export { LABEL_WIDTH, MARK_SIZE, THUMB_INNER_SIZE, THUMB_SIZE, TOOLTIP_ARROW_SIZE, TOOLTIP_MARGIN_BOTTOM, TRACK_HEIGHT };
@@ -0,0 +1 @@
1
+ export * from './slider';
@@ -0,0 +1 @@
1
+ export * from "./slider.js";
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import type { UXSliderProps } from './slider.types';
3
+ export declare const UXSlider: React.FC<UXSliderProps>;
@@ -0,0 +1,284 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { View } from "react-native";
4
+ import { Gesture, GestureDetector } from "react-native-gesture-handler";
5
+ import react_native_reanimated, { useAnimatedStyle, useSharedValue } from "react-native-reanimated";
6
+ import { scheduleOnRN } from "react-native-worklets";
7
+ import { useTheme } from "../../hooks/index.js";
8
+ import { Box } from "../layout/index.js";
9
+ import { Text } from "../Text/index.js";
10
+ import { UXPressable } from "../UXPressable/index.js";
11
+ import { LABEL_WIDTH, MARK_SIZE, THUMB_SIZE } from "./constants.js";
12
+ import { useStyles } from "./slider.styles.js";
13
+ const UXSlider = ({ color = 'primary', minValue = 0, maxValue = 100, defaultValue, value: controlledValue, onChange, onChangeEnd, fillOffset, marks, showMarksSteps = true, step, showTooltip, getValue, ...restProps })=>{
14
+ const { colors } = useTheme();
15
+ const [trackWidth, setTrackWidth] = useState(0);
16
+ const [internalValue, setInternalValue] = useState(defaultValue ?? minValue);
17
+ const [isDragging, setIsDragging] = useState(false);
18
+ const [tooltipWidth, setTooltipWidth] = useState(0);
19
+ const styles = useStyles({
20
+ color
21
+ });
22
+ let currentValue = void 0 !== controlledValue ? Math.max(minValue, Math.min(maxValue, controlledValue)) : internalValue;
23
+ if (!Number.isFinite(currentValue)) currentValue = fillOffset ?? minValue;
24
+ const thumbX = useSharedValue(0);
25
+ const trackWidthShared = useSharedValue(0);
26
+ const valueToPosition = useCallback((val)=>{
27
+ if (0 === trackWidth) return THUMB_SIZE / 2;
28
+ const usableWidth = trackWidth - THUMB_SIZE;
29
+ return THUMB_SIZE / 2 + (val - minValue) / (maxValue - minValue) * usableWidth;
30
+ }, [
31
+ trackWidth,
32
+ minValue,
33
+ maxValue
34
+ ]);
35
+ const valueToMarkThumbPosition = useCallback((val)=>{
36
+ if (0 === trackWidth) return MARK_SIZE / 2;
37
+ const usableWidth = trackWidth - MARK_SIZE;
38
+ return MARK_SIZE / 2 + (val - minValue) / (maxValue - minValue) * usableWidth;
39
+ }, [
40
+ trackWidth,
41
+ minValue,
42
+ maxValue
43
+ ]);
44
+ const positionToValueWorklet = (pos, width)=>{
45
+ 'worklet';
46
+ if (0 === width) return minValue;
47
+ const usableWidth = width - THUMB_SIZE;
48
+ if (usableWidth <= 0) return minValue;
49
+ const adjustedPos = pos - THUMB_SIZE / 2;
50
+ const percentage = Math.max(0, Math.min(1, adjustedPos / usableWidth));
51
+ let val = minValue + percentage * (maxValue - minValue);
52
+ if (step && step > 0) {
53
+ val = Math.round(val / step) * step;
54
+ const decimals = (step.toString().split('.')[1] || '').length;
55
+ val = Number(val.toFixed(decimals));
56
+ }
57
+ return Math.max(minValue, Math.min(maxValue, val));
58
+ };
59
+ useEffect(()=>{
60
+ thumbX.value = valueToPosition(currentValue);
61
+ }, [
62
+ currentValue,
63
+ valueToPosition,
64
+ thumbX
65
+ ]);
66
+ useEffect(()=>{
67
+ trackWidthShared.value = trackWidth;
68
+ }, [
69
+ trackWidth,
70
+ trackWidthShared
71
+ ]);
72
+ const setDraggingTrue = useCallback(()=>setIsDragging(true), []);
73
+ const setDraggingFalse = useCallback(()=>setIsDragging(false), []);
74
+ const handleValueChange = useCallback((newValue)=>{
75
+ if (void 0 === controlledValue) setInternalValue(newValue);
76
+ onChange?.(newValue);
77
+ }, [
78
+ controlledValue,
79
+ onChange
80
+ ]);
81
+ const handleChangeEnd = useCallback((finalValue)=>{
82
+ onChangeEnd?.(finalValue);
83
+ }, [
84
+ onChangeEnd
85
+ ]);
86
+ const panGesture = Gesture.Pan().activeOffsetX([
87
+ -8,
88
+ 8
89
+ ]).failOffsetY([
90
+ -16,
91
+ 16
92
+ ]).onStart((event)=>{
93
+ 'worklet';
94
+ scheduleOnRN(setDraggingTrue);
95
+ const minPos = THUMB_SIZE / 2;
96
+ const maxPos = trackWidthShared.value - THUMB_SIZE / 2;
97
+ const touchX = Math.max(minPos, Math.min(event.x, maxPos));
98
+ thumbX.value = touchX;
99
+ }).onUpdate((event)=>{
100
+ 'worklet';
101
+ const minPos = THUMB_SIZE / 2;
102
+ const maxPos = trackWidthShared.value - THUMB_SIZE / 2;
103
+ const touchX = Math.max(minPos, Math.min(event.x, maxPos));
104
+ thumbX.value = touchX;
105
+ const newValue = positionToValueWorklet(touchX, trackWidthShared.value);
106
+ scheduleOnRN(handleValueChange, newValue);
107
+ }).onEnd(()=>{
108
+ 'worklet';
109
+ scheduleOnRN(setDraggingFalse);
110
+ const finalValue = positionToValueWorklet(thumbX.value, trackWidthShared.value);
111
+ scheduleOnRN(handleChangeEnd, finalValue);
112
+ });
113
+ const tapGesture = Gesture.Tap().onEnd((event)=>{
114
+ 'worklet';
115
+ if (event.y > THUMB_SIZE) return;
116
+ const minPos = THUMB_SIZE / 2;
117
+ const maxPos = trackWidthShared.value - THUMB_SIZE / 2;
118
+ const touchX = Math.max(minPos, Math.min(event.x, maxPos));
119
+ thumbX.value = touchX;
120
+ const newValue = positionToValueWorklet(touchX, trackWidthShared.value);
121
+ scheduleOnRN(handleValueChange, newValue);
122
+ scheduleOnRN(handleChangeEnd, newValue);
123
+ });
124
+ const gesture = Gesture.Simultaneous(panGesture, tapGesture);
125
+ const labelBlockerGesture = Gesture.Native();
126
+ const thumbAnimatedStyle = useAnimatedStyle(()=>({
127
+ transform: [
128
+ {
129
+ translateX: thumbX.value - THUMB_SIZE / 2
130
+ }
131
+ ]
132
+ }));
133
+ const fillAnimatedStyle = useAnimatedStyle(()=>{
134
+ if (void 0 !== fillOffset) {
135
+ const offsetPos = (fillOffset - minValue) / (maxValue - minValue) * trackWidthShared.value;
136
+ const currentPos = thumbX.value;
137
+ return currentPos >= offsetPos ? {
138
+ left: offsetPos,
139
+ width: currentPos - offsetPos
140
+ } : {
141
+ left: currentPos,
142
+ width: offsetPos - currentPos
143
+ };
144
+ }
145
+ return {
146
+ left: 0,
147
+ width: thumbX.value
148
+ };
149
+ });
150
+ const tooltipAnimatedStyle = useAnimatedStyle(()=>{
151
+ const left = thumbX.value - tooltipWidth / 2;
152
+ const clampedLeft = Math.max(0, Math.min(trackWidthShared.value - tooltipWidth, left));
153
+ return {
154
+ transform: [
155
+ {
156
+ translateX: clampedLeft
157
+ }
158
+ ]
159
+ };
160
+ });
161
+ const getTooltipText = useCallback(()=>{
162
+ if (getValue) return getValue(currentValue);
163
+ return currentValue.toString();
164
+ }, [
165
+ currentValue,
166
+ getValue
167
+ ]);
168
+ const handleTrackLayout = (event)=>setTrackWidth(event.nativeEvent.layout.width);
169
+ const handleTooltipLayout = (event)=>setTooltipWidth(event.nativeEvent.layout.width);
170
+ const handleMarkLabelPress = useCallback((markValue)=>{
171
+ setIsDragging(false);
172
+ thumbX.value = valueToPosition(markValue);
173
+ handleValueChange(markValue);
174
+ handleChangeEnd(markValue);
175
+ }, [
176
+ thumbX,
177
+ valueToPosition,
178
+ handleValueChange,
179
+ handleChangeEnd
180
+ ]);
181
+ return /*#__PURE__*/ jsx(Box, {
182
+ fullWidth: true,
183
+ ph: marks && marks.length > 0 && marks.some((mark)=>mark.value === maxValue) ? LABEL_WIDTH / 2 : 0,
184
+ ...restProps,
185
+ children: /*#__PURE__*/ jsx(GestureDetector, {
186
+ gesture: gesture,
187
+ children: /*#__PURE__*/ jsxs(react_native_reanimated.View, {
188
+ style: styles.gestureWrapper,
189
+ children: [
190
+ /*#__PURE__*/ jsxs(View, {
191
+ style: styles.trackContainer,
192
+ onLayout: handleTrackLayout,
193
+ children: [
194
+ showTooltip && isDragging && /*#__PURE__*/ jsx(react_native_reanimated.View, {
195
+ style: [
196
+ styles.tooltipWrapper,
197
+ tooltipAnimatedStyle
198
+ ],
199
+ pointerEvents: "none",
200
+ onLayout: handleTooltipLayout,
201
+ children: /*#__PURE__*/ jsxs(View, {
202
+ style: styles.tooltip,
203
+ children: [
204
+ /*#__PURE__*/ jsx(Text, {
205
+ color: "white",
206
+ children: getTooltipText()
207
+ }),
208
+ /*#__PURE__*/ jsx(View, {
209
+ style: styles.tooltipArrow
210
+ })
211
+ ]
212
+ })
213
+ }),
214
+ /*#__PURE__*/ jsx(Box, {
215
+ style: styles.track
216
+ }),
217
+ /*#__PURE__*/ jsx(react_native_reanimated.View, {
218
+ style: [
219
+ styles.fill,
220
+ fillAnimatedStyle
221
+ ]
222
+ }),
223
+ showMarksSteps && marks?.map((mark, index)=>{
224
+ const markPos = valueToMarkThumbPosition(mark.value);
225
+ const isActive = void 0 !== fillOffset ? currentValue >= fillOffset && mark.value <= currentValue && mark.value >= fillOffset || currentValue < fillOffset && mark.value >= currentValue && mark.value <= fillOffset : mark.value <= currentValue;
226
+ return /*#__PURE__*/ jsx(View, {
227
+ style: [
228
+ styles.mark,
229
+ {
230
+ left: markPos - MARK_SIZE / 2,
231
+ backgroundColor: isActive ? colors[color] : colors.tertiary
232
+ }
233
+ ]
234
+ }, index);
235
+ }),
236
+ /*#__PURE__*/ jsx(react_native_reanimated.View, {
237
+ style: [
238
+ styles.thumb,
239
+ thumbAnimatedStyle
240
+ ]
241
+ })
242
+ ]
243
+ }),
244
+ marks && marks.length > 0 && /*#__PURE__*/ jsx(GestureDetector, {
245
+ gesture: labelBlockerGesture,
246
+ children: /*#__PURE__*/ jsx(View, {
247
+ style: styles.labelsContainer,
248
+ children: marks.map((mark, index)=>{
249
+ const isActive = void 0 !== fillOffset ? currentValue >= fillOffset && mark.value <= currentValue && mark.value >= fillOffset || currentValue < fillOffset && mark.value >= currentValue && mark.value <= fillOffset : mark.value <= currentValue;
250
+ return /*#__PURE__*/ jsx(UXPressable, {
251
+ center: true,
252
+ style: [
253
+ styles.markLabelWrapper,
254
+ {
255
+ left: valueToMarkThumbPosition(mark.value) - LABEL_WIDTH / 2
256
+ }
257
+ ],
258
+ hitSlop: {
259
+ top: 8,
260
+ bottom: 8,
261
+ left: 8,
262
+ right: 8
263
+ },
264
+ onPress: ()=>handleMarkLabelPress(mark.value),
265
+ children: /*#__PURE__*/ jsx(Text, {
266
+ caption1: true,
267
+ style: [
268
+ {
269
+ color: isActive ? colors.foreground : colors.secondary
270
+ }
271
+ ],
272
+ numberOfLines: 1,
273
+ children: mark.label
274
+ })
275
+ }, index);
276
+ })
277
+ })
278
+ })
279
+ ]
280
+ })
281
+ })
282
+ });
283
+ };
284
+ export { UXSlider };
@@ -0,0 +1,92 @@
1
+ import type { UXSliderProps } from './slider.types';
2
+ export declare const useStyles: ({ color }: UXSliderProps) => {
3
+ gestureWrapper: {
4
+ width: "100%";
5
+ };
6
+ trackContainer: {
7
+ width: "100%";
8
+ justifyContent: "center";
9
+ position: "relative";
10
+ height: number;
11
+ };
12
+ track: {
13
+ width: "100%";
14
+ borderRadius: number;
15
+ position: "absolute";
16
+ backgroundColor: string;
17
+ height: number;
18
+ };
19
+ fill: {
20
+ position: "absolute";
21
+ borderRadius: number;
22
+ backgroundColor: string;
23
+ height: number;
24
+ };
25
+ mark: {
26
+ position: "absolute";
27
+ width: number;
28
+ height: number;
29
+ top: "50%";
30
+ marginTop: number;
31
+ borderRadius: number;
32
+ };
33
+ thumb: {
34
+ alignItems: "center";
35
+ justifyContent: "center";
36
+ position: "absolute";
37
+ top: "50%";
38
+ marginTop: number;
39
+ width: number;
40
+ height: number;
41
+ borderRadius: number;
42
+ shadowColor: string;
43
+ shadowOffset: {
44
+ width: number;
45
+ height: number;
46
+ };
47
+ shadowOpacity: number;
48
+ shadowRadius: number;
49
+ elevation: number;
50
+ backgroundColor: string;
51
+ };
52
+ labelsContainer: {
53
+ width: "100%";
54
+ height: number;
55
+ marginTop: number;
56
+ position: "relative";
57
+ };
58
+ markLabelWrapper: {
59
+ position: "absolute";
60
+ width: number;
61
+ overflow: "visible";
62
+ };
63
+ tooltipWrapper: {
64
+ position: "absolute";
65
+ left: number;
66
+ top: number;
67
+ justifyContent: "center";
68
+ alignItems: "center";
69
+ zIndex: number;
70
+ };
71
+ tooltip: {
72
+ position: "absolute";
73
+ paddingHorizontal: number;
74
+ paddingVertical: number;
75
+ borderRadius: number;
76
+ alignItems: "center";
77
+ backgroundColor: string;
78
+ bottom: number;
79
+ };
80
+ tooltipArrow: {
81
+ position: "absolute";
82
+ bottom: number;
83
+ width: number;
84
+ height: number;
85
+ borderLeftWidth: number;
86
+ borderRightWidth: number;
87
+ borderTopWidth: number;
88
+ borderLeftColor: string;
89
+ borderRightColor: string;
90
+ borderTopColor: string;
91
+ };
92
+ };
@@ -0,0 +1,100 @@
1
+ import { StyleSheet } from "react-native";
2
+ import { useTheme } from "../../hooks/index.js";
3
+ import { LABEL_WIDTH, MARK_SIZE, THUMB_SIZE, TOOLTIP_ARROW_SIZE, TOOLTIP_MARGIN_BOTTOM, TRACK_HEIGHT } from "./constants.js";
4
+ const useStyles = ({ color })=>{
5
+ const { colors } = useTheme();
6
+ const colorValue = colors[color];
7
+ const styles = StyleSheet.create({
8
+ gestureWrapper: {
9
+ width: '100%'
10
+ },
11
+ trackContainer: {
12
+ width: '100%',
13
+ justifyContent: 'center',
14
+ position: 'relative',
15
+ height: THUMB_SIZE
16
+ },
17
+ track: {
18
+ width: '100%',
19
+ borderRadius: TRACK_HEIGHT / 2,
20
+ position: 'absolute',
21
+ backgroundColor: colors['bg-200'],
22
+ height: TRACK_HEIGHT
23
+ },
24
+ fill: {
25
+ position: 'absolute',
26
+ borderRadius: TRACK_HEIGHT / 2,
27
+ backgroundColor: colorValue,
28
+ height: TRACK_HEIGHT
29
+ },
30
+ mark: {
31
+ position: 'absolute',
32
+ width: MARK_SIZE,
33
+ height: MARK_SIZE,
34
+ top: '50%',
35
+ marginTop: -MARK_SIZE / 2,
36
+ borderRadius: 999
37
+ },
38
+ thumb: {
39
+ alignItems: 'center',
40
+ justifyContent: 'center',
41
+ position: 'absolute',
42
+ top: '50%',
43
+ marginTop: -THUMB_SIZE / 2,
44
+ width: THUMB_SIZE,
45
+ height: THUMB_SIZE,
46
+ borderRadius: 999,
47
+ shadowColor: '#000',
48
+ shadowOffset: {
49
+ width: 0,
50
+ height: 2
51
+ },
52
+ shadowOpacity: 0.1,
53
+ shadowRadius: 3,
54
+ elevation: 3,
55
+ backgroundColor: colorValue
56
+ },
57
+ labelsContainer: {
58
+ width: '100%',
59
+ height: 14,
60
+ marginTop: 6,
61
+ position: 'relative'
62
+ },
63
+ markLabelWrapper: {
64
+ position: 'absolute',
65
+ width: LABEL_WIDTH,
66
+ overflow: 'visible'
67
+ },
68
+ tooltipWrapper: {
69
+ position: 'absolute',
70
+ left: 0,
71
+ top: 0,
72
+ justifyContent: 'center',
73
+ alignItems: 'center',
74
+ zIndex: 100
75
+ },
76
+ tooltip: {
77
+ position: 'absolute',
78
+ paddingHorizontal: 12,
79
+ paddingVertical: 6,
80
+ borderRadius: 6,
81
+ alignItems: 'center',
82
+ backgroundColor: colorValue,
83
+ bottom: THUMB_SIZE / 2 + TOOLTIP_MARGIN_BOTTOM
84
+ },
85
+ tooltipArrow: {
86
+ position: 'absolute',
87
+ bottom: -TOOLTIP_ARROW_SIZE + 1,
88
+ width: 0,
89
+ height: 0,
90
+ borderLeftWidth: TOOLTIP_ARROW_SIZE,
91
+ borderRightWidth: TOOLTIP_ARROW_SIZE,
92
+ borderTopWidth: TOOLTIP_ARROW_SIZE,
93
+ borderLeftColor: 'transparent',
94
+ borderRightColor: 'transparent',
95
+ borderTopColor: colorValue
96
+ }
97
+ });
98
+ return styles;
99
+ };
100
+ export { useStyles };
@@ -0,0 +1,30 @@
1
+ import type { UXForegroundColor } from '@particle-network/ui-shared';
2
+ import type { BoxProps } from '../layout';
3
+ export interface UXSliderProps extends BoxProps {
4
+ color?: Exclude<UXForegroundColor, 'default' | 'white'>;
5
+ minValue?: number;
6
+ maxValue?: number;
7
+ defaultValue?: number;
8
+ value?: number;
9
+ onChange?: (value: number) => void;
10
+ onChangeEnd?: (value: number) => void;
11
+ /**
12
+ * 起始填充的偏移量
13
+ */
14
+ fillOffset?: number;
15
+ /**
16
+ * 滑杆底部标记点
17
+ */
18
+ marks?: {
19
+ value: number;
20
+ label: string;
21
+ }[];
22
+ /** 是否显示滑杆上标记记点 */
23
+ showMarksSteps?: boolean;
24
+ /** 拖动步长 */
25
+ step?: number;
26
+ /** 拖动时是否显示气泡提示框 */
27
+ showTooltip?: boolean;
28
+ /** 格式化 value,用于显示 tooltip 的文本 */
29
+ getValue?: (value: number) => string;
30
+ }
File without changes
@@ -1,16 +1,11 @@
1
1
  import React from 'react';
2
2
  import { type UXTabsProps } from '../UXTabs';
3
- interface UXTabSwitchProps {
4
- tabStyle?: UXTabsProps['tabStyle'];
5
- containerStyle?: UXTabsProps['containerStyle'];
6
- size?: UXTabsProps['size'];
7
- color?: UXTabsProps['color'];
3
+ interface UXTabSwitchProps extends Omit<UXTabsProps, 'variant' | 'selectedKey' | 'onSelectionChange'> {
8
4
  onTitle?: string;
9
5
  onIcon?: React.ReactNode;
10
6
  offTitle?: string;
11
7
  offIcon?: React.ReactNode;
12
8
  isSelected?: boolean;
13
- isDisabled?: boolean;
14
9
  onValueChange?: (isSelected: boolean) => void;
15
10
  }
16
11
  export declare const UXTabSwitch: React.FC<UXTabSwitchProps>;
@@ -3,19 +3,15 @@ import "react";
3
3
  import { useI18n } from "../../hooks/useI18n.js";
4
4
  import { UXTab, UXTabs } from "../UXTabs/index.js";
5
5
  const UXTabSwitch = (props)=>{
6
- const { tabStyle, containerStyle, size, color, onTitle, onIcon, offTitle, offIcon, isSelected = false, isDisabled = false, onValueChange } = props;
6
+ const { onTitle, onIcon, offTitle, offIcon, isSelected = false, onValueChange, ...restProps } = props;
7
7
  const i18n = useI18n();
8
8
  return /*#__PURE__*/ jsxs(UXTabs, {
9
- tabStyle: tabStyle,
10
- containerStyle: containerStyle,
11
- size: size,
12
9
  variant: "switch",
13
- color: color,
14
- isDisabled: isDisabled,
15
10
  selectedKey: isSelected.toString(),
16
11
  onSelectionChange: (key)=>{
17
12
  onValueChange?.('true' === key);
18
13
  },
14
+ ...restProps,
19
15
  children: [
20
16
  /*#__PURE__*/ jsx(UXTab, {
21
17
  title: offTitle || i18n.switch.off,
@@ -5,7 +5,7 @@ export declare const useStyles: (props: Partial<UXTabsProps> & {
5
5
  tabsWrapper: {
6
6
  backgroundColor: string | undefined;
7
7
  gap: import("@particle-network/ui-shared").SpacingType;
8
- flex: number;
8
+ flex: number | undefined;
9
9
  justifyContent: "flex-start" | "space-between";
10
10
  borderRadius: number | undefined;
11
11
  height: number;
@@ -14,7 +14,7 @@ export declare const useStyles: (props: Partial<UXTabsProps> & {
14
14
  };
15
15
  tab: {
16
16
  flexDirection: "column";
17
- flexGrow: number;
17
+ flex: number | undefined;
18
18
  height: "100%";
19
19
  alignItems: "center";
20
20
  justifyContent: "center";
@@ -81,7 +81,7 @@ const useStyles = (props)=>{
81
81
  ]);
82
82
  const wrapperBackgroundColor = useMemo(()=>{
83
83
  if ('switch' === variant) return getColor('bg-200');
84
- if ('solid' === variant) return getColor('bg-400');
84
+ if ('solid' === variant) return getColor('bg-200');
85
85
  return 'transparent';
86
86
  }, [
87
87
  variant,
@@ -125,8 +125,8 @@ const useStyles = (props)=>{
125
125
  if (!isSelected) return 'transparent';
126
126
  if ('text' === variant || 'underlined' === variant) return 'transparent';
127
127
  if ('default' === color) {
128
- if ('switch' === variant) return getColor('tertiary');
129
- return getColor('bg-200');
128
+ if ('light' === variant) return getColor('bg-200');
129
+ return getColor('tertiary');
130
130
  }
131
131
  return getColor(color);
132
132
  }, [
@@ -153,7 +153,7 @@ const useStyles = (props)=>{
153
153
  tabsWrapper: {
154
154
  backgroundColor: wrapperBackgroundColor,
155
155
  gap: gapValue,
156
- flex: fullWidth || w ? 1 : 0,
156
+ flex: fullWidth || w ? 1 : void 0,
157
157
  justifyContent: fullWidth || w ? 'space-between' : 'flex-start',
158
158
  borderRadius: wrapperBorderRadius,
159
159
  height,
@@ -162,11 +162,10 @@ const useStyles = (props)=>{
162
162
  },
163
163
  tab: {
164
164
  flexDirection: 'column',
165
- flexGrow: [
166
- 'text',
167
- 'light',
168
- 'underlined'
169
- ].includes(variant) ? 0 : 1,
165
+ flex: [
166
+ 'solid',
167
+ 'switch'
168
+ ].includes(variant) ? 1 : void 0,
170
169
  height: '100%',
171
170
  alignItems: 'center',
172
171
  justifyContent: 'center',
@@ -70,7 +70,7 @@ const UXDatePicker = ({ title, value, defaultValue, defaultInternalValue, onChan
70
70
  footer: /*#__PURE__*/ jsx(UXButton, {
71
71
  fullWidth: true,
72
72
  color: "primary",
73
- size: "lg",
73
+ size: "xl",
74
74
  onPress: handleConfirm,
75
75
  children: i18n.datePicker.confirm
76
76
  }),
@@ -122,7 +122,7 @@ const UXDateRangePicker = ({ title, value, defaultValue, defaultInternalValue, o
122
122
  /*#__PURE__*/ jsx(UXButton, {
123
123
  fullWidth: true,
124
124
  color: "primary",
125
- size: "lg",
125
+ size: "xl",
126
126
  onPress: handleConfirm,
127
127
  children: i18n.datePicker.confirm
128
128
  })
@@ -13,6 +13,7 @@ export * from './UXListBox';
13
13
  export * from './UXModal';
14
14
  export * from './UXPressable';
15
15
  export * from './UXRadio';
16
+ export * from './UXSlider';
16
17
  export * from './UXSpinner';
17
18
  export * from './UXSwitch';
18
19
  export * from './UXTabs';
@@ -13,6 +13,7 @@ export * from "./UXListBox/index.js";
13
13
  export * from "./UXModal/index.js";
14
14
  export * from "./UXPressable/index.js";
15
15
  export * from "./UXRadio/index.js";
16
+ export * from "./UXSlider/index.js";
16
17
  export * from "./UXSpinner/index.js";
17
18
  export * from "./UXSwitch/index.js";
18
19
  export * from "./UXTabs/index.js";
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
3
- import { TextInput } from "react-native";
4
- import { useColors, useKeyboard } from "../../hooks/index.js";
3
+ import { Platform, TextInput } from "react-native";
4
+ import { useColors, useI18n, useKeyboard } from "../../hooks/index.js";
5
5
  import { Icon } from "../../icons/index.js";
6
6
  import { HStack } from "../layout/HStack.js";
7
7
  import { VStack } from "../layout/VStack.js";
@@ -16,6 +16,7 @@ const UXInput = /*#__PURE__*/ forwardRef((props, ref)=>{
16
16
  const [isFocused, setIsFocused] = useState(false);
17
17
  const [isInvalid, setIsInvalid] = useState(isInvalidProp);
18
18
  const { isKeyboardVisible } = useKeyboard();
19
+ const i18n = useI18n();
19
20
  useEffect(()=>{
20
21
  if (!isKeyboardVisible && blurOnKeyboardHide) inputRef.current?.blur();
21
22
  }, [
@@ -43,6 +44,16 @@ const UXInput = /*#__PURE__*/ forwardRef((props, ref)=>{
43
44
  isInvalid,
44
45
  isFocused
45
46
  });
47
+ useEffect(()=>{
48
+ if ('web' === Platform.OS) return;
49
+ if (inputRef.current) inputRef.current.setNativeProps({
50
+ style: {
51
+ color: styles.input.color
52
+ }
53
+ });
54
+ }, [
55
+ styles.input.color
56
+ ]);
46
57
  useEffect(()=>{
47
58
  if (void 0 !== controlledValue) setInternalValue(controlledValue);
48
59
  else if (void 0 !== defaultValue) setInternalValue(defaultValue);
@@ -78,7 +89,7 @@ const UXInput = /*#__PURE__*/ forwardRef((props, ref)=>{
78
89
  setIsInvalid(true);
79
90
  return {
80
91
  isValid: false,
81
- errorMessage: 'This field is required'
92
+ errorMessage: i18n.validation.required
82
93
  };
83
94
  }
84
95
  setIsInvalid(false);
@@ -87,7 +98,8 @@ const UXInput = /*#__PURE__*/ forwardRef((props, ref)=>{
87
98
  };
88
99
  }, [
89
100
  internalValue,
90
- isRequired
101
+ isRequired,
102
+ i18n
91
103
  ]);
92
104
  const renderError = useMemo(()=>{
93
105
  if (isInvalidProp && errorMessage) {
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
3
3
  import { Platform, TextInput } from "react-native";
4
- import { useColors, useKeyboard } from "../../hooks/index.js";
4
+ import { useColors, useI18n, useKeyboard } from "../../hooks/index.js";
5
5
  import { Icon } from "../../icons/index.js";
6
6
  import { HStack } from "../layout/HStack.js";
7
7
  import { VStack } from "../layout/VStack.js";
@@ -9,14 +9,25 @@ import { Text } from "../Text/index.js";
9
9
  import { UXPressable } from "../UXPressable/index.js";
10
10
  import { useStyles } from "./styles.js";
11
11
  const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
12
- const { containerStyle, wrapperStyle, inputStyle, value: controlledValue, defaultValue, errorMessage, minValue, maxValue, formatOptions, startContent, endContent, isRequired, isReadOnly, isDisabled, isClearable, isInvalid: isInvalidProp, autoErrorMessage, allowNegative, label, onChangeText, onValueChange, onFocus, onBlur, blurOnKeyboardHide = true, ...restProps } = props;
12
+ const { containerStyle, wrapperStyle, inputStyle, value: controlledValue, defaultValue, errorMessage, minValue, maxValue, startContent, endContent, isRequired, isReadOnly, isDisabled, isClearable, isInvalid: isInvalidProp, autoErrorMessage, allowNegative, label, onChangeText, onValueChange, onFocus, onBlur, blurOnKeyboardHide = true, ...restProps } = props;
13
13
  const { getColor } = useColors();
14
14
  const inputRef = useRef(null);
15
15
  const [internalValue, setInternalValue] = useState(defaultValue ?? NaN);
16
16
  const [displayText, setDisplayText] = useState(defaultValue?.toString() ?? '');
17
17
  const [isFocused, setIsFocused] = useState(false);
18
18
  const [isInvalid, setIsInvalid] = useState(isInvalidProp);
19
+ const i18n = useI18n();
19
20
  const { isKeyboardVisible } = useKeyboard();
21
+ const formatOptions = useMemo(()=>{
22
+ const restFormatOptions = {
23
+ maximumFractionDigits: 3,
24
+ ...restProps.formatOptions ?? {}
25
+ };
26
+ delete restFormatOptions.signDisplay;
27
+ return restFormatOptions;
28
+ }, [
29
+ restProps.formatOptions
30
+ ]);
20
31
  useEffect(()=>{
21
32
  if (!isKeyboardVisible && blurOnKeyboardHide) inputRef.current?.blur();
22
33
  }, [
@@ -46,6 +57,15 @@ const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
46
57
  isInvalid,
47
58
  isFocused
48
59
  });
60
+ useEffect(()=>{
61
+ if (inputRef.current) inputRef.current.setNativeProps({
62
+ style: {
63
+ color: styles.input.color
64
+ }
65
+ });
66
+ }, [
67
+ styles.input.color
68
+ ]);
49
69
  useEffect(()=>{
50
70
  if (void 0 !== controlledValue) {
51
71
  setInternalValue(controlledValue);
@@ -58,24 +78,21 @@ const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
58
78
  defaultValue,
59
79
  controlledValue
60
80
  ]);
61
- const numberFormatter = useMemo(()=>{
62
- if (formatOptions) return new Intl.NumberFormat(void 0, formatOptions);
63
- return null;
64
- }, [
81
+ const numberFormatter = useMemo(()=>new Intl.NumberFormat(void 0, formatOptions), [
65
82
  formatOptions
66
83
  ]);
67
84
  const validationResult = useMemo(()=>{
68
85
  if (isNaN(internalValue) && isRequired) return {
69
86
  isValid: false,
70
- errorMessage: 'This field is required'
87
+ errorMessage: i18n.validation.required
71
88
  };
72
89
  if (void 0 !== minValue && internalValue < minValue) return {
73
90
  isValid: false,
74
- errorMessage: `Value must be at least ${minValue}`
91
+ errorMessage: i18n.validation.min.replace('{min}', minValue.toString())
75
92
  };
76
93
  if (void 0 !== maxValue && internalValue > maxValue) return {
77
94
  isValid: false,
78
- errorMessage: `Value must be at most ${maxValue}`
95
+ errorMessage: i18n.validation.max.replace('{max}', maxValue.toString())
79
96
  };
80
97
  setIsInvalid(false);
81
98
  return {
@@ -85,22 +102,19 @@ const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
85
102
  internalValue,
86
103
  isRequired,
87
104
  minValue,
88
- maxValue
105
+ maxValue,
106
+ i18n
89
107
  ]);
90
108
  const adjustValueToRange = useCallback((num)=>{
91
- const numValue = isNaN(num) ? 0 : num;
92
- if (void 0 !== minValue && numValue < minValue) return minValue;
93
- if (void 0 !== maxValue && numValue > maxValue) return maxValue;
94
- return numValue;
109
+ if (isNaN(num)) return NaN;
110
+ if (void 0 !== minValue && num < minValue) return minValue;
111
+ if (void 0 !== maxValue && num > maxValue) return maxValue;
112
+ return num;
95
113
  }, [
96
114
  minValue,
97
115
  maxValue
98
116
  ]);
99
- const adjustValueToFractionDigits = useCallback((numValue)=>{
100
- if (formatOptions?.minimumFractionDigits !== void 0 || formatOptions?.maximumFractionDigits !== void 0) return Number(numberFormatter?.format(numValue).replaceAll(',', ''));
101
- return numValue;
102
- }, [
103
- formatOptions,
117
+ const adjustValueToFractionDigits = useCallback((numValue)=>Number(numberFormatter?.format(numValue).replaceAll(',', '')), [
104
118
  numberFormatter
105
119
  ]);
106
120
  const handleChangeText = useCallback((text)=>{
@@ -111,17 +125,11 @@ const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
111
125
  if (cleanedText.includes('-') && !cleanedText.startsWith('-')) return;
112
126
  setDisplayText(cleanedText);
113
127
  onChangeText?.(cleanedText);
114
- const numValue = parseFloat(cleanedText);
115
- if (isNaN(numValue)) {
116
- setInternalValue(NaN);
117
- onValueChange?.(NaN);
118
- } else {
119
- setInternalValue(numValue);
120
- onValueChange?.(numValue);
121
- }
128
+ if ('' === cleanedText || '-' === cleanedText) return void setInternalValue(NaN);
129
+ const numValue = Number(cleanedText);
130
+ isNaN(numValue) ? setInternalValue(NaN) : setInternalValue(numValue);
122
131
  }, [
123
- onChangeText,
124
- onValueChange
132
+ onChangeText
125
133
  ]);
126
134
  const handleFocus = useCallback((e)=>{
127
135
  setIsFocused(true);
@@ -131,8 +139,9 @@ const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
131
139
  ]);
132
140
  const handleBlur = useCallback((e)=>{
133
141
  setIsFocused(false);
134
- const adjustedValue = adjustValueToFractionDigits(adjustValueToRange(internalValue));
135
- if (adjustedValue !== internalValue) {
142
+ if (isNaN(internalValue)) onValueChange?.(NaN);
143
+ else {
144
+ const adjustedValue = adjustValueToFractionDigits(adjustValueToRange(internalValue));
136
145
  const adjustedText = adjustedValue?.toString();
137
146
  setDisplayText(adjustedText);
138
147
  setInternalValue(adjustedValue);
@@ -165,10 +174,11 @@ const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
165
174
  if (isNaN(internalValue)) return '';
166
175
  if (numberFormatter) {
167
176
  const formattedValue = numberFormatter.format(internalValue);
168
- if (formatOptions?.signDisplay === 'exceptZero' || formatOptions?.signDisplay === 'always') {
177
+ const signDisplay = restProps.formatOptions?.signDisplay;
178
+ if ('exceptZero' === signDisplay || 'always' === signDisplay) {
169
179
  if (internalValue > 0) return `+${formattedValue}`;
170
180
  else if (internalValue < 0) ;
171
- else if ('always' === formatOptions.signDisplay) return `+${formattedValue}`;
181
+ else if ('always' === signDisplay) return `+${formattedValue}`;
172
182
  }
173
183
  return formattedValue;
174
184
  }
@@ -178,7 +188,7 @@ const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
178
188
  displayText,
179
189
  numberFormatter,
180
190
  isFocused,
181
- formatOptions
191
+ restProps.formatOptions
182
192
  ]);
183
193
  const renderError = useMemo(()=>{
184
194
  if (isInvalidProp && errorMessage) {
@@ -5,13 +5,15 @@ const defaultComponentConfig = {
5
5
  xs: 20,
6
6
  sm: 24,
7
7
  md: 30,
8
- lg: 44
8
+ lg: 36,
9
+ xl: 44
9
10
  },
10
11
  fontSize: {
11
12
  xs: 11,
12
13
  sm: 10,
13
14
  md: 12,
14
- lg: 16
15
+ lg: 14,
16
+ xl: 16
15
17
  },
16
18
  color: {
17
19
  default: {
@@ -7,13 +7,15 @@ const streetComponentConfig = {
7
7
  xs: 36,
8
8
  sm: 40,
9
9
  md: 44,
10
- lg: 48
10
+ lg: 46,
11
+ xl: 48
11
12
  },
12
13
  fontSize: {
13
14
  xs: 12,
14
15
  sm: 14,
15
16
  md: 16,
16
- lg: 18
17
+ lg: 16,
18
+ xl: 18
17
19
  },
18
20
  color: {
19
21
  default: {
@@ -41,5 +41,10 @@ export declare const en: {
41
41
  on: string;
42
42
  off: string;
43
43
  };
44
+ validation: {
45
+ required: string;
46
+ min: string;
47
+ max: string;
48
+ };
44
49
  };
45
50
  export type LocaleText = typeof en;
@@ -40,6 +40,11 @@ const en = {
40
40
  switch: {
41
41
  on: 'On',
42
42
  off: 'Off'
43
+ },
44
+ validation: {
45
+ required: 'This field is required',
46
+ min: 'Value must be greater than {min}',
47
+ max: 'Value must be less than {max}'
43
48
  }
44
49
  };
45
50
  export { en };
@@ -45,6 +45,11 @@ export declare const locales: {
45
45
  on: string;
46
46
  off: string;
47
47
  };
48
+ validation: {
49
+ required: string;
50
+ min: string;
51
+ max: string;
52
+ };
48
53
  };
49
54
  zh: {
50
55
  datePicker: {
@@ -89,6 +94,11 @@ export declare const locales: {
89
94
  on: string;
90
95
  off: string;
91
96
  };
97
+ validation: {
98
+ required: string;
99
+ min: string;
100
+ max: string;
101
+ };
92
102
  };
93
103
  };
94
104
  export declare function getLocaleText(locale: Locale): {
@@ -134,4 +144,9 @@ export declare function getLocaleText(locale: Locale): {
134
144
  on: string;
135
145
  off: string;
136
146
  };
147
+ validation: {
148
+ required: string;
149
+ min: string;
150
+ max: string;
151
+ };
137
152
  };
@@ -40,6 +40,11 @@ const zh = {
40
40
  switch: {
41
41
  on: '开',
42
42
  off: '关'
43
+ },
44
+ validation: {
45
+ required: '请输入',
46
+ min: '值不能小于{min}',
47
+ max: '值不能大于{max}'
43
48
  }
44
49
  };
45
50
  export { zh };
@@ -10,12 +10,14 @@ export interface CommonComponentConfig {
10
10
  sm: number;
11
11
  md: number;
12
12
  lg: number;
13
+ xl?: number;
13
14
  };
14
15
  fontSize: {
15
16
  xs?: number;
16
17
  sm: number;
17
18
  md: number;
18
19
  lg: number;
20
+ xl?: number;
19
21
  };
20
22
  color: Record<string, {
21
23
  background: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-network/ui-native",
3
- "version": "0.4.2-beta.9",
3
+ "version": "0.5.1-beta.0",
4
4
  "main": "./entry.js",
5
5
  "react-native": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -44,8 +44,9 @@
44
44
  "react-native-paper": "^5.14.5",
45
45
  "react-native-size-matters": "^0.4.2",
46
46
  "react-native-toast-message": "^2.3.3",
47
- "@particle-network/icons": "0.4.2-beta.7",
48
- "@particle-network/ui-shared": "0.3.2-beta.3"
47
+ "react-native-worklets": "0.5.1",
48
+ "@particle-network/icons": "0.5.1-beta.0",
49
+ "@particle-network/ui-shared": "0.4.0"
49
50
  },
50
51
  "devDependencies": {
51
52
  "@babel/core": "^7.24.0",
@@ -59,13 +60,13 @@
59
60
  "@rsbuild/core": "^1.5.0",
60
61
  "@rsbuild/plugin-react": "^1.3.5",
61
62
  "@rslib/core": "^0.12.2",
62
- "@storybook/addon-docs": "^9.1.6",
63
- "@storybook/addon-ondevice-actions": "^9.1.2",
64
- "@storybook/addon-ondevice-backgrounds": "^9.1.2",
65
- "@storybook/addon-ondevice-controls": "^9.1.2",
66
- "@storybook/addon-ondevice-notes": "^9.1.2",
67
- "@storybook/react-native": "^9.1.2",
68
- "@storybook/react-native-web-vite": "^9.1.6",
63
+ "@storybook/addon-docs": "^10.0.0",
64
+ "@storybook/addon-ondevice-actions": "^10.0.0",
65
+ "@storybook/addon-ondevice-backgrounds": "^10.0.0",
66
+ "@storybook/addon-ondevice-controls": "^10.0.0",
67
+ "@storybook/addon-ondevice-notes": "^10.0.0",
68
+ "@storybook/react-native": "^10.0.0",
69
+ "@storybook/react-native-web-vite": "^10.0.0",
69
70
  "@types/react": "^19.1.10",
70
71
  "babel-plugin-module-resolver": "^5.0.2",
71
72
  "babel-plugin-react-docgen-typescript": "^1.5.1",
@@ -79,18 +80,18 @@
79
80
  "react-dom": "19.1.0",
80
81
  "react-native": "0.81.5",
81
82
  "react-native-gesture-handler": "~2.28.0",
82
- "react-native-reanimated": "~4.1.0",
83
+ "react-native-reanimated": "4.1.6",
83
84
  "react-native-safe-area-context": "5.6.1",
84
85
  "react-native-svg": "15.12.1",
85
86
  "react-native-web": "^0.21.1",
86
87
  "serve": "^14.2.5",
87
- "storybook": "^9.1.6",
88
+ "storybook": "^10.0.0",
88
89
  "unfetch": "^4.2.0",
89
90
  "vite": "^6.3.5",
90
91
  "zustand": "^5.0.8",
91
- "@particle-network/icons": "0.4.2-beta.7",
92
- "@particle-network/eslint-config": "0.3.0",
93
- "@particle-network/lintstaged-config": "0.1.0"
92
+ "@particle-network/icons": "0.5.1-beta.0",
93
+ "@particle-network/lintstaged-config": "0.1.0",
94
+ "@particle-network/eslint-config": "0.3.0"
94
95
  },
95
96
  "overrides": {
96
97
  "react-docgen-typescript": "2.2.2",