@coreui/react-pro 4.11.0-next.1 → 4.11.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreui/react-pro",
3
- "version": "4.11.0-next.1",
3
+ "version": "4.11.1",
4
4
  "description": "UI Components Library for React.js",
5
5
  "keywords": [
6
6
  "react",
@@ -64,7 +64,7 @@
64
64
  "typescript": "^4.9.5"
65
65
  },
66
66
  "peerDependencies": {
67
- "@coreui/coreui-pro": ">=4.4.4",
67
+ "@coreui/coreui-pro": ">=4.5.0",
68
68
  "react": ">=17",
69
69
  "react-dom": ">=17"
70
70
  }
@@ -1,7 +1,6 @@
1
1
  import { CAccordion } from './CAccordion'
2
2
  import { CAccordionBody } from './CAccordionBody'
3
3
  import { CAccordionButton } from './CAccordionButton'
4
- import { CAccordionCollapse } from './CAccordionCollapse'
5
4
  import { CAccordionHeader } from './CAccordionHeader'
6
5
  import { CAccordionItem } from './CAccordionItem'
7
6
 
@@ -9,7 +8,6 @@ export {
9
8
  CAccordion,
10
9
  CAccordionBody,
11
10
  CAccordionButton,
12
- CAccordionCollapse,
13
11
  CAccordionHeader,
14
12
  CAccordionItem,
15
13
  }
@@ -106,13 +106,13 @@ export interface CCalendarProps {
106
106
  /**
107
107
  * Set whether days in adjacent months shown before or after the current month are selectable. This only applies if the `showAdjacementDays` option is set to true.
108
108
  *
109
- * @since 4.11.0-next.0
109
+ * @since 4.11.0
110
110
  */
111
111
  selectAdjacementDays?: boolean
112
112
  /**
113
113
  * Set whether to display dates in adjacent months (non-selectable) at the start and end of the current month.
114
114
  *
115
- * @since 4.11.0-next.0
115
+ * @since 4.11.0
116
116
  */
117
117
  showAdjacementDays?: boolean
118
118
  /**
@@ -78,6 +78,12 @@ export interface CDropdownProps extends HTMLAttributes<HTMLDivElement | HTMLLIEl
78
78
  * If you want to disable dynamic positioning set this property to `true`.
79
79
  */
80
80
  popper?: boolean
81
+ /**
82
+ * Generates dropdown menu using createPortal.
83
+ *
84
+ * @since 4.8.0
85
+ */
86
+ portal?: boolean
81
87
  /**
82
88
  * Set the dropdown variant to an btn-group, dropdown, input-group, and nav-item.
83
89
  */
@@ -88,13 +94,7 @@ export interface CDropdownProps extends HTMLAttributes<HTMLDivElement | HTMLLIEl
88
94
  visible?: boolean
89
95
  }
90
96
 
91
- const PopperManagerWrapper = ({
92
- children,
93
- popper,
94
- }: {
95
- children: ReactNode
96
- popper: boolean
97
- }) => {
97
+ const PopperManagerWrapper = ({ children, popper }: { children: ReactNode; popper: boolean }) => {
98
98
  return popper ? <Manager>{children}</Manager> : <>{children}</>
99
99
  }
100
100
 
@@ -102,6 +102,7 @@ interface ContextProps extends CDropdownProps {
102
102
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
103
103
  dropdownToggleRef: RefObject<any> | undefined
104
104
  setVisible: React.Dispatch<React.SetStateAction<boolean | undefined>>
105
+ portal: boolean
105
106
  }
106
107
 
107
108
  export const CDropdownContext = createContext({} as ContextProps)
@@ -119,6 +120,7 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
119
120
  onShow,
120
121
  placement = 'bottom-start',
121
122
  popper = true,
123
+ portal = false,
122
124
  variant = 'btn-group',
123
125
  component = 'div',
124
126
  visible = false,
@@ -146,6 +148,7 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
146
148
  dropdownToggleRef,
147
149
  placement: placement,
148
150
  popper,
151
+ portal: portal,
149
152
  variant,
150
153
  visible: _visible,
151
154
  setVisible,
@@ -172,7 +175,8 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
172
175
  {
173
176
  'dropdown-center': direction === 'center',
174
177
  'dropup dropup-center': direction === 'dropup-center',
175
- direction: direction && direction !== 'center' && direction !== 'dropup-center',
178
+ [`${direction}`]:
179
+ direction && direction !== 'center' && direction !== 'dropup-center',
176
180
  show: _visible,
177
181
  },
178
182
  className,
@@ -215,6 +219,7 @@ CDropdown.propTypes = {
215
219
  onShow: PropTypes.func,
216
220
  placement: placementPropType,
217
221
  popper: PropTypes.bool,
222
+ portal: PropTypes.bool,
218
223
  variant: PropTypes.oneOf(['btn-group', 'dropdown', 'input-group', 'nav-item']),
219
224
  visible: PropTypes.bool,
220
225
  }
@@ -4,6 +4,7 @@ import classNames from 'classnames'
4
4
  import { Popper, PopperChildrenProps } from 'react-popper'
5
5
 
6
6
  import { Alignments, CDropdownContext } from './CDropdown'
7
+ import { CConditionalPortal } from '../conditional-portal'
7
8
 
8
9
  import type { Placements } from '../../types'
9
10
 
@@ -30,6 +31,21 @@ export interface CDropdownMenuProps
30
31
  component?: string | ElementType
31
32
  }
32
33
 
34
+ const alignmentClassNames = (alignment: Alignments) => {
35
+ const classNames: string[] = []
36
+ if (typeof alignment === 'object') {
37
+ Object.keys(alignment).map((key) => {
38
+ classNames.push(`dropdown-menu${key === 'xs' ? '' : `-${key}`}-${alignment[key]}`)
39
+ })
40
+ }
41
+
42
+ if (typeof alignment === 'string') {
43
+ classNames.push(`dropdown-menu-${alignment}`)
44
+ }
45
+
46
+ return classNames
47
+ }
48
+
33
49
  export const CDropdownMenu: FC<CDropdownMenuProps> = ({
34
50
  children,
35
51
  className,
@@ -44,6 +60,7 @@ export const CDropdownMenu: FC<CDropdownMenuProps> = ({
44
60
  dropdownToggleRef,
45
61
  placement,
46
62
  popper,
63
+ portal,
47
64
  visible,
48
65
  setVisible,
49
66
  } = useContext(CDropdownContext)
@@ -111,48 +128,35 @@ export const CDropdownMenu: FC<CDropdownMenuProps> = ({
111
128
  _placement = 'bottom-end'
112
129
  }
113
130
 
114
- const alignmentClassNames = (alignment: Alignments) => {
115
- const classNames: string[] = []
116
- if (typeof alignment === 'object') {
117
- Object.keys(alignment).map((key) => {
118
- classNames.push(`dropdown-menu${key === 'xs' ? '' : `-${key}`}-${alignment[key]}`)
119
- })
120
- }
121
-
122
- if (typeof alignment === 'string') {
123
- classNames.push(`dropdown-menu-${alignment}`)
124
- }
125
-
126
- return classNames
127
- }
128
-
129
131
  const dropdownMenuComponent = (style?: React.CSSProperties, ref?: React.Ref<HTMLDivElement>) => (
130
- <Component
131
- className={classNames(
132
- 'dropdown-menu',
133
- {
134
- 'dropdown-menu-dark': dark,
135
- show: visible,
136
- },
137
- alignment && alignmentClassNames(alignment),
138
- className,
139
- )}
140
- ref={ref}
141
- style={style}
142
- role="menu"
143
- aria-hidden={!visible}
144
- {...(!popper && { 'data-coreui-popper': 'static' })}
145
- {...rest}
146
- >
147
- {Component === 'ul'
148
- ? React.Children.map(children, (child, index) => {
149
- if (React.isValidElement(child)) {
150
- return <li key={index}>{React.cloneElement(child)}</li>
151
- }
152
- return
153
- })
154
- : children}
155
- </Component>
132
+ <CConditionalPortal portal={portal ?? false}>
133
+ <Component
134
+ className={classNames(
135
+ 'dropdown-menu',
136
+ {
137
+ 'dropdown-menu-dark': dark,
138
+ show: visible,
139
+ },
140
+ alignment && alignmentClassNames(alignment),
141
+ className,
142
+ )}
143
+ ref={ref}
144
+ style={style}
145
+ role="menu"
146
+ aria-hidden={!visible}
147
+ {...(!popper && { 'data-coreui-popper': 'static' })}
148
+ {...rest}
149
+ >
150
+ {Component === 'ul'
151
+ ? React.Children.map(children, (child, index) => {
152
+ if (React.isValidElement(child)) {
153
+ return <li key={index}>{React.cloneElement(child)}</li>
154
+ }
155
+ return
156
+ })
157
+ : children}
158
+ </Component>
159
+ </CConditionalPortal>
156
160
  )
157
161
 
158
162
  return popper && visible ? (
@@ -29,7 +29,7 @@ export interface CMultiSelectProps
29
29
  /**
30
30
  * Allow users to create options if they are not in the list of options.
31
31
  *
32
- * @since 4.11.0-next.0
32
+ * @since 4.11.0
33
33
  */
34
34
  allowCreateOptions?: boolean
35
35
  /**
@@ -43,7 +43,7 @@ export interface CMultiSelectProps
43
43
  /**
44
44
  * Clear current search on selecting an item.
45
45
  *
46
- * @since 4.11.0-next.0
46
+ * @since 4.11.0
47
47
  */
48
48
  clearSearchOnSelect?: boolean
49
49
  /**
@@ -53,7 +53,7 @@ export interface CMultiSelectProps
53
53
  /**
54
54
  * When set, the options list will have a loading style: loading spinner and reduced opacity.
55
55
  *
56
- * @since 4.11.0-next.0
56
+ * @since 4.11.0
57
57
  */
58
58
  loading?: boolean
59
59
  /**
@@ -80,11 +80,9 @@ export const COffcanvas = forwardRef<HTMLDivElement, COffcanvasProps>(
80
80
  }, [visible])
81
81
 
82
82
  useEffect(() => {
83
- if (_visible) {
84
- if (!scroll) {
85
- document.body.style.overflow = 'hidden'
86
- document.body.style.paddingRight = '0px'
87
- }
83
+ if (_visible && !scroll) {
84
+ document.body.style.overflow = 'hidden'
85
+ document.body.style.paddingRight = '0px'
88
86
  return
89
87
  }
90
88
 
@@ -88,9 +88,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
88
88
  const [columnFilterState, setColumnFilterState] = useState<ColumnFilterValue>({})
89
89
  const [selectedAll, setSelectedAll] = useState<boolean | string>()
90
90
  const [sorterState, setSorterState] = useState<SorterValue>({})
91
- const [tableFilterState, setTableFilterState] = useState<string>(
92
- tableFilterValue ? tableFilterValue : '',
93
- )
91
+ const [tableFilterState, setTableFilterState] = useState<string>(tableFilterValue ?? '')
94
92
 
95
93
  useEffect(() => {
96
94
  setActivePage(activePage)
@@ -170,7 +168,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
170
168
  return
171
169
  }
172
170
 
173
- if (_selected.length !== 0 && _selected.length !== _itemsNumber) {
171
+ if (_selected.length > 0 && _selected.length !== _itemsNumber) {
174
172
  setSelectedAll('indeterminate')
175
173
  }
176
174
  }
@@ -420,6 +418,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
420
418
  selectable={selectable}
421
419
  selectAll={selectAll}
422
420
  selectedAll={selectedAll}
421
+ showGroups={false}
423
422
  />
424
423
  )}
425
424
  {Array.isArray(footer) && (
@@ -51,7 +51,7 @@ export const CSmartTableBody = forwardRef<HTMLTableSectionElement, CSmartTableBo
51
51
  {...rest}
52
52
  ref={ref}
53
53
  >
54
- {currentItems.length ? (
54
+ {currentItems.length > 0 ? (
55
55
  currentItems.map((item: Item, trIndex) => {
56
56
  return (
57
57
  <React.Fragment key={trIndex}>
@@ -94,11 +94,13 @@ export const CSmartTableBody = forwardRef<HTMLTableSectionElement, CSmartTableBo
94
94
  {
95
95
  key: index,
96
96
  },
97
- )) || (
97
+ )) ||
98
+ // eslint-disable-next-line unicorn/no-typeof-undefined
99
+ (typeof item[colName] !== 'undefined' && (
98
100
  <CTableDataCell {...getTableDataCellProps(item, colName)} key={index}>
99
101
  {String(item[colName])}
100
102
  </CTableDataCell>
101
- )
103
+ ))
102
104
  )
103
105
  })}
104
106
  </CTableRow>
@@ -1,4 +1,12 @@
1
- import React, { ElementType, forwardRef, ReactNode, useEffect, useRef, useState } from 'react'
1
+ import React, {
2
+ ElementType,
3
+ forwardRef,
4
+ ReactNode,
5
+ useEffect,
6
+ useMemo,
7
+ useRef,
8
+ useState,
9
+ } from 'react'
2
10
  import PropTypes from 'prop-types'
3
11
 
4
12
  import { CFormCheck, CFormInput } from '../form'
@@ -8,6 +16,8 @@ import { CTableHead, CTableHeadProps } from '../table/CTableHead'
8
16
  import {
9
17
  getColumnKey,
10
18
  getColumnLabel,
19
+ getColumnGroups,
20
+ getColumns,
11
21
  getColumnSorterState,
12
22
  getColumnValues,
13
23
  getTableHeaderCellProps,
@@ -31,6 +41,7 @@ export interface CSmartTableHeadProps extends CTableHeadProps {
31
41
  selectable?: boolean
32
42
  selectAll?: boolean | { external?: boolean }
33
43
  selectedAll?: boolean | string
44
+ showGroups?: boolean
34
45
  sorterState?: SorterValue
35
46
  sortingIcon?: ReactNode
36
47
  sortingIconAscending?: ReactNode
@@ -54,6 +65,7 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
54
65
  selectable,
55
66
  selectAll,
56
67
  selectedAll,
68
+ showGroups = true,
57
69
  sorterState,
58
70
  sortingIcon,
59
71
  sortingIconAscending,
@@ -65,6 +77,9 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
65
77
  const selectAllcheckboxRef = useRef<HTMLInputElement>(null)
66
78
  const [refresh, setRefresh] = useState(false)
67
79
 
80
+ const _columns = useMemo(() => getColumns(columns), [columns])
81
+ const groups = useMemo(() => getColumnGroups(columns), [columns])
82
+
68
83
  useEffect(() => {
69
84
  if (selectedAll === 'indeterminate') {
70
85
  if (selectAllcheckboxRef.current) selectAllcheckboxRef.current.indeterminate = true
@@ -107,6 +122,23 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
107
122
 
108
123
  return (
109
124
  <Component {...rest} ref={ref}>
125
+ {showGroups &&
126
+ groups &&
127
+ groups.length > 0 &&
128
+ groups.map((row, index) => (
129
+ <CTableRow key={index}>
130
+ {selectable && <CTableHeaderCell></CTableHeaderCell>}
131
+ {row.map((cell, index) => (
132
+ <CTableHeaderCell
133
+ colSpan={cell.colspan}
134
+ {...getTableHeaderCellProps(cell)}
135
+ key={index}
136
+ >
137
+ {cell.label}
138
+ </CTableHeaderCell>
139
+ ))}
140
+ </CTableRow>
141
+ ))}
110
142
  <CTableRow>
111
143
  {selectable && (
112
144
  <CTableHeaderCell>
@@ -119,7 +151,7 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
119
151
  )}
120
152
  </CTableHeaderCell>
121
153
  )}
122
- {columns.map((column: Column | string, index: number) => {
154
+ {_columns.map((column: Column | string, index: number) => {
123
155
  return (
124
156
  <CTableHeaderCell
125
157
  {...getTableHeaderCellProps(column)}
@@ -129,11 +161,11 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
129
161
  >
130
162
  <div className="d-inline">{getColumnLabel(column)}</div>
131
163
  {columnSorter &&
132
- (typeof column !== 'object'
164
+ (typeof column === 'object'
165
+ ? typeof column.sorter === 'undefined'
133
166
  ? true
134
- : typeof column.sorter === 'undefined'
135
- ? true
136
- : column.sorter) &&
167
+ : column.sorter
168
+ : true) &&
137
169
  columnSorterIcon(column)}
138
170
  </CTableHeaderCell>
139
171
  )
@@ -142,15 +174,15 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
142
174
  {columnFilter && (
143
175
  <CTableRow>
144
176
  {selectable && <CTableHeaderCell></CTableHeaderCell>}
145
- {columns.map((column: Column | string, index: number) => {
177
+ {_columns.map((column: Column | string, index: number) => {
146
178
  return (
147
179
  <CTableHeaderCell {...getTableHeaderCellProps(column)} key={index}>
148
180
  {(
149
- typeof column !== 'object'
150
- ? true
151
- : typeof column.filter === 'undefined'
181
+ typeof column === 'object'
182
+ ? column.filter === undefined
152
183
  ? true
153
184
  : column.filter
185
+ : true
154
186
  ) ? (
155
187
  typeof column !== 'string' && typeof column.filter === 'function' ? (
156
188
  !refresh &&
@@ -5,7 +5,9 @@ import { CTableHeaderCellProps } from '../table/CTableHeaderCell'
5
5
  import { CTableRowProps } from '../table/CTableRow'
6
6
 
7
7
  export type Column = {
8
+ children?: Column[]
8
9
  filter?: boolean | ((values: any[], onChange: (value: any) => void) => ReactNode)
10
+ group?: string
9
11
  key: string
10
12
  label?: string
11
13
  sorter?: boolean
@@ -27,6 +29,17 @@ export type FooterItem = {
27
29
  _props?: CTableDataCellProps
28
30
  }
29
31
 
32
+ export type Group = {
33
+ children?: Group[] | Column[]
34
+ colspan?: number
35
+ deep?: number
36
+ group?: string
37
+ key: string
38
+ label?: string
39
+ _style?: any
40
+ _props?: CTableHeaderCellProps
41
+ }
42
+
30
43
  export type Item = {
31
44
  [key: string]: number | string | any
32
45
  _cellProps?: any
@@ -2,6 +2,7 @@ import type {
2
2
  Column,
3
3
  ColumnFilter,
4
4
  ColumnFilterValue,
5
+ Group,
5
6
  Item,
6
7
  Sorter,
7
8
  SorterValue,
@@ -77,12 +78,130 @@ export const getColumnLabel = (column: Column | string) =>
77
78
  : pretifyName(column.key)
78
79
  : pretifyName(column)
79
80
 
80
- export const getColumnNames = (columns: (string | Column)[] | undefined, items: Item[]) =>
81
- columns
82
- ? columns.map((column: Column | string) => {
83
- return typeof column === 'object' ? column.key : column
81
+ // export const getColumnNames = (columns: (string | Column)[] | undefined, items: Item[]) =>
82
+ // columns
83
+ // ? columns.map((column: Column | string) => {
84
+ // return typeof column === 'object' ? column.key : column
85
+ // })
86
+ // : getColumnNamesFromItems(items)
87
+
88
+ export const getColumnNames = (
89
+ columns: (string | Column)[] | undefined,
90
+ items: Item[],
91
+ ): string[] => {
92
+ if (columns) {
93
+ const _columns = []
94
+
95
+ for (const column of columns) {
96
+ if (typeof column === 'object' && column.children) {
97
+ _columns.push(...getColumnNames(column.children, []))
98
+ continue
99
+ }
100
+
101
+ typeof column === 'object' ? _columns.push(column.key) : _columns.push(column)
102
+ }
103
+
104
+ return _columns
105
+ }
106
+
107
+ return getColumnNamesFromItems(items)
108
+ }
109
+
110
+ export const getColumns = (_columns: (Column | Group | string)[]): (Column | string)[] => {
111
+ const columns = []
112
+
113
+ for (const column of _columns) {
114
+ if (typeof column === 'object' && column.group && column.children) {
115
+ columns.push(...getColumns(column.children))
116
+ continue
117
+ }
118
+
119
+ if (typeof column === 'object' && column.children) {
120
+ columns.push(...getColumns(column.children))
121
+ }
122
+
123
+ columns.push(column)
124
+ }
125
+
126
+ return columns
127
+ }
128
+
129
+ export const countColumns = (columns: Column[], counter = 0) => {
130
+ let _counter = counter
131
+ for (const column of columns) {
132
+ if (!column.children) {
133
+ _counter++
134
+ }
135
+
136
+ if (column.children) {
137
+ _counter = countColumns(column.children, _counter)
138
+ }
139
+ }
140
+
141
+ return _counter
142
+ }
143
+
144
+ export const getColumnGroups = (columns: (string | Column)[] | undefined) => {
145
+ const groups = []
146
+
147
+ const traverseColumns = (column: Column, deep = 0, colSpan = 0): Group[] => {
148
+ const groups = []
149
+
150
+ if (column.children) {
151
+ for (const _column of column.children) {
152
+ if (!_column.group) {
153
+ colSpan++
154
+ }
155
+ groups.push(...traverseColumns(_column, deep + 1, colSpan))
156
+ }
157
+ }
158
+
159
+ if (typeof column === 'object' && column.group) {
160
+ const { children, group, ...rest } = column
161
+ groups.push({
162
+ deep: deep,
163
+ label: group,
164
+ ...(children && { colspan: countColumns(children) }),
165
+ ...rest,
84
166
  })
85
- : getColumnNamesFromItems(items)
167
+ }
168
+
169
+ return groups
170
+ }
171
+
172
+ if (columns) {
173
+ for (const column of columns) {
174
+ if (typeof column === 'object' && column.group) {
175
+ const objects = traverseColumns(column)
176
+
177
+ if (objects) {
178
+ for (const object of objects) {
179
+ const { deep, ...rest } = object
180
+
181
+ if (deep === undefined) {
182
+ continue
183
+ }
184
+
185
+ for (let i = 0; i < deep; i++) {
186
+ if (groups[i]) {
187
+ continue
188
+ }
189
+
190
+ groups.push([])
191
+ }
192
+
193
+ if (groups[deep]) {
194
+ groups[deep].push(rest)
195
+ } else {
196
+ groups.push([rest])
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
203
+ return groups
204
+ }
86
205
 
87
206
  export const getColumnNamesFromItems = (items: Item[]) =>
88
207
  Object.keys(items[0] || {}).filter((el) => el.charAt(0) !== '_')