@douyinfe/semi-foundation 2.22.3 → 2.23.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/cascader/cascader.scss +15 -0
  2. package/cascader/variables.scss +1 -0
  3. package/checkbox/variables.scss +1 -1
  4. package/form/form.scss +3 -4
  5. package/form/interface.ts +8 -4
  6. package/form/rtl.scss +0 -1
  7. package/form/variables.scss +38 -35
  8. package/image/imageFoundation.ts +1 -1
  9. package/image/previewFooterFoundation.ts +2 -2
  10. package/image/previewImageFoundation.ts +0 -1
  11. package/image/previewInnerFoundation.ts +2 -2
  12. package/lib/cjs/cascader/cascader.css +12 -0
  13. package/lib/cjs/cascader/cascader.scss +15 -0
  14. package/lib/cjs/cascader/variables.scss +1 -0
  15. package/lib/cjs/checkbox/variables.scss +1 -1
  16. package/lib/cjs/form/form.css +0 -2
  17. package/lib/cjs/form/form.scss +3 -4
  18. package/lib/cjs/form/interface.d.ts +8 -6
  19. package/lib/cjs/form/rtl.scss +0 -1
  20. package/lib/cjs/form/variables.scss +38 -35
  21. package/lib/cjs/image/imageFoundation.js +1 -1
  22. package/lib/cjs/image/previewFooterFoundation.js +2 -2
  23. package/lib/cjs/image/previewInnerFoundation.d.ts +1 -1
  24. package/lib/cjs/image/previewInnerFoundation.js +1 -1
  25. package/lib/cjs/navigation/navigation.css +6 -0
  26. package/lib/cjs/navigation/navigation.scss +9 -0
  27. package/lib/cjs/table/constants.d.ts +1 -0
  28. package/lib/cjs/table/constants.js +4 -2
  29. package/lib/cjs/table/table.css +2 -1
  30. package/lib/cjs/table/table.scss +2 -1
  31. package/lib/cjs/tabs/tabs.css +40 -0
  32. package/lib/cjs/tabs/tabs.scss +43 -2
  33. package/lib/cjs/tabs/variables.scss +20 -0
  34. package/lib/cjs/tooltip/constants.d.ts +1 -0
  35. package/lib/cjs/tooltip/constants.js +2 -2
  36. package/lib/cjs/tooltip/foundation.d.ts +21 -2
  37. package/lib/cjs/tooltip/foundation.js +352 -77
  38. package/lib/cjs/transfer/foundation.d.ts +1 -1
  39. package/lib/cjs/transfer/foundation.js +3 -4
  40. package/lib/es/cascader/cascader.css +12 -0
  41. package/lib/es/cascader/cascader.scss +15 -0
  42. package/lib/es/cascader/variables.scss +1 -0
  43. package/lib/es/checkbox/variables.scss +1 -1
  44. package/lib/es/form/form.css +0 -2
  45. package/lib/es/form/form.scss +3 -4
  46. package/lib/es/form/interface.d.ts +8 -6
  47. package/lib/es/form/rtl.scss +0 -1
  48. package/lib/es/form/variables.scss +38 -35
  49. package/lib/es/image/imageFoundation.js +1 -1
  50. package/lib/es/image/previewFooterFoundation.js +2 -2
  51. package/lib/es/image/previewInnerFoundation.d.ts +1 -1
  52. package/lib/es/image/previewInnerFoundation.js +1 -1
  53. package/lib/es/navigation/navigation.css +6 -0
  54. package/lib/es/navigation/navigation.scss +9 -0
  55. package/lib/es/table/constants.d.ts +1 -0
  56. package/lib/es/table/constants.js +4 -2
  57. package/lib/es/table/table.css +2 -1
  58. package/lib/es/table/table.scss +2 -1
  59. package/lib/es/tabs/tabs.css +40 -0
  60. package/lib/es/tabs/tabs.scss +43 -2
  61. package/lib/es/tabs/variables.scss +20 -0
  62. package/lib/es/tooltip/constants.d.ts +1 -0
  63. package/lib/es/tooltip/constants.js +2 -2
  64. package/lib/es/tooltip/foundation.d.ts +21 -2
  65. package/lib/es/tooltip/foundation.js +352 -77
  66. package/lib/es/transfer/foundation.d.ts +1 -1
  67. package/lib/es/transfer/foundation.js +3 -4
  68. package/navigation/navigation.scss +9 -0
  69. package/package.json +2 -2
  70. package/table/constants.ts +2 -0
  71. package/table/table.scss +2 -1
  72. package/tabs/tabs.scss +43 -2
  73. package/tabs/variables.scss +20 -0
  74. package/tooltip/constants.ts +1 -0
  75. package/tooltip/foundation.ts +318 -78
  76. package/transfer/foundation.ts +3 -3
@@ -133,11 +133,26 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
133
133
  unBindResizeEvent() {
134
134
  this._adapter.unregisterResizeHandler(this.onResize);
135
135
  }
136
-
136
+
137
137
  removePortal = () => {
138
138
  this._adapter.removePortal();
139
139
  }
140
140
 
141
+ _adjustPos(position = '', isVertical = false, adjustType = 'reverse', concatPos?: any) {
142
+ switch (adjustType) {
143
+ case 'reverse':
144
+ return this._reversePos(position, isVertical);
145
+ case 'expand':
146
+ // only happens when position is top/bottom/left/right
147
+ return this._expandPos(position, concatPos);
148
+ case 'reduce':
149
+ // only happens when position other than top/bottom/left/right
150
+ return this._reducePos(position);
151
+ default:
152
+ return this._reversePos(position, isVertical);
153
+ }
154
+ }
155
+
141
156
  _reversePos(position = '', isVertical = false) {
142
157
  if (isVertical) {
143
158
  if (REGS.TOP.test(position)) {
@@ -153,6 +168,16 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
153
168
  return position;
154
169
  }
155
170
 
171
+ _expandPos(position = '', concatPos: string) {
172
+ return position.concat(concatPos);
173
+ }
174
+
175
+ _reducePos(position = '') {
176
+ // if cur position consists of two directions, remove the last position
177
+ const found = ['Top', 'Bottom', 'Left', 'Right'].find(pos => position.endsWith(pos));
178
+ return found ? position.replace(found, ''): position;
179
+ }
180
+
156
181
  clearDelayTimer() {
157
182
  if (this._timer) {
158
183
  clearTimeout(this._timer);
@@ -285,9 +310,7 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
285
310
  this._togglePortalVisible(true);
286
311
  });
287
312
 
288
- const position = this.calcPosition(null, null, null, false);
289
-
290
- this._adapter.insertPortal(content, position);
313
+ this._adapter.insertPortal(content, { left: -9990, top: -9999 }); // offscreen rendering
291
314
 
292
315
  if (trigger === 'custom') {
293
316
  // eslint-disable-next-line
@@ -358,14 +381,15 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
358
381
  return null;
359
382
  }
360
383
 
361
- calcPosStyle(triggerRect: DOMRect, wrapperRect: DOMRect, containerRect: PopupContainerDOMRect, position?: Position, spacing?: number) {
362
- triggerRect = (isEmpty(triggerRect) ? triggerRect : this._adapter.getTriggerBounding()) || { ...defaultRect as any };
363
- containerRect = (isEmpty(containerRect) ? containerRect : this._adapter.getPopupContainerRect()) || {
384
+ calcPosStyle(props: {triggerRect: DOMRect; wrapperRect: DOMRect; containerRect: PopupContainerDOMRect; position?: Position; spacing?: number; isOverFlow?: [boolean, boolean]}) {
385
+ const { spacing, isOverFlow } = props;
386
+ const triggerRect = (isEmpty(props.triggerRect) ? props.triggerRect : this._adapter.getTriggerBounding()) || { ...defaultRect as any };
387
+ const containerRect = (isEmpty(props.containerRect) ? props.containerRect : this._adapter.getPopupContainerRect()) || {
364
388
  ...defaultRect,
365
389
  };
366
- wrapperRect = (isEmpty(wrapperRect) ? wrapperRect : this._adapter.getWrapperBounding()) || { ...defaultRect as any };
390
+ const wrapperRect = (isEmpty(props.wrapperRect) ? props.wrapperRect : this._adapter.getWrapperBounding()) || { ...defaultRect as any };
367
391
  // eslint-disable-next-line
368
- position = position != null ? position : this.getProp('position');
392
+ const position = props.position != null ? props.position : this.getProp('position');
369
393
  // eslint-disable-next-line
370
394
  const SPACING = spacing != null ? spacing : this.getProp('spacing');
371
395
  const { arrowPointAtCenter, showArrow, arrowBounding } = this.getProps();
@@ -389,67 +413,104 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
389
413
  const offsetXWithArrow = positionOffsetX + horizontalArrowWidth / 2;
390
414
  const offsetYWithArrow = positionOffsetY + verticalArrowHeight / 2;
391
415
 
416
+ const heightDifference = wrapperRect.height - containerRect.height;
417
+ const widthDifference = wrapperRect.width - containerRect.width;
418
+
419
+ const offsetHeight = heightDifference > 0 ? heightDifference : 0;
420
+ const offsetWidth = widthDifference > 0 ? widthDifference : 0;
421
+ const isHeightOverFlow = isOverFlow && isOverFlow[0];
422
+ const isWidthOverFlow = isOverFlow && isOverFlow[1];
423
+
424
+ const isTriggerNearLeft = middleX - containerRect.left < containerRect.right - middleX;
425
+ const isTriggerNearTop = middleY - containerRect.top < containerRect.bottom - middleY;
426
+
427
+
392
428
  switch (position) {
393
429
  case 'top':
394
- left = middleX;
395
- top = triggerRect.top - SPACING;
430
+ // left = middleX;
431
+ // top = triggerRect.top - SPACING;
432
+ left = isWidthOverFlow ? (isTriggerNearLeft ? containerRect.left + wrapperRect.width / 2 : containerRect.right - wrapperRect.width / 2 + offsetWidth): middleX;
433
+ top = isHeightOverFlow ? containerRect.bottom + offsetHeight : triggerRect.top - SPACING;
396
434
  translateX = -0.5;
397
435
  translateY = -1;
398
436
  break;
399
437
  case 'topLeft':
400
- left = pointAtCenter ? middleX - offsetXWithArrow : triggerRect.left;
401
- top = triggerRect.top - SPACING;
438
+ // left = pointAtCenter ? middleX - offsetXWithArrow : triggerRect.left;
439
+ // top = triggerRect.top - SPACING;
440
+ left = isWidthOverFlow ? containerRect.left : (pointAtCenter ? middleX - offsetXWithArrow : triggerRect.left);
441
+ top = isHeightOverFlow ? containerRect.bottom + offsetHeight : triggerRect.top - SPACING;
402
442
  translateY = -1;
403
443
  break;
404
444
  case 'topRight':
405
- left = pointAtCenter ? middleX + offsetXWithArrow : triggerRect.right;
406
- top = triggerRect.top - SPACING;
445
+ // left = pointAtCenter ? middleX + offsetXWithArrow : triggerRect.right;
446
+ // top = triggerRect.top - SPACING;
447
+ left = isWidthOverFlow ? containerRect.right + offsetWidth : (pointAtCenter ? middleX + offsetXWithArrow : triggerRect.right);
448
+ top = isHeightOverFlow ? containerRect.bottom + offsetHeight : triggerRect.top - SPACING;
407
449
  translateY = -1;
408
450
  translateX = -1;
409
451
  break;
410
452
  case 'left':
411
- left = triggerRect.left - SPACING;
412
- top = middleY;
453
+ // left = triggerRect.left - SPACING;
454
+ // top = middleY;
455
+ // left = isWidthOverFlow? containerRect.right - SPACING : triggerRect.left - SPACING;
456
+ left = isWidthOverFlow ? containerRect.right + offsetWidth - SPACING + offsetXWithArrow : triggerRect.left - SPACING;
457
+ top = isHeightOverFlow ? (isTriggerNearTop ? containerRect.top + wrapperRect.height / 2 : containerRect.bottom - wrapperRect.height / 2 + offsetHeight): middleY;
413
458
  translateX = -1;
414
459
  translateY = -0.5;
415
460
  break;
416
461
  case 'leftTop':
417
- left = triggerRect.left - SPACING;
418
- top = pointAtCenter ? middleY - offsetYWithArrow : triggerRect.top;
462
+ // left = triggerRect.left - SPACING;
463
+ // top = pointAtCenter ? middleY - offsetYWithArrow : triggerRect.top;
464
+ left = isWidthOverFlow ? containerRect.right + offsetWidth - SPACING + offsetXWithArrow : triggerRect.left - SPACING;
465
+ top = isHeightOverFlow ? containerRect.top : (pointAtCenter ? middleY - offsetYWithArrow : triggerRect.top);
419
466
  translateX = -1;
420
467
  break;
421
468
  case 'leftBottom':
422
- left = triggerRect.left - SPACING;
423
- top = pointAtCenter ? middleY + offsetYWithArrow : triggerRect.bottom;
469
+ // left = triggerRect.left - SPACING;
470
+ // top = pointAtCenter ? middleY + offsetYWithArrow : triggerRect.bottom;
471
+ left = isWidthOverFlow ? containerRect.right + offsetWidth - SPACING + offsetXWithArrow: triggerRect.left - SPACING;
472
+ top = isHeightOverFlow ? containerRect.bottom + offsetHeight: (pointAtCenter ? middleY + offsetYWithArrow : triggerRect.bottom);
424
473
  translateX = -1;
425
474
  translateY = -1;
426
475
  break;
427
476
  case 'bottom':
428
- left = middleX;
429
- top = triggerRect.top + triggerRect.height + SPACING;
477
+ // left = middleX;
478
+ // top = triggerRect.top + triggerRect.height + SPACING;
479
+ left = isWidthOverFlow ? (isTriggerNearLeft ? containerRect.left + wrapperRect.width / 2 : containerRect.right - wrapperRect.width / 2 + offsetWidth): middleX;
480
+ top = isHeightOverFlow ? containerRect.top + offsetYWithArrow - SPACING: triggerRect.top + triggerRect.height + SPACING;
430
481
  translateX = -0.5;
431
482
  break;
432
483
  case 'bottomLeft':
433
- left = pointAtCenter ? middleX - offsetXWithArrow : triggerRect.left;
434
- top = triggerRect.bottom + SPACING;
484
+ // left = pointAtCenter ? middleX - offsetXWithArrow : triggerRect.left;
485
+ // top = triggerRect.bottom + SPACING;
486
+ left = isWidthOverFlow ? containerRect.left : (pointAtCenter ? middleX - offsetXWithArrow : triggerRect.left);
487
+ top = isHeightOverFlow ? containerRect.top + offsetYWithArrow - SPACING : triggerRect.top + triggerRect.height + SPACING;
435
488
  break;
436
489
  case 'bottomRight':
437
- left = pointAtCenter ? middleX + offsetXWithArrow : triggerRect.right;
438
- top = triggerRect.bottom + SPACING;
490
+ // left = pointAtCenter ? middleX + offsetXWithArrow : triggerRect.right;
491
+ // top = triggerRect.bottom + SPACING;
492
+ left = isWidthOverFlow ? containerRect.right + offsetWidth : (pointAtCenter ? middleX + offsetXWithArrow : triggerRect.right);
493
+ top = isHeightOverFlow ? containerRect.top + offsetYWithArrow - SPACING : triggerRect.top + triggerRect.height + SPACING;
439
494
  translateX = -1;
440
495
  break;
441
496
  case 'right':
442
- left = triggerRect.right + SPACING;
443
- top = middleY;
497
+ // left = triggerRect.right + SPACING;
498
+ // top = middleY;
499
+ left = isWidthOverFlow ? containerRect.left - SPACING + offsetXWithArrow : triggerRect.right + SPACING;
500
+ top = isHeightOverFlow ? (isTriggerNearTop ? containerRect.top + wrapperRect.height / 2 : containerRect.bottom - wrapperRect.height / 2 + offsetHeight) : middleY;
444
501
  translateY = -0.5;
445
502
  break;
446
503
  case 'rightTop':
447
- left = triggerRect.right + SPACING;
448
- top = pointAtCenter ? middleY - offsetYWithArrow : triggerRect.top;
504
+ // left = triggerRect.right + SPACING;
505
+ // top = pointAtCenter ? middleY - offsetYWithArrow : triggerRect.top;
506
+ left = isWidthOverFlow ? containerRect.left - SPACING + offsetXWithArrow : triggerRect.right + SPACING;
507
+ top = isHeightOverFlow ? containerRect.top : (pointAtCenter ? middleY - offsetYWithArrow : triggerRect.top);
449
508
  break;
450
509
  case 'rightBottom':
451
- left = triggerRect.right + SPACING;
452
- top = pointAtCenter ? middleY + offsetYWithArrow : triggerRect.bottom;
510
+ // left = triggerRect.right + SPACING;
511
+ // top = pointAtCenter ? middleY + offsetYWithArrow : triggerRect.bottom;
512
+ left = isWidthOverFlow ? containerRect.left - SPACING + offsetXWithArrow : triggerRect.right + SPACING;
513
+ top = isHeightOverFlow ? containerRect.bottom + offsetHeight : (pointAtCenter ? middleY + offsetYWithArrow : triggerRect.bottom);
453
514
  translateY = -1;
454
515
  break;
455
516
  case 'leftTopOver':
@@ -574,18 +635,18 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
574
635
 
575
636
  // console.log('containerRect: ', containerRect, 'triggerRect: ', triggerRect, 'wrapperRect: ', wrapperRect);
576
637
 
577
- let style = this.calcPosStyle(triggerRect, wrapperRect, containerRect);
638
+ let style = this.calcPosStyle({ triggerRect, wrapperRect, containerRect });
578
639
 
579
640
  let position = this.getProp('position');
580
641
 
581
642
  if (this.getProp('autoAdjustOverflow')) {
582
643
  // console.log('style: ', style, '\ntriggerRect: ', triggerRect, '\nwrapperRect: ', wrapperRect);
583
- const adjustedPos = this.adjustPosIfNeed(position, style, triggerRect, wrapperRect, containerRect);
644
+ const { position: adjustedPos, isHeightOverFlow, isWidthOverFlow } = this.adjustPosIfNeed(position, style, triggerRect, wrapperRect, containerRect);
584
645
 
585
- if (position !== adjustedPos) {
646
+ if (position !== adjustedPos || isHeightOverFlow || isWidthOverFlow) {
586
647
  position = adjustedPos;
587
648
 
588
- style = this.calcPosStyle(triggerRect, wrapperRect, containerRect, position);
649
+ style = this.calcPosStyle({ triggerRect, wrapperRect, containerRect, position, spacing: null, isOverFlow: [ isHeightOverFlow, isWidthOverFlow ] });
589
650
  }
590
651
  }
591
652
 
@@ -598,17 +659,66 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
598
659
  };
599
660
 
600
661
  isLR(position = '') {
601
- return position.indexOf('left') === 0 || position.indexOf('right') === 0;
662
+ return position.includes('left') || position.includes('right');
602
663
  }
603
664
 
604
665
  isTB(position = '') {
605
- return position.indexOf('top') === 0 || position.indexOf('bottom') === 0;
666
+ return position.includes('top') || position.includes('bottom');
667
+ }
668
+
669
+ isReverse(rowSpace: number, reverseSpace: number, size: number) {
670
+ // 原空间不足,反向空间足够
671
+ // Insufficient original space, enough reverse space
672
+ return rowSpace < size && reverseSpace > size;
673
+ }
674
+
675
+ isOverFlow(rowSpace: number, reverseSpace: number, size: number){
676
+ // 原空间且反向空间都不足
677
+ // The original space and the reverse space are not enough
678
+ return rowSpace < size && reverseSpace < size;
679
+ }
680
+
681
+ isHalfOverFlow(posSpace: number, negSpace: number, size: number){
682
+ // 正半空间或者负半空间不足,即表示有遮挡,需要偏移
683
+ // Insufficient positive half space or negative half space means that there is occlusion and needs to be offset
684
+ return posSpace < size || negSpace < size;
685
+ }
686
+
687
+ isHalfAllEnough(posSpace: number, negSpace: number, size: number){
688
+ // 正半空间和负半空间都足够,即表示可以从 topLeft/topRight 变成 top
689
+ // Both positive and negative half-spaces are sufficient, which means you can change from topLeft/topRight to top
690
+ return posSpace >= size || negSpace >= size;
691
+ }
692
+
693
+ getReverse(viewOverFlow: boolean, containerOverFlow: boolean, shouldReverseView: boolean, shouldReverseContainer: boolean) {
694
+ /**
695
+ * 基于视口和容器一起判断,以下几种情况允许从原方向转到反方向,以判断是否应该由top->bottom为例子
696
+ *
697
+ * 1. 视口上下空间不足 且 容器上空间❌下空间✅
698
+ * 2. 视口上空间❌下空间✅ 且 容器上下空间不足
699
+ * 3. 视口上空间❌下空间✅ 且 容器上空间❌下空间✅
700
+ *
701
+ * Based on the judgment of the viewport and the container, the following situations are allowed to turn from the original direction to the opposite direction
702
+ * to judge whether it should be top->bottom as an example
703
+ * 1. There is insufficient space above and below the viewport and the space above the container ❌ the space below ✅
704
+ * 2. The space above the viewport ❌ the space below ✅ and the space above and below the container is insufficient
705
+ * 3. Viewport upper space ❌ lower space✅ and container upper space ❌ lower space✅
706
+ */
707
+ return (viewOverFlow && shouldReverseContainer) || (shouldReverseView && containerOverFlow) || (shouldReverseView && shouldReverseContainer);
606
708
  }
607
709
 
608
710
  // place the dom correctly
609
711
  adjustPosIfNeed(position: Position | string, style: Record<string, any>, triggerRect: DOMRect, wrapperRect: DOMRect, containerRect: PopupContainerDOMRect) {
610
712
  const { innerWidth, innerHeight } = window;
611
- const { spacing } = this.getProps();
713
+ const { spacing, margin } = this.getProps();
714
+
715
+ const marginLeft = typeof margin === 'number' ? margin : margin.marginLeft;
716
+ const marginTop = typeof margin === 'number' ? margin : margin.marginTop;
717
+ const marginRight = typeof margin === 'number' ? margin : margin.marginRight;
718
+ const marginBottom = typeof margin === 'number' ? margin : margin.marginBottom;
719
+
720
+ let isHeightOverFlow = false;
721
+ let isWidthOverFlow = false;
612
722
 
613
723
  if (wrapperRect.width > 0 && wrapperRect.height > 0) {
614
724
  // let clientLeft = left + translateX * wrapperRect.width - containerRect.scrollLeft;
@@ -638,144 +748,274 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
638
748
 
639
749
  // The wrapperR ect.top|bottom equivalent cannot be directly used here for comparison, which is easy to cause jitter
640
750
 
641
- const shouldReverseTop = clientTop < wrapperRect.height + spacing && restClientBottom > wrapperRect.height + spacing;
642
- const shouldReverseLeft = clientLeft < wrapperRect.width + spacing && restClientRight > wrapperRect.width + spacing;
643
- const shouldReverseBottom = restClientBottom < wrapperRect.height + spacing && clientTop > wrapperRect.height + spacing;
644
- const shouldReverseRight = restClientRight < wrapperRect.width + spacing && clientLeft > wrapperRect.width + spacing;
751
+ // 基于视口的微调判断
752
+ // Fine-tuning judgment based on viewport
753
+ const shouldViewReverseTop = clientTop - marginTop < wrapperRect.height + spacing && restClientBottom - marginBottom > wrapperRect.height + spacing;
754
+ const shouldViewReverseLeft = clientLeft - marginLeft < wrapperRect.width + spacing && restClientRight - marginRight > wrapperRect.width + spacing;
755
+ const shouldViewReverseBottom = restClientBottom - marginBottom < wrapperRect.height + spacing && clientTop - marginTop > wrapperRect.height + spacing;
756
+ const shouldViewReverseRight = restClientRight - marginRight < wrapperRect.width + spacing && clientLeft - marginLeft > wrapperRect.width + spacing;
757
+ const shouldViewReverseTopOver = restClientTop - marginBottom< wrapperRect.height + spacing && clientBottom - marginTop> wrapperRect.height + spacing;
758
+ const shouldViewReverseBottomOver = clientBottom - marginTop < wrapperRect.height + spacing && restClientTop - marginBottom > wrapperRect.height + spacing;
759
+
760
+ const shouldViewReverseTopSide = restClientTop < wrapperRect.height && clientBottom > wrapperRect.height;
761
+ const shouldViewReverseBottomSide = clientBottom < wrapperRect.height && restClientTop > wrapperRect.height;
762
+ const shouldViewReverseLeftSide = restClientLeft < wrapperRect.width && clientRight > wrapperRect.width;
763
+ const shouldViewReverseRightSide = clientRight < wrapperRect.width && restClientLeft > wrapperRect.width;
764
+
645
765
  const shouldReverseTopOver = restClientTop < wrapperRect.height + spacing && clientBottom > wrapperRect.height + spacing;
646
766
  const shouldReverseBottomOver = clientBottom < wrapperRect.height + spacing && restClientTop > wrapperRect.height + spacing;
647
767
 
648
- const shouldReverseTopSide = restClientTop < wrapperRect.height && clientBottom > wrapperRect.height;
649
- const shouldReverseBottomSide = clientBottom < wrapperRect.height && restClientTop > wrapperRect.height;
650
- const shouldReverseLeftSide = restClientLeft < wrapperRect.width && clientRight > wrapperRect.width;
651
- const shouldReverseRightSide = clientRight < wrapperRect.width && restClientLeft > wrapperRect.width;
652
-
653
768
  const shouldReverseLeftOver = restClientLeft < wrapperRect.width && clientRight > wrapperRect.width;
654
769
  const shouldReverseRightOver = clientRight < wrapperRect.width && restClientLeft > wrapperRect.width;
655
770
 
771
+ // 基于容器的微调判断
772
+ // Fine-tuning judgment based on container
773
+ const clientTopInContainer = clientTop - containerRect.top;
774
+ const clientLeftInContainer = clientLeft - containerRect.left;
775
+ const clientBottomInContainer = clientTopInContainer + triggerRect.height;
776
+ const clientRightInContainer = clientLeftInContainer + triggerRect.width;
777
+
778
+ const restClientBottomInContainer = containerRect.bottom - clientBottom;
779
+ const restClientRightInContainer = containerRect.right - clientRight;
780
+ const restClientTopInContainer = restClientBottomInContainer + triggerRect.height;
781
+ const restClientLeftInContainer = restClientRightInContainer + triggerRect.width;
782
+
783
+ // 当原空间不足,反向空间足够时,可以反向。
784
+ // When the original space is insufficient and the reverse space is sufficient, the reverse can be performed.
785
+ const shouldContainerReverseTop = this.isReverse(clientTopInContainer - marginTop, restClientBottomInContainer - marginBottom, wrapperRect.height + spacing);
786
+ const shouldContainerReverseLeft = this.isReverse(clientLeftInContainer - marginLeft, restClientRightInContainer - marginRight, wrapperRect.width + spacing);
787
+ const shouldContainerReverseBottom = this.isReverse(restClientBottomInContainer - marginBottom, clientTopInContainer - marginTop, wrapperRect.height + spacing);
788
+ const shouldContainerReverseRight = this.isReverse(restClientRightInContainer - marginRight, clientLeftInContainer - marginLeft, wrapperRect.width + spacing);
789
+ const shouldContainerReverseTopOver = this.isReverse(restClientTopInContainer - marginBottom, clientBottomInContainer - marginTop, wrapperRect.height + spacing);
790
+ const shouldContainerReverseBottomOver = this.isReverse(clientBottomInContainer - marginTop, restClientTopInContainer - marginBottom, wrapperRect.height + spacing);
791
+
792
+ const shouldContainerReverseTopSide = this.isReverse(restClientTopInContainer, clientBottomInContainer, wrapperRect.height);
793
+ const shouldContainerReverseBottomSide = this.isReverse(clientBottomInContainer, restClientTopInContainer, wrapperRect.height);
794
+ const shouldContainerReverseLeftSide = this.isReverse(restClientLeftInContainer, clientRightInContainer, wrapperRect.width);
795
+ const shouldContainerReverseRightSide = this.isReverse(clientRightInContainer, restClientLeftInContainer, wrapperRect.width);
796
+
797
+ const halfHeight = triggerRect.height / 2;
798
+ const halfWidth = triggerRect.width / 2;
799
+
800
+ // 视口, 原空间与反向空间是否都不足判断
801
+ // Viewport, whether the original space and the reverse space are insufficient to judge
802
+ const isViewYOverFlow = this.isOverFlow(clientTop - marginTop, restClientBottom - marginBottom, wrapperRect.height + spacing);
803
+ const isViewXOverFlow = this.isOverFlow(clientLeft - marginLeft, restClientRight - marginRight, wrapperRect.width + spacing);
804
+ const isViewYOverFlowSide = this.isOverFlow(clientBottom - marginTop, restClientTop - marginBottom, wrapperRect.height + spacing);
805
+ const isViewXOverFlowSide = this.isOverFlow(clientRight - marginLeft, restClientLeft - marginRight, wrapperRect.width + spacing);
806
+ const isViewYOverFlowSideHalf = this.isHalfOverFlow(clientBottom - halfHeight, restClientTop - halfHeight, wrapperRect.height / 2);
807
+ const isViewXOverFlowSideHalf = this.isHalfOverFlow(clientRight - halfWidth, restClientLeft - halfWidth, wrapperRect.width / 2);
808
+ const isViewYEnoughSideHalf = this.isHalfAllEnough(clientBottom - halfHeight, restClientTop - halfHeight, wrapperRect.height / 2);
809
+ const isViewXEnoughSideHalf = this.isHalfAllEnough(clientRight - halfWidth, restClientLeft - halfWidth, wrapperRect.width / 2);
810
+
811
+ // 容器, 原空间与反向空间是否都不足判断
812
+ // container, whether the original space and the reverse space are insufficient to judge
813
+ const isContainerYOverFlow = this.isOverFlow(clientTopInContainer - marginTop, restClientBottomInContainer - marginBottom, wrapperRect.height + spacing);
814
+ const isContainerXOverFlow = this.isOverFlow(clientLeftInContainer - marginLeft, restClientRightInContainer - marginRight, wrapperRect.width + spacing);
815
+ const isContainerYOverFlowSide = this.isOverFlow(clientBottomInContainer - marginTop, restClientTopInContainer - marginBottom, wrapperRect.height + spacing);
816
+ const isContainerXOverFlowSide = this.isOverFlow(clientRightInContainer - marginLeft, restClientLeftInContainer - marginRight, wrapperRect.width + spacing);
817
+ const isContainerYOverFlowSideHalf = this.isHalfOverFlow(clientBottomInContainer - halfHeight, restClientTopInContainer - halfHeight, wrapperRect.height / 2);
818
+ const isContainerXOverFlowSideHalf = this.isHalfOverFlow(clientRightInContainer - halfWidth, restClientLeftInContainer - halfWidth, wrapperRect.width / 2);
819
+ const isContainerYEnoughSideHalf = this.isHalfAllEnough(clientBottomInContainer - halfHeight, restClientTopInContainer - halfHeight, wrapperRect.height / 2);
820
+ const isContainerXEnoughSideHalf = this.isHalfAllEnough(clientRightInContainer - halfWidth, restClientLeftInContainer - halfWidth, wrapperRect.width / 2);
821
+
822
+ // 综合 viewport + container 判断微调,即视口 + 容器都放置不行时才能考虑位置调整
823
+ // Comprehensive viewport + container judgment fine-tuning, that is, the position adjustment can only be considered when the viewport + container cannot be placed.
824
+ const shouldReverseTop = this.getReverse(isViewYOverFlow, isContainerYOverFlow, shouldViewReverseTop, shouldContainerReverseTop);
825
+ const shouldReverseLeft = this.getReverse(isViewXOverFlow, isContainerXOverFlow, shouldViewReverseLeft, shouldContainerReverseLeft);
826
+ const shouldReverseBottom = this.getReverse(isViewYOverFlow, isContainerYOverFlow, shouldViewReverseBottom, shouldContainerReverseBottom);
827
+ const shouldReverseRight = this.getReverse(isViewXOverFlow, isContainerXOverFlow, shouldViewReverseRight, shouldContainerReverseRight);
828
+
829
+ // const shouldReverseTopOver = this.getReverse(isViewYOverFlowSide, isContainerYOverFlowSide, shouldViewReverseTopOver, shouldContainerReverseTopOver);
830
+ // const shouldReverseBottomOver = this.getReverse(isViewYOverFlowSide, isContainerYOverFlowSide, shouldViewReverseBottomOver, shouldContainerReverseBottomOver);
831
+
832
+ const shouldReverseTopSide = this.getReverse(isViewYOverFlowSide, isContainerYOverFlowSide, shouldViewReverseTopSide, shouldContainerReverseTopSide);
833
+ const shouldReverseBottomSide = this.getReverse(isViewYOverFlowSide, isContainerYOverFlowSide, shouldViewReverseBottomSide, shouldContainerReverseBottomSide);
834
+ const shouldReverseLeftSide = this.getReverse(isViewXOverFlowSide, isContainerXOverFlowSide, shouldViewReverseLeftSide, shouldContainerReverseLeftSide);
835
+ const shouldReverseRightSide = this.getReverse(isViewXOverFlowSide, isContainerXOverFlowSide, shouldViewReverseRightSide, shouldContainerReverseRightSide);
836
+
837
+ const isYOverFlowSideHalf = isViewYOverFlowSideHalf && isContainerYOverFlowSideHalf;
838
+ const isXOverFlowSideHalf = isViewXOverFlowSideHalf && isContainerXOverFlowSideHalf;
839
+
656
840
  switch (position) {
657
841
  case 'top':
658
842
  if (shouldReverseTop) {
659
- position = this._reversePos(position, true);
843
+ position = this._adjustPos(position, true);
844
+ }
845
+ if (isXOverFlowSideHalf && (shouldReverseLeftSide || shouldReverseRightSide)) {
846
+ position = this._adjustPos(position, true, 'expand', shouldReverseLeftSide ? 'Right' : 'Left');
660
847
  }
661
848
  break;
662
849
  case 'topLeft':
663
850
  if (shouldReverseTop) {
664
- position = this._reversePos(position, true);
851
+ position = this._adjustPos(position, true);
665
852
  }
666
853
  if (shouldReverseLeftSide && widthIsBigger) {
667
- position = this._reversePos(position);
854
+ position = this._adjustPos(position, true);
855
+ }
856
+ if (isWidthOverFlow && (isViewXEnoughSideHalf || isContainerXEnoughSideHalf)) {
857
+ position = this._adjustPos(position, true, 'reduce');
668
858
  }
669
859
  break;
670
860
  case 'topRight':
671
861
  if (shouldReverseTop) {
672
- position = this._reversePos(position, true);
862
+ position = this._adjustPos(position, true);
673
863
  }
674
864
  if (shouldReverseRightSide && widthIsBigger) {
675
- position = this._reversePos(position);
865
+ position = this._adjustPos(position);
866
+ }
867
+ if (isWidthOverFlow && (isViewXEnoughSideHalf || isContainerXEnoughSideHalf)) {
868
+ position = this._adjustPos(position, true, 'reduce');
676
869
  }
677
870
  break;
678
871
  case 'left':
679
872
  if (shouldReverseLeft) {
680
- position = this._reversePos(position);
873
+ position = this._adjustPos(position);
874
+ }
875
+ if (isYOverFlowSideHalf && (shouldReverseTopSide || shouldReverseBottomSide)) {
876
+ position = this._adjustPos(position, false, 'expand', shouldReverseTopSide ? 'Bottom' : 'Top');
681
877
  }
682
878
  break;
683
879
  case 'leftTop':
684
880
  if (shouldReverseLeft) {
685
- position = this._reversePos(position);
881
+ position = this._adjustPos(position);
686
882
  }
687
883
  if (shouldReverseTopSide && heightIsBigger) {
688
- position = this._reversePos(position, true);
884
+ position = this._adjustPos(position, true);
885
+ }
886
+ if (isHeightOverFlow && (isViewYEnoughSideHalf || isContainerYEnoughSideHalf)) {
887
+ position = this._adjustPos(position, false, 'reduce');
689
888
  }
690
889
  break;
691
890
  case 'leftBottom':
692
891
  if (shouldReverseLeft) {
693
- position = this._reversePos(position);
892
+ position = this._adjustPos(position);
694
893
  }
695
894
  if (shouldReverseBottomSide && heightIsBigger) {
696
- position = this._reversePos(position, true);
895
+ position = this._adjustPos(position, true);
896
+ }
897
+ if (isHeightOverFlow && (isViewYEnoughSideHalf || isContainerYEnoughSideHalf)) {
898
+ position = this._adjustPos(position, false, 'reduce');
697
899
  }
698
900
  break;
699
901
  case 'bottom':
700
902
  if (shouldReverseBottom) {
701
- position = this._reversePos(position, true);
903
+ position = this._adjustPos(position, true);
904
+ }
905
+ if (isXOverFlowSideHalf && (shouldReverseLeftSide || shouldReverseRightSide)) {
906
+ position = this._adjustPos(position, true, 'expand', shouldReverseLeftSide ? 'Right' : 'Left');
702
907
  }
703
908
  break;
704
909
  case 'bottomLeft':
705
910
  if (shouldReverseBottom) {
706
- position = this._reversePos(position, true);
911
+ position = this._adjustPos(position, true);
707
912
  }
708
913
  if (shouldReverseLeftSide && widthIsBigger) {
709
- position = this._reversePos(position);
914
+ position = this._adjustPos(position);
915
+ }
916
+ if (isWidthOverFlow && (isViewXEnoughSideHalf || isContainerXEnoughSideHalf)) {
917
+ position = this._adjustPos(position, true, 'reduce');
710
918
  }
711
919
  break;
712
920
  case 'bottomRight':
713
921
  if (shouldReverseBottom) {
714
- position = this._reversePos(position, true);
922
+ position = this._adjustPos(position, true);
715
923
  }
716
924
  if (shouldReverseRightSide && widthIsBigger) {
717
- position = this._reversePos(position);
925
+ position = this._adjustPos(position);
926
+ }
927
+ if (isWidthOverFlow && (isViewXEnoughSideHalf || isContainerXEnoughSideHalf)) {
928
+ position = this._adjustPos(position, true, 'reduce');
718
929
  }
719
930
  break;
720
931
  case 'right':
721
932
  if (shouldReverseRight) {
722
- position = this._reversePos(position);
933
+ position = this._adjustPos(position);
934
+ }
935
+ if (isYOverFlowSideHalf && (shouldReverseTopSide || shouldReverseBottomSide)) {
936
+ position = this._adjustPos(position, false, 'expand', shouldReverseTopSide ? 'Bottom' : 'Top');
723
937
  }
724
938
  break;
725
939
  case 'rightTop':
726
940
  if (shouldReverseRight) {
727
- position = this._reversePos(position);
941
+ position = this._adjustPos(position);
728
942
  }
729
943
  if (shouldReverseTopSide && heightIsBigger) {
730
- position = this._reversePos(position, true);
944
+ position = this._adjustPos(position, true);
945
+ }
946
+ if (isHeightOverFlow && (isViewYEnoughSideHalf || isContainerYEnoughSideHalf)) {
947
+ position = this._adjustPos(position, false, 'reduce');
731
948
  }
732
949
  break;
733
950
  case 'rightBottom':
734
951
  if (shouldReverseRight) {
735
- position = this._reversePos(position);
952
+ position = this._adjustPos(position);
736
953
  }
737
954
  if (shouldReverseBottomSide && heightIsBigger) {
738
- position = this._reversePos(position, true);
955
+ position = this._adjustPos(position, true);
956
+ }
957
+ if (isHeightOverFlow && (isViewYEnoughSideHalf || isContainerYEnoughSideHalf)) {
958
+ position = this._adjustPos(position, false, 'reduce');
739
959
  }
740
960
  break;
741
961
  case 'leftTopOver':
742
962
  if (shouldReverseTopOver) {
743
- position = this._reversePos(position, true);
963
+ position = this._adjustPos(position, true);
744
964
  }
745
965
  if (shouldReverseLeftOver) {
746
- position = this._reversePos(position);
966
+ position = this._adjustPos(position);
747
967
  }
748
968
  break;
749
969
  case 'leftBottomOver':
750
970
  if (shouldReverseBottomOver) {
751
- position = this._reversePos(position, true);
971
+ position = this._adjustPos(position, true);
752
972
  }
753
973
  if (shouldReverseLeftOver) {
754
- position = this._reversePos(position);
974
+ position = this._adjustPos(position);
755
975
  }
756
976
  break;
757
977
  case 'rightTopOver':
758
978
  if (shouldReverseTopOver) {
759
- position = this._reversePos(position, true);
979
+ position = this._adjustPos(position, true);
760
980
  }
761
981
  if (shouldReverseRightOver) {
762
- position = this._reversePos(position);
982
+ position = this._adjustPos(position);
763
983
  }
764
984
  break;
765
985
  case 'rightBottomOver':
766
986
  if (shouldReverseBottomOver) {
767
- position = this._reversePos(position, true);
987
+ position = this._adjustPos(position, true);
768
988
  }
769
989
  if (shouldReverseRightOver) {
770
- position = this._reversePos(position);
990
+ position = this._adjustPos(position);
771
991
  }
772
992
  break;
773
993
  default:
774
994
  break;
775
995
  }
996
+
997
+ // 判断溢出 Judgment overflow
998
+ // 上下方向 top and bottom
999
+ if (this.isTB(position)){
1000
+ isHeightOverFlow = isViewYOverFlow && isContainerYOverFlow;
1001
+ if (position === 'top' || position === 'bottom') {
1002
+ isWidthOverFlow = isViewXOverFlowSideHalf && isContainerXOverFlowSideHalf;
1003
+ } else {
1004
+ isWidthOverFlow = isViewXOverFlowSide && isContainerXOverFlowSide;
1005
+ }
1006
+ }
1007
+ // 左右方向 left and right
1008
+ if (this.isLR(position)){
1009
+ isWidthOverFlow = isViewXOverFlow && isContainerXOverFlow;
1010
+ if (position === 'left' || position === 'right') {
1011
+ isHeightOverFlow = isViewYOverFlowSideHalf && isContainerYOverFlowSideHalf;
1012
+ } else {
1013
+ isHeightOverFlow = isViewYOverFlowSide && isContainerYOverFlowSide;
1014
+ }
1015
+ }
776
1016
  }
777
1017
 
778
- return position;
1018
+ return { position, isHeightOverFlow, isWidthOverFlow };
779
1019
  }
780
1020
 
781
1021
  delayHide = () => {
@@ -61,13 +61,13 @@ export default class TransferFoundation<P = Record<string, any>, S = Record<stri
61
61
  return path.map((p: any) => p.label).join(' > ');
62
62
  }
63
63
 
64
- handleInputChange(inputVal: string) {
64
+ handleInputChange(inputVal: string, notify: boolean) {
65
65
  const { data } = this.getStates();
66
66
  const { filter, type } = this.getProps();
67
67
  if (type === strings.TYPE_TREE_TO_LIST) {
68
68
  const searchResult = new Set(data.map((item: BasicResolvedDataItem) => item.key)) as Set<number | string>;
69
69
  this._adapter.searchTree(inputVal);
70
- this._adapter.notifySearch(inputVal);
70
+ notify && this._adapter.notifySearch(inputVal);
71
71
  this._adapter.updateInput(inputVal);
72
72
  this._adapter.updateSearchResult(searchResult);
73
73
  return;
@@ -77,7 +77,7 @@ export default class TransferFoundation<P = Record<string, any>, S = Record<stri
77
77
  (item: BasicResolvedDataItem) => typeof item.label === 'string' && item.label.includes(inputVal);
78
78
  const searchData = data.filter(filterFunc);
79
79
  const searchResult = new Set(searchData.map((item: BasicResolvedDataItem) => item.key)) as Set<number | string>;
80
- this._adapter.notifySearch(inputVal);
80
+ notify && this._adapter.notifySearch(inputVal);
81
81
  this._adapter.updateInput(inputVal);
82
82
  this._adapter.updateSearchResult(searchResult);
83
83
  }