view-anchor 0.2.2 → 1.0.0-beta.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/README.md +71 -87
- package/README.zh-CN.md +59 -64
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/protocol-publisher.d.ts +7 -9
- package/dist/protocol-publisher.d.ts.map +1 -1
- package/dist/protocol-publisher.js +2 -8
- package/dist/protocol-types.d.ts +5 -8
- package/dist/protocol-types.d.ts.map +1 -1
- package/dist/protocol-types.js +3 -6
- package/dist/protocol.d.ts +2 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +10 -2
- package/dist/react.d.ts +2 -15
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +43 -38
- package/dist/{size-advertiser.d.ts → size-anchor.d.ts} +6 -5
- package/dist/size-anchor.d.ts.map +1 -0
- package/dist/size-anchor.js +131 -0
- package/dist/types.d.ts +26 -32
- package/dist/types.d.ts.map +1 -1
- package/dist/view-anchor.d.ts +52 -33
- package/dist/view-anchor.d.ts.map +1 -1
- package/dist/view-anchor.js +186 -265
- package/docs/bidirectional-design.md +29 -34
- package/docs/index.html +656 -366
- package/docs/mechanism.md +35 -57
- package/docs/performance-report.md +12 -54
- package/docs/protocol.md +12 -3
- package/package.json +4 -6
- package/src/index.ts +5 -19
- package/src/protocol-publisher.ts +10 -16
- package/src/protocol-types.ts +5 -8
- package/src/protocol.ts +13 -7
- package/src/react.ts +51 -64
- package/src/size-anchor.ts +131 -0
- package/src/types.ts +29 -37
- package/src/view-anchor.ts +221 -287
- package/dist/measure-loop.d.ts +0 -24
- package/dist/measure-loop.d.ts.map +0 -1
- package/dist/measure-loop.js +0 -89
- package/dist/size-advertiser.d.ts.map +0 -1
- package/dist/size-advertiser.js +0 -94
- package/src/measure-loop.ts +0 -101
- package/src/size-advertiser.ts +0 -108
package/dist/measure-loop.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal helper: animation-frame scheduling and deduplication loop for
|
|
3
|
-
* `createSizeAdvertiser`.
|
|
4
|
-
*
|
|
5
|
-
* Coalesces resize triggers into a single requestAnimationFrame, drops
|
|
6
|
-
* duplicate measurements, and manages disposal.
|
|
7
|
-
*/
|
|
8
|
-
export interface MeasureLoop<T> {
|
|
9
|
-
schedule(): void;
|
|
10
|
-
emitNow(value: T): void;
|
|
11
|
-
setActive(on: boolean): void;
|
|
12
|
-
cancel(): void;
|
|
13
|
-
dispose(): void;
|
|
14
|
-
}
|
|
15
|
-
export declare function createMeasureLoop<T>(cfg: {
|
|
16
|
-
/**
|
|
17
|
-
* Produce the value to emit in the animation frame. Return null to skip
|
|
18
|
-
* the frame (e.g. for non-finite measurements).
|
|
19
|
-
*/
|
|
20
|
-
produce: () => T | null;
|
|
21
|
-
same: (a: T, b: T) => boolean;
|
|
22
|
-
sink: import('./types.js').Publisher<T>;
|
|
23
|
-
}): MeasureLoop<T>;
|
|
24
|
-
//# sourceMappingURL=measure-loop.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"measure-loop.d.ts","sourceRoot":"","sources":["../src/measure-loop.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,QAAQ,IAAI,IAAI,CAAA;IAChB,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IACvB,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAA;IAC5B,MAAM,IAAI,IAAI,CAAA;IACd,OAAO,IAAI,IAAI,CAAA;CAChB;AASD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE;IACxC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;IAC7B,IAAI,EAAE,OAAO,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;CACxC,GAAG,WAAW,CAAC,CAAC,CAAC,CAqEjB"}
|
package/dist/measure-loop.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal helper: animation-frame scheduling and deduplication loop for
|
|
3
|
-
* `createSizeAdvertiser`.
|
|
4
|
-
*
|
|
5
|
-
* Coalesces resize triggers into a single requestAnimationFrame, drops
|
|
6
|
-
* duplicate measurements, and manages disposal.
|
|
7
|
-
*/
|
|
8
|
-
// Terminal-state stand-ins for cfg.produce/same/sink so a retained handle's
|
|
9
|
-
// dispose()d loop does not keep the original closures (or what they
|
|
10
|
-
// captured) alive. Guarded call sites never actually reach these.
|
|
11
|
-
const NOOP_PRODUCE = () => null;
|
|
12
|
-
const NOOP_SAME = () => true;
|
|
13
|
-
const NOOP_SINK = () => false;
|
|
14
|
-
export function createMeasureLoop(cfg) {
|
|
15
|
-
let produce = cfg.produce;
|
|
16
|
-
let same = cfg.same;
|
|
17
|
-
let sink = cfg.sink;
|
|
18
|
-
let rafId = null;
|
|
19
|
-
let active = false;
|
|
20
|
-
let disposed = false;
|
|
21
|
-
let last = null;
|
|
22
|
-
let publicationRevision = 0;
|
|
23
|
-
const deliver = (value) => {
|
|
24
|
-
// A reentrant dispose() from produce()/same() (invoked by frame() just
|
|
25
|
-
// before this call) already cleared `last`; do not let this delivery
|
|
26
|
-
// attempt write over that terminal state.
|
|
27
|
-
if (disposed)
|
|
28
|
-
return false;
|
|
29
|
-
const previous = last;
|
|
30
|
-
const attempt = ++publicationRevision;
|
|
31
|
-
last = value;
|
|
32
|
-
try {
|
|
33
|
-
const accepted = sink(value) !== false;
|
|
34
|
-
// A reentrant dispose() during sink() already cleared `last`; do not
|
|
35
|
-
// resurrect the pre-dispose value over that terminal state.
|
|
36
|
-
if (!accepted && publicationRevision === attempt && !disposed)
|
|
37
|
-
last = previous;
|
|
38
|
-
return accepted;
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
if (publicationRevision === attempt && !disposed)
|
|
42
|
-
last = previous;
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const cancel = () => {
|
|
47
|
-
if (rafId !== null) {
|
|
48
|
-
cancelAnimationFrame(rafId);
|
|
49
|
-
rafId = null;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
const frame = () => {
|
|
53
|
-
rafId = null;
|
|
54
|
-
if (disposed || !active)
|
|
55
|
-
return;
|
|
56
|
-
const value = produce();
|
|
57
|
-
if (value === null)
|
|
58
|
-
return;
|
|
59
|
-
if (last !== null && same(value, last))
|
|
60
|
-
return;
|
|
61
|
-
deliver(value);
|
|
62
|
-
};
|
|
63
|
-
return {
|
|
64
|
-
schedule() {
|
|
65
|
-
if (disposed || !active || rafId !== null)
|
|
66
|
-
return;
|
|
67
|
-
rafId = requestAnimationFrame(frame);
|
|
68
|
-
},
|
|
69
|
-
emitNow(value) {
|
|
70
|
-
if (disposed)
|
|
71
|
-
return;
|
|
72
|
-
deliver(value);
|
|
73
|
-
},
|
|
74
|
-
setActive(on) {
|
|
75
|
-
active = on;
|
|
76
|
-
},
|
|
77
|
-
cancel,
|
|
78
|
-
dispose() {
|
|
79
|
-
if (disposed)
|
|
80
|
-
return;
|
|
81
|
-
disposed = true;
|
|
82
|
-
cancel();
|
|
83
|
-
produce = NOOP_PRODUCE;
|
|
84
|
-
same = NOOP_SAME;
|
|
85
|
-
sink = NOOP_SINK;
|
|
86
|
-
last = null;
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"size-advertiser.d.ts","sourceRoot":"","sources":["../src/size-advertiser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,YAAY,CAAA;AAQnB;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,qBAAqB,GAC1B,oBAAoB,CA8EtB"}
|
package/dist/size-advertiser.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { watchAbort } from './abort.js';
|
|
2
|
-
import { createMeasureLoop } from './measure-loop.js';
|
|
3
|
-
// Replaces a disposed instance's publish callback so a retained handle does
|
|
4
|
-
// not keep the caller's original callback (and whatever it captured) alive.
|
|
5
|
-
const NOOP_PUBLISH = () => false;
|
|
6
|
-
/**
|
|
7
|
-
* Report content size for a single axis back to the host.
|
|
8
|
-
*
|
|
9
|
-
* Runs in a downstream document, reads the content size from
|
|
10
|
-
* `ResizeObserverEntry.borderBoxSize` without triggering reflow, and
|
|
11
|
-
* publishes updates through an animation frame loop (`createMeasureLoop`).
|
|
12
|
-
*
|
|
13
|
-
* Measurements are rounded to integer pixels and clamped to >= 0.
|
|
14
|
-
*
|
|
15
|
-
* Note: `target` should be a shrink-to-fit wrapper on the owned axis.
|
|
16
|
-
* If its size is driven by the host view itself (such as `<body>` or `<html>`),
|
|
17
|
-
* updates will not shrink back to content size.
|
|
18
|
-
*/
|
|
19
|
-
export function createSizeAdvertiser(target, opts) {
|
|
20
|
-
const axis = opts.axis;
|
|
21
|
-
let publish = opts.publish;
|
|
22
|
-
let observer = null;
|
|
23
|
-
let disposed = false;
|
|
24
|
-
// Latest border-box recorded by the ResizeObserver callback.
|
|
25
|
-
let latest = null;
|
|
26
|
-
const produce = () => {
|
|
27
|
-
if (!latest)
|
|
28
|
-
return null;
|
|
29
|
-
const raw = axis === 'block' ? latest.blockSize : latest.inlineSize;
|
|
30
|
-
if (!Number.isFinite(raw))
|
|
31
|
-
return null;
|
|
32
|
-
return Math.max(0, Math.round(raw));
|
|
33
|
-
};
|
|
34
|
-
const loop = createMeasureLoop({
|
|
35
|
-
produce,
|
|
36
|
-
same: (a, b) => a === b,
|
|
37
|
-
sink: (extent) => publish({ axis, extent }),
|
|
38
|
-
});
|
|
39
|
-
const onResize = (entries) => {
|
|
40
|
-
// A callback queued before disconnect() can still fire once more; do not
|
|
41
|
-
// let it write `latest` after dispose() has already cleared it.
|
|
42
|
-
if (disposed)
|
|
43
|
-
return;
|
|
44
|
-
const entry = entries[entries.length - 1];
|
|
45
|
-
if (entry) {
|
|
46
|
-
latest = entry.borderBoxSize?.[0] ?? entry.contentBoxSize?.[0] ?? latest;
|
|
47
|
-
}
|
|
48
|
-
loop.schedule();
|
|
49
|
-
};
|
|
50
|
-
// Warn if measuring body or documentElement, whose size matches the view.
|
|
51
|
-
const doc = target.ownerDocument;
|
|
52
|
-
if (target === doc.body || target === doc.documentElement) {
|
|
53
|
-
console.warn(`[view-anchor] size-advertiser: <${target === doc.body ? 'body' : 'html'}>'s ` +
|
|
54
|
-
`${axis} size is the view size, not content size. The advertiser will ` +
|
|
55
|
-
`never shrink to content; measure a shrink-to-fit wrapper instead.`);
|
|
56
|
-
}
|
|
57
|
-
let removeAbortListener = () => { };
|
|
58
|
-
const dispose = () => {
|
|
59
|
-
if (disposed)
|
|
60
|
-
return;
|
|
61
|
-
disposed = true;
|
|
62
|
-
removeAbortListener();
|
|
63
|
-
removeAbortListener = () => { };
|
|
64
|
-
loop.cancel();
|
|
65
|
-
if (observer) {
|
|
66
|
-
observer.disconnect();
|
|
67
|
-
observer = null;
|
|
68
|
-
}
|
|
69
|
-
loop.dispose();
|
|
70
|
-
publish = NOOP_PUBLISH;
|
|
71
|
-
latest = null;
|
|
72
|
-
};
|
|
73
|
-
if (opts.signal?.aborted)
|
|
74
|
-
dispose();
|
|
75
|
-
else {
|
|
76
|
-
removeAbortListener = watchAbort(opts.signal, dispose);
|
|
77
|
-
loop.setActive(true);
|
|
78
|
-
observer = new ResizeObserver(onResize);
|
|
79
|
-
observer.observe(target);
|
|
80
|
-
}
|
|
81
|
-
return {
|
|
82
|
-
update(nextPublish) {
|
|
83
|
-
if (disposed)
|
|
84
|
-
return;
|
|
85
|
-
publish = nextPublish;
|
|
86
|
-
// Re-publish the current size to the new sink immediately so it is not
|
|
87
|
-
// empty until the next ResizeObserver tick.
|
|
88
|
-
const cur = produce();
|
|
89
|
-
if (cur !== null)
|
|
90
|
-
loop.emitNow(cur);
|
|
91
|
-
},
|
|
92
|
-
dispose,
|
|
93
|
-
};
|
|
94
|
-
}
|
package/src/measure-loop.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal helper: animation-frame scheduling and deduplication loop for
|
|
3
|
-
* `createSizeAdvertiser`.
|
|
4
|
-
*
|
|
5
|
-
* Coalesces resize triggers into a single requestAnimationFrame, drops
|
|
6
|
-
* duplicate measurements, and manages disposal.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export interface MeasureLoop<T> {
|
|
10
|
-
schedule(): void
|
|
11
|
-
emitNow(value: T): void
|
|
12
|
-
setActive(on: boolean): void
|
|
13
|
-
cancel(): void
|
|
14
|
-
dispose(): void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Terminal-state stand-ins for cfg.produce/same/sink so a retained handle's
|
|
18
|
-
// dispose()d loop does not keep the original closures (or what they
|
|
19
|
-
// captured) alive. Guarded call sites never actually reach these.
|
|
20
|
-
const NOOP_PRODUCE = (): null => null
|
|
21
|
-
const NOOP_SAME = (): true => true
|
|
22
|
-
const NOOP_SINK = (): false => false
|
|
23
|
-
|
|
24
|
-
export function createMeasureLoop<T>(cfg: {
|
|
25
|
-
/**
|
|
26
|
-
* Produce the value to emit in the animation frame. Return null to skip
|
|
27
|
-
* the frame (e.g. for non-finite measurements).
|
|
28
|
-
*/
|
|
29
|
-
produce: () => T | null
|
|
30
|
-
same: (a: T, b: T) => boolean
|
|
31
|
-
sink: import('./types.js').Publisher<T>
|
|
32
|
-
}): MeasureLoop<T> {
|
|
33
|
-
let produce = cfg.produce
|
|
34
|
-
let same = cfg.same
|
|
35
|
-
let sink = cfg.sink
|
|
36
|
-
let rafId: number | null = null
|
|
37
|
-
let active = false
|
|
38
|
-
let disposed = false
|
|
39
|
-
let last: T | null = null
|
|
40
|
-
let publicationRevision = 0
|
|
41
|
-
|
|
42
|
-
const deliver = (value: T): boolean => {
|
|
43
|
-
// A reentrant dispose() from produce()/same() (invoked by frame() just
|
|
44
|
-
// before this call) already cleared `last`; do not let this delivery
|
|
45
|
-
// attempt write over that terminal state.
|
|
46
|
-
if (disposed) return false
|
|
47
|
-
const previous = last
|
|
48
|
-
const attempt = ++publicationRevision
|
|
49
|
-
last = value
|
|
50
|
-
try {
|
|
51
|
-
const accepted = sink(value) !== false
|
|
52
|
-
// A reentrant dispose() during sink() already cleared `last`; do not
|
|
53
|
-
// resurrect the pre-dispose value over that terminal state.
|
|
54
|
-
if (!accepted && publicationRevision === attempt && !disposed) last = previous
|
|
55
|
-
return accepted
|
|
56
|
-
} catch (error) {
|
|
57
|
-
if (publicationRevision === attempt && !disposed) last = previous
|
|
58
|
-
throw error
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const cancel = (): void => {
|
|
63
|
-
if (rafId !== null) {
|
|
64
|
-
cancelAnimationFrame(rafId)
|
|
65
|
-
rafId = null
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const frame = (): void => {
|
|
70
|
-
rafId = null
|
|
71
|
-
if (disposed || !active) return
|
|
72
|
-
const value = produce()
|
|
73
|
-
if (value === null) return
|
|
74
|
-
if (last !== null && same(value, last)) return
|
|
75
|
-
deliver(value)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
schedule(): void {
|
|
80
|
-
if (disposed || !active || rafId !== null) return
|
|
81
|
-
rafId = requestAnimationFrame(frame)
|
|
82
|
-
},
|
|
83
|
-
emitNow(value: T): void {
|
|
84
|
-
if (disposed) return
|
|
85
|
-
deliver(value)
|
|
86
|
-
},
|
|
87
|
-
setActive(on: boolean): void {
|
|
88
|
-
active = on
|
|
89
|
-
},
|
|
90
|
-
cancel,
|
|
91
|
-
dispose(): void {
|
|
92
|
-
if (disposed) return
|
|
93
|
-
disposed = true
|
|
94
|
-
cancel()
|
|
95
|
-
produce = NOOP_PRODUCE
|
|
96
|
-
same = NOOP_SAME
|
|
97
|
-
sink = NOOP_SINK
|
|
98
|
-
last = null
|
|
99
|
-
},
|
|
100
|
-
}
|
|
101
|
-
}
|
package/src/size-advertiser.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AdvertisedSize,
|
|
3
|
-
Publisher,
|
|
4
|
-
SizeAdvertiserOptions,
|
|
5
|
-
SizeAdvertiserHandle,
|
|
6
|
-
} from './types.js'
|
|
7
|
-
import { watchAbort } from './abort.js'
|
|
8
|
-
import { createMeasureLoop } from './measure-loop.js'
|
|
9
|
-
|
|
10
|
-
// Replaces a disposed instance's publish callback so a retained handle does
|
|
11
|
-
// not keep the caller's original callback (and whatever it captured) alive.
|
|
12
|
-
const NOOP_PUBLISH = (): false => false
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Report content size for a single axis back to the host.
|
|
16
|
-
*
|
|
17
|
-
* Runs in a downstream document, reads the content size from
|
|
18
|
-
* `ResizeObserverEntry.borderBoxSize` without triggering reflow, and
|
|
19
|
-
* publishes updates through an animation frame loop (`createMeasureLoop`).
|
|
20
|
-
*
|
|
21
|
-
* Measurements are rounded to integer pixels and clamped to >= 0.
|
|
22
|
-
*
|
|
23
|
-
* Note: `target` should be a shrink-to-fit wrapper on the owned axis.
|
|
24
|
-
* If its size is driven by the host view itself (such as `<body>` or `<html>`),
|
|
25
|
-
* updates will not shrink back to content size.
|
|
26
|
-
*/
|
|
27
|
-
export function createSizeAdvertiser(
|
|
28
|
-
target: HTMLElement,
|
|
29
|
-
opts: SizeAdvertiserOptions,
|
|
30
|
-
): SizeAdvertiserHandle {
|
|
31
|
-
const axis = opts.axis
|
|
32
|
-
let publish = opts.publish
|
|
33
|
-
let observer: ResizeObserver | null = null
|
|
34
|
-
let disposed = false
|
|
35
|
-
// Latest border-box recorded by the ResizeObserver callback.
|
|
36
|
-
let latest: ResizeObserverSize | null = null
|
|
37
|
-
|
|
38
|
-
const produce = (): number | null => {
|
|
39
|
-
if (!latest) return null
|
|
40
|
-
const raw = axis === 'block' ? latest.blockSize : latest.inlineSize
|
|
41
|
-
if (!Number.isFinite(raw)) return null
|
|
42
|
-
return Math.max(0, Math.round(raw))
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const loop = createMeasureLoop<number>({
|
|
46
|
-
produce,
|
|
47
|
-
same: (a, b) => a === b,
|
|
48
|
-
sink: (extent) => publish({ axis, extent }),
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
const onResize: ResizeObserverCallback = (entries) => {
|
|
52
|
-
// A callback queued before disconnect() can still fire once more; do not
|
|
53
|
-
// let it write `latest` after dispose() has already cleared it.
|
|
54
|
-
if (disposed) return
|
|
55
|
-
const entry = entries[entries.length - 1]
|
|
56
|
-
if (entry) {
|
|
57
|
-
latest = entry.borderBoxSize?.[0] ?? entry.contentBoxSize?.[0] ?? latest
|
|
58
|
-
}
|
|
59
|
-
loop.schedule()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Warn if measuring body or documentElement, whose size matches the view.
|
|
63
|
-
const doc = target.ownerDocument
|
|
64
|
-
if (target === doc.body || target === doc.documentElement) {
|
|
65
|
-
console.warn(
|
|
66
|
-
`[view-anchor] size-advertiser: <${target === doc.body ? 'body' : 'html'}>'s ` +
|
|
67
|
-
`${axis} size is the view size, not content size. The advertiser will ` +
|
|
68
|
-
`never shrink to content; measure a shrink-to-fit wrapper instead.`,
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let removeAbortListener = (): void => {}
|
|
73
|
-
|
|
74
|
-
const dispose = (): void => {
|
|
75
|
-
if (disposed) return
|
|
76
|
-
disposed = true
|
|
77
|
-
removeAbortListener()
|
|
78
|
-
removeAbortListener = (): void => {}
|
|
79
|
-
loop.cancel()
|
|
80
|
-
if (observer) {
|
|
81
|
-
observer.disconnect()
|
|
82
|
-
observer = null
|
|
83
|
-
}
|
|
84
|
-
loop.dispose()
|
|
85
|
-
publish = NOOP_PUBLISH
|
|
86
|
-
latest = null
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (opts.signal?.aborted) dispose()
|
|
90
|
-
else {
|
|
91
|
-
removeAbortListener = watchAbort(opts.signal, dispose)
|
|
92
|
-
loop.setActive(true)
|
|
93
|
-
observer = new ResizeObserver(onResize)
|
|
94
|
-
observer.observe(target)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
update(nextPublish: Publisher<AdvertisedSize>): void {
|
|
99
|
-
if (disposed) return
|
|
100
|
-
publish = nextPublish
|
|
101
|
-
// Re-publish the current size to the new sink immediately so it is not
|
|
102
|
-
// empty until the next ResizeObserver tick.
|
|
103
|
-
const cur = produce()
|
|
104
|
-
if (cur !== null) loop.emitNow(cur)
|
|
105
|
-
},
|
|
106
|
-
dispose,
|
|
107
|
-
}
|
|
108
|
-
}
|