From 5634808fbb83a6644430925866ca7241b46e9836 Mon Sep 17 00:00:00 2001 From: manajdov Date: Mon, 17 Dec 2018 14:35:39 +0100 Subject: [PATCH 01/23] -added on prop in the Popup for allowing the user to change the trigger event of the popup on click or hover -added usage examples --- .../Usage/PopupExampleClick.shorthand.tsx | 8 ++ .../Usage/PopupExampleHover.shorthand.tsx | 8 ++ .../examples/components/Popup/Usage/index.tsx | 21 +++++ docs/src/examples/components/Popup/index.tsx | 2 + src/components/Popup/Popup.tsx | 84 +++++++++++++++++-- src/components/Popup/PopupContent.tsx | 37 +++++++- 6 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx create mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx create mode 100644 docs/src/examples/components/Popup/Usage/index.tsx diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx new file mode 100644 index 0000000000..f8548bfa44 --- /dev/null +++ b/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx @@ -0,0 +1,8 @@ +import React from 'react' +import { Button, Popup } from '@stardust-ui/react' + +const PopupExampleClick = () => ( + } content="Hello from popup on click!" on="click" /> +) + +export default PopupExampleClick diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx new file mode 100644 index 0000000000..1dc2575dab --- /dev/null +++ b/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx @@ -0,0 +1,8 @@ +import React from 'react' +import { Button, Popup } from '@stardust-ui/react' + +const PopupExampleHover = () => ( + } content="Hello from popup on hover!" on="hover" /> +) + +export default PopupExampleHover diff --git a/docs/src/examples/components/Popup/Usage/index.tsx b/docs/src/examples/components/Popup/Usage/index.tsx new file mode 100644 index 0000000000..089b8c8bb7 --- /dev/null +++ b/docs/src/examples/components/Popup/Usage/index.tsx @@ -0,0 +1,21 @@ +import React from 'react' + +import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection' + +const Usage = () => ( + + + + +) + +export default Usage diff --git a/docs/src/examples/components/Popup/index.tsx b/docs/src/examples/components/Popup/index.tsx index 37e5e811f9..c28a709017 100644 --- a/docs/src/examples/components/Popup/index.tsx +++ b/docs/src/examples/components/Popup/index.tsx @@ -1,11 +1,13 @@ import React from 'react' import Types from './Types' import Variations from './Variations' +import Usage from './Usage' const PopupExamples = () => (
+
) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 3876f75dde..2c28613be3 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -54,6 +54,9 @@ export interface PopupProps /** Initial value for 'open'. */ defaultOpen?: boolean + /** Delay in ms for the mouse leave event, before the popup will be closed. */ + mouseLeaveDelay?: number + /** Offset value to apply to rendered popup. Accepts the following units: * - px or unit-less, interpreted as pixels * - %, percentage relative to the length of the trigger element @@ -63,6 +66,9 @@ export interface PopupProps */ offset?: string + /** Events triggering the popup. */ + on?: 'click' | 'hover' + /** Defines whether popup is displayed. */ open?: boolean @@ -119,6 +125,8 @@ export default class Popup extends AutoControlledComponent { + const { mouseLeaveDelay } = this.props + this.isPopupClosing = true + setTimeout(() => { + if (this.isPopupClosing) { + this.trySetOpen(false, e) + } + + this.isPopupClosing = false + }, mouseLeaveDelay) + } private outsideClickSubscription = EventStack.noSubscription private triggerDomElement = null @@ -224,10 +256,54 @@ export default class Popup extends AutoControlledComponent { + this.trySetOpen(!this.state.open, e) + _.invoke(triggerElement, 'props.onClick', e, ...rest) + } + } + if (on === 'hover') { + triggerProps.onMouseEnter = (e, ...rest) => { + this.setPopupOpen(true, e) + _.invoke(triggerElement, 'props.onMouseEnter', e, ...rest) + } + triggerProps.onMouseLeave = (e, ...rest) => { + this.setPopupOpen(false, e) + _.invoke(triggerElement, 'props.onMouseLeave', e, ...rest) + } + } + + return triggerProps + } + + handleContentOverrides = predefinedProps => { + const contentProps: any = {} + + const { on } = this.props + + if (on === 'hover') { + contentProps.onMouseEnter = (e, contentProps) => { + this.setPopupOpen(true, e) + _.invoke(predefinedProps, 'onMouseEnter', e, contentProps) + } + contentProps.onMouseLeave = (e, contentProps) => { + this.setPopupOpen(false, e) + _.invoke(predefinedProps, 'onMouseLeave', e, contentProps) + } + } + + return contentProps + } + private renderTrigger(accessibility) { const { children, trigger } = this.props const triggerElement = childrenExist(children) ? children : (trigger as any) - + const triggerProps = this.getTriggerProps(triggerElement) return ( triggerElement && ( {React.cloneElement(triggerElement, { - onClick: (e, ...rest) => { - this.trySetOpen(!this.state.open, e) - _.invoke(triggerElement, 'props.onClick', e, ...rest) - }, + ...triggerProps, ...accessibility.attributes.trigger, ...accessibility.keyHandlers.trigger, })} @@ -308,6 +381,7 @@ export default class Popup extends AutoControlledComponent + + /** + * Called after user's mouse leave. + * @param {SyntheticEvent} event - React's original SyntheticEvent. + * @param {object} data - All props. + */ + onMouseLeave?: ComponentEventHandler +} /** * A PopupContent displays the content of a Popup component @@ -30,6 +46,16 @@ class PopupContent extends UIComponent, any> { public static propTypes = { ...commonPropTypes.createCommon(), + onMouseEnter: PropTypes.func, + onMouseLeave: PropTypes.func, + } + + private handleMouseEnter = e => { + _.invoke(this.props, 'onMouseEnter', e, this.props) + } + + private handleMouseLeave = e => { + _.invoke(this.props, 'onMouseLeave', e, this.props) } public renderComponent({ @@ -40,7 +66,12 @@ class PopupContent extends UIComponent, any> { const { children, content } = this.props return ( - + {childrenExist(children) ? children : content} ) From dc3142d420b41a48d2a595dab983d8cf7fdc07e8 Mon Sep 17 00:00:00 2001 From: manajdov Date: Mon, 17 Dec 2018 16:45:34 +0100 Subject: [PATCH 02/23] -updated changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6140d7bc1c..0eace7cc27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Features +- Add `on` and `mouseLeaveDelay` props to `Popup` component @mnajdova ([#622](https://github.com/stardust-ui/react/pull/622)) + ## [v0.15.0](https://github.com/stardust-ui/react/tree/v0.15.0) (2018-12-17) [Compare changes](https://github.com/stardust-ui/react/compare/v0.14.0...v0.15.0) From da52a3333093c8d5fc83afcbe5b6adf3a7ba0107 Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 19 Dec 2018 18:39:42 +0100 Subject: [PATCH 03/23] -wip: adding focus, click, hover combinations for the on prop --- src/components/Popup/Popup.tsx | 48 ++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 2c28613be3..73007e1143 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -67,7 +67,7 @@ export interface PopupProps offset?: string /** Events triggering the popup. */ - on?: 'click' | 'hover' + on?: 'click' | 'hover' | 'focus' | ['focus' | 'click'] | ['focus' | 'hover'] /** Defines whether popup is displayed. */ open?: boolean @@ -126,7 +126,11 @@ export default class Popup extends AutoControlledComponent { this.trySetOpen(!this.state.open, e) _.invoke(triggerElement, 'props.onClick', e, ...rest) } } - if (on === 'hover') { + if (_.includes(normalizedOn, 'focus')) { + triggerProps.onFocus = (e, ...rest) => { + console.log('Calledn trigger on focus') + this.trySetOpen(true, e) + _.invoke(triggerElement, 'props.onFocus', e, ...rest) + } + triggerProps.onBlur = (e, ...rest) => { + if ( + !e.currentTarget.contains(e.relatedTarget) && + !this.popupDomElement.contains(e.relatedTarget) + ) { + this.trySetOpen(false, e) + } + _.invoke(triggerElement, 'props.onBlur', e, ...rest) + } + } + if (_.includes(normalizedOn, 'hover')) { triggerProps.onMouseEnter = (e, ...rest) => { this.setPopupOpen(true, e) _.invoke(triggerElement, 'props.onMouseEnter', e, ...rest) @@ -285,8 +306,9 @@ export default class Popup extends AutoControlledComponent { this.setPopupOpen(true, e) _.invoke(predefinedProps, 'onMouseEnter', e, contentProps) @@ -296,6 +318,21 @@ export default class Popup extends AutoControlledComponent { + !this.state.open && this.trySetOpen(true, e) + _.invoke(predefinedProps, 'props.onFocus', e, ...rest) + } + contentProps.onBlur = (e, ...rest) => { + if ( + !e.currentTarget.contains(e.relatedTarget) && + !this.popupDomElement.contains(e.relatedTarget) + ) { + this.trySetOpen(false, e) + } + _.invoke(predefinedProps, 'props.onBlur', e, ...rest) + } + } return contentProps } @@ -357,6 +394,7 @@ export default class Popup extends AutoControlledComponent { const { content } = this.props + // TODO: add here the handlers (onFocus, onBlur etc..) const popupWrapperAttributes = { ...(rtl && { dir: 'rtl' }), ...accessibility.attributes.popup, From f1fe2b40cf39d359ccc37d2fa3f745f49d173f90 Mon Sep 17 00:00:00 2001 From: manajdov Date: Thu, 20 Dec 2018 12:36:37 +0100 Subject: [PATCH 04/23] -fixed some issues -copied handlers on the primitive content element --- src/components/Popup/Popup.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 73007e1143..53c4f2af46 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -274,7 +274,6 @@ export default class Popup extends AutoControlledComponent { - console.log('Calledn trigger on focus') this.trySetOpen(true, e) _.invoke(triggerElement, 'props.onFocus', e, ...rest) } @@ -302,7 +301,7 @@ export default class Popup extends AutoControlledComponent { + handleContentOverrides = (predefinedProps?) => { const contentProps: any = {} const { on } = this.props @@ -311,26 +310,26 @@ export default class Popup extends AutoControlledComponent { this.setPopupOpen(true, e) - _.invoke(predefinedProps, 'onMouseEnter', e, contentProps) + predefinedProps && _.invoke(predefinedProps, 'onMouseEnter', e, contentProps) } contentProps.onMouseLeave = (e, contentProps) => { this.setPopupOpen(false, e) - _.invoke(predefinedProps, 'onMouseLeave', e, contentProps) + predefinedProps && _.invoke(predefinedProps, 'onMouseLeave', e, contentProps) } } if (_.includes(normalizedOn, 'focus')) { - contentProps.onFocus = (e, ...rest) => { + contentProps.onFocus = (e, contentProps) => { !this.state.open && this.trySetOpen(true, e) - _.invoke(predefinedProps, 'props.onFocus', e, ...rest) + predefinedProps && _.invoke(predefinedProps, 'onFocus', e, contentProps) } - contentProps.onBlur = (e, ...rest) => { + contentProps.onBlur = (e, contentProps) => { if ( !e.currentTarget.contains(e.relatedTarget) && !this.popupDomElement.contains(e.relatedTarget) ) { this.trySetOpen(false, e) } - _.invoke(predefinedProps, 'props.onBlur', e, ...rest) + predefinedProps && _.invoke(predefinedProps, 'onBlur', e, contentProps) } } @@ -402,6 +401,7 @@ export default class Popup extends AutoControlledComponent Date: Thu, 20 Dec 2018 13:53:07 +0100 Subject: [PATCH 05/23] -added escape key handler on the trigger -hover should by default add the focus handler as well --- src/components/Popup/Popup.tsx | 16 +++++++++------- .../Behaviors/Popup/popupBehavior.ts | 5 +++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 53c4f2af46..4ca1757ce8 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -182,15 +182,19 @@ export default class Popup extends AutoControlledComponent { - this.closeAndFocusTrigger(e) + this.closeAndFocusTrigger(e, true) + e.stopPropagation() + }, + close: e => { + this.closeAndFocusTrigger(e, false) e.stopPropagation() }, } - private closeAndFocusTrigger = e => { + private closeAndFocusTrigger = (e, focusTrigger) => { if (this.state.open) { this.trySetOpen(false, e, true) - _.invoke(this.triggerDomElement, 'focus') + focusTrigger && _.invoke(this.triggerDomElement, 'focus') } } @@ -219,8 +223,6 @@ export default class Popup extends AutoControlledComponent { this.trySetOpen(true, e) _.invoke(triggerElement, 'props.onFocus', e, ...rest) @@ -317,7 +319,7 @@ export default class Popup extends AutoControlledComponent { !this.state.open && this.trySetOpen(true, e) predefinedProps && _.invoke(predefinedProps, 'onFocus', e, contentProps) diff --git a/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts b/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts index 3b5ac45942..71a943944f 100644 --- a/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts +++ b/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts @@ -26,6 +26,11 @@ const popupBehavior: Accessibility = (props: any) => ({ keyCombinations: [{ keyCode: keyboardKey.Escape }], }, }, + trigger: { + close: { + keyCombinations: [{ keyCode: keyboardKey.Escape }], + }, + }, }, }) From 0b4c4d42078ea6ab51437d64ef5a3aefa968510e Mon Sep 17 00:00:00 2001 From: manajdov Date: Thu, 20 Dec 2018 17:37:38 +0100 Subject: [PATCH 06/23] -fixed focus handlers -fixed examples imports --- .../Usage/PopupExampleClick.shorthand.tsx | 2 +- .../Usage/PopupExampleHover.shorthand.tsx | 2 +- .../examples/components/Popup/Usage/index.tsx | 2 +- .../Behaviors/Popup/popupBehavior.ts | 48 +++++++++++-------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx index f8548bfa44..18109cddc8 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import * as React from 'react' import { Button, Popup } from '@stardust-ui/react' const PopupExampleClick = () => ( diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx index 1dc2575dab..d04af309b4 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import * as React from 'react' import { Button, Popup } from '@stardust-ui/react' const PopupExampleHover = () => ( diff --git a/docs/src/examples/components/Popup/Usage/index.tsx b/docs/src/examples/components/Popup/Usage/index.tsx index 089b8c8bb7..db5711347a 100644 --- a/docs/src/examples/components/Popup/Usage/index.tsx +++ b/docs/src/examples/components/Popup/Usage/index.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import * as React from 'react' import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample' import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection' diff --git a/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts b/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts index 71a943944f..116791480b 100644 --- a/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts +++ b/src/lib/accessibility/Behaviors/Popup/popupBehavior.ts @@ -10,29 +10,39 @@ import * as _ from 'lodash' * @specification * Adds attribute 'aria-disabled=true' to 'trigger' component's part based on the property 'disabled'. */ -const popupBehavior: Accessibility = (props: any) => ({ - attributes: { - trigger: { - role: getAriaAttributeFromProps('role', props, 'button'), - tabIndex: getAriaAttributeFromProps('tabIndex', props, '0'), - 'aria-disabled': !_.isNil(props['aria-disabled']) - ? props['aria-disabled'] - : !!props['disabled'], - }, - }, - keyActions: { - popup: { - closeAndFocusTrigger: { - keyCombinations: [{ keyCode: keyboardKey.Escape }], +const popupBehavior: Accessibility = (props: any) => { + const { on } = props + const normalizedOn = _.isArray(on) ? on : [on] + return { + attributes: { + trigger: { + role: getAriaAttributeFromProps('role', props, 'button'), + tabIndex: getAriaAttributeFromProps('tabIndex', props, '0'), + 'aria-disabled': !_.isNil(props['aria-disabled']) + ? props['aria-disabled'] + : !!props['disabled'], }, }, - trigger: { - close: { - keyCombinations: [{ keyCode: keyboardKey.Escape }], + keyActions: { + popup: { + closeAndFocusTrigger: { + keyCombinations: [{ keyCode: keyboardKey.Escape }], + }, + }, + trigger: { + toggle: { + keyCombinations: + _.includes(normalizedOn, 'focus') && !_.includes(normalizedOn, 'click') + ? [{ keyCode: keyboardKey.Enter }, { keyCode: keyboardKey.Spacebar }] + : [], + }, + close: { + keyCombinations: [{ keyCode: keyboardKey.Escape }], + }, }, }, - }, -}) + } +} const isFocusable = propsData => { try { From 22bd970c33cd2e33407126ef8bf8dca64be8b9c0 Mon Sep 17 00:00:00 2001 From: manajdov Date: Fri, 21 Dec 2018 12:17:23 +0100 Subject: [PATCH 07/23] -fixed focus --- src/components/Popup/Popup.tsx | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index e733d5df88..d3fda44c9d 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -274,7 +274,7 @@ export default class Popup extends AutoControlledComponent { this.trySetOpen(true, e) _.invoke(triggerElement, 'props.onFocus', e, ...rest) @@ -298,6 +298,10 @@ export default class Popup extends AutoControlledComponent { + this.setPopupOpen(true, e) + _.invoke(triggerElement, 'props.onClick', e, ...rest) + } } return triggerProps @@ -309,17 +313,7 @@ export default class Popup extends AutoControlledComponent { - this.setPopupOpen(true, e) - predefinedProps && _.invoke(predefinedProps, 'onMouseEnter', e, contentProps) - } - contentProps.onMouseLeave = (e, contentProps) => { - this.setPopupOpen(false, e) - predefinedProps && _.invoke(predefinedProps, 'onMouseLeave', e, contentProps) - } - } - if (_.includes(normalizedOn, 'focus') || _.includes(normalizedOn, 'hover')) { + if (_.includes(normalizedOn, 'focus')) { contentProps.onFocus = (e, contentProps) => { !this.state.open && this.trySetOpen(true, e) predefinedProps && _.invoke(predefinedProps, 'onFocus', e, contentProps) @@ -334,6 +328,20 @@ export default class Popup extends AutoControlledComponent { + this.setPopupOpen(true, e) + predefinedProps && _.invoke(predefinedProps, 'onMouseEnter', e, contentProps) + } + contentProps.onMouseLeave = (e, contentProps) => { + this.setPopupOpen(false, e) + predefinedProps && _.invoke(predefinedProps, 'onMouseLeave', e, contentProps) + } + contentProps.onClick = (e, contentProps) => { + this.setPopupOpen(true, e) + predefinedProps && _.invoke(predefinedProps, 'onClick', e, contentProps) + } + } return contentProps } @@ -398,7 +406,6 @@ export default class Popup extends AutoControlledComponent { const { content } = this.props - // TODO: add here the handlers (onFocus, onBlur etc..) const popupWrapperAttributes = { ...(rtl && { dir: 'rtl' }), ...accessibility.attributes.popup, From 1bbe26d5d47e5dc398f667ab800ddec858ff0983 Mon Sep 17 00:00:00 2001 From: manajdov Date: Fri, 21 Dec 2018 12:21:35 +0100 Subject: [PATCH 08/23] -added focus usage example --- .../Popup/Usage/PopupExampleFocus.shorthand.tsx | 8 ++++++++ docs/src/examples/components/Popup/Usage/index.tsx | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx new file mode 100644 index 0000000000..f4870e1b81 --- /dev/null +++ b/docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx @@ -0,0 +1,8 @@ +import * as React from 'react' +import { Button, Popup } from '@stardust-ui/react' + +const PopupExampleFocus = () => ( + } content="Hello from popup on click!" on="focus" /> +) + +export default PopupExampleFocus diff --git a/docs/src/examples/components/Popup/Usage/index.tsx b/docs/src/examples/components/Popup/Usage/index.tsx index db5711347a..fb25eb8b6f 100644 --- a/docs/src/examples/components/Popup/Usage/index.tsx +++ b/docs/src/examples/components/Popup/Usage/index.tsx @@ -15,6 +15,11 @@ const Usage = () => ( description="A popup can be triggered on click." examplePath="components/Popup/Usage/PopupExampleClick" /> + ) From 982ddd4d9705d70fed058369eaa470353e686139 Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 10:28:22 +0100 Subject: [PATCH 09/23] -fixed on prop type -hover on blur should close the popup -rearranged the examples for the on prop --- .../Usage/PopupExampleClick.shorthand.tsx | 8 --- .../Usage/PopupExampleFocus.shorthand.tsx | 8 --- .../Usage/PopupExampleHover.shorthand.tsx | 8 --- .../Popup/Usage/PopupExampleOn.shorthand.tsx | 15 ++++++ .../PopupExampleOnMultiple.shorthand.tsx | 21 ++++++++ .../examples/components/Popup/Usage/index.tsx | 17 +++--- src/components/Popup/Popup.tsx | 53 ++++++++++++------- src/index.ts | 9 +++- .../Behaviors/Popup/popupBehavior.ts | 8 --- 9 files changed, 85 insertions(+), 62 deletions(-) delete mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx delete mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx delete mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx create mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx create mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx deleted file mode 100644 index 18109cddc8..0000000000 --- a/docs/src/examples/components/Popup/Usage/PopupExampleClick.shorthand.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import * as React from 'react' -import { Button, Popup } from '@stardust-ui/react' - -const PopupExampleClick = () => ( - } content="Hello from popup on click!" on="click" /> -) - -export default PopupExampleClick diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx deleted file mode 100644 index f4870e1b81..0000000000 --- a/docs/src/examples/components/Popup/Usage/PopupExampleFocus.shorthand.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import * as React from 'react' -import { Button, Popup } from '@stardust-ui/react' - -const PopupExampleFocus = () => ( - } content="Hello from popup on click!" on="focus" /> -) - -export default PopupExampleFocus diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx deleted file mode 100644 index d04af309b4..0000000000 --- a/docs/src/examples/components/Popup/Usage/PopupExampleHover.shorthand.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import * as React from 'react' -import { Button, Popup } from '@stardust-ui/react' - -const PopupExampleHover = () => ( - } content="Hello from popup on hover!" on="hover" /> -) - -export default PopupExampleHover diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx new file mode 100644 index 0000000000..57316de0a3 --- /dev/null +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' +import { Button, Popup, Grid, Text } from '@stardust-ui/react' + +const PopupExampleUsages = () => ( + + + + + } content="Hello from popup on click!" on="click" /> + } content="Hello from popup on hover!" on="hover" /> + } content="Hello from popup on focus!" on="focus" /> + +) + +export default PopupExampleUsages diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx new file mode 100644 index 0000000000..2189eb7ffc --- /dev/null +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx @@ -0,0 +1,21 @@ +import * as React from 'react' +import { Button, Popup, Grid, Text } from '@stardust-ui/react' + +const PopupExampleHover = () => ( + + + + } + content="Hello from popup on click!" + on={['click', 'focus']} + /> + } + content="Hello from popup on hover!" + on={['hover', 'focus']} + /> + +) + +export default PopupExampleHover diff --git a/docs/src/examples/components/Popup/Usage/index.tsx b/docs/src/examples/components/Popup/Usage/index.tsx index fb25eb8b6f..b1fbd5c813 100644 --- a/docs/src/examples/components/Popup/Usage/index.tsx +++ b/docs/src/examples/components/Popup/Usage/index.tsx @@ -6,19 +6,14 @@ import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection' const Usage = () => ( - ) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index d3fda44c9d..e8b5a62a71 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -34,6 +34,10 @@ import { const POSITIONS: Position[] = ['above', 'below', 'before', 'after'] const ALIGNMENTS: Alignment[] = ['top', 'bottom', 'start', 'end', 'center'] +export type PopupEvents = 'click' | 'hover' | 'focus' +export type RestrictedClickEvents = 'click' | 'focus' +export type RestrictedHoverEvents = 'hover' | 'focus' + export interface PopupProps extends StyledComponentProps, ChildrenComponentProps, @@ -67,7 +71,7 @@ export interface PopupProps offset?: string /** Events triggering the popup. */ - on?: 'click' | 'hover' | 'focus' | ['focus' | 'click'] | ['focus' | 'hover'] + on?: PopupEvents | RestrictedClickEvents[] | RestrictedHoverEvents[] /** Defines whether popup is displayed. */ open?: boolean @@ -178,23 +182,20 @@ export default class Popup extends AutoControlledComponent { - this.trySetOpen(!this.state.open, e, true) - }, closeAndFocusTrigger: e => { - this.closeAndFocusTrigger(e, true) + this.close(e, () => _.invoke(this.triggerDomElement, 'focus')) e.stopPropagation() }, close: e => { - this.closeAndFocusTrigger(e, false) + this.close(e) e.stopPropagation() }, } - private closeAndFocusTrigger = (e, focusTrigger) => { + private close = (e, onClose?: Function) => { if (this.state.open) { this.trySetOpen(false, e, true) - focusTrigger && _.invoke(this.triggerDomElement, 'focus') + onClose && onClose() } } @@ -268,12 +269,6 @@ export default class Popup extends AutoControlledComponent { - this.trySetOpen(!this.state.open, e) - _.invoke(triggerElement, 'props.onClick', e, ...rest) - } - } if (_.includes(normalizedOn, 'focus')) { triggerProps.onFocus = (e, ...rest) => { this.trySetOpen(true, e) @@ -288,7 +283,19 @@ export default class Popup extends AutoControlledComponent { + this.setPopupOpen(true, e) + _.invoke(triggerElement, 'props.onClick', e, ...rest) + } } + + if (_.includes(normalizedOn, 'click')) { + triggerProps.onClick = (e, ...rest) => { + this.trySetOpen(!this.state.open, e) + _.invoke(triggerElement, 'props.onClick', e, ...rest) + } + } + if (_.includes(normalizedOn, 'hover')) { triggerProps.onMouseEnter = (e, ...rest) => { this.setPopupOpen(true, e) @@ -302,12 +309,21 @@ export default class Popup extends AutoControlledComponent { + if ( + !e.currentTarget.contains(e.relatedTarget) && + !this.popupDomElement.contains(e.relatedTarget) + ) { + this.trySetOpen(false, e) + } + _.invoke(triggerElement, 'props.onBlur', e, ...rest) + } } return triggerProps } - handleContentOverrides = (predefinedProps?) => { + getContentProps = (predefinedProps?) => { const contentProps: any = {} const { on } = this.props @@ -315,7 +331,7 @@ export default class Popup extends AutoControlledComponent { - !this.state.open && this.trySetOpen(true, e) + this.trySetOpen(true, e) predefinedProps && _.invoke(predefinedProps, 'onFocus', e, contentProps) } contentProps.onBlur = (e, contentProps) => { @@ -328,6 +344,7 @@ export default class Popup extends AutoControlledComponent { this.setPopupOpen(true, e) @@ -413,7 +430,7 @@ export default class Popup extends AutoControlledComponent { - const { on } = props - const normalizedOn = _.isArray(on) ? on : [on] return { attributes: { trigger: { @@ -30,12 +28,6 @@ const popupBehavior: Accessibility = (props: any) => { }, }, trigger: { - toggle: { - keyCombinations: - _.includes(normalizedOn, 'focus') && !_.includes(normalizedOn, 'click') - ? [{ keyCode: keyboardKey.Enter }, { keyCode: keyboardKey.Spacebar }] - : [], - }, close: { keyCombinations: [{ keyCode: keyboardKey.Escape }], }, From 600de3724eecd442fec43d0c62ee3980b9756a39 Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 10:40:35 +0100 Subject: [PATCH 10/23] -handle timeout for closing only if mouseLeaveDelay is greater then 0 --- src/components/Popup/Popup.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index e8b5a62a71..450c43c963 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -168,14 +168,22 @@ export default class Popup extends AutoControlledComponent { const { mouseLeaveDelay } = this.props this.isPopupClosing = true - setTimeout(() => { - if (this.isPopupClosing) { - this.trySetOpen(false, e) - } + if (mouseLeaveDelay > 0) { + setTimeout(() => { + this.handlePopupClose(e) + }, mouseLeaveDelay) + } else { + this.handlePopupClose(e) + } + } + handlePopupClose = e => { + if (this.isPopupClosing) { + this.trySetOpen(false, e) this.isPopupClosing = false - }, mouseLeaveDelay) + } } + private outsideClickSubscription = EventStack.noSubscription private triggerDomElement = null From 4627a97fcdca0960efa3068fbfa794187d2d8062 Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 11:17:27 +0100 Subject: [PATCH 11/23] -adding comments on the handlers created -refactoring on the blur conditions --- src/components/Popup/Popup.tsx | 40 ++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 450c43c963..83596ba2ce 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -165,7 +165,7 @@ export default class Popup extends AutoControlledComponent { + private schedulePopupClose = e => { const { mouseLeaveDelay } = this.props this.isPopupClosing = true if (mouseLeaveDelay > 0) { @@ -177,7 +177,7 @@ export default class Popup extends AutoControlledComponent { + private handlePopupClose = e => { if (this.isPopupClosing) { this.trySetOpen(false, e) this.isPopupClosing = false @@ -277,16 +277,16 @@ export default class Popup extends AutoControlledComponent { this.trySetOpen(true, e) _.invoke(triggerElement, 'props.onFocus', e, ...rest) } triggerProps.onBlur = (e, ...rest) => { - if ( - !e.currentTarget.contains(e.relatedTarget) && - !this.popupDomElement.contains(e.relatedTarget) - ) { + if (this.shouldBlurClose(e)) { this.trySetOpen(false, e) } _.invoke(triggerElement, 'props.onBlur', e, ...rest) @@ -297,6 +297,9 @@ export default class Popup extends AutoControlledComponent { this.trySetOpen(!this.state.open, e) @@ -304,6 +307,9 @@ export default class Popup extends AutoControlledComponent { this.setPopupOpen(true, e) @@ -318,10 +324,7 @@ export default class Popup extends AutoControlledComponent { - if ( - !e.currentTarget.contains(e.relatedTarget) && - !this.popupDomElement.contains(e.relatedTarget) - ) { + if (this.shouldBlurClose(e)) { this.trySetOpen(false, e) } _.invoke(triggerElement, 'props.onBlur', e, ...rest) @@ -337,22 +340,25 @@ export default class Popup extends AutoControlledComponent { this.trySetOpen(true, e) predefinedProps && _.invoke(predefinedProps, 'onFocus', e, contentProps) } contentProps.onBlur = (e, contentProps) => { - if ( - !e.currentTarget.contains(e.relatedTarget) && - !this.popupDomElement.contains(e.relatedTarget) - ) { + if (this.shouldBlurClose(e)) { this.trySetOpen(false, e) } predefinedProps && _.invoke(predefinedProps, 'onBlur', e, contentProps) } } + /** + * The hover is adding the mouseEnter, mouseLeave and click event (always opening on click) + */ if (_.includes(normalizedOn, 'hover')) { contentProps.onMouseEnter = (e, contentProps) => { this.setPopupOpen(true, e) @@ -371,6 +377,12 @@ export default class Popup extends AutoControlledComponent { + return ( + !e.currentTarget.contains(e.relatedTarget) && !this.popupDomElement.contains(e.relatedTarget) + ) + } + private renderTrigger(accessibility) { const { children, trigger } = this.props const triggerElement = childrenExist(children) ? children : (trigger as any) From d0fd9410815c9a2e5be3dc871b32c67db168f763 Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 13:41:01 +0100 Subject: [PATCH 12/23] -rearranged usage example and added example using the trap focus behavior --- .../Popup/Usage/PopupExampleOn.shorthand.tsx | 7 ++-- .../PopupExampleOnMultiple.shorthand.tsx | 6 +-- .../PopupExampleOnWithFocusTrap.shorthand.tsx | 39 +++++++++++++++++++ .../examples/components/Popup/Usage/index.tsx | 5 +++ src/components/Popup/Popup.tsx | 5 ++- 5 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx index 57316de0a3..de5a6020c9 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx @@ -1,15 +1,16 @@ import * as React from 'react' import { Button, Popup, Grid, Text } from '@stardust-ui/react' -const PopupExampleUsages = () => ( - +const PopupExampleOn = () => ( + + } content="Hello from popup on click!" on="click" /> } content="Hello from popup on hover!" on="hover" /> } content="Hello from popup on focus!" on="focus" /> ) -export default PopupExampleUsages +export default PopupExampleOn diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx index 2189eb7ffc..7f734f87d7 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import { Button, Popup, Grid, Text } from '@stardust-ui/react' -const PopupExampleHover = () => ( - +const PopupExampleOnMultiple = () => ( + ( ) -export default PopupExampleHover +export default PopupExampleOnMultiple diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx new file mode 100644 index 0000000000..8e442e89ef --- /dev/null +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx @@ -0,0 +1,39 @@ +import * as React from 'react' +import { Button, Popup, Grid, Text, popupFocusTrapBehavior } from '@stardust-ui/react' + +const contentWithButtons = { + content: ( + <> + + + + ), +} + +const PopupExampleOnWithFocusTrap = () => ( + + + + + } + content={contentWithButtons} + accessibility={popupFocusTrapBehavior} + on="click" + /> + } + content={contentWithButtons} + accessibility={popupFocusTrapBehavior} + on="hover" + /> + } + content={contentWithButtons} + accessibility={popupFocusTrapBehavior} + on="focus" + /> + +) + +export default PopupExampleOnWithFocusTrap diff --git a/docs/src/examples/components/Popup/Usage/index.tsx b/docs/src/examples/components/Popup/Usage/index.tsx index b1fbd5c813..35387717bf 100644 --- a/docs/src/examples/components/Popup/Usage/index.tsx +++ b/docs/src/examples/components/Popup/Usage/index.tsx @@ -10,6 +10,11 @@ const Usage = () => ( description="A popup can be triggered on click, hover or focus." examplePath="components/Popup/Usage/PopupExampleOn" /> + { return ( - !e.currentTarget.contains(e.relatedTarget) && !this.popupDomElement.contains(e.relatedTarget) + !e.currentTarget || + !this.popupDomElement || + (!e.currentTarget.contains(e.relatedTarget) && + !this.popupDomElement.contains(e.relatedTarget)) ) } From dcb40ec9ef44349a9aac509ff1e93cbaf67d0a5c Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 13:46:21 +0100 Subject: [PATCH 13/23] -improved typing for the on prop in the Popup --- src/components/Popup/Popup.tsx | 3 ++- src/index.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 430c06be53..7fb1a0af48 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -37,6 +37,7 @@ const ALIGNMENTS: Alignment[] = ['top', 'bottom', 'start', 'end', 'center'] export type PopupEvents = 'click' | 'hover' | 'focus' export type RestrictedClickEvents = 'click' | 'focus' export type RestrictedHoverEvents = 'hover' | 'focus' +export type PopupEventsArray = RestrictedClickEvents[] | RestrictedHoverEvents[] export interface PopupProps extends StyledComponentProps, @@ -71,7 +72,7 @@ export interface PopupProps offset?: string /** Events triggering the popup. */ - on?: PopupEvents | RestrictedClickEvents[] | RestrictedHoverEvents[] + on?: PopupEvents | PopupEventsArray /** Defines whether popup is displayed. */ open?: boolean diff --git a/src/index.ts b/src/index.ts index 50fa81a239..fc36dad5f4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -84,6 +84,7 @@ export { PopupEvents, RestrictedHoverEvents, RestrictedClickEvents, + PopupEventsArray, } from './components/Popup/Popup' export { default as PopupContent, PopupContentProps } from './components/Popup/PopupContent' export { Placement, Alignment, Position } from './components/Popup/positioningHelper' From 28f3e67612807d1a362be53a1d85651c8de7ef8f Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 14:13:04 +0100 Subject: [PATCH 14/23] -removed expressions for strings in the examples --- .../components/Popup/Usage/PopupExampleOn.shorthand.tsx | 6 +++--- .../Popup/Usage/PopupExampleOnMultiple.shorthand.tsx | 4 ++-- .../Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx index de5a6020c9..36c02f88ef 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx @@ -3,9 +3,9 @@ import { Button, Popup, Grid, Text } from '@stardust-ui/react' const PopupExampleOn = () => ( - - - + + + } content="Hello from popup on click!" on="click" /> } content="Hello from popup on hover!" on="hover" /> diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx index 7f734f87d7..a086ad74f1 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx @@ -3,8 +3,8 @@ import { Button, Popup, Grid, Text } from '@stardust-ui/react' const PopupExampleOnMultiple = () => ( - - + + } content="Hello from popup on click!" diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx index 8e442e89ef..ec68583190 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx @@ -12,9 +12,9 @@ const contentWithButtons = { const PopupExampleOnWithFocusTrap = () => ( - - - + + + } content={contentWithButtons} From f51ef3a9671f4a0228b63ff61c878cfdcb4ecee2 Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 14:16:08 +0100 Subject: [PATCH 15/23] -replaced double quotes with single quotes From c31494d7b912751d598bf92dd1f37d1c46c4c507 Mon Sep 17 00:00:00 2001 From: manajdov Date: Wed, 2 Jan 2019 14:28:45 +0100 Subject: [PATCH 16/23] -added aria-label on the popup examples --- .../Popup/Usage/PopupExampleOn.shorthand.tsx | 18 +++++++++++++++--- .../Usage/PopupExampleOnMultiple.shorthand.tsx | 4 ++-- .../PopupExampleOnWithFocusTrap.shorthand.tsx | 6 +++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx index 36c02f88ef..7b7eb01326 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx @@ -7,9 +7,21 @@ const PopupExampleOn = () => ( - } content="Hello from popup on click!" on="click" /> - } content="Hello from popup on hover!" on="hover" /> - } content="Hello from popup on focus!" on="focus" /> + } + content="Hello from popup on click!" + on="click" + /> + } + content="Hello from popup on hover!" + on="hover" + /> + } + content="Hello from popup on focus!" + on="focus" + /> ) diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx index a086ad74f1..d97a8b436d 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx @@ -6,12 +6,12 @@ const PopupExampleOnMultiple = () => ( } + trigger={ + ), From 318b09bcf711fa5f5573d4cb0e4fc626859ca1c4 Mon Sep 17 00:00:00 2001 From: manajdov Date: Fri, 4 Jan 2019 12:26:39 +0100 Subject: [PATCH 19/23] -refactoring the timeout handling and added clear logic --- src/components/Popup/Popup.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 00596ae058..2623897a44 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -155,25 +155,22 @@ export default class Popup extends AutoControlledComponent { const { mouseLeaveDelay } = this.props - this.isPopupClosing = true - setTimeout(() => { - if (this.isPopupClosing) { - this.trySetOpen(false, e) - this.isPopupClosing = false - } + + this.closeTimeoutId = setTimeout(() => { + this.trySetOpen(false, e) }, mouseLeaveDelay) } From f8e2bcaa205e0374e82b6fe485deda6577c40877 Mon Sep 17 00:00:00 2001 From: manajdov Date: Fri, 4 Jan 2019 17:25:21 +0100 Subject: [PATCH 20/23] -small refactorings --- src/components/Popup/Popup.tsx | 102 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 2623897a44..5c73a21fa6 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -155,30 +155,13 @@ export default class Popup extends AutoControlledComponent { - const { mouseLeaveDelay } = this.props - - this.closeTimeoutId = setTimeout(() => { - this.trySetOpen(false, e) - }, mouseLeaveDelay) - } - private outsideClickSubscription = EventStack.noSubscription private triggerDomElement = null private popupDomElement = null + private closeTimeoutId + protected actionHandlers: AccessibilityActionHandlers = { closeAndFocusTrigger: e => { this.close(e, () => _.invoke(this.triggerDomElement, 'focus')) @@ -190,38 +173,6 @@ export default class Popup extends AutoControlledComponent { - if (this.state.open) { - this.trySetOpen(false, e, true) - onClose && onClose() - } - } - - private updateOutsideClickSubscription() { - this.outsideClickSubscription.unsubscribe() - - if (this.state.open) { - setTimeout(() => { - this.outsideClickSubscription = EventStack.subscribe( - 'click', - e => { - const isOutsidePopupElement = - this.popupDomElement && !this.popupDomElement.contains(e.target) - const isOutsideTriggerElement = - this.triggerDomElement && !this.triggerDomElement.contains(e.target) - - if (isOutsidePopupElement && isOutsideTriggerElement) { - this.state.open && this.trySetOpen(false, e, true) - } - }, - { - useCapture: true, - }, - ) - }) - } - } - public componentDidMount() { this.updateOutsideClickSubscription() @@ -261,7 +212,32 @@ export default class Popup extends AutoControlledComponent { + this.outsideClickSubscription = EventStack.subscribe( + 'click', + e => { + const isOutsidePopupElement = + this.popupDomElement && !this.popupDomElement.contains(e.target) + const isOutsideTriggerElement = + this.triggerDomElement && !this.triggerDomElement.contains(e.target) + + if (isOutsidePopupElement && isOutsideTriggerElement) { + this.state.open && this.trySetOpen(false, e, true) + } + }, + { + useCapture: true, + }, + ) + }) + } + } + + private getTriggerProps(triggerElement) { const triggerProps: any = {} const { on } = this.props @@ -324,7 +300,7 @@ export default class Popup extends AutoControlledComponent { + private getContentProps = (predefinedProps?) => { const contentProps: any = {} const { on } = this.props @@ -485,4 +461,24 @@ export default class Popup extends AutoControlledComponent { + const { mouseLeaveDelay } = this.props + + this.closeTimeoutId = setTimeout(() => { + this.trySetOpen(false, e) + }, mouseLeaveDelay) + } + + private close = (e, onClose?: Function) => { + if (this.state.open) { + this.trySetOpen(false, e, true) + onClose && onClose() + } + } } From da204e0b8bbfa00431b4f93160648bfc6d1533b7 Mon Sep 17 00:00:00 2001 From: Levi Thomason Date: Mon, 7 Jan 2019 11:02:32 -0800 Subject: [PATCH 21/23] docs: simplify popup usage examples --- .../Popup/Usage/PopupExampleOn.shorthand.tsx | 16 ++++++---------- .../Usage/PopupExampleOnMultiple.shorthand.tsx | 12 +++++------- .../PopupExampleOnWithFocusTrap.shorthand.tsx | 15 ++++++--------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx index 7b7eb01326..eed10f73f1 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOn.shorthand.tsx @@ -1,28 +1,24 @@ import * as React from 'react' -import { Button, Popup, Grid, Text } from '@stardust-ui/react' +import { Button, Popup } from '@stardust-ui/react' const PopupExampleOn = () => ( - - - - - +
} + trigger={
) export default PopupExampleOn diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx index d97a8b436d..81ed8cb157 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnMultiple.shorthand.tsx @@ -1,21 +1,19 @@ import * as React from 'react' -import { Button, Popup, Grid, Text } from '@stardust-ui/react' +import { Button, Popup } from '@stardust-ui/react' const PopupExampleOnMultiple = () => ( - - - +
} + trigger={
) export default PopupExampleOnMultiple diff --git a/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx b/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx index 67f3f8209c..10c55693d4 100644 --- a/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx +++ b/docs/src/examples/components/Popup/Usage/PopupExampleOnWithFocusTrap.shorthand.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Button, Popup, Grid, Text, popupFocusTrapBehavior } from '@stardust-ui/react' +import { Button, Popup, popupFocusTrapBehavior } from '@stardust-ui/react' const contentWithButtons = { content: ( @@ -11,29 +11,26 @@ const contentWithButtons = { } const PopupExampleOnWithFocusTrap = () => ( - - - - +
} + trigger={
) export default PopupExampleOnWithFocusTrap From efd9d5290768eb69125f20c90980004bfd2d9ad5 Mon Sep 17 00:00:00 2001 From: manajdov Date: Tue, 8 Jan 2019 09:46:23 +0100 Subject: [PATCH 22/23] -fix focus + click opening --- src/components/Popup/Popup.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index 5c73a21fa6..eef2ea94ab 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -14,6 +14,7 @@ import { ContentComponentProps, StyledComponentProps, commonPropTypes, + isFromKeyboard, } from '../../lib' import { ComponentEventHandler, ReactProps, ShorthandValue } from '../../../types/utils' @@ -248,7 +249,9 @@ export default class Popup extends AutoControlledComponent { - this.trySetOpen(true, e) + if (isFromKeyboard()) { + this.trySetOpen(true, e) + } _.invoke(triggerElement, 'props.onFocus', e, ...rest) } triggerProps.onBlur = (e, ...rest) => { From 8fa0a2c5ef989732213ed1c3604197ebd9668757 Mon Sep 17 00:00:00 2001 From: manajdov Date: Tue, 8 Jan 2019 10:00:48 +0100 Subject: [PATCH 23/23] -fixed changelog after merging master --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe3f7c7206..8481b4041b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Features +- Add `on` and `mouseLeaveDelay` props to `Popup` component @mnajdova ([#622](https://github.com/stardust-ui/react/pull/622)) + ## [v0.16.0](https://github.com/stardust-ui/react/tree/v0.16.0) (2019-01-07) [Compare changes](https://github.com/stardust-ui/react/compare/v0.15.0...v0.16.0) @@ -50,7 +53,6 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Add `color` prop to `Icon` component @Bugaa92 ([#651](https://github.com/stardust-ui/react/pull/651)) - Create a `base` theme with Text component example @almedint ([#618](https://github.com/stardust-ui/react/pull/618)) - Adding attachment behavior to handle space/enter key @kolaps33 ([#375](https://github.com/stardust-ui/react/pull/375)) -- Add `on` and `mouseLeaveDelay` props to `Popup` component @mnajdova ([#622](https://github.com/stardust-ui/react/pull/622)) ### Documentation - Add more accessibility descriptions to components and behaviors @jurokapsiar ([#648](https://github.com/stardust-ui/react/pull/648))