PluginProbe
The Innovative Form Builder – IvyForms / 0.7
The Innovative Form Builder – IvyForms v0.7
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / views / _components / tooltip / IvyTooltip.vue

IvyTooltip.vue in The Innovative Form Builder – IvyForms 0.7, at frontend/src/views/_components/tooltip/IvyTooltip.vue

176 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <template>
2 <div
3 class="ivyforms-tooltip"
4 role="tooltip"
5 :aria-label="props.ariaLabel || props.content || getLabel('tooltip')"
6 >
7 <ElTooltip
8 v-model="localModelValue"
9 :popper-class="['ivyforms-tooltip-popper', themeClass]"
10 effect="customized"
11 v-bind="$attrs"
12 :hide-after="validatedHideAfter"
13 :placement="placement"
14 :popper-options="{
15 modifiers: [
16 { name: 'preventOverflow', options: { boundary: 'viewport' } },
17 { name: 'flip', options: { fallbackPlacements: ['top', 'bottom', 'right', 'left'] } },
18 {
19 name: 'maxWidth',
20 enabled: true,
21 fn: ({ state }) => {
22 state.styles.popper.maxWidth = validatedMaxWidth
23 },
24 phase: 'beforeWrite',
25 requires: ['computeStyles'],
26 },
27 ],
28 }"
29 role="tooltip"
30 :aria-hidden="!localModelValue"
31 :aria-label="props.ariaLabel || getLabel('tooltip')"
32 >
33 <template #content>
34 <div :id="tooltipId">
35 <slot name="content">{{ props.content }}</slot>
36 </div>
37 </template>
38 <div ref="tooltipTrigger" :aria-describedby="tooltipId">
39 <slot />
40 </div>
41 </ElTooltip>
42 </div>
43 </template>
44
45 <script setup lang="ts">
46 import { ref, computed } from 'vue'
47 import { nanoid } from 'nanoid'
48 import { useLabels } from '@/composables/useLabels'
49 const { getLabel } = useLabels()
50
51 interface Props {
52 modelValue?: boolean
53 content?: string | undefined
54 maxWidth?: string
55 hideAfter?: number
56 placement?:
57 | 'top'
58 | 'top-start'
59 | 'top-end'
60 | 'bottom'
61 | 'bottom-start'
62 | 'bottom-end'
63 | 'left'
64 | 'left-start'
65 | 'left-end'
66 | 'right'
67 | 'right-start'
68 | 'right-end'
69 theme?: 'light' | 'inverted' | 'dusk'
70 ariaLabel?: string
71 }
72
73 const props = withDefaults(defineProps<Props>(), {
74 content: '',
75 maxWidth: '320px',
76 hideAfter: 0,
77 placement: 'top',
78 theme: 'inverted',
79 ariaLabel: '',
80 })
81
82 const emit = defineEmits(['update:modelValue'])
83
84 const localModelValue = computed({
85 get() {
86 return props.modelValue
87 },
88 set(value) {
89 emit('update:modelValue', value)
90 },
91 })
92
93 // Generate a unique tooltip ID
94 const tooltipId = ref(`ivyforms-tooltip-${nanoid(6)}`)
95
96 // Validation
97 const validatedHideAfter = computed(() =>
98 props.hideAfter && props.hideAfter > 0 ? props.hideAfter : 0,
99 )
100 const validatedMaxWidth = computed(() =>
101 /^(\d+(\.\d+)?(px|em|rem|%)|auto)$/.test(props.maxWidth ?? '320px') ? props.maxWidth : '320px',
102 )
103
104 const themeClass = computed(() => `ivyforms-tooltip-${props.theme}`)
105 </script>
106
107 <style lang="scss">
108 // Tooltip Popper
109 .ivyforms-tooltip-popper {
110 // Element Popper
111 &.el-popper {
112 border-radius: 8px;
113 box-shadow:
114 0 1px 2px 0 rgba(18, 26, 38, 0.3),
115 0 1px 3px 1px rgba(18, 26, 38, 0.15);
116 text-align: center;
117 font-size: 12px;
118 font-style: normal;
119 font-weight: 500;
120 line-height: 16px;
121 display: flex;
122 flex-direction: column;
123 align-items: flex-start;
124 gap: 4px;
125 color: var(--map-base-text-0);
126 background: var(--map-ground-level-2-foreground);
127
128 // Arrow
129 .el-popper__arrow {
130 &::before {
131 top: 0;
132 left: 0;
133 right: 0;
134 bottom: 0;
135 position: absolute;
136 border: none;
137 background: var(--map-ground-level-2-foreground);
138 }
139 }
140
141 // Themes
142 &.is-customized {
143 // Inverted
144 &.ivyforms-tooltip-inverted {
145 color: var(--map-base-dusk-fill--4);
146 background: var(--map-base-dusk-fill-4);
147 // Arrow
148 .el-popper__arrow::before {
149 background: var(--map-base-dusk-fill-4);
150 }
151 }
152
153 // Dusk
154 &.ivyforms-tooltip-dusk {
155 color: var(--map-base-text-0);
156 background: var(--map-base-dusk-fill--4);
157 // Arrow
158 .el-popper__arrow::before {
159 background: var(--map-base-dusk-fill--4) !important;
160 }
161 }
162
163 // Light
164 &.ivyforms-tooltip-light {
165 color: var(--map-base-text-0);
166 background: var(--map-ground-level-2-foreground);
167 // Arrow
168 .el-popper__arrow::before {
169 background: var(--map-ground-level-2-foreground);
170 }
171 }
172 }
173 }
174 }
175 </style>
176