Skip to content

Commit

Permalink
fix(Checkbox): set indeterminate flag correctly on input
Browse files Browse the repository at this point in the history
Ref UXD-1540
  • Loading branch information
ajkl2533 committed Jan 13, 2025
1 parent 66d1612 commit b4ff38e
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 4 deletions.
98 changes: 98 additions & 0 deletions src/components/forms/Checkbox/Checkbox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { screen } from '@testing-library/react';
import { vi } from 'vitest';

import { setup } from '../../../utils/tests/setup';
import Checkbox from './Checkbox';

describe('Checkbox', () => {
it('should set input indeterminate state when isIndeterminate is true', () => {
setup(
<Checkbox
checkboxId="test-checkbox"
name="test"
isIndeterminate
label="Test Checkbox"
/>,
);

const checkbox = screen.getByRole('checkbox');
expect(checkbox).toBePartiallyChecked();
});

it('should update indeterminate state when prop changes', () => {
const { rerender } = setup(
<Checkbox
checkboxId="test-checkbox"
name="test"
isIndeterminate={false}
label="Test Checkbox"
/>,
);

expect(screen.getByRole('checkbox')).not.toBePartiallyChecked();

rerender(
<Checkbox
checkboxId="test-checkbox"
name="test"
isIndeterminate
label="Test Checkbox"
/>,
);

expect(screen.getByRole('checkbox')).toBePartiallyChecked();
});

it('should handle ref correctly with indeterminate state', () => {
const ref = { current: null };
setup(
<Checkbox
ref={ref}
checkboxId="test-checkbox"
name="test"
isIndeterminate
label="Test Checkbox"
/>,
);

expect(ref.current).not.toBeNull();
expect(ref.current as HTMLInputElement).toBePartiallyChecked();
});

it('should update indeterminate state after user interactions', async () => {
const onChange = vi.fn();
const { user } = setup(
<Checkbox
checkboxId="test-checkbox"
name="test"
isIndeterminate
label="Test Checkbox"
onChange={onChange}
/>,
);

const checkbox = screen.getByRole('checkbox');
expect(checkbox).toBePartiallyChecked();

await user.click(checkbox);
expect(onChange).toHaveBeenCalled();
expect(checkbox).not.toBePartiallyChecked();
});

it('should handle both checked and indeterminate states', () => {
setup(
<Checkbox
checkboxId="test-checkbox"
name="test"
checked
onChange={vi.fn()}
isIndeterminate
label="Test Checkbox"
/>,
);

const checkbox = screen.getByRole('checkbox');
expect(checkbox).toBeChecked();
expect(checkbox).toBePartiallyChecked();
});
});
18 changes: 14 additions & 4 deletions src/components/forms/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { forwardRef } from 'react';
import { forwardRef, useEffect, useRef } from 'react';
import styled, { css } from 'styled-components';
import { add, identity, memoizeWith, pipe } from 'ramda';
import { identity, memoizeWith, pipe } from 'ramda';
import { isNotUndefined } from 'ramda-adjunct';
import cls from 'classnames';

Expand All @@ -11,6 +11,7 @@ import { Label } from '../Label';
import { TogglingInputProps } from '../types/forms.types';
import { CheckboxProps } from './Checkbox.types';
import { CLX_COMPONENT } from '../../../theme/constants';
import { mergeRefs } from '../../../utils/mergeRefs';

const CheckboxWrapper = styled.div`
display: flex;
Expand Down Expand Up @@ -119,7 +120,9 @@ const CheckboxLabel = styled(Label)<{ isDisabled: boolean }>`
padding-top: 0;
padding-bottom: 0;
padding-left: ${({ theme }) =>
pipe(getFormStyle('toggleSize'), add(theme.space.sm), pxToRem)({ theme })};
`calc(${pxToRem(
getFormStyle('toggleSize', { theme }),
)} + var(--sscds-space-2x))`};
${getLabelStyles};
${({ isDisabled }) =>
Expand Down Expand Up @@ -153,12 +156,19 @@ const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
},
ref,
) => {
const inputRef = useRef<HTMLInputElement>(null);
const hasLabel = isNotUndefined(label);

useEffect(() => {
if (inputRef.current) {
inputRef.current.indeterminate = isIndeterminate;
}
}, [isIndeterminate]);

return (
<CheckboxWrapper className={cls(CLX_COMPONENT, className)}>
<CheckboxInput
ref={ref}
ref={mergeRefs(ref, inputRef)}
disabled={isDisabled}
id={checkboxId}
isIndeterminate={isIndeterminate}
Expand Down

0 comments on commit b4ff38e

Please sign in to comment.