web-to-print 0.1.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 (92) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
  3. package/dist/cjs/canvas-helpers-A6rp5rPD.js +765 -0
  4. package/dist/cjs/index-IFGFRm-i.js +1649 -0
  5. package/dist/cjs/index.cjs.js +232 -0
  6. package/dist/cjs/loader.cjs.js +13 -0
  7. package/dist/cjs/logo-BUX-b45R.js +18 -0
  8. package/dist/cjs/web-to-print.cjs.js +25 -0
  9. package/dist/cjs/wtp-editor_2.cjs.entry.js +12386 -0
  10. package/dist/cjs/wtp-logo-renderer.cjs.entry.js +353 -0
  11. package/dist/cjs/wtp-print-area-editor.cjs.entry.js +431 -0
  12. package/dist/collection/collection-manifest.json +16 -0
  13. package/dist/collection/components/wtp-editor/wtp-editor.css +124 -0
  14. package/dist/collection/components/wtp-editor/wtp-editor.js +1114 -0
  15. package/dist/collection/components/wtp-logo-renderer/wtp-logo-renderer.css +30 -0
  16. package/dist/collection/components/wtp-logo-renderer/wtp-logo-renderer.js +455 -0
  17. package/dist/collection/components/wtp-logo-upload/wtp-logo-upload.css +428 -0
  18. package/dist/collection/components/wtp-logo-upload/wtp-logo-upload.js +573 -0
  19. package/dist/collection/components/wtp-print-area-editor/wtp-print-area-editor.css +20 -0
  20. package/dist/collection/components/wtp-print-area-editor/wtp-print-area-editor.js +600 -0
  21. package/dist/collection/examples/schaeffler--big.svg +1 -0
  22. package/dist/collection/index.js +8 -0
  23. package/dist/collection/types/editor.js +1 -0
  24. package/dist/collection/types/index.js +2 -0
  25. package/dist/collection/types/labels.js +30 -0
  26. package/dist/collection/types/logo.js +13 -0
  27. package/dist/collection/utils/background-removal.js +717 -0
  28. package/dist/collection/utils/canvas-helpers.js +380 -0
  29. package/dist/collection/utils/format-detection.js +48 -0
  30. package/dist/collection/utils/html-render-helpers.js +106 -0
  31. package/dist/collection/utils/image-preview.js +54 -0
  32. package/dist/collection/utils/logo-validation.js +141 -0
  33. package/dist/collection/utils/pdf-export.js +224 -0
  34. package/dist/components/index.d.ts +35 -0
  35. package/dist/components/index.js +1 -0
  36. package/dist/components/p-5qCsRzlt.js +1 -0
  37. package/dist/components/p-Bn9gR_8e.js +1 -0
  38. package/dist/components/p-D8pVJRuX.js +1 -0
  39. package/dist/components/wtp-editor.d.ts +11 -0
  40. package/dist/components/wtp-editor.js +1 -0
  41. package/dist/components/wtp-logo-renderer.d.ts +11 -0
  42. package/dist/components/wtp-logo-renderer.js +1 -0
  43. package/dist/components/wtp-logo-upload.d.ts +11 -0
  44. package/dist/components/wtp-logo-upload.js +1 -0
  45. package/dist/components/wtp-print-area-editor.d.ts +11 -0
  46. package/dist/components/wtp-print-area-editor.js +1 -0
  47. package/dist/esm/app-globals-DQuL1Twl.js +3 -0
  48. package/dist/esm/canvas-helpers-CK8OAq2J.js +748 -0
  49. package/dist/esm/index-CUetmLbL.js +1641 -0
  50. package/dist/esm/index.js +228 -0
  51. package/dist/esm/loader.js +11 -0
  52. package/dist/esm/logo-D8pVJRuX.js +15 -0
  53. package/dist/esm/web-to-print.js +21 -0
  54. package/dist/esm/wtp-editor_2.entry.js +12383 -0
  55. package/dist/esm/wtp-logo-renderer.entry.js +351 -0
  56. package/dist/esm/wtp-print-area-editor.entry.js +429 -0
  57. package/dist/index.cjs.js +1 -0
  58. package/dist/index.js +1 -0
  59. package/dist/types/components/wtp-editor/wtp-editor.d.ts +101 -0
  60. package/dist/types/components/wtp-logo-renderer/wtp-logo-renderer.d.ts +55 -0
  61. package/dist/types/components/wtp-logo-upload/wtp-logo-upload.d.ts +76 -0
  62. package/dist/types/components/wtp-print-area-editor/wtp-print-area-editor.d.ts +43 -0
  63. package/dist/types/components.d.ts +507 -0
  64. package/dist/types/index.d.ts +11 -0
  65. package/dist/types/stencil-public-runtime.d.ts +1860 -0
  66. package/dist/types/types/editor.d.ts +79 -0
  67. package/dist/types/types/index.d.ts +5 -0
  68. package/dist/types/types/labels.d.ts +30 -0
  69. package/dist/types/types/logo.d.ts +47 -0
  70. package/dist/types/utils/background-removal.d.ts +95 -0
  71. package/dist/types/utils/canvas-helpers.d.ts +60 -0
  72. package/dist/types/utils/format-detection.d.ts +4 -0
  73. package/dist/types/utils/html-render-helpers.d.ts +44 -0
  74. package/dist/types/utils/image-preview.d.ts +13 -0
  75. package/dist/types/utils/logo-validation.d.ts +2 -0
  76. package/dist/types/utils/pdf-export.d.ts +32 -0
  77. package/dist/web-to-print/index.esm.js +1 -0
  78. package/dist/web-to-print/p-611ec561.entry.js +1 -0
  79. package/dist/web-to-print/p-703e4c52.entry.js +1 -0
  80. package/dist/web-to-print/p-CK8OAq2J.js +1 -0
  81. package/dist/web-to-print/p-CUetmLbL.js +2 -0
  82. package/dist/web-to-print/p-D8pVJRuX.js +1 -0
  83. package/dist/web-to-print/p-DQuL1Twl.js +1 -0
  84. package/dist/web-to-print/p-b532777b.entry.js +1 -0
  85. package/dist/web-to-print/web-to-print.esm.js +1 -0
  86. package/loader/cdn.js +1 -0
  87. package/loader/index.cjs.js +1 -0
  88. package/loader/index.d.ts +24 -0
  89. package/loader/index.es2017.js +1 -0
  90. package/loader/index.js +2 -0
  91. package/package.json +68 -0
  92. package/readme.md +490 -0
package/readme.md ADDED
@@ -0,0 +1,490 @@
1
+ # web-to-print
2
+
3
+ A Stencil.js Web Components library for promotional product customization. Upload logos, preview them on products, and edit layouts — all client-side, no server required.
4
+
5
+ ## Components
6
+
7
+ | Component | Description | Encapsulation |
8
+ |---|---|---|
9
+ | `<wtp-logo-upload>` | Logo upload with drag-and-drop, URL fetch, format detection, print validation, and optional background removal | Shadow DOM |
10
+ | `<wtp-logo-renderer>` | Static logo-on-product rendering via Fabric.js StaticCanvas | Scoped |
11
+ | `<wtp-editor>` | Interactive canvas editor with toolbar, text tool, and JSON serialization via Fabric.js | Scoped |
12
+
13
+ Components communicate via CustomEvents and can be used standalone or composed together.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install web-to-print
19
+ ```
20
+
21
+ ### Lazy-loading (recommended)
22
+
23
+ ```html
24
+ <script type="module" src="web-to-print/loader/index.js"></script>
25
+ ```
26
+
27
+ Or with a bundler:
28
+
29
+ ```js
30
+ import { defineCustomElements } from 'web-to-print/loader';
31
+ defineCustomElements();
32
+ ```
33
+
34
+ ### Standalone custom elements
35
+
36
+ ```js
37
+ import 'web-to-print/wtp-logo-upload';
38
+ import 'web-to-print/wtp-editor';
39
+ import 'web-to-print/wtp-logo-renderer';
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ ```html
45
+ <!-- 1. Upload a logo -->
46
+ <wtp-logo-upload id="uploader"></wtp-logo-upload>
47
+
48
+ <!-- 2. Render it on a product -->
49
+ <wtp-logo-renderer id="renderer" width="400" height="300"></wtp-logo-renderer>
50
+
51
+ <!-- 3. Open an interactive editor -->
52
+ <wtp-editor id="editor" width="800" height="600"></wtp-editor>
53
+
54
+ <script>
55
+ const uploader = document.getElementById('uploader');
56
+ const renderer = document.getElementById('renderer');
57
+ const editor = document.getElementById('editor');
58
+
59
+ uploader.addEventListener('wtpLogoValidated', async (e) => {
60
+ const logo = e.detail;
61
+
62
+ // Place logo on the static renderer
63
+ renderer.logos = [{
64
+ id: 'logo-1',
65
+ dataUrl: logo.dataUrl,
66
+ transform: { x: 200, y: 150, scaleX: 0.5, scaleY: 0.5, angle: 0 },
67
+ }];
68
+
69
+ // Or add it to the interactive editor
70
+ await editor.addLogo(logo);
71
+ });
72
+ </script>
73
+ ```
74
+
75
+ ## Component API
76
+
77
+ ### `<wtp-logo-upload>`
78
+
79
+ Validates uploaded files against configurable print-quality rules (format, DPI, dimensions, file size). Supports file picker, drag-and-drop, and URL fetch.
80
+
81
+ #### Properties
82
+
83
+ | Property | Attribute | Type | Default | Description |
84
+ |---|---|---|---|---|
85
+ | `config` | — | `LogoValidationConfig` | See below | Validation rules for uploaded logos |
86
+ | `accept` | `accept` | `string` | `'image/png,image/jpeg,image/svg+xml,image/tiff,image/avif,application/pdf'` | Accepted MIME types for file input |
87
+ | `multiple` | `multiple` | `boolean` | `false` | Allow multiple file uploads |
88
+ | `disabled` | `disabled` | `boolean` | `false` | Disable the upload component |
89
+ | `enableBackgroundRemoval` | `enable-background-removal` | `boolean` | `false` | Enable client-side background removal for raster images |
90
+ | `bgRemovalConfig` | — | `Partial<BgRemovalConfig>` | `{}` | Configuration for the color-based background removal algorithm |
91
+ | `labels` | — | `Partial<LogoUploadLabels>` | `{}` | Override user-facing strings (see [Localizing text](#localizing-text-labels-prop)) |
92
+
93
+ **Default validation config:**
94
+
95
+ ```js
96
+ {
97
+ minDpi: 300,
98
+ maxFileSize: 50 * 1024 * 1024, // 50 MB
99
+ minWidth: 100,
100
+ minHeight: 100,
101
+ allowedFormats: ['png', 'jpeg', 'svg', 'pdf', 'tiff', 'avif'],
102
+ }
103
+ ```
104
+
105
+ #### Events
106
+
107
+ | Event | Detail | Description |
108
+ |---|---|---|
109
+ | `wtpLogoValidated` | `LogoData` | Fires when a logo passes validation |
110
+ | `wtpLogoRejected` | `{ file: File; issues: LogoValidationIssue[] }` | Fires when a logo fails validation |
111
+ | `wtpLogoProcessing` | `boolean` | Fires when processing state changes (`true` = busy) |
112
+
113
+ #### Background Removal
114
+
115
+ When `enable-background-removal` is set and a raster image (PNG, JPEG, TIFF, AVIF) is uploaded, the user is presented with a choice between the original image and a version with the background removed. SVG and PDF files skip this step entirely.
116
+
117
+ The background removal runs entirely client-side using a color-based flood-fill algorithm with zero external dependencies:
118
+
119
+ 1. Samples all pixels along the 4 edges of the image
120
+ 2. Finds the dominant edge color (quantized into buckets)
121
+ 3. BFS flood-fills from edge pixels within `tolerance` distance of the background color
122
+ 4. Sets matched pixels to transparent — interior regions of the same color (e.g. white text) are preserved
123
+
124
+ Configure via `bgRemovalConfig`:
125
+
126
+ | Option | Type | Default | Description |
127
+ |---|---|---|---|
128
+ | `tolerance` | `number` | `40` | Color distance threshold (0-255, Euclidean RGB distance) |
129
+ | `minEdgeRatio` | `number` | `0.3` | Minimum fraction of edge pixels sharing a color to count as background |
130
+
131
+ ```html
132
+ <wtp-logo-upload enable-background-removal></wtp-logo-upload>
133
+ ```
134
+
135
+ #### URL Input
136
+
137
+ Users can also paste an HTTPS URL to fetch a remote logo. The fetched file goes through the same validation pipeline. Non-HTTPS URLs are rejected, and CORS errors are displayed with a clear message.
138
+
139
+ ---
140
+
141
+ ### `<wtp-logo-renderer>`
142
+
143
+ Non-interactive canvas for rendering logos on product images. Uses Fabric.js `StaticCanvas` for lightweight rendering without user interaction.
144
+
145
+ #### Properties
146
+
147
+ | Property | Attribute | Type | Default | Description |
148
+ |---|---|---|---|---|
149
+ | `productImage` | `product-image` | `string \| undefined` | `undefined` | Product background image URL |
150
+ | `width` | `width` | `number` | `600` | Canvas width in pixels |
151
+ | `height` | `height` | `number` | `400` | Canvas height in pixels |
152
+ | `logos` | — | `PlacedLogo[]` | `[]` | Array of logos to place on the canvas |
153
+ | `backgroundColor` | `background-color` | `string` | `'#ffffff'` | Canvas background color |
154
+ | `printArea` | — | `PrintArea \| undefined` | `undefined` | Auto-fits logos without an explicit `transform` into the area (0–1 relative coords) |
155
+
156
+ #### Events
157
+
158
+ | Event | Detail | Description |
159
+ |---|---|---|
160
+ | `wtpRenderComplete` | `{ dataUrl: string }` | Fires when all logos have been rendered |
161
+ | `wtpRenderError` | `{ message: string }` | Fires on rendering error |
162
+
163
+ #### Methods
164
+
165
+ | Method | Signature | Description |
166
+ |---|---|---|
167
+ | `exportImage` | `(format?: 'png' \| 'jpeg', quality?: number) => Promise<string>` | Export canvas as a data URL |
168
+
169
+ ---
170
+
171
+ ### `<wtp-editor>`
172
+
173
+ Interactive canvas editor with a built-in toolbar for adding text, changing fonts, deleting objects, and exporting. Uses Fabric.js `Canvas` for full interactivity (drag, resize, rotate).
174
+
175
+ #### Properties
176
+
177
+ | Property | Attribute | Type | Default | Description |
178
+ |---|---|---|---|---|
179
+ | `width` | `width` | `number` | `800` | Canvas width in pixels |
180
+ | `height` | `height` | `number` | `600` | Canvas height in pixels |
181
+ | `productImage` | `product-image` | `string \| undefined` | `undefined` | Product background image URL |
182
+ | `initialState` | `initial-state` | `string \| undefined` | `undefined` | JSON-serialized initial editor state |
183
+ | `fonts` | — | `string[]` | `['Arial', 'Helvetica', 'Times New Roman', 'Georgia', 'Verdana']` | Available font families for the text tool |
184
+ | `printArea` | — | `PrintArea \| undefined` | `undefined` | Print area (0–1 relative coords) used to constrain objects to a defined region |
185
+ | `debug` | `debug` | `boolean` | `false` | Show the print-area overlay and clamp bounding box on the canvas |
186
+ | `labels` | — | `Partial<EditorLabels>` | `{}` | Override toolbar strings (see [Localizing text](#localizing-text-labels-prop)) |
187
+
188
+ #### Events
189
+
190
+ | Event | Detail | Description |
191
+ |---|---|---|
192
+ | `wtpEditorReady` | `void` | Fires when the canvas is initialized |
193
+ | `wtpEditorStateChanged` | `EditorState` | Fires on any object change (add/move/remove) |
194
+ | `wtpEditorObjectSelected` | `{ id: string; type: string }` | Fires when an object is selected |
195
+ | `wtpEditorObjectDeselected` | `void` | Fires when the selection is cleared |
196
+
197
+ #### Methods
198
+
199
+ | Method | Signature | Description |
200
+ |---|---|---|
201
+ | `addLogo` | `(logoData: LogoData) => Promise<string>` | Add a logo image, returns its object ID |
202
+ | `addText` | `(text: string, options?: { fontFamily?, fontSize?, fill? }) => Promise<string>` | Add a text object, returns its object ID |
203
+ | `updateText` | `(id: string, text: string) => Promise<void>` | Update the text content of an `i-text` object by ID |
204
+ | `removeObject` | `(id: string) => Promise<void>` | Remove an object by ID |
205
+ | `resetCanvas` | `() => Promise<void>` | Clear all user objects, keep the canvas instance alive |
206
+ | `exportState` | `() => Promise<EditorState>` | Export the full editor state as a serializable object |
207
+ | `loadState` | `(state: EditorState) => Promise<void>` | Restore a previously exported editor state |
208
+ | `exportImage` | `(format?: 'png' \| 'jpeg', quality?: number) => Promise<string>` | Export canvas as a data URL (1× resolution) |
209
+ | `exportImageHighRes` | `(format?, quality?, multiplier?) => Promise<{ dataUrl, width, height }>` | High-resolution export for PDF/print (default 3× multiplier) |
210
+ | `getObjects` | `() => Promise<{ id: string; type: string }[]>` | List all objects on the canvas |
211
+
212
+ ## TypeScript Types
213
+
214
+ All types are exported from the package root:
215
+
216
+ ```ts
217
+ import type {
218
+ LogoFormat, // 'png' | 'jpeg' | 'svg' | 'pdf' | 'tiff' | 'avif' | 'unknown'
219
+ LogoMetadata, // Format, dimensions, DPI, file size, transparency
220
+ LogoValidationConfig, // Validation rules (minDpi, maxFileSize, minWidth, etc.)
221
+ LogoValidationIssue, // { code, severity, message }
222
+ LogoValidationResult, // { valid, metadata, issues }
223
+ LogoData, // { dataUrl, previewDataUrl?, metadata }
224
+ BgRemovalConfig, // { tolerance, minEdgeRatio }
225
+ CanvasTransform, // { x, y, scaleX, scaleY, angle, skewX?, skewY? }
226
+ PlacedLogo, // { id, dataUrl, previewDataUrl?, transform? }
227
+ PlacedText, // { id, text, fontFamily, fontSize, fill, transform }
228
+ EditorState, // { fabricJson, logos, texts, productImage, width, height }
229
+ PrintArea, // { topLeft, topRight, bottomRight, bottomLeft, bulge? } (0–1 coords)
230
+ RelativePoint, // { x, y } in 0–1 space
231
+ ArticleView, // Single article view + print-method metadata
232
+ Article, // Multi-view article descriptor
233
+ LogoUploadLabels, // Strings used by <wtp-logo-upload>
234
+ EditorLabels, // Strings used by <wtp-editor>
235
+ } from 'web-to-print';
236
+
237
+ import {
238
+ DEFAULT_VALIDATION_CONFIG,
239
+ DEFAULT_BG_REMOVAL_CONFIG,
240
+ DEFAULT_LOGO_UPLOAD_LABELS,
241
+ DEFAULT_EDITOR_LABELS,
242
+ } from 'web-to-print';
243
+ ```
244
+
245
+ ## Theming
246
+
247
+ Components expose colors and the font family as **CSS custom properties** with sensible fallbacks. Override them with a plain CSS rule — no build step or SCSS knowledge required. CSS variables inherit through the Shadow DOM, so the same rule themes `wtp-logo-upload` (shadow-encapsulated) and the scoped components.
248
+
249
+ ```css
250
+ /* Theme all components globally */
251
+ :root {
252
+ --wtp-color-primary: #ff6600;
253
+ --wtp-color-primary-hover: #e65500;
254
+ --wtp-color-primary-light: #ffe4d1;
255
+ --wtp-color-primary-fade: rgba(255, 102, 0, 0.2); /* used for focus glow */
256
+ --wtp-font-family: 'Inter', sans-serif;
257
+ }
258
+
259
+ /* Or scope to a single instance */
260
+ wtp-editor {
261
+ --wtp-color-border: #aaaaaa;
262
+ --wtp-color-bg-muted: #1e1e1e;
263
+ --wtp-color-text: #ffffff;
264
+ }
265
+ ```
266
+
267
+ ### Available CSS custom properties
268
+
269
+ | Variable | Default | Description |
270
+ |---|---|---|
271
+ | `--wtp-color-primary` | `#2563eb` | Primary action color (buttons, focus rings, dashed outlines) |
272
+ | `--wtp-color-primary-hover` | `#1d4ed8` | Primary hover state |
273
+ | `--wtp-color-primary-light` | `#dbeafe` | Primary tint (drop zone hover/drag-over) |
274
+ | `--wtp-color-primary-fade` | `rgba(37, 99, 235, 0.2)` | Translucent primary (selected-preview glow) |
275
+ | `--wtp-color-secondary` | `#64748b` | Secondary accent (upload icon stroke, preview hover) |
276
+ | `--wtp-color-error` | `#dc2626` | Error state color |
277
+ | `--wtp-color-error-light` | `#fee2e2` | Error background tint |
278
+ | `--wtp-color-success` | `#16a34a` | Success state color |
279
+ | `--wtp-color-success-light` | `#dcfce7` | Success background tint |
280
+ | `--wtp-color-warning` | `#d97706` | Warning state color |
281
+ | `--wtp-color-warning-light` | `#fef3c7` | Warning background tint |
282
+ | `--wtp-color-text` | `#1e293b` | Primary text color |
283
+ | `--wtp-color-text-muted` | `#64748b` | Muted/secondary text color |
284
+ | `--wtp-color-border` | `#e2e8f0` | Border color |
285
+ | `--wtp-color-bg` | `#ffffff` | Background color |
286
+ | `--wtp-color-bg-muted` | `#f8fafc` | Muted background (toolbar, drop zone) |
287
+ | `--wtp-font-family` | system stack | UI font family |
288
+
289
+ > Spacing and border-radius remain build-time SCSS tokens (`$wtp-spacing-*`, `$wtp-radius-*`) — they're not exposed as CSS variables. Fork the package if you need to change them.
290
+
291
+ ### `::part()` styling (`wtp-logo-upload`)
292
+
293
+ Because `wtp-logo-upload` uses Shadow DOM, internal elements aren't reachable with normal selectors. Use the `::part()` pseudo-element to target specific elements:
294
+
295
+ ```css
296
+ wtp-logo-upload::part(url-submit-btn) {
297
+ background: #16a34a;
298
+ border-color: #16a34a;
299
+ }
300
+
301
+ wtp-logo-upload::part(upload-zone drag-over) {
302
+ border-color: red;
303
+ background: #ffe5e5;
304
+ }
305
+
306
+ wtp-logo-upload::part(preview-item selected) {
307
+ outline: 3px solid gold;
308
+ }
309
+ ```
310
+
311
+ | Part name | Element |
312
+ |---|---|
313
+ | `root` | Outer wrapper |
314
+ | `url-input` | URL `<input type="url">` |
315
+ | `url-submit-btn` | "Fetch" button |
316
+ | `url-error` | URL error message paragraph |
317
+ | `divider` | "or" divider line |
318
+ | `upload-zone` | Drag-and-drop zone (also `drag-over` and `disabled` modifier parts) |
319
+ | `prompt-text` / `prompt-hint` | Default prompt text and hint inside the drop zone |
320
+ | `rejections` / `rejection-item` | Validation failure container and items |
321
+ | `pending-choices` / `choice-card` / `choice-option` | Background-removal choice cards |
322
+ | `previews` / `preview-item` | Preview gallery and items (selected items also get `selected`) |
323
+ | `remove-btn` | Per-preview remove button |
324
+
325
+ ### Localizing text (`labels` prop)
326
+
327
+ `wtp-logo-upload` and `wtp-editor` accept a `labels` prop with **partial** overrides — supply only the keys you want to change; missing keys fall back to the English defaults.
328
+
329
+ ```html
330
+ <wtp-logo-upload id="uploader"></wtp-logo-upload>
331
+ <script>
332
+ document.getElementById('uploader').labels = {
333
+ dropPromptText: 'Logo hierher ziehen oder klicken',
334
+ dropPromptHint: 'PNG, JPEG, SVG, TIFF oder AVIF',
335
+ dividerText: 'oder',
336
+ urlSubmit: 'Laden',
337
+ urlPlaceholder: 'https://beispiel.de/logo.png',
338
+ urlErrorEmpty: 'Bitte eine URL eingeben',
339
+ urlErrorInvalid: 'Ungültiges URL-Format',
340
+ urlErrorProtocol: 'Nur HTTPS-URLs werden unterstützt',
341
+ urlErrorNetwork: 'Bild konnte nicht geladen werden (CORS).',
342
+ bgRemovalUseOriginal: 'Original verwenden',
343
+ bgRemovalUseRemoved: 'Ohne Hintergrund',
344
+ bgRemovalProcessing: 'Hintergrund wird entfernt...',
345
+ bgRemovalFailed: 'Fehlgeschlagen',
346
+ uploadAriaLabel: 'Logo-Datei hochladen',
347
+ removeAriaLabel: (name) => `${name} entfernen`,
348
+ rejectionDpiUnit: 'DPI',
349
+ };
350
+ </script>
351
+ ```
352
+
353
+ ```js
354
+ document.querySelector('wtp-editor').labels = {
355
+ addTextButton: 'Text hinzufügen',
356
+ addTextTooltip: 'Text hinzufügen',
357
+ fontSelectTooltip: 'Schriftart',
358
+ colorPickerTooltip: 'Textfarbe',
359
+ deleteButtonTooltip: 'Auswahl löschen',
360
+ defaultText: 'Neuer Text',
361
+ };
362
+ ```
363
+
364
+ Import the type and the defaults if you want to start from a complete object:
365
+
366
+ ```ts
367
+ import {
368
+ LogoUploadLabels,
369
+ EditorLabels,
370
+ DEFAULT_LOGO_UPLOAD_LABELS,
371
+ DEFAULT_EDITOR_LABELS,
372
+ } from 'web-to-print';
373
+
374
+ const myLabels: LogoUploadLabels = {
375
+ ...DEFAULT_LOGO_UPLOAD_LABELS,
376
+ dividerText: 'oder',
377
+ };
378
+ ```
379
+
380
+ #### `LogoUploadLabels` keys
381
+
382
+ `urlPlaceholder`, `urlSubmit`, `dividerText`, `dropPromptText`, `dropPromptHint`, `uploadAriaLabel`, `removeAriaLabel(fileName)`, `urlErrorEmpty`, `urlErrorInvalid`, `urlErrorProtocol`, `urlErrorHttp(status, statusText)`, `urlErrorNetwork`, `urlErrorFetch`, `bgRemovalProcessing`, `bgRemovalUseOriginal`, `bgRemovalUseRemoved`, `bgRemovalFailed`, `rejectionDpiUnit`.
383
+
384
+ #### `EditorLabels` keys
385
+
386
+ `addTextButton`, `addTextTooltip`, `fontSelectTooltip`, `colorPickerTooltip`, `deleteButtonTooltip`, `defaultText`.
387
+
388
+ ## Development
389
+
390
+ ```bash
391
+ # Install dependencies
392
+ npm install
393
+
394
+ # Dev server with hot reload
395
+ npm start
396
+
397
+ # Build for production
398
+ npm run build
399
+
400
+ # Run all tests (spec + e2e)
401
+ npm test
402
+
403
+ # Run only unit tests
404
+ npm run test.spec
405
+
406
+ # Run only e2e tests
407
+ npm run test.e2e
408
+
409
+ # Run tests in watch mode
410
+ npm run test.watch
411
+
412
+ # Run a single test file
413
+ npx stencil test --spec -- src/utils/format-detection.spec.ts
414
+
415
+ # Lint
416
+ npm run lint
417
+ ```
418
+
419
+ ## Release
420
+
421
+ Releases are published to npm via a GitHub Action (`.github/workflows/release.yml`). Two flows are supported:
422
+
423
+ ### Option A — local version bump (recommended)
424
+
425
+ ```bash
426
+ npm run release:patch # 0.1.0 → 0.1.1
427
+ npm run release:minor # 0.1.0 → 0.2.0
428
+ npm run release:major # 0.1.0 → 1.0.0
429
+ ```
430
+
431
+ Each script bumps `package.json`, creates a `v<version>` git tag, and pushes both. The GitHub Action then runs tests, builds, publishes to npm (with [provenance attestation](https://docs.npmjs.com/generating-provenance-statements)), and creates a GitHub Release with auto-generated notes.
432
+
433
+ ### Option B — manual via GitHub UI
434
+
435
+ Trigger the **Release** workflow from the Actions tab with a bump (`patch`/`minor`/`major`) or an explicit version like `1.2.3`. The workflow performs the bump, commit, tag, and push, then publishes.
436
+
437
+ ### Prerequisites
438
+
439
+ 1. **`NPM_TOKEN`** secret on the repo (Settings → Secrets and variables → Actions). Create an [automation token](https://docs.npmjs.com/creating-and-viewing-access-tokens) on npmjs.com that allows publish.
440
+ 2. The package name in `package.json` must be available on npm (or use a scoped name like `@your-org/web-to-print`). Provenance requires the workflow to run on a public repo, so make sure the repo is public when publishing.
441
+ 3. The workflow skips publish if the same `name@version` already exists on npm — no need to manually guard against accidental re-runs.
442
+
443
+ ## Project Structure
444
+
445
+ ```
446
+ src/
447
+ components/
448
+ wtp-editor/ Interactive canvas editor
449
+ wtp-logo-renderer/ Static logo-on-product renderer (HTML/img-based)
450
+ wtp-logo-upload/ Logo upload with validation
451
+ wtp-print-area-editor/ Interactive print-area definition tool (4-corner quad + bulge)
452
+ styles/
453
+ _variables.scss Design tokens (colors and font-family exposed as CSS vars)
454
+ _mixins.scss SCSS mixins
455
+ _reset.scss CSS reset
456
+ types/
457
+ logo.ts Logo-related interfaces
458
+ editor.ts Editor/canvas interfaces
459
+ labels.ts User-facing string interfaces and English defaults
460
+ index.ts Re-exports
461
+ utils/
462
+ background-removal.ts Color-based flood-fill background removal
463
+ canvas-helpers.ts Fabric.js canvas utilities + CORS-safe image loader
464
+ format-detection.ts Magic-byte file format detection
465
+ logo-validation.ts DPI, dimension, and format validation
466
+ image-preview.ts Downscaled preview generation
467
+ html-render-helpers.ts <img>-based layout/export helpers for the renderer
468
+ pdf-export.ts Multi-page PDF export with print-area metadata
469
+ index.ts Public API exports
470
+ index.html Dev server demo page
471
+ scripts/
472
+ image-proxy.mjs Local dev-only CORS proxy for cross-origin product images
473
+ stencil.config.ts Stencil build configuration
474
+ ```
475
+
476
+ > The dev script (`npm start`) automatically launches `scripts/image-proxy.mjs` on port 3001. The canvas helper tries direct CORS first, then this proxy as a fallback, before loading the image tainted (which would block export).
477
+
478
+ ## Key Dependencies
479
+
480
+ | Package | Purpose |
481
+ |---|---|
482
+ | [Fabric.js](https://fabricjs.com/) v7 | Canvas rendering, object manipulation, JSON serialization |
483
+ | [ExifReader](https://github.com/nicolo-ribaudo/exifreader) | DPI and metadata extraction from raster images |
484
+ | — | Background removal uses a built-in color-based flood-fill (zero dependencies) |
485
+ | [@stencil/core](https://stenciljs.com/) v4 | Web component compiler |
486
+ | [@stencil/sass](https://github.com/ionic-team/stencil-sass) | SCSS support |
487
+
488
+ ## License
489
+
490
+ MIT