diff --git a/docs/src/routes/Components/ContentDialog/SimpleExample.tsx b/docs/src/routes/Components/ContentDialog/SimpleExample.tsx index 67ed8a3c..0481acdb 100644 --- a/docs/src/routes/Components/ContentDialog/SimpleExample.tsx +++ b/docs/src/routes/Components/ContentDialog/SimpleExample.tsx @@ -78,6 +78,9 @@ export default class SimpleExample extends React.Component<{}, SimpleExampleStat primaryButtonAction={this.toggleShowStatusBarDialog} secondaryButtonAction={this.toggleShowStatusBarDialog} closeButtonAction={this.toggleShowStatusBarDialog} + onCloseDialog={() => { + this.setState({ showStatusBarDialog: false }); + }} />
@@ -93,6 +96,9 @@ export default class SimpleExample extends React.Component<{}, SimpleExampleStat primaryButtonAction={this.toggleShowDialog} secondaryButtonAction={this.toggleShowDialog} closeButtonAction={this.toggleShowDialog} + onCloseDialog={() => { + this.setState({ showDialog: false }); + }} />
diff --git a/src/AutoSuggestBox/index.tsx b/src/AutoSuggestBox/index.tsx index 1c862423..8a2c4c64 100644 --- a/src/AutoSuggestBox/index.tsx +++ b/src/AutoSuggestBox/index.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; import Icon from "../Icon"; import TextBox from "../TextBox"; diff --git a/src/Button/index.doc.json b/src/Button/index.doc.json index 1c89f375..989dfb15 100644 --- a/src/Button/index.doc.json +++ b/src/Button/index.doc.json @@ -109,7 +109,7 @@ }, { "name": "defaultProps", - "initializerText": " {\n borderSize: \"2px\",\n children: \"Button\",\n iconPosition: \"left\"\n }", + "initializerText": " {\r\n borderSize: \"2px\",\r\n children: \"Button\",\r\n iconPosition: \"left\"\r\n }", "documentation": "", "type": "ButtonProps" }, diff --git a/src/CalendarDatePicker/index.tsx b/src/CalendarDatePicker/index.tsx index de57f7c9..1c779a51 100644 --- a/src/CalendarDatePicker/index.tsx +++ b/src/CalendarDatePicker/index.tsx @@ -1,6 +1,8 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; +import AddBlurEvent from "../common/AddBlurEvent"; import Icon from "../Icon"; import TextBox from "../TextBox"; import CalendarView from "../CalendarView"; @@ -53,9 +55,37 @@ export class CalendarDatePicker extends React.Component { + this.addBlurEvent.setConfig({ + addListener: this.state.showCalendarView, + clickExcludeElm: this.rootElm, + blurCallback: () => { + this.setState({ + showCalendarView: false + }); + }, + blurKeyCodes: [codes.esc] + }); + } + + componentDidMount() { + this.addBlurEventMethod(); + } + + componentDidUpdate() { + this.addBlurEventMethod(); + } + + componentWillUnmount() { + this.addBlurEvent.cleanEvent(); + } toggleShowCalendarView = (showCalendarView?: any) => { if (!this.textBox.rootElm.contains(showCalendarView.target)) return; @@ -101,6 +131,7 @@ export class CalendarDatePicker extends React.Component this.rootElm = rootElm} > { + this.addBlurEvent.setConfig({ + addListener: this.state.currExpanded, + clickExcludeElm: this.rootElm, + blurCallback: () => { + this.setState({ + currExpanded: false + }); + }, + blurKeyCodes: [codes.esc] + }); + } + + componentDidMount() { + this.addBlurEventMethod(); + } + + componentDidUpdate() { + this.addBlurEventMethod(); + } + + componentWillUnmount() { + this.addBlurEvent.cleanEvent(); + } + toggleExpanded = (currExpanded?: any) => { if (typeof currExpanded === "boolean") { if (currExpanded !== this.state.currExpanded) this.setState({ currExpanded }); @@ -108,7 +137,7 @@ export class CommandBar extends React.Component +
this.rootElm = rootElm}>
{(content !== void 0 || contentNode !== void 0) && (
{content || contentNode}
diff --git a/src/ContentDialog/index.doc.json b/src/ContentDialog/index.doc.json index eb0a848c..21e7a675 100644 --- a/src/ContentDialog/index.doc.json +++ b/src/ContentDialog/index.doc.json @@ -10,6 +10,10 @@ "name": "ContentDialogProps", "documentation": "" }, + { + "name": "ContentDialogState", + "documentation": "" + }, { "name": "ContentDialog", "documentation": "" @@ -91,6 +95,18 @@ "documentation": "secondaryButton `click callback`.", "isRequired": false, "type": "(e: MouseEvent) => void" + }, + { + "name": "onCloseDialog", + "documentation": "callback run end close dialog.", + "isRequired": false, + "type": "() => void" + }, + { + "name": "background", + "documentation": "Set custom background.", + "isRequired": false, + "type": "string" } ], "documentation": "" @@ -103,6 +119,18 @@ "HTMLAttributes" ] }, + { + "name": "ContentDialogState", + "members": [ + { + "name": "showDialog", + "documentation": "", + "isRequired": false, + "type": "boolean" + } + ], + "documentation": "" + }, { "documentation": "", "name": "emptyFunc", @@ -124,7 +152,7 @@ }, { "name": "defaultProps", - "initializerText": " {\n primaryButtonText: \"Delete\",\n secondaryButtonText: \"Cancel\",\n closeButtonAction: emptyFunc,\n primaryButtonAction: emptyFunc,\n secondaryButtonAction: emptyFunc\n }", + "initializerText": " {\n primaryButtonText: \"Delete\",\n secondaryButtonText: \"Cancel\",\n closeButtonAction: emptyFunc,\n primaryButtonAction: emptyFunc,\n secondaryButtonAction: emptyFunc,\n onCloseDialog: emptyFunc\n }", "documentation": "", "type": "ContentDialogProps" }, @@ -137,15 +165,47 @@ ], "members": [ { - "name": "refs", + "name": "state", + "initializerText": " {\n showDialog: this.props.defaultShow\n }", "documentation": "", - "type": "{ renderToBody: any; }" + "type": "ContentDialogState" + }, + { + "name": "addBlurEvent", + "initializerText": " new AddBlurEvent()", + "documentation": "", + "type": "AddBlurEvent" }, { "name": "context", "documentation": "", "type": "{ theme: any; }" }, + { + "name": "renderToBody", + "documentation": "", + "type": "any" + }, + { + "name": "rootElm", + "documentation": "", + "type": "HTMLDivElement" + }, + { + "name": "shouldComponentUpdate", + "documentation": "", + "type": "(nextProps: ContentDialogProps, nextState: ContentDialogState) => boolean" + }, + { + "name": "componentDidUpdate", + "documentation": "", + "type": "() => void" + }, + { + "name": "componentWillUnmount", + "documentation": "", + "type": "() => void" + }, { "name": "containerMouseEnterHandle", "initializerText": " (e: React.MouseEvent) => {\n e.currentTarget.style.border = `1px solid ${this.context.theme.accent}`;\n }", @@ -158,6 +218,12 @@ "documentation": "", "type": "(e: MouseEvent) => void" }, + { + "name": "closeDialog", + "initializerText": " () => {\n this.setState({ showDialog: false });\n this.props.onCloseDialog();\n }", + "documentation": "", + "type": "() => void" + }, { "name": "render", "documentation": "", diff --git a/src/ContentDialog/index.tsx b/src/ContentDialog/index.tsx index 9aab3170..43a8770d 100644 --- a/src/ContentDialog/index.tsx +++ b/src/ContentDialog/index.tsx @@ -1,6 +1,9 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; +import AddBlurEvent from "../common/AddBlurEvent"; +import shallowEqual from "../common/shallowEqual"; import Button from "../Button"; import IconButton from "../IconButton"; import RenderToBody from "../RenderToBody"; @@ -50,6 +53,10 @@ export interface DataProps { * secondaryButton `click callback`. */ secondaryButtonAction?: (e: React.MouseEvent) => void; + /** + * callback run end close dialog. + */ + onCloseDialog?: () => void; /** * Set custom background. */ @@ -57,21 +64,64 @@ export interface DataProps { } export interface ContentDialogProps extends DataProps, React.HTMLAttributes {} +export interface ContentDialogState { + showDialog?: boolean; +} const emptyFunc = () => {}; - -export class ContentDialog extends React.Component { +export class ContentDialog extends React.Component { static defaultProps: ContentDialogProps = { primaryButtonText: "Delete", secondaryButtonText: "Cancel", closeButtonAction: emptyFunc, primaryButtonAction: emptyFunc, - secondaryButtonAction: emptyFunc + secondaryButtonAction: emptyFunc, + onCloseDialog: emptyFunc + }; + + state: ContentDialogState = { + showDialog: this.props.defaultShow }; - refs: { renderToBody: RenderToBody }; + addBlurEvent = new AddBlurEvent(); static contextTypes = { theme: PropTypes.object }; context: { theme: ReactUWP.ThemeType }; + renderToBody: RenderToBody; + rootElm: HTMLDivElement; + + shouldComponentUpdate(nextProps: ContentDialogProps, nextState: ContentDialogState) { + const shouldUpdate = !shallowEqual(nextProps, this.props); + if (shouldUpdate) { + this.state.showDialog = nextProps.defaultShow; + } + return shouldUpdate; + } + + addBlurEventMethod = () => { + this.addBlurEvent.setConfig({ + addListener: this.state.showDialog, + clickExcludeElm: this.rootElm, + blurCallback: () => { + this.setState({ + showDialog: false + }); + this.props.onCloseDialog(); + }, + blurKeyCodes: [codes.esc] + }); + } + + componentDidMount() { + this.addBlurEventMethod(); + } + + componentDidUpdate() { + this.addBlurEventMethod(); + } + + componentWillUnmount() { + this.addBlurEvent.cleanEvent(); + } containerMouseEnterHandle = (e: React.MouseEvent) => { e.currentTarget.style.border = `1px solid ${this.context.theme.accent}`; @@ -81,6 +131,11 @@ export class ContentDialog extends React.Component { e.currentTarget.style.border = `1px solid ${this.context.theme.baseLow}`; } + closeDialog = () => { + this.setState({ showDialog: false }); + this.props.onCloseDialog(); + } + render() { const { statusBarTitle, @@ -94,6 +149,7 @@ export class ContentDialog extends React.Component { primaryButtonAction, secondaryButtonAction, closeButtonAction, + onCloseDialog, background, ...attributes } = this.props; @@ -101,12 +157,13 @@ export class ContentDialog extends React.Component { const styles = getStyles(this); return ( - + this.renderToBody = renderToBody}>
this.rootElm = rootElm} style={styles.container} onMouseEnter={this.containerMouseEnterHandle} onMouseLeave={this.containerMouseLeaveHandle} @@ -136,10 +193,16 @@ export class ContentDialog extends React.Component { {contentNode}
- -
@@ -161,7 +224,7 @@ function getStyles(contentDialog: ContentDialog): { buttonGroup?: React.CSSProperties; button?: React.CSSProperties; } { - const { context, props: { style, defaultShow, background } } = contentDialog; + const { context, props: { style, background }, state: { showDialog } } = contentDialog; const { theme } = context; const { prepareStyles } = theme; @@ -171,8 +234,8 @@ function getStyles(contentDialog: ContentDialog): { margin: 0, padding: 0, zIndex: 2000, - opacity: defaultShow ? 1 : 0, - pointerEvents: defaultShow ? "all" : "none", + opacity: showDialog ? 1 : 0, + pointerEvents: showDialog ? "all" : "none", position: "fixed", top: 0, left: 0, @@ -185,7 +248,7 @@ function getStyles(contentDialog: ContentDialog): { justifyContent: "center", color: theme.baseHigh, background: theme.altMediumHigh, - transition: `all .25s ${defaultShow ? 0 : 0.25}s ease-in-out`, + transition: `all .25s ${showDialog ? 0 : 0.25}s ease-in-out`, ...style }), container: prepareStyles({ @@ -195,9 +258,9 @@ function getStyles(contentDialog: ContentDialog): { width: "80%", maxWidth: 720, cursor: "default", - transform: `scale(${defaultShow ? 1 : 0})`, - opacity: defaultShow ? 1 : 0, - transition: `all .25s ${defaultShow ? 0.25 : 0}s ease-in-out` + transform: `scale(${showDialog ? 1 : 0})`, + opacity: showDialog ? 1 : 0, + transition: `all .25s ${showDialog ? 0.25 : 0}s ease-in-out` }), statusBarTitle: prepareStyles({ color: "#fff", diff --git a/src/DatePicker/index.tsx b/src/DatePicker/index.tsx index bb93a47e..fd3269c2 100644 --- a/src/DatePicker/index.tsx +++ b/src/DatePicker/index.tsx @@ -1,6 +1,8 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; +import AddBlurEvent from "../common/AddBlurEvent"; import Separator from "../Separator"; import IconButton from "../IconButton"; import ElementState from "../ElementState"; @@ -62,10 +64,10 @@ export class DatePicker extends React.Component { const { pickerItemHeight } = this.props; scrollToYEasing(this.monthListView.rootElm, this.monthIndex * pickerItemHeight, 0.1); scrollToYEasing(this.dateListView.rootElm, this.dateIndex * pickerItemHeight, 0.1); scrollToYEasing(this.yearListView.rootElm, this.yearIndex * pickerItemHeight, 0.1); + + this.addBlurEvent.setConfig({ + addListener: this.state.showPicker, + clickExcludeElm: this.elementState.rootElm, + blurCallback: () => { + this.setState({ + showPicker: false + }); + }, + blurKeyCodes: [codes.esc] + }); + } + + componentDidMount() { + this.addBlurEventMethod(); + } + + componentDidUpdate() { + this.addBlurEventMethod(); + } + + componentWillUnmount() { + this.addBlurEvent.cleanEvent(); } toggleShowPicker = (showPicker?: any) => { @@ -153,6 +181,7 @@ export class DatePicker extends React.Component this.elementState = elementState} >
diff --git a/src/DropDownMenu/index.tsx b/src/DropDownMenu/index.tsx index 76e232d6..f4d9436c 100644 --- a/src/DropDownMenu/index.tsx +++ b/src/DropDownMenu/index.tsx @@ -2,8 +2,8 @@ import * as React from "react"; import * as PropTypes from "prop-types"; import { codes } from "keycode"; -import Icon from "../Icon"; import AddBlurEvent from "../common/AddBlurEvent"; +import Icon from "../Icon"; export interface DataProps { /** @@ -52,8 +52,6 @@ export interface DropDownMenuState { currentValues?: string[]; } -const addBlurEvent = new AddBlurEvent(); - const emptyFunc = () => {}; export class DropDownMenu extends React.Component { static defaultProps: DropDownMenuProps = { @@ -82,6 +80,7 @@ export class DropDownMenu extends React.Component { + this.addBlurEvent.setConfig({ addListener: this.state.showList, clickExcludeElm: this.rootElm, blurCallback: () => { @@ -118,8 +117,16 @@ export class DropDownMenu extends React.Component) => { diff --git a/src/Menu/MenuItem.tsx b/src/Menu/MenuItem.tsx index 443ea1fa..23149b8e 100644 --- a/src/Menu/MenuItem.tsx +++ b/src/Menu/MenuItem.tsx @@ -1,6 +1,8 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; +import AddBlurEvent from "../common/AddBlurEvent"; import Icon from "../Icon"; import ElementState from "../ElementState"; @@ -55,6 +57,9 @@ export class MenuItem extends React.Component { expanded: this.props.defaultExpanded }; + addBlurEvent = new AddBlurEvent(); + elementState: ElementState; + static contextTypes = { theme: PropTypes.object }; context: { theme: ReactUWP.ThemeType }; @@ -66,6 +71,31 @@ export class MenuItem extends React.Component { } } + addBlurEventMethod = () => { + this.addBlurEvent.setConfig({ + addListener: this.state.expanded, + clickExcludeElm: this.elementState.rootElm, + blurCallback: () => { + this.setState({ + expanded: false + }); + }, + blurKeyCodes: [codes.esc] + }); + } + + componentDidMount() { + this.addBlurEventMethod(); + } + + componentDidUpdate() { + this.addBlurEventMethod(); + } + + componentWillUnmount() { + this.addBlurEvent.cleanEvent(); + } + toggleExpanded = (expanded?: any) => { if (typeof expanded === "boolean") { if (expanded !== this.state.expanded) { @@ -105,6 +135,7 @@ export class MenuItem extends React.Component { hoverStyle={hoverStyle || { background: theme.listLow }} + ref={(elementState) => this.elementState = elementState} >
diff --git a/src/NavigationView/index.tsx b/src/NavigationView/index.tsx index 6bd40ce9..a8a43ef5 100644 --- a/src/NavigationView/index.tsx +++ b/src/NavigationView/index.tsx @@ -1,8 +1,9 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; +import AddBlurEvent from "../common/AddBlurEvent"; import shallowEqual from "../common/shallowEqual"; - import SlideInOut from "../Animate/SlideInOut"; import IconButton from "../IconButton"; import SplitViewCommand from "../SplitViewCommand"; @@ -96,18 +97,39 @@ export class NavigationView extends React.Component { + this.addBlurEvent.setConfig({ + addListener: this.state.expanded, + clickExcludeElm: this.paneElm, + blurCallback: () => { + this.setState({ + expanded: false + }); + }, + blurKeyCodes: [codes.esc] + }); + } + componentDidMount() { if (this.props.autoResize) { this.autoResize(); window.addEventListener("resize", this.autoResize); } + this.addBlurEventMethod(); } - componentWillMount() { - this.updateProps2State(this.props); + componentDidUpdate() { + this.addBlurEventMethod(); } shouldComponentUpdate(nextProps: NavigationViewProps, nextState: NavigationViewState, nextContext: { theme: ReactUWP.ThemeType }) { @@ -118,6 +140,7 @@ export class NavigationView extends React.Component { @@ -201,7 +224,7 @@ export class NavigationView extends React.Component -
+
this.paneElm = paneElm}>
diff --git a/src/PopupMenu/index.tsx b/src/PopupMenu/index.tsx deleted file mode 100644 index cb6f4103..00000000 --- a/src/PopupMenu/index.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import * as React from "react"; -import * as PropTypes from "prop-types"; - -export interface DataProps {} - -export interface PopupMenuProps extends DataProps, React.HTMLAttributes {} - -export default class PopupMenu extends React.Component { - static defaultProps: PopupMenuProps = { - }; - - static contextTypes = { theme: PropTypes.object }; - context: { theme: ReactUWP.ThemeType }; - - render() { - const { ...attributes } = this.props; - const { theme } = this.context; - const styles = getStyles(this); - - return ( -
- PopupMenu -
- ); - } -} - -function getStyles(popupMenu: PopupMenu): { - root?: React.CSSProperties; -} { - const { - context: { theme }, - props: { style } - } = popupMenu; - const { prepareStyles } = theme; - - return { - root: prepareStyles({ - fontSize: 14, - color: theme.baseMediumHigh, - background: theme.altMediumHigh, - ...style - }) - }; -} diff --git a/src/SplitView/SplitViewPane.tsx b/src/SplitView/SplitViewPane.tsx index c868855f..7d0f3ed3 100644 --- a/src/SplitView/SplitViewPane.tsx +++ b/src/SplitView/SplitViewPane.tsx @@ -8,6 +8,7 @@ export interface SplitViewPaneProps extends DataProps, React.HTMLAttributes { static contextTypes = { theme: PropTypes.object }; context: { theme: ReactUWP.ThemeType }; + rootElm: HTMLDivElement; render() { const { children, style, ...attributes } = this.props; @@ -17,6 +18,7 @@ export class SplitViewPane extends React.Component {
this.rootElm = rootElm} > {children}
diff --git a/src/SplitView/index.doc.json b/src/SplitView/index.doc.json index 3674a88d..bb431f21 100644 --- a/src/SplitView/index.doc.json +++ b/src/SplitView/index.doc.json @@ -18,6 +18,10 @@ "name": "SplitViewProps", "documentation": "" }, + { + "name": "SplitViewState", + "documentation": "" + }, { "name": "SplitView", "documentation": "" @@ -63,6 +67,12 @@ "documentation": "", "isRequired": false, "type": "CSSProperties" + }, + { + "name": "onClosePane", + "documentation": "", + "isRequired": false, + "type": "() => void" } ], "documentation": "" @@ -75,6 +85,29 @@ "HTMLAttributes" ] }, + { + "name": "SplitViewState", + "members": [ + { + "name": "expanded", + "documentation": "", + "isRequired": false, + "type": "boolean" + } + ], + "documentation": "" + }, + { + "documentation": "", + "name": "emptyFunc", + "type": "() => void", + "initializerText": " () => {}" + }, + { + "name": "emptyFunc", + "documentation": "", + "type": "() => void" + }, { "name": "SplitView", "exports": [ @@ -85,7 +118,7 @@ }, { "name": "defaultProps", - "initializerText": " {\n expandedWidth: 320,\n displayMode: \"compact\",\n panePosition: \"right\"\n }", + "initializerText": " {\n expandedWidth: 320,\n displayMode: \"compact\",\n panePosition: \"right\",\n onClosePane: emptyFunc\n }", "documentation": "", "type": "SplitViewProps" }, @@ -97,6 +130,49 @@ } ], "members": [ + { + "name": "state", + "initializerText": " {\n expanded: this.props.defaultExpanded\n }", + "documentation": "", + "type": "SplitViewState" + }, + { + "name": "addBlurEvent", + "initializerText": " new AddBlurEvent()", + "documentation": "", + "type": "AddBlurEvent" + }, + { + "name": "splitViewPaneElm", + "documentation": "", + "type": "HTMLDivElement" + }, + { + "name": "componentWillReceiveProps", + "documentation": "", + "type": "(nextProps: SplitViewProps) => void" + }, + { + "name": "addBlurEventMethod", + "initializerText": " () => {\n this.addBlurEvent.setConfig({\n addListener: this.state.expanded,\n clickExcludeElm: this.splitViewPaneElm,\n blurCallback: () => {\n this.setState({\n expanded: false\n }, this.props.onClosePane);\n },\n blurKeyCodes: [codes.esc]\n });\n }", + "documentation": "", + "type": "() => void" + }, + { + "name": "componentDidMount", + "documentation": "", + "type": "() => void" + }, + { + "name": "componentDidUpdate", + "documentation": "", + "type": "() => void" + }, + { + "name": "componentWillUnmount", + "documentation": "", + "type": "() => void" + }, { "name": "context", "documentation": "", diff --git a/src/SplitView/index.tsx b/src/SplitView/index.tsx index 052cc0de..a415a847 100644 --- a/src/SplitView/index.tsx +++ b/src/SplitView/index.tsx @@ -1,8 +1,9 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; +import AddBlurEvent from "../common/AddBlurEvent"; import SplitViewPane, { SplitViewPaneProps } from "./SplitViewPane"; - export { SplitViewPane, SplitViewPaneProps }; export interface DataProps { @@ -11,17 +12,62 @@ export interface DataProps { defaultExpanded?: boolean; panePosition?: "left" | "right"; paneStyle?: React.CSSProperties; + onClosePane?: () => void; } export interface SplitViewProps extends DataProps, React.HTMLAttributes {} +export interface SplitViewState { + expanded?: boolean; +} - -export class SplitView extends React.Component { +const emptyFunc = () => {}; +export class SplitView extends React.Component { static defaultProps: SplitViewProps = { expandedWidth: 320, displayMode: "compact", - panePosition: "right" + panePosition: "right", + onClosePane: emptyFunc }; + state: SplitViewState = { + expanded: this.props.defaultExpanded + }; + + addBlurEvent = new AddBlurEvent(); + splitViewPaneElm: HTMLDivElement; + + componentWillReceiveProps(nextProps: SplitViewProps) { + const { defaultExpanded } = nextProps; + if (defaultExpanded !== void 0 && defaultExpanded !== this.state.expanded) { + this.setState({ + expanded: defaultExpanded + }); + } + } + + addBlurEventMethod = () => { + this.addBlurEvent.setConfig({ + addListener: this.state.expanded, + clickExcludeElm: this.splitViewPaneElm, + blurCallback: () => { + this.setState({ + expanded: false + }, this.props.onClosePane); + }, + blurKeyCodes: [codes.esc] + }); + } + + componentDidMount() { + this.addBlurEventMethod(); + } + + componentDidUpdate() { + this.addBlurEventMethod(); + } + + componentWillUnmount() { + this.addBlurEvent.cleanEvent(); + } static contextTypes = { theme: PropTypes.object }; context: { theme: ReactUWP.ThemeType }; @@ -34,6 +80,7 @@ export class SplitView extends React.Component { panePosition, children, paneStyle, + onClosePane, ...attributes } = this.props; const { theme } = this.context; @@ -46,6 +93,11 @@ export class SplitView extends React.Component { if (child.type === SplitViewPane) { splitViewPanes.push(React.cloneElement(child, { style: { ...styles.pane, ...child.props.style }, + ref: (splitViewPane: SplitViewPane) => { + if (splitViewPane) { + this.splitViewPaneElm = splitViewPane.rootElm; + } + }, key: index.toString() })); } else { @@ -77,11 +129,13 @@ function getStyles(splitView: SplitView): { context, props: { style, - defaultExpanded, expandedWidth, displayMode, panePosition, paneStyle + }, + state: { + expanded } } = splitView; const { theme } = context; @@ -122,7 +176,7 @@ function getStyles(splitView: SplitView): { ...(isCompact ? { height: "100%", width: expandedWidth, - transform: `translate3d(${defaultExpanded ? 0 : expandedWidth}px, 0, 0)` + transform: `translate3d(${expanded ? 0 : expandedWidth}px, 0, 0)` } as React.CSSProperties : void 0), ...(isOverlay ? { position: "absolute", @@ -131,7 +185,7 @@ function getStyles(splitView: SplitView): { left: panePositionIsRight ? void 0 : 0, height: "100%", width: expandedWidth, - transform: `translate3d(${defaultExpanded ? 0 : expandedWidth}px, 0, 0)` + transform: `translate3d(${expanded ? 0 : expandedWidth}px, 0, 0)` } as React.CSSProperties : void 0), ...paneStyle }) diff --git a/src/TimePicker/index.tsx b/src/TimePicker/index.tsx index e2f7d607..27084bc4 100644 --- a/src/TimePicker/index.tsx +++ b/src/TimePicker/index.tsx @@ -1,6 +1,8 @@ import * as React from "react"; import * as PropTypes from "prop-types"; +import { codes } from "keycode"; +import AddBlurEvent from "../common/AddBlurEvent"; import Separator from "../Separator"; import IconButton from "../IconButton"; import ElementState from "../ElementState"; @@ -63,6 +65,9 @@ export class TimePicker extends React.Component { + this.addBlurEvent.setConfig({ + addListener: this.state.showPicker, + clickExcludeElm: this.elementState.rootElm, + blurCallback: () => { + this.setState({ + showPicker: false + }); + }, + blurKeyCodes: [codes.esc] + }); + } + + componentDidMount() { + this.addBlurEventMethod(); + } + componentDidUpdate() { const { pickerItemHeight } = this.props; scrollToYEasing(this.hourListView.rootElm, this.hourIndex * pickerItemHeight, 0.1); scrollToYEasing(this.minuteListView.rootElm, this.minuteIndex * pickerItemHeight, 0.1); scrollToYEasing(this.timeTypeListView.rootElm, this.timeTypeIndex * pickerItemHeight, 0.1); + + this.addBlurEventMethod(); + } + + componentWillUnmount() { + this.addBlurEvent.cleanEvent(); } toggleShowPicker = (showPicker?: any) => { @@ -144,6 +172,7 @@ export class TimePicker extends React.Component this.elementState = elementState} >
diff --git a/src/common/addBlurEvent.ts b/src/common/addBlurEvent.ts index 70b5afe6..e2a7fcae 100644 --- a/src/common/addBlurEvent.ts +++ b/src/common/addBlurEvent.ts @@ -33,7 +33,7 @@ export default class AddBlurEvent { this.clickListener = (e: Event) => { if (clickExcludeElm) { if (clickExcludeElm.contains(e.target as Node)) { - this.cleanEvent(); + return; } else { this.cleanEvent(); blurCallback(e);