@citizenplane/pimp 9.16.3 → 10.0.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/pimp.es.js +5419 -7042
- package/dist/pimp.umd.js +44 -44
- package/dist/style.css +1 -1
- package/package.json +1 -2
- package/src/components/CpSelectMenu.vue +1 -13
- package/src/components/CpToast.vue +9 -0
- package/src/components/index.ts +1 -10
- package/src/components/CpToaster.vue +0 -382
- package/src/plugins/toaster.ts +0 -71
- package/src/stories/CpToaster.stories.ts +0 -188
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citizenplane/pimp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "storybook dev -p 8080",
|
|
6
6
|
"build-storybook": "storybook build --output-dir ./docs",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"./*.css": "./dist/*.css"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"animejs": "^4.2.2",
|
|
37
36
|
"feather-icons": "^4.29.2",
|
|
38
37
|
"floating-vue": "^5.2.2",
|
|
39
38
|
"luxon": "^3.7.2",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
type="chevron-down"
|
|
9
9
|
/>
|
|
10
10
|
</button>
|
|
11
|
-
<transition
|
|
11
|
+
<transition mode="out-in" name="scale-elastic">
|
|
12
12
|
<div v-if="isDropdownOpen" ref="dropdownRef" class="cpSelectMenu__dropdown dropdown">
|
|
13
13
|
<p v-if="dropdownTitle" class="dropdown__title">
|
|
14
14
|
{{ dropdownTitle }}
|
|
@@ -47,7 +47,6 @@
|
|
|
47
47
|
</template>
|
|
48
48
|
|
|
49
49
|
<script setup lang="ts">
|
|
50
|
-
import { animate, cubicBezier } from 'animejs'
|
|
51
50
|
import { ref, computed, nextTick } from 'vue'
|
|
52
51
|
|
|
53
52
|
interface SelectValue {
|
|
@@ -92,17 +91,6 @@ const inputType = computed(() => {
|
|
|
92
91
|
return props.isMultiSelect ? 'checkbox' : 'radio'
|
|
93
92
|
})
|
|
94
93
|
|
|
95
|
-
const enter = (): void => {
|
|
96
|
-
if (dropdownRef.value) {
|
|
97
|
-
animate(dropdownRef.value, {
|
|
98
|
-
scale: [0.8, 1],
|
|
99
|
-
opacity: [0, 1],
|
|
100
|
-
duration: 200,
|
|
101
|
-
ease: cubicBezier(0.175, 0.885, 0.32, 1.175),
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
94
|
const toggleDropdown = (): void => {
|
|
107
95
|
isDropdownOpen.value = !isDropdownOpen.value
|
|
108
96
|
|
|
@@ -224,6 +224,10 @@ const handleActionClick = (onClick: VoidFunction, closeCallback: VoidFunction) =
|
|
|
224
224
|
&__summary {
|
|
225
225
|
font-weight: 600;
|
|
226
226
|
color: fn.v(text-accent-primary);
|
|
227
|
+
|
|
228
|
+
&:first-letter {
|
|
229
|
+
text-transform: capitalize;
|
|
230
|
+
}
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
&__detail {
|
|
@@ -362,5 +366,10 @@ const handleActionClick = (onClick: VoidFunction, closeCallback: VoidFunction) =
|
|
|
362
366
|
margin: 0 auto;
|
|
363
367
|
text-align: center;
|
|
364
368
|
}
|
|
369
|
+
|
|
370
|
+
.cpToast {
|
|
371
|
+
max-width: 100%;
|
|
372
|
+
min-width: 100%;
|
|
373
|
+
}
|
|
365
374
|
}
|
|
366
375
|
</style>
|
package/src/components/index.ts
CHANGED
|
@@ -43,7 +43,6 @@ import CpTabs from './CpTabs.vue'
|
|
|
43
43
|
import CpTelInput from './CpTelInput.vue'
|
|
44
44
|
import CpTextarea from './CpTextarea.vue'
|
|
45
45
|
import CpToast from './CpToast.vue'
|
|
46
|
-
import CpToaster from './CpToaster.vue'
|
|
47
46
|
import CpTooltip from './CpTooltip.vue'
|
|
48
47
|
import CpTransitionDialog from './CpTransitionDialog.vue'
|
|
49
48
|
import IconAirline from './icons/IconAirline.vue'
|
|
@@ -56,10 +55,8 @@ import IconSupplier from './icons/IconSupplier.vue'
|
|
|
56
55
|
import IconThirdParty from './icons/IconThirdParty.vue'
|
|
57
56
|
import IconTooltip from './icons/IconTooltip.vue'
|
|
58
57
|
import TransitionExpand from './TransitionExpand.vue'
|
|
59
|
-
import createToaster from '@/plugins/toaster'
|
|
60
58
|
|
|
61
59
|
const Components = {
|
|
62
|
-
CpToaster,
|
|
63
60
|
CpToast,
|
|
64
61
|
CpBadge,
|
|
65
62
|
CpTabs,
|
|
@@ -105,7 +102,7 @@ const Components = {
|
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
const Pimp = {
|
|
108
|
-
install(app: App
|
|
105
|
+
install(app: App) {
|
|
109
106
|
app.use(PrimeVue, { unstyled: true })
|
|
110
107
|
app.use(VueTelInput)
|
|
111
108
|
app.use(ToastService)
|
|
@@ -119,12 +116,6 @@ const Pimp = {
|
|
|
119
116
|
app.directive('bind-once', BindOnceDirective)
|
|
120
117
|
app.directive('maska', vMaska)
|
|
121
118
|
app.directive('tooltip', vTooltip)
|
|
122
|
-
|
|
123
|
-
// CpToaster
|
|
124
|
-
const methods = createToaster(options)
|
|
125
|
-
// @ts-expect-error <comment on type error>
|
|
126
|
-
app.$toaster = methods
|
|
127
|
-
app.config.globalProperties.$toaster = methods
|
|
128
119
|
},
|
|
129
120
|
}
|
|
130
121
|
|
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<transition @enter="enter" @leave="leave">
|
|
3
|
-
<div
|
|
4
|
-
v-show="isOpen"
|
|
5
|
-
:id="toasterId"
|
|
6
|
-
:key="toasterId"
|
|
7
|
-
class="cpToaster"
|
|
8
|
-
:class="dynamicClass"
|
|
9
|
-
role="alert"
|
|
10
|
-
@mouseenter="setHoverState()"
|
|
11
|
-
@mouseleave="setHoverState(false)"
|
|
12
|
-
>
|
|
13
|
-
<div class="cpToaster__content">
|
|
14
|
-
<cp-icon class="cpToaster__icon" :type="toasterIcon" />
|
|
15
|
-
<div class="cpToaster__body">
|
|
16
|
-
<cp-heading class="cpToaster__title" :heading-level="HeadingLevels.H4" :size="400">{{ title }}</cp-heading>
|
|
17
|
-
<p v-if="description" class="cpToaster__description">{{ description }}</p>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
<button class="cpToaster__close" type="button" @click="closeToaster">
|
|
21
|
-
<cp-icon type="x" />
|
|
22
|
-
</button>
|
|
23
|
-
<div v-if="actionLabel" class="cpToaster__footer">
|
|
24
|
-
<button v-if="actionIsButton" class="cpToaster__button" type="button" @click="handleActionMethod">
|
|
25
|
-
{{ actionLabel }}
|
|
26
|
-
</button>
|
|
27
|
-
<a v-else class="cpToaster__button" v-bind="actionLinkProperties">
|
|
28
|
-
{{ actionLabel }}
|
|
29
|
-
</a>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
</transition>
|
|
33
|
-
</template>
|
|
34
|
-
|
|
35
|
-
<script setup lang="ts">
|
|
36
|
-
import { animate, cubicBezier } from 'animejs'
|
|
37
|
-
import { ref, computed, watch, onBeforeMount, onMounted, nextTick, getCurrentInstance, useId } from 'vue'
|
|
38
|
-
|
|
39
|
-
import CpHeading from '@/components/CpHeading.vue'
|
|
40
|
-
import CpIcon from '@/components/CpIcon.vue'
|
|
41
|
-
|
|
42
|
-
import { HeadingLevels, Intent } from '@/constants'
|
|
43
|
-
|
|
44
|
-
interface Props {
|
|
45
|
-
actionAs?: 'link' | 'button'
|
|
46
|
-
actionLabel?: string
|
|
47
|
-
actionLinkProperties?: Record<string, unknown>
|
|
48
|
-
actionMethod?: (vmProperties: Record<string, unknown>) => void
|
|
49
|
-
delayBeforeCloseInMs?: number
|
|
50
|
-
description?: string
|
|
51
|
-
isUnique?: boolean
|
|
52
|
-
title: string
|
|
53
|
-
type?: string
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface PublicMethods {
|
|
57
|
-
closeToaster: () => void
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
61
|
-
description: '',
|
|
62
|
-
type: 'info',
|
|
63
|
-
delayBeforeCloseInMs: 5000,
|
|
64
|
-
actionLabel: '',
|
|
65
|
-
actionLinkProperties: () => ({}),
|
|
66
|
-
actionAs: 'button',
|
|
67
|
-
actionMethod: () => {},
|
|
68
|
-
isUnique: false,
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
const validateType = (value: string): boolean => {
|
|
72
|
-
const intentValues = Object.values(Intent).map((item) => item.value)
|
|
73
|
-
return intentValues.includes(value)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (!validateType(props.type)) {
|
|
77
|
-
console.warn(`Type de toaster invalide: ${props.type}`)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const toasterId = useId()
|
|
81
|
-
const toastersContainer = ref<HTMLElement | null>(null)
|
|
82
|
-
const isOpen = ref<boolean>(false)
|
|
83
|
-
const isHovered = ref<boolean>(false)
|
|
84
|
-
const deleteCountDown = ref<number>(props.delayBeforeCloseInMs)
|
|
85
|
-
const timeoutID = ref<ReturnType<typeof setTimeout>>()
|
|
86
|
-
const countDownInterval = ref<ReturnType<typeof setInterval>>()
|
|
87
|
-
|
|
88
|
-
const instance = getCurrentInstance()
|
|
89
|
-
|
|
90
|
-
const actionIsButton = computed(() => props.actionAs === 'button')
|
|
91
|
-
|
|
92
|
-
const toasterIcon = computed(() => {
|
|
93
|
-
const intentValues = Object.values(Intent)
|
|
94
|
-
const intent = intentValues.find((intentItem) => intentItem.value === props.type)
|
|
95
|
-
return intent ? intent.icon : Intent.INFO.icon
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
const dynamicClass = computed(() => {
|
|
99
|
-
return `cpToaster--${props.type || Intent.INFO.value}`
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
watch(isHovered, (newValue: boolean) => {
|
|
103
|
-
if (!newValue) {
|
|
104
|
-
handleDeleteEvent()
|
|
105
|
-
} else {
|
|
106
|
-
cancelDelete()
|
|
107
|
-
}
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
const createContainer = (): void => {
|
|
111
|
-
toastersContainer.value = document.querySelector('.cpToaster__container')
|
|
112
|
-
|
|
113
|
-
if (toastersContainer.value) return
|
|
114
|
-
|
|
115
|
-
if (!toastersContainer.value) {
|
|
116
|
-
toastersContainer.value = document.createElement('section')
|
|
117
|
-
toastersContainer.value.className = 'cpToaster__container'
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const setupContainer = (): void => {
|
|
122
|
-
if (toastersContainer.value) {
|
|
123
|
-
document.body.appendChild(toastersContainer.value)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const removeSiblings = (): void => {
|
|
128
|
-
if (!props.isUnique) return
|
|
129
|
-
|
|
130
|
-
const siblings = document.querySelectorAll('.cpToaster')
|
|
131
|
-
siblings.forEach(removeElement)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const showToaster = (): void => {
|
|
135
|
-
isOpen.value = true
|
|
136
|
-
|
|
137
|
-
nextTick(() => {
|
|
138
|
-
if (toastersContainer.value && instance?.proxy?.$el) {
|
|
139
|
-
toastersContainer.value.insertAdjacentElement('afterbegin', instance.proxy.$el)
|
|
140
|
-
}
|
|
141
|
-
})
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const setHoverState = (state: boolean = true): void => {
|
|
145
|
-
isHovered.value = state
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const handleDeleteEvent = (): void => {
|
|
149
|
-
startCountDown()
|
|
150
|
-
|
|
151
|
-
timeoutID.value = setTimeout(() => {
|
|
152
|
-
closeToaster()
|
|
153
|
-
}, props.delayBeforeCloseInMs)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const cancelDelete = (): void => {
|
|
157
|
-
if (timeoutID.value) {
|
|
158
|
-
clearTimeout(timeoutID.value)
|
|
159
|
-
}
|
|
160
|
-
if (countDownInterval.value) {
|
|
161
|
-
clearInterval(countDownInterval.value)
|
|
162
|
-
}
|
|
163
|
-
resetCountDown()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const startCountDown = (): void => {
|
|
167
|
-
countDownInterval.value = setInterval(() => {
|
|
168
|
-
deleteCountDown.value -= 1000
|
|
169
|
-
if (deleteCountDown.value <= 0 && countDownInterval.value) {
|
|
170
|
-
clearInterval(countDownInterval.value)
|
|
171
|
-
}
|
|
172
|
-
}, 1000)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const resetCountDown = (): void => {
|
|
176
|
-
deleteCountDown.value = props.delayBeforeCloseInMs
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const handleActionMethod = (): void => {
|
|
180
|
-
const vmProperties: Record<string, unknown> = {
|
|
181
|
-
closeToaster,
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return props.actionMethod(vmProperties)
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const closeToaster = (): void => {
|
|
188
|
-
cancelDelete()
|
|
189
|
-
isOpen.value = false
|
|
190
|
-
|
|
191
|
-
setTimeout(() => {
|
|
192
|
-
if (instance?.proxy?.$el) {
|
|
193
|
-
removeElement(instance.proxy.$el)
|
|
194
|
-
}
|
|
195
|
-
}, 240)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const removeElement = (el: Element): void => {
|
|
199
|
-
if (typeof el.remove !== 'undefined') {
|
|
200
|
-
el.remove()
|
|
201
|
-
} else if (el.parentNode) {
|
|
202
|
-
el.parentNode.removeChild(el)
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const enter = async (el: Element, done: () => void): Promise<void> => {
|
|
207
|
-
animate(el, {
|
|
208
|
-
translateY: [-60, 0],
|
|
209
|
-
opacity: [0, 1],
|
|
210
|
-
duration: 240,
|
|
211
|
-
ease: cubicBezier(0.175, 0.885, 0.32, 1.175),
|
|
212
|
-
complete: function () {
|
|
213
|
-
done()
|
|
214
|
-
},
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const leave = async (el: Element, done: () => void): Promise<void> => {
|
|
219
|
-
animate(el, {
|
|
220
|
-
scale: [1, 0.8],
|
|
221
|
-
opacity: [1, 0],
|
|
222
|
-
duration: 240,
|
|
223
|
-
ease: cubicBezier(0.0, 0.0, 0.2, 1),
|
|
224
|
-
complete: function () {
|
|
225
|
-
done()
|
|
226
|
-
},
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
onBeforeMount(() => {
|
|
231
|
-
createContainer()
|
|
232
|
-
setupContainer()
|
|
233
|
-
removeSiblings()
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
onMounted(() => {
|
|
237
|
-
showToaster()
|
|
238
|
-
handleDeleteEvent()
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
defineExpose<PublicMethods>({
|
|
242
|
-
closeToaster,
|
|
243
|
-
})
|
|
244
|
-
</script>
|
|
245
|
-
|
|
246
|
-
<style lang="scss">
|
|
247
|
-
@mixin cp-toaster-style($color, $className) {
|
|
248
|
-
&--#{$className} &__icon {
|
|
249
|
-
color: $color;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
&--#{$className}:before {
|
|
253
|
-
background-color: $color;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
.cpToaster {
|
|
258
|
-
position: relative;
|
|
259
|
-
box-shadow:
|
|
260
|
-
rgba(67, 90, 111, 0.3) 0 0 1px,
|
|
261
|
-
rgba(67, 90, 111, 0.47) 0 8px 10px -4px;
|
|
262
|
-
background: colors.$neutral-light;
|
|
263
|
-
padding: sp.$space-md;
|
|
264
|
-
overflow: hidden;
|
|
265
|
-
width: max-content;
|
|
266
|
-
max-width: 100%;
|
|
267
|
-
margin: auto;
|
|
268
|
-
pointer-events: auto;
|
|
269
|
-
font-size: fn.px-to-rem(14);
|
|
270
|
-
|
|
271
|
-
@media (min-width: 769px) {
|
|
272
|
-
border-radius: fn.px-to-rem(8);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
@media (max-width: 768px) {
|
|
276
|
-
min-width: 100%;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
&:before {
|
|
280
|
-
content: '';
|
|
281
|
-
position: absolute;
|
|
282
|
-
top: 0;
|
|
283
|
-
left: 0;
|
|
284
|
-
width: fn.px-to-rem(3);
|
|
285
|
-
height: 100%;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
&__container {
|
|
289
|
-
position: fixed;
|
|
290
|
-
z-index: 9999;
|
|
291
|
-
top: 0;
|
|
292
|
-
left: 0;
|
|
293
|
-
right: 0;
|
|
294
|
-
margin: auto;
|
|
295
|
-
padding: sp.$space-lg;
|
|
296
|
-
max-width: fn.px-to-rem(400);
|
|
297
|
-
pointer-events: none;
|
|
298
|
-
|
|
299
|
-
& > *:not(:last-child) {
|
|
300
|
-
margin-bottom: sp.$space;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
@media (max-width: 768px) {
|
|
304
|
-
max-width: 100%;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
&__content {
|
|
309
|
-
display: flex;
|
|
310
|
-
align-items: flex-start;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
&__body {
|
|
314
|
-
flex: 1;
|
|
315
|
-
margin-left: sp.$space;
|
|
316
|
-
padding-right: calc(sp.$space-lg + sp.$space-lg);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
&__icon {
|
|
320
|
-
flex-shrink: 0;
|
|
321
|
-
height: fn.px-to-rem(16);
|
|
322
|
-
width: fn.px-to-rem(16);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
&__content,
|
|
326
|
-
&__title {
|
|
327
|
-
line-height: fn.px-to-rem(16);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
&__title {
|
|
331
|
-
font-weight: 600;
|
|
332
|
-
|
|
333
|
-
&:not(:only-child) {
|
|
334
|
-
margin-bottom: sp.$space-sm;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
&__description {
|
|
339
|
-
font-size: fn.px-to-rem(14);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
&__close {
|
|
343
|
-
position: absolute;
|
|
344
|
-
right: sp.$space;
|
|
345
|
-
top: sp.$space;
|
|
346
|
-
display: flex;
|
|
347
|
-
border-radius: fn.px-to-rem(4);
|
|
348
|
-
padding: sp.$space-sm;
|
|
349
|
-
color: colors.$neutral-dark-1;
|
|
350
|
-
|
|
351
|
-
svg {
|
|
352
|
-
margin: 0;
|
|
353
|
-
width: fn.px-to-rem(18);
|
|
354
|
-
height: fn.px-to-rem(18);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
&:hover {
|
|
358
|
-
background-color: rgba(colors.$neutral-dark-1, 0.1);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
&__footer {
|
|
363
|
-
display: flex;
|
|
364
|
-
justify-content: flex-end;
|
|
365
|
-
margin-top: sp.$space-lg;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
&__button {
|
|
369
|
-
font-size: fn.px-to-rem(12);
|
|
370
|
-
color: colors.$secondary-color;
|
|
371
|
-
|
|
372
|
-
&:not(:hover) {
|
|
373
|
-
text-decoration: underline;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
@include cp-toaster-style(colors.$secondary-color, 'info');
|
|
378
|
-
@include cp-toaster-style(colors.$warning-color, 'warning');
|
|
379
|
-
@include cp-toaster-style(colors.$success-color, 'success');
|
|
380
|
-
@include cp-toaster-style(colors.$error-color, 'critical');
|
|
381
|
-
}
|
|
382
|
-
</style>
|
package/src/plugins/toaster.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { App, h, render, VNode } from 'vue'
|
|
2
|
-
|
|
3
|
-
import CpToaster from '@/components/CpToaster.vue'
|
|
4
|
-
|
|
5
|
-
import { Intent } from '@/constants'
|
|
6
|
-
|
|
7
|
-
type MountOptions = {
|
|
8
|
-
app?: App | null
|
|
9
|
-
children?: unknown
|
|
10
|
-
element?: HTMLElement | null
|
|
11
|
-
props?: Record<string, unknown>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const createElement = () => (typeof document !== 'undefined' ? document.createElement('div') : null)
|
|
15
|
-
|
|
16
|
-
const mount = (component: unknown, { props, children, element, app }: MountOptions = {}) => {
|
|
17
|
-
let el: HTMLElement | null = element ? element : createElement()
|
|
18
|
-
|
|
19
|
-
// @ts-expect-error <comment on type error>
|
|
20
|
-
let vNode: VNode = h(component, props, children)
|
|
21
|
-
if (app && app._context) {
|
|
22
|
-
vNode.appContext = app._context
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
render(vNode, el as HTMLElement)
|
|
26
|
-
|
|
27
|
-
const destroy = () => {
|
|
28
|
-
if (el) {
|
|
29
|
-
render(null, el)
|
|
30
|
-
}
|
|
31
|
-
el = null
|
|
32
|
-
// @ts-expect-error explicit nulling for GC
|
|
33
|
-
vNode = null
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return { vNode, destroy, el }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const createToaster = (globalOptions: Record<string, unknown> = {}) => {
|
|
40
|
-
return {
|
|
41
|
-
show(options: Record<string, unknown> = {}) {
|
|
42
|
-
const localOptions = { ...options }
|
|
43
|
-
|
|
44
|
-
mount(CpToaster, {
|
|
45
|
-
props: { ...globalOptions, ...localOptions },
|
|
46
|
-
})
|
|
47
|
-
},
|
|
48
|
-
unique(options: Record<string, unknown> = {}) {
|
|
49
|
-
options.isUnique = true
|
|
50
|
-
return this.show(options)
|
|
51
|
-
},
|
|
52
|
-
success(options: Record<string, unknown> = {}) {
|
|
53
|
-
options.type = Intent.SUCCESS.value
|
|
54
|
-
return this.show(options)
|
|
55
|
-
},
|
|
56
|
-
critical(options: Record<string, unknown> = {}) {
|
|
57
|
-
options.type = Intent.CRITICAL.value
|
|
58
|
-
return this.show(options)
|
|
59
|
-
},
|
|
60
|
-
info(options: Record<string, unknown> = {}) {
|
|
61
|
-
options.type = Intent.INFO.value
|
|
62
|
-
return this.show(options)
|
|
63
|
-
},
|
|
64
|
-
warning(options: Record<string, unknown> = {}) {
|
|
65
|
-
options.type = Intent.WARNING.value
|
|
66
|
-
return this.show(options)
|
|
67
|
-
},
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export default createToaster
|