srcdev-nuxt-components 6.1.40 → 6.1.42

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.
@@ -75,7 +75,7 @@ const props = defineProps({
75
75
 
76
76
  const slots = useSlots()
77
77
  const promptElementRef = useTemplateRef<HTMLElement>("promptElementRef")
78
- const parentComponentState = defineModel<boolean>("parentComponentState", { default: false })
78
+ const parentComponentState = defineModel<boolean>({ default: false })
79
79
  const compopnentOpen = ref(true)
80
80
  const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
81
81
 
@@ -49,11 +49,14 @@
49
49
  * v-model="showToast"
50
50
  * :config="{
51
51
  * appearance: { theme: 'success', position: 'top', alignment: 'right' },
52
- * behavior: { autoDismiss: true, duration: 3000 },
52
+ * behavior: { autoDismiss: true, duration: 3000, returnFocusTo: buttonRef },
53
53
  * content: { text: 'Operation completed successfully!' }
54
54
  * }"
55
55
  * />
56
56
  *
57
+ * The returnFocusTo property accepts an HTMLElement or ComponentPublicInstance
58
+ * and will focus that element when the toast is dismissed for better accessibility.
59
+ *
57
60
  * Types exported for use in other components:
58
61
  * - DisplayToastConfig
59
62
  * - DisplayToastProps
@@ -88,6 +91,7 @@ export interface DisplayToastBehaviorConfig {
88
91
  autoDismiss?: boolean
89
92
  duration?: number
90
93
  revealDuration?: number
94
+ returnFocusTo?: HTMLElement | ComponentPublicInstance | null
91
95
  }
92
96
 
93
97
  export interface DisplayToastContentConfig {
@@ -157,6 +161,7 @@ const fullWidth = computed(() => props.config?.appearance?.fullWidth ?? false)
157
161
  const autoDismiss = computed(() => props.config?.behavior?.autoDismiss ?? true)
158
162
  const duration = computed(() => props.config?.behavior?.duration ?? 5000)
159
163
  const revealDuration = computed(() => props.config?.behavior?.revealDuration ?? 550)
164
+ const returnFocusTo = computed(() => props.config?.behavior?.returnFocusTo ?? null)
160
165
  const toastDisplayText = computed(() => props.config?.content?.text ?? "")
161
166
  const customIcon = computed(() => props.config?.content?.customIcon)
162
167
 
@@ -209,6 +214,23 @@ const displayDurationMs = computed(() => duration.value + "ms")
209
214
  const setDismissToast = async () => {
210
215
  transitionalState.value = false
211
216
  await useSleep(revealDuration.value)
217
+
218
+ // Return focus to specified element if provided
219
+ if (returnFocusTo.value) {
220
+ // Handle both HTMLElement and ComponentPublicInstance
221
+ let focusTarget: HTMLElement | null = null
222
+
223
+ if (returnFocusTo.value instanceof HTMLElement) {
224
+ focusTarget = returnFocusTo.value
225
+ } else if (returnFocusTo.value && "$el" in returnFocusTo.value) {
226
+ focusTarget = returnFocusTo.value.$el as HTMLElement
227
+ }
228
+
229
+ if (focusTarget && typeof focusTarget.focus === "function") {
230
+ focusTarget.focus()
231
+ }
232
+ }
233
+
212
234
  externalTriggerModel.value = false
213
235
  privateDisplayToast.value = false
214
236
  }
@@ -240,9 +262,16 @@ watch(
240
262
  await useSleep(duration.value)
241
263
  setDismissToast()
242
264
  }
265
+ } else if (!newValue && previousValue) {
266
+ // If external model is set to false, dismiss the toast
267
+ setDismissToast()
243
268
  }
244
269
  }
245
270
  )
271
+
272
+ onBeforeRouteLeave(() => {
273
+ setDismissToast()
274
+ })
246
275
  </script>
247
276
 
248
277
  <style lang="css">
@@ -253,7 +282,7 @@ watch(
253
282
  }
254
283
  }
255
284
 
256
- @keyframes hide {
285
+ @keyframes hideTop {
257
286
  0% {
258
287
  opacity: 1;
259
288
  transform: translateY(0);
@@ -264,6 +293,17 @@ watch(
264
293
  }
265
294
  }
266
295
 
296
+ @keyframes hideBottom {
297
+ 0% {
298
+ opacity: 1;
299
+ transform: translateY(0);
300
+ }
301
+ 100% {
302
+ opacity: 0;
303
+ transform: translateY(30px);
304
+ }
305
+ }
306
+
267
307
  @keyframes progress {
268
308
  to {
269
309
  transform: scaleX(1);
@@ -306,18 +346,27 @@ watch(
306
346
 
307
347
  &.hide {
308
348
  @supports (animation-timing-function: linear(0, 1)) {
309
- animation: hide v-bind(revealDurationMs) var(--spring-easing) forwards;
349
+ animation: hideTop v-bind(revealDurationMs) var(--spring-easing) forwards;
310
350
  }
311
351
 
312
352
  @supports not (animation-timing-function: linear(0, 1)) {
313
- animation: hide calc(v-bind(revealDurationMs) / 2) linear forwards;
353
+ animation: hideTop calc(v-bind(revealDurationMs) / 2) linear forwards;
354
+ }
355
+
356
+ &.bottom {
357
+ @supports (animation-timing-function: linear(0, 1)) {
358
+ animation: hideBottom v-bind(revealDurationMs) var(--spring-easing) forwards;
359
+ }
360
+
361
+ @supports not (animation-timing-function: linear(0, 1)) {
362
+ animation: hideBottom calc(v-bind(revealDurationMs) / 2) linear forwards;
363
+ }
314
364
  }
315
365
  }
316
366
 
317
367
  /*
318
368
  * Default is centre for smaller screens
319
369
  */
320
-
321
370
  inset-inline: var(--_toast-gutter);
322
371
  margin-inline: auto;
323
372
 
@@ -447,9 +496,8 @@ watch(
447
496
 
448
497
  .display-toast-progress {
449
498
  position: absolute;
450
- right: 8px;
451
- bottom: 4px;
452
- width: calc(100% - 16px);
499
+ inset-block-end: 4px;
500
+ inset-inline: 15px 8px;
453
501
  height: 3px;
454
502
  transform: scaleX(0);
455
503
  transform-origin: right;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "6.1.40",
4
+ "version": "6.1.42",
5
5
  "main": "nuxt.config.ts",
6
6
  "scripts": {
7
7
  "clean": "rm -rf .nuxt && rm -rf .output && rm -rf .playground/.nuxt && rm -rf .playground/.output",