From f1dbab75ae48f677aca8ee5d539ebeb4a99fed2c Mon Sep 17 00:00:00 2001 From: nicolethoen Date: Mon, 23 Jan 2023 16:46:12 -0500 Subject: [PATCH 1/3] feat(DragDrop): introduce new package and deprecate old implementation --- .../components/DataList/examples/DataList.md | 13 +- .../DataList/examples/DataListDraggable.tsx | 105 ----------- .../examples/DualListSelector.md | 20 --- .../src/components/DualListSelector/index.ts | 1 + packages/react-core/src/components/index.ts | 1 - .../components/DragDrop/DragDrop.tsx | 0 .../components/DragDrop/Draggable.tsx | 0 .../components/DragDrop/Droppable.tsx | 0 .../components/DragDrop/DroppableContext.ts | 0 .../DragDrop/__tests__/DragDrop.test.tsx | 0 .../__snapshots__/DragDrop.test.tsx.snap | 0 .../components/DragDrop/examples/DragDrop.md | 5 +- .../DragDrop/examples/DragDropBasic.tsx | 10 +- .../examples/DragDropMultipleLists.tsx | 12 +- .../components/DragDrop/index.ts | 1 + .../src/deprecated/components/index.ts | 1 + packages/react-docs/package.json | 1 + .../patternfly-docs/patternfly-docs.source.js | 5 + packages/react-drag-drop/package.json | 50 ++++++ .../src/components/DragDrop/DragButton.tsx | 22 +++ .../src/components/DragDrop/DragDropSort.tsx | 147 +++++++++++++++ .../src/components/DragDrop/Draggable.tsx | 58 ++++++ .../DragDrop/DraggableDataListItem.tsx | 51 ++++++ .../DraggableDualListSelectorListItem.tsx | 91 ++++++++++ .../src/components/DragDrop/Droppable.tsx | 27 +++ .../components/DragDrop/DroppableContext.ts | 6 + .../DragDrop/__tests__/DragDrop.test.tsx | 19 ++ .../__snapshots__/DragDrop.test.tsx.snap | 61 +++++++ .../DragDrop/examples/BasicSorting.tsx | 19 ++ .../examples/BasicSortingWithDragButton.tsx | 20 +++ .../DragDrop/examples/DataListDraggable.tsx | 42 +++++ .../components/DragDrop/examples/DragDrop.md | 57 ++++++ .../examples/DualListSelectorDraggable.tsx | 169 ++++++++++++++++++ .../src/components/DragDrop/index.ts | 1 + .../react-drag-drop/src/components/index.ts | 1 + packages/react-drag-drop/src/index.ts | 1 + packages/react-drag-drop/tsconfig.cjs.json | 8 + packages/react-drag-drop/tsconfig.json | 23 +++ packages/tsconfig.cjs.json | 3 + packages/tsconfig.json | 3 + scripts/promote.sh | 1 + 41 files changed, 907 insertions(+), 148 deletions(-) delete mode 100644 packages/react-core/src/components/DataList/examples/DataListDraggable.tsx rename packages/react-core/src/{ => deprecated}/components/DragDrop/DragDrop.tsx (100%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/Draggable.tsx (100%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/Droppable.tsx (100%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/DroppableContext.ts (100%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/__tests__/DragDrop.test.tsx (100%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap (100%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/examples/DragDrop.md (89%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/examples/DragDropBasic.tsx (83%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/examples/DragDropMultipleLists.tsx (88%) rename packages/react-core/src/{ => deprecated}/components/DragDrop/index.ts (70%) create mode 100644 packages/react-drag-drop/package.json create mode 100644 packages/react-drag-drop/src/components/DragDrop/DragButton.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/DragDropSort.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/Draggable.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/DraggableDataListItem.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/DraggableDualListSelectorListItem.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/Droppable.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/DroppableContext.ts create mode 100644 packages/react-drag-drop/src/components/DragDrop/__tests__/DragDrop.test.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap create mode 100644 packages/react-drag-drop/src/components/DragDrop/examples/BasicSorting.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/examples/BasicSortingWithDragButton.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/examples/DataListDraggable.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/examples/DragDrop.md create mode 100644 packages/react-drag-drop/src/components/DragDrop/examples/DualListSelectorDraggable.tsx create mode 100644 packages/react-drag-drop/src/components/DragDrop/index.ts create mode 100644 packages/react-drag-drop/src/components/index.ts create mode 100644 packages/react-drag-drop/src/index.ts create mode 100644 packages/react-drag-drop/tsconfig.cjs.json create mode 100644 packages/react-drag-drop/tsconfig.json diff --git a/packages/react-core/src/components/DataList/examples/DataList.md b/packages/react-core/src/components/DataList/examples/DataList.md index 88e96dd7b4f..6c4a2f26c5b 100644 --- a/packages/react-core/src/components/DataList/examples/DataList.md +++ b/packages/react-core/src/components/DataList/examples/DataList.md @@ -13,8 +13,7 @@ propComponents: 'DataListItemRow', 'DataListToggle', 'DataListContent', - 'DataListDragButton', - 'DataListControl' + 'DataListControl', ] --- @@ -84,16 +83,6 @@ 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: Keyboard accessibility and screen reader accessibility for the `DragDrop` component are still in development. - -```ts isBeta file="./DataListDraggable.tsx" - -``` - ### Small grid breakpoint ```ts file="./DataListSmGridBreakpoint.tsx" diff --git a/packages/react-core/src/components/DataList/examples/DataListDraggable.tsx b/packages/react-core/src/components/DataList/examples/DataListDraggable.tsx deleted file mode 100644 index c55244af0b1..00000000000 --- a/packages/react-core/src/components/DataList/examples/DataListDraggable.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react'; -import { - DataList, - DataListItem, - DataListCell, - DataListItemRow, - DataListCheck, - DataListControl, - DataListDragButton, - DataListItemCells, - DragDrop, - Draggable, - Droppable, - getUniqueId -} from '@patternfly/react-core'; - -interface ItemType { - id: string; - content: string; -} - -const getItems = (count: number) => - Array.from({ length: count }, (_, idx) => idx).map((idx) => ({ - id: `draggable-item-${idx}`, - content: `item ${idx} `.repeat(idx === 4 ? 20 : 1) - })); - -const reorder = (list: ItemType[], startIndex: number, endIndex: number) => { - const result = list; - const [removed] = result.splice(startIndex, 1); - result.splice(endIndex, 0, removed); - return result; -}; - -export const DataListDraggable: React.FunctionComponent = () => { - const [items, setItems] = React.useState(getItems(10)); - const [liveText, setLiveText] = React.useState(''); - - function onDrag(source) { - setLiveText(`Started dragging ${items[source.index].content}`); - // Return true to allow drag - return true; - } - - function onDragMove(source, dest) { - const newText = dest ? `Move ${items[source.index].content} to ${items[dest.index].content}` : 'Invalid drop zone'; - if (newText !== liveText) { - setLiveText(newText); - } - } - - function onDrop(source, dest) { - if (dest) { - const newItems = reorder(items, source.index, dest.index); - setItems(newItems); - - setLiveText('Dragging finished.'); - return true; // Signal that this is a valid drop and not to animate the item returning home. - } else { - setLiveText('Dragging cancelled. List unchanged.'); - } - } - - const uniqueId = getUniqueId(); - - return ( - - - - {items.map(({ id, content }) => ( - - - - - - - - - {content} - - ]} - /> - - - - ))} - - -
- {liveText} -
-
- Press space or enter to begin dragging, and use the arrow keys to navigate up or down. Press enter to confirm - the drag, or any other key to cancel the drag operation. -
-
- ); -}; diff --git a/packages/react-core/src/components/DualListSelector/examples/DualListSelector.md b/packages/react-core/src/components/DualListSelector/examples/DualListSelector.md index 60288c158ff..0eee867b386 100644 --- a/packages/react-core/src/components/DualListSelector/examples/DualListSelector.md +++ b/packages/react-core/src/components/DualListSelector/examples/DualListSelector.md @@ -85,26 +85,6 @@ The dual list selector can also be built in a composable manner to make customiz ``` -### Composable with drag and drop - -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 -- wrap the `DualListSelectorList` in a `Droppable` component -- wrap the `DualListSelectorListItem` components in a `Draggable` component -- define an `onDrop` callback which reorders the sortable options. - - The `onDrop` function provides the starting location and destination location for a dragged item. It should return - true to enable the 'drop' animation in the new location and false to enable the 'drop' animation back to the item's - old position. - - 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. - -```ts file="DualListSelectorComposableDragDrop.tsx" - -``` - ### Composable with tree ```ts file="DualListSelectorComposableTree.tsx" diff --git a/packages/react-core/src/components/DualListSelector/index.ts b/packages/react-core/src/components/DualListSelector/index.ts index d2b6deb96ff..73837532076 100644 --- a/packages/react-core/src/components/DualListSelector/index.ts +++ b/packages/react-core/src/components/DualListSelector/index.ts @@ -5,3 +5,4 @@ export * from './DualListSelectorPane'; export * from './DualListSelectorList'; export * from './DualListSelectorListItem'; export * from './DualListSelectorTree'; +export * from './DualListSelectorContext'; diff --git a/packages/react-core/src/components/index.ts b/packages/react-core/src/components/index.ts index a322279493d..d806b56dc93 100644 --- a/packages/react-core/src/components/index.ts +++ b/packages/react-core/src/components/index.ts @@ -76,7 +76,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'; diff --git a/packages/react-core/src/components/DragDrop/DragDrop.tsx b/packages/react-core/src/deprecated/components/DragDrop/DragDrop.tsx similarity index 100% rename from packages/react-core/src/components/DragDrop/DragDrop.tsx rename to packages/react-core/src/deprecated/components/DragDrop/DragDrop.tsx diff --git a/packages/react-core/src/components/DragDrop/Draggable.tsx b/packages/react-core/src/deprecated/components/DragDrop/Draggable.tsx similarity index 100% rename from packages/react-core/src/components/DragDrop/Draggable.tsx rename to packages/react-core/src/deprecated/components/DragDrop/Draggable.tsx diff --git a/packages/react-core/src/components/DragDrop/Droppable.tsx b/packages/react-core/src/deprecated/components/DragDrop/Droppable.tsx similarity index 100% rename from packages/react-core/src/components/DragDrop/Droppable.tsx rename to packages/react-core/src/deprecated/components/DragDrop/Droppable.tsx diff --git a/packages/react-core/src/components/DragDrop/DroppableContext.ts b/packages/react-core/src/deprecated/components/DragDrop/DroppableContext.ts similarity index 100% rename from packages/react-core/src/components/DragDrop/DroppableContext.ts rename to packages/react-core/src/deprecated/components/DragDrop/DroppableContext.ts diff --git a/packages/react-core/src/components/DragDrop/__tests__/DragDrop.test.tsx b/packages/react-core/src/deprecated/components/DragDrop/__tests__/DragDrop.test.tsx similarity index 100% rename from packages/react-core/src/components/DragDrop/__tests__/DragDrop.test.tsx rename to packages/react-core/src/deprecated/components/DragDrop/__tests__/DragDrop.test.tsx diff --git a/packages/react-core/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap b/packages/react-core/src/deprecated/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap similarity index 100% rename from packages/react-core/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap rename to packages/react-core/src/deprecated/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap diff --git a/packages/react-core/src/components/DragDrop/examples/DragDrop.md b/packages/react-core/src/deprecated/components/DragDrop/examples/DragDrop.md similarity index 89% rename from packages/react-core/src/components/DragDrop/examples/DragDrop.md rename to packages/react-core/src/deprecated/components/DragDrop/examples/DragDrop.md index b3a379223ee..139a9fe2e1d 100644 --- a/packages/react-core/src/components/DragDrop/examples/DragDrop.md +++ b/packages/react-core/src/deprecated/components/DragDrop/examples/DragDrop.md @@ -2,14 +2,15 @@ id: Drag and drop section: components propComponents: [DragDrop, Draggable, Droppable, DraggableItemPosition] -beta: true --- You can use the `DragDrop` component to move items in or between lists. The `DragDrop` component should contain `Droppable` components which contain `Draggable` components. +import { DragDrop, Draggable, Droppable, DraggableItemPosition } from '@patternfly/react-core/deprecated'; + ```ts noLive import React from 'react'; -import { DragDrop, Draggable, Droppable } from '@patternfly/react-core'; +import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; const DragDropCodeSample: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/DragDrop/examples/DragDropBasic.tsx b/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropBasic.tsx similarity index 83% rename from packages/react-core/src/components/DragDrop/examples/DragDropBasic.tsx rename to packages/react-core/src/deprecated/components/DragDrop/examples/DragDropBasic.tsx index 684c315bcf5..7a19414d120 100644 --- a/packages/react-core/src/components/DragDrop/examples/DragDropBasic.tsx +++ b/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropBasic.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { DragDrop, Draggable, Droppable } from '@patternfly/react-core'; +import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; interface ItemType { id: string; @@ -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(getItems(10)); function onDrop(source: SourceType, dest: DestinationType) { if (dest) { @@ -42,8 +42,8 @@ export const DragDropBasic: React.FunctionComponent = () => { return ( - {items.map(({ content }, i) => ( - + {items.map(({ id, content }) => ( + {content} ))} diff --git a/packages/react-core/src/components/DragDrop/examples/DragDropMultipleLists.tsx b/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropMultipleLists.tsx similarity index 88% rename from packages/react-core/src/components/DragDrop/examples/DragDropMultipleLists.tsx rename to packages/react-core/src/deprecated/components/DragDrop/examples/DragDropMultipleLists.tsx index 50cc54658c8..55116062c5a 100644 --- a/packages/react-core/src/components/DragDrop/examples/DragDropMultipleLists.tsx +++ b/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropMultipleLists.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { DragDrop, Draggable, Droppable, Split, SplitItem } from '@patternfly/react-core'; +import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; +import { Split, SplitItem } from '@patternfly/react-core'; interface ItemType { id: string; @@ -11,6 +12,11 @@ interface SourceType { index: number; } +interface MultipleListState { + items1: ItemType[]; + items2: ItemType[]; +} + interface DestinationType extends SourceType {} const getItems = (count: number, startIndex: number) => @@ -35,7 +41,7 @@ const move = (source: ItemType[], destination: ItemType[], sourceIndex: number, }; export const DragDropMultipleLists: React.FunctionComponent = () => { - const [items, setItems] = React.useState({ + const [items, setItems] = React.useState({ items1: getItems(10, 0), items2: getItems(5, 10) }); @@ -84,7 +90,7 @@ export const DragDropMultipleLists: React.FunctionComponent = () => { {Object.entries(items).map(([key, subitems]) => ( - {subitems.map(({ id, content }) => ( + {(subitems as ItemType[]).map(({ id, content }) => ( {content} diff --git a/packages/react-core/src/components/DragDrop/index.ts b/packages/react-core/src/deprecated/components/DragDrop/index.ts similarity index 70% rename from packages/react-core/src/components/DragDrop/index.ts rename to packages/react-core/src/deprecated/components/DragDrop/index.ts index 032ae9dfe38..7a4a6bd342e 100644 --- a/packages/react-core/src/components/DragDrop/index.ts +++ b/packages/react-core/src/deprecated/components/DragDrop/index.ts @@ -1,3 +1,4 @@ export * from './DragDrop'; export * from './Draggable'; export * from './Droppable'; +export * from './DroppableContext'; diff --git a/packages/react-core/src/deprecated/components/index.ts b/packages/react-core/src/deprecated/components/index.ts index b32add8bc6e..f652bb999e5 100644 --- a/packages/react-core/src/deprecated/components/index.ts +++ b/packages/react-core/src/deprecated/components/index.ts @@ -1,5 +1,6 @@ export * from './ApplicationLauncher'; export * from './ContextSelector'; +export * from './DragDrop'; export * from './Dropdown'; export * from './OptionsMenu'; export * from './PageHeader'; diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index b1e5b008ed9..4351f3bbd16 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -26,6 +26,7 @@ "@patternfly/react-charts": "^7.2.0-prerelease.4", "@patternfly/react-code-editor": "^5.2.0-prerelease.10", "@patternfly/react-core": "^5.2.0-prerelease.10", + "@patternfly/react-drag-drop": "^5.0.0-alpha.0", "@patternfly/react-icons": "^5.2.0-prerelease.3", "@patternfly/react-styles": "^5.2.0-prerelease.2", "@patternfly/react-table": "^5.2.0-prerelease.10", diff --git a/packages/react-docs/patternfly-docs/patternfly-docs.source.js b/packages/react-docs/patternfly-docs/patternfly-docs.source.js index b90f892c8d3..e3211c12faf 100644 --- a/packages/react-docs/patternfly-docs/patternfly-docs.source.js +++ b/packages/react-docs/patternfly-docs/patternfly-docs.source.js @@ -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'); @@ -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'); + // OUIA MD sourceMD(path.join(reactCorePath, 'helpers/OUIA/OUIA.md'), 'react'); }; diff --git a/packages/react-drag-drop/package.json b/packages/react-drag-drop/package.json new file mode 100644 index 00000000000..f25cfb65142 --- /dev/null +++ b/packages/react-drag-drop/package.json @@ -0,0 +1,50 @@ +{ + "name": "@patternfly/react-drag-drop", + "version": "5.0.0-alpha.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", + "tag": "alpha" + }, + "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.0.0-alpha.33", + "@patternfly/react-icons": "^5.0.0-alpha.4", + "@patternfly/react-styles": "^5.0.0-alpha.4", + "memoize-one": "^5.1.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "devDependencies": { + "rimraf": "^2.6.2", + "typescript": "^4.7.4" + } +} diff --git a/packages/react-drag-drop/src/components/DragDrop/DragButton.tsx b/packages/react-drag-drop/src/components/DragDrop/DragButton.tsx new file mode 100644 index 00000000000..1b82c2f28e8 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/DragButton.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import { css } from '@patternfly/react-styles'; +import dragButtonStyles from '@patternfly/react-styles/css/components/DataList/data-list'; +import GripVerticalIcon from '@patternfly/react-icons/dist/esm/icons/grip-vertical-icon'; + +export interface DragButtonProps extends React.HTMLProps { + /** 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 = ({ className, ...props }: DragButtonProps) => ( + +); +DragButton.displayName = 'DragButton'; diff --git a/packages/react-drag-drop/src/components/DragDrop/DragDropSort.tsx b/packages/react-drag-drop/src/components/DragDrop/DragDropSort.tsx new file mode 100644 index 00000000000..4b9ebe69feb --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/DragDropSort.tsx @@ -0,0 +1,147 @@ +import * as React from 'react'; +import { + DndContext, + closestCenter, + DragOverlay, + DndContextProps, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragEndEvent, + DragStartEvent +} from '@dnd-kit/core'; +import { + arrayMove, + SortableContext, + sortableKeyboardCoordinates, + verticalListSortingStrategy +} from '@dnd-kit/sortable'; +import { Draggable } from './Draggable'; +import { DragButton } from './DragButton'; +import { DraggableDataListItem } from './DraggableDataListItem'; +import { DraggableDualListSelectorListItem } from './DraggableDualListSelectorListItem'; + +export type DragDropSortDragEndEvent = DragEndEvent; +export type DragDropSortDragStartEvent = DragStartEvent; + +export interface DraggableObject { + /** Unique id of the draggable object */ + id: string; + /** Content rendered in the draggable object */ + content: React.ReactNode; + /** Props spread to the rendered wrapper of the draggable object */ + props?: any; +} + +export interface DragDropSortProps extends DndContextProps { + /** Custom defined content wrapper for draggable items. By default, draggable items are wrapped in a styled div. + * Intended to be a 'DataList' or 'DualListSelectorList' without children. */ + children?: React.ReactElement; + /** Sorted array of draggable objects */ + items: DraggableObject[]; + /** Callback when user drops a draggable object */ + onDrop: (event: DragDropSortDragEndEvent, items: DraggableObject[], oldIndex?: number, newIndex?: number) => void; + /** Callback when use begins dragging a draggable object */ + onDrag?: (event: DragDropSortDragStartEvent, oldIndex: number) => void; + /** The variant determines which component wraps the draggable object. + * Default and defaultWithHandle varaints wrap the draggable object in a div. + * DataList vairant wraps the draggable object in a DataListItem + * DualListSelectorList variant wraps the draggable objects in a DualListSelectorListItem and a div.pf-c-dual-list-selector__item-text element + * TableComposable variant wraps the draggable objects in TODO + * */ + variant?: 'default' | 'defaultWithHandle' | 'DataList' | 'DualListSelectorList' | 'TableComposable'; +} + +export const DragDropSort: React.FunctionComponent = ({ + items, + onDrop = () => {}, + onDrag = () => {}, + variant = 'default', + children, + ...props +}: DragDropSortProps) => { + const [activeId, setActiveId] = React.useState(null); + const [dragging, setDragging] = React.useState(false); + + const itemIds = React.useMemo(() => (items ? Array.from(items, item => item.id as string) : []), [items]); + + const getItemById = (id: string): DraggableObject => items.find(item => item.id === id); + + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates + }) + ); + + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + const oldIndex = itemIds.indexOf(active.id as string); + const newIndex = itemIds.indexOf(over.id as string); + const newItems = arrayMove(items, oldIndex, newIndex); + setDragging(false); + onDrop(event, newItems, oldIndex, newIndex); + return newItems; + }; + + const handleDragStart = (event: DragStartEvent) => { + setActiveId(event.active.id as string); + setDragging(true); + onDrag(event, itemIds.indexOf(event.active.id as string)); + }; + + const renderedChildren = ( + + {items.map((item: DraggableObject) => { + switch (variant) { + case 'DualListSelectorList': + return ( + + {item.content} + + ); + case 'DataList': + return ( + + {item.content} + + ); + default: + return ( + + {item.content} + + ); + } + })} + +
+ {variant !== 'default' && } + {activeId ? getItemById(activeId).content : null} +
+
+
+ ); + + return ( + + {children && React.cloneElement(children, { + children: renderedChildren, + className: `pf-c-droppable ${dragging ? 'pf-m-dragging' : ''}` + })} + {!children && ( +
+ {renderedChildren} +
+ )} +
+ ); +}; +DragDropSort.displayName = 'DragDropSort'; diff --git a/packages/react-drag-drop/src/components/DragDrop/Draggable.tsx b/packages/react-drag-drop/src/components/DragDrop/Draggable.tsx new file mode 100644 index 00000000000..a1d7e80876d --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/Draggable.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; +import { useSortable } from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/DragDrop/drag-drop'; +import { DragButton } from './DragButton'; + +export interface DraggableProps extends React.HTMLProps { + /** Content rendered inside DragDrop */ + children?: React.ReactNode; + /** Don't wrap the component in a div. Requires passing a single child. */ + hasNoWrapper?: boolean; + /** Class to add to outer div */ + className?: string; + /** */ + id?: string; + /** */ + useDragButton?: boolean; +} + +export const Draggable: React.FunctionComponent = ({ + children, + id, + className, + useDragButton = false, + ...props +}: DraggableProps) => { + const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ + id + }); + + const style = { + transform: CSS.Transform.toString(transform), + transition + }; + + return useDragButton ? ( +
+ + {children} +
+ ) : ( +
+ {children} +
+ ); +}; +Draggable.displayName = 'Draggable'; diff --git a/packages/react-drag-drop/src/components/DragDrop/DraggableDataListItem.tsx b/packages/react-drag-drop/src/components/DragDrop/DraggableDataListItem.tsx new file mode 100644 index 00000000000..ca9dde501b7 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/DraggableDataListItem.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import { useSortable } from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/DataList/data-list'; +import { DragButton } from './DragButton'; +import { DataListItemRow, DataListControl } from '@patternfly/react-core'; + +export interface DraggableDataListItemObject { + id?: string; + content?: React.ReactNode; +} + +export interface DraggableDataListItemProps extends React.HTMLProps { + /** Content rendered inside DragDrop */ + children?: React.ReactNode; + /** Don't wrap the component in a div. Requires passing a single child. */ + hasNoWrapper?: boolean; + /** Class to add to outer div */ + className?: string; + /** */ + id?: string; +} + +export const DraggableDataListItem: React.FunctionComponent = ({ + children, + id, + className, + ...props +}: DraggableDataListItemProps) => { + const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ + id + }); + + const style = { + transform: CSS.Transform.toString(transform), + transition + }; + + return ( +
  • + + + + + {children} + +
  • + ); +}; +DraggableDataListItem.displayName = 'DraggableDataListItem'; diff --git a/packages/react-drag-drop/src/components/DragDrop/DraggableDualListSelectorListItem.tsx b/packages/react-drag-drop/src/components/DragDrop/DraggableDualListSelectorListItem.tsx new file mode 100644 index 00000000000..6c0ec079555 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/DraggableDualListSelectorListItem.tsx @@ -0,0 +1,91 @@ +import * as React from 'react'; +import { useSortable } from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; +import { DragButton } from './DragButton'; +import { DualListSelectorListContext } from '@patternfly/react-core'; + +export interface DraggableObject { + id?: string; + content?: React.ReactNode; +} + +export interface DraggableDualListSelectorListItemProps extends React.HTMLProps { + /** Content rendered inside DragDrop */ + children?: React.ReactNode; + /** Don't wrap the component in a div. Requires passing a single child. */ + hasNoWrapper?: boolean; + /** Class to add to outer div */ + className?: string; + /** */ + id?: string; + /** Flag indicating the list item is currently selected. */ + isSelected?: boolean; + /** Callback fired when an option is selected. */ + onOptionSelect?: (e: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent, id?: string) => void; + /** @hide Internal field used to keep track of order of unfiltered options. */ + orderIndex?: number; + /** @hide Forwarded ref */ + innerRef?: React.RefObject; + /** Flag indicating if the dual list selector is in a disabled state */ + isDisabled?: boolean; +} + +export const DraggableDualListSelectorListItem: React.FunctionComponent = ({ + children, + id, + className, + orderIndex, + isSelected, + onOptionSelect, + ...props +}: DraggableDualListSelectorListItemProps) => { + const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ + id + }); + + const { setFocusedOption } = React.useContext(DualListSelectorListContext); + + const style = { + transform: CSS.Transform.toString(transform), + transition + }; + + return ( + + ); +}; +DraggableDualListSelectorListItem.displayName = 'DraggableDualListSelectorListItem'; diff --git a/packages/react-drag-drop/src/components/DragDrop/Droppable.tsx b/packages/react-drag-drop/src/components/DragDrop/Droppable.tsx new file mode 100644 index 00000000000..ccb05fe9e26 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/Droppable.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import { useDroppable } from '@dnd-kit/core'; + +interface DroppableProps extends React.HTMLProps { + /** Content rendered inside DragDrop */ + children?: React.ReactNode; + /** Class to add to outer div */ + className?: string; + /** Name of zone that items can be dragged between. Should specify if there is more than one Droppable on the page. */ + zone?: string; + /** Id to be passed back on drop events */ + droppableId?: string; + /** Don't wrap the component in a div. Requires passing a single child. */ + hasNoWrapper?: boolean; +} + +export const Droppable: React.FunctionComponent = ({ children, ...props }: DroppableProps) => { + const { isOver, setNodeRef } = useDroppable({ id: 'droppable' }); + const style = { color: isOver ? 'green' : undefined }; + + return ( +
    + {children} +
    + ); +}; +Droppable.displayName = 'Droppable'; diff --git a/packages/react-drag-drop/src/components/DragDrop/DroppableContext.ts b/packages/react-drag-drop/src/components/DragDrop/DroppableContext.ts new file mode 100644 index 00000000000..888cb4fc66f --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/DroppableContext.ts @@ -0,0 +1,6 @@ +import * as React from 'react'; + +export const DroppableContext = React.createContext({ + zone: 'defaultDroppableZone', + droppableId: 'defaultDroppableId' +}); diff --git a/packages/react-drag-drop/src/components/DragDrop/__tests__/DragDrop.test.tsx b/packages/react-drag-drop/src/components/DragDrop/__tests__/DragDrop.test.tsx new file mode 100644 index 00000000000..42b33a0f6e3 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/__tests__/DragDrop.test.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { DragDropSort } from '../'; + +test('renders some divs', () => { + const { asFragment } = render( +
    + {}} + /> +
    + ); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-drag-drop/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap b/packages/react-drag-drop/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap new file mode 100644 index 00000000000..50bd3164230 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders some divs 1`] = ` + +
    +
    +
    + one +
    +
    + two +
    +
    + three +
    +
    + +
    +
    + +`; diff --git a/packages/react-drag-drop/src/components/DragDrop/examples/BasicSorting.tsx b/packages/react-drag-drop/src/components/DragDrop/examples/BasicSorting.tsx new file mode 100644 index 00000000000..40021ef9f60 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/examples/BasicSorting.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { DragDropSort, DraggableObject } from '@patternfly/react-drag-drop'; + +export const BasicSorting: React.FunctionComponent = () => { + const [items, setItems] = React.useState([ + { id: 'basic-1', content: 'one' }, + { id: 'basic-2', content: 'two' }, + { id: 'basic-3', content: 'three' } + ]); + + return ( + { + setItems(newItems); + }} + /> + ); +}; diff --git a/packages/react-drag-drop/src/components/DragDrop/examples/BasicSortingWithDragButton.tsx b/packages/react-drag-drop/src/components/DragDrop/examples/BasicSortingWithDragButton.tsx new file mode 100644 index 00000000000..0cea4a69962 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/examples/BasicSortingWithDragButton.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { DragDropSort, DraggableObject } from '@patternfly/react-drag-drop'; + +export const BasicSortingWithDragButton: React.FunctionComponent = () => { + const [items, setItems] = React.useState([ + { id: 'with-button-1', content: 'one' }, + { id: 'with-button-2', content: 'two' }, + { id: 'with-button-3', content: 'three' } + ]); + + return ( + { + setItems(newItems); + }} + /> + ); +}; diff --git a/packages/react-drag-drop/src/components/DragDrop/examples/DataListDraggable.tsx b/packages/react-drag-drop/src/components/DragDrop/examples/DataListDraggable.tsx new file mode 100644 index 00000000000..48f3ffe8626 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/examples/DataListDraggable.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { DataList, DataListCell, DataListCheck, DataListControl, DataListItemCells } from '@patternfly/react-core'; +import { DragDropSort, DraggableObject } from '@patternfly/react-drag-drop'; + +const getItems = (count: number): DraggableObject[] => + Array.from({ length: count }, (_, idx) => idx).map(idx => ({ + id: `data-list-item-${idx}`, + content: ( + <> + + + + + {`item-${idx}`} + + ]} + /> + + ) + })); + +export const DataListDraggable: React.FunctionComponent = props => { + const [items, setItems] = React.useState(getItems(10)); + + return ( + { + setItems(newItems); + }} + variant="DataList" + > + + + ); +}; diff --git a/packages/react-drag-drop/src/components/DragDrop/examples/DragDrop.md b/packages/react-drag-drop/src/components/DragDrop/examples/DragDrop.md new file mode 100644 index 00000000000..7b3395b2d77 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/examples/DragDrop.md @@ -0,0 +1,57 @@ +--- +id: Drag and drop +section: components +cssPrefix: pf-c-drag-drop +propComponents: [ + DragDropSort, + DraggableObject +] +hideNavItem: true +--- +Note: DragDrop lives in its own package at @patternfly/react-drag-drop!' + +import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon'; +import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; +import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon'; +import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; +import PficonSortCommonAscIcon from '@patternfly/react-icons/dist/esm/icons/pficon-sort-common-asc-icon'; + +import { DragDropSort, DraggableObject } from '@patternfly/react-drag-drop'; + +## Sorting examples +### Basic drag and drop sorting +```ts isBeta file="./BasicSorting.tsx" +``` + +### Basic drag and drop sorting with drag button + +```ts isBeta file="./BasicSortingWithDragButton.tsx" +``` + +### Drag and drop sortable data list + +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: Keyboard accessibility and screen reader accessibility for the `DragDrop` component are still in development. + +```ts isBeta file="./DataListDraggable.tsx" +``` + +### Drag and drop sortable dual list selector + +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 `DragDropSort` component +- wrap the `DualListSelectorList` in a `Droppable` component +- wrap the `DualListSelectorListItem` components in a `Draggable` component +- define an `onDrop` callback which reorders the sortable options. + - The `onDrop` function provides the starting location and destination location for a dragged item. It should return + true to enable the 'drop' animation in the new location and false to enable the 'drop' animation back to the item's + old position. + - 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 `DragDropSort` component are still in development. + +```ts file="./DualListSelectorDraggable.tsx" +``` diff --git a/packages/react-drag-drop/src/components/DragDrop/examples/DualListSelectorDraggable.tsx b/packages/react-drag-drop/src/components/DragDrop/examples/DualListSelectorDraggable.tsx new file mode 100644 index 00000000000..52337adaedf --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/examples/DualListSelectorDraggable.tsx @@ -0,0 +1,169 @@ +import React from 'react'; +import { + DualListSelector, + DualListSelectorPane, + DualListSelectorList, + DualListSelectorListItem, + DualListSelectorControlsWrapper, + DualListSelectorControl +} from '@patternfly/react-core'; +import { DragDropSort, DragDropSortDragEndEvent, DraggableObject } from '@patternfly/react-drag-drop'; + +import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon'; +import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; +import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon'; +import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; + +export const ComposableDualListSelector: React.FunctionComponent = () => { + const [ignoreNextOptionSelect, setIgnoreNextOptionSelect] = React.useState(false); + const [availableOptions, setAvailableOptions] = React.useState([ + { text: 'Apple', selected: false, isVisible: true }, + { text: 'Banana', selected: false, isVisible: true }, + { text: 'Pineapple', selected: false, isVisible: true } + ]); + const [chosenOptions, setChosenOptions] = React.useState([ + { text: 'Orange', selected: false, isVisible: true }, + { text: 'Grape', selected: false, isVisible: true }, + { text: 'Peach', selected: false, isVisible: true }, + { text: 'Strawberry', selected: false, isVisible: true } + ]); + + const moveSelected = fromAvailable => { + const sourceOptions = fromAvailable ? availableOptions : chosenOptions; + const destinationOptions = fromAvailable ? chosenOptions : availableOptions; + for (let i = 0; i < sourceOptions.length; i++) { + const option = sourceOptions[i]; + if (option.selected && option.isVisible) { + sourceOptions.splice(i, 1); + destinationOptions.push(option); + option.selected = false; + i--; + } + } + if (fromAvailable) { + setAvailableOptions([...sourceOptions]); + setChosenOptions([...destinationOptions]); + } else { + setChosenOptions([...sourceOptions]); + setAvailableOptions([...destinationOptions]); + } + }; + + const moveAll = fromAvailable => { + if (fromAvailable) { + setChosenOptions([...availableOptions.filter(x => x.isVisible), ...chosenOptions]); + setAvailableOptions([...availableOptions.filter(x => !x.isVisible)]); + } else { + setAvailableOptions([...chosenOptions.filter(x => x.isVisible), ...availableOptions]); + setChosenOptions([...chosenOptions.filter(x => !x.isVisible)]); + } + }; + + const onOptionSelect = (event, index, isChosen) => { + if (ignoreNextOptionSelect) { + setIgnoreNextOptionSelect(false); + return; + } + if (isChosen) { + const newChosen = [...chosenOptions]; + newChosen[index].selected = !chosenOptions[index].selected; + setChosenOptions(newChosen); + } else { + const newAvailable = [...availableOptions]; + newAvailable[index].selected = !availableOptions[index].selected; + setAvailableOptions(newAvailable); + } + }; + + const onDrop = (event: DragDropSortDragEndEvent, newItems: DraggableObject[], oldIndex: number, newIndex: number) => { + const newList = [...chosenOptions]; + const [removed] = newList.splice(oldIndex, 1); + newList.splice(newIndex, 0, removed); + setChosenOptions(newList); + }; + + const sortableChosenOptions = chosenOptions.map((option, index) => + option.isVisible + ? { + id: `composable-available-option-${option.text}`, + content: option.text, + props: { + key: index, + isSelected: option.selected, + onOptionSelect: e => onOptionSelect(e, index, true) + } + } + : null + ); + + return ( + + x.selected && x.isVisible).length} of ${ + availableOptions.filter(x => x.isVisible).length + } options selected`} + > + + {availableOptions.map((option, index) => + option.isVisible ? ( + onOptionSelect(e, index, false)} + > + {option.text} + + ) : null + )} + + + + option.selected)} + onClick={() => moveSelected(true)} + aria-label="Add selected" + > + + + moveAll(true)} + aria-label="Add all" + > + + + moveAll(false)} + aria-label="Remove all" + > + + + moveSelected(false)} + isDisabled={!chosenOptions.some(option => option.selected)} + aria-label="Remove selected" + > + + + + x.selected && x.isVisible).length} of ${ + chosenOptions.filter(x => x.isVisible).length + } options selected`} + isChosen + > + + + + + + ); +}; diff --git a/packages/react-drag-drop/src/components/DragDrop/index.ts b/packages/react-drag-drop/src/components/DragDrop/index.ts new file mode 100644 index 00000000000..ddc081716b1 --- /dev/null +++ b/packages/react-drag-drop/src/components/DragDrop/index.ts @@ -0,0 +1 @@ +export * from './DragDropSort'; diff --git a/packages/react-drag-drop/src/components/index.ts b/packages/react-drag-drop/src/components/index.ts new file mode 100644 index 00000000000..99bbd1480e6 --- /dev/null +++ b/packages/react-drag-drop/src/components/index.ts @@ -0,0 +1 @@ +export * from './DragDrop'; diff --git a/packages/react-drag-drop/src/index.ts b/packages/react-drag-drop/src/index.ts new file mode 100644 index 00000000000..07635cbbc8e --- /dev/null +++ b/packages/react-drag-drop/src/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/packages/react-drag-drop/tsconfig.cjs.json b/packages/react-drag-drop/tsconfig.cjs.json new file mode 100644 index 00000000000..578d46af9d3 --- /dev/null +++ b/packages/react-drag-drop/tsconfig.cjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist/js", + "module": "commonjs", + "tsBuildInfoFile": "dist/cjs.tsbuildinfo" + } +} diff --git a/packages/react-drag-drop/tsconfig.json b/packages/react-drag-drop/tsconfig.json new file mode 100644 index 00000000000..f08aeb83272 --- /dev/null +++ b/packages/react-drag-drop/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist/esm", + "tsBuildInfoFile": "dist/esm.tsbuildinfo" + }, + "include": [ + "./src/*", + "./src/**/*" + ], + "references": [ + { + "path": "../react-core" + }, + { + "path": "../react-icons" + }, + { + "path": "../react-styles" + } + ] +} diff --git a/packages/tsconfig.cjs.json b/packages/tsconfig.cjs.json index 6a79555e886..607146bbcac 100644 --- a/packages/tsconfig.cjs.json +++ b/packages/tsconfig.cjs.json @@ -10,6 +10,9 @@ { "path": "./react-core/tsconfig.cjs.json" }, + { + "path": "./react-drag-drop/tsconfig.cjs.json" + }, { "path": "./react-icons/tsconfig.cjs.json" }, diff --git a/packages/tsconfig.json b/packages/tsconfig.json index 8e6c82bdb5f..b7ea8c38508 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -10,6 +10,9 @@ { "path": "./react-core" }, + { + "path": "./react-drag-drop" + }, { "path": "./react-icons" }, diff --git a/scripts/promote.sh b/scripts/promote.sh index 0464729f77b..26118a1e43d 100755 --- a/scripts/promote.sh +++ b/scripts/promote.sh @@ -4,6 +4,7 @@ packages=( @patternfly/react-charts @patternfly/react-code-editor @patternfly/react-core + @patternfly/react-drag-drop @patternfly/react-icons @patternfly/react-styles @patternfly/react-table From c9a211d0bf75493b04d33197289da6a64de5fdc4 Mon Sep 17 00:00:00 2001 From: nicolethoen Date: Tue, 17 Oct 2023 14:07:38 -0400 Subject: [PATCH 2/3] refactor a bunch --- .../components/DragDrop/DragDrop.tsx | 0 .../components/DragDrop/Draggable.tsx | 0 .../components/DragDrop/Droppable.tsx | 0 .../components/DragDrop/DroppableContext.ts | 0 .../DragDrop/__tests__/DragDrop.test.tsx | 0 .../__snapshots__/DragDrop.test.tsx.snap | 0 .../components/DragDrop/examples/DragDrop.md | 5 +- .../DragDrop/examples/DragDropBasic.tsx | 2 +- .../examples/DragDropMultipleLists.tsx | 3 +- .../components/DragDrop/index.ts | 0 .../src/components/DualListSelector/index.ts | 1 + packages/react-core/src/components/index.ts | 1 + .../src/deprecated/components/index.ts | 1 - packages/react-docs/package.json | 12 +++++ .../patternfly-docs/patternfly-docs.source.js | 2 +- packages/react-drag-drop/package.json | 15 +++--- .../src/components/DragDrop/DragButton.tsx | 3 +- .../src/components/DragDrop/DragDropSort.tsx | 13 +++-- .../DraggableDualListSelectorListItem.tsx | 2 +- .../components/DragDrop/examples/DragDrop.md | 1 + yarn.lock | 54 +++++++++++++++++++ 21 files changed, 92 insertions(+), 23 deletions(-) rename packages/react-core/src/{deprecated => }/components/DragDrop/DragDrop.tsx (100%) rename packages/react-core/src/{deprecated => }/components/DragDrop/Draggable.tsx (100%) rename packages/react-core/src/{deprecated => }/components/DragDrop/Droppable.tsx (100%) rename packages/react-core/src/{deprecated => }/components/DragDrop/DroppableContext.ts (100%) rename packages/react-core/src/{deprecated => }/components/DragDrop/__tests__/DragDrop.test.tsx (100%) rename packages/react-core/src/{deprecated => }/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap (100%) rename packages/react-core/src/{deprecated => }/components/DragDrop/examples/DragDrop.md (89%) rename packages/react-core/src/{deprecated => }/components/DragDrop/examples/DragDropBasic.tsx (98%) rename packages/react-core/src/{deprecated => }/components/DragDrop/examples/DragDropMultipleLists.tsx (95%) rename packages/react-core/src/{deprecated => }/components/DragDrop/index.ts (100%) diff --git a/packages/react-core/src/deprecated/components/DragDrop/DragDrop.tsx b/packages/react-core/src/components/DragDrop/DragDrop.tsx similarity index 100% rename from packages/react-core/src/deprecated/components/DragDrop/DragDrop.tsx rename to packages/react-core/src/components/DragDrop/DragDrop.tsx diff --git a/packages/react-core/src/deprecated/components/DragDrop/Draggable.tsx b/packages/react-core/src/components/DragDrop/Draggable.tsx similarity index 100% rename from packages/react-core/src/deprecated/components/DragDrop/Draggable.tsx rename to packages/react-core/src/components/DragDrop/Draggable.tsx diff --git a/packages/react-core/src/deprecated/components/DragDrop/Droppable.tsx b/packages/react-core/src/components/DragDrop/Droppable.tsx similarity index 100% rename from packages/react-core/src/deprecated/components/DragDrop/Droppable.tsx rename to packages/react-core/src/components/DragDrop/Droppable.tsx diff --git a/packages/react-core/src/deprecated/components/DragDrop/DroppableContext.ts b/packages/react-core/src/components/DragDrop/DroppableContext.ts similarity index 100% rename from packages/react-core/src/deprecated/components/DragDrop/DroppableContext.ts rename to packages/react-core/src/components/DragDrop/DroppableContext.ts diff --git a/packages/react-core/src/deprecated/components/DragDrop/__tests__/DragDrop.test.tsx b/packages/react-core/src/components/DragDrop/__tests__/DragDrop.test.tsx similarity index 100% rename from packages/react-core/src/deprecated/components/DragDrop/__tests__/DragDrop.test.tsx rename to packages/react-core/src/components/DragDrop/__tests__/DragDrop.test.tsx diff --git a/packages/react-core/src/deprecated/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap b/packages/react-core/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap similarity index 100% rename from packages/react-core/src/deprecated/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap rename to packages/react-core/src/components/DragDrop/__tests__/__snapshots__/DragDrop.test.tsx.snap diff --git a/packages/react-core/src/deprecated/components/DragDrop/examples/DragDrop.md b/packages/react-core/src/components/DragDrop/examples/DragDrop.md similarity index 89% rename from packages/react-core/src/deprecated/components/DragDrop/examples/DragDrop.md rename to packages/react-core/src/components/DragDrop/examples/DragDrop.md index 139a9fe2e1d..7e700e1c8e8 100644 --- a/packages/react-core/src/deprecated/components/DragDrop/examples/DragDrop.md +++ b/packages/react-core/src/components/DragDrop/examples/DragDrop.md @@ -2,15 +2,14 @@ id: Drag and drop section: components propComponents: [DragDrop, Draggable, Droppable, DraggableItemPosition] +title: React - next --- You can use the `DragDrop` component to move items in or between lists. The `DragDrop` component should contain `Droppable` components which contain `Draggable` components. -import { DragDrop, Draggable, Droppable, DraggableItemPosition } from '@patternfly/react-core/deprecated'; - ```ts noLive import React from 'react'; -import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; +import { DragDrop, Draggable, Droppable } from '@patternfly/react-core'; const DragDropCodeSample: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropBasic.tsx b/packages/react-core/src/components/DragDrop/examples/DragDropBasic.tsx similarity index 98% rename from packages/react-core/src/deprecated/components/DragDrop/examples/DragDropBasic.tsx rename to packages/react-core/src/components/DragDrop/examples/DragDropBasic.tsx index 7a19414d120..d80a6a7f213 100644 --- a/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropBasic.tsx +++ b/packages/react-core/src/components/DragDrop/examples/DragDropBasic.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; +import { DragDrop, Draggable, Droppable } from '@patternfly/react-core'; interface ItemType { id: string; diff --git a/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropMultipleLists.tsx b/packages/react-core/src/components/DragDrop/examples/DragDropMultipleLists.tsx similarity index 95% rename from packages/react-core/src/deprecated/components/DragDrop/examples/DragDropMultipleLists.tsx rename to packages/react-core/src/components/DragDrop/examples/DragDropMultipleLists.tsx index 55116062c5a..0400633987f 100644 --- a/packages/react-core/src/deprecated/components/DragDrop/examples/DragDropMultipleLists.tsx +++ b/packages/react-core/src/components/DragDrop/examples/DragDropMultipleLists.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; -import { Split, SplitItem } from '@patternfly/react-core'; +import { DragDrop, Draggable, Droppable, Split, SplitItem } from '@patternfly/react-core'; interface ItemType { id: string; diff --git a/packages/react-core/src/deprecated/components/DragDrop/index.ts b/packages/react-core/src/components/DragDrop/index.ts similarity index 100% rename from packages/react-core/src/deprecated/components/DragDrop/index.ts rename to packages/react-core/src/components/DragDrop/index.ts diff --git a/packages/react-core/src/components/DualListSelector/index.ts b/packages/react-core/src/components/DualListSelector/index.ts index 73837532076..7f66aa3a037 100644 --- a/packages/react-core/src/components/DualListSelector/index.ts +++ b/packages/react-core/src/components/DualListSelector/index.ts @@ -1,4 +1,5 @@ export * from './DualListSelector'; +export * from './DualListSelectorContext'; export * from './DualListSelectorControl'; export * from './DualListSelectorControlsWrapper'; export * from './DualListSelectorPane'; diff --git a/packages/react-core/src/components/index.ts b/packages/react-core/src/components/index.ts index d806b56dc93..a4338497ba5 100644 --- a/packages/react-core/src/components/index.ts +++ b/packages/react-core/src/components/index.ts @@ -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'; diff --git a/packages/react-core/src/deprecated/components/index.ts b/packages/react-core/src/deprecated/components/index.ts index f652bb999e5..b32add8bc6e 100644 --- a/packages/react-core/src/deprecated/components/index.ts +++ b/packages/react-core/src/deprecated/components/index.ts @@ -1,6 +1,5 @@ export * from './ApplicationLauncher'; export * from './ContextSelector'; -export * from './DragDrop'; export * from './Dropdown'; export * from './OptionsMenu'; export * from './PageHeader'; diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index 4351f3bbd16..f5efe799288 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -22,6 +22,7 @@ "test:a11y": "patternfly-a11y --config patternfly-a11y.config" }, "dependencies": { +<<<<<<< HEAD "@patternfly/patternfly": "5.2.0-prerelease.2", "@patternfly/react-charts": "^7.2.0-prerelease.4", "@patternfly/react-code-editor": "^5.2.0-prerelease.10", @@ -31,6 +32,17 @@ "@patternfly/react-styles": "^5.2.0-prerelease.2", "@patternfly/react-table": "^5.2.0-prerelease.10", "@patternfly/react-tokens": "^5.2.0-prerelease.3" +======= + "@patternfly/patternfly": "5.2.0-prerelease.1", + "@patternfly/react-charts": "^7.2.0-prerelease.2", + "@patternfly/react-code-editor": "^5.2.0-prerelease.2", + "@patternfly/react-core": "^5.2.0-prerelease.2", + "@patternfly/react-drag-drop": "^5.2.0-prelease.0", + "@patternfly/react-icons": "^5.2.0-prerelease.1", + "@patternfly/react-styles": "^5.2.0-prerelease.1", + "@patternfly/react-table": "^5.2.0-prerelease.2", + "@patternfly/react-tokens": "^5.2.0-prerelease.1" +>>>>>>> 4380b50910 (refactor a bunch) }, "devDependencies": { "@patternfly/documentation-framework": "^5.0.15", diff --git a/packages/react-docs/patternfly-docs/patternfly-docs.source.js b/packages/react-docs/patternfly-docs/patternfly-docs.source.js index e3211c12faf..0d6f20116d6 100644 --- a/packages/react-docs/patternfly-docs/patternfly-docs.source.js +++ b/packages/react-docs/patternfly-docs/patternfly-docs.source.js @@ -44,7 +44,7 @@ module.exports = (baseSourceMD, sourceProps) => { sourceMD(path.join(reactCodeEditorPath, '/**/examples/*.md'), 'react'); // Drag drop MD - sourceMD(path.join(reactDragDropPath, '/**/examples/*.md'), 'react'); + sourceMD(path.join(reactDragDropPath, '/**/examples/*.md'), 'react-next'); // OUIA MD sourceMD(path.join(reactCorePath, 'helpers/OUIA/OUIA.md'), 'react'); diff --git a/packages/react-drag-drop/package.json b/packages/react-drag-drop/package.json index f25cfb65142..168e722a531 100644 --- a/packages/react-drag-drop/package.json +++ b/packages/react-drag-drop/package.json @@ -1,14 +1,13 @@ { "name": "@patternfly/react-drag-drop", - "version": "5.0.0-alpha.0", + "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", - "tag": "alpha" + "access": "public" }, "patternfly:src": "src/", "repository": { @@ -33,15 +32,15 @@ "@dnd-kit/core": "^6.0.8", "@dnd-kit/modifiers": "^6.0.1", "@dnd-kit/sortable": "^7.0.2", - "@patternfly/react-core": "^5.0.0-alpha.33", - "@patternfly/react-icons": "^5.0.0-alpha.4", - "@patternfly/react-styles": "^5.0.0-alpha.4", + "@patternfly/react-core": "^5.2.0-prerelease.2", + "@patternfly/react-icons": "^5.2.0-prerelease.1", + "@patternfly/react-styles": "^5.2.0-prerelease.1", "memoize-one": "^5.1.0", "resize-observer-polyfill": "^1.5.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^17 || ^18", + "react-dom": "^17 || ^18" }, "devDependencies": { "rimraf": "^2.6.2", diff --git a/packages/react-drag-drop/src/components/DragDrop/DragButton.tsx b/packages/react-drag-drop/src/components/DragDrop/DragButton.tsx index 1b82c2f28e8..a559839b257 100644 --- a/packages/react-drag-drop/src/components/DragDrop/DragButton.tsx +++ b/packages/react-drag-drop/src/components/DragDrop/DragButton.tsx @@ -1,6 +1,7 @@ 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 { @@ -13,7 +14,7 @@ export interface DragButtonProps extends React.HTMLProps { } export const DragButton: React.FunctionComponent = ({ className, ...props }: DragButtonProps) => ( -