@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.
- package/README.md +1 -1
- package/dist/cjs/components/dropdown/CDropdown.js +1 -1
- package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/nav/CNavGroup.d.ts +3 -1
- package/dist/cjs/components/nav/CNavGroup.js +9 -5
- package/dist/cjs/components/nav/CNavGroup.js.map +1 -1
- package/dist/cjs/components/popover/CPopover.js +14 -17
- package/dist/cjs/components/popover/CPopover.js.map +1 -1
- package/dist/cjs/components/search-button/CSearchButton.d.ts +32 -0
- package/dist/cjs/components/search-button/CSearchButton.js +77 -0
- package/dist/cjs/components/search-button/CSearchButton.js.map +1 -0
- package/dist/cjs/components/search-button/index.d.ts +2 -0
- package/dist/cjs/components/search-button/types.d.ts +10 -0
- package/dist/cjs/components/search-button/utils.d.ts +11 -0
- package/dist/cjs/components/search-button/utils.js +115 -0
- package/dist/cjs/components/search-button/utils.js.map +1 -0
- package/dist/cjs/components/sidebar/CSidebarNav.d.ts +12 -0
- package/dist/cjs/components/sidebar/CSidebarNav.js +7 -2
- package/dist/cjs/components/sidebar/CSidebarNav.js.map +1 -1
- package/dist/cjs/components/tooltip/CTooltip.js +14 -17
- package/dist/cjs/components/tooltip/CTooltip.js.map +1 -1
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/components/dropdown/CDropdown.js +1 -1
- package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/nav/CNavGroup.d.ts +3 -1
- package/dist/esm/components/nav/CNavGroup.js +9 -5
- package/dist/esm/components/nav/CNavGroup.js.map +1 -1
- package/dist/esm/components/popover/CPopover.js +14 -17
- package/dist/esm/components/popover/CPopover.js.map +1 -1
- package/dist/esm/components/search-button/CSearchButton.d.ts +32 -0
- package/dist/esm/components/search-button/CSearchButton.js +75 -0
- package/dist/esm/components/search-button/CSearchButton.js.map +1 -0
- package/dist/esm/components/search-button/index.d.ts +2 -0
- package/dist/esm/components/search-button/types.d.ts +10 -0
- package/dist/esm/components/search-button/utils.d.ts +11 -0
- package/dist/esm/components/search-button/utils.js +104 -0
- package/dist/esm/components/search-button/utils.js.map +1 -0
- package/dist/esm/components/sidebar/CSidebarNav.d.ts +12 -0
- package/dist/esm/components/sidebar/CSidebarNav.js +7 -2
- package/dist/esm/components/sidebar/CSidebarNav.js.map +1 -1
- package/dist/esm/components/tooltip/CTooltip.js +14 -17
- package/dist/esm/components/tooltip/CTooltip.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +5 -5
- package/src/components/dropdown/CDropdown.tsx +1 -1
- package/src/components/dropdown/__tests__/CDropdown.spec.tsx +1 -1
- package/src/components/dropdown/__tests__/__snapshots__/CDropdown.spec.tsx.snap +2 -2
- package/src/components/dropdown/__tests__/__snapshots__/CDropdownMenu.spec.tsx.snap +1 -1
- package/src/components/index.ts +1 -0
- package/src/components/nav/CNavGroup.tsx +11 -6
- package/src/components/nav/__tests__/CNavGroup.spec.tsx +29 -1
- package/src/components/nav/__tests__/__snapshots__/CNavGroup.spec.tsx.snap +1 -1
- package/src/components/popover/CPopover.tsx +15 -20
- package/src/components/popover/__tests__/CPopover.spec.tsx +10 -4
- package/src/components/search-button/CSearchButton.tsx +195 -0
- package/src/components/search-button/__tests__/CSearchButton.spec.tsx +95 -0
- package/src/components/search-button/__tests__/__snapshots__/CSearchButton.spec.tsx.snap +87 -0
- package/src/components/search-button/index.ts +3 -0
- package/src/components/search-button/types.ts +10 -0
- package/src/components/search-button/utils.ts +140 -0
- package/src/components/sidebar/CSidebarNav.tsx +27 -2
- package/src/components/tooltip/CTooltip.tsx +15 -20
- 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,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
|
|
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
|
-
|
|
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
|
|