@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativetail/ui",
3
- "version": "0.1.3",
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-2", containerClassname)}>
60
- {keys.map((inputKey) => {
61
- const Input = inputs[inputKey];
62
- const Render = Input.render;
63
- if (!Render) {
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
- <InputComponent
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
- return <Render control={form.control} name={inputKey} key={inputKey} />;
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: InputProps;
124
+ props?: InputProps;
114
125
  };
115
126
  type FloatingInputType = {
116
127
  type: "floating";
117
- props: FloatingInputProps;
128
+ props?: FloatingInputProps;
118
129
  };
119
130
  type SelectInputType = {
120
131
  type: "select";
121
- props: SelectProps;
132
+ props?: SelectProps;
122
133
  };
123
134
  type MultiSelectInputType = {
124
135
  type: "multi-select";
125
- props: MultiSelectProps;
136
+ props?: MultiSelectProps;
126
137
  };
127
138
  type PinInputType = {
128
139
  type: "pin";
129
- props: PinInputProps;
140
+ props?: PinInputProps;
130
141
  };
131
142
  type PhoneInputType = {
132
143
  type: "phone";
133
- props: TextInputProps;
144
+ props?: TextInputProps;
134
145
  };
135
146
  type InputType =
136
147
  | TextInputType
@@ -18,3 +18,5 @@ export * from "./check";
18
18
  export * from "./card";
19
19
  export * from "./indicator";
20
20
  export * from "./loader-dialog";
21
+ export * from "./stepper";
22
+ export * from "./multi-step-form";
@@ -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-2 bottom-2"
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 { cn, View } from "@nativetail/core";
2
- import { useCallback } from "react";
1
+ import CircularProgress from "react-native-circular-progress-indicator";
3
2
 
4
- export type StepperProps = {
5
- steps: string[];
6
- activeStepIndex: number;
7
- setActiveStepIndex?: (index: number) => void;
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 const Stepper = (props: StepperProps) => {
10
- const renderSteps = useCallback(() => {
11
- return props.steps.map((step, index) => {
12
- const isActive = index === props.activeStepIndex;
13
- const isCompleted = index < props.activeStepIndex;
14
- return (
15
- <View key={index} className="flex-row items-center">
16
- <View
17
- className={cn("w-4 h-4 rounded-full", {
18
- "bg-primary": isActive,
19
- "bg-gray-300": !isActive && !isCompleted,
20
- "bg-success": isCompleted,
21
- })}
22
- />
23
- {index < props.steps.length - 1 && (
24
- <View className="h-0.5 bg-gray-300 w-4" />
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
- }, [props.steps, props.activeStepIndex]);
30
- return <View className="flex-row items-center">{renderSteps()}</View>;
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
+ }