@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.
@@ -17,7 +17,7 @@ function CounterRotate({ children, ...props }) {
17
17
  e.stopPropagation();
18
18
  };
19
19
  element.addEventListener("pointerdown", handlePointerDown, { capture: true });
20
- element.addEventListener("touchstart", handleTouchStart, { capture: true });
20
+ element.addEventListener("touchstart", handleTouchStart, { capture: true, passive: true });
21
21
  return () => {
22
22
  element.removeEventListener("pointerdown", handlePointerDown, { capture: true });
23
23
  element.removeEventListener("touchstart", handleTouchStart, { capture: true });
@@ -49,165 +49,6 @@ function CounterRotate({ children, ...props }) {
49
49
  }
50
50
  }) });
51
51
  }
52
- const ROTATION_HANDLE_MARGIN = 35;
53
- const HANDLE_BASE_ANGLE = {
54
- n: 0,
55
- ne: 45,
56
- e: 90,
57
- se: 135,
58
- s: 180,
59
- sw: 225,
60
- w: 270,
61
- nw: 315
62
- };
63
- const SECTOR_CURSORS = [
64
- "ns-resize",
65
- // 0: north
66
- "nesw-resize",
67
- // 1: NE
68
- "ew-resize",
69
- // 2: east
70
- "nwse-resize",
71
- // 3: SE
72
- "ns-resize",
73
- // 4: south
74
- "nesw-resize",
75
- // 5: SW
76
- "ew-resize",
77
- // 6: west
78
- "nwse-resize"
79
- // 7: NW
80
- ];
81
- function diagonalCursor(handle, pageQuarterTurns, annotationRotation = 0) {
82
- const pageAngle = pageQuarterTurns * 90;
83
- const totalAngle = HANDLE_BASE_ANGLE[handle] + pageAngle + annotationRotation;
84
- const normalized = (totalAngle % 360 + 360) % 360;
85
- const sector = Math.round(normalized / 45) % 8;
86
- return SECTOR_CURSORS[sector];
87
- }
88
- function edgeOffset(k, spacing, mode) {
89
- const base = -k / 2;
90
- if (mode === "center") return base;
91
- return mode === "outside" ? base - spacing : base + spacing;
92
- }
93
- function describeResizeFromConfig(cfg, ui = {}) {
94
- const {
95
- handleSize = 8,
96
- spacing = 1,
97
- offsetMode = "outside",
98
- includeSides = false,
99
- zIndex = 3,
100
- rotationAwareCursor = true
101
- } = ui;
102
- const pageQuarterTurns = (cfg.pageRotation ?? 0) % 4;
103
- const annotationRot = cfg.annotationRotation ?? 0;
104
- const off = (edge) => ({
105
- [edge]: edgeOffset(handleSize, spacing, offsetMode) + "px"
106
- });
107
- const corners = [
108
- ["nw", { ...off("top"), ...off("left") }],
109
- ["ne", { ...off("top"), ...off("right") }],
110
- ["sw", { ...off("bottom"), ...off("left") }],
111
- ["se", { ...off("bottom"), ...off("right") }]
112
- ];
113
- const sides = includeSides ? [
114
- ["n", { ...off("top"), left: `calc(50% - ${handleSize / 2}px)` }],
115
- ["s", { ...off("bottom"), left: `calc(50% - ${handleSize / 2}px)` }],
116
- ["w", { ...off("left"), top: `calc(50% - ${handleSize / 2}px)` }],
117
- ["e", { ...off("right"), top: `calc(50% - ${handleSize / 2}px)` }]
118
- ] : [];
119
- const all = [...corners, ...sides];
120
- return all.map(([handle, pos]) => ({
121
- handle,
122
- style: {
123
- position: "absolute",
124
- width: handleSize + "px",
125
- height: handleSize + "px",
126
- borderRadius: "50%",
127
- zIndex,
128
- cursor: rotationAwareCursor ? diagonalCursor(handle, pageQuarterTurns, annotationRot) : "default",
129
- pointerEvents: "auto",
130
- touchAction: "none",
131
- ...pos
132
- },
133
- attrs: { "data-epdf-handle": handle }
134
- }));
135
- }
136
- function describeVerticesFromConfig(cfg, ui = {}, liveVertices) {
137
- const { vertexSize = 12, zIndex = 4 } = ui;
138
- const rect = cfg.element;
139
- const scale = cfg.scale ?? 1;
140
- const verts = liveVertices ?? cfg.vertices ?? [];
141
- return verts.map((v, i) => {
142
- const left = (v.x - rect.origin.x) * scale - vertexSize / 2;
143
- const top = (v.y - rect.origin.y) * scale - vertexSize / 2;
144
- return {
145
- handle: "nw",
146
- // not used; kept for type
147
- style: {
148
- position: "absolute",
149
- left: left + "px",
150
- top: top + "px",
151
- width: vertexSize + "px",
152
- height: vertexSize + "px",
153
- borderRadius: "50%",
154
- cursor: "pointer",
155
- zIndex,
156
- pointerEvents: "auto",
157
- touchAction: "none"
158
- },
159
- attrs: { "data-epdf-vertex": i }
160
- };
161
- });
162
- }
163
- function describeRotationFromConfig(cfg, ui = {}, currentAngle = 0) {
164
- const { handleSize = 16, zIndex = 5, showConnector = true, connectorWidth = 1 } = ui;
165
- const scale = cfg.scale ?? 1;
166
- const rect = cfg.element;
167
- const orbitRect = cfg.rotationElement ?? rect;
168
- const orbitCenter = cfg.rotationCenter ?? {
169
- x: rect.origin.x + rect.size.width / 2,
170
- y: rect.origin.y + rect.size.height / 2
171
- };
172
- orbitRect.size.width * scale;
173
- orbitRect.size.height * scale;
174
- const centerX = (orbitCenter.x - orbitRect.origin.x) * scale;
175
- const centerY = (orbitCenter.y - orbitRect.origin.y) * scale;
176
- const angleRad = currentAngle * Math.PI / 180;
177
- const margin = ui.margin ?? ROTATION_HANDLE_MARGIN;
178
- const radius = rect.size.height * scale / 2 + margin;
179
- const handleCenterX = centerX + radius * Math.sin(angleRad);
180
- const handleCenterY = centerY - radius * Math.cos(angleRad);
181
- const handleLeft = handleCenterX - handleSize / 2;
182
- const handleTop = handleCenterY - handleSize / 2;
183
- return {
184
- handleStyle: {
185
- position: "absolute",
186
- left: handleLeft + "px",
187
- top: handleTop + "px",
188
- width: handleSize + "px",
189
- height: handleSize + "px",
190
- borderRadius: "50%",
191
- cursor: "grab",
192
- zIndex,
193
- pointerEvents: "auto",
194
- touchAction: "none"
195
- },
196
- connectorStyle: showConnector ? {
197
- position: "absolute",
198
- left: centerX - connectorWidth / 2 + "px",
199
- top: centerY - radius + "px",
200
- width: connectorWidth + "px",
201
- height: radius + "px",
202
- transformOrigin: "center bottom",
203
- transform: `rotate(${currentAngle}deg)`,
204
- zIndex: zIndex - 1,
205
- pointerEvents: "none"
206
- } : {},
207
- radius,
208
- attrs: { "data-epdf-rotation-handle": true }
209
- };
210
- }
211
52
  function getAnchor(handle) {
212
53
  return {
213
54
  x: handle.includes("e") ? "left" : handle.includes("w") ? "right" : "center",
@@ -448,6 +289,165 @@ function computeResizedRect(delta, handle, config) {
448
289
  }
449
290
  return computeResizeStep(delta, handle, config, true, false);
450
291
  }
292
+ const ROTATION_HANDLE_MARGIN = 35;
293
+ const HANDLE_BASE_ANGLE = {
294
+ n: 0,
295
+ ne: 45,
296
+ e: 90,
297
+ se: 135,
298
+ s: 180,
299
+ sw: 225,
300
+ w: 270,
301
+ nw: 315
302
+ };
303
+ const SECTOR_CURSORS = [
304
+ "ns-resize",
305
+ // 0: north
306
+ "nesw-resize",
307
+ // 1: NE
308
+ "ew-resize",
309
+ // 2: east
310
+ "nwse-resize",
311
+ // 3: SE
312
+ "ns-resize",
313
+ // 4: south
314
+ "nesw-resize",
315
+ // 5: SW
316
+ "ew-resize",
317
+ // 6: west
318
+ "nwse-resize"
319
+ // 7: NW
320
+ ];
321
+ function diagonalCursor(handle, pageQuarterTurns, annotationRotation = 0) {
322
+ const pageAngle = pageQuarterTurns * 90;
323
+ const totalAngle = HANDLE_BASE_ANGLE[handle] + pageAngle + annotationRotation;
324
+ const normalized = (totalAngle % 360 + 360) % 360;
325
+ const sector = Math.round(normalized / 45) % 8;
326
+ return SECTOR_CURSORS[sector];
327
+ }
328
+ function edgeOffset(k, spacing, mode) {
329
+ const base = -k / 2;
330
+ if (mode === "center") return base;
331
+ return mode === "outside" ? base - spacing : base + spacing;
332
+ }
333
+ function describeResizeFromConfig(cfg, ui = {}) {
334
+ const {
335
+ handleSize = 8,
336
+ spacing = 1,
337
+ offsetMode = "outside",
338
+ includeSides = false,
339
+ zIndex = 3,
340
+ rotationAwareCursor = true
341
+ } = ui;
342
+ const pageQuarterTurns = (cfg.pageRotation ?? 0) % 4;
343
+ const annotationRot = cfg.annotationRotation ?? 0;
344
+ const off = (edge) => ({
345
+ [edge]: edgeOffset(handleSize, spacing, offsetMode) + "px"
346
+ });
347
+ const corners = [
348
+ ["nw", { ...off("top"), ...off("left") }],
349
+ ["ne", { ...off("top"), ...off("right") }],
350
+ ["sw", { ...off("bottom"), ...off("left") }],
351
+ ["se", { ...off("bottom"), ...off("right") }]
352
+ ];
353
+ const sides = includeSides ? [
354
+ ["n", { ...off("top"), left: `calc(50% - ${handleSize / 2}px)` }],
355
+ ["s", { ...off("bottom"), left: `calc(50% - ${handleSize / 2}px)` }],
356
+ ["w", { ...off("left"), top: `calc(50% - ${handleSize / 2}px)` }],
357
+ ["e", { ...off("right"), top: `calc(50% - ${handleSize / 2}px)` }]
358
+ ] : [];
359
+ const all = [...corners, ...sides];
360
+ return all.map(([handle, pos]) => ({
361
+ handle,
362
+ style: {
363
+ position: "absolute",
364
+ width: handleSize + "px",
365
+ height: handleSize + "px",
366
+ borderRadius: "50%",
367
+ zIndex,
368
+ cursor: rotationAwareCursor ? diagonalCursor(handle, pageQuarterTurns, annotationRot) : "default",
369
+ pointerEvents: "auto",
370
+ touchAction: "none",
371
+ ...pos
372
+ },
373
+ attrs: { "data-epdf-handle": handle }
374
+ }));
375
+ }
376
+ function describeVerticesFromConfig(cfg, ui = {}, liveVertices) {
377
+ const { vertexSize = 12, zIndex = 4 } = ui;
378
+ const rect = cfg.element;
379
+ const scale = cfg.scale ?? 1;
380
+ const verts = liveVertices ?? cfg.vertices ?? [];
381
+ return verts.map((v, i) => {
382
+ const left = (v.x - rect.origin.x) * scale - vertexSize / 2;
383
+ const top = (v.y - rect.origin.y) * scale - vertexSize / 2;
384
+ return {
385
+ handle: "nw",
386
+ // not used; kept for type
387
+ style: {
388
+ position: "absolute",
389
+ left: left + "px",
390
+ top: top + "px",
391
+ width: vertexSize + "px",
392
+ height: vertexSize + "px",
393
+ borderRadius: "50%",
394
+ cursor: "pointer",
395
+ zIndex,
396
+ pointerEvents: "auto",
397
+ touchAction: "none"
398
+ },
399
+ attrs: { "data-epdf-vertex": i }
400
+ };
401
+ });
402
+ }
403
+ function describeRotationFromConfig(cfg, ui = {}, currentAngle = 0) {
404
+ const { handleSize = 16, zIndex = 5, showConnector = true, connectorWidth = 1 } = ui;
405
+ const scale = cfg.scale ?? 1;
406
+ const rect = cfg.element;
407
+ const orbitRect = cfg.rotationElement ?? rect;
408
+ const orbitCenter = cfg.rotationCenter ?? {
409
+ x: rect.origin.x + rect.size.width / 2,
410
+ y: rect.origin.y + rect.size.height / 2
411
+ };
412
+ orbitRect.size.width * scale;
413
+ orbitRect.size.height * scale;
414
+ const centerX = (orbitCenter.x - orbitRect.origin.x) * scale;
415
+ const centerY = (orbitCenter.y - orbitRect.origin.y) * scale;
416
+ const angleRad = currentAngle * Math.PI / 180;
417
+ const margin = ui.margin ?? ROTATION_HANDLE_MARGIN;
418
+ const radius = rect.size.height * scale / 2 + margin;
419
+ const handleCenterX = centerX + radius * Math.sin(angleRad);
420
+ const handleCenterY = centerY - radius * Math.cos(angleRad);
421
+ const handleLeft = handleCenterX - handleSize / 2;
422
+ const handleTop = handleCenterY - handleSize / 2;
423
+ return {
424
+ handleStyle: {
425
+ position: "absolute",
426
+ left: handleLeft + "px",
427
+ top: handleTop + "px",
428
+ width: handleSize + "px",
429
+ height: handleSize + "px",
430
+ borderRadius: "50%",
431
+ cursor: "grab",
432
+ zIndex,
433
+ pointerEvents: "auto",
434
+ touchAction: "none"
435
+ },
436
+ connectorStyle: showConnector ? {
437
+ position: "absolute",
438
+ left: centerX - connectorWidth / 2 + "px",
439
+ top: centerY - radius + "px",
440
+ width: connectorWidth + "px",
441
+ height: radius + "px",
442
+ transformOrigin: "center bottom",
443
+ transform: `rotate(${currentAngle}deg)`,
444
+ zIndex: zIndex - 1,
445
+ pointerEvents: "none"
446
+ } : {},
447
+ radius,
448
+ attrs: { "data-epdf-rotation-handle": true }
449
+ };
450
+ }
451
451
  class DragResizeController {
452
452
  constructor(config, onUpdate) {
453
453
  this.config = config;
@@ -571,7 +571,7 @@ class DragResizeController {
571
571
  // ---------------------------------------------------------------------------
572
572
  // Gesture move
573
573
  // ---------------------------------------------------------------------------
574
- move(clientX, clientY, buttons) {
574
+ move(clientX, clientY, buttons, lockAspectRatio) {
575
575
  if (this.state === "idle" || !this.startPoint) return;
576
576
  if (buttons !== void 0 && buttons === 0) {
577
577
  this.end();
@@ -589,7 +589,7 @@ class DragResizeController {
589
589
  const delta = this.calculateLocalDelta(clientX, clientY);
590
590
  const position = computeResizedRect(delta, this.activeHandle, {
591
591
  startRect: this.startElement,
592
- maintainAspectRatio: this.config.maintainAspectRatio,
592
+ maintainAspectRatio: this.config.maintainAspectRatio || !!lockAspectRatio,
593
593
  annotationRotation: this.config.annotationRotation,
594
594
  constraints: this.config.constraints
595
595
  });
@@ -601,7 +601,7 @@ class DragResizeController {
601
601
  changes: { rect: position },
602
602
  metadata: {
603
603
  handle: this.activeHandle,
604
- maintainAspectRatio: this.config.maintainAspectRatio
604
+ maintainAspectRatio: this.config.maintainAspectRatio || !!lockAspectRatio
605
605
  }
606
606
  }
607
607
  });
@@ -1023,7 +1023,7 @@ function useDragResize(options) {
1023
1023
  e.stopPropagation();
1024
1024
  const activePointerId = activePointerIdRef.current;
1025
1025
  if (activePointerId !== null && e.pointerId !== activePointerId) return;
1026
- (_a = controllerRef.current) == null ? void 0 : _a.move(e.clientX, e.clientY, e.buttons);
1026
+ (_a = controllerRef.current) == null ? void 0 : _a.move(e.clientX, e.clientY, e.buttons, e.shiftKey);
1027
1027
  if (activePointerIdRef.current === e.pointerId && e.buttons === 0) {
1028
1028
  endPointerSession(e.pointerId);
1029
1029
  }