@instructure/ui-dom-utils 10.26.1-snapshot-1 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -2
- package/es/findDOMNode.js +41 -15
- package/es/findFocusable.js +6 -5
- package/es/{getComputedStyle.js → getCSSStyleDeclaration.js} +11 -7
- package/es/getFontSize.js +2 -2
- package/es/getOffsetParents.js +2 -2
- package/es/getScrollParents.js +4 -4
- package/es/index.js +1 -1
- package/es/isVisible.js +6 -6
- package/lib/findDOMNode.js +40 -15
- package/lib/findFocusable.js +5 -4
- package/lib/{getComputedStyle.js → getCSSStyleDeclaration.js} +11 -7
- package/lib/getFontSize.js +2 -2
- package/lib/getOffsetParents.js +2 -2
- package/lib/getScrollParents.js +4 -4
- package/lib/index.js +5 -5
- package/lib/isVisible.js +6 -6
- package/package.json +7 -7
- package/src/findDOMNode.ts +48 -34
- package/src/findFocusable.ts +10 -11
- package/src/{getComputedStyle.ts → getCSSStyleDeclaration.ts} +14 -8
- package/src/getFontSize.ts +2 -2
- package/src/getOffsetParents.ts +2 -2
- package/src/getScrollParents.ts +4 -4
- package/src/index.ts +1 -1
- package/src/isVisible.ts +10 -8
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/findDOMNode.d.ts +11 -3
- package/types/findDOMNode.d.ts.map +1 -1
- package/types/findFocusable.d.ts.map +1 -1
- package/types/{getComputedStyle.d.ts → getCSSStyleDeclaration.d.ts} +6 -6
- package/types/getCSSStyleDeclaration.d.ts.map +1 -0
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/isVisible.d.ts.map +1 -1
- package/types/getComputedStyle.d.ts.map +0 -1
package/src/findDOMNode.ts
CHANGED
|
@@ -22,34 +22,42 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import ReactDOM from 'react-dom'
|
|
26
|
-
import type { ReactInstance, RefObject } from 'react'
|
|
27
25
|
import type { UIElement } from '@instructure/shared-types'
|
|
28
|
-
|
|
29
|
-
ref: RefObject<Element | ReactInstance> | Element | ReactInstance
|
|
30
|
-
}
|
|
31
|
-
type CustomRefNode =
|
|
32
|
-
| ReactNodeWithRef
|
|
33
|
-
| RefObject<Element>
|
|
34
|
-
| Element
|
|
35
|
-
| ReactInstance
|
|
26
|
+
import ReactDOM from 'react-dom'
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Return the ref of an element in a way that is compatible both with
|
|
30
|
+
* React 18 (element.ref) and React 19+ (element.props.ref)
|
|
31
|
+
*/
|
|
32
|
+
function getElementRef(elem: { ref?: any; props?: { ref: any } }) {
|
|
33
|
+
// Note that this is added by InstUI components like Position
|
|
34
|
+
if (elem.ref) {
|
|
35
|
+
return elem.ref
|
|
36
|
+
}
|
|
37
|
+
// note that trying to access this will display a warning in React 18.
|
|
38
|
+
// this is OK because without it React itself would show an error because
|
|
39
|
+
// its using findDOMNode
|
|
40
|
+
return elem?.props?.ref
|
|
42
41
|
}
|
|
42
|
+
|
|
43
43
|
/**
|
|
44
44
|
* ---
|
|
45
45
|
* category: utilities/DOM
|
|
46
46
|
* ---
|
|
47
47
|
*
|
|
48
|
-
*
|
|
48
|
+
* Returns the underlying DOM node. It looks the following places:
|
|
49
|
+
* - If it's a native HTML element e.g. `HtmlSpanElement` its returned as is.
|
|
50
|
+
* - If the element has a non-nullish `ref` prop or instance variable which is a
|
|
51
|
+
* `HTMLElement` its returned. If it`s something else then `findDOMNode` is called
|
|
52
|
+
* on the object. (it also checks `ref.current`)
|
|
53
|
+
* - If the element has a `ref` prop or instance variable whose value is `null`,
|
|
54
|
+
* `undefined` is returned.
|
|
55
|
+
* - If the element does not have a `ref` prop or instance variable `undefined`
|
|
56
|
+
* is returned with a warning
|
|
49
57
|
* @module findDOMNode
|
|
50
58
|
*
|
|
51
|
-
* @param
|
|
52
|
-
* @returns
|
|
59
|
+
* @param el - component, DOM node, or function returning a DOM node
|
|
60
|
+
* @returns The native DOM node of this element or `undefined`
|
|
53
61
|
*/
|
|
54
62
|
function findDOMNode(el?: UIElement): Element | Node | Window | undefined {
|
|
55
63
|
const node = typeof el === 'function' ? el() : el
|
|
@@ -63,27 +71,33 @@ function findDOMNode(el?: UIElement): Element | Node | Window | undefined {
|
|
|
63
71
|
) {
|
|
64
72
|
return node as Node | Window
|
|
65
73
|
} else if (node) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
const refElement = isRefObject(reactNode.ref)
|
|
70
|
-
? reactNode.ref.current
|
|
71
|
-
: reactNode.ref
|
|
74
|
+
const ref = getElementRef(node as object)
|
|
75
|
+
const refElement = ref?.current ? ref.current : ref
|
|
76
|
+
if (refElement) {
|
|
72
77
|
if (!(refElement instanceof HTMLElement)) {
|
|
73
78
|
return findDOMNode(refElement)
|
|
74
79
|
}
|
|
75
80
|
return refElement
|
|
76
|
-
} else {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
} else if (refElement === null) {
|
|
82
|
+
// weird, but changing it would be a breaking change
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
const elName = (node as any).constructor.componentId
|
|
86
|
+
? (node as any).constructor.componentId
|
|
87
|
+
: (node as any).constructor.name
|
|
88
|
+
console.error(
|
|
89
|
+
`findDOMNode error: ${elName} doesn't have "ref" property.\n
|
|
90
|
+
your code will likely not work with React 19+, because ReactDOM.findDOMNode() was removed.\n
|
|
91
|
+
See more here: https://instructure.design/#accessing-the-dom`
|
|
92
|
+
)
|
|
93
|
+
// TODO remove when we only support React 19 or greater
|
|
94
|
+
const ReactDomInstance = ReactDOM as {
|
|
95
|
+
findDOMNode?: (arg: unknown) => Element
|
|
96
|
+
}
|
|
97
|
+
if (typeof ReactDomInstance.findDOMNode === 'function') {
|
|
98
|
+
return ReactDomInstance.findDOMNode(node)
|
|
86
99
|
}
|
|
100
|
+
return undefined
|
|
87
101
|
}
|
|
88
102
|
return undefined
|
|
89
103
|
}
|
package/src/findFocusable.ts
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
// or even better use the native <dialog> component.
|
|
38
38
|
// tabbable has issues with scrollable containers, e.g.
|
|
39
39
|
// https://github.com/focus-trap/tabbable/issues/167
|
|
40
|
-
import {
|
|
40
|
+
import { getCSSStyleDeclaration, findDOMNode } from './'
|
|
41
41
|
import type { UIElement } from '@instructure/shared-types'
|
|
42
42
|
|
|
43
43
|
const focusableSelector = [
|
|
@@ -103,8 +103,8 @@ function findFocusable(
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
function hidden(element: Element | Node) {
|
|
106
|
-
const cs =
|
|
107
|
-
return cs
|
|
106
|
+
const cs = getCSSStyleDeclaration(element)
|
|
107
|
+
return cs?.display === 'none'
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
function positioned(element: Element | Node) {
|
|
@@ -112,11 +112,12 @@ function positioned(element: Element | Node) {
|
|
|
112
112
|
if (POS.includes((element as HTMLElement).style.position?.toLowerCase())) {
|
|
113
113
|
return true
|
|
114
114
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
)
|
|
119
|
-
|
|
115
|
+
|
|
116
|
+
const position = getCSSStyleDeclaration(element)
|
|
117
|
+
?.getPropertyValue('position')
|
|
118
|
+
?.toLowerCase()
|
|
119
|
+
|
|
120
|
+
if (position && POS.includes(position)) {
|
|
120
121
|
return true
|
|
121
122
|
}
|
|
122
123
|
return false
|
|
@@ -140,6 +141,4 @@ function focusable(element: Element & { disabled?: boolean }) {
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
export default findFocusable
|
|
143
|
-
export {
|
|
144
|
-
findFocusable
|
|
145
|
-
}
|
|
144
|
+
export { findFocusable }
|
|
@@ -34,23 +34,29 @@ import type { UIElement } from '@instructure/shared-types'
|
|
|
34
34
|
*
|
|
35
35
|
* Get the associated CSS properties and values for a
|
|
36
36
|
* specified element
|
|
37
|
-
* @module
|
|
37
|
+
* @module getCSSStyleDeclaration
|
|
38
38
|
*
|
|
39
39
|
* @param { Node | Window | React.ReactElement | React.Component | function } el - component or DOM node
|
|
40
40
|
* @param { string | null | undefined } pseudoElt - A string specifying the pseudo-element to match. Omitted (or null ) for real elements.
|
|
41
|
-
* @returns {
|
|
41
|
+
* @returns { CSSStyleDeclaration | undefined } The style declaration containing css properties and values for the element or undefined
|
|
42
42
|
*/
|
|
43
|
-
function
|
|
44
|
-
let style
|
|
43
|
+
function getCSSStyleDeclaration(el?: UIElement, pseudoElt?: string | null) {
|
|
44
|
+
let style: CSSStyleDeclaration | undefined
|
|
45
45
|
if (canUseDOM) {
|
|
46
46
|
const node = el && findDOMNode(el)
|
|
47
47
|
if (node) {
|
|
48
48
|
const window = ownerWindow(el)
|
|
49
|
-
|
|
49
|
+
try {
|
|
50
|
+
style = window
|
|
51
|
+
? window.getComputedStyle(node as Element, pseudoElt)
|
|
52
|
+
: undefined
|
|
53
|
+
} catch {
|
|
54
|
+
style = undefined
|
|
55
|
+
}
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
|
-
return style
|
|
58
|
+
return style
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
export default
|
|
56
|
-
export {
|
|
61
|
+
export default getCSSStyleDeclaration
|
|
62
|
+
export { getCSSStyleDeclaration }
|
package/src/getFontSize.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import { canUseDOM } from './canUseDOM'
|
|
25
25
|
import { ownerDocument } from './ownerDocument'
|
|
26
|
-
import {
|
|
26
|
+
import { getCSSStyleDeclaration } from './getCSSStyleDeclaration'
|
|
27
27
|
import React from 'react'
|
|
28
28
|
|
|
29
29
|
const COMPUTED_CACHE: WeakMap<any, number> = new WeakMap()
|
|
@@ -63,7 +63,7 @@ function getFontSize(
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
const fontSize = parseInt(
|
|
66
|
-
(
|
|
66
|
+
(getCSSStyleDeclaration(container) as CSSStyleDeclaration).getPropertyValue(
|
|
67
67
|
'font-size'
|
|
68
68
|
)
|
|
69
69
|
)
|
package/src/getOffsetParents.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
import { findDOMNode } from './findDOMNode'
|
|
26
26
|
import { canUseDOM } from './canUseDOM'
|
|
27
|
-
import {
|
|
27
|
+
import { getCSSStyleDeclaration } from './getCSSStyleDeclaration'
|
|
28
28
|
import { ownerDocument } from './ownerDocument'
|
|
29
29
|
import { UIElement } from '@instructure/shared-types'
|
|
30
30
|
|
|
@@ -59,7 +59,7 @@ function getOffsetParents(el?: UIElement) {
|
|
|
59
59
|
parent.nodeType === 1 &&
|
|
60
60
|
(parent as Element).tagName !== 'BODY'
|
|
61
61
|
) {
|
|
62
|
-
const style =
|
|
62
|
+
const style = getCSSStyleDeclaration(parent) as CSSStyleDeclaration
|
|
63
63
|
const transform =
|
|
64
64
|
style.getPropertyValue('-webkit-transform') ||
|
|
65
65
|
style.getPropertyValue('-moz-transform') ||
|
package/src/getScrollParents.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
import { findDOMNode } from './findDOMNode'
|
|
26
26
|
import { canUseDOM } from './canUseDOM'
|
|
27
|
-
import {
|
|
27
|
+
import { getCSSStyleDeclaration } from './getCSSStyleDeclaration'
|
|
28
28
|
import { UIElement } from '@instructure/shared-types'
|
|
29
29
|
|
|
30
30
|
/**
|
|
@@ -53,8 +53,8 @@ function getScrollParents(el?: UIElement) {
|
|
|
53
53
|
if (node) {
|
|
54
54
|
// In firefox if the element is inside an iframe with display: none; window.getComputedStyle() will return null;
|
|
55
55
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=548397
|
|
56
|
-
const computedStyle =
|
|
57
|
-
const position = computedStyle
|
|
56
|
+
const computedStyle = getCSSStyleDeclaration(node)
|
|
57
|
+
const position = computedStyle?.position
|
|
58
58
|
|
|
59
59
|
if (position === 'fixed') {
|
|
60
60
|
return [(node as Node).ownerDocument]
|
|
@@ -68,7 +68,7 @@ function getScrollParents(el?: UIElement) {
|
|
|
68
68
|
) {
|
|
69
69
|
let style
|
|
70
70
|
try {
|
|
71
|
-
style =
|
|
71
|
+
style = getCSSStyleDeclaration(parent)
|
|
72
72
|
} catch (err: any) {} // eslint-disable-line no-empty
|
|
73
73
|
|
|
74
74
|
if (typeof style === 'undefined' || style === null) {
|
package/src/index.ts
CHANGED
|
@@ -37,7 +37,7 @@ export { getActiveElement } from './getActiveElement'
|
|
|
37
37
|
export { getBoundingClientRect } from './getBoundingClientRect'
|
|
38
38
|
export type { RectType } from './getBoundingClientRect'
|
|
39
39
|
export { getClassList } from './getClassList'
|
|
40
|
-
export {
|
|
40
|
+
export { getCSSStyleDeclaration } from './getCSSStyleDeclaration'
|
|
41
41
|
export { getFontSize } from './getFontSize'
|
|
42
42
|
export { getOffsetParents } from './getOffsetParents'
|
|
43
43
|
export { getScrollParents } from './getScrollParents'
|
package/src/isVisible.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { findDOMNode } from './findDOMNode'
|
|
26
|
-
import {
|
|
26
|
+
import { getCSSStyleDeclaration } from './getCSSStyleDeclaration'
|
|
27
27
|
import { UIElement } from '@instructure/shared-types'
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -52,22 +52,24 @@ function isVisible(el?: UIElement, recursive = true): boolean {
|
|
|
52
52
|
return isVisible(parent, recursive)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const style = node
|
|
55
|
+
const style = node
|
|
56
|
+
? getCSSStyleDeclaration(node)
|
|
57
|
+
: ({} as CSSStyleDeclaration)
|
|
56
58
|
// physically and visually hidden
|
|
57
|
-
if (style
|
|
59
|
+
if (style?.display === 'none') {
|
|
58
60
|
return false
|
|
59
61
|
}
|
|
60
62
|
// visually hidden
|
|
61
|
-
if (style
|
|
63
|
+
if (style?.visibility === 'hidden' || style?.opacity === '0') {
|
|
62
64
|
return false
|
|
63
65
|
}
|
|
64
66
|
// hidden by clipping
|
|
65
67
|
if (
|
|
66
|
-
style
|
|
67
|
-
style
|
|
68
|
-
style
|
|
68
|
+
style?.overflow === 'hidden' &&
|
|
69
|
+
style?.position === 'absolute' &&
|
|
70
|
+
style?.clip !== 'auto'
|
|
69
71
|
) {
|
|
70
|
-
const rect = style
|
|
72
|
+
const rect = style?.clip.substring(5).slice(0, -1).split(', ')
|
|
71
73
|
let zeros = true
|
|
72
74
|
rect.forEach((a) => {
|
|
73
75
|
if (a !== '0px') {
|