diff --git a/package.json b/package.json index c47ae45f1..50c0e8a02 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,6 @@ "@babel/preset-typescript": "^7.12.1", "@babel/register": "^7.11.5", "@date-io/date-fns": "^2.10.6", - "@faceless-ui/collapsibles": "^1.0.0", "@faceless-ui/modal": "^1.1.7", "@faceless-ui/scroll-info": "^1.2.3", "@faceless-ui/window-info": "^2.0.2", diff --git a/src/admin/components/elements/ArrayAction/index.scss b/src/admin/components/elements/ArrayAction/index.scss new file mode 100644 index 000000000..c7682aced --- /dev/null +++ b/src/admin/components/elements/ArrayAction/index.scss @@ -0,0 +1,54 @@ +@import '../../../scss/styles.scss'; + +.array-actions { + &__button { + @extend %btn-reset; + cursor: pointer; + border-radius: 100px; + + &:hover { + background: var(--theme-elevation-0); + } + } + + &.popup--active .array-actions__button { + background: var(--theme-elevation-0); + } + + &__button, + &__action { + @extend %btn-reset; + cursor: pointer; + } + + &__actions { + list-style: none; + margin: 0; + padding: 0; + } + + &__action { + @extend %btn-reset; + display: block; + + svg { + position: relative; + top: -1px; + margin-right: base(.25); + + .stroke { + stroke-width: 1px; + } + } + + &:hover { + opacity: .7; + } + } + + &__move-up { + svg { + transform: rotate(180deg); + } + } +} diff --git a/src/admin/components/elements/ArrayAction/index.tsx b/src/admin/components/elements/ArrayAction/index.tsx new file mode 100644 index 000000000..e2d911864 --- /dev/null +++ b/src/admin/components/elements/ArrayAction/index.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import Popup from '../Popup'; +import More from '../../icons/More'; +import Chevron from '../../icons/Chevron'; +import { Props } from './types'; +import Plus from '../../icons/Plus'; +import X from '../../icons/X'; +import Copy from '../../icons/Copy'; + +import './index.scss'; + +const baseClass = 'array-actions'; + +export const ArrayAction: React.FC = ({ + moveRow, + index, + rowCount, + addRow, + duplicateRow, + removeRow, +}) => { + return ( + } + render={({ close }) => { + return ( + + {index !== 0 && ( + + )} + {index < rowCount - 1 && ( + + )} + + + + + ); + }} + /> + ); +}; diff --git a/src/admin/components/elements/ArrayAction/types.ts b/src/admin/components/elements/ArrayAction/types.ts new file mode 100644 index 000000000..540cc9b8d --- /dev/null +++ b/src/admin/components/elements/ArrayAction/types.ts @@ -0,0 +1,8 @@ +export type Props = { + addRow: (current: number) => void + duplicateRow: (current: number) => void + removeRow: (index: number) => void + moveRow: (from: number, to: number) => void + index: number + rowCount: number +} diff --git a/src/admin/components/elements/Collapsible/index.scss b/src/admin/components/elements/Collapsible/index.scss index 0cba40597..cd150286c 100644 --- a/src/admin/components/elements/Collapsible/index.scss +++ b/src/admin/components/elements/Collapsible/index.scss @@ -1,6 +1,9 @@ @import '../../../scss/styles.scss'; .collapsible { + --toggle-pad-h: #{base(.75)}; + --toggle-pad-v: #{base(.5)}; + border: 1px solid var(--theme-elevation-200); border-radius: $style-radius-m; @@ -8,20 +11,42 @@ border: 1px solid var(--theme-elevation-300); } + &__toggle-wrap { + position: relative; + } + + &--hovered { + .collapsible__drag { + opacity: 1; + } + + .collapsible__toggle { + background: var(--theme-elevation-100); + } + } + + &__drag { + opacity: .5; + position: absolute; + z-index: 1; + top: var(--toggle-pad-v); + left: base(.5); + } + &__toggle { @extend %btn-reset; + @extend %body; + text-align: left; cursor: pointer; background: var(--theme-elevation-50); border-top-right-radius: $style-radius-s; border-top-left-radius: $style-radius-s; width: 100%; - display: flex; - align-items: center; - padding: base(.5) base(1); + padding: var(--toggle-pad-v) var(--toggle-pad-h); + } - &:hover { - background: var(--theme-elevation-100); - } + &__toggle--has-drag-handle { + padding-left: base(1.5); } &--collapsed { @@ -35,12 +60,26 @@ } } + &__actions-wrap { + position: absolute; + right: var(--toggle-pad-h); + top: var(--toggle-pad-v); + pointer-events: none; + display: flex; + } + + &__actions { + pointer-events: all; + } + &__indicator { - margin: 0 0 0 auto; transform: rotate(.5turn); } &__content { + background-color: var(--theme-elevation-0); + border-bottom-left-radius: $style-radius-s; + border-bottom-right-radius: $style-radius-s; padding: $baseline; } diff --git a/src/admin/components/elements/Collapsible/index.tsx b/src/admin/components/elements/Collapsible/index.tsx index 7f911bb91..30ab38545 100644 --- a/src/admin/components/elements/Collapsible/index.tsx +++ b/src/admin/components/elements/Collapsible/index.tsx @@ -3,39 +3,75 @@ import AnimateHeight from 'react-animate-height'; import { Props } from './types'; import { CollapsibleProvider, useCollapsible } from './provider'; import Chevron from '../../icons/Chevron'; +import DragHandle from '../../icons/Drag'; import './index.scss'; const baseClass = 'collapsible'; -export const Collapsible: React.FC = ({ children, onToggle, className, header, initCollapsed }) => { - const [collapsed, setCollapsed] = useState(Boolean(initCollapsed)); +export const Collapsible: React.FC = ({ + children, + collapsed: collapsedFromProps, + onToggle, + className, + header, + initCollapsed, + dragHandleProps, + actions, +}) => { + const [collapsedLocal, setCollapsedLocal] = useState(Boolean(initCollapsed)); + const [hovered, setHovered] = useState(false); const isNested = useCollapsible(); + const collapsed = typeof collapsedFromProps === 'boolean' ? collapsedFromProps : collapsedLocal; + return (
- + +
+ {actions && ( +
+ {actions} +
+ )} + +
+
void initCollapsed?: boolean + dragHandleProps?: DraggableProvidedDragHandleProps } diff --git a/src/admin/components/elements/Popup/PopupButton/index.tsx b/src/admin/components/elements/Popup/PopupButton/index.tsx index 6394fdce6..7f6b81f5a 100644 --- a/src/admin/components/elements/Popup/PopupButton/index.tsx +++ b/src/admin/components/elements/Popup/PopupButton/index.tsx @@ -7,6 +7,7 @@ const baseClass = 'popup-button'; const PopupButton: React.FC = (props) => { const { + className, buttonType, button, setActive, @@ -15,6 +16,7 @@ const PopupButton: React.FC = (props) => { const classes = [ baseClass, + className, `${baseClass}--${buttonType}`, ].filter(Boolean).join(' '); diff --git a/src/admin/components/elements/Popup/PopupButton/types.ts b/src/admin/components/elements/Popup/PopupButton/types.ts index 627c3d0d0..20748ab32 100644 --- a/src/admin/components/elements/Popup/PopupButton/types.ts +++ b/src/admin/components/elements/Popup/PopupButton/types.ts @@ -1,4 +1,5 @@ export type Props = { + className?: string buttonType: 'custom' | 'default' | 'none', button: React.ReactNode, setActive: (active: boolean) => void, diff --git a/src/admin/components/elements/Popup/index.scss b/src/admin/components/elements/Popup/index.scss index 30693ed9b..7b56a7e10 100644 --- a/src/admin/components/elements/Popup/index.scss +++ b/src/admin/components/elements/Popup/index.scss @@ -43,7 +43,7 @@ &--size-small { .popup__content { - @include shadow-sm; + @include shadow-m; } &.popup--h-align-left { @@ -69,7 +69,7 @@ &--size-wide { .popup__content { - @include shadow-sm; + @include shadow-m; &:after { border: 12px solid transparent; @@ -109,11 +109,11 @@ &--h-align-center { .popup__content { left: 50%; - transform: translateX(-0%); + transform: translateX(-50%); &:after { left: 50%; - transform: translateX(-0%); + transform: translateX(-50%); } } } diff --git a/src/admin/components/elements/Popup/index.tsx b/src/admin/components/elements/Popup/index.tsx index afc9e2ee2..e7aaa503c 100644 --- a/src/admin/components/elements/Popup/index.tsx +++ b/src/admin/components/elements/Popup/index.tsx @@ -13,6 +13,7 @@ const baseClass = 'popup'; const Popup: React.FC = (props) => { const { className, + buttonClassName, render, size = 'small', color = 'light', @@ -129,21 +130,11 @@ const Popup: React.FC = (props) => { onMouseEnter={() => setActive(true)} onMouseLeave={() => setActive(false)} > - + ) : ( - + )} diff --git a/src/admin/components/elements/Popup/types.ts b/src/admin/components/elements/Popup/types.ts index f10dc240c..d68d104c4 100644 --- a/src/admin/components/elements/Popup/types.ts +++ b/src/admin/components/elements/Popup/types.ts @@ -2,6 +2,7 @@ import { CSSProperties } from 'react'; export type Props = { className?: string + buttonClassName?: string render?: (any) => React.ReactNode, children?: React.ReactNode, verticalAlign?: 'top' | 'bottom' diff --git a/src/admin/components/forms/DraggableSection/index.tsx b/src/admin/components/forms/DraggableSection/index.tsx index 568ccb9a5..0f51d6e61 100644 --- a/src/admin/components/forms/DraggableSection/index.tsx +++ b/src/admin/components/forms/DraggableSection/index.tsx @@ -76,28 +76,6 @@ const DraggableSection: React.FC = (props) => {
- {blockType === 'blocks' && ( -
- - - -
- )} - string +export type DescriptionFunction = (value?: unknown) => string export type DescriptionComponent = React.ComponentType<{ value: unknown }> @@ -8,7 +8,7 @@ export type Description = string | DescriptionFunction | DescriptionComponent export type Props = { description?: Description - value: unknown; + value?: unknown; } export function isComponent(description: Description): description is DescriptionComponent { diff --git a/src/admin/components/forms/Form/fieldReducer.ts b/src/admin/components/forms/Form/fieldReducer.ts index f05c1e982..cbd254639 100644 --- a/src/admin/components/forms/Form/fieldReducer.ts +++ b/src/admin/components/forms/Form/fieldReducer.ts @@ -1,4 +1,5 @@ import equal from 'deep-equal'; +import ObjectID from 'bson-objectid'; import { unflatten, flatten } from 'flatley'; import flattenFilters from './flattenFilters'; import getSiblingData from './getSiblingData'; @@ -109,6 +110,32 @@ function fieldReducer(state: Fields, action): Fields { return newState; } + case 'DUPLICATE_ROW': { + const { + rowIndex, path, + } = action; + + const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, path); + + const duplicate = { + ...unflattenedRows[rowIndex], + id: new ObjectID().toHexString(), + }; + + // If there are subfields + if (Object.keys(duplicate).length > 0) { + // Add new object containing subfield names to unflattenedRows array + unflattenedRows.splice(rowIndex + 1, 0, duplicate); + } + + const newState = { + ...remainingFlattenedState, + ...(flatten({ [path]: unflattenedRows }, { filters: flattenFilters })), + }; + + return newState; + } + case 'MOVE_ROW': { const { moveFromIndex, moveToIndex, path } = action; const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, path); diff --git a/src/admin/components/forms/field-types/Array/Array.tsx b/src/admin/components/forms/field-types/Array/Array.tsx index 0d35bce0f..032be7a7f 100644 --- a/src/admin/components/forms/field-types/Array/Array.tsx +++ b/src/admin/components/forms/field-types/Array/Array.tsx @@ -1,10 +1,9 @@ import React, { useCallback, useEffect, useReducer, useState } from 'react'; -import { DragDropContext, Droppable } from 'react-beautiful-dnd'; +import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; import { useAuth } from '../../../utilities/Auth'; import withCondition from '../../withCondition'; import Button from '../../../elements/Button'; -import DraggableSection from '../../DraggableSection'; -import reducer from '../rowReducer'; +import reducer, { Row } from '../rowReducer'; import { useForm } from '../../Form/context'; import buildStateFromSchema from '../../Form/buildStateFromSchema'; import useField from '../../useField'; @@ -13,14 +12,18 @@ import Error from '../../Error'; import { array } from '../../../../../fields/validations'; import Banner from '../../../elements/Banner'; import FieldDescription from '../../FieldDescription'; -import { Props } from './types'; - import { useDocumentInfo } from '../../../utilities/DocumentInfo'; import { useOperation } from '../../../utilities/OperationProvider'; +import { Collapsible } from '../../../elements/Collapsible'; +import RenderFields from '../../RenderFields'; +import { fieldAffectsData } from '../../../../../fields/config/types'; +import { Props } from './types'; +import { usePreferences } from '../../../utilities/Preferences'; +import { ArrayAction } from '../../../elements/ArrayAction'; import './index.scss'; -const baseClass = 'field-type array'; +const baseClass = 'array-field'; const ArrayFieldType: React.FC = (props) => { const { @@ -52,6 +55,8 @@ const ArrayFieldType: React.FC = (props) => { // eslint-disable-next-line react/destructuring-assignment const label = props?.label ?? props?.labels?.singular; + const { preferencesKey, preferences } = useDocumentInfo(); + const { setPreference } = usePreferences(); const [rows, dispatchRows] = useReducer(reducer, []); const formContext = useForm(); const { user } = useAuth(); @@ -81,20 +86,26 @@ const ArrayFieldType: React.FC = (props) => { condition, }); - const addRow = useCallback(async (rowIndex) => { + const addRow = useCallback(async (rowIndex: number) => { const subFieldState = await buildStateFromSchema({ fieldSchema: fields, operation, id, user, locale }); dispatchFields({ type: 'ADD_ROW', rowIndex, subFieldState, path }); dispatchRows({ type: 'ADD', rowIndex }); setValue(value as number + 1); }, [dispatchRows, dispatchFields, fields, path, setValue, value, operation, id, user, locale]); - const removeRow = useCallback((rowIndex) => { + const duplicateRow = useCallback(async (rowIndex: number) => { + dispatchFields({ type: 'DUPLICATE_ROW', rowIndex, path }); + dispatchRows({ type: 'ADD', rowIndex }); + setValue(value as number + 1); + }, [dispatchRows, dispatchFields, path, setValue, value]); + + const removeRow = useCallback((rowIndex: number) => { dispatchRows({ type: 'REMOVE', rowIndex }); dispatchFields({ type: 'REMOVE_ROW', rowIndex, path }); setValue(value as number - 1); }, [dispatchRows, dispatchFields, path, value, setValue]); - const moveRow = useCallback((moveFromIndex, moveToIndex) => { + const moveRow = useCallback((moveFromIndex: number, moveToIndex: number) => { dispatchRows({ type: 'MOVE', moveFromIndex, moveToIndex }); dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path }); }, [dispatchRows, dispatchFields, path]); @@ -106,10 +117,57 @@ const ArrayFieldType: React.FC = (props) => { moveRow(sourceIndex, destinationIndex); }, [moveRow]); + const setCollapse = useCallback(async (rowID: string, collapsed: boolean) => { + dispatchRows({ type: 'SET_COLLAPSE', id: rowID, collapsed }); + + if (preferencesKey) { + const preferencesToSet = preferences || { fields: {} }; + let newCollapsedState = preferencesToSet?.fields?.[path]?.collapsed + .filter((filterID) => (rows.find((row) => row.id === filterID))) + || []; + + if (!collapsed) { + newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID); + } else { + newCollapsedState.push(rowID); + } + + setPreference(preferencesKey, { + ...preferencesToSet, + fields: { + ...preferencesToSet?.fields || {}, + [path]: { + ...preferencesToSet?.fields?.[path], + collapsed: newCollapsedState, + }, + }, + }); + } + }, [preferencesKey, preferences, path, setPreference, rows]); + + const toggleCollapseAll = useCallback(async (collapse: boolean) => { + dispatchRows({ type: 'SET_ALL_COLLAPSED', collapse }); + + if (preferencesKey) { + const preferencesToSet = preferences || { fields: {} }; + + setPreference(preferencesKey, { + ...preferencesToSet, + fields: { + ...preferencesToSet?.fields || {}, + [path]: { + ...preferencesToSet?.fields?.[path], + collapsed: collapse ? rows.map(({ id: rowID }) => rowID) : [], + }, + }, + }); + } + }, [path, preferences, preferencesKey, rows, setPreference]); + useEffect(() => { - const data = formContext.getDataByPath(path); - dispatchRows({ type: 'SET_ALL', data: data || [] }); - }, [formContext, path]); + const data = formContext.getDataByPath(path); + dispatchRows({ type: 'SET_ALL', data: data || [], collapsedState: preferences?.fields?.[path]?.collapsed }); + }, [formContext, path, preferences]); useEffect(() => { setValue(rows?.length || 0, true); @@ -124,6 +182,7 @@ const ArrayFieldType: React.FC = (props) => { const hasMaxRows = maxRows && rows.length >= maxRows; const classes = [ + 'field-type', baseClass, className, ].filter(Boolean).join(' '); @@ -140,7 +199,29 @@ const ArrayFieldType: React.FC = (props) => { />
-

{label}

+
+

{label}

+
    +
  • + +
  • +
  • + +
  • +
+
= (props) => { {...provided.droppableProps} > {rows.length > 0 && rows.map((row, i) => ( - + draggableId={row.id} + index={i} + isDragDisabled={readOnly} + > + {(providedDrag) => ( +
+ setCollapse(row.id, collapsed)} + className={`${baseClass}__row`} + key={row.id} + dragHandleProps={providedDrag.dragHandleProps} + header={`${labels.singular} ${i + 1}`} + actions={!readOnly ? ( + + ) : undefined} + > + ({ + ...field, + path: `${path}.${i}${fieldAffectsData(field) ? `.${field.name}` : ''}`, + }))} + /> + + +
+ )} + ))} {(rows.length < minRows || (required && rows.length === 0)) && ( @@ -195,7 +303,7 @@ const ArrayFieldType: React.FC = (props) => { {(!readOnly && (!hasMaxRows)) && (
} - onToggle={onToggle} - > - ({ - ...field, - path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`, - }))} + + {label}} + onToggle={onToggle} + > + ({ + ...field, + path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`, + }))} + /> + + - + ); }; diff --git a/src/admin/components/forms/field-types/rowReducer.tsx b/src/admin/components/forms/field-types/rowReducer.tsx index 1ddd30cd6..57e4591bc 100644 --- a/src/admin/components/forms/field-types/rowReducer.tsx +++ b/src/admin/components/forms/field-types/rowReducer.tsx @@ -1,14 +1,55 @@ import ObjectID from 'bson-objectid'; -const reducer = (currentState, action) => { - const { - type, rowIndex, moveFromIndex, moveToIndex, data, blockType, collapsedState, collapsed, id, - } = action; +export type Row = { + id: string + collapsed?: boolean + blockType?: string +} +type SET_ALL = { + type: 'SET_ALL' + data: { id?: string, blockType?: string }[] + collapsedState?: string[] + blockType?: string +} + +type SET_COLLAPSE = { + type: 'SET_COLLAPSE' + id: string + collapsed: boolean +} + +type SET_ALL_COLLAPSED = { + type: 'SET_ALL_COLLAPSED' + collapse: boolean +} + +type ADD = { + type: 'ADD' + rowIndex: number + blockType?: string +} + +type REMOVE = { + type: 'REMOVE' + rowIndex: number +} + +type MOVE = { + type: 'MOVE' + moveFromIndex: number + moveToIndex: number +} + +type Action = SET_ALL | SET_COLLAPSE | SET_ALL_COLLAPSED | ADD | REMOVE | MOVE; + +const reducer = (currentState: Row[], action: Action): Row[] => { const stateCopy = [...currentState]; - switch (type) { + switch (action.type) { case 'SET_ALL': { + const { data, collapsedState } = action; + if (Array.isArray(data)) { return data.map((dataRow, i) => { const row = { @@ -25,6 +66,8 @@ const reducer = (currentState, action) => { } case 'SET_COLLAPSE': { + const { collapsed, id } = action; + const matchedRowIndex = stateCopy.findIndex(({ id: rowID }) => rowID === id); if (matchedRowIndex > -1 && stateCopy[matchedRowIndex]) { @@ -34,10 +77,25 @@ const reducer = (currentState, action) => { return stateCopy; } + case 'SET_ALL_COLLAPSED': { + const { collapse } = action; + + const newState = stateCopy.map((row) => ({ + ...row, + collapsed: collapse, + })); + + console.log(newState); + + return newState; + } + case 'ADD': { + const { rowIndex, blockType } = action; + const newRow = { id: new ObjectID().toHexString(), - open: true, + collapsed: false, blockType: undefined, }; @@ -48,11 +106,14 @@ const reducer = (currentState, action) => { return stateCopy; } - case 'REMOVE': + case 'REMOVE': { + const { rowIndex } = action; stateCopy.splice(rowIndex, 1); return stateCopy; + } case 'MOVE': { + const { moveFromIndex, moveToIndex } = action; const movingRowState = { ...stateCopy[moveFromIndex] }; stateCopy.splice(moveFromIndex, 1); stateCopy.splice(moveToIndex, 0, movingRowState); diff --git a/src/admin/components/icons/Drag/index.scss b/src/admin/components/icons/Drag/index.scss new file mode 100644 index 000000000..fdb987066 --- /dev/null +++ b/src/admin/components/icons/Drag/index.scss @@ -0,0 +1,10 @@ +@import '../../../scss/styles'; + +.icon--drag-handle { + height: $baseline; + width: $baseline; + + .fill { + fill: var(--theme-elevation-800); + } +} diff --git a/src/admin/components/icons/Drag/index.tsx b/src/admin/components/icons/Drag/index.tsx new file mode 100644 index 000000000..5b597f319 --- /dev/null +++ b/src/admin/components/icons/Drag/index.tsx @@ -0,0 +1,53 @@ +import React from 'react'; + +import './index.scss'; + +const DragHandle: React.FC<{ className?: string }> = ({ className }) => ( + + + + + + + + +); + +export default DragHandle; diff --git a/src/admin/components/icons/More/index.scss b/src/admin/components/icons/More/index.scss new file mode 100644 index 000000000..1275eb44b --- /dev/null +++ b/src/admin/components/icons/More/index.scss @@ -0,0 +1,10 @@ +@import '../../../scss/styles'; + +.icon--more { + height: $baseline; + width: $baseline; + + .fill { + fill: var(--theme-elevation-800); + } +} diff --git a/src/admin/components/icons/More/index.tsx b/src/admin/components/icons/More/index.tsx new file mode 100644 index 000000000..057bd64a7 --- /dev/null +++ b/src/admin/components/icons/More/index.tsx @@ -0,0 +1,35 @@ +import React from 'react'; + +import './index.scss'; + +const DragHandle: React.FC<{ className?: string }> = ({ className }) => ( + + + + + +); + +export default DragHandle; diff --git a/src/admin/components/views/Account/index.tsx b/src/admin/components/views/Account/index.tsx index 63eafe764..3fca07099 100644 --- a/src/admin/components/views/Account/index.tsx +++ b/src/admin/components/views/Account/index.tsx @@ -18,7 +18,7 @@ const AccountView: React.FC = () => { const { setStepNav } = useStepNav(); const { user, permissions } = useAuth(); const [initialState, setInitialState] = useState({}); - const { id } = useDocumentInfo(); + const { id, preferences } = useDocumentInfo(); const { serverURL, @@ -44,7 +44,7 @@ const AccountView: React.FC = () => { const collectionPermissions = permissions?.collections?.[adminUser]; - const [{ data, isLoading }] = usePayloadAPI( + const [{ data, isLoading: isLoadingDocument }] = usePayloadAPI( `${serverURL}${api}/${collection?.slug}/${user?.id}?depth=0`, { initialParams: { 'fallback-locale': 'null' } }, ); @@ -85,7 +85,7 @@ const AccountView: React.FC = () => { hasSavePermission, initialState, apiURL, - isLoading, + isLoading: isLoadingDocument || !preferences, }} /> diff --git a/src/admin/components/views/Global/index.tsx b/src/admin/components/views/Global/index.tsx index 8ab28945d..d5aaba65b 100644 --- a/src/admin/components/views/Global/index.tsx +++ b/src/admin/components/views/Global/index.tsx @@ -20,7 +20,7 @@ const GlobalView: React.FC = (props) => { const { setStepNav } = useStepNav(); const { permissions, user } = useAuth(); const [initialState, setInitialState] = useState({}); - const { getVersions } = useDocumentInfo(); + const { getVersions, preferences } = useDocumentInfo(); const { serverURL, @@ -50,7 +50,7 @@ const GlobalView: React.FC = (props) => { setInitialState(state); }, [getVersions, fields, user, locale]); - const [{ data, isLoading }] = usePayloadAPI( + const [{ data, isLoading: isLoadingDocument }] = usePayloadAPI( `${serverURL}${api}/globals/${slug}`, { initialParams: { 'fallback-locale': 'null', depth: 0, draft: 'true' } }, ); @@ -82,7 +82,7 @@ const GlobalView: React.FC = (props) => { DefaultComponent={DefaultGlobal} CustomComponent={CustomEdit} componentProps={{ - isLoading, + isLoading: isLoadingDocument || !preferences, data: dataToRender, permissions: globalPermissions, initialState, diff --git a/src/admin/components/views/collections/Edit/index.tsx b/src/admin/components/views/collections/Edit/index.tsx index 0f9b05ed6..b3a008bc9 100644 --- a/src/admin/components/views/collections/Edit/index.tsx +++ b/src/admin/components/views/collections/Edit/index.tsx @@ -44,7 +44,7 @@ const EditView: React.FC = (props) => { const { setStepNav } = useStepNav(); const [initialState, setInitialState] = useState({}); const { permissions, user } = useAuth(); - const { getVersions } = useDocumentInfo(); + const { getVersions, preferences } = useDocumentInfo(); const onSave = useCallback(async (json: any) => { getVersions(); @@ -56,7 +56,7 @@ const EditView: React.FC = (props) => { } }, [admin, collection, history, isEditing, getVersions, user, id, locale]); - const [{ data, isLoading, isError }] = usePayloadAPI( + const [{ data, isLoading: isLoadingDocument, isError }] = usePayloadAPI( (isEditing ? `${serverURL}${api}/${slug}/${id}` : null), { initialParams: { 'fallback-locale': 'null', depth: 0, draft: 'true' } }, ); @@ -97,7 +97,7 @@ const EditView: React.FC = (props) => { }, [setStepNav, isEditing, pluralLabel, dataToRender, slug, useAsTitle, admin]); useEffect(() => { - if (isLoading) { + if (isLoadingDocument) { return; } const awaitInitialState = async () => { @@ -106,7 +106,7 @@ const EditView: React.FC = (props) => { }; awaitInitialState(); - }, [dataToRender, fields, isEditing, id, user, locale, isLoading]); + }, [dataToRender, fields, isEditing, id, user, locale, isLoadingDocument]); if (isError) { return ( @@ -125,7 +125,7 @@ const EditView: React.FC = (props) => { DefaultComponent={DefaultEdit} CustomComponent={CustomEdit} componentProps={{ - isLoading, + isLoading: isLoadingDocument || !preferences, data: dataToRender, collection, permissions: collectionPermissions, diff --git a/src/admin/scss/toastify.scss b/src/admin/scss/toastify.scss index 7c22fd7a2..9f4a35a9f 100644 --- a/src/admin/scss/toastify.scss +++ b/src/admin/scss/toastify.scss @@ -25,16 +25,16 @@ } .Toastify__toast--success { - color: var(--color-success-900); + color: var(--color-success-100); background: var(--color-success-500); .Toastify__progress-bar { - background-color: var(--color-success-900); + background-color: var(--color-success-100); } } .Toastify__close-button--success { - color: var(--color-success-900); + color: var(--color-success-100); } .Toastify__toast--error { diff --git a/src/admin/scss/vars.scss b/src/admin/scss/vars.scss index 6030d6359..1526d71b1 100644 --- a/src/admin/scss/vars.scss +++ b/src/admin/scss/vars.scss @@ -70,7 +70,11 @@ $focus-box-shadow: 0 0 0 $style-stroke-width-m var(--color-success-500); ////////////////////////////// @mixin shadow-sm { - box-shadow: 0 2px 3px 0 rgba(0, 2, 4, 0.1), 0 6px 4px -4px rgba(0, 2, 4, 0.02); + box-shadow: 0 2px 3px 0 rgba(0, 2, 4, 0.05), 0 10px 4px -8px rgba(0, 2, 4, 0.02); +} + +@mixin shadow-m { + box-shadow: 0 0 30px 0 rgb(0 2 4 / 12%), 0 30px 25px -8px rgb(0 2 4 / 10%); } @mixin shadow-lg { diff --git a/test/e2e/fields/config.ts b/test/e2e/fields/config.ts index 948cdf69d..1b3c4eed6 100644 --- a/test/e2e/fields/config.ts +++ b/test/e2e/fields/config.ts @@ -8,7 +8,7 @@ export default buildConfig({ slug: 'array-fields', fields: [ { - name: 'array', + name: 'items', type: 'array', required: true, fields: [ @@ -59,6 +59,9 @@ export default buildConfig({ { label: 'Collapsible Field', type: 'collapsible', + admin: { + description: 'This is a collapsible field.', + }, fields: [ { name: 'text', diff --git a/test/e2e/fields/shared.ts b/test/e2e/fields/shared.ts index 08f1b016b..711a7a2a3 100644 --- a/test/e2e/fields/shared.ts +++ b/test/e2e/fields/shared.ts @@ -1,5 +1,5 @@ export const arrayDoc = { - array: [ + items: [ { text: 'first row', }, diff --git a/yarn.lock b/yarn.lock index 5447c52be..541d516e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1265,14 +1265,6 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== -"@faceless-ui/collapsibles@^1.0.0": - version "1.1.1" - resolved "https://registry.npmjs.org/@faceless-ui/collapsibles/-/collapsibles-1.1.1.tgz#89b86e11eceae55ed87caa4de9d395f7b082a938" - integrity sha512-7tU5CjXUnW7bKthpMgNKs5TirTb+DQVFASnstqlpe+gXl8W76Rq4Z9m6nS3PnnG2B5h9aqtUVaNgroLc1J+i/w== - dependencies: - react-animate-height "^2.0.16" - react-transition-group "^4.4.2" - "@faceless-ui/modal@^1.1.7": version "1.2.0" resolved "https://registry.npmjs.org/@faceless-ui/modal/-/modal-1.2.0.tgz#0ca43e480f83d307dcd84c033fbc82c0619f5d8c" @@ -10322,7 +10314,7 @@ rc@1.2.8, rc@^1.2.7, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-animate-height@^2.0.16, react-animate-height@^2.0.20: +react-animate-height@^2.0.20: version "2.1.2" resolved "https://registry.npmjs.org/react-animate-height/-/react-animate-height-2.1.2.tgz#9b450fc64d46f10f5e07da8d0d5e2c47b9f15030" integrity sha512-A9jfz/4CTdsIsE7WCQtO9UkOpMBcBRh8LxyHl2eoZz1ki02jpyUL5xt58gabd0CyeLQ8fRyQ+s2lyV2Ufu8Owg==