@weni/unnnic-system 3.11.1-alpha.2 → 3.11.1-alpha.4

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 (27) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/components/DatePicker/DatePicker.vue.d.ts +69 -249
  3. package/dist/components/DatePicker/DatePicker.vue.d.ts.map +1 -1
  4. package/dist/components/InputDatePicker/InputDatePicker.vue.d.ts +47 -911
  5. package/dist/components/InputDatePicker/InputDatePicker.vue.d.ts.map +1 -1
  6. package/dist/components/Select/SelectItem.vue.d.ts +1 -1
  7. package/dist/components/SelectSmart/SelectSmart.vue.d.ts +1 -1
  8. package/dist/components/SelectSmart/SelectSmartOption.vue.d.ts +1 -1
  9. package/dist/components/Sidebar/SidebarItem.vue.d.ts +2 -2
  10. package/dist/{es-2f0d1dd1.mjs → es-fc643bdb.mjs} +1 -1
  11. package/dist/{index-7d496127.mjs → index-4601aaf4.mjs} +9037 -9104
  12. package/dist/{pt-br-ec24bd23.mjs → pt-br-0b82e6d2.mjs} +1 -1
  13. package/dist/style.css +1 -1
  14. package/dist/unnnic.mjs +1 -1
  15. package/dist/unnnic.umd.js +42 -42
  16. package/package.json +1 -1
  17. package/src/components/DatePicker/DatePicker.vue +628 -516
  18. package/src/components/DatePicker/__tests__/DatePicker.spec.js +227 -0
  19. package/src/components/Drawer/__tests__/Drawer.spec.js +11 -15
  20. package/src/components/Drawer/__tests__/__snapshots__/Drawer.spec.js.snap +9 -9
  21. package/src/components/InputDatePicker/InputDatePicker.vue +149 -183
  22. package/src/components/InputDatePicker/__test__/InputDatePicker.spec.js +159 -0
  23. package/src/components/Tab/__test__/__snapshots__/Tab.spec.js.snap +1 -1
  24. package/src/stories/DatePicker.stories.js +71 -0
  25. package/src/stories/InputDatePicker.stories.js +22 -0
  26. package/dist/components/index.d.ts +0 -25946
  27. package/dist/components/index.d.ts.map +0 -1
@@ -0,0 +1,227 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, it, expect, beforeEach } from 'vitest';
3
+ import DatePicker from '../DatePicker.vue';
4
+
5
+ const factory = (props = {}) =>
6
+ mount(DatePicker, {
7
+ props: {
8
+ size: 'large',
9
+ type: 'day',
10
+ ...props,
11
+ },
12
+ global: {
13
+ mocks: {
14
+ $i18n: { locale: 'en-us' },
15
+ },
16
+ stubs: {
17
+ UnnnicButton: true,
18
+ },
19
+ },
20
+ });
21
+
22
+ const findFirstSelectableDay = (wrapper) =>
23
+ wrapper
24
+ .findAll('[data-testid="date-picker-day"]')
25
+ .find((day) => day.classes().includes('selectable'));
26
+
27
+ describe('DatePicker.vue', () => {
28
+ let wrapper;
29
+
30
+ beforeEach(() => {
31
+ wrapper = factory({
32
+ options: [
33
+ { name: 'Last 7 days', id: 'last-7-days' },
34
+ { name: 'Custom', id: 'custom' },
35
+ ],
36
+ });
37
+ });
38
+
39
+ it('renders day view with two months and options', () => {
40
+ expect(wrapper.find('[data-testid="date-picker-root"]').exists()).toBe(
41
+ true,
42
+ );
43
+ expect(
44
+ wrapper.findAll('[data-testid="date-picker-month-container"]').length,
45
+ ).toBe(2);
46
+ expect(wrapper.findAll('[data-testid="date-picker-option"]').length).toBe(
47
+ 2,
48
+ );
49
+ });
50
+
51
+ it('selects a date range and emits change', async () => {
52
+ const first = findFirstSelectableDay(wrapper);
53
+ const second = wrapper
54
+ .findAll('[data-testid="date-picker-day"]')
55
+ .reverse()
56
+ .find((day) => day.classes().includes('selectable'));
57
+
58
+ await first.trigger('click');
59
+ await second.trigger('click');
60
+
61
+ const emittedChange = wrapper.emitted('change');
62
+ expect(emittedChange).toBeTruthy();
63
+ const [{ startDate, endDate }] = emittedChange.pop();
64
+ expect(startDate).not.toBe('');
65
+ expect(endDate).not.toBe('');
66
+ });
67
+
68
+ it('clears selection when clear button is clicked', async () => {
69
+ const day = findFirstSelectableDay(wrapper);
70
+ await day.trigger('click');
71
+
72
+ await wrapper.find('[data-testid="date-picker-clear"]').trigger('click');
73
+
74
+ expect(wrapper.vm.startDate).toBe('');
75
+ expect(wrapper.vm.endDate).toBe('');
76
+ expect(wrapper.vm.optionSelected).toBe('');
77
+ });
78
+
79
+ it('submits with selected period and emits equivalent option name', async () => {
80
+ await wrapper.vm.autoSelect('last-7-days');
81
+ await wrapper.find('[data-testid="date-picker-submit"]').trigger('click');
82
+
83
+ const submit = wrapper.emitted('submit');
84
+ const updateEquivalent = wrapper.emitted('update:equivalentOption');
85
+
86
+ expect(submit).toBeTruthy();
87
+ expect(submit[0][0]).toHaveProperty('startDate');
88
+ expect(submit[0][0]).toHaveProperty('endDate');
89
+
90
+ expect(updateEquivalent[0][0]).toBe('Last 7 days');
91
+ });
92
+
93
+ it('submits with custom selection and clears equivalent option', async () => {
94
+ wrapper.vm.optionSelected = 'custom';
95
+ await wrapper.find('[data-testid="date-picker-submit"]').trigger('click');
96
+
97
+ const updateEquivalent = wrapper.emitted('update:equivalentOption');
98
+ expect(updateEquivalent[0][0]).toBe('');
99
+ });
100
+
101
+ it('uses periodBaseDate to compute relative ranges', async () => {
102
+ const base = '2025-01-15';
103
+ wrapper = factory({
104
+ periodBaseDate: base,
105
+ options: [{ name: 'Last 7 days', id: 'last-7-days' }],
106
+ });
107
+
108
+ await wrapper.vm.autoSelect('last-7-days');
109
+
110
+ const [year, month, day] = base.split('-');
111
+ const baseDate = new Date(Number(year), Number(month) - 1, Number(day));
112
+ const expectedEnd = wrapper.vm.dateToString(baseDate);
113
+
114
+ expect(wrapper.vm.endDate).toBe(expectedEnd);
115
+ });
116
+
117
+ it('renders month view and selects a month', async () => {
118
+ wrapper = factory({
119
+ type: 'month',
120
+ options: [{ name: 'Last 12 months', id: 'last-12-months' }],
121
+ });
122
+
123
+ const monthCell = wrapper.find('[data-testid="date-picker-month-cell"]');
124
+ await monthCell.trigger('click');
125
+
126
+ expect(wrapper.vm.startDate).not.toBe('');
127
+ expect(wrapper.vm.endDate).not.toBe('');
128
+ });
129
+
130
+ it('renders year view and selects a year', async () => {
131
+ wrapper = factory({
132
+ type: 'year',
133
+ options: [{ name: 'Previous year', id: 'previous-year' }],
134
+ });
135
+
136
+ const yearCell = wrapper.find('[data-testid="date-picker-year-cell"]');
137
+ await yearCell.trigger('click');
138
+
139
+ expect(wrapper.vm.startDate).not.toBe('');
140
+ expect(wrapper.vm.endDate).not.toBe('');
141
+ });
142
+
143
+ it('hides options when size is small and respects disableClear', async () => {
144
+ wrapper = factory({
145
+ size: 'small',
146
+ options: [{ name: 'Last 7 days', id: 'last-7-days' }],
147
+ });
148
+ expect(wrapper.find('[data-testid="date-picker-options"]').exists()).toBe(
149
+ false,
150
+ );
151
+
152
+ wrapper = factory({
153
+ disableClear: true,
154
+ options: [{ name: 'Last 7 days', id: 'last-7-days' }],
155
+ });
156
+ expect(wrapper.find('[data-testid="date-picker-clear"]').exists()).toBe(
157
+ false,
158
+ );
159
+ expect(wrapper.find('[data-testid="date-picker-submit"]').exists()).toBe(
160
+ true,
161
+ );
162
+ });
163
+
164
+ it('navigates between months using navigation buttons', async () => {
165
+ const initialReference = wrapper.vm.referenceDate;
166
+
167
+ const nextButton = wrapper.find('[data-testid="date-picker-nav-right"]');
168
+ await nextButton.trigger('click');
169
+
170
+ expect(wrapper.vm.referenceDate).not.toBe(initialReference);
171
+ });
172
+
173
+ it('exposes i18n helper compatible with previous mixin', () => {
174
+ const text = wrapper.vm.i18n('clean', 'Clean');
175
+ expect(text).toBeTruthy();
176
+ });
177
+
178
+ it('computes previous-month period correctly based on periodBaseDate', () => {
179
+ const base = '2025-03-15';
180
+ wrapper = factory({
181
+ periodBaseDate: base,
182
+ options: [{ name: 'Previous month', id: 'previous-month' }],
183
+ });
184
+
185
+ const { startDate, endDate } =
186
+ wrapper.vm.getStartAndEndDateByPeriod('previous-month');
187
+
188
+ const baseDate = new Date(base);
189
+ const firstPrevMonth = new Date(
190
+ baseDate.getFullYear(),
191
+ baseDate.getMonth() - 1,
192
+ 1,
193
+ );
194
+ const lastPrevMonth = new Date(
195
+ firstPrevMonth.getFullYear(),
196
+ firstPrevMonth.getMonth() + 1,
197
+ 0,
198
+ );
199
+
200
+ const expectedStart = wrapper.vm.dateToString(firstPrevMonth);
201
+ const expectedEnd = wrapper.vm.dateToString(lastPrevMonth);
202
+
203
+ expect(startDate).toBe(expectedStart);
204
+ expect(endDate).toBe(expectedEnd);
205
+ });
206
+
207
+ it('marks dates outside minDate and maxDate as out of range', () => {
208
+ const min = '2025-02-10';
209
+ const max = '2025-02-20';
210
+
211
+ wrapper = factory({
212
+ minDate: min,
213
+ maxDate: max,
214
+ });
215
+
216
+ const [year, month] = min.split('-');
217
+ const reference = `${Number(month)} 1 ${year}`;
218
+
219
+ const dates = wrapper.vm.getDatesOfTheMonth(reference);
220
+
221
+ const hasOutOfRange = dates.some((d) =>
222
+ d.properties.includes('out of range'),
223
+ );
224
+
225
+ expect(hasOutOfRange).toBe(true);
226
+ });
227
+ });
@@ -10,12 +10,6 @@ describe('Drawer.vue', () => {
10
10
  UnnnicIcon: true,
11
11
  UnnnicButton: true,
12
12
  Teleport: templateSlot,
13
- Drawer: templateSlot,
14
- DrawerContent: templateSlot,
15
- DrawerFooter: templateSlot,
16
- DrawerClose: templateSlot,
17
- DrawerTitle: templateSlot,
18
- DrawerDescription: templateSlot,
19
13
  };
20
14
 
21
15
  beforeEach(() => {
@@ -35,7 +29,7 @@ describe('Drawer.vue', () => {
35
29
 
36
30
  const element = (id) => wrapper.find(`[data-testid="${id}"]`);
37
31
  const component = (id) => wrapper.findComponent(`[data-testid="${id}"]`);
38
- const drawer = () => element('drawer');
32
+ const drawerRoot = () => wrapper.findComponent({ name: 'UnnnicDrawerNext' });
39
33
  const title = () => element('drawer-title');
40
34
  const description = () => element('drawer-description');
41
35
  const primaryButton = () => component('primary-button');
@@ -43,6 +37,8 @@ describe('Drawer.vue', () => {
43
37
  const footer = () => element('footer');
44
38
  const closeIcon = () => component('close-icon');
45
39
  const drawerContainer = () => element('drawer-container');
40
+ const drawerContentComponent = () =>
41
+ wrapper.findComponent({ name: 'UnnnicDrawerContent' });
46
42
 
47
43
  describe('Component Rendering', () => {
48
44
  describe('Component Rendering', () => {
@@ -51,23 +47,21 @@ describe('Drawer.vue', () => {
51
47
  });
52
48
 
53
49
  it('should render the drawer when modelValue is true', () => {
54
- expect(drawer().attributes('open')).toBe('true');
50
+ expect(drawerRoot().props('open')).toBe(true);
55
51
  });
56
52
 
57
53
  it('should not render the drawer when modelValue is false', async () => {
58
54
  await wrapper.setProps({ modelValue: false });
59
- expect(drawer().attributes('open')).toBe('false');
55
+ expect(drawerRoot().props('open')).toBe(false);
60
56
  });
61
57
 
62
58
  it('should render the overlay when withoutOverlay is false', () => {
63
- console.log('wrapper.html()', wrapper.html());
64
-
65
- expect(drawerContainer().attributes('showoverlay')).toBe('true');
59
+ expect(drawerContentComponent().props('showOverlay')).toBe(true);
66
60
  });
67
61
 
68
62
  it('should not render the overlay when withoutOverlay is true', async () => {
69
63
  await wrapper.setProps({ withoutOverlay: true });
70
- expect(drawerContainer().attributes('showoverlay')).toBe('false');
64
+ expect(drawerContentComponent().props('showOverlay')).toBe(false);
71
65
  });
72
66
 
73
67
  it('should display the title and description correctly', () => {
@@ -217,14 +211,16 @@ describe('Drawer.vue', () => {
217
211
  describe('Props and Computed Properties', () => {
218
212
  it('should render the correct size class based on size prop', async () => {
219
213
  await wrapper.setProps({ size: 'lg' });
220
- expect(drawerContainer().classes()).toContain(
214
+ expect(drawerContentComponent().props('class')).toContain(
221
215
  'unnnic-drawer__container--lg',
222
216
  );
217
+ expect(drawerContentComponent().props('size')).toBe('large');
223
218
 
224
219
  await wrapper.setProps({ size: 'xl' });
225
- expect(drawerContainer().classes()).toContain(
220
+ expect(drawerContentComponent().props('class')).toContain(
226
221
  'unnnic-drawer__container--xl',
227
222
  );
223
+ expect(drawerContentComponent().props('size')).toBe('extra-large');
228
224
  });
229
225
 
230
226
  it('should display footer if either primaryButtonText or secondaryButtonText is provided', async () => {
@@ -1,22 +1,22 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`Drawer.vue > Component Rendering > Component Rendering > matches the snapshot 1`] = `
4
- "<div data-v-196de012="" open="true" class="unnnic-drawer" data-testid="drawer">
5
- <div data-v-196de012="" showoverlay="true" data-testid="drawer-container" size="medium" class="unnnic-drawer__container unnnic-drawer__container--md">
4
+ "<div data-v-e761d31f="" data-v-196de012="" disabled="false" defer="false" forcemount="false" data-testid="drawer-container">
5
+ <div data-v-7f241b30="" data-v-e761d31f="" data-state="open" style="pointer-events: auto;" data-vaul-overlay="" data-vaul-snap-points="false" data-vaul-snap-points-overlay="true" class="unnnic-drawer__overlay"></div>
6
+ <div data-v-e761d31f="" data-dismissable-layer="" style="--snap-point-height: 0; --initial-transform: calc(100% + 8px); pointer-events: auto;" tabindex="-1" data-vaul-drawer="" data-vaul-drawer-direction="right" data-vaul-delayed-snap-points="false" data-vaul-snap-points="false" size="medium" showoverlay="true" class="unnnic-drawer__content unnnic-drawer__content--medium unnnic-drawer__container unnnic-drawer__container--md" id="" role="dialog" aria-describedby="reka-dialog-description-v-1" aria-labelledby="reka-dialog-title-v-0" data-state="open">
6
7
  <header data-v-39d0dfb8="" data-v-196de012="" class="unnnic-drawer__header unnnic-drawer__header">
7
8
  <section data-v-196de012="" class="unnnic-drawer__title-container">
8
- <div data-v-196de012="" class="unnnic-drawer__title" data-testid="drawer-title">Test Title</div>
9
- <div data-v-196de012="" class="unnnic-drawer__description" data-testid="drawer-description">Test Description</div>
10
- </section>
11
- <div data-v-196de012="">
9
+ <h2 data-v-97709962="" data-v-196de012="" id="reka-dialog-title-v-0" class="unnnic-drawer__title unnnic-drawer__title" data-testid="drawer-title">Test Title</h2>
10
+ <p data-v-750ea255="" data-v-196de012="" id="reka-dialog-description-v-1" class="unnnic-drawer__description unnnic-drawer__description" data-testid="drawer-description">Test Description</p>
11
+ </section><button data-v-4a771f40="" data-v-196de012="" type="button" class="unnnic-drawer__close">
12
12
  <unnnic-button-stub data-v-196de012="" size="small" text="" type="tertiary" float="false" iconleft="" iconright="" iconcenter="arrow_forward" iconsfilled="false" disabled="false" loading="false" class="unnnic-drawer__close-icon" data-testid="close-icon"></unnnic-button-stub>
13
- </div>
13
+ </button>
14
14
  </header>
15
15
  <section data-v-196de012="" class="unnnic-drawer__content"></section>
16
- <div data-v-196de012="" class="unnnic-drawer__footer" data-testid="footer">
16
+ <footer data-v-02ebc5b4="" data-v-196de012="" class="unnnic-drawer__footer unnnic-drawer__footer" data-testid="footer">
17
17
  <unnnic-button-stub data-v-196de012="" size="large" text="Secondary Action" type="tertiary" float="false" iconleft="" iconright="" iconcenter="" iconsfilled="false" disabled="false" loading="false" data-testid="secondary-button"></unnnic-button-stub>
18
18
  <unnnic-button-stub data-v-196de012="" size="large" text="Primary Action" type="primary" float="false" iconleft="" iconright="" iconcenter="" iconsfilled="false" disabled="false" loading="false" data-testid="primary-button"></unnnic-button-stub>
19
- </div>
19
+ </footer>
20
20
  </div>
21
21
  </div>"
22
22
  `;
@@ -6,11 +6,11 @@
6
6
  <UnnnicInput
7
7
  :class="['input', { 'date-picker-input-next': next }]"
8
8
  :size="size"
9
- :iconLeft="iconPosition === 'left' && 'calendar_month'"
10
- :iconRight="iconPosition === 'right' && 'calendar_month'"
9
+ :iconLeft="iconPosition === 'left' ? 'calendar_month' : undefined"
10
+ :iconRight="iconPosition === 'right' ? 'calendar_month' : undefined"
11
11
  hasCloudyColor
12
12
  readonly
13
- :modelValue="overwrittenValue || filterText"
13
+ :modelValue="overwrittenValue || filterText || ''"
14
14
  @focus="showCalendarFilter = true"
15
15
  />
16
16
 
@@ -27,6 +27,7 @@
27
27
  :months="months"
28
28
  :days="days"
29
29
  :options="options"
30
+ :periodBaseDate="periodBaseDate"
30
31
  :initialStartDate="initialStartDate"
31
32
  :initialEndDate="initialEndDate"
32
33
  :minDate="minDate"
@@ -39,191 +40,156 @@
39
40
  </div>
40
41
  </template>
41
42
 
42
- <script>
43
+ <script setup lang="ts">
44
+ import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
43
45
  import moment from 'moment';
46
+
44
47
  import UnnnicInput from '../Input/Input.vue';
45
48
  import UnnnicDatePicker from '../DatePicker/DatePicker.vue';
46
49
 
47
- export default {
48
- components: {
49
- UnnnicInput,
50
- UnnnicDatePicker,
51
- },
52
- model: {
53
- event: 'changed',
54
- },
55
-
56
- props: {
57
- modelValue: {
58
- type: Object,
59
- required: true,
60
- },
61
-
62
- iconPosition: {
63
- type: String,
64
- default: 'left',
65
- validator(position) {
66
- return ['left', 'right'].includes(position);
67
- },
68
- },
69
-
70
- minDate: { type: String, default: '' },
71
- maxDate: { type: String, default: '' },
72
-
73
- fillW: {
74
- type: Boolean,
75
- default: false,
76
- },
77
-
78
- type: {
79
- type: String,
80
- default: 'day',
81
- },
82
-
83
- size: {
84
- type: String,
85
- default: 'md',
86
- },
87
-
88
- clearText: {
89
- type: String,
90
- default: 'Clear',
91
- },
92
-
93
- actionText: {
94
- type: String,
95
- default: 'Filter',
96
- },
97
-
98
- months: {
99
- type: Array,
100
- default: () => [],
101
- },
102
-
103
- days: {
104
- type: Array,
105
- default: () => [],
106
- },
107
-
108
- options: {
109
- type: Array,
110
- default: () => [],
111
- },
112
-
113
- next: {
114
- type: Boolean,
115
- default: false,
116
- },
117
-
118
- format: {
119
- type: String,
120
- default: 'YYYY-MM-DD',
121
- },
122
-
123
- inputFormat: {
124
- type: String,
125
- default: 'MM-DD-YYYY',
126
- },
127
-
128
- position: {
129
- type: String,
130
- default: 'left',
131
- },
132
- disableClear: {
133
- type: Boolean,
134
- default: false,
135
- },
136
- },
137
-
138
- emits: ['update:model-value', 'selectDate'],
139
-
140
- data() {
141
- return {
142
- showCalendarFilter: false,
143
- overwrittenValue: '',
144
- };
145
- },
146
-
147
- computed: {
148
- filterText() {
149
- const dates = [];
150
-
151
- if (this.modelValue?.start) {
152
- dates.push(
153
- moment(this.modelValue?.start, this.format).format(this.inputFormat),
154
- );
155
- }
156
-
157
- if (this.modelValue?.end) {
158
- dates.push(
159
- moment(this.modelValue?.end, this.format).format(this.inputFormat),
160
- );
161
- }
162
-
163
- if (!dates.length) {
164
- return String(this.inputFormat).replaceAll('-', '/').toLowerCase();
165
- }
166
-
167
- return dates.join(' ~ ');
168
- },
169
-
170
- initialStartDate() {
171
- return this.modelValue.start
172
- ? moment(this.modelValue.start, this.format).format('MM DD YYYY')
173
- : null;
174
- },
175
-
176
- initialEndDate() {
177
- return this.modelValue.end
178
- ? moment(this.modelValue.end, this.format).format('MM DD YYYY')
179
- : null;
180
- },
181
- },
182
-
183
- mounted() {
184
- window.document.body.addEventListener('click', this.mouseout);
185
- },
186
-
187
- beforeUnmount() {
188
- window.document.body.removeEventListener('click', this.mouseout);
189
- },
190
-
191
- methods: {
192
- emitSelectDate(date) {
193
- const { startDate, endDate } = date;
194
- const formattedDates = {
195
- start: moment(startDate, 'MM-DD-YYYY').format(this.format),
196
- end: moment(endDate, 'MM-DD-YYYY').format(this.format),
197
- };
198
- this.$emit('selectDate', formattedDates);
199
- },
200
- mouseout(event) {
201
- if (this.$refs.dropdown?.contains(event.target)) {
202
- return;
203
- }
204
-
205
- this.showCalendarFilter = false;
206
- },
207
-
208
- changeDate(value) {
209
- const startDate = value.startDate.replace(
210
- /(\d+)-(\d+)-(\d+)/,
211
- '$3-$1-$2',
212
- );
213
-
214
- const endDate = value.endDate.replace(/(\d+)-(\d+)-(\d+)/, '$3-$1-$2');
215
-
216
- this.showCalendarFilter = false;
217
-
218
- this.$emit('update:model-value', {
219
- start: startDate
220
- ? moment(startDate, 'YYYY-MM-DD').format(this.format)
221
- : null,
222
- end: endDate ? moment(endDate, 'YYYY-MM-DD').format(this.format) : null,
223
- });
224
- },
225
- },
50
+ defineOptions({
51
+ name: 'UnnnicInputDatePicker',
52
+ });
53
+
54
+ type DateRangeValue = {
55
+ start: string | null;
56
+ end: string | null;
226
57
  };
58
+
59
+ interface InputDatePickerProps {
60
+ modelValue: DateRangeValue;
61
+
62
+ iconPosition?: 'left' | 'right';
63
+
64
+ minDate?: string;
65
+ maxDate?: string;
66
+
67
+ fillW?: boolean;
68
+
69
+ type?: 'day' | 'month' | 'year';
70
+ size?: string;
71
+
72
+ clearText?: string;
73
+ actionText?: string;
74
+
75
+ months?: string[];
76
+ days?: string[];
77
+ options?: Array<{ name: string; id: string }>;
78
+
79
+ next?: boolean;
80
+
81
+ format?: string;
82
+ inputFormat?: string | null;
83
+
84
+ position?: 'left' | 'right';
85
+ disableClear?: boolean;
86
+
87
+ periodBaseDate?: string;
88
+ }
89
+
90
+ const props = withDefaults(defineProps<InputDatePickerProps>(), {
91
+ iconPosition: 'left',
92
+ minDate: '',
93
+ maxDate: '',
94
+ fillW: false,
95
+ type: 'day',
96
+ size: 'md',
97
+ clearText: 'Clear',
98
+ actionText: 'Filter',
99
+ months: () => [],
100
+ days: () => [],
101
+ options: () => [],
102
+ next: false,
103
+ format: 'YYYY-MM-DD',
104
+ inputFormat: 'MM-DD-YYYY',
105
+ position: 'left',
106
+ disableClear: false,
107
+ periodBaseDate: '',
108
+ });
109
+
110
+ const emit = defineEmits<{
111
+ (e: 'update:model-value', value: DateRangeValue): void;
112
+ (e: 'selectDate', value: DateRangeValue): void;
113
+ }>();
114
+
115
+ const dropdown = ref<HTMLElement | null>(null);
116
+ const showCalendarFilter = ref(false);
117
+ const overwrittenValue = ref('');
118
+
119
+ const filterText = computed(() => {
120
+ const dates: string[] = [];
121
+
122
+ const { start, end } = props.modelValue || {};
123
+
124
+ if (start) {
125
+ dates.push(moment(start, props.format).format(props.inputFormat || ''));
126
+ }
127
+
128
+ if (end) {
129
+ dates.push(moment(end, props.format).format(props.inputFormat || ''));
130
+ }
131
+
132
+ if (!dates.length) {
133
+ return String(props.inputFormat || '')
134
+ .replaceAll('-', '/')
135
+ .toLowerCase();
136
+ }
137
+
138
+ return dates.join(' ~ ');
139
+ });
140
+
141
+ const initialStartDate = computed<string | undefined>(() => {
142
+ return props.modelValue.start
143
+ ? moment(props.modelValue.start, props.format).format('MM DD YYYY')
144
+ : undefined;
145
+ });
146
+
147
+ const initialEndDate = computed<string | undefined>(() => {
148
+ return props.modelValue.end
149
+ ? moment(props.modelValue.end, props.format).format('MM DD YYYY')
150
+ : undefined;
151
+ });
152
+
153
+ function emitSelectDate(date: { startDate: string; endDate: string }) {
154
+ const { startDate, endDate } = date;
155
+ const formattedDates: DateRangeValue = {
156
+ start: moment(startDate, 'MM-DD-YYYY').format(props.format),
157
+ end: moment(endDate, 'MM-DD-YYYY').format(props.format),
158
+ };
159
+
160
+ emit('selectDate', formattedDates);
161
+ }
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
+
171
+ function changeDate(value: { startDate: string; endDate: string }) {
172
+ const startDate = value.startDate.replace(/(\d+)-(\d+)-(\d+)/, '$3-$1-$2');
173
+
174
+ const endDate = value.endDate.replace(/(\d+)-(\d+)-(\d+)/, '$3-$1-$2');
175
+
176
+ showCalendarFilter.value = false;
177
+
178
+ emit('update:model-value', {
179
+ start: startDate
180
+ ? moment(startDate, 'YYYY-MM-DD').format(props.format)
181
+ : null,
182
+ end: endDate ? moment(endDate, 'YYYY-MM-DD').format(props.format) : null,
183
+ });
184
+ }
185
+
186
+ onMounted(() => {
187
+ window.document.body.addEventListener('click', mouseout as any);
188
+ });
189
+
190
+ onBeforeUnmount(() => {
191
+ window.document.body.removeEventListener('click', mouseout as any);
192
+ });
227
193
  </script>
228
194
 
229
195
  <style lang="scss" scoped>