srcdev-nuxt-components 6.2.12 → 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.
- package/app/components/alert-mask/AlertMaskCore.vue +7 -16
- package/app/components/display-prompt/DisplayPromptCore.vue +4 -2
- package/app/components/display-toast/DisplayToast.vue +34 -104
- package/app/components/display-toast/molecules/DefaultToastContent.vue +165 -0
- package/app/components/display-tooltip/DisplayTooltip.vue +165 -0
- package/app/components/display-tooltip/DisplayTooltipDefined.vue +101 -0
- package/app/components/marquee-scroller/MarqueeScroller.vue +218 -53
- package/app/components/masonry-grid/MasonryGrid.vue +2 -2
- package/app/components/masonry-grid-ordered/MasonryGridOrdered.vue +1 -1
- package/app/components/qr-code/CaptureQrCode.vue +181 -0
- package/app/components/qr-code/DecodeQrCode.vue +77 -0
- package/app/components/qr-code/DisplayQrCode.vue +51 -0
- package/app/composables/useTooltips.ts +174 -0
- package/app/types/components/alert-mask-core.d.ts +10 -0
- package/app/types/components/display-toast.d.ts +53 -0
- package/app/types/components/qr-code.d.ts +7 -0
- package/app/types/index.ts +5 -0
- package/nuxt.config.ts +2 -1
- package/package.json +7 -3
- package/types.d.ts +4 -0
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
</mask>
|
|
9
9
|
</defs>
|
|
10
10
|
|
|
11
|
-
<path :d="outerPath" :fill="cfg.
|
|
12
|
-
<path :d="innerPath" fill="
|
|
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<
|
|
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
|
-
|
|
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" :
|
|
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:
|
|
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
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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>
|