@seed-design/react-field-button 1.0.0 → 1.0.1
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/lib/{FieldButton-12s-nUvzy79W.js → FieldButton-12s-CcR1XhHB.js} +22 -11
- package/lib/{FieldButton-12s-CF9DP1xP.cjs → FieldButton-12s-Ctrm9BuF.cjs} +22 -11
- package/lib/index.cjs +1 -1
- package/lib/index.d.ts +8 -2
- package/lib/index.js +2 -2
- package/package.json +3 -2
- package/src/FieldButton.tsx +2 -2
- package/src/useFieldButton.test.tsx +47 -0
- package/src/useFieldButton.ts +30 -9
|
@@ -4,6 +4,7 @@ import { composeRefs } from '@radix-ui/react-compose-refs';
|
|
|
4
4
|
import { elementProps, dataAttr, buttonProps, inputProps, ariaAttr, mergeProps } from '@seed-design/dom-utils';
|
|
5
5
|
import { Primitive } from '@seed-design/react-primitive';
|
|
6
6
|
import { useId, useCallback, useState, createContext, useContext, forwardRef } from 'react';
|
|
7
|
+
import { useSupports } from '@seed-design/react-supports';
|
|
7
8
|
|
|
8
9
|
const getDescriptionId = (id)=>`field-button:${id}:description`;
|
|
9
10
|
const getErrorMessageId = (id)=>`field-button:${id}:error-message`;
|
|
@@ -42,9 +43,9 @@ function useFieldButtonState({ values = [], onValuesChange = ()=>{} }) {
|
|
|
42
43
|
setIsFocusVisible
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
|
-
function useFieldButton(
|
|
46
|
+
function useFieldButton({ values: propValues, onValuesChange, disabled = false, invalid = false, readOnly = false, name }) {
|
|
46
47
|
const id = useId();
|
|
47
|
-
const
|
|
48
|
+
const isFocusVisibleSupported = useSupports("selector(:focus-visible)");
|
|
48
49
|
const { values: stateValues, isHovered, isActive, isFocused, isFocusVisible, refs, renderedElements, setValues, setIsHovered, setIsActive, setIsFocused, setIsFocusVisible } = useFieldButtonState({
|
|
49
50
|
values: propValues,
|
|
50
51
|
onValuesChange
|
|
@@ -59,13 +60,16 @@ function useFieldButton(props) {
|
|
|
59
60
|
"data-focus": dataAttr(isFocused),
|
|
60
61
|
"data-focus-visible": dataAttr(isFocusVisible),
|
|
61
62
|
"data-disabled": dataAttr(disabled),
|
|
62
|
-
"data-invalid": dataAttr(invalid)
|
|
63
|
+
"data-invalid": dataAttr(invalid),
|
|
64
|
+
"data-readonly": dataAttr(readOnly)
|
|
63
65
|
});
|
|
64
66
|
return {
|
|
65
67
|
values: stateValues,
|
|
66
68
|
active: isActive,
|
|
67
69
|
focused: isFocused,
|
|
68
70
|
invalid,
|
|
71
|
+
disabled,
|
|
72
|
+
readOnly,
|
|
69
73
|
setIsFocused,
|
|
70
74
|
setIsFocusVisible,
|
|
71
75
|
refs,
|
|
@@ -83,8 +87,8 @@ function useFieldButton(props) {
|
|
|
83
87
|
buttonProps: buttonProps({
|
|
84
88
|
...stateProps,
|
|
85
89
|
type: "button",
|
|
86
|
-
disabled,
|
|
87
|
-
"aria-disabled": ariaAttr(disabled),
|
|
90
|
+
disabled: disabled || readOnly,
|
|
91
|
+
"aria-disabled": ariaAttr(disabled || readOnly),
|
|
88
92
|
"aria-describedby": ariaDescribedBy,
|
|
89
93
|
// note that pointerdown and pointerup are attached to the button, not the root
|
|
90
94
|
// this is for preventing setting isActive to true when the clear button is pressed
|
|
@@ -96,21 +100,25 @@ function useFieldButton(props) {
|
|
|
96
100
|
},
|
|
97
101
|
onBlur () {
|
|
98
102
|
setIsFocused(false);
|
|
99
|
-
|
|
103
|
+
if (isFocusVisibleSupported) {
|
|
104
|
+
setIsFocusVisible(false);
|
|
105
|
+
}
|
|
100
106
|
},
|
|
101
107
|
onFocus (event) {
|
|
102
108
|
setIsFocused(true);
|
|
103
|
-
|
|
109
|
+
if (isFocusVisibleSupported) {
|
|
110
|
+
setIsFocusVisible(event.target.matches(":focus-visible"));
|
|
111
|
+
}
|
|
104
112
|
}
|
|
105
113
|
}),
|
|
106
114
|
clearButtonProps: buttonProps({
|
|
107
115
|
...stateProps,
|
|
108
116
|
type: "button",
|
|
109
|
-
disabled,
|
|
117
|
+
disabled: disabled || readOnly,
|
|
110
118
|
onClick: useCallback(()=>setValues([]), [
|
|
111
119
|
setValues
|
|
112
120
|
]),
|
|
113
|
-
hidden: disabled
|
|
121
|
+
hidden: disabled || readOnly
|
|
114
122
|
}),
|
|
115
123
|
getHiddenInputProps: useCallback((index)=>{
|
|
116
124
|
const value = stateValues[index];
|
|
@@ -118,12 +126,14 @@ function useFieldButton(props) {
|
|
|
118
126
|
return inputProps({
|
|
119
127
|
type: "hidden",
|
|
120
128
|
value,
|
|
129
|
+
disabled,
|
|
121
130
|
name: name || id
|
|
122
131
|
});
|
|
123
132
|
}, [
|
|
124
133
|
stateValues,
|
|
125
134
|
name,
|
|
126
|
-
id
|
|
135
|
+
id,
|
|
136
|
+
disabled
|
|
127
137
|
]),
|
|
128
138
|
descriptionProps: elementProps({
|
|
129
139
|
...stateProps,
|
|
@@ -147,9 +157,10 @@ function useFieldButtonContext({ strict = true } = {}) {
|
|
|
147
157
|
return context;
|
|
148
158
|
}
|
|
149
159
|
|
|
150
|
-
const FieldButtonRoot = /*#__PURE__*/ forwardRef(({ disabled, invalid, name, values, onValuesChange, ...otherProps }, ref)=>{
|
|
160
|
+
const FieldButtonRoot = /*#__PURE__*/ forwardRef(({ disabled, readOnly, invalid, name, values, onValuesChange, ...otherProps }, ref)=>{
|
|
151
161
|
const api = useFieldButton({
|
|
152
162
|
disabled,
|
|
163
|
+
readOnly,
|
|
153
164
|
invalid,
|
|
154
165
|
name,
|
|
155
166
|
values,
|
|
@@ -4,6 +4,7 @@ var reactComposeRefs = require('@radix-ui/react-compose-refs');
|
|
|
4
4
|
var domUtils = require('@seed-design/dom-utils');
|
|
5
5
|
var reactPrimitive = require('@seed-design/react-primitive');
|
|
6
6
|
var react = require('react');
|
|
7
|
+
var reactSupports = require('@seed-design/react-supports');
|
|
7
8
|
|
|
8
9
|
const getDescriptionId = (id)=>`field-button:${id}:description`;
|
|
9
10
|
const getErrorMessageId = (id)=>`field-button:${id}:error-message`;
|
|
@@ -42,9 +43,9 @@ function useFieldButtonState({ values = [], onValuesChange = ()=>{} }) {
|
|
|
42
43
|
setIsFocusVisible
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
|
-
function useFieldButton(
|
|
46
|
+
function useFieldButton({ values: propValues, onValuesChange, disabled = false, invalid = false, readOnly = false, name }) {
|
|
46
47
|
const id = react.useId();
|
|
47
|
-
const
|
|
48
|
+
const isFocusVisibleSupported = reactSupports.useSupports("selector(:focus-visible)");
|
|
48
49
|
const { values: stateValues, isHovered, isActive, isFocused, isFocusVisible, refs, renderedElements, setValues, setIsHovered, setIsActive, setIsFocused, setIsFocusVisible } = useFieldButtonState({
|
|
49
50
|
values: propValues,
|
|
50
51
|
onValuesChange
|
|
@@ -59,13 +60,16 @@ function useFieldButton(props) {
|
|
|
59
60
|
"data-focus": domUtils.dataAttr(isFocused),
|
|
60
61
|
"data-focus-visible": domUtils.dataAttr(isFocusVisible),
|
|
61
62
|
"data-disabled": domUtils.dataAttr(disabled),
|
|
62
|
-
"data-invalid": domUtils.dataAttr(invalid)
|
|
63
|
+
"data-invalid": domUtils.dataAttr(invalid),
|
|
64
|
+
"data-readonly": domUtils.dataAttr(readOnly)
|
|
63
65
|
});
|
|
64
66
|
return {
|
|
65
67
|
values: stateValues,
|
|
66
68
|
active: isActive,
|
|
67
69
|
focused: isFocused,
|
|
68
70
|
invalid,
|
|
71
|
+
disabled,
|
|
72
|
+
readOnly,
|
|
69
73
|
setIsFocused,
|
|
70
74
|
setIsFocusVisible,
|
|
71
75
|
refs,
|
|
@@ -83,8 +87,8 @@ function useFieldButton(props) {
|
|
|
83
87
|
buttonProps: domUtils.buttonProps({
|
|
84
88
|
...stateProps,
|
|
85
89
|
type: "button",
|
|
86
|
-
disabled,
|
|
87
|
-
"aria-disabled": domUtils.ariaAttr(disabled),
|
|
90
|
+
disabled: disabled || readOnly,
|
|
91
|
+
"aria-disabled": domUtils.ariaAttr(disabled || readOnly),
|
|
88
92
|
"aria-describedby": ariaDescribedBy,
|
|
89
93
|
// note that pointerdown and pointerup are attached to the button, not the root
|
|
90
94
|
// this is for preventing setting isActive to true when the clear button is pressed
|
|
@@ -96,21 +100,25 @@ function useFieldButton(props) {
|
|
|
96
100
|
},
|
|
97
101
|
onBlur () {
|
|
98
102
|
setIsFocused(false);
|
|
99
|
-
|
|
103
|
+
if (isFocusVisibleSupported) {
|
|
104
|
+
setIsFocusVisible(false);
|
|
105
|
+
}
|
|
100
106
|
},
|
|
101
107
|
onFocus (event) {
|
|
102
108
|
setIsFocused(true);
|
|
103
|
-
|
|
109
|
+
if (isFocusVisibleSupported) {
|
|
110
|
+
setIsFocusVisible(event.target.matches(":focus-visible"));
|
|
111
|
+
}
|
|
104
112
|
}
|
|
105
113
|
}),
|
|
106
114
|
clearButtonProps: domUtils.buttonProps({
|
|
107
115
|
...stateProps,
|
|
108
116
|
type: "button",
|
|
109
|
-
disabled,
|
|
117
|
+
disabled: disabled || readOnly,
|
|
110
118
|
onClick: react.useCallback(()=>setValues([]), [
|
|
111
119
|
setValues
|
|
112
120
|
]),
|
|
113
|
-
hidden: disabled
|
|
121
|
+
hidden: disabled || readOnly
|
|
114
122
|
}),
|
|
115
123
|
getHiddenInputProps: react.useCallback((index)=>{
|
|
116
124
|
const value = stateValues[index];
|
|
@@ -118,12 +126,14 @@ function useFieldButton(props) {
|
|
|
118
126
|
return domUtils.inputProps({
|
|
119
127
|
type: "hidden",
|
|
120
128
|
value,
|
|
129
|
+
disabled,
|
|
121
130
|
name: name || id
|
|
122
131
|
});
|
|
123
132
|
}, [
|
|
124
133
|
stateValues,
|
|
125
134
|
name,
|
|
126
|
-
id
|
|
135
|
+
id,
|
|
136
|
+
disabled
|
|
127
137
|
]),
|
|
128
138
|
descriptionProps: domUtils.elementProps({
|
|
129
139
|
...stateProps,
|
|
@@ -147,9 +157,10 @@ function useFieldButtonContext({ strict = true } = {}) {
|
|
|
147
157
|
return context;
|
|
148
158
|
}
|
|
149
159
|
|
|
150
|
-
const FieldButtonRoot = /*#__PURE__*/ react.forwardRef(({ disabled, invalid, name, values, onValuesChange, ...otherProps }, ref)=>{
|
|
160
|
+
const FieldButtonRoot = /*#__PURE__*/ react.forwardRef(({ disabled, readOnly, invalid, name, values, onValuesChange, ...otherProps }, ref)=>{
|
|
151
161
|
const api = useFieldButton({
|
|
152
162
|
disabled,
|
|
163
|
+
readOnly,
|
|
153
164
|
invalid,
|
|
154
165
|
name,
|
|
155
166
|
values,
|
package/lib/index.cjs
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -15,14 +15,20 @@ interface UseFieldButtonProps extends UseFieldButtonStateProps {
|
|
|
15
15
|
* @default false
|
|
16
16
|
*/
|
|
17
17
|
invalid?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
readOnly?: boolean;
|
|
18
22
|
name?: string;
|
|
19
23
|
}
|
|
20
24
|
type UseFieldButtonReturn = ReturnType<typeof useFieldButton>;
|
|
21
|
-
declare function useFieldButton(
|
|
25
|
+
declare function useFieldButton({ values: propValues, onValuesChange, disabled, invalid, readOnly, name, }: UseFieldButtonProps): {
|
|
22
26
|
values: string[];
|
|
23
27
|
active: boolean;
|
|
24
28
|
focused: boolean;
|
|
25
29
|
invalid: boolean;
|
|
30
|
+
disabled: boolean;
|
|
31
|
+
readOnly: boolean;
|
|
26
32
|
setIsFocused: react.Dispatch<react.SetStateAction<boolean>>;
|
|
27
33
|
setIsFocusVisible: react.Dispatch<react.SetStateAction<boolean>>;
|
|
28
34
|
refs: {
|
|
@@ -1179,6 +1185,7 @@ declare function useFieldButton(props: UseFieldButtonProps): {
|
|
|
1179
1185
|
};
|
|
1180
1186
|
getHiddenInputProps: (index: number) => {
|
|
1181
1187
|
disabled?: boolean | undefined | undefined;
|
|
1188
|
+
readOnly?: boolean | undefined | undefined;
|
|
1182
1189
|
name?: string | undefined | undefined;
|
|
1183
1190
|
defaultChecked?: boolean | undefined | undefined;
|
|
1184
1191
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
@@ -1482,7 +1489,6 @@ declare function useFieldButton(props: UseFieldButtonProps): {
|
|
|
1482
1489
|
multiple?: boolean | undefined | undefined;
|
|
1483
1490
|
pattern?: string | undefined | undefined;
|
|
1484
1491
|
placeholder?: string | undefined | undefined;
|
|
1485
|
-
readOnly?: boolean | undefined | undefined;
|
|
1486
1492
|
required?: boolean | undefined | undefined;
|
|
1487
1493
|
size?: number | undefined | undefined;
|
|
1488
1494
|
src?: string | undefined | undefined;
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FieldButtonButton, a as FieldButtonClearButton, b as FieldButtonDescription, c as FieldButtonErrorMessage, d as FieldButtonHiddenInput, e as FieldButtonRoot } from './FieldButton-12s-
|
|
2
|
-
export { u as useFieldButtonContext } from './FieldButton-12s-
|
|
1
|
+
import { F as FieldButtonButton, a as FieldButtonClearButton, b as FieldButtonDescription, c as FieldButtonErrorMessage, d as FieldButtonHiddenInput, e as FieldButtonRoot } from './FieldButton-12s-CcR1XhHB.js';
|
|
2
|
+
export { u as useFieldButtonContext } from './FieldButton-12s-CcR1XhHB.js';
|
|
3
3
|
|
|
4
4
|
var FieldButton_namespace = {
|
|
5
5
|
__proto__: null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-design/react-field-button",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/daangn/seed-design.git",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"@radix-ui/react-compose-refs": "^1.1.2",
|
|
31
31
|
"@radix-ui/react-use-controllable-state": "^1.2.2",
|
|
32
32
|
"@seed-design/dom-utils": "1.0.0",
|
|
33
|
-
"@seed-design/react-primitive": "1.0.0"
|
|
33
|
+
"@seed-design/react-primitive": "1.0.0",
|
|
34
|
+
"@seed-design/react-supports": "0.0.1"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/react": "^19.1.6",
|
package/src/FieldButton.tsx
CHANGED
|
@@ -13,8 +13,8 @@ export interface FieldButtonRootProps
|
|
|
13
13
|
HTMLAttributes<HTMLDivElement> {}
|
|
14
14
|
|
|
15
15
|
export const FieldButtonRoot = forwardRef<HTMLDivElement, FieldButtonRootProps>(
|
|
16
|
-
({ disabled, invalid, name, values, onValuesChange, ...otherProps }, ref) => {
|
|
17
|
-
const api = useFieldButton({ disabled, invalid, name, values, onValuesChange });
|
|
16
|
+
({ disabled, readOnly, invalid, name, values, onValuesChange, ...otherProps }, ref) => {
|
|
17
|
+
const api = useFieldButton({ disabled, readOnly, invalid, name, values, onValuesChange });
|
|
18
18
|
const mergedProps = mergeProps(api.rootProps, otherProps);
|
|
19
19
|
|
|
20
20
|
return (
|
|
@@ -39,6 +39,11 @@ function FieldButton(props: FieldButtonRootProps) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
describe("useFieldButton", () => {
|
|
42
|
+
global.CSS = {
|
|
43
|
+
// @ts-expect-error
|
|
44
|
+
supports: (_k, _v) => true,
|
|
45
|
+
};
|
|
46
|
+
|
|
42
47
|
it("should render the field button correctly", () => {
|
|
43
48
|
const { getByRole } = setUp(<FieldButton />);
|
|
44
49
|
const button = getByRole("button", { name: "Click me" });
|
|
@@ -103,6 +108,15 @@ describe("useFieldButton", () => {
|
|
|
103
108
|
expect(button).toHaveAttribute("aria-disabled", "true");
|
|
104
109
|
});
|
|
105
110
|
|
|
111
|
+
it("should have readOnly state when readOnly prop is true", () => {
|
|
112
|
+
const { getByRole } = setUp(<FieldButton readOnly />);
|
|
113
|
+
const button = getByRole("button", { name: "Click me" });
|
|
114
|
+
|
|
115
|
+
expect(button).toBeDisabled();
|
|
116
|
+
expect(button).toHaveAttribute("data-readonly");
|
|
117
|
+
expect(button).toHaveAttribute("aria-disabled", "true");
|
|
118
|
+
});
|
|
119
|
+
|
|
106
120
|
it("should have invalid state when invalid prop is true", () => {
|
|
107
121
|
const { getByRole } = setUp(<FieldButton invalid />);
|
|
108
122
|
const button = getByRole("button", { name: "Click me" });
|
|
@@ -158,6 +172,26 @@ describe("useFieldButton", () => {
|
|
|
158
172
|
expect(button).not.toHaveAttribute("data-active");
|
|
159
173
|
});
|
|
160
174
|
|
|
175
|
+
it("should not disable hidden inputs when readOnly (unlike disabled)", () => {
|
|
176
|
+
const { container } = setUp(<FieldButton readOnly values={["value1", "value2"]} />);
|
|
177
|
+
const hiddenInputs = container.querySelectorAll('input[type="hidden"]');
|
|
178
|
+
|
|
179
|
+
expect(hiddenInputs).toHaveLength(2);
|
|
180
|
+
expect(hiddenInputs[0]).not.toBeDisabled();
|
|
181
|
+
expect(hiddenInputs[1]).not.toBeDisabled();
|
|
182
|
+
expect(hiddenInputs[0]).toHaveValue("value1");
|
|
183
|
+
expect(hiddenInputs[1]).toHaveValue("value2");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should disable hidden inputs when disabled", () => {
|
|
187
|
+
const { container } = setUp(<FieldButton disabled values={["value1", "value2"]} />);
|
|
188
|
+
const hiddenInputs = container.querySelectorAll('input[type="hidden"]');
|
|
189
|
+
|
|
190
|
+
expect(hiddenInputs).toHaveLength(2);
|
|
191
|
+
expect(hiddenInputs[0]).toBeDisabled();
|
|
192
|
+
expect(hiddenInputs[1]).toBeDisabled();
|
|
193
|
+
});
|
|
194
|
+
|
|
161
195
|
it("should render without description and errorMessage", () => {
|
|
162
196
|
function MinimalFieldButton(props: FieldButtonRootProps) {
|
|
163
197
|
return (
|
|
@@ -222,6 +256,19 @@ describe("useFieldButton", () => {
|
|
|
222
256
|
expect(handleValuesChange).not.toHaveBeenCalled();
|
|
223
257
|
});
|
|
224
258
|
|
|
259
|
+
it("should hide clear button when readOnly", async () => {
|
|
260
|
+
const handleValuesChange = vi.fn();
|
|
261
|
+
const { getByText, user } = setUp(
|
|
262
|
+
<FieldButton readOnly values={["value1"]} onValuesChange={handleValuesChange} />,
|
|
263
|
+
);
|
|
264
|
+
const clearButton = getByText("Clear");
|
|
265
|
+
|
|
266
|
+
expect(clearButton).toHaveAttribute("hidden");
|
|
267
|
+
|
|
268
|
+
await user.click(clearButton);
|
|
269
|
+
expect(handleValuesChange).not.toHaveBeenCalled();
|
|
270
|
+
});
|
|
271
|
+
|
|
225
272
|
it("should not have active state when clear button is pressed", () => {
|
|
226
273
|
const { getByRole } = setUp(<FieldButton />);
|
|
227
274
|
const button = getByRole("button", { name: "Click me" });
|
package/src/useFieldButton.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ariaAttr, buttonProps, dataAttr, elementProps, inputProps } from "@seed-design/dom-utils";
|
|
2
2
|
import { useCallback, useId, useState } from "react";
|
|
3
3
|
import { getDescriptionId, getErrorMessageId } from "./dom";
|
|
4
|
+
import { useSupports } from "@seed-design/react-supports";
|
|
4
5
|
|
|
5
6
|
interface UseFieldButtonStateProps {
|
|
6
7
|
values?: string[];
|
|
@@ -57,14 +58,26 @@ export interface UseFieldButtonProps extends UseFieldButtonStateProps {
|
|
|
57
58
|
*/
|
|
58
59
|
invalid?: boolean;
|
|
59
60
|
|
|
61
|
+
/**
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
readOnly?: boolean;
|
|
65
|
+
|
|
60
66
|
name?: string;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
export type UseFieldButtonReturn = ReturnType<typeof useFieldButton>;
|
|
64
70
|
|
|
65
|
-
export function useFieldButton(
|
|
71
|
+
export function useFieldButton({
|
|
72
|
+
values: propValues,
|
|
73
|
+
onValuesChange,
|
|
74
|
+
disabled = false,
|
|
75
|
+
invalid = false,
|
|
76
|
+
readOnly = false,
|
|
77
|
+
name,
|
|
78
|
+
}: UseFieldButtonProps) {
|
|
66
79
|
const id = useId();
|
|
67
|
-
const
|
|
80
|
+
const isFocusVisibleSupported = useSupports("selector(:focus-visible)");
|
|
68
81
|
|
|
69
82
|
const {
|
|
70
83
|
values: stateValues,
|
|
@@ -96,6 +109,7 @@ export function useFieldButton(props: UseFieldButtonProps) {
|
|
|
96
109
|
"data-focus-visible": dataAttr(isFocusVisible),
|
|
97
110
|
"data-disabled": dataAttr(disabled),
|
|
98
111
|
"data-invalid": dataAttr(invalid),
|
|
112
|
+
"data-readonly": dataAttr(readOnly),
|
|
99
113
|
});
|
|
100
114
|
|
|
101
115
|
return {
|
|
@@ -103,6 +117,8 @@ export function useFieldButton(props: UseFieldButtonProps) {
|
|
|
103
117
|
active: isActive,
|
|
104
118
|
focused: isFocused,
|
|
105
119
|
invalid,
|
|
120
|
+
disabled,
|
|
121
|
+
readOnly,
|
|
106
122
|
|
|
107
123
|
setIsFocused,
|
|
108
124
|
setIsFocusVisible,
|
|
@@ -127,9 +143,9 @@ export function useFieldButton(props: UseFieldButtonProps) {
|
|
|
127
143
|
...stateProps,
|
|
128
144
|
|
|
129
145
|
type: "button",
|
|
130
|
-
disabled,
|
|
146
|
+
disabled: disabled || readOnly,
|
|
131
147
|
|
|
132
|
-
"aria-disabled": ariaAttr(disabled),
|
|
148
|
+
"aria-disabled": ariaAttr(disabled || readOnly),
|
|
133
149
|
"aria-describedby": ariaDescribedBy,
|
|
134
150
|
|
|
135
151
|
// note that pointerdown and pointerup are attached to the button, not the root
|
|
@@ -143,11 +159,15 @@ export function useFieldButton(props: UseFieldButtonProps) {
|
|
|
143
159
|
|
|
144
160
|
onBlur() {
|
|
145
161
|
setIsFocused(false);
|
|
146
|
-
|
|
162
|
+
if (isFocusVisibleSupported) {
|
|
163
|
+
setIsFocusVisible(false);
|
|
164
|
+
}
|
|
147
165
|
},
|
|
148
166
|
onFocus(event) {
|
|
149
167
|
setIsFocused(true);
|
|
150
|
-
|
|
168
|
+
if (isFocusVisibleSupported) {
|
|
169
|
+
setIsFocusVisible(event.target.matches(":focus-visible"));
|
|
170
|
+
}
|
|
151
171
|
},
|
|
152
172
|
}),
|
|
153
173
|
|
|
@@ -155,11 +175,11 @@ export function useFieldButton(props: UseFieldButtonProps) {
|
|
|
155
175
|
...stateProps,
|
|
156
176
|
|
|
157
177
|
type: "button",
|
|
158
|
-
disabled,
|
|
178
|
+
disabled: disabled || readOnly,
|
|
159
179
|
|
|
160
180
|
onClick: useCallback(() => setValues([]), [setValues]),
|
|
161
181
|
|
|
162
|
-
hidden: disabled,
|
|
182
|
+
hidden: disabled || readOnly,
|
|
163
183
|
}),
|
|
164
184
|
|
|
165
185
|
getHiddenInputProps: useCallback(
|
|
@@ -171,10 +191,11 @@ export function useFieldButton(props: UseFieldButtonProps) {
|
|
|
171
191
|
return inputProps({
|
|
172
192
|
type: "hidden",
|
|
173
193
|
value,
|
|
194
|
+
disabled, // disabled field button should not submit values, while readonly field button should submit values
|
|
174
195
|
name: name || id,
|
|
175
196
|
});
|
|
176
197
|
},
|
|
177
|
-
[stateValues, name, id],
|
|
198
|
+
[stateValues, name, id, disabled],
|
|
178
199
|
),
|
|
179
200
|
|
|
180
201
|
descriptionProps: elementProps({
|