Skip to content

Commit 93dd4fa

Browse files
authored
Merge pull request #283 from rcdexta/feature/inline-lane-title
[#278 #263] Feature/inline lane title [testing]
2 parents 36da27a + 2b4bae0 commit 93dd4fa

14 files changed

Lines changed: 1706 additions & 710 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
# Changelog
2+
23
All notable changes to this project will be documented in this file.
34

45
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
56
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
67

7-
## Unreleased
8+
## [Unreleased]
9+
10+
## [2.3.0-alpha.1] - 2019-07-15
11+
12+
### Added
13+
14+
* Add `editLaneTitle` and `onLaneUpdate` props (availability to inline edit lane
15+
title)
816

917
## [2.2.0-alpha.1] - 2019-07-01
1018

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ This is the container component that encapsulates the lanes and cards
111111
| editable | boolean | Makes the entire board editable. Allow cards to be added or deleted Default: false |
112112
| canAddLanes | boolean | Allows new lanes to be added to the board. Default: false |
113113
| hideCardDeleteIcon | boolean | Disable showing the delete icon to the top right corner of the card (when board is editable) |
114+
| editLaneTitle | boolean | Allow inline lane title edit Default: false |
114115

115116

116117
### Callbacks and handlers
@@ -128,7 +129,8 @@ This is the container component that encapsulates the lanes and cards
128129
| onCardMoveAcrossLanes | function | Called when a card is moved across lanes `onCardMoveAcrossLanes(fromLaneId, toLaneId, cardId, index)` |
129130
| onLaneAdd | function | Called when a new lane is added: `onLaneAdd(params)` |
130131
| onLaneDelete | function | Called when a lane is deleted `onLaneDelete(laneId)` |
131-
| onLaneClick | function | Called when a lane is clicked: `onLaneClick(laneId)`. Card clicks are not propagated to lane click event |
132+
| onLaneUpdate | function | Called when a lane attributes are updated `onLaneUpdate(laneId, data)` |
133+
| onLaneClick | function | Called when a lane is clicked `onLaneClick(laneId)`. Card clicks are not propagated to lane click event |
132134
| onLaneScroll | function | Called when a lane is scrolled to the end: `onLaneScroll(requestedPage, laneId)` |
133135

134136
### Other functions

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-trello",
3-
"version": "2.2.0-alpha.1",
3+
"version": "2.3.0-alpha.2",
44
"description": "Pluggable components to add a trello like kanban board to your application",
55
"main": "dist/index.js",
66
"jsnext:main": "components/index.js",
@@ -42,6 +42,7 @@
4242
"homepage": "https://github.com/rcdexta/react-trello",
4343
"dependencies": {
4444
"@terebentina/react-popover": "^2.0.0",
45+
"autosize": "^4.0.2",
4546
"classnames": "^2.2.6",
4647
"immutability-helper": "^2.8.1",
4748
"lodash": "^4.17.11",

src/actions/LaneActions.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const removeCard = createAction('REMOVE_CARD')
55
export const moveCardAcrossLanes = createAction('MOVE_CARD')
66
export const updateCards = createAction('UPDATE_CARDS')
77
export const updateLanes = createAction('UPDATE_LANES')
8+
export const updateLane = createAction('UPDATE_LANE')
89
export const paginateLane = createAction('PAGINATE_LANE')
910
export const moveLane = createAction('MOVE_LANE')
1011
export const removeLane = createAction('REMOVE_LANE')

src/components/Lane/LaneHeader.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
11
import React from 'react'
22
import PropTypes from 'prop-types'
3-
import EditableLabel from 'components/widgets/EditableLabel'
4-
3+
import InlineInput from 'components/widgets/InlineInput'
54
import {Title, LaneHeader, RightContent } from 'styles/Base'
65
import LaneMenu from './LaneHeader/LaneMenu'
76

87
const LaneHeaderComponent = ({
9-
updateTitle, canAddLanes, onDelete, onDoubleClick, inlineEditTitle, label, title, titleStyle, labelStyle, t
8+
updateTitle, canAddLanes, onDelete, onDoubleClick, editLaneTitle, label, title, titleStyle, labelStyle, t
109
}) => {
1110

1211
return (
13-
<LaneHeader onDoubleClick={onDoubleClick}>
12+
<LaneHeader onDoubleClick={onDoubleClick} editLaneTitle={editLaneTitle}>
1413
<Title style={titleStyle}>
15-
{inlineEditTitle ?
16-
<EditableLabel value={title} border placeholder={t('placeholder.title')} onSave={updateTitle} /> :
17-
title
18-
}
14+
{editLaneTitle ?
15+
<InlineInput value={title} border placeholder={t('placeholder.title')} onSave={updateTitle} /> :
16+
title
17+
}
1918
</Title>
2019
{label && (
2120
<RightContent>
2221
<span style={labelStyle}>{label}</span>
23-
</RightContent>
24-
)}
22+
</RightContent>
23+
)}
2524
{canAddLanes && <LaneMenu t={t} onDelete={onDelete}/>}
2625
</LaneHeader>
2726
)
2827
}
2928

3029
LaneHeaderComponent.propTypes = {
3130
updateTitle: PropTypes.func,
32-
inlineEditTitle: PropTypes.bool,
31+
editLaneTitle: PropTypes.bool,
3332
canAddLanes: PropTypes.bool,
3433
label: PropTypes.string,
3534
title: PropTypes.string,
3635
onDelete: PropTypes.func,
3736
onDoubleClick: PropTypes.func,
37+
editLaneTitle: PropTypes.bool,
3838
t: PropTypes.func.isRequired
3939
}
4040

4141
LaneHeaderComponent.defaultProps = {
4242
updateTitle: () => {},
43-
inlineEditTitle: false,
43+
editLaneTitle: false,
4444
canAddLanes: false
4545
}
4646

src/components/widgets/EditableLabel.js

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ import React from 'react'
22
import PropTypes from 'prop-types'
33

44
class EditableLabel extends React.Component {
5-
state = {text: ''}
5+
constructor({value}) {
6+
super()
7+
this.state = { value: value }
8+
}
69

710
getText = el => {
811
return el.innerText
912
}
1013

1114
onTextChange = ev => {
12-
const text = this.getText(ev.target)
13-
this.setState({text: text})
15+
const value = this.getText(ev.target)
16+
this.setState({value: value})
1417
}
1518

1619
componentDidMount() {
@@ -20,20 +23,35 @@ class EditableLabel extends React.Component {
2023
}
2124

2225
onBlur = () => {
23-
this.props.onChange(this.state.text)
26+
this.props.onChange(this.state.value)
2427
}
2528

2629
onPaste = ev => {
2730
ev.preventDefault()
28-
const text = ev.clipboardData.getData('text')
29-
document.execCommand('insertText', false, text)
31+
const value = ev.clipboardData.getData('text')
32+
document.execCommand('insertText', false, value)
3033
}
3134

3235
getClassName = () => {
33-
const placeholder = this.state.text === '' ? 'comPlainTextContentEditable--has-placeholder' : ''
36+
const placeholder = this.state.value === '' ? 'comPlainTextContentEditable--has-placeholder' : ''
3437
return `comPlainTextContentEditable ${placeholder}`
3538
}
3639

40+
onKeyDown = (e) => {
41+
if(e.keyCode === 13) {
42+
this.props.onChange(this.state.value)
43+
this.refDiv.blur()
44+
e.preventDefault()
45+
}
46+
if(e.keyCode === 27) {
47+
this.refDiv.value = this.props.value
48+
this.setState({value: this.props.value})
49+
// this.refDiv.blur()
50+
e.preventDefault()
51+
e.stopPropagation()
52+
}
53+
}
54+
3755
render() {
3856
return (
3957
<div
@@ -43,21 +61,26 @@ class EditableLabel extends React.Component {
4361
onPaste={this.onPaste}
4462
onBlur={this.onBlur}
4563
onInput={this.onTextChange}
46-
placeholder={this.props.placeholder}
47-
/>
64+
onKeyDown={this.onKeyDown}
65+
placeholder={this.props.value.length == 0 ? false : this.props.placeholder}
66+
>{this.props.value}</div>
4867
)
4968
}
5069
}
5170

52-
EditableLabel.defaultProps = {
53-
onChange: () => {},
54-
placeholder: '',
55-
autoFocus: false
56-
}
5771
EditableLabel.propTypes = {
5872
onChange: PropTypes.func,
5973
placeholder: PropTypes.string,
60-
autoFocus: PropTypes.bool
74+
autoFocus: PropTypes.bool,
75+
inline: PropTypes.bool,
76+
value: PropTypes.string,
6177
}
6278

79+
EditableLabel.defaultProps = {
80+
onChange: () => {},
81+
placeholder: '',
82+
autoFocus: false,
83+
inline: false,
84+
value: ''
85+
}
6386
export default EditableLabel
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
import {InlineInput} from 'styles/Base'
4+
import autosize from 'autosize'
5+
6+
class InlineInputController extends React.Component {
7+
onFocus = (e) => e.target.select()
8+
9+
// This is the way to select all text if mouse clicked
10+
onMouseDown = (e) => {
11+
if (document.activeElement != e.target) {
12+
e.preventDefault()
13+
this.refInput.focus()
14+
}
15+
}
16+
17+
onBlur = () => {
18+
this.updateValue()
19+
}
20+
21+
onKeyDown = (e) => {
22+
if(e.keyCode == 13) {
23+
this.refInput.blur()
24+
e.preventDefault()
25+
}
26+
if(e.keyCode == 27) {
27+
this.setValue(this.props.value)
28+
this.refInput.blur()
29+
e.preventDefault()
30+
}
31+
if(e.keyCode == 9) {
32+
if (this.getValue().length == 0) {
33+
this.props.onCancel()
34+
}
35+
this.refInput.blur()
36+
e.preventDefault()
37+
}
38+
}
39+
40+
getValue = () => this.refInput.value
41+
setValue = (value) => this.refInput.value=value
42+
43+
updateValue = () => {
44+
if (this.getValue() != this.props.value) {
45+
this.props.onSave(this.getValue())
46+
}
47+
}
48+
49+
setRef = (ref) => {
50+
this.refInput = ref
51+
if (this.props.resize != 'none') {
52+
autosize(this.refInput)
53+
}
54+
}
55+
56+
componentWillReceiveProps(nextProps) {
57+
this.setValue(nextProps.value)
58+
}
59+
60+
render() {
61+
const {autoFocus, border, value, placeholder} = this.props
62+
63+
return <InlineInput
64+
ref={this.setRef}
65+
border={border}
66+
onMouseDown={this.onMouseDown}
67+
onFocus={this.onFocus}
68+
onBlur={this.onBlur}
69+
onKeyDown={this.onKeyDown}
70+
placeholder={value.length == 0 ? undefined : placeholder}
71+
defaultValue={value}
72+
autoComplete="off"
73+
autoCorrect="off"
74+
autoCapitalize="off"
75+
spellCheck="false"
76+
dataGramm="false"
77+
rows={1}
78+
autoFocus={autoFocus}
79+
/>
80+
}
81+
}
82+
83+
InlineInputController.propTypes = {
84+
onSave: PropTypes.func,
85+
border: PropTypes.bool,
86+
placeholder: PropTypes.string,
87+
value: PropTypes.string,
88+
autoFocus: PropTypes.bool,
89+
resize: PropTypes.oneOf(['none', 'vertical', 'horizontal']),
90+
}
91+
92+
InlineInputController.defaultProps = {
93+
onSave: () => {},
94+
placeholder: '',
95+
value: '',
96+
border: false,
97+
autoFocus: false,
98+
resize: 'none'
99+
}
100+
101+
export default InlineInputController

src/controllers/BoardContainer.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ class BoardContainer extends Component {
7676
})
7777
case 'UPDATE_LANES':
7878
return actions.updateLanes(event.lanes)
79+
case 'UPDATE_LANE':
80+
return actions.updateLane(event.lane)
7981
}
8082
}
8183
}
@@ -119,9 +121,11 @@ class BoardContainer extends Component {
119121
onLaneClick,
120122
onLaneAdd,
121123
onLaneDelete,
124+
onLaneUpdate,
122125
editable,
123126
canAddLanes,
124127
laneStyle,
128+
onCardMoveAcrossLanes,
125129
t,
126130
...otherProps
127131
} = this.props
@@ -132,6 +136,7 @@ class BoardContainer extends Component {
132136
'onCardMoveAcrossLanes',
133137
'onLaneScroll',
134138
'onLaneDelete',
139+
'onLaneUpdate',
135140
'onCardClick',
136141
'onCardDelete',
137142
'onCardAdd',
@@ -146,6 +151,7 @@ class BoardContainer extends Component {
146151
'handleDragStart',
147152
'handleDragEnd',
148153
'cardDragClass',
154+
'editLaneTitle',
149155
't'
150156
])
151157

@@ -211,6 +217,7 @@ BoardContainer.propTypes = {
211217
onLaneAdd: PropTypes.func,
212218
onLaneDelete: PropTypes.func,
213219
onLaneClick: PropTypes.func,
220+
onLaneUpdate: PropTypes.func,
214221
laneSortFunction: PropTypes.func,
215222
draggable: PropTypes.bool,
216223
collapsibleLanes: PropTypes.bool,
@@ -241,6 +248,7 @@ BoardContainer.defaultProps = {
241248
onLaneAdd: () => {},
242249
onLaneDelete: () => {},
243250
onCardMoveAcrossLanes: () => {},
251+
onLaneUpdate: () => {},
244252
editable: false,
245253
canAddLanes: false,
246254
hideCardDeleteIcon: false,

0 commit comments

Comments
 (0)