mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
193 lines
4.3 KiB
TypeScript
193 lines
4.3 KiB
TypeScript
import { makeStyles } from "@material-ui/core/styles"
|
|
import {
|
|
FormFooterProps as BaseFormFooterProps,
|
|
FormFooter as BaseFormFooter,
|
|
} from "components/FormFooter/FormFooter"
|
|
import { Stack } from "components/Stack/Stack"
|
|
import {
|
|
createContext,
|
|
FC,
|
|
HTMLProps,
|
|
PropsWithChildren,
|
|
useContext,
|
|
} from "react"
|
|
import { combineClasses } from "util/combineClasses"
|
|
|
|
type FormContextValue = { direction?: "horizontal" | "vertical" }
|
|
|
|
const FormContext = createContext<FormContextValue>({
|
|
direction: "horizontal",
|
|
})
|
|
|
|
type FormProps = HTMLProps<HTMLFormElement> & {
|
|
direction?: FormContextValue["direction"]
|
|
}
|
|
|
|
export const Form: FC<FormProps> = ({ direction, className, ...formProps }) => {
|
|
const styles = useStyles()
|
|
|
|
return (
|
|
<FormContext.Provider value={{ direction }}>
|
|
<form
|
|
{...formProps}
|
|
className={combineClasses([styles.form, className])}
|
|
/>
|
|
</FormContext.Provider>
|
|
)
|
|
}
|
|
|
|
export const HorizontalForm: FC<HTMLProps<HTMLFormElement>> = ({
|
|
children,
|
|
...formProps
|
|
}) => {
|
|
return (
|
|
<Form direction="horizontal" {...formProps}>
|
|
{children}
|
|
</Form>
|
|
)
|
|
}
|
|
|
|
export const VerticalForm: FC<HTMLProps<HTMLFormElement>> = ({
|
|
children,
|
|
...formProps
|
|
}) => {
|
|
return (
|
|
<Form direction="vertical" {...formProps}>
|
|
{children}
|
|
</Form>
|
|
)
|
|
}
|
|
|
|
export const FormSection: FC<
|
|
PropsWithChildren & {
|
|
title: string | JSX.Element
|
|
description: string | JSX.Element
|
|
classes?: {
|
|
root?: string
|
|
infoTitle?: string
|
|
}
|
|
}
|
|
> = ({ children, title, description, classes = {} }) => {
|
|
const formContext = useContext(FormContext)
|
|
const styles = useStyles(formContext)
|
|
|
|
return (
|
|
<div className={combineClasses([styles.formSection, classes.root])}>
|
|
<div className={styles.formSectionInfo}>
|
|
<h2
|
|
className={combineClasses([
|
|
styles.formSectionInfoTitle,
|
|
classes.infoTitle,
|
|
])}
|
|
>
|
|
{title}
|
|
</h2>
|
|
<div className={styles.formSectionInfoDescription}>{description}</div>
|
|
</div>
|
|
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const FormFields: FC<PropsWithChildren> = ({ children }) => {
|
|
const styles = useStyles()
|
|
return (
|
|
<Stack direction="column" className={styles.formSectionFields}>
|
|
{children}
|
|
</Stack>
|
|
)
|
|
}
|
|
|
|
export const FormFooter: FC<BaseFormFooterProps> = (props) => {
|
|
const formFooterStyles = useFormFooterStyles()
|
|
return (
|
|
<BaseFormFooter
|
|
{...props}
|
|
styles={{ ...formFooterStyles, ...props.styles }}
|
|
/>
|
|
)
|
|
}
|
|
|
|
const useStyles = makeStyles((theme) => ({
|
|
form: {
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
gap: ({ direction }: FormContextValue = {}) =>
|
|
direction === "horizontal" ? theme.spacing(10) : theme.spacing(5),
|
|
|
|
[theme.breakpoints.down("sm")]: {
|
|
gap: theme.spacing(8),
|
|
},
|
|
},
|
|
|
|
formSection: {
|
|
display: "flex",
|
|
alignItems: "flex-start",
|
|
gap: ({ direction }: FormContextValue = {}) =>
|
|
direction === "horizontal" ? theme.spacing(15) : theme.spacing(3),
|
|
flexDirection: ({ direction }: FormContextValue = {}) =>
|
|
direction === "horizontal" ? "row" : "column",
|
|
|
|
[theme.breakpoints.down("sm")]: {
|
|
flexDirection: "column",
|
|
gap: theme.spacing(2),
|
|
},
|
|
},
|
|
|
|
formSectionInfo: {
|
|
maxWidth: ({ direction }: FormContextValue = {}) =>
|
|
direction === "horizontal" ? 312 : undefined,
|
|
flexShrink: 0,
|
|
position: ({ direction }: FormContextValue = {}) =>
|
|
direction === "horizontal" ? "sticky" : undefined,
|
|
top: theme.spacing(3),
|
|
|
|
[theme.breakpoints.down("sm")]: {
|
|
width: "100%",
|
|
position: "initial",
|
|
},
|
|
},
|
|
|
|
formSectionInfoTitle: {
|
|
fontSize: 20,
|
|
color: theme.palette.text.primary,
|
|
fontWeight: 400,
|
|
margin: 0,
|
|
marginBottom: theme.spacing(1),
|
|
},
|
|
|
|
formSectionInfoDescription: {
|
|
fontSize: 14,
|
|
color: theme.palette.text.secondary,
|
|
lineHeight: "160%",
|
|
margin: 0,
|
|
},
|
|
|
|
formSectionFields: {
|
|
width: "100%",
|
|
},
|
|
}))
|
|
|
|
const useFormFooterStyles = makeStyles((theme) => ({
|
|
button: {
|
|
minWidth: theme.spacing(23),
|
|
|
|
[theme.breakpoints.down("sm")]: {
|
|
width: "100%",
|
|
},
|
|
},
|
|
footer: {
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "flex-start",
|
|
flexDirection: "row-reverse",
|
|
gap: theme.spacing(2),
|
|
|
|
[theme.breakpoints.down("sm")]: {
|
|
flexDirection: "column",
|
|
gap: theme.spacing(1),
|
|
},
|
|
},
|
|
}))
|