@weni/unnnic-system 3.12.6-alpha-teleports.0 → 3.12.6
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/.vscode/extensions.json +3 -0
- package/CHANGELOG.md +1074 -0
- package/README.md +1 -9
- package/dist/{es-ebc7770b.mjs → es-e7dc92a2.mjs} +1 -1
- package/dist/{index-f117a889.mjs → index-84ade580.mjs} +51079 -53907
- package/dist/index.d.ts +1363 -4701
- package/dist/{pt-br-b1a08da0.mjs → pt-br-51fd679a.mjs} +1 -1
- package/dist/style.css +1 -1
- package/dist/unnnic.mjs +206 -234
- package/dist/unnnic.umd.js +44 -48
- package/package.json +2 -3
- package/src/assets/scss/tailwind.scss +0 -8
- package/src/components/Alert/__tests__/__snapshots__/Alert.spec.js.snap +1 -1
- package/src/components/ChartFunnel/DefaultFunnel/ChartDefaultFunnelBase.vue +1 -2
- package/src/components/ChartFunnel/SvgFunnel/ChartFunnelTwoRows.vue +60 -61
- package/src/components/Checkbox/Checkbox.vue +8 -2
- package/src/components/CheckboxGroup/CheckboxGroup.vue +7 -5
- package/src/components/Chip/Chip.vue +1 -1
- package/src/components/Drawer/Drawer.vue +270 -180
- package/src/components/Drawer/__tests__/Drawer.spec.js +43 -32
- package/src/components/Drawer/__tests__/__snapshots__/Drawer.spec.js.snap +19 -18
- package/src/components/FormElement/FormElement.vue +96 -87
- package/src/components/Input/Input.vue +2 -2
- package/src/components/ModalDialog/ModalDialog.vue +154 -63
- package/src/components/ModalDialog/__tests__/ModalDialog.spec.js +221 -11
- package/src/components/ModalDialog/__tests__/__snapshots__/ModalDialog.spec.js.snap +22 -1
- package/src/components/Radio/Radio.vue +12 -6
- package/src/components/Radio/__test__/Radio.spec.js +3 -1
- package/src/components/RadioGroup/RadioGroup.vue +18 -10
- package/src/components/Switch/Switch.vue +10 -3
- package/src/components/Tab/__test__/__snapshots__/Tab.spec.js.snap +1 -3
- package/src/components/TemplatePreview/TemplatePreview.vue +28 -25
- package/src/components/TemplatePreview/TemplatePreviewModal.vue +10 -10
- package/src/components/TemplatePreview/types.d.ts +3 -3
- package/src/components/Toast/Toast.vue +1 -4
- package/src/components/Toast/ToastManager.ts +1 -4
- package/src/components/Toast/__tests__/ToastManager.spec.js +6 -10
- package/src/components/ToolTip/ToolTip.vue +177 -25
- package/src/components/ToolTip/__tests__/ToolTip.spec.js +61 -339
- package/src/components/index.ts +0 -56
- package/src/components/ui/popover/PopoverContent.vue +3 -7
- package/src/components/ui/popover/PopoverTrigger.vue +1 -5
- package/src/index.ts +2 -9
- package/src/stories/Drawer.stories.js +1 -1
- package/src/stories/ModalDialog.mdx +0 -3
- package/src/stories/ModalDialog.stories.js +1 -1
- package/src/stories/TemplatePreview.stories.js +27 -27
- package/src/stories/TemplatePreviewModal.stories.js +31 -31
- package/src/components/ui/dialog/Dialog.vue +0 -19
- package/src/components/ui/dialog/DialogClose.vue +0 -29
- package/src/components/ui/dialog/DialogContent.vue +0 -140
- package/src/components/ui/dialog/DialogFooter.vue +0 -50
- package/src/components/ui/dialog/DialogHeader.vue +0 -83
- package/src/components/ui/dialog/DialogTitle.vue +0 -38
- package/src/components/ui/dialog/DialogTrigger.vue +0 -16
- package/src/components/ui/dialog/index.ts +0 -7
- package/src/components/ui/drawer/Drawer.vue +0 -27
- package/src/components/ui/drawer/DrawerClose.vue +0 -31
- package/src/components/ui/drawer/DrawerContent.vue +0 -113
- package/src/components/ui/drawer/DrawerDescription.vue +0 -40
- package/src/components/ui/drawer/DrawerFooter.vue +0 -38
- package/src/components/ui/drawer/DrawerHeader.vue +0 -57
- package/src/components/ui/drawer/DrawerOverlay.vue +0 -33
- package/src/components/ui/drawer/DrawerTitle.vue +0 -37
- package/src/components/ui/drawer/DrawerTrigger.vue +0 -31
- package/src/components/ui/drawer/index.ts +0 -10
- package/src/components/ui/tooltip/Tooltip.vue +0 -21
- package/src/components/ui/tooltip/TooltipContent.vue +0 -77
- package/src/components/ui/tooltip/TooltipTrigger.vue +0 -24
- package/src/components/ui/tooltip/index.ts +0 -3
- package/src/lib/__tests__/teleport-target.spec.ts +0 -73
- package/src/lib/layer-manager.ts +0 -64
- package/src/lib/teleport-target.ts +0 -46
- package/src/stories/Dialog.stories.js +0 -832
- package/src/stories/DrawerNext.stories.js +0 -611
- package/src/stories/LayerManager.docs.mdx +0 -40
- package/src/stories/LayerManager.stories.js +0 -407
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
|
-
import { describe, it } 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,16 +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-
|
|
42
|
+
const modalContainer = wrapper.find('[data-testid="modal-container"]');
|
|
43
|
+
const defaultClass = 'unnnic-modal-dialog__container';
|
|
36
44
|
|
|
37
|
-
expect(modalContainer.
|
|
45
|
+
expect(modalContainer.classes()).toContain(defaultClass + '--md');
|
|
38
46
|
|
|
39
47
|
await wrapper.setProps({ size: 'lg' });
|
|
40
|
-
expect(modalContainer.
|
|
48
|
+
expect(modalContainer.classes()).toContain(defaultClass + '--lg');
|
|
41
49
|
|
|
42
50
|
await wrapper.setProps({ size: 'sm' });
|
|
43
|
-
expect(modalContainer.
|
|
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);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
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, {
|
|
142
|
+
props: {
|
|
143
|
+
modelValue: true,
|
|
144
|
+
},
|
|
145
|
+
slots: {
|
|
146
|
+
default: '<div data-testid="default-slot">Default Slot Content</div>',
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
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');
|
|
220
|
+
|
|
221
|
+
await wrapper.setProps({ modelValue: true });
|
|
222
|
+
expect(updateBodyOverflowSpy).toHaveBeenCalledWith(true);
|
|
223
|
+
|
|
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
|
+
});
|
|
44
254
|
});
|
|
45
255
|
});
|
|
46
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`] = `
|
|
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
|
|
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
|
|
16
|
-
|
|
17
|
-
|
|
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(
|
|
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 () => {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<section
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
<section
|
|
3
|
+
:class="[
|
|
4
|
+
'unnnic-radio-group__container',
|
|
5
|
+
`unnnic-radio-group--state-${state}`,
|
|
6
|
+
]"
|
|
7
|
+
>
|
|
6
8
|
<UnnnicLabel
|
|
7
9
|
v-if="label"
|
|
8
10
|
:label="label"
|
|
@@ -68,11 +70,14 @@ const emit = defineEmits(['update:modelValue']);
|
|
|
68
70
|
|
|
69
71
|
const contextModelValue = ref(props.modelValue);
|
|
70
72
|
|
|
71
|
-
watch(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
watch(
|
|
74
|
+
() => props.modelValue,
|
|
75
|
+
(newVal) => {
|
|
76
|
+
if (newVal !== contextModelValue.value) {
|
|
77
|
+
contextModelValue.value = newVal;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
);
|
|
76
81
|
|
|
77
82
|
watch(contextModelValue, (newVal) => {
|
|
78
83
|
if (newVal !== props.modelValue) {
|
|
@@ -81,7 +86,10 @@ watch(contextModelValue, (newVal) => {
|
|
|
81
86
|
});
|
|
82
87
|
|
|
83
88
|
const computedName = computed(() => {
|
|
84
|
-
return
|
|
89
|
+
return (
|
|
90
|
+
props.name ||
|
|
91
|
+
`unnnic-radio-group-${Math.random().toString(36).substring(2, 15)}`
|
|
92
|
+
);
|
|
85
93
|
});
|
|
86
94
|
|
|
87
95
|
provide('contextModelValue', contextModelValue);
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
class="unnnic-switch__label"
|
|
9
9
|
/>
|
|
10
10
|
|
|
11
|
-
<label
|
|
11
|
+
<label
|
|
12
|
+
:class="[
|
|
13
|
+
'unnnic-switch__input-wrapper',
|
|
14
|
+
{ 'unnnic-switch__input-wrapper--disabled': disabled },
|
|
15
|
+
]"
|
|
16
|
+
>
|
|
12
17
|
<input
|
|
13
18
|
class="unnnic-switch__input"
|
|
14
19
|
type="checkbox"
|
|
@@ -78,7 +83,7 @@ export default {
|
|
|
78
83
|
type: String,
|
|
79
84
|
default: '',
|
|
80
85
|
},
|
|
81
|
-
|
|
86
|
+
|
|
82
87
|
helper: {
|
|
83
88
|
type: String,
|
|
84
89
|
default: '',
|
|
@@ -176,7 +181,9 @@ $switch-height: 20px;
|
|
|
176
181
|
background-repeat: no-repeat;
|
|
177
182
|
background-position: 4px center;
|
|
178
183
|
|
|
179
|
-
transition:
|
|
184
|
+
transition:
|
|
185
|
+
120ms linear background-position,
|
|
186
|
+
120ms linear background-color;
|
|
180
187
|
|
|
181
188
|
cursor: pointer;
|
|
182
189
|
|
|
@@ -4,9 +4,7 @@ exports[`Tab.vue > matches the snapshot 1`] = `
|
|
|
4
4
|
"<div data-v-b4e39fac="" class="tab size-md">
|
|
5
5
|
<header data-v-b4e39fac="" class="tab-header">
|
|
6
6
|
<ul data-v-b4e39fac="" class="tab-content">
|
|
7
|
-
<li data-v-b4e39fac="" class="tab-head">tab1<div data-v-
|
|
8
|
-
<!--teleport start-->
|
|
9
|
-
<!--teleport end-->
|
|
7
|
+
<li data-v-b4e39fac="" class="tab-head">tab1<div data-v-bf0cf546="" data-v-b4e39fac="" class="unnnic-tooltip"><span data-v-26446d8e="" data-v-b4e39fac="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--sm unnnic-icon__size--sm" data-testid="material-icon" translate="no">help</span><span data-v-bf0cf546="" class="unnnic-tooltip-label unnnic-tooltip-label-bottom" data-testid="tooltip-label" style="left: 0px; top: 8px;">Tooltip text <br data-v-bf0cf546=""><!--v-if--></span></div>
|
|
10
8
|
</li>
|
|
11
9
|
<li data-v-b4e39fac="" class="tab-head tab-head--active">tab2
|
|
12
10
|
<!--v-if-->
|
|
@@ -75,7 +75,10 @@
|
|
|
75
75
|
{{ template?.footer }}
|
|
76
76
|
</footer>
|
|
77
77
|
</section>
|
|
78
|
-
<footer
|
|
78
|
+
<footer
|
|
79
|
+
v-if="hasButtons"
|
|
80
|
+
class="unnnic-template-preview__buttons"
|
|
81
|
+
>
|
|
79
82
|
<section
|
|
80
83
|
v-for="(button, index) in template?.buttons"
|
|
81
84
|
:key="`button-${index}`"
|
|
@@ -96,15 +99,15 @@
|
|
|
96
99
|
</template>
|
|
97
100
|
|
|
98
101
|
<script lang="ts" setup>
|
|
99
|
-
import { computed } from
|
|
102
|
+
import { computed } from 'vue';
|
|
100
103
|
|
|
101
|
-
import type { Template } from
|
|
104
|
+
import type { Template } from './types';
|
|
102
105
|
|
|
103
|
-
import imagePreview from
|
|
104
|
-
import documentPreview from
|
|
105
|
-
import videoPreview from
|
|
106
|
+
import imagePreview from '../../assets/img/previews/image-preview.png';
|
|
107
|
+
import documentPreview from '../../assets/img/previews/doc-preview.png';
|
|
108
|
+
import videoPreview from '../../assets/img/previews/video-preview.png';
|
|
106
109
|
|
|
107
|
-
import UnnnicIcon from
|
|
110
|
+
import UnnnicIcon from '../Icon.vue';
|
|
108
111
|
|
|
109
112
|
interface Props {
|
|
110
113
|
template?: Template | null;
|
|
@@ -115,30 +118,30 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
const hasHeader = computed(
|
|
118
|
-
() => props.template?.header && props.template.header.type
|
|
121
|
+
() => props.template?.header && props.template.header.type,
|
|
119
122
|
);
|
|
120
123
|
const hasHeaderMedia = computed(
|
|
121
|
-
() => !!props.template?.header && props.template.header.type ===
|
|
124
|
+
() => !!props.template?.header && props.template.header.type === 'MEDIA',
|
|
122
125
|
);
|
|
123
126
|
const hasBody = computed(
|
|
124
|
-
() => !!props.template?.body && props.template.body.length > 0
|
|
127
|
+
() => !!props.template?.body && props.template.body.length > 0,
|
|
125
128
|
);
|
|
126
129
|
const hasFooter = computed(
|
|
127
|
-
() => !!props.template?.footer && props.template.footer.length > 0
|
|
130
|
+
() => !!props.template?.footer && props.template.footer.length > 0,
|
|
128
131
|
);
|
|
129
132
|
const hasButtons = computed(
|
|
130
|
-
() => !!props.template?.buttons && props.template.buttons.length > 0
|
|
133
|
+
() => !!props.template?.buttons && props.template.buttons.length > 0,
|
|
131
134
|
);
|
|
132
135
|
const parsedBody = computed(() => {
|
|
133
|
-
if (!hasBody.value) return
|
|
136
|
+
if (!hasBody.value) return '';
|
|
134
137
|
|
|
135
138
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
136
139
|
const result = props
|
|
137
|
-
.template!.body!.replaceAll(
|
|
138
|
-
.replaceAll(/(?:\*)([^*<\n]+)(?:\*)/g,
|
|
139
|
-
.replaceAll(/(?:_)([^_<\n]+)(?:_)/g,
|
|
140
|
-
.replaceAll(/(?:~)([^~<\n]+)(?:~)/g,
|
|
141
|
-
.replaceAll(/(?:```)([^```<\n]+)(?:```)/g,
|
|
140
|
+
.template!.body!.replaceAll('\n', '<br/>')
|
|
141
|
+
.replaceAll(/(?:\*)([^*<\n]+)(?:\*)/g, '<strong>$1</strong>')
|
|
142
|
+
.replaceAll(/(?:_)([^_<\n]+)(?:_)/g, '<i>$1</i>')
|
|
143
|
+
.replaceAll(/(?:~)([^~<\n]+)(?:~)/g, '<s>$1</s>')
|
|
144
|
+
.replaceAll(/(?:```)([^```<\n]+)(?:```)/g, '<tt>$1</tt>')
|
|
142
145
|
.replaceAll(/{{.*?}}/g, (match) => `<strong>${match}</strong>`);
|
|
143
146
|
|
|
144
147
|
return result;
|
|
@@ -146,19 +149,19 @@ const parsedBody = computed(() => {
|
|
|
146
149
|
|
|
147
150
|
const getButtonIcon = (buttonType) => {
|
|
148
151
|
const buttonMapper = {
|
|
149
|
-
PHONE_NUMBER:
|
|
150
|
-
URL:
|
|
151
|
-
COPY_CODE:
|
|
152
|
-
FLOW:
|
|
153
|
-
QUICK_REPLY:
|
|
152
|
+
PHONE_NUMBER: 'phone',
|
|
153
|
+
URL: 'open_in_new',
|
|
154
|
+
COPY_CODE: 'content_copy',
|
|
155
|
+
FLOW: '',
|
|
156
|
+
QUICK_REPLY: 'reply',
|
|
154
157
|
};
|
|
155
158
|
|
|
156
|
-
return buttonMapper[buttonType] ||
|
|
159
|
+
return buttonMapper[buttonType] || '';
|
|
157
160
|
};
|
|
158
161
|
</script>
|
|
159
162
|
|
|
160
163
|
<style lang="scss" scoped>
|
|
161
|
-
@use
|
|
164
|
+
@use '@/assets/scss/unnnic' as *;
|
|
162
165
|
|
|
163
166
|
.unnnic-template-preview {
|
|
164
167
|
display: flex;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<UnnnicModalDialog
|
|
3
|
-
:
|
|
3
|
+
:modelValue="modelValue"
|
|
4
4
|
@update:modelValue="$event === false && $emit('close')"
|
|
5
5
|
:title="defaultTranslations.title[props.locale]"
|
|
6
|
-
:
|
|
6
|
+
:showCloseIcon="true"
|
|
7
7
|
class="unnnic-template-preview-modal"
|
|
8
8
|
>
|
|
9
9
|
<UnnnicTemplatePreview :template="template" />
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
13
|
<script lang="ts" setup>
|
|
14
|
-
import UnnnicTemplatePreview from
|
|
15
|
-
import UnnnicModalDialog from
|
|
14
|
+
import UnnnicTemplatePreview from './TemplatePreview.vue';
|
|
15
|
+
import UnnnicModalDialog from '../ModalDialog/ModalDialog.vue';
|
|
16
16
|
|
|
17
|
-
import type { Template } from
|
|
17
|
+
import type { Template } from './types';
|
|
18
18
|
|
|
19
19
|
const defaultTranslations = {
|
|
20
20
|
title: {
|
|
21
|
-
|
|
22
|
-
en:
|
|
23
|
-
es:
|
|
21
|
+
'pt-br': 'Visualizar modelo',
|
|
22
|
+
en: 'Template preview',
|
|
23
|
+
es: 'Vista previa de plantilla',
|
|
24
24
|
},
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -31,7 +31,7 @@ interface Props {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const props = withDefaults(defineProps<Props>(), {
|
|
34
|
-
locale:
|
|
34
|
+
locale: 'en',
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
defineEmits<{
|
|
@@ -40,7 +40,7 @@ defineEmits<{
|
|
|
40
40
|
</script>
|
|
41
41
|
|
|
42
42
|
<style lang="scss" scoped>
|
|
43
|
-
@use
|
|
43
|
+
@use '@/assets/scss/unnnic' as *;
|
|
44
44
|
|
|
45
45
|
:deep(.unnnic-modal-dialog__container__content) {
|
|
46
46
|
display: flex;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export interface Template {
|
|
2
2
|
header: {
|
|
3
|
-
type:
|
|
4
|
-
mediaType?:
|
|
3
|
+
type: 'TEXT' | 'MEDIA';
|
|
4
|
+
mediaType?: 'IMAGE' | 'VIDEO' | 'DOCUMENT';
|
|
5
5
|
text?: string | null;
|
|
6
6
|
src?: string | null;
|
|
7
7
|
};
|
|
8
8
|
body?: string;
|
|
9
9
|
footer?: string;
|
|
10
10
|
buttons?: Array<{
|
|
11
|
-
type:
|
|
11
|
+
type: 'QUICK_REPLY' | 'PHONE_NUMBER';
|
|
12
12
|
text: string;
|
|
13
13
|
countryCode?: string;
|
|
14
14
|
phoneNumber?: string;
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
:role="type === 'error' ? 'alert' : 'status'"
|
|
12
12
|
:aria-live="type === 'error' ? 'assertive' : 'polite'"
|
|
13
13
|
data-testid="toast"
|
|
14
|
-
:style="{ zIndex: toastZIndex }"
|
|
15
14
|
>
|
|
16
15
|
<section
|
|
17
16
|
class="unnnic-toast__content"
|
|
@@ -75,7 +74,6 @@ import { ref, computed, onMounted, onUnmounted } from 'vue';
|
|
|
75
74
|
|
|
76
75
|
import UnnnicIcon from '@/components/Icon.vue';
|
|
77
76
|
import UnnnicButton from '@/components/Button/Button.vue';
|
|
78
|
-
import { useLayerZIndex } from '@/lib/layer-manager';
|
|
79
77
|
|
|
80
78
|
import type { ToastProps, ToastEmits } from './types';
|
|
81
79
|
import type { SchemeColor } from '@/types/scheme-colors';
|
|
@@ -111,8 +109,6 @@ const typeConfig = computed(() => {
|
|
|
111
109
|
};
|
|
112
110
|
});
|
|
113
111
|
|
|
114
|
-
const toastZIndex = useLayerZIndex();
|
|
115
|
-
|
|
116
112
|
const handleClose = () => {
|
|
117
113
|
isVisible.value = false;
|
|
118
114
|
emit('close');
|
|
@@ -156,6 +152,7 @@ onUnmounted(() => {
|
|
|
156
152
|
position: fixed;
|
|
157
153
|
bottom: $unnnic-space-4;
|
|
158
154
|
right: $unnnic-space-4;
|
|
155
|
+
z-index: 9999;
|
|
159
156
|
|
|
160
157
|
display: flex;
|
|
161
158
|
align-items: flex-end;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createApp } from 'vue';
|
|
2
|
-
import { getTeleportContainer } from '@/lib/teleport-target';
|
|
3
2
|
import Toast from './Toast.vue';
|
|
4
3
|
import type {
|
|
5
4
|
ToastProps,
|
|
@@ -21,9 +20,7 @@ class ToastManager implements ToastManager {
|
|
|
21
20
|
this.container = document.createElement('div');
|
|
22
21
|
this.container.setAttribute('unnnic-toast-container', 'true');
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
host?.appendChild(this.container);
|
|
26
|
-
|
|
23
|
+
document.body.appendChild(this.container);
|
|
27
24
|
return this.container;
|
|
28
25
|
}
|
|
29
26
|
|