srcdev-nuxt-components 6.1.17 → 6.1.19

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.
@@ -1,8 +1,12 @@
1
1
  <template>
2
- <div class="display-prompt-core" :class="[{ dismissed: hide }]" :data-test-id="`display-prompt-core-${theme}`">
2
+ <div
3
+ class="display-prompt-core"
4
+ :class="[{ closed: !compopnentOpen }]"
5
+ :data-test-id="`display-prompt-core-${theme}`"
6
+ >
3
7
  <div class="display-prompt-wrapper" :data-theme="theme" :class="[elementClasses]" data-test-id="display-prompt">
4
8
  <div class="display-prompt-inner">
5
- <div class="display-prompt-icon" data-test-id="prompt-icon">
9
+ <div class="display-prompt-icon" data-test-id="prompt-icon" aria-hidden="true">
6
10
  <slot name="customDecoratorIcon">
7
11
  <Icon :name="displayPromptIcons[theme] ?? 'akar-icons:circle-alert'" class="icon" :color="iconColor" />
8
12
  </slot>
@@ -17,7 +21,7 @@
17
21
  </div>
18
22
  <button
19
23
  v-if="dismissible"
20
- @click.prevent="dismissPrompt()"
24
+ @click.prevent="updateComponentState()"
21
25
  data-test-id="display-prompt-action"
22
26
  class="display-prompt-action"
23
27
  >
@@ -70,12 +74,17 @@ const props = defineProps({
70
74
  })
71
75
 
72
76
  const slots = useSlots()
73
- const hide = ref(false)
77
+ const parentComponentState = defineModel<boolean>("parentComponentState", { default: false })
78
+ const compopnentOpen = ref(true)
74
79
  const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
75
80
 
76
- const dismissPrompt = () => {
77
- // styleClassPassthrough.value = '';
78
- hide.value = true
81
+ const updateComponentState = () => {
82
+ if (parentComponentState.value) {
83
+ parentComponentState.value = false
84
+ return
85
+ }
86
+
87
+ compopnentOpen.value = false
79
88
  }
80
89
  </script>
81
90
 
@@ -86,7 +95,7 @@ const dismissPrompt = () => {
86
95
  opacity: 1;
87
96
  transition: all 200ms ease-in-out;
88
97
 
89
- &.dismissed {
98
+ &.closed {
90
99
  grid-template-rows: 0fr;
91
100
  opacity: 0;
92
101
  pointer-events: none;
@@ -141,7 +150,7 @@ const dismissPrompt = () => {
141
150
  }
142
151
 
143
152
  .text {
144
- font-size: var(--step-5);
153
+ font-size: var(--step-4);
145
154
  font-weight: normal;
146
155
  line-height: 1.3;
147
156
  color: var(--colour-theme-8);
@@ -0,0 +1,361 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <div
4
+ v-if="privateToastState"
5
+ class="display-toast"
6
+ :class="[
7
+ elementClasses,
8
+ {
9
+ [theme]: !slots.default,
10
+ 'has-theme': !slots.default,
11
+ show: publicToastState && !isHiding && displayDurationInt === 0,
12
+ 'use-timer': displayDurationInt > 0,
13
+ hide: isHiding,
14
+ },
15
+ ]"
16
+ :data-theme="theme"
17
+ >
18
+ <slot v-if="slots.default"></slot>
19
+
20
+ <div v-else class="display-toast-inner">
21
+ <div class="toast-icon" aria-hidden="true">
22
+ <slot name="customToastIcon">
23
+ <Icon :name="defaultThemeIcons[props.theme] ?? 'akar-icons:info'" class="icon" />
24
+ </slot>
25
+ </div>
26
+ <div class="toast-message">{{ toastDisplayText }}</div>
27
+ <div class="toast-action">
28
+ <button @click.prevent="closeToast">
29
+ <Icon name="material-symbols:close" class="icon" />
30
+ <span class="sr-only">Close</span>
31
+ </button>
32
+ </div>
33
+ </div>
34
+ <div v-if="displayDurationInt > 0" @transitionend="closeToast()" class="display-toast-progress"></div>
35
+ </div>
36
+ </Teleport>
37
+ </template>
38
+ <script setup lang="ts">
39
+ const props = defineProps({
40
+ theme: {
41
+ type: String as PropType<"primary" | "secondary" | "tertiary" | "ghost" | "error" | "info" | "success" | "warning">,
42
+ default: "ghost",
43
+ validator(value: string) {
44
+ return ["primary", "secondary", "tertiary", "ghost", "error", "info", "success", "warning"].includes(value)
45
+ },
46
+ },
47
+ revealDuration: {
48
+ type: Number,
49
+ default: 3000,
50
+ },
51
+ duration: {
52
+ type: Number,
53
+ default: 5000,
54
+ },
55
+ toastDisplayText: {
56
+ type: String,
57
+ default: "",
58
+ },
59
+ styleClassPassthrough: {
60
+ type: Array as PropType<string[]>,
61
+ default: () => [],
62
+ },
63
+ })
64
+
65
+ const defaultThemeIcons = {
66
+ primary: "akar-icons:info",
67
+ secondary: "akar-icons:info",
68
+ tertiary: "akar-icons:info",
69
+ ghost: "akar-icons:info",
70
+ error: "akar-icons:circle-alert",
71
+ info: "akar-icons:info",
72
+ success: "akar-icons:info",
73
+ warning: "akar-icons:circle-alert",
74
+ }
75
+
76
+ const slots = useSlots()
77
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
78
+
79
+ const privateToastState = ref(false)
80
+ const isHiding = ref(false)
81
+ const publicToastState = defineModel<boolean>({ default: false })
82
+
83
+ const revealDurationInt = computed(() => props.revealDuration)
84
+ const revealDuration = computed(() => revealDurationInt.value + "ms")
85
+ const displayDurationInt = computed(() => props.duration)
86
+ const displayDuration = computed(() => displayDurationInt.value + "ms")
87
+
88
+ const progressDurationInt = computed(() => Math.floor(displayDurationInt.value - revealDurationInt.value / 2))
89
+ const progressDuration = computed(() => progressDurationInt.value + "ms")
90
+
91
+ const sendCloseEvent = () => {
92
+ publicToastState.value = false
93
+ privateToastState.value = false
94
+ isHiding.value = false
95
+ }
96
+
97
+ const closeToast = async () => {
98
+ isHiding.value = true
99
+ await useSleep(revealDurationInt.value)
100
+ sendCloseEvent()
101
+ }
102
+
103
+ watch(
104
+ () => props.styleClassPassthrough,
105
+ () => {
106
+ resetElementClasses(props.styleClassPassthrough)
107
+ }
108
+ )
109
+
110
+ watch(
111
+ () => publicToastState.value,
112
+ async (newValue, previousValue) => {
113
+ if (!previousValue && newValue) {
114
+ privateToastState.value = true
115
+
116
+ if (newValue && displayDurationInt.value > 0) {
117
+ await useSleep(displayDurationInt.value)
118
+ sendCloseEvent()
119
+ }
120
+ } else if (previousValue && !newValue) {
121
+ closeToast()
122
+ }
123
+ }
124
+ )
125
+ </script>
126
+
127
+ <style scoped lang="css">
128
+ @keyframes fade-in {
129
+ 5% {
130
+ opacity: 1;
131
+ visibility: visible;
132
+ transform: translateY(0);
133
+ }
134
+ 95% {
135
+ opacity: 1;
136
+ transform: translateY(0);
137
+ }
138
+ }
139
+
140
+ @keyframes show {
141
+ to {
142
+ opacity: 1;
143
+ visibility: visible;
144
+ transform: translateY(0);
145
+ }
146
+ }
147
+
148
+ @keyframes hide {
149
+ 0% {
150
+ opacity: 1;
151
+ visibility: visible;
152
+ transform: translateY(0);
153
+ }
154
+ 100% {
155
+ opacity: 0;
156
+ visibility: hidden;
157
+ transform: translateY(-30px);
158
+ }
159
+ }
160
+
161
+ @keyframes progress {
162
+ to {
163
+ transform: scaleX(1);
164
+ }
165
+ }
166
+
167
+ .display-toast {
168
+ display: block;
169
+ overflow: hidden;
170
+ position: fixed;
171
+ margin: 0;
172
+ opacity: 0;
173
+ visibility: hidden;
174
+
175
+ z-index: 100;
176
+
177
+ &.use-timer {
178
+ animation: fade-in v-bind(displayDuration) linear;
179
+ }
180
+
181
+ &.show {
182
+ animation: show v-bind(revealDuration)
183
+ linear(
184
+ 0,
185
+ 0.029 1.6%,
186
+ 0.123 3.5%,
187
+ 0.651 10.6%,
188
+ 0.862 14.1%,
189
+ 1.002 17.7%,
190
+ 1.046 19.6%,
191
+ 1.074 21.6%,
192
+ 1.087 23.9%,
193
+ 1.086 26.6%,
194
+ 1.014 38.5%,
195
+ 0.994 46.3%,
196
+ 1
197
+ )
198
+ forwards;
199
+ }
200
+
201
+ &.hide {
202
+ animation: hide v-bind(revealDuration)
203
+ linear(
204
+ 0,
205
+ 0.006 53.7%,
206
+ 0.986 61.5%,
207
+ 1.014 73.4%,
208
+ 1.087 76.1%,
209
+ 1.074 78.4%,
210
+ 1.046 80.4%,
211
+ 1.002 82.3%,
212
+ 0.862 85.9%,
213
+ 0.651 89.4%,
214
+ 0.123 96.5%,
215
+ 0.029 98.4%,
216
+ 0
217
+ )
218
+ forwards;
219
+ }
220
+
221
+ &:hover {
222
+ .display-toast-progress {
223
+ animation-play-state: paused;
224
+ }
225
+ }
226
+
227
+ &.full-width {
228
+ left: 24px;
229
+ right: 24px;
230
+ }
231
+
232
+ &:not(.full-width) {
233
+ &.left {
234
+ left: 24px;
235
+ }
236
+
237
+ &.right {
238
+ right: 24px;
239
+ }
240
+
241
+ &.center {
242
+ left: 50%;
243
+ /* transform: translateX(-50%); */
244
+ }
245
+ }
246
+
247
+ &.top {
248
+ top: 24px;
249
+ transform: translateY(-30px);
250
+ }
251
+ &.bottom {
252
+ bottom: 24px;
253
+ transform: translateY(30px);
254
+ }
255
+
256
+ /*
257
+ * Styles for the display toast component
258
+ */
259
+
260
+ &.has-theme {
261
+ padding-inline-start: 6px;
262
+ background-color: var(--colour-theme-8);
263
+
264
+ border: 0.1rem solid var(--colour-theme-8);
265
+ border-start-start-radius: 8px;
266
+ border-end-start-radius: 8px;
267
+ overflow: hidden;
268
+
269
+ .display-toast-inner {
270
+ display: grid;
271
+ grid-template-columns: auto 1fr auto;
272
+ gap: 12px;
273
+ align-items: center;
274
+ background-color: var(--gray-10);
275
+ border-start-start-radius: 8px;
276
+ border-end-start-radius: 8px;
277
+ padding: 12px 14px;
278
+ overflow: hidden;
279
+
280
+ .toast-icon {
281
+ display: inline-flex;
282
+ align-items: center;
283
+ justify-content: center;
284
+ margin-right: 12px;
285
+
286
+ .icon {
287
+ color: var(--colour-theme-0);
288
+ display: inline-block;
289
+ font-size: 2.5rem;
290
+ font-style: normal;
291
+ font-weight: normal;
292
+ overflow: hidden;
293
+ }
294
+ }
295
+
296
+ .toast-message {
297
+ display: flex;
298
+ align-items: center;
299
+ font-size: var(--step-4);
300
+ font-weight: normal;
301
+ line-height: 1.3;
302
+ color: var(--colour-theme-0);
303
+ margin: 0;
304
+ padding: 0;
305
+ }
306
+
307
+ .toast-action {
308
+ display: flex;
309
+ align-items: center;
310
+ justify-content: center;
311
+ margin-left: 12px;
312
+
313
+ button {
314
+ display: flex;
315
+ align-items: center;
316
+ justify-content: center;
317
+ background: var(--colour-theme-10);
318
+ border: 0.1rem solid var(--colour-theme-8);
319
+ outline: 0.1rem solid transparent;
320
+ border-radius: 50%;
321
+ box-shadow: none;
322
+ color: var(--colour-theme-0);
323
+ cursor: pointer;
324
+ font-size: var(--step-4);
325
+ font-weight: bold;
326
+ padding: 0.5rem;
327
+ text-decoration: underline;
328
+
329
+ transition: all 0.3s ease;
330
+
331
+ .icon {
332
+ font-size: 1.5rem;
333
+ vertical-align: middle;
334
+ }
335
+
336
+ &:hover {
337
+ box-shadow: none;
338
+ background-color: var(--colour-theme-8);
339
+ color: var(--colour-theme-0);
340
+ outline: 0.1rem solid var(--colour-theme-3);
341
+ outline-offset: 0.2rem;
342
+ }
343
+ }
344
+ }
345
+ }
346
+ }
347
+
348
+ .display-toast-progress {
349
+ position: absolute;
350
+ right: 8px;
351
+ bottom: 4px;
352
+ width: calc(100% - 16px);
353
+ height: 3px;
354
+ transform: scaleX(0);
355
+ transform-origin: right;
356
+ background: linear-gradient(to right, var(--colour-theme-2), var(--colour-theme-8));
357
+ border-radius: inherit;
358
+ animation: progress v-bind(progressDuration) linear forwards;
359
+ }
360
+ }
361
+ </style>
@@ -0,0 +1,8 @@
1
+ const useSleep = async (duration: number) => {
2
+ return new Promise((resolve) => {
3
+ setTimeout(() => {
4
+ resolve(true)
5
+ }, duration)
6
+ })
7
+ }
8
+ export default useSleep
@@ -0,0 +1,6 @@
1
+ export interface IToastConfig {
2
+ showToast: boolean
3
+ variant: string
4
+ duration: number
5
+ toastDisplayText: string
6
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "6.1.17",
4
+ "version": "6.1.19",
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",