Skip to content

Commit

Permalink
feature(BcContentFilter): improve UX via focus management
Browse files Browse the repository at this point in the history
`.stop` modifier will stop `event propagation` which is useful
when the `focus` is in the `input field`, while the component
is used in a `dialog`, which should not get `closed` then.

Add `sr-only` (screen reader only) class for `a11y`

See: BIDS-3248
See: BEDS-161
  • Loading branch information
MarcelBitfly authored and marcel-bitfly committed Aug 6, 2024
1 parent a6969a1 commit 104f319
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 78 deletions.
13 changes: 13 additions & 0 deletions frontend/assets/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,16 @@ svg{
}
}
}

// see https://tailwindcss.com/docs/screen-readers
sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
107 changes: 107 additions & 0 deletions frontend/components/bc/BcContentFilter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<script lang="ts" setup>
import { faMagnifyingGlass } from '@fortawesome/pro-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import type InputText from 'primevue/inputtext'
interface Props {
searchPlaceholder?: string;
disabledFilter?: boolean;
}
const props = defineProps<Props>()
defineEmits<{(e: 'filter-changed', value: string): void }>()
const isFilterVisible = ref(false)
const filter = ref('')
const button = ref<{$el: HTMLButtonElement} | null>(null)
const input = ref<{$el: HTMLInputElement} | null>(null)
const focusAndSelect = (inputElement: {$el: HTMLInputElement}) => {
if (inputElement?.$el) {
// make sure the input is not disabled anymore
nextTick(() => {
inputElement.$el.focus()
inputElement.$el.select()
})
}
}
const closeFilter = () => {
isFilterVisible.value = false
button.value?.$el.focus()
}
const handleClick = () => {
isFilterVisible.value = !isFilterVisible.value
if (input.value) {
focusAndSelect(input.value)
}
}
</script>

<template>
<div class="filter_elements_container">
<InputText
ref="input"
v-model="filter"
:placeholder="props.searchPlaceholder"
:disabled="!isFilterVisible"
:class="{ visible: isFilterVisible }"
@keydown.escape.stop="closeFilter"
@input="$emit('filter-changed', filter)"
/>
<Button
ref="button"
:disabled="disabledFilter"
:aria-expanded="isFilterVisible"
class="p-button-icon-only"
:class="{ filter_visible: isFilterVisible }"
@click="handleClick"
>
<span class="sr-only">
{{ !isFilterVisible ? $t('filter.open') : $t('filter.close') }}
</span>
<FontAwesomeIcon :icon="faMagnifyingGlass" />
</Button>
</div>
</template>

<style lang="scss">
.filter_elements_container {
display: flex;
justify-content: flex-end;
position: relative;
> :first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
height: var(--default-button-height);
width: 0;
opacity: 0;
padding: 0;
position: absolute;
transition: width 0.2s ease-in-out, opacity 0.01s ease-in-out 0.19s,
padding 0.2s ease-in-out;
&.visible {
width: 230px;
opacity: 100%;
padding: 4px;
transition: width 0.2s ease-in-out, opacity 0.01s ease-in-out,
padding 0.2s ease-in-out;
}
}
> :last-child {
flex-shrink: 0;
border-top-left-radius: var(--border-radius);
border-bottom-left-radius: var(--border-radius);
transition: all 0.2s ease-in-out;
&.filter_visible {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
</style>
77 changes: 0 additions & 77 deletions frontend/components/bc/ContentFilter.vue

This file was deleted.

4 changes: 3 additions & 1 deletion frontend/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@
"valid": "Valid"
},
"filter": {
"close": "Open Filter.",
"disabled": "Filter disabled.",
"enabled": "Filter enabled.",
"disabled": "Filter disabled."
"open": "Close Filter."
},
"premium": {
"title": "beaconcha.in Premium",
Expand Down

0 comments on commit 104f319

Please sign in to comment.