@getuserfeedback/protocol 3.0.10 → 3.0.12
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/host/widget-layout-transition-plan.d.ts +19 -4
- package/dist/host/widget-layout-transition-plan.d.ts.map +1 -1
- package/dist/host/widget-layout-transition-plan.js +40 -8
- package/package.json +2 -2
- package/src/host/widget-layout-transition-plan.test.ts +133 -0
- package/src/host/widget-layout-transition-plan.ts +90 -13
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { WidgetLayoutSize, WidgetLayoutSizeUpdate, WidgetLayoutTimedSizeUpdate } from "./widget-layout-size-update.js";
|
|
2
2
|
export type WidgetLayoutComparableSizeUpdate = WidgetLayoutSizeUpdate | WidgetLayoutTimedSizeUpdate;
|
|
3
|
-
export type WidgetLayoutUnchangedTransitionPlan = {
|
|
3
|
+
export type WidgetLayoutUnchangedTransitionPlan<Update extends WidgetLayoutComparableSizeUpdate = WidgetLayoutComparableSizeUpdate> = {
|
|
4
4
|
kind: "unchanged";
|
|
5
5
|
size: WidgetLayoutSize;
|
|
6
|
-
update:
|
|
6
|
+
update: Update;
|
|
7
7
|
observedAtMs: number;
|
|
8
8
|
};
|
|
9
9
|
export type WidgetLayoutInstantTransitionPlan = {
|
|
@@ -13,11 +13,26 @@ export type WidgetLayoutInstantTransitionPlan = {
|
|
|
13
13
|
startedAtMs: number;
|
|
14
14
|
settledAtMs: number;
|
|
15
15
|
};
|
|
16
|
-
export type
|
|
16
|
+
export type WidgetLayoutTimedTransitionPlan = {
|
|
17
|
+
kind: "timed";
|
|
18
|
+
size: WidgetLayoutSize;
|
|
19
|
+
update: WidgetLayoutTimedSizeUpdate;
|
|
20
|
+
startedAtMs: number;
|
|
21
|
+
settledAtMs: number;
|
|
22
|
+
};
|
|
23
|
+
export type WidgetLayoutInstantOnlyTransitionPlan = WidgetLayoutUnchangedTransitionPlan<WidgetLayoutSizeUpdate> | WidgetLayoutInstantTransitionPlan;
|
|
24
|
+
export type WidgetLayoutTransitionPlan = WidgetLayoutInstantOnlyTransitionPlan;
|
|
25
|
+
export type WidgetLayoutTimedCapableTransitionPlan = WidgetLayoutUnchangedTransitionPlan | WidgetLayoutInstantTransitionPlan | WidgetLayoutTimedTransitionPlan;
|
|
26
|
+
export declare function getWidgetLayoutPlanNowMs(): number;
|
|
17
27
|
export declare function areWidgetLayoutSizeUpdatesEqual(left: WidgetLayoutComparableSizeUpdate | undefined, right: WidgetLayoutComparableSizeUpdate): boolean;
|
|
18
28
|
export declare function planWidgetLayoutTransition(input: {
|
|
19
29
|
previous?: WidgetLayoutSizeUpdate;
|
|
20
30
|
next: WidgetLayoutSizeUpdate;
|
|
21
31
|
nowMs: number;
|
|
22
|
-
}):
|
|
32
|
+
}): WidgetLayoutInstantOnlyTransitionPlan;
|
|
33
|
+
export declare function planWidgetLayoutTransition(input: {
|
|
34
|
+
previous?: WidgetLayoutComparableSizeUpdate;
|
|
35
|
+
next: WidgetLayoutComparableSizeUpdate;
|
|
36
|
+
nowMs: number;
|
|
37
|
+
}): WidgetLayoutTimedCapableTransitionPlan;
|
|
23
38
|
//# sourceMappingURL=widget-layout-transition-plan.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-layout-transition-plan.d.ts","sourceRoot":"","sources":["../../src/host/widget-layout-transition-plan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,gCAAgC,CAAC;AAExC,MAAM,MAAM,gCAAgC,GACzC,sBAAsB,GACtB,2BAA2B,CAAC;AAE/B,MAAM,MAAM,mCAAmC,GAAG;
|
|
1
|
+
{"version":3,"file":"widget-layout-transition-plan.d.ts","sourceRoot":"","sources":["../../src/host/widget-layout-transition-plan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,gCAAgC,CAAC;AAExC,MAAM,MAAM,gCAAgC,GACzC,sBAAsB,GACtB,2BAA2B,CAAC;AAE/B,MAAM,MAAM,mCAAmC,CAC9C,MAAM,SACL,gCAAgC,GAAG,gCAAgC,IACjE;IACH,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC/C,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC7C,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,2BAA2B,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAC9C,mCAAmC,CAAC,sBAAsB,CAAC,GAC3D,iCAAiC,CAAC;AAErC,MAAM,MAAM,0BAA0B,GAAG,qCAAqC,CAAC;AAE/E,MAAM,MAAM,sCAAsC,GAC/C,mCAAmC,GACnC,iCAAiC,GACjC,+BAA+B,CAAC;AAEnC,wBAAgB,wBAAwB,IAAI,MAAM,CAQjD;AAED,wBAAgB,+BAA+B,CAC9C,IAAI,EAAE,gCAAgC,GAAG,SAAS,EAClD,KAAK,EAAE,gCAAgC,GACrC,OAAO,CAiCT;AAsCD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IACjD,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;CACd,GAAG,qCAAqC,CAAC;AAC1C,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IACjD,QAAQ,CAAC,EAAE,gCAAgC,CAAC;IAC5C,IAAI,EAAE,gCAAgC,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC;CACd,GAAG,sCAAsC,CAAC"}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
export function getWidgetLayoutPlanNowMs() {
|
|
2
|
+
const performanceNow = typeof globalThis.performance?.now === "function"
|
|
3
|
+
? globalThis.performance.now()
|
|
4
|
+
: undefined;
|
|
5
|
+
return typeof performanceNow === "number" && Number.isFinite(performanceNow)
|
|
6
|
+
? performanceNow
|
|
7
|
+
: Date.now();
|
|
8
|
+
}
|
|
1
9
|
export function areWidgetLayoutSizeUpdatesEqual(left, right) {
|
|
2
10
|
if (left?.size.width !== right.size.width ||
|
|
3
11
|
left.size.height !== right.size.height ||
|
|
@@ -24,6 +32,27 @@ export function areWidgetLayoutSizeUpdatesEqual(left, right) {
|
|
|
24
32
|
}
|
|
25
33
|
}
|
|
26
34
|
}
|
|
35
|
+
function cloneWidgetLayoutSizeUpdate(update) {
|
|
36
|
+
if (update.transition.kind === "timed") {
|
|
37
|
+
return {
|
|
38
|
+
size: { ...update.size },
|
|
39
|
+
transition: {
|
|
40
|
+
...update.transition,
|
|
41
|
+
easing: {
|
|
42
|
+
...update.transition.easing,
|
|
43
|
+
points: [...update.transition.easing.points],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
size: { ...update.size },
|
|
50
|
+
transition: { ...update.transition },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function isWidgetLayoutTimedSizeUpdate(update) {
|
|
54
|
+
return update.transition.kind === "timed";
|
|
55
|
+
}
|
|
27
56
|
export function planWidgetLayoutTransition(input) {
|
|
28
57
|
if (!Number.isFinite(input.nowMs)) {
|
|
29
58
|
throw new RangeError("Widget layout transition plans require finite nowMs");
|
|
@@ -32,20 +61,23 @@ export function planWidgetLayoutTransition(input) {
|
|
|
32
61
|
return {
|
|
33
62
|
kind: "unchanged",
|
|
34
63
|
size: { ...input.next.size },
|
|
35
|
-
update:
|
|
36
|
-
size: { ...input.next.size },
|
|
37
|
-
transition: { ...input.next.transition },
|
|
38
|
-
},
|
|
64
|
+
update: cloneWidgetLayoutSizeUpdate(input.next),
|
|
39
65
|
observedAtMs: input.nowMs,
|
|
40
66
|
};
|
|
41
67
|
}
|
|
68
|
+
if (isWidgetLayoutTimedSizeUpdate(input.next)) {
|
|
69
|
+
return {
|
|
70
|
+
kind: "timed",
|
|
71
|
+
size: { ...input.next.size },
|
|
72
|
+
update: cloneWidgetLayoutSizeUpdate(input.next),
|
|
73
|
+
startedAtMs: input.nowMs,
|
|
74
|
+
settledAtMs: input.nowMs + input.next.transition.durationMs,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
42
77
|
return {
|
|
43
78
|
kind: "instant",
|
|
44
79
|
size: { ...input.next.size },
|
|
45
|
-
update:
|
|
46
|
-
size: { ...input.next.size },
|
|
47
|
-
transition: { ...input.next.transition },
|
|
48
|
-
},
|
|
80
|
+
update: cloneWidgetLayoutSizeUpdate(input.next),
|
|
49
81
|
startedAtMs: input.nowMs,
|
|
50
82
|
settledAtMs: input.nowMs,
|
|
51
83
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getuserfeedback/protocol",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.12",
|
|
4
4
|
"description": "getuserfeedback widget protocol — host surface and (later) wire protocol",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"getuserfeedback",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
},
|
|
134
134
|
"scripts": {
|
|
135
135
|
"lint": "ultracite check .",
|
|
136
|
-
"build": "bun ../../scripts/clean-build-output.ts dist tsconfig.tsbuildinfo && tsc -b tsconfig.json",
|
|
136
|
+
"build": "bun ../../scripts/clean-build-output.ts dist tsconfig.tsbuildinfo && tsc -b tsconfig.json && bun scripts/verify-dist-js.ts",
|
|
137
137
|
"types": "bun ../../scripts/clean-build-output.ts dist tsconfig.tsbuildinfo && tsc -b tsconfig.json --emitDeclarationOnly",
|
|
138
138
|
"typecheck": "tsc -b tsconfig.json",
|
|
139
139
|
"test": "bun test --dots",
|
|
@@ -5,13 +5,95 @@ import {
|
|
|
5
5
|
} from "./widget-layout-size-update.js";
|
|
6
6
|
import {
|
|
7
7
|
areWidgetLayoutSizeUpdatesEqual,
|
|
8
|
+
getWidgetLayoutPlanNowMs,
|
|
8
9
|
planWidgetLayoutTransition,
|
|
10
|
+
type WidgetLayoutInstantOnlyTransitionPlan,
|
|
11
|
+
type WidgetLayoutTransitionPlan,
|
|
9
12
|
} from "./widget-layout-transition-plan.js";
|
|
10
13
|
|
|
11
14
|
describe("widget layout transition plan", () => {
|
|
15
|
+
function expectInstantOnlyPlan(
|
|
16
|
+
_plan: WidgetLayoutInstantOnlyTransitionPlan,
|
|
17
|
+
): void {}
|
|
18
|
+
function expectLegacyTransitionPlan(
|
|
19
|
+
_plan: WidgetLayoutTransitionPlan,
|
|
20
|
+
): void {}
|
|
21
|
+
|
|
22
|
+
test("uses the browser monotonic clock for layout plan timestamps", () => {
|
|
23
|
+
const originalPerformanceDescriptor = Object.getOwnPropertyDescriptor(
|
|
24
|
+
globalThis,
|
|
25
|
+
"performance",
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
Object.defineProperty(globalThis, "performance", {
|
|
30
|
+
configurable: true,
|
|
31
|
+
value: {
|
|
32
|
+
now: () => 123.45,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(getWidgetLayoutPlanNowMs()).toBe(123.45);
|
|
37
|
+
} finally {
|
|
38
|
+
if (originalPerformanceDescriptor) {
|
|
39
|
+
Object.defineProperty(
|
|
40
|
+
globalThis,
|
|
41
|
+
"performance",
|
|
42
|
+
originalPerformanceDescriptor,
|
|
43
|
+
);
|
|
44
|
+
} else {
|
|
45
|
+
Reflect.deleteProperty(globalThis, "performance");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("falls back to Date.now when the monotonic clock is unavailable", () => {
|
|
51
|
+
const originalNow = Date.now;
|
|
52
|
+
const originalPerformanceDescriptor = Object.getOwnPropertyDescriptor(
|
|
53
|
+
globalThis,
|
|
54
|
+
"performance",
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
Date.now = () => 1_700;
|
|
59
|
+
Object.defineProperty(globalThis, "performance", {
|
|
60
|
+
configurable: true,
|
|
61
|
+
value: {
|
|
62
|
+
now: () => Number.NaN,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(getWidgetLayoutPlanNowMs()).toBe(1_700);
|
|
67
|
+
} finally {
|
|
68
|
+
Date.now = originalNow;
|
|
69
|
+
if (originalPerformanceDescriptor) {
|
|
70
|
+
Object.defineProperty(
|
|
71
|
+
globalThis,
|
|
72
|
+
"performance",
|
|
73
|
+
originalPerformanceDescriptor,
|
|
74
|
+
);
|
|
75
|
+
} else {
|
|
76
|
+
Reflect.deleteProperty(globalThis, "performance");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
12
81
|
test("plans the first instant layout update at the requested time", () => {
|
|
13
82
|
const next = toInstantWidgetLayoutSizeUpdate({ width: 320, height: 240 });
|
|
14
83
|
|
|
84
|
+
expectInstantOnlyPlan(
|
|
85
|
+
planWidgetLayoutTransition({
|
|
86
|
+
next,
|
|
87
|
+
nowMs: 1_000,
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
expectLegacyTransitionPlan(
|
|
91
|
+
planWidgetLayoutTransition({
|
|
92
|
+
next,
|
|
93
|
+
nowMs: 1_000,
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
|
|
15
97
|
expect(
|
|
16
98
|
planWidgetLayoutTransition({
|
|
17
99
|
next,
|
|
@@ -93,6 +175,37 @@ describe("widget layout transition plan", () => {
|
|
|
93
175
|
});
|
|
94
176
|
});
|
|
95
177
|
|
|
178
|
+
test("plans explicit timed updates with settled time from duration", () => {
|
|
179
|
+
const next = toTimedWidgetLayoutSizeUpdate({
|
|
180
|
+
size: { width: 320, height: 360 },
|
|
181
|
+
durationMs: 180,
|
|
182
|
+
easing: [0.2, 0, 0, 1],
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(
|
|
186
|
+
planWidgetLayoutTransition({
|
|
187
|
+
next,
|
|
188
|
+
nowMs: 1_500,
|
|
189
|
+
}),
|
|
190
|
+
).toEqual({
|
|
191
|
+
kind: "timed",
|
|
192
|
+
size: { width: 320, height: 360 },
|
|
193
|
+
update: {
|
|
194
|
+
size: { width: 320, height: 360 },
|
|
195
|
+
transition: {
|
|
196
|
+
kind: "timed",
|
|
197
|
+
durationMs: 180,
|
|
198
|
+
easing: {
|
|
199
|
+
kind: "cubic-bezier",
|
|
200
|
+
points: [0.2, 0, 0, 1],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
startedAtMs: 1_500,
|
|
205
|
+
settledAtMs: 1_680,
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
96
209
|
test("does not leak mutable references from the next update", () => {
|
|
97
210
|
const next = {
|
|
98
211
|
size: { width: 320, height: 240 },
|
|
@@ -111,6 +224,26 @@ describe("widget layout transition plan", () => {
|
|
|
111
224
|
expect(plan.update.transition.durationMs).toBe(0);
|
|
112
225
|
});
|
|
113
226
|
|
|
227
|
+
test("does not leak mutable timed transition points from the next update", () => {
|
|
228
|
+
const next = toTimedWidgetLayoutSizeUpdate({
|
|
229
|
+
size: { width: 320, height: 240 },
|
|
230
|
+
durationMs: 180,
|
|
231
|
+
easing: [0.2, 0, 0, 1],
|
|
232
|
+
});
|
|
233
|
+
const plan = planWidgetLayoutTransition({
|
|
234
|
+
next,
|
|
235
|
+
nowMs: 1_000,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
(next.transition.easing.points as unknown as number[])[0] = 0.4;
|
|
239
|
+
|
|
240
|
+
expect(plan.update.transition.kind).toBe("timed");
|
|
241
|
+
if (plan.update.transition.kind !== "timed") {
|
|
242
|
+
throw new Error("expected timed transition");
|
|
243
|
+
}
|
|
244
|
+
expect(plan.update.transition.easing.points).toEqual([0.2, 0, 0, 1]);
|
|
245
|
+
});
|
|
246
|
+
|
|
114
247
|
test("rejects non-finite plan time", () => {
|
|
115
248
|
expect(() =>
|
|
116
249
|
planWidgetLayoutTransition({
|
|
@@ -8,10 +8,13 @@ export type WidgetLayoutComparableSizeUpdate =
|
|
|
8
8
|
| WidgetLayoutSizeUpdate
|
|
9
9
|
| WidgetLayoutTimedSizeUpdate;
|
|
10
10
|
|
|
11
|
-
export type WidgetLayoutUnchangedTransitionPlan
|
|
11
|
+
export type WidgetLayoutUnchangedTransitionPlan<
|
|
12
|
+
Update extends
|
|
13
|
+
WidgetLayoutComparableSizeUpdate = WidgetLayoutComparableSizeUpdate,
|
|
14
|
+
> = {
|
|
12
15
|
kind: "unchanged";
|
|
13
16
|
size: WidgetLayoutSize;
|
|
14
|
-
update:
|
|
17
|
+
update: Update;
|
|
15
18
|
observedAtMs: number;
|
|
16
19
|
};
|
|
17
20
|
|
|
@@ -23,10 +26,35 @@ export type WidgetLayoutInstantTransitionPlan = {
|
|
|
23
26
|
settledAtMs: number;
|
|
24
27
|
};
|
|
25
28
|
|
|
26
|
-
export type
|
|
27
|
-
|
|
29
|
+
export type WidgetLayoutTimedTransitionPlan = {
|
|
30
|
+
kind: "timed";
|
|
31
|
+
size: WidgetLayoutSize;
|
|
32
|
+
update: WidgetLayoutTimedSizeUpdate;
|
|
33
|
+
startedAtMs: number;
|
|
34
|
+
settledAtMs: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type WidgetLayoutInstantOnlyTransitionPlan =
|
|
38
|
+
| WidgetLayoutUnchangedTransitionPlan<WidgetLayoutSizeUpdate>
|
|
28
39
|
| WidgetLayoutInstantTransitionPlan;
|
|
29
40
|
|
|
41
|
+
export type WidgetLayoutTransitionPlan = WidgetLayoutInstantOnlyTransitionPlan;
|
|
42
|
+
|
|
43
|
+
export type WidgetLayoutTimedCapableTransitionPlan =
|
|
44
|
+
| WidgetLayoutUnchangedTransitionPlan
|
|
45
|
+
| WidgetLayoutInstantTransitionPlan
|
|
46
|
+
| WidgetLayoutTimedTransitionPlan;
|
|
47
|
+
|
|
48
|
+
export function getWidgetLayoutPlanNowMs(): number {
|
|
49
|
+
const performanceNow =
|
|
50
|
+
typeof globalThis.performance?.now === "function"
|
|
51
|
+
? globalThis.performance.now()
|
|
52
|
+
: undefined;
|
|
53
|
+
return typeof performanceNow === "number" && Number.isFinite(performanceNow)
|
|
54
|
+
? performanceNow
|
|
55
|
+
: Date.now();
|
|
56
|
+
}
|
|
57
|
+
|
|
30
58
|
export function areWidgetLayoutSizeUpdatesEqual(
|
|
31
59
|
left: WidgetLayoutComparableSizeUpdate | undefined,
|
|
32
60
|
right: WidgetLayoutComparableSizeUpdate,
|
|
@@ -65,11 +93,57 @@ export function areWidgetLayoutSizeUpdatesEqual(
|
|
|
65
93
|
}
|
|
66
94
|
}
|
|
67
95
|
|
|
96
|
+
function cloneWidgetLayoutSizeUpdate(
|
|
97
|
+
update: WidgetLayoutSizeUpdate,
|
|
98
|
+
): WidgetLayoutSizeUpdate;
|
|
99
|
+
function cloneWidgetLayoutSizeUpdate(
|
|
100
|
+
update: WidgetLayoutTimedSizeUpdate,
|
|
101
|
+
): WidgetLayoutTimedSizeUpdate;
|
|
102
|
+
function cloneWidgetLayoutSizeUpdate(
|
|
103
|
+
update: WidgetLayoutComparableSizeUpdate,
|
|
104
|
+
): WidgetLayoutComparableSizeUpdate;
|
|
105
|
+
function cloneWidgetLayoutSizeUpdate(
|
|
106
|
+
update: WidgetLayoutComparableSizeUpdate,
|
|
107
|
+
): WidgetLayoutComparableSizeUpdate {
|
|
108
|
+
if (update.transition.kind === "timed") {
|
|
109
|
+
return {
|
|
110
|
+
size: { ...update.size },
|
|
111
|
+
transition: {
|
|
112
|
+
...update.transition,
|
|
113
|
+
easing: {
|
|
114
|
+
...update.transition.easing,
|
|
115
|
+
points: [...update.transition.easing.points],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
size: { ...update.size },
|
|
122
|
+
transition: { ...update.transition },
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isWidgetLayoutTimedSizeUpdate(
|
|
127
|
+
update: WidgetLayoutComparableSizeUpdate,
|
|
128
|
+
): update is WidgetLayoutTimedSizeUpdate {
|
|
129
|
+
return update.transition.kind === "timed";
|
|
130
|
+
}
|
|
131
|
+
|
|
68
132
|
export function planWidgetLayoutTransition(input: {
|
|
69
133
|
previous?: WidgetLayoutSizeUpdate;
|
|
70
134
|
next: WidgetLayoutSizeUpdate;
|
|
71
135
|
nowMs: number;
|
|
72
|
-
}):
|
|
136
|
+
}): WidgetLayoutInstantOnlyTransitionPlan;
|
|
137
|
+
export function planWidgetLayoutTransition(input: {
|
|
138
|
+
previous?: WidgetLayoutComparableSizeUpdate;
|
|
139
|
+
next: WidgetLayoutComparableSizeUpdate;
|
|
140
|
+
nowMs: number;
|
|
141
|
+
}): WidgetLayoutTimedCapableTransitionPlan;
|
|
142
|
+
export function planWidgetLayoutTransition(input: {
|
|
143
|
+
previous?: WidgetLayoutComparableSizeUpdate;
|
|
144
|
+
next: WidgetLayoutComparableSizeUpdate;
|
|
145
|
+
nowMs: number;
|
|
146
|
+
}): WidgetLayoutTimedCapableTransitionPlan {
|
|
73
147
|
if (!Number.isFinite(input.nowMs)) {
|
|
74
148
|
throw new RangeError("Widget layout transition plans require finite nowMs");
|
|
75
149
|
}
|
|
@@ -77,20 +151,23 @@ export function planWidgetLayoutTransition(input: {
|
|
|
77
151
|
return {
|
|
78
152
|
kind: "unchanged",
|
|
79
153
|
size: { ...input.next.size },
|
|
80
|
-
update:
|
|
81
|
-
size: { ...input.next.size },
|
|
82
|
-
transition: { ...input.next.transition },
|
|
83
|
-
},
|
|
154
|
+
update: cloneWidgetLayoutSizeUpdate(input.next),
|
|
84
155
|
observedAtMs: input.nowMs,
|
|
85
156
|
};
|
|
86
157
|
}
|
|
158
|
+
if (isWidgetLayoutTimedSizeUpdate(input.next)) {
|
|
159
|
+
return {
|
|
160
|
+
kind: "timed",
|
|
161
|
+
size: { ...input.next.size },
|
|
162
|
+
update: cloneWidgetLayoutSizeUpdate(input.next),
|
|
163
|
+
startedAtMs: input.nowMs,
|
|
164
|
+
settledAtMs: input.nowMs + input.next.transition.durationMs,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
87
167
|
return {
|
|
88
168
|
kind: "instant",
|
|
89
169
|
size: { ...input.next.size },
|
|
90
|
-
update:
|
|
91
|
-
size: { ...input.next.size },
|
|
92
|
-
transition: { ...input.next.transition },
|
|
93
|
-
},
|
|
170
|
+
update: cloneWidgetLayoutSizeUpdate(input.next),
|
|
94
171
|
startedAtMs: input.nowMs,
|
|
95
172
|
settledAtMs: input.nowMs,
|
|
96
173
|
};
|