115 lines
2.7 KiB
TypeScript
115 lines
2.7 KiB
TypeScript
import { Box, Text, UnstyledButton, Flex, Stack } from "@mantine/core";
|
|
import { CaretRightIcon } from "@phosphor-icons/react";
|
|
import React, { ComponentType, useContext } from "react";
|
|
import { SlidePanelContext } from "./slide-panel-context";
|
|
|
|
interface SlidePanelFieldProps {
|
|
key: string;
|
|
value?: any;
|
|
onChange?: (value: any) => void;
|
|
Component: ComponentType<any>;
|
|
title: string;
|
|
label?: string;
|
|
placeholder?: string;
|
|
formatValue?: (value: any) => string | React.ReactNode;
|
|
componentProps?: Record<string, any>;
|
|
withAsterisk?: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
const SlidePanelField = ({
|
|
value,
|
|
onChange,
|
|
Component,
|
|
title,
|
|
label,
|
|
placeholder = "Select value",
|
|
withAsterisk = false,
|
|
formatValue,
|
|
componentProps,
|
|
error,
|
|
}: SlidePanelFieldProps) => {
|
|
const context = useContext(SlidePanelContext);
|
|
|
|
if (!context) {
|
|
throw new Error("SlidePanelField must be used within a SlidePanel");
|
|
}
|
|
|
|
const handleClick = () => {
|
|
if (!onChange) return;
|
|
|
|
context.openPanel({
|
|
title,
|
|
Component,
|
|
value,
|
|
onChange,
|
|
componentProps,
|
|
});
|
|
};
|
|
|
|
const displayValue = () => {
|
|
if (formatValue && value != null) {
|
|
return formatValue(value);
|
|
}
|
|
if (value != null) {
|
|
if (value instanceof Date) {
|
|
return value.toLocaleDateString();
|
|
}
|
|
return String(value);
|
|
}
|
|
return placeholder;
|
|
};
|
|
|
|
return (
|
|
<Box>
|
|
<UnstyledButton
|
|
onClick={handleClick}
|
|
p="sm"
|
|
style={{
|
|
width: "100%",
|
|
border: error
|
|
? "1px solid var(--mantine-color-error)"
|
|
: "1px solid var(--mantine-color-dimmed)",
|
|
borderRadius: "var(--mantine-radius-md)",
|
|
backgroundColor: "var(--mantine-color-body)",
|
|
textAlign: "left",
|
|
}}
|
|
>
|
|
<Flex justify="space-between" align="center">
|
|
<Stack>
|
|
<Text size="sm" fw={500}>
|
|
{label}
|
|
{withAsterisk && (
|
|
<Text
|
|
span
|
|
size="sm"
|
|
c="var(--mantine-color-error)"
|
|
fw={500}
|
|
ml={4}
|
|
>
|
|
*
|
|
</Text>
|
|
)}
|
|
</Text>
|
|
<Text size="sm" c="dimmed">
|
|
{displayValue()}
|
|
</Text>
|
|
</Stack>
|
|
<CaretRightIcon
|
|
size={24}
|
|
weight="thin"
|
|
style={{ marginRight: "12px" }}
|
|
/>
|
|
</Flex>
|
|
</UnstyledButton>
|
|
{error && (
|
|
<Text size="xs" c="var(--mantine-color-error)" fw={500} ml={4} mt={4}>
|
|
{error}
|
|
</Text>
|
|
)}
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export { SlidePanelField };
|