= (props) => {
aboutToDelete
diff --git a/src/admin/components/elements/DocumentDrawer/index.scss b/src/admin/components/elements/DocumentDrawer/index.scss
new file mode 100644
index 0000000000..61cb02f0cf
--- /dev/null
+++ b/src/admin/components/elements/DocumentDrawer/index.scss
@@ -0,0 +1,36 @@
+@import '../../../scss/styles.scss';
+
+.doc-drawer {
+ &__header {
+ margin-bottom: base(1);
+ }
+
+ &__header-content {
+ 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..8cf5de3077
--- /dev/null
+++ b/src/admin/components/elements/DocumentDrawer/index.tsx
@@ -0,0 +1,239 @@
+import React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
+import { useModal } from '@faceless-ui/modal';
+import { useTranslation } from 'react-i18next';
+import { toast } from 'react-toastify';
+import { DocumentDrawerProps, DocumentTogglerProps, UseDocumentDrawer } 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 } from '../Drawer';
+import Button from '../Button';
+import { useConfig } from '../../utilities/Config';
+import { useLocale } from '../../utilities/Locale';
+import { useAuth } from '../../utilities/Auth';
+import { DocumentInfoProvider } from '../../utilities/DocumentInfo';
+import RenderCustomComponent from '../../utilities/RenderCustomComponent';
+import usePayloadAPI from '../../../hooks/usePayloadAPI';
+import formatFields from '../../views/collections/Edit/formatFields';
+import { useRelatedCollections } from '../../forms/field-types/Relationship/AddNew/useRelatedCollections';
+import IDLabel from '../IDLabel';
+import { useEditDepth } from '../../utilities/EditDepth';
+import './index.scss';
+
+const baseClass = 'doc-drawer';
+
+const formatDocumentDrawerSlug = ({
+ collectionSlug,
+ id,
+ depth,
+ uuid,
+}: {
+ collectionSlug: string,
+ id: string,
+ depth: number,
+ uuid?: string, // supply when creating a new document and no id is available
+}) => `doc-drawer_${collectionSlug}_${depth}_${id || uuid || '0'}`;
+
+export const DocumentDrawerToggler: React.FC = ({
+ children,
+ className,
+ drawerSlug,
+ id,
+ collectionSlug,
+ ...rest
+}) => {
+ const { t, i18n } = useTranslation(['fields', 'general']);
+ const [collectionConfig] = useRelatedCollections(collectionSlug);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const DocumentDrawer: React.FC = ({
+ collectionSlug,
+ id,
+ drawerSlug,
+ onSave,
+ customHeader,
+}) => {
+ const { serverURL, routes: { api } } = useConfig();
+ const { toggleModal, modalState, closeModal } = useModal();
+ const locale = useLocale();
+ const { permissions, user } = useAuth();
+ const [initialState, setInitialState] = useState();
+ const { t, i18n } = useTranslation(['fields', 'general']);
+ const hasInitializedState = useRef(false);
+ const [isOpen, setIsOpen] = useState(false);
+ const [collectionConfig] = useRelatedCollections(collectionSlug);
+
+ const [fields, setFields] = useState(() => formatFields(collectionConfig, true));
+
+ useEffect(() => {
+ setFields(formatFields(collectionConfig, true));
+ }, [collectionSlug, collectionConfig]);
+
+ const [{ data, isLoading: isLoadingDocument, isError }] = usePayloadAPI(
+ (id ? `${serverURL}${api}/${collectionSlug}/${id}` : null),
+ { initialParams: { 'fallback-locale': 'null', depth: 0, draft: 'true' } },
+ );
+
+ useEffect(() => {
+ if (isLoadingDocument || hasInitializedState.current === true) {
+ return;
+ }
+
+ const awaitInitialState = async () => {
+ const state = await buildStateFromSchema({
+ fieldSchema: fields,
+ data,
+ user,
+ operation: id ? 'update' : 'create',
+ id,
+ locale,
+ t,
+ });
+ setInitialState(state);
+ };
+
+ awaitInitialState();
+ hasInitializedState.current = true;
+ }, [data, fields, id, user, locale, isLoadingDocument, t]);
+
+ useEffect(() => {
+ setIsOpen(Boolean(modalState[drawerSlug]?.isOpen));
+ }, [modalState, drawerSlug]);
+
+ useEffect(() => {
+ if (isOpen && !isLoadingDocument && isError) {
+ closeModal(drawerSlug);
+ toast.error(data.errors?.[0].message || t('error:unspecific'));
+ }
+ }, [isError, t, isOpen, data, drawerSlug, closeModal, isLoadingDocument]);
+
+ if (isError) return null;
+
+ if (isOpen) {
+ // IMPORTANT: we must ensure that modals are not recursively rendered
+ // to do this, do not render the drawer until it is open
+ return (
+
+
+
+
+
+ {!customHeader ? t(!id ? 'fields:addNewLabel' : 'general:editLabel', { label: getTranslation(collectionConfig.labels.singular, i18n) }) : customHeader}
+
+
+
+ {id && (
+
+ )}
+
+ ),
+ }}
+ />
+
+
+ );
+ }
+ return null;
+};
+
+export const useDocumentDrawer: UseDocumentDrawer = ({ id, collectionSlug }) => {
+ const drawerDepth = useEditDepth();
+ const uuid = useId();
+ const { modalState, toggleModal } = useModal();
+ const [isOpen, setIsOpen] = useState(false);
+ const drawerSlug = formatDocumentDrawerSlug({
+ collectionSlug,
+ id,
+ depth: drawerDepth,
+ uuid,
+ });
+
+ useEffect(() => {
+ setIsOpen(Boolean(modalState[drawerSlug]?.isOpen));
+ }, [modalState, drawerSlug]);
+
+ const toggleDrawer = useCallback(() => {
+ toggleModal(drawerSlug);
+ }, [toggleModal, drawerSlug]);
+
+ const MemoizedDrawer = useMemo(() => {
+ return ((props) => (
+
+ ));
+ }, [id, drawerSlug, collectionSlug]);
+
+ const MemoizedDrawerToggler = useMemo(() => {
+ return ((props) => (
+
+ ));
+ }, [id, drawerSlug, collectionSlug]);
+
+ const MemoizedDrawerState = useMemo(() => ({
+ drawerSlug,
+ drawerDepth,
+ isDrawerOpen: isOpen,
+ toggleDrawer,
+ }), [drawerDepth, drawerSlug, isOpen, toggleDrawer]);
+
+ return [
+ MemoizedDrawer,
+ MemoizedDrawerToggler,
+ MemoizedDrawerState,
+ ];
+};
diff --git a/src/admin/components/elements/DocumentDrawer/types.ts b/src/admin/components/elements/DocumentDrawer/types.ts
new file mode 100644
index 0000000000..0a5361cb9e
--- /dev/null
+++ b/src/admin/components/elements/DocumentDrawer/types.ts
@@ -0,0 +1,31 @@
+import React, { HTMLAttributes } from 'react';
+
+export type DocumentDrawerProps = {
+ collectionSlug: string
+ id?: string
+ onSave?: (json: Record) => void
+ customHeader?: React.ReactNode
+ drawerSlug?: string
+}
+
+export type DocumentTogglerProps = HTMLAttributes & {
+ children?: React.ReactNode
+ className?: string
+ drawerSlug?: string
+ id?: string
+ collectionSlug: string
+}
+
+export type UseDocumentDrawer = (args: {
+ id?: string
+ collectionSlug: string
+}) => [
+ React.FC>, // drawer
+ React.FC>, // toggler
+ {
+ drawerSlug: string,
+ drawerDepth: number
+ isDrawerOpen: boolean
+ toggleDrawer: () => void
+ }
+]
diff --git a/src/admin/components/elements/Drawer/index.scss b/src/admin/components/elements/Drawer/index.scss
new file mode 100644
index 0000000000..3a564e8fd8
--- /dev/null
+++ b/src/admin/components/elements/Drawer/index.scss
@@ -0,0 +1,86 @@
+@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;
+ transform: translateX(#{base(4)});
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ transition: all 300ms ease-out;
+ }
+
+ &__content-children {
+ position: relative;
+ z-index: 1;
+ overflow: auto;
+ height: 100%;
+ }
+
+ &--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);
+ }
+ }
+
+ &__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;
+ will-change: opacity;
+ transition: none;
+ transition-delay: 0ms;
+
+ &: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..af487a1632
--- /dev/null
+++ b/src/admin/components/elements/Drawer/index.tsx
@@ -0,0 +1,100 @@
+import React, { useCallback, useEffect, useState } from 'react';
+import { Modal, useModal } from '@faceless-ui/modal';
+import { useWindowInfo } from '@faceless-ui/window-info';
+import { useTranslation } from 'react-i18next';
+import { Props, TogglerProps } from './types';
+import { EditDepthContext, useEditDepth } from '../../utilities/EditDepth';
+import './index.scss';
+
+const baseClass = 'drawer';
+
+const zBase = 100;
+
+const formatDrawerSlug = ({
+ slug,
+ depth,
+}: {
+ slug: string,
+ depth: number,
+}) => `drawer_${depth}_${slug}`;
+
+export const DrawerToggler: React.FC = ({
+ slug,
+ formatSlug,
+ children,
+ className,
+ onClick,
+ ...rest
+}) => {
+ const { openModal } = useModal();
+ const drawerDepth = useEditDepth();
+
+ const handleClick = useCallback((e) => {
+ openModal(formatSlug !== false ? formatDrawerSlug({ slug, depth: drawerDepth }) : slug);
+ if (typeof onClick === 'function') onClick(e);
+ }, [openModal, drawerDepth, slug, onClick, formatSlug]);
+
+ return (
+
+ );
+};
+
+export const Drawer: React.FC = ({
+ slug,
+ formatSlug,
+ children,
+ className,
+}) => {
+ const { t } = useTranslation('general');
+ const { closeModal, modalState } = useModal();
+ const { breakpoints: { m: midBreak } } = useWindowInfo();
+ const drawerDepth = useEditDepth();
+ const [isOpen, setIsOpen] = useState(false);
+ const [modalSlug] = useState(() => (formatSlug !== false ? formatDrawerSlug({ slug, depth: drawerDepth }) : slug));
+
+ useEffect(() => {
+ setIsOpen(modalState[modalSlug].isOpen);
+ }, [modalSlug, modalState]);
+
+ return (
+
+ {drawerDepth === 1 && (
+
+ )}
+
+ );
+};
diff --git a/src/admin/components/elements/Drawer/types.ts b/src/admin/components/elements/Drawer/types.ts
new file mode 100644
index 0000000000..b137f08a84
--- /dev/null
+++ b/src/admin/components/elements/Drawer/types.ts
@@ -0,0 +1,15 @@
+import { HTMLAttributes } from 'react';
+
+export type Props = {
+ slug: string
+ formatSlug?: boolean
+ children: React.ReactNode
+ className?: string
+}
+
+export type TogglerProps = HTMLAttributes & {
+ slug: string
+ formatSlug?: boolean
+ children: React.ReactNode
+ className?: string
+}
diff --git a/src/admin/components/elements/ReactSelect/ClearIndicator/index.scss b/src/admin/components/elements/ReactSelect/ClearIndicator/index.scss
new file mode 100644
index 0000000000..6bc57c5d54
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/ClearIndicator/index.scss
@@ -0,0 +1,5 @@
+@import '../../../../scss/styles.scss';
+
+.clear-indicator {
+ cursor: pointer;
+}
diff --git a/src/admin/components/elements/ReactSelect/ClearIndicator/index.tsx b/src/admin/components/elements/ReactSelect/ClearIndicator/index.tsx
new file mode 100644
index 0000000000..c8f7a39bfe
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/ClearIndicator/index.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { IndicatorProps } from 'react-select';
+import X from '../../../icons/X';
+import { Option as OptionType } from '../types';
+import './index.scss';
+
+const baseClass = 'clear-indicator';
+
+export const ClearIndicator: React.FC> = (props) => {
+ const {
+ innerProps: { ref, ...restInnerProps },
+ } = props;
+
+ return (
+
+
+
+ );
+};
diff --git a/src/admin/components/elements/ReactSelect/Control/index.tsx b/src/admin/components/elements/ReactSelect/Control/index.tsx
new file mode 100644
index 0000000000..1a229fd794
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/Control/index.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { components as SelectComponents, ControlProps } from 'react-select';
+import { Option } from '../../../forms/field-types/Relationship/types';
+
+export const Control: React.FC> = (props) => {
+ const {
+ children,
+ innerProps,
+ selectProps: {
+ selectProps: {
+ disableMouseDown,
+ disableKeyDown,
+ },
+ },
+ } = props;
+
+ return (
+ {
+ // we need to prevent react-select from hijacking the 'onMouseDown' event while modals are open (i.e. the 'Relationship' field component)
+ if (!disableMouseDown) {
+ innerProps.onMouseDown(e);
+ }
+ },
+ // react-select has this typed incorrectly so we disable the linting rule
+ // we need to prevent react-select from hijacking the 'onKeyDown' event while modals are open (i.e. the 'Relationship' field component)
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ onKeyDown: (e) => {
+ if (disableKeyDown) {
+ e.stopPropagation();
+ }
+ },
+ }}
+ >
+ {children}
+
+ );
+};
diff --git a/src/admin/components/elements/ReactSelect/MultiValue/index.scss b/src/admin/components/elements/ReactSelect/MultiValue/index.scss
new file mode 100644
index 0000000000..02c112e61c
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/MultiValue/index.scss
@@ -0,0 +1,15 @@
+@import '../../../../scss/styles.scss';
+
+.multi-value {
+ &.rs__multi-value {
+ padding: 0;
+ background: transparent;
+ border: $style-stroke-width-s solid var(--theme-elevation-800);
+ line-height: calc(#{$baseline} - #{$style-stroke-width-s * 2});
+ margin: base(.25) base(.5) base(.25) 0;
+
+ &.draggable {
+ cursor: grab;
+ }
+ }
+}
diff --git a/src/admin/components/elements/ReactSelect/MultiValue/index.tsx b/src/admin/components/elements/ReactSelect/MultiValue/index.tsx
new file mode 100644
index 0000000000..a27dfddfa7
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/MultiValue/index.tsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import {
+ MultiValueProps,
+ components as SelectComponents,
+} from 'react-select';
+import { useSortable } from '@dnd-kit/sortable';
+import { Option as OptionType } from '../types';
+
+import './index.scss';
+
+const baseClass = 'multi-value';
+
+export const MultiValue: React.FC> = (props) => {
+ const {
+ className,
+ isDisabled,
+ innerProps,
+ data: {
+ value,
+ },
+ selectProps: {
+ selectProps,
+ selectProps: {
+ disableMouseDown,
+ },
+ },
+ } = props;
+
+ const { attributes, listeners, setNodeRef, transform } = useSortable({
+ id: value as string,
+ });
+
+ const classes = [
+ baseClass,
+ className,
+ !isDisabled && 'draggable',
+ ].filter(Boolean).join(' ');
+
+ return (
+ {
+ if (!disableMouseDown) {
+ // we need to prevent the dropdown from opening when clicking on the drag handle, but not when a modal is open (i.e. the 'Relationship' field component)
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ },
+ style: {
+ ...transform ? {
+ transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
+ } : {},
+ },
+ }}
+ selectProps={{
+ ...selectProps,
+ // pass the draggable props through to the label so it alone acts as the draggable handle
+ draggableProps: {
+ ...attributes,
+ ...listeners,
+ },
+ }}
+ />
+ );
+};
diff --git a/src/admin/components/elements/ReactSelect/MultiValueLabel/index.scss b/src/admin/components/elements/ReactSelect/MultiValueLabel/index.scss
new file mode 100644
index 0000000000..87113ecffb
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/MultiValueLabel/index.scss
@@ -0,0 +1,15 @@
+@import '../../../../scss/styles.scss';
+
+.multi-value-label {
+ @extend %small;
+ display: flex;
+ align-items: center;
+ padding: 0 base(.125) 0 base(.25);
+ max-width: 150px;
+ color: currentColor;
+
+ &__text {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+}
diff --git a/src/admin/components/elements/ReactSelect/MultiValueLabel/index.tsx b/src/admin/components/elements/ReactSelect/MultiValueLabel/index.tsx
new file mode 100644
index 0000000000..032591f288
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/MultiValueLabel/index.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { components as SelectComponents, MultiValueProps } from 'react-select';
+import { Option } from '../../../forms/field-types/Relationship/types';
+import './index.scss';
+
+const baseClass = 'multi-value-label';
+
+export const MultiValueLabel: React.FC> = (props) => {
+ const {
+ selectProps: {
+ draggableProps,
+ },
+ } = props;
+
+ return (
+
+
+
+ );
+};
diff --git a/src/admin/components/elements/ReactSelect/MultiValueRemove/index.scss b/src/admin/components/elements/ReactSelect/MultiValueRemove/index.scss
new file mode 100644
index 0000000000..d93c8824ed
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/MultiValueRemove/index.scss
@@ -0,0 +1,24 @@
+@import '../../../../scss/styles.scss';
+
+.multi-value-remove {
+ cursor: pointer;
+ width: base(.75);
+ height: base(.75);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ background-color: transparent;
+ border: none;
+ padding: 0;
+
+ &:hover {
+ color: var(--theme-elevation-800);
+ background: var(--theme-error-150);
+ }
+
+ &__icon {
+ width: 100%;
+ height: 100%;
+ }
+}
diff --git a/src/admin/components/elements/ReactSelect/MultiValueRemove/index.tsx b/src/admin/components/elements/ReactSelect/MultiValueRemove/index.tsx
new file mode 100644
index 0000000000..43d701236f
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/MultiValueRemove/index.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { MultiValueRemoveProps } from 'react-select/src/components/MultiValue';
+import X from '../../../icons/X';
+import Tooltip from '../../Tooltip';
+import { Option as OptionType } from '../types';
+import './index.scss';
+
+const baseClass = 'multi-value-remove';
+
+export const MultiValueRemove: React.FC> = (props) => {
+ const {
+ innerProps,
+ } = props;
+ const [showTooltip, setShowTooltip] = React.useState(false);
+ const { t } = useTranslation('general');
+
+ return (
+
+ );
+};
diff --git a/src/admin/components/elements/ReactSelect/ValueContainer/index.scss b/src/admin/components/elements/ReactSelect/ValueContainer/index.scss
new file mode 100644
index 0000000000..41bc946078
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/ValueContainer/index.scss
@@ -0,0 +1,33 @@
+@import '../../../../scss/styles.scss';
+
+.value-container {
+ flex-grow: 1;
+
+ .rs__value-container {
+ padding: base(.25) 0;
+ min-height: base(1.5);
+ overflow: visible;
+
+ > * {
+ margin: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ &--is-multi {
+ margin-left: - base(0.25);
+ width: calc(100% + base(0.5));
+ padding-top: base(0.25);
+ padding-bottom: base(0.25);
+ padding-left: base(0.25);
+
+ .rs__multi-value {
+ margin: calc(#{base(.125)} - #{$style-stroke-width-s * 2});
+ }
+
+ &.rs__value-container--has-value {
+ padding-left: 0;
+ }
+ }
+ }
+}
diff --git a/src/admin/components/elements/ReactSelect/ValueContainer/index.tsx b/src/admin/components/elements/ReactSelect/ValueContainer/index.tsx
new file mode 100644
index 0000000000..82aea89190
--- /dev/null
+++ b/src/admin/components/elements/ReactSelect/ValueContainer/index.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { components as SelectComponents, ValueContainerProps } from 'react-select';
+import { Option } from '../types';
+
+import './index.scss';
+
+const baseClass = 'value-container';
+
+export const ValueContainer: React.FC> = (props) => {
+ const {
+ selectProps,
+ } = props;
+
+ return (
+
+
+
+ );
+};
diff --git a/src/admin/components/elements/ReactSelect/index.scss b/src/admin/components/elements/ReactSelect/index.scss
index 97fd1bb174..2fb544d262 100644
--- a/src/admin/components/elements/ReactSelect/index.scss
+++ b/src/admin/components/elements/ReactSelect/index.scss
@@ -1,41 +1,17 @@
@import '../../../scss/styles';
-div.react-select {
- div.rs__control {
+.react-select {
+ .rs__control {
@include formInput;
height: auto;
padding-top: base(.25);
padding-bottom: base(.25);
- }
-
- .rs__value-container {
- padding: base(.25) 0;
- min-height: base(1.5);
-
- >* {
- margin-top: 0;
- margin-bottom: 0;
- padding-top: 0;
- padding-bottom: 0;
- }
-
- &--is-multi {
- margin-left: - base(.25);
- padding-top: 0;
- padding-bottom: 0;
- }
- }
-
- .rs__indicators {
- .arrow {
- margin-left: base(.5);
- transform: rotate(90deg);
- width: base(.3);
- }
+ flex-wrap: nowrap;
}
.rs__indicator {
padding: 0px 4px;
+ cursor: pointer;
}
.rs__indicator-separator {
@@ -47,7 +23,7 @@ div.react-select {
input {
font-family: var(--font-body);
- width: 100% !important;
+ width: 10px;
}
}
@@ -79,38 +55,6 @@ div.react-select {
}
}
- .rs__single-value {
- color: currentColor;
- }
-
- .rs__multi-value {
- padding: 0;
- background: transparent;
- border: $style-stroke-width-s solid var(--theme-elevation-800);
- line-height: calc(#{$baseline} - #{$style-stroke-width-s * 2});
- margin: base(.25) base(.5) base(.25) 0;
-
- &.draggable {
- cursor: grab;
- }
- }
-
- .rs__multi-value__label {
- padding: 0 base(.125) 0 base(.25);
- max-width: 150px;
- color: currentColor;
- }
-
- .rs__multi-value__remove {
- padding: 0 base(.125);
- cursor: pointer;
-
- &:hover {
- color: var(--theme-elevation-800);
- background: var(--theme-error-150);
- }
- }
-
&--error {
div.rs__control {
background-color: var(--theme-error-200);
@@ -120,4 +64,4 @@ div.react-select {
&.rs--is-disabled .rs__control {
background: var(--theme-elevation-200);
}
-}
\ No newline at end of file
+}
diff --git a/src/admin/components/elements/ReactSelect/index.tsx b/src/admin/components/elements/ReactSelect/index.tsx
index 700980bf45..63816e1de7 100644
--- a/src/admin/components/elements/ReactSelect/index.tsx
+++ b/src/admin/components/elements/ReactSelect/index.tsx
@@ -1,61 +1,39 @@
-import React, { MouseEventHandler, useCallback } from 'react';
-import Select, {
- components,
- MultiValueProps,
- Props as SelectProps,
-} from 'react-select';
+import React, { useCallback, useId } from 'react';
import {
- SortableContainer,
- SortableContainerProps,
- SortableElement,
- SortStartHandler,
- SortEndHandler,
- SortableHandle,
-} from 'react-sortable-hoc';
+ DragEndEvent,
+ useDroppable,
+ DndContext,
+ closestCenter,
+ KeyboardSensor,
+ PointerSensor,
+ useSensor,
+ useSensors,
+} from '@dnd-kit/core';
+import Select from 'react-select';
import { useTranslation } from 'react-i18next';
-import { arrayMove } from '../../../../utilities/arrayMove';
-import { Props, Option } from './types';
+import {
+ arrayMove,
+ SortableContext,
+ sortableKeyboardCoordinates,
+} from '@dnd-kit/sortable';
+import { Props } from './types';
import Chevron from '../../icons/Chevron';
import { getTranslation } from '../../../../utilities/getTranslation';
-
+import { MultiValueLabel } from './MultiValueLabel';
+import { MultiValue } from './MultiValue';
+import { SingleValue } from '../../forms/field-types/Relationship/select-components/SingleValue';
+import { ValueContainer } from './ValueContainer';
+import { ClearIndicator } from './ClearIndicator';
+import { MultiValueRemove } from './MultiValueRemove';
+import { Control } from './Control';
import './index.scss';
-const SortableMultiValue = SortableElement(
- (props: MultiValueProps