Compare commits
	
		
			2 commits
		
	
	
		
			9b52470f6b
			...
			79467e29f2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 79467e29f2 | |||
| 0dc5c28060 | 
					 3 changed files with 67 additions and 7 deletions
				
			
		|  | @ -10,6 +10,7 @@ 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, | ||||||
|  | @ -17,7 +18,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<number>(); |     const [id, setId] = useState<bigint>(); | ||||||
|     const [algorithm, setAlgorithm] = useState('wilson'); |     const [algorithm, setAlgorithm] = useState('wilson'); | ||||||
| 
 | 
 | ||||||
|     const handleSubmit = (e: FormEvent) => { |     const handleSubmit = (e: FormEvent) => { | ||||||
|  | @ -54,15 +55,14 @@ export default function InputForm({state, dispatch}: { | ||||||
|             value: numberValue |             value: numberValue | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|     const validateIdInput: ValidatorFunction<string, number> = value => { |     const validateIdInput: ValidatorFunction<string, bigint> = value => { | ||||||
|         if ("" === value) { |         if ("" === value) { | ||||||
|             return { |             return { | ||||||
|                 valid: true |                 valid: true | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|         const numberValue = Number(value); |         const numberValue = BigInt(value); | ||||||
|         // FIXME doesn't handle strings with characters correctly (e.g. "asdf" yields an empty value, due to "type=number").
 |         if (numberValue.toString() !== value.trim()) { | ||||||
|         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} | ||||||
|                 /> |                 /> | ||||||
|                 <ValidatingInputNumberField id={"id"} |                 <ValidatingInputBigIntField id={"id"} | ||||||
|                                             label={"ID (optional)"} |                                             label={"ID (optional)"} | ||||||
|                                             value={id} |                                             value={id} | ||||||
|                                             validatorFn={validateIdInput} |                                             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": { |   "compilerOptions": { | ||||||
|     "target": "ES2017", |     "target": "ES2020", | ||||||
|     "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