Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix:RangePicker the triangle sign was not positioned correctly in some cases #886

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
4 changes: 2 additions & 2 deletions src/PickerInput/Popup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
onSubmit,
} = props;

const { prefixCls } = React.useContext(PickerContext);
const { prefixCls, alignedPlacement } = React.useContext(PickerContext);
const panelPrefixCls = `${prefixCls}-panel`;

const rtl = direction === 'rtl';
Expand Down Expand Up @@ -213,7 +213,7 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
);

if (range) {
const realPlacement = getRealPlacement(placement, rtl);
const realPlacement = getRealPlacement(alignedPlacement || placement, rtl);
const offsetUnit = getoffsetUnit(realPlacement, rtl);
renderNode = (
<div
Expand Down
16 changes: 15 additions & 1 deletion src/PickerInput/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,9 @@ function RangePicker<DateType extends object = any>(
onKeyDown?.(event, preventDefault);
};

// ======================= popup align =======================
const [alignedPlacement, setAlignedPlacement] = React.useState<string>();

// ======================= Context ========================
const context = React.useMemo(
() => ({
Expand All @@ -674,8 +677,18 @@ function RangePicker<DateType extends object = any>(
generateConfig,
button: components.button,
input: components.input,
alignedPlacement,
setAlignedPlacement,
}),
[prefixCls, locale, generateConfig, components.button, components.input],
[
prefixCls,
locale,
generateConfig,
components.button,
components.input,
alignedPlacement,
setAlignedPlacement,
],
);

// ======================== Effect ========================
Expand Down Expand Up @@ -739,6 +752,7 @@ function RangePicker<DateType extends object = any>(
// Visible
visible={mergedOpen}
onClose={onPopupClose}
alignedPlacement={alignedPlacement}
// Range
range
>
Expand Down
30 changes: 22 additions & 8 deletions src/PickerInput/Selector/RangeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import useRootProps from './hooks/useRootProps';
import Icon, { ClearIcon } from './Icon';
import Input, { type InputRef } from './Input';
import { getoffsetUnit, getRealPlacement } from '../../utils/uiUtil';
import { getWin } from './util';

export type SelectorIdType =
| string
Expand Down Expand Up @@ -120,7 +121,7 @@ function RangeSelector<DateType extends object = any>(
const rtl = direction === 'rtl';

// ======================== Prefix ========================
const { prefixCls } = React.useContext(PickerContext);
const { prefixCls, alignedPlacement } = React.useContext(PickerContext);

// ========================== Id ==========================
const ids = React.useMemo(() => {
Expand Down Expand Up @@ -173,7 +174,7 @@ function RangeSelector<DateType extends object = any>(
});

// ====================== ActiveBar =======================
const realPlacement = getRealPlacement(placement, rtl);
const realPlacement = getRealPlacement(alignedPlacement || placement, rtl);
const offsetUnit = getoffsetUnit(realPlacement, rtl);
const placementRight = realPlacement?.toLowerCase().endsWith('right');
const [activeBarStyle, setActiveBarStyle] = React.useState<React.CSSProperties>({
Expand All @@ -184,21 +185,34 @@ function RangeSelector<DateType extends object = any>(
const syncActiveOffset = useEvent(() => {
const input = getInput(activeIndex);
if (input) {
const { offsetWidth, offsetLeft, offsetParent } = input.nativeElement;
const parentWidth = (offsetParent as HTMLElement)?.offsetWidth || 0;
const activeOffset = placementRight ? (parentWidth - offsetWidth - offsetLeft) : offsetLeft;
const { offsetParent } = input.nativeElement;
// offsetLeft is an integer, which will cause incorrect reulst.
const { x = 0, width: inputWidth = 0 } = input.nativeElement.getBoundingClientRect() || {};
const { x: pX = 0, width: parentWidth = 0 } = offsetParent?.getBoundingClientRect() || {};
const parentStyles =
offsetParent && getWin(offsetParent as HTMLElement).getComputedStyle(offsetParent);
const parentBorderRightWidth = Number(
(placementRight ? parentStyles?.borderRightWidth : parentStyles?.borderLeftWidth)?.replace(
'px',
'',
) || 0,
);
const offsetLeft = x - pX;

const activeOffset = placementRight ? parentWidth - inputWidth - offsetLeft : offsetLeft;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉有点复杂,我再想想有没有更简洁的解法。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

想办法给这种自动更换 placement 情况下的 offsetUnit 去反应该就行。

setActiveBarStyle(({ insetInlineStart, insetInlineEnd, ...rest }) => ({
...rest,
width: offsetWidth,
[offsetUnit]: activeOffset
width: inputWidth,
// parent will have border while focus, so need to cut `parentBorderWidth` on opposite side.
[offsetUnit]: activeOffset - parentBorderRightWidth,
}));
onActiveOffset(activeOffset);
}
});

React.useEffect(() => {
syncActiveOffset();
}, [activeIndex]);
}, [activeIndex, alignedPlacement]);

// ======================== Clear =========================
const showClear = clearIcon && ((value[0] && !disabled[0]) || (value[1] && !disabled[1]));
Expand Down
6 changes: 5 additions & 1 deletion src/PickerInput/Selector/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ export function getMaskRange(key: string): [startVal: number, endVal: number, de
};

return PresetRange[key];
}
}

export function getWin(ele: HTMLElement) {
return ele.ownerDocument.defaultView;
}
4 changes: 3 additions & 1 deletion src/PickerInput/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export interface PickerContextProps<DateType = any> {
/** Customize button component */
button?: Components['button'];
input?: Components['input'];

/** trigger will change placement while aligining */
alignedPlacement?: string;
setAlignedPlacement?: React.Dispatch<React.SetStateAction<string>>;
}

const PickerContext = React.createContext<PickerContextProps>(null!);
Expand Down
21 changes: 17 additions & 4 deletions src/PickerTrigger/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type PickerTriggerProps = {
placement?: string;
builtinPlacements?: BuildInPlacements;
direction?: 'ltr' | 'rtl';

alignedPlacement?: string;
// Visible
visible: boolean;
onClose: () => void;
Expand All @@ -72,15 +72,15 @@ function PickerTrigger({
placement,
builtinPlacements = BUILT_IN_PLACEMENTS,
direction,

alignedPlacement,
// Visible
visible,
onClose,
}: PickerTriggerProps) {
const { prefixCls } = React.useContext(PickerContext);
const { prefixCls, setAlignedPlacement } = React.useContext(PickerContext);
const dropdownPrefixCls = `${prefixCls}-dropdown`;

const realPlacement = getRealPlacement(placement, direction === 'rtl');
const realPlacement = getRealPlacement(alignedPlacement || placement, direction === 'rtl');

return (
<Trigger
Expand All @@ -100,6 +100,19 @@ function PickerTrigger({
popupStyle={popupStyle}
stretch="minWidth"
getPopupContainer={getPopupContainer}
onPopupAlign={(_, align) => {
if (!setAlignedPlacement) return;

const matchedKey = Object.keys(BUILT_IN_PLACEMENTS).find(
(key) =>
BUILT_IN_PLACEMENTS[key].points[0] === align.points[0] &&
BUILT_IN_PLACEMENTS[key].points[1] === align.points[1],
);

if (matchedKey) {
setAlignedPlacement(matchedKey);
}
}}
onPopupVisibleChange={(nextVisible) => {
if (!nextVisible) {
onClose();
Expand Down
Loading