react-native-bouncy-checkbox-group
Version:
Fully customizable bouncy checkbox group for React Native
85 lines • 4.23 kB
JavaScript
import * as React from "react";
import { View } from "react-native";
import BouncyCheckbox from "react-native-bouncy-checkbox";
import styles from "./BouncyCheckboxGroup.style";
import useStateWithCallback from "./helpers/useStateWithCallback";
const BouncyCheckboxGroup = ({ style, checkboxProps, initial, data, onChange, multiple = false, alwaysSelect = false, animationDuration = 300, spacing = 0, itemContainerStyle, }) => {
const normalizeId = (id) => String(id);
const getInitialSelection = React.useCallback(() => {
if (!initial) {
// If alwaysSelect is true and no initial is provided, select the first item
if (alwaysSelect && !multiple && data.length > 0) {
return [data[0]];
}
return [];
}
// Convert the initial value to array of strings for comparison
const initialIds = Array.isArray(initial)
? initial.map(normalizeId)
: [normalizeId(initial)];
return data.filter((item) => initialIds.includes(normalizeId(item.id)));
}, [initial, data, alwaysSelect, multiple]);
const [selectedItems, setSelectedItems] = useStateWithCallback(getInitialSelection());
// Handle selection changes
const updateSelection = React.useCallback((newItems) => {
setSelectedItems(newItems, (items) => {
onChange(multiple ? items : items[0]);
});
}, [multiple, onChange, setSelectedItems]);
// Check if a specific item is currently selected
const isItemSelected = React.useCallback((item) => {
return selectedItems.some((selectedItem) => normalizeId(selectedItem.id) === normalizeId(item.id));
}, [selectedItems]);
const handleItemPress = React.useCallback((item) => {
if (multiple) {
// For multiple selection mode
const isSelected = isItemSelected(item);
let newSelectedItems;
if (isSelected) {
// Remove from selection
newSelectedItems = selectedItems.filter((selectedItem) => normalizeId(selectedItem.id) !== normalizeId(item.id));
}
else {
// Add to selection
newSelectedItems = [...selectedItems, item];
}
updateSelection(newSelectedItems);
}
else {
// For single selection mode
const isSelected = isItemSelected(item);
// If alwaysSelect is true and this is the only selected item,
// don't allow deselection by tapping it again
if (isSelected && alwaysSelect && selectedItems.length === 1) {
return;
}
// If the item is already selected and we can deselect it, deselect it
// Otherwise, select the new item
const newSelectedItems = isSelected ? [] : [item];
updateSelection(newSelectedItems);
}
}, [multiple, selectedItems, alwaysSelect, isItemSelected, updateSelection]);
// Render a single checkbox with appropriate configuration
const renderCheckbox = React.useCallback((item) => {
const { id, ...checkboxItemProps } = item;
const isSelected = isItemSelected(item);
// Determine if this checkbox should be disallowed from toggling off
// (When it's an already selected item in alwaysSelect mode)
const isUntoggleable = alwaysSelect && !multiple && isSelected && selectedItems.length === 1;
return (<View key={normalizeId(id)} style={[{ marginRight: spacing }, itemContainerStyle]}>
<BouncyCheckbox innerIconStyle={{ borderWidth: 0 }} bounceEffect={0.8} bounceFriction={10} useNativeDriver={true} {...checkboxProps} {...checkboxItemProps} isChecked={isSelected} useBuiltInState={!isUntoggleable} onPress={() => handleItemPress(item)}/>
</View>);
}, [
spacing,
itemContainerStyle,
checkboxProps,
alwaysSelect,
multiple,
selectedItems,
isItemSelected,
handleItemPress,
]);
return (<View style={[styles.container, style]}>{data.map(renderCheckbox)}</View>);
};
export default BouncyCheckboxGroup;
//# sourceMappingURL=BouncyCheckboxGroup.js.map