Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EUI+] Fix/update various docs examples to match production #8118

Merged
merged 23 commits into from
Nov 11, 2024
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
21feb82
Update getting started + theming pages to remove references to Sass a…
cee-chen Nov 4, 2024
dc97d41
Fix EuiFormControlLayoutDelimited docs
cee-chen Nov 4, 2024
700879f
Update EuiDraggable portal/popover docs
cee-chen Nov 4, 2024
578be7d
Update EuiResizable docs to match prod/use `accountForScrollbars`
cee-chen Nov 4, 2024
5ba0f55
Update EuiSuperDatePicker from prod
cee-chen Nov 4, 2024
230715d
Update EuiCallOut docs to match prod
cee-chen Nov 4, 2024
7efa516
EuiIcons updates/fixes
cee-chen Nov 4, 2024
f58a363
Update/fix EuiToast docs
cee-chen Nov 4, 2024
e1437d4
Delete EuiPopover `panelClassName` example
cee-chen Nov 4, 2024
218ac57
Fix broken EuiDatePicker `className` demo
cee-chen Nov 4, 2024
ea436d2
Update EuiDatePicker display toggles to match prod
cee-chen Nov 4, 2024
3473798
Update first `EuiComboBox` example to not autoFocus/attempt to open o…
cee-chen Nov 4, 2024
4485dbb
Update various form row `display` props to match propd
cee-chen Nov 4, 2024
54344d0
Update/fix markdown links
cee-chen Nov 4, 2024
ca9ae70
Fix EuiSearchBar demos
cee-chen Nov 4, 2024
74c399a
Fix EuiDatePicker `customInput` example
cee-chen Nov 4, 2024
5dc1233
Fix EuiSuperDatePicker demos
cee-chen Nov 4, 2024
39e88b6
Fix EuiText sizing example + custom CSS
cee-chen Nov 4, 2024
deee3ec
Fix EuiAvatar icon example
cee-chen Nov 4, 2024
5b8baa9
Fix broken EuiContextMenu example
cee-chen Nov 4, 2024
750e7f2
Fix EuiEmptyPrompt multiple types example
cee-chen Nov 4, 2024
1d6a216
Update table selection demo to allow toggling uncontrolled + controll…
cee-chen Nov 5, 2024
b56e233
[PR feedback] Typo
cee-chen Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
257 changes: 185 additions & 72 deletions packages/website/docs/components/display/drag_and_drop.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,192 @@ export default () => {
</EuiDragDropContext>
);
};
```

## Portalled items

**EuiDraggables** use fixed positioning to render and animate the item being dragged. This positioning logic does not work as expected when used inside of containers that have their own [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context).

To ensure dragging works as expected inside e.g. **EuiFlyout**, **EuiModal** or **EuiPopover**, use the prop `usePortal` on **EuiDraggable** components. This will render the currently dragged element inside a portal appended to the document body (or wherever **EuiPortal** is configured to `insert` to by default).

:::warning Style inheritance
If the styling of the your draggable content is scoped to a parent component, the styling won't be applied while dragging it when using `usePortal`. This is due to the portalled position in the DOM, which changes previous hierarchical relations to other ancestor elements. To prevent this from happening, we recommend applying styling from within the **EuiDraggable** scope without any parent selectors.
cee-chen marked this conversation as resolved.
Show resolved Hide resolved
:::

```tsx interactive
import React, { FunctionComponent, ReactElement, useState } from 'react';
import {
EuiButton,
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutHeader,
EuiModal,
EuiModalBody,
EuiModalHeader,
EuiPanel,
EuiPopover,
EuiSpacer,
EuiTitle,
euiDragDropReorder,
htmlIdGenerator,
} from '@elastic/eui';
import { DroppableProps, OnDragEndResponder } from '@hello-pangea/dnd';

const makeId = htmlIdGenerator();

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

const DragContainer: FunctionComponent<{
children: ReactElement | ReactElement[] | DroppableProps['children'];
onDragEnd: OnDragEndResponder;
}> = ({ children, onDragEnd }) => (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA" spacing="m">
{children}
</EuiDroppable>
</EuiDragDropContext>
);

export default () => {
const [isFlyoutOpen, setFlyoutOpen] = useState(false);
const [isModalOpen, setModalOpen] = useState(false);
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const [list, setList] = useState(makeList(3));
const onDragEnd: OnDragEndResponder = ({ 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 <strong>EuiDraggable</strong> items
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<DragContainer onDragEnd={onDragEnd}>
{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>
))}
</DragContainer>
</EuiFlyoutBody>
</EuiFlyout>
)}

{isModalOpen && (
<EuiModal onClose={() => setModalOpen(false)}>
<EuiModalHeader>
<EuiTitle size="s">
<h2>
Portalled <strong>EuiDraggable</strong> items
</h2>
</EuiTitle>
</EuiModalHeader>
<EuiModalBody>
<DragContainer onDragEnd={onDragEnd}>
{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>
))}
</DragContainer>
</EuiModalBody>
</EuiModal>
)}

<EuiSpacer />

<EuiPopover
isOpen={isPopoverOpen}
closePopover={() => setIsPopoverOpen(false)}
button={
<EuiButton onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
Toggle popover
</EuiButton>
}
panelPaddingSize="none"
panelProps={{ css: { inlineSize: 200 } }}
>
<DragContainer
onDragEnd={({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(
list,
source.index,
destination.index
);
setList(items);
}
}}
>
{list.map(({ content, id }, idx) => (
<EuiDraggable
spacing="m"
key={id}
index={idx}
draggableId={id}
usePortal
>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>{content}</EuiPanel>
)}
</EuiDraggable>
))}
</DragContainer>
</EuiPopover>
</>
);
};
```

## Kitchen sink
Expand Down Expand Up @@ -853,78 +1038,6 @@ export default () => {

```

## Using drag and drop in popovers

**EuiDraggables** use fixed positioning to render and animate the item being dragged. This positioning logic does not work as expected when used inside of containers that have their own [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context).

This behavior particularly affects [**EuiPopover**](/docs/layout/popover). If using drag and drop UX within a popover, you **must** include the `<EuiPopover hasDragDrop>` prop for items to properly render while being dragged.

```tsx interactive
import React, { useState } from 'react';
import {
EuiPopover,
EuiButton,
EuiPanel,
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
euiDragDropReorder,
htmlIdGenerator,
} from '@elastic/eui';

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

export default () => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [list, setList] = useState(makeList(3));

return (
<EuiPopover
hasDragDrop
isOpen={isPopoverOpen}
closePopover={() => setIsPopoverOpen(false)}
button={
<EuiButton onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
Toggle popover with drag and drop content
</EuiButton>
}
panelPaddingSize="none"
panelProps={{ css: { inlineSize: 200 } }}
>
<EuiDragDropContext
onDragEnd={({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(
list,
source.index,
destination.index
);
setList(items);
}
}}
>
<EuiDroppable droppableId="droppableInPopover" spacing="m">
{list.map(({ content, id }, idx) => (
<EuiDraggable spacing="m" key={id} index={idx} draggableId={id}>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>{content}</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
</EuiPopover>
);
};
```

## Props

import docgen from '@elastic/eui-docgen/dist/components/drag_and_drop';
Expand Down