haze-ui 1.8.1 → 1.10.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
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
English | [简体中文](./README-zh_CN.md)
|
|
6
6
|
|
|
7
|
+
[](https://www.npmjs.com/package/haze-ui)
|
|
8
|
+
[](https://github.com/wmzy/haze-ui/actions/workflows/ci.yml)
|
|
9
|
+
|
|
7
10
|
## Features
|
|
8
11
|
|
|
9
12
|
- Integrated [react use control](https://github.com/wmzy/react-use-control) provides component internal states
|
|
@@ -86,6 +89,40 @@ function ProfileForm() {
|
|
|
86
89
|
surfaces the first error in a `role="alert"` element — no manual
|
|
87
90
|
`FieldError` wiring.
|
|
88
91
|
|
|
92
|
+
#### `mode`: per-field validation timing (react-f0rm ≥ 0.6)
|
|
93
|
+
|
|
94
|
+
Pass `mode` to validate one field on its own schedule instead of the
|
|
95
|
+
form-wide validation mode — other fields are unaffected. It accepts
|
|
96
|
+
react-f0rm's `ValidationMode` values: `'onSubmit'` (default form
|
|
97
|
+
behavior), `'onBlur'`, `'onChange'`, `'onTouched'` or `'all'`. Omit it to
|
|
98
|
+
keep the form's mode.
|
|
99
|
+
|
|
100
|
+
```jsx
|
|
101
|
+
<FormItem
|
|
102
|
+
form={form}
|
|
103
|
+
name="email"
|
|
104
|
+
label="Email"
|
|
105
|
+
mode="onBlur"
|
|
106
|
+
validate={(v) => (v.includes('@') ? undefined : 'must be an email')}
|
|
107
|
+
>
|
|
108
|
+
{({ id, errorId, invalid, onBlur, control }) => (
|
|
109
|
+
<Input
|
|
110
|
+
id={id}
|
|
111
|
+
value={control}
|
|
112
|
+
aria-invalid={invalid}
|
|
113
|
+
aria-describedby={errorId}
|
|
114
|
+
onBlur={onBlur}
|
|
115
|
+
/>
|
|
116
|
+
)}
|
|
117
|
+
</FormItem>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
With `mode="onBlur"` (and the binding's `onBlur` passed to the control,
|
|
121
|
+
as above) the email field is validated the moment it loses focus — no
|
|
122
|
+
submit needed. `mode` accepts `'onSubmit'`, `'onBlur'`, `'onChange'`,
|
|
123
|
+
`'onTouched'` or `'all'`; only this field's schedule changes, the rest
|
|
124
|
+
of the form keeps its own `mode`.
|
|
125
|
+
|
|
89
126
|
## Related Projects
|
|
90
127
|
|
|
91
128
|
- [react-use-control](https://github.com/wmzy/react-use-control)
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import { classnames as e } from "../../utils/classnames.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import { jsx as t } from "react/jsx-runtime";
|
|
4
|
+
import { forwardRef as n } from "react";
|
|
4
5
|
//#region src/lib/components/NavigationBar/NavLink.tsx
|
|
5
|
-
var
|
|
6
|
-
|
|
6
|
+
var r = "haze-NavLink__link", i = "haze-NavLink__activeLink", a = n(function({ href: n = "#", active: a, children: o, onClick: s, className: c, "aria-current": l, ...u }, d) {
|
|
7
|
+
let f = a ?? l === "page";
|
|
7
8
|
return /* @__PURE__ */ t("a", {
|
|
8
|
-
|
|
9
|
+
ref: d,
|
|
10
|
+
href: n,
|
|
11
|
+
"aria-current": f ? "page" : l,
|
|
9
12
|
onClick: (e) => {
|
|
10
|
-
|
|
13
|
+
n === "#" && e.preventDefault(), s?.(e);
|
|
11
14
|
},
|
|
12
|
-
|
|
15
|
+
...u,
|
|
13
16
|
className: e([
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
r,
|
|
18
|
+
f && i,
|
|
16
19
|
c
|
|
17
20
|
]),
|
|
18
21
|
children: o
|
|
19
22
|
});
|
|
20
|
-
}
|
|
23
|
+
});
|
|
21
24
|
//#endregion
|
|
22
|
-
export {
|
|
25
|
+
export { a as default };
|
package/dist/form/FormItem.js
CHANGED
|
@@ -6,34 +6,34 @@ import { useId as i } from "react";
|
|
|
6
6
|
import { useField as a, useFieldErrors as o } from "react-f0rm";
|
|
7
7
|
//#region src/lib/form/FormItem.tsx
|
|
8
8
|
var s = "haze-FormItem__item", c = "haze-FormItem__labelText", l = "haze-FormItem__errorText";
|
|
9
|
-
function u({ form: u, name: d, label: f, validate: p,
|
|
10
|
-
let
|
|
11
|
-
a({
|
|
9
|
+
function u({ form: u, name: d, label: f, validate: p, mode: m, className: h, children: g }) {
|
|
10
|
+
let _ = `haze-field-${i()}`, v = `${_}-error`, { onBlur: y } = a({
|
|
12
11
|
form: u,
|
|
13
12
|
name: d,
|
|
14
|
-
validate: p
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
validate: p,
|
|
14
|
+
mode: m
|
|
15
|
+
}), b = o(u, d), x = t(u, d), S = b.length > 0;
|
|
17
16
|
return /* @__PURE__ */ r("div", {
|
|
18
|
-
className: e([s,
|
|
17
|
+
className: e([s, h]),
|
|
19
18
|
children: [
|
|
20
19
|
f !== void 0 && /* @__PURE__ */ n("label", {
|
|
21
|
-
htmlFor:
|
|
20
|
+
htmlFor: _,
|
|
22
21
|
className: e(c),
|
|
23
22
|
children: f
|
|
24
23
|
}),
|
|
25
|
-
|
|
26
|
-
id: g,
|
|
27
|
-
errorId: _,
|
|
28
|
-
invalid: b,
|
|
29
|
-
errors: v,
|
|
30
|
-
control: y
|
|
31
|
-
}),
|
|
32
|
-
b && /* @__PURE__ */ n("span", {
|
|
24
|
+
g({
|
|
33
25
|
id: _,
|
|
26
|
+
errorId: v,
|
|
27
|
+
invalid: S,
|
|
28
|
+
errors: b,
|
|
29
|
+
onBlur: y,
|
|
30
|
+
control: x
|
|
31
|
+
}),
|
|
32
|
+
S && /* @__PURE__ */ n("span", {
|
|
33
|
+
id: v,
|
|
34
34
|
role: "alert",
|
|
35
35
|
className: e(l),
|
|
36
|
-
children:
|
|
36
|
+
children: b[0].message
|
|
37
37
|
})
|
|
38
38
|
]
|
|
39
39
|
});
|
|
@@ -1,10 +1,42 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { ComponentPropsWithoutRef, MouseEvent, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Extends the native `<a>` attributes. Everything not listed below is spread
|
|
4
|
+
* onto the rendered anchor, so callers (and routers composing NavLink via
|
|
5
|
+
* their `as` prop) can inject `target`, `rel`, `aria-*`, and friends.
|
|
6
|
+
*/
|
|
2
7
|
type NavLinkProps = {
|
|
3
8
|
href?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Explicit active state. Falls back to `aria-current="page"` when omitted,
|
|
11
|
+
* letting routers drive highlighting through the standard aria attribute.
|
|
12
|
+
*/
|
|
4
13
|
active?: boolean;
|
|
5
14
|
children: ReactNode;
|
|
6
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Native click handler: receives the underlying mouse event. Whether to
|
|
17
|
+
* call `event.preventDefault()` is up to the caller (an SPA router Link
|
|
18
|
+
* does so itself), except for placeholder hrefs where NavLink keeps
|
|
19
|
+
* button semantics (see the onClick handler below).
|
|
20
|
+
*/
|
|
21
|
+
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
7
22
|
className?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
23
|
+
} & Omit<ComponentPropsWithoutRef<'a'>, 'href' | 'children' | 'onClick' | 'className'>;
|
|
24
|
+
declare const _default: import("react").ForwardRefExoticComponent<{
|
|
25
|
+
href?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Explicit active state. Falls back to `aria-current="page"` when omitted,
|
|
28
|
+
* letting routers drive highlighting through the standard aria attribute.
|
|
29
|
+
*/
|
|
30
|
+
active?: boolean;
|
|
31
|
+
children: ReactNode;
|
|
32
|
+
/**
|
|
33
|
+
* Native click handler: receives the underlying mouse event. Whether to
|
|
34
|
+
* call `event.preventDefault()` is up to the caller (an SPA router Link
|
|
35
|
+
* does so itself), except for placeholder hrefs where NavLink keeps
|
|
36
|
+
* button semantics (see the onClick handler below).
|
|
37
|
+
*/
|
|
38
|
+
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
39
|
+
className?: string;
|
|
40
|
+
} & Omit<Omit<import("react").DetailedHTMLProps<import("react").AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "ref">, "className" | "children" | "onClick" | "href"> & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
41
|
+
export default _default;
|
|
10
42
|
export type { NavLinkProps };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type { FieldError, FieldPath, Name } from 'react-f0rm';
|
|
2
|
+
import type { FieldError, FieldPath, Name, ValidationMode } from 'react-f0rm';
|
|
3
3
|
import type { Control } from 'react-use-control';
|
|
4
4
|
import type { FormInstance, PathValueOf } from './useFormControl';
|
|
5
5
|
/**
|
|
@@ -22,6 +22,10 @@ export type FormItemBinding<TValues, P extends FieldPath<TValues> | Name> = {
|
|
|
22
22
|
invalid: boolean;
|
|
23
23
|
/** every error registered for the field, in insertion order */
|
|
24
24
|
errors: FieldError[];
|
|
25
|
+
/** react-f0rm blur hook for this field — pass to the control's `onBlur`
|
|
26
|
+
* (`<Input onBlur={onBlur}/>`) so blur-scheduled validation modes
|
|
27
|
+
* (`mode='onBlur' | 'onTouched' | 'all'`) fire when the field loses focus. */
|
|
28
|
+
onBlur: () => void;
|
|
25
29
|
/** Control bound to the field value — pass to a control prop */
|
|
26
30
|
control: Control<PathValueOf<TValues, P>>;
|
|
27
31
|
};
|
|
@@ -32,6 +36,11 @@ export type FormItemProps<TValues extends Record<string, any> = any, P extends F
|
|
|
32
36
|
/** Field-level validator, registered through react-f0rm's own
|
|
33
37
|
* `useField` channel — validated per the form's `mode` and on submit. */
|
|
34
38
|
validate?: FieldValidator;
|
|
39
|
+
/** Per-field validation mode override (react-f0rm ≥0.6): when given,
|
|
40
|
+
* this field validates on its own schedule — e.g. `'onBlur'` — instead
|
|
41
|
+
* of the form's `mode`; other fields are unaffected. Omit to keep the
|
|
42
|
+
* form-wide behavior. */
|
|
43
|
+
mode?: ValidationMode;
|
|
35
44
|
className?: string;
|
|
36
45
|
children: (binding: FormItemBinding<TValues, P>) => ReactNode;
|
|
37
46
|
};
|
|
@@ -52,4 +61,4 @@ export type FormItemProps<TValues extends Record<string, any> = any, P extends F
|
|
|
52
61
|
* `<span id={errorId} role='alert'>` next to the children; with no errors
|
|
53
62
|
* no extra element is rendered.
|
|
54
63
|
*/
|
|
55
|
-
export default function FormItem<TValues extends Record<string, any> = any, P extends FieldPath<TValues> | Name = Name>({ form, name, label, validate, className, children }: FormItemProps<TValues, P>): import("react").JSX.Element;
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "haze-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.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",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"react-f0rm": ">=0.3.0"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"react-toolroom": "^0.
|
|
58
|
+
"react-toolroom": "^0.11.0",
|
|
59
59
|
"react-use-control": "^1.3.2"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
@@ -65,26 +65,26 @@
|
|
|
65
65
|
"@faker-js/faker": "^10.6.0",
|
|
66
66
|
"@for-fun/event-emitter": "^1.0.1",
|
|
67
67
|
"@linaria/core": "^8.2.0",
|
|
68
|
-
"@native-router/core": "^1.
|
|
69
|
-
"@native-router/react": "^1.
|
|
68
|
+
"@native-router/core": "^1.8.0",
|
|
69
|
+
"@native-router/react": "^1.6.1",
|
|
70
70
|
"@testing-library/jest-dom": "^7.0.1",
|
|
71
71
|
"@testing-library/react": "^16.3.2",
|
|
72
72
|
"@testing-library/user-event": "^14.6.6",
|
|
73
73
|
"@types/jest-axe": "^3.5.9",
|
|
74
|
-
"@types/node": "^26.
|
|
74
|
+
"@types/node": "^26.3.0",
|
|
75
75
|
"@types/ramda": "^0.32.0",
|
|
76
76
|
"@types/react": "^19.2.18",
|
|
77
|
-
"@types/react-dom": "^19.2.
|
|
77
|
+
"@types/react-dom": "^19.2.5",
|
|
78
78
|
"@vitejs/plugin-react": "^6.1.0",
|
|
79
79
|
"@vitest/coverage-v8": "4.1.11",
|
|
80
|
-
"@wyw-in-js/babel-preset": "^2.4.
|
|
81
|
-
"@wyw-in-js/vite": "^2.4.
|
|
80
|
+
"@wyw-in-js/babel-preset": "^2.4.3",
|
|
81
|
+
"@wyw-in-js/vite": "^2.4.3",
|
|
82
82
|
"babel-plugin-transform-jsx-class": "^0.1.3",
|
|
83
83
|
"babel-plugin-transform-jsx-condition": "^0.1.3",
|
|
84
84
|
"commitizen": "^4.3.2",
|
|
85
85
|
"core-js": "^3.50.0",
|
|
86
86
|
"date-fns": "^4.4.0",
|
|
87
|
-
"eslint": "^10.9.
|
|
87
|
+
"eslint": "^10.9.1",
|
|
88
88
|
"eslint-plugin-compat": "^7.0.2",
|
|
89
89
|
"gh-pages": "^6.3.0",
|
|
90
90
|
"husky": "^9.1.7",
|
|
@@ -92,17 +92,17 @@
|
|
|
92
92
|
"jsdom": "^30.0.1",
|
|
93
93
|
"json-schema-faker": "^0.6.3",
|
|
94
94
|
"lint-staged": "^17.3.0",
|
|
95
|
-
"lucide-react": "^1.
|
|
95
|
+
"lucide-react": "^1.34.0",
|
|
96
96
|
"prettier": "^3.9.6",
|
|
97
97
|
"qss": "^3.0.0",
|
|
98
98
|
"ramda": "^0.32.0",
|
|
99
99
|
"react": "^19.2.8",
|
|
100
100
|
"react-dom": "^19.2.8",
|
|
101
|
-
"react-f0rm": "^0.
|
|
101
|
+
"react-f0rm": "^0.6.0",
|
|
102
102
|
"react-icons": "^5.7.0",
|
|
103
103
|
"rollup-plugin-type-as-json-schema": "^0.2.6",
|
|
104
104
|
"semantic-release": "^25.0.9",
|
|
105
|
-
"terser": "^5.
|
|
105
|
+
"terser": "^5.51.0",
|
|
106
106
|
"tools-config": "^0.3.0",
|
|
107
107
|
"tsc-alias": "^1.9.2",
|
|
108
108
|
"typescript": "^6.0.3",
|