diff --git a/src/components/NeDropdownFilter.vue b/src/components/NeDropdownFilter.vue index d232d06..3909b43 100644 --- a/src/components/NeDropdownFilter.vue +++ b/src/components/NeDropdownFilter.vue @@ -13,6 +13,8 @@ import { v4 as uuidv4 } from 'uuid' import NeBadge from './NeBadge.vue' import NeLink from './NeLink.vue' import type { ButtonSize } from './NeButton.vue' +import NeTextInput from './NeTextInput.vue' +import { focusElement } from '@/main' export type FilterKind = 'radio' | 'checkbox' @@ -39,6 +41,12 @@ export interface Props { openMenuAriaLabel: string showClearFilter?: boolean showSelectionCount?: boolean + noOptionsLabel: string + showOptionsFilter?: boolean + optionsFilterPlaceholder?: string + // limit the number of options displayed for performance + maxOptionsShown?: number + moreOptionsHiddenLabel: string alignToRight?: boolean size?: ButtonSize disabled?: boolean @@ -48,6 +56,9 @@ export interface Props { const props = withDefaults(defineProps(), { showClearFilter: true, showSelectionCount: true, + showOptionsFilter: false, + optionsFilterPlaceholder: '', + maxOptionsShown: 25, alignToRight: false, size: 'md', disabled: false, @@ -61,6 +72,8 @@ const top = ref(0) const left = ref(0) const right = ref(0) const buttonRef = ref() +const optionsFilter = ref('') +const optionsFilterRef = ref() const componentId = computed(() => (props.id ? props.id : uuidv4())) @@ -68,6 +81,34 @@ const isSelectionCountShown = computed(() => { return props.showSelectionCount && props.kind == 'checkbox' && checkboxModel.value.length > 0 }) +const optionsToDisplay = computed(() => { + return filteredOptions.value.slice(0, props.maxOptionsShown) +}) + +const moreOptionsHidden = computed(() => { + return filteredOptions.value.length > props.maxOptionsShown +}) + +const isShowingOptionsFilter = computed(() => { + return props.showOptionsFilter || props.options.length > props.maxOptionsShown +}) + +const filteredOptions = computed(() => { + if (!isShowingOptionsFilter.value) { + // return all options + return props.options + } + + // show only options that match the options filter + + const regex = /[^a-zA-Z0-9-]/g + const queryText = optionsFilter.value.replace(regex, '') + + return props.options.filter((option) => { + return new RegExp(queryText, 'i').test(option.label?.replace(regex, '')) + }) +}) + watch( () => props.alignToRight, () => { @@ -119,6 +160,12 @@ function calculatePosition() { buttonRef.value?.$el.getBoundingClientRect().right - window.scrollX } + +function maybeFocusOptionsFilter() { + if (isShowingOptionsFilter.value) { + focusElement(optionsFilterRef) + } +}