cmdk icon indicating copy to clipboard operation
cmdk copied to clipboard

Idea: `shouldFilter` per `Group`/`Item`

Open nandorojo opened this issue 1 year ago • 2 comments

I have some items which I'm fetching from TypeSense and don't need filtering. Others are statically-defined. It would be useful to define shouldFilter at the Item/Group level, rather than only the parent. I believe cmdk is built in a way where this would be possible, but I haven't peaked at the source in a while, so I'm not totally sure. Figured I'd mention it!

nandorojo avatar Apr 04 '23 14:04 nandorojo

@nandorojo One way around this I found, is to use the searchFilter prop and assign something common to the <Command.Group> value prop to ensure that these items dont get filtered like so:

<Command
     filter={(value, search) => {
       if (value.includes(search) || value.includes("doNotFilter-")) return 1; // ensures items arent filtered
       return 0;
     }}
>
   <Command.Group>
      {unfilteredItem.map((item) => (
         <Command.Item value={`doNotFilter-${item.name}`} />
      )}
   </Command.Group>
   <Command.Group>
      {filtered.map((item) => (
         <Command.Item value={item.name} />
      )}
   </Command.Group>
</Command>

joseph-mccombs avatar Apr 10 '23 19:04 joseph-mccombs

I've also ran into a very similar use case to you, where my command consists of static data, such as links to pages, but also has dynamic data which has been fetching and searched via an API.

For example:

const Page = () => {
  const [searchTerm, setSearchTerm] = React.useState<string>('');

  const { data: itemsA } = useSearchItemsA({
    query: {
      search: searchTerm,
    },
    enabled: !!searchTerm,
  });

  const { data: itemsB } = useSearchItemsB({
    query: {
      search: searchTerm,
    },
    enabled: !!searchTerm,
  });

  return (
    <div>
      <Command>
        <Command.Input placeholder="Search…" onValueChange={setSearchTerm} />
        <Command.List>
          <Command.Empty>No results.</Command.Empty>
          <Command.Group heading="Links">
            <Command.Item>Link A</Command.Item>
            <Command.Item>Link B</Command.Item>
            <Command.Item>Link C</Command.Item>
          </Command.Group>

          {/* This data has already been filtered by an external source, do not apply additional filtering */}
          <Command.Group heading="Items A">
            {itemsA.map((item) => (
              <Command.Item key={item.id}>{item.name}</Command.Item>
            ))}
          </Command.Group>

          {/* This data has already been filtered by an external source, do not apply additional filtering */}
          <Command.Group heading="Items B">
            {itemsB.map((item) => (
              <Command.Item key={item.id}>{item.name}</Command.Item>
            ))}
          </Command.Group>
        </Command.List>
      </Command>
    </div>
  );
};

I've opened a PR, which adds shouldFilter to the Command.Item component so these items can be skipped during any filtering.

Jamess-Lucass avatar May 10 '24 20:05 Jamess-Lucass