@getuserfeedback/protocol 3.0.12 → 3.0.14

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.
@@ -1,4 +1,4 @@
1
- import type { WidgetLayoutSize, WidgetLayoutSizeUpdate, WidgetLayoutTimedSizeUpdate } from "./widget-layout-size-update.js";
1
+ import type { WidgetLayoutCubicBezier, WidgetLayoutSize, WidgetLayoutSizeUpdate, WidgetLayoutTimedSizeUpdate } from "./widget-layout-size-update.js";
2
2
  export type WidgetLayoutComparableSizeUpdate = WidgetLayoutSizeUpdate | WidgetLayoutTimedSizeUpdate;
3
3
  export type WidgetLayoutUnchangedTransitionPlan<Update extends WidgetLayoutComparableSizeUpdate = WidgetLayoutComparableSizeUpdate> = {
4
4
  kind: "unchanged";
@@ -23,8 +23,37 @@ export type WidgetLayoutTimedTransitionPlan = {
23
23
  export type WidgetLayoutInstantOnlyTransitionPlan = WidgetLayoutUnchangedTransitionPlan<WidgetLayoutSizeUpdate> | WidgetLayoutInstantTransitionPlan;
24
24
  export type WidgetLayoutTransitionPlan = WidgetLayoutInstantOnlyTransitionPlan;
25
25
  export type WidgetLayoutTimedCapableTransitionPlan = WidgetLayoutUnchangedTransitionPlan | WidgetLayoutInstantTransitionPlan | WidgetLayoutTimedTransitionPlan;
26
+ export type WidgetLayoutInstantTransitionPolicy = {
27
+ kind: "instant";
28
+ durationMs: 0;
29
+ };
30
+ export type WidgetLayoutTimedTransitionPolicy = {
31
+ kind: "timed";
32
+ durationMs: number;
33
+ easing: WidgetLayoutCubicBezier;
34
+ };
35
+ export type WidgetLayoutTransitionPolicy = WidgetLayoutInstantTransitionPolicy | WidgetLayoutTimedTransitionPolicy;
36
+ export declare const INSTANT_WIDGET_LAYOUT_TRANSITION_POLICY: WidgetLayoutInstantTransitionPolicy;
26
37
  export declare function getWidgetLayoutPlanNowMs(): number;
27
38
  export declare function areWidgetLayoutSizeUpdatesEqual(left: WidgetLayoutComparableSizeUpdate | undefined, right: WidgetLayoutComparableSizeUpdate): boolean;
39
+ type WidgetLayoutInstantPolicyPlanInput = {
40
+ previous?: WidgetLayoutComparableSizeUpdate;
41
+ size: WidgetLayoutSize;
42
+ nowMs: number;
43
+ transitionPolicy?: WidgetLayoutInstantTransitionPolicy;
44
+ };
45
+ type WidgetLayoutTimedCapablePolicyPlanInput = {
46
+ previous?: WidgetLayoutComparableSizeUpdate;
47
+ size: WidgetLayoutSize;
48
+ nowMs: number;
49
+ transitionPolicy: WidgetLayoutTimedTransitionPolicy;
50
+ };
51
+ type WidgetLayoutOptionalPolicyPlanInput = {
52
+ previous?: WidgetLayoutComparableSizeUpdate;
53
+ size: WidgetLayoutSize;
54
+ nowMs: number;
55
+ transitionPolicy?: WidgetLayoutTransitionPolicy;
56
+ };
28
57
  export declare function planWidgetLayoutTransition(input: {
29
58
  previous?: WidgetLayoutSizeUpdate;
30
59
  next: WidgetLayoutSizeUpdate;
@@ -35,4 +64,8 @@ export declare function planWidgetLayoutTransition(input: {
35
64
  next: WidgetLayoutComparableSizeUpdate;
36
65
  nowMs: number;
37
66
  }): WidgetLayoutTimedCapableTransitionPlan;
67
+ export declare function planWidgetLayoutTransition(input: WidgetLayoutInstantPolicyPlanInput): WidgetLayoutInstantOnlyTransitionPlan;
68
+ export declare function planWidgetLayoutTransition(input: WidgetLayoutTimedCapablePolicyPlanInput): WidgetLayoutTimedCapableTransitionPlan;
69
+ export declare function planWidgetLayoutTransition(input: WidgetLayoutOptionalPolicyPlanInput): WidgetLayoutTimedCapableTransitionPlan;
70
+ export {};
38
71
  //# 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,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
+ {"version":3,"file":"widget-layout-transition-plan.d.ts","sourceRoot":"","sources":["../../src/host/widget-layout-transition-plan.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,8 @@
1
+ import { toInstantWidgetLayoutSizeUpdate, toTimedWidgetLayoutSizeUpdate, } from "./widget-layout-size-update.js";
2
+ export const INSTANT_WIDGET_LAYOUT_TRANSITION_POLICY = {
3
+ kind: "instant",
4
+ durationMs: 0,
5
+ };
1
6
  export function getWidgetLayoutPlanNowMs() {
2
7
  const performanceNow = typeof globalThis.performance?.now === "function"
3
8
  ? globalThis.performance.now()
@@ -53,31 +58,54 @@ function cloneWidgetLayoutSizeUpdate(update) {
53
58
  function isWidgetLayoutTimedSizeUpdate(update) {
54
59
  return update.transition.kind === "timed";
55
60
  }
61
+ function toWidgetLayoutSizeUpdateForPolicy(input) {
62
+ const policy = input.policy ?? INSTANT_WIDGET_LAYOUT_TRANSITION_POLICY;
63
+ switch (policy.kind) {
64
+ case "instant":
65
+ return toInstantWidgetLayoutSizeUpdate(input.size);
66
+ case "timed":
67
+ return toTimedWidgetLayoutSizeUpdate({
68
+ size: input.size,
69
+ durationMs: policy.durationMs,
70
+ easing: policy.easing,
71
+ });
72
+ default: {
73
+ const unreachable = policy;
74
+ throw new Error(`Unsupported widget layout transition policy: ${JSON.stringify(unreachable)}`);
75
+ }
76
+ }
77
+ }
56
78
  export function planWidgetLayoutTransition(input) {
57
79
  if (!Number.isFinite(input.nowMs)) {
58
80
  throw new RangeError("Widget layout transition plans require finite nowMs");
59
81
  }
60
- if (areWidgetLayoutSizeUpdatesEqual(input.previous, input.next)) {
82
+ const next = "next" in input
83
+ ? input.next
84
+ : toWidgetLayoutSizeUpdateForPolicy({
85
+ size: input.size,
86
+ policy: input.transitionPolicy,
87
+ });
88
+ if (areWidgetLayoutSizeUpdatesEqual(input.previous, next)) {
61
89
  return {
62
90
  kind: "unchanged",
63
- size: { ...input.next.size },
64
- update: cloneWidgetLayoutSizeUpdate(input.next),
91
+ size: { ...next.size },
92
+ update: cloneWidgetLayoutSizeUpdate(next),
65
93
  observedAtMs: input.nowMs,
66
94
  };
67
95
  }
68
- if (isWidgetLayoutTimedSizeUpdate(input.next)) {
96
+ if (isWidgetLayoutTimedSizeUpdate(next)) {
69
97
  return {
70
98
  kind: "timed",
71
- size: { ...input.next.size },
72
- update: cloneWidgetLayoutSizeUpdate(input.next),
99
+ size: { ...next.size },
100
+ update: cloneWidgetLayoutSizeUpdate(next),
73
101
  startedAtMs: input.nowMs,
74
- settledAtMs: input.nowMs + input.next.transition.durationMs,
102
+ settledAtMs: input.nowMs + next.transition.durationMs,
75
103
  };
76
104
  }
77
105
  return {
78
106
  kind: "instant",
79
- size: { ...input.next.size },
80
- update: cloneWidgetLayoutSizeUpdate(input.next),
107
+ size: { ...next.size },
108
+ update: cloneWidgetLayoutSizeUpdate(next),
81
109
  startedAtMs: input.nowMs,
82
110
  settledAtMs: input.nowMs,
83
111
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/protocol",
3
- "version": "3.0.12",
3
+ "version": "3.0.14",
4
4
  "description": "getuserfeedback widget protocol — host surface and (later) wire protocol",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -132,7 +132,7 @@
132
132
  }
133
133
  },
134
134
  "scripts": {
135
- "lint": "ultracite check .",
135
+ "lint": "biome check .",
136
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",
@@ -6,8 +6,10 @@ import {
6
6
  import {
7
7
  areWidgetLayoutSizeUpdatesEqual,
8
8
  getWidgetLayoutPlanNowMs,
9
+ INSTANT_WIDGET_LAYOUT_TRANSITION_POLICY,
9
10
  planWidgetLayoutTransition,
10
11
  type WidgetLayoutInstantOnlyTransitionPlan,
12
+ type WidgetLayoutTimedCapableTransitionPlan,
11
13
  type WidgetLayoutTransitionPlan,
12
14
  } from "./widget-layout-transition-plan.js";
13
15
 
@@ -18,6 +20,9 @@ describe("widget layout transition plan", () => {
18
20
  function expectLegacyTransitionPlan(
19
21
  _plan: WidgetLayoutTransitionPlan,
20
22
  ): void {}
23
+ function expectTimedCapablePlan(
24
+ _plan: WidgetLayoutTimedCapableTransitionPlan,
25
+ ): void {}
21
26
 
22
27
  test("uses the browser monotonic clock for layout plan timestamps", () => {
23
28
  const originalPerformanceDescriptor = Object.getOwnPropertyDescriptor(
@@ -134,6 +139,44 @@ describe("widget layout transition plan", () => {
134
139
  expect(areWidgetLayoutSizeUpdatesEqual(previous, next)).toBe(true);
135
140
  });
136
141
 
142
+ test("plans size input as instant by default", () => {
143
+ const previous = toInstantWidgetLayoutSizeUpdate({
144
+ width: 320,
145
+ height: 240,
146
+ });
147
+
148
+ const plan = planWidgetLayoutTransition({
149
+ previous,
150
+ size: { width: 320, height: 360 },
151
+ nowMs: 1_500,
152
+ });
153
+ expectInstantOnlyPlan(plan);
154
+ expect(plan).toEqual({
155
+ kind: "instant",
156
+ size: { width: 320, height: 360 },
157
+ update: {
158
+ size: { width: 320, height: 360 },
159
+ transition: {
160
+ kind: "instant",
161
+ durationMs: 0,
162
+ },
163
+ },
164
+ startedAtMs: 1_500,
165
+ settledAtMs: 1_500,
166
+ });
167
+ });
168
+
169
+ test("keeps explicit instant transition policy instant-only", () => {
170
+ const plan = planWidgetLayoutTransition({
171
+ size: { width: 320, height: 360 },
172
+ nowMs: 1_500,
173
+ transitionPolicy: INSTANT_WIDGET_LAYOUT_TRANSITION_POLICY,
174
+ });
175
+
176
+ expectInstantOnlyPlan(plan);
177
+ expect(plan.kind).toBe("instant");
178
+ });
179
+
137
180
  test("compares the full timed transition shape before it is live", () => {
138
181
  const base = {
139
182
  size: { width: 320, height: 240 },
@@ -206,6 +249,51 @@ describe("widget layout transition plan", () => {
206
249
  });
207
250
  });
208
251
 
252
+ test("plans timed transition policy from size input", () => {
253
+ const plan = planWidgetLayoutTransition({
254
+ size: { width: 320, height: 360 },
255
+ nowMs: 1_500,
256
+ transitionPolicy: {
257
+ kind: "timed",
258
+ durationMs: 180,
259
+ easing: [0.2, 0, 0, 1],
260
+ },
261
+ });
262
+ expectTimedCapablePlan(plan);
263
+
264
+ expect(plan).toEqual({
265
+ kind: "timed",
266
+ size: { width: 320, height: 360 },
267
+ update: {
268
+ size: { width: 320, height: 360 },
269
+ transition: {
270
+ kind: "timed",
271
+ durationMs: 180,
272
+ easing: {
273
+ kind: "cubic-bezier",
274
+ points: [0.2, 0, 0, 1],
275
+ },
276
+ },
277
+ },
278
+ startedAtMs: 1_500,
279
+ settledAtMs: 1_680,
280
+ });
281
+ });
282
+
283
+ test("rejects invalid timed transition policy through protocol helpers", () => {
284
+ expect(() =>
285
+ planWidgetLayoutTransition({
286
+ size: { width: 320, height: 360 },
287
+ nowMs: 1_500,
288
+ transitionPolicy: {
289
+ kind: "timed",
290
+ durationMs: 0,
291
+ easing: [0.2, 0, 0, 1],
292
+ },
293
+ }),
294
+ ).toThrow(RangeError);
295
+ });
296
+
209
297
  test("does not leak mutable references from the next update", () => {
210
298
  const next = {
211
299
  size: { width: 320, height: 240 },
@@ -1,8 +1,13 @@
1
1
  import type {
2
+ WidgetLayoutCubicBezier,
2
3
  WidgetLayoutSize,
3
4
  WidgetLayoutSizeUpdate,
4
5
  WidgetLayoutTimedSizeUpdate,
5
6
  } from "./widget-layout-size-update.js";
7
+ import {
8
+ toInstantWidgetLayoutSizeUpdate,
9
+ toTimedWidgetLayoutSizeUpdate,
10
+ } from "./widget-layout-size-update.js";
6
11
 
7
12
  export type WidgetLayoutComparableSizeUpdate =
8
13
  | WidgetLayoutSizeUpdate
@@ -45,6 +50,27 @@ export type WidgetLayoutTimedCapableTransitionPlan =
45
50
  | WidgetLayoutInstantTransitionPlan
46
51
  | WidgetLayoutTimedTransitionPlan;
47
52
 
53
+ export type WidgetLayoutInstantTransitionPolicy = {
54
+ kind: "instant";
55
+ durationMs: 0;
56
+ };
57
+
58
+ export type WidgetLayoutTimedTransitionPolicy = {
59
+ kind: "timed";
60
+ durationMs: number;
61
+ easing: WidgetLayoutCubicBezier;
62
+ };
63
+
64
+ export type WidgetLayoutTransitionPolicy =
65
+ | WidgetLayoutInstantTransitionPolicy
66
+ | WidgetLayoutTimedTransitionPolicy;
67
+
68
+ export const INSTANT_WIDGET_LAYOUT_TRANSITION_POLICY: WidgetLayoutInstantTransitionPolicy =
69
+ {
70
+ kind: "instant",
71
+ durationMs: 0,
72
+ };
73
+
48
74
  export function getWidgetLayoutPlanNowMs(): number {
49
75
  const performanceNow =
50
76
  typeof globalThis.performance?.now === "function"
@@ -129,45 +155,120 @@ function isWidgetLayoutTimedSizeUpdate(
129
155
  return update.transition.kind === "timed";
130
156
  }
131
157
 
132
- export function planWidgetLayoutTransition(input: {
158
+ function toWidgetLayoutSizeUpdateForPolicy(input: {
159
+ policy: WidgetLayoutTransitionPolicy | undefined;
160
+ size: WidgetLayoutSize;
161
+ }): WidgetLayoutComparableSizeUpdate {
162
+ const policy = input.policy ?? INSTANT_WIDGET_LAYOUT_TRANSITION_POLICY;
163
+ switch (policy.kind) {
164
+ case "instant":
165
+ return toInstantWidgetLayoutSizeUpdate(input.size);
166
+ case "timed":
167
+ return toTimedWidgetLayoutSizeUpdate({
168
+ size: input.size,
169
+ durationMs: policy.durationMs,
170
+ easing: policy.easing,
171
+ });
172
+ default: {
173
+ const unreachable: never = policy;
174
+ throw new Error(
175
+ `Unsupported widget layout transition policy: ${JSON.stringify(unreachable)}`,
176
+ );
177
+ }
178
+ }
179
+ }
180
+
181
+ type WidgetLayoutInstantUpdatePlanInput = {
133
182
  previous?: WidgetLayoutSizeUpdate;
134
183
  next: WidgetLayoutSizeUpdate;
135
184
  nowMs: number;
136
- }): WidgetLayoutInstantOnlyTransitionPlan;
137
- export function planWidgetLayoutTransition(input: {
185
+ };
186
+
187
+ type WidgetLayoutTimedCapableUpdatePlanInput = {
138
188
  previous?: WidgetLayoutComparableSizeUpdate;
139
189
  next: WidgetLayoutComparableSizeUpdate;
140
190
  nowMs: number;
141
- }): WidgetLayoutTimedCapableTransitionPlan;
191
+ };
192
+
193
+ type WidgetLayoutInstantPolicyPlanInput = {
194
+ previous?: WidgetLayoutComparableSizeUpdate;
195
+ size: WidgetLayoutSize;
196
+ nowMs: number;
197
+ transitionPolicy?: WidgetLayoutInstantTransitionPolicy;
198
+ };
199
+
200
+ type WidgetLayoutTimedCapablePolicyPlanInput = {
201
+ previous?: WidgetLayoutComparableSizeUpdate;
202
+ size: WidgetLayoutSize;
203
+ nowMs: number;
204
+ transitionPolicy: WidgetLayoutTimedTransitionPolicy;
205
+ };
206
+
207
+ type WidgetLayoutOptionalPolicyPlanInput = {
208
+ previous?: WidgetLayoutComparableSizeUpdate;
209
+ size: WidgetLayoutSize;
210
+ nowMs: number;
211
+ transitionPolicy?: WidgetLayoutTransitionPolicy;
212
+ };
213
+
214
+ export function planWidgetLayoutTransition(input: {
215
+ previous?: WidgetLayoutSizeUpdate;
216
+ next: WidgetLayoutSizeUpdate;
217
+ nowMs: number;
218
+ }): WidgetLayoutInstantOnlyTransitionPlan;
142
219
  export function planWidgetLayoutTransition(input: {
143
220
  previous?: WidgetLayoutComparableSizeUpdate;
144
221
  next: WidgetLayoutComparableSizeUpdate;
145
222
  nowMs: number;
146
- }): WidgetLayoutTimedCapableTransitionPlan {
223
+ }): WidgetLayoutTimedCapableTransitionPlan;
224
+ export function planWidgetLayoutTransition(
225
+ input: WidgetLayoutInstantPolicyPlanInput,
226
+ ): WidgetLayoutInstantOnlyTransitionPlan;
227
+ export function planWidgetLayoutTransition(
228
+ input: WidgetLayoutTimedCapablePolicyPlanInput,
229
+ ): WidgetLayoutTimedCapableTransitionPlan;
230
+ export function planWidgetLayoutTransition(
231
+ input: WidgetLayoutOptionalPolicyPlanInput,
232
+ ): WidgetLayoutTimedCapableTransitionPlan;
233
+ export function planWidgetLayoutTransition(
234
+ input:
235
+ | WidgetLayoutInstantUpdatePlanInput
236
+ | WidgetLayoutTimedCapableUpdatePlanInput
237
+ | WidgetLayoutInstantPolicyPlanInput
238
+ | WidgetLayoutTimedCapablePolicyPlanInput
239
+ | WidgetLayoutOptionalPolicyPlanInput,
240
+ ): WidgetLayoutTimedCapableTransitionPlan {
147
241
  if (!Number.isFinite(input.nowMs)) {
148
242
  throw new RangeError("Widget layout transition plans require finite nowMs");
149
243
  }
150
- if (areWidgetLayoutSizeUpdatesEqual(input.previous, input.next)) {
244
+ const next =
245
+ "next" in input
246
+ ? input.next
247
+ : toWidgetLayoutSizeUpdateForPolicy({
248
+ size: input.size,
249
+ policy: input.transitionPolicy,
250
+ });
251
+ if (areWidgetLayoutSizeUpdatesEqual(input.previous, next)) {
151
252
  return {
152
253
  kind: "unchanged",
153
- size: { ...input.next.size },
154
- update: cloneWidgetLayoutSizeUpdate(input.next),
254
+ size: { ...next.size },
255
+ update: cloneWidgetLayoutSizeUpdate(next),
155
256
  observedAtMs: input.nowMs,
156
257
  };
157
258
  }
158
- if (isWidgetLayoutTimedSizeUpdate(input.next)) {
259
+ if (isWidgetLayoutTimedSizeUpdate(next)) {
159
260
  return {
160
261
  kind: "timed",
161
- size: { ...input.next.size },
162
- update: cloneWidgetLayoutSizeUpdate(input.next),
262
+ size: { ...next.size },
263
+ update: cloneWidgetLayoutSizeUpdate(next),
163
264
  startedAtMs: input.nowMs,
164
- settledAtMs: input.nowMs + input.next.transition.durationMs,
265
+ settledAtMs: input.nowMs + next.transition.durationMs,
165
266
  };
166
267
  }
167
268
  return {
168
269
  kind: "instant",
169
- size: { ...input.next.size },
170
- update: cloneWidgetLayoutSizeUpdate(input.next),
270
+ size: { ...next.size },
271
+ update: cloneWidgetLayoutSizeUpdate(next),
171
272
  startedAtMs: input.nowMs,
172
273
  settledAtMs: input.nowMs,
173
274
  };