Skip to content

Commit

Permalink
docs: add docs entries
Browse files Browse the repository at this point in the history
  • Loading branch information
mgadewoll committed Sep 26, 2024
1 parent b69b3cf commit e89fc1e
Show file tree
Hide file tree
Showing 3 changed files with 309 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const dragAndDropTypesSource = require('!!raw-loader!./drag_and_drop_types');
import DragAndDropClone from './drag_and_drop_clone';
const dragAndDropCloneSource = require('!!raw-loader!./drag_and_drop_clone');

import DragAndDropPortal from './drag_and_drop_portal';
const dragAndDropPortalSource = require('!!raw-loader!./drag_and_drop_portal');

import DragAndDropComplex from './drag_and_drop_complex';
const dragAndDropComplexSource = require('!!raw-loader!./drag_and_drop_complex');

Expand Down Expand Up @@ -342,6 +345,56 @@ export const DragAndDropExample = {
),
demo: <DragAndDropClone />,
},
{
title: 'Portalled items',
source: [
{
type: GuideSectionTypes.JS,
code: dragAndDropPortalSource,
},
],
text: (
<>
<p>
When using EUI drag components inside a stacking context, the fixed
drag positioning might be affected. To ensure dragging works as
expected inside e.g. <EuiCode>EuiFlyout</EuiCode> or{' '}
<EuiCode>EuiModal</EuiCode> use the prop{' '}
<EuiCode>usePortal</EuiCode> on <EuiCode>EuiDraggable</EuiCode>{' '}
components. This will render the currently dragged element inside a
portal on the body scope .
</p>
<p>
If the styling of the <EuiCode>EuiDraggable</EuiCode> content is
relative to an outer scope component, the styling won't be applied
whiled dragging it when using <EuiCode>usePortal</EuiCode>. This is
because due to the changed position in the DOM which changes
previous hierarchical relations to other ancestor elements. To
prevent this from happening, we recommend to apply styling from
within the <EuiCode>EuiDraggable</EuiCode> scope.
</p>
</>
),
snippet: `<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA">
<EuiDraggable
spacing="m"
key="DRAGGABLE_ID"
index={0}
draggableId="DRAGGABLE_ID"
usePortal
>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>
Item 1
{state.isDragging && ' ✨'}
</EuiPanel>
)}
</EuiDraggable>
</EuiDroppable>
</EuiDragDropContext>`,
demo: <DragAndDropPortal />,
},
{
title: 'Kitchen sink',
source: [
Expand Down
121 changes: 121 additions & 0 deletions packages/eui/src-docs/src/views/drag_and_drop/drag_and_drop_portal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useState } from 'react';
import {
EuiButton,
EuiCode,
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutHeader,
EuiModal,
EuiModalBody,
EuiModalHeader,
EuiPanel,
EuiSpacer,
EuiTitle,
euiDragDropReorder,
} from '../../../../src/components';
import { htmlIdGenerator } from '../../../../src/services';

const makeId = htmlIdGenerator();

const makeList = (number, start = 1) =>
Array.from({ length: number }, (v, k) => k + start).map((el) => {
return {
content: `Item ${el}`,
id: makeId(),
};
});

export default () => {
const [isFlyoutOpen, setFlyoutOpen] = useState(false);
const [isModalOpen, setModalOpen] = useState(false);
const [list, setList] = useState(makeList(3));
const onDragEnd = ({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(list, source.index, destination.index);

setList(items);
}
};

return (
<>
<EuiButton onClick={() => setFlyoutOpen(!isFlyoutOpen)}>
Toggle flyout
</EuiButton>
<EuiSpacer />
<EuiButton onClick={() => setModalOpen(!isModalOpen)}>
Toggle modal
</EuiButton>
{isFlyoutOpen && (
<EuiFlyout onClose={() => setFlyoutOpen(false)}>
<EuiFlyoutHeader>
<EuiTitle size="s">
<h2>
Portalled <EuiCode>EuiDraggable</EuiCode> items
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA" spacing="m" withPanel>
{list.map(({ content, id }, idx) => (
<EuiDraggable
spacing="m"
key={id}
index={idx}
draggableId={id}
usePortal
>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>
{content}
{state.isDragging && ' ✨'}
</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
</EuiFlyoutBody>
</EuiFlyout>
)}

{isModalOpen && (
<EuiModal onClose={() => setModalOpen(false)}>
<EuiModalHeader>
<EuiTitle size="s">
<h2>
Portalled <EuiCode>EuiDraggable</EuiCode> items
</h2>
</EuiTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA" spacing="m" withPanel>
{list.map(({ content, id }, idx) => (
<EuiDraggable
spacing="m"
key={id}
index={idx}
draggableId={id}
usePortal
>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>
{content}
{state.isDragging && ' ✨'}
</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
</EuiModalBody>
</EuiModal>
)}
</>
);
};
135 changes: 135 additions & 0 deletions packages/website/docs/02_components/display/drag_and_drop/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,141 @@ the visual changes with drop-to-remove interactions.

<!-- TODO: Add copyable items example -->

## Portalled items

When using EUI drag components inside a stacking context, the fixed drag positioning might be affected. To ensure
dragging works as expected inside e.g. **EuiFlyout** or **EuiModal use the prop `usePortal` on **EuiDraggable** components.
This will render the currently dragged element inside a portal on the body scope.

If the styling of the **EuiDraggable** content is relative to an outer scope component, the styling won't be applied
whiled dragging it when using **usePortal**. This is because due to the changed position in the DOM which changes
previous hierarchical relations to other ancestor elements. To prevent this from happening, we recommend to apply
styling from within the **EuiDraggable** scope.

```tsx interactive
import React, { useState } from 'react';
import {
EuiButton,
EuiCode,
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutHeader,
EuiModal,
EuiModalBody,
EuiModalHeader,
EuiPanel,
EuiSpacer,
EuiTitle,
euiDragDropReorder,
htmlIdGenerator
} from '@elastic/eui';

const makeId = htmlIdGenerator();

const makeList = (number, start = 1) =>
Array.from({ length: number }, (v, k) => k + start).map((el) => {
return {
content: `Item ${el}`,
id: makeId(),
};
});

export default () => {
const [isFlyoutOpen, setFlyoutOpen] = useState(false);
const [isModalOpen, setModalOpen] = useState(false);
const [list, setList] = useState(makeList(3));
const onDragEnd = ({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(list, source.index, destination.index);

setList(items);
}
};

return (
<>
<EuiButton onClick={() => setFlyoutOpen(!isFlyoutOpen)}>
Toggle flyout
</EuiButton>
<EuiSpacer />
<EuiButton onClick={() => setModalOpen(!isModalOpen)}>
Toggle modal
</EuiButton>
{isFlyoutOpen && (
<EuiFlyout onClose={() => setFlyoutOpen(false)}>
<EuiFlyoutHeader>
<EuiTitle size="s">
<h2>
Portalled <EuiCode>EuiDraggable</EuiCode> items
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA" spacing="m" withPanel>
{list.map(({ content, id }, idx) => (
<EuiDraggable
spacing="m"
key={id}
index={idx}
draggableId={id}
usePortal
>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>
{content}
{state.isDragging && ''}
</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
</EuiFlyoutBody>
</EuiFlyout>
)}

{isModalOpen && (
<EuiModal onClose={() => setModalOpen(false)}>
<EuiModalHeader>
<EuiTitle size="s">
<h2>
Portalled <EuiCode>EuiDraggable</EuiCode> items
</h2>
</EuiTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA" spacing="m" withPanel>
{list.map(({ content, id }, idx) => (
<EuiDraggable
spacing="m"
key={id}
index={idx}
draggableId={id}
usePortal
>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>
{content}
{state.isDragging && ''}
</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
</EuiModalBody>
</EuiModal>
)}
</>
);
};
```

## Kitchen sink

**EuiDraggables** in **EuiDroppables**, **EuiDroppables** in **EuiDraggables**, custom drag handles, horizontal
Expand Down

0 comments on commit e89fc1e

Please sign in to comment.