@hkdigital/lib-sveltekit 0.0.97 → 0.0.99
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/dist/classes/svelte/image/ImageVariantsLoader.svelte.d.ts +9 -2
- package/dist/classes/svelte/image/ImageVariantsLoader.svelte.js +38 -31
- package/dist/components/image/EnhancedImage.svelte__ +162 -0
- package/dist/components/image/ImageBox.svelte +104 -145
- package/dist/components/image/ImageBox.svelte.d.ts +6 -49
- package/dist/components/image/ImageBox.svelte__ +242 -0
- package/dist/components/image/ImageBox.svelte___ +241 -0
- package/dist/components/image/ResponsiveImage.svelte +2 -14
- package/dist/components/image/ResponsiveImage.svelte__ +90 -0
- package/dist/components/image/index.d.ts +0 -1
- package/dist/components/image/index.js +0 -1
- package/dist/components/inputs/text-input/TextInput.svelte +2 -2
- package/dist/config/tailwind.extend.d.ts +7 -0
- package/dist/config/tailwind.extend.js +8 -0
- package/dist/constants/index.js +1 -1
- package/dist/constants/state-labels/submit-states.d.ts +4 -0
- package/dist/constants/state-labels/submit-states.js +4 -0
- package/dist/util/image/index.d.ts +16 -0
- package/dist/util/image/index.js +62 -0
- package/package.json +2 -2
- package/dist/constants/css-states/index.d.ts +0 -1
- package/dist/constants/css-states/index.js +0 -1
- /package/dist/constants/{css-states → state-labels}/input-states.d.ts +0 -0
- /package/dist/constants/{css-states → state-labels}/input-states.js +0 -0
@@ -0,0 +1,242 @@
|
|
1
|
+
<script>
|
2
|
+
import { onMount } from 'svelte';
|
3
|
+
|
4
|
+
import { ImageLoader } from '$lib/classes/svelte/image/index.js';
|
5
|
+
|
6
|
+
import { toSingleImageMeta } from '$lib/util/image/index.js';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* @example
|
10
|
+
* import { ImageBox } from '/path/to/ImageBox/index.js';
|
11
|
+
*
|
12
|
+
* // @note 'as=metadata' is set by the preset
|
13
|
+
* import NeonLightsOff from '$lib/img/NeonLightsOff.jpg?preset=gradient';
|
14
|
+
*
|
15
|
+
* <!-- Example that fits in an outer-box -->
|
16
|
+
*
|
17
|
+
* <div class="outer-box">
|
18
|
+
* <ImageBox image={ArmyGreen} fit="contain" position="center center" />
|
19
|
+
* </div>
|
20
|
+
*
|
21
|
+
* <!-- Examples that has have width, height or aspect set -->
|
22
|
+
*
|
23
|
+
* <ImageBox
|
24
|
+
* image={ArmyGreen}
|
25
|
+
* fit="contain"
|
26
|
+
* position="center center"
|
27
|
+
* width="w-[200px]"
|
28
|
+
* height="h-[200px]"
|
29
|
+
* classes="border-8 border-green-500"
|
30
|
+
* />
|
31
|
+
*
|
32
|
+
* <ImageBox
|
33
|
+
* image={ArmyGreen}
|
34
|
+
* fit="contain"
|
35
|
+
* position="center center"
|
36
|
+
* width="w-[200px]"
|
37
|
+
* aspect="aspect-square"
|
38
|
+
* classes="border-8 border-green-500"
|
39
|
+
* />
|
40
|
+
*
|
41
|
+
* <ImageBox
|
42
|
+
* image={ArmyGreen}
|
43
|
+
* fit="contain"
|
44
|
+
* position="center center"
|
45
|
+
* height="h-[200px]"
|
46
|
+
* aspect="aspect-square"
|
47
|
+
* classes="border-8 border-green-500"
|
48
|
+
* />
|
49
|
+
*
|
50
|
+
* <!-- Or hack it using !important -->
|
51
|
+
*
|
52
|
+
* <ImageBox
|
53
|
+
* image={ArmyGreen}
|
54
|
+
* fit="contain"
|
55
|
+
* position="center center"
|
56
|
+
* classes="!w-[200px] !h-[200px] border-8 border-green-500"
|
57
|
+
* />
|
58
|
+
*/
|
59
|
+
|
60
|
+
/**
|
61
|
+
* @typedef {import('./typedef.js').ObjectFit} ObjectFit
|
62
|
+
* @typedef {import('./typedef.js').ObjectPosition} ObjectPosition
|
63
|
+
*
|
64
|
+
* @typedef {import('$lib/classes/svelte/network-loader/typedef.js').LoadingProgress} LoadingProgress
|
65
|
+
*
|
66
|
+
* @typedef {import('$lib/config/typedef.js').ImageMeta} ImageMeta
|
67
|
+
*
|
68
|
+
* @typedef {Object} Props
|
69
|
+
* @property {string} [base] - Base styling class
|
70
|
+
* @property {string} [bg] - Background styling class
|
71
|
+
* @property {string} [classes] - Additional CSS classes
|
72
|
+
* @property {string} [width] - Width of the image container
|
73
|
+
* @property {string} [height] - Height of the image container
|
74
|
+
* @property {string} [aspect] - Aspect ratio of the image container
|
75
|
+
* @property {string} [overflow] - Overflow behavior
|
76
|
+
* @property {ObjectFit} [fit] - Object-fit property
|
77
|
+
* @property {ObjectPosition} [position] - Object-position property
|
78
|
+
*
|
79
|
+
* @property {ImageMeta|ImageMeta[]} [imageMeta]
|
80
|
+
* Image metadata, TODO: array of image metadata for responsive image
|
81
|
+
*
|
82
|
+
* @property {ImageLoader} [imageLoader]
|
83
|
+
* Image loader
|
84
|
+
*
|
85
|
+
* @property {string} [alt] - Alternative text for the image
|
86
|
+
* @property {() => LoadingProgress} [onProgress] - Progress callback function
|
87
|
+
* @property {*} [attr] - Additional arbitrary attributes
|
88
|
+
*/
|
89
|
+
|
90
|
+
/** @type {Props} */
|
91
|
+
let {
|
92
|
+
// Style
|
93
|
+
base,
|
94
|
+
bg,
|
95
|
+
classes,
|
96
|
+
width,
|
97
|
+
height,
|
98
|
+
aspect,
|
99
|
+
overflow = 'overflow-clip',
|
100
|
+
|
101
|
+
// Fitting and positioning of image in its container
|
102
|
+
fit = 'contain',
|
103
|
+
position = 'left top',
|
104
|
+
|
105
|
+
// Single image or responsive image meta data
|
106
|
+
imageMeta,
|
107
|
+
|
108
|
+
imageLoader,
|
109
|
+
|
110
|
+
alt = '',
|
111
|
+
|
112
|
+
// Attributes
|
113
|
+
...attrs
|
114
|
+
} = $props();
|
115
|
+
|
116
|
+
if (!imageMeta) {
|
117
|
+
throw new Error('Missing [imageMeta]');
|
118
|
+
}
|
119
|
+
|
120
|
+
// let show = $state(false);
|
121
|
+
|
122
|
+
/** @type {HTMLImageElement|undefined} */
|
123
|
+
let imgElem = $state();
|
124
|
+
|
125
|
+
let aspectStyle = $state('');
|
126
|
+
|
127
|
+
// > Loading
|
128
|
+
|
129
|
+
let metaWidth = $state(0);
|
130
|
+
let metaHeight = $state(0);
|
131
|
+
|
132
|
+
let imageMeta_ = $state();
|
133
|
+
|
134
|
+
$effect(() => {
|
135
|
+
//
|
136
|
+
// Is imageMeta is a list of responsive options: pick one
|
137
|
+
//
|
138
|
+
if (imageMeta) {
|
139
|
+
imageMeta_ = toSingleImageMeta(imageMeta);
|
140
|
+
}
|
141
|
+
});
|
142
|
+
|
143
|
+
$effect(() => {
|
144
|
+
//
|
145
|
+
// Set meta width and height
|
146
|
+
//
|
147
|
+
if (imageMeta_) {
|
148
|
+
if (imageMeta_.width) {
|
149
|
+
metaWidth = imageMeta_.width;
|
150
|
+
}
|
151
|
+
|
152
|
+
if (imageMeta_.height) {
|
153
|
+
metaHeight = imageMeta_.height;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
});
|
157
|
+
|
158
|
+
/** @type {ImageLoader|undefined} */
|
159
|
+
let imageLoader_ = $state();
|
160
|
+
|
161
|
+
$effect(() => {
|
162
|
+
//
|
163
|
+
// User supplied imageLoader instead of imageMeta
|
164
|
+
//
|
165
|
+
if (!imageMeta && imageLoader && !imageLoader_) {
|
166
|
+
imageLoader_ = imageLoader;
|
167
|
+
imageMeta_ = imageLoader.imageMeta;
|
168
|
+
}
|
169
|
+
});
|
170
|
+
|
171
|
+
/** @type {string|null} */
|
172
|
+
let objectUrl = $state(null);
|
173
|
+
|
174
|
+
$effect(() => {
|
175
|
+
//
|
176
|
+
// Create image loader
|
177
|
+
//
|
178
|
+
if (imageMeta_ && !imageLoader_) {
|
179
|
+
imageLoader_ = new ImageLoader({ imageMeta: imageMeta_ });
|
180
|
+
}
|
181
|
+
});
|
182
|
+
|
183
|
+
$effect(() => {
|
184
|
+
//
|
185
|
+
// Start loading if imageLoader_ is in state 'initial'
|
186
|
+
//
|
187
|
+
// TODO: implement lazy flag
|
188
|
+
//
|
189
|
+
if (imageLoader_?.initial) {
|
190
|
+
imageLoader_.load();
|
191
|
+
}
|
192
|
+
});
|
193
|
+
|
194
|
+
$effect(() => {
|
195
|
+
//
|
196
|
+
// Get objectUrl when the image has finished loading
|
197
|
+
//
|
198
|
+
if (imageLoader_.loaded) {
|
199
|
+
// @ts-ignore
|
200
|
+
objectUrl = imageLoader_.getObjectURL();
|
201
|
+
}
|
202
|
+
|
203
|
+
return () => {
|
204
|
+
if (objectUrl) {
|
205
|
+
URL.revokeObjectURL(objectUrl);
|
206
|
+
objectUrl = null;
|
207
|
+
}
|
208
|
+
};
|
209
|
+
});
|
210
|
+
</script>
|
211
|
+
|
212
|
+
<div
|
213
|
+
data-image="box"
|
214
|
+
class="{base} {bg} {aspect} {overflow} {width} {height} {classes}"
|
215
|
+
style:--fit={fit}
|
216
|
+
style:--pos={position}
|
217
|
+
style:aspect-ratio={aspectStyle}
|
218
|
+
style:width={width || (height && aspect) ? undefined : '100%'}
|
219
|
+
style:height={height || (width && aspect) ? undefined : '100%'}
|
220
|
+
{...attrs}
|
221
|
+
>
|
222
|
+
{#if objectUrl && metaWidth && metaHeight}
|
223
|
+
<img src={objectUrl} {alt} width={metaWidth} height={metaHeight} />
|
224
|
+
{/if}
|
225
|
+
</div>
|
226
|
+
|
227
|
+
<style>
|
228
|
+
[data-image='box'] {
|
229
|
+
max-width: 100%;
|
230
|
+
max-height: 100%;
|
231
|
+
}
|
232
|
+
|
233
|
+
img {
|
234
|
+
display: block;
|
235
|
+
width: 100%;
|
236
|
+
height: 100%;
|
237
|
+
max-width: 100%;
|
238
|
+
max-height: 100%;
|
239
|
+
object-fit: var(--fit);
|
240
|
+
object-position: var(--pos);
|
241
|
+
}
|
242
|
+
</style>
|
@@ -0,0 +1,241 @@
|
|
1
|
+
<script>
|
2
|
+
import { onMount } from 'svelte';
|
3
|
+
import { ImageLoader } from '$lib/classes/svelte/image/index.js';
|
4
|
+
import { ImageVariantsLoader } from '$lib/classes/svelte/image/index.js';
|
5
|
+
import { toSingleImageMeta } from '$lib/util/image/index.js';
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @type {{
|
9
|
+
* base?: string,
|
10
|
+
* bg?: string,
|
11
|
+
* classes?: string,
|
12
|
+
* width?: string,
|
13
|
+
* height?: string,
|
14
|
+
* aspect?: string,
|
15
|
+
* overflow?: string,
|
16
|
+
* fit?: 'contain' | 'cover' | 'fill',
|
17
|
+
* position?: string,
|
18
|
+
* imageMeta: import('$lib/config/typedef.js').ImageMeta | import('$lib/config/typedef.js').ImageMeta[],
|
19
|
+
* imageLoader?: import('$lib/classes/svelte/image/index.js').ImageLoader,
|
20
|
+
* alt?: string,
|
21
|
+
* onProgress?: () => import('$lib/classes/svelte/network-loader/typedef.js').LoadingProgress,
|
22
|
+
* debug?: boolean,
|
23
|
+
* [attr: string]: any
|
24
|
+
* }}
|
25
|
+
*/
|
26
|
+
let {
|
27
|
+
// Style
|
28
|
+
base,
|
29
|
+
bg,
|
30
|
+
classes,
|
31
|
+
width,
|
32
|
+
height,
|
33
|
+
aspect,
|
34
|
+
overflow = 'overflow-clip',
|
35
|
+
|
36
|
+
// Fitting and positioning of image in its container
|
37
|
+
fit = 'contain',
|
38
|
+
position = 'left top',
|
39
|
+
|
40
|
+
// Single image or responsive image meta data
|
41
|
+
imageMeta,
|
42
|
+
imageLoader,
|
43
|
+
|
44
|
+
// Accessibility
|
45
|
+
alt = '',
|
46
|
+
|
47
|
+
// Development
|
48
|
+
debug = false,
|
49
|
+
|
50
|
+
// Additional attributes
|
51
|
+
...attrs
|
52
|
+
} = $props();
|
53
|
+
|
54
|
+
if (!imageMeta) {
|
55
|
+
throw new Error('Missing [imageMeta]');
|
56
|
+
}
|
57
|
+
|
58
|
+
/** @type {HTMLDivElement|undefined} */
|
59
|
+
let containerElem = $state();
|
60
|
+
|
61
|
+
/** @type {HTMLImageElement|undefined} */
|
62
|
+
let imgElem = $state();
|
63
|
+
|
64
|
+
let aspectStyle = $state('');
|
65
|
+
|
66
|
+
// > Loading
|
67
|
+
let metaWidth = $state(0);
|
68
|
+
let metaHeight = $state(0);
|
69
|
+
|
70
|
+
let imageMeta_ = $state();
|
71
|
+
let variantsLoader = $state();
|
72
|
+
let variantObjectUrl = $state(null);
|
73
|
+
let objectUrl = $state(null);
|
74
|
+
|
75
|
+
$effect(() => {
|
76
|
+
//
|
77
|
+
// Is imageMeta is a list of responsive options:
|
78
|
+
// => setup variants loader
|
79
|
+
//
|
80
|
+
if (Array.isArray(imageMeta) && !imageLoader && !variantsLoader) {
|
81
|
+
// $inspect(imageMeta, 'Creating variantsLoader');
|
82
|
+
|
83
|
+
variantsLoader = new ImageVariantsLoader(imageMeta, {
|
84
|
+
devicePixelRatio: window.devicePixelRatio
|
85
|
+
});
|
86
|
+
}
|
87
|
+
//
|
88
|
+
// Single image meta (only if not using variants)
|
89
|
+
//
|
90
|
+
else if (imageMeta && !variantsLoader) {
|
91
|
+
// Only run if there is no variantsLoader
|
92
|
+
|
93
|
+
//$inspect(imageMeta, 'Using single imageMeta');
|
94
|
+
|
95
|
+
imageMeta_ = toSingleImageMeta(imageMeta);
|
96
|
+
}
|
97
|
+
});
|
98
|
+
|
99
|
+
$effect(() => {
|
100
|
+
//
|
101
|
+
// Set meta width and height for single image
|
102
|
+
//
|
103
|
+
if (imageMeta_) {
|
104
|
+
if (imageMeta_.width) {
|
105
|
+
metaWidth = imageMeta_.width;
|
106
|
+
}
|
107
|
+
|
108
|
+
if (imageMeta_.height) {
|
109
|
+
metaHeight = imageMeta_.height;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
});
|
113
|
+
|
114
|
+
/** @type {ImageLoader|undefined} */
|
115
|
+
let imageLoader_ = $state();
|
116
|
+
|
117
|
+
$effect(() => {
|
118
|
+
//
|
119
|
+
// User supplied imageLoader instead of imageMeta
|
120
|
+
//
|
121
|
+
if (!imageMeta && imageLoader && !imageLoader_) {
|
122
|
+
imageLoader_ = imageLoader;
|
123
|
+
imageMeta_ = imageLoader.imageMeta;
|
124
|
+
}
|
125
|
+
});
|
126
|
+
|
127
|
+
$effect(() => {
|
128
|
+
//
|
129
|
+
// Create image loader for single image
|
130
|
+
//
|
131
|
+
if (imageMeta_ && !imageLoader_) {
|
132
|
+
imageLoader_ = new ImageLoader({ imageMeta: imageMeta_ });
|
133
|
+
}
|
134
|
+
});
|
135
|
+
|
136
|
+
$effect(() => {
|
137
|
+
//
|
138
|
+
// Start loading if imageLoader_ is in state 'initial'
|
139
|
+
//
|
140
|
+
if (imageLoader_?.initial) {
|
141
|
+
imageLoader_.load();
|
142
|
+
}
|
143
|
+
});
|
144
|
+
|
145
|
+
$effect(() => {
|
146
|
+
//
|
147
|
+
// Get objectUrl when the single image has finished loading
|
148
|
+
//
|
149
|
+
if (imageLoader_?.loaded) {
|
150
|
+
objectUrl = imageLoader_.getObjectURL();
|
151
|
+
}
|
152
|
+
|
153
|
+
return () => {
|
154
|
+
if (objectUrl) {
|
155
|
+
URL.revokeObjectURL(objectUrl);
|
156
|
+
objectUrl = null;
|
157
|
+
}
|
158
|
+
};
|
159
|
+
});
|
160
|
+
|
161
|
+
$effect(() => {
|
162
|
+
//
|
163
|
+
// Setup resize observer for variants loading
|
164
|
+
//
|
165
|
+
if (!containerElem || !variantsLoader) return;
|
166
|
+
|
167
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
168
|
+
for (const entry of entries) {
|
169
|
+
const { width, height } = entry.contentRect;
|
170
|
+
|
171
|
+
variantsLoader.updateOptimalImageMeta({
|
172
|
+
containerWidth: width,
|
173
|
+
containerHeight: height,
|
174
|
+
fit
|
175
|
+
});
|
176
|
+
}
|
177
|
+
});
|
178
|
+
|
179
|
+
resizeObserver.observe(containerElem);
|
180
|
+
|
181
|
+
return () => {
|
182
|
+
resizeObserver.disconnect();
|
183
|
+
};
|
184
|
+
});
|
185
|
+
|
186
|
+
$effect(() => {
|
187
|
+
//
|
188
|
+
// Get variantObjectUrl when a variant has finished loading
|
189
|
+
//
|
190
|
+
if (variantsLoader?.loaded) {
|
191
|
+
variantObjectUrl = variantsLoader.getObjectURL();
|
192
|
+
}
|
193
|
+
|
194
|
+
return () => {
|
195
|
+
if (variantObjectUrl) {
|
196
|
+
URL.revokeObjectURL(variantObjectUrl);
|
197
|
+
variantObjectUrl = null;
|
198
|
+
}
|
199
|
+
};
|
200
|
+
});
|
201
|
+
</script>
|
202
|
+
|
203
|
+
<div
|
204
|
+
data-image="box"
|
205
|
+
bind:this={containerElem}
|
206
|
+
class="{base} {bg} {aspect} {overflow} {width} {height} {classes}"
|
207
|
+
style:--fit={fit}
|
208
|
+
style:--pos={position}
|
209
|
+
style:aspect-ratio={aspectStyle}
|
210
|
+
style:width={width || (height && aspect) ? undefined : '100%'}
|
211
|
+
style:height={height || (width && aspect) ? undefined : '100%'}
|
212
|
+
{...attrs}
|
213
|
+
>
|
214
|
+
{#if variantsLoader?.loaded && variantObjectUrl}
|
215
|
+
<img
|
216
|
+
src={variantObjectUrl}
|
217
|
+
{alt}
|
218
|
+
width={variantsLoader.variant.width}
|
219
|
+
height={variantsLoader.variant.height}
|
220
|
+
/>
|
221
|
+
{:else if objectUrl && metaWidth && metaHeight}
|
222
|
+
<img src={objectUrl} {alt} width={metaWidth} height={metaHeight} />
|
223
|
+
{/if}
|
224
|
+
</div>
|
225
|
+
|
226
|
+
<style>
|
227
|
+
[data-image='box'] {
|
228
|
+
max-width: 100%;
|
229
|
+
max-height: 100%;
|
230
|
+
}
|
231
|
+
|
232
|
+
img {
|
233
|
+
display: block;
|
234
|
+
width: 100%;
|
235
|
+
height: 100%;
|
236
|
+
max-width: 100%;
|
237
|
+
max-height: 100%;
|
238
|
+
object-fit: var(--fit);
|
239
|
+
object-position: var(--pos);
|
240
|
+
}
|
241
|
+
</style>
|
@@ -37,7 +37,7 @@
|
|
37
37
|
let imageVariant = $state(null);
|
38
38
|
|
39
39
|
$effect(() => {
|
40
|
-
variantsLoader.updateOptimalImageMeta(containerWidth);
|
40
|
+
variantsLoader.updateOptimalImageMeta({ containerWidth });
|
41
41
|
});
|
42
42
|
|
43
43
|
// $effect(() => {
|
@@ -53,22 +53,9 @@
|
|
53
53
|
if (variantsLoader.loaded) {
|
54
54
|
// @ts-ignore
|
55
55
|
imageUrl = variantsLoader.getObjectURL();
|
56
|
-
|
57
|
-
// image = new Image();
|
58
|
-
// image.src = url;
|
59
|
-
|
60
|
-
// image.onload = () => {
|
61
|
-
// console.log('loaded');
|
62
|
-
// imageUrl = url;
|
63
|
-
// };
|
64
56
|
}
|
65
57
|
|
66
58
|
return () => {
|
67
|
-
// if (image) {
|
68
|
-
// image.onload = null;
|
69
|
-
// image = undefined;
|
70
|
-
// }
|
71
|
-
|
72
59
|
if (imageUrl) {
|
73
60
|
URL.revokeObjectURL(imageUrl);
|
74
61
|
imageUrl = null;
|
@@ -81,6 +68,7 @@
|
|
81
68
|
// let image = $derived(variantsLoader.image);
|
82
69
|
</script>
|
83
70
|
|
71
|
+
™
|
84
72
|
<div
|
85
73
|
bind:clientWidth={containerWidth}
|
86
74
|
class="{boxBase} {boxClasses}"
|
@@ -0,0 +1,90 @@
|
|
1
|
+
<script>
|
2
|
+
/** @typedef {import('$lib/config/typedef.js').ImageMeta} ImageMeta */
|
3
|
+
|
4
|
+
import { ImageVariantsLoader } from '$lib/classes/svelte/image/index.js';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @type {{
|
8
|
+
* base?: string,
|
9
|
+
* classes?: string
|
10
|
+
* boxBase?: string,
|
11
|
+
* boxClasses?: string
|
12
|
+
* boxAttrs?: { [attr: string]: * },
|
13
|
+
* images: ImageMeta[],
|
14
|
+
* alt?: string
|
15
|
+
* } & { [attr: string]: * }}
|
16
|
+
*/
|
17
|
+
const {
|
18
|
+
base,
|
19
|
+
classes,
|
20
|
+
boxBase,
|
21
|
+
boxClasses,
|
22
|
+
boxAttrs,
|
23
|
+
|
24
|
+
// Functional
|
25
|
+
images,
|
26
|
+
alt = '',
|
27
|
+
|
28
|
+
// Attributes
|
29
|
+
...attrs
|
30
|
+
} = $props();
|
31
|
+
|
32
|
+
let variantsLoader = new ImageVariantsLoader(images);
|
33
|
+
|
34
|
+
let containerWidth = $state(0);
|
35
|
+
|
36
|
+
/** @type {ImageMeta|null} */
|
37
|
+
let imageVariant = $state(null);
|
38
|
+
|
39
|
+
$effect(() => {
|
40
|
+
variantsLoader.updateOptimalImageMeta({ containerWidth });
|
41
|
+
});
|
42
|
+
|
43
|
+
// $effect(() => {
|
44
|
+
// console.log('imageVariant', $state.snapshot(imageVariant));
|
45
|
+
// });
|
46
|
+
|
47
|
+
/** @type {string|null} */
|
48
|
+
let imageUrl = $state(null);
|
49
|
+
|
50
|
+
$effect(() => {
|
51
|
+
let image;
|
52
|
+
|
53
|
+
if (variantsLoader.loaded) {
|
54
|
+
// @ts-ignore
|
55
|
+
imageUrl = variantsLoader.getObjectURL();
|
56
|
+
}
|
57
|
+
|
58
|
+
return () => {
|
59
|
+
if (imageUrl) {
|
60
|
+
URL.revokeObjectURL(imageUrl);
|
61
|
+
imageUrl = null;
|
62
|
+
}
|
63
|
+
};
|
64
|
+
});
|
65
|
+
|
66
|
+
let variant = $derived(variantsLoader.variant);
|
67
|
+
|
68
|
+
// let image = $derived(variantsLoader.image);
|
69
|
+
</script>
|
70
|
+
|
71
|
+
™
|
72
|
+
<div
|
73
|
+
bind:clientWidth={containerWidth}
|
74
|
+
class="{boxBase} {boxClasses}"
|
75
|
+
{...boxAttrs}
|
76
|
+
>
|
77
|
+
<!-- <p class="p text-white">variant: {JSON.stringify(variant)}</p> -->
|
78
|
+
|
79
|
+
{#if variant}
|
80
|
+
<img
|
81
|
+
data-image="responsive"
|
82
|
+
src={imageUrl ? imageUrl : ''}
|
83
|
+
width={variant.width}
|
84
|
+
height={variant.height}
|
85
|
+
{alt}
|
86
|
+
class="{boxBase} {boxClasses}"
|
87
|
+
{...attrs}
|
88
|
+
/>
|
89
|
+
{/if}
|
90
|
+
</div>
|
@@ -15,7 +15,7 @@
|
|
15
15
|
INVALID,
|
16
16
|
REQUIRED,
|
17
17
|
DISABLED
|
18
|
-
} from '../../../constants/
|
18
|
+
} from '../../../constants/state-labels/input-states.js';
|
19
19
|
|
20
20
|
/**
|
21
21
|
* @type {{
|
@@ -136,7 +136,7 @@
|
|
136
136
|
//
|
137
137
|
// Return CSS classes that indicate the component's state
|
138
138
|
//
|
139
|
-
// @see $lib/constants/
|
139
|
+
// @see $lib/constants/state-labels
|
140
140
|
//
|
141
141
|
const outArr = [];
|
142
142
|
|
package/dist/constants/index.js
CHANGED
@@ -7,3 +7,19 @@
|
|
7
7
|
* @param {ImageMeta|ImageMeta[]} imageMeta
|
8
8
|
*/
|
9
9
|
export function toSingleImageMeta(imageMeta: ImageMeta | ImageMeta[]): import("../../config/typedef").ImageMeta;
|
10
|
+
/**
|
11
|
+
* Calculate effective width based on container dimensions and fit mode
|
12
|
+
*
|
13
|
+
* @param {object} params
|
14
|
+
* @param {number} [params.containerWidth] Container width in pixels
|
15
|
+
* @param {number} [params.containerHeight] Container height in pixels
|
16
|
+
* @param {number} params.imageAspectRatio Original image aspect ratio (width/height)
|
17
|
+
* @param {'cover'|'contain'|'fill'} [params.fit='contain'] Fit mode
|
18
|
+
* @returns {number} Effective width needed
|
19
|
+
*/
|
20
|
+
export function calculateEffectiveWidth({ containerWidth, containerHeight, imageAspectRatio, fit }: {
|
21
|
+
containerWidth?: number;
|
22
|
+
containerHeight?: number;
|
23
|
+
imageAspectRatio: number;
|
24
|
+
fit?: "cover" | "contain" | "fill";
|
25
|
+
}): number;
|