@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
@@ -0,0 +1,214 @@
1
+ import type { SlotsType } from 'vue'
2
+ import { defineComponent, onBeforeUnmount, onMounted, onUpdated, shallowRef } from 'vue'
3
+ import raf from './raf'
4
+ import canUseDom from './Dom/canUseDom'
5
+ import ScrollLocker from './Dom/scrollLocker'
6
+ import setStyle from './setStyle'
7
+ import type { PortalRef } from './Portal'
8
+ import Portal from './Portal'
9
+
10
+ // import raf from './raf';
11
+
12
+ let openCount = 0
13
+ const supportDom = canUseDom()
14
+
15
+ /**
16
+ * @private
17
+ */
18
+ export function getOpenCount() {
19
+ return process.env.NODE_ENV === 'test' ? openCount : 0
20
+ }
21
+
22
+ // https://github.com/ant-design/ant-design/issues/19340
23
+ // https://github.com/ant-design/ant-design/issues/19332
24
+ let cacheOverflow = {}
25
+
26
+ function getParent(getContainer: GetContainer) {
27
+ if (!supportDom)
28
+ return null
29
+
30
+ if (getContainer) {
31
+ if (typeof getContainer === 'string')
32
+ return document.querySelectorAll(getContainer)[0]
33
+
34
+ if (typeof getContainer === 'function')
35
+ return getContainer()
36
+
37
+ if (
38
+ typeof getContainer === 'object'
39
+ && getContainer instanceof window.HTMLElement
40
+ )
41
+ return getContainer
42
+ }
43
+ return document.body
44
+ }
45
+
46
+ export type GetContainer = string | HTMLElement | (() => HTMLElement)
47
+
48
+ export type DefaultSlotInfo = SlotsType<{
49
+ default: {
50
+ getOpenCount: () => number
51
+ getContainer: () => HTMLElement
52
+ switchScrollingEffect: () => void
53
+ scrollLocker: ScrollLocker
54
+ }
55
+ }>
56
+
57
+ export interface PortalWrapperProps {
58
+ visible?: boolean
59
+ getContainer?: GetContainer
60
+ wrapperClassName?: string
61
+ forceRender?: boolean
62
+ }
63
+
64
+ const PortalWrapper = defineComponent<PortalWrapperProps, any, string, DefaultSlotInfo>((props, ctx) => {
65
+ const container = shallowRef<HTMLElement>()
66
+ const componentRef = shallowRef<PortalRef>()
67
+ const rafId = shallowRef<number>()
68
+ const scrollLocker = shallowRef<ScrollLocker>()
69
+
70
+ const removeCurrentContainer = () => {
71
+ // Portal will remove from `parentNode`.
72
+ // Let's handle this again to avoid refactor issue.
73
+ container.value?.parentNode?.removeChild(container.value)
74
+ }
75
+
76
+ const updateOpenCount = (prevProps?: Partial<PortalWrapperProps>) => {
77
+ const { visible: prevVisible, getContainer: prevGetContainer }
78
+ = prevProps || {}
79
+ const { visible, getContainer } = props
80
+
81
+ // Update count
82
+ if (
83
+ visible !== prevVisible
84
+ && supportDom
85
+ && getParent(getContainer!) === document.body
86
+ ) {
87
+ if (visible && !prevVisible)
88
+ openCount += 1
89
+ else if (prevProps)
90
+ openCount -= 1
91
+ }
92
+
93
+ // Clean up container if needed
94
+ const getContainerIsFunc
95
+ = typeof getContainer === 'function'
96
+ && typeof prevGetContainer === 'function'
97
+ if (
98
+ getContainerIsFunc
99
+ ? getContainer.toString() !== prevGetContainer.toString()
100
+ : getContainer !== prevGetContainer
101
+ )
102
+ removeCurrentContainer()
103
+ }
104
+
105
+ const attachToParent = (force = false) => {
106
+ if (force || (container.value && !container.value.parentNode)) {
107
+ const parent = getParent(props.getContainer!)
108
+ if (parent) {
109
+ parent.appendChild(container.value!)
110
+ return true
111
+ }
112
+
113
+ return false
114
+ }
115
+
116
+ return true
117
+ }
118
+ const setWrapperClassName = () => {
119
+ const { wrapperClassName } = props
120
+ if (
121
+ container.value
122
+ && wrapperClassName
123
+ && wrapperClassName !== container.value.className
124
+ )
125
+ container.value.className = wrapperClassName
126
+ }
127
+
128
+ const getContainer = () => {
129
+ if (!supportDom)
130
+ return null
131
+
132
+ if (!container.value) {
133
+ container.value = document.createElement('div')
134
+ attachToParent(true)
135
+ }
136
+ setWrapperClassName()
137
+ return container.value
138
+ }
139
+
140
+ onMounted(() => {
141
+ scrollLocker.value = new ScrollLocker({
142
+ container: getParent(props.getContainer!) as HTMLElement,
143
+ })
144
+ updateOpenCount()
145
+ if (!attachToParent()) {
146
+ rafId.value = raf(() => {
147
+ // 对组件执行强制更新 forceUpdate,准备采用改变key的方式来实现
148
+ })
149
+ }
150
+ })
151
+
152
+ onUpdated(() => {
153
+ updateOpenCount(props)
154
+ updateOpenCount(props)
155
+ setWrapperClassName()
156
+ attachToParent()
157
+ })
158
+
159
+ onBeforeUnmount(() => {
160
+ const { visible, getContainer } = props
161
+ if (supportDom && getParent(getContainer!) === document.body) {
162
+ // 离开时不会 render, 导到离开时数值不变,改用 func 。。
163
+ openCount = visible && openCount ? openCount - 1 : openCount
164
+ }
165
+ removeCurrentContainer()
166
+ raf.cancel(rafId.value!)
167
+ })
168
+
169
+ /**
170
+ * Enhance ./switchScrollingEffect
171
+ * 1. Simulate document body scroll bar with
172
+ * 2. Record body has overflow style and recover when all of PortalWrapper invisible
173
+ * 3. Disable body scroll when PortalWrapper has open
174
+ *
175
+ * @memberof PortalWrapper
176
+ */
177
+ const switchScrollingEffect = () => {
178
+ if (openCount === 1 && !Object.keys(cacheOverflow).length) {
179
+ switchScrollingEffect()
180
+ // Must be set after switchScrollingEffect
181
+ cacheOverflow = setStyle({
182
+ overflow: 'hidden',
183
+ overflowX: 'hidden',
184
+ overflowY: 'hidden',
185
+ })
186
+ }
187
+ else if (!openCount) {
188
+ setStyle(cacheOverflow)
189
+ cacheOverflow = {}
190
+ switchScrollingEffect()
191
+ }
192
+ }
193
+ return () => {
194
+ const { forceRender, visible } = props
195
+ let portal = null
196
+ const childProps = {
197
+ getOpenCount,
198
+ getContainer,
199
+ switchScrollingEffect,
200
+ scrollLocker: scrollLocker.value,
201
+ }
202
+ if (forceRender || visible || componentRef.value) {
203
+ portal = (
204
+ <Portal getContainer={getContainer as any} ref={componentRef}>
205
+ {ctx?.slots?.default(childProps as any)}
206
+ </Portal>
207
+ )
208
+ }
209
+ return portal
210
+ }
211
+ // TODO
212
+ })
213
+
214
+ export default PortalWrapper
@@ -0,0 +1,23 @@
1
+ function composeProps<T extends Record<string, any>>(
2
+ originProps: T,
3
+ patchProps: Partial<T>,
4
+ isAll?: boolean,
5
+ ) {
6
+ const composedProps: Record<string, any> = {
7
+ ...originProps,
8
+ ...(isAll ? patchProps : {}),
9
+ }
10
+
11
+ Object.keys(patchProps).forEach((key) => {
12
+ const func = patchProps[key]
13
+ if (typeof func === 'function') {
14
+ composedProps[key] = (...args: any[]) => {
15
+ func(...args)
16
+ return originProps[key]?.(...args)
17
+ }
18
+ }
19
+ })
20
+ return composedProps
21
+ }
22
+
23
+ export default composeProps
@@ -0,0 +1,33 @@
1
+ import type { Ref } from 'vue'
2
+
3
+ // eslint-disable-next-line ts/no-unsafe-function-type
4
+ export interface RefObject extends Function {
5
+ current?: any
6
+ }
7
+
8
+ function createRef(): any {
9
+ const func: RefObject = (node: any) => {
10
+ func.current = node
11
+ }
12
+ return func
13
+ }
14
+
15
+ export function fillRef<T>(ref: Ref, node: T) {
16
+ if (typeof ref === 'function')
17
+ (ref as any)(node)
18
+ else if (typeof ref === 'object' && ref && 'current' in ref)
19
+ (ref as any).current = node
20
+ }
21
+
22
+ /**
23
+ * Merge refs into one ref function to support ref passing.
24
+ */
25
+ export function composeRef<T>(...refs: any[]) {
26
+ return (node: T) => {
27
+ refs.forEach((ref) => {
28
+ fillRef(ref, node)
29
+ })
30
+ }
31
+ }
32
+
33
+ export default createRef
@@ -0,0 +1,66 @@
1
+ // eslint-disable-next-line ts/ban-ts-comment
2
+ // @ts-nocheck
3
+ function createArray() {
4
+ const arr: any[] = []
5
+ // eslint-disable-next-line no-proto,no-restricted-properties
6
+ arr.__proto__ = []
7
+ // eslint-disable-next-line no-proto,no-restricted-properties
8
+ arr.__proto__.format = function toString() {
9
+ return this.map(obj => ({
10
+ ...obj,
11
+ path: obj.path.join(' > '),
12
+ }))
13
+ }
14
+ // eslint-disable-next-line no-proto,no-restricted-properties
15
+ arr.__proto__.toString = function toString() {
16
+ return JSON.stringify(this.format(), null, 2)
17
+ }
18
+ return arr
19
+ }
20
+
21
+ export default function diff(obj1, obj2, depth = 10, path = [], diffList = createArray()) {
22
+ if (depth <= 0)
23
+ return diffList
24
+
25
+ const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)])
26
+ keys.forEach((key) => {
27
+ const value1 = obj1[key]
28
+ const value2 = obj2[key]
29
+
30
+ // Same value
31
+ if (value1 === value2)
32
+ return
33
+
34
+ const type1 = typeof value1
35
+ const type2 = typeof value2
36
+
37
+ // Diff type
38
+ if (type1 !== type2) {
39
+ diffList.push({
40
+ path: path.concat(key),
41
+ value1,
42
+ value2,
43
+ })
44
+ return
45
+ }
46
+
47
+ // NaN
48
+ if (Number.isNaN(value1) && Number.isNaN(value2))
49
+ return
50
+
51
+ // Object & Array
52
+ if (type1 === 'object' && value1 !== null && value2 !== null) {
53
+ diff(value1, value2, depth - 1, path.concat(key), diffList)
54
+ return
55
+ }
56
+
57
+ // Rest
58
+ diffList.push({
59
+ path: path.concat(key),
60
+ value1,
61
+ value2,
62
+ })
63
+ })
64
+
65
+ return diffList
66
+ }
@@ -0,0 +1,8 @@
1
+ export default function deprecated(props: any, instead: any, component: any) {
2
+ if (typeof window !== 'undefined' && window.console && window.console.error) {
3
+ window.console.error(
4
+ `Warning: ${props} is deprecated at [ ${component} ], `
5
+ + `use [ ${instead} ] instead of it.`,
6
+ )
7
+ }
8
+ }
@@ -0,0 +1,57 @@
1
+ let cached: number
2
+
3
+ export default function getScrollBarSize(fresh?: boolean) {
4
+ if (typeof document === 'undefined')
5
+ return 0
6
+
7
+ if (fresh || cached === undefined) {
8
+ const inner = document.createElement('div')
9
+ inner.style.width = '100%'
10
+ inner.style.height = '200px'
11
+
12
+ const outer = document.createElement('div')
13
+ const outerStyle = outer.style
14
+
15
+ outerStyle.position = 'absolute'
16
+ outerStyle.top = '0'
17
+ outerStyle.left = '0'
18
+ outerStyle.pointerEvents = 'none'
19
+ outerStyle.visibility = 'hidden'
20
+ outerStyle.width = '200px'
21
+ outerStyle.height = '150px'
22
+ outerStyle.overflow = 'hidden'
23
+
24
+ outer.appendChild(inner)
25
+
26
+ document.body.appendChild(outer)
27
+
28
+ const widthContained = inner.offsetWidth
29
+ outer.style.overflow = 'scroll'
30
+ let widthScroll = inner.offsetWidth
31
+
32
+ if (widthContained === widthScroll)
33
+ widthScroll = outer.clientWidth
34
+
35
+ document.body.removeChild(outer)
36
+
37
+ cached = widthContained - widthScroll
38
+ }
39
+ return cached
40
+ }
41
+
42
+ function ensureSize(str: string) {
43
+ const match = str.match(/^(.*)px$/)
44
+ const value = Number(match?.[1])
45
+ return Number.isNaN(value) ? getScrollBarSize() : value
46
+ }
47
+
48
+ export function getTargetScrollBarSize(target: HTMLElement) {
49
+ if (typeof document === 'undefined' || !target || !(target instanceof Element))
50
+ return { width: 0, height: 0 }
51
+
52
+ const { width, height } = getComputedStyle(target, '::-webkit-scrollbar')
53
+ return {
54
+ width: ensureSize(width),
55
+ height: ensureSize(height),
56
+ }
57
+ }
package/src/guid.ts ADDED
@@ -0,0 +1,4 @@
1
+ let seed = 0
2
+ export default function guid() {
3
+ return `${Date.now()}_${seed++}`
4
+ }
@@ -0,0 +1,31 @@
1
+ import { ref } from 'vue'
2
+ import canUseDom from '../Dom/canUseDom'
3
+
4
+ let uuid = 0
5
+
6
+ /** Is client side and not jsdom */
7
+ export const isBrowserClient = process.env.NODE_ENV !== 'test' && canUseDom()
8
+
9
+ /** Get unique id for accessibility usage */
10
+ export function getUUID(): number | string {
11
+ let retId: string | number
12
+
13
+ // Test never reach
14
+ /* istanbul ignore if */
15
+ if (isBrowserClient) {
16
+ retId = uuid
17
+ uuid += 1
18
+ }
19
+ else {
20
+ retId = 'TEST_OR_SSR'
21
+ }
22
+
23
+ return retId
24
+ }
25
+
26
+ export default function useId(id = ref('')) {
27
+ // Inner id for accessibility usage. Only work in client side
28
+ const innerId = `vc_unique_${getUUID()}`
29
+
30
+ return id.value || innerId
31
+ }
@@ -0,0 +1,21 @@
1
+ import type { Ref, WatchSource } from 'vue'
2
+ import { ref, watch } from 'vue'
3
+
4
+ export default function useMemo<T>(
5
+ getValue: () => T,
6
+ condition: (WatchSource<unknown> | object)[],
7
+ shouldUpdate?: (prev: any[], next: any[]) => boolean,
8
+ ) {
9
+ const cacheRef: Ref<T> = ref(getValue() as any)
10
+ watch(condition, (next, pre) => {
11
+ if (shouldUpdate) {
12
+ if (shouldUpdate(next, pre))
13
+ cacheRef.value = getValue()
14
+ }
15
+ else {
16
+ cacheRef.value = getValue()
17
+ }
18
+ })
19
+
20
+ return cacheRef
21
+ }
@@ -0,0 +1,44 @@
1
+ import type { ComputedRef, Ref, UnwrapRef } from 'vue'
2
+ import { ref, toRaw, unref, watch, watchEffect } from 'vue'
3
+
4
+ export default function useMergedState<T, R = Ref<T>>(
5
+ defaultStateValue: T | (() => T),
6
+ option?: {
7
+ defaultValue?: T | (() => T)
8
+ value?: Ref<T> | Ref<UnwrapRef<T>> | ComputedRef<T>
9
+ onChange?: (val: T, prevValue: T) => void
10
+ postState?: (val: T) => T
11
+ },
12
+ ): [R, (val: T) => void] {
13
+ const { defaultValue, value = ref() } = option || {}
14
+ let initValue: T
15
+ = typeof defaultStateValue === 'function' ? (defaultStateValue as any)() : defaultStateValue
16
+ if (value.value !== undefined)
17
+ initValue = unref(value as any) as T
18
+
19
+ if (defaultValue !== undefined)
20
+ initValue = typeof defaultValue === 'function' ? (defaultValue as any)() : defaultValue
21
+
22
+ const innerValue = ref(initValue) as Ref<T>
23
+ const mergedValue = ref(initValue) as Ref<T>
24
+ watchEffect(() => {
25
+ let val = value.value !== undefined ? value.value : innerValue.value
26
+ if (option?.postState)
27
+ val = option.postState(val as T)
28
+ mergedValue.value = val as T
29
+ })
30
+
31
+ function triggerChange(newValue: T) {
32
+ const preVal = mergedValue.value
33
+ innerValue.value = newValue
34
+ if (toRaw(mergedValue.value) !== newValue && option?.onChange)
35
+ option.onChange(newValue, preVal)
36
+ }
37
+
38
+ // Effect of reset value to `undefined`
39
+ watch(value, () => {
40
+ innerValue.value = value.value as T
41
+ })
42
+
43
+ return [mergedValue as unknown as R, triggerChange]
44
+ }
@@ -0,0 +1,17 @@
1
+ import type { Ref } from 'vue'
2
+ import { ref } from 'vue'
3
+
4
+ export default function useState<T, R = Ref<T>>(
5
+ defaultStateValue?: T | (() => T),
6
+ ): [R, (val: T) => void] {
7
+ const initValue: T
8
+ = typeof defaultStateValue === 'function' ? (defaultStateValue as any)() : defaultStateValue
9
+
10
+ const innerValue = ref(initValue) as Ref<T>
11
+
12
+ function triggerChange(newValue: T) {
13
+ innerValue.value = newValue
14
+ }
15
+
16
+ return [innerValue as unknown as R, triggerChange]
17
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { default as get } from './utils/get'
2
+ export { default as set } from './utils/set'
3
+ export { default as warning } from './warning'
package/src/isEqual.ts ADDED
@@ -0,0 +1,50 @@
1
+ import warning from './warning'
2
+
3
+ /**
4
+ * Deeply compares two object literals.
5
+ * @param obj1 object 1
6
+ * @param obj2 object 2
7
+ * @param shallow shallow compare
8
+ */
9
+ function isEqual(obj1: any, obj2: any, shallow = false): boolean {
10
+ // https://github.com/mapbox/mapbox-gl-js/pull/5979/files#diff-fde7145050c47cc3a306856efd5f9c3016e86e859de9afbd02c879be5067e58f
11
+ const refSet = new Set<any>()
12
+ function deepEqual(a: any, b: any, level = 1): boolean {
13
+ const circular = refSet.has(a)
14
+ warning(!circular, 'Warning: There may be circular references')
15
+ if (circular)
16
+ return false
17
+
18
+ if (a === b)
19
+ return true
20
+
21
+ if (shallow && level > 1)
22
+ return false
23
+
24
+ refSet.add(a)
25
+ const newLevel = level + 1
26
+ if (Array.isArray(a)) {
27
+ if (!Array.isArray(b) || a.length !== b.length)
28
+ return false
29
+
30
+ for (let i = 0; i < a.length; i++) {
31
+ if (!deepEqual(a[i], b[i], newLevel))
32
+ return false
33
+ }
34
+ return true
35
+ }
36
+ if (a && b && typeof a === 'object' && typeof b === 'object') {
37
+ const keys = Object.keys(a)
38
+ if (keys.length !== Object.keys(b).length)
39
+ return false
40
+
41
+ return keys.every(key => deepEqual(a[key], b[key], newLevel))
42
+ }
43
+ // other
44
+ return false
45
+ }
46
+
47
+ return deepEqual(obj1, obj2)
48
+ }
49
+
50
+ export default isEqual
@@ -0,0 +1,15 @@
1
+ export default () => {
2
+ if (typeof navigator === 'undefined' || typeof window === 'undefined')
3
+ return false
4
+
5
+ const agent
6
+ = navigator.userAgent || navigator.vendor || (window as any).opera
7
+ return (
8
+ /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(
9
+ agent,
10
+ )
11
+ || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(
12
+ agent?.substr(0, 4),
13
+ )
14
+ )
15
+ }
package/src/omit.ts ADDED
@@ -0,0 +1,14 @@
1
+ export default function omit<T extends object, K extends keyof T>(
2
+ obj: T,
3
+ fields: K[] | readonly K[],
4
+ ): Omit<T, K> {
5
+ const clone = { ...obj }
6
+
7
+ if (Array.isArray(fields)) {
8
+ fields.forEach((key) => {
9
+ delete clone[key]
10
+ })
11
+ }
12
+
13
+ return clone
14
+ }
@@ -0,0 +1,78 @@
1
+ const attributes = `accept acceptCharset accessKey action allowFullScreen allowTransparency
2
+ alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
3
+ charSet checked classID className colSpan cols content contentEditable contextMenu
4
+ controls coords crossOrigin data dateTime default defer dir disabled download draggable
5
+ encType form formAction formEncType formMethod formNoValidate formTarget frameBorder
6
+ headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity
7
+ is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media
8
+ mediaGroup method min minLength multiple muted name noValidate nonce open
9
+ optimum pattern placeholder poster preload radioGroup readOnly rel required
10
+ reversed role rowSpan rows sandbox scope scoped scrolling seamless selected
11
+ shape size sizes span spellCheck src srcDoc srcLang srcSet start step style
12
+ summary tabIndex target title type useMap value width wmode wrap`
13
+
14
+ const eventsName = `onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown
15
+ onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick
16
+ onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown
17
+ onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel
18
+ onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough
19
+ onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata
20
+ onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError`
21
+
22
+ const propList = `${attributes} ${eventsName}`.split(/[\s\n]+/)
23
+
24
+ const ariaPrefix = 'aria-'
25
+ const dataPrefix = 'data-'
26
+
27
+ function match(key: string, prefix: string) {
28
+ return key.indexOf(prefix) === 0
29
+ }
30
+
31
+ export interface PickConfig {
32
+ aria?: boolean
33
+ data?: boolean
34
+ attr?: boolean
35
+ }
36
+
37
+ /**
38
+ * Picker props from exist props with filter
39
+ * @param props Passed props
40
+ * @param ariaOnly boolean | { aria?: boolean; data?: boolean; attr?: boolean; } filter config
41
+ */
42
+ export default function pickAttrs(
43
+ props: object,
44
+ ariaOnly: boolean | PickConfig = false,
45
+ ) {
46
+ let mergedConfig: PickConfig
47
+ if (ariaOnly === false) {
48
+ mergedConfig = {
49
+ aria: true,
50
+ data: true,
51
+ attr: true,
52
+ }
53
+ }
54
+ else if (ariaOnly === true) {
55
+ mergedConfig = {
56
+ aria: true,
57
+ }
58
+ }
59
+ else {
60
+ mergedConfig = {
61
+ ...ariaOnly,
62
+ }
63
+ }
64
+
65
+ const attrs: Record<string, any> = {}
66
+ Object.keys(props).forEach((key) => {
67
+ if (
68
+ // Aria
69
+ (mergedConfig.aria && (key === 'role' || match(key, ariaPrefix)))
70
+ // Data
71
+ || (mergedConfig.data && match(key, dataPrefix))
72
+ // Attr
73
+ || (mergedConfig.attr && propList.includes(key))
74
+ )
75
+ attrs[key] = (props as any)[key]
76
+ })
77
+ return attrs
78
+ }