diff --git a/.changeset/brave-meals-hammer.md b/.changeset/brave-meals-hammer.md new file mode 100644 index 0000000000..373f60f479 --- /dev/null +++ b/.changeset/brave-meals-hammer.md @@ -0,0 +1,5 @@ +--- +"@marigold/components": patch +--- + +feat: forward ref for `` diff --git a/packages/components/src/Switch/Switch.test.tsx b/packages/components/src/Switch/Switch.test.tsx index b417e26a5a..bf8244a6eb 100644 --- a/packages/components/src/Switch/Switch.test.tsx +++ b/packages/components/src/Switch/Switch.test.tsx @@ -236,3 +236,14 @@ test('supports controlled component usage', () => { expect(onChange).toHaveBeenCalledWith(false); expect(input).toHaveAttribute('aria-checked', 'false'); }); + +test('forwards ref', () => { + const ref = React.createRef(); + render( + + Label + + ); + + expect(ref.current).toBeInstanceOf(HTMLInputElement); +}); diff --git a/packages/components/src/Switch/Switch.tsx b/packages/components/src/Switch/Switch.tsx index 0973d5f5a9..83a06bc869 100755 --- a/packages/components/src/Switch/Switch.tsx +++ b/packages/components/src/Switch/Switch.tsx @@ -1,6 +1,7 @@ -import React, { useRef } from 'react'; +import React, { forwardRef } from 'react'; import { useFocusRing } from '@react-aria/focus'; import { useSwitch } from '@react-aria/switch'; +import { useObjectRef } from '@react-aria/utils'; import { useToggleState } from '@react-stately/toggle'; import { AriaSwitchProps } from '@react-types/switch'; @@ -40,110 +41,116 @@ export interface SwitchProps size?: string; width?: string; } + // Component // --------------- -export const Switch = ({ - variant, - size, - width = '100%', - checked, - disabled, - readOnly, - defaultChecked, - ...rest -}: SwitchProps) => { - const ref = useRef(null); - // Adjust props to the react-aria API - const props = { - isSelected: checked, - isDisabled: disabled, - isReadOnly: readOnly, - defaultSelected: defaultChecked, - ...rest, - }; +export const Switch = forwardRef( + ( + { + variant, + size, + width = '100%', + checked, + disabled, + readOnly, + defaultChecked, + ...rest + }, + ref + ) => { + const inputRef = useObjectRef(ref); + // Adjust props to the react-aria API + const props = { + isSelected: checked, + isDisabled: disabled, + isReadOnly: readOnly, + defaultSelected: defaultChecked, + ...rest, + }; - const state = useToggleState(props); - const { inputProps } = useSwitch(props, state, ref); - const { isFocusVisible, focusProps } = useFocusRing(); - const stateProps = useStateProps({ - checked: state.isSelected, - disabled: disabled, - readOnly: readOnly, - focus: isFocusVisible, - }); + const state = useToggleState(props); + const { inputProps } = useSwitch(props, state, inputRef); + const { isFocusVisible, focusProps } = useFocusRing(); + const stateProps = useStateProps({ + checked: state.isSelected, + disabled: disabled, + readOnly: readOnly, + focus: isFocusVisible, + }); - const styles = useComponentStyles( - 'Switch', - { variant, size }, - { parts: ['container', 'label', 'track', 'thumb'] } - ); + const styles = useComponentStyles( + 'Switch', + { variant, size }, + { parts: ['container', 'label', 'track', 'thumb'] } + ); - return ( - - - {props.children && {props.children}} + return ( + {props.children && {props.children}} + + + '&:checked': { + transform: 'translateX(calc(47px - 100%))', + }, + }} + css={styles.thumb} + {...stateProps} + /> + - - ); -}; + ); + } +);