@limetech/lime-elements 38.23.5 → 38.24.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/CHANGELOG.md +9 -0
- package/dist/cjs/lime-elements.cjs.js +1 -1
- package/dist/cjs/limel-action-bar_2.cjs.entry.js +1 -1
- package/dist/cjs/limel-ai-avatar.cjs.entry.js +1 -1
- package/dist/cjs/limel-badge.cjs.entry.js +42 -0
- package/dist/cjs/limel-badge.cjs.entry.js.map +1 -0
- package/dist/cjs/limel-callout.cjs.entry.js +1 -1
- package/dist/cjs/limel-chart.cjs.entry.js +1 -1
- package/dist/cjs/limel-chip_2.cjs.entry.js +1 -1
- package/dist/cjs/limel-collapsible-section.cjs.entry.js +1 -1
- package/dist/cjs/limel-file-viewer.cjs.entry.js +1 -1
- package/dist/cjs/limel-file.cjs.entry.js +1 -1
- package/dist/cjs/limel-flatpickr-adapter.cjs.entry.js +1 -1
- package/dist/cjs/limel-linear-progress.cjs.entry.js +1 -1
- package/dist/cjs/{limel-portal_2.cjs.entry.js → limel-portal_3.cjs.entry.js} +107 -11
- package/dist/cjs/limel-portal_3.cjs.entry.js.map +1 -0
- package/dist/cjs/limel-profile-picture.cjs.entry.js +536 -0
- package/dist/cjs/limel-profile-picture.cjs.entry.js.map +1 -0
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +1 -1
- package/dist/cjs/limel-snackbar.cjs.entry.js +1 -1
- package/dist/cjs/limel-table.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{translations-2746c4c6.js → translations-7499f391.js} +25 -1
- package/dist/cjs/translations-7499f391.js.map +1 -0
- package/dist/collection/collection-manifest.json +1 -0
- package/dist/collection/components/profile-picture/profile-picture.css +255 -0
- package/dist/collection/components/profile-picture/profile-picture.js +554 -0
- package/dist/collection/components/profile-picture/profile-picture.js.map +1 -0
- package/dist/collection/translations/da.js +3 -0
- package/dist/collection/translations/da.js.map +1 -1
- package/dist/collection/translations/de.js +3 -0
- package/dist/collection/translations/de.js.map +1 -1
- package/dist/collection/translations/en.js +3 -0
- package/dist/collection/translations/en.js.map +1 -1
- package/dist/collection/translations/fi.js +3 -0
- package/dist/collection/translations/fi.js.map +1 -1
- package/dist/collection/translations/fr.js +3 -0
- package/dist/collection/translations/fr.js.map +1 -1
- package/dist/collection/translations/nl.js +3 -0
- package/dist/collection/translations/nl.js.map +1 -1
- package/dist/collection/translations/no.js +3 -0
- package/dist/collection/translations/no.js.map +1 -1
- package/dist/collection/translations/sv.js +3 -0
- package/dist/collection/translations/sv.js.map +1 -1
- package/dist/collection/util/image-resize.js +305 -0
- package/dist/collection/util/image-resize.js.map +1 -0
- package/dist/esm/lime-elements.js +1 -1
- package/dist/esm/limel-action-bar_2.entry.js +1 -1
- package/dist/esm/limel-ai-avatar.entry.js +1 -1
- package/dist/esm/limel-badge.entry.js +38 -0
- package/dist/esm/limel-badge.entry.js.map +1 -0
- package/dist/esm/limel-callout.entry.js +1 -1
- package/dist/esm/limel-chart.entry.js +1 -1
- package/dist/esm/limel-chip_2.entry.js +1 -1
- package/dist/esm/limel-collapsible-section.entry.js +1 -1
- package/dist/esm/limel-file-viewer.entry.js +1 -1
- package/dist/esm/limel-file.entry.js +1 -1
- package/dist/esm/limel-flatpickr-adapter.entry.js +1 -1
- package/dist/esm/limel-linear-progress.entry.js +1 -1
- package/dist/esm/{limel-portal_2.entry.js → limel-portal_3.entry.js} +107 -12
- package/dist/esm/limel-portal_3.entry.js.map +1 -0
- package/dist/esm/limel-profile-picture.entry.js +532 -0
- package/dist/esm/limel-profile-picture.entry.js.map +1 -0
- package/dist/esm/limel-prosemirror-adapter.entry.js +1 -1
- package/dist/esm/limel-snackbar.entry.js +1 -1
- package/dist/esm/limel-table.entry.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{translations-0c3c0779.js → translations-1d617679.js} +25 -1
- package/dist/esm/translations-1d617679.js.map +1 -0
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/lime-elements.esm.js.map +1 -1
- package/dist/lime-elements/{p-6edfe426.entry.js → p-011f5d81.entry.js} +2 -2
- package/dist/lime-elements/p-18a3c28a.entry.js +2 -0
- package/dist/lime-elements/p-18a3c28a.entry.js.map +1 -0
- package/dist/lime-elements/{p-8a7bc823.entry.js → p-20d1913a.entry.js} +2 -2
- package/dist/lime-elements/{p-244e13f5.entry.js → p-3f698d18.entry.js} +2 -2
- package/dist/lime-elements/{p-9abbe61a.entry.js → p-441c1eab.entry.js} +2 -2
- package/dist/lime-elements/{p-b957a3ca.entry.js → p-4558a60e.entry.js} +2 -2
- package/dist/lime-elements/p-58777116.js +2 -0
- package/dist/lime-elements/p-58777116.js.map +1 -0
- package/dist/lime-elements/{p-d7e93894.entry.js → p-597e6f79.entry.js} +2 -2
- package/dist/lime-elements/{p-208f87d2.entry.js → p-78abbc50.entry.js} +2 -2
- package/dist/lime-elements/p-7e3a4f49.entry.js +2 -0
- package/dist/lime-elements/p-7e3a4f49.entry.js.map +1 -0
- package/dist/lime-elements/{p-e4d64dd2.entry.js → p-8ae75f4a.entry.js} +2 -2
- package/dist/lime-elements/{p-5018673b.entry.js → p-99de518a.entry.js} +2 -2
- package/dist/lime-elements/p-b5a96409.entry.js +2 -0
- package/dist/lime-elements/p-b5a96409.entry.js.map +1 -0
- package/dist/lime-elements/{p-2173d6d5.entry.js → p-bd619d56.entry.js} +2 -2
- package/dist/lime-elements/{p-65d5d2fb.entry.js → p-bd6878ee.entry.js} +2 -2
- package/dist/lime-elements/{p-5bf57c21.entry.js → p-ce29c097.entry.js} +2 -2
- package/dist/lime-elements/{p-00aee6b6.entry.js → p-e7201ebd.entry.js} +2 -2
- package/dist/types/components/profile-picture/profile-picture.d.ts +126 -0
- package/dist/types/components.d.ts +203 -0
- package/dist/types/translations/da.d.ts +3 -0
- package/dist/types/translations/de.d.ts +3 -0
- package/dist/types/translations/en.d.ts +3 -0
- package/dist/types/translations/fi.d.ts +3 -0
- package/dist/types/translations/fr.d.ts +3 -0
- package/dist/types/translations/nl.d.ts +3 -0
- package/dist/types/translations/no.d.ts +3 -0
- package/dist/types/translations/sv.d.ts +3 -0
- package/dist/types/util/image-resize.d.ts +138 -0
- package/package.json +1 -1
- package/dist/cjs/limel-badge_2.cjs.entry.js +0 -138
- package/dist/cjs/limel-badge_2.cjs.entry.js.map +0 -1
- package/dist/cjs/limel-portal_2.cjs.entry.js.map +0 -1
- package/dist/cjs/translations-2746c4c6.js.map +0 -1
- package/dist/esm/limel-badge_2.entry.js +0 -133
- package/dist/esm/limel-badge_2.entry.js.map +0 -1
- package/dist/esm/limel-portal_2.entry.js.map +0 -1
- package/dist/esm/translations-0c3c0779.js.map +0 -1
- package/dist/lime-elements/p-29b1f083.entry.js +0 -2
- package/dist/lime-elements/p-29b1f083.entry.js.map +0 -1
- package/dist/lime-elements/p-c8825e88.js +0 -2
- package/dist/lime-elements/p-c8825e88.js.map +0 -1
- package/dist/lime-elements/p-fe7243c1.entry.js +0 -2
- package/dist/lime-elements/p-fe7243c1.entry.js.map +0 -1
- /package/dist/lime-elements/{p-6edfe426.entry.js.map → p-011f5d81.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-8a7bc823.entry.js.map → p-20d1913a.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-244e13f5.entry.js.map → p-3f698d18.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-9abbe61a.entry.js.map → p-441c1eab.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-b957a3ca.entry.js.map → p-4558a60e.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-d7e93894.entry.js.map → p-597e6f79.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-208f87d2.entry.js.map → p-78abbc50.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-e4d64dd2.entry.js.map → p-8ae75f4a.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-5018673b.entry.js.map → p-99de518a.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-2173d6d5.entry.js.map → p-bd619d56.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-65d5d2fb.entry.js.map → p-bd6878ee.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-5bf57c21.entry.js.map → p-ce29c097.entry.js.map} +0 -0
- /package/dist/lime-elements/{p-00aee6b6.entry.js.map → p-e7201ebd.entry.js.map} +0 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
const index = require('./index-174a078a.js');
|
|
6
|
+
const files = require('./files-d660a1fa.js');
|
|
7
|
+
const getIconProps = require('./get-icon-props-65f39e40.js');
|
|
8
|
+
const translations = require('./translations-7499f391.js');
|
|
9
|
+
const randomString = require('./random-string-27fb6c74.js');
|
|
10
|
+
require('./file-metadata-8b0b9ea3.js');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Image resize utilities
|
|
14
|
+
*
|
|
15
|
+
* Overview
|
|
16
|
+
* --------
|
|
17
|
+
* This module provides a small, dependency-free utility to resize images on the client
|
|
18
|
+
* (in the browser) before uploading. It works by decoding an input `File` to an
|
|
19
|
+
* `ImageBitmap` (or falling back to an `HTMLImageElement`), drawing it onto a
|
|
20
|
+
* `Canvas`/`OffscreenCanvas` with the requested strategy (cover/contain), and
|
|
21
|
+
* then exporting the result to a new `File` with your preferred MIME type and
|
|
22
|
+
* quality.
|
|
23
|
+
*
|
|
24
|
+
* Why resize client-side?
|
|
25
|
+
* - Faster perceived uploads and lower bandwidth usage
|
|
26
|
+
* - Consistent avatar sizes and formats (e.g., JPEG 400x400)
|
|
27
|
+
* - No server-side transformation required for common cases
|
|
28
|
+
*
|
|
29
|
+
* Fit strategies
|
|
30
|
+
* - `cover` (default): The image is scaled to cover the target rectangle, and
|
|
31
|
+
* the excess parts are center-cropped. Good for avatars.
|
|
32
|
+
* - `contain`: The image is scaled to fit entirely within the target rectangle
|
|
33
|
+
* without cropping, letterboxing if needed. Good when you must preserve the
|
|
34
|
+
* entire image.
|
|
35
|
+
*
|
|
36
|
+
* Decoding & EXIF orientation
|
|
37
|
+
* EXIF orientation is a piece of metadata stored inside image files
|
|
38
|
+
* (usually JPEGs) that tells image renderer software how the image should be displayed
|
|
39
|
+
* i.e., whether it should be rotated or flipped. This meta data is normally added
|
|
40
|
+
* to photos by digital cameras and phones.
|
|
41
|
+
* - When available, `createImageBitmap(file, { imageOrientation: 'from-image' })`
|
|
42
|
+
* is used to automatically respect EXIF orientation.
|
|
43
|
+
* - If not available or it fails (e.g., unsupported format), we fall back to
|
|
44
|
+
* decoding via an `HTMLImageElement`.
|
|
45
|
+
*
|
|
46
|
+
* OffscreenCanvas
|
|
47
|
+
* - If the environment supports `OffscreenCanvas`, it will be used for the draw
|
|
48
|
+
* and encode operations for better performance in some cases. Otherwise, a
|
|
49
|
+
* regular `HTMLCanvasElement` is used.
|
|
50
|
+
*
|
|
51
|
+
* HEIC/HEIF notes
|
|
52
|
+
* - All major browsers except Safari lack native HEIC/HEIF decoding.
|
|
53
|
+
* In such cases the `resizeImage` function will throw when decoding fails.
|
|
54
|
+
* The caller should catch and fall back
|
|
55
|
+
* to using the original file or handle conversion on the server.
|
|
56
|
+
* - If we need guaranteed client-side HEIC->JPEG conversion, we must add a small
|
|
57
|
+
* library or WASM module; this utility intentionally avoids extra dependencies.
|
|
58
|
+
*
|
|
59
|
+
* Output type & quality
|
|
60
|
+
* - Default output is `image/jpeg` with `quality=0.85`, which is typically
|
|
61
|
+
* appropriate for avatars. You can switch to `image/png` to preserve
|
|
62
|
+
* transparency.
|
|
63
|
+
* - The output filename extension is adjusted to match the chosen MIME type by
|
|
64
|
+
* default (e.g., `.jpg` or `.png`). You can override naming via the `rename`
|
|
65
|
+
* option.
|
|
66
|
+
*
|
|
67
|
+
* Error handling
|
|
68
|
+
* - Throws if canvas/context cannot be created or if canvas->blob conversion fails.
|
|
69
|
+
* - Decoding failures (unsupported type) will throw; caller can try/catch and
|
|
70
|
+
* fall back to the original file.
|
|
71
|
+
*
|
|
72
|
+
* Performance tips
|
|
73
|
+
* - Keep target sizes reasonable (e.g., 256–1024 px) to avoid long processing
|
|
74
|
+
* times on modest devices.
|
|
75
|
+
* - JPEG with quality 0.8–0.9 often strikes a good balance between size and
|
|
76
|
+
* perceived quality for photos/avatars.
|
|
77
|
+
*
|
|
78
|
+
* Usage examples
|
|
79
|
+
* --------------
|
|
80
|
+
* Basic usage:
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { resizeImage } from '@limetech/lime-elements/util/image-resize';
|
|
83
|
+
*
|
|
84
|
+
* const processed = await resizeImage(file, {
|
|
85
|
+
* width: 400,
|
|
86
|
+
* height: 400,
|
|
87
|
+
* fit: 'cover', // default; center-crops
|
|
88
|
+
* type: 'image/jpeg', // default
|
|
89
|
+
* quality: 0.85, // default
|
|
90
|
+
* });
|
|
91
|
+
* // Upload `processed` instead of the original file
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* With custom naming:
|
|
95
|
+
* ```ts
|
|
96
|
+
* const processed = await resizeImage(file, {
|
|
97
|
+
* width: 800,
|
|
98
|
+
* height: 800,
|
|
99
|
+
* fit: 'contain',
|
|
100
|
+
* type: 'image/png',
|
|
101
|
+
* rename: (name) => name.replace(/\.[^.]+$/, '') + '_resized.png',
|
|
102
|
+
* });
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* In a Stencil component (simplified):
|
|
106
|
+
* ```tsx
|
|
107
|
+
* private async handleFilesSelected(file: File) {
|
|
108
|
+
* try {
|
|
109
|
+
* const resized = await resizeImage(file, { width: 400, height: 400 });
|
|
110
|
+
* // build your FileInfo and emit
|
|
111
|
+
* } catch {
|
|
112
|
+
* // fall back to original
|
|
113
|
+
* }
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
// (Removed exported ResizeFit to avoid forcing a public symbol.)
|
|
118
|
+
/**
|
|
119
|
+
* Resize an image file on the client using Canvas/OffscreenCanvas.
|
|
120
|
+
* Returns a new File with the requested format and dimensions.
|
|
121
|
+
*
|
|
122
|
+
* Contract
|
|
123
|
+
* - Input: image `File`
|
|
124
|
+
* - Output: resized image as a new `File` with updated `type`, name, and size
|
|
125
|
+
* - Errors: may throw on decode failure or canvas export failure
|
|
126
|
+
*
|
|
127
|
+
* @beta
|
|
128
|
+
* @param file - The image file to resize.
|
|
129
|
+
* @param options - Configuration for the resize operation.
|
|
130
|
+
*/
|
|
131
|
+
async function resizeImage(file, options) {
|
|
132
|
+
const { width, height, fit = 'cover', type = 'image/jpeg', quality = 0.85, rename = (name) => renameWithType(name, type), } = options;
|
|
133
|
+
const source = await loadSource(file);
|
|
134
|
+
const { sx, sy, sw, sh, dx, dy, dw, dh } = computeRects(source.width, source.height, width, height, fit);
|
|
135
|
+
const canvas = createCanvas(width, height);
|
|
136
|
+
const ctx = get2dContext(canvas);
|
|
137
|
+
ctx.clearRect(0, 0, width, height);
|
|
138
|
+
ctx.drawImage(source, sx, sy, sw, sh, dx, dy, dw, dh);
|
|
139
|
+
const blob = await canvasToBlob(canvas, type, quality);
|
|
140
|
+
const name = rename(file.name);
|
|
141
|
+
return new File([blob], name, { type });
|
|
142
|
+
}
|
|
143
|
+
/** Whether OffscreenCanvas is available in the current environment. */
|
|
144
|
+
function supportsOffscreen() {
|
|
145
|
+
try {
|
|
146
|
+
return typeof globalThis.OffscreenCanvas === 'function';
|
|
147
|
+
}
|
|
148
|
+
catch (_a) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Create either an OffscreenCanvas or a regular canvas for drawing.
|
|
154
|
+
* @param width - Target width
|
|
155
|
+
* @param height - Target height
|
|
156
|
+
*/
|
|
157
|
+
function createCanvas(width, height) {
|
|
158
|
+
if (supportsOffscreen()) {
|
|
159
|
+
return new globalThis.OffscreenCanvas(width, height);
|
|
160
|
+
}
|
|
161
|
+
const canvas = document.createElement('canvas');
|
|
162
|
+
canvas.width = width;
|
|
163
|
+
canvas.height = height;
|
|
164
|
+
return canvas;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the 2D rendering context, throwing a descriptive error if unavailable.
|
|
168
|
+
* @param canvas - The canvas to get context from
|
|
169
|
+
*/
|
|
170
|
+
function get2dContext(canvas) {
|
|
171
|
+
const ctx = canvas.getContext('2d', { alpha: true });
|
|
172
|
+
if (!ctx) {
|
|
173
|
+
throw new Error('2D canvas context not available');
|
|
174
|
+
}
|
|
175
|
+
return ctx;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Convert the canvas content to a Blob, supporting both canvas types.
|
|
179
|
+
* @param canvas - The source canvas
|
|
180
|
+
* @param type - Output MIME type
|
|
181
|
+
* @param quality - JPEG quality (0..1)
|
|
182
|
+
*/
|
|
183
|
+
function canvasToBlob(canvas, type, quality) {
|
|
184
|
+
if ('convertToBlob' in canvas) {
|
|
185
|
+
return canvas.convertToBlob({ type, quality });
|
|
186
|
+
}
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
canvas.toBlob((blob) => {
|
|
189
|
+
if (!blob) {
|
|
190
|
+
reject(new Error('Failed to create blob from canvas'));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
resolve(blob);
|
|
194
|
+
}, type, quality);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Load the image into a decodable source (ImageBitmap preferred).
|
|
199
|
+
* @param file - The input file to decode
|
|
200
|
+
*/
|
|
201
|
+
async function loadSource(file) {
|
|
202
|
+
var _a, _b;
|
|
203
|
+
if (typeof globalThis.createImageBitmap === 'function') {
|
|
204
|
+
try {
|
|
205
|
+
return await globalThis.createImageBitmap(file, {
|
|
206
|
+
imageOrientation: 'from-image',
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
// Log for debugging in development, but continue with fallback
|
|
211
|
+
const isDev = ((_b = (_a = globalThis.process) === null || _a === void 0 ? void 0 : _a.env) === null || _b === void 0 ? void 0 : _b.NODE_ENV) !== 'production';
|
|
212
|
+
if (isDev &&
|
|
213
|
+
typeof console !== 'undefined' &&
|
|
214
|
+
typeof console.debug === 'function') {
|
|
215
|
+
console.debug('createImageBitmap failed, falling back to HTMLImageElement:', error);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return await loadImageElement(file);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Decode an image file via HTMLImageElement when ImageBitmap is unavailable.
|
|
223
|
+
* @param file - The input file to decode
|
|
224
|
+
*/
|
|
225
|
+
async function loadImageElement(file) {
|
|
226
|
+
var _a;
|
|
227
|
+
const url = URL.createObjectURL(file);
|
|
228
|
+
try {
|
|
229
|
+
const img = new Image();
|
|
230
|
+
img.decoding = 'sync';
|
|
231
|
+
img.src = url;
|
|
232
|
+
await ((_a = img.decode) === null || _a === void 0 ? void 0 : _a.call(img).catch(() => undefined));
|
|
233
|
+
if (!img.complete) {
|
|
234
|
+
await new Promise((resolve, reject) => {
|
|
235
|
+
const cleanup = () => {
|
|
236
|
+
img.removeEventListener('load', onLoad);
|
|
237
|
+
img.removeEventListener('error', onError);
|
|
238
|
+
};
|
|
239
|
+
const onLoad = () => {
|
|
240
|
+
cleanup();
|
|
241
|
+
resolve();
|
|
242
|
+
};
|
|
243
|
+
const onError = (e) => {
|
|
244
|
+
cleanup();
|
|
245
|
+
reject(e);
|
|
246
|
+
};
|
|
247
|
+
img.addEventListener('load', onLoad);
|
|
248
|
+
img.addEventListener('error', onError);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return img;
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
URL.revokeObjectURL(url);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Compute source and destination rectangles for drawImage based on the fit mode.
|
|
259
|
+
*
|
|
260
|
+
* Returns sx, sy, sw, sh for the source crop/area and dx, dy, dw, dh for the
|
|
261
|
+
* destination rectangle on the target canvas.
|
|
262
|
+
*
|
|
263
|
+
* @param sw - Source width
|
|
264
|
+
* @param sh - Source height
|
|
265
|
+
* @param tw - Target width
|
|
266
|
+
* @param th - Target height
|
|
267
|
+
* @param fit - Fit mode (cover/contain)
|
|
268
|
+
*/
|
|
269
|
+
function computeRects(sw, sh, tw, th, fit) {
|
|
270
|
+
const sRatio = sw / sh;
|
|
271
|
+
const tRatio = tw / th;
|
|
272
|
+
if (fit === 'cover') {
|
|
273
|
+
// scale source to cover target, then center-crop
|
|
274
|
+
let cropW;
|
|
275
|
+
let cropH;
|
|
276
|
+
if (sRatio > tRatio) {
|
|
277
|
+
// source is wider than target: crop width
|
|
278
|
+
cropH = sh;
|
|
279
|
+
cropW = sh * tRatio;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// source is taller than target: crop height
|
|
283
|
+
cropW = sw;
|
|
284
|
+
cropH = sw / tRatio;
|
|
285
|
+
}
|
|
286
|
+
const sx = (sw - cropW) / 2;
|
|
287
|
+
const sy = (sh - cropH) / 2;
|
|
288
|
+
return { sx, sy, sw: cropW, sh: cropH, dx: 0, dy: 0, dw: tw, dh: th };
|
|
289
|
+
}
|
|
290
|
+
// contain: fit inside, letterbox if needed
|
|
291
|
+
let drawW;
|
|
292
|
+
let drawH;
|
|
293
|
+
if (sRatio > tRatio) {
|
|
294
|
+
drawW = tw;
|
|
295
|
+
drawH = tw / sRatio;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
drawH = th;
|
|
299
|
+
drawW = th * sRatio;
|
|
300
|
+
}
|
|
301
|
+
const dx = (tw - drawW) / 2;
|
|
302
|
+
const dy = (th - drawH) / 2;
|
|
303
|
+
return { sx: 0, sy: 0, sw, sh, dx, dy, dw: drawW, dh: drawH };
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Update filename extension to match the desired MIME type.
|
|
307
|
+
* @param name - Original filename
|
|
308
|
+
* @param type - Output MIME type
|
|
309
|
+
*/
|
|
310
|
+
function renameWithType(name, type) {
|
|
311
|
+
const ext = type === 'image/png' ? 'png' : 'jpg';
|
|
312
|
+
const idx = name.lastIndexOf('.');
|
|
313
|
+
const base = idx > 0 ? name.slice(0, idx) : name;
|
|
314
|
+
return `${base}.${ext}`;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const profilePictureCss = "@charset \"UTF-8\";:host(limel-profile-picture){position:relative;display:inline-flex;min-width:1.5rem;min-height:1.5rem;border-radius:var(--profile-picture-border-radius, 100vw);background-color:rgb(var(--contrast-400))}*{box-sizing:border-box}limel-file-dropzone,limel-file-input,button.avatar{display:flex;align-items:center;justify-content:center;width:100%;height:100%}button{all:unset;display:block}button:focus{outline:none}button:focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}button.avatar{overflow:hidden;border-radius:var(--profile-picture-border-radius, 100vw)}:host(:not([disabled]):not([disabled=true])) button.avatar{transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:var(--limel-theme-on-surface-color);background-color:transparent}:host(:not([disabled]):not([disabled=true])) button.avatar:hover,:host(:not([disabled]):not([disabled=true])) button.avatar:focus,:host(:not([disabled]):not([disabled=true])) button.avatar:focus-visible{will-change:color, background-color, box-shadow, transform}:host(:not([disabled]):not([disabled=true])) button.avatar:hover,:host(:not([disabled]):not([disabled=true])) button.avatar:focus-visible{transform:translate3d(0, 0.01rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}:host(:not([disabled]):not([disabled=true])) button.avatar:hover{box-shadow:var(--button-shadow-hovered)}:host(:not([disabled]):not([disabled=true])) button.avatar:active{--limel-clickable-transform-timing-function:cubic-bezier(\n 0.83,\n -0.15,\n 0.49,\n 1.16\n );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}:host(:not([disabled]):not([disabled=true])) button.avatar:hover,:host(:not([disabled]):not([disabled=true])) button.avatar:active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}:host([invalid]:not([invalid=false])) button.avatar{box-shadow:var(--shadow-error-state)}button.remove{transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:var(--limel-theme-on-surface-color);background-color:rgb(var(--contrast-900));cursor:pointer;height:1.25rem;width:1.25rem;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:0.75rem;background-image:url(\"data:image/svg+xml; utf8, <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><defs/><path fill='rgb(255,255,255)' d='M7.219 5.781L5.78 7.22 14.563 16 5.78 24.781 7.22 26.22 16 17.437l8.781 8.782 1.438-1.438L17.437 16l8.782-8.781L24.78 5.78 16 14.563z'/></svg>\");position:absolute;top:0;left:0;opacity:0}button.remove:hover,button.remove:focus,button.remove:focus-visible{will-change:color, background-color, box-shadow, transform}button.remove:hover,button.remove:focus-visible{transform:translate3d(0, 0.01rem, 0);color:rgb(var(--color-white));background-color:rgb(var(--color-red-default))}button.remove:hover{box-shadow:var(--button-shadow-hovered)}button.remove:active{--limel-clickable-transform-timing-function:cubic-bezier(\n 0.83,\n -0.15,\n 0.49,\n 1.16\n );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}button.remove:hover,button.remove:active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}:host(:hover) button.remove,:host(:focus) button.remove,:host(:focus-visible) button.remove,:host(:focus-within) button.remove,:host(:active) button.remove{animation:show 0.4s ease-in-out forwards}@keyframes show{0%{transform:scale(0.9);opacity:0}100%{transform:scale(1);opacity:1}}button.avatar,img,limel-icon{border-radius:var(--profile-picture-border-radius, 100vw)}limel-icon{width:calc(100% - 1rem);min-width:1rem;max-width:4rem;color:var(--limel-theme-text-secondary-on-background-color);margin:auto}img{object-fit:var(--limel-profile-picture-object-fit);width:100%;height:100%}:host(.has-image-error) img{border:1px dashed rgb(var(--contrast-600));background:url(\"data:image/svg+xml;charset=utf-8, <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' style='fill-rule:evenodd;'><path fill='rgba(186,186,192,0.16)' d='M0 0h4v4H0zM4 4h4v4H4z'/></svg>\");background-size:0.5rem}limel-spinner{position:absolute;inset:0;margin:auto}limel-popover{position:absolute;inset:auto 0 0 auto;display:block;width:2.25rem;height:2.25rem}";
|
|
318
|
+
|
|
319
|
+
const ProfilePicture = class {
|
|
320
|
+
constructor(hostRef) {
|
|
321
|
+
index.registerInstance(this, hostRef);
|
|
322
|
+
this.change = index.createEvent(this, "change", 7);
|
|
323
|
+
this.filesRejected = index.createEvent(this, "filesRejected", 7);
|
|
324
|
+
this.removeButtonId = randomString.createRandomString();
|
|
325
|
+
this.browseButtonId = randomString.createRandomString();
|
|
326
|
+
this.renderHelperText = () => {
|
|
327
|
+
if (!this.helperText) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
return (index.h("limel-tooltip", { elementId: this.browseButtonId, label: this.helperText }));
|
|
331
|
+
};
|
|
332
|
+
this.handleNewFiles = async (event) => {
|
|
333
|
+
var _a, _b;
|
|
334
|
+
event.stopPropagation();
|
|
335
|
+
if (this.disabled) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const file = (_a = event.detail) === null || _a === void 0 ? void 0 : _a[0];
|
|
339
|
+
if (!file) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (!files.isTypeAccepted(file, this.accept)) {
|
|
343
|
+
this.filesRejected.emit([file]);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
this.revokeObjectUrl();
|
|
347
|
+
this.imageError = false;
|
|
348
|
+
let out = file;
|
|
349
|
+
// Optional client-side resize
|
|
350
|
+
if (this.resize && file.fileContent instanceof File) {
|
|
351
|
+
try {
|
|
352
|
+
const processed = await resizeImage(file.fileContent, Object.assign(Object.assign({}, this.resize), { fit: (_b = this.resize.fit) !== null && _b !== void 0 ? _b : this.imageFit }));
|
|
353
|
+
out = Object.assign(Object.assign({}, file), { filename: processed.name, size: processed.size, contentType: processed.type, fileContent: processed });
|
|
354
|
+
}
|
|
355
|
+
catch (_c) {
|
|
356
|
+
// Fall back to original file if resize fails
|
|
357
|
+
out = file;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Create an object URL for immediate preview if no href present
|
|
361
|
+
if (!out.href && out.fileContent instanceof File) {
|
|
362
|
+
this.objectUrl = URL.createObjectURL(out.fileContent);
|
|
363
|
+
}
|
|
364
|
+
this.change.emit(out);
|
|
365
|
+
};
|
|
366
|
+
this.handleRejectedFiles = (event) => {
|
|
367
|
+
event.stopPropagation();
|
|
368
|
+
this.filesRejected.emit(event.detail);
|
|
369
|
+
};
|
|
370
|
+
this.handleClear = (event) => {
|
|
371
|
+
event.stopPropagation();
|
|
372
|
+
this.revokeObjectUrl();
|
|
373
|
+
this.imageError = false;
|
|
374
|
+
this.change.emit(undefined);
|
|
375
|
+
};
|
|
376
|
+
this.onImageError = () => {
|
|
377
|
+
this.imageError = true;
|
|
378
|
+
};
|
|
379
|
+
this.openPopover = (event) => {
|
|
380
|
+
event.stopPropagation();
|
|
381
|
+
this.isErrorMessagePopoverOpen = true;
|
|
382
|
+
};
|
|
383
|
+
this.onPopoverClose = (event) => {
|
|
384
|
+
event.stopPropagation();
|
|
385
|
+
this.isErrorMessagePopoverOpen = false;
|
|
386
|
+
};
|
|
387
|
+
this.getTranslation = (key) => {
|
|
388
|
+
return translations.translate.get(key, this.language);
|
|
389
|
+
};
|
|
390
|
+
this.language = 'en';
|
|
391
|
+
this.label = undefined;
|
|
392
|
+
this.icon = 'user';
|
|
393
|
+
this.helperText = undefined;
|
|
394
|
+
this.disabled = false;
|
|
395
|
+
this.readonly = false;
|
|
396
|
+
this.required = false;
|
|
397
|
+
this.invalid = false;
|
|
398
|
+
this.loading = false;
|
|
399
|
+
this.value = undefined;
|
|
400
|
+
this.imageFit = 'cover';
|
|
401
|
+
this.accept = 'image/jpeg,image/png,image/heic,.jpg,.jpeg,.png,.heic';
|
|
402
|
+
this.resize = undefined;
|
|
403
|
+
this.objectUrl = undefined;
|
|
404
|
+
this.imageError = false;
|
|
405
|
+
this.isErrorMessagePopoverOpen = false;
|
|
406
|
+
}
|
|
407
|
+
disconnectedCallback() {
|
|
408
|
+
this.revokeObjectUrl();
|
|
409
|
+
}
|
|
410
|
+
handleValueChange() {
|
|
411
|
+
// Clear previously created object URL when value changes
|
|
412
|
+
this.revokeObjectUrl();
|
|
413
|
+
this.imageError = false;
|
|
414
|
+
// If a new File without href is provided, create an object URL for preview
|
|
415
|
+
const currentValue = this.value;
|
|
416
|
+
if (currentValue &&
|
|
417
|
+
typeof currentValue !== 'string' &&
|
|
418
|
+
!currentValue.href &&
|
|
419
|
+
currentValue.fileContent instanceof File) {
|
|
420
|
+
this.objectUrl = URL.createObjectURL(currentValue.fileContent);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
render() {
|
|
424
|
+
const hostClassNames = {
|
|
425
|
+
'has-image-error': this.imageError,
|
|
426
|
+
};
|
|
427
|
+
if (this.readonly) {
|
|
428
|
+
return index.h(index.Host, { class: hostClassNames }, this.renderAvatar());
|
|
429
|
+
}
|
|
430
|
+
return (index.h(index.Host, { class: hostClassNames }, index.h("limel-file-dropzone", { disabled: this.disabled, accept: this.accept, onFilesSelected: this.handleNewFiles, onFilesRejected: this.handleRejectedFiles }, index.h("limel-file-input", { accept: this.accept, disabled: this.disabled, "aria-required": this.required ? 'true' : undefined, "aria-invalid": this.invalid ? 'true' : undefined }, this.renderBrowseButton())), this.renderClearButton(), this.renderSpinner(), this.renderErrorMessage(), this.renderHelperText()));
|
|
431
|
+
}
|
|
432
|
+
get hasValue() {
|
|
433
|
+
if (typeof this.value === 'string') {
|
|
434
|
+
return !!this.value;
|
|
435
|
+
}
|
|
436
|
+
if (this.value && (this.value.href || this.value.fileContent)) {
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
return !!this.objectUrl;
|
|
440
|
+
}
|
|
441
|
+
renderBrowseButton() {
|
|
442
|
+
return (index.h("button", { id: this.browseButtonId, type: "button", class: "avatar", disabled: this.disabled, "aria-label": this.label, "aria-busy": this.loading ? 'true' : 'false', "aria-live": "polite" }, this.renderAvatar()));
|
|
443
|
+
}
|
|
444
|
+
renderAvatar() {
|
|
445
|
+
const src = this.getImageSrc();
|
|
446
|
+
if (src) {
|
|
447
|
+
return (index.h("img", { src: src, alt: "", style: {
|
|
448
|
+
'--limel-profile-picture-object-fit': this.imageFit,
|
|
449
|
+
}, loading: "lazy", onError: this.onImageError }));
|
|
450
|
+
}
|
|
451
|
+
return this.renderIcon();
|
|
452
|
+
}
|
|
453
|
+
renderIcon() {
|
|
454
|
+
var _a, _b;
|
|
455
|
+
const icon = getIconProps.getIconName(this.icon);
|
|
456
|
+
return (index.h("limel-icon", { name: icon, style: {
|
|
457
|
+
color: `${(_a = this.icon) === null || _a === void 0 ? void 0 : _a.color}`,
|
|
458
|
+
'background-color': `${(_b = this.icon) === null || _b === void 0 ? void 0 : _b.backgroundColor}`,
|
|
459
|
+
} }));
|
|
460
|
+
}
|
|
461
|
+
renderClearButton() {
|
|
462
|
+
if (!this.hasValue || this.disabled) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
return [
|
|
466
|
+
index.h("button", { class: "remove", type: "button", id: this.removeButtonId, onClick: this.handleClear }),
|
|
467
|
+
index.h("limel-tooltip", { label: this.getTranslation('profile-picture.remove'), elementId: this.removeButtonId }),
|
|
468
|
+
];
|
|
469
|
+
}
|
|
470
|
+
renderSpinner() {
|
|
471
|
+
if (!this.loading) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
return index.h("limel-spinner", null);
|
|
475
|
+
}
|
|
476
|
+
// Collects derived flags used for deciding whether to show the unsupported preview message
|
|
477
|
+
getUnsupportedPreviewContext() {
|
|
478
|
+
const currentValue = this.value;
|
|
479
|
+
const hasNoSrc = !this.getImageSrc();
|
|
480
|
+
const hasLocalFile = !!(currentValue &&
|
|
481
|
+
typeof currentValue !== 'string' &&
|
|
482
|
+
currentValue.fileContent instanceof File &&
|
|
483
|
+
!currentValue.href);
|
|
484
|
+
const isResizeConfigured = !!this.resize;
|
|
485
|
+
return { hasNoSrc, hasLocalFile, isResizeConfigured };
|
|
486
|
+
}
|
|
487
|
+
shouldShowErrorMessage() {
|
|
488
|
+
const { hasNoSrc, hasLocalFile, isResizeConfigured } = this.getUnsupportedPreviewContext();
|
|
489
|
+
return ((hasNoSrc || this.imageError) && hasLocalFile && isResizeConfigured);
|
|
490
|
+
}
|
|
491
|
+
// Shows a non-intrusive note when there is a File without href and no object URL, which
|
|
492
|
+
// can happen if the browser failed to decode the source (e.g., HEIC in Chromium).
|
|
493
|
+
renderErrorMessage() {
|
|
494
|
+
if (!this.shouldShowErrorMessage()) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const errorIcon = {
|
|
498
|
+
name: 'error',
|
|
499
|
+
color: 'rgb(var(--color-orange-dark))',
|
|
500
|
+
};
|
|
501
|
+
const errorMessageStyles = {
|
|
502
|
+
maxWidth: '20rem',
|
|
503
|
+
borderRadius: '0.75rem',
|
|
504
|
+
};
|
|
505
|
+
return (index.h("limel-popover", { open: this.isErrorMessagePopoverOpen, onClick: this.openPopover, onClose: this.onPopoverClose }, index.h("limel-icon-button", { slot: "trigger", elevated: true, icon: errorIcon, "aria-live": "polite", label: this.getTranslation('profile-picture.unsupported-preview.title') }), index.h("limel-callout", { type: "warning", style: errorMessageStyles, heading: this.getTranslation('profile-picture.unsupported-preview.title') }, this.getTranslation('profile-picture.unsupported-preview.description'))));
|
|
506
|
+
}
|
|
507
|
+
getImageSrc() {
|
|
508
|
+
if (!this.value) {
|
|
509
|
+
return this.objectUrl; // Could be set from last selection before parent consumes
|
|
510
|
+
}
|
|
511
|
+
if (typeof this.value === 'string') {
|
|
512
|
+
return this.value;
|
|
513
|
+
}
|
|
514
|
+
if (this.value.href) {
|
|
515
|
+
return this.value.href;
|
|
516
|
+
}
|
|
517
|
+
if (this.value.fileContent instanceof File) {
|
|
518
|
+
return this.objectUrl;
|
|
519
|
+
}
|
|
520
|
+
return undefined;
|
|
521
|
+
}
|
|
522
|
+
revokeObjectUrl() {
|
|
523
|
+
if (this.objectUrl) {
|
|
524
|
+
URL.revokeObjectURL(this.objectUrl);
|
|
525
|
+
this.objectUrl = undefined;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
static get watchers() { return {
|
|
529
|
+
"value": ["handleValueChange"]
|
|
530
|
+
}; }
|
|
531
|
+
};
|
|
532
|
+
ProfilePicture.style = profilePictureCss;
|
|
533
|
+
|
|
534
|
+
exports.limel_profile_picture = ProfilePicture;
|
|
535
|
+
|
|
536
|
+
//# sourceMappingURL=limel-profile-picture.cjs.entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"file":"limel-profile-picture.entry.cjs.js","mappings":"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","names":["createRandomString","h","isTypeAccepted","translate","Host","getIconName"],"sources":["./src/util/image-resize.ts","./src/components/profile-picture/profile-picture.scss?tag=limel-profile-picture&encapsulation=shadow","./src/components/profile-picture/profile-picture.tsx"],"sourcesContent":["/**\n * Image resize utilities\n *\n * Overview\n * --------\n * This module provides a small, dependency-free utility to resize images on the client\n * (in the browser) before uploading. It works by decoding an input `File` to an\n * `ImageBitmap` (or falling back to an `HTMLImageElement`), drawing it onto a\n * `Canvas`/`OffscreenCanvas` with the requested strategy (cover/contain), and\n * then exporting the result to a new `File` with your preferred MIME type and\n * quality.\n *\n * Why resize client-side?\n * - Faster perceived uploads and lower bandwidth usage\n * - Consistent avatar sizes and formats (e.g., JPEG 400x400)\n * - No server-side transformation required for common cases\n *\n * Fit strategies\n * - `cover` (default): The image is scaled to cover the target rectangle, and\n * the excess parts are center-cropped. Good for avatars.\n * - `contain`: The image is scaled to fit entirely within the target rectangle\n * without cropping, letterboxing if needed. Good when you must preserve the\n * entire image.\n *\n * Decoding & EXIF orientation\n * EXIF orientation is a piece of metadata stored inside image files\n * (usually JPEGs) that tells image renderer software how the image should be displayed\n * i.e., whether it should be rotated or flipped. This meta data is normally added\n * to photos by digital cameras and phones.\n * - When available, `createImageBitmap(file, { imageOrientation: 'from-image' })`\n * is used to automatically respect EXIF orientation.\n * - If not available or it fails (e.g., unsupported format), we fall back to\n * decoding via an `HTMLImageElement`.\n *\n * OffscreenCanvas\n * - If the environment supports `OffscreenCanvas`, it will be used for the draw\n * and encode operations for better performance in some cases. Otherwise, a\n * regular `HTMLCanvasElement` is used.\n *\n * HEIC/HEIF notes\n * - All major browsers except Safari lack native HEIC/HEIF decoding.\n * In such cases the `resizeImage` function will throw when decoding fails.\n * The caller should catch and fall back\n * to using the original file or handle conversion on the server.\n * - If we need guaranteed client-side HEIC->JPEG conversion, we must add a small\n * library or WASM module; this utility intentionally avoids extra dependencies.\n *\n * Output type & quality\n * - Default output is `image/jpeg` with `quality=0.85`, which is typically\n * appropriate for avatars. You can switch to `image/png` to preserve\n * transparency.\n * - The output filename extension is adjusted to match the chosen MIME type by\n * default (e.g., `.jpg` or `.png`). You can override naming via the `rename`\n * option.\n *\n * Error handling\n * - Throws if canvas/context cannot be created or if canvas->blob conversion fails.\n * - Decoding failures (unsupported type) will throw; caller can try/catch and\n * fall back to the original file.\n *\n * Performance tips\n * - Keep target sizes reasonable (e.g., 256–1024 px) to avoid long processing\n * times on modest devices.\n * - JPEG with quality 0.8–0.9 often strikes a good balance between size and\n * perceived quality for photos/avatars.\n *\n * Usage examples\n * --------------\n * Basic usage:\n * ```ts\n * import { resizeImage } from '@limetech/lime-elements/util/image-resize';\n *\n * const processed = await resizeImage(file, {\n * width: 400,\n * height: 400,\n * fit: 'cover', // default; center-crops\n * type: 'image/jpeg', // default\n * quality: 0.85, // default\n * });\n * // Upload `processed` instead of the original file\n * ```\n *\n * With custom naming:\n * ```ts\n * const processed = await resizeImage(file, {\n * width: 800,\n * height: 800,\n * fit: 'contain',\n * type: 'image/png',\n * rename: (name) => name.replace(/\\.[^.]+$/, '') + '_resized.png',\n * });\n * ```\n *\n * In a Stencil component (simplified):\n * ```tsx\n * private async handleFilesSelected(file: File) {\n * try {\n * const resized = await resizeImage(file, { width: 400, height: 400 });\n * // build your FileInfo and emit\n * } catch {\n * // fall back to original\n * }\n * }\n * ```\n */\n// (Removed exported ResizeFit to avoid forcing a public symbol.)\n\n/**\n * Options for client-side image resizing.\n * @beta\n */\nexport type ResizeOptions = {\n /** Target width in CSS pixels. */\n width: number;\n /** Target height in CSS pixels. */\n height: number;\n /** Fit strategy; defaults to 'cover'. */\n fit?: 'cover' | 'contain';\n /** Output MIME type; 'image/jpeg' by default. */\n type?: 'image/jpeg' | 'image/png';\n /** JPEG quality (0..1); used only for 'image/jpeg'. Defaults to 0.85. */\n quality?: number;\n /** Optional renaming function. Defaults to changing extension to match MIME. */\n rename?: (originalName: string) => string;\n};\n\ntype SourceLike = ImageBitmap | HTMLImageElement;\n\n/**\n * Resize an image file on the client using Canvas/OffscreenCanvas.\n * Returns a new File with the requested format and dimensions.\n *\n * Contract\n * - Input: image `File`\n * - Output: resized image as a new `File` with updated `type`, name, and size\n * - Errors: may throw on decode failure or canvas export failure\n *\n * @beta\n * @param file - The image file to resize.\n * @param options - Configuration for the resize operation.\n */\nexport async function resizeImage(\n file: File,\n options: ResizeOptions\n): Promise<File> {\n const {\n width,\n height,\n fit = 'cover',\n type = 'image/jpeg',\n quality = 0.85,\n rename = (name: string) => renameWithType(name, type),\n } = options;\n\n const source = await loadSource(file);\n const { sx, sy, sw, sh, dx, dy, dw, dh } = computeRects(\n source.width as number,\n source.height as number,\n width,\n height,\n fit\n );\n\n const canvas = createCanvas(width, height);\n const ctx = get2dContext(canvas);\n ctx.clearRect(0, 0, width, height);\n ctx.drawImage(source, sx, sy, sw, sh, dx, dy, dw, dh);\n\n const blob = await canvasToBlob(canvas, type, quality);\n const name = rename(file.name);\n return new File([blob], name, { type });\n}\n\n/** Whether OffscreenCanvas is available in the current environment. */\nfunction supportsOffscreen(): boolean {\n try {\n return typeof (globalThis as any).OffscreenCanvas === 'function';\n } catch {\n return false;\n }\n}\n\n/**\n * Create either an OffscreenCanvas or a regular canvas for drawing.\n * @param width - Target width\n * @param height - Target height\n */\nfunction createCanvas(\n width: number,\n height: number\n): HTMLCanvasElement | OffscreenCanvas {\n if (supportsOffscreen()) {\n return new (globalThis as any).OffscreenCanvas(width, height);\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\n/**\n * Get the 2D rendering context, throwing a descriptive error if unavailable.\n * @param canvas - The canvas to get context from\n */\nfunction get2dContext(canvas: HTMLCanvasElement | OffscreenCanvas) {\n const ctx = (canvas as any).getContext('2d', { alpha: true });\n if (!ctx) {\n throw new Error('2D canvas context not available');\n }\n\n return ctx as CanvasRenderingContext2D;\n}\n\n/**\n * Convert the canvas content to a Blob, supporting both canvas types.\n * @param canvas - The source canvas\n * @param type - Output MIME type\n * @param quality - JPEG quality (0..1)\n */\nfunction canvasToBlob(\n canvas: HTMLCanvasElement | OffscreenCanvas,\n type: string,\n quality: number\n): Promise<Blob> {\n if ('convertToBlob' in canvas) {\n return (canvas as OffscreenCanvas).convertToBlob({ type, quality });\n }\n\n return new Promise((resolve, reject) => {\n (canvas as HTMLCanvasElement).toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Failed to create blob from canvas'));\n return;\n }\n resolve(blob);\n },\n type,\n quality\n );\n });\n}\n\n/**\n * Load the image into a decodable source (ImageBitmap preferred).\n * @param file - The input file to decode\n */\n\nasync function loadSource(file: File): Promise<SourceLike> {\n if (typeof (globalThis as any).createImageBitmap === 'function') {\n try {\n return await (globalThis as any).createImageBitmap(file, {\n imageOrientation: 'from-image',\n } as any);\n } catch (error) {\n // Log for debugging in development, but continue with fallback\n const isDev =\n (globalThis as any).process?.env?.NODE_ENV !== 'production';\n\n if (\n isDev &&\n typeof console !== 'undefined' &&\n typeof console.debug === 'function'\n ) {\n console.debug(\n 'createImageBitmap failed, falling back to HTMLImageElement:',\n error\n );\n }\n }\n }\n\n return await loadImageElement(file);\n}\n\n/**\n * Decode an image file via HTMLImageElement when ImageBitmap is unavailable.\n * @param file - The input file to decode\n */\nasync function loadImageElement(file: File): Promise<HTMLImageElement> {\n const url = URL.createObjectURL(file);\n try {\n const img = new Image();\n img.decoding = 'sync';\n img.src = url;\n await img.decode?.().catch(() => undefined);\n if (!img.complete) {\n await new Promise<void>((resolve, reject) => {\n const cleanup = () => {\n img.removeEventListener('load', onLoad);\n img.removeEventListener('error', onError);\n };\n\n const onLoad = () => {\n cleanup();\n resolve();\n };\n const onError = (e: Event) => {\n cleanup();\n reject(e);\n };\n\n img.addEventListener('load', onLoad);\n img.addEventListener('error', onError);\n });\n }\n return img;\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n\n/**\n * Compute source and destination rectangles for drawImage based on the fit mode.\n *\n * Returns sx, sy, sw, sh for the source crop/area and dx, dy, dw, dh for the\n * destination rectangle on the target canvas.\n *\n * @param sw - Source width\n * @param sh - Source height\n * @param tw - Target width\n * @param th - Target height\n * @param fit - Fit mode (cover/contain)\n */\nfunction computeRects(\n sw: number,\n sh: number,\n tw: number,\n th: number,\n fit: 'cover' | 'contain'\n) {\n const sRatio = sw / sh;\n const tRatio = tw / th;\n\n if (fit === 'cover') {\n // scale source to cover target, then center-crop\n let cropW: number;\n let cropH: number;\n if (sRatio > tRatio) {\n // source is wider than target: crop width\n cropH = sh;\n cropW = sh * tRatio;\n } else {\n // source is taller than target: crop height\n cropW = sw;\n cropH = sw / tRatio;\n }\n const sx = (sw - cropW) / 2;\n const sy = (sh - cropH) / 2;\n return { sx, sy, sw: cropW, sh: cropH, dx: 0, dy: 0, dw: tw, dh: th };\n }\n\n // contain: fit inside, letterbox if needed\n let drawW: number;\n let drawH: number;\n if (sRatio > tRatio) {\n drawW = tw;\n drawH = tw / sRatio;\n } else {\n drawH = th;\n drawW = th * sRatio;\n }\n const dx = (tw - drawW) / 2;\n const dy = (th - drawH) / 2;\n\n return { sx: 0, sy: 0, sw, sh, dx, dy, dw: drawW, dh: drawH };\n}\n\n/**\n * Update filename extension to match the desired MIME type.\n * @param name - Original filename\n * @param type - Output MIME type\n */\nfunction renameWithType(name: string, type: string): string {\n const ext = type === 'image/png' ? 'png' : 'jpg';\n const idx = name.lastIndexOf('.');\n const base = idx > 0 ? name.slice(0, idx) : name;\n return `${base}.${ext}`;\n}\n","@use '../../style/mixins';\n\n/**\n* @prop --profile-picture-border-radius: Border radius of the profile picture. Defaults to `100vw` to render a circular shape.\n*/\n\n:host(limel-profile-picture) {\n position: relative;\n\n display: inline-flex;\n min-width: 1.5rem;\n min-height: 1.5rem;\n\n border-radius: var(--profile-picture-border-radius, 100vw);\n background-color: rgb(var(--contrast-400));\n}\n\n* {\n box-sizing: border-box;\n}\n\nlimel-file-dropzone,\nlimel-file-input,\nbutton.avatar {\n display: flex;\n align-items: center;\n justify-content: center;\n\n width: 100%;\n height: 100%;\n}\n\nbutton {\n all: unset;\n display: block;\n @include mixins.visualize-keyboard-focus();\n\n &.avatar {\n overflow: hidden;\n border-radius: var(--profile-picture-border-radius, 100vw);\n\n :host(:not([disabled]):not([disabled='true'])) & {\n @include mixins.is-flat-clickable();\n }\n\n :host([invalid]:not([invalid='false'])) & {\n box-shadow: var(--shadow-error-state);\n }\n }\n\n &.remove {\n @include mixins.clear-all-button();\n position: absolute;\n top: 0;\n left: 0;\n opacity: 0;\n\n :host(:hover) &,\n :host(:focus) &,\n :host(:focus-visible) &,\n :host(:focus-within) &,\n :host(:active) & {\n animation: show 0.4s ease-in-out forwards;\n }\n }\n}\n\n@keyframes show {\n 0% {\n transform: scale(0.9);\n opacity: 0;\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n\nbutton.avatar,\nimg,\nlimel-icon {\n border-radius: var(--profile-picture-border-radius, 100vw);\n}\n\nlimel-icon {\n width: calc(100% - 1rem);\n min-width: 1rem;\n max-width: 4rem;\n color: var(--limel-theme-text-secondary-on-background-color);\n margin: auto;\n}\n\nimg {\n object-fit: var(--limel-profile-picture-object-fit);\n width: 100%;\n height: 100%;\n\n :host(.has-image-error) & {\n border: 1px dashed rgb(var(--contrast-600));\n background: url(\"data:image/svg+xml;charset=utf-8, <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' style='fill-rule:evenodd;'><path fill='rgba(186,186,192,0.16)' d='M0 0h4v4H0zM4 4h4v4H4z'/></svg>\");\n background-size: 0.5rem;\n }\n}\n\nlimel-spinner {\n position: absolute;\n inset: 0;\n margin: auto;\n}\n\nlimel-popover {\n position: absolute;\n inset: auto 0 0 auto;\n display: block;\n width: 2.25rem;\n height: 2.25rem;\n}\n","import {\n Component,\n Event,\n EventEmitter,\n h,\n Host,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport { FileInfo } from '../../global/shared-types/file.types';\nimport { isTypeAccepted } from '../../util/files';\nimport { Icon } from '../../global/shared-types/icon.types';\nimport { getIconName } from '../icon/get-icon-props';\nimport translate from '../../global/translations';\nimport { Languages } from '../date-picker/date.types';\nimport { createRandomString } from '../../util/random-string';\nimport { resizeImage, ResizeOptions } from '../../util/image-resize';\n\n/**\n * This component displays a profile picture, while allowing the user\n * to change it via a file input or drag-and-drop.\n *\n * It supports client-side image resizing and conversion,\n * as well as a simple lazy-loading mechanism.\n *\n * @exampleComponent limel-example-profile-picture-basic\n * @exampleComponent limel-example-profile-picture-helper-text\n * @exampleComponent limel-example-profile-picture-icon\n * @exampleComponent limel-example-profile-picture-with-value\n * @exampleComponent limel-example-profile-picture-loading\n * @exampleComponent limel-example-profile-picture-image-fit\n * @exampleComponent limel-example-profile-picture-composite\n * @exampleComponent limel-example-profile-picture-resize-contain\n * @exampleComponent limel-example-profile-picture-resize-cover\n * @exampleComponent limel-example-profile-picture-resize-fallback\n * @exampleComponent limel-example-profile-picture-styling\n * @beta\n */\n@Component({\n tag: 'limel-profile-picture',\n shadow: true,\n styleUrl: 'profile-picture.scss',\n})\nexport class ProfilePicture {\n /**\n * Defines the language for translations.\n * Will translate the translatable strings on the components.\n */\n @Prop({ reflect: true })\n public language: Languages = 'en';\n\n /**\n * Accessible label for the the browse button.\n */\n @Prop({ reflect: true })\n public label: string;\n\n /**\n * Placeholder icon of the component, displayed when no image is present.\n */\n @Prop()\n public icon: string | Icon = 'user';\n\n /**\n * Helper text shown as a tooltip on hover or focus.\n */\n @Prop()\n public helperText?: string;\n\n /**\n * Disables user interaction.\n * Prevents uploading new pictures or removing existing ones.\n */\n @Prop({ reflect: true })\n public disabled = false;\n\n /**\n * Readonly prevents changing the value but allows interaction like focus.\n */\n @Prop({ reflect: true })\n public readonly = false;\n\n /**\n * Marks the control as required.\n */\n @Prop({ reflect: true })\n public required = false;\n\n /**\n * Marks the control as invalid.\n */\n @Prop({ reflect: true })\n public invalid = false;\n\n /**\n * Set to `true` to put the component in the `loading` state,\n * and render an indeterminate progress indicator inside.\n * This does _not_ disable the interactivity of the component!\n */\n @Prop({ reflect: true })\n public loading = false;\n\n /**\n * Current image to display. Either a URL string or a `FileInfo` with an href.\n */\n @Prop()\n public value?: string | FileInfo;\n\n /**\n * How the image should fit within the container.\n * - `cover` will fill the container and crop excess parts.\n * - `contain` will scale the image to fit within the container without cropping.\n */\n @Prop({ reflect: true })\n public imageFit: 'cover' | 'contain' = 'cover';\n\n /**\n * A comma-separated list of accepted file types.\n */\n @Prop({ reflect: true })\n public accept: string =\n 'image/jpeg,image/png,image/heic,.jpg,.jpeg,.png,.heic';\n\n /**\n * Optional client-side resize before emitting the file.\n * If provided, the selected image will be resized on the client device.\n * :::note\n * HEIC may not decode in all browsers; when decoding fails, the original\n * file will be emitted. See the examples for more info.\n * :::\n */\n @Prop()\n public resize?: ResizeOptions;\n\n /**\n * Emitted when the picture changes (first FileInfo only).\n */\n @Event()\n public change: EventEmitter<FileInfo | undefined>;\n\n /**\n * Emitted when a file is rejected by accept filter.\n */\n @Event()\n public filesRejected: EventEmitter<FileInfo[]>;\n\n @State()\n private objectUrl?: string;\n\n @State()\n private imageError = false;\n\n @State()\n private isErrorMessagePopoverOpen = false;\n\n private removeButtonId = createRandomString();\n private browseButtonId = createRandomString();\n\n public disconnectedCallback() {\n this.revokeObjectUrl();\n }\n\n @Watch('value')\n protected handleValueChange() {\n // Clear previously created object URL when value changes\n this.revokeObjectUrl();\n this.imageError = false;\n\n // If a new File without href is provided, create an object URL for preview\n const currentValue = this.value;\n if (\n currentValue &&\n typeof currentValue !== 'string' &&\n !currentValue.href &&\n currentValue.fileContent instanceof File\n ) {\n this.objectUrl = URL.createObjectURL(currentValue.fileContent);\n }\n }\n\n public render() {\n const hostClassNames = {\n 'has-image-error': this.imageError,\n };\n\n if (this.readonly) {\n return <Host class={hostClassNames}>{this.renderAvatar()}</Host>;\n }\n\n return (\n <Host class={hostClassNames}>\n <limel-file-dropzone\n disabled={this.disabled}\n accept={this.accept}\n onFilesSelected={this.handleNewFiles}\n onFilesRejected={this.handleRejectedFiles}\n >\n <limel-file-input\n accept={this.accept}\n disabled={this.disabled}\n aria-required={this.required ? 'true' : undefined}\n aria-invalid={this.invalid ? 'true' : undefined}\n >\n {this.renderBrowseButton()}\n </limel-file-input>\n </limel-file-dropzone>\n {this.renderClearButton()}\n {this.renderSpinner()}\n {this.renderErrorMessage()}\n {this.renderHelperText()}\n </Host>\n );\n }\n\n private get hasValue(): boolean {\n if (typeof this.value === 'string') {\n return !!this.value;\n }\n\n if (this.value && (this.value.href || this.value.fileContent)) {\n return true;\n }\n\n return !!this.objectUrl;\n }\n\n private renderBrowseButton() {\n return (\n <button\n id={this.browseButtonId}\n type=\"button\"\n class=\"avatar\"\n disabled={this.disabled}\n aria-label={this.label}\n aria-busy={this.loading ? 'true' : 'false'}\n aria-live=\"polite\"\n >\n {this.renderAvatar()}\n </button>\n );\n }\n\n private renderAvatar() {\n const src = this.getImageSrc();\n\n if (src) {\n return (\n <img\n src={src}\n alt=\"\"\n style={{\n '--limel-profile-picture-object-fit': this.imageFit,\n }}\n loading=\"lazy\"\n onError={this.onImageError}\n />\n );\n }\n\n return this.renderIcon();\n }\n\n private renderIcon() {\n const icon = getIconName(this.icon);\n\n return (\n <limel-icon\n name={icon}\n style={{\n color: `${(this.icon as Icon)?.color}`,\n 'background-color': `${\n (this.icon as Icon)?.backgroundColor\n }`,\n }}\n />\n );\n }\n\n private renderClearButton() {\n if (!this.hasValue || this.disabled) {\n return;\n }\n\n return [\n <button\n class=\"remove\"\n type=\"button\"\n id={this.removeButtonId}\n onClick={this.handleClear}\n />,\n <limel-tooltip\n label={this.getTranslation('profile-picture.remove')}\n elementId={this.removeButtonId}\n />,\n ];\n }\n\n private renderSpinner() {\n if (!this.loading) {\n return;\n }\n\n return <limel-spinner />;\n }\n\n private renderHelperText = () => {\n if (!this.helperText) {\n return;\n }\n\n return (\n <limel-tooltip\n elementId={this.browseButtonId}\n label={this.helperText}\n />\n );\n };\n\n // Collects derived flags used for deciding whether to show the unsupported preview message\n private getUnsupportedPreviewContext() {\n const currentValue = this.value;\n const hasNoSrc = !this.getImageSrc();\n const hasLocalFile = !!(\n currentValue &&\n typeof currentValue !== 'string' &&\n currentValue.fileContent instanceof File &&\n !currentValue.href\n );\n const isResizeConfigured = !!this.resize;\n\n return { hasNoSrc, hasLocalFile, isResizeConfigured };\n }\n\n private shouldShowErrorMessage(): boolean {\n const { hasNoSrc, hasLocalFile, isResizeConfigured } =\n this.getUnsupportedPreviewContext();\n\n return (\n (hasNoSrc || this.imageError) && hasLocalFile && isResizeConfigured\n );\n }\n\n // Shows a non-intrusive note when there is a File without href and no object URL, which\n // can happen if the browser failed to decode the source (e.g., HEIC in Chromium).\n private renderErrorMessage() {\n if (!this.shouldShowErrorMessage()) {\n return;\n }\n\n const errorIcon = {\n name: 'error',\n color: 'rgb(var(--color-orange-dark))',\n };\n const errorMessageStyles = {\n maxWidth: '20rem',\n borderRadius: '0.75rem',\n };\n return (\n <limel-popover\n open={this.isErrorMessagePopoverOpen}\n onClick={this.openPopover}\n onClose={this.onPopoverClose}\n >\n <limel-icon-button\n slot=\"trigger\"\n elevated={true}\n icon={errorIcon}\n aria-live=\"polite\"\n label={this.getTranslation(\n 'profile-picture.unsupported-preview.title'\n )}\n />\n <limel-callout\n type=\"warning\"\n style={errorMessageStyles}\n heading={this.getTranslation(\n 'profile-picture.unsupported-preview.title'\n )}\n >\n {this.getTranslation(\n 'profile-picture.unsupported-preview.description'\n )}\n </limel-callout>\n </limel-popover>\n );\n }\n\n private handleNewFiles = async (event: CustomEvent<FileInfo[]>) => {\n event.stopPropagation();\n if (this.disabled) {\n return;\n }\n\n const file = event.detail?.[0];\n if (!file) {\n return;\n }\n\n if (!isTypeAccepted(file, this.accept)) {\n this.filesRejected.emit([file]);\n return;\n }\n\n this.revokeObjectUrl();\n this.imageError = false;\n\n let out = file;\n\n // Optional client-side resize\n if (this.resize && file.fileContent instanceof File) {\n try {\n const processed = await resizeImage(file.fileContent, {\n ...this.resize,\n fit: this.resize.fit ?? this.imageFit,\n });\n out = {\n ...file,\n filename: processed.name,\n size: processed.size,\n contentType: processed.type,\n fileContent: processed,\n };\n } catch {\n // Fall back to original file if resize fails\n out = file;\n }\n }\n // Create an object URL for immediate preview if no href present\n if (!out.href && out.fileContent instanceof File) {\n this.objectUrl = URL.createObjectURL(out.fileContent);\n }\n this.change.emit(out);\n };\n\n private handleRejectedFiles = (event: CustomEvent<FileInfo[]>) => {\n event.stopPropagation();\n this.filesRejected.emit(event.detail);\n };\n\n private getImageSrc(): string | undefined {\n if (!this.value) {\n return this.objectUrl; // Could be set from last selection before parent consumes\n }\n\n if (typeof this.value === 'string') {\n return this.value;\n }\n\n if (this.value.href) {\n return this.value.href;\n }\n\n if (this.value.fileContent instanceof File) {\n return this.objectUrl;\n }\n\n return undefined;\n }\n\n private revokeObjectUrl() {\n if (this.objectUrl) {\n URL.revokeObjectURL(this.objectUrl);\n this.objectUrl = undefined;\n }\n }\n\n private handleClear = (event: Event) => {\n event.stopPropagation();\n this.revokeObjectUrl();\n this.imageError = false;\n this.change.emit(undefined);\n };\n\n private onImageError = () => {\n this.imageError = true;\n };\n\n private openPopover = (event: MouseEvent) => {\n event.stopPropagation();\n this.isErrorMessagePopoverOpen = true;\n };\n\n private onPopoverClose = (event: CustomEvent) => {\n event.stopPropagation();\n this.isErrorMessagePopoverOpen = false;\n };\n\n private getTranslation = (key: string) => {\n return translate.get(key, this.language);\n };\n}\n"],"version":3}
|
|
@@ -13,7 +13,7 @@ const _getTag = require('./_getTag-8d76f8e1.js');
|
|
|
13
13
|
const _getPrototype = require('./_getPrototype-de167139.js');
|
|
14
14
|
const isArray = require('./isArray-d188a04f.js');
|
|
15
15
|
const isObjectLike = require('./isObjectLike-3e3f0cba.js');
|
|
16
|
-
const translations = require('./translations-
|
|
16
|
+
const translations = require('./translations-7499f391.js');
|
|
17
17
|
const randomString = require('./random-string-27fb6c74.js');
|
|
18
18
|
const isItem = require('./is-item-19d9d601.js');
|
|
19
19
|
const files = require('./files-d660a1fa.js');
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
const index = require('./index-174a078a.js');
|
|
6
|
-
const translations = require('./translations-
|
|
6
|
+
const translations = require('./translations-7499f391.js');
|
|
7
7
|
const randomString = require('./random-string-27fb6c74.js');
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -11,7 +11,7 @@ const isObject = require('./isObject-e28b7997.js');
|
|
|
11
11
|
const _getAllKeysIn = require('./_getAllKeysIn-6b9014ad.js');
|
|
12
12
|
const negate = require('./negate-14a67e26.js');
|
|
13
13
|
const isEqual = require('./isEqual-84d785f8.js');
|
|
14
|
-
const translations = require('./translations-
|
|
14
|
+
const translations = require('./translations-7499f391.js');
|
|
15
15
|
require('./_baseIsEqual-2203758e.js');
|
|
16
16
|
require('./eq-282c9b48.js');
|
|
17
17
|
require('./_getTag-8d76f8e1.js');
|