Skip to content

Commit

Permalink
feat(DragDrop): new drag drop styling fixes (#9784)
Browse files Browse the repository at this point in the history
* feat(DragDrop): introduce new package and deprecate old implementation

* refactor a bunch

* style fixes

* fix lint errors

* fix lint

* update snap

* update duallistselector example, try exporting interface from separate file

* bump versions in dragdrop for mismatch

* fix versions

* pr feedback

* fix versions after merge

* version update after rebase

* update md

* move into next folder for docgen

* update version after rebase

* update ver after rebase

* update ver after rebase

* update ver after rebase

* remove unused prop, update wording

* move some examples to demos

* update ver after rebase

* update new demos text

* update wording p1

* update wording p2

* update wording p3

* update wording p4

* fix links

* remove beta flags since page is beta

* update ver after rebase

---------

Co-authored-by: nicolethoen <[email protected]>
  • Loading branch information
kmcfaul and nicolethoen authored Jan 8, 2024
1 parent c90c7f2 commit 19ddee7
Show file tree
Hide file tree
Showing 37 changed files with 1,008 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ import global_BorderWidth_sm from '@patternfly/react-tokens/dist/esm/global_Bord

### Draggable

Draggable data lists used to have their own HTML5-based API for drag and drop, which wasn't able to fulfill requirements such as custom styling on items being dragged. So we wrote generic `DragDrop`, `Draggable`, and `Droppable` components for this purpose. Use those new components instead of the deprecated (and buggy!) HTML5-based API.
Note: There is a new recommended drag and drop implementation with full keyboard functionality, which replaces this implementation. To adhere to our new recommendations, refer to the [drag and drop demos](/components/drag-and-drop/react-next-demos).

Note: Keyboard accessibility and screen reader accessibility for the `DragDrop` component are still in development.
Previously, draggable data lists had their own API for the [drag and drop component](/components/drag-and-drop), which wasn't flexible enough to allow custom styling for items as they are dragged. To address this disparity, `<DragDrop>`, `<Draggable>`, and `<Droppable>` components were added to replace our now deprecated HTML5-based API. Keyboard and screen reader accessibility for the `<DragDrop>` component is still in development.

```ts isBeta file="./DataListDraggable.tsx"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
id: Drag and drop
section: components
propComponents: [DragDrop, Draggable, Droppable, DraggableItemPosition]
beta: true
title: Drag and drop
---

You can use the `DragDrop` component to move items in or between lists. The `DragDrop` component should contain `Droppable` components which contain `Draggable` components.
You can use the `<DragDrop>` component to move items in or between lists. The `<DragDrop>` component should contain `<Droppable>` components which contain `<Draggable>` components.

```ts noLive
import React from 'react';
Expand Down Expand Up @@ -35,9 +35,11 @@ Note: Keyboard accessibility and screen reader accessibility are still in develo
### Basic

```ts file="./DragDropBasic.tsx"

```

### Multiple lists

```ts file="./DragDropMultipleLists.tsx"

```
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ const getItems = (count: number) =>
}));

const reorder = (list: ItemType[], startIndex: number, endIndex: number) => {
const result = list;
const result = [...list];
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};

export const DragDropBasic: React.FunctionComponent = () => {
const [items, setItems] = React.useState(getItems(10));
const [items, setItems] = React.useState<ItemType[]>(getItems(10));

function onDrop(source: SourceType, dest: DestinationType) {
if (dest) {
Expand All @@ -42,8 +42,8 @@ export const DragDropBasic: React.FunctionComponent = () => {
return (
<DragDrop onDrop={onDrop}>
<Droppable>
{items.map(({ content }, i) => (
<Draggable key={i} style={{ padding: '8px' }}>
{items.map(({ id, content }) => (
<Draggable key={id} style={{ padding: '8px' }}>
{content}
</Draggable>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ interface SourceType {
index: number;
}

interface MultipleListState {
items1: ItemType[];
items2: ItemType[];
}

interface DestinationType extends SourceType {}

const getItems = (count: number, startIndex: number) =>
Expand All @@ -35,7 +40,7 @@ const move = (source: ItemType[], destination: ItemType[], sourceIndex: number,
};

export const DragDropMultipleLists: React.FunctionComponent = () => {
const [items, setItems] = React.useState({
const [items, setItems] = React.useState<MultipleListState>({
items1: getItems(10, 0),
items2: getItems(5, 10)
});
Expand Down Expand Up @@ -84,7 +89,7 @@ export const DragDropMultipleLists: React.FunctionComponent = () => {
{Object.entries(items).map(([key, subitems]) => (
<SplitItem key={key} style={{ flex: 1 }}>
<Droppable zone="multizone" droppableId={key}>
{subitems.map(({ id, content }) => (
{(subitems as ItemType[]).map(({ id, content }) => (
<Draggable key={id} style={{ padding: '8px' }}>
{content}
</Draggable>
Expand Down
1 change: 1 addition & 0 deletions packages/react-core/src/components/DragDrop/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './DragDrop';
export * from './Draggable';
export * from './Droppable';
export * from './DroppableContext';
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ The dual list selector can also be built in a composable manner to make customiz

### Composable with drag and drop

Note: There is a new recommended drag and drop implementation with full keyboard functionality, which replaces this implementation. To adhere to our new recommendations, refer to the [drag and drop demos](/components/drag-and-drop/react-next-demos).

This example only allows reordering the contents of the "chosen" pane with drag and drop. To make a pane able to be reordered:

- wrap the `DualListSelectorPane` in a `DragDrop` component
Expand All @@ -99,7 +101,7 @@ This example only allows reordering the contents of the "chosen" pane with drag
- define an `onDrag` callback which ensures that the drag event will not cross hairs with the `onOptionSelect` click
event set on the option. Note: the `ignoreNextOptionSelect` state value is used to prevent selection while dragging.

Note: Keyboard accessibility and screen reader accessibility for the `DragDrop` component are still in development.
Keyboard and screen reader accessibility for the `<DragDrop>` component is still in development.

```ts file="DualListSelectorComposableDragDrop.tsx"

Expand Down
2 changes: 2 additions & 0 deletions packages/react-core/src/components/DualListSelector/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export * from './DualListSelector';
export * from './DualListSelectorContext';
export * from './DualListSelectorControl';
export * from './DualListSelectorControlsWrapper';
export * from './DualListSelectorPane';
export * from './DualListSelectorList';
export * from './DualListSelectorListItem';
export * from './DualListSelectorTree';
export * from './DualListSelectorContext';
2 changes: 1 addition & 1 deletion packages/react-core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from './DataList';
export * from './DatePicker';
export * from './DescriptionList';
export * from './Divider';
export * from './DragDrop';
export * from './Drawer';
export * from './Dropdown';
export * from './DualListSelector';
Expand Down Expand Up @@ -76,7 +77,6 @@ export * from './Tooltip';
export * from './NumberInput';
export * from './TreeView';
export * from './Wizard';
export * from './DragDrop';
export * from './TextInputGroup';
export * from './Panel';
export * from './Truncate';
1 change: 1 addition & 0 deletions packages/react-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@patternfly/react-icons": "^5.2.0-prerelease.9",
"@patternfly/react-styles": "^5.2.0-prerelease.6",
"@patternfly/react-table": "^5.2.0-prerelease.41",
"@patternfly/react-drag-drop": "^5.2.0-prelease.0",
"@patternfly/react-tokens": "^5.2.0-prerelease.7"
},
"devDependencies": {
Expand Down
5 changes: 5 additions & 0 deletions packages/react-docs/patternfly-docs/patternfly-docs.source.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ module.exports = (baseSourceMD, sourceProps) => {
const reactCodeEditorPath = require
.resolve('@patternfly/react-code-editor/package.json')
.replace('package.json', 'src');
const reactDragDropPath = require.resolve('@patternfly/react-drag-drop/package.json').replace('package.json', 'src');
const reactPropsIgnore = '**/*.test.tsx';

sourceProps(path.join(reactCorePath, '/**/*.tsx'), reactPropsIgnore);
sourceProps(path.join(reactTablePath, '/**/*.tsx'), reactPropsIgnore);
sourceProps(path.join(reactChartsPath, '/**/*.tsx'), reactPropsIgnore);
sourceProps(path.join(reactCodeEditorPath, '/**/*.tsx'), reactPropsIgnore);
sourceProps(path.join(reactDragDropPath, '/**/*.tsx'), reactPropsIgnore);

// React MD
sourceMD(path.join(reactCorePath, '/components/**/examples/*.md'), 'react');
Expand All @@ -41,6 +43,9 @@ module.exports = (baseSourceMD, sourceProps) => {
// Code Editor MD
sourceMD(path.join(reactCodeEditorPath, '/**/examples/*.md'), 'react');

// Drag drop MD
sourceMD(path.join(reactDragDropPath, '/**/examples/*.md'), 'react-next');

// OUIA MD
sourceMD(path.join(reactCorePath, 'helpers/OUIA/OUIA.md'), 'react');
};
49 changes: 49 additions & 0 deletions packages/react-drag-drop/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@patternfly/react-drag-drop",
"version": "5.2.0-prelease.0",
"description": "PatternFly drag and drop solution",
"main": "dist/js/index.js",
"module": "dist/esm/index.js",
"types": "dist/esm/index.d.ts",
"sideEffects": false,
"publishConfig": {
"access": "public"
},
"patternfly:src": "src/",
"repository": {
"type": "git",
"url": "https://github.com/patternfly/patternfly-react.git"
},
"keywords": [
"react",
"patternfly",
"drag-drop"
],
"author": "Red Hat",
"license": "MIT",
"bugs": {
"url": "https://github.com/patternfly/patternfly-react/issues"
},
"homepage": "https://github.com/patternfly/patternfly-react/tree/main/packages/react-drag-drop#readme",
"scripts": {
"clean": "rimraf dist"
},
"dependencies": {
"@dnd-kit/core": "^6.0.8",
"@dnd-kit/modifiers": "^6.0.1",
"@dnd-kit/sortable": "^7.0.2",
"@patternfly/react-core": "^5.2.0-prerelease.41",
"@patternfly/react-icons": "^5.2.0-prerelease.9",
"@patternfly/react-styles": "^5.2.0-prerelease.6",
"memoize-one": "^5.1.0",
"resize-observer-polyfill": "^1.5.1"
},
"peerDependencies": {
"react": "^17 || ^18",
"react-dom": "^17 || ^18"
},
"devDependencies": {
"rimraf": "^2.6.2",
"typescript": "^4.7.4"
}
}
1 change: 1 addition & 0 deletions packages/react-drag-drop/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './next';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from 'react';
import { css } from '@patternfly/react-styles';
import dragButtonStyles from '@patternfly/react-styles/css/components/DataList/data-list';
import buttonStyles from '@patternfly/react-styles/css/components/Button/button';
import GripVerticalIcon from '@patternfly/react-icons/dist/esm/icons/grip-vertical-icon';

export interface DragButtonProps extends React.HTMLProps<HTMLButtonElement> {
/** Additional classes added to the drag button */
className?: string;
/** Sets button type */
type?: 'button' | 'submit' | 'reset';
/** Flag indicating if drag is disabled for the item */
isDisabled?: boolean;
}

export const DragButton: React.FunctionComponent<DragButtonProps> = ({ className, ...props }: DragButtonProps) => (
<button
className={css(className, buttonStyles.button, buttonStyles.modifiers.plain)}
aria-label="Drag button"
{...props}
>
<span className={css(dragButtonStyles.dataListItemDraggableIcon)}>
<GripVerticalIcon />
</span>
</button>
);
DragButton.displayName = 'DragButton';
Loading

0 comments on commit 19ddee7

Please sign in to comment.