vanjs-jsf 0.0.11 → 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 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.
@@ -18,7 +18,10 @@ export declare class VanJsfField extends VanJSComponent {
18
18
  get inputType(): string;
19
19
  get label(): string;
20
20
  get class(): string;
21
+ get errorClass(): string;
22
+ get codemirrorExtension(): Array<any>;
21
23
  get containerClass(): string;
24
+ get containerId(): string;
22
25
  get titleClass(): string;
23
26
  get descriptionClass(): string;
24
27
  get description(): string;
@@ -1,10 +1,17 @@
1
1
  import van from "vanjs-core";
2
2
  import { VanJSComponent } from "./VanJSComponent";
3
3
  import pikaday from "pikaday";
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";
4
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";
10
17
  FieldType["select"] = "select";
@@ -12,6 +19,21 @@ var FieldType;
12
19
  FieldType["date"] = "date";
13
20
  FieldType["fieldset"] = "fieldset";
14
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
+ };
15
37
  export class VanJsfField extends VanJSComponent {
16
38
  name;
17
39
  field;
@@ -38,9 +60,58 @@ export class VanJsfField extends VanJSComponent {
38
60
  get class() {
39
61
  return this.field.class;
40
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
+ }
41
109
  get containerClass() {
42
110
  return this.field.containerClass;
43
111
  }
112
+ get containerId() {
113
+ return this.field.containerId;
114
+ }
44
115
  get titleClass() {
45
116
  return this.field.titleClass;
46
117
  }
@@ -80,7 +151,7 @@ export class VanJsfField extends VanJSComponent {
80
151
  class: this.class ? this.class : '',
81
152
  value: this.iniVal,
82
153
  oninput: (e) => this.handleChange(this, e.target.value),
83
- }), p(() => this.error));
154
+ }), p({ class: this.errorClass }, () => this.error));
84
155
  break;
85
156
  case FieldType.textarea:
86
157
  el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
@@ -91,9 +162,17 @@ export class VanJsfField extends VanJSComponent {
91
162
  rows: this.field.rows,
92
163
  cols: this.field.columns,
93
164
  oninput: (e) => this.handleChange(this, e.target.value),
94
- }));
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
+ });
95
175
  break;
96
- //TODO: Add select component
97
176
  case FieldType.select:
98
177
  el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
99
178
  div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), select({
@@ -101,7 +180,7 @@ export class VanJsfField extends VanJSComponent {
101
180
  name: this.name,
102
181
  class: this.class ? this.class : null,
103
182
  oninput: (e) => this.handleChange(this, e.target.value),
104
- }, this.options?.map((opt) => option({ class: this.class ? this.class : null, value: opt.value }, opt.label, opt.description))));
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));
105
184
  break;
106
185
  case FieldType.date:
107
186
  const calendarInput = input({
@@ -113,10 +192,11 @@ export class VanJsfField extends VanJSComponent {
113
192
  });
114
193
  el =
115
194
  div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
116
- 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" }));
117
196
  new pikaday({
118
197
  field: calendarInput,
119
198
  format: 'YYYY/MM/DD',
199
+ container: el,
120
200
  firstDay: 1,
121
201
  toString(date) {
122
202
  // you should do formatting based on the passed format,
@@ -144,7 +224,7 @@ export class VanJsfField extends VanJSComponent {
144
224
  class: this.class ? this.class : null,
145
225
  value: this.iniVal,
146
226
  oninput: (e) => this.handleChange(this, e.target.value),
147
- }));
227
+ }), p({ class: this.errorClass }, () => this.error));
148
228
  break;
149
229
  case FieldType.fieldset:
150
230
  console.log(this.field);
@@ -159,7 +239,7 @@ export class VanJsfField extends VanJSComponent {
159
239
  value: opt.value,
160
240
  checked: this.iniVal === opt.value,
161
241
  onchange: (e) => this.handleChange(this, e.target.value),
162
- }), opt.label, opt.description))));
242
+ }), opt.label, opt.description), p({ class: this.errorClass }, () => this.error))));
163
243
  break;
164
244
  default:
165
245
  el = div({ style: "border: 1px dashed gray; padding: 8px;" }, `Field "${this.name}" unsupported: The type "${this.inputType}" has no UI component built yet.`);
@@ -18,7 +18,9 @@ class VanJsfForm {
18
18
  this.config = config;
19
19
  this.isValid = isValid || undefined;
20
20
  // Working with parameters
21
+ const initialValues = { ...config?.initialValues };
21
22
  this.headlessForm = createHeadlessForm(jsonSchema, config);
23
+ this.config.initialValues = initialValues;
22
24
  // Read documentation about `getFieldsAndValuedFromJsf` method below
23
25
  const { vanJsfFields, formValues } = this.getFieldsAndValuesFromJsf(this.headlessForm, this.config.initialValues);
24
26
  this.formFields = vanJsfFields;
@@ -52,24 +54,30 @@ class VanJsfForm {
52
54
  */
53
55
  getFieldsAndValuesFromJsf(headlessForm, initialValues) {
54
56
  const fields = headlessForm.fields;
55
- console.log(fields);
56
57
  const formValues = {};
58
+ const values = { ...initialValues };
59
+ console.log(values);
57
60
  const vanJsfFields = this.processFields(fields, initialValues, formValues);
58
61
  return { vanJsfFields, formValues };
59
62
  }
60
63
  handleFieldChange(field, value) {
61
- console.log(`Field ${field.name} changed to ${value}`);
64
+ console.log(value);
65
+ console.log(field.name);
62
66
  this.formValues[field.name] = value;
63
67
  const { formErrors } = this.headlessForm.handleValidation(this.formValues);
68
+ let extraError = false;
64
69
  console.log("formErrors", formErrors);
65
70
  this.formFields.forEach((f) => {
66
71
  f.isVisible = f.field.isVisible;
67
72
  f.error = formErrors?.[f.name] ?? "";
73
+ console.log(f.field.error);
74
+ if (f.field.error) {
75
+ extraError = true;
76
+ }
68
77
  });
69
78
  if (this.isValid) {
70
- if (formErrors) {
71
- if (this.isValid)
72
- this.isValid.val = false;
79
+ if (formErrors || extraError) {
80
+ this.isValid.val = false;
73
81
  }
74
82
  else {
75
83
  this.isValid.val = true;
@@ -84,8 +92,6 @@ class VanJsfForm {
84
92
  const initVal = initialValues[fieldPath] || field.default || "";
85
93
  // Store the initial value in the form values map
86
94
  formValues[fieldPath] = initVal;
87
- console.log(formValues);
88
- console.log(initialValues);
89
95
  // Check if the field has nested fields and process them recursively
90
96
  if (field.fields && field.fields.length > 0) {
91
97
  field.fields = this.processFields(field.fields, initialValues, formValues, fieldPath);