fix: i18n duplicate field ui replication (#582)
This commit is contained in:
parent
142bbdda13
commit
0b451b1db7
@ -21,6 +21,7 @@ import { borders, colors, lengths, transitions } from '@staticcms/core/component
|
||||
import { transientOptions } from '@staticcms/core/lib';
|
||||
import useMemoCompare from '@staticcms/core/lib/hooks/useMemoCompare';
|
||||
import useUUID from '@staticcms/core/lib/hooks/useUUID';
|
||||
import { isFieldDuplicate, isFieldHidden } from '@staticcms/core/lib/i18n';
|
||||
import { resolveWidget } from '@staticcms/core/lib/registry';
|
||||
import { getFieldLabel } from '@staticcms/core/lib/util/field.util';
|
||||
import { isNotNullish } from '@staticcms/core/lib/util/null.util';
|
||||
@ -144,10 +145,11 @@ const EditorControl = ({
|
||||
fieldsErrors,
|
||||
submitted,
|
||||
getAsset,
|
||||
isDisabled,
|
||||
isFieldDuplicate,
|
||||
isFieldHidden,
|
||||
isHidden = false,
|
||||
isDisabled = false,
|
||||
isParentDuplicate = false,
|
||||
isFieldDuplicate: deprecatedIsFieldDuplicate,
|
||||
isParentHidden = false,
|
||||
isFieldHidden: deprecatedIsFieldHidden,
|
||||
locale,
|
||||
mediaPaths,
|
||||
openMediaLibrary,
|
||||
@ -191,6 +193,15 @@ const EditorControl = ({
|
||||
[collection],
|
||||
);
|
||||
|
||||
const isDuplicate = useMemo(
|
||||
() => isParentDuplicate || isFieldDuplicate(field, locale, i18n?.defaultLocale),
|
||||
[field, i18n?.defaultLocale, isParentDuplicate, locale],
|
||||
);
|
||||
const isHidden = useMemo(
|
||||
() => isParentHidden || isFieldHidden(field, locale, i18n?.defaultLocale),
|
||||
[field, i18n?.defaultLocale, isParentHidden, locale],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if ((!dirty && !submitted) || isHidden) {
|
||||
return;
|
||||
@ -257,9 +268,11 @@ const EditorControl = ({
|
||||
fieldsErrors,
|
||||
submitted,
|
||||
getAsset: handleGetAsset,
|
||||
isDisabled: isDisabled ?? false,
|
||||
isFieldDuplicate,
|
||||
isFieldHidden,
|
||||
isDisabled: isDisabled || isDuplicate,
|
||||
isDuplicate,
|
||||
isFieldDuplicate: deprecatedIsFieldDuplicate,
|
||||
isHidden,
|
||||
isFieldHidden: deprecatedIsFieldHidden,
|
||||
label: getFieldLabel(field, t),
|
||||
locale,
|
||||
mediaPaths,
|
||||
@ -330,9 +343,16 @@ interface EditorControlOwnProps {
|
||||
fieldsErrors: FieldsErrors;
|
||||
submitted: boolean;
|
||||
isDisabled?: boolean;
|
||||
isParentDuplicate?: boolean;
|
||||
/**
|
||||
* @deprecated use isDuplicate instead
|
||||
*/
|
||||
isFieldDuplicate?: (field: Field) => boolean;
|
||||
isParentHidden?: boolean;
|
||||
/**
|
||||
* @deprecated use isHidden instead
|
||||
*/
|
||||
isFieldHidden?: (field: Field) => boolean;
|
||||
isHidden?: boolean;
|
||||
locale?: string;
|
||||
parentPath: string;
|
||||
value: ValueOrNestedValue;
|
||||
|
@ -195,8 +195,6 @@ const EditorControlPane = ({
|
||||
) : null}
|
||||
{fields.map(field => {
|
||||
const isTranslatable = isFieldTranslatable(field, locale, i18n?.defaultLocale);
|
||||
const isDuplicate = isFieldDuplicate(field, locale, i18n?.defaultLocale);
|
||||
const isHidden = isFieldHidden(field, locale, i18n?.defaultLocale);
|
||||
const key = i18n ? `field-${locale}_${field.name}` : `field-${field.name}`;
|
||||
|
||||
return (
|
||||
@ -206,8 +204,6 @@ const EditorControlPane = ({
|
||||
value={getFieldValue(field, entry, isTranslatable, locale)}
|
||||
fieldsErrors={fieldsErrors}
|
||||
submitted={submitted}
|
||||
isDisabled={isDuplicate}
|
||||
isHidden={isHidden}
|
||||
isFieldDuplicate={field => isFieldDuplicate(field, locale, i18n?.defaultLocale)}
|
||||
isFieldHidden={field => isFieldHidden(field, locale, i18n?.defaultLocale)}
|
||||
locale={locale}
|
||||
|
@ -235,7 +235,7 @@ export interface DisplayURLState {
|
||||
export type TranslatedProps<T> = T & ReactPolyglotTranslateProps;
|
||||
|
||||
/**
|
||||
* @deprecated Should use `useMediaAsset` React hook instead
|
||||
* @deprecated Use `useMediaAsset` React hook instead. Will be removed in v2.0.0
|
||||
*/
|
||||
export type GetAssetFunction<F extends BaseField = UnknownField> = (
|
||||
path: string,
|
||||
@ -251,11 +251,19 @@ export interface WidgetControlProps<T, F extends BaseField = UnknownField> {
|
||||
submitted: boolean;
|
||||
forList: boolean;
|
||||
/**
|
||||
* @deprecated Should use `useMediaAsset` React hook instead
|
||||
* @deprecated Use `useMediaAsset` React hook instead. Will be removed in v2.0.0
|
||||
*/
|
||||
getAsset: GetAssetFunction<F>;
|
||||
isDisabled: boolean;
|
||||
isDuplicate: boolean;
|
||||
/**
|
||||
* @deprecated Use `isDuplicate` instead. Will be removed in v2.0.0
|
||||
*/
|
||||
isFieldDuplicate: EditorControlProps['isFieldDuplicate'];
|
||||
isHidden: boolean;
|
||||
/**
|
||||
* @deprecated Use `isHidden` instead. Will be removed in v2.0.0
|
||||
*/
|
||||
isFieldHidden: EditorControlProps['isFieldHidden'];
|
||||
label: string;
|
||||
locale: string | undefined;
|
||||
|
@ -38,7 +38,9 @@ const createControlWrapper = <V = unknown, F extends BaseField = UnknownField>({
|
||||
return Promise.resolve(null) as any;
|
||||
},
|
||||
isDisabled = false,
|
||||
isDuplicate = false,
|
||||
isFieldDuplicate = () => false,
|
||||
isHidden = false,
|
||||
isFieldHidden = () => false,
|
||||
label = defaultLabel,
|
||||
locale = 'en',
|
||||
@ -75,7 +77,9 @@ const createControlWrapper = <V = unknown, F extends BaseField = UnknownField>({
|
||||
forList={forList}
|
||||
getAsset={getAsset}
|
||||
isDisabled={isDisabled}
|
||||
isDuplicate={isDuplicate}
|
||||
isFieldDuplicate={isFieldDuplicate}
|
||||
isHidden={isHidden}
|
||||
isFieldHidden={isFieldHidden}
|
||||
label={label}
|
||||
locale={locale}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { red } from '@mui/material/colors';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import type { BooleanField, WidgetControlProps } from '@staticcms/core/interface';
|
||||
import type { ChangeEvent, FC } from 'react';
|
||||
@ -9,10 +9,15 @@ import type { ChangeEvent, FC } from 'react';
|
||||
const BooleanControl: FC<WidgetControlProps<boolean, BooleanField>> = ({
|
||||
value,
|
||||
label,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
hasErrors,
|
||||
}) => {
|
||||
const [internalValue, setInternalValue] = useState(value);
|
||||
const [internalRawValue, setInternalValue] = useState(value);
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
|
@ -60,6 +60,7 @@ function valueToOption(val: string | { name: string; label?: string }): {
|
||||
|
||||
const CodeControl: FC<WidgetControlProps<string | { [key: string]: string }, CodeField>> = ({
|
||||
field,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
hasErrors,
|
||||
value,
|
||||
@ -77,7 +78,12 @@ const CodeControl: FC<WidgetControlProps<string | { [key: string]: string }, Cod
|
||||
|
||||
const valueIsMap = useMemo(() => Boolean(!field.output_code_only), [field.output_code_only]);
|
||||
|
||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
||||
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const [lang, setLang] = useState<ProcessedCodeLanguage | null>(null);
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
|
@ -3,7 +3,7 @@ import IconButton from '@mui/material/IconButton';
|
||||
import InputAdornment from '@mui/material/InputAdornment';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { ChromePicker } from 'react-color';
|
||||
import validateColor from 'validate-color';
|
||||
|
||||
@ -104,6 +104,7 @@ const ClickOutsideDiv = styled('div')`
|
||||
|
||||
const ColorControl: FC<WidgetControlProps<string, ColorField>> = ({
|
||||
field,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
value,
|
||||
hasErrors,
|
||||
@ -116,7 +117,11 @@ const ColorControl: FC<WidgetControlProps<string, ColorField>> = ({
|
||||
}, [collapsed]);
|
||||
|
||||
const [showColorPicker, setShowColorPicker] = useState(false);
|
||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
||||
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
// show/hide color picker
|
||||
const handleClick = useCallback(() => {
|
||||
|
@ -62,6 +62,7 @@ const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({
|
||||
value,
|
||||
t,
|
||||
isDisabled,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
hasErrors,
|
||||
}) => {
|
||||
@ -118,7 +119,11 @@ const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({
|
||||
: field.default;
|
||||
}, [field.default, field.picker_utc, format, inputFormat, timezoneOffset]);
|
||||
|
||||
const [internalValue, setInternalValue] = useState(value);
|
||||
const [internalRawValue, setInternalValue] = useState(value);
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const dateValue: Date = useMemo(() => {
|
||||
let valueToParse = internalValue;
|
||||
|
@ -213,6 +213,7 @@ const withFileControl = ({ forImage = false }: WithFileControlProps = {}) => {
|
||||
collection,
|
||||
field,
|
||||
entry,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
openMediaLibrary,
|
||||
clearMediaControl,
|
||||
@ -222,7 +223,11 @@ const withFileControl = ({ forImage = false }: WithFileControlProps = {}) => {
|
||||
}) => {
|
||||
const controlID = useUUID();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
||||
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const handleOnChange = useCallback(
|
||||
(newValue: string | string[]) => {
|
||||
|
@ -68,7 +68,9 @@ interface SortableItemProps {
|
||||
field: ListField;
|
||||
fieldsErrors: FieldsErrors;
|
||||
submitted: boolean;
|
||||
isDuplicate: boolean;
|
||||
isFieldDuplicate: ((field: Field<UnknownField>) => boolean) | undefined;
|
||||
isHidden: boolean;
|
||||
isFieldHidden: ((field: Field<UnknownField>) => boolean) | undefined;
|
||||
locale: string | undefined;
|
||||
path: string;
|
||||
@ -86,7 +88,9 @@ const SortableItem: FC<SortableItemProps> = ({
|
||||
field,
|
||||
fieldsErrors,
|
||||
submitted,
|
||||
isDuplicate,
|
||||
isFieldDuplicate,
|
||||
isHidden,
|
||||
isFieldHidden,
|
||||
locale,
|
||||
path,
|
||||
@ -118,7 +122,9 @@ const SortableItem: FC<SortableItemProps> = ({
|
||||
field={field}
|
||||
fieldsErrors={fieldsErrors}
|
||||
submitted={submitted}
|
||||
isDuplicate={isDuplicate}
|
||||
isFieldDuplicate={isFieldDuplicate}
|
||||
isHidden={isHidden}
|
||||
isFieldHidden={isFieldHidden}
|
||||
locale={locale}
|
||||
path={path}
|
||||
@ -188,7 +194,9 @@ const ListControl: FC<WidgetControlProps<ValueOrNestedValue[], ListField>> = ({
|
||||
field,
|
||||
fieldsErrors,
|
||||
submitted,
|
||||
isDuplicate,
|
||||
isFieldDuplicate,
|
||||
isHidden,
|
||||
isFieldHidden,
|
||||
locale,
|
||||
onChange,
|
||||
@ -356,7 +364,9 @@ const ListControl: FC<WidgetControlProps<ValueOrNestedValue[], ListField>> = ({
|
||||
field={field}
|
||||
fieldsErrors={fieldsErrors}
|
||||
submitted={submitted}
|
||||
isDuplicate={isDuplicate}
|
||||
isFieldDuplicate={isFieldDuplicate}
|
||||
isHidden={isHidden}
|
||||
isFieldHidden={isFieldHidden}
|
||||
locale={locale}
|
||||
path={path}
|
||||
|
@ -93,7 +93,9 @@ interface ListItemProps
|
||||
| 'field'
|
||||
| 'fieldsErrors'
|
||||
| 'submitted'
|
||||
| 'isDuplicate'
|
||||
| 'isFieldDuplicate'
|
||||
| 'isHidden'
|
||||
| 'isFieldHidden'
|
||||
| 'locale'
|
||||
| 'path'
|
||||
@ -114,7 +116,9 @@ const ListItem: FC<ListItemProps> = ({
|
||||
field,
|
||||
fieldsErrors,
|
||||
submitted,
|
||||
isDuplicate,
|
||||
isFieldDuplicate,
|
||||
isHidden,
|
||||
isFieldHidden,
|
||||
locale,
|
||||
path,
|
||||
@ -197,9 +201,6 @@ const ListItem: FC<ListItemProps> = ({
|
||||
[collapsed],
|
||||
);
|
||||
|
||||
const isDuplicate = isFieldDuplicate && isFieldDuplicate(field);
|
||||
const isHidden = isFieldHidden && isFieldHidden(field);
|
||||
|
||||
const finalValue = useMemo(() => {
|
||||
if (field.fields && field.fields.length === 1) {
|
||||
return {
|
||||
@ -232,8 +233,9 @@ const ListItem: FC<ListItemProps> = ({
|
||||
submitted={submitted}
|
||||
parentPath={path}
|
||||
isDisabled={isDuplicate}
|
||||
isHidden={isHidden}
|
||||
isParentDuplicate={isDuplicate}
|
||||
isFieldDuplicate={isFieldDuplicate}
|
||||
isParentHidden={isHidden}
|
||||
isFieldHidden={isFieldHidden}
|
||||
locale={locale}
|
||||
i18n={i18n}
|
||||
|
@ -39,9 +39,14 @@ export interface WithMarkdownControlProps {
|
||||
|
||||
const withMarkdownControl = ({ useMdx }: WithMarkdownControlProps) => {
|
||||
const MarkdownControl: FC<WidgetControlProps<string, MarkdownField>> = controlProps => {
|
||||
const { label, value, onChange, hasErrors, collection, entry, field } = controlProps;
|
||||
const { label, value, isDuplicate, onChange, hasErrors, collection, entry, field } =
|
||||
controlProps;
|
||||
|
||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
||||
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
const [hasFocus, setHasFocus] = useState(false);
|
||||
const debouncedFocus = useDebounce(hasFocus, 150);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import TextField from '@mui/material/TextField';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import type { FieldError, NumberField, WidgetControlProps } from '@staticcms/core/interface';
|
||||
import type { ChangeEvent, FC } from 'react';
|
||||
@ -62,10 +62,15 @@ const NumberControl: FC<WidgetControlProps<string | number, NumberField>> = ({
|
||||
label,
|
||||
field,
|
||||
value,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
hasErrors,
|
||||
}) => {
|
||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
||||
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
|
@ -53,7 +53,9 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
||||
fieldsErrors,
|
||||
submitted,
|
||||
forList,
|
||||
isDuplicate,
|
||||
isFieldDuplicate,
|
||||
isHidden,
|
||||
isFieldHidden,
|
||||
locale,
|
||||
path,
|
||||
@ -96,9 +98,6 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
||||
parentPath = splitPath.join('.');
|
||||
}
|
||||
|
||||
const isDuplicate = isFieldDuplicate && isFieldDuplicate(field);
|
||||
const isHidden = isFieldHidden && isFieldHidden(field);
|
||||
|
||||
return (
|
||||
<EditorControl
|
||||
key={index}
|
||||
@ -109,8 +108,9 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
||||
submitted={submitted}
|
||||
parentPath={parentPath}
|
||||
isDisabled={isDuplicate}
|
||||
isHidden={isHidden}
|
||||
isParentDuplicate={isDuplicate}
|
||||
isFieldDuplicate={isFieldDuplicate}
|
||||
isParentHidden={isHidden}
|
||||
isFieldHidden={isFieldHidden}
|
||||
locale={locale}
|
||||
i18n={i18n}
|
||||
@ -122,8 +122,10 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
||||
fieldsErrors,
|
||||
forList,
|
||||
i18n,
|
||||
isDuplicate,
|
||||
isFieldDuplicate,
|
||||
isFieldHidden,
|
||||
isHidden,
|
||||
locale,
|
||||
multiFields,
|
||||
path,
|
||||
|
@ -118,13 +118,18 @@ function getSelectedValue(
|
||||
const RelationControl: FC<WidgetControlProps<string | string[], RelationField>> = ({
|
||||
value,
|
||||
field,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
config,
|
||||
locale,
|
||||
label,
|
||||
hasErrors,
|
||||
}) => {
|
||||
const [internalValue, setInternalValue] = useState(value);
|
||||
const [internalRawValue, setInternalValue] = useState(value);
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
const [initialOptions, setInitialOptions] = useState<HitOption[]>([]);
|
||||
|
||||
const searchCollectionSelector = useMemo(
|
||||
|
@ -31,9 +31,14 @@ const SelectControl: FC<WidgetControlProps<string | number | (string | number)[]
|
||||
field,
|
||||
value,
|
||||
hasErrors,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
}) => {
|
||||
const [internalValue, setInternalValue] = useState(value);
|
||||
const [internalRawValue, setInternalValue] = useState(value);
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const fieldOptions: (string | number | Option)[] = useMemo(() => field.options, [field.options]);
|
||||
const isMultiple = useMemo(() => field.multiple ?? false, [field.multiple]);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import TextField from '@mui/material/TextField';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import type { StringOrTextField, WidgetControlProps } from '@staticcms/core/interface';
|
||||
import type { ChangeEvent, FC } from 'react';
|
||||
@ -7,10 +7,15 @@ import type { ChangeEvent, FC } from 'react';
|
||||
const StringControl: FC<WidgetControlProps<string, StringOrTextField>> = ({
|
||||
value,
|
||||
label,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
hasErrors,
|
||||
}) => {
|
||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
||||
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import TextField from '@mui/material/TextField';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import type { StringOrTextField, WidgetControlProps } from '@staticcms/core/interface';
|
||||
import type { ChangeEvent, FC } from 'react';
|
||||
@ -7,10 +7,15 @@ import type { ChangeEvent, FC } from 'react';
|
||||
const TextControl: FC<WidgetControlProps<string, StringOrTextField>> = ({
|
||||
label,
|
||||
value,
|
||||
isDuplicate,
|
||||
onChange,
|
||||
hasErrors,
|
||||
}) => {
|
||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
||||
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||
const internalValue = useMemo(
|
||||
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||
[internalRawValue, isDuplicate, value],
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
|
@ -55,10 +55,12 @@ The react component that renders the control. It receives the following props:
|
||||
| fieldsErrors | object | Key/value object of field names mapping to validation errors |
|
||||
| isDisabled | boolean | Specifies if the widget control should be disabled |
|
||||
| submitted | boolean | Specifies if a save attempt has been made in the editor session |
|
||||
| forList | boolean | Specifices if the widget is within a `list` widget |
|
||||
| isFieldDuplicate | function | Function that given a field configuration, returns if that field is a duplicate |
|
||||
| isFieldHidden | function | Function that given a field configuration, returns if that field is hidden |
|
||||
| getAsset | Async function | __Deprecated__ Function that given a url returns (as a promise) a loaded asset |
|
||||
| forList | boolean | Specifies if the widget is within a `list` widget |
|
||||
| isDuplicate | function | Specifies if that field is an i18n duplicate |
|
||||
| isFieldDuplicate | function | **Deprecated** Function that given a field configuration, returns if that field is a duplicate |
|
||||
| isHidden | function | Specifies if that field should be hidden |
|
||||
| isFieldHidden | function | **Deprecated** Function that given a field configuration, returns if that field is hidden |
|
||||
| getAsset | Async function | **Deprecated** Function that given a url returns (as a promise) a loaded asset |
|
||||
| locale | string<br />\| undefined | The current locale of the editor |
|
||||
| mediaPaths | object | Key/value object of control IDs (passed to the media library) mapping to media paths |
|
||||
| clearMediaControl | function | Clears a control ID's value from the internal store |
|
||||
@ -107,7 +109,7 @@ The react component that renders the preview. It receives the following props:
|
||||
| collection | object | The collection configuration for the current widget. See [Collections](/docs/collection-overview) |
|
||||
| config | object | The current Static CMS config. See [configuration options](/docs/configuration-options) |
|
||||
| entry | object | Object with a `data` field that contains the current value of all widgets in the editor |
|
||||
| getAsset | Async function | __Deprecated__ Function that given a url returns (as a promise) a loaded asset |
|
||||
| getAsset | Async function | **Deprecated** Function that given a url returns (as a promise) a loaded asset |
|
||||
|
||||
### Options
|
||||
|
||||
@ -167,9 +169,12 @@ import CMS from '@staticcms/core';
|
||||
const CategoriesControl = ({ label, value, field, onChange }) => {
|
||||
const separator = useMemo(() => field.separator ?? ', ', [field.separator]);
|
||||
|
||||
const handleChange = useCallback((e) => {
|
||||
const handleChange = useCallback(
|
||||
e => {
|
||||
onChange(e.target.value.split(separator).map(e => e.trim()));
|
||||
}, [separator, onChange]);
|
||||
},
|
||||
[separator, onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -178,7 +183,8 @@ const CategoriesControl = ({ label, value, field, onChange }) => {
|
||||
id="inputId"
|
||||
type="text"
|
||||
value={value ? value.join(separator) : ''}
|
||||
onChange={handleChange} />
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -208,15 +214,23 @@ import CMS from '@staticcms/core';
|
||||
import type { WidgetControlProps, WidgetPreviewProps } from '@staticcms/core';
|
||||
|
||||
interface CategoriesField {
|
||||
widget: 'categories'
|
||||
widget: 'categories';
|
||||
}
|
||||
|
||||
const CategoriesControl = ({ label, value, field, onChange }: WidgetControlProps<string[], CategoriesField>) => {
|
||||
const CategoriesControl = ({
|
||||
label,
|
||||
value,
|
||||
field,
|
||||
onChange,
|
||||
}: WidgetControlProps<string[], CategoriesField>) => {
|
||||
const separator = useMemo(() => field.separator ?? ', ', [field.separator]);
|
||||
|
||||
const handleChange = useCallback((e) => {
|
||||
const handleChange = useCallback(
|
||||
e => {
|
||||
onChange(e.target.value.split(separator).map(e => e.trim()));
|
||||
}, [separator, onChange]);
|
||||
},
|
||||
[separator, onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -225,7 +239,8 @@ const CategoriesControl = ({ label, value, field, onChange }: WidgetControlProps
|
||||
id="inputId"
|
||||
type="text"
|
||||
value={value ? value.join(separator) : ''}
|
||||
onChange={handleChange} />
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -367,7 +382,7 @@ const FileControl = ({ collection, field, value, entry, onChange }) => {
|
||||
|
||||
return [
|
||||
h('button', { type: 'button', onClick: handleOpenMediaLibrary }, 'Upload'),
|
||||
h('img', { role: 'presentation', src: assetSource })
|
||||
h('img', { role: 'presentation', src: assetSource }),
|
||||
];
|
||||
};
|
||||
```
|
||||
|
Loading…
x
Reference in New Issue
Block a user