significant refactor
This commit is contained in:
@@ -32,12 +32,12 @@ const SlidePanelField = ({
|
||||
const context = useContext(SlidePanelContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('SlidePanelField must be used within a SlidePanel');
|
||||
throw new Error("SlidePanelField must be used within a SlidePanel");
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
if (!onChange) return;
|
||||
|
||||
|
||||
context.openPanel({
|
||||
title,
|
||||
Component,
|
||||
@@ -64,26 +64,51 @@ const SlidePanelField = ({
|
||||
<Box>
|
||||
<UnstyledButton
|
||||
onClick={handleClick}
|
||||
p='sm'
|
||||
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',
|
||||
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>
|
||||
<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' }} />
|
||||
<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>}
|
||||
{error && (
|
||||
<Text size="xs" c="var(--mantine-color-error)" fw={500} ml={4} mt={4}>
|
||||
{error}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export { SlidePanelField };
|
||||
export { SlidePanelField };
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { Box, Text, Group, ActionIcon, ScrollArea, Divider } from "@mantine/core";
|
||||
import {
|
||||
Box,
|
||||
Text,
|
||||
Group,
|
||||
ActionIcon,
|
||||
ScrollArea,
|
||||
Divider,
|
||||
} from "@mantine/core";
|
||||
import { ArrowLeftIcon, CheckIcon } from "@phosphor-icons/react";
|
||||
import { useState, ReactNode} from "react";
|
||||
import { useState, ReactNode } from "react";
|
||||
import { SlidePanelContext, type PanelConfig } from "./slide-panel-context";
|
||||
import Button from "@/components/button";
|
||||
|
||||
@@ -15,20 +22,15 @@ interface SlidePanelProps {
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* SlidePanel is a form component meant to be used inside a drawer/modal
|
||||
* It is used to create a form with multiple views/panels that slides in from the side
|
||||
* Use with SlidePanelField for an extra panel
|
||||
*/
|
||||
const SlidePanel = ({
|
||||
children,
|
||||
const SlidePanel = ({
|
||||
children,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
submitText = "Submit",
|
||||
cancelText = "Cancel",
|
||||
maxHeight = "70vh",
|
||||
formProps = {},
|
||||
loading = false
|
||||
loading = false,
|
||||
}: SlidePanelProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [panelConfig, setPanelConfig] = useState<PanelConfig | null>(null);
|
||||
@@ -58,54 +60,62 @@ const SlidePanel = ({
|
||||
|
||||
return (
|
||||
<SlidePanelContext.Provider value={{ openPanel, closePanel }}>
|
||||
<Box
|
||||
style={{
|
||||
position: 'relative',
|
||||
<Box
|
||||
style={{
|
||||
position: "relative",
|
||||
height: maxHeight,
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
position: 'absolute',
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
transform: isOpen ? 'translateX(-100%)' : 'translateX(0)',
|
||||
transition: 'transform 0.3s ease-in-out',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
transform: isOpen ? "translateX(-100%)" : "translateX(0)",
|
||||
transition: "transform 0.3s ease-in-out",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<form
|
||||
{...formProps}
|
||||
onSubmit={handleFormSubmit}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
...formProps.style,
|
||||
}}
|
||||
>
|
||||
<ScrollArea style={{ flex: 1 }} scrollbarSize={8} scrollbars='y' type='always'>
|
||||
<Box p="md">
|
||||
{children}
|
||||
</Box>
|
||||
<ScrollArea
|
||||
style={{ flex: 1 }}
|
||||
scrollbarSize={8}
|
||||
scrollbars="y"
|
||||
type="always"
|
||||
>
|
||||
<Box p="md">{children}</Box>
|
||||
</ScrollArea>
|
||||
|
||||
<Box p="sm">
|
||||
<Group gap="md">
|
||||
<Button type="submit" fullWidth loading={loading} disabled={loading}>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
>
|
||||
{submitText}
|
||||
</Button>
|
||||
{onCancel && (
|
||||
<Button
|
||||
variant="subtle"
|
||||
color="red"
|
||||
fullWidth
|
||||
<Button
|
||||
variant="subtle"
|
||||
color="red"
|
||||
fullWidth
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
disabled={loading}
|
||||
@@ -120,32 +130,41 @@ const SlidePanel = ({
|
||||
|
||||
<Box
|
||||
style={{
|
||||
position: 'absolute',
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
transform: isOpen ? 'translateX(0)' : 'translateX(100%)',
|
||||
transition: 'transform 0.3s ease-in-out',
|
||||
backgroundColor: 'var(--mantine-color-body)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
transform: isOpen ? "translateX(0)" : "translateX(100%)",
|
||||
transition: "transform 0.3s ease-in-out",
|
||||
backgroundColor: "var(--mantine-color-body)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{panelConfig && (
|
||||
<>
|
||||
<Group justify="space-between" p="md" align="center" w='100%'>
|
||||
<Group justify="space-between" p="md" align="center" w="100%">
|
||||
<ActionIcon variant="transparent" onClick={closePanel}>
|
||||
<ArrowLeftIcon size={24} />
|
||||
</ActionIcon>
|
||||
<Text fw={500}>{panelConfig.title}</Text>
|
||||
<ActionIcon variant="transparent" color="green" onClick={handleConfirm}>
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
color="green"
|
||||
onClick={handleConfirm}
|
||||
>
|
||||
<CheckIcon size={24} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
|
||||
<Divider h='1px' w='100%' bg='var(--mantine-color-dimmed)' my='xs'/>
|
||||
<Divider
|
||||
h="1px"
|
||||
w="100%"
|
||||
bg="var(--mantine-color-dimmed)"
|
||||
my="xs"
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<panelConfig.Component
|
||||
@@ -162,4 +181,4 @@ const SlidePanel = ({
|
||||
);
|
||||
};
|
||||
|
||||
export { SlidePanel };
|
||||
export { SlidePanel };
|
||||
|
||||
Reference in New Issue
Block a user