@wishbone-media/spark 0.19.0 → 0.21.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/dist/index.js +1874 -1244
- package/package.json +1 -1
- package/src/assets/css/index.css +1 -0
- package/src/assets/css/nprogress.css +6 -0
- package/src/components/SparkAlert.vue +5 -1
- package/src/components/SparkButton.vue +2 -0
- package/src/components/SparkNotificationOutlet.vue +68 -0
- package/src/components/SparkOverlay.vue +15 -2
- package/src/components/SparkToastContainer.vue +184 -0
- package/src/components/index.js +2 -0
- package/src/composables/index.js +1 -0
- package/src/composables/sparkModalService.js +49 -0
- package/src/composables/sparkNotificationService.js +459 -0
- package/src/composables/sparkOverlayService.js +4 -4
- package/src/composables/useSparkOverlay.js +6 -3
- package/src/composables/useSparkTableRouteSync.js +19 -2
- package/src/utils/sparkTable/renderers/actions.js +27 -2
- package/src/utils/sparkTable/renderers/boolean.js +97 -0
- package/src/utils/sparkTable/renderers/index.js +3 -0
package/package.json
CHANGED
package/src/assets/css/index.css
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<div class="ml-3">
|
|
8
8
|
<slot />
|
|
9
9
|
</div>
|
|
10
|
-
<div class="ml-auto pl-3 pt-1 self-start">
|
|
10
|
+
<div v-if="closeable" class="ml-auto pl-3 pt-1 self-start">
|
|
11
11
|
<div class="-mx-1.5 -my-1.5">
|
|
12
12
|
<button
|
|
13
13
|
type="button"
|
|
@@ -33,6 +33,10 @@ const props = defineProps({
|
|
|
33
33
|
default: 'info',
|
|
34
34
|
validator: (value) => ['success', 'warning', 'danger', 'info'].includes(value),
|
|
35
35
|
},
|
|
36
|
+
closeable: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: true,
|
|
39
|
+
},
|
|
36
40
|
})
|
|
37
41
|
|
|
38
42
|
defineEmits(['close'])
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Transition
|
|
3
|
+
enter-active-class="transition-all duration-300 ease-out"
|
|
4
|
+
enter-from-class="opacity-0 -translate-y-2"
|
|
5
|
+
enter-to-class="opacity-100 translate-y-0"
|
|
6
|
+
leave-active-class="transition-all duration-200 ease-in"
|
|
7
|
+
leave-from-class="opacity-100 translate-y-0"
|
|
8
|
+
leave-to-class="opacity-0 -translate-y-2"
|
|
9
|
+
mode="out-in"
|
|
10
|
+
>
|
|
11
|
+
<SparkAlert
|
|
12
|
+
v-if="outlet.state.isVisible"
|
|
13
|
+
:key="notificationKey"
|
|
14
|
+
:type="outlet.state.type"
|
|
15
|
+
:closeable="outlet.state.closeable"
|
|
16
|
+
@close="handleClose"
|
|
17
|
+
@mouseenter="handleMouseEnter"
|
|
18
|
+
@mouseleave="handleMouseLeave"
|
|
19
|
+
>
|
|
20
|
+
<component
|
|
21
|
+
v-if="outlet.state.component"
|
|
22
|
+
:is="outlet.state.component"
|
|
23
|
+
v-bind="outlet.state.props"
|
|
24
|
+
/>
|
|
25
|
+
<template v-else>
|
|
26
|
+
{{ outlet.state.message }}
|
|
27
|
+
</template>
|
|
28
|
+
</SparkAlert>
|
|
29
|
+
</Transition>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup>
|
|
33
|
+
import { computed, ref, watch } from 'vue'
|
|
34
|
+
import { sparkNotificationService } from '@/composables/sparkNotificationService'
|
|
35
|
+
import SparkAlert from '@/components/SparkAlert.vue'
|
|
36
|
+
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
name: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: 'default',
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const outlet = computed(() => sparkNotificationService.getOutlet(props.name))
|
|
45
|
+
|
|
46
|
+
// Generate unique key for each notification to trigger transition on content change
|
|
47
|
+
const notificationKey = ref(0)
|
|
48
|
+
watch(
|
|
49
|
+
() => [outlet.value.state.message, outlet.value.state.component, outlet.value.state.type],
|
|
50
|
+
() => {
|
|
51
|
+
if (outlet.value.state.isVisible) {
|
|
52
|
+
notificationKey.value++
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const handleClose = () => {
|
|
58
|
+
sparkNotificationService.hide(props.name)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const handleMouseEnter = () => {
|
|
62
|
+
sparkNotificationService.pause(props.name)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const handleMouseLeave = () => {
|
|
66
|
+
sparkNotificationService.resume(props.name)
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
<DialogPanel
|
|
35
35
|
ref="panelRef"
|
|
36
36
|
:class="[
|
|
37
|
-
'flex
|
|
37
|
+
'flex py-2.5',
|
|
38
|
+
widthClass,
|
|
38
39
|
position === 'left' ? 'relative left-[10px]' : 'absolute right-[10px] h-full',
|
|
39
40
|
]"
|
|
40
41
|
>
|
|
@@ -52,11 +53,19 @@
|
|
|
52
53
|
</template>
|
|
53
54
|
|
|
54
55
|
<script setup>
|
|
55
|
-
import { ref } from 'vue'
|
|
56
|
+
import { computed, ref } from 'vue'
|
|
56
57
|
import { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'
|
|
57
58
|
|
|
58
59
|
const panelRef = ref(null)
|
|
59
60
|
|
|
61
|
+
const sizeClasses = {
|
|
62
|
+
xs: 'w-[250px]',
|
|
63
|
+
sm: 'w-[300px]',
|
|
64
|
+
md: 'w-[450px]',
|
|
65
|
+
lg: 'w-[810px]',
|
|
66
|
+
xl: 'w-[1000px]',
|
|
67
|
+
}
|
|
68
|
+
|
|
60
69
|
const props = defineProps({
|
|
61
70
|
position: {
|
|
62
71
|
type: String,
|
|
@@ -72,6 +81,10 @@ const props = defineProps({
|
|
|
72
81
|
|
|
73
82
|
const emit = defineEmits(['close'])
|
|
74
83
|
|
|
84
|
+
const widthClass = computed(() => {
|
|
85
|
+
return sizeClasses[props.overlayInstance.state.size] || sizeClasses.md
|
|
86
|
+
})
|
|
87
|
+
|
|
75
88
|
const handleClose = () => {
|
|
76
89
|
props.overlayInstance.close()
|
|
77
90
|
emit('close')
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Teleport to="body">
|
|
3
|
+
<!-- Top Left -->
|
|
4
|
+
<div class="fixed top-4 left-4 z-[2000] flex flex-col gap-3 max-w-sm w-full pointer-events-none">
|
|
5
|
+
<TransitionGroup
|
|
6
|
+
enter-active-class="transition-all duration-300 ease-out"
|
|
7
|
+
enter-from-class="opacity-0 -translate-x-4"
|
|
8
|
+
enter-to-class="opacity-100 translate-x-0"
|
|
9
|
+
leave-active-class="transition-all duration-200 ease-in"
|
|
10
|
+
leave-from-class="opacity-100 translate-x-0"
|
|
11
|
+
leave-to-class="opacity-0 -translate-x-4"
|
|
12
|
+
>
|
|
13
|
+
<div v-for="toast in topLeftToasts" :key="toast.id" class="pointer-events-auto">
|
|
14
|
+
<SparkAlert
|
|
15
|
+
:type="toast.type"
|
|
16
|
+
:closeable="toast.closeable"
|
|
17
|
+
@close="handleClose(toast.id)"
|
|
18
|
+
@mouseenter="handleMouseEnter(toast.id)"
|
|
19
|
+
@mouseleave="handleMouseLeave(toast.id)"
|
|
20
|
+
>
|
|
21
|
+
<component
|
|
22
|
+
v-if="toast.component"
|
|
23
|
+
:is="toast.component"
|
|
24
|
+
v-bind="toast.props"
|
|
25
|
+
/>
|
|
26
|
+
<template v-else>{{ toast.message }}</template>
|
|
27
|
+
</SparkAlert>
|
|
28
|
+
</div>
|
|
29
|
+
</TransitionGroup>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<!-- Top Right -->
|
|
33
|
+
<div class="fixed top-4 right-4 z-[2000] flex flex-col gap-3 max-w-sm w-full pointer-events-none">
|
|
34
|
+
<TransitionGroup
|
|
35
|
+
enter-active-class="transition-all duration-300 ease-out"
|
|
36
|
+
enter-from-class="opacity-0 translate-x-4"
|
|
37
|
+
enter-to-class="opacity-100 translate-x-0"
|
|
38
|
+
leave-active-class="transition-all duration-200 ease-in"
|
|
39
|
+
leave-from-class="opacity-100 translate-x-0"
|
|
40
|
+
leave-to-class="opacity-0 translate-x-4"
|
|
41
|
+
>
|
|
42
|
+
<div v-for="toast in topRightToasts" :key="toast.id" class="pointer-events-auto">
|
|
43
|
+
<SparkAlert
|
|
44
|
+
:type="toast.type"
|
|
45
|
+
:closeable="toast.closeable"
|
|
46
|
+
@close="handleClose(toast.id)"
|
|
47
|
+
@mouseenter="handleMouseEnter(toast.id)"
|
|
48
|
+
@mouseleave="handleMouseLeave(toast.id)"
|
|
49
|
+
>
|
|
50
|
+
<component
|
|
51
|
+
v-if="toast.component"
|
|
52
|
+
:is="toast.component"
|
|
53
|
+
v-bind="toast.props"
|
|
54
|
+
/>
|
|
55
|
+
<template v-else>{{ toast.message }}</template>
|
|
56
|
+
</SparkAlert>
|
|
57
|
+
</div>
|
|
58
|
+
</TransitionGroup>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<!-- Center (slightly above center) -->
|
|
62
|
+
<div class="fixed top-[40%] left-1/2 -translate-x-1/2 -translate-y-1/2 z-[2000] flex flex-col gap-3 max-w-sm w-full pointer-events-none">
|
|
63
|
+
<TransitionGroup
|
|
64
|
+
enter-active-class="transition-all duration-300 ease-out"
|
|
65
|
+
enter-from-class="opacity-0 scale-95"
|
|
66
|
+
enter-to-class="opacity-100 scale-100"
|
|
67
|
+
leave-active-class="transition-all duration-200 ease-in"
|
|
68
|
+
leave-from-class="opacity-100 scale-100"
|
|
69
|
+
leave-to-class="opacity-0 scale-95"
|
|
70
|
+
>
|
|
71
|
+
<div v-for="toast in centerToasts" :key="toast.id" class="pointer-events-auto">
|
|
72
|
+
<SparkAlert
|
|
73
|
+
:type="toast.type"
|
|
74
|
+
:closeable="toast.closeable"
|
|
75
|
+
@close="handleClose(toast.id)"
|
|
76
|
+
@mouseenter="handleMouseEnter(toast.id)"
|
|
77
|
+
@mouseleave="handleMouseLeave(toast.id)"
|
|
78
|
+
>
|
|
79
|
+
<component
|
|
80
|
+
v-if="toast.component"
|
|
81
|
+
:is="toast.component"
|
|
82
|
+
v-bind="toast.props"
|
|
83
|
+
/>
|
|
84
|
+
<template v-else>{{ toast.message }}</template>
|
|
85
|
+
</SparkAlert>
|
|
86
|
+
</div>
|
|
87
|
+
</TransitionGroup>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<!-- Bottom Left -->
|
|
91
|
+
<div class="fixed bottom-4 left-4 z-[2000] flex flex-col-reverse gap-3 max-w-sm w-full pointer-events-none">
|
|
92
|
+
<TransitionGroup
|
|
93
|
+
enter-active-class="transition-all duration-300 ease-out"
|
|
94
|
+
enter-from-class="opacity-0 -translate-x-4"
|
|
95
|
+
enter-to-class="opacity-100 translate-x-0"
|
|
96
|
+
leave-active-class="transition-all duration-200 ease-in"
|
|
97
|
+
leave-from-class="opacity-100 translate-x-0"
|
|
98
|
+
leave-to-class="opacity-0 -translate-x-4"
|
|
99
|
+
>
|
|
100
|
+
<div v-for="toast in bottomLeftToasts" :key="toast.id" class="pointer-events-auto">
|
|
101
|
+
<SparkAlert
|
|
102
|
+
:type="toast.type"
|
|
103
|
+
:closeable="toast.closeable"
|
|
104
|
+
@close="handleClose(toast.id)"
|
|
105
|
+
@mouseenter="handleMouseEnter(toast.id)"
|
|
106
|
+
@mouseleave="handleMouseLeave(toast.id)"
|
|
107
|
+
>
|
|
108
|
+
<component
|
|
109
|
+
v-if="toast.component"
|
|
110
|
+
:is="toast.component"
|
|
111
|
+
v-bind="toast.props"
|
|
112
|
+
/>
|
|
113
|
+
<template v-else>{{ toast.message }}</template>
|
|
114
|
+
</SparkAlert>
|
|
115
|
+
</div>
|
|
116
|
+
</TransitionGroup>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<!-- Bottom Right -->
|
|
120
|
+
<div class="fixed bottom-4 right-4 z-[2000] flex flex-col-reverse gap-3 max-w-sm w-full pointer-events-none">
|
|
121
|
+
<TransitionGroup
|
|
122
|
+
enter-active-class="transition-all duration-300 ease-out"
|
|
123
|
+
enter-from-class="opacity-0 translate-x-4"
|
|
124
|
+
enter-to-class="opacity-100 translate-x-0"
|
|
125
|
+
leave-active-class="transition-all duration-200 ease-in"
|
|
126
|
+
leave-from-class="opacity-100 translate-x-0"
|
|
127
|
+
leave-to-class="opacity-0 translate-x-4"
|
|
128
|
+
>
|
|
129
|
+
<div v-for="toast in bottomRightToasts" :key="toast.id" class="pointer-events-auto">
|
|
130
|
+
<SparkAlert
|
|
131
|
+
:type="toast.type"
|
|
132
|
+
:closeable="toast.closeable"
|
|
133
|
+
@close="handleClose(toast.id)"
|
|
134
|
+
@mouseenter="handleMouseEnter(toast.id)"
|
|
135
|
+
@mouseleave="handleMouseLeave(toast.id)"
|
|
136
|
+
>
|
|
137
|
+
<component
|
|
138
|
+
v-if="toast.component"
|
|
139
|
+
:is="toast.component"
|
|
140
|
+
v-bind="toast.props"
|
|
141
|
+
/>
|
|
142
|
+
<template v-else>{{ toast.message }}</template>
|
|
143
|
+
</SparkAlert>
|
|
144
|
+
</div>
|
|
145
|
+
</TransitionGroup>
|
|
146
|
+
</div>
|
|
147
|
+
</Teleport>
|
|
148
|
+
</template>
|
|
149
|
+
|
|
150
|
+
<script setup>
|
|
151
|
+
import { computed } from 'vue'
|
|
152
|
+
import { sparkNotificationService } from '@/composables/sparkNotificationService'
|
|
153
|
+
import SparkAlert from '@/components/SparkAlert.vue'
|
|
154
|
+
|
|
155
|
+
const toastState = sparkNotificationService.toastState
|
|
156
|
+
|
|
157
|
+
const topLeftToasts = computed(() =>
|
|
158
|
+
toastState.toasts.filter(t => t.position === 'top-left')
|
|
159
|
+
)
|
|
160
|
+
const topRightToasts = computed(() =>
|
|
161
|
+
toastState.toasts.filter(t => t.position === 'top-right')
|
|
162
|
+
)
|
|
163
|
+
const centerToasts = computed(() =>
|
|
164
|
+
toastState.toasts.filter(t => t.position === 'center')
|
|
165
|
+
)
|
|
166
|
+
const bottomLeftToasts = computed(() =>
|
|
167
|
+
toastState.toasts.filter(t => t.position === 'bottom-left')
|
|
168
|
+
)
|
|
169
|
+
const bottomRightToasts = computed(() =>
|
|
170
|
+
toastState.toasts.filter(t => t.position === 'bottom-right')
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
const handleClose = (toastId) => {
|
|
174
|
+
sparkNotificationService.hideToast(toastId)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const handleMouseEnter = (toastId) => {
|
|
178
|
+
sparkNotificationService.pauseToast(toastId)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const handleMouseLeave = (toastId) => {
|
|
182
|
+
sparkNotificationService.resumeToast(toastId)
|
|
183
|
+
}
|
|
184
|
+
</script>
|
package/src/components/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { default as SparkAlert } from './SparkAlert.vue'
|
|
2
2
|
export { default as SparkAppSelector } from './SparkAppSelector.vue'
|
|
3
|
+
export { default as SparkNotificationOutlet } from './SparkNotificationOutlet.vue'
|
|
4
|
+
export { default as SparkToastContainer } from './SparkToastContainer.vue'
|
|
3
5
|
export { default as SparkBrandSelector } from './SparkBrandSelector.vue'
|
|
4
6
|
export { default as SparkButton } from './SparkButton.vue'
|
|
5
7
|
export { default as SparkButtonGroup } from './SparkButtonGroup.vue'
|
package/src/composables/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { sparkModalService } from './sparkModalService.js'
|
|
2
|
+
export { sparkNotificationService } from './sparkNotificationService.js'
|
|
2
3
|
export { sparkOverlayService } from './sparkOverlayService.js'
|
|
3
4
|
export { useSparkOverlay } from './useSparkOverlay.js'
|
|
4
5
|
export { useSparkTableRouteSync } from './useSparkTableRouteSync.js'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { reactive, markRaw } from 'vue'
|
|
2
|
+
import SparkModalDialog from '@/components/SparkModalDialog.vue'
|
|
2
3
|
|
|
3
4
|
class SparkModalService {
|
|
4
5
|
constructor() {
|
|
@@ -21,6 +22,54 @@ class SparkModalService {
|
|
|
21
22
|
this.state.isVisible = false
|
|
22
23
|
this.state.eventHandlers = {}
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Show a confirmation dialog and return a Promise
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} options - Confirmation options
|
|
30
|
+
* @param {string} [options.title='Confirm'] - Dialog title
|
|
31
|
+
* @param {string} [options.message='Are you sure?'] - Dialog message
|
|
32
|
+
* @param {string} [options.type='warning'] - Dialog type (info, success, warning, danger)
|
|
33
|
+
* @param {string} [options.confirmText='Confirm'] - Confirm button text
|
|
34
|
+
* @param {string} [options.cancelText='Cancel'] - Cancel button text
|
|
35
|
+
* @param {string} [options.confirmVariant='primary'] - Confirm button variant
|
|
36
|
+
* @returns {Promise<boolean>} - Resolves to true if confirmed, false if cancelled
|
|
37
|
+
*/
|
|
38
|
+
confirm = (options = {}) => {
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
const {
|
|
41
|
+
title = 'Confirm',
|
|
42
|
+
message = 'Are you sure?',
|
|
43
|
+
type = 'warning',
|
|
44
|
+
confirmText = 'Confirm',
|
|
45
|
+
cancelText = 'Cancel',
|
|
46
|
+
confirmVariant = 'primary',
|
|
47
|
+
} = options
|
|
48
|
+
|
|
49
|
+
this.show(
|
|
50
|
+
SparkModalDialog,
|
|
51
|
+
{
|
|
52
|
+
title,
|
|
53
|
+
message,
|
|
54
|
+
type,
|
|
55
|
+
buttons: [
|
|
56
|
+
{ text: confirmText, variant: confirmVariant, event: 'confirm' },
|
|
57
|
+
{ text: cancelText, variant: 'secondary', event: 'cancel' },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
confirm: () => {
|
|
62
|
+
this.hide()
|
|
63
|
+
resolve(true)
|
|
64
|
+
},
|
|
65
|
+
cancel: () => {
|
|
66
|
+
this.hide()
|
|
67
|
+
resolve(false)
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
})
|
|
72
|
+
}
|
|
24
73
|
}
|
|
25
74
|
|
|
26
75
|
export const sparkModalService = new SparkModalService()
|