@nativetail/ui 0.1.3 → 0.1.4
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/package.json +2 -1
- package/src/components/form-builder/index.tsx +31 -20
- package/src/components/index.ts +2 -0
- package/src/components/input/input.tsx +7 -7
- package/src/components/input/show-password.tsx +1 -1
- package/src/components/multi-step-form/index.tsx +27 -0
- package/src/components/stepper/index.tsx +42 -28
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nativetail/ui",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.4",
|
4
4
|
"description": "",
|
5
5
|
"main": "src/index.ts",
|
6
6
|
"scripts": {},
|
@@ -38,6 +38,7 @@
|
|
38
38
|
"react-hook-form": "^7.51.0",
|
39
39
|
"react-native": "0.74.3",
|
40
40
|
"react-native-actions-sheet": "^0.9.6",
|
41
|
+
"react-native-circular-progress-indicator": "^4.4.2",
|
41
42
|
"react-native-gesture-handler": "^2.17.1",
|
42
43
|
"react-native-mask-text": "^0.14.2",
|
43
44
|
"react-native-reanimated": "~3.10.1",
|
@@ -37,6 +37,7 @@ export type FormBuilderProps<
|
|
37
37
|
onError?: (values: Partial<Record<keyof T, any>>) => void;
|
38
38
|
isSubmitting?: boolean;
|
39
39
|
defaultValues?: DefaultValues<IValues>;
|
40
|
+
inputContainerClassname?: string;
|
40
41
|
};
|
41
42
|
export function FormBuilder<T extends z.ZodRawShape>({
|
42
43
|
schema,
|
@@ -47,6 +48,7 @@ export function FormBuilder<T extends z.ZodRawShape>({
|
|
47
48
|
onError,
|
48
49
|
isSubmitting,
|
49
50
|
defaultValues,
|
51
|
+
inputContainerClassname,
|
50
52
|
}: FormBuilderProps<T>) {
|
51
53
|
const shape = schema.shape;
|
52
54
|
const keys = Object.keys(shape);
|
@@ -56,22 +58,31 @@ export function FormBuilder<T extends z.ZodRawShape>({
|
|
56
58
|
defaultValues: defaultValues,
|
57
59
|
});
|
58
60
|
return (
|
59
|
-
<View className={cn("gap-
|
60
|
-
{
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
<View className={cn("gap-4", containerClassname)}>
|
62
|
+
<View className={cn("flex-1 gap-2", inputContainerClassname)}>
|
63
|
+
{keys.map((inputKey) => {
|
64
|
+
const Input = inputs[inputKey] || {
|
65
|
+
type: "text",
|
66
|
+
props: {
|
67
|
+
placeholder: inputKey,
|
68
|
+
},
|
69
|
+
};
|
70
|
+
const Render = Input.render;
|
71
|
+
if (!Render) {
|
72
|
+
return (
|
73
|
+
<InputComponent
|
74
|
+
control={form.control}
|
75
|
+
name={inputKey}
|
76
|
+
{...Input}
|
77
|
+
key={inputKey}
|
78
|
+
/>
|
79
|
+
);
|
80
|
+
}
|
64
81
|
return (
|
65
|
-
<
|
66
|
-
control={form.control}
|
67
|
-
name={inputKey}
|
68
|
-
{...Input}
|
69
|
-
key={inputKey}
|
70
|
-
/>
|
82
|
+
<Render control={form.control} name={inputKey} key={inputKey} />
|
71
83
|
);
|
72
|
-
}
|
73
|
-
|
74
|
-
})}
|
84
|
+
})}
|
85
|
+
</View>
|
75
86
|
<Button
|
76
87
|
className="w-full"
|
77
88
|
children={"Submit"}
|
@@ -110,27 +121,27 @@ const InputComponent = ({
|
|
110
121
|
|
111
122
|
type TextInputType = {
|
112
123
|
type: "text";
|
113
|
-
props
|
124
|
+
props?: InputProps;
|
114
125
|
};
|
115
126
|
type FloatingInputType = {
|
116
127
|
type: "floating";
|
117
|
-
props
|
128
|
+
props?: FloatingInputProps;
|
118
129
|
};
|
119
130
|
type SelectInputType = {
|
120
131
|
type: "select";
|
121
|
-
props
|
132
|
+
props?: SelectProps;
|
122
133
|
};
|
123
134
|
type MultiSelectInputType = {
|
124
135
|
type: "multi-select";
|
125
|
-
props
|
136
|
+
props?: MultiSelectProps;
|
126
137
|
};
|
127
138
|
type PinInputType = {
|
128
139
|
type: "pin";
|
129
|
-
props
|
140
|
+
props?: PinInputProps;
|
130
141
|
};
|
131
142
|
type PhoneInputType = {
|
132
143
|
type: "phone";
|
133
|
-
props
|
144
|
+
props?: TextInputProps;
|
134
145
|
};
|
135
146
|
type InputType =
|
136
147
|
| TextInputType
|
package/src/components/index.ts
CHANGED
@@ -133,18 +133,18 @@ const BaseInput = <T extends Record<string, any>>({
|
|
133
133
|
</Pressable>
|
134
134
|
)}
|
135
135
|
|
136
|
+
{isSecretToggleable && (
|
137
|
+
<ShowPassword
|
138
|
+
showPassword={showPassword}
|
139
|
+
setShowPassword={setShowPassword}
|
140
|
+
/>
|
141
|
+
)}
|
142
|
+
|
136
143
|
{rightElement}
|
137
144
|
</View>
|
138
145
|
{helperText && <Text className="text-muted text-sm">{helperText}</Text>}
|
139
146
|
|
140
147
|
{error && <Text className="text-danger text-sm">{error}</Text>}
|
141
|
-
|
142
|
-
{isSecretToggleable && (
|
143
|
-
<ShowPassword
|
144
|
-
showPassword={showPassword}
|
145
|
-
setShowPassword={setShowPassword}
|
146
|
-
/>
|
147
|
-
)}
|
148
148
|
</View>
|
149
149
|
);
|
150
150
|
};
|
@@ -11,7 +11,7 @@ export default function ShowPassword({
|
|
11
11
|
return (
|
12
12
|
<Pressable
|
13
13
|
onPress={() => setShowPassword(!showPassword)}
|
14
|
-
className="absolute right-
|
14
|
+
className="absolute right-0 bottom-0 items-center justify-center h-full p-2"
|
15
15
|
>
|
16
16
|
{showPassword ? (
|
17
17
|
<Eye size={20} color={useColor("foreground")} />
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { View } from "@nativetail/core";
|
2
|
+
import { FormBuilder, FormBuilderProps } from "../form-builder";
|
3
|
+
import { Stepper } from "../stepper";
|
4
|
+
import { z } from "zod";
|
5
|
+
type FormStep<
|
6
|
+
T extends string,
|
7
|
+
ISchema extends z.ZodRawShape,
|
8
|
+
> = FormBuilderProps<ISchema> & {
|
9
|
+
name: T;
|
10
|
+
};
|
11
|
+
|
12
|
+
type MultiStepFormProps<T extends string, ISchema extends z.ZodRawShape> = {
|
13
|
+
steps: FormStep<T, any>[];
|
14
|
+
activeStep: T;
|
15
|
+
};
|
16
|
+
export function MultiStepForm<T extends string, ISchema extends z.ZodRawShape>({
|
17
|
+
activeStep,
|
18
|
+
steps,
|
19
|
+
}: MultiStepFormProps<T, ISchema>) {
|
20
|
+
const currentStep = steps.find((step) => step.name === activeStep);
|
21
|
+
return (
|
22
|
+
<View className="flex-1">
|
23
|
+
<Stepper steps={steps.map((step) => step.name)} activeStep={activeStep} />
|
24
|
+
<FormBuilder containerClassname="mt-4 flex-1" {...currentStep} />
|
25
|
+
</View>
|
26
|
+
);
|
27
|
+
}
|
@@ -1,31 +1,45 @@
|
|
1
|
-
import
|
2
|
-
import { useCallback } from "react";
|
1
|
+
import CircularProgress from "react-native-circular-progress-indicator";
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
import { Text, useColor, View } from "@nativetail/core";
|
4
|
+
import { CircularProgressBaseProps } from "react-native-circular-progress-indicator/lib/typescript/types";
|
5
|
+
|
6
|
+
export type StepperProps<T extends string> = {
|
7
|
+
steps: T[];
|
8
|
+
activeStep: T;
|
9
|
+
progressProps?: CircularProgressBaseProps;
|
8
10
|
};
|
9
|
-
export
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
{
|
24
|
-
|
25
|
-
|
11
|
+
export function Stepper<T extends string>({
|
12
|
+
steps,
|
13
|
+
activeStep,
|
14
|
+
progressProps,
|
15
|
+
}: StepperProps<T>) {
|
16
|
+
const activeStepIndex = steps.findIndex((step) => step === activeStep);
|
17
|
+
const stepProgresss = ((activeStepIndex + 1) / steps.length) * 100;
|
18
|
+
const nextStep = steps[activeStepIndex + 1];
|
19
|
+
const nextStepData = nextStep ? nextStep : "Completed";
|
20
|
+
|
21
|
+
return (
|
22
|
+
<View className="flex-row items-center gap-2">
|
23
|
+
<View className="w-17 h-17 ">
|
24
|
+
<CircularProgress
|
25
|
+
value={stepProgresss}
|
26
|
+
activeStrokeWidth={8}
|
27
|
+
radius={33}
|
28
|
+
showProgressValue={false}
|
29
|
+
activeStrokeColor={useColor("primary")}
|
30
|
+
inActiveStrokeColor={useColor("primary/15")}
|
31
|
+
{...progressProps}
|
32
|
+
/>
|
33
|
+
<View className="absolute top-0 left-0 w-full h-full text-center flex items-center justify-center ">
|
34
|
+
<Text className="text-sm foreground ">
|
35
|
+
{activeStepIndex + 1} of {steps.length}
|
36
|
+
</Text>
|
26
37
|
</View>
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
38
|
+
</View>
|
39
|
+
<View className="gap-0.5">
|
40
|
+
<Text className="text-[16px] font-medium">{activeStep}</Text>
|
41
|
+
<Text className="text-sm text-muted">Next: {nextStepData}</Text>
|
42
|
+
</View>
|
43
|
+
</View>
|
44
|
+
);
|
45
|
+
}
|