@v-c/util 0.0.1

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 (187) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Children/isFragment.cjs +1 -0
  3. package/dist/Children/isFragment.d.ts +3 -0
  4. package/dist/Children/isFragment.js +7 -0
  5. package/dist/Children/toArray.cjs +1 -0
  6. package/dist/Children/toArray.d.ts +8 -0
  7. package/dist/Children/toArray.js +11 -0
  8. package/dist/Dom/addEventListener.cjs +1 -0
  9. package/dist/Dom/addEventListener.d.ts +8 -0
  10. package/dist/Dom/addEventListener.js +12 -0
  11. package/dist/Dom/canUseDom.cjs +1 -0
  12. package/dist/Dom/canUseDom.d.ts +1 -0
  13. package/dist/Dom/canUseDom.js +6 -0
  14. package/dist/Dom/class.cjs +1 -0
  15. package/dist/Dom/class.d.ts +3 -0
  16. package/dist/Dom/class.js +19 -0
  17. package/dist/Dom/contains.cjs +1 -0
  18. package/dist/Dom/contains.d.ts +1 -0
  19. package/dist/Dom/contains.js +16 -0
  20. package/dist/Dom/css.cjs +1 -0
  21. package/dist/Dom/css.d.ts +20 -0
  22. package/dist/Dom/css.js +75 -0
  23. package/dist/Dom/dynamicCSS.cjs +1 -0
  24. package/dist/Dom/dynamicCSS.d.ts +24 -0
  25. package/dist/Dom/dynamicCSS.js +78 -0
  26. package/dist/Dom/findDOMNode.cjs +1 -0
  27. package/dist/Dom/findDOMNode.d.ts +7 -0
  28. package/dist/Dom/findDOMNode.js +12 -0
  29. package/dist/Dom/focus.cjs +1 -0
  30. package/dist/Dom/focus.d.ts +8 -0
  31. package/dist/Dom/focus.js +40 -0
  32. package/dist/Dom/isVisible.cjs +1 -0
  33. package/dist/Dom/isVisible.d.ts +2 -0
  34. package/dist/Dom/isVisible.js +22 -0
  35. package/dist/Dom/scrollLocker.cjs +1 -0
  36. package/dist/Dom/scrollLocker.d.ts +12 -0
  37. package/dist/Dom/scrollLocker.js +81 -0
  38. package/dist/Dom/shadow.cjs +1 -0
  39. package/dist/Dom/shadow.d.ts +8 -0
  40. package/dist/Dom/shadow.js +14 -0
  41. package/dist/Dom/styleChecker.cjs +1 -0
  42. package/dist/Dom/styleChecker.d.ts +2 -0
  43. package/dist/Dom/styleChecker.js +20 -0
  44. package/dist/Dom/support.cjs +1 -0
  45. package/dist/Dom/support.d.ts +6 -0
  46. package/dist/Dom/support.js +24 -0
  47. package/dist/EventInterface.cjs +1 -0
  48. package/dist/EventInterface.d.ts +18 -0
  49. package/dist/EventInterface.js +1 -0
  50. package/dist/KeyCode.cjs +1 -0
  51. package/dist/KeyCode.d.ts +435 -0
  52. package/dist/KeyCode.js +516 -0
  53. package/dist/Portal.cjs +1 -0
  54. package/dist/Portal.d.ts +8 -0
  55. package/dist/Portal.js +38 -0
  56. package/dist/PortalWrapper.cjs +1 -0
  57. package/dist/PortalWrapper.d.ts +28 -0
  58. package/dist/PortalWrapper.js +114 -0
  59. package/dist/composeProps.cjs +1 -0
  60. package/dist/composeProps.d.ts +2 -0
  61. package/dist/composeProps.js +16 -0
  62. package/dist/createRef.cjs +1 -0
  63. package/dist/createRef.d.ts +12 -0
  64. package/dist/createRef.js +21 -0
  65. package/dist/debug/diff.cjs +1 -0
  66. package/dist/debug/diff.d.ts +1 -0
  67. package/dist/debug/diff.js +41 -0
  68. package/dist/deprecated.cjs +1 -0
  69. package/dist/deprecated.d.ts +1 -0
  70. package/dist/deprecated.js +8 -0
  71. package/dist/getScrollBarSize.cjs +1 -0
  72. package/dist/getScrollBarSize.d.ts +5 -0
  73. package/dist/getScrollBarSize.js +37 -0
  74. package/dist/guid.cjs +1 -0
  75. package/dist/guid.d.ts +1 -0
  76. package/dist/guid.js +7 -0
  77. package/dist/hooks/useId.cjs +1 -0
  78. package/dist/hooks/useId.d.ts +5 -0
  79. package/dist/hooks/useId.js +17 -0
  80. package/dist/hooks/useMemo.cjs +1 -0
  81. package/dist/hooks/useMemo.d.ts +3 -0
  82. package/dist/hooks/useMemo.js +10 -0
  83. package/dist/hooks/useMergedState.cjs +1 -0
  84. package/dist/hooks/useMergedState.d.ts +8 -0
  85. package/dist/hooks/useMergedState.js +21 -0
  86. package/dist/hooks/useState.cjs +1 -0
  87. package/dist/hooks/useState.d.ts +3 -0
  88. package/dist/hooks/useState.js +11 -0
  89. package/dist/index.cjs +1 -0
  90. package/dist/index.d.ts +3 -0
  91. package/dist/index.js +8 -0
  92. package/dist/isEqual.cjs +1 -0
  93. package/dist/isEqual.d.ts +8 -0
  94. package/dist/isEqual.js +32 -0
  95. package/dist/isMobile.cjs +1 -0
  96. package/dist/isMobile.d.ts +2 -0
  97. package/dist/isMobile.js +13 -0
  98. package/dist/omit.cjs +1 -0
  99. package/dist/omit.d.ts +1 -0
  100. package/dist/omit.js +9 -0
  101. package/dist/pickAttrs.cjs +18 -0
  102. package/dist/pickAttrs.d.ts +11 -0
  103. package/dist/pickAttrs.js +41 -0
  104. package/dist/props-util/index.cjs +1 -0
  105. package/dist/props-util/index.d.ts +2 -0
  106. package/dist/props-util/index.js +14 -0
  107. package/dist/raf.cjs +1 -0
  108. package/dist/raf.d.ts +6 -0
  109. package/dist/raf.js +30 -0
  110. package/dist/setStyle.cjs +1 -0
  111. package/dist/setStyle.d.ts +13 -0
  112. package/dist/setStyle.js +13 -0
  113. package/dist/switchScrollingEffect.cjs +1 -0
  114. package/dist/switchScrollingEffect.d.ts +2 -0
  115. package/dist/switchScrollingEffect.js +31 -0
  116. package/dist/test/domHook.cjs +1 -0
  117. package/dist/test/domHook.d.ts +8 -0
  118. package/dist/test/domHook.js +37 -0
  119. package/dist/type.cjs +1 -0
  120. package/dist/type.d.ts +63 -0
  121. package/dist/type.js +49 -0
  122. package/dist/utils/checkSlotProp.cjs +1 -0
  123. package/dist/utils/checkSlotProp.d.ts +1 -0
  124. package/dist/utils/checkSlotProp.js +7 -0
  125. package/dist/utils/get.cjs +1 -0
  126. package/dist/utils/get.d.ts +1 -0
  127. package/dist/utils/get.js +12 -0
  128. package/dist/utils/set.cjs +1 -0
  129. package/dist/utils/set.d.ts +6 -0
  130. package/dist/utils/set.js +41 -0
  131. package/dist/vnode.cjs +1 -0
  132. package/dist/vnode.d.ts +12 -0
  133. package/dist/vnode.js +41 -0
  134. package/dist/warning.cjs +1 -0
  135. package/dist/warning.d.ts +18 -0
  136. package/dist/warning.js +48 -0
  137. package/package.json +37 -0
  138. package/src/Children/isFragment.ts +6 -0
  139. package/src/Children/tests/isFragment.test.tsx +15 -0
  140. package/src/Children/tests/toArray.test.tsx +101 -0
  141. package/src/Children/toArray.ts +27 -0
  142. package/src/Dom/addEventListener.ts +20 -0
  143. package/src/Dom/canUseDom.ts +7 -0
  144. package/src/Dom/class.ts +29 -0
  145. package/src/Dom/contains.ts +19 -0
  146. package/src/Dom/css.ts +113 -0
  147. package/src/Dom/dynamicCSS.ts +173 -0
  148. package/src/Dom/findDOMNode.ts +23 -0
  149. package/src/Dom/focus.ts +96 -0
  150. package/src/Dom/isVisible.ts +23 -0
  151. package/src/Dom/scrollLocker.ts +143 -0
  152. package/src/Dom/shadow.ts +17 -0
  153. package/src/Dom/styleChecker.ts +31 -0
  154. package/src/Dom/support.ts +27 -0
  155. package/src/EventInterface.ts +19 -0
  156. package/src/KeyCode.ts +516 -0
  157. package/src/Portal.tsx +50 -0
  158. package/src/PortalWrapper.tsx +214 -0
  159. package/src/composeProps.ts +23 -0
  160. package/src/createRef.ts +33 -0
  161. package/src/debug/diff.ts +66 -0
  162. package/src/deprecated.ts +8 -0
  163. package/src/getScrollBarSize.tsx +57 -0
  164. package/src/guid.ts +4 -0
  165. package/src/hooks/useId.ts +31 -0
  166. package/src/hooks/useMemo.ts +21 -0
  167. package/src/hooks/useMergedState.ts +44 -0
  168. package/src/hooks/useState.ts +17 -0
  169. package/src/index.ts +3 -0
  170. package/src/isEqual.ts +50 -0
  171. package/src/isMobile.ts +15 -0
  172. package/src/omit.ts +14 -0
  173. package/src/pickAttrs.ts +78 -0
  174. package/src/props-util/index.ts +22 -0
  175. package/src/raf.ts +55 -0
  176. package/src/setStyle.ts +38 -0
  177. package/src/switchScrollingEffect.ts +48 -0
  178. package/src/test/domHook.ts +67 -0
  179. package/src/type.ts +94 -0
  180. package/src/utils/checkSlotProp.ts +10 -0
  181. package/src/utils/get.ts +15 -0
  182. package/src/utils/set.ts +110 -0
  183. package/src/vnode.ts +86 -0
  184. package/src/warning.ts +79 -0
  185. package/tests/Portal.test.tsx +199 -0
  186. package/tsconfig.json +7 -0
  187. package/vite.config.ts +18 -0
package/src/Dom/css.ts ADDED
@@ -0,0 +1,113 @@
1
+ const PIXEL_PATTERN = /margin|padding|width|height|max|min|offset/
2
+
3
+ const removePixel: any = {
4
+ left: true,
5
+ top: true,
6
+ }
7
+ const floatMap: any = {
8
+ cssFloat: 1,
9
+ styleFloat: 1,
10
+ float: 1,
11
+ }
12
+
13
+ function getComputedStyle(node: HTMLElement) {
14
+ return node.nodeType === 1 ? (node as any).ownerDocument.defaultView.getComputedStyle(node, null) : {}
15
+ }
16
+
17
+ function getStyleValue(node: HTMLElement, type: string, value: string) {
18
+ type = type.toLowerCase()
19
+ if (value === 'auto') {
20
+ if (type === 'height')
21
+ return node.offsetHeight
22
+
23
+ if (type === 'width')
24
+ return node.offsetWidth
25
+ }
26
+ if (!(type in removePixel))
27
+ removePixel[type] = PIXEL_PATTERN.test(type)
28
+
29
+ return removePixel[type] ? Number.parseFloat(value) || 0 : value
30
+ }
31
+
32
+ export function get(node: HTMLElement, name: any) {
33
+ const length = arguments.length
34
+ const style = getComputedStyle(node)
35
+
36
+ name = floatMap[name] ? ('cssFloat' in node.style ? 'cssFloat' : 'styleFloat') : name
37
+
38
+ return length === 1 ? style : getStyleValue(node, name, style[name] || node.style[name])
39
+ }
40
+
41
+ export function set(node: HTMLElement, name: any, value: string | number) {
42
+ const length = arguments.length
43
+ name = floatMap[name] ? ('cssFloat' in node.style ? 'cssFloat' : 'styleFloat') : name
44
+ if (length === 3) {
45
+ if (typeof value === 'number' && PIXEL_PATTERN.test(name))
46
+ value = `${value}px`
47
+
48
+ ;(node.style as any)[name] = value // Number
49
+ return value
50
+ }
51
+ for (const x in name) {
52
+ if (x in name)
53
+ set(node, x, name[x])
54
+ }
55
+ return getComputedStyle(node)
56
+ }
57
+
58
+ export function getOuterWidth(el: HTMLElement) {
59
+ if (el === document.body)
60
+ return document.documentElement.clientWidth
61
+
62
+ return el.offsetWidth
63
+ }
64
+
65
+ export function getOuterHeight(el: HTMLElement) {
66
+ if (el === document.body)
67
+ return window.innerHeight || document.documentElement.clientHeight
68
+
69
+ return el.offsetHeight
70
+ }
71
+
72
+ export function getDocSize() {
73
+ const width = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth)
74
+ const height = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight)
75
+
76
+ return {
77
+ width,
78
+ height,
79
+ }
80
+ }
81
+
82
+ export function getClientSize() {
83
+ const width = document.documentElement.clientWidth
84
+ const height = window.innerHeight || document.documentElement.clientHeight
85
+ return {
86
+ width,
87
+ height,
88
+ }
89
+ }
90
+
91
+ export function getScroll() {
92
+ return {
93
+ scrollLeft: Math.max(document.documentElement.scrollLeft, document.body.scrollLeft),
94
+ scrollTop: Math.max(document.documentElement.scrollTop, document.body.scrollTop),
95
+ }
96
+ }
97
+
98
+ export function getOffset(node: any) {
99
+ const box = node.getBoundingClientRect()
100
+ const docElem = document.documentElement
101
+
102
+ // < ie8 不支持 win.pageXOffset, 则使用 docElem.scrollLeft
103
+ return {
104
+ left:
105
+ box.left
106
+ + (window.pageXOffset || docElem.scrollLeft)
107
+ - (docElem.clientLeft || document.body.clientLeft || 0),
108
+ top:
109
+ box.top
110
+ + (window.pageYOffset || docElem.scrollTop)
111
+ - (docElem.clientTop || document.body.clientTop || 0),
112
+ }
113
+ }
@@ -0,0 +1,173 @@
1
+ import canUseDom from './canUseDom'
2
+ import contains from './contains'
3
+
4
+ const APPEND_ORDER = 'data-vc-order'
5
+ const APPEND_PRIORITY = 'data-vc-priority'
6
+ const MARK_KEY = `vc-util-key`
7
+
8
+ const containerCache = new Map<ContainerType, Node & ParentNode>()
9
+
10
+ export type ContainerType = Element | ShadowRoot
11
+ export type Prepend = boolean | 'queue'
12
+ export type AppendType = 'prependQueue' | 'append' | 'prepend'
13
+
14
+ interface Options {
15
+ attachTo?: ContainerType
16
+ csp?: { nonce?: string }
17
+ prepend?: Prepend
18
+ /**
19
+ * Config the `priority` of `prependQueue`. Default is `0`.
20
+ * It's useful if you need to insert style before other style.
21
+ */
22
+ priority?: number
23
+ mark?: string
24
+ }
25
+
26
+ function getMark({ mark }: Options = {}) {
27
+ if (mark)
28
+ return mark.startsWith('data-') ? mark : `data-${mark}`
29
+
30
+ return MARK_KEY
31
+ }
32
+
33
+ function getContainer(option: Options) {
34
+ if (option.attachTo)
35
+ return option.attachTo
36
+
37
+ const head = document.querySelector('head')
38
+ return head || document.body
39
+ }
40
+
41
+ function getOrder(prepend?: Prepend): AppendType {
42
+ if (prepend === 'queue')
43
+ return 'prependQueue'
44
+
45
+ return prepend ? 'prepend' : 'append'
46
+ }
47
+
48
+ /**
49
+ * Find style which inject by rc-util
50
+ */
51
+ function findStyles(container: ContainerType) {
52
+ return Array.from(
53
+ (containerCache.get(container) || container).children,
54
+ ).filter(node => node.tagName === 'STYLE') as HTMLStyleElement[]
55
+ }
56
+
57
+ export function injectCSS(css: string, option: Options = {}) {
58
+ if (!canUseDom())
59
+ return null
60
+
61
+ const { csp, prepend, priority = 0 } = option
62
+ const mergedOrder = getOrder(prepend)
63
+ const isPrependQueue = mergedOrder === 'prependQueue'
64
+
65
+ const styleNode = document.createElement('style')
66
+ styleNode.setAttribute(APPEND_ORDER, mergedOrder)
67
+
68
+ if (isPrependQueue && priority)
69
+ styleNode.setAttribute(APPEND_PRIORITY, `${priority}`)
70
+
71
+ if (csp?.nonce)
72
+ styleNode.nonce = csp?.nonce
73
+
74
+ styleNode.innerHTML = css
75
+
76
+ const container = getContainer(option)
77
+ const { firstChild } = container
78
+
79
+ if (prepend) {
80
+ // If is queue `prepend`, it will prepend first style and then append rest style
81
+ if (isPrependQueue) {
82
+ const existStyle = findStyles(container).filter((node: any) => {
83
+ // Ignore style which not injected by rc-util with prepend
84
+ if (
85
+ !['prepend', 'prependQueue'].includes(node.getAttribute(APPEND_ORDER))
86
+ )
87
+ return false
88
+
89
+ // Ignore style which priority less then new style
90
+ const nodePriority = Number(node.getAttribute(APPEND_PRIORITY) || 0)
91
+ return priority >= nodePriority
92
+ })
93
+
94
+ if (existStyle.length) {
95
+ container.insertBefore(
96
+ styleNode,
97
+ existStyle[existStyle.length - 1].nextSibling,
98
+ )
99
+
100
+ return styleNode
101
+ }
102
+ }
103
+
104
+ // Use `insertBefore` as `prepend`
105
+ container.insertBefore(styleNode, firstChild)
106
+ }
107
+ else {
108
+ container.appendChild(styleNode)
109
+ }
110
+
111
+ return styleNode
112
+ }
113
+
114
+ function findExistNode(key: string, option: Options = {}) {
115
+ const container = getContainer(option)
116
+
117
+ return findStyles(container).find(
118
+ node => node.getAttribute(getMark(option)) === key,
119
+ )
120
+ }
121
+
122
+ export function removeCSS(key: string, option: Options = {}) {
123
+ const existNode = findExistNode(key, option)
124
+ if (existNode) {
125
+ const container = getContainer(option)
126
+ container.removeChild(existNode)
127
+ }
128
+ }
129
+
130
+ /**
131
+ * qiankun will inject `appendChild` to insert into other
132
+ */
133
+ function syncRealContainer(container: ContainerType, option: Options) {
134
+ const cachedRealContainer = containerCache.get(container)
135
+
136
+ // Find real container when not cached or cached container removed
137
+ if (!cachedRealContainer || !contains(document, cachedRealContainer)) {
138
+ const placeholderStyle: any = injectCSS('', option)
139
+ const { parentNode } = placeholderStyle
140
+ containerCache.set(container, parentNode)
141
+ container.removeChild(placeholderStyle)
142
+ }
143
+ }
144
+
145
+ /**
146
+ * manually clear container cache to avoid global cache in unit testes
147
+ */
148
+ export function clearContainerCache() {
149
+ containerCache.clear()
150
+ }
151
+
152
+ export function updateCSS(css: string, key: string, option: Options = {}) {
153
+ const container = getContainer(option)
154
+
155
+ // Sync real parent
156
+ syncRealContainer(container, option)
157
+
158
+ const existNode = findExistNode(key, option)
159
+
160
+ if (existNode) {
161
+ if (option.csp?.nonce && existNode.nonce !== option.csp?.nonce)
162
+ existNode.nonce = option.csp?.nonce
163
+
164
+ if (existNode.innerHTML !== css)
165
+ existNode.innerHTML = css
166
+
167
+ return existNode
168
+ }
169
+
170
+ const newNode: any = injectCSS(css, option)
171
+ newNode.setAttribute(getMark(option), key)
172
+ return newNode
173
+ }
@@ -0,0 +1,23 @@
1
+ import type { ComponentPublicInstance, MaybeRef } from 'vue'
2
+ import { unref } from 'vue'
3
+
4
+ export function isDOM(node: any): node is HTMLElement | SVGElement {
5
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element
6
+ // Since XULElement is also subclass of Element, we only need HTMLElement and SVGElement
7
+ return node instanceof HTMLElement || node instanceof SVGElement
8
+ }
9
+
10
+ /**
11
+ * Return if a node is a DOM node. Else will return by `findDOMNode`
12
+ */
13
+ export default function findDOMNode<T = Element | Text>(
14
+ _node: MaybeRef<ComponentPublicInstance | HTMLElement | SVGElement>,
15
+ ): T | null {
16
+ const node = unref(_node)
17
+ if (isDOM(node))
18
+ return (node as unknown) as T
19
+ else if (node && '$el' in node)
20
+ return (node.$el as unknown) as T
21
+
22
+ return null
23
+ }
@@ -0,0 +1,96 @@
1
+ import isVisible from './isVisible'
2
+
3
+ type DisabledElement =
4
+ | HTMLLinkElement
5
+ | HTMLInputElement
6
+ | HTMLFieldSetElement
7
+ | HTMLButtonElement
8
+ | HTMLOptGroupElement
9
+ | HTMLOptionElement
10
+ | HTMLSelectElement
11
+ | HTMLTextAreaElement
12
+
13
+ function focusable(node: HTMLElement, includePositive = false): boolean {
14
+ if (isVisible(node)) {
15
+ const nodeName = node.nodeName.toLowerCase()
16
+ const isFocusableElement
17
+ // Focusable element
18
+ = ['input', 'select', 'textarea', 'button'].includes(nodeName)
19
+ // Editable element
20
+ || node.isContentEditable
21
+ // Anchor with href element
22
+ || (nodeName === 'a' && !!node.getAttribute('href'))
23
+
24
+ // Get tabIndex
25
+ const tabIndexAttr = node.getAttribute('tabindex')
26
+ const tabIndexNum = Number(tabIndexAttr)
27
+
28
+ // Parse as number if validate
29
+ let tabIndex: number | null = null
30
+ if (tabIndexAttr && !Number.isNaN(tabIndexNum))
31
+ tabIndex = tabIndexNum
32
+ else if (isFocusableElement && tabIndex === null)
33
+ tabIndex = 0
34
+
35
+ // Block focusable if disabled
36
+ if (isFocusableElement && (node as DisabledElement).disabled)
37
+ tabIndex = null
38
+
39
+ return (
40
+ tabIndex !== null && (tabIndex >= 0 || (includePositive && tabIndex < 0))
41
+ )
42
+ }
43
+
44
+ return false
45
+ }
46
+
47
+ export function getFocusNodeList(node: HTMLElement, includePositive = false) {
48
+ const res = [...node.querySelectorAll<HTMLElement>('*')].filter((child) => {
49
+ return focusable(child, includePositive)
50
+ })
51
+ if (focusable(node, includePositive))
52
+ res.unshift(node)
53
+
54
+ return res
55
+ }
56
+
57
+ let lastFocusElement: any = null
58
+
59
+ /** @deprecated Do not use since this may failed when used in async */
60
+ export function saveLastFocusNode() {
61
+ lastFocusElement = document.activeElement
62
+ }
63
+
64
+ /** @deprecated Do not use since this may failed when used in async */
65
+ export function clearLastFocusNode() {
66
+ lastFocusElement = null
67
+ }
68
+
69
+ /** @deprecated Do not use since this may failed when used in async */
70
+ export function backLastFocusNode() {
71
+ if (lastFocusElement) {
72
+ try {
73
+ // 元素可能已经被移动了
74
+ lastFocusElement.focus()
75
+ }
76
+ // eslint-disable-next-line unused-imports/no-unused-vars
77
+ catch (_e: any) {
78
+ // empty
79
+ }
80
+ }
81
+ }
82
+
83
+ export function limitTabRange(node: HTMLElement, e: KeyboardEvent) {
84
+ if (e.keyCode === 9) {
85
+ const tabNodeList = getFocusNodeList(node)
86
+ const lastTabNode = tabNodeList[e.shiftKey ? 0 : tabNodeList.length - 1]
87
+ const leavingTab
88
+ = lastTabNode === document.activeElement || node === document.activeElement
89
+
90
+ if (leavingTab) {
91
+ const target = tabNodeList[e.shiftKey ? tabNodeList.length - 1 : 0]
92
+ target.focus()
93
+ e.preventDefault()
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,23 @@
1
+ export default (element: Element): boolean => {
2
+ if (!element)
3
+ return false
4
+
5
+ if (element instanceof Element) {
6
+ if ((element as HTMLElement).offsetParent)
7
+ return true
8
+
9
+ if ((element as SVGGraphicsElement).getBBox) {
10
+ const { width, height } = (element as SVGGraphicsElement).getBBox()
11
+ if (width || height)
12
+ return true
13
+ }
14
+
15
+ if (element.getBoundingClientRect) {
16
+ const { width, height } = element.getBoundingClientRect()
17
+ if (width || height)
18
+ return true
19
+ }
20
+ }
21
+
22
+ return false
23
+ }
@@ -0,0 +1,143 @@
1
+ import type { CSSProperties } from 'vue'
2
+ import getScrollBarSize from '../getScrollBarSize'
3
+ import setStyle from '../setStyle'
4
+
5
+ export interface scrollLockOptions {
6
+ container: HTMLElement
7
+ }
8
+
9
+ let uuid = 0
10
+
11
+ interface Ilocks {
12
+ target: typeof uuid
13
+ options: scrollLockOptions
14
+ }
15
+
16
+ let locks: Ilocks[] = []
17
+ const scrollingEffectClassName = 'ant-scrolling-effect'
18
+ const scrollingEffectClassNameReg = new RegExp(
19
+ `${scrollingEffectClassName}`,
20
+ 'g',
21
+ )
22
+
23
+ // https://github.com/ant-design/ant-design/issues/19340
24
+ // https://github.com/ant-design/ant-design/issues/19332
25
+ const cacheStyle = new Map<Element, CSSProperties>()
26
+
27
+ export default class ScrollLocker {
28
+ private readonly lockTarget: typeof uuid
29
+
30
+ private options: scrollLockOptions | undefined
31
+
32
+ constructor(options?: scrollLockOptions) {
33
+ this.lockTarget = uuid++
34
+ this.options = options
35
+ }
36
+
37
+ getContainer = (): HTMLElement | undefined => {
38
+ return this.options?.container
39
+ }
40
+
41
+ // if options change...
42
+ reLock = (options?: scrollLockOptions) => {
43
+ const findLock = locks.find(({ target }) => target === this.lockTarget)
44
+
45
+ if (findLock)
46
+ this.unLock()
47
+
48
+ this.options = options
49
+
50
+ if (findLock) {
51
+ findLock.options = options!
52
+
53
+ this.lock()
54
+ }
55
+ }
56
+
57
+ lock = () => {
58
+ // If lockTarget exist return
59
+ if (locks.some(({ target }) => target === this.lockTarget))
60
+ return
61
+
62
+ // If same container effect, return
63
+ if (
64
+ locks.some(
65
+ ({ options }) => options?.container === this.options?.container,
66
+ )
67
+ ) {
68
+ locks = [...locks!, { target: this.lockTarget, options: this.options! }]
69
+ return
70
+ }
71
+
72
+ let scrollBarSize = 0
73
+ const container = this.options?.container || document.body
74
+
75
+ if (
76
+ (container === document.body
77
+ && window.innerWidth - document.documentElement.clientWidth > 0)
78
+ || container.scrollHeight > container.clientHeight
79
+ ) {
80
+ if (getComputedStyle(container).overflow !== 'hidden')
81
+ scrollBarSize = getScrollBarSize()
82
+ }
83
+
84
+ const containerClassName = container.className
85
+
86
+ if (
87
+ locks.filter(
88
+ ({ options }) => options?.container === this.options?.container,
89
+ ).length === 0
90
+ ) {
91
+ cacheStyle.set(
92
+ container,
93
+ setStyle(
94
+ {
95
+ width:
96
+ scrollBarSize !== 0
97
+ ? `calc(100% - ${scrollBarSize}px)`
98
+ : undefined,
99
+ overflow: 'hidden',
100
+ overflowX: 'hidden',
101
+ overflowY: 'hidden',
102
+ },
103
+ { element: container },
104
+ ),
105
+ )
106
+ }
107
+
108
+ // https://github.com/ant-design/ant-design/issues/19729
109
+ if (!scrollingEffectClassNameReg.test(containerClassName)) {
110
+ const addClassName = `${containerClassName} ${scrollingEffectClassName}`
111
+ container.className = addClassName.trim()
112
+ }
113
+
114
+ locks = [...locks!, { target: this.lockTarget, options: this.options! }]
115
+ }
116
+
117
+ unLock = () => {
118
+ const findLock = locks.find(({ target }) => target === this.lockTarget)
119
+
120
+ locks = locks.filter(({ target }) => target !== this.lockTarget)
121
+
122
+ if (
123
+ !findLock
124
+ || locks.some(
125
+ ({ options }) => options?.container === findLock.options?.container,
126
+ )
127
+ )
128
+ return
129
+
130
+ // Remove Effect
131
+ const container = this.options?.container || document.body
132
+ const containerClassName = container.className
133
+
134
+ if (!scrollingEffectClassNameReg.test(containerClassName))
135
+ return
136
+
137
+ setStyle(cacheStyle.get(container)!, { element: container })
138
+ cacheStyle.delete(container)
139
+ container.className = container.className
140
+ .replace(scrollingEffectClassNameReg, '')
141
+ .trim()
142
+ }
143
+ }
@@ -0,0 +1,17 @@
1
+ function getRoot(ele: Node) {
2
+ return ele?.getRootNode?.()
3
+ }
4
+
5
+ /**
6
+ * Check if is in shadowRoot
7
+ */
8
+ export function inShadow(ele: Node) {
9
+ return getRoot(ele) instanceof ShadowRoot
10
+ }
11
+
12
+ /**
13
+ * Return shadowRoot if possible
14
+ */
15
+ export function getShadowRoot(ele: Node): ShadowRoot | null {
16
+ return inShadow(ele) ? (getRoot(ele) as ShadowRoot) : null
17
+ }
@@ -0,0 +1,31 @@
1
+ import canUseDom from './canUseDom'
2
+
3
+ function isStyleNameSupport(styleName: string | string[]): boolean {
4
+ if (canUseDom() && window.document.documentElement) {
5
+ const styleNameList = Array.isArray(styleName) ? styleName : [styleName]
6
+ const { documentElement } = window.document
7
+
8
+ return styleNameList.some(name => name in documentElement.style)
9
+ }
10
+ return false
11
+ }
12
+
13
+ function isStyleValueSupport(styleName: string, value: any) {
14
+ if (!isStyleNameSupport(styleName))
15
+ return false
16
+
17
+ const ele: any = document.createElement('div')
18
+ const origin = ele.style[styleName]
19
+ ele.style[styleName] = value
20
+ return ele.style[styleName] !== origin
21
+ }
22
+
23
+ export function isStyleSupport(styleName: string | string[]): boolean
24
+ export function isStyleSupport(styleName: string, styleValue: any): boolean
25
+
26
+ export function isStyleSupport(styleName: string | string[], styleValue?: any) {
27
+ if (!Array.isArray(styleName) && styleValue !== undefined)
28
+ return isStyleValueSupport(styleName, styleValue)
29
+
30
+ return isStyleNameSupport(styleName)
31
+ }
@@ -0,0 +1,27 @@
1
+ import canUseDOM from './canUseDom'
2
+
3
+ const animationEndEventNames = {
4
+ WebkitAnimation: 'webkitAnimationEnd',
5
+ OAnimation: 'oAnimationEnd',
6
+ animation: 'animationend',
7
+ }
8
+ const transitionEventNames = {
9
+ WebkitTransition: 'webkitTransitionEnd',
10
+ OTransition: 'oTransitionEnd',
11
+ transition: 'transitionend',
12
+ }
13
+
14
+ function supportEnd(names: Record<string, any>) {
15
+ const el: any = document.createElement('div')
16
+ for (const name in names) {
17
+ if (names.hasOwnProperty(name) && el.style[name] !== undefined) {
18
+ return {
19
+ end: names[name],
20
+ }
21
+ }
22
+ }
23
+ return false
24
+ }
25
+
26
+ export const animation = canUseDOM() && supportEnd(animationEndEventNames)
27
+ export const transition = canUseDOM() && supportEnd(transitionEventNames)
@@ -0,0 +1,19 @@
1
+ export type FocusEventHandler = (e: FocusEvent) => void
2
+ export type MouseEventHandler = (e: MouseEvent) => void
3
+ export type KeyboardEventHandler = (e: KeyboardEvent) => void
4
+ export type CompositionEventHandler = (e: CompositionEvent) => void
5
+ export type ClipboardEventHandler = (e: ClipboardEvent) => void
6
+ export type ChangeEventHandler = (e: ChangeEvent) => void
7
+ export type WheelEventHandler = (e: WheelEvent) => void
8
+ export type ChangeEvent = Event & {
9
+ target: {
10
+ value?: string | undefined
11
+ }
12
+ }
13
+ export type CheckboxChangeEvent = Event & {
14
+ target: {
15
+ checked?: boolean
16
+ }
17
+ }
18
+
19
+ export type EventHandler = (...args: any[]) => void