@weni/unnnic-system 3.9.1 → 3.9.3-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 (257) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/assets/tokens/colors.json.d.ts +376 -0
  3. package/dist/components/Accordion/Accordion.vue.d.ts +1 -1
  4. package/dist/components/Alert/Alert.vue.d.ts +17 -116
  5. package/dist/components/Alert/Alert.vue.d.ts.map +1 -1
  6. package/dist/components/Alert/Version1dot1.vue.d.ts +2 -38
  7. package/dist/components/Alert/Version1dot1.vue.d.ts.map +1 -1
  8. package/dist/components/AudioRecorder/AudioHandler.vue.d.ts +2 -2
  9. package/dist/components/AudioRecorder/AudioPlayer.vue.d.ts +1 -1
  10. package/dist/components/AudioRecorder/AudioRecorder.vue.d.ts +5 -5
  11. package/dist/components/AvatarIcon/AvatarIcon.vue.d.ts +3 -3
  12. package/dist/components/Banner/Banner.vue.d.ts +1 -1
  13. package/dist/components/Banner/InfoBanner.vue.d.ts +1 -1
  14. package/dist/components/Breadcrumb/Breadcrumb.vue.d.ts +1 -1
  15. package/dist/components/Button/Button.vue.d.ts +1 -1
  16. package/dist/components/Button/Button.vue.d.ts.map +1 -1
  17. package/dist/components/Button/ButtonIcon.vue.d.ts +1 -1
  18. package/dist/components/Button/types.d.ts +1 -1
  19. package/dist/components/Button/types.d.ts.map +1 -1
  20. package/dist/components/Card/AccountCard.vue.d.ts +5 -5
  21. package/dist/components/Card/BlankCard.vue.d.ts +1 -1
  22. package/dist/components/Card/Card.vue.d.ts +27 -27
  23. package/dist/components/Card/CardCompany.vue.d.ts +11 -414
  24. package/dist/components/Card/CardData.vue.d.ts +1 -1
  25. package/dist/components/Card/CardStatusesContainer.vue.d.ts +5 -5
  26. package/dist/components/Card/ContentCard.vue.d.ts +3 -3
  27. package/dist/components/Card/DashCard.vue.d.ts +5 -5
  28. package/dist/components/Card/DefaultCard.vue.d.ts +1 -1
  29. package/dist/components/Card/MarketplaceCard.vue.d.ts +2 -2
  30. package/dist/components/Card/SimpleCard.vue.d.ts +3 -3
  31. package/dist/components/Card/StatusCard.vue.d.ts +2 -2
  32. package/dist/components/Card/TitleCard.vue.d.ts +3 -3
  33. package/dist/components/CardImage/CardImage.vue.d.ts +24 -31
  34. package/dist/components/CardInformation/CardInformation.vue.d.ts +5 -5
  35. package/dist/components/CardProject/CardProject.vue.d.ts +3 -3
  36. package/dist/components/Carousel/Carousel.vue.d.ts +13 -416
  37. package/dist/components/Carousel/TagCarousel.vue.d.ts +12 -415
  38. package/dist/components/ChartBar/ChartBar.vue.d.ts +5 -5
  39. package/dist/components/ChartLine/ChartLine.vue.d.ts +1 -1
  40. package/dist/components/ChatText/ChatText.vue.d.ts +2 -2
  41. package/dist/components/ChatsContact/ChatsContact.vue.d.ts +30 -448
  42. package/dist/components/ChatsDashboardTagLive/ChatsDashboardTagLive.vue.d.ts +1 -1
  43. package/dist/components/ChatsHeader/ChatsHeader.vue.d.ts +1 -1
  44. package/dist/components/ChatsHeader/ChatsHeader.vue.d.ts.map +1 -1
  45. package/dist/components/ChatsMessage/ChatsMessage.vue.d.ts +5 -5
  46. package/dist/components/ChatsMessage/ChatsMessageStatusBackdrop.vue.d.ts +2 -2
  47. package/dist/components/ChatsNavbar/ChatsNavbar.vue.d.ts +1 -1
  48. package/dist/components/ChatsUserAvatar/ChatsUserAvatar.vue.d.ts +2 -2
  49. package/dist/components/Checkbox/Checkbox.vue.d.ts +19 -26
  50. package/dist/components/Checkbox/Checkbox.vue.d.ts.map +1 -1
  51. package/dist/components/CheckboxGroup/CheckboxGroup.vue.d.ts +28 -0
  52. package/dist/components/CheckboxGroup/CheckboxGroup.vue.d.ts.map +1 -0
  53. package/dist/components/Comment/Comment.vue.d.ts +1 -1
  54. package/dist/components/DataArea/DataArea.vue.d.ts +2 -2
  55. package/dist/components/DataTable/index.vue.d.ts +12 -2
  56. package/dist/components/DataTable/index.vue.d.ts.map +1 -1
  57. package/dist/components/DateFilter/DateFilter.vue.d.ts +251 -41
  58. package/dist/components/DatePicker/DatePicker.vue.d.ts +4 -4
  59. package/dist/components/Drawer/Drawer.vue.d.ts +4 -4
  60. package/dist/components/Dropdown/Dropdown.vue.d.ts +1 -1
  61. package/dist/components/Dropdown/LanguageSelect.vue.d.ts +3 -3
  62. package/dist/components/Flag.vue.d.ts +2 -2
  63. package/dist/components/FormElement/FormElement.vue.d.ts +51 -28
  64. package/dist/components/FormElement/FormElement.vue.d.ts.map +1 -1
  65. package/dist/components/Icon.vue.d.ts +1 -1
  66. package/dist/components/Icon.vue.d.ts.map +1 -1
  67. package/dist/components/IconLoading/IconLoading.vue.d.ts +1 -1
  68. package/dist/components/ImportCard/ImportCard.vue.d.ts +4 -4
  69. package/dist/components/Input/BaseInput.vue.d.ts +33 -2
  70. package/dist/components/Input/BaseInput.vue.d.ts.map +1 -1
  71. package/dist/components/Input/Input.vue.d.ts +251 -41
  72. package/dist/components/Input/Input.vue.d.ts.map +1 -1
  73. package/dist/components/Input/TextInput.vue.d.ts +85 -25
  74. package/dist/components/Input/TextInput.vue.d.ts.map +1 -1
  75. package/dist/components/InputDatePicker/InputDatePicker.vue.d.ts +256 -46
  76. package/dist/components/InputNext/InputNext.vue.d.ts +5 -5
  77. package/dist/components/Label/Label.vue.d.ts +9 -15
  78. package/dist/components/Label/Label.vue.d.ts.map +1 -1
  79. package/dist/components/Modal/Modal.vue.d.ts +2 -2
  80. package/dist/components/ModalDialog/ModalDialog.vue.d.ts +6 -6
  81. package/dist/components/ModalNext/ModalNext.vue.d.ts +256 -46
  82. package/dist/components/ModalUpload/ModalUpload.vue.d.ts +9 -9
  83. package/dist/components/MoodRating/MoodRating.vue.d.ts +1 -1
  84. package/dist/components/MultiSelect/MultiSelect.vue.d.ts +26 -14
  85. package/dist/components/PageHeader/PageHeader.vue.d.ts +28 -0
  86. package/dist/components/PageHeader/PageHeader.vue.d.ts.map +1 -0
  87. package/dist/components/PageHeader/index.d.ts +3 -0
  88. package/dist/components/PageHeader/index.d.ts.map +1 -0
  89. package/dist/components/PageHeader/types.d.ts +9 -0
  90. package/dist/components/PageHeader/types.d.ts.map +1 -0
  91. package/dist/components/Pagination/Pagination.vue.d.ts +3 -3
  92. package/dist/components/ProgressBar/ProgressBar.vue.d.ts +1 -1
  93. package/dist/components/Radio/Radio.vue.d.ts +10 -6
  94. package/dist/components/Radio/Radio.vue.d.ts.map +1 -1
  95. package/dist/components/SelectSmart/SelectSmart.vue.d.ts +120 -470
  96. package/dist/components/SelectSmart/SelectSmartMultipleHeader.vue.d.ts +11 -414
  97. package/dist/components/SelectSmart/SelectSmartOption.vue.d.ts +21 -28
  98. package/dist/components/SelectSmart/SelectSmartOption.vue.d.ts.map +1 -1
  99. package/dist/components/SelectTime/index.vue.d.ts +85 -25
  100. package/dist/components/SkeletonLoading/skeletonTheme.vue.d.ts +1 -1
  101. package/dist/components/Slider/Slider.vue.d.ts +2 -2
  102. package/dist/components/StarRating/StarRating.vue.d.ts +1 -1
  103. package/dist/components/Switch/Switch.vue.d.ts +55 -21
  104. package/dist/components/Switch/Switch.vue.d.ts.map +1 -1
  105. package/dist/components/Tab/Tab.vue.d.ts +13 -2
  106. package/dist/components/TableNext/TableBodyCell.vue.d.ts +2 -2
  107. package/dist/components/TableNext/TablePagination.vue.d.ts +3 -3
  108. package/dist/components/TabsExpanded/TabsExpanded.vue.d.ts +1 -1
  109. package/dist/components/Tag/DefaultTag.vue.d.ts +4 -83
  110. package/dist/components/Tag/DefaultTag.vue.d.ts.map +1 -1
  111. package/dist/components/Tag/Tag.vue.d.ts +12 -414
  112. package/dist/components/Tag/Tag.vue.d.ts.map +1 -1
  113. package/dist/components/Tag/types.d.ts +18 -0
  114. package/dist/components/Tag/types.d.ts.map +1 -0
  115. package/dist/components/TextArea/TextArea.vue.d.ts +78 -33
  116. package/dist/components/TextArea/TextArea.vue.d.ts.map +1 -1
  117. package/dist/components/Toast/Toast.vue.d.ts +16 -0
  118. package/dist/components/Toast/Toast.vue.d.ts.map +1 -0
  119. package/dist/components/Toast/ToastManager.d.ts +14 -0
  120. package/dist/components/Toast/ToastManager.d.ts.map +1 -0
  121. package/dist/components/Toast/types.d.ts +35 -0
  122. package/dist/components/Toast/types.d.ts.map +1 -0
  123. package/dist/components/ToolTip/ToolTip.vue.d.ts +1 -1
  124. package/dist/components/Tour/Tour.vue.d.ts +3 -3
  125. package/dist/components/Tour/TourPopover.vue.d.ts +3 -3
  126. package/dist/components/UploadArea/UploadArea.vue.d.ts +4 -4
  127. package/dist/components/index.d.ts +8736 -10161
  128. package/dist/components/index.d.ts.map +1 -1
  129. package/dist/components/ui/popover/PopoverContent.vue.d.ts +1 -1
  130. package/dist/components/ui/popover/PopoverContent.vue.d.ts.map +1 -1
  131. package/dist/{es-efb4f902.mjs → es-61b41785.mjs} +1 -1
  132. package/dist/{index-e30fc518.mjs → index-10160248.mjs} +9383 -8807
  133. package/dist/locales/en.json.d.ts +2 -1
  134. package/dist/locales/es.json.d.ts +2 -1
  135. package/dist/locales/pt_br.json.d.ts +2 -1
  136. package/dist/{pt-br-4bacdbb6.mjs → pt-br-31a68683.mjs} +1 -1
  137. package/dist/style.css +1 -1
  138. package/dist/unnnic.mjs +158 -151
  139. package/dist/unnnic.umd.js +34 -35
  140. package/dist/utils/call.d.ts +2 -1
  141. package/dist/utils/call.d.ts.map +1 -1
  142. package/package.json +2 -2
  143. package/src/assets/icons/checkbox-checked-disabled.svg +3 -0
  144. package/src/assets/icons/checkbox-checked.svg +3 -0
  145. package/src/assets/icons/checkbox-less-disabled.svg +3 -0
  146. package/src/assets/icons/checkbox-less.svg +3 -0
  147. package/src/assets/icons/radio-checked.svg +3 -0
  148. package/src/assets/icons/switch-checked-disabled.svg +3 -0
  149. package/src/assets/icons/switch-checked.svg +3 -0
  150. package/src/assets/scss/scheme-colors.scss +309 -223
  151. package/src/components/Alert/Alert.vue +26 -135
  152. package/src/components/Alert/Version1dot1.vue +0 -36
  153. package/src/components/Alert/__tests__/Alert.spec.js +2 -45
  154. package/src/components/Alert/__tests__/Version1dot1.spec.js +0 -21
  155. package/src/components/Alert/__tests__/__snapshots__/Alert.spec.js.snap +11 -7
  156. package/src/components/Alert/__tests__/__snapshots__/AlertBanner.spec.js.snap +2 -2
  157. package/src/components/Alert/__tests__/__snapshots__/Version1dot1.spec.js.snap +1 -1
  158. package/src/components/Button/Button.vue +67 -117
  159. package/src/components/Button/types.ts +0 -1
  160. package/src/components/ChatsContact/ChatsContact.vue +16 -8
  161. package/src/components/Checkbox/Checkbox.vue +117 -65
  162. package/src/components/Checkbox/__tests__/Checkbox.spec.js +6 -21
  163. package/src/components/CheckboxGroup/CheckboxGroup.vue +96 -0
  164. package/src/components/DataTable/index.vue +48 -0
  165. package/src/components/FormElement/FormElement.vue +63 -93
  166. package/src/components/Icon.vue +2 -0
  167. package/src/components/Input/BaseInput.vue +33 -14
  168. package/src/components/Input/Input.scss +22 -22
  169. package/src/components/Input/Input.vue +79 -56
  170. package/src/components/Input/TextInput.vue +81 -65
  171. package/src/components/Input/__test__/Input.spec.js +13 -33
  172. package/src/components/Input/__test__/TextInput.spec.js +6 -8
  173. package/src/components/Input/__test__/__snapshots__/Input.spec.js.snap +17 -4
  174. package/src/components/Input/__test__/__snapshots__/TextInput.spec.js.snap +7 -1
  175. package/src/components/Label/Label.vue +52 -21
  176. package/src/components/Label/__tests__/Label.spec.js +1 -1
  177. package/src/components/Label/__tests__/__snapshots__/Label.spec.js.snap +1 -1
  178. package/src/components/MultiSelectV2/MultSelectOption.vue +67 -0
  179. package/src/components/MultiSelectV2/__tests__/MultiSelect.spec.js +556 -0
  180. package/src/components/MultiSelectV2/__tests__/MultiSelectOption.spec.js +229 -0
  181. package/src/components/MultiSelectV2/__tests__/__snapshots__/MultiSelect.spec.js.snap +121 -0
  182. package/src/components/MultiSelectV2/__tests__/__snapshots__/MultiSelectOption.spec.js.snap +51 -0
  183. package/src/components/MultiSelectV2/index.vue +221 -0
  184. package/src/components/PageHeader/PageHeader.vue +148 -0
  185. package/src/components/PageHeader/index.ts +2 -0
  186. package/src/components/PageHeader/types.ts +10 -0
  187. package/src/components/Popover/__tests__/Popover.spec.js +147 -0
  188. package/src/components/Popover/__tests__/__snapshots__/Popover.spec.js.snap +8 -0
  189. package/src/components/Popover/index.vue +146 -0
  190. package/src/components/Radio/Radio.vue +118 -66
  191. package/src/components/Radio/__test__/Radio.spec.js +14 -20
  192. package/src/components/Radio/__test__/__snapshots__/Radio.spec.js.snap +4 -3
  193. package/src/components/RadioGroup/RadioGroup.vue +142 -0
  194. package/src/components/Select/SelectOption.vue +65 -0
  195. package/src/components/Select/__tests__/Select.spec.js +412 -0
  196. package/src/components/Select/__tests__/SelectItem.spec.js +330 -0
  197. package/src/components/Select/__tests__/SelectOption.spec.js +174 -0
  198. package/src/components/Select/__tests__/__snapshots__/Select.spec.js.snap +97 -0
  199. package/src/components/Select/__tests__/__snapshots__/SelectItem.spec.js.snap +15 -0
  200. package/src/components/Select/__tests__/__snapshots__/SelectOption.spec.js.snap +25 -0
  201. package/src/components/Select/index.vue +249 -0
  202. package/src/components/SelectSmart/SelectSmart.vue +4 -3
  203. package/src/components/Switch/Switch.vue +132 -91
  204. package/src/components/Switch/__tests__/Switch.spec.js +8 -75
  205. package/src/components/Switch/__tests__/__snapshots__/Switch.spec.js.snap +5 -6
  206. package/src/components/Tab/Tab.vue +37 -23
  207. package/src/components/Tab/__test__/__snapshots__/Tab.spec.js.snap +1 -1
  208. package/src/components/TableNext/__test__/__snapshots__/TableNext.spec.js.snap +2 -2
  209. package/src/components/TableNext/__test__/__snapshots__/TablePagination.spec.js.snap +2 -2
  210. package/src/components/Tag/DefaultTag.vue +51 -107
  211. package/src/components/Tag/Tag.vue +32 -79
  212. package/src/components/Tag/types.ts +19 -0
  213. package/src/components/TextArea/TextArea.vue +41 -12
  214. package/src/components/TextArea/__test__/__snapshots__/TextArea.spec.js.snap +11 -3
  215. package/src/components/Toast/Toast.vue +246 -0
  216. package/src/components/Toast/ToastManager.ts +110 -0
  217. package/src/components/Toast/__tests__/Toast.spec.js +291 -0
  218. package/src/components/Toast/__tests__/ToastManager.spec.js +294 -0
  219. package/src/components/Toast/types.ts +57 -0
  220. package/src/components/index.ts +33 -18
  221. package/src/locales/en.json +2 -1
  222. package/src/locales/es.json +2 -1
  223. package/src/locales/pt_br.json +2 -1
  224. package/src/stories/Alert.stories.js +6 -67
  225. package/src/stories/Button.stories.js +29 -39
  226. package/src/stories/ChatsContact.stories.js +9 -0
  227. package/src/stories/Checkbox.stories.js +11 -4
  228. package/src/stories/CheckboxGroup.stories.js +105 -0
  229. package/src/stories/DataTable.stories.js +192 -0
  230. package/src/stories/Input.stories.js +71 -76
  231. package/src/stories/Label.stories.js +7 -0
  232. package/src/stories/MultiSelectV2.stories.js +158 -0
  233. package/src/stories/PageHeader.stories.js +330 -0
  234. package/src/stories/Radio.stories.js +28 -1
  235. package/src/stories/RadioGroup.stories.js +144 -0
  236. package/src/stories/Select.stories.js +158 -0
  237. package/src/stories/Switch.stories.js +10 -5
  238. package/src/stories/Tab.stories.js +11 -4
  239. package/src/stories/Tag.stories.js +24 -43
  240. package/src/stories/TextArea.stories.js +14 -2
  241. package/src/stories/Toast.mdx +123 -0
  242. package/src/stories/Toast.stories.js +126 -0
  243. package/src/types/scheme-colors.d.ts +1 -0
  244. package/src/utils/call.js +46 -18
  245. package/dist/components/Tag/BrandTag.vue.d.ts +0 -51
  246. package/dist/components/Tag/BrandTag.vue.d.ts.map +0 -1
  247. package/dist/components/Tag/IndicatorTag.vue.d.ts +0 -151
  248. package/dist/components/Tag/IndicatorTag.vue.d.ts.map +0 -1
  249. package/dist/components/Tag/TagNext.vue.d.ts +0 -24
  250. package/dist/components/Tag/TagNext.vue.d.ts.map +0 -1
  251. package/src/components/Alert/AlertBanner.vue +0 -182
  252. package/src/components/Alert/AlertCaller.vue +0 -49
  253. package/src/components/Alert/__tests__/AlertBanner.spec.js +0 -89
  254. package/src/components/Alert/__tests__/AlertCaller.spec.js +0 -98
  255. package/src/components/Tag/BrandTag.vue +0 -96
  256. package/src/components/Tag/IndicatorTag.vue +0 -107
  257. package/src/components/Tag/TagNext.vue +0 -60
@@ -0,0 +1,249 @@
1
+ <template>
2
+ <div
3
+ class="unnnic-select"
4
+ @keydown="handleKeyDown"
5
+ >
6
+ <UnnnicPopover
7
+ v-model="openPopover"
8
+ :popoverBalloonProps="{ maxHeight: calculatedMaxHeight }"
9
+ >
10
+ <template #trigger>
11
+ <UnnnicInput
12
+ :modelValue="inputValue"
13
+ class="unnnic-select__input"
14
+ readonly
15
+ :forceActiveStatus="openPopover"
16
+ :size="props.size"
17
+ :placeholder="props.placeholder"
18
+ :label="props.label"
19
+ :errors="props.errors"
20
+ :message="props.message"
21
+ :iconRight="openPopover ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
22
+ :disabled="props.disabled"
23
+ showClear
24
+ @clear="emit('update:modelValue', '')"
25
+ />
26
+ </template>
27
+ <template #content>
28
+ <div class="unnnic-select__content">
29
+ <UnnnicInput
30
+ v-if="props.enableSearch"
31
+ class="unnnic-select__input-search"
32
+ :modelValue="props.search"
33
+ :placeholder="$t('search')"
34
+ iconLeft="search"
35
+ @update:model-value="handleSearch"
36
+ />
37
+ <UnnnicSelectOption
38
+ v-for="(option, index) in filteredOptions"
39
+ :key="option[props.itemValue]"
40
+ :data-option-index="index"
41
+ :label="option[props.itemLabel]"
42
+ :active="
43
+ option[props.itemValue] === selectedItem?.[props.itemValue]
44
+ "
45
+ :focused="focusedOptionIndex === index"
46
+ :disabled="option.disabled"
47
+ @click="handleSelectOption(option)"
48
+ />
49
+ </div>
50
+ </template>
51
+ </UnnnicPopover>
52
+ </div>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ import { computed, ref, watch, nextTick } from 'vue';
57
+ import UnnnicInput from '../Input/Input.vue';
58
+ import UnnnicPopover from '../Popover/index.vue';
59
+ import UnnnicSelectOption from './SelectOption.vue';
60
+ import UnnnicI18n from '../../mixins/i18n';
61
+
62
+ defineOptions({
63
+ name: 'UnnnicSelect',
64
+ mixins: [UnnnicI18n],
65
+ });
66
+
67
+ interface SelectProps {
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ options: Array<{ [key: string]: any }>;
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ modelValue: any;
72
+ returnObject?: boolean;
73
+ itemLabel?: string;
74
+ itemValue?: string;
75
+ placeholder?: string;
76
+ label?: string;
77
+ type?: 'normal' | 'error';
78
+ errors?: string | Array<string>;
79
+ message?: string;
80
+ size?: 'sm' | 'md';
81
+ optionsLines?: number;
82
+ enableSearch?: boolean;
83
+ search?: string;
84
+ locale?: string;
85
+ disabled?: boolean;
86
+ }
87
+
88
+ const props = withDefaults(defineProps<SelectProps>(), {
89
+ size: 'md',
90
+ type: 'normal',
91
+ placeholder: '',
92
+ optionsLines: 5,
93
+ returnObject: false,
94
+ itemLabel: 'label',
95
+ itemValue: 'value',
96
+ locale: 'en',
97
+ enableSearch: false,
98
+ disabled: false,
99
+ label: '',
100
+ errors: '',
101
+ message: '',
102
+ search: '',
103
+ });
104
+
105
+ const emit = defineEmits<{
106
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
107
+ 'update:modelValue': [value: any];
108
+ 'update:search': [value: string];
109
+ }>();
110
+
111
+ const openPopover = ref(false);
112
+
113
+ watch(openPopover, () => {
114
+ if (!openPopover.value) {
115
+ handleSearch('');
116
+ } else {
117
+ focusedOptionIndex.value = -1;
118
+ }
119
+
120
+ if (openPopover.value && props.modelValue) {
121
+ const selectedOptionIndex = props.options.findIndex(
122
+ (option) =>
123
+ option[props.itemValue] === selectedItem.value?.[props.itemValue],
124
+ );
125
+ scrollToOption(selectedOptionIndex, 'instant', 'center');
126
+ }
127
+ });
128
+
129
+ const handleKeyDown = (event) => {
130
+ const { key } = event;
131
+ const validKeys = ['ArrowUp', 'ArrowDown', 'Enter'];
132
+ if (validKeys.includes(key)) {
133
+ event.preventDefault();
134
+ if (key === 'ArrowUp') {
135
+ if (focusedOptionIndex.value === 0) return;
136
+ focusedOptionIndex.value--;
137
+ scrollToOption(focusedOptionIndex.value);
138
+ }
139
+ if (key === 'ArrowDown') {
140
+ if (focusedOptionIndex.value === filteredOptions.value.length - 1) return;
141
+ focusedOptionIndex.value++;
142
+ scrollToOption(focusedOptionIndex.value);
143
+ }
144
+ if (key === 'Enter') {
145
+ handleSelectOption(filteredOptions.value[focusedOptionIndex.value]);
146
+ }
147
+ }
148
+ };
149
+
150
+ const focusedOptionIndex = ref<number>(-1);
151
+
152
+ const scrollToOption = (
153
+ index: number,
154
+ behavior: 'smooth' | 'instant' = 'smooth',
155
+ block: 'center' | 'start' | 'end' | 'nearest' = 'center',
156
+ ) => {
157
+ nextTick(() => {
158
+ const option = document.querySelector(`[data-option-index="${index}"]`);
159
+ if (option) {
160
+ option.scrollIntoView({ behavior, block });
161
+ }
162
+ });
163
+ };
164
+
165
+ const calculatedMaxHeight = computed(() => {
166
+ if (!props.options || props.options.length === 0) return 'unset';
167
+ const popoverPadding = 32;
168
+ const popoverGap = 4;
169
+ // 37 = 21px (height) + 16px (padding)
170
+ const fieldsHeight = 37 * props.optionsLines;
171
+ const size =
172
+ fieldsHeight + popoverPadding + (popoverGap * props.optionsLines - 2);
173
+ return `${props.enableSearch ? size + 54 : size}px`;
174
+ });
175
+
176
+ const selectedItem = computed(() => {
177
+ if (props.returnObject) return props.modelValue;
178
+
179
+ return props.options.find(
180
+ (option) => option[props.itemValue] === props.modelValue,
181
+ );
182
+ });
183
+
184
+ const inputValue = computed(() => {
185
+ return selectedItem.value?.[props.itemLabel];
186
+ });
187
+
188
+ const handleSelectOption = (option) => {
189
+ if (
190
+ option[props.itemValue] === selectedItem.value?.[props.itemValue] ||
191
+ option.disabled
192
+ )
193
+ return;
194
+
195
+ emit(
196
+ 'update:modelValue',
197
+ props.returnObject ? option : option[props.itemValue],
198
+ );
199
+ openPopover.value = false;
200
+ };
201
+
202
+ const handleSearch = (value: string) => {
203
+ emit('update:search', value);
204
+ };
205
+
206
+ const filteredOptions = computed(() => {
207
+ if (!props.enableSearch || !props.search) return props.options;
208
+
209
+ return props.options.filter(
210
+ (option) =>
211
+ option[props.itemLabel]
212
+ .toLowerCase()
213
+ .includes(props.search?.toLowerCase()) ||
214
+ option[props.itemValue]
215
+ .toLowerCase()
216
+ .includes(props.search?.toLowerCase()),
217
+ );
218
+ });
219
+ </script>
220
+
221
+ <style lang="scss" scoped>
222
+ @use '@/assets/scss/unnnic' as *;
223
+
224
+ :deep(.unnnic-select__input) {
225
+ cursor: pointer;
226
+ }
227
+
228
+ :deep(.unnnic-select__input-search) {
229
+ > .icon-left {
230
+ color: $unnnic-color-fg-base;
231
+ }
232
+ }
233
+
234
+ :deep(.unnnic-select__input) {
235
+ > .icon-right {
236
+ color: $unnnic-color-fg-base;
237
+ }
238
+ }
239
+
240
+ .unnnic-select {
241
+ &__content {
242
+ display: flex;
243
+ flex-direction: column;
244
+ padding: 0;
245
+ margin: 0;
246
+ gap: $unnnic-space-1;
247
+ }
248
+ }
249
+ </style>
@@ -730,9 +730,10 @@ export default {
730
730
 
731
731
  margin-top: $unnnic-spacing-nano;
732
732
 
733
- border-radius: $unnnic-border-radius-sm;
733
+ border-radius: $unnnic-radius-2;
734
+ border: 1px solid $unnnic-color-border-base;
734
735
 
735
- box-shadow: $unnnic-shadow-level-near;
736
+ box-shadow: $unnnic-shadow-1;
736
737
 
737
738
  background-color: $unnnic-color-background-snow;
738
739
 
@@ -757,7 +758,7 @@ export default {
757
758
 
758
759
  display: grid;
759
760
 
760
- margin: $unnnic-spacing-xs;
761
+ margin: $unnnic-space-4;
761
762
  margin-right: $unnnic-inline-xs;
762
763
  padding-right: $unnnic-inline-xs;
763
764
 
@@ -1,49 +1,60 @@
1
1
  <template>
2
- <div class="unnnic-switch">
3
- <div
4
- v-if="textLeft"
5
- data-test-id="switch-text-left"
6
- :class="[
7
- 'unnnic-switch__label',
8
- 'unnnic-switch__label__left',
9
- `unnnic-switch__label__${size}`,
10
- ]"
11
- >
12
- {{ textLeft }}
13
- </div>
14
-
15
- <UnnnicIcon
16
- :class="{ 'unnnic-switch__icon': true, active: isActive }"
17
- :icon="currentIcon"
18
- :size="iconSize"
19
- :scheme="iconScheme"
20
- :lineHeight="iconLineHeight"
21
- :disabled="disabled"
22
- :clickable="!disabled"
23
- data-test-id="switch-icon"
24
- @click="toggleState"
2
+ <section class="unnnic-switch">
3
+ <UnnnicLabel
4
+ v-if="label"
5
+ :label="label"
6
+ :tooltip="labelTooltip"
7
+ :useHtmlTooltip="labelUseHtmlTooltip"
8
+ class="unnnic-switch__label"
25
9
  />
26
10
 
27
- <div
28
- v-if="textRight"
29
- data-test-id="switch-text-right"
11
+ <label
30
12
  :class="[
31
- 'unnnic-switch__label',
32
- 'unnnic-switch__label__right',
33
- `unnnic-switch__label__${size}`,
13
+ 'unnnic-switch__input-wrapper',
14
+ { 'unnnic-switch__input-wrapper--disabled': disabled },
34
15
  ]"
35
16
  >
36
- {{ textRight }}
37
- </div>
38
- </div>
17
+ <input
18
+ class="unnnic-switch__input"
19
+ type="checkbox"
20
+ :disabled="disabled"
21
+ :checked="modelValue"
22
+ @change="toggleState"
23
+ v-bind="pick($attrs, ['id', 'name'])"
24
+ />
25
+
26
+ <p
27
+ v-if="option || textLeft || textRight"
28
+ :class="[
29
+ 'unnnic-switch__option',
30
+ { 'unnnic-switch__option--disabled': disabled },
31
+ ]"
32
+ data-testid="switch-option"
33
+ >
34
+ {{ option }}
35
+ {{ textLeft }}
36
+ {{ textRight }}
37
+ </p>
38
+ </label>
39
+
40
+ <p
41
+ v-if="helper"
42
+ class="unnnic-switch__helper"
43
+ >
44
+ {{ helper }}
45
+ </p>
46
+ </section>
39
47
  </template>
40
48
 
41
49
  <script>
42
- import UnnnicIcon from '../Icon.vue';
50
+ import { pick } from 'lodash';
51
+ import UnnnicLabel from '../Label/Label.vue';
43
52
 
44
53
  export default {
45
54
  name: 'UnnnicSwitch',
46
- components: { UnnnicIcon },
55
+ components: {
56
+ UnnnicLabel,
57
+ },
47
58
  props: {
48
59
  size: {
49
60
  type: String,
@@ -52,6 +63,32 @@ export default {
52
63
  return ['small', 'medium'].indexOf(value) !== -1;
53
64
  },
54
65
  },
66
+
67
+ label: {
68
+ type: String,
69
+ default: '',
70
+ },
71
+
72
+ labelTooltip: {
73
+ type: String,
74
+ default: '',
75
+ },
76
+
77
+ labelUseHtmlTooltip: {
78
+ type: Boolean,
79
+ default: false,
80
+ },
81
+
82
+ option: {
83
+ type: String,
84
+ default: '',
85
+ },
86
+
87
+ helper: {
88
+ type: String,
89
+ default: '',
90
+ },
91
+
55
92
  textLeft: {
56
93
  type: String,
57
94
  default: '',
@@ -78,33 +115,6 @@ export default {
78
115
  isActive: false,
79
116
  };
80
117
  },
81
- computed: {
82
- currentIcon() {
83
- if (this.disabled) {
84
- return this.isActive
85
- ? 'switch-selected-disabled'
86
- : 'switch-default-disabled';
87
- }
88
-
89
- return 'switch-default';
90
- },
91
-
92
- iconSize() {
93
- return this.size === 'small' ? 'sm' : 'md';
94
- },
95
-
96
- iconScheme() {
97
- if (this.disabled) {
98
- return 'neutral-soft';
99
- }
100
-
101
- return this.isActive === false ? 'neutral-soft' : 'brand-weni';
102
- },
103
-
104
- iconLineHeight() {
105
- return this.size === 'small' ? 'sm' : '';
106
- },
107
- },
108
118
 
109
119
  watch: {
110
120
  modelValue: {
@@ -116,6 +126,8 @@ export default {
116
126
  },
117
127
 
118
128
  methods: {
129
+ pick,
130
+
119
131
  toggleState() {
120
132
  if (!this.disabled) {
121
133
  if (this.useVModel) {
@@ -133,51 +145,80 @@ export default {
133
145
  <style lang="scss" scoped>
134
146
  @use '@/assets/scss/unnnic' as *;
135
147
 
148
+ $switch-width: 38px;
149
+ $switch-height: 20px;
150
+
136
151
  .unnnic-switch {
137
152
  display: flex;
138
- flex-direction: row;
153
+ flex-direction: column;
139
154
 
140
- &__label {
141
- font-family: $unnnic-font-family-secondary;
142
- font-weight: $unnnic-font-weight-regular;
143
- color: $unnnic-color-neutral-dark;
155
+ &__input-wrapper {
156
+ width: fit-content;
144
157
 
145
- margin: $unnnic-spacing-stack-nano 0;
146
- margin-right: $unnnic-inline-nano;
158
+ display: flex;
159
+ align-items: center;
160
+ column-gap: $unnnic-space-2;
147
161
 
148
- &__small {
149
- font-size: $unnnic-font-size-body-md;
150
- line-height: $unnnic-font-size-body-md + $unnnic-line-height-md;
151
- }
162
+ cursor: pointer;
152
163
 
153
- &__medium {
154
- font-size: $unnnic-font-size-body-gt;
155
- line-height: $unnnic-font-size-body-gt + $unnnic-line-height-md;
164
+ &--disabled {
165
+ cursor: not-allowed;
156
166
  }
157
167
  }
158
168
 
159
- &__icon {
160
- align-self: center;
161
- margin: $unnnic-spacing-stack-nano $unnnic-inline-nano;
162
-
163
- :deep(#default-circle) {
164
- transition: 0.2s linear transform;
169
+ &__input {
170
+ appearance: none;
171
+ width: $switch-width;
172
+ min-width: $switch-width;
173
+ height: $switch-height;
174
+ margin: 0;
175
+ background-color: $unnnic-color-bg-muted;
176
+ border-radius: $unnnic-radius-3;
177
+ box-sizing: border-box;
178
+ outline: none;
179
+
180
+ background-image: url('@/assets/icons/switch-checked.svg');
181
+ background-repeat: no-repeat;
182
+ background-position: 4px center;
183
+
184
+ transition:
185
+ 120ms linear background-position,
186
+ 120ms linear background-color;
187
+
188
+ cursor: pointer;
189
+
190
+ &:checked {
191
+ background-color: $unnnic-color-bg-active;
192
+ background-position: 20px center;
165
193
  }
166
194
 
167
- &.active {
168
- :deep(#default-circle) {
169
- transform: translateX(45%);
170
- }
195
+ &:disabled {
196
+ background-color: $unnnic-color-bg-muted;
197
+ background-image: url('@/assets/icons/switch-checked-disabled.svg');
198
+
199
+ cursor: not-allowed;
171
200
  }
172
201
  }
173
- }
174
202
 
175
- .unnnic-icon__size {
176
- &--md {
177
- width: 3 * $unnnic-font-size;
203
+ &__label {
204
+ margin-bottom: $unnnic-space-3;
205
+ }
206
+
207
+ &__option {
208
+ margin: 0;
209
+ font: $unnnic-font-body;
210
+ color: $unnnic-color-fg-emphasized;
211
+
212
+ &--disabled {
213
+ color: $unnnic-color-fg-muted;
214
+ }
178
215
  }
179
- &--sm {
180
- width: 2 * $unnnic-font-size;
216
+
217
+ &__helper {
218
+ margin: 0;
219
+ margin-left: $switch-width + $unnnic-space-2;
220
+ font: $unnnic-font-caption-2;
221
+ color: $unnnic-color-fg-base;
181
222
  }
182
223
  }
183
224
  </style>
@@ -12,93 +12,26 @@ describe('Switch', () => {
12
12
  beforeEach(() => {
13
13
  wrapper = createWrapper({ modelValue: false });
14
14
  });
15
- it('should render the component correctly with default props', () => {
16
- expect(wrapper.exists()).toBe(true);
17
- expect(wrapper.findComponent({ name: 'UnnnicIcon' }).exists()).toBe(true);
18
- expect(wrapper.text()).toBe('');
19
- });
20
-
21
- it('should render the left text (textLeft) when provided', async () => {
22
- await wrapper.setProps({ textLeft: 'Left Text' });
23
-
24
- // This check ensures that the icon is placed before the switch text
25
- const switchChildren = wrapper.findComponent(Switch).element.children;
26
- expect(switchChildren[0].getAttribute('data-test-id')).toBe(
27
- 'switch-text-left',
28
- );
29
- expect(switchChildren[1].getAttribute('data-test-id')).toBe('switch-icon');
30
- });
31
-
32
- it('should render the right text (textRight) when provided', async () => {
33
- await wrapper.setProps({ textRight: 'Right Text' });
34
-
35
- // This check ensures that the icon is placed after the switch text
36
- const switchChildren = wrapper.findComponent(Switch).element.children;
37
- expect(switchChildren[0].getAttribute('data-test-id')).toBe('switch-icon');
38
- expect(switchChildren[1].getAttribute('data-test-id')).toBe(
39
- 'switch-text-right',
40
- );
41
- });
42
-
43
- it('should render the correct icon when the switch is disabled/enabled', async () => {
44
- await wrapper.setProps({ disabled: true });
45
- const disabledIconComponent = wrapper.findComponent({ name: 'UnnnicIcon' });
46
- expect(disabledIconComponent.props('icon')).toBe('switch-default-disabled');
47
15
 
48
- await wrapper.setProps({ modelValue: true });
49
- const enabledIconComponent = wrapper.findComponent({ name: 'UnnnicIcon' });
50
- expect(enabledIconComponent.props('icon')).toBe('switch-selected-disabled');
51
- });
16
+ it('should render the option when provided', async () => {
17
+ await wrapper.setProps({ option: 'Option Text' });
52
18
 
53
- it('should render the correct icon based on the isActive state', async () => {
54
- expect(wrapper.vm.isActive).toBe(false);
55
- await wrapper.setProps({ modelValue: true });
56
- expect(wrapper.vm.isActive).toBe(true);
57
- expect(wrapper.findComponent({ name: 'UnnnicIcon' }).props('icon')).toBe(
58
- 'switch-default',
59
- );
60
- });
61
-
62
- it('should render the correct icon size based on the size prop', async () => {
63
- await wrapper.setProps({ size: 'small' });
64
- expect(wrapper.findComponent({ name: 'UnnnicIcon' }).props('size')).toBe(
65
- 'sm',
66
- );
67
-
68
- await wrapper.setProps({ size: 'medium' });
69
- expect(wrapper.findComponent({ name: 'UnnnicIcon' }).props('size')).toBe(
70
- 'md',
71
- );
72
- });
73
-
74
- it('should change the icon color based on the state', async () => {
75
- expect(wrapper.findComponent({ name: 'UnnnicIcon' }).props('scheme')).toBe(
76
- 'neutral-soft',
77
- );
78
-
79
- await wrapper.setProps({ modelValue: true });
80
- expect(wrapper.findComponent({ name: 'UnnnicIcon' }).props('scheme')).toBe(
81
- 'brand-weni',
82
- );
83
-
84
- await wrapper.setProps({ disabled: true });
85
- expect(wrapper.findComponent({ name: 'UnnnicIcon' }).props('scheme')).toBe(
86
- 'neutral-soft',
87
- );
19
+ const switchOption = wrapper.find('[data-testid="switch-option"]');
20
+ expect(switchOption.text()).toBe('Option Text');
88
21
  });
89
22
 
90
23
  it('should toggle isActive state and emit the correct event when toggleState is called', async () => {
91
24
  const initialIsActive = wrapper.vm.isActive;
92
- const switchIcon = wrapper.findComponent('[ data-test-id="switch-icon"]');
93
- await switchIcon.trigger('click');
25
+ const switchInput = wrapper.find('input[type="checkbox"]');
26
+ await switchInput.trigger('change');
94
27
  expect(wrapper.emitted('update:model-value')).toBeTruthy();
95
28
  expect(wrapper.vm.isActive).toBe(!initialIsActive);
96
29
  });
97
30
 
98
31
  it('should not change state when disabled is true', async () => {
99
32
  await wrapper.setProps({ disabled: true });
100
- const switchIcon = wrapper.findComponent('[ data-test-id="switch-icon"]');
101
- await switchIcon.trigger('click');
33
+ const switchInput = wrapper.find('input[type="checkbox"]');
34
+ await switchInput.trigger('change');
102
35
  expect(wrapper.emitted('update:model-value')).toBeFalsy();
103
36
  expect(wrapper.vm.isActive).toBe(false);
104
37
  });
@@ -1,11 +1,10 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`Switch > should match the snapshot 1`] = `
4
- "<div data-v-e4356c9d="" class="unnnic-switch">
5
- <!--v-if--><svg data-v-3d58a7dd="" data-v-26446d8e="" data-v-e4356c9d="" id="default" width="80" height="40" viewBox="0 0 80 40" xmlns="http://www.w3.org/2000/svg" class="unnnic-icon unnnic-icon--size-svg-md unnnic-icon__size--md unnnic--clickable unnnic-icon-scheme--neutral-soft unnnic-switch__icon" data-testid="custom-icon" lineHeight="" disabled="false" data-test-id="switch-icon">
6
- <rect data-v-3d58a7dd="" x="4.20013" y="2.10046" width="71.6" height="35.8" rx="17.9" class="primary"></rect>
7
- <circle data-v-3d58a7dd="" id="default-circle" cx="22.5" cy="20.0005" r="12.5" fill="white"></circle>
8
- </svg>
4
+ "<section data-v-e4356c9d="" class="unnnic-switch">
5
+ <!--v-if--><label data-v-e4356c9d="" class="unnnic-switch__input-wrapper"><input data-v-e4356c9d="" class="unnnic-switch__input" type="checkbox">
6
+ <!--v-if-->
7
+ </label>
9
8
  <!--v-if-->
10
- </div>"
9
+ </section>"
11
10
  `;