@vxe-ui/core 3.4.31 → 3.4.33

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.
@@ -0,0 +1,194 @@
1
+ import XEUtils from 'xe-utils'
2
+
3
+ import type { VxePopperUtils, VxePopperOptions } from '../../types'
4
+
5
+ /**
6
+ * 获取包裹容器的元素
7
+ */
8
+ function getWrapperElement (panelElem: HTMLElement | null | undefined) {
9
+ if (!panelElem) {
10
+ return null
11
+ }
12
+ const bodyEl = document.body
13
+ const parentEl = panelElem.parentElement
14
+ return (parentEl === bodyEl ? document.documentElement : parentEl) || null
15
+ }
16
+
17
+ /**
18
+ * 获取插入到指定容器的元素或字符串
19
+ */
20
+ function getAppendSelector (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined) {
21
+ const selectElem = appendTo && XEUtils.isFunction(appendTo) ? appendTo({}) : appendTo
22
+ return selectElem || 'body'
23
+ }
24
+
25
+ /**
26
+ * 获取插入到指定容器的元素
27
+ */
28
+ function getAppendElement (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined) {
29
+ const selectElem = getAppendSelector(appendTo)
30
+ if (XEUtils.isString(selectElem)) {
31
+ return document.querySelector<HTMLElement>(selectElem) || document.body
32
+ }
33
+ return selectElem
34
+ }
35
+
36
+ export const popperUtils: VxePopperUtils = {
37
+ /**
38
+ * 更新位置
39
+ */
40
+ updatePlacement (targetElem: HTMLElement | null | undefined, panelElem: HTMLElement | null | undefined, options: VxePopperOptions) {
41
+ const { defaultTop, defaultLeft, placement, defaultPlacement, appendTo, teleportTo, marginSize, isMinWidth } = Object.assign({
42
+ appendTo: '',
43
+ teleportTo: false,
44
+ marginSize: 18,
45
+ isMinWidth: true
46
+ }, options)
47
+ let panelPlacement: 'top' | 'bottom' = 'bottom'
48
+ let top: number | '' = ''
49
+ let bottom: number | '' = ''
50
+ let left = 0
51
+ let minWidth: number | '' = ''
52
+ let arrowLeft: number | '' = ''
53
+ const stys: Record<string, string> = {}
54
+ if (panelElem && targetElem) {
55
+ const bodyEl = document.body
56
+ const parentWrapperEl = getWrapperElement(teleportTo ? getAppendElement(appendTo) : panelElem)
57
+ if (parentWrapperEl) {
58
+ const targetWidth = targetElem.offsetWidth
59
+ const targetHeight = targetElem.offsetHeight
60
+ const panelWidth = panelElem.offsetWidth
61
+ const panelHeight = panelElem.offsetHeight
62
+
63
+ const parentWrapperRect = parentWrapperEl.getBoundingClientRect()
64
+ const panelRect = panelElem.getBoundingClientRect()
65
+ const targetRect = targetElem.getBoundingClientRect()
66
+ const visibleHeight = bodyEl.clientHeight
67
+ const visibleWidth = bodyEl.clientWidth
68
+
69
+ const parentWrapperScrollLeft = parentWrapperEl.scrollLeft
70
+ const parentWrapperScrollTop = parentWrapperEl.scrollTop
71
+ const parentWrapperOffsetLeft = parentWrapperRect.left
72
+ const parentWrapperOffsetTop = parentWrapperRect.top
73
+ const targetLeft = targetRect.left
74
+ const targetTop = targetRect.top
75
+
76
+ minWidth = targetElem.offsetWidth
77
+
78
+ if (teleportTo) {
79
+ left = (defaultLeft || (targetLeft - (panelWidth - targetWidth) / 2)) - parentWrapperScrollLeft
80
+ top = (defaultTop || (targetTop + targetHeight)) - parentWrapperScrollTop
81
+ if (placement === 'top') {
82
+ panelPlacement = 'top'
83
+ top = targetTop - panelHeight
84
+ } else if (!placement) {
85
+ if (defaultPlacement === 'top') {
86
+ panelPlacement = 'top'
87
+ if (!defaultTop) {
88
+ top = targetTop - panelHeight
89
+ }
90
+ // 如果上面不够放,则向下
91
+ if (top < marginSize) {
92
+ panelPlacement = 'bottom'
93
+ top = targetTop + targetHeight
94
+ }
95
+ // 如果下面不够放,则向上(优先)
96
+ if (top + panelHeight + marginSize > visibleHeight) {
97
+ panelPlacement = 'top'
98
+ top = targetTop - panelHeight
99
+ }
100
+ } else {
101
+ // 如果下面不够放,则向上
102
+ if (top + panelHeight + marginSize > visibleHeight) {
103
+ panelPlacement = 'top'
104
+ top = targetTop - panelHeight
105
+ }
106
+ // 如果上面不够放,则向下(优先)
107
+ if (top < marginSize) {
108
+ panelPlacement = 'bottom'
109
+ top = targetTop + targetHeight
110
+ }
111
+ }
112
+ }
113
+ // 如果溢出右边
114
+ if (left + panelWidth + marginSize > visibleWidth) {
115
+ left -= left + panelWidth + marginSize - visibleWidth
116
+ }
117
+ // 如果溢出左边
118
+ if (left < marginSize) {
119
+ left = marginSize
120
+ }
121
+
122
+ // 偏移
123
+ top -= parentWrapperOffsetTop
124
+ left -= parentWrapperOffsetLeft
125
+ } else {
126
+ if (placement === 'top') {
127
+ panelPlacement = 'top'
128
+ bottom = targetHeight
129
+ } else if (!placement) {
130
+ // 如果下面不够放,则向上
131
+ top = targetHeight
132
+ if (targetTop + targetHeight + panelHeight + marginSize > visibleHeight) {
133
+ // 如果上面不够放,则向下(优先)
134
+ if (targetTop - targetHeight - panelHeight > marginSize) {
135
+ panelPlacement = 'top'
136
+ top = ''
137
+ bottom = targetHeight
138
+ }
139
+ }
140
+ }
141
+ // 是否超出右侧
142
+ if (panelRect.left + panelRect.width + marginSize > visibleWidth) {
143
+ left = -(panelRect.left + panelRect.width + marginSize - visibleWidth)
144
+ }
145
+ }
146
+ if (XEUtils.isNumber(top)) {
147
+ stys.top = top + 'px'
148
+ }
149
+ if (XEUtils.isNumber(bottom)) {
150
+ stys.bottom = bottom + 'px'
151
+ }
152
+ if (XEUtils.isNumber(left)) {
153
+ stys.left = left + 'px'
154
+ }
155
+ if (isMinWidth && XEUtils.isNumber(minWidth)) {
156
+ stys.minWidth = minWidth + 'px'
157
+ }
158
+
159
+ // 箭头
160
+ if (left === targetLeft) {
161
+ if (targetWidth <= panelWidth) {
162
+ arrowLeft = targetWidth / 2
163
+ }
164
+ } else if (left < targetLeft) {
165
+ if (left + panelWidth > targetLeft + targetWidth) {
166
+ arrowLeft = (targetLeft - left) + targetWidth / 2
167
+ } else {
168
+ arrowLeft = (targetLeft - left) + (panelWidth - (targetLeft - left)) / 2
169
+ }
170
+ }
171
+ }
172
+ }
173
+ return {
174
+ top: top || 0,
175
+ bottom: bottom || 0,
176
+ left: left || 0,
177
+ arrowLeft: arrowLeft || 0,
178
+ style: stys,
179
+ placement: panelPlacement
180
+ }
181
+ },
182
+ /**
183
+ * 获取包裹容器的元素
184
+ */
185
+ getWrapperElement,
186
+ /**
187
+ * 获取插入到指定容器的元素或字符串
188
+ */
189
+ getAppendSelector,
190
+ /**
191
+ * 获取插入到指定容器的元素
192
+ */
193
+ getAppendElement
194
+ }
@@ -2,6 +2,10 @@
2
2
  type Nullish = null | undefined
3
3
  export type VxeBaseEmptyValue = '' | Nullish
4
4
 
5
+ interface EnableConfOptions {
6
+ enabled?: boolean
7
+ }
8
+
5
9
  export interface VxeBaseUtils {
6
10
  /**
7
11
  * 转成字符串
@@ -19,4 +23,18 @@ export interface VxeBaseUtils {
19
23
  * @param defVal
20
24
  */
21
25
  getDefVal<T = any, D = any>(value: T, defVal: D): T | D
26
+ /**
27
+ * 判断配置项是否启用
28
+ * @param conf
29
+ */
30
+ isEnabled(conf: EnableConfOptions): boolean
31
+ /**
32
+ * 用于判断开关类型的配置项
33
+ * 局部启用规则:conf={}
34
+ * 局部禁用规则:conf={enabled:false}
35
+ * 全局默认启用规则:conf.enabled=true
36
+ * @param conf
37
+ * @param opts
38
+ */
39
+ hasEnableConf(conf: EnableConfOptions, opts: EnableConfOptions): boolean
22
40
  }
@@ -1,5 +1,33 @@
1
1
 
2
2
  export interface VxeDomUtils {
3
+ /**
4
+ * 判断是否像素px单位 '100px' | 100
5
+ * @param val
6
+ */
7
+ isPx(val: any): boolean
8
+ /**
9
+ * 判断是否百分比%单位 '100%'
10
+ * @param val
11
+ */
12
+ isScale(val: any): boolean
13
+ /**
14
+ * 判断元素是否包含 class
15
+ * @param elem
16
+ * @param cls
17
+ */
18
+ hasClass(elem: HTMLElement, cls: string): boolean
19
+ /**
20
+ * 给元素删除 class
21
+ * @param elem
22
+ * @param cls
23
+ */
24
+ removeClass(elem: HTMLElement, cls: string): void
25
+ /**
26
+ * 给元素增加 class
27
+ * @param elem
28
+ * @param cls
29
+ */
30
+ addClass(elem: HTMLElement, cls: string): void
3
31
  /**
4
32
  * 生成 className
5
33
  * @param staticClassNames
@@ -18,6 +18,7 @@ import { VxeGlobalPermission } from './permission'
18
18
  import { VxeBaseUtils } from './base-utils'
19
19
  import { VxeDomUtils } from './dom-utils'
20
20
  import { VxeScrollbarUtils } from './scrollbar-utils'
21
+ import { VxePopperUtils } from './popper-utils'
21
22
  import { VxeGlobalComponentMethod, VxeGlobalGetComponentMethod, VxeGlobalHasComponentMethod } from './components'
22
23
  import { VxeGlobalUseMixins } from './mixins'
23
24
  import { VxeGlobalLog } from './log'
@@ -76,6 +77,7 @@ export const permission: VxeGlobalPermission
76
77
  export const baseUtils: VxeBaseUtils
77
78
  export const domUtils: VxeDomUtils
78
79
  export const scrollbarUtils: VxeScrollbarUtils
80
+ export const popperUtils: VxePopperUtils
79
81
 
80
82
  export const globalEvents: VxeGlobalEvents
81
83
 
@@ -302,6 +304,7 @@ export * from './permission'
302
304
  export * from './base-utils'
303
305
  export * from './dom-utils'
304
306
  export * from './scrollbar-utils'
307
+ export * from './popper-utils'
305
308
 
306
309
  export * from './log'
307
310
 
@@ -0,0 +1,44 @@
1
+ export interface VxePopperOptions {
2
+ defaultTop?: number
3
+ defaultLeft?: number
4
+ placement?: '' | 'top' | 'bottom' | null
5
+ defaultPlacement?: '' | 'top' | 'bottom' | null
6
+ appendTo?: string | HTMLElement | ((params: any) => string | HTMLElement)
7
+ teleportTo?: boolean
8
+ marginSize?: number
9
+ isMinWidth?: boolean
10
+ }
11
+
12
+ export interface VxePopperPlacementResult {
13
+ top: number
14
+ bottom: number
15
+ left: number
16
+ arrowLeft: number
17
+ style: Record<string, string>
18
+ placement: 'top' | 'bottom'
19
+ }
20
+
21
+ export interface VxePopperUtils {
22
+ /**
23
+ * 更新位置
24
+ * @param targetElem
25
+ * @param panelElem
26
+ * @param options
27
+ */
28
+ updatePlacement (targetElem: HTMLElement | null | undefined, panelElem: HTMLElement | null | undefined, options: VxePopperOptions): VxePopperPlacementResult
29
+ /**
30
+ * 获取包裹容器的元素
31
+ * @param panelElem
32
+ */
33
+ getWrapperElement (panelElem: HTMLElement | null | undefined): HTMLElement | null
34
+ /**
35
+ * 获取插入到指定容器的元素或字符串
36
+ * @param appendTo
37
+ */
38
+ getAppendSelector (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined): HTMLElement | string
39
+ /**
40
+ * 获取插入到指定容器的元素
41
+ * @param appendTo
42
+ */
43
+ getAppendElement (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined): HTMLElement | null
44
+ }