Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
Fixes inserting empty return if there is nothing in field (#464)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjbo authored and Jon Quach committed Jan 31, 2019
1 parent 4794f98 commit 3b15148
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 12 deletions.
25 changes: 19 additions & 6 deletions src/components/Input/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Keys from '../../constants/Keys'
import { classNames } from '../../utilities/classNames'
import { namespaceComponent } from '../../utilities/component'
import { createUniqueIDFactory } from '../../utilities/id'
import { isModifierKeyPressed } from '../../utilities/keys'
import { isDefined } from '../../utilities/is'
import { noop, requestAnimationFrame } from '../../utilities/other'
import {
Expand Down Expand Up @@ -353,15 +354,27 @@ export class Input extends Component<Props, State> {
}

insertCarriageReturnAtCursorIndex(event) {
if (!(event.ctrlKey || event.metaKey || event.altKey)) return
const cursorIndex = event.currentTarget.selectionStart
const nextValue = event.currentTarget.value
const prevValue = this.state.value

// this prevents a return being inserted if the field is completely empty
// this works on every modifier key, and with standalone returns
const isEmptyField =
cursorIndex == 0 && nextValue.length === 0 && prevValue.length === 0

if (isEmptyField) {
event.preventDefault() // prevents shift and return from inserting a line break
return
}

if (!isModifierKeyPressed(event)) return
// this inserts a return into the value if a modifier key is also pressed
event.preventDefault()
event.stopPropagation()
const cursorIndex = event.currentTarget.selectionStart
const currentValue = event.currentTarget.value
const newValue = `${currentValue.substr(
0,
const newValue = `${nextValue.substr(0, cursorIndex)}\n${nextValue.substr(
cursorIndex
)}\n${currentValue.substr(cursorIndex)}`
)}`
this.setState({ value: newValue }, () => {
this.props.onChange(this.state.value)
this.inputNode.setSelectionRange(cursorIndex + 1, cursorIndex + 1)
Expand Down
38 changes: 32 additions & 6 deletions src/components/Input/__tests__/Input.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,18 +185,44 @@ describe('Events', () => {
})

describe('insertCarriageReturnsAtCursorIndex', () => {
test('expect state to get set', () => {
const onChangeSpy = jest.fn()
const setSelectionRangeSpy = jest.fn()
const preventDefaultSpy = jest.fn()
const stopPropagationSpy = jest.fn()
const wrapper = shallow(
let onChangeSpy,
preventDefaultSpy,
setSelectionRangeSpy,
stopPropagationSpy,
wrapper

beforeEach(() => {
onChangeSpy = jest.fn()
setSelectionRangeSpy = jest.fn()
preventDefaultSpy = jest.fn()
stopPropagationSpy = jest.fn()
wrapper = shallow(
<Input hasInsertCarriageReturns={true} onChange={onChangeSpy} />
)
wrapper
.instance()
.setInputNodeRef({ setSelectionRange: setSelectionRangeSpy })
wrapper.instance().setState = jest.fn((newState, callback) => callback())
})

test('if empty value with cursorIndex at 0, should only call preventDefault', () => {
wrapper.instance().insertCarriageReturnAtCursorIndex({
shiftKey: true,
preventDefault: preventDefaultSpy,
stopPropagation: stopPropagationSpy,
currentTarget: {
selectionStart: 0,
value: '',
},
})
expect(preventDefaultSpy).toHaveBeenCalledTimes(1)
expect(stopPropagationSpy).toHaveBeenCalledTimes(0)
expect(wrapper.instance().setState).toHaveBeenCalledTimes(0)
expect(onChangeSpy).toHaveBeenCalledTimes(0)
expect(setSelectionRangeSpy).toHaveBeenCalledTimes(0)
})

test('expect state to get set and update the value', () => {
wrapper.instance().insertCarriageReturnAtCursorIndex({
ctrlKey: true,
preventDefault: preventDefaultSpy,
Expand Down

0 comments on commit 3b15148

Please sign in to comment.