diff --git a/apps/console/src/components/table/GraphQLCell.tsx b/apps/console/src/components/table/GraphQLCell.tsx index 2384ec8cc..fc700fbaf 100644 --- a/apps/console/src/components/table/GraphQLCell.tsx +++ b/apps/console/src/components/table/GraphQLCell.tsx @@ -24,7 +24,7 @@ type Props = { | { defaultValue: T[]; multiple: true } ); -export function GraphQLCell(props: Props) { +export function GraphQLCell>(props: Props) { const [value, setValue, valueRef] = useStateWithRef( props.defaultValue, ); diff --git a/apps/console/src/hooks/useMutateField.tsx b/apps/console/src/hooks/useMutateField.tsx index ef82cd9bb..93ee2a580 100644 --- a/apps/console/src/hooks/useMutateField.tsx +++ b/apps/console/src/hooks/useMutateField.tsx @@ -1,9 +1,9 @@ import type { GraphQLTaggedNode } from "relay-runtime"; import { useMutation } from "react-relay"; -export type MutationFieldUpdate = ( - field: keyof T, - value: T[typeof field], +export type MutationFieldUpdate, TKey extends keyof T> = ( + field: TKey, + value: T[TKey], ) => void; /** diff --git a/packages/hooks/src/useStateWithRef.ts b/packages/hooks/src/useStateWithRef.ts index c05c4d23a..45c5b932e 100644 --- a/packages/hooks/src/useStateWithRef.ts +++ b/packages/hooks/src/useStateWithRef.ts @@ -4,14 +4,18 @@ import { useCallback, useRef, useState } from "react"; * A useState hook that also returns a ref to the current state (usable in callbacks) */ export function useStateWithRef(initialValue: T) { - const [state, setState] = useState(initialValue); + const [state, setState] = useState(initialValue); const ref = useRef(state); return [ state, - useCallback((v: T) => { - setState(v); - ref.current = v; + useCallback((v: T | ((prevState: T) => T)) => { + setState(prev => { + const nextState = typeof v === "function" + ? (v as (prevState: T) => T)(prev) : v; + ref.current = nextState; + return nextState; + }); }, []), ref, ] as const; diff --git a/packages/ui/src/Molecules/Table/SelectCell.tsx b/packages/ui/src/Molecules/Table/SelectCell.tsx index 583ce2b55..c91ab074f 100644 --- a/packages/ui/src/Molecules/Table/SelectCell.tsx +++ b/packages/ui/src/Molecules/Table/SelectCell.tsx @@ -27,13 +27,13 @@ export const selectCell = tv({ }, }); -export function SelectCell(props: Props) { +export function SelectCell>(props: Props) { const [value, setValue, valueRef] = useStateWithRef( props.defaultValue, ); const cellRef = useEditableCellRef(); const { __ } = useTranslate(); - const filteredValue = Array.isArray(value) ? value.filter(Boolean) : value ? [value] : []; + const filteredValue = Array.isArray(value) ? value.filter(v => v !== undefined) : value ? [value] : []; const usedKeys = new Set(filteredValue.map(getKey).filter(Boolean) as string[]); const { onUpdate } = useEditableRowContext(); @@ -103,12 +103,12 @@ export function SelectCell(props: Props) { ); } -export function SelectValue(props: { +export function SelectValue>(props: { itemRenderer: Props["itemRenderer"]; onValueChange?: (value: T | T[]) => void; value: T | T[] | undefined; }) { - if (!props.value) { + if (props.value === undefined) { return ""; } if (!Array.isArray(props.value)) { diff --git a/packages/ui/src/Molecules/Table/TextCell.tsx b/packages/ui/src/Molecules/Table/TextCell.tsx index 7c39cd6b8..618a17e53 100644 --- a/packages/ui/src/Molecules/Table/TextCell.tsx +++ b/packages/ui/src/Molecules/Table/TextCell.tsx @@ -24,7 +24,7 @@ export function TextCell(props: Props) { if (props.required && inputValue === "") { return; } - if (inputValue !== props.defaultValue) { + if (inputValue !== value) { setValue(inputValue); onUpdate(props.name, inputValue); }