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.
- package/dist/glass_easel_miniprogram_adapter.js +1 -1
- package/dist/glass_easel_miniprogram_adapter.js.map +1 -1
- package/dist/types/src/backend.d.ts +8 -0
- package/dist/types/src/backend.d.ts.map +1 -1
- package/dist/types/src/behavior.d.ts +1 -1
- package/dist/types/src/behavior.d.ts.map +1 -1
- package/dist/types/src/component.d.ts +12 -2
- package/dist/types/src/component.d.ts.map +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/intersection.d.ts +24 -0
- package/dist/types/src/intersection.d.ts.map +1 -0
- package/dist/types/src/media_query.d.ts +13 -0
- package/dist/types/src/media_query.d.ts.map +1 -0
- package/dist/types/src/selector_query.d.ts.map +1 -1
- package/dist/types/src/space.d.ts +3 -3
- package/dist/types/src/space.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +4 -4
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/utils.d.ts.map +1 -1
- package/dist/types/tests/base/env.d.ts.map +1 -1
- package/jest.config.js +1 -3
- package/package.json +5 -5
- package/src/backend.ts +20 -10
- package/src/behavior.ts +7 -29
- package/src/component.ts +56 -38
- package/src/index.ts +1 -3
- package/src/intersection.ts +119 -0
- package/src/media_query.ts +28 -0
- package/src/selector_query.ts +176 -174
- package/src/space.ts +154 -238
- package/src/types.ts +33 -33
- package/src/utils.ts +4 -3
- package/tests/base/env.ts +1 -2
- package/tests/data_update.test.ts +43 -37
- package/tests/env.test.ts +37 -37
- package/tests/selector.test.ts +295 -189
- package/tests/space.test.ts +216 -91
- package/tests/trait_behavior.test.ts +26 -23
- 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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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[]
|
|
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[]
|
|
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)[]
|
|
258
|
-
|
|
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
|
-
|
|
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
|
@@ -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
|
+
}
|