diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts index 13644db3a403696352168de1b8cc81d216b26b53..ba057a54d120513be3521af918d643771e9d2970 100644 --- a/ivette/src/frama-c/states.ts +++ b/ivette/src/frama-c/states.ts @@ -37,6 +37,7 @@ import { GlobalState, useGlobalState } from 'dome/data/states'; import { Client, useModel } from 'dome/table/models'; import { CompactModel } from 'dome/table/arrays'; import * as Ast from 'frama-c/kernel/api/ast'; +import { FieldState, FieldError } from 'dome/layout/forms'; import * as Server from './server'; // -------------------------------------------------------------------------- @@ -307,6 +308,34 @@ export function useSyncValue<A>(value: Value<A>): A | undefined { return v; } +/** Synchronize FieldState and server state only if there is no error. */ +export function useServerField<A>( + state: State<A>, + defaultValue: A, +): FieldState<A> { + const [value, setState] = useSyncState(state); + const [localValue, setLocalValue] = React.useState(value); + const [localError, setLocalError] = React.useState<FieldError>(undefined); + + React.useEffect(() => { + !localError && setLocalValue(value); + }, [value, localError]); + + const update = React.useCallback((newValue: A, newError: FieldError) => { + setLocalValue(newValue); + setLocalError(newError); + if (!newError) { + setState(newValue); + } + }, [setState]); + + return { + value: localValue ?? defaultValue, + error: localError, + onChanged: update + }; +} + // -------------------------------------------------------------------------- // --- Synchronized Arrays // --------------------------------------------------------------------------