Skip to content
This repository has been archived by the owner on Dec 23, 2022. It is now read-only.

Commit

Permalink
Add a new blurBehavior of add-or-clear (#329)
Browse files Browse the repository at this point in the history
`add-or-clear` is similar to `add`, but clears the input if `onBeforeAdd` returns `false`
  • Loading branch information
vdh committed Sep 8, 2020
1 parent 65aeee5 commit 9d1e628
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import ChipInput from 'material-ui-chip-input'
|---|---|---|---|
|allowDuplicates|`bool`|`false`|Allows duplicate chips if set to true.|
|alwaysShowPlaceholder|`bool`||If true, the placeholder will always be visible.|
|blurBehavior|`enum`|`'clear'`|Behavior when the chip input is blurred: `'clear'` clears the input, `'add'` creates a chip and `'ignore'` keeps the input.|
|blurBehavior|`enum`|`'clear'`|Behavior when the chip input is blurred: `'clear'` clears the input, `'add'` creates a chip, `'add-or-clear'` either creates a chip or clears the input on failure (see: `onBeforeAdd`), and `'ignore'` keeps the input.|
|chipRenderer|`func`||A function of the type `({ value, text, chip, isFocused, isDisabled, isReadOnly, handleClick, handleDelete, className }, key) => node` that returns a chip based on the given properties. This can be used to customize chip styles. Each item in the `dataSource` array will be passed to `chipRenderer` as arguments `chip`, `value` and `text`. If `dataSource` is an array of objects and `dataSourceConfig` is present, then `value` and `text` will instead correspond to the object values defined in `dataSourceConfig`. If `dataSourceConfig` is not set and `dataSource` is an array of objects, then a custom `chipRenderer` must be set. `chip` is always the raw value from `dataSource`, either an object or a string.|
|clearInputValueOnChange|`bool`|`false`|Whether the input value should be cleared if the `value` prop is changed.|
|dataSource|`array`||Data source for auto complete. This should be an array of strings or objects.|
Expand Down
17 changes: 13 additions & 4 deletions src/ChipInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,11 @@ class ChipInput extends React.Component {
this.setState({ focusedChip: null })
}
const value = event.target.value
let addChipOptions
switch (this.props.blurBehavior) {
case 'add-or-clear':
addChipOptions = { clearInputOnFail: true }
// falls through
case 'add':
if (this.props.delayBeforeAdd) {
// Lets assume that we only want to add the existing content as chip, when
Expand All @@ -273,13 +277,13 @@ class ChipInput extends React.Component {
this.inputBlurTimeout = setTimeout(() => {
const numChipsAfter = (this.props.value || this.state.chips).length
if (numChipsBefore === numChipsAfter) {
this.handleAddChip(value)
this.handleAddChip(value, addChipOptions)
} else {
this.clearInput()
}
}, 150)
} else {
this.handleAddChip(value)
this.handleAddChip(value, addChipOptions)
}
break
case 'clear':
Expand Down Expand Up @@ -385,11 +389,16 @@ class ChipInput extends React.Component {
/**
* Handles adding a chip.
* @param {string|object} chip Value of the chip, either a string or an object (if dataSourceConfig is set)
* @param {object=} options Additional options
* @param {boolean=} options.clearInputOnFail If `true`, and `onBeforeAdd` returns `false`, clear the input
* @returns True if the chip was added (or at least `onAdd` was called), false if adding the chip was prevented
*/
handleAddChip (chip) {
handleAddChip (chip, options) {
if (this.props.onBeforeAdd && !this.props.onBeforeAdd(chip)) {
this._preventChipCreation = true
if (options != null && options.clearInputOnFail) {
this.clearInput()
}
return false
}
this.clearInput()
Expand Down Expand Up @@ -651,7 +660,7 @@ ChipInput.propTypes = {
/** If true, the placeholder will always be visible. */
alwaysShowPlaceholder: PropTypes.bool,
/** Behavior when the chip input is blurred: `'clear'` clears the input, `'add'` creates a chip and `'ignore'` keeps the input. */
blurBehavior: PropTypes.oneOf(['clear', 'add', 'ignore']),
blurBehavior: PropTypes.oneOf(['clear', 'add', 'add-or-clear', 'ignore']),
/** A function of the type `({ value, text, chip, isFocused, isDisabled, isReadOnly, handleClick, handleDelete, className }, key) => node` that returns a chip based on the given properties. This can be used to customize chip styles. Each item in the `dataSource` array will be passed to `chipRenderer` as arguments `chip`, `value` and `text`. If `dataSource` is an array of objects and `dataSourceConfig` is present, then `value` and `text` will instead correspond to the object values defined in `dataSourceConfig`. If `dataSourceConfig` is not set and `dataSource` is an array of objects, then a custom `chipRenderer` must be set. `chip` is always the raw value from `dataSource`, either an object or a string. */
chipRenderer: PropTypes.func,
/** Whether the input value should be cleared if the `value` prop is changed. */
Expand Down
34 changes: 34 additions & 0 deletions src/ChipInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,40 @@ describe('blurBehavior modes', () => {
tree.update()
expect(tree.find('Chip').map((chip) => chip.text())).toEqual(['a', 'b', 'blur'])
})

it('adds the input on blur with blurBehavior set to add add-or-clear, if onBeforeAdd passes', () => {
const handleChange = jest.fn()
const tree = mount(
<ChipInput
defaultValue={['a', 'b']}
onChange={handleChange}
blurBehavior='add-or-clear'
onBeforeAdd={(value) => value === 'c'}
/>
)
tree.find('input').getDOMNode().value = 'c'
tree.find('input').simulate('blur')

expect(tree.find('input').getDOMNode().value).toBe('')

expect(handleChange.mock.calls[0][0]).toEqual(['a', 'b', 'c'])

tree.update()
expect(tree.find('Chip').map((chip) => chip.text())).toEqual(['a', 'b', 'c'])
})

it('clears the input on blur with blurBehavior set to add-or-clear, if onBeforeAdd fails', () => {
const tree = mount(
<ChipInput
defaultValue={['a', 'b']}
blurBehavior='add-or-clear'
onBeforeAdd={(value) => value === 'c'}
/>
)
tree.find('input').simulate('change', { target: { value: 'foo' } })
tree.find('input').simulate('blur')
expect(tree.find('input').getDOMNode().value).toBe('')
})
})

describe('keys', () => {
Expand Down
6 changes: 6 additions & 0 deletions stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ storiesOf('ChipInput', module)
)
*/
.add('add text input value on blur', () => <ChipInput blurBehavior='add' />)
.add('add number input value on blur, or clear input if not a number', () =>
<ChipInput
blurBehavior='add-or-clear'
onBeforeAdd={(value) => !Number.isNaN(parseFloat(value))}
/>
)
.add('clear text input value on blur ', () => (
<ChipInput blurBehavior='clear' />
))
Expand Down
2 changes: 1 addition & 1 deletion typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
export interface BaseTextFieldProps extends Omit<FormControlProps, 'onChange'> {
allowDuplicates?: boolean;
alwaysShowPlaceholder?: boolean;
blurBehavior?: 'clear' | 'add' | 'ignore';
blurBehavior?: 'clear' | 'add' | 'add-or-clear' | 'ignore';
chipRenderer?: ChipRenderer;
classes?: Record<string, string>;
clearInputValueOnChange?: boolean;
Expand Down

0 comments on commit 9d1e628

Please sign in to comment.