@coreui/vue-pro 4.9.0-beta.2 → 4.9.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 (34) hide show
  1. package/README.md +1 -1
  2. package/dist/components/dropdown/CDropdown.d.ts +62 -4
  3. package/dist/components/dropdown/CDropdownToggle.d.ts +1 -1
  4. package/dist/components/multi-select/CMultiSelect.d.ts +6 -6
  5. package/dist/components/popover/CPopover.d.ts +75 -6
  6. package/dist/components/toast/CToast.d.ts +1 -1
  7. package/dist/components/tooltip/CTooltip.d.ts +77 -8
  8. package/dist/composables/index.d.ts +2 -2
  9. package/dist/composables/useColorModes.d.ts +1 -1
  10. package/dist/composables/usePopper.d.ts +6 -0
  11. package/dist/index.es.js +424 -325
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.js +423 -324
  14. package/dist/index.js.map +1 -1
  15. package/dist/types.d.ts +1 -1
  16. package/dist/utils/getRTLPlacement.d.ts +3 -0
  17. package/dist/utils/index.d.ts +2 -1
  18. package/package.json +10 -10
  19. package/src/components/date-range-picker/CDateRangePicker.ts +50 -17
  20. package/src/components/dropdown/CDropdown.ts +116 -61
  21. package/src/components/dropdown/CDropdownMenu.ts +2 -47
  22. package/src/components/dropdown/CDropdownToggle.ts +5 -5
  23. package/src/components/multi-select/CMultiSelect.ts +58 -67
  24. package/src/components/multi-select/CMultiSelectSelection.ts +10 -11
  25. package/src/components/picker/CPicker.ts +22 -7
  26. package/src/components/popover/CPopover.ts +96 -50
  27. package/src/components/time-picker/CTimePicker.ts +63 -34
  28. package/src/components/tooltip/CTooltip.ts +97 -51
  29. package/src/composables/index.ts +2 -2
  30. package/src/composables/usePopper.ts +25 -0
  31. package/src/types.ts +1 -1
  32. package/src/utils/getRTLPlacement.ts +18 -0
  33. package/src/utils/index.ts +2 -1
  34. package/src/composables/useColorModes.ts +0 -62
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type Breakpoints = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
2
2
  export type Colors = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'dark' | 'light' | 'primary-gradient' | 'secondary-gradient' | 'success-gradient' | 'danger-gradient' | 'warning-gradient' | 'info-gradient' | 'dark-gradient' | 'light-gradient' | string;
3
- export type Placements = 'auto' | 'auto-start' | 'auto-end' | 'top-end' | 'top' | 'top-start' | 'bottom-end' | 'bottom' | 'bottom-start' | 'right-start' | 'right' | 'right-end' | 'left-start' | 'left' | 'left-end' | undefined;
3
+ export type Placements = 'auto' | 'auto-start' | 'auto-end' | 'top-end' | 'top' | 'top-start' | 'bottom-end' | 'bottom' | 'bottom-start' | 'right-start' | 'right' | 'right-end' | 'left-start' | 'left' | 'left-end' | string;
4
4
  export type Shapes = 'rounded' | 'rounded-top' | 'rounded-end' | 'rounded-bottom' | 'rounded-start' | 'rounded-circle' | 'rounded-pill' | 'rounded-0' | 'rounded-1' | 'rounded-2' | 'rounded-3' | string;
5
5
  export type Triggers = 'hover' | 'focus' | 'click';
@@ -0,0 +1,3 @@
1
+ import { Placement } from '@popperjs/core';
2
+ declare const getRTLPlacement: (placement: string, element: HTMLDivElement | null) => Placement;
3
+ export default getRTLPlacement;
@@ -1,5 +1,6 @@
1
+ import getRTLPlacement from './getRTLPlacement';
1
2
  import getUID from './getUID';
2
3
  import isInViewport from './isInViewport';
3
4
  import isObjectInArray from './isObjectInArray';
4
5
  import isRTL from './isRTL';
5
- export { getUID, isInViewport, isObjectInArray, isRTL };
6
+ export { getRTLPlacement, getUID, isInViewport, isObjectInArray, isRTL };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreui/vue-pro",
3
- "version": "4.9.0-beta.2",
3
+ "version": "4.9.0",
4
4
  "description": "UI Components Library for Vue.js",
5
5
  "keywords": [
6
6
  "vue",
@@ -38,24 +38,24 @@
38
38
  },
39
39
  "devDependencies": {
40
40
  "@popperjs/core": "^2.11.8",
41
- "@rollup/plugin-commonjs": "^25.0.1",
41
+ "@rollup/plugin-commonjs": "^25.0.2",
42
42
  "@rollup/plugin-node-resolve": "^15.1.0",
43
- "@rollup/plugin-typescript": "^11.1.1",
43
+ "@rollup/plugin-typescript": "^11.1.2",
44
44
  "@types/jest": "^29.5.2",
45
- "@vue/test-utils": "^2.3.2",
45
+ "@vue/test-utils": "^2.4.0",
46
46
  "@vue/vue3-jest": "29.2.4",
47
47
  "date-fns": "^2.29.3",
48
- "jest": "^29.5.0",
49
- "jest-environment-jsdom": "^29.5.0",
50
- "rollup": "^3.25.0",
48
+ "jest": "^29.6.1",
49
+ "jest-environment-jsdom": "^29.6.1",
50
+ "rollup": "^3.26.2",
51
51
  "rollup-plugin-vue": "^6.0.0",
52
- "ts-jest": "^29.1.0",
52
+ "ts-jest": "^29.1.1",
53
53
  "typescript": "^4.9.5",
54
54
  "vue": "^3.3.4",
55
- "vue-types": "^5.0.3"
55
+ "vue-types": "^5.1.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "@coreui/coreui-pro": "^4.3.4",
58
+ "@coreui/coreui-pro": "^4.5.0",
59
59
  "vue": "^3.2.21"
60
60
  },
61
61
  "standard": {
@@ -495,8 +495,9 @@ const CDateRangePicker = defineComponent({
495
495
  () => props.startDate,
496
496
  () => {
497
497
  if (props.startDate) {
498
- calendarDate.value = new Date(props.startDate)
499
- startDate.value = new Date(props.startDate)
498
+ const date = new Date(props.startDate)
499
+ calendarDate.value = date
500
+ startDate.value = date
500
501
  }
501
502
  },
502
503
  )
@@ -505,8 +506,9 @@ const CDateRangePicker = defineComponent({
505
506
  () => props.endDate,
506
507
  () => {
507
508
  if (props.endDate) {
508
- calendarDate.value = new Date(props.endDate)
509
- endDate.value = new Date(props.endDate)
509
+ const date = new Date(props.endDate)
510
+ calendarDate.value = date
511
+ endDate.value = date
510
512
  }
511
513
  },
512
514
  )
@@ -645,13 +647,19 @@ const CDateRangePicker = defineComponent({
645
647
  h(
646
648
  'div',
647
649
  {
648
- class: 'date-picker-input-group',
650
+ class: [
651
+ 'input-group',
652
+ 'picker-input-group',
653
+ {
654
+ [`input-group-${props.size}`]: props.size,
655
+ },
656
+ ],
649
657
  },
650
658
  [
651
659
  h('input', {
652
660
  autocomplete: 'off',
653
661
  class: [
654
- 'date-picker-input',
662
+ 'form-control date-picker-input',
655
663
  {
656
664
  hover: inputStartHoverValue.value,
657
665
  },
@@ -682,12 +690,20 @@ const CDateRangePicker = defineComponent({
682
690
  ? setInputValue(inputStartHoverValue.value)
683
691
  : setInputValue(startDate.value),
684
692
  }),
685
- props.range && props.separator !== false && h('div', { class: 'date-picker-separator' }),
693
+ props.range &&
694
+ props.separator !== false &&
695
+ h(
696
+ 'span',
697
+ { class: 'input-group-text' },
698
+ slots.separator
699
+ ? slots.separator()
700
+ : h('span', { class: 'picker-input-group-icon date-picker-arrow-icon' }),
701
+ ),
686
702
  props.range &&
687
703
  h('input', {
688
704
  autocomplete: 'off',
689
705
  class: [
690
- 'date-picker-input',
706
+ 'form-control date-picker-input',
691
707
  {
692
708
  hover: inputEndHoverValue.value,
693
709
  },
@@ -716,13 +732,31 @@ const CDateRangePicker = defineComponent({
716
732
  ? setInputValue(inputEndHoverValue.value)
717
733
  : setInputValue(endDate.value),
718
734
  }),
719
- props.indicator && h('div', { class: 'date-picker-indicator' }),
720
- props.cleaner &&
721
- (startDate.value || endDate.value) &&
722
- h('div', {
723
- class: 'date-picker-cleaner',
724
- onClick: (event: Event) => handleClear(event),
725
- }),
735
+ (props.indicator || props.cleaner) &&
736
+ h('span', { class: 'input-group-text' }, [
737
+ props.indicator &&
738
+ h(
739
+ 'span',
740
+ {
741
+ class: 'picker-input-group-indicator',
742
+ },
743
+ slots.indicator
744
+ ? slots.indicator()
745
+ : h('span', { class: 'picker-input-group-icon date-picker-input-icon' }),
746
+ ),
747
+ props.cleaner &&
748
+ h(
749
+ 'span',
750
+ {
751
+ class: 'picker-input-group-cleaner',
752
+ onClick: (event: Event) => handleClear(event),
753
+ role: 'button',
754
+ },
755
+ slots.cleaner
756
+ ? slots.cleaner()
757
+ : h('span', { class: 'picker-input-group-icon date-picker-cleaner-icon' }),
758
+ ),
759
+ ]),
726
760
  ],
727
761
  )
728
762
 
@@ -749,7 +783,6 @@ const CDateRangePicker = defineComponent({
749
783
  class: [
750
784
  'date-picker',
751
785
  {
752
- [`date-picker-${props.size}`]: props.size,
753
786
  disabled: props.disabled,
754
787
  'is-invalid': isValid.value === false ? true : false,
755
788
  'is-valid': isValid.value,
@@ -780,7 +813,7 @@ const CDateRangePicker = defineComponent({
780
813
  {
781
814
  toggler: () => InputGroup(),
782
815
  footer: () =>
783
- h('div', { class: 'date-picker-footer' }, [
816
+ h('div', { class: 'picker-footer' }, [
784
817
  props.todayButton &&
785
818
  h(
786
819
  CButton,
@@ -1,9 +1,53 @@
1
- import { defineComponent, h, ref, provide, watch, PropType, onMounted } from 'vue'
2
- import { createPopper, Placement } from '@popperjs/core'
1
+ import { defineComponent, h, ref, provide, watch, PropType } from 'vue'
2
+ import type { Placement } from '@popperjs/core'
3
3
 
4
- import { Triggers } from '../../types'
4
+ import { usePopper } from '../../composables'
5
+ import type { Placements, Triggers } from '../../types'
5
6
  import { isRTL } from '../../utils'
6
7
 
8
+ export type Directions = 'start' | 'end'
9
+
10
+ export type Breakpoints =
11
+ | { xs: Directions }
12
+ | { sm: Directions }
13
+ | { md: Directions }
14
+ | { lg: Directions }
15
+ | { xl: Directions }
16
+ | { xxl: Directions }
17
+
18
+ export type Alignments = Directions | Breakpoints
19
+
20
+ const getPlacement = (
21
+ placement: Placement,
22
+ direction: string | undefined,
23
+ alignment: Alignments | string | undefined,
24
+ isRTL: boolean,
25
+ ): Placements => {
26
+ let _placement = placement
27
+
28
+ if (direction === 'dropup') {
29
+ _placement = isRTL ? 'top-end' : 'top-start'
30
+ }
31
+
32
+ if (direction === 'dropup-center') {
33
+ _placement = 'top'
34
+ }
35
+
36
+ if (direction === 'dropend') {
37
+ _placement = isRTL ? 'left-start' : 'right-start'
38
+ }
39
+
40
+ if (direction === 'dropstart') {
41
+ _placement = isRTL ? 'right-start' : 'left-start'
42
+ }
43
+
44
+ if (alignment === 'end') {
45
+ _placement = isRTL ? 'bottom-start' : 'bottom-end'
46
+ }
47
+
48
+ return _placement
49
+ }
50
+
7
51
  const CDropdown = defineComponent({
8
52
  name: 'CDropdown',
9
53
  props: {
@@ -13,7 +57,7 @@ const CDropdown = defineComponent({
13
57
  * @values { 'start' | 'end' | { xs: 'start' | 'end' } | { sm: 'start' | 'end' } | { md: 'start' | 'end' } | { lg: 'start' | 'end' } | { xl: 'start' | 'end'} | { xxl: 'start' | 'end'} }
14
58
  */
15
59
  alignment: {
16
- type: [String, Object],
60
+ type: [String, Object] as PropType<string | Alignments>,
17
61
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
62
  validator: (value: string | any) => {
19
63
  if (value === 'start' || value === 'end') {
@@ -74,6 +118,15 @@ const CDropdown = defineComponent({
74
118
  * Toggle the disabled state for the component.
75
119
  */
76
120
  disabled: Boolean,
121
+ /**
122
+ * Offset of the dropdown menu relative to its target.
123
+ *
124
+ * @since 4.9.0
125
+ */
126
+ offset: {
127
+ type: Array,
128
+ default: () => [0, 2],
129
+ },
77
130
  /**
78
131
  * Describes the placement of your component after Popper.js has applied all the modifiers that may have flipped or altered the originally provided placement property.
79
132
  *
@@ -127,10 +180,28 @@ const CDropdown = defineComponent({
127
180
  setup(props, { slots, emit }) {
128
181
  const dropdownToggleRef = ref()
129
182
  const dropdownMenuRef = ref()
130
- const placement = ref(props.placement)
131
- const popper = ref()
183
+ const popper = ref(typeof props.alignment === 'object' ? false : props.popper)
132
184
  const visible = ref(props.visible)
133
185
 
186
+ const { initPopper, destroyPopper } = usePopper()
187
+
188
+ const popperConfig = {
189
+ modifiers: [
190
+ {
191
+ name: 'offset',
192
+ options: {
193
+ offset: props.offset,
194
+ },
195
+ },
196
+ ],
197
+ placement: getPlacement(
198
+ props.placement,
199
+ props.direction,
200
+ props.alignment,
201
+ isRTL(dropdownMenuRef.value),
202
+ ) as Placement,
203
+ }
204
+
134
205
  watch(
135
206
  () => props.visible,
136
207
  () => {
@@ -138,8 +209,22 @@ const CDropdown = defineComponent({
138
209
  },
139
210
  )
140
211
 
212
+ watch(visible, () => {
213
+ if (visible.value && dropdownToggleRef.value && dropdownMenuRef.value) {
214
+ popper.value && initPopper(dropdownToggleRef.value, dropdownMenuRef.value, popperConfig)
215
+ window.addEventListener('mouseup', handleMouseUp)
216
+ window.addEventListener('keyup', handleKeyup)
217
+ emit('show')
218
+ return
219
+ }
220
+
221
+ popper.value && destroyPopper()
222
+ window.removeEventListener('mouseup', handleMouseUp)
223
+ window.removeEventListener('keyup', handleKeyup)
224
+ emit('hide')
225
+ })
226
+
141
227
  provide('config', {
142
- autoClose: props.autoClose,
143
228
  alignment: props.alignment,
144
229
  dark: props.dark,
145
230
  popper: props.popper,
@@ -150,27 +235,38 @@ const CDropdown = defineComponent({
150
235
  provide('dropdownToggleRef', dropdownToggleRef)
151
236
  provide('dropdownMenuRef', dropdownMenuRef)
152
237
 
153
- const initPopper = () => {
154
- // Disable popper if responsive aligment is set.
155
- if (typeof props.alignment === 'object') {
238
+ const handleKeyup = (event: KeyboardEvent) => {
239
+ if (props.autoClose === false) {
156
240
  return
157
241
  }
158
242
 
159
- if (dropdownToggleRef.value) {
160
- popper.value = createPopper(dropdownToggleRef.value, dropdownMenuRef.value, {
161
- placement: placement.value,
162
- })
243
+ if (event.key === 'Escape') {
244
+ setVisible(false)
163
245
  }
164
246
  }
165
247
 
166
- const destroyPopper = () => {
167
- if (popper.value) {
168
- popper.value.destroy()
248
+ const handleMouseUp = (event: Event) => {
249
+ if (!dropdownToggleRef.value || !dropdownMenuRef.value) {
250
+ return
251
+ }
252
+
253
+ if (dropdownToggleRef.value.contains(event.target as HTMLElement)) {
254
+ return
255
+ }
256
+
257
+ if (
258
+ props.autoClose === true ||
259
+ (props.autoClose === 'inside' &&
260
+ dropdownMenuRef.value.contains(event.target as HTMLElement)) ||
261
+ (props.autoClose === 'outside' &&
262
+ !dropdownMenuRef.value.contains(event.target as HTMLElement))
263
+ ) {
264
+ setVisible(false)
265
+ return
169
266
  }
170
- popper.value = undefined
171
267
  }
172
268
 
173
- const toggleMenu = (_visible?: boolean) => {
269
+ const setVisible = (_visible?: boolean) => {
174
270
  if (props.disabled) {
175
271
  return
176
272
  }
@@ -188,48 +284,7 @@ const CDropdown = defineComponent({
188
284
  visible.value = true
189
285
  }
190
286
 
191
- provide('toggleMenu', toggleMenu)
192
-
193
- const hideMenu = () => {
194
- if (props.disabled) {
195
- return
196
- }
197
-
198
- visible.value = false
199
- }
200
-
201
- provide('hideMenu', hideMenu)
202
-
203
- watch(visible, () => {
204
- props.popper && (visible.value ? initPopper() : destroyPopper())
205
- visible.value ? emit('show') : emit('hide')
206
- })
207
-
208
- onMounted(() => {
209
- if (props.direction === 'center') {
210
- placement.value = 'bottom'
211
- }
212
-
213
- if (props.direction === 'dropup') {
214
- placement.value = isRTL(dropdownMenuRef.value) ? 'top-end' : 'top-start'
215
- }
216
-
217
- if (props.direction === 'dropup-center') {
218
- placement.value = 'top'
219
- }
220
-
221
- if (props.direction === 'dropend') {
222
- placement.value = isRTL(dropdownMenuRef.value) ? 'left-start' : 'right-start'
223
- }
224
-
225
- if (props.direction === 'dropstart') {
226
- placement.value = isRTL(dropdownMenuRef.value) ? 'right-start' : 'left-start'
227
- }
228
-
229
- if (props.alignment === 'end') {
230
- placement.value = isRTL(dropdownMenuRef.value) ? 'bottom-start' : 'bottom-end'
231
- }
232
- })
287
+ provide('setVisible', setVisible)
233
288
 
234
289
  return () =>
235
290
  props.variant === 'input-group'
@@ -1,4 +1,4 @@
1
- import { defineComponent, h, inject, onUnmounted, onUpdated, Ref } from 'vue'
1
+ import { defineComponent, h, inject, Ref } from 'vue'
2
2
 
3
3
  const CDropdownMenu = defineComponent({
4
4
  name: 'CDropdownMenu',
@@ -14,13 +14,11 @@ const CDropdownMenu = defineComponent({
14
14
  },
15
15
  },
16
16
  setup(props, { slots }) {
17
- const dropdownToggleRef = inject('dropdownToggleRef') as Ref<HTMLElement>
18
17
  const dropdownMenuRef = inject('dropdownMenuRef') as Ref<HTMLElement>
19
18
  const config = inject('config') as any // eslint-disable-line @typescript-eslint/no-explicit-any
20
- const hideMenu = inject('hideMenu') as () => void
21
19
  const visible = inject('visible') as Ref<boolean>
22
20
 
23
- const { autoClose, alignment, dark, popper } = config
21
+ const { alignment, dark, popper } = config
24
22
 
25
23
  // eslint-disable-next-line @typescript-eslint/ban-types, unicorn/consistent-function-scoping
26
24
  const alignmentClassNames = (alignment: object | string) => {
@@ -36,49 +34,6 @@ const CDropdownMenu = defineComponent({
36
34
  return classNames
37
35
  }
38
36
 
39
- const handleKeyup = (event: KeyboardEvent) => {
40
- if (autoClose === false) {
41
- return
42
- }
43
-
44
- if (event.key === 'Escape') {
45
- hideMenu()
46
- }
47
- }
48
-
49
- const handleMouseUp = (event: Event) => {
50
- if (dropdownToggleRef.value?.contains(event.target as HTMLElement)) {
51
- return
52
- }
53
-
54
- if (autoClose === true) {
55
- hideMenu()
56
- return
57
- }
58
-
59
- if (autoClose === 'inside' && dropdownMenuRef.value?.contains(event.target as HTMLElement)) {
60
- hideMenu()
61
- return
62
- }
63
-
64
- if (
65
- autoClose === 'outside' &&
66
- !dropdownMenuRef.value?.contains(event.target as HTMLElement)
67
- ) {
68
- hideMenu()
69
- }
70
- }
71
-
72
- onUpdated(() => {
73
- visible.value && window.addEventListener('mouseup', handleMouseUp)
74
- visible.value && window.addEventListener('keyup', handleKeyup)
75
- })
76
-
77
- onUnmounted(() => {
78
- window.removeEventListener('mouseup', handleMouseUp)
79
- window.removeEventListener('keyup', handleKeyup)
80
- })
81
-
82
37
  return () =>
83
38
  h(
84
39
  props.component,
@@ -3,7 +3,7 @@ import { cloneVNode, defineComponent, h, inject, onMounted, PropType, Ref, ref }
3
3
  import { CButton } from '../button'
4
4
 
5
5
  import { Color, Shape } from '../../props'
6
- import { Triggers } from '../../types'
6
+ import type { Triggers } from '../../types'
7
7
 
8
8
  const CDropdownToggle = defineComponent({
9
9
  name: 'CDropdownToggle',
@@ -85,7 +85,7 @@ const CDropdownToggle = defineComponent({
85
85
  const dropdownToggleRef = inject('dropdownToggleRef') as Ref<HTMLElement>
86
86
  const dropdownVariant = inject('variant') as string
87
87
  const visible = inject('visible') as Ref<boolean>
88
- const toggleMenu = inject('toggleMenu') as (_visible?: boolean) => void
88
+ const setVisible = inject('setVisible') as (_visible?: boolean) => void
89
89
 
90
90
  const className = [
91
91
  {
@@ -103,7 +103,7 @@ const CDropdownToggle = defineComponent({
103
103
  return
104
104
  }
105
105
 
106
- toggleMenu()
106
+ setVisible()
107
107
  },
108
108
  }),
109
109
  ...((props.trigger === 'focus' || props.trigger.includes('focus')) && {
@@ -112,13 +112,13 @@ const CDropdownToggle = defineComponent({
112
112
  return
113
113
  }
114
114
 
115
- toggleMenu(true)
115
+ setVisible(true)
116
116
  },
117
117
  onblur: () => {
118
118
  if (props.disabled) {
119
119
  return
120
120
  }
121
- toggleMenu(false)
121
+ setVisible(false)
122
122
  },
123
123
  }),
124
124
  }