@react-spectrum/s2 3.0.0-nightly-5ed06068e-241105 → 3.0.0-nightly-09ccc53e7-241107
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/ActionButton.cjs +54 -11
- package/dist/ActionButton.cjs.map +1 -1
- package/dist/ActionButton.css +47 -3
- package/dist/ActionButton.css.map +1 -1
- package/dist/ActionButton.mjs +55 -12
- package/dist/ActionButton.mjs.map +1 -1
- package/dist/ActionButtonGroup.cjs +77 -0
- package/dist/ActionButtonGroup.cjs.map +1 -0
- package/dist/ActionButtonGroup.css +44 -0
- package/dist/ActionButtonGroup.css.map +1 -0
- package/dist/ActionButtonGroup.mjs +70 -0
- package/dist/ActionButtonGroup.mjs.map +1 -0
- package/dist/Badge.cjs +42 -42
- package/dist/Badge.css +35 -35
- package/dist/Badge.mjs +42 -42
- package/dist/Card.cjs +1 -1
- package/dist/Card.css +1 -1
- package/dist/Card.mjs +1 -1
- package/dist/Content.cjs +1 -0
- package/dist/Content.cjs.map +1 -1
- package/dist/Content.mjs +1 -0
- package/dist/Content.mjs.map +1 -1
- package/dist/ContextualHelp.cjs +1 -1
- package/dist/ContextualHelp.cjs.map +1 -1
- package/dist/ContextualHelp.css +32 -16
- package/dist/ContextualHelp.css.map +1 -1
- package/dist/ContextualHelp.mjs +1 -1
- package/dist/ContextualHelp.mjs.map +1 -1
- package/dist/IllustratedMessage.cjs +6 -2
- package/dist/IllustratedMessage.cjs.map +1 -1
- package/dist/IllustratedMessage.css +2 -2
- package/dist/IllustratedMessage.css.map +1 -1
- package/dist/IllustratedMessage.mjs +6 -2
- package/dist/IllustratedMessage.mjs.map +1 -1
- package/dist/InlineAlert.cjs +8 -8
- package/dist/InlineAlert.css +6 -6
- package/dist/InlineAlert.mjs +8 -8
- package/dist/Meter.cjs +4 -17
- package/dist/Meter.cjs.map +1 -1
- package/dist/Meter.css +7 -19
- package/dist/Meter.css.map +1 -1
- package/dist/Meter.mjs +4 -17
- package/dist/Meter.mjs.map +1 -1
- package/dist/Modal.cjs +1 -1
- package/dist/Modal.css +1 -1
- package/dist/Modal.mjs +1 -1
- package/dist/Picker.cjs +3 -0
- package/dist/Picker.cjs.map +1 -1
- package/dist/Picker.css +12 -0
- package/dist/Picker.css.map +1 -1
- package/dist/Picker.mjs +3 -0
- package/dist/Picker.mjs.map +1 -1
- package/dist/Popover.cjs +1 -1
- package/dist/Popover.css +1 -1
- package/dist/Popover.mjs +1 -1
- package/dist/ProgressBar.cjs +19 -3
- package/dist/ProgressBar.cjs.map +1 -1
- package/dist/ProgressBar.css +14 -0
- package/dist/ProgressBar.css.map +1 -1
- package/dist/ProgressBar.mjs +19 -3
- package/dist/ProgressBar.mjs.map +1 -1
- package/dist/Provider.cjs +1 -1
- package/dist/Provider.css +1 -1
- package/dist/Provider.mjs +1 -1
- package/dist/Radio.cjs +2 -2
- package/dist/Radio.cjs.map +1 -1
- package/dist/Radio.css +4 -8
- package/dist/Radio.css.map +1 -1
- package/dist/Radio.mjs +2 -2
- package/dist/Radio.mjs.map +1 -1
- package/dist/SegmentedControl.cjs +76 -62
- package/dist/SegmentedControl.cjs.map +1 -1
- package/dist/SegmentedControl.css +110 -69
- package/dist/SegmentedControl.css.map +1 -1
- package/dist/SegmentedControl.mjs +77 -63
- package/dist/SegmentedControl.mjs.map +1 -1
- package/dist/ToggleButton.cjs +13 -6
- package/dist/ToggleButton.cjs.map +1 -1
- package/dist/ToggleButton.css +16 -0
- package/dist/ToggleButton.css.map +1 -1
- package/dist/ToggleButton.mjs +14 -7
- package/dist/ToggleButton.mjs.map +1 -1
- package/dist/ToggleButtonGroup.cjs +54 -0
- package/dist/ToggleButtonGroup.cjs.map +1 -0
- package/dist/ToggleButtonGroup.mjs +48 -0
- package/dist/ToggleButtonGroup.mjs.map +1 -0
- package/dist/main.cjs +8 -0
- package/dist/main.cjs.map +1 -1
- package/dist/module.mjs +5 -1
- package/dist/module.mjs.map +1 -1
- package/dist/types.d.ts +57 -12
- package/dist/types.d.ts.map +1 -1
- package/package.json +17 -17
- package/src/ActionButton.tsx +88 -8
- package/src/ActionButtonGroup.tsx +106 -0
- package/src/Content.tsx +2 -1
- package/src/ContextualHelp.tsx +1 -1
- package/src/IllustratedMessage.tsx +1 -3
- package/src/Meter.tsx +4 -4
- package/src/Picker.tsx +10 -1
- package/src/ProgressBar.tsx +20 -3
- package/src/Radio.tsx +1 -3
- package/src/SegmentedControl.tsx +56 -45
- package/src/ToggleButton.tsx +23 -7
- package/src/ToggleButtonGroup.tsx +55 -0
- package/src/index.ts +4 -0
- package/style/dist/spectrum-theme.cjs +5 -0
- package/style/dist/spectrum-theme.cjs.map +1 -1
- package/style/dist/spectrum-theme.mjs +5 -0
- package/style/dist/spectrum-theme.mjs.map +1 -1
- package/style/dist/types.d.ts +2 -2
- package/style/dist/types.d.ts.map +1 -1
- package/style/spectrum-theme.ts +5 -0
package/src/ActionButton.tsx
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import {ActionButtonGroupContext} from './ActionButtonGroup';
|
|
13
14
|
import {baseColor, focusRing, fontRelative, style} from '../style' with { type: 'macro' };
|
|
14
|
-
import {ButtonProps, ButtonRenderProps, ContextValue, OverlayTriggerStateContext, Provider, Button as RACButton} from 'react-aria-components';
|
|
15
|
+
import {ButtonProps, ButtonRenderProps, ContextValue, OverlayTriggerStateContext, Provider, Button as RACButton, useSlottedContext} from 'react-aria-components';
|
|
15
16
|
import {centerBaseline} from './CenterBaseline';
|
|
16
17
|
import {createContext, forwardRef, ReactNode, useContext} from 'react';
|
|
17
18
|
import {FocusableRef, FocusableRefValue} from '@react-types/shared';
|
|
@@ -44,18 +45,32 @@ interface ToggleButtonStyleProps {
|
|
|
44
45
|
isEmphasized?: boolean
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
interface ActionGroupItemStyleProps {
|
|
49
|
+
density?: 'regular' | 'compact',
|
|
50
|
+
orientation?: 'horizontal' | 'vertical',
|
|
51
|
+
isJustified?: boolean
|
|
52
|
+
}
|
|
53
|
+
|
|
47
54
|
export interface ActionButtonProps extends Omit<ButtonProps, 'className' | 'style' | 'children' | 'onHover' | 'onHoverStart' | 'onHoverEnd' | 'onHoverChange' | 'isPending'>, StyleProps, ActionButtonStyleProps {
|
|
48
55
|
/** The content to display in the ActionButton. */
|
|
49
56
|
children?: ReactNode
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
// These styles handle both ActionButton and ToggleButton
|
|
53
|
-
|
|
60
|
+
const iconOnly = ':has([slot=icon]):not(:has([data-rsp-slot=text]))';
|
|
61
|
+
export const btnStyles = style<ButtonRenderProps & ActionButtonStyleProps & ToggleButtonStyleProps & ActionGroupItemStyleProps>({
|
|
54
62
|
...focusRing(),
|
|
55
63
|
display: 'flex',
|
|
56
64
|
alignItems: 'center',
|
|
57
65
|
justifyContent: 'center',
|
|
58
66
|
columnGap: 'text-to-visual',
|
|
67
|
+
flexShrink: 0,
|
|
68
|
+
flexGrow: {
|
|
69
|
+
isJustified: 1
|
|
70
|
+
},
|
|
71
|
+
flexBasis: {
|
|
72
|
+
isJustified: 0
|
|
73
|
+
},
|
|
59
74
|
font: 'control',
|
|
60
75
|
fontWeight: 'medium',
|
|
61
76
|
userSelect: 'none',
|
|
@@ -159,17 +174,69 @@ export const btnStyles = style<ButtonRenderProps & ActionButtonStyleProps & Togg
|
|
|
159
174
|
borderStyle: 'none',
|
|
160
175
|
paddingX: {
|
|
161
176
|
default: 'edge-to-text',
|
|
162
|
-
|
|
177
|
+
[iconOnly]: 0
|
|
163
178
|
},
|
|
164
179
|
paddingY: 0,
|
|
165
|
-
|
|
180
|
+
borderTopStartRadius: {
|
|
181
|
+
default: 'control',
|
|
182
|
+
density: {
|
|
183
|
+
compact: {
|
|
184
|
+
default: 'none',
|
|
185
|
+
':first-child': 'control'
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
borderTopEndRadius: {
|
|
190
|
+
default: 'control',
|
|
191
|
+
density: {
|
|
192
|
+
compact: {
|
|
193
|
+
default: 'none',
|
|
194
|
+
orientation: {
|
|
195
|
+
horizontal: {
|
|
196
|
+
':last-child': 'control'
|
|
197
|
+
},
|
|
198
|
+
vertical: {
|
|
199
|
+
':first-child': 'control'
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
borderBottomStartRadius: {
|
|
206
|
+
default: 'control',
|
|
207
|
+
density: {
|
|
208
|
+
compact: {
|
|
209
|
+
default: 'none',
|
|
210
|
+
orientation: {
|
|
211
|
+
horizontal: {
|
|
212
|
+
':first-child': 'control'
|
|
213
|
+
},
|
|
214
|
+
vertical: {
|
|
215
|
+
':last-child': 'control'
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
borderBottomEndRadius: {
|
|
222
|
+
default: 'control',
|
|
223
|
+
density: {
|
|
224
|
+
compact: {
|
|
225
|
+
default: 'none',
|
|
226
|
+
':last-child': 'control'
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
},
|
|
166
230
|
'--iconMargin': {
|
|
167
231
|
type: 'marginTop',
|
|
168
232
|
value: {
|
|
169
233
|
default: fontRelative(-2),
|
|
170
|
-
|
|
234
|
+
[iconOnly]: 0
|
|
171
235
|
}
|
|
172
236
|
},
|
|
237
|
+
zIndex: {
|
|
238
|
+
isFocusVisible: 2
|
|
239
|
+
},
|
|
173
240
|
disableTapHighlight: true
|
|
174
241
|
}, getAllowedOverrides());
|
|
175
242
|
|
|
@@ -180,19 +247,32 @@ function ActionButton(props: ActionButtonProps, ref: FocusableRef<HTMLButtonElem
|
|
|
180
247
|
props = useFormProps(props as any);
|
|
181
248
|
let domRef = useFocusableRef(ref);
|
|
182
249
|
let overlayTriggerState = useContext(OverlayTriggerStateContext);
|
|
250
|
+
let {
|
|
251
|
+
density = 'regular',
|
|
252
|
+
isJustified,
|
|
253
|
+
orientation = 'horizontal',
|
|
254
|
+
staticColor = props.staticColor,
|
|
255
|
+
isQuiet = props.isQuiet,
|
|
256
|
+
size = props.size || 'M',
|
|
257
|
+
isDisabled = props.isDisabled
|
|
258
|
+
} = useSlottedContext(ActionButtonGroupContext) || {};
|
|
183
259
|
|
|
184
260
|
return (
|
|
185
261
|
<RACButton
|
|
186
262
|
{...props}
|
|
263
|
+
isDisabled={isDisabled}
|
|
187
264
|
ref={domRef}
|
|
188
265
|
style={pressScale(domRef, props.UNSAFE_style)}
|
|
189
266
|
className={renderProps => (props.UNSAFE_className || '') + btnStyles({
|
|
190
267
|
...renderProps,
|
|
191
268
|
// Retain hover styles when an overlay is open.
|
|
192
269
|
isHovered: renderProps.isHovered || overlayTriggerState?.isOpen || false,
|
|
193
|
-
staticColor
|
|
194
|
-
size
|
|
195
|
-
isQuiet
|
|
270
|
+
staticColor,
|
|
271
|
+
size,
|
|
272
|
+
isQuiet,
|
|
273
|
+
density,
|
|
274
|
+
isJustified,
|
|
275
|
+
orientation
|
|
196
276
|
}, props.styles)}>
|
|
197
277
|
<Provider
|
|
198
278
|
values={[
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {ContextValue, SlotProps, Toolbar} from 'react-aria-components';
|
|
14
|
+
import {createContext, ForwardedRef, forwardRef, ReactNode} from 'react';
|
|
15
|
+
import {getAllowedOverrides, StylesPropWithHeight, UnsafeStyles} from './style-utils' with {type: 'macro'};
|
|
16
|
+
import {style} from '../style' with {type: 'macro'};
|
|
17
|
+
import {useSpectrumContextProps} from './useSpectrumContextProps';
|
|
18
|
+
|
|
19
|
+
export interface ActionButtonGroupProps extends UnsafeStyles, SlotProps {
|
|
20
|
+
/** Spectrum-defined styles, returned by the `style()` macro. */
|
|
21
|
+
styles?: StylesPropWithHeight,
|
|
22
|
+
/** The children of the group. */
|
|
23
|
+
children: ReactNode,
|
|
24
|
+
/**
|
|
25
|
+
* Size of the buttons.
|
|
26
|
+
* @default "M"
|
|
27
|
+
*/
|
|
28
|
+
size?: 'XS' | 'S' | 'M' | 'L' | 'XL',
|
|
29
|
+
/**
|
|
30
|
+
* Spacing between the buttons.
|
|
31
|
+
* @default "regular"
|
|
32
|
+
*/
|
|
33
|
+
density?: 'compact' | 'regular',
|
|
34
|
+
/** Whether the button should be displayed with a [quiet style](https://spectrum.adobe.com/page/action-button/#Quiet). */
|
|
35
|
+
isQuiet?: boolean,
|
|
36
|
+
/** Whether the buttons should divide the container width equally. */
|
|
37
|
+
isJustified?: boolean,
|
|
38
|
+
/** Whether the button should be displayed with an [emphasized style](https://spectrum.adobe.com/page/action-button/#Emphasis). */
|
|
39
|
+
staticColor?: 'white' | 'black',
|
|
40
|
+
/**
|
|
41
|
+
* The axis the group should align with.
|
|
42
|
+
* @default 'horizontal'
|
|
43
|
+
*/
|
|
44
|
+
orientation?: 'horizontal' | 'vertical',
|
|
45
|
+
/** Whether the group is disabled. */
|
|
46
|
+
isDisabled?: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const actionGroupStyle = style({
|
|
50
|
+
display: 'flex',
|
|
51
|
+
flexDirection: {
|
|
52
|
+
orientation: {
|
|
53
|
+
horizontal: 'row',
|
|
54
|
+
vertical: 'column'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
gap: {
|
|
58
|
+
density: {
|
|
59
|
+
compact: 2,
|
|
60
|
+
regular: {
|
|
61
|
+
size: {
|
|
62
|
+
XS: 4,
|
|
63
|
+
S: 4,
|
|
64
|
+
M: 8,
|
|
65
|
+
L: 8,
|
|
66
|
+
XL: 8
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}, getAllowedOverrides({height: true}));
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
export const ActionButtonGroupContext = createContext<ContextValue<ActionButtonGroupProps, HTMLDivElement>>(null);
|
|
75
|
+
|
|
76
|
+
function ActionButtonGroup(props: ActionButtonGroupProps, ref: ForwardedRef<HTMLDivElement>) {
|
|
77
|
+
[props, ref] = useSpectrumContextProps(props, ref, ActionButtonGroupContext);
|
|
78
|
+
let {
|
|
79
|
+
density = 'regular',
|
|
80
|
+
size = 'M',
|
|
81
|
+
orientation = 'horizontal',
|
|
82
|
+
isJustified,
|
|
83
|
+
children,
|
|
84
|
+
UNSAFE_className = '',
|
|
85
|
+
UNSAFE_style,
|
|
86
|
+
styles
|
|
87
|
+
} = props;
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<Toolbar
|
|
91
|
+
{...props}
|
|
92
|
+
ref={ref}
|
|
93
|
+
style={UNSAFE_style}
|
|
94
|
+
className={UNSAFE_className + actionGroupStyle({size, density, orientation, isJustified}, styles)}>
|
|
95
|
+
<ActionButtonGroupContext.Provider value={props}>
|
|
96
|
+
{children}
|
|
97
|
+
</ActionButtonGroupContext.Provider>
|
|
98
|
+
</Toolbar>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* An ActionButtonGroup is a grouping of related ActionButtons.
|
|
104
|
+
*/
|
|
105
|
+
const _ActionButtonGroup = forwardRef(ActionButtonGroup);
|
|
106
|
+
export {_ActionButtonGroup as ActionButtonGroup};
|
package/src/Content.tsx
CHANGED
|
@@ -120,7 +120,8 @@ function Text(props: ContentProps, ref: DOMRef) {
|
|
|
120
120
|
inert={isSkeleton ? 'true' : undefined}
|
|
121
121
|
className={UNSAFE_className + styles}
|
|
122
122
|
style={UNSAFE_style}
|
|
123
|
-
slot={slot || undefined}
|
|
123
|
+
slot={slot || undefined}
|
|
124
|
+
data-rsp-slot="text">
|
|
124
125
|
{children}
|
|
125
126
|
</TextAria>
|
|
126
127
|
);
|
package/src/ContextualHelp.tsx
CHANGED
|
@@ -101,7 +101,7 @@ function ContextualHelp(props: ContextualHelpProps, ref: FocusableRef<HTMLButton
|
|
|
101
101
|
crossOffset={crossOffset}
|
|
102
102
|
hideArrow
|
|
103
103
|
UNSAFE_className={popover}>
|
|
104
|
-
<RACDialog className={mergeStyles(dialogInner, style({borderRadius: 'none'}))}>
|
|
104
|
+
<RACDialog className={mergeStyles(dialogInner, style({borderRadius: 'none', margin: -24, padding: 24}))}>
|
|
105
105
|
<Provider
|
|
106
106
|
values={[
|
|
107
107
|
[TextContext, {
|
|
@@ -114,9 +114,7 @@ const illustration = style<IllustratedMessageStyleProps & {isInDropZone?: boolea
|
|
|
114
114
|
'--iconPrimary': {
|
|
115
115
|
type: 'color',
|
|
116
116
|
value: {
|
|
117
|
-
|
|
118
|
-
default: 'gray-800',
|
|
119
|
-
isInDropZone: 'gray-500', // neutral doesn't seem to match the color in designs, opted for gray-500 instead
|
|
117
|
+
default: 'neutral',
|
|
120
118
|
isDropTarget: 'accent'
|
|
121
119
|
}
|
|
122
120
|
}
|
package/src/Meter.tsx
CHANGED
|
@@ -82,11 +82,11 @@ const fillStyles = style<MeterStyleProps>({
|
|
|
82
82
|
borderStyle: 'none',
|
|
83
83
|
borderRadius: 'full',
|
|
84
84
|
backgroundColor: {
|
|
85
|
-
default: 'informative',
|
|
85
|
+
default: 'informative-visual',
|
|
86
86
|
variant: {
|
|
87
|
-
positive: 'positive',
|
|
88
|
-
notice: 'notice',
|
|
89
|
-
negative: 'negative'
|
|
87
|
+
positive: 'positive-visual',
|
|
88
|
+
notice: 'notice-visual',
|
|
89
|
+
negative: 'negative-visual'
|
|
90
90
|
},
|
|
91
91
|
staticColor: {
|
|
92
92
|
white: {
|
package/src/Picker.tsx
CHANGED
|
@@ -122,7 +122,16 @@ const inputButton = style<PickerButtonProps | AriaSelectRenderProps>({
|
|
|
122
122
|
font: 'control',
|
|
123
123
|
display: 'flex',
|
|
124
124
|
textAlign: 'start',
|
|
125
|
-
borderStyle:
|
|
125
|
+
borderStyle: {
|
|
126
|
+
default: 'none',
|
|
127
|
+
forcedColors: 'solid'
|
|
128
|
+
},
|
|
129
|
+
borderColor: {
|
|
130
|
+
forcedColors: {
|
|
131
|
+
default: 'ButtonText',
|
|
132
|
+
isDisabled: 'GrayText'
|
|
133
|
+
}
|
|
134
|
+
},
|
|
126
135
|
borderRadius: 'control',
|
|
127
136
|
alignItems: 'center',
|
|
128
137
|
height: 'control',
|
package/src/ProgressBar.tsx
CHANGED
|
@@ -24,6 +24,7 @@ import {keyframes} from '../style/style-macro' with {type: 'macro'};
|
|
|
24
24
|
import {mergeStyles} from '../style/runtime';
|
|
25
25
|
import {size, style} from '../style' with {type: 'macro'};
|
|
26
26
|
import {useDOMRef} from '@react-spectrum/utils';
|
|
27
|
+
import {useLocale} from '@react-aria/i18n';
|
|
27
28
|
import {useSpectrumContextProps} from './useSpectrumContextProps';
|
|
28
29
|
|
|
29
30
|
interface ProgressBarStyleProps {
|
|
@@ -56,7 +57,7 @@ export interface ProgressBarProps extends Omit<AriaProgressBarProps, 'children'
|
|
|
56
57
|
|
|
57
58
|
export const ProgressBarContext = createContext<ContextValue<ProgressBarProps, DOMRefValue<HTMLDivElement>>>(null);
|
|
58
59
|
|
|
59
|
-
const
|
|
60
|
+
const indeterminateLTR = keyframes(`
|
|
60
61
|
0% {
|
|
61
62
|
transform: translateX(-70%) scaleX(0.7);
|
|
62
63
|
}
|
|
@@ -65,6 +66,15 @@ const indeterminate = keyframes(`
|
|
|
65
66
|
}
|
|
66
67
|
`);
|
|
67
68
|
|
|
69
|
+
const indeterminateRTL = keyframes(`
|
|
70
|
+
0% {
|
|
71
|
+
transform: translateX(100%) scaleX(0.7);
|
|
72
|
+
}
|
|
73
|
+
100% {
|
|
74
|
+
transform: translateX(-70%) scaleX(0.7);
|
|
75
|
+
}
|
|
76
|
+
`);
|
|
77
|
+
|
|
68
78
|
const wrapper = style({
|
|
69
79
|
...bar(),
|
|
70
80
|
gridTemplateColumns: {
|
|
@@ -151,7 +161,12 @@ const fill = style<ProgressBarStyleProps>({
|
|
|
151
161
|
});
|
|
152
162
|
|
|
153
163
|
const indeterminateAnimation = style({
|
|
154
|
-
animation:
|
|
164
|
+
animation: {
|
|
165
|
+
direction: {
|
|
166
|
+
ltr: indeterminateLTR,
|
|
167
|
+
rtl: indeterminateRTL
|
|
168
|
+
}
|
|
169
|
+
},
|
|
155
170
|
animationDuration: 1000,
|
|
156
171
|
animationIterationCount: 'infinite',
|
|
157
172
|
animationTimingFunction: 'in-out',
|
|
@@ -170,6 +185,8 @@ function ProgressBar(props: ProgressBarProps, ref: DOMRef<HTMLDivElement>) {
|
|
|
170
185
|
UNSAFE_className = ''
|
|
171
186
|
} = props;
|
|
172
187
|
let domRef = useDOMRef(ref);
|
|
188
|
+
let {direction} = useLocale();
|
|
189
|
+
|
|
173
190
|
return (
|
|
174
191
|
<AriaProgressBar
|
|
175
192
|
{...props}
|
|
@@ -182,7 +199,7 @@ function ProgressBar(props: ProgressBarProps, ref: DOMRef<HTMLDivElement>) {
|
|
|
182
199
|
{label && !isIndeterminate && <span className={valueStyles({size, labelAlign: 'end', staticColor})}>{valueText}</span>}
|
|
183
200
|
<div className={trackStyles({...props})}>
|
|
184
201
|
<div
|
|
185
|
-
className={mergeStyles(fill({...props, staticColor}), (isIndeterminate ? indeterminateAnimation : null))}
|
|
202
|
+
className={mergeStyles(fill({...props, staticColor}), (isIndeterminate ? indeterminateAnimation({direction}) : null))}
|
|
186
203
|
style={{width: isIndeterminate ? undefined : percentage + '%'}} />
|
|
187
204
|
</div>
|
|
188
205
|
</>
|
package/src/Radio.tsx
CHANGED
|
@@ -74,9 +74,7 @@ const circle = style<RenderProps>({
|
|
|
74
74
|
display: 'flex',
|
|
75
75
|
alignItems: 'center',
|
|
76
76
|
justifyContent: 'center',
|
|
77
|
-
transition: '
|
|
78
|
-
transitionDuration: 250,
|
|
79
|
-
transitionTimingFunction: 'in-out',
|
|
77
|
+
transition: 'default',
|
|
80
78
|
borderRadius: 'full',
|
|
81
79
|
borderStyle: 'solid',
|
|
82
80
|
boxSizing: 'border-box',
|
package/src/SegmentedControl.tsx
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {AriaLabelingProps, DOMRef, DOMRefValue, FocusableRef} from '@react-types/shared';
|
|
13
|
+
import {AriaLabelingProps, DOMRef, DOMRefValue, FocusableRef, Key} from '@react-types/shared';
|
|
14
14
|
import {centerBaseline} from './CenterBaseline';
|
|
15
|
-
import {ContextValue, DEFAULT_SLOT, Provider, TextContext as RACTextContext,
|
|
15
|
+
import {ContextValue, DEFAULT_SLOT, Provider, TextContext as RACTextContext, SlotProps, ToggleButton, ToggleButtonGroup, ToggleGroupStateContext} from 'react-aria-components';
|
|
16
16
|
import {createContext, forwardRef, ReactNode, RefObject, useCallback, useContext, useRef} from 'react';
|
|
17
17
|
import {focusRing, size, style} from '../style' with {type: 'macro'};
|
|
18
18
|
import {getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'};
|
|
@@ -32,12 +32,14 @@ export interface SegmentedControlProps extends AriaLabelingProps, StyleProps, Sl
|
|
|
32
32
|
* Whether the segmented control is disabled.
|
|
33
33
|
*/
|
|
34
34
|
isDisabled?: boolean,
|
|
35
|
+
/** Whether the items should divide the container width equally. */
|
|
36
|
+
isJustified?: boolean,
|
|
35
37
|
/** The id of the currently selected item (controlled). */
|
|
36
|
-
selectedKey?:
|
|
38
|
+
selectedKey?: Key | null,
|
|
37
39
|
/** The id of the initial selected item (uncontrolled). */
|
|
38
|
-
defaultSelectedKey?:
|
|
40
|
+
defaultSelectedKey?: Key,
|
|
39
41
|
/** Handler that is called when the selection changes. */
|
|
40
|
-
onSelectionChange?: (id:
|
|
42
|
+
onSelectionChange?: (id: Key) => void
|
|
41
43
|
}
|
|
42
44
|
export interface SegmentedControlItemProps extends AriaLabelingProps, StyleProps {
|
|
43
45
|
/**
|
|
@@ -45,25 +47,27 @@ export interface SegmentedControlItemProps extends AriaLabelingProps, StyleProps
|
|
|
45
47
|
*/
|
|
46
48
|
children: ReactNode,
|
|
47
49
|
/** The id of the item, matching the value used in SegmentedControl's `selectedKey` prop. */
|
|
48
|
-
id:
|
|
50
|
+
id: Key,
|
|
49
51
|
/** Whether the item is disabled or not. */
|
|
50
52
|
isDisabled?: boolean
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
export const SegmentedControlContext = createContext<ContextValue<SegmentedControlProps, DOMRefValue<HTMLDivElement>>>(null);
|
|
54
56
|
|
|
55
|
-
const segmentedControl = style
|
|
56
|
-
font: 'control',
|
|
57
|
+
const segmentedControl = style({
|
|
57
58
|
display: 'flex',
|
|
59
|
+
gap: 4,
|
|
58
60
|
backgroundColor: 'gray-100',
|
|
59
|
-
borderRadius: '
|
|
60
|
-
width: '
|
|
61
|
+
borderRadius: 'default',
|
|
62
|
+
width: 'fit'
|
|
61
63
|
}, getAllowedOverrides());
|
|
62
64
|
|
|
63
65
|
const controlItem = style({
|
|
66
|
+
...focusRing(),
|
|
64
67
|
position: 'relative',
|
|
65
68
|
display: 'flex',
|
|
66
69
|
forcedColorAdjust: 'none',
|
|
70
|
+
font: 'control',
|
|
67
71
|
color: {
|
|
68
72
|
default: 'gray-700',
|
|
69
73
|
isHovered: 'neutral-subdued',
|
|
@@ -78,17 +82,25 @@ const controlItem = style({
|
|
|
78
82
|
// TODO: update this padding for icon-only items when we introduce the non-track style back
|
|
79
83
|
paddingX: {
|
|
80
84
|
default: 'edge-to-text',
|
|
81
|
-
':has([slot=icon]:
|
|
85
|
+
':has([slot=icon]):not(:has([data-rsp-slot=text]))': size(6)
|
|
82
86
|
},
|
|
83
87
|
height: 32,
|
|
84
88
|
alignItems: 'center',
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
flexGrow: {
|
|
90
|
+
isJustified: 1
|
|
91
|
+
},
|
|
92
|
+
flexBasis: {
|
|
93
|
+
isJustified: 0
|
|
94
|
+
},
|
|
87
95
|
flexShrink: 0,
|
|
88
96
|
minWidth: 0,
|
|
89
97
|
justifyContent: 'center',
|
|
90
98
|
whiteSpace: 'nowrap',
|
|
91
99
|
disableTapHighlight: true,
|
|
100
|
+
userSelect: 'none',
|
|
101
|
+
backgroundColor: 'transparent',
|
|
102
|
+
borderStyle: 'none',
|
|
103
|
+
borderRadius: 'default',
|
|
92
104
|
'--iconPrimary': {
|
|
93
105
|
type: 'fill',
|
|
94
106
|
value: 'currentColor'
|
|
@@ -96,7 +108,6 @@ const controlItem = style({
|
|
|
96
108
|
}, getAllowedOverrides());
|
|
97
109
|
|
|
98
110
|
const slider = style({
|
|
99
|
-
...focusRing(),
|
|
100
111
|
backgroundColor: {
|
|
101
112
|
default: 'gray-25',
|
|
102
113
|
forcedColors: {
|
|
@@ -123,17 +134,19 @@ const slider = style({
|
|
|
123
134
|
});
|
|
124
135
|
|
|
125
136
|
interface InternalSegmentedControlContextProps {
|
|
126
|
-
register?: (value:
|
|
137
|
+
register?: (value: Key, isDisabled?: boolean) => void,
|
|
127
138
|
prevRef?: RefObject<DOMRect | null>,
|
|
128
|
-
currentSelectedRef?: RefObject<HTMLDivElement | null
|
|
139
|
+
currentSelectedRef?: RefObject<HTMLDivElement | null>,
|
|
140
|
+
isJustified?: boolean
|
|
129
141
|
}
|
|
130
142
|
|
|
131
143
|
interface DefaultSelectionTrackProps {
|
|
132
|
-
defaultValue?:
|
|
133
|
-
value?:
|
|
144
|
+
defaultValue?: Key | null,
|
|
145
|
+
value?: Key | null,
|
|
134
146
|
children?: ReactNode,
|
|
135
147
|
prevRef: RefObject<DOMRect | null>,
|
|
136
|
-
currentSelectedRef: RefObject<HTMLDivElement | null
|
|
148
|
+
currentSelectedRef: RefObject<HTMLDivElement | null>,
|
|
149
|
+
isJustified?: boolean
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
const InternalSegmentedControlContext = createContext<InternalSegmentedControlContextProps>({});
|
|
@@ -150,63 +163,63 @@ function SegmentedControl(props: SegmentedControlProps, ref: DOMRef<HTMLDivEleme
|
|
|
150
163
|
let prevRef = useRef<DOMRect>(null);
|
|
151
164
|
let currentSelectedRef = useRef<HTMLDivElement>(null);
|
|
152
165
|
|
|
153
|
-
let onChange = (
|
|
166
|
+
let onChange = (values: Set<Key>) => {
|
|
154
167
|
if (currentSelectedRef.current) {
|
|
155
168
|
prevRef.current = currentSelectedRef?.current.getBoundingClientRect();
|
|
156
169
|
}
|
|
157
170
|
|
|
158
171
|
if (onSelectionChange) {
|
|
159
|
-
onSelectionChange(value);
|
|
172
|
+
onSelectionChange(values.values().next().value);
|
|
160
173
|
}
|
|
161
174
|
};
|
|
162
175
|
|
|
163
176
|
return (
|
|
164
|
-
<
|
|
177
|
+
<ToggleButtonGroup
|
|
165
178
|
{...props}
|
|
166
|
-
|
|
167
|
-
|
|
179
|
+
selectedKeys={selectedKey != null ? [selectedKey] : undefined}
|
|
180
|
+
defaultSelectedKeys={defaultSelectedKey != null ? [defaultSelectedKey] : undefined}
|
|
181
|
+
disallowEmptySelection
|
|
168
182
|
ref={domRef}
|
|
169
183
|
orientation="horizontal"
|
|
170
184
|
style={props.UNSAFE_style}
|
|
171
|
-
|
|
172
|
-
className={(props.UNSAFE_className || '') + segmentedControl(
|
|
185
|
+
onSelectionChange={onChange}
|
|
186
|
+
className={(props.UNSAFE_className || '') + segmentedControl(null, props.styles)}
|
|
173
187
|
aria-label={props['aria-label']}>
|
|
174
|
-
<DefaultSelectionTracker defaultValue={defaultSelectedKey} value={selectedKey} prevRef={prevRef} currentSelectedRef={currentSelectedRef}>
|
|
188
|
+
<DefaultSelectionTracker defaultValue={defaultSelectedKey} value={selectedKey} prevRef={prevRef} currentSelectedRef={currentSelectedRef} isJustified={props.isJustified}>
|
|
175
189
|
{props.children}
|
|
176
190
|
</DefaultSelectionTracker>
|
|
177
|
-
</
|
|
191
|
+
</ToggleButtonGroup>
|
|
178
192
|
);
|
|
179
193
|
}
|
|
180
194
|
|
|
181
195
|
function DefaultSelectionTracker(props: DefaultSelectionTrackProps) {
|
|
182
|
-
let state = useContext(
|
|
196
|
+
let state = useContext(ToggleGroupStateContext);
|
|
183
197
|
let isRegistered = useRef(!(props.defaultValue == null && props.value == null));
|
|
184
198
|
|
|
185
199
|
// default select the first available item
|
|
186
|
-
let register = useCallback((value:
|
|
200
|
+
let register = useCallback((value: Key) => {
|
|
187
201
|
if (state && !isRegistered.current) {
|
|
188
202
|
isRegistered.current = true;
|
|
189
|
-
state.
|
|
203
|
+
state.toggleKey(value);
|
|
190
204
|
}
|
|
191
205
|
}, []);
|
|
192
206
|
|
|
193
207
|
return (
|
|
194
208
|
<Provider
|
|
195
209
|
values={[
|
|
196
|
-
[InternalSegmentedControlContext, {register: register, prevRef: props.prevRef, currentSelectedRef: props.currentSelectedRef}]
|
|
210
|
+
[InternalSegmentedControlContext, {register: register, prevRef: props.prevRef, currentSelectedRef: props.currentSelectedRef, isJustified: props.isJustified}]
|
|
197
211
|
]}>
|
|
198
212
|
{props.children}
|
|
199
213
|
</Provider>
|
|
200
214
|
);
|
|
201
215
|
}
|
|
202
216
|
|
|
203
|
-
function SegmentedControlItem(props: SegmentedControlItemProps, ref: FocusableRef<
|
|
204
|
-
let
|
|
205
|
-
let domRef = useFocusableRef(ref, inputRef);
|
|
217
|
+
function SegmentedControlItem(props: SegmentedControlItemProps, ref: FocusableRef<HTMLButtonElement>) {
|
|
218
|
+
let domRef = useFocusableRef(ref);
|
|
206
219
|
let divRef = useRef<HTMLDivElement>(null);
|
|
207
|
-
let {register, prevRef, currentSelectedRef} = useContext(InternalSegmentedControlContext);
|
|
208
|
-
let state = useContext(
|
|
209
|
-
let isSelected = props.id
|
|
220
|
+
let {register, prevRef, currentSelectedRef, isJustified} = useContext(InternalSegmentedControlContext);
|
|
221
|
+
let state = useContext(ToggleGroupStateContext);
|
|
222
|
+
let isSelected = state?.selectedKeys.has(props.id);
|
|
210
223
|
// do not apply animation if a user has the prefers-reduced-motion setting
|
|
211
224
|
let isReduced = false;
|
|
212
225
|
if (window?.matchMedia) {
|
|
@@ -239,16 +252,14 @@ function SegmentedControlItem(props: SegmentedControlItemProps, ref: FocusableRe
|
|
|
239
252
|
}, [isSelected]);
|
|
240
253
|
|
|
241
254
|
return (
|
|
242
|
-
<
|
|
255
|
+
<ToggleButton
|
|
243
256
|
{...props}
|
|
244
|
-
value={props.id}
|
|
245
257
|
ref={domRef}
|
|
246
|
-
inputRef={inputRef}
|
|
247
258
|
style={props.UNSAFE_style}
|
|
248
|
-
className={renderProps => (props.UNSAFE_className || '') + controlItem({...renderProps}, props.styles)} >
|
|
249
|
-
{({isSelected,
|
|
259
|
+
className={renderProps => (props.UNSAFE_className || '') + controlItem({...renderProps, isJustified}, props.styles)} >
|
|
260
|
+
{({isSelected, isPressed, isDisabled}) => (
|
|
250
261
|
<>
|
|
251
|
-
{isSelected && <div className={slider({
|
|
262
|
+
{isSelected && <div className={slider({isDisabled})} ref={currentSelectedRef} />}
|
|
252
263
|
<Provider
|
|
253
264
|
values={[
|
|
254
265
|
[IconContext, {
|
|
@@ -264,7 +275,7 @@ function SegmentedControlItem(props: SegmentedControlItemProps, ref: FocusableRe
|
|
|
264
275
|
</>
|
|
265
276
|
)
|
|
266
277
|
}
|
|
267
|
-
</
|
|
278
|
+
</ToggleButton>
|
|
268
279
|
);
|
|
269
280
|
}
|
|
270
281
|
|