@coreui/vue-pro 4.7.0-alpha.1 → 4.8.0-next.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 (46) hide show
  1. package/README.md +1 -1
  2. package/dist/components/calendar/utils.d.ts +23 -0
  3. package/dist/components/element-cover/CElementCover.d.ts +14 -11
  4. package/dist/components/modal/CModal.d.ts +4 -20
  5. package/dist/components/offcanvas/COffcanvas.d.ts +35 -18
  6. package/dist/components/smart-table/CSmartTable.d.ts +83 -94
  7. package/dist/components/smart-table/CSmartTableBody.d.ts +16 -40
  8. package/dist/components/smart-table/CSmartTableHead.d.ts +20 -61
  9. package/dist/components/smart-table/CSmartTableInterface.d.ts +5 -1
  10. package/dist/components/smart-table/types.d.ts +50 -0
  11. package/dist/components/smart-table/utils.d.ts +17 -0
  12. package/dist/components/table/CTable.d.ts +5 -11
  13. package/dist/components/time-picker/types.d.ts +15 -0
  14. package/dist/components/time-picker/utils.d.ts +23 -0
  15. package/dist/index.es.js +1114 -4423
  16. package/dist/index.es.js.map +1 -1
  17. package/dist/index.js +1115 -4424
  18. package/dist/index.js.map +1 -1
  19. package/dist/utils/calendar.d.ts +2 -2
  20. package/dist/utils/index.d.ts +2 -2
  21. package/dist/utils/isInViewport.d.ts +2 -0
  22. package/dist/utils/isObjectInArray.d.ts +2 -0
  23. package/package.json +10 -14
  24. package/src/components/calendar/CCalendar.ts +1 -1
  25. package/src/{utils/calendar.ts → components/calendar/utils.ts} +3 -3
  26. package/src/components/carousel/CCarousel.ts +3 -3
  27. package/src/components/date-range-picker/CDateRangePicker.ts +1 -1
  28. package/src/components/element-cover/CElementCover.ts +45 -30
  29. package/src/components/form/CFormControlWrapper.ts +36 -22
  30. package/src/components/modal/CModal.ts +10 -10
  31. package/src/components/multi-select/CMultiSelect.ts +0 -10
  32. package/src/components/offcanvas/COffcanvas.ts +50 -28
  33. package/src/components/sidebar/CSidebar.ts +5 -5
  34. package/src/components/smart-table/CSmartTable.ts +409 -272
  35. package/src/components/smart-table/CSmartTableBody.ts +126 -137
  36. package/src/components/smart-table/CSmartTableHead.ts +54 -139
  37. package/src/components/smart-table/CSmartTableInterface.ts +7 -1
  38. package/src/components/smart-table/types.ts +61 -0
  39. package/src/components/smart-table/utils.ts +212 -0
  40. package/src/components/table/CTable.ts +45 -42
  41. package/src/components/time-picker/CTimePicker.ts +49 -26
  42. package/src/components/time-picker/types.ts +15 -0
  43. package/src/{utils/time.ts → components/time-picker/utils.ts} +49 -10
  44. package/src/utils/index.ts +2 -2
  45. package/src/utils/isInViewport.ts +11 -0
  46. package/src/utils/isVisible.ts +0 -11
@@ -11,8 +11,8 @@ export declare const getMonthDetails: (year: number, month: number, firstDayOfWe
11
11
  date: Date;
12
12
  month: string;
13
13
  }[][];
14
- export declare const isDisableDateInRange: (startDate?: Date | null, endDate?: Date | null, dates?: Date[] | Date[][]) => boolean;
15
- export declare const isDateDisabled: (date: Date, min?: Date | null, max?: Date | null, dates?: Date[] | Date[][]) => boolean | undefined;
14
+ export declare const isDisableDateInRange: (startDate?: Date | null, endDate?: Date | null, dates?: Date[] | Date[][] | (Date | Date[])[]) => boolean;
15
+ export declare const isDateDisabled: (date: Date, min?: Date | null, max?: Date | null, dates?: Date[] | Date[][] | (Date | Date[])[]) => boolean | undefined;
16
16
  export declare const isDateInRange: (date: Date, start: Date | null, end: Date | null) => boolean | null;
17
17
  export declare const isDateSelected: (date: Date, start: Date | null, end: Date | null) => boolean | null;
18
18
  export declare const isEndDate: (date: Date, start: Date | null, end: Date | null) => boolean | null;
@@ -1,4 +1,4 @@
1
1
  import getNextSibling from './getNextSibling';
2
2
  import getPreviousSibling from './getPreviousSibling';
3
- import isVisible from './isVisible';
4
- export { getNextSibling, getPreviousSibling, isVisible };
3
+ import isInViewport from './isInViewport';
4
+ export { getNextSibling, getPreviousSibling, isInViewport };
@@ -0,0 +1,2 @@
1
+ declare const isInViewport: (element: HTMLElement) => boolean;
2
+ export default isInViewport;
@@ -0,0 +1,2 @@
1
+ declare const isObjectInArray: <T>(array: T[], item: T, ignore?: string[]) => boolean;
2
+ export default isObjectInArray;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreui/vue-pro",
3
- "version": "4.7.0-alpha.1",
3
+ "version": "4.8.0-next.0",
4
4
  "description": "UI Components Library for Vue.js",
5
5
  "keywords": [
6
6
  "vue",
@@ -31,24 +31,20 @@
31
31
  "src/"
32
32
  ],
33
33
  "scripts": {
34
- "build": "rollup -c",
35
- "watch": "rollup -c -w"
36
- },
37
- "config": {
38
- "version_short": "4.6"
34
+ "build": "rollup -c --bundleConfigAsCjs"
39
35
  },
40
36
  "devDependencies": {
41
37
  "@popperjs/core": "^2.11.6",
42
- "@rollup/plugin-commonjs": "^22.0.2",
43
- "@rollup/plugin-node-resolve": "^13.3.0",
44
- "@rollup/plugin-typescript": "^8.5.0",
45
- "@vue/test-utils": "^2.0.2",
38
+ "@rollup/plugin-commonjs": "^24.0.1",
39
+ "@rollup/plugin-node-resolve": "^15.0.1",
40
+ "@rollup/plugin-typescript": "^11.0.0",
41
+ "@vue/test-utils": "^2.2.10",
46
42
  "date-fns": "^2.29.3",
47
- "rollup": "^2.79.0",
43
+ "rollup": "^3.15.0",
48
44
  "rollup-plugin-vue": "^6.0.0",
49
- "typescript": "^4.8.3",
50
- "vue": "^3.2.39",
51
- "vue-types": "^4.2.1"
45
+ "typescript": "^4.9.5",
46
+ "vue": "^3.2.47",
47
+ "vue-types": "^5.0.2"
52
48
  },
53
49
  "peerDependencies": {
54
50
  "@coreui/coreui-pro": "^4.3.4",
@@ -16,7 +16,7 @@ import {
16
16
  isToday,
17
17
  isStartDate,
18
18
  isEndDate,
19
- } from '../../utils/calendar'
19
+ } from './utils'
20
20
 
21
21
  const CCalendar = defineComponent({
22
22
  name: 'CCalendar',
@@ -4,7 +4,7 @@ export const convertToLocalDate = (d: Date, locale: string, options = {}) =>
4
4
  export const convertToLocalTime = (d: Date, locale: string, options = {}) =>
5
5
  d.toLocaleTimeString(locale, options)
6
6
 
7
- export const createGroupsInArray = (arr: any[], numberOfGroups: number) => {
7
+ export const createGroupsInArray = <T>(arr: T[], numberOfGroups: number): T[][] => {
8
8
  const perGroup = Math.ceil(arr.length / numberOfGroups)
9
9
  return new Array(numberOfGroups)
10
10
  .fill('')
@@ -164,7 +164,7 @@ export const getMonthDetails = (year: number, month: number, firstDayOfWeek: num
164
164
  export const isDisableDateInRange = (
165
165
  startDate?: Date | null,
166
166
  endDate?: Date | null,
167
- dates?: Date[] | Date[][],
167
+ dates?: Date[] | Date[][] | (Date | Date[])[],
168
168
  ) => {
169
169
  if (startDate && endDate) {
170
170
  const date = new Date(startDate)
@@ -188,7 +188,7 @@ export const isDateDisabled = (
188
188
  date: Date,
189
189
  min?: Date | null,
190
190
  max?: Date | null,
191
- dates?: Date[] | Date[][],
191
+ dates?: Date[] | Date[][] | (Date | Date[])[],
192
192
  ) => {
193
193
  let disabled
194
194
  if (dates) {
@@ -11,7 +11,7 @@ import {
11
11
  watch,
12
12
  } from 'vue'
13
13
 
14
- import { isVisible } from './../../utils'
14
+ import { isInViewport } from './../../utils'
15
15
 
16
16
  const CCarousel = defineComponent({
17
17
  name: 'CCarousel',
@@ -133,7 +133,7 @@ const CCarousel = defineComponent({
133
133
  const nextItemWhenVisible = () => {
134
134
  // Don't call next when the page isn't visible
135
135
  // or the carousel or its parent isn't visible
136
- if (!document.hidden && isVisible(carouselRef.value)) {
136
+ if (!document.hidden && isInViewport(carouselRef.value)) {
137
137
  handleControlClick('next')
138
138
  }
139
139
  }
@@ -156,7 +156,7 @@ const CCarousel = defineComponent({
156
156
  }
157
157
 
158
158
  const handleScroll = () => {
159
- if (!document.hidden && isVisible(carouselRef.value)) {
159
+ if (!document.hidden && isInViewport(carouselRef.value)) {
160
160
  visible.value = true
161
161
  } else {
162
162
  visible.value = false
@@ -9,7 +9,7 @@ import { CFormControlWrapper } from './../form/CFormControlWrapper'
9
9
  import { CPicker } from '../picker'
10
10
  import { CTimePicker } from '../time-picker'
11
11
 
12
- import { getLocalDateFromString } from '../../utils/calendar'
12
+ import { getLocalDateFromString } from '../calendar/utils'
13
13
 
14
14
  import { Color } from '../props'
15
15
 
@@ -1,4 +1,4 @@
1
- import { defineComponent, h, onMounted, nextTick, ref, Ref } from 'vue'
1
+ import { defineComponent, h, onMounted, nextTick, ref, PropType, Ref } from 'vue'
2
2
  import { CSpinner } from '../spinner'
3
3
 
4
4
  const CElementCover = defineComponent({
@@ -11,11 +11,7 @@ const CElementCover = defineComponent({
11
11
  *
12
12
  * @type {sides: string[], query: string}[]
13
13
  */
14
- boundaries: {
15
- // TODO: check if this is correct, TJ
16
- type: Array,
17
- require: true,
18
- },
14
+ boundaries: Array as PropType<{ sides: string[]; query: string }[]>,
19
15
  /**
20
16
  * Opacity of the cover. [docs]
21
17
  *
@@ -23,30 +19,38 @@ const CElementCover = defineComponent({
23
19
  */
24
20
  opacity: {
25
21
  type: Number,
26
- require: false,
22
+ default: 0.4,
27
23
  },
28
24
  },
29
- setup(props) {
30
- let containerCoords = {}
31
- const elementRef = ref() as Ref<HTMLElement>
25
+ /**
26
+ * Location for custom content.
27
+ *
28
+ * @slot default
29
+ */
30
+ setup(props, { slots }) {
31
+ const elementCoverRef = ref() as Ref<HTMLElement>
32
+ const customBoundaries = ref({})
32
33
 
33
34
  const getCustomBoundaries = () => {
34
- if (!props.boundaries || elementRef === null) {
35
+ if (!props.boundaries || elementCoverRef === null) {
35
36
  return {}
36
37
  }
37
- const parent = elementRef.value.parentElement
38
+
39
+ const parent = elementCoverRef.value.parentElement
38
40
  if (!parent) {
39
41
  return {}
40
42
  }
43
+
41
44
  const parentCoords = parent.getBoundingClientRect()
42
45
  const customBoundaries = {}
43
- props.boundaries.forEach((value: any) => {
44
- const element = parent.querySelector(value.query)
45
- if (!element || !value.sides) {
46
+ props.boundaries.forEach(({ sides, query }) => {
47
+ const element = parent.querySelector(query)
48
+ if (!element || !sides) {
46
49
  return
47
50
  }
51
+
48
52
  const coords = element.getBoundingClientRect()
49
- value.sides.forEach((side: string) => {
53
+ sides.forEach((side) => {
50
54
  const sideMargin = Math.abs(coords[side] - parentCoords[side])
51
55
  customBoundaries[side] = `${sideMargin}px`
52
56
  })
@@ -54,9 +58,22 @@ const CElementCover = defineComponent({
54
58
  return customBoundaries
55
59
  }
56
60
 
57
- onMounted(function () {
58
- nextTick(function () {
59
- containerCoords = getCustomBoundaries()
61
+ const containerCoords = {
62
+ top: 0,
63
+ left: 0,
64
+ right: 0,
65
+ bottom: 0,
66
+ }
67
+
68
+ const coverStyles = {
69
+ ...containerCoords,
70
+ position: 'absolute',
71
+ 'background-color': `rgba(255,255,255,${props.opacity})`,
72
+ }
73
+
74
+ onMounted(() => {
75
+ nextTick(() => {
76
+ customBoundaries.value = getCustomBoundaries()
60
77
  })
61
78
  })
62
79
 
@@ -64,15 +81,11 @@ const CElementCover = defineComponent({
64
81
  h(
65
82
  'div',
66
83
  {
67
- style: {
68
- ...containerCoords,
69
- position: 'absolute',
70
- 'background-color': `rgb(255,255,255,${props.opacity})`,
71
- },
72
- ref: elementRef,
84
+ style: { ...coverStyles, ...customBoundaries.value },
85
+ ref: elementCoverRef,
73
86
  },
74
87
  h(
75
- 'div', // TODO: use slot to override this
88
+ 'div',
76
89
  {
77
90
  style: {
78
91
  position: 'absolute',
@@ -81,10 +94,12 @@ const CElementCover = defineComponent({
81
94
  transform: 'translateX(-50%) translateY(-50%)',
82
95
  },
83
96
  },
84
- h(CSpinner, {
85
- variant: 'grow',
86
- color: 'primary',
87
- }),
97
+ slots.default
98
+ ? slots.default()
99
+ : h(CSpinner, {
100
+ variant: 'grow',
101
+ color: 'primary',
102
+ }),
88
103
  ),
89
104
  )
90
105
  },
@@ -41,6 +41,30 @@ const CFormControlWrapper = defineComponent({
41
41
  },
42
42
  },
43
43
  setup(props, { slots }) {
44
+ const formControlValidation = () =>
45
+ h(
46
+ CFormControlValidation,
47
+ {
48
+ describedby: props.describedby,
49
+ feedback: props.feedback,
50
+ feedbackInvalid: props.feedbackInvalid,
51
+ feedbackValid: props.feedbackValid,
52
+ floatingLabel: props.floatingLabel,
53
+ invalid: props.invalid,
54
+ tooltipFeedback: props.tooltipFeedback,
55
+ valid: props.valid,
56
+ },
57
+ {
58
+ ...(slots.feedback && { feedback: () => slots.feedback && slots.feedback() }),
59
+ ...(slots.feedbackInvalid && {
60
+ feedbackInvalid: () => slots.feedbackInvalid && slots.feedbackInvalid(),
61
+ }),
62
+ ...(slots.feedbackValid && {
63
+ feedbackValid: () => slots.feedbackInvalid && slots.feedbackInvalid(),
64
+ }),
65
+ },
66
+ )
67
+
44
68
  return () =>
45
69
  props.floatingLabel
46
70
  ? h(CFormFloating, () => [
@@ -54,6 +78,17 @@ const CFormControlWrapper = defineComponent({
54
78
  default: () => (slots.label && slots.label()) || props.label || props.floatingLabel,
55
79
  },
56
80
  ),
81
+ (props.text || slots.text) &&
82
+ h(
83
+ CFormText,
84
+ {
85
+ id: props.describedby,
86
+ },
87
+ {
88
+ default: () => (slots.text && slots.text()) || props.text,
89
+ },
90
+ ),
91
+ formControlValidation(),
57
92
  ])
58
93
  : [
59
94
  (props.label || slots.label) &&
@@ -77,28 +112,7 @@ const CFormControlWrapper = defineComponent({
77
112
  default: () => (slots.text && slots.text()) || props.text,
78
113
  },
79
114
  ),
80
- h(
81
- CFormControlValidation,
82
- {
83
- describedby: props.describedby,
84
- feedback: props.feedback,
85
- feedbackInvalid: props.feedbackInvalid,
86
- feedbackValid: props.feedbackValid,
87
- floatingLabel: props.floatingLabel,
88
- invalid: props.invalid,
89
- tooltipFeedback: props.tooltipFeedback,
90
- valid: props.valid,
91
- },
92
- {
93
- ...(slots.feedback && { feedback: () => slots.feedback && slots.feedback() }),
94
- ...(slots.feedbackInvalid && {
95
- feedbackInvalid: () => slots.feedbackInvalid && slots.feedbackInvalid(),
96
- }),
97
- ...(slots.feedbackValid && {
98
- feedbackValid: () => slots.feedbackInvalid && slots.feedbackInvalid(),
99
- }),
100
- },
101
- ),
115
+ formControlValidation(),
102
116
  ]
103
117
  },
104
118
  })
@@ -25,7 +25,6 @@ const CModal = defineComponent({
25
25
  */
26
26
  alignment: {
27
27
  default: 'top',
28
- required: false,
29
28
  validator: (value: string) => {
30
29
  return ['top', 'center'].includes(value)
31
30
  },
@@ -33,12 +32,20 @@ const CModal = defineComponent({
33
32
  /**
34
33
  * Apply a backdrop on body while offcanvas is open.
35
34
  *
36
- * @values 'static'
35
+ * @values boolean | 'static'
37
36
  */
38
37
  backdrop: {
39
38
  type: [Boolean, String],
40
39
  default: true,
41
- require: false,
40
+ validator: (value: boolean | string) => {
41
+ if (typeof value == 'string') {
42
+ return ['static'].includes(value)
43
+ }
44
+ if (typeof value == 'boolean') {
45
+ return true
46
+ }
47
+ return false
48
+ },
42
49
  },
43
50
  /**
44
51
  * A string of all className you want applied to the modal content component.
@@ -46,7 +53,6 @@ const CModal = defineComponent({
46
53
  contentClassName: {
47
54
  type: String,
48
55
  default: undefined,
49
- required: false,
50
56
  },
51
57
  /**
52
58
  * Set modal to covers the entire user viewport
@@ -56,7 +62,6 @@ const CModal = defineComponent({
56
62
  fullscreen: {
57
63
  type: [Boolean, String],
58
64
  default: undefined,
59
- required: false,
60
65
  validator: (value: boolean | string) => {
61
66
  if (typeof value == 'string') {
62
67
  return ['sm', 'md', 'lg', 'xl', 'xxl'].includes(value)
@@ -73,14 +78,12 @@ const CModal = defineComponent({
73
78
  keyboard: {
74
79
  type: Boolean,
75
80
  default: true,
76
- required: false,
77
81
  },
78
82
  /**
79
83
  * Create a scrollable modal that allows scrolling the modal body.
80
84
  */
81
85
  scrollable: {
82
86
  type: Boolean,
83
- required: false,
84
87
  },
85
88
  /**
86
89
  * Size the component small, large, or extra large.
@@ -90,7 +93,6 @@ const CModal = defineComponent({
90
93
  size: {
91
94
  type: String,
92
95
  default: undefined,
93
- required: false,
94
96
  validator: (value: string) => {
95
97
  return ['sm', 'lg', 'xl'].includes(value)
96
98
  },
@@ -101,7 +103,6 @@ const CModal = defineComponent({
101
103
  transition: {
102
104
  type: Boolean,
103
105
  default: true,
104
- required: false,
105
106
  },
106
107
  /**
107
108
  * By default the component is unmounted after close animation, if you want to keep the component mounted set this property to false.
@@ -109,7 +110,6 @@ const CModal = defineComponent({
109
110
  unmountOnClose: {
110
111
  type: Boolean,
111
112
  default: true,
112
- required: false,
113
113
  },
114
114
  /**
115
115
  * Toggle the visibility of alert component.
@@ -361,16 +361,6 @@ const CMultiSelect = defineComponent({
361
361
  : options.value
362
362
  }
363
363
 
364
- // watch(
365
- // () => props.options,
366
- // (newValue, oldValue) => {
367
- // console.log(props.options)
368
- // if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) options.value = newValue
369
- // },
370
- // )
371
-
372
-
373
-
374
364
  const handleSearchChange = (event: InputEvent) => {
375
365
  const target = event.target as HTMLInputElement
376
366
  search.value = target.value.toLowerCase()
@@ -10,11 +10,21 @@ const COffcanvas = defineComponent({
10
10
  props: {
11
11
  /**
12
12
  * Apply a backdrop on body while offcanvas is open.
13
+ *
14
+ * @values boolean | 'static'
13
15
  */
14
16
  backdrop: {
15
- type: Boolean,
17
+ type: [Boolean, String],
16
18
  default: true,
17
- require: false,
19
+ validator: (value: boolean | string) => {
20
+ if (typeof value === 'string') {
21
+ return ['static'].includes(value)
22
+ }
23
+ if (typeof value === 'boolean') {
24
+ return true
25
+ }
26
+ return false
27
+ },
18
28
  },
19
29
  /**
20
30
  * Closes the offcanvas when escape key is pressed.
@@ -22,7 +32,6 @@ const COffcanvas = defineComponent({
22
32
  keyboard: {
23
33
  type: Boolean,
24
34
  default: true,
25
- require: false,
26
35
  },
27
36
  /**
28
37
  * Components placement, there’s no default placement.
@@ -37,21 +46,36 @@ const COffcanvas = defineComponent({
37
46
  return ['start', 'end', 'top', 'bottom'].includes(value)
38
47
  },
39
48
  },
49
+ /**
50
+ * Responsive offcanvas property hide content outside the viewport from a specified breakpoint and down.
51
+ *
52
+ * @values boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
53
+ * @since 4.7.0
54
+ */
55
+ responsive: {
56
+ type: [Boolean, String],
57
+ default: true,
58
+ validator: (value: boolean | string) => {
59
+ if (typeof value === 'string') {
60
+ return ['sm', 'md', 'lg', 'xl', 'xxl'].includes(value)
61
+ }
62
+ if (typeof value === 'boolean') {
63
+ return true
64
+ }
65
+ return false
66
+ },
67
+ },
40
68
  /**
41
69
  * Allow body scrolling while offcanvas is open
42
70
  */
43
71
  scroll: {
44
72
  type: Boolean,
45
73
  default: false,
46
- required: false,
47
74
  },
48
75
  /**
49
76
  * Toggle the visibility of offcanvas component.
50
77
  */
51
- visible: {
52
- type: Boolean,
53
- require: false,
54
- },
78
+ visible: Boolean,
55
79
  },
56
80
  emits: [
57
81
  /**
@@ -93,22 +117,21 @@ const COffcanvas = defineComponent({
93
117
  emit('show')
94
118
  executeAfterTransition(() => done(), el as HTMLElement)
95
119
  setTimeout(() => {
96
- el.style.visibility = 'visible'
97
120
  el.classList.add('show')
98
121
  }, 1)
99
122
  }
123
+
100
124
  const handleAfterEnter = () => {
101
- window.addEventListener('mousedown', handleMouseDown)
102
- window.addEventListener('keyup', handleKeyUp)
125
+ offcanvasRef.value.focus()
103
126
  }
127
+
104
128
  const handleLeave = (el: RendererElement, done: () => void) => {
105
129
  executeAfterTransition(() => done(), el as HTMLElement)
106
- window.removeEventListener('mousedown', handleMouseDown)
107
- window.removeEventListener('keyup', handleKeyUp)
108
- el.classList.remove('show')
130
+ el.classList.add('hiding')
109
131
  }
132
+
110
133
  const handleAfterLeave = (el: RendererElement) => {
111
- el.style.visibility = 'hidden'
134
+ el.classList.remove('show', 'hiding')
112
135
  }
113
136
 
114
137
  const handleDismiss = () => {
@@ -116,21 +139,15 @@ const COffcanvas = defineComponent({
116
139
  emit('hide')
117
140
  }
118
141
 
119
- const handleKeyUp = (event: KeyboardEvent) => {
120
- if (offcanvasRef.value && !offcanvasRef.value.contains(event.target as HTMLElement)) {
121
- if (event.key === 'Escape' && props.keyboard && props.backdrop) {
122
- return handleDismiss()
123
- }
142
+ const handleBackdropDismiss = () => {
143
+ if (props.backdrop !== 'static') {
144
+ handleDismiss()
124
145
  }
125
146
  }
126
147
 
127
- const handleMouseDown = (event: Event) => {
128
- window.addEventListener('mouseup', () => handleMouseUp(event), { once: true })
129
- }
130
-
131
- const handleMouseUp = (event: Event) => {
132
- if (offcanvasRef.value && !offcanvasRef.value.contains(event.target as HTMLElement)) {
133
- props.backdrop && handleDismiss()
148
+ const handleKeyDown = (event: KeyboardEvent) => {
149
+ if (event.key === 'Escape' && props.keyboard) {
150
+ handleDismiss()
134
151
  }
135
152
  }
136
153
 
@@ -150,13 +167,17 @@ const COffcanvas = defineComponent({
150
167
  'div',
151
168
  {
152
169
  class: [
153
- 'offcanvas',
154
170
  {
171
+ [`offcanvas${
172
+ typeof props.responsive !== 'boolean' ? '-' + props.responsive : ''
173
+ }`]: props.responsive,
155
174
  [`offcanvas-${props.placement}`]: props.placement,
156
175
  },
157
176
  ],
177
+ onKeydown: (event: KeyboardEvent) => handleKeyDown(event),
158
178
  ref: offcanvasRef,
159
179
  role: 'dialog',
180
+ tabindex: -1,
160
181
  },
161
182
  slots.default && slots.default(),
162
183
  ),
@@ -166,6 +187,7 @@ const COffcanvas = defineComponent({
166
187
  props.backdrop &&
167
188
  h(CBackdrop, {
168
189
  class: 'offcanvas-backdrop',
190
+ onClick: handleBackdropDismiss,
169
191
  visible: visible.value,
170
192
  }),
171
193
  ]
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, h, onBeforeUnmount, onMounted, ref, watch } from 'vue'
2
2
  import { CBackdrop } from '../backdrop'
3
3
 
4
- import { isVisible } from './../../utils'
4
+ import { isInViewport } from './../../utils'
5
5
 
6
6
  const isOnMobile = (element: HTMLDivElement) =>
7
7
  Boolean(getComputedStyle(element).getPropertyValue('--cui-is-mobile'))
@@ -111,7 +111,7 @@ const CSidebar = defineComponent({
111
111
 
112
112
  onMounted(() => {
113
113
  mobile.value = isOnMobile(sidebarRef.value)
114
- inViewport.value = isVisible(sidebarRef.value)
114
+ inViewport.value = isInViewport(sidebarRef.value)
115
115
 
116
116
  window.addEventListener('resize', () => handleResize())
117
117
  window.addEventListener('mouseup', handleClickOutside)
@@ -119,7 +119,7 @@ const CSidebar = defineComponent({
119
119
 
120
120
  sidebarRef.value.addEventListener('mouseup', handleOnClick)
121
121
  sidebarRef.value.addEventListener('transitionend', () => {
122
- inViewport.value = isVisible(sidebarRef.value)
122
+ inViewport.value = isInViewport(sidebarRef.value)
123
123
  })
124
124
  })
125
125
 
@@ -130,7 +130,7 @@ const CSidebar = defineComponent({
130
130
 
131
131
  sidebarRef.value.removeEventListener('mouseup', handleOnClick)
132
132
  sidebarRef.value.removeEventListener('transitionend', () => {
133
- inViewport.value = isVisible(sidebarRef.value)
133
+ inViewport.value = isInViewport(sidebarRef.value)
134
134
  })
135
135
  })
136
136
 
@@ -141,7 +141,7 @@ const CSidebar = defineComponent({
141
141
 
142
142
  const handleResize = () => {
143
143
  mobile.value = isOnMobile(sidebarRef.value)
144
- inViewport.value = isVisible(sidebarRef.value)
144
+ inViewport.value = isInViewport(sidebarRef.value)
145
145
  }
146
146
 
147
147
  const handleKeyup = (event: Event) => {