From c6013c39043cc7bf9e8ff39551662c25e8d744c8 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Tue, 29 Nov 2022 17:40:05 -0500 Subject: [PATCH 01/31] feat: builds Drawer component --- .../components/elements/Drawer/index.scss | 78 +++++++++++++++++++ .../components/elements/Drawer/index.tsx | 71 +++++++++++++++++ src/admin/components/elements/Drawer/types.ts | 4 + 3 files changed, 153 insertions(+) create mode 100644 src/admin/components/elements/Drawer/index.scss create mode 100644 src/admin/components/elements/Drawer/index.tsx create mode 100644 src/admin/components/elements/Drawer/types.ts diff --git a/src/admin/components/elements/Drawer/index.scss b/src/admin/components/elements/Drawer/index.scss new file mode 100644 index 0000000000..17d6b7f63d --- /dev/null +++ b/src/admin/components/elements/Drawer/index.scss @@ -0,0 +1,78 @@ +@import '../../../scss/styles.scss'; + +.drawer { + display: flex; + overflow: hidden; + position: fixed; + height: 100vh; + + &__blur-bg { + @include blur-bg(); + position: absolute; + z-index: 1; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0; + transition: all 300ms ease-out; + } + + &__content { + @include blur-bg(); + opacity: 0; + transition: all 300ms ease-out; + transform: translateX(#{base(4)}); + position: relative; + z-index: 2; + width: 100%; + } + + &__content-children { + position: relative; + z-index: 1; + } + + &--animated { + .drawer__content, + .drawer__blur-bg, + .drawer__close { + opacity: 1; + } + + .drawer__content { + transform: translateX(0); + } + } + + &__close { + @extend %btn-reset; + position: relative; + z-index: 2; + flex-shrink: 0; + text-indent: -9999px; + background: rgba(0, 0, 0, 0.08); + cursor: pointer; + opacity: 0; + transition: all 300ms ease-in-out; + transition-delay: 100ms; + + &:active, + &:focus { + outline: 0; + } + } + + + @include mid-break { + &__close { + width: base(1); + } + } +} + +html[data-theme=dark] { + .drawer__close { + background: rgba(0, 0, 0, 0.2); + } +} diff --git a/src/admin/components/elements/Drawer/index.tsx b/src/admin/components/elements/Drawer/index.tsx new file mode 100644 index 0000000000..f62a54a826 --- /dev/null +++ b/src/admin/components/elements/Drawer/index.tsx @@ -0,0 +1,71 @@ +import React, { createContext, useContext, useEffect, useState } from 'react'; +import { Modal, useModal } from '@faceless-ui/modal'; +import { useWindowInfo } from '@faceless-ui/window-info'; +import { IModalContext } from '@faceless-ui/modal/dist/ModalProvider/context'; +import { Props } from './types'; +import './index.scss'; + +const baseClass = 'drawer'; + +export const useDrawer = (): IModalContext => { + const modalContext = useModal(); + return modalContext; +}; + +export const DrawerDepthContext = createContext(1); + +export const useDrawerDepth = (): number => useContext(DrawerDepthContext); + +const baseZIndex = 100; + +const Drawer: React.FC = ({ + modalSlug, + children, +}) => { + const { toggleModal } = useModal(); + const { breakpoints: { m: midBreak } } = useWindowInfo(); + const [isAnimated, setIsAnimated] = useState(false); + const drawerDepth = useDrawerDepth(); + + useEffect(() => { + setIsAnimated(true); + }, []); + + return ( + + {drawerDepth === 1 && ( +
+ )} + + +
+
+ {children} +
+
+
+ + ); +}; + +export default Drawer; diff --git a/src/admin/components/elements/Drawer/types.ts b/src/admin/components/elements/Drawer/types.ts new file mode 100644 index 0000000000..04b28139f1 --- /dev/null +++ b/src/admin/components/elements/Drawer/types.ts @@ -0,0 +1,4 @@ +export type Props = { + modalSlug: string + children: React.ReactNode +} From f8cf4c7b6a39e9d24446de290d905c2a3c866a70 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Wed, 30 Nov 2022 13:54:45 -0500 Subject: [PATCH 02/31] chore: reconfigures drawer context --- .../components/elements/Drawer/index.scss | 14 ++- .../components/elements/Drawer/index.tsx | 105 +++++++++++------- src/admin/components/elements/Drawer/types.ts | 7 +- 3 files changed, 82 insertions(+), 44 deletions(-) diff --git a/src/admin/components/elements/Drawer/index.scss b/src/admin/components/elements/Drawer/index.scss index 17d6b7f63d..a8fc8a3a07 100644 --- a/src/admin/components/elements/Drawer/index.scss +++ b/src/admin/components/elements/Drawer/index.scss @@ -21,11 +21,11 @@ &__content { @include blur-bg(); opacity: 0; - transition: all 300ms ease-out; transform: translateX(#{base(4)}); position: relative; z-index: 2; width: 100%; + transition: all 300ms ease-out; } &__content-children { @@ -33,13 +33,18 @@ z-index: 1; } - &--animated { + &--is-open { .drawer__content, .drawer__blur-bg, .drawer__close { opacity: 1; } + .drawer__close { + transition: opacity 300ms ease-in-out; + transition-delay: 100ms; + } + .drawer__content { transform: translateX(0); } @@ -54,8 +59,9 @@ background: rgba(0, 0, 0, 0.08); cursor: pointer; opacity: 0; - transition: all 300ms ease-in-out; - transition-delay: 100ms; + will-change: opacity; + transition: none; + transition-delay: 0ms; &:active, &:focus { diff --git a/src/admin/components/elements/Drawer/index.tsx b/src/admin/components/elements/Drawer/index.tsx index f62a54a826..41a9b9f11e 100644 --- a/src/admin/components/elements/Drawer/index.tsx +++ b/src/admin/components/elements/Drawer/index.tsx @@ -1,71 +1,98 @@ -import React, { createContext, useContext, useEffect, useState } from 'react'; +import React, { createContext, useContext } from 'react'; import { Modal, useModal } from '@faceless-ui/modal'; import { useWindowInfo } from '@faceless-ui/window-info'; -import { IModalContext } from '@faceless-ui/modal/dist/ModalProvider/context'; -import { Props } from './types'; +import { Props, TogglerProps } from './types'; import './index.scss'; const baseClass = 'drawer'; -export const useDrawer = (): IModalContext => { - const modalContext = useModal(); - return modalContext; -}; - -export const DrawerDepthContext = createContext(1); +export const DrawerDepthContext = createContext(0); export const useDrawerDepth = (): number => useContext(DrawerDepthContext); -const baseZIndex = 100; +const zBase = 100; -const Drawer: React.FC = ({ - modalSlug, +const formatDrawerSlug = ({ + slug, + depth, +}: { + slug: string, + depth: number, +}) => `drawer-lvl${depth}-${slug}`; + +export const DrawerToggler: React.FC = ({ + slug, children, }) => { - const { toggleModal } = useModal(); - const { breakpoints: { m: midBreak } } = useWindowInfo(); - const [isAnimated, setIsAnimated] = useState(false); + const { openModal } = useModal(); const drawerDepth = useDrawerDepth(); - useEffect(() => { - setIsAnimated(true); - }, []); + return ( + + ); +}; + +export const Drawer: React.FC = ({ + slug, + children, +}) => { + const { toggleModal, isModalOpen } = useModal(); + const { breakpoints: { m: midBreak } } = useWindowInfo(); + const drawerDepth = useDrawerDepth(); + + const modalSlug = formatDrawerSlug({ slug, depth: drawerDepth }); + const isOpen = isModalOpen(modalSlug); return ( - {drawerDepth === 1 && ( + {drawerDepth === 0 && (
)} - - -
-
+ +
+
+ {children} -
+
- +
); }; -export default Drawer; +export type IDrawerContext = { + Drawer: React.FC, + DrawerToggler: React.FC +} + +export const DrawerContext = createContext({ + Drawer, + DrawerToggler, +}); + +export const useDrawer = (): IDrawerContext => useContext(DrawerContext); diff --git a/src/admin/components/elements/Drawer/types.ts b/src/admin/components/elements/Drawer/types.ts index 04b28139f1..10434572f7 100644 --- a/src/admin/components/elements/Drawer/types.ts +++ b/src/admin/components/elements/Drawer/types.ts @@ -1,4 +1,9 @@ export type Props = { - modalSlug: string + slug: string + children: React.ReactNode +} + +export type TogglerProps = { + slug: string children: React.ReactNode } From 2118927f4248a4969d88fad57bc0528991c23b7f Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Wed, 30 Nov 2022 15:40:46 -0500 Subject: [PATCH 03/31] feat: builds DocumentDrawer component --- .../elements/DocumentDrawer/index.scss | 32 ++++ .../elements/DocumentDrawer/index.tsx | 153 ++++++++++++++++++ .../elements/DocumentDrawer/types.ts | 14 ++ .../components/elements/Drawer/index.tsx | 6 +- src/admin/components/elements/Drawer/types.ts | 2 + 5 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 src/admin/components/elements/DocumentDrawer/index.scss create mode 100644 src/admin/components/elements/DocumentDrawer/index.tsx create mode 100644 src/admin/components/elements/DocumentDrawer/types.ts diff --git a/src/admin/components/elements/DocumentDrawer/index.scss b/src/admin/components/elements/DocumentDrawer/index.scss new file mode 100644 index 0000000000..d08065b8c8 --- /dev/null +++ b/src/admin/components/elements/DocumentDrawer/index.scss @@ -0,0 +1,32 @@ +@import '../../../scss/styles.scss'; + +.doc-drawer { + &__header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-top: base(2.5); + } + + &__header-close { + svg { + width: base(2.5); + height: base(2.5); + position: relative; + top: base(-.5); + right: base(-.75); + + .stroke { + stroke-width: .5px; + } + } + } + + @include mid-break { + &__header-close { + svg { + top: base(-.75); + } + } + } +} diff --git a/src/admin/components/elements/DocumentDrawer/index.tsx b/src/admin/components/elements/DocumentDrawer/index.tsx new file mode 100644 index 0000000000..7e0c4fe7b5 --- /dev/null +++ b/src/admin/components/elements/DocumentDrawer/index.tsx @@ -0,0 +1,153 @@ +import React, { createContext, useContext, useEffect, useState } from 'react'; +import { useModal } from '@faceless-ui/modal'; +import { useTranslation } from 'react-i18next'; +import { Redirect } from 'react-router-dom'; +import { Props, TogglerProps } from './types'; +import DefaultEdit from '../../views/collections/Edit/Default'; +import X from '../../icons/X'; +import { Fields } from '../../forms/Form/types'; +import buildStateFromSchema from '../../forms/Form/buildStateFromSchema'; +import { getTranslation } from '../../../../utilities/getTranslation'; +import { Drawer, DrawerToggler, useDrawerDepth } from '../Drawer'; +import Button from '../Button'; +import { useConfig } from '../../utilities/Config'; +import { useLocale } from '../../utilities/Locale'; +import { useAuth } from '../../utilities/Auth'; +import { DocumentInfoProvider, useDocumentInfo } from '../../utilities/DocumentInfo'; +import RenderCustomComponent from '../../utilities/RenderCustomComponent'; +import usePayloadAPI from '../../../hooks/usePayloadAPI'; +import { usePreferences } from '../../utilities/Preferences'; +import formatFields from '../../views/collections/Edit/formatFields'; +import './index.scss'; + +const baseClass = 'doc-drawer'; + +const formatDrawerSlug = ({ + collection, + id, + depth, +}: { + collection: string, + id: string, + depth: number, +}) => `doc-${collection}-${id}-lvl-${depth}`; + +export const DocumentDrawerToggler: React.FC = ({ + id, + collection, + children, +}) => { + const drawerDepth = useDrawerDepth(); + + return ( + + {children} + + ); +}; + +export const DocumentDrawer: React.FC = ({ + collection, + id, + onSave, + customHeader, +}) => { + const { serverURL, routes: { api } } = useConfig(); + const { toggleModal } = useModal(); + const locale = useLocale(); + const { permissions, user } = useAuth(); + const [initialState, setInitialState] = useState(); + const { t, i18n } = useTranslation('fields'); + const drawerDepth = useDrawerDepth(); + const config = useConfig(); + const [modalSlug] = useState(() => formatDrawerSlug({ collection, id, depth: drawerDepth })); + const { getPreference } = usePreferences(); + const { preferencesKey } = useDocumentInfo(); + + const collectionConfig = config.collections.find((col) => col.slug === collection); + const [fields] = useState(() => formatFields(collectionConfig, true)); + + const [{ data, isLoading: isLoadingDocument, isError }] = usePayloadAPI( + (id ? `${serverURL}${api}/${collection}/${id}` : null), + { initialParams: { 'fallback-locale': 'null', depth: 0, draft: 'true' } }, + ); + + useEffect(() => { + if (isLoadingDocument) { + return; + } + const awaitInitialState = async () => { + const state = await buildStateFromSchema({ fieldSchema: fields, data, user, operation: id ? 'update' : 'create', id, locale, t }); + await getPreference(preferencesKey); + setInitialState(state); + }; + + awaitInitialState(); + }, [data, fields, id, user, locale, isLoadingDocument, preferencesKey, getPreference, t]); + + const modalAction = `${serverURL}${api}/${collection}?locale=${locale}&depth=0&fallback-locale=null`; + + if (isError) { + return ( + + ); + } + + return ( + + + +

+ {!customHeader ? t(!id ? 'addNewLabel' : 'editLabel', { label: getTranslation(collectionConfig.labels.singular, i18n) }) : customHeader} +

+ +
+ ), + }} + /> + + + ); +}; + +export type IDocumentDrawerContext = { + DocumentDrawer: React.FC, + DocumentDrawerToggler: React.FC +} + +export const DocumentDrawerContext = createContext({ + DocumentDrawer, + DocumentDrawerToggler, +}); + +export const useDocumentDrawer = (): IDocumentDrawerContext => useContext(DocumentDrawerContext); diff --git a/src/admin/components/elements/DocumentDrawer/types.ts b/src/admin/components/elements/DocumentDrawer/types.ts new file mode 100644 index 0000000000..eeceb8c114 --- /dev/null +++ b/src/admin/components/elements/DocumentDrawer/types.ts @@ -0,0 +1,14 @@ +import React from 'react'; + +export type Props = { + collection: string + id?: string + onSave?: (json: Record) => void + customHeader?: React.ReactNode +} + +export type TogglerProps = { + collection: string + id?: string + children?: React.ReactNode +} diff --git a/src/admin/components/elements/Drawer/index.tsx b/src/admin/components/elements/Drawer/index.tsx index 41a9b9f11e..75ccf9b223 100644 --- a/src/admin/components/elements/Drawer/index.tsx +++ b/src/admin/components/elements/Drawer/index.tsx @@ -22,6 +22,7 @@ const formatDrawerSlug = ({ export const DrawerToggler: React.FC = ({ slug, + exactSlug, children, }) => { const { openModal } = useModal(); @@ -29,7 +30,7 @@ export const DrawerToggler: React.FC = ({ return ( -
- ), - }} - /> - + {isOpen && ( + // IMPORTANT: we must ensure that modals are not recursively rendered + // to do this, do not render the document until the modal is open + + +

+ {!customHeader ? t(!id ? 'addNewLabel' : 'editLabel', { label: getTranslation(collectionConfig.labels.singular, i18n) }) : customHeader} +

+ +
+ ), + }} + /> + + )} ); }; export type IDocumentDrawerContext = { DocumentDrawer: React.FC, - DocumentDrawerToggler: React.FC + DocumentDrawerToggler: React.FC } export const DocumentDrawerContext = createContext({ diff --git a/src/admin/components/elements/DocumentDrawer/types.ts b/src/admin/components/elements/DocumentDrawer/types.ts index eeceb8c114..4b9d620ade 100644 --- a/src/admin/components/elements/DocumentDrawer/types.ts +++ b/src/admin/components/elements/DocumentDrawer/types.ts @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { HTMLAttributes } from 'react'; export type Props = { collection: string @@ -7,8 +7,9 @@ export type Props = { customHeader?: React.ReactNode } -export type TogglerProps = { +export type DocumentTogglerProps = HTMLAttributes & { collection: string id?: string children?: React.ReactNode + className?: string } diff --git a/src/admin/components/elements/Drawer/index.tsx b/src/admin/components/elements/Drawer/index.tsx index 75ccf9b223..9fffbac1b6 100644 --- a/src/admin/components/elements/Drawer/index.tsx +++ b/src/admin/components/elements/Drawer/index.tsx @@ -24,14 +24,22 @@ export const DrawerToggler: React.FC = ({ slug, exactSlug, children, + className, + onClick, + ...rest }) => { const { openModal } = useModal(); const drawerDepth = useDrawerDepth(); return ( diff --git a/src/admin/components/elements/Drawer/types.ts b/src/admin/components/elements/Drawer/types.ts index 89becbfba6..b7b073317b 100644 --- a/src/admin/components/elements/Drawer/types.ts +++ b/src/admin/components/elements/Drawer/types.ts @@ -1,11 +1,14 @@ +import { HTMLAttributes } from 'react'; + export type Props = { slug: string exactSlug?: boolean children: React.ReactNode } -export type TogglerProps = { +export type TogglerProps = HTMLAttributes & { slug: string exactSlug?: boolean children: React.ReactNode + className?: string } From 475f147f2cab64bf79ff019a1eae9e7f18690557 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 1 Dec 2022 16:34:05 -0500 Subject: [PATCH 05/31] feat: retrofits DocumentDrawer into relationship AddNew --- .../Relationship/AddNew/Modal/index.scss | 117 --------------- .../Relationship/AddNew/Modal/index.tsx | 110 -------------- .../Relationship/AddNew/Modal/types.ts | 7 - .../Relationship/AddNew/index.scss | 24 +--- .../field-types/Relationship/AddNew/index.tsx | 136 ++++++++++-------- 5 files changed, 82 insertions(+), 312 deletions(-) delete mode 100644 src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.scss delete mode 100644 src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.tsx delete mode 100644 src/admin/components/forms/field-types/Relationship/AddNew/Modal/types.ts diff --git a/src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.scss b/src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.scss deleted file mode 100644 index a6d8b8f942..0000000000 --- a/src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.scss +++ /dev/null @@ -1,117 +0,0 @@ -@import '../../../../../../scss/styles.scss'; - -.relationship-add-new-modal { - display: flex; - overflow: hidden; - position: fixed; - height: 100vh; - - &__blur-bg { - @include blur-bg(); - position: absolute; - z-index: 1; - top: 0; - right: 0; - bottom: 0; - left: 0; - opacity: 0; - transition: all 300ms ease-out; - } - - .collection-edit { - @include blur-bg(); - transform: translateX(#{base(4)}); - opacity: 0; - transition: all 300ms ease-out; - position: relative; - z-index: 2; - } - - .collection-edit__form { - overflow: auto; - position: relative; - z-index: 1; - } - - .collection-edit__document-actions { - - &:before, - &:after { - content: none; - } - } - - &--animated { - - .collection-edit, - .relationship-add-new-modal__blur-bg, - .relationship-add-new-modal__close { - opacity: 1; - } - - .collection-edit { - transform: translateX(0); - } - } - - .collection-edit__document-actions { - margin-top: base(2.75); - } - - &__close { - @extend %btn-reset; - position: relative; - z-index: 2; - flex-shrink: 0; - text-indent: -9999px; - background: rgba(0, 0, 0, 0.08); - cursor: pointer; - opacity: 0; - transition: all 300ms ease-in-out; - transition-delay: 100ms; - - &:active, - &:focus { - outline: 0; - } - } - - &__header { - display: flex; - justify-content: space-between; - align-items: flex-start; - margin-top: base(2.5); - } - - &__header-close { - svg { - width: base(2.5); - height: base(2.5); - position: relative; - top: base(-.5); - right: base(-.75); - - .stroke { - stroke-width: .5px; - } - } - } - - @include mid-break { - &__header-close { - svg { - top: base(-.75); - } - } - - &__close { - width: base(1); - } - } -} - -html[data-theme=dark] { - .relationship-add-new-modal__close { - background: rgba(0, 0, 0, 0.2); - } -} \ No newline at end of file diff --git a/src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.tsx b/src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.tsx deleted file mode 100644 index b7fd41b6dc..0000000000 --- a/src/admin/components/forms/field-types/Relationship/AddNew/Modal/index.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Modal, useModal } from '@faceless-ui/modal'; -import { useWindowInfo } from '@faceless-ui/window-info'; -import { useTranslation } from 'react-i18next'; -import Button from '../../../../../elements/Button'; -import { Props } from './types'; -import { useAuth } from '../../../../../utilities/Auth'; -import RenderCustomComponent from '../../../../../utilities/RenderCustomComponent'; -import { useLocale } from '../../../../../utilities/Locale'; -import { useConfig } from '../../../../../utilities/Config'; -import DefaultEdit from '../../../../../views/collections/Edit/Default'; -import X from '../../../../../icons/X'; -import { Fields } from '../../../../Form/types'; -import buildStateFromSchema from '../../../../Form/buildStateFromSchema'; -import { EditDepthContext, useEditDepth } from '../../../../../utilities/EditDepth'; -import { getTranslation } from '../../../../../../../utilities/getTranslation'; -import { DocumentInfoProvider } from '../../../../../utilities/DocumentInfo'; - -import './index.scss'; - -const baseClass = 'relationship-add-new-modal'; - -export const AddNewRelationModal: React.FC = ({ modalCollection, onSave, modalSlug }) => { - const { serverURL, routes: { api } } = useConfig(); - const { toggleModal } = useModal(); - const { breakpoints: { m: midBreak } } = useWindowInfo(); - const locale = useLocale(); - const { permissions, user } = useAuth(); - const [initialState, setInitialState] = useState(); - const [isAnimated, setIsAnimated] = useState(false); - const editDepth = useEditDepth(); - const { t, i18n } = useTranslation('fields'); - - const modalAction = `${serverURL}${api}/${modalCollection.slug}?locale=${locale}&depth=0&fallback-locale=null`; - - useEffect(() => { - const buildState = async () => { - const state = await buildStateFromSchema({ fieldSchema: modalCollection.fields, data: {}, user, operation: 'create', locale, t }); - setInitialState(state); - }; - - buildState(); - }, [modalCollection, locale, user, t]); - - useEffect(() => { - setIsAnimated(true); - }, []); - - return ( - - {editDepth === 1 && ( -
- )} - - - - -

- {t('addNewLabel', { label: getTranslation(modalCollection.labels.singular, i18n) })} -

- -
- ), - }} - /> - - -
- ); -}; diff --git a/src/admin/components/forms/field-types/Relationship/AddNew/Modal/types.ts b/src/admin/components/forms/field-types/Relationship/AddNew/Modal/types.ts deleted file mode 100644 index c617447602..0000000000 --- a/src/admin/components/forms/field-types/Relationship/AddNew/Modal/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { SanitizedCollectionConfig } from '../../../../../../../collections/config/types'; - -export type Props = { - modalSlug: string - modalCollection: SanitizedCollectionConfig - onSave: (json: Record) => void -} diff --git a/src/admin/components/forms/field-types/Relationship/AddNew/index.scss b/src/admin/components/forms/field-types/Relationship/AddNew/index.scss index 58328e92b7..ea75d441b8 100644 --- a/src/admin/components/forms/field-types/Relationship/AddNew/index.scss +++ b/src/admin/components/forms/field-types/Relationship/AddNew/index.scss @@ -12,28 +12,16 @@ &__add-button { @include formInput; + position: relative; height: 100%; margin-left: -1px; display: flex; - padding: 0; - - .btn__content, - .btn__label { - display: flex; - } - - .btn__content, - .btn__label { - height: 100%; - } - - .btn__label { - padding: 0 base(.5); - align-items: center; - } + padding: 0 base(0.5); + align-items: center; + display: flex; + cursor: pointer; } - &__relations { list-style: none; margin: 0; @@ -57,4 +45,4 @@ opacity: .7; } } -} \ No newline at end of file +} diff --git a/src/admin/components/forms/field-types/Relationship/AddNew/index.tsx b/src/admin/components/forms/field-types/Relationship/AddNew/index.tsx index 56d9d26cf9..91c07ec369 100644 --- a/src/admin/components/forms/field-types/Relationship/AddNew/index.tsx +++ b/src/admin/components/forms/field-types/Relationship/AddNew/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { Fragment, useCallback, useEffect, useState } from 'react'; import { useModal } from '@faceless-ui/modal'; import { useTranslation } from 'react-i18next'; import Button from '../../../../elements/Button'; @@ -7,10 +7,11 @@ import { SanitizedCollectionConfig } from '../../../../../../collections/config/ import Popup from '../../../../elements/Popup'; import { useRelatedCollections } from './useRelatedCollections'; import { useAuth } from '../../../../utilities/Auth'; -import { AddNewRelationModal } from './Modal'; import { useEditDepth } from '../../../../utilities/EditDepth'; import Plus from '../../../../icons/Plus'; import { getTranslation } from '../../../../../../utilities/getTranslation'; +import { DocumentDrawer, DocumentDrawerToggler } from '../../../../elements/DocumentDrawer'; +import Tooltip from '../../../../elements/Tooltip'; import './index.scss'; @@ -18,30 +19,26 @@ const baseClass = 'relationship-add-new'; export const AddNewRelation: React.FC = ({ path, hasMany, relationTo, value, setValue, dispatchOptions }) => { const relatedCollections = useRelatedCollections(relationTo); - const { toggleModal, isModalOpen } = useModal(); + const { isModalOpen } = useModal(); const { permissions } = useAuth(); const [hasPermission, setHasPermission] = useState(false); - const [modalCollection, setModalCollection] = useState(); + const [selectedCollection, setSelectedCollection] = useState(); const [popupOpen, setPopupOpen] = useState(false); const editDepth = useEditDepth(); const { t, i18n } = useTranslation('fields'); + const [showTooltip, setShowTooltip] = useState(false); const modalSlug = `${path}-add-modal-depth-${editDepth}`; - const openModal = useCallback(async (collection: SanitizedCollectionConfig) => { - setModalCollection(collection); - toggleModal(modalSlug); - }, [toggleModal, modalSlug]); - const onSave = useCallback((json) => { const newValue = Array.isArray(relationTo) ? { - relationTo: modalCollection.slug, + relationTo: selectedCollection.slug, value: json.doc.id, } : json.doc.id; dispatchOptions({ type: 'ADD', - collection: modalCollection, + collection: selectedCollection, docs: [ json.doc, ], @@ -55,9 +52,9 @@ export const AddNewRelation: React.FC = ({ path, hasMany, relationTo, val setValue(newValue); } - setModalCollection(undefined); - toggleModal(modalSlug); - }, [relationTo, modalCollection, dispatchOptions, i18n, hasMany, toggleModal, modalSlug, setValue, value]); + setSelectedCollection(undefined); + // toggleModal(modalSlug); + }, [relationTo, selectedCollection, dispatchOptions, i18n, hasMany, setValue, value]); const onPopopToggle = useCallback((state) => { setPopupOpen(state); @@ -75,7 +72,7 @@ export const AddNewRelation: React.FC = ({ path, hasMany, relationTo, val useEffect(() => { if (!isModalOpen(modalSlug)) { - setModalCollection(undefined); + setSelectedCollection(undefined); } }, [isModalOpen, modalSlug]); @@ -85,56 +82,75 @@ export const AddNewRelation: React.FC = ({ path, hasMany, relationTo, val id={`${path}-add-new`} > {relatedCollections.length === 1 && ( - + + setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + > + {showTooltip && ( + + {t('addNewLabel', { label: relatedCollections[0].labels.singular })} + + )} + + + {relatedCollections[0] && ( + + )} + )} {relatedCollections.length > 1 && ( - - - + + + + )} - render={({ close: closePopup }) => ( -
    - {relatedCollections.map((relatedCollection) => { - if (permissions.collections[relatedCollection.slug].create.permission) { - return ( -
  • - -
  • - ); - } + render={({ close: closePopup }) => ( +
      + {relatedCollections.map((relatedCollection) => { + if (permissions.collections[relatedCollection.slug].create.permission) { + return ( +
    • + { + closePopup(); + setSelectedCollection(relatedCollection); + }} + > + {getTranslation(relatedCollection.labels.singular, i18n)} + +
    • + ); + } - return null; - })} -
    + return null; + })} +
+ )} + /> + {selectedCollection && ( + )} - /> - )} - {modalCollection && ( - +
)} ) : null; From 7a42e38cca87e34d90b1af369fcc8575c8622456 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 1 Dec 2022 17:38:26 -0500 Subject: [PATCH 06/31] feat: supports custom react-select components --- .../components/elements/ReactSelect/index.tsx | 25 +++++++++++-------- .../components/elements/ReactSelect/types.ts | 3 +++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/admin/components/elements/ReactSelect/index.tsx b/src/admin/components/elements/ReactSelect/index.tsx index 700980bf45..264b137266 100644 --- a/src/admin/components/elements/ReactSelect/index.tsx +++ b/src/admin/components/elements/ReactSelect/index.tsx @@ -1,6 +1,6 @@ import React, { MouseEventHandler, useCallback } from 'react'; import Select, { - components, + components as SelectComponents, MultiValueProps, Props as SelectProps, } from 'react-select'; @@ -14,14 +14,14 @@ import { } from 'react-sortable-hoc'; import { useTranslation } from 'react-i18next'; import { arrayMove } from '../../../../utilities/arrayMove'; -import { Props, Option } from './types'; +import { Props, Option as OptionType } from './types'; import Chevron from '../../icons/Chevron'; import { getTranslation } from '../../../../utilities/getTranslation'; import './index.scss'; const SortableMultiValue = SortableElement( - (props: MultiValueProps