177 lines
5.1 KiB
TypeScript
177 lines
5.1 KiB
TypeScript
import type { ReactNode } from 'react'
|
|
|
|
import {
|
|
Box,
|
|
Center,
|
|
Flex,
|
|
type FlexProps,
|
|
Paper,
|
|
Stack,
|
|
Title,
|
|
type TitleProps,
|
|
Tooltip,
|
|
useMantineColorScheme,
|
|
} from '@mantine/core'
|
|
import React from 'react'
|
|
|
|
import classes from './InlineWapper.module.css'
|
|
|
|
interface InlineWrapperCallbackProps extends Partial<InlineWrapperPropsOnly> {
|
|
classNames: React.CSSProperties
|
|
dataCssProps?: Record<string, any>
|
|
size: string
|
|
}
|
|
|
|
interface InlineWrapperProps extends InlineWrapperPropsOnly{
|
|
children?: ((props: InlineWrapperCallbackProps) => ReactNode) | ReactNode
|
|
}
|
|
interface InlineWrapperPropsOnly {
|
|
error?: ReactNode | string
|
|
flexProps?: FlexProps
|
|
label: ReactNode | string
|
|
labelProps?: TitleProps
|
|
promptArea?: ((props: InlineWrapperCallbackProps) => ReactNode) | ReactNode
|
|
promptWidth?: FlexProps['w']
|
|
required?: boolean
|
|
rightSection?: ((props: InlineWrapperCallbackProps) => ReactNode) | ReactNode
|
|
styles?: React.CSSProperties
|
|
tooltip?: string
|
|
value?: any
|
|
}
|
|
|
|
function InlineWrapper(props: InlineWrapperProps) {
|
|
return (
|
|
<Stack gap={0}>
|
|
<Flex
|
|
gap={0}
|
|
h={undefined}
|
|
m={0}
|
|
mb={0}
|
|
p={0}
|
|
w={undefined}
|
|
wrap='nowrap'
|
|
{...props.flexProps}
|
|
bg={'var(--input-background)'}
|
|
>
|
|
{props.promptWidth && props.promptWidth !== 0 ? <Prompt {...props} /> : null}
|
|
<div
|
|
style={{
|
|
borderRadius: 0,
|
|
flex: 10,
|
|
}}
|
|
>
|
|
{typeof props.children === 'function' ? (
|
|
props.children({ ...props, classNames: classes, size: 'xs' })
|
|
) : typeof props.children === 'object' && React.isValidElement(props.children) ? (
|
|
<props.children.type classNames={classes} size='xs' {...(typeof props.children.props === "object" ? props.children.props : {})} />
|
|
) : (
|
|
props.children
|
|
)}
|
|
</div>
|
|
|
|
{!props.rightSection ? undefined : typeof props.rightSection === 'function' ? (
|
|
props.rightSection({
|
|
...props,
|
|
classNames: classes,
|
|
size: 'xs',
|
|
})
|
|
) : typeof props.rightSection === 'object' && React.isValidElement(props.rightSection) ? (
|
|
<props.rightSection.type classNames={classes} size='xs' {...(typeof props.rightSection.props === "object" ? props.rightSection.props : {})} />
|
|
) : (
|
|
props.rightSection
|
|
)}
|
|
</Flex>
|
|
{/* <ErrorComponent {...props} /> */}
|
|
</Stack>
|
|
)
|
|
}
|
|
|
|
function isValueEmpty(inputValue: any) {
|
|
if (inputValue === null || inputValue === undefined) return true
|
|
if (typeof inputValue === 'number') {
|
|
if (inputValue === 0) return false
|
|
} else if (typeof inputValue === 'string' || inputValue === '') {
|
|
return inputValue.trim() === ''
|
|
} else if (inputValue instanceof File) {
|
|
return inputValue.size === 0
|
|
} else if (inputValue.target) {
|
|
return isValueEmpty(inputValue.target?.value)
|
|
} else if (inputValue.constructor?.name === 'Date') {
|
|
return false
|
|
}
|
|
}
|
|
|
|
function Prompt(props: Partial<InlineWrapperProps>) {
|
|
return (
|
|
<>
|
|
{props.tooltip ? (
|
|
<Tooltip label={props.tooltip}>
|
|
<PromptDetail {...props} />
|
|
</Tooltip>
|
|
) : (
|
|
<PromptDetail {...props} />
|
|
)}
|
|
</>
|
|
)
|
|
}
|
|
|
|
function PromptDetail(props: Partial<InlineWrapperProps>) {
|
|
const colors = useColors(props)
|
|
return props.promptArea ? (
|
|
<Box maw={props.promptWidth} w={'100%'}>
|
|
{!props.promptArea ? undefined : typeof props.promptArea === 'function' ? (
|
|
props.promptArea({
|
|
...props,
|
|
classNames: classes,
|
|
dataCssProps: { 'data-promptArea': true },
|
|
size: 'xs',
|
|
})
|
|
) : typeof props.rightSection === 'object' && React.isValidElement(props.promptArea) ? (
|
|
<props.promptArea.type
|
|
classNames={classes}
|
|
data-promptArea='true'
|
|
size='xs'
|
|
{...(typeof props.promptArea?.props === "object" ? props.promptArea.props : {})}
|
|
/>
|
|
) : (
|
|
props.promptArea
|
|
)}
|
|
</Box>
|
|
) : (
|
|
<Paper
|
|
bg={colors.paperColor}
|
|
className={classes.prompt}
|
|
px='md'
|
|
w={props.promptWidth}
|
|
withBorder
|
|
>
|
|
<Center h='100%' style={{ justifyContent: 'start' }} w='100%'>
|
|
<Title c={colors.titleColor} fz='xs' order={6} {...props.labelProps}>
|
|
{props.label}
|
|
{props.required && isValueEmpty(props.value) && <span style={{ color: 'red' }}>*</span>}
|
|
</Title>
|
|
</Center>
|
|
</Paper>
|
|
)
|
|
}
|
|
|
|
function useColors(props: Partial<InlineWrapperProps>) {
|
|
const { colorScheme } = useMantineColorScheme()
|
|
|
|
let titleColor = colorScheme === 'dark' ? 'dark.0' : 'gray.8'
|
|
let paperColor = colorScheme === 'dark' ? 'dark.7' : 'gray.1'
|
|
|
|
if (props.required && isValueEmpty(props.value)) {
|
|
paperColor = colorScheme === 'dark' ? '#413012e7' : 'yellow.1'
|
|
}
|
|
|
|
if (props.error) {
|
|
paperColor = colorScheme === 'dark' ? 'red.7' : 'red.0'
|
|
titleColor = colorScheme === 'dark' ? 'red.0' : 'red.9'
|
|
}
|
|
return { paperColor, titleColor }
|
|
}
|
|
|
|
export { InlineWrapper }
|
|
export type { InlineWrapperProps }
|