@libresign/pdf-elements 0.4.0 → 1.0.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.
Files changed (39) hide show
  1. package/README.md +24 -1
  2. package/dist/components/DraggableElement.vue.d.ts +240 -0
  3. package/dist/components/PDFElements.vue.d.ts +552 -0
  4. package/dist/components/PDFPage.vue.d.ts +40 -0
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.mjs +1293 -0
  8. package/dist/pdf-uHvE5neP.mjs +17593 -0
  9. package/dist/pdf.worker.min-DmO9Xdfo.mjs +4 -0
  10. package/dist/types.d.ts +30 -0
  11. package/dist/utils/asyncReader.d.ts +10 -0
  12. package/dist/utils/geometry.d.ts +5 -0
  13. package/dist/utils/measurements.d.ts +12 -0
  14. package/dist/utils/objectStore.d.ts +5 -0
  15. package/dist/utils/pageBounds.d.ts +5 -0
  16. package/dist/utils/zoom.d.ts +2 -0
  17. package/package.json +46 -21
  18. package/src/components/DraggableElement.vue +18 -15
  19. package/src/components/PDFElements.vue +87 -60
  20. package/src/components/PDFPage.vue +11 -7
  21. package/src/index.ts +18 -0
  22. package/src/types.ts +35 -0
  23. package/src/utils/asyncReader.ts +103 -0
  24. package/src/utils/{geometry.js → geometry.ts} +16 -2
  25. package/src/utils/{measurements.js → measurements.ts} +20 -1
  26. package/src/utils/{objectStore.js → objectStore.ts} +15 -4
  27. package/src/utils/{pageBounds.js → pageBounds.ts} +2 -2
  28. package/src/utils/{zoom.js → zoom.ts} +3 -1
  29. package/dist/demo.html +0 -1
  30. package/dist/pdf-elements.common.js +0 -31760
  31. package/dist/pdf-elements.common.js.map +0 -1
  32. package/dist/pdf-elements.css +0 -1
  33. package/dist/pdf-elements.umd.js +0 -31772
  34. package/dist/pdf-elements.umd.js.map +0 -1
  35. package/dist/pdf-elements.umd.min.js +0 -2
  36. package/dist/pdf-elements.umd.min.js.map +0 -1
  37. package/dist/pdf.worker.min.mjs +0 -22
  38. package/src/index.js +0 -17
  39. package/src/utils/asyncReader.js +0 -44
@@ -7,12 +7,15 @@ SPDX-License-Identifier: AGPL-3.0-or-later
7
7
  <canvas ref="canvas" />
8
8
  </template>
9
9
 
10
- <script>
11
- export default {
10
+ <script lang="ts">
11
+ import { defineComponent, type PropType } from 'vue'
12
+
13
+ export default defineComponent({
12
14
  name: 'PDFPage',
15
+ emits: ['onMeasure'],
13
16
  props: {
14
17
  page: {
15
- type: Promise,
18
+ type: Object as PropType<Promise<unknown>>,
16
19
  required: true,
17
20
  },
18
21
  scale: {
@@ -25,7 +28,7 @@ export default {
25
28
  dynamicScale: this.scale,
26
29
  isRendering: false,
27
30
  pendingRender: false,
28
- renderTask: null,
31
+ renderTask: null as { cancel: () => void; promise: Promise<void> } | null,
29
32
  }
30
33
  },
31
34
  watch: {
@@ -41,7 +44,7 @@ export default {
41
44
  if (this.renderTask) {
42
45
  try {
43
46
  this.renderTask.cancel()
44
- } catch (e) {
47
+ } catch {
45
48
  // Ignore render cancellation errors.
46
49
  }
47
50
  this.renderTask = null
@@ -73,12 +76,13 @@ export default {
73
76
  if (this.renderTask) {
74
77
  try {
75
78
  this.renderTask.cancel()
76
- } catch (e) {
79
+ } catch {
77
80
  // Ignore render cancellation errors.
78
81
  }
79
82
  this.renderTask = null
80
83
  }
81
84
  const context = canvas.getContext('2d')
85
+ if (!context) return
82
86
  const viewport = _page.getViewport({
83
87
  scale: this.dynamicScale,
84
88
  })
@@ -100,7 +104,7 @@ export default {
100
104
  }
101
105
  },
102
106
  },
103
- }
107
+ })
104
108
  </script>
105
109
 
106
110
  <style scoped>
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ import type { App } from 'vue'
5
+ import PDFElements from './components/PDFElements.vue'
6
+
7
+ export { setWorkerPath } from './utils/asyncReader'
8
+ export type { PDFDocumentEntry, PDFElementObject, PDFElementsPublicApi } from './types'
9
+
10
+ const install = (app: App) => {
11
+ const name = PDFElements.name || 'PDFElements'
12
+ app.component(name, PDFElements)
13
+ }
14
+
15
+ ;(PDFElements as { install?: (app: App) => void }).install = install
16
+
17
+ export default PDFElements
18
+ export { PDFElements }
package/src/types.ts ADDED
@@ -0,0 +1,35 @@
1
+ // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ export interface PDFElementObject {
5
+ id?: string
6
+ x: number
7
+ y: number
8
+ width: number
9
+ height: number
10
+ type?: string
11
+ label?: string
12
+ icon?: string
13
+ resizable?: boolean
14
+ [key: string]: unknown
15
+ }
16
+
17
+ export interface PDFDocumentEntry {
18
+ name: string
19
+ file: unknown
20
+ pdfDoc: unknown
21
+ numPages: number
22
+ pages: Promise<unknown>[]
23
+ pageWidths: number[]
24
+ pagesScale: number[]
25
+ allObjects: PDFElementObject[][]
26
+ }
27
+
28
+ export interface PDFElementsPublicApi {
29
+ startAddingElement: (templateObject: PDFElementObject) => void
30
+ addObjectToPage: (object: PDFElementObject, pageIndex?: number, docIndex?: number) => boolean
31
+ getAllObjects: (docIndex?: number) => PDFElementObject[]
32
+ updateObject: (docIndex: number, objectId: string, payload: Partial<PDFElementObject>) => void
33
+ deleteObject: (docIndex: number, objectId: string) => void
34
+ duplicateObject: (docIndex: number, objectId: string) => void
35
+ }
@@ -0,0 +1,103 @@
1
+ // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ import type { PDFDocumentProxy, PDFWorker } from 'pdfjs-dist'
5
+
6
+ let sharedWorker: PDFWorker | null = null
7
+ let pdfjsPromise: Promise<typeof import('pdfjs-dist')> | null = null
8
+ let workerUrlPromise: Promise<string> | null = null
9
+ let workerSrcOverride: string | null = null
10
+
11
+ function loadPdfjs() {
12
+ if (!pdfjsPromise) {
13
+ pdfjsPromise = import('pdfjs-dist')
14
+ }
15
+ return pdfjsPromise
16
+ }
17
+
18
+ function loadWorkerUrl() {
19
+ if (!workerUrlPromise) {
20
+ workerUrlPromise = import('pdfjs-dist/build/pdf.worker.min.mjs?url').then(
21
+ (mod) => mod.default as string
22
+ )
23
+ }
24
+ return workerUrlPromise
25
+ }
26
+
27
+ async function ensureWorkerSrc(pdfjs: typeof import('pdfjs-dist')) {
28
+ if (workerSrcOverride) {
29
+ pdfjs.GlobalWorkerOptions.workerSrc = workerSrcOverride
30
+ return
31
+ }
32
+ if (!pdfjs.GlobalWorkerOptions.workerSrc) {
33
+ pdfjs.GlobalWorkerOptions.workerSrc = await loadWorkerUrl()
34
+ }
35
+ }
36
+
37
+ async function getSharedWorker(pdfjs: typeof import('pdfjs-dist')): Promise<PDFWorker> {
38
+ if (!sharedWorker) {
39
+ await ensureWorkerSrc(pdfjs)
40
+ sharedWorker = new pdfjs.PDFWorker({}) as PDFWorker
41
+ }
42
+ return sharedWorker
43
+ }
44
+
45
+ export function setWorkerPath(path: string) {
46
+ workerSrcOverride = path
47
+ if (pdfjsPromise) {
48
+ pdfjsPromise.then((pdfjs) => {
49
+ pdfjs.GlobalWorkerOptions.workerSrc = path
50
+ })
51
+ }
52
+ }
53
+
54
+ export function readAsArrayBuffer(file: Blob): Promise<ArrayBuffer> {
55
+ return new Promise((resolve, reject) => {
56
+ const reader = new FileReader()
57
+ reader.onload = () => resolve(reader.result as ArrayBuffer)
58
+ reader.onerror = reject
59
+ reader.readAsArrayBuffer(file)
60
+ })
61
+ }
62
+
63
+ type PdfInput =
64
+ | string
65
+ | ArrayBuffer
66
+ | ArrayBufferView
67
+ | Blob
68
+ | {
69
+ url?: string
70
+ data?: ArrayBuffer | Uint8Array
71
+ [key: string]: unknown
72
+ }
73
+
74
+ export async function readAsPDF(
75
+ file: PdfInput,
76
+ options: Record<string, unknown> = {}
77
+ ): Promise<PDFDocumentProxy> {
78
+ const pdfjs = await loadPdfjs()
79
+ const worker = await getSharedWorker(pdfjs)
80
+ const isArrayBuffer = file instanceof ArrayBuffer
81
+ const isView = ArrayBuffer.isView(file)
82
+ const isBlob = typeof Blob !== 'undefined' && file instanceof Blob
83
+
84
+ if (file && typeof file === 'object' && !isArrayBuffer && !isView && !isBlob) {
85
+ return pdfjs.getDocument({ ...(file as Record<string, unknown>), ...options, worker }).promise
86
+ }
87
+ if (typeof file === 'string') {
88
+ return pdfjs.getDocument({ url: file, ...options, worker }).promise
89
+ }
90
+ if (isBlob) {
91
+ const data = await readAsArrayBuffer(file as Blob)
92
+ return pdfjs.getDocument({ data, ...options, worker }).promise
93
+ }
94
+ const data = isArrayBuffer
95
+ ? (file as ArrayBuffer)
96
+ : new Uint8Array(
97
+ (file as ArrayBufferView).buffer,
98
+ (file as ArrayBufferView).byteOffset,
99
+ (file as ArrayBufferView).byteLength
100
+ )
101
+
102
+ return pdfjs.getDocument({ data, ...options, worker }).promise
103
+ }
@@ -1,14 +1,28 @@
1
1
  // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
- export function clampPosition(x, y, width, height, pageWidth, pageHeight) {
4
+ export function clampPosition(
5
+ x: number,
6
+ y: number,
7
+ width: number,
8
+ height: number,
9
+ pageWidth: number,
10
+ pageHeight: number
11
+ ) {
5
12
  return {
6
13
  x: Math.max(0, Math.min(x, pageWidth - width)),
7
14
  y: Math.max(0, Math.min(y, pageHeight - height)),
8
15
  }
9
16
  }
10
17
 
11
- export function getVisibleArea(newX, newY, objWidth, objHeight, pageWidth, pageHeight) {
18
+ export function getVisibleArea(
19
+ newX: number,
20
+ newY: number,
21
+ objWidth: number,
22
+ objHeight: number,
23
+ pageWidth: number,
24
+ pageHeight: number
25
+ ) {
12
26
  const visibleLeft = Math.max(0, newX)
13
27
  const visibleTop = Math.max(0, newY)
14
28
  const visibleRight = Math.min(pageWidth, newX + objWidth)
@@ -1,7 +1,26 @@
1
1
  // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
- export function getCachedMeasurement(cache, cacheKey, pageRef, pagesScale) {
4
+ export interface CanvasMeasurement {
5
+ canvasWidth: number
6
+ canvasHeight: number
7
+ }
8
+
9
+ export interface PageMeasurement {
10
+ width: number
11
+ height: number
12
+ }
13
+
14
+ export interface PageMeasurementProvider {
15
+ getCanvasMeasurement: () => CanvasMeasurement
16
+ }
17
+
18
+ export function getCachedMeasurement(
19
+ cache: Record<string, PageMeasurement>,
20
+ cacheKey: string,
21
+ pageRef: PageMeasurementProvider,
22
+ pagesScale: number
23
+ ) {
5
24
  const cached = cache[cacheKey]
6
25
  if (cached) {
7
26
  return cached
@@ -1,12 +1,14 @@
1
1
  // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
- export function objectIdExistsInDoc(doc, objectId) {
4
+ import type { PDFDocumentEntry, PDFElementObject } from '../types'
5
+
6
+ export function objectIdExistsInDoc(doc: PDFDocumentEntry | undefined, objectId: string) {
5
7
  if (!doc || !objectId) return false
6
8
  return doc.allObjects.some((objects) => objects.some((obj) => obj.id === objectId))
7
9
  }
8
10
 
9
- export function findObjectPageIndex(doc, objectId) {
11
+ export function findObjectPageIndex(doc: PDFDocumentEntry | undefined, objectId: string) {
10
12
  if (!doc || !objectId) return undefined
11
13
  for (let pageIndex = 0; pageIndex < doc.allObjects.length; pageIndex++) {
12
14
  if (doc.allObjects[pageIndex].some((obj) => obj.id === objectId)) {
@@ -16,7 +18,12 @@ export function findObjectPageIndex(doc, objectId) {
16
18
  return undefined
17
19
  }
18
20
 
19
- export function updateObjectInDoc(doc, pageIndex, objectId, payload) {
21
+ export function updateObjectInDoc(
22
+ doc: PDFDocumentEntry | undefined,
23
+ pageIndex: number,
24
+ objectId: string,
25
+ payload: Partial<PDFElementObject>
26
+ ) {
20
27
  const objects = doc?.allObjects?.[pageIndex]
21
28
  if (!objects) return false
22
29
  const objectIndex = objects.findIndex((obj) => obj.id === objectId)
@@ -25,7 +32,11 @@ export function updateObjectInDoc(doc, pageIndex, objectId, payload) {
25
32
  return true
26
33
  }
27
34
 
28
- export function removeObjectFromDoc(doc, pageIndex, objectId) {
35
+ export function removeObjectFromDoc(
36
+ doc: PDFDocumentEntry | undefined,
37
+ pageIndex: number,
38
+ objectId: string
39
+ ) {
29
40
  const objects = doc?.allObjects?.[pageIndex]
30
41
  if (!objects) return false
31
42
  const objectIndex = objects.findIndex((obj) => obj.id === objectId)
@@ -1,13 +1,13 @@
1
1
  // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
- export function getViewportWindow(scrollTop, viewHeight, margin = 300) {
4
+ export function getViewportWindow(scrollTop: number, viewHeight: number, margin = 300) {
5
5
  return {
6
6
  minY: Math.max(0, scrollTop - margin),
7
7
  maxY: scrollTop + viewHeight + margin,
8
8
  }
9
9
  }
10
10
 
11
- export function isPageInViewport(offsetTop, offsetHeight, minY, maxY) {
11
+ export function isPageInViewport(offsetTop: number, offsetHeight: number, minY: number, maxY: number) {
12
12
  return !(offsetTop + offsetHeight < minY || offsetTop > maxY)
13
13
  }
@@ -1,7 +1,9 @@
1
1
  // SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
- export function applyScaleToDocs(docs, scale) {
4
+ import type { PDFDocumentEntry } from '../types'
5
+
6
+ export function applyScaleToDocs(docs: PDFDocumentEntry[], scale: number) {
5
7
  docs.forEach((doc) => {
6
8
  doc.pagesScale = doc.pagesScale.map(() => scale)
7
9
  })
package/dist/demo.html DELETED
@@ -1 +0,0 @@
1
- <!doctype html><meta charset="utf-8"><title>pdf-elements demo</title><script src="./pdf-elements.umd.js"></script><link rel="stylesheet" href="./pdf-elements.css"><script>console.log(pdf-elements)</script>