@weni/unnnic-system 3.12.8-alpha-teleports.0 → 3.12.8-alpha.1
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 +1114 -0
- package/README.md +1 -9
- package/dist/{es-2f6793d2.mjs → es-9d6892f7.mjs} +1 -1
- package/dist/{index-799af668.mjs → index-78117c0a.mjs} +9299 -8975
- package/dist/index.d.ts +870 -321
- package/dist/{pt-br-f5121b47.mjs → pt-br-89839646.mjs} +1 -1
- package/dist/style.css +1 -1
- package/dist/unnnic.mjs +156 -154
- package/dist/unnnic.umd.js +33 -33
- package/package.json +1 -1
- 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 +9 -3
- package/src/components/CheckboxGroup/CheckboxGroup.vue +7 -5
- package/src/components/Chip/Chip.vue +1 -1
- package/src/components/DatePicker/DatePicker.vue +1 -11
- package/src/components/Drawer/Drawer.vue +20 -9
- package/src/components/Drawer/__tests__/Drawer.spec.js +11 -9
- package/src/components/Drawer/__tests__/__snapshots__/Drawer.spec.js.snap +9 -9
- package/src/components/EmojiPicker/EmojiPicker.vue +1 -1
- package/src/components/FormElement/FormElement.vue +97 -88
- package/src/components/Input/BaseInput.vue +25 -5
- package/src/components/Input/Input.scss +2 -1
- package/src/components/Input/Input.vue +26 -3
- package/src/components/Input/TextInput.vue +64 -25
- package/src/components/Input/__test__/TextInput.spec.js +1 -1
- package/src/components/Input/__test__/__snapshots__/Input.spec.js.snap +5 -1
- package/src/components/Input/__test__/__snapshots__/TextInput.spec.js.snap +7 -1
- package/src/components/InputDatePicker/InputDatePicker.vue +73 -68
- package/src/components/InputDatePicker/__test__/InputDatePicker.spec.js +24 -31
- package/src/components/ModalDialog/ModalDialog.vue +8 -1
- package/src/components/ModalDialog/__tests__/ModalDialog.spec.js +1 -31
- package/src/components/MultiSelect/MultSelectOption.vue +49 -0
- package/src/components/MultiSelect/__tests__/MultiSelect.spec.js +557 -0
- package/src/components/MultiSelect/__tests__/MultiSelectOption.spec.js +229 -0
- package/src/components/MultiSelect/__tests__/__snapshots__/MultiSelect.spec.js.snap +87 -0
- package/src/components/MultiSelect/__tests__/__snapshots__/MultiSelectOption.spec.js.snap +51 -0
- package/src/components/MultiSelect/index.vue +265 -0
- package/src/components/Radio/Radio.vue +13 -7
- package/src/components/Radio/__test__/Radio.spec.js +3 -1
- package/src/components/RadioGroup/RadioGroup.vue +18 -10
- package/src/components/Select/__tests__/Select.spec.js +422 -0
- package/src/components/Select/__tests__/SelectItem.spec.js +330 -0
- package/src/components/Select/__tests__/__snapshots__/Popover.spec.js.snap +8 -0
- package/src/components/Select/__tests__/__snapshots__/Select.spec.js.snap +71 -0
- package/src/components/Select/__tests__/__snapshots__/SelectItem.spec.js.snap +15 -0
- package/src/components/Select/__tests__/__snapshots__/SelectOption.spec.js.snap +25 -0
- package/src/components/Select/__tests__/__snapshots__/SelectPopover.spec.js.snap +8 -0
- package/src/components/Select/index.vue +308 -0
- package/src/components/Switch/Switch.vue +11 -4
- package/src/components/TemplatePreview/TemplatePreview.vue +30 -27
- package/src/components/TemplatePreview/TemplatePreviewModal.vue +11 -11
- package/src/components/TemplatePreview/types.d.ts +3 -3
- package/src/components/Toast/Toast.vue +13 -9
- package/src/components/Toast/ToastManager.ts +1 -4
- package/src/components/Toast/__tests__/ToastManager.spec.js +6 -10
- package/src/components/ToolTip/ToolTip.vue +1 -1
- package/src/components/index.ts +6 -6
- package/src/components/ui/dialog/DialogContent.vue +5 -5
- package/src/components/ui/drawer/DrawerContent.vue +2 -4
- package/src/components/ui/popover/PopoverContent.vue +2 -4
- package/src/components/ui/popover/PopoverOption.vue +4 -0
- package/src/components/ui/tooltip/TooltipContent.vue +2 -5
- package/src/components/ui/tooltip/TooltipTrigger.vue +4 -2
- package/src/index.ts +2 -9
- package/src/lib/layer-manager.ts +52 -24
- package/src/locales/en.json +3 -1
- package/src/locales/es.json +3 -1
- package/src/locales/pt_br.json +3 -1
- package/src/stories/Input.mdx +3 -0
- package/src/stories/LayerManager.docs.mdx +9 -9
- package/src/stories/LayerManager.stories.js +11 -54
- package/src/stories/ModalDialog.stories.js +0 -95
- package/src/stories/MultiSelect.stories.js +143 -45
- package/src/stories/Select.stories.js +161 -0
- package/src/stories/TemplatePreview.stories.js +27 -27
- package/src/stories/TemplatePreviewModal.stories.js +31 -31
- package/dist/apple-64.png +0 -0
- package/public/apple-64.png +0 -0
- package/src/components/MultiSelect/MultiSelect.vue +0 -297
- package/src/lib/__tests__/teleport-target.spec.ts +0 -73
- package/src/lib/teleport-target.ts +0 -46
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
v-mask="mask"
|
|
5
5
|
v-bind="attributes"
|
|
6
6
|
:value="fullySanitize(modelValue)"
|
|
7
|
-
:class="classes"
|
|
7
|
+
:class="[classes, { focus, 'use-focus-prop': useFocusProp }]"
|
|
8
8
|
:type="nativeType"
|
|
9
|
+
:readonly="readonly"
|
|
9
10
|
/>
|
|
10
11
|
<input
|
|
11
12
|
v-else
|
|
12
13
|
v-bind="attributes"
|
|
13
14
|
:value="fullySanitize(modelValue)"
|
|
14
|
-
:class="classes"
|
|
15
|
+
:class="[classes, { focus, 'use-focus-prop': useFocusProp }]"
|
|
15
16
|
:type="nativeType"
|
|
16
17
|
:maxlength="maxlength"
|
|
18
|
+
:readonly="readonly"
|
|
17
19
|
/>
|
|
18
20
|
</template>
|
|
19
21
|
|
|
@@ -49,15 +51,25 @@ export default {
|
|
|
49
51
|
},
|
|
50
52
|
hasIconLeft: Boolean,
|
|
51
53
|
hasIconRight: Boolean,
|
|
54
|
+
hasClearIcon: Boolean,
|
|
52
55
|
maxlength: {
|
|
53
56
|
type: Number,
|
|
54
57
|
default: null,
|
|
55
58
|
},
|
|
59
|
+
readonly: {
|
|
60
|
+
type: Boolean,
|
|
61
|
+
default: false,
|
|
62
|
+
},
|
|
63
|
+
useFocusProp: {
|
|
64
|
+
type: Boolean,
|
|
65
|
+
default: false,
|
|
66
|
+
},
|
|
67
|
+
focus: {
|
|
68
|
+
type: Boolean,
|
|
69
|
+
default: false,
|
|
70
|
+
},
|
|
56
71
|
},
|
|
57
72
|
emits: ['update:modelValue'],
|
|
58
|
-
data() {
|
|
59
|
-
return {};
|
|
60
|
-
},
|
|
61
73
|
computed: {
|
|
62
74
|
attributes() {
|
|
63
75
|
return {
|
|
@@ -77,6 +89,7 @@ export default {
|
|
|
77
89
|
{
|
|
78
90
|
'input--has-icon-left': this.hasIconLeft,
|
|
79
91
|
'input--has-icon-right': this.hasIconRight,
|
|
92
|
+
'input--has-clear-icon': this.hasClearIcon,
|
|
80
93
|
},
|
|
81
94
|
];
|
|
82
95
|
},
|
|
@@ -117,6 +130,13 @@ export default {
|
|
|
117
130
|
|
|
118
131
|
&.input--has-icon-right {
|
|
119
132
|
padding-right: $unnnic-space-10;
|
|
133
|
+
&.input--has-clear-icon {
|
|
134
|
+
padding-right: $unnnic-space-10 + $unnnic-space-6;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&.input--has-clear-icon {
|
|
139
|
+
padding-right: $unnnic-space-10;
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
&.error {
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
v-bind="$attrs"
|
|
14
14
|
v-model="val"
|
|
15
15
|
class="unnnic-form-input"
|
|
16
|
+
:useFocusProp="useFocusProp"
|
|
17
|
+
:focus="focus"
|
|
16
18
|
:placeholder="placeholder"
|
|
17
19
|
:iconLeft="iconLeft"
|
|
18
20
|
:iconRight="iconRight"
|
|
@@ -25,6 +27,9 @@
|
|
|
25
27
|
:nativeType="nativeType"
|
|
26
28
|
:maxlength="maxlength"
|
|
27
29
|
:disabled="disabled"
|
|
30
|
+
:readonly="readonly"
|
|
31
|
+
:showClear="showClear"
|
|
32
|
+
@clear="$emit('clear')"
|
|
28
33
|
/>
|
|
29
34
|
|
|
30
35
|
<template
|
|
@@ -43,8 +48,8 @@ import UnnnicFormElement from '../FormElement/FormElement.vue';
|
|
|
43
48
|
|
|
44
49
|
export default {
|
|
45
50
|
name: 'UnnnicInput',
|
|
46
|
-
components: {
|
|
47
|
-
TextInput,
|
|
51
|
+
components: {
|
|
52
|
+
TextInput,
|
|
48
53
|
UnnnicFormElement,
|
|
49
54
|
},
|
|
50
55
|
props: {
|
|
@@ -127,8 +132,26 @@ export default {
|
|
|
127
132
|
type: Boolean,
|
|
128
133
|
default: false,
|
|
129
134
|
},
|
|
135
|
+
readonly: {
|
|
136
|
+
type: Boolean,
|
|
137
|
+
default: false,
|
|
138
|
+
},
|
|
139
|
+
useFocusProp: {
|
|
140
|
+
type: Boolean,
|
|
141
|
+
default: false,
|
|
142
|
+
},
|
|
143
|
+
focus: {
|
|
144
|
+
type: Boolean,
|
|
145
|
+
default: false,
|
|
146
|
+
},
|
|
147
|
+
showClear: {
|
|
148
|
+
type: Boolean,
|
|
149
|
+
default: false,
|
|
150
|
+
},
|
|
130
151
|
},
|
|
131
|
-
|
|
152
|
+
|
|
153
|
+
emits: ['update:modelValue', 'clear'],
|
|
154
|
+
|
|
132
155
|
data() {
|
|
133
156
|
return {
|
|
134
157
|
val: this.modelValue,
|
|
@@ -12,9 +12,11 @@
|
|
|
12
12
|
class="input-itself"
|
|
13
13
|
:hasIconLeft="!!iconLeft"
|
|
14
14
|
:hasIconRight="!!iconRight || allowTogglePassword"
|
|
15
|
+
:hasClearIcon="showClear"
|
|
15
16
|
:maxlength="maxlength"
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
:readonly="readonly"
|
|
18
|
+
:useFocusProp="useFocusProp"
|
|
19
|
+
:focus="focus"
|
|
18
20
|
/>
|
|
19
21
|
|
|
20
22
|
<UnnnicIcon
|
|
@@ -27,18 +29,28 @@
|
|
|
27
29
|
@click="onIconLeftClick"
|
|
28
30
|
/>
|
|
29
31
|
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
<section class="icon-right-container">
|
|
33
|
+
<UnnnicIcon
|
|
34
|
+
v-if="showClear"
|
|
35
|
+
class="icon-clear"
|
|
36
|
+
:scheme="iconScheme"
|
|
37
|
+
icon="close"
|
|
38
|
+
size="ant"
|
|
39
|
+
clickable
|
|
40
|
+
@click.stop="onClearClick"
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
<UnnnicIcon
|
|
44
|
+
v-if="iconRightSvg"
|
|
45
|
+
:scheme="iconScheme"
|
|
46
|
+
:icon="iconRightSvg"
|
|
47
|
+
size="ant"
|
|
48
|
+
:clickable="iconRightClickable || allowTogglePassword"
|
|
49
|
+
class="icon-right"
|
|
50
|
+
:class="{ clickable: iconRightClickable || allowTogglePassword }"
|
|
51
|
+
@click="onIconRightClick"
|
|
52
|
+
/>
|
|
53
|
+
</section>
|
|
42
54
|
</div>
|
|
43
55
|
</template>
|
|
44
56
|
|
|
@@ -103,8 +115,24 @@ export default {
|
|
|
103
115
|
type: Boolean,
|
|
104
116
|
default: false,
|
|
105
117
|
},
|
|
118
|
+
readonly: {
|
|
119
|
+
type: Boolean,
|
|
120
|
+
default: false,
|
|
121
|
+
},
|
|
122
|
+
useFocusProp: {
|
|
123
|
+
type: Boolean,
|
|
124
|
+
default: false,
|
|
125
|
+
},
|
|
126
|
+
focus: {
|
|
127
|
+
type: Boolean,
|
|
128
|
+
default: false,
|
|
129
|
+
},
|
|
130
|
+
showClear: {
|
|
131
|
+
type: Boolean,
|
|
132
|
+
default: false,
|
|
133
|
+
},
|
|
106
134
|
},
|
|
107
|
-
emits: ['icon-left-click', 'icon-right-click'],
|
|
135
|
+
emits: ['icon-left-click', 'icon-right-click', 'clear'],
|
|
108
136
|
data() {
|
|
109
137
|
return {
|
|
110
138
|
isFocused: false,
|
|
@@ -128,7 +156,6 @@ export default {
|
|
|
128
156
|
if (this.isDisabled) {
|
|
129
157
|
return 'fg-muted';
|
|
130
158
|
}
|
|
131
|
-
|
|
132
159
|
return 'fg-base';
|
|
133
160
|
},
|
|
134
161
|
|
|
@@ -138,7 +165,7 @@ export default {
|
|
|
138
165
|
},
|
|
139
166
|
|
|
140
167
|
methods: {
|
|
141
|
-
|
|
168
|
+
focusInput() {
|
|
142
169
|
this.$refs['base-input'].$el.focus();
|
|
143
170
|
},
|
|
144
171
|
|
|
@@ -154,6 +181,10 @@ export default {
|
|
|
154
181
|
if (this.iconLeftClickable) this.$emit('icon-left-click');
|
|
155
182
|
},
|
|
156
183
|
|
|
184
|
+
onClearClick() {
|
|
185
|
+
this.$emit('clear');
|
|
186
|
+
},
|
|
187
|
+
|
|
157
188
|
onIconRightClick() {
|
|
158
189
|
if (this.attributes.disabled) return;
|
|
159
190
|
if (this.allowTogglePassword) this.showPassword = !this.showPassword;
|
|
@@ -171,25 +202,33 @@ export default {
|
|
|
171
202
|
}
|
|
172
203
|
|
|
173
204
|
.icon {
|
|
174
|
-
&-left,
|
|
175
|
-
&-right {
|
|
176
|
-
&:not(.clickable) {
|
|
177
|
-
pointer-events: none;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
205
|
&-left {
|
|
182
206
|
position: absolute;
|
|
183
207
|
top: 50%;
|
|
184
208
|
transform: translateY(-50%);
|
|
185
209
|
left: $unnnic-space-4;
|
|
210
|
+
|
|
211
|
+
&:not(.clickable) {
|
|
212
|
+
pointer-events: none;
|
|
213
|
+
}
|
|
186
214
|
}
|
|
187
215
|
|
|
188
|
-
&-right {
|
|
216
|
+
&-right-container {
|
|
189
217
|
position: absolute;
|
|
190
218
|
top: 50%;
|
|
191
219
|
transform: translateY(-50%);
|
|
192
220
|
right: $unnnic-space-4;
|
|
221
|
+
|
|
222
|
+
display: flex;
|
|
223
|
+
align-items: center;
|
|
224
|
+
gap: $unnnic-space-2;
|
|
225
|
+
|
|
226
|
+
.icon-clear {
|
|
227
|
+
cursor: pointer;
|
|
228
|
+
}
|
|
229
|
+
.icon-right:not(.clickable) {
|
|
230
|
+
pointer-events: none;
|
|
231
|
+
}
|
|
193
232
|
}
|
|
194
233
|
}
|
|
195
234
|
</style>
|
|
@@ -129,7 +129,7 @@ describe('TextInput.vue', () => {
|
|
|
129
129
|
|
|
130
130
|
test('focus method calls focus on base input element', () => {
|
|
131
131
|
const focusSpy = vi.spyOn(wrapper.vm.$refs['base-input'].$el, 'focus');
|
|
132
|
-
wrapper.vm.
|
|
132
|
+
wrapper.vm.focusInput();
|
|
133
133
|
|
|
134
134
|
expect(focusSpy).toHaveBeenCalled();
|
|
135
135
|
focusSpy.mockRestore();
|
|
@@ -6,7 +6,11 @@ exports[`Input.vue > matches the snapshot 1`] = `
|
|
|
6
6
|
<p data-v-7f222291="" class="unnnic-label__label">Sample Label</p>
|
|
7
7
|
<!--v-if-->
|
|
8
8
|
</section>
|
|
9
|
-
<div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-form-input" hascloudycolor="false" mask="####-####"><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-form-input input-itself input size-md normal input--has-icon-left input--has-icon-right unnnic-form-input input-itself" hascloudycolor="false" placeholder="Enter text" iconleft="search" iconright="clear" iconleftclickable="true" iconrightclickable="true" type="text" value=""><span data-v-26446d8e="" data-v-a0d36167="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic-icon__size--ant unnnic--clickable icon-left clickable" data-testid="material-icon" translate="no">search</span
|
|
9
|
+
<div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-form-input" hascloudycolor="false" mask="####-####"><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-form-input input-itself input size-md normal input--has-icon-left input--has-icon-right unnnic-form-input input-itself" hascloudycolor="false" placeholder="Enter text" iconleft="search" iconright="clear" iconleftclickable="true" iconrightclickable="true" showclear="false" type="text" value=""><span data-v-26446d8e="" data-v-a0d36167="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic-icon__size--ant unnnic--clickable icon-left clickable" data-testid="material-icon" translate="no">search</span>
|
|
10
|
+
<section data-v-a0d36167="" class="icon-right-container">
|
|
11
|
+
<!--v-if--><span data-v-26446d8e="" data-v-a0d36167="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic-icon__size--ant unnnic--clickable icon-right clickable" data-testid="material-icon" translate="no">clear</span>
|
|
12
|
+
</section>
|
|
13
|
+
</div>
|
|
10
14
|
<section data-v-9f8d6c86="" class="unnnic-form-element__hints-container">
|
|
11
15
|
<section data-v-9f8d6c86="" class="unnnic-form-element__message-container">
|
|
12
16
|
<p data-v-9f8d6c86="" class="unnnic-form-element__message">Error message</p>
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
-
exports[`TextInput.vue > matches the snapshot 1`] = `
|
|
3
|
+
exports[`TextInput.vue > matches the snapshot 1`] = `
|
|
4
|
+
"<div data-v-a0d36167="" class="text-input size--md"><input data-v-86533b41="" data-v-a0d36167="" placeholder="Enter text" iconleft="search" iconright="clear" iconleftclickable="true" iconrightclickable="true" allowtogglepassword="false" showclear="false" class="input-itself input size-md normal input--has-icon-left input--has-icon-right input-itself" type="text" value=""><span data-v-26446d8e="" data-v-a0d36167="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic-icon__size--ant unnnic--clickable icon-left clickable" data-testid="material-icon" translate="no">search</span>
|
|
5
|
+
<section data-v-a0d36167="" class="icon-right-container">
|
|
6
|
+
<!--v-if--><span data-v-26446d8e="" data-v-a0d36167="" class="unnnic-icon material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic-icon__size--ant unnnic--clickable icon-right clickable" data-testid="material-icon" translate="no">clear</span>
|
|
7
|
+
</section>
|
|
8
|
+
</div>"
|
|
9
|
+
`;
|
|
@@ -1,61 +1,51 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@change="emitSelectDate"
|
|
41
|
-
@submit="changeDate"
|
|
42
|
-
/>
|
|
43
|
-
</UnnnicPopoverContent>
|
|
44
|
-
</UnnnicPopover>
|
|
2
|
+
<div
|
|
3
|
+
ref="dropdown"
|
|
4
|
+
:class="['dropdown', { active: showCalendarFilter, 'fill-w': fillW }]"
|
|
5
|
+
>
|
|
6
|
+
<UnnnicInput
|
|
7
|
+
:class="['input', { 'date-picker-input-next': next }]"
|
|
8
|
+
:size="size"
|
|
9
|
+
:iconLeft="iconPosition === 'left' ? 'calendar_month' : undefined"
|
|
10
|
+
:iconRight="iconPosition === 'right' ? 'calendar_month' : undefined"
|
|
11
|
+
hasCloudyColor
|
|
12
|
+
readonly
|
|
13
|
+
:modelValue="overwrittenValue || filterText || ''"
|
|
14
|
+
@focus="showCalendarFilter = true"
|
|
15
|
+
/>
|
|
16
|
+
|
|
17
|
+
<div
|
|
18
|
+
class="dropdown-data"
|
|
19
|
+
:style="{ [position]: '0' }"
|
|
20
|
+
>
|
|
21
|
+
<UnnnicDatePicker
|
|
22
|
+
v-if="showCalendarFilter"
|
|
23
|
+
v-model:equivalentOption="overwrittenValue"
|
|
24
|
+
:type="type"
|
|
25
|
+
:clearLabel="clearText"
|
|
26
|
+
:actionLabel="actionText"
|
|
27
|
+
:months="months"
|
|
28
|
+
:days="days"
|
|
29
|
+
:options="options"
|
|
30
|
+
:periodBaseDate="periodBaseDate"
|
|
31
|
+
:initialStartDate="initialStartDate"
|
|
32
|
+
:initialEndDate="initialEndDate"
|
|
33
|
+
:minDate="minDate"
|
|
34
|
+
:maxDate="maxDate"
|
|
35
|
+
:disableClear="disableClear"
|
|
36
|
+
@change="emitSelectDate"
|
|
37
|
+
@submit="changeDate"
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
45
40
|
</div>
|
|
46
41
|
</template>
|
|
47
42
|
|
|
48
43
|
<script setup lang="ts">
|
|
49
|
-
import { computed, ref } from 'vue';
|
|
44
|
+
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
|
50
45
|
import moment from 'moment';
|
|
51
46
|
|
|
52
47
|
import UnnnicInput from '../Input/Input.vue';
|
|
53
48
|
import UnnnicDatePicker from '../DatePicker/DatePicker.vue';
|
|
54
|
-
import {
|
|
55
|
-
Popover as UnnnicPopover,
|
|
56
|
-
PopoverContent as UnnnicPopoverContent,
|
|
57
|
-
PopoverTrigger as UnnnicPopoverTrigger,
|
|
58
|
-
} from '../ui/popover';
|
|
59
49
|
|
|
60
50
|
defineOptions({
|
|
61
51
|
name: 'UnnnicInputDatePicker',
|
|
@@ -122,11 +112,9 @@ const emit = defineEmits<{
|
|
|
122
112
|
(e: 'selectDate', value: DateRangeValue): void;
|
|
123
113
|
}>();
|
|
124
114
|
|
|
125
|
-
const
|
|
115
|
+
const dropdown = ref<HTMLElement | null>(null);
|
|
116
|
+
const showCalendarFilter = ref(false);
|
|
126
117
|
const overwrittenValue = ref('');
|
|
127
|
-
const popoverAlign = computed<'start' | 'end'>(() =>
|
|
128
|
-
props.position === 'right' ? 'end' : 'start',
|
|
129
|
-
);
|
|
130
118
|
|
|
131
119
|
const filterText = computed(() => {
|
|
132
120
|
const dates: string[] = [];
|
|
@@ -172,12 +160,20 @@ function emitSelectDate(date: { startDate: string; endDate: string }) {
|
|
|
172
160
|
emit('selectDate', formattedDates);
|
|
173
161
|
}
|
|
174
162
|
|
|
163
|
+
function mouseout(event: MouseEvent | { target: EventTarget | null }) {
|
|
164
|
+
if (dropdown.value?.contains(event.target as Node)) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
showCalendarFilter.value = false;
|
|
169
|
+
}
|
|
170
|
+
|
|
175
171
|
function changeDate(value: { startDate: string; endDate: string }) {
|
|
176
172
|
const startDate = value.startDate.replace(/(\d+)-(\d+)-(\d+)/, '$3-$1-$2');
|
|
177
173
|
|
|
178
174
|
const endDate = value.endDate.replace(/(\d+)-(\d+)-(\d+)/, '$3-$1-$2');
|
|
179
175
|
|
|
180
|
-
|
|
176
|
+
showCalendarFilter.value = false;
|
|
181
177
|
|
|
182
178
|
emit('update:model-value', {
|
|
183
179
|
start: startDate
|
|
@@ -187,30 +183,39 @@ function changeDate(value: { startDate: string; endDate: string }) {
|
|
|
187
183
|
});
|
|
188
184
|
}
|
|
189
185
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
</script>
|
|
194
|
-
|
|
195
|
-
<style lang="scss">
|
|
196
|
-
@use '@/assets/scss/unnnic' as *;
|
|
186
|
+
onMounted(() => {
|
|
187
|
+
window.document.body.addEventListener('click', mouseout as any);
|
|
188
|
+
});
|
|
197
189
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
</style>
|
|
190
|
+
onBeforeUnmount(() => {
|
|
191
|
+
window.document.body.removeEventListener('click', mouseout as any);
|
|
192
|
+
});
|
|
193
|
+
</script>
|
|
204
194
|
|
|
205
195
|
<style lang="scss" scoped>
|
|
206
196
|
@use '@/assets/scss/unnnic' as *;
|
|
207
197
|
.fill-w {
|
|
208
198
|
width: 100%;
|
|
209
199
|
}
|
|
210
|
-
|
|
211
200
|
.dropdown {
|
|
201
|
+
position: relative;
|
|
212
202
|
display: inline-block;
|
|
213
203
|
|
|
204
|
+
.dropdown-data {
|
|
205
|
+
position: absolute;
|
|
206
|
+
pointer-events: none;
|
|
207
|
+
display: none;
|
|
208
|
+
top: 100%;
|
|
209
|
+
z-index: 2;
|
|
210
|
+
margin-top: $unnnic-spacing-stack-nano;
|
|
211
|
+
width: max-content;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
&.active .dropdown-data {
|
|
215
|
+
pointer-events: auto;
|
|
216
|
+
display: block;
|
|
217
|
+
}
|
|
218
|
+
|
|
214
219
|
.input {
|
|
215
220
|
display: inline-block;
|
|
216
221
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
4
3
|
import InputDatePicker from '../InputDatePicker.vue';
|
|
5
4
|
|
|
6
5
|
const factory = (props = {}) =>
|
|
@@ -12,7 +11,20 @@ const factory = (props = {}) =>
|
|
|
12
11
|
},
|
|
13
12
|
...props,
|
|
14
13
|
},
|
|
15
|
-
|
|
14
|
+
global: {
|
|
15
|
+
stubs: {
|
|
16
|
+
UnnnicInput: {
|
|
17
|
+
name: 'UnnnicInput',
|
|
18
|
+
template:
|
|
19
|
+
'<input data-testid="input" v-bind="$attrs" @focus="$emit(\'focus\', $event)" />',
|
|
20
|
+
},
|
|
21
|
+
UnnnicDatePicker: {
|
|
22
|
+
name: 'UnnnicDatePicker',
|
|
23
|
+
props: ['minDate', 'maxDate', 'periodBaseDate', 'options'],
|
|
24
|
+
template: '<div data-testid="datepicker"></div>',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
16
28
|
});
|
|
17
29
|
|
|
18
30
|
describe('InputDatePicker.vue', () => {
|
|
@@ -22,12 +34,6 @@ describe('InputDatePicker.vue', () => {
|
|
|
22
34
|
wrapper = factory();
|
|
23
35
|
});
|
|
24
36
|
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
if (wrapper) {
|
|
27
|
-
wrapper.unmount();
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
37
|
it('renders input and does not show datepicker by default', () => {
|
|
32
38
|
expect(wrapper.find('[data-testid="input"]').exists()).toBe(true);
|
|
33
39
|
expect(wrapper.find('[data-testid="datepicker"]').exists()).toBe(false);
|
|
@@ -36,23 +42,13 @@ describe('InputDatePicker.vue', () => {
|
|
|
36
42
|
it('opens datepicker when input receives focus', async () => {
|
|
37
43
|
const input = wrapper.find('[data-testid="input"]');
|
|
38
44
|
await input.trigger('focus');
|
|
39
|
-
await wrapper.vm.$nextTick();
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
true,
|
|
43
|
-
);
|
|
44
|
-
expect(wrapper.vm.isPopoverOpen).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('opens datepicker when input receives click', async () => {
|
|
48
|
-
const input = wrapper.find('[data-testid="input"]');
|
|
49
|
-
await input.trigger('click');
|
|
46
|
+
wrapper.vm.showCalendarFilter = true;
|
|
50
47
|
await wrapper.vm.$nextTick();
|
|
51
48
|
|
|
52
49
|
expect(wrapper.findComponent({ name: 'UnnnicDatePicker' }).exists()).toBe(
|
|
53
50
|
true,
|
|
54
51
|
);
|
|
55
|
-
expect(wrapper.vm.isPopoverOpen).toBe(true);
|
|
56
52
|
});
|
|
57
53
|
|
|
58
54
|
it('computes filterText placeholder when there is no date selected', () => {
|
|
@@ -70,7 +66,6 @@ describe('InputDatePicker.vue', () => {
|
|
|
70
66
|
});
|
|
71
67
|
|
|
72
68
|
expect(withDates.vm.filterText).toBe('01-10-2025 ~ 01-20-2025');
|
|
73
|
-
withDates.unmount();
|
|
74
69
|
});
|
|
75
70
|
|
|
76
71
|
it('computes initialStartDate and initialEndDate for DatePicker', () => {
|
|
@@ -83,11 +78,10 @@ describe('InputDatePicker.vue', () => {
|
|
|
83
78
|
|
|
84
79
|
expect(withDates.vm.initialStartDate).toBe('01 10 2025');
|
|
85
80
|
expect(withDates.vm.initialEndDate).toBe('01 20 2025');
|
|
86
|
-
withDates.unmount();
|
|
87
81
|
});
|
|
88
82
|
|
|
89
83
|
it('emits selectDate with formatted dates when DatePicker emits change', async () => {
|
|
90
|
-
wrapper.vm.
|
|
84
|
+
wrapper.vm.showCalendarFilter = true;
|
|
91
85
|
await wrapper.vm.$nextTick();
|
|
92
86
|
|
|
93
87
|
const datePicker = wrapper.findComponent({ name: 'UnnnicDatePicker' });
|
|
@@ -110,7 +104,7 @@ describe('InputDatePicker.vue', () => {
|
|
|
110
104
|
});
|
|
111
105
|
|
|
112
106
|
it('emits update:model-value and closes dropdown when DatePicker emits submit', async () => {
|
|
113
|
-
wrapper.vm.
|
|
107
|
+
wrapper.vm.showCalendarFilter = true;
|
|
114
108
|
await wrapper.vm.$nextTick();
|
|
115
109
|
|
|
116
110
|
const datePicker = wrapper.findComponent({ name: 'UnnnicDatePicker' });
|
|
@@ -131,7 +125,7 @@ describe('InputDatePicker.vue', () => {
|
|
|
131
125
|
end: '2025-01-20',
|
|
132
126
|
});
|
|
133
127
|
|
|
134
|
-
expect(wrapper.vm.
|
|
128
|
+
expect(wrapper.vm.showCalendarFilter).toBe(false);
|
|
135
129
|
});
|
|
136
130
|
|
|
137
131
|
it('passes minDate, maxDate, options and periodBaseDate down to DatePicker', async () => {
|
|
@@ -143,7 +137,7 @@ describe('InputDatePicker.vue', () => {
|
|
|
143
137
|
};
|
|
144
138
|
|
|
145
139
|
wrapper = factory(props);
|
|
146
|
-
wrapper.vm.
|
|
140
|
+
wrapper.vm.showCalendarFilter = true;
|
|
147
141
|
await wrapper.vm.$nextTick();
|
|
148
142
|
|
|
149
143
|
const datePicker = wrapper.findComponent({ name: 'UnnnicDatePicker' });
|
|
@@ -153,14 +147,13 @@ describe('InputDatePicker.vue', () => {
|
|
|
153
147
|
expect(dpProps.maxDate).toBe(props.maxDate);
|
|
154
148
|
expect(dpProps.periodBaseDate).toBe(props.periodBaseDate);
|
|
155
149
|
expect(dpProps.options).toEqual(props.options);
|
|
156
|
-
expect(dpProps.variant).toBe('popover');
|
|
157
150
|
});
|
|
158
151
|
|
|
159
|
-
it('
|
|
160
|
-
|
|
152
|
+
it('closes dropdown on mouseout when clicking outside', () => {
|
|
153
|
+
wrapper.vm.showCalendarFilter = true;
|
|
161
154
|
|
|
162
|
-
|
|
155
|
+
wrapper.vm.mouseout({ target: document.createElement('div') });
|
|
163
156
|
|
|
164
|
-
|
|
157
|
+
expect(wrapper.vm.showCalendarFilter).toBe(false);
|
|
165
158
|
});
|
|
166
159
|
});
|
|
@@ -178,10 +178,18 @@ export default {
|
|
|
178
178
|
},
|
|
179
179
|
};
|
|
180
180
|
},
|
|
181
|
+
watch: {
|
|
182
|
+
modelValue(value) {
|
|
183
|
+
this.updateBodyOverflow(value);
|
|
184
|
+
},
|
|
185
|
+
},
|
|
181
186
|
methods: {
|
|
182
187
|
close() {
|
|
183
188
|
this.$emit('update:modelValue', false);
|
|
184
189
|
},
|
|
190
|
+
updateBodyOverflow(isHidden) {
|
|
191
|
+
document.body.style.overflow = isHidden ? 'hidden' : '';
|
|
192
|
+
},
|
|
185
193
|
persistentHandler(event) {
|
|
186
194
|
if (this.persistent) {
|
|
187
195
|
event.preventDefault();
|
|
@@ -193,7 +201,6 @@ export default {
|
|
|
193
201
|
|
|
194
202
|
<style lang="scss" scoped>
|
|
195
203
|
@use '@/assets/scss/unnnic' as *;
|
|
196
|
-
|
|
197
204
|
.unnnic-modal-dialog__container {
|
|
198
205
|
&__left-sidebar {
|
|
199
206
|
background-color: $unnnic-color-neutral-black;
|