feat: blocks drawer #1909
This commit is contained in:
@@ -39,7 +39,6 @@ export const DocumentDrawerToggler: React.FC<DocumentTogglerProps> = ({
|
||||
return (
|
||||
<DrawerToggler
|
||||
slug={drawerSlug}
|
||||
formatSlug={false}
|
||||
className={[
|
||||
className,
|
||||
`${baseClass}__toggler`,
|
||||
@@ -59,7 +58,6 @@ export const DocumentDrawer: React.FC<DocumentDrawerProps> = (props) => {
|
||||
return (
|
||||
<Drawer
|
||||
slug={drawerSlug}
|
||||
formatSlug={false}
|
||||
className={baseClass}
|
||||
>
|
||||
<DocumentDrawerContent {...props} />
|
||||
|
||||
@@ -20,7 +20,6 @@ export const formatDrawerSlug = ({
|
||||
|
||||
export const DrawerToggler: React.FC<TogglerProps> = ({
|
||||
slug,
|
||||
formatSlug,
|
||||
children,
|
||||
className,
|
||||
onClick,
|
||||
@@ -28,12 +27,11 @@ export const DrawerToggler: React.FC<TogglerProps> = ({
|
||||
...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 (
|
||||
<button
|
||||
@@ -50,7 +48,6 @@ export const DrawerToggler: React.FC<TogglerProps> = ({
|
||||
|
||||
export const Drawer: React.FC<Props> = ({
|
||||
slug,
|
||||
formatSlug,
|
||||
children,
|
||||
className,
|
||||
}) => {
|
||||
@@ -60,11 +57,10 @@ export const Drawer: React.FC<Props> = ({
|
||||
const drawerDepth = useEditDepth();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [animateIn, setAnimateIn] = useState(false);
|
||||
const [modalSlug] = useState(() => (formatSlug !== false ? formatDrawerSlug({ slug, depth: drawerDepth }) : slug));
|
||||
|
||||
useEffect(() => {
|
||||
setIsOpen(modalState[modalSlug]?.isOpen);
|
||||
}, [modalSlug, modalState]);
|
||||
setIsOpen(modalState[slug]?.isOpen);
|
||||
}, [slug, modalState]);
|
||||
|
||||
useEffect(() => {
|
||||
setAnimateIn(isOpen);
|
||||
@@ -75,7 +71,7 @@ export const Drawer: React.FC<Props> = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
slug={modalSlug}
|
||||
slug={slug}
|
||||
className={[
|
||||
className,
|
||||
baseClass,
|
||||
@@ -90,9 +86,9 @@ export const Drawer: React.FC<Props> = ({
|
||||
)}
|
||||
<button
|
||||
className={`${baseClass}__close`}
|
||||
id={`close-drawer__${modalSlug}`}
|
||||
id={`close-drawer__${slug}`}
|
||||
type="button"
|
||||
onClick={() => closeModal(modalSlug)}
|
||||
onClick={() => closeModal(slug)}
|
||||
style={{
|
||||
width: `calc(${midBreak ? 'var(--gutter-h)' : 'var(--nav-width)'} + ${drawerDepth - 1} * 25px)`,
|
||||
}}
|
||||
|
||||
@@ -2,14 +2,12 @@ import { HTMLAttributes } from 'react';
|
||||
|
||||
export type Props = {
|
||||
slug: string
|
||||
formatSlug?: boolean
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
export type TogglerProps = HTMLAttributes<HTMLButtonElement> & {
|
||||
slug: string
|
||||
formatSlug?: boolean
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
|
||||
12
src/admin/components/elements/Drawer/useDrawerSlug.tsx
Normal file
12
src/admin/components/elements/Drawer/useDrawerSlug.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useId } from 'react';
|
||||
import { formatDrawerSlug } from '.';
|
||||
import { useEditDepth } from '../../utilities/EditDepth';
|
||||
|
||||
export const useDrawerSlug = (slug: string): string => {
|
||||
const uuid = useId();
|
||||
const editDepth = useEditDepth();
|
||||
return formatDrawerSlug({
|
||||
slug: `${slug}-${uuid}`,
|
||||
depth: editDepth,
|
||||
});
|
||||
};
|
||||
@@ -27,7 +27,6 @@ export const ListDrawerToggler: React.FC<ListTogglerProps> = ({
|
||||
return (
|
||||
<DrawerToggler
|
||||
slug={drawerSlug}
|
||||
formatSlug={false}
|
||||
className={[
|
||||
className,
|
||||
`${baseClass}__toggler`,
|
||||
@@ -46,7 +45,6 @@ export const ListDrawer: React.FC<ListDrawerProps> = (props) => {
|
||||
return (
|
||||
<Drawer
|
||||
slug={drawerSlug}
|
||||
formatSlug={false}
|
||||
className={baseClass}
|
||||
>
|
||||
<ListDrawerContent {...props} />
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
@import '../../../../../../scss/styles';
|
||||
|
||||
.blocks-container {
|
||||
width: 100%;
|
||||
margin-top: base(1);
|
||||
margin-bottom: base(.5);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
min-width: 450px;
|
||||
max-width: 80vw;
|
||||
max-height: 300px;
|
||||
position: relative;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Props } from './types';
|
||||
|
||||
import BlockSelection from '../BlockSelection';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'blocks-container';
|
||||
|
||||
const BlocksContainer: React.FC<Props> = (props) => {
|
||||
const { blocks, ...remainingProps } = props;
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
{blocks?.map((block, index) => (
|
||||
<BlockSelection
|
||||
key={index}
|
||||
block={block}
|
||||
{...remainingProps}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlocksContainer;
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Block } from '../../../../../../../fields/config/types';
|
||||
|
||||
export type Props = {
|
||||
blocks: Block[]
|
||||
close: () => void
|
||||
addRow: (i: number, block: string) => void
|
||||
addRowIndex: number
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
@import '../../../../../scss/styles.scss';
|
||||
|
||||
.block-selector {
|
||||
|
||||
@include mid-break {
|
||||
min-width: 80vw;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import BlockSearch from './BlockSearch';
|
||||
import BlocksContainer from './BlocksContainer';
|
||||
import { Props } from './types';
|
||||
|
||||
const baseClass = 'block-selector';
|
||||
|
||||
const BlockSelector: React.FC<Props> = (props) => {
|
||||
const {
|
||||
blocks, close, parentIsHovered, watchParentHover, ...remainingProps
|
||||
} = props;
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [filteredBlocks, setFilteredBlocks] = useState(blocks);
|
||||
const [isBlockSelectorHovered, setBlockSelectorHovered] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const matchingBlocks = blocks.reduce((matchedBlocks, block) => {
|
||||
if (block.slug.toLowerCase().indexOf(searchTerm.toLowerCase()) !== -1) matchedBlocks.push(block);
|
||||
return matchedBlocks;
|
||||
}, []);
|
||||
|
||||
setFilteredBlocks(matchingBlocks);
|
||||
}, [searchTerm, blocks]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!parentIsHovered && !isBlockSelectorHovered && close && watchParentHover) close();
|
||||
}, [isBlockSelectorHovered, parentIsHovered, close, watchParentHover]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={baseClass}
|
||||
onMouseEnter={() => setBlockSelectorHovered(true)}
|
||||
onMouseLeave={() => setBlockSelectorHovered(false)}
|
||||
>
|
||||
<BlockSearch setSearchTerm={setSearchTerm} />
|
||||
<BlocksContainer
|
||||
blocks={filteredBlocks}
|
||||
close={close}
|
||||
{...remainingProps}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlockSelector;
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Block } from '../../../../../../fields/config/types';
|
||||
|
||||
export type Props = {
|
||||
blocks: Block[]
|
||||
addRow: (index: number, blockType?: string) => void
|
||||
watchParentHover?: boolean
|
||||
parentIsHovered?: boolean
|
||||
close: () => void
|
||||
addRowIndex: number
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getTranslation } from '../../../../../../../utilities/getTranslation';
|
||||
import DefaultBlockImage from '../../../../../graphics/DefaultBlockImage';
|
||||
@@ -10,7 +10,10 @@ const baseClass = 'block-selection';
|
||||
|
||||
const BlockSelection: React.FC<Props> = (props) => {
|
||||
const {
|
||||
addRow, addRowIndex, block, close,
|
||||
onClick,
|
||||
addRow,
|
||||
addRowIndex,
|
||||
block,
|
||||
} = props;
|
||||
|
||||
const { i18n } = useTranslation();
|
||||
@@ -19,10 +22,12 @@ const BlockSelection: React.FC<Props> = (props) => {
|
||||
labels, slug, imageURL, imageAltText,
|
||||
} = block;
|
||||
|
||||
const handleBlockSelection = () => {
|
||||
close();
|
||||
const handleBlockSelection = useCallback(() => {
|
||||
addRow(addRowIndex, slug);
|
||||
};
|
||||
if (typeof onClick === 'function') {
|
||||
onClick();
|
||||
}
|
||||
}, [onClick, addRow, addRowIndex, slug]);
|
||||
|
||||
return (
|
||||
<button
|
||||
@@ -32,14 +37,12 @@ const BlockSelection: React.FC<Props> = (props) => {
|
||||
onClick={handleBlockSelection}
|
||||
>
|
||||
<div className={`${baseClass}__image`}>
|
||||
{imageURL
|
||||
? (
|
||||
<img
|
||||
src={imageURL}
|
||||
alt={imageAltText}
|
||||
/>
|
||||
)
|
||||
: <DefaultBlockImage />}
|
||||
{imageURL ? (
|
||||
<img
|
||||
src={imageURL}
|
||||
alt={imageAltText}
|
||||
/>
|
||||
) : <DefaultBlockImage />}
|
||||
</div>
|
||||
<div className={`${baseClass}__label`}>{getTranslation(labels.singular, i18n)}</div>
|
||||
</button>
|
||||
@@ -4,5 +4,5 @@ export type Props = {
|
||||
addRow: (i: number, block: string) => void
|
||||
addRowIndex: number
|
||||
block: Block
|
||||
close: () => void
|
||||
onClick?: () => void
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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> = (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 (
|
||||
<Drawer slug={drawerSlug}>
|
||||
<Gutter className={baseClass}>
|
||||
<h2>
|
||||
{t('addLabel', { label: getTranslation(labels.singular, i18n) })}
|
||||
</h2>
|
||||
<BlockSearch setSearchTerm={setSearchTerm} />
|
||||
<div className={baseClass}>
|
||||
{filteredBlocks?.map((block, index) => (
|
||||
<BlockSelection
|
||||
key={index}
|
||||
block={block}
|
||||
onClick={() => {
|
||||
closeModal(drawerSlug);
|
||||
}}
|
||||
addRow={addRow}
|
||||
addRowIndex={addRowIndex}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Gutter>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
@@ -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
|
||||
}
|
||||
61
src/admin/components/forms/field-types/Blocks/RowActions.tsx
Normal file
61
src/admin/components/forms/field-types/Blocks/RowActions.tsx
Normal file
@@ -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 (
|
||||
<React.Fragment>
|
||||
<BlocksDrawer
|
||||
drawerSlug={drawerSlug}
|
||||
blocks={blocks}
|
||||
addRow={(index, rowBlockType) => {
|
||||
if (typeof addRow === 'function') {
|
||||
addRow(index, rowBlockType);
|
||||
}
|
||||
closeModal(drawerSlug);
|
||||
}}
|
||||
addRowIndex={rowIndex}
|
||||
labels={labels}
|
||||
/>
|
||||
<ArrayAction
|
||||
rowCount={rows.length}
|
||||
addRow={() => {
|
||||
openModal(drawerSlug);
|
||||
}}
|
||||
duplicateRow={() => duplicateRow(rowIndex, blockType)}
|
||||
moveRow={moveRow}
|
||||
removeRow={removeRow}
|
||||
index={rowIndex}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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> = (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> = (props) => {
|
||||
const locale = useLocale();
|
||||
const operation = useOperation();
|
||||
const { dispatchFields, setModified } = formContext;
|
||||
const [selectorIndexOpen, setSelectorIndexOpen] = useState<number>();
|
||||
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> = (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> = (props) => {
|
||||
description={description}
|
||||
/>
|
||||
</header>
|
||||
|
||||
<NullifyField
|
||||
path={path}
|
||||
fieldValue={value}
|
||||
/>
|
||||
|
||||
<Droppable
|
||||
droppableId="blocks-drop"
|
||||
isDropDisabled={readOnly}
|
||||
@@ -321,32 +317,17 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
</div>
|
||||
)}
|
||||
actions={!readOnly ? (
|
||||
<React.Fragment>
|
||||
<Popup
|
||||
key={`${blockType}-${i}`}
|
||||
forceOpen={selectorIndexOpen === i}
|
||||
onToggleOpen={onAddPopupToggle}
|
||||
buttonType="none"
|
||||
size="large"
|
||||
horizontalAlign="right"
|
||||
render={({ close }) => (
|
||||
<BlockSelector
|
||||
blocks={blocks}
|
||||
addRow={addRow}
|
||||
addRowIndex={i}
|
||||
close={close}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<ArrayAction
|
||||
rowCount={rows.length}
|
||||
duplicateRow={() => duplicateRow(i, blockType)}
|
||||
addRow={() => setSelectorIndexOpen(i)}
|
||||
moveRow={moveRow}
|
||||
removeRow={removeRow}
|
||||
index={i}
|
||||
/>
|
||||
</React.Fragment>
|
||||
<RowActions
|
||||
addRow={addRow}
|
||||
removeRow={removeRow}
|
||||
duplicateRow={duplicateRow}
|
||||
moveRow={moveRow}
|
||||
rows={rows}
|
||||
blockType={blockType}
|
||||
blocks={blocks}
|
||||
labels={labels}
|
||||
rowIndex={i}
|
||||
/>
|
||||
) : undefined}
|
||||
>
|
||||
<HiddenInput
|
||||
@@ -375,7 +356,6 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
|
||||
return null;
|
||||
})}
|
||||
|
||||
{!checkSkipValidation(value) && (
|
||||
<React.Fragment>
|
||||
{(rows.length < minRows || (required && rows.length === 0)) && (
|
||||
@@ -397,33 +377,30 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
|
||||
{(!readOnly && !hasMaxRows) && (
|
||||
<div className={`${baseClass}__add-button-wrap`}>
|
||||
<Popup
|
||||
buttonType="custom"
|
||||
size="large"
|
||||
horizontalAlign="left"
|
||||
button={(
|
||||
<Button
|
||||
buttonStyle="icon-label"
|
||||
icon="plus"
|
||||
iconPosition="left"
|
||||
iconStyle="with-border"
|
||||
>
|
||||
{t('addLabel', { label: getTranslation(labels.singular, i18n) })}
|
||||
</Button>
|
||||
)}
|
||||
render={({ close }) => (
|
||||
<BlockSelector
|
||||
blocks={blocks}
|
||||
addRow={addRow}
|
||||
addRowIndex={value}
|
||||
close={close}
|
||||
/>
|
||||
)}
|
||||
<Fragment>
|
||||
<DrawerToggler
|
||||
slug={drawerSlug}
|
||||
className={`${baseClass}__drawer-toggler`}
|
||||
>
|
||||
<Button
|
||||
el="span"
|
||||
icon="plus"
|
||||
buttonStyle="icon-label"
|
||||
iconPosition="left"
|
||||
iconStyle="with-border"
|
||||
>
|
||||
{t('addLabel', { label: getTranslation(labels.singular, i18n) })}
|
||||
</Button>
|
||||
</DrawerToggler>
|
||||
<BlocksDrawer
|
||||
drawerSlug={drawerSlug}
|
||||
blocks={blocks}
|
||||
addRow={addRow}
|
||||
addRowIndex={value}
|
||||
labels={labels}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
</DragDropContext>
|
||||
|
||||
@@ -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 (
|
||||
<Fragment>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -26,7 +26,6 @@ export const LinkDrawer: React.FC<Props> = ({
|
||||
return (
|
||||
<Drawer
|
||||
slug={drawerSlug}
|
||||
formatSlug={false}
|
||||
className={baseClass}
|
||||
>
|
||||
<Gutter className={`${baseClass}__template`}>
|
||||
|
||||
Reference in New Issue
Block a user