@coreui/vue-pro 4.9.0-beta.2 → 4.9.0-rc.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 (41) 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/form/CFormCheck.d.ts +1 -1
  5. package/dist/components/form/CFormControl.d.ts +1 -1
  6. package/dist/components/form/CFormInput.d.ts +2 -2
  7. package/dist/components/form/CFormTextarea.d.ts +2 -2
  8. package/dist/components/multi-select/CMultiSelect.d.ts +1 -1
  9. package/dist/components/multi-select/CMultiSelectNativeSelect.d.ts +1 -1
  10. package/dist/components/multi-select/CMultiSelectSelection.d.ts +1 -1
  11. package/dist/components/picker/CPicker.d.ts +3 -3
  12. package/dist/components/popover/CPopover.d.ts +75 -6
  13. package/dist/components/toast/CToast.d.ts +1 -1
  14. package/dist/components/tooltip/CTooltip.d.ts +77 -8
  15. package/dist/composables/index.d.ts +2 -2
  16. package/dist/composables/useColorModes.d.ts +1 -1
  17. package/dist/composables/usePopper.d.ts +6 -0
  18. package/dist/index.es.js +3748 -3667
  19. package/dist/index.es.js.map +1 -1
  20. package/dist/index.js +3747 -3666
  21. package/dist/index.js.map +1 -1
  22. package/dist/types.d.ts +1 -1
  23. package/dist/utils/getRTLPlacement.d.ts +3 -0
  24. package/dist/utils/index.d.ts +2 -1
  25. package/package.json +2 -2
  26. package/src/components/date-range-picker/CDateRangePicker.ts +85 -65
  27. package/src/components/dropdown/CDropdown.ts +116 -61
  28. package/src/components/dropdown/CDropdownMenu.ts +2 -47
  29. package/src/components/dropdown/CDropdownToggle.ts +5 -5
  30. package/src/components/multi-select/CMultiSelect.ts +55 -64
  31. package/src/components/multi-select/CMultiSelectSelection.ts +10 -11
  32. package/src/components/picker/CPicker.ts +22 -7
  33. package/src/components/popover/CPopover.ts +96 -50
  34. package/src/components/time-picker/CTimePicker.ts +29 -11
  35. package/src/components/tooltip/CTooltip.ts +97 -51
  36. package/src/composables/index.ts +2 -2
  37. package/src/composables/usePopper.ts +25 -0
  38. package/src/types.ts +1 -1
  39. package/src/utils/getRTLPlacement.ts +18 -0
  40. package/src/utils/index.ts +2 -1
  41. package/src/composables/useColorModes.ts +0 -62
@@ -535,13 +535,18 @@ const CMultiSelect = defineComponent({
535
535
  'div',
536
536
  {
537
537
  class: [
538
+ 'dropdown',
539
+ 'picker',
538
540
  'form-multi-select',
539
541
  {
542
+ 'form-multi-select-with-cleaner': props.cleaner,
540
543
  disabled: props.disabled,
541
544
  [`form-multi-select-${props.size}`]: props.size,
545
+ 'form-multi-select-selection-tags':
546
+ props.multiple && props.selectionType === 'tags',
547
+ show: visible.value,
542
548
  'is-invalid': props.invalid,
543
549
  'is-valid': props.valid,
544
- show: visible.value,
545
550
  },
546
551
  ],
547
552
  'aria-expanded': visible.value,
@@ -561,78 +566,64 @@ const CMultiSelect = defineComponent({
561
566
  },
562
567
  {
563
568
  default: () => [
564
- h(
565
- CMultiSelectSelection,
566
- {
567
- multiple: props.multiple,
568
- placeholder: props.placeholder,
569
- onRemove: (option: Option) =>
570
- !props.disabled && handleOptionClick(option),
571
- search: props.search,
572
- selected: selected.value,
573
- selectionType: props.selectionType,
574
- selectionTypeCounterText: props.selectionTypeCounterText,
575
- },
576
- {
577
- default: () =>
578
- props.search &&
579
- h('input', {
580
- type: 'text',
581
- class: 'form-multi-select-search',
582
- disabled: props.disabled,
583
- autocomplete: 'off',
584
- onInput: (event: InputEvent) => handleSearchChange(event),
585
- onKeydown: (event: KeyboardEvent) => handleSearchKeyDown(event),
586
- ...(selected.value.length === 0 && {
587
- placeholder: props.placeholder,
588
- }),
589
- ...(selected.value.length > 0 &&
590
- props.selectionType === 'counter' && {
591
- placeholder: `${selected.value.length} ${props.selectionTypeCounterText}`,
592
- }),
593
- ...(selected.value.length > 0 &&
594
- !props.multiple && {
595
- placeholder: selected.value.map((option) => option.text)[0],
596
- }),
597
-
598
- ...(props.multiple &&
599
- selected.value.length > 0 &&
600
- props.selectionType !== 'counter' && {
601
- size: searchValue.value.length + 2,
602
- }),
603
- ref: searchRef,
569
+ h(CMultiSelectSelection, {
570
+ multiple: props.multiple,
571
+ placeholder: props.placeholder,
572
+ onRemove: (option: Option) =>
573
+ !props.disabled && handleOptionClick(option),
574
+ search: props.search,
575
+ selected: selected.value,
576
+ selectionType: props.selectionType,
577
+ selectionTypeCounterText: props.selectionTypeCounterText,
578
+ }),
579
+ props.multiple &&
580
+ props.cleaner &&
581
+ selected.value.length > 0 &&
582
+ !props.disabled &&
583
+ h('button', {
584
+ type: 'button',
585
+ class: 'form-multi-select-selection-cleaner',
586
+ onClick: () => handleDeselectAll(),
587
+ }),
588
+ props.search &&
589
+ h('input', {
590
+ type: 'text',
591
+ class: 'form-multi-select-search',
592
+ disabled: props.disabled,
593
+ autocomplete: 'off',
594
+ onInput: (event: InputEvent) => handleSearchChange(event),
595
+ onKeydown: (event: KeyboardEvent) => handleSearchKeyDown(event),
596
+ ...(selected.value.length === 0 && {
597
+ placeholder: props.placeholder,
598
+ }),
599
+ ...(selected.value.length > 0 &&
600
+ props.selectionType === 'counter' && {
601
+ placeholder: `${selected.value.length} ${props.selectionTypeCounterText}`,
604
602
  }),
605
- },
606
- ),
607
- h(
608
- 'div',
609
- { class: 'form-multi-select-buttons' },
610
- {
611
- default: () => [
612
- h('button', {
613
- class: 'form-multi-select-cleaner',
614
- onClick: () => handleDeselectAll(),
615
- type: 'button',
603
+ ...(selected.value.length > 0 &&
604
+ !props.multiple && {
605
+ placeholder: selected.value.map((option) => option.text)[0],
616
606
  }),
617
- h('button', {
618
- class: 'form-multi-select-indicator',
619
- onClick: (event: Event) => {
620
- event.preventDefault()
621
- event.stopPropagation()
622
- visible.value = !visible.value
623
- },
624
- type: 'button',
607
+
608
+ ...(props.multiple &&
609
+ selected.value.length > 0 &&
610
+ props.selectionType !== 'counter' && {
611
+ size: searchValue.value.length + 2,
625
612
  }),
626
- ],
627
- },
628
- ),
613
+ ref: searchRef,
614
+ }),
629
615
  ],
630
616
  },
631
617
  ),
632
618
  h(
633
619
  'div',
634
620
  {
635
- class: 'form-multi-select-dropdown',
621
+ class: [
622
+ 'dropdown-menu',
623
+ {
624
+ show: visible.value,
625
+ },
626
+ ],
636
627
  role: 'menu',
637
628
  ref: dropdownRef,
638
629
  },
@@ -36,12 +36,7 @@ const CMultiSelectSelection = defineComponent({
36
36
  h(
37
37
  'div',
38
38
  {
39
- class: [
40
- 'form-multi-select-selection',
41
- {
42
- 'form-multi-select-selection-tags': props.multiple && props.selectionType === 'tags',
43
- },
44
- ],
39
+ class: 'form-multi-select-selection',
45
40
  },
46
41
  [
47
42
  props.multiple &&
@@ -61,11 +56,15 @@ const CMultiSelectSelection = defineComponent({
61
56
  return h('span', { class: 'form-multi-select-tag' }, [
62
57
  option.text,
63
58
  !option.disabled &&
64
- h('button', {
65
- class: 'form-multi-select-tag-delete',
66
- ariaLabel: 'Close',
67
- onClick: () => handleRemove(option),
68
- }),
59
+ h(
60
+ 'button',
61
+ {
62
+ class: 'form-multi-select-tag-delete close',
63
+ ariaLabel: 'Close',
64
+ onClick: () => handleRemove(option),
65
+ },
66
+ h('span', { ariaHidden: 'true' }, 'x'),
67
+ ),
69
68
  ])
70
69
  }
71
70
  return
@@ -130,6 +130,8 @@ const CPicker = defineComponent({
130
130
  'div',
131
131
  {
132
132
  class: [
133
+ 'dropdown',
134
+ 'picker',
133
135
  attrs.class,
134
136
  {
135
137
  show: visible.value,
@@ -154,13 +156,26 @@ const CPicker = defineComponent({
154
156
  },
155
157
  }),
156
158
  ),
157
- h('div', { class: props.dropdownClassNames, ref: dropdownRef }, [
158
- slots.default && slots.default(),
159
- /**
160
- * @slot Location for the footer element.
161
- */
162
- slots.footer && slots.footer(),
163
- ]),
159
+ h(
160
+ 'div',
161
+ {
162
+ class: [
163
+ 'dropdown-menu',
164
+ {
165
+ show: visible.value,
166
+ },
167
+ props.dropdownClassNames,
168
+ ],
169
+ ref: dropdownRef,
170
+ },
171
+ [
172
+ slots.default && slots.default(),
173
+ /**
174
+ * @slot Location for the footer element.
175
+ */
176
+ slots.footer && slots.footer(),
177
+ ],
178
+ ),
164
179
  ],
165
180
  )
166
181
  }
@@ -1,30 +1,54 @@
1
1
  import { defineComponent, h, PropType, ref, RendererElement, Teleport, Transition } from 'vue'
2
- import { createPopper, Placement } from '@popperjs/core'
2
+ import type { Placement } from '@popperjs/core'
3
3
 
4
+ import { usePopper } from '../../composables'
5
+ import type { Placements, Triggers } from '../../types'
4
6
  import { executeAfterTransition } from '../../utils/transition'
5
- import { isRTL } from '../../utils'
6
-
7
- const getPlacement = (placement: string, element: HTMLDivElement | null): Placement => {
8
- switch (placement) {
9
- case 'right': {
10
- return isRTL(element) ? 'left' : 'right'
11
- }
12
- case 'left': {
13
- return isRTL(element) ? 'right' : 'left'
14
- }
15
- default: {
16
- return placement as Placement
17
- }
18
- }
19
- }
7
+ import { getRTLPlacement } from '../../utils'
20
8
 
21
9
  const CPopover = defineComponent({
22
10
  name: 'CPopover',
23
11
  props: {
12
+ /**
13
+ * Apply a CSS fade transition to the popover.
14
+ *
15
+ * @since 4.9.0-rc.0
16
+ */
17
+ animation: {
18
+ type: Boolean,
19
+ default: true,
20
+ },
24
21
  /**
25
22
  * Content for your component. If you want to pass non-string value please use dedicated slot `<template #content>...</template>`
26
23
  */
27
24
  content: String,
25
+ /**
26
+ * The delay for displaying and hiding the popover (in milliseconds). When a numerical value is provided, the delay applies to both the hide and show actions. The object structure for specifying the delay is as follows: delay: `{ 'show': 500, 'hide': 100 }`.
27
+ *
28
+ * @since 4.9.0-rc.0
29
+ */
30
+ delay: {
31
+ type: [Number, Object] as PropType<number | { show: number; hide: number }>,
32
+ default: 0,
33
+ },
34
+ /**
35
+ * Specify the desired order of fallback placements by providing a list of placements as an array. The placements should be prioritized based on preference.
36
+ *
37
+ * @since 4.9.0-rc.0
38
+ */
39
+ fallbackPlacements: {
40
+ type: [String, Array] as PropType<Placements | Placements[]>,
41
+ default: () => ['top', 'right', 'bottom', 'left'],
42
+ validator: (value: Placements | Placements[]) => {
43
+ if (typeof value === 'string') {
44
+ return ['top', 'right', 'bottom', 'left'].includes(value)
45
+ }
46
+ if (Array.isArray(value)) {
47
+ return value.every((e) => ['top', 'right', 'bottom', 'left'].includes(e))
48
+ }
49
+ return false
50
+ },
51
+ },
28
52
  /**
29
53
  * Offset of the popover relative to its target.
30
54
  */
@@ -52,9 +76,9 @@ const CPopover = defineComponent({
52
76
  * @values 'click', 'focus', 'hover'
53
77
  */
54
78
  trigger: {
55
- type: [String, Array] as PropType<string | string[]>,
79
+ type: [String, Array] as PropType<Triggers | Triggers[]>,
56
80
  default: 'click',
57
- validator: (value: string | string[]) => {
81
+ validator: (value: Triggers | Triggers[]) => {
58
82
  if (typeof value === 'string') {
59
83
  return ['click', 'focus', 'hover'].includes(value)
60
84
  }
@@ -82,12 +106,39 @@ const CPopover = defineComponent({
82
106
  setup(props, { attrs, slots, emit }) {
83
107
  const togglerRef = ref()
84
108
  const popoverRef = ref()
85
- const popper = ref()
86
109
  const visible = ref(props.visible)
110
+ const { initPopper, destroyPopper } = usePopper()
111
+
112
+ const delay =
113
+ typeof props.delay === 'number' ? { show: props.delay, hide: props.delay } : props.delay
114
+
115
+ const popperConfig = {
116
+ modifiers: [
117
+ {
118
+ name: 'arrow',
119
+ options: {
120
+ element: '.popover-arrow',
121
+ },
122
+ },
123
+ {
124
+ name: 'flip',
125
+ options: {
126
+ fallbackPlacements: props.fallbackPlacements,
127
+ },
128
+ },
129
+ {
130
+ name: 'offset',
131
+ options: {
132
+ offset: props.offset,
133
+ },
134
+ },
135
+ ],
136
+ placement: getRTLPlacement(props.placement, togglerRef.value),
137
+ }
87
138
 
88
139
  const handleEnter = (el: RendererElement, done: () => void) => {
89
140
  emit('show')
90
- initPopper()
141
+ initPopper(togglerRef.value, popoverRef.value, popperConfig)
91
142
  el.classList.add('show')
92
143
  executeAfterTransition(() => done(), el as HTMLElement)
93
144
  }
@@ -101,32 +152,18 @@ const CPopover = defineComponent({
101
152
  }, el as HTMLElement)
102
153
  }
103
154
 
104
- const handleToggle = (event: Event) => {
155
+ const toggleVisible = (event: Event, _visible: boolean) => {
105
156
  togglerRef.value = event.target
106
- visible.value = !visible.value
107
- }
108
-
109
- const initPopper = () => {
110
- if (togglerRef.value) {
111
- popper.value = createPopper(togglerRef.value, popoverRef.value, {
112
- placement: getPlacement(props.placement, togglerRef.value),
113
- modifiers: [
114
- {
115
- name: 'offset',
116
- options: {
117
- offset: props.offset,
118
- },
119
- },
120
- ],
121
- })
157
+ if (_visible) {
158
+ setTimeout(() => {
159
+ visible.value = true
160
+ }, delay.show)
161
+ return
122
162
  }
123
- }
124
163
 
125
- const destroyPopper = () => {
126
- if (popper.value) {
127
- popper.value.destroy()
128
- }
129
- popper.value = undefined
164
+ setTimeout(() => {
165
+ visible.value = false
166
+ }, delay.hide)
130
167
  }
131
168
 
132
169
  return () => [
@@ -146,13 +183,19 @@ const CPopover = defineComponent({
146
183
  h(
147
184
  'div',
148
185
  {
149
- class: 'popover fade bs-popover-auto',
186
+ class: [
187
+ 'popover',
188
+ 'bs-popover-auto',
189
+ {
190
+ fade: props.animation,
191
+ },
192
+ ],
150
193
  ref: popoverRef,
151
194
  role: 'tooltip',
152
195
  ...attrs,
153
196
  },
154
197
  [
155
- h('div', { class: 'popover-arrow', 'data-popper-arrow': '' }),
198
+ h('div', { class: 'popover-arrow' }),
156
199
  (props.title || slots.title) &&
157
200
  h(
158
201
  'div',
@@ -176,11 +219,14 @@ const CPopover = defineComponent({
176
219
  slots.toggler &&
177
220
  slots.toggler({
178
221
  on: {
179
- click: (event: Event) => props.trigger.includes('click') && handleToggle(event),
180
- blur: (event: Event) => props.trigger.includes('focus') && handleToggle(event),
181
- focus: (event: Event) => props.trigger.includes('focus') && handleToggle(event),
182
- mouseenter: (event: Event) => props.trigger.includes('hover') && handleToggle(event),
183
- mouseleave: (event: Event) => props.trigger.includes('hover') && handleToggle(event),
222
+ click: (event: Event) =>
223
+ props.trigger.includes('click') && toggleVisible(event, !visible.value),
224
+ blur: (event: Event) => props.trigger.includes('focus') && toggleVisible(event, false),
225
+ focus: (event: Event) => props.trigger.includes('focus') && toggleVisible(event, true),
226
+ mouseenter: (event: Event) =>
227
+ props.trigger.includes('hover') && toggleVisible(event, true),
228
+ mouseleave: (event: Event) =>
229
+ props.trigger.includes('hover') && toggleVisible(event, false),
184
230
  },
185
231
  }),
186
232
  ]
@@ -1,6 +1,7 @@
1
1
  import { defineComponent, h, ref, watch } from 'vue'
2
2
 
3
3
  import { CButton } from '../button'
4
+ import { CInputGroup } from '../form'
4
5
  import { CFormControlWrapper } from '../form/CFormControlWrapper'
5
6
  import { CPicker } from '../picker'
6
7
 
@@ -391,10 +392,10 @@ const CTimePicker = defineComponent({
391
392
  }
392
393
 
393
394
  const InputGroup = () =>
394
- h('div', { class: 'time-picker-input-group' }, [
395
+ h(CInputGroup, { class: 'picker-input-group', size: props.size }, () => [
395
396
  h('input', {
396
397
  autocomplete: 'off',
397
- class: 'time-picker-input',
398
+ class: 'form-control',
398
399
  disabled: props.disabled,
399
400
  onInput: (event: Event) => {
400
401
  if (isValidTime((event.target as HTMLInputElement).value)) {
@@ -412,13 +413,31 @@ const CTimePicker = defineComponent({
412
413
  })
413
414
  : '',
414
415
  }),
415
- props.indicator && h('div', { class: 'time-picker-indicator' }),
416
- props.cleaner &&
417
- date.value &&
418
- h('div', {
419
- class: 'time-picker-cleaner',
420
- onClick: (event: Event) => handleClear(event),
421
- }),
416
+ (props.indicator || props.cleaner) &&
417
+ h('div', { class: 'input-group-text' }, [
418
+ props.indicator &&
419
+ h(
420
+ 'span',
421
+ {
422
+ class: 'picker-input-group-indicator',
423
+ },
424
+ slots.indicator
425
+ ? slots.indicator()
426
+ : h('span', { class: 'picker-input-group-icon time-picker-input-icon' }),
427
+ ),
428
+ props.cleaner &&
429
+ h(
430
+ 'span',
431
+ {
432
+ class: 'picker-input-group-cleaner',
433
+ onClick: (event: Event) => handleClear(event),
434
+ role: 'button',
435
+ },
436
+ slots.cleaner
437
+ ? slots.cleaner()
438
+ : h('span', { class: 'picker-input-group-icon time-picker-cleaner-icon' }),
439
+ ),
440
+ ]),
422
441
  ])
423
442
 
424
443
  const TimePickerSelect = () => [
@@ -568,7 +587,6 @@ const CTimePicker = defineComponent({
568
587
  class: [
569
588
  'time-picker',
570
589
  {
571
- [`time-picker-${props.size}`]: props.size,
572
590
  disabled: props.disabled,
573
591
  'is-invalid': isValid.value === false ? true : false,
574
592
  'is-valid': isValid.value,
@@ -614,7 +632,7 @@ const CTimePicker = defineComponent({
614
632
  props.variant === 'select' ? TimePickerSelect() : TimePickerRoll(),
615
633
  ),
616
634
  footer: () =>
617
- h('div', { class: 'time-picker-footer' }, [
635
+ h('div', { class: 'picker-footer' }, [
618
636
  props.cancelButton &&
619
637
  h(
620
638
  CButton,