From f8d690d45762a34eed48ea2becd754d4f5ddac40 Mon Sep 17 00:00:00 2001 From: liningzhu Date: Fri, 10 Nov 2023 18:19:59 +0800 Subject: [PATCH] feat: add drag for chord-list --- packages/buitar/package.json | 2 + .../buitar/src/components/basic/drag-list.tsx | 46 +++++++ packages/buitar/src/components/basic/index.ts | 1 + .../chord-list/chord-list.component.tsx | 32 +++-- .../src/pages/collections/collections.tsx | 1 + pnpm-lock.yaml | 115 +++++++++++++++++- 6 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 packages/buitar/src/components/basic/drag-list.tsx diff --git a/packages/buitar/package.json b/packages/buitar/package.json index 049291b..52d85d6 100644 --- a/packages/buitar/package.json +++ b/packages/buitar/package.json @@ -16,6 +16,7 @@ "devDependencies": { "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", + "@types/react-beautiful-dnd": "^13.1.7", "@vite-pwa/assets-generator": "^0.0.7", "@vitejs/plugin-react": "^4.0.3", "classnames": "^2.3.1", @@ -32,6 +33,7 @@ "@buitar/abc-editor": "workspace:*", "@buitar/to-guitar": "workspace:*", "@buitar/tone-player": "workspace:*", + "react-beautiful-dnd": "^13.1.1", "vexflow": "^4.2.3" } } diff --git a/packages/buitar/src/components/basic/drag-list.tsx b/packages/buitar/src/components/basic/drag-list.tsx new file mode 100644 index 0000000..32bcf5f --- /dev/null +++ b/packages/buitar/src/components/basic/drag-list.tsx @@ -0,0 +1,46 @@ +import { FC } from 'react' +import { + DragDropContext, + Droppable, + Draggable, + type DragDropContextProps, + type DroppableProps, +} from 'react-beautiful-dnd' + +export type DragableListProps = { + list: any[] + className?: string +} & Pick & + Pick + +export const DragableList: FC = ({ + list, + onDragEnd, + className, + direction = 'horizontal', +}) => { + return ( + + + {(provided) => ( +
+ {list.map((item, index) => ( + + {(provided) => ( +
+ {item} +
+ )} +
+ ))} + {provided.placeholder} +
+ )} +
+
+ ) +} diff --git a/packages/buitar/src/components/basic/index.ts b/packages/buitar/src/components/basic/index.ts index 3e5bcee..3f57cf4 100644 --- a/packages/buitar/src/components/basic/index.ts +++ b/packages/buitar/src/components/basic/index.ts @@ -1,2 +1,3 @@ export * from './collection-selecter' +export * from './drag-list' export * from './text-input' diff --git a/packages/buitar/src/components/chord-list/chord-list.component.tsx b/packages/buitar/src/components/chord-list/chord-list.component.tsx index 8a63aad..b261eb6 100644 --- a/packages/buitar/src/components/chord-list/chord-list.component.tsx +++ b/packages/buitar/src/components/chord-list/chord-list.component.tsx @@ -2,9 +2,10 @@ import { FC } from 'react' import { ChordType, Point } from '@buitar/to-guitar' import { ChordCard, useBoardContext } from '../guitar-board' import { Icon } from '@/components/icon' -import { useConfigContext } from '../slide-menu/config-provider' -import cx from 'classnames' +import { useConfigContext } from '@/components/slide-menu/config-provider' +import { DragableList, type DragableListProps } from '@/components/basic' +import cx from 'classnames' import styles from './chord-list.module.scss' export type CollectionChord = { @@ -19,9 +20,10 @@ export const ChordList: FC<{ title?: string intro?: string disableCollect?: boolean + disableDrag?: boolean className?: string titleClassName?: string -}> = ({ data, title, intro, disableCollect, titleClassName, className, index }) => { +}> = ({ data, title, intro, disableCollect, disableDrag, titleClassName, className, index }) => { const { collection, dispatchCollection, instrumentKeyboard } = useBoardContext() const { isMobileDevice } = useConfigContext() @@ -35,6 +37,16 @@ export const ChordList: FC<{ dispatchCollection({ type: 'set', payload: collection }) } + const handleDragEnd: DragableListProps['onDragEnd'] = (result) => { + if (!result.destination) return // 如果没有目标位置,不执行任何操作 + const items = Array.from(data) + const [reorderedItem] = items.splice(result.source.index, 1) + items.splice(result.destination.index, 0, reorderedItem) + + collection[instrumentKeyboard][index].data = items + dispatchCollection({ type: 'set', payload: collection }) + } + const dataView = data.map((item, dataIndex) => { return (
-
- {title} -
+
{title}
{!disableCollect && (
@@ -62,7 +72,15 @@ export const ChordList: FC<{ )} {intro &&
{intro}
}
-
{dataView}
+ {disableDrag ? ( +
{dataView}
+ ) : ( + + )}
) } diff --git a/packages/buitar/src/pages/collections/collections.tsx b/packages/buitar/src/pages/collections/collections.tsx index 97fb867..608f2b5 100644 --- a/packages/buitar/src/pages/collections/collections.tsx +++ b/packages/buitar/src/pages/collections/collections.tsx @@ -93,6 +93,7 @@ export const CagedCollection: FC = () => { index={index} title={key} disableCollect + disableDrag className={styles['caged-list']} titleClassName={styles['caged-title']} /> diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 722ff0b..fdea8f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,10 +53,16 @@ importers: '@buitar/tone-player': specifier: workspace:* version: link:../tone-player + react-beautiful-dnd: + specifier: ^13.1.1 + version: 13.1.1 vexflow: specifier: ^4.2.3 version: 4.2.3 devDependencies: + '@types/react-beautiful-dnd': + specifier: ^13.1.7 + version: 13.1.7 '@typescript-eslint/eslint-plugin': specifier: ^6.0.0 version: 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.45.0)(typescript@5.1.6) @@ -2115,6 +2121,13 @@ packages: resolution: {integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==} dev: true + /@types/hoist-non-react-statics@3.3.5: + resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} + dependencies: + '@types/react': 17.0.2 + hoist-non-react-statics: 3.3.2 + dev: false + /@types/istanbul-lib-coverage@2.0.4: resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} dev: true @@ -2156,6 +2169,11 @@ packages: /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} + + /@types/react-beautiful-dnd@13.1.7: + resolution: {integrity: sha512-jQZLov9OkD0xRQkqz8/lx66bHYAYv+g4+POBqnH5Jtt/xo4MygzM879Q9sxAiosPBdNj1JYTdbPxDn3dNRYgow==} + dependencies: + '@types/react': 17.0.2 dev: true /@types/react-dom@17.0.2: @@ -2164,6 +2182,15 @@ packages: '@types/react': 17.0.2 dev: true + /@types/react-redux@7.1.30: + resolution: {integrity: sha512-i2kqM6YaUwFKduamV6QM/uHbb0eCP8f8ZQ/0yWf+BsAVVsZPRYJ9eeGWZ3uxLfWwwA0SrPRMTPTqsPFkY3HZdA==} + dependencies: + '@types/hoist-non-react-statics': 3.3.5 + '@types/react': 17.0.2 + hoist-non-react-statics: 3.3.2 + redux: 4.2.1 + dev: false + /@types/react-router-dom@5.3.3: resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==} dependencies: @@ -2184,7 +2211,6 @@ packages: dependencies: '@types/prop-types': 15.7.5 csstype: 3.1.2 - dev: true /@types/resolve@0.0.8: resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} @@ -3050,6 +3076,12 @@ packages: engines: {node: '>=8'} dev: true + /css-box-model@1.2.1: + resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==} + dependencies: + tiny-invariant: 1.3.1 + dev: false + /cssom@0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} dev: true @@ -3067,7 +3099,6 @@ packages: /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - dev: true /data-urls@2.0.0: resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} @@ -3854,6 +3885,12 @@ packages: function-bind: 1.1.1 dev: true + /hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + dependencies: + react-is: 16.13.1 + dev: false + /html-encoding-sniffer@2.0.1: resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} engines: {node: '>=10'} @@ -4910,6 +4947,10 @@ packages: tmpl: 1.0.5 dev: true + /memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + dev: false + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true @@ -5235,6 +5276,14 @@ packages: sisteransi: 1.0.5 dev: true + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: false + /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: true @@ -5263,6 +5312,10 @@ packages: resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} dev: true + /raf-schd@4.0.3: + resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} + dev: false + /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -5279,6 +5332,23 @@ packages: strip-json-comments: 2.0.1 dev: 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 + dependencies: + '@babel/runtime': 7.22.6 + css-box-model: 1.2.1 + memoize-one: 5.2.1 + raf-schd: 4.0.3 + react-redux: 7.2.9 + redux: 4.2.1 + use-memo-one: 1.1.3 + transitivePeerDependencies: + - react-native + dev: false + /react-dom@17.0.2(react@17.0.2): resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} peerDependencies: @@ -5290,9 +5360,32 @@ packages: scheduler: 0.20.2 dev: false + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: false + /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - dev: true + + /react-redux@7.2.9: + resolution: {integrity: sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==} + peerDependencies: + react: ^16.8.3 || ^17 || ^18 + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@babel/runtime': 7.22.6 + '@types/react-redux': 7.1.30 + hoist-non-react-statics: 3.3.2 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react-is: 17.0.2 + dev: false /react-refresh@0.14.0: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} @@ -5346,6 +5439,12 @@ packages: picomatch: 2.3.1 dev: true + /redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + dependencies: + '@babel/runtime': 7.22.6 + dev: false + /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} engines: {node: '>=4'} @@ -5965,6 +6064,10 @@ packages: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} dev: true + /tiny-invariant@1.3.1: + resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} + dev: false + /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true @@ -6266,6 +6369,12 @@ packages: requires-port: 1.0.0 dev: 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 + dev: false + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true