diff --git a/src/admin/components/elements/DocumentDrawer/index.tsx b/src/admin/components/elements/DocumentDrawer/index.tsx index fb2ca87800..c9f7c96248 100644 --- a/src/admin/components/elements/DocumentDrawer/index.tsx +++ b/src/admin/components/elements/DocumentDrawer/index.tsx @@ -39,7 +39,6 @@ export const DocumentDrawerToggler: React.FC = ({ return ( = (props) => { return ( diff --git a/src/admin/components/elements/Drawer/index.tsx b/src/admin/components/elements/Drawer/index.tsx index 0016c2c663..053f98ca7c 100644 --- a/src/admin/components/elements/Drawer/index.tsx +++ b/src/admin/components/elements/Drawer/index.tsx @@ -20,7 +20,6 @@ export const formatDrawerSlug = ({ export const DrawerToggler: React.FC = ({ slug, - formatSlug, children, className, onClick, @@ -28,12 +27,11 @@ export const DrawerToggler: React.FC = ({ ...rest }) => { const { openModal } = useModal(); - const drawerDepth = useEditDepth(); const handleClick = useCallback((e) => { - openModal(formatSlug !== false ? formatDrawerSlug({ slug, depth: drawerDepth }) : slug); + openModal(slug); if (typeof onClick === 'function') onClick(e); - }, [openModal, drawerDepth, slug, onClick, formatSlug]); + }, [openModal, slug, onClick]); return ( diff --git a/src/admin/components/forms/field-types/Blocks/BlockSelector/BlockSelection/types.ts b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/BlockSelection/types.ts similarity index 88% rename from src/admin/components/forms/field-types/Blocks/BlockSelector/BlockSelection/types.ts rename to src/admin/components/forms/field-types/Blocks/BlocksDrawer/BlockSelection/types.ts index 60b031e704..2a35a01d34 100644 --- a/src/admin/components/forms/field-types/Blocks/BlockSelector/BlockSelection/types.ts +++ b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/BlockSelection/types.ts @@ -4,5 +4,5 @@ export type Props = { addRow: (i: number, block: string) => void addRowIndex: number block: Block - close: () => void + onClick?: () => void } diff --git a/src/admin/components/forms/field-types/Blocks/BlocksDrawer/index.scss b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/index.scss new file mode 100644 index 0000000000..c039c09a11 --- /dev/null +++ b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/index.scss @@ -0,0 +1,10 @@ +@import '../../../../../scss/styles.scss'; + +.blocks-drawer { + margin-top: base(2.5); + width: 100%; + + @include mid-break { + margin-top: base(1.5); + } +} diff --git a/src/admin/components/forms/field-types/Blocks/BlocksDrawer/index.tsx b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/index.tsx new file mode 100644 index 0000000000..ec17dcf52f --- /dev/null +++ b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/index.tsx @@ -0,0 +1,61 @@ +import React, { useState, useEffect } from 'react'; +import { useModal } from '@faceless-ui/modal'; +import { useTranslation } from 'react-i18next'; +import BlockSearch from './BlockSearch'; +import { Props } from './types'; +import BlockSelection from './BlockSelection'; +import { Drawer } from '../../../../elements/Drawer'; +import { Gutter } from '../../../../elements/Gutter'; +import { getTranslation } from '../../../../../../utilities/getTranslation'; + +import './index.scss'; + +const baseClass = 'blocks-drawer'; + +export const BlocksDrawer: React.FC = (props) => { + const { + blocks, + addRow, + addRowIndex, + drawerSlug, + labels, + } = props; + + const [searchTerm, setSearchTerm] = useState(''); + const [filteredBlocks, setFilteredBlocks] = useState(blocks); + const { closeModal } = useModal(); + const { t, i18n } = useTranslation('fields'); + + useEffect(() => { + const matchingBlocks = blocks.reduce((matchedBlocks, block) => { + if (block.slug.toLowerCase().indexOf(searchTerm.toLowerCase()) !== -1) matchedBlocks.push(block); + return matchedBlocks; + }, []); + + setFilteredBlocks(matchingBlocks); + }, [searchTerm, blocks]); + + return ( + + +

+ {t('addLabel', { label: getTranslation(labels.singular, i18n) })} +

+ +
+ {filteredBlocks?.map((block, index) => ( + { + closeModal(drawerSlug); + }} + addRow={addRow} + addRowIndex={addRowIndex} + /> + ))} +
+
+
+ ); +}; diff --git a/src/admin/components/forms/field-types/Blocks/BlocksDrawer/types.ts b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/types.ts new file mode 100644 index 0000000000..967ae7ab83 --- /dev/null +++ b/src/admin/components/forms/field-types/Blocks/BlocksDrawer/types.ts @@ -0,0 +1,9 @@ +import { Block, Labels } from '../../../../../../fields/config/types'; + +export type Props = { + drawerSlug: string + blocks: Block[] + addRow: (index: number, blockType?: string) => void + addRowIndex: number + labels: Labels +} diff --git a/src/admin/components/forms/field-types/Blocks/RowActions.tsx b/src/admin/components/forms/field-types/Blocks/RowActions.tsx new file mode 100644 index 0000000000..dadc34dfc9 --- /dev/null +++ b/src/admin/components/forms/field-types/Blocks/RowActions.tsx @@ -0,0 +1,61 @@ +import { useModal } from '@faceless-ui/modal'; +import React from 'react'; +import { Block, Labels } from '../../../../../fields/config/types'; +import { ArrayAction } from '../../../elements/ArrayAction'; +import { useDrawerSlug } from '../../../elements/Drawer/useDrawerSlug'; +import { Row } from '../rowReducer'; +import { BlocksDrawer } from './BlocksDrawer'; + +export const RowActions: React.FC<{ + addRow: (rowIndex: number, blockType: string) => void + duplicateRow: (rowIndex: number, blockType: string) => void + removeRow: (rowIndex: number) => void + moveRow: (fromIndex: number, toIndex: number) => void + labels: Labels + blocks: Block[] + rowIndex: number + rows: Row[] + blockType: string +}> = (props) => { + const { + addRow, + duplicateRow, + removeRow, + moveRow, + labels, + blocks, + rowIndex, + rows, + blockType, + } = props; + + const { openModal, closeModal } = useModal(); + const drawerSlug = useDrawerSlug('blocks-drawer'); + + return ( + + { + if (typeof addRow === 'function') { + addRow(index, rowBlockType); + } + closeModal(drawerSlug); + }} + addRowIndex={rowIndex} + labels={labels} + /> + { + openModal(drawerSlug); + }} + duplicateRow={() => duplicateRow(rowIndex, blockType)} + moveRow={moveRow} + removeRow={removeRow} + index={rowIndex} + /> + + ); +}; diff --git a/src/admin/components/forms/field-types/Blocks/index.scss b/src/admin/components/forms/field-types/Blocks/index.scss index 446cdcaf13..ab5cdfe366 100644 --- a/src/admin/components/forms/field-types/Blocks/index.scss +++ b/src/admin/components/forms/field-types/Blocks/index.scss @@ -62,7 +62,11 @@ position: relative; } - &__add-button-wrap { + &__drawer-toggler { + background-color: transparent; + margin: 0; + padding: 0; + border: none; .btn { color: var(--theme-elevation-400); diff --git a/src/admin/components/forms/field-types/Blocks/index.tsx b/src/admin/components/forms/field-types/Blocks/index.tsx index 10c06aa98c..caa83c8ffb 100644 --- a/src/admin/components/forms/field-types/Blocks/index.tsx +++ b/src/admin/components/forms/field-types/Blocks/index.tsx @@ -1,27 +1,23 @@ -import React, { useCallback, useEffect, useReducer, useState } from 'react'; +import React, { Fragment, useCallback, useEffect, useReducer } from 'react'; import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; - import { useTranslation } from 'react-i18next'; import { useAuth } from '../../../utilities/Auth'; import { usePreferences } from '../../../utilities/Preferences'; import { useLocale } from '../../../utilities/Locale'; import withCondition from '../../withCondition'; -import Button from '../../../elements/Button'; import reducer, { Row } from '../rowReducer'; import { useDocumentInfo } from '../../../utilities/DocumentInfo'; import { useForm } from '../../Form/context'; import buildStateFromSchema from '../../Form/buildStateFromSchema'; import Error from '../../Error'; import useField from '../../useField'; -import Popup from '../../../elements/Popup'; -import BlockSelector from './BlockSelector'; +import { BlocksDrawer } from './BlocksDrawer'; import { blocks as blocksValidator } from '../../../../../fields/validations'; import Banner from '../../../elements/Banner'; import FieldDescription from '../../FieldDescription'; import { Props } from './types'; import { useOperation } from '../../../utilities/OperationProvider'; import { Collapsible } from '../../../elements/Collapsible'; -import { ArrayAction } from '../../../elements/ArrayAction'; import RenderFields from '../../RenderFields'; import SectionTitle from './SectionTitle'; import Pill from '../../../elements/Pill'; @@ -31,6 +27,10 @@ import { getTranslation } from '../../../../../utilities/getTranslation'; import { NullifyField } from '../../NullifyField'; import { useConfig } from '../../../utilities/Config'; import { createNestedFieldPath } from '../../Form/createNestedFieldPath'; +import { DrawerToggler } from '../../../elements/Drawer'; +import { useDrawerSlug } from '../../../elements/Drawer/useDrawerSlug'; +import Button from '../../../elements/Button'; +import { RowActions } from './RowActions'; import './index.scss'; @@ -38,15 +38,13 @@ const baseClass = 'blocks-field'; const BlocksField: React.FC = (props) => { const { t, i18n } = useTranslation('fields'); + const { label, name, path: pathFromProps, blocks, - labels = { - singular: t('block'), - plural: t('blocks'), - }, + labels: labelsFromProps, fieldTypes, maxRows, minRows, @@ -75,8 +73,14 @@ const BlocksField: React.FC = (props) => { const locale = useLocale(); const operation = useOperation(); const { dispatchFields, setModified } = formContext; - const [selectorIndexOpen, setSelectorIndexOpen] = useState(); const { localization } = useConfig(); + const drawerSlug = useDrawerSlug('blocks-drawer'); + + const labels = { + singular: t('block'), + plural: t('blocks'), + ...labelsFromProps, + }; const checkSkipValidation = useCallback((value) => { const defaultLocale = (localization && localization.defaultLocale) ? localization.defaultLocale : 'en'; @@ -102,12 +106,6 @@ const BlocksField: React.FC = (props) => { disableFormData: rows?.length > 0, }); - const onAddPopupToggle = useCallback((open) => { - if (!open) { - setSelectorIndexOpen(undefined); - } - }, []); - const addRow = useCallback(async (rowIndex: number, blockType: string) => { const block = blocks.find((potentialBlock) => potentialBlock.slug === blockType); const subFieldState = await buildStateFromSchema({ fieldSchema: block.fields, operation, id, user, locale, t }); @@ -262,12 +260,10 @@ const BlocksField: React.FC = (props) => { description={description} /> - - = (props) => { )} actions={!readOnly ? ( - - ( - - )} - /> - duplicateRow(i, blockType)} - addRow={() => setSelectorIndexOpen(i)} - moveRow={moveRow} - removeRow={removeRow} - index={i} - /> - + ) : undefined} > = (props) => { return null; })} - {!checkSkipValidation(value) && ( {(rows.length < minRows || (required && rows.length === 0)) && ( @@ -397,33 +377,30 @@ const BlocksField: React.FC = (props) => { )} - {(!readOnly && !hasMaxRows) && ( -
- - {t('addLabel', { label: getTranslation(labels.singular, i18n) })} - - )} - render={({ close }) => ( - - )} + + + + + -
+ )} diff --git a/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx b/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx index f21c376876..56cf239efb 100644 --- a/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useId, useState } from 'react'; +import React, { Fragment, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactEditor, useSlate } from 'slate-react'; import { Transforms, Range, Editor } from 'slate'; @@ -9,8 +9,6 @@ import reduceFieldsToValues from '../../../../../Form/reduceFieldsToValues'; import { useConfig } from '../../../../../../utilities/Config'; import isElementActive from '../../isActive'; import { unwrapLink } from '../utilities'; -import { useEditDepth } from '../../../../../../utilities/EditDepth'; -import { formatDrawerSlug } from '../../../../../../elements/Drawer'; import { getBaseFields } from '../LinkDrawer/baseFields'; import { LinkDrawer } from '../LinkDrawer'; import { Field } from '../../../../../../../../fields/config/types'; @@ -19,6 +17,7 @@ import buildStateFromSchema from '../../../../../Form/buildStateFromSchema'; import { useAuth } from '../../../../../../utilities/Auth'; import { Fields } from '../../../../../Form/types'; import { useLocale } from '../../../../../../utilities/Locale'; +import { useDrawerSlug } from '../../../../../../elements/Drawer/useDrawerSlug'; const insertLink = (editor, fields) => { const isCollapsed = editor.selection && Range.isCollapsed(editor.selection); @@ -93,12 +92,7 @@ export const LinkButton: React.FC<{ }); const { openModal, closeModal } = useModal(); - const uuid = useId(); - const editDepth = useEditDepth(); - const drawerSlug = formatDrawerSlug({ - slug: `rich-text-link-${uuid}`, - depth: editDepth, - }); + const drawerSlug = useDrawerSlug('rich-text-link'); return ( diff --git a/src/admin/components/forms/field-types/RichText/elements/link/Element/index.tsx b/src/admin/components/forms/field-types/RichText/elements/link/Element/index.tsx index a17614cfd4..f8183ed56c 100644 --- a/src/admin/components/forms/field-types/RichText/elements/link/Element/index.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/link/Element/index.tsx @@ -1,4 +1,4 @@ -import React, { HTMLAttributes, useCallback, useEffect, useId, useState } from 'react'; +import React, { HTMLAttributes, useCallback, useEffect, useState } from 'react'; import { ReactEditor, useSlate } from 'slate-react'; import { Transforms, Node, Editor } from 'slate'; import { useModal } from '@faceless-ui/modal'; @@ -17,10 +17,9 @@ import reduceFieldsToValues from '../../../../../Form/reduceFieldsToValues'; import deepCopyObject from '../../../../../../../../utilities/deepCopyObject'; import Button from '../../../../../../elements/Button'; import { getTranslation } from '../../../../../../../../utilities/getTranslation'; -import { useEditDepth } from '../../../../../../utilities/EditDepth'; -import { formatDrawerSlug } from '../../../../../../elements/Drawer'; import { Props as RichTextFieldProps } from '../../../types'; import './index.scss'; +import { useDrawerSlug } from '../../../../../../elements/Drawer/useDrawerSlug'; const baseClass = 'rich-text-link'; @@ -103,13 +102,7 @@ export const LinkElement: React.FC<{ return fields; }); - const uuid = useId(); - const editDepth = useEditDepth(); - - const drawerSlug = formatDrawerSlug({ - slug: `rich-text-link-${uuid}`, - depth: editDepth, - }); + const drawerSlug = useDrawerSlug('rich-text-link'); const handleTogglePopup = useCallback((render) => { if (!render) { diff --git a/src/admin/components/forms/field-types/RichText/elements/link/LinkDrawer/index.tsx b/src/admin/components/forms/field-types/RichText/elements/link/LinkDrawer/index.tsx index 85bbe74f0a..b9c3620a62 100644 --- a/src/admin/components/forms/field-types/RichText/elements/link/LinkDrawer/index.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/link/LinkDrawer/index.tsx @@ -26,7 +26,6 @@ export const LinkDrawer: React.FC = ({ return (