mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-20 22:23:53 +08:00
update(components): Add support to create new items inside EditableList
- Adds logic to allow simple item creation - Adds new onItemCreated callback - Updates specs
This commit is contained in:
parent
68a0a81f77
commit
31796e396d
3 changed files with 87 additions and 8 deletions
|
@ -38,6 +38,37 @@ describe('EditableList', ()=> {
|
|||
});
|
||||
});
|
||||
|
||||
describe('_onCreateInputKeyDown', ()=> {
|
||||
it('calls onItemCreated', ()=> {
|
||||
const onItemCreated = jasmine.createSpy('onItemCreated');
|
||||
const list = makeList(['1', '2'], {initialState: {creatingItem: true}, onItemCreated});
|
||||
const createItem = findRenderedDOMComponentWithClass(list, 'create-item');
|
||||
const input = findRenderedDOMComponentWithTag(createItem, 'input');
|
||||
findDOMNode(input).value = 'New Item';
|
||||
|
||||
Simulate.keyDown(input, {key: 'Enter'});
|
||||
|
||||
expect(onItemCreated).toHaveBeenCalledWith('New Item');
|
||||
});
|
||||
});
|
||||
|
||||
describe('_onCreateItem', ()=> {
|
||||
it('should call prop callback when provided', ()=> {
|
||||
const onCreateItem = jasmine.createSpy('onCreateItem');
|
||||
const list = makeList(['1', '2'], {onCreateItem});
|
||||
|
||||
list._onCreateItem();
|
||||
expect(onCreateItem).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set state for creating item when no callback provided', ()=> {
|
||||
const list = makeList(['1', '2']);
|
||||
spyOn(list, 'setState');
|
||||
list._onCreateItem();
|
||||
expect(list.setState).toHaveBeenCalledWith({creatingItem: true});
|
||||
});
|
||||
});
|
||||
|
||||
describe('_renderItem', ()=> {
|
||||
const makeItem = (item, idx, state = {}, handlers = {})=> {
|
||||
const list = makeList();
|
||||
|
@ -109,18 +140,26 @@ describe('EditableList', ()=> {
|
|||
const innerList = findDOMNode(
|
||||
findRenderedDOMComponentWithClass(list, 'items-wrapper')
|
||||
);
|
||||
expect(()=> {
|
||||
findRenderedDOMComponentWithClass(list, 'create-item');
|
||||
}).toThrow();
|
||||
|
||||
expect(innerList.childNodes.length).toEqual(3);
|
||||
items.forEach((item, idx)=> expect(innerList.childNodes[idx].textContent).toEqual(item));
|
||||
});
|
||||
|
||||
it('renders create input as an item when creating', ()=> {
|
||||
const items = ['1', '2', '3'];
|
||||
const list = makeList(items, {initialState: {creatingItem: true}});
|
||||
const createItem = findRenderedDOMComponentWithClass(list, 'create-item');
|
||||
expect(createItem).toBeDefined();
|
||||
});
|
||||
|
||||
it('renders add button', ()=> {
|
||||
const onCreateItem = jasmine.createSpy('onCreateItem');
|
||||
const list = makeList([], {onCreateItem});
|
||||
const list = makeList();
|
||||
const button = scryRenderedDOMComponentsWithClass(list, 'btn-editable-list')[0];
|
||||
|
||||
Simulate.click(button);
|
||||
|
||||
expect(onCreateItem).toHaveBeenCalled();
|
||||
expect(findDOMNode(button).textContent).toEqual('+');
|
||||
});
|
||||
|
||||
it('renders delete button', ()=> {
|
||||
|
@ -130,6 +169,7 @@ describe('EditableList', ()=> {
|
|||
|
||||
Simulate.click(button);
|
||||
|
||||
expect(findDOMNode(button).textContent).toEqual('—');
|
||||
expect(onDeleteItem).toHaveBeenCalledWith('2', 1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,15 +16,16 @@ class EditableList extends Component {
|
|||
onDeleteItem: PropTypes.func,
|
||||
onItemEdited: PropTypes.func,
|
||||
onItemSelected: PropTypes.func,
|
||||
onItemCreated: PropTypes.func,
|
||||
initialState: PropTypes.object,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
children: [],
|
||||
onCreateItem: ()=> {},
|
||||
onDeleteItem: ()=> {},
|
||||
onItemEdited: ()=> {},
|
||||
onItemSelected: ()=> {},
|
||||
onItemCreated: ()=> {},
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -34,6 +35,7 @@ class EditableList extends Component {
|
|||
this.state = props.initialState || {
|
||||
editing: null,
|
||||
selected: null,
|
||||
creatingItem: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -54,6 +56,13 @@ class EditableList extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onCreateInputKeyDown = (event)=> {
|
||||
if (_.includes(['Enter', 'Return'], event.key)) {
|
||||
this.setState({creatingItem: false});
|
||||
this.props.onItemCreated(event.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
_onItemClick = (event, item, idx)=> {
|
||||
this._selectItem(item, idx);
|
||||
}
|
||||
|
@ -83,7 +92,11 @@ class EditableList extends Component {
|
|||
}
|
||||
|
||||
_onCreateItem = ()=> {
|
||||
this.props.onCreateItem();
|
||||
if (this.props.onCreateItem) {
|
||||
this.props.onCreateItem();
|
||||
} else {
|
||||
this.setState({creatingItem: true});
|
||||
}
|
||||
}
|
||||
|
||||
_onDeleteItem = ()=> {
|
||||
|
@ -137,7 +150,23 @@ class EditableList extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
_renderCreateItem = (onCreateInputKeyDown = this._onCreateInputKeyDown)=> {
|
||||
return (
|
||||
<div className="create-item">
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
onKeyDown={onCreateInputKeyDown} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let items = this._items.map((item, idx)=> this._renderItem(item, idx));
|
||||
if (this.state.creatingItem === true) {
|
||||
items = items.concat(this._renderCreateItem());
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`nylas-editable-list ${this.props.className}`}>
|
||||
<div
|
||||
|
@ -145,7 +174,7 @@ class EditableList extends Component {
|
|||
tabIndex="1"
|
||||
onBlur={this._onListBlur}
|
||||
onKeyDown={this._onListKeyDown}>
|
||||
{this._items.map((item, idx)=> this._renderItem(item, idx))}
|
||||
{items}
|
||||
</div>
|
||||
<div className="buttons-wrapper">
|
||||
<button className="btn btn-small btn-editable-list" onClick={this._onCreateItem}>+</button>
|
||||
|
|
|
@ -31,6 +31,16 @@
|
|||
color: @text-color-inverse-very-subtle;
|
||||
}
|
||||
}
|
||||
|
||||
.create-item {
|
||||
padding: @padding-small-vertical @padding-small-horizontal;
|
||||
border-top: 1px solid @border-color-divider;
|
||||
input {
|
||||
border: none;
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.buttons-wrapper {
|
||||
|
|
Loading…
Reference in a new issue