|
1 | 1 | import styled from '@emotion/styled'
|
2 |
| -import type { ChangeEvent, ChangeEventHandler, ReactNode } from 'react' |
3 |
| -import { useCallback, useEffect, useState } from 'react' |
| 2 | +import { forwardRef, useCallback, useEffect, useState } from 'react' |
| 3 | +import type { ChangeEvent, ChangeEventHandler, ReactNode, Ref } from 'react' |
4 | 4 | import { Icon } from '../Icon'
|
5 | 5 | import { Tooltip } from '../Tooltip'
|
6 | 6 |
|
@@ -140,66 +140,76 @@ type ToggleProps = {
|
140 | 140 | required?: boolean
|
141 | 141 | }
|
142 | 142 |
|
143 |
| -export const Toggle = ({ |
144 |
| - checked = false, |
145 |
| - disabled = false, |
146 |
| - id, |
147 |
| - name, |
148 |
| - onChange, |
149 |
| - size = 'large', |
150 |
| - tooltip, |
151 |
| - labelPosition = 'right', |
152 |
| - label, |
153 |
| - required, |
154 |
| - className, |
155 |
| -}: ToggleProps) => { |
156 |
| - const [state, setState] = useState(checked) |
157 |
| - |
158 |
| - const onLocalChange = useCallback( |
159 |
| - (event: ChangeEvent<HTMLInputElement>) => { |
160 |
| - if (onChange) onChange?.(event) |
161 |
| - else setState(event.target.checked) |
162 |
| - }, |
163 |
| - [onChange, setState], |
164 |
| - ) |
165 |
| - |
166 |
| - useEffect(() => { |
167 |
| - setState(checked) |
168 |
| - }, [checked, setState]) |
169 |
| - |
170 |
| - return ( |
171 |
| - <Tooltip text={tooltip}> |
172 |
| - <StyledLabel |
173 |
| - aria-disabled={disabled} |
174 |
| - size={size} |
175 |
| - onClick={evt => evt.stopPropagation()} |
176 |
| - className={className} |
177 |
| - > |
178 |
| - {label && labelPosition === 'left' ? ( |
179 |
| - <> |
180 |
| - {label} |
181 |
| - {required ? <RequiredIcon /> : null} |
182 |
| - </> |
183 |
| - ) : null} |
184 |
| - <StyledToggle size={size} data-checked={state} data-disabled={disabled}> |
185 |
| - <StyledCheckbox |
186 |
| - id={id || name} |
187 |
| - aria-label={name} |
188 |
| - checked={state} |
189 |
| - aria-checked={state} |
190 |
| - disabled={disabled} |
191 |
| - name={name} |
192 |
| - onChange={onLocalChange} |
193 |
| - type="checkbox" |
194 |
| - /> |
195 |
| - </StyledToggle> |
196 |
| - {label && labelPosition === 'right' ? ( |
197 |
| - <> |
198 |
| - {label} |
199 |
| - {required ? <RequiredIcon /> : null} |
200 |
| - </> |
201 |
| - ) : null} |
202 |
| - </StyledLabel> |
203 |
| - </Tooltip> |
204 |
| - ) |
205 |
| -} |
| 143 | +export const Toggle = forwardRef( |
| 144 | + ( |
| 145 | + { |
| 146 | + checked = false, |
| 147 | + disabled = false, |
| 148 | + id, |
| 149 | + name, |
| 150 | + onChange, |
| 151 | + size = 'large', |
| 152 | + tooltip, |
| 153 | + labelPosition = 'right', |
| 154 | + label, |
| 155 | + required, |
| 156 | + className, |
| 157 | + }: ToggleProps, |
| 158 | + ref: Ref<HTMLInputElement>, |
| 159 | + ) => { |
| 160 | + const [state, setState] = useState(checked) |
| 161 | + |
| 162 | + const onLocalChange = useCallback( |
| 163 | + (event: ChangeEvent<HTMLInputElement>) => { |
| 164 | + if (onChange) onChange?.(event) |
| 165 | + else setState(event.target.checked) |
| 166 | + }, |
| 167 | + [onChange, setState], |
| 168 | + ) |
| 169 | + |
| 170 | + useEffect(() => { |
| 171 | + setState(checked) |
| 172 | + }, [checked, setState]) |
| 173 | + |
| 174 | + return ( |
| 175 | + <Tooltip text={tooltip}> |
| 176 | + <StyledLabel |
| 177 | + aria-disabled={disabled} |
| 178 | + size={size} |
| 179 | + onClick={evt => evt.stopPropagation()} |
| 180 | + className={className} |
| 181 | + > |
| 182 | + {label && labelPosition === 'left' ? ( |
| 183 | + <> |
| 184 | + {label} |
| 185 | + {required ? <RequiredIcon /> : null} |
| 186 | + </> |
| 187 | + ) : null} |
| 188 | + <StyledToggle |
| 189 | + size={size} |
| 190 | + data-checked={state} |
| 191 | + data-disabled={disabled} |
| 192 | + > |
| 193 | + <StyledCheckbox |
| 194 | + id={id || name} |
| 195 | + aria-label={name} |
| 196 | + checked={state} |
| 197 | + aria-checked={state} |
| 198 | + disabled={disabled} |
| 199 | + name={name} |
| 200 | + onChange={onLocalChange} |
| 201 | + type="checkbox" |
| 202 | + ref={ref} |
| 203 | + /> |
| 204 | + </StyledToggle> |
| 205 | + {label && labelPosition === 'right' ? ( |
| 206 | + <> |
| 207 | + {label} |
| 208 | + {required ? <RequiredIcon /> : null} |
| 209 | + </> |
| 210 | + ) : null} |
| 211 | + </StyledLabel> |
| 212 | + </Tooltip> |
| 213 | + ) |
| 214 | + }, |
| 215 | +) |
0 commit comments