Skip to content
This repository was archived by the owner on Sep 9, 2024. It is now read-only.

Commit 0b451b1

Browse files
authored
fix: i18n duplicate field ui replication (#582)
1 parent 142bbdd commit 0b451b1

File tree

19 files changed

+168
-55
lines changed

19 files changed

+168
-55
lines changed

packages/core/src/components/Editor/EditorControlPane/EditorControl.tsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { borders, colors, lengths, transitions } from '@staticcms/core/component
2121
import { transientOptions } from '@staticcms/core/lib';
2222
import useMemoCompare from '@staticcms/core/lib/hooks/useMemoCompare';
2323
import useUUID from '@staticcms/core/lib/hooks/useUUID';
24+
import { isFieldDuplicate, isFieldHidden } from '@staticcms/core/lib/i18n';
2425
import { resolveWidget } from '@staticcms/core/lib/registry';
2526
import { getFieldLabel } from '@staticcms/core/lib/util/field.util';
2627
import { isNotNullish } from '@staticcms/core/lib/util/null.util';
@@ -144,10 +145,11 @@ const EditorControl = ({
144145
fieldsErrors,
145146
submitted,
146147
getAsset,
147-
isDisabled,
148-
isFieldDuplicate,
149-
isFieldHidden,
150-
isHidden = false,
148+
isDisabled = false,
149+
isParentDuplicate = false,
150+
isFieldDuplicate: deprecatedIsFieldDuplicate,
151+
isParentHidden = false,
152+
isFieldHidden: deprecatedIsFieldHidden,
151153
locale,
152154
mediaPaths,
153155
openMediaLibrary,
@@ -191,6 +193,15 @@ const EditorControl = ({
191193
[collection],
192194
);
193195

196+
const isDuplicate = useMemo(
197+
() => isParentDuplicate || isFieldDuplicate(field, locale, i18n?.defaultLocale),
198+
[field, i18n?.defaultLocale, isParentDuplicate, locale],
199+
);
200+
const isHidden = useMemo(
201+
() => isParentHidden || isFieldHidden(field, locale, i18n?.defaultLocale),
202+
[field, i18n?.defaultLocale, isParentHidden, locale],
203+
);
204+
194205
useEffect(() => {
195206
if ((!dirty && !submitted) || isHidden) {
196207
return;
@@ -257,9 +268,11 @@ const EditorControl = ({
257268
fieldsErrors,
258269
submitted,
259270
getAsset: handleGetAsset,
260-
isDisabled: isDisabled ?? false,
261-
isFieldDuplicate,
262-
isFieldHidden,
271+
isDisabled: isDisabled || isDuplicate,
272+
isDuplicate,
273+
isFieldDuplicate: deprecatedIsFieldDuplicate,
274+
isHidden,
275+
isFieldHidden: deprecatedIsFieldHidden,
263276
label: getFieldLabel(field, t),
264277
locale,
265278
mediaPaths,
@@ -330,9 +343,16 @@ interface EditorControlOwnProps {
330343
fieldsErrors: FieldsErrors;
331344
submitted: boolean;
332345
isDisabled?: boolean;
346+
isParentDuplicate?: boolean;
347+
/**
348+
* @deprecated use isDuplicate instead
349+
*/
333350
isFieldDuplicate?: (field: Field) => boolean;
351+
isParentHidden?: boolean;
352+
/**
353+
* @deprecated use isHidden instead
354+
*/
334355
isFieldHidden?: (field: Field) => boolean;
335-
isHidden?: boolean;
336356
locale?: string;
337357
parentPath: string;
338358
value: ValueOrNestedValue;

packages/core/src/components/Editor/EditorControlPane/EditorControlPane.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,6 @@ const EditorControlPane = ({
195195
) : null}
196196
{fields.map(field => {
197197
const isTranslatable = isFieldTranslatable(field, locale, i18n?.defaultLocale);
198-
const isDuplicate = isFieldDuplicate(field, locale, i18n?.defaultLocale);
199-
const isHidden = isFieldHidden(field, locale, i18n?.defaultLocale);
200198
const key = i18n ? `field-${locale}_${field.name}` : `field-${field.name}`;
201199

202200
return (
@@ -206,8 +204,6 @@ const EditorControlPane = ({
206204
value={getFieldValue(field, entry, isTranslatable, locale)}
207205
fieldsErrors={fieldsErrors}
208206
submitted={submitted}
209-
isDisabled={isDuplicate}
210-
isHidden={isHidden}
211207
isFieldDuplicate={field => isFieldDuplicate(field, locale, i18n?.defaultLocale)}
212208
isFieldHidden={field => isFieldHidden(field, locale, i18n?.defaultLocale)}
213209
locale={locale}

packages/core/src/interface.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export interface DisplayURLState {
235235
export type TranslatedProps<T> = T & ReactPolyglotTranslateProps;
236236

237237
/**
238-
* @deprecated Should use `useMediaAsset` React hook instead
238+
* @deprecated Use `useMediaAsset` React hook instead. Will be removed in v2.0.0
239239
*/
240240
export type GetAssetFunction<F extends BaseField = UnknownField> = (
241241
path: string,
@@ -251,11 +251,19 @@ export interface WidgetControlProps<T, F extends BaseField = UnknownField> {
251251
submitted: boolean;
252252
forList: boolean;
253253
/**
254-
* @deprecated Should use `useMediaAsset` React hook instead
254+
* @deprecated Use `useMediaAsset` React hook instead. Will be removed in v2.0.0
255255
*/
256256
getAsset: GetAssetFunction<F>;
257257
isDisabled: boolean;
258+
isDuplicate: boolean;
259+
/**
260+
* @deprecated Use `isDuplicate` instead. Will be removed in v2.0.0
261+
*/
258262
isFieldDuplicate: EditorControlProps['isFieldDuplicate'];
263+
isHidden: boolean;
264+
/**
265+
* @deprecated Use `isHidden` instead. Will be removed in v2.0.0
266+
*/
259267
isFieldHidden: EditorControlProps['isFieldHidden'];
260268
label: string;
261269
locale: string | undefined;

packages/core/src/lib/test-utils/ControlWrapper.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const createControlWrapper = <V = unknown, F extends BaseField = UnknownField>({
3838
return Promise.resolve(null) as any;
3939
},
4040
isDisabled = false,
41+
isDuplicate = false,
4142
isFieldDuplicate = () => false,
43+
isHidden = false,
4244
isFieldHidden = () => false,
4345
label = defaultLabel,
4446
locale = 'en',
@@ -75,7 +77,9 @@ const createControlWrapper = <V = unknown, F extends BaseField = UnknownField>({
7577
forList={forList}
7678
getAsset={getAsset}
7779
isDisabled={isDisabled}
80+
isDuplicate={isDuplicate}
7881
isFieldDuplicate={isFieldDuplicate}
82+
isHidden={isHidden}
7983
isFieldHidden={isFieldHidden}
8084
label={label}
8185
locale={locale}

packages/core/src/widgets/boolean/BooleanControl.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import { red } from '@mui/material/colors';
22
import FormControlLabel from '@mui/material/FormControlLabel';
33
import Switch from '@mui/material/Switch';
4-
import React, { useCallback, useState } from 'react';
4+
import React, { useCallback, useMemo, useState } from 'react';
55

66
import type { BooleanField, WidgetControlProps } from '@staticcms/core/interface';
77
import type { ChangeEvent, FC } from 'react';
88

99
const BooleanControl: FC<WidgetControlProps<boolean, BooleanField>> = ({
1010
value,
1111
label,
12+
isDuplicate,
1213
onChange,
1314
hasErrors,
1415
}) => {
15-
const [internalValue, setInternalValue] = useState(value);
16+
const [internalRawValue, setInternalValue] = useState(value);
17+
const internalValue = useMemo(
18+
() => (isDuplicate ? value : internalRawValue),
19+
[internalRawValue, isDuplicate, value],
20+
);
1621

1722
const handleChange = useCallback(
1823
(event: ChangeEvent<HTMLInputElement>) => {

packages/core/src/widgets/code/CodeControl.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function valueToOption(val: string | { name: string; label?: string }): {
6060

6161
const CodeControl: FC<WidgetControlProps<string | { [key: string]: string }, CodeField>> = ({
6262
field,
63+
isDuplicate,
6364
onChange,
6465
hasErrors,
6566
value,
@@ -77,7 +78,12 @@ const CodeControl: FC<WidgetControlProps<string | { [key: string]: string }, Cod
7778

7879
const valueIsMap = useMemo(() => Boolean(!field.output_code_only), [field.output_code_only]);
7980

80-
const [internalValue, setInternalValue] = useState(value ?? '');
81+
const [internalRawValue, setInternalValue] = useState(value ?? '');
82+
const internalValue = useMemo(
83+
() => (isDuplicate ? value ?? '' : internalRawValue),
84+
[internalRawValue, isDuplicate, value],
85+
);
86+
8187
const [lang, setLang] = useState<ProcessedCodeLanguage | null>(null);
8288
const [collapsed, setCollapsed] = useState(false);
8389

packages/core/src/widgets/colorstring/ColorControl.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import IconButton from '@mui/material/IconButton';
33
import InputAdornment from '@mui/material/InputAdornment';
44
import { styled } from '@mui/material/styles';
55
import TextField from '@mui/material/TextField';
6-
import React, { useCallback, useState } from 'react';
6+
import React, { useCallback, useMemo, useState } from 'react';
77
import { ChromePicker } from 'react-color';
88
import validateColor from 'validate-color';
99

@@ -104,6 +104,7 @@ const ClickOutsideDiv = styled('div')`
104104

105105
const ColorControl: FC<WidgetControlProps<string, ColorField>> = ({
106106
field,
107+
isDuplicate,
107108
onChange,
108109
value,
109110
hasErrors,
@@ -116,7 +117,11 @@ const ColorControl: FC<WidgetControlProps<string, ColorField>> = ({
116117
}, [collapsed]);
117118

118119
const [showColorPicker, setShowColorPicker] = useState(false);
119-
const [internalValue, setInternalValue] = useState(value ?? '');
120+
const [internalRawValue, setInternalValue] = useState(value ?? '');
121+
const internalValue = useMemo(
122+
() => (isDuplicate ? value ?? '' : internalRawValue),
123+
[internalRawValue, isDuplicate, value],
124+
);
120125

121126
// show/hide color picker
122127
const handleClick = useCallback(() => {

packages/core/src/widgets/datetime/DateTimeControl.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({
6262
value,
6363
t,
6464
isDisabled,
65+
isDuplicate,
6566
onChange,
6667
hasErrors,
6768
}) => {
@@ -118,7 +119,11 @@ const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({
118119
: field.default;
119120
}, [field.default, field.picker_utc, format, inputFormat, timezoneOffset]);
120121

121-
const [internalValue, setInternalValue] = useState(value);
122+
const [internalRawValue, setInternalValue] = useState(value);
123+
const internalValue = useMemo(
124+
() => (isDuplicate ? value : internalRawValue),
125+
[internalRawValue, isDuplicate, value],
126+
);
122127

123128
const dateValue: Date = useMemo(() => {
124129
let valueToParse = internalValue;

packages/core/src/widgets/file/withFileControl.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ const withFileControl = ({ forImage = false }: WithFileControlProps = {}) => {
213213
collection,
214214
field,
215215
entry,
216+
isDuplicate,
216217
onChange,
217218
openMediaLibrary,
218219
clearMediaControl,
@@ -222,7 +223,11 @@ const withFileControl = ({ forImage = false }: WithFileControlProps = {}) => {
222223
}) => {
223224
const controlID = useUUID();
224225
const [collapsed, setCollapsed] = useState(false);
225-
const [internalValue, setInternalValue] = useState(value ?? '');
226+
const [internalRawValue, setInternalValue] = useState(value ?? '');
227+
const internalValue = useMemo(
228+
() => (isDuplicate ? value ?? '' : internalRawValue),
229+
[internalRawValue, isDuplicate, value],
230+
);
226231

227232
const handleOnChange = useCallback(
228233
(newValue: string | string[]) => {

packages/core/src/widgets/list/ListControl.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ interface SortableItemProps {
6868
field: ListField;
6969
fieldsErrors: FieldsErrors;
7070
submitted: boolean;
71+
isDuplicate: boolean;
7172
isFieldDuplicate: ((field: Field<UnknownField>) => boolean) | undefined;
73+
isHidden: boolean;
7274
isFieldHidden: ((field: Field<UnknownField>) => boolean) | undefined;
7375
locale: string | undefined;
7476
path: string;
@@ -86,7 +88,9 @@ const SortableItem: FC<SortableItemProps> = ({
8688
field,
8789
fieldsErrors,
8890
submitted,
91+
isDuplicate,
8992
isFieldDuplicate,
93+
isHidden,
9094
isFieldHidden,
9195
locale,
9296
path,
@@ -118,7 +122,9 @@ const SortableItem: FC<SortableItemProps> = ({
118122
field={field}
119123
fieldsErrors={fieldsErrors}
120124
submitted={submitted}
125+
isDuplicate={isDuplicate}
121126
isFieldDuplicate={isFieldDuplicate}
127+
isHidden={isHidden}
122128
isFieldHidden={isFieldHidden}
123129
locale={locale}
124130
path={path}
@@ -188,7 +194,9 @@ const ListControl: FC<WidgetControlProps<ValueOrNestedValue[], ListField>> = ({
188194
field,
189195
fieldsErrors,
190196
submitted,
197+
isDuplicate,
191198
isFieldDuplicate,
199+
isHidden,
192200
isFieldHidden,
193201
locale,
194202
onChange,
@@ -356,7 +364,9 @@ const ListControl: FC<WidgetControlProps<ValueOrNestedValue[], ListField>> = ({
356364
field={field}
357365
fieldsErrors={fieldsErrors}
358366
submitted={submitted}
367+
isDuplicate={isDuplicate}
359368
isFieldDuplicate={isFieldDuplicate}
369+
isHidden={isHidden}
360370
isFieldHidden={isFieldHidden}
361371
locale={locale}
362372
path={path}

0 commit comments

Comments
 (0)