Skip to content

Commit

Permalink
Add none checker checkbox (#5)
Browse files Browse the repository at this point in the history
* Add none checker checkbox

* Update readme
  • Loading branch information
AlexLisenkov authored Nov 20, 2019
1 parent 3b731c2 commit 0cb0659
Show file tree
Hide file tree
Showing 32 changed files with 1,008 additions and 296 deletions.
68 changes: 64 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![npm](https://img.shields.io/npm/dt/@createnl/grouped-checkboxes)](https://www.npmjs.com/package/@createnl/grouped-checkboxes)
[![React](https://img.shields.io/badge/React-^16.8.0-brightgreen)](https://github.com/facebook/react)

An easy to use React Component to create a checkbox group with a checkbox to check all checkboxes.
An easy to use React Component to create a checkbox group with a checkbox to check all checkboxes and a checkbox to check none.

## Installation
```
Expand All @@ -16,6 +16,8 @@ yarn add @createnl/grouped-checkboxes
```

## Example
[![See examples](example.gif)](https://v5sww.csb.app/)

Live examples: https://v5sww.csb.app/

Codesandbox: https://codesandbox.io/s/grouped-checkboxes-v5sww
Expand Down Expand Up @@ -44,7 +46,7 @@ Note that:
- All checkboxes and allCheckerCheckboxes must have an unique id

## Features
- Multiple `AllCheckerCheckboxes` inside a group
- Multiple `AllCheckerCheckboxes` and `NoneCheckerCheckboxes` inside a group
- `onChange` callback on group
- Possibility to nest checkboxes in your own components
- Possibility to check or disable by default
Expand All @@ -69,7 +71,7 @@ Note that:
</CheckboxGroup>
```

### Real life example
### Real life example (with check all)
``` jsx harmony
import React from "react";
import { AllCheckerCheckbox, Checkbox, CheckboxGroup } from 'grouped-checkboxes';
Expand Down Expand Up @@ -108,7 +110,7 @@ The value of an onChange parameter looks like:
{
"checked": true,
"disabled": false,
"id": "tos",
"id": "tos"
},
{
"checked": true,
Expand All @@ -123,3 +125,61 @@ The value of an onChange parameter looks like:
]
```
All given props will be accessible.

### Real life example (with none-checker)
If you need a checkbox that will check when nothing is checked you can use the NoneCheckerCheckbox.
This checkbox can be clicked to uncheck everything else, but can't be unchecked to check everything else.

``` jsx harmony
import React from "react";
import { NoneCheckerCheckbox, Checkbox, CheckboxGroup } from 'grouped-checkboxes';

const LunchDeclaration = (props) => {
const onCheckboxChange = (checkboxes) => {
console.log(checkboxes);
}

return (
<CheckboxGroup onChange={console.log}>
<h1>What did you eat for lunch?</h1>
<label>
<Checkbox id="pizza" />
Pizza
</label>
<label>
<Checkbox id="burger" />
Burger
</label>
<label>
<Checkbox id="fries" />
Fries
</label>
<label>
<NoneCheckerCheckbox id="nothing" />
Nothing
</label>
</CheckboxGroup>
);
};
```
The value of an onChange parameter looks like:
```json
[
{
"checked": true,
"disabled": false,
"id": "pizza"
},
{
"checked": true,
"disabled": false,
"id": "burger"
},
{
"checked": true,
"disabled": false,
"id": "fries"
}
]
```
Note that the value of the NoneCheckerCheckbox will not be passed.
159 changes: 159 additions & 0 deletions __tests__/AllCheckboxEventTests.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import {cleanup, fireEvent, render} from '@testing-library/react';
import React from 'react';
import {AllCheckerCheckbox, Checkbox, CheckboxGroup} from "../src";

// automatically unmount and cleanup DOM after the test is finished.
afterEach(cleanup);

it('Unchecked allCheckerCheckbox will check on click', () => {
const component = render(
<CheckboxGroup>
<AllCheckerCheckbox id={"test-checkbox"} data-testid="test-checkbox" />
</CheckboxGroup>
);

const checkbox = component.getByTestId('test-checkbox') as HTMLInputElement;

expect(checkbox.checked).toEqual(false);
fireEvent.click(checkbox);
expect(checkbox.checked).toEqual(true);
});

it('Checked allCheckerCheckbox will uncheck on click', () => {
const component = render(
<CheckboxGroup defaultChecked>
<AllCheckerCheckbox id={"test-checkbox"} data-testid="test-checkbox" />
</CheckboxGroup>
);

const checkbox = component.getByTestId('test-checkbox') as HTMLInputElement;

expect(checkbox.checked).toEqual(true);
fireEvent.click(checkbox);
expect(checkbox.checked).toEqual(false);
});

it('All checkboxes will check on allCheckboxesChecker click', () => {
const component = render(
<CheckboxGroup>
<AllCheckerCheckbox id={"all-checker-checkbox"} data-testid="all-checker-checkbox" />
<Checkbox id={"test-checkbox-1"} data-testid="test-checkbox-1" />
<Checkbox id={"test-checkbox-2"} data-testid="test-checkbox-2" />
</CheckboxGroup>
);

const allCheckerCheckbox = component.getByTestId('all-checker-checkbox') as HTMLInputElement;
const checkbox1 = component.getByTestId('test-checkbox-1') as HTMLInputElement;
const checkbox2 = component.getByTestId('test-checkbox-2') as HTMLInputElement;

expect(checkbox1.checked).toEqual(false);
expect(checkbox2.checked).toEqual(false);
fireEvent.click(allCheckerCheckbox);
expect(checkbox1.checked).toEqual(true);
expect(checkbox2.checked).toEqual(true);
});

it('All checkboxes will uncheck on allCheckboxesChecker click', () => {
const component = render(
<CheckboxGroup>
<AllCheckerCheckbox id={"all-checker-checkbox"} data-testid="all-checker-checkbox" />
<Checkbox id={"test-checkbox-1"} data-testid="test-checkbox-1" checked/>
<Checkbox id={"test-checkbox-2"} data-testid="test-checkbox-2" checked/>
</CheckboxGroup>
);

const allCheckerCheckbox = component.getByTestId('all-checker-checkbox') as HTMLInputElement;
const checkbox1 = component.getByTestId('test-checkbox-1') as HTMLInputElement;
const checkbox2 = component.getByTestId('test-checkbox-2') as HTMLInputElement;

expect(checkbox1.checked).toEqual(true);
expect(checkbox2.checked).toEqual(true);
fireEvent.click(allCheckerCheckbox);
expect(checkbox1.checked).toEqual(false);
expect(checkbox2.checked).toEqual(false);
});


it('All allCheckerCheckboxes will uncheck when not all checkboxes are checked', () => {
const component = render(
<CheckboxGroup>
<AllCheckerCheckbox id={"all-checker-checkbox-1"} data-testid="all-checker-checkbox-1" />
<Checkbox id={"test-checkbox-1"} data-testid="test-checkbox" checked/>
<Checkbox id={"test-checkbox-2"} checked/>
<Checkbox id={"test-checkbox-3"} checked/>
<AllCheckerCheckbox id={"all-checker-checkbox-2"} data-testid="all-checker-checkbox-2" />
</CheckboxGroup>
);

const allCheckerCheckbox1 = component.getByTestId('all-checker-checkbox-1') as HTMLInputElement;
const allCheckerCheckbox2 = component.getByTestId('all-checker-checkbox-2') as HTMLInputElement;
const checkbox = component.getByTestId('test-checkbox') as HTMLInputElement;

expect(allCheckerCheckbox1.checked).toEqual(true);
expect(allCheckerCheckbox2.checked).toEqual(true);
fireEvent.click(checkbox);
expect(allCheckerCheckbox1.checked).toEqual(false);
expect(allCheckerCheckbox2.checked).toEqual(false);
});

it('All allCheckerCheckboxes will check when all checkboxes are checked', () => {
const component = render(
<CheckboxGroup>
<AllCheckerCheckbox id={"all-checker-checkbox-1"} data-testid="all-checker-checkbox-1" />
<Checkbox id={"test-checkbox-1"} data-testid="test-checkbox-1" />
<Checkbox id={"test-checkbox-2"} data-testid="test-checkbox-2" />
<Checkbox id={"test-checkbox-3"} data-testid="test-checkbox-3" />
<AllCheckerCheckbox id={"all-checker-checkbox-2"} data-testid="all-checker-checkbox-2" />
</CheckboxGroup>
);

const allCheckerCheckbox1 = component.getByTestId('all-checker-checkbox-1') as HTMLInputElement;
const allCheckerCheckbox2 = component.getByTestId('all-checker-checkbox-2') as HTMLInputElement;
const checkbox1 = component.getByTestId('test-checkbox-1') as HTMLInputElement;
const checkbox2 = component.getByTestId('test-checkbox-2') as HTMLInputElement;
const checkbox3 = component.getByTestId('test-checkbox-3') as HTMLInputElement;

expect(allCheckerCheckbox1.checked).toEqual(false);
expect(allCheckerCheckbox2.checked).toEqual(false);
fireEvent.click(checkbox1);
fireEvent.click(checkbox2);
fireEvent.click(checkbox3);
expect(allCheckerCheckbox1.checked).toEqual(true);
expect(allCheckerCheckbox2.checked).toEqual(true);
});

it('Click on allCheckerCheckbox will trigger onChange on checkboxGroup', () => {
const testOnChange = jest.fn();

const component = render(
<CheckboxGroup onChange={testOnChange}>
<AllCheckerCheckbox id={"all-checker-checkbox-1"} data-testid="all-checker-checkbox-1" />
<Checkbox id={"test-checkbox-1"} data-testid="test-checkbox-1" />
<Checkbox id={"test-checkbox-2"} data-testid="test-checkbox-2" />
<Checkbox id={"test-checkbox-3"} data-testid="test-checkbox-3" />
<AllCheckerCheckbox id={"all-checker-checkbox-2"} data-testid="all-checker-checkbox-2" />
</CheckboxGroup>
);
setTimeout(() => {
const allCheckerCheckbox1 = component.getByTestId('all-checker-checkbox-1') as HTMLInputElement;
fireEvent.click(allCheckerCheckbox1);
expect(testOnChange.mock.calls.length).toBe(1);
}, 251);
});

it('Click will trigger onChange on allCheckerCheckbox', () => {
const testOnChange = jest.fn();

const component = render(
<CheckboxGroup>
<AllCheckerCheckbox id={"test-checkbox"} data-testid="test-checkbox" onChange={testOnChange} />
</CheckboxGroup>
);

const checkbox1 = component.getByTestId('test-checkbox') as HTMLInputElement;

fireEvent.click(checkbox1);
expect(testOnChange.mock.calls.length).toBe(1);
});


17 changes: 15 additions & 2 deletions __tests__/CheckboxDefaultsTest.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {cleanup, render} from '@testing-library/react';
import React from 'react';
import {AllCheckerCheckbox, Checkbox, CheckboxGroup} from "../src";
import {AllCheckerCheckbox, Checkbox, CheckboxGroup, NoneCheckerCheckbox} from "../src";

// automatically unmount and cleanup DOM after the test is finished.
afterEach(cleanup);
Expand Down Expand Up @@ -270,46 +270,59 @@ it('CheckboxGroup with default disabled combination of checkboxes and allChecker
it('CheckboxGroup without default disabled combination of checkboxes and allCheckerCheckbox will be disabled', () => {
const component = render(
<CheckboxGroup>
<NoneCheckerCheckbox id={"test-checkbox-6"} data-testid="test-checkbox-6" />
<AllCheckerCheckbox id={"test-checkbox-1"} data-testid="test-checkbox-1" />
<Checkbox id={"test-checkbox-2"} data-testid="test-checkbox-2" />
<Checkbox id={"test-checkbox-3"} data-testid="test-checkbox-3" />
<AllCheckerCheckbox id={"test-checkbox-4"} data-testid="test-checkbox-4" />
<NoneCheckerCheckbox id={"test-checkbox-5"} data-testid="test-checkbox-5" />
</CheckboxGroup>
);

const checkbox1 = component.getByTestId('test-checkbox-1') as HTMLInputElement;
const checkbox2 = component.getByTestId('test-checkbox-2') as HTMLInputElement;
const checkbox3 = component.getByTestId('test-checkbox-3') as HTMLInputElement;
const checkbox4 = component.getByTestId('test-checkbox-4') as HTMLInputElement;
const checkbox5 = component.getByTestId('test-checkbox-5') as HTMLInputElement;
const checkbox6 = component.getByTestId('test-checkbox-6') as HTMLInputElement;

expect(checkbox1.disabled).toEqual(false);
expect(checkbox2.disabled).toEqual(false);
expect(checkbox3.disabled).toEqual(false);
expect(checkbox4.disabled).toEqual(false);
expect(checkbox5.disabled).toEqual(false);
expect(checkbox6.disabled).toEqual(false);
});

it('CheckboxGroup with default checked and default disabled combination of checkboxes and allCheckerCheckbox will be checked and disabled', () => {
const component = render(
<CheckboxGroup defaultChecked defaultDisabled>
<NoneCheckerCheckbox id={"test-checkbox-6"} data-testid="test-checkbox-6" />
<AllCheckerCheckbox id={"test-checkbox-1"} data-testid="test-checkbox-1" />
<Checkbox id={"test-checkbox-2"} data-testid="test-checkbox-2" />
<Checkbox id={"test-checkbox-3"} data-testid="test-checkbox-3" />
<AllCheckerCheckbox id={"test-checkbox-4"} data-testid="test-checkbox-4" />
<NoneCheckerCheckbox id={"test-checkbox-5"} data-testid="test-checkbox-5" />
</CheckboxGroup>
);

const checkbox1 = component.getByTestId('test-checkbox-1') as HTMLInputElement;
const checkbox2 = component.getByTestId('test-checkbox-2') as HTMLInputElement;
const checkbox3 = component.getByTestId('test-checkbox-3') as HTMLInputElement;
const checkbox4 = component.getByTestId('test-checkbox-4') as HTMLInputElement;
const checkbox5 = component.getByTestId('test-checkbox-5') as HTMLInputElement;
const checkbox6 = component.getByTestId('test-checkbox-6') as HTMLInputElement;

expect(checkbox1.checked).toEqual(true);
expect(checkbox2.checked).toEqual(true);
expect(checkbox3.checked).toEqual(true);
expect(checkbox4.checked).toEqual(true);
expect(checkbox5.checked).toEqual(false);
expect(checkbox6.checked).toEqual(false);

expect(checkbox1.disabled).toEqual(true);
expect(checkbox2.disabled).toEqual(true);
expect(checkbox3.disabled).toEqual(true);
expect(checkbox4.disabled).toEqual(true);
expect(checkbox5.disabled).toEqual(true);
expect(checkbox6.disabled).toEqual(true);
});
Loading

0 comments on commit 0cb0659

Please sign in to comment.