@cloudscape-design/components 3.0.489 → 3.0.491

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.
Files changed (32) hide show
  1. package/internal/components/chart-plot/application-controller.js +4 -9
  2. package/internal/components/chart-plot/application-controller.js.map +1 -1
  3. package/internal/components/chart-popover/index.js +3 -1
  4. package/internal/components/chart-popover/index.js.map +1 -1
  5. package/internal/components/dropdown/dropdown-fit-handler.d.ts +5 -5
  6. package/internal/components/dropdown/dropdown-fit-handler.d.ts.map +1 -1
  7. package/internal/components/dropdown/dropdown-fit-handler.js.map +1 -1
  8. package/internal/environment.js +1 -1
  9. package/internal/environment.json +1 -1
  10. package/internal/manifest.json +1 -1
  11. package/internal/utils/scrollable-containers.d.ts +9 -2
  12. package/internal/utils/scrollable-containers.d.ts.map +1 -1
  13. package/internal/utils/scrollable-containers.js +25 -0
  14. package/internal/utils/scrollable-containers.js.map +1 -1
  15. package/mixed-line-bar-chart/chart-container.js +2 -2
  16. package/mixed-line-bar-chart/chart-container.js.map +1 -1
  17. package/package.json +1 -1
  18. package/popover/container.d.ts +3 -1
  19. package/popover/container.d.ts.map +1 -1
  20. package/popover/container.js +16 -127
  21. package/popover/container.js.map +1 -1
  22. package/popover/interfaces.d.ts +2 -2
  23. package/popover/interfaces.d.ts.map +1 -1
  24. package/popover/interfaces.js.map +1 -1
  25. package/popover/use-popover-position.d.ts +20 -0
  26. package/popover/use-popover-position.d.ts.map +1 -0
  27. package/popover/use-popover-position.js +149 -0
  28. package/popover/use-popover-position.js.map +1 -0
  29. package/popover/utils/positions.d.ts +10 -9
  30. package/popover/utils/positions.d.ts.map +1 -1
  31. package/popover/utils/positions.js +69 -48
  32. package/popover/utils/positions.js.map +1 -1
@@ -0,0 +1,149 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { useCallback, useRef, useState } from 'react';
4
+ import { calculatePosition, getDimensions, getOffsetDimensions } from './utils/positions';
5
+ import { nodeContains } from '@cloudscape-design/component-toolkit/dom';
6
+ import { calculateScroll, scrollRectangleIntoView } from '../internal/utils/scrollable-containers';
7
+ import { getContainingBlock } from '../internal/utils/dom';
8
+ export default function usePopoverPosition({ popoverRef, bodyRef, arrowRef, trackRef, contentRef, allowScrollToFit, allowVerticalOverflow, preferredPosition, renderWithPortal, keepPosition, }) {
9
+ const previousInternalPositionRef = useRef(null);
10
+ const [popoverStyle, setPopoverStyle] = useState({});
11
+ const [internalPosition, setInternalPosition] = useState(null);
12
+ // Store the handler in a ref so that it can still be replaced from outside of the listener closure.
13
+ const positionHandlerRef = useRef(() => { });
14
+ const updatePositionHandler = useCallback((onContentResize = false) => {
15
+ var _a;
16
+ if (!trackRef.current || !popoverRef.current || !bodyRef.current || !contentRef.current || !arrowRef.current) {
17
+ return;
18
+ }
19
+ // Get important elements
20
+ const popover = popoverRef.current;
21
+ const body = bodyRef.current;
22
+ const arrow = arrowRef.current;
23
+ const document = popover.ownerDocument;
24
+ const track = trackRef.current;
25
+ // If the popover body isn't being rendered for whatever reason (e.g. "display: none" or JSDOM),
26
+ // or track does not belong to the document - bail on calculating dimensions.
27
+ const { offsetWidth, offsetHeight } = getOffsetDimensions(popover);
28
+ if (offsetWidth === 0 || offsetHeight === 0 || !nodeContains(document.body, track)) {
29
+ return;
30
+ }
31
+ // Imperatively move body off-screen to give it room to expand.
32
+ // Not doing this in React because this recalculation should happen
33
+ // in the span of a single frame without rerendering anything.
34
+ const prevTop = popover.style.top;
35
+ const prevLeft = popover.style.left;
36
+ popover.style.top = '0';
37
+ popover.style.left = '0';
38
+ // Imperatively remove body styles that can remain from the previous computation.
39
+ body.style.maxHeight = '';
40
+ body.style.overflowX = '';
41
+ body.style.overflowY = '';
42
+ // Get rects representing key elements
43
+ // Use getComputedStyle for arrowRect to avoid modifications made by transform
44
+ const viewportRect = getViewportRect(document.defaultView);
45
+ const trackRect = track.getBoundingClientRect();
46
+ const arrowRect = getDimensions(arrow);
47
+ const containingBlock = getContainingBlock(popover);
48
+ const containingBlockRect = containingBlock ? containingBlock.getBoundingClientRect() : viewportRect;
49
+ const bodyBorderWidth = getBorderWidth(body);
50
+ const contentRect = contentRef.current.getBoundingClientRect();
51
+ const contentBoundingBox = {
52
+ width: contentRect.width + 2 * bodyBorderWidth,
53
+ height: contentRect.height + 2 * bodyBorderWidth,
54
+ };
55
+ // When keepPosition is true and the recalculation was triggered by a resize of the popover content,
56
+ // we maintain the previously defined internal position,
57
+ // but we still call calculatePosition to know if the popover should be scrollable.
58
+ const shouldKeepPosition = keepPosition && onContentResize && !!previousInternalPositionRef.current;
59
+ const fixedInternalPosition = (_a = (shouldKeepPosition && previousInternalPositionRef.current)) !== null && _a !== void 0 ? _a : undefined;
60
+ // Calculate the arrow direction and viewport-relative position of the popover.
61
+ const { scrollable, internalPosition: newInternalPosition, rect, } = calculatePosition({
62
+ preferredPosition,
63
+ fixedInternalPosition,
64
+ trigger: trackRect,
65
+ arrow: arrowRect,
66
+ body: contentBoundingBox,
67
+ container: containingBlock ? containingBlockRect : getDocumentRect(document),
68
+ viewport: viewportRect,
69
+ renderWithPortal,
70
+ allowVerticalOverflow,
71
+ });
72
+ // Get the position of the popover relative to the offset parent.
73
+ const popoverOffset = toRelativePosition(rect, containingBlockRect);
74
+ // Cache the distance between the trigger and the popover (which stays the same as you scroll),
75
+ // and use that to recalculate the new popover position.
76
+ const trackRelativeOffset = toRelativePosition(popoverOffset, toRelativePosition(trackRect, containingBlockRect));
77
+ // Bring back the container to its original position to prevent any flashing.
78
+ popover.style.top = prevTop;
79
+ popover.style.left = prevLeft;
80
+ // Allow popover body to scroll if can't fit the popover into the container/viewport otherwise.
81
+ if (scrollable) {
82
+ body.style.maxHeight = rect.height + 'px';
83
+ body.style.overflowX = 'hidden';
84
+ body.style.overflowY = 'auto';
85
+ }
86
+ // Remember the internal position in case we want to keep it later.
87
+ previousInternalPositionRef.current = newInternalPosition;
88
+ setInternalPosition(newInternalPosition);
89
+ const shouldScroll = allowScrollToFit && !shouldKeepPosition;
90
+ // Position the popover
91
+ const top = shouldScroll ? popoverOffset.top + calculateScroll(rect) : popoverOffset.top;
92
+ setPopoverStyle({ top, left: popoverOffset.left });
93
+ if (shouldScroll) {
94
+ scrollRectangleIntoView(rect);
95
+ }
96
+ positionHandlerRef.current = () => {
97
+ const newTrackOffset = toRelativePosition(track.getBoundingClientRect(), containingBlock ? containingBlock.getBoundingClientRect() : viewportRect);
98
+ setPopoverStyle({
99
+ top: newTrackOffset.top + trackRelativeOffset.top,
100
+ left: newTrackOffset.left + trackRelativeOffset.left,
101
+ });
102
+ };
103
+ }, [
104
+ trackRef,
105
+ popoverRef,
106
+ bodyRef,
107
+ contentRef,
108
+ arrowRef,
109
+ keepPosition,
110
+ allowScrollToFit,
111
+ preferredPosition,
112
+ renderWithPortal,
113
+ allowVerticalOverflow,
114
+ ]);
115
+ return { updatePositionHandler, popoverStyle, internalPosition, positionHandlerRef };
116
+ }
117
+ function getBorderWidth(element) {
118
+ return parseInt(getComputedStyle(element).borderWidth) || 0;
119
+ }
120
+ /**
121
+ * Convert a viewport-relative offset to an element-relative offset.
122
+ */
123
+ function toRelativePosition(element, parent) {
124
+ return {
125
+ top: element.top - parent.top,
126
+ left: element.left - parent.left,
127
+ };
128
+ }
129
+ /**
130
+ * Get a BoundingBox that represents the visible viewport.
131
+ */
132
+ function getViewportRect(window) {
133
+ return {
134
+ top: 0,
135
+ left: 0,
136
+ width: window.innerWidth,
137
+ height: window.innerHeight,
138
+ };
139
+ }
140
+ function getDocumentRect(document) {
141
+ const { top, left } = document.documentElement.getBoundingClientRect();
142
+ return {
143
+ top,
144
+ left,
145
+ width: document.documentElement.scrollWidth,
146
+ height: document.documentElement.scrollHeight,
147
+ };
148
+ }
149
+ //# sourceMappingURL=use-popover-position.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-popover-position.js","sourceRoot":"lib/default/","sources":["popover/use-popover-position.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport React, { useCallback, useRef, useState } from 'react';\nimport { BoundingBox, InternalPosition, Offset, PopoverProps } from './interfaces';\nimport { calculatePosition, getDimensions, getOffsetDimensions } from './utils/positions';\nimport { nodeContains } from '@cloudscape-design/component-toolkit/dom';\nimport { calculateScroll, scrollRectangleIntoView } from '../internal/utils/scrollable-containers';\nimport { getContainingBlock } from '../internal/utils/dom';\n\nexport default function usePopoverPosition({\n popoverRef,\n bodyRef,\n arrowRef,\n trackRef,\n contentRef,\n allowScrollToFit,\n allowVerticalOverflow,\n preferredPosition,\n renderWithPortal,\n keepPosition,\n}: {\n popoverRef: React.RefObject<HTMLDivElement | null>;\n bodyRef: React.RefObject<HTMLDivElement | null>;\n arrowRef: React.RefObject<HTMLDivElement | null>;\n trackRef: React.RefObject<Element | null>;\n contentRef: React.RefObject<HTMLDivElement | null>;\n allowScrollToFit?: boolean;\n allowVerticalOverflow?: boolean;\n preferredPosition: PopoverProps.Position;\n renderWithPortal?: boolean;\n keepPosition?: boolean;\n}) {\n const previousInternalPositionRef = useRef<InternalPosition | null>(null);\n const [popoverStyle, setPopoverStyle] = useState<Partial<Offset>>({});\n const [internalPosition, setInternalPosition] = useState<InternalPosition | null>(null);\n\n // Store the handler in a ref so that it can still be replaced from outside of the listener closure.\n const positionHandlerRef = useRef<() => void>(() => {});\n\n const updatePositionHandler = useCallback(\n (onContentResize = false) => {\n if (!trackRef.current || !popoverRef.current || !bodyRef.current || !contentRef.current || !arrowRef.current) {\n return;\n }\n\n // Get important elements\n const popover = popoverRef.current;\n const body = bodyRef.current;\n const arrow = arrowRef.current;\n const document = popover.ownerDocument;\n const track = trackRef.current;\n\n // If the popover body isn't being rendered for whatever reason (e.g. \"display: none\" or JSDOM),\n // or track does not belong to the document - bail on calculating dimensions.\n const { offsetWidth, offsetHeight } = getOffsetDimensions(popover);\n if (offsetWidth === 0 || offsetHeight === 0 || !nodeContains(document.body, track)) {\n return;\n }\n\n // Imperatively move body off-screen to give it room to expand.\n // Not doing this in React because this recalculation should happen\n // in the span of a single frame without rerendering anything.\n const prevTop = popover.style.top;\n const prevLeft = popover.style.left;\n\n popover.style.top = '0';\n popover.style.left = '0';\n // Imperatively remove body styles that can remain from the previous computation.\n body.style.maxHeight = '';\n body.style.overflowX = '';\n body.style.overflowY = '';\n\n // Get rects representing key elements\n // Use getComputedStyle for arrowRect to avoid modifications made by transform\n const viewportRect = getViewportRect(document.defaultView!);\n const trackRect = track.getBoundingClientRect();\n const arrowRect = getDimensions(arrow);\n const containingBlock = getContainingBlock(popover);\n const containingBlockRect = containingBlock ? containingBlock.getBoundingClientRect() : viewportRect;\n\n const bodyBorderWidth = getBorderWidth(body);\n const contentRect = contentRef.current.getBoundingClientRect();\n const contentBoundingBox = {\n width: contentRect.width + 2 * bodyBorderWidth,\n height: contentRect.height + 2 * bodyBorderWidth,\n };\n\n // When keepPosition is true and the recalculation was triggered by a resize of the popover content,\n // we maintain the previously defined internal position,\n // but we still call calculatePosition to know if the popover should be scrollable.\n const shouldKeepPosition = keepPosition && onContentResize && !!previousInternalPositionRef.current;\n const fixedInternalPosition = (shouldKeepPosition && previousInternalPositionRef.current) ?? undefined;\n\n // Calculate the arrow direction and viewport-relative position of the popover.\n const {\n scrollable,\n internalPosition: newInternalPosition,\n rect,\n } = calculatePosition({\n preferredPosition,\n fixedInternalPosition,\n trigger: trackRect,\n arrow: arrowRect,\n body: contentBoundingBox,\n container: containingBlock ? containingBlockRect : getDocumentRect(document),\n viewport: viewportRect,\n renderWithPortal,\n allowVerticalOverflow,\n });\n\n // Get the position of the popover relative to the offset parent.\n const popoverOffset = toRelativePosition(rect, containingBlockRect);\n\n // Cache the distance between the trigger and the popover (which stays the same as you scroll),\n // and use that to recalculate the new popover position.\n const trackRelativeOffset = toRelativePosition(popoverOffset, toRelativePosition(trackRect, containingBlockRect));\n\n // Bring back the container to its original position to prevent any flashing.\n popover.style.top = prevTop;\n popover.style.left = prevLeft;\n\n // Allow popover body to scroll if can't fit the popover into the container/viewport otherwise.\n if (scrollable) {\n body.style.maxHeight = rect.height + 'px';\n body.style.overflowX = 'hidden';\n body.style.overflowY = 'auto';\n }\n\n // Remember the internal position in case we want to keep it later.\n previousInternalPositionRef.current = newInternalPosition;\n setInternalPosition(newInternalPosition);\n\n const shouldScroll = allowScrollToFit && !shouldKeepPosition;\n\n // Position the popover\n const top = shouldScroll ? popoverOffset.top + calculateScroll(rect) : popoverOffset.top;\n setPopoverStyle({ top, left: popoverOffset.left });\n if (shouldScroll) {\n scrollRectangleIntoView(rect);\n }\n\n positionHandlerRef.current = () => {\n const newTrackOffset = toRelativePosition(\n track.getBoundingClientRect(),\n containingBlock ? containingBlock.getBoundingClientRect() : viewportRect\n );\n setPopoverStyle({\n top: newTrackOffset.top + trackRelativeOffset.top,\n left: newTrackOffset.left + trackRelativeOffset.left,\n });\n };\n },\n [\n trackRef,\n popoverRef,\n bodyRef,\n contentRef,\n arrowRef,\n keepPosition,\n allowScrollToFit,\n preferredPosition,\n renderWithPortal,\n allowVerticalOverflow,\n ]\n );\n return { updatePositionHandler, popoverStyle, internalPosition, positionHandlerRef };\n}\n\nfunction getBorderWidth(element: HTMLElement) {\n return parseInt(getComputedStyle(element).borderWidth) || 0;\n}\n\n/**\n * Convert a viewport-relative offset to an element-relative offset.\n */\nfunction toRelativePosition(element: Offset, parent: Offset): Offset {\n return {\n top: element.top - parent.top,\n left: element.left - parent.left,\n };\n}\n\n/**\n * Get a BoundingBox that represents the visible viewport.\n */\nfunction getViewportRect(window: Window): BoundingBox {\n return {\n top: 0,\n left: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n}\n\nfunction getDocumentRect(document: Document): BoundingBox {\n const { top, left } = document.documentElement.getBoundingClientRect();\n return {\n top,\n left,\n width: document.documentElement.scrollWidth,\n height: document.documentElement.scrollHeight,\n };\n}\n"]}
@@ -1,26 +1,27 @@
1
- import { PopoverProps, InternalPosition, BoundingOffset, BoundingBox } from '../interfaces';
1
+ import { PopoverProps, InternalPosition, BoundingBox, Dimensions } from '../interfaces';
2
2
  interface CalculatedPosition {
3
3
  scrollable?: boolean;
4
4
  internalPosition: InternalPosition;
5
- boundingOffset: BoundingOffset;
5
+ rect: BoundingBox;
6
6
  }
7
7
  export declare const PRIORITY_MAPPING: Record<PopoverProps.Position, InternalPosition[]>;
8
8
  /**
9
9
  * Returns the area of the intersection of passed in rectangles or a null, if there is no intersection
10
10
  */
11
- export declare function intersectRectangles(rectangles: BoundingOffset[]): number | null;
11
+ export declare function intersectRectangles(rectangles: BoundingBox[]): number | null;
12
12
  /**
13
13
  * A functions that returns the correct popover position based on screen dimensions.
14
14
  */
15
- export declare function calculatePosition({ preferredPosition, fixedInternalPosition, trigger, arrow, body, container, viewport, renderWithPortal, }: {
15
+ export declare function calculatePosition({ preferredPosition, fixedInternalPosition, trigger, arrow, body, container, viewport, renderWithPortal, allowVerticalOverflow, }: {
16
16
  preferredPosition: PopoverProps.Position;
17
17
  fixedInternalPosition?: InternalPosition;
18
- trigger: BoundingOffset;
19
- arrow: BoundingBox;
20
- body: BoundingBox;
21
- container: BoundingOffset;
22
- viewport: BoundingOffset;
18
+ trigger: BoundingBox;
19
+ arrow: Dimensions;
20
+ body: Dimensions;
21
+ container: BoundingBox;
22
+ viewport: BoundingBox;
23
23
  renderWithPortal?: boolean;
24
+ allowVerticalOverflow?: boolean;
24
25
  }): CalculatedPosition;
25
26
  export declare function getOffsetDimensions(element: HTMLElement): {
26
27
  offsetHeight: number;
@@ -1 +1 @@
1
- {"version":3,"file":"positions.d.ts","sourceRoot":"lib/default/","sources":["popover/utils/positions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5F,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,cAAc,CAAC;CAChC;AAUD,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,gBAAgB,EAAE,CAiD9E,CAAC;AA0HF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,GAAG,IAAI,CAsB/E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,iBAAiB,EACjB,qBAAqB,EACrB,OAAO,EACP,KAAK,EACL,IAAI,EACJ,SAAS,EACT,QAAQ,EAER,gBAAgB,GACjB,EAAE;IACD,iBAAiB,EAAE,YAAY,CAAC,QAAQ,CAAC;IACzC,qBAAqB,CAAC,EAAE,gBAAgB,CAAC;IACzC,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,cAAc,CAAC;IAEzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,kBAAkB,CAuCrB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW;;;EAEvD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW;;;EAMjD"}
1
+ {"version":3,"file":"positions.d.ts","sourceRoot":"lib/default/","sources":["popover/utils/positions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGxF,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,IAAI,EAAE,WAAW,CAAC;CACnB;AAUD,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,gBAAgB,EAAE,CAiD9E,CAAC;AA0IF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,WAAW,EAAE,GAAG,MAAM,GAAG,IAAI,CAG5E;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,iBAAiB,EACjB,qBAAqB,EACrB,OAAO,EACP,KAAK,EACL,IAAI,EACJ,SAAS,EACT,QAAQ,EAER,gBAAgB,EAChB,qBAAqB,GACtB,EAAE;IACD,iBAAiB,EAAE,YAAY,CAAC,QAAQ,CAAC;IACzC,qBAAqB,CAAC,EAAE,gBAAgB,CAAC;IACzC,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IAEtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,GAAG,kBAAkB,CAmDrB;AAmBD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW;;;EAEvD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW;;;EAMjD"}
@@ -131,15 +131,6 @@ const RECTANGLE_CALCULATIONS = {
131
131
  };
132
132
  },
133
133
  };
134
- /**
135
- * Returns whether one rectangle fits in another.
136
- */
137
- function canRectFit(inner, outer) {
138
- return (inner.left >= outer.left &&
139
- inner.top >= outer.top &&
140
- inner.left + inner.width <= outer.left + outer.width &&
141
- inner.top + inner.height <= outer.top + outer.height);
142
- }
143
134
  function fitIntoContainer(inner, outer) {
144
135
  let { left, width, top, height } = inner;
145
136
  // Adjust left boundary.
@@ -162,72 +153,99 @@ function fitIntoContainer(inner, outer) {
162
153
  }
163
154
  return { left, width, top, height };
164
155
  }
165
- /**
166
- * Returns the area of the intersection of passed in rectangles or a null, if there is no intersection
167
- */
168
- export function intersectRectangles(rectangles) {
169
- let boundingOffset = null;
156
+ function getTallestRect(rect1, rect2) {
157
+ return rect1.height >= rect2.height ? rect1 : rect2;
158
+ }
159
+ function getIntersection(rectangles) {
160
+ let boundingBox = null;
170
161
  for (const currentRect of rectangles) {
171
- if (!boundingOffset) {
172
- boundingOffset = currentRect;
162
+ if (!boundingBox) {
163
+ boundingBox = currentRect;
173
164
  continue;
174
165
  }
175
- const left = Math.max(boundingOffset.left, currentRect.left);
176
- const top = Math.max(boundingOffset.top, currentRect.top);
177
- const right = Math.min(boundingOffset.left + boundingOffset.width, currentRect.left + currentRect.width);
178
- const bottom = Math.min(boundingOffset.top + boundingOffset.height, currentRect.top + currentRect.height);
166
+ const left = Math.max(boundingBox.left, currentRect.left);
167
+ const top = Math.max(boundingBox.top, currentRect.top);
168
+ const right = Math.min(boundingBox.left + boundingBox.width, currentRect.left + currentRect.width);
169
+ const bottom = Math.min(boundingBox.top + boundingBox.height, currentRect.top + currentRect.height);
179
170
  if (right < left || bottom < top) {
180
171
  return null;
181
172
  }
182
- boundingOffset = {
173
+ boundingBox = {
183
174
  left,
184
175
  top,
185
176
  width: right - left,
186
177
  height: bottom - top,
187
178
  };
188
179
  }
189
- return boundingOffset && boundingOffset.height * boundingOffset.width;
180
+ return boundingBox;
181
+ }
182
+ /**
183
+ * Returns the area of the intersection of passed in rectangles or a null, if there is no intersection
184
+ */
185
+ export function intersectRectangles(rectangles) {
186
+ const boundingBox = getIntersection(rectangles);
187
+ return boundingBox && boundingBox.height * boundingBox.width;
190
188
  }
191
189
  /**
192
190
  * A functions that returns the correct popover position based on screen dimensions.
193
191
  */
194
192
  export function calculatePosition({ preferredPosition, fixedInternalPosition, trigger, arrow, body, container, viewport,
195
193
  // the popover is only bound by the viewport if it is rendered in a portal
196
- renderWithPortal, }) {
197
- let bestPositionOutsideViewport = null;
198
- let largestArea = 0;
194
+ renderWithPortal, allowVerticalOverflow, }) {
195
+ let bestOption = null;
199
196
  // If a fixed internal position is passed, only consider this one.
200
197
  const preferredInternalPositions = fixedInternalPosition
201
198
  ? [fixedInternalPosition]
202
199
  : PRIORITY_MAPPING[preferredPosition];
203
- // Attempt to position the popover based on the priority list for this position,
204
- // trying to fit it inside the container and inside the viewport.
200
+ // Attempt to position the popover based on the priority list for this position.
205
201
  for (const internalPosition of preferredInternalPositions) {
206
- const boundingOffset = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });
207
- const fitsInContainer = renderWithPortal || canRectFit(boundingOffset, container);
208
- const fitsInViewport = canRectFit(boundingOffset, viewport);
209
- if (fitsInContainer && fitsInViewport) {
210
- return { internalPosition, boundingOffset };
211
- }
212
- const boundingRectangles = [boundingOffset, viewport];
213
- if (!renderWithPortal) {
214
- boundingRectangles.push(container);
215
- }
216
- const availableArea = intersectRectangles(boundingRectangles);
217
- if (availableArea && availableArea > largestArea) {
218
- bestPositionOutsideViewport = { internalPosition, boundingOffset };
219
- largestArea = availableArea;
202
+ const rect = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });
203
+ const visibleArea = renderWithPortal
204
+ ? getIntersection([rect, viewport])
205
+ : getIntersection([rect, viewport, container]);
206
+ const fitsWithoutOverflow = visibleArea && visibleArea.width === body.width && visibleArea.height === body.height;
207
+ if (fitsWithoutOverflow) {
208
+ return { internalPosition, rect };
220
209
  }
210
+ const newOption = { rect, internalPosition, visibleArea };
211
+ bestOption = getBestOption(newOption, bestOption);
221
212
  }
222
213
  // Use best possible placement.
223
- const internalPosition = (bestPositionOutsideViewport === null || bestPositionOutsideViewport === void 0 ? void 0 : bestPositionOutsideViewport.internalPosition) || 'right-top';
214
+ const internalPosition = (bestOption === null || bestOption === void 0 ? void 0 : bestOption.internalPosition) || 'right-top';
224
215
  // Get default rect for that placement.
225
- const defaultOffset = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });
226
- // Get largest possible rect that fits into viewport.
227
- const optimisedOffset = fitIntoContainer(defaultOffset, viewport);
228
- // If largest possible rect is smaller than original - set body scroll.
229
- const scrollable = optimisedOffset.height < defaultOffset.height;
230
- return { internalPosition, boundingOffset: optimisedOffset, scrollable };
216
+ const rect = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });
217
+ // Get largest possible rect that fits into the viewport or container.
218
+ // We allow the popover to overflow the viewport if allowVerticalOverflow is true _and_ the popover will be anchored to the top or the bottom.
219
+ // If it is anchored to the right or left, we consider that it should have enough vertical space so that applying scroll to it is a better option.
220
+ const tallestBoundingContainer = getTallestRect(viewport, container);
221
+ const boundingContainer = allowVerticalOverflow && isTopOrBottom(internalPosition)
222
+ ? {
223
+ top: tallestBoundingContainer.top,
224
+ height: tallestBoundingContainer.height,
225
+ left: viewport.left,
226
+ width: viewport.width,
227
+ }
228
+ : viewport;
229
+ const optimizedRect = fitIntoContainer(rect, boundingContainer);
230
+ // If largest possible rect is shorter than original - set body scroll.
231
+ const scrollable = optimizedRect.height < rect.height;
232
+ return { internalPosition, rect: optimizedRect, scrollable };
233
+ }
234
+ function getBestOption(option1, option2) {
235
+ // Within calculatePosition, the only case where option2 will not be defined will be in the first call.
236
+ // The only case where the visibleArea of an option will be null is when the popover is totally outside of the viewport.
237
+ if (!(option2 === null || option2 === void 0 ? void 0 : option2.visibleArea)) {
238
+ return option1;
239
+ }
240
+ if (!option1.visibleArea) {
241
+ return option2;
242
+ }
243
+ // Only if none of the two options overflows horizontally, choose the best based on the visible height.
244
+ if (option1.visibleArea.width === option2.visibleArea.width) {
245
+ return option1.visibleArea.height > option2.visibleArea.height ? option1 : option2;
246
+ }
247
+ // Otherwise, choose the option that is less cut off horizontally.
248
+ return option1.visibleArea.width > option2.visibleArea.width ? option1 : option2;
231
249
  }
232
250
  export function getOffsetDimensions(element) {
233
251
  return { offsetHeight: element.offsetHeight, offsetWidth: element.offsetWidth };
@@ -239,4 +257,7 @@ export function getDimensions(element) {
239
257
  height: parseFloat(computedStyle.height),
240
258
  };
241
259
  }
260
+ function isTopOrBottom(internalPosition) {
261
+ return ['top', 'bottom'].includes(internalPosition.split('-')[0]);
262
+ }
242
263
  //# sourceMappingURL=positions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"positions.js","sourceRoot":"lib/default/","sources":["popover/utils/positions.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { PopoverProps, InternalPosition, BoundingOffset, BoundingBox } from '../interfaces';\n\n// A structure describing how the popover should be positioned\ninterface CalculatedPosition {\n scrollable?: boolean;\n internalPosition: InternalPosition;\n boundingOffset: BoundingOffset;\n}\n\ninterface ElementGroup {\n body: BoundingBox;\n trigger: BoundingOffset;\n arrow: BoundingBox;\n}\n\nconst ARROW_OFFSET = 12;\n\nexport const PRIORITY_MAPPING: Record<PopoverProps.Position, InternalPosition[]> = {\n top: [\n 'top-center',\n 'top-right',\n 'top-left',\n 'bottom-center',\n 'bottom-right',\n 'bottom-left',\n 'right-top',\n 'right-bottom',\n 'left-top',\n 'left-bottom',\n ],\n bottom: [\n 'bottom-center',\n 'bottom-right',\n 'bottom-left',\n 'top-center',\n 'top-right',\n 'top-left',\n 'right-top',\n 'right-bottom',\n 'left-top',\n 'left-bottom',\n ],\n left: [\n 'left-top',\n 'left-bottom',\n 'right-top',\n 'right-bottom',\n 'bottom-center',\n 'top-center',\n 'bottom-left',\n 'top-left',\n 'bottom-right',\n 'top-right',\n ],\n right: [\n 'right-top',\n 'right-bottom',\n 'left-top',\n 'left-bottom',\n 'bottom-center',\n 'top-center',\n 'bottom-right',\n 'top-right',\n 'bottom-left',\n 'top-left',\n ],\n};\n\nconst RECTANGLE_CALCULATIONS: Record<InternalPosition, (r: ElementGroup) => BoundingOffset> = {\n 'top-center': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top - body.height - arrow.height,\n left: trigger.left + trigger.width / 2 - body.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'top-right': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top - body.height - arrow.height,\n left: trigger.left + trigger.width / 2 - ARROW_OFFSET - arrow.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'top-left': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top - body.height - arrow.height,\n left: trigger.left + trigger.width / 2 + ARROW_OFFSET + arrow.width / 2 - body.width,\n width: body.width,\n height: body.height,\n };\n },\n 'bottom-center': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height + arrow.height,\n left: trigger.left + trigger.width / 2 - body.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'bottom-right': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height + arrow.height,\n left: trigger.left + trigger.width / 2 - ARROW_OFFSET - arrow.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'bottom-left': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height + arrow.height,\n left: trigger.left + trigger.width / 2 + ARROW_OFFSET + arrow.width / 2 - body.width,\n width: body.width,\n height: body.height,\n };\n },\n 'right-top': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - ARROW_OFFSET - arrow.height,\n left: trigger.left + trigger.width + arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n 'right-bottom': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - body.height + ARROW_OFFSET + arrow.height,\n left: trigger.left + trigger.width + arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n 'left-top': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - ARROW_OFFSET - arrow.height,\n left: trigger.left - body.width - arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n 'left-bottom': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - body.height + ARROW_OFFSET + arrow.height,\n left: trigger.left - body.width - arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n};\n\n/**\n * Returns whether one rectangle fits in another.\n */\nfunction canRectFit(inner: BoundingOffset, outer: BoundingOffset): boolean {\n return (\n inner.left >= outer.left &&\n inner.top >= outer.top &&\n inner.left + inner.width <= outer.left + outer.width &&\n inner.top + inner.height <= outer.top + outer.height\n );\n}\n\nfunction fitIntoContainer(inner: BoundingOffset, outer: BoundingOffset): BoundingOffset {\n let { left, width, top, height } = inner;\n\n // Adjust left boundary.\n if (left < outer.left) {\n width = left + width - outer.left;\n left = outer.left;\n }\n // Adjust right boundary.\n else if (left + width > outer.left + outer.width) {\n width = outer.left + outer.width - left;\n }\n // Adjust top boundary.\n if (top < outer.top) {\n height = top + height - outer.top;\n top = outer.top;\n }\n // Adjust bottom boundary.\n else if (top + height > outer.top + outer.height) {\n height = outer.top + outer.height - top;\n }\n\n return { left, width, top, height };\n}\n\n/**\n * Returns the area of the intersection of passed in rectangles or a null, if there is no intersection\n */\nexport function intersectRectangles(rectangles: BoundingOffset[]): number | null {\n let boundingOffset: BoundingOffset | null = null;\n for (const currentRect of rectangles) {\n if (!boundingOffset) {\n boundingOffset = currentRect;\n continue;\n }\n const left = Math.max(boundingOffset.left, currentRect.left);\n const top = Math.max(boundingOffset.top, currentRect.top);\n const right = Math.min(boundingOffset.left + boundingOffset.width, currentRect.left + currentRect.width);\n const bottom = Math.min(boundingOffset.top + boundingOffset.height, currentRect.top + currentRect.height);\n if (right < left || bottom < top) {\n return null;\n }\n boundingOffset = {\n left,\n top,\n width: right - left,\n height: bottom - top,\n };\n }\n return boundingOffset && boundingOffset.height * boundingOffset.width;\n}\n\n/**\n * A functions that returns the correct popover position based on screen dimensions.\n */\nexport function calculatePosition({\n preferredPosition,\n fixedInternalPosition,\n trigger,\n arrow,\n body,\n container,\n viewport,\n // the popover is only bound by the viewport if it is rendered in a portal\n renderWithPortal,\n}: {\n preferredPosition: PopoverProps.Position;\n fixedInternalPosition?: InternalPosition;\n trigger: BoundingOffset;\n arrow: BoundingBox;\n body: BoundingBox;\n container: BoundingOffset;\n viewport: BoundingOffset;\n // the popover is only bound by the viewport if it is rendered in a portal\n renderWithPortal?: boolean;\n}): CalculatedPosition {\n let bestPositionOutsideViewport: CalculatedPosition | null = null;\n let largestArea = 0;\n\n // If a fixed internal position is passed, only consider this one.\n const preferredInternalPositions = fixedInternalPosition\n ? [fixedInternalPosition]\n : PRIORITY_MAPPING[preferredPosition];\n\n // Attempt to position the popover based on the priority list for this position,\n // trying to fit it inside the container and inside the viewport.\n for (const internalPosition of preferredInternalPositions) {\n const boundingOffset = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });\n const fitsInContainer = renderWithPortal || canRectFit(boundingOffset, container);\n const fitsInViewport = canRectFit(boundingOffset, viewport);\n if (fitsInContainer && fitsInViewport) {\n return { internalPosition, boundingOffset };\n }\n const boundingRectangles = [boundingOffset, viewport];\n if (!renderWithPortal) {\n boundingRectangles.push(container);\n }\n const availableArea = intersectRectangles(boundingRectangles);\n if (availableArea && availableArea > largestArea) {\n bestPositionOutsideViewport = { internalPosition, boundingOffset };\n largestArea = availableArea;\n }\n }\n\n // Use best possible placement.\n const internalPosition = bestPositionOutsideViewport?.internalPosition || 'right-top';\n // Get default rect for that placement.\n const defaultOffset = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });\n // Get largest possible rect that fits into viewport.\n const optimisedOffset = fitIntoContainer(defaultOffset, viewport);\n // If largest possible rect is smaller than original - set body scroll.\n const scrollable = optimisedOffset.height < defaultOffset.height;\n\n return { internalPosition, boundingOffset: optimisedOffset, scrollable };\n}\n\nexport function getOffsetDimensions(element: HTMLElement) {\n return { offsetHeight: element.offsetHeight, offsetWidth: element.offsetWidth };\n}\n\nexport function getDimensions(element: HTMLElement) {\n const computedStyle = getComputedStyle(element);\n return {\n width: parseFloat(computedStyle.width),\n height: parseFloat(computedStyle.height),\n };\n}\n"]}
1
+ {"version":3,"file":"positions.js","sourceRoot":"lib/default/","sources":["popover/utils/positions.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { PopoverProps, InternalPosition, BoundingBox, Dimensions } from '../interfaces';\n\n// A structure describing how the popover should be positioned\ninterface CalculatedPosition {\n scrollable?: boolean;\n internalPosition: InternalPosition;\n rect: BoundingBox;\n}\n\ninterface ElementGroup {\n body: Dimensions;\n trigger: BoundingBox;\n arrow: Dimensions;\n}\n\nconst ARROW_OFFSET = 12;\n\nexport const PRIORITY_MAPPING: Record<PopoverProps.Position, InternalPosition[]> = {\n top: [\n 'top-center',\n 'top-right',\n 'top-left',\n 'bottom-center',\n 'bottom-right',\n 'bottom-left',\n 'right-top',\n 'right-bottom',\n 'left-top',\n 'left-bottom',\n ],\n bottom: [\n 'bottom-center',\n 'bottom-right',\n 'bottom-left',\n 'top-center',\n 'top-right',\n 'top-left',\n 'right-top',\n 'right-bottom',\n 'left-top',\n 'left-bottom',\n ],\n left: [\n 'left-top',\n 'left-bottom',\n 'right-top',\n 'right-bottom',\n 'bottom-center',\n 'top-center',\n 'bottom-left',\n 'top-left',\n 'bottom-right',\n 'top-right',\n ],\n right: [\n 'right-top',\n 'right-bottom',\n 'left-top',\n 'left-bottom',\n 'bottom-center',\n 'top-center',\n 'bottom-right',\n 'top-right',\n 'bottom-left',\n 'top-left',\n ],\n};\n\nconst RECTANGLE_CALCULATIONS: Record<InternalPosition, (r: ElementGroup) => BoundingBox> = {\n 'top-center': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top - body.height - arrow.height,\n left: trigger.left + trigger.width / 2 - body.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'top-right': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top - body.height - arrow.height,\n left: trigger.left + trigger.width / 2 - ARROW_OFFSET - arrow.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'top-left': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top - body.height - arrow.height,\n left: trigger.left + trigger.width / 2 + ARROW_OFFSET + arrow.width / 2 - body.width,\n width: body.width,\n height: body.height,\n };\n },\n 'bottom-center': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height + arrow.height,\n left: trigger.left + trigger.width / 2 - body.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'bottom-right': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height + arrow.height,\n left: trigger.left + trigger.width / 2 - ARROW_OFFSET - arrow.width / 2,\n width: body.width,\n height: body.height,\n };\n },\n 'bottom-left': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height + arrow.height,\n left: trigger.left + trigger.width / 2 + ARROW_OFFSET + arrow.width / 2 - body.width,\n width: body.width,\n height: body.height,\n };\n },\n 'right-top': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - ARROW_OFFSET - arrow.height,\n left: trigger.left + trigger.width + arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n 'right-bottom': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - body.height + ARROW_OFFSET + arrow.height,\n left: trigger.left + trigger.width + arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n 'left-top': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - ARROW_OFFSET - arrow.height,\n left: trigger.left - body.width - arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n 'left-bottom': ({ body, trigger, arrow }) => {\n return {\n top: trigger.top + trigger.height / 2 - body.height + ARROW_OFFSET + arrow.height,\n left: trigger.left - body.width - arrow.height,\n width: body.width,\n height: body.height,\n };\n },\n};\n\nfunction fitIntoContainer(inner: BoundingBox, outer: BoundingBox): BoundingBox {\n let { left, width, top, height } = inner;\n\n // Adjust left boundary.\n if (left < outer.left) {\n width = left + width - outer.left;\n left = outer.left;\n }\n // Adjust right boundary.\n else if (left + width > outer.left + outer.width) {\n width = outer.left + outer.width - left;\n }\n // Adjust top boundary.\n if (top < outer.top) {\n height = top + height - outer.top;\n top = outer.top;\n }\n // Adjust bottom boundary.\n else if (top + height > outer.top + outer.height) {\n height = outer.top + outer.height - top;\n }\n\n return { left, width, top, height };\n}\n\nfunction getTallestRect(rect1: BoundingBox, rect2: BoundingBox): BoundingBox {\n return rect1.height >= rect2.height ? rect1 : rect2;\n}\n\nfunction getIntersection(rectangles: BoundingBox[]): BoundingBox | null {\n let boundingBox: BoundingBox | null = null;\n for (const currentRect of rectangles) {\n if (!boundingBox) {\n boundingBox = currentRect;\n continue;\n }\n const left = Math.max(boundingBox.left, currentRect.left);\n const top = Math.max(boundingBox.top, currentRect.top);\n const right = Math.min(boundingBox.left + boundingBox.width, currentRect.left + currentRect.width);\n const bottom = Math.min(boundingBox.top + boundingBox.height, currentRect.top + currentRect.height);\n if (right < left || bottom < top) {\n return null;\n }\n boundingBox = {\n left,\n top,\n width: right - left,\n height: bottom - top,\n };\n }\n return boundingBox;\n}\n\n/**\n * Returns the area of the intersection of passed in rectangles or a null, if there is no intersection\n */\nexport function intersectRectangles(rectangles: BoundingBox[]): number | null {\n const boundingBox: BoundingBox | null = getIntersection(rectangles);\n return boundingBox && boundingBox.height * boundingBox.width;\n}\n\ntype CandidatePosition = CalculatedPosition & { visibleArea: BoundingBox | null };\n\n/**\n * A functions that returns the correct popover position based on screen dimensions.\n */\nexport function calculatePosition({\n preferredPosition,\n fixedInternalPosition,\n trigger,\n arrow,\n body,\n container,\n viewport,\n // the popover is only bound by the viewport if it is rendered in a portal\n renderWithPortal,\n allowVerticalOverflow,\n}: {\n preferredPosition: PopoverProps.Position;\n fixedInternalPosition?: InternalPosition;\n trigger: BoundingBox;\n arrow: Dimensions;\n body: Dimensions;\n container: BoundingBox;\n viewport: BoundingBox;\n // the popover is only bound by the viewport if it is rendered in a portal\n renderWithPortal?: boolean;\n allowVerticalOverflow?: boolean;\n}): CalculatedPosition {\n let bestOption: CandidatePosition | null = null;\n\n // If a fixed internal position is passed, only consider this one.\n const preferredInternalPositions = fixedInternalPosition\n ? [fixedInternalPosition]\n : PRIORITY_MAPPING[preferredPosition];\n\n // Attempt to position the popover based on the priority list for this position.\n for (const internalPosition of preferredInternalPositions) {\n const rect = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });\n const visibleArea = renderWithPortal\n ? getIntersection([rect, viewport])\n : getIntersection([rect, viewport, container]);\n\n const fitsWithoutOverflow = visibleArea && visibleArea.width === body.width && visibleArea.height === body.height;\n\n if (fitsWithoutOverflow) {\n return { internalPosition, rect };\n }\n\n const newOption = { rect, internalPosition, visibleArea };\n bestOption = getBestOption(newOption, bestOption);\n }\n\n // Use best possible placement.\n const internalPosition = bestOption?.internalPosition || 'right-top';\n // Get default rect for that placement.\n const rect = RECTANGLE_CALCULATIONS[internalPosition]({ body, trigger, arrow });\n\n // Get largest possible rect that fits into the viewport or container.\n\n // We allow the popover to overflow the viewport if allowVerticalOverflow is true _and_ the popover will be anchored to the top or the bottom.\n // If it is anchored to the right or left, we consider that it should have enough vertical space so that applying scroll to it is a better option.\n const tallestBoundingContainer = getTallestRect(viewport, container);\n const boundingContainer =\n allowVerticalOverflow && isTopOrBottom(internalPosition)\n ? {\n top: tallestBoundingContainer.top,\n height: tallestBoundingContainer.height,\n left: viewport.left,\n width: viewport.width,\n }\n : viewport;\n\n const optimizedRect = fitIntoContainer(rect, boundingContainer);\n\n // If largest possible rect is shorter than original - set body scroll.\n const scrollable = optimizedRect.height < rect.height;\n\n return { internalPosition, rect: optimizedRect, scrollable };\n}\n\nfunction getBestOption(option1: CandidatePosition, option2: CandidatePosition | null) {\n // Within calculatePosition, the only case where option2 will not be defined will be in the first call.\n // The only case where the visibleArea of an option will be null is when the popover is totally outside of the viewport.\n if (!option2?.visibleArea) {\n return option1;\n }\n if (!option1.visibleArea) {\n return option2;\n }\n // Only if none of the two options overflows horizontally, choose the best based on the visible height.\n if (option1.visibleArea.width === option2.visibleArea.width) {\n return option1.visibleArea.height > option2.visibleArea.height ? option1 : option2;\n }\n // Otherwise, choose the option that is less cut off horizontally.\n return option1.visibleArea.width > option2.visibleArea.width ? option1 : option2;\n}\n\nexport function getOffsetDimensions(element: HTMLElement) {\n return { offsetHeight: element.offsetHeight, offsetWidth: element.offsetWidth };\n}\n\nexport function getDimensions(element: HTMLElement) {\n const computedStyle = getComputedStyle(element);\n return {\n width: parseFloat(computedStyle.width),\n height: parseFloat(computedStyle.height),\n };\n}\n\nfunction isTopOrBottom(internalPosition: InternalPosition) {\n return ['top', 'bottom'].includes(internalPosition.split('-')[0]);\n}\n"]}