@cloudscape-design/components 3.0.490 → 3.0.492
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/internal/components/chart-popover/index.js +3 -1
- package/internal/components/chart-popover/index.js.map +1 -1
- package/internal/components/dropdown/dropdown-fit-handler.d.ts +5 -5
- package/internal/components/dropdown/dropdown-fit-handler.d.ts.map +1 -1
- package/internal/components/dropdown/dropdown-fit-handler.js.map +1 -1
- package/internal/components/option/highlight-match.d.ts.map +1 -1
- package/internal/components/option/highlight-match.js +5 -0
- package/internal/components/option/highlight-match.js.map +1 -1
- package/internal/environment.js +1 -1
- package/internal/environment.json +1 -1
- package/internal/manifest.json +1 -1
- package/internal/utils/scrollable-containers.d.ts +9 -2
- package/internal/utils/scrollable-containers.d.ts.map +1 -1
- package/internal/utils/scrollable-containers.js +25 -0
- package/internal/utils/scrollable-containers.js.map +1 -1
- package/mixed-line-bar-chart/chart-container.js +2 -2
- package/mixed-line-bar-chart/chart-container.js.map +1 -1
- package/package.json +1 -1
- package/popover/container.d.ts +3 -1
- package/popover/container.d.ts.map +1 -1
- package/popover/container.js +16 -127
- package/popover/container.js.map +1 -1
- package/popover/interfaces.d.ts +2 -2
- package/popover/interfaces.d.ts.map +1 -1
- package/popover/interfaces.js.map +1 -1
- package/popover/use-popover-position.d.ts +20 -0
- package/popover/use-popover-position.d.ts.map +1 -0
- package/popover/use-popover-position.js +149 -0
- package/popover/use-popover-position.js.map +1 -0
- package/popover/utils/positions.d.ts +10 -9
- package/popover/utils/positions.d.ts.map +1 -1
- package/popover/utils/positions.js +69 -48
- package/popover/utils/positions.js.map +1 -1
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@cloudscape-design/components","main":"./index.js","exports":{".":"./index.js","./package.json":"./package.json","./theming":"./theming/index.js","./test-utils/dom":"./test-utils/dom/index.js","./test-utils/selectors":"./test-utils/selectors/index.js","./interfaces":"./interfaces.js","./contexts/form-field":"./contexts/form-field.js","./alert":"./alert/index.js","./anchor-navigation":"./anchor-navigation/index.js","./annotation-context":"./annotation-context/index.js","./app-layout":"./app-layout/index.js","./area-chart":"./area-chart/index.js","./attribute-editor":"./attribute-editor/index.js","./autosuggest":"./autosuggest/index.js","./badge":"./badge/index.js","./bar-chart":"./bar-chart/index.js","./box":"./box/index.js","./breadcrumb-group":"./breadcrumb-group/index.js","./button":"./button/index.js","./button-dropdown":"./button-dropdown/index.js","./calendar":"./calendar/index.js","./cards":"./cards/index.js","./checkbox":"./checkbox/index.js","./code-editor":"./code-editor/index.js","./collection-preferences":"./collection-preferences/index.js","./column-layout":"./column-layout/index.js","./container":"./container/index.js","./content-layout":"./content-layout/index.js","./date-input":"./date-input/index.js","./date-picker":"./date-picker/index.js","./date-range-picker":"./date-range-picker/index.js","./drawer":"./drawer/index.js","./expandable-section":"./expandable-section/index.js","./file-upload":"./file-upload/index.js","./flashbar":"./flashbar/index.js","./form":"./form/index.js","./form-field":"./form-field/index.js","./grid":"./grid/index.js","./header":"./header/index.js","./help-panel":"./help-panel/index.js","./hotspot":"./hotspot/index.js","./icon":"./icon/index.js","./input":"./input/index.js","./line-chart":"./line-chart/index.js","./link":"./link/index.js","./mixed-line-bar-chart":"./mixed-line-bar-chart/index.js","./modal":"./modal/index.js","./multiselect":"./multiselect/index.js","./pagination":"./pagination/index.js","./pie-chart":"./pie-chart/index.js","./popover":"./popover/index.js","./progress-bar":"./progress-bar/index.js","./property-filter":"./property-filter/index.js","./radio-group":"./radio-group/index.js","./s3-resource-selector":"./s3-resource-selector/index.js","./segmented-control":"./segmented-control/index.js","./select":"./select/index.js","./side-navigation":"./side-navigation/index.js","./space-between":"./space-between/index.js","./spinner":"./spinner/index.js","./split-panel":"./split-panel/index.js","./status-indicator":"./status-indicator/index.js","./table":"./table/index.js","./tabs":"./tabs/index.js","./tag-editor":"./tag-editor/index.js","./text-content":"./text-content/index.js","./text-filter":"./text-filter/index.js","./textarea":"./textarea/index.js","./tiles":"./tiles/index.js","./time-input":"./time-input/index.js","./toggle":"./toggle/index.js","./token-group":"./token-group/index.js","./top-navigation":"./top-navigation/index.js","./tutorial-panel":"./tutorial-panel/index.js","./wizard":"./wizard/index.js","./top-navigation/1.0-beta":"./top-navigation/1.0-beta/index.js","./i18n":"./i18n/index.js","./i18n/messages/all.all":"./i18n/messages/all.all.js","./i18n/messages/all.all.json":"./i18n/messages/all.all.json","./i18n/messages/all.de":"./i18n/messages/all.de.js","./i18n/messages/all.de.json":"./i18n/messages/all.de.json","./i18n/messages/all.en-GB":"./i18n/messages/all.en-GB.js","./i18n/messages/all.en-GB.json":"./i18n/messages/all.en-GB.json","./i18n/messages/all.en":"./i18n/messages/all.en.js","./i18n/messages/all.en.json":"./i18n/messages/all.en.json","./i18n/messages/all.es":"./i18n/messages/all.es.js","./i18n/messages/all.es.json":"./i18n/messages/all.es.json","./i18n/messages/all.fr":"./i18n/messages/all.fr.js","./i18n/messages/all.fr.json":"./i18n/messages/all.fr.json","./i18n/messages/all.id":"./i18n/messages/all.id.js","./i18n/messages/all.id.json":"./i18n/messages/all.id.json","./i18n/messages/all.it":"./i18n/messages/all.it.js","./i18n/messages/all.it.json":"./i18n/messages/all.it.json","./i18n/messages/all.ja":"./i18n/messages/all.ja.js","./i18n/messages/all.ja.json":"./i18n/messages/all.ja.json","./i18n/messages/all.ko":"./i18n/messages/all.ko.js","./i18n/messages/all.ko.json":"./i18n/messages/all.ko.json","./i18n/messages/all.pt-BR":"./i18n/messages/all.pt-BR.js","./i18n/messages/all.pt-BR.json":"./i18n/messages/all.pt-BR.json","./i18n/messages/all.th":"./i18n/messages/all.th.js","./i18n/messages/all.th.json":"./i18n/messages/all.th.json","./i18n/messages/all.tr":"./i18n/messages/all.tr.js","./i18n/messages/all.tr.json":"./i18n/messages/all.tr.json","./i18n/messages/all.zh-CN":"./i18n/messages/all.zh-CN.js","./i18n/messages/all.zh-CN.json":"./i18n/messages/all.zh-CN.json","./i18n/messages/all.zh-TW":"./i18n/messages/all.zh-TW.js","./i18n/messages/all.zh-TW.json":"./i18n/messages/all.zh-TW.json"},"sideEffects":["*.css","./internal/base-component/index.js","./internal/base-component/styles.css.js"],"version":"3.0.
|
|
1
|
+
{"name":"@cloudscape-design/components","main":"./index.js","exports":{".":"./index.js","./package.json":"./package.json","./theming":"./theming/index.js","./test-utils/dom":"./test-utils/dom/index.js","./test-utils/selectors":"./test-utils/selectors/index.js","./interfaces":"./interfaces.js","./contexts/form-field":"./contexts/form-field.js","./alert":"./alert/index.js","./anchor-navigation":"./anchor-navigation/index.js","./annotation-context":"./annotation-context/index.js","./app-layout":"./app-layout/index.js","./area-chart":"./area-chart/index.js","./attribute-editor":"./attribute-editor/index.js","./autosuggest":"./autosuggest/index.js","./badge":"./badge/index.js","./bar-chart":"./bar-chart/index.js","./box":"./box/index.js","./breadcrumb-group":"./breadcrumb-group/index.js","./button":"./button/index.js","./button-dropdown":"./button-dropdown/index.js","./calendar":"./calendar/index.js","./cards":"./cards/index.js","./checkbox":"./checkbox/index.js","./code-editor":"./code-editor/index.js","./collection-preferences":"./collection-preferences/index.js","./column-layout":"./column-layout/index.js","./container":"./container/index.js","./content-layout":"./content-layout/index.js","./date-input":"./date-input/index.js","./date-picker":"./date-picker/index.js","./date-range-picker":"./date-range-picker/index.js","./drawer":"./drawer/index.js","./expandable-section":"./expandable-section/index.js","./file-upload":"./file-upload/index.js","./flashbar":"./flashbar/index.js","./form":"./form/index.js","./form-field":"./form-field/index.js","./grid":"./grid/index.js","./header":"./header/index.js","./help-panel":"./help-panel/index.js","./hotspot":"./hotspot/index.js","./icon":"./icon/index.js","./input":"./input/index.js","./line-chart":"./line-chart/index.js","./link":"./link/index.js","./mixed-line-bar-chart":"./mixed-line-bar-chart/index.js","./modal":"./modal/index.js","./multiselect":"./multiselect/index.js","./pagination":"./pagination/index.js","./pie-chart":"./pie-chart/index.js","./popover":"./popover/index.js","./progress-bar":"./progress-bar/index.js","./property-filter":"./property-filter/index.js","./radio-group":"./radio-group/index.js","./s3-resource-selector":"./s3-resource-selector/index.js","./segmented-control":"./segmented-control/index.js","./select":"./select/index.js","./side-navigation":"./side-navigation/index.js","./space-between":"./space-between/index.js","./spinner":"./spinner/index.js","./split-panel":"./split-panel/index.js","./status-indicator":"./status-indicator/index.js","./table":"./table/index.js","./tabs":"./tabs/index.js","./tag-editor":"./tag-editor/index.js","./text-content":"./text-content/index.js","./text-filter":"./text-filter/index.js","./textarea":"./textarea/index.js","./tiles":"./tiles/index.js","./time-input":"./time-input/index.js","./toggle":"./toggle/index.js","./token-group":"./token-group/index.js","./top-navigation":"./top-navigation/index.js","./tutorial-panel":"./tutorial-panel/index.js","./wizard":"./wizard/index.js","./top-navigation/1.0-beta":"./top-navigation/1.0-beta/index.js","./i18n":"./i18n/index.js","./i18n/messages/all.all":"./i18n/messages/all.all.js","./i18n/messages/all.all.json":"./i18n/messages/all.all.json","./i18n/messages/all.de":"./i18n/messages/all.de.js","./i18n/messages/all.de.json":"./i18n/messages/all.de.json","./i18n/messages/all.en-GB":"./i18n/messages/all.en-GB.js","./i18n/messages/all.en-GB.json":"./i18n/messages/all.en-GB.json","./i18n/messages/all.en":"./i18n/messages/all.en.js","./i18n/messages/all.en.json":"./i18n/messages/all.en.json","./i18n/messages/all.es":"./i18n/messages/all.es.js","./i18n/messages/all.es.json":"./i18n/messages/all.es.json","./i18n/messages/all.fr":"./i18n/messages/all.fr.js","./i18n/messages/all.fr.json":"./i18n/messages/all.fr.json","./i18n/messages/all.id":"./i18n/messages/all.id.js","./i18n/messages/all.id.json":"./i18n/messages/all.id.json","./i18n/messages/all.it":"./i18n/messages/all.it.js","./i18n/messages/all.it.json":"./i18n/messages/all.it.json","./i18n/messages/all.ja":"./i18n/messages/all.ja.js","./i18n/messages/all.ja.json":"./i18n/messages/all.ja.json","./i18n/messages/all.ko":"./i18n/messages/all.ko.js","./i18n/messages/all.ko.json":"./i18n/messages/all.ko.json","./i18n/messages/all.pt-BR":"./i18n/messages/all.pt-BR.js","./i18n/messages/all.pt-BR.json":"./i18n/messages/all.pt-BR.json","./i18n/messages/all.th":"./i18n/messages/all.th.js","./i18n/messages/all.th.json":"./i18n/messages/all.th.json","./i18n/messages/all.tr":"./i18n/messages/all.tr.js","./i18n/messages/all.tr.json":"./i18n/messages/all.tr.json","./i18n/messages/all.zh-CN":"./i18n/messages/all.zh-CN.js","./i18n/messages/all.zh-CN.json":"./i18n/messages/all.zh-CN.json","./i18n/messages/all.zh-TW":"./i18n/messages/all.zh-TW.js","./i18n/messages/all.zh-TW.json":"./i18n/messages/all.zh-TW.json"},"sideEffects":["*.css","./internal/base-component/index.js","./internal/base-component/styles.css.js"],"version":"3.0.492","repository":{"type":"git","url":"https://github.com/cloudscape-design/components.git"},"homepage":"https://cloudscape.design","dependencies":{"@cloudscape-design/collection-hooks":"^1.0.0","@cloudscape-design/component-toolkit":"^1.0.0-beta","@cloudscape-design/test-utils-core":"^1.0.0","@cloudscape-design/theming-runtime":"^1.0.0","@dnd-kit/core":"^6.0.8","@dnd-kit/sortable":"^7.0.2","@dnd-kit/utilities":"^3.2.1","@juggle/resize-observer":"^3.3.1","ace-builds":"^1.23.0","balanced-match":"^1.0.2","clsx":"^1.1.0","d3-shape":"^1.3.7","date-fns":"^2.25.0","intl-messageformat":"^10.3.1","mnth":"^2.0.0","react-keyed-flatten-children":"^1.3.0","react-transition-group":"^4.4.2","react-virtual":"^2.8.2","tslib":"^2.4.0","weekstart":"^1.1.0"},"peerDependencies":{"react":"^16.8 || ^17 || ^18","react-dom":"^16.8 || ^17 || ^18"},"license":"Apache-2.0"}
|
package/popover/container.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface PopoverContainerProps {
|
|
|
22
22
|
fixedWidth: boolean;
|
|
23
23
|
variant?: 'annotation';
|
|
24
24
|
keepPosition?: boolean;
|
|
25
|
+
allowScrollToFit?: boolean;
|
|
26
|
+
allowVerticalOverflow?: boolean;
|
|
25
27
|
}
|
|
26
|
-
export default function PopoverContainer({ position, trackRef, trackKey, arrow, children, zIndex, renderWithPortal, size, fixedWidth, variant, keepPosition, }: PopoverContainerProps): JSX.Element;
|
|
28
|
+
export default function PopoverContainer({ position, trackRef, trackKey, arrow, children, zIndex, renderWithPortal, size, fixedWidth, variant, keepPosition, allowScrollToFit, allowVerticalOverflow, }: PopoverContainerProps): JSX.Element;
|
|
27
29
|
//# sourceMappingURL=container.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"lib/default/","sources":["popover/container.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"lib/default/","sources":["popover/container.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAKvD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAK9D,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACnC;;;;;;;;MAQE;IACF,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC;IAC9D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,MAAM,EACN,gBAAgB,EAChB,IAAI,EACJ,UAAU,EACV,OAAO,EACP,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,GACtB,EAAE,qBAAqB,eAgGvB"}
|
package/popover/container.js
CHANGED
|
@@ -1,110 +1,31 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import React, {
|
|
3
|
+
import React, { useLayoutEffect, useRef } from 'react';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
import { nodeContains } from '@cloudscape-design/component-toolkit/dom';
|
|
6
6
|
import { useResizeObserver } from '@cloudscape-design/component-toolkit/internal';
|
|
7
|
-
import { getContainingBlock } from '../internal/utils/dom';
|
|
8
|
-
import { calculatePosition, getDimensions, getOffsetDimensions } from './utils/positions';
|
|
9
7
|
import styles from './styles.css.js';
|
|
10
8
|
import { useVisualRefresh } from '../internal/hooks/use-visual-mode';
|
|
11
|
-
|
|
12
|
-
export default function PopoverContainer({ position, trackRef, trackKey, arrow, children, zIndex, renderWithPortal, size, fixedWidth, variant, keepPosition, }) {
|
|
9
|
+
import usePopoverPosition from './use-popover-position.js';
|
|
10
|
+
export default function PopoverContainer({ position, trackRef, trackKey, arrow, children, zIndex, renderWithPortal, size, fixedWidth, variant, keepPosition, allowScrollToFit, allowVerticalOverflow, }) {
|
|
13
11
|
const bodyRef = useRef(null);
|
|
14
12
|
const contentRef = useRef(null);
|
|
15
13
|
const popoverRef = useRef(null);
|
|
16
14
|
const arrowRef = useRef(null);
|
|
17
|
-
const previousInternalPositionRef = useRef(null);
|
|
18
|
-
const [popoverStyle, setPopoverStyle] = useState(INITIAL_STYLES);
|
|
19
|
-
const [internalPosition, setInternalPosition] = useState(null);
|
|
20
15
|
const isRefresh = useVisualRefresh();
|
|
21
|
-
// Store the handler in a ref so that it can still be replaced from outside of the listener closure.
|
|
22
|
-
const positionHandlerRef = useRef(() => { });
|
|
23
16
|
// Updates the position handler.
|
|
24
|
-
const updatePositionHandler
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// or track does not belong to the document - bail on calculating dimensions.
|
|
37
|
-
const { offsetWidth, offsetHeight } = getOffsetDimensions(popover);
|
|
38
|
-
if (offsetWidth === 0 || offsetHeight === 0 || !nodeContains(document.body, track)) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
// Imperatively move body off-screen to give it room to expand.
|
|
42
|
-
// Not doing this in React because this recalculation should happen
|
|
43
|
-
// in the span of a single frame without rerendering anything.
|
|
44
|
-
const prevTop = popover.style.top;
|
|
45
|
-
const prevLeft = popover.style.left;
|
|
46
|
-
popover.style.top = '0';
|
|
47
|
-
popover.style.left = '0';
|
|
48
|
-
// Imperatively remove body styles that can remain from the previous computation.
|
|
49
|
-
body.style.maxHeight = '';
|
|
50
|
-
body.style.overflowX = '';
|
|
51
|
-
body.style.overflowY = '';
|
|
52
|
-
// Get rects representing key elements
|
|
53
|
-
// Use getComputedStyle for arrowRect to avoid modifications made by transform
|
|
54
|
-
const viewportRect = getViewportRect(document.defaultView);
|
|
55
|
-
const trackRect = track.getBoundingClientRect();
|
|
56
|
-
const arrowRect = getDimensions(arrow);
|
|
57
|
-
const containingBlock = getContainingBlock(popover);
|
|
58
|
-
const containingBlockRect = containingBlock ? containingBlock.getBoundingClientRect() : viewportRect;
|
|
59
|
-
const bodyBorderWidth = getBorderWidth(body);
|
|
60
|
-
const contentRect = contentRef.current.getBoundingClientRect();
|
|
61
|
-
const contentBoundingBox = {
|
|
62
|
-
width: contentRect.width + 2 * bodyBorderWidth,
|
|
63
|
-
height: contentRect.height + 2 * bodyBorderWidth,
|
|
64
|
-
};
|
|
65
|
-
// When keepPosition is true and the recalculation was triggered by a resize of the popover content,
|
|
66
|
-
// we maintain the previously defined internal position,
|
|
67
|
-
// but we still call calculatePosition to know if the popover should be scrollable.
|
|
68
|
-
const shouldKeepPosition = keepPosition && onContentResize && !!previousInternalPositionRef.current;
|
|
69
|
-
const fixedInternalPosition = (_a = (shouldKeepPosition && previousInternalPositionRef.current)) !== null && _a !== void 0 ? _a : undefined;
|
|
70
|
-
// Calculate the arrow direction and viewport-relative position of the popover.
|
|
71
|
-
const { scrollable, internalPosition: newInternalPosition, boundingOffset, } = calculatePosition({
|
|
72
|
-
preferredPosition: position,
|
|
73
|
-
fixedInternalPosition,
|
|
74
|
-
trigger: trackRect,
|
|
75
|
-
arrow: arrowRect,
|
|
76
|
-
body: contentBoundingBox,
|
|
77
|
-
container: containingBlock ? containingBlockRect : getDocumentRect(document),
|
|
78
|
-
viewport: viewportRect,
|
|
79
|
-
renderWithPortal,
|
|
80
|
-
});
|
|
81
|
-
// Get the position of the popover relative to the offset parent.
|
|
82
|
-
const popoverOffset = toRelativePosition(boundingOffset, containingBlockRect);
|
|
83
|
-
// Cache the distance between the trigger and the popover (which stays the same as you scroll),
|
|
84
|
-
// and use that to recalculate the new popover position.
|
|
85
|
-
const trackRelativeOffset = toRelativePosition(popoverOffset, toRelativePosition(trackRect, containingBlockRect));
|
|
86
|
-
// Bring back the container to its original position to prevent any flashing.
|
|
87
|
-
popover.style.top = prevTop;
|
|
88
|
-
popover.style.left = prevLeft;
|
|
89
|
-
// Allow popover body to scroll if can't fit the popover into the container/viewport otherwise.
|
|
90
|
-
if (scrollable) {
|
|
91
|
-
body.style.maxHeight = boundingOffset.height + 'px';
|
|
92
|
-
body.style.overflowX = 'hidden';
|
|
93
|
-
body.style.overflowY = 'auto';
|
|
94
|
-
}
|
|
95
|
-
// Remember the internal position in case we want to keep it later.
|
|
96
|
-
previousInternalPositionRef.current = newInternalPosition;
|
|
97
|
-
// Position the popover
|
|
98
|
-
setInternalPosition(newInternalPosition);
|
|
99
|
-
setPopoverStyle({ top: popoverOffset.top, left: popoverOffset.left });
|
|
100
|
-
positionHandlerRef.current = () => {
|
|
101
|
-
const newTrackOffset = toRelativePosition(track.getBoundingClientRect(), containingBlock ? containingBlock.getBoundingClientRect() : viewportRect);
|
|
102
|
-
setPopoverStyle({
|
|
103
|
-
top: newTrackOffset.top + trackRelativeOffset.top,
|
|
104
|
-
left: newTrackOffset.left + trackRelativeOffset.left,
|
|
105
|
-
});
|
|
106
|
-
};
|
|
107
|
-
}, [trackRef, keepPosition, position, renderWithPortal]);
|
|
17
|
+
const { updatePositionHandler, popoverStyle, internalPosition, positionHandlerRef } = usePopoverPosition({
|
|
18
|
+
popoverRef,
|
|
19
|
+
bodyRef,
|
|
20
|
+
arrowRef,
|
|
21
|
+
trackRef,
|
|
22
|
+
contentRef,
|
|
23
|
+
allowScrollToFit,
|
|
24
|
+
allowVerticalOverflow,
|
|
25
|
+
preferredPosition: position,
|
|
26
|
+
renderWithPortal,
|
|
27
|
+
keepPosition,
|
|
28
|
+
});
|
|
108
29
|
// Recalculate position when properties change.
|
|
109
30
|
useLayoutEffect(() => {
|
|
110
31
|
updatePositionHandler();
|
|
@@ -144,7 +65,7 @@ export default function PopoverContainer({ position, trackRef, trackKey, arrow,
|
|
|
144
65
|
window.removeEventListener('resize', updatePositionOnResize);
|
|
145
66
|
window.removeEventListener('scroll', refreshPosition, true);
|
|
146
67
|
};
|
|
147
|
-
}, [keepPosition, trackRef, updatePositionHandler]);
|
|
68
|
+
}, [keepPosition, positionHandlerRef, trackRef, updatePositionHandler]);
|
|
148
69
|
return (React.createElement("div", { ref: popoverRef, style: Object.assign(Object.assign({}, popoverStyle), { zIndex }), className: clsx(styles.container, isRefresh && styles.refresh) },
|
|
149
70
|
React.createElement("div", { ref: arrowRef, className: clsx(styles[`container-arrow`], styles[`container-arrow-position-${internalPosition}`]), "aria-hidden": true }, arrow(internalPosition)),
|
|
150
71
|
React.createElement("div", { ref: bodyRef, className: clsx(styles['container-body'], styles[`container-body-size-${size}`], {
|
|
@@ -153,36 +74,4 @@ export default function PopoverContainer({ position, trackRef, trackKey, arrow,
|
|
|
153
74
|
}) },
|
|
154
75
|
React.createElement("div", { ref: contentRef }, children))));
|
|
155
76
|
}
|
|
156
|
-
function getBorderWidth(element) {
|
|
157
|
-
return parseInt(getComputedStyle(element).borderWidth) || 0;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Convert a viewport-relative offset to an element-relative offset.
|
|
161
|
-
*/
|
|
162
|
-
function toRelativePosition(element, parent) {
|
|
163
|
-
return {
|
|
164
|
-
top: element.top - parent.top,
|
|
165
|
-
left: element.left - parent.left,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Get a BoundingOffset that represents the visible viewport.
|
|
170
|
-
*/
|
|
171
|
-
function getViewportRect(window) {
|
|
172
|
-
return {
|
|
173
|
-
top: 0,
|
|
174
|
-
left: 0,
|
|
175
|
-
width: window.innerWidth,
|
|
176
|
-
height: window.innerHeight,
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
function getDocumentRect(document) {
|
|
180
|
-
const { top, left } = document.documentElement.getBoundingClientRect();
|
|
181
|
-
return {
|
|
182
|
-
top,
|
|
183
|
-
left,
|
|
184
|
-
width: document.documentElement.scrollWidth,
|
|
185
|
-
height: document.documentElement.scrollHeight,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
77
|
//# sourceMappingURL=container.js.map
|
package/popover/container.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.js","sourceRoot":"lib/default/","sources":["popover/container.tsx"],"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 React, { CSSProperties, useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\nimport { nodeContains } from '@cloudscape-design/component-toolkit/dom';\nimport { useResizeObserver } from '@cloudscape-design/component-toolkit/internal';\n\nimport { getContainingBlock } from '../internal/utils/dom';\nimport { BoundingOffset, InternalPosition, Offset, PopoverProps } from './interfaces';\nimport { calculatePosition, getDimensions, getOffsetDimensions } from './utils/positions';\nimport styles from './styles.css.js';\nimport { useVisualRefresh } from '../internal/hooks/use-visual-mode';\n\nexport interface PopoverContainerProps {\n /** References the element the container is positioned against. */\n trackRef: React.RefObject<Element>;\n /**\n Used to update the container position in case track or track position changes:\n \n const trackRef = useRef<Element>(null)\n return (<>\n <Track style={getPosition(selectedItemId)} ref={trackRef} />\n <PopoverContainer trackRef={trackRef} trackKey={selectedItemId} .../>\n </>)\n */\n trackKey?: string | number;\n position: PopoverProps.Position;\n zIndex?: React.CSSProperties['zIndex'];\n arrow: (position: InternalPosition | null) => React.ReactNode;\n children: React.ReactNode;\n renderWithPortal?: boolean;\n size: PopoverProps.Size;\n fixedWidth: boolean;\n variant?: 'annotation';\n // When keepPosition is true, the popover will not recalculate its position when it resizes nor when it receives clicks.\n keepPosition?: boolean;\n}\n\nconst INITIAL_STYLES: CSSProperties = { top: -9999, left: -9999 };\n\nexport default function PopoverContainer({\n position,\n trackRef,\n trackKey,\n arrow,\n children,\n zIndex,\n renderWithPortal,\n size,\n fixedWidth,\n variant,\n keepPosition,\n}: PopoverContainerProps) {\n const bodyRef = useRef<HTMLDivElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const popoverRef = useRef<HTMLDivElement | null>(null);\n const arrowRef = useRef<HTMLDivElement | null>(null);\n const previousInternalPositionRef = useRef<InternalPosition | null>(null);\n\n const [popoverStyle, setPopoverStyle] = useState<CSSProperties>(INITIAL_STYLES);\n const [internalPosition, setInternalPosition] = useState<InternalPosition | null>(null);\n const isRefresh = useVisualRefresh();\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 // Updates the position handler.\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 boundingOffset,\n } = calculatePosition({\n preferredPosition: position,\n fixedInternalPosition,\n trigger: trackRect,\n arrow: arrowRect,\n body: contentBoundingBox,\n container: containingBlock ? containingBlockRect : getDocumentRect(document),\n viewport: viewportRect,\n renderWithPortal,\n });\n\n // Get the position of the popover relative to the offset parent.\n const popoverOffset = toRelativePosition(boundingOffset, 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 = boundingOffset.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\n // Position the popover\n setInternalPosition(newInternalPosition);\n setPopoverStyle({ top: popoverOffset.top, left: popoverOffset.left });\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 [trackRef, keepPosition, position, renderWithPortal]\n );\n\n // Recalculate position when properties change.\n useLayoutEffect(() => {\n updatePositionHandler();\n }, [updatePositionHandler, trackKey]);\n\n // Recalculate position when content size changes.\n useResizeObserver(contentRef, () => {\n updatePositionHandler(true);\n });\n\n // Recalculate position on DOM events.\n useLayoutEffect(() => {\n /*\n This is a heuristic. Some layout changes are caused by user clicks (e.g. toggling the tools panel, submitting a form),\n and by tracking the click event we can adapt the popover's position to the new layout.\n\n TODO: extend this to Enter and Spacebar?\n */\n\n const onClick = (event: UIEvent | KeyboardEvent) => {\n if (\n // Do not update position if keepPosition is true.\n keepPosition ||\n // If the click was on the trigger, this will make the popover appear or disappear,\n // so no need to update its position either in this case.\n nodeContains(trackRef.current, event.target)\n ) {\n return;\n }\n\n requestAnimationFrame(() => {\n updatePositionHandler();\n });\n };\n\n const updatePositionOnResize = () => requestAnimationFrame(() => updatePositionHandler());\n const refreshPosition = () => requestAnimationFrame(() => positionHandlerRef.current());\n\n window.addEventListener('click', onClick);\n window.addEventListener('resize', updatePositionOnResize);\n window.addEventListener('scroll', refreshPosition, true);\n\n return () => {\n window.removeEventListener('click', onClick);\n window.removeEventListener('resize', updatePositionOnResize);\n window.removeEventListener('scroll', refreshPosition, true);\n };\n }, [keepPosition, trackRef, updatePositionHandler]);\n\n return (\n <div\n ref={popoverRef}\n style={{ ...popoverStyle, zIndex }}\n className={clsx(styles.container, isRefresh && styles.refresh)}\n >\n <div\n ref={arrowRef}\n className={clsx(styles[`container-arrow`], styles[`container-arrow-position-${internalPosition}`])}\n aria-hidden={true}\n >\n {arrow(internalPosition)}\n </div>\n\n <div\n ref={bodyRef}\n className={clsx(styles['container-body'], styles[`container-body-size-${size}`], {\n [styles['fixed-width']]: fixedWidth,\n [styles[`container-body-variant-${variant}`]]: variant,\n })}\n >\n <div ref={contentRef}>{children}</div>\n </div>\n </div>\n );\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 BoundingOffset that represents the visible viewport.\n */\nfunction getViewportRect(window: Window): BoundingOffset {\n return {\n top: 0,\n left: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n}\n\nfunction getDocumentRect(document: Document): BoundingOffset {\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
|
+
{"version":3,"file":"container.js","sourceRoot":"lib/default/","sources":["popover/container.tsx"],"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 React, { useLayoutEffect, useRef } from 'react';\nimport clsx from 'clsx';\nimport { nodeContains } from '@cloudscape-design/component-toolkit/dom';\nimport { useResizeObserver } from '@cloudscape-design/component-toolkit/internal';\n\nimport { InternalPosition, PopoverProps } from './interfaces';\nimport styles from './styles.css.js';\nimport { useVisualRefresh } from '../internal/hooks/use-visual-mode';\nimport usePopoverPosition from './use-popover-position.js';\n\nexport interface PopoverContainerProps {\n /** References the element the container is positioned against. */\n trackRef: React.RefObject<Element>;\n /**\n Used to update the container position in case track or track position changes:\n \n const trackRef = useRef<Element>(null)\n return (<>\n <Track style={getPosition(selectedItemId)} ref={trackRef} />\n <PopoverContainer trackRef={trackRef} trackKey={selectedItemId} .../>\n </>)\n */\n trackKey?: string | number;\n position: PopoverProps.Position;\n zIndex?: React.CSSProperties['zIndex'];\n arrow: (position: InternalPosition | null) => React.ReactNode;\n children: React.ReactNode;\n renderWithPortal?: boolean;\n size: PopoverProps.Size;\n fixedWidth: boolean;\n variant?: 'annotation';\n // When keepPosition is true, the popover will not recalculate its position when it resizes nor when it receives clicks.\n keepPosition?: boolean;\n // When allowScrollToFit is true, we will scroll to the the popover if it overflows the viewport even when choosing the best possible position for it.\n // Do not use this if the popover is open on hover, in order to avoid unexpected movement.\n allowScrollToFit?: boolean;\n allowVerticalOverflow?: boolean;\n}\n\nexport default function PopoverContainer({\n position,\n trackRef,\n trackKey,\n arrow,\n children,\n zIndex,\n renderWithPortal,\n size,\n fixedWidth,\n variant,\n keepPosition,\n allowScrollToFit,\n allowVerticalOverflow,\n}: PopoverContainerProps) {\n const bodyRef = useRef<HTMLDivElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const popoverRef = useRef<HTMLDivElement | null>(null);\n const arrowRef = useRef<HTMLDivElement | null>(null);\n\n const isRefresh = useVisualRefresh();\n\n // Updates the position handler.\n const { updatePositionHandler, popoverStyle, internalPosition, positionHandlerRef } = usePopoverPosition({\n popoverRef,\n bodyRef,\n arrowRef,\n trackRef,\n contentRef,\n allowScrollToFit,\n allowVerticalOverflow,\n preferredPosition: position,\n renderWithPortal,\n keepPosition,\n });\n\n // Recalculate position when properties change.\n useLayoutEffect(() => {\n updatePositionHandler();\n }, [updatePositionHandler, trackKey]);\n\n // Recalculate position when content size changes.\n useResizeObserver(contentRef, () => {\n updatePositionHandler(true);\n });\n\n // Recalculate position on DOM events.\n useLayoutEffect(() => {\n /*\n This is a heuristic. Some layout changes are caused by user clicks (e.g. toggling the tools panel, submitting a form),\n and by tracking the click event we can adapt the popover's position to the new layout.\n\n TODO: extend this to Enter and Spacebar?\n */\n\n const onClick = (event: UIEvent | KeyboardEvent) => {\n if (\n // Do not update position if keepPosition is true.\n keepPosition ||\n // If the click was on the trigger, this will make the popover appear or disappear,\n // so no need to update its position either in this case.\n nodeContains(trackRef.current, event.target)\n ) {\n return;\n }\n\n requestAnimationFrame(() => {\n updatePositionHandler();\n });\n };\n\n const updatePositionOnResize = () => requestAnimationFrame(() => updatePositionHandler());\n const refreshPosition = () => requestAnimationFrame(() => positionHandlerRef.current());\n\n window.addEventListener('click', onClick);\n window.addEventListener('resize', updatePositionOnResize);\n window.addEventListener('scroll', refreshPosition, true);\n\n return () => {\n window.removeEventListener('click', onClick);\n window.removeEventListener('resize', updatePositionOnResize);\n window.removeEventListener('scroll', refreshPosition, true);\n };\n }, [keepPosition, positionHandlerRef, trackRef, updatePositionHandler]);\n\n return (\n <div\n ref={popoverRef}\n style={{ ...popoverStyle, zIndex }}\n className={clsx(styles.container, isRefresh && styles.refresh)}\n >\n <div\n ref={arrowRef}\n className={clsx(styles[`container-arrow`], styles[`container-arrow-position-${internalPosition}`])}\n aria-hidden={true}\n >\n {arrow(internalPosition)}\n </div>\n\n <div\n ref={bodyRef}\n className={clsx(styles['container-body'], styles[`container-body-size-${size}`], {\n [styles['fixed-width']]: fixedWidth,\n [styles[`container-body-variant-${variant}`]]: variant,\n })}\n >\n <div ref={contentRef}>{children}</div>\n </div>\n </div>\n );\n}\n"]}
|
package/popover/interfaces.d.ts
CHANGED
|
@@ -68,11 +68,11 @@ export interface Offset {
|
|
|
68
68
|
left: number;
|
|
69
69
|
top: number;
|
|
70
70
|
}
|
|
71
|
-
export interface
|
|
71
|
+
export interface Dimensions {
|
|
72
72
|
width: number;
|
|
73
73
|
height: number;
|
|
74
74
|
}
|
|
75
|
-
export type
|
|
75
|
+
export type BoundingBox = Dimensions & Offset;
|
|
76
76
|
export declare namespace PopoverProps {
|
|
77
77
|
type Position = 'top' | 'right' | 'bottom' | 'left';
|
|
78
78
|
type Size = 'small' | 'medium' | 'large';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.d.ts","sourceRoot":"lib/default/","sources":["popover/interfaces.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC;IAEjC;;OAEG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC;IAEzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;OAIG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC;IAEvC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,cAAc,GACd,UAAU,GACV,aAAa,GACb,YAAY,GACZ,WAAW,GACX,UAAU,GACV,eAAe,GACf,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"lib/default/","sources":["popover/interfaces.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC;IAEjC;;OAEG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC;IAEzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;OAIG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC;IAEvC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,cAAc,GACd,UAAU,GACV,aAAa,GACb,YAAY,GACZ,WAAW,GACX,UAAU,GACV,eAAe,GACf,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAE9C,yBAAiB,YAAY,CAAC;IAC5B,KAAY,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3D,KAAY,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAChD,KAAY,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;CAC7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.js","sourceRoot":"lib/default/","sources":["popover/interfaces.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { BaseComponentProps } from '../internal/base-component';\n\nexport interface PopoverProps extends BaseComponentProps {\n /**\n * Determines where the popover is displayed when opened, relative to the trigger.\n * If the popover doesn't have enough space to open in this direction, it\n * automatically chooses a better direction based on available space.\n */\n position?: PopoverProps.Position;\n\n /**\n * Determines the maximum width for the popover.\n */\n size?: PopoverProps.Size;\n\n /**\n * Expands the popover body to its maximum width regardless of content.\n * For example, use it when you need to place a column layout in the popover content.\n */\n fixedWidth?: boolean;\n\n /**\n * Specifies the type of content inside the trigger region. The following types are available:\n * - `text` - Use for inline text triggers.\n * - `custom` - Use for the [button](/components/button/) component.\n */\n triggerType?: PopoverProps.TriggerType;\n\n /**\n * Adds `aria-label` to the text trigger button. Use this to provide an accessible name for triggers\n * that don't have visible text, and to distinguish between multiple triggers with identical visible text.\n */\n triggerAriaLabel?: string;\n\n /**\n * Element that triggers the popover when selected by the user.\n * @displayname trigger\n */\n children?: React.ReactNode;\n\n /**\n * Specifies optional header text for the popover.\n */\n header?: string;\n\n /**\n * Content of the popover.\n */\n content?: React.ReactNode;\n\n /**\n * Determines whether the dismiss button is shown in the popover body.\n */\n dismissButton?: boolean;\n\n /**\n * Adds an `aria-label` to the dismiss button for accessibility.\n * @i18n\n */\n dismissAriaLabel?: string;\n\n /**\n * By default, the popover is constrained to fit inside its parent\n * [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context).\n * Enabling this property will allow the popover to be rendered in the root stack context using\n * [React Portals](https://reactjs.org/docs/portals.html).\n * Enable this setting if you need the popover to ignore its parent stacking context, such as in side navigation.\n *\n * Note: Using popover rendered with portal within a Modal is not supported.\n */\n renderWithPortal?: boolean;\n}\n\n/**\n * The position the popover is actually in, given space constraints.\n */\nexport type InternalPosition =\n | 'right-top'\n | 'right-bottom'\n | 'left-top'\n | 'left-bottom'\n | 'top-center'\n | 'top-right'\n | 'top-left'\n | 'bottom-center'\n | 'bottom-right'\n | 'bottom-left';\n\nexport interface Offset {\n left: number;\n top: number;\n}\n\nexport interface
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"lib/default/","sources":["popover/interfaces.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { BaseComponentProps } from '../internal/base-component';\n\nexport interface PopoverProps extends BaseComponentProps {\n /**\n * Determines where the popover is displayed when opened, relative to the trigger.\n * If the popover doesn't have enough space to open in this direction, it\n * automatically chooses a better direction based on available space.\n */\n position?: PopoverProps.Position;\n\n /**\n * Determines the maximum width for the popover.\n */\n size?: PopoverProps.Size;\n\n /**\n * Expands the popover body to its maximum width regardless of content.\n * For example, use it when you need to place a column layout in the popover content.\n */\n fixedWidth?: boolean;\n\n /**\n * Specifies the type of content inside the trigger region. The following types are available:\n * - `text` - Use for inline text triggers.\n * - `custom` - Use for the [button](/components/button/) component.\n */\n triggerType?: PopoverProps.TriggerType;\n\n /**\n * Adds `aria-label` to the text trigger button. Use this to provide an accessible name for triggers\n * that don't have visible text, and to distinguish between multiple triggers with identical visible text.\n */\n triggerAriaLabel?: string;\n\n /**\n * Element that triggers the popover when selected by the user.\n * @displayname trigger\n */\n children?: React.ReactNode;\n\n /**\n * Specifies optional header text for the popover.\n */\n header?: string;\n\n /**\n * Content of the popover.\n */\n content?: React.ReactNode;\n\n /**\n * Determines whether the dismiss button is shown in the popover body.\n */\n dismissButton?: boolean;\n\n /**\n * Adds an `aria-label` to the dismiss button for accessibility.\n * @i18n\n */\n dismissAriaLabel?: string;\n\n /**\n * By default, the popover is constrained to fit inside its parent\n * [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context).\n * Enabling this property will allow the popover to be rendered in the root stack context using\n * [React Portals](https://reactjs.org/docs/portals.html).\n * Enable this setting if you need the popover to ignore its parent stacking context, such as in side navigation.\n *\n * Note: Using popover rendered with portal within a Modal is not supported.\n */\n renderWithPortal?: boolean;\n}\n\n/**\n * The position the popover is actually in, given space constraints.\n */\nexport type InternalPosition =\n | 'right-top'\n | 'right-bottom'\n | 'left-top'\n | 'left-bottom'\n | 'top-center'\n | 'top-right'\n | 'top-left'\n | 'bottom-center'\n | 'bottom-right'\n | 'bottom-left';\n\nexport interface Offset {\n left: number;\n top: number;\n}\n\nexport interface Dimensions {\n width: number;\n height: number;\n}\n\nexport type BoundingBox = Dimensions & Offset;\n\nexport namespace PopoverProps {\n export type Position = 'top' | 'right' | 'bottom' | 'left';\n export type Size = 'small' | 'medium' | 'large';\n export type TriggerType = 'text' | 'custom';\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { InternalPosition, Offset, PopoverProps } from './interfaces';
|
|
3
|
+
export default function usePopoverPosition({ popoverRef, bodyRef, arrowRef, trackRef, contentRef, allowScrollToFit, allowVerticalOverflow, preferredPosition, renderWithPortal, keepPosition, }: {
|
|
4
|
+
popoverRef: React.RefObject<HTMLDivElement | null>;
|
|
5
|
+
bodyRef: React.RefObject<HTMLDivElement | null>;
|
|
6
|
+
arrowRef: React.RefObject<HTMLDivElement | null>;
|
|
7
|
+
trackRef: React.RefObject<Element | null>;
|
|
8
|
+
contentRef: React.RefObject<HTMLDivElement | null>;
|
|
9
|
+
allowScrollToFit?: boolean;
|
|
10
|
+
allowVerticalOverflow?: boolean;
|
|
11
|
+
preferredPosition: PopoverProps.Position;
|
|
12
|
+
renderWithPortal?: boolean;
|
|
13
|
+
keepPosition?: boolean;
|
|
14
|
+
}): {
|
|
15
|
+
updatePositionHandler: (onContentResize?: any) => void;
|
|
16
|
+
popoverStyle: Partial<Offset>;
|
|
17
|
+
internalPosition: InternalPosition | null;
|
|
18
|
+
positionHandlerRef: React.MutableRefObject<() => void>;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=use-popover-position.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-popover-position.d.ts","sourceRoot":"lib/default/","sources":["popover/use-popover-position.ts"],"names":[],"mappings":"AAGA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAe,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAMnF,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EACzC,UAAU,EACV,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,GACb,EAAE;IACD,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACnD,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAChD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC1C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACnD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,EAAE,YAAY,CAAC,QAAQ,CAAC;IACzC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;;;;qDAMyC,IAAI;EAiI7C"}
|
|
@@ -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,
|
|
1
|
+
import { PopoverProps, InternalPosition, BoundingBox, Dimensions } from '../interfaces';
|
|
2
2
|
interface CalculatedPosition {
|
|
3
3
|
scrollable?: boolean;
|
|
4
4
|
internalPosition: InternalPosition;
|
|
5
|
-
|
|
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:
|
|
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:
|
|
19
|
-
arrow:
|
|
20
|
-
body:
|
|
21
|
-
container:
|
|
22
|
-
viewport:
|
|
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,
|
|
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"}
|