@coreui/react 5.9.2 → 5.11.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 (92) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -2
  3. package/dist/cjs/components/chip/CChip.d.ts +76 -0
  4. package/dist/cjs/components/chip/CChip.js +178 -0
  5. package/dist/cjs/components/chip/CChip.js.map +1 -0
  6. package/dist/cjs/components/chip/index.d.ts +2 -0
  7. package/dist/cjs/components/dropdown/CDropdown.js +1 -1
  8. package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
  9. package/dist/cjs/components/form/CChipInput.d.ts +92 -0
  10. package/dist/cjs/components/form/CChipInput.js +253 -0
  11. package/dist/cjs/components/form/CChipInput.js.map +1 -0
  12. package/dist/cjs/components/form/index.d.ts +2 -1
  13. package/dist/cjs/components/index.d.ts +2 -0
  14. package/dist/cjs/components/nav/CNavGroup.d.ts +3 -1
  15. package/dist/cjs/components/nav/CNavGroup.js +9 -5
  16. package/dist/cjs/components/nav/CNavGroup.js.map +1 -1
  17. package/dist/cjs/components/popover/CPopover.js +14 -17
  18. package/dist/cjs/components/popover/CPopover.js.map +1 -1
  19. package/dist/cjs/components/search-button/CSearchButton.d.ts +32 -0
  20. package/dist/cjs/components/search-button/CSearchButton.js +77 -0
  21. package/dist/cjs/components/search-button/CSearchButton.js.map +1 -0
  22. package/dist/cjs/components/search-button/index.d.ts +2 -0
  23. package/dist/cjs/components/search-button/types.d.ts +10 -0
  24. package/dist/cjs/components/search-button/utils.d.ts +11 -0
  25. package/dist/cjs/components/search-button/utils.js +115 -0
  26. package/dist/cjs/components/search-button/utils.js.map +1 -0
  27. package/dist/cjs/components/sidebar/CSidebarNav.d.ts +12 -0
  28. package/dist/cjs/components/sidebar/CSidebarNav.js +7 -2
  29. package/dist/cjs/components/sidebar/CSidebarNav.js.map +1 -1
  30. package/dist/cjs/components/tooltip/CTooltip.js +14 -17
  31. package/dist/cjs/components/tooltip/CTooltip.js.map +1 -1
  32. package/dist/cjs/index.js +6 -0
  33. package/dist/cjs/index.js.map +1 -1
  34. package/dist/esm/components/chip/CChip.d.ts +76 -0
  35. package/dist/esm/components/chip/CChip.js +176 -0
  36. package/dist/esm/components/chip/CChip.js.map +1 -0
  37. package/dist/esm/components/chip/index.d.ts +2 -0
  38. package/dist/esm/components/dropdown/CDropdown.js +1 -1
  39. package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
  40. package/dist/esm/components/form/CChipInput.d.ts +92 -0
  41. package/dist/esm/components/form/CChipInput.js +251 -0
  42. package/dist/esm/components/form/CChipInput.js.map +1 -0
  43. package/dist/esm/components/form/index.d.ts +2 -1
  44. package/dist/esm/components/index.d.ts +2 -0
  45. package/dist/esm/components/nav/CNavGroup.d.ts +3 -1
  46. package/dist/esm/components/nav/CNavGroup.js +9 -5
  47. package/dist/esm/components/nav/CNavGroup.js.map +1 -1
  48. package/dist/esm/components/popover/CPopover.js +14 -17
  49. package/dist/esm/components/popover/CPopover.js.map +1 -1
  50. package/dist/esm/components/search-button/CSearchButton.d.ts +32 -0
  51. package/dist/esm/components/search-button/CSearchButton.js +75 -0
  52. package/dist/esm/components/search-button/CSearchButton.js.map +1 -0
  53. package/dist/esm/components/search-button/index.d.ts +2 -0
  54. package/dist/esm/components/search-button/types.d.ts +10 -0
  55. package/dist/esm/components/search-button/utils.d.ts +11 -0
  56. package/dist/esm/components/search-button/utils.js +104 -0
  57. package/dist/esm/components/search-button/utils.js.map +1 -0
  58. package/dist/esm/components/sidebar/CSidebarNav.d.ts +12 -0
  59. package/dist/esm/components/sidebar/CSidebarNav.js +7 -2
  60. package/dist/esm/components/sidebar/CSidebarNav.js.map +1 -1
  61. package/dist/esm/components/tooltip/CTooltip.js +14 -17
  62. package/dist/esm/components/tooltip/CTooltip.js.map +1 -1
  63. package/dist/esm/index.js +3 -0
  64. package/dist/esm/index.js.map +1 -1
  65. package/package.json +7 -7
  66. package/src/components/chip/CChip.tsx +372 -0
  67. package/src/components/chip/__tests__/CChip.spec.tsx +113 -0
  68. package/src/components/chip/__tests__/__snapshots__/CChip.spec.tsx.snap +65 -0
  69. package/src/components/chip/index.ts +3 -0
  70. package/src/components/dropdown/CDropdown.tsx +1 -1
  71. package/src/components/dropdown/__tests__/CDropdown.spec.tsx +1 -1
  72. package/src/components/dropdown/__tests__/__snapshots__/CDropdown.spec.tsx.snap +2 -2
  73. package/src/components/dropdown/__tests__/__snapshots__/CDropdownMenu.spec.tsx.snap +1 -1
  74. package/src/components/form/CChipInput.tsx +477 -0
  75. package/src/components/form/__tests__/CChipInput.spec.tsx +62 -0
  76. package/src/components/form/__tests__/__snapshots__/CChipInput.spec.tsx.snap +91 -0
  77. package/src/components/form/index.ts +2 -0
  78. package/src/components/index.ts +2 -0
  79. package/src/components/nav/CNavGroup.tsx +11 -6
  80. package/src/components/nav/__tests__/CNavGroup.spec.tsx +29 -1
  81. package/src/components/nav/__tests__/__snapshots__/CNavGroup.spec.tsx.snap +1 -1
  82. package/src/components/popover/CPopover.tsx +15 -20
  83. package/src/components/popover/__tests__/CPopover.spec.tsx +10 -4
  84. package/src/components/search-button/CSearchButton.tsx +195 -0
  85. package/src/components/search-button/__tests__/CSearchButton.spec.tsx +95 -0
  86. package/src/components/search-button/__tests__/__snapshots__/CSearchButton.spec.tsx.snap +87 -0
  87. package/src/components/search-button/index.ts +3 -0
  88. package/src/components/search-button/types.ts +10 -0
  89. package/src/components/search-button/utils.ts +140 -0
  90. package/src/components/sidebar/CSidebarNav.tsx +27 -2
  91. package/src/components/tooltip/CTooltip.tsx +15 -20
  92. package/src/components/tooltip/__tests__/CTooltip.spec.tsx +6 -0
@@ -0,0 +1,140 @@
1
+ import type { SearchButtonShortcut } from './types'
2
+
3
+ const MODIFIER_KEYS = new Set(['alt', 'ctrl', 'meta', 'shift'])
4
+ const KEY_ALIASES: Record<string, string> = {
5
+ ' ': 'space',
6
+ cmd: 'meta',
7
+ command: 'meta',
8
+ control: 'ctrl',
9
+ esc: 'escape',
10
+ option: 'alt',
11
+ return: 'enter',
12
+ spacebar: 'space',
13
+ }
14
+ const KEY_LABELS: Record<string, string> = {
15
+ alt: 'Alt',
16
+ ctrl: 'Ctrl',
17
+ meta: '⌘',
18
+ shift: 'Shift',
19
+ space: 'Space',
20
+ }
21
+ const EDITABLE_TARGET_SELECTOR =
22
+ 'input, textarea, select, [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]'
23
+
24
+ export const normalizeKey = (key: string) => KEY_ALIASES[key.toLowerCase()] || key.toLowerCase()
25
+
26
+ export const parseShortcut = (shortcut: string): SearchButtonShortcut[] =>
27
+ shortcut
28
+ .split(',')
29
+ .map((value) => value.trim())
30
+ .filter(Boolean)
31
+ .map((value) => {
32
+ const keys = value.split('+').map((part) => normalizeKey(part.trim()))
33
+ const modifiers = {
34
+ alt: false,
35
+ ctrl: false,
36
+ meta: false,
37
+ shift: false,
38
+ }
39
+
40
+ let key = ''
41
+
42
+ for (const part of keys) {
43
+ if (MODIFIER_KEYS.has(part)) {
44
+ modifiers[part as keyof typeof modifiers] = true
45
+ continue
46
+ }
47
+
48
+ key = part
49
+ }
50
+
51
+ return {
52
+ key,
53
+ modifiers,
54
+ shortcut: value,
55
+ }
56
+ })
57
+
58
+ const getPlatform = () => {
59
+ if (typeof window === 'undefined') {
60
+ return ''
61
+ }
62
+
63
+ const navigator = window.navigator as Navigator & {
64
+ userAgentData?: {
65
+ platform?: string
66
+ }
67
+ }
68
+
69
+ return navigator.userAgentData?.platform || navigator.platform || navigator.userAgent || ''
70
+ }
71
+
72
+ export const isMacOS = () => /Mac|iPhone|iPad|iPod|macOS|Macintosh/.test(getPlatform())
73
+
74
+ export const getPreferredShortcut = (shortcuts: SearchButtonShortcut[]) =>
75
+ shortcuts.find((shortcut) => (isMacOS() ? shortcut.modifiers.meta : shortcut.modifiers.ctrl)) ||
76
+ shortcuts[0] ||
77
+ null
78
+
79
+ export const getKeyLabel = (key: string) =>
80
+ KEY_LABELS[key] ||
81
+ (key.length === 1 ? key.toUpperCase() : `${key.charAt(0).toUpperCase()}${key.slice(1)}`)
82
+
83
+ export const formatShortcutTokens = (shortcut: string) =>
84
+ shortcut
85
+ .split('+')
86
+ .map((part) => normalizeKey(part.trim()))
87
+ .map((part) => getKeyLabel(part))
88
+ .filter(Boolean)
89
+
90
+ export const getPressedKeys = (event: KeyboardEvent) => {
91
+ const pressedKeys = new Set<string>()
92
+
93
+ if (event.altKey) {
94
+ pressedKeys.add(KEY_LABELS.alt)
95
+ }
96
+
97
+ if (event.ctrlKey) {
98
+ pressedKeys.add(KEY_LABELS.ctrl)
99
+ }
100
+
101
+ if (event.metaKey) {
102
+ pressedKeys.add(KEY_LABELS.meta)
103
+ }
104
+
105
+ if (event.shiftKey) {
106
+ pressedKeys.add(KEY_LABELS.shift)
107
+ }
108
+
109
+ const normalizedKey = normalizeKey(event.key)
110
+
111
+ if (!MODIFIER_KEYS.has(normalizedKey) && event.type === 'keydown') {
112
+ pressedKeys.add(getKeyLabel(normalizedKey))
113
+ }
114
+
115
+ return pressedKeys
116
+ }
117
+
118
+ export const isEditableTarget = (target: EventTarget | null) => {
119
+ if (!(target instanceof Element)) {
120
+ return false
121
+ }
122
+
123
+ return target.matches(EDITABLE_TARGET_SELECTOR) || !!target.closest(EDITABLE_TARGET_SELECTOR)
124
+ }
125
+
126
+ export const shouldIgnoreShortcut = (event: KeyboardEvent) =>
127
+ isEditableTarget(event.target) && !event.ctrlKey && !event.metaKey
128
+
129
+ export const matchesShortcut = (shortcut: SearchButtonShortcut, event: KeyboardEvent) => {
130
+ if (!shortcut.key || normalizeKey(event.key) !== shortcut.key) {
131
+ return false
132
+ }
133
+
134
+ return (
135
+ shortcut.modifiers.alt === event.altKey &&
136
+ shortcut.modifiers.ctrl === event.ctrlKey &&
137
+ shortcut.modifiers.meta === event.metaKey &&
138
+ shortcut.modifiers.shift === event.shiftKey
139
+ )
140
+ }
@@ -28,6 +28,18 @@ export interface CSidebarNavProps extends HTMLAttributes<HTMLUListElement> {
28
28
  * A string of all className you want applied to the component.
29
29
  */
30
30
  className?: string
31
+ /**
32
+ * Make navigation more compact by cutting link padding in half.
33
+ *
34
+ * @since 5.11.0
35
+ */
36
+ compact?: boolean
37
+ /**
38
+ * Sets the navigation variant.
39
+ *
40
+ * @since 5.11.0
41
+ */
42
+ variant?: 'tree'
31
43
  }
32
44
 
33
45
  const isNavElement = (
@@ -69,7 +81,7 @@ const recursiveClone = (children: ReactNode, id?: string, updateId?: boolean): R
69
81
  export const CSidebarNav: PolymorphicRefForwardingComponent<'ul', CSidebarNavProps> = forwardRef<
70
82
  HTMLUListElement,
71
83
  CSidebarNavProps
72
- >(({ children, as: Component = 'ul', className, ...rest }, ref) => {
84
+ >(({ children, as: Component = 'ul', className, compact, variant, ...rest }, ref) => {
73
85
  const [visibleGroup, setVisibleGroup] = useState('')
74
86
  const CNavContextValues = {
75
87
  visibleGroup,
@@ -78,7 +90,18 @@ export const CSidebarNav: PolymorphicRefForwardingComponent<'ul', CSidebarNavPro
78
90
 
79
91
  return (
80
92
  <CSidebarNavContext.Provider value={CNavContextValues}>
81
- <Component className={classNames('sidebar-nav', className)} ref={ref} {...rest}>
93
+ <Component
94
+ className={classNames(
95
+ 'sidebar-nav',
96
+ {
97
+ compact,
98
+ 'sidebar-nav-tree': variant === 'tree',
99
+ },
100
+ className
101
+ )}
102
+ ref={ref}
103
+ {...rest}
104
+ >
82
105
  {recursiveClone(children)}
83
106
  </Component>
84
107
  </CSidebarNavContext.Provider>
@@ -89,6 +112,8 @@ CSidebarNav.propTypes = {
89
112
  as: PropTypes.elementType,
90
113
  children: PropTypes.node,
91
114
  className: PropTypes.string,
115
+ compact: PropTypes.bool,
116
+ variant: PropTypes.oneOf(['tree']),
92
117
  }
93
118
 
94
119
  CSidebarNav.displayName = 'CSidebarNav'
@@ -188,13 +188,24 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
188
188
  ...(typeof popperConfig === 'function' ? popperConfig(defaultPopperConfig) : popperConfig),
189
189
  }
190
190
 
191
+ const handleShow = () => {
192
+ setMounted(true)
193
+ onShow?.()
194
+ }
195
+
196
+ const handleHide = () => {
197
+ setTimeout(() => {
198
+ setVisible(false)
199
+ onHide?.()
200
+ }, _delay.hide)
201
+ }
202
+
191
203
  useEffect(() => {
192
- if (visible) {
204
+ if (visible === true) {
193
205
  handleShow()
194
- return
206
+ } else if (visible === false) {
207
+ handleHide()
195
208
  }
196
-
197
- handleHide()
198
209
  }, [visible])
199
210
 
200
211
  useEffect(() => {
@@ -220,22 +231,6 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
220
231
  }
221
232
  }, [_visible])
222
233
 
223
- const handleShow = () => {
224
- setMounted(true)
225
- if (onShow) {
226
- onShow()
227
- }
228
- }
229
-
230
- const handleHide = () => {
231
- setTimeout(() => {
232
- setVisible(false)
233
- if (onHide) {
234
- onHide()
235
- }
236
- }, _delay.hide)
237
- }
238
-
239
234
  useEffect(() => {
240
235
  updatePopper()
241
236
  }, [content])
@@ -66,6 +66,9 @@ test('CTooltip onShow and onHide', async () => {
66
66
 
67
67
  act(() => {
68
68
  fireEvent.click(btn)
69
+ })
70
+
71
+ act(() => {
69
72
  jest.runAllTimers()
70
73
  })
71
74
 
@@ -74,6 +77,9 @@ test('CTooltip onShow and onHide', async () => {
74
77
 
75
78
  act(() => {
76
79
  fireEvent.click(btn)
80
+ })
81
+
82
+ act(() => {
77
83
  jest.runAllTimers()
78
84
  })
79
85