Skip to content

Commit 0678075

Browse files
authored
feat: emit adding-ended event (#53)
* feat: add adding-ended payload types Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> * feat: re-export adding-ended payload types Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> * feat: emit adding-ended event from pdf elements Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> * test: cover adding-ended pdf elements event Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> * docs: document adding-ended event Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> * chore: bump pdf-elements version to 1.2.0 Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> * chore: sync pdf-elements lockfile Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --------- Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent e6b8501 commit 0678075

7 files changed

Lines changed: 86 additions & 15 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ Example:
5757
### Events
5858

5959
- `pdf-elements:end-init` - Emitted when PDF is loaded
60+
- `pdf-elements:adding-ended` - Emitted when interactive placement ends. Payload: `{ reason: 'placed', object, docIndex, pageIndex }` on success or `{ reason: 'cancelled' }` when the placement is cancelled.
61+
62+
### Exposed methods
63+
64+
- `startAddingElement(templateObject)` - Starts interactive placement mode.
65+
- `cancelAdding()` - Cancels the current placement session and emits `pdf-elements:adding-ended` with `{ reason: 'cancelled' }` when a session was active.
6066

6167
### Slots
6268

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@libresign/pdf-elements",
33
"description": "PDF viewer with draggable and resizable element overlays for Vue 3",
4-
"version": "1.1.6",
4+
"version": "1.2.0",
55
"author": "LibreCode <contact@librecode.coop>",
66
"private": false,
77
"main": "dist/index.mjs",

src/components/PDFElements.vue

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,11 @@ import { getViewportWindow, isPageInViewport } from '../utils/pageBounds'
154154
import { applyScaleToDocs } from '../utils/zoom'
155155
import { objectIdExistsInDoc, findObjectPageIndex, updateObjectInDoc, removeObjectFromDoc } from '../utils/objectStore'
156156
import { getCachedMeasurement } from '../utils/measurements'
157-
import type { PDFDocumentEntry, PDFElementObject } from '../types'
157+
import type { PDFDocumentEntry, PDFElementObject, PDFElementsAddingEndedPayload } from '../types'
158158
159159
export default defineComponent({
160160
name: 'PDFElements',
161-
emits: ['pdf-elements:end-init', 'pdf-elements:delete-object', 'pdf-elements:object-click'],
161+
emits: ['pdf-elements:end-init', 'pdf-elements:delete-object', 'pdf-elements:object-click', 'pdf-elements:adding-ended'],
162162
components: {
163163
PDFPage,
164164
DraggableElement,
@@ -738,10 +738,14 @@ export default defineComponent({
738738
739739
handleKeyDown(event) {
740740
if (event.key === 'Escape' && this.isAddingMode) {
741-
this.cancelAdding()
741+
this.cancelAdding({ reason: 'cancelled' })
742742
}
743743
},
744744
745+
emitAddingEnded(payload: PDFElementsAddingEndedPayload) {
746+
this.$emit('pdf-elements:adding-ended', payload)
747+
},
748+
745749
getOverlayAriaLabel(docIndex, pageIndex) {
746750
const doc = this.pdfDocuments?.[docIndex]
747751
const docName = doc?.name ?? `Document ${docIndex + 1}`
@@ -827,7 +831,7 @@ export default defineComponent({
827831
if (objectToAdd.x < 0 || objectToAdd.y < 0 ||
828832
objectToAdd.x + objectToAdd.width > pageWidth ||
829833
objectToAdd.y + objectToAdd.height > pageHeight) {
830-
this.cancelAdding()
834+
this.cancelAdding({ reason: 'cancelled' })
831835
return
832836
}
833837
@@ -837,7 +841,12 @@ export default defineComponent({
837841
const docIndex = this.previewPageDocIndex
838842
const objectId = objectToAdd.id
839843
840-
this.cancelAdding()
844+
this.cancelAdding({
845+
reason: 'placed',
846+
object: objectToAdd,
847+
docIndex,
848+
pageIndex,
849+
})
841850
842851
this.$nextTick(() => {
843852
const refKey = `draggable${docIndex}-${pageIndex}-${objectId}`
@@ -848,11 +857,17 @@ export default defineComponent({
848857
})
849858
},
850859
851-
cancelAdding() {
860+
cancelAdding(payload: PDFElementsAddingEndedPayload = { reason: 'cancelled' }) {
861+
const hadPendingAdd = this.isAddingMode || this.previewElement !== null || this.previewVisible
862+
852863
this.isAddingMode = false
853864
this.previewElement = null
854865
this.previewVisible = false
855866
this.detachAddingListeners()
867+
868+
if (hadPendingAdd) {
869+
this.emitAddingEnded(payload)
870+
}
856871
},
857872
generateObjectId() {
858873
const counter = this.nextObjectCounter++

src/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ import type { App } from 'vue'
55
import PDFElements from './components/PDFElements.vue'
66

77
export { ensureWorkerReady, setWorkerPath } from './utils/asyncReader'
8-
export type { PDFDocumentEntry, PDFElementObject, PDFElementsPublicApi } from './types'
8+
export type {
9+
PDFDocumentEntry,
10+
PDFElementObject,
11+
PDFElementsAddingEndedCancelledPayload,
12+
PDFElementsAddingEndedPayload,
13+
PDFElementsAddingEndedPlacedPayload,
14+
PDFElementsAddingEndedReason,
15+
PDFElementsPublicApi,
16+
} from './types'
917

1018
const install = (app: App) => {
1119
const name = PDFElements.name || 'PDFElements'

src/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@ export interface PDFElementObject {
1414
[key: string]: unknown
1515
}
1616

17+
export type PDFElementsAddingEndedReason = 'placed' | 'cancelled'
18+
19+
export interface PDFElementsAddingEndedPlacedPayload {
20+
reason: 'placed'
21+
object: PDFElementObject
22+
docIndex: number
23+
pageIndex: number
24+
}
25+
26+
export interface PDFElementsAddingEndedCancelledPayload {
27+
reason: 'cancelled'
28+
}
29+
30+
export type PDFElementsAddingEndedPayload =
31+
| PDFElementsAddingEndedPlacedPayload
32+
| PDFElementsAddingEndedCancelledPayload
33+
1734
export interface PDFDocumentEntry {
1835
name: string
1936
file: unknown
@@ -32,4 +49,5 @@ export interface PDFElementsPublicApi {
3249
updateObject: (docIndex: number, objectId: string, payload: Partial<PDFElementObject>) => void
3350
deleteObject: (docIndex: number, objectId: string) => void
3451
duplicateObject: (docIndex: number, objectId: string) => void
52+
cancelAdding: () => void
3553
}

tests/components/PDFElements.spec.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ describe('PDFElements business rules', () => {
297297
})
298298

299299
it('finishes adding only when preview is visible and within bounds', () => {
300-
const { ctx } = makeWrapper()
300+
const { wrapper, ctx } = makeWrapper()
301301
const doc = makeDoc()
302302
ctx.pdfDocuments = [doc]
303303

@@ -316,6 +316,17 @@ describe('PDFElements business rules', () => {
316316

317317
ctx.finishAdding()
318318
expect(doc.allObjects[0].length).toBe(1)
319+
expect(wrapper.emitted()['pdf-elements:adding-ended']?.[0][0]).toEqual({
320+
reason: 'placed',
321+
object: expect.objectContaining({
322+
x: 10,
323+
y: 10,
324+
width: 20,
325+
height: 20,
326+
}),
327+
docIndex: 0,
328+
pageIndex: 0,
329+
})
319330

320331
ctx.isAddingMode = true
321332
ctx.previewVisible = true
@@ -324,6 +335,9 @@ describe('PDFElements business rules', () => {
324335

325336
ctx.finishAdding()
326337
expect(doc.allObjects[0].length).toBe(1)
338+
expect(wrapper.emitted()['pdf-elements:adding-ended']?.[1][0]).toEqual({
339+
reason: 'cancelled',
340+
})
327341
})
328342

329343
it('uses changedTouches coordinates on touchend pointer position', () => {
@@ -368,8 +382,8 @@ describe('PDFElements business rules', () => {
368382
expect(doc.allObjects[0][0].y).toBe(20)
369383
})
370384

371-
it('cancels adding resets preview state', () => {
372-
const { ctx } = makeWrapper()
385+
it('cancels adding resets preview state and emits cancellation once', () => {
386+
const { wrapper, ctx } = makeWrapper()
373387
ctx.isAddingMode = true
374388
ctx.previewElement = { width: 10, height: 10 }
375389
ctx.previewVisible = true
@@ -379,17 +393,27 @@ describe('PDFElements business rules', () => {
379393
expect(ctx.isAddingMode).toBe(false)
380394
expect(ctx.previewElement).toBeNull()
381395
expect(ctx.previewVisible).toBe(false)
396+
expect(wrapper.emitted()['pdf-elements:adding-ended']).toEqual([[{ reason: 'cancelled' }]])
382397
})
383398

384-
it('cancels adding on escape key', () => {
385-
const { ctx } = makeWrapper()
399+
it('does not emit cancellation when no add session is active', () => {
400+
const { wrapper, ctx } = makeWrapper()
401+
402+
ctx.cancelAdding()
403+
404+
expect(wrapper.emitted()['pdf-elements:adding-ended']).toBeUndefined()
405+
})
406+
407+
it('cancels adding on escape key and emits cancellation', () => {
408+
const { wrapper, ctx } = makeWrapper()
386409
ctx.isAddingMode = true
387410
ctx.previewElement = { width: 10, height: 10 }
388411
ctx.previewVisible = true
389412

390413
ctx.handleKeyDown({ key: 'Escape' })
391414

392415
expect(ctx.isAddingMode).toBe(false)
416+
expect(wrapper.emitted()['pdf-elements:adding-ended']).toEqual([[{ reason: 'cancelled' }]])
393417
})
394418

395419
it('starts adding element and prepares preview state', () => {

0 commit comments

Comments
 (0)