Skip to content

Commit 618a869

Browse files
authored
fix(toggle): add forward ref (#2257)
1 parent b7c7f3b commit 618a869

File tree

1 file changed

+75
-65
lines changed

1 file changed

+75
-65
lines changed

packages/ui/src/components/Toggle/index.tsx

+75-65
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
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'
44
import { Icon } from '../Icon'
55
import { Tooltip } from '../Tooltip'
66

@@ -140,66 +140,76 @@ type ToggleProps = {
140140
required?: boolean
141141
}
142142

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

Comments
 (0)