@wishbone-media/spark 0.28.0 → 0.29.0

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": "@wishbone-media/spark",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -30,7 +30,8 @@
30
30
  </template>
31
31
 
32
32
  <script setup>
33
- import { computed, ref, watch } from 'vue'
33
+ import { computed, ref, watch, onMounted } from 'vue'
34
+ import { useRoute } from 'vue-router'
34
35
  import { sparkNotificationService } from '@/composables/sparkNotificationService'
35
36
  import SparkAlert from '@/components/SparkAlert.vue'
36
37
 
@@ -39,8 +40,13 @@ const props = defineProps({
39
40
  type: String,
40
41
  default: 'default',
41
42
  },
43
+ clearOnRouteChange: {
44
+ type: Boolean,
45
+ default: true,
46
+ },
42
47
  })
43
48
 
49
+ const route = useRoute()
44
50
  const outlet = computed(() => sparkNotificationService.getOutlet(props.name))
45
51
 
46
52
  // Generate unique key for each notification to trigger transition on content change
@@ -54,6 +60,43 @@ watch(
54
60
  },
55
61
  )
56
62
 
63
+ // Track which path the notification was shown on
64
+ watch(
65
+ () => outlet.value.state.isVisible,
66
+ (isVisible) => {
67
+ if (isVisible && !outlet.value.state.shownOnPath) {
68
+ outlet.value.state.shownOnPath = route.path
69
+ }
70
+ },
71
+ { immediate: true },
72
+ )
73
+
74
+ // On mount, check if notification was shown on a different route
75
+ onMounted(() => {
76
+ if (!props.clearOnRouteChange) return
77
+ if (route.meta.preserveNotifications) return
78
+ if (!outlet.value.state.isVisible) return
79
+ if (outlet.value.state.persistent) return
80
+
81
+ // If notification was shown on a different path, hide it
82
+ if (outlet.value.state.shownOnPath && outlet.value.state.shownOnPath !== route.path) {
83
+ outlet.value.hide()
84
+ }
85
+ })
86
+
87
+ // Auto-clear notification on route change (while mounted)
88
+ watch(
89
+ () => route.path,
90
+ () => {
91
+ if (!props.clearOnRouteChange) return
92
+ if (route.meta.preserveNotifications) return
93
+ if (!outlet.value.state.isVisible) return
94
+ if (outlet.value.state.persistent) return
95
+
96
+ outlet.value.hide()
97
+ },
98
+ )
99
+
57
100
  const handleClose = () => {
58
101
  sparkNotificationService.hide(props.name)
59
102
  }
@@ -24,6 +24,8 @@ function createNotificationOutlet() {
24
24
  props: {},
25
25
  closeable: true,
26
26
  duration: null,
27
+ persistent: false,
28
+ shownOnPath: null,
27
29
  })
28
30
 
29
31
  // Timer state (not reactive, internal only)
@@ -90,6 +92,7 @@ function createNotificationOutlet() {
90
92
  props = {},
91
93
  closeable = true,
92
94
  duration = null,
95
+ persistent = false,
93
96
  } = options
94
97
 
95
98
  state.type = type
@@ -97,6 +100,7 @@ function createNotificationOutlet() {
97
100
  state.component = component ? markRaw(component) : null
98
101
  state.props = props
99
102
  state.closeable = closeable
103
+ state.persistent = persistent
100
104
  state.isVisible = true
101
105
 
102
106
  // Determine duration: explicit > default for type
@@ -116,6 +120,8 @@ function createNotificationOutlet() {
116
120
  state.props = {}
117
121
  state.closeable = true
118
122
  state.duration = null
123
+ state.persistent = false
124
+ state.shownOnPath = null
119
125
  }
120
126
 
121
127
  return {
@@ -187,6 +193,7 @@ class SparkNotificationService {
187
193
  * @param {Object} options.props - Props to pass to the component
188
194
  * @param {boolean} options.closeable - Whether to show close button (default: true)
189
195
  * @param {number} options.duration - Auto-dismiss duration in ms (0 = sticky, null = use default)
196
+ * @param {boolean} options.persistent - Whether notification survives route changes (default: false)
190
197
  * @param {string} outletName - Target outlet name (default: 'default')
191
198
  */
192
199
  show(options = {}, outletName = 'default') {
@@ -212,6 +219,18 @@ class SparkNotificationService {
212
219
  }
213
220
  }
214
221
 
222
+ /**
223
+ * Hide all non-persistent banner notifications
224
+ * Called by setupNotificationGuard on route change
225
+ */
226
+ hideAllNonPersistent() {
227
+ for (const outlet of this.outlets.values()) {
228
+ if (!outlet.state.persistent) {
229
+ outlet.hide()
230
+ }
231
+ }
232
+ }
233
+
215
234
  /**
216
235
  * Pause auto-dismiss timer for the specified banner outlet
217
236
  * @param {string} outletName - Target outlet name (default: 'default')