@react-spectrum/button 3.0.0-nightly.2597 → 3.0.0-nightly.2602
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/dist/import.mjs +44 -244
- package/dist/main.css +1 -1
- package/dist/main.js +42 -242
- package/dist/main.js.map +1 -1
- package/dist/module.js +44 -244
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -16
- package/src/Button.tsx +40 -11
package/src/Button.tsx
CHANGED
@@ -22,14 +22,14 @@ import {FocusableRef} from '@react-types/shared';
|
|
22
22
|
import {FocusRing} from '@react-aria/focus';
|
23
23
|
// @ts-ignore
|
24
24
|
import intlMessages from '../intl/*.json';
|
25
|
-
import {mergeProps} from '@react-aria/utils';
|
25
|
+
import {mergeProps, useId} from '@react-aria/utils';
|
26
26
|
import {ProgressCircle} from '@react-spectrum/progress';
|
27
27
|
import React, {ElementType, ReactElement, useEffect, useState} from 'react';
|
28
28
|
import {SpectrumButtonProps} from '@react-types/button';
|
29
29
|
import styles from '@adobe/spectrum-css-temp/components/button/vars.css';
|
30
30
|
import {Text} from '@react-spectrum/text';
|
31
31
|
import {useButton} from '@react-aria/button';
|
32
|
-
import {useHover} from '@react-aria/interactions';
|
32
|
+
import {useFocus, useHover} from '@react-aria/interactions';
|
33
33
|
import {useLocalizedStringFormatter} from '@react-aria/i18n';
|
34
34
|
import {useProviderProps} from '@react-spectrum/provider';
|
35
35
|
|
@@ -67,11 +67,21 @@ function Button<T extends ElementType = 'button'>(props: SpectrumButtonProps<T>,
|
|
67
67
|
let domRef = useFocusableRef(ref);
|
68
68
|
let {buttonProps, isPressed} = useButton(props, domRef);
|
69
69
|
let {hoverProps, isHovered} = useHover({isDisabled});
|
70
|
+
let [isFocused, onFocusChange] = useState(false);
|
71
|
+
let {focusProps} = useFocus({onFocusChange, isDisabled});
|
70
72
|
let stringFormatter = useLocalizedStringFormatter(intlMessages);
|
71
73
|
let {styleProps} = useStyleProps(otherProps);
|
72
74
|
let hasLabel = useHasChild(`.${styles['spectrum-Button-label']}`, domRef);
|
73
75
|
let hasIcon = useHasChild(`.${styles['spectrum-Icon']}`, domRef);
|
76
|
+
// an aria label will block children and their labels from being read, this is undesirable for pending state
|
77
|
+
let hasAriaLabel = !!buttonProps['aria-label'] || !!buttonProps['aria-labelledby'];
|
74
78
|
let [isProgressVisible, setIsProgressVisible] = useState(false);
|
79
|
+
let backupButtonId = useId();
|
80
|
+
let buttonId = buttonProps.id || backupButtonId;
|
81
|
+
let spinnerId = useId();
|
82
|
+
let textId = useId();
|
83
|
+
let iconId = useId();
|
84
|
+
let auxLabelId = useId();
|
75
85
|
|
76
86
|
useEffect(() => {
|
77
87
|
let timeout: ReturnType<typeof setTimeout>;
|
@@ -102,13 +112,16 @@ function Button<T extends ElementType = 'button'>(props: SpectrumButtonProps<T>,
|
|
102
112
|
<FocusRing focusRingClass={classNames(styles, 'focus-ring')} autoFocus={autoFocus}>
|
103
113
|
<Element
|
104
114
|
{...styleProps}
|
105
|
-
{...mergeProps(buttonProps, hoverProps)}
|
115
|
+
{...mergeProps(buttonProps, hoverProps, focusProps)}
|
116
|
+
id={buttonId}
|
106
117
|
ref={domRef}
|
107
118
|
data-variant={variant}
|
108
119
|
data-style={style}
|
109
120
|
data-static-color={staticColor || undefined}
|
110
|
-
aria-disabled={isPending
|
111
|
-
aria-
|
121
|
+
aria-disabled={isPending ? 'true' : undefined}
|
122
|
+
aria-label={isPending ? undefined : buttonProps['aria-label']}
|
123
|
+
aria-labelledby={isPending ? undefined : buttonProps['aria-labelledby']}
|
124
|
+
aria-live={isPending && isFocused ? 'polite' : undefined}
|
112
125
|
className={
|
113
126
|
classNames(
|
114
127
|
styles,
|
@@ -126,22 +139,38 @@ function Button<T extends ElementType = 'button'>(props: SpectrumButtonProps<T>,
|
|
126
139
|
<SlotProvider
|
127
140
|
slots={{
|
128
141
|
icon: {
|
142
|
+
id: iconId,
|
129
143
|
size: 'S',
|
130
144
|
UNSAFE_className: classNames(styles, 'spectrum-Icon')
|
131
145
|
},
|
132
146
|
text: {
|
147
|
+
id: textId,
|
133
148
|
UNSAFE_className: classNames(styles, 'spectrum-Button-label')
|
134
149
|
}
|
135
150
|
}}>
|
136
|
-
{isProgressVisible && <ProgressCircle
|
137
|
-
aria-label={stringFormatter.format('loading')}
|
138
|
-
isIndeterminate
|
139
|
-
size="S"
|
140
|
-
UNSAFE_className={classNames(styles, 'spectrum-Button-circleLoader')}
|
141
|
-
staticColor={staticColor} />}
|
142
151
|
{typeof children === 'string'
|
143
152
|
? <Text>{children}</Text>
|
144
153
|
: children}
|
154
|
+
{isPending && <ProgressCircle
|
155
|
+
aria-hidden="true"
|
156
|
+
isIndeterminate
|
157
|
+
size="S"
|
158
|
+
UNSAFE_className={classNames(styles, 'spectrum-Button-circleLoader')}
|
159
|
+
UNSAFE_style={{visibility: isProgressVisible ? 'visible' : 'hidden'}}
|
160
|
+
staticColor={staticColor} />
|
161
|
+
}
|
162
|
+
{/* Adding the element here with the same labels as the button itself causes aria-live to pick up the change in Safari.
|
163
|
+
Safari with VO unfortunately doesn't announce changes to *all* of its labels specifically for button
|
164
|
+
https://a11ysupport.io/tests/tech__html__button-name-change#assertion-aria-aria-label_attribute-convey_name_change-html-button_element-vo_macos-safari
|
165
|
+
The aria-live does cause extra announcements in other browsers. */}
|
166
|
+
{isPending && hasAriaLabel &&
|
167
|
+
<div aria-hidden="true" id={auxLabelId} aria-label={buttonProps['aria-label']} aria-labelledby={buttonProps['aria-labelledby']?.replace(buttonId, auxLabelId)} />
|
168
|
+
}
|
169
|
+
{isPending && <div
|
170
|
+
id={spinnerId}
|
171
|
+
aria-label={stringFormatter.format('pending')}
|
172
|
+
aria-labelledby={`${hasAriaLabel ? '' : iconId} ${hasAriaLabel ? auxLabelId : textId} ${spinnerId}`} />
|
173
|
+
}
|
145
174
|
</SlotProvider>
|
146
175
|
</Element>
|
147
176
|
</FocusRing>
|