refactor: handling keyboard shortcuts (#9242)

* fix: Resolve and go next keyboard shortcuts doesn't work

* refactor: use buildHotKeys instead of  hasPressedCommandPlusAltAndEKey

* feat: install tinykeys

* refactor: use tinykeys

* test: update buildKeyEvents

* fix: remove stray import

* feat: handle action list globally

* feat: allow configuring `allowOnFocusedInput`

* chore: Navigate chat list item

* chore: Navigate dashboard

* feat: Navigate editor top panel

* feat: Toggle file upload

* chore: More keyboard shortcuts

* chore: Update mention selection mixin

* chore: Phone input

* chore: Clean up

* chore: Clean up

* chore: Dropdown and editor

* chore: Enter key to send and clean up

* chore: Rename mixin

* chore: Review fixes

* chore: Removed unused shortcut from modal

* fix: Specs

---------

Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
This commit is contained in:
Shivam Mishra
2024-04-26 15:41:02 +05:30
committed by GitHub
parent ffd47081bd
commit 47f8b2cd0c
36 changed files with 599 additions and 596 deletions

View File

@@ -50,13 +50,8 @@ import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue';
import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue';
import { mixin as clickaway } from 'vue-clickaway';
import adminMixin from 'dashboard/mixins/isAdmin';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
import {
buildHotKeys,
isEscape,
isActiveElementTypeable,
} from 'shared/helpers/KeyboardHelpers';
export default {
components: {
@@ -65,7 +60,12 @@ export default {
AddLabel,
},
mixins: [clickaway, conversationLabelMixin, adminMixin, eventListenerMixins],
mixins: [
clickaway,
conversationLabelMixin,
adminMixin,
keyboardEventListenerMixins,
],
props: {
conversationId: {
type: Number,
@@ -93,16 +93,23 @@ export default {
closeDropdownLabel() {
this.showSearchDropdownLabel = false;
},
handleKeyEvents(e) {
const keyPattern = buildHotKeys(e);
if (keyPattern === 'l' && !isActiveElementTypeable(e)) {
this.toggleLabels();
e.preventDefault();
} else if (isEscape(e) && this.showSearchDropdownLabel) {
this.closeDropdownLabel();
e.preventDefault();
}
getKeyboardEvents() {
return {
KeyL: {
action: e => {
e.preventDefault();
this.toggleLabels();
},
},
Escape: {
action: () => {
if (this.showSearchDropdownLabel) {
this.toggleLabels();
}
},
allowOnFocusedInput: true,
},
};
},
},
};

View File

@@ -34,15 +34,11 @@
</template>
<script>
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import {
buildHotKeys,
isActiveElementTypeable,
} from 'shared/helpers/KeyboardHelpers';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
export default {
name: 'ChatwootSearch',
mixins: [eventListenerMixins],
mixins: [keyboardEventListenerMixins],
props: {
title: {
type: String,
@@ -71,13 +67,15 @@ export default {
onBlur() {
this.isInputFocused = false;
},
handleKeyEvents(e) {
const keyPattern = buildHotKeys(e);
if (keyPattern === '/' && !isActiveElementTypeable(e)) {
e.preventDefault();
this.$refs.searchInput.focus();
}
getKeyboardEvents() {
return {
Slash: {
action: e => {
e.preventDefault();
this.$refs.searchInput.focus();
},
},
};
},
},
};

View File

@@ -35,10 +35,7 @@
<script>
import { debounce } from '@chatwoot/utils';
import { mixin as clickaway } from 'vue-clickaway';
import {
isEscape,
isActiveElementTypeable,
} from 'shared/helpers/KeyboardHelpers';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import SearchHeader from './Header.vue';
import SearchResults from './SearchResults.vue';
@@ -55,7 +52,7 @@ export default {
SearchResults,
ArticleView,
},
mixins: [clickaway, portalMixin, alertMixin],
mixins: [clickaway, portalMixin, alertMixin, keyboardEventListenerMixins],
props: {
selectedPortalSlug: {
type: String,
@@ -97,10 +94,6 @@ export default {
mounted() {
this.fetchArticlesByQuery(this.searchQuery);
this.debounceSearch = debounce(this.fetchArticlesByQuery, 500, false);
document.body.addEventListener('keydown', this.closeOnEsc);
},
beforeDestroy() {
document.body.removeEventListener('keydown', this.closeOnEsc);
},
methods: {
generateArticleUrl(article) {
@@ -158,11 +151,15 @@ export default {
);
this.onClose();
},
closeOnEsc(e) {
if (isEscape(e) && !isActiveElementTypeable(e)) {
e.preventDefault();
this.onClose();
}
getKeyboardEvents() {
return {
Escape: {
action: () => {
this.onClose();
},
allowOnFocusedInput: true,
},
};
},
},
};