shadcn-vue
shadcn-vue copied to clipboard
[Feature]: Make it possible to use CommandInput with our own filtering method
Describe the feature
I want to do a "CommandDialog" with a CommandInput but use Algolia to search in my database collections.
The issue I have is that if I use CommandInput, it automatically does the filtering using each CommandItem "value" but I want to avoid this since I create the CommandItem dynamically with the algolia search results, and the algolia filters are more complex than just filtering text on "value"
also there is a weird issue if I change the filters by typing, deleting, starting again, the "CommandItem" seem to be accessed in a random order (and some are not accessible) when using up and down keys? (you will see the selected item "jump around" sometimes, although I only press either "down key" multiple times, or "up key" multiple times, but I don't mix them)
https://github.com/radix-vue/shadcn-vue/assets/15458/fee362d0-a38d-409d-81b6-c70db90d430e
Additional information
- [ ] I intend to submit a PR for this feature.
- [ ] I have already implemented and/or tested this feature.
To make it clear: I'd like a way to do the CommandDialog where the CommandInput only lets me select options with up/down, but does not filter on its own the content, so that I can use something like this to dynamically replace the result, and still use the "up/down/enter" selection
<CommandDialog :open="open" @update:open="(v) => (open = v)">
<ais-instant-search
:search-client="searchClient"
:index-name="searchIndexes.batteryAssemblies"
:stalled-search-delay="200"
>
<ais-configure :hits-per-page.camel="5" />
<ais-search-box placeholder="Type to search...">
<template v-slot="{ refine }">
<CommandInput
@input="refine($event.currentTarget.value)"
placeholder="Type to search..."
></CommandInput>
</template>
</ais-search-box>
<algolia-loading-indicator />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup
:heading="category.title"
v-for="category in categories"
:key="category.value"
>
<ais-index :index-name="category.searchIndex">
<ais-hits>
<template #item="{ item }">
<CommandItem
:value="item.id"
:key="item.id"
@click="
(event) => openCategoryId(event, category.value, item.id)
"
>
{{ item.id }}
</CommandItem>
</template>
</ais-hits>
</ais-index>
</CommandGroup>
</CommandList>
</ais-instant-search>
</CommandDialog>
Ha it seems it is possible to do what I want by ading the "filter-function" prop of "Command" to the "CommandDialog" helper
Hmmm @zernonia I'm trying to do this to put the "filterFunction" on the Command in CommandDialog, but it complains because it also appears in "filtered" and therefore on "Dialog", do you know how to solve this?
<script setup lang="ts">
import { defineProps, defineEmits } from "vue";
import { useForwardPropsEmits, VisuallyHidden } from "radix-vue";
import type { DialogRootEmits, DialogRootProps } from "radix-vue";
import Command from "./Command.vue";
import {
Dialog,
DialogContent,
DialogTitle,
DialogDescription,
} from "../index";
const props = defineProps<
DialogRootProps & {
filterFunction?: (val: Array<string | any>, term: string) => Array<any>;
}
>();
const emits = defineEmits<DialogRootEmits>();
const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<Dialog v-bind="forwarded">
<DialogContent class="p-0 overflow-hidden shadow-lg">
<VisuallyHidden>
<!-- TODO: would be better if the title could be updated via a prop, so it could be changed for each case -->
<DialogTitle>Type command or search</DialogTitle>
<DialogDescription
>Type command or search</DialogDescription
></VisuallyHidden
>
<Command
:filterFunction="props.filterFunction"
class="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
>
<slot />
</Command>
</DialogContent>
</Dialog>
</template>
Doing this now, but it feels like a hack... perhaps there's a better way to allow adding the props of "Command" on the "CommandDialog" to make it more flexible?
Speaking of CommandDialog, I also had warnings from vue saying it misses a DialogTitle and a DialogDescription for accessibility, so I had to do this, there's probably a better way?
Started working on this but need some more tests to make a PR, have some issues with output CommandItem component with v-for directive after API call (mock data for test)
Don't work with Algolia previously, but will try to make a new Demo for such testcase, think that it will be helpful because every second website uses this type of search engine 😅
Any progress on this?
For me I just added this to CommandDialog:
<script setup lang="ts">
import { useForwardPropsEmits } from "radix-vue";
import type { DialogRootEmits, DialogRootProps } from "radix-vue";
import {
Command,
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@ui";
import { computed } from "vue";
// We define our own filterFunction, so we are able to use this with Algolia for instance
const props = defineProps<
DialogRootProps & {
filterFunction?: (val: Array<string | any>, term: string) => Array<any>;
}
>();
const emits = defineEmits<DialogRootEmits>();
const forwarded = useForwardPropsEmits(props, emits);
const forwardedExceptFilterFunction = computed(() => {
const { filterFunction: _, ...rest } = forwarded.value;
return rest;
});
</script>
<template>
<Dialog v-bind="forwardedExceptFilterFunction">
<!-- Hidden header because otherwise the framework complains that there is no description -->
<DialogHeader class="hidden">
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<DialogContent class="overflow-hidden p-0 shadow-lg">
<Command
:filter-function="filterFunction"
class="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
>
<slot />
</Command>
</DialogContent>
</Dialog>
</template>
Added a PR here @sadeghbarati https://github.com/radix-vue/shadcn-vue/pull/368