@createnl/grouped-checkboxes
Advanced tools
Comparing version 0.0.2 to 1.0.0
@@ -34,9 +34,4 @@ "use strict"; | ||
var _e = react_1.useState(disabled !== undefined ? disabled : checkboxGroup.defaultDisabled), isDisabled = _e[0], setIsDisabled = _e[1]; | ||
var assertIdDoesNotExist = function (subject) { | ||
if (checkboxGroup.checkboxes.has(subject) || checkboxGroup.allCheckerCheckboxes.has(subject)) { | ||
throw new Error("Duplicate id " + subject + " in CheckboxGroup"); | ||
} | ||
}; | ||
react_1.useEffect(function () { | ||
assertIdDoesNotExist(id); | ||
checkboxGroup.assertIdDoesNotExist(id); | ||
return function () { | ||
@@ -48,3 +43,3 @@ checkboxGroup.allCheckerCheckboxes.delete(id); | ||
if (prevId !== id) { | ||
assertIdDoesNotExist(id); | ||
checkboxGroup.assertIdDoesNotExist(id); | ||
checkboxGroup.allCheckerCheckboxes.delete(prevId); | ||
@@ -51,0 +46,0 @@ setInitialized(false); |
@@ -33,9 +33,4 @@ "use strict"; | ||
var _d = react_1.useState(disabled !== undefined ? disabled : checkboxGroup.defaultDisabled), isDisabled = _d[0], setIsDisabled = _d[1]; | ||
var assertIdDoesNotExist = function (subject) { | ||
if (checkboxGroup.checkboxes.has(subject) || checkboxGroup.allCheckerCheckboxes.has(subject)) { | ||
throw new Error("Duplicate id " + subject + " in CheckboxGroup"); | ||
} | ||
}; | ||
react_1.useEffect(function () { | ||
assertIdDoesNotExist(id); | ||
checkboxGroup.assertIdDoesNotExist(id); | ||
return function () { | ||
@@ -54,3 +49,3 @@ checkboxGroup.checkboxes.delete(id); | ||
if (prevId !== id) { | ||
assertIdDoesNotExist(id); | ||
checkboxGroup.assertIdDoesNotExist(id); | ||
checkboxGroup.checkboxes.delete(prevId); | ||
@@ -57,0 +52,0 @@ setPrevId(id); |
@@ -13,2 +13,5 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
@@ -21,8 +24,7 @@ if (mod && mod.__esModule) return mod; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var lodash_debounce_1 = __importDefault(require("lodash.debounce")); | ||
var react_1 = __importStar(require("react")); | ||
var CheckboxGroupContext_1 = __importDefault(require("./CheckboxGroupContext")); | ||
var ON_CHANGE_DEBOUNCE_TIMEOUT = 100; | ||
var CheckboxGroup = function (_a) { | ||
@@ -32,2 +34,3 @@ var children = _a.children, defaultChecked = _a.defaultChecked, defaultDisabled = _a.defaultDisabled, onChange = _a.onChange; | ||
var allCheckerCheckboxes = react_1.useState(new Map())[0]; | ||
var noneCheckerCheckboxes = react_1.useState(new Map())[0]; | ||
var dispatchOnChange = function () { | ||
@@ -43,4 +46,6 @@ if (onChange === undefined) { | ||
}; | ||
var debouncedOnChange = lodash_debounce_1.default(dispatchOnChange, ON_CHANGE_DEBOUNCE_TIMEOUT); | ||
var setAllCheckboxesChecked = function (state) { | ||
allCheckerCheckboxes.forEach(function (checkbox) { return checkbox.setIsChecked(state); }); | ||
noneCheckerCheckboxes.forEach(function (checkbox) { return checkbox.setIsChecked(!state); }); | ||
checkboxes.forEach(function (checkbox, key) { | ||
@@ -53,15 +58,22 @@ var clone = checkbox; | ||
}; | ||
var allCheckboxesAreChecked = function () { | ||
var amountChecked = 0; | ||
var amountChecked = function () { | ||
var count = 0; | ||
checkboxes.forEach(function (checkbox) { | ||
if (checkbox.isChecked === true) { | ||
amountChecked += 1; | ||
count += 1; | ||
} | ||
}); | ||
return amountChecked > 0 && amountChecked === checkboxes.size; | ||
return count; | ||
}; | ||
var allCheckboxesAreChecked = function () { | ||
var checkedCount = amountChecked(); | ||
return checkedCount > 0 && checkedCount === checkboxes.size; | ||
}; | ||
var allCheckboxesAreNotChecked = function () { return amountChecked() === 0; }; | ||
var onCheckboxChange = function () { | ||
var allChecked = allCheckboxesAreChecked(); | ||
allCheckerCheckboxes.forEach(function (checkbox) { return checkbox.setIsChecked(allChecked); }); | ||
dispatchOnChange(); | ||
var noneChecked = allCheckboxesAreNotChecked(); | ||
noneCheckerCheckboxes.forEach(function (checkbox) { return checkbox.setIsChecked(noneChecked); }); | ||
debouncedOnChange(); | ||
}; | ||
@@ -75,3 +87,3 @@ var onAllCheckerCheckboxChange = function (key, initialized) { | ||
setAllCheckboxesChecked(allCheckerCheckbox.isChecked === true); | ||
dispatchOnChange(); | ||
debouncedOnChange(); | ||
} | ||
@@ -82,9 +94,31 @@ else { | ||
}; | ||
var onNoneCheckerCheckboxChange = function (key, initialized) { | ||
var noneCheckerCheckbox = noneCheckerCheckboxes.get(key); | ||
if (!noneCheckerCheckbox) { | ||
return; | ||
} | ||
if (initialized && noneCheckerCheckbox.isChecked) { | ||
setAllCheckboxesChecked(false); | ||
debouncedOnChange(); | ||
} | ||
else if (!noneCheckerCheckbox.isChecked && allCheckboxesAreNotChecked()) { | ||
noneCheckerCheckbox.setIsChecked(true); | ||
} | ||
}; | ||
var hasCheckbox = function (id) { return checkboxes.has(id) || allCheckerCheckboxes.has(id) || noneCheckerCheckboxes.has(id); }; | ||
var assertIdDoesNotExist = function (subject) { | ||
if (hasCheckbox(subject)) { | ||
throw new Error("Duplicate id " + subject + " in CheckboxGroup"); | ||
} | ||
}; | ||
var contextValue = { | ||
allCheckerCheckboxes: allCheckerCheckboxes, | ||
assertIdDoesNotExist: assertIdDoesNotExist, | ||
checkboxes: checkboxes, | ||
defaultChecked: defaultChecked, | ||
defaultDisabled: defaultDisabled, | ||
noneCheckerCheckboxes: noneCheckerCheckboxes, | ||
onAllCheckerCheckboxChange: onAllCheckerCheckboxChange, | ||
onCheckboxChange: onCheckboxChange, | ||
onNoneCheckerCheckboxChange: onNoneCheckerCheckboxChange, | ||
}; | ||
@@ -91,0 +125,0 @@ return (react_1.default.createElement(CheckboxGroupContext_1.default.Provider, { value: contextValue }, children)); |
@@ -13,8 +13,11 @@ import React from 'react'; | ||
allCheckerCheckboxes: Map<string, CheckboxEntry>; | ||
assertIdDoesNotExist: (id: string) => void; | ||
checkboxes: Map<string, CheckboxEntry>; | ||
defaultChecked?: boolean | undefined; | ||
defaultDisabled?: boolean | undefined; | ||
noneCheckerCheckboxes: Map<string, CheckboxEntry>; | ||
onAllCheckerCheckboxChange: (key: string, initialized: boolean) => void; | ||
onCheckboxChange: () => void; | ||
onNoneCheckerCheckboxChange: (key: string, initialized: boolean) => void; | ||
}>; | ||
export default _default; |
@@ -10,4 +10,9 @@ "use strict"; | ||
allCheckerCheckboxes: new Map(), | ||
assertIdDoesNotExist: function () { | ||
return; | ||
}, | ||
checkboxes: new Map(), | ||
defaultChecked: false, | ||
defaultDisabled: false, | ||
noneCheckerCheckboxes: new Map(), | ||
onAllCheckerCheckboxChange: function () { | ||
@@ -19,3 +24,6 @@ return; | ||
}, | ||
onNoneCheckerCheckboxChange: function () { | ||
return; | ||
}, | ||
}); | ||
//# sourceMappingURL=CheckboxGroupContext.js.map |
import AllCheckerCheckbox from "./AllCheckerCheckbox"; | ||
import Checkbox from "./Checkbox"; | ||
import CheckboxGroup from "./CheckboxGroup"; | ||
export { AllCheckerCheckbox, Checkbox, CheckboxGroup, }; | ||
import NoneCheckerCheckbox from "./NoneCheckerCheckbox"; | ||
export { AllCheckerCheckbox, Checkbox, CheckboxGroup, NoneCheckerCheckbox, }; |
@@ -12,2 +12,4 @@ "use strict"; | ||
exports.CheckboxGroup = CheckboxGroup_1.default; | ||
var NoneCheckerCheckbox_1 = __importDefault(require("./NoneCheckerCheckbox")); | ||
exports.NoneCheckerCheckbox = NoneCheckerCheckbox_1.default; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@createnl/grouped-checkboxes", | ||
"version": "0.0.2", | ||
"version": "1.0.0", | ||
"description": "Grouped checkboxes with check-all checkboxes", | ||
@@ -28,17 +28,17 @@ "repository": { | ||
"devDependencies": { | ||
"@testing-library/react": "^9.2.0", | ||
"@types/jest": "^24.0.18", | ||
"@testing-library/react": "^9.3.2", | ||
"@types/jest": "^24.0.22", | ||
"@types/lodash.debounce": "^4.0.6", | ||
"@types/react": "^16.9.3", | ||
"@types/react-dom": "^16.9.1", | ||
"@types/react": "^16.9.11", | ||
"@types/react-dom": "^16.9.4", | ||
"jest": "^24.9.0", | ||
"react": "^16.8.*", | ||
"react-dom": "^16.9.0", | ||
"react-test-renderer": "^16.9.0", | ||
"react-test-renderer": "^16.11.0", | ||
"ts-jest": "^24.1.0", | ||
"tslint": "^5.20.0", | ||
"tslint": "^5.20.1", | ||
"tslint-config-prettier": "^1.18.0", | ||
"tslint-react": "^4.1.0", | ||
"tslint-react-hooks": "^2.2.1", | ||
"typescript": "^3.6.3" | ||
"typescript": "^3.7.2" | ||
}, | ||
@@ -45,0 +45,0 @@ "jest": { |
@@ -8,3 +8,3 @@ # Grouped Checkboxes | ||
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. | ||
@@ -20,2 +20,4 @@ ## Installation | ||
## Example | ||
[![See examples](example.gif)](https://v5sww.csb.app/) | ||
Live examples: https://v5sww.csb.app/ | ||
@@ -49,3 +51,3 @@ | ||
## Features | ||
- Multiple `AllCheckerCheckboxes` inside a group | ||
- Multiple `AllCheckerCheckboxes` and `NoneCheckerCheckboxes` inside a group | ||
- `onChange` callback on group | ||
@@ -75,3 +77,3 @@ - Possibility to nest checkboxes in your own components | ||
### Real life example | ||
### Real life example (with check all) | ||
``` jsx harmony | ||
@@ -115,3 +117,3 @@ import React from "react"; | ||
"disabled": false, | ||
"id": "tos", | ||
"id": "tos" | ||
}, | ||
@@ -131,1 +133,59 @@ { | ||
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. |
@@ -5,26 +5,37 @@ /* istanbul ignore file */ | ||
export interface CheckboxEntry { | ||
isChecked?: boolean; | ||
setIsChecked: (checked: boolean) => void; | ||
isDisabled?: boolean; | ||
setIsDisabled: (disabled: boolean) => void; | ||
props: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> & { id: string }; | ||
isChecked?: boolean; | ||
setIsChecked: (checked: boolean) => void; | ||
isDisabled?: boolean; | ||
setIsDisabled: (disabled: boolean) => void; | ||
props: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> & { id: string }; | ||
} | ||
export default React.createContext<{ | ||
allCheckerCheckboxes: Map<string, CheckboxEntry>; | ||
checkboxes: Map<string, CheckboxEntry>; | ||
defaultChecked?: boolean; | ||
defaultDisabled?: boolean; | ||
onAllCheckerCheckboxChange: (key: string, initialized: boolean) => void; | ||
onCheckboxChange: () => void; | ||
allCheckerCheckboxes: Map<string, CheckboxEntry>; | ||
assertIdDoesNotExist: (id: string) => void; | ||
checkboxes: Map<string, CheckboxEntry>; | ||
defaultChecked?: boolean; | ||
defaultDisabled?: boolean; | ||
noneCheckerCheckboxes: Map<string, CheckboxEntry>; | ||
onAllCheckerCheckboxChange: (key: string, initialized: boolean) => void; | ||
onCheckboxChange: () => void; | ||
onNoneCheckerCheckboxChange: (key: string, initialized: boolean) => void; | ||
}>({ | ||
allCheckerCheckboxes: new Map<string, CheckboxEntry>(), | ||
checkboxes: new Map<string, CheckboxEntry>(), | ||
defaultChecked: false, | ||
onAllCheckerCheckboxChange: (): void => { | ||
return; | ||
}, | ||
onCheckboxChange: (): void => { | ||
return; | ||
}, | ||
}); | ||
allCheckerCheckboxes: new Map<string, CheckboxEntry>(), | ||
assertIdDoesNotExist: (): void => { | ||
return; | ||
}, | ||
checkboxes: new Map<string, CheckboxEntry>(), | ||
defaultChecked: false, | ||
defaultDisabled: false, | ||
noneCheckerCheckboxes: new Map<string, CheckboxEntry>(), | ||
onAllCheckerCheckboxChange: (): void => { | ||
return; | ||
}, | ||
onCheckboxChange: (): void => { | ||
return; | ||
}, | ||
onNoneCheckerCheckboxChange: (): void => { | ||
return; | ||
}, | ||
}); |
import AllCheckerCheckbox from "./AllCheckerCheckbox"; | ||
import Checkbox from "./Checkbox"; | ||
import CheckboxGroup from "./CheckboxGroup"; | ||
import NoneCheckerCheckbox from "./NoneCheckerCheckbox"; | ||
@@ -9,2 +10,3 @@ export { | ||
CheckboxGroup, | ||
NoneCheckerCheckbox, | ||
} |
{ | ||
"defaultSeverity": "error", | ||
"extends": [ | ||
"tslint:latest", | ||
"tslint:recommended", | ||
@@ -5,0 +6,0 @@ "tslint-react", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
143949
39
1795
0
186