diff --git a/packages/design-system/src/components/OcSearchBar/OcSearchBar.vue b/packages/design-system/src/components/OcSearchBar/OcSearchBar.vue index 5afe5d371a..db07cb0f1b 100644 --- a/packages/design-system/src/components/OcSearchBar/OcSearchBar.vue +++ b/packages/design-system/src/components/OcSearchBar/OcSearchBar.vue @@ -190,7 +190,8 @@ const inputClass = computed(() => { 'p-4', 'rounded-4xl', 'disabled:cursor-not-allowed', - 'focus:bg-none' + 'focus:bg-none', + 'focus:outline focus:outline-offset-2 focus:outline-white' ] if (!buttonHidden) { classes.push(...['oc-search-input-button', 'rounded-r-none']) diff --git a/packages/web-app-search/src/portals/SearchBar.vue b/packages/web-app-search/src/portals/SearchBar.vue index 8c30310725..e062f4d708 100644 --- a/packages/web-app-search/src/portals/SearchBar.vue +++ b/packages/web-app-search/src/portals/SearchBar.vue @@ -8,6 +8,7 @@ > import { + Key, + Modifier, SearchProvider, createLocationCommon, isLocationCommonActive, @@ -130,6 +133,7 @@ import { useAuthStore, useCapabilityStore, useIsAppActive, + useKeyboardActions, useResourcesStore } from '@opencloud-eu/web-pkg' import Mark from 'mark.js' @@ -175,6 +179,8 @@ export default defineComponent({ const locationFilterId = ref(SearchLocationFilterConstants.allFiles) const optionsDropRef = useTemplateRef>('optionsDropRef') + const searchInputRef = useTemplateRef('searchInputRef') + const searchBarRef = useTemplateRef('searchBar') const activePreviewIndex = ref(null) const term = ref('') const restoreSearchFromRoute = ref(false) @@ -362,6 +368,17 @@ export default defineComponent({ term.value = '' }) + const { bindKeyAction } = useKeyboardActions() + + const onSearchShortcut = (event: KeyboardEvent) => { + const inputElement = unref(searchBarRef)?.querySelector('input') as HTMLElement + inputElement?.focus() + } + + bindKeyAction({ primary: Key.S }, onSearchShortcut) + bindKeyAction({ primary: Key.Slash }, onSearchShortcut) + bindKeyAction({ primary: Key.Slash, modifier: Modifier.Shift }, onSearchShortcut) + onBeforeUnmount(() => { eventBus.unsubscribe('app.search.term.clear', clearTermEvent) }) @@ -398,7 +415,8 @@ export default defineComponent({ getSearchResultLocation, showDrop, isAppActive, - getFocusableElements + getFocusableElements, + onSearchShortcut } }, diff --git a/packages/web-app-search/tests/unit/portals/SearchBar.spec.ts b/packages/web-app-search/tests/unit/portals/SearchBar.spec.ts index 207ea44156..425073a509 100644 --- a/packages/web-app-search/tests/unit/portals/SearchBar.spec.ts +++ b/packages/web-app-search/tests/unit/portals/SearchBar.spec.ts @@ -215,6 +215,36 @@ describe('Search Bar portal component', () => { const spyRouterPushStub = wrapper.vm.$router.push expect(spyRouterPushStub).not.toHaveBeenCalled() }) + test('focuses search input when pressing "s"', () => { + const { wrapper } = getMountedWrapper() + const nonEditableTarget = document.createElement('div') + document.body.appendChild(nonEditableTarget) + nonEditableTarget.focus() + const keyEvent = new KeyboardEvent('keydown', { key: 's', cancelable: true }) + + wrapper.vm.onSearchShortcut(keyEvent) + nonEditableTarget.remove() + }) + test('focuses search input when pressing "/"', () => { + const { wrapper } = getMountedWrapper() + const nonEditableTarget = document.createElement('button') + document.body.appendChild(nonEditableTarget) + nonEditableTarget.focus() + const keyEvent = new KeyboardEvent('keydown', { key: '/', cancelable: true }) + + wrapper.vm.onSearchShortcut(keyEvent) + nonEditableTarget.remove() + }) + test('does not focus search input when editable element is already focused', () => { + const { wrapper } = getMountedWrapper() + const textInput = document.createElement('input') + document.body.appendChild(textInput) + textInput.focus() + + const keyEvent = new KeyboardEvent('keydown', { key: 's', cancelable: true }) + wrapper.vm.onSearchShortcut(keyEvent) + textInput.remove() + }) }) function getMountedWrapper({ diff --git a/packages/web-pkg/src/composables/keyboardActions/useKeyboardActions.ts b/packages/web-pkg/src/composables/keyboardActions/useKeyboardActions.ts index f5f8194d59..157858e085 100644 --- a/packages/web-pkg/src/composables/keyboardActions/useKeyboardActions.ts +++ b/packages/web-pkg/src/composables/keyboardActions/useKeyboardActions.ts @@ -16,6 +16,7 @@ export enum Key { Plus = '+', Minus = '-', Space = ' ', + Slash = '/', ArrowUp = 'ArrowUp', ArrowDown = 'ArrowDown', ArrowLeft = 'ArrowLeft',