@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.
- package/README.md +57 -0
- package/dist/components/ProgressWrapper/index.d.ts +35 -0
- package/dist/components/ProgressWrapper/index.js +120 -0
- package/dist/components/Text/index.d.ts +2 -0
- package/dist/components/Text/index.js +2 -0
- package/dist/components/Text/text.d.ts +4 -0
- package/dist/components/Text/text.js +196 -0
- package/dist/components/Text/text.types.d.ts +109 -0
- package/dist/components/Text/text.types.js +77 -0
- package/dist/components/UXButton/button.d.ts +3 -0
- package/dist/components/UXButton/button.js +74 -0
- package/dist/components/UXButton/button.styles.d.ts +53 -0
- package/dist/components/UXButton/button.styles.js +157 -0
- package/dist/components/UXButton/button.types.d.ts +18 -0
- package/dist/components/UXButton/button.types.js +0 -0
- package/dist/components/UXButton/index.d.ts +2 -0
- package/dist/components/UXButton/index.js +1 -0
- package/dist/components/UXCheckbox/checkbox-group.d.ts +8 -0
- package/dist/components/UXCheckbox/checkbox-group.js +30 -0
- package/dist/components/UXCheckbox/checkbox.d.ts +10 -0
- package/dist/components/UXCheckbox/checkbox.js +78 -0
- package/dist/components/UXCheckbox/context.d.ts +8 -0
- package/dist/components/UXCheckbox/context.js +8 -0
- package/dist/components/UXCheckbox/index.d.ts +4 -0
- package/dist/components/UXCheckbox/index.js +3 -0
- package/dist/components/UXCheckbox/types.d.ts +6 -0
- package/dist/components/UXCheckbox/types.js +0 -0
- package/dist/components/UXChip/chip.d.ts +3 -0
- package/dist/components/UXChip/chip.js +48 -0
- package/dist/components/UXChip/index.d.ts +2 -0
- package/dist/components/UXChip/index.js +1 -0
- package/dist/components/UXChip/styles.d.ts +24 -0
- package/dist/components/UXChip/styles.js +70 -0
- package/dist/components/UXChip/types.d.ts +11 -0
- package/dist/components/UXChip/types.js +0 -0
- package/dist/components/UXDivider/index.d.ts +8 -0
- package/dist/components/UXDivider/index.js +34 -0
- package/dist/components/UXHint/index.d.ts +7 -0
- package/dist/components/UXHint/index.js +19 -0
- package/dist/components/UXModal/index.d.ts +24 -0
- package/dist/components/UXModal/index.js +271 -0
- package/dist/components/UXPressable/index.d.ts +4 -0
- package/dist/components/UXPressable/index.js +36 -0
- package/dist/components/UXRadio/context.d.ts +7 -0
- package/dist/components/UXRadio/context.js +10 -0
- package/dist/components/UXRadio/index.d.ts +2 -0
- package/dist/components/UXRadio/index.js +2 -0
- package/dist/components/UXRadio/radio-group.d.ts +5 -0
- package/dist/components/UXRadio/radio-group.js +21 -0
- package/dist/components/UXRadio/radio.d.ts +5 -0
- package/dist/components/UXRadio/radio.js +67 -0
- package/dist/components/UXRadio/types.d.ts +10 -0
- package/dist/components/UXRadio/types.js +0 -0
- package/dist/components/UXSwitch/index.d.ts +2 -0
- package/dist/components/UXSwitch/index.js +1 -0
- package/dist/components/UXSwitch/styles.d.ts +16 -0
- package/dist/components/UXSwitch/styles.js +58 -0
- package/dist/components/UXSwitch/switch.d.ts +3 -0
- package/dist/components/UXSwitch/switch.js +103 -0
- package/dist/components/UXSwitch/types.d.ts +11 -0
- package/dist/components/UXSwitch/types.js +0 -0
- package/dist/components/UXTabs/context.d.ts +5 -0
- package/dist/components/UXTabs/context.js +8 -0
- package/dist/components/UXTabs/index.d.ts +4 -0
- package/dist/components/UXTabs/index.js +3 -0
- package/dist/components/UXTabs/styles.d.ts +30 -0
- package/dist/components/UXTabs/styles.js +191 -0
- package/dist/components/UXTabs/tab.d.ts +3 -0
- package/dist/components/UXTabs/tab.js +55 -0
- package/dist/components/UXTabs/tabs.d.ts +3 -0
- package/dist/components/UXTabs/tabs.js +66 -0
- package/dist/components/UXTabs/types.d.ts +23 -0
- package/dist/components/UXTabs/types.js +0 -0
- package/dist/components/UXTooltip/index.d.ts +6 -0
- package/dist/components/UXTooltip/index.js +32 -0
- package/dist/components/UXTouchableOpacity/index.d.ts +4 -0
- package/dist/components/UXTouchableOpacity/index.js +24 -0
- package/dist/components/index.d.ts +22 -0
- package/dist/components/index.js +22 -0
- package/dist/components/input/index.d.ts +3 -0
- package/dist/components/input/index.js +2 -0
- package/dist/components/input/input.d.ts +3 -0
- package/dist/components/input/input.js +138 -0
- package/dist/components/input/number-input.d.ts +3 -0
- package/dist/components/input/number-input.js +231 -0
- package/dist/components/input/styles.d.ts +31 -0
- package/dist/components/input/styles.js +102 -0
- package/dist/components/input/types.d.ts +61 -0
- package/dist/components/input/types.js +0 -0
- package/dist/components/layout/Box/box.d.ts +12 -0
- package/dist/components/layout/Box/box.js +89 -0
- package/dist/components/layout/Box/index.d.ts +3 -0
- package/dist/components/layout/Box/index.js +2 -0
- package/dist/components/layout/Box/useBox.style.d.ts +3 -0
- package/dist/components/layout/Box/useBox.style.js +141 -0
- package/dist/components/layout/Box/useBox.type.d.ts +292 -0
- package/dist/components/layout/Box/useBox.type.js +0 -0
- package/dist/components/layout/Center.d.ts +5 -0
- package/dist/components/layout/Center.js +10 -0
- package/dist/components/layout/Circle.d.ts +7 -0
- package/dist/components/layout/Circle.js +14 -0
- package/dist/components/layout/Flex/flex.d.ts +6 -0
- package/dist/components/layout/Flex/flex.js +33 -0
- package/dist/components/layout/Flex/index.d.ts +4 -0
- package/dist/components/layout/Flex/index.js +3 -0
- package/dist/components/layout/Flex/useFlex.style.d.ts +3 -0
- package/dist/components/layout/Flex/useFlex.style.js +122 -0
- package/dist/components/layout/Flex/useFlex.type.d.ts +65 -0
- package/dist/components/layout/Flex/useFlex.type.js +0 -0
- package/dist/components/layout/Flex/useFlexBox.style.d.ts +134 -0
- package/dist/components/layout/Flex/useFlexBox.style.js +26 -0
- package/dist/components/layout/HStack.d.ts +5 -0
- package/dist/components/layout/HStack.js +11 -0
- package/dist/components/layout/Square.d.ts +9 -0
- package/dist/components/layout/Square.js +14 -0
- package/dist/components/layout/VStack.d.ts +5 -0
- package/dist/components/layout/VStack.js +14 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/useColors.d.ts +7 -0
- package/dist/hooks/useColors.js +18 -0
- package/dist/hooks/useKeyboard.d.ts +4 -0
- package/dist/hooks/useKeyboard.js +29 -0
- package/dist/hooks/useRadius.d.ts +7 -0
- package/dist/hooks/useRadius.js +16 -0
- package/dist/hooks/useSpacing.d.ts +7 -0
- package/dist/hooks/useSpacing.js +16 -0
- package/dist/hooks/useTheme.d.ts +5 -0
- package/dist/hooks/useTheme.js +6 -0
- package/dist/icons/CheckboxOffIcon.d.ts +4 -0
- package/dist/icons/CheckboxOffIcon.js +21 -0
- package/dist/icons/CheckboxOnIcon.d.ts +4 -0
- package/dist/icons/CheckboxOnIcon.js +26 -0
- package/dist/icons/DotIcon.d.ts +4 -0
- package/dist/icons/DotIcon.js +23 -0
- package/dist/icons/QuestionIcon.d.ts +4 -0
- package/dist/icons/QuestionIcon.js +30 -0
- package/dist/icons/RadioOffIcon.d.ts +4 -0
- package/dist/icons/RadioOffIcon.js +22 -0
- package/dist/icons/RadioOnIcon.d.ts +4 -0
- package/dist/icons/RadioOnIcon.js +42 -0
- package/dist/icons/types.d.ts +6 -0
- package/dist/icons/types.js +0 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/provider/ThemeContext.d.ts +3 -0
- package/dist/provider/ThemeContext.js +15 -0
- package/dist/provider/ThemeProvider.d.ts +10 -0
- package/dist/provider/ThemeProvider.js +31 -0
- package/dist/provider/index.d.ts +2 -0
- package/dist/provider/index.js +2 -0
- package/dist/theme/colors.d.ts +6 -0
- package/dist/theme/colors.js +17 -0
- package/dist/theme/index.d.ts +7 -0
- package/dist/theme/index.js +16 -0
- package/dist/theme/opacity.d.ts +2 -0
- package/dist/theme/opacity.js +3 -0
- package/dist/theme/radius.d.ts +3 -0
- package/dist/theme/radius.js +10 -0
- package/dist/theme/spacing.d.ts +3 -0
- package/dist/theme/spacing.js +10 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +0 -0
- package/dist/types/theme.d.ts +17 -0
- package/dist/types/theme.js +0 -0
- package/dist/utils/triggerHapticFeedback.d.ts +5 -0
- package/dist/utils/triggerHapticFeedback.js +16 -0
- package/package.json +110 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { TextInput } from "react-native";
|
|
4
|
+
import { HStack, Text, VStack } from "../index.js";
|
|
5
|
+
import { useColors } from "../../hooks/index.js";
|
|
6
|
+
import { useStyles } from "./styles.js";
|
|
7
|
+
const UXInput = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
8
|
+
const { containerStyle, wrapperStyle, inputStyle, value: controlledValue, defaultValue, errorMessage, startContent, endContent, isReadOnly, isDisabled, isRequired, isInvalid: isInvalidProp, autoErrorMessage, label, onChangeText, onValueChange, onFocus, onBlur, ...restProps } = props;
|
|
9
|
+
const { getColor } = useColors();
|
|
10
|
+
const inputRef = useRef(null);
|
|
11
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
12
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
13
|
+
const [isInvalid, setIsInvalid] = useState(isInvalidProp);
|
|
14
|
+
useImperativeHandle(ref, ()=>({
|
|
15
|
+
blur: ()=>{
|
|
16
|
+
inputRef.current?.blur();
|
|
17
|
+
},
|
|
18
|
+
focus: ()=>{
|
|
19
|
+
inputRef.current?.focus();
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
useEffect(()=>{
|
|
23
|
+
setIsInvalid(isInvalidProp);
|
|
24
|
+
}, [
|
|
25
|
+
isInvalidProp
|
|
26
|
+
]);
|
|
27
|
+
useEffect(()=>{
|
|
28
|
+
if (!internalValue && isRequired) setIsInvalid(true);
|
|
29
|
+
}, []);
|
|
30
|
+
const styles = useStyles({
|
|
31
|
+
...props,
|
|
32
|
+
isInvalid,
|
|
33
|
+
isFocused
|
|
34
|
+
});
|
|
35
|
+
useEffect(()=>{
|
|
36
|
+
if (void 0 !== controlledValue) setInternalValue(controlledValue);
|
|
37
|
+
else if (void 0 !== defaultValue) setInternalValue(defaultValue);
|
|
38
|
+
}, [
|
|
39
|
+
defaultValue,
|
|
40
|
+
controlledValue
|
|
41
|
+
]);
|
|
42
|
+
const handleFocus = useCallback((e)=>{
|
|
43
|
+
setIsFocused(true);
|
|
44
|
+
onFocus?.(e);
|
|
45
|
+
}, [
|
|
46
|
+
onFocus
|
|
47
|
+
]);
|
|
48
|
+
const handleBlur = useCallback((e)=>{
|
|
49
|
+
setIsFocused(false);
|
|
50
|
+
onBlur?.(e);
|
|
51
|
+
}, [
|
|
52
|
+
onBlur
|
|
53
|
+
]);
|
|
54
|
+
const validationResult = useMemo(()=>{
|
|
55
|
+
if (!internalValue && isRequired) {
|
|
56
|
+
setIsInvalid(true);
|
|
57
|
+
return {
|
|
58
|
+
isValid: false,
|
|
59
|
+
errorMessage: 'This field is required'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
setIsInvalid(false);
|
|
63
|
+
return {
|
|
64
|
+
isValid: true
|
|
65
|
+
};
|
|
66
|
+
}, [
|
|
67
|
+
internalValue,
|
|
68
|
+
isRequired
|
|
69
|
+
]);
|
|
70
|
+
const renderError = useMemo(async ()=>{
|
|
71
|
+
if (isInvalidProp && errorMessage) {
|
|
72
|
+
setIsInvalid(true);
|
|
73
|
+
return errorMessage;
|
|
74
|
+
}
|
|
75
|
+
if (!validationResult.isValid) return autoErrorMessage ? validationResult.errorMessage : null;
|
|
76
|
+
return null;
|
|
77
|
+
}, [
|
|
78
|
+
validationResult,
|
|
79
|
+
errorMessage,
|
|
80
|
+
isInvalidProp,
|
|
81
|
+
autoErrorMessage
|
|
82
|
+
]);
|
|
83
|
+
const renderContent = async (content)=>{
|
|
84
|
+
if (!content) return null;
|
|
85
|
+
if ('object' == typeof content) return content;
|
|
86
|
+
return /*#__PURE__*/ jsx(Text, {
|
|
87
|
+
color: "tertiary",
|
|
88
|
+
children: content
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
return /*#__PURE__*/ jsxs(VStack, {
|
|
92
|
+
gap: 4,
|
|
93
|
+
style: containerStyle,
|
|
94
|
+
children: [
|
|
95
|
+
label ? /*#__PURE__*/ jsx(Text, {
|
|
96
|
+
children: label
|
|
97
|
+
}) : null,
|
|
98
|
+
/*#__PURE__*/ jsxs(HStack, {
|
|
99
|
+
borderStyle: "solid",
|
|
100
|
+
gap: 6,
|
|
101
|
+
ph: 12,
|
|
102
|
+
style: [
|
|
103
|
+
styles.container,
|
|
104
|
+
wrapperStyle
|
|
105
|
+
],
|
|
106
|
+
children: [
|
|
107
|
+
renderContent(startContent),
|
|
108
|
+
/*#__PURE__*/ jsx(TextInput, {
|
|
109
|
+
ref: inputRef,
|
|
110
|
+
editable: !isDisabled && !isReadOnly,
|
|
111
|
+
placeholderTextColor: getColor('tertiary'),
|
|
112
|
+
selectionColor: isInvalid ? `${styles.container.borderColor}80` : styles.container.borderColor,
|
|
113
|
+
style: [
|
|
114
|
+
styles.input,
|
|
115
|
+
inputStyle
|
|
116
|
+
],
|
|
117
|
+
value: internalValue,
|
|
118
|
+
onBlur: handleBlur,
|
|
119
|
+
onChangeText: (v)=>{
|
|
120
|
+
setInternalValue(v);
|
|
121
|
+
onChangeText?.(v);
|
|
122
|
+
onValueChange?.(v);
|
|
123
|
+
},
|
|
124
|
+
onFocus: handleFocus,
|
|
125
|
+
...restProps
|
|
126
|
+
}),
|
|
127
|
+
renderContent(endContent)
|
|
128
|
+
]
|
|
129
|
+
}),
|
|
130
|
+
!!renderError && /*#__PURE__*/ jsx(Text, {
|
|
131
|
+
color: "danger",
|
|
132
|
+
children: renderError
|
|
133
|
+
})
|
|
134
|
+
]
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
UXInput.displayName = 'UXInput';
|
|
138
|
+
export { UXInput };
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Platform, TextInput } from "react-native";
|
|
4
|
+
import { HStack, Text, VStack } from "../index.js";
|
|
5
|
+
import { useColors } from "../../hooks/index.js";
|
|
6
|
+
import { useStyles } from "./styles.js";
|
|
7
|
+
const UXNumberInput = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
8
|
+
const { containerStyle, wrapperStyle, inputStyle, value: controlledValue, defaultValue, errorMessage, minValue, maxValue, formatOptions, startContent, endContent, isRequired, isReadOnly, isDisabled, isInvalid: isInvalidProp, autoErrorMessage, allowNegative, label, onChangeText, onValueChange, onFocus, onBlur, ...restProps } = props;
|
|
9
|
+
const { getColor } = useColors();
|
|
10
|
+
const inputRef = useRef(null);
|
|
11
|
+
const [internalValue, setInternalValue] = useState(defaultValue ?? NaN);
|
|
12
|
+
const [displayText, setDisplayText] = useState(defaultValue?.toString() ?? '');
|
|
13
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
14
|
+
const [isInvalid, setIsInvalid] = useState(isInvalidProp);
|
|
15
|
+
useImperativeHandle(ref, ()=>({
|
|
16
|
+
blur: ()=>{
|
|
17
|
+
inputRef.current?.blur();
|
|
18
|
+
},
|
|
19
|
+
focus: ()=>{
|
|
20
|
+
inputRef.current?.focus();
|
|
21
|
+
}
|
|
22
|
+
}));
|
|
23
|
+
useEffect(()=>{
|
|
24
|
+
setIsInvalid(isInvalidProp);
|
|
25
|
+
}, [
|
|
26
|
+
isInvalidProp
|
|
27
|
+
]);
|
|
28
|
+
useEffect(()=>{
|
|
29
|
+
if (isNaN(internalValue) && isRequired) setIsInvalid(true);
|
|
30
|
+
if (void 0 !== minValue && internalValue < minValue) setIsInvalid(true);
|
|
31
|
+
if (void 0 !== maxValue && internalValue > maxValue) setIsInvalid(true);
|
|
32
|
+
}, []);
|
|
33
|
+
const styles = useStyles({
|
|
34
|
+
...props,
|
|
35
|
+
isInvalid,
|
|
36
|
+
isFocused
|
|
37
|
+
});
|
|
38
|
+
useEffect(()=>{
|
|
39
|
+
if (void 0 !== controlledValue) {
|
|
40
|
+
setInternalValue(controlledValue);
|
|
41
|
+
setDisplayText(isNaN(controlledValue) ? '' : controlledValue.toString());
|
|
42
|
+
} else if (void 0 !== defaultValue) {
|
|
43
|
+
setInternalValue(defaultValue);
|
|
44
|
+
setDisplayText(isNaN(defaultValue) ? '' : defaultValue.toString());
|
|
45
|
+
}
|
|
46
|
+
}, [
|
|
47
|
+
defaultValue,
|
|
48
|
+
controlledValue
|
|
49
|
+
]);
|
|
50
|
+
const numberFormatter = useMemo(()=>{
|
|
51
|
+
if (formatOptions) return new Intl.NumberFormat(void 0, formatOptions);
|
|
52
|
+
return null;
|
|
53
|
+
}, [
|
|
54
|
+
formatOptions
|
|
55
|
+
]);
|
|
56
|
+
const validationResult = useMemo(()=>{
|
|
57
|
+
if (isNaN(internalValue) && isRequired) return {
|
|
58
|
+
isValid: false,
|
|
59
|
+
errorMessage: 'This field is required'
|
|
60
|
+
};
|
|
61
|
+
if (void 0 !== minValue && internalValue < minValue) return {
|
|
62
|
+
isValid: false,
|
|
63
|
+
errorMessage: `Value must be at least ${minValue}`
|
|
64
|
+
};
|
|
65
|
+
if (void 0 !== maxValue && internalValue > maxValue) return {
|
|
66
|
+
isValid: false,
|
|
67
|
+
errorMessage: `Value must be at most ${maxValue}`
|
|
68
|
+
};
|
|
69
|
+
setIsInvalid(false);
|
|
70
|
+
return {
|
|
71
|
+
isValid: true
|
|
72
|
+
};
|
|
73
|
+
}, [
|
|
74
|
+
internalValue,
|
|
75
|
+
isRequired,
|
|
76
|
+
minValue,
|
|
77
|
+
maxValue
|
|
78
|
+
]);
|
|
79
|
+
const adjustValueToRange = useCallback((num)=>{
|
|
80
|
+
const numValue = isNaN(num) ? 0 : num;
|
|
81
|
+
if (void 0 !== minValue && numValue < minValue) return minValue;
|
|
82
|
+
if (void 0 !== maxValue && numValue > maxValue) return maxValue;
|
|
83
|
+
return numValue;
|
|
84
|
+
}, [
|
|
85
|
+
minValue,
|
|
86
|
+
maxValue
|
|
87
|
+
]);
|
|
88
|
+
const adjustValueToFractionDigits = useCallback((numValue)=>{
|
|
89
|
+
if (formatOptions?.minimumFractionDigits !== void 0 || formatOptions?.maximumFractionDigits !== void 0) return Number(numberFormatter?.format(numValue).replaceAll(',', ''));
|
|
90
|
+
return numValue;
|
|
91
|
+
}, [
|
|
92
|
+
formatOptions,
|
|
93
|
+
numberFormatter
|
|
94
|
+
]);
|
|
95
|
+
const handleChangeText = useCallback((text)=>{
|
|
96
|
+
const cleanedText = text.replace(/[^0-9.-]/gu, '');
|
|
97
|
+
const parts = cleanedText.split('.');
|
|
98
|
+
if (parts.length > 2) return;
|
|
99
|
+
if ((cleanedText.match(/-/gu) || []).length > 1) return;
|
|
100
|
+
if (cleanedText.includes('-') && !cleanedText.startsWith('-')) return;
|
|
101
|
+
setDisplayText(cleanedText);
|
|
102
|
+
onChangeText?.(cleanedText);
|
|
103
|
+
const numValue = parseFloat(cleanedText);
|
|
104
|
+
if (isNaN(numValue)) {
|
|
105
|
+
setInternalValue(NaN);
|
|
106
|
+
onValueChange?.(NaN);
|
|
107
|
+
} else {
|
|
108
|
+
setInternalValue(numValue);
|
|
109
|
+
onValueChange?.(numValue);
|
|
110
|
+
}
|
|
111
|
+
}, [
|
|
112
|
+
onChangeText,
|
|
113
|
+
onValueChange
|
|
114
|
+
]);
|
|
115
|
+
const handleFocus = useCallback((e)=>{
|
|
116
|
+
setIsFocused(true);
|
|
117
|
+
onFocus?.(e);
|
|
118
|
+
}, [
|
|
119
|
+
onFocus
|
|
120
|
+
]);
|
|
121
|
+
const handleBlur = useCallback((e)=>{
|
|
122
|
+
setIsFocused(false);
|
|
123
|
+
const adjustedValue = adjustValueToFractionDigits(adjustValueToRange(internalValue));
|
|
124
|
+
if (adjustedValue !== internalValue) {
|
|
125
|
+
const adjustedText = adjustedValue.toString();
|
|
126
|
+
setDisplayText(adjustedText);
|
|
127
|
+
setInternalValue(adjustedValue);
|
|
128
|
+
onChangeText?.(adjustedText);
|
|
129
|
+
onValueChange?.(adjustedValue);
|
|
130
|
+
}
|
|
131
|
+
onBlur?.(e);
|
|
132
|
+
}, [
|
|
133
|
+
internalValue,
|
|
134
|
+
onChangeText,
|
|
135
|
+
onValueChange,
|
|
136
|
+
adjustValueToRange,
|
|
137
|
+
adjustValueToFractionDigits,
|
|
138
|
+
onBlur
|
|
139
|
+
]);
|
|
140
|
+
const displayValue = useMemo(()=>{
|
|
141
|
+
if (isFocused) return displayText;
|
|
142
|
+
if (isNaN(internalValue)) return '';
|
|
143
|
+
if (numberFormatter) {
|
|
144
|
+
const formattedValue = numberFormatter.format(internalValue);
|
|
145
|
+
if (formatOptions?.signDisplay === 'exceptZero' || formatOptions?.signDisplay === 'always') {
|
|
146
|
+
if (internalValue > 0) return `+${formattedValue}`;
|
|
147
|
+
else if (internalValue < 0) ;
|
|
148
|
+
else if ('always' === formatOptions.signDisplay) return `+${formattedValue}`;
|
|
149
|
+
}
|
|
150
|
+
return formattedValue;
|
|
151
|
+
}
|
|
152
|
+
return internalValue.toString();
|
|
153
|
+
}, [
|
|
154
|
+
internalValue,
|
|
155
|
+
displayText,
|
|
156
|
+
numberFormatter,
|
|
157
|
+
isFocused,
|
|
158
|
+
formatOptions
|
|
159
|
+
]);
|
|
160
|
+
const renderError = useMemo(async ()=>{
|
|
161
|
+
if (isInvalidProp && errorMessage) {
|
|
162
|
+
setIsInvalid(true);
|
|
163
|
+
return errorMessage;
|
|
164
|
+
}
|
|
165
|
+
if (!validationResult.isValid) return autoErrorMessage ? validationResult.errorMessage : null;
|
|
166
|
+
return null;
|
|
167
|
+
}, [
|
|
168
|
+
validationResult,
|
|
169
|
+
errorMessage,
|
|
170
|
+
isInvalidProp,
|
|
171
|
+
autoErrorMessage
|
|
172
|
+
]);
|
|
173
|
+
const keyboardType = useMemo(()=>{
|
|
174
|
+
if (allowNegative) return 'ios' === Platform.OS ? 'numbers-and-punctuation' : 'default';
|
|
175
|
+
return 'numeric';
|
|
176
|
+
}, [
|
|
177
|
+
allowNegative
|
|
178
|
+
]);
|
|
179
|
+
const renderContent = async (content)=>{
|
|
180
|
+
if (!content) return null;
|
|
181
|
+
if ('object' == typeof content) return content;
|
|
182
|
+
return /*#__PURE__*/ jsx(Text, {
|
|
183
|
+
color: "tertiary",
|
|
184
|
+
children: content
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
return /*#__PURE__*/ jsxs(VStack, {
|
|
188
|
+
gap: 4,
|
|
189
|
+
style: containerStyle,
|
|
190
|
+
children: [
|
|
191
|
+
label ? /*#__PURE__*/ jsx(Text, {
|
|
192
|
+
children: label
|
|
193
|
+
}) : null,
|
|
194
|
+
/*#__PURE__*/ jsxs(HStack, {
|
|
195
|
+
borderStyle: "solid",
|
|
196
|
+
gap: 6,
|
|
197
|
+
ph: 12,
|
|
198
|
+
style: [
|
|
199
|
+
styles.container,
|
|
200
|
+
wrapperStyle
|
|
201
|
+
],
|
|
202
|
+
children: [
|
|
203
|
+
renderContent(startContent),
|
|
204
|
+
/*#__PURE__*/ jsx(TextInput, {
|
|
205
|
+
ref: inputRef,
|
|
206
|
+
editable: !isDisabled && !isReadOnly,
|
|
207
|
+
keyboardType: keyboardType,
|
|
208
|
+
placeholderTextColor: getColor('tertiary'),
|
|
209
|
+
selectionColor: isInvalid ? `${styles.container.borderColor}80` : styles.container.borderColor,
|
|
210
|
+
style: [
|
|
211
|
+
styles.input,
|
|
212
|
+
inputStyle
|
|
213
|
+
],
|
|
214
|
+
value: displayValue,
|
|
215
|
+
onBlur: handleBlur,
|
|
216
|
+
onChangeText: handleChangeText,
|
|
217
|
+
onFocus: handleFocus,
|
|
218
|
+
...restProps
|
|
219
|
+
}),
|
|
220
|
+
renderContent(endContent)
|
|
221
|
+
]
|
|
222
|
+
}),
|
|
223
|
+
!!renderError && /*#__PURE__*/ jsx(Text, {
|
|
224
|
+
color: "danger",
|
|
225
|
+
children: renderError
|
|
226
|
+
})
|
|
227
|
+
]
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
UXNumberInput.displayName = 'UXNumberInput';
|
|
231
|
+
export { UXNumberInput };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { UXInputCommonProps } from './types';
|
|
2
|
+
type UseStylesProps = UXInputCommonProps & {
|
|
3
|
+
isFocused?: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare const useStyles: ({ isInvalid, isDisabled, fullWidth, isFocused, color, size, variant, radius, width: widthProp, textAlign, }: UseStylesProps) => {
|
|
6
|
+
container: {
|
|
7
|
+
width: number | "auto" | `${number}%` | import("react-native").Animated.AnimatedNode;
|
|
8
|
+
height: number;
|
|
9
|
+
borderRadius: number | undefined;
|
|
10
|
+
borderColor: string | undefined;
|
|
11
|
+
backgroundColor: string | undefined;
|
|
12
|
+
borderWidth: number;
|
|
13
|
+
opacity: number;
|
|
14
|
+
};
|
|
15
|
+
input: {
|
|
16
|
+
flex: number;
|
|
17
|
+
paddingTop: number;
|
|
18
|
+
paddingBottom: number;
|
|
19
|
+
paddingLeft: number;
|
|
20
|
+
paddingRight: number;
|
|
21
|
+
margin: number;
|
|
22
|
+
fontSize: number;
|
|
23
|
+
color: string | undefined;
|
|
24
|
+
fontWeight: "500";
|
|
25
|
+
textAlign: "left" | "center" | "right";
|
|
26
|
+
};
|
|
27
|
+
clearButton: {
|
|
28
|
+
padding: number;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { StyleSheet } from "react-native";
|
|
3
|
+
import { ms } from "react-native-size-matters";
|
|
4
|
+
import { sizeMap } from "@particle-network/ui-shared";
|
|
5
|
+
import { useColors, useRadius } from "../../hooks/index.js";
|
|
6
|
+
import { disabledOpacity } from "../../theme/index.js";
|
|
7
|
+
const fontSizeMap = {
|
|
8
|
+
sm: ms(12),
|
|
9
|
+
md: ms(12),
|
|
10
|
+
lg: ms(14)
|
|
11
|
+
};
|
|
12
|
+
const radiusMap = {
|
|
13
|
+
sm: 'sm',
|
|
14
|
+
md: 'sm',
|
|
15
|
+
lg: 'md'
|
|
16
|
+
};
|
|
17
|
+
const useStyles = ({ isInvalid, isDisabled, fullWidth, isFocused, color = 'primary', size = 'md', variant = 'flat', radius, width: widthProp, textAlign = 'left' })=>{
|
|
18
|
+
const { getColor } = useColors();
|
|
19
|
+
const { getRadius } = useRadius();
|
|
20
|
+
const width = useMemo(()=>{
|
|
21
|
+
if (fullWidth) return '100%';
|
|
22
|
+
if (widthProp) return widthProp;
|
|
23
|
+
return 'auto';
|
|
24
|
+
}, [
|
|
25
|
+
fullWidth,
|
|
26
|
+
widthProp
|
|
27
|
+
]);
|
|
28
|
+
const height = useMemo(()=>ms(sizeMap[size]), [
|
|
29
|
+
size
|
|
30
|
+
]);
|
|
31
|
+
const fontSize = useMemo(()=>fontSizeMap[size], [
|
|
32
|
+
size
|
|
33
|
+
]);
|
|
34
|
+
const borderRadius = useMemo(()=>getRadius(radius ?? radiusMap[size]), [
|
|
35
|
+
radius,
|
|
36
|
+
size
|
|
37
|
+
]);
|
|
38
|
+
const borderColor = useMemo(()=>{
|
|
39
|
+
if (isInvalid) return getColor('danger');
|
|
40
|
+
if (isFocused) return getColor(color);
|
|
41
|
+
if ('bordered' === variant) return getColor(color);
|
|
42
|
+
return 'transparent';
|
|
43
|
+
}, [
|
|
44
|
+
color,
|
|
45
|
+
getColor,
|
|
46
|
+
variant,
|
|
47
|
+
isFocused,
|
|
48
|
+
isInvalid
|
|
49
|
+
]);
|
|
50
|
+
const inputTextColor = useMemo(()=>{
|
|
51
|
+
if (isInvalid) return getColor('danger');
|
|
52
|
+
return getColor('foreground');
|
|
53
|
+
}, [
|
|
54
|
+
isInvalid,
|
|
55
|
+
getColor
|
|
56
|
+
]);
|
|
57
|
+
const backgroundColor = useMemo(()=>{
|
|
58
|
+
if (isInvalid) return `${getColor('danger')}50`;
|
|
59
|
+
return getColor('bg-200');
|
|
60
|
+
}, [
|
|
61
|
+
isInvalid,
|
|
62
|
+
getColor
|
|
63
|
+
]);
|
|
64
|
+
const styles = useMemo(()=>StyleSheet.create({
|
|
65
|
+
container: {
|
|
66
|
+
width,
|
|
67
|
+
height,
|
|
68
|
+
borderRadius,
|
|
69
|
+
borderColor,
|
|
70
|
+
backgroundColor,
|
|
71
|
+
borderWidth: 1,
|
|
72
|
+
opacity: isDisabled ? disabledOpacity : 1
|
|
73
|
+
},
|
|
74
|
+
input: {
|
|
75
|
+
flex: 1,
|
|
76
|
+
paddingTop: 0,
|
|
77
|
+
paddingBottom: 0,
|
|
78
|
+
paddingLeft: 0,
|
|
79
|
+
paddingRight: 0,
|
|
80
|
+
margin: 0,
|
|
81
|
+
fontSize,
|
|
82
|
+
color: inputTextColor,
|
|
83
|
+
fontWeight: '500',
|
|
84
|
+
textAlign
|
|
85
|
+
},
|
|
86
|
+
clearButton: {
|
|
87
|
+
padding: ms(4)
|
|
88
|
+
}
|
|
89
|
+
}), [
|
|
90
|
+
width,
|
|
91
|
+
height,
|
|
92
|
+
borderRadius,
|
|
93
|
+
borderColor,
|
|
94
|
+
isDisabled,
|
|
95
|
+
fontSize,
|
|
96
|
+
inputTextColor,
|
|
97
|
+
textAlign,
|
|
98
|
+
backgroundColor
|
|
99
|
+
]);
|
|
100
|
+
return styles;
|
|
101
|
+
};
|
|
102
|
+
export { useStyles };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { StyleProp, TextInputProps, TextStyle, ViewStyle } from 'react-native';
|
|
3
|
+
import type { UXForegroundColor, UXRadius, UXSize } from '@particle-network/ui-shared';
|
|
4
|
+
export interface UXInputRef {
|
|
5
|
+
blur: () => void;
|
|
6
|
+
focus: () => void;
|
|
7
|
+
}
|
|
8
|
+
export interface ValidationResult {
|
|
9
|
+
isValid: boolean;
|
|
10
|
+
errorMessage?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface UXInputCommonProps extends Omit<TextInputProps, 'value' | 'defaultValue'> {
|
|
13
|
+
/**
|
|
14
|
+
* 最外层容器,包括 label 和 error
|
|
15
|
+
*/
|
|
16
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
17
|
+
/**
|
|
18
|
+
* 输入框容器
|
|
19
|
+
*/
|
|
20
|
+
wrapperStyle?: StyleProp<ViewStyle>;
|
|
21
|
+
/**
|
|
22
|
+
* 输入框样式
|
|
23
|
+
*/
|
|
24
|
+
inputStyle?: StyleProp<TextStyle>;
|
|
25
|
+
color?: UXForegroundColor;
|
|
26
|
+
size?: UXSize;
|
|
27
|
+
variant?: 'bordered' | 'flat';
|
|
28
|
+
radius?: UXRadius;
|
|
29
|
+
width?: ViewStyle['width'];
|
|
30
|
+
errorMessage?: ReactNode;
|
|
31
|
+
startContent?: ReactNode;
|
|
32
|
+
endContent?: ReactNode;
|
|
33
|
+
fullWidth?: boolean;
|
|
34
|
+
isClearable?: boolean;
|
|
35
|
+
isRequired?: boolean;
|
|
36
|
+
isReadOnly?: boolean;
|
|
37
|
+
isDisabled?: boolean;
|
|
38
|
+
isInvalid?: boolean;
|
|
39
|
+
label?: string;
|
|
40
|
+
textAlign?: 'left' | 'center' | 'right';
|
|
41
|
+
autoErrorMessage?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface UXInputProps extends UXInputCommonProps {
|
|
44
|
+
value?: string;
|
|
45
|
+
defaultValue?: string;
|
|
46
|
+
onValueChange?: (value: string) => void;
|
|
47
|
+
}
|
|
48
|
+
export interface UXNumberInputProps extends UXInputCommonProps {
|
|
49
|
+
value?: number;
|
|
50
|
+
defaultValue?: number;
|
|
51
|
+
minValue?: number;
|
|
52
|
+
maxValue?: number;
|
|
53
|
+
formatOptions?: Intl.NumberFormatOptions;
|
|
54
|
+
step?: number;
|
|
55
|
+
showStepper?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* 启用带符号的键盘
|
|
58
|
+
*/
|
|
59
|
+
allowNegative?: boolean;
|
|
60
|
+
onValueChange?: (value: number) => void;
|
|
61
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, type ViewProps } from 'react-native';
|
|
3
|
+
import type { UseBoxProps } from './useBox.type';
|
|
4
|
+
export interface BoxProps extends ViewProps, UseBoxProps {
|
|
5
|
+
/**
|
|
6
|
+
* Child to render
|
|
7
|
+
*/
|
|
8
|
+
as?: React.ReactElement<{
|
|
9
|
+
style?: unknown;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
export declare const Box: React.ForwardRefExoticComponent<BoxProps & React.RefAttributes<View>>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import react, { forwardRef } from "react";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { useBoxStyle } from "./useBox.style.js";
|
|
5
|
+
const Box = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
6
|
+
const { as, style, fullWidth, fullHeight, h, minH, maxH, w, minW, maxW, m, mt, mr, mb, ml, ms, me, mh, mv, p, pt, pr, pb, pl, ps, pe, ph, pv, borderStyle, border, borderTop, borderRight, borderBottom, borderLeft, borderStart, borderEnd, borderColor, borderTopColor, borderRightColor, borderBottomColor, borderLeftColor, borderStartColor, borderEndColor, radius, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, topStartRadius, topEndRadius, bottomStartRadius, bottomEndRadius, position, top, right, bottom, left, start, end, bg, bgOpacity, opacity, zIndex, overflow, ...restProps } = props;
|
|
7
|
+
const boxStyle = useBoxStyle({
|
|
8
|
+
fullWidth,
|
|
9
|
+
fullHeight,
|
|
10
|
+
h,
|
|
11
|
+
minH,
|
|
12
|
+
maxH,
|
|
13
|
+
w,
|
|
14
|
+
minW,
|
|
15
|
+
maxW,
|
|
16
|
+
m,
|
|
17
|
+
mt,
|
|
18
|
+
mr,
|
|
19
|
+
mb,
|
|
20
|
+
ml,
|
|
21
|
+
ms,
|
|
22
|
+
me,
|
|
23
|
+
mh,
|
|
24
|
+
mv,
|
|
25
|
+
p,
|
|
26
|
+
pt,
|
|
27
|
+
pr,
|
|
28
|
+
pb,
|
|
29
|
+
pl,
|
|
30
|
+
ps,
|
|
31
|
+
pe,
|
|
32
|
+
ph,
|
|
33
|
+
pv,
|
|
34
|
+
borderStyle,
|
|
35
|
+
border,
|
|
36
|
+
borderTop,
|
|
37
|
+
borderRight,
|
|
38
|
+
borderBottom,
|
|
39
|
+
borderLeft,
|
|
40
|
+
borderStart,
|
|
41
|
+
borderEnd,
|
|
42
|
+
borderColor,
|
|
43
|
+
borderTopColor,
|
|
44
|
+
borderRightColor,
|
|
45
|
+
borderBottomColor,
|
|
46
|
+
borderLeftColor,
|
|
47
|
+
borderStartColor,
|
|
48
|
+
borderEndColor,
|
|
49
|
+
radius,
|
|
50
|
+
topLeftRadius,
|
|
51
|
+
topRightRadius,
|
|
52
|
+
bottomLeftRadius,
|
|
53
|
+
bottomRightRadius,
|
|
54
|
+
topStartRadius,
|
|
55
|
+
topEndRadius,
|
|
56
|
+
bottomStartRadius,
|
|
57
|
+
bottomEndRadius,
|
|
58
|
+
position,
|
|
59
|
+
top,
|
|
60
|
+
right,
|
|
61
|
+
bottom,
|
|
62
|
+
left,
|
|
63
|
+
start,
|
|
64
|
+
end,
|
|
65
|
+
bg,
|
|
66
|
+
bgOpacity,
|
|
67
|
+
opacity,
|
|
68
|
+
zIndex,
|
|
69
|
+
overflow
|
|
70
|
+
});
|
|
71
|
+
if (as) return /*#__PURE__*/ react.cloneElement(as, {
|
|
72
|
+
...restProps,
|
|
73
|
+
style: [
|
|
74
|
+
boxStyle,
|
|
75
|
+
style,
|
|
76
|
+
as.props.style
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
return /*#__PURE__*/ jsx(View, {
|
|
80
|
+
ref: ref,
|
|
81
|
+
style: [
|
|
82
|
+
boxStyle,
|
|
83
|
+
style
|
|
84
|
+
],
|
|
85
|
+
...restProps
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
Box.displayName = 'UXBox';
|
|
89
|
+
export { Box };
|