design-system-next 2.24.2 → 2.26.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/dist/design-system-next.es.d.ts +152 -114
- package/dist/design-system-next.es.js +10058 -9379
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +12 -12
- package/dist/design-system-next.umd.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/package.json +3 -2
- package/src/App.vue +1 -89
- package/src/components/date-picker/date-picker.ts +9 -12
- package/src/components/date-picker/date-picker.vue +1 -1
- package/src/components/date-picker/date-range-picker/date-range-picker.ts +9 -12
- package/src/components/date-picker/date-range-picker/use-date-range-picker.ts +64 -49
- package/src/components/date-picker/month-year-picker/month-year-picker.ts +134 -0
- package/src/components/date-picker/month-year-picker/month-year-picker.vue +233 -0
- package/src/components/date-picker/month-year-picker/use-month-year-picker.ts +603 -0
- package/src/components/date-picker/use-date-picker.ts +88 -147
- package/src/components/list/list-item/list-item.ts +60 -60
- package/src/components/list/list.ts +5 -0
- package/src/components/list/list.vue +2 -0
- package/src/components/list/use-list.ts +36 -3
- package/src/components/radio-grouped/radio-grouped.ts +65 -65
- package/src/components/radio-grouped/use-radio-grouped.ts +62 -62
- package/src/components/select/select-multiple/use-select-multiple.ts +7 -3
- package/src/components/select/use-select.ts +9 -5
- package/src/components/sidepanel/sidepanel.ts +7 -0
- package/src/components/sidepanel/sidepanel.vue +24 -4
- package/src/components/sidepanel/use-sidepanel.ts +4 -0
- package/src/components/table/table-header-dropdown/table-header-dropdown.vue +5 -1
- package/src/components/table/table.vue +14 -0
- package/src/components/table/use-table.ts +1 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, toRefs, computed, ComputedRef, SetupContext, onMounted, watch, nextTick } from 'vue';
|
|
2
|
-
import { useVModel, onClickOutside
|
|
2
|
+
import { useVModel, onClickOutside } from '@vueuse/core';
|
|
3
3
|
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
5
|
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
|
|
@@ -143,8 +143,6 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
143
143
|
const dateInput = ref<string>('');
|
|
144
144
|
const yearInput = ref<string>('');
|
|
145
145
|
|
|
146
|
-
const datePickerErrors = ref<{ title: string; message: string }[]>([]);
|
|
147
|
-
|
|
148
146
|
// #region - Calendar Tab
|
|
149
147
|
const calendarTabPageData = ref({
|
|
150
148
|
selectedMonth: dayjs().month(),
|
|
@@ -295,12 +293,18 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
295
293
|
}
|
|
296
294
|
|
|
297
295
|
// Check if date and month are selected, but not year
|
|
298
|
-
if (dateInput.value && monthInput && !yearInput.value && !calendarTabIsDateIsDisabled(day)) {
|
|
296
|
+
if (dateInput.value && monthInput.value && !yearInput.value && !calendarTabIsDateIsDisabled(day)) {
|
|
299
297
|
return day.date.getDate() === Number(dateInput.value) && day.date.getMonth() === monthValue && !day.inactive;
|
|
300
298
|
}
|
|
301
299
|
|
|
302
300
|
// Check if date, month, and year are selected
|
|
303
|
-
if (
|
|
301
|
+
if (
|
|
302
|
+
dateInput.value &&
|
|
303
|
+
monthInput.value &&
|
|
304
|
+
yearInput.value &&
|
|
305
|
+
monthValue !== undefined &&
|
|
306
|
+
!calendarTabIsDateIsDisabled(day)
|
|
307
|
+
) {
|
|
304
308
|
return (
|
|
305
309
|
day.date.getDate() === Number(dateInput.value) &&
|
|
306
310
|
day.date.getMonth() === monthValue &&
|
|
@@ -471,10 +475,6 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
471
475
|
emitDateFormats();
|
|
472
476
|
emitInputValue();
|
|
473
477
|
|
|
474
|
-
datePickerErrors.value = [];
|
|
475
|
-
|
|
476
|
-
emit('getDateErrors', datePickerErrors.value);
|
|
477
|
-
|
|
478
478
|
setTimeout(() => {
|
|
479
479
|
datePopperState.value = false;
|
|
480
480
|
}, 100);
|
|
@@ -494,11 +494,7 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
494
494
|
handleConvertMonthIfValid();
|
|
495
495
|
calendarTabUpdateCalendar();
|
|
496
496
|
emitDateFormats();
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
datePickerErrors.value = [];
|
|
500
|
-
|
|
501
|
-
emit('getDateErrors', datePickerErrors.value);
|
|
497
|
+
emitInputValue();
|
|
502
498
|
};
|
|
503
499
|
// #endregion - Month Tab
|
|
504
500
|
|
|
@@ -564,11 +560,7 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
564
560
|
handleConvertMonthIfValid();
|
|
565
561
|
calendarTabUpdateCalendar();
|
|
566
562
|
emitDateFormats();
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
datePickerErrors.value = [];
|
|
570
|
-
|
|
571
|
-
emit('getDateErrors', datePickerErrors.value);
|
|
563
|
+
emitInputValue();
|
|
572
564
|
};
|
|
573
565
|
// #endregion - Year Tab
|
|
574
566
|
|
|
@@ -640,8 +632,6 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
640
632
|
const date = formattedDate.format('DD');
|
|
641
633
|
const year = formattedDate.format('YYYY');
|
|
642
634
|
|
|
643
|
-
handleValidateDate();
|
|
644
|
-
|
|
645
635
|
monthInput.value = month;
|
|
646
636
|
dateInput.value = date;
|
|
647
637
|
yearInput.value = year;
|
|
@@ -655,13 +645,7 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
655
645
|
handleConvertMonthIfValid();
|
|
656
646
|
calendarTabUpdateCalendar();
|
|
657
647
|
emitDateFormats();
|
|
658
|
-
|
|
659
|
-
// Use the specified format for the input value
|
|
660
|
-
if (!monthInput.value && !dateInput.value && !yearInput.value) {
|
|
661
|
-
emit('getInputValue', null);
|
|
662
|
-
} else {
|
|
663
|
-
emit('getInputValue', formattedDate.format(format.value));
|
|
664
|
-
}
|
|
648
|
+
emitInputValue();
|
|
665
649
|
} else {
|
|
666
650
|
console.error(`Error: Could not parse date "${modelValue.value}" with format "${format.value}"`);
|
|
667
651
|
}
|
|
@@ -686,48 +670,71 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
686
670
|
};
|
|
687
671
|
|
|
688
672
|
const handleMonthInput = () => {
|
|
689
|
-
datePopperState.value = false;
|
|
690
|
-
|
|
691
673
|
monthInput.value = monthInput.value.replace(/[^A-Za-z0-9\s]/g, '').toLocaleUpperCase();
|
|
692
674
|
|
|
693
|
-
datePickerErrors.value = [];
|
|
694
|
-
|
|
695
|
-
emit('getDateErrors', datePickerErrors.value);
|
|
696
|
-
|
|
697
675
|
handleConvertMonthIfValid();
|
|
698
676
|
|
|
699
|
-
|
|
677
|
+
// Update calendar if month, date, and year are all provided
|
|
678
|
+
if (monthInput.value && dateInput.value && yearInput.value) {
|
|
679
|
+
const monthValue = getMonthObject('text', monthInput.value)?.monthValue;
|
|
680
|
+
const yearNumber = Number(yearInput.value);
|
|
681
|
+
|
|
682
|
+
if (monthValue !== undefined && yearNumber >= minMaxYear.value.min && yearNumber <= minMaxYear.value.max) {
|
|
683
|
+
calendarTabPageData.value.selectedMonth = monthValue;
|
|
684
|
+
calendarTabPageData.value.selectedYear = yearNumber;
|
|
685
|
+
calendarTabUpdateCalendar();
|
|
686
|
+
}
|
|
687
|
+
} else if (!monthInput.value && !dateInput.value && !yearInput.value) {
|
|
688
|
+
// Clear modelValue when all inputs are empty
|
|
689
|
+
modelValue.value = '';
|
|
690
|
+
}
|
|
700
691
|
|
|
701
692
|
// Emit the partial date value as user types
|
|
702
|
-
|
|
693
|
+
emitInputValue();
|
|
703
694
|
};
|
|
704
695
|
|
|
705
696
|
const handleDateInput = () => {
|
|
706
|
-
datePopperState.value = false;
|
|
707
|
-
|
|
708
697
|
dateInput.value = dateInput.value.replace(/[^0-9]/g, '');
|
|
709
698
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
699
|
+
// Update calendar if month, date, and year are all provided
|
|
700
|
+
if (monthInput.value && dateInput.value && yearInput.value) {
|
|
701
|
+
const monthValue = getMonthObject('text', monthInput.value)?.monthValue;
|
|
702
|
+
const yearNumber = Number(yearInput.value);
|
|
713
703
|
|
|
714
|
-
|
|
704
|
+
if (monthValue !== undefined && yearNumber >= minMaxYear.value.min && yearNumber <= minMaxYear.value.max) {
|
|
705
|
+
calendarTabPageData.value.selectedMonth = monthValue;
|
|
706
|
+
calendarTabPageData.value.selectedYear = yearNumber;
|
|
707
|
+
calendarTabUpdateCalendar();
|
|
708
|
+
}
|
|
709
|
+
} else if (!monthInput.value && !dateInput.value && !yearInput.value) {
|
|
710
|
+
// Clear modelValue when all inputs are empty
|
|
711
|
+
modelValue.value = '';
|
|
712
|
+
}
|
|
715
713
|
|
|
716
714
|
// Emit the partial date value as user types
|
|
717
|
-
|
|
715
|
+
emitInputValue();
|
|
718
716
|
};
|
|
719
717
|
|
|
720
718
|
const handleYearInput = () => {
|
|
721
|
-
datePopperState.value = false;
|
|
722
|
-
|
|
723
719
|
yearInput.value = yearInput.value.replace(/[^0-9]/g, '');
|
|
724
720
|
|
|
725
|
-
|
|
721
|
+
// Update calendar if month, date, and year are all provided
|
|
722
|
+
if (monthInput.value && dateInput.value && yearInput.value) {
|
|
723
|
+
const monthValue = getMonthObject('text', monthInput.value)?.monthValue;
|
|
724
|
+
const yearNumber = Number(yearInput.value);
|
|
726
725
|
|
|
727
|
-
|
|
726
|
+
if (monthValue !== undefined && yearNumber >= minMaxYear.value.min && yearNumber <= minMaxYear.value.max) {
|
|
727
|
+
calendarTabPageData.value.selectedMonth = monthValue;
|
|
728
|
+
calendarTabPageData.value.selectedYear = yearNumber;
|
|
729
|
+
calendarTabUpdateCalendar();
|
|
730
|
+
}
|
|
731
|
+
} else if (!monthInput.value && !dateInput.value && !yearInput.value) {
|
|
732
|
+
// Clear modelValue when all inputs are empty
|
|
733
|
+
modelValue.value = '';
|
|
734
|
+
}
|
|
728
735
|
|
|
729
736
|
// Emit the partial date value as user types
|
|
730
|
-
|
|
737
|
+
emitInputValue();
|
|
731
738
|
};
|
|
732
739
|
|
|
733
740
|
const handleConvertMonthIfValid = () => {
|
|
@@ -755,51 +762,6 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
755
762
|
}
|
|
756
763
|
};
|
|
757
764
|
|
|
758
|
-
const handleValidateDate = useDebounceFn(() => {
|
|
759
|
-
if (monthInput.value && dateInput.value && yearInput.value) {
|
|
760
|
-
const selectedDate = `${monthInput.value}-${dateInput.value}-${yearInput.value}`;
|
|
761
|
-
|
|
762
|
-
const isDateValid = dayjs(selectedDate, 'MM-DD-YYYY').isValid();
|
|
763
|
-
const isYearValid =
|
|
764
|
-
Number(yearInput.value) >= minMaxYear.value.min && Number(yearInput.value) <= minMaxYear.value.max;
|
|
765
|
-
|
|
766
|
-
if (isDateValid && isYearValid) {
|
|
767
|
-
datePickerErrors.value = datePickerErrors.value.filter((error) => error.title !== 'Invalid Date');
|
|
768
|
-
|
|
769
|
-
const monthValue = getMonthObject('text', monthInput.value)?.monthValue;
|
|
770
|
-
|
|
771
|
-
calendarTabPageData.value.selectedMonth = Number(monthValue);
|
|
772
|
-
calendarTabPageData.value.selectedYear = Number(yearInput.value);
|
|
773
|
-
|
|
774
|
-
calendarTabUpdateCalendar();
|
|
775
|
-
emitDateFormats();
|
|
776
|
-
} else {
|
|
777
|
-
const errorExists = datePickerErrors.value.some((error) => error.title === 'Invalid Date');
|
|
778
|
-
|
|
779
|
-
if (!errorExists) {
|
|
780
|
-
let errorMessage;
|
|
781
|
-
|
|
782
|
-
if (!isYearValid) {
|
|
783
|
-
errorMessage = `Year must be between ${minMaxYear.value.min} and ${minMaxYear.value.max}.`;
|
|
784
|
-
} else {
|
|
785
|
-
errorMessage = `Invalid Date Format. Please use ${format.value}`;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
datePickerErrors.value.push({
|
|
789
|
-
title: 'Invalid Date',
|
|
790
|
-
message: errorMessage,
|
|
791
|
-
});
|
|
792
|
-
|
|
793
|
-
datePopperState.value = false;
|
|
794
|
-
|
|
795
|
-
emit('getDateErrors', datePickerErrors.value);
|
|
796
|
-
|
|
797
|
-
console.error(`Invalid Date: "${selectedDate}". ${errorMessage}`);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}, 500);
|
|
802
|
-
|
|
803
765
|
const handleTabClick = (tab: string) => {
|
|
804
766
|
if (currentTab.value === tab) {
|
|
805
767
|
currentTab.value = 'tab-calendar';
|
|
@@ -824,34 +786,28 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
824
786
|
}
|
|
825
787
|
};
|
|
826
788
|
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
const isNumeric = !isNaN(Number(monthInput.value)) && !isNaN(parseFloat(monthInput.value));
|
|
833
|
-
|
|
834
|
-
if (!isNumeric) {
|
|
835
|
-
const monthIsValid = monthsList.value.find(
|
|
836
|
-
(_month: MonthsList) => _month.text.toLowerCase() === monthInput.value.toLowerCase(),
|
|
837
|
-
);
|
|
789
|
+
const emitInputValue = () => {
|
|
790
|
+
if (monthInput.value || dateInput.value || yearInput.value) {
|
|
791
|
+
emit('getInputValue', `${monthInput.value}-${dateInput.value}-${yearInput.value}`);
|
|
792
|
+
} else {
|
|
793
|
+
emit('getInputValue', null);
|
|
838
794
|
|
|
839
|
-
|
|
840
|
-
emittedMonth =
|
|
841
|
-
monthIsValid.monthValue < 10 ? `0${monthIsValid.monthValue + 1}` : `${monthIsValid.monthValue + 1}`;
|
|
842
|
-
}
|
|
843
|
-
}
|
|
795
|
+
modelValue.value = '';
|
|
844
796
|
}
|
|
845
797
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
798
|
+
if (monthInput.value && dateInput.value && yearInput.value) {
|
|
799
|
+
const monthIsValid = monthsList.value.find(
|
|
800
|
+
(_month: MonthsList) => _month.text.toLowerCase() === monthInput.value.toLowerCase(),
|
|
801
|
+
);
|
|
850
802
|
|
|
851
|
-
|
|
803
|
+
const yearIsValid = yearTabPageData.value.yearsArray.find((_year) => _year === Number(yearInput.value));
|
|
852
804
|
|
|
853
|
-
|
|
854
|
-
|
|
805
|
+
if (monthIsValid && yearIsValid) {
|
|
806
|
+
const _date = dayjs(`${monthInput.value}-${dateInput.value}-${yearInput.value}`, 'MM-DD-YYYY');
|
|
807
|
+
|
|
808
|
+
modelValue.value = _date.format(format.value);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
855
811
|
};
|
|
856
812
|
|
|
857
813
|
const emitDateFormats = () => {
|
|
@@ -904,28 +860,6 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
904
860
|
}
|
|
905
861
|
};
|
|
906
862
|
|
|
907
|
-
const emitInputValue = () => {
|
|
908
|
-
let emittedMonth = monthInput.value;
|
|
909
|
-
|
|
910
|
-
const isNumeric = !isNaN(Number(monthInput.value)) && !isNaN(parseFloat(monthInput.value));
|
|
911
|
-
|
|
912
|
-
if (!isNumeric) {
|
|
913
|
-
const monthIsValid = monthsList.value.find(
|
|
914
|
-
(_month: MonthsList) => _month.text.toLowerCase() === monthInput.value.toLowerCase(),
|
|
915
|
-
);
|
|
916
|
-
|
|
917
|
-
if (monthIsValid) {
|
|
918
|
-
emittedMonth =
|
|
919
|
-
monthIsValid.monthValue < 10 ? `0${monthIsValid.monthValue + 1}` : `${monthIsValid.monthValue + 1}`;
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
// Format the date according to the format prop
|
|
923
|
-
const dateObj = dayjs(`${emittedMonth}-${dateInput.value}-${yearInput.value}`, 'MM-DD-YYYY');
|
|
924
|
-
|
|
925
|
-
// Use the specified format for the input value
|
|
926
|
-
emit('getInputValue', (modelValue.value = dateObj.format(format.value)));
|
|
927
|
-
};
|
|
928
|
-
|
|
929
863
|
const emitMonthList = () => {
|
|
930
864
|
emit('getMonthList', monthsList.value);
|
|
931
865
|
};
|
|
@@ -939,6 +873,9 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
939
873
|
monthInput.value = '';
|
|
940
874
|
dateInput.value = '';
|
|
941
875
|
yearInput.value = '';
|
|
876
|
+
modelValue.value = '';
|
|
877
|
+
|
|
878
|
+
emitInputValue();
|
|
942
879
|
};
|
|
943
880
|
|
|
944
881
|
const handleSlotClick = () => {
|
|
@@ -972,14 +909,19 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
972
909
|
}
|
|
973
910
|
});
|
|
974
911
|
|
|
975
|
-
watch(
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
912
|
+
watch(
|
|
913
|
+
minMaxYear,
|
|
914
|
+
() => {
|
|
915
|
+
yearTabPageData.value.yearsArray = Array.from(
|
|
916
|
+
{ length: minMaxYear.value.max - minMaxYear.value.min + 1 },
|
|
917
|
+
(_, index) => minMaxYear.value.min + index,
|
|
918
|
+
).filter((year) => year <= minMaxYear.value.max && year >= minMaxYear.value.min);
|
|
919
|
+
|
|
920
|
+
yearTabPageData.value.currentPage = 0;
|
|
921
|
+
emitYearList();
|
|
922
|
+
},
|
|
923
|
+
{ deep: true },
|
|
924
|
+
);
|
|
983
925
|
|
|
984
926
|
onClickOutside(datePickerRef, () => {
|
|
985
927
|
datePopperState.value = false;
|
|
@@ -1014,7 +956,6 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
|
|
|
1014
956
|
dateInput,
|
|
1015
957
|
monthInput,
|
|
1016
958
|
yearInput,
|
|
1017
|
-
datePickerErrors,
|
|
1018
959
|
calendarTabPageData,
|
|
1019
960
|
calendarTabIsMinMonth,
|
|
1020
961
|
calendarTabIsMaxMonth,
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import type { PropType, ExtractPropTypes } from 'vue';
|
|
2
|
-
import type { MenuListType } from '../list';
|
|
3
|
-
|
|
4
|
-
export const listItemPropTypes = {
|
|
5
|
-
item: {
|
|
6
|
-
type: Object as PropType<MenuListType>,
|
|
7
|
-
required: true,
|
|
8
|
-
},
|
|
9
|
-
isSelected: {
|
|
10
|
-
type: Boolean,
|
|
11
|
-
required: true,
|
|
12
|
-
},
|
|
13
|
-
classes: {
|
|
14
|
-
type: [String, Array, Object] as PropType<string | string[] | Record<string, boolean>>,
|
|
15
|
-
required: true,
|
|
16
|
-
},
|
|
17
|
-
multiSelect: {
|
|
18
|
-
type: Boolean,
|
|
19
|
-
default: false,
|
|
20
|
-
},
|
|
21
|
-
lozenge: {
|
|
22
|
-
type: Boolean,
|
|
23
|
-
default: false,
|
|
24
|
-
},
|
|
25
|
-
ladderized: {
|
|
26
|
-
type: Boolean,
|
|
27
|
-
default: false,
|
|
28
|
-
},
|
|
29
|
-
noCheck: {
|
|
30
|
-
type: Boolean,
|
|
31
|
-
default: false,
|
|
32
|
-
},
|
|
33
|
-
itemIcon: {
|
|
34
|
-
type: String,
|
|
35
|
-
default: '',
|
|
36
|
-
},
|
|
37
|
-
itemIconTone: {
|
|
38
|
-
type: String,
|
|
39
|
-
default: 'plain',
|
|
40
|
-
},
|
|
41
|
-
itemIconFill: {
|
|
42
|
-
type: Boolean,
|
|
43
|
-
default: false,
|
|
44
|
-
},
|
|
45
|
-
disabledUnselectedItems: {
|
|
46
|
-
type: Boolean,
|
|
47
|
-
default: false,
|
|
48
|
-
},
|
|
49
|
-
radioList: {
|
|
50
|
-
type: Boolean,
|
|
51
|
-
default: false,
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const listItemEmitTypes = {
|
|
56
|
-
select: () => true,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export type ListItemPropTypes = ExtractPropTypes<typeof listItemPropTypes>;
|
|
60
|
-
export type ListItemEmitTypes = typeof listItemEmitTypes;
|
|
1
|
+
import type { PropType, ExtractPropTypes } from 'vue';
|
|
2
|
+
import type { MenuListType } from '../list';
|
|
3
|
+
|
|
4
|
+
export const listItemPropTypes = {
|
|
5
|
+
item: {
|
|
6
|
+
type: Object as PropType<MenuListType>,
|
|
7
|
+
required: true,
|
|
8
|
+
},
|
|
9
|
+
isSelected: {
|
|
10
|
+
type: Boolean,
|
|
11
|
+
required: true,
|
|
12
|
+
},
|
|
13
|
+
classes: {
|
|
14
|
+
type: [String, Array, Object] as PropType<string | string[] | Record<string, boolean>>,
|
|
15
|
+
required: true,
|
|
16
|
+
},
|
|
17
|
+
multiSelect: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: false,
|
|
20
|
+
},
|
|
21
|
+
lozenge: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: false,
|
|
24
|
+
},
|
|
25
|
+
ladderized: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
},
|
|
29
|
+
noCheck: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
default: false,
|
|
32
|
+
},
|
|
33
|
+
itemIcon: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: '',
|
|
36
|
+
},
|
|
37
|
+
itemIconTone: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: 'plain',
|
|
40
|
+
},
|
|
41
|
+
itemIconFill: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: false,
|
|
44
|
+
},
|
|
45
|
+
disabledUnselectedItems: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
default: false,
|
|
48
|
+
},
|
|
49
|
+
radioList: {
|
|
50
|
+
type: Boolean,
|
|
51
|
+
default: false,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const listItemEmitTypes = {
|
|
56
|
+
select: () => true,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type ListItemPropTypes = ExtractPropTypes<typeof listItemPropTypes>;
|
|
60
|
+
export type ListItemEmitTypes = typeof listItemEmitTypes;
|
|
@@ -123,12 +123,17 @@ export const listPropTypes = {
|
|
|
123
123
|
type: Boolean,
|
|
124
124
|
default: false,
|
|
125
125
|
},
|
|
126
|
+
allowDeselect: {
|
|
127
|
+
type: Boolean,
|
|
128
|
+
default: false
|
|
129
|
+
}
|
|
126
130
|
};
|
|
127
131
|
|
|
128
132
|
export const listEmitTypes = {
|
|
129
133
|
'update:modelValue': (value: MenuListType[]) => value,
|
|
130
134
|
'update:searchValue': (value: string) => typeof value === 'string',
|
|
131
135
|
'get-single-selected-item': (item: MenuListType) => item,
|
|
136
|
+
'get-single-deselected-item': (item: MenuListType) => item,
|
|
132
137
|
};
|
|
133
138
|
|
|
134
139
|
export type ListPropTypes = ExtractPropTypes<typeof listPropTypes>;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
v-model="searchText"
|
|
9
9
|
:placeholder="props.searchableMenuPlaceholder"
|
|
10
10
|
autocomplete="off"
|
|
11
|
+
@keyup="handleSearchKeyup"
|
|
11
12
|
/>
|
|
12
13
|
<span
|
|
13
14
|
v-if="props.supportingDisplayText || props.displayListItemSelected"
|
|
@@ -121,5 +122,6 @@ const {
|
|
|
121
122
|
isItemSelected,
|
|
122
123
|
getListItemClasses,
|
|
123
124
|
handleSelectedItem,
|
|
125
|
+
handleSearchKeyup,
|
|
124
126
|
} = useList(props, emit);
|
|
125
127
|
</script>
|
|
@@ -22,6 +22,7 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
|
|
|
22
22
|
noCheck,
|
|
23
23
|
disabledUnselectedItems,
|
|
24
24
|
stickySearchOffset,
|
|
25
|
+
allowDeselect,
|
|
25
26
|
} = toRefs(props);
|
|
26
27
|
|
|
27
28
|
const listClasses: ComputedRef<ListClasses> = computed(() => {
|
|
@@ -518,14 +519,31 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
|
|
|
518
519
|
// Track the deselection but DON'T add items back to selectedItems when deselecting
|
|
519
520
|
trackNewlySelectedItems(item, true);
|
|
520
521
|
}
|
|
522
|
+
emit('get-single-selected-item', item);
|
|
521
523
|
} else {
|
|
522
524
|
// For single-select, simply replace the selection
|
|
523
|
-
|
|
525
|
+
if (allowDeselect.value) {
|
|
526
|
+
handleDeselect(item);
|
|
527
|
+
} else {
|
|
528
|
+
handleSingleSelect(item);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
};
|
|
524
532
|
|
|
525
|
-
|
|
533
|
+
const handleDeselect = (item: MenuListType) => {
|
|
534
|
+
if (selectedItems.value.length === 0 || !isItemSelected(item)) {
|
|
535
|
+
selectedItems.value = [item];
|
|
536
|
+
emit('get-single-selected-item', item);
|
|
537
|
+
} else {
|
|
538
|
+
selectedItems.value = [];
|
|
539
|
+
emit('get-single-deselected-item', item);
|
|
526
540
|
}
|
|
541
|
+
};
|
|
527
542
|
|
|
528
|
-
|
|
543
|
+
const handleSingleSelect = (item: MenuListType) => {
|
|
544
|
+
selectedItems.value = [item];
|
|
545
|
+
if (item.onClickFn) item.onClickFn();
|
|
546
|
+
emit('get-single-selected-item', item);
|
|
529
547
|
};
|
|
530
548
|
// #endregion - Helper Methods
|
|
531
549
|
|
|
@@ -608,6 +626,20 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
|
|
|
608
626
|
setPreSelectedItems();
|
|
609
627
|
});
|
|
610
628
|
|
|
629
|
+
// Handle search keyup to ignore modifier-only keys
|
|
630
|
+
const handleSearchKeyup = (event: KeyboardEvent) => {
|
|
631
|
+
// Ignore pure modifier keys: Shift, Control, Alt, Meta (Command/Windows), CapsLock
|
|
632
|
+
const modifierOnlyKeys = ['Shift', 'Control', 'Alt', 'Meta', 'CapsLock'];
|
|
633
|
+
|
|
634
|
+
if (!modifierOnlyKeys.includes(event.key)) {
|
|
635
|
+
// Allow the search to proceed - v-model will handle the actual update
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// For modifier-only keys, prevent default behavior if needed
|
|
640
|
+
event.preventDefault();
|
|
641
|
+
};
|
|
642
|
+
|
|
611
643
|
return {
|
|
612
644
|
listClasses,
|
|
613
645
|
stickyOffsetStyle,
|
|
@@ -623,5 +655,6 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
|
|
|
623
655
|
handleSearch,
|
|
624
656
|
handleSelectedItem,
|
|
625
657
|
trackNewlySelectedItems,
|
|
658
|
+
handleSearchKeyup,
|
|
626
659
|
};
|
|
627
660
|
};
|