@energie360/ui-library 0.1.17 → 0.1.18

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 (85) hide show
  1. package/components/badge/badge.scss +56 -0
  2. package/components/badge/u-badge.vue +47 -0
  3. package/components/card-contact/card-contact.scss +39 -0
  4. package/components/card-contact/u-card-contact.vue +44 -0
  5. package/components/card-cta-bar/card-cta-bar.scss +4 -0
  6. package/components/card-cta-bar/u-card-cta-bar.vue +24 -0
  7. package/components/card-cta-header/u-card-cta-header.vue +10 -7
  8. package/components/card-footer/u-card-footer.vue +5 -3
  9. package/components/card-group/u-card-group.vue +1 -1
  10. package/components/card-header/card-header.scss +29 -4
  11. package/components/card-header/u-card-header.vue +22 -3
  12. package/components/card-highlight/card-highlight.scss +70 -0
  13. package/components/card-highlight/u-card-highlight.vue +41 -0
  14. package/components/card-price-list/card-price-list.scss +39 -0
  15. package/components/card-price-list/u-card-price-list.vue +37 -0
  16. package/components/card-section/card-section.scss +21 -1
  17. package/components/card-section/u-card-section.vue +9 -1
  18. package/components/data-card/data-card.scss +34 -0
  19. package/components/data-card/u-data-card.vue +49 -0
  20. package/components/data-card-group/data-card-group.scss +12 -0
  21. package/components/data-card-group/u-data-card-group.vue +7 -0
  22. package/components/download-list/download-list.scss +58 -0
  23. package/components/download-list/u-download-list.vue +44 -0
  24. package/components/download-list-item/download-list-item.scss +267 -0
  25. package/components/download-list-item/u-download-list-item.vue +65 -0
  26. package/components/file-upload/file-list.scss +68 -0
  27. package/components/file-upload/file-upload.scss +119 -0
  28. package/components/file-upload/u-file-list.vue +55 -0
  29. package/components/file-upload/u-file-upload.vue +220 -0
  30. package/components/hint/hint.scss +67 -6
  31. package/components/hint/u-hint.vue +11 -1
  32. package/components/index.js +12 -0
  33. package/components/progress-avatar/u-progress-avatar.vue +27 -3
  34. package/components/search-group/search-group.scss +59 -0
  35. package/components/search-group/u-search-group.vue +32 -0
  36. package/components/skeleton-loader/skeleton-loader.scss +39 -0
  37. package/components/skeleton-loader/u-skeleton-loader.vue +28 -0
  38. package/components/table/cell-ctas.scss +1 -7
  39. package/components/table/cell-icon-text.scss +15 -4
  40. package/components/table/table-cell.mixins.scss +3 -2
  41. package/components/table/table-cell.scss +5 -0
  42. package/components/table/table-heading.scss +7 -0
  43. package/components/table/u-cell-ctas.vue +15 -6
  44. package/components/table/u-cell-icon-text.vue +13 -5
  45. package/components/table/u-table-cell.vue +3 -1
  46. package/components/table/u-table-heading.vue +2 -1
  47. package/components/tabs/tabs.scss +10 -1
  48. package/components/tabs/u-tabs.vue +64 -25
  49. package/dist/layout/split.css.map +1 -1
  50. package/elements/button/_button-plain-small-spaceless.scss +10 -0
  51. package/elements/button/button.scss +32 -0
  52. package/elements/button/u-button.vue +47 -4
  53. package/elements/form-field/form-field-base.scss +4 -0
  54. package/elements/select/u-select.vue +6 -6
  55. package/elements/text-field/text-field.scss +15 -0
  56. package/elements/text-field/text-field.types.ts +1 -0
  57. package/elements/text-field/u-text-field.vue +27 -6
  58. package/elements/toggle-switch/toggle-switch-small.scss +10 -0
  59. package/elements/toggle-switch/toggle-switch.scss +25 -21
  60. package/elements/toggle-switch/u-toggle-switch.vue +22 -12
  61. package/i18n/i18n.ts +32 -0
  62. package/layout/container/container.scss +18 -0
  63. package/layout/index.js +2 -0
  64. package/layout/portal/portal.scss +35 -7
  65. package/layout/portal/u-portal.vue +33 -4
  66. package/layout/settings/settings.scss +2 -2
  67. package/layout/tile-grid/tile-grid.scss +13 -0
  68. package/layout/tile-grid/tile-item.scss +31 -0
  69. package/layout/tile-grid/u-tile-grid.vue +7 -0
  70. package/layout/tile-grid/u-tile-item.vue +15 -0
  71. package/modules/content-title/content-title.scss +43 -0
  72. package/modules/content-title/u-content-title.vue +19 -0
  73. package/modules/dialog/dialog.scss +7 -3
  74. package/modules/dialog/u-dialog.vue +6 -1
  75. package/modules/footer/footer.scss +8 -1
  76. package/modules/footer/u-footer.vue +1 -1
  77. package/modules/index.js +2 -0
  78. package/modules/search-filter/search-filter.scss +106 -0
  79. package/modules/search-filter/u-search-filter.vue +54 -0
  80. package/package.json +2 -1
  81. package/utils/array/intersect.js +7 -0
  82. package/utils/functions/breakpoint.js +4 -9
  83. package/utils/functions/format-bytes.js +17 -0
  84. package/utils/global/mime-types.js +8 -0
  85. package/utils/translations/translate.js +10 -2
@@ -13,10 +13,21 @@
13
13
  }
14
14
 
15
15
  @include a.type(100);
16
- }
17
16
 
18
- .cell-text {
19
- @include a.bp(m) {
20
- @include a.visually-hidden;
17
+ // Modifiers
18
+ &.hide-text-lg {
19
+ .cell-text {
20
+ @include a.bp(lg) {
21
+ @include a.visually-hidden;
22
+ }
23
+ }
24
+ }
25
+
26
+ &.hide-text-m {
27
+ .cell-text {
28
+ @include a.bp(m) {
29
+ @include a.visually-hidden;
30
+ }
31
+ }
21
32
  }
22
33
  }
@@ -4,8 +4,7 @@
4
4
  display: table-cell;
5
5
  padding: var(--e-space-4);
6
6
  height: a.rem(56);
7
-
8
- @include a.type(100);
7
+ line-height: 0;
9
8
 
10
9
  @include a.bp(m) {
11
10
  height: auto;
@@ -18,6 +17,8 @@
18
17
  }
19
18
 
20
19
  .cell-content {
20
+ @include a.type(100);
21
+
21
22
  display: inline-flex;
22
23
  column-gap: var(--e-space-2);
23
24
  min-height: a.rem(24);
@@ -14,6 +14,11 @@
14
14
  &.text-bold {
15
15
  font-weight: var(--e-type-weight-strong);
16
16
  }
17
+
18
+ // Modifiers
19
+ &.nowrap {
20
+ white-space: nowrap;
21
+ }
17
22
  }
18
23
 
19
24
  .info-tooltip {
@@ -6,3 +6,10 @@
6
6
 
7
7
  @include c.table-cell-base;
8
8
  }
9
+
10
+ .cell-content {
11
+ // Modifiers
12
+ &.nowrap {
13
+ white-space: nowrap;
14
+ }
15
+ }
@@ -4,10 +4,11 @@ import UButton from '../../elements/button/u-button.vue'
4
4
 
5
5
  interface CellCta extends Cta {
6
6
  icon: string
7
+ attr: object
7
8
  }
8
9
 
9
10
  interface Props {
10
- ctas: CellCta[]
11
+ ctas?: CellCta[]
11
12
  }
12
13
 
13
14
  defineProps<Props>()
@@ -16,13 +17,21 @@ defineProps<Props>()
16
17
  <template>
17
18
  <div class="cell-ctas">
18
19
  <template v-for="(cta, idx) in ctas" :key="idx">
19
- <UButton variant="plain" :icon="cta.icon" :href="cta.href" :target="cta.target">
20
- <span class="button-label">{{ cta.label }}</span>
20
+ <UButton
21
+ nowrap
22
+ variant="plain"
23
+ :icon="cta.icon"
24
+ :href="cta.href"
25
+ :target="cta.target"
26
+ v-bind="cta.attr"
27
+ hide-label-m
28
+ >
29
+ {{ cta.label }}
21
30
  </UButton>
22
31
  </template>
32
+
33
+ <slot></slot>
23
34
  </div>
24
35
  </template>
25
36
 
26
- <style scoped lang="scss">
27
- @use './cell-ctas.scss';
28
- </style>
37
+ <style scoped lang="scss" src="./cell-ctas.scss"></style>
@@ -5,19 +5,27 @@ import UIcon from '../../elements/icon/u-icon.vue'
5
5
  interface Props extends TableCellBase {
6
6
  icon: string
7
7
  iconColor?: TableCellIconColor
8
+ hideTextM?: false
9
+ hideTextLg?: false
8
10
  }
9
11
 
10
12
  const { iconColor = TableCellIconColor.grey } = defineProps<Props>()
11
13
  </script>
12
14
 
13
15
  <template>
14
- <div :class="['cell-icon-text', `icon-color-${iconColor}`]">
16
+ <div
17
+ :class="[
18
+ 'cell-icon-text',
19
+ `icon-color-${iconColor}`,
20
+ { 'hide-text-m': hideTextM, 'hide-text-lg': hideTextLg },
21
+ ]"
22
+ >
15
23
  <UIcon :name="icon"></UIcon>
16
24
 
17
- <span class="cell-text">{{ text }}</span>
25
+ <span class="cell-text">
26
+ <slot>{{ text }}</slot>
27
+ </span>
18
28
  </div>
19
29
  </template>
20
30
 
21
- <style scoped lang="scss">
22
- @use './cell-icon-text.scss';
23
- </style>
31
+ <style scoped lang="scss" src="./cell-icon-text.scss"></style>
@@ -6,12 +6,14 @@ import UTooltip from '../tooltip/u-tooltip.vue'
6
6
  interface Props extends TableCellBase {
7
7
  infoText?: string
8
8
  textStyle?: TableCellTextStyle
9
+ nowrap?: boolean
9
10
  }
10
11
 
11
12
  const {
12
13
  textStyle = TableCellTextStyle.normal,
13
14
  hAlign = TableCellHAlign.left,
14
15
  vAlign = TableCellVAlign.center,
16
+ nowrap = false,
15
17
  } = defineProps<Props>()
16
18
  </script>
17
19
 
@@ -20,7 +22,7 @@ const {
20
22
  role="cell"
21
23
  :class="['table-cell', `h-align-${hAlign}`, `v-align-${vAlign}`, { 'has-tooltip': infoText }]"
22
24
  >
23
- <div :class="['cell-content', `text-${textStyle}`]">
25
+ <div :class="['cell-content', `text-${textStyle}`, { nowrap }]">
24
26
  <slot>{{ text }}</slot>
25
27
  </div>
26
28
 
@@ -3,6 +3,7 @@ interface Props {
3
3
  text?: string
4
4
  hAlign?: 'left' | 'center' | 'right'
5
5
  vAlign?: 'top' | 'center' | 'bottom'
6
+ nowrap?: boolean
6
7
  }
7
8
 
8
9
  const { hAlign = 'left', vAlign = 'top' } = defineProps<Props>()
@@ -10,7 +11,7 @@ const { hAlign = 'left', vAlign = 'top' } = defineProps<Props>()
10
11
 
11
12
  <template>
12
13
  <div role="cell" :class="['table-heading', `h-align-${hAlign}`, `v-align-${vAlign}`]">
13
- <div class="cell-content">
14
+ <div :class="['cell-content', { nowrap }]">
14
15
  <slot :text="text">{{ text }}</slot>
15
16
  </div>
16
17
  </div>
@@ -1,4 +1,4 @@
1
- @use '../../base/abstracts/' as a;
1
+ @use '../../base/abstracts' as a;
2
2
 
3
3
  .tabs {
4
4
  $scroll-space: 18px;
@@ -86,3 +86,12 @@
86
86
  width a.$trs-default;
87
87
  }
88
88
  }
89
+
90
+ // Modifiers
91
+ .tabs.no-gradient {
92
+ .tabs__wrapper {
93
+ &::after {
94
+ content: none;
95
+ }
96
+ }
97
+ }
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { useTemplateRef, ref, watch } from 'vue'
2
+ import { useTemplateRef, ref, watch, useSlots } from 'vue'
3
3
  import { getOffsetParentPosition } from '../../utils/dom/dom'
4
4
  import { debounce } from '../../utils/functions/debounce'
5
5
 
@@ -11,14 +11,16 @@ interface Tab {
11
11
 
12
12
  interface Props {
13
13
  activation?: 'manual' | 'automatic'
14
- items: Tab[]
14
+ items?: Tab[]
15
+ noGradient?: boolean
15
16
  }
16
17
 
17
- const { activation = 'manual' } = defineProps<Props>()
18
+ const { items = [], activation = 'manual' } = defineProps<Props>()
18
19
  const emit = defineEmits<{ (e: 'tabFocus', id: string): void }>()
19
20
 
20
21
  const model = defineModel<string>()
21
22
  const activeBarStyles = ref({})
23
+ const slots = useSlots()
22
24
 
23
25
  const tabs = useTemplateRef('tabs')
24
26
  const list = useTemplateRef('list')
@@ -87,7 +89,14 @@ const onResize = debounce(() => {
87
89
  const isActiveTab = (currentTabId: string) => currentTabId === model.value
88
90
 
89
91
  const positionActiveBar = () => {
90
- const activeTabEl = tabs.value.find((item) => item.value === model.value)
92
+ let activeTabEl
93
+
94
+ if (slots.default) {
95
+ activeTabEl = Array.from(list.value.children).find((el) => el.classList.contains('active'))
96
+ } else {
97
+ activeTabEl = tabs.value.find((item) => item.value === model.value)
98
+ }
99
+
91
100
  const activeTabRelPos = getOffsetParentPosition(activeTabEl)
92
101
 
93
102
  activeBarStyles.value = {
@@ -107,36 +116,66 @@ onResize()
107
116
  </script>
108
117
 
109
118
  <template>
110
- <div class="tabs">
119
+ <div :class="['tabs', { 'no-gradient': noGradient }]">
111
120
  <div class="tabs__row">
112
121
  <div class="tabs__col">
113
122
  <div class="tabs__wrapper">
114
123
  <div ref="list" class="tabs__list" role="tablist">
115
- <button
116
- v-for="(item, idx) in items"
117
- :key="idx"
118
- ref="tabs"
119
- :class="{ active: isActiveTab(item.value) }"
120
- :value="item.value"
121
- type="button"
122
- role="tab"
123
- :tabindex="isActiveTab(item.value) ? 0 : -1"
124
- :aria-selected="isActiveTab(item.value)"
125
- v-bind="item.analyticsAttributes || {}"
126
- @click="onTabClick"
127
- @keydown="onTabKeyDown"
128
- >
129
- {{ item.label }}
130
- </button>
131
-
132
- <div class="tabs__active-bar" :style="activeBarStyles"></div>
124
+ <slot>
125
+ <button
126
+ v-for="(item, idx) in items"
127
+ :key="idx"
128
+ ref="tabs"
129
+ :class="{ active: isActiveTab(item.value) }"
130
+ :value="item.value"
131
+ type="button"
132
+ role="tab"
133
+ :tabindex="isActiveTab(item.value) ? 0 : -1"
134
+ :aria-selected="isActiveTab(item.value)"
135
+ v-bind="item.analyticsAttributes || {}"
136
+ @click="onTabClick"
137
+ @keydown="onTabKeyDown"
138
+ >
139
+ {{ item.label }}
140
+ </button>
141
+ </slot>
133
142
  </div>
143
+ <div class="tabs__active-bar" :style="activeBarStyles"></div>
134
144
  </div>
135
145
  </div>
136
146
  </div>
137
147
  </div>
138
148
  </template>
139
149
 
140
- <style lang="scss">
141
- @use './tabs.scss';
150
+ <style scoped lang="scss" src="./tabs.scss"></style>
151
+ <style scoped lang="scss">
152
+ @use '../../base/abstracts' as a;
153
+
154
+ .tabs__list {
155
+ :slotted(a),
156
+ :slotted(button) {
157
+ @include a.type(200, strong);
158
+
159
+ display: block;
160
+ padding: var(--e-space-4);
161
+ text-decoration: none;
162
+ color: var(--e-c-mono-700);
163
+ transition: color a.$trs-default;
164
+ white-space: nowrap;
165
+ outline-offset: -4px;
166
+ cursor: pointer;
167
+
168
+ &.active,
169
+ &:focus,
170
+ &:hover {
171
+ color: var(--e-c-primary-01-700);
172
+ }
173
+
174
+ @include a.bp(lg) {
175
+ @include a.type(100, strong);
176
+
177
+ padding: var(--e-space-2) var(--e-space-3);
178
+ }
179
+ }
180
+ }
142
181
  </style>
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../../base/abstracts/_variables.scss","../../base/abstracts/_functions.scss","../../layout/container/container.scss","../../base/abstracts/_mixins.scss","../../layout/split/split.scss"],"names":[],"mappings":"AAqCiF;AChCjF;ACsBA;EAtBE;EACA;EACA;EACA;EACA;;ACYA;EDMF;IAfI;IACA;;;ACQF;EDMF;IAVI;IACA;;;ACGF;EDMF;IALI;IACA;;;;AEjBJ;EACE;EACA;EACA;EACA;EACA;;ADUA;ECfF;IAQI;IACA;IACA;IACA;IACA;IACA,qBACE;;;ADCJ;ECfF;IAmBI;IACA;;;;AAIJ;EACE;EACA;;ADXA;ECSF;IAKI;IACA;;;ADfF;ECSF;IAUI;IACA;IACA;;;;AAIJ;EACE;;AD1BA;ECyBF;IAII;IACA;;;AD9BF;ECyBF;IASI;;;;AAIJ;EACE;EACA;EACA;EACA;;AD1CA;ECsCF;IAOI;IAIA;IACA;;;ADlDF;ECsCF;IAgBI;IACA;IACA;IACA;IACA;IACA;;;AD3DF;ECsCF;IAyBI;IACA;IACA;;;;AAIJ;EACE;;ADtEA;ECqEF;IAII;;;ADzEF;ECqEF;IAQI","file":"split.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../../base/abstracts/_variables.scss","../../base/abstracts/_functions.scss","../../layout/container/container.scss","../../base/abstracts/_mixins.scss","../../layout/split/split.scss"],"names":[],"mappings":"AAqCiF;AChCjF;ACwCA;EAxCE;EACA;EACA;EACA;EACA;;ACYA;EDwBF;IAjCI;IACA;;;ACQF;EDwBF;IA5BI;IACA;;;ACGF;EDwBF;IAvBI;IACA;;;;AEjBJ;EACE;EACA;EACA;EACA;EACA;;ADUA;ECfF;IAQI;IACA;IACA;IACA;IACA;IACA,qBACE;;;ADCJ;ECfF;IAmBI;IACA;;;;AAIJ;EACE;EACA;;ADXA;ECSF;IAKI;IACA;;;ADfF;ECSF;IAUI;IACA;IACA;;;;AAIJ;EACE;;AD1BA;ECyBF;IAII;IACA;;;AD9BF;ECyBF;IASI;;;;AAIJ;EACE;EACA;EACA;EACA;;AD1CA;ECsCF;IAOI;IAIA;IACA;;;ADlDF;ECsCF;IAgBI;IACA;IACA;IACA;IACA;IACA;;;AD3DF;ECsCF;IAyBI;IACA;IACA;;;;AAIJ;EACE;;ADtEA;ECqEF;IAII;;;ADzEF;ECqEF;IAQI","file":"split.css"}
@@ -0,0 +1,10 @@
1
+ @use '../../base/abstracts' as a;
2
+ @use './button-plain' as *;
3
+
4
+ @mixin button-plain-small-spaceless {
5
+ @include button-plain;
6
+ @include a.type(100, strong);
7
+
8
+ padding: 0;
9
+ border-radius: var(--e-brd-radius-1); // For nicer focus outline.
10
+ }
@@ -4,6 +4,7 @@
4
4
  @use 'button-plain' as *;
5
5
  @use 'button-plain-spaceless' as *;
6
6
  @use 'button-plain-small' as *;
7
+ @use 'button-plain-small-spaceless' as *;
7
8
  @use 'button-filled-inverted' as *;
8
9
  @use 'button-outlined-inverted' as *;
9
10
  @use 'button-secondary-outlined' as *;
@@ -41,6 +42,10 @@
41
42
  @include button-plain-small;
42
43
  }
43
44
 
45
+ &.plain-small-spaceless {
46
+ @include button-plain-small-spaceless;
47
+ }
48
+
44
49
  &.filled-inverted {
45
50
  @include button-filled-inverted;
46
51
  }
@@ -70,4 +75,31 @@
70
75
  --icon-fill-color: transparent;
71
76
  }
72
77
  }
78
+
79
+ // Modifiers
80
+ &.nowrap {
81
+ white-space: nowrap;
82
+ }
83
+
84
+ // In some cases we need to force full width of a button.
85
+ // Is mostly the case when the button is wrapped by another element.
86
+ &.full-width {
87
+ width: 100%;
88
+ }
89
+
90
+ &.hide-label-lg {
91
+ @include a.bp(lg) {
92
+ .button__label {
93
+ @include a.visually-hidden;
94
+ }
95
+ }
96
+ }
97
+
98
+ &.hide-label-m {
99
+ @include a.bp(m) {
100
+ .button__label {
101
+ @include a.visually-hidden;
102
+ }
103
+ }
104
+ }
73
105
  }
@@ -12,6 +12,10 @@ interface ButtonProps {
12
12
  target?: string
13
13
  variant?: string
14
14
  asSpan?: boolean
15
+ nowrap?: boolean
16
+ fullWidth?: boolean
17
+ hideLabelM?: boolean
18
+ hideLabelLg?: boolean
15
19
  }
16
20
 
17
21
  const { asSpan = false } = defineProps<ButtonProps>()
@@ -21,20 +25,59 @@ const buttonTag = computed(() => (asSpan ? 'span' : 'button'))
21
25
 
22
26
  <template>
23
27
  <template v-if="href">
24
- <a :class="['button', variant]" :href :target>
28
+ <a
29
+ :class="[
30
+ 'button',
31
+ variant,
32
+ {
33
+ nowrap,
34
+ 'full-width': fullWidth,
35
+ 'hide-label-m': hideLabelM,
36
+ 'hide-label-lg': hideLabelLg,
37
+ },
38
+ ]"
39
+ :href
40
+ :target
41
+ v-bind="$attrs"
42
+ >
25
43
  <UIcon v-if="icon" :name="icon"></UIcon>
26
- <slot>{{ label }}</slot>
44
+
45
+ <span v-if="hideLabelM || hideLabelLg" class="button__label">
46
+ <slot>{{ label }}</slot>
47
+ </span>
48
+
49
+ <template v-else>
50
+ <slot>{{ label }}</slot>
51
+ </template>
27
52
  </a>
28
53
  </template>
29
54
 
30
55
  <template v-else>
31
56
  <component
32
57
  :is="buttonTag"
33
- :class="['button', variant, { loading: loading, disabled }]"
58
+ :class="[
59
+ 'button',
60
+ variant,
61
+ {
62
+ nowrap,
63
+ 'full-width': fullWidth,
64
+ 'hide-label-m': hideLabelM,
65
+ 'hide-label-lg': hideLabelLg,
66
+ loading: loading,
67
+ disabled,
68
+ },
69
+ ]"
34
70
  :disabled="disabled || null"
35
71
  >
36
72
  <UIcon v-if="icon" :name="icon" />
37
- <slot>{{ label }}</slot>
73
+
74
+ <span v-if="hideLabelM || hideLabelLg" class="button__label">
75
+ <slot>{{ label }}</slot>
76
+ </span>
77
+
78
+ <template v-else>
79
+ <slot>{{ label }}</slot>
80
+ </template>
38
81
 
39
82
  <span v-if="loading" class="button__loader">
40
83
  <ULoader />
@@ -23,6 +23,10 @@
23
23
  font-size a.$trs-default,
24
24
  color a.$trs-default,
25
25
  line-height a.$trs-default;
26
+ white-space: nowrap;
27
+ max-width: calc(100% - var(--e-space-6));
28
+ overflow: hidden;
29
+ text-overflow: ellipsis;
26
30
  }
27
31
 
28
32
  .control {
@@ -51,7 +51,7 @@ const onHoverOut = () => {
51
51
  }
52
52
 
53
53
  const hasHelpText = computed(() => {
54
- return !!helpText || !!slots.helpText || required
54
+ return !!helpText || !!slots.helpText || !required
55
55
  })
56
56
 
57
57
  const needsHelpTextSpacer = computed(() => {
@@ -70,7 +70,7 @@ const needsHelpTextSpacer = computed(() => {
70
70
  hover: isHovering,
71
71
  'float-label': true,
72
72
  'has-error': error,
73
- 'show-help-text': !required || hasHelpText,
73
+ 'show-help-text': hasHelpText,
74
74
  },
75
75
  ]"
76
76
  @mouseenter="onHover"
@@ -111,10 +111,10 @@ const needsHelpTextSpacer = computed(() => {
111
111
  </div>
112
112
 
113
113
  <div class="help-text">
114
- <span class="optional-text"
115
- >{{ getTranslation('optional')
116
- }}<span v-if="needsHelpTextSpacer" v-html="spacer"></span></span
117
- ><slot name="helpText">{{ helpText }}</slot>
114
+ <span class="optional-text">
115
+ {{ getTranslation('optional') }}<span v-if="needsHelpTextSpacer" v-html="spacer"></span>
116
+ </span>
117
+ <slot name="helpText">{{ helpText }}</slot>
118
118
  </div>
119
119
 
120
120
  <div class="error-messages-container">
@@ -28,4 +28,19 @@
28
28
  color: var(--e-c-secondary-01-700);
29
29
  }
30
30
  }
31
+
32
+ // Type: Search
33
+ .cancel-search {
34
+ display: block;
35
+ border-radius: var(--e-brd-radius-1);
36
+ color: var(--e-c-primary-01-900);
37
+ visibility: hidden;
38
+ pointer-events: none;
39
+
40
+ &.visible {
41
+ visibility: visible;
42
+ pointer-events: auto;
43
+ cursor: pointer;
44
+ }
45
+ }
31
46
  }
@@ -4,4 +4,5 @@ export enum TextFieldTypes {
4
4
  email = 'email',
5
5
  password = 'password',
6
6
  date = 'date',
7
+ search = 'search',
7
8
  }
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import UIcon from '../icon/u-icon.vue'
3
3
  import { TextFieldTypes } from './text-field.types'
4
- import { computed, ref, useSlots, useTemplateRef, useId, watch } from 'vue'
4
+ import { computed, ref, useId, useSlots, useTemplateRef, watch } from 'vue'
5
5
  import { FormFieldBase } from '../form-field/form-field.types'
6
6
  import { getTranslation } from '../../utils/translations/translate'
7
7
 
@@ -95,6 +95,10 @@ const passwordA11yText = computed(() => {
95
95
  return _inputType.value === TextFieldTypes.password ? 'showPassword' : 'hidePassword'
96
96
  })
97
97
 
98
+ const onCancelSearch = () => {
99
+ model.value = ''
100
+ }
101
+
98
102
  watch(
99
103
  () => type,
100
104
  () => {
@@ -165,16 +169,33 @@ watch(
165
169
  </button>
166
170
  </span>
167
171
 
172
+ <!-- TYPE: DATE -->
173
+ <span v-if="type === TextFieldTypes.date" class="suffix-icon">
174
+ <UIcon name="calendar" />
175
+ </span>
176
+
177
+ <!-- TYPE: SEARCH -->
178
+ <span v-if="type === TextFieldTypes.search" class="prefix-icon">
179
+ <UIcon name="search" />
180
+ </span>
181
+
182
+ <span v-if="type === TextFieldTypes.search" class="suffix-action">
183
+ <button
184
+ type="button"
185
+ :class="['cancel-search', { visible: hasValue && (isHovering || isFocused) }]"
186
+ tabindex="-1"
187
+ @click="onCancelSearch"
188
+ >
189
+ <span class="visually-hidden">{{ getTranslation('cancelSearch') }}</span>
190
+ <UIcon name="close-circle-filled"></UIcon>
191
+ </button>
192
+ </span>
193
+
168
194
  <!-- UNIT -->
169
195
  <span v-if="unit" class="suffix-text">
170
196
  {{ unit }}
171
197
  </span>
172
198
 
173
- <!-- DATE -->
174
- <span v-if="type === TextFieldTypes.date" class="suffix-icon">
175
- <UIcon name="calendar"></UIcon>
176
- </span>
177
-
178
199
  <!-- ACTION -->
179
200
  <span v-if="!!slots.action" class="suffix-action custom-action">
180
201
  <slot name="action"></slot>
@@ -11,6 +11,10 @@
11
11
  align-items: center;
12
12
  width: 100%;
13
13
  gap: var(--e-space-4);
14
+
15
+ input {
16
+ width: var(--width);
17
+ }
14
18
  }
15
19
 
16
20
  .toggle-switch__handle {
@@ -37,4 +41,10 @@
37
41
  margin-right: auto;
38
42
  }
39
43
  }
44
+
45
+ .toggle-switch__additional-label {
46
+ display: inline;
47
+
48
+ @include a.type(200);
49
+ }
40
50
  }