-
Notifications
You must be signed in to change notification settings - Fork 843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uses new WindowEvent component for Flyout "close on ESC" #1127
Changes from 5 commits
55535bb
48608b7
dbe6c71
6acd453
300fcb3
b703e5f
a348dbb
73f0ed0
e4d90d9
f8b6f3e
870a759
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import React, { Component } from 'react'; | ||
|
||
import { | ||
EuiWindowEvent, | ||
EuiIcon, | ||
EuiButton, | ||
EuiSpacer, | ||
} from '../../../../src/components'; | ||
|
||
export class WindowEvent extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
stars: [] | ||
}; | ||
this.add = this.add.bind(this); | ||
this.remove = this.remove.bind(this); | ||
} | ||
|
||
add() { | ||
this.setState((state) => ({ stars: [...state.stars, <EuiIcon type="starEmpty" />] })); | ||
} | ||
|
||
remove({ key }) { | ||
if (key === 'Backspace' || key === 'Delete') { | ||
this.setState((state) => ({ stars: state.stars.slice(0, -1) })); | ||
return; | ||
} | ||
} | ||
|
||
render() { | ||
const { stars } = this.state; | ||
return ( | ||
<div> | ||
<EuiWindowEvent event="keydown" handler={this.remove} /> | ||
<EuiButton onClick={this.add}>Add a Star</EuiButton> | ||
|
||
<EuiSpacer size="m" /> | ||
|
||
<p>To remove a star, press the backspace or delete key.</p> | ||
|
||
<EuiSpacer size="m" /> | ||
|
||
<div className="stars-container"> | ||
{stars.map((star, i) => <span key={i} style={{ marginRight: '5px' }}>{star}</span>)} | ||
</div> | ||
</div> | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react'; | ||
|
||
import { renderToHtml } from '../../services'; | ||
|
||
import { | ||
GuideSectionTypes, | ||
} from '../../components'; | ||
|
||
import { | ||
EuiCode, | ||
EuiWindowEvent, | ||
} from '../../../../src/components'; | ||
|
||
import { WindowEvent } from './window_event'; | ||
const source = require('!!raw-loader!./window_event'); | ||
const html = renderToHtml(WindowEvent); | ||
|
||
export const WindowEventExample = { | ||
title: 'Window Event', | ||
sections: [{ | ||
title: 'Window Event', | ||
source: [{ | ||
type: GuideSectionTypes.JS, | ||
code: source, | ||
}, { | ||
type: GuideSectionTypes.HTML, | ||
code: html, | ||
}], | ||
text: ( | ||
<p> | ||
Use an <EuiCode>EuiWindowEvent</EuiCode> to safely manage adding and auto-removing event listeners to <EuiCode>window</EuiCode>. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also describe how? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed: e4d90d9 |
||
</p> | ||
), | ||
components: { EuiWindowEvent }, | ||
demo: <WindowEvent />, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also add a props key here to populate a props tab with the props listed in a table like so: |
||
}], | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default as EuiWindowEvent } from './window_event'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you need the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is how you "proxy export" a default component from another file, I think. Or I could make the export in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think we just name everything so we ensure there are no conflicts or that we can add to them down the line without breaking changes. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { Component } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
/** | ||
* Adds and removes window events for you (renders null) | ||
* Usage: | ||
* <WindowEvent event='keydown' handler={this.handleKeyDown} /> | ||
*/ | ||
export default class WindowEvent extends Component { | ||
|
||
componentDidMount() { | ||
this.addEvent(this.props); | ||
} | ||
|
||
componentDidUpdate(prevProps) { | ||
if (prevProps.event !== this.props.event || prevProps.handler !== this.props.handler) { | ||
this.removeEvent(prevProps); | ||
this.addEvent(this.props); | ||
} | ||
} | ||
|
||
componentWillUnmount() { | ||
this.removeEvent(this.props); | ||
} | ||
|
||
addEvent({ event, handler }) { | ||
window.addEventListener(event, handler); | ||
} | ||
|
||
removeEvent({ event, handler }) { | ||
window.removeEventListener(event, handler); | ||
} | ||
|
||
render() { | ||
return null; | ||
} | ||
|
||
} | ||
|
||
WindowEvent.displayName = 'WindowEvent'; | ||
|
||
WindowEvent.propTypes = { | ||
/** | ||
* Type of event | ||
*/ | ||
event: PropTypes.string.isRequired, | ||
/** | ||
* Event callback function | ||
*/ | ||
handler: PropTypes.func.isRequired | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import React from 'react'; | ||
import { shallow } from 'enzyme'; | ||
import { EuiWindowEvent } from '.'; | ||
|
||
describe('EuiWindowEvent', () => { | ||
|
||
beforeEach(() => { | ||
window.addEventListener = jest.fn(); | ||
window.removeEventListener = jest.fn(); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
test('attaches handler to window event on mount', () => { | ||
const handler = () => null; | ||
shallow(<EuiWindowEvent event="click" handler={handler} />); | ||
expect(window.addEventListener).toHaveBeenCalledTimes(1); | ||
expect(window.addEventListener).toHaveBeenCalledWith('click', handler); | ||
}); | ||
|
||
test('removes handler on unmount', () => { | ||
const handler = () => null; | ||
const wrapper = shallow(<EuiWindowEvent event="click" handler={handler} />); | ||
wrapper.unmount(); | ||
expect(window.removeEventListener).toHaveBeenLastCalledWith('click', handler); | ||
}); | ||
|
||
test('removes and re-attaches handler to window event on update', () => { | ||
const handler1 = () => null; | ||
const handler2 = () => null; | ||
const wrapper = shallow(<EuiWindowEvent event="click" handler={handler1} />); | ||
|
||
expect(window.addEventListener).toHaveBeenLastCalledWith('click', handler1); | ||
|
||
wrapper.setProps({ event: 'hover', handler: handler2 }); | ||
|
||
expect(window.removeEventListener).toHaveBeenLastCalledWith('click', handler1); | ||
expect(window.addEventListener).toHaveBeenLastCalledWith('hover', handler2); | ||
}); | ||
|
||
test('does not remove or re-attach handler if update is irrelevant', () => { | ||
const handler = () => null; | ||
const wrapper = shallow(<EuiWindowEvent event="click" handler={handler} />); | ||
expect(window.addEventListener).toHaveBeenCalledTimes(1); | ||
|
||
wrapper.setProps({ whatever: 'ugh' }); | ||
expect(window.addEventListener).toHaveBeenCalledTimes(1); | ||
expect(window.removeEventListener).not.toHaveBeenCalled(); | ||
}); | ||
|
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a copied heading, you can just append your bullets after the
EuiSuperSelect
one.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed here: 73f0ed0