vanjs-jsf 0.0.5 → 0.0.7
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/dist/JsfUtils.d.ts +0 -1
- package/dist/JsfUtils.js +10 -0
- package/dist/VanJSComponent.d.ts +0 -1
- package/dist/VanJSComponent.js +2 -0
- package/dist/VanJsfField.d.ts +0 -1
- package/dist/VanJsfField.js +100 -0
- package/dist/VanJsfForm.d.ts +0 -1
- package/dist/VanJsfForm.js +106 -0
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -0
- package/dist/index.js.map +7 -0
- package/dist/main.d.ts +0 -1
- package/dist/main.js +78 -0
- package/package.json +28 -20
- package/dist/JsfUtils.d.ts.map +0 -1
- package/dist/VanJSComponent.d.ts.map +0 -1
- package/dist/VanJsfField.d.ts.map +0 -1
- package/dist/VanJsfForm.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/vanjs-jsf.js +0 -267
- package/dist/vanjs-jsf.umd.cjs +0 -1
package/dist/JsfUtils.d.ts
CHANGED
package/dist/JsfUtils.js
ADDED
package/dist/VanJSComponent.d.ts
CHANGED
package/dist/VanJsfField.d.ts
CHANGED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import van from "vanjs-core";
|
|
2
|
+
import { VanJSComponent } from "./VanJSComponent";
|
|
3
|
+
const { div, p, input, label, textarea, legend } = van.tags;
|
|
4
|
+
var FieldType;
|
|
5
|
+
(function (FieldType) {
|
|
6
|
+
FieldType["text"] = "text";
|
|
7
|
+
FieldType["number"] = "number";
|
|
8
|
+
FieldType["textarea"] = "textarea";
|
|
9
|
+
FieldType["radio"] = "radio";
|
|
10
|
+
})(FieldType || (FieldType = {}));
|
|
11
|
+
export class VanJsfField extends VanJSComponent {
|
|
12
|
+
name;
|
|
13
|
+
field;
|
|
14
|
+
iniVal;
|
|
15
|
+
handleChange;
|
|
16
|
+
isVisibleState;
|
|
17
|
+
errorState;
|
|
18
|
+
constructor(field, initVal, handleChange) {
|
|
19
|
+
super();
|
|
20
|
+
this.field = field;
|
|
21
|
+
this.name = field.name;
|
|
22
|
+
this.iniVal = initVal;
|
|
23
|
+
this.handleChange = handleChange;
|
|
24
|
+
this.isVisibleState = van.state(this.field.isVisible);
|
|
25
|
+
this.errorState = van.state("");
|
|
26
|
+
van.derive(() => console.log(`Field ${this.name} isVisible: ${this.isVisibleState.val}`));
|
|
27
|
+
}
|
|
28
|
+
get inputType() {
|
|
29
|
+
return this.field.inputType;
|
|
30
|
+
}
|
|
31
|
+
get label() {
|
|
32
|
+
return this.field.label;
|
|
33
|
+
}
|
|
34
|
+
get description() {
|
|
35
|
+
return this.field.description;
|
|
36
|
+
}
|
|
37
|
+
get options() {
|
|
38
|
+
return this.field.options;
|
|
39
|
+
}
|
|
40
|
+
get isVisible() {
|
|
41
|
+
return this.isVisibleState.val;
|
|
42
|
+
}
|
|
43
|
+
set isVisible(val) {
|
|
44
|
+
this.isVisibleState.val = val;
|
|
45
|
+
}
|
|
46
|
+
get error() {
|
|
47
|
+
return this.errorState.val;
|
|
48
|
+
}
|
|
49
|
+
set error(val) {
|
|
50
|
+
this.errorState.val = val;
|
|
51
|
+
}
|
|
52
|
+
render() {
|
|
53
|
+
let el;
|
|
54
|
+
const props = {
|
|
55
|
+
style: () => (this.isVisible ? "display: block" : "display: none"),
|
|
56
|
+
};
|
|
57
|
+
switch (this.inputType) {
|
|
58
|
+
case FieldType.text:
|
|
59
|
+
el = div(props, label({ for: this.name }, this.label), this.description &&
|
|
60
|
+
div({ id: `${this.name}-description` }, this.description), input({
|
|
61
|
+
id: this.name,
|
|
62
|
+
type: "text",
|
|
63
|
+
value: this.iniVal,
|
|
64
|
+
oninput: (e) => this.handleChange(this, e.target.value),
|
|
65
|
+
}), p(() => this.error));
|
|
66
|
+
break;
|
|
67
|
+
case FieldType.textarea:
|
|
68
|
+
el = div(props, label({ for: this.name }, this.label), this.description &&
|
|
69
|
+
div({ id: `${this.name}-description` }, this.description), textarea({
|
|
70
|
+
id: this.name,
|
|
71
|
+
name: this.name,
|
|
72
|
+
rows: this.field.rows,
|
|
73
|
+
cols: this.field.columns,
|
|
74
|
+
oninput: (e) => this.handleChange(this, e.target.value),
|
|
75
|
+
}));
|
|
76
|
+
break;
|
|
77
|
+
case FieldType.number:
|
|
78
|
+
el = div(props, label({ for: this.name }, this.label), this.description &&
|
|
79
|
+
div({ id: `${this.name}-description` }, this.description), input({
|
|
80
|
+
id: this.name,
|
|
81
|
+
type: "number",
|
|
82
|
+
value: this.iniVal,
|
|
83
|
+
oninput: (e) => this.handleChange(this, e.target.value),
|
|
84
|
+
}));
|
|
85
|
+
break;
|
|
86
|
+
case FieldType.radio:
|
|
87
|
+
el = div(legend(this.label), this.description && div(this.description), div(this.options?.map((opt) => label(input({
|
|
88
|
+
type: "radio",
|
|
89
|
+
name: this.name,
|
|
90
|
+
value: opt.value,
|
|
91
|
+
checked: this.iniVal === opt.value,
|
|
92
|
+
onchange: (e) => this.handleChange(this, e.target.value),
|
|
93
|
+
}), opt.label, opt.description))));
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
el = div({ style: "border: 1px dashed gray; padding: 8px;" }, `Field "${this.name}" unsupported: The type "${this.inputType}" has no UI component built yet.`);
|
|
97
|
+
}
|
|
98
|
+
return el;
|
|
99
|
+
}
|
|
100
|
+
}
|
package/dist/VanJsfForm.d.ts
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import van from "vanjs-core";
|
|
2
|
+
import { createHeadlessForm, } from "@remoteoss/json-schema-form";
|
|
3
|
+
import { VanJsfField } from "./VanJsfField";
|
|
4
|
+
const { form } = van.tags;
|
|
5
|
+
class VanJsfForm {
|
|
6
|
+
schema;
|
|
7
|
+
config;
|
|
8
|
+
headlessForm;
|
|
9
|
+
formFields;
|
|
10
|
+
formValues;
|
|
11
|
+
constructor(jsonSchema, config) {
|
|
12
|
+
// Bind methods to instance. Needed to pass functions as props to child components
|
|
13
|
+
//this.handleSubmit = this.handleSubmit.bind(this);
|
|
14
|
+
this.handleFieldChange = this.handleFieldChange.bind(this);
|
|
15
|
+
// Receive parameters
|
|
16
|
+
this.schema = jsonSchema;
|
|
17
|
+
this.config = config;
|
|
18
|
+
// Working with parameters
|
|
19
|
+
this.headlessForm = createHeadlessForm(jsonSchema, config);
|
|
20
|
+
// Read documentation about `getFieldsAndValuedFromJsf` method below
|
|
21
|
+
const { vanJsfFields, formValues } = this.getFieldsAndValuesFromJsf(this.headlessForm, this.config.initialValues);
|
|
22
|
+
this.formFields = vanJsfFields;
|
|
23
|
+
this.formValues = formValues;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Generates fields and their initial values from a headless JSON Schema Form (JSF).
|
|
27
|
+
* This method processes the fields provided by the headless form, maps them to `VanJsfField` instances,
|
|
28
|
+
* and initializes the corresponding form values.
|
|
29
|
+
*
|
|
30
|
+
* @param headlessForm - The output of the `createHeadlessForm` function, containing metadata and configuration for the form fields.
|
|
31
|
+
* @param initialValues - A record object where the keys represent field names, and the values are the initial values for the fields.
|
|
32
|
+
*
|
|
33
|
+
* @returns An object containing:
|
|
34
|
+
* - `vanJsfFields`: An array of `VanJsfField` instances representing the fields in the form.
|
|
35
|
+
* - `formValues`: A record object mapping field names to their respective initial values.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* - **Field Sets**: The method currently does not support field sets recursively. This needs to be implemented as part of future enhancements.
|
|
39
|
+
* - **Default Values**:
|
|
40
|
+
* - The default values are determined based on the following precedence:
|
|
41
|
+
* 1. Value in `initialValues`.
|
|
42
|
+
* 2. The `field.default` property.
|
|
43
|
+
* 3. An empty string (`""`) if neither is present.
|
|
44
|
+
* - 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.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const { vanJsfFields, formValues } = getFieldsFromJsf(headlessForm, initialValues);
|
|
48
|
+
* console.log(vanJsfFields); // Array of VanJsfField instances
|
|
49
|
+
* console.log(formValues); // Record of field names and their initial values
|
|
50
|
+
*/
|
|
51
|
+
getFieldsAndValuesFromJsf(headlessForm, initialValues) {
|
|
52
|
+
const fields = headlessForm.fields;
|
|
53
|
+
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
|
+
});
|
|
68
|
+
return { vanJsfFields, formValues };
|
|
69
|
+
}
|
|
70
|
+
handleFieldChange(field, value) {
|
|
71
|
+
console.log(`Field ${field.name} changed to ${value}`);
|
|
72
|
+
this.formValues[field.name] = value;
|
|
73
|
+
const { formErrors } = this.headlessForm.handleValidation(this.formValues);
|
|
74
|
+
console.log("formErrors", formErrors);
|
|
75
|
+
this.formFields.forEach((f) => {
|
|
76
|
+
f.isVisible = f.field.isVisible;
|
|
77
|
+
f.error = formErrors?.[f.name] ?? "";
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function jsform(attributes, ...children) {
|
|
82
|
+
if (!attributes.schema) {
|
|
83
|
+
throw new Error("JSON Schema is required");
|
|
84
|
+
}
|
|
85
|
+
let config = attributes.config;
|
|
86
|
+
if (!config) {
|
|
87
|
+
config = { initialValues: {}, formValues: {} };
|
|
88
|
+
}
|
|
89
|
+
else if (!config.initialValues) {
|
|
90
|
+
config.initialValues = {};
|
|
91
|
+
}
|
|
92
|
+
else if (!config.formValues) {
|
|
93
|
+
config.formValues = {};
|
|
94
|
+
}
|
|
95
|
+
const vanJsfForm = new VanJsfForm(attributes.schema, config);
|
|
96
|
+
const fields = vanJsfForm.formFields.map((field) => field.render());
|
|
97
|
+
const childrenWithFields = [...fields, ...children]; // Concatenate fields with other children
|
|
98
|
+
const originalOnSubmit = attributes.onsubmit;
|
|
99
|
+
const handleSubmit = (e) => {
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
config.formValues = vanJsfForm.formValues;
|
|
102
|
+
originalOnSubmit && originalOnSubmit(e);
|
|
103
|
+
};
|
|
104
|
+
attributes.onsubmit = handleSubmit;
|
|
105
|
+
return form(attributes, ...childrenWithFields);
|
|
106
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { jsform } from "./VanJsfForm";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../lib/VanJsfForm.ts", "../lib/VanJsfField.ts", "../lib/VanJSComponent.ts"],
|
|
4
|
+
"sourcesContent": ["import van from \"vanjs-core\";\n\nimport {\n createHeadlessForm,\n HeadlessFormOutput,\n Fields,\n JSONSchemaObjectType,\n} from \"@remoteoss/json-schema-form\";\n\nimport { VanJsfField, MultiType } from \"./VanJsfField\";\n\nconst { form } = van.tags;\n\nclass VanJsfForm {\n schema: JSONSchemaObjectType;\n config: Record<string, any>;\n headlessForm: HeadlessFormOutput;\n formFields: VanJsfField[];\n formValues: Record<string, any>;\n\n constructor(jsonSchema: JSONSchemaObjectType, config: Record<string, any>) {\n // Bind methods to instance. Needed to pass functions as props to child components\n //this.handleSubmit = this.handleSubmit.bind(this);\n this.handleFieldChange = this.handleFieldChange.bind(this);\n // Receive parameters\n this.schema = jsonSchema;\n this.config = config;\n // Working with parameters\n this.headlessForm = createHeadlessForm(jsonSchema, config);\n // Read documentation about `getFieldsAndValuedFromJsf` method below\n const { vanJsfFields, formValues } = this.getFieldsAndValuesFromJsf(\n this.headlessForm,\n this.config.initialValues\n );\n this.formFields = vanJsfFields;\n this.formValues = formValues;\n }\n\n /**\n * Generates fields and their initial values from a headless JSON Schema Form (JSF).\n * This method processes the fields provided by the headless form, maps them to `VanJsfField` instances,\n * and initializes the corresponding form values.\n *\n * @param headlessForm - The output of the `createHeadlessForm` function, containing metadata and configuration for the form fields.\n * @param initialValues - A record object where the keys represent field names, and the values are the initial values for the fields.\n *\n * @returns An object containing:\n * - `vanJsfFields`: An array of `VanJsfField` instances representing the fields in the form.\n * - `formValues`: A record object mapping field names to their respective initial values.\n *\n * @remarks\n * - **Field Sets**: The method currently does not support field sets recursively. This needs to be implemented as part of future enhancements.\n * - **Default Values**:\n * - The default values are determined based on the following precedence:\n * 1. Value in `initialValues`.\n * 2. The `field.default` property.\n * 3. An empty string (`\"\"`) if neither is present.\n * - 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.\n *\n * @example\n * const { vanJsfFields, formValues } = getFieldsFromJsf(headlessForm, initialValues);\n * console.log(vanJsfFields); // Array of VanJsfField instances\n * console.log(formValues); // Record of field names and their initial values\n */\n getFieldsAndValuesFromJsf(\n headlessForm: HeadlessFormOutput,\n initialValues: Record<string, any>\n ): { vanJsfFields: VanJsfField[]; formValues: Record<string, any> } {\n const fields: Fields = headlessForm.fields;\n const formValues: Record<string, any> = {};\n const vanJsfFields: VanJsfField[] = fields.map((field) => {\n // TODO needs to support field sets recursively\n // Extract the field name as a string\n const fieldName: string = field.name as string;\n // Determine the initial value for the field\n // **Important**!: `field.default` is not properly documented in\n // https://json-schema-form.vercel.app/?path=/docs/api-reference-api--docs\n // They say the property for default values is `defaultValue` but it's not\n const initVal = initialValues[fieldName] || field.default || \"\";\n // Store the initial value in the form values map\n formValues[fieldName] = initVal;\n // Create and return a new VanJsfField instance for this field\n return new VanJsfField(field, initVal, this.handleFieldChange);\n });\n return { vanJsfFields, formValues };\n }\n\n handleFieldChange(field: VanJsfField, value: MultiType) {\n console.log(`Field ${field.name} changed to ${value}`);\n this.formValues[field.name] = value;\n const { formErrors } = this.headlessForm.handleValidation(this.formValues);\n console.log(\"formErrors\", formErrors);\n this.formFields.forEach((f) => {\n f.isVisible = f.field.isVisible as boolean;\n f.error = formErrors?.[f.name] ?? \"\";\n });\n }\n}\n\nexport function jsform(\n attributes: Record<string, any>,\n ...children: any[]\n): HTMLFormElement {\n if (!attributes.schema) {\n throw new Error(\"JSON Schema is required\");\n }\n let config = attributes.config;\n if (!config) {\n config = { initialValues: {}, formValues: {} };\n } else if (!config.initialValues) {\n config.initialValues = {};\n } else if (!config.formValues) {\n config.formValues = {};\n }\n const vanJsfForm: VanJsfForm = new VanJsfForm(attributes.schema, config);\n const fields: Element[] = vanJsfForm.formFields.map((field: VanJsfField) =>\n field.render()\n );\n\n const childrenWithFields = [...fields, ...children]; // Concatenate fields with other children\n\n const originalOnSubmit = attributes.onsubmit;\n const handleSubmit = (e: Event) => {\n e.preventDefault();\n config.formValues = vanJsfForm.formValues;\n originalOnSubmit && originalOnSubmit(e);\n };\n attributes.onsubmit = handleSubmit;\n return form(attributes, ...childrenWithFields);\n}\n", "import van, { State } from \"vanjs-core\";\nimport { VanJSComponent } from \"./VanJSComponent\";\n\nconst { div, p, input, label, textarea, legend } = van.tags;\n\nenum FieldType {\n text = \"text\",\n number = \"number\",\n textarea = \"textarea\",\n radio = \"radio\",\n}\n\nexport interface Option {\n label: string;\n value: string;\n description: string;\n}\n\nexport type MultiType = string | number | boolean;\n\nexport class VanJsfField extends VanJSComponent {\n name: string;\n field: Record<string, unknown>;\n iniVal: MultiType;\n handleChange: (field: VanJsfField, value: MultiType) => void;\n isVisibleState: State<boolean>;\n errorState: State<string>;\n\n constructor(\n field: Record<string, unknown>,\n initVal: string,\n handleChange: (field: VanJsfField, value: MultiType) => void\n ) {\n super();\n this.field = field;\n this.name = field.name as string;\n this.iniVal = initVal;\n this.handleChange = handleChange;\n this.isVisibleState = van.state(this.field.isVisible as boolean);\n this.errorState = van.state(\"\");\n van.derive(() =>\n console.log(`Field ${this.name} isVisible: ${this.isVisibleState.val}`)\n );\n }\n\n get inputType(): string {\n return this.field.inputType as string;\n }\n get label(): string {\n return this.field.label as string;\n }\n get description(): string {\n return this.field.description as string;\n }\n get options(): Option[] {\n return this.field.options as Option[];\n }\n get isVisible(): boolean {\n return this.isVisibleState.val;\n }\n\n set isVisible(val: boolean) {\n this.isVisibleState.val = val;\n }\n\n get error(): string {\n return this.errorState.val;\n }\n\n set error(val: string) {\n this.errorState.val = val;\n }\n\n render(): Element {\n let el: Element;\n const props: Record<string, any> = {\n style: () => (this.isVisible ? \"display: block\" : \"display: none\"),\n };\n switch (this.inputType) {\n case FieldType.text:\n el = div(\n props,\n label({ for: this.name }, this.label),\n this.description &&\n div({ id: `${this.name}-description` }, this.description),\n input({\n id: this.name,\n type: \"text\",\n value: this.iniVal,\n oninput: (e: any) => this.handleChange(this, e.target.value),\n }),\n p(() => this.error)\n );\n break;\n\n case FieldType.textarea:\n el = div(\n props,\n label({ for: this.name }, this.label),\n this.description &&\n div({ id: `${this.name}-description` }, this.description),\n textarea({\n id: this.name,\n name: this.name,\n rows: this.field.rows as number,\n cols: this.field.columns as number,\n oninput: (e: any) => this.handleChange(this, e.target.value),\n })\n );\n break;\n case FieldType.number:\n el = div(\n props,\n label({ for: this.name }, this.label),\n this.description &&\n div({ id: `${this.name}-description` }, this.description),\n input({\n id: this.name,\n type: \"number\",\n value: this.iniVal,\n oninput: (e: any) => this.handleChange(this, e.target.value),\n })\n );\n break;\n case FieldType.radio:\n el = div(\n legend(this.label),\n this.description && div(this.description),\n div(\n this.options?.map((opt: any) =>\n label(\n input({\n type: \"radio\",\n name: this.name,\n value: opt.value,\n checked: this.iniVal === opt.value,\n onchange: (e: any) => this.handleChange(this, e.target.value),\n }),\n opt.label,\n opt.description\n )\n )\n )\n );\n break;\n default:\n el = div(\n { style: \"border: 1px dashed gray; padding: 8px;\" },\n `Field \"${this.name}\" unsupported: The type \"${this.inputType}\" has no UI component built yet.`\n );\n }\n return el;\n }\n}\n", "export abstract class VanJSComponent {\n abstract render(): Element;\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,OAAOA,UAAS;AAEhB;AAAA,EACE;AAAA,OAIK;;;ACPP,OAAO,SAAoB;;;ACApB,IAAe,iBAAf,MAA8B;AAErC;;;ADCA,IAAM,EAAE,KAAK,GAAG,OAAO,OAAO,UAAU,OAAO,IAAI,IAAI;AAiBhD,IAAM,cAAN,cAA0B,eAAe;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YACE,OACA,SACA,cACA;AACA,UAAM;AACN,SAAK,QAAQ;AACb,SAAK,OAAO,MAAM;AAClB,SAAK,SAAS;AACd,SAAK,eAAe;AACpB,SAAK,iBAAiB,IAAI,MAAM,KAAK,MAAM,SAAoB;AAC/D,SAAK,aAAa,IAAI,MAAM,EAAE;AAC9B,QAAI;AAAA,MAAO,MACT,QAAQ,IAAI,SAAS,KAAK,IAAI,eAAe,KAAK,eAAe,GAAG,EAAE;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,IAAI,YAAoB;AACtB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EACA,IAAI,QAAgB;AAClB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EACA,IAAI,cAAsB;AACxB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EACA,IAAI,UAAoB;AACtB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EACA,IAAI,YAAqB;AACvB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,IAAI,UAAU,KAAc;AAC1B,SAAK,eAAe,MAAM;AAAA,EAC5B;AAAA,EAEA,IAAI,QAAgB;AAClB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA,EAEA,IAAI,MAAM,KAAa;AACrB,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA,EAEA,SAAkB;AAChB,QAAI;AACJ,UAAM,QAA6B;AAAA,MACjC,OAAO,MAAO,KAAK,YAAY,mBAAmB;AAAA,IACpD;AACA,YAAQ,KAAK,WAAW;AAAA,MACtB,KAAK;AACH,aAAK;AAAA,UACH;AAAA,UACA,MAAM,EAAE,KAAK,KAAK,KAAK,GAAG,KAAK,KAAK;AAAA,UACpC,KAAK,eACH,IAAI,EAAE,IAAI,GAAG,KAAK,IAAI,eAAe,GAAG,KAAK,WAAW;AAAA,UAC1D,MAAM;AAAA,YACJ,IAAI,KAAK;AAAA,YACT,MAAM;AAAA,YACN,OAAO,KAAK;AAAA,YACZ,SAAS,CAAC,MAAW,KAAK,aAAa,MAAM,EAAE,OAAO,KAAK;AAAA,UAC7D,CAAC;AAAA,UACD,EAAE,MAAM,KAAK,KAAK;AAAA,QACpB;AACA;AAAA,MAEF,KAAK;AACH,aAAK;AAAA,UACH;AAAA,UACA,MAAM,EAAE,KAAK,KAAK,KAAK,GAAG,KAAK,KAAK;AAAA,UACpC,KAAK,eACH,IAAI,EAAE,IAAI,GAAG,KAAK,IAAI,eAAe,GAAG,KAAK,WAAW;AAAA,UAC1D,SAAS;AAAA,YACP,IAAI,KAAK;AAAA,YACT,MAAM,KAAK;AAAA,YACX,MAAM,KAAK,MAAM;AAAA,YACjB,MAAM,KAAK,MAAM;AAAA,YACjB,SAAS,CAAC,MAAW,KAAK,aAAa,MAAM,EAAE,OAAO,KAAK;AAAA,UAC7D,CAAC;AAAA,QACH;AACA;AAAA,MACF,KAAK;AACH,aAAK;AAAA,UACH;AAAA,UACA,MAAM,EAAE,KAAK,KAAK,KAAK,GAAG,KAAK,KAAK;AAAA,UACpC,KAAK,eACH,IAAI,EAAE,IAAI,GAAG,KAAK,IAAI,eAAe,GAAG,KAAK,WAAW;AAAA,UAC1D,MAAM;AAAA,YACJ,IAAI,KAAK;AAAA,YACT,MAAM;AAAA,YACN,OAAO,KAAK;AAAA,YACZ,SAAS,CAAC,MAAW,KAAK,aAAa,MAAM,EAAE,OAAO,KAAK;AAAA,UAC7D,CAAC;AAAA,QACH;AACA;AAAA,MACF,KAAK;AACH,aAAK;AAAA,UACH,OAAO,KAAK,KAAK;AAAA,UACjB,KAAK,eAAe,IAAI,KAAK,WAAW;AAAA,UACxC;AAAA,YACE,KAAK,SAAS;AAAA,cAAI,CAAC,QACjB;AAAA,gBACE,MAAM;AAAA,kBACJ,MAAM;AAAA,kBACN,MAAM,KAAK;AAAA,kBACX,OAAO,IAAI;AAAA,kBACX,SAAS,KAAK,WAAW,IAAI;AAAA,kBAC7B,UAAU,CAAC,MAAW,KAAK,aAAa,MAAM,EAAE,OAAO,KAAK;AAAA,gBAC9D,CAAC;AAAA,gBACD,IAAI;AAAA,gBACJ,IAAI;AAAA,cACN;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA;AAAA,MACF;AACE,aAAK;AAAA,UACH,EAAE,OAAO,yCAAyC;AAAA,UAClD,UAAU,KAAK,IAAI,4BAA4B,KAAK,SAAS;AAAA,QAC/D;AAAA,IACJ;AACA,WAAO;AAAA,EACT;AACF;;;AD9IA,IAAM,EAAE,KAAK,IAAIC,KAAI;AAErB,IAAM,aAAN,MAAiB;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,YAAkC,QAA6B;AAGzE,SAAK,oBAAoB,KAAK,kBAAkB,KAAK,IAAI;AAEzD,SAAK,SAAS;AACd,SAAK,SAAS;AAEd,SAAK,eAAe,mBAAmB,YAAY,MAAM;AAEzD,UAAM,EAAE,cAAc,WAAW,IAAI,KAAK;AAAA,MACxC,KAAK;AAAA,MACL,KAAK,OAAO;AAAA,IACd;AACA,SAAK,aAAa;AAClB,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BA,0BACE,cACA,eACkE;AAClE,UAAM,SAAiB,aAAa;AACpC,UAAM,aAAkC,CAAC;AACzC,UAAM,eAA8B,OAAO,IAAI,CAAC,UAAU;AAGxD,YAAM,YAAoB,MAAM;AAKhC,YAAM,UAAU,cAAc,SAAS,KAAK,MAAM,WAAW;AAE7D,iBAAW,SAAS,IAAI;AAExB,aAAO,IAAI,YAAY,OAAO,SAAS,KAAK,iBAAiB;AAAA,IAC/D,CAAC;AACD,WAAO,EAAE,cAAc,WAAW;AAAA,EACpC;AAAA,EAEA,kBAAkB,OAAoB,OAAkB;AACtD,YAAQ,IAAI,SAAS,MAAM,IAAI,eAAe,KAAK,EAAE;AACrD,SAAK,WAAW,MAAM,IAAI,IAAI;AAC9B,UAAM,EAAE,WAAW,IAAI,KAAK,aAAa,iBAAiB,KAAK,UAAU;AACzE,YAAQ,IAAI,cAAc,UAAU;AACpC,SAAK,WAAW,QAAQ,CAAC,MAAM;AAC7B,QAAE,YAAY,EAAE,MAAM;AACtB,QAAE,QAAQ,aAAa,EAAE,IAAI,KAAK;AAAA,IACpC,CAAC;AAAA,EACH;AACF;AAEO,SAAS,OACd,eACG,UACc;AACjB,MAAI,CAAC,WAAW,QAAQ;AACtB,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AACA,MAAI,SAAS,WAAW;AACxB,MAAI,CAAC,QAAQ;AACX,aAAS,EAAE,eAAe,CAAC,GAAG,YAAY,CAAC,EAAE;AAAA,EAC/C,WAAW,CAAC,OAAO,eAAe;AAChC,WAAO,gBAAgB,CAAC;AAAA,EAC1B,WAAW,CAAC,OAAO,YAAY;AAC7B,WAAO,aAAa,CAAC;AAAA,EACvB;AACA,QAAM,aAAyB,IAAI,WAAW,WAAW,QAAQ,MAAM;AACvE,QAAM,SAAoB,WAAW,WAAW;AAAA,IAAI,CAAC,UACnD,MAAM,OAAO;AAAA,EACf;AAEA,QAAM,qBAAqB,CAAC,GAAG,QAAQ,GAAG,QAAQ;AAElD,QAAM,mBAAmB,WAAW;AACpC,QAAM,eAAe,CAAC,MAAa;AACjC,MAAE,eAAe;AACjB,WAAO,aAAa,WAAW;AAC/B,wBAAoB,iBAAiB,CAAC;AAAA,EACxC;AACA,aAAW,WAAW;AACtB,SAAO,KAAK,YAAY,GAAG,kBAAkB;AAC/C;",
|
|
6
|
+
"names": ["van", "van"]
|
|
7
|
+
}
|
package/dist/main.d.ts
CHANGED
package/dist/main.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import van from "vanjs-core";
|
|
2
|
+
import { jsform } from "./index";
|
|
3
|
+
const { div, p, h1, button } = van.tags;
|
|
4
|
+
const jsonSchemaDemo = {
|
|
5
|
+
type: "object",
|
|
6
|
+
additionalProperties: false,
|
|
7
|
+
properties: {
|
|
8
|
+
has_pet: {
|
|
9
|
+
title: "Has Pet",
|
|
10
|
+
description: "Do you have a pet?",
|
|
11
|
+
oneOf: [
|
|
12
|
+
{ title: "Yes", const: "yes" },
|
|
13
|
+
{ title: "No", const: "no" },
|
|
14
|
+
],
|
|
15
|
+
"x-jsf-presentation": { inputType: "radio" },
|
|
16
|
+
type: "string",
|
|
17
|
+
},
|
|
18
|
+
pet_name: {
|
|
19
|
+
title: "Pet's name",
|
|
20
|
+
description: "What's your pet's name?",
|
|
21
|
+
"x-jsf-presentation": { inputType: "text" },
|
|
22
|
+
type: "string",
|
|
23
|
+
},
|
|
24
|
+
pet_age: {
|
|
25
|
+
title: "Pet's age",
|
|
26
|
+
description: "What's your pet's age? With more than 5 years, we need to know more about your pet.",
|
|
27
|
+
"x-jsf-presentation": { inputType: "number" },
|
|
28
|
+
type: "number",
|
|
29
|
+
default: 1,
|
|
30
|
+
},
|
|
31
|
+
dietary_needs: {
|
|
32
|
+
title: "Dietary needs",
|
|
33
|
+
description: "What are your pet's dietary needs?",
|
|
34
|
+
"x-jsf-presentation": { inputType: "textarea", rows: 15, columns: 50 },
|
|
35
|
+
type: "string",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
required: ["has_pet"],
|
|
39
|
+
"x-jsf-order": ["has_pet", "pet_name", "pet_age", "dietary_needs"],
|
|
40
|
+
allOf: [
|
|
41
|
+
{
|
|
42
|
+
if: { properties: { has_pet: { const: "yes" } }, required: ["has_pet"] },
|
|
43
|
+
then: { required: ["pet_age", "pet_name"] },
|
|
44
|
+
else: { properties: { pet_age: false, pet_name: false } },
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
if: {
|
|
48
|
+
properties: { has_pet: { const: "yes" }, pet_age: { minimum: 5 } },
|
|
49
|
+
required: ["pet_age"],
|
|
50
|
+
},
|
|
51
|
+
then: { required: ["dietary_needs"] },
|
|
52
|
+
else: { properties: { dietary_needs: false } },
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
// App
|
|
57
|
+
const App = () => {
|
|
58
|
+
const initialValues = { pet_name: "Simon" };
|
|
59
|
+
const jsfConfig = {
|
|
60
|
+
strictInputType: false,
|
|
61
|
+
initialValues: initialValues,
|
|
62
|
+
formValues: initialValues,
|
|
63
|
+
};
|
|
64
|
+
const handleOnSubmit = (e) => {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
const values = jsfConfig.formValues;
|
|
67
|
+
alert(`Submitted successfully: ${JSON.stringify(values, null, 2)}`);
|
|
68
|
+
console.log("Submitted!", values);
|
|
69
|
+
};
|
|
70
|
+
return div(h1("json-schema-form + VanJS"), p("This demo uses VanJS without any other form library."), jsform({
|
|
71
|
+
name: "my-jsf-form",
|
|
72
|
+
schema: jsonSchemaDemo,
|
|
73
|
+
config: jsfConfig,
|
|
74
|
+
onsubmit: handleOnSubmit,
|
|
75
|
+
}, button({ type: "submit" }, "Submit")));
|
|
76
|
+
};
|
|
77
|
+
// Render the app
|
|
78
|
+
van.add(document.body, App());
|
package/package.json
CHANGED
|
@@ -1,36 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanjs-jsf",
|
|
3
3
|
"description": "A JSON Schema Form UI Library for VanJS",
|
|
4
|
-
"keywords": [
|
|
5
|
-
|
|
4
|
+
"keywords": [
|
|
5
|
+
"vanjs",
|
|
6
|
+
"json",
|
|
7
|
+
"schema",
|
|
8
|
+
"form",
|
|
9
|
+
"ui-library"
|
|
10
|
+
],
|
|
11
|
+
"version": "0.0.7",
|
|
6
12
|
"author": {
|
|
7
13
|
"name": "Carlos Prados",
|
|
8
14
|
"email": "carlos.prados@gmail.com"
|
|
9
15
|
},
|
|
10
16
|
"license": "Apache-2.0",
|
|
11
17
|
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"module": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
12
21
|
"type": "module",
|
|
13
|
-
"files": [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
|
|
17
27
|
"scripts": {
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"tsc": "tsc",
|
|
22
|
-
"preview": "vite preview"
|
|
28
|
+
"build": "node build.js",
|
|
29
|
+
"types": "tsc",
|
|
30
|
+
"dev": "node build.js --watch & vite"
|
|
23
31
|
},
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"ts-jest": "^29.2.5",
|
|
28
|
-
"typescript": "^5.7.2",
|
|
29
|
-
"vite": "^6.0.3"
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"esbuild": "^0.24.2",
|
|
34
|
+
"typescript": "^5.7.3"
|
|
30
35
|
},
|
|
31
36
|
"dependencies": {
|
|
32
|
-
"@remoteoss/json-schema-form": "^0.11.
|
|
33
|
-
"vanjs-core": "^1.5.
|
|
34
|
-
"vanjs-ext": "^0.6.
|
|
37
|
+
"@remoteoss/json-schema-form": "^0.11.9-beta.0",
|
|
38
|
+
"vanjs-core": "^1.5.3",
|
|
39
|
+
"vanjs-ext": "^0.6.2"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"vite": "^6.0.9"
|
|
35
43
|
}
|
|
36
44
|
}
|
package/dist/JsfUtils.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"JsfUtils.d.ts","sourceRoot":"","sources":["../lib/JsfUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAErD,qBAAa,QAAQ;IACnB,MAAM,CAAC,iBAAiB,CACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAQlC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VanJSComponent.d.ts","sourceRoot":"","sources":["../lib/VanJSComponent.ts"],"names":[],"mappings":"AAAA,8BAAsB,cAAc;IAClC,QAAQ,CAAC,MAAM,IAAI,OAAO;CAC3B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VanJsfField.d.ts","sourceRoot":"","sources":["../lib/VanJsfField.ts"],"names":[],"mappings":"AAAA,OAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAWlD,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAElD,qBAAa,WAAY,SAAQ,cAAc;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7D,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;gBAGxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,KAAK,IAAI;IAc9D,IAAI,SAAS,IAAI,MAAM,CAEtB;IACD,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,WAAW,IAAI,MAAM,CAExB;IACD,IAAI,OAAO,IAAI,MAAM,EAAE,CAEtB;IACD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAEzB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,GAAG,EAAE,MAAM,EAEpB;IAED,MAAM,IAAI,OAAO;CAgFlB"}
|
package/dist/VanJsfForm.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VanJsfForm.d.ts","sourceRoot":"","sources":["../lib/VanJsfForm.ts"],"names":[],"mappings":"AAmGA,wBAAgB,MAAM,CACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,GAAG,QAAQ,EAAE,GAAG,EAAE,GACjB,eAAe,CA2BjB"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/main.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../lib/main.ts"],"names":[],"mappings":""}
|
package/dist/vanjs-jsf.js
DELETED
|
@@ -1,267 +0,0 @@
|
|
|
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());
|
package/dist/vanjs-jsf.umd.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
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())});
|