raise-common-lib 0.0.220 → 0.0.222-beta

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.
@@ -24292,22 +24292,91 @@
24292
24292
  if (this.opened === "yes" &&
24293
24293
  previousTrigger !== this.currentTriggerElement &&
24294
24294
  this.currentTriggerElement) {
24295
- // 使用新的打开方式更新位置
24296
- this.positioning = "yes";
24297
- this.ref.markForCheck();
24298
- requestAnimationFrame((/**
24299
- * @return {?}
24300
- */
24301
- function () {
24295
+ // 如果提供了固定尺寸,直接重新计算位置(避免位置跳动)
24296
+ if (this._width !== null && this._height !== null) {
24297
+ // 先隐藏弹窗(positioning = yes)
24298
+ this.positioning = "yes";
24299
+ this.ref.markForCheck();
24300
+ this.ref.detectChanges(); // 立即应用隐藏状态
24302
24301
  requestAnimationFrame((/**
24303
24302
  * @return {?}
24304
24303
  */
24305
24304
  function () {
24306
- _this.updatePopupPosition();
24307
- _this.positioning = "no";
24308
- _this.ref.markForCheck();
24305
+ if (_this.currentTriggerElement) {
24306
+ /** @type {?} */
24307
+ var triggerRect = _this.currentTriggerElement.getBoundingClientRect();
24308
+ /** @type {?} */
24309
+ var popupSize = {
24310
+ width: (/** @type {?} */ (_this._width)),
24311
+ height: (/** @type {?} */ (_this._height)),
24312
+ };
24313
+ /** @type {?} */
24314
+ var targetInfo = _this.placementInfo;
24315
+ /** @type {?} */
24316
+ var finalPlacement = targetInfo.placement;
24317
+ /** @type {?} */
24318
+ var finalPosition = targetInfo.position;
24319
+ if (_this.autoAdjust) {
24320
+ /** @type {?} */
24321
+ var popupRect = (/** @type {?} */ ({
24322
+ width: popupSize.width,
24323
+ height: popupSize.height,
24324
+ top: 0,
24325
+ left: 0,
24326
+ right: popupSize.width,
24327
+ bottom: popupSize.height,
24328
+ x: 0,
24329
+ y: 0,
24330
+ toJSON: (/**
24331
+ * @return {?}
24332
+ */
24333
+ function () { return ({}); }),
24334
+ }));
24335
+ /** @type {?} */
24336
+ var optimal = _this.calculateOptimalPlacement(triggerRect, popupRect, window.innerWidth, window.innerHeight);
24337
+ finalPlacement = optimal.placement;
24338
+ }
24339
+ _this.actualPlacement = finalPlacement;
24340
+ _this.actualPosition = finalPosition;
24341
+ /** @type {?} */
24342
+ var position = _this.calculatePositionCoordinates(triggerRect, finalPlacement, finalPosition, popupSize);
24343
+ if (_this.popupElement && _this.popupElement.nativeElement) {
24344
+ /** @type {?} */
24345
+ var popupEl = _this.popupElement.nativeElement;
24346
+ popupEl.style.top = position.top;
24347
+ popupEl.style.left = position.left;
24348
+ popupEl.style.transform = "translate(" + position.translateX + ", " + position.translateY + ")";
24349
+ popupEl.offsetHeight; // 强制同步应用样式
24350
+ // 位置设置完成后,再显示弹窗
24351
+ requestAnimationFrame((/**
24352
+ * @return {?}
24353
+ */
24354
+ function () {
24355
+ _this.positioning = "no";
24356
+ _this.ref.markForCheck();
24357
+ }));
24358
+ }
24359
+ }
24309
24360
  }));
24310
- }));
24361
+ }
24362
+ else {
24363
+ // 使用新的打开方式更新位置
24364
+ this.positioning = "yes";
24365
+ this.ref.markForCheck();
24366
+ requestAnimationFrame((/**
24367
+ * @return {?}
24368
+ */
24369
+ function () {
24370
+ requestAnimationFrame((/**
24371
+ * @return {?}
24372
+ */
24373
+ function () {
24374
+ _this.updatePopupPosition();
24375
+ _this.positioning = "no";
24376
+ _this.ref.markForCheck();
24377
+ }));
24378
+ }));
24379
+ }
24311
24380
  }
24312
24381
  }
24313
24382
  // 处理 open 变化(确保在触发元素更新后处理)
@@ -24437,22 +24506,92 @@
24437
24506
  console.warn("SmartPopupComponent: No trigger element found");
24438
24507
  return;
24439
24508
  }
24440
- // 如果已经打开,先关闭再打开(更新位置)
24509
+ // 如果已经打开,且提供了固定尺寸,直接重新计算位置(避免关闭再打开导致的跳动)
24441
24510
  if (this.opened === "yes") {
24442
- // 先关闭弹窗
24443
- this.opened = "no";
24444
- this.positioning = "no";
24445
- this.ref.markForCheck();
24446
- // 立即在新位置打开
24447
- requestAnimationFrame((/**
24448
- * @return {?}
24449
- */
24450
- function () {
24451
- // 再次确保触发元素已更新
24452
- _this.updateTriggerElement();
24453
- _this.openPopup();
24454
- }));
24455
- return;
24511
+ if (this._width !== null && this._height !== null) {
24512
+ // 有固定尺寸,直接重新计算位置,不关闭弹窗
24513
+ // 先隐藏弹窗(positioning = yes)
24514
+ this.positioning = "yes";
24515
+ this.ref.markForCheck();
24516
+ this.ref.detectChanges(); // 立即应用隐藏状态
24517
+ requestAnimationFrame((/**
24518
+ * @return {?}
24519
+ */
24520
+ function () {
24521
+ // 再次确保触发元素已更新
24522
+ _this.updateTriggerElement();
24523
+ if (_this.currentTriggerElement) {
24524
+ /** @type {?} */
24525
+ var triggerRect = _this.currentTriggerElement.getBoundingClientRect();
24526
+ /** @type {?} */
24527
+ var popupSize = {
24528
+ width: (/** @type {?} */ (_this._width)),
24529
+ height: (/** @type {?} */ (_this._height)),
24530
+ };
24531
+ /** @type {?} */
24532
+ var targetInfo = _this.placementInfo;
24533
+ /** @type {?} */
24534
+ var finalPlacement = targetInfo.placement;
24535
+ /** @type {?} */
24536
+ var finalPosition = targetInfo.position;
24537
+ if (_this.autoAdjust) {
24538
+ /** @type {?} */
24539
+ var popupRect = (/** @type {?} */ ({
24540
+ width: popupSize.width,
24541
+ height: popupSize.height,
24542
+ top: 0,
24543
+ left: 0,
24544
+ right: popupSize.width,
24545
+ bottom: popupSize.height,
24546
+ x: 0,
24547
+ y: 0,
24548
+ toJSON: (/**
24549
+ * @return {?}
24550
+ */
24551
+ function () { return ({}); }),
24552
+ }));
24553
+ /** @type {?} */
24554
+ var optimal = _this.calculateOptimalPlacement(triggerRect, popupRect, window.innerWidth, window.innerHeight);
24555
+ finalPlacement = optimal.placement;
24556
+ }
24557
+ _this.actualPlacement = finalPlacement;
24558
+ _this.actualPosition = finalPosition;
24559
+ /** @type {?} */
24560
+ var position = _this.calculatePositionCoordinates(triggerRect, finalPlacement, finalPosition, popupSize);
24561
+ if (_this.popupElement && _this.popupElement.nativeElement) {
24562
+ /** @type {?} */
24563
+ var popupEl = _this.popupElement.nativeElement;
24564
+ popupEl.style.top = position.top;
24565
+ popupEl.style.left = position.left;
24566
+ popupEl.style.transform = "translate(" + position.translateX + ", " + position.translateY + ")";
24567
+ popupEl.offsetHeight; // 强制同步应用样式
24568
+ // 位置设置完成后,再显示弹窗
24569
+ requestAnimationFrame((/**
24570
+ * @return {?}
24571
+ */
24572
+ function () {
24573
+ _this.positioning = "no";
24574
+ _this.ref.markForCheck();
24575
+ }));
24576
+ }
24577
+ }
24578
+ }));
24579
+ return;
24580
+ }
24581
+ else {
24582
+ // 没有固定尺寸,先关闭再打开
24583
+ this.opened = "no";
24584
+ this.positioning = "no";
24585
+ this.ref.markForCheck();
24586
+ requestAnimationFrame((/**
24587
+ * @return {?}
24588
+ */
24589
+ function () {
24590
+ _this.updateTriggerElement();
24591
+ _this.openPopup();
24592
+ }));
24593
+ return;
24594
+ }
24456
24595
  }
24457
24596
  // 确保触发元素已更新
24458
24597
  this.updateTriggerElement();
@@ -24507,13 +24646,15 @@
24507
24646
  var targetInfo = this.placementInfo;
24508
24647
  /** @type {?} */
24509
24648
  var finalPlacement = targetInfo.placement;
24649
+ // 始终使用用户指定的 position,autoAdjust 只调整 placement(方向),不改变对齐方式
24510
24650
  /** @type {?} */
24511
24651
  var finalPosition = targetInfo.position;
24512
24652
  if (this.autoAdjust) {
24513
24653
  /** @type {?} */
24514
24654
  var optimal = this.calculateOptimalPlacement(triggerRect, popupRect, viewportWidth, viewportHeight);
24655
+ // autoAdjust 只调整 placement(上下左右),保持用户指定的 position(对齐方式)
24515
24656
  finalPlacement = optimal.placement;
24516
- finalPosition = optimal.position;
24657
+ // finalPosition 保持用户指定的值,不改变
24517
24658
  }
24518
24659
  this.actualPlacement = finalPlacement;
24519
24660
  this.actualPosition = finalPosition;
@@ -24521,56 +24662,57 @@
24521
24662
  /** @type {?} */
24522
24663
  var position_1 = this.calculatePositionCoordinates(triggerRect, finalPlacement, finalPosition, popupSize);
24523
24664
  // 先设置打开状态,但保持隐藏(positioning = yes)
24524
- this.opened = "yes";
24665
+ // 注意:先设置 positioning = yes,再设置 opened = yes,确保弹窗在位置计算完成前始终隐藏
24525
24666
  this.positioning = "yes";
24667
+ this.opened = "yes";
24526
24668
  this.openChange.emit(true);
24527
24669
  this.ref.markForCheck();
24528
- // 强制更新视图,确保DOM已更新
24670
+ // 强制更新视图,确保DOM已更新,但弹窗仍然隐藏(因为 positioning = yes)
24529
24671
  this.ref.detectChanges();
24530
- // 如果元素已经存在,立即设置位置(不等待 requestAnimationFrame)
24672
+ // 设置位置的函数
24673
+ /** @type {?} */
24674
+ var setPosition_1 = (/**
24675
+ * @return {?}
24676
+ */
24677
+ function () {
24678
+ if (_this.popupElement && _this.popupElement.nativeElement) {
24679
+ /** @type {?} */
24680
+ var popupEl = _this.popupElement.nativeElement;
24681
+ // 立即设置尺寸和位置
24682
+ popupEl.style.width = _this._width + "px";
24683
+ popupEl.style.height = _this._height + "px";
24684
+ popupEl.style.minWidth = _this._width + "px";
24685
+ popupEl.style.maxWidth = _this._width + "px";
24686
+ popupEl.style.minHeight = _this._height + "px";
24687
+ popupEl.style.maxHeight = _this._height + "px";
24688
+ popupEl.style.top = position_1.top;
24689
+ popupEl.style.left = position_1.left;
24690
+ popupEl.style.transform = "translate(" + position_1.translateX + ", " + position_1.translateY + ")";
24691
+ // 强制同步应用样式,确保位置已设置
24692
+ popupEl.offsetHeight;
24693
+ // 位置设置完成后,再显示弹窗(设置 positioning = no)
24694
+ // 使用 requestAnimationFrame 确保样式已应用
24695
+ requestAnimationFrame((/**
24696
+ * @return {?}
24697
+ */
24698
+ function () {
24699
+ _this.positioning = "no";
24700
+ _this.ref.markForCheck();
24701
+ }));
24702
+ }
24703
+ });
24704
+ // 如果元素已经存在,立即设置位置
24531
24705
  if (this.popupElement && this.popupElement.nativeElement) {
24532
- /** @type {?} */
24533
- var popupEl = this.popupElement.nativeElement;
24534
- // 立即设置尺寸和位置
24535
- popupEl.style.width = this._width + "px";
24536
- popupEl.style.height = this._height + "px";
24537
- popupEl.style.minWidth = this._width + "px";
24538
- popupEl.style.maxWidth = this._width + "px";
24539
- popupEl.style.minHeight = this._height + "px";
24540
- popupEl.style.maxHeight = this._height + "px";
24541
- popupEl.style.top = position_1.top;
24542
- popupEl.style.left = position_1.left;
24543
- popupEl.style.transform = "translate(" + position_1.translateX + ", " + position_1.translateY + ")";
24544
- // 强制同步应用样式
24545
- popupEl.offsetHeight;
24546
- // 位置设置完成后,立即显示弹窗
24547
- this.positioning = "no";
24548
- this.ref.markForCheck();
24706
+ setPosition_1();
24549
24707
  }
24550
24708
  else {
24551
- // 如果元素还不存在,等待渲染
24709
+ // 如果元素还不存在,等待渲染后再设置位置
24552
24710
  requestAnimationFrame((/**
24553
24711
  * @return {?}
24554
24712
  */
24555
24713
  function () {
24556
24714
  if (_this.popupElement && _this.popupElement.nativeElement) {
24557
- /** @type {?} */
24558
- var popupEl = _this.popupElement.nativeElement;
24559
- // 立即设置尺寸和位置
24560
- popupEl.style.width = _this._width + "px";
24561
- popupEl.style.height = _this._height + "px";
24562
- popupEl.style.minWidth = _this._width + "px";
24563
- popupEl.style.maxWidth = _this._width + "px";
24564
- popupEl.style.minHeight = _this._height + "px";
24565
- popupEl.style.maxHeight = _this._height + "px";
24566
- popupEl.style.top = position_1.top;
24567
- popupEl.style.left = position_1.left;
24568
- popupEl.style.transform = "translate(" + position_1.translateX + ", " + position_1.translateY + ")";
24569
- // 强制同步应用样式
24570
- popupEl.offsetHeight;
24571
- // 位置设置完成后,立即显示弹窗
24572
- _this.positioning = "no";
24573
- _this.ref.markForCheck();
24715
+ setPosition_1();
24574
24716
  }
24575
24717
  }));
24576
24718
  }
@@ -24734,13 +24876,15 @@
24734
24876
  var targetInfo = this.placementInfo;
24735
24877
  /** @type {?} */
24736
24878
  var finalPlacement = targetInfo.placement;
24879
+ // 始终使用用户指定的 position,autoAdjust 只调整 placement(方向),不改变对齐方式
24737
24880
  /** @type {?} */
24738
24881
  var finalPosition = targetInfo.position;
24739
24882
  if (this.autoAdjust) {
24740
24883
  /** @type {?} */
24741
24884
  var optimal = this.calculateOptimalPlacement(triggerRect, popupRect, viewportWidth, viewportHeight);
24885
+ // autoAdjust 只调整 placement(上下左右),保持用户指定的 position(对齐方式)
24742
24886
  finalPlacement = optimal.placement;
24743
- finalPosition = optimal.position;
24887
+ // finalPosition 保持用户指定的值,不改变
24744
24888
  }
24745
24889
  this.actualPlacement = finalPlacement;
24746
24890
  this.actualPosition = finalPosition;
@@ -24794,13 +24938,15 @@
24794
24938
  var targetInfo = this.placementInfo;
24795
24939
  /** @type {?} */
24796
24940
  var finalPlacement = targetInfo.placement;
24941
+ // 始终使用用户指定的 position,autoAdjust 只调整 placement(方向),不改变对齐方式
24797
24942
  /** @type {?} */
24798
24943
  var finalPosition = targetInfo.position;
24799
24944
  if (this.autoAdjust) {
24800
24945
  /** @type {?} */
24801
24946
  var optimal = this.calculateOptimalPlacement(triggerRect, popupRect, viewportWidth, viewportHeight);
24947
+ // autoAdjust 只调整 placement(上下左右),保持用户指定的 position(对齐方式)
24802
24948
  finalPlacement = optimal.placement;
24803
- finalPosition = optimal.position;
24949
+ // finalPosition 保持用户指定的值,不改变
24804
24950
  }
24805
24951
  this.actualPlacement = finalPlacement;
24806
24952
  this.actualPosition = finalPosition;
@@ -24970,17 +25116,12 @@
24970
25116
  });
24971
25117
  // 如果首选位置有足够空间,优先使用用户指定的position
24972
25118
  if (hasEnoughSpace(preferred)) {
24973
- // 检查用户指定的position是否有足够空间
24974
- if (checkPositionSpace(preferred, preferredPosition)) {
24975
- return {
24976
- placement: preferred,
24977
- position: preferredPosition,
24978
- };
24979
- }
24980
- // 如果指定的position空间不足,自动计算最佳position
25119
+ // 即使指定的position空间不足,也尽量保持用户指定的position
25120
+ // 边界约束逻辑会在 calculatePositionCoordinates 中处理位置调整
25121
+ // 这样可以保持用户期望的对齐方式
24981
25122
  return {
24982
25123
  placement: preferred,
24983
- position: calculatePosition(preferred),
25124
+ position: preferredPosition,
24984
25125
  };
24985
25126
  }
24986
25127
  // 根据首选位置选择备选位置
@@ -25031,7 +25172,9 @@
25031
25172
  };
25032
25173
  };
25033
25174
  // 计算位置坐标(纯计算,不依赖DOM,包含边界约束)
25175
+ // 注意:弹窗使用 position: fixed,所以坐标应该是相对于视口的,不需要加上滚动偏移
25034
25176
  // 计算位置坐标(纯计算,不依赖DOM,包含边界约束)
25177
+ // 注意:弹窗使用 position: fixed,所以坐标应该是相对于视口的,不需要加上滚动偏移
25035
25178
  /**
25036
25179
  * @private
25037
25180
  * @param {?} triggerRect
@@ -25042,6 +25185,7 @@
25042
25185
  */
25043
25186
  SmartPopupComponent.prototype.calculatePositionCoordinates =
25044
25187
  // 计算位置坐标(纯计算,不依赖DOM,包含边界约束)
25188
+ // 注意:弹窗使用 position: fixed,所以坐标应该是相对于视口的,不需要加上滚动偏移
25045
25189
  /**
25046
25190
  * @private
25047
25191
  * @param {?} triggerRect
@@ -25060,10 +25204,6 @@
25060
25204
  /** @type {?} */
25061
25205
  var viewportHeight = window.innerHeight;
25062
25206
  /** @type {?} */
25063
- var scrollX = window.scrollX;
25064
- /** @type {?} */
25065
- var scrollY = window.scrollY;
25066
- /** @type {?} */
25067
25207
  var top = 0;
25068
25208
  /** @type {?} */
25069
25209
  var left = 0;
@@ -25073,109 +25213,268 @@
25073
25213
  var translateY = "0";
25074
25214
  switch (placement) {
25075
25215
  case "top":
25076
- top = triggerRect.top + scrollY - this.offset;
25216
+ // 弹窗在触发元素上方
25217
+ top = triggerRect.top - this.offset;
25077
25218
  translateY = "-100%";
25078
25219
  if (position === "start") {
25079
- left = triggerRect.left + scrollX;
25220
+ // 左对齐
25221
+ left = triggerRect.left;
25222
+ translateX = "0";
25080
25223
  }
25081
25224
  else if (position === "center") {
25082
- left = triggerRect.left + scrollX + triggerWidth / 2;
25225
+ // 居中对齐
25226
+ left = triggerRect.left + triggerWidth / 2;
25083
25227
  translateX = "-50%";
25084
25228
  }
25085
25229
  else {
25086
- left = triggerRect.left + scrollX + triggerWidth;
25230
+ // 右对齐(end)
25231
+ left = triggerRect.right;
25087
25232
  translateX = "-100%";
25088
25233
  }
25089
25234
  // 边界约束:确保弹窗不超出视口
25090
- if (top - popupSize.height < scrollY) {
25091
- top = scrollY + 8; // 距离顶部至少8px
25235
+ /** @type {?} */
25236
+ var popupTop = top - popupSize.height;
25237
+ if (popupTop < 0) {
25238
+ top = popupSize.height + 8; // 距离顶部至少8px
25239
+ translateY = "0"; // 取消向上偏移
25092
25240
  }
25093
- if (left < scrollX) {
25094
- left = scrollX + 8;
25095
- translateX = "0";
25241
+ // 水平边界约束:尽量保持原始对齐方式
25242
+ if (position === "start") {
25243
+ // 左对齐:如果超出右边界,调整到右边界;如果超出左边界,调整到左边界
25244
+ if (left + popupSize.width > viewportWidth) {
25245
+ left = viewportWidth - popupSize.width - 8;
25246
+ }
25247
+ if (left < 8) {
25248
+ left = 8;
25249
+ }
25096
25250
  }
25097
- else if (left + popupSize.width > scrollX + viewportWidth) {
25098
- left = scrollX + viewportWidth - popupSize.width - 8;
25099
- translateX = "0";
25251
+ else if (position === "center") {
25252
+ // 居中对齐:计算实际左边界
25253
+ /** @type {?} */
25254
+ var actualLeft = left - popupSize.width / 2;
25255
+ if (actualLeft < 8) {
25256
+ // 左边界不足,尽量保持居中,但调整到不超出左边界
25257
+ left = 8 + popupSize.width / 2;
25258
+ translateX = "-50%";
25259
+ }
25260
+ else if (actualLeft + popupSize.width > viewportWidth - 8) {
25261
+ // 右边界不足,尽量保持居中,但调整到不超出右边界
25262
+ left = viewportWidth - 8 - popupSize.width / 2;
25263
+ translateX = "-50%";
25264
+ }
25265
+ }
25266
+ else {
25267
+ // 右对齐(end):弹窗右边缘与触发元素右边缘对齐
25268
+ // left 是弹窗的右边缘位置(因为 translateX = "-100%")
25269
+ // 弹窗的左边缘在 left - popupSize.width
25270
+ /** @type {?} */
25271
+ var popupLeftEdge = left - popupSize.width;
25272
+ // 如果弹窗左边缘超出左边界,调整位置但保持右对齐
25273
+ if (popupLeftEdge < 8) {
25274
+ left = 8 + popupSize.width;
25275
+ translateX = "-100%";
25276
+ }
25277
+ // 如果弹窗右边缘超出右边界,调整位置但保持右对齐
25278
+ if (left > viewportWidth - 8) {
25279
+ left = viewportWidth - 8;
25280
+ translateX = "-100%";
25281
+ }
25100
25282
  }
25101
25283
  break;
25102
25284
  case "bottom":
25103
- top = triggerRect.bottom + scrollY + this.offset;
25285
+ // 弹窗在触发元素下方
25286
+ top = triggerRect.bottom + this.offset;
25104
25287
  if (position === "start") {
25105
- left = triggerRect.left + scrollX;
25288
+ // 左对齐
25289
+ left = triggerRect.left;
25290
+ translateX = "0";
25106
25291
  }
25107
25292
  else if (position === "center") {
25108
- left = triggerRect.left + scrollX + triggerWidth / 2;
25293
+ // 居中对齐
25294
+ left = triggerRect.left + triggerWidth / 2;
25109
25295
  translateX = "-50%";
25110
25296
  }
25111
25297
  else {
25112
- left = triggerRect.left + scrollX + triggerWidth;
25298
+ // 右对齐(end)
25299
+ left = triggerRect.right;
25113
25300
  translateX = "-100%";
25114
25301
  }
25115
25302
  // 边界约束:确保弹窗不超出视口
25116
- if (top + popupSize.height > scrollY + viewportHeight) {
25117
- top = scrollY + viewportHeight - popupSize.height - 8; // 距离底部至少8px
25303
+ if (top + popupSize.height > viewportHeight) {
25304
+ top = viewportHeight - popupSize.height - 8; // 距离底部至少8px
25118
25305
  }
25119
- if (left < scrollX) {
25120
- left = scrollX + 8;
25121
- translateX = "0";
25306
+ // 水平边界约束:尽量保持原始对齐方式
25307
+ if (position === "start") {
25308
+ // 左对齐:如果超出右边界,调整到右边界;如果超出左边界,调整到左边界
25309
+ if (left + popupSize.width > viewportWidth) {
25310
+ left = viewportWidth - popupSize.width - 8;
25311
+ }
25312
+ if (left < 8) {
25313
+ left = 8;
25314
+ }
25122
25315
  }
25123
- else if (left + popupSize.width > scrollX + viewportWidth) {
25124
- left = scrollX + viewportWidth - popupSize.width - 8;
25125
- translateX = "0";
25316
+ else if (position === "center") {
25317
+ // 居中对齐:计算实际左边界
25318
+ /** @type {?} */
25319
+ var actualLeft = left - popupSize.width / 2;
25320
+ if (actualLeft < 8) {
25321
+ // 左边界不足,尽量保持居中,但调整到不超出左边界
25322
+ left = 8 + popupSize.width / 2;
25323
+ translateX = "-50%";
25324
+ }
25325
+ else if (actualLeft + popupSize.width > viewportWidth - 8) {
25326
+ // 右边界不足,尽量保持居中,但调整到不超出右边界
25327
+ left = viewportWidth - 8 - popupSize.width / 2;
25328
+ translateX = "-50%";
25329
+ }
25330
+ }
25331
+ else {
25332
+ // 右对齐(end):弹窗右边缘与触发元素右边缘对齐
25333
+ // left 是弹窗的右边缘位置(因为 translateX = "-100%")
25334
+ // 弹窗的左边缘在 left - popupSize.width
25335
+ /** @type {?} */
25336
+ var popupLeftEdge = left - popupSize.width;
25337
+ // 优先保持与触发元素右对齐,只在必要时调整
25338
+ // 如果弹窗右边缘超出右边界,调整位置但保持右对齐
25339
+ if (left > viewportWidth - 8) {
25340
+ left = viewportWidth - 8;
25341
+ translateX = "-100%";
25342
+ }
25343
+ // 如果弹窗左边缘超出左边界,且弹窗可以完全显示在视口内,才调整位置
25344
+ // 这样可以确保在可能的情况下,弹窗始终与触发元素右对齐
25345
+ if (popupLeftEdge < 8 && popupSize.width < viewportWidth - 16) {
25346
+ // 只有当弹窗可以完全显示在视口内时,才调整位置
25347
+ // 否则保持与触发元素右对齐,即使部分超出左边界
25348
+ left = 8 + popupSize.width;
25349
+ translateX = "-100%";
25350
+ }
25126
25351
  }
25127
25352
  break;
25128
25353
  case "left":
25129
- left = triggerRect.left + scrollX - this.offset;
25354
+ // 弹窗在触发元素左侧
25355
+ left = triggerRect.left - this.offset;
25130
25356
  translateX = "-100%";
25131
25357
  if (position === "start") {
25132
- top = triggerRect.top + scrollY;
25358
+ // 上对齐
25359
+ top = triggerRect.top;
25360
+ translateY = "0";
25133
25361
  }
25134
25362
  else if (position === "center") {
25135
- top = triggerRect.top + scrollY + triggerHeight / 2;
25363
+ // 居中对齐
25364
+ top = triggerRect.top + triggerHeight / 2;
25136
25365
  translateY = "-50%";
25137
25366
  }
25138
25367
  else {
25139
- top = triggerRect.top + scrollY + triggerHeight;
25368
+ // 下对齐(end)
25369
+ top = triggerRect.bottom;
25140
25370
  translateY = "-100%";
25141
25371
  }
25142
25372
  // 边界约束:确保弹窗不超出视口
25143
- if (left - popupSize.width < scrollX) {
25144
- left = scrollX + 8; // 距离左侧至少8px
25373
+ /** @type {?} */
25374
+ var popupLeftSide = left - popupSize.width;
25375
+ if (popupLeftSide < 0) {
25376
+ left = 8; // 距离左侧至少8px
25377
+ translateX = "0"; // 取消向左偏移
25145
25378
  }
25146
- if (top < scrollY) {
25147
- top = scrollY + 8;
25148
- translateY = "0";
25379
+ // 垂直边界约束:尽量保持原始对齐方式
25380
+ if (position === "start") {
25381
+ // 上对齐:如果超出下边界,调整到下边界;如果超出上边界,调整到上边界
25382
+ if (top + popupSize.height > viewportHeight) {
25383
+ top = viewportHeight - popupSize.height - 8;
25384
+ }
25385
+ if (top < 8) {
25386
+ top = 8;
25387
+ }
25149
25388
  }
25150
- else if (top + popupSize.height > scrollY + viewportHeight) {
25151
- top = scrollY + viewportHeight - popupSize.height - 8;
25152
- translateY = "0";
25389
+ else if (position === "center") {
25390
+ // 居中对齐:计算实际上边界
25391
+ /** @type {?} */
25392
+ var actualTop = top - popupSize.height / 2;
25393
+ if (actualTop < 8) {
25394
+ // 上边界不足,尽量保持居中,但调整到不超出上边界
25395
+ top = 8 + popupSize.height / 2;
25396
+ translateY = "-50%";
25397
+ }
25398
+ else if (actualTop + popupSize.height > viewportHeight - 8) {
25399
+ // 下边界不足,尽量保持居中,但调整到不超出下边界
25400
+ top = viewportHeight - 8 - popupSize.height / 2;
25401
+ translateY = "-50%";
25402
+ }
25403
+ }
25404
+ else {
25405
+ // 下对齐(end):如果超出上边界,调整到上边界;如果超出下边界,调整到下边界
25406
+ /** @type {?} */
25407
+ var actualTop = top - popupSize.height;
25408
+ if (actualTop < 8) {
25409
+ top = 8 + popupSize.height;
25410
+ translateY = "-100%";
25411
+ }
25412
+ if (top > viewportHeight - 8) {
25413
+ top = viewportHeight - 8;
25414
+ translateY = "-100%";
25415
+ }
25153
25416
  }
25154
25417
  break;
25155
25418
  case "right":
25156
- left = triggerRect.right + scrollX + this.offset;
25419
+ // 弹窗在触发元素右侧
25420
+ left = triggerRect.right + this.offset;
25421
+ translateX = "0";
25157
25422
  if (position === "start") {
25158
- top = triggerRect.top + scrollY;
25423
+ // 上对齐
25424
+ top = triggerRect.top;
25425
+ translateY = "0";
25159
25426
  }
25160
25427
  else if (position === "center") {
25161
- top = triggerRect.top + scrollY + triggerHeight / 2;
25428
+ // 居中对齐
25429
+ top = triggerRect.top + triggerHeight / 2;
25162
25430
  translateY = "-50%";
25163
25431
  }
25164
25432
  else {
25165
- top = triggerRect.top + scrollY + triggerHeight;
25433
+ // 下对齐(end)
25434
+ top = triggerRect.bottom;
25166
25435
  translateY = "-100%";
25167
25436
  }
25168
25437
  // 边界约束:确保弹窗不超出视口
25169
- if (left + popupSize.width > scrollX + viewportWidth) {
25170
- left = scrollX + viewportWidth - popupSize.width - 8; // 距离右侧至少8px
25438
+ if (left + popupSize.width > viewportWidth) {
25439
+ left = viewportWidth - popupSize.width - 8; // 距离右侧至少8px
25171
25440
  }
25172
- if (top < scrollY) {
25173
- top = scrollY + 8;
25174
- translateY = "0";
25441
+ // 垂直边界约束:尽量保持原始对齐方式
25442
+ if (position === "start") {
25443
+ // 上对齐:如果超出下边界,调整到下边界;如果超出上边界,调整到上边界
25444
+ if (top + popupSize.height > viewportHeight) {
25445
+ top = viewportHeight - popupSize.height - 8;
25446
+ }
25447
+ if (top < 8) {
25448
+ top = 8;
25449
+ }
25175
25450
  }
25176
- else if (top + popupSize.height > scrollY + viewportHeight) {
25177
- top = scrollY + viewportHeight - popupSize.height - 8;
25178
- translateY = "0";
25451
+ else if (position === "center") {
25452
+ // 居中对齐:计算实际上边界
25453
+ /** @type {?} */
25454
+ var actualTop = top - popupSize.height / 2;
25455
+ if (actualTop < 8) {
25456
+ // 上边界不足,尽量保持居中,但调整到不超出上边界
25457
+ top = 8 + popupSize.height / 2;
25458
+ translateY = "-50%";
25459
+ }
25460
+ else if (actualTop + popupSize.height > viewportHeight - 8) {
25461
+ // 下边界不足,尽量保持居中,但调整到不超出下边界
25462
+ top = viewportHeight - 8 - popupSize.height / 2;
25463
+ translateY = "-50%";
25464
+ }
25465
+ }
25466
+ else {
25467
+ // 下对齐(end):如果超出上边界,调整到上边界;如果超出下边界,调整到下边界
25468
+ /** @type {?} */
25469
+ var actualTop = top - popupSize.height;
25470
+ if (actualTop < 8) {
25471
+ top = 8 + popupSize.height;
25472
+ translateY = "-100%";
25473
+ }
25474
+ if (top > viewportHeight - 8) {
25475
+ top = viewportHeight - 8;
25476
+ translateY = "-100%";
25477
+ }
25179
25478
  }
25180
25479
  break;
25181
25480
  }
@@ -25240,7 +25539,7 @@
25240
25539
  { type: core.Component, args: [{
25241
25540
  selector: "rs-smart-popup",
25242
25541
  template: "<!-- \u89E6\u53D1\u5143\u7D20\u63D2\u69FD -->\r\n<ng-container #trigger>\r\n <ng-content select=\"[trigger]\"></ng-content>\r\n</ng-container>\r\n\r\n<!-- \u5F39\u7A97\u5185\u5BB9 -->\r\n<div\r\n #popup\r\n class=\"rs-smart-popup-content\"\r\n [attr.data-opened]=\"opened\"\r\n [attr.data-positioning]=\"positioning\"\r\n (wheel)=\"onPopupWheel($event)\"\r\n (scroll)=\"onPopupScroll($event)\"\r\n>\r\n <div *ngIf=\"loading\" class=\"rs-smart-popup-loading\">\r\n <div class=\"loading-spinner\"></div>\r\n </div>\r\n <div *ngIf=\"!loading\" class=\"rs-smart-popup-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n\r\n",
25243
- styles: [".rs-smart-popup-trigger{display:inline-block;cursor:pointer}::ng-deep #rs-smart-popup-fixed-container{width:0;height:0;z-index:100000;pointer-events:none}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content{pointer-events:auto;position:fixed;z-index:100001;padding:8px;border-radius:8px;background:#fff;box-shadow:0 0 8px 0 rgba(0,0,0,.25);min-width:200px;max-width:400px;max-height:500px;overflow:auto}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=no]{display:none}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=yes]{display:block}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=yes][data-positioning=yes]{display:none!important}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=yes][data-positioning=no]{display:block;visibility:visible;opacity:1;pointer-events:auto;-webkit-animation:.2s ease-out popup-fade-in;animation:.2s ease-out popup-fade-in}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;min-height:100px}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-loading .loading-spinner{width:24px;height:24px;border:3px solid #f3f3f3;border-top:3px solid #3498db;border-radius:50%;-webkit-animation:1s linear infinite spin;animation:1s linear infinite spin;margin-bottom:12px}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-loading .loading-text{color:#666;font-size:14px}@-webkit-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-body{width:100%}@-webkit-keyframes popup-fade-in{from{opacity:0;transform:translate(var(--translate-x,0),var(--translate-y,0)) scale(.95)}to{opacity:1;transform:translate(var(--translate-x,0),var(--translate-y,0)) scale(1)}}@keyframes popup-fade-in{from{opacity:0;transform:translate(var(--translate-x,0),var(--translate-y,0)) scale(.95)}to{opacity:1;transform:translate(var(--translate-x,0),var(--translate-y,0)) scale(1)}}"]
25542
+ styles: [".rs-smart-popup-trigger{display:inline-block;cursor:pointer}::ng-deep #rs-smart-popup-fixed-container{width:0;height:0;z-index:100000;pointer-events:none}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content{pointer-events:auto;position:fixed;z-index:100001;padding:8px;border-radius:8px;background:#fff;box-shadow:0 0 8px 0 rgba(0,0,0,.25);min-width:200px;max-width:400px;max-height:500px;overflow:auto}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=no]{display:none}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=yes]{display:block}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=yes][data-positioning=yes]{display:none!important}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content[data-opened=yes][data-positioning=no]{display:block;visibility:visible;opacity:1;pointer-events:auto}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;min-height:100px}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-loading .loading-spinner{width:24px;height:24px;border:3px solid #f3f3f3;border-top:3px solid #3498db;border-radius:50%;-webkit-animation:1s linear infinite spin;animation:1s linear infinite spin;margin-bottom:12px}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-loading .loading-text{color:#666;font-size:14px}@-webkit-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}::ng-deep #rs-smart-popup-fixed-container .rs-smart-popup-content .rs-smart-popup-body{width:100%}"]
25244
25543
  }] }
25245
25544
  ];
25246
25545
  /** @nocollapse */