vanjs-jsf 0.0.10 → 0.0.12
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 +10 -0
- package/dist/VanJsfField.d.ts +5 -1
- package/dist/VanJsfField.js +97 -6
- package/dist/VanJsfForm.js +27 -6
- package/dist/index.js.map +4 -4
- package/dist/main.js +34 -8
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -15,6 +15,16 @@ This library aims to provide a robust and flexible solution for dynamically gene
|
|
|
15
15
|
- [ ] **Validation Support**: Easily integrate JSON Schema-based validation for seamless user input handling.
|
|
16
16
|
- [ ] **Extensible Architecture**: Add custom widgets, field types, and behaviours as needed.
|
|
17
17
|
|
|
18
|
+
### Available components
|
|
19
|
+
The currently supported form element types are:
|
|
20
|
+
- text = "text",
|
|
21
|
+
- number = "number",
|
|
22
|
+
- textarea = "textarea",
|
|
23
|
+
- select = "select",
|
|
24
|
+
- radio = "radio",
|
|
25
|
+
- date = "date",
|
|
26
|
+
- fieldset = "fieldset"
|
|
27
|
+
|
|
18
28
|
### Use Cases
|
|
19
29
|
|
|
20
30
|
- Quickly generate forms for dashboards, admin panels, and dynamic web applications.
|
package/dist/VanJsfField.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { VanJSComponent } from "./VanJSComponent";
|
|
|
3
3
|
export interface Option {
|
|
4
4
|
label: string;
|
|
5
5
|
value: string;
|
|
6
|
-
description
|
|
6
|
+
description?: string;
|
|
7
|
+
img?: string;
|
|
7
8
|
}
|
|
8
9
|
export type MultiType = string | number | boolean;
|
|
9
10
|
export declare class VanJsfField extends VanJSComponent {
|
|
@@ -17,7 +18,10 @@ export declare class VanJsfField extends VanJSComponent {
|
|
|
17
18
|
get inputType(): string;
|
|
18
19
|
get label(): string;
|
|
19
20
|
get class(): string;
|
|
21
|
+
get errorClass(): string;
|
|
22
|
+
get codemirrorExtension(): Array<any>;
|
|
20
23
|
get containerClass(): string;
|
|
24
|
+
get containerId(): string;
|
|
21
25
|
get titleClass(): string;
|
|
22
26
|
get descriptionClass(): string;
|
|
23
27
|
get description(): string;
|
package/dist/VanJsfField.js
CHANGED
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
import van from "vanjs-core";
|
|
2
2
|
import { VanJSComponent } from "./VanJSComponent";
|
|
3
3
|
import pikaday from "pikaday";
|
|
4
|
-
|
|
4
|
+
import { basicSetup, EditorView } from "codemirror";
|
|
5
|
+
import { javascript, esLint } from "@codemirror/lang-javascript";
|
|
6
|
+
import { json, jsonParseLinter } from "@codemirror/lang-json";
|
|
7
|
+
import { lintGutter, linter, forEachDiagnostic } from "@codemirror/lint";
|
|
8
|
+
import * as eslint from "eslint-linter-browserify";
|
|
9
|
+
import globals from "globals";
|
|
10
|
+
const { div, p, input, label, textarea, legend, link, fieldset, span, select, option } = van.tags;
|
|
5
11
|
var FieldType;
|
|
6
12
|
(function (FieldType) {
|
|
7
13
|
FieldType["text"] = "text";
|
|
14
|
+
FieldType["code"] = "code";
|
|
8
15
|
FieldType["number"] = "number";
|
|
9
16
|
FieldType["textarea"] = "textarea";
|
|
17
|
+
FieldType["select"] = "select";
|
|
10
18
|
FieldType["radio"] = "radio";
|
|
11
19
|
FieldType["date"] = "date";
|
|
12
20
|
FieldType["fieldset"] = "fieldset";
|
|
13
21
|
})(FieldType || (FieldType = {}));
|
|
22
|
+
const eslintConfig = {
|
|
23
|
+
// eslint configuration
|
|
24
|
+
languageOptions: {
|
|
25
|
+
globals: {
|
|
26
|
+
...globals.node,
|
|
27
|
+
},
|
|
28
|
+
parserOptions: {
|
|
29
|
+
ecmaVersion: 2022,
|
|
30
|
+
sourceType: "module",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
rules: {
|
|
34
|
+
semi: ["error", "never"],
|
|
35
|
+
},
|
|
36
|
+
};
|
|
14
37
|
export class VanJsfField extends VanJSComponent {
|
|
15
38
|
name;
|
|
16
39
|
field;
|
|
@@ -37,9 +60,58 @@ export class VanJsfField extends VanJSComponent {
|
|
|
37
60
|
get class() {
|
|
38
61
|
return this.field.class;
|
|
39
62
|
}
|
|
63
|
+
get errorClass() {
|
|
64
|
+
return this.field.errorClass;
|
|
65
|
+
}
|
|
66
|
+
get codemirrorExtension() {
|
|
67
|
+
const theme = EditorView.theme({
|
|
68
|
+
'.cm-content, .cm-gutter': {
|
|
69
|
+
"min-height": "150px",
|
|
70
|
+
},
|
|
71
|
+
'.cm-content': {
|
|
72
|
+
"min-height": "150px",
|
|
73
|
+
},
|
|
74
|
+
'.cm-gutters': {
|
|
75
|
+
margin: '1px',
|
|
76
|
+
},
|
|
77
|
+
'.cm-scroller': {
|
|
78
|
+
overflow: 'auto',
|
|
79
|
+
},
|
|
80
|
+
'.cm-wrap': {
|
|
81
|
+
border: '1px solid silver',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
const extensions = [theme, EditorView.updateListener.of((e) => {
|
|
85
|
+
this.field.error = null;
|
|
86
|
+
forEachDiagnostic(e.state, (diag) => {
|
|
87
|
+
if (diag.severity === "error") {
|
|
88
|
+
this.field.error = diag.message;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
this.handleChange(this, e.state.doc.toString());
|
|
92
|
+
}), basicSetup, lintGutter()];
|
|
93
|
+
switch (this.field.codemirrorType) {
|
|
94
|
+
case "json":
|
|
95
|
+
extensions.push(json(), linter(jsonParseLinter()));
|
|
96
|
+
break;
|
|
97
|
+
case "javascript":
|
|
98
|
+
extensions.push(javascript(), linter(esLint(new eslint.Linter(), eslintConfig)));
|
|
99
|
+
break;
|
|
100
|
+
case "typescript":
|
|
101
|
+
extensions.push(javascript({ typescript: true }), linter(esLint(new eslint.Linter(), eslintConfig)));
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
extensions.push(javascript(), linter(esLint(new eslint.Linter(), eslintConfig)));
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
return extensions;
|
|
108
|
+
}
|
|
40
109
|
get containerClass() {
|
|
41
110
|
return this.field.containerClass;
|
|
42
111
|
}
|
|
112
|
+
get containerId() {
|
|
113
|
+
return this.field.containerId;
|
|
114
|
+
}
|
|
43
115
|
get titleClass() {
|
|
44
116
|
return this.field.titleClass;
|
|
45
117
|
}
|
|
@@ -79,7 +151,7 @@ export class VanJsfField extends VanJSComponent {
|
|
|
79
151
|
class: this.class ? this.class : '',
|
|
80
152
|
value: this.iniVal,
|
|
81
153
|
oninput: (e) => this.handleChange(this, e.target.value),
|
|
82
|
-
}), p(() => this.error));
|
|
154
|
+
}), p({ class: this.errorClass }, () => this.error));
|
|
83
155
|
break;
|
|
84
156
|
case FieldType.textarea:
|
|
85
157
|
el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
|
|
@@ -90,7 +162,25 @@ export class VanJsfField extends VanJSComponent {
|
|
|
90
162
|
rows: this.field.rows,
|
|
91
163
|
cols: this.field.columns,
|
|
92
164
|
oninput: (e) => this.handleChange(this, e.target.value),
|
|
93
|
-
}));
|
|
165
|
+
}), p({ class: this.errorClass }, () => this.error));
|
|
166
|
+
break;
|
|
167
|
+
case FieldType.code:
|
|
168
|
+
el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
|
|
169
|
+
div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description));
|
|
170
|
+
new EditorView({
|
|
171
|
+
doc: new String(this.iniVal).toString(),
|
|
172
|
+
parent: el,
|
|
173
|
+
extensions: this.codemirrorExtension
|
|
174
|
+
});
|
|
175
|
+
break;
|
|
176
|
+
case FieldType.select:
|
|
177
|
+
el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
|
|
178
|
+
div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), select({
|
|
179
|
+
id: this.name,
|
|
180
|
+
name: this.name,
|
|
181
|
+
class: this.class ? this.class : null,
|
|
182
|
+
oninput: (e) => this.handleChange(this, e.target.value),
|
|
183
|
+
}, this.options?.map((opt) => option({ class: this.class ? this.class : null, value: opt.value }, opt.label, opt.description))), p({ class: this.errorClass }, () => this.error));
|
|
94
184
|
break;
|
|
95
185
|
case FieldType.date:
|
|
96
186
|
const calendarInput = input({
|
|
@@ -102,10 +192,11 @@ export class VanJsfField extends VanJSComponent {
|
|
|
102
192
|
});
|
|
103
193
|
el =
|
|
104
194
|
div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
|
|
105
|
-
div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), calendarInput, link({ rel: "stylesheet", type: "text/css", href: "https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css" }));
|
|
195
|
+
div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), calendarInput, p({ class: this.errorClass }, () => this.error), link({ rel: "stylesheet", type: "text/css", href: "https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css" }));
|
|
106
196
|
new pikaday({
|
|
107
197
|
field: calendarInput,
|
|
108
198
|
format: 'YYYY/MM/DD',
|
|
199
|
+
container: el,
|
|
109
200
|
firstDay: 1,
|
|
110
201
|
toString(date) {
|
|
111
202
|
// you should do formatting based on the passed format,
|
|
@@ -133,7 +224,7 @@ export class VanJsfField extends VanJSComponent {
|
|
|
133
224
|
class: this.class ? this.class : null,
|
|
134
225
|
value: this.iniVal,
|
|
135
226
|
oninput: (e) => this.handleChange(this, e.target.value),
|
|
136
|
-
}));
|
|
227
|
+
}), p({ class: this.errorClass }, () => this.error));
|
|
137
228
|
break;
|
|
138
229
|
case FieldType.fieldset:
|
|
139
230
|
console.log(this.field);
|
|
@@ -148,7 +239,7 @@ export class VanJsfField extends VanJSComponent {
|
|
|
148
239
|
value: opt.value,
|
|
149
240
|
checked: this.iniVal === opt.value,
|
|
150
241
|
onchange: (e) => this.handleChange(this, e.target.value),
|
|
151
|
-
}), opt.label, opt.description))));
|
|
242
|
+
}), opt.label, opt.description), p({ class: this.errorClass }, () => this.error))));
|
|
152
243
|
break;
|
|
153
244
|
default:
|
|
154
245
|
el = div({ style: "border: 1px dashed gray; padding: 8px;" }, `Field "${this.name}" unsupported: The type "${this.inputType}" has no UI component built yet.`);
|
package/dist/VanJsfForm.js
CHANGED
|
@@ -5,18 +5,22 @@ const { form } = van.tags;
|
|
|
5
5
|
class VanJsfForm {
|
|
6
6
|
schema;
|
|
7
7
|
config;
|
|
8
|
+
isValid;
|
|
8
9
|
headlessForm;
|
|
9
10
|
formFields;
|
|
10
11
|
formValues;
|
|
11
|
-
constructor(jsonSchema, config) {
|
|
12
|
+
constructor(jsonSchema, config, isValid) {
|
|
12
13
|
// Bind methods to instance. Needed to pass functions as props to child components
|
|
13
14
|
//this.handleSubmit = this.handleSubmit.bind(this);
|
|
14
15
|
this.handleFieldChange = this.handleFieldChange.bind(this);
|
|
15
16
|
// Receive parameters
|
|
16
17
|
this.schema = jsonSchema;
|
|
17
18
|
this.config = config;
|
|
19
|
+
this.isValid = isValid || undefined;
|
|
18
20
|
// Working with parameters
|
|
21
|
+
const initialValues = { ...config?.initialValues };
|
|
19
22
|
this.headlessForm = createHeadlessForm(jsonSchema, config);
|
|
23
|
+
this.config.initialValues = initialValues;
|
|
20
24
|
// Read documentation about `getFieldsAndValuedFromJsf` method below
|
|
21
25
|
const { vanJsfFields, formValues } = this.getFieldsAndValuesFromJsf(this.headlessForm, this.config.initialValues);
|
|
22
26
|
this.formFields = vanJsfFields;
|
|
@@ -50,20 +54,35 @@ class VanJsfForm {
|
|
|
50
54
|
*/
|
|
51
55
|
getFieldsAndValuesFromJsf(headlessForm, initialValues) {
|
|
52
56
|
const fields = headlessForm.fields;
|
|
53
|
-
console.log(fields);
|
|
54
57
|
const formValues = {};
|
|
58
|
+
const values = { ...initialValues };
|
|
59
|
+
console.log(values);
|
|
55
60
|
const vanJsfFields = this.processFields(fields, initialValues, formValues);
|
|
56
61
|
return { vanJsfFields, formValues };
|
|
57
62
|
}
|
|
58
63
|
handleFieldChange(field, value) {
|
|
59
|
-
console.log(
|
|
64
|
+
console.log(value);
|
|
65
|
+
console.log(field.name);
|
|
60
66
|
this.formValues[field.name] = value;
|
|
61
67
|
const { formErrors } = this.headlessForm.handleValidation(this.formValues);
|
|
68
|
+
let extraError = false;
|
|
62
69
|
console.log("formErrors", formErrors);
|
|
63
70
|
this.formFields.forEach((f) => {
|
|
64
71
|
f.isVisible = f.field.isVisible;
|
|
65
72
|
f.error = formErrors?.[f.name] ?? "";
|
|
73
|
+
console.log(f.field.error);
|
|
74
|
+
if (f.field.error) {
|
|
75
|
+
extraError = true;
|
|
76
|
+
}
|
|
66
77
|
});
|
|
78
|
+
if (this.isValid) {
|
|
79
|
+
if (formErrors || extraError) {
|
|
80
|
+
this.isValid.val = false;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.isValid.val = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
67
86
|
}
|
|
68
87
|
processFields(fields, initialValues, formValues, parentPath = "") {
|
|
69
88
|
return fields.map((field) => {
|
|
@@ -73,8 +92,6 @@ class VanJsfForm {
|
|
|
73
92
|
const initVal = initialValues[fieldPath] || field.default || "";
|
|
74
93
|
// Store the initial value in the form values map
|
|
75
94
|
formValues[fieldPath] = initVal;
|
|
76
|
-
console.log(formValues);
|
|
77
|
-
console.log(initialValues);
|
|
78
95
|
// Check if the field has nested fields and process them recursively
|
|
79
96
|
if (field.fields && field.fields.length > 0) {
|
|
80
97
|
field.fields = this.processFields(field.fields, initialValues, formValues, fieldPath);
|
|
@@ -89,6 +106,7 @@ export function jsform(attributes, ...children) {
|
|
|
89
106
|
throw new Error("JSON Schema is required");
|
|
90
107
|
}
|
|
91
108
|
let config = attributes.config;
|
|
109
|
+
let isValid = attributes.isValid;
|
|
92
110
|
if (!config) {
|
|
93
111
|
config = { initialValues: {}, formValues: {} };
|
|
94
112
|
}
|
|
@@ -98,7 +116,7 @@ export function jsform(attributes, ...children) {
|
|
|
98
116
|
else if (!config.formValues) {
|
|
99
117
|
config.formValues = {};
|
|
100
118
|
}
|
|
101
|
-
const vanJsfForm = new VanJsfForm(attributes.schema, config);
|
|
119
|
+
const vanJsfForm = new VanJsfForm(attributes.schema, config, isValid);
|
|
102
120
|
console.log(vanJsfForm);
|
|
103
121
|
const fields = vanJsfForm.formFields.map((field) => field.render());
|
|
104
122
|
const childrenWithFields = [...fields, ...children]; // Concatenate fields with other children
|
|
@@ -108,8 +126,11 @@ export function jsform(attributes, ...children) {
|
|
|
108
126
|
config.formValues = vanJsfForm.formValues;
|
|
109
127
|
originalOnSubmit && originalOnSubmit(e);
|
|
110
128
|
};
|
|
129
|
+
const originalOnChange = attributes.onchange;
|
|
111
130
|
const handleChange = (e) => {
|
|
131
|
+
e.preventDefault();
|
|
112
132
|
config.formValues = vanJsfForm.formValues;
|
|
133
|
+
originalOnChange && originalOnChange(vanJsfForm, e);
|
|
113
134
|
};
|
|
114
135
|
attributes.onsubmit = handleSubmit;
|
|
115
136
|
attributes.onchange = handleChange;
|