vanjs-jsf 0.0.2 → 0.0.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.
@@ -0,0 +1,267 @@
1
+ var c = Object.defineProperty;
2
+ var f = (i, t, e) => t in i ? c(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
3
+ var r = (i, t, e) => f(i, typeof t != "symbol" ? t + "" : t, e);
4
+ import d from "vanjs-core";
5
+ import { createHeadlessForm as g } from "@remoteoss/json-schema-form";
6
+ class y {
7
+ }
8
+ const { div: o, p: V, input: u, label: m, textarea: b, legend: F } = d.tags;
9
+ class v extends y {
10
+ constructor(e, s, n) {
11
+ super();
12
+ r(this, "name");
13
+ r(this, "field");
14
+ r(this, "iniVal");
15
+ r(this, "handleChange");
16
+ r(this, "isVisibleState");
17
+ r(this, "errorState");
18
+ this.field = e, this.name = e.name, this.iniVal = s, this.handleChange = n, this.isVisibleState = d.state(this.field.isVisible), this.errorState = d.state(""), d.derive(
19
+ () => console.log(`Field ${this.name} isVisible: ${this.isVisibleState.val}`)
20
+ );
21
+ }
22
+ get inputType() {
23
+ return this.field.inputType;
24
+ }
25
+ get label() {
26
+ return this.field.label;
27
+ }
28
+ get description() {
29
+ return this.field.description;
30
+ }
31
+ get options() {
32
+ return this.field.options;
33
+ }
34
+ get isVisible() {
35
+ return this.isVisibleState.val;
36
+ }
37
+ set isVisible(e) {
38
+ this.isVisibleState.val = e;
39
+ }
40
+ get error() {
41
+ return this.errorState.val;
42
+ }
43
+ set error(e) {
44
+ this.errorState.val = e;
45
+ }
46
+ render() {
47
+ var n;
48
+ let e;
49
+ const s = {
50
+ style: () => this.isVisible ? "display: block" : "display: none"
51
+ };
52
+ switch (this.inputType) {
53
+ case "text":
54
+ e = o(
55
+ s,
56
+ m({ for: this.name }, this.label),
57
+ this.description && o({ id: `${this.name}-description` }, this.description),
58
+ u({
59
+ id: this.name,
60
+ type: "text",
61
+ value: this.iniVal,
62
+ oninput: (a) => this.handleChange(this, a.target.value)
63
+ }),
64
+ V(() => this.error)
65
+ );
66
+ break;
67
+ case "textarea":
68
+ e = o(
69
+ s,
70
+ m({ for: this.name }, this.label),
71
+ this.description && o({ id: `${this.name}-description` }, this.description),
72
+ b({
73
+ id: this.name,
74
+ name: this.name,
75
+ rows: this.field.rows,
76
+ cols: this.field.columns,
77
+ oninput: (a) => this.handleChange(this, a.target.value)
78
+ })
79
+ );
80
+ break;
81
+ case "number":
82
+ e = o(
83
+ s,
84
+ m({ for: this.name }, this.label),
85
+ this.description && o({ id: `${this.name}-description` }, this.description),
86
+ u({
87
+ id: this.name,
88
+ type: "number",
89
+ value: this.iniVal,
90
+ oninput: (a) => this.handleChange(this, a.target.value)
91
+ })
92
+ );
93
+ break;
94
+ case "radio":
95
+ e = o(
96
+ F(this.label),
97
+ this.description && o(this.description),
98
+ o(
99
+ (n = this.options) == null ? void 0 : n.map(
100
+ (a) => m(
101
+ u({
102
+ type: "radio",
103
+ name: this.name,
104
+ value: a.value,
105
+ checked: this.iniVal === a.value,
106
+ onchange: (l) => this.handleChange(this, l.target.value)
107
+ }),
108
+ a.label,
109
+ a.description
110
+ )
111
+ )
112
+ )
113
+ );
114
+ break;
115
+ default:
116
+ e = o(
117
+ { style: "border: 1px dashed gray; padding: 8px;" },
118
+ `Field "${this.name}" unsupported: The type "${this.inputType}" has no UI component built yet.`
119
+ );
120
+ }
121
+ return e;
122
+ }
123
+ }
124
+ const { form: S } = d.tags;
125
+ class _ {
126
+ constructor(t, e) {
127
+ r(this, "schema");
128
+ r(this, "config");
129
+ r(this, "headlessForm");
130
+ r(this, "formFields");
131
+ r(this, "formValues");
132
+ this.handleFieldChange = this.handleFieldChange.bind(this), this.schema = t, this.config = e, this.headlessForm = g(t, e);
133
+ const { vanJsfFields: s, formValues: n } = this.getFieldsAndValuesFromJsf(
134
+ this.headlessForm,
135
+ this.config.initialValues
136
+ );
137
+ this.formFields = s, this.formValues = n;
138
+ }
139
+ /**
140
+ * Generates fields and their initial values from a headless JSON Schema Form (JSF).
141
+ * This method processes the fields provided by the headless form, maps them to `VanJsfField` instances,
142
+ * and initializes the corresponding form values.
143
+ *
144
+ * @param headlessForm - The output of the `createHeadlessForm` function, containing metadata and configuration for the form fields.
145
+ * @param initialValues - A record object where the keys represent field names, and the values are the initial values for the fields.
146
+ *
147
+ * @returns An object containing:
148
+ * - `vanJsfFields`: An array of `VanJsfField` instances representing the fields in the form.
149
+ * - `formValues`: A record object mapping field names to their respective initial values.
150
+ *
151
+ * @remarks
152
+ * - **Field Sets**: The method currently does not support field sets recursively. This needs to be implemented as part of future enhancements.
153
+ * - **Default Values**:
154
+ * - The default values are determined based on the following precedence:
155
+ * 1. Value in `initialValues`.
156
+ * 2. The `field.default` property.
157
+ * 3. An empty string (`""`) if neither is present.
158
+ * - Note: The `field.default` property is not clearly documented in the JSF API. The documentation mentions `defaultValue` instead, but this is not observed in practice.
159
+ *
160
+ * @example
161
+ * const { vanJsfFields, formValues } = getFieldsFromJsf(headlessForm, initialValues);
162
+ * console.log(vanJsfFields); // Array of VanJsfField instances
163
+ * console.log(formValues); // Record of field names and their initial values
164
+ */
165
+ getFieldsAndValuesFromJsf(t, e) {
166
+ const s = t.fields, n = {};
167
+ return { vanJsfFields: s.map((l) => {
168
+ const p = l.name, h = e[p] || l.default || "";
169
+ return n[p] = h, new v(l, h, this.handleFieldChange);
170
+ }), formValues: n };
171
+ }
172
+ handleFieldChange(t, e) {
173
+ console.log(`Field ${t.name} changed to ${e}`), this.formValues[t.name] = e;
174
+ const { formErrors: s } = this.headlessForm.handleValidation(this.formValues);
175
+ console.log("formErrors", s), this.formFields.forEach((n) => {
176
+ n.isVisible = n.field.isVisible, n.error = (s == null ? void 0 : s[n.name]) ?? "";
177
+ });
178
+ }
179
+ }
180
+ function x(i, ...t) {
181
+ if (!i.schema)
182
+ throw new Error("JSON Schema is required");
183
+ let e = i.config;
184
+ e ? e.initialValues ? e.formValues || (e.formValues = {}) : e.initialValues = {} : e = { initialValues: {}, formValues: {} };
185
+ const s = new _(i.schema, e), a = [...s.formFields.map(
186
+ (h) => h.render()
187
+ ), ...t], l = i.onsubmit, p = (h) => {
188
+ h.preventDefault(), e.formValues = s.formValues, l && l(h);
189
+ };
190
+ return i.onsubmit = p, S(i, ...a);
191
+ }
192
+ const { div: J, p: C, h1: $, button: w } = d.tags, T = {
193
+ type: "object",
194
+ additionalProperties: !1,
195
+ properties: {
196
+ has_pet: {
197
+ title: "Has Pet",
198
+ description: "Do you have a pet?",
199
+ oneOf: [
200
+ { title: "Yes", const: "yes" },
201
+ { title: "No", const: "no" }
202
+ ],
203
+ "x-jsf-presentation": { inputType: "radio" },
204
+ type: "string"
205
+ },
206
+ pet_name: {
207
+ title: "Pet's name",
208
+ description: "What's your pet's name?",
209
+ "x-jsf-presentation": { inputType: "text" },
210
+ type: "string"
211
+ },
212
+ pet_age: {
213
+ title: "Pet's age",
214
+ description: "What's your pet's age? With more than 5 years, we need to know more about your pet.",
215
+ "x-jsf-presentation": { inputType: "number" },
216
+ type: "number",
217
+ default: 1
218
+ },
219
+ dietary_needs: {
220
+ title: "Dietary needs",
221
+ description: "What are your pet's dietary needs?",
222
+ "x-jsf-presentation": { inputType: "textarea", rows: 15, columns: 50 },
223
+ type: "string"
224
+ }
225
+ },
226
+ required: ["has_pet"],
227
+ "x-jsf-order": ["has_pet", "pet_name", "pet_age", "dietary_needs"],
228
+ allOf: [
229
+ {
230
+ if: { properties: { has_pet: { const: "yes" } }, required: ["has_pet"] },
231
+ then: { required: ["pet_age", "pet_name"] },
232
+ else: { properties: { pet_age: !1, pet_name: !1 } }
233
+ },
234
+ {
235
+ if: {
236
+ properties: { has_pet: { const: "yes" }, pet_age: { minimum: 5 } },
237
+ required: ["pet_age"]
238
+ },
239
+ then: { required: ["dietary_needs"] },
240
+ else: { properties: { dietary_needs: !1 } }
241
+ }
242
+ ]
243
+ }, j = () => {
244
+ const i = { pet_name: "Simon" }, t = {
245
+ strictInputType: !1,
246
+ initialValues: i,
247
+ formValues: i
248
+ }, e = (s) => {
249
+ s.preventDefault();
250
+ const n = t.formValues;
251
+ alert(`Submitted successfully: ${JSON.stringify(n, null, 2)}`), console.log("Submitted!", n);
252
+ };
253
+ return J(
254
+ $("json-schema-form + VanJS"),
255
+ C("This demo uses VanJS without any other form library."),
256
+ x(
257
+ {
258
+ name: "my-jsf-form",
259
+ schema: T,
260
+ config: t,
261
+ onsubmit: e
262
+ },
263
+ w({ type: "submit" }, "Submit")
264
+ )
265
+ );
266
+ };
267
+ d.add(document.body, j());
@@ -0,0 +1 @@
1
+ (function(s,n){typeof exports=="object"&&typeof module<"u"?n(require("vanjs-core"),require("@remoteoss/json-schema-form")):typeof define=="function"&&define.amd?define(["vanjs-core","@remoteoss/json-schema-form"],n):(s=typeof globalThis<"u"?globalThis:s||self,n(s.van,s.jsonSchemaForm))})(this,function(s,n){"use strict";var $=Object.defineProperty;var w=(s,n,m)=>n in s?$(s,n,{enumerable:!0,configurable:!0,writable:!0,value:m}):s[n]=m;var l=(s,n,m)=>w(s,typeof n!="symbol"?n+"":n,m);class m{}const{div:h,p:g,input:f,label:u,textarea:y,legend:V}=s.tags;class b extends m{constructor(e,t,i){super();l(this,"name");l(this,"field");l(this,"iniVal");l(this,"handleChange");l(this,"isVisibleState");l(this,"errorState");this.field=e,this.name=e.name,this.iniVal=t,this.handleChange=i,this.isVisibleState=s.state(this.field.isVisible),this.errorState=s.state(""),s.derive(()=>console.log(`Field ${this.name} isVisible: ${this.isVisibleState.val}`))}get inputType(){return this.field.inputType}get label(){return this.field.label}get description(){return this.field.description}get options(){return this.field.options}get isVisible(){return this.isVisibleState.val}set isVisible(e){this.isVisibleState.val=e}get error(){return this.errorState.val}set error(e){this.errorState.val=e}render(){var i;let e;const t={style:()=>this.isVisible?"display: block":"display: none"};switch(this.inputType){case"text":e=h(t,u({for:this.name},this.label),this.description&&h({id:`${this.name}-description`},this.description),f({id:this.name,type:"text",value:this.iniVal,oninput:r=>this.handleChange(this,r.target.value)}),g(()=>this.error));break;case"textarea":e=h(t,u({for:this.name},this.label),this.description&&h({id:`${this.name}-description`},this.description),y({id:this.name,name:this.name,rows:this.field.rows,cols:this.field.columns,oninput:r=>this.handleChange(this,r.target.value)}));break;case"number":e=h(t,u({for:this.name},this.label),this.description&&h({id:`${this.name}-description`},this.description),f({id:this.name,type:"number",value:this.iniVal,oninput:r=>this.handleChange(this,r.target.value)}));break;case"radio":e=h(V(this.label),this.description&&h(this.description),h((i=this.options)==null?void 0:i.map(r=>u(f({type:"radio",name:this.name,value:r.value,checked:this.iniVal===r.value,onchange:d=>this.handleChange(this,d.target.value)}),r.label,r.description))));break;default:e=h({style:"border: 1px dashed gray; padding: 8px;"},`Field "${this.name}" unsupported: The type "${this.inputType}" has no UI component built yet.`)}return e}}const{form:F}=s.tags;class S{constructor(a,e){l(this,"schema");l(this,"config");l(this,"headlessForm");l(this,"formFields");l(this,"formValues");this.handleFieldChange=this.handleFieldChange.bind(this),this.schema=a,this.config=e,this.headlessForm=n.createHeadlessForm(a,e);const{vanJsfFields:t,formValues:i}=this.getFieldsAndValuesFromJsf(this.headlessForm,this.config.initialValues);this.formFields=t,this.formValues=i}getFieldsAndValuesFromJsf(a,e){const t=a.fields,i={};return{vanJsfFields:t.map(d=>{const c=d.name,p=e[c]||d.default||"";return i[c]=p,new b(d,p,this.handleFieldChange)}),formValues:i}}handleFieldChange(a,e){console.log(`Field ${a.name} changed to ${e}`),this.formValues[a.name]=e;const{formErrors:t}=this.headlessForm.handleValidation(this.formValues);console.log("formErrors",t),this.formFields.forEach(i=>{i.isVisible=i.field.isVisible,i.error=(t==null?void 0:t[i.name])??""})}}function v(o,...a){if(!o.schema)throw new Error("JSON Schema is required");let e=o.config;e?e.initialValues?e.formValues||(e.formValues={}):e.initialValues={}:e={initialValues:{},formValues:{}};const t=new S(o.schema,e),r=[...t.formFields.map(p=>p.render()),...a],d=o.onsubmit,c=p=>{p.preventDefault(),e.formValues=t.formValues,d&&d(p)};return o.onsubmit=c,F(o,...r)}const{div:_,p:j,h1:x,button:J}=s.tags,T={type:"object",additionalProperties:!1,properties:{has_pet:{title:"Has Pet",description:"Do you have a pet?",oneOf:[{title:"Yes",const:"yes"},{title:"No",const:"no"}],"x-jsf-presentation":{inputType:"radio"},type:"string"},pet_name:{title:"Pet's name",description:"What's your pet's name?","x-jsf-presentation":{inputType:"text"},type:"string"},pet_age:{title:"Pet's age",description:"What's your pet's age? With more than 5 years, we need to know more about your pet.","x-jsf-presentation":{inputType:"number"},type:"number",default:1},dietary_needs:{title:"Dietary needs",description:"What are your pet's dietary needs?","x-jsf-presentation":{inputType:"textarea",rows:15,columns:50},type:"string"}},required:["has_pet"],"x-jsf-order":["has_pet","pet_name","pet_age","dietary_needs"],allOf:[{if:{properties:{has_pet:{const:"yes"}},required:["has_pet"]},then:{required:["pet_age","pet_name"]},else:{properties:{pet_age:!1,pet_name:!1}}},{if:{properties:{has_pet:{const:"yes"},pet_age:{minimum:5}},required:["pet_age"]},then:{required:["dietary_needs"]},else:{properties:{dietary_needs:!1}}}]},C=()=>{const o={pet_name:"Simon"},a={strictInputType:!1,initialValues:o,formValues:o},e=t=>{t.preventDefault();const i=a.formValues;alert(`Submitted successfully: ${JSON.stringify(i,null,2)}`),console.log("Submitted!",i)};return _(x("json-schema-form + VanJS"),j("This demo uses VanJS without any other form library."),v({name:"my-jsf-form",schema:T,config:a,onsubmit:e},J({type:"submit"},"Submit")))};s.add(document.body,C())});
package/package.json CHANGED
@@ -1,19 +1,24 @@
1
1
  {
2
2
  "name": "vanjs-jsf",
3
- "version": "0.0.2",
4
- "description": "A JSON Schema Form Library for VanJS",
5
- "main": "index.js",
6
- "files": [ "dist", "README.md" ],
7
- "keywords": ["vanjs", "json-schema", "form", "ui-library"],
3
+ "description": "A JSON Schema Form UI Library for VanJS",
4
+ "keywords": ["vanjs", "json", "schema", "form", "ui-library"],
5
+ "version": "0.0.4",
8
6
  "author": {
9
7
  "name": "Carlos Prados",
10
8
  "email": "carlos.prados@gmail.com"
11
9
  },
12
10
  "license": "Apache-2.0",
11
+
12
+ "type": "module",
13
+ "files": [ "dist", "README.md" ],
14
+ "main": "./dist/vanjs-jsf.umd.cjs",
15
+ "module": "./dist/vanjs-jsf.js",
16
+
13
17
  "scripts": {
14
18
  "dev": "vite",
15
19
  "test": "jest",
16
20
  "build": "tsc && vite build",
21
+ "tsc": "tsc",
17
22
  "preview": "vite preview"
18
23
  },
19
24
  "devDependencies": {