prometheus/web/ui/mantine-ui/src/components/StateMultiSelect.tsx
Julius Volz 0180cf31aa
Some checks failed
CI / Go tests (push) Has been cancelled
CI / More Go tests (push) Has been cancelled
CI / Go tests with previous Go version (push) Has been cancelled
CI / UI tests (push) Has been cancelled
CI / Go tests on Windows (push) Has been cancelled
CI / Mixins tests (push) Has been cancelled
CI / Build Prometheus for common architectures (0) (push) Has been cancelled
CI / Build Prometheus for common architectures (1) (push) Has been cancelled
CI / Build Prometheus for common architectures (2) (push) Has been cancelled
CI / Build Prometheus for all architectures (0) (push) Has been cancelled
CI / Build Prometheus for all architectures (1) (push) Has been cancelled
CI / Build Prometheus for all architectures (10) (push) Has been cancelled
CI / Build Prometheus for all architectures (11) (push) Has been cancelled
CI / Build Prometheus for all architectures (2) (push) Has been cancelled
CI / Build Prometheus for all architectures (3) (push) Has been cancelled
CI / Build Prometheus for all architectures (4) (push) Has been cancelled
CI / Build Prometheus for all architectures (5) (push) Has been cancelled
CI / Build Prometheus for all architectures (6) (push) Has been cancelled
CI / Build Prometheus for all architectures (7) (push) Has been cancelled
CI / Build Prometheus for all architectures (8) (push) Has been cancelled
CI / Build Prometheus for all architectures (9) (push) Has been cancelled
CI / Check generated parser (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
CI / fuzzing (push) Has been cancelled
CI / codeql (push) Has been cancelled
CI / Report status of build Prometheus for all architectures (push) Has been cancelled
CI / Publish main branch artifacts (push) Has been cancelled
CI / Publish release artefacts (push) Has been cancelled
CI / Publish UI on npm Registry (push) Has been cancelled
Factor out common icon and card styles
Signed-off-by: Julius Volz <julius.volz@gmail.com>
2024-09-13 14:44:04 +02:00

144 lines
3.7 KiB
TypeScript

import { FC } from "react";
import {
CheckIcon,
Combobox,
ComboboxChevron,
ComboboxClearButton,
Group,
Pill,
PillsInput,
useCombobox,
} from "@mantine/core";
import { IconHeartRateMonitor } from "@tabler/icons-react";
import { inputIconStyle } from "../styles";
interface StatePillProps extends React.ComponentPropsWithoutRef<"div"> {
value: string;
onRemove?: () => void;
}
export function StatePill({ value, onRemove, ...others }: StatePillProps) {
return (
<Pill
fw={600}
style={{ textTransform: "uppercase", fontWeight: 600 }}
onRemove={onRemove}
{...others}
withRemoveButton={!!onRemove}
>
{value}
</Pill>
);
}
interface StateMultiSelectProps {
options: string[];
optionClass: (option: string) => string;
optionCount?: (option: string) => number;
placeholder: string;
values: string[];
onChange: (values: string[]) => void;
}
export const StateMultiSelect: FC<StateMultiSelectProps> = ({
options,
optionClass,
optionCount,
placeholder,
values,
onChange,
}) => {
const combobox = useCombobox({
onDropdownClose: () => combobox.resetSelectedOption(),
onDropdownOpen: () => combobox.updateSelectedOptionIndex("active"),
});
const handleValueSelect = (val: string) =>
onChange(
values.includes(val) ? values.filter((v) => v !== val) : [...values, val]
);
const handleValueRemove = (val: string) =>
onChange(values.filter((v) => v !== val));
const renderedValues = values.map((item) => (
<StatePill
value={optionCount ? `${item} (${optionCount(item)})` : item}
className={optionClass(item)}
onRemove={() => handleValueRemove(item)}
key={item}
/>
));
return (
<Combobox
store={combobox}
onOptionSubmit={handleValueSelect}
withinPortal={false}
>
<Combobox.DropdownTarget>
<PillsInput
pointer
onClick={() => combobox.toggleDropdown()}
miw={200}
leftSection={<IconHeartRateMonitor style={inputIconStyle} />}
rightSection={
values.length > 0 ? (
<ComboboxClearButton onClear={() => onChange([])} />
) : (
<ComboboxChevron />
)
}
>
<Pill.Group>
{renderedValues.length > 0 ? (
renderedValues
) : (
<PillsInput.Field placeholder={placeholder} mt={1} />
)}
<Combobox.EventsTarget>
<PillsInput.Field
type="hidden"
onBlur={() => combobox.closeDropdown()}
onKeyDown={(event) => {
if (event.key === "Backspace") {
event.preventDefault();
handleValueRemove(values[values.length - 1]);
}
}}
/>
</Combobox.EventsTarget>
</Pill.Group>
</PillsInput>
</Combobox.DropdownTarget>
<Combobox.Dropdown>
<Combobox.Options>
{options.map((value) => {
return (
<Combobox.Option
value={value}
key={value}
active={values.includes(value)}
>
<Group gap="sm">
{values.includes(value) ? (
<CheckIcon size={12} color="gray" />
) : null}
<StatePill
value={
optionCount ? `${value} (${optionCount(value)})` : value
}
className={optionClass(value)}
/>
</Group>
</Combobox.Option>
);
})}
</Combobox.Options>
</Combobox.Dropdown>
</Combobox>
);
};