@embedpdf/core-stage 3.0.0-next.13 → 3.0.0-next.15

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/index.cjs CHANGED
@@ -9,21 +9,20 @@ let _embedpdf_core_geometry = require("@embedpdf/core-geometry");
9
9
  * (a focal point relative to a page — what survives layout/zoom changes & reloads).
10
10
  *
11
11
  * Navigation is pure camera math. Bounds/home/margin are three separate functions.
12
- * No DOM, no framework; plain-data model plus derived spatial queries (the DATA
13
- * is serializable — `Scene` also carries query methods derived from it). This
14
- * is the v4 Rust core, verbatim.
12
+ * No DOM, no framework; plain-data model plus derived spatial queries (the data
13
+ * is serializable — `Scene` also carries query methods derived from it).
15
14
  */
16
15
  /** The page's on-screen footprint: w↔h swapped for quarter-turns (via the shared
17
- * geometry primitive), scaled by its `/UserUnit` (the page's PHYSICAL size — a
16
+ * geometry primitive), scaled by its `/UserUnit` (the page's physical size — a
18
17
  * userUnit-5 page measures 5× its point size). Everything the layout packs uses
19
18
  * these display dims; the content scale (isotropic) and the renderer's
20
19
  * transform recover the content. */
21
20
  function displayDims(pg) {
22
- const u = pg.userUnit ?? 1;
23
- const d = (0, _embedpdf_core_geometry.displaySize)(pg.size, pg.rotation ?? 0);
24
- return u === 1 ? d : {
25
- width: d.width * u,
26
- height: d.height * u
21
+ const userUnit = pg.userUnit ?? 1;
22
+ const size = (0, _embedpdf_core_geometry.displaySize)(pg.size, pg.rotation ?? 0);
23
+ return userUnit === 1 ? size : {
24
+ width: size.width * userUnit,
25
+ height: size.height * userUnit
27
26
  };
28
27
  }
29
28
  const ZOOM_MIN = .05;
@@ -32,37 +31,37 @@ const ZoomMode = {
32
31
  Automatic: "automatic",
33
32
  FitPage: "fit-page",
34
33
  FitWidth: "fit-width",
35
- /** Fit the WHOLE scene (every page) in view — the construction overview. */
34
+ /** Fit the whole scene (every page) in view — the construction overview. */
36
35
  FitAll: "fit-all"
37
36
  };
38
- const clamp = (v, lo, hi) => Math.min(Math.max(v, lo), hi);
39
- const toScreen = (c, w) => ({
40
- x: (w.x - c.x) * c.zoom,
41
- y: (w.y - c.y) * c.zoom
37
+ const clamp = (value, lo, hi) => Math.min(Math.max(value, lo), hi);
38
+ const toScreen = (camera, point) => ({
39
+ x: (point.x - camera.x) * camera.zoom,
40
+ y: (point.y - camera.y) * camera.zoom
42
41
  });
43
- const toWorld = (c, s) => ({
44
- x: c.x + s.x / c.zoom,
45
- y: c.y + s.y / c.zoom
42
+ const toWorld = (camera, point) => ({
43
+ x: camera.x + point.x / camera.zoom,
44
+ y: camera.y + point.y / camera.zoom
46
45
  });
47
- const cameraWorldRect = (c, vp) => ({
48
- x: c.x,
49
- y: c.y,
50
- width: vp.width / c.zoom,
51
- height: vp.height / c.zoom
46
+ const cameraWorldRect = (camera, vp) => ({
47
+ x: camera.x,
48
+ y: camera.y,
49
+ width: vp.width / camera.zoom,
50
+ height: vp.height / camera.zoom
52
51
  });
53
52
  /** Focal zoom: keep the world point under `screenPt` fixed (no bounce). */
54
- const zoomAround = (c, screenPt, factor) => {
55
- const zoom = clamp(c.zoom * factor, ZOOM_MIN, 64);
53
+ const zoomAround = (camera, screenPt, factor) => {
54
+ const zoom = clamp(camera.zoom * factor, ZOOM_MIN, 64);
56
55
  return {
57
- x: c.x + screenPt.x / c.zoom - screenPt.x / zoom,
58
- y: c.y + screenPt.y / c.zoom - screenPt.y / zoom,
56
+ x: camera.x + screenPt.x / camera.zoom - screenPt.x / zoom,
57
+ y: camera.y + screenPt.y / camera.zoom - screenPt.y / zoom,
59
58
  zoom
60
59
  };
61
60
  };
62
- const panByScreen = (c, dxScreen, dyScreen) => ({
63
- x: c.x - dxScreen / c.zoom,
64
- y: c.y - dyScreen / c.zoom,
65
- zoom: c.zoom
61
+ const panByScreen = (camera, dxScreen, dyScreen) => ({
62
+ x: camera.x - dxScreen / camera.zoom,
63
+ y: camera.y - dyScreen / camera.zoom,
64
+ zoom: camera.zoom
66
65
  });
67
66
  const centerOnWorld = (worldPt, vp, zoom) => ({
68
67
  zoom,
@@ -80,82 +79,82 @@ const travelRange = (origin, content, view, zoom, padding) => ({
80
79
  * with a `padding` gutter the camera may reveal beyond each content edge.
81
80
  *
82
81
  * Per axis the travel interval is `travelRange`'s [near, far]. If the padded
83
- * content OVERFLOWS the viewport, the camera travels freely in it. If it FITS,
84
- * the camera is LOCKED to the `fitAlign` rest point — start = near, end = far,
82
+ * content overflows the viewport, the camera travels freely in it. If it fits,
83
+ * the camera is locked to the `fitAlign` rest point — start = near, end = far,
85
84
  * center = midpoint (x resolved logically against `direction`).
86
85
  */
87
- const clampCamera = (c, bounds, vp, k) => {
88
- if (!k.bounded) return c;
89
- const p = k.padding;
90
- const fit = k.fitAlign ?? {
86
+ const clampCamera = (camera, bounds, vp, constraint) => {
87
+ if (!constraint.bounded) return camera;
88
+ const padding = constraint.padding;
89
+ const fit = constraint.fitAlign ?? {
91
90
  x: "center",
92
91
  y: "center"
93
92
  };
94
- const axis = (pos, origin, content, view, a) => {
95
- const t = travelRange(origin, content, view, c.zoom, p);
96
- if (t.fits) return a === "start" ? t.near : a === "end" ? t.far : (t.near + t.far) / 2;
97
- return clamp(pos, t.near, t.far);
93
+ const axis = (pos, origin, content, view, align) => {
94
+ const travel = travelRange(origin, content, view, camera.zoom, padding);
95
+ if (travel.fits) return align === "start" ? travel.near : align === "end" ? travel.far : (travel.near + travel.far) / 2;
96
+ return clamp(pos, travel.near, travel.far);
98
97
  };
99
- const ax = k.direction === "rtl" && fit.x !== "center" ? fit.x === "start" ? "end" : "start" : fit.x;
98
+ const ax = constraint.direction === "rtl" && fit.x !== "center" ? fit.x === "start" ? "end" : "start" : fit.x;
100
99
  return {
101
- zoom: c.zoom,
102
- x: axis(c.x, bounds.x, bounds.width, vp.width, ax),
103
- y: axis(c.y, bounds.y, bounds.height, vp.height, fit.y)
100
+ zoom: camera.zoom,
101
+ x: axis(camera.x, bounds.x, bounds.width, vp.width, ax),
102
+ y: axis(camera.y, bounds.y, bounds.height, vp.height, fit.y)
104
103
  };
105
104
  };
106
- const scrollMetrics = (c, bounds, vp, padding) => {
105
+ const scrollMetrics = (camera, bounds, vp, padding) => {
107
106
  const axis = (pos, origin, content, view) => {
108
- const lo = Math.min(origin - padding / c.zoom, pos);
109
- const total = (Math.max(origin + content + padding / c.zoom, pos + view / c.zoom) - lo) * c.zoom;
107
+ const lo = Math.min(origin - padding / camera.zoom, pos);
108
+ const total = (Math.max(origin + content + padding / camera.zoom, pos + view / camera.zoom) - lo) * camera.zoom;
110
109
  return {
111
- offset: (pos - lo) * c.zoom,
110
+ offset: (pos - lo) * camera.zoom,
112
111
  total,
113
112
  scrollable: total > view + .5
114
113
  };
115
114
  };
116
- const x = axis(c.x, bounds.x, bounds.width, vp.width);
117
- const y = axis(c.y, bounds.y, bounds.height, vp.height);
115
+ const horizontal = axis(camera.x, bounds.x, bounds.width, vp.width);
116
+ const vertical = axis(camera.y, bounds.y, bounds.height, vp.height);
118
117
  return {
119
- scrollLeft: x.offset,
120
- scrollTop: y.offset,
121
- scrollWidth: x.total,
122
- scrollHeight: y.total,
118
+ scrollLeft: horizontal.offset,
119
+ scrollTop: vertical.offset,
120
+ scrollWidth: horizontal.total,
121
+ scrollHeight: vertical.total,
123
122
  clientWidth: vp.width,
124
123
  clientHeight: vp.height,
125
- scrollableX: x.scrollable,
126
- scrollableY: y.scrollable
124
+ scrollableX: horizontal.scrollable,
125
+ scrollableY: vertical.scrollable
127
126
  };
128
127
  };
129
128
  /**
130
129
  * The inverse write — `Element.scrollTo` semantics: absolute offsets into the
131
- * CURRENT range (the same union `scrollMetrics` reports), clamped into
130
+ * current range (the same union `scrollMetrics` reports), clamped into
132
131
  * [0, total − view]; an omitted axis does not move. Zoom is untouched: scrolling
133
132
  * is a pan in scroller clothing.
134
133
  */
135
- const cameraFromScroll = (c, bounds, vp, padding, target) => {
134
+ const cameraFromScroll = (camera, bounds, vp, padding, target) => {
136
135
  const axis = (want, pos, origin, content, view) => {
137
136
  if (want === void 0) return pos;
138
- const lo = Math.min(origin - padding / c.zoom, pos);
139
- const hi = Math.max(origin + content + padding / c.zoom, pos + view / c.zoom);
140
- const max = Math.max(0, (hi - lo) * c.zoom - view);
141
- return lo + clamp(want, 0, max) / c.zoom;
137
+ const lo = Math.min(origin - padding / camera.zoom, pos);
138
+ const hi = Math.max(origin + content + padding / camera.zoom, pos + view / camera.zoom);
139
+ const max = Math.max(0, (hi - lo) * camera.zoom - view);
140
+ return lo + clamp(want, 0, max) / camera.zoom;
142
141
  };
143
142
  return {
144
- zoom: c.zoom,
145
- x: axis(target.left, c.x, bounds.x, bounds.width, vp.width),
146
- y: axis(target.top, c.y, bounds.y, bounds.height, vp.height)
143
+ zoom: camera.zoom,
144
+ x: axis(target.left, camera.x, bounds.x, bounds.width, vp.width),
145
+ y: axis(target.top, camera.y, bounds.y, bounds.height, vp.height)
147
146
  };
148
147
  };
149
148
  /**
150
- * THE placement algorithm — every arrival (goToPage, next/prev, reset) lands
149
+ * The placement algorithm — every arrival (goToPage, next/prev, reset) lands
151
150
  * through it. Pure alignment: put the subject at `align` in the viewport —
152
151
  * per axis 'start' (reading edge at the padded viewport edge), 'end' (far
153
152
  * edge), 'center', or a fraction — with x resolved logically against the
154
- * reading direction. The SAME rule at every zoom: whether the subject fits or
153
+ * reading direction. The same rule at every zoom: whether the subject fits or
155
154
  * overflows never changes where it lands. Landing is policy, not a side
156
155
  * effect of magnification.
157
156
  *
158
- * Deliberately clamp-free: the caller clamps the result against the TRUE
157
+ * Deliberately clamp-free: the caller clamps the result against the true
159
158
  * travel bounds (the scene in continuous flow, the item slice in paged). On
160
159
  * an axis with no real freedom that clamp collapses the landing to the
161
160
  * `fitAlign` rest point — "rests where it must" comes out of the clamp's
@@ -165,11 +164,11 @@ function placeCamera(subject, vp, zoom, padding = 0, align = {
165
164
  x: "start",
166
165
  y: "start"
167
166
  }, direction = "ltr") {
168
- const axis = (a, pos, extent, view) => {
169
- if (a === "start") return pos - padding / zoom;
170
- if (a === "end") return pos + extent - (view - padding) / zoom;
171
- const f = a === "center" ? .5 : clamp(a, 0, 1);
172
- return pos + extent / 2 - view * f / zoom;
167
+ const axis = (alignValue, pos, extent, view) => {
168
+ if (alignValue === "start") return pos - padding / zoom;
169
+ if (alignValue === "end") return pos + extent - (view - padding) / zoom;
170
+ const fraction = alignValue === "center" ? .5 : clamp(alignValue, 0, 1);
171
+ return pos + extent / 2 - view * fraction / zoom;
173
172
  };
174
173
  return {
175
174
  zoom,
@@ -178,13 +177,13 @@ function placeCamera(subject, vp, zoom, padding = 0, align = {
178
177
  };
179
178
  }
180
179
  /**
181
- * The MINIMAL camera move that makes `rect` fully visible (with a `padding` gutter)
180
+ * The minimal camera move that makes `rect` fully visible (with a `padding` gutter)
182
181
  * — DOM scrollIntoView({ block: 'nearest' }) as camera math. Per axis, the cameras
183
- * that show the rect form an interval; the answer is the current camera CLAMPED
182
+ * that show the rect form an interval; the answer is the current camera clamped
184
183
  * into it: already inside → unchanged (the no-op case, by construction, not by
185
184
  * condition). An oversized rect (interval inverted) aligns to its start.
186
185
  *
187
- * This is deliberately NOT placement: `placeCamera` answers "I am navigating here"
186
+ * This is deliberately not placement: `placeCamera` answers "I am navigating here"
188
187
  * (canonical); `revealCamera` answers "make sure this is seeable" (minimal).
189
188
  */
190
189
  function revealCamera(cam, rect, vp, padding = 0) {
@@ -219,11 +218,11 @@ function anchorAtPoint(scene, worldPt) {
219
218
  const item = scene.nearestItem(worldPt);
220
219
  let page = item.pages[0];
221
220
  let best = Infinity;
222
- for (const p of item.pages) {
223
- const d = Math.abs(p.x + p.width / 2 - worldPt.x);
224
- if (d < best) {
225
- best = d;
226
- page = p;
221
+ for (const candidate of item.pages) {
222
+ const distance = Math.abs(candidate.x + candidate.width / 2 - worldPt.x);
223
+ if (distance < best) {
224
+ best = distance;
225
+ page = candidate;
227
226
  }
228
227
  }
229
228
  return {
@@ -232,11 +231,11 @@ function anchorAtPoint(scene, worldPt) {
232
231
  fy: (worldPt.y - page.y) / page.height
233
232
  };
234
233
  }
235
- /** The camera that puts the anchor's world point at a given SCREEN point. */
234
+ /** The camera that puts the anchor's world point at a given screen point. */
236
235
  function cameraForAnchorAtScreen(anchor, scene, screenPt, zoom) {
237
236
  const item = scene.items[scene.itemOfPage(anchor.pageIndex)];
238
237
  let page = item.pages[0];
239
- for (const p of item.pages) if (p.pageIndex === anchor.pageIndex) page = p;
238
+ for (const candidate of item.pages) if (candidate.pageIndex === anchor.pageIndex) page = candidate;
240
239
  const world = {
241
240
  x: page.x + anchor.fx * page.width,
242
241
  y: page.y + anchor.fy * page.height
@@ -256,53 +255,53 @@ function anchorFromCamera(cam, scene, vp, at) {
256
255
  }));
257
256
  }
258
257
  /** The camera that restores an anchor to the same viewport point it was
259
- * captured at — capture and restore MUST agree on `at` for exact round-trips. */
258
+ * captured at — capture and restore must agree on `at` for exact round-trips. */
260
259
  function cameraFromAnchor(anchor, scene, vp, zoom, at) {
261
260
  return cameraForAnchorAtScreen(anchor, scene, at ?? {
262
261
  x: vp.width / 2,
263
262
  y: vp.height / 2
264
263
  }, zoom);
265
264
  }
266
- function lowerBound(arr, t) {
265
+ function lowerBound(arr, value) {
267
266
  let lo = 0;
268
267
  let hi = arr.length;
269
268
  while (lo < hi) {
270
269
  const mid = lo + hi >> 1;
271
- if (arr[mid] < t) lo = mid + 1;
270
+ if (arr[mid] < value) lo = mid + 1;
272
271
  else hi = mid;
273
272
  }
274
273
  return lo;
275
274
  }
276
- function upperBound(arr, t) {
275
+ function upperBound(arr, value) {
277
276
  let lo = 0;
278
277
  let hi = arr.length;
279
278
  while (lo < hi) {
280
279
  const mid = lo + hi >> 1;
281
- if (arr[mid] <= t) lo = mid + 1;
280
+ if (arr[mid] <= value) lo = mid + 1;
282
281
  else hi = mid;
283
282
  }
284
283
  return lo;
285
284
  }
286
285
  const OVERSCAN = 2;
287
286
  /** Intrinsic item dimensions (pages only, no margins) — the `uniform` reference.
288
- * Uses DISPLAY dims, so `uniform` equalizes the rotated footprint and a rotated
287
+ * Uses display dims, so `uniform` equalizes the rotated footprint and a rotated
289
288
  * page sizes to match its neighbours as it actually appears. */
290
289
  function measureItem(pages, group, gap) {
291
- let w = 0;
292
- let h = 0;
290
+ let width = 0;
291
+ let height = 0;
293
292
  for (let j = 0; j < group.length; j++) {
294
- const d = displayDims(pages[group[j]]);
295
- w += d.width + (j > 0 ? gap : 0);
296
- if (d.height > h) h = d.height;
293
+ const size = displayDims(pages[group[j]]);
294
+ width += size.width + (j > 0 ? gap : 0);
295
+ if (size.height > height) height = size.height;
297
296
  }
298
297
  return {
299
- width: w,
300
- height: h
298
+ width,
299
+ height
301
300
  };
302
301
  }
303
302
  /**
304
- * Pack one item from SCALED pages plus constant per-page margins. The page boxes
305
- * (and the spread's inner gap) scale with the sizing factor; the margins do NOT —
303
+ * Pack one item from scaled pages plus constant per-page margins. The page boxes
304
+ * (and the spread's inner gap) scale with the sizing factor; the margins do not —
306
305
  * they are screen-px-derived chrome bands and stay constant in world space.
307
306
  */
308
307
  function packScaledItem(pages, group, scale, gap, frame, direction) {
@@ -311,23 +310,23 @@ function packScaledItem(pages, group, scale, gap, frame, direction) {
311
310
  const local = [];
312
311
  let lx = 0;
313
312
  for (let j = 0; j < group.length; j++) {
314
- const d = displayDims(pages[group[j]]);
315
- const w = d.width * scale;
316
- const h = d.height * scale;
313
+ const size = displayDims(pages[group[j]]);
314
+ const scaledWidth = size.width * scale;
315
+ const scaledHeight = size.height * scale;
317
316
  local.push({
318
317
  pageIndex: group[j],
319
318
  lx: lx + frame.left,
320
- ly: frame.top + (maxH - h) / 2,
321
- w,
322
- h,
319
+ ly: frame.top + (maxH - scaledHeight) / 2,
320
+ w: scaledWidth,
321
+ h: scaledHeight,
323
322
  rotation: pages[group[j]].rotation ?? 0,
324
323
  userUnit: pages[group[j]].userUnit ?? 1
325
324
  });
326
- lx += frame.left + w + frame.right + gap * scale;
325
+ lx += frame.left + scaledWidth + frame.right + gap * scale;
327
326
  }
328
327
  const width = Math.max(0, lx - gap * scale);
329
328
  const height = frame.top + maxH + frame.bottom;
330
- if (direction === "rtl") for (const b of local) b.lx = width - b.lx - b.w + (frame.left - frame.right);
329
+ if (direction === "rtl") for (const box of local) box.lx = width - box.lx - box.w + (frame.left - frame.right);
331
330
  return {
332
331
  local,
333
332
  width,
@@ -335,14 +334,14 @@ function packScaledItem(pages, group, scale, gap, frame, direction) {
335
334
  };
336
335
  }
337
336
  function placePages(item, local, contentScale) {
338
- return local.map((b) => ({
339
- pageIndex: b.pageIndex,
340
- x: item.x + b.lx,
341
- y: item.y + b.ly,
342
- width: b.w,
343
- height: b.h,
344
- rotation: b.rotation,
345
- contentScale: contentScale * b.userUnit
337
+ return local.map((box) => ({
338
+ pageIndex: box.pageIndex,
339
+ x: item.x + box.lx,
340
+ y: item.y + box.ly,
341
+ width: box.w,
342
+ height: box.h,
343
+ rotation: box.rotation,
344
+ contentScale: contentScale * box.userUnit
346
345
  }));
347
346
  }
348
347
  /** Per-item world scale = sizing factor (1 intrinsic, else cross-equalize for
@@ -350,17 +349,17 @@ function placePages(item, local, contentScale) {
350
349
  * result becomes the page's `contentScale`, so world units are view px and 100%
351
350
  * is physically accurate. `viewUnitsPerPoint` defaults to 1 (neutral). */
352
351
  const itemScale = (crossIntrinsic, refCross, sizing, viewUnitsPerPoint = 1) => (sizing === "uniform" && crossIntrinsic > 0 ? refCross / crossIntrinsic : 1) * viewUnitsPerPoint;
353
- function linearLayout(pages, grouping, opts = {}) {
354
- const gap = opts.gap ?? 16;
355
- const vertical = (opts.axis ?? "y") === "y";
356
- const align = opts.align ?? "center";
357
- const sizing = opts.sizing ?? "intrinsic";
358
- const direction = opts.direction ?? "ltr";
352
+ function linearLayout(pages, grouping, options = {}) {
353
+ const gap = options.gap ?? 16;
354
+ const vertical = (options.axis ?? "y") === "y";
355
+ const align = options.align ?? "center";
356
+ const sizing = options.sizing ?? "intrinsic";
357
+ const direction = options.direction ?? "ltr";
359
358
  const mirrored = !vertical && direction === "rtl";
360
- const frame = opts.pageFrame ?? _embedpdf_core_geometry.NO_FRAME;
359
+ const frame = options.pageFrame ?? _embedpdf_core_geometry.NO_FRAME;
361
360
  const measures = grouping.map((group) => measureItem(pages, group, gap));
362
- const crossOf = (p) => vertical ? p.width : p.height;
363
- const refCross = measures.reduce((m, p) => Math.max(m, crossOf(p)), 0);
361
+ const crossOf = (measure) => vertical ? measure.width : measure.height;
362
+ const refCross = measures.reduce((largest, measure) => Math.max(largest, crossOf(measure)), 0);
364
363
  const items = new Array(grouping.length);
365
364
  const locals = new Array(grouping.length);
366
365
  const scales = new Array(grouping.length);
@@ -369,10 +368,10 @@ function linearLayout(pages, grouping, opts = {}) {
369
368
  let maxW = 0;
370
369
  let maxH = 0;
371
370
  for (let i = 0; i < grouping.length; i++) {
372
- const s = itemScale(crossOf(measures[i]), refCross, sizing, opts.viewUnitsPerPoint);
373
- const packed = packScaledItem(pages, grouping[i], s, gap, frame, direction);
371
+ const scale = itemScale(crossOf(measures[i]), refCross, sizing, options.viewUnitsPerPoint);
372
+ const packed = packScaledItem(pages, grouping[i], scale, gap, frame, direction);
374
373
  const { width, height } = packed;
375
- scales[i] = s;
374
+ scales[i] = scale;
376
375
  locals[i] = packed.local;
377
376
  const it = {
378
377
  index: i,
@@ -410,13 +409,13 @@ function linearLayout(pages, grouping, opts = {}) {
410
409
  else it.y = align === "center" ? (size.height - it.height) / 2 : 0;
411
410
  it.pages = placePages(it, locals[i], scales[i]);
412
411
  }
413
- const posIdx = (k) => mirrored ? items.length - 1 - k : k;
414
- const starts = items.map((_, k) => {
415
- const it = items[posIdx(k)];
412
+ const posIdx = (position) => mirrored ? items.length - 1 - position : position;
413
+ const starts = items.map((_, position) => {
414
+ const it = items[posIdx(position)];
416
415
  return vertical ? it.y : it.x;
417
416
  });
418
- const ends = items.map((_, k) => {
419
- const it = items[posIdx(k)];
417
+ const ends = items.map((_, position) => {
418
+ const it = items[posIdx(position)];
420
419
  return vertical ? it.y + it.height : it.x + it.width;
421
420
  });
422
421
  const firstPage = items.map((it) => it.pageIndexes[0]);
@@ -429,41 +428,41 @@ function linearLayout(pages, grouping, opts = {}) {
429
428
  width: maxW,
430
429
  height: maxH
431
430
  },
432
- query(r) {
433
- const a0 = vertical ? r.y : r.x;
434
- const a1 = vertical ? r.y + r.height : r.x + r.width;
431
+ query(rect) {
432
+ const a0 = vertical ? rect.y : rect.x;
433
+ const a1 = vertical ? rect.y + rect.height : rect.x + rect.width;
435
434
  const lo = Math.max(0, lowerBound(ends, a0) - OVERSCAN);
436
435
  const hi = Math.min(items.length, upperBound(starts, a1) + OVERSCAN);
437
436
  const out = [];
438
- for (let k = lo; k < hi; k++) out.push(items[posIdx(k)]);
437
+ for (let position = lo; position < hi; position++) out.push(items[posIdx(position)]);
439
438
  return out;
440
439
  },
441
440
  nearestItem(pt) {
442
- const k = clamp(upperBound(starts, vertical ? pt.y : pt.x) - 1, 0, items.length - 1);
443
- return items[posIdx(k)];
441
+ const position = clamp(upperBound(starts, vertical ? pt.y : pt.x) - 1, 0, items.length - 1);
442
+ return items[posIdx(position)];
444
443
  },
445
444
  itemOfPage(pi) {
446
445
  return clamp(upperBound(firstPage, pi) - 1, 0, items.length - 1);
447
446
  }
448
447
  };
449
448
  }
450
- function gridLayout(pages, grouping, opts = {}) {
451
- const gap = opts.gap ?? 48;
452
- const n = grouping.length;
453
- const sizing = opts.sizing ?? "intrinsic";
454
- const direction = opts.direction ?? "ltr";
455
- const frame = opts.pageFrame ?? _embedpdf_core_geometry.NO_FRAME;
449
+ function gridLayout(pages, grouping, options = {}) {
450
+ const gap = options.gap ?? 48;
451
+ const itemCount = grouping.length;
452
+ const sizing = options.sizing ?? "intrinsic";
453
+ const direction = options.direction ?? "ltr";
454
+ const frame = options.pageFrame ?? _embedpdf_core_geometry.NO_FRAME;
456
455
  const measures = grouping.map((group) => measureItem(pages, group, gap));
457
- const refW = measures.reduce((m, p) => Math.max(m, p.width), 0);
458
- const locals = new Array(n);
459
- const sizes = new Array(n);
460
- const scales = new Array(n);
456
+ const refW = measures.reduce((widest, measure) => Math.max(widest, measure.width), 0);
457
+ const locals = new Array(itemCount);
458
+ const sizes = new Array(itemCount);
459
+ const scales = new Array(itemCount);
461
460
  let cellW = 1;
462
461
  let cellH = 1;
463
- for (let i = 0; i < n; i++) {
464
- const s = itemScale(measures[i].width, refW, sizing, opts.viewUnitsPerPoint);
465
- const packed = packScaledItem(pages, grouping[i], s, gap, frame, direction);
466
- scales[i] = s;
462
+ for (let i = 0; i < itemCount; i++) {
463
+ const scale = itemScale(measures[i].width, refW, sizing, options.viewUnitsPerPoint);
464
+ const packed = packScaledItem(pages, grouping[i], scale, gap, frame, direction);
465
+ scales[i] = scale;
467
466
  locals[i] = packed.local;
468
467
  sizes[i] = {
469
468
  width: packed.width,
@@ -472,25 +471,25 @@ function gridLayout(pages, grouping, opts = {}) {
472
471
  cellW = Math.max(cellW, sizes[i].width);
473
472
  cellH = Math.max(cellH, sizes[i].height);
474
473
  }
475
- const wanted = opts.lineWidth !== void 0 ? Math.floor((opts.lineWidth + gap) / (cellW + gap)) : opts.columns ?? Math.ceil(Math.sqrt(n));
476
- const columns = Math.max(1, Math.min(wanted, Math.max(1, n)));
474
+ const wanted = options.lineWidth !== void 0 ? Math.floor((options.lineWidth + gap) / (cellW + gap)) : options.columns ?? Math.ceil(Math.sqrt(itemCount));
475
+ const columns = Math.max(1, Math.min(wanted, Math.max(1, itemCount)));
477
476
  const colAt = (col) => direction === "rtl" ? columns - 1 - col : col;
478
477
  const stepX = cellW + gap;
479
- const rows = Math.max(1, Math.ceil(n / columns));
478
+ const rows = Math.max(1, Math.ceil(itemCount / columns));
480
479
  const rowHeight = new Array(rows).fill(1);
481
- for (let i = 0; i < n; i++) {
480
+ for (let i = 0; i < itemCount; i++) {
482
481
  const row = Math.floor(i / columns);
483
482
  rowHeight[row] = Math.max(rowHeight[row], sizes[i].height);
484
483
  }
485
484
  const rowTop = new Array(rows);
486
485
  let yCursor = 0;
487
- for (let r = 0; r < rows; r++) {
488
- rowTop[r] = yCursor;
489
- yCursor += rowHeight[r] + gap;
486
+ for (let row = 0; row < rows; row++) {
487
+ rowTop[row] = yCursor;
488
+ yCursor += rowHeight[row] + gap;
490
489
  }
491
- const rowEnd = rowTop.map((top, r) => top + rowHeight[r]);
492
- const items = new Array(n);
493
- for (let i = 0; i < n; i++) {
490
+ const rowEnd = rowTop.map((top, row) => top + rowHeight[row]);
491
+ const items = new Array(itemCount);
492
+ for (let i = 0; i < itemCount; i++) {
494
493
  const col = colAt(i % columns);
495
494
  const row = Math.floor(i / columns);
496
495
  const it = {
@@ -513,31 +512,31 @@ function gridLayout(pages, grouping, opts = {}) {
513
512
  return {
514
513
  size,
515
514
  items,
516
- itemCount: n,
515
+ itemCount,
517
516
  axis: "grid",
518
517
  maxItemSize: {
519
518
  width: cellW,
520
519
  height: cellH
521
520
  },
522
- query(r) {
523
- const c0 = Math.max(0, Math.floor(r.x / stepX));
524
- const c1 = Math.min(columns - 1, Math.floor((r.x + r.width) / stepX));
525
- const r0 = Math.max(0, lowerBound(rowEnd, r.y));
526
- const r1 = Math.min(rows - 1, upperBound(rowTop, r.y + r.height) - 1);
521
+ query(rect) {
522
+ const c0 = Math.max(0, Math.floor(rect.x / stepX));
523
+ const c1 = Math.min(columns - 1, Math.floor((rect.x + rect.width) / stepX));
524
+ const r0 = Math.max(0, lowerBound(rowEnd, rect.y));
525
+ const r1 = Math.min(rows - 1, upperBound(rowTop, rect.y + rect.height) - 1);
527
526
  const out = [];
528
527
  for (let row = r0; row <= r1; row++) for (let col = c0; col <= c1; col++) {
529
- const idx = row * columns + colAt(col);
530
- if (idx < n) out.push(items[idx]);
528
+ const index = row * columns + colAt(col);
529
+ if (index < itemCount) out.push(items[index]);
531
530
  }
532
531
  return out;
533
532
  },
534
533
  nearestItem(pt) {
535
534
  const col = clamp(Math.floor(pt.x / stepX), 0, columns - 1);
536
535
  const row = clamp(upperBound(rowTop, pt.y) - 1, 0, rows - 1);
537
- return items[clamp(row * columns + colAt(col), 0, n - 1)];
536
+ return items[clamp(row * columns + colAt(col), 0, itemCount - 1)];
538
537
  },
539
538
  itemOfPage(pi) {
540
- return clamp(upperBound(firstPage, pi) - 1, 0, n - 1);
539
+ return clamp(upperBound(firstPage, pi) - 1, 0, itemCount - 1);
541
540
  }
542
541
  };
543
542
  }