feat: Replace the use of keyboardEventListener mixin to a composable (Part -3) (#9897)

This commit is contained in:
Sivin Varghese
2024-08-08 12:40:56 +05:30
committed by GitHub
parent ae938b2154
commit 74bbbd25b9
6 changed files with 156 additions and 178 deletions

View File

@@ -1,43 +1,34 @@
<script> <script setup>
import { ref, computed } from 'vue';
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
export default {
components: {
WootMessageEditor,
},
mixins: [keyboardEventListenerMixins],
data() {
return {
noteContent: '',
};
},
computed: { const emit = defineEmits(['add']);
buttonDisabled() {
return this.noteContent === ''; const addNoteRef = ref(null);
}, const noteContent = ref('');
},
methods: { const buttonDisabled = computed(() => noteContent.value === '');
getKeyboardEvents() {
return { const onAdd = () => {
'$mod+Enter': { if (noteContent.value !== '') {
action: () => this.onAdd(), emit('add', noteContent.value);
allowOnFocusedInput: true, }
}, noteContent.value = '';
}; };
},
onAdd() { const keyboardEvents = {
if (this.noteContent !== '') { '$mod+Enter': {
this.$emit('add', this.noteContent); action: () => onAdd(),
} allowOnFocusedInput: true,
this.noteContent = '';
},
}, },
}; };
useKeyboardEvents(keyboardEvents, addNoteRef);
</script> </script>
<template> <template>
<div <div
ref="addNoteRef"
class="flex flex-col flex-grow p-4 mb-2 overflow-hidden bg-white border border-solid rounded-md shadow-sm border-slate-75 dark:border-slate-700 dark:bg-slate-900 text-slate-700 dark:text-slate-100" class="flex flex-col flex-grow p-4 mb-2 overflow-hidden bg-white border border-solid rounded-md shadow-sm border-slate-75 dark:border-slate-700 dark:bg-slate-900 text-slate-700 dark:text-slate-100"
> >
<WootMessageEditor <WootMessageEditor

View File

@@ -1,10 +1,11 @@
<script> <script>
import { ref } from 'vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAdmin } from 'dashboard/composables/useAdmin'; import { useAdmin } from 'dashboard/composables/useAdmin';
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue'; import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue';
import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue'; import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin'; import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
export default { export default {
@@ -14,7 +15,7 @@ export default {
AddLabel, AddLabel,
}, },
mixins: [conversationLabelMixin, keyboardEventListenerMixins], mixins: [conversationLabelMixin],
props: { props: {
// conversationId prop is used in /conversation/labelMixin, // conversationId prop is used in /conversation/labelMixin,
// remove this props when refactoring to composable if not needed // remove this props when refactoring to composable if not needed
@@ -26,14 +27,46 @@ export default {
}, },
setup() { setup() {
const { isAdmin } = useAdmin(); const { isAdmin } = useAdmin();
const conversationLabelBoxRef = ref(null);
const showSearchDropdownLabel = ref(false);
const toggleLabels = () => {
showSearchDropdownLabel.value = !showSearchDropdownLabel.value;
};
const closeDropdownLabel = () => {
showSearchDropdownLabel.value = false;
};
const keyboardEvents = {
KeyL: {
action: e => {
e.preventDefault();
toggleLabels();
},
},
Escape: {
action: () => {
if (showSearchDropdownLabel.value) {
toggleLabels();
}
},
allowOnFocusedInput: true,
},
};
useKeyboardEvents(keyboardEvents, conversationLabelBoxRef);
return { return {
isAdmin, isAdmin,
conversationLabelBoxRef,
showSearchDropdownLabel,
closeDropdownLabel,
toggleLabels,
}; };
}, },
data() { data() {
return { return {
selectedLabels: [], selectedLabels: [],
showSearchDropdownLabel: false,
}; };
}, },
@@ -42,37 +75,11 @@ export default {
conversationUiFlags: 'conversationLabels/getUIFlags', conversationUiFlags: 'conversationLabels/getUIFlags',
}), }),
}, },
methods: {
toggleLabels() {
this.showSearchDropdownLabel = !this.showSearchDropdownLabel;
},
closeDropdownLabel() {
this.showSearchDropdownLabel = false;
},
getKeyboardEvents() {
return {
KeyL: {
action: e => {
e.preventDefault();
this.toggleLabels();
},
},
Escape: {
action: () => {
if (this.showSearchDropdownLabel) {
this.toggleLabels();
}
},
allowOnFocusedInput: true,
},
};
},
},
}; };
</script> </script>
<template> <template>
<div class="sidebar-labels-wrap"> <div ref="conversationLabelBoxRef" class="sidebar-labels-wrap">
<div <div
v-if="!conversationUiFlags.isFetching" v-if="!conversationUiFlags.isFetching"
class="contact-conversation--list" class="contact-conversation--list"

View File

@@ -1,53 +1,51 @@
<script> <script setup>
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import { ref, onMounted } from 'vue';
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
export default { defineProps({
name: 'ChatwootSearch', title: {
mixins: [keyboardEventListenerMixins], type: String,
props: { default: 'Chatwoot',
title: { },
type: String, });
default: 'Chatwoot',
const emit = defineEmits(['search', 'close']);
const articleSearchHeaderRef = ref(null);
const searchInputRef = ref(null);
const searchQuery = ref('');
onMounted(() => {
searchInputRef.value.focus();
});
const onInput = e => {
emit('search', e.target.value);
};
const onClose = () => {
emit('close');
};
const keyboardEvents = {
Slash: {
action: e => {
e.preventDefault();
searchInputRef.value.focus();
}, },
}, },
data() { Escape: {
return { action: () => {
searchQuery: '', onClose();
isInputFocused: false,
};
},
mounted() {
this.$refs.searchInput.focus();
},
methods: {
onInput(e) {
this.$emit('search', e.target.value);
},
onClose() {
this.$emit('close');
},
onFocus() {
this.isInputFocused = true;
},
onBlur() {
this.isInputFocused = false;
},
getKeyboardEvents() {
return {
Slash: {
action: e => {
e.preventDefault();
this.$refs.searchInput.focus();
},
},
};
}, },
allowOnFocusedInput: true,
}, },
}; };
useKeyboardEvents(keyboardEvents, articleSearchHeaderRef);
</script> </script>
<template> <template>
<div class="flex flex-col py-1"> <div ref="articleSearchHeaderRef" class="flex flex-col py-1">
<div class="flex items-center justify-between py-2 mb-1"> <div class="flex items-center justify-between py-2 mb-1">
<h3 class="text-base text-slate-900 dark:text-slate-25"> <h3 class="text-base text-slate-900 dark:text-slate-25">
{{ title }} {{ title }}
@@ -68,13 +66,11 @@ export default {
<fluent-icon icon="search" class="" size="18" /> <fluent-icon icon="search" class="" size="18" />
</div> </div>
<input <input
ref="searchInput" ref="searchInputRef"
type="text" type="text"
:placeholder="$t('HELP_CENTER.ARTICLE_SEARCH.PLACEHOLDER')" :placeholder="$t('HELP_CENTER.ARTICLE_SEARCH.PLACEHOLDER')"
class="block w-full !h-9 ltr:!pl-8 rtl:!pr-8 dark:!bg-slate-700 !bg-slate-25 text-sm rounded-md leading-8 text-slate-700 shadow-sm ring-2 ring-transparent ring-slate-300 border border-solid border-slate-300 placeholder:text-slate-400 focus:border-woot-600 focus:ring-woot-200 !mb-0 focus:bg-slate-25 dark:focus:bg-slate-700 dark:focus:ring-woot-700" class="block w-full !h-9 ltr:!pl-8 rtl:!pr-8 dark:!bg-slate-700 !bg-slate-25 text-sm rounded-md leading-8 text-slate-700 shadow-sm ring-2 ring-transparent ring-slate-300 border border-solid border-slate-300 placeholder:text-slate-400 focus:border-woot-600 focus:ring-woot-200 !mb-0 focus:bg-slate-25 dark:focus:bg-slate-700 dark:focus:ring-woot-700"
:value="searchQuery" :value="searchQuery"
@focus="onFocus"
@blur="onBlur"
@input="onInput" @input="onInput"
/> />
</div> </div>

View File

@@ -1,7 +1,6 @@
<script> <script>
import { debounce } from '@chatwoot/utils'; import { debounce } from '@chatwoot/utils';
import { useAlert } from 'dashboard/composables'; import { useAlert } from 'dashboard/composables';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import SearchHeader from './Header.vue'; import SearchHeader from './Header.vue';
import SearchResults from './SearchResults.vue'; import SearchResults from './SearchResults.vue';
@@ -17,7 +16,7 @@ export default {
SearchResults, SearchResults,
ArticleView, ArticleView,
}, },
mixins: [portalMixin, keyboardEventListenerMixins], mixins: [portalMixin],
props: { props: {
selectedPortalSlug: { selectedPortalSlug: {
type: String, type: String,
@@ -114,16 +113,6 @@ export default {
useAlert(this.$t('HELP_CENTER.ARTICLE_SEARCH.SUCCESS_ARTICLE_INSERTED')); useAlert(this.$t('HELP_CENTER.ARTICLE_SEARCH.SUCCESS_ARTICLE_INSERTED'));
this.onClose(); this.onClose();
}, },
getKeyboardEvents() {
return {
Escape: {
action: () => {
this.onClose();
},
allowOnFocusedInput: true,
},
};
},
}, },
}; };
</script> </script>

View File

@@ -1,59 +1,63 @@
<script> <script setup>
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import { ref } from 'vue';
export default { import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
name: 'WootDropdownMenu',
componentName: 'WootDropdownMenu',
mixins: [keyboardEventListenerMixins], defineProps({
placement: {
props: { type: String,
placement: { default: 'top',
type: String,
default: 'top',
},
}, },
methods: { });
dropdownMenuButtons() {
return this.$refs.dropdownMenu.querySelectorAll( const dropdownMenuRef = ref(null);
'ul.dropdown li.dropdown-menu__item .button'
); const dropdownMenuButtons = () => {
}, return dropdownMenuRef.value.querySelectorAll(
getActiveButtonIndex(menuButtons) { 'ul.dropdown li.dropdown-menu__item .button'
const focusedButton = this.$refs.dropdownMenu.querySelector( );
'ul.dropdown li.dropdown-menu__item .button:focus' };
);
return Array.from(menuButtons).indexOf(focusedButton); const getActiveButtonIndex = menuButtons => {
}, const focusedButton = dropdownMenuRef.value.querySelector(
getKeyboardEvents() { 'ul.dropdown li.dropdown-menu__item .button:focus'
const menuButtons = this.dropdownMenuButtons(); );
return { return Array.from(menuButtons).indexOf(focusedButton);
ArrowUp: () => this.focusPreviousButton(menuButtons), };
ArrowDown: () => this.focusNextButton(menuButtons),
}; const focusButton = (menuButtons, newIndex) => {
}, if (menuButtons.length === 0) return;
focusPreviousButton(menuButtons) { menuButtons[newIndex].focus();
const activeIndex = this.getActiveButtonIndex(menuButtons); };
const newIndex =
activeIndex >= 1 ? activeIndex - 1 : menuButtons.length - 1; const focusPreviousButton = menuButtons => {
this.focusButton(menuButtons, newIndex); const activeIndex = getActiveButtonIndex(menuButtons);
}, const newIndex = activeIndex >= 1 ? activeIndex - 1 : menuButtons.length - 1;
focusNextButton(menuButtons) { focusButton(menuButtons, newIndex);
const activeIndex = this.getActiveButtonIndex(menuButtons); };
const newIndex =
activeIndex === menuButtons.length - 1 ? 0 : activeIndex + 1; const focusNextButton = menuButtons => {
this.focusButton(menuButtons, newIndex); const activeIndex = getActiveButtonIndex(menuButtons);
}, const newIndex = activeIndex === menuButtons.length - 1 ? 0 : activeIndex + 1;
focusButton(menuButtons, newIndex) { focusButton(menuButtons, newIndex);
if (menuButtons.length === 0) return; };
menuButtons[newIndex].focus();
}, const keyboardEvents = {
ArrowUp: {
action: () => focusPreviousButton(dropdownMenuButtons()),
allowOnFocusedInput: true,
},
ArrowDown: {
action: () => focusNextButton(dropdownMenuButtons()),
allowOnFocusedInput: true,
}, },
}; };
useKeyboardEvents(keyboardEvents, dropdownMenuRef);
</script> </script>
<template> <template>
<ul <ul
ref="dropdownMenu" ref="dropdownMenuRef"
class="dropdown menu vertical" class="dropdown menu vertical"
:class="[placement && `dropdown--${placement}`]" :class="[placement && `dropdown--${placement}`]"
> >

View File

@@ -1,6 +1,5 @@
<script> <script>
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import PlaygroundHeader from '../../components/playground/Header.vue'; import PlaygroundHeader from '../../components/playground/Header.vue';
import UserMessage from '../../components/playground/UserMessage.vue'; import UserMessage from '../../components/playground/UserMessage.vue';
import BotMessage from '../../components/playground/BotMessage.vue'; import BotMessage from '../../components/playground/BotMessage.vue';
@@ -13,7 +12,7 @@ export default {
BotMessage, BotMessage,
TypingIndicator, TypingIndicator,
}, },
mixins: [messageFormatterMixin, keyboardEventListenerMixins], mixins: [messageFormatterMixin],
props: { props: {
componentData: { componentData: {
type: Object, type: Object,
@@ -35,16 +34,6 @@ export default {
this.focusInput(); this.focusInput();
}, },
methods: { methods: {
getKeyboardEvents() {
return {
'$mod+Enter': {
action: () => {
this.onMessageSend();
},
allowOnFocusedInput: true,
},
};
},
focusInput() { focusInput() {
this.$refs.messageInput.focus(); this.$refs.messageInput.focus();
}, },
@@ -133,6 +122,8 @@ export default {
placeholder="Type a message... [CMD/CTRL + Enter to send]" placeholder="Type a message... [CMD/CTRL + Enter to send]"
autofocus autofocus
autocomplete="off" autocomplete="off"
@keydown.meta.enter="onMessageSend"
@keydown.ctrl.enter="onMessageSend"
/> />
</div> </div>
</section> </section>