ketekny-ui-kit 1.0.46 → 1.0.48

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,7 +1,7 @@
1
1
  {
2
2
  "name": "ketekny-ui-kit",
3
3
  "type": "module",
4
- "version": "1.0.46",
4
+ "version": "1.0.48",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -89,13 +89,34 @@
89
89
  </button>
90
90
  </div>
91
91
  </div>
92
+
93
+ <div
94
+ v-if="showDismissProgress"
95
+ :class="['mt-1 flex items-center justify-end gap-1 text-[10px] font-medium leading-none', colors.label]"
96
+ aria-hidden="true"
97
+ >
98
+ <Clock3 class="h-2.5 w-2.5" />
99
+ <span>{{ dismissSecondsLeft }}s</span>
100
+ </div>
101
+
102
+ <div
103
+ v-if="showDismissProgress"
104
+ :class="['pointer-events-none absolute inset-x-0 bottom-0 h-1', progressTracks[type]]"
105
+ aria-hidden="true"
106
+ />
107
+ <div
108
+ v-if="showDismissProgress"
109
+ :class="['pointer-events-none absolute bottom-0 left-0 h-1', progressBars[type]]"
110
+ :style="{ width: `${dismissElapsedPercent}%` }"
111
+ aria-hidden="true"
112
+ />
92
113
  </div>
93
114
  </Transition>
94
115
  </template>
95
116
 
96
117
  <script setup>
97
118
  import { computed, onBeforeUnmount, ref, useSlots, watch } from 'vue'
98
- import { X as CloseIcon, Info, CircleCheckBig, TriangleAlert, OctagonX } from 'lucide-vue-next'
119
+ import { X as CloseIcon, Info, CircleCheckBig, TriangleAlert, OctagonX, Clock3 } from 'lucide-vue-next'
99
120
 
100
121
  // ─── Color config ────────────────────────────────────────────────────────────
101
122
 
@@ -109,7 +130,7 @@ const colorConfig = {
109
130
  label: 'text-slate-500 dark:text-slate-300',
110
131
  },
111
132
  standard: {
112
- container: 'border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900/90',
133
+ container: 'border-sky-200/90 bg-sky-50/60 dark:border-sky-500/35 dark:bg-sky-950/35',
113
134
  icon: 'bg-sky-100 border-sky-300 text-sky-700 dark:bg-sky-500/15 dark:border-sky-400/40 dark:text-sky-300',
114
135
  title: 'text-sky-700 dark:text-sky-300',
115
136
  body: 'text-slate-700 dark:text-slate-200',
@@ -139,7 +160,7 @@ const colorConfig = {
139
160
  label: 'text-slate-500 dark:text-slate-300',
140
161
  },
141
162
  standard: {
142
- container: 'border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900/90',
163
+ container: 'border-emerald-200/90 bg-emerald-50/60 dark:border-emerald-500/35 dark:bg-emerald-950/35',
143
164
  icon: 'bg-emerald-100 border-emerald-300 text-emerald-700 dark:bg-emerald-500/15 dark:border-emerald-400/40 dark:text-emerald-300',
144
165
  title: 'text-emerald-700 dark:text-emerald-300',
145
166
  body: 'text-slate-700 dark:text-slate-200',
@@ -169,7 +190,7 @@ const colorConfig = {
169
190
  label: 'text-slate-500 dark:text-slate-300',
170
191
  },
171
192
  standard: {
172
- container: 'border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900/90',
193
+ container: 'border-amber-200/90 bg-amber-50/60 dark:border-amber-500/35 dark:bg-amber-950/35',
173
194
  icon: 'bg-amber-100 border-amber-300 text-amber-700 dark:bg-amber-500/15 dark:border-amber-400/40 dark:text-amber-300',
174
195
  title: 'text-amber-700 dark:text-amber-300',
175
196
  body: 'text-slate-700 dark:text-slate-200',
@@ -199,7 +220,7 @@ const colorConfig = {
199
220
  label: 'text-slate-500 dark:text-slate-300',
200
221
  },
201
222
  standard: {
202
- container: 'border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900/90',
223
+ container: 'border-rose-200/90 bg-rose-50/60 dark:border-rose-500/35 dark:bg-rose-950/35',
203
224
  icon: 'bg-rose-100 border-rose-300 text-rose-700 dark:bg-rose-500/15 dark:border-rose-400/40 dark:text-rose-300',
204
225
  title: 'text-rose-700 dark:text-rose-300',
205
226
  body: 'text-slate-700 dark:text-slate-200',
@@ -298,7 +319,9 @@ const slots = useSlots()
298
319
  const internalVisible = ref(true)
299
320
  const messageRef = ref(null)
300
321
  const dismissTimer = ref(null)
322
+ const dismissRaf = ref(null)
301
323
  const dismissStartedAt = ref(0)
324
+ const dismissRemainingAtStart = ref(0)
302
325
  const dismissRemaining = ref(0)
303
326
 
304
327
  const isVisible = computed(() => (props.visible !== null ? props.visible : internalVisible.value))
@@ -312,12 +335,53 @@ const dismissAfterMs = computed(() => {
312
335
  const value = Number(props.dismissAfter)
313
336
  return Number.isFinite(value) && value > 0 ? value : 0
314
337
  })
338
+ const showDismissProgress = computed(() => isVisible.value && dismissAfterMs.value > 0)
339
+ const dismissElapsedPercent = computed(() => {
340
+ if (dismissAfterMs.value <= 0) return 0
341
+ return Math.min(100, Math.max(0, ((dismissAfterMs.value - dismissRemaining.value) / dismissAfterMs.value) * 100))
342
+ })
343
+ const dismissSecondsLeft = computed(() => Math.max(0, Math.ceil(dismissRemaining.value / 1000)))
344
+
345
+ const progressTracks = {
346
+ info: 'bg-sky-200/60 dark:bg-sky-900/55',
347
+ success: 'bg-emerald-200/60 dark:bg-emerald-900/55',
348
+ warning: 'bg-amber-200/60 dark:bg-amber-900/55',
349
+ error: 'bg-rose-200/60 dark:bg-rose-900/55',
350
+ }
351
+
352
+ const progressBars = {
353
+ info: 'bg-sky-500/70 dark:bg-sky-400/80',
354
+ success: 'bg-emerald-500/70 dark:bg-emerald-400/80',
355
+ warning: 'bg-amber-500/80 dark:bg-amber-400/85',
356
+ error: 'bg-rose-500/70 dark:bg-rose-400/80',
357
+ }
358
+
359
+ function stopDismissRaf() {
360
+ if (dismissRaf.value) {
361
+ cancelAnimationFrame(dismissRaf.value)
362
+ dismissRaf.value = null
363
+ }
364
+ }
365
+
366
+ function syncDismissRemaining() {
367
+ if (!dismissTimer.value) return
368
+
369
+ const elapsed = Date.now() - dismissStartedAt.value
370
+ dismissRemaining.value = Math.max(0, dismissRemainingAtStart.value - elapsed)
371
+
372
+ if (dismissRemaining.value > 0) {
373
+ dismissRaf.value = requestAnimationFrame(syncDismissRemaining)
374
+ } else {
375
+ dismissRaf.value = null
376
+ }
377
+ }
315
378
 
316
379
  function clearDismissTimer() {
317
380
  if (dismissTimer.value) {
318
381
  clearTimeout(dismissTimer.value)
319
382
  dismissTimer.value = null
320
383
  }
384
+ stopDismissRaf()
321
385
  }
322
386
 
323
387
  function startDismissTimer(duration) {
@@ -325,9 +389,12 @@ function startDismissTimer(duration) {
325
389
  if (!isVisible.value || duration <= 0) return
326
390
 
327
391
  dismissRemaining.value = duration
392
+ dismissRemainingAtStart.value = duration
328
393
  dismissStartedAt.value = Date.now()
394
+ dismissRaf.value = requestAnimationFrame(syncDismissRemaining)
329
395
  dismissTimer.value = setTimeout(() => {
330
396
  dismissTimer.value = null
397
+ stopDismissRaf()
331
398
  dismissRemaining.value = 0
332
399
  close()
333
400
  }, duration)
@@ -337,7 +404,7 @@ function pauseDismissTimer() {
337
404
  if (!dismissTimer.value || dismissAfterMs.value <= 0) return
338
405
 
339
406
  const elapsed = Date.now() - dismissStartedAt.value
340
- dismissRemaining.value = Math.max(0, dismissRemaining.value - elapsed)
407
+ dismissRemaining.value = Math.max(0, dismissRemainingAtStart.value - elapsed)
341
408
  clearDismissTimer()
342
409
  }
343
410