From e2a06bd6022663fc4b4c858b390de551ce483093 Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Fri, 15 Dec 2023 10:03:01 -0600 Subject: [PATCH] fix: Fix Switch not toggling. (#985) --- src/inputs/Switch.stories.tsx | 1 - src/inputs/Switch.test.tsx | 41 +++++++++++++++++++++++++++++++++++ src/inputs/Switch.tsx | 36 ++++++++++++++++-------------- 3 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 src/inputs/Switch.test.tsx diff --git a/src/inputs/Switch.stories.tsx b/src/inputs/Switch.stories.tsx index 1567372a8..c4cb5e3b7 100644 --- a/src/inputs/Switch.stories.tsx +++ b/src/inputs/Switch.stories.tsx @@ -123,7 +123,6 @@ type SwitchWrapperProps = Omit & function SwitchWrapper({ isHovered, isFocused, ...props }: SwitchWrapperProps) { const [selected, setSelected] = useState(props.selected || false); - return (
{ + it("can change", async () => { + const onChange = jest.fn(); + // Given a switch + const r = await render(); + // Then it defaults no checked + expect(r.age).not.toBeChecked(); + // And when we click it, it flips to checked + click(r.age); + expect(r.age).toBeChecked(); + expect(onChange).toHaveBeenCalledTimes(1); + // And if we click it again, it flips back to unchecked + click(r.age); + expect(r.age).not.toBeChecked(); + expect(onChange).toHaveBeenCalledTimes(2); + }); +}); + +type SwitchTestProps = Omit & { + onChange?: (value: boolean) => void; + selected?: boolean; +}; + +function SwitchTest({ selected: initSelected, onChange: _onChange, ...props }: SwitchTestProps) { + const [selected, setSelected] = useState(initSelected || false); + return ( + { + _onChange?.(value); + setSelected(value); + }} + {...props} + /> + ); +} diff --git a/src/inputs/Switch.tsx b/src/inputs/Switch.tsx index 3450392a9..96e482ca9 100644 --- a/src/inputs/Switch.tsx +++ b/src/inputs/Switch.tsx @@ -4,7 +4,7 @@ import { resolveTooltip } from "src/components"; import { Label } from "src/components/Label"; import { Css, Palette } from "src/Css"; import { Icon } from "../components/Icon"; -import { toToggleState } from "../utils"; +import { toToggleState, useTestIds } from "../utils"; export interface SwitchProps { /** Whether the element should receive focus on render. */ @@ -17,7 +17,7 @@ export interface SwitchProps { label: string; /** Where to put the label. */ labelStyle?: "form" | "inline" | "filter" | "hidden" | "left" | "centered"; // TODO: Update `labelStyle` to make consistent with other `labelStyle` properties in the library - /** Whether or not to hide the label */ + /** Whether to hide the label */ hideLabel?: boolean; /** Handler when the interactive element state changes. */ onChange: (value: boolean) => void; @@ -49,12 +49,13 @@ export function Switch(props: SwitchProps) { const { isFocusVisible: isKeyboardFocus, focusProps } = useFocusRing(otherProps); const { hoverProps, isHovered } = useHover(ariaProps); const tooltip = resolveTooltip(disabled, props.tooltip); + const tid = useTestIds(otherProps, label); return ( -
)} - + -
+ ); } @@ -122,22 +123,25 @@ export const switchFocusStyles = Css.bshFocus.$; export const switchSelectedHoverStyles = Css.bgBlue900.$; // Circle inside Switcher/Toggle element styles -const switchCircleDefaultStyles = (isCompact: boolean) => ({ - ...Css.wPx(circleDiameter(isCompact)) - .hPx(circleDiameter(isCompact)) - .br100.bgWhite.bshBasic.absolute.leftPx(2) - .topPx(2).transition.df.aic.jcc.$, - svg: Css.hPx(toggleHeight(isCompact) / 2).wPx(toggleHeight(isCompact) / 2).$, -}); +function switchCircleDefaultStyles(isCompact: boolean) { + return { + ...Css.wPx(circleDiameter(isCompact)) + .hPx(circleDiameter(isCompact)) + .br100.bgWhite.bshBasic.absolute.leftPx(2) + .topPx(2).transition.df.aic.jcc.$, + svg: Css.hPx(toggleHeight(isCompact) / 2).wPx(toggleHeight(isCompact) / 2).$, + }; +} /** * Affecting the `left` property due to transitions only working when there is * a previous value to work from. * - * Calculation is as follow: + * Calculation is as follows: * - `100%` is the toggle width * - `${circleDiameter(isCompact)}px` is the circle diameter * - `2px` is to keep 2px edge spacing. */ -const switchCircleSelectedStyles = (isCompact: boolean) => - Css.left(`calc(100% - ${circleDiameter(isCompact)}px - 2px);`).$; +function switchCircleSelectedStyles(isCompact: boolean) { + return Css.left(`calc(100% - ${circleDiameter(isCompact)}px - 2px);`).$; +}