@coreui/vue-pro 5.14.0 → 5.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/components/calendar/CCalendar.js +67 -65
- package/dist/cjs/components/calendar/CCalendar.js.map +1 -1
- package/dist/cjs/components/calendar/utils.d.ts +53 -2
- package/dist/cjs/components/calendar/utils.js +466 -43
- package/dist/cjs/components/calendar/utils.js.map +1 -1
- package/dist/cjs/components/date-range-picker/CDateRangePicker.js +86 -57
- package/dist/cjs/components/date-range-picker/CDateRangePicker.js.map +1 -1
- package/dist/cjs/components/date-range-picker/utils.d.ts +0 -9
- package/dist/cjs/components/date-range-picker/utils.js +0 -38
- package/dist/cjs/components/date-range-picker/utils.js.map +1 -1
- package/dist/cjs/components/dropdown/CDropdown.d.ts +32 -7
- package/dist/cjs/components/dropdown/CDropdown.js +67 -29
- package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
- package/dist/cjs/components/dropdown/CDropdownToggle.d.ts +19 -0
- package/dist/cjs/components/dropdown/CDropdownToggle.js +17 -2
- package/dist/cjs/components/dropdown/CDropdownToggle.js.map +1 -1
- package/dist/cjs/components/dropdown/utils.d.ts +2 -0
- package/dist/cjs/components/dropdown/utils.js +13 -0
- package/dist/cjs/components/dropdown/utils.js.map +1 -1
- package/dist/cjs/components/focus-trap/CFocusTrap.d.ts +108 -0
- package/dist/cjs/components/focus-trap/CFocusTrap.js +254 -0
- package/dist/cjs/components/focus-trap/CFocusTrap.js.map +1 -0
- package/dist/cjs/components/focus-trap/index.d.ts +6 -0
- package/dist/cjs/components/focus-trap/index.js +13 -0
- package/dist/cjs/components/focus-trap/index.js.map +1 -0
- package/dist/cjs/components/focus-trap/utils.d.ts +28 -0
- package/dist/cjs/components/focus-trap/utils.js +83 -0
- package/dist/cjs/components/focus-trap/utils.js.map +1 -0
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +70 -66
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/components/modal/CModal.d.ts +2 -2
- package/dist/cjs/components/modal/CModal.js +19 -27
- package/dist/cjs/components/modal/CModal.js.map +1 -1
- package/dist/cjs/components/modal/CModalHeader.js +4 -2
- package/dist/cjs/components/modal/CModalHeader.js.map +1 -1
- package/dist/cjs/components/nav/CNavItem.d.ts +2 -2
- package/dist/cjs/components/offcanvas/COffcanvas.js +3 -2
- package/dist/cjs/components/offcanvas/COffcanvas.js.map +1 -1
- package/dist/cjs/components/picker/CPicker.js +3 -2
- package/dist/cjs/components/picker/CPicker.js.map +1 -1
- package/dist/cjs/components/time-picker/CTimePicker.d.ts +45 -1
- package/dist/cjs/components/time-picker/CTimePicker.js +64 -8
- package/dist/cjs/components/time-picker/CTimePicker.js.map +1 -1
- package/dist/cjs/components/time-picker/CTimePickerRollCol.d.ts +19 -7
- package/dist/cjs/components/time-picker/CTimePickerRollCol.js +80 -8
- package/dist/cjs/components/time-picker/CTimePickerRollCol.js.map +1 -1
- package/dist/cjs/components/time-picker/utils.d.ts +1 -1
- package/dist/cjs/composables/useDebouncedCallback.d.ts +1 -1
- package/dist/cjs/composables/useDebouncedCallback.js +1 -1
- package/dist/cjs/composables/useDebouncedCallback.js.map +1 -1
- package/dist/cjs/index.js +76 -72
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/components/calendar/CCalendar.js +67 -65
- package/dist/esm/components/calendar/CCalendar.js.map +1 -1
- package/dist/esm/components/calendar/utils.d.ts +53 -2
- package/dist/esm/components/calendar/utils.js +464 -44
- package/dist/esm/components/calendar/utils.js.map +1 -1
- package/dist/esm/components/date-range-picker/CDateRangePicker.js +86 -57
- package/dist/esm/components/date-range-picker/CDateRangePicker.js.map +1 -1
- package/dist/esm/components/date-range-picker/utils.d.ts +0 -9
- package/dist/esm/components/date-range-picker/utils.js +1 -38
- package/dist/esm/components/date-range-picker/utils.js.map +1 -1
- package/dist/esm/components/dropdown/CDropdown.d.ts +32 -7
- package/dist/esm/components/dropdown/CDropdown.js +69 -31
- package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
- package/dist/esm/components/dropdown/CDropdownToggle.d.ts +19 -0
- package/dist/esm/components/dropdown/CDropdownToggle.js +17 -2
- package/dist/esm/components/dropdown/CDropdownToggle.js.map +1 -1
- package/dist/esm/components/dropdown/utils.d.ts +2 -0
- package/dist/esm/components/dropdown/utils.js +13 -1
- package/dist/esm/components/dropdown/utils.js.map +1 -1
- package/dist/esm/components/focus-trap/CFocusTrap.d.ts +108 -0
- package/dist/esm/components/focus-trap/CFocusTrap.js +252 -0
- package/dist/esm/components/focus-trap/CFocusTrap.js.map +1 -0
- package/dist/esm/components/focus-trap/index.d.ts +6 -0
- package/dist/esm/components/focus-trap/index.js +10 -0
- package/dist/esm/components/focus-trap/index.js.map +1 -0
- package/dist/esm/components/focus-trap/utils.d.ts +28 -0
- package/dist/esm/components/focus-trap/utils.js +78 -0
- package/dist/esm/components/focus-trap/utils.js.map +1 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +2 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/components/modal/CModal.d.ts +2 -2
- package/dist/esm/components/modal/CModal.js +19 -27
- package/dist/esm/components/modal/CModal.js.map +1 -1
- package/dist/esm/components/modal/CModalHeader.js +4 -2
- package/dist/esm/components/modal/CModalHeader.js.map +1 -1
- package/dist/esm/components/nav/CNavItem.d.ts +2 -2
- package/dist/esm/components/offcanvas/COffcanvas.js +3 -2
- package/dist/esm/components/offcanvas/COffcanvas.js.map +1 -1
- package/dist/esm/components/picker/CPicker.js +3 -2
- package/dist/esm/components/picker/CPicker.js.map +1 -1
- package/dist/esm/components/time-picker/CTimePicker.d.ts +45 -1
- package/dist/esm/components/time-picker/CTimePicker.js +64 -8
- package/dist/esm/components/time-picker/CTimePicker.js.map +1 -1
- package/dist/esm/components/time-picker/CTimePickerRollCol.d.ts +19 -7
- package/dist/esm/components/time-picker/CTimePickerRollCol.js +80 -8
- package/dist/esm/components/time-picker/CTimePickerRollCol.js.map +1 -1
- package/dist/esm/components/time-picker/utils.d.ts +1 -1
- package/dist/esm/composables/useDebouncedCallback.d.ts +1 -1
- package/dist/esm/composables/useDebouncedCallback.js +1 -1
- package/dist/esm/composables/useDebouncedCallback.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +5 -5
- package/src/components/calendar/CCalendar.ts +61 -70
- package/src/components/calendar/utils.ts +595 -47
- package/src/components/date-range-picker/CDateRangePicker.ts +131 -82
- package/src/components/date-range-picker/utils.ts +0 -58
- package/src/components/dropdown/CDropdown.ts +119 -52
- package/src/components/dropdown/CDropdownToggle.ts +18 -3
- package/src/components/dropdown/utils.ts +21 -0
- package/src/components/focus-trap/CFocusTrap.ts +303 -0
- package/src/components/focus-trap/index.ts +10 -0
- package/src/components/focus-trap/utils.ts +90 -0
- package/src/components/index.ts +1 -0
- package/src/components/modal/CModal.ts +32 -37
- package/src/components/modal/CModalHeader.ts +5 -3
- package/src/components/nav/CNavItem.ts +1 -1
- package/src/components/offcanvas/COffcanvas.ts +40 -36
- package/src/components/picker/CPicker.ts +58 -52
- package/src/components/time-picker/CTimePicker.ts +80 -22
- package/src/components/time-picker/CTimePickerRollCol.ts +87 -9
- package/src/composables/useDebouncedCallback.ts +1 -1
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { defineComponent, h, onMounted, PropType, ref, watch } from 'vue'
|
|
1
|
+
import { defineComponent, h, onMounted, PropType, Ref, ref, watch } from 'vue'
|
|
2
2
|
|
|
3
3
|
import { CButton } from '../button'
|
|
4
4
|
import { CCalendar } from '../calendar'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
convertToDateObject,
|
|
7
|
+
getDateBySelectionType,
|
|
8
|
+
getLocalDateFromString,
|
|
9
|
+
isDateDisabled,
|
|
10
|
+
} from '../calendar/utils'
|
|
6
11
|
import { CFormControlWrapper } from './../form/CFormControlWrapper'
|
|
7
12
|
import { CPicker } from '../picker'
|
|
8
13
|
import { CTimePicker } from '../time-picker'
|
|
9
14
|
|
|
10
|
-
import { getInputIdOrName
|
|
15
|
+
import { getInputIdOrName } from './utils'
|
|
11
16
|
|
|
12
17
|
import { useDebouncedCallback } from '../../composables'
|
|
13
18
|
import { Color } from '../props'
|
|
@@ -649,9 +654,17 @@ const CDateRangePicker = defineComponent({
|
|
|
649
654
|
|
|
650
655
|
const formatDate = (date: Date | string) => {
|
|
651
656
|
if (props.inputDateFormat) {
|
|
652
|
-
|
|
657
|
+
const convertedDate =
|
|
653
658
|
date instanceof Date ? new Date(date) : convertToDateObject(date, props.selectionType)
|
|
654
|
-
|
|
659
|
+
|
|
660
|
+
if (
|
|
661
|
+
!convertedDate ||
|
|
662
|
+
(convertedDate instanceof Date && Number.isNaN(convertedDate.getTime()))
|
|
663
|
+
) {
|
|
664
|
+
return ''
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
return props.inputDateFormat(convertedDate)
|
|
655
668
|
}
|
|
656
669
|
|
|
657
670
|
if (props.selectionType !== 'day') {
|
|
@@ -659,13 +672,20 @@ const CDateRangePicker = defineComponent({
|
|
|
659
672
|
}
|
|
660
673
|
|
|
661
674
|
const _date = new Date(date)
|
|
675
|
+
if (Number.isNaN(_date.getTime())) {
|
|
676
|
+
return ''
|
|
677
|
+
}
|
|
662
678
|
|
|
663
679
|
return props.timepicker
|
|
664
680
|
? _date.toLocaleString(props.locale)
|
|
665
681
|
: _date.toLocaleDateString(props.locale)
|
|
666
682
|
}
|
|
667
683
|
|
|
668
|
-
const setInputValue = (date: Date | string | null) => {
|
|
684
|
+
const setInputValue = (date: Date | string | null, value?: Ref<HTMLInputElement>) => {
|
|
685
|
+
if (date instanceof Date && isNaN(date.getTime())) {
|
|
686
|
+
return value?.value
|
|
687
|
+
}
|
|
688
|
+
|
|
669
689
|
if (date) {
|
|
670
690
|
return formatDate(date)
|
|
671
691
|
}
|
|
@@ -750,24 +770,118 @@ const CDateRangePicker = defineComponent({
|
|
|
750
770
|
}
|
|
751
771
|
|
|
752
772
|
const handleOnChange = (value: string, input: string) => {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
773
|
+
let date: Date | string | null = null
|
|
774
|
+
|
|
775
|
+
if (props.inputDateParse) {
|
|
776
|
+
date = props.inputDateParse(value)
|
|
777
|
+
} else if (props.selectionType === 'day') {
|
|
778
|
+
date = getLocalDateFromString(value, props.locale, props.timepicker)
|
|
779
|
+
} else {
|
|
780
|
+
date = convertToDateObject(value, props.selectionType)
|
|
781
|
+
}
|
|
782
|
+
|
|
756
783
|
if (date instanceof Date && date.getTime()) {
|
|
784
|
+
if (
|
|
785
|
+
isDateDisabled(
|
|
786
|
+
date,
|
|
787
|
+
props.minDate ? convertToDateObject(props.minDate, props.selectionType) : null,
|
|
788
|
+
props.maxDate ? convertToDateObject(props.maxDate, props.selectionType) : null,
|
|
789
|
+
props.disabledDates
|
|
790
|
+
)
|
|
791
|
+
) {
|
|
792
|
+
return // Don't update if date is disabled
|
|
793
|
+
}
|
|
794
|
+
|
|
757
795
|
calendarDate.value = date
|
|
758
796
|
}
|
|
759
797
|
|
|
798
|
+
let formatedDate: Date | string | null = date ?? null
|
|
799
|
+
|
|
800
|
+
if (date instanceof Date && date.getTime() && props.selectionType !== 'day') {
|
|
801
|
+
formatedDate = getDateBySelectionType(date, props.selectionType)
|
|
802
|
+
}
|
|
803
|
+
|
|
760
804
|
if (input === 'start') {
|
|
761
|
-
startDate.value =
|
|
762
|
-
emit('start-date-change',
|
|
763
|
-
emit('update:start-date',
|
|
805
|
+
startDate.value = formatedDate ?? null
|
|
806
|
+
emit('start-date-change', formatedDate ?? null)
|
|
807
|
+
emit('update:start-date', formatedDate ?? null)
|
|
764
808
|
} else {
|
|
765
|
-
endDate.value =
|
|
766
|
-
emit('end-date-change',
|
|
767
|
-
emit('update:end-date',
|
|
809
|
+
endDate.value = formatedDate ?? null
|
|
810
|
+
emit('end-date-change', formatedDate ?? null)
|
|
811
|
+
emit('update:end-date', formatedDate ?? null)
|
|
768
812
|
}
|
|
769
813
|
}
|
|
770
814
|
|
|
815
|
+
const createInputElement = (position: 'start' | 'end') => {
|
|
816
|
+
const isStart = position === 'start'
|
|
817
|
+
const hoverValue = isStart ? inputStartHoverValue.value : inputEndHoverValue.value
|
|
818
|
+
const dateValue = isStart ? startDate.value : endDate.value
|
|
819
|
+
const inputRef = isStart ? inputStartRef : inputEndRef
|
|
820
|
+
|
|
821
|
+
return h('input', {
|
|
822
|
+
autocomplete: 'off',
|
|
823
|
+
class: [
|
|
824
|
+
'date-picker-input',
|
|
825
|
+
{
|
|
826
|
+
hover: hoverValue,
|
|
827
|
+
},
|
|
828
|
+
],
|
|
829
|
+
disabled: props.disabled,
|
|
830
|
+
...(props.id && { id: getInputIdOrName(props.id, props.range, position) }),
|
|
831
|
+
...(props.name && { name: getInputIdOrName(props.name, props.range, position) }),
|
|
832
|
+
...(props.id &&
|
|
833
|
+
!Array.isArray(props.id) &&
|
|
834
|
+
!props.name && {
|
|
835
|
+
name: isStart
|
|
836
|
+
? props.range
|
|
837
|
+
? `${props.id}-start-date`
|
|
838
|
+
: `${props.id}-date`
|
|
839
|
+
: `${props.id}-end-date`,
|
|
840
|
+
}), // TODO: remove in v6
|
|
841
|
+
onClick: () => {
|
|
842
|
+
selectEndDate.value = !isStart
|
|
843
|
+
},
|
|
844
|
+
onChange: (event: Event) =>
|
|
845
|
+
handleOnChange((event.target as HTMLInputElement).value, position),
|
|
846
|
+
onInput: useDebouncedCallback(
|
|
847
|
+
(event: Event) => handleOnChange((event.target as HTMLInputElement).value, position),
|
|
848
|
+
props.inputOnChangeDelay
|
|
849
|
+
),
|
|
850
|
+
placeholder: Array.isArray(props.placeholder)
|
|
851
|
+
? props.placeholder[isStart ? 0 : 1]
|
|
852
|
+
: props.placeholder,
|
|
853
|
+
readonly: props.inputReadOnly || typeof props.format === 'string',
|
|
854
|
+
required: props.required,
|
|
855
|
+
ref: inputRef,
|
|
856
|
+
value: setInputValue(dateValue, inputRef.value),
|
|
857
|
+
})
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const createPreviewInput = (position: 'start' | 'end') => {
|
|
861
|
+
const isStart = position === 'start'
|
|
862
|
+
const hoverValue = isStart ? inputStartHoverValue.value : inputEndHoverValue.value
|
|
863
|
+
|
|
864
|
+
return (
|
|
865
|
+
hoverValue &&
|
|
866
|
+
h('input', {
|
|
867
|
+
class: 'date-picker-input date-picker-input-preview',
|
|
868
|
+
disabled: props.disabled,
|
|
869
|
+
readonly: true,
|
|
870
|
+
tabIndex: -1,
|
|
871
|
+
value: hoverValue ? setInputValue(hoverValue) : '',
|
|
872
|
+
})
|
|
873
|
+
)
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
const createInputWithWrapper = (position: 'start' | 'end') => {
|
|
877
|
+
return props.previewDateOnHover
|
|
878
|
+
? h('div', { class: 'date-picker-input-wrapper' }, [
|
|
879
|
+
createInputElement(position),
|
|
880
|
+
createPreviewInput(position),
|
|
881
|
+
])
|
|
882
|
+
: createInputElement(position)
|
|
883
|
+
}
|
|
884
|
+
|
|
771
885
|
const InputGroup = () =>
|
|
772
886
|
h(
|
|
773
887
|
'div',
|
|
@@ -775,74 +889,9 @@ const CDateRangePicker = defineComponent({
|
|
|
775
889
|
class: 'date-picker-input-group',
|
|
776
890
|
},
|
|
777
891
|
[
|
|
778
|
-
|
|
779
|
-
autocomplete: 'off',
|
|
780
|
-
class: [
|
|
781
|
-
'date-picker-input',
|
|
782
|
-
{
|
|
783
|
-
hover: inputStartHoverValue.value,
|
|
784
|
-
},
|
|
785
|
-
],
|
|
786
|
-
disabled: props.disabled,
|
|
787
|
-
...(props.id && { id: getInputIdOrName(props.id, props.range, 'start') }),
|
|
788
|
-
...(props.name && { name: getInputIdOrName(props.name, props.range, 'start') }),
|
|
789
|
-
...(props.id &&
|
|
790
|
-
!Array.isArray(props.id) &&
|
|
791
|
-
!props.name && { name: props.range ? `${props.id}-start-date` : `${props.id}-date` }), // TODO: remove in v6
|
|
792
|
-
onClick: () => {
|
|
793
|
-
selectEndDate.value = false
|
|
794
|
-
},
|
|
795
|
-
onChange: (event: Event) =>
|
|
796
|
-
handleOnChange((event.target as HTMLInputElement).value, 'start'),
|
|
797
|
-
onInput: (event: Event) =>
|
|
798
|
-
useDebouncedCallback(
|
|
799
|
-
() => handleOnChange((event.target as HTMLInputElement).value, 'start'),
|
|
800
|
-
props.inputOnChangeDelay
|
|
801
|
-
),
|
|
802
|
-
placeholder: Array.isArray(props.placeholder)
|
|
803
|
-
? props.placeholder[0]
|
|
804
|
-
: props.placeholder,
|
|
805
|
-
readonly: props.inputReadOnly || typeof props.format === 'string',
|
|
806
|
-
required: props.required,
|
|
807
|
-
ref: inputStartRef,
|
|
808
|
-
value: inputStartHoverValue.value
|
|
809
|
-
? setInputValue(inputStartHoverValue.value)
|
|
810
|
-
: setInputValue(startDate.value),
|
|
811
|
-
}),
|
|
892
|
+
createInputWithWrapper('start'),
|
|
812
893
|
props.range && props.separator !== false && h('div', { class: 'date-picker-separator' }),
|
|
813
|
-
props.range &&
|
|
814
|
-
h('input', {
|
|
815
|
-
autocomplete: 'off',
|
|
816
|
-
class: [
|
|
817
|
-
'date-picker-input',
|
|
818
|
-
{
|
|
819
|
-
hover: inputEndHoverValue.value,
|
|
820
|
-
},
|
|
821
|
-
],
|
|
822
|
-
disabled: props.disabled,
|
|
823
|
-
...(props.id && { id: getInputIdOrName(props.id, props.range, 'end') }),
|
|
824
|
-
...(props.name && { name: getInputIdOrName(props.name, props.range, 'end') }),
|
|
825
|
-
...(props.id &&
|
|
826
|
-
!Array.isArray(props.id) &&
|
|
827
|
-
!props.name && { name: `${props.id}-end-date` }), // TODO: remove in v6
|
|
828
|
-
onClick: () => {
|
|
829
|
-
selectEndDate.value = true
|
|
830
|
-
},
|
|
831
|
-
onChange: (event: Event) =>
|
|
832
|
-
handleOnChange((event.target as HTMLInputElement).value, 'end'),
|
|
833
|
-
onInput: (event: Event) =>
|
|
834
|
-
useDebouncedCallback(
|
|
835
|
-
() => handleOnChange((event.target as HTMLInputElement).value, 'end'),
|
|
836
|
-
props.inputOnChangeDelay
|
|
837
|
-
),
|
|
838
|
-
placeholder: props.placeholder[1],
|
|
839
|
-
readonly: props.inputReadOnly || typeof props.format === 'string',
|
|
840
|
-
required: props.required,
|
|
841
|
-
ref: inputEndRef,
|
|
842
|
-
value: inputEndHoverValue.value
|
|
843
|
-
? setInputValue(inputEndHoverValue.value)
|
|
844
|
-
: setInputValue(endDate.value),
|
|
845
|
-
}),
|
|
894
|
+
props.range && createInputWithWrapper('end'),
|
|
846
895
|
props.indicator &&
|
|
847
896
|
h('div', {
|
|
848
897
|
class: 'date-picker-indicator',
|
|
@@ -21,61 +21,3 @@ export const getInputIdOrName = (
|
|
|
21
21
|
|
|
22
22
|
return attribute
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Parses a date string into a Date object based on the provided locale and time inclusion.
|
|
27
|
-
*
|
|
28
|
-
* @param dateString - The date string to parse.
|
|
29
|
-
* @param locale - The locale to use for parsing the date string.
|
|
30
|
-
* @param includeTime - Optional. Determines whether to include time in the parsed Date object.
|
|
31
|
-
* @returns A Date object representing the parsed date and time, or `undefined` if parsing fails.
|
|
32
|
-
*/
|
|
33
|
-
export const getLocalDateFromString = (
|
|
34
|
-
string: string,
|
|
35
|
-
locale: string,
|
|
36
|
-
time?: boolean
|
|
37
|
-
): Date | undefined => {
|
|
38
|
-
const date = new Date(2013, 11, 31, 17, 19, 22)
|
|
39
|
-
let regex = time ? date.toLocaleString(locale) : date.toLocaleDateString(locale)
|
|
40
|
-
regex = regex
|
|
41
|
-
.replace('2013', '(?<year>[0-9]{2,4})')
|
|
42
|
-
.replace('12', '(?<month>[0-9]{1,2})')
|
|
43
|
-
.replace('31', '(?<day>[0-9]{1,2})')
|
|
44
|
-
|
|
45
|
-
if (time) {
|
|
46
|
-
regex = regex
|
|
47
|
-
.replace('5', '(?<hour>[0-9]{1,2})')
|
|
48
|
-
.replace('17', '(?<hour>[0-9]{1,2})')
|
|
49
|
-
.replace('19', '(?<minute>[0-9]{1,2})')
|
|
50
|
-
.replace('22', '(?<second>[0-9]{1,2})')
|
|
51
|
-
.replace('PM', '(?<ampm>[A-Z]{2})')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const rgx = new RegExp(`${regex}`)
|
|
55
|
-
const partials = string.match(rgx)
|
|
56
|
-
|
|
57
|
-
if (partials === null) return
|
|
58
|
-
|
|
59
|
-
const newDate =
|
|
60
|
-
partials.groups &&
|
|
61
|
-
(time
|
|
62
|
-
? new Date(
|
|
63
|
-
Number(partials.groups['year']),
|
|
64
|
-
Number(partials.groups['month']) - 1,
|
|
65
|
-
Number(partials.groups['day']),
|
|
66
|
-
partials.groups['ampm']
|
|
67
|
-
? partials.groups['ampm'] === 'PM'
|
|
68
|
-
? Number(partials.groups['hour']) + 12
|
|
69
|
-
: Number(partials.groups['hour'])
|
|
70
|
-
: Number(partials.groups['hour']),
|
|
71
|
-
Number(partials.groups['minute']),
|
|
72
|
-
Number(partials.groups['second'])
|
|
73
|
-
)
|
|
74
|
-
: new Date(
|
|
75
|
-
Number(partials.groups['year']),
|
|
76
|
-
Number(partials.groups['month']) - 1,
|
|
77
|
-
Number(partials.groups['day'])
|
|
78
|
-
))
|
|
79
|
-
|
|
80
|
-
return newDate
|
|
81
|
-
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
computed,
|
|
3
|
+
defineComponent,
|
|
4
|
+
h,
|
|
5
|
+
nextTick,
|
|
6
|
+
onUnmounted,
|
|
7
|
+
provide,
|
|
8
|
+
PropType,
|
|
9
|
+
ref,
|
|
10
|
+
Ref,
|
|
11
|
+
watch,
|
|
12
|
+
} from 'vue'
|
|
2
13
|
import type { Placement } from '@popperjs/core'
|
|
3
14
|
|
|
4
15
|
import { usePopper } from '../../composables'
|
|
@@ -6,7 +17,8 @@ import type { Triggers } from '../../types'
|
|
|
6
17
|
import { getNextActiveElement, isRTL } from '../../utils'
|
|
7
18
|
|
|
8
19
|
import type { Alignments } from './types'
|
|
9
|
-
import { getPlacement } from './utils'
|
|
20
|
+
import { getPlacement, getReferenceElement } from './utils'
|
|
21
|
+
import { CFocusTrap } from '../focus-trap'
|
|
10
22
|
|
|
11
23
|
const CDropdown = defineComponent({
|
|
12
24
|
name: 'CDropdown',
|
|
@@ -53,7 +65,7 @@ const CDropdown = defineComponent({
|
|
|
53
65
|
* - `'outside'` - the dropdown will be closed (only) by clicking outside the dropdown menu.
|
|
54
66
|
*/
|
|
55
67
|
autoClose: {
|
|
56
|
-
type: [Boolean, String]
|
|
68
|
+
type: [Boolean, String] as PropType<boolean | 'inside' | 'outside'>,
|
|
57
69
|
default: true,
|
|
58
70
|
validator: (value: boolean | string) => {
|
|
59
71
|
return typeof value === 'boolean' || ['inside', 'outside'].includes(value)
|
|
@@ -112,6 +124,21 @@ const CDropdown = defineComponent({
|
|
|
112
124
|
type: Boolean,
|
|
113
125
|
default: true,
|
|
114
126
|
},
|
|
127
|
+
/**
|
|
128
|
+
* Sets the reference element for positioning the Vue Dropdown Menu.
|
|
129
|
+
* - `toggle` - The Vue Dropdown Toggle button (default).
|
|
130
|
+
* - `parent` - The Vue Dropdown wrapper element.
|
|
131
|
+
* - `HTMLElement` - A custom HTML element.
|
|
132
|
+
* - `Ref` - A custom reference element.
|
|
133
|
+
*
|
|
134
|
+
* @since 5.7.0
|
|
135
|
+
*/
|
|
136
|
+
reference: {
|
|
137
|
+
type: [String, Object] as PropType<
|
|
138
|
+
'parent' | 'toggle' | HTMLElement | Ref<HTMLElement | null>
|
|
139
|
+
>,
|
|
140
|
+
default: 'toggle',
|
|
141
|
+
},
|
|
115
142
|
/**
|
|
116
143
|
* Generates dropdown menu using Teleport.
|
|
117
144
|
*
|
|
@@ -156,14 +183,16 @@ const CDropdown = defineComponent({
|
|
|
156
183
|
'show',
|
|
157
184
|
],
|
|
158
185
|
setup(props, { slots, emit }) {
|
|
159
|
-
const
|
|
160
|
-
const dropdownMenuRef = ref()
|
|
186
|
+
const dropdownRef = ref<HTMLElement | null>(null)
|
|
187
|
+
const dropdownMenuRef = ref<HTMLElement | null>(null)
|
|
188
|
+
const dropdownToggleRef = ref<HTMLElement | null>(null)
|
|
189
|
+
const pendingKeyDownEventRef = ref<KeyboardEvent | null>(null)
|
|
161
190
|
const popper = ref(typeof props.alignment === 'object' ? false : props.popper)
|
|
162
191
|
const visible = ref(props.visible)
|
|
163
192
|
|
|
164
193
|
const { initPopper, destroyPopper } = usePopper()
|
|
165
194
|
|
|
166
|
-
const popperConfig = {
|
|
195
|
+
const popperConfig = computed(() => ({
|
|
167
196
|
modifiers: [
|
|
168
197
|
{
|
|
169
198
|
name: 'offset',
|
|
@@ -176,37 +205,62 @@ const CDropdown = defineComponent({
|
|
|
176
205
|
props.placement,
|
|
177
206
|
props.direction,
|
|
178
207
|
props.alignment,
|
|
179
|
-
isRTL(dropdownMenuRef.value)
|
|
208
|
+
isRTL(dropdownMenuRef.value)
|
|
180
209
|
) as Placement,
|
|
181
|
-
}
|
|
210
|
+
}))
|
|
182
211
|
|
|
183
212
|
watch(
|
|
184
213
|
() => props.visible,
|
|
185
214
|
() => {
|
|
186
215
|
visible.value = props.visible
|
|
187
|
-
}
|
|
216
|
+
}
|
|
188
217
|
)
|
|
189
218
|
|
|
190
219
|
watch(visible, () => {
|
|
191
220
|
if (visible.value && dropdownToggleRef.value && dropdownMenuRef.value) {
|
|
192
|
-
|
|
193
|
-
|
|
221
|
+
const referenceElement = getReferenceElement(
|
|
222
|
+
props.reference,
|
|
223
|
+
dropdownToggleRef,
|
|
224
|
+
dropdownRef
|
|
225
|
+
)
|
|
226
|
+
if (referenceElement && popper.value) {
|
|
227
|
+
initPopper(referenceElement, dropdownMenuRef.value, popperConfig.value)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
window.addEventListener('click', handleClick)
|
|
194
231
|
window.addEventListener('keyup', handleKeyup)
|
|
195
232
|
dropdownToggleRef.value.addEventListener('keydown', handleKeydown)
|
|
196
233
|
dropdownMenuRef.value.addEventListener('keydown', handleKeydown)
|
|
234
|
+
|
|
235
|
+
if (pendingKeyDownEventRef.value) {
|
|
236
|
+
nextTick(() => {
|
|
237
|
+
handleKeydown(pendingKeyDownEventRef.value as KeyboardEvent)
|
|
238
|
+
pendingKeyDownEventRef.value = null
|
|
239
|
+
})
|
|
240
|
+
}
|
|
241
|
+
|
|
197
242
|
emit('show')
|
|
198
243
|
return
|
|
199
244
|
}
|
|
200
245
|
|
|
201
|
-
popper.value
|
|
202
|
-
|
|
246
|
+
if (popper.value) {
|
|
247
|
+
destroyPopper()
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
window.removeEventListener('click', handleClick)
|
|
203
251
|
window.removeEventListener('keyup', handleKeyup)
|
|
252
|
+
dropdownMenuRef.value && dropdownMenuRef.value.removeEventListener('keydown', handleKeydown)
|
|
204
253
|
dropdownToggleRef.value &&
|
|
205
254
|
dropdownToggleRef.value.removeEventListener('keydown', handleKeydown)
|
|
206
|
-
dropdownMenuRef.value && dropdownMenuRef.value.removeEventListener('keydown', handleKeydown)
|
|
207
255
|
emit('hide')
|
|
208
256
|
})
|
|
209
257
|
|
|
258
|
+
onUnmounted(() => {
|
|
259
|
+
dropdownToggleRef.value &&
|
|
260
|
+
dropdownToggleRef.value.removeEventListener('keydown', handleKeydown)
|
|
261
|
+
dropdownMenuRef.value && dropdownMenuRef.value.removeEventListener('keydown', handleKeydown)
|
|
262
|
+
})
|
|
263
|
+
|
|
210
264
|
provide('config', {
|
|
211
265
|
alignment: props.alignment,
|
|
212
266
|
container: props.container,
|
|
@@ -219,18 +273,14 @@ const CDropdown = defineComponent({
|
|
|
219
273
|
provide('visible', visible)
|
|
220
274
|
provide('dropdownToggleRef', dropdownToggleRef)
|
|
221
275
|
provide('dropdownMenuRef', dropdownMenuRef)
|
|
276
|
+
provide('pendingKeyDownEventRef', pendingKeyDownEventRef)
|
|
222
277
|
|
|
223
278
|
const handleKeydown = (event: KeyboardEvent) => {
|
|
224
|
-
if (
|
|
225
|
-
visible.value &&
|
|
226
|
-
dropdownMenuRef.value &&
|
|
227
|
-
(event.key === 'ArrowDown' || event.key === 'ArrowUp')
|
|
228
|
-
) {
|
|
279
|
+
if (dropdownMenuRef.value && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
|
|
229
280
|
event.preventDefault()
|
|
230
281
|
const target = event.target as HTMLElement
|
|
231
|
-
// eslint-disable-next-line unicorn/prefer-spread
|
|
232
282
|
const items: HTMLElement[] = Array.from(
|
|
233
|
-
dropdownMenuRef.value.querySelectorAll('.dropdown-item:not(.disabled):not(:disabled)')
|
|
283
|
+
dropdownMenuRef.value.querySelectorAll('.dropdown-item:not(.disabled):not(:disabled)')
|
|
234
284
|
)
|
|
235
285
|
getNextActiveElement(items, target, event.key === 'ArrowDown', true).focus()
|
|
236
286
|
}
|
|
@@ -243,67 +293,84 @@ const CDropdown = defineComponent({
|
|
|
243
293
|
|
|
244
294
|
if (event.key === 'Escape') {
|
|
245
295
|
setVisible(false)
|
|
296
|
+
dropdownToggleRef.value?.focus()
|
|
246
297
|
}
|
|
247
298
|
}
|
|
248
299
|
|
|
249
|
-
const
|
|
300
|
+
const handleClick = (event: Event) => {
|
|
250
301
|
if (!dropdownToggleRef.value || !dropdownMenuRef.value) {
|
|
251
302
|
return
|
|
252
303
|
}
|
|
253
304
|
|
|
254
|
-
if (
|
|
305
|
+
if ((event as MouseEvent).button === 2) {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const composedPath = event.composedPath()
|
|
310
|
+
const isOnToggle = composedPath.includes(dropdownToggleRef.value)
|
|
311
|
+
const isOnMenu = composedPath.includes(dropdownMenuRef.value)
|
|
312
|
+
|
|
313
|
+
if (isOnToggle) {
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const target = event.target as HTMLElement | null
|
|
318
|
+
const FORM_TAG_RE = /^(input|select|option|textarea|form|button|label)$/i
|
|
319
|
+
|
|
320
|
+
if (isOnMenu && target && FORM_TAG_RE.test(target.tagName)) {
|
|
255
321
|
return
|
|
256
322
|
}
|
|
257
323
|
|
|
258
324
|
if (
|
|
259
325
|
props.autoClose === true ||
|
|
260
|
-
(props.autoClose === 'inside' &&
|
|
261
|
-
|
|
262
|
-
(props.autoClose === 'outside' &&
|
|
263
|
-
!dropdownMenuRef.value.contains(event.target as HTMLElement))
|
|
326
|
+
(props.autoClose === 'inside' && isOnMenu) ||
|
|
327
|
+
(props.autoClose === 'outside' && !isOnMenu)
|
|
264
328
|
) {
|
|
265
329
|
setVisible(false)
|
|
266
|
-
return
|
|
267
330
|
}
|
|
268
331
|
}
|
|
269
332
|
|
|
270
|
-
const setVisible = (_visible?: boolean) => {
|
|
333
|
+
const setVisible = (_visible?: boolean, event?: KeyboardEvent) => {
|
|
271
334
|
if (props.disabled) {
|
|
272
335
|
return
|
|
273
336
|
}
|
|
274
337
|
|
|
275
|
-
if (typeof _visible
|
|
338
|
+
if (typeof _visible === 'boolean') {
|
|
339
|
+
if (event) {
|
|
340
|
+
pendingKeyDownEventRef.value = event || null
|
|
341
|
+
}
|
|
342
|
+
|
|
276
343
|
visible.value = _visible
|
|
277
|
-
return
|
|
278
|
-
}
|
|
279
344
|
|
|
280
|
-
if (visible.value === true) {
|
|
281
|
-
visible.value = false
|
|
282
345
|
return
|
|
283
346
|
}
|
|
284
|
-
|
|
285
|
-
visible.value = true
|
|
286
347
|
}
|
|
287
348
|
|
|
288
349
|
provide('setVisible', setVisible)
|
|
289
350
|
|
|
290
351
|
return () =>
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
:
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
352
|
+
h(
|
|
353
|
+
CFocusTrap,
|
|
354
|
+
{ active: props.teleport && visible.value, additionalContainer: dropdownMenuRef },
|
|
355
|
+
() =>
|
|
356
|
+
props.variant === 'input-group'
|
|
357
|
+
? [slots.default && slots.default()]
|
|
358
|
+
: h(
|
|
359
|
+
'div',
|
|
360
|
+
{
|
|
361
|
+
class: [
|
|
362
|
+
props.variant === 'nav-item' ? 'nav-item dropdown' : props.variant,
|
|
363
|
+
props.direction === 'center'
|
|
364
|
+
? 'dropdown-center'
|
|
365
|
+
: props.direction === 'dropup-center'
|
|
366
|
+
? 'dropup dropup-center'
|
|
367
|
+
: props.direction,
|
|
368
|
+
],
|
|
369
|
+
ref: dropdownRef,
|
|
370
|
+
},
|
|
371
|
+
slots.default && slots.default()
|
|
372
|
+
)
|
|
373
|
+
)
|
|
307
374
|
},
|
|
308
375
|
})
|
|
309
376
|
|
|
@@ -74,6 +74,15 @@ const CDropdownToggle = defineComponent({
|
|
|
74
74
|
* Similarly, create split button dropdowns with virtually the same markup as single button dropdowns, but with the addition of `.dropdown-toggle-split` className for proper spacing around the dropdown caret.
|
|
75
75
|
*/
|
|
76
76
|
split: Boolean,
|
|
77
|
+
/**
|
|
78
|
+
* Screen reader label for split button dropdown toggle.
|
|
79
|
+
*
|
|
80
|
+
* @since 5.7.0
|
|
81
|
+
*/
|
|
82
|
+
splitLabel: {
|
|
83
|
+
type: String,
|
|
84
|
+
default: 'Toggle Dropdown',
|
|
85
|
+
},
|
|
77
86
|
/**
|
|
78
87
|
* Sets which event handlers you’d like provided to your toggle prop. You can specify one trigger or an array of them.
|
|
79
88
|
*
|
|
@@ -100,7 +109,7 @@ const CDropdownToggle = defineComponent({
|
|
|
100
109
|
const dropdownToggleRef = inject('dropdownToggleRef') as Ref<HTMLElement>
|
|
101
110
|
const dropdownVariant = inject('variant') as string
|
|
102
111
|
const visible = inject('visible') as Ref<boolean>
|
|
103
|
-
const setVisible = inject('setVisible') as (_visible?: boolean) => void
|
|
112
|
+
const setVisible = inject('setVisible') as (_visible?: boolean, event?: KeyboardEvent) => void
|
|
104
113
|
|
|
105
114
|
const triggers = {
|
|
106
115
|
...((props.trigger === 'click' || props.trigger.includes('click')) && {
|
|
@@ -110,7 +119,7 @@ const CDropdownToggle = defineComponent({
|
|
|
110
119
|
return
|
|
111
120
|
}
|
|
112
121
|
|
|
113
|
-
setVisible()
|
|
122
|
+
setVisible(!visible.value)
|
|
114
123
|
},
|
|
115
124
|
}),
|
|
116
125
|
...((props.trigger === 'focus' || props.trigger.includes('focus')) && {
|
|
@@ -128,6 +137,12 @@ const CDropdownToggle = defineComponent({
|
|
|
128
137
|
setVisible(false)
|
|
129
138
|
},
|
|
130
139
|
}),
|
|
140
|
+
onkeydown: (event: KeyboardEvent) => {
|
|
141
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
142
|
+
event.preventDefault()
|
|
143
|
+
setVisible(true, event)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
131
146
|
}
|
|
132
147
|
|
|
133
148
|
const togglerProps = computed(() => {
|
|
@@ -188,7 +203,7 @@ const CDropdownToggle = defineComponent({
|
|
|
188
203
|
},
|
|
189
204
|
() =>
|
|
190
205
|
props.split
|
|
191
|
-
? h('span', { class: 'visually-hidden' },
|
|
206
|
+
? h('span', { class: 'visually-hidden' }, props.splitLabel)
|
|
192
207
|
: slots.default && slots.default(),
|
|
193
208
|
)
|
|
194
209
|
},
|