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
@@ -0,0 +1,573 @@
1
+ import { h } from "@stencil/core";
2
+ import { DEFAULT_VALIDATION_CONFIG, DEFAULT_LOGO_UPLOAD_LABELS } from "../../types";
3
+ import { validateLogo } from "../../utils/logo-validation";
4
+ import { removeBackground } from "../../utils/background-removal";
5
+ import { generatePreviewDataUrl } from "../../utils/image-preview";
6
+ import { trimSvgWhitespace, parseSvgDimensions } from "../../utils/canvas-helpers";
7
+ export class WtpLogoUpload {
8
+ /** Validation rules for uploaded logos. */
9
+ config = DEFAULT_VALIDATION_CONFIG;
10
+ /** Accepted file MIME types for the file input. */
11
+ accept = 'image/png,image/jpeg,image/svg+xml,image/tiff,image/avif';
12
+ /** Whether multiple files can be uploaded at once. */
13
+ multiple = false;
14
+ /** Disables the upload component. */
15
+ disabled = false;
16
+ /** Enables background removal for raster images after upload. */
17
+ enableBackgroundRemoval = false;
18
+ /** Configuration for the color-based background removal algorithm. */
19
+ bgRemovalConfig = {};
20
+ /** Override any of the user-facing strings. Missing keys fall back to English defaults. */
21
+ labels = {};
22
+ getLabels() {
23
+ return { ...DEFAULT_LOGO_UPLOAD_LABELS, ...this.labels };
24
+ }
25
+ isDragOver = false;
26
+ previews = [];
27
+ selectedIndex = -1;
28
+ rejections = [];
29
+ isProcessing = false;
30
+ pendingChoices = [];
31
+ urlInput = '';
32
+ urlError = null;
33
+ isUrlFetching = false;
34
+ /** Fires when a logo passes validation and is ready for use. */
35
+ wtpLogoValidated;
36
+ /** Fires when a logo fails validation. */
37
+ wtpLogoRejected;
38
+ /** Fires when processing state changes (true = busy, false = idle). */
39
+ wtpLogoProcessing;
40
+ /** Fires when a logo is selected from the preview gallery. */
41
+ wtpLogoSelected;
42
+ fileInputRef;
43
+ async buildLogoData(dataUrl, metadata) {
44
+ const previewDataUrl = await generatePreviewDataUrl(dataUrl);
45
+ return { dataUrl, previewDataUrl, metadata };
46
+ }
47
+ isRasterFormat(format) {
48
+ return ['png', 'jpeg', 'tiff', 'avif'].includes(format);
49
+ }
50
+ async processFiles(files) {
51
+ if (this.disabled)
52
+ return;
53
+ this.isProcessing = true;
54
+ this.rejections = [];
55
+ this.wtpLogoProcessing.emit(true);
56
+ const fileArray = Array.from(files);
57
+ for (const file of fileArray) {
58
+ const result = await validateLogo(file, this.config);
59
+ if (result.valid) {
60
+ const rawDataUrl = await this.fileToDataUrl(file);
61
+ let dataUrl;
62
+ const metadata = result.metadata;
63
+ if (metadata.format === 'svg') {
64
+ dataUrl = await trimSvgWhitespace(rawDataUrl);
65
+ const trimmedDims = parseSvgDimensions(dataUrl);
66
+ if (trimmedDims !== null) {
67
+ metadata.width = trimmedDims.width;
68
+ metadata.height = trimmedDims.height;
69
+ }
70
+ }
71
+ else {
72
+ dataUrl = rawDataUrl;
73
+ }
74
+ if (this.enableBackgroundRemoval && this.isRasterFormat(metadata.format)) {
75
+ this.addPendingChoice(dataUrl, metadata, file);
76
+ }
77
+ else {
78
+ const logoData = await this.buildLogoData(dataUrl, metadata);
79
+ this.previews = [...this.previews, logoData];
80
+ this.selectedIndex = this.previews.length - 1;
81
+ this.wtpLogoValidated.emit(logoData);
82
+ this.wtpLogoSelected.emit(logoData);
83
+ }
84
+ }
85
+ else {
86
+ this.rejections = [...this.rejections, { fileName: file.name, issues: result.issues }];
87
+ this.wtpLogoRejected.emit({ file, issues: result.issues });
88
+ }
89
+ }
90
+ this.isProcessing = false;
91
+ this.wtpLogoProcessing.emit(false);
92
+ }
93
+ addPendingChoice(originalDataUrl, metadata, file) {
94
+ const choice = {
95
+ originalDataUrl,
96
+ removedBgDataUrl: null,
97
+ removedBgWidth: null,
98
+ removedBgHeight: null,
99
+ metadata,
100
+ status: 'processing',
101
+ errorMessage: null,
102
+ };
103
+ this.pendingChoices = [...this.pendingChoices, choice];
104
+ const index = this.pendingChoices.length - 1;
105
+ this.performBackgroundRemoval(file, index);
106
+ }
107
+ async performBackgroundRemoval(file, index) {
108
+ try {
109
+ const result = await removeBackground(file, this.bgRemovalConfig);
110
+ this.pendingChoices = this.pendingChoices.map((c, i) => i === index ? { ...c, removedBgDataUrl: result.dataUrl, removedBgWidth: result.width, removedBgHeight: result.height, status: 'ready' } : c);
111
+ }
112
+ catch (err) {
113
+ const message = err instanceof Error ? err.message : 'Background removal failed';
114
+ this.pendingChoices = this.pendingChoices.map((c, i) => i === index ? { ...c, status: 'error', errorMessage: message } : c);
115
+ }
116
+ }
117
+ async selectChoice(index, useRemoved) {
118
+ const choice = this.pendingChoices[index];
119
+ if (choice === undefined)
120
+ return;
121
+ const dataUrl = useRemoved && choice.removedBgDataUrl !== null ? choice.removedBgDataUrl : choice.originalDataUrl;
122
+ const metadata = useRemoved && choice.removedBgWidth !== null && choice.removedBgHeight !== null
123
+ ? { ...choice.metadata, width: choice.removedBgWidth, height: choice.removedBgHeight }
124
+ : choice.metadata;
125
+ const logoData = await this.buildLogoData(dataUrl, metadata);
126
+ this.previews = [...this.previews, logoData];
127
+ this.selectedIndex = this.previews.length - 1;
128
+ this.wtpLogoValidated.emit(logoData);
129
+ this.wtpLogoSelected.emit(logoData);
130
+ this.pendingChoices = this.pendingChoices.filter((_, i) => i !== index);
131
+ }
132
+ extractFileNameFromUrl(url) {
133
+ try {
134
+ const pathname = new URL(url).pathname;
135
+ const segments = pathname.split('/');
136
+ const last = segments[segments.length - 1];
137
+ return last !== undefined && last !== '' && last.includes('.') ? decodeURIComponent(last) : 'downloaded-image';
138
+ }
139
+ catch {
140
+ return 'downloaded-image';
141
+ }
142
+ }
143
+ async handleUrlSubmit() {
144
+ const url = this.urlInput.trim();
145
+ const labels = this.getLabels();
146
+ this.urlError = null;
147
+ if (url === '') {
148
+ this.urlError = labels.urlErrorEmpty;
149
+ return;
150
+ }
151
+ let parsed;
152
+ try {
153
+ parsed = new URL(url);
154
+ }
155
+ catch {
156
+ this.urlError = labels.urlErrorInvalid;
157
+ return;
158
+ }
159
+ if (parsed.protocol !== 'https:') {
160
+ this.urlError = labels.urlErrorProtocol;
161
+ return;
162
+ }
163
+ this.isUrlFetching = true;
164
+ try {
165
+ const response = await fetch(url, { mode: 'cors' });
166
+ if (!response.ok) {
167
+ this.urlError = labels.urlErrorHttp(response.status, response.statusText);
168
+ return;
169
+ }
170
+ const blob = await response.blob();
171
+ const fileName = this.extractFileNameFromUrl(url);
172
+ const file = new File([blob], fileName, { type: blob.type });
173
+ this.urlInput = '';
174
+ await this.processFiles([file]);
175
+ }
176
+ catch (err) {
177
+ const message = err instanceof Error ? err.message : labels.urlErrorFetch;
178
+ if (message.includes('Failed to fetch') || message.includes('NetworkError')) {
179
+ this.urlError = labels.urlErrorNetwork;
180
+ }
181
+ else {
182
+ this.urlError = message;
183
+ }
184
+ }
185
+ finally {
186
+ this.isUrlFetching = false;
187
+ }
188
+ }
189
+ fileToDataUrl(file) {
190
+ return new Promise((resolve, reject) => {
191
+ const reader = new FileReader();
192
+ reader.onload = () => resolve(reader.result);
193
+ reader.onerror = () => reject(new Error('Failed to read file'));
194
+ reader.readAsDataURL(file);
195
+ });
196
+ }
197
+ handleDragOver = (e) => {
198
+ e.preventDefault();
199
+ e.stopPropagation();
200
+ if (!this.disabled)
201
+ this.isDragOver = true;
202
+ };
203
+ handleDragLeave = (e) => {
204
+ e.preventDefault();
205
+ e.stopPropagation();
206
+ this.isDragOver = false;
207
+ };
208
+ handleDrop = (e) => {
209
+ e.preventDefault();
210
+ e.stopPropagation();
211
+ this.isDragOver = false;
212
+ if (e.dataTransfer?.files !== undefined) {
213
+ this.processFiles(e.dataTransfer.files);
214
+ }
215
+ };
216
+ handleInputChange = (e) => {
217
+ const input = e.target;
218
+ if (input.files !== null) {
219
+ this.processFiles(input.files);
220
+ }
221
+ };
222
+ handleClick = () => {
223
+ if (!this.disabled) {
224
+ this.fileInputRef?.click();
225
+ }
226
+ };
227
+ handleKeyDown = (e) => {
228
+ if (e.key === 'Enter' || e.key === ' ') {
229
+ e.preventDefault();
230
+ this.handleClick();
231
+ }
232
+ };
233
+ handleUrlInput = (e) => {
234
+ this.urlInput = e.target.value;
235
+ };
236
+ handleUrlInputKeyDown = (e) => {
237
+ if (e.key === 'Enter') {
238
+ e.preventDefault();
239
+ this.handleUrlSubmit();
240
+ }
241
+ };
242
+ handleUrlSubmitClick = () => {
243
+ this.handleUrlSubmit();
244
+ };
245
+ handleSelectOriginal = (e) => {
246
+ const btn = e.currentTarget.closest('[data-index]');
247
+ if (btn === null)
248
+ return;
249
+ this.selectChoice(Number(btn.dataset.index), false);
250
+ };
251
+ handleSelectRemoved = (e) => {
252
+ const btn = e.currentTarget.closest('[data-index]');
253
+ if (btn === null)
254
+ return;
255
+ this.selectChoice(Number(btn.dataset.index), true);
256
+ };
257
+ handleSelectPreview = (e) => {
258
+ const item = e.currentTarget.closest('[data-index]');
259
+ if (item === null)
260
+ return;
261
+ const index = Number(item.dataset.index);
262
+ this.selectedIndex = index;
263
+ this.wtpLogoSelected.emit(this.previews[index]);
264
+ };
265
+ handleRemovePreview = (e) => {
266
+ e.stopPropagation();
267
+ const btn = e.currentTarget.closest('[data-index]');
268
+ if (btn === null)
269
+ return;
270
+ const index = Number(btn.dataset.index);
271
+ this.previews = this.previews.filter((_, i) => i !== index);
272
+ if (this.selectedIndex === index) {
273
+ this.selectedIndex = this.previews.length > 0 ? 0 : -1;
274
+ if (this.selectedIndex >= 0) {
275
+ this.wtpLogoSelected.emit(this.previews[this.selectedIndex]);
276
+ }
277
+ }
278
+ else if (this.selectedIndex > index) {
279
+ this.selectedIndex--;
280
+ }
281
+ };
282
+ render() {
283
+ const labels = this.getLabels();
284
+ return (h("div", { key: '605b0b0f0e3d523fad548c8e250deb586fa047cd', class: "wtp-logo-upload", part: "root" }, h("div", { key: '206c52a14ba4bf1ca88361298ea1dd34ede33abe', class: "url-input-section" }, h("div", { key: '8bbe6a257f53d3aaf40566b1686c77352a571182', class: "url-input-wrapper" }, h("input", { key: '88f87e7772bf404088a1978a3964af098362d2fd', type: "url", class: "url-input", part: "url-input", placeholder: labels.urlPlaceholder, value: this.urlInput, disabled: this.disabled || this.isUrlFetching, onInput: this.handleUrlInput, onKeyDown: this.handleUrlInputKeyDown }), h("button", { key: '77b0b04012be3869fcad0841542ff6ba65175b69', class: "url-submit-btn", part: "url-submit-btn", disabled: this.disabled || this.isUrlFetching || this.urlInput.trim() === '', onClick: this.handleUrlSubmitClick }, this.isUrlFetching ? h("span", { class: "spinner-sm" }) : labels.urlSubmit)), this.urlError !== null && h("p", { key: '21af070e82a88911b00cfb35c21c9f4a0b1f9537', class: "url-error", part: "url-error" }, this.urlError)), h("div", { key: '40ea61275f84ea49bde47d4a2d7df6b48733b8df', class: "divider", part: "divider" }, h("span", { key: '617d48c410b5166efbe38902fbc36a537f98f359', class: "divider-text" }, labels.dividerText)), h("div", { key: '56aebdb221b17ed365e8e1b780f643d2985a0a76', class: {
285
+ 'upload-zone': true,
286
+ 'drag-over': this.isDragOver,
287
+ 'disabled': this.disabled,
288
+ }, part: `upload-zone${this.isDragOver ? ' drag-over' : ''}${this.disabled ? ' disabled' : ''}`, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop, onClick: this.handleClick, onKeyDown: this.handleKeyDown, role: "button", tabindex: this.disabled ? -1 : 0, "aria-label": labels.uploadAriaLabel, "aria-disabled": this.disabled ? 'true' : undefined }, h("input", { key: 'b4dd839c3d9dfa26f7e22058ca8d88d1b5128a78', type: "file", ref: el => (this.fileInputRef = el), accept: this.accept, multiple: this.multiple, onChange: this.handleInputChange, class: "file-input", tabindex: -1 }), h("slot", { key: '77c9c469ed07b881d8e09d15ba6ab39938c8685e', name: "prompt" }, h("div", { key: '1dc98ac4ee1f0a830fff45c420dcdb83d5e51e08', class: "default-prompt" }, h("svg", { key: '6b0b37518c24f7af3d69df7cfb00a367ceeed172', class: "upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("path", { key: '7f8c88dc1022380127cac7dc278b6363013293f8', d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), h("polyline", { key: '0ae415e56725fa3e35229dd95824c69c35b8b157', points: "17 8 12 3 7 8" }), h("line", { key: '4aceb053d8f82b24b01c250337d17787435b93a2', x1: "12", y1: "3", x2: "12", y2: "15" })), h("p", { key: 'dbc8e47dc04b7f1c03053e244c7d8c5d5e70b533', class: "prompt-text", part: "prompt-text" }, labels.dropPromptText), h("p", { key: 'f3c1d7b332ce6439725dcf15eda5732a8f6d45e2', class: "prompt-hint", part: "prompt-hint" }, labels.dropPromptHint))), this.isProcessing && h("div", { key: '4f5730a0bfd918788c851dd7b4e0282643e782cc', class: "processing-overlay" }, h("span", { key: 'd1f7e503dd250b7125132790976554c3b91a0aba', class: "spinner" }))), this.rejections.length > 0 && (h("div", { key: '5f2aa8bb1b64d70db7138ff2eddda68ed7aa62e3', class: "rejections", part: "rejections" }, this.rejections.map(r => (h("div", { class: "rejection-item", part: "rejection-item" }, h("strong", null, r.fileName), h("ul", null, r.issues.filter(i => i.severity === 'error').map(i => (h("li", { class: "error" }, i.message))), r.issues.filter(i => i.severity === 'warning').map(i => (h("li", { class: "warning" }, i.message))))))))), this.pendingChoices.length > 0 && (h("div", { key: 'c1c43dfeb2d32a66261c70d3c4edd0339c88f098', class: "pending-choices", part: "pending-choices" }, this.pendingChoices.map((choice, index) => (h("div", { class: "choice-card", part: "choice-card" }, h("p", { class: "choice-title" }, choice.metadata.fileName), h("div", { class: "choice-options" }, h("button", { class: "choice-option", part: "choice-option", "data-index": index, onClick: this.handleSelectOriginal }, h("img", { src: choice.originalDataUrl, alt: "Original", class: "choice-image" }), h("span", { class: "choice-label" }, labels.bgRemovalUseOriginal)), h("button", { class: {
289
+ 'choice-option': true,
290
+ 'choice-option--disabled': choice.status === 'processing',
291
+ }, part: "choice-option", disabled: choice.status === 'processing', "data-index": index, onClick: this.handleSelectRemoved }, choice.status === 'processing' && (h("div", { class: "choice-image choice-image--loading" }, h("span", { class: "spinner-sm" }), h("span", { class: "choice-loading-text" }, labels.bgRemovalProcessing))), choice.status === 'ready' && choice.removedBgDataUrl !== null && (h("img", { src: choice.removedBgDataUrl, alt: "Background removed", class: "choice-image choice-image--transparent" })), choice.status === 'error' && (h("div", { class: "choice-image choice-image--error" }, h("span", { class: "choice-error-text" }, choice.errorMessage))), h("span", { class: "choice-label" }, choice.status === 'error' ? labels.bgRemovalFailed : labels.bgRemovalUseRemoved)))))))), this.previews.length > 0 && (h("div", { key: '69d0dab6c5377d471b8802d7ba92c640785e3d52', class: "previews", part: "previews" }, this.previews.map((preview, index) => (h("div", { class: { 'preview-item': true, 'preview-item--selected': index === this.selectedIndex }, part: `preview-item${index === this.selectedIndex ? ' selected' : ''}`, "data-index": index, onClick: this.handleSelectPreview, role: "button", tabindex: 0 }, h("img", { src: preview.previewDataUrl ?? preview.dataUrl, alt: preview.metadata.fileName, class: "preview-image" }), h("div", { class: "preview-info" }, h("span", { class: "preview-name" }, preview.metadata.fileName), h("span", { class: "preview-dims" }, preview.metadata.width, " x ", preview.metadata.height, "px"), preview.metadata.dpiX !== null && h("span", { class: "preview-dpi" }, preview.metadata.dpiX, " ", labels.rejectionDpiUnit)), h("button", { class: "remove-btn", part: "remove-btn", "data-index": index, onClick: this.handleRemovePreview, "aria-label": labels.removeAriaLabel(preview.metadata.fileName) }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" }))))))))));
292
+ }
293
+ static get is() { return "wtp-logo-upload"; }
294
+ static get encapsulation() { return "shadow"; }
295
+ static get originalStyleUrls() {
296
+ return {
297
+ "$": ["wtp-logo-upload.scss"]
298
+ };
299
+ }
300
+ static get styleUrls() {
301
+ return {
302
+ "$": ["wtp-logo-upload.css"]
303
+ };
304
+ }
305
+ static get properties() {
306
+ return {
307
+ "config": {
308
+ "type": "unknown",
309
+ "mutable": false,
310
+ "complexType": {
311
+ "original": "LogoValidationConfig",
312
+ "resolved": "LogoValidationConfig",
313
+ "references": {
314
+ "LogoValidationConfig": {
315
+ "location": "import",
316
+ "path": "../../types",
317
+ "id": "src/types/index.ts::LogoValidationConfig",
318
+ "referenceLocation": "LogoValidationConfig"
319
+ }
320
+ }
321
+ },
322
+ "required": false,
323
+ "optional": false,
324
+ "docs": {
325
+ "tags": [],
326
+ "text": "Validation rules for uploaded logos."
327
+ },
328
+ "getter": false,
329
+ "setter": false,
330
+ "defaultValue": "DEFAULT_VALIDATION_CONFIG"
331
+ },
332
+ "accept": {
333
+ "type": "string",
334
+ "mutable": false,
335
+ "complexType": {
336
+ "original": "string",
337
+ "resolved": "string",
338
+ "references": {}
339
+ },
340
+ "required": false,
341
+ "optional": false,
342
+ "docs": {
343
+ "tags": [],
344
+ "text": "Accepted file MIME types for the file input."
345
+ },
346
+ "getter": false,
347
+ "setter": false,
348
+ "reflect": false,
349
+ "attribute": "accept",
350
+ "defaultValue": "'image/png,image/jpeg,image/svg+xml,image/tiff,image/avif'"
351
+ },
352
+ "multiple": {
353
+ "type": "boolean",
354
+ "mutable": false,
355
+ "complexType": {
356
+ "original": "boolean",
357
+ "resolved": "boolean",
358
+ "references": {}
359
+ },
360
+ "required": false,
361
+ "optional": false,
362
+ "docs": {
363
+ "tags": [],
364
+ "text": "Whether multiple files can be uploaded at once."
365
+ },
366
+ "getter": false,
367
+ "setter": false,
368
+ "reflect": false,
369
+ "attribute": "multiple",
370
+ "defaultValue": "false"
371
+ },
372
+ "disabled": {
373
+ "type": "boolean",
374
+ "mutable": false,
375
+ "complexType": {
376
+ "original": "boolean",
377
+ "resolved": "boolean",
378
+ "references": {}
379
+ },
380
+ "required": false,
381
+ "optional": false,
382
+ "docs": {
383
+ "tags": [],
384
+ "text": "Disables the upload component."
385
+ },
386
+ "getter": false,
387
+ "setter": false,
388
+ "reflect": false,
389
+ "attribute": "disabled",
390
+ "defaultValue": "false"
391
+ },
392
+ "enableBackgroundRemoval": {
393
+ "type": "boolean",
394
+ "mutable": false,
395
+ "complexType": {
396
+ "original": "boolean",
397
+ "resolved": "boolean",
398
+ "references": {}
399
+ },
400
+ "required": false,
401
+ "optional": false,
402
+ "docs": {
403
+ "tags": [],
404
+ "text": "Enables background removal for raster images after upload."
405
+ },
406
+ "getter": false,
407
+ "setter": false,
408
+ "reflect": false,
409
+ "attribute": "enable-background-removal",
410
+ "defaultValue": "false"
411
+ },
412
+ "bgRemovalConfig": {
413
+ "type": "unknown",
414
+ "mutable": false,
415
+ "complexType": {
416
+ "original": "Partial<BgRemovalConfig>",
417
+ "resolved": "BgRemovalConfig",
418
+ "references": {
419
+ "Partial": {
420
+ "location": "global",
421
+ "id": "global::Partial"
422
+ },
423
+ "BgRemovalConfig": {
424
+ "location": "import",
425
+ "path": "../../types",
426
+ "id": "src/types/index.ts::BgRemovalConfig",
427
+ "referenceLocation": "BgRemovalConfig"
428
+ }
429
+ }
430
+ },
431
+ "required": false,
432
+ "optional": false,
433
+ "docs": {
434
+ "tags": [],
435
+ "text": "Configuration for the color-based background removal algorithm."
436
+ },
437
+ "getter": false,
438
+ "setter": false,
439
+ "defaultValue": "{}"
440
+ },
441
+ "labels": {
442
+ "type": "unknown",
443
+ "mutable": false,
444
+ "complexType": {
445
+ "original": "Partial<LogoUploadLabels>",
446
+ "resolved": "LogoUploadLabels",
447
+ "references": {
448
+ "Partial": {
449
+ "location": "global",
450
+ "id": "global::Partial"
451
+ },
452
+ "LogoUploadLabels": {
453
+ "location": "import",
454
+ "path": "../../types",
455
+ "id": "src/types/index.ts::LogoUploadLabels",
456
+ "referenceLocation": "LogoUploadLabels"
457
+ }
458
+ }
459
+ },
460
+ "required": false,
461
+ "optional": false,
462
+ "docs": {
463
+ "tags": [],
464
+ "text": "Override any of the user-facing strings. Missing keys fall back to English defaults."
465
+ },
466
+ "getter": false,
467
+ "setter": false,
468
+ "defaultValue": "{}"
469
+ }
470
+ };
471
+ }
472
+ static get states() {
473
+ return {
474
+ "isDragOver": {},
475
+ "previews": {},
476
+ "selectedIndex": {},
477
+ "rejections": {},
478
+ "isProcessing": {},
479
+ "pendingChoices": {},
480
+ "urlInput": {},
481
+ "urlError": {},
482
+ "isUrlFetching": {}
483
+ };
484
+ }
485
+ static get events() {
486
+ return [{
487
+ "method": "wtpLogoValidated",
488
+ "name": "wtpLogoValidated",
489
+ "bubbles": true,
490
+ "cancelable": true,
491
+ "composed": true,
492
+ "docs": {
493
+ "tags": [],
494
+ "text": "Fires when a logo passes validation and is ready for use."
495
+ },
496
+ "complexType": {
497
+ "original": "LogoData",
498
+ "resolved": "LogoData",
499
+ "references": {
500
+ "LogoData": {
501
+ "location": "import",
502
+ "path": "../../types",
503
+ "id": "src/types/index.ts::LogoData",
504
+ "referenceLocation": "LogoData"
505
+ }
506
+ }
507
+ }
508
+ }, {
509
+ "method": "wtpLogoRejected",
510
+ "name": "wtpLogoRejected",
511
+ "bubbles": true,
512
+ "cancelable": true,
513
+ "composed": true,
514
+ "docs": {
515
+ "tags": [],
516
+ "text": "Fires when a logo fails validation."
517
+ },
518
+ "complexType": {
519
+ "original": "{ file: File; issues: LogoValidationIssue[] }",
520
+ "resolved": "{ file: File; issues: LogoValidationIssue[]; }",
521
+ "references": {
522
+ "File": {
523
+ "location": "global",
524
+ "id": "global::File"
525
+ },
526
+ "LogoValidationIssue": {
527
+ "location": "import",
528
+ "path": "../../types",
529
+ "id": "src/types/index.ts::LogoValidationIssue",
530
+ "referenceLocation": "LogoValidationIssue"
531
+ }
532
+ }
533
+ }
534
+ }, {
535
+ "method": "wtpLogoProcessing",
536
+ "name": "wtpLogoProcessing",
537
+ "bubbles": true,
538
+ "cancelable": true,
539
+ "composed": true,
540
+ "docs": {
541
+ "tags": [],
542
+ "text": "Fires when processing state changes (true = busy, false = idle)."
543
+ },
544
+ "complexType": {
545
+ "original": "boolean",
546
+ "resolved": "boolean",
547
+ "references": {}
548
+ }
549
+ }, {
550
+ "method": "wtpLogoSelected",
551
+ "name": "wtpLogoSelected",
552
+ "bubbles": true,
553
+ "cancelable": true,
554
+ "composed": true,
555
+ "docs": {
556
+ "tags": [],
557
+ "text": "Fires when a logo is selected from the preview gallery."
558
+ },
559
+ "complexType": {
560
+ "original": "LogoData",
561
+ "resolved": "LogoData",
562
+ "references": {
563
+ "LogoData": {
564
+ "location": "import",
565
+ "path": "../../types",
566
+ "id": "src/types/index.ts::LogoData",
567
+ "referenceLocation": "LogoData"
568
+ }
569
+ }
570
+ }
571
+ }];
572
+ }
573
+ }
@@ -0,0 +1,20 @@
1
+ *,
2
+ *::before,
3
+ *::after {
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ :host {
8
+ font-family: var(--wtp-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
9
+ color: var(--wtp-color-text, #1e293b);
10
+ line-height: 1.5;
11
+ }
12
+
13
+ .wtp-print-area-editor {
14
+ display: inline-block;
15
+ line-height: 0;
16
+ border: 1px solid var(--wtp-color-border, #e2e8f0);
17
+ border-radius: 8px;
18
+ overflow: hidden;
19
+ background: repeating-conic-gradient(#e5e7eb 0% 25%, transparent 0% 50%) 50%/20px 20px;
20
+ }