@nvs-dynamic-form/react-core 1.2.3 → 1.2.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/lib/index.tsx ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./nvsDynamicForm";
2
+ export * from "./types";
@@ -0,0 +1,93 @@
1
+ import { INvsDynamicForm, NvsDynamicForm } from "./";
2
+ import * as Yup from "yup";
3
+
4
+ import { Field } from "formik";
5
+ import React from "react";
6
+ import { FieldBase } from "../types";
7
+
8
+ export default {
9
+ component: NvsDynamicForm,
10
+ title: "Nvs Dynamic Form",
11
+ };
12
+
13
+ const ButtonComponent = ({ children }: { children: string }) => {
14
+ return (
15
+ <button style={{ width: "100%" }} type="submit">
16
+ {children}
17
+ </button>
18
+ );
19
+ };
20
+
21
+ const TextboxElement = (opt: TextboxField) => {
22
+ return (
23
+ <Field
24
+ style={{ width: "100%", boxSizing: "border-box" }}
25
+ id={opt.id}
26
+ name={opt.id}
27
+ placeholder={opt.label}
28
+ />
29
+ );
30
+ };
31
+
32
+ class TextboxField extends FieldBase<string> {
33
+ override readonly fieldType? = "textbox";
34
+ type?: "email" | "number" | "password" | "tel" | "text" | "url";
35
+ placeholder?: string;
36
+
37
+ constructor(options: TextboxField) {
38
+ super(options, "");
39
+ this.type = options.type ?? "text";
40
+ this.placeholder = options.placeholder ?? "";
41
+ }
42
+ }
43
+
44
+ export const Default: { args: INvsDynamicForm } = {
45
+ args: {
46
+ onSubmit: (values) => {
47
+ alert(JSON.stringify(values));
48
+ },
49
+ submitButtonIsFullWidth: false,
50
+ submitButtonLabel: "Save",
51
+ submitButtonVisible: true,
52
+ submitButtonPosition: "right",
53
+ submitButton: {
54
+ component: ButtonComponent,
55
+ defaultOptions: {
56
+ label: "Save",
57
+ isFullWidth: true,
58
+ position: "right",
59
+ },
60
+ },
61
+ formElements: {
62
+ textbox: {
63
+ component: TextboxElement,
64
+ class: TextboxField,
65
+ },
66
+ },
67
+ fields: [
68
+ new TextboxField({
69
+ id: "firstName",
70
+ label: "First Name",
71
+ defaultValue: "ismet",
72
+ screenSize: {
73
+ desktop: 6,
74
+ },
75
+ validate: Yup.string().required(),
76
+ }),
77
+ new TextboxField({
78
+ id: "lastName",
79
+ label: "Last Name",
80
+ screenSize: {
81
+ desktop: 6,
82
+ },
83
+ validate: Yup.string().required(),
84
+ }),
85
+ new TextboxField({
86
+ id: "emailAddress",
87
+ label: "E-mail Address",
88
+ screenSize: 12,
89
+ type: "email",
90
+ }),
91
+ ],
92
+ },
93
+ };
@@ -0,0 +1,5 @@
1
+ .df-button {
2
+ display: inline-flex;
3
+ margin-top: 8px;
4
+ padding: 0 4px;
5
+ }
@@ -0,0 +1,143 @@
1
+ import "nvs-flexgrid";
2
+ import "./_style.css";
3
+
4
+ import * as Yup from "yup";
5
+
6
+ import {
7
+ DynamicObject,
8
+ FieldBase,
9
+ IScreenSize,
10
+ ScreenSizeType,
11
+ } from "../types";
12
+ import { Form, Formik, FormikErrors, FormikTouched } from "formik";
13
+ import React, { useEffect, useState } from "react";
14
+
15
+ import { INvsDynamicForm } from "./_type";
16
+
17
+ export const NvsDynamicForm = ({
18
+ onSubmit,
19
+ formElements = {},
20
+ fields = [],
21
+ formClass,
22
+ submitButton,
23
+ submitButtonVisible = true,
24
+ submitButtonLabel = submitButton.defaultOptions.label,
25
+ submitButtonIsFullWidth = submitButton.defaultOptions.isFullWidth,
26
+ submitButtonPosition = submitButton.defaultOptions.position,
27
+ }: INvsDynamicForm) => {
28
+ const getDefaultValues = (): DynamicObject => {
29
+ return fields.reduce((acc: DynamicObject, field: FieldBase<any>) => {
30
+ acc[field.id] = field.defaultValue;
31
+ return acc;
32
+ }, {});
33
+ };
34
+
35
+ const getValidateSchema = () => {
36
+ const validationSchema = fields.reduce(
37
+ (acc: { [key: string]: Yup.AnySchema }, field) => {
38
+ if (field?.validate) {
39
+ acc[field.id] = field.validate;
40
+ }
41
+ return acc;
42
+ },
43
+ {},
44
+ );
45
+ return Yup.object(validationSchema);
46
+ };
47
+
48
+ const [defaultValues, setDefaultValues] = useState(getDefaultValues());
49
+ const [validateSchema, setValidateSchema] = useState(getValidateSchema());
50
+
51
+ useEffect(() => {
52
+ setDefaultValues(getDefaultValues());
53
+ setValidateSchema(getValidateSchema());
54
+ }, [fields]);
55
+
56
+ const createFieldItemClass = (
57
+ screenSize: ScreenSizeType | IScreenSize,
58
+ ): Array<string> => {
59
+ const className: Array<string> = [];
60
+ if (typeof screenSize == "number") className.push("nvs-col-" + screenSize);
61
+ else {
62
+ className.push("nvs-col-md-" + screenSize?.desktop);
63
+ if (screenSize?.tablet) className.push("nvs-col-sm-" + screenSize.tablet);
64
+ if (screenSize?.mobile) className.push("nvs-col-xs-" + screenSize.mobile);
65
+ }
66
+ return className;
67
+ };
68
+
69
+ const createFormElement = (field: FieldBase<any>) => {
70
+ const Field = formElements[field.fieldType!]?.component;
71
+ return Field ? <Field {...field} /> : <></>;
72
+ };
73
+
74
+ const createFormElements = (
75
+ errors: FormikErrors<DynamicObject>,
76
+ touched: FormikTouched<DynamicObject>,
77
+ ) => {
78
+ return fields.map((field: FieldBase<any>) => (
79
+ <div
80
+ key={field.id}
81
+ className={createFieldItemClass(field.screenSize ?? 12).join(" ")}
82
+ >
83
+ {createFormElement({
84
+ ...field,
85
+ error: errors[field.id],
86
+ touched: touched[field.id],
87
+ })}
88
+ </div>
89
+ ));
90
+ };
91
+
92
+ const getSubmitButtonComponent = () => {
93
+ const SubmitButton = submitButton.component;
94
+ return <SubmitButton>{submitButtonLabel}</SubmitButton>;
95
+ };
96
+
97
+ const getButtonPositionClass = (position: "left" | "right" | "center") => {
98
+ const classes = {
99
+ left: "nvs-jc-start",
100
+ right: "nvs-jc-end",
101
+ center: "nvs-jc-center",
102
+ };
103
+ return classes[position];
104
+ };
105
+
106
+ const createSubmitButton = () => {
107
+ const buttonClasses = ["df-button"];
108
+
109
+ submitButtonIsFullWidth && buttonClasses.push("nvs-col-12");
110
+
111
+ return (
112
+ <div
113
+ className={`nvs-row ${getButtonPositionClass(submitButtonPosition)}`}
114
+ >
115
+ <div className={buttonClasses.join(" ")}>
116
+ {getSubmitButtonComponent()}
117
+ </div>
118
+ </div>
119
+ );
120
+ };
121
+
122
+ const createForm = (
123
+ errors: FormikErrors<DynamicObject>,
124
+ touched: FormikTouched<DynamicObject>,
125
+ ) => (
126
+ <Form className={`nvs-container-fluid${formClass ? ` ${formClass}` : ""}`}>
127
+ <div className="nvs-row">{createFormElements(errors, touched)}</div>
128
+ {submitButtonVisible && createSubmitButton()}
129
+ </Form>
130
+ );
131
+
132
+ return (
133
+ <Formik
134
+ initialValues={defaultValues}
135
+ validationSchema={validateSchema}
136
+ onSubmit={async (values) => {
137
+ onSubmit && (await onSubmit(values));
138
+ }}
139
+ >
140
+ {({ errors, touched }) => createForm(errors, touched)}
141
+ </Formik>
142
+ );
143
+ };
@@ -0,0 +1,21 @@
1
+ import { FieldBase, SubmitButtonOptions } from "../types";
2
+
3
+ export interface INvsDynamicForm {
4
+ onSubmit?: ((values: unknown) => void) | ((values: unknown) => Promise<void>);
5
+ submitButton: {
6
+ component: React.FC<any>;
7
+ defaultOptions: SubmitButtonOptions;
8
+ };
9
+ formElements: {
10
+ [key: string]: {
11
+ component: React.FC<any>;
12
+ class: typeof FieldBase<any>;
13
+ };
14
+ };
15
+ fields: Array<FieldBase<unknown>>;
16
+ formClass?: string;
17
+ submitButtonVisible?: boolean;
18
+ submitButtonLabel?: string;
19
+ submitButtonPosition?: "left" | "center" | "right";
20
+ submitButtonIsFullWidth?: boolean;
21
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./_template";
2
+ export * from "./_type";
@@ -0,0 +1,3 @@
1
+ export class DynamicObject {
2
+ [key: string]: number | string | boolean | null;
3
+ }
@@ -0,0 +1,23 @@
1
+ import * as Yup from "yup";
2
+
3
+ import { IScreenSize, ScreenSizeType } from "./screen-size.type";
4
+
5
+ export abstract class FieldBase<ValueType> {
6
+ id!: string;
7
+ label!: string;
8
+ fieldType?: string;
9
+ defaultValue?: ValueType;
10
+ screenSize?: ScreenSizeType | IScreenSize;
11
+ validate?: Yup.AnySchema;
12
+ error?: string;
13
+ touched?: boolean;
14
+
15
+ constructor(options: FieldBase<ValueType>, fieldDefaultValue?: ValueType) {
16
+ this.defaultValue = options.defaultValue ?? fieldDefaultValue;
17
+ this.id = options.id;
18
+ this.label = options.label;
19
+ this.fieldType = options.fieldType;
20
+ this.screenSize = options.screenSize ?? 12;
21
+ this.validate = options.validate;
22
+ }
23
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./form-field.type";
2
+ export * from "./screen-size.type";
3
+ export * from "./dynamic-object.type";
4
+ export * from "./submit-button-options.type";
@@ -0,0 +1,7 @@
1
+ export type ScreenSizeType = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
2
+
3
+ export interface IScreenSize {
4
+ desktop: ScreenSizeType;
5
+ mobile?: ScreenSizeType;
6
+ tablet?: ScreenSizeType;
7
+ }
@@ -0,0 +1,5 @@
1
+ export class SubmitButtonOptions {
2
+ label!: string;
3
+ isFullWidth!: boolean;
4
+ position!: "left" | "right" | "center";
5
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@nvs-dynamic-form/react-core",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "types": "dist/cjs/index.d.ts",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
7
7
  "files": [
8
8
  "dist",
9
+ "lib",
9
10
  "packages.json"
10
11
  ],
11
12
  "scripts": {