@vaadin/hilla-react-form 24.7.0-alpha9 → 24.7.0-beta1

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/index.d.ts CHANGED
@@ -1,53 +1,52 @@
1
- import { type AbstractModel, type BinderConfiguration, type DetachedModelConstructor, type Validator, type Value, type ValueError, type ArrayModel, type ArrayItemModel } from '@vaadin/hilla-lit-form';
1
+ import { type AbstractModel, type BinderConfiguration, type DetachedModelConstructor, type Validator, type Value, type ValueError, type ArrayModel, type ArrayItemModel } from "@vaadin/hilla-lit-form";
2
2
  export type FieldDirectiveResult = Readonly<{
3
- name: string;
4
- onBlur(): void;
5
- onChange(): void;
6
- onInput(): void;
7
- ref(element: HTMLElement | null): void;
3
+ name: string
4
+ onBlur(): void
5
+ onChange(): void
6
+ onInput(): void
7
+ ref(element: HTMLElement | null): void
8
8
  }>;
9
9
  export type FieldDirective = (model: AbstractModel) => FieldDirectiveResult;
10
10
  export type UseFormPartResult<M extends AbstractModel> = Readonly<{
11
- defaultValue?: Value<M>;
12
- dirty: boolean;
13
- errors: readonly ValueError[];
14
- invalid: boolean;
15
- model: M;
16
- name: string;
17
- field: FieldDirective;
18
- ownErrors: ReadonlyArray<ValueError<Value<M>>>;
19
- required: boolean;
20
- validators: ReadonlyArray<Validator<Value<M>>>;
21
- value?: Value<M>;
22
- visited: boolean;
23
- addValidator(validator: Validator<Value<M>>): void;
24
- setValidators(validators: ReadonlyArray<Validator<Value<M>>>): void;
25
- setValue(value: Value<M> | undefined): void;
26
- setVisited(visited: boolean): void;
27
- validate(): Promise<readonly ValueError[]>;
11
+ defaultValue?: Value<M>
12
+ dirty: boolean
13
+ errors: readonly ValueError[]
14
+ invalid: boolean
15
+ model: M
16
+ name: string
17
+ field: FieldDirective
18
+ ownErrors: ReadonlyArray<ValueError<Value<M>>>
19
+ required: boolean
20
+ validators: ReadonlyArray<Validator<Value<M>>>
21
+ value?: Value<M>
22
+ visited: boolean
23
+ addValidator(validator: Validator<Value<M>>): void
24
+ setValidators(validators: ReadonlyArray<Validator<Value<M>>>): void
25
+ setValue(value: Value<M> | undefined): void
26
+ setVisited(visited: boolean): void
27
+ validate(): Promise<readonly ValueError[]>
28
28
  }>;
29
- export type UseFormResult<M extends AbstractModel> = Omit<UseFormPartResult<M>, 'setValue' | 'value'> & Readonly<{
30
- value: Value<M>;
31
- submitting: boolean;
32
- setDefaultValue(value: Value<M>): void;
33
- setValue(value: Value<M>): void;
34
- submit(): Promise<Value<M> | undefined | void>;
35
- reset(): void;
36
- clear(): void;
37
- read(value: Value<M> | null | undefined): void;
38
- update(): void;
29
+ export type UseFormResult<M extends AbstractModel> = Omit<UseFormPartResult<M>, "setValue" | "value"> & Readonly<{
30
+ value: Value<M>
31
+ submitting: boolean
32
+ setDefaultValue(value: Value<M>): void
33
+ setValue(value: Value<M>): void
34
+ submit(): Promise<Value<M> | undefined | void>
35
+ reset(): void
36
+ clear(): void
37
+ read(value: Value<M> | null | undefined): void
38
+ update(): void
39
39
  }>;
40
- export type UseFormArrayPartResult<M extends ArrayModel> = Omit<UseFormPartResult<M>, 'field'> & {
41
- items: ReadonlyArray<ArrayItemModel<M>>;
40
+ export type UseFormArrayPartResult<M extends ArrayModel> = Omit<UseFormPartResult<M>, "field"> & {
41
+ items: ReadonlyArray<ArrayItemModel<M>>
42
42
  };
43
43
  export declare function useForm<M extends AbstractModel>(Model: DetachedModelConstructor<M>, config?: BinderConfiguration<Value<M>>): UseFormResult<M>;
44
44
  export declare function useFormPart<M extends AbstractModel>(model: M): UseFormPartResult<M>;
45
45
  /**
46
- * Hook to access an array model part of a form. It provides the same API as `useFormPart`,
47
- * but adds an `items` property that allows to iterate over the items in form of an array of models.
48
- *
49
- * @param model - The array model to access
50
- * @returns The array model part of the form
51
- */
46
+ * Hook to access an array model part of a form. It provides the same API as `useFormPart`,
47
+ * but adds an `items` property that allows to iterate over the items in form of an array of models.
48
+ *
49
+ * @param model - The array model to access
50
+ * @returns The array model part of the form
51
+ */
52
52
  export declare function useFormArrayPart<M extends ArrayModel>(model: M): UseFormArrayPartResult<M>;
53
- //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,202 +1,192 @@
1
- function __REGISTER__(feature, vaadinObj = window.Vaadin ??= {}) {
2
- vaadinObj.registrations ??= [];
3
- vaadinObj.registrations.push({
4
- is: feature ? `${"@vaadin/hilla-react-form"}/${feature}` : "@vaadin/hilla-react-form",
5
- version: "24.7.0-alpha9"
6
- });
7
- }
8
- import {
9
- _fromString,
10
- _validity,
11
- BinderRoot,
12
- CHANGED,
13
- getBinderNode,
14
- getDefaultFieldStrategy,
15
- hasFromString,
16
- isFieldElement
17
- } from "@vaadin/hilla-lit-form";
1
+ import { _fromString, _validity, BinderRoot, CHANGED, getBinderNode, getDefaultFieldStrategy, hasFromString, isFieldElement } from "@vaadin/hilla-lit-form";
18
2
  import { useEffect, useMemo, useReducer, useRef } from "react";
19
- __REGISTER__();
3
+ ((feature, vaadinObj = window.Vaadin ??= {}) => {
4
+ vaadinObj.registrations ??= [];
5
+ vaadinObj.registrations.push({
6
+ is: feature ? `@vaadin/hilla-react-form/${feature}` : "@vaadin/hilla-react-form",
7
+ version: "24.7.0-beta1"
8
+ });
9
+ })();
20
10
  let isRendering = false;
21
11
  function useUpdate() {
22
- const [_, count] = useReducer((x) => x + 1, 0);
23
- return () => {
24
- if (isRendering) {
25
- return;
26
- }
27
- count();
28
- };
12
+ const [_, count] = useReducer((x) => x + 1, 0);
13
+ return () => {
14
+ if (isRendering) {
15
+ return;
16
+ }
17
+ count();
18
+ };
29
19
  }
30
20
  function convertFieldValue(model, fieldValue) {
31
- return typeof fieldValue === "string" && hasFromString(model) ? model[_fromString](fieldValue) : fieldValue;
21
+ return typeof fieldValue === "string" && hasFromString(model) ? model[_fromString](fieldValue) : fieldValue;
32
22
  }
33
23
  function getFormPart(node) {
34
- return {
35
- addValidator: node.addValidator.bind(node),
36
- get defaultValue() {
37
- return node.defaultValue;
38
- },
39
- dirty: node.dirty,
40
- errors: node.errors,
41
- invalid: node.invalid,
42
- model: node.model,
43
- name: node.name,
44
- ownErrors: node.ownErrors,
45
- required: node.required,
46
- setValidators(validators) {
47
- node.validators = validators;
48
- },
49
- setValue(value) {
50
- node.value = value;
51
- },
52
- setVisited(visited) {
53
- node.visited = visited;
54
- },
55
- validate: node.validate.bind(node),
56
- validators: node.validators,
57
- get value() {
58
- return node.value;
59
- },
60
- visited: node.visited
61
- };
24
+ return {
25
+ addValidator: node.addValidator.bind(node),
26
+ get defaultValue() {
27
+ return node.defaultValue;
28
+ },
29
+ dirty: node.dirty,
30
+ errors: node.errors,
31
+ invalid: node.invalid,
32
+ model: node.model,
33
+ name: node.name,
34
+ ownErrors: node.ownErrors,
35
+ required: node.required,
36
+ setValidators(validators) {
37
+ node.validators = validators;
38
+ },
39
+ setValue(value) {
40
+ node.value = value;
41
+ },
42
+ setVisited(visited) {
43
+ node.visited = visited;
44
+ },
45
+ validate: node.validate.bind(node),
46
+ validators: node.validators,
47
+ get value() {
48
+ return node.value;
49
+ },
50
+ visited: node.visited
51
+ };
62
52
  }
63
53
  function useFields(node) {
64
- const update = useUpdate();
65
- return useMemo(() => {
66
- const registry = /* @__PURE__ */ new WeakMap();
67
- return (model) => {
68
- isRendering = true;
69
- const n = getBinderNode(model);
70
- let fieldState = registry.get(model);
71
- if (!fieldState) {
72
- fieldState = {
73
- changeHandler() {
74
- fieldState.inputHandler();
75
- n.validate().catch(() => {
76
- });
77
- },
78
- element: void 0,
79
- errorMessage: "",
80
- inputHandler() {
81
- if (fieldState.strategy) {
82
- fieldState.strategy.invalid = false;
83
- fieldState.strategy.checkValidity();
84
- n[_validity] = fieldState.strategy.validity;
85
- n.value = convertFieldValue(model, fieldState.strategy.value);
86
- }
87
- },
88
- invalid: false,
89
- blurHandler() {
90
- fieldState.inputHandler();
91
- n.validate().catch(() => {
92
- });
93
- n.visited = true;
94
- },
95
- ref(element) {
96
- if (!element) {
97
- fieldState.element?.removeEventListener("blur", fieldState.blurHandler);
98
- fieldState.strategy?.removeEventListeners();
99
- fieldState.element = void 0;
100
- fieldState.strategy = void 0;
101
- update();
102
- return;
103
- }
104
- if (!isFieldElement(element)) {
105
- throw new TypeError(`Element '${element.localName}' is not a form element`);
106
- }
107
- if (fieldState.element !== element) {
108
- fieldState.element = element;
109
- fieldState.element.addEventListener("blur", fieldState.blurHandler);
110
- fieldState.strategy = getDefaultFieldStrategy(element, model);
111
- fieldState.strategy.onInput = fieldState.inputHandler;
112
- fieldState.strategy.onChange = fieldState.changeHandler;
113
- update();
114
- }
115
- },
116
- required: false,
117
- strategy: void 0
118
- };
119
- registry.set(model, fieldState);
120
- }
121
- if (fieldState.strategy) {
122
- const valueFromField = convertFieldValue(model, fieldState.strategy.value);
123
- if (valueFromField !== n.value && !(Number.isNaN(n.value) && Number.isNaN(valueFromField))) {
124
- fieldState.strategy.value = Number.isNaN(n.value) ? "" : n.value;
125
- }
126
- if (fieldState.required !== n.required) {
127
- fieldState.required = n.required;
128
- fieldState.strategy.required = n.required;
129
- }
130
- const firstError = n.ownErrors.at(0);
131
- const errorMessage = firstError?.message ?? "";
132
- if (fieldState.errorMessage !== errorMessage) {
133
- fieldState.errorMessage = errorMessage;
134
- fieldState.strategy.errorMessage = errorMessage;
135
- }
136
- fieldState.invalid = n.invalid;
137
- fieldState.strategy.invalid = n.invalid;
138
- }
139
- isRendering = false;
140
- return {
141
- name: n.name,
142
- ref: fieldState.ref
143
- };
144
- };
145
- }, [node]);
54
+ const update = useUpdate();
55
+ return useMemo(() => {
56
+ const registry = new WeakMap();
57
+ return (model) => {
58
+ isRendering = true;
59
+ const n = getBinderNode(model);
60
+ let fieldState = registry.get(model);
61
+ if (!fieldState) {
62
+ fieldState = {
63
+ changeHandler() {
64
+ fieldState.inputHandler();
65
+ n.validate().catch(() => {});
66
+ },
67
+ element: undefined,
68
+ errorMessage: "",
69
+ inputHandler() {
70
+ if (fieldState.strategy) {
71
+ fieldState.strategy.invalid = false;
72
+ fieldState.strategy.checkValidity();
73
+ n[_validity] = fieldState.strategy.validity;
74
+ n.value = convertFieldValue(model, fieldState.strategy.value);
75
+ }
76
+ },
77
+ invalid: false,
78
+ blurHandler() {
79
+ fieldState.inputHandler();
80
+ n.validate().catch(() => {});
81
+ n.visited = true;
82
+ },
83
+ ref(element) {
84
+ if (!element) {
85
+ fieldState.element?.removeEventListener("blur", fieldState.blurHandler);
86
+ fieldState.strategy?.removeEventListeners();
87
+ fieldState.element = undefined;
88
+ fieldState.strategy = undefined;
89
+ update();
90
+ return;
91
+ }
92
+ if (!isFieldElement(element)) {
93
+ throw new TypeError(`Element '${element.localName}' is not a form element`);
94
+ }
95
+ if (fieldState.element !== element) {
96
+ fieldState.element = element;
97
+ fieldState.element.addEventListener("blur", fieldState.blurHandler);
98
+ fieldState.strategy = getDefaultFieldStrategy(element, model);
99
+ fieldState.strategy.onInput = fieldState.inputHandler;
100
+ fieldState.strategy.onChange = fieldState.changeHandler;
101
+ update();
102
+ }
103
+ },
104
+ required: false,
105
+ strategy: undefined
106
+ };
107
+ registry.set(model, fieldState);
108
+ }
109
+ if (fieldState.strategy) {
110
+ const valueFromField = convertFieldValue(model, fieldState.strategy.value);
111
+ if (valueFromField !== n.value && !(Number.isNaN(n.value) && Number.isNaN(valueFromField))) {
112
+ fieldState.strategy.value = Number.isNaN(n.value) ? "" : n.value;
113
+ }
114
+ if (fieldState.required !== n.required) {
115
+ fieldState.required = n.required;
116
+ fieldState.strategy.required = n.required;
117
+ }
118
+ const firstError = n.ownErrors.at(0);
119
+ const errorMessage = firstError?.message ?? "";
120
+ if (fieldState.errorMessage !== errorMessage) {
121
+ fieldState.errorMessage = errorMessage;
122
+ fieldState.strategy.errorMessage = errorMessage;
123
+ }
124
+ fieldState.invalid = n.invalid;
125
+ fieldState.strategy.invalid = n.invalid;
126
+ }
127
+ isRendering = false;
128
+ return {
129
+ name: n.name,
130
+ ref: fieldState.ref
131
+ };
132
+ };
133
+ }, [node]);
146
134
  }
147
- function useForm(Model, config) {
148
- const configRef = useRef({});
149
- configRef.current.onSubmit = config?.onSubmit;
150
- configRef.current.onChange = config?.onChange;
151
- const update = useUpdate();
152
- const binder = useMemo(() => new BinderRoot(Model, configRef.current), [Model]);
153
- const field = useFields(binder);
154
- const clear = binder.clear.bind(binder);
155
- useEffect(() => {
156
- binder.addEventListener(CHANGED.type, update);
157
- clear();
158
- return () => binder.removeEventListener(CHANGED.type, update);
159
- }, [binder]);
160
- return {
161
- ...getFormPart(binder),
162
- clear,
163
- field,
164
- read: binder.read.bind(binder),
165
- reset: binder.reset.bind(binder),
166
- setDefaultValue(defaultValue) {
167
- binder.defaultValue = defaultValue;
168
- },
169
- setValue(value) {
170
- binder.value = value;
171
- },
172
- submit: binder.submit.bind(binder),
173
- value: binder.value,
174
- submitting: binder.submitting,
175
- update
176
- };
135
+ export function useForm(Model, config) {
136
+ const configRef = useRef({});
137
+ configRef.current.onSubmit = config?.onSubmit;
138
+ configRef.current.onChange = config?.onChange;
139
+ const update = useUpdate();
140
+ const binder = useMemo(() => new BinderRoot(Model, configRef.current), [Model]);
141
+ const field = useFields(binder);
142
+ const clear = binder.clear.bind(binder);
143
+ useEffect(() => {
144
+ binder.addEventListener(CHANGED.type, update);
145
+ clear();
146
+ return () => binder.removeEventListener(CHANGED.type, update);
147
+ }, [binder]);
148
+ return {
149
+ ...getFormPart(binder),
150
+ clear,
151
+ field,
152
+ read: binder.read.bind(binder),
153
+ reset: binder.reset.bind(binder),
154
+ setDefaultValue(defaultValue) {
155
+ binder.defaultValue = defaultValue;
156
+ },
157
+ setValue(value) {
158
+ binder.value = value;
159
+ },
160
+ submit: binder.submit.bind(binder),
161
+ value: binder.value,
162
+ submitting: binder.submitting,
163
+ update
164
+ };
177
165
  }
178
- function useFormPart(model) {
179
- isRendering = true;
180
- const binderNode = getBinderNode(model);
181
- const field = useFields(binderNode);
182
- isRendering = false;
183
- return {
184
- ...getFormPart(binderNode),
185
- field
186
- };
166
+ export function useFormPart(model) {
167
+ isRendering = true;
168
+ const binderNode = getBinderNode(model);
169
+ const field = useFields(binderNode);
170
+ isRendering = false;
171
+ return {
172
+ ...getFormPart(binderNode),
173
+ field
174
+ };
187
175
  }
188
- function useFormArrayPart(model) {
189
- isRendering = true;
190
- const binderNode = getBinderNode(model);
191
- isRendering = false;
192
- return {
193
- ...getFormPart(binderNode),
194
- items: Array.from(model, (item) => item.model)
195
- };
176
+ /**
177
+ * Hook to access an array model part of a form. It provides the same API as `useFormPart`,
178
+ * but adds an `items` property that allows to iterate over the items in form of an array of models.
179
+ *
180
+ * @param model - The array model to access
181
+ * @returns The array model part of the form
182
+ */
183
+ export function useFormArrayPart(model) {
184
+ isRendering = true;
185
+ const binderNode = getBinderNode(model);
186
+ isRendering = false;
187
+ return {
188
+ ...getFormPart(binderNode),
189
+ items: Array.from(model, (item) => item.model)
190
+ };
196
191
  }
197
- export {
198
- useForm,
199
- useFormArrayPart,
200
- useFormPart
201
- };
202
- //# sourceMappingURL=index.js.map
192
+ //# sourceMappingURL=./index.js.map
package/index.js.map CHANGED
@@ -1,7 +1 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../scripts/register.js", "src/index.ts"],
4
- "sourcesContent": ["export function __REGISTER__(feature, vaadinObj = (window.Vaadin ??= {})) {\n vaadinObj.registrations ??= [];\n vaadinObj.registrations.push({\n is: feature ? `${__NAME__}/${feature}` : __NAME__,\n version: __VERSION__,\n });\n}\n", "/* eslint-disable @typescript-eslint/unbound-method */\nimport {\n _fromString,\n _validity,\n type AbstractModel,\n type BinderConfiguration,\n type BinderNode,\n BinderRoot,\n CHANGED,\n type DetachedModelConstructor,\n type FieldStrategy,\n getBinderNode,\n getDefaultFieldStrategy,\n hasFromString,\n isFieldElement,\n type Validator,\n type Value,\n type ValueError,\n type ArrayModel,\n type ArrayItemModel,\n} from '@vaadin/hilla-lit-form';\nimport { useEffect, useMemo, useReducer, useRef } from 'react';\nimport type { Writable } from 'type-fest';\n\n// @ts-expect-error: esbuild injection\n// eslint-disable-next-line @typescript-eslint/no-unsafe-call\n__REGISTER__();\n\nlet isRendering = false;\n\nfunction useUpdate() {\n const [_, count] = useReducer((x: number) => x + 1, 0);\n return () => {\n if (isRendering) {\n return;\n }\n count();\n };\n}\n\nexport type FieldDirectiveResult = Readonly<{\n name: string;\n onBlur(): void;\n onChange(): void;\n onInput(): void;\n ref(element: HTMLElement | null): void;\n}>;\n\nexport type FieldDirective = (model: AbstractModel) => FieldDirectiveResult;\n\nexport type UseFormPartResult<M extends AbstractModel> = Readonly<{\n defaultValue?: Value<M>;\n dirty: boolean;\n errors: readonly ValueError[];\n invalid: boolean;\n model: M;\n name: string;\n field: FieldDirective;\n ownErrors: ReadonlyArray<ValueError<Value<M>>>;\n required: boolean;\n validators: ReadonlyArray<Validator<Value<M>>>;\n value?: Value<M>;\n visited: boolean;\n addValidator(validator: Validator<Value<M>>): void;\n setValidators(validators: ReadonlyArray<Validator<Value<M>>>): void;\n setValue(value: Value<M> | undefined): void;\n setVisited(visited: boolean): void;\n validate(): Promise<readonly ValueError[]>;\n}>;\n\nexport type UseFormResult<M extends AbstractModel> = Omit<UseFormPartResult<M>, 'setValue' | 'value'> &\n Readonly<{\n value: Value<M>;\n submitting: boolean;\n setDefaultValue(value: Value<M>): void;\n setValue(value: Value<M>): void;\n submit(): Promise<Value<M> | undefined | void>;\n reset(): void;\n clear(): void;\n read(value: Value<M> | null | undefined): void;\n update(): void;\n }>;\n\nexport type UseFormArrayPartResult<M extends ArrayModel> = Omit<UseFormPartResult<M>, 'field'> & {\n items: ReadonlyArray<ArrayItemModel<M>>;\n};\n\ntype FieldState<T = unknown> = {\n required: boolean;\n invalid: boolean;\n errorMessage: string;\n strategy?: FieldStrategy<T>;\n element?: HTMLElement;\n inputHandler(): void;\n changeHandler(): void;\n blurHandler(): void;\n ref(element: HTMLElement | null): void;\n};\n\nfunction convertFieldValue<T extends AbstractModel>(model: T, fieldValue: unknown) {\n return typeof fieldValue === 'string' && hasFromString(model) ? model[_fromString](fieldValue) : fieldValue;\n}\n\nfunction getFormPart<M extends AbstractModel>(node: BinderNode<M>): Omit<UseFormPartResult<M>, 'field'> {\n return {\n addValidator: node.addValidator.bind(node),\n get defaultValue() {\n return node.defaultValue;\n },\n dirty: node.dirty,\n errors: node.errors,\n invalid: node.invalid,\n model: node.model,\n name: node.name,\n ownErrors: node.ownErrors,\n required: node.required,\n setValidators(validators) {\n node.validators = validators;\n },\n setValue(value) {\n node.value = value;\n },\n setVisited(visited: boolean) {\n node.visited = visited;\n },\n validate: node.validate.bind(node),\n validators: node.validators,\n get value() {\n return node.value;\n },\n visited: node.visited,\n };\n}\n\nfunction useFields<M extends AbstractModel>(node: BinderNode<M>): FieldDirective {\n const update = useUpdate();\n\n return useMemo(() => {\n const registry = new WeakMap<AbstractModel, FieldState>();\n\n return ((model: AbstractModel) => {\n isRendering = true;\n const n = getBinderNode(model);\n\n let fieldState = registry.get(model);\n\n if (!fieldState) {\n fieldState = {\n changeHandler() {\n fieldState!.inputHandler();\n n.validate().catch(() => {});\n },\n element: undefined,\n errorMessage: '',\n inputHandler() {\n if (fieldState!.strategy) {\n // Remove invalid flag, so that .checkValidity() in Vaadin Components\n // does not interfere with errors from Hilla.\n fieldState!.strategy.invalid = false;\n // When bad input is detected, skip reading new value in binder state\n fieldState!.strategy.checkValidity();\n n[_validity] = fieldState!.strategy.validity;\n n.value = convertFieldValue(model, fieldState!.strategy.value);\n }\n },\n invalid: false,\n blurHandler() {\n fieldState!.inputHandler();\n n.validate().catch(() => {});\n n.visited = true;\n },\n ref(element: HTMLElement | null) {\n if (!element) {\n fieldState!.element?.removeEventListener('blur', fieldState!.blurHandler);\n fieldState!.strategy?.removeEventListeners();\n fieldState!.element = undefined;\n fieldState!.strategy = undefined;\n update();\n return;\n }\n\n if (!isFieldElement(element)) {\n throw new TypeError(`Element '${element.localName}' is not a form element`);\n }\n\n if (fieldState!.element !== element) {\n fieldState!.element = element;\n fieldState!.element.addEventListener('blur', fieldState!.blurHandler);\n fieldState!.strategy = getDefaultFieldStrategy(element, model);\n fieldState!.strategy.onInput = fieldState!.inputHandler;\n fieldState!.strategy.onChange = fieldState!.changeHandler;\n update();\n }\n },\n required: false,\n strategy: undefined,\n };\n\n registry.set(model, fieldState);\n }\n\n if (fieldState.strategy) {\n const valueFromField = convertFieldValue(model, fieldState.strategy.value);\n if (valueFromField !== n.value && !(Number.isNaN(n.value) && Number.isNaN(valueFromField))) {\n fieldState.strategy.value = Number.isNaN(n.value) ? '' : n.value;\n }\n\n if (fieldState.required !== n.required) {\n fieldState.required = n.required;\n fieldState.strategy.required = n.required;\n }\n\n const firstError = n.ownErrors.at(0);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const errorMessage = firstError?.message ?? '';\n if (fieldState.errorMessage !== errorMessage) {\n fieldState.errorMessage = errorMessage;\n fieldState.strategy.errorMessage = errorMessage;\n }\n\n // Make sure invalid state is always in sync\n fieldState.invalid = n.invalid;\n fieldState.strategy.invalid = n.invalid;\n }\n\n isRendering = false;\n return {\n name: n.name,\n ref: fieldState.ref,\n };\n }) as FieldDirective;\n }, [node]);\n}\n\nexport function useForm<M extends AbstractModel>(\n Model: DetachedModelConstructor<M>,\n config?: BinderConfiguration<Value<M>>,\n): UseFormResult<M> {\n const configRef = useRef<Writable<BinderConfiguration<Value<M>>>>({});\n configRef.current.onSubmit = config?.onSubmit;\n configRef.current.onChange = config?.onChange;\n const update = useUpdate();\n const binder = useMemo(() => new BinderRoot(Model, configRef.current), [Model]);\n const field = useFields(binder);\n const clear = binder.clear.bind(binder);\n\n useEffect(() => {\n binder.addEventListener(CHANGED.type, update);\n clear(); // this allows to initialize the validation strategies (issue 2282)\n return () => binder.removeEventListener(CHANGED.type, update);\n }, [binder]);\n\n return {\n ...getFormPart(binder),\n clear,\n field,\n read: binder.read.bind(binder),\n reset: binder.reset.bind(binder),\n setDefaultValue(defaultValue) {\n binder.defaultValue = defaultValue;\n },\n setValue(value) {\n binder.value = value;\n },\n submit: binder.submit.bind(binder),\n value: binder.value,\n submitting: binder.submitting,\n update,\n };\n}\n\nexport function useFormPart<M extends AbstractModel>(model: M): UseFormPartResult<M> {\n isRendering = true;\n const binderNode = getBinderNode(model);\n const field = useFields(binderNode);\n isRendering = false;\n\n return {\n ...getFormPart(binderNode),\n field,\n };\n}\n\n/**\n * Hook to access an array model part of a form. It provides the same API as `useFormPart`,\n * but adds an `items` property that allows to iterate over the items in form of an array of models.\n *\n * @param model - The array model to access\n * @returns The array model part of the form\n */\nexport function useFormArrayPart<M extends ArrayModel>(model: M): UseFormArrayPartResult<M> {\n isRendering = true;\n const binderNode = getBinderNode(model);\n isRendering = false;\n return {\n ...getFormPart(binderNode),\n items: Array.from(model, (item) => item.model as ArrayItemModel<M>),\n };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
1
+ {"mappings":"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","names":["x: number","model: T","fieldValue: unknown","node: BinderNode<M>","visited: boolean","model: AbstractModel","element: HTMLElement | null","Model: DetachedModelConstructor<M>","config?: BinderConfiguration<Value<M>>","model: M"],"sources":["/opt/agent/work/1af72d8adc613024/hilla/packages/ts/react-form/src/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport {\n _fromString,\n _validity,\n type AbstractModel,\n type BinderConfiguration,\n type BinderNode,\n BinderRoot,\n CHANGED,\n type DetachedModelConstructor,\n type FieldStrategy,\n getBinderNode,\n getDefaultFieldStrategy,\n hasFromString,\n isFieldElement,\n type Validator,\n type Value,\n type ValueError,\n type ArrayModel,\n type ArrayItemModel,\n} from '@vaadin/hilla-lit-form';\nimport { useEffect, useMemo, useReducer, useRef } from 'react';\nimport type { Writable } from 'type-fest';\n\n// @ts-expect-error: esbuild injection\n// eslint-disable-next-line @typescript-eslint/no-unsafe-call\n((feature, vaadinObj = (window.Vaadin ??= {})) => {\n vaadinObj.registrations ??= [];\n vaadinObj.registrations.push({\n is: feature ? `@vaadin/hilla-react-form/${feature}` : '@vaadin/hilla-react-form',\n version: '24.7.0-beta1',\n });\n})();\n\nlet isRendering = false;\n\nfunction useUpdate() {\n const [_, count] = useReducer((x: number) => x + 1, 0);\n return () => {\n if (isRendering) {\n return;\n }\n count();\n };\n}\n\nexport type FieldDirectiveResult = Readonly<{\n name: string;\n onBlur(): void;\n onChange(): void;\n onInput(): void;\n ref(element: HTMLElement | null): void;\n}>;\n\nexport type FieldDirective = (model: AbstractModel) => FieldDirectiveResult;\n\nexport type UseFormPartResult<M extends AbstractModel> = Readonly<{\n defaultValue?: Value<M>;\n dirty: boolean;\n errors: readonly ValueError[];\n invalid: boolean;\n model: M;\n name: string;\n field: FieldDirective;\n ownErrors: ReadonlyArray<ValueError<Value<M>>>;\n required: boolean;\n validators: ReadonlyArray<Validator<Value<M>>>;\n value?: Value<M>;\n visited: boolean;\n addValidator(validator: Validator<Value<M>>): void;\n setValidators(validators: ReadonlyArray<Validator<Value<M>>>): void;\n setValue(value: Value<M> | undefined): void;\n setVisited(visited: boolean): void;\n validate(): Promise<readonly ValueError[]>;\n}>;\n\nexport type UseFormResult<M extends AbstractModel> = Omit<UseFormPartResult<M>, 'setValue' | 'value'> &\n Readonly<{\n value: Value<M>;\n submitting: boolean;\n setDefaultValue(value: Value<M>): void;\n setValue(value: Value<M>): void;\n submit(): Promise<Value<M> | undefined | void>;\n reset(): void;\n clear(): void;\n read(value: Value<M> | null | undefined): void;\n update(): void;\n }>;\n\nexport type UseFormArrayPartResult<M extends ArrayModel> = Omit<UseFormPartResult<M>, 'field'> & {\n items: ReadonlyArray<ArrayItemModel<M>>;\n};\n\ntype FieldState<T = unknown> = {\n required: boolean;\n invalid: boolean;\n errorMessage: string;\n strategy?: FieldStrategy<T>;\n element?: HTMLElement;\n inputHandler(): void;\n changeHandler(): void;\n blurHandler(): void;\n ref(element: HTMLElement | null): void;\n};\n\nfunction convertFieldValue<T extends AbstractModel>(model: T, fieldValue: unknown) {\n return typeof fieldValue === 'string' && hasFromString(model) ? model[_fromString](fieldValue) : fieldValue;\n}\n\nfunction getFormPart<M extends AbstractModel>(node: BinderNode<M>): Omit<UseFormPartResult<M>, 'field'> {\n return {\n addValidator: node.addValidator.bind(node),\n get defaultValue() {\n return node.defaultValue;\n },\n dirty: node.dirty,\n errors: node.errors,\n invalid: node.invalid,\n model: node.model,\n name: node.name,\n ownErrors: node.ownErrors,\n required: node.required,\n setValidators(validators) {\n node.validators = validators;\n },\n setValue(value) {\n node.value = value;\n },\n setVisited(visited: boolean) {\n node.visited = visited;\n },\n validate: node.validate.bind(node),\n validators: node.validators,\n get value() {\n return node.value;\n },\n visited: node.visited,\n };\n}\n\nfunction useFields<M extends AbstractModel>(node: BinderNode<M>): FieldDirective {\n const update = useUpdate();\n\n return useMemo(() => {\n const registry = new WeakMap<AbstractModel, FieldState>();\n\n return ((model: AbstractModel) => {\n isRendering = true;\n const n = getBinderNode(model);\n\n let fieldState = registry.get(model);\n\n if (!fieldState) {\n fieldState = {\n changeHandler() {\n fieldState!.inputHandler();\n n.validate().catch(() => {});\n },\n element: undefined,\n errorMessage: '',\n inputHandler() {\n if (fieldState!.strategy) {\n // Remove invalid flag, so that .checkValidity() in Vaadin Components\n // does not interfere with errors from Hilla.\n fieldState!.strategy.invalid = false;\n // When bad input is detected, skip reading new value in binder state\n fieldState!.strategy.checkValidity();\n n[_validity] = fieldState!.strategy.validity;\n n.value = convertFieldValue(model, fieldState!.strategy.value);\n }\n },\n invalid: false,\n blurHandler() {\n fieldState!.inputHandler();\n n.validate().catch(() => {});\n n.visited = true;\n },\n ref(element: HTMLElement | null) {\n if (!element) {\n fieldState!.element?.removeEventListener('blur', fieldState!.blurHandler);\n fieldState!.strategy?.removeEventListeners();\n fieldState!.element = undefined;\n fieldState!.strategy = undefined;\n update();\n return;\n }\n\n if (!isFieldElement(element)) {\n throw new TypeError(`Element '${element.localName}' is not a form element`);\n }\n\n if (fieldState!.element !== element) {\n fieldState!.element = element;\n fieldState!.element.addEventListener('blur', fieldState!.blurHandler);\n fieldState!.strategy = getDefaultFieldStrategy(element, model);\n fieldState!.strategy.onInput = fieldState!.inputHandler;\n fieldState!.strategy.onChange = fieldState!.changeHandler;\n update();\n }\n },\n required: false,\n strategy: undefined,\n };\n\n registry.set(model, fieldState);\n }\n\n if (fieldState.strategy) {\n const valueFromField = convertFieldValue(model, fieldState.strategy.value);\n if (valueFromField !== n.value && !(Number.isNaN(n.value) && Number.isNaN(valueFromField))) {\n fieldState.strategy.value = Number.isNaN(n.value) ? '' : n.value;\n }\n\n if (fieldState.required !== n.required) {\n fieldState.required = n.required;\n fieldState.strategy.required = n.required;\n }\n\n const firstError = n.ownErrors.at(0);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const errorMessage = firstError?.message ?? '';\n if (fieldState.errorMessage !== errorMessage) {\n fieldState.errorMessage = errorMessage;\n fieldState.strategy.errorMessage = errorMessage;\n }\n\n // Make sure invalid state is always in sync\n fieldState.invalid = n.invalid;\n fieldState.strategy.invalid = n.invalid;\n }\n\n isRendering = false;\n return {\n name: n.name,\n ref: fieldState.ref,\n };\n }) as FieldDirective;\n }, [node]);\n}\n\nexport function useForm<M extends AbstractModel>(\n Model: DetachedModelConstructor<M>,\n config?: BinderConfiguration<Value<M>>,\n): UseFormResult<M> {\n const configRef = useRef<Writable<BinderConfiguration<Value<M>>>>({});\n configRef.current.onSubmit = config?.onSubmit;\n configRef.current.onChange = config?.onChange;\n const update = useUpdate();\n const binder = useMemo(() => new BinderRoot(Model, configRef.current), [Model]);\n const field = useFields(binder);\n const clear = binder.clear.bind(binder);\n\n useEffect(() => {\n binder.addEventListener(CHANGED.type, update);\n clear(); // this allows to initialize the validation strategies (issue 2282)\n return () => binder.removeEventListener(CHANGED.type, update);\n }, [binder]);\n\n return {\n ...getFormPart<M>(binder),\n clear,\n field,\n read: binder.read.bind(binder),\n reset: binder.reset.bind(binder),\n setDefaultValue(defaultValue) {\n binder.defaultValue = defaultValue;\n },\n setValue(value) {\n binder.value = value;\n },\n submit: binder.submit.bind(binder),\n value: binder.value,\n submitting: binder.submitting,\n update,\n };\n}\n\nexport function useFormPart<M extends AbstractModel>(model: M): UseFormPartResult<M> {\n isRendering = true;\n const binderNode = getBinderNode(model);\n const field = useFields(binderNode);\n isRendering = false;\n\n return {\n ...getFormPart(binderNode),\n field,\n };\n}\n\n/**\n * Hook to access an array model part of a form. It provides the same API as `useFormPart`,\n * but adds an `items` property that allows to iterate over the items in form of an array of models.\n *\n * @param model - The array model to access\n * @returns The array model part of the form\n */\nexport function useFormArrayPart<M extends ArrayModel>(model: M): UseFormArrayPartResult<M> {\n isRendering = true;\n const binderNode = getBinderNode(model);\n isRendering = false;\n return {\n ...getFormPart(binderNode),\n items: Array.from(model, (item) => item.model as ArrayItemModel<M>),\n };\n}\n"],"version":3}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/hilla-react-form",
3
- "version": "24.7.0-alpha9",
3
+ "version": "24.7.0-beta1",
4
4
  "description": "Hilla form utils for React",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -17,15 +17,12 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "clean:build": "git clean -fx . -e .vite -e node_modules",
20
- "build": "concurrently npm:build:*",
21
- "build:esbuild": "tsx ../../../scripts/build.ts",
22
- "build:dts": "tsc --isolatedModules -p tsconfig.build.json",
23
- "build:copy": "cd src && copyfiles **/*.d.ts ..",
20
+ "build": "tsx ../../../scripts/fast-build.ts",
24
21
  "lint": "eslint src test",
25
22
  "lint:fix": "eslint src test --fix",
26
- "test": "karma start ../../../karma.config.cjs --port 9874",
27
- "test:coverage": "npm run test -- --coverage",
28
- "test:watch": "npm run test -- --watch",
23
+ "test": "vitest --run",
24
+ "test:coverage": "vitest --run --coverage",
25
+ "test:watch": "vitest",
29
26
  "typecheck": "tsc --noEmit"
30
27
  },
31
28
  "exports": {
@@ -46,30 +43,10 @@
46
43
  "access": "public"
47
44
  },
48
45
  "dependencies": {
49
- "@vaadin/hilla-lit-form": "24.7.0-alpha9"
46
+ "@vaadin/hilla-lit-form": "24.7.0-beta1"
50
47
  },
51
48
  "peerDependencies": {
52
49
  "react": "18 || 19",
53
50
  "react-dom": "18 || 19"
54
- },
55
- "devDependencies": {
56
- "@testing-library/dom": "^10.4.0",
57
- "@testing-library/react": "^16.1.0",
58
- "@testing-library/user-event": "^14.5.2",
59
- "@types/chai": "^4.3.20",
60
- "@types/chai-as-promised": "^7.1.8",
61
- "@types/chai-dom": "^1.11.3",
62
- "@types/mocha": "^10.0.10",
63
- "@types/react": "^18.3.18",
64
- "@types/react-dom": "^18",
65
- "@types/sinon": "^10.0.20",
66
- "@types/sinon-chai": "^3.2.12",
67
- "@types/validator": "^13.12.2",
68
- "chai": "^5.1.2",
69
- "chai-as-promised": "^7.1.2",
70
- "chai-dom": "^1.12.0",
71
- "sinon": "^16.1.3",
72
- "sinon-chai": "^3.7.0",
73
- "typescript": "5.7.3"
74
51
  }
75
52
  }
package/index.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"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"}