@coreui/react 5.10.0 → 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 (67) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/dropdown/CDropdown.js +1 -1
  3. package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
  4. package/dist/cjs/components/index.d.ts +1 -0
  5. package/dist/cjs/components/nav/CNavGroup.d.ts +3 -1
  6. package/dist/cjs/components/nav/CNavGroup.js +9 -5
  7. package/dist/cjs/components/nav/CNavGroup.js.map +1 -1
  8. package/dist/cjs/components/popover/CPopover.js +14 -17
  9. package/dist/cjs/components/popover/CPopover.js.map +1 -1
  10. package/dist/cjs/components/search-button/CSearchButton.d.ts +32 -0
  11. package/dist/cjs/components/search-button/CSearchButton.js +77 -0
  12. package/dist/cjs/components/search-button/CSearchButton.js.map +1 -0
  13. package/dist/cjs/components/search-button/index.d.ts +2 -0
  14. package/dist/cjs/components/search-button/types.d.ts +10 -0
  15. package/dist/cjs/components/search-button/utils.d.ts +11 -0
  16. package/dist/cjs/components/search-button/utils.js +115 -0
  17. package/dist/cjs/components/search-button/utils.js.map +1 -0
  18. package/dist/cjs/components/sidebar/CSidebarNav.d.ts +12 -0
  19. package/dist/cjs/components/sidebar/CSidebarNav.js +7 -2
  20. package/dist/cjs/components/sidebar/CSidebarNav.js.map +1 -1
  21. package/dist/cjs/components/tooltip/CTooltip.js +14 -17
  22. package/dist/cjs/components/tooltip/CTooltip.js.map +1 -1
  23. package/dist/cjs/index.js +2 -0
  24. package/dist/cjs/index.js.map +1 -1
  25. package/dist/esm/components/dropdown/CDropdown.js +1 -1
  26. package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
  27. package/dist/esm/components/index.d.ts +1 -0
  28. package/dist/esm/components/nav/CNavGroup.d.ts +3 -1
  29. package/dist/esm/components/nav/CNavGroup.js +9 -5
  30. package/dist/esm/components/nav/CNavGroup.js.map +1 -1
  31. package/dist/esm/components/popover/CPopover.js +14 -17
  32. package/dist/esm/components/popover/CPopover.js.map +1 -1
  33. package/dist/esm/components/search-button/CSearchButton.d.ts +32 -0
  34. package/dist/esm/components/search-button/CSearchButton.js +75 -0
  35. package/dist/esm/components/search-button/CSearchButton.js.map +1 -0
  36. package/dist/esm/components/search-button/index.d.ts +2 -0
  37. package/dist/esm/components/search-button/types.d.ts +10 -0
  38. package/dist/esm/components/search-button/utils.d.ts +11 -0
  39. package/dist/esm/components/search-button/utils.js +104 -0
  40. package/dist/esm/components/search-button/utils.js.map +1 -0
  41. package/dist/esm/components/sidebar/CSidebarNav.d.ts +12 -0
  42. package/dist/esm/components/sidebar/CSidebarNav.js +7 -2
  43. package/dist/esm/components/sidebar/CSidebarNav.js.map +1 -1
  44. package/dist/esm/components/tooltip/CTooltip.js +14 -17
  45. package/dist/esm/components/tooltip/CTooltip.js.map +1 -1
  46. package/dist/esm/index.js +1 -0
  47. package/dist/esm/index.js.map +1 -1
  48. package/package.json +5 -5
  49. package/src/components/dropdown/CDropdown.tsx +1 -1
  50. package/src/components/dropdown/__tests__/CDropdown.spec.tsx +1 -1
  51. package/src/components/dropdown/__tests__/__snapshots__/CDropdown.spec.tsx.snap +2 -2
  52. package/src/components/dropdown/__tests__/__snapshots__/CDropdownMenu.spec.tsx.snap +1 -1
  53. package/src/components/index.ts +1 -0
  54. package/src/components/nav/CNavGroup.tsx +11 -6
  55. package/src/components/nav/__tests__/CNavGroup.spec.tsx +29 -1
  56. package/src/components/nav/__tests__/__snapshots__/CNavGroup.spec.tsx.snap +1 -1
  57. package/src/components/popover/CPopover.tsx +15 -20
  58. package/src/components/popover/__tests__/CPopover.spec.tsx +10 -4
  59. package/src/components/search-button/CSearchButton.tsx +195 -0
  60. package/src/components/search-button/__tests__/CSearchButton.spec.tsx +95 -0
  61. package/src/components/search-button/__tests__/__snapshots__/CSearchButton.spec.tsx.snap +87 -0
  62. package/src/components/search-button/index.ts +3 -0
  63. package/src/components/search-button/types.ts +10 -0
  64. package/src/components/search-button/utils.ts +140 -0
  65. package/src/components/sidebar/CSidebarNav.tsx +27 -2
  66. package/src/components/tooltip/CTooltip.tsx +15 -20
  67. package/src/components/tooltip/__tests__/CTooltip.spec.tsx +6 -0
@@ -0,0 +1,87 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`CSearchButton customize 1`] = `
4
+ <div>
5
+ <button
6
+ class="search-button bazinga"
7
+ type="button"
8
+ >
9
+ <svg
10
+ aria-hidden="true"
11
+ class="search-button-icon"
12
+ viewBox="0 0 512 512"
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ >
15
+ <path
16
+ d="m479.6 399.716-81.084-81.084-62.368-25.767A175 175 0 0 0 368 192c0-97.047-78.953-176-176-176S16 94.953 16 192s78.953 176 176 176a175.03 175.03 0 0 0 101.619-32.377l25.7 62.2 81.081 81.088a56 56 0 1 0 79.2-79.195M48 192c0-79.4 64.6-144 144-144s144 64.6 144 144-64.6 144-144 144S48 271.4 48 192m408.971 264.284a24.03 24.03 0 0 1-33.942 0l-76.572-76.572-23.894-57.835 57.837 23.894 76.573 76.572a24.03 24.03 0 0 1-.002 33.941"
17
+ fill="currentColor"
18
+ />
19
+ </svg>
20
+ <span
21
+ class="search-button-placeholder"
22
+ >
23
+ Command palette
24
+ </span>
25
+ <span
26
+ aria-hidden="true"
27
+ class="search-button-keys"
28
+ >
29
+ <span
30
+ class="search-button-key"
31
+ data-coreui-search-button-key="⌘"
32
+ >
33
+
34
+ </span>
35
+ <span
36
+ class="search-button-key"
37
+ data-coreui-search-button-key="K"
38
+ >
39
+ K
40
+ </span>
41
+ </span>
42
+ </button>
43
+ </div>
44
+ `;
45
+
46
+ exports[`loads and displays CSearchButton component 1`] = `
47
+ <div>
48
+ <button
49
+ class="search-button"
50
+ type="button"
51
+ >
52
+ <svg
53
+ aria-hidden="true"
54
+ class="search-button-icon"
55
+ viewBox="0 0 512 512"
56
+ xmlns="http://www.w3.org/2000/svg"
57
+ >
58
+ <path
59
+ d="m479.6 399.716-81.084-81.084-62.368-25.767A175 175 0 0 0 368 192c0-97.047-78.953-176-176-176S16 94.953 16 192s78.953 176 176 176a175.03 175.03 0 0 0 101.619-32.377l25.7 62.2 81.081 81.088a56 56 0 1 0 79.2-79.195M48 192c0-79.4 64.6-144 144-144s144 64.6 144 144-64.6 144-144 144S48 271.4 48 192m408.971 264.284a24.03 24.03 0 0 1-33.942 0l-76.572-76.572-23.894-57.835 57.837 23.894 76.573 76.572a24.03 24.03 0 0 1-.002 33.941"
60
+ fill="currentColor"
61
+ />
62
+ </svg>
63
+ <span
64
+ class="search-button-placeholder"
65
+ >
66
+ Search
67
+ </span>
68
+ <span
69
+ aria-hidden="true"
70
+ class="search-button-keys"
71
+ >
72
+ <span
73
+ class="search-button-key"
74
+ data-coreui-search-button-key="⌘"
75
+ >
76
+
77
+ </span>
78
+ <span
79
+ class="search-button-key"
80
+ data-coreui-search-button-key="/"
81
+ >
82
+ /
83
+ </span>
84
+ </span>
85
+ </button>
86
+ </div>
87
+ `;
@@ -0,0 +1,3 @@
1
+ import { CSearchButton } from './CSearchButton'
2
+
3
+ export { CSearchButton }
@@ -0,0 +1,10 @@
1
+ export type SearchButtonShortcut = {
2
+ key: string
3
+ modifiers: {
4
+ alt: boolean
5
+ ctrl: boolean
6
+ meta: boolean
7
+ shift: boolean
8
+ }
9
+ shortcut: string
10
+ }
@@ -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