Skip to content

Commit

Permalink
fix: calculate page size
Browse files Browse the repository at this point in the history
`window.innerWidth` or `window.innerHeight` is Incorrect when window zoom
  • Loading branch information
xiejay97 committed Jul 7, 2023
1 parent 2c6e61d commit f2fa480
Show file tree
Hide file tree
Showing 25 changed files with 128 additions and 69 deletions.
1 change: 0 additions & 1 deletion packages/hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export { useForceUpdate } from './useForceUpdate';
export { useForkRef } from './useForkRef';
export { useId } from './useId';
export { useImmer } from './useImmer';
export { useLockScroll } from './useLockScroll';
export { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
export { useMount } from './useMount';
export { useRefExtra } from './useRefExtra';
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/_date-input/DateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ import ReactDOM from 'react-dom';

import { useAsync, useEvent, useEventCallback, useForceUpdate, useForkRef, useImmer, useRefExtra, useResize } from '@react-devui/hooks';
import { CloseCircleFilled, SwapRightOutlined } from '@react-devui/icons';
import { checkNodeExist, getClassName, getVerticalSidePosition } from '@react-devui/utils';
import { checkNodeExist, getClassName } from '@react-devui/utils';

import dayjs from '../../dayjs';
import { useDValue, useMaxIndex } from '../../hooks';
import { cloneHTMLElement, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { cloneHTMLElement, getVerticalSidePosition, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { ESC_CLOSABLE_DATA } from '../../utils/checkNoExpandedEl';
import { DBaseDesign } from '../_base-design';
import { DBaseInput } from '../_base-input';
import { DComboboxKeyboard } from '../_keyboard';
import { DTransition } from '../_transition';
import { useFormControl } from '../form';
import { useGlobalScroll, useLayout, usePrefixConfig, useTranslation } from '../root';
import { ROOT_DATA, useGlobalScroll, useLayout, usePrefixConfig, useTranslation } from '../root';
import { deepCompareDate } from './utils';

export interface DDateInputRef {
Expand Down Expand Up @@ -232,7 +232,7 @@ function DateInput(props: DDateInputProps, ref: React.ForwardedRef<DDateInputRef
const updatePosition = useEventCallback(() => {
if (dVisible && boxRef.current && popupRef.current) {
const height = popupRef.current.offsetHeight;
const maxWidth = window.innerWidth - WINDOW_SPACE * 2;
const maxWidth = ROOT_DATA.pageSize.width - WINDOW_SPACE * 2;
const width = Math.min(popupRef.current.scrollWidth, maxWidth);
const { top, left, transformOrigin } = getVerticalSidePosition(
boxRef.current,
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/auto-complete/AutoComplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import ReactDOM from 'react-dom';

import { useEvent, useEventCallback, useId, useRefExtra, useResize } from '@react-devui/hooks';
import { LoadingOutlined } from '@react-devui/icons';
import { findNested, getClassName, getVerticalSidePosition } from '@react-devui/utils';
import { findNested, getClassName } from '@react-devui/utils';

import { useMaxIndex, useDValue } from '../../hooks';
import { cloneHTMLElement, registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { cloneHTMLElement, getVerticalSidePosition, registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { DFocusVisible } from '../_focus-visible';
import { DComboboxKeyboard } from '../_keyboard';
import { DTransition } from '../_transition';
import { DInput } from '../input';
import { useComponentConfig, useGlobalScroll, useLayout, usePrefixConfig, useTranslation } from '../root';
import { ROOT_DATA, useComponentConfig, useGlobalScroll, useLayout, usePrefixConfig, useTranslation } from '../root';
import { DVirtualScroll } from '../virtual-scroll';

export interface DAutoCompleteRef {
Expand Down Expand Up @@ -106,7 +106,7 @@ function AutoComplete<T extends DAutoCompleteItem>(
if (visible && boxRef.current && popupRef.current) {
const boxWidth = boxRef.current.offsetWidth;
const height = popupRef.current.offsetHeight;
const maxWidth = window.innerWidth - WINDOW_SPACE * 2;
const maxWidth = ROOT_DATA.pageSize.width - WINDOW_SPACE * 2;
const width = Math.min(Math.max(popupRef.current.scrollWidth, boxWidth), maxWidth);
const { top, left, transformOrigin } = getVerticalSidePosition(
boxRef.current,
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/cascader/Cascader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import React, { useCallback, useState, useMemo, useRef, useImperativeHandle } fr

import { useEventCallback, useId } from '@react-devui/hooks';
import { CloseOutlined, LoadingOutlined } from '@react-devui/icons';
import { findNested, getClassName, getVerticalSidePosition } from '@react-devui/utils';
import { findNested, getClassName } from '@react-devui/utils';

import { useGeneralContext, useDValue } from '../../hooks';
import { cloneHTMLElement, registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { cloneHTMLElement, getVerticalSidePosition, registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { DComboboxKeyboard } from '../_keyboard';
import { DSelectbox } from '../_selectbox';
import { DTransition } from '../_transition';
import { DDropdown } from '../dropdown';
import { useFormControl } from '../form';
import { useComponentConfig, usePrefixConfig, useTranslation } from '../root';
import { ROOT_DATA, useComponentConfig, usePrefixConfig, useTranslation } from '../root';
import { DTag } from '../tag';
import { DSearchPanel as DTreeSearchPanel } from '../tree/SearchPanel';
import { MultipleTreeNode } from '../tree/multiple-node';
Expand Down Expand Up @@ -282,7 +282,7 @@ function Cascader<V extends DId, T extends DCascaderItem<V>>(
const updatePosition = useEventCallback(() => {
if (visible && boxRef.current && popupRef.current) {
const height = popupRef.current.offsetHeight;
const maxWidth = window.innerWidth - WINDOW_SPACE * 2;
const maxWidth = ROOT_DATA.pageSize.width - WINDOW_SPACE * 2;
const width = Math.min(popupRef.current.scrollWidth, maxWidth);
const { top, left, transformOrigin } = getVerticalSidePosition(
boxRef.current,
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/drawer/Drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { isString, isUndefined } from 'lodash';
import React, { useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';

import { useId, useLockScroll, useRefExtra } from '@react-devui/hooks';
import { useId, useRefExtra } from '@react-devui/hooks';
import { getClassName, toPx } from '@react-devui/utils';

import { useMaxIndex, useDValue } from '../../hooks';
import { useMaxIndex, useDValue, useLockScroll } from '../../hooks';
import { registerComponentMate, handleModalKeyDown, TTANSITION_DURING_BASE, checkNoExpandedEl } from '../../utils';
import { DMask } from '../_mask';
import { DTransition } from '../_transition';
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import React, { useImperativeHandle, useRef, useState } from 'react';
import ReactDOM from 'react-dom';

import { useEvent, useEventCallback, useId, useImmer, useRefExtra } from '@react-devui/hooks';
import { getClassName, getVerticalSidePosition, scrollToView } from '@react-devui/utils';
import { getClassName, scrollToView } from '@react-devui/utils';

import { useMaxIndex, useDValue } from '../../hooks';
import { registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { getVerticalSidePosition, registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { ESC_CLOSABLE_DATA } from '../../utils/checkNoExpandedEl';
import { DFocusVisible } from '../_focus-visible';
import { DPopup, useNestedPopup } from '../_popup';
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/dropdown/Sub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import ReactDOM from 'react-dom';

import { useEventCallback, useRefExtra } from '@react-devui/hooks';
import { RightOutlined } from '@react-devui/icons';
import { checkNodeExist, getClassName, getHorizontalSidePosition } from '@react-devui/utils';
import { checkNodeExist, getClassName } from '@react-devui/utils';

import { TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { getHorizontalSidePosition, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { DPopup } from '../_popup';
import { DTransition } from '../_transition';
import { usePrefixConfig, useTranslation } from '../root';
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/image/ImagePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { isUndefined } from 'lodash';
import React, { useRef, useState } from 'react';
import ReactDOM from 'react-dom';

import { useEvent, useImmer, useIsomorphicLayoutEffect, useLockScroll, useRefExtra } from '@react-devui/hooks';
import { useEvent, useImmer, useIsomorphicLayoutEffect, useRefExtra } from '@react-devui/hooks';
import { CloseOutlined, LeftOutlined, RightOutlined, RotateRightOutlined, ZoomInOutlined, ZoomOutOutlined } from '@react-devui/icons';
import { getClassName } from '@react-devui/utils';

import { useDValue, useMaxIndex } from '../../hooks';
import { useDValue, useLockScroll, useMaxIndex } from '../../hooks';
import { registerComponentMate, TTANSITION_DURING_BASE } from '../../utils';
import { DMask } from '../_mask';
import { DTransition } from '../_transition';
import { DButton } from '../button';
import { DInput } from '../input';
import { useComponentConfig, usePrefixConfig } from '../root';
import { ROOT_DATA, useComponentConfig, usePrefixConfig } from '../root';

export interface DImagePreviewProps extends React.HTMLAttributes<HTMLDivElement> {
dList: (React.ImgHTMLAttributes<HTMLImageElement> & { src: string })[];
Expand Down Expand Up @@ -102,7 +102,7 @@ export function DImagePreview(props: DImagePreviewProps): JSX.Element | null {
})();

const getOffset = () => {
setOffset(~~((window.innerWidth - 108) / 120));
setOffset(~~((ROOT_DATA.pageSize.width - 108) / 120));
};
useIsomorphicLayoutEffect(() => {
getOffset();
Expand Down
10 changes: 8 additions & 2 deletions packages/ui/src/components/menu/Sub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import React, { useState, useRef, useImperativeHandle, useEffect } from 'react';
import ReactDOM from 'react-dom';

import { useEventCallback, useRefExtra } from '@react-devui/hooks';
import { checkNodeExist, getClassName, getHorizontalSidePosition, getVerticalSidePosition } from '@react-devui/utils';
import { checkNodeExist, getClassName } from '@react-devui/utils';

import { useMaxIndex } from '../../hooks';
import { TTANSITION_DURING_BASE, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import {
getHorizontalSidePosition,
getVerticalSidePosition,
TTANSITION_DURING_BASE,
TTANSITION_DURING_POPUP,
WINDOW_SPACE,
} from '../../utils';
import { DPopup } from '../_popup';
import { DCollapseTransition, DTransition } from '../_transition';
import { usePrefixConfig, useTranslation } from '../root';
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { isNumber, isString, isUndefined } from 'lodash';
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';

import { useId, useLockScroll, useRefExtra } from '@react-devui/hooks';
import { useId, useRefExtra } from '@react-devui/hooks';
import { CheckCircleOutlined, CloseCircleOutlined, ExclamationCircleOutlined, WarningOutlined } from '@react-devui/icons';
import { checkNodeExist, getClassName } from '@react-devui/utils';

import { useMaxIndex, useDValue } from '../../hooks';
import { useMaxIndex, useDValue, useLockScroll } from '../../hooks';
import { registerComponentMate, handleModalKeyDown, TTANSITION_DURING_BASE, checkNoExpandedEl } from '../../utils';
import { DMask } from '../_mask';
import { DTransition } from '../_transition';
Expand Down Expand Up @@ -134,8 +134,8 @@ export const DModal: {
if (isUndefined(ROOT_DATA.clickEvent) || performance.now() - ROOT_DATA.clickEvent.time > 100) {
dataRef.current.transformOrigin = undefined;
} else if (modalContentRef.current) {
const left = `${(window.innerWidth - modalContentRef.current.offsetWidth) / 2}px`;
const top = dTop === 'center' ? `${(window.innerHeight - modalContentRef.current.offsetHeight) / 2}px` : topStyle;
const left = `${(ROOT_DATA.pageSize.width - modalContentRef.current.offsetWidth) / 2}px`;
const top = dTop === 'center' ? `${(ROOT_DATA.pageSize.height - modalContentRef.current.offsetHeight) / 2}px` : topStyle;
dataRef.current.transformOrigin = `calc(${ROOT_DATA.clickEvent.e.clientX}px - ${left}) calc(${ROOT_DATA.clickEvent.e.clientY}px - ${top})`;
}
}}
Expand Down
16 changes: 8 additions & 8 deletions packages/ui/src/components/popover/Popover.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import type { DPopupPlacement } from '../../utils/position';
import type { DPopoverFooterPrivateProps } from './PopoverFooter';
import type { DPopoverHeaderPrivateProps } from './PopoverHeader';
import type { DRefExtra } from '@react-devui/hooks/useRefExtra';
import type { DPopupPlacement } from '@react-devui/utils/position';

import { isString, isUndefined } from 'lodash';
import React, { useImperativeHandle, useRef, useState } from 'react';
import ReactDOM from 'react-dom';

import { useEvent, useEventCallback, useId, useLockScroll, useRefExtra } from '@react-devui/hooks';
import { getClassName, getPopupPosition } from '@react-devui/utils';
import { useEvent, useEventCallback, useId, useRefExtra } from '@react-devui/hooks';
import { getClassName } from '@react-devui/utils';

import { useMaxIndex, useDValue } from '../../hooks';
import { registerComponentMate, handleModalKeyDown, cloneHTMLElement, checkNoExpandedEl } from '../../utils';
import { useMaxIndex, useDValue, useLockScroll } from '../../hooks';
import { registerComponentMate, handleModalKeyDown, cloneHTMLElement, checkNoExpandedEl, getPopupPosition } from '../../utils';
import { ESC_CLOSABLE_DATA } from '../../utils/checkNoExpandedEl';
import { DPopup } from '../_popup';
import { DTransition } from '../_transition';
import { useComponentConfig, usePrefixConfig } from '../root';
import { ROOT_DATA, useComponentConfig, usePrefixConfig } from '../root';
import { DPopoverFooter } from './PopoverFooter';
import { DPopoverHeader } from './PopoverHeader';

Expand Down Expand Up @@ -144,8 +144,8 @@ function Popover(props: DPopoverProps, ref: React.ForwardedRef<DPopoverRef>): JS
const containerRect = containerRef.current.getBoundingClientRect();
space = [
containerRect.top,
window.innerWidth - containerRect.left - containerRect.width,
window.innerHeight - containerRect.top - containerRect.height,
ROOT_DATA.pageSize.width - containerRect.left - containerRect.width,
ROOT_DATA.pageSize.height - containerRect.top - containerRect.height,
containerRect.left,
];
}
Expand Down
45 changes: 40 additions & 5 deletions packages/ui/src/components/root/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { DPartialConfigContextData } from './contex';
import type { DIconContextData } from '@react-devui/icons/Icon';

import { useContext, useMemo } from 'react';
import { useContext, useEffect, useMemo, useRef } from 'react';
import ReactDOM from 'react-dom';

import { useRefExtra, useEvent } from '@react-devui/hooks';
import { DIconContext } from '@react-devui/icons/Icon';
Expand Down Expand Up @@ -30,7 +31,10 @@ export const ROOT_DATA: {
time: number;
e: MouseEvent;
};
} = {};
pageSize: { width: number; height: number };
} = {
pageSize: typeof window !== 'undefined' ? { width: window.innerWidth, height: window.innerHeight } : { width: 0, height: 0 },
};

export interface DRootProps {
children: React.ReactNode;
Expand All @@ -43,6 +47,7 @@ export function DRoot(props: DRootProps): JSX.Element | null {
const parent = useContext(DConfigContext);

const windowRef = useRefExtra(() => window);
const pageSizeRef = useRef<HTMLDivElement>(null);

const [context, iconContext] = useMemo<[DConfigContextManager, DIconContextData]>(() => {
const context = new DConfigContextManager((parent ?? ROOT).mergeContext(_context ?? {}));
Expand Down Expand Up @@ -100,9 +105,39 @@ export function DRoot(props: DRootProps): JSX.Element | null {
{ capture: true }
);

useEffect(() => {
if (pageSizeRef.current) {
const observer = new ResizeObserver(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
ROOT_DATA.pageSize = { width: pageSizeRef.current!.clientWidth, height: pageSizeRef.current!.clientHeight };
});
observer.observe(pageSizeRef.current);
return () => {
observer.disconnect();
};
}
});

return (
<DConfigContext.Provider value={context}>
{parent ? children : <DIconContext.Provider value={iconContext}>{children}</DIconContext.Provider>}
</DConfigContext.Provider>
<>
<DConfigContext.Provider value={context}>
{parent ? children : <DIconContext.Provider value={iconContext}>{children}</DIconContext.Provider>}
</DConfigContext.Provider>
{windowRef.current &&
ReactDOM.createPortal(
<div
ref={pageSizeRef}
style={{
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0,
pointerEvents: 'none',
}}
></div>,
windowRef.current.document.body
)}
</>
);
}
10 changes: 5 additions & 5 deletions packages/ui/src/components/select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import React, { useState, useCallback, useMemo, useRef, useImperativeHandle } fr

import { useEventCallback, useId } from '@react-devui/hooks';
import { CloseOutlined, LoadingOutlined, PlusOutlined } from '@react-devui/icons';
import { findNested, getClassName, getVerticalSidePosition } from '@react-devui/utils';
import { findNested, getClassName } from '@react-devui/utils';

import { useGeneralContext, useDValue } from '../../hooks';
import { cloneHTMLElement, registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { cloneHTMLElement, getVerticalSidePosition, registerComponentMate, TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../../utils';
import { DComboboxKeyboard } from '../_keyboard';
import { DSelectbox } from '../_selectbox';
import { DTransition } from '../_transition';
import { DCheckbox } from '../checkbox';
import { DDropdown } from '../dropdown';
import { useFormControl } from '../form';
import { useComponentConfig, usePrefixConfig, useTranslation } from '../root';
import { ROOT_DATA, useComponentConfig, usePrefixConfig, useTranslation } from '../root';
import { DTag } from '../tag';
import { DVirtualScroll } from '../virtual-scroll';

Expand Down Expand Up @@ -311,7 +311,7 @@ function Select<V extends DId, T extends DSelectItem<V>>(
const updatePosition = useEventCallback(() => {
if (visible && boxRef.current && popupRef.current) {
if (dMonospaced) {
const width = Math.min(boxRef.current.offsetWidth, window.innerWidth - WINDOW_SPACE * 2);
const width = Math.min(boxRef.current.offsetWidth, ROOT_DATA.pageSize.width - WINDOW_SPACE * 2);
const height = popupRef.current.offsetHeight;
const { top, left, transformOrigin } = getVerticalSidePosition(
boxRef.current,
Expand All @@ -330,7 +330,7 @@ function Select<V extends DId, T extends DSelectItem<V>>(
} else {
const boxWidth = boxRef.current.offsetWidth;
const height = popupRef.current.offsetHeight;
const maxWidth = window.innerWidth - WINDOW_SPACE * 2;
const maxWidth = ROOT_DATA.pageSize.width - WINDOW_SPACE * 2;
const width = Math.min(Math.max(popupRef.current.scrollWidth, boxWidth), maxWidth);
const { top, left, transformOrigin } = getVerticalSidePosition(
boxRef.current,
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/components/time-picker/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ function Panel(props: DPanelProps, ref: React.ForwardedRef<(date: Date) => void>
dataRef.current.clearHTid = scrollTo(ulHRef.current, {
top: Array.prototype.indexOf.call(ulHRef.current.children, ulHRef.current.querySelector(`[data-h="${hour}"]`)) * 28,
behavior,
during: 200,
});
}
}
Expand All @@ -90,6 +91,7 @@ function Panel(props: DPanelProps, ref: React.ForwardedRef<(date: Date) => void>
dataRef.current.clearMTid = scrollTo(ulMRef.current, {
top: Array.prototype.indexOf.call(ulMRef.current.children, ulMRef.current.querySelector(`[data-m="${minute}"]`)) * 28,
behavior,
during: 200,
});
}
}
Expand All @@ -101,6 +103,7 @@ function Panel(props: DPanelProps, ref: React.ForwardedRef<(date: Date) => void>
dataRef.current.clearSTid = scrollTo(ulSRef.current, {
top: Array.prototype.indexOf.call(ulSRef.current.children, ulSRef.current.querySelector(`[data-s="${second}"]`)) * 28,
behavior,
during: 200,
});
}
}
Expand Down
Loading

0 comments on commit f2fa480

Please sign in to comment.