From 31cf31e931fcd4ddda40ba1c72f2faa5f2dc5e3b Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Wed, 15 Mar 2023 17:19:25 +0100 Subject: [PATCH] Replace unmaintained HammerJS dependency with VueUse Ref: https://github.com/hammerjs/hammer.js/issues/1278 Signed-off-by: Ferdinand Thiessen --- package-lock.json | 150 +++++++++++++++++-- package.json | 2 +- src/components/NcAppContent/NcAppContent.vue | 54 ++++--- src/components/NcModal/NcModal.vue | 20 ++- 4 files changed, 179 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d3c398800..fed881059e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,13 +23,13 @@ "@nextcloud/router": "^2.0.0", "@nextcloud/vue-select": "^3.21.2", "@skjnldsv/sanitize-svg": "^1.0.2", + "@vueuse/core": "^9.13.0", "clone": "^2.1.2", "debounce": "1.2.1", "emoji-mart-vue-fast": "^12.0.1", "escape-html": "^1.0.3", "floating-vue": "^1.0.0-beta.19", "focus-trap": "^7.1.0", - "hammerjs": "^2.0.8", "linkify-string": "^4.0.0", "md5": "^2.3.0", "node-polyfill-webpack-plugin": "^2.0.1", @@ -3820,6 +3820,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, "node_modules/@types/webpack": { "version": "4.41.33", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz", @@ -4456,6 +4461,89 @@ } } }, + "node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@vxna/mini-html-webpack-template": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@vxna/mini-html-webpack-template/-/mini-html-webpack-template-1.0.0.tgz", @@ -11858,14 +11946,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -29301,7 +29381,7 @@ "version": "git+ssh://git@github.com/nextcloud/webpack-vue-config.git#9ef2a77f26d35e10e18403b6d6b70233ebee129f", "integrity": "sha512-SvgLgQ1NlSnTrv2ArapeCAcQFd2vgwMRgVTD1TtGs8s0veU0lR5QYe/CcJbN2eBavpJxqDaGi183mPeObJTH/Q==", "dev": true, - "from": "@nextcloud/webpack-vue-config@github:nextcloud/webpack-vue-config#9ef2a77f26d35e10e18403b6d6b70233ebee129f", + "from": "@nextcloud/webpack-vue-config@github:nextcloud/webpack-vue-config#master", "requires": {} }, "@nicolo-ribaudo/eslint-scope-5-internals": { @@ -29895,6 +29975,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" }, + "@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, "@types/webpack": { "version": "4.41.33", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz", @@ -30360,6 +30445,46 @@ "tsconfig": "^7.0.0" } }, + "@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "requires": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "requires": {} + } + } + }, + "@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==" + }, + "@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "requires": { + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "requires": {} + } + } + }, "@vxna/mini-html-webpack-template": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@vxna/mini-html-webpack-template/-/mini-html-webpack-template-1.0.0.tgz", @@ -36123,11 +36248,6 @@ "duplexer": "^0.1.2" } }, - "hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==" - }, "handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", diff --git a/package.json b/package.json index 06b5595a51..65f15ef58d 100644 --- a/package.json +++ b/package.json @@ -54,13 +54,13 @@ "@nextcloud/router": "^2.0.0", "@nextcloud/vue-select": "^3.21.2", "@skjnldsv/sanitize-svg": "^1.0.2", + "@vueuse/core": "^9.13.0", "clone": "^2.1.2", "debounce": "1.2.1", "emoji-mart-vue-fast": "^12.0.1", "escape-html": "^1.0.3", "floating-vue": "^1.0.0-beta.19", "focus-trap": "^7.1.0", - "hammerjs": "^2.0.8", "linkify-string": "^4.0.0", "md5": "^2.3.0", "node-polyfill-webpack-plugin": "^2.0.1", diff --git a/src/components/NcAppContent/NcAppContent.vue b/src/components/NcAppContent/NcAppContent.vue index 69d3cceec8..9d8b9b4b6f 100644 --- a/src/components/NcAppContent/NcAppContent.vue +++ b/src/components/NcAppContent/NcAppContent.vue @@ -117,9 +117,11 @@ import isMobile from '../../mixins/isMobile/index.js' import { getBuilder } from '@nextcloud/browser-storage' import { emit } from '@nextcloud/event-bus' -import Hammer from 'hammerjs' -import 'splitpanes/dist/splitpanes.css' +import { useSwipe } from '@vueuse/core' import { Splitpanes, Pane } from 'splitpanes' +import { ref } from 'vue' + +import 'splitpanes/dist/splitpanes.css' const browserStorage = getBuilder('nextcloud').persist().build() @@ -199,8 +201,10 @@ export default { data() { return { contentHeight: 0, - hasList: false, + + lengthX: ref(0), + coordsStart: ref({}), listPaneSize: this.restorePaneConfig(), } }, @@ -255,34 +259,36 @@ export default { }, mounted() { - if (this.allowSwipeNavigation) { - this.mc = new Hammer(this.$el, { cssProps: { userSelect: 'text' } }) - this.mc.on('swipeleft swiperight', this.handleSwipe) - } + const { coordsStart, lengthX } = useSwipe(this.$el, { + onSwipeEnd: this.handleSwipe, + }) + this.coordsStart = coordsStart + this.lengthX = lengthX this.checkListSlot() this.restorePaneConfig() }, - beforeDestroy() { - this.mc.off('swipeleft swiperight', this.handleSwipe) - }, - methods: { - // handle the swipe event - handleSwipe(e) { + /** + * handle the swipe event + * + * @param {TouchEvent} e The touch event + * @param {import('@vueuse/core').SwipeDirection} direction The swipe direction of the event + */ + handleSwipe(e, direction) { const minSwipeX = 70 - const touchzone = 40 - const startX = e.srcEvent.pageX - e.deltaX - const hasEnoughDistance = Math.abs(e.deltaX) > minSwipeX - if (hasEnoughDistance && startX < touchzone) { - emit('toggle-navigation', { - open: true, - }) - } else if (hasEnoughDistance && startX < touchzone + 300) { - emit('toggle-navigation', { - open: false, - }) + const touchZone = 300 + if (this.lengthX.value > minSwipeX) { + if (this.coordsStart.value.x < (touchZone / 2) && direction === 'RIGHT') { + emit('toggle-navigation', { + open: true, + }) + } else if (this.coordsStart.value.x < touchZone * 1.5 && direction === 'LEFT') { + emit('toggle-navigation', { + open: false, + }) + } } }, diff --git a/src/components/NcModal/NcModal.vue b/src/components/NcModal/NcModal.vue index 057b90e742..891480f3d2 100644 --- a/src/components/NcModal/NcModal.vue +++ b/src/components/NcModal/NcModal.vue @@ -322,7 +322,7 @@ import Pause from 'vue-material-design-icons/Pause.vue' import Play from 'vue-material-design-icons/Play.vue' import { createFocusTrap } from 'focus-trap' -import Hammer from 'hammerjs' +import { useSwipe } from '@vueuse/core' export default { name: 'NcModal', @@ -552,9 +552,8 @@ export default { mounted() { // init clear view this.useFocusTrap() - this.mc = new Hammer(this.$refs.mask) - this.mc.on('swipeleft swiperight', e => { - this.handleSwipe(e) + useSwipe(this.$refs.mask, { + onSwipeEnd: this.handleSwipe, }) if (this.container) { @@ -629,12 +628,19 @@ export default { break } }, - handleSwipe(e) { + + /** + * handle the swipe event + * + * @param {TouchEvent} e The touch event + * @param {import('@vueuse/core').SwipeDirection} direction Swipe direction + */ + handleSwipe(e, direction) { if (this.enableSwipe) { - if (e.type === 'swipeleft') { + if (direction === 'LEFT') { // swiping to left to go to the next item this.next(e) - } else if (e.type === 'swiperight') { + } else if (direction === 'RIGHT') { // swiping to right to go back to the previous item this.previous(e) }