Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
jperals committed Jan 21, 2025
1 parent 9b68ef0 commit 731bb5c
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 41 deletions.
5 changes: 3 additions & 2 deletions src/internal/components/dropdown/dropdown-fit-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getLogicalBoundingClientRect } from '@cloudscape-design/component-toolk

import { getBreakpointValue } from '../../breakpoints';
import { BoundingBox, getOverflowParentDimensions, getOverflowParents } from '../../utils/scrollable-containers';
import { LogicalDOMRect } from './dropdown-position';

import styles from './styles.css.js';

Expand Down Expand Up @@ -361,7 +362,7 @@ export const calculatePosition = (
isMobile: boolean,
minWidth?: number,
stretchBeyondTriggerWidth?: boolean
): [DropdownPosition, DOMRect] => {
): [DropdownPosition, LogicalDOMRect] => {
// cleaning previously assigned values,
// so that they are not reused in case of screen resize and similar events
verticalContainerElement.style.maxBlockSize = '';
Expand Down Expand Up @@ -393,6 +394,6 @@ export const calculatePosition = (
isMobile,
stretchBeyondTriggerWidth,
});
const triggerBox = triggerElement.getBoundingClientRect();
const triggerBox = getLogicalBoundingClientRect(triggerElement);
return [position, triggerBox];
};
47 changes: 47 additions & 0 deletions src/internal/components/dropdown/dropdown-position.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { getIsRtl } from '@cloudscape-design/component-toolkit/internal';

import { DropdownPosition } from './dropdown-fit-handler';

export interface LogicalDOMRect {
blockSize: number;
inlineSize: number;
insetBlockStart: number;
insetBlockEnd: number;
insetInlineStart: number;
insetInlineEnd: number;
}

export function applyFixedDropdownPosition({
position,
dropdownElement,
triggerRect,
}: {
position: DropdownPosition;
dropdownElement: HTMLElement;
triggerRect: LogicalDOMRect;
}) {
const useAbsolutePositioning = window.visualViewport?.height && window.visualViewport.height < window.innerHeight;

const verticalScrollOffset = useAbsolutePositioning ? document.documentElement.scrollTop : 0;
const horizontalScrollOffset = useAbsolutePositioning
? getIsRtl(document.body)
? window.innerWidth - document.documentElement.scrollLeft
: document.documentElement.scrollLeft

Check warning on line 32 in src/internal/components/dropdown/dropdown-position.ts

View check run for this annotation

Codecov / codecov/patch

src/internal/components/dropdown/dropdown-position.ts#L31-L32

Added lines #L31 - L32 were not covered by tests
: 0;

dropdownElement.style.position = useAbsolutePositioning ? 'absolute' : 'fixed';

if (position.dropBlockStart) {
dropdownElement.style.insetBlockEnd = `calc(100% - ${verticalScrollOffset + triggerRect.insetBlockStart}px)`;

Check warning on line 38 in src/internal/components/dropdown/dropdown-position.ts

View check run for this annotation

Codecov / codecov/patch

src/internal/components/dropdown/dropdown-position.ts#L38

Added line #L38 was not covered by tests
} else {
dropdownElement.style.insetBlockStart = `${verticalScrollOffset + triggerRect.insetBlockEnd}px`;
}
if (position.dropInlineStart) {
dropdownElement.style.insetInlineStart = `calc(${horizontalScrollOffset + triggerRect.insetInlineEnd}px - ${position.inlineSize})`;

Check warning on line 43 in src/internal/components/dropdown/dropdown-position.ts

View check run for this annotation

Codecov / codecov/patch

src/internal/components/dropdown/dropdown-position.ts#L43

Added line #L43 was not covered by tests
} else {
dropdownElement.style.insetInlineStart = `${horizontalScrollOffset + triggerRect.insetInlineStart}px`;
}
}
52 changes: 13 additions & 39 deletions src/internal/components/dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
hasEnoughSpaceToStretchBeyondTriggerWidth,
InteriorDropdownPosition,
} from './dropdown-fit-handler';
import { applyFixedDropdownPosition, LogicalDOMRect } from './dropdown-position';
import { DropdownProps } from './interfaces';

import styles from './styles.css.js';
Expand Down Expand Up @@ -196,7 +197,7 @@ const Dropdown = ({

const setDropdownPosition = (
position: DropdownPosition | InteriorDropdownPosition,
triggerBox: DOMRect,
triggerBox: LogicalDOMRect,
target: HTMLDivElement,
verticalContainer: HTMLDivElement
) => {
Expand Down Expand Up @@ -233,21 +234,11 @@ const Dropdown = ({

// Position normal overflow dropdowns with fixed positioning relative to viewport
if (expandToViewport && !interior) {
const isIOSVirtualKeyboardPresent =
window.visualViewport?.height && window.visualViewport.height < window.innerHeight;
target.style.position = isIOSVirtualKeyboardPresent ? 'absolute' : 'fixed';
const verticalScrollOffset = isIOSVirtualKeyboardPresent ? document.documentElement.scrollTop : 0;
const horizontalScrollOffset = isIOSVirtualKeyboardPresent ? document.documentElement.scrollLeft : 0;
if (position.dropBlockStart) {
target.style.insetBlockEnd = `calc(100% - ${verticalScrollOffset + triggerBox.top}px)`;
} else {
target.style.insetBlockStart = `${verticalScrollOffset + triggerBox.bottom}px`;
}
if (position.dropInlineStart) {
target.style.insetInlineStart = `calc(${horizontalScrollOffset + triggerBox.right}px - ${position.inlineSize})`;
} else {
target.style.insetInlineStart = `${horizontalScrollOffset + triggerBox.left}px`;
}
applyFixedDropdownPosition({
position,
dropdownElement: target,
triggerRect: triggerBox,
});
// Keep track of the initial dropdown position and direction.
// Dropdown direction doesn't need to change as the user scrolls, just needs to stay attached to the trigger.
fixedPosition.current = position;
Expand Down Expand Up @@ -394,29 +385,12 @@ const Dropdown = ({
return;
}
const updateDropdownPosition = () => {
if (triggerRef.current && dropdownRef.current && verticalContainerRef.current) {
const isIOSVirtualKeyboardPresent =
window.visualViewport?.height && window.visualViewport.height < window.innerHeight;

dropdownRef.current.style.position = isIOSVirtualKeyboardPresent ? 'absolute' : 'fixed';

const verticalScrollOffset = isIOSVirtualKeyboardPresent ? document.documentElement.scrollTop : 0;
const horizontalScrollOffset = isIOSVirtualKeyboardPresent ? document.documentElement.scrollLeft : 0;

const triggerRect = getLogicalBoundingClientRect(triggerRef.current);
const target = dropdownRef.current;
if (fixedPosition.current) {
if (fixedPosition.current.dropBlockStart) {
dropdownRef.current.style.insetBlockEnd = `calc(100% - ${verticalScrollOffset + triggerRect.insetBlockStart}px)`;
} else {
target.style.insetBlockStart = `${verticalScrollOffset + triggerRect.insetBlockEnd}px`;
}
if (fixedPosition.current.dropInlineStart) {
target.style.insetInlineStart = `calc(${horizontalScrollOffset + triggerRect.insetInlineEnd}px - ${fixedPosition.current.inlineSize})`;
} else {
target.style.insetInlineStart = `${horizontalScrollOffset + triggerRect.insetInlineStart}px`;
}
}
if (triggerRef.current && dropdownRef.current && verticalContainerRef.current && fixedPosition.current) {
applyFixedDropdownPosition({
position: fixedPosition.current,
dropdownElement: dropdownRef.current,
triggerRect: getLogicalBoundingClientRect(triggerRef.current),
});
}
};

Expand Down

0 comments on commit 731bb5c

Please sign in to comment.