@weni/unnnic-system 3.22.0 → 3.23.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weni/unnnic-system",
3
- "version": "3.22.0",
3
+ "version": "3.23.0",
4
4
  "type": "commonjs",
5
5
  "files": [
6
6
  "dist",
@@ -28,12 +28,14 @@
28
28
  <slot name="leftSidebar" />
29
29
  </section>
30
30
  <UnnnicDialogHeader
31
- v-if="title"
31
+ v-if="title || $slots.title"
32
32
  :closeButton="showCloseIcon"
33
33
  :type="type"
34
34
  >
35
35
  <UnnnicDialogTitle>
36
- {{ title }}
36
+ <slot name="title">
37
+ {{ title }}
38
+ </slot>
37
39
  </UnnnicDialogTitle>
38
40
  </UnnnicDialogHeader>
39
41
  <section class="unnnic-modal-dialog__container__content">
@@ -44,6 +44,89 @@ describe('ModalDialog.vue', () => {
44
44
  });
45
45
  });
46
46
 
47
+ describe('Title slot', () => {
48
+ const titleSlotStubs = {
49
+ teleport: true,
50
+ UnnnicIcon: true,
51
+ UnnnicButton: true,
52
+ DialogPortal: { template: '<div><slot /></div>' },
53
+ DialogOverlay: true,
54
+ };
55
+
56
+ it('renders the header when the title slot is provided without a title prop', () => {
57
+ wrapper = mount(ModalDialog, {
58
+ props: {
59
+ modelValue: true,
60
+ primaryButtonProps: { text: 'Confirm' },
61
+ },
62
+ slots: {
63
+ title:
64
+ '<span class="custom-title">Custom <strong>Title</strong></span>',
65
+ },
66
+ global: {
67
+ stubs: titleSlotStubs,
68
+ },
69
+ });
70
+
71
+ expect(wrapper.find('.custom-title').exists()).toBe(true);
72
+ expect(wrapper.find('.custom-title').html()).toContain(
73
+ '<strong>Title</strong>',
74
+ );
75
+ });
76
+
77
+ it('does not render the header when neither title prop nor title slot is provided', () => {
78
+ wrapper = mount(ModalDialog, {
79
+ props: {
80
+ modelValue: true,
81
+ primaryButtonProps: { text: 'Confirm' },
82
+ },
83
+ global: {
84
+ stubs: titleSlotStubs,
85
+ },
86
+ });
87
+
88
+ expect(
89
+ wrapper.findComponent({ name: 'UnnnicDialogHeader' }).exists(),
90
+ ).toBe(false);
91
+ });
92
+
93
+ it('renders the title prop text when no title slot is provided', () => {
94
+ wrapper = mount(ModalDialog, {
95
+ props: {
96
+ title: 'Test Title',
97
+ modelValue: true,
98
+ primaryButtonProps: { text: 'Confirm' },
99
+ },
100
+ global: {
101
+ stubs: titleSlotStubs,
102
+ },
103
+ });
104
+
105
+ expect(wrapper.findComponent({ name: 'UnnnicDialogTitle' }).text()).toBe(
106
+ 'Test Title',
107
+ );
108
+ });
109
+
110
+ it('renders the title slot content instead of the title prop when both are provided', () => {
111
+ wrapper = mount(ModalDialog, {
112
+ props: {
113
+ title: 'Prop Title',
114
+ modelValue: true,
115
+ primaryButtonProps: { text: 'Confirm' },
116
+ },
117
+ slots: {
118
+ title: '<span class="slot-title">Slot Title</span>',
119
+ },
120
+ global: {
121
+ stubs: titleSlotStubs,
122
+ },
123
+ });
124
+
125
+ expect(wrapper.find('.slot-title').exists()).toBe(true);
126
+ expect(wrapper.find('.slot-title').text()).toBe('Slot Title');
127
+ });
128
+ });
129
+
47
130
  describe('persistentHandler', () => {
48
131
  it('prevents default when persistent is true', () => {
49
132
  wrapper = mount(ModalDialog, {
@@ -4,6 +4,7 @@ import UnnnicLabel from '../components/Label/Label.vue';
4
4
  import UnnnicInputDatePicker from '../components/InputDatePicker/InputDatePicker.vue';
5
5
  import UnnnicSwitch from '../components/Switch/Switch.vue';
6
6
  import UnnnicButton from '../components/Button/Button.vue';
7
+ import UnnnicTag from '../components/Tag/Tag.vue';
7
8
 
8
9
  import { action } from '@storybook/addon-actions';
9
10
  import iconsList from '../utils/iconList';
@@ -356,3 +357,92 @@ WithDatePicker.args = {
356
357
  text: 'Cancel',
357
358
  },
358
359
  };
360
+
361
+ const TemplateCustomTitleSlot = (args) => ({
362
+ components: { UnnnicModalDialog, UnnnicTag, UnnnicButton },
363
+ setup() {
364
+ const updateModelValue = (value) => {
365
+ action('update:modelValue')(value);
366
+ args.modelValue = value;
367
+ };
368
+ return { args, updateModelValue };
369
+ },
370
+ template: `
371
+ <div>
372
+ <button @click="updateModelValue(true)">Open Modal</button>
373
+ <unnnic-modal-dialog
374
+ v-bind="args"
375
+ @primaryButtonClick="primaryButtonClick"
376
+ @secondaryButtonClick="secondaryButtonClick"
377
+ @update:modelValue="updateModelValue"
378
+ >
379
+ <template #title>
380
+ <span style="display: flex; align-items: center; gap: 8px;">
381
+ Custom Title
382
+ <UnnnicTag text="New" scheme="feedback-green" />
383
+ </span>
384
+ </template>
385
+ <p style="margin: 0;">This modal uses the <strong>title slot</strong> instead of the title prop, allowing you to add custom components like tags, buttons, or icons inside the title area.</p>
386
+ </unnnic-modal-dialog>
387
+ </div>
388
+ `,
389
+ methods: {
390
+ primaryButtonClick: action('primaryButtonClick'),
391
+ secondaryButtonClick: action('secondaryButtonClick'),
392
+ },
393
+ });
394
+
395
+ export const CustomTitleSlot = TemplateCustomTitleSlot.bind({});
396
+ CustomTitleSlot.args = {
397
+ type: '',
398
+ showCloseIcon: true,
399
+ primaryButtonProps: {
400
+ text: 'Confirm',
401
+ },
402
+ };
403
+
404
+ const TemplateCustomTitleWithButtons = (args) => ({
405
+ components: { UnnnicModalDialog, UnnnicButton },
406
+ setup() {
407
+ const updateModelValue = (value) => {
408
+ action('update:modelValue')(value);
409
+ args.modelValue = value;
410
+ };
411
+ return { args, updateModelValue };
412
+ },
413
+ template: `
414
+ <div>
415
+ <button @click="updateModelValue(true)">Open Modal</button>
416
+ <unnnic-modal-dialog
417
+ v-bind="args"
418
+ @primaryButtonClick="primaryButtonClick"
419
+ @secondaryButtonClick="secondaryButtonClick"
420
+ @update:modelValue="updateModelValue"
421
+ >
422
+ <template #title>
423
+ <span style="display: flex; align-items: center; gap: 8px;">
424
+ Settings
425
+ <UnnnicButton type="tertiary" iconCenter="help" size="small" />
426
+ </span>
427
+ </template>
428
+ <p style="margin: 0;">This modal demonstrates a title with an inline help button using the <strong>title slot</strong>.</p>
429
+ </unnnic-modal-dialog>
430
+ </div>
431
+ `,
432
+ methods: {
433
+ primaryButtonClick: action('primaryButtonClick'),
434
+ secondaryButtonClick: action('secondaryButtonClick'),
435
+ },
436
+ });
437
+
438
+ export const CustomTitleWithButton = TemplateCustomTitleWithButtons.bind({});
439
+ CustomTitleWithButton.args = {
440
+ type: '',
441
+ showCloseIcon: true,
442
+ primaryButtonProps: {
443
+ text: 'Save',
444
+ },
445
+ secondaryButtonProps: {
446
+ text: 'Cancel',
447
+ },
448
+ };