@formily-design/shared 1.0.0
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.
- package/LICENSE.md +20 -0
- package/README.md +1 -0
- package/dist/designable.shared.umd.production.js +1 -0
- package/dist/designable.shared.umd.production.min.js +2051 -0
- package/esm/animation.d.ts +2 -0
- package/esm/animation.js +33 -0
- package/esm/array.d.ts +37 -0
- package/esm/array.js +111 -0
- package/esm/clone.d.ts +4 -0
- package/esm/clone.js +97 -0
- package/esm/compose.d.ts +1 -0
- package/esm/compose.js +7 -0
- package/esm/coordinate.d.ts +106 -0
- package/esm/coordinate.js +475 -0
- package/esm/element.d.ts +6 -0
- package/esm/element.js +137 -0
- package/esm/event.d.ts +96 -0
- package/esm/event.js +213 -0
- package/esm/globalThisPolyfill.d.ts +1 -0
- package/esm/globalThisPolyfill.js +22 -0
- package/esm/index.d.ts +17 -0
- package/esm/index.js +17 -0
- package/esm/instanceof.d.ts +1 -0
- package/esm/instanceof.js +11 -0
- package/esm/keycode.d.ts +147 -0
- package/esm/keycode.js +150 -0
- package/esm/lru.d.ts +73 -0
- package/esm/lru.js +293 -0
- package/esm/observer.d.ts +9 -0
- package/esm/observer.js +29 -0
- package/esm/request-idle.d.ts +10 -0
- package/esm/request-idle.js +8 -0
- package/esm/scroller.d.ts +10 -0
- package/esm/scroller.js +82 -0
- package/esm/subscribable.d.ts +14 -0
- package/esm/subscribable.js +48 -0
- package/esm/types.d.ts +13 -0
- package/esm/types.js +21 -0
- package/esm/uid.d.ts +1 -0
- package/esm/uid.js +9 -0
- package/lib/animation.d.ts +2 -0
- package/lib/animation.js +38 -0
- package/lib/array.d.ts +37 -0
- package/lib/array.js +125 -0
- package/lib/clone.d.ts +4 -0
- package/lib/clone.js +102 -0
- package/lib/compose.d.ts +1 -0
- package/lib/compose.js +11 -0
- package/lib/coordinate.d.ts +106 -0
- package/lib/coordinate.js +504 -0
- package/lib/element.d.ts +6 -0
- package/lib/element.js +145 -0
- package/lib/event.d.ts +96 -0
- package/lib/event.js +218 -0
- package/lib/globalThisPolyfill.d.ts +1 -0
- package/lib/globalThisPolyfill.js +25 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.js +33 -0
- package/lib/instanceof.d.ts +1 -0
- package/lib/instanceof.js +15 -0
- package/lib/keycode.d.ts +147 -0
- package/lib/keycode.js +154 -0
- package/lib/lru.d.ts +73 -0
- package/lib/lru.js +297 -0
- package/lib/observer.d.ts +9 -0
- package/lib/observer.js +33 -0
- package/lib/request-idle.d.ts +10 -0
- package/lib/request-idle.js +13 -0
- package/lib/scroller.d.ts +10 -0
- package/lib/scroller.js +88 -0
- package/lib/subscribable.d.ts +14 -0
- package/lib/subscribable.js +52 -0
- package/lib/types.d.ts +13 -0
- package/lib/types.js +29 -0
- package/lib/uid.d.ts +1 -0
- package/lib/uid.js +12 -0
- package/package.json +32 -0
- package/rollup.config.js +3 -0
- package/src/animation.ts +38 -0
- package/src/array.ts +301 -0
- package/src/clone.ts +96 -0
- package/src/compose.ts +7 -0
- package/src/coordinate.ts +633 -0
- package/src/element.ts +144 -0
- package/src/event.ts +379 -0
- package/src/globalThisPolyfill.ts +19 -0
- package/src/index.ts +17 -0
- package/src/instanceof.ts +10 -0
- package/src/keycode.ts +150 -0
- package/src/lru.ts +322 -0
- package/src/observer.ts +38 -0
- package/src/request-idle.ts +22 -0
- package/src/scroller.ts +113 -0
- package/src/subscribable.ts +60 -0
- package/src/types.ts +27 -0
- package/src/uid.ts +10 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +5 -0
package/src/element.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Point } from './coordinate'
|
|
2
|
+
|
|
3
|
+
const InlineLayoutTagNames = new Set([
|
|
4
|
+
'A',
|
|
5
|
+
'ABBR',
|
|
6
|
+
'ACRONYM',
|
|
7
|
+
'AUDIO',
|
|
8
|
+
'B',
|
|
9
|
+
'BDI',
|
|
10
|
+
'BDO',
|
|
11
|
+
'BIG',
|
|
12
|
+
'BR',
|
|
13
|
+
'BUTTON',
|
|
14
|
+
'CANVAS',
|
|
15
|
+
'CITE',
|
|
16
|
+
'CODE',
|
|
17
|
+
'DATA',
|
|
18
|
+
'DATALIST',
|
|
19
|
+
'DEL',
|
|
20
|
+
'DFN',
|
|
21
|
+
'EM',
|
|
22
|
+
'EMBED',
|
|
23
|
+
'I',
|
|
24
|
+
'IFRAME',
|
|
25
|
+
'IMG',
|
|
26
|
+
'INS',
|
|
27
|
+
'KBD',
|
|
28
|
+
'LABEL',
|
|
29
|
+
'MAP',
|
|
30
|
+
'MARK',
|
|
31
|
+
'METER',
|
|
32
|
+
'NOSCRIPT',
|
|
33
|
+
'OBJECT',
|
|
34
|
+
'OUTPUT',
|
|
35
|
+
'PICTURE',
|
|
36
|
+
'PROGRESS',
|
|
37
|
+
'Q',
|
|
38
|
+
'RUBY',
|
|
39
|
+
'S',
|
|
40
|
+
'SAMP',
|
|
41
|
+
'SELECT',
|
|
42
|
+
'SLOT',
|
|
43
|
+
'SMALL',
|
|
44
|
+
'STRONG',
|
|
45
|
+
'SUB',
|
|
46
|
+
'SUP',
|
|
47
|
+
'SVG',
|
|
48
|
+
'TEMPLATE',
|
|
49
|
+
'TEXTAREA',
|
|
50
|
+
'TIME',
|
|
51
|
+
'U',
|
|
52
|
+
'TT',
|
|
53
|
+
'VAR',
|
|
54
|
+
'VIDEO',
|
|
55
|
+
'WBR',
|
|
56
|
+
'INPUT',
|
|
57
|
+
'SPAN',
|
|
58
|
+
])
|
|
59
|
+
|
|
60
|
+
export const calcElementOuterWidth = (
|
|
61
|
+
innerWidth: number,
|
|
62
|
+
style: CSSStyleDeclaration
|
|
63
|
+
) => {
|
|
64
|
+
return (
|
|
65
|
+
innerWidth +
|
|
66
|
+
parseFloat(style.marginLeft) +
|
|
67
|
+
parseFloat(style.marginRight) +
|
|
68
|
+
parseFloat(style.paddingLeft) +
|
|
69
|
+
parseFloat(style.paddingRight) +
|
|
70
|
+
parseFloat(style.borderLeftWidth) +
|
|
71
|
+
parseFloat(style.borderRightWidth)
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const calcElementLayout = (element: Element) => {
|
|
76
|
+
if (!element) return 'vertical'
|
|
77
|
+
const parent = element.parentElement
|
|
78
|
+
if (!parent) return 'vertical'
|
|
79
|
+
const tagName = element.tagName
|
|
80
|
+
const parentTagName = parent.tagName
|
|
81
|
+
const style = getComputedStyle(element)
|
|
82
|
+
const parentStyle = getComputedStyle(parent)
|
|
83
|
+
|
|
84
|
+
const isNotFullWidth = () => {
|
|
85
|
+
const innerWidth = element.getBoundingClientRect().width
|
|
86
|
+
const outerWidth = calcElementOuterWidth(innerWidth, style)
|
|
87
|
+
const parentInnerWidth = parent.getBoundingClientRect().width
|
|
88
|
+
return outerWidth.toFixed(0) < parentInnerWidth.toFixed(0)
|
|
89
|
+
}
|
|
90
|
+
if (tagName === 'TH' || tagName === 'TD') {
|
|
91
|
+
if (parentTagName === 'TR') return 'horizontal'
|
|
92
|
+
}
|
|
93
|
+
if (parentStyle.display === 'flex' && parentStyle.flexDirection === 'row')
|
|
94
|
+
return 'horizontal'
|
|
95
|
+
if (parentStyle.display === 'grid') {
|
|
96
|
+
if (isNotFullWidth()) {
|
|
97
|
+
return 'horizontal'
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (InlineLayoutTagNames.has(tagName)) {
|
|
101
|
+
if (style.display === 'block') {
|
|
102
|
+
if (style.float === 'left' || style.float === 'right') {
|
|
103
|
+
if (isNotFullWidth()) {
|
|
104
|
+
return 'horizontal'
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return 'vertical'
|
|
108
|
+
}
|
|
109
|
+
return 'horizontal'
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const calcElementTranslate = (element: HTMLElement) => {
|
|
114
|
+
const transform = element?.style?.transform
|
|
115
|
+
if (transform) {
|
|
116
|
+
const [x, y] = transform
|
|
117
|
+
.match(
|
|
118
|
+
/translate(?:3d)?\(\s*([-\d.]+)[a-z]+?[\s,]+([-\d.]+)[a-z]+?(?:[\s,]+([-\d.]+))?[a-z]+?\s*\)/
|
|
119
|
+
)
|
|
120
|
+
?.slice(1, 3) ?? [0, 0]
|
|
121
|
+
|
|
122
|
+
return new Point(Number(x), Number(y))
|
|
123
|
+
} else {
|
|
124
|
+
return new Point(Number(element.offsetLeft), Number(element.offsetTop))
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export const calcElementRotate = (element: HTMLElement) => {
|
|
129
|
+
const transform = element?.style?.transform
|
|
130
|
+
if (transform) {
|
|
131
|
+
return Number(transform.match(/rotate\(\s*([-\d.]+)/)?.[1] ?? 0)
|
|
132
|
+
} else {
|
|
133
|
+
return 0
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const calcElementScale = (element: HTMLElement) => {
|
|
138
|
+
const transform = element?.style?.transform
|
|
139
|
+
if (transform) {
|
|
140
|
+
return Number(transform.match(/scale\(\s*([-\d.]+)/)?.[1] ?? 0)
|
|
141
|
+
} else {
|
|
142
|
+
return 0
|
|
143
|
+
}
|
|
144
|
+
}
|
package/src/event.ts
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { isArr, isWindow } from './types'
|
|
2
|
+
import { Subscribable, ISubscriber } from './subscribable'
|
|
3
|
+
import { globalThisPolyfill } from './globalThisPolyfill'
|
|
4
|
+
|
|
5
|
+
const ATTACHED_SYMBOL = Symbol('ATTACHED_SYMBOL')
|
|
6
|
+
const EVENTS_SYMBOL = Symbol('__EVENTS_SYMBOL__')
|
|
7
|
+
const EVENTS_ONCE_SYMBOL = Symbol('EVENTS_ONCE_SYMBOL')
|
|
8
|
+
const EVENTS_BATCH_SYMBOL = Symbol('EVENTS_BATCH_SYMBOL')
|
|
9
|
+
const DRIVER_INSTANCES_SYMBOL = Symbol('DRIVER_INSTANCES_SYMBOL')
|
|
10
|
+
|
|
11
|
+
export type EventOptions =
|
|
12
|
+
| boolean
|
|
13
|
+
| (AddEventListenerOptions &
|
|
14
|
+
EventListenerOptions & {
|
|
15
|
+
mode?: 'onlyOne' | 'onlyParent' | 'onlyChild'
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export type EventContainer = Window | HTMLElement | HTMLDocument
|
|
19
|
+
|
|
20
|
+
export type EventDriverContainer = HTMLElement | HTMLDocument
|
|
21
|
+
|
|
22
|
+
export interface IEventEffect<T> {
|
|
23
|
+
(engine: T): void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IEventDriver {
|
|
27
|
+
container: EventDriverContainer
|
|
28
|
+
contentWindow: Window
|
|
29
|
+
attach(container: EventDriverContainer): void
|
|
30
|
+
detach(container: EventDriverContainer): void
|
|
31
|
+
dispatch<T extends ICustomEvent<any> = any>(event: T): void | boolean
|
|
32
|
+
subscribe<T extends ICustomEvent<any> = any>(subscriber: ISubscriber<T>): void
|
|
33
|
+
addEventListener<K extends keyof HTMLElementEventMap>(
|
|
34
|
+
type: K,
|
|
35
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
36
|
+
options?: boolean | EventOptions
|
|
37
|
+
): void
|
|
38
|
+
addEventListener(
|
|
39
|
+
type: string,
|
|
40
|
+
listener: EventListenerOrEventListenerObject,
|
|
41
|
+
options?: boolean | EventOptions
|
|
42
|
+
): void
|
|
43
|
+
addEventListener(type: any, listener: any, options: any): void
|
|
44
|
+
removeEventListener<K extends keyof HTMLElementEventMap>(
|
|
45
|
+
type: K,
|
|
46
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
47
|
+
options?: boolean | EventOptions
|
|
48
|
+
): void
|
|
49
|
+
removeEventListener(
|
|
50
|
+
type: string,
|
|
51
|
+
listener: EventListenerOrEventListenerObject,
|
|
52
|
+
options?: boolean | EventOptions
|
|
53
|
+
): void
|
|
54
|
+
removeEventListener(type: any, listener: any, options?: any): void
|
|
55
|
+
batchAddEventListener<K extends keyof HTMLElementEventMap>(
|
|
56
|
+
type: K,
|
|
57
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
58
|
+
options?: boolean | EventOptions
|
|
59
|
+
): void
|
|
60
|
+
batchAddEventListener(
|
|
61
|
+
type: string,
|
|
62
|
+
listener: EventListenerOrEventListenerObject,
|
|
63
|
+
options?: boolean | EventOptions
|
|
64
|
+
): void
|
|
65
|
+
batchAddEventListener(type: any, listener: any, options?: any): void
|
|
66
|
+
batchRemoveEventListener<K extends keyof HTMLElementEventMap>(
|
|
67
|
+
type: K,
|
|
68
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
69
|
+
options?: boolean | EventOptions
|
|
70
|
+
): void
|
|
71
|
+
batchRemoveEventListener(
|
|
72
|
+
type: string,
|
|
73
|
+
listener: EventListenerOrEventListenerObject,
|
|
74
|
+
options?: boolean | EventOptions
|
|
75
|
+
): void
|
|
76
|
+
batchRemoveEventListener(type: any, listener: any, options: any): void
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface IEventDriverClass<T> {
|
|
80
|
+
new (engine: T, context?: any): IEventDriver
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface ICustomEvent<EventData = any, EventContext = any> {
|
|
84
|
+
type: string
|
|
85
|
+
data?: EventData
|
|
86
|
+
context?: EventContext
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface CustomEventClass {
|
|
90
|
+
new (...args: any[]): any
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface IEventProps<T = Event> {
|
|
94
|
+
drivers?: IEventDriverClass<T>[]
|
|
95
|
+
effects?: IEventEffect<T>[]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const isOnlyMode = (mode: string) =>
|
|
99
|
+
mode === 'onlyOne' || mode === 'onlyChild' || mode === 'onlyParent'
|
|
100
|
+
/**
|
|
101
|
+
* 事件驱动器基类
|
|
102
|
+
*/
|
|
103
|
+
export class EventDriver<Engine extends Event = Event, Context = any>
|
|
104
|
+
implements IEventDriver
|
|
105
|
+
{
|
|
106
|
+
engine: Engine
|
|
107
|
+
|
|
108
|
+
container: EventDriverContainer = document
|
|
109
|
+
|
|
110
|
+
contentWindow: Window = globalThisPolyfill
|
|
111
|
+
|
|
112
|
+
context: Context
|
|
113
|
+
|
|
114
|
+
constructor(engine: Engine, context?: Context) {
|
|
115
|
+
this.engine = engine
|
|
116
|
+
this.context = context
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
dispatch<T extends ICustomEvent<any> = any>(event: T) {
|
|
120
|
+
return this.engine.dispatch(event, this.context)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
subscribe<T extends ICustomEvent<any> = any>(subscriber: ISubscriber<T>) {
|
|
124
|
+
return this.engine.subscribe(subscriber)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
subscribeTo<T extends CustomEventClass>(
|
|
128
|
+
type: T,
|
|
129
|
+
subscriber: ISubscriber<InstanceType<T>>
|
|
130
|
+
) {
|
|
131
|
+
return this.engine.subscribeTo(type, subscriber)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
subscribeWith<T extends ICustomEvent = ICustomEvent>(
|
|
135
|
+
type: string | string[],
|
|
136
|
+
subscriber: ISubscriber<T>
|
|
137
|
+
) {
|
|
138
|
+
return this.engine.subscribeWith(type, subscriber)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
attach(container: EventDriverContainer) {
|
|
142
|
+
console.error('attach must implement.')
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
detach(container: EventDriverContainer) {
|
|
146
|
+
console.error('attach must implement.')
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
eventTarget(type: string) {
|
|
150
|
+
if (type === 'resize' || type === 'scroll') {
|
|
151
|
+
if (this.container === this.contentWindow?.document) {
|
|
152
|
+
return this.contentWindow
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return this.container
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
addEventListener<K extends keyof HTMLElementEventMap>(
|
|
159
|
+
type: K,
|
|
160
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
161
|
+
options?: boolean | EventOptions
|
|
162
|
+
): void
|
|
163
|
+
addEventListener(
|
|
164
|
+
type: string,
|
|
165
|
+
listener: EventListenerOrEventListenerObject,
|
|
166
|
+
options?: boolean | EventOptions
|
|
167
|
+
): void
|
|
168
|
+
addEventListener(type: any, listener: any, options: any) {
|
|
169
|
+
const target = this.eventTarget(type)
|
|
170
|
+
if (isOnlyMode(options?.mode)) {
|
|
171
|
+
target[EVENTS_ONCE_SYMBOL] = target[EVENTS_ONCE_SYMBOL] || {}
|
|
172
|
+
const constructor = this['constructor']
|
|
173
|
+
constructor[EVENTS_ONCE_SYMBOL] = constructor[EVENTS_ONCE_SYMBOL] || {}
|
|
174
|
+
const handler = target[EVENTS_ONCE_SYMBOL][type]
|
|
175
|
+
const container = constructor[EVENTS_ONCE_SYMBOL][type]
|
|
176
|
+
if (!handler) {
|
|
177
|
+
if (container) {
|
|
178
|
+
if (options.mode === 'onlyChild') {
|
|
179
|
+
if (container.contains(target)) {
|
|
180
|
+
container.removeEventListener(
|
|
181
|
+
type,
|
|
182
|
+
container[EVENTS_ONCE_SYMBOL][type],
|
|
183
|
+
options
|
|
184
|
+
)
|
|
185
|
+
delete container[EVENTS_ONCE_SYMBOL][type]
|
|
186
|
+
}
|
|
187
|
+
} else if (options.mode === 'onlyParent') {
|
|
188
|
+
if (container.contains(target)) return
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
target.addEventListener(type, listener, options)
|
|
192
|
+
target[EVENTS_ONCE_SYMBOL][type] = listener
|
|
193
|
+
constructor[EVENTS_ONCE_SYMBOL][type] = target
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
target[EVENTS_SYMBOL] = target[EVENTS_SYMBOL] || {}
|
|
197
|
+
target[EVENTS_SYMBOL][type] = target[EVENTS_SYMBOL][type] || new Map()
|
|
198
|
+
if (!target[EVENTS_SYMBOL][type]?.get?.(listener)) {
|
|
199
|
+
target.addEventListener(type, listener, options)
|
|
200
|
+
target[EVENTS_SYMBOL][type]?.set?.(listener, true)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
removeEventListener<K extends keyof HTMLElementEventMap>(
|
|
206
|
+
type: K,
|
|
207
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
208
|
+
options?: boolean | EventOptions
|
|
209
|
+
): void
|
|
210
|
+
removeEventListener(
|
|
211
|
+
type: string,
|
|
212
|
+
listener: EventListenerOrEventListenerObject,
|
|
213
|
+
options?: boolean | EventOptions
|
|
214
|
+
): void
|
|
215
|
+
removeEventListener(type: any, listener: any, options?: any) {
|
|
216
|
+
const target = this.eventTarget(type)
|
|
217
|
+
if (isOnlyMode(options?.mode)) {
|
|
218
|
+
const constructor = this['constructor']
|
|
219
|
+
constructor[EVENTS_ONCE_SYMBOL] = constructor[EVENTS_ONCE_SYMBOL] || {}
|
|
220
|
+
target[EVENTS_ONCE_SYMBOL] = target[EVENTS_ONCE_SYMBOL] || {}
|
|
221
|
+
delete constructor[EVENTS_ONCE_SYMBOL][type]
|
|
222
|
+
delete target[EVENTS_ONCE_SYMBOL][type]
|
|
223
|
+
target.removeEventListener(type, listener, options)
|
|
224
|
+
} else {
|
|
225
|
+
target[EVENTS_SYMBOL] = target[EVENTS_SYMBOL] || {}
|
|
226
|
+
target[EVENTS_SYMBOL][type] = target[EVENTS_SYMBOL][type] || new Map()
|
|
227
|
+
target[EVENTS_SYMBOL][type]?.delete?.(listener)
|
|
228
|
+
target.removeEventListener(type, listener, options)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
batchAddEventListener<K extends keyof HTMLElementEventMap>(
|
|
233
|
+
type: K,
|
|
234
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
235
|
+
options?: boolean | EventOptions
|
|
236
|
+
): void
|
|
237
|
+
batchAddEventListener(
|
|
238
|
+
type: string,
|
|
239
|
+
listener: EventListenerOrEventListenerObject,
|
|
240
|
+
options?: boolean | EventOptions
|
|
241
|
+
): void
|
|
242
|
+
batchAddEventListener(type: any, listener: any, options?: any) {
|
|
243
|
+
this.engine[DRIVER_INSTANCES_SYMBOL] =
|
|
244
|
+
this.engine[DRIVER_INSTANCES_SYMBOL] || []
|
|
245
|
+
if (!this.engine[DRIVER_INSTANCES_SYMBOL].includes(this)) {
|
|
246
|
+
this.engine[DRIVER_INSTANCES_SYMBOL].push(this)
|
|
247
|
+
}
|
|
248
|
+
this.engine[DRIVER_INSTANCES_SYMBOL].forEach((driver) => {
|
|
249
|
+
const target = driver.eventTarget(type)
|
|
250
|
+
target[EVENTS_BATCH_SYMBOL] = target[EVENTS_BATCH_SYMBOL] || {}
|
|
251
|
+
if (!target[EVENTS_BATCH_SYMBOL][type]) {
|
|
252
|
+
target.addEventListener(type, listener, options)
|
|
253
|
+
target[EVENTS_BATCH_SYMBOL][type] = listener
|
|
254
|
+
}
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
batchRemoveEventListener<K extends keyof HTMLElementEventMap>(
|
|
259
|
+
type: K,
|
|
260
|
+
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
|
261
|
+
options?: boolean | EventOptions
|
|
262
|
+
): void
|
|
263
|
+
batchRemoveEventListener(
|
|
264
|
+
type: string,
|
|
265
|
+
listener: EventListenerOrEventListenerObject,
|
|
266
|
+
options?: boolean | EventOptions
|
|
267
|
+
): void
|
|
268
|
+
batchRemoveEventListener(type: any, listener: any, options: any) {
|
|
269
|
+
this.engine[DRIVER_INSTANCES_SYMBOL] =
|
|
270
|
+
this.engine[DRIVER_INSTANCES_SYMBOL] || []
|
|
271
|
+
this.engine[DRIVER_INSTANCES_SYMBOL].forEach((driver) => {
|
|
272
|
+
const target = driver.eventTarget(type)
|
|
273
|
+
target[EVENTS_BATCH_SYMBOL] = target[EVENTS_BATCH_SYMBOL] || {}
|
|
274
|
+
target.removeEventListener(type, listener, options)
|
|
275
|
+
delete target[EVENTS_BATCH_SYMBOL][type]
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* 事件引擎
|
|
281
|
+
*/
|
|
282
|
+
export class Event extends Subscribable<ICustomEvent<any>> {
|
|
283
|
+
private drivers: IEventDriverClass<any>[] = []
|
|
284
|
+
private containers: EventContainer[] = []
|
|
285
|
+
constructor(props?: IEventProps) {
|
|
286
|
+
super()
|
|
287
|
+
if (isArr(props?.effects)) {
|
|
288
|
+
props.effects.forEach((plugin) => {
|
|
289
|
+
plugin(this)
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
if (isArr(props?.drivers)) {
|
|
293
|
+
this.drivers = props.drivers
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
subscribeTo<T extends CustomEventClass>(
|
|
298
|
+
type: T,
|
|
299
|
+
subscriber: ISubscriber<InstanceType<T>>
|
|
300
|
+
) {
|
|
301
|
+
return this.subscribe((event) => {
|
|
302
|
+
if (type && event instanceof type) {
|
|
303
|
+
return subscriber(event)
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
subscribeWith<T extends ICustomEvent = ICustomEvent>(
|
|
309
|
+
type: string | string[],
|
|
310
|
+
subscriber: ISubscriber<T>
|
|
311
|
+
) {
|
|
312
|
+
return this.subscribe((event) => {
|
|
313
|
+
if (isArr(type)) {
|
|
314
|
+
if (type.includes(event?.type)) {
|
|
315
|
+
return subscriber(event)
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
if (type && event?.type === type) {
|
|
319
|
+
return subscriber(event)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
attachEvents(
|
|
326
|
+
container: EventContainer,
|
|
327
|
+
contentWindow: Window = globalThisPolyfill,
|
|
328
|
+
context?: any
|
|
329
|
+
) {
|
|
330
|
+
if (!container) return
|
|
331
|
+
if (isWindow(container)) {
|
|
332
|
+
return this.attachEvents(container.document, container, context)
|
|
333
|
+
}
|
|
334
|
+
if (container[ATTACHED_SYMBOL]) return
|
|
335
|
+
container[ATTACHED_SYMBOL] = this.drivers.map((EventDriver) => {
|
|
336
|
+
const driver = new EventDriver(this, context)
|
|
337
|
+
driver.contentWindow = contentWindow
|
|
338
|
+
driver.container = container
|
|
339
|
+
driver.attach(container)
|
|
340
|
+
return driver
|
|
341
|
+
})
|
|
342
|
+
if (!this.containers.includes(container)) {
|
|
343
|
+
this.containers.push(container)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
detachEvents(container?: EventContainer) {
|
|
348
|
+
if (!container) {
|
|
349
|
+
this.containers.forEach((container) => {
|
|
350
|
+
this.detachEvents(container)
|
|
351
|
+
})
|
|
352
|
+
return
|
|
353
|
+
}
|
|
354
|
+
if (isWindow(container)) {
|
|
355
|
+
return this.detachEvents(container.document)
|
|
356
|
+
}
|
|
357
|
+
if (!container[ATTACHED_SYMBOL]) return
|
|
358
|
+
container[ATTACHED_SYMBOL].forEach((driver) => {
|
|
359
|
+
driver.detach(container)
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
this[DRIVER_INSTANCES_SYMBOL] = this[DRIVER_INSTANCES_SYMBOL] || []
|
|
363
|
+
this[DRIVER_INSTANCES_SYMBOL] = this[DRIVER_INSTANCES_SYMBOL].reduce(
|
|
364
|
+
(drivers, driver) => {
|
|
365
|
+
if (driver.container === container) {
|
|
366
|
+
driver.detach(container)
|
|
367
|
+
return drivers
|
|
368
|
+
}
|
|
369
|
+
return drivers.concat(driver)
|
|
370
|
+
},
|
|
371
|
+
[]
|
|
372
|
+
)
|
|
373
|
+
this.containers = this.containers.filter((item) => item !== container)
|
|
374
|
+
delete container[ATTACHED_SYMBOL]
|
|
375
|
+
delete container[EVENTS_SYMBOL]
|
|
376
|
+
delete container[EVENTS_ONCE_SYMBOL]
|
|
377
|
+
delete container[EVENTS_BATCH_SYMBOL]
|
|
378
|
+
}
|
|
379
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function getGlobalThis() {
|
|
2
|
+
try {
|
|
3
|
+
if (typeof self !== 'undefined') {
|
|
4
|
+
return self
|
|
5
|
+
}
|
|
6
|
+
} catch (e) {}
|
|
7
|
+
try {
|
|
8
|
+
if (typeof globalThisPolyfill !== 'undefined') {
|
|
9
|
+
return globalThisPolyfill
|
|
10
|
+
}
|
|
11
|
+
} catch (e) {}
|
|
12
|
+
try {
|
|
13
|
+
if (typeof global !== 'undefined') {
|
|
14
|
+
return global
|
|
15
|
+
}
|
|
16
|
+
} catch (e) {}
|
|
17
|
+
return Function('return this')()
|
|
18
|
+
}
|
|
19
|
+
export const globalThisPolyfill: Window = getGlobalThis()
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './event'
|
|
2
|
+
export * from './scroller'
|
|
3
|
+
export * from './subscribable'
|
|
4
|
+
export * from './coordinate'
|
|
5
|
+
export * from './types'
|
|
6
|
+
export * from './uid'
|
|
7
|
+
export * from './clone'
|
|
8
|
+
export * from './instanceof'
|
|
9
|
+
export * from './lru'
|
|
10
|
+
export * from './compose'
|
|
11
|
+
export * from './array'
|
|
12
|
+
export * from './keycode'
|
|
13
|
+
export * from './animation'
|
|
14
|
+
export * from './request-idle'
|
|
15
|
+
export * from './element'
|
|
16
|
+
export * from './globalThisPolyfill'
|
|
17
|
+
export * from './observer'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isStr, isFn } from './types'
|
|
2
|
+
import { globalThisPolyfill } from './globalThisPolyfill'
|
|
3
|
+
export const instOf = (value: any, cls: any) => {
|
|
4
|
+
if (isFn(cls)) return value instanceof cls
|
|
5
|
+
if (isStr(cls))
|
|
6
|
+
return globalThisPolyfill[cls]
|
|
7
|
+
? value instanceof globalThisPolyfill[cls]
|
|
8
|
+
: false
|
|
9
|
+
return false
|
|
10
|
+
}
|