@react-native-aria/overlays 0.3.5 → 0.3.7
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/lib/commonjs/web/overlays/src/calculatePosition.js +53 -16
- package/lib/commonjs/web/overlays/src/calculatePosition.js.map +1 -1
- package/lib/commonjs/web/overlays/src/useCloseOnScroll.js.map +1 -1
- package/lib/commonjs/web/overlays/src/useOverlayPosition.js +21 -1
- package/lib/commonjs/web/overlays/src/useOverlayPosition.js.map +1 -1
- package/lib/module/web/overlays/src/calculatePosition.js +52 -16
- package/lib/module/web/overlays/src/calculatePosition.js.map +1 -1
- package/lib/module/web/overlays/src/useCloseOnScroll.js.map +1 -1
- package/lib/module/web/overlays/src/useOverlayPosition.js +21 -1
- package/lib/module/web/overlays/src/useOverlayPosition.js.map +1 -1
- package/package.json +1 -1
- package/src/web/overlays/src/calculatePosition.ts +227 -85
- package/src/web/overlays/src/useCloseOnScroll.ts +5 -5
- package/src/web/overlays/src/useOverlayPosition.ts +24 -1
- package/yarn-error.log +0 -10007
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["useCloseOnScroll.ts"],"names":["useEffect","onCloseMap","WeakMap","useCloseOnScroll","opts","triggerRef","isOpen","onClose","onScroll","e","target","current","contains","onCloseHandler","get","window","addEventListener","removeEventListener"],"mappings":"AAAA;;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,
|
1
|
+
{"version":3,"sources":["useCloseOnScroll.ts"],"names":["useEffect","onCloseMap","WeakMap","useCloseOnScroll","opts","triggerRef","isOpen","onClose","onScroll","e","target","current","contains","onCloseHandler","get","window","addEventListener","removeEventListener"],"mappings":"AAAA;;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,SAAoBA,SAApB,QAAqC,OAArC,C,CAEA;AACA;AACA;AACA;AACA;;AACA,OAAO,MAAMC,UAA4C,GAAG,IAAIC,OAAJ,EAArD;;AAQP;AACA,OAAO,SAASC,gBAAT,CAA0BC,IAA1B,EAAsD;AAC3D,MAAI;AAAEC,IAAAA,UAAF;AAAcC,IAAAA,MAAd;AAAsBC,IAAAA;AAAtB,MAAkCH,IAAtC;AAEAJ,EAAAA,SAAS,CAAC,MAAM;AACd,QAAI,CAACM,MAAL,EAAa;AACX;AACD;;AAED,QAAIE,QAAQ,GAAIC,CAAD,IAAmB;AAChC;AACA,UAAIC,MAAM,GAAGD,CAAC,CAACC,MAAf;;AACA,UAAI,CAACL,UAAU,CAACM,OAAZ,IAAuB,CAACD,MAAM,CAACE,QAAP,CAAgBP,UAAU,CAACM,OAA3B,CAA5B,EAAiE;AAC/D;AACD;;AAED,UAAIE,cAAc,GAAGN,OAAO,IAAIN,UAAU,CAACa,GAAX,CAAeT,UAAU,CAACM,OAA1B,CAAhC;;AACA,UAAIE,cAAJ,EAAoB;AAClBA,QAAAA,cAAc;AACf;AACF,KAXD;;AAaAE,IAAAA,MAAM,CAACC,gBAAP,CAAwB,QAAxB,EAAkCR,QAAlC,EAA4C,IAA5C;AACA,WAAO,MAAM;AACXO,MAAAA,MAAM,CAACE,mBAAP,CAA2B,QAA3B,EAAqCT,QAArC,EAA+C,IAA/C;AACD,KAFD;AAGD,GAtBQ,EAsBN,CAACF,MAAD,EAASC,OAAT,EAAkBF,UAAlB,CAtBM,CAAT;AAuBD","sourcesContent":["//@ts-nocheck\n/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { RefObject, useEffect } from 'react';\n\n// This behavior moved from useOverlayTrigger to useOverlayPosition.\n// For backward compatibility, where useOverlayTrigger handled hiding the popover on close,\n// it sets a close function here mapped from the trigger element. This way we can avoid\n// forcing users to pass an onClose function to useOverlayPosition which could be considered\n// a breaking change.\nexport const onCloseMap: WeakMap<HTMLElement, () => void> = new WeakMap();\n\ninterface CloseOnScrollOptions {\n triggerRef: RefObject<HTMLElement>;\n isOpen?: boolean;\n onClose?: () => void;\n}\n\n/** @private */\nexport function useCloseOnScroll(opts: CloseOnScrollOptions) {\n let { triggerRef, isOpen, onClose } = opts;\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n let onScroll = (e: MouseEvent) => {\n // Ignore if scrolling an scrollable region outside the trigger's tree.\n let target = e.target as HTMLElement;\n if (!triggerRef.current || !target.contains(triggerRef.current)) {\n return;\n }\n\n let onCloseHandler = onClose || onCloseMap.get(triggerRef.current);\n if (onCloseHandler) {\n onCloseHandler();\n }\n };\n\n window.addEventListener('scroll', onScroll, true);\n return () => {\n window.removeEventListener('scroll', onScroll, true);\n };\n }, [isOpen, onClose, triggerRef]);\n}\n"]}
|
@@ -100,7 +100,27 @@ export function useOverlayPosition(props) {
|
|
100
100
|
triggerRef: targetRef,
|
101
101
|
isOpen,
|
102
102
|
onClose: onClose ? close : undefined
|
103
|
-
});
|
103
|
+
}); // useLayoutEffect(() => {
|
104
|
+
// const mutationObserver = new MutationObserver((mutations) => {
|
105
|
+
// updatePosition();
|
106
|
+
// mutations.forEach((mutation) => {
|
107
|
+
// // if (mutation.attributeName === 'style') {
|
108
|
+
// // const transform = mutation.target.style.transform;
|
109
|
+
// // if (transform) {
|
110
|
+
// // const match = transform.match(/scale\((.+)\)/);
|
111
|
+
// // if (match) {
|
112
|
+
// // const scale = parseFloat(match[1]);
|
113
|
+
// // console.log(`Scale: ${scale}`);
|
114
|
+
// // // updatePosition();
|
115
|
+
// // }
|
116
|
+
// // }
|
117
|
+
// // }
|
118
|
+
// });
|
119
|
+
// });
|
120
|
+
// mutationObserver.observe(overlayRef?.current, { attributes: true });
|
121
|
+
// return () => mutationObserver.disconnect();
|
122
|
+
// }, [overlayRef, updatePosition]);
|
123
|
+
|
104
124
|
return {
|
105
125
|
rendered: true,
|
106
126
|
overlayProps: {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["useOverlayPosition.ts"],"names":["calculatePosition","useCallback","useRef","useState","useCloseOnScroll","isRTL","useLayoutEffect","visualViewport","window","useOverlayPosition","props","direction","undefined","targetRef","overlayRef","scrollRef","placement","containerPadding","shouldFlip","boundaryElement","document","body","offset","crossOffset","shouldUpdatePosition","isOpen","shouldOverlapWithTrigger","onClose","position","setPosition","arrowOffsetLeft","arrowOffsetTop","maxHeight","deps","current","updatePosition","translateRTL","overlayNode","targetNode","scrollNode","padding","useResize","isResizing","timeout","onResize","clearTimeout","setTimeout","addEventListener","removeEventListener","close","triggerRef","rendered","overlayProps","style","zIndex","arrowProps","left","top","replace"],"mappings":"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","sourcesContent":["//@ts-nocheck\n/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { calculatePosition, PositionResult } from './calculatePosition';\nimport {\n HTMLAttributes,\n RefObject,\n useCallback,\n useRef,\n useState,\n} from 'react';\nimport { Placement, PlacementAxis, PositionProps } from '@react-types/overlays';\nimport { useCloseOnScroll } from './useCloseOnScroll';\nimport { isRTL, useLayoutEffect } from '@react-native-aria/utils';\n\ninterface AriaPositionProps extends PositionProps {\n /**\n * Element that that serves as the positioning boundary.\n * @default document.body\n */\n boundaryElement?: HTMLElement;\n /**\n * The ref for the element which the overlay positions itself with respect to.\n */\n targetRef: RefObject<HTMLElement>;\n /**\n * The ref for the overlay element.\n */\n overlayRef: RefObject<HTMLElement>;\n /**\n * A ref for the scrollable region within the overlay.\n * @default overlayRef\n */\n scrollRef?: RefObject<HTMLElement>;\n /**\n * Whether the overlay should update its position automatically.\n * @default true\n */\n shouldUpdatePosition?: boolean;\n /** Handler that is called when the overlay should close. */\n onClose?: () => void;\n /** Determines whether the overlay should overlap with the trigger */\n shouldOverlapWithTrigger?: boolean;\n}\n\ninterface PositionAria {\n /** Props for the overlay container element. */\n overlayProps: HTMLAttributes<Element>;\n /** Props for the overlay tip arrow if any. */\n arrowProps: HTMLAttributes<Element>;\n /** Placement of the overlay with respect to the overlay trigger. */\n placement: PlacementAxis;\n /** Updates the position of the overlay. */\n updatePosition(): void;\n}\n\n// @ts-ignore\nlet visualViewport = typeof window !== 'undefined' && window.visualViewport;\n\n/**\n * Handles positioning overlays like popovers and menus relative to a trigger\n * element, and updating the position when the window resizes.\n */\nexport function useOverlayPosition(props: AriaPositionProps): PositionAria {\n const direction = isRTL() ? 'rtl' : undefined;\n let {\n targetRef,\n overlayRef,\n scrollRef = overlayRef,\n placement = 'bottom' as Placement,\n containerPadding = 12,\n shouldFlip = true,\n boundaryElement = typeof document !== 'undefined' ? document.body : null,\n offset = 0,\n crossOffset = 0,\n shouldUpdatePosition = true,\n isOpen = true,\n shouldOverlapWithTrigger = false,\n onClose,\n } = props;\n let [position, setPosition] = useState<PositionResult>({\n position: {},\n arrowOffsetLeft: undefined,\n arrowOffsetTop: undefined,\n maxHeight: undefined,\n placement: undefined,\n });\n\n let deps = [\n shouldUpdatePosition,\n placement,\n overlayRef.current,\n targetRef.current,\n scrollRef.current,\n containerPadding,\n shouldFlip,\n boundaryElement,\n offset,\n crossOffset,\n isOpen,\n direction,\n shouldOverlapWithTrigger\n ];\n\n let updatePosition = useCallback(() => {\n if (\n shouldUpdatePosition === false ||\n !isOpen ||\n !overlayRef.current ||\n !targetRef.current ||\n !scrollRef.current ||\n !boundaryElement\n ) {\n return;\n }\n\n setPosition(\n calculatePosition({\n placement: translateRTL(placement, direction),\n overlayNode: overlayRef.current,\n targetNode: targetRef.current,\n scrollNode: scrollRef.current,\n padding: containerPadding,\n shouldFlip,\n boundaryElement,\n offset,\n crossOffset,\n shouldOverlapWithTrigger,\n })\n );\n }, deps);\n\n // Update position when anything changes\n useLayoutEffect(updatePosition, deps);\n\n // Update position on window resize\n useResize(updatePosition);\n\n // Reposition the overlay and do not close on scroll while the visual viewport is resizing.\n // This will ensure that overlays adjust their positioning when the iOS virtual keyboard appears.\n let isResizing = useRef(false);\n useLayoutEffect(() => {\n let timeout: NodeJS.Timeout;\n let onResize = () => {\n isResizing.current = true;\n clearTimeout(timeout);\n\n timeout = setTimeout(() => {\n isResizing.current = false;\n }, 500);\n\n updatePosition();\n };\n\n visualViewport?.addEventListener('resize', onResize);\n\n return () => {\n visualViewport?.removeEventListener('resize', onResize);\n };\n }, [updatePosition]);\n\n let close = useCallback(() => {\n if (!isResizing.current) {\n onClose();\n }\n }, [onClose, isResizing]);\n\n // When scrolling a parent scrollable region of the trigger (other than the body),\n // we hide the popover. Otherwise, its position would be incorrect.\n useCloseOnScroll({\n triggerRef: targetRef,\n isOpen,\n onClose: onClose ? close : undefined,\n });\n\n return {\n rendered: true,\n overlayProps: {\n style: {\n position: 'absolute',\n zIndex: 100000, // should match the z-index in ModalTrigger\n ...position.position,\n maxHeight: position.maxHeight,\n },\n },\n placement: position.placement,\n arrowProps: {\n style: {\n left: position.arrowOffsetLeft,\n top: position.arrowOffsetTop,\n },\n },\n updatePosition,\n };\n}\n\nfunction useResize(onResize) {\n useLayoutEffect(() => {\n window.addEventListener('resize', onResize, false);\n return () => {\n window.removeEventListener('resize', onResize, false);\n };\n }, [onResize]);\n}\n\nfunction translateRTL(position, direction) {\n if (direction === 'rtl') {\n return position.replace('start', 'right').replace('end', 'left');\n }\n return position.replace('start', 'left').replace('end', 'right');\n}\n"]}
|
1
|
+
{"version":3,"sources":["useOverlayPosition.ts"],"names":["calculatePosition","useCallback","useRef","useState","useCloseOnScroll","isRTL","useLayoutEffect","visualViewport","window","useOverlayPosition","props","direction","undefined","targetRef","overlayRef","scrollRef","placement","containerPadding","shouldFlip","boundaryElement","document","body","offset","crossOffset","shouldUpdatePosition","isOpen","shouldOverlapWithTrigger","onClose","position","setPosition","arrowOffsetLeft","arrowOffsetTop","maxHeight","deps","current","updatePosition","translateRTL","overlayNode","targetNode","scrollNode","padding","useResize","isResizing","timeout","onResize","clearTimeout","setTimeout","addEventListener","removeEventListener","close","triggerRef","rendered","overlayProps","style","zIndex","arrowProps","left","top","replace"],"mappings":"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","sourcesContent":["//@ts-nocheck\n/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { calculatePosition, PositionResult } from './calculatePosition';\nimport {\n HTMLAttributes,\n RefObject,\n useCallback,\n useRef,\n useState,\n} from 'react';\nimport { Placement, PlacementAxis, PositionProps } from '@react-types/overlays';\nimport { useCloseOnScroll } from './useCloseOnScroll';\nimport { isRTL, useLayoutEffect } from '@react-native-aria/utils';\n\ninterface AriaPositionProps extends PositionProps {\n /**\n * Element that that serves as the positioning boundary.\n * @default document.body\n */\n boundaryElement?: HTMLElement;\n /**\n * The ref for the element which the overlay positions itself with respect to.\n */\n targetRef: RefObject<HTMLElement>;\n /**\n * The ref for the overlay element.\n */\n overlayRef: RefObject<HTMLElement>;\n /**\n * A ref for the scrollable region within the overlay.\n * @default overlayRef\n */\n scrollRef?: RefObject<HTMLElement>;\n /**\n * Whether the overlay should update its position automatically.\n * @default true\n */\n shouldUpdatePosition?: boolean;\n /** Handler that is called when the overlay should close. */\n onClose?: () => void;\n /** Determines whether the overlay should overlap with the trigger */\n shouldOverlapWithTrigger?: boolean;\n}\n\ninterface PositionAria {\n /** Props for the overlay container element. */\n overlayProps: HTMLAttributes<Element>;\n /** Props for the overlay tip arrow if any. */\n arrowProps: HTMLAttributes<Element>;\n /** Placement of the overlay with respect to the overlay trigger. */\n placement: PlacementAxis;\n /** Updates the position of the overlay. */\n updatePosition(): void;\n}\n\n// @ts-ignore\nlet visualViewport = typeof window !== 'undefined' && window.visualViewport;\n\n/**\n * Handles positioning overlays like popovers and menus relative to a trigger\n * element, and updating the position when the window resizes.\n */\nexport function useOverlayPosition(props: AriaPositionProps): PositionAria {\n const direction = isRTL() ? 'rtl' : undefined;\n let {\n targetRef,\n overlayRef,\n scrollRef = overlayRef,\n placement = 'bottom' as Placement,\n containerPadding = 12,\n shouldFlip = true,\n boundaryElement = typeof document !== 'undefined' ? document.body : null,\n offset = 0,\n crossOffset = 0,\n shouldUpdatePosition = true,\n isOpen = true,\n shouldOverlapWithTrigger = false,\n onClose,\n } = props;\n let [position, setPosition] = useState<PositionResult>({\n position: {},\n arrowOffsetLeft: undefined,\n arrowOffsetTop: undefined,\n maxHeight: undefined,\n placement: undefined,\n });\n\n let deps = [\n shouldUpdatePosition,\n placement,\n overlayRef.current,\n targetRef.current,\n scrollRef.current,\n containerPadding,\n shouldFlip,\n boundaryElement,\n offset,\n crossOffset,\n isOpen,\n direction,\n shouldOverlapWithTrigger,\n ];\n\n let updatePosition = useCallback(() => {\n if (\n shouldUpdatePosition === false ||\n !isOpen ||\n !overlayRef.current ||\n !targetRef.current ||\n !scrollRef.current ||\n !boundaryElement\n ) {\n return;\n }\n\n setPosition(\n calculatePosition({\n placement: translateRTL(placement, direction),\n overlayNode: overlayRef.current,\n targetNode: targetRef.current,\n scrollNode: scrollRef.current,\n padding: containerPadding,\n shouldFlip,\n boundaryElement,\n offset,\n crossOffset,\n shouldOverlapWithTrigger,\n })\n );\n }, deps);\n\n // Update position when anything changes\n useLayoutEffect(updatePosition, deps);\n\n // Update position on window resize\n useResize(updatePosition);\n\n // Reposition the overlay and do not close on scroll while the visual viewport is resizing.\n // This will ensure that overlays adjust their positioning when the iOS virtual keyboard appears.\n let isResizing = useRef(false);\n useLayoutEffect(() => {\n let timeout: NodeJS.Timeout;\n let onResize = () => {\n isResizing.current = true;\n clearTimeout(timeout);\n\n timeout = setTimeout(() => {\n isResizing.current = false;\n }, 500);\n\n updatePosition();\n };\n\n visualViewport?.addEventListener('resize', onResize);\n\n return () => {\n visualViewport?.removeEventListener('resize', onResize);\n };\n }, [updatePosition]);\n\n let close = useCallback(() => {\n if (!isResizing.current) {\n onClose();\n }\n }, [onClose, isResizing]);\n\n // When scrolling a parent scrollable region of the trigger (other than the body),\n // we hide the popover. Otherwise, its position would be incorrect.\n useCloseOnScroll({\n triggerRef: targetRef,\n isOpen,\n onClose: onClose ? close : undefined,\n });\n\n // useLayoutEffect(() => {\n // const mutationObserver = new MutationObserver((mutations) => {\n // updatePosition();\n // mutations.forEach((mutation) => {\n // // if (mutation.attributeName === 'style') {\n // // const transform = mutation.target.style.transform;\n // // if (transform) {\n // // const match = transform.match(/scale\\((.+)\\)/);\n // // if (match) {\n // // const scale = parseFloat(match[1]);\n // // console.log(`Scale: ${scale}`);\n // // // updatePosition();\n // // }\n // // }\n // // }\n // });\n // });\n\n // mutationObserver.observe(overlayRef?.current, { attributes: true });\n\n // return () => mutationObserver.disconnect();\n // }, [overlayRef, updatePosition]);\n\n return {\n rendered: true,\n overlayProps: {\n style: {\n position: 'absolute',\n zIndex: 100000, // should match the z-index in ModalTrigger\n ...position.position,\n maxHeight: position.maxHeight,\n },\n },\n placement: position.placement,\n arrowProps: {\n style: {\n left: position.arrowOffsetLeft,\n top: position.arrowOffsetTop,\n },\n },\n updatePosition,\n };\n}\n\nfunction useResize(onResize) {\n useLayoutEffect(() => {\n window.addEventListener('resize', onResize, false);\n return () => {\n window.removeEventListener('resize', onResize, false);\n };\n }, [onResize]);\n}\n\nfunction translateRTL(position, direction) {\n if (direction === 'rtl') {\n return position.replace('start', 'right').replace('end', 'left');\n }\n return position.replace('start', 'left').replace('end', 'right');\n}\n"]}
|
package/package.json
CHANGED
@@ -11,88 +11,94 @@
|
|
11
11
|
* governing permissions and limitations under the License.
|
12
12
|
*/
|
13
13
|
|
14
|
-
import {
|
14
|
+
import {
|
15
|
+
Axis,
|
16
|
+
Placement,
|
17
|
+
PlacementAxis,
|
18
|
+
SizeAxis,
|
19
|
+
} from '@react-types/overlays';
|
15
20
|
import getCss from 'dom-helpers/css';
|
16
21
|
import getOffset from 'dom-helpers/offset';
|
17
22
|
import getPosition from 'dom-helpers/position';
|
18
23
|
import getScrollLeft from 'dom-helpers/scrollLeft';
|
19
24
|
import getScrollTop from 'dom-helpers/scrollTop';
|
20
25
|
import ownerDocument from 'dom-helpers/ownerDocument';
|
26
|
+
import getComputedStyle from 'dom-helpers/getComputedStyle';
|
21
27
|
|
22
28
|
interface Position {
|
23
|
-
top?: number
|
24
|
-
left?: number
|
25
|
-
bottom?: number
|
26
|
-
right?: number
|
29
|
+
top?: number;
|
30
|
+
left?: number;
|
31
|
+
bottom?: number;
|
32
|
+
right?: number;
|
27
33
|
}
|
28
34
|
|
29
35
|
interface Dimensions {
|
30
|
-
width: number
|
31
|
-
height: number
|
32
|
-
top: number
|
33
|
-
left: number
|
34
|
-
scroll: Position
|
36
|
+
width: number;
|
37
|
+
height: number;
|
38
|
+
top: number;
|
39
|
+
left: number;
|
40
|
+
scroll: Position;
|
35
41
|
}
|
36
42
|
|
37
43
|
interface ParsedPlacement {
|
38
|
-
placement: PlacementAxis
|
39
|
-
crossPlacement: PlacementAxis
|
40
|
-
axis: Axis
|
41
|
-
crossAxis: Axis
|
42
|
-
size: SizeAxis
|
43
|
-
crossSize: SizeAxis
|
44
|
+
placement: PlacementAxis;
|
45
|
+
crossPlacement: PlacementAxis;
|
46
|
+
axis: Axis;
|
47
|
+
crossAxis: Axis;
|
48
|
+
size: SizeAxis;
|
49
|
+
crossSize: SizeAxis;
|
44
50
|
}
|
45
51
|
|
46
52
|
interface Offset {
|
47
|
-
top: number
|
48
|
-
left: number
|
49
|
-
width: number
|
50
|
-
height: number
|
53
|
+
top: number;
|
54
|
+
left: number;
|
55
|
+
width: number;
|
56
|
+
height: number;
|
51
57
|
}
|
52
58
|
|
53
59
|
interface PositionOpts {
|
54
|
-
placement: Placement
|
55
|
-
targetNode: HTMLElement
|
56
|
-
overlayNode: HTMLElement
|
57
|
-
scrollNode: HTMLElement
|
58
|
-
padding: number
|
59
|
-
shouldFlip: boolean
|
60
|
-
boundaryElement: HTMLElement
|
61
|
-
offset: number
|
62
|
-
crossOffset: number
|
63
|
-
shouldOverlapWithTrigger: boolean
|
60
|
+
placement: Placement;
|
61
|
+
targetNode: HTMLElement;
|
62
|
+
overlayNode: HTMLElement;
|
63
|
+
scrollNode: HTMLElement;
|
64
|
+
padding: number;
|
65
|
+
shouldFlip: boolean;
|
66
|
+
boundaryElement: HTMLElement;
|
67
|
+
offset: number;
|
68
|
+
crossOffset: number;
|
69
|
+
shouldOverlapWithTrigger: boolean;
|
64
70
|
}
|
65
71
|
|
66
72
|
export interface PositionResult {
|
67
|
-
position?: Position
|
68
|
-
arrowOffsetLeft?: number
|
69
|
-
arrowOffsetTop?: number
|
70
|
-
maxHeight?: number
|
71
|
-
placement: PlacementAxis
|
73
|
+
position?: Position;
|
74
|
+
arrowOffsetLeft?: number;
|
75
|
+
arrowOffsetTop?: number;
|
76
|
+
maxHeight?: number;
|
77
|
+
placement: PlacementAxis;
|
72
78
|
}
|
73
79
|
|
74
80
|
const AXIS = {
|
75
81
|
top: 'top',
|
76
82
|
bottom: 'top',
|
77
83
|
left: 'left',
|
78
|
-
right: 'left'
|
84
|
+
right: 'left',
|
79
85
|
};
|
80
86
|
|
81
87
|
const FLIPPED_DIRECTION = {
|
82
88
|
top: 'bottom',
|
83
89
|
bottom: 'top',
|
84
90
|
left: 'right',
|
85
|
-
right: 'left'
|
91
|
+
right: 'left',
|
86
92
|
};
|
87
93
|
|
88
94
|
const CROSS_AXIS = {
|
89
95
|
top: 'left',
|
90
|
-
left: 'top'
|
96
|
+
left: 'top',
|
91
97
|
};
|
92
98
|
|
93
99
|
const AXIS_SIZE = {
|
94
100
|
top: 'height',
|
95
|
-
left: 'width'
|
101
|
+
left: 'width',
|
96
102
|
};
|
97
103
|
|
98
104
|
const PARSED_PLACEMENT_CACHE = {};
|
@@ -101,7 +107,10 @@ const PARSED_PLACEMENT_CACHE = {};
|
|
101
107
|
let visualViewport = typeof window !== 'undefined' && window.visualViewport;
|
102
108
|
|
103
109
|
function getContainerDimensions(containerNode: Element): Dimensions {
|
104
|
-
let width = 0,
|
110
|
+
let width = 0,
|
111
|
+
height = 0,
|
112
|
+
top = 0,
|
113
|
+
left = 0;
|
105
114
|
let scroll: Position = {};
|
106
115
|
|
107
116
|
if (containerNode.tagName === 'BODY') {
|
@@ -115,12 +124,12 @@ function getContainerDimensions(containerNode: Element): Dimensions {
|
|
115
124
|
getScrollLeft(ownerDocument(containerNode).documentElement) ||
|
116
125
|
getScrollLeft(containerNode);
|
117
126
|
} else {
|
118
|
-
({width, height, top, left} = getOffset(containerNode));
|
127
|
+
({ width, height, top, left } = getOffset(containerNode));
|
119
128
|
scroll.top = getScrollTop(containerNode);
|
120
129
|
scroll.left = getScrollLeft(containerNode);
|
121
130
|
}
|
122
131
|
|
123
|
-
return {width, height, scroll, top, left};
|
132
|
+
return { width, height, scroll, top, left };
|
124
133
|
}
|
125
134
|
|
126
135
|
function getScroll(node: HTMLElement): Offset {
|
@@ -128,7 +137,7 @@ function getScroll(node: HTMLElement): Offset {
|
|
128
137
|
top: node.scrollTop,
|
129
138
|
left: node.scrollLeft,
|
130
139
|
width: node.scrollWidth,
|
131
|
-
height: node.scrollHeight
|
140
|
+
height: node.scrollHeight,
|
132
141
|
};
|
133
142
|
}
|
134
143
|
|
@@ -160,7 +169,7 @@ function getMargins(node: HTMLElement): Position {
|
|
160
169
|
top: parseInt(style.marginTop, 10) || 0,
|
161
170
|
bottom: parseInt(style.marginBottom, 10) || 0,
|
162
171
|
left: parseInt(style.marginLeft, 10) || 0,
|
163
|
-
right: parseInt(style.marginRight, 10) || 0
|
172
|
+
right: parseInt(style.marginRight, 10) || 0,
|
164
173
|
};
|
165
174
|
}
|
166
175
|
|
@@ -179,7 +188,14 @@ function parsePlacement(input: Placement): ParsedPlacement {
|
|
179
188
|
|
180
189
|
let size = AXIS_SIZE[axis];
|
181
190
|
let crossSize = AXIS_SIZE[crossAxis];
|
182
|
-
PARSED_PLACEMENT_CACHE[input] = {
|
191
|
+
PARSED_PLACEMENT_CACHE[input] = {
|
192
|
+
placement,
|
193
|
+
crossPlacement,
|
194
|
+
axis,
|
195
|
+
crossAxis,
|
196
|
+
size,
|
197
|
+
crossSize,
|
198
|
+
};
|
183
199
|
return PARSED_PLACEMENT_CACHE[input];
|
184
200
|
}
|
185
201
|
|
@@ -193,32 +209,47 @@ function computePosition(
|
|
193
209
|
containerOffsetWithBoundary: Offset,
|
194
210
|
isContainerPositioned: boolean
|
195
211
|
) {
|
196
|
-
let {
|
212
|
+
let {
|
213
|
+
placement,
|
214
|
+
crossPlacement,
|
215
|
+
axis,
|
216
|
+
crossAxis,
|
217
|
+
size,
|
218
|
+
crossSize,
|
219
|
+
} = placementInfo;
|
197
220
|
let position: Position = {};
|
198
221
|
|
199
222
|
// button position
|
200
223
|
position[crossAxis] = childOffset[crossAxis];
|
224
|
+
|
201
225
|
if (crossPlacement === 'center') {
|
202
226
|
// + (button size / 2) - (overlay size / 2)
|
203
227
|
// at this point the overlay center should match the button center
|
204
|
-
position[crossAxis] +=
|
228
|
+
position[crossAxis] +=
|
229
|
+
(childOffset[crossSize] - overlaySize[crossSize]) / 2;
|
205
230
|
} else if (crossPlacement !== crossAxis) {
|
206
231
|
// + (button size) - (overlay size)
|
207
232
|
// at this point the overlay bottom should match the button bottom
|
208
|
-
position[crossAxis] +=
|
209
|
-
}/* else {
|
233
|
+
position[crossAxis] += childOffset[crossSize] - overlaySize[crossSize];
|
234
|
+
} /* else {
|
210
235
|
the overlay top should match the button top
|
211
236
|
} */
|
212
237
|
// add the crossOffset from props
|
213
238
|
position[crossAxis] += crossOffset;
|
214
239
|
|
215
|
-
// this is button center position - the overlay size + half of the button to align bottom of overlay with button center
|
216
|
-
let minViablePosition =
|
217
|
-
//
|
218
|
-
|
240
|
+
// // this is button center position - the overlay size + half of the button to align bottom of overlay with button center
|
241
|
+
// let minViablePosition =
|
242
|
+
// childOffset[crossAxis] +
|
243
|
+
// childOffset[crossSize] / 2 -
|
244
|
+
// overlaySize[crossSize];
|
245
|
+
// // this is button position of center, aligns top of overlay with button center
|
246
|
+
// let maxViablePosition = childOffset[crossAxis] + childOffset[crossSize] / 2;
|
219
247
|
|
220
|
-
// clamp it into the range of the min/max positions
|
221
|
-
position[crossAxis] = Math.min(
|
248
|
+
// // clamp it into the range of the min/max positions
|
249
|
+
// position[crossAxis] = Math.min(
|
250
|
+
// Math.max(minViablePosition, position[crossAxis]),
|
251
|
+
// maxViablePosition
|
252
|
+
// );
|
222
253
|
|
223
254
|
// Floor these so the position isn't placed on a partial pixel, only whole pixels. Shouldn't matter if it was floored or ceiled, so chose one.
|
224
255
|
if (placement === axis) {
|
@@ -226,8 +257,12 @@ function computePosition(
|
|
226
257
|
// height, as `bottom` will be relative to this height. But if the container is static,
|
227
258
|
// then it can only be the `document.body`, and `bottom` will be relative to _its_
|
228
259
|
// container, which should be as large as boundaryDimensions.
|
229
|
-
const containerHeight =
|
230
|
-
|
260
|
+
const containerHeight = isContainerPositioned
|
261
|
+
? containerOffsetWithBoundary[size]
|
262
|
+
: boundaryDimensions[size];
|
263
|
+
position[FLIPPED_DIRECTION[axis]] = Math.floor(
|
264
|
+
containerHeight - childOffset[axis] + offset
|
265
|
+
);
|
231
266
|
} else {
|
232
267
|
position[axis] = Math.floor(childOffset[axis] + childOffset[size] + offset);
|
233
268
|
}
|
@@ -244,17 +279,22 @@ function getMaxHeight(
|
|
244
279
|
padding: number
|
245
280
|
) {
|
246
281
|
return position.top != null
|
247
|
-
// We want the distance between the top of the overlay to the bottom of the boundary
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
282
|
+
? // We want the distance between the top of the overlay to the bottom of the boundary
|
283
|
+
Math.max(
|
284
|
+
0,
|
285
|
+
boundaryDimensions.height +
|
286
|
+
boundaryDimensions.top +
|
287
|
+
boundaryDimensions.scroll.top - // this is the bottom of the boundary
|
288
|
+
(containerOffsetWithBoundary.top + position.top) - // this is the top of the overlay
|
289
|
+
(margins.top + margins.bottom + padding) // save additional space for margin and padding
|
252
290
|
)
|
253
|
-
// We want the distance between the top of the trigger to the top of the boundary
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
291
|
+
: // We want the distance between the top of the trigger to the top of the boundary
|
292
|
+
Math.max(
|
293
|
+
0,
|
294
|
+
childOffset.top +
|
295
|
+
containerOffsetWithBoundary.top - // this is the top of the trigger
|
296
|
+
(boundaryDimensions.top + boundaryDimensions.scroll.top) - // this is the top of the boundary
|
297
|
+
(margins.top + margins.bottom + padding) // save additional space for margin and padding
|
258
298
|
);
|
259
299
|
}
|
260
300
|
|
@@ -266,12 +306,32 @@ function getAvailableSpace(
|
|
266
306
|
padding: number,
|
267
307
|
placementInfo: ParsedPlacement
|
268
308
|
) {
|
269
|
-
let {placement, axis, size} = placementInfo;
|
309
|
+
let { placement, axis, size } = placementInfo;
|
270
310
|
if (placement === axis) {
|
271
|
-
return Math.max(
|
311
|
+
return Math.max(
|
312
|
+
0,
|
313
|
+
childOffset[axis] -
|
314
|
+
boundaryDimensions[axis] -
|
315
|
+
boundaryDimensions.scroll[axis] +
|
316
|
+
containerOffsetWithBoundary[axis] -
|
317
|
+
margins[axis] -
|
318
|
+
margins[FLIPPED_DIRECTION[axis]] -
|
319
|
+
padding
|
320
|
+
);
|
272
321
|
}
|
273
322
|
|
274
|
-
return Math.max(
|
323
|
+
return Math.max(
|
324
|
+
0,
|
325
|
+
boundaryDimensions[size] +
|
326
|
+
boundaryDimensions[axis] +
|
327
|
+
boundaryDimensions.scroll[axis] -
|
328
|
+
containerOffsetWithBoundary[axis] -
|
329
|
+
childOffset[axis] -
|
330
|
+
childOffset[size] -
|
331
|
+
margins[axis] -
|
332
|
+
margins[FLIPPED_DIRECTION[axis]] -
|
333
|
+
padding
|
334
|
+
);
|
275
335
|
}
|
276
336
|
|
277
337
|
export function calculatePositionInternal(
|
@@ -290,8 +350,25 @@ export function calculatePositionInternal(
|
|
290
350
|
shouldOverlapWithTrigger: boolean
|
291
351
|
): PositionResult {
|
292
352
|
let placementInfo = parsePlacement(placementInput);
|
293
|
-
let {
|
294
|
-
|
353
|
+
let {
|
354
|
+
size,
|
355
|
+
crossAxis,
|
356
|
+
crossSize,
|
357
|
+
placement,
|
358
|
+
crossPlacement,
|
359
|
+
axis,
|
360
|
+
} = placementInfo;
|
361
|
+
let position = computePosition(
|
362
|
+
childOffset,
|
363
|
+
boundaryDimensions,
|
364
|
+
overlaySize,
|
365
|
+
placementInfo,
|
366
|
+
offset,
|
367
|
+
crossOffset,
|
368
|
+
containerOffsetWithBoundary,
|
369
|
+
isContainerPositioned
|
370
|
+
);
|
371
|
+
|
295
372
|
let normalizedOffset = offset;
|
296
373
|
let space = getAvailableSpace(
|
297
374
|
boundaryDimensions,
|
@@ -304,8 +381,19 @@ export function calculatePositionInternal(
|
|
304
381
|
|
305
382
|
// Check if the scroll size of the overlay is greater than the available space to determine if we need to flip
|
306
383
|
if (flip && scrollSize[size] > space) {
|
307
|
-
let flippedPlacementInfo = parsePlacement(
|
308
|
-
|
384
|
+
let flippedPlacementInfo = parsePlacement(
|
385
|
+
`${FLIPPED_DIRECTION[placement]} ${crossPlacement}` as Placement
|
386
|
+
);
|
387
|
+
let flippedPosition = computePosition(
|
388
|
+
childOffset,
|
389
|
+
boundaryDimensions,
|
390
|
+
overlaySize,
|
391
|
+
flippedPlacementInfo,
|
392
|
+
offset,
|
393
|
+
crossOffset,
|
394
|
+
containerOffsetWithBoundary,
|
395
|
+
isContainerPositioned
|
396
|
+
);
|
309
397
|
let flippedSpace = getAvailableSpace(
|
310
398
|
boundaryDimensions,
|
311
399
|
containerOffsetWithBoundary,
|
@@ -323,7 +411,13 @@ export function calculatePositionInternal(
|
|
323
411
|
}
|
324
412
|
}
|
325
413
|
|
326
|
-
let delta = getDelta(
|
414
|
+
let delta = getDelta(
|
415
|
+
crossAxis,
|
416
|
+
position[crossAxis],
|
417
|
+
overlaySize[crossSize],
|
418
|
+
boundaryDimensions,
|
419
|
+
padding
|
420
|
+
);
|
327
421
|
position[crossAxis] += delta;
|
328
422
|
|
329
423
|
let maxHeight = getMaxHeight(
|
@@ -337,15 +431,32 @@ export function calculatePositionInternal(
|
|
337
431
|
|
338
432
|
overlaySize.height = Math.min(overlaySize.height, maxHeight);
|
339
433
|
|
340
|
-
position = computePosition(
|
341
|
-
|
434
|
+
position = computePosition(
|
435
|
+
childOffset,
|
436
|
+
boundaryDimensions,
|
437
|
+
overlaySize,
|
438
|
+
placementInfo,
|
439
|
+
normalizedOffset,
|
440
|
+
crossOffset,
|
441
|
+
containerOffsetWithBoundary,
|
442
|
+
isContainerPositioned
|
443
|
+
);
|
444
|
+
delta = getDelta(
|
445
|
+
crossAxis,
|
446
|
+
position[crossAxis],
|
447
|
+
overlaySize[crossSize],
|
448
|
+
boundaryDimensions,
|
449
|
+
padding
|
450
|
+
);
|
342
451
|
position[crossAxis] += delta;
|
343
452
|
|
344
453
|
let arrowPosition: Position = {};
|
345
|
-
arrowPosition[crossAxis] =
|
454
|
+
arrowPosition[crossAxis] =
|
455
|
+
childOffset[crossAxis] - position[crossAxis] + childOffset[crossSize] / 2;
|
346
456
|
|
347
457
|
if (shouldOverlapWithTrigger) {
|
348
|
-
position[FLIPPED_DIRECTION[placementInfo.placement]] =
|
458
|
+
position[FLIPPED_DIRECTION[placementInfo.placement]] =
|
459
|
+
position[FLIPPED_DIRECTION[placementInfo.placement]] - childOffset[size];
|
349
460
|
}
|
350
461
|
|
351
462
|
return {
|
@@ -353,7 +464,7 @@ export function calculatePositionInternal(
|
|
353
464
|
maxHeight: maxHeight,
|
354
465
|
arrowOffsetLeft: arrowPosition.left,
|
355
466
|
arrowOffsetTop: arrowPosition.top,
|
356
|
-
placement: placementInfo.placement
|
467
|
+
placement: placementInfo.placement,
|
357
468
|
};
|
358
469
|
}
|
359
470
|
|
@@ -371,14 +482,17 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
|
|
371
482
|
boundaryElement,
|
372
483
|
offset,
|
373
484
|
crossOffset,
|
374
|
-
shouldOverlapWithTrigger
|
485
|
+
shouldOverlapWithTrigger,
|
375
486
|
} = opts;
|
376
487
|
|
377
488
|
let container = overlayNode.offsetParent || document.body;
|
378
489
|
let isBodyContainer = container.tagName === 'BODY';
|
379
490
|
const containerPositionStyle = window.getComputedStyle(container).position;
|
380
|
-
let isContainerPositioned =
|
381
|
-
|
491
|
+
let isContainerPositioned =
|
492
|
+
!!containerPositionStyle && containerPositionStyle !== 'static';
|
493
|
+
let childOffset: Offset = isBodyContainer
|
494
|
+
? getOffset(targetNode)
|
495
|
+
: getPosition(targetNode, container);
|
382
496
|
|
383
497
|
if (!isBodyContainer) {
|
384
498
|
childOffset.top += parseInt(getCss(targetNode, 'marginTop'), 10) || 0;
|
@@ -386,14 +500,42 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
|
|
386
500
|
}
|
387
501
|
|
388
502
|
let overlaySize: Offset = getOffset(overlayNode);
|
503
|
+
const matrix = getComputedStyle(overlayNode).getPropertyValue('transform');
|
504
|
+
const transform = matrix;
|
505
|
+
const regex = /matrix\((-?\d*\.?\d+),\s*(-?\d*\.?\d+),\s*(-?\d*\.?\d+),\s*(-?\d*\.?\d+),\s*(-?\d*\.?\d+),\s*(-?\d*\.?\d+)\)/;
|
506
|
+
const matches = transform.match(regex);
|
507
|
+
let scaleX = 1;
|
508
|
+
let scaleY = 1;
|
509
|
+
|
510
|
+
if (matches) {
|
511
|
+
scaleX = parseFloat(matches[1]);
|
512
|
+
scaleY = parseFloat(matches[4]);
|
513
|
+
if (!scaleX || !Number.isFinite(scaleX)) {
|
514
|
+
scaleX = 1;
|
515
|
+
}
|
516
|
+
|
517
|
+
if (!scaleY || !Number.isFinite(scaleY)) {
|
518
|
+
scaleY = 1;
|
519
|
+
}
|
520
|
+
}
|
521
|
+
|
389
522
|
let margins = getMargins(overlayNode);
|
390
523
|
overlaySize.width += margins.left + margins.right;
|
391
524
|
overlaySize.height += margins.top + margins.bottom;
|
392
525
|
|
526
|
+
if (scaleX) {
|
527
|
+
overlaySize.width = overlaySize.width / scaleX;
|
528
|
+
}
|
529
|
+
if (scaleY) {
|
530
|
+
overlaySize.height = overlaySize.height / scaleY;
|
531
|
+
}
|
532
|
+
|
393
533
|
let scrollSize = getScroll(scrollNode);
|
394
534
|
let boundaryDimensions = getContainerDimensions(boundaryElement);
|
395
|
-
let containerOffsetWithBoundary: Offset =
|
396
|
-
|
535
|
+
let containerOffsetWithBoundary: Offset =
|
536
|
+
boundaryElement.tagName === 'BODY'
|
537
|
+
? getOffset(container)
|
538
|
+
: getPosition(container, boundaryElement);
|
397
539
|
|
398
540
|
return calculatePositionInternal(
|
399
541
|
placement,
|
@@ -11,7 +11,7 @@
|
|
11
11
|
* governing permissions and limitations under the License.
|
12
12
|
*/
|
13
13
|
|
14
|
-
import {RefObject, useEffect} from 'react';
|
14
|
+
import { RefObject, useEffect } from 'react';
|
15
15
|
|
16
16
|
// This behavior moved from useOverlayTrigger to useOverlayPosition.
|
17
17
|
// For backward compatibility, where useOverlayTrigger handled hiding the popover on close,
|
@@ -21,14 +21,14 @@ import {RefObject, useEffect} from 'react';
|
|
21
21
|
export const onCloseMap: WeakMap<HTMLElement, () => void> = new WeakMap();
|
22
22
|
|
23
23
|
interface CloseOnScrollOptions {
|
24
|
-
triggerRef: RefObject<HTMLElement
|
25
|
-
isOpen?: boolean
|
26
|
-
onClose?: () => void
|
24
|
+
triggerRef: RefObject<HTMLElement>;
|
25
|
+
isOpen?: boolean;
|
26
|
+
onClose?: () => void;
|
27
27
|
}
|
28
28
|
|
29
29
|
/** @private */
|
30
30
|
export function useCloseOnScroll(opts: CloseOnScrollOptions) {
|
31
|
-
let {triggerRef, isOpen, onClose} = opts;
|
31
|
+
let { triggerRef, isOpen, onClose } = opts;
|
32
32
|
|
33
33
|
useEffect(() => {
|
34
34
|
if (!isOpen) {
|