UNPKG

5.17 kBSource Map (JSON)View Raw
1{"version":3,"file":"FocusVisible.js","sources":["../src/components/FocusVisible/FocusVisible.js"],"sourcesContent":["import React from 'react'\nimport PropTypes from 'prop-types'\n\n// Implements a behavior similar to :focus-visible for browsers that are not\n// supporting it yet.\n//\n// It follows the Chrome implementation, checking for a pointer device rather\n// than a keyboard event.\n//\n// Resources:\n// - https://caniuse.com/#search=%3Afocus-visible\n// - https://github.com/WICG/focus-visible/issues/88#issuecomment-363227219\n// - https://chromium-review.googlesource.com/c/chromium/src/+/897002<Paste>\n//\nclass FocusVisible extends React.Component {\n static propTypes = {\n // children is called with an object containing two entries:\n // - focusVisible represents the visibility of the focus (boolean).\n // - onFocus() need to be called when the target element is focused.\n children: PropTypes.func.isRequired,\n }\n _element = React.createRef()\n _document = null\n state = {\n focusVisible: false,\n }\n componentDidMount() {\n // `document` was previously set as a state entry, which was having the\n // advantages of keeping track of it, and also triggering a rerender to\n // remove the injected span.\n //\n // The issue with this approach is that the component can get unmounted\n // before the state gets updated (e.g. in case of an error in the tree),\n // preventing to remove the event listeners.\n //\n // this._document is now set on the instance directly, and\n // this.forceUpdate() is used to trigger the second render needed to remove\n // the injected span.\n this._document = this._element.current.ownerDocument\n this._document.addEventListener('mousedown', this.handlePointerEvent)\n this._document.addEventListener('mouseup', this.handlePointerEvent)\n this._document.addEventListener('touchstart', this.handlePointerEvent)\n this._document.addEventListener('touchend', this.handlePointerEvent)\n this.forceUpdate()\n }\n componentWillUnmount() {\n if (this._document) {\n this._document.removeEventListener('mousedown', this.handlePointerEvent)\n this._document.removeEventListener('mouseup', this.handlePointerEvent)\n this._document.removeEventListener('touchstart', this.handlePointerEvent)\n this._document.removeEventListener('touchend', this.handlePointerEvent)\n }\n }\n // It doesn’t seem to be specified, but pointer-related events happen before\n // the focus-related events on every modern browser.\n handlePointerEvent = e => {\n this._pointerActive = true\n this._timer = setTimeout(() => {\n this._pointerActive = false\n }, 0)\n if (this.state.focusVisible) {\n this.setState({ focusVisible: false })\n }\n }\n // This is passed to `children()`, and called from the outside.\n handleFocus = () => {\n this.setState({ focusVisible: !this._pointerActive })\n }\n render() {\n const { focusVisible } = this.state\n return (\n <React.Fragment>\n {this.props.children({ focusVisible, onFocus: this.handleFocus })}\n {!this._document && <span ref={this._element} />}\n </React.Fragment>\n )\n }\n}\n\nexport default FocusVisible\n"],"names":["FocusVisible","React","createRef","focusVisible","e","_pointerActive","_timer","setTimeout","state","setState","_document","_element","current","ownerDocument","addEventListener","handlePointerEvent","forceUpdate","removeEventListener","props","children","onFocus","handleFocus","Component","PropTypes","func","isRequired"],"mappings":";;;;;;;;;;;;;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IACMA;;;;;;;;;;;;;;;;6FAOOC,cAAK,CAACC,SAAN;;8FACC;;0FACJ;AACNC,MAAAA,YAAY,EAAE;AADR;;uGAgCa,UAAAC,CAAC,EAAI;AACxB,YAAKC,cAAL,GAAsB,IAAtB;AACA,YAAKC,MAAL,GAAcC,UAAU,CAAC,YAAM;AAC7B,cAAKF,cAAL,GAAsB,KAAtB;AACD,OAFuB,EAErB,CAFqB,CAAxB;;AAGA,UAAI,MAAKG,KAAL,CAAWL,YAAf,EAA6B;AAC3B,cAAKM,QAAL,CAAc;AAAEN,UAAAA,YAAY,EAAE;AAAhB,SAAd;AACD;AACF;;gGAEa,YAAM;AAClB,YAAKM,QAAL,CAAc;AAAEN,QAAAA,YAAY,EAAE,CAAC,MAAKE;AAAtB,OAAd;AACD;;;;;;;wCAzCmB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAKK,SAAL,GAAiB,KAAKC,QAAL,CAAcC,OAAd,CAAsBC,aAAvC;;AACA,WAAKH,SAAL,CAAeI,gBAAf,CAAgC,WAAhC,EAA6C,KAAKC,kBAAlD;;AACA,WAAKL,SAAL,CAAeI,gBAAf,CAAgC,SAAhC,EAA2C,KAAKC,kBAAhD;;AACA,WAAKL,SAAL,CAAeI,gBAAf,CAAgC,YAAhC,EAA8C,KAAKC,kBAAnD;;AACA,WAAKL,SAAL,CAAeI,gBAAf,CAAgC,UAAhC,EAA4C,KAAKC,kBAAjD;;AACA,WAAKC,WAAL;AACD;;;2CACsB;AACrB,UAAI,KAAKN,SAAT,EAAoB;AAClB,aAAKA,SAAL,CAAeO,mBAAf,CAAmC,WAAnC,EAAgD,KAAKF,kBAArD;;AACA,aAAKL,SAAL,CAAeO,mBAAf,CAAmC,SAAnC,EAA8C,KAAKF,kBAAnD;;AACA,aAAKL,SAAL,CAAeO,mBAAf,CAAmC,YAAnC,EAAiD,KAAKF,kBAAtD;;AACA,aAAKL,SAAL,CAAeO,mBAAf,CAAmC,UAAnC,EAA+C,KAAKF,kBAApD;AACD;AACF;AAED;;;;6BAcS;AAAA,UACCZ,YADD,GACkB,KAAKK,KADvB,CACCL,YADD;AAEP,0BACEF,6BAACA,cAAD,CAAO,QAAP,QACG,KAAKiB,KAAL,CAAWC,QAAX,CAAoB;AAAEhB,QAAAA,YAAY,EAAZA,YAAF;AAAgBiB,QAAAA,OAAO,EAAE,KAAKC;AAA9B,OAApB,CADH,EAEG,CAAC,KAAKX,SAAN,iBAAmBT;AAAM,QAAA,GAAG,EAAE,KAAKU;AAAhB,QAFtB,CADF;AAMD;;;;EA9DwBV,cAAK,CAACqB;;+BAA3BtB,2BACe;AACjB;AACA;AACA;AACAmB,EAAAA,QAAQ,EAAEI,eAAS,CAACC,IAAV,CAAeC;AAJR;;;;"}
\No newline at end of file