@react-spectrum/button 3.14.1 → 3.16.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/dist/ar-AE.main.js +6 -0
- package/dist/ar-AE.main.js.map +1 -0
- package/dist/ar-AE.mjs +8 -0
- package/dist/ar-AE.module.js +8 -0
- package/dist/ar-AE.module.js.map +1 -0
- package/dist/bg-BG.main.js +6 -0
- package/dist/bg-BG.main.js.map +1 -0
- package/dist/bg-BG.mjs +8 -0
- package/dist/bg-BG.module.js +8 -0
- package/dist/bg-BG.module.js.map +1 -0
- package/dist/cs-CZ.main.js +6 -0
- package/dist/cs-CZ.main.js.map +1 -0
- package/dist/cs-CZ.mjs +8 -0
- package/dist/cs-CZ.module.js +8 -0
- package/dist/cs-CZ.module.js.map +1 -0
- package/dist/da-DK.main.js +6 -0
- package/dist/da-DK.main.js.map +1 -0
- package/dist/da-DK.mjs +8 -0
- package/dist/da-DK.module.js +8 -0
- package/dist/da-DK.module.js.map +1 -0
- package/dist/de-DE.main.js +6 -0
- package/dist/de-DE.main.js.map +1 -0
- package/dist/de-DE.mjs +8 -0
- package/dist/de-DE.module.js +8 -0
- package/dist/de-DE.module.js.map +1 -0
- package/dist/el-GR.main.js +6 -0
- package/dist/el-GR.main.js.map +1 -0
- package/dist/el-GR.mjs +8 -0
- package/dist/el-GR.module.js +8 -0
- package/dist/el-GR.module.js.map +1 -0
- package/dist/en-US.main.js +6 -0
- package/dist/en-US.main.js.map +1 -0
- package/dist/en-US.mjs +8 -0
- package/dist/en-US.module.js +8 -0
- package/dist/en-US.module.js.map +1 -0
- package/dist/es-ES.main.js +6 -0
- package/dist/es-ES.main.js.map +1 -0
- package/dist/es-ES.mjs +8 -0
- package/dist/es-ES.module.js +8 -0
- package/dist/es-ES.module.js.map +1 -0
- package/dist/et-EE.main.js +6 -0
- package/dist/et-EE.main.js.map +1 -0
- package/dist/et-EE.mjs +8 -0
- package/dist/et-EE.module.js +8 -0
- package/dist/et-EE.module.js.map +1 -0
- package/dist/fi-FI.main.js +6 -0
- package/dist/fi-FI.main.js.map +1 -0
- package/dist/fi-FI.mjs +8 -0
- package/dist/fi-FI.module.js +8 -0
- package/dist/fi-FI.module.js.map +1 -0
- package/dist/fr-FR.main.js +6 -0
- package/dist/fr-FR.main.js.map +1 -0
- package/dist/fr-FR.mjs +8 -0
- package/dist/fr-FR.module.js +8 -0
- package/dist/fr-FR.module.js.map +1 -0
- package/dist/he-IL.main.js +6 -0
- package/dist/he-IL.main.js.map +1 -0
- package/dist/he-IL.mjs +8 -0
- package/dist/he-IL.module.js +8 -0
- package/dist/he-IL.module.js.map +1 -0
- package/dist/hr-HR.main.js +6 -0
- package/dist/hr-HR.main.js.map +1 -0
- package/dist/hr-HR.mjs +8 -0
- package/dist/hr-HR.module.js +8 -0
- package/dist/hr-HR.module.js.map +1 -0
- package/dist/hu-HU.main.js +6 -0
- package/dist/hu-HU.main.js.map +1 -0
- package/dist/hu-HU.mjs +8 -0
- package/dist/hu-HU.module.js +8 -0
- package/dist/hu-HU.module.js.map +1 -0
- package/dist/import.mjs +86 -182
- package/dist/it-IT.main.js +6 -0
- package/dist/it-IT.main.js.map +1 -0
- package/dist/it-IT.mjs +8 -0
- package/dist/it-IT.module.js +8 -0
- package/dist/it-IT.module.js.map +1 -0
- package/dist/ja-JP.main.js +6 -0
- package/dist/ja-JP.main.js.map +1 -0
- package/dist/ja-JP.mjs +8 -0
- package/dist/ja-JP.module.js +8 -0
- package/dist/ja-JP.module.js.map +1 -0
- package/dist/ko-KR.main.js +6 -0
- package/dist/ko-KR.main.js.map +1 -0
- package/dist/ko-KR.mjs +8 -0
- package/dist/ko-KR.module.js +8 -0
- package/dist/ko-KR.module.js.map +1 -0
- package/dist/lt-LT.main.js +6 -0
- package/dist/lt-LT.main.js.map +1 -0
- package/dist/lt-LT.mjs +8 -0
- package/dist/lt-LT.module.js +8 -0
- package/dist/lt-LT.module.js.map +1 -0
- package/dist/lv-LV.main.js +6 -0
- package/dist/lv-LV.main.js.map +1 -0
- package/dist/lv-LV.mjs +8 -0
- package/dist/lv-LV.module.js +8 -0
- package/dist/lv-LV.module.js.map +1 -0
- package/dist/main.css +1771 -1
- package/dist/main.css.map +1 -0
- package/dist/main.js +84 -180
- package/dist/main.js.map +1 -1
- package/dist/module.js +86 -182
- package/dist/module.js.map +1 -1
- package/dist/nb-NO.main.js +6 -0
- package/dist/nb-NO.main.js.map +1 -0
- package/dist/nb-NO.mjs +8 -0
- package/dist/nb-NO.module.js +8 -0
- package/dist/nb-NO.module.js.map +1 -0
- package/dist/nl-NL.main.js +6 -0
- package/dist/nl-NL.main.js.map +1 -0
- package/dist/nl-NL.mjs +8 -0
- package/dist/nl-NL.module.js +8 -0
- package/dist/nl-NL.module.js.map +1 -0
- package/dist/pl-PL.main.js +6 -0
- package/dist/pl-PL.main.js.map +1 -0
- package/dist/pl-PL.mjs +8 -0
- package/dist/pl-PL.module.js +8 -0
- package/dist/pl-PL.module.js.map +1 -0
- package/dist/pt-BR.main.js +6 -0
- package/dist/pt-BR.main.js.map +1 -0
- package/dist/pt-BR.mjs +8 -0
- package/dist/pt-BR.module.js +8 -0
- package/dist/pt-BR.module.js.map +1 -0
- package/dist/pt-PT.main.js +6 -0
- package/dist/pt-PT.main.js.map +1 -0
- package/dist/pt-PT.mjs +8 -0
- package/dist/pt-PT.module.js +8 -0
- package/dist/pt-PT.module.js.map +1 -0
- package/dist/ro-RO.main.js +6 -0
- package/dist/ro-RO.main.js.map +1 -0
- package/dist/ro-RO.mjs +8 -0
- package/dist/ro-RO.module.js +8 -0
- package/dist/ro-RO.module.js.map +1 -0
- package/dist/ru-RU.main.js +6 -0
- package/dist/ru-RU.main.js.map +1 -0
- package/dist/ru-RU.mjs +8 -0
- package/dist/ru-RU.module.js +8 -0
- package/dist/ru-RU.module.js.map +1 -0
- package/dist/sk-SK.main.js +6 -0
- package/dist/sk-SK.main.js.map +1 -0
- package/dist/sk-SK.mjs +8 -0
- package/dist/sk-SK.module.js +8 -0
- package/dist/sk-SK.module.js.map +1 -0
- package/dist/sl-SI.main.js +6 -0
- package/dist/sl-SI.main.js.map +1 -0
- package/dist/sl-SI.mjs +8 -0
- package/dist/sl-SI.module.js +8 -0
- package/dist/sl-SI.module.js.map +1 -0
- package/dist/sr-SP.main.js +6 -0
- package/dist/sr-SP.main.js.map +1 -0
- package/dist/sr-SP.mjs +8 -0
- package/dist/sr-SP.module.js +8 -0
- package/dist/sr-SP.module.js.map +1 -0
- package/dist/sv-SE.main.js +6 -0
- package/dist/sv-SE.main.js.map +1 -0
- package/dist/sv-SE.mjs +8 -0
- package/dist/sv-SE.module.js +8 -0
- package/dist/sv-SE.module.js.map +1 -0
- package/dist/tr-TR.main.js +6 -0
- package/dist/tr-TR.main.js.map +1 -0
- package/dist/tr-TR.mjs +8 -0
- package/dist/tr-TR.module.js +8 -0
- package/dist/tr-TR.module.js.map +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/uk-UA.main.js +6 -0
- package/dist/uk-UA.main.js.map +1 -0
- package/dist/uk-UA.mjs +8 -0
- package/dist/uk-UA.module.js +8 -0
- package/dist/uk-UA.module.js.map +1 -0
- package/dist/zh-CN.main.js +6 -0
- package/dist/zh-CN.main.js.map +1 -0
- package/dist/zh-CN.mjs +8 -0
- package/dist/zh-CN.module.js +8 -0
- package/dist/zh-CN.module.js.map +1 -0
- package/dist/zh-TW.main.js +6 -0
- package/dist/zh-TW.main.js.map +1 -0
- package/dist/zh-TW.mjs +8 -0
- package/dist/zh-TW.module.js +8 -0
- package/dist/zh-TW.module.js.map +1 -0
- package/package.json +14 -15
- package/src/Button.tsx +55 -15
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 {isAppleDevice, isFirefox, 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
|
|
@@ -54,7 +54,7 @@ function Button<T extends ElementType = 'button'>(props: SpectrumButtonProps<T>,
|
|
54
54
|
props = useSlotProps(props, 'button');
|
55
55
|
props = disablePendingProps(props);
|
56
56
|
let {
|
57
|
-
elementType:
|
57
|
+
elementType: Element = 'button',
|
58
58
|
children,
|
59
59
|
variant,
|
60
60
|
style = variant === 'accent' || variant === 'cta' ? 'fill' : 'outline',
|
@@ -67,11 +67,20 @@ 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
|
70
|
+
let [isFocused, onFocusChange] = useState(false);
|
71
|
+
let {focusProps} = useFocus({onFocusChange, isDisabled});
|
72
|
+
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/button');
|
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 iconId = useId();
|
82
|
+
let textId = useId();
|
83
|
+
let spinnerId = useId();
|
75
84
|
|
76
85
|
useEffect(() => {
|
77
86
|
let timeout: ReturnType<typeof setTimeout>;
|
@@ -98,17 +107,26 @@ function Button<T extends ElementType = 'button'>(props: SpectrumButtonProps<T>,
|
|
98
107
|
staticColor = 'white';
|
99
108
|
}
|
100
109
|
|
110
|
+
const isPendingAriaLiveLabel = `${hasAriaLabel ? buttonProps['aria-label'] : ''} ${stringFormatter.format('pending')}`.trim();
|
111
|
+
const isPendingAriaLiveLabelledby = hasAriaLabel ? (buttonProps['aria-labelledby']?.replace(buttonId, spinnerId) ?? spinnerId) : `${hasIcon ? iconId : ''} ${hasLabel ? textId : ''} ${spinnerId}`.trim();
|
112
|
+
|
113
|
+
let ariaLive: 'off' | 'polite' | 'assertive' = 'polite';
|
114
|
+
if (isAppleDevice() && (!hasAriaLabel || isFirefox())) {
|
115
|
+
ariaLive = 'off';
|
116
|
+
}
|
101
117
|
return (
|
102
118
|
<FocusRing focusRingClass={classNames(styles, 'focus-ring')} autoFocus={autoFocus}>
|
103
|
-
<
|
119
|
+
<Element
|
104
120
|
{...styleProps}
|
105
|
-
{...mergeProps(buttonProps, hoverProps)}
|
121
|
+
{...mergeProps(buttonProps, hoverProps, focusProps)}
|
122
|
+
id={buttonId}
|
106
123
|
ref={domRef}
|
107
124
|
data-variant={variant}
|
108
125
|
data-style={style}
|
109
126
|
data-static-color={staticColor || undefined}
|
110
|
-
aria-disabled={isPending
|
111
|
-
aria-
|
127
|
+
aria-disabled={isPending ? 'true' : undefined}
|
128
|
+
aria-label={isPending ? isPendingAriaLiveLabel : buttonProps['aria-label']}
|
129
|
+
aria-labelledby={isPending ? isPendingAriaLiveLabelledby : buttonProps['aria-labelledby']}
|
112
130
|
className={
|
113
131
|
classNames(
|
114
132
|
styles,
|
@@ -126,24 +144,46 @@ function Button<T extends ElementType = 'button'>(props: SpectrumButtonProps<T>,
|
|
126
144
|
<SlotProvider
|
127
145
|
slots={{
|
128
146
|
icon: {
|
147
|
+
id: iconId,
|
129
148
|
size: 'S',
|
130
149
|
UNSAFE_className: classNames(styles, 'spectrum-Icon')
|
131
150
|
},
|
132
151
|
text: {
|
152
|
+
id: textId,
|
133
153
|
UNSAFE_className: classNames(styles, 'spectrum-Button-label')
|
134
154
|
}
|
135
155
|
}}>
|
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
156
|
{typeof children === 'string'
|
143
157
|
? <Text>{children}</Text>
|
144
158
|
: children}
|
159
|
+
{isPending && (
|
160
|
+
<div
|
161
|
+
aria-hidden="true"
|
162
|
+
style={{visibility: isProgressVisible ? 'visible' : 'hidden'}}
|
163
|
+
className={classNames(styles, 'spectrum-Button-circleLoader')}>
|
164
|
+
<ProgressCircle
|
165
|
+
aria-label={isPendingAriaLiveLabel}
|
166
|
+
isIndeterminate
|
167
|
+
size="S"
|
168
|
+
staticColor={staticColor} />
|
169
|
+
</div>
|
170
|
+
)}
|
171
|
+
{isPending &&
|
172
|
+
<>
|
173
|
+
<div aria-live={isFocused ? ariaLive : 'off'}>
|
174
|
+
{isProgressVisible &&
|
175
|
+
<div role="img" aria-labelledby={isPendingAriaLiveLabelledby} />
|
176
|
+
}
|
177
|
+
</div>
|
178
|
+
{/* Adding the element here with the same labels as the button itself causes aria-live to pick up the change in Safari.
|
179
|
+
Safari with VO unfortunately doesn't announce changes to *all* of its labels specifically for button
|
180
|
+
https://a11ysupport.io/tests/tech__html__button-name-change#assertion-aria-aria-label_attribute-convey_name_change-html-button_element-vo_macos-safari
|
181
|
+
The aria-live may cause extra announcements in other browsers. */}
|
182
|
+
<div id={spinnerId} role="img" aria-label={isPendingAriaLiveLabel} />
|
183
|
+
</>
|
184
|
+
}
|
145
185
|
</SlotProvider>
|
146
|
-
</
|
186
|
+
</Element>
|
147
187
|
</FocusRing>
|
148
188
|
);
|
149
189
|
}
|