@weni/unnnic-system 3.14.0-alpha-teleports.0 → 3.14.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 (77) hide show
  1. package/README.md +1 -9
  2. package/dist/{es-0d53b5b2.mjs → es-91ae9eed.mjs} +1 -1
  3. package/dist/{index-d7070de8.mjs → index-3b503557.mjs} +26122 -28965
  4. package/dist/index.d.ts +1485 -4826
  5. package/dist/{pt-br-bf4e1f97.mjs → pt-br-9553a558.mjs} +1 -1
  6. package/dist/style.css +1 -1
  7. package/dist/unnnic.mjs +204 -232
  8. package/dist/unnnic.umd.js +44 -48
  9. package/package.json +2 -3
  10. package/src/assets/scss/tailwind.scss +0 -8
  11. package/src/components/Alert/__tests__/__snapshots__/Alert.spec.js.snap +1 -1
  12. package/src/components/ChartFunnel/DefaultFunnel/ChartDefaultFunnelBase.vue +1 -2
  13. package/src/components/ChartFunnel/SvgFunnel/ChartFunnelTwoRows.vue +60 -61
  14. package/src/components/CheckboxGroup/CheckboxGroup.vue +7 -5
  15. package/src/components/Chip/Chip.vue +1 -1
  16. package/src/components/DatePicker/DatePicker.vue +1 -10
  17. package/src/components/Drawer/Drawer.vue +270 -180
  18. package/src/components/Drawer/__tests__/Drawer.spec.js +43 -32
  19. package/src/components/Drawer/__tests__/__snapshots__/Drawer.spec.js.snap +19 -18
  20. package/src/components/FormElement/FormElement.vue +96 -87
  21. package/src/components/InputDatePicker/InputDatePicker.vue +73 -68
  22. package/src/components/InputDatePicker/__test__/InputDatePicker.spec.js +24 -31
  23. package/src/components/ModalDialog/ModalDialog.vue +154 -63
  24. package/src/components/ModalDialog/__tests__/ModalDialog.spec.js +210 -30
  25. package/src/components/ModalDialog/__tests__/__snapshots__/ModalDialog.spec.js.snap +22 -1
  26. package/src/components/Radio/Radio.vue +12 -6
  27. package/src/components/Radio/__test__/Radio.spec.js +3 -1
  28. package/src/components/RadioGroup/RadioGroup.vue +18 -10
  29. package/src/components/Select/__tests__/SelectItem.spec.js +35 -15
  30. package/src/components/Switch/Switch.vue +10 -3
  31. package/src/components/Tab/__test__/__snapshots__/Tab.spec.js.snap +1 -3
  32. package/src/components/TemplatePreview/TemplatePreview.vue +28 -25
  33. package/src/components/TemplatePreview/TemplatePreviewModal.vue +10 -10
  34. package/src/components/TemplatePreview/types.d.ts +3 -3
  35. package/src/components/Toast/Toast.vue +1 -4
  36. package/src/components/Toast/ToastManager.ts +1 -4
  37. package/src/components/Toast/__tests__/ToastManager.spec.js +6 -10
  38. package/src/components/ToolTip/ToolTip.vue +177 -25
  39. package/src/components/ToolTip/__tests__/ToolTip.spec.js +61 -339
  40. package/src/components/index.ts +0 -56
  41. package/src/components/ui/popover/PopoverContent.vue +4 -7
  42. package/src/components/ui/popover/PopoverTrigger.vue +1 -5
  43. package/src/index.ts +2 -9
  44. package/src/stories/Drawer.stories.js +1 -1
  45. package/src/stories/ModalDialog.mdx +0 -3
  46. package/src/stories/ModalDialog.stories.js +1 -96
  47. package/src/stories/TemplatePreview.stories.js +27 -27
  48. package/src/stories/TemplatePreviewModal.stories.js +31 -31
  49. package/src/components/ui/dialog/Dialog.vue +0 -19
  50. package/src/components/ui/dialog/DialogClose.vue +0 -29
  51. package/src/components/ui/dialog/DialogContent.vue +0 -140
  52. package/src/components/ui/dialog/DialogFooter.vue +0 -50
  53. package/src/components/ui/dialog/DialogHeader.vue +0 -83
  54. package/src/components/ui/dialog/DialogTitle.vue +0 -38
  55. package/src/components/ui/dialog/DialogTrigger.vue +0 -16
  56. package/src/components/ui/dialog/index.ts +0 -7
  57. package/src/components/ui/drawer/Drawer.vue +0 -27
  58. package/src/components/ui/drawer/DrawerClose.vue +0 -31
  59. package/src/components/ui/drawer/DrawerContent.vue +0 -113
  60. package/src/components/ui/drawer/DrawerDescription.vue +0 -40
  61. package/src/components/ui/drawer/DrawerFooter.vue +0 -38
  62. package/src/components/ui/drawer/DrawerHeader.vue +0 -57
  63. package/src/components/ui/drawer/DrawerOverlay.vue +0 -33
  64. package/src/components/ui/drawer/DrawerTitle.vue +0 -37
  65. package/src/components/ui/drawer/DrawerTrigger.vue +0 -31
  66. package/src/components/ui/drawer/index.ts +0 -10
  67. package/src/components/ui/tooltip/Tooltip.vue +0 -21
  68. package/src/components/ui/tooltip/TooltipContent.vue +0 -77
  69. package/src/components/ui/tooltip/TooltipTrigger.vue +0 -24
  70. package/src/components/ui/tooltip/index.ts +0 -3
  71. package/src/lib/__tests__/teleport-target.spec.ts +0 -73
  72. package/src/lib/layer-manager.ts +0 -64
  73. package/src/lib/teleport-target.ts +0 -46
  74. package/src/stories/Dialog.stories.js +0 -832
  75. package/src/stories/DrawerNext.stories.js +0 -611
  76. package/src/stories/LayerManager.docs.mdx +0 -40
  77. package/src/stories/LayerManager.stories.js +0 -407
@@ -1,47 +1,64 @@
1
1
  <template>
2
- <UnnnicDialog
3
- :open="modelValue"
4
- @update:open="$emit('update:modelValue', $event)"
2
+ <section
3
+ v-if="modelValue"
4
+ class="unnnic-modal-dialog"
5
+ data-testid="modal-dialog"
5
6
  >
6
- <UnnnicDialogContent
7
- v-bind="$attrs"
8
- :size="size === 'sm' ? 'small' : size === 'lg' ? 'large' : 'medium'"
9
- :parentClass="['unnnic-modal-dialog', $attrs.class]"
10
- class="unnnic-modal-dialog__container"
11
- data-testid="modal-dialog"
12
- @escape-key-down="persistentHandler"
13
- @pointer-down-outside="persistentHandler"
7
+ <section
8
+ class="unnnic-modal-dialog__overlay"
9
+ data-testid="modal-overlay"
10
+ @click.stop="!persistent && close()"
11
+ />
12
+ <section
13
+ :class="[
14
+ 'unnnic-modal-dialog__container',
15
+ `unnnic-modal-dialog__container--${size}`,
16
+ ]"
17
+ data-testid="modal-container"
14
18
  >
15
19
  <section
16
- :class="[
17
- 'unnnic-modal-dialog__container__body',
18
- {
19
- 'unnnic-modal-dialog__container__body--left-sidebar':
20
- $slots.leftSidebar,
21
- },
22
- ]"
20
+ v-if="$slots.leftSidebar"
21
+ class="unnnic-modal-dialog__container__left-sidebar"
23
22
  >
24
- <section
25
- v-if="$slots.leftSidebar"
26
- class="unnnic-modal-dialog__container__left-sidebar"
27
- >
28
- <slot name="leftSidebar" />
29
- </section>
30
- <UnnnicDialogHeader
23
+ <slot name="leftSidebar" />
24
+ </section>
25
+
26
+ <section class="unnnic-modal-dialog__container__body">
27
+ <header
31
28
  v-if="title"
32
- :closeButton="showCloseIcon"
33
- :type="type"
29
+ class="unnnic-modal-dialog__container__header"
34
30
  >
35
- <UnnnicDialogTitle>
36
- {{ title }}
37
- </UnnnicDialogTitle>
38
- </UnnnicDialogHeader>
31
+ <section class="unnnic-modal-dialog__container__title-container">
32
+ <UnnnicIcon
33
+ v-if="icon || type"
34
+ data-testid="title-icon"
35
+ class="unnnic-modal-dialog__container__title-icon"
36
+ :icon="icon || iconsMapper[type]?.icon"
37
+ :scheme="iconScheme || iconsMapper[type]?.scheme"
38
+ size="md"
39
+ />
40
+ <h1
41
+ class="unnnic-modal-dialog__container__title-text"
42
+ data-testid="title-text"
43
+ >
44
+ {{ title }}
45
+ </h1>
46
+ </section>
47
+ <UnnnicIcon
48
+ v-if="showCloseIcon"
49
+ data-testid="close-icon"
50
+ icon="close"
51
+ clickable
52
+ scheme="neutral-cloudy"
53
+ @click="close()"
54
+ />
55
+ </header>
39
56
  <section class="unnnic-modal-dialog__container__content">
40
57
  <slot></slot>
41
58
  </section>
42
-
43
- <UnnnicDialogFooter
59
+ <section
44
60
  v-if="primaryButtonProps.text"
61
+ data-testid="actions-section"
45
62
  :class="[
46
63
  'unnnic-modal-dialog__container__actions',
47
64
  {
@@ -49,8 +66,6 @@
49
66
  showActionsDivider,
50
67
  },
51
68
  ]"
52
- :divider="showActionsDivider"
53
- data-testid="actions-section"
54
69
  >
55
70
  <UnnnicButton
56
71
  v-if="!hideSecondaryButton"
@@ -77,33 +92,24 @@
77
92
  class="unnnic-modal-dialog__container__actions__primary-button"
78
93
  @click.stop="$emit('primaryButtonClick')"
79
94
  />
80
- </UnnnicDialogFooter>
95
+ </section>
81
96
  </section>
82
- </UnnnicDialogContent>
83
- </UnnnicDialog>
97
+ </section>
98
+ </section>
84
99
  </template>
85
100
 
86
101
  <script>
102
+ import UnnnicIcon from '../Icon.vue';
87
103
  import UnnnicButton from '../Button/Button.vue';
88
104
  import UnnnicI18n from '../../mixins/i18n';
89
- import UnnnicDialog from '../ui/dialog/Dialog.vue';
90
- import UnnnicDialogContent from '../ui/dialog/DialogContent.vue';
91
- import UnnnicDialogHeader from '../ui/dialog/DialogHeader.vue';
92
- import UnnnicDialogTitle from '../ui/dialog/DialogTitle.vue';
93
- import UnnnicDialogFooter from '../ui/dialog/DialogFooter.vue';
94
105
 
95
106
  export default {
96
107
  name: 'UnnnicModalDialog',
97
108
  components: {
109
+ UnnnicIcon,
98
110
  UnnnicButton,
99
- UnnnicDialog,
100
- UnnnicDialogContent,
101
- UnnnicDialogHeader,
102
- UnnnicDialogTitle,
103
- UnnnicDialogFooter,
104
111
  },
105
112
  mixins: [UnnnicI18n],
106
- inheritAttrs: false,
107
113
  props: {
108
114
  modelValue: {
109
115
  type: Boolean,
@@ -171,6 +177,11 @@ export default {
171
177
  es: 'Cancelar',
172
178
  },
173
179
  },
180
+ iconsMapper: {
181
+ success: { icon: 'check_circle', scheme: 'aux-green-500' },
182
+ warning: { icon: 'warning', scheme: 'aux-red-500' },
183
+ attention: { icon: 'error', scheme: 'aux-yellow-500' },
184
+ },
174
185
  primaryButtonTypeMapper: {
175
186
  success: 'primary',
176
187
  warning: 'warning',
@@ -178,14 +189,17 @@ export default {
178
189
  },
179
190
  };
180
191
  },
192
+ watch: {
193
+ modelValue(value) {
194
+ this.updateBodyOverflow(value);
195
+ },
196
+ },
181
197
  methods: {
182
198
  close() {
183
199
  this.$emit('update:modelValue', false);
184
200
  },
185
- persistentHandler(event) {
186
- if (this.persistent) {
187
- event.preventDefault();
188
- }
201
+ updateBodyOverflow(isHidden) {
202
+ document.body.style.overflow = isHidden ? 'hidden' : '';
189
203
  },
190
204
  },
191
205
  };
@@ -193,29 +207,85 @@ export default {
193
207
 
194
208
  <style lang="scss" scoped>
195
209
  @use '@/assets/scss/unnnic' as *;
210
+ * {
211
+ margin: 0;
212
+ padding: 0;
213
+ box-sizing: border-box;
214
+ }
215
+ .unnnic-modal-dialog {
216
+ width: 100vw;
217
+ height: 100vh;
218
+ position: fixed;
219
+ left: 0;
220
+ top: 0;
221
+ display: flex;
222
+ justify-content: center;
223
+ align-items: center;
224
+ z-index: 9999;
225
+
226
+ &__overlay {
227
+ position: absolute;
228
+ width: 100%;
229
+ height: 100%;
230
+ background-color: rgba(0, 0, 0, 0.4);
231
+ }
232
+ }
196
233
 
197
234
  .unnnic-modal-dialog__container {
235
+ display: flex;
236
+ background: $unnnic-color-neutral-white;
237
+ border-radius: $unnnic-spacing-xs;
238
+ box-shadow: $unnnic-shadow-level-near;
239
+ position: fixed;
240
+ max-height: calc(100vh - $unnnic-spacing-giant);
241
+ overflow: hidden;
242
+
243
+ &--sm {
244
+ width: 400px;
245
+ }
246
+ &--md {
247
+ width: 600px;
248
+ }
249
+ &--lg {
250
+ width: 800px;
251
+ }
252
+
198
253
  &__left-sidebar {
199
254
  background-color: $unnnic-color-neutral-black;
200
255
  color: $unnnic-color-neutral-white;
201
-
202
- grid-area: left-sidebar;
203
- grid-row: span 3;
204
256
  }
205
257
 
206
258
  &__body {
207
259
  flex: 1;
208
260
  display: flex;
209
261
  flex-direction: column;
262
+ }
210
263
 
211
- overflow-y: auto;
264
+ &__header {
265
+ display: flex;
266
+ justify-content: space-between;
267
+ align-items: center;
268
+ border-bottom: 1px solid $unnnic-color-neutral-soft;
269
+ padding: $unnnic-spacing-md;
270
+ flex-shrink: 0;
271
+ }
212
272
 
213
- &--left-sidebar {
214
- border-radius: $unnnic-radius-4 0 0 $unnnic-radius-4;
215
- display: grid;
216
- grid-template-columns: auto 1fr;
217
- grid-template-areas: 'left-sidebar content';
218
- }
273
+ &__title-container {
274
+ display: flex;
275
+ align-items: center;
276
+ gap: $unnnic-spacing-ant;
277
+ }
278
+
279
+ &__title-icon {
280
+ font-size: 28px;
281
+ }
282
+
283
+ &__title-text {
284
+ font-family: $unnnic-font-family-secondary;
285
+ font-size: $unnnic-font-size-title-sm;
286
+ font-weight: $unnnic-font-weight-black;
287
+ line-height: 28px;
288
+ color: $unnnic-color-neutral-darkest;
219
289
  }
220
290
 
221
291
  &__content {
@@ -239,5 +309,26 @@ export default {
239
309
  border-radius: $unnnic-border-radius-pill;
240
310
  }
241
311
  }
312
+
313
+ &__actions {
314
+ display: grid;
315
+ grid-template-columns: 1fr 1fr;
316
+ grid-template-areas: 'secondary-button primary-button';
317
+ gap: $unnnic-spacing-sm;
318
+ padding: $unnnic-spacing-md;
319
+ flex-shrink: 0;
320
+
321
+ &--divider {
322
+ border-top: 1px solid $unnnic-color-neutral-soft;
323
+ }
324
+
325
+ &__secondary-button {
326
+ grid-area: secondary-button;
327
+ }
328
+
329
+ &__primary-button {
330
+ grid-area: primary-button;
331
+ }
332
+ }
242
333
  }
243
334
  </style>
@@ -1,5 +1,5 @@
1
1
  import { mount } from '@vue/test-utils';
2
- import { beforeEach, describe, it, expect, vi } from 'vitest';
2
+ import { describe, it, vi } from 'vitest';
3
3
  import ModalDialog from '../ModalDialog.vue';
4
4
 
5
5
  describe('ModalDialog.vue', () => {
@@ -16,12 +16,7 @@ describe('ModalDialog.vue', () => {
16
16
  'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
17
17
  },
18
18
  global: {
19
- stubs: [
20
- 'teleport',
21
- 'UnnnicIcon',
22
- 'UnnnicButton',
23
- 'UnnnicDialogContent',
24
- ],
19
+ stubs: ['UnnnicIcon', 'UnnnicButton'],
25
20
  },
26
21
  });
27
22
  });
@@ -31,46 +26,231 @@ describe('ModalDialog.vue', () => {
31
26
  expect(wrapper.html()).toMatchSnapshot();
32
27
  });
33
28
 
29
+ it('should render correctly when modelValue is true', () => {
30
+ const modal = wrapper.find('[data-testid="modal-dialog"]');
31
+ expect(modal.exists()).toBe(true);
32
+ });
33
+
34
+ it('should not render when modelValue is false', async () => {
35
+ await wrapper.setProps({ modelValue: false });
36
+
37
+ const modal = wrapper.find('[data-testid="modal-dialog"]');
38
+ expect(modal.exists()).toBe(false);
39
+ });
40
+
34
41
  it('should apply the correct size class based on the size prop', async () => {
35
- const modalContainer = wrapper.find('[data-testid="modal-dialog"]');
42
+ const modalContainer = wrapper.find('[data-testid="modal-container"]');
43
+ const defaultClass = 'unnnic-modal-dialog__container';
36
44
 
37
- expect(modalContainer.attributes('size')).toContain('medium');
45
+ expect(modalContainer.classes()).toContain(defaultClass + '--md');
38
46
 
39
47
  await wrapper.setProps({ size: 'lg' });
40
- expect(modalContainer.attributes('size')).toContain('large');
48
+ expect(modalContainer.classes()).toContain(defaultClass + '--lg');
41
49
 
42
50
  await wrapper.setProps({ size: 'sm' });
43
- expect(modalContainer.attributes('size')).toContain('small');
51
+ expect(modalContainer.classes()).toContain(defaultClass + '--sm');
52
+ });
53
+
54
+ it('should render the icon and title when provided', () => {
55
+ const title = wrapper.find('[data-testid="title-text"]');
56
+ expect(title.exists()).toBe(true);
57
+ expect(title.text()).toBe('Test Title');
58
+
59
+ const icon = wrapper.findComponent('[data-testid="title-icon"]');
60
+ expect(icon.exists()).toBe(true);
61
+ expect(icon.props('icon')).toBe('test-icon');
62
+ });
63
+
64
+ it('should render the icon from iconsMapper when type prop is provided', async () => {
65
+ await wrapper.setProps({
66
+ type: 'success',
67
+ icon: '',
68
+ });
69
+
70
+ const icon = wrapper.findComponent('[data-testid="title-icon"]');
71
+ expect(icon.exists()).toBe(true);
72
+ expect(icon.props().icon).toBe(wrapper.vm.iconsMapper['success'].icon);
73
+ });
74
+
75
+ it('should not render the icon when both icon and type props are not provided', async () => {
76
+ await wrapper.setProps({
77
+ icon: '',
78
+ type: '',
79
+ });
80
+
81
+ const icon = wrapper.find('[data-testid="title-icon"]');
82
+ expect(icon.exists()).toBe(false);
83
+ });
84
+
85
+ it('should render the close icon when showCloseIcon is true', () => {
86
+ const closeIcon = wrapper.find('[data-testid="close-icon"]');
87
+ expect(closeIcon.exists()).toBe(true);
88
+ });
89
+
90
+ it('should not render buttons when primaryButtonProps is not provided', async () => {
91
+ await wrapper.setProps({ primaryButtonProps: undefined });
92
+
93
+ const primaryButton = wrapper.find('[data-testid="primary-button"]');
94
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
95
+ expect(primaryButton.exists()).toBe(false);
96
+ expect(secondaryButton.exists()).toBe(false);
44
97
  });
45
98
  });
46
99
 
47
- describe('persistentHandler', () => {
48
- it('prevents default when persistent is true', () => {
49
- wrapper = mount(ModalDialog, {
100
+ describe('Overlay behavior', () => {
101
+ it('should close the modal when clicking on the overlay if persistent is false', async () => {
102
+ expect(wrapper.props().modelValue).toBe(true);
103
+
104
+ const overlay = wrapper.find('[data-testid="modal-overlay"]');
105
+ await overlay.trigger('click');
106
+
107
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
108
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual([false]);
109
+ expect(wrapper.props().modelValue).toBe(false);
110
+ });
111
+
112
+ it('should not close the modal when clicking on the overlay if persistent is true', async () => {
113
+ await wrapper.setProps({ persistent: true });
114
+
115
+ const overlay = wrapper.find('[data-testid="modal-overlay"]');
116
+ await overlay.trigger('click');
117
+
118
+ expect(wrapper.emitted('update:modelValue')).toBeFalsy();
119
+ expect(wrapper.props().modelValue).toBe(true);
120
+ });
121
+ });
122
+
123
+ describe('Slot rendering', () => {
124
+ it('should render leftSidebar slot when provided', () => {
125
+ const wrapper = mount(ModalDialog, {
126
+ props: {
127
+ modelValue: true,
128
+ },
129
+ slots: {
130
+ leftSidebar:
131
+ '<div data-testid="left-sidebar">Left Sidebar Content</div>',
132
+ },
133
+ });
134
+
135
+ const leftSidebar = wrapper.find('[data-testid="left-sidebar"]');
136
+ expect(leftSidebar.exists()).toBe(true);
137
+ expect(leftSidebar.text()).toBe('Left Sidebar Content');
138
+ });
139
+
140
+ it('should render default slot content', () => {
141
+ const wrapper = mount(ModalDialog, {
50
142
  props: {
51
- title: 'Test Title',
52
143
  modelValue: true,
53
- persistent: true,
54
- primaryButtonProps: { text: 'Confirm' },
55
144
  },
56
- global: {
57
- stubs: [
58
- 'teleport',
59
- 'UnnnicIcon',
60
- 'UnnnicButton',
61
- 'UnnnicDialogContent',
62
- ],
145
+ slots: {
146
+ default: '<div data-testid="default-slot">Default Slot Content</div>',
63
147
  },
64
148
  });
65
149
 
66
- const mockEvent = {
67
- preventDefault: vi.fn(),
68
- target: document.createElement('div'),
69
- };
150
+ const defaultSlot = wrapper.find('[data-testid="default-slot"]');
151
+ expect(defaultSlot.exists()).toBe(true);
152
+ expect(defaultSlot.text()).toBe('Default Slot Content');
153
+ });
154
+ });
155
+
156
+ describe('Buttons actions', () => {
157
+ it('should close the modal when clicking on close icon', async () => {
158
+ const closeIcon = wrapper.find('[data-testid="close-icon"]');
159
+ await closeIcon.trigger('click');
160
+
161
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
162
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual([false]);
163
+ expect(wrapper.props().modelValue).toBe(false);
164
+ });
165
+
166
+ it('should emit primaryButtonClick event when the primary button is clicked', async () => {
167
+ const primaryButton = wrapper.find('[data-testid="primary-button"]');
168
+ await primaryButton.trigger('click');
169
+
170
+ expect(wrapper.emitted('primaryButtonClick')).toBeTruthy();
171
+ });
172
+
173
+ it('should emit secondaryButtonClick event when the secondary button is clicked', async () => {
174
+ await wrapper.setProps({
175
+ secondaryButtonProps: { text: 'Cancel' },
176
+ });
177
+
178
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
179
+ await secondaryButton.trigger('click');
180
+
181
+ expect(wrapper.emitted('secondaryButtonClick')).toBeTruthy();
182
+ });
183
+
184
+ it('should close the modal when the secondary button is clicked and no secondaryButtonClick event is provided', async () => {
185
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
186
+ await secondaryButton.trigger('click');
187
+
188
+ const emittedValue = wrapper.emitted('update:modelValue');
189
+
190
+ expect(emittedValue).toBeTruthy();
191
+ expect(emittedValue[0][0]).toEqual(false);
192
+ });
193
+ });
194
+
195
+ describe('Actions and appearance', () => {
196
+ it('should not render the secondary button when hideSecondaryButton is true', async () => {
197
+ await wrapper.setProps({
198
+ hideSecondaryButton: true,
199
+ });
200
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
201
+ expect(secondaryButton.exists()).toBe(false);
202
+ });
203
+
204
+ it('should apply a divider class to the actions section when showActionsDivider is true', async () => {
205
+ await wrapper.setProps({
206
+ showActionsDivider: true,
207
+ });
208
+
209
+ const actionsSection = wrapper.find('[data-testid="actions-section"]');
210
+ expect(actionsSection.classes()).toContain(
211
+ 'unnnic-modal-dialog__container__actions--divider',
212
+ );
213
+ });
214
+ });
215
+
216
+ describe('Body overflow', () => {
217
+ it('should toggle body overflow based on modal visibility', async () => {
218
+ await wrapper.setProps({ modelValue: false });
219
+ const updateBodyOverflowSpy = vi.spyOn(wrapper.vm, 'updateBodyOverflow');
70
220
 
71
- wrapper.vm.persistentHandler(mockEvent);
221
+ await wrapper.setProps({ modelValue: true });
222
+ expect(updateBodyOverflowSpy).toHaveBeenCalledWith(true);
72
223
 
73
- expect(mockEvent.preventDefault).toHaveBeenCalled();
224
+ await wrapper.setProps({ modelValue: false });
225
+ expect(updateBodyOverflowSpy).toHaveBeenCalledWith(false);
226
+ });
227
+ });
228
+
229
+ describe('Validators', () => {
230
+ describe('type prop validator', () => {
231
+ it('should validate type prop when a valid value is provided', () => {
232
+ const validTypes = ['success', 'warning', 'attention'];
233
+ validTypes.forEach((validType) => {
234
+ expect(ModalDialog.props.type.validate(validType)).toBe(true);
235
+ });
236
+ });
237
+
238
+ it('should invalidate type prop when an invalid value is provided', () => {
239
+ expect(ModalDialog.props.type.validate('invalidType')).toBe(false);
240
+ });
241
+ });
242
+
243
+ describe('size prop validator', () => {
244
+ it('should validate size prop when a valid value is provided', () => {
245
+ const validSizes = ['sm', 'md', 'lg'];
246
+ validSizes.forEach((validSize) => {
247
+ expect(ModalDialog.props.size.validate(validSize)).toBe(true);
248
+ });
249
+ });
250
+
251
+ it('should invalidate size prop when an invalid value is provided', () => {
252
+ expect(ModalDialog.props.size.validate('invalidSize')).toBe(false);
253
+ });
74
254
  });
75
255
  });
76
256
  });
@@ -1,3 +1,24 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`ModalDialog.vue > Elements rendering > matches the snapshot 1`] = `"<unnnic-dialog-content-stub data-v-68ebadeb="" forcemount="false" disableoutsidepointerevents="false" aschild="false" parentclass="unnnic-modal-dialog," class="unnnic-modal-dialog__container" size="medium" data-testid="modal-dialog"></unnnic-dialog-content-stub>"`;
3
+ exports[`ModalDialog.vue > Elements rendering > matches the snapshot 1`] = `
4
+ "<section data-v-68ebadeb="" class="unnnic-modal-dialog" data-testid="modal-dialog">
5
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__overlay" data-testid="modal-overlay"></section>
6
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container unnnic-modal-dialog__container--md" data-testid="modal-container">
7
+ <!--v-if-->
8
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container__body">
9
+ <header data-v-68ebadeb="" class="unnnic-modal-dialog__container__header">
10
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container__title-container">
11
+ <unnnic-icon-stub data-v-68ebadeb="" filled="false" icon="test-icon" clickable="false" size="md" scheme="neutral-darkest" data-testid="title-icon" class="unnnic-modal-dialog__container__title-icon"></unnnic-icon-stub>
12
+ <h1 data-v-68ebadeb="" class="unnnic-modal-dialog__container__title-text" data-testid="title-text">Test Title</h1>
13
+ </section>
14
+ <unnnic-icon-stub data-v-68ebadeb="" filled="false" icon="close" clickable="true" size="md" scheme="neutral-cloudy" data-testid="close-icon"></unnnic-icon-stub>
15
+ </header>
16
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container__content"></section>
17
+ <section data-v-68ebadeb="" data-testid="actions-section" class="unnnic-modal-dialog__container__actions">
18
+ <unnnic-button-stub data-v-68ebadeb="" size="large" text="Cancel" type="tertiary" float="false" iconleft="" iconright="" iconcenter="" iconsfilled="false" disabled="false" loading="false" data-testid="secondary-button" class="unnnic-modal-dialog__container__actions__secondary-button"></unnnic-button-stub>
19
+ <unnnic-button-stub data-v-68ebadeb="" size="large" text="Confirm" type="primary" float="false" iconleft="" iconright="" iconcenter="" iconsfilled="false" disabled="false" loading="false" data-testid="primary-button" class="unnnic-modal-dialog__container__actions__primary-button"></unnnic-button-stub>
20
+ </section>
21
+ </section>
22
+ </section>
23
+ </section>"
24
+ `;
@@ -1,7 +1,12 @@
1
1
  <!-- eslint-disable vue/multi-word-component-names -->
2
2
  <template>
3
3
  <section class="unnnic-radio">
4
- <label :class="['unnnic-radio__input-wrapper', {'unnnic-radio__input-wrapper--disabled': disabled}]">
4
+ <label
5
+ :class="[
6
+ 'unnnic-radio__input-wrapper',
7
+ { 'unnnic-radio__input-wrapper--disabled': disabled },
8
+ ]"
9
+ >
5
10
  <input
6
11
  class="unnnic-radio__input"
7
12
  type="radio"
@@ -12,10 +17,12 @@
12
17
  v-bind="pick($attrs, ['id'])"
13
18
  />
14
19
 
15
- <p :class="[
16
- 'unnnic-radio__label',
17
- { 'unnnic-radio__label--disabled': disabled },
18
- ]">
20
+ <p
21
+ :class="[
22
+ 'unnnic-radio__label',
23
+ { 'unnnic-radio__label--disabled': disabled },
24
+ ]"
25
+ >
19
26
  {{ label }}
20
27
  <slot />
21
28
  </p>
@@ -109,7 +116,6 @@ $radio-size: 21px;
109
116
  cursor: not-allowed;
110
117
  }
111
118
  }
112
-
113
119
 
114
120
  &__input {
115
121
  appearance: none;
@@ -43,7 +43,9 @@ describe('Radio.vue', () => {
43
43
 
44
44
  test('applies disabled class when disabled prop is true', async () => {
45
45
  await wrapper.setProps({ disabled: true });
46
- expect(wrapper.find('.unnnic-radio__label').classes()).toContain('unnnic-radio__label--disabled');
46
+ expect(wrapper.find('.unnnic-radio__label').classes()).toContain(
47
+ 'unnnic-radio__label--disabled',
48
+ );
47
49
  });
48
50
 
49
51
  test('icon changes based on valueName', async () => {