Merge pull request '#11: Fix ID input.' (#12) from feature/11-fix-id-input into main
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Reviewed-on: #12
This commit is contained in:
commit
79467e29f2
3 changed files with 67 additions and 7 deletions
|
@ -10,6 +10,7 @@ import {
|
|||
import styles from "./input-form.module.css";
|
||||
import "./input-form.css";
|
||||
import {State} from "@/app/state/state.ts";
|
||||
import ValidatingInputBigIntField from "@/app/validating-input-bigint-field.tsx";
|
||||
|
||||
export default function InputForm({state, dispatch}: {
|
||||
state: State,
|
||||
|
@ -17,7 +18,7 @@ export default function InputForm({state, dispatch}: {
|
|||
}) {
|
||||
const [width, setWidth] = useState(10);
|
||||
const [height, setHeight] = useState(10);
|
||||
const [id, setId] = useState<number>();
|
||||
const [id, setId] = useState<bigint>();
|
||||
const [algorithm, setAlgorithm] = useState('wilson');
|
||||
|
||||
const handleSubmit = (e: FormEvent) => {
|
||||
|
@ -54,15 +55,14 @@ export default function InputForm({state, dispatch}: {
|
|||
value: numberValue
|
||||
};
|
||||
};
|
||||
const validateIdInput: ValidatorFunction<string, number> = value => {
|
||||
const validateIdInput: ValidatorFunction<string, bigint> = value => {
|
||||
if ("" === value) {
|
||||
return {
|
||||
valid: true
|
||||
};
|
||||
}
|
||||
const numberValue = Number(value);
|
||||
// FIXME doesn't handle strings with characters correctly (e.g. "asdf" yields an empty value, due to "type=number").
|
||||
if (isNaN(numberValue) || Math.floor(numberValue) !== numberValue) {
|
||||
const numberValue = BigInt(value);
|
||||
if (numberValue.toString() !== value.trim()) {
|
||||
return {
|
||||
valid: false,
|
||||
message: "Must be empty or an integer"
|
||||
|
@ -96,7 +96,7 @@ export default function InputForm({state, dispatch}: {
|
|||
disabled={state.loading}
|
||||
onChange={setHeight}
|
||||
/>
|
||||
<ValidatingInputNumberField id={"id"}
|
||||
<ValidatingInputBigIntField id={"id"}
|
||||
label={"ID (optional)"}
|
||||
value={id}
|
||||
validatorFn={validateIdInput}
|
||||
|
|
60
src/app/validating-input-bigint-field.tsx
Normal file
60
src/app/validating-input-bigint-field.tsx
Normal file
|
@ -0,0 +1,60 @@
|
|||
import React, {ChangeEventHandler, useState} from 'react';
|
||||
|
||||
export default function ValidatingInputBigIntField({
|
||||
id,
|
||||
label,
|
||||
value = 0n,
|
||||
constraints = undefined,
|
||||
validatorFn = (value) => {
|
||||
return {valid: true, value: BigInt(value)};
|
||||
},
|
||||
disabled = false,
|
||||
onChange = () => {
|
||||
}
|
||||
}:
|
||||
{
|
||||
id: string;
|
||||
label: string;
|
||||
value?: bigint;
|
||||
constraints?: { min?: bigint; max?: bigint; };
|
||||
validatorFn: ValidatorFunction<string, bigint>;
|
||||
disabled: boolean;
|
||||
onChange: (v: bigint) => void;
|
||||
}) {
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
const handleValueChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
const value = e.target.value;
|
||||
const validation = validatorFn(value);
|
||||
if (!validation.valid) {
|
||||
setError(validation.message);
|
||||
} else {
|
||||
setError(undefined);
|
||||
}
|
||||
if (validation.value !== undefined) {
|
||||
onChange(validation.value);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={id}>{label}: </label>
|
||||
<input id={id}
|
||||
type={"number"}
|
||||
onChange={handleValueChange}
|
||||
value={value?.toString() || ""}
|
||||
min={constraints?.min?.toString()}
|
||||
max={constraints?.max?.toString()}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<span>{error}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export interface Validation<T> {
|
||||
valid: boolean;
|
||||
message?: string;
|
||||
value?: T;
|
||||
}
|
||||
|
||||
export type ValidatorFunction<I, T> = (v: I) => Validation<T>;
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"target": "ES2020",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
|
|
Loading…
Reference in a new issue