Skip to content
This repository was archived by the owner on Sep 9, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/core/dev-test/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,27 @@ collections:
name: thumb
widget: image
required: false
- label: Collapsed, optional with required children
name: collapsed_optional_with_required_children
widget: object
required: false
collapsed: true
fields:
- name: layout
widget: hidden
default: post
- label: Number of posts on frontpage
name: front_limit
widget: number
required: true
- label: Author
name: author
widget: string
required: true
- label: Thumbnail
name: thumb
widget: image
required: true
- name: relation
label: Relation
file: _widgets/relation.json
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/reducers/selectors/entryDraft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import { getDataPath } from '@staticcms/core/lib/i18n';
import type { I18nSettings } from '@staticcms/core/interface';
import type { RootState } from '@staticcms/core/store';

export const getEntryDataPath = (i18n: I18nSettings | undefined) => {
return (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
};

export const selectFieldErrors =
(path: string, i18n: I18nSettings | undefined) => (state: RootState) => {
const dataPath = (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
const dataPath = getEntryDataPath(i18n);
const fullPath = `${dataPath.join('.')}.${path}`;
return state.entryDraft.fieldsErrors[fullPath] ?? [];
};
Expand Down
16 changes: 13 additions & 3 deletions packages/core/src/widgets/object/ObjectControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ObjectWidgetTopBar from '@staticcms/core/components/UI/ObjectWidgetTopBar
import Outline from '@staticcms/core/components/UI/Outline';
import { transientOptions } from '@staticcms/core/lib';
import { compileStringTemplate } from '@staticcms/core/lib/widgets/stringTemplate';
import { getEntryDataPath } from '@staticcms/core/reducers/selectors/entryDraft';

import type { ObjectField, ObjectValue, WidgetControlProps } from '@staticcms/core/interface';
import type { FC } from 'react';
Expand Down Expand Up @@ -61,7 +62,7 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
hasErrors,
value = {},
}) => {
const [collapsed, setCollapsed] = useState(false);
const [collapsed, setCollapsed] = useState(field.collapsed ?? false);

const handleCollapseToggle = useCallback(() => {
setCollapsed(!collapsed);
Expand All @@ -75,6 +76,13 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({

const multiFields = useMemo(() => field.fields, [field.fields]);

const childHasError = useMemo(() => {
const dataPath = getEntryDataPath(i18n);
const fullPath = `${dataPath}.${path}`;

return Boolean(Object.keys(fieldsErrors).find(key => key.startsWith(fullPath)));
}, [fieldsErrors, i18n, path]);

const renderedField = useMemo(() => {
return (
multiFields?.map((field, index) => {
Expand Down Expand Up @@ -132,15 +140,17 @@ const ObjectControl: FC<WidgetControlProps<ObjectValue, ObjectField>> = ({
collapsed={collapsed}
onCollapseToggle={handleCollapseToggle}
heading={objectLabel}
hasError={hasErrors}
hasError={hasErrors || childHasError}
t={t}
testId="object-title"
/>
)}
<StyledFieldsBox $collapsed={collapsed} key="object-control-fields">
{renderedField}
</StyledFieldsBox>
{forList ? null : <Outline key="object-control-outline" hasError={hasErrors} />}
{forList ? null : (
<Outline key="object-control-outline" hasError={hasErrors || childHasError} />
)}
</StyledObjectControlWrapper>
);
}
Expand Down