glass-easel 0.2.0 → 0.3.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.
Files changed (197) hide show
  1. package/.eslintignore +4 -0
  2. package/dist/glass_easel.all.js +2 -2
  3. package/dist/glass_easel.all.js.map +1 -1
  4. package/dist/glass_easel.d.ts +2546 -0
  5. package/dist/glass_easel.domlike.global.js +2 -2
  6. package/dist/glass_easel.domlike.global.js.map +1 -1
  7. package/guide/zh_CN/appendix/backend_protocol.md +164 -74
  8. package/jest.unit.config.js +7 -4
  9. package/package.json +7 -5
  10. package/rollup.config.ts +101 -0
  11. package/src/backend/backend_protocol.ts +26 -345
  12. package/src/backend/composed_backend_protocol.ts +10 -264
  13. package/src/backend/current_window_backend_context.ts +478 -0
  14. package/src/backend/domlike_backend_protocol.ts +9 -498
  15. package/src/backend/empty_backend.ts +265 -0
  16. package/src/backend/empty_composed_backend.ts +245 -0
  17. package/src/backend/index.ts +18 -0
  18. package/src/backend/suggested_backend_protocol.ts +62 -11
  19. package/src/behavior.ts +131 -442
  20. package/src/class_list.ts +328 -222
  21. package/src/component.ts +349 -184
  22. package/src/component_params.ts +54 -25
  23. package/src/component_space.ts +36 -15
  24. package/src/data_path.ts +22 -34
  25. package/src/data_proxy.ts +334 -27
  26. package/src/devtool.ts +89 -0
  27. package/src/element.ts +667 -285
  28. package/src/element_iterator.ts +9 -4
  29. package/src/event.ts +39 -20
  30. package/src/external_shadow_tree.ts +2 -2
  31. package/src/func_arr.ts +55 -101
  32. package/src/global_options.ts +18 -42
  33. package/src/index.ts +72 -73
  34. package/src/mutation_observer.ts +10 -7
  35. package/src/native_node.ts +79 -35
  36. package/src/node.ts +23 -30
  37. package/src/relation.ts +101 -12
  38. package/src/render.ts +5 -3
  39. package/src/selector.ts +9 -7
  40. package/src/shadow_root.ts +96 -240
  41. package/src/template_engine.ts +10 -7
  42. package/src/text_node.ts +43 -19
  43. package/src/tmpl/index.ts +38 -30
  44. package/src/tmpl/native_rendering.ts +14 -21
  45. package/src/tmpl/proc_gen_wrapper.ts +189 -151
  46. package/src/tmpl/proc_gen_wrapper_dom.ts +10 -8
  47. package/src/tmpl/range_list_diff.ts +30 -9
  48. package/src/trait_behaviors.ts +1 -1
  49. package/src/type_symbol.ts +36 -0
  50. package/src/virtual_node.ts +26 -13
  51. package/src/warning.ts +119 -0
  52. package/tests/base/composed_backend.ts +143 -142
  53. package/tests/base/env.ts +76 -3
  54. package/tests/base/match.ts +24 -22
  55. package/tests/base/shadow_backend.ts +917 -0
  56. package/tests/core/backend.test.ts +53 -1
  57. package/tests/core/behavior.test.ts +1 -1
  58. package/tests/core/data_update.test.ts +135 -0
  59. package/tests/core/misc.test.ts +91 -21
  60. package/tests/core/placeholder.test.ts +66 -25
  61. package/tests/core/slot.test.ts +161 -23
  62. package/tests/legacy/component.test.js +152 -78
  63. package/tests/legacy/data_path.test.js +19 -19
  64. package/tests/legacy/data_proxy.test.js +14 -7
  65. package/tests/legacy/external.test.js +8 -8
  66. package/tests/legacy/mutation_observer.test.js +7 -5
  67. package/tests/legacy/slot.test.js +2 -3
  68. package/tests/legacy/virtual.test.js +258 -25
  69. package/tests/tmpl/binding_map.test.ts +201 -195
  70. package/tests/tmpl/event.test.ts +138 -23
  71. package/tests/tmpl/expression.test.ts +15 -15
  72. package/tests/tmpl/lvalue.test.ts +101 -0
  73. package/tests/tmpl/structure.test.ts +486 -43
  74. package/tests/types/chaining.test.ts +27 -30
  75. package/tests/types/createElement.test.ts +5 -4
  76. package/tests/types/definition.test.ts +11 -14
  77. package/tsconfig.json +1 -3
  78. package/dist/glass_easel.all.d.ts +0 -1
  79. package/dist/glass_easel.domlike.global.d.ts +0 -1
  80. package/dist/index.d.ts +0 -1
  81. package/dist/index.js +0 -1
  82. package/dist/types/src/backend/backend_protocol.d.ts +0 -141
  83. package/dist/types/src/backend/backend_protocol.d.ts.map +0 -1
  84. package/dist/types/src/backend/composed_backend_protocol.d.ts +0 -102
  85. package/dist/types/src/backend/composed_backend_protocol.d.ts.map +0 -1
  86. package/dist/types/src/backend/domlike_backend_protocol.d.ts +0 -100
  87. package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +0 -1
  88. package/dist/types/src/backend/mode.d.ts +0 -65
  89. package/dist/types/src/backend/mode.d.ts.map +0 -1
  90. package/dist/types/src/backend/suggested_backend_protocol.d.ts +0 -30
  91. package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +0 -1
  92. package/dist/types/src/behavior.d.ts +0 -434
  93. package/dist/types/src/behavior.d.ts.map +0 -1
  94. package/dist/types/src/class_list.d.ts +0 -83
  95. package/dist/types/src/class_list.d.ts.map +0 -1
  96. package/dist/types/src/component.d.ts +0 -325
  97. package/dist/types/src/component.d.ts.map +0 -1
  98. package/dist/types/src/component_params.d.ts +0 -236
  99. package/dist/types/src/component_params.d.ts.map +0 -1
  100. package/dist/types/src/component_space.d.ts +0 -211
  101. package/dist/types/src/component_space.d.ts.map +0 -1
  102. package/dist/types/src/data_path.d.ts +0 -5
  103. package/dist/types/src/data_path.d.ts.map +0 -1
  104. package/dist/types/src/data_proxy.d.ts +0 -107
  105. package/dist/types/src/data_proxy.d.ts.map +0 -1
  106. package/dist/types/src/data_utils.d.ts +0 -3
  107. package/dist/types/src/data_utils.d.ts.map +0 -1
  108. package/dist/types/src/element.d.ts +0 -365
  109. package/dist/types/src/element.d.ts.map +0 -1
  110. package/dist/types/src/element_iterator.d.ts +0 -43
  111. package/dist/types/src/element_iterator.d.ts.map +0 -1
  112. package/dist/types/src/event.d.ts +0 -105
  113. package/dist/types/src/event.d.ts.map +0 -1
  114. package/dist/types/src/external_shadow_tree.d.ts +0 -20
  115. package/dist/types/src/external_shadow_tree.d.ts.map +0 -1
  116. package/dist/types/src/func_arr.d.ts +0 -39
  117. package/dist/types/src/func_arr.d.ts.map +0 -1
  118. package/dist/types/src/global_options.d.ts +0 -120
  119. package/dist/types/src/global_options.d.ts.map +0 -1
  120. package/dist/types/src/index.d.ts +0 -43
  121. package/dist/types/src/index.d.ts.map +0 -1
  122. package/dist/types/src/mutation_observer.d.ts +0 -79
  123. package/dist/types/src/mutation_observer.d.ts.map +0 -1
  124. package/dist/types/src/native_node.d.ts +0 -11
  125. package/dist/types/src/native_node.d.ts.map +0 -1
  126. package/dist/types/src/node.d.ts +0 -48
  127. package/dist/types/src/node.d.ts.map +0 -1
  128. package/dist/types/src/relation.d.ts +0 -46
  129. package/dist/types/src/relation.d.ts.map +0 -1
  130. package/dist/types/src/render.d.ts +0 -3
  131. package/dist/types/src/render.d.ts.map +0 -1
  132. package/dist/types/src/selector.d.ts +0 -32
  133. package/dist/types/src/selector.d.ts.map +0 -1
  134. package/dist/types/src/shadow_root.d.ts +0 -174
  135. package/dist/types/src/shadow_root.d.ts.map +0 -1
  136. package/dist/types/src/template_engine.d.ts +0 -56
  137. package/dist/types/src/template_engine.d.ts.map +0 -1
  138. package/dist/types/src/text_node.d.ts +0 -44
  139. package/dist/types/src/text_node.d.ts.map +0 -1
  140. package/dist/types/src/tmpl/index.d.ts +0 -19
  141. package/dist/types/src/tmpl/index.d.ts.map +0 -1
  142. package/dist/types/src/tmpl/native_rendering.d.ts +0 -45
  143. package/dist/types/src/tmpl/native_rendering.d.ts.map +0 -1
  144. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +0 -89
  145. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +0 -1
  146. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +0 -50
  147. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +0 -1
  148. package/dist/types/src/tmpl/range_list_diff.d.ts +0 -19
  149. package/dist/types/src/tmpl/range_list_diff.d.ts.map +0 -1
  150. package/dist/types/src/trait_behaviors.d.ts +0 -38
  151. package/dist/types/src/trait_behaviors.d.ts.map +0 -1
  152. package/dist/types/src/virtual_node.d.ts +0 -10
  153. package/dist/types/src/virtual_node.d.ts.map +0 -1
  154. package/dist/types/tests/backend/domlike.test.d.ts +0 -2
  155. package/dist/types/tests/backend/domlike.test.d.ts.map +0 -1
  156. package/dist/types/tests/base/composed_backend.d.ts +0 -123
  157. package/dist/types/tests/base/composed_backend.d.ts.map +0 -1
  158. package/dist/types/tests/base/env.d.ts +0 -30
  159. package/dist/types/tests/base/env.d.ts.map +0 -1
  160. package/dist/types/tests/base/match.d.ts +0 -9
  161. package/dist/types/tests/base/match.d.ts.map +0 -1
  162. package/dist/types/tests/core/backend.test.d.ts +0 -2
  163. package/dist/types/tests/core/backend.test.d.ts.map +0 -1
  164. package/dist/types/tests/core/behavior.test.d.ts +0 -2
  165. package/dist/types/tests/core/behavior.test.d.ts.map +0 -1
  166. package/dist/types/tests/core/component_space.test.d.ts +0 -2
  167. package/dist/types/tests/core/component_space.test.d.ts.map +0 -1
  168. package/dist/types/tests/core/data_update.test.d.ts +0 -2
  169. package/dist/types/tests/core/data_update.test.d.ts.map +0 -1
  170. package/dist/types/tests/core/misc.test.d.ts +0 -2
  171. package/dist/types/tests/core/misc.test.d.ts.map +0 -1
  172. package/dist/types/tests/core/placeholder.test.d.ts +0 -2
  173. package/dist/types/tests/core/placeholder.test.d.ts.map +0 -1
  174. package/dist/types/tests/core/slot.test.d.ts +0 -2
  175. package/dist/types/tests/core/slot.test.d.ts.map +0 -1
  176. package/dist/types/tests/core/trait_behaviors.test.d.ts +0 -2
  177. package/dist/types/tests/core/trait_behaviors.test.d.ts.map +0 -1
  178. package/dist/types/tests/tmpl/binding_map.test.d.ts +0 -2
  179. package/dist/types/tests/tmpl/binding_map.test.d.ts.map +0 -1
  180. package/dist/types/tests/tmpl/event.test.d.ts +0 -2
  181. package/dist/types/tests/tmpl/event.test.d.ts.map +0 -1
  182. package/dist/types/tests/tmpl/expression.test.d.ts +0 -2
  183. package/dist/types/tests/tmpl/expression.test.d.ts.map +0 -1
  184. package/dist/types/tests/tmpl/lvalue.test.d.ts +0 -2
  185. package/dist/types/tests/tmpl/lvalue.test.d.ts.map +0 -1
  186. package/dist/types/tests/tmpl/native_rendering.test.d.ts +0 -2
  187. package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +0 -1
  188. package/dist/types/tests/tmpl/structure.test.d.ts +0 -2
  189. package/dist/types/tests/tmpl/structure.test.d.ts.map +0 -1
  190. package/dist/types/tests/types/chaining.test.d.ts +0 -2
  191. package/dist/types/tests/types/chaining.test.d.ts.map +0 -1
  192. package/dist/types/tests/types/createElement.test.d.ts +0 -2
  193. package/dist/types/tests/types/createElement.test.d.ts.map +0 -1
  194. package/dist/types/tests/types/definition.test.d.ts +0 -2
  195. package/dist/types/tests/types/definition.test.d.ts.map +0 -1
  196. package/webpack.config.js +0 -275
  197. /package/src/backend/{mode.ts → shared.ts} +0 -0
@@ -0,0 +1,478 @@
1
+ /* eslint-disable class-methods-use-this */
2
+ /* global window, document */
3
+
4
+ import { type Element as GlassEaselElement } from '../element'
5
+ import { EventBubbleStatus, MutLevel, type EventOptions } from '../event'
6
+ import { safeCallback } from '../func_arr'
7
+ import { triggerWarning } from '../warning'
8
+ import { type Context, type Element } from './domlike_backend_protocol'
9
+ import {
10
+ BackendMode,
11
+ type IntersectionStatus,
12
+ type MediaQueryStatus,
13
+ type Observer,
14
+ } from './shared'
15
+
16
+ const DELEGATE_EVENTS = [
17
+ 'touchstart',
18
+ 'touchmove',
19
+ 'touchend',
20
+ 'touchcancel',
21
+ 'mousedown',
22
+ 'mousemove',
23
+ 'mouseout',
24
+ 'mouseover',
25
+ 'mouseup',
26
+ 'click',
27
+ ]
28
+
29
+ export class CurrentWindowBackendContext implements Context {
30
+ mode: BackendMode.Domlike = BackendMode.Domlike
31
+ document = document as unknown as {
32
+ createElement(tagName: string): Element
33
+ createTextNode(content: string): Element
34
+ createDocumentFragment(): Element
35
+ }
36
+ /* @internal */
37
+ private _$styleSheets: HTMLElement[] = []
38
+ /* @internal */
39
+ private _$styleSheetRegistry = Object.create(null) as { [path: string]: string }
40
+ /* @internal */
41
+ private _$delegatedEventListeners = Object.create(null) as Record<string, true>
42
+ /* @internal */
43
+ private _$elementEventListeners = new WeakMap<Element, Record<string, true>>()
44
+ /* @internal */
45
+ private _$elementCaptureEventListeners = new WeakMap<Element, Record<string, true>>()
46
+ /* @internal */
47
+ private _$triggedEvents = new WeakSet<Event>()
48
+ /* @internal */
49
+ private _$eventListener?: (
50
+ target: any,
51
+ type: string,
52
+ detail: any,
53
+ options: EventOptions,
54
+ ) => EventBubbleStatus | void
55
+
56
+ destroy() {
57
+ /* empty */
58
+ }
59
+
60
+ getWindowWidth(): number {
61
+ return document.documentElement.clientWidth
62
+ }
63
+
64
+ getWindowHeight(): number {
65
+ return document.documentElement.clientHeight
66
+ }
67
+
68
+ getDevicePixelRatio(): number {
69
+ return window.devicePixelRatio
70
+ }
71
+
72
+ getTheme(): string {
73
+ return 'light'
74
+ }
75
+
76
+ registerStyleSheetContent(path: string, content: unknown): void {
77
+ this._$styleSheetRegistry[path] = String(content)
78
+ }
79
+
80
+ appendStyleSheetPath(path: string, styleScope?: number): number {
81
+ const styleText = this._$styleSheetRegistry[path]
82
+ if (styleText === undefined) throw new Error(`No style sheet registry "${path}"`)
83
+ const s = document.createElement('style')
84
+ s.type = 'text/css'
85
+ s.innerHTML = styleText
86
+ if (styleScope !== undefined) s.setAttribute('wx-style-scope', String(styleScope))
87
+ document.head.appendChild(s)
88
+ const id = this._$styleSheets.length
89
+ this._$styleSheets.push(s)
90
+ return id
91
+ }
92
+
93
+ disableStyleSheet(index: number) {
94
+ const ss = this._$styleSheets[index]
95
+ if (ss) document.head.removeChild(ss)
96
+ }
97
+
98
+ render(cb: (err: Error | null) => void) {
99
+ window.requestAnimationFrame(() => {
100
+ safeCallback('Render Callback', cb, this, [null])
101
+ })
102
+ }
103
+
104
+ getRootNode(): Element {
105
+ return document.body as unknown as Element
106
+ }
107
+
108
+ associateValue(element: Element, value: GlassEaselElement): void {
109
+ element.__wxElement = value
110
+ }
111
+
112
+ onEvent(
113
+ listener: (
114
+ target: GlassEaselElement,
115
+ type: string,
116
+ detail: any,
117
+ options: EventOptions,
118
+ ) => EventBubbleStatus | void,
119
+ ) {
120
+ if (!this._$eventListener) {
121
+ this._$initEvent()
122
+ }
123
+ this._$eventListener = listener
124
+ }
125
+
126
+ /* @internal */
127
+ private _$getEventDetail(ev: Event) {
128
+ const detail: { [key: string]: unknown } = {}
129
+ let e: Event = ev
130
+ while (Object.getPrototypeOf(e) !== Event.prototype) {
131
+ const keys = Object.keys(e)
132
+ for (let i = 0; i < keys.length; i += 1) {
133
+ const key = keys[i]!
134
+ if (typeof (ev as unknown as { [key: string]: unknown })[key] === 'function') continue
135
+ detail[key] = (ev as unknown as { [key: string]: unknown })[key]
136
+ }
137
+ e = Object.getPrototypeOf(e) as Event
138
+ }
139
+ return detail
140
+ }
141
+
142
+ /* @internal */
143
+ private _$trigger(ev: Event, type: string, detail: unknown, bubbles: boolean, composed: boolean) {
144
+ if (!this._$eventListener || !ev.target) return
145
+
146
+ let t: Element | null = ev.target as any as Element
147
+ while (t && !t.__wxElement) t = t.parentNode
148
+ if (!t) return
149
+
150
+ const bubbleStatus = this._$eventListener(t.__wxElement!, type, detail, {
151
+ originalEvent: ev,
152
+ bubbles,
153
+ composed,
154
+ capturePhase: true,
155
+ })
156
+ if (bubbleStatus === EventBubbleStatus.NoDefault) {
157
+ ev.preventDefault()
158
+ }
159
+ }
160
+
161
+ /* @internal */
162
+ private _$initEvent() {
163
+ const TAP_DIST = 10
164
+
165
+ const possibleTaps = Object.create(null) as { [id: number]: { x: number; y: number } }
166
+ const SIMULATED_MOUSE_ID = -1
167
+ let disableMouseEvents = false
168
+
169
+ const handleTapStart = (
170
+ _ev: Event,
171
+ t: { identifier: number; clientX: number; clientY: number },
172
+ ) => {
173
+ possibleTaps[t.identifier] = {
174
+ x: t.clientX,
175
+ y: t.clientY,
176
+ }
177
+ }
178
+
179
+ const handleTapMove = (
180
+ ev: Event,
181
+ t: { identifier: number; clientX: number; clientY: number },
182
+ ) => {
183
+ const id = t.identifier
184
+ if (possibleTaps[id]) {
185
+ const u = possibleTaps[id]!
186
+ if (Math.abs(u.x - t.clientX) > TAP_DIST || Math.abs(u.y - t.clientY) > TAP_DIST) {
187
+ delete possibleTaps[id]
188
+ this._$trigger(ev, 'canceltap', u, true, true)
189
+ }
190
+ }
191
+ }
192
+
193
+ const handleTapEnd = (
194
+ ev: Event,
195
+ t: { identifier: number; clientX: number; clientY: number },
196
+ ) => {
197
+ const id = t.identifier
198
+ if (possibleTaps[id]) {
199
+ const u = possibleTaps[id]!
200
+ delete possibleTaps[id]
201
+ if (Math.abs(u.x - t.clientX) > TAP_DIST || Math.abs(u.y - t.clientY) > TAP_DIST) {
202
+ this._$trigger(ev, 'canceltap', u, true, true)
203
+ } else {
204
+ this._$trigger(ev, 'tap', u, true, true)
205
+ }
206
+ }
207
+ }
208
+
209
+ const handleTapCancel = (
210
+ ev: Event,
211
+ t: { identifier: number; clientX: number; clientY: number },
212
+ ) => {
213
+ const id = t.identifier
214
+ if (possibleTaps[id]) {
215
+ const u = possibleTaps[id]!
216
+ delete possibleTaps[id]
217
+ this._$trigger(ev, 'canceltap', u, true, true)
218
+ }
219
+ }
220
+
221
+ const handleTouchStart = (ev: TouchEvent) => {
222
+ disableMouseEvents = true
223
+ const changedTouches = ev.changedTouches
224
+ for (let i = 0; i < changedTouches.length; i += 1) {
225
+ handleTapStart(ev, changedTouches[i]!)
226
+ }
227
+ const target = ev.target as unknown as HTMLElement & { __touchCount?: number }
228
+ if (!target.__touchCount) {
229
+ target.__touchCount = 0
230
+ target.addEventListener('touchend', handleTouchEnd)
231
+ target.addEventListener('touchcancel', handleTouchCancel)
232
+ }
233
+ target.__touchCount += changedTouches.length
234
+ }
235
+
236
+ const handleTouchMove = (ev: TouchEvent) => {
237
+ const changedTouches = ev.changedTouches
238
+ for (let i = 0; i < changedTouches.length; i += 1) {
239
+ handleTapMove(ev, changedTouches[i]!)
240
+ }
241
+ }
242
+
243
+ const handleTouchEnd = (ev: TouchEvent) => {
244
+ const changedTouches = ev.changedTouches
245
+ for (let i = 0; i < changedTouches.length; i += 1) {
246
+ handleTapEnd(ev, changedTouches[i]!)
247
+ }
248
+ const target = ev.target as unknown as HTMLElement & { __touchCount?: number }
249
+ target.__touchCount! -= changedTouches.length
250
+ if (target.__touchCount! <= 0) {
251
+ target.__touchCount = 0
252
+ target.removeEventListener('touchend', handleTouchEnd)
253
+ target.removeEventListener('touchcancel', handleTouchCancel)
254
+ }
255
+ }
256
+
257
+ const handleTouchCancel = (ev: TouchEvent) => {
258
+ const changedTouches = ev.changedTouches
259
+ for (let i = 0; i < changedTouches.length; i += 1) {
260
+ handleTapCancel(ev, changedTouches[i]!)
261
+ }
262
+ const target = ev.target as unknown as HTMLElement & { __touchCount?: number }
263
+ target.__touchCount! -= changedTouches.length
264
+ if (target.__touchCount! <= 0) {
265
+ target.__touchCount = 0
266
+ target.removeEventListener('touchend', handleTouchEnd)
267
+ target.removeEventListener('touchcancel', handleTouchCancel)
268
+ }
269
+ }
270
+
271
+ const handleMouseDown = (ev: MouseEvent) => {
272
+ if (disableMouseEvents) return
273
+ handleTapStart(ev, {
274
+ identifier: SIMULATED_MOUSE_ID,
275
+ clientX: ev.clientX,
276
+ clientY: ev.clientY,
277
+ })
278
+ }
279
+
280
+ const handleMouseOver = (ev: MouseEvent) => {
281
+ if (disableMouseEvents) return
282
+ handleTapMove(ev, {
283
+ identifier: SIMULATED_MOUSE_ID,
284
+ clientX: ev.clientX,
285
+ clientY: ev.clientY,
286
+ })
287
+ }
288
+
289
+ const handleMouseUp = (ev: MouseEvent) => {
290
+ if (disableMouseEvents) return
291
+ handleTapEnd(ev, {
292
+ identifier: SIMULATED_MOUSE_ID,
293
+ clientX: ev.clientX,
294
+ clientY: ev.clientY,
295
+ })
296
+ }
297
+
298
+ document.body.addEventListener('touchstart', handleTouchStart, { capture: true })
299
+ document.body.addEventListener('touchmove', handleTouchMove, { capture: true })
300
+ document.body.addEventListener('mousedown', handleMouseDown, { capture: true })
301
+ document.body.addEventListener('mousemove', handleMouseOver, { capture: true })
302
+ document.body.addEventListener('mouseup', handleMouseUp, { capture: true })
303
+ }
304
+
305
+ setListenerStats(element: Element, type: string, capture: boolean, mutLevel: MutLevel): void {
306
+ // for non-passive events,
307
+ // the default-prevented status can also be found in `EventBubbleStatus` ,
308
+ // so there is nothing to do with non-passive events.
309
+ if (!element) return
310
+
311
+ const shouldDelegate = DELEGATE_EVENTS.includes(type)
312
+ const defaultPrevented = mutLevel === MutLevel.Final
313
+
314
+ if (shouldDelegate) {
315
+ if (this._$delegatedEventListeners[type]) return
316
+ this._$delegatedEventListeners[type] = true
317
+
318
+ document.body.addEventListener(
319
+ type,
320
+ (ev) => {
321
+ if (defaultPrevented) ev.preventDefault()
322
+ this._$trigger(ev, type, this._$getEventDetail(ev), ev.bubbles, ev.composed)
323
+ },
324
+ { capture: true },
325
+ )
326
+ return
327
+ }
328
+
329
+ const elementEventListeners = capture
330
+ ? this._$elementCaptureEventListeners
331
+ : this._$elementEventListeners
332
+ if (!elementEventListeners.has(element)) elementEventListeners.set(element, Object.create(null))
333
+ const listeners = elementEventListeners.get(element)!
334
+ if (listeners[type]) return
335
+ listeners[type] = true
336
+
337
+ element.addEventListener(type, (ev) => {
338
+ if (this._$triggedEvents.has(ev)) return
339
+ this._$triggedEvents.add(ev)
340
+ if (defaultPrevented) ev.preventDefault()
341
+ this._$trigger(ev, type, this._$getEventDetail(ev), ev.bubbles, ev.composed)
342
+ })
343
+ }
344
+
345
+ setModelBindingStat(
346
+ element: Element,
347
+ attributeName: string,
348
+ listener: ((newValue: unknown) => void) | null,
349
+ ): void {
350
+ const updateEventListener = (evName: string, valueFn: () => void) => {
351
+ if (!element._$wxArgs) {
352
+ element._$wxArgs = {
353
+ modelListeners: Object.create(null) as {
354
+ [name: string]: ((newValue: unknown) => void) | null
355
+ },
356
+ }
357
+ }
358
+ if (element._$wxArgs.modelListeners[attributeName] === undefined) {
359
+ if (!listener) return
360
+ element._$wxArgs.modelListeners[attributeName] = listener
361
+ element.addEventListener(evName, () => {
362
+ const listener = element._$wxArgs?.modelListeners[attributeName]
363
+ listener?.(valueFn())
364
+ })
365
+ }
366
+ element._$wxArgs.modelListeners[attributeName] = listener
367
+ }
368
+ const tagName = element.tagName
369
+ let valid = false
370
+ if (tagName === 'INPUT') {
371
+ const elem = element as unknown as HTMLInputElement
372
+ const type = elem.type
373
+ if (type === 'checkbox') {
374
+ if (attributeName === 'checked') {
375
+ valid = true
376
+ updateEventListener('change', () => elem.checked)
377
+ }
378
+ } else if (type === 'radio') {
379
+ if (attributeName === 'checked') {
380
+ valid = true
381
+ updateEventListener('change', () => elem.checked)
382
+ }
383
+ } else {
384
+ if (attributeName === 'value') {
385
+ valid = true
386
+ updateEventListener('input', () => elem.value)
387
+ }
388
+ }
389
+ } else if (tagName === 'TEXTAREA') {
390
+ const elem = element as unknown as HTMLTextAreaElement
391
+ if (attributeName === 'value') {
392
+ valid = true
393
+ updateEventListener('input', () => elem.value)
394
+ }
395
+ } else if (tagName === 'SELECT') {
396
+ const elem = element as unknown as HTMLSelectElement
397
+ if (attributeName === 'value') {
398
+ valid = true
399
+ updateEventListener('change', () => elem.value)
400
+ }
401
+ }
402
+ if (!valid) {
403
+ triggerWarning(
404
+ `unsupported model binding on "${attributeName}" of "${tagName.toLowerCase()}" element.`,
405
+ )
406
+ }
407
+ }
408
+
409
+ createIntersectionObserver(
410
+ targetElement: Element,
411
+ relativeElement: Element | null,
412
+ relativeElementMargin: string,
413
+ thresholds: number[],
414
+ listener: (res: IntersectionStatus) => void,
415
+ ): Observer {
416
+ const observer = new IntersectionObserver(
417
+ (info) => {
418
+ info.forEach((entry) => {
419
+ listener({
420
+ intersectionRatio: entry.intersectionRatio,
421
+ boundingClientRect: entry.boundingClientRect,
422
+ intersectionRect: entry.intersectionRect,
423
+ relativeRect: entry.rootBounds!,
424
+ time: entry.time,
425
+ })
426
+ })
427
+ },
428
+ {
429
+ root: relativeElement as unknown as HTMLElement,
430
+ rootMargin: relativeElementMargin,
431
+ threshold: thresholds,
432
+ },
433
+ )
434
+ observer.observe(targetElement as unknown as HTMLElement)
435
+ return {
436
+ disconnect() {
437
+ observer.disconnect()
438
+ },
439
+ }
440
+ }
441
+
442
+ createMediaQueryObserver(
443
+ status: MediaQueryStatus,
444
+ listener: (res: { matches: boolean }) => void,
445
+ ): Observer {
446
+ const calcMatches = () => {
447
+ const width = document.documentElement.clientWidth
448
+ const height = document.documentElement.clientHeight
449
+ if (status.width !== undefined && width !== status.width) return false
450
+ if (status.maxWidth !== undefined && width > status.maxWidth) return false
451
+ if (status.minWidth !== undefined && width < status.minWidth) return false
452
+ if (status.width !== undefined && height !== status.height) return false
453
+ if (status.maxHeight !== undefined && height > status.maxHeight) return false
454
+ if (status.minHeight !== undefined && height < status.minHeight) return false
455
+ const orientation = width > height ? 'landscape' : 'portrait'
456
+ if (orientation !== status.orientation) return false
457
+ return true
458
+ }
459
+ let curMatches: boolean | null = null
460
+ const listenerFunc = () => {
461
+ const matches = calcMatches()
462
+ if (curMatches === matches) return
463
+ curMatches = matches
464
+ listener({ matches })
465
+ }
466
+ setTimeout(listenerFunc, 0)
467
+ window.addEventListener('resize', listenerFunc)
468
+ return {
469
+ disconnect() {
470
+ window.removeEventListener('resize', listenerFunc)
471
+ },
472
+ }
473
+ }
474
+
475
+ getContext(element: Element, cb: (res: unknown) => void): void {
476
+ cb(null)
477
+ }
478
+ }