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.
@@ -2,4 +2,3 @@ import { Fields } from "@remoteoss/json-schema-form";
2
2
  export declare class JsfUtils {
3
3
  static getJsfFieldByName(fields: Fields, name: string): Record<string, unknown> | null;
4
4
  }
5
- //# sourceMappingURL=JsfUtils.d.ts.map
@@ -0,0 +1,10 @@
1
+ export class JsfUtils {
2
+ static getJsfFieldByName(fields, name) {
3
+ for (const field of fields) {
4
+ if (typeof field["name"] === "string" && field["name"] === name) {
5
+ return field;
6
+ }
7
+ }
8
+ return null;
9
+ }
10
+ }
@@ -1,4 +1,3 @@
1
1
  export declare abstract class VanJSComponent {
2
2
  abstract render(): Element;
3
3
  }
4
- //# sourceMappingURL=VanJSComponent.d.ts.map
@@ -0,0 +1,2 @@
1
+ export class VanJSComponent {
2
+ }
@@ -24,4 +24,3 @@ export declare class VanJsfField extends VanJSComponent {
24
24
  set error(val: string);
25
25
  render(): Element;
26
26
  }
27
- //# sourceMappingURL=VanJsfField.d.ts.map
@@ -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
+ }
@@ -1,2 +1 @@
1
1
  export declare function jsform(attributes: Record<string, any>, ...children: any[]): HTMLFormElement;
2
- //# sourceMappingURL=VanJsfForm.d.ts.map
@@ -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
@@ -1,3 +1 @@
1
- import { jsform } from "./VanJsfForm";
2
- export { jsform };
3
- //# sourceMappingURL=index.d.ts.map
1
+ export { jsform } from "./VanJsfForm";
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": "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",
6
+ "names": ["van", "van"]
7
+ }
package/dist/main.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=main.d.ts.map
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": ["vanjs", "json", "schema", "form", "ui-library"],
5
- "version": "0.0.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": [ "dist", "README.md" ],
14
- "main": "./dist/vanjs-jsf.umd.cjs",
15
- "module": "./dist/vanjs-jsf.js",
16
-
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+
17
27
  "scripts": {
18
- "dev": "vite",
19
- "test": "jest",
20
- "build": "tsc && vite build && tsc",
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
- "devDependencies": {
25
- "@types/jest": "^29.5.14",
26
- "jest": "^29.7.0",
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.8-beta.0",
33
- "vanjs-core": "^1.5.2",
34
- "vanjs-ext": "^0.6.1"
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
  }
@@ -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"}
@@ -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"}
@@ -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"}
@@ -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());
@@ -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())});