From 361934df43fce40c0afdf9b38546e0f925c9c58d Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Wed, 17 Jun 2020 15:34:27 -0600 Subject: [PATCH 01/15] WIP: react-focus-on --- package.json | 2 +- src/components/focus_trap/focus_trap.tsx | 28 +++--- src/components/popover/popover.tsx | 4 +- yarn.lock | 106 ++++++++++++++++++----- 4 files changed, 104 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 64495011c554..95a72c9a8f4f 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "prop-types": "^15.6.0", "react-ace": "^7.0.5", "react-beautiful-dnd": "^13.0.0", - "react-focus-lock": "^1.17.7", + "react-focus-on": "^3.4.1", "react-input-autosize": "^2.2.2", "react-is": "~16.3.0", "react-virtualized": "^9.21.2", diff --git a/src/components/focus_trap/focus_trap.tsx b/src/components/focus_trap/focus_trap.tsx index 2ac49c293b12..918504e6a09b 100644 --- a/src/components/focus_trap/focus_trap.tsx +++ b/src/components/focus_trap/focus_trap.tsx @@ -24,7 +24,8 @@ import React, { EventHandler, CSSProperties, } from 'react'; -import FocusLock, { Props as ReactFocusLockProps } from 'react-focus-lock'; // eslint-disable-line import/named +import { FocusOn } from 'react-focus-on'; +import { ReactFocusOnProps } from 'react-focus-on/dist/es5/types'; import { CommonProps } from '../common'; import { EuiOutsideClickDetector } from '../outside_click_detector'; @@ -52,19 +53,23 @@ const OutsideEventDetector: FunctionComponent = ({ */ export type FocusTarget = HTMLElement | string | (() => HTMLElement); -interface EuiFocusTrapProps { +interface EuiFocusTrapInterface { clickOutsideDisables?: boolean; initialFocus?: FocusTarget; style?: CSSProperties; + disabled?: boolean; } -type Props = CommonProps & ReactFocusLockProps & EuiFocusTrapProps; +export interface EuiFocusTrapProps + extends CommonProps, + Omit, // Inverted `disabled` prop used instead + EuiFocusTrapInterface {} interface State { hasBeenDisabledByClick: boolean; } -export class EuiFocusTrap extends Component { +export class EuiFocusTrap extends Component { state: State = { hasBeenDisabledByClick: false, }; @@ -76,7 +81,7 @@ export class EuiFocusTrap extends Component { this.setInitialFocus(this.props.initialFocus); } - componentDidUpdate(prevProps: Props) { + componentDidUpdate(prevProps: EuiFocusTrapProps) { if (prevProps.disabled === true && this.props.disabled === false) { // eslint-disable-next-line react/no-did-update-set-state this.setState({ hasBeenDisabledByClick: false }); @@ -92,7 +97,7 @@ export class EuiFocusTrap extends Component { node = (initialFocus as () => HTMLElement)(); } if (!node) return; - // `data-autofocus` is part of the 'react-focus-lock' API + // `data-autofocus` is part of the 'react-focus-on' API node.setAttribute('data-autofocus', 'true'); }; @@ -137,13 +142,12 @@ export class EuiFocusTrap extends Component { clickOutsideDisables = false, disabled = false, returnFocus = true, - style, ...rest } = this.props; const isDisabled = disabled || this.state.hasBeenDisabledByClick; const lockProps = { - disabled: isDisabled, returnFocus, + enabled: !isDisabled, ...rest, }; return clickOutsideDisables ? ( @@ -151,15 +155,13 @@ export class EuiFocusTrap extends Component { isDisabled={isDisabled} onOutsideClick={this.handleOutsideClick}> - + {children} - + ) : ( - - {children} - + {children} ); } } diff --git a/src/components/popover/popover.tsx b/src/components/popover/popover.tsx index d67f8982af05..e96f718ddbf5 100644 --- a/src/components/popover/popover.tsx +++ b/src/components/popover/popover.tsx @@ -30,7 +30,7 @@ import tabbable from 'tabbable'; import { CommonProps, NoArgCallback } from '../common'; import { FocusTarget, EuiFocusTrap } from '../focus_trap'; -import { Props as ReactFocusLockProps } from 'react-focus-lock'; // eslint-disable-line import/named +import { ReactFocusOnProps } from 'react-focus-on/dist/es5/types'; import { cascadingMenuKeys, @@ -140,7 +140,7 @@ export interface EuiPopoverProps { /** * Function callback for when the focus trap is deactivated */ - onTrapDeactivation?: ReactFocusLockProps['onDeactivation']; + onTrapDeactivation?: ReactFocusOnProps['onDeactivation']; /** * Distance away from the anchor that the popover will render. diff --git a/yarn.lock b/yarn.lock index 53f2187a1503..ba18b9fd54d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1921,6 +1921,13 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-hidden@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.1.tgz#0c356026d3f65e2bd487a3adb73f0c586be2c37e" + integrity sha512-M7zYxCcOQPOaxGHoMTKUFD2UNcVFTp9ycrdStLcTPLf8zgTXC3+YcGe+UuzSh5X1BX/0/PtS8xTNy4xyH/6xtw== + dependencies: + tslib "^1.0.0" + aria-query@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" @@ -6447,10 +6454,10 @@ flush-write-stream@^1.0.0: inherits "^2.0.1" readable-stream "^2.0.4" -focus-lock@^0.5.2: - version "0.5.4" - resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.5.4.tgz#537644d61b9e90fd97075aa680b8add1de24e819" - integrity sha512-A9ngdb0NyI6UygBQ0eD+p8SpLWTkdEDn67I3EGUUcDUfxH694mLA/xBWwhWhoj/2YLtsv2EoQdAx9UOKs8d/ZQ== +focus-lock@^0.6.7: + version "0.6.8" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.6.8.tgz#61985fadfa92f02f2ee1d90bc738efaf7f3c9f46" + integrity sha512-vkHTluRCoq9FcsrldC0ulQHiyBYgVJB2CX53I8r0nTC6KnEij7Of0jpBspjt3/CuNb6fyoj3aOh9J2HgQUM0og== follow-redirects@1.5.10: version "1.5.10" @@ -6796,6 +6803,11 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-port@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" @@ -12962,13 +12974,12 @@ react-beautiful-dnd@^13.0.0: redux "^4.0.4" use-memo-one "^1.1.1" -react-clientside-effect@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.0.tgz#db823695f75e9616a5e4dd6d908e5ea627fb2516" - integrity sha512-cVIsGG7SNHsQsCP4+fw7KFUB0HiYiU8hbvL640XaLCbZ31aK8/lj0qOKJ2K+xRjuQz/IM4Q4qclI0aEqTtcXtA== +react-clientside-effect@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.2.tgz#6212fb0e07b204e714581dd51992603d1accc837" + integrity sha512-nRmoyxeok5PBO6ytPvSjKp9xwXg9xagoTK1mMjwnQxqM9Hd7MNPl+LS1bOSOe+CV2+4fnEquc7H/S8QD3q697A== dependencies: "@babel/runtime" "^7.0.0" - shallowequal "^1.1.0" react-docgen@^4.1.0: version "4.1.1" @@ -12993,15 +13004,29 @@ react-dom@^16.12.0: prop-types "^15.6.2" scheduler "^0.18.0" -react-focus-lock@^1.17.7: - version "1.17.7" - resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-1.17.7.tgz#ea7fd05d88d0e32833cad241f9333c124c35ba9a" - integrity sha512-zDCqkIhuuHCCmWzJghAz6EM6ROx8/sHhQJWjmO6oteQRHX+xTCE5FWIu3zLB5UiUa5eLd66tTh4Fs8YDp0G+6Q== +react-focus-lock@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.3.1.tgz#9d5d85899773609c7eefa4fc54fff6a0f5f2fc47" + integrity sha512-j15cWLPzH0gOmRrUg01C09Peu8qbcdVqr6Bjyfxj80cNZmH+idk/bNBYEDSmkAtwkXI+xEYWSmHYqtaQhZ8iUQ== dependencies: "@babel/runtime" "^7.0.0" - focus-lock "^0.5.2" + focus-lock "^0.6.7" prop-types "^15.6.2" - react-clientside-effect "^1.2.0" + react-clientside-effect "^1.2.2" + use-callback-ref "^1.2.1" + use-sidecar "^1.0.1" + +react-focus-on@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/react-focus-on/-/react-focus-on-3.4.1.tgz#e184f3c44185e341598c5d9d44b2987ad459b240" + integrity sha512-KGRIl0iAu+1k1dcX7eQCXF5ZR/nl+XyXN5Ukw/OY80vLaK2b6vDzNqnX0HdYbY5xSUhIRUvMWEzSsdEyPjvk/Q== + dependencies: + aria-hidden "^1.1.1" + react-focus-lock "^2.3.1" + react-remove-scroll "^2.3.0" + react-style-singleton "^2.1.0" + use-callback-ref "^1.2.3" + use-sidecar "^1.0.1" react-input-autosize@^2.2.2: version "2.2.2" @@ -13066,6 +13091,25 @@ react-redux@^7.1.1: prop-types "^15.7.2" react-is "^16.9.0" +react-remove-scroll-bar@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.1.0.tgz#edafe9b42a42c0dad9bdd10712772a1f9a39d7b9" + integrity sha512-5X5Y5YIPjIPrAoMJxf6Pfa7RLNGCgwZ95TdnVPgPuMftRfO8DaC7F4KP1b5eiO8hHbe7u+wZNDbYN5WUTpv7+g== + dependencies: + react-style-singleton "^2.1.0" + tslib "^1.0.0" + +react-remove-scroll@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.3.0.tgz#3af06fe2f7130500704b676cdef94452c08fe593" + integrity sha512-UqVimLeAe+5EHXKfsca081hAkzg3WuDmoT9cayjBegd6UZVhlTEchleNp9J4TMGkb/ftLve7ARB5Wph+HJ7A5g== + dependencies: + react-remove-scroll-bar "^2.1.0" + react-style-singleton "^2.1.0" + tslib "^1.0.0" + use-callback-ref "^1.2.3" + use-sidecar "^1.0.1" + react-router-dom@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" @@ -13100,6 +13144,15 @@ react-router@5.2.0, react-router@^5.2.0: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" +react-style-singleton@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.0.tgz#7396885332e9729957f9df51f08cadbfc164e1c4" + integrity sha512-DH4ED+YABC1dhvSDYGGreAHmfuTXj6+ezT3CmHoqIEfxNgEYfIMoOtmbRp42JsUst3IPqBTDL+8r4TF7EWhIHw== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^1.0.0" + react-test-renderer@^16.0.0-0: version "16.8.2" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.2.tgz#3ce0bf12aa211116612fda01a886d6163c9c459b" @@ -14381,11 +14434,6 @@ shallow-clone@^1.0.0: kind-of "^5.0.0" mixin-object "^2.0.1" -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -15610,6 +15658,11 @@ ts-debounce@^1.0.0: resolved "https://registry.yarnpkg.com/ts-debounce/-/ts-debounce-1.0.0.tgz#e433301744ba75fe25466f7f23e1382c646aae6a" integrity sha512-V+IzWj418IoqqxVJD6I0zjPtgIyvAJ8VyViqzcxZ0JRiJXsi5mCmy1yUKkWd2gUygT28a8JsVFCgqdrf2pLUHQ== +tslib@^1.0.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" + integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== + tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -15961,11 +16014,24 @@ url@^0.11.0, url@~0.11.0: punycode "1.3.2" querystring "0.2.0" +use-callback-ref@^1.2.1, use-callback-ref@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.4.tgz#d86d1577bfd0b955b6e04aaf5971025f406bea3c" + integrity sha512-rXpsyvOnqdScyied4Uglsp14qzag1JIemLeTWGKbwpotWht57hbP78aNT+Q4wdFKQfQibbUX4fb6Qb4y11aVOQ== + use-memo-one@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.1.tgz#39e6f08fe27e422a7d7b234b5f9056af313bd22c" integrity sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ== +use-sidecar@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.2.tgz#e72f582a75842f7de4ef8becd6235a4720ad8af6" + integrity sha512-287RZny6m5KNMTb/Kq9gmjafi7lQL0YHO1lYolU6+tY1h9+Z3uCtkJJ3OSOq3INwYf2hBryCcDh4520AhJibMA== + dependencies: + detect-node "^2.0.4" + tslib "^1.9.3" + use@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8" From 319ac9c9523f5de2262844620b4d24644e0d4c97 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Wed, 17 Jun 2020 15:34:58 -0600 Subject: [PATCH 02/15] WIP: fix GuideFullScreen --- src-docs/src/services/full_screen/full_screen.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src-docs/src/services/full_screen/full_screen.tsx b/src-docs/src/services/full_screen/full_screen.tsx index 67895ead2ef5..3356ff59f7e7 100644 --- a/src-docs/src/services/full_screen/full_screen.tsx +++ b/src-docs/src/services/full_screen/full_screen.tsx @@ -46,7 +46,11 @@ export const GuideFullScreen: FunctionComponent<{ {buttonText} - {fullScreen && {children(setFullScreen)}} + {fullScreen && ( + + {children(setFullScreen)} + + )} ); }; From 72af3a476889c5f05ef1f00dbe6148cb91943f17 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Mon, 6 Jul 2020 12:24:55 -0700 Subject: [PATCH 03/15] noIsolation; onClickOutside --- .../src/views/focus_trap/focus_trap_example.js | 6 ++++++ .../collapsible_nav/collapsible_nav.tsx | 5 ++++- src/components/focus_trap/focus_trap.tsx | 15 +++++++++------ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src-docs/src/views/focus_trap/focus_trap_example.js b/src-docs/src/views/focus_trap/focus_trap_example.js index 89de1fad48f5..e11a382be51d 100644 --- a/src-docs/src/views/focus_trap/focus_trap_example.js +++ b/src-docs/src/views/focus_trap/focus_trap_example.js @@ -47,6 +47,12 @@ export const FocusTrapExample = { Use clickOutsideDisables to disable the focus trap when the user clicks outside the trap.

+

+ Use noIsolation when allowing pointer events on + outside elements is needed. For instance, when used with an{' '} + EuiOverlayMask that has a click handler, set{' '} + noIsolation=true. +

), props: { EuiFocusTrap }, diff --git a/src/components/collapsible_nav/collapsible_nav.tsx b/src/components/collapsible_nav/collapsible_nav.tsx index c9b5f745d0e5..8fbf30f1f745 100644 --- a/src/components/collapsible_nav/collapsible_nav.tsx +++ b/src/components/collapsible_nav/collapsible_nav.tsx @@ -193,7 +193,10 @@ export const EuiCollapsibleNav: FunctionComponent = ({ {optionalOverlay} {/* Trap focus only when docked={false} */} - +