@v-c/trigger 0.0.11 → 0.0.13

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.
@@ -14,6 +14,7 @@ const defaults = {
14
14
  };
15
15
  const Popup = /* @__PURE__ */ vue.defineComponent((props, {
16
16
  attrs,
17
+ slots,
17
18
  expose
18
19
  }) => {
19
20
  const popupContent = vue.computed(() => typeof props.popup === "function" ? props.popup() : props.popup);
@@ -158,9 +159,9 @@ const Popup = /* @__PURE__ */ vue.defineComponent((props, {
158
159
  "onClick": onClick
159
160
  }, {
160
161
  onPointerdownCapture: onPointerDownCapture
161
- }), [arrow && vue.createVNode(Arrow.Arrow, {
162
+ }), [!!arrow && vue.createVNode(Arrow.Arrow, {
162
163
  "prefixCls": prefixCls,
163
- "arrow": arrow,
164
+ "arrow": arrow === true ? {} : arrow,
164
165
  "arrowPos": arrowPos,
165
166
  "align": align2
166
167
  }, null), vue.createVNode(PopupContent.default, {
@@ -169,7 +170,7 @@ const Popup = /* @__PURE__ */ vue.defineComponent((props, {
169
170
  default: () => [popupContent.value]
170
171
  })]), [[vue.vShow, open.value]])]
171
172
  })]
172
- })]
173
+ }), slots?.default?.()]
173
174
  });
174
175
  };
175
176
  }, {
@@ -241,7 +242,7 @@ const Popup = /* @__PURE__ */ vue.defineComponent((props, {
241
242
  default: void 0
242
243
  },
243
244
  arrow: {
244
- type: Object,
245
+ type: [Object, Boolean],
245
246
  required: false,
246
247
  default: void 0
247
248
  },
@@ -24,7 +24,7 @@ export interface PopupProps {
24
24
  mask?: boolean;
25
25
  onVisibleChanged: (visible: boolean) => void;
26
26
  align?: AlignType;
27
- arrow?: ArrowTypeOuter;
27
+ arrow?: ArrowTypeOuter | boolean;
28
28
  arrowPos: ArrowPos;
29
29
  open: boolean;
30
30
  /** Tell Portal that should keep in screen. e.g. should wait all motion end */
@@ -12,6 +12,7 @@ const defaults = {
12
12
  };
13
13
  const Popup = /* @__PURE__ */ defineComponent((props, {
14
14
  attrs,
15
+ slots,
15
16
  expose
16
17
  }) => {
17
18
  const popupContent = computed(() => typeof props.popup === "function" ? props.popup() : props.popup);
@@ -156,9 +157,9 @@ const Popup = /* @__PURE__ */ defineComponent((props, {
156
157
  "onClick": onClick
157
158
  }, {
158
159
  onPointerdownCapture: onPointerDownCapture
159
- }), [arrow && createVNode(Arrow, {
160
+ }), [!!arrow && createVNode(Arrow, {
160
161
  "prefixCls": prefixCls,
161
- "arrow": arrow,
162
+ "arrow": arrow === true ? {} : arrow,
162
163
  "arrowPos": arrowPos,
163
164
  "align": align2
164
165
  }, null), createVNode(PopupContent, {
@@ -167,7 +168,7 @@ const Popup = /* @__PURE__ */ defineComponent((props, {
167
168
  default: () => [popupContent.value]
168
169
  })]), [[vShow, open.value]])]
169
170
  })]
170
- })]
171
+ }), slots?.default?.()]
171
172
  });
172
173
  };
173
174
  }, {
@@ -239,7 +240,7 @@ const Popup = /* @__PURE__ */ defineComponent((props, {
239
240
  default: void 0
240
241
  },
241
242
  arrow: {
242
- type: Object,
243
+ type: [Object, Boolean],
243
244
  required: false,
244
245
  default: void 0
245
246
  },
@@ -23,12 +23,11 @@ const UniqueContainer = /* @__PURE__ */ vue.defineComponent((props) => {
23
23
  cachedOffsetStyleRef.value = offsetStyle.value;
24
24
  }
25
25
  });
26
- vue.watch(open, (nextVisible) => {
26
+ vue.watch(open, async (nextVisible) => {
27
+ await vue.nextTick();
27
28
  if (nextVisible) {
28
29
  motionVisible.value = true;
29
30
  }
30
- }, {
31
- immediate: true
32
31
  });
33
32
  return () => {
34
33
  const {
@@ -47,18 +46,10 @@ const UniqueContainer = /* @__PURE__ */ vue.defineComponent((props) => {
47
46
  const baseTransitionProps = transition.getTransitionProps(motion?.name, motion);
48
47
  const mergedTransitionProps = {
49
48
  ...baseTransitionProps,
50
- onBeforeAppear: (element) => {
51
- motionVisible.value = true;
52
- baseTransitionProps.onBeforeAppear?.(element);
53
- },
54
49
  onBeforeEnter: (element) => {
55
50
  motionVisible.value = true;
56
51
  baseTransitionProps.onBeforeEnter?.(element);
57
52
  },
58
- onAfterAppear: (element) => {
59
- motionVisible.value = true;
60
- baseTransitionProps.onAfterAppear?.(element);
61
- },
62
53
  onAfterEnter: (element) => {
63
54
  motionVisible.value = true;
64
55
  baseTransitionProps.onAfterEnter?.(element);
@@ -72,8 +63,8 @@ const UniqueContainer = /* @__PURE__ */ vue.defineComponent((props) => {
72
63
  return vue.createVNode(vue.Transition, mergedTransitionProps, {
73
64
  default: () => [vue.withDirectives(vue.createVNode("div", {
74
65
  "class": [containerCls, uniqueContainerClassName, {
75
- [`${containerCls}-visible`]: motionVisible.value,
76
- [`${containerCls}-hidden`]: !motionVisible.value
66
+ [`${containerCls}-visible`]: motionVisible.value
67
+ // [`${containerCls}-hidden`]: !motionVisible.value,
77
68
  }],
78
69
  "style": [{
79
70
  "--arrow-x": `${arrowPos?.x || 0}px`,
@@ -1,4 +1,4 @@
1
- import { defineComponent, shallowRef, watchEffect, watch, createVNode, Transition, withDirectives, vShow } from "vue";
1
+ import { defineComponent, shallowRef, watchEffect, watch, nextTick, createVNode, Transition, withDirectives, vShow } from "vue";
2
2
  import { toPropsRefs } from "@v-c/util/dist/props-util";
3
3
  import { getTransitionProps } from "@v-c/util/dist/utils/transition";
4
4
  import useOffsetStyle from "../hooks/useOffsetStyle.js";
@@ -21,12 +21,11 @@ const UniqueContainer = /* @__PURE__ */ defineComponent((props) => {
21
21
  cachedOffsetStyleRef.value = offsetStyle.value;
22
22
  }
23
23
  });
24
- watch(open, (nextVisible) => {
24
+ watch(open, async (nextVisible) => {
25
+ await nextTick();
25
26
  if (nextVisible) {
26
27
  motionVisible.value = true;
27
28
  }
28
- }, {
29
- immediate: true
30
29
  });
31
30
  return () => {
32
31
  const {
@@ -45,18 +44,10 @@ const UniqueContainer = /* @__PURE__ */ defineComponent((props) => {
45
44
  const baseTransitionProps = getTransitionProps(motion?.name, motion);
46
45
  const mergedTransitionProps = {
47
46
  ...baseTransitionProps,
48
- onBeforeAppear: (element) => {
49
- motionVisible.value = true;
50
- baseTransitionProps.onBeforeAppear?.(element);
51
- },
52
47
  onBeforeEnter: (element) => {
53
48
  motionVisible.value = true;
54
49
  baseTransitionProps.onBeforeEnter?.(element);
55
50
  },
56
- onAfterAppear: (element) => {
57
- motionVisible.value = true;
58
- baseTransitionProps.onAfterAppear?.(element);
59
- },
60
51
  onAfterEnter: (element) => {
61
52
  motionVisible.value = true;
62
53
  baseTransitionProps.onAfterEnter?.(element);
@@ -70,8 +61,8 @@ const UniqueContainer = /* @__PURE__ */ defineComponent((props) => {
70
61
  return createVNode(Transition, mergedTransitionProps, {
71
62
  default: () => [withDirectives(createVNode("div", {
72
63
  "class": [containerCls, uniqueContainerClassName, {
73
- [`${containerCls}-visible`]: motionVisible.value,
74
- [`${containerCls}-hidden`]: !motionVisible.value
64
+ [`${containerCls}-visible`]: motionVisible.value
65
+ // [`${containerCls}-hidden`]: !motionVisible.value,
75
66
  }],
76
67
  "style": [{
77
68
  "--arrow-x": `${arrowPos?.x || 0}px`,
@@ -52,6 +52,9 @@ const UniqueProvider = /* @__PURE__ */ vue.defineComponent((props, {
52
52
  };
53
53
  const setPopupRef = (node) => {
54
54
  const element = resolveToElement(node);
55
+ if (!element) {
56
+ return;
57
+ }
55
58
  externalPopupRef.value = element;
56
59
  if (popupEle.value !== element) {
57
60
  popupEle.value = element;
@@ -84,9 +87,9 @@ const UniqueProvider = /* @__PURE__ */ vue.defineComponent((props, {
84
87
  offsetB,
85
88
  arrowX,
86
89
  arrowY,
87
- // scaleX - not used in UniqueProvider
88
90
  ,
89
91
  ,
92
+ // scaleX - not used in UniqueProvider
90
93
  // scaleY - not used in UniqueProvider
91
94
  alignInfo,
92
95
  onAlign
@@ -50,6 +50,9 @@ const UniqueProvider = /* @__PURE__ */ defineComponent((props, {
50
50
  };
51
51
  const setPopupRef = (node) => {
52
52
  const element = resolveToElement(node);
53
+ if (!element) {
54
+ return;
55
+ }
53
56
  externalPopupRef.value = element;
54
57
  if (popupEle.value !== element) {
55
58
  popupEle.value = element;
@@ -82,9 +85,9 @@ const UniqueProvider = /* @__PURE__ */ defineComponent((props, {
82
85
  offsetB,
83
86
  arrowX,
84
87
  arrowY,
85
- // scaleX - not used in UniqueProvider
86
88
  ,
87
89
  ,
90
+ // scaleX - not used in UniqueProvider
88
91
  // scaleY - not used in UniqueProvider
89
92
  alignInfo,
90
93
  onAlign
@@ -58,6 +58,75 @@ function reversePoints(points, index) {
58
58
  return point;
59
59
  }).join("");
60
60
  }
61
+ function parseOriginValue(value, size, axis) {
62
+ const fallback = size / 2;
63
+ if (!value) {
64
+ return fallback;
65
+ }
66
+ const val = value.trim();
67
+ if (!val) {
68
+ return fallback;
69
+ }
70
+ if (val.endsWith("%")) {
71
+ return size * (parseFloat(val) / 100);
72
+ }
73
+ if (val.endsWith("px")) {
74
+ return parseFloat(val);
75
+ }
76
+ if (val === "center") {
77
+ return fallback;
78
+ }
79
+ if (axis === "x") {
80
+ if (val === "left") {
81
+ return 0;
82
+ }
83
+ if (val === "right") {
84
+ return size;
85
+ }
86
+ } else if (axis === "y") {
87
+ if (val === "top") {
88
+ return 0;
89
+ }
90
+ if (val === "bottom") {
91
+ return size;
92
+ }
93
+ }
94
+ const num = parseFloat(val);
95
+ return Number.isNaN(num) ? fallback : num;
96
+ }
97
+ function getTransformOriginPoint(origin, width, height) {
98
+ const [originX = "50%", originY = "50%"] = origin?.split(/\s+/).filter(Boolean) ?? [];
99
+ return [
100
+ parseOriginValue(originX, width, "x"),
101
+ parseOriginValue(originY, height, "y")
102
+ ];
103
+ }
104
+ function normalizeRect(rect, scaleX, scaleY, originX, originY) {
105
+ const rawX = rect.x ?? rect.left;
106
+ const rawY = rect.y ?? rect.top;
107
+ const width = rect.width / scaleX;
108
+ const height = rect.height / scaleY;
109
+ const x = rawX - (1 - scaleX) * originX;
110
+ const y = rawY - (1 - scaleY) * originY;
111
+ const right = x + width;
112
+ const bottom = y + height;
113
+ return {
114
+ x,
115
+ y,
116
+ width,
117
+ height,
118
+ left: x,
119
+ top: y,
120
+ right,
121
+ bottom
122
+ };
123
+ }
124
+ function shouldSwitchPlacement(isOverflow, isVisibleFirst, newVisibleArea, originVisibleArea, newRecommendArea, originRecommendArea) {
125
+ if (isOverflow) {
126
+ return newVisibleArea > originVisibleArea || newVisibleArea === originVisibleArea && (!isVisibleFirst || newRecommendArea >= originRecommendArea);
127
+ }
128
+ return newVisibleArea > originVisibleArea || isVisibleFirst && newVisibleArea === originVisibleArea && newRecommendArea > originRecommendArea;
129
+ }
61
130
  function useAlign(open, popupEle, target, placement, builtinPlacements, popupAlign, onPopupAlign, mobile) {
62
131
  const offsetInfo = vue.reactive({
63
132
  ready: false,
@@ -103,7 +172,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
103
172
  const popupElement = popupEle.value;
104
173
  const doc = popupElement.ownerDocument;
105
174
  const win = util.getWin(popupElement);
106
- const { position: popupPosition } = win.getComputedStyle(popupElement);
175
+ const popupComputedStyle = win.getComputedStyle(popupElement);
176
+ const { position: popupPosition } = popupComputedStyle;
107
177
  const originLeft = popupElement.style.left;
108
178
  const originTop = popupElement.style.top;
109
179
  const originRight = popupElement.style.right;
@@ -144,10 +214,7 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
144
214
  height: rect.height
145
215
  };
146
216
  }
147
- const popupRect = popupElement.getBoundingClientRect();
148
- const { height, width } = win.getComputedStyle(popupElement);
149
- popupRect.x = popupRect.x ?? popupRect.left;
150
- popupRect.y = popupRect.y ?? popupRect.top;
217
+ const rawPopupRect = popupElement.getBoundingClientRect();
151
218
  const {
152
219
  clientWidth,
153
220
  clientHeight,
@@ -156,8 +223,6 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
156
223
  scrollTop,
157
224
  scrollLeft
158
225
  } = doc.documentElement;
159
- const popupHeight = popupRect.height;
160
- const popupWidth = popupRect.width;
161
226
  const targetHeight = targetRect.height;
162
227
  const targetWidth = targetRect.width;
163
228
  const visibleRegion = {
@@ -187,22 +252,43 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
187
252
  popupElement.style.top = "auto";
188
253
  popupElement.style.right = "0";
189
254
  popupElement.style.bottom = "0";
190
- const popupMirrorRect = popupElement.getBoundingClientRect();
255
+ const rawPopupMirrorRect = popupElement.getBoundingClientRect();
191
256
  popupElement.style.left = originLeft;
192
257
  popupElement.style.top = originTop;
193
258
  popupElement.style.right = originRight;
194
259
  popupElement.style.bottom = originBottom;
195
260
  popupElement.style.overflow = originOverflow;
196
261
  popupElement.parentElement?.removeChild(placeholderElement);
262
+ const widthValue = parseFloat(popupComputedStyle.width);
263
+ const heightValue = parseFloat(popupComputedStyle.height);
264
+ const baseWidth = !Number.isNaN(widthValue) && widthValue > 0 ? widthValue : popupElement.offsetWidth;
265
+ const baseHeight = !Number.isNaN(heightValue) && heightValue > 0 ? heightValue : popupElement.offsetHeight;
266
+ const safeBaseWidth = baseWidth || rawPopupRect.width || 1;
267
+ const safeBaseHeight = baseHeight || rawPopupRect.height || 1;
197
268
  const scaleX2 = util.toNum(
198
- Math.round(popupWidth / parseFloat(width) * 1e3) / 1e3
269
+ Math.round(rawPopupRect.width / safeBaseWidth * 1e3) / 1e3
199
270
  );
200
271
  const scaleY2 = util.toNum(
201
- Math.round(popupHeight / parseFloat(height) * 1e3) / 1e3
272
+ Math.round(rawPopupRect.height / safeBaseHeight * 1e3) / 1e3
202
273
  );
203
274
  if (scaleX2 === 0 || scaleY2 === 0 || findDOMNode.isDOM(target) && !isVisible(target)) {
204
275
  return;
205
276
  }
277
+ const [originX, originY] = getTransformOriginPoint(
278
+ popupComputedStyle.transformOrigin,
279
+ safeBaseWidth,
280
+ safeBaseHeight
281
+ );
282
+ const popupRect = normalizeRect(rawPopupRect, scaleX2, scaleY2, originX, originY);
283
+ const popupMirrorRect = normalizeRect(
284
+ rawPopupMirrorRect,
285
+ scaleX2,
286
+ scaleY2,
287
+ originX,
288
+ originY
289
+ );
290
+ const popupHeight = popupRect.height;
291
+ const popupWidth = popupRect.width;
206
292
  const { offset, targetOffset } = placementInfo;
207
293
  let [popupOffsetX, popupOffsetY] = getNumberOffset(popupRect, offset);
208
294
  const [targetOffsetX, targetOffsetY] = getNumberOffset(
@@ -249,7 +335,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
249
335
  syncNextPopupPosition();
250
336
  const needAdjustY = supportAdjust(adjustY);
251
337
  const sameTB = popupPoints[0] === targetPoints[0];
252
- if (needAdjustY && popupPoints[0] === "t" && (nextPopupBottom > adjustCheckVisibleArea.bottom || prevFlipRef.value.bt)) {
338
+ const overflowBottom = nextPopupBottom > adjustCheckVisibleArea.bottom;
339
+ if (needAdjustY && popupPoints[0] === "t" && (overflowBottom || prevFlipRef.value.bt)) {
253
340
  let tmpNextOffsetY = nextOffsetY;
254
341
  if (sameTB) {
255
342
  tmpNextOffsetY -= popupHeight - targetHeight;
@@ -265,10 +352,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
265
352
  tmpNextOffsetY,
266
353
  visibleRegionArea
267
354
  );
268
- if (
269
- // Of course use larger one
270
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
271
- ) {
355
+ const shouldFlip = shouldSwitchPlacement(
356
+ overflowBottom,
357
+ isVisibleFirst,
358
+ newVisibleArea,
359
+ originIntersectionVisibleArea,
360
+ newVisibleRecommendArea,
361
+ originIntersectionRecommendArea
362
+ );
363
+ if (shouldFlip) {
272
364
  prevFlipRef.value.bt = true;
273
365
  nextOffsetY = tmpNextOffsetY;
274
366
  popupOffsetY = -popupOffsetY;
@@ -280,7 +372,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
280
372
  prevFlipRef.value.bt = false;
281
373
  }
282
374
  }
283
- if (needAdjustY && popupPoints[0] === "b" && (nextPopupY < adjustCheckVisibleArea.top || prevFlipRef.value.tb)) {
375
+ const overflowTop = nextPopupY < adjustCheckVisibleArea.top;
376
+ if (needAdjustY && popupPoints[0] === "b" && (overflowTop || prevFlipRef.value.tb)) {
284
377
  let tmpNextOffsetY = nextOffsetY;
285
378
  if (sameTB) {
286
379
  tmpNextOffsetY += popupHeight - targetHeight;
@@ -296,10 +389,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
296
389
  tmpNextOffsetY,
297
390
  visibleRegionArea
298
391
  );
299
- if (
300
- // Of course use larger one
301
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
302
- ) {
392
+ const shouldFlip = shouldSwitchPlacement(
393
+ overflowTop,
394
+ isVisibleFirst,
395
+ newVisibleArea,
396
+ originIntersectionVisibleArea,
397
+ newVisibleRecommendArea,
398
+ originIntersectionRecommendArea
399
+ );
400
+ if (shouldFlip) {
303
401
  prevFlipRef.value.tb = true;
304
402
  nextOffsetY = tmpNextOffsetY;
305
403
  popupOffsetY = -popupOffsetY;
@@ -313,7 +411,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
313
411
  }
314
412
  const needAdjustX = supportAdjust(adjustX);
315
413
  const sameLR = popupPoints[1] === targetPoints[1];
316
- if (needAdjustX && popupPoints[1] === "l" && (nextPopupRight > adjustCheckVisibleArea.right || prevFlipRef.value.rl)) {
414
+ const overflowRight = nextPopupRight > adjustCheckVisibleArea.right;
415
+ if (needAdjustX && popupPoints[1] === "l" && (overflowRight || prevFlipRef.value.rl)) {
317
416
  let tmpNextOffsetX = nextOffsetX;
318
417
  if (sameLR) {
319
418
  tmpNextOffsetX -= popupWidth - targetWidth;
@@ -329,10 +428,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
329
428
  nextOffsetY,
330
429
  visibleRegionArea
331
430
  );
332
- if (
333
- // Of course use larger one
334
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
335
- ) {
431
+ const shouldFlip = shouldSwitchPlacement(
432
+ overflowRight,
433
+ isVisibleFirst,
434
+ newVisibleArea,
435
+ originIntersectionVisibleArea,
436
+ newVisibleRecommendArea,
437
+ originIntersectionRecommendArea
438
+ );
439
+ if (shouldFlip) {
336
440
  prevFlipRef.value.rl = true;
337
441
  nextOffsetX = tmpNextOffsetX;
338
442
  popupOffsetX = -popupOffsetX;
@@ -344,7 +448,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
344
448
  prevFlipRef.value.rl = false;
345
449
  }
346
450
  }
347
- if (needAdjustX && popupPoints[1] === "r" && (nextPopupX < adjustCheckVisibleArea.left || prevFlipRef.value.lr)) {
451
+ const overflowLeft = nextPopupX < adjustCheckVisibleArea.left;
452
+ if (needAdjustX && popupPoints[1] === "r" && (overflowLeft || prevFlipRef.value.lr)) {
348
453
  let tmpNextOffsetX = nextOffsetX;
349
454
  if (sameLR) {
350
455
  tmpNextOffsetX += popupWidth - targetWidth;
@@ -360,10 +465,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
360
465
  nextOffsetY,
361
466
  visibleRegionArea
362
467
  );
363
- if (
364
- // Of course use larger one
365
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
366
- ) {
468
+ const shouldFlip = shouldSwitchPlacement(
469
+ overflowLeft,
470
+ isVisibleFirst,
471
+ newVisibleArea,
472
+ originIntersectionVisibleArea,
473
+ newVisibleRecommendArea,
474
+ originIntersectionRecommendArea
475
+ );
476
+ if (shouldFlip) {
367
477
  prevFlipRef.value.lr = true;
368
478
  nextOffsetX = tmpNextOffsetX;
369
479
  popupOffsetX = -popupOffsetX;
@@ -435,12 +545,12 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
435
545
  }
436
546
  const nextOffsetInfo = {
437
547
  ready: true,
438
- offsetX: nextOffsetX / scaleX2,
439
- offsetY: nextOffsetY / scaleY2,
440
- offsetR: offsetX4Right / scaleX2,
441
- offsetB: offsetY4Bottom / scaleY2,
442
- arrowX: nextArrowX / scaleX2,
443
- arrowY: nextArrowY / scaleY2,
548
+ offsetX: nextOffsetX,
549
+ offsetY: nextOffsetY,
550
+ offsetR: offsetX4Right,
551
+ offsetB: offsetY4Bottom,
552
+ arrowX: nextArrowX,
553
+ arrowY: nextArrowY,
444
554
  scaleX: scaleX2,
445
555
  scaleY: scaleY2,
446
556
  align: nextAlignInfo
@@ -470,17 +580,21 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
470
580
  const resetReady = () => {
471
581
  offsetInfo.ready = false;
472
582
  };
473
- vue.watch(placement, async () => {
474
- await vue.nextTick();
583
+ vue.watch(placement, () => {
475
584
  resetReady();
476
585
  });
477
- vue.watchEffect(async () => {
478
- if (!open.value) {
479
- resetFlipCache();
480
- await vue.nextTick();
481
- resetReady();
586
+ vue.watch(
587
+ open,
588
+ () => {
589
+ if (!open.value) {
590
+ resetFlipCache();
591
+ resetReady();
592
+ }
593
+ },
594
+ {
595
+ immediate: true
482
596
  }
483
- });
597
+ );
484
598
  const { ready, offsetX, offsetR, offsetY, offsetB, align, arrowY, arrowX, scaleY, scaleX } = vue.toRefs(offsetInfo);
485
599
  return [
486
600
  ready,
@@ -1,7 +1,7 @@
1
1
  import { isDOM } from "@v-c/util/dist/Dom/findDOMNode";
2
2
  import isVisible from "@v-c/util/dist/Dom/isVisible";
3
3
  import { rafDebounce } from "@v-c/util/dist/raf";
4
- import { reactive, shallowRef, computed, ref, watch, nextTick, watchEffect, toRefs } from "vue";
4
+ import { reactive, shallowRef, computed, ref, watch, nextTick, toRefs } from "vue";
5
5
  import { collectScroller, getWin, getVisibleArea, toNum } from "../util.js";
6
6
  function getUnitOffset(size, offset = 0) {
7
7
  const offsetStr = `${offset}`;
@@ -56,6 +56,75 @@ function reversePoints(points, index) {
56
56
  return point;
57
57
  }).join("");
58
58
  }
59
+ function parseOriginValue(value, size, axis) {
60
+ const fallback = size / 2;
61
+ if (!value) {
62
+ return fallback;
63
+ }
64
+ const val = value.trim();
65
+ if (!val) {
66
+ return fallback;
67
+ }
68
+ if (val.endsWith("%")) {
69
+ return size * (parseFloat(val) / 100);
70
+ }
71
+ if (val.endsWith("px")) {
72
+ return parseFloat(val);
73
+ }
74
+ if (val === "center") {
75
+ return fallback;
76
+ }
77
+ if (axis === "x") {
78
+ if (val === "left") {
79
+ return 0;
80
+ }
81
+ if (val === "right") {
82
+ return size;
83
+ }
84
+ } else if (axis === "y") {
85
+ if (val === "top") {
86
+ return 0;
87
+ }
88
+ if (val === "bottom") {
89
+ return size;
90
+ }
91
+ }
92
+ const num = parseFloat(val);
93
+ return Number.isNaN(num) ? fallback : num;
94
+ }
95
+ function getTransformOriginPoint(origin, width, height) {
96
+ const [originX = "50%", originY = "50%"] = origin?.split(/\s+/).filter(Boolean) ?? [];
97
+ return [
98
+ parseOriginValue(originX, width, "x"),
99
+ parseOriginValue(originY, height, "y")
100
+ ];
101
+ }
102
+ function normalizeRect(rect, scaleX, scaleY, originX, originY) {
103
+ const rawX = rect.x ?? rect.left;
104
+ const rawY = rect.y ?? rect.top;
105
+ const width = rect.width / scaleX;
106
+ const height = rect.height / scaleY;
107
+ const x = rawX - (1 - scaleX) * originX;
108
+ const y = rawY - (1 - scaleY) * originY;
109
+ const right = x + width;
110
+ const bottom = y + height;
111
+ return {
112
+ x,
113
+ y,
114
+ width,
115
+ height,
116
+ left: x,
117
+ top: y,
118
+ right,
119
+ bottom
120
+ };
121
+ }
122
+ function shouldSwitchPlacement(isOverflow, isVisibleFirst, newVisibleArea, originVisibleArea, newRecommendArea, originRecommendArea) {
123
+ if (isOverflow) {
124
+ return newVisibleArea > originVisibleArea || newVisibleArea === originVisibleArea && (!isVisibleFirst || newRecommendArea >= originRecommendArea);
125
+ }
126
+ return newVisibleArea > originVisibleArea || isVisibleFirst && newVisibleArea === originVisibleArea && newRecommendArea > originRecommendArea;
127
+ }
59
128
  function useAlign(open, popupEle, target, placement, builtinPlacements, popupAlign, onPopupAlign, mobile) {
60
129
  const offsetInfo = reactive({
61
130
  ready: false,
@@ -101,7 +170,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
101
170
  const popupElement = popupEle.value;
102
171
  const doc = popupElement.ownerDocument;
103
172
  const win = getWin(popupElement);
104
- const { position: popupPosition } = win.getComputedStyle(popupElement);
173
+ const popupComputedStyle = win.getComputedStyle(popupElement);
174
+ const { position: popupPosition } = popupComputedStyle;
105
175
  const originLeft = popupElement.style.left;
106
176
  const originTop = popupElement.style.top;
107
177
  const originRight = popupElement.style.right;
@@ -142,10 +212,7 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
142
212
  height: rect.height
143
213
  };
144
214
  }
145
- const popupRect = popupElement.getBoundingClientRect();
146
- const { height, width } = win.getComputedStyle(popupElement);
147
- popupRect.x = popupRect.x ?? popupRect.left;
148
- popupRect.y = popupRect.y ?? popupRect.top;
215
+ const rawPopupRect = popupElement.getBoundingClientRect();
149
216
  const {
150
217
  clientWidth,
151
218
  clientHeight,
@@ -154,8 +221,6 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
154
221
  scrollTop,
155
222
  scrollLeft
156
223
  } = doc.documentElement;
157
- const popupHeight = popupRect.height;
158
- const popupWidth = popupRect.width;
159
224
  const targetHeight = targetRect.height;
160
225
  const targetWidth = targetRect.width;
161
226
  const visibleRegion = {
@@ -185,22 +250,43 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
185
250
  popupElement.style.top = "auto";
186
251
  popupElement.style.right = "0";
187
252
  popupElement.style.bottom = "0";
188
- const popupMirrorRect = popupElement.getBoundingClientRect();
253
+ const rawPopupMirrorRect = popupElement.getBoundingClientRect();
189
254
  popupElement.style.left = originLeft;
190
255
  popupElement.style.top = originTop;
191
256
  popupElement.style.right = originRight;
192
257
  popupElement.style.bottom = originBottom;
193
258
  popupElement.style.overflow = originOverflow;
194
259
  popupElement.parentElement?.removeChild(placeholderElement);
260
+ const widthValue = parseFloat(popupComputedStyle.width);
261
+ const heightValue = parseFloat(popupComputedStyle.height);
262
+ const baseWidth = !Number.isNaN(widthValue) && widthValue > 0 ? widthValue : popupElement.offsetWidth;
263
+ const baseHeight = !Number.isNaN(heightValue) && heightValue > 0 ? heightValue : popupElement.offsetHeight;
264
+ const safeBaseWidth = baseWidth || rawPopupRect.width || 1;
265
+ const safeBaseHeight = baseHeight || rawPopupRect.height || 1;
195
266
  const scaleX2 = toNum(
196
- Math.round(popupWidth / parseFloat(width) * 1e3) / 1e3
267
+ Math.round(rawPopupRect.width / safeBaseWidth * 1e3) / 1e3
197
268
  );
198
269
  const scaleY2 = toNum(
199
- Math.round(popupHeight / parseFloat(height) * 1e3) / 1e3
270
+ Math.round(rawPopupRect.height / safeBaseHeight * 1e3) / 1e3
200
271
  );
201
272
  if (scaleX2 === 0 || scaleY2 === 0 || isDOM(target) && !isVisible(target)) {
202
273
  return;
203
274
  }
275
+ const [originX, originY] = getTransformOriginPoint(
276
+ popupComputedStyle.transformOrigin,
277
+ safeBaseWidth,
278
+ safeBaseHeight
279
+ );
280
+ const popupRect = normalizeRect(rawPopupRect, scaleX2, scaleY2, originX, originY);
281
+ const popupMirrorRect = normalizeRect(
282
+ rawPopupMirrorRect,
283
+ scaleX2,
284
+ scaleY2,
285
+ originX,
286
+ originY
287
+ );
288
+ const popupHeight = popupRect.height;
289
+ const popupWidth = popupRect.width;
204
290
  const { offset, targetOffset } = placementInfo;
205
291
  let [popupOffsetX, popupOffsetY] = getNumberOffset(popupRect, offset);
206
292
  const [targetOffsetX, targetOffsetY] = getNumberOffset(
@@ -247,7 +333,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
247
333
  syncNextPopupPosition();
248
334
  const needAdjustY = supportAdjust(adjustY);
249
335
  const sameTB = popupPoints[0] === targetPoints[0];
250
- if (needAdjustY && popupPoints[0] === "t" && (nextPopupBottom > adjustCheckVisibleArea.bottom || prevFlipRef.value.bt)) {
336
+ const overflowBottom = nextPopupBottom > adjustCheckVisibleArea.bottom;
337
+ if (needAdjustY && popupPoints[0] === "t" && (overflowBottom || prevFlipRef.value.bt)) {
251
338
  let tmpNextOffsetY = nextOffsetY;
252
339
  if (sameTB) {
253
340
  tmpNextOffsetY -= popupHeight - targetHeight;
@@ -263,10 +350,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
263
350
  tmpNextOffsetY,
264
351
  visibleRegionArea
265
352
  );
266
- if (
267
- // Of course use larger one
268
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
269
- ) {
353
+ const shouldFlip = shouldSwitchPlacement(
354
+ overflowBottom,
355
+ isVisibleFirst,
356
+ newVisibleArea,
357
+ originIntersectionVisibleArea,
358
+ newVisibleRecommendArea,
359
+ originIntersectionRecommendArea
360
+ );
361
+ if (shouldFlip) {
270
362
  prevFlipRef.value.bt = true;
271
363
  nextOffsetY = tmpNextOffsetY;
272
364
  popupOffsetY = -popupOffsetY;
@@ -278,7 +370,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
278
370
  prevFlipRef.value.bt = false;
279
371
  }
280
372
  }
281
- if (needAdjustY && popupPoints[0] === "b" && (nextPopupY < adjustCheckVisibleArea.top || prevFlipRef.value.tb)) {
373
+ const overflowTop = nextPopupY < adjustCheckVisibleArea.top;
374
+ if (needAdjustY && popupPoints[0] === "b" && (overflowTop || prevFlipRef.value.tb)) {
282
375
  let tmpNextOffsetY = nextOffsetY;
283
376
  if (sameTB) {
284
377
  tmpNextOffsetY += popupHeight - targetHeight;
@@ -294,10 +387,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
294
387
  tmpNextOffsetY,
295
388
  visibleRegionArea
296
389
  );
297
- if (
298
- // Of course use larger one
299
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
300
- ) {
390
+ const shouldFlip = shouldSwitchPlacement(
391
+ overflowTop,
392
+ isVisibleFirst,
393
+ newVisibleArea,
394
+ originIntersectionVisibleArea,
395
+ newVisibleRecommendArea,
396
+ originIntersectionRecommendArea
397
+ );
398
+ if (shouldFlip) {
301
399
  prevFlipRef.value.tb = true;
302
400
  nextOffsetY = tmpNextOffsetY;
303
401
  popupOffsetY = -popupOffsetY;
@@ -311,7 +409,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
311
409
  }
312
410
  const needAdjustX = supportAdjust(adjustX);
313
411
  const sameLR = popupPoints[1] === targetPoints[1];
314
- if (needAdjustX && popupPoints[1] === "l" && (nextPopupRight > adjustCheckVisibleArea.right || prevFlipRef.value.rl)) {
412
+ const overflowRight = nextPopupRight > adjustCheckVisibleArea.right;
413
+ if (needAdjustX && popupPoints[1] === "l" && (overflowRight || prevFlipRef.value.rl)) {
315
414
  let tmpNextOffsetX = nextOffsetX;
316
415
  if (sameLR) {
317
416
  tmpNextOffsetX -= popupWidth - targetWidth;
@@ -327,10 +426,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
327
426
  nextOffsetY,
328
427
  visibleRegionArea
329
428
  );
330
- if (
331
- // Of course use larger one
332
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
333
- ) {
429
+ const shouldFlip = shouldSwitchPlacement(
430
+ overflowRight,
431
+ isVisibleFirst,
432
+ newVisibleArea,
433
+ originIntersectionVisibleArea,
434
+ newVisibleRecommendArea,
435
+ originIntersectionRecommendArea
436
+ );
437
+ if (shouldFlip) {
334
438
  prevFlipRef.value.rl = true;
335
439
  nextOffsetX = tmpNextOffsetX;
336
440
  popupOffsetX = -popupOffsetX;
@@ -342,7 +446,8 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
342
446
  prevFlipRef.value.rl = false;
343
447
  }
344
448
  }
345
- if (needAdjustX && popupPoints[1] === "r" && (nextPopupX < adjustCheckVisibleArea.left || prevFlipRef.value.lr)) {
449
+ const overflowLeft = nextPopupX < adjustCheckVisibleArea.left;
450
+ if (needAdjustX && popupPoints[1] === "r" && (overflowLeft || prevFlipRef.value.lr)) {
346
451
  let tmpNextOffsetX = nextOffsetX;
347
452
  if (sameLR) {
348
453
  tmpNextOffsetX += popupWidth - targetWidth;
@@ -358,10 +463,15 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
358
463
  nextOffsetY,
359
464
  visibleRegionArea
360
465
  );
361
- if (
362
- // Of course use larger one
363
- newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst || newVisibleRecommendArea >= originIntersectionRecommendArea)
364
- ) {
466
+ const shouldFlip = shouldSwitchPlacement(
467
+ overflowLeft,
468
+ isVisibleFirst,
469
+ newVisibleArea,
470
+ originIntersectionVisibleArea,
471
+ newVisibleRecommendArea,
472
+ originIntersectionRecommendArea
473
+ );
474
+ if (shouldFlip) {
365
475
  prevFlipRef.value.lr = true;
366
476
  nextOffsetX = tmpNextOffsetX;
367
477
  popupOffsetX = -popupOffsetX;
@@ -433,12 +543,12 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
433
543
  }
434
544
  const nextOffsetInfo = {
435
545
  ready: true,
436
- offsetX: nextOffsetX / scaleX2,
437
- offsetY: nextOffsetY / scaleY2,
438
- offsetR: offsetX4Right / scaleX2,
439
- offsetB: offsetY4Bottom / scaleY2,
440
- arrowX: nextArrowX / scaleX2,
441
- arrowY: nextArrowY / scaleY2,
546
+ offsetX: nextOffsetX,
547
+ offsetY: nextOffsetY,
548
+ offsetR: offsetX4Right,
549
+ offsetB: offsetY4Bottom,
550
+ arrowX: nextArrowX,
551
+ arrowY: nextArrowY,
442
552
  scaleX: scaleX2,
443
553
  scaleY: scaleY2,
444
554
  align: nextAlignInfo
@@ -468,17 +578,21 @@ function useAlign(open, popupEle, target, placement, builtinPlacements, popupAli
468
578
  const resetReady = () => {
469
579
  offsetInfo.ready = false;
470
580
  };
471
- watch(placement, async () => {
472
- await nextTick();
581
+ watch(placement, () => {
473
582
  resetReady();
474
583
  });
475
- watchEffect(async () => {
476
- if (!open.value) {
477
- resetFlipCache();
478
- await nextTick();
479
- resetReady();
584
+ watch(
585
+ open,
586
+ () => {
587
+ if (!open.value) {
588
+ resetFlipCache();
589
+ resetReady();
590
+ }
591
+ },
592
+ {
593
+ immediate: true
480
594
  }
481
- });
595
+ );
482
596
  const { ready, offsetX, offsetR, offsetY, offsetB, align, arrowY, arrowX, scaleY, scaleX } = toRefs(offsetInfo);
483
597
  return [
484
598
  ready,
@@ -10,6 +10,10 @@ function useOffsetStyle(isMobile, ready, open, align, offsetR, offsetB, offsetX,
10
10
  right: AUTO,
11
11
  bottom: AUTO
12
12
  };
13
+ const offsetShow = offsetX.value > 0 || offsetY.value > 0 || offsetR.value > 0 || offsetB.value > 0;
14
+ if (!offsetShow) {
15
+ return {};
16
+ }
13
17
  if (!isMobile.value && (ready.value || !open.value)) {
14
18
  const { points } = align.value ?? {};
15
19
  const dynamicInset = align.value?.dynamicInset || align.value?._experimental?.dynamicInset;
@@ -8,6 +8,10 @@ function useOffsetStyle(isMobile, ready, open, align, offsetR, offsetB, offsetX,
8
8
  right: AUTO,
9
9
  bottom: AUTO
10
10
  };
11
+ const offsetShow = offsetX.value > 0 || offsetY.value > 0 || offsetR.value > 0 || offsetB.value > 0;
12
+ if (!offsetShow) {
13
+ return {};
14
+ }
11
15
  if (!isMobile.value && (ready.value || !open.value)) {
12
16
  const { points } = align.value ?? {};
13
17
  const dynamicInset = align.value?.dynamicInset || align.value?._experimental?.dynamicInset;
package/dist/index.d.ts CHANGED
@@ -63,7 +63,7 @@ export interface TriggerProps {
63
63
  unique?: boolean;
64
64
  arrow?: boolean | ArrowTypeOuter;
65
65
  /**
66
- * @private Bump fixed position at bottom in mobile.
66
+ * @private
67
67
  * Will replace the config of root props.
68
68
  * This will directly trade as mobile view which will not check what real is.
69
69
  * This is internal usage currently, do not use in your prod.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@v-c/trigger",
3
3
  "type": "module",
4
- "version": "0.0.11",
4
+ "version": "0.0.13",
5
5
  "description": "",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -29,8 +29,8 @@
29
29
  "vue": "^3.0.0"
30
30
  },
31
31
  "dependencies": {
32
- "@v-c/portal": "0.0.3",
33
- "@v-c/resize-observer": "0.0.2",
32
+ "@v-c/portal": "0.0.4",
33
+ "@v-c/resize-observer": "0.0.3",
34
34
  "@v-c/util": "0.0.13"
35
35
  },
36
36
  "scripts": {