@coreui/vue-pro 5.14.0 → 5.15.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.
Files changed (106) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/calendar/CCalendar.js +61 -65
  3. package/dist/cjs/components/calendar/CCalendar.js.map +1 -1
  4. package/dist/cjs/components/calendar/utils.d.ts +53 -2
  5. package/dist/cjs/components/calendar/utils.js +466 -43
  6. package/dist/cjs/components/calendar/utils.js.map +1 -1
  7. package/dist/cjs/components/date-range-picker/CDateRangePicker.js +86 -57
  8. package/dist/cjs/components/date-range-picker/CDateRangePicker.js.map +1 -1
  9. package/dist/cjs/components/date-range-picker/utils.d.ts +0 -9
  10. package/dist/cjs/components/date-range-picker/utils.js +0 -38
  11. package/dist/cjs/components/date-range-picker/utils.js.map +1 -1
  12. package/dist/cjs/components/dropdown/CDropdown.js +22 -13
  13. package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
  14. package/dist/cjs/components/dropdown/CDropdownToggle.js +7 -1
  15. package/dist/cjs/components/dropdown/CDropdownToggle.js.map +1 -1
  16. package/dist/cjs/components/focus-trap/CFocusTrap.d.ts +108 -0
  17. package/dist/cjs/components/focus-trap/CFocusTrap.js +254 -0
  18. package/dist/cjs/components/focus-trap/CFocusTrap.js.map +1 -0
  19. package/dist/cjs/components/focus-trap/index.d.ts +6 -0
  20. package/dist/cjs/components/focus-trap/index.js +13 -0
  21. package/dist/cjs/components/focus-trap/index.js.map +1 -0
  22. package/dist/cjs/components/focus-trap/utils.d.ts +28 -0
  23. package/dist/cjs/components/focus-trap/utils.js +83 -0
  24. package/dist/cjs/components/focus-trap/utils.js.map +1 -0
  25. package/dist/cjs/components/index.d.ts +1 -0
  26. package/dist/cjs/components/index.js +70 -66
  27. package/dist/cjs/components/index.js.map +1 -1
  28. package/dist/cjs/components/modal/CModal.d.ts +2 -2
  29. package/dist/cjs/components/modal/CModal.js +19 -27
  30. package/dist/cjs/components/modal/CModal.js.map +1 -1
  31. package/dist/cjs/components/modal/CModalHeader.js +4 -2
  32. package/dist/cjs/components/modal/CModalHeader.js.map +1 -1
  33. package/dist/cjs/components/offcanvas/COffcanvas.js +3 -2
  34. package/dist/cjs/components/offcanvas/COffcanvas.js.map +1 -1
  35. package/dist/cjs/components/picker/CPicker.js +3 -2
  36. package/dist/cjs/components/picker/CPicker.js.map +1 -1
  37. package/dist/cjs/components/time-picker/CTimePicker.d.ts +1 -1
  38. package/dist/cjs/components/time-picker/CTimePicker.js +1 -1
  39. package/dist/cjs/components/time-picker/CTimePicker.js.map +1 -1
  40. package/dist/cjs/components/time-picker/utils.d.ts +1 -1
  41. package/dist/cjs/composables/useDebouncedCallback.d.ts +1 -1
  42. package/dist/cjs/composables/useDebouncedCallback.js +1 -1
  43. package/dist/cjs/composables/useDebouncedCallback.js.map +1 -1
  44. package/dist/cjs/index.js +76 -72
  45. package/dist/cjs/index.js.map +1 -1
  46. package/dist/esm/components/calendar/CCalendar.js +61 -65
  47. package/dist/esm/components/calendar/CCalendar.js.map +1 -1
  48. package/dist/esm/components/calendar/utils.d.ts +53 -2
  49. package/dist/esm/components/calendar/utils.js +464 -44
  50. package/dist/esm/components/calendar/utils.js.map +1 -1
  51. package/dist/esm/components/date-range-picker/CDateRangePicker.js +86 -57
  52. package/dist/esm/components/date-range-picker/CDateRangePicker.js.map +1 -1
  53. package/dist/esm/components/date-range-picker/utils.d.ts +0 -9
  54. package/dist/esm/components/date-range-picker/utils.js +1 -38
  55. package/dist/esm/components/date-range-picker/utils.js.map +1 -1
  56. package/dist/esm/components/dropdown/CDropdown.js +23 -14
  57. package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
  58. package/dist/esm/components/dropdown/CDropdownToggle.js +7 -1
  59. package/dist/esm/components/dropdown/CDropdownToggle.js.map +1 -1
  60. package/dist/esm/components/focus-trap/CFocusTrap.d.ts +108 -0
  61. package/dist/esm/components/focus-trap/CFocusTrap.js +252 -0
  62. package/dist/esm/components/focus-trap/CFocusTrap.js.map +1 -0
  63. package/dist/esm/components/focus-trap/index.d.ts +6 -0
  64. package/dist/esm/components/focus-trap/index.js +10 -0
  65. package/dist/esm/components/focus-trap/index.js.map +1 -0
  66. package/dist/esm/components/focus-trap/utils.d.ts +28 -0
  67. package/dist/esm/components/focus-trap/utils.js +78 -0
  68. package/dist/esm/components/focus-trap/utils.js.map +1 -0
  69. package/dist/esm/components/index.d.ts +1 -0
  70. package/dist/esm/components/index.js +2 -0
  71. package/dist/esm/components/index.js.map +1 -1
  72. package/dist/esm/components/modal/CModal.d.ts +2 -2
  73. package/dist/esm/components/modal/CModal.js +19 -27
  74. package/dist/esm/components/modal/CModal.js.map +1 -1
  75. package/dist/esm/components/modal/CModalHeader.js +4 -2
  76. package/dist/esm/components/modal/CModalHeader.js.map +1 -1
  77. package/dist/esm/components/offcanvas/COffcanvas.js +3 -2
  78. package/dist/esm/components/offcanvas/COffcanvas.js.map +1 -1
  79. package/dist/esm/components/picker/CPicker.js +3 -2
  80. package/dist/esm/components/picker/CPicker.js.map +1 -1
  81. package/dist/esm/components/time-picker/CTimePicker.d.ts +1 -1
  82. package/dist/esm/components/time-picker/CTimePicker.js +1 -1
  83. package/dist/esm/components/time-picker/CTimePicker.js.map +1 -1
  84. package/dist/esm/components/time-picker/utils.d.ts +1 -1
  85. package/dist/esm/composables/useDebouncedCallback.d.ts +1 -1
  86. package/dist/esm/composables/useDebouncedCallback.js +1 -1
  87. package/dist/esm/composables/useDebouncedCallback.js.map +1 -1
  88. package/dist/esm/index.js +2 -0
  89. package/dist/esm/index.js.map +1 -1
  90. package/package.json +4 -4
  91. package/src/components/calendar/CCalendar.ts +55 -70
  92. package/src/components/calendar/utils.ts +595 -47
  93. package/src/components/date-range-picker/CDateRangePicker.ts +131 -82
  94. package/src/components/date-range-picker/utils.ts +0 -58
  95. package/src/components/dropdown/CDropdown.ts +34 -23
  96. package/src/components/dropdown/CDropdownToggle.ts +8 -2
  97. package/src/components/focus-trap/CFocusTrap.ts +303 -0
  98. package/src/components/focus-trap/index.ts +10 -0
  99. package/src/components/focus-trap/utils.ts +90 -0
  100. package/src/components/index.ts +1 -0
  101. package/src/components/modal/CModal.ts +32 -37
  102. package/src/components/modal/CModalHeader.ts +5 -3
  103. package/src/components/offcanvas/COffcanvas.ts +40 -36
  104. package/src/components/picker/CPicker.ts +58 -52
  105. package/src/components/time-picker/CTimePicker.ts +12 -13
  106. 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 { convertToDateObject } from '../calendar/utils'
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, getLocalDateFromString } from './utils'
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
- return props.inputDateFormat(
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
- const date = props.inputDateParse
754
- ? props.inputDateParse(value)
755
- : getLocalDateFromString(value, props.locale, props.timepicker)
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 = date ?? null
762
- emit('start-date-change', date ?? null)
763
- emit('update:start-date', date ?? null)
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 = date ?? null
766
- emit('end-date-change', date ?? null)
767
- emit('update:end-date', date ?? null)
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
- h('input', {
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,4 @@
1
- import { defineComponent, h, ref, provide, watch, PropType } from 'vue'
1
+ import { defineComponent, h, ref, provide, watch, PropType, onUnmounted, nextTick } from 'vue'
2
2
  import type { Placement } from '@popperjs/core'
3
3
 
4
4
  import { usePopper } from '../../composables'
@@ -158,6 +158,7 @@ const CDropdown = defineComponent({
158
158
  setup(props, { slots, emit }) {
159
159
  const dropdownToggleRef = ref()
160
160
  const dropdownMenuRef = ref()
161
+ const pendingKeyDownEventRef = ref<KeyboardEvent | null>(null)
161
162
  const popper = ref(typeof props.alignment === 'object' ? false : props.popper)
162
163
  const visible = ref(props.visible)
163
164
 
@@ -176,7 +177,7 @@ const CDropdown = defineComponent({
176
177
  props.placement,
177
178
  props.direction,
178
179
  props.alignment,
179
- isRTL(dropdownMenuRef.value),
180
+ isRTL(dropdownMenuRef.value)
180
181
  ) as Placement,
181
182
  }
182
183
 
@@ -184,16 +185,27 @@ const CDropdown = defineComponent({
184
185
  () => props.visible,
185
186
  () => {
186
187
  visible.value = props.visible
187
- },
188
+ }
188
189
  )
189
190
 
190
191
  watch(visible, () => {
191
192
  if (visible.value && dropdownToggleRef.value && dropdownMenuRef.value) {
192
- popper.value && initPopper(dropdownToggleRef.value, dropdownMenuRef.value, popperConfig)
193
+ if (popper.value) {
194
+ initPopper(dropdownToggleRef.value, dropdownMenuRef.value, popperConfig)
195
+ }
196
+
193
197
  window.addEventListener('mouseup', handleMouseUp)
194
198
  window.addEventListener('keyup', handleKeyup)
195
199
  dropdownToggleRef.value.addEventListener('keydown', handleKeydown)
196
200
  dropdownMenuRef.value.addEventListener('keydown', handleKeydown)
201
+
202
+ if (pendingKeyDownEventRef.value) {
203
+ nextTick(() => {
204
+ handleKeydown(pendingKeyDownEventRef.value as KeyboardEvent)
205
+ pendingKeyDownEventRef.value = null
206
+ })
207
+ }
208
+
197
209
  emit('show')
198
210
  return
199
211
  }
@@ -201,10 +213,14 @@ const CDropdown = defineComponent({
201
213
  popper.value && destroyPopper()
202
214
  window.removeEventListener('mouseup', handleMouseUp)
203
215
  window.removeEventListener('keyup', handleKeyup)
216
+ dropdownMenuRef.value && dropdownMenuRef.value.removeEventListener('keydown', handleKeydown)
217
+ emit('hide')
218
+ })
219
+
220
+ onUnmounted(() => {
204
221
  dropdownToggleRef.value &&
205
222
  dropdownToggleRef.value.removeEventListener('keydown', handleKeydown)
206
223
  dropdownMenuRef.value && dropdownMenuRef.value.removeEventListener('keydown', handleKeydown)
207
- emit('hide')
208
224
  })
209
225
 
210
226
  provide('config', {
@@ -219,18 +235,14 @@ const CDropdown = defineComponent({
219
235
  provide('visible', visible)
220
236
  provide('dropdownToggleRef', dropdownToggleRef)
221
237
  provide('dropdownMenuRef', dropdownMenuRef)
238
+ provide('pendingKeyDownEventRef', pendingKeyDownEventRef)
222
239
 
223
240
  const handleKeydown = (event: KeyboardEvent) => {
224
- if (
225
- visible.value &&
226
- dropdownMenuRef.value &&
227
- (event.key === 'ArrowDown' || event.key === 'ArrowUp')
228
- ) {
241
+ if (dropdownMenuRef.value && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
229
242
  event.preventDefault()
230
243
  const target = event.target as HTMLElement
231
- // eslint-disable-next-line unicorn/prefer-spread
232
244
  const items: HTMLElement[] = Array.from(
233
- dropdownMenuRef.value.querySelectorAll('.dropdown-item:not(.disabled):not(:disabled)'),
245
+ dropdownMenuRef.value.querySelectorAll('.dropdown-item:not(.disabled):not(:disabled)')
234
246
  )
235
247
  getNextActiveElement(items, target, event.key === 'ArrowDown', true).focus()
236
248
  }
@@ -243,6 +255,7 @@ const CDropdown = defineComponent({
243
255
 
244
256
  if (event.key === 'Escape') {
245
257
  setVisible(false)
258
+ dropdownToggleRef.value?.focus()
246
259
  }
247
260
  }
248
261
 
@@ -267,22 +280,20 @@ const CDropdown = defineComponent({
267
280
  }
268
281
  }
269
282
 
270
- const setVisible = (_visible?: boolean) => {
283
+ const setVisible = (_visible?: boolean, event?: KeyboardEvent) => {
271
284
  if (props.disabled) {
272
285
  return
273
286
  }
274
287
 
275
- if (typeof _visible == 'boolean') {
288
+ if (typeof _visible === 'boolean') {
289
+ if (event) {
290
+ pendingKeyDownEventRef.value = event || null
291
+ }
292
+
276
293
  visible.value = _visible
277
- return
278
- }
279
294
 
280
- if (visible.value === true) {
281
- visible.value = false
282
295
  return
283
296
  }
284
-
285
- visible.value = true
286
297
  }
287
298
 
288
299
  provide('setVisible', setVisible)
@@ -298,11 +309,11 @@ const CDropdown = defineComponent({
298
309
  props.direction === 'center'
299
310
  ? 'dropdown-center'
300
311
  : props.direction === 'dropup-center'
301
- ? 'dropup dropup-center'
302
- : props.direction,
312
+ ? 'dropup dropup-center'
313
+ : props.direction,
303
314
  ],
304
315
  },
305
- slots.default && slots.default(),
316
+ slots.default && slots.default()
306
317
  )
307
318
  },
308
319
  })
@@ -100,7 +100,7 @@ const CDropdownToggle = defineComponent({
100
100
  const dropdownToggleRef = inject('dropdownToggleRef') as Ref<HTMLElement>
101
101
  const dropdownVariant = inject('variant') as string
102
102
  const visible = inject('visible') as Ref<boolean>
103
- const setVisible = inject('setVisible') as (_visible?: boolean) => void
103
+ const setVisible = inject('setVisible') as (_visible?: boolean, event?: KeyboardEvent) => void
104
104
 
105
105
  const triggers = {
106
106
  ...((props.trigger === 'click' || props.trigger.includes('click')) && {
@@ -110,7 +110,7 @@ const CDropdownToggle = defineComponent({
110
110
  return
111
111
  }
112
112
 
113
- setVisible()
113
+ setVisible(!visible.value)
114
114
  },
115
115
  }),
116
116
  ...((props.trigger === 'focus' || props.trigger.includes('focus')) && {
@@ -128,6 +128,12 @@ const CDropdownToggle = defineComponent({
128
128
  setVisible(false)
129
129
  },
130
130
  }),
131
+ onkeydown: (event: KeyboardEvent) => {
132
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
133
+ event.preventDefault()
134
+ setVisible(true, event)
135
+ }
136
+ }
131
137
  }
132
138
 
133
139
  const togglerProps = computed(() => {