diff --git a/packages/dnb-ui-lib/src/components/modal/Modal.js b/packages/dnb-ui-lib/src/components/modal/Modal.js index e7a42a5691c..7dc175a1bb4 100644 --- a/packages/dnb-ui-lib/src/components/modal/Modal.js +++ b/packages/dnb-ui-lib/src/components/modal/Modal.js @@ -492,9 +492,6 @@ class ModalContent extends PureComponent { this._id = props.content_id || makeUniqueId() } componentDidMount() { - // since touch devices works diffrent, and we also use preventScreenReaderPossibility - // we dont set the tabindex by using removeFocusPossibility - this.isTouchDevice = isTouchDevice() this.removeScrollPossibility() this.preventScreenReaderPossibility() this.removeFocusPossibility() @@ -555,7 +552,9 @@ class ModalContent extends PureComponent { } removeFocusPossibility() { - if (typeof document === 'undefined' || this.isTouchDevice) { + // since touch devices works diffrent, and we also use preventScreenReaderPossibility + // we dont set the tabindex by using removeFocusPossibility + if (typeof document === 'undefined' || isTouchDevice()) { return } const modalNodes = Array.from( @@ -588,7 +587,9 @@ class ModalContent extends PureComponent { } revertFocusPossibility() { - if (!this.nonModalNodes || this.isTouchDevice) { + // since touch devices works diffrent, and we also use preventScreenReaderPossibility + // we dont set the tabindex by using removeFocusPossibility + if (!this.nonModalNodes || isTouchDevice()) { return } // restore or remove tabindex from nodes diff --git a/packages/dnb-ui-lib/src/components/slider/Slider.js b/packages/dnb-ui-lib/src/components/slider/Slider.js index 7848d432187..d042cbe1a8e 100644 --- a/packages/dnb-ui-lib/src/components/slider/Slider.js +++ b/packages/dnb-ui-lib/src/components/slider/Slider.js @@ -174,7 +174,6 @@ export default class Slider extends PureComponent { super(props) this._id = props.id || makeUniqueId() // cause we need an id anyway this._trackRef = React.createRef() - this.isTouch = isTouchDevice() this.state = { _listenForPropChanges: true, value: Slider.getValue(props) // so on_state_update not gets called @@ -401,7 +400,7 @@ export default class Slider extends PureComponent { componentDidMount() { if ( - (this.isTouch || isTrue(this.props.use_scrollwheel)) && + (isTouchDevice() || isTrue(this.props.use_scrollwheel)) && this._trackRef.current ) { this._trackRef.current.addEventListener( @@ -545,18 +544,18 @@ export default class Slider extends PureComponent { if (label) { rangeParams['aria-labelledby'] = id + '-label' - if (this.isTouch) { + if (isTouchDevice()) { trackParams['aria-labelledby'] = id + '-label' } } if (showStatus) { rangeParams['aria-describedby'] = id + '-status' - if (this.isTouch) { + if (isTouchDevice()) { trackParams['aria-describedby'] = id + '-status' } } - if (this.isTouch) { + if (isTouchDevice()) { trackParams.role = 'slider' trackParams['aria-valuenow'] = this.roundValue(value) trackParams['aria-valuemin'] = min @@ -623,7 +622,7 @@ export default class Slider extends PureComponent { style={inlineThumbStyles} > {/* Keep the possibility open to use a native slider inside */} - {!this.isTouch && ( + {!isTouchDevice() && ( diff --git a/packages/dnb-ui-lib/src/shared/component-helper.js b/packages/dnb-ui-lib/src/shared/component-helper.js index 3bc4975a845..3df87d0c508 100644 --- a/packages/dnb-ui-lib/src/shared/component-helper.js +++ b/packages/dnb-ui-lib/src/shared/component-helper.js @@ -32,11 +32,89 @@ export const isMac = () => * Check if device is touch device or not */ +let IS_TOUCH_DEVICE = undefined export function isTouchDevice() { - if (typeof isTouchDevice.result !== 'undefined') { - return isTouchDevice.result + if (typeof IS_TOUCH_DEVICE !== 'undefined') { + if (typeof window !== 'undefined') { + window.IS_TOUCH_DEVICE = IS_TOUCH_DEVICE + } + return IS_TOUCH_DEVICE } - let result = undefined + + return IS_TOUCH_DEVICE +} + +/** + * Detects if device supports touches + * + * @param {[type]} [interactive=true}] [Makes it posible that the state changes interactive] + * @return {[type]} [void] + */ +export function defineIsTouch({ interactive = true } = {}) { + const handleDefineTouch = () => { + if (typeof document === 'undefined' || typeof window === 'undefined') { + return + } + + // to give it a change to have isTouch from the very beginning + if (unsafeIsTouchDeviceCheck()) { + document.documentElement.setAttribute('data-is-touch', true) + } + + window.addEventListener( + 'touchstart', + function onFirstTouch() { + try { + if (IS_TOUCH_DEVICE !== true) { + document.documentElement.setAttribute('data-is-touch', true) + } + IS_TOUCH_DEVICE = true + } catch (e) { + console.warn('Could not apply "touch attribute"', e) + } + if (!interactive) { + window.removeEventListener('touchstart', onFirstTouch, false) + } + }, + false + ) + + window.addEventListener( + 'mouseover', + function onFirstHover() { + try { + if (IS_TOUCH_DEVICE === true) { + document.documentElement.removeAttribute('data-is-touch') + } + IS_TOUCH_DEVICE = false + } catch (e) { + console.warn('Could not apply "touch attribute"', e) + } + if (!interactive) { + window.removeEventListener('mouseover', onFirstHover, false) + } + }, + false + ) + + document.removeEventListener('DOMContentLoaded', handleDefineTouch) + } + + if ( + typeof document !== 'undefined' && + document.readyState === 'loading' + ) { + document.addEventListener('DOMContentLoaded', handleDefineTouch) + } else { + handleDefineTouch() + } +} + +function unsafeIsTouchDeviceCheck() { + if (typeof document === 'undefined' || typeof window === 'undefined') { + return false + } + let result = false try { if (window.PointerEvent && 'maxTouchPoints' in navigator) { @@ -61,32 +139,7 @@ export function isTouchDevice() { result = false } - return (isTouchDevice.result = result) -} - -export function defineIsTouch() { - const handleDefineTouch = () => { - if (typeof document === 'undefined' || typeof window === 'undefined') - return - try { - if (isTouchDevice()) { - document.documentElement.setAttribute('data-is-touch', true) - } - } catch (e) { - console.warn('Could not apply "touch attribute"', e) - } - - document.removeEventListener('DOMContentLoaded', handleDefineTouch) - } - - if ( - typeof document !== 'undefined' && - document.readyState === 'loading' - ) { - document.addEventListener('DOMContentLoaded', handleDefineTouch) - } else { - handleDefineTouch() - } + return result } export function defineNavigator() {