339 lines
13 KiB
TypeScript
339 lines
13 KiB
TypeScript
import { Box, DefaultMantineColor, Flex, Input, MantineSpacing, Paper, Select, StyleProp, Switch, Text } from "@mantine/core"
|
|
import classes from './SettingsInput.module.css'
|
|
import { Children, cloneElement, HTMLInputTypeAttribute, isValidElement, MouseEvent, ReactNode, useEffect, useRef, useState } from "react";
|
|
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
|
|
import { useClipboard } from "@mantine/hooks";
|
|
import { IconChevronRight } from "@tabler/icons-react";
|
|
|
|
|
|
export function SettingsInput() {}
|
|
export interface SettingsInputCopy {
|
|
hit: string;
|
|
placeholder?: string;
|
|
value?: string;
|
|
style?: any;
|
|
mt?: StyleProp<MantineSpacing>;
|
|
}
|
|
export interface SettingsInputDefaultProps {
|
|
hit: string;
|
|
placeholder?: string;
|
|
value?: string;
|
|
disabled?: boolean;
|
|
onChange?: (event : any) => void;
|
|
style?: any;
|
|
mt?: StyleProp<MantineSpacing>;
|
|
rightSection?: ReactNode;
|
|
type?: HTMLInputTypeAttribute;
|
|
}
|
|
export interface SettingsInputGroupProps {
|
|
mt?: StyleProp<MantineSpacing>;
|
|
children: any;
|
|
}
|
|
export interface SettingsInputClickableProps {
|
|
onClick: () => void;
|
|
hit: string;
|
|
placeholder?: string;
|
|
style?: any;
|
|
mt?: StyleProp<MantineSpacing>;
|
|
value?: string;
|
|
rightSection?: ReactNode;
|
|
c?: StyleProp<DefaultMantineColor>;
|
|
rightChevronHide?: boolean;
|
|
settingsIcon?: React.ReactNode;
|
|
}
|
|
export interface SettingsInputSelectProps {
|
|
hit: string;
|
|
variants: string[];
|
|
mt?: StyleProp<MantineSpacing>;
|
|
style?: any;
|
|
leftSection?: ReactNode;
|
|
onChange?: (value: string|undefined) => void;
|
|
width?: number;
|
|
defaultValue?: string;
|
|
}
|
|
|
|
export interface SettingsInputSwitch {
|
|
hit: string;
|
|
mt?: StyleProp<MantineSpacing>;
|
|
style?: any;
|
|
onChange?: (value: boolean) => void;
|
|
defaultValue: boolean;
|
|
}
|
|
|
|
SettingsInput.Copy = SettingsInputCopy;
|
|
SettingsInput.Clickable = SettingsInputClickable;
|
|
SettingsInput.Default = SettingsInputDefault;
|
|
SettingsInput.Group = SettingsInputGroup;
|
|
SettingsInput.Select = SettingsInputSelect;
|
|
SettingsInput.Switch = SettingsInputSwitch;
|
|
|
|
function SettingsInputSwitch(props: SettingsInputSwitch) {
|
|
const colors = useRosettaColors();
|
|
const [checked, setChecked] = useState(props.defaultValue);
|
|
|
|
useEffect(() => {
|
|
setChecked(props.defaultValue);
|
|
}, [props.defaultValue]);
|
|
|
|
const onSwitch = (checked: boolean) => {
|
|
if(props.onChange){
|
|
props.onChange(checked);
|
|
}
|
|
setChecked(checked);
|
|
}
|
|
|
|
return (
|
|
<Paper mt={props.mt} style={props.style} withBorder styles={{
|
|
root: {
|
|
borderTop: '1px solid ' + colors.borderColor,
|
|
borderBottom: '1px solid ' + colors.borderColor,
|
|
borderLeft: '1px solid ' + colors.borderColor,
|
|
borderRight: '1px solid ' + colors.borderColor,
|
|
cursor: 'pointer'
|
|
}
|
|
}}
|
|
>
|
|
<Flex direction={'row'} pr={'sm'} pl={'sm'} align={'center'} justify={'space-between'}>
|
|
<Text size={'sm'} fw={400}>{props.hit}</Text>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'flex-end',
|
|
height: 36,
|
|
cursor: 'pointer'
|
|
}}>
|
|
<Switch
|
|
checked={checked}
|
|
onChange={(event) => onSwitch(event.currentTarget.checked)}
|
|
size="sm"
|
|
/>
|
|
</div>
|
|
</Flex>
|
|
</Paper>
|
|
);
|
|
}
|
|
|
|
function SettingsInputSelect(props: SettingsInputSelectProps) {
|
|
const colors = useRosettaColors();
|
|
const [value, setValue] = useState(props.defaultValue);
|
|
|
|
const onChange = (selectValue : any) => {
|
|
if(selectValue != value && selectValue != null){
|
|
props.onChange!(selectValue);
|
|
setValue(selectValue);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Paper mt={props.mt} style={props.style} withBorder styles={{
|
|
root: {
|
|
borderTop: '1px solid ' + colors.borderColor,
|
|
borderBottom: '1px solid ' + colors.borderColor,
|
|
borderLeft: '1px solid ' + colors.borderColor,
|
|
borderRight: '1px solid ' + colors.borderColor,
|
|
cursor: 'pointer'
|
|
}
|
|
}}
|
|
>
|
|
<Flex direction={'row'} pr={'sm'} pl={'sm'} align={'center'} justify={'space-between'}>
|
|
<Text size={'sm'} fw={400}>{props.hit}</Text>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'flex-end',
|
|
height: 36,
|
|
cursor: 'pointer'
|
|
}}>
|
|
<Select allowDeselect={false} onChange={(v) => onChange(v)} style={{
|
|
width: props.width
|
|
}} leftSection={props.leftSection} color="gray" p={0} classNames={{
|
|
input: classes.input
|
|
}} variant={'unstyled'} comboboxProps={{
|
|
middlewares: { flip: true, shift: true }, offset: 0, transitionProps: { transition: 'pop', duration: 50 } }} data={props.variants} value={props.defaultValue}>
|
|
</Select>
|
|
</div>
|
|
</Flex>
|
|
</Paper>
|
|
);
|
|
}
|
|
|
|
function SettingsInputCopy(props : SettingsInputCopy) {
|
|
const colors = useRosettaColors();
|
|
const {copied, copy} = useClipboard({
|
|
timeout: 1500
|
|
});
|
|
const onClick = (e : MouseEvent) => {
|
|
e.stopPropagation();
|
|
copy(props.value);
|
|
}
|
|
return (
|
|
<Paper mt={props.mt} style={props.style} withBorder styles={{
|
|
root: {
|
|
borderTop: '1px solid ' + colors.borderColor,
|
|
borderBottom: '1px solid ' + colors.borderColor,
|
|
borderLeft: '1px solid ' + colors.borderColor,
|
|
borderRight: '1px solid ' + colors.borderColor,
|
|
cursor: 'pointer'
|
|
}
|
|
}}
|
|
|
|
onClick={onClick}
|
|
>
|
|
<Flex direction={'row'} pr={'sm'} pl={'sm'} align={'center'} justify={'space-between'}>
|
|
<Text size={'sm'} fw={400}>{props.hit}</Text>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'flex-end',
|
|
height: 36,
|
|
cursor: 'pointer'
|
|
}} onClick={onClick}>
|
|
{!copied && (
|
|
<Input defaultValue={ props.value } readOnly onClick={onClick} variant={'unstyled'} spellCheck={false} color="gray" classNames={{
|
|
input: classes.input
|
|
}} placeholder={props.placeholder}></Input>)}
|
|
{copied && (
|
|
<Input defaultValue={'copied'} readOnly spellCheck={false} styles={{
|
|
input: {
|
|
color: 'var(--mantine-color-green-6)',
|
|
textAlign: 'right',
|
|
cursor: 'pointer'
|
|
}
|
|
}} variant={'unstyled'}></Input>
|
|
)}
|
|
</div>
|
|
</Flex>
|
|
</Paper>
|
|
);
|
|
}
|
|
|
|
function SettingsInputClickable(
|
|
props : SettingsInputClickableProps
|
|
) {
|
|
const colors = useRosettaColors();
|
|
const onClick = (e : MouseEvent) => {
|
|
e.stopPropagation();
|
|
props.onClick();
|
|
}
|
|
return (
|
|
<Paper mt={props.mt} style={props.style} withBorder styles={{
|
|
root: {
|
|
borderTop: '1px solid ' + colors.borderColor,
|
|
borderBottom: '1px solid ' + colors.borderColor,
|
|
borderLeft: '1px solid ' + colors.borderColor,
|
|
borderRight: '1px solid ' + colors.borderColor,
|
|
cursor: 'pointer'
|
|
}
|
|
}}
|
|
|
|
onClick={onClick}
|
|
>
|
|
<Flex direction={'row'} pr={'sm'} pl={'sm'} align={'center'} justify={'space-between'}>
|
|
<Flex gap={'sm'} align={'center'}>
|
|
{props.settingsIcon}
|
|
<Text size={'sm'} c={props.c} fw={400}>{props.hit}</Text>
|
|
</Flex>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'flex-end',
|
|
height: 36,
|
|
cursor: 'pointer'
|
|
}} onClick={onClick}>
|
|
{props.rightSection && (
|
|
<Input defaultValue={props.value} readOnly onClick={onClick} rightSection={props.rightSection} classNames={{
|
|
input: classes.input
|
|
}} spellCheck={false} variant={'unstyled'}></Input>
|
|
)}
|
|
{!props.rightSection && (
|
|
<Input readOnly defaultValue={props.value} onClick={onClick} variant={'unstyled'} spellCheck={false} color="gray" classNames={{
|
|
input: classes.input
|
|
}} placeholder={props.placeholder}></Input>)
|
|
}
|
|
{!props.rightChevronHide && (<IconChevronRight size={20} onClick={onClick} color={colors.chevrons.active}></IconChevronRight>)}
|
|
</div>
|
|
</Flex>
|
|
</Paper>
|
|
);
|
|
}
|
|
|
|
function SettingsInputDefault(props : SettingsInputDefaultProps) {
|
|
const colors = useRosettaColors();
|
|
const input = useRef<any>(undefined);
|
|
|
|
const onClick = (e : MouseEvent) => {
|
|
e.stopPropagation();
|
|
if(!props.disabled){
|
|
input.current.focus();
|
|
return;
|
|
}
|
|
}
|
|
return (<>
|
|
<Paper mt={props.mt} style={props.style} withBorder styles={{
|
|
root: {
|
|
borderTop: '1px solid ' + colors.borderColor,
|
|
borderBottom: '1px solid ' + colors.borderColor,
|
|
borderLeft: '1px solid ' + colors.borderColor,
|
|
borderRight: '1px solid ' + colors.borderColor,
|
|
cursor: 'pointer'
|
|
}
|
|
}}
|
|
|
|
onClick={onClick}
|
|
>
|
|
<Flex direction={'row'} pr={'sm'} pl={'sm'} align={'center'} justify={'space-between'}>
|
|
<Text size={'sm'} fw={400}>{props.hit}</Text>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'flex-end',
|
|
height: 36,
|
|
cursor: 'pointer'
|
|
}} onClick={onClick}>
|
|
{props.rightSection && (
|
|
<Input type={props.type} defaultValue={props.value} readOnly onClick={onClick} rightSection={props.rightSection} classNames={{
|
|
input: classes.input
|
|
}} spellCheck={false} variant={'unstyled'}></Input>
|
|
)}
|
|
{!props.rightSection && (
|
|
<Input type={props.type} defaultValue={!props.onChange ? props.value : undefined} value={!props.onChange ? undefined : props.value} ref={input} disabled={props.disabled} onClick={(e) => {
|
|
onClick(e)
|
|
}} onChange={props.onChange} variant={'unstyled'} spellCheck={false} color="gray" classNames={{
|
|
input: classes.input
|
|
}} placeholder={props.placeholder}></Input>)
|
|
}
|
|
</div>
|
|
</Flex>
|
|
</Paper>
|
|
</>)
|
|
}
|
|
|
|
|
|
function SettingsInputGroup(props : SettingsInputGroupProps) {
|
|
const colors = useRosettaColors();
|
|
|
|
const childrenArray = Children.toArray(props.children).filter(
|
|
(child): child is React.ReactElement<{ style?: React.CSSProperties }> =>
|
|
isValidElement(child)
|
|
);
|
|
return (
|
|
<Box mt={props.mt}>
|
|
{childrenArray.map((child, index) => {
|
|
const isFirst = index === 0;
|
|
const isLast = index === childrenArray.length - 1;
|
|
return cloneElement(child, {
|
|
style: {
|
|
borderRadius: isFirst
|
|
? "var(--mantine-radius-default) var(--mantine-radius-default) 0 0"
|
|
: isLast
|
|
? "0 0 var(--mantine-radius-default) var(--mantine-radius-default)"
|
|
: "0",
|
|
borderTop: isLast ? 'unset' : '1px solid ' + colors.borderColor,
|
|
borderBottom: isFirst ? '1px solid ' + colors.borderColor : '1px solid ' + colors.borderColor,
|
|
...(child.props.style || {}),
|
|
},
|
|
});
|
|
})}
|
|
</Box>
|
|
);
|
|
} |