Skip to content

Commit bf2476d

Browse files
authored
[#281] Improve new lane title editor (#297)
* [#281] Add improved new lane title editor * Add react-click-outside
1 parent 93cea44 commit bf2476d

File tree

4 files changed

+131
-16
lines changed

4 files changed

+131
-16
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"immutability-helper": "^2.8.1",
4646
"lodash": "^4.17.11",
4747
"prop-types": "^15.7.2",
48+
"react-click-outside": "tj/react-click-outside",
4849
"react-popopo": "^2.1.9",
4950
"react-redux": "^5.0.7",
5051
"redux": "^4.0.0",

src/components/NewLaneForm.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,57 @@
1-
import React, {Component} from 'react'
1+
import React, { Component } from 'react'
22
import PropTypes from 'prop-types'
3-
import {LaneTitle, NewLaneButtons, Section} from 'rt/styles/Base'
4-
import {AddButton, CancelButton} from 'rt/styles/Elements'
5-
import EditableLabel from 'rt/widgets/EditableLabel'
3+
import { LaneTitle, NewLaneButtons, Section } from 'rt/styles/Base'
4+
import { AddButton, CancelButton } from 'rt/styles/Elements'
5+
import NewLaneTitleEditor from 'rt/widgets/NewLaneTitleEditor'
6+
import ClickOutside from 'react-click-outside'
67

7-
class NewLaneForm extends Component {
8-
updateField = (field, value) => {
9-
this.setState({[field]: value})
8+
class NewLane extends Component {
9+
handleSubmit = () => {
10+
this.props.onAdd({ title: this.getValue() })
1011
}
1112

12-
handleAdd = () => {
13-
this.props.onAdd(this.state)
13+
getValue = () => this.refInput.getValue()
14+
15+
onClickOutside = (a,b,c) => {
16+
if (this.getValue().length > 0) {
17+
this.handleSubmit()
18+
} else {
19+
this.props.onCancel()
20+
}
1421
}
1522

1623
render() {
17-
const {onCancel, t} = this.props
24+
const { onCancel, t } = this.props
1825
return (
26+
<ClickOutside onClickOutside={this.onClickOutside}>
1927
<Section>
2028
<LaneTitle>
21-
<EditableLabel placeholder={t('placeholder.title')} onChange={val => this.updateField('title', val)} autoFocus/>
29+
<NewLaneTitleEditor
30+
ref={ref => (this.refInput = ref)}
31+
placeholder={t('placeholder.title')}
32+
onCancel={this.props.onCancel}
33+
onSave={this.handleSubmit}
34+
resize='vertical'
35+
border
36+
autoFocus
37+
/>
2238
</LaneTitle>
2339
<NewLaneButtons>
24-
<AddButton onClick={this.handleAdd}>{t('button.Add lane')}</AddButton>
40+
<AddButton onClick={this.handleSubmit}>{t('button.Add lane')}</AddButton>
2541
<CancelButton onClick={onCancel}>{t('button.Cancel')}</CancelButton>
2642
</NewLaneButtons>
2743
</Section>
44+
</ClickOutside>
2845
)
2946
}
3047
}
3148

32-
NewLaneForm.propTypes = {
49+
NewLane.propTypes = {
3350
onCancel: PropTypes.func.isRequired,
3451
onAdd: PropTypes.func.isRequired,
35-
t: PropTypes.func.isRequired
52+
t: PropTypes.func.isRequired,
3653
}
37-
NewLaneForm.defaultProps = {}
3854

39-
export default NewLaneForm
55+
NewLane.defaultProps = {}
56+
57+
export default NewLane

src/widgets/NewLaneTitleEditor.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
import {InlineInput} from 'rt/styles/Base'
4+
import autosize from 'autosize'
5+
6+
class NewLaneTitleEditor extends React.Component {
7+
onKeyDown = (e) => {
8+
if(e.keyCode == 13) {
9+
this.refInput.blur()
10+
this.props.onSave()
11+
e.preventDefault()
12+
}
13+
if(e.keyCode == 27) {
14+
this.cancel()
15+
e.preventDefault()
16+
}
17+
18+
if(e.keyCode == 9) {
19+
if (this.getValue().length == 0) {
20+
this.cancel()
21+
} else {
22+
this.props.onSave()
23+
}
24+
e.preventDefault()
25+
}
26+
}
27+
28+
cancel = () => {
29+
this.setValue('')
30+
this.props.onCancel()
31+
this.refInput.blur()
32+
}
33+
34+
getValue = () => this.refInput.value
35+
setValue = (value) => this.refInput.value = value
36+
37+
saveValue = () => {
38+
if (this.getValue() != this.props.value) {
39+
this.props.onSave(this.getValue())
40+
}
41+
}
42+
43+
focus = () => this.refInput.focus()
44+
45+
setRef = (ref) => {
46+
this.refInput = ref
47+
if (this.props.resize != 'none') {
48+
autosize(this.refInput)
49+
}
50+
}
51+
52+
render() {
53+
const {autoFocus, resize, border, autoResize, value, placeholder} = this.props
54+
55+
return <InlineInput
56+
style={{resize: resize}}
57+
ref={this.setRef}
58+
border={border}
59+
onKeyDown={this.onKeyDown}
60+
placeholder={value.length == 0 ? undefined : placeholder}
61+
defaultValue={value}
62+
rows={3}
63+
autoResize={autoResize}
64+
autoFocus={autoFocus}
65+
/>
66+
}
67+
}
68+
69+
NewLaneTitleEditor.propTypes = {
70+
onSave: PropTypes.func,
71+
onCancel: PropTypes.func,
72+
border: PropTypes.bool,
73+
placeholder: PropTypes.string,
74+
value: PropTypes.string,
75+
autoFocus: PropTypes.bool,
76+
autoResize: PropTypes.bool,
77+
resize: PropTypes.oneOf(['none', 'vertical', 'horizontal']),
78+
}
79+
80+
NewLaneTitleEditor.defaultProps = {
81+
inputRef: () => {},
82+
onSave: () => {},
83+
onCancel: () => {},
84+
placeholder: '',
85+
value: '',
86+
border: false,
87+
autoFocus: false,
88+
autoResize: false,
89+
resize: 'none'
90+
}
91+
92+
export default NewLaneTitleEditor

yarn.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11708,6 +11708,10 @@ react-addons-create-fragment@^15.5.3:
1170811708
loose-envify "^1.3.1"
1170911709
object-assign "^4.1.0"
1171011710

11711+
react-click-outside@tj/react-click-outside:
11712+
version "1.1.1"
11713+
resolved "https://codeload.github.com/tj/react-click-outside/tar.gz/a833ddc5be47490307f9fcc6ed09d8c353108510"
11714+
1171111715
react-dev-utils@^6.1.0:
1171211716
version "6.1.1"
1171311717
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-6.1.1.tgz#a07e3e8923c4609d9f27e5af5207e3ca20724895"

0 commit comments

Comments
 (0)