@flighthq/node 0.3.1-next.847.2e6f8bf → 0.3.1-next.887.9f59a84

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,6 +1,7 @@
1
1
  import { createNode, getNodeRuntime } from '@flighthq/node/contract';
2
2
  import type { Node, NodeRuntime } from '@flighthq/types/contract';
3
3
 
4
+ import { addNodeChild } from './hierarchy';
4
5
  import {
5
6
  computeNodeWorldTransformRevision,
6
7
  getNodeAppearanceRevision,
@@ -41,6 +42,7 @@ describe('computeNodeWorldTransformRevision', () => {
41
42
  computeNodeWorldTransformRevision(runtime);
42
43
  expect(runtime.worldTransformUsingLocalTransformId).toBe(3);
43
44
  expect(runtime.worldTransformUsingParentTransformId).toBe(0);
45
+ expect(runtime.worldTransformId).not.toBe(0);
44
46
  });
45
47
 
46
48
  it('incorporates parent worldTransformId when provided', () => {
@@ -51,6 +53,17 @@ describe('computeNodeWorldTransformRevision', () => {
51
53
  computeNodeWorldTransformRevision(runtime, parentRuntime);
52
54
  expect(runtime.worldTransformUsingParentTransformId).toBe(7);
53
55
  });
56
+
57
+ it('assigns the next monotonic world revision on every recompute', () => {
58
+ const runtime = getEntityRuntime(node);
59
+ computeNodeWorldTransformRevision(runtime);
60
+ const first = runtime.worldTransformId;
61
+
62
+ computeNodeWorldTransformRevision(runtime);
63
+
64
+ const next = (first + 1) >>> 0;
65
+ expect(runtime.worldTransformId).toBe(next === 0 ? 1 : next);
66
+ });
54
67
  });
55
68
 
56
69
  describe('getNodeAppearanceRevision', () => {
@@ -246,6 +259,19 @@ describe('invalidateNodeWorldBounds', () => {
246
259
  expect(runtime.worldBoundsUsingWorldTransformId).toBe(-1);
247
260
  expect(runtime.worldBoundsUsingLocalBoundsId).toBe(-1);
248
261
  });
262
+
263
+ it('invalidates every ancestor whose aggregate includes the target', () => {
264
+ const parent = createTestNode();
265
+ addNodeChild(parent, node);
266
+ const parentRuntime = getEntityRuntime(parent);
267
+ parentRuntime.worldBoundsUsingWorldTransformId = 1;
268
+ parentRuntime.worldBoundsUsingLocalBoundsId = 1;
269
+
270
+ invalidateNodeWorldBounds(node);
271
+
272
+ expect(parentRuntime.worldBoundsUsingWorldTransformId).toBe(-1);
273
+ expect(parentRuntime.worldBoundsUsingLocalBoundsId).toBe(-1);
274
+ });
249
275
  });
250
276
 
251
277
  type TestNode = Node;
@@ -18,10 +18,12 @@ import {
18
18
 
19
19
  const TestNodeKind = 'TestNode';
20
20
 
21
- function makeNodeWithBounds(width: number, height: number) {
21
+ function makeNodeWithBounds(width: number, height: number, x = 0, y = 0) {
22
22
  const node = createNode(TestNodeKind);
23
23
  const runtime = getNodeRuntime(node) as unknown as HasBoundsRectangleRuntime;
24
24
  runtime.computeLocalBoundsRectangle = (out) => {
25
+ out.x = x;
26
+ out.y = y;
25
27
  out.width = width;
26
28
  out.height = height;
27
29
  };
@@ -137,6 +139,18 @@ describe('computeScene2DFitTransform', () => {
137
139
  expect(m.d).toBe(1);
138
140
  });
139
141
 
142
+ it('sets identity when only the content width is zero', () => {
143
+ const m = createMatrix(2, 3, 4, 5, 6, 7);
144
+ computeScene2DFitTransform(m, fit({ root: makeNodeWithBounds(0, 50), scaleMode: 'exactfit' }), 800, 600);
145
+ expect(m).toMatchObject({ a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 });
146
+ });
147
+
148
+ it('sets identity when only the content height is zero', () => {
149
+ const m = createMatrix(2, 3, 4, 5, 6, 7);
150
+ computeScene2DFitTransform(m, fit({ root: makeNodeWithBounds(100, 0), scaleMode: 'exactfit' }), 800, 600);
151
+ expect(m).toMatchObject({ a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 });
152
+ });
153
+
140
154
  it('noscale with topleft: identity scale at origin', () => {
141
155
  const m = createMatrix();
142
156
  computeScene2DFitTransform(
@@ -226,4 +240,45 @@ describe('computeScene2DFitTransform', () => {
226
240
  expect(m.b).toBe(0);
227
241
  expect(m.c).toBe(0);
228
242
  });
243
+
244
+ it('maps a nonzero content-bounds origin to the selected alignment', () => {
245
+ const m = createMatrix();
246
+ computeScene2DFitTransform(
247
+ m,
248
+ fit({ align: 'topleft', root: makeNodeWithBounds(100, 50, 10, -20), scaleMode: 'exactfit' }),
249
+ 200,
250
+ 100,
251
+ );
252
+
253
+ expect(m.a).toBe(2);
254
+ expect(m.d).toBe(2);
255
+ expect(m.tx).toBe(-20);
256
+ expect(m.ty).toBe(40);
257
+ });
258
+
259
+ it('uses scaled width before subtracting a nonzero origin on a centered horizontal axis', () => {
260
+ const m = createMatrix();
261
+ computeScene2DFitTransform(
262
+ m,
263
+ fit({ align: 'top', root: makeNodeWithBounds(100, 50, 10, -20), scaleMode: 'exactfit' }),
264
+ 200,
265
+ 100,
266
+ );
267
+
268
+ expect(m.tx).toBe(-20);
269
+ expect(m.ty).toBe(40);
270
+ });
271
+
272
+ it('uses scaled height before subtracting a nonzero origin on a centered vertical axis', () => {
273
+ const m = createMatrix();
274
+ computeScene2DFitTransform(
275
+ m,
276
+ fit({ align: 'left', root: makeNodeWithBounds(100, 50, 10, -20), scaleMode: 'exactfit' }),
277
+ 200,
278
+ 100,
279
+ );
280
+
281
+ expect(m.tx).toBe(-20);
282
+ expect(m.ty).toBe(40);
283
+ });
229
284
  });
@@ -196,6 +196,12 @@ describe('getNodeNextSibling', () => {
196
196
 
197
197
  expect(getNodeNextSibling(childA)).toBeNull();
198
198
  });
199
+
200
+ it('returns null for a stale parent whose nonempty child list omits the source', () => {
201
+ (getNodeRuntime(root) as NodeRuntime).children = [childB];
202
+
203
+ expect(getNodeNextSibling(childA)).toBeNull();
204
+ });
199
205
  });
200
206
 
201
207
  describe('getNodePreviousSibling', () => {