@energie360/ui-library 0.1.1 → 0.1.3

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 (92) hide show
  1. package/base/_input-resets.scss +9 -3
  2. package/base/_resets.scss +5 -0
  3. package/components/accordion-item/accordion-item.scss +62 -0
  4. package/components/accordion-item/u-accordion-item.vue +44 -0
  5. package/components/card/card.scss +58 -0
  6. package/components/card/u-card.vue +26 -0
  7. package/components/card-header/card-header.scss +102 -0
  8. package/components/card-header/u-card-header.vue +51 -0
  9. package/components/card-hint/card-hint.scss +13 -0
  10. package/components/card-hint/u-card-hint.vue +23 -0
  11. package/components/card-price/card-price.scss +110 -0
  12. package/components/card-price/u-card-price.vue +47 -0
  13. package/components/card-table/card-table.scss +76 -0
  14. package/components/card-table/u-card-table.vue +77 -0
  15. package/components/card-toggle-switches/card-toggle-switches.scss +13 -0
  16. package/components/card-toggle-switches/u-card-toggle-switches.vue +30 -0
  17. package/components/collapsible/collapsible.scss +14 -0
  18. package/components/collapsible/u-collapsible.vue +81 -0
  19. package/components/collapsible-group/u-collapsible-group.vue +14 -0
  20. package/components/icon-teaser/icon-teaser.scss +58 -0
  21. package/components/icon-teaser/u-icon-teaser.vue +35 -0
  22. package/components/icon-teaser-group/icon-teaser-group.scss +10 -0
  23. package/components/icon-teaser-group/u-icon-teaser-group.vue +19 -0
  24. package/components/icon-text-block/u-icon-text-block.vue +3 -8
  25. package/components/language-nav/language-nav.scss +32 -0
  26. package/components/language-nav/u-language-nav.vue +27 -0
  27. package/components/panel/panel.scss +43 -6
  28. package/components/panel/u-panel.vue +22 -11
  29. package/components/progress-bar/u-progress-bar.vue +1 -1
  30. package/components/richtext/richtext.scss +208 -0
  31. package/components/richtext/u-richtext.vue +21 -0
  32. package/components/table/u-cell-ctas.vue +2 -7
  33. package/components/table/u-cell-icon-group.vue +1 -1
  34. package/components/table/u-cell-icon-text.vue +1 -1
  35. package/components/table/u-cell-progress-bar.vue +1 -1
  36. package/components/table/u-table-cell.vue +3 -13
  37. package/components/table/u-table-heading.vue +1 -4
  38. package/components/tooltip/{popover.js → popover.ts} +51 -43
  39. package/components/tooltip/u-tooltip.vue +40 -60
  40. package/dist/base-style.css +409 -2
  41. package/dist/base-style.css.map +1 -0
  42. package/dist/elements/text-link.css +40 -0
  43. package/dist/elements/text-link.css.map +1 -0
  44. package/dist/layout/split.css +124 -0
  45. package/dist/layout/split.css.map +1 -0
  46. package/elements/button/u-button.vue +2 -5
  47. package/elements/button-chip/button-chip.scss +83 -0
  48. package/elements/button-chip/u-button-chip.vue +45 -0
  49. package/elements/form-field/form-field-base.scss +2 -3
  50. package/elements/form-field/form-field.types.ts +8 -0
  51. package/elements/icon/u-icon.vue +1 -3
  52. package/elements/image/u-image.vue +2 -2
  53. package/elements/numeric-stepper/numeric-stepper.scss +110 -0
  54. package/elements/numeric-stepper/u-numeric-stepper.vue +135 -0
  55. package/elements/select/select.scss +32 -0
  56. package/elements/select/u-select.vue +130 -0
  57. package/elements/select-chip/select-chip.scss +18 -0
  58. package/elements/select-chip/u-select-chip.vue +50 -0
  59. package/elements/select-chips/select-chips.scss +5 -0
  60. package/elements/select-chips/u-select-chips.vue +23 -0
  61. package/elements/spectro/spectro.scss +1 -4
  62. package/elements/text-field/u-text-field.vue +43 -27
  63. package/elements/text-link/text-link.scss +57 -0
  64. package/elements/toggle-switch/toggle-switch-small.scss +40 -0
  65. package/elements/toggle-switch/toggle-switch.scss +149 -0
  66. package/elements/toggle-switch/u-toggle-switch.vue +68 -0
  67. package/elements/types.ts +7 -0
  68. package/globals.js +6 -2
  69. package/helpers/transition-height.vue +39 -0
  70. package/i18n/i18n.ts +40 -0
  71. package/layout/grid/grid.mixin.scss +4 -11
  72. package/layout/split/split.scss +96 -0
  73. package/modules/footer/footer.scss +161 -0
  74. package/modules/footer/u-footer.vue +59 -0
  75. package/package.json +23 -13
  76. package/utility/elements/text-link.scss +1 -0
  77. package/utility/layout/split.scss +1 -0
  78. package/utility/utility-text.js +1 -0
  79. package/utils/object/deep-get.js +1 -2
  80. package/utils/translations/translate.js +13 -0
  81. package/vite.config.ts +1 -0
  82. package/watch.js +27 -0
  83. package/wizard/wizard-intro/wizard-intro.scss +4 -0
  84. package/wizard/wizard-layout/u-wizard-layout-block.vue +1 -1
  85. package/wizard/wizard-layout/u-wizard-layout-element.vue +1 -1
  86. package/wizard/wizard-layout/u-wizard-layout.vue +1 -1
  87. package/wizard/wizard-layout/wizard-layout.scss +6 -6
  88. package/dist/base-style.js +0 -2
  89. package/dist/base-style.js.map +0 -1
  90. package/dist/custom-elements.css +0 -1
  91. package/dist/custom-elements.js +0 -5185
  92. package/dist/custom-elements.js.map +0 -1
@@ -0,0 +1,208 @@
1
+ @use '../../base/abstracts/' as a;
2
+ @use '../../elements/text-link/text-link.scss' as t;
3
+
4
+ .richtext {
5
+ // Spacing rules
6
+ * + * {
7
+ margin-top: var(--e-space-3);
8
+ }
9
+
10
+ ul + *,
11
+ ol + * {
12
+ margin-top: var(--e-space-8);
13
+ }
14
+
15
+ * + h2,
16
+ * + h3,
17
+ * + .richtext__title-large,
18
+ * + .richtext__title-small {
19
+ margin-top: var(--e-space-16);
20
+ }
21
+
22
+ * + ul,
23
+ * + ol {
24
+ margin-top: var(--e-space-6);
25
+ }
26
+
27
+ @include a.bp(lg) {
28
+ * + * {
29
+ margin-top: var(--e-space-2);
30
+ }
31
+
32
+ ul + *,
33
+ ol + * {
34
+ margin-top: var(--e-space-6);
35
+ }
36
+
37
+ * + h2,
38
+ * + h3,
39
+ * + .richtext__title-large,
40
+ * + .richtext__title-small {
41
+ margin-top: var(--e-space-10);
42
+ }
43
+ }
44
+
45
+ // Element styles
46
+ h2,
47
+ .richtext__title-large {
48
+ @include a.type(700, strong);
49
+
50
+ color: var(--e-c-primary-01-500);
51
+
52
+ @include a.bp(lg) {
53
+ @include a.type(400, strong);
54
+ }
55
+ }
56
+
57
+ h3,
58
+ .richtext__title-small {
59
+ @include a.type(400, strong);
60
+
61
+ color: var(--e-c-primary-01-500);
62
+
63
+ @include a.bp(lg) {
64
+ @include a.type(300, strong);
65
+ }
66
+ }
67
+
68
+ p {
69
+ @include a.type(300);
70
+
71
+ @include a.bp(lg) {
72
+ @include a.type(200);
73
+ }
74
+ }
75
+
76
+ a {
77
+ @include t.text-link;
78
+ }
79
+
80
+ ul,
81
+ ol {
82
+ @include a.type(300);
83
+
84
+ padding-left: var(--e-space-4);
85
+
86
+ > li {
87
+ position: relative;
88
+ }
89
+
90
+ br {
91
+ font-size: 0; // Firefox hack
92
+ }
93
+
94
+ @include a.bp(lg) {
95
+ @include a.type(200);
96
+ }
97
+ }
98
+
99
+ ul {
100
+ > li {
101
+ &::before {
102
+ content: '';
103
+ position: absolute;
104
+ top: var(--e-space-2_5);
105
+ left: calc(var(--e-space-4) * -1);
106
+ display: block;
107
+ width: a.rem(8);
108
+ height: a.rem(8);
109
+ border-radius: 100%;
110
+ background-color: var(--e-c-secondary-05-500);
111
+ }
112
+
113
+ @include a.bp(lg) {
114
+ &::before {
115
+ top: var(--e-space-2);
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ ol {
122
+ counter-reset: li;
123
+
124
+ > li {
125
+ counter-increment: li;
126
+
127
+ &::before {
128
+ @include a.type(200, strong);
129
+
130
+ content: counter(li);
131
+ position: absolute;
132
+ top: 2px;
133
+ left: calc(var(--e-space-4) * -1);
134
+ display: block;
135
+ color: var(--e-c-secondary-05-500);
136
+ font-weight: 700;
137
+ }
138
+ }
139
+
140
+ @include a.bp(lg) {
141
+ > li::before {
142
+ top: 0;
143
+ }
144
+ }
145
+ }
146
+
147
+ u {
148
+ text-underline-offset: a.rem(4);
149
+ }
150
+
151
+ p,
152
+ h2,
153
+ h3,
154
+ a,
155
+ li {
156
+ text-wrap: pretty;
157
+ }
158
+
159
+ // Modifiers
160
+ &.richtext--inverted {
161
+ color: var(--e-c-mono-00);
162
+
163
+ h2,
164
+ h3,
165
+ .richtext__title-small,
166
+ .richtext__title-large {
167
+ color: var(--e-c-mono-00);
168
+ }
169
+
170
+ a {
171
+ @include t.text-link--inverted;
172
+ }
173
+
174
+ ul > li::before {
175
+ background-color: var(--e-c-mono-00);
176
+ }
177
+
178
+ ol > li::before {
179
+ color: var(--e-c-mono-00);
180
+ }
181
+ }
182
+
183
+ // TODO: Spacing between must also be adjusted for richtext--small.
184
+ &.richtext--small {
185
+ p {
186
+ @include a.type(200);
187
+ }
188
+
189
+ ul,
190
+ ol {
191
+ @include a.type(200);
192
+ }
193
+
194
+ ul {
195
+ > li {
196
+ &::before {
197
+ top: var(--e-space-2);
198
+ }
199
+ }
200
+ }
201
+
202
+ ol {
203
+ > li::before {
204
+ top: 0;
205
+ }
206
+ }
207
+ }
208
+ }
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ interface Props {
3
+ text?: string
4
+ small?: boolean
5
+ inverted?: boolean
6
+ }
7
+
8
+ const { small = false, inverted = false } = defineProps<Props>()
9
+
10
+ const classes = ['richtext', { 'richtext--small': small, 'richtext--inverted': inverted }]
11
+ </script>
12
+
13
+ <template>
14
+ <div v-if="text" :class="classes" v-html="text"></div>
15
+
16
+ <div v-else :class="classes"><slot></slot></div>
17
+ </template>
18
+
19
+ <style lang="scss">
20
+ @use './richtext.scss';
21
+ </style>
@@ -15,13 +15,8 @@ defineProps<Props>()
15
15
 
16
16
  <template>
17
17
  <div class="cell-ctas">
18
- <template v-for="cta in ctas">
19
- <UButton
20
- variant="plain"
21
- :icon="cta.icon"
22
- :href="cta.href"
23
- :target="cta.target"
24
- >
18
+ <template v-for="(cta, idx) in ctas" :key="idx">
19
+ <UButton variant="plain" :icon="cta.icon" :href="cta.href" :target="cta.target">
25
20
  <span class="button-label">{{ cta.label }}</span>
26
21
  </UButton>
27
22
  </template>
@@ -18,7 +18,7 @@ defineProps<Props>()
18
18
 
19
19
  <template>
20
20
  <div class="cell-icon-group">
21
- <template v-for="item in icons">
21
+ <template v-for="(item, idx) in icons" :key="idx">
22
22
  <UTooltip :title="item.title">
23
23
  <UIcon :name="item.icon" :class="[`icon-color-${item.color}`]"></UIcon>
24
24
  </UTooltip>
@@ -4,7 +4,7 @@ import UIcon from '../../elements/icon/u-icon.vue'
4
4
 
5
5
  interface Props extends TableCellBase {
6
6
  icon: string
7
- iconColor: TableCellIconColor
7
+ iconColor?: TableCellIconColor
8
8
  }
9
9
 
10
10
  const { iconColor = TableCellIconColor.grey } = defineProps<Props>()
@@ -12,7 +12,7 @@ const { labelPosition = 'top' } = defineProps<Props>()
12
12
 
13
13
  <template>
14
14
  <div :class="['cell-progress-bar', `label-position-${labelPosition}`]">
15
- <p class="progress-bar-label" v-if="label">{{ label }}</p>
15
+ <p v-if="label" class="progress-bar-label">{{ label }}</p>
16
16
  <UProgressBar :value="value"></UProgressBar>
17
17
  </div>
18
18
  </template>
@@ -1,10 +1,5 @@
1
1
  <script setup lang="ts">
2
- import {
3
- TableCellBase,
4
- TableCellHAlign,
5
- TableCellTextStyle,
6
- TableCellVAlign,
7
- } from './table.type'
2
+ import { TableCellBase, TableCellHAlign, TableCellTextStyle, TableCellVAlign } from './table.type'
8
3
  import UIcon from '../../elements/icon/u-icon.vue'
9
4
  import UTooltip from '../tooltip/u-tooltip.vue'
10
5
 
@@ -23,18 +18,13 @@ const {
23
18
  <template>
24
19
  <div
25
20
  role="cell"
26
- :class="[
27
- 'table-cell',
28
- `h-align-${hAlign}`,
29
- `v-align-${vAlign}`,
30
- { 'has-tooltip': infoText },
31
- ]"
21
+ :class="['table-cell', `h-align-${hAlign}`, `v-align-${vAlign}`, { 'has-tooltip': infoText }]"
32
22
  >
33
23
  <div :class="['cell-content', `text-${textStyle}`]">
34
24
  <slot>{{ text }}</slot>
35
25
  </div>
36
26
 
37
- <div class="info-tooltip" v-if="infoText">
27
+ <div v-if="infoText" class="info-tooltip">
38
28
  <UTooltip :title="infoText">
39
29
  <UIcon name="info"></UIcon>
40
30
  </UTooltip>
@@ -9,10 +9,7 @@ const { hAlign = 'left', vAlign = 'top' } = defineProps<Props>()
9
9
  </script>
10
10
 
11
11
  <template>
12
- <div
13
- role="cell"
14
- :class="['table-heading', `h-align-${hAlign}`, `v-align-${vAlign}`]"
15
- >
12
+ <div role="cell" :class="['table-heading', `h-align-${hAlign}`, `v-align-${vAlign}`]">
16
13
  <div class="cell-content">
17
14
  <slot :text="text">{{ text }}</slot>
18
15
  </div>
@@ -1,6 +1,26 @@
1
1
  import { getViewportDimensions } from './viewport'
2
2
  import { getOffsetParentPosition } from './dom'
3
3
 
4
+ export type Placement =
5
+ | 'top-right'
6
+ | 'top-left'
7
+ | 'top-center'
8
+ | 'bottom-right'
9
+ | 'bottom-left'
10
+ | 'bottom-center'
11
+ export interface PopoverPositionParams {
12
+ placement?: Placement
13
+ offset?: number
14
+ viewportPadding?: number
15
+ }
16
+
17
+ export interface PopoverPosition {
18
+ top: number
19
+ left: number
20
+ topCorrection: number
21
+ leftCorrection: number
22
+ }
23
+
4
24
  const defaultOptions = {
5
25
  offset: 0,
6
26
  viewportPadding: 0,
@@ -13,23 +33,25 @@ const defaultOptions = {
13
33
  *
14
34
  * @param {Element} refEl
15
35
  * @param {Element} popoverEl
16
- * @param {Object} options - Options object
17
- * @param {number} options.offset - offset to refEl in px
18
- * @param {number} options.viewportPadding - Padding to viewport in px
19
- * @param {string} options.placement - One of the following keywords: top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
36
+ * @param {Object} opts - Options object
37
+ * @param {number} opts.offset - offset to refEl in px
38
+ * @param {number} opts.viewportPadding - Padding to viewport in px
39
+ * @param {string} opts.placement - One of the following keywords: top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
20
40
  */
21
- export const getPopoverPosition = (refEl, popoverEl, options = {}) => {
22
- options = Object.assign({}, defaultOptions, options)
41
+ export const getPopoverPosition = (
42
+ refEl: HTMLElement,
43
+ popoverEl: HTMLElement,
44
+ opts: PopoverPositionParams,
45
+ ) => {
46
+ const options = Object.assign({}, defaultOptions, opts)
23
47
 
24
48
  const refRect = refEl.getBoundingClientRect()
25
49
  let popoverRect = popoverEl.getBoundingClientRect()
26
50
 
27
- const offsetParent = getOffsetParentPosition(refEl)
51
+ const { top: offsetTop, left: offsetLeft } = getOffsetParentPosition(refEl)
28
52
 
29
- let top
30
- let left
31
- const offsetTop = offsetParent.top
32
- const offsetLeft = offsetParent.left
53
+ let top = 0
54
+ let left = 0
33
55
  const { vpWidth } = getViewportDimensions()
34
56
  const docHeight = document.documentElement.scrollHeight
35
57
  const scrollY = window.scrollY
@@ -46,7 +68,6 @@ export const getPopoverPosition = (refEl, popoverEl, options = {}) => {
46
68
  case 'top-right':
47
69
  top = offsetTop - popoverRect.height - options.offset
48
70
  left = offsetLeft + refRect.width - popoverRect.width
49
- // console.log(left)
50
71
  break
51
72
 
52
73
  case 'top-left':
@@ -77,10 +98,7 @@ export const getPopoverPosition = (refEl, popoverEl, options = {}) => {
77
98
  const leftDiff = refRect.left - offsetLeft
78
99
  if (left + leftDiff < options.viewportPadding) {
79
100
  left = 0 - leftDiff + options.viewportPadding
80
- } else if (
81
- left + leftDiff + popoverRect.width >
82
- vpWidth - options.viewportPadding
83
- ) {
101
+ } else if (left + leftDiff + popoverRect.width > vpWidth - options.viewportPadding) {
84
102
  left = vpWidth - leftDiff - popoverRect.width - options.viewportPadding
85
103
  }
86
104
 
@@ -88,23 +106,15 @@ export const getPopoverPosition = (refEl, popoverEl, options = {}) => {
88
106
  const topDiff = refRect.top - offsetTop
89
107
  if (top + topDiff + scrollY < options.viewportPadding) {
90
108
  // popover is too high.
91
- // console.log('too high')
92
109
  // Switch position to bottom
93
110
  top = offsetTop + refRect.height + options.offset
94
- } else if (
95
- top + topDiff + scrollY + popoverRect.height >
96
- docHeight - options.viewportPadding
97
- ) {
111
+ } else if (top + topDiff + scrollY + popoverRect.height > docHeight - options.viewportPadding) {
98
112
  // popover is too low.
99
- // console.log('too low')
100
113
  // Swith position to top.
101
114
  top = offsetTop - popoverRect.height - options.offset
102
115
  }
103
116
 
104
- return {
105
- top,
106
- left,
107
- }
117
+ return { top, left }
108
118
  }
109
119
 
110
120
  /**
@@ -112,21 +122,26 @@ export const getPopoverPosition = (refEl, popoverEl, options = {}) => {
112
122
  *
113
123
  * @param {Element} refEl
114
124
  * @param {Element} popoverEl
115
- * @param {Object} options - Options object
116
- * @param {number} options.offset - offset to refEl in px
117
- * @param {number} options.viewportPadding - Padding to viewport in px
118
- * @param {string} options.placement - One of the following keywords: top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
125
+ * @param {Object} opts - Options object
126
+ * @param {number} opts.offset - offset to refEl in px
127
+ * @param {number} opts.viewportPadding - Padding to viewport in px
128
+ * @param {string} opts.placement - One of the following keywords: top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
119
129
  */
120
- export const getPopoverPositionBody = (refEl, popoverEl, options = {}) => {
121
- options = Object.assign({}, defaultOptions, options)
130
+ export function getPopoverPositionBody(
131
+ refEl: HTMLElement,
132
+ popoverEl: HTMLElement,
133
+ opts: PopoverPositionParams,
134
+ ): PopoverPosition {
135
+ const options = Object.assign({}, defaultOptions, opts)
122
136
 
123
137
  const refRect = refEl.getBoundingClientRect()
124
138
  let popoverRect = popoverEl.getBoundingClientRect()
125
139
 
126
- let top
127
- let left
140
+ let top = 0
141
+ let left = 0
128
142
  const topCorrection = 0
129
143
  let leftCorrection = 0
144
+
130
145
  const scrollY = window.scrollY
131
146
  const scrollX = window.scrollX
132
147
  const { vpWidth } = getViewportDimensions()
@@ -146,7 +161,6 @@ export const getPopoverPositionBody = (refEl, popoverEl, options = {}) => {
146
161
  case 'top-right':
147
162
  // top = offsetTop - popoverRect.height - options.offset
148
163
  // left = offsetLeft + refRect.width - popoverRect.width
149
- // console.log(left)
150
164
  break
151
165
 
152
166
  case 'top-left':
@@ -183,18 +197,12 @@ export const getPopoverPositionBody = (refEl, popoverEl, options = {}) => {
183
197
  left = options.viewportPadding
184
198
  } else if (left + popoverRect.width > vpWidth - options.viewportPadding) {
185
199
  // too right
186
- leftCorrection =
187
- vpWidth - options.viewportPadding - popoverRect.width - left
200
+ leftCorrection = vpWidth - options.viewportPadding - popoverRect.width - left
188
201
  left = vpWidth - options.viewportPadding - popoverRect.width
189
202
  }
190
203
 
191
204
  // Check top or bottom overflow
192
205
  // TODO: Add these corrections
193
206
 
194
- return {
195
- top,
196
- left,
197
- leftCorrection,
198
- topCorrection,
199
- }
207
+ return { top, left, leftCorrection, topCorrection }
200
208
  }
@@ -1,88 +1,68 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue'
3
3
  import { getPopoverPositionBody } from './popover'
4
+ import type { PopoverPositionParams } from './popover'
4
5
 
5
- interface Props {
6
+ interface Props extends PopoverPositionParams {
6
7
  title: string
7
- placement?:
8
- | 'top-right'
9
- | 'top-left'
10
- | 'top-center'
11
- | 'bottom-right'
12
- | 'bottom-left'
13
- | 'bottom-center'
14
- offset?: number
15
- viewportPadding?: number
16
8
  }
17
9
 
18
- const {
19
- placement = 'top-center',
20
- offset = 12,
21
- viewportPadding = 20,
22
- } = defineProps<Props>()
10
+ const { placement = 'top-center', offset = 12, viewportPadding = 20 } = defineProps<Props>()
23
11
 
24
- const tooltip = ref(null)
25
- const root = ref(null)
26
- const pointer = ref(null)
12
+ const tooltip = ref<HTMLDivElement | null>(null)
13
+ const root = ref<HTMLSpanElement | null>(null)
14
+ const pointer = ref<HTMLSpanElement | null>(null)
15
+ const isTooltipVisible = ref<boolean>(false)
27
16
 
28
- const showTooltip = () => {
29
- const popoverPosition = getPopoverPositionBody(root.value, tooltip.value, {
30
- offset,
31
- placement,
32
- viewportPadding,
33
- })
34
-
35
- // Set position
36
- tooltip.value.style.top = `${popoverPosition.top}px`
37
- tooltip.value.style.left = `${popoverPosition.left}px`
38
-
39
- // Fix pointer position if necessary
40
- if (popoverPosition.leftCorrection) {
41
- pointer.value.style.transform = `translateX(${popoverPosition.leftCorrection * -1}px)`
42
- }
43
-
44
- tooltip.value.ariaHidden = 'false'
45
- tooltip.value.classList.toggle('tooltip--open', true)
17
+ // On desktop (or non-touch devices) mouse events will be fired before the pointer events.
18
+ // For mobile and touch devices it's th opposite, pointer events will be fired first.
19
+ // This way we can detect on what device we are and handle the behaviour accordingly.
20
+ function hideTooltip() {
21
+ isTooltipVisible.value = false
46
22
  }
47
23
 
48
- const hideTooltip = () => {
49
- const onTransitionend = () => {
50
- tooltip.value.removeEventListener('transitionend', onTransitionend)
51
-
52
- tooltip.value.style.top = ''
53
- tooltip.value.style.left = ''
54
- pointer.value.style.transform = ''
55
- }
56
-
57
- tooltip.value.addEventListener('transitionend', onTransitionend)
58
-
59
- tooltip.value.ariaHidden = 'true'
60
- tooltip.value.classList.toggle('tooltip--open', false)
24
+ function showTooltip() {
25
+ updatePositions()
26
+ isTooltipVisible.value = true
61
27
  }
62
28
 
63
- // On desktop (or non-touch devices) mouse events will be fired before the pointer events.
64
- // For mobile and touch devices it's th opposite, pointer events will be fired first.
65
- // This way we can detect on what device we are and handle the behaviour accordingly.
66
- const onMouseenter = () => {
67
- showTooltip()
29
+ function onTransitionend() {
30
+ if (isTooltipVisible.value) return
31
+ updatePositions(true)
32
+ isTooltipVisible.value = false
68
33
  }
69
34
 
70
- const onMouseleave = () => {
71
- hideTooltip()
35
+ function updatePositions(resetPositions = false) {
36
+ const { top, left, leftCorrection } = getPopoverPositionBody(root.value!, tooltip.value!, {
37
+ offset,
38
+ placement,
39
+ viewportPadding,
40
+ })
41
+
42
+ tooltip.value!.style.top = resetPositions ? '' : `${top}px`
43
+ tooltip.value!.style.left = resetPositions ? '' : `${left}px`
44
+ // Fix pointer position if necessary
45
+ pointer.value!.style.transform =
46
+ !resetPositions && leftCorrection ? `translateX(${leftCorrection * -1}px)` : ''
72
47
  }
73
48
  </script>
74
49
 
75
50
  <template>
76
- <span @mouseenter="onMouseenter" @mouseleave="onMouseleave" ref="root">
77
- <slot></slot>
51
+ <span ref="root" @mouseenter="showTooltip" @mouseleave="hideTooltip">
52
+ <slot />
78
53
  </span>
79
54
 
80
55
  <Teleport to="body">
81
- <div ref="tooltip" class="tooltip">
56
+ <div
57
+ ref="tooltip"
58
+ :class="['tooltip', { 'tooltip--open': isTooltipVisible }]"
59
+ :aria-hidden="!isTooltipVisible"
60
+ @transitionend="onTransitionend"
61
+ >
82
62
  <div class="tooltip__content">
83
63
  {{ title }}
84
64
  </div>
85
- <span class="tooltip__pointer" ref="pointer"></span>
65
+ <span ref="pointer" class="tooltip__pointer" />
86
66
  </div>
87
67
  </Teleport>
88
68
  </template>