kentcdodds / match-sorter

Simple, expected, and deterministic best-match sorting of an array in JavaScript
https://npm.im/match-sorter
MIT License
3.73k stars 129 forks source link

Allow collections to maintain their sort order #75

Closed jblock closed 4 years ago

jblock commented 5 years ago

What: Adds an option to allow users to maintain their original sort order (while still filtering down their result set)

Why: I'm encountering a use case in our company's application where:

  1. We need a to be able to quickly filter down a list of options client-side via a text-based search
  2. We need to maintain the original order of those options as delivered from our server

Here's a rough mockup of the UI we're working on: 2019-09-19 17 19 03

For some context on our use-case:

Our company is building out a marketplace for landscape contractors to acquire plant material, and the "sizes" you're seeing there are a combination of some sort of dimensional measurement and the container of said plant being sold. Landscape contractors are used to seeing these different sizes grouped and sorted in a very particular way (as they were coming from using print catalogs with large tables before using our app), and we are currently maintaining said sort order within the application code of our server.

Counterintuitive as it might be, we only need the match aspect of match-sorter, as we'd like to maintain that arrangement & grouping that comes back from our server as to not jar any customers using this filter while still letting folks filter down a large list of results.

Here's what that same UI looks like when sorted by the rank returned by matchSorter:

2019-09-19 17 27 03

As you can see, one of the Container options (18" 18"w #2 Container) jumps below BB, even though it comes before all the BB options in the list. Here's how we'd prefer that behavior to look to an end user:

2019-09-19 17 36 29

How: I added an option to the main matchSorter method to allow users to preserve their initial sort order. All this does is skip the step where the reduced input gets sorted by rank.

Checklist:

Let me know if this behavior is out-of-scope for this library! We have a workaround, but since the change was relatively straightforward I figured we might as well explore contributing something back upstream.

Our workaround:

const sizes = [/* ... */]

function Component({sizes}) {
  const [query, setQuery] = useState("");
  // Omitting all the code for the input actually changing `query`

  const filteredSizes = matchSorter(sizes, query)

  return <ul>
    {sizes
      .filter(size => filteredSizes.includes(size))
      .map(size => <li key={size}>{size}</li>)}
  </ul>
}
kentcdodds commented 5 years ago

This does feel a little bit out of scope, but what if we allowed this:

import {filter as matchFilter} from 'match-sorter'

const filteredSizes = matchFilter(sizes, query)

That should be relatively easy to accomplish I think. What do you think?

jblock commented 5 years ago

That'd definitely work for us! I'll push up some changes in that vein for review in the next day or two

kentcdodds commented 4 years ago

This is now supported with the new baseSort option