Compare commits
	
		
			No commits in common. "79467e29f23730994c5012c1773d35eed7f022ab" and "9b52470f6b8c5321991396d34ea28edfb4c31960" have entirely different histories.
		
	
	
		
			79467e29f2
			...
			9b52470f6b
		
	
		
					 3 changed files with 7 additions and 67 deletions
				
			
		|  | @ -10,7 +10,6 @@ import { | ||||||
| import styles from "./input-form.module.css"; | import styles from "./input-form.module.css"; | ||||||
| import "./input-form.css"; | import "./input-form.css"; | ||||||
| import {State} from "@/app/state/state.ts"; | import {State} from "@/app/state/state.ts"; | ||||||
| import ValidatingInputBigIntField from "@/app/validating-input-bigint-field.tsx"; |  | ||||||
| 
 | 
 | ||||||
| export default function InputForm({state, dispatch}: { | export default function InputForm({state, dispatch}: { | ||||||
|     state: State, |     state: State, | ||||||
|  | @ -18,7 +17,7 @@ export default function InputForm({state, dispatch}: { | ||||||
| }) { | }) { | ||||||
|     const [width, setWidth] = useState(10); |     const [width, setWidth] = useState(10); | ||||||
|     const [height, setHeight] = useState(10); |     const [height, setHeight] = useState(10); | ||||||
|     const [id, setId] = useState<bigint>(); |     const [id, setId] = useState<number>(); | ||||||
|     const [algorithm, setAlgorithm] = useState('wilson'); |     const [algorithm, setAlgorithm] = useState('wilson'); | ||||||
| 
 | 
 | ||||||
|     const handleSubmit = (e: FormEvent) => { |     const handleSubmit = (e: FormEvent) => { | ||||||
|  | @ -55,14 +54,15 @@ export default function InputForm({state, dispatch}: { | ||||||
|             value: numberValue |             value: numberValue | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     const validateIdInput: ValidatorFunction<string, bigint> = value => { |     const validateIdInput: ValidatorFunction<string, number> = value => { | ||||||
|         if ("" === value) { |         if ("" === value) { | ||||||
|             return { |             return { | ||||||
|                 valid: true |                 valid: true | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|         const numberValue = BigInt(value); |         const numberValue = Number(value); | ||||||
|         if (numberValue.toString() !== value.trim()) { |         // 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) { | ||||||
|             return { |             return { | ||||||
|                 valid: false, |                 valid: false, | ||||||
|                 message: "Must be empty or an integer" |                 message: "Must be empty or an integer" | ||||||
|  | @ -96,7 +96,7 @@ export default function InputForm({state, dispatch}: { | ||||||
|                                             disabled={state.loading} |                                             disabled={state.loading} | ||||||
|                                             onChange={setHeight} |                                             onChange={setHeight} | ||||||
|                 /> |                 /> | ||||||
|                 <ValidatingInputBigIntField id={"id"} |                 <ValidatingInputNumberField id={"id"} | ||||||
|                                             label={"ID (optional)"} |                                             label={"ID (optional)"} | ||||||
|                                             value={id} |                                             value={id} | ||||||
|                                             validatorFn={validateIdInput} |                                             validatorFn={validateIdInput} | ||||||
|  |  | ||||||
|  | @ -1,60 +0,0 @@ | ||||||
| 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": { |   "compilerOptions": { | ||||||
|     "target": "ES2020", |     "target": "ES2017", | ||||||
|     "lib": ["dom", "dom.iterable", "esnext"], |     "lib": ["dom", "dom.iterable", "esnext"], | ||||||
|     "allowJs": true, |     "allowJs": true, | ||||||
|     "allowImportingTsExtensions": true, |     "allowImportingTsExtensions": true, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue