@weni/unnnic-system 3.12.2 → 3.12.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 (211) hide show
  1. package/dist/components/Alert/Alert.vue.d.ts +3 -3
  2. package/dist/components/Alert/Version1dot1.vue.d.ts +1 -1
  3. package/dist/components/AudioRecorder/AudioHandler.vue.d.ts +92 -18
  4. package/dist/components/AudioRecorder/AudioRecorder.vue.d.ts +184 -36
  5. package/dist/components/AvatarIcon/AvatarIcon.vue.d.ts +1 -1
  6. package/dist/components/Button/Button.vue.d.ts +2 -2
  7. package/dist/components/Card/AccountCard.vue.d.ts +2 -2
  8. package/dist/components/Card/Card.vue.d.ts +103 -29
  9. package/dist/components/Card/CardCompany.vue.d.ts +2 -2
  10. package/dist/components/Card/CardStatusesContainer.vue.d.ts +93 -19
  11. package/dist/components/Card/ContentCard.vue.d.ts +1 -1
  12. package/dist/components/Card/DashCard.vue.d.ts +2 -2
  13. package/dist/components/Card/DefaultCard.vue.d.ts +1 -1
  14. package/dist/components/Card/MarketplaceCard.vue.d.ts +1 -1
  15. package/dist/components/Card/SimpleCard.vue.d.ts +92 -18
  16. package/dist/components/Card/StatusCard.vue.d.ts +1 -1
  17. package/dist/components/Card/TitleCard.vue.d.ts +92 -18
  18. package/dist/components/CardImage/CardImage.vue.d.ts +5 -5
  19. package/dist/components/CardInformation/CardInformation.vue.d.ts +93 -19
  20. package/dist/components/CardProject/CardProject.vue.d.ts +2 -2
  21. package/dist/components/Carousel/Carousel.vue.d.ts +2 -2
  22. package/dist/components/Carousel/TagCarousel.vue.d.ts +2 -2
  23. package/dist/components/ChartBar/ChartBar.vue.d.ts +98 -24
  24. package/dist/components/ChartLine/ChartLine.vue.d.ts +92 -18
  25. package/dist/components/ChatText/ChatText.vue.d.ts +92 -18
  26. package/dist/components/ChatsContact/ChatsContact.vue.d.ts +6 -6
  27. package/dist/components/ChatsMessage/ChatsMessage.vue.d.ts +92 -18
  28. package/dist/components/ChatsUserAvatar/ChatsUserAvatar.vue.d.ts +1 -1
  29. package/dist/components/Checkbox/Checkbox.vue.d.ts +3 -3
  30. package/dist/components/DataArea/DataArea.vue.d.ts +92 -18
  31. package/dist/components/DataTable/index.vue.d.ts +1 -1
  32. package/dist/components/DataTable/index.vue.d.ts.map +1 -1
  33. package/dist/components/DateFilter/DateFilter.vue.d.ts +94 -15
  34. package/dist/components/Drawer/Drawer.vue.d.ts +37 -207
  35. package/dist/components/Drawer/Drawer.vue.d.ts.map +1 -1
  36. package/dist/components/Dropdown/Dropdown.vue.d.ts +1 -1
  37. package/dist/components/FormElement/FormElement.vue.d.ts +6 -6
  38. package/dist/components/ImportCard/ImportCard.vue.d.ts +6 -6
  39. package/dist/components/Input/BaseInput.vue.d.ts +22 -0
  40. package/dist/components/Input/BaseInput.vue.d.ts.map +1 -1
  41. package/dist/components/Input/Input.vue.d.ts +93 -14
  42. package/dist/components/Input/Input.vue.d.ts.map +1 -1
  43. package/dist/components/Input/TextInput.vue.d.ts +54 -3
  44. package/dist/components/Input/TextInput.vue.d.ts.map +1 -1
  45. package/dist/components/InputNext/InputNext.vue.d.ts +4 -4
  46. package/dist/components/Label/Label.vue.d.ts +1 -1
  47. package/dist/components/Label/Label.vue.d.ts.map +1 -1
  48. package/dist/components/Modal/Modal.vue.d.ts +1 -1
  49. package/dist/components/ModalDialog/ModalDialog.vue.d.ts +209 -35
  50. package/dist/components/ModalDialog/ModalDialog.vue.d.ts.map +1 -1
  51. package/dist/components/ModalNext/ModalNext.vue.d.ts +99 -20
  52. package/dist/components/ModalUpload/ModalUpload.vue.d.ts +12 -12
  53. package/dist/components/MoodRating/MoodRating.vue.d.ts +92 -18
  54. package/dist/components/MultiSelect/MultiSelect.vue.d.ts +18 -18
  55. package/dist/components/Pagination/Pagination.vue.d.ts +6 -6
  56. package/dist/components/Radio/Radio.vue.d.ts +6 -6
  57. package/dist/components/Select/index.vue.d.ts +44 -0
  58. package/dist/components/Select/index.vue.d.ts.map +1 -0
  59. package/dist/components/SelectSmart/SelectSmart.vue.d.ts +63 -12
  60. package/dist/components/SelectSmart/SelectSmartMultipleHeader.vue.d.ts +2 -2
  61. package/dist/components/SelectSmart/SelectSmartOption.vue.d.ts +5 -5
  62. package/dist/components/SelectTime/index.vue.d.ts +55 -4
  63. package/dist/components/Slider/Slider.vue.d.ts +92 -18
  64. package/dist/components/Switch/Switch.vue.d.ts +3 -3
  65. package/dist/components/Tab/Tab.vue.d.ts +92 -18
  66. package/dist/components/TableNext/TableBodyCell.vue.d.ts +2 -2
  67. package/dist/components/TableNext/TablePagination.vue.d.ts +6 -6
  68. package/dist/components/Tag/DefaultTag.vue.d.ts +1 -1
  69. package/dist/components/Tag/Tag.vue.d.ts +2 -2
  70. package/dist/components/TextArea/TextArea.vue.d.ts +8 -8
  71. package/dist/components/Toast/Toast.vue.d.ts +1 -1
  72. package/dist/components/Toast/Toast.vue.d.ts.map +1 -1
  73. package/dist/components/ToolTip/ToolTip.vue.d.ts +92 -18
  74. package/dist/components/ToolTip/ToolTip.vue.d.ts.map +1 -1
  75. package/dist/components/Tour/Tour.vue.d.ts +6 -6
  76. package/dist/components/Tour/TourPopover.vue.d.ts +6 -6
  77. package/dist/components/UploadArea/UploadArea.vue.d.ts +6 -6
  78. package/dist/components/ui/dialog/Dialog.vue.d.ts +23 -0
  79. package/dist/components/ui/dialog/Dialog.vue.d.ts.map +1 -0
  80. package/dist/components/ui/dialog/DialogClose.vue.d.ts +19 -0
  81. package/dist/components/ui/dialog/DialogClose.vue.d.ts.map +1 -0
  82. package/dist/components/ui/dialog/DialogContent.vue.d.ts +43 -0
  83. package/dist/components/ui/dialog/DialogContent.vue.d.ts.map +1 -0
  84. package/dist/components/ui/dialog/DialogFooter.vue.d.ts +25 -0
  85. package/dist/components/ui/dialog/DialogFooter.vue.d.ts.map +1 -0
  86. package/dist/components/ui/dialog/DialogHeader.vue.d.ts +29 -0
  87. package/dist/components/ui/dialog/DialogHeader.vue.d.ts.map +1 -0
  88. package/dist/components/ui/dialog/DialogTitle.vue.d.ts +23 -0
  89. package/dist/components/ui/dialog/DialogTitle.vue.d.ts.map +1 -0
  90. package/dist/components/ui/dialog/DialogTrigger.vue.d.ts +19 -0
  91. package/dist/components/ui/dialog/DialogTrigger.vue.d.ts.map +1 -0
  92. package/dist/components/ui/dialog/index.d.ts +8 -0
  93. package/dist/components/ui/dialog/index.d.ts.map +1 -0
  94. package/dist/components/ui/drawer/Drawer.vue.d.ts +35 -0
  95. package/dist/components/ui/drawer/Drawer.vue.d.ts.map +1 -0
  96. package/dist/components/ui/drawer/DrawerClose.vue.d.ts +19 -0
  97. package/dist/components/ui/drawer/DrawerClose.vue.d.ts.map +1 -0
  98. package/dist/components/ui/drawer/DrawerContent.vue.d.ts +43 -0
  99. package/dist/components/ui/drawer/DrawerContent.vue.d.ts.map +1 -0
  100. package/dist/components/ui/drawer/DrawerDescription.vue.d.ts +23 -0
  101. package/dist/components/ui/drawer/DrawerDescription.vue.d.ts.map +1 -0
  102. package/dist/components/ui/drawer/DrawerFooter.vue.d.ts +22 -0
  103. package/dist/components/ui/drawer/DrawerFooter.vue.d.ts.map +1 -0
  104. package/dist/components/ui/drawer/DrawerHeader.vue.d.ts +25 -0
  105. package/dist/components/ui/drawer/DrawerHeader.vue.d.ts.map +1 -0
  106. package/dist/components/ui/drawer/DrawerOverlay.vue.d.ts +8 -0
  107. package/dist/components/ui/drawer/DrawerOverlay.vue.d.ts.map +1 -0
  108. package/dist/components/ui/drawer/DrawerTitle.vue.d.ts +23 -0
  109. package/dist/components/ui/drawer/DrawerTitle.vue.d.ts.map +1 -0
  110. package/dist/components/ui/drawer/DrawerTrigger.vue.d.ts +19 -0
  111. package/dist/components/ui/drawer/DrawerTrigger.vue.d.ts.map +1 -0
  112. package/dist/components/ui/drawer/index.d.ts +11 -0
  113. package/dist/components/ui/drawer/index.d.ts.map +1 -0
  114. package/dist/components/ui/popover/PopoverContent.vue.d.ts +2 -2
  115. package/dist/components/ui/popover/PopoverContent.vue.d.ts.map +1 -1
  116. package/dist/components/ui/popover/PopoverOption.vue.d.ts +1 -1
  117. package/dist/components/ui/popover/PopoverOption.vue.d.ts.map +1 -1
  118. package/dist/components/ui/popover/PopoverTrigger.vue.d.ts.map +1 -1
  119. package/dist/components/ui/tooltip/Tooltip.vue.d.ts +23 -0
  120. package/dist/components/ui/tooltip/Tooltip.vue.d.ts.map +1 -0
  121. package/dist/components/ui/tooltip/TooltipContent.vue.d.ts +31 -0
  122. package/dist/components/ui/tooltip/TooltipContent.vue.d.ts.map +1 -0
  123. package/dist/components/ui/tooltip/TooltipTrigger.vue.d.ts +19 -0
  124. package/dist/components/ui/tooltip/TooltipTrigger.vue.d.ts.map +1 -0
  125. package/dist/components/ui/tooltip/index.d.ts +4 -0
  126. package/dist/components/ui/tooltip/index.d.ts.map +1 -0
  127. package/dist/{es-40d7aad6.mjs → es-59933601.mjs} +1 -1
  128. package/dist/{index-56b50ff8.mjs → index-4fe9253b.mjs} +99820 -96757
  129. package/dist/lib/layer-manager.d.ts +16 -0
  130. package/dist/lib/layer-manager.d.ts.map +1 -0
  131. package/dist/locales/en.json.d.ts +2 -1
  132. package/dist/locales/es.json.d.ts +2 -1
  133. package/dist/locales/pt_br.json.d.ts +2 -1
  134. package/dist/{pt-br-e6e2313f.mjs → pt-br-10db3200.mjs} +1 -1
  135. package/dist/style.css +1 -1
  136. package/dist/unnnic.mjs +234 -204
  137. package/dist/unnnic.umd.js +48 -44
  138. package/package.json +3 -2
  139. package/src/assets/scss/scheme-colors.scss +223 -223
  140. package/src/assets/scss/tailwind.scss +8 -0
  141. package/src/components/Alert/__tests__/__snapshots__/Alert.spec.js.snap +1 -1
  142. package/src/components/Checkbox/Checkbox.vue +1 -1
  143. package/src/components/Drawer/Drawer.vue +190 -269
  144. package/src/components/Drawer/__tests__/Drawer.spec.js +37 -46
  145. package/src/components/Drawer/__tests__/__snapshots__/Drawer.spec.js.snap +18 -19
  146. package/src/components/Input/BaseInput.vue +21 -2
  147. package/src/components/Input/Input.scss +2 -3
  148. package/src/components/Input/Input.vue +19 -1
  149. package/src/components/Input/TextInput.vue +58 -22
  150. package/src/components/Input/__test__/__snapshots__/Input.spec.js.snap +5 -1
  151. package/src/components/Input/__test__/__snapshots__/TextInput.spec.js.snap +7 -1
  152. package/src/components/ModalDialog/ModalDialog.vue +64 -148
  153. package/src/components/ModalDialog/__tests__/ModalDialog.spec.js +11 -221
  154. package/src/components/ModalDialog/__tests__/__snapshots__/ModalDialog.spec.js.snap +1 -22
  155. package/src/components/MultiSelectV2/MultSelectOption.vue +67 -0
  156. package/src/components/MultiSelectV2/__tests__/MultiSelect.spec.js +556 -0
  157. package/src/components/MultiSelectV2/__tests__/MultiSelectOption.spec.js +229 -0
  158. package/src/components/MultiSelectV2/__tests__/__snapshots__/MultiSelect.spec.js.snap +121 -0
  159. package/src/components/MultiSelectV2/__tests__/__snapshots__/MultiSelectOption.spec.js.snap +51 -0
  160. package/src/components/MultiSelectV2/index.vue +224 -0
  161. package/src/components/Select/__tests__/Select.spec.js +422 -0
  162. package/src/components/Select/__tests__/SelectItem.spec.js +330 -0
  163. package/src/components/Select/__tests__/__snapshots__/Popover.spec.js.snap +8 -0
  164. package/src/components/Select/__tests__/__snapshots__/Select.spec.js.snap +65 -0
  165. package/src/components/Select/__tests__/__snapshots__/SelectItem.spec.js.snap +15 -0
  166. package/src/components/Select/__tests__/__snapshots__/SelectOption.spec.js.snap +25 -0
  167. package/src/components/Select/__tests__/__snapshots__/SelectPopover.spec.js.snap +8 -0
  168. package/src/components/Select/index.vue +261 -0
  169. package/src/components/Tab/__test__/__snapshots__/Tab.spec.js.snap +3 -1
  170. package/src/components/Toast/Toast.vue +16 -9
  171. package/src/components/ToolTip/ToolTip.vue +25 -177
  172. package/src/components/ToolTip/__tests__/ToolTip.spec.js +339 -61
  173. package/src/components/index.ts +60 -4
  174. package/src/components/ui/dialog/Dialog.vue +19 -0
  175. package/src/components/ui/dialog/DialogClose.vue +29 -0
  176. package/src/components/ui/dialog/DialogContent.vue +140 -0
  177. package/src/components/ui/dialog/DialogFooter.vue +50 -0
  178. package/src/components/ui/dialog/DialogHeader.vue +83 -0
  179. package/src/components/ui/dialog/DialogTitle.vue +38 -0
  180. package/src/components/ui/dialog/DialogTrigger.vue +16 -0
  181. package/src/components/ui/dialog/index.ts +7 -0
  182. package/src/components/ui/drawer/Drawer.vue +27 -0
  183. package/src/components/ui/drawer/DrawerClose.vue +37 -0
  184. package/src/components/ui/drawer/DrawerContent.vue +111 -0
  185. package/src/components/ui/drawer/DrawerDescription.vue +40 -0
  186. package/src/components/ui/drawer/DrawerFooter.vue +38 -0
  187. package/src/components/ui/drawer/DrawerHeader.vue +57 -0
  188. package/src/components/ui/drawer/DrawerOverlay.vue +33 -0
  189. package/src/components/ui/drawer/DrawerTitle.vue +37 -0
  190. package/src/components/ui/drawer/DrawerTrigger.vue +31 -0
  191. package/src/components/ui/drawer/index.ts +10 -0
  192. package/src/components/ui/popover/PopoverContent.vue +4 -2
  193. package/src/components/ui/popover/PopoverOption.vue +4 -0
  194. package/src/components/ui/popover/PopoverTrigger.vue +5 -1
  195. package/src/components/ui/tooltip/Tooltip.vue +21 -0
  196. package/src/components/ui/tooltip/TooltipContent.vue +74 -0
  197. package/src/components/ui/tooltip/TooltipTrigger.vue +26 -0
  198. package/src/components/ui/tooltip/index.ts +3 -0
  199. package/src/lib/layer-manager.ts +84 -0
  200. package/src/locales/en.json +2 -1
  201. package/src/locales/es.json +2 -1
  202. package/src/locales/pt_br.json +2 -1
  203. package/src/stories/Dialog.stories.js +832 -0
  204. package/src/stories/Drawer.stories.js +1 -1
  205. package/src/stories/DrawerNext.stories.js +611 -0
  206. package/src/stories/LayerManager.docs.mdx +40 -0
  207. package/src/stories/LayerManager.stories.js +364 -0
  208. package/src/stories/ModalDialog.mdx +3 -0
  209. package/src/stories/ModalDialog.stories.js +1 -1
  210. package/src/stories/MultiSelectV2.stories.js +158 -0
  211. package/src/stories/Select.stories.js +158 -0
@@ -0,0 +1,229 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { beforeEach, describe, expect, test, afterEach } from 'vitest';
3
+ import MultiSelectOption from '../MultSelectOption.vue';
4
+
5
+ const createWrapper = (props = {}) => {
6
+ return mount(MultiSelectOption, { props });
7
+ };
8
+
9
+ describe('MultiSelectOption.vue', () => {
10
+ let wrapper;
11
+
12
+ beforeEach(() => {
13
+ wrapper = createWrapper({
14
+ label: 'Test Option',
15
+ });
16
+ });
17
+
18
+ afterEach(() => {
19
+ if (wrapper) {
20
+ wrapper.unmount();
21
+ }
22
+ });
23
+
24
+ test('renders correctly', () => {
25
+ expect(wrapper.exists()).toBe(true);
26
+ });
27
+
28
+ test('applies the correct base CSS class', () => {
29
+ expect(wrapper.classes()).toContain('unnnic-multi-select-option');
30
+ });
31
+
32
+ test('renders UnnnicCheckbox component', () => {
33
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
34
+ expect(checkbox.exists()).toBe(true);
35
+ });
36
+
37
+ test('passes label prop to checkbox', () => {
38
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
39
+ expect(checkbox.props('label')).toBe('Test Option');
40
+ });
41
+
42
+ describe('props validation', () => {
43
+ test('validates required label prop', () => {
44
+ const wrapper = createWrapper({ label: 'Required Label' });
45
+ expect(wrapper.props('label')).toBe('Required Label');
46
+ });
47
+
48
+ test('validates optional disabled prop with default value', () => {
49
+ expect(wrapper.props('disabled')).toBe(false);
50
+ });
51
+
52
+ test('validates optional active prop with default value', () => {
53
+ expect(wrapper.props('active')).toBe(false);
54
+ });
55
+
56
+ test('validates optional focused prop with default value', () => {
57
+ expect(wrapper.props('focused')).toBe(false);
58
+ });
59
+ });
60
+
61
+ describe('disabled state', () => {
62
+ test('passes disabled prop to checkbox when disabled is true', async () => {
63
+ await wrapper.setProps({ disabled: true });
64
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
65
+ expect(checkbox.props('disabled')).toBe(true);
66
+ });
67
+
68
+ test('passes disabled prop to checkbox when disabled is false', async () => {
69
+ await wrapper.setProps({ disabled: false });
70
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
71
+ expect(checkbox.props('disabled')).toBe(false);
72
+ });
73
+ });
74
+
75
+ describe('active state', () => {
76
+ test('passes active prop to checkbox modelValue when active is true', async () => {
77
+ await wrapper.setProps({ active: true });
78
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
79
+ expect(checkbox.props('modelValue')).toBe(true);
80
+ });
81
+
82
+ test('passes active prop to checkbox modelValue when active is false', async () => {
83
+ await wrapper.setProps({ active: false });
84
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
85
+ expect(checkbox.props('modelValue')).toBe(false);
86
+ });
87
+ });
88
+
89
+ describe('events', () => {
90
+ test('emits update:modelValue when checkbox emits update:model-value', async () => {
91
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
92
+
93
+ await checkbox.vm.$emit('update:model-value', true);
94
+
95
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
96
+ expect(wrapper.emitted('update:modelValue')[0][0]).toBe(true);
97
+ });
98
+
99
+ test('emits update:modelValue with toggled value when active is false', async () => {
100
+ await wrapper.setProps({ active: false });
101
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
102
+
103
+ await checkbox.vm.$emit('update:model-value', true);
104
+
105
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
106
+ expect(wrapper.emitted('update:modelValue')[0][0]).toBe(true);
107
+ });
108
+
109
+ test('emits update:modelValue with toggled value when active is true', async () => {
110
+ await wrapper.setProps({ active: true });
111
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
112
+
113
+ await checkbox.vm.$emit('update:model-value', false);
114
+
115
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
116
+ expect(wrapper.emitted('update:modelValue')[0][0]).toBe(false);
117
+ });
118
+ });
119
+
120
+ describe('combined states', () => {
121
+ test('can be both active and disabled', async () => {
122
+ await wrapper.setProps({ active: true, disabled: true });
123
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
124
+
125
+ expect(checkbox.props('modelValue')).toBe(true);
126
+ expect(checkbox.props('disabled')).toBe(true);
127
+ });
128
+
129
+ test('renders correctly with all props', async () => {
130
+ await wrapper.setProps({
131
+ label: 'Complex Option',
132
+ active: true,
133
+ disabled: false,
134
+ focused: true,
135
+ });
136
+
137
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
138
+ expect(checkbox.props('label')).toBe('Complex Option');
139
+ expect(checkbox.props('modelValue')).toBe(true);
140
+ expect(checkbox.props('disabled')).toBe(false);
141
+ });
142
+ });
143
+
144
+ describe('component structure', () => {
145
+ test('has correct component name', () => {
146
+ expect(wrapper.vm.$options.name).toBe('UnnnicMultiSelectOption');
147
+ });
148
+
149
+ test('renders a div element', () => {
150
+ expect(wrapper.element.tagName).toBe('DIV');
151
+ });
152
+
153
+ test('contains UnnnicCheckbox component', () => {
154
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
155
+ expect(checkbox.exists()).toBe(true);
156
+ });
157
+ });
158
+
159
+ describe('edge cases', () => {
160
+ test('handles empty label', async () => {
161
+ await wrapper.setProps({ label: '' });
162
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
163
+ expect(checkbox.props('label')).toBe('');
164
+ });
165
+
166
+ test('handles long label text', async () => {
167
+ const longText =
168
+ 'This is a very long label text that should be handled properly by the component';
169
+ await wrapper.setProps({ label: longText });
170
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
171
+ expect(checkbox.props('label')).toBe(longText);
172
+ });
173
+
174
+ test('handles special characters in label', async () => {
175
+ const specialText = 'Option with special chars: @#$%^&*()';
176
+ await wrapper.setProps({ label: specialText });
177
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
178
+ expect(checkbox.props('label')).toBe(specialText);
179
+ });
180
+
181
+ test('handles rapid state changes', async () => {
182
+ await wrapper.setProps({ active: true });
183
+ await wrapper.setProps({ active: false });
184
+ await wrapper.setProps({ active: true });
185
+
186
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
187
+ expect(checkbox.props('modelValue')).toBe(true);
188
+ });
189
+ });
190
+
191
+ describe('accessibility', () => {
192
+ test('checkbox receives disabled state for accessibility', async () => {
193
+ await wrapper.setProps({ disabled: true });
194
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
195
+ expect(checkbox.props('disabled')).toBe(true);
196
+ });
197
+
198
+ test('checkbox receives label for accessibility', () => {
199
+ const checkbox = wrapper.findComponent({ name: 'UnnnicCheckbox' });
200
+ expect(checkbox.props('label')).toBe('Test Option');
201
+ });
202
+ });
203
+
204
+ describe('snapshot testing', () => {
205
+ test('matches snapshot with default props', () => {
206
+ expect(wrapper.html()).toMatchSnapshot();
207
+ });
208
+
209
+ test('matches snapshot with active state', async () => {
210
+ await wrapper.setProps({ active: true });
211
+ expect(wrapper.html()).toMatchSnapshot();
212
+ });
213
+
214
+ test('matches snapshot with disabled state', async () => {
215
+ await wrapper.setProps({ disabled: true });
216
+ expect(wrapper.html()).toMatchSnapshot();
217
+ });
218
+
219
+ test('matches snapshot with both active and disabled states', async () => {
220
+ await wrapper.setProps({ active: true, disabled: true });
221
+ expect(wrapper.html()).toMatchSnapshot();
222
+ });
223
+
224
+ test('matches snapshot with focused state', async () => {
225
+ await wrapper.setProps({ focused: true });
226
+ expect(wrapper.html()).toMatchSnapshot();
227
+ });
228
+ });
229
+ });
@@ -0,0 +1,121 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`UnnnicMultiSelect.vue > snapshot testing > matches snapshot with default props 1`] = `
4
+ "<div data-v-de5c711a="" class="unnnic-multi-select">
5
+ <section data-v-5a3125ac="" data-v-de5c711a="" class="unnnic-popover">
6
+ <div data-v-5a3125ac="" class="unnnic-popover__trigger" data-testid="popover-trigger">
7
+ <div data-v-d890ad85="" data-v-de5c711a="" class="unnnic-form md unnnic-multi-select__input">
8
+ <!--v-if-->
9
+ <div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-multi-select__input unnnic-form-input" mask=""><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-multi-select__input unnnic-form-input input-itself input size-md normal input--has-icon-right input--has-clear-icon unnnic-multi-select__input unnnic-form-input input-itself" placeholder="" iconleft="" iconright="keyboard_arrow_down" iconleftclickable="false" iconrightclickable="false" hascloudycolor="false" showclear="true" type="text" readonly="" value="">
10
+ <!--v-if-->
11
+ <section data-v-a0d36167="" class="icon-right-container"><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic--clickable icon-clear" data-testid="material-icon" translate="no">close</span><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant icon-right" data-testid="material-icon" translate="no">keyboard_arrow_down</span></section>
12
+ </div>
13
+ <section data-v-d890ad85="" class="unnnic-form__hints-container">
14
+ <section data-v-d890ad85="" class="unnnic-form__message-container">
15
+ <!--v-if-->
16
+ <!--v-if-->
17
+ </section>
18
+ <!--v-if-->
19
+ </section>
20
+ </div>
21
+ </div>
22
+ <!--v-if-->
23
+ </section>
24
+ </div>"
25
+ `;
26
+
27
+ exports[`UnnnicMultiSelect.vue > snapshot testing > matches snapshot with disabled state 1`] = `
28
+ "<div data-v-de5c711a="" class="unnnic-multi-select">
29
+ <section data-v-5a3125ac="" data-v-de5c711a="" class="unnnic-popover">
30
+ <div data-v-5a3125ac="" class="unnnic-popover__trigger" data-testid="popover-trigger">
31
+ <div data-v-d890ad85="" data-v-de5c711a="" class="unnnic-form md unnnic-multi-select__input">
32
+ <!--v-if-->
33
+ <div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-multi-select__input unnnic-form-input" mask=""><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-multi-select__input unnnic-form-input input-itself input size-md normal input--has-icon-right input--has-clear-icon unnnic-multi-select__input unnnic-form-input input-itself" placeholder="" iconleft="" iconright="keyboard_arrow_down" iconleftclickable="false" iconrightclickable="false" hascloudycolor="false" showclear="true" type="text" readonly="" value="" disabled="">
34
+ <!--v-if-->
35
+ <section data-v-a0d36167="" class="icon-right-container"><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-muted unnnic-icon-size--ant unnnic--clickable icon-clear" data-testid="material-icon" translate="no">close</span><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-muted unnnic-icon-size--ant icon-right" data-testid="material-icon" translate="no">keyboard_arrow_down</span></section>
36
+ </div>
37
+ <section data-v-d890ad85="" class="unnnic-form__hints-container">
38
+ <section data-v-d890ad85="" class="unnnic-form__message-container">
39
+ <!--v-if-->
40
+ <!--v-if-->
41
+ </section>
42
+ <!--v-if-->
43
+ </section>
44
+ </div>
45
+ </div>
46
+ <!--v-if-->
47
+ </section>
48
+ </div>"
49
+ `;
50
+
51
+ exports[`UnnnicMultiSelect.vue > snapshot testing > matches snapshot with multiple selected values 1`] = `
52
+ "<div data-v-de5c711a="" class="unnnic-multi-select">
53
+ <section data-v-5a3125ac="" data-v-de5c711a="" class="unnnic-popover">
54
+ <div data-v-5a3125ac="" class="unnnic-popover__trigger" data-testid="popover-trigger">
55
+ <div data-v-d890ad85="" data-v-de5c711a="" class="unnnic-form md unnnic-multi-select__input">
56
+ <!--v-if-->
57
+ <div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-multi-select__input unnnic-form-input" mask=""><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-multi-select__input unnnic-form-input input-itself input size-md normal input--has-icon-right input--has-clear-icon unnnic-multi-select__input unnnic-form-input input-itself" placeholder="" iconleft="" iconright="keyboard_arrow_down" iconleftclickable="false" iconrightclickable="false" hascloudycolor="false" showclear="true" type="text" readonly="" value="Option 1, Option 2">
58
+ <!--v-if-->
59
+ <section data-v-a0d36167="" class="icon-right-container"><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--color-gray-700 unnnic-icon-size--ant unnnic--clickable icon-clear" data-testid="material-icon" translate="no">close</span><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--color-gray-700 unnnic-icon-size--ant icon-right" data-testid="material-icon" translate="no">keyboard_arrow_down</span></section>
60
+ </div>
61
+ <section data-v-d890ad85="" class="unnnic-form__hints-container">
62
+ <section data-v-d890ad85="" class="unnnic-form__message-container">
63
+ <!--v-if-->
64
+ <!--v-if-->
65
+ </section>
66
+ <!--v-if-->
67
+ </section>
68
+ </div>
69
+ </div>
70
+ <!--v-if-->
71
+ </section>
72
+ </div>"
73
+ `;
74
+
75
+ exports[`UnnnicMultiSelect.vue > snapshot testing > matches snapshot with search enabled 1`] = `
76
+ "<div data-v-de5c711a="" class="unnnic-multi-select">
77
+ <section data-v-5a3125ac="" data-v-de5c711a="" class="unnnic-popover">
78
+ <div data-v-5a3125ac="" class="unnnic-popover__trigger" data-testid="popover-trigger">
79
+ <div data-v-d890ad85="" data-v-de5c711a="" class="unnnic-form md unnnic-multi-select__input">
80
+ <!--v-if-->
81
+ <div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-multi-select__input unnnic-form-input" mask=""><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-multi-select__input unnnic-form-input input-itself input size-md normal input--has-icon-right input--has-clear-icon unnnic-multi-select__input unnnic-form-input input-itself" placeholder="" iconleft="" iconright="keyboard_arrow_down" iconleftclickable="false" iconrightclickable="false" hascloudycolor="false" showclear="true" type="text" readonly="" value="">
82
+ <!--v-if-->
83
+ <section data-v-a0d36167="" class="icon-right-container"><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic--clickable icon-clear" data-testid="material-icon" translate="no">close</span><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant icon-right" data-testid="material-icon" translate="no">keyboard_arrow_down</span></section>
84
+ </div>
85
+ <section data-v-d890ad85="" class="unnnic-form__hints-container">
86
+ <section data-v-d890ad85="" class="unnnic-form__message-container">
87
+ <!--v-if-->
88
+ <!--v-if-->
89
+ </section>
90
+ <!--v-if-->
91
+ </section>
92
+ </div>
93
+ </div>
94
+ <!--v-if-->
95
+ </section>
96
+ </div>"
97
+ `;
98
+
99
+ exports[`UnnnicMultiSelect.vue > snapshot testing > matches snapshot with selected values 1`] = `
100
+ "<div data-v-de5c711a="" class="unnnic-multi-select">
101
+ <section data-v-5a3125ac="" data-v-de5c711a="" class="unnnic-popover">
102
+ <div data-v-5a3125ac="" class="unnnic-popover__trigger" data-testid="popover-trigger">
103
+ <div data-v-d890ad85="" data-v-de5c711a="" class="unnnic-form md unnnic-multi-select__input">
104
+ <!--v-if-->
105
+ <div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-multi-select__input unnnic-form-input" mask=""><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-multi-select__input unnnic-form-input input-itself input size-md normal input--has-icon-right input--has-clear-icon unnnic-multi-select__input unnnic-form-input input-itself" placeholder="" iconleft="" iconright="keyboard_arrow_down" iconleftclickable="false" iconrightclickable="false" hascloudycolor="false" showclear="true" type="text" readonly="" value="Option 1">
106
+ <!--v-if-->
107
+ <section data-v-a0d36167="" class="icon-right-container"><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--color-gray-700 unnnic-icon-size--ant unnnic--clickable icon-clear" data-testid="material-icon" translate="no">close</span><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--color-gray-700 unnnic-icon-size--ant icon-right" data-testid="material-icon" translate="no">keyboard_arrow_down</span></section>
108
+ </div>
109
+ <section data-v-d890ad85="" class="unnnic-form__hints-container">
110
+ <section data-v-d890ad85="" class="unnnic-form__message-container">
111
+ <!--v-if-->
112
+ <!--v-if-->
113
+ </section>
114
+ <!--v-if-->
115
+ </section>
116
+ </div>
117
+ </div>
118
+ <!--v-if-->
119
+ </section>
120
+ </div>"
121
+ `;
@@ -0,0 +1,51 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`MultiSelectOption.vue > snapshot testing > matches snapshot with active state 1`] = `
4
+ "<div data-v-72fb6e0d="" class="unnnic-multi-select-option">
5
+ <section data-v-18939422="" data-v-72fb6e0d="" class="unnnic-checkbox-wrapper"><label data-v-18939422=""><input data-v-18939422="" class="unnnic-checkbox" type="checkbox" checked="">
6
+ <p data-v-18939422="" class="unnnic-checkbox__label" data-testid="checkbox-text-right">Test Option</p>
7
+ </label>
8
+ <!--v-if-->
9
+ </section>
10
+ </div>"
11
+ `;
12
+
13
+ exports[`MultiSelectOption.vue > snapshot testing > matches snapshot with both active and disabled states 1`] = `
14
+ "<div data-v-72fb6e0d="" class="unnnic-multi-select-option">
15
+ <section data-v-18939422="" data-v-72fb6e0d="" class="unnnic-checkbox-wrapper"><label data-v-18939422=""><input data-v-18939422="" class="unnnic-checkbox" type="checkbox" disabled="" checked="">
16
+ <p data-v-18939422="" class="unnnic-checkbox__label unnnic-checkbox__label--disabled" data-testid="checkbox-text-right">Test Option</p>
17
+ </label>
18
+ <!--v-if-->
19
+ </section>
20
+ </div>"
21
+ `;
22
+
23
+ exports[`MultiSelectOption.vue > snapshot testing > matches snapshot with default props 1`] = `
24
+ "<div data-v-72fb6e0d="" class="unnnic-multi-select-option">
25
+ <section data-v-18939422="" data-v-72fb6e0d="" class="unnnic-checkbox-wrapper"><label data-v-18939422=""><input data-v-18939422="" class="unnnic-checkbox" type="checkbox">
26
+ <p data-v-18939422="" class="unnnic-checkbox__label" data-testid="checkbox-text-right">Test Option</p>
27
+ </label>
28
+ <!--v-if-->
29
+ </section>
30
+ </div>"
31
+ `;
32
+
33
+ exports[`MultiSelectOption.vue > snapshot testing > matches snapshot with disabled state 1`] = `
34
+ "<div data-v-72fb6e0d="" class="unnnic-multi-select-option">
35
+ <section data-v-18939422="" data-v-72fb6e0d="" class="unnnic-checkbox-wrapper"><label data-v-18939422=""><input data-v-18939422="" class="unnnic-checkbox" type="checkbox" disabled="">
36
+ <p data-v-18939422="" class="unnnic-checkbox__label unnnic-checkbox__label--disabled" data-testid="checkbox-text-right">Test Option</p>
37
+ </label>
38
+ <!--v-if-->
39
+ </section>
40
+ </div>"
41
+ `;
42
+
43
+ exports[`MultiSelectOption.vue > snapshot testing > matches snapshot with focused state 1`] = `
44
+ "<div data-v-72fb6e0d="" class="unnnic-multi-select-option">
45
+ <section data-v-18939422="" data-v-72fb6e0d="" class="unnnic-checkbox-wrapper"><label data-v-18939422=""><input data-v-18939422="" class="unnnic-checkbox" type="checkbox">
46
+ <p data-v-18939422="" class="unnnic-checkbox__label" data-testid="checkbox-text-right">Test Option</p>
47
+ </label>
48
+ <!--v-if-->
49
+ </section>
50
+ </div>"
51
+ `;
@@ -0,0 +1,224 @@
1
+ <template>
2
+ <div class="unnnic-multi-select">
3
+ <Popover
4
+ :open="openPopover"
5
+ @update:open="openPopover = $event"
6
+ >
7
+ <PopoverTrigger>
8
+ <UnnnicInput
9
+ :modelValue="inputValue"
10
+ class="unnnic-multi-select__input"
11
+ readonly
12
+ :forceActiveStatus="openPopover"
13
+ :size="props.size"
14
+ :placeholder="props.placeholder"
15
+ :label="props.label"
16
+ :errors="props.errors"
17
+ :message="props.message"
18
+ :iconRight="openPopover ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
19
+ :disabled="props.disabled"
20
+ showClear
21
+ @clear="emit('update:modelValue', [])"
22
+ />
23
+ </PopoverTrigger>
24
+ <PopoverContent
25
+ align="start"
26
+ :style="{ maxHeight: calculatedMaxHeight, overflow: 'auto' }"
27
+ >
28
+ <div class="unnnic-multi-select__content">
29
+ <UnnnicInput
30
+ v-if="props.enableSearch"
31
+ class="unnnic-multi-select__input-search"
32
+ :modelValue="props.search"
33
+ :placeholder="$t('search')"
34
+ iconLeft="search"
35
+ @update:model-value="handleSearch"
36
+ />
37
+ <div class="unnnic-multi-select__options">
38
+ <UnnnicMultiSelectOption
39
+ v-for="(option, index) in filteredOptions"
40
+ :key="option[props.itemValue]"
41
+ :data-option-index="index"
42
+ :label="option[props.itemLabel]"
43
+ :active="getActivatedOptionStatus(option)"
44
+ :focused="focusedOptionIndex === index"
45
+ :disabled="option.disabled"
46
+ @update:model-value="handleSelectOption(option, $event)"
47
+ />
48
+ </div>
49
+ </div>
50
+ </PopoverContent>
51
+ </Popover>
52
+ </div>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ import { computed, ref } from 'vue';
57
+
58
+ import { Popover, PopoverTrigger, PopoverContent } from '../ui/popover';
59
+ import UnnnicInput from '../Input/Input.vue';
60
+ import UnnnicMultiSelectOption from './MultSelectOption.vue';
61
+
62
+ defineOptions({
63
+ name: 'UnnnicMultiSelect',
64
+ });
65
+
66
+ interface MultiSelectProps {
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ options: Array<{ [key: string]: any }>;
69
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
+ modelValue: any[];
71
+ returnObject?: boolean;
72
+ itemLabel?: string;
73
+ itemValue?: string;
74
+ placeholder?: string;
75
+ label?: string;
76
+ type?: 'normal' | 'error';
77
+ errors?: string | Array<string>;
78
+ message?: string;
79
+ size?: 'sm' | 'md';
80
+ optionsLines?: number;
81
+ enableSearch?: boolean;
82
+ search?: string;
83
+ locale?: string;
84
+ disabled?: boolean;
85
+ }
86
+
87
+ const props = withDefaults(defineProps<MultiSelectProps>(), {
88
+ size: 'md',
89
+ type: 'normal',
90
+ placeholder: '',
91
+ optionsLines: 5,
92
+ returnObject: false,
93
+ itemLabel: 'label',
94
+ itemValue: 'value',
95
+ locale: 'en',
96
+ enableSearch: false,
97
+ disabled: false,
98
+ label: '',
99
+ errors: '',
100
+ message: '',
101
+ search: '',
102
+ });
103
+
104
+ const openPopover = ref(false);
105
+
106
+ const calculatedMaxHeight = computed(() => {
107
+ if (!props.options || props.options.length === 0) return 'unset';
108
+ const popoverSearchGap = props.enableSearch ? 16 : 0;
109
+ const popoverGap = 24;
110
+ const fieldsHeight = 22 * props.optionsLines;
111
+ const size = fieldsHeight + (popoverGap * props.optionsLines - 2);
112
+ return `${props.enableSearch ? size + 51 + popoverSearchGap : size}px`;
113
+ });
114
+
115
+ const emit = defineEmits<{
116
+ 'update:modelValue': [unknown[]];
117
+ 'update:search': [string];
118
+ }>();
119
+
120
+ const focusedOptionIndex = ref<number>(-1);
121
+
122
+ const selectedItems = computed(() => {
123
+ if (props.returnObject) return props.modelValue;
124
+
125
+ const modelValueValues = props.returnObject
126
+ ? props.modelValue.map((item) => item[props.itemValue])
127
+ : props.modelValue;
128
+
129
+ return props.options.filter((option) =>
130
+ modelValueValues.includes(option[props.itemValue]),
131
+ );
132
+ });
133
+ const inputValue = computed(() => {
134
+ return selectedItems.value.map((item) => item[props.itemLabel]).join(', ');
135
+ });
136
+
137
+ const filteredOptions = computed(() => {
138
+ if (!props.enableSearch || !props.search) return props.options;
139
+
140
+ return props.options.filter(
141
+ (option) =>
142
+ option[props.itemLabel]
143
+ .toLowerCase()
144
+ .includes(props.search?.toLowerCase()) ||
145
+ option[props.itemValue]
146
+ .toLowerCase()
147
+ .includes(props.search?.toLowerCase()),
148
+ );
149
+ });
150
+
151
+ const handleSearch = (value: string) => {
152
+ emit('update:search', value);
153
+ };
154
+
155
+ const getActivatedOptionStatus = (option: (typeof props.options)[number]) => {
156
+ if (props.returnObject) {
157
+ return props.modelValue.find(
158
+ (item) => item[props.itemValue] === option[props.itemValue],
159
+ );
160
+ }
161
+ return props.modelValue.includes(option[props.itemValue]);
162
+ };
163
+
164
+ const handleSelectOption = (
165
+ option: (typeof props.options)[number],
166
+ selected: boolean,
167
+ ) => {
168
+ if (selected) {
169
+ emit(
170
+ 'update:modelValue',
171
+ props.returnObject
172
+ ? [...props.modelValue, option]
173
+ : [...props.modelValue, option[props.itemValue]],
174
+ );
175
+ } else {
176
+ emit(
177
+ 'update:modelValue',
178
+ props.returnObject
179
+ ? props.modelValue.filter(
180
+ (item) => item[props.itemValue] !== option[props.itemValue],
181
+ )
182
+ : props.modelValue.filter((item) => item !== option[props.itemValue]),
183
+ );
184
+ }
185
+ };
186
+ </script>
187
+
188
+ <style lang="scss" scoped>
189
+ @use '@/assets/scss/unnnic' as *;
190
+
191
+ :deep(.unnnic-multi-select__input) {
192
+ cursor: pointer;
193
+ }
194
+
195
+ :deep(.unnnic-multi-select__input-search) {
196
+ > .icon-left {
197
+ color: $unnnic-color-fg-base;
198
+ }
199
+ }
200
+
201
+ :deep(.unnnic-multi-select__input) {
202
+ > .icon-right {
203
+ color: $unnnic-color-fg-base;
204
+ }
205
+ }
206
+
207
+ .unnnic-multi-select {
208
+ &__content {
209
+ display: flex;
210
+ flex-direction: column;
211
+ padding: 0;
212
+ margin: 0;
213
+ gap: $unnnic-space-4;
214
+ }
215
+
216
+ &__options {
217
+ padding: 0;
218
+ margin: 0;
219
+ display: flex;
220
+ flex-direction: column;
221
+ gap: $unnnic-space-6;
222
+ }
223
+ }
224
+ </style>