@rsj-de/pdfmergesortsplit 0.0.0-stage → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +164 -2
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +150 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +2 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.js +53 -0
- package/dist/react.js.map +1 -0
- package/package.json +66 -4
- package/types/index.d.ts +129 -0
- package/types/react.d.ts +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RSJ Software GmbH, Germering, Germany
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,165 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @rsj-de/pdfmergesortsplit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Embed the PDF editor of [pdfmerge.rsj.de](https://pdfmerge.rsj.de) in your own
|
|
4
|
+
product: merging, sorting, rotating, splitting and exporting PDFs inside one
|
|
5
|
+
iframe, with the documents never leaving the browser.
|
|
6
|
+
|
|
7
|
+
**Website:** <https://pdfmerge.rsj.de> · **Documentation:**
|
|
8
|
+
<https://pdfmerge.rsj.de/docs> · **Source and samples:**
|
|
9
|
+
<https://github.com/pdfmergesortsplit/pdfmergesortsplit> · **Licence:** MIT
|
|
10
|
+
([LICENSE](LICENSE))
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Merge** any number of PDFs, or ZIP archives containing PDFs.
|
|
15
|
+
- **Sort** pages by drag & drop, including multi-selection (Ctrl/Cmd+click,
|
|
16
|
+
Shift+click a range); rotate, duplicate and delete one page or a whole
|
|
17
|
+
selection; undo/redo on every edit.
|
|
18
|
+
- **Split** into parts: every part has a title line, an editable name used as
|
|
19
|
+
the file name, and its own save and print button. Pages can be moved between
|
|
20
|
+
parts, also with the keyboard.
|
|
21
|
+
- **Export** one PDF per part, one merged PDF, or a ZIP of all parts — from your
|
|
22
|
+
own buttons or from the editor's.
|
|
23
|
+
- **Page provenance**: every page keeps the source file and page it came from;
|
|
24
|
+
a source can bring its own provenance, it can be written into exported PDFs,
|
|
25
|
+
and it is restored when such a PDF is imported again.
|
|
26
|
+
- **Google Drive**: open a file from Drive's "Open with" menu, browse Drive in
|
|
27
|
+
the editor's own dialog, and save the result back to Drive.
|
|
28
|
+
- **Your branding**: replace the title and icon, hide any control, inject your
|
|
29
|
+
own buttons into three injection points and receive their clicks as events.
|
|
30
|
+
- **Your product's look**: light and dark theme, a page viewer, seven languages.
|
|
31
|
+
- **Nothing uploaded**: PDFs are parsed, edited and rebuilt in the visitor's
|
|
32
|
+
browser; no document reaches a server.
|
|
33
|
+
- **Two levels**: a framework-agnostic class and a React component with a hook.
|
|
34
|
+
|
|
35
|
+
## Business model
|
|
36
|
+
|
|
37
|
+
The **code** of this SDK is MIT-licensed (see [LICENSE](LICENSE)): read it, fork
|
|
38
|
+
it, change it, ship it.
|
|
39
|
+
|
|
40
|
+
The **editor it embeds** is a subscription product. An embedded editor asks for a
|
|
41
|
+
licence token (`apiKey`); without a valid one it runs in **test mode** — every
|
|
42
|
+
feature works, a banner marks the embedding as unlicensed. Licences are per
|
|
43
|
+
integration and volume, not per page.
|
|
44
|
+
|
|
45
|
+
- Pricing and the licence model: <https://pdfmerge.rsj.de/docs/licensing>
|
|
46
|
+
- A licence: [info@rsj.de](mailto:info@rsj.de?subject=RSJ%20PDF%20Merge%20SDK%20licence)
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @rsj-de/pdfmergesortsplit
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`react` is an optional peer dependency: the plain class does not import it.
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
import { PDFMergeSortSplitClass } from '@rsj-de/pdfmergesortsplit';
|
|
60
|
+
|
|
61
|
+
const editor = new PDFMergeSortSplitClass('#editor', {
|
|
62
|
+
apiKey: '<licence JWT>', // test mode without one
|
|
63
|
+
title: 'Acme Document Suite',
|
|
64
|
+
actions: {
|
|
65
|
+
saveAll: {
|
|
66
|
+
savePdf: { title: 'Export PDF' },
|
|
67
|
+
saveZip: { title: 'Export ZIP' },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await editor.whenReady();
|
|
73
|
+
await editor.loadDocument({ name: 'contract.pdf', content: file });
|
|
74
|
+
|
|
75
|
+
const pdf = await editor.exportDocument(0, 'pdf'); // part 0 → Blob
|
|
76
|
+
|
|
77
|
+
editor.on('action', async ({ action, part }) => {
|
|
78
|
+
if (action === 'savePdf') download(await editor.exportDocument(part));
|
|
79
|
+
if (action === 'saveZip') download(await editor.exportDocument(undefined, 'zip'));
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
React:
|
|
84
|
+
|
|
85
|
+
```jsx
|
|
86
|
+
import { PDFMergeSortSplit, usePdfMergeSortSplit } from '@rsj-de/pdfmergesortsplit/react';
|
|
87
|
+
|
|
88
|
+
export function PdfEditor({ apiKey }) {
|
|
89
|
+
const { ref, exportDocument } = usePdfMergeSortSplit();
|
|
90
|
+
|
|
91
|
+
const handleAction = async ({ action, part }) => {
|
|
92
|
+
if (action === 'savePdf') download(await exportDocument(part, 'pdf'));
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<PDFMergeSortSplit
|
|
97
|
+
ref={ref}
|
|
98
|
+
config={{ apiKey }}
|
|
99
|
+
style={{ height: 640 }}
|
|
100
|
+
onAction={handleAction}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
More, including the configuration reference, the events and the provenance
|
|
107
|
+
model: <https://pdfmerge.rsj.de/docs>.
|
|
108
|
+
|
|
109
|
+
## API
|
|
110
|
+
|
|
111
|
+
| Member | Description |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `new PDFMergeSortSplitClass(container, config)` | Creates the editor in `container` (element or selector). |
|
|
114
|
+
| `whenReady()` | Resolves when the editor took the configuration. |
|
|
115
|
+
| `setConfig(config)` | Applies a new configuration to the running editor (no reload). |
|
|
116
|
+
| `loadDocument({name, content, provenance})` | Adds a PDF (File, Blob, ArrayBuffer, base64, data URL), optionally with per-page provenance. |
|
|
117
|
+
| `getPages()` | The pages in screen order, each with its provenance. |
|
|
118
|
+
| `exportDocument(reference?, mode?)` | One part (`"pdf"`, by index or name) or everything (`"zip"`) → `Blob`. |
|
|
119
|
+
| `on("action" \| "export" \| "license", handler)` | Injected buttons, finished exports, licence state; returns an unsubscribe function. |
|
|
120
|
+
| `destroy()` | Removes the editor and rejects pending requests. |
|
|
121
|
+
|
|
122
|
+
## Configuration
|
|
123
|
+
|
|
124
|
+
- `apiKey` — the licence token; without one the editor runs in test mode.
|
|
125
|
+
- `embedUrl` — where the editor is served (default `https://pdfmerge.rsj.de`,
|
|
126
|
+
or your self-hosted deployment).
|
|
127
|
+
- `title`, `icon` — replace the title bar of the editor.
|
|
128
|
+
- `ui` — hide any combination of the title-bar, toolbar and part-header controls.
|
|
129
|
+
- `actions.loaders` / `actions.saveAll` / `actions.savePart` — buttons injected
|
|
130
|
+
into the editor; their clicks arrive as `on("action", …)` with
|
|
131
|
+
`{action, where, reference, part}`.
|
|
132
|
+
- `provenance.attach` — write the page provenance into exported PDFs.
|
|
133
|
+
- `googleClientId` — OAuth client ID of your own Google Cloud project for the
|
|
134
|
+
Drive integration (see <https://pdfmerge.rsj.de/docs/google-drive>).
|
|
135
|
+
|
|
136
|
+
A running editor takes a new configuration with `setConfig(config)`; the React
|
|
137
|
+
component calls it whenever the `config` prop changes, so the open document
|
|
138
|
+
stays. Only a different `embedUrl` needs a new iframe. The full schema is in
|
|
139
|
+
`types/index.d.ts`.
|
|
140
|
+
|
|
141
|
+
## Samples
|
|
142
|
+
|
|
143
|
+
`../sdksimple` (plain JavaScript) and `../sdksample` (React) use this package
|
|
144
|
+
through `link:../sdk`, so build the SDK before starting a sample:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pnpm --dir sdk install --ignore-workspace
|
|
148
|
+
pnpm --dir sdk run build
|
|
149
|
+
pnpm --dir sdksimple install --ignore-workspace && pnpm --dir sdksimple run dev
|
|
150
|
+
pnpm --dir sdksample install --ignore-workspace && pnpm --dir sdksample run dev
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Build and publish
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pnpm install --ignore-workspace # this package is not part of the app's workspace
|
|
157
|
+
pnpm run build # dist/index.js, dist/index.cjs, dist/react.*
|
|
158
|
+
npm publish # prepublishOnly builds again
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Licence
|
|
162
|
+
|
|
163
|
+
MIT — see [LICENSE](LICENSE). The MIT licence covers this SDK's code; operating
|
|
164
|
+
the embedded editor requires a subscription as described under
|
|
165
|
+
[Business model](#business-model).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=`https://pdfmerge.rsj.de`,t=2e4,n=e=>typeof Blob<`u`&&e instanceof Blob||e instanceof ArrayBuffer||ArrayBuffer.isView(e),r=class{constructor(n,r={}){let i=typeof n==`string`?document.querySelector(n):n;if(!i)throw Error(`pdfmerge: container not found: ${String(n)}`);this.config=r??{},this.embedUrl=String(this.config.embedUrl||e).replace(/\/+$/,``),this.origin=new URL(this.embedUrl).origin,this.handlers=new Map,this.pending=new Map,this.requestId=0,this.readyDone=!1,this.destroyed=!1,this.iframe=document.createElement(`iframe`),this.iframe.src=`${this.embedUrl}/`,this.iframe.title=`PDF Merge, Sort & Split`,this.iframe.setAttribute(`allow`,`clipboard-read; clipboard-write; fullscreen`),this.iframe.setAttribute(`allowfullscreen`,`true`),this.iframe.style.cssText=`display:block;width:100%;height:100%;border:0`,i.appendChild(this.iframe),this.handleMessage=e=>this.receive(e),window.addEventListener(`message`,this.handleMessage);let a=this.config.readyTimeout??t;this.ready=new Promise((e,t)=>{this.resolveReady=e,this.rejectReady=t,this.readyTimer=setTimeout(()=>{t(Error(`pdfmerge: the editor did not answer within ${a} ms`))},a)}),this.ready.catch(()=>{})}whenReady(){return this.ready}setConfig(e={}){this.config=e??{},this.send({op:`config`,config:this.config})}on(e,t){return this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(t),()=>this.off(e,t)}off(e,t){this.handlers.get(e)?.delete(t)}async loadDocument(e,t,r){let i=e&&typeof e==`object`&&!n(e)?e:{name:e,content:t,provenance:r},a=await this.request(`addPages`,`addPagesRsp`,{name:i.name||`document.pdf`,content:i.content,provenance:i.provenance});if(a?.ok===!1)throw Error(`pdfmerge: loading failed: ${a.error}`);return a}async getPages(){return(await this.request(`pages`,`pagesRsp`))?.pages??[]}async exportDocument(e,t=`pdf`){let n=Number.isInteger(e),r=await this.request(`export`,`exportRsp`,{mode:t,part:n?e:void 0,reference:n?void 0:e});if(r?.error)throw Error(`pdfmerge: export failed: ${r.error}`);let i=new Blob([r.bytes],{type:r.mimeType||`application/pdf`});return this.emit(`export`,{reference:e,mode:t,fileName:r.fileName,pages:r.pages??[],blob:i}),i}destroy(){if(!this.destroyed){this.destroyed=!0,window.removeEventListener(`message`,this.handleMessage),clearTimeout(this.readyTimer);for(let[,e]of this.pending)clearTimeout(e.timer),e.reject(Error(`pdfmerge: the editor was destroyed`));this.pending.clear(),this.iframe.remove()}}send(e){this.iframe.contentWindow?.postMessage({partner:`pdfmerge`,...e},this.origin)}request(e,n,r={},i=t){let a=++this.requestId;return new Promise((t,o)=>{if(this.destroyed){o(Error(`pdfmerge: the editor was destroyed`));return}let s=setTimeout(()=>{this.pending.delete(a),o(Error(`pdfmerge: "${e}" timed out after ${i} ms`))},i);this.pending.set(a,{op:n,resolve:t,reject:o,timer:s}),this.send({op:e,id:a,...r})})}receive(e){if(e.origin!==this.origin||e.source!==this.iframe.contentWindow)return;let t=e.data;if(t&&typeof t==`object`)switch(t.op){case`init`:this.clearReadyTimer(),this.send({op:`initRsp`,config:this.config}),this.readyDone||(this.readyDone=!0,this.resolveReady(this));return;case`licenseRequest`:this.config.apiKey&&this.send({op:`licenseRsp`,token:this.config.apiKey});return;case`licenseStatus`:this.emit(`license`,{licensed:!!t.licensed,reason:t.reason});return;case`action`:this.emit(`action`,{action:t.action,where:t.where,reference:t.reference,part:t.part});return;case`pagesRsp`:case`exportRsp`:case`addPagesRsp`:case`addFilesRsp`:{let e=t.id===void 0?void 0:this.pending.get(t.id);e&&e.op===t.op&&(clearTimeout(e.timer),this.pending.delete(t.id),e.resolve(t));return}default:return}}emit(e,t){for(let n of this.handlers.get(e)??[])try{n(t)}catch(e){console.error(`pdfmerge: event handler failed`,e)}}clearReadyTimer(){this.readyTimer&&=(clearTimeout(this.readyTimer),null)}};exports.PDFMergeSortSplitClass=r,exports.default=r;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["DEFAULT_EMBED_URL","DEFAULT_TIMEOUT","isBinary","value","PDFMergeSortSplitClass","element","container","config","event","timeout","resolve","reject","handler","options","nameOrOptions","answer","byIndex","reference","blob","entry","message","id","timer","op","responseOp","payload","data","error"],"sources":["../src/index.js"],"sourcesContent":["/**\n * RSJ PDF Merge, Sort & Split - SDK\n *\n * The editor runs in an iframe (hosted by RSJ, or by you when self-hosting).\n * This class owns that iframe and the postMessage protocol between the two:\n *\n * app -> host {op: \"init\", version} the editor is up\n * host -> app {op: \"initRsp\", config} title, icon, hidden UI, actions, apiKey\n * app -> host {op: \"licenseRequest\"} framed and not licensed yet: asks for a licence\n * host -> app {op: \"licenseRsp\", token} the licence (config.apiKey), or no token\n * app -> host {op: \"licenseStatus\", licensed, reason} the verdict\n * host -> app {op: \"addFiles\", data} File/Blob/base64/data URL -> addFilesRsp\n * host -> app {op: \"addPages\", name, content, provenance} -> addPagesRsp\n * host -> app {op: \"pages\"} -> pagesRsp\n * host -> app {op: \"export\", mode, part|reference} -> exportRsp\n * app -> host {op: \"action\", action, where, reference, part} a button the host configured\n *\n * `action` is the key of the button in `config.actions`, `where` the injection\n * point it was configured in; an injection point holds any number of buttons.\n *\n * Every request carries an `id` that the answer echoes, so concurrent calls do\n * not get mixed up.\n */\n\nconst DEFAULT_EMBED_URL = 'https://pdfmerge.rsj.de';\nconst DEFAULT_TIMEOUT = 20000;\n\n/** Requests whose payload is the document itself, not options. */\nconst isBinary = (value) =>\n (typeof Blob !== 'undefined' && value instanceof Blob) ||\n value instanceof ArrayBuffer ||\n ArrayBuffer.isView(value);\n\nexport class PDFMergeSortSplitClass {\n /**\n * @param {string|HTMLElement} container element (or selector) that receives the iframe\n * @param {object} config `{ embedUrl, apiKey, title, icon, ui, actions, provenance, … }`\n */\n constructor(container, config = {}) {\n const element = typeof container === 'string' ? document.querySelector(container) : container;\n\n if (!element) {\n throw new Error(`pdfmerge: container not found: ${String(container)}`);\n }\n\n this.config = config ?? {};\n this.embedUrl = String(this.config.embedUrl || DEFAULT_EMBED_URL).replace(/\\/+$/, '');\n this.origin = new URL(this.embedUrl).origin;\n this.handlers = new Map();\n this.pending = new Map();\n this.requestId = 0;\n this.readyDone = false;\n this.destroyed = false;\n\n this.iframe = document.createElement('iframe');\n this.iframe.src = `${this.embedUrl}/`;\n this.iframe.title = 'PDF Merge, Sort & Split';\n this.iframe.setAttribute('allow', 'clipboard-read; clipboard-write; fullscreen');\n this.iframe.setAttribute('allowfullscreen', 'true');\n this.iframe.style.cssText = 'display:block;width:100%;height:100%;border:0';\n element.appendChild(this.iframe);\n\n this.handleMessage = (event) => this.receive(event);\n window.addEventListener('message', this.handleMessage);\n\n const timeout = this.config.readyTimeout ?? DEFAULT_TIMEOUT;\n this.ready = new Promise((resolve, reject) => {\n this.resolveReady = resolve;\n this.rejectReady = reject;\n this.readyTimer = setTimeout(() => {\n reject(new Error(`pdfmerge: the editor did not answer within ${timeout} ms`));\n }, timeout);\n });\n // Nobody has to await it; an unhandled rejection would only be noise.\n this.ready.catch(() => {});\n }\n\n /** Resolves once the editor has taken our configuration. */\n whenReady() {\n return this.ready;\n }\n\n /**\n * Replace the configuration on the running editor.\n *\n * The editor applies it immediately - title, icon, hidden controls, injected\n * buttons, provenance and the licence token - without reloading the iframe.\n * `embedUrl` is the exception: it is the iframe's `src`, so changing it needs\n * a new iframe (the React component does that for you).\n */\n setConfig(config = {}) {\n this.config = config ?? {};\n this.send({ op: 'config', config: this.config });\n }\n\n /** Subscribe to \"action\" / \"export\"; returns an unsubscribe function. */\n on(event, handler) {\n if (!this.handlers.has(event)) {\n this.handlers.set(event, new Set());\n }\n this.handlers.get(event).add(handler);\n\n return () => this.off(event, handler);\n }\n\n /** Remove a handler added with `on`. */\n off(event, handler) {\n this.handlers.get(event)?.delete(handler);\n }\n\n /**\n * Add a PDF to the editor.\n *\n * `loadDocument({name, content, provenance})` or `loadDocument(name, content)`.\n * `content` may be a File, a Blob, an ArrayBuffer, a Uint8Array, base64 or a\n * data URL; `provenance` is one entry per page (any JSON).\n */\n async loadDocument(nameOrOptions, content, provenance) {\n const options =\n nameOrOptions && typeof nameOrOptions === 'object' && !isBinary(nameOrOptions)\n ? nameOrOptions\n : { name: nameOrOptions, content, provenance };\n\n const answer = await this.request('addPages', 'addPagesRsp', {\n name: options.name || 'document.pdf',\n content: options.content,\n provenance: options.provenance,\n });\n\n if (answer?.ok === false) {\n throw new Error(`pdfmerge: loading failed: ${answer.error}`);\n }\n\n return answer;\n }\n\n /** The current pages, each with its provenance. */\n async getPages() {\n const answer = await this.request('pages', 'pagesRsp');\n return answer?.pages ?? [];\n }\n\n /**\n * Export a part as a PDF, or every part as a ZIP (`mode: \"zip\"`).\n *\n * `reference` is a part index or a part name; without it every page goes into\n * one document. Resolves with a Blob and emits \"export\".\n */\n async exportDocument(reference, mode = 'pdf') {\n const byIndex = Number.isInteger(reference);\n const answer = await this.request('export', 'exportRsp', {\n mode,\n part: byIndex ? reference : undefined,\n reference: byIndex ? undefined : reference,\n });\n\n if (answer?.error) {\n throw new Error(`pdfmerge: export failed: ${answer.error}`);\n }\n\n const blob = new Blob([answer.bytes], { type: answer.mimeType || 'application/pdf' });\n this.emit('export', {\n reference,\n mode,\n fileName: answer.fileName,\n pages: answer.pages ?? [],\n blob,\n });\n\n return blob;\n }\n\n /** Remove the iframe and stop listening. */\n destroy() {\n if (this.destroyed) {\n return;\n }\n this.destroyed = true;\n window.removeEventListener('message', this.handleMessage);\n clearTimeout(this.readyTimer);\n\n for (const [, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(new Error('pdfmerge: the editor was destroyed'));\n }\n this.pending.clear();\n\n this.iframe.remove();\n }\n\n /** postMessage into the iframe. */\n send(message) {\n this.iframe.contentWindow?.postMessage({ partner: 'pdfmerge', ...message }, this.origin);\n }\n\n /** Send a request and wait for the answer that echoes its id. */\n request(op, responseOp, payload = {}, timeout = DEFAULT_TIMEOUT) {\n const id = ++this.requestId;\n\n return new Promise((resolve, reject) => {\n if (this.destroyed) {\n reject(new Error('pdfmerge: the editor was destroyed'));\n return;\n }\n\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`pdfmerge: \"${op}\" timed out after ${timeout} ms`));\n }, timeout);\n\n this.pending.set(id, { op: responseOp, resolve, reject, timer });\n this.send({ op, id, ...payload });\n });\n }\n\n receive(event) {\n if (event.origin !== this.origin) {\n return;\n }\n if (event.source !== this.iframe.contentWindow) {\n return;\n }\n\n const data = event.data;\n if (!data || typeof data !== 'object') {\n return;\n }\n\n switch (data.op) {\n case 'init':\n this.clearReadyTimer();\n this.send({ op: 'initRsp', config: this.config });\n if (!this.readyDone) {\n this.readyDone = true;\n this.resolveReady(this);\n }\n return;\n\n case 'licenseRequest':\n // The editor is framed and tainted: answer with the licence it may use.\n // Without `apiKey` there is nothing to send and it stays in test mode.\n if (this.config.apiKey) {\n this.send({ op: 'licenseRsp', token: this.config.apiKey });\n }\n return;\n\n case 'licenseStatus':\n // The editor tells us whether the licence was accepted, so a host can\n // show the state instead of guessing.\n this.emit('license', { licensed: Boolean(data.licensed), reason: data.reason });\n return;\n\n case 'action':\n this.emit('action', {\n action: data.action,\n where: data.where,\n reference: data.reference,\n part: data.part,\n });\n return;\n\n case 'pagesRsp':\n case 'exportRsp':\n case 'addPagesRsp':\n case 'addFilesRsp': {\n const entry = data.id === undefined ? undefined : this.pending.get(data.id);\n\n if (entry && entry.op === data.op) {\n clearTimeout(entry.timer);\n this.pending.delete(data.id);\n entry.resolve(data);\n }\n return;\n }\n\n default:\n return;\n }\n }\n\n emit(event, payload) {\n for (const handler of this.handlers.get(event) ?? []) {\n try {\n handler(payload);\n } catch (error) {\n // A failing consumer handler must not break the message loop.\n console.error('pdfmerge: event handler failed', error);\n }\n }\n }\n\n clearReadyTimer() {\n if (this.readyTimer) {\n clearTimeout(this.readyTimer);\n this.readyTimer = null;\n }\n }\n}\n\nexport default PDFMergeSortSplitClass;\n"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// src/index.js
|
|
2
|
+
var e = 2e4, t = (e) => typeof Blob < "u" && e instanceof Blob || e instanceof ArrayBuffer || ArrayBuffer.isView(e), n = class {
|
|
3
|
+
constructor(t, n = {}) {
|
|
4
|
+
let r = typeof t == "string" ? document.querySelector(t) : t;
|
|
5
|
+
if (!r) throw Error(`pdfmerge: container not found: ${String(t)}`);
|
|
6
|
+
this.config = n ?? {}, this.embedUrl = String(this.config.embedUrl || "https://pdfmerge.rsj.de").replace(/\/+$/, ""), this.origin = new URL(this.embedUrl).origin, this.handlers = /* @__PURE__ */ new Map(), this.pending = /* @__PURE__ */ new Map(), this.requestId = 0, this.readyDone = !1, this.destroyed = !1, this.iframe = document.createElement("iframe"), this.iframe.src = `${this.embedUrl}/`, this.iframe.title = "PDF Merge, Sort & Split", this.iframe.setAttribute("allow", "clipboard-read; clipboard-write; fullscreen"), this.iframe.setAttribute("allowfullscreen", "true"), this.iframe.style.cssText = "display:block;width:100%;height:100%;border:0", r.appendChild(this.iframe), this.handleMessage = (e) => this.receive(e), window.addEventListener("message", this.handleMessage);
|
|
7
|
+
let i = this.config.readyTimeout ?? e;
|
|
8
|
+
this.ready = new Promise((e, t) => {
|
|
9
|
+
this.resolveReady = e, this.rejectReady = t, this.readyTimer = setTimeout(() => {
|
|
10
|
+
t(/* @__PURE__ */ Error(`pdfmerge: the editor did not answer within ${i} ms`));
|
|
11
|
+
}, i);
|
|
12
|
+
}), this.ready.catch(() => {});
|
|
13
|
+
}
|
|
14
|
+
whenReady() {
|
|
15
|
+
return this.ready;
|
|
16
|
+
}
|
|
17
|
+
setConfig(e = {}) {
|
|
18
|
+
this.config = e ?? {}, this.send({
|
|
19
|
+
op: "config",
|
|
20
|
+
config: this.config
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
on(e, t) {
|
|
24
|
+
return this.handlers.has(e) || this.handlers.set(e, /* @__PURE__ */ new Set()), this.handlers.get(e).add(t), () => this.off(e, t);
|
|
25
|
+
}
|
|
26
|
+
off(e, t) {
|
|
27
|
+
this.handlers.get(e)?.delete(t);
|
|
28
|
+
}
|
|
29
|
+
async loadDocument(e, n, r) {
|
|
30
|
+
let i = e && typeof e == "object" && !t(e) ? e : {
|
|
31
|
+
name: e,
|
|
32
|
+
content: n,
|
|
33
|
+
provenance: r
|
|
34
|
+
}, a = await this.request("addPages", "addPagesRsp", {
|
|
35
|
+
name: i.name || "document.pdf",
|
|
36
|
+
content: i.content,
|
|
37
|
+
provenance: i.provenance
|
|
38
|
+
});
|
|
39
|
+
if (a?.ok === !1) throw Error(`pdfmerge: loading failed: ${a.error}`);
|
|
40
|
+
return a;
|
|
41
|
+
}
|
|
42
|
+
async getPages() {
|
|
43
|
+
return (await this.request("pages", "pagesRsp"))?.pages ?? [];
|
|
44
|
+
}
|
|
45
|
+
async exportDocument(e, t = "pdf") {
|
|
46
|
+
let n = Number.isInteger(e), r = await this.request("export", "exportRsp", {
|
|
47
|
+
mode: t,
|
|
48
|
+
part: n ? e : void 0,
|
|
49
|
+
reference: n ? void 0 : e
|
|
50
|
+
});
|
|
51
|
+
if (r?.error) throw Error(`pdfmerge: export failed: ${r.error}`);
|
|
52
|
+
let i = new Blob([r.bytes], { type: r.mimeType || "application/pdf" });
|
|
53
|
+
return this.emit("export", {
|
|
54
|
+
reference: e,
|
|
55
|
+
mode: t,
|
|
56
|
+
fileName: r.fileName,
|
|
57
|
+
pages: r.pages ?? [],
|
|
58
|
+
blob: i
|
|
59
|
+
}), i;
|
|
60
|
+
}
|
|
61
|
+
destroy() {
|
|
62
|
+
if (!this.destroyed) {
|
|
63
|
+
this.destroyed = !0, window.removeEventListener("message", this.handleMessage), clearTimeout(this.readyTimer);
|
|
64
|
+
for (let [, e] of this.pending) clearTimeout(e.timer), e.reject(/* @__PURE__ */ Error("pdfmerge: the editor was destroyed"));
|
|
65
|
+
this.pending.clear(), this.iframe.remove();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
send(e) {
|
|
69
|
+
this.iframe.contentWindow?.postMessage({
|
|
70
|
+
partner: "pdfmerge",
|
|
71
|
+
...e
|
|
72
|
+
}, this.origin);
|
|
73
|
+
}
|
|
74
|
+
request(t, n, r = {}, i = e) {
|
|
75
|
+
let a = ++this.requestId;
|
|
76
|
+
return new Promise((e, o) => {
|
|
77
|
+
if (this.destroyed) {
|
|
78
|
+
o(/* @__PURE__ */ Error("pdfmerge: the editor was destroyed"));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
let s = setTimeout(() => {
|
|
82
|
+
this.pending.delete(a), o(/* @__PURE__ */ Error(`pdfmerge: "${t}" timed out after ${i} ms`));
|
|
83
|
+
}, i);
|
|
84
|
+
this.pending.set(a, {
|
|
85
|
+
op: n,
|
|
86
|
+
resolve: e,
|
|
87
|
+
reject: o,
|
|
88
|
+
timer: s
|
|
89
|
+
}), this.send({
|
|
90
|
+
op: t,
|
|
91
|
+
id: a,
|
|
92
|
+
...r
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
receive(e) {
|
|
97
|
+
if (e.origin !== this.origin || e.source !== this.iframe.contentWindow) return;
|
|
98
|
+
let t = e.data;
|
|
99
|
+
if (t && typeof t == "object") switch (t.op) {
|
|
100
|
+
case "init":
|
|
101
|
+
this.clearReadyTimer(), this.send({
|
|
102
|
+
op: "initRsp",
|
|
103
|
+
config: this.config
|
|
104
|
+
}), this.readyDone || (this.readyDone = !0, this.resolveReady(this));
|
|
105
|
+
return;
|
|
106
|
+
case "licenseRequest":
|
|
107
|
+
this.config.apiKey && this.send({
|
|
108
|
+
op: "licenseRsp",
|
|
109
|
+
token: this.config.apiKey
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
case "licenseStatus":
|
|
113
|
+
this.emit("license", {
|
|
114
|
+
licensed: !!t.licensed,
|
|
115
|
+
reason: t.reason
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
case "action":
|
|
119
|
+
this.emit("action", {
|
|
120
|
+
action: t.action,
|
|
121
|
+
where: t.where,
|
|
122
|
+
reference: t.reference,
|
|
123
|
+
part: t.part
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
case "pagesRsp":
|
|
127
|
+
case "exportRsp":
|
|
128
|
+
case "addPagesRsp":
|
|
129
|
+
case "addFilesRsp": {
|
|
130
|
+
let e = t.id === void 0 ? void 0 : this.pending.get(t.id);
|
|
131
|
+
e && e.op === t.op && (clearTimeout(e.timer), this.pending.delete(t.id), e.resolve(t));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
default: return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
emit(e, t) {
|
|
138
|
+
for (let n of this.handlers.get(e) ?? []) try {
|
|
139
|
+
n(t);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
console.error("pdfmerge: event handler failed", e);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
clearReadyTimer() {
|
|
145
|
+
this.readyTimer &&= (clearTimeout(this.readyTimer), null);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
export { n as PDFMergeSortSplitClass, n as default };
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["DEFAULT_TIMEOUT","isBinary","value","PDFMergeSortSplitClass","element","container","config","event","timeout","resolve","reject","handler","options","nameOrOptions","answer","byIndex","reference","blob","entry","message","id","timer","op","responseOp","payload","data","error"],"sources":["../src/index.js"],"sourcesContent":["/**\n * RSJ PDF Merge, Sort & Split - SDK\n *\n * The editor runs in an iframe (hosted by RSJ, or by you when self-hosting).\n * This class owns that iframe and the postMessage protocol between the two:\n *\n * app -> host {op: \"init\", version} the editor is up\n * host -> app {op: \"initRsp\", config} title, icon, hidden UI, actions, apiKey\n * app -> host {op: \"licenseRequest\"} framed and not licensed yet: asks for a licence\n * host -> app {op: \"licenseRsp\", token} the licence (config.apiKey), or no token\n * app -> host {op: \"licenseStatus\", licensed, reason} the verdict\n * host -> app {op: \"addFiles\", data} File/Blob/base64/data URL -> addFilesRsp\n * host -> app {op: \"addPages\", name, content, provenance} -> addPagesRsp\n * host -> app {op: \"pages\"} -> pagesRsp\n * host -> app {op: \"export\", mode, part|reference} -> exportRsp\n * app -> host {op: \"action\", action, where, reference, part} a button the host configured\n *\n * `action` is the key of the button in `config.actions`, `where` the injection\n * point it was configured in; an injection point holds any number of buttons.\n *\n * Every request carries an `id` that the answer echoes, so concurrent calls do\n * not get mixed up.\n */\n\nconst DEFAULT_EMBED_URL = 'https://pdfmerge.rsj.de';\nconst DEFAULT_TIMEOUT = 20000;\n\n/** Requests whose payload is the document itself, not options. */\nconst isBinary = (value) =>\n (typeof Blob !== 'undefined' && value instanceof Blob) ||\n value instanceof ArrayBuffer ||\n ArrayBuffer.isView(value);\n\nexport class PDFMergeSortSplitClass {\n /**\n * @param {string|HTMLElement} container element (or selector) that receives the iframe\n * @param {object} config `{ embedUrl, apiKey, title, icon, ui, actions, provenance, … }`\n */\n constructor(container, config = {}) {\n const element = typeof container === 'string' ? document.querySelector(container) : container;\n\n if (!element) {\n throw new Error(`pdfmerge: container not found: ${String(container)}`);\n }\n\n this.config = config ?? {};\n this.embedUrl = String(this.config.embedUrl || DEFAULT_EMBED_URL).replace(/\\/+$/, '');\n this.origin = new URL(this.embedUrl).origin;\n this.handlers = new Map();\n this.pending = new Map();\n this.requestId = 0;\n this.readyDone = false;\n this.destroyed = false;\n\n this.iframe = document.createElement('iframe');\n this.iframe.src = `${this.embedUrl}/`;\n this.iframe.title = 'PDF Merge, Sort & Split';\n this.iframe.setAttribute('allow', 'clipboard-read; clipboard-write; fullscreen');\n this.iframe.setAttribute('allowfullscreen', 'true');\n this.iframe.style.cssText = 'display:block;width:100%;height:100%;border:0';\n element.appendChild(this.iframe);\n\n this.handleMessage = (event) => this.receive(event);\n window.addEventListener('message', this.handleMessage);\n\n const timeout = this.config.readyTimeout ?? DEFAULT_TIMEOUT;\n this.ready = new Promise((resolve, reject) => {\n this.resolveReady = resolve;\n this.rejectReady = reject;\n this.readyTimer = setTimeout(() => {\n reject(new Error(`pdfmerge: the editor did not answer within ${timeout} ms`));\n }, timeout);\n });\n // Nobody has to await it; an unhandled rejection would only be noise.\n this.ready.catch(() => {});\n }\n\n /** Resolves once the editor has taken our configuration. */\n whenReady() {\n return this.ready;\n }\n\n /**\n * Replace the configuration on the running editor.\n *\n * The editor applies it immediately - title, icon, hidden controls, injected\n * buttons, provenance and the licence token - without reloading the iframe.\n * `embedUrl` is the exception: it is the iframe's `src`, so changing it needs\n * a new iframe (the React component does that for you).\n */\n setConfig(config = {}) {\n this.config = config ?? {};\n this.send({ op: 'config', config: this.config });\n }\n\n /** Subscribe to \"action\" / \"export\"; returns an unsubscribe function. */\n on(event, handler) {\n if (!this.handlers.has(event)) {\n this.handlers.set(event, new Set());\n }\n this.handlers.get(event).add(handler);\n\n return () => this.off(event, handler);\n }\n\n /** Remove a handler added with `on`. */\n off(event, handler) {\n this.handlers.get(event)?.delete(handler);\n }\n\n /**\n * Add a PDF to the editor.\n *\n * `loadDocument({name, content, provenance})` or `loadDocument(name, content)`.\n * `content` may be a File, a Blob, an ArrayBuffer, a Uint8Array, base64 or a\n * data URL; `provenance` is one entry per page (any JSON).\n */\n async loadDocument(nameOrOptions, content, provenance) {\n const options =\n nameOrOptions && typeof nameOrOptions === 'object' && !isBinary(nameOrOptions)\n ? nameOrOptions\n : { name: nameOrOptions, content, provenance };\n\n const answer = await this.request('addPages', 'addPagesRsp', {\n name: options.name || 'document.pdf',\n content: options.content,\n provenance: options.provenance,\n });\n\n if (answer?.ok === false) {\n throw new Error(`pdfmerge: loading failed: ${answer.error}`);\n }\n\n return answer;\n }\n\n /** The current pages, each with its provenance. */\n async getPages() {\n const answer = await this.request('pages', 'pagesRsp');\n return answer?.pages ?? [];\n }\n\n /**\n * Export a part as a PDF, or every part as a ZIP (`mode: \"zip\"`).\n *\n * `reference` is a part index or a part name; without it every page goes into\n * one document. Resolves with a Blob and emits \"export\".\n */\n async exportDocument(reference, mode = 'pdf') {\n const byIndex = Number.isInteger(reference);\n const answer = await this.request('export', 'exportRsp', {\n mode,\n part: byIndex ? reference : undefined,\n reference: byIndex ? undefined : reference,\n });\n\n if (answer?.error) {\n throw new Error(`pdfmerge: export failed: ${answer.error}`);\n }\n\n const blob = new Blob([answer.bytes], { type: answer.mimeType || 'application/pdf' });\n this.emit('export', {\n reference,\n mode,\n fileName: answer.fileName,\n pages: answer.pages ?? [],\n blob,\n });\n\n return blob;\n }\n\n /** Remove the iframe and stop listening. */\n destroy() {\n if (this.destroyed) {\n return;\n }\n this.destroyed = true;\n window.removeEventListener('message', this.handleMessage);\n clearTimeout(this.readyTimer);\n\n for (const [, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(new Error('pdfmerge: the editor was destroyed'));\n }\n this.pending.clear();\n\n this.iframe.remove();\n }\n\n /** postMessage into the iframe. */\n send(message) {\n this.iframe.contentWindow?.postMessage({ partner: 'pdfmerge', ...message }, this.origin);\n }\n\n /** Send a request and wait for the answer that echoes its id. */\n request(op, responseOp, payload = {}, timeout = DEFAULT_TIMEOUT) {\n const id = ++this.requestId;\n\n return new Promise((resolve, reject) => {\n if (this.destroyed) {\n reject(new Error('pdfmerge: the editor was destroyed'));\n return;\n }\n\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`pdfmerge: \"${op}\" timed out after ${timeout} ms`));\n }, timeout);\n\n this.pending.set(id, { op: responseOp, resolve, reject, timer });\n this.send({ op, id, ...payload });\n });\n }\n\n receive(event) {\n if (event.origin !== this.origin) {\n return;\n }\n if (event.source !== this.iframe.contentWindow) {\n return;\n }\n\n const data = event.data;\n if (!data || typeof data !== 'object') {\n return;\n }\n\n switch (data.op) {\n case 'init':\n this.clearReadyTimer();\n this.send({ op: 'initRsp', config: this.config });\n if (!this.readyDone) {\n this.readyDone = true;\n this.resolveReady(this);\n }\n return;\n\n case 'licenseRequest':\n // The editor is framed and tainted: answer with the licence it may use.\n // Without `apiKey` there is nothing to send and it stays in test mode.\n if (this.config.apiKey) {\n this.send({ op: 'licenseRsp', token: this.config.apiKey });\n }\n return;\n\n case 'licenseStatus':\n // The editor tells us whether the licence was accepted, so a host can\n // show the state instead of guessing.\n this.emit('license', { licensed: Boolean(data.licensed), reason: data.reason });\n return;\n\n case 'action':\n this.emit('action', {\n action: data.action,\n where: data.where,\n reference: data.reference,\n part: data.part,\n });\n return;\n\n case 'pagesRsp':\n case 'exportRsp':\n case 'addPagesRsp':\n case 'addFilesRsp': {\n const entry = data.id === undefined ? undefined : this.pending.get(data.id);\n\n if (entry && entry.op === data.op) {\n clearTimeout(entry.timer);\n this.pending.delete(data.id);\n entry.resolve(data);\n }\n return;\n }\n\n default:\n return;\n }\n }\n\n emit(event, payload) {\n for (const handler of this.handlers.get(event) ?? []) {\n try {\n handler(payload);\n } catch (error) {\n // A failing consumer handler must not break the message loop.\n console.error('pdfmerge: event handler failed', error);\n }\n }\n }\n\n clearReadyTimer() {\n if (this.readyTimer) {\n clearTimeout(this.readyTimer);\n this.readyTimer = null;\n }\n }\n}\n\nexport default PDFMergeSortSplitClass;\n"],"mappings":"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"}
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));const c=require("./index.cjs");let l=require("react");l=s(l,1);let u=require("react/jsx-runtime");var d=()=>{let e=(0,l.useRef)(null);return{ref:e,loadDocument:(0,l.useCallback)(t=>e.current.loadDocument(t),[]),exportDocument:(0,l.useCallback)((t,n)=>e.current.exportDocument(t,n),[]),getPages:(0,l.useCallback)(()=>e.current.getPages(),[])}},f=(0,l.forwardRef)(function({config:e,style:t,className:n,onAction:r,onExport:i,onLicense:a,onReady:o},s){let d=(0,l.useRef)(null),f=(0,l.useRef)(null),p=(0,l.useRef)({onAction:r,onExport:i,onLicense:a,onReady:o});p.current={onAction:r,onExport:i,onLicense:a,onReady:o};let m=(0,l.useRef)(e);m.current=e;let h=(0,l.useRef)(null),g=e?.embedUrl;return(0,l.useEffect)(()=>{let e=m.current,t=new c.PDFMergeSortSplitClass(d.current,e);f.current=t,h.current=JSON.stringify(e??{}),s&&(s.current=t),t.whenReady().then(e=>p.current.onReady?.(e)).catch(()=>{});let n=t.on(`action`,e=>p.current.onAction?.(e)),r=t.on(`export`,e=>p.current.onExport?.(e)),i=t.on(`license`,e=>p.current.onLicense?.(e));return()=>{n(),r(),i(),t.destroy(),f.current=null,s&&(s.current=null)}},[g]),(0,l.useEffect)(()=>{let t=f.current;if(!t)return;let n=JSON.stringify(e??{});n!==h.current&&(h.current=n,t.setConfig(e))},[e]),(0,u.jsx)(`div`,{ref:d,className:n,style:{width:`100%`,height:`100%`,...t}})});exports.PDFMergeSortSplit=f,exports.default=f,exports.PDFMergeSortSplitClass=c.PDFMergeSortSplitClass,exports.usePdfMergeSortSplit=d;
|
|
2
|
+
//# sourceMappingURL=react.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.cjs","names":["useRef","useCallback","forwardRef","PDFMergeSortSplitClass","__create","__defProp","__getOwnPropDesc","__getOwnPropNames","__getProtoOf","__hasOwnProp","__copyProps","from","keys","i","n","key","to","except","k","desc","__toESM","mod","isNodeMode","target","require_index","react","react_jsx_runtime","usePdfMergeSortSplit","ref","document","reference","mode","PDFMergeSortSplit","container","instance","handlers","configRef","config","applied","embedUrl","current","created","ready","offAction","payload","offExport","offLicense","json","style"],"sources":["../src/react.jsx"],"sourcesContent":["import React, { forwardRef, useCallback, useEffect, useRef } from 'react';\n\nimport { PDFMergeSortSplitClass } from './index.js';\n\n/**\n * The editor's methods, bound to the instance the component creates.\n *\n * ```jsx\n * const { ref, loadDocument, exportDocument, getPages } = usePdfMergeSortSplit();\n *\n * const handleAction = async ({ action }) => {\n * if (action === 'saveZip') download(await exportDocument(undefined, 'zip'));\n * };\n *\n * <PDFMergeSortSplit ref={ref} config={{ apiKey }} onAction={handleAction} />\n * ```\n *\n * The returned functions are stable, so callers need no `useCallback` or\n * `useMemo` wrapper; `ref` is only needed for the escape hatches\n * (`whenReady`, `on`, `destroy`) and to pass to the component.\n */\nexport const usePdfMergeSortSplit = () => {\n const ref = useRef(null);\n\n const loadDocument = useCallback(\n (document) => ref.current.loadDocument(document),\n [],\n );\n const exportDocument = useCallback(\n (reference, mode) => ref.current.exportDocument(reference, mode),\n [],\n );\n const getPages = useCallback(() => ref.current.getPages(), []);\n\n return { ref, loadDocument, exportDocument, getPages };\n};\n\n/**\n * The editor as a React component.\n *\n * The iframe is created once and lives for the lifetime of the component:\n * changing `onAction` / `onExport` / `onReady` does not reload it, and a new\n * `config` is applied to the running editor (`setConfig`) instead of rebuilding\n * it, so the open document stays. Only a different `config.embedUrl` needs a\n * new iframe, which the component creates itself.\n */\nexport const PDFMergeSortSplit = forwardRef(function PDFMergeSortSplit(\n { config, style, className, onAction, onExport, onLicense, onReady },\n ref,\n) {\n const container = useRef(null);\n const instance = useRef(null);\n const handlers = useRef({ onAction, onExport, onLicense, onReady });\n handlers.current = { onAction, onExport, onLicense, onReady };\n\n // The effect that creates the iframe needs the config of the render it runs\n // in, but must not re-run for every new config object.\n const configRef = useRef(config);\n configRef.current = config;\n\n // What the running editor already knows. `config={{ … }}` is a new object on\n // every render, so the comparison is by content, not by reference.\n const applied = useRef(null);\n\n // `embedUrl` is the iframe's src: only that needs a new iframe.\n const embedUrl = config?.embedUrl;\n\n useEffect(() => {\n const current = configRef.current;\n const created = new PDFMergeSortSplitClass(container.current, current);\n instance.current = created;\n applied.current = JSON.stringify(current ?? {});\n\n if (ref) {\n ref.current = created;\n }\n\n created\n .whenReady()\n .then((ready) => handlers.current.onReady?.(ready))\n .catch(() => {\n // `ready` rejects when the editor never answers; onReady is not called.\n });\n\n const offAction = created.on('action', (payload) =>\n handlers.current.onAction?.(payload),\n );\n const offExport = created.on('export', (payload) =>\n handlers.current.onExport?.(payload),\n );\n const offLicense = created.on('license', (payload) =>\n handlers.current.onLicense?.(payload),\n );\n\n return () => {\n offAction();\n offExport();\n offLicense();\n created.destroy();\n instance.current = null;\n\n if (ref) {\n ref.current = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [embedUrl]);\n\n // Everything except `embedUrl` is applied to the running editor, so a config\n // change does not reload the iframe and the open document stays.\n useEffect(() => {\n const current = instance.current;\n if (!current) {\n return;\n }\n\n const json = JSON.stringify(config ?? {});\n if (json === applied.current) {\n return;\n }\n applied.current = json;\n\n current.setConfig(config);\n }, [config]);\n\n return (\n <div\n ref={container}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n />\n );\n});\n\nexport { PDFMergeSortSplitClass } from './index.js';\nexport default PDFMergeSortSplit;\n"],"mappings":"A,qrBAqBA,IAAa2B,MAA6B,CACxC,IAAMC,GAAA,EAAM5B,EAAAA,OAAAA,CAAO,IAAI,EAYvB,MAAO,CAAE,MAAK,cAAA,EAVOC,EAAAA,YAAAA,CAClB,GAAa2B,EAAI,QAAQ,aAAaC,CAAQ,EAC/C,CAAC,CAQW,EAAc,gBAAA,EANL5B,EAAAA,YAAAA,EACpB,EAAW,IAAS2B,EAAI,QAAQ,eAAeE,EAAWC,CAAI,EAC/D,CAAC,CAIyB,EAAgB,UAAA,EAF3B9B,EAAAA,YAAAA,KAAkB2B,EAAI,QAAQ,SAAS,EAAG,CAAC,CAEhB,CAAS,CACvD,EAWaI,GAAA,EAAoB9B,EAAAA,WAAAA,CAAW,SAC1C,CAAE,SAAQ,QAAO,YAAW,WAAU,WAAU,YAAW,WAC3D,EACA,CACA,IAAM+B,GAAA,EAAYjC,EAAAA,OAAAA,CAAO,IAAI,EACvBkC,GAAA,EAAWlC,EAAAA,OAAAA,CAAO,IAAI,EACtBmC,GAAA,EAAWnC,EAAAA,OAAAA,CAAO,CAAE,WAAU,WAAU,YAAW,SAAQ,CAAC,EAClE,EAAS,QAAU,CAAE,WAAU,WAAU,YAAW,SAAQ,EAI5D,IAAMoC,GAAA,EAAYpC,EAAAA,OAAAA,CAAOqC,CAAM,EAC/B,EAAU,QAAUA,EAIpB,IAAMC,GAAA,EAAUtC,EAAAA,OAAAA,CAAO,IAAI,EAGrBuC,EAAWF,GAAQ,SA4DzB,OA1DA,EAAAZ,EAAA,UAAA,KAAgB,CACd,IAAMe,EAAUJ,EAAU,QACpBK,EAAU,IAAItC,EAAAA,uBAAuB8B,EAAU,QAASO,CAAO,EACrE,EAAS,QAAUC,EACnB,EAAQ,QAAU,KAAK,UAAUD,GAAW,CAAC,CAAC,EAE1CZ,IACF,EAAI,QAAUa,GAGhBA,EACG,UAAU,CAAC,CACX,KAAM,GAAUN,EAAS,QAAQ,UAAUO,CAAK,CAAC,CAAC,CAClD,UAAY,CAEb,CAAC,EAEH,IAAMC,EAAYF,EAAQ,GAAG,SAAW,GACtCN,EAAS,QAAQ,WAAWS,CAAO,CACrC,EACMC,EAAYJ,EAAQ,GAAG,SAAW,GACtCN,EAAS,QAAQ,WAAWS,CAAO,CACrC,EACME,EAAaL,EAAQ,GAAG,UAAY,GACxCN,EAAS,QAAQ,YAAYS,CAAO,CACtC,EAEA,UAAa,CACXD,EAAU,EACVE,EAAU,EACVC,EAAW,EACXL,EAAQ,QAAQ,EAChB,EAAS,QAAU,KAEfb,IACF,EAAI,QAAU,KAElB,CAEF,EAAG,CAACW,CAAQ,CAAC,GAIb,EAAAd,EAAA,UAAA,KAAgB,CACd,IAAMe,EAAUN,EAAS,QACzB,GAAI,CAACM,EACH,OAGF,IAAMO,EAAO,KAAK,UAAUV,GAAU,CAAC,CAAC,EACpCU,IAAST,EAAQ,UAGrB,EAAQ,QAAUS,EAElBP,EAAQ,UAAUH,CAAM,EAC1B,EAAG,CAACA,CAAM,CAAC,GAGT,EAAAX,EAAA,IAAA,CAAC,MAAD,CACE,IAAKO,EACM,YACX,MAAO,CAAE,MAAO,OAAQ,OAAQ,OAAQ,GAAGe,CAAM,CAClD,CAAA,CAEL,CAAC,E"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { PDFMergeSortSplitClass as e } from "./index.js";
|
|
2
|
+
import { forwardRef as t, useCallback as n, useEffect as r, useRef as i } from "react";
|
|
3
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
4
|
+
// src/react.jsx
|
|
5
|
+
var o = () => {
|
|
6
|
+
let e = i(null);
|
|
7
|
+
return {
|
|
8
|
+
ref: e,
|
|
9
|
+
loadDocument: n((t) => e.current.loadDocument(t), []),
|
|
10
|
+
exportDocument: n((t, n) => e.current.exportDocument(t, n), []),
|
|
11
|
+
getPages: n(() => e.current.getPages(), [])
|
|
12
|
+
};
|
|
13
|
+
}, s = t(function({ config: t, style: n, className: o, onAction: s, onExport: c, onLicense: l, onReady: u }, d) {
|
|
14
|
+
let f = i(null), p = i(null), m = i({
|
|
15
|
+
onAction: s,
|
|
16
|
+
onExport: c,
|
|
17
|
+
onLicense: l,
|
|
18
|
+
onReady: u
|
|
19
|
+
});
|
|
20
|
+
m.current = {
|
|
21
|
+
onAction: s,
|
|
22
|
+
onExport: c,
|
|
23
|
+
onLicense: l,
|
|
24
|
+
onReady: u
|
|
25
|
+
};
|
|
26
|
+
let h = i(t);
|
|
27
|
+
h.current = t;
|
|
28
|
+
let g = i(null), _ = t?.embedUrl;
|
|
29
|
+
return r(() => {
|
|
30
|
+
let t = h.current, n = new e(f.current, t);
|
|
31
|
+
p.current = n, g.current = JSON.stringify(t ?? {}), d && (d.current = n), n.whenReady().then((e) => m.current.onReady?.(e)).catch(() => {});
|
|
32
|
+
let r = n.on("action", (e) => m.current.onAction?.(e)), i = n.on("export", (e) => m.current.onExport?.(e)), a = n.on("license", (e) => m.current.onLicense?.(e));
|
|
33
|
+
return () => {
|
|
34
|
+
r(), i(), a(), n.destroy(), p.current = null, d && (d.current = null);
|
|
35
|
+
};
|
|
36
|
+
}, [_]), r(() => {
|
|
37
|
+
let e = p.current;
|
|
38
|
+
if (!e) return;
|
|
39
|
+
let n = JSON.stringify(t ?? {});
|
|
40
|
+
n !== g.current && (g.current = n, e.setConfig(t));
|
|
41
|
+
}, [t]), /* @__PURE__ */ a("div", {
|
|
42
|
+
ref: f,
|
|
43
|
+
className: o,
|
|
44
|
+
style: {
|
|
45
|
+
width: "100%",
|
|
46
|
+
height: "100%",
|
|
47
|
+
...n
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
export { s as PDFMergeSortSplit, s as default, e as PDFMergeSortSplitClass, o as usePdfMergeSortSplit };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","names":["usePdfMergeSortSplit","ref","useRef","useCallback","document","reference","mode","PDFMergeSortSplit","forwardRef","container","instance","handlers","configRef","config","applied","embedUrl","useEffect","current","created","PDFMergeSortSplitClass","ready","offAction","payload","offExport","offLicense","json","style"],"sources":["../src/react.jsx"],"sourcesContent":["import React, { forwardRef, useCallback, useEffect, useRef } from 'react';\n\nimport { PDFMergeSortSplitClass } from './index.js';\n\n/**\n * The editor's methods, bound to the instance the component creates.\n *\n * ```jsx\n * const { ref, loadDocument, exportDocument, getPages } = usePdfMergeSortSplit();\n *\n * const handleAction = async ({ action }) => {\n * if (action === 'saveZip') download(await exportDocument(undefined, 'zip'));\n * };\n *\n * <PDFMergeSortSplit ref={ref} config={{ apiKey }} onAction={handleAction} />\n * ```\n *\n * The returned functions are stable, so callers need no `useCallback` or\n * `useMemo` wrapper; `ref` is only needed for the escape hatches\n * (`whenReady`, `on`, `destroy`) and to pass to the component.\n */\nexport const usePdfMergeSortSplit = () => {\n const ref = useRef(null);\n\n const loadDocument = useCallback(\n (document) => ref.current.loadDocument(document),\n [],\n );\n const exportDocument = useCallback(\n (reference, mode) => ref.current.exportDocument(reference, mode),\n [],\n );\n const getPages = useCallback(() => ref.current.getPages(), []);\n\n return { ref, loadDocument, exportDocument, getPages };\n};\n\n/**\n * The editor as a React component.\n *\n * The iframe is created once and lives for the lifetime of the component:\n * changing `onAction` / `onExport` / `onReady` does not reload it, and a new\n * `config` is applied to the running editor (`setConfig`) instead of rebuilding\n * it, so the open document stays. Only a different `config.embedUrl` needs a\n * new iframe, which the component creates itself.\n */\nexport const PDFMergeSortSplit = forwardRef(function PDFMergeSortSplit(\n { config, style, className, onAction, onExport, onLicense, onReady },\n ref,\n) {\n const container = useRef(null);\n const instance = useRef(null);\n const handlers = useRef({ onAction, onExport, onLicense, onReady });\n handlers.current = { onAction, onExport, onLicense, onReady };\n\n // The effect that creates the iframe needs the config of the render it runs\n // in, but must not re-run for every new config object.\n const configRef = useRef(config);\n configRef.current = config;\n\n // What the running editor already knows. `config={{ … }}` is a new object on\n // every render, so the comparison is by content, not by reference.\n const applied = useRef(null);\n\n // `embedUrl` is the iframe's src: only that needs a new iframe.\n const embedUrl = config?.embedUrl;\n\n useEffect(() => {\n const current = configRef.current;\n const created = new PDFMergeSortSplitClass(container.current, current);\n instance.current = created;\n applied.current = JSON.stringify(current ?? {});\n\n if (ref) {\n ref.current = created;\n }\n\n created\n .whenReady()\n .then((ready) => handlers.current.onReady?.(ready))\n .catch(() => {\n // `ready` rejects when the editor never answers; onReady is not called.\n });\n\n const offAction = created.on('action', (payload) =>\n handlers.current.onAction?.(payload),\n );\n const offExport = created.on('export', (payload) =>\n handlers.current.onExport?.(payload),\n );\n const offLicense = created.on('license', (payload) =>\n handlers.current.onLicense?.(payload),\n );\n\n return () => {\n offAction();\n offExport();\n offLicense();\n created.destroy();\n instance.current = null;\n\n if (ref) {\n ref.current = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [embedUrl]);\n\n // Everything except `embedUrl` is applied to the running editor, so a config\n // change does not reload the iframe and the open document stays.\n useEffect(() => {\n const current = instance.current;\n if (!current) {\n return;\n }\n\n const json = JSON.stringify(config ?? {});\n if (json === applied.current) {\n return;\n }\n applied.current = json;\n\n current.setConfig(config);\n }, [config]);\n\n return (\n <div\n ref={container}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n />\n );\n});\n\nexport { PDFMergeSortSplitClass } from './index.js';\nexport default PDFMergeSortSplit;\n"],"mappings":";;;;AAqBA,IAAaA,UAA6B;CACxC,IAAMC,IAAMC,EAAO,IAAI;CAYvB,OAAO;EAAE;EAAK,cAVOC,GAClB,MAAaF,EAAI,QAAQ,aAAaG,CAAQ,GAC/C,CAAC,CAQW;EAAc,gBANLD,GACpB,GAAW,MAASF,EAAI,QAAQ,eAAeI,GAAWC,CAAI,GAC/D,CAAC,CAIyB;EAAgB,UAF3BH,QAAkBF,EAAI,QAAQ,SAAS,GAAG,CAAC,CAEhB;CAAS;AACvD,GAWaM,IAAoBC,EAAW,SAC1C,EAAE,WAAQ,UAAO,cAAW,aAAU,aAAU,cAAW,cAC3D,GACA;CACA,IAAMC,IAAYP,EAAO,IAAI,GACvBQ,IAAWR,EAAO,IAAI,GACtBS,IAAWT,EAAO;EAAE;EAAU;EAAU;EAAW;CAAQ,CAAC;CAClE,EAAS,UAAU;EAAE;EAAU;EAAU;EAAW;CAAQ;CAI5D,IAAMU,IAAYV,EAAOW,CAAM;CAC/B,EAAU,UAAUA;CAIpB,IAAMC,IAAUZ,EAAO,IAAI,GAGrBa,IAAWF,GAAQ;CA4DzB,OA1DAG,QAAgB;EACd,IAAMC,IAAUL,EAAU,SACpBM,IAAU,IAAIC,EAAuBV,EAAU,SAASQ,CAAO;EAQrE,AAPA,EAAS,UAAUC,GACnB,EAAQ,UAAU,KAAK,UAAUD,KAAW,CAAC,CAAC,GAE1ChB,MACF,EAAI,UAAUiB,IAGhBA,EACG,UAAU,CAAC,CACX,MAAM,MAAUP,EAAS,QAAQ,UAAUS,CAAK,CAAC,CAAC,CAClD,YAAY,CAEb,CAAC;EAEH,IAAMC,IAAYH,EAAQ,GAAG,WAAW,MACtCP,EAAS,QAAQ,WAAWW,CAAO,CACrC,GACMC,IAAYL,EAAQ,GAAG,WAAW,MACtCP,EAAS,QAAQ,WAAWW,CAAO,CACrC,GACME,IAAaN,EAAQ,GAAG,YAAY,MACxCP,EAAS,QAAQ,YAAYW,CAAO,CACtC;EAEA,aAAa;GAOX,AANAD,EAAU,GACVE,EAAU,GACVC,EAAW,GACXN,EAAQ,QAAQ,GAChB,EAAS,UAAU,MAEfjB,MACF,EAAI,UAAU;EAElB;CAEF,GAAG,CAACc,CAAQ,CAAC,GAIbC,QAAgB;EACd,IAAMC,IAAUP,EAAS;EACzB,IAAI,CAACO,GACH;EAGF,IAAMQ,IAAO,KAAK,UAAUZ,KAAU,CAAC,CAAC;EACxC,AAAIY,MAASX,EAAQ,YAGrB,EAAQ,UAAUW,GAElBR,EAAQ,UAAUJ,CAAM;CAC1B,GAAG,CAACA,CAAM,CAAC,GAGT,kBAAC,OAAD;EACE,KAAKJ;EACM;EACX,OAAO;GAAE,OAAO;GAAQ,QAAQ;GAAQ,GAAGiB;EAAM;CAClD,CAAA;AAEL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rsj-de/pdfmergesortsplit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Embed the RSJ PDF Merge, Sort & Split editor in your own product: one iframe, a small SDK, documents never leave the browser.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pdf",
|
|
7
|
+
"merge",
|
|
8
|
+
"split",
|
|
9
|
+
"pdf-editor",
|
|
10
|
+
"iframe",
|
|
11
|
+
"rsj"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://pdfmerge.rsj.de/docs/getting-started",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/pdfmergesortsplit/pdfmergesortsplit.git",
|
|
17
|
+
"directory": "sdk"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/pdfmergesortsplit/pdfmergesortsplit/issues"
|
|
21
|
+
},
|
|
22
|
+
"author": "RSJ Software GmbH <ruediger.jungbeck@rsj.de> (https://rsj.de)",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "./dist/index.cjs",
|
|
25
|
+
"module": "./dist/index.js",
|
|
26
|
+
"types": "./types/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./types/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js",
|
|
31
|
+
"require": "./dist/index.cjs"
|
|
32
|
+
},
|
|
33
|
+
"./react": {
|
|
34
|
+
"types": "./types/react.d.ts",
|
|
35
|
+
"import": "./dist/react.js",
|
|
36
|
+
"require": "./dist/react.cjs"
|
|
37
|
+
},
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"types",
|
|
43
|
+
"README.md",
|
|
44
|
+
"LICENSE"
|
|
45
|
+
],
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"sideEffects": false,
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "vite build",
|
|
53
|
+
"prepublishOnly": "pnpm run build"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"react": ">=18"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"react": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@vitejs/plugin-react": "^4.7.0",
|
|
65
|
+
"react": "^19.2.6",
|
|
66
|
+
"vite": "^8.0.13"
|
|
67
|
+
}
|
|
68
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/** Configuration the embedding page hands to the editor. */
|
|
2
|
+
export interface PDFMergeConfig {
|
|
3
|
+
/** Where the editor is served (default `https://pdfmerge.rsj.de`). */
|
|
4
|
+
embedUrl?: string;
|
|
5
|
+
/** Licence JWT - removes the test-mode banner in the embedded editor. */
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
/** Title shown in the editor's title bar. */
|
|
8
|
+
title?: string;
|
|
9
|
+
/** Icon (URL) that replaces ours in the title bar. */
|
|
10
|
+
icon?: string;
|
|
11
|
+
/**
|
|
12
|
+
* OAuth client ID of your own Google Cloud project for the Drive integration.
|
|
13
|
+
* It overrides the one compiled into the editor, so a self-hosted deployment
|
|
14
|
+
* needs no rebuild. Without it the Drive buttons are hidden.
|
|
15
|
+
*/
|
|
16
|
+
googleClientId?: string;
|
|
17
|
+
/** Hide parts of the editor's UI. Everything is shown by default. */
|
|
18
|
+
ui?: {
|
|
19
|
+
logo?: boolean;
|
|
20
|
+
icon?: boolean;
|
|
21
|
+
landing?: boolean;
|
|
22
|
+
title?: boolean;
|
|
23
|
+
about?: boolean;
|
|
24
|
+
blog?: boolean;
|
|
25
|
+
language?: boolean;
|
|
26
|
+
extension?: boolean;
|
|
27
|
+
fullscreen?: boolean;
|
|
28
|
+
theme?: boolean;
|
|
29
|
+
toolbar?: {
|
|
30
|
+
new?: boolean;
|
|
31
|
+
savePdf?: boolean;
|
|
32
|
+
saveZip?: boolean;
|
|
33
|
+
saveDrive?: boolean;
|
|
34
|
+
print?: boolean;
|
|
35
|
+
undo?: boolean;
|
|
36
|
+
redo?: boolean;
|
|
37
|
+
upload?: boolean;
|
|
38
|
+
drive?: boolean;
|
|
39
|
+
addText?: boolean;
|
|
40
|
+
scaleSort?: boolean;
|
|
41
|
+
pages?: boolean;
|
|
42
|
+
rotate?: boolean;
|
|
43
|
+
previous?: boolean;
|
|
44
|
+
next?: boolean;
|
|
45
|
+
delete?: boolean;
|
|
46
|
+
scalePage?: boolean;
|
|
47
|
+
};
|
|
48
|
+
partHeader?: {
|
|
49
|
+
label?: boolean;
|
|
50
|
+
name?: boolean;
|
|
51
|
+
pages?: boolean;
|
|
52
|
+
save?: boolean;
|
|
53
|
+
drive?: boolean;
|
|
54
|
+
print?: boolean;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
/** Buttons injected into the editor; clicks arrive as "action" events. */
|
|
58
|
+
actions?: {
|
|
59
|
+
loaders?: Record<string, PDFMergeAction>;
|
|
60
|
+
saveAll?: Record<string, PDFMergeAction>;
|
|
61
|
+
savePart?: Record<string, PDFMergeAction>;
|
|
62
|
+
};
|
|
63
|
+
/** Write the page provenance into exported PDFs (default off). */
|
|
64
|
+
provenance?: { attach?: boolean };
|
|
65
|
+
/** Timeout for the initial handshake in ms (default 20000). */
|
|
66
|
+
readyTimeout?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface PDFMergeAction {
|
|
70
|
+
title?: string;
|
|
71
|
+
icon?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface PDFMergePage {
|
|
75
|
+
id: number;
|
|
76
|
+
page: number;
|
|
77
|
+
rotate: number;
|
|
78
|
+
partName: string;
|
|
79
|
+
provenance: unknown;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface PDFMergeActionEvent {
|
|
83
|
+
/** Key of the clicked button in `config.actions` - not the injection point. */
|
|
84
|
+
action: string;
|
|
85
|
+
/** Injection point the button was configured in. */
|
|
86
|
+
where: 'loaders' | 'saveAll' | 'savePart';
|
|
87
|
+
reference?: string;
|
|
88
|
+
part?: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface PDFMergeExportEvent {
|
|
92
|
+
reference?: string | number;
|
|
93
|
+
mode: 'pdf' | 'zip';
|
|
94
|
+
fileName: string;
|
|
95
|
+
pages: Array<{ page: number; provenance: unknown }>;
|
|
96
|
+
blob: Blob;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface PDFMergeLicenseEvent {
|
|
100
|
+
licensed: boolean;
|
|
101
|
+
reason?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface LoadDocumentOptions {
|
|
105
|
+
name?: string;
|
|
106
|
+
content: File | Blob | ArrayBuffer | Uint8Array | string;
|
|
107
|
+
provenance?: unknown[] | object;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export declare class PDFMergeSortSplitClass {
|
|
111
|
+
constructor(container: string | HTMLElement, config?: PDFMergeConfig);
|
|
112
|
+
|
|
113
|
+
readonly iframe: HTMLIFrameElement;
|
|
114
|
+
|
|
115
|
+
whenReady(): Promise<PDFMergeSortSplitClass>;
|
|
116
|
+
/** Apply a new configuration to the running editor (no reload). */
|
|
117
|
+
setConfig(config?: PDFMergeConfig): void;
|
|
118
|
+
on(event: 'action', handler: (event: PDFMergeActionEvent) => void): () => void;
|
|
119
|
+
on(event: 'export', handler: (event: PDFMergeExportEvent) => void): () => void;
|
|
120
|
+
on(event: 'license', handler: (event: PDFMergeLicenseEvent) => void): () => void;
|
|
121
|
+
off(event: string, handler: (event: unknown) => void): void;
|
|
122
|
+
loadDocument(options: LoadDocumentOptions): Promise<unknown>;
|
|
123
|
+
loadDocument(name: string, content: LoadDocumentOptions['content']): Promise<unknown>;
|
|
124
|
+
getPages(): Promise<PDFMergePage[]>;
|
|
125
|
+
exportDocument(reference?: string | number, mode?: 'pdf' | 'zip'): Promise<Blob>;
|
|
126
|
+
destroy(): void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default PDFMergeSortSplitClass;
|
package/types/react.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CSSProperties, RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
PDFMergeActionEvent,
|
|
5
|
+
PDFMergeConfig,
|
|
6
|
+
PDFMergeExportEvent,
|
|
7
|
+
PDFMergeLicenseEvent,
|
|
8
|
+
PDFMergePage,
|
|
9
|
+
PDFMergeSortSplitClass,
|
|
10
|
+
} from './index.js';
|
|
11
|
+
|
|
12
|
+
export interface PDFMergeSortSplitProps {
|
|
13
|
+
config?: PDFMergeConfig;
|
|
14
|
+
style?: CSSProperties;
|
|
15
|
+
className?: string;
|
|
16
|
+
onAction?: (event: PDFMergeActionEvent) => void;
|
|
17
|
+
onExport?: (event: PDFMergeExportEvent) => void;
|
|
18
|
+
onLicense?: (event: PDFMergeLicenseEvent) => void;
|
|
19
|
+
onReady?: (editor: PDFMergeSortSplitClass) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export declare const PDFMergeSortSplit: React.ForwardRefExoticComponent<
|
|
23
|
+
PDFMergeSortSplitProps & React.RefAttributes<PDFMergeSortSplitClass | null>
|
|
24
|
+
>;
|
|
25
|
+
|
|
26
|
+
export declare function usePdfMergeSortSplit(): {
|
|
27
|
+
ref: RefObject<PDFMergeSortSplitClass | null>;
|
|
28
|
+
loadDocument: (
|
|
29
|
+
document:
|
|
30
|
+
| { name?: string; content: File | Blob | ArrayBuffer | Uint8Array | string; provenance?: unknown[] | object }
|
|
31
|
+
| string,
|
|
32
|
+
content?: File | Blob | ArrayBuffer | Uint8Array | string,
|
|
33
|
+
) => Promise<unknown>;
|
|
34
|
+
exportDocument: (reference?: string | number, mode?: 'pdf' | 'zip') => Promise<Blob>;
|
|
35
|
+
getPages: () => Promise<PDFMergePage[]>;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export { PDFMergeSortSplitClass } from './index.js';
|
|
39
|
+
export default PDFMergeSortSplit;
|