vuetify
Version:
Vue Material Component Framework
105 lines (103 loc) • 3.73 kB
JavaScript
/* eslint-disable max-statements */
/* eslint-disable no-labels */
// Utilities
import { getPropertyFromItem, propsFactory, wrapInArray } from "../util/index.mjs";
import { computed, ref, unref, watchEffect } from 'vue';
// Types
// Composables
export const defaultFilter = (value, query, item) => {
if (value == null || query == null) return -1;
return value.toString().toLocaleLowerCase().indexOf(query.toString().toLocaleLowerCase());
};
export const makeFilterProps = propsFactory({
customFilter: Function,
customKeyFilter: Object,
filterKeys: [Array, String],
filterMode: {
type: String,
default: 'intersection'
},
noFilter: Boolean
}, 'filter');
export function filterItems(items, query, options) {
const array = [];
// always ensure we fall back to a functioning filter
const filter = options?.default ?? defaultFilter;
const keys = options?.filterKeys ? wrapInArray(options.filterKeys) : false;
const customFiltersLength = Object.keys(options?.customKeyFilter ?? {}).length;
if (!items?.length) return array;
loop: for (let i = 0; i < items.length; i++) {
const item = items[i];
const customMatches = {};
const defaultMatches = {};
let match = -1;
if (query && !options?.noFilter) {
if (typeof item === 'object') {
const filterKeys = keys || Object.keys(item);
for (const key of filterKeys) {
const value = getPropertyFromItem(item, key, item);
const keyFilter = options?.customKeyFilter?.[key];
match = keyFilter ? keyFilter(value, query, item) : filter(value, query, item);
if (match !== -1 && match !== false) {
if (keyFilter) customMatches[key] = match;else defaultMatches[key] = match;
} else if (options?.filterMode === 'every') {
continue loop;
}
}
} else {
match = filter(item, query, item);
if (match !== -1 && match !== false) {
defaultMatches.title = match;
}
}
const defaultMatchesLength = Object.keys(defaultMatches).length;
const customMatchesLength = Object.keys(customMatches).length;
if (!defaultMatchesLength && !customMatchesLength) continue;
if (options?.filterMode === 'union' && customMatchesLength !== customFiltersLength && !defaultMatchesLength) continue;
if (options?.filterMode === 'intersection' && (customMatchesLength !== customFiltersLength || !defaultMatchesLength)) continue;
}
array.push({
index: i,
matches: {
...defaultMatches,
...customMatches
}
});
}
return array;
}
export function useFilter(props, items, query, options) {
const strQuery = computed(() => typeof query?.value !== 'string' && typeof query?.value !== 'number' ? '' : String(query.value));
const filteredItems = ref([]);
const filteredMatches = ref(new Map());
watchEffect(() => {
filteredItems.value = [];
filteredMatches.value = new Map();
const transformedItems = unref(items);
const results = filterItems(transformedItems, strQuery.value, {
customKeyFilter: props.customKeyFilter,
default: props.customFilter,
filterKeys: unref(options?.filterKeys) ?? props.filterKeys,
filterMode: props.filterMode,
noFilter: props.noFilter
});
results.forEach(_ref => {
let {
index,
matches
} = _ref;
const item = transformedItems[index];
filteredItems.value.push(item);
filteredMatches.value.set(item.value, matches);
});
});
function getMatches(item) {
return filteredMatches.value.get(item.value);
}
return {
filteredItems,
filteredMatches,
getMatches
};
}
//# sourceMappingURL=filter.mjs.map