From 7b9d6534115265534073ba26ff925a3a844570b5 Mon Sep 17 00:00:00 2001 From: Daniel Lautzenheiser Date: Wed, 11 Oct 2023 16:25:01 -0400 Subject: [PATCH] fix: properly update duplicated and none i18n fields when default locale updates (#934) --- .../editor-control-pane/EditorControl.tsx | 10 ++++--- .../core/src/widgets/string/StringControl.tsx | 22 ++++++--------- .../string/__tests__/StringControl.spec.ts | 4 +-- .../core/src/widgets/text/TextControl.tsx | 27 ++++++++----------- .../text/__tests__/TextControl.spec.ts | 10 +++---- 5 files changed, 29 insertions(+), 44 deletions(-) diff --git a/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx b/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx index 4ffe48557..f61ca6bf4 100644 --- a/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx +++ b/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx @@ -105,13 +105,15 @@ const EditorControl = ({ [field, i18n?.defaultLocale, parentDuplicate, locale], ); const i18nDisabled = useMemo( - () => isFieldHidden(field, locale, i18n?.defaultLocale), + () => + isFieldHidden(field, locale, i18n?.defaultLocale) || + isFieldDuplicate(field, locale, i18n?.defaultLocale), [field, i18n?.defaultLocale, locale], ); const hidden = useHidden(field, entry, listItemPath); useEffect(() => { - if (!['list', 'object'].includes(field.widget)) { + if (!['list', 'object'].includes(field.widget) && !i18nDisabled) { return; } @@ -220,7 +222,7 @@ const EditorControl = ({ field: field as UnknownField, fieldsErrors, submitted, - disabled: disabled || duplicate || hidden || i18nDisabled, + disabled: disabled || duplicate || controlled || i18nDisabled, duplicate, label: getFieldLabel(field, t), locale, @@ -237,7 +239,7 @@ const EditorControl = ({ hasErrors, errors, theme, - controlled, + controlled: controlled || i18nDisabled, })} ); diff --git a/packages/core/src/widgets/string/StringControl.tsx b/packages/core/src/widgets/string/StringControl.tsx index 186f70672..2a5d09f9c 100644 --- a/packages/core/src/widgets/string/StringControl.tsx +++ b/packages/core/src/widgets/string/StringControl.tsx @@ -1,8 +1,7 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; import Field from '@staticcms/core/components/common/field/Field'; import TextField from '@staticcms/core/components/common/text-field/TextField'; -import useDebounce from '@staticcms/core/lib/hooks/useDebounce'; import classNames from '@staticcms/core/lib/util/classNames.util'; import { generateClassNames } from '@staticcms/core/lib/util/theming.util'; @@ -36,21 +35,16 @@ const StringControl: FC> = ({ () => (controlled || duplicate ? rawValue : internalRawValue), [controlled, duplicate, rawValue, internalRawValue], ); - const debouncedInternalValue = useDebounce(internalValue, 250); const ref = useRef(null); - const handleChange = useCallback((event: ChangeEvent) => { - setInternalValue(event.target.value); - }, []); - - useEffect(() => { - if (rawValue === debouncedInternalValue) { - return; - } - - onChange(debouncedInternalValue); - }, [debouncedInternalValue, onChange, rawValue]); + const handleChange = useCallback( + (event: ChangeEvent) => { + onChange(event.target.value); + setInternalValue(event.target.value); + }, + [onChange], + ); return ( { await userEvent.type(input, 'I am some text'); }); - expect(onChange).toHaveBeenCalledTimes(0); - await waitFor(() => { - expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledTimes(14); expect(onChange).toHaveBeenLastCalledWith('I am some text'); }); }); diff --git a/packages/core/src/widgets/text/TextControl.tsx b/packages/core/src/widgets/text/TextControl.tsx index 789f03358..1cdee8167 100644 --- a/packages/core/src/widgets/text/TextControl.tsx +++ b/packages/core/src/widgets/text/TextControl.tsx @@ -1,8 +1,7 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; import Field from '@staticcms/core/components/common/field/Field'; import TextArea from '@staticcms/core/components/common/text-field/TextArea'; -import useDebounce from '@staticcms/core/lib/hooks/useDebounce'; import classNames from '@staticcms/core/lib/util/classNames.util'; import { generateClassNames } from '@staticcms/core/lib/util/theming.util'; @@ -27,29 +26,25 @@ const TextControl: FC> = ({ disabled, field, forSingleList, + controlled, onChange, }) => { const rawValue = useMemo(() => value ?? '', [value]); const [internalRawValue, setInternalValue] = useState(rawValue); const internalValue = useMemo( - () => (duplicate ? rawValue : internalRawValue), - [internalRawValue, duplicate, rawValue], + () => (controlled || duplicate ? rawValue : internalRawValue), + [controlled, duplicate, rawValue, internalRawValue], ); - const debouncedInternalValue = useDebounce(internalValue, 250); const ref = useRef(null); - const handleChange = useCallback((event: ChangeEvent) => { - setInternalValue(event.target.value); - }, []); - - useEffect(() => { - if (rawValue === debouncedInternalValue) { - return; - } - - onChange(debouncedInternalValue); - }, [debouncedInternalValue, onChange, rawValue]); + const handleChange = useCallback( + (event: ChangeEvent) => { + onChange(event.target.value); + setInternalValue(event.target.value); + }, + [onChange], + ); return ( { await userEvent.type(input, 'I am some text'); }); - expect(onChange).toHaveBeenCalledTimes(0); - - await waitFor(() => { - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenLastCalledWith('I am some text'); - }); + expect(onChange).toHaveBeenCalledTimes(14); + expect(onChange).toHaveBeenLastCalledWith('I am some text'); }); it('should show error', async () => {