pacocoursey / cmdk

Fast, unstyled command menu React component.
https://cmdk.paco.me
MIT License
9.68k stars 279 forks source link

Custom Filter does not sort list appropriately #118

Closed joseph-mccombs closed 8 months ago

joseph-mccombs commented 1 year ago

When providing a custom filter to <Command>, the filter should use numeric weighting similar to commandScore instead of a boolean. This would allow users better control over how their lists should be sorted. For example:

<Command
   filter={(value, searchValue) => {
      if (value === "test1") return 0.5;
      if (value === "test2" return 1;
      if (value === "test3") return 0.1;
      return commandScore(value, searchValue);
   }
>
   <Command.List>
      {["test1", "test2", "test3"].map((item) => {
         <Command.Item value={item}>{item}</Command.Item>
      }
   <Command.List>
</Command>

I would expect that my list would be sorted according to the numerical filter value like so:

But its currently being ordered:

Love the library! Think this would be a nice improvement to the filter prop.

jeloi commented 1 year ago

Also running to this issue, it's pretty seriously limiting! Would love for this to get addressed!

tcolinpa commented 1 year ago

Same here.. anyone got it right?

filter: (value, search) => {
          let score = 0;
          const date = new Date(value);
          if (date.toString() === "Invalid Date") return 0;

          const splittedValue = search.includes(":")
            ? search.split(":")
            : [search];

          const hour = splittedValue[0];
          const min = splittedValue.length > 1 ? splittedValue[1] : "";

          const isSameHour = date.getHours().toString().includes(hour!);
          const isSameMin = date.getMinutes().toString().includes(min!);

          if (isSameHour) {
            score = 0.5;
            if (isSameMin) {
              score = 1;
            }
          }

          console.log(date, score);

          return score;
        }

Above is a PoC for a time input, the score prints right but it isn't computed into the sorting. If I type 15:15, the scores are: image

However, below is the current behavior

https://github.com/pacocoursey/cmdk/assets/44402590/af30c7f6-541e-4f92-8b95-6f1fd7691ca4

mlinzner commented 1 year ago

As far as I can see, sorting is never working, no matter if a custom filter is in place or not. The reason is that the scores which are used for the sorting https://github.com/pacocoursey/cmdk/blob/05199cbad94a800ee98510645f138537f368dc85/cmdk/src/index.tsx#L323 are not updated and are always undefined.

Changing https://github.com/pacocoursey/cmdk/blob/05199cbad94a800ee98510645f138537f368dc85/cmdk/src/index.tsx#L350 to

return (score(valueB) ?? 0) - (score(valueA) ?? 0)

calculates the scores everytime from scratch and the sorting works. Ultimately the state update should be fixed to work correctly, but I could not find a fix for that in a reasonable time.

katinthehatsite commented 8 months ago

I ran into the same issue, I wrote the unit tests for the filter to confirm what was happening and it returned the correct values but the sorting was not working regardless.