bazarr/frontend/src/pages/Settings/components/forms.tsx

278 lines
6.9 KiB
TypeScript
Raw Normal View History

import {
2022-05-31 15:49:04 +00:00
Action as GlobalAction,
FileBrowser,
FileBrowserProps,
2022-05-31 15:49:04 +00:00
MultiSelector as GlobalMultiSelector,
MultiSelectorProps as GlobalMultiSelectorProps,
Selector as GlobalSelector,
SelectorProps as GlobalSelectorProps,
} from "@/components";
2022-05-31 15:49:04 +00:00
import { ActionProps as GlobalActionProps } from "@/components/inputs/Action";
import ChipInput, { ChipInputProps } from "@/components/inputs/ChipInput";
import { useSliderMarks } from "@/utilities";
2021-03-25 14:22:43 +00:00
import {
2022-05-31 15:49:04 +00:00
InputWrapper,
NumberInput,
NumberInputProps,
PasswordInput,
PasswordInputProps,
Slider as MantineSlider,
SliderProps as MantineSliderProps,
Switch,
TextInput,
TextInputProps,
} from "@mantine/core";
import { FunctionComponent, ReactText, useCallback } from "react";
import { useSettingValue } from ".";
2022-05-31 15:49:04 +00:00
import { FormKey, useFormActions } from "../utilities/FormValues";
import { OverrideFuncType } from "./hooks";
2021-03-25 14:22:43 +00:00
export interface BaseInput<T> {
disabled?: boolean;
settingKey: string;
2022-05-31 15:49:04 +00:00
location?: FormKey;
2021-03-25 14:22:43 +00:00
override?: OverrideFuncType<T>;
beforeStaged?: (v: T) => unknown;
2021-03-25 14:22:43 +00:00
}
2022-05-31 15:49:04 +00:00
export type NumberProps = BaseInput<number> & NumberInputProps;
export const Number: FunctionComponent<NumberProps> = ({
beforeStaged,
override,
settingKey,
location,
...props
}) => {
const value = useSettingValue<number>(settingKey, override);
const { setValue } = useFormActions();
return (
<NumberInput
{...props}
value={value ?? undefined}
onChange={(val = 0) => {
const value = beforeStaged ? beforeStaged(val) : val;
setValue(value, settingKey, location);
}}
></NumberInput>
);
};
export type TextProps = BaseInput<ReactText> & TextInputProps;
2021-03-25 14:22:43 +00:00
export const Text: FunctionComponent<TextProps> = ({
beforeStaged,
override,
settingKey,
2022-05-31 15:49:04 +00:00
location,
...props
2021-03-25 14:22:43 +00:00
}) => {
2022-05-31 15:49:04 +00:00
const value = useSettingValue<ReactText>(settingKey, override);
const { setValue } = useFormActions();
2021-03-25 14:22:43 +00:00
return (
2022-05-31 15:49:04 +00:00
<TextInput
{...props}
value={value ?? undefined}
2021-03-25 14:22:43 +00:00
onChange={(e) => {
const val = e.currentTarget.value;
const value = beforeStaged ? beforeStaged(val) : val;
2022-05-31 15:49:04 +00:00
setValue(value, settingKey, location);
}}
></TextInput>
);
};
export type PasswordProps = BaseInput<string> & PasswordInputProps;
export const Password: FunctionComponent<PasswordProps> = ({
settingKey,
location,
override,
beforeStaged,
...props
}) => {
const value = useSettingValue<ReactText>(settingKey, override);
const { setValue } = useFormActions();
return (
<PasswordInput
{...props}
value={value ?? undefined}
onChange={(e) => {
const val = e.currentTarget.value;
const value = beforeStaged ? beforeStaged(val) : val;
setValue(value, settingKey, location);
2021-03-25 14:22:43 +00:00
}}
2022-05-31 15:49:04 +00:00
></PasswordInput>
2021-03-25 14:22:43 +00:00
);
};
export interface CheckProps extends BaseInput<boolean> {
label?: string;
inline?: boolean;
}
export const Check: FunctionComponent<CheckProps> = ({
label,
override,
disabled,
settingKey,
2022-05-31 15:49:04 +00:00
location,
2021-03-25 14:22:43 +00:00
}) => {
2022-05-31 15:49:04 +00:00
const value = useSettingValue<boolean>(settingKey, override);
const { setValue } = useFormActions();
2021-03-25 14:22:43 +00:00
return (
2022-05-31 15:49:04 +00:00
<Switch
2021-03-25 14:22:43 +00:00
id={settingKey}
label={label}
onChange={(e) => {
const { checked } = e.currentTarget;
2022-05-31 15:49:04 +00:00
setValue(checked, settingKey, location);
2021-03-25 14:22:43 +00:00
}}
disabled={disabled}
2022-05-31 15:49:04 +00:00
checked={value ?? false}
></Switch>
2021-03-25 14:22:43 +00:00
);
};
2022-05-31 15:49:04 +00:00
export type SelectorProps<T extends string | number> = BaseInput<T> &
GlobalSelectorProps<T>;
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
export function Selector<T extends string | number>(props: SelectorProps<T>) {
const { settingKey, location, override, beforeStaged, ...selector } = props;
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
const value = useSettingValue<T>(settingKey, override);
const { setValue } = useFormActions();
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
return (
<GlobalSelector
{...selector}
value={value}
onChange={(v) => {
const result = beforeStaged && v ? beforeStaged(v) : v;
setValue(result, settingKey, location);
}}
></GlobalSelector>
2021-03-25 14:22:43 +00:00
);
2022-05-31 15:49:04 +00:00
}
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
export type MultiSelectorProps<T extends string | number> = BaseInput<T[]> &
GlobalMultiSelectorProps<T>;
export function MultiSelector<T extends string | number>(
props: MultiSelectorProps<T>
) {
const { settingKey, location, override, beforeStaged, ...selector } = props;
const value = useSettingValue<T[]>(settingKey, override);
const { setValue } = useFormActions();
2021-03-25 14:22:43 +00:00
return (
2022-05-31 15:49:04 +00:00
<GlobalMultiSelector
2021-03-25 14:22:43 +00:00
{...selector}
2022-05-31 15:49:04 +00:00
value={value ?? []}
2021-03-25 14:22:43 +00:00
onChange={(v) => {
2022-05-31 15:49:04 +00:00
const result = beforeStaged && v ? beforeStaged(v) : v;
setValue(result, settingKey, location);
2021-03-25 14:22:43 +00:00
}}
2022-05-31 15:49:04 +00:00
></GlobalMultiSelector>
2021-03-25 14:22:43 +00:00
);
}
type SliderProps = BaseInput<number> &
2022-05-31 15:49:04 +00:00
Omit<MantineSliderProps, "onChange" | "onChangeEnd" | "marks">;
2021-03-25 14:22:43 +00:00
export const Slider: FunctionComponent<SliderProps> = (props) => {
2022-05-31 15:49:04 +00:00
const { settingKey, location, override, label, ...slider } = props;
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
const value = useSettingValue<number>(settingKey, override);
const { setValue } = useFormActions();
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
const marks = useSliderMarks([(slider.min = 0), (slider.max = 100)]);
2021-03-25 14:22:43 +00:00
return (
2022-05-31 15:49:04 +00:00
<InputWrapper label={label}>
<MantineSlider
marks={marks}
onChange={(v) => {
setValue(v, settingKey, location);
}}
value={value ?? 0}
{...slider}
></MantineSlider>
</InputWrapper>
2021-03-25 14:22:43 +00:00
);
};
type ChipsProp = BaseInput<string[]> &
2022-05-31 15:49:04 +00:00
Omit<ChipInputProps, "onChange" | "data">;
2021-03-25 14:22:43 +00:00
export const Chips: FunctionComponent<ChipsProp> = (props) => {
2022-05-31 15:49:04 +00:00
const { settingKey, location, override, ...chips } = props;
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
const value = useSettingValue<string[]>(settingKey, override);
const { setValue } = useFormActions();
2021-03-25 14:22:43 +00:00
return (
2022-05-31 15:49:04 +00:00
<ChipInput
value={value ?? []}
2021-03-25 14:22:43 +00:00
onChange={(v) => {
2022-05-31 15:49:04 +00:00
setValue(v, settingKey, location);
2021-03-25 14:22:43 +00:00
}}
{...chips}
2022-05-31 15:49:04 +00:00
></ChipInput>
2021-03-25 14:22:43 +00:00
);
};
2022-05-31 15:49:04 +00:00
type ActionProps = {
onClick?: (update: (v: unknown) => void, value?: string) => void;
2021-03-25 14:22:43 +00:00
} & Omit<BaseInput<string>, "override" | "beforeStaged">;
2022-05-31 15:49:04 +00:00
export const Action: FunctionComponent<
Override<ActionProps, GlobalActionProps>
> = (props) => {
const { onClick, settingKey, location, ...button } = props;
const value = useSettingValue<string>(settingKey);
const { setValue } = useFormActions();
2021-03-25 14:22:43 +00:00
2022-05-31 15:49:04 +00:00
const wrappedSetValue = useCallback(
(v: unknown) => {
setValue(v, settingKey, location);
},
[location, setValue, settingKey]
);
2021-03-25 14:22:43 +00:00
return (
2022-05-31 15:49:04 +00:00
<GlobalAction
2021-03-25 14:22:43 +00:00
onClick={() => {
2022-05-31 15:49:04 +00:00
onClick?.(wrappedSetValue, value ?? undefined);
2021-03-25 14:22:43 +00:00
}}
{...button}
2022-05-31 15:49:04 +00:00
></GlobalAction>
2021-03-25 14:22:43 +00:00
);
};
interface FileProps extends BaseInput<string> {}
export const File: FunctionComponent<Override<FileProps, FileBrowserProps>> = (
props
) => {
2022-05-31 15:49:04 +00:00
const { settingKey, location, override, ...file } = props;
const value = useSettingValue<string>(settingKey);
const { setValue } = useFormActions();
return (
<FileBrowser
defaultValue={value ?? undefined}
onChange={(p) => {
2022-05-31 15:49:04 +00:00
setValue(p, settingKey, location);
}}
{...file}
></FileBrowser>
);
};