project setup

This commit is contained in:
Sone
2025-11-02 10:08:56 +01:00
commit 568838003e
174 changed files with 27100 additions and 0 deletions
+110
View File
@@ -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>
);
};