Skip to content

Commit 97741dd

Browse files
authored
fix: use Rect for logic (#906)
* fix: use Rect for logic * test: update snapshot * chore: clean up * chore: fix build
1 parent 8863871 commit 97741dd

File tree

7 files changed

+114
-253
lines changed

7 files changed

+114
-253
lines changed

assets/index.less

+6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
&-invalid {
3838
box-shadow: 0 0 2px red;
3939
}
40+
41+
&-panels {
42+
display: flex;
43+
flex-wrap: nowrap;
44+
}
45+
4046
&-panel {
4147
display: inline-block;
4248
vertical-align: top;

src/PickerInput/Popup/index.tsx

+26-20
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import type {
88
ValueDate,
99
} from '../../interface';
1010
import { toArray } from '../../utils/miscUtil';
11-
import { getRealPlacement, getoffsetUnit } from '../../utils/uiUtil';
1211
import PickerContext from '../context';
1312
import Footer, { type FooterProps } from './Footer';
1413
import PopupPanel, { type PopupPanelProps } from './PopupPanel';
@@ -32,8 +31,7 @@ export interface PopupProps<DateType extends object = any, PresetValue = DateTyp
3231
onPresetSubmit: (presetValue: PresetValue) => void;
3332

3433
// Range
35-
activeOffset?: number;
36-
placement?: string;
34+
activeInfo?: [activeInputLeft: number, activeInputRight: number, selectorWidth: number];
3735
// Direction
3836
direction?: 'ltr' | 'rtl';
3937

@@ -59,8 +57,7 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
5957
// Range
6058
range,
6159
multiple,
62-
activeOffset = 0,
63-
placement,
60+
activeInfo = [0, 0, 0],
6461

6562
// Presets
6663
presets,
@@ -96,28 +93,43 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
9693
// ======================== Offset ========================
9794
const [containerWidth, setContainerWidth] = React.useState<number>(0);
9895
const [containerOffset, setContainerOffset] = React.useState<number>(0);
96+
const [arrowOffset, setArrowOffset] = React.useState<number>(0);
9997

10098
const onResize: ResizeObserverProps['onResize'] = (info) => {
101-
if (info.offsetWidth) {
102-
setContainerWidth(info.offsetWidth);
99+
if (info.width) {
100+
setContainerWidth(info.width);
103101
}
104102
};
105103

104+
const [activeInputLeft, activeInputRight, selectorWidth] = activeInfo;
105+
106106
React.useEffect(() => {
107107
// `activeOffset` is always align with the active input element
108108
// So we need only check container contains the `activeOffset`
109-
if (range) {
109+
if (range && wrapperRef.current) {
110110
// Offset in case container has border radius
111111
const arrowWidth = arrowRef.current?.offsetWidth || 0;
112112

113-
const maxOffset = containerWidth - arrowWidth;
114-
if (activeOffset <= maxOffset) {
115-
setContainerOffset(0);
113+
// Arrow Offset
114+
const wrapperRect = wrapperRef.current.getBoundingClientRect();
115+
const nextArrowOffset = rtl
116+
? activeInputRight - arrowWidth
117+
: activeInputLeft - wrapperRect.left;
118+
setArrowOffset(nextArrowOffset);
119+
120+
// Container Offset
121+
if (containerWidth < selectorWidth) {
122+
const offset = rtl
123+
? wrapperRect.right - (activeInputRight - arrowWidth + containerWidth)
124+
: activeInputLeft + arrowWidth - wrapperRect.left - containerWidth;
125+
126+
const safeOffset = Math.max(0, offset);
127+
setContainerOffset(safeOffset);
116128
} else {
117-
setContainerOffset(activeOffset + arrowWidth - containerWidth);
129+
setContainerOffset(0);
118130
}
119131
}
120-
}, [containerWidth, activeOffset, range]);
132+
}, [rtl, containerWidth, activeInputLeft, activeInputRight, selectorWidth, range]);
121133

122134
// ======================== Custom ========================
123135
function filterEmpty<T>(list: T[]) {
@@ -213,19 +225,13 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
213225
);
214226

215227
if (range) {
216-
const realPlacement = getRealPlacement(placement, rtl);
217-
const offsetUnit = getoffsetUnit(realPlacement, rtl);
218228
renderNode = (
219229
<div
220230
onMouseDown={onPanelMouseDown}
221231
ref={wrapperRef}
222232
className={classNames(`${prefixCls}-range-wrapper`, `${prefixCls}-${picker}-range-wrapper`)}
223233
>
224-
<div
225-
ref={arrowRef}
226-
className={`${prefixCls}-range-arrow`}
227-
style={{ [offsetUnit]: activeOffset }}
228-
/>
234+
<div ref={arrowRef} className={`${prefixCls}-range-arrow`} style={{ left: arrowOffset }} />
229235

230236
{/* Watch for container size */}
231237
<ResizeObserver onResize={onResize}>{renderNode}</ResizeObserver>

src/PickerInput/RangePicker.tsx

+6-5
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ function RangePicker<DateType extends object = any>(
160160
prefixCls,
161161
styles,
162162
classNames,
163-
placement,
164163

165164
// Value
166165
defaultValue,
@@ -473,7 +472,10 @@ function RangePicker<DateType extends object = any>(
473472
// == Panels ==
474473
// ========================================================
475474
// Save the offset with active bar position
476-
const [activeOffset, setActiveOffset] = React.useState(0);
475+
// const [activeOffset, setActiveOffset] = React.useState(0);
476+
const [activeInfo, setActiveInfo] = React.useState<
477+
[activeInputLeft: number, activeInputRight: number, selectorWidth: number]
478+
>([0, 0, 0]);
477479

478480
// ======================= Presets ========================
479481
const presetList = usePresets(presets, ranges);
@@ -574,8 +576,7 @@ function RangePicker<DateType extends object = any>(
574576
// Range
575577
range
576578
multiplePanel={multiplePanel}
577-
activeOffset={activeOffset}
578-
placement={placement}
579+
activeInfo={activeInfo}
579580
// Disabled
580581
disabledDate={mergedDisabledDate}
581582
// Focus
@@ -796,7 +797,7 @@ function RangePicker<DateType extends object = any>(
796797
invalid={submitInvalidates}
797798
onInvalid={onSelectorInvalid}
798799
// Offset
799-
onActiveOffset={setActiveOffset}
800+
onActiveInfo={setActiveInfo}
800801
/>
801802
</PickerTrigger>
802803
</PickerContext.Provider>

src/PickerInput/Selector/RangeSelector.tsx

+13-14
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import useInputProps from './hooks/useInputProps';
88
import useRootProps from './hooks/useRootProps';
99
import Icon, { ClearIcon } from './Icon';
1010
import Input, { type InputRef } from './Input';
11-
import { getoffsetUnit, getRealPlacement } from '../../utils/uiUtil';
1211

1312
export type SelectorIdType =
1413
| string
@@ -42,7 +41,9 @@ export interface RangeSelectorProps<DateType = any> extends SelectorProps<DateTy
4241
* Trigger when the active bar offset position changed.
4342
* This is used for popup panel offset.
4443
*/
45-
onActiveOffset: (offset: number) => void;
44+
onActiveInfo: (
45+
info: [activeInputLeft: number, activeInputRight: number, selectorWidth: number],
46+
) => void;
4647
}
4748

4849
function RangeSelector<DateType extends object = any>(
@@ -102,7 +103,7 @@ function RangeSelector<DateType extends object = any>(
102103
onOpenChange,
103104

104105
// Offset
105-
onActiveOffset,
106+
onActiveInfo,
106107
placement,
107108

108109
// Native
@@ -173,9 +174,6 @@ function RangeSelector<DateType extends object = any>(
173174
});
174175

175176
// ====================== ActiveBar =======================
176-
const realPlacement = getRealPlacement(placement, rtl);
177-
const offsetUnit = getoffsetUnit(realPlacement, rtl);
178-
const placementRight = realPlacement?.toLowerCase().endsWith('right');
179177
const [activeBarStyle, setActiveBarStyle] = React.useState<React.CSSProperties>({
180178
position: 'absolute',
181179
width: 0,
@@ -184,15 +182,16 @@ function RangeSelector<DateType extends object = any>(
184182
const syncActiveOffset = useEvent(() => {
185183
const input = getInput(activeIndex);
186184
if (input) {
187-
const { offsetWidth, offsetLeft, offsetParent } = input.nativeElement;
188-
const parentWidth = (offsetParent as HTMLElement)?.offsetWidth || 0;
189-
const activeOffset = placementRight ? (parentWidth - offsetWidth - offsetLeft) : offsetLeft;
190-
setActiveBarStyle(({ insetInlineStart, insetInlineEnd, ...rest }) => ({
191-
...rest,
192-
width: offsetWidth,
193-
[offsetUnit]: activeOffset
185+
const inputRect = input.nativeElement.getBoundingClientRect();
186+
const parentRect = rootRef.current.getBoundingClientRect();
187+
188+
const rectOffset = inputRect.left - parentRect.left;
189+
setActiveBarStyle((ori) => ({
190+
...ori,
191+
width: inputRect.width,
192+
left: rectOffset,
194193
}));
195-
onActiveOffset(activeOffset);
194+
onActiveInfo([inputRect.left, inputRect.right, parentRect.width]);
196195
}
197196
});
198197

0 commit comments

Comments
 (0)