diff options
author | crupest <crupest@outlook.com> | 2023-07-30 23:47:53 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2023-07-30 23:47:53 +0800 |
commit | 538d6830a0022b49b99695095d85e567b0c86e71 (patch) | |
tree | a0c4d164b05d03f636d603b28f77ca881c16ef10 /FrontEnd/src/views/common | |
parent | a148f11c193d35ba489f887ed393aedf58a1c714 (diff) | |
download | timeline-538d6830a0022b49b99695095d85e567b0c86e71.tar.gz timeline-538d6830a0022b49b99695095d85e567b0c86e71.tar.bz2 timeline-538d6830a0022b49b99695095d85e567b0c86e71.zip |
...
Diffstat (limited to 'FrontEnd/src/views/common')
-rw-r--r-- | FrontEnd/src/views/common/dialog/OperationDialog.tsx | 6 | ||||
-rw-r--r-- | FrontEnd/src/views/common/input/InputGroup.tsx | 47 |
2 files changed, 36 insertions, 17 deletions
diff --git a/FrontEnd/src/views/common/dialog/OperationDialog.tsx b/FrontEnd/src/views/common/dialog/OperationDialog.tsx index da1ff0e0..de92e541 100644 --- a/FrontEnd/src/views/common/dialog/OperationDialog.tsx +++ b/FrontEnd/src/views/common/dialog/OperationDialog.tsx @@ -43,7 +43,7 @@ export interface OperationDialogProps<TData> { color?: ThemeColor; inputColor?: ThemeColor; title: Text; - inputPrompt?: Text; + inputPrompt?: () => ReactNode; successPrompt?: (data: TData) => ReactNode; failurePrompt?: (error: unknown) => ReactNode; @@ -68,8 +68,6 @@ function OperationDialog<TData>(props: OperationDialogProps<TData>) { onSuccessAndClose, } = props; - const c = useC(); - type Step = | { type: "input" } | { type: "process" } @@ -130,7 +128,7 @@ function OperationDialog<TData>(props: OperationDialogProps<TData>) { body = ( <div> - <OperationDialogPrompt customMessage={c(inputPrompt)} /> + <OperationDialogPrompt customMessage={inputPrompt?.()} /> <InputGroup containerClassName="cru-operation-dialog-input-group" color={inputColor ?? "primary"} diff --git a/FrontEnd/src/views/common/input/InputGroup.tsx b/FrontEnd/src/views/common/input/InputGroup.tsx index ee89b05c..5714411c 100644 --- a/FrontEnd/src/views/common/input/InputGroup.tsx +++ b/FrontEnd/src/views/common/input/InputGroup.tsx @@ -70,6 +70,13 @@ export type InputErrorDict = Record<string, Text>; export type InputDisabledDict = Record<string, boolean>; export type InputDirtyDict = Record<string, boolean>; +export type GeneralInputErrorDict = + | { + [key: string]: Text | null | undefined; + } + | null + | undefined; + type MakeInputInfo<I extends Input> = Omit<I, "value" | "error" | "disabled">; export type InputInfo = { @@ -79,7 +86,7 @@ export type InputInfo = { export type Validator = ( values: InputValueDict, inputs: InputInfo[], -) => InputErrorDict; +) => GeneralInputErrorDict; export type InputScheme = { inputs: InputInfo[]; @@ -98,7 +105,12 @@ export type State = { data: InputData; }; -export type DataInitialization = Partial<InputData>; +export type DataInitialization = { + values?: InputValueDict; + errors?: GeneralInputErrorDict; + disabled?: InputDisabledDict; + dirties?: InputDirtyDict; +}; export type Initialization = { scheme: InputScheme; @@ -118,14 +130,14 @@ export interface InputGroupProps { onChange: (index: number, value: Input["value"]) => void; } -function cleanObject<V>(o: Record<string, V>): Record<string, V> { +function cleanObject<V>(o: Record<string, V>): Record<string, NonNullable<V>> { const result = { ...o }; for (const key of Object.keys(result)) { if (result[key] == null) { delete result[key]; } } - return result; + return result as never; } export type ConfirmResult = @@ -138,6 +150,14 @@ export type ConfirmResult = errors: InputErrorDict; }; +function validate( + validator: Validator | null | undefined, + values: InputValueDict, + inputs: InputInfo[], +): InputErrorDict { + return cleanObject(validator?.(values, inputs) ?? {}); +} + export function useInputs(options: { init: Initializer }): { inputGroupProps: InputGroupProps; hasError: boolean; @@ -182,18 +202,22 @@ export function useInputs(options: { init: Initializer }): { }; checkKeys(dataInit?.values); - checkKeys(dataInit?.errors); + checkKeys(dataInit?.errors ?? {}); checkKeys(dataInit?.disabled); checkKeys(dataInit?.dirties); } - function clean<V>(dict: Record<string, V> | undefined): Record<string, V> { + function clean<V>( + dict: Record<string, V> | null | undefined, + ): Record<string, NonNullable<V>> { return dict != null ? cleanObject(dict) : {}; } const values: InputValueDict = {}; const disabled: InputDisabledDict = clean(dataInit?.disabled); const dirties: InputDirtyDict = clean(dataInit?.dirties); + const isErrorSet = dataInit?.errors != null; + let errors: InputErrorDict = clean(dataInit?.errors); for (let i = 0; i < inputs.length; i++) { const input = inputs[i]; @@ -202,17 +226,14 @@ export function useInputs(options: { init: Initializer }): { values[key] = initializeValue(input, dataInit?.values?.[key]); } - let errors = dataInit?.errors; - - if (errors != null) { + if (isErrorSet) { if (process.env.NODE_ENV === "development") { console.log( "You explicitly set errors (not undefined) in initializer, so validator won't run.", ); } - errors = cleanObject(errors); } else { - errors = validator?.(values, inputs) ?? {}; + errors = validate(validator, values, inputs); } return { @@ -272,7 +293,7 @@ export function useInputs(options: { init: Initializer }): { const { key } = input; const newValues = { ...data.values, [key]: value }; const newDirties = { ...data.dirties, [key]: true }; - const newErrors = validator?.(newValues, scheme.inputs) ?? {}; + const newErrors = validate(validator, newValues, scheme.inputs); setState({ scheme, data: { @@ -288,7 +309,7 @@ export function useInputs(options: { init: Initializer }): { hasErrorAndDirty: hasError && hasDirty, confirm() { const newDirties = createAllDirties(); - const newErrors = validator?.(data.values, scheme.inputs) ?? {}; + const newErrors = validate(validator, data.values, scheme.inputs); setState({ scheme, |