project setup
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { View, TouchableOpacity } from "react-native";
|
||||
import { Menu, Text, IconButton, Divider } from "react-native-paper";
|
||||
|
||||
import { MultiSelectGlyph } from "./filters/MultiSelectGlyph";
|
||||
|
||||
export type FilterOption = {
|
||||
value: string;
|
||||
label: string;
|
||||
icon?: React.ReactNode;
|
||||
};
|
||||
|
||||
interface FilterMultiSelectProps {
|
||||
label: string;
|
||||
options: FilterOption[];
|
||||
selected: string[];
|
||||
onChange: (values: string[]) => void;
|
||||
iconName?: string;
|
||||
className?: string;
|
||||
menuWidth?: number;
|
||||
showClearAll?: boolean;
|
||||
}
|
||||
|
||||
export const FilterMultiSelect = ({
|
||||
label,
|
||||
options,
|
||||
selected,
|
||||
onChange,
|
||||
iconName = undefined,
|
||||
className,
|
||||
menuWidth,
|
||||
showClearAll = true,
|
||||
}: FilterMultiSelectProps) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const selectedSet = useMemo(() => new Set(selected), [selected]);
|
||||
|
||||
const toggle = (value: string) => {
|
||||
const next = new Set(selectedSet);
|
||||
if (next.has(value)) {
|
||||
next.delete(value);
|
||||
} else {
|
||||
next.add(value);
|
||||
}
|
||||
onChange(Array.from(next));
|
||||
};
|
||||
|
||||
const anchor = (
|
||||
<TouchableOpacity
|
||||
onPress={() => setVisible(true)}
|
||||
className={`flex-row items-center px-2 h-8 rounded ${className || ""}`}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={{ fontSize: 12, color: "#000" }}>{label}</Text>
|
||||
{iconName ? (
|
||||
<IconButton
|
||||
icon={iconName}
|
||||
size={18}
|
||||
onPress={() => setVisible(true)}
|
||||
/>
|
||||
) : (
|
||||
<MultiSelectGlyph />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
visible={visible}
|
||||
onDismiss={() => setVisible(false)}
|
||||
anchor={anchor}
|
||||
contentStyle={menuWidth ? { width: menuWidth } : undefined}
|
||||
>
|
||||
{options.map((opt) => {
|
||||
const isSelected = selectedSet.has(opt.value);
|
||||
return (
|
||||
<Menu.Item
|
||||
key={opt.value}
|
||||
onPress={() => toggle(opt.value)}
|
||||
leadingIcon={
|
||||
isSelected ? "checkbox-marked" : "checkbox-blank-outline"
|
||||
}
|
||||
title={
|
||||
<View className="flex-row items-center">
|
||||
{opt.icon ? <View className="mr-2">{opt.icon}</View> : null}
|
||||
<Text>{opt.label}</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{showClearAll && (
|
||||
<>
|
||||
<Divider />
|
||||
<Menu.Item
|
||||
onPress={() => onChange([])}
|
||||
leadingIcon="close-circle-outline"
|
||||
disabled={selectedSet.size === 0}
|
||||
title="Clear all"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Menu.Item
|
||||
onPress={() => setVisible(false)}
|
||||
leadingIcon="check"
|
||||
title="Done"
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user