haze-ui 1.11.1 → 1.12.0

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/README.md CHANGED
@@ -137,6 +137,45 @@ submit needed. `mode` accepts `'onSubmit'`, `'onBlur'`, `'onChange'`,
137
137
  `'onTouched'` or `'all'`; only this field's schedule changes, the rest
138
138
  of the form keeps its own `mode`.
139
139
 
140
+ #### `validateDebounce` / `delayError` / `rules` (react-f0rm ≥ 0.6)
141
+
142
+ `FormItem` passes these field-level options straight through to
143
+ react-f0rm's `useField`:
144
+
145
+ - `validateDebounce={300}` — debounce this field's validation kicks:
146
+ only the last kick inside the window runs the validator (e.g. keeps a
147
+ per-keystroke async validator from firing while the user types fast).
148
+ While the timer is pending the field counts as validating, so
149
+ `trigger`/submit wait it out.
150
+ - `delayError={500}` — delay *showing* a newly appearing error in the
151
+ rendered error span (and the binding's `invalid`/`errors`). The form's
152
+ error state stays immediate — submit and `getError` still gate on it.
153
+ An error that clears inside the window never shows.
154
+ - `rules={{ required: 'Email is required', minLength: 4, pattern: { value: /@/, message: 'Must be an email' } }}`
155
+ — declarative constraints (a subset of react-hook-form's `register`
156
+ rules) compiled into a validator that runs *before* `validate`; both
157
+ sources' errors merge into the field's error list, rules errors ahead.
158
+
159
+ ```jsx
160
+ <FormItem
161
+ form={form}
162
+ name="email"
163
+ label="Email"
164
+ validateDebounce={300}
165
+ delayError={500}
166
+ rules={{ required: 'Email is required' }}
167
+ validate={(v) => (v.includes('@') ? undefined : 'must be an email')}
168
+ >
169
+ {({ id, errorId, invalid, control }) => (
170
+ <Input id={id} value={control} aria-invalid={invalid} aria-describedby={errorId} />
171
+ )}
172
+ </FormItem>
173
+ ```
174
+
175
+ All three are optional; omit them and the field behaves exactly as
176
+ before (immediate validation per the form's `mode`, immediate error
177
+ display, `validate`-only).
178
+
140
179
  ## Related Projects
141
180
 
142
181
  - [react-use-control](https://github.com/wmzy/react-use-control)
@@ -4,40 +4,43 @@ import { useFormControl as t } from "./useFormControl.js";
4
4
  /* empty css */
5
5
  import { jsx as n, jsxs as r } from "react/jsx-runtime";
6
6
  import { useId as i } from "react";
7
- import { useField as a, useFieldErrors as o } from "react-f0rm";
7
+ import { useField as a } from "react-f0rm";
8
8
  //#region src/lib/form/FormItem.tsx
9
- var s = "haze-FormItem__item", c = "haze-FormItem__labelText", l = "haze-FormItem__errorText";
10
- function u({ form: u, name: d, label: f, validate: p, mode: m, className: h, children: g }) {
11
- let _ = `haze-field-${i()}`, v = `${_}-error`, { onBlur: y } = a({
12
- form: u,
13
- name: d,
14
- validate: p,
15
- mode: m
16
- }), b = o(u, d), x = t(u, d), S = b.length > 0;
9
+ var o = "haze-FormItem__item", s = "haze-FormItem__labelText", c = "haze-FormItem__errorText";
10
+ function l({ form: l, name: u, label: d, validate: f, mode: p, validateDebounce: m, delayError: h, rules: g, className: _, children: v }) {
11
+ let y = `haze-field-${i()}`, b = `${y}-error`, { onBlur: x, errors: S } = a({
12
+ form: l,
13
+ name: u,
14
+ validate: f,
15
+ mode: p,
16
+ validateDebounce: m,
17
+ delayError: h,
18
+ rules: g
19
+ }), C = t(l, u), w = S.length > 0;
17
20
  return /* @__PURE__ */ r("div", {
18
- className: e([s, h]),
21
+ className: e([o, _]),
19
22
  children: [
20
- f !== void 0 && /* @__PURE__ */ n("label", {
21
- htmlFor: _,
22
- className: e(c),
23
- children: f
23
+ d !== void 0 && /* @__PURE__ */ n("label", {
24
+ htmlFor: y,
25
+ className: e(s),
26
+ children: d
24
27
  }),
25
- g({
26
- id: _,
27
- errorId: v,
28
- invalid: S,
29
- errors: b,
30
- onBlur: y,
31
- control: x
28
+ v({
29
+ id: y,
30
+ errorId: b,
31
+ invalid: w,
32
+ errors: S,
33
+ onBlur: x,
34
+ control: C
32
35
  }),
33
- S && /* @__PURE__ */ n("span", {
34
- id: v,
36
+ w && /* @__PURE__ */ n("span", {
37
+ id: b,
35
38
  role: "alert",
36
- className: e(l),
37
- children: b[0].message
39
+ className: e(c),
40
+ children: S[0].message
38
41
  })
39
42
  ]
40
43
  });
41
44
  }
42
45
  //#endregion
43
- export { u as default };
46
+ export { l as default };
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { FieldError, FieldPath, Name, ValidationMode } from 'react-f0rm';
2
+ import type { FieldError, FieldPath, FieldRules, Name, ValidationMode } from 'react-f0rm';
3
3
  import type { Control } from 'react-use-control';
4
4
  import type { FormInstance, PathValueOf } from './useFormControl';
5
5
  /**
@@ -41,6 +41,23 @@ export type FormItemProps<TValues extends Record<string, any> = any, P extends F
41
41
  * of the form's `mode`; other fields are unaffected. Omit to keep the
42
42
  * form-wide behavior. */
43
43
  mode?: ValidationMode;
44
+ /** Milliseconds to debounce this field's validation kicks (react-f0rm
45
+ * ≥0.6): only the last kick inside the window runs the validator — e.g.
46
+ * `300` keeps a fast typist from firing a per-keystroke async validator.
47
+ * While the timer is pending the field counts as validating. Omit for
48
+ * immediate validation (react-f0rm's default). */
49
+ validateDebounce?: number;
50
+ /** Milliseconds to delay *showing* a newly appearing error in the render
51
+ * layer (react-f0rm ≥0.6): the form's error state stays immediate —
52
+ * submit/trigger still gate on it — only the rendered error span and
53
+ * `invalid` wait out the window. An error that clears inside the window
54
+ * never shows. Omit for immediate display. */
55
+ delayError?: number;
56
+ /** Declarative rules (required/min/max/minLength/maxLength/pattern;
57
+ * react-f0rm ≥0.6), compiled into a validator that runs *before*
58
+ * `validate` — both sources' errors merge, rules errors ahead. Omit for
59
+ * `validate`-only validation. */
60
+ rules?: FieldRules;
44
61
  className?: string;
45
62
  children: (binding: FormItemBinding<TValues, P>) => ReactNode;
46
63
  };
@@ -61,4 +78,4 @@ export type FormItemProps<TValues extends Record<string, any> = any, P extends F
61
78
  * `<span id={errorId} role='alert'>` next to the children; with no errors
62
79
  * no extra element is rendered.
63
80
  */
64
- export default function FormItem<TValues extends Record<string, any> = any, P extends FieldPath<TValues> | Name = Name>({ form, name, label, validate, mode, className, children }: FormItemProps<TValues, P>): import("react").JSX.Element;
81
+ export default function FormItem<TValues extends Record<string, any> = any, P extends FieldPath<TValues> | Name = Name>({ form, name, label, validate, mode, validateDebounce, delayError, rules, className, children }: FormItemProps<TValues, P>): import("react").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haze-ui",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
4
4
  "type": "module",
5
5
  "description": "A React UI component library powered by react-use-control and Linaria",
6
6
  "main": "./dist/index.js",