diff --git a/packages/react-native-web/src/exports/Switch/__tests__/index-test.js b/packages/react-native-web/src/exports/Switch/__tests__/index-test.js
index af390699..0435cfb9 100644
--- a/packages/react-native-web/src/exports/Switch/__tests__/index-test.js
+++ b/packages/react-native-web/src/exports/Switch/__tests__/index-test.js
@@ -1,54 +1,58 @@
/* eslint-env jasmine, jest */
import React from 'react';
-import { shallow } from 'enzyme';
+import { render } from '@testing-library/react';
import Switch from '..';
-const checkboxSelector = 'input[type="checkbox"]';
+function findCheckbox(container) {
+ return container.firstChild.querySelector('input');
+}
describe('components/Switch', () => {
test('accessibilityLabel is applied to native checkbox', () => {
- const component = shallow();
- expect(component.find(checkboxSelector).prop('aria-label')).toBe('switch');
+ const { container } = render();
+ expect(findCheckbox(container).getAttribute('aria-label')).toBe('switch');
});
describe('disabled', () => {
test('when "false" a default checkbox is rendered', () => {
- const component = shallow();
- expect(component.find(checkboxSelector).prop('disabled')).toBe(undefined);
+ const { container } = render();
+ expect(findCheckbox(container).disabled).toBe(false);
});
test('when "true" a disabled checkbox is rendered', () => {
- const component = shallow();
- expect(component.find(checkboxSelector).prop('disabled')).toBe(true);
+ const { container } = render();
+ expect(findCheckbox(container).disabled).toBe(true);
});
});
describe('onValueChange', () => {
test('when value is "false" it receives "true"', () => {
const onValueChange = jest.fn();
- const component = shallow();
- component.find('input').simulate('change', { nativeEvent: { target: { checked: true } } });
+ const { container } = render();
+ const checkbox = findCheckbox(container);
+ checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
expect(onValueChange).toHaveBeenCalledWith(true);
});
test('when value is "true" it receives "false"', () => {
const onValueChange = jest.fn();
- const component = shallow();
- component.find('input').simulate('change', { nativeEvent: { target: { checked: false } } });
+ const { container } = render();
+ const checkbox = findCheckbox(container);
+ checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
expect(onValueChange).toHaveBeenCalledWith(false);
});
});
describe('value', () => {
test('when "false" an unchecked checkbox is rendered', () => {
- const component = shallow();
- expect(component.find(checkboxSelector).prop('checked')).toBe(false);
+ const { container } = render();
+ expect(findCheckbox(container).checked).toBe(false);
});
test('when "true" a checked checkbox is rendered', () => {
- const component = shallow();
- expect(component.find(checkboxSelector).prop('checked')).toBe(true);
+ const { container } = render();
+ expect(findCheckbox(container).checked).toBe(true);
});
});
});
diff --git a/packages/react-native-web/src/exports/Switch/index.js b/packages/react-native-web/src/exports/Switch/index.js
index 1a84a2be..f25c3226 100644
--- a/packages/react-native-web/src/exports/Switch/index.js
+++ b/packages/react-native-web/src/exports/Switch/index.js
@@ -10,13 +10,12 @@
import type { ColorValue } from '../../types';
import type { ViewProps } from '../View';
-import applyNativeMethods from '../../modules/applyNativeMethods';
import createElement from '../createElement';
import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue';
import StyleSheet from '../StyleSheet';
import UIManager from '../UIManager';
import View from '../View';
-import React from 'react';
+import React, { forwardRef, useImperativeHandle, useRef } from 'react';
type SwitchProps = {
...ViewProps,
@@ -33,110 +32,119 @@ const emptyObject = {};
const thumbDefaultBoxShadow = '0px 1px 3px rgba(0,0,0,0.5)';
const thumbFocusedBoxShadow = `${thumbDefaultBoxShadow}, 0 0 0 10px rgba(0,0,0,0.1)`;
-class Switch extends React.Component {
- _checkboxElement: HTMLInputElement;
- _thumbElement: View;
+const Switch = forwardRef((props, ref) => {
+ const {
+ accessibilityLabel,
+ activeThumbColor = '#009688',
+ activeTrackColor = '#A3D3CF',
+ disabled = false,
+ onValueChange,
+ style = emptyObject,
+ thumbColor = '#FAFAFA',
+ trackColor = '#939393',
+ value = false,
+ ...other
+ } = props;
- static displayName = 'Switch';
+ const checkboxRef = useRef(null);
+ const thumbRef = useRef(null);
- blur() {
- UIManager.blur(this._checkboxElement);
+ useImperativeHandle(
+ ref,
+ () => {
+ return {
+ blur() {
+ UIManager.blur(checkboxRef.current);
+ },
+ focus() {
+ UIManager.focus(checkboxRef.current);
+ }
+ };
+ },
+ [checkboxRef]
+ );
+
+ function handleChange(event: Object) {
+ if (onValueChange != null) {
+ onValueChange(event.nativeEvent.target.checked);
+ }
}
- focus() {
- UIManager.focus(this._checkboxElement);
- }
-
- render() {
- const {
- accessibilityLabel,
- activeThumbColor = '#009688',
- activeTrackColor = '#A3D3CF',
- disabled = false,
- onValueChange, // eslint-disable-line
- style = emptyObject,
- thumbColor = '#FAFAFA',
- trackColor = '#939393',
- value = false,
- ...other
- } = this.props;
-
- const { height: styleHeight, width: styleWidth } = StyleSheet.flatten(style);
- const height = styleHeight || 20;
- const minWidth = multiplyStyleLengthValue(height, 2);
- const width = styleWidth > minWidth ? styleWidth : minWidth;
- const trackBorderRadius = multiplyStyleLengthValue(height, 0.5);
- const trackCurrentColor = value
- ? (trackColor != null && typeof trackColor === 'object' && trackColor.true) ||
- activeTrackColor
- : (trackColor != null && typeof trackColor === 'object' && trackColor.false) || trackColor;
- const thumbCurrentColor = value ? activeThumbColor : thumbColor;
- const thumbHeight = height;
- const thumbWidth = thumbHeight;
-
- const rootStyle = [styles.root, style, disabled && styles.cursorDefault, { height, width }];
-
- const trackStyle = [
- styles.track,
- {
- backgroundColor: disabled ? '#D5D5D5' : trackCurrentColor,
- borderRadius: trackBorderRadius
- }
- ];
-
- const thumbStyle = [
- styles.thumb,
- value && styles.thumbActive,
- {
- backgroundColor: disabled ? '#BDBDBD' : thumbCurrentColor,
- height: thumbHeight,
- marginStart: value ? multiplyStyleLengthValue(thumbWidth, -1) : 0,
- width: thumbWidth
- }
- ];
-
- const nativeControl = createElement('input', {
- accessibilityLabel,
- checked: value,
- disabled: disabled,
- onBlur: this._handleFocusState,
- onChange: this._handleChange,
- onFocus: this._handleFocusState,
- ref: this._setCheckboxRef,
- style: [styles.nativeControl, styles.cursorInherit],
- type: 'checkbox'
- });
-
- return (
-
-
-
- {nativeControl}
-
- );
- }
-
- _handleChange = (event: Object) => {
- const { onValueChange } = this.props;
- onValueChange && onValueChange(event.nativeEvent.target.checked);
- };
-
- _handleFocusState = (event: Object) => {
+ function handleFocusState(event: Object) {
const isFocused = event.nativeEvent.type === 'focus';
const boxShadow = isFocused ? thumbFocusedBoxShadow : thumbDefaultBoxShadow;
- if (this._thumbElement) {
- this._thumbElement.setNativeProps({ style: { boxShadow } });
+ if (thumbRef.current != null) {
+ thumbRef.current.setNativeProps({ style: { boxShadow } });
}
- };
+ }
- _setCheckboxRef = element => {
- this._checkboxElement = element;
- };
+ const { height: styleHeight, width: styleWidth } = StyleSheet.flatten(style);
+ const height = styleHeight || 20;
+ const minWidth = multiplyStyleLengthValue(height, 2);
+ const width = styleWidth > minWidth ? styleWidth : minWidth;
+ const trackBorderRadius = multiplyStyleLengthValue(height, 0.5);
+ const trackCurrentColor = (function() {
+ if (value === true) {
+ if (trackColor != null && typeof trackColor === 'object') {
+ return trackColor.true;
+ } else {
+ return activeTrackColor;
+ }
+ } else {
+ if (trackColor != null && typeof trackColor === 'object') {
+ return trackColor.false;
+ } else {
+ return trackColor;
+ }
+ }
+ })();
+ const thumbCurrentColor = value ? activeThumbColor : thumbColor;
+ const thumbHeight = height;
+ const thumbWidth = thumbHeight;
- _setThumbRef = element => {
- this._thumbElement = element;
- };
-}
+ const rootStyle = [styles.root, style, disabled && styles.cursorDefault, { height, width }];
+
+ const trackStyle = [
+ styles.track,
+ {
+ backgroundColor: disabled ? '#D5D5D5' : trackCurrentColor,
+ borderRadius: trackBorderRadius
+ }
+ ];
+
+ const thumbStyle = [
+ styles.thumb,
+ value && styles.thumbActive,
+ {
+ backgroundColor: disabled ? '#BDBDBD' : thumbCurrentColor,
+ height: thumbHeight,
+ marginStart: value ? multiplyStyleLengthValue(thumbWidth, -1) : 0,
+ width: thumbWidth
+ }
+ ];
+
+ const nativeControl = createElement('input', {
+ accessibilityLabel,
+ checked: value,
+ disabled: disabled,
+ onBlur: handleFocusState,
+ onChange: handleChange,
+ onFocus: handleFocusState,
+ ref: checkboxRef,
+ style: [styles.nativeControl, styles.cursorInherit],
+ type: 'checkbox'
+ });
+
+ return (
+
+
+
+ {nativeControl}
+
+ );
+});
+
+Switch.displayName = 'Switch';
const styles = StyleSheet.create({
root: {
@@ -177,4 +185,4 @@ const styles = StyleSheet.create({
}
});
-export default applyNativeMethods(Switch);
+export default Switch;