@karbonjs/ui-svelte 0.2.2 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karbonjs/ui-svelte",
3
- "version": "0.2.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.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 = 'dark',
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/80 backdrop-blur-md',
33
+ blur: 'bg-black/70 backdrop-blur-xl',
33
34
  dark: 'bg-black/90',
34
- transparent: 'bg-transparent',
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') onclose()
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 class="fixed inset-0 z-[70] flex items-center justify-center {backdropClasses[backdrop]} {className}">
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={onclose}
123
+ onclick={close}
106
124
  aria-label="Fermer"
107
- class="absolute top-4 right-4 z-10 rounded-full p-2 text-white/60 hover:text-white hover:bg-white/10 transition-colors cursor-pointer"
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="24" height="24" 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>
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-2 bg-black/40 rounded-full px-3 py-1.5">
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="18" height="18" 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>
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="18" height="18" 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>
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-2 text-white/60 hover:text-white hover:bg-white/10 transition-colors cursor-pointer"
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="28" height="28" 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>
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-2 text-white/60 hover:text-white hover:bg-white/10 transition-colors cursor-pointer"
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="28" height="28" 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>
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-16 {scale > 1 ? 'cursor-grab' : ''} {dragging ? 'cursor-grabbing' : ''}"
149
- onclick={(e) => { if (e.target === e.currentTarget && scale <= 1) onclose() }}
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-transform duration-150"
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
- <!-- Caption + counter -->
163
- {#if caption || images.length > 1}
164
- <div class="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 text-center">
165
- {#if caption}
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>