vanjs-jsf 0.0.7 → 0.0.10

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.
@@ -1,12 +1,15 @@
1
1
  import van from "vanjs-core";
2
2
  import { VanJSComponent } from "./VanJSComponent";
3
- const { div, p, input, label, textarea, legend } = van.tags;
3
+ import pikaday from "pikaday";
4
+ const { div, p, input, label, textarea, legend, link, fieldset, span } = van.tags;
4
5
  var FieldType;
5
6
  (function (FieldType) {
6
7
  FieldType["text"] = "text";
7
8
  FieldType["number"] = "number";
8
9
  FieldType["textarea"] = "textarea";
9
10
  FieldType["radio"] = "radio";
11
+ FieldType["date"] = "date";
12
+ FieldType["fieldset"] = "fieldset";
10
13
  })(FieldType || (FieldType = {}));
11
14
  export class VanJsfField extends VanJSComponent {
12
15
  name;
@@ -31,6 +34,18 @@ export class VanJsfField extends VanJSComponent {
31
34
  get label() {
32
35
  return this.field.label;
33
36
  }
37
+ get class() {
38
+ return this.field.class;
39
+ }
40
+ get containerClass() {
41
+ return this.field.containerClass;
42
+ }
43
+ get titleClass() {
44
+ return this.field.titleClass;
45
+ }
46
+ get descriptionClass() {
47
+ return this.field.descriptionClass;
48
+ }
34
49
  get description() {
35
50
  return this.field.description;
36
51
  }
@@ -53,40 +68,83 @@ export class VanJsfField extends VanJSComponent {
53
68
  let el;
54
69
  const props = {
55
70
  style: () => (this.isVisible ? "display: block" : "display: none"),
71
+ class: this.containerClass ? this.containerClass : ''
56
72
  };
57
73
  switch (this.inputType) {
58
74
  case FieldType.text:
59
- el = div(props, label({ for: this.name }, this.label), this.description &&
60
- div({ id: `${this.name}-description` }, this.description), input({
75
+ el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
76
+ div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), input({
61
77
  id: this.name,
62
78
  type: "text",
79
+ class: this.class ? this.class : '',
63
80
  value: this.iniVal,
64
81
  oninput: (e) => this.handleChange(this, e.target.value),
65
82
  }), p(() => this.error));
66
83
  break;
67
84
  case FieldType.textarea:
68
- el = div(props, label({ for: this.name }, this.label), this.description &&
69
- div({ id: `${this.name}-description` }, this.description), textarea({
85
+ el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
86
+ div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), textarea({
70
87
  id: this.name,
71
88
  name: this.name,
89
+ class: this.class ? this.class : null,
72
90
  rows: this.field.rows,
73
91
  cols: this.field.columns,
74
92
  oninput: (e) => this.handleChange(this, e.target.value),
75
93
  }));
76
94
  break;
95
+ case FieldType.date:
96
+ const calendarInput = input({
97
+ id: this.name,
98
+ type: "text",
99
+ class: this.class ? this.class : null,
100
+ value: this.iniVal,
101
+ onchange: (e) => this.handleChange(this, e.target.value),
102
+ });
103
+ el =
104
+ 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" }));
106
+ new pikaday({
107
+ field: calendarInput,
108
+ format: 'YYYY/MM/DD',
109
+ firstDay: 1,
110
+ toString(date) {
111
+ // you should do formatting based on the passed format,
112
+ // but we will just return 'D/M/YYYY' for simplicity
113
+ const day = date.getDate();
114
+ const month = date.getMonth() + 1;
115
+ const year = date.getFullYear();
116
+ return `${year}-${("0" + month).slice(-2)}-${("0" + day).slice(-2)}`;
117
+ },
118
+ parse(dateString, format) {
119
+ // dateString is the result of `toString` method
120
+ const parts = dateString.split('/');
121
+ const day = parseInt(parts[0], 10);
122
+ const month = parseInt(parts[1], 10) - 1;
123
+ const year = parseInt(parts[2], 10);
124
+ return new Date(year, month, day);
125
+ }
126
+ });
127
+ break;
77
128
  case FieldType.number:
78
- el = div(props, label({ for: this.name }, this.label), this.description &&
79
- div({ id: `${this.name}-description` }, this.description), input({
129
+ el = div(props, label({ for: this.name, style: "margin-right: 5px;", class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
130
+ div({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), input({
80
131
  id: this.name,
81
132
  type: "number",
133
+ class: this.class ? this.class : null,
82
134
  value: this.iniVal,
83
135
  oninput: (e) => this.handleChange(this, e.target.value),
84
136
  }));
85
137
  break;
138
+ case FieldType.fieldset:
139
+ console.log(this.field);
140
+ el = div(props, fieldset(legend({ class: this.titleClass ? this.titleClass : '' }, this.label), this.description &&
141
+ span({ id: `${this.name}-description`, class: this.descriptionClass ? this.descriptionClass : '' }, this.description), this.isVanJsfFieldArray(this.field.fields) ? this.field.fields.map((field) => field.render()) : null));
142
+ break;
86
143
  case FieldType.radio:
87
- el = div(legend(this.label), this.description && div(this.description), div(this.options?.map((opt) => label(input({
144
+ el = div(legend({ class: this.titleClass ? this.titleClass : '' }, this.label), this.description && div(this.description), div(this.options?.map((opt) => label(input({
88
145
  type: "radio",
89
146
  name: this.name,
147
+ class: this.class ? this.class : null,
90
148
  value: opt.value,
91
149
  checked: this.iniVal === opt.value,
92
150
  onchange: (e) => this.handleChange(this, e.target.value),
@@ -97,4 +155,7 @@ export class VanJsfField extends VanJSComponent {
97
155
  }
98
156
  return el;
99
157
  }
158
+ isVanJsfFieldArray(fields) {
159
+ return Array.isArray(fields) && fields.every(field => field instanceof VanJsfField);
160
+ }
100
161
  }
@@ -50,21 +50,9 @@ class VanJsfForm {
50
50
  */
51
51
  getFieldsAndValuesFromJsf(headlessForm, initialValues) {
52
52
  const fields = headlessForm.fields;
53
+ console.log(fields);
53
54
  const formValues = {};
54
- const vanJsfFields = fields.map((field) => {
55
- // TODO needs to support field sets recursively
56
- // Extract the field name as a string
57
- const fieldName = field.name;
58
- // Determine the initial value for the field
59
- // **Important**!: `field.default` is not properly documented in
60
- // https://json-schema-form.vercel.app/?path=/docs/api-reference-api--docs
61
- // They say the property for default values is `defaultValue` but it's not
62
- const initVal = initialValues[fieldName] || field.default || "";
63
- // Store the initial value in the form values map
64
- formValues[fieldName] = initVal;
65
- // Create and return a new VanJsfField instance for this field
66
- return new VanJsfField(field, initVal, this.handleFieldChange);
67
- });
55
+ const vanJsfFields = this.processFields(fields, initialValues, formValues);
68
56
  return { vanJsfFields, formValues };
69
57
  }
70
58
  handleFieldChange(field, value) {
@@ -77,6 +65,24 @@ class VanJsfForm {
77
65
  f.error = formErrors?.[f.name] ?? "";
78
66
  });
79
67
  }
68
+ processFields(fields, initialValues, formValues, parentPath = "") {
69
+ return fields.map((field) => {
70
+ // Construct the full path for the field
71
+ const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name;
72
+ // Determine the initial value for the field
73
+ const initVal = initialValues[fieldPath] || field.default || "";
74
+ // Store the initial value in the form values map
75
+ formValues[fieldPath] = initVal;
76
+ console.log(formValues);
77
+ console.log(initialValues);
78
+ // Check if the field has nested fields and process them recursively
79
+ if (field.fields && field.fields.length > 0) {
80
+ field.fields = this.processFields(field.fields, initialValues, formValues, fieldPath);
81
+ }
82
+ // Create and return a new VanJsfField instance for this field
83
+ return new VanJsfField(field, initVal, this.handleFieldChange);
84
+ });
85
+ }
80
86
  }
81
87
  export function jsform(attributes, ...children) {
82
88
  if (!attributes.schema) {
@@ -93,6 +99,7 @@ export function jsform(attributes, ...children) {
93
99
  config.formValues = {};
94
100
  }
95
101
  const vanJsfForm = new VanJsfForm(attributes.schema, config);
102
+ console.log(vanJsfForm);
96
103
  const fields = vanJsfForm.formFields.map((field) => field.render());
97
104
  const childrenWithFields = [...fields, ...children]; // Concatenate fields with other children
98
105
  const originalOnSubmit = attributes.onsubmit;
@@ -101,6 +108,10 @@ export function jsform(attributes, ...children) {
101
108
  config.formValues = vanJsfForm.formValues;
102
109
  originalOnSubmit && originalOnSubmit(e);
103
110
  };
111
+ const handleChange = (e) => {
112
+ config.formValues = vanJsfForm.formValues;
113
+ };
104
114
  attributes.onsubmit = handleSubmit;
115
+ attributes.onchange = handleChange;
105
116
  return form(attributes, ...childrenWithFields);
106
117
  }