Merge branch 'main' into next
This commit is contained in:
commit
2d5678430a
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"version": "1.2.9"
|
"version": "1.2.10"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@staticcms/app",
|
"name": "@staticcms/app",
|
||||||
"version": "1.2.9",
|
"version": "1.2.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Static CMS application.",
|
"description": "Static CMS application.",
|
||||||
"repository": "https://github.com/StaticJsCMS/static-cms",
|
"repository": "https://github.com/StaticJsCMS/static-cms",
|
||||||
@ -35,7 +35,7 @@
|
|||||||
"@babel/eslint-parser": "7.19.1",
|
"@babel/eslint-parser": "7.19.1",
|
||||||
"@babel/runtime": "7.21.0",
|
"@babel/runtime": "7.21.0",
|
||||||
"@emotion/babel-preset-css-prop": "11.10.0",
|
"@emotion/babel-preset-css-prop": "11.10.0",
|
||||||
"@staticcms/core": "^1.2.9",
|
"@staticcms/core": "^1.2.10",
|
||||||
"buffer": "6.0.3",
|
"buffer": "6.0.3",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@staticcms/core",
|
"name": "@staticcms/core",
|
||||||
"version": "1.2.9",
|
"version": "1.2.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Static CMS core application.",
|
"description": "Static CMS core application.",
|
||||||
"repository": "https://github.com/StaticJsCMS/static-cms",
|
"repository": "https://github.com/StaticJsCMS/static-cms",
|
||||||
|
@ -21,6 +21,7 @@ import { borders, colors, lengths, transitions } from '@staticcms/core/component
|
|||||||
import { transientOptions } from '@staticcms/core/lib';
|
import { transientOptions } from '@staticcms/core/lib';
|
||||||
import useMemoCompare from '@staticcms/core/lib/hooks/useMemoCompare';
|
import useMemoCompare from '@staticcms/core/lib/hooks/useMemoCompare';
|
||||||
import useUUID from '@staticcms/core/lib/hooks/useUUID';
|
import useUUID from '@staticcms/core/lib/hooks/useUUID';
|
||||||
|
import { isFieldDuplicate, isFieldHidden } from '@staticcms/core/lib/i18n';
|
||||||
import { resolveWidget } from '@staticcms/core/lib/registry';
|
import { resolveWidget } from '@staticcms/core/lib/registry';
|
||||||
import { getFieldLabel } from '@staticcms/core/lib/util/field.util';
|
import { getFieldLabel } from '@staticcms/core/lib/util/field.util';
|
||||||
import { isNotNullish } from '@staticcms/core/lib/util/null.util';
|
import { isNotNullish } from '@staticcms/core/lib/util/null.util';
|
||||||
@ -144,10 +145,11 @@ const EditorControl = ({
|
|||||||
fieldsErrors,
|
fieldsErrors,
|
||||||
submitted,
|
submitted,
|
||||||
getAsset,
|
getAsset,
|
||||||
isDisabled,
|
isDisabled = false,
|
||||||
isFieldDuplicate,
|
isParentDuplicate = false,
|
||||||
isFieldHidden,
|
isFieldDuplicate: deprecatedIsFieldDuplicate,
|
||||||
isHidden = false,
|
isParentHidden = false,
|
||||||
|
isFieldHidden: deprecatedIsFieldHidden,
|
||||||
locale,
|
locale,
|
||||||
mediaPaths,
|
mediaPaths,
|
||||||
openMediaLibrary,
|
openMediaLibrary,
|
||||||
@ -191,6 +193,15 @@ const EditorControl = ({
|
|||||||
[collection],
|
[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(() => {
|
useEffect(() => {
|
||||||
if ((!dirty && !submitted) || isHidden) {
|
if ((!dirty && !submitted) || isHidden) {
|
||||||
return;
|
return;
|
||||||
@ -257,9 +268,11 @@ const EditorControl = ({
|
|||||||
fieldsErrors,
|
fieldsErrors,
|
||||||
submitted,
|
submitted,
|
||||||
getAsset: handleGetAsset,
|
getAsset: handleGetAsset,
|
||||||
isDisabled: isDisabled ?? false,
|
isDisabled: isDisabled || isDuplicate,
|
||||||
isFieldDuplicate,
|
isDuplicate,
|
||||||
isFieldHidden,
|
isFieldDuplicate: deprecatedIsFieldDuplicate,
|
||||||
|
isHidden,
|
||||||
|
isFieldHidden: deprecatedIsFieldHidden,
|
||||||
label: getFieldLabel(field, t),
|
label: getFieldLabel(field, t),
|
||||||
locale,
|
locale,
|
||||||
mediaPaths,
|
mediaPaths,
|
||||||
@ -330,9 +343,16 @@ interface EditorControlOwnProps {
|
|||||||
fieldsErrors: FieldsErrors;
|
fieldsErrors: FieldsErrors;
|
||||||
submitted: boolean;
|
submitted: boolean;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
|
isParentDuplicate?: boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated use isDuplicate instead
|
||||||
|
*/
|
||||||
isFieldDuplicate?: (field: Field) => boolean;
|
isFieldDuplicate?: (field: Field) => boolean;
|
||||||
|
isParentHidden?: boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated use isHidden instead
|
||||||
|
*/
|
||||||
isFieldHidden?: (field: Field) => boolean;
|
isFieldHidden?: (field: Field) => boolean;
|
||||||
isHidden?: boolean;
|
|
||||||
locale?: string;
|
locale?: string;
|
||||||
parentPath: string;
|
parentPath: string;
|
||||||
value: ValueOrNestedValue;
|
value: ValueOrNestedValue;
|
||||||
|
@ -195,8 +195,6 @@ const EditorControlPane = ({
|
|||||||
) : null}
|
) : null}
|
||||||
{fields.map(field => {
|
{fields.map(field => {
|
||||||
const isTranslatable = isFieldTranslatable(field, locale, i18n?.defaultLocale);
|
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}`;
|
const key = i18n ? `field-${locale}_${field.name}` : `field-${field.name}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -206,8 +204,6 @@ const EditorControlPane = ({
|
|||||||
value={getFieldValue(field, entry, isTranslatable, locale)}
|
value={getFieldValue(field, entry, isTranslatable, locale)}
|
||||||
fieldsErrors={fieldsErrors}
|
fieldsErrors={fieldsErrors}
|
||||||
submitted={submitted}
|
submitted={submitted}
|
||||||
isDisabled={isDuplicate}
|
|
||||||
isHidden={isHidden}
|
|
||||||
isFieldDuplicate={field => isFieldDuplicate(field, locale, i18n?.defaultLocale)}
|
isFieldDuplicate={field => isFieldDuplicate(field, locale, i18n?.defaultLocale)}
|
||||||
isFieldHidden={field => isFieldHidden(field, locale, i18n?.defaultLocale)}
|
isFieldHidden={field => isFieldHidden(field, locale, i18n?.defaultLocale)}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
@ -235,7 +235,7 @@ export interface DisplayURLState {
|
|||||||
export type TranslatedProps<T> = T & ReactPolyglotTranslateProps;
|
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> = (
|
export type GetAssetFunction<F extends BaseField = UnknownField> = (
|
||||||
path: string,
|
path: string,
|
||||||
@ -251,11 +251,19 @@ export interface WidgetControlProps<T, F extends BaseField = UnknownField> {
|
|||||||
submitted: boolean;
|
submitted: boolean;
|
||||||
forList: 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>;
|
getAsset: GetAssetFunction<F>;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
|
isDuplicate: boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Use `isDuplicate` instead. Will be removed in v2.0.0
|
||||||
|
*/
|
||||||
isFieldDuplicate: EditorControlProps['isFieldDuplicate'];
|
isFieldDuplicate: EditorControlProps['isFieldDuplicate'];
|
||||||
|
isHidden: boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Use `isHidden` instead. Will be removed in v2.0.0
|
||||||
|
*/
|
||||||
isFieldHidden: EditorControlProps['isFieldHidden'];
|
isFieldHidden: EditorControlProps['isFieldHidden'];
|
||||||
label: string;
|
label: string;
|
||||||
locale: string | undefined;
|
locale: string | undefined;
|
||||||
|
@ -38,7 +38,9 @@ const createControlWrapper = <V = unknown, F extends BaseField = UnknownField>({
|
|||||||
return Promise.resolve(null) as any;
|
return Promise.resolve(null) as any;
|
||||||
},
|
},
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
|
isDuplicate = false,
|
||||||
isFieldDuplicate = () => false,
|
isFieldDuplicate = () => false,
|
||||||
|
isHidden = false,
|
||||||
isFieldHidden = () => false,
|
isFieldHidden = () => false,
|
||||||
label = defaultLabel,
|
label = defaultLabel,
|
||||||
locale = 'en',
|
locale = 'en',
|
||||||
@ -75,7 +77,9 @@ const createControlWrapper = <V = unknown, F extends BaseField = UnknownField>({
|
|||||||
forList={forList}
|
forList={forList}
|
||||||
getAsset={getAsset}
|
getAsset={getAsset}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
|
isDuplicate={isDuplicate}
|
||||||
isFieldDuplicate={isFieldDuplicate}
|
isFieldDuplicate={isFieldDuplicate}
|
||||||
|
isHidden={isHidden}
|
||||||
isFieldHidden={isFieldHidden}
|
isFieldHidden={isFieldHidden}
|
||||||
label={label}
|
label={label}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { red } from '@mui/material/colors';
|
import { red } from '@mui/material/colors';
|
||||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||||
import Switch from '@mui/material/Switch';
|
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 { BooleanField, WidgetControlProps } from '@staticcms/core/interface';
|
||||||
import type { ChangeEvent, FC } from 'react';
|
import type { ChangeEvent, FC } from 'react';
|
||||||
@ -9,10 +9,15 @@ import type { ChangeEvent, FC } from 'react';
|
|||||||
const BooleanControl: FC<WidgetControlProps<boolean, BooleanField>> = ({
|
const BooleanControl: FC<WidgetControlProps<boolean, BooleanField>> = ({
|
||||||
value,
|
value,
|
||||||
label,
|
label,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
}) => {
|
}) => {
|
||||||
const [internalValue, setInternalValue] = useState(value);
|
const [internalRawValue, setInternalValue] = useState(value);
|
||||||
|
const internalValue = useMemo(
|
||||||
|
() => (isDuplicate ? value : internalRawValue),
|
||||||
|
[internalRawValue, isDuplicate, value],
|
||||||
|
);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement>) => {
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
@ -60,6 +60,7 @@ function valueToOption(val: string | { name: string; label?: string }): {
|
|||||||
|
|
||||||
const CodeControl: FC<WidgetControlProps<string | { [key: string]: string }, CodeField>> = ({
|
const CodeControl: FC<WidgetControlProps<string | { [key: string]: string }, CodeField>> = ({
|
||||||
field,
|
field,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
value,
|
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 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 [lang, setLang] = useState<ProcessedCodeLanguage | null>(null);
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import IconButton from '@mui/material/IconButton';
|
|||||||
import InputAdornment from '@mui/material/InputAdornment';
|
import InputAdornment from '@mui/material/InputAdornment';
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
import TextField from '@mui/material/TextField';
|
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 { ChromePicker } from 'react-color';
|
||||||
import validateColor from 'validate-color';
|
import validateColor from 'validate-color';
|
||||||
|
|
||||||
@ -104,6 +104,7 @@ const ClickOutsideDiv = styled('div')`
|
|||||||
|
|
||||||
const ColorControl: FC<WidgetControlProps<string, ColorField>> = ({
|
const ColorControl: FC<WidgetControlProps<string, ColorField>> = ({
|
||||||
field,
|
field,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
value,
|
value,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
@ -116,7 +117,11 @@ const ColorControl: FC<WidgetControlProps<string, ColorField>> = ({
|
|||||||
}, [collapsed]);
|
}, [collapsed]);
|
||||||
|
|
||||||
const [showColorPicker, setShowColorPicker] = useState(false);
|
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
|
// show/hide color picker
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
|
@ -62,6 +62,7 @@ const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({
|
|||||||
value,
|
value,
|
||||||
t,
|
t,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
}) => {
|
}) => {
|
||||||
@ -118,7 +119,11 @@ const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({
|
|||||||
: field.default;
|
: field.default;
|
||||||
}, [field.default, field.picker_utc, format, inputFormat, timezoneOffset]);
|
}, [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(() => {
|
const dateValue: Date = useMemo(() => {
|
||||||
let valueToParse = internalValue;
|
let valueToParse = internalValue;
|
||||||
|
@ -213,6 +213,7 @@ const withFileControl = ({ forImage = false }: WithFileControlProps = {}) => {
|
|||||||
collection,
|
collection,
|
||||||
field,
|
field,
|
||||||
entry,
|
entry,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
openMediaLibrary,
|
openMediaLibrary,
|
||||||
clearMediaControl,
|
clearMediaControl,
|
||||||
@ -222,7 +223,11 @@ const withFileControl = ({ forImage = false }: WithFileControlProps = {}) => {
|
|||||||
}) => {
|
}) => {
|
||||||
const controlID = useUUID();
|
const controlID = useUUID();
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
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(
|
const handleOnChange = useCallback(
|
||||||
(newValue: string | string[]) => {
|
(newValue: string | string[]) => {
|
||||||
|
@ -68,7 +68,9 @@ interface SortableItemProps {
|
|||||||
field: ListField;
|
field: ListField;
|
||||||
fieldsErrors: FieldsErrors;
|
fieldsErrors: FieldsErrors;
|
||||||
submitted: boolean;
|
submitted: boolean;
|
||||||
|
isDuplicate: boolean;
|
||||||
isFieldDuplicate: ((field: Field<UnknownField>) => boolean) | undefined;
|
isFieldDuplicate: ((field: Field<UnknownField>) => boolean) | undefined;
|
||||||
|
isHidden: boolean;
|
||||||
isFieldHidden: ((field: Field<UnknownField>) => boolean) | undefined;
|
isFieldHidden: ((field: Field<UnknownField>) => boolean) | undefined;
|
||||||
locale: string | undefined;
|
locale: string | undefined;
|
||||||
path: string;
|
path: string;
|
||||||
@ -86,7 +88,9 @@ const SortableItem: FC<SortableItemProps> = ({
|
|||||||
field,
|
field,
|
||||||
fieldsErrors,
|
fieldsErrors,
|
||||||
submitted,
|
submitted,
|
||||||
|
isDuplicate,
|
||||||
isFieldDuplicate,
|
isFieldDuplicate,
|
||||||
|
isHidden,
|
||||||
isFieldHidden,
|
isFieldHidden,
|
||||||
locale,
|
locale,
|
||||||
path,
|
path,
|
||||||
@ -118,7 +122,9 @@ const SortableItem: FC<SortableItemProps> = ({
|
|||||||
field={field}
|
field={field}
|
||||||
fieldsErrors={fieldsErrors}
|
fieldsErrors={fieldsErrors}
|
||||||
submitted={submitted}
|
submitted={submitted}
|
||||||
|
isDuplicate={isDuplicate}
|
||||||
isFieldDuplicate={isFieldDuplicate}
|
isFieldDuplicate={isFieldDuplicate}
|
||||||
|
isHidden={isHidden}
|
||||||
isFieldHidden={isFieldHidden}
|
isFieldHidden={isFieldHidden}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
path={path}
|
path={path}
|
||||||
@ -188,7 +194,9 @@ const ListControl: FC<WidgetControlProps<ValueOrNestedValue[], ListField>> = ({
|
|||||||
field,
|
field,
|
||||||
fieldsErrors,
|
fieldsErrors,
|
||||||
submitted,
|
submitted,
|
||||||
|
isDuplicate,
|
||||||
isFieldDuplicate,
|
isFieldDuplicate,
|
||||||
|
isHidden,
|
||||||
isFieldHidden,
|
isFieldHidden,
|
||||||
locale,
|
locale,
|
||||||
onChange,
|
onChange,
|
||||||
@ -356,7 +364,9 @@ const ListControl: FC<WidgetControlProps<ValueOrNestedValue[], ListField>> = ({
|
|||||||
field={field}
|
field={field}
|
||||||
fieldsErrors={fieldsErrors}
|
fieldsErrors={fieldsErrors}
|
||||||
submitted={submitted}
|
submitted={submitted}
|
||||||
|
isDuplicate={isDuplicate}
|
||||||
isFieldDuplicate={isFieldDuplicate}
|
isFieldDuplicate={isFieldDuplicate}
|
||||||
|
isHidden={isHidden}
|
||||||
isFieldHidden={isFieldHidden}
|
isFieldHidden={isFieldHidden}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
path={path}
|
path={path}
|
||||||
|
@ -93,7 +93,9 @@ interface ListItemProps
|
|||||||
| 'field'
|
| 'field'
|
||||||
| 'fieldsErrors'
|
| 'fieldsErrors'
|
||||||
| 'submitted'
|
| 'submitted'
|
||||||
|
| 'isDuplicate'
|
||||||
| 'isFieldDuplicate'
|
| 'isFieldDuplicate'
|
||||||
|
| 'isHidden'
|
||||||
| 'isFieldHidden'
|
| 'isFieldHidden'
|
||||||
| 'locale'
|
| 'locale'
|
||||||
| 'path'
|
| 'path'
|
||||||
@ -114,7 +116,9 @@ const ListItem: FC<ListItemProps> = ({
|
|||||||
field,
|
field,
|
||||||
fieldsErrors,
|
fieldsErrors,
|
||||||
submitted,
|
submitted,
|
||||||
|
isDuplicate,
|
||||||
isFieldDuplicate,
|
isFieldDuplicate,
|
||||||
|
isHidden,
|
||||||
isFieldHidden,
|
isFieldHidden,
|
||||||
locale,
|
locale,
|
||||||
path,
|
path,
|
||||||
@ -197,9 +201,6 @@ const ListItem: FC<ListItemProps> = ({
|
|||||||
[collapsed],
|
[collapsed],
|
||||||
);
|
);
|
||||||
|
|
||||||
const isDuplicate = isFieldDuplicate && isFieldDuplicate(field);
|
|
||||||
const isHidden = isFieldHidden && isFieldHidden(field);
|
|
||||||
|
|
||||||
const finalValue = useMemo(() => {
|
const finalValue = useMemo(() => {
|
||||||
if (field.fields && field.fields.length === 1) {
|
if (field.fields && field.fields.length === 1) {
|
||||||
return {
|
return {
|
||||||
@ -232,8 +233,9 @@ const ListItem: FC<ListItemProps> = ({
|
|||||||
submitted={submitted}
|
submitted={submitted}
|
||||||
parentPath={path}
|
parentPath={path}
|
||||||
isDisabled={isDuplicate}
|
isDisabled={isDuplicate}
|
||||||
isHidden={isHidden}
|
isParentDuplicate={isDuplicate}
|
||||||
isFieldDuplicate={isFieldDuplicate}
|
isFieldDuplicate={isFieldDuplicate}
|
||||||
|
isParentHidden={isHidden}
|
||||||
isFieldHidden={isFieldHidden}
|
isFieldHidden={isFieldHidden}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
@ -39,9 +39,14 @@ export interface WithMarkdownControlProps {
|
|||||||
|
|
||||||
const withMarkdownControl = ({ useMdx }: WithMarkdownControlProps) => {
|
const withMarkdownControl = ({ useMdx }: WithMarkdownControlProps) => {
|
||||||
const MarkdownControl: FC<WidgetControlProps<string, MarkdownField>> = controlProps => {
|
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 [hasFocus, setHasFocus] = useState(false);
|
||||||
const debouncedFocus = useDebounce(hasFocus, 150);
|
const debouncedFocus = useDebounce(hasFocus, 150);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import TextField from '@mui/material/TextField';
|
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 { FieldError, NumberField, WidgetControlProps } from '@staticcms/core/interface';
|
||||||
import type { ChangeEvent, FC } from 'react';
|
import type { ChangeEvent, FC } from 'react';
|
||||||
@ -62,10 +62,15 @@ const NumberControl: FC<WidgetControlProps<string | number, NumberField>> = ({
|
|||||||
label,
|
label,
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
}) => {
|
}) => {
|
||||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||||
|
const internalValue = useMemo(
|
||||||
|
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||||
|
[internalRawValue, isDuplicate, value],
|
||||||
|
);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
@ -53,7 +53,9 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
|||||||
fieldsErrors,
|
fieldsErrors,
|
||||||
submitted,
|
submitted,
|
||||||
forList,
|
forList,
|
||||||
|
isDuplicate,
|
||||||
isFieldDuplicate,
|
isFieldDuplicate,
|
||||||
|
isHidden,
|
||||||
isFieldHidden,
|
isFieldHidden,
|
||||||
locale,
|
locale,
|
||||||
path,
|
path,
|
||||||
@ -96,9 +98,6 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
|||||||
parentPath = splitPath.join('.');
|
parentPath = splitPath.join('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const isDuplicate = isFieldDuplicate && isFieldDuplicate(field);
|
|
||||||
const isHidden = isFieldHidden && isFieldHidden(field);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditorControl
|
<EditorControl
|
||||||
key={index}
|
key={index}
|
||||||
@ -109,8 +108,9 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
|||||||
submitted={submitted}
|
submitted={submitted}
|
||||||
parentPath={parentPath}
|
parentPath={parentPath}
|
||||||
isDisabled={isDuplicate}
|
isDisabled={isDuplicate}
|
||||||
isHidden={isHidden}
|
isParentDuplicate={isDuplicate}
|
||||||
isFieldDuplicate={isFieldDuplicate}
|
isFieldDuplicate={isFieldDuplicate}
|
||||||
|
isParentHidden={isHidden}
|
||||||
isFieldHidden={isFieldHidden}
|
isFieldHidden={isFieldHidden}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
@ -122,8 +122,10 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
|
|||||||
fieldsErrors,
|
fieldsErrors,
|
||||||
forList,
|
forList,
|
||||||
i18n,
|
i18n,
|
||||||
|
isDuplicate,
|
||||||
isFieldDuplicate,
|
isFieldDuplicate,
|
||||||
isFieldHidden,
|
isFieldHidden,
|
||||||
|
isHidden,
|
||||||
locale,
|
locale,
|
||||||
multiFields,
|
multiFields,
|
||||||
path,
|
path,
|
||||||
|
@ -118,13 +118,18 @@ function getSelectedValue(
|
|||||||
const RelationControl: FC<WidgetControlProps<string | string[], RelationField>> = ({
|
const RelationControl: FC<WidgetControlProps<string | string[], RelationField>> = ({
|
||||||
value,
|
value,
|
||||||
field,
|
field,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
config,
|
config,
|
||||||
locale,
|
locale,
|
||||||
label,
|
label,
|
||||||
hasErrors,
|
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 [initialOptions, setInitialOptions] = useState<HitOption[]>([]);
|
||||||
|
|
||||||
const searchCollectionSelector = useMemo(
|
const searchCollectionSelector = useMemo(
|
||||||
|
@ -31,9 +31,14 @@ const SelectControl: FC<WidgetControlProps<string | number | (string | number)[]
|
|||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
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 fieldOptions: (string | number | Option)[] = useMemo(() => field.options, [field.options]);
|
||||||
const isMultiple = useMemo(() => field.multiple ?? false, [field.multiple]);
|
const isMultiple = useMemo(() => field.multiple ?? false, [field.multiple]);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import TextField from '@mui/material/TextField';
|
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 { StringOrTextField, WidgetControlProps } from '@staticcms/core/interface';
|
||||||
import type { ChangeEvent, FC } from 'react';
|
import type { ChangeEvent, FC } from 'react';
|
||||||
@ -7,10 +7,15 @@ import type { ChangeEvent, FC } from 'react';
|
|||||||
const StringControl: FC<WidgetControlProps<string, StringOrTextField>> = ({
|
const StringControl: FC<WidgetControlProps<string, StringOrTextField>> = ({
|
||||||
value,
|
value,
|
||||||
label,
|
label,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
}) => {
|
}) => {
|
||||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||||
|
const internalValue = useMemo(
|
||||||
|
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||||
|
[internalRawValue, isDuplicate, value],
|
||||||
|
);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import TextField from '@mui/material/TextField';
|
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 { StringOrTextField, WidgetControlProps } from '@staticcms/core/interface';
|
||||||
import type { ChangeEvent, FC } from 'react';
|
import type { ChangeEvent, FC } from 'react';
|
||||||
@ -7,10 +7,15 @@ import type { ChangeEvent, FC } from 'react';
|
|||||||
const TextControl: FC<WidgetControlProps<string, StringOrTextField>> = ({
|
const TextControl: FC<WidgetControlProps<string, StringOrTextField>> = ({
|
||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
|
isDuplicate,
|
||||||
onChange,
|
onChange,
|
||||||
hasErrors,
|
hasErrors,
|
||||||
}) => {
|
}) => {
|
||||||
const [internalValue, setInternalValue] = useState(value ?? '');
|
const [internalRawValue, setInternalValue] = useState(value ?? '');
|
||||||
|
const internalValue = useMemo(
|
||||||
|
() => (isDuplicate ? value ?? '' : internalRawValue),
|
||||||
|
[internalRawValue, isDuplicate, value],
|
||||||
|
);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
(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 |
|
| fieldsErrors | object | Key/value object of field names mapping to validation errors |
|
||||||
| isDisabled | boolean | Specifies if the widget control should be disabled |
|
| isDisabled | boolean | Specifies if the widget control should be disabled |
|
||||||
| submitted | boolean | Specifies if a save attempt has been made in the editor session |
|
| 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 |
|
| forList | boolean | Specifies if the widget is within a `list` widget |
|
||||||
| isFieldDuplicate | function | Function that given a field configuration, returns if that field is a duplicate |
|
| isDuplicate | function | Specifies if that field is an i18n duplicate |
|
||||||
| isFieldHidden | function | Function that given a field configuration, returns if that field is hidden |
|
| isFieldDuplicate | function | **Deprecated** Function that given a field configuration, returns if that field is a duplicate |
|
||||||
| getAsset | Async function | __Deprecated__ Function that given a url returns (as a promise) a loaded asset |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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) |
|
| 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) |
|
| 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 |
|
| 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
|
### Options
|
||||||
|
|
||||||
@ -167,9 +169,12 @@ import CMS from '@staticcms/core';
|
|||||||
const CategoriesControl = ({ label, value, field, onChange }) => {
|
const CategoriesControl = ({ label, value, field, onChange }) => {
|
||||||
const separator = useMemo(() => field.separator ?? ', ', [field.separator]);
|
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()));
|
onChange(e.target.value.split(separator).map(e => e.trim()));
|
||||||
}, [separator, onChange]);
|
},
|
||||||
|
[separator, onChange],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -178,7 +183,8 @@ const CategoriesControl = ({ label, value, field, onChange }) => {
|
|||||||
id="inputId"
|
id="inputId"
|
||||||
type="text"
|
type="text"
|
||||||
value={value ? value.join(separator) : ''}
|
value={value ? value.join(separator) : ''}
|
||||||
onChange={handleChange} />
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -208,15 +214,23 @@ import CMS from '@staticcms/core';
|
|||||||
import type { WidgetControlProps, WidgetPreviewProps } from '@staticcms/core';
|
import type { WidgetControlProps, WidgetPreviewProps } from '@staticcms/core';
|
||||||
|
|
||||||
interface CategoriesField {
|
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 separator = useMemo(() => field.separator ?? ', ', [field.separator]);
|
||||||
|
|
||||||
const handleChange = useCallback((e) => {
|
const handleChange = useCallback(
|
||||||
|
e => {
|
||||||
onChange(e.target.value.split(separator).map(e => e.trim()));
|
onChange(e.target.value.split(separator).map(e => e.trim()));
|
||||||
}, [separator, onChange]);
|
},
|
||||||
|
[separator, onChange],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -225,7 +239,8 @@ const CategoriesControl = ({ label, value, field, onChange }: WidgetControlProps
|
|||||||
id="inputId"
|
id="inputId"
|
||||||
type="text"
|
type="text"
|
||||||
value={value ? value.join(separator) : ''}
|
value={value ? value.join(separator) : ''}
|
||||||
onChange={handleChange} />
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -367,7 +382,7 @@ const FileControl = ({ collection, field, value, entry, onChange }) => {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
h('button', { type: 'button', onClick: handleOpenMediaLibrary }, 'Upload'),
|
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