@karbonjs/ui-svelte 0.2.1 → 0.2.3
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/package.json +2 -2
- package/src/overlay/ImgBox.svelte +44 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karbonjs/ui-svelte",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Karbon UI components for Svelte 5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"svelte": "src/index.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"src"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@karbonjs/ui-core": "0.2.
|
|
18
|
+
"@karbonjs/ui-core": "0.2.3"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"svelte": "^5.0.0"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
images,
|
|
16
16
|
index = $bindable(0),
|
|
17
17
|
open = $bindable(false),
|
|
18
|
-
backdrop = '
|
|
18
|
+
backdrop = 'blur',
|
|
19
19
|
captions = [],
|
|
20
20
|
class: className = '',
|
|
21
21
|
onclose
|
|
@@ -25,13 +25,14 @@
|
|
|
25
25
|
let translateX = $state(0)
|
|
26
26
|
let translateY = $state(0)
|
|
27
27
|
let dragging = $state(false)
|
|
28
|
+
let visible = $state(false)
|
|
28
29
|
let startX = 0
|
|
29
30
|
let startY = 0
|
|
30
31
|
|
|
31
32
|
const backdropClasses: Record<string, string> = {
|
|
32
|
-
blur: 'bg-black/
|
|
33
|
+
blur: 'bg-black/70 backdrop-blur-xl',
|
|
33
34
|
dark: 'bg-black/90',
|
|
34
|
-
transparent: 'bg-
|
|
35
|
+
transparent: 'bg-black/40 backdrop-blur-sm',
|
|
35
36
|
none: ''
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -39,6 +40,20 @@
|
|
|
39
40
|
const hasNext = $derived(index < images.length - 1)
|
|
40
41
|
const caption = $derived(captions[index] ?? '')
|
|
41
42
|
|
|
43
|
+
// Animate in
|
|
44
|
+
$effect(() => {
|
|
45
|
+
if (open) {
|
|
46
|
+
requestAnimationFrame(() => { visible = true })
|
|
47
|
+
} else {
|
|
48
|
+
visible = false
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
function close() {
|
|
53
|
+
visible = false
|
|
54
|
+
setTimeout(() => onclose(), 200)
|
|
55
|
+
}
|
|
56
|
+
|
|
42
57
|
function prev() {
|
|
43
58
|
if (hasPrev) { index--; resetTransform() }
|
|
44
59
|
}
|
|
@@ -64,7 +79,7 @@
|
|
|
64
79
|
|
|
65
80
|
function handleKeydown(e: KeyboardEvent) {
|
|
66
81
|
if (!open) return
|
|
67
|
-
if (e.key === 'Escape')
|
|
82
|
+
if (e.key === 'Escape') close()
|
|
68
83
|
if (e.key === 'ArrowLeft') prev()
|
|
69
84
|
if (e.key === 'ArrowRight') next()
|
|
70
85
|
if (e.key === '+' || e.key === '=') zoomIn()
|
|
@@ -99,24 +114,30 @@
|
|
|
99
114
|
|
|
100
115
|
{#if open && images.length > 0}
|
|
101
116
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
102
|
-
<div
|
|
117
|
+
<div
|
|
118
|
+
class="fixed inset-0 z-[99999] flex items-center justify-center transition-opacity duration-200 {backdropClasses[backdrop]} {className}"
|
|
119
|
+
style="opacity: {visible ? 1 : 0}"
|
|
120
|
+
>
|
|
103
121
|
<!-- Close button -->
|
|
104
122
|
<button
|
|
105
|
-
onclick={
|
|
123
|
+
onclick={close}
|
|
106
124
|
aria-label="Fermer"
|
|
107
|
-
class="absolute top-4 right-4 z-10 rounded-full p-2 text-white/
|
|
125
|
+
class="absolute top-4 right-4 z-10 rounded-full p-2.5 text-white/70 hover:text-white bg-black/30 hover:bg-black/50 transition-all cursor-pointer"
|
|
108
126
|
>
|
|
109
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
127
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
110
128
|
</button>
|
|
111
129
|
|
|
112
130
|
<!-- Zoom controls -->
|
|
113
|
-
<div class="absolute top-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-
|
|
131
|
+
<div class="absolute top-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-1 bg-black/40 rounded-full px-3 py-1.5 transition-opacity duration-300" style="opacity: {visible ? 1 : 0}">
|
|
114
132
|
<button onclick={zoomOut} aria-label="Dézoomer" class="text-white/60 hover:text-white transition-colors cursor-pointer p-1">
|
|
115
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
133
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" x2="16.65" y1="21" y2="16.65"/><line x1="8" x2="14" y1="11" y2="11"/></svg>
|
|
116
134
|
</button>
|
|
117
135
|
<span class="text-white/80 text-xs font-medium min-w-[3rem] text-center">{Math.round(scale * 100)}%</span>
|
|
118
136
|
<button onclick={zoomIn} aria-label="Zoomer" class="text-white/60 hover:text-white transition-colors cursor-pointer p-1">
|
|
119
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
137
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" x2="16.65" y1="21" y2="16.65"/><line x1="11" x2="11" y1="8" y2="14"/><line x1="8" x2="14" y1="11" y2="11"/></svg>
|
|
138
|
+
</button>
|
|
139
|
+
<button onclick={resetTransform} aria-label="Réinitialiser" class="text-white/60 hover:text-white transition-colors cursor-pointer p-1 ml-1 border-l border-white/20 pl-2">
|
|
140
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
|
120
141
|
</button>
|
|
121
142
|
</div>
|
|
122
143
|
|
|
@@ -125,9 +146,9 @@
|
|
|
125
146
|
<button
|
|
126
147
|
onclick={prev}
|
|
127
148
|
aria-label="Image précédente"
|
|
128
|
-
class="absolute left-4 z-10 rounded-full p-
|
|
149
|
+
class="absolute left-4 z-10 rounded-full p-3 text-white/60 hover:text-white bg-black/20 hover:bg-black/50 transition-all cursor-pointer"
|
|
129
150
|
>
|
|
130
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
151
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
131
152
|
</button>
|
|
132
153
|
{/if}
|
|
133
154
|
|
|
@@ -136,38 +157,33 @@
|
|
|
136
157
|
<button
|
|
137
158
|
onclick={next}
|
|
138
159
|
aria-label="Image suivante"
|
|
139
|
-
class="absolute right-4 z-10 rounded-full p-
|
|
160
|
+
class="absolute right-4 z-10 rounded-full p-3 text-white/60 hover:text-white bg-black/20 hover:bg-black/50 transition-all cursor-pointer"
|
|
140
161
|
>
|
|
141
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
162
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
142
163
|
</button>
|
|
143
164
|
{/if}
|
|
144
165
|
|
|
145
166
|
<!-- Image -->
|
|
146
167
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
147
168
|
<div
|
|
148
|
-
class="flex items-center justify-center w-full h-full p-
|
|
149
|
-
onclick={(e) => { if (e.target === e.currentTarget && scale <= 1)
|
|
169
|
+
class="flex items-center justify-center w-full h-full p-12 {scale > 1 ? 'cursor-grab' : ''} {dragging ? 'cursor-grabbing' : ''}"
|
|
170
|
+
onclick={(e) => { if (e.target === e.currentTarget && scale <= 1) close() }}
|
|
150
171
|
onmousedown={handleMouseDown}
|
|
151
172
|
onwheel={handleWheel}
|
|
152
173
|
>
|
|
153
174
|
<img
|
|
154
175
|
src={images[index]}
|
|
155
176
|
alt={caption || `Image ${index + 1}`}
|
|
156
|
-
class="max-w-full max-h-full object-contain select-none transition-
|
|
157
|
-
style="transform: scale({scale}) translate({translateX / scale}px, {translateY / scale}px)"
|
|
177
|
+
class="max-w-full max-h-full object-contain select-none transition-all duration-200"
|
|
178
|
+
style="transform: scale({visible ? scale : 0.9}) translate({translateX / scale}px, {translateY / scale}px); opacity: {visible ? 1 : 0}"
|
|
158
179
|
draggable="false"
|
|
159
180
|
/>
|
|
160
181
|
</div>
|
|
161
182
|
|
|
162
|
-
<!--
|
|
163
|
-
{#if
|
|
164
|
-
<div class="absolute bottom-4 left-1/2 -translate-x-1/2 z-10
|
|
165
|
-
{
|
|
166
|
-
<p class="text-white/80 text-sm mb-1">{caption}</p>
|
|
167
|
-
{/if}
|
|
168
|
-
{#if images.length > 1}
|
|
169
|
-
<span class="text-white/40 text-xs">{index + 1} / {images.length}</span>
|
|
170
|
-
{/if}
|
|
183
|
+
<!-- Counter only (no caption on image) -->
|
|
184
|
+
{#if images.length > 1}
|
|
185
|
+
<div class="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-black/40 rounded-full px-3 py-1">
|
|
186
|
+
<span class="text-white/60 text-xs">{index + 1} / {images.length}</span>
|
|
171
187
|
</div>
|
|
172
188
|
{/if}
|
|
173
189
|
</div>
|