@embedpdf/utils 2.6.2 → 2.8.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.
@@ -2,165 +2,6 @@ import * as $ from "svelte/internal/client";
2
2
  import { rotatePointAround, calculateRotatedRectAABB, normalizeAngle } from "@embedpdf/models";
3
3
  import "svelte/internal/disclose-version";
4
4
  import { getCounterRotation } from "@embedpdf/utils";
5
- const ROTATION_HANDLE_MARGIN = 35;
6
- const HANDLE_BASE_ANGLE = {
7
- n: 0,
8
- ne: 45,
9
- e: 90,
10
- se: 135,
11
- s: 180,
12
- sw: 225,
13
- w: 270,
14
- nw: 315
15
- };
16
- const SECTOR_CURSORS = [
17
- "ns-resize",
18
- // 0: north
19
- "nesw-resize",
20
- // 1: NE
21
- "ew-resize",
22
- // 2: east
23
- "nwse-resize",
24
- // 3: SE
25
- "ns-resize",
26
- // 4: south
27
- "nesw-resize",
28
- // 5: SW
29
- "ew-resize",
30
- // 6: west
31
- "nwse-resize"
32
- // 7: NW
33
- ];
34
- function diagonalCursor(handle, pageQuarterTurns, annotationRotation = 0) {
35
- const pageAngle = pageQuarterTurns * 90;
36
- const totalAngle = HANDLE_BASE_ANGLE[handle] + pageAngle + annotationRotation;
37
- const normalized = (totalAngle % 360 + 360) % 360;
38
- const sector = Math.round(normalized / 45) % 8;
39
- return SECTOR_CURSORS[sector];
40
- }
41
- function edgeOffset(k, spacing, mode) {
42
- const base = -k / 2;
43
- if (mode === "center") return base;
44
- return mode === "outside" ? base - spacing : base + spacing;
45
- }
46
- function describeResizeFromConfig(cfg, ui = {}) {
47
- const {
48
- handleSize = 8,
49
- spacing = 1,
50
- offsetMode = "outside",
51
- includeSides = false,
52
- zIndex = 3,
53
- rotationAwareCursor = true
54
- } = ui;
55
- const pageQuarterTurns = (cfg.pageRotation ?? 0) % 4;
56
- const annotationRot = cfg.annotationRotation ?? 0;
57
- const off = (edge) => ({
58
- [edge]: edgeOffset(handleSize, spacing, offsetMode) + "px"
59
- });
60
- const corners = [
61
- ["nw", { ...off("top"), ...off("left") }],
62
- ["ne", { ...off("top"), ...off("right") }],
63
- ["sw", { ...off("bottom"), ...off("left") }],
64
- ["se", { ...off("bottom"), ...off("right") }]
65
- ];
66
- const sides = includeSides ? [
67
- ["n", { ...off("top"), left: `calc(50% - ${handleSize / 2}px)` }],
68
- ["s", { ...off("bottom"), left: `calc(50% - ${handleSize / 2}px)` }],
69
- ["w", { ...off("left"), top: `calc(50% - ${handleSize / 2}px)` }],
70
- ["e", { ...off("right"), top: `calc(50% - ${handleSize / 2}px)` }]
71
- ] : [];
72
- const all = [...corners, ...sides];
73
- return all.map(([handle, pos]) => ({
74
- handle,
75
- style: {
76
- position: "absolute",
77
- width: handleSize + "px",
78
- height: handleSize + "px",
79
- borderRadius: "50%",
80
- zIndex,
81
- cursor: rotationAwareCursor ? diagonalCursor(handle, pageQuarterTurns, annotationRot) : "default",
82
- pointerEvents: "auto",
83
- touchAction: "none",
84
- ...pos
85
- },
86
- attrs: { "data-epdf-handle": handle }
87
- }));
88
- }
89
- function describeVerticesFromConfig(cfg, ui = {}, liveVertices) {
90
- const { vertexSize = 12, zIndex = 4 } = ui;
91
- const rect = cfg.element;
92
- const scale = cfg.scale ?? 1;
93
- const verts = liveVertices ?? cfg.vertices ?? [];
94
- return verts.map((v, i) => {
95
- const left = (v.x - rect.origin.x) * scale - vertexSize / 2;
96
- const top = (v.y - rect.origin.y) * scale - vertexSize / 2;
97
- return {
98
- handle: "nw",
99
- // not used; kept for type
100
- style: {
101
- position: "absolute",
102
- left: left + "px",
103
- top: top + "px",
104
- width: vertexSize + "px",
105
- height: vertexSize + "px",
106
- borderRadius: "50%",
107
- cursor: "pointer",
108
- zIndex,
109
- pointerEvents: "auto",
110
- touchAction: "none"
111
- },
112
- attrs: { "data-epdf-vertex": i }
113
- };
114
- });
115
- }
116
- function describeRotationFromConfig(cfg, ui = {}, currentAngle = 0) {
117
- const { handleSize = 16, zIndex = 5, showConnector = true, connectorWidth = 1 } = ui;
118
- const scale = cfg.scale ?? 1;
119
- const rect = cfg.element;
120
- const orbitRect = cfg.rotationElement ?? rect;
121
- const orbitCenter = cfg.rotationCenter ?? {
122
- x: rect.origin.x + rect.size.width / 2,
123
- y: rect.origin.y + rect.size.height / 2
124
- };
125
- orbitRect.size.width * scale;
126
- orbitRect.size.height * scale;
127
- const centerX = (orbitCenter.x - orbitRect.origin.x) * scale;
128
- const centerY = (orbitCenter.y - orbitRect.origin.y) * scale;
129
- const angleRad = currentAngle * Math.PI / 180;
130
- const margin = ui.margin ?? ROTATION_HANDLE_MARGIN;
131
- const radius = rect.size.height * scale / 2 + margin;
132
- const handleCenterX = centerX + radius * Math.sin(angleRad);
133
- const handleCenterY = centerY - radius * Math.cos(angleRad);
134
- const handleLeft = handleCenterX - handleSize / 2;
135
- const handleTop = handleCenterY - handleSize / 2;
136
- return {
137
- handleStyle: {
138
- position: "absolute",
139
- left: handleLeft + "px",
140
- top: handleTop + "px",
141
- width: handleSize + "px",
142
- height: handleSize + "px",
143
- borderRadius: "50%",
144
- cursor: "grab",
145
- zIndex,
146
- pointerEvents: "auto",
147
- touchAction: "none"
148
- },
149
- connectorStyle: showConnector ? {
150
- position: "absolute",
151
- left: centerX - connectorWidth / 2 + "px",
152
- top: centerY - radius + "px",
153
- width: connectorWidth + "px",
154
- height: radius + "px",
155
- transformOrigin: "center bottom",
156
- transform: `rotate(${currentAngle}deg)`,
157
- zIndex: zIndex - 1,
158
- pointerEvents: "none"
159
- } : {},
160
- radius,
161
- attrs: { "data-epdf-rotation-handle": true }
162
- };
163
- }
164
5
  function getAnchor(handle) {
165
6
  return {
166
7
  x: handle.includes("e") ? "left" : handle.includes("w") ? "right" : "center",
@@ -401,6 +242,165 @@ function computeResizedRect(delta, handle, config) {
401
242
  }
402
243
  return computeResizeStep(delta, handle, config, true, false);
403
244
  }
245
+ const ROTATION_HANDLE_MARGIN = 35;
246
+ const HANDLE_BASE_ANGLE = {
247
+ n: 0,
248
+ ne: 45,
249
+ e: 90,
250
+ se: 135,
251
+ s: 180,
252
+ sw: 225,
253
+ w: 270,
254
+ nw: 315
255
+ };
256
+ const SECTOR_CURSORS = [
257
+ "ns-resize",
258
+ // 0: north
259
+ "nesw-resize",
260
+ // 1: NE
261
+ "ew-resize",
262
+ // 2: east
263
+ "nwse-resize",
264
+ // 3: SE
265
+ "ns-resize",
266
+ // 4: south
267
+ "nesw-resize",
268
+ // 5: SW
269
+ "ew-resize",
270
+ // 6: west
271
+ "nwse-resize"
272
+ // 7: NW
273
+ ];
274
+ function diagonalCursor(handle, pageQuarterTurns, annotationRotation = 0) {
275
+ const pageAngle = pageQuarterTurns * 90;
276
+ const totalAngle = HANDLE_BASE_ANGLE[handle] + pageAngle + annotationRotation;
277
+ const normalized = (totalAngle % 360 + 360) % 360;
278
+ const sector = Math.round(normalized / 45) % 8;
279
+ return SECTOR_CURSORS[sector];
280
+ }
281
+ function edgeOffset(k, spacing, mode) {
282
+ const base = -k / 2;
283
+ if (mode === "center") return base;
284
+ return mode === "outside" ? base - spacing : base + spacing;
285
+ }
286
+ function describeResizeFromConfig(cfg, ui = {}) {
287
+ const {
288
+ handleSize = 8,
289
+ spacing = 1,
290
+ offsetMode = "outside",
291
+ includeSides = false,
292
+ zIndex = 3,
293
+ rotationAwareCursor = true
294
+ } = ui;
295
+ const pageQuarterTurns = (cfg.pageRotation ?? 0) % 4;
296
+ const annotationRot = cfg.annotationRotation ?? 0;
297
+ const off = (edge) => ({
298
+ [edge]: edgeOffset(handleSize, spacing, offsetMode) + "px"
299
+ });
300
+ const corners = [
301
+ ["nw", { ...off("top"), ...off("left") }],
302
+ ["ne", { ...off("top"), ...off("right") }],
303
+ ["sw", { ...off("bottom"), ...off("left") }],
304
+ ["se", { ...off("bottom"), ...off("right") }]
305
+ ];
306
+ const sides = includeSides ? [
307
+ ["n", { ...off("top"), left: `calc(50% - ${handleSize / 2}px)` }],
308
+ ["s", { ...off("bottom"), left: `calc(50% - ${handleSize / 2}px)` }],
309
+ ["w", { ...off("left"), top: `calc(50% - ${handleSize / 2}px)` }],
310
+ ["e", { ...off("right"), top: `calc(50% - ${handleSize / 2}px)` }]
311
+ ] : [];
312
+ const all = [...corners, ...sides];
313
+ return all.map(([handle, pos]) => ({
314
+ handle,
315
+ style: {
316
+ position: "absolute",
317
+ width: handleSize + "px",
318
+ height: handleSize + "px",
319
+ borderRadius: "50%",
320
+ zIndex,
321
+ cursor: rotationAwareCursor ? diagonalCursor(handle, pageQuarterTurns, annotationRot) : "default",
322
+ pointerEvents: "auto",
323
+ touchAction: "none",
324
+ ...pos
325
+ },
326
+ attrs: { "data-epdf-handle": handle }
327
+ }));
328
+ }
329
+ function describeVerticesFromConfig(cfg, ui = {}, liveVertices) {
330
+ const { vertexSize = 12, zIndex = 4 } = ui;
331
+ const rect = cfg.element;
332
+ const scale = cfg.scale ?? 1;
333
+ const verts = liveVertices ?? cfg.vertices ?? [];
334
+ return verts.map((v, i) => {
335
+ const left = (v.x - rect.origin.x) * scale - vertexSize / 2;
336
+ const top = (v.y - rect.origin.y) * scale - vertexSize / 2;
337
+ return {
338
+ handle: "nw",
339
+ // not used; kept for type
340
+ style: {
341
+ position: "absolute",
342
+ left: left + "px",
343
+ top: top + "px",
344
+ width: vertexSize + "px",
345
+ height: vertexSize + "px",
346
+ borderRadius: "50%",
347
+ cursor: "pointer",
348
+ zIndex,
349
+ pointerEvents: "auto",
350
+ touchAction: "none"
351
+ },
352
+ attrs: { "data-epdf-vertex": i }
353
+ };
354
+ });
355
+ }
356
+ function describeRotationFromConfig(cfg, ui = {}, currentAngle = 0) {
357
+ const { handleSize = 16, zIndex = 5, showConnector = true, connectorWidth = 1 } = ui;
358
+ const scale = cfg.scale ?? 1;
359
+ const rect = cfg.element;
360
+ const orbitRect = cfg.rotationElement ?? rect;
361
+ const orbitCenter = cfg.rotationCenter ?? {
362
+ x: rect.origin.x + rect.size.width / 2,
363
+ y: rect.origin.y + rect.size.height / 2
364
+ };
365
+ orbitRect.size.width * scale;
366
+ orbitRect.size.height * scale;
367
+ const centerX = (orbitCenter.x - orbitRect.origin.x) * scale;
368
+ const centerY = (orbitCenter.y - orbitRect.origin.y) * scale;
369
+ const angleRad = currentAngle * Math.PI / 180;
370
+ const margin = ui.margin ?? ROTATION_HANDLE_MARGIN;
371
+ const radius = rect.size.height * scale / 2 + margin;
372
+ const handleCenterX = centerX + radius * Math.sin(angleRad);
373
+ const handleCenterY = centerY - radius * Math.cos(angleRad);
374
+ const handleLeft = handleCenterX - handleSize / 2;
375
+ const handleTop = handleCenterY - handleSize / 2;
376
+ return {
377
+ handleStyle: {
378
+ position: "absolute",
379
+ left: handleLeft + "px",
380
+ top: handleTop + "px",
381
+ width: handleSize + "px",
382
+ height: handleSize + "px",
383
+ borderRadius: "50%",
384
+ cursor: "grab",
385
+ zIndex,
386
+ pointerEvents: "auto",
387
+ touchAction: "none"
388
+ },
389
+ connectorStyle: showConnector ? {
390
+ position: "absolute",
391
+ left: centerX - connectorWidth / 2 + "px",
392
+ top: centerY - radius + "px",
393
+ width: connectorWidth + "px",
394
+ height: radius + "px",
395
+ transformOrigin: "center bottom",
396
+ transform: `rotate(${currentAngle}deg)`,
397
+ zIndex: zIndex - 1,
398
+ pointerEvents: "none"
399
+ } : {},
400
+ radius,
401
+ attrs: { "data-epdf-rotation-handle": true }
402
+ };
403
+ }
404
404
  class DragResizeController {
405
405
  constructor(config, onUpdate) {
406
406
  this.config = config;
@@ -524,7 +524,7 @@ class DragResizeController {
524
524
  // ---------------------------------------------------------------------------
525
525
  // Gesture move
526
526
  // ---------------------------------------------------------------------------
527
- move(clientX, clientY, buttons) {
527
+ move(clientX, clientY, buttons, lockAspectRatio) {
528
528
  if (this.state === "idle" || !this.startPoint) return;
529
529
  if (buttons !== void 0 && buttons === 0) {
530
530
  this.end();
@@ -542,7 +542,7 @@ class DragResizeController {
542
542
  const delta = this.calculateLocalDelta(clientX, clientY);
543
543
  const position = computeResizedRect(delta, this.activeHandle, {
544
544
  startRect: this.startElement,
545
- maintainAspectRatio: this.config.maintainAspectRatio,
545
+ maintainAspectRatio: this.config.maintainAspectRatio || !!lockAspectRatio,
546
546
  annotationRotation: this.config.annotationRotation,
547
547
  constraints: this.config.constraints
548
548
  });
@@ -554,7 +554,7 @@ class DragResizeController {
554
554
  changes: { rect: position },
555
555
  metadata: {
556
556
  handle: this.activeHandle,
557
- maintainAspectRatio: this.config.maintainAspectRatio
557
+ maintainAspectRatio: this.config.maintainAspectRatio || !!lockAspectRatio
558
558
  }
559
559
  }
560
560
  });
@@ -891,7 +891,7 @@ function useDragResize(getOptions) {
891
891
  var _a;
892
892
  e.preventDefault();
893
893
  e.stopPropagation();
894
- (_a = $.get(controller)) == null ? void 0 : _a.move(e.clientX, e.clientY, e.buttons);
894
+ (_a = $.get(controller)) == null ? void 0 : _a.move(e.clientX, e.clientY, e.buttons, e.shiftKey);
895
895
  };
896
896
  const handleEnd = (e) => {
897
897
  var _a, _b, _c;
@@ -1082,7 +1082,7 @@ function CounterRotateContainer($$anchor, $$props) {
1082
1082
  e.stopPropagation();
1083
1083
  };
1084
1084
  node.addEventListener("pointerdown", handlePointerDown, { capture: true });
1085
- node.addEventListener("touchstart", handleTouchStart, { capture: true });
1085
+ node.addEventListener("touchstart", handleTouchStart, { capture: true, passive: true });
1086
1086
  return {
1087
1087
  destroy() {
1088
1088
  node.removeEventListener("pointerdown", handlePointerDown, { capture: true });