Skip to content

Commit

Permalink
[EUI+] Fix/update various docs examples to match production (#8118)
Browse files Browse the repository at this point in the history
  • Loading branch information
cee-chen authored Nov 11, 2024
1 parent b937ece commit f954160
Show file tree
Hide file tree
Showing 34 changed files with 1,465 additions and 1,068 deletions.
14 changes: 4 additions & 10 deletions packages/website/docs/components/display/avatar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,13 @@ If your icon has multiples or custom colors like a logo, you can keep the defaul

```tsx interactive
import React, { useContext } from 'react';
import { EuiAvatar, EuiSpacer, EuiTitle } from '@elastic/eui';
import { ThemeContext } from '../../components';
import { EuiAvatar, EuiSpacer, EuiTitle, useEuiTheme } from '@elastic/eui';

export default () => {
const themeContext = useContext(ThemeContext);

/**
* Setup theme based on current light/dark theme
*/
const isDarkTheme = themeContext.theme.includes('dark');
const isDarkTheme = useEuiTheme().colorMode === 'DARK';

return (
<div>
<>
<EuiTitle size="xs">
<h2>Avatar colors and sizes</h2>
</EuiTitle>
Expand Down Expand Up @@ -166,7 +160,7 @@ export default () => {
&emsp;
<EuiAvatar name="Large iconSize" iconType="managementApp" iconSize="l" />
&emsp;
</div>
</>
);
};
```
Expand Down
2 changes: 1 addition & 1 deletion packages/website/docs/components/display/callout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default () => (
Here be dragons. Don&rsquo;t wanna mess with no dragons. And{' '}
<EuiLink href="#">here&rsquo;s a link</EuiLink>.
</p>
<EuiButton href="#" color="warning">
<EuiButton href="#" color="warning" fill>
Link button
</EuiButton>
</EuiCallOut>
Expand Down
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 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.
:::

```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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit f954160

Please sign in to comment.