srcdev-nuxt-components 6.2.13 → 6.3.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.
@@ -8,8 +8,8 @@
8
8
  </mask>
9
9
  </defs>
10
10
 
11
- <path :d="outerPath" :fill="cfg.color" mask="url(#borderMask)" vector-effect="non-scaling-stroke" />
12
- <path :d="innerPath" fill="rgba(0,0,0,0.5)" />
11
+ <path :d="outerPath" :fill="cfg.borderColour" mask="url(#borderMask)" vector-effect="non-scaling-stroke" />
12
+ <path :d="innerPath" :fill="cfg.backgroundColour" />
13
13
  </svg>
14
14
 
15
15
  <div
@@ -28,21 +28,11 @@
28
28
  </div>
29
29
  </template>
30
30
 
31
- <script lang="ts">
32
- export interface BorderConfig {
33
- color?: string
34
- radiusLeft?: number
35
- radiusRight?: number
36
- borderLeft?: number
37
- borderTop?: number
38
- borderRight?: number
39
- borderBottom?: number
40
- }
41
- </script>
42
-
43
31
  <script setup lang="ts">
32
+ import type { AlertMaskConfig } from "../../types/components/alert-mask-core"
33
+
44
34
  const props = defineProps({
45
- config: Object as PropType<BorderConfig>,
35
+ config: Object as PropType<AlertMaskConfig>,
46
36
  styleClassPassthrough: {
47
37
  type: [String, Array] as PropType<string | string[]>,
48
38
  default: () => [],
@@ -81,7 +71,8 @@ onMounted(() => {
81
71
  })
82
72
 
83
73
  const cfg = computed(() => ({
84
- color: props.config?.color ?? "var(--orange-8)",
74
+ backgroundColour: props.config?.backgroundColour ?? "rgba(0,0,0,0.25)",
75
+ borderColour: props.config?.borderColour ?? "var(--orange-8)",
85
76
  radiusLeft: props.config?.radiusLeft ?? 12,
86
77
  radiusRight: props.config?.radiusRight ?? 12,
87
78
  borderLeft: props.config?.borderLeft ?? 8,
@@ -6,7 +6,7 @@
6
6
  ref="promptElementRef"
7
7
  tabindex="0"
8
8
  >
9
- <div class="display-prompt-wrapper" :data-theme="theme" :class="[elementClasses]" data-test-id="display-prompt">
9
+ <div class="display-prompt-wrapper" :class="[theme, elementClasses]" data-test-id="display-prompt">
10
10
  <div class="display-prompt-inner">
11
11
  <div class="display-prompt-icon" data-test-id="prompt-icon" aria-hidden="true">
12
12
  <slot name="customDecoratorIcon">
@@ -197,7 +197,9 @@ onMounted(async () => {
197
197
  border-radius: 50%;
198
198
  outline: 1px solid var(--colour-theme-3);
199
199
 
200
- transition: border 200ms ease-in-out, outline 200ms ease-in-out;
200
+ transition:
201
+ border 200ms ease-in-out,
202
+ outline 200ms ease-in-out;
201
203
 
202
204
  &:hover {
203
205
  cursor: pointer;
@@ -8,11 +8,11 @@
8
8
  elementClasses,
9
9
  cssStateClass,
10
10
  positionClasses,
11
+ theme,
11
12
  {
12
13
  'has-theme': !slots.default,
13
14
  },
14
15
  ]"
15
- :data-theme="theme"
16
16
  :role="toastRole"
17
17
  :aria-live="ariaLive"
18
18
  :tabindex="slots.default ? undefined : '0'"
@@ -21,102 +21,41 @@
21
21
  >
22
22
  <slot v-if="slots.default"></slot>
23
23
 
24
- <div v-else class="display-toast-inner">
25
- <div class="toast-icon" aria-hidden="true">
26
- <slot name="customToastIcon">
27
- <Icon :name="customIcon || defaultThemeIcons[theme] || 'akar-icons:info'" class="icon" />
28
- </slot>
29
- </div>
30
- <div class="toast-message" :id="'toast-message-' + toastId">{{ toastDisplayText }}</div>
31
- <div v-if="!autoDismiss" class="toast-action">
32
- <button @click.prevent="setDismissToast()">
33
- <Icon name="material-symbols:close" class="icon" />
34
- <span class="sr-only">Close</span>
35
- </button>
36
- </div>
37
- </div>
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" />
37
+ </template>
38
+ <template #title>
39
+ <slot name="title" />
40
+ </template>
41
+ <template #description>
42
+ <slot name="description" />
43
+ </template>
44
+ </DefaultToastContent>
38
45
  <div v-if="autoDismiss" class="display-toast-progress"></div>
39
46
  </div>
40
47
  </Teleport>
41
48
  </template>
42
49
 
43
- <script lang="ts">
44
- /**
45
- * DisplayToast - Configurable toast notification component
46
- *
47
- * Example usage with config object:
48
- * <DisplayToast
49
- * v-model="showToast"
50
- * :config="{
51
- * appearance: { theme: 'success', position: 'top', alignment: 'right' },
52
- * behavior: { autoDismiss: true, duration: 3000, returnFocusTo: buttonRef },
53
- * content: { text: 'Operation completed successfully!' }
54
- * }"
55
- * />
56
- *
57
- * The returnFocusTo property accepts an HTMLElement or ComponentPublicInstance
58
- * and will focus that element when the toast is dismissed for better accessibility.
59
- *
60
- * Types exported for use in other components:
61
- * - DisplayToastConfig
62
- * - DisplayToastProps
63
- * - DisplayToastTheme
64
- * - DisplayToastAppearanceConfig
65
- * - DisplayToastBehaviorConfig
66
- * - DisplayToastContentConfig
67
- * - ToastSlots
68
- */
69
-
70
- export type DisplayToastTheme =
71
- | "primary"
72
- | "secondary"
73
- | "tertiary"
74
- | "ghost"
75
- | "error"
76
- | "info"
77
- | "success"
78
- | "warning"
79
-
80
- export type DisplayToastPosition = "top" | "bottom"
81
- export type DisplayToastAlignment = "left" | "center" | "right"
82
-
83
- export interface DisplayToastAppearanceConfig {
84
- theme?: DisplayToastTheme
85
- position?: DisplayToastPosition
86
- alignment?: DisplayToastAlignment
87
- fullWidth?: boolean
88
- }
89
-
90
- export interface DisplayToastBehaviorConfig {
91
- autoDismiss?: boolean
92
- duration?: number
93
- revealDuration?: number
94
- returnFocusTo?: HTMLElement | ComponentPublicInstance | null
95
- }
96
-
97
- export interface DisplayToastContentConfig {
98
- text?: string
99
- customIcon?: string
100
- }
101
-
102
- export interface DisplayToastConfig {
103
- appearance?: DisplayToastAppearanceConfig
104
- behavior?: DisplayToastBehaviorConfig
105
- content?: DisplayToastContentConfig
106
- }
107
-
108
- export interface DisplayToastProps {
109
- config?: DisplayToastConfig
110
- styleClassPassthrough?: string | string[]
111
- }
112
-
113
- export interface ToastSlots {
114
- default?(props?: {}): any
115
- customToastIcon?(props?: {}): any
116
- }
117
- </script>
118
-
119
50
  <script setup lang="ts">
51
+ import type {
52
+ DisplayToastProps,
53
+ DisplayToastTheme,
54
+ DisplayToastPosition,
55
+ DisplayToastAlignment,
56
+ ToastSlots,
57
+ } from "../../types/components/display-toast.d"
58
+
120
59
  const props = withDefaults(defineProps<DisplayToastProps>(), {
121
60
  config: () => ({
122
61
  appearance: {
@@ -140,17 +79,6 @@ const props = withDefaults(defineProps<DisplayToastProps>(), {
140
79
 
141
80
  const slots = defineSlots<ToastSlots>()
142
81
 
143
- const defaultThemeIcons = {
144
- primary: "akar-icons:info",
145
- secondary: "akar-icons:info",
146
- tertiary: "akar-icons:info",
147
- ghost: "akar-icons:info",
148
- error: "akar-icons:circle-alert",
149
- info: "akar-icons:info",
150
- success: "akar-icons:info",
151
- warning: "akar-icons:circle-alert",
152
- }
153
-
154
82
  const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
155
83
 
156
84
  // Computed properties for accessing config values with defaults
@@ -163,6 +91,8 @@ const duration = computed(() => props.config?.behavior?.duration ?? 5000)
163
91
  const revealDuration = computed(() => props.config?.behavior?.revealDuration ?? 550)
164
92
  const returnFocusTo = computed(() => props.config?.behavior?.returnFocusTo ?? null)
165
93
  const toastDisplayText = computed(() => props.config?.content?.text ?? "")
94
+ const toastTitle = computed(() => props.config?.content?.title ?? "")
95
+ const toastDescription = computed(() => props.config?.content?.description ?? "")
166
96
  const customIcon = computed(() => props.config?.content?.customIcon)
167
97
 
168
98
  // Computed classes for positioning
@@ -414,7 +344,7 @@ onBeforeRouteLeave(() => {
414
344
 
415
345
  overflow: hidden;
416
346
 
417
- .display-toast-inner {
347
+ /* .display-toast-inner {
418
348
  display: grid;
419
349
  grid-template-columns: auto 1fr auto;
420
350
  gap: 12px;
@@ -491,7 +421,7 @@ onBeforeRouteLeave(() => {
491
421
  }
492
422
  }
493
423
  }
494
- }
424
+ } */
495
425
  }
496
426
 
497
427
  .display-toast-progress {
@@ -0,0 +1,165 @@
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 class="toast-message" :id="'toast-message-' + toastId">
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/display-toast.d"
33
+
34
+ interface DefaultToastContentProps {
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
+ const props = defineProps<DefaultToastContentProps>()
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 = defineSlots<{
59
+ customToastIcon?: () => any
60
+ title?: () => any
61
+ description?: () => any
62
+ }>()
63
+ </script>
64
+
65
+ <style lang="css">
66
+ .display-toast-inner {
67
+ display: grid;
68
+ grid-template-columns: auto 1fr auto;
69
+ gap: 12px;
70
+ align-items: center;
71
+ background-color: var(--gray-10);
72
+ border-start-start-radius: 8px;
73
+ border-end-start-radius: 8px;
74
+ padding: 12px 14px;
75
+ overflow: hidden;
76
+
77
+ .toast-icon {
78
+ display: inline-flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ margin-right: 12px;
82
+
83
+ .icon {
84
+ color: var(--colour-theme-0);
85
+ display: inline-block;
86
+ font-size: 2.5rem;
87
+ font-style: normal;
88
+ font-weight: normal;
89
+ overflow: hidden;
90
+ }
91
+ }
92
+
93
+ .toast-message {
94
+ display: flex;
95
+ align-items: center;
96
+ gap: var(--step-1);
97
+ font-size: var(--step-4);
98
+ font-weight: normal;
99
+ line-height: 1.3;
100
+ color: var(--colour-theme-0);
101
+ margin: 0;
102
+ padding: 0;
103
+
104
+ .title {
105
+ margin: 0;
106
+ font-weight: 600;
107
+ font-size: var(--step-4);
108
+ line-height: 1.2;
109
+ }
110
+
111
+ .description {
112
+ margin: 0;
113
+ font-size: var(--step-3);
114
+ line-height: 1.4;
115
+ opacity: 0.9;
116
+ }
117
+
118
+ /* When using slots, change flex direction to column */
119
+ &:has(.title, .text) {
120
+ flex-direction: column;
121
+ align-items: flex-start;
122
+ }
123
+ }
124
+
125
+ .toast-action {
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ margin-left: 12px;
130
+
131
+ button {
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ background: var(--colour-theme-10);
136
+ border: 0.1rem solid var(--colour-theme-8);
137
+ outline: 0.1rem solid transparent;
138
+ border-radius: 50%;
139
+ box-shadow: none;
140
+ color: var(--colour-theme-0);
141
+ cursor: pointer;
142
+ font-size: var(--step-4);
143
+ font-weight: bold;
144
+ padding: 0.5rem;
145
+ text-decoration: underline;
146
+
147
+ transition: all 0.3s ease;
148
+
149
+ .icon {
150
+ font-size: 1.5rem;
151
+ vertical-align: middle;
152
+ }
153
+
154
+ &:hover,
155
+ &:focus-visible {
156
+ box-shadow: none;
157
+ background-color: var(--colour-theme-8);
158
+ color: var(--colour-theme-0);
159
+ outline: 0.1rem solid var(--colour-theme-3);
160
+ outline-offset: 0.2rem;
161
+ }
162
+ }
163
+ }
164
+ }
165
+ </style>
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <div class="display-tooltip-core" :class="[elementClasses]" :style="`--anchor-name: ${tooltipAnchorName}`">
3
+ <div class="display-tooltip-trigger-wrapper body-md">
4
+ <slot v-if="slots.triggerContent" name="triggerContent"></slot>
5
+ <button
6
+ :popovertarget="tooltipId"
7
+ popovertargetaction="toggle"
8
+ class="display-tooltip-trigger-button"
9
+ :class="{ hide: hideTooltipTrigger }"
10
+ aria-label="Toggle the popover"
11
+ >
12
+ <Icon name="fa7-solid:circle-question" class="display-tooltip-trigger-icon" aria-hidden="true" />
13
+ </button>
14
+ </div>
15
+ <div popover class="display-tooltip-popover" :id="tooltipId" ref="popover1">
16
+ <div class="display-tooltip-popover-content">
17
+ <slot name="tooltipContent"></slot>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </template>
22
+
23
+ <script setup lang="ts">
24
+ const props = defineProps({
25
+ tooltipId: {
26
+ type: String,
27
+ default: "",
28
+ },
29
+ styleClassPassthrough: {
30
+ type: [String, Array] as PropType<string | string[]>,
31
+ default: () => [],
32
+ },
33
+ })
34
+
35
+ const slots = useSlots()
36
+ const tooltipId = computed(() => {
37
+ return props.tooltipId.length ? props.tooltipId : `nuxt-tooltip-${useId()}`
38
+ })
39
+ const tooltipAnchorName = `tooltip-anchor-${useId()}`
40
+ const hideTooltipTrigger = ref(false)
41
+
42
+ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
43
+ </script>
44
+
45
+ <style lang="css">
46
+ .display-tooltip-core {
47
+ padding-block: 8px;
48
+ position: relative;
49
+
50
+ .display-tooltip-trigger-wrapper {
51
+ display: inline-flex;
52
+ align-items: flex-start;
53
+
54
+ .display-tooltip-trigger-button {
55
+ margin-left: 8px;
56
+
57
+ &.hide {
58
+ width: 0;
59
+ overflow: hidden;
60
+ opacity: 0;
61
+ }
62
+
63
+ .display-tooltip-trigger-icon {
64
+ display: inline-flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ width: 20px;
68
+ height: 20px;
69
+ color: var(--nuxt-text-header);
70
+ font-size: 18px;
71
+ line-height: 20px;
72
+ }
73
+ }
74
+ }
75
+
76
+ .display-tooltip-trigger-button {
77
+ all: unset;
78
+ aspect-ratio: 1 / 1;
79
+ width: 24px;
80
+ display: grid;
81
+ place-items: center;
82
+
83
+ outline: 1px solid transparent;
84
+ anchor-name: var(--anchor-name);
85
+
86
+ @supports (corner-shape: squircle) {
87
+ corner-shape: squircle;
88
+ border-radius: 50%;
89
+ }
90
+
91
+ &:hover {
92
+ cursor: pointer;
93
+ text-decoration: underline;
94
+ }
95
+
96
+ &:hover,
97
+ &:focus-visible {
98
+ outline-offset: 2px;
99
+ }
100
+ }
101
+
102
+ .display-tooltip-popover {
103
+ display: none;
104
+ position: absolute;
105
+ border: none;
106
+ width: 300px;
107
+
108
+ outline: 1px solid light-dark(black, white);
109
+ color: light-dark(black, white);
110
+ background-color: light-dark(white, black);
111
+ border-radius: 8px;
112
+
113
+ position-anchor: var(--anchor-name);
114
+ margin: 0;
115
+ inset: auto;
116
+ top: calc(anchor(top) + 0px);
117
+ left: calc(anchor(right) + 1px);
118
+ opacity: 0;
119
+ transition: opacity 200ms, display 200ms, overlay 200ms;
120
+
121
+ transition-behavior: allow-discrete;
122
+ position-try-fallbacks: flip-inline;
123
+
124
+ /* .popover-action {
125
+ display: flex;
126
+ justify-content: flex-end;
127
+ padding: 8px;
128
+ border-bottom: 1px solid var(--nuxt-stroke-border-grey);
129
+ } */
130
+
131
+ .display-tooltip-popover-content {
132
+ .display-tooltip-close-button {
133
+ all: unset;
134
+ cursor: pointer;
135
+ color: var(--nuxt-text-accessibility-blue);
136
+ border: 1px solid var(--theme-button-border);
137
+ outline: 1px solid var(--theme-button-outline);
138
+
139
+ font-weight: 600;
140
+ padding: 8px 12px;
141
+
142
+ &:hover,
143
+ &:focus {
144
+ text-decoration: underline;
145
+ border: 1px solid var(--theme-button-border-hover);
146
+ outline: 1px solid var(--theme-button-outline-hover);
147
+ outline-offset: 2px;
148
+ }
149
+ }
150
+ }
151
+
152
+ &:popover-open {
153
+ display: flex;
154
+ opacity: 1;
155
+
156
+ flex-direction: column;
157
+
158
+ @starting-style {
159
+ display: flex;
160
+ opacity: 0;
161
+ }
162
+ }
163
+ }
164
+ }
165
+ </style>
@@ -0,0 +1,101 @@
1
+ <template>
2
+ <DisplayTooltip :tooltip-id="tooltipId" :style-class-passthrough>
3
+ <template v-if="slots.triggerContent" #triggerContent>
4
+ <slot name="triggerContent"></slot>
5
+ </template>
6
+ <template #tooltipContent>
7
+ <div class="popover-content-defined">
8
+ <component
9
+ :is="props.contentText.tooltipTitle?.tag"
10
+ v-if="props.contentText.tooltipTitle"
11
+ class="tooltip-title subtitle-sm"
12
+ >
13
+ {{ props.contentText.tooltipTitle.text }}
14
+ </component>
15
+ <component
16
+ :is="props.contentText.tooltipContent?.tag"
17
+ v-if="props.contentText.tooltipContent"
18
+ class="tooltip-body body-sm"
19
+ >
20
+ {{ props.contentText.tooltipContent.text }}
21
+ </component>
22
+ <component
23
+ :is="props.contentText.tooltipAction?.tag"
24
+ v-if="props.contentText.tooltipAction"
25
+ class="tooltip-action input-value"
26
+ >
27
+ {{ props.contentText.tooltipAction.text }}
28
+ </component>
29
+ <button
30
+ :popovertarget="tooltipId"
31
+ popovertargetaction="hide"
32
+ class="display-tooltip-close-button"
33
+ aria-label="Close tool tip"
34
+ >
35
+ Close
36
+ </button>
37
+ </div>
38
+ </template>
39
+ </DisplayTooltip>
40
+ </template>
41
+
42
+ <script lang="ts">
43
+ export interface TooltipContentText {
44
+ tooltipTitle?: {
45
+ tag: string
46
+ text: string
47
+ }
48
+ tooltipContent?: {
49
+ tag: string
50
+ text: string
51
+ }
52
+ tooltipAction?: {
53
+ tag: string
54
+ text: string
55
+ }
56
+ }
57
+ </script>
58
+
59
+ <script setup lang="ts">
60
+ const props = defineProps({
61
+ tooltipId: {
62
+ type: String,
63
+ default: "",
64
+ },
65
+ contentText: {
66
+ type: Object as PropType<TooltipContentText>,
67
+ default: () => ({}),
68
+ },
69
+ styleClassPassthrough: {
70
+ type: [String, Array] as PropType<string | string[]>,
71
+ default: () => [],
72
+ },
73
+ })
74
+
75
+ const slots = useSlots()
76
+ const tooltipId = computed(() => {
77
+ return props.tooltipId.length ? `nuxt-tooltip-${props.tooltipId}` : `nuxt-tooltip-${useId()}`
78
+ })
79
+ </script>
80
+
81
+ <style lang="css">
82
+ .display-tooltip-core {
83
+ .popover {
84
+ .popover-content {
85
+ .popover-content-defined {
86
+ .tooltip-title {
87
+ color: var(--nuxt-text-white-header);
88
+ }
89
+
90
+ .tooltip-body {
91
+ color: var(--nuxt-text-white-body);
92
+ }
93
+
94
+ .tooltip-action {
95
+ color: var(--nuxt-text-white-body);
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ </style>