chore: add sortable group component which using react-beautiful-dnd
This commit is contained in:
parent
f309000a0c
commit
91ade2ab55
@ -288,6 +288,9 @@ importers:
|
|||||||
react:
|
react:
|
||||||
specifier: ^18.2.0
|
specifier: ^18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
react-beautiful-dnd:
|
||||||
|
specifier: ^13.1.1
|
||||||
|
version: 13.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||||
react-day-picker:
|
react-day-picker:
|
||||||
specifier: ^8.10.1
|
specifier: ^8.10.1
|
||||||
version: 8.10.1(date-fns@3.6.0)(react@18.2.0)
|
version: 8.10.1(date-fns@3.6.0)(react@18.2.0)
|
||||||
@ -376,6 +379,9 @@ importers:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^18.2.22
|
specifier: ^18.2.22
|
||||||
version: 18.2.78
|
version: 18.2.78
|
||||||
|
'@types/react-beautiful-dnd':
|
||||||
|
specifier: ^13.1.8
|
||||||
|
version: 13.1.8
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: ^18.2.7
|
specifier: ^18.2.7
|
||||||
version: 18.2.7
|
version: 18.2.7
|
||||||
@ -4707,6 +4713,9 @@ packages:
|
|||||||
'@types/range-parser@1.2.4':
|
'@types/range-parser@1.2.4':
|
||||||
resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
|
resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
|
||||||
|
|
||||||
|
'@types/react-beautiful-dnd@13.1.8':
|
||||||
|
resolution: {integrity: sha512-E3TyFsro9pQuK4r8S/OL6G99eq7p8v29sX0PM7oT8Z+PJfZvSQTx4zTQbUJ+QZXioAF0e7TGBEcA1XhYhCweyQ==}
|
||||||
|
|
||||||
'@types/react-dom@18.2.7':
|
'@types/react-dom@18.2.7':
|
||||||
resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==}
|
resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==}
|
||||||
|
|
||||||
@ -6103,6 +6112,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==}
|
resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
css-box-model@1.2.1:
|
||||||
|
resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==}
|
||||||
|
|
||||||
css-color-converter@2.0.0:
|
css-color-converter@2.0.0:
|
||||||
resolution: {integrity: sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==}
|
resolution: {integrity: sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==}
|
||||||
|
|
||||||
@ -8729,6 +8741,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==}
|
resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==}
|
||||||
engines: {node: '>= 4.0.0'}
|
engines: {node: '>= 4.0.0'}
|
||||||
|
|
||||||
|
memoize-one@5.2.1:
|
||||||
|
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
|
||||||
|
|
||||||
meow@12.1.1:
|
meow@12.1.1:
|
||||||
resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==}
|
resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==}
|
||||||
engines: {node: '>=16.10'}
|
engines: {node: '>=16.10'}
|
||||||
@ -10417,6 +10432,9 @@ packages:
|
|||||||
radix3@1.1.0:
|
radix3@1.1.0:
|
||||||
resolution: {integrity: sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==}
|
resolution: {integrity: sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==}
|
||||||
|
|
||||||
|
raf-schd@4.0.3:
|
||||||
|
resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==}
|
||||||
|
|
||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||||
|
|
||||||
@ -10764,6 +10782,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
react-beautiful-dnd@13.1.1:
|
||||||
|
resolution: {integrity: sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.5 || ^17.0.0 || ^18.0.0
|
||||||
|
react-dom: ^16.8.5 || ^17.0.0 || ^18.0.0
|
||||||
|
|
||||||
react-color@2.17.1:
|
react-color@2.17.1:
|
||||||
resolution: {integrity: sha512-S+I6TkUKJaqfALLkAIfiCZ/MANQyy7dKkf7g9ZU5GTUy2rf8c2Rx62otyvADAviWR+6HRkzdf2vL1Qvz9goCLQ==}
|
resolution: {integrity: sha512-S+I6TkUKJaqfALLkAIfiCZ/MANQyy7dKkf7g9ZU5GTUy2rf8c2Rx62otyvADAviWR+6HRkzdf2vL1Qvz9goCLQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -12617,6 +12641,11 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
use-memo-one@1.1.3:
|
||||||
|
resolution: {integrity: sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
|
||||||
use-sidecar@1.1.2:
|
use-sidecar@1.1.2:
|
||||||
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -18765,6 +18794,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/range-parser@1.2.4': {}
|
'@types/range-parser@1.2.4': {}
|
||||||
|
|
||||||
|
'@types/react-beautiful-dnd@13.1.8':
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
|
||||||
'@types/react-dom@18.2.7':
|
'@types/react-dom@18.2.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 18.2.78
|
'@types/react': 18.2.78
|
||||||
@ -20466,6 +20499,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
type-fest: 1.4.0
|
type-fest: 1.4.0
|
||||||
|
|
||||||
|
css-box-model@1.2.1:
|
||||||
|
dependencies:
|
||||||
|
tiny-invariant: 1.3.3
|
||||||
|
|
||||||
css-color-converter@2.0.0:
|
css-color-converter@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-convert: 0.5.3
|
color-convert: 0.5.3
|
||||||
@ -23830,6 +23867,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fs-monkey: 1.0.5
|
fs-monkey: 1.0.5
|
||||||
|
|
||||||
|
memoize-one@5.2.1: {}
|
||||||
|
|
||||||
meow@12.1.1: {}
|
meow@12.1.1: {}
|
||||||
|
|
||||||
merge-descriptors@1.0.1: {}
|
merge-descriptors@1.0.1: {}
|
||||||
@ -26000,6 +26039,8 @@ snapshots:
|
|||||||
|
|
||||||
radix3@1.1.0: {}
|
radix3@1.1.0: {}
|
||||||
|
|
||||||
|
raf-schd@4.0.3: {}
|
||||||
|
|
||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@ -26710,6 +26751,20 @@ snapshots:
|
|||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
strip-json-comments: 2.0.1
|
strip-json-comments: 2.0.1
|
||||||
|
|
||||||
|
react-beautiful-dnd@13.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.0
|
||||||
|
css-box-model: 1.2.1
|
||||||
|
memoize-one: 5.2.1
|
||||||
|
raf-schd: 4.0.3
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-redux: 7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||||
|
redux: 4.2.1
|
||||||
|
use-memo-one: 1.1.3(react@18.2.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- react-native
|
||||||
|
|
||||||
react-color@2.17.1(react@18.2.0):
|
react-color@2.17.1(react@18.2.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@icons/material': 0.2.4(react@18.2.0)
|
'@icons/material': 0.2.4(react@18.2.0)
|
||||||
@ -26896,6 +26951,18 @@ snapshots:
|
|||||||
|
|
||||||
react-magic-dropzone@1.0.1: {}
|
react-magic-dropzone@1.0.1: {}
|
||||||
|
|
||||||
|
react-redux@7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.0
|
||||||
|
'@types/react-redux': 7.1.33
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-is: 17.0.2
|
||||||
|
optionalDependencies:
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
|
||||||
react-redux@7.2.9(react-dom@18.2.0(react@18.3.1))(react@18.3.1):
|
react-redux@7.2.9(react-dom@18.2.0(react@18.3.1))(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.24.0
|
'@babel/runtime': 7.24.0
|
||||||
@ -29066,6 +29133,10 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 18.2.78
|
'@types/react': 18.2.78
|
||||||
|
|
||||||
|
use-memo-one@1.1.3(react@18.2.0):
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
|
||||||
use-sidecar@1.1.2(@types/react@18.2.78)(react@18.2.0):
|
use-sidecar@1.1.2(@types/react@18.2.78)(react@18.2.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
detect-node-es: 1.1.0
|
detect-node-es: 1.1.0
|
||||||
|
62
src/client/components/SortableGroup.tsx
Normal file
62
src/client/components/SortableGroup.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { DragDropContext, DropResult } from 'react-beautiful-dnd';
|
||||||
|
import { useEvent } from '@/hooks/useEvent';
|
||||||
|
import { reorder } from '@/utils/reorder';
|
||||||
|
|
||||||
|
interface BasicItem {
|
||||||
|
type: 'root' | 'group' | 'item';
|
||||||
|
items?: BasicItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SortableGroupProps {
|
||||||
|
list: BasicItem[];
|
||||||
|
onChange: (list: BasicItem[]) => void;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SortableGroup: React.FC<SortableGroupProps> = React.memo(
|
||||||
|
(props) => {
|
||||||
|
const [list, setList] = useState(props.list);
|
||||||
|
|
||||||
|
const handleDragEnd = useEvent((result: DropResult) => {
|
||||||
|
// dropped outside the list
|
||||||
|
if (!result.destination) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.type === 'root') {
|
||||||
|
setList(reorder(list, result.source.index, result.destination.index));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.type === 'group') {
|
||||||
|
const nestedIndex = list.findIndex((item): boolean => 'items' in item);
|
||||||
|
|
||||||
|
if (nestedIndex === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nested = list[nestedIndex].items;
|
||||||
|
if (!nested) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const children = Array.from(list);
|
||||||
|
children[nestedIndex].items = reorder(
|
||||||
|
nested,
|
||||||
|
result.source.index,
|
||||||
|
result.destination.index
|
||||||
|
);
|
||||||
|
|
||||||
|
setList([...list]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DragDropContext onDragEnd={handleDragEnd}>
|
||||||
|
{props.children}
|
||||||
|
</DragDropContext>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
SortableGroup.displayName = 'SortableGroup';
|
@ -75,6 +75,7 @@
|
|||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"pretty-ms": "^9.0.0",
|
"pretty-ms": "^9.0.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-easy-sort": "^1.5.3",
|
"react-easy-sort": "^1.5.3",
|
||||||
@ -106,6 +107,7 @@
|
|||||||
"@types/loadable__component": "^5.13.8",
|
"@types/loadable__component": "^5.13.8",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.22",
|
||||||
|
"@types/react-beautiful-dnd": "^13.1.8",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"@types/react-grid-layout": "^1.3.5",
|
"@types/react-grid-layout": "^1.3.5",
|
||||||
"@types/react-helmet": "^6.1.11",
|
"@types/react-helmet": "^6.1.11",
|
||||||
|
12
src/client/utils/reorder.ts
Normal file
12
src/client/utils/reorder.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// a little function to help us with reordering the result
|
||||||
|
export function reorder<T>(
|
||||||
|
list: T[],
|
||||||
|
startIndex: number,
|
||||||
|
endIndex: number
|
||||||
|
): T[] {
|
||||||
|
const result = Array.from(list);
|
||||||
|
const [removed] = result.splice(startIndex, 1);
|
||||||
|
result.splice(endIndex, 0, removed);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user