glass-easel-miniprogram-adapter 0.1.1 → 0.2.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 (39) hide show
  1. package/dist/glass_easel_miniprogram_adapter.js +1 -1
  2. package/dist/glass_easel_miniprogram_adapter.js.map +1 -1
  3. package/dist/types/src/backend.d.ts +8 -0
  4. package/dist/types/src/backend.d.ts.map +1 -1
  5. package/dist/types/src/behavior.d.ts +1 -1
  6. package/dist/types/src/behavior.d.ts.map +1 -1
  7. package/dist/types/src/component.d.ts +12 -2
  8. package/dist/types/src/component.d.ts.map +1 -1
  9. package/dist/types/src/index.d.ts.map +1 -1
  10. package/dist/types/src/intersection.d.ts +24 -0
  11. package/dist/types/src/intersection.d.ts.map +1 -0
  12. package/dist/types/src/media_query.d.ts +13 -0
  13. package/dist/types/src/media_query.d.ts.map +1 -0
  14. package/dist/types/src/selector_query.d.ts.map +1 -1
  15. package/dist/types/src/space.d.ts +3 -3
  16. package/dist/types/src/space.d.ts.map +1 -1
  17. package/dist/types/src/types.d.ts +4 -4
  18. package/dist/types/src/types.d.ts.map +1 -1
  19. package/dist/types/src/utils.d.ts.map +1 -1
  20. package/dist/types/tests/base/env.d.ts.map +1 -1
  21. package/jest.config.js +1 -3
  22. package/package.json +5 -5
  23. package/src/backend.ts +20 -10
  24. package/src/behavior.ts +7 -29
  25. package/src/component.ts +56 -38
  26. package/src/index.ts +1 -3
  27. package/src/intersection.ts +119 -0
  28. package/src/media_query.ts +28 -0
  29. package/src/selector_query.ts +176 -174
  30. package/src/space.ts +154 -238
  31. package/src/types.ts +33 -33
  32. package/src/utils.ts +4 -3
  33. package/tests/base/env.ts +1 -2
  34. package/tests/data_update.test.ts +43 -37
  35. package/tests/env.test.ts +37 -37
  36. package/tests/selector.test.ts +295 -189
  37. package/tests/space.test.ts +216 -91
  38. package/tests/trait_behavior.test.ts +26 -23
  39. package/webpack.config.js +14 -13
package/src/component.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as glassEasel from 'glass-easel'
2
- import {
3
- utils as typeUtils,
4
- } from './types'
2
+ import { utils as typeUtils } from './types'
5
3
  import { ComponentType, GeneralBehavior, TraitBehavior } from './behavior'
6
4
  import { SelectorQuery } from './selector_query'
5
+ import { IntersectionObserver } from './intersection'
6
+ import { MediaQueryObserver } from './media_query'
7
7
 
8
8
  type DataList = typeUtils.DataList
9
9
  type PropertyList = typeUtils.PropertyList
@@ -18,11 +18,9 @@ type ExportType<
18
18
  UProperty extends PropertyList,
19
19
  UMethod extends MethodList,
20
20
  UComponentExport,
21
- > = (
22
- UComponentExport extends undefined
23
- ? Component<UData, UProperty, UMethod, UComponentExport>
24
- : UComponentExport
25
- )
21
+ > = UComponentExport extends undefined
22
+ ? Component<UData, UProperty, UMethod, UComponentExport>
23
+ : UComponentExport
26
24
 
27
25
  const filterComponentExportWithType = <
28
26
  UData extends DataList,
@@ -30,10 +28,10 @@ const filterComponentExportWithType = <
30
28
  UMethod extends MethodList,
31
29
  UComponentExport,
32
30
  >(
33
- source: ComponentCaller<any, any, any, any>,
34
- elem: glassEasel.Element,
35
- componentType: ComponentType<UData, UProperty, UMethod, UComponentExport>,
36
- ): ExportType<UData, UProperty, UMethod, UComponentExport> | undefined => {
31
+ source: ComponentCaller<any, any, any, any>,
32
+ elem: glassEasel.Element,
33
+ componentType: ComponentType<UData, UProperty, UMethod, UComponentExport>,
34
+ ): ExportType<UData, UProperty, UMethod, UComponentExport> | undefined => {
37
35
  const comp = elem.asInstanceOf(componentType._$)
38
36
  if (comp === null) return undefined
39
37
  const selectedSpace = comp.getRootBehavior().ownerSpace
@@ -78,8 +76,9 @@ export type Component<
78
76
  TProperty extends PropertyList,
79
77
  TMethod extends MethodList,
80
78
  TComponentExport,
81
- > = ComponentCaller<TData, TProperty, TMethod, TComponentExport>
82
- & { [k in keyof TMethod]: TMethod[k] }
79
+ > = ComponentCaller<TData, TProperty, TMethod, TComponentExport> & {
80
+ [k in keyof TMethod]: TMethod[k]
81
+ }
83
82
 
84
83
  export class ComponentCaller<
85
84
  TData extends DataList,
@@ -87,12 +86,8 @@ export class ComponentCaller<
87
86
  TMethod extends MethodList,
88
87
  TComponentExport,
89
88
  > {
90
- /** @internal */
91
- _$!: glassEasel.Component<
92
- TData,
93
- TProperty,
94
- TMethod
95
- >
89
+ /** The corresponding `Component` */
90
+ _$!: glassEasel.Component<TData, TProperty, TMethod>
96
91
  /** @internal */
97
92
  _$export?: (source: GeneralComponent | null) => TComponentExport
98
93
 
@@ -218,12 +213,10 @@ export class ComponentCaller<
218
213
  * All data observers will not be triggered immediately before applied.
219
214
  * Reads of the data will get the unchanged value before applied.
220
215
  */
221
- replaceDataOnPath<
222
- T extends (string | number)[],
223
- >(
216
+ replaceDataOnPath<T extends (string | number)[]>(
224
217
  path: readonly [...T],
225
218
  data: typeUtils.GetFromDataPath<typeUtils.DataWithPropertyValues<TData, TProperty>, T>,
226
- ): void;
219
+ ): void
227
220
  replaceDataOnPath(path: any, data: any) {
228
221
  this._$.replaceDataOnPath(path, data)
229
222
  }
@@ -239,23 +232,27 @@ export class ComponentCaller<
239
232
  * All data observers will not be triggered immediately before applied.
240
233
  * Reads of the data will get the unchanged value before applied.
241
234
  */
242
- spliceArrayDataOnPath<
243
- T extends (string | number)[],
244
- >(
235
+ spliceArrayDataOnPath<T extends (string | number)[]>(
245
236
  path: readonly [...T],
246
237
  index: typeUtils.GetFromDataPath<
247
238
  typeUtils.DataWithPropertyValues<TData, TProperty>,
248
239
  T
249
- > extends any[] ? number | undefined : never,
240
+ > extends any[]
241
+ ? number | undefined
242
+ : never,
250
243
  del: typeUtils.GetFromDataPath<
251
244
  typeUtils.DataWithPropertyValues<TData, TProperty>,
252
245
  T
253
- > extends any[] ? number | undefined : never,
246
+ > extends any[]
247
+ ? number | undefined
248
+ : never,
254
249
  inserts: typeUtils.GetFromDataPath<
255
250
  typeUtils.DataWithPropertyValues<TData, TProperty>,
256
251
  T
257
- > extends (infer I)[] ? I[] : never
258
- ): void;
252
+ > extends (infer I)[]
253
+ ? I[]
254
+ : never,
255
+ ): void
259
256
  spliceArrayDataOnPath(
260
257
  path: (string | number)[],
261
258
  index: number | undefined,
@@ -308,9 +305,9 @@ export class ComponentCaller<
308
305
  name: string,
309
306
  detail: any,
310
307
  options: {
311
- bubbles?: boolean,
312
- composed?: boolean,
313
- capturePhase?: boolean,
308
+ bubbles?: boolean
309
+ composed?: boolean
310
+ capturePhase?: boolean
314
311
  },
315
312
  ) {
316
313
  return this._$.triggerEvent(name, detail, options)
@@ -321,9 +318,26 @@ export class ComponentCaller<
321
318
  return new SelectorQuery(this)
322
319
  }
323
320
 
321
+ /** Create an intersection observer */
322
+ createIntersectionObserver(options?: {
323
+ thresholds?: number[]
324
+ initialRatio?: number
325
+ observeAll?: boolean
326
+ }): IntersectionObserver {
327
+ return new IntersectionObserver(
328
+ this,
329
+ options?.thresholds || [0],
330
+ options?.initialRatio || 0,
331
+ options?.observeAll || false,
332
+ )
333
+ }
334
+
335
+ /** Create an media query observer */
336
+ createMediaQueryObserver(): MediaQueryObserver {
337
+ return new MediaQueryObserver(this)
338
+ }
339
+
324
340
  // TODO support animate / applyAnimation / clearAnimation
325
- // TODO support createIntersectionObserver
326
- // TODO support createMediaQueryObserver
327
341
  // TODO support setUpdatePerformanceListener
328
342
 
329
343
  /**
@@ -464,8 +478,12 @@ export class ComponentProto<
464
478
  private proto: Component<TData, TProperty, TMethod, TComponentExport>
465
479
 
466
480
  constructor(methods: TMethod, componentExport?: () => TComponentExport) {
467
- this.proto = Object.create(ComponentCaller.prototype) as
468
- Component<TData, TProperty, TMethod, TComponentExport>
481
+ this.proto = Object.create(ComponentCaller.prototype) as Component<
482
+ TData,
483
+ TProperty,
484
+ TMethod,
485
+ TComponentExport
486
+ >
469
487
  Object.assign(this.proto, methods)
470
488
  this.proto._$export = componentExport
471
489
  }
package/src/index.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import * as glassEasel from 'glass-easel'
2
2
  import { AssociatedBackend } from './backend'
3
- import {
4
- CodeSpace,
5
- } from './space'
3
+ import { CodeSpace } from './space'
6
4
 
7
5
  export * as glassEasel from 'glass-easel'
8
6
  export * as types from './types'
@@ -0,0 +1,119 @@
1
+ import * as glassEasel from 'glass-easel'
2
+ import { GeneralComponent } from './component'
3
+
4
+ export type IntersectionObserverMargins = {
5
+ left: number
6
+ top: number
7
+ right: number
8
+ bottom: number
9
+ }
10
+
11
+ const defaultMargins = {
12
+ left: 0,
13
+ top: 0,
14
+ right: 0,
15
+ bottom: 0,
16
+ }
17
+
18
+ export class IntersectionObserver {
19
+ private _$comp: GeneralComponent
20
+ private _$thresholds: number[]
21
+ private _$initialRatio: number
22
+ private _$observeAll: boolean
23
+ private _$selector: string | null = null
24
+ private _$margins: IntersectionObserverMargins | null = null
25
+ private _$observers: glassEasel.backend.Observer[] = []
26
+
27
+ /** @internal */
28
+ constructor(
29
+ comp: GeneralComponent,
30
+ thresholds: number[],
31
+ initialRatio: number,
32
+ observeAll: boolean,
33
+ ) {
34
+ this._$comp = comp
35
+ this._$thresholds = thresholds
36
+ this._$initialRatio = initialRatio
37
+ this._$observeAll = observeAll
38
+ }
39
+
40
+ relativeTo(selector: string, margins?: IntersectionObserverMargins): this {
41
+ this._$selector = selector
42
+ this._$margins = margins ?? defaultMargins
43
+ return this
44
+ }
45
+
46
+ relativeToViewport(margins?: IntersectionObserverMargins): this {
47
+ this._$selector = null
48
+ this._$margins = margins ?? defaultMargins
49
+ return this
50
+ }
51
+
52
+ observe(
53
+ targetSelector: string,
54
+ listener: (status: glassEasel.backend.IntersectionStatus) => void,
55
+ ) {
56
+ const shadowRoot = this._$comp._$.getShadowRoot()
57
+ let targets: glassEasel.Element[]
58
+ if (!shadowRoot) {
59
+ targets = []
60
+ } else if (this._$observeAll) {
61
+ targets = shadowRoot.querySelectorAll(targetSelector)
62
+ } else {
63
+ const elem = shadowRoot.querySelector(targetSelector)
64
+ if (elem === null) {
65
+ targets = []
66
+ } else {
67
+ targets = [elem]
68
+ }
69
+ }
70
+ let relativeElement: glassEasel.Element | null
71
+ if (this._$selector === null || !shadowRoot) {
72
+ relativeElement = null
73
+ } else {
74
+ const rel = shadowRoot.querySelector(this._$selector)
75
+ if (rel === null) {
76
+ // TODO warn no matched relative element
77
+ } else {
78
+ relativeElement = rel
79
+ }
80
+ }
81
+ if (!this._$margins) {
82
+ throw new Error('`relativeTo` or `relativeToViewport` should be called before observe')
83
+ }
84
+ const { left, top, right, bottom } = this._$margins
85
+ const margin = `${top}px ${right}px ${bottom}px ${left}px`
86
+ targets.forEach((target) => {
87
+ let initial: number | null = this._$initialRatio
88
+ const observer = target.createIntersectionObserver(
89
+ relativeElement,
90
+ margin,
91
+ this._$thresholds,
92
+ (args) => {
93
+ if (initial !== null) {
94
+ let i = 0
95
+ for (; i < this._$thresholds.length; i += 1) {
96
+ const threshold = this._$thresholds[i]!
97
+ if (initial === args.intersectionRatio) continue
98
+ if ((initial - threshold) * (args.intersectionRatio - threshold) <= 0) break
99
+ }
100
+ initial = null
101
+ if (i < this._$thresholds.length) return
102
+ }
103
+ listener(args)
104
+ },
105
+ )
106
+ if (observer === null) {
107
+ // TODO warn no observer attached
108
+ } else {
109
+ this._$observers.push(observer)
110
+ }
111
+ })
112
+ }
113
+
114
+ disconnect() {
115
+ const observers = this._$observers
116
+ this._$observers = []
117
+ observers.forEach((observer) => observer.disconnect())
118
+ }
119
+ }
@@ -0,0 +1,28 @@
1
+ import * as glassEasel from 'glass-easel'
2
+ import { GeneralComponent } from './component'
3
+
4
+ export class MediaQueryObserver {
5
+ private _$comp: GeneralComponent
6
+ private _$observer: glassEasel.backend.Observer | null = null
7
+
8
+ /** @internal */
9
+ constructor(comp: GeneralComponent) {
10
+ this._$comp = comp
11
+ }
12
+
13
+ observe(
14
+ descriptor: glassEasel.backend.MediaQueryStatus,
15
+ listener: (status: { matches: boolean }) => void,
16
+ ) {
17
+ if (this._$observer) this._$observer.disconnect()
18
+ this._$observer = this._$comp._$.getBackendContext().createMediaQueryObserver(
19
+ descriptor,
20
+ listener,
21
+ )
22
+ }
23
+
24
+ disconnect() {
25
+ if (this._$observer) this._$observer.disconnect()
26
+ this._$observer = null
27
+ }
28
+ }