@@ -5,6 +5,7 @@ import { spaces } from "../common/variables";
55import useTheme from "../useTheme" ;
66import ToggleGroupPropsType , { OptionLabel } from "./types" ;
77import BackgroundColorContext , { BackgroundColors } from "../BackgroundColorContext" ;
8+ import DxcFlex from "../flex/Flex" ;
89
910const DxcToggleGroup = ( {
1011 label,
@@ -18,10 +19,10 @@ const DxcToggleGroup = ({
1819 multiple = false ,
1920 tabIndex = 0 ,
2021} : ToggleGroupPropsType ) : JSX . Element => {
21- const colorsTheme = useTheme ( ) ;
22+ const [ toggleGroupLabelId ] = useState ( `label-toggle-group- ${ uuidv4 ( ) } ` ) ;
2223 const [ selectedValue , setSelectedValue ] = useState ( defaultValue ?? ( multiple ? [ ] : - 1 ) ) ;
23- const [ toggleGroupId ] = useState ( `toggle-group-${ uuidv4 ( ) } ` ) ;
2424
25+ const colorsTheme = useTheme ( ) ;
2526 const backgroundType = useContext ( BackgroundColorContext ) ;
2627
2728 const handleToggleChange = ( selectedOption ) => {
@@ -49,22 +50,28 @@ const DxcToggleGroup = ({
4950 onChange ?.( multiple ? newSelectedOptions : selectedOption ) ;
5051 } ;
5152
52- const handleKeyPress = ( event , optionValue ) => {
53- event . preventDefault ( ) ;
54- if ( ! disabled && ( event . nativeEvent . code === "Enter" || event . nativeEvent . code === "Space" ) )
55- handleToggleChange ( optionValue ) ;
53+ const handleOnKeyDown = ( event , optionValue ) => {
54+ switch ( event . key ) {
55+ case "Enter" :
56+ case " " :
57+ event . preventDefault ( ) ;
58+ handleToggleChange ( optionValue ) ;
59+ }
5660 } ;
61+
5762 return (
5863 < ThemeProvider theme = { colorsTheme . toggleGroup } >
5964 < ToggleGroup margin = { margin } >
60- < Label htmlFor = { toggleGroupId } disabled = { disabled } >
65+ < Label id = { toggleGroupLabelId } disabled = { disabled } >
6166 { label }
6267 </ Label >
6368 < HelperText disabled = { disabled } > { helperText } </ HelperText >
64- < OptionsContainer id = { toggleGroupId } role = { multiple ? "group" : "radiogroup" } >
69+ < OptionsContainer aria-labelledby = { toggleGroupLabelId } >
6570 { options . map ( ( option , i ) => (
66- < ToggleContainer
67- selected = {
71+ < ToggleButton
72+ key = { `toggle-${ i } -${ option . label } ` }
73+ aria-label = { option . title }
74+ aria-pressed = {
6875 multiple
6976 ? value
7077 ? Array . isArray ( value ) && value . includes ( option . value )
@@ -73,9 +80,19 @@ const DxcToggleGroup = ({
7380 ? option . value === value
7481 : option . value === selectedValue
7582 }
76- role = { multiple ? "switch" : "radio" }
83+ disabled = { disabled }
84+ onClick = { ( ) => {
85+ handleToggleChange ( option . value ) ;
86+ } }
87+ onKeyDown = { ( event ) => {
88+ handleOnKeyDown ( event , option . value ) ;
89+ } }
90+ tabIndex = { ! disabled ? tabIndex : - 1 }
91+ title = { option . title }
7792 backgroundType = { backgroundType }
78- aria-checked = {
93+ hasIcon = { option . icon }
94+ optionLabel = { option . label }
95+ selected = {
7996 multiple
8097 ? value
8198 ? Array . isArray ( value ) && value . includes ( option . value )
@@ -84,33 +101,37 @@ const DxcToggleGroup = ({
84101 ? option . value === value
85102 : option . value === selectedValue
86103 }
87- tabIndex = { ! disabled ? tabIndex : - 1 }
88- onClick = { ( ) => ! disabled && handleToggleChange ( option . value ) }
89- isLast = { i === options . length - 1 }
90- isIcon = { option . icon }
91- optionLabel = { option . label }
92- disabled = { disabled }
93- onKeyPress = { ( event ) => {
94- handleKeyPress ( event , option . value ) ;
95- } }
96- key = { `toggle-${ i } -${ option . label } ` }
97104 >
98- < OptionContent >
105+ < DxcFlex alignItems = "center" >
99106 { option . icon && (
100107 < IconContainer optionLabel = { option . label } >
101- { typeof option . icon === "string" ? < Icon src = { option . icon } /> : option . icon }
108+ { typeof option . icon === "string" ? < img src = { option . icon } /> : option . icon }
102109 </ IconContainer >
103110 ) }
104111 { option . label && < LabelContainer > { option . label } </ LabelContainer > }
105- </ OptionContent >
106- </ ToggleContainer >
112+ </ DxcFlex >
113+ </ ToggleButton >
107114 ) ) }
108115 </ OptionsContainer >
109116 </ ToggleGroup >
110117 </ ThemeProvider >
111118 ) ;
112119} ;
113120
121+ const ToggleGroup = styled . div < { margin : ToggleGroupPropsType [ "margin" ] } > `
122+ display: inline-flex;
123+ flex-direction: column;
124+ margin: ${ ( props ) => ( props . margin && typeof props . margin !== "object" ? spaces [ props . margin ] : "0px" ) } ;
125+ margin-top: ${ ( props ) =>
126+ props . margin && typeof props . margin === "object" && props . margin . top ? spaces [ props . margin . top ] : "" } ;
127+ margin-right: ${ ( props ) =>
128+ props . margin && typeof props . margin === "object" && props . margin . right ? spaces [ props . margin . right ] : "" } ;
129+ margin-bottom: ${ ( props ) =>
130+ props . margin && typeof props . margin === "object" && props . margin . bottom ? spaces [ props . margin . bottom ] : "" } ;
131+ margin-left: ${ ( props ) =>
132+ props . margin && typeof props . margin === "object" && props . margin . left ? spaces [ props . margin . left ] : "" } ;
133+ ` ;
134+
114135const Label = styled . label < { disabled : ToggleGroupPropsType [ "disabled" ] } > `
115136 color: ${ ( props ) => ( props . disabled ? props . theme . disabledLabelFontColor : props . theme . labelFontColor ) } ;
116137 font-family: ${ ( props ) => props . theme . labelFontFamily } ;
@@ -129,100 +150,68 @@ const HelperText = styled.span<{ disabled: ToggleGroupPropsType["disabled"] }>`
129150 line-height: ${ ( props ) => props . theme . helperTextLineHeight } ;
130151` ;
131152
132- const ToggleGroup = styled . div < { margin : ToggleGroupPropsType [ "margin" ] } > `
133- display: inline-flex;
134- flex-direction: column;
135- margin: ${ ( props ) => ( props . margin && typeof props . margin !== "object" ? spaces [ props . margin ] : "0px" ) } ;
136- margin-top: ${ ( props ) =>
137- props . margin && typeof props . margin === "object" && props . margin . top ? spaces [ props . margin . top ] : "" } ;
138- margin-right: ${ ( props ) =>
139- props . margin && typeof props . margin === "object" && props . margin . right ? spaces [ props . margin . right ] : "" } ;
140- margin-bottom: ${ ( props ) =>
141- props . margin && typeof props . margin === "object" && props . margin . bottom ? spaces [ props . margin . bottom ] : "" } ;
142- margin-left: ${ ( props ) =>
143- props . margin && typeof props . margin === "object" && props . margin . left ? spaces [ props . margin . left ] : "" } ;
144- ` ;
145-
146153const OptionsContainer = styled . div `
147154 display: flex;
148- flex-direction: row ;
155+ gap: 0.25rem ;
149156 width: max-content;
150- opacity: 1;
151157 height: calc(48px - 4px - 4px);
158+ padding: 0.25rem;
152159 border-width: ${ ( props ) => props . theme . containerBorderThickness } ;
153160 border-style: ${ ( props ) => props . theme . containerBorderStyle } ;
154161 border-radius: ${ ( props ) => props . theme . containerBorderRadius } ;
155162 border-color: ${ ( props ) => props . theme . containerBorderColor } ;
156- background-color: ${ ( props ) => props . theme . containerBackgroundColor } ;
157- padding: 4px;
158163 margin-top: ${ ( props ) => props . theme . containerMarginTop } ;
164+ background-color: ${ ( props ) => props . theme . containerBackgroundColor } ;
159165` ;
160166
161- const ToggleContainer = styled . div < {
167+ const ToggleButton = styled . button < {
162168 selected : boolean ;
163- disabled : ToggleGroupPropsType [ "disabled" ] ;
164- isLast : boolean ;
165- isIcon : OptionLabel [ "icon" ] ;
169+ hasIcon : OptionLabel [ "icon" ] ;
166170 optionLabel : OptionLabel [ "label" ] ;
167171 backgroundType : BackgroundColors ;
168172} > `
169173 display: flex;
170174 flex-direction: column;
171175 justify-content: center;
172- margin-right: ${ ( props ) => ! props . isLast && "4px" } ;
173-
174- ${ ( props ) => `
175- background-color: ${
176- props . selected
177- ? props . disabled
178- ? props . theme . selectedDisabledBackgroundColor
179- : props . theme . selectedBackgroundColor
180- : props . disabled
181- ? props . theme . unselectedDisabledBackgroundColor
182- : props . theme . unselectedBackgroundColor
183- } ;
184- border-width: ${ props . theme . optionBorderThickness } ;
185- border-style: ${ props . theme . optionBorderStyle } ;
186- border-radius: ${ props . theme . optionBorderRadius } ;
187- padding-left: ${
188- ( props . optionLabel && props . isIcon ) || ( props . optionLabel && ! props . isIcon )
189- ? props . theme . labelPaddingLeft
190- : props . theme . iconPaddingLeft
191- } ;
192- padding-right: ${
193- ( props . optionLabel && props . isIcon ) || ( props . optionLabel && ! props . isIcon )
194- ? props . theme . labelPaddingRight
195- : props . theme . iconPaddingRight
196- } ;
197- ${
198- ! props . disabled
199- ? `:hover {
200- background-color: ${
201- props . selected ? props . theme . selectedHoverBackgroundColor : props . theme . unselectedHoverBackgroundColor
202- } ;
203- }
204- :active {
205- background-color: ${
206- props . selected ? props . theme . selectedActiveBackgroundColor : props . theme . unselectedActiveBackgroundColor
207- } ;
208- color: #ffffff;
209- }
210- :focus {
211- border-color: transparent;
212- box-shadow: 0 0 0 ${ props . theme . optionFocusBorderThickness } ${
213- props . backgroundType === "dark" ? props . theme . focusColorOnDark : props . theme . focusColor
214- } ;
215- }
216- &:focus-visible {
217- outline: none;
218- }
219- cursor: pointer;
220- color: ${ props . selected ? props . theme . selectedFontColor : props . theme . unselectedFontColor } ;
221- `
222- : `color: ${ props . selected ? props . theme . selectedDisabledFontColor : props . theme . unselectedDisabledFontColor } ;
223- cursor: not-allowed;`
224- }
225- ` }
176+ padding-left: ${ ( props ) =>
177+ ( props . optionLabel && props . hasIcon ) || ( props . optionLabel && ! props . hasIcon )
178+ ? props . theme . labelPaddingLeft
179+ : props . theme . iconPaddingLeft } ;
180+ padding-right: ${ ( props ) =>
181+ ( props . optionLabel && props . hasIcon ) || ( props . optionLabel && ! props . hasIcon )
182+ ? props . theme . labelPaddingRight
183+ : props . theme . iconPaddingRight } ;
184+ border-width: ${ ( props ) => props . theme . optionBorderThickness } ;
185+ border-style: ${ ( props ) => props . theme . optionBorderStyle } ;
186+ border-radius: ${ ( props ) => props . theme . optionBorderRadius } ;
187+ background-color: ${ ( props ) =>
188+ props . selected ? props . theme . selectedBackgroundColor : props . theme . unselectedBackgroundColor } ;
189+ color: ${ ( props ) => ( props . selected ? props . theme . selectedFontColor : props . theme . unselectedFontColor ) } ;
190+ cursor: pointer;
191+
192+ &:hover {
193+ background-color: ${ ( props ) =>
194+ props . selected ? props . theme . selectedHoverBackgroundColor : props . theme . unselectedHoverBackgroundColor } ;
195+ }
196+ &:active {
197+ background-color: ${ ( props ) =>
198+ props . selected ? props . theme . selectedActiveBackgroundColor : props . theme . unselectedActiveBackgroundColor } ;
199+ color: #ffffff;
200+ }
201+ &:focus {
202+ outline: none;
203+ box-shadow: ${ ( props ) =>
204+ `0 0 0 ${ props . theme . optionFocusBorderThickness } ${
205+ props . backgroundType === "dark" ? props . theme . focusColorOnDark : props . theme . focusColor
206+ } `} ;
207+ }
208+ &:disabled {
209+ background-color: ${ ( props ) =>
210+ props . selected ? props . theme . selectedDisabledBackgroundColor : props . theme . unselectedDisabledBackgroundColor } ;
211+ color: ${ ( props ) =>
212+ props . selected ? props . theme . selectedDisabledFontColor : props . theme . unselectedDisabledFontColor } ;
213+ cursor: not-allowed;
214+ }
226215` ;
227216
228217const LabelContainer = styled . span `
@@ -232,24 +221,18 @@ const LabelContainer = styled.span`
232221 font-weight: ${ ( props ) => props . theme . optionLabelFontWeight } ;
233222` ;
234223
235- const OptionContent = styled . div `
236- display: flex;
237- flex-direction: row;
238- align-items: center;
239- ` ;
240-
241- const Icon = styled . img `` ;
242-
243224const IconContainer = styled . div < { optionLabel : OptionLabel [ "label" ] } > `
244- margin-right: ${ ( props ) => props . optionLabel && props . theme . iconMarginRight } ;
225+ display: flex ;
245226 height: 24px;
246227 width: 24px;
228+ margin-right: ${ ( props ) => props . optionLabel && props . theme . iconMarginRight } ;
247229 overflow: hidden;
248- display: flex;
230+
249231 img,
250232 svg {
251233 height: 100%;
252234 width: 100%;
253235 }
254236` ;
237+
255238export default DxcToggleGroup ;
0 commit comments