@weni/unnnic-system 3.12.6 → 3.12.8-alpha.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{es-e7dc92a2.mjs → es-52edeb71.mjs} +1 -1
  3. package/dist/{index-84ade580.mjs → index-756fe685.mjs} +99873 -96635
  4. package/dist/index.d.ts +5714 -1674
  5. package/dist/{pt-br-51fd679a.mjs → pt-br-24583c8c.mjs} +1 -1
  6. package/dist/style.css +1 -1
  7. package/dist/unnnic.mjs +236 -204
  8. package/dist/unnnic.umd.js +48 -44
  9. package/package.json +3 -2
  10. package/src/assets/scss/scheme-colors.scss +223 -223
  11. package/src/assets/scss/tailwind.scss +8 -0
  12. package/src/components/Alert/__tests__/__snapshots__/Alert.spec.js.snap +1 -1
  13. package/src/components/Checkbox/Checkbox.vue +1 -1
  14. package/src/components/Drawer/Drawer.vue +190 -269
  15. package/src/components/Drawer/__tests__/Drawer.spec.js +37 -46
  16. package/src/components/Drawer/__tests__/__snapshots__/Drawer.spec.js.snap +18 -19
  17. package/src/components/FormElement/FormElement.vue +1 -1
  18. package/src/components/Input/BaseInput.vue +25 -5
  19. package/src/components/Input/Input.scss +2 -3
  20. package/src/components/Input/Input.vue +24 -1
  21. package/src/components/Input/TextInput.vue +64 -25
  22. package/src/components/Input/__test__/TextInput.spec.js +1 -1
  23. package/src/components/Input/__test__/__snapshots__/Input.spec.js.snap +5 -1
  24. package/src/components/Input/__test__/__snapshots__/TextInput.spec.js.snap +7 -1
  25. package/src/components/ModalDialog/ModalDialog.vue +64 -148
  26. package/src/components/ModalDialog/__tests__/ModalDialog.spec.js +11 -221
  27. package/src/components/ModalDialog/__tests__/__snapshots__/ModalDialog.spec.js.snap +1 -22
  28. package/src/components/MultiSelect/MultSelectOption.vue +49 -0
  29. package/src/components/MultiSelect/__tests__/MultiSelect.spec.js +557 -0
  30. package/src/components/MultiSelect/__tests__/MultiSelectOption.spec.js +229 -0
  31. package/src/components/MultiSelect/__tests__/__snapshots__/MultiSelect.spec.js.snap +87 -0
  32. package/src/components/MultiSelect/__tests__/__snapshots__/MultiSelectOption.spec.js.snap +51 -0
  33. package/src/components/MultiSelect/index.vue +265 -0
  34. package/src/components/Radio/Radio.vue +1 -1
  35. package/src/components/Select/__tests__/Select.spec.js +422 -0
  36. package/src/components/Select/__tests__/SelectItem.spec.js +330 -0
  37. package/src/components/Select/__tests__/__snapshots__/Popover.spec.js.snap +8 -0
  38. package/src/components/Select/__tests__/__snapshots__/Select.spec.js.snap +71 -0
  39. package/src/components/Select/__tests__/__snapshots__/SelectItem.spec.js.snap +15 -0
  40. package/src/components/Select/__tests__/__snapshots__/SelectOption.spec.js.snap +25 -0
  41. package/src/components/Select/__tests__/__snapshots__/SelectPopover.spec.js.snap +8 -0
  42. package/src/components/Select/index.vue +308 -0
  43. package/src/components/Switch/Switch.vue +1 -1
  44. package/src/components/Tab/__test__/__snapshots__/Tab.spec.js.snap +3 -1
  45. package/src/components/TemplatePreview/TemplatePreview.vue +2 -2
  46. package/src/components/TemplatePreview/TemplatePreviewModal.vue +1 -1
  47. package/src/components/Toast/Toast.vue +16 -9
  48. package/src/components/ToolTip/ToolTip.vue +25 -177
  49. package/src/components/ToolTip/__tests__/ToolTip.spec.js +339 -61
  50. package/src/components/index.ts +66 -6
  51. package/src/components/ui/dialog/Dialog.vue +19 -0
  52. package/src/components/ui/dialog/DialogClose.vue +29 -0
  53. package/src/components/ui/dialog/DialogContent.vue +140 -0
  54. package/src/components/ui/dialog/DialogFooter.vue +50 -0
  55. package/src/components/ui/dialog/DialogHeader.vue +83 -0
  56. package/src/components/ui/dialog/DialogTitle.vue +38 -0
  57. package/src/components/ui/dialog/DialogTrigger.vue +16 -0
  58. package/src/components/ui/dialog/index.ts +7 -0
  59. package/src/components/ui/drawer/Drawer.vue +27 -0
  60. package/src/components/ui/drawer/DrawerClose.vue +31 -0
  61. package/src/components/ui/drawer/DrawerContent.vue +111 -0
  62. package/src/components/ui/drawer/DrawerDescription.vue +40 -0
  63. package/src/components/ui/drawer/DrawerFooter.vue +38 -0
  64. package/src/components/ui/drawer/DrawerHeader.vue +57 -0
  65. package/src/components/ui/drawer/DrawerOverlay.vue +33 -0
  66. package/src/components/ui/drawer/DrawerTitle.vue +37 -0
  67. package/src/components/ui/drawer/DrawerTrigger.vue +31 -0
  68. package/src/components/ui/drawer/index.ts +10 -0
  69. package/src/components/ui/popover/PopoverContent.vue +30 -10
  70. package/src/components/ui/popover/PopoverOption.vue +5 -1
  71. package/src/components/ui/popover/PopoverTrigger.vue +5 -1
  72. package/src/components/ui/tooltip/Tooltip.vue +21 -0
  73. package/src/components/ui/tooltip/TooltipContent.vue +74 -0
  74. package/src/components/ui/tooltip/TooltipTrigger.vue +26 -0
  75. package/src/components/ui/tooltip/index.ts +3 -0
  76. package/src/lib/layer-manager.ts +92 -0
  77. package/src/locales/en.json +3 -1
  78. package/src/locales/es.json +3 -1
  79. package/src/locales/pt_br.json +3 -1
  80. package/src/stories/Dialog.stories.js +832 -0
  81. package/src/stories/Drawer.stories.js +1 -1
  82. package/src/stories/DrawerNext.stories.js +611 -0
  83. package/src/stories/Input.mdx +3 -0
  84. package/src/stories/LayerManager.docs.mdx +40 -0
  85. package/src/stories/LayerManager.stories.js +364 -0
  86. package/src/stories/ModalDialog.mdx +3 -0
  87. package/src/stories/ModalDialog.stories.js +1 -1
  88. package/src/stories/MultiSelect.stories.js +143 -45
  89. package/src/stories/Popover.stories.js +5 -0
  90. package/src/stories/Select.stories.js +161 -0
  91. package/src/components/MultiSelect/MultiSelect.vue +0 -297
@@ -0,0 +1,308 @@
1
+ <template>
2
+ <div
3
+ class="unnnic-select"
4
+ @keydown="handleKeyDown"
5
+ >
6
+ <Popover
7
+ :open="openPopover"
8
+ @update:open="openPopover = $event"
9
+ >
10
+ <PopoverTrigger class="w-full">
11
+ <UnnnicInput
12
+ ref="selectInputRef"
13
+ :modelValue="inputValue"
14
+ class="unnnic-select__input"
15
+ readonly
16
+ useFocusProp
17
+ :focus="openPopover"
18
+ :size="props.size"
19
+ :placeholder="props.placeholder"
20
+ :label="props.label"
21
+ :errors="props.errors"
22
+ :message="props.message"
23
+ :iconRight="openPopover ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
24
+ :disabled="props.disabled"
25
+ :showClear="!!selectedItem"
26
+ @clear="emit('update:modelValue', '')"
27
+ />
28
+ </PopoverTrigger>
29
+ <PopoverContent
30
+ align="start"
31
+ :class="'h-full'"
32
+ :style="popoverContentCustomStyles"
33
+ :width="inputWidthString"
34
+ >
35
+ <div class="unnnic-select__content">
36
+ <UnnnicInput
37
+ v-if="props.enableSearch"
38
+ class="unnnic-select__input-search"
39
+ :modelValue="props.search"
40
+ :placeholder="$t('search')"
41
+ iconLeft="search"
42
+ @update:model-value="handleSearch"
43
+ />
44
+ <p
45
+ v-if="filteredOptions.length === 0"
46
+ class="unnnic-select__content-no-results"
47
+ >
48
+ {{ $t('without_results') }}
49
+ </p>
50
+ <PopoverOption
51
+ v-for="(option, index) in filteredOptions"
52
+ v-else
53
+ :key="option[props.itemValue]"
54
+ :data-option-index="index"
55
+ data-testid="select-option"
56
+ :label="option[props.itemLabel]"
57
+ :active="
58
+ option[props.itemValue] === selectedItem?.[props.itemValue]
59
+ "
60
+ :focused="focusedOptionIndex === index"
61
+ :disabled="option.disabled"
62
+ @click="handleSelectOption(option)"
63
+ />
64
+ </div>
65
+ </PopoverContent>
66
+ </Popover>
67
+ </div>
68
+ </template>
69
+
70
+ <script setup lang="ts">
71
+ import { computed, ref, watch, nextTick } from 'vue';
72
+ import { useElementSize } from '@vueuse/core';
73
+
74
+ import UnnnicInput from '../Input/Input.vue';
75
+
76
+ import {
77
+ Popover,
78
+ PopoverTrigger,
79
+ PopoverContent,
80
+ PopoverOption,
81
+ } from '../ui/popover/index';
82
+
83
+ import UnnnicI18n from '../../mixins/i18n';
84
+
85
+ defineOptions({
86
+ name: 'UnnnicSelect',
87
+ mixins: [UnnnicI18n],
88
+ });
89
+
90
+ interface SelectProps {
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ options: Array<{ [key: string]: any }>;
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ modelValue: any;
95
+ returnObject?: boolean;
96
+ itemLabel?: string;
97
+ itemValue?: string;
98
+ placeholder?: string;
99
+ label?: string;
100
+ type?: 'normal' | 'error';
101
+ errors?: string | Array<string>;
102
+ message?: string;
103
+ size?: 'sm' | 'md';
104
+ optionsLines?: number;
105
+ enableSearch?: boolean;
106
+ search?: string;
107
+ locale?: string;
108
+ disabled?: boolean;
109
+ }
110
+
111
+ const props = withDefaults(defineProps<SelectProps>(), {
112
+ size: 'md',
113
+ type: 'normal',
114
+ placeholder: '',
115
+ optionsLines: 5,
116
+ returnObject: false,
117
+ itemLabel: 'label',
118
+ itemValue: 'value',
119
+ locale: 'en',
120
+ enableSearch: false,
121
+ disabled: false,
122
+ label: '',
123
+ errors: '',
124
+ message: '',
125
+ search: '',
126
+ });
127
+
128
+ const emit = defineEmits<{
129
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
130
+ 'update:modelValue': [value: any];
131
+ 'update:search': [value: string];
132
+ }>();
133
+
134
+ const openPopover = ref(false);
135
+ const selectInputRef = ref<HTMLInputElement | null>(null);
136
+ const { width: inputWidth } = useElementSize(selectInputRef);
137
+
138
+ const inputWidthString = computed(() => {
139
+ return `${inputWidth.value}px`;
140
+ });
141
+
142
+ watch(openPopover, () => {
143
+ if (!openPopover.value) {
144
+ handleSearch('');
145
+ } else {
146
+ focusedOptionIndex.value = -1;
147
+ }
148
+
149
+ if (openPopover.value && props.modelValue) {
150
+ const selectedOptionIndex = props.options.findIndex(
151
+ (option) =>
152
+ option[props.itemValue] === selectedItem.value?.[props.itemValue],
153
+ );
154
+ scrollToOption(selectedOptionIndex, 'instant', 'center');
155
+ }
156
+ });
157
+
158
+ const handleKeyDown = (event) => {
159
+ const { key } = event;
160
+ const validKeys = ['ArrowUp', 'ArrowDown', 'Enter'];
161
+
162
+ if (validKeys.includes(key)) {
163
+ event.preventDefault();
164
+ if (key === 'ArrowUp') {
165
+ if (focusedOptionIndex.value === 0) return;
166
+ focusedOptionIndex.value--;
167
+ scrollToOption(focusedOptionIndex.value);
168
+ }
169
+ if (key === 'ArrowDown') {
170
+ if (focusedOptionIndex.value === filteredOptions.value.length - 1) return;
171
+ focusedOptionIndex.value++;
172
+ scrollToOption(focusedOptionIndex.value);
173
+ }
174
+ if (key === 'Enter' && focusedOptionIndex.value !== -1) {
175
+ handleSelectOption(filteredOptions.value[focusedOptionIndex.value]);
176
+ }
177
+ }
178
+ };
179
+
180
+ const focusedOptionIndex = ref<number>(-1);
181
+
182
+ const scrollToOption = (
183
+ index: number,
184
+ behavior: 'smooth' | 'instant' = 'smooth',
185
+ block: 'center' | 'start' | 'end' | 'nearest' = 'center',
186
+ ) => {
187
+ nextTick(() => {
188
+ const option = document.querySelector(`[data-option-index="${index}"]`);
189
+ if (option) {
190
+ option.scrollIntoView?.({ behavior, block });
191
+ }
192
+ });
193
+ };
194
+
195
+ const calculatedPopoverHeight = computed(() => {
196
+ if (!props.options || props.options.length === 0) return 'unset';
197
+ const popoverPadding = 32;
198
+ const popoverGap = 4;
199
+ // 37 = 21px (height) + 16px (padding)
200
+ const fieldsHeight = 37 * props.optionsLines;
201
+ const gapsCompensation = props.enableSearch ? 1 : 2;
202
+
203
+ const size =
204
+ fieldsHeight +
205
+ popoverPadding +
206
+ (popoverGap * props.optionsLines - gapsCompensation);
207
+
208
+ return `${props.enableSearch ? size + 45 + 1 : size}px`;
209
+ });
210
+
211
+ const popoverContentCustomStyles = computed(() => {
212
+ const emptyFilteredOptions = filteredOptions.value?.length === 0;
213
+ return {
214
+ overflow: 'auto',
215
+ display: 'flex',
216
+ flexDirection: 'column',
217
+ minHeight: calculatedPopoverHeight.value,
218
+ maxHeight: emptyFilteredOptions ? 'unset' : calculatedPopoverHeight.value,
219
+ height: emptyFilteredOptions ? calculatedPopoverHeight.value : 'unset',
220
+ };
221
+ });
222
+
223
+ const selectedItem = computed(() => {
224
+ if (props.returnObject) return props.modelValue;
225
+
226
+ return props.options.find(
227
+ (option) => option[props.itemValue] === props.modelValue,
228
+ );
229
+ });
230
+
231
+ const inputValue = computed(() => {
232
+ return selectedItem.value?.[props.itemLabel];
233
+ });
234
+
235
+ const handleSelectOption = (option) => {
236
+ if (
237
+ option[props.itemValue] === selectedItem.value?.[props.itemValue] ||
238
+ option.disabled
239
+ )
240
+ return;
241
+
242
+ emit(
243
+ 'update:modelValue',
244
+ props.returnObject ? option : option[props.itemValue],
245
+ );
246
+ openPopover.value = false;
247
+ };
248
+
249
+ const handleSearch = (value: string) => {
250
+ emit('update:search', value);
251
+ };
252
+
253
+ const filteredOptions = computed(() => {
254
+ if (!props.enableSearch || !props.search) return props.options;
255
+
256
+ return props.options.filter(
257
+ (option) =>
258
+ option[props.itemLabel]
259
+ .toLowerCase()
260
+ .includes(props.search?.toLowerCase()) ||
261
+ option[props.itemValue]
262
+ .toLowerCase()
263
+ .includes(props.search?.toLowerCase()),
264
+ );
265
+ });
266
+ </script>
267
+
268
+ <style lang="scss" scoped>
269
+ @use '@/assets/scss/unnnic' as *;
270
+
271
+ :deep(.unnnic-select__input) {
272
+ cursor: pointer;
273
+ }
274
+
275
+ :deep(.unnnic-select__input-search) {
276
+ > .icon-left {
277
+ color: $unnnic-color-fg-base;
278
+ }
279
+ }
280
+
281
+ :deep(.unnnic-select__input) {
282
+ > .icon-right {
283
+ color: $unnnic-color-fg-base;
284
+ }
285
+ }
286
+
287
+ .unnnic-select {
288
+ &__content {
289
+ display: flex;
290
+ flex-direction: column;
291
+ padding: 0;
292
+ margin: 0;
293
+ gap: $unnnic-space-1;
294
+
295
+ height: -webkit-fill-available;
296
+
297
+ &-no-results {
298
+ margin: 0;
299
+ display: flex;
300
+ align-items: center;
301
+ justify-content: center;
302
+ height: 100%;
303
+ font: $unnnic-font-emphasis;
304
+ color: $unnnic-color-fg-muted;
305
+ }
306
+ }
307
+ }
308
+ </style>
@@ -19,8 +19,8 @@
19
19
  type="checkbox"
20
20
  :disabled="disabled"
21
21
  :checked="modelValue"
22
- @change="toggleState"
23
22
  v-bind="pick($attrs, ['id', 'name'])"
23
+ @change="toggleState"
24
24
  />
25
25
 
26
26
  <p
@@ -4,7 +4,9 @@ exports[`Tab.vue > matches the snapshot 1`] = `
4
4
  "<div data-v-b4e39fac="" class="tab size-md">
5
5
  <header data-v-b4e39fac="" class="tab-header">
6
6
  <ul data-v-b4e39fac="" class="tab-content">
7
- <li data-v-b4e39fac="" class="tab-head">tab1<div data-v-bf0cf546="" data-v-b4e39fac="" class="unnnic-tooltip"><span data-v-26446d8e="" data-v-b4e39fac="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--sm unnnic-icon__size--sm" data-testid="material-icon" translate="no">help</span><span data-v-bf0cf546="" class="unnnic-tooltip-label unnnic-tooltip-label-bottom" data-testid="tooltip-label" style="left: 0px; top: 8px;">Tooltip text <br data-v-bf0cf546=""><!--v-if--></span></div>
7
+ <li data-v-b4e39fac="" class="tab-head">tab1<div data-v-b3d24f2b="" class="unnnic-tooltip-trigger" data-testid="tooltip-trigger" data-state="closed" data-grace-area-trigger=""><span data-v-26446d8e="" data-v-b4e39fac="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--sm unnnic-icon__size--sm" data-testid="material-icon" translate="no">help</span></div>
8
+ <!--teleport start-->
9
+ <!--teleport end-->
8
10
  </li>
9
11
  <li data-v-b4e39fac="" class="tab-head tab-head--active">tab2
10
12
  <!--v-if-->
@@ -13,11 +13,11 @@
13
13
  }`"
14
14
  >
15
15
  <img
16
- class="unnnic-template-preview__header__media__preview"
17
16
  v-if="
18
17
  template?.header.type === 'MEDIA' &&
19
18
  template?.header.mediaType === 'IMAGE'
20
19
  "
20
+ class="unnnic-template-preview__header__media__preview"
21
21
  :src="template.header.src || imagePreview"
22
22
  />
23
23
  <template
@@ -50,8 +50,8 @@
50
50
  />
51
51
  </template>
52
52
  <h1
53
- class="unnnic-template-preview__header__text__preview"
54
53
  v-else-if="template?.header.type === 'TEXT'"
54
+ class="unnnic-template-preview__header__text__preview"
55
55
  >
56
56
  {{ template.header.text }}
57
57
  </h1>
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
  <UnnnicModalDialog
3
3
  :modelValue="modelValue"
4
- @update:modelValue="$event === false && $emit('close')"
5
4
  :title="defaultTranslations.title[props.locale]"
6
5
  :showCloseIcon="true"
7
6
  class="unnnic-template-preview-modal"
7
+ @update:model-value="$event === false && $emit('close')"
8
8
  >
9
9
  <UnnnicTemplatePreview :template="template" />
10
10
  </UnnnicModalDialog>
@@ -7,10 +7,11 @@
7
7
  >
8
8
  <aside
9
9
  v-if="isVisible"
10
- :class="['unnnic-toast', `unnnic-toast--${type}`]"
11
- :role="type === 'error' ? 'alert' : 'status'"
12
- :aria-live="type === 'error' ? 'assertive' : 'polite'"
10
+ :class="['unnnic-toast', `unnnic-toast--${validType}`]"
11
+ :role="validType === 'error' ? 'alert' : 'status'"
12
+ :aria-live="validType === 'error' ? 'assertive' : 'polite'"
13
13
  data-testid="toast"
14
+ :style="{ zIndex: toastZIndex }"
14
15
  >
15
16
  <section
16
17
  class="unnnic-toast__content"
@@ -22,7 +23,7 @@
22
23
  >
23
24
  <UnnnicIcon
24
25
  :icon="typeConfig.icon"
25
- :scheme="typeConfig.scheme"
26
+ :scheme="typeConfig.scheme as SchemeColor"
26
27
  size="ant"
27
28
  data-testid="toast-type-icon"
28
29
  />
@@ -74,6 +75,7 @@ import { ref, computed, onMounted, onUnmounted } from 'vue';
74
75
 
75
76
  import UnnnicIcon from '@/components/Icon.vue';
76
77
  import UnnnicButton from '@/components/Button/Button.vue';
78
+ import { useLayerZIndex } from '@/lib/layer-manager';
77
79
 
78
80
  import type { ToastProps, ToastEmits } from './types';
79
81
  import type { SchemeColor } from '@/types/scheme-colors';
@@ -95,6 +97,13 @@ const emit = defineEmits<ToastEmits>();
95
97
  const isVisible = ref(false);
96
98
  let timeoutId: number | null = null;
97
99
 
100
+ const validType = computed(() => {
101
+ if (['informational', 'attention', 'success', 'error'].includes(props.type)) {
102
+ return props.type;
103
+ }
104
+ return 'informational';
105
+ });
106
+
98
107
  const typeConfig = computed(() => {
99
108
  const configMap = {
100
109
  informational: { icon: 'info', scheme: 'blue-500' },
@@ -103,12 +112,11 @@ const typeConfig = computed(() => {
103
112
  error: { icon: 'cancel', scheme: 'red-500' },
104
113
  };
105
114
 
106
- return configMap[props.type || 'informational'] as {
107
- icon: string;
108
- scheme: SchemeColor;
109
- };
115
+ return configMap[validType.value];
110
116
  });
111
117
 
118
+ const toastZIndex = useLayerZIndex('toast');
119
+
112
120
  const handleClose = () => {
113
121
  isVisible.value = false;
114
122
  emit('close');
@@ -152,7 +160,6 @@ onUnmounted(() => {
152
160
  position: fixed;
153
161
  bottom: $unnnic-space-4;
154
162
  right: $unnnic-space-4;
155
- z-index: 9999;
156
163
 
157
164
  display: flex;
158
165
  align-items: flex-end;
@@ -1,23 +1,25 @@
1
1
  <template>
2
- <div
3
- ref="tooltip"
4
- :class="{
5
- 'unnnic-tooltip': enabled || forceOpen,
6
- 'force-open': forceOpen,
7
- }"
8
- @mouseover="handleResize"
2
+ <Tooltip
3
+ :disabled="!(enabled || forceOpen)"
4
+ :open="forceOpen || undefined"
5
+ data-testid="tooltip-wrapper"
9
6
  >
10
- <slot />
11
- <span
12
- v-show="enabled || forceOpen"
13
- ref="label"
7
+ <TooltipTrigger data-testid="tooltip-trigger">
8
+ <slot />
9
+ </TooltipTrigger>
10
+
11
+ <TooltipContent
14
12
  :class="['unnnic-tooltip-label', `unnnic-tooltip-label-${side}`]"
15
- :style="{ maxWidth: maxWidth, left: leftPos, top: topPos }"
16
- data-testid="tooltip-label"
13
+ :style="{ maxWidth: maxWidth }"
14
+ :side="side"
15
+ data-testid="tooltip-content"
17
16
  >
18
17
  <template v-if="enableHtml">
19
18
  <!-- eslint-disable-next-line vue/no-v-html -->
20
- <section v-html="text"></section>
19
+ <section
20
+ data-testid="tooltip-html-content"
21
+ v-html="text"
22
+ ></section>
21
23
  </template>
22
24
  <template
23
25
  v-for="(line, index) in text.split('\n')"
@@ -27,22 +29,20 @@
27
29
  {{ line }}
28
30
  <br />
29
31
  </template>
30
-
31
- <template v-if="shortcutText">
32
- <span
33
- class="unnnic-tooltip-label-shortcut"
34
- data-testid="tooltip-label-shortcut"
35
- >
36
- {{ shortcutText }}
37
- </span>
38
- </template>
39
- </span>
40
- </div>
32
+ </TooltipContent>
33
+ </Tooltip>
41
34
  </template>
42
35
 
43
36
  <script>
37
+ import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip';
38
+
44
39
  export default {
45
40
  name: 'UnnnicTooltip',
41
+ components: {
42
+ Tooltip,
43
+ TooltipTrigger,
44
+ TooltipContent,
45
+ },
46
46
  props: {
47
47
  text: {
48
48
  type: String,
@@ -67,162 +67,10 @@ export default {
67
67
  type: String,
68
68
  default: '',
69
69
  },
70
- shortcutText: {
71
- type: String,
72
- default: null,
73
- },
74
70
  enableHtml: {
75
71
  type: Boolean,
76
72
  default: false,
77
73
  },
78
74
  },
79
- data() {
80
- return {
81
- topPos: null,
82
- leftPos: null,
83
- };
84
- },
85
- watch: {
86
- side() {
87
- this.getRightPost(this.$refs.tooltip);
88
- },
89
- },
90
- mounted() {
91
- this.handleResize();
92
-
93
- window.addEventListener('scroll', this.handleResize);
94
- window.addEventListener('resize', this.handleResize);
95
- },
96
- unmounted() {
97
- window.removeEventListener('scroll', this.handleResize);
98
- window.removeEventListener('resize', this.handleResize);
99
- },
100
- methods: {
101
- handleResize() {
102
- this.getRightPost(this.$refs.tooltip);
103
- },
104
- getRightPost(element) {
105
- const elementPos = element.getBoundingClientRect();
106
-
107
- if (element && this.$refs.label) {
108
- if (this.side === 'right') {
109
- this.leftPos = `${elementPos.x + elementPos.width + 8}px`;
110
- this.topPos = `${elementPos.y + elementPos.height / 2 - this.$refs.label.offsetHeight / 2}px`;
111
- } else if (this.side === 'left') {
112
- this.leftPos = `${elementPos.x - this.$refs.label.offsetWidth - 8}px`;
113
- this.topPos = `${elementPos.y + elementPos.height / 2 - this.$refs.label.offsetHeight / 2}px`;
114
- } else if (this.side === 'top') {
115
- this.leftPos = `${elementPos.x + elementPos.width / 2 - this.$refs.label.clientWidth / 2}px`;
116
- this.topPos = `${elementPos.y - this.$refs.label.offsetHeight - 8}px`;
117
- } else if (this.side === 'bottom') {
118
- this.leftPos = `${elementPos.x + elementPos.width / 2 - this.$refs.label.clientWidth / 2}px`;
119
- this.topPos = `${elementPos.y + elementPos.height + 8}px`;
120
- }
121
- }
122
- },
123
- },
124
75
  };
125
76
  </script>
126
-
127
- <style lang="scss" scoped>
128
- @use '@/assets/scss/unnnic' as *;
129
-
130
- .unnnic-tooltip {
131
- position: relative;
132
- display: inline-block;
133
- overflow-wrap: break-word;
134
- }
135
-
136
- .unnnic-tooltip-label {
137
- z-index: 1;
138
- visibility: hidden;
139
- text-align: center;
140
- position: fixed;
141
- width: max-content;
142
- min-width: 2 * $unnnic-font-size;
143
- box-sizing: border-box;
144
- width: auto;
145
- display: flex;
146
- justify-content: center;
147
- gap: $unnnic-spacing-xs;
148
- align-items: center;
149
-
150
- background-color: $unnnic-color-neutral-black;
151
- color: $unnnic-color-neutral-snow;
152
- border-radius: $unnnic-border-radius-sm;
153
- padding: $unnnic-inset-nano;
154
- box-shadow: $unnnic-shadow-level-near;
155
- font-size: $unnnic-font-size-body-md;
156
- font-family: $unnnic-font-family-secondary;
157
- font-weight: $unnnic-font-weight-regular;
158
- line-height: ($unnnic-font-size-body-md + $unnnic-line-height-medium);
159
-
160
- &::after {
161
- content: '';
162
- position: absolute;
163
- border-width: 5px;
164
- border-style: solid;
165
- }
166
-
167
- &-top {
168
- position: fixed;
169
- &::after {
170
- top: 100%;
171
- left: 50%;
172
- margin-left: -5px;
173
- border-color: $unnnic-color-neutral-black transparent transparent
174
- transparent;
175
- }
176
- }
177
-
178
- &-bottom {
179
- position: fixed;
180
- &::after {
181
- bottom: 100%;
182
- left: 50%;
183
- margin-left: -5px;
184
- border-color: transparent transparent $unnnic-color-neutral-black
185
- transparent;
186
- }
187
- }
188
- &-right {
189
- position: fixed;
190
- &::after {
191
- top: 50%;
192
- right: 100%;
193
- margin-top: -5px;
194
- border-color: transparent $unnnic-color-neutral-black transparent
195
- transparent;
196
- }
197
- }
198
- &-left {
199
- position: fixed;
200
- &::after {
201
- top: 50%;
202
- left: 100%;
203
- margin-top: -5px;
204
- border-color: transparent transparent transparent
205
- $unnnic-color-neutral-black;
206
- }
207
- }
208
-
209
- &-shortcut {
210
- background-color: $unnnic-color-neutral-darkest;
211
- border-radius: $unnnic-border-radius-sm;
212
- padding: calc($unnnic-inset-nano / 2) $unnnic-inset-nano;
213
- }
214
- }
215
-
216
- .unnnic-tooltip.force-open {
217
- .unnnic-tooltip-label {
218
- visibility: visible;
219
- }
220
- }
221
-
222
- .unnnic-tooltip:hover {
223
- .unnnic-tooltip-label {
224
- visibility: visible;
225
- width: auto;
226
- }
227
- }
228
- </style>