1
1
'use client' ;
2
2
import * as React from 'react' ;
3
3
import PropTypes from 'prop-types' ;
4
- import { NOOP } from '../utils/noop' ;
5
- import { useComponentRenderer } from '../utils/useComponentRenderer' ;
6
- import type { BaseUIComponentProps } from '../utils/types' ;
4
+ import { useRenderElement } from '../utils/useRenderElement' ;
5
+ import type { BaseUIComponentProps , Orientation } from '../utils/types' ;
7
6
import { CompositeRoot } from '../composite/root/CompositeRoot' ;
7
+ import { useControlled } from '../utils/useControlled' ;
8
8
import { useDirection } from '../direction-provider/DirectionContext' ;
9
+ import { useEventCallback } from '../utils/useEventCallback' ;
9
10
import { useToolbarRootContext } from '../toolbar/root/ToolbarRootContext' ;
10
- import { useToggleGroup } from './useToggleGroup' ;
11
11
import { ToggleGroupContext } from './ToggleGroupContext' ;
12
12
import { ToggleGroupDataAttributes } from './ToggleGroupDataAttributes' ;
13
13
@@ -33,7 +33,7 @@ const ToggleGroup = React.forwardRef(function ToggleGroup(
33
33
defaultValue : defaultValueProp ,
34
34
disabled : disabledProp = false ,
35
35
loop = true ,
36
- onValueChange : onValueChangeProp ,
36
+ onValueChange,
37
37
orientation = 'horizontal' ,
38
38
toggleMultiple = false ,
39
39
value : valueProp ,
@@ -54,12 +54,31 @@ const ToggleGroup = React.forwardRef(function ToggleGroup(
54
54
return undefined ;
55
55
} , [ valueProp , defaultValueProp ] ) ;
56
56
57
- const { getRootProps, disabled, setGroupValue, value } = useToggleGroup ( {
58
- value : valueProp ,
59
- defaultValue,
60
- disabled : ( toolbarContext ?. disabled ?? false ) || disabledProp ,
61
- toggleMultiple,
62
- onValueChange : onValueChangeProp ?? NOOP ,
57
+ const disabled = ( toolbarContext ?. disabled ?? false ) || disabledProp ;
58
+
59
+ const [ groupValue , setValueState ] = useControlled ( {
60
+ controlled : valueProp ,
61
+ default : defaultValue ,
62
+ name : 'ToggleGroup' ,
63
+ state : 'value' ,
64
+ } ) ;
65
+
66
+ const setGroupValue = useEventCallback ( ( newValue : string , nextPressed : boolean , event : Event ) => {
67
+ let newGroupValue : any [ ] | undefined ;
68
+ if ( toggleMultiple ) {
69
+ newGroupValue = groupValue . slice ( ) ;
70
+ if ( nextPressed ) {
71
+ newGroupValue . push ( newValue ) ;
72
+ } else {
73
+ newGroupValue . splice ( groupValue . indexOf ( newValue ) , 1 ) ;
74
+ }
75
+ } else {
76
+ newGroupValue = nextPressed ? [ newValue ] : [ ] ;
77
+ }
78
+ if ( Array . isArray ( newGroupValue ) ) {
79
+ setValueState ( newGroupValue ) ;
80
+ onValueChange ?.( newGroupValue , event ) ;
81
+ }
63
82
} ) ;
64
83
65
84
const state : ToggleGroup . State = React . useMemo (
@@ -72,19 +91,21 @@ const ToggleGroup = React.forwardRef(function ToggleGroup(
72
91
disabled,
73
92
orientation,
74
93
setGroupValue,
75
- value,
94
+ value : groupValue ,
76
95
} ) ,
77
- [ disabled , orientation , setGroupValue , value ] ,
96
+ [ disabled , orientation , setGroupValue , groupValue ] ,
78
97
) ;
79
98
80
- const { renderElement } = useComponentRenderer ( {
81
- propGetter : getRootProps ,
82
- render : render ?? 'div' ,
83
- ref : forwardedRef ,
99
+ const renderElement = useRenderElement ( 'div' , props , {
84
100
state,
85
- className,
101
+ ref : forwardedRef ,
102
+ props : [
103
+ {
104
+ role : 'group' ,
105
+ } ,
106
+ otherProps ,
107
+ ] ,
86
108
customStyleHookMapping,
87
- extraProps : otherProps ,
88
109
} ) ;
89
110
90
111
return (
@@ -100,8 +121,6 @@ const ToggleGroup = React.forwardRef(function ToggleGroup(
100
121
101
122
export { ToggleGroup } ;
102
123
103
- export type ToggleGroupOrientation = 'horizontal' | 'vertical' ;
104
-
105
124
namespace ToggleGroup {
106
125
export interface State {
107
126
/**
@@ -111,9 +130,26 @@ namespace ToggleGroup {
111
130
multiple : boolean ;
112
131
}
113
132
114
- export interface Props
115
- extends Partial < useToggleGroup . Parameters > ,
116
- Omit < BaseUIComponentProps < 'div' , State > , 'defaultValue' > {
133
+ export interface Props extends Omit < BaseUIComponentProps < 'div' , State > , 'defaultValue' > {
134
+ /**
135
+ * The open state of the ToggleGroup represented by an array of
136
+ * the values of all pressed toggle buttons
137
+ * This is the controlled counterpart of `defaultValue`.
138
+ */
139
+ value ?: readonly any [ ] ;
140
+ /**
141
+ * The open state of the ToggleGroup represented by an array of
142
+ * the values of all pressed toggle buttons.
143
+ * This is the uncontrolled counterpart of `value`.
144
+ */
145
+ defaultValue ?: readonly any [ ] ;
146
+ /**
147
+ * Callback fired when the pressed states of the ToggleGroup changes.
148
+ *
149
+ * @param {any[] } groupValue An array of the `value`s of all the pressed items.
150
+ * @param {Event } event The corresponding event that initiated the change.
151
+ */
152
+ onValueChange : ( groupValue : any [ ] , event : Event ) => void ;
117
153
/**
118
154
* Whether the component should ignore user interaction.
119
155
* @default false
@@ -122,13 +158,20 @@ namespace ToggleGroup {
122
158
/**
123
159
* @default 'horizontal'
124
160
*/
125
- orientation ?: ToggleGroupOrientation ;
161
+ orientation ?: Orientation ;
126
162
/**
127
163
* Whether to loop keyboard focus back to the first item
128
164
* when the end of the list is reached while using the arrow keys.
129
165
* @default true
130
166
*/
131
167
loop ?: boolean ;
168
+ /**
169
+ * When `false` only one item in the group can be pressed. If any item in
170
+ * the group becomes pressed, the others will become unpressed.
171
+ * When `true` multiple items can be pressed.
172
+ * @default false
173
+ */
174
+ toggleMultiple ?: boolean ;
132
175
}
133
176
}
134
177
@@ -148,7 +191,7 @@ ToggleGroup.propTypes /* remove-proptypes */ = {
148
191
className : PropTypes . oneOfType ( [ PropTypes . func , PropTypes . string ] ) ,
149
192
/**
150
193
* The open state of the ToggleGroup represented by an array of
151
- * the values of all pressed `<ToggleGroup.Item/>`s .
194
+ * the values of all pressed toggle buttons .
152
195
* This is the uncontrolled counterpart of `value`.
153
196
*/
154
197
defaultValue : PropTypes . array ,
@@ -169,7 +212,7 @@ ToggleGroup.propTypes /* remove-proptypes */ = {
169
212
* @param {any[] } groupValue An array of the `value`s of all the pressed items.
170
213
* @param {Event } event The corresponding event that initiated the change.
171
214
*/
172
- onValueChange : PropTypes . func ,
215
+ onValueChange : PropTypes . func . isRequired ,
173
216
/**
174
217
* @default 'horizontal'
175
218
*/
@@ -190,7 +233,7 @@ ToggleGroup.propTypes /* remove-proptypes */ = {
190
233
toggleMultiple : PropTypes . bool ,
191
234
/**
192
235
* The open state of the ToggleGroup represented by an array of
193
- * the values of all pressed `<ToggleGroup.Item/>`s
236
+ * the values of all pressed toggle buttons
194
237
* This is the controlled counterpart of `defaultValue`.
195
238
*/
196
239
value : PropTypes . array ,
0 commit comments