diff --git a/.eslintrc.js b/.eslintrc.js
index db56d42..47fa709 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -11,11 +11,23 @@ module.exports = {
extends: [
'plugin:vue/essential',
'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
],
parserOptions: {
- parser: '@babel/eslint-parser',
- requireConfigFile: false,
+ parser: '@typescript-eslint/parser',
+ ecmaVersion: 2021,
+ sourceType: 'module',
},
+ parser: 'vue-eslint-parser',
+ overrides: [
+ {
+ files: ['tests/**/*.ts'],
+ env: {
+ 'vitest/globals': true,
+ },
+ plugins: ['vitest'],
+ },
+ ],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml
index a83e4e3..bf4f3bd 100644
--- a/.github/workflows/node.yml
+++ b/.github/workflows/node.yml
@@ -52,7 +52,7 @@ jobs:
run: npm run lint
- name: Build library
- run: npm run build:lib
+ run: npm run build
- name: Check build changes
run: |
diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml
index e4a293a..0a2a906 100644
--- a/.github/workflows/npm-publish.yml
+++ b/.github/workflows/npm-publish.yml
@@ -47,7 +47,7 @@ jobs:
CYPRESS_INSTALL_BINARY: 0
run: |
npm i
- npm run build:lib
+ npm run build
- name: Publish to npm
run: npm publish --provenance --access public
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 5c014b2..bc697bc 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
-name: Deploy A DEMO
+name: Deploy Demo
on:
workflow_dispatch:
@@ -16,17 +16,28 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- - name: Set up Node.js
+ - name: Read package.json node and npm engines version
+ uses: skjnldsv/read-package-engines-version-actions@8205673bab74a63eb9b8093402fd9e0e018663a1 # v2.2
+ id: versions
+ with:
+ fallbackNode: '^20'
+ fallbackNpm: '^10'
+
+ - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@v4
+ with:
+ node-version: ${{ steps.versions.outputs.nodeVersion }}
+
+ - name: Set up npm ${{ steps.versions.outputs.npmVersion }}
+ run: npm i -g 'npm@${{ steps.versions.outputs.npmVersion }}'
- name: Install & Build
run: |
npm i
- npm install -g cross-env
- cross-env PUBLIC_PATH=/pdf-elements/ npm run build
+ npm run build:demo
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: gh-pages
- folder: dist
+ folder: dist-demo
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..a572b9f
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,52 @@
+# SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+name: Tests
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+
+permissions:
+ contents: read
+
+concurrency:
+ group: tests-${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ name: NPM test
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ persist-credentials: false
+
+ - name: Read package.json node and npm engines version
+ uses: skjnldsv/read-package-engines-version-actions@8205673bab74a63eb9b8093402fd9e0e018663a1 # v2.2
+ id: versions
+ with:
+ fallbackNode: '^20'
+ fallbackNpm: '^10'
+
+ - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ steps.versions.outputs.nodeVersion }}
+
+ - name: Set up npm ${{ steps.versions.outputs.npmVersion }}
+ run: npm i -g 'npm@${{ steps.versions.outputs.npmVersion }}'
+
+ - name: Install dependencies
+ env:
+ CYPRESS_INSTALL_BINARY: 0
+ PUPPETEER_SKIP_DOWNLOAD: true
+ run: npm i
+
+ - name: Test
+ run: npm run test
diff --git a/.npmignore b/.npmignore
index 438781d..534324e 100644
--- a/.npmignore
+++ b/.npmignore
@@ -4,12 +4,16 @@
# Source files
src/
examples/
+tests/
# Config files
.babelrc
.eslintrc.js
-vue.config.js
+env.d.ts
postcss.config.js
+tsconfig.json
+vite.config.ts
+vitest.config.ts
REUSE.toml
LICENSES/
CONTRIBUTING.md
diff --git a/README.md b/README.md
index 58d8d76..b0e442c 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,16 @@ SPDX-License-Identifier: AGPL-3.0-or-later
# PDF Elements
-A Vue 2 component for rendering PDFs with draggable and resizable element overlays.
+A Vue 3 component for rendering PDFs with draggable and resizable element overlays.
**[Demo](https://libresign.github.io/pdf-elements/)** · [Examples](examples/)
+## Development
+
+- `npm run dev` - Run the demo with Vite
+- `npm run build` - Build the library (ESM + types)
+- `npm run build:demo` - Build the demo to `dist-demo`
+
## API
### Props
@@ -28,6 +34,23 @@ A Vue 2 component for rendering PDFs with draggable and resizable element overla
| `ignoreClickOutsideSelectors` | Array | `[]` | CSS selectors that keep the selection active when clicking outside the element |
| `pageCountFormat` | String | `'{currentPage} of {totalPages}'` | Format string for page counter |
| `autoFitZoom` | Boolean | `false` | Automatically adjust zoom to fit viewport on window resize |
+| `pdfjsOptions` | Object | `{}` | Options passed to PDF.js `getDocument` (advanced) |
+
+### PDF.js options
+
+`pdfjsOptions` is forwarded to PDF.js `getDocument(...)` and can be used to tune performance.
+
+Example:
+
+```ts
+
+```
### Events
diff --git a/REUSE.toml b/REUSE.toml
index a6d2e50..90cb2c5 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -12,11 +12,15 @@ default-copyright = "2025 LibreCode coop and contributors"
path = [
".babelrc",
".eslintrc.js",
+ "env.d.ts",
"package.json",
"package-lock.json",
"postcss.config.js",
- "vue.config.js",
+ "tsconfig.json",
+ "vite.config.ts",
+ "vitest.config.ts",
"examples/**",
+ "tests/**",
"dist/**",
]
precedence = "aggregate"
diff --git a/env.d.ts b/env.d.ts
new file mode 100644
index 0000000..2c3ed98
--- /dev/null
+++ b/env.d.ts
@@ -0,0 +1,7 @@
+///
+
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue'
+ const component: DefineComponent, Record, unknown>
+ export default component
+}
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..9faac68
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,94 @@
+// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const js = require('@eslint/js')
+const globals = require('globals')
+const vue = require('eslint-plugin-vue')
+const tsPlugin = require('@typescript-eslint/eslint-plugin')
+const tsParser = require('@typescript-eslint/parser')
+const vueParser = require('vue-eslint-parser')
+const vitest = require('eslint-plugin-vitest')
+
+const vitestGlobals = {
+ afterAll: 'readonly',
+ afterEach: 'readonly',
+ beforeAll: 'readonly',
+ beforeEach: 'readonly',
+ describe: 'readonly',
+ expect: 'readonly',
+ it: 'readonly',
+ test: 'readonly',
+ vi: 'readonly',
+}
+
+module.exports = [
+ {
+ ignores: ['dist/**', 'dist-demo/**', 'node_modules/**', '.eslintrc.js'],
+ },
+ js.configs.recommended,
+ {
+ files: ['**/*.{ts,vue}'],
+ languageOptions: {
+ parser: vueParser,
+ parserOptions: {
+ parser: tsParser,
+ ecmaVersion: 2021,
+ sourceType: 'module',
+ },
+ globals: {
+ ...globals.browser,
+ ...globals.es2021,
+ },
+ },
+ plugins: {
+ vue,
+ '@typescript-eslint': tsPlugin,
+ },
+ rules: {
+ ...vue.configs['flat/essential'].rules,
+ ...tsPlugin.configs.recommended.rules,
+ 'no-undef': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
+ 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+ },
+ },
+ {
+ files: ['eslint.config.js', '**/*.config.js', '**/*.config.cjs', 'postcss.config.js'],
+ languageOptions: {
+ globals: {
+ ...globals.node,
+ ...globals.es2021,
+ },
+ sourceType: 'script',
+ },
+ rules: {
+ 'no-undef': 'off',
+ },
+ },
+ {
+ files: ['vite.config.ts', 'vitest.config.ts'],
+ languageOptions: {
+ globals: {
+ ...globals.node,
+ ...globals.es2021,
+ },
+ },
+ },
+ {
+ files: ['tests/**/*.ts'],
+ plugins: {
+ vitest,
+ },
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.es2021,
+ ...vitestGlobals,
+ },
+ },
+ rules: {
+ ...(vitest.configs?.recommended?.rules || {}),
+ },
+ },
+]
diff --git a/examples/basic/App.vue b/examples/basic/App.vue
index 6ed1217..15df9bc 100644
--- a/examples/basic/App.vue
+++ b/examples/basic/App.vue
@@ -56,8 +56,8 @@ SPDX-License-Identifier: AGPL-3.0-or-later
-