srcdev-nuxt-components 9.1.54 → 9.1.56

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.
Files changed (101) hide show
  1. package/.claude/settings.json +29 -2
  2. package/.claude/skills/components/alert-content-inner.md +60 -0
  3. package/.claude/skills/components/display-dialog.md +80 -0
  4. package/.claude/skills/components/display-prompt.md +163 -0
  5. package/.claude/skills/components/display-toast.md +235 -0
  6. package/.claude/skills/index.md +7 -3
  7. package/.claude/skills/theming-colour-ramps.md +328 -0
  8. package/.claude/skills/theming-override-default.md +115 -186
  9. package/.claude/skills/theming-partial-override.md +88 -75
  10. package/README.md +166 -0
  11. package/app/app.config.ts +44 -0
  12. package/app/assets/styles/setup/01.config/_head.css +3 -3
  13. package/app/assets/styles/setup/02.colours/_amber.css +12 -10
  14. package/app/assets/styles/setup/02.colours/_blue.css +10 -9
  15. package/app/assets/styles/setup/02.colours/_green.css +12 -11
  16. package/app/assets/styles/setup/02.colours/_orange.css +12 -10
  17. package/app/assets/styles/setup/02.colours/_red.css +10 -9
  18. package/app/assets/styles/setup/02.colours/_slate.css +12 -11
  19. package/app/assets/styles/setup/02.colours/_sunset.css +12 -10
  20. package/app/assets/styles/setup/02.colours/_theme-params.css +18 -0
  21. package/app/assets/styles/setup/02.colours/index.css +1 -0
  22. package/app/assets/styles/setup/03.theming/_default.css +87 -0
  23. package/app/assets/styles/setup/03.theming/_error.css +14 -0
  24. package/app/assets/styles/setup/03.theming/_success.css +4 -0
  25. package/app/assets/styles/setup/03.theming/_theme-slots.css +16 -0
  26. package/app/assets/styles/setup/03.theming/_warning.css +13 -0
  27. package/app/assets/styles/setup/03.theming/index.css +6 -4
  28. package/app/assets/styles/setup/03.theming/theme-ramp.css +19 -0
  29. package/app/assets/styles/setup/04.elements/forms/00.element-defaults.css +0 -7
  30. package/app/assets/styles/setup/04.elements/forms/06.button-geometry.css +1 -1
  31. package/app/assets/styles/setup/index.css +1 -1
  32. package/app/components/01.atoms/display-dialog/DisplayDialog.vue +74 -24
  33. package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +148 -14
  34. package/app/components/01.atoms/display-dialog/tests/__snapshots__/DisplayDialog.spec.ts.snap +3 -3
  35. package/app/components/01.atoms/page-row/PageRow.vue +5 -0
  36. package/app/components/01.atoms/prompt/DisplayPrompt.vue +113 -0
  37. package/app/components/01.atoms/prompt/stories/DisplayPrompt.stories.ts +112 -0
  38. package/app/components/01.atoms/prompt/tests/DisplayPrompt.spec.ts +205 -0
  39. package/app/components/01.atoms/toast/DisplayToast.vue +327 -0
  40. package/app/components/01.atoms/toast/DisplayToastProvider.vue +362 -0
  41. package/app/components/01.atoms/toast/stories/DisplayToast.stories.ts +195 -0
  42. package/app/components/01.atoms/toast/stories/DisplayToastProvider.stories.ts +142 -0
  43. package/app/components/01.atoms/toast/tests/DisplayToast.spec.ts +266 -0
  44. package/app/components/01.atoms/toast/tests/DisplayToastProvider.spec.ts +256 -0
  45. package/app/components/02.molecules/action-menu/ActionMenu.vue +8 -1
  46. package/app/components/02.molecules/action-menu/ActionMenuItemCore.vue +11 -3
  47. package/app/components/02.molecules/alert-content/AlertContent.vue +67 -0
  48. package/app/components/02.molecules/alert-content/AlertContentInner.vue +153 -0
  49. package/app/components/02.molecules/alert-content/stories/AlertContent.stories.ts +131 -0
  50. package/app/components/02.molecules/alert-content/tests/AlertContent.spec.ts +135 -0
  51. package/app/components/02.molecules/alert-content/tests/AlertContentInner.spec.ts +135 -0
  52. package/app/components/02.molecules/alert-masked-content/AlertMaskedContent.vue +78 -0
  53. package/app/components/02.molecules/alert-masked-content/stories/AlertMaskedContent.stories.ts +132 -0
  54. package/app/components/02.molecules/alert-masked-content/tests/AlertMaskedContent.spec.ts +149 -0
  55. package/app/components/05.forms/input-button/InputButtonCore.vue +35 -39
  56. package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue +8 -8
  57. package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue +5 -5
  58. package/app/components/05.forms/input-copy/InputCopyCore.vue +7 -7
  59. package/app/components/05.forms/input-number/InputNumberCore.vue +5 -5
  60. package/app/components/05.forms/input-select/InputSelectCore.vue +6 -6
  61. package/app/components/05.forms/input-text/InputTextCore.vue +6 -6
  62. package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +2 -2
  63. package/app/components/05.forms/input-textarea/InputTextareaCore.vue +5 -5
  64. package/app/components/05.forms/pending-effect/PendingEffect.vue +60 -60
  65. package/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue +10 -10
  66. package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +4 -4
  67. package/app/components/display-theme-switch/DisplayThemeSwitch.vue +4 -4
  68. package/app/components/display-tooltip/DisplayTooltip.vue +4 -4
  69. package/app/composables/useBodyLock.ts +21 -0
  70. package/app/composables/useDialogControls.ts +11 -11
  71. package/app/composables/useToastQueue.ts +39 -0
  72. package/app/layouts/default.vue +1 -1
  73. package/app/pages/ui/display-dialog.vue +275 -127
  74. package/app/pages/ui/display-prompt.vue +255 -52
  75. package/app/pages/ui/display-toast.vue +278 -299
  76. package/app/pages/ui/mask-element.vue +25 -3
  77. package/app/pages/ui/settings.vue +9 -35
  78. package/app/types/app-config.d.ts +41 -0
  79. package/app/types/components/display-prompt.d.ts +11 -0
  80. package/app/types/components/display-toast.d.ts +11 -9
  81. package/app/types/components/index.ts +2 -0
  82. package/app/types/components/semantic-theme.d.ts +1 -0
  83. package/nuxt.config.ts +16 -0
  84. package/package.json +6 -4
  85. package/app/assets/styles/setup/03.theming/default/_dark.css +0 -156
  86. package/app/assets/styles/setup/03.theming/default/_light.css +0 -166
  87. package/app/assets/styles/setup/03.theming/default/index.css +0 -2
  88. package/app/assets/styles/setup/03.theming/error/_dark.css +0 -56
  89. package/app/assets/styles/setup/03.theming/error/_light.css +0 -74
  90. package/app/assets/styles/setup/03.theming/error/index.css +0 -2
  91. package/app/assets/styles/setup/03.theming/success/_dark.css +0 -50
  92. package/app/assets/styles/setup/03.theming/success/_light.css +0 -65
  93. package/app/assets/styles/setup/03.theming/success/index.css +0 -2
  94. package/app/assets/styles/setup/03.theming/warning/_dark.css +0 -50
  95. package/app/assets/styles/setup/03.theming/warning/_light.css +0 -64
  96. package/app/assets/styles/setup/03.theming/warning/index.css +0 -2
  97. package/app/components/display-prompt/DisplayPromptCore.vue +0 -228
  98. package/app/components/display-prompt/variants/DisplayPromptError.vue +0 -53
  99. package/app/components/display-toast/DisplayToast.vue +0 -447
  100. package/app/components/display-toast/molecules/DefaultToastContent.vue +0 -163
  101. package/app/components/display-toast/stories/DisplayToast.stories.ts +0 -380
@@ -1,447 +0,0 @@
1
- <template>
2
- <Teleport to="body">
3
- <div
4
- v-if="privateDisplayToast"
5
- ref="toastElementRef"
6
- class="display-toast"
7
- :class="[
8
- elementClasses,
9
- cssStateClass,
10
- positionClasses,
11
- {
12
- 'has-theme': !slots.default,
13
- },
14
- ]"
15
- :data-theme="theme"
16
- :role="toastRole"
17
- :aria-live="ariaLive"
18
- :tabindex="slots.default ? undefined : '0'"
19
- :aria-describedby="slots.default ? undefined : 'toast-message-' + toastId"
20
- @keydown.escape="setDismissToast"
21
- >
22
- <slot v-if="slots.default"></slot>
23
-
24
- <DefaultToastContent
25
- v-else
26
- :theme="theme"
27
- :custom-icon="customIcon"
28
- :toast-id="toastId"
29
- :toast-display-text="toastDisplayText"
30
- :toast-title="toastTitle"
31
- :toast-description="toastDescription"
32
- :auto-dismiss="autoDismiss"
33
- :set-dismiss-toast="setDismissToast"
34
- >
35
- <template #customToastIcon>
36
- <slot name="customToastIcon"></slot>
37
- </template>
38
- <template #title>
39
- <slot name="title"></slot>
40
- </template>
41
- <template #description>
42
- <slot name="description"></slot>
43
- </template>
44
- </DefaultToastContent>
45
- <div v-if="autoDismiss" class="display-toast-progress"></div>
46
- </div>
47
- </Teleport>
48
- </template>
49
-
50
- <script setup lang="ts">
51
- import type {
52
- DisplayToastConfig,
53
- DisplayToastTheme,
54
- DisplayToastPosition,
55
- DisplayToastAlignment,
56
- ToastSlots,
57
- } from "../../types/components";
58
-
59
- const props = defineProps({
60
- config: {
61
- type: Object as PropType<DisplayToastConfig>,
62
- default: () => ({
63
- appearance: {
64
- theme: "ghost" as DisplayToastTheme,
65
- position: "top" as DisplayToastPosition,
66
- alignment: "right" as DisplayToastAlignment,
67
- fullWidth: false,
68
- },
69
- behavior: {
70
- autoDismiss: true,
71
- duration: 5000,
72
- revealDuration: 550,
73
- },
74
- content: {
75
- text: "",
76
- customIcon: undefined,
77
- },
78
- }),
79
- },
80
- styleClassPassthrough: {
81
- type: [String, Array] as PropType<string | string[]>,
82
- default: () => [],
83
- },
84
- });
85
-
86
- const slots = defineSlots<ToastSlots>();
87
-
88
- const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
89
-
90
- // Computed properties for accessing config values with defaults
91
- const theme = computed(() => props.config?.appearance?.theme ?? "ghost");
92
- const position = computed(() => props.config?.appearance?.position ?? "top");
93
- const alignment = computed(() => props.config?.appearance?.alignment ?? "right");
94
- const fullWidth = computed(() => props.config?.appearance?.fullWidth ?? false);
95
- const autoDismiss = computed(() => props.config?.behavior?.autoDismiss ?? true);
96
- const duration = computed(() => props.config?.behavior?.duration ?? 5000);
97
- const revealDuration = computed(() => props.config?.behavior?.revealDuration ?? 550);
98
- const returnFocusTo = computed(() => props.config?.behavior?.returnFocusTo ?? null);
99
- const toastDisplayText = computed(() => props.config?.content?.text ?? "");
100
- const toastTitle = computed(() => props.config?.content?.title ?? "");
101
- const toastDescription = computed(() => props.config?.content?.description ?? "");
102
- const customIcon = computed(() => props.config?.content?.customIcon);
103
-
104
- // Computed classes for positioning
105
- const positionClasses = computed(() => {
106
- const classes = [];
107
- classes.push(position.value);
108
- if (fullWidth.value) {
109
- classes.push("full-width");
110
- } else {
111
- classes.push(alignment.value);
112
- }
113
- return classes;
114
- });
115
-
116
- /*
117
- * Accessibility setup
118
- */
119
- const toastId = useId();
120
- const toastElementRef = useTemplateRef<HTMLElement>("toastElementRef");
121
-
122
- // Determine appropriate ARIA attributes based on theme
123
- const toastRole = computed(() => {
124
- return ["error", "warning"].includes(theme.value) ? "alert" : "status";
125
- });
126
-
127
- const ariaLive = computed(() => {
128
- return ["error", "warning"].includes(theme.value) ? "assertive" : "polite";
129
- });
130
-
131
- /*
132
- * Setup component state
133
- */
134
- const externalTriggerModel = defineModel<boolean>({ default: false });
135
- const privateDisplayToast = ref(false);
136
- const transitionalState = ref(false);
137
- const cssStateClass = computed(() => {
138
- return transitionalState.value ? "show" : "hide";
139
- });
140
-
141
- /*
142
- * Computed properties for durations (in ms for CSS)
143
- */
144
- const revealDurationMs = computed(() => revealDuration.value + "ms");
145
- const displayDurationMs = computed(() => duration.value + "ms");
146
-
147
- /*
148
- * Lifecycle hooks
149
- */
150
- const setDismissToast = async () => {
151
- transitionalState.value = false;
152
- await useSleep(revealDuration.value);
153
-
154
- // Return focus to specified element if provided
155
- if (returnFocusTo.value) {
156
- // Handle both HTMLElement and ComponentPublicInstance
157
- let focusTarget: HTMLElement | null = null;
158
-
159
- if (returnFocusTo.value instanceof HTMLElement) {
160
- focusTarget = returnFocusTo.value;
161
- } else if (returnFocusTo.value && "$el" in returnFocusTo.value) {
162
- focusTarget = returnFocusTo.value.$el as HTMLElement;
163
- }
164
-
165
- if (focusTarget && typeof focusTarget.focus === "function") {
166
- focusTarget.focus();
167
- }
168
- }
169
-
170
- externalTriggerModel.value = false;
171
- privateDisplayToast.value = false;
172
- };
173
-
174
- watch(
175
- () => props.styleClassPassthrough,
176
- () => {
177
- resetElementClasses(props.styleClassPassthrough);
178
- }
179
- );
180
-
181
- watch(
182
- () => externalTriggerModel.value,
183
- async (newValue, previousValue) => {
184
- if (newValue) {
185
- privateDisplayToast.value = true;
186
- transitionalState.value = true;
187
-
188
- // Focus management for accessibility when not using custom slots
189
- if (!slots.default) {
190
- await nextTick();
191
- // Wait for animation to start before focusing
192
- setTimeout(() => {
193
- toastElementRef.value?.focus();
194
- }, 100);
195
- }
196
-
197
- if (autoDismiss.value) {
198
- await useSleep(duration.value);
199
- setDismissToast();
200
- }
201
- } else if (!newValue && previousValue) {
202
- // If external model is set to false, dismiss the toast
203
- setDismissToast();
204
- }
205
- }
206
- );
207
-
208
- onBeforeRouteLeave(() => {
209
- setDismissToast();
210
- });
211
- </script>
212
-
213
- <style lang="css">
214
- @layer components {
215
- @keyframes show {
216
- to {
217
- opacity: 1;
218
- transform: translateY(0);
219
- }
220
- }
221
-
222
- @keyframes hideTop {
223
- 0% {
224
- opacity: 1;
225
- transform: translateY(0);
226
- }
227
- 100% {
228
- opacity: 0;
229
- transform: translateY(-30px);
230
- }
231
- }
232
-
233
- @keyframes hideBottom {
234
- 0% {
235
- opacity: 1;
236
- transform: translateY(0);
237
- }
238
- 100% {
239
- opacity: 0;
240
- transform: translateY(30px);
241
- }
242
- }
243
-
244
- @keyframes progress {
245
- to {
246
- transform: scaleX(1);
247
- }
248
- }
249
-
250
- .display-toast {
251
- --_toast-gutter: 12px;
252
- @media (width >= 600px) {
253
- --_toast-gutter: 24px;
254
- }
255
-
256
- display: block;
257
- overflow: hidden;
258
- position: fixed;
259
- margin: 0;
260
- opacity: 0;
261
-
262
- z-index: 100;
263
-
264
- /* Focus styles for accessibility */
265
- &:focus {
266
- outline: 2px solid var(--colour-theme-3, #007acc);
267
- outline-offset: 2px;
268
- }
269
-
270
- &:focus:not(:focus-visible) {
271
- outline: none;
272
- }
273
-
274
- &.show {
275
- @supports (animation-timing-function: linear(0, 1)) {
276
- animation: show v-bind(revealDurationMs) var(--spring-easing) forwards;
277
- }
278
-
279
- @supports not (animation-timing-function: linear(0, 1)) {
280
- animation: show calc(v-bind(revealDurationMs) / 2) linear forwards;
281
- }
282
- }
283
-
284
- &.hide {
285
- @supports (animation-timing-function: linear(0, 1)) {
286
- animation: hideTop v-bind(revealDurationMs) var(--spring-easing) forwards;
287
- }
288
-
289
- @supports not (animation-timing-function: linear(0, 1)) {
290
- animation: hideTop calc(v-bind(revealDurationMs) / 2) linear forwards;
291
- }
292
-
293
- &.bottom {
294
- @supports (animation-timing-function: linear(0, 1)) {
295
- animation: hideBottom v-bind(revealDurationMs) var(--spring-easing) forwards;
296
- }
297
-
298
- @supports not (animation-timing-function: linear(0, 1)) {
299
- animation: hideBottom calc(v-bind(revealDurationMs) / 2) linear forwards;
300
- }
301
- }
302
- }
303
-
304
- /*
305
- * Default is centre for smaller screens
306
- */
307
- inset-inline: var(--_toast-gutter);
308
- margin-inline: auto;
309
-
310
- @media (width >= 600px) {
311
- &.left {
312
- inset-inline-start: var(--_toast-gutter);
313
- inset-inline-end: unset;
314
- }
315
-
316
- &.right {
317
- inset-inline-end: var(--_toast-gutter);
318
- inset-inline-start: unset;
319
- }
320
-
321
- &.center {
322
- &:not(.full-width) {
323
- inset-inline: 0;
324
- margin-inline: auto;
325
- width: max-content;
326
- }
327
- }
328
- }
329
-
330
- &.top {
331
- inset-block-start: var(--_toast-gutter);
332
- transform: translateY(-30px);
333
- }
334
- &.bottom {
335
- inset-block-end: var(--_toast-gutter);
336
- transform: translateY(30px);
337
- }
338
-
339
- /*
340
- * Styles for the display toast component if slot is empty
341
- */
342
- &.has-theme {
343
- padding-inline-start: 6px;
344
- background-color: var(--colour-theme-8);
345
-
346
- border: 0.1rem solid var(--colour-theme-8);
347
- border-start-start-radius: 8px;
348
- border-end-start-radius: 8px;
349
- border-start-end-radius: 4px;
350
- border-end-end-radius: 4px;
351
-
352
- overflow: hidden;
353
-
354
- /* .display-toast-inner {
355
- display: grid;
356
- grid-template-columns: auto 1fr auto;
357
- gap: 12px;
358
- align-items: center;
359
- background-color: var(--slate-10);
360
- border-start-start-radius: 8px;
361
- border-end-start-radius: 8px;
362
- padding: 12px 14px;
363
- overflow: hidden;
364
-
365
- .toast-icon {
366
- display: inline-flex;
367
- align-items: center;
368
- justify-content: center;
369
- margin-right: 12px;
370
-
371
- .icon {
372
- color: var(--colour-theme-0);
373
- display: inline-block;
374
- font-size: 2.5rem;
375
- font-style: normal;
376
- font-weight: normal;
377
- overflow: hidden;
378
- }
379
- }
380
-
381
- .toast-message {
382
- display: flex;
383
- align-items: center;
384
- font-size: var(--step-4);
385
- font-weight: normal;
386
- line-height: 1.3;
387
- color: var(--colour-theme-0);
388
- margin: 0;
389
- padding: 0;
390
- }
391
-
392
- .toast-action {
393
- display: flex;
394
- align-items: center;
395
- justify-content: center;
396
- margin-left: 12px;
397
-
398
- button {
399
- display: flex;
400
- align-items: center;
401
- justify-content: center;
402
- background: var(--colour-theme-10);
403
- border: 0.1rem solid var(--colour-theme-8);
404
- outline: 0.1rem solid transparent;
405
- border-radius: 50%;
406
- box-shadow: none;
407
- color: var(--colour-theme-0);
408
- cursor: pointer;
409
- font-size: var(--step-4);
410
- font-weight: bold;
411
- padding: 0.5rem;
412
- text-decoration: underline;
413
-
414
- transition: all 0.3s ease;
415
-
416
- .icon {
417
- font-size: 1.5rem;
418
- vertical-align: middle;
419
- }
420
-
421
- &:hover,
422
- &:focus-visible {
423
- box-shadow: none;
424
- background-color: var(--colour-theme-8);
425
- color: var(--colour-theme-0);
426
- outline: 0.1rem solid var(--colour-theme-3);
427
- outline-offset: 0.2rem;
428
- }
429
- }
430
- }
431
- } */
432
- }
433
-
434
- .display-toast-progress {
435
- position: absolute;
436
- inset-block-end: 4px;
437
- inset-inline: 15px 8px;
438
- height: 3px;
439
- transform: scaleX(0);
440
- transform-origin: right;
441
- background: linear-gradient(to right, var(--colour-theme-2), var(--colour-theme-8));
442
- border-radius: inherit;
443
- animation: progress v-bind(displayDurationMs) linear forwards;
444
- }
445
- }
446
- }
447
- </style>
@@ -1,163 +0,0 @@
1
- <template>
2
- <div class="display-toast-inner">
3
- <div class="toast-icon" aria-hidden="true">
4
- <slot name="customToastIcon">
5
- <Icon :name="customIcon || defaultThemeIcons[theme] || 'akar-icons:info'" class="icon" />
6
- </slot>
7
- </div>
8
- <div :id="'toast-message-' + toastId" class="toast-message">
9
- <template v-if="slots.title || slots.description || toastTitle || toastDescription">
10
- <p v-if="slots.title || toastTitle" class="title" data-test-id="toast-title">
11
- <slot name="title">{{ toastTitle }}</slot>
12
- </p>
13
- <p v-if="slots.description || toastDescription" class="description" data-test-id="toast-description">
14
- <slot name="description">{{ toastDescription }}</slot>
15
- </p>
16
- </template>
17
- <template v-else>
18
- {{ toastDisplayText }}
19
- </template>
20
- </div>
21
-
22
- <div v-if="!autoDismiss" class="toast-action">
23
- <button @click.prevent="setDismissToast()">
24
- <Icon name="material-symbols:close" class="icon" />
25
- <span class="sr-only">Close</span>
26
- </button>
27
- </div>
28
- </div>
29
- </template>
30
-
31
- <script setup lang="ts">
32
- import type { DisplayToastTheme } from "../../../types/components";
33
-
34
- interface Props {
35
- theme: DisplayToastTheme;
36
- customIcon?: string;
37
- toastId: string;
38
- toastDisplayText: string;
39
- toastTitle?: string;
40
- toastDescription?: string;
41
- autoDismiss: boolean;
42
- setDismissToast: () => void;
43
- }
44
-
45
- defineProps<Props>();
46
-
47
- const defaultThemeIcons = {
48
- primary: "akar-icons:info",
49
- secondary: "akar-icons:info",
50
- tertiary: "akar-icons:info",
51
- ghost: "akar-icons:info",
52
- error: "akar-icons:circle-alert",
53
- info: "akar-icons:info",
54
- success: "akar-icons:info",
55
- warning: "akar-icons:circle-alert",
56
- };
57
-
58
- const slots = useSlots();
59
- </script>
60
-
61
- <style lang="css">
62
- @layer components {
63
- .display-toast-inner {
64
- display: grid;
65
- grid-template-columns: auto 1fr auto;
66
- gap: 12px;
67
- align-items: center;
68
- background-color: var(--colour-theme-1);
69
- border-start-start-radius: 8px;
70
- border-end-start-radius: 8px;
71
- padding: 12px 14px;
72
- overflow: hidden;
73
-
74
- .toast-icon {
75
- display: inline-flex;
76
- align-items: center;
77
- justify-content: center;
78
- margin-right: 12px;
79
-
80
- .icon {
81
- color: var(--colour-theme-0);
82
- display: inline-block;
83
- font-size: 2.5rem;
84
- font-style: normal;
85
- font-weight: normal;
86
- overflow: hidden;
87
- }
88
- }
89
-
90
- .toast-message {
91
- display: flex;
92
- align-items: center;
93
- gap: var(--step-1);
94
- font-size: var(--step-4);
95
- font-weight: normal;
96
- line-height: 1.3;
97
- color: var(--colour-theme-0);
98
- margin: 0;
99
- padding: 0;
100
-
101
- .title {
102
- margin: 0;
103
- font-weight: 600;
104
- font-size: var(--step-4);
105
- line-height: 1.2;
106
- }
107
-
108
- .description {
109
- margin: 0;
110
- font-size: var(--step-3);
111
- line-height: 1.4;
112
- opacity: 0.9;
113
- }
114
-
115
- /* When using slots, change flex direction to column */
116
- &:has(.title, .text) {
117
- flex-direction: column;
118
- align-items: flex-start;
119
- }
120
- }
121
-
122
- .toast-action {
123
- display: flex;
124
- align-items: center;
125
- justify-content: center;
126
- margin-left: 12px;
127
-
128
- button {
129
- display: flex;
130
- align-items: center;
131
- justify-content: center;
132
- background: var(--colour-theme-10);
133
- border: 0.1rem solid var(--colour-theme-8);
134
- outline: 0.1rem solid transparent;
135
- border-radius: 50%;
136
- box-shadow: none;
137
- color: var(--colour-theme-1);
138
- cursor: pointer;
139
- font-size: var(--step-4);
140
- font-weight: bold;
141
- padding: 0.5rem;
142
- text-decoration: underline;
143
-
144
- transition: all 0.3s ease;
145
-
146
- .icon {
147
- font-size: 1.5rem;
148
- vertical-align: middle;
149
- }
150
-
151
- &:hover,
152
- &:focus-visible {
153
- box-shadow: none;
154
- background-color: var(--colour-theme-8);
155
- color: var(--colour-theme-0);
156
- outline: 0.1rem solid var(--colour-theme-3);
157
- outline-offset: 0.2rem;
158
- }
159
- }
160
- }
161
- }
162
- }
163
- </style>