Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Dropdown): make deburr opt-in, and deburr input #2223

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react'
import _ from 'lodash'
import { Dropdown } from 'semantic-ui-react'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's sort imports in alphabetical order

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course! 😄 On it!

Is there a linting rule for this that I'm missing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, we don't have or don't use it 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright. Btw, how do you sort it? Alphabetically by module name, i.e. react, lodash, and semantic-ui-react?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--> lodash, react, semantic-ui-react

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, by module name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating. FWIW, there is a fixable lint rule for this that we should turn on sort-imports so this is done automatically for people.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@levithomason It seems that lint does not sort on the module name, but rather on the imported member, or am I missing something?


const caseSensitiveSearch = (options, query) => {
const re = new RegExp(_.escapeRegExp(query))
return options.filter(opt => re.test(opt.text))
}

const options = [
{ key: 'a', value: 'a', text: 'UPPERCASE' },
{ key: 'b', value: 'b', text: 'lowercase' },
]

const DropdownExampleCustomSearchFunction = () => (
<Dropdown
options={options}
search={caseSensitiveSearch}
selection
fluid
placeholder={'Try to search for case or CASE'}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And props in alphatical order, too 😄

/>
)

export default DropdownExampleCustomSearchFunction
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react'
import { Dropdown } from 'semantic-ui-react'

const options = [
{ key: 'a', value: 'a', text: 'Café with accent' },
{ key: 'b', value: 'b', text: 'Cafe without accent' },
{ key: 'c', value: 'c', text: 'Déjà vu' },
{ key: 'd', value: 'd', text: 'Deja vu' },
{ key: 'e', value: 'e', text: 'Scandinavian å ä æ ø ö' },
{ key: 'f', value: 'f', text: 'Scandinavian a a ae o o' },
]

const DropdownExampleSearchSelection = () => (
<Dropdown
placeholder='Try to search for "Deja vu"'
fluid
search
selection
deburr
options={options}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^

/>
)

export default DropdownExampleSearchSelection
10 changes: 10 additions & 0 deletions docs/app/Examples/modules/Dropdown/Usage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ const DropdownUsageExamples = () => (
selection.
</Message>
</ComponentExample>
<ComponentExample
title='Search Deburr'
description='A dropdown allows the search to ignore diacritics.'
examplePath='modules/Dropdown/Usage/DropdownExampleDeburrSearch'
/>
<ComponentExample
title='Custom Search Function'
description='A dropdown allows you to provide your own search function.'
examplePath='modules/Dropdown/Usage/DropdownExampleCustomSearchFunction'
/>
<ComponentExample
title='Upward'
description='A dropdown can open its menu upward.'
Expand Down
3 changes: 3 additions & 0 deletions src/modules/Dropdown/Dropdown.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export interface DropdownProps {
/** A compact dropdown has no minimum width. */
compact?: boolean;

/** Whether or not the dropdown should strip diacritics in options and input search */
deburr?: boolean;

/** Initial value of open. */
defaultOpen?: boolean;

Expand Down
14 changes: 11 additions & 3 deletions src/modules/Dropdown/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ export default class Dropdown extends Component {
/** A compact dropdown has no minimum width. */
compact: PropTypes.bool,

/** Whether or not the dropdown should strip diacritics in options and input search */
deburr: PropTypes.bool,

/** Initial value of open. */
defaultOpen: PropTypes.bool,

Expand Down Expand Up @@ -354,6 +357,7 @@ export default class Dropdown extends Component {
additionLabel: 'Add ',
additionPosition: 'top',
closeOnBlur: true,
deburr: false,
icon: 'dropdown',
minCharacters: 1,
noResultsMessage: 'No results found.',
Expand Down Expand Up @@ -787,7 +791,7 @@ export default class Dropdown extends Component {
// There are times when we need to calculate the options based on a value
// that hasn't yet been persisted to state.
getMenuOptions = (value = this.state.value, options = this.props.options) => {
const { multiple, search, allowAdditions, additionPosition, additionLabel } = this.props
const { multiple, search, allowAdditions, additionPosition, additionLabel, deburr } = this.props
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's sort props there too

const { searchQuery } = this.state

let filteredOptions = options
Expand All @@ -802,9 +806,13 @@ export default class Dropdown extends Component {
if (_.isFunction(search)) {
filteredOptions = search(filteredOptions, searchQuery)
} else {
const re = new RegExp(_.escapeRegExp(searchQuery), 'i')
// remove diacritics on search
filteredOptions = _.filter(filteredOptions, opt => re.test(_.deburr(opt.text)))
const strippedQuery = deburr ? _.deburr(searchQuery) : searchQuery

const re = new RegExp(_.escapeRegExp(strippedQuery), 'i')

filteredOptions = _.filter(filteredOptions, opt =>
re.test(deburr ? _.deburr(opt.text) : opt.text))
}
}

Expand Down
60 changes: 53 additions & 7 deletions test/specs/modules/Dropdown/Dropdown-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -658,22 +658,68 @@ describe('Dropdown', () => {
.find('.selected')
.should.contain.text('a2')
})
it('filter after diacritics', () => {
it('filters diacritics on options when using deburr prop', () => {
const inputText = 'floresti'
const textToFind = 'FLOREŞTI'

const opts = [
{ text: 'FLOREŞTI', value: '1' },
{ text: 'ŞANŢU FLOREŞTI', value: '2' },
{ text: 'FLOREŞTI Alba', value: '3' },
{ text: textToFind, value: '1' },
{ text: `ŞANŢU ${textToFind}`, value: '2' },
{ text: `${textToFind} Alba`, value: '3' },
]

// search for 'floresti'
wrapperMount(<Dropdown options={opts} search selection />)
wrapperMount(<Dropdown options={opts} search deburr selection />)
.simulate('click')
.find('input.search')
.simulate('change', { target: { value: inputText } })

wrapper
.find('.selected')
.should.contain.text(textToFind)
})
it('filters diacritics on input when using deburr prop', () => {
const inputText = 'FLORÉŞTI'
const textToFind = 'FLORESTI'

const opts = [
{ text: textToFind, value: '1' },
{ text: `SANTU ${textToFind}`, value: '2' },
{ text: `${textToFind} Alba`, value: '3' },
]

// search for 'floresti'
wrapperMount(<Dropdown options={opts} search deburr selection />)
.simulate('click')
.find('input.search')
.simulate('change', { target: { value: 'floresti' } })
.simulate('change', { target: { value: inputText } })

wrapper
.find('.selected')
.should.contain.text('FLOREŞTI')
.should.contain.text(textToFind)
})
it('should not filter diacritics when deburr is not set', () => {
const inputText = 'FLORÉŞTI'
const textToFind = 'FLORESTI'

// Add this in case the default 'no results text' changes.
const noResultsText = 'NoResultsFound'

const opts = [
{ text: textToFind, value: '1' },
{ text: `SANTU ${textToFind}`, value: '2' },
{ text: `${textToFind} Alba`, value: '3' },
]

// search for 'floresti'
wrapperMount(<Dropdown options={opts} search selection noResultsMessage={noResultsText} />)
.simulate('click')
.find('input.search')
.simulate('change', { target: { value: inputText } })

wrapper
.find('.message')
.should.contain.text(noResultsText)
})
it('still works after encountering "no results"', () => {
const opts = [
Expand Down