Skip to content

Commit 1766875

Browse files
author
泊淞
committed
fix(DatePicker2): Fix the arrow direction issue when popupAlign is set to br tr or tr br
1 parent fcb7abd commit 1766875

File tree

3 files changed

+174
-10
lines changed

3 files changed

+174
-10
lines changed

components/date-picker2/__tests__/index-spec.js

+105
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,94 @@ describe('Picker', () => {
861861
});
862862
});
863863

864+
describe('RangePicker arrow', () => {
865+
it('align tl bl', () => {
866+
return co(function* () {
867+
wrapper = render(<RangePicker popupAlign="tl bl" />);
868+
const inputBegin = wrapper.find('.next-input')[0];
869+
ReactTestUtils.Simulate.click(inputBegin);
870+
yield delay(300);
871+
assert.equal(findArrowDom().offsetTop, 13);
872+
assert.equal(findArrowDom().style.left, `${getArrowLeft()}px`);
873+
wrapper.unmount();
874+
});
875+
});
876+
it('align tr br', () => {
877+
return co(function* () {
878+
wrapper = render(
879+
<div
880+
style={{
881+
display: 'flex',
882+
flexDirection: 'row',
883+
}}
884+
>
885+
<div style={{ flex: 1 }}></div>
886+
<div style={{ width: 300 }}>
887+
<RangePicker dev={true} popupAlign="tr br" />
888+
</div>
889+
</div>
890+
);
891+
const inputBegin = wrapper.find('.next-input')[0];
892+
ReactTestUtils.Simulate.click(inputBegin);
893+
yield delay(300);
894+
assert.equal(findArrowDom().offsetTop, 13);
895+
assert.equal(findArrowDom().style.left, `${getArrowLeft()}px`);
896+
wrapper.unmount();
897+
});
898+
});
899+
900+
it('align br tr', () => {
901+
return co(function* () {
902+
wrapper = render(
903+
<div
904+
style={{
905+
display: 'flex',
906+
flexDirection: 'row',
907+
height: 400,
908+
alignItems: 'end',
909+
}}
910+
>
911+
<div style={{ flex: 1 }}></div>
912+
<div style={{ width: 300 }}>
913+
<RangePicker popupAlign="br tr" />
914+
</div>
915+
</div>
916+
);
917+
const inputBegin = wrapper.find('.next-input')[0];
918+
ReactTestUtils.Simulate.click(inputBegin);
919+
yield delay(300);
920+
const count = findOverlayDom().offsetHeight - findArrowDom().offsetTop;
921+
assert.equal(count, 25);
922+
assert.equal(findArrowDom().style.left, `${getArrowLeft()}px`);
923+
wrapper.unmount();
924+
});
925+
});
926+
927+
it('align bl tl', () => {
928+
return co(function* () {
929+
wrapper = render(
930+
<div
931+
style={{
932+
display: 'flex',
933+
flexDirection: 'row',
934+
height: 400,
935+
alignItems: 'end',
936+
}}
937+
>
938+
<RangePicker popupAlign="bl tl" />
939+
</div>
940+
);
941+
const inputBegin = wrapper.find('.next-input')[0];
942+
ReactTestUtils.Simulate.click(inputBegin);
943+
yield delay(300);
944+
const count = findOverlayDom().offsetHeight - findArrowDom().offsetTop;
945+
assert.equal(count, 25);
946+
assert.equal(findArrowDom().style.left, `${getArrowLeft()}px`);
947+
wrapper.unmount();
948+
});
949+
});
950+
});
951+
864952
describe('event', () => {
865953
it('onChange', () => {
866954
let changeCount = 0;
@@ -1360,3 +1448,20 @@ function hasClassNames(node, classNames) {
13601448
function showTimePanel() {
13611449
return !!wrapper.find('.next-time-picker2-panel').length;
13621450
}
1451+
1452+
function findArrowDom() {
1453+
return document.querySelector('.next-range-picker2-arrow');
1454+
}
1455+
1456+
function findOverlayDom() {
1457+
return document.querySelector('.next-date-picker2-overlay');
1458+
}
1459+
1460+
function getArrowLeft() {
1461+
const inputBegin = wrapper.find('.next-input')[0];
1462+
const { left: arrowLeft } = inputBegin.getBoundingClientRect();
1463+
const { left: panelLeft } = findOverlayDom().getBoundingClientRect();
1464+
const offset = Math.round(Math.abs(arrowLeft - panelLeft));
1465+
const inputOffsetLeft = inputBegin.offsetLeft;
1466+
return offset + inputOffsetLeft;
1467+
}

components/date-picker2/main.scss

+11
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,17 @@
192192
transform: translate(0, 50%) rotate(135deg);
193193
}
194194
}
195+
#{$date-picker2-prefix}-tr-br {
196+
#{$range-picker2-prefix}-arrow {
197+
top: 12.5px;
198+
}
199+
}
200+
#{$date-picker2-prefix}-br-tr {
201+
#{$range-picker2-prefix}-arrow {
202+
bottom: 13px;
203+
transform: translate(0, 50%) rotate(135deg);
204+
}
205+
}
195206

196207
.#{$css-prefix}date-time-picker-wrapper {
197208
border-left: 1px solid $color-line1-1;

components/date-picker2/picker.jsx

+58-10
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,11 @@ class Picker extends React.Component {
425425
if (isRange) {
426426
const updatedInputValue = [...inputValue];
427427
updatedInputValue[inputType] = updatedInputValue[inputType] + ' ';
428-
this.setState({ inputValue: updatedInputValue })
428+
this.setState({ inputValue: updatedInputValue });
429429
} else {
430430
this.setState({
431-
inputValue: inputValue + ' '
432-
})
431+
inputValue: inputValue + ' ',
432+
});
433433
}
434434
break;
435435
}
@@ -441,7 +441,13 @@ class Picker extends React.Component {
441441
handleChange = (v, eventType) => {
442442
const { format } = this.props;
443443
const { isRange, showOk, value, preValue } = this.state;
444-
const forceEvents = ['KEYDOWN_ENTER', 'CLICK_PRESET', 'CLICK_OK', 'INPUT_CLEAR', 'VISIBLE_CHANGE'];
444+
const forceEvents = [
445+
'KEYDOWN_ENTER',
446+
'CLICK_PRESET',
447+
'CLICK_OK',
448+
'INPUT_CLEAR',
449+
'VISIBLE_CHANGE',
450+
];
445451
const isTemporary = showOk && !forceEvents.includes(eventType);
446452

447453
// 面板收起时候,将值设置为确认值
@@ -566,15 +572,37 @@ class Picker extends React.Component {
566572
return left;
567573
};
568574

575+
getRangeInputStartClientRect = () => {
576+
const rect =
577+
this.dateInput &&
578+
this.dateInput.input &&
579+
this.dateInput.input[DATE_INPUT_TYPE.BEGIN] &&
580+
this.dateInput.input &&
581+
this.dateInput.input[DATE_INPUT_TYPE.BEGIN].getInputNode().getBoundingClientRect();
582+
return rect || {};
583+
};
584+
569585
getPopupOffsetLeft = () => {
570586
const inputOffsetLeft = this.getRangeInputOffsetLeft();
571587
const popupElement = this.popupRef.current;
572588
const popupElementWidth = popupElement ? popupElement.offsetWidth : 0;
589+
// 计算弹层相对于输入框的偏移量
590+
let { left: inputLeft = 0 } = this.getRangeInputStartClientRect();
591+
const popupElementLeft = popupElement ? popupElement.getBoundingClientRect().left || 0 : 0;
592+
const offset = popupElementWidth ? Math.round(Math.abs(popupElementLeft - inputLeft)) : 0;
593+
594+
// 没有的时候,默认不偏移,要不然会因为 css 中的 transform 属性导致会有偏移动画
595+
if (!popupElementWidth || (!inputOffsetLeft && inputOffsetLeft !== 0)) {
596+
return {
597+
arrowLeft: 0,
598+
panelLeft: 0,
599+
};
600+
}
573601

574602
// 弹层宽度大于输入元素长度,只偏移 arrow
575603
if (popupElementWidth > 1.2 * inputOffsetLeft) {
576604
return {
577-
arrowLeft: inputOffsetLeft,
605+
arrowLeft: inputOffsetLeft + offset,
578606
panelLeft: 0,
579607
};
580608
} else {
@@ -587,7 +615,13 @@ class Picker extends React.Component {
587615
};
588616

589617
renderArrow = left => {
590-
return <div key="arrow" className={`${this.props.prefix}range-picker2-arrow`} style={{ left }} />;
618+
return (
619+
<div
620+
key="arrow"
621+
className={`${this.props.prefix}range-picker2-arrow`}
622+
style={{ left }}
623+
/>
624+
);
591625
};
592626

593627
render() {
@@ -641,7 +675,10 @@ class Picker extends React.Component {
641675

642676
return (
643677
<div className={previewCls}>
644-
{renderNode(renderPreview, isRange ? inputValue.join('-') : inputValue, [curValue, this.props])}
678+
{renderNode(renderPreview, isRange ? inputValue.join('-') : inputValue, [
679+
curValue,
680+
this.props,
681+
])}
645682
</div>
646683
);
647684
}
@@ -698,13 +735,20 @@ class Picker extends React.Component {
698735
};
699736

700737
const DateNode = isRange ? (
701-
<RangePanel justBeginInput={justBeginInput} onCalendarChange={onCalendarChange} {...panelProps} />
738+
<RangePanel
739+
justBeginInput={justBeginInput}
740+
onCalendarChange={onCalendarChange}
741+
{...panelProps}
742+
/>
702743
) : (
703744
<DatePanel {...panelProps} />
704745
);
705746

706747
// 底部节点
707-
const oKable = !!(!this.checkValueDisabled(inputValue) && (isRange ? inputValue && inputValue[inputType] : inputValue));
748+
const oKable = !!(
749+
!this.checkValueDisabled(inputValue) &&
750+
(isRange ? inputValue && inputValue[inputType] : inputValue)
751+
);
708752
const shouldShowFooter = showOk || preset || extraFooterRender;
709753

710754
const footerNode = shouldShowFooter ? (
@@ -774,7 +818,11 @@ class Picker extends React.Component {
774818
>
775819
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
776820
<div onMouseDown={handleMouseDown} style={{ marginLeft: panelLeft }}>
777-
<div dir={rtl ? 'rtl' : undefined} className={`${prefixCls}-wrapper`} ref={this.popupRef}>
821+
<div
822+
dir={rtl ? 'rtl' : undefined}
823+
className={`${prefixCls}-wrapper`}
824+
ref={this.popupRef}
825+
>
778826
{isRange ? this.renderArrow(arrowLeft) : null}
779827
{DateNode}
780828
{this.state.panelMode !== this.props.mode ? null : footerNode}

0 commit comments

Comments
 (0)