carbon-react 128.4.1 → 130.0.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/esm/components/flat-table/sort/sort.component.d.ts +7 -5
- package/esm/components/flat-table/sort/sort.component.js +8 -4
- package/esm/components/link/link.style.js +17 -17
- package/esm/components/menu/__internal__/submenu/submenu.style.js +23 -14
- package/esm/components/menu/menu-full-screen/menu-full-screen.component.js +0 -17
- package/esm/components/menu/menu-full-screen/menu-full-screen.style.js +12 -26
- package/esm/components/menu/menu-item/menu-item.component.js +7 -7
- package/esm/components/menu/menu-item/menu-item.style.js +9 -7
- package/esm/components/menu/menu.style.js +4 -1
- package/esm/components/search/index.d.ts +1 -1
- package/esm/components/search/search-button.style.js +8 -3
- package/esm/components/search/search.component.d.ts +10 -7
- package/esm/components/search/search.component.js +35 -42
- package/esm/components/search/search.style.d.ts +0 -1
- package/esm/components/search/search.style.js +64 -52
- package/esm/locales/__internal__/es-es.js +6 -0
- package/esm/locales/en-gb.js +6 -0
- package/esm/locales/locale.d.ts +10 -4
- package/lib/components/flat-table/sort/sort.component.d.ts +7 -5
- package/lib/components/flat-table/sort/sort.component.js +8 -4
- package/lib/components/link/link.style.js +17 -17
- package/lib/components/menu/__internal__/submenu/submenu.style.js +23 -14
- package/lib/components/menu/menu-full-screen/menu-full-screen.component.js +0 -17
- package/lib/components/menu/menu-full-screen/menu-full-screen.style.js +12 -26
- package/lib/components/menu/menu-item/menu-item.component.js +7 -7
- package/lib/components/menu/menu-item/menu-item.style.js +9 -7
- package/lib/components/menu/menu.style.js +4 -1
- package/lib/components/search/index.d.ts +1 -1
- package/lib/components/search/search-button.style.js +8 -3
- package/lib/components/search/search.component.d.ts +10 -7
- package/lib/components/search/search.component.js +34 -41
- package/lib/components/search/search.style.d.ts +0 -1
- package/lib/components/search/search.style.js +64 -52
- package/lib/locales/__internal__/es-es.js +6 -0
- package/lib/locales/en-gb.js +6 -0
- package/lib/locales/locale.d.ts +10 -4
- package/package.json +1 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
export interface SortProps {
|
|
3
3
|
/** if `asc` it will show `sort_up` icon, if `desc` it will show `sort_down` */
|
|
4
|
-
sortType?: "ascending" | "descending"
|
|
5
|
-
/** Callback fired when the
|
|
4
|
+
sortType?: "ascending" | "descending";
|
|
5
|
+
/** Callback fired when the component is clicked */
|
|
6
6
|
onClick?: () => void;
|
|
7
|
-
/** Sets the content of
|
|
8
|
-
children?:
|
|
7
|
+
/** Sets the text content of the component */
|
|
8
|
+
children?: string;
|
|
9
|
+
/** Sets the accessible name of the component */
|
|
10
|
+
accessibleName?: string;
|
|
9
11
|
}
|
|
10
|
-
export declare const Sort: ({ children, onClick, sortType }: SortProps) => React.JSX.Element;
|
|
12
|
+
export declare const Sort: ({ children, onClick, sortType, accessibleName, }: SortProps) => React.JSX.Element;
|
|
11
13
|
export default Sort;
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import React, { useRef, useContext } from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
import Event from "../../../__internal__/utils/helpers/events";
|
|
4
|
+
import Typography from "../../typography";
|
|
4
5
|
import { StyledSort, StyledSpaceHolder, StyledSortIcon } from "./sort.style";
|
|
5
6
|
import guid from "../../../__internal__/utils/helpers/guid";
|
|
7
|
+
import useLocale from "../../../hooks/__internal__/useLocale";
|
|
6
8
|
import { FlatTableThemeContext } from "../flat-table.component";
|
|
7
9
|
export const Sort = ({
|
|
8
10
|
children,
|
|
9
11
|
onClick,
|
|
10
|
-
sortType
|
|
12
|
+
sortType,
|
|
13
|
+
accessibleName
|
|
11
14
|
}) => {
|
|
12
15
|
const id = useRef(guid());
|
|
16
|
+
const locale = useLocale();
|
|
13
17
|
const onKeyDown = e => {
|
|
14
18
|
if (Event.isEnterOrSpaceKey(e)) {
|
|
15
19
|
e.preventDefault();
|
|
@@ -20,10 +24,10 @@ export const Sort = ({
|
|
|
20
24
|
const {
|
|
21
25
|
colorTheme
|
|
22
26
|
} = useContext(FlatTableThemeContext);
|
|
23
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(
|
|
24
|
-
|
|
27
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Typography, {
|
|
28
|
+
screenReaderOnly: true,
|
|
25
29
|
id: id.current
|
|
26
|
-
},
|
|
30
|
+
}, accessibleName || locale.sort.accessibleName(children, sortType)), /*#__PURE__*/React.createElement(StyledSort, {
|
|
27
31
|
role: "button",
|
|
28
32
|
onKeyDown: onKeyDown,
|
|
29
33
|
tabIndex: 0,
|
|
@@ -55,14 +55,14 @@ const StyledLink = styled.span`
|
|
|
55
55
|
${isSkipLink && css`
|
|
56
56
|
a {
|
|
57
57
|
position: absolute;
|
|
58
|
-
padding-left:
|
|
59
|
-
padding-right:
|
|
58
|
+
padding-left: var(--spacing300);
|
|
59
|
+
padding-right: var(--spacing300);
|
|
60
60
|
line-height: 36px;
|
|
61
61
|
left: -999em;
|
|
62
62
|
z-index: ${theme.zIndex.aboveAll};
|
|
63
|
-
box-shadow: inset 0 0 0
|
|
64
|
-
border:
|
|
65
|
-
font-size:
|
|
63
|
+
box-shadow: inset 0 0 0 var(--spacing025) var(--colorsActionMajor500);
|
|
64
|
+
border: var(--spacing025) solid var(--colorsUtilityYang100);
|
|
65
|
+
font-size: var(--fontSizes200);
|
|
66
66
|
color: var(--colorsUtilityYin090);
|
|
67
67
|
|
|
68
68
|
&:hover {
|
|
@@ -80,15 +80,15 @@ const StyledLink = styled.span`
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
a:focus {
|
|
83
|
-
top:
|
|
84
|
-
left:
|
|
83
|
+
top: var(--spacing100);
|
|
84
|
+
left: var(--spacing100);
|
|
85
85
|
}
|
|
86
86
|
`}
|
|
87
87
|
|
|
88
88
|
${!isSkipLink && css`
|
|
89
|
-
a,
|
|
90
|
-
button {
|
|
91
|
-
font-size:
|
|
89
|
+
> a,
|
|
90
|
+
> button {
|
|
91
|
+
font-size: var(--fontSizes100);
|
|
92
92
|
|
|
93
93
|
${!disabled && css`
|
|
94
94
|
color: ${color};
|
|
@@ -99,7 +99,7 @@ const StyledLink = styled.span`
|
|
|
99
99
|
&:hover {
|
|
100
100
|
color: ${hoverColor};
|
|
101
101
|
|
|
102
|
-
${StyledIcon} {
|
|
102
|
+
> ${StyledIcon} {
|
|
103
103
|
color: ${hoverColor};
|
|
104
104
|
}
|
|
105
105
|
}
|
|
@@ -120,8 +120,8 @@ const StyledLink = styled.span`
|
|
|
120
120
|
}
|
|
121
121
|
`}
|
|
122
122
|
|
|
123
|
-
a,
|
|
124
|
-
button {
|
|
123
|
+
> a,
|
|
124
|
+
> button {
|
|
125
125
|
text-decoration: ${hasContent ? "underline" : "none"};
|
|
126
126
|
${isMenuItem && "display: inline-block;"}
|
|
127
127
|
|
|
@@ -160,20 +160,20 @@ const StyledLink = styled.span`
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
${!isSkipLink && !disabled && !theme.focusRedesignOptOut && hasFocus && css`
|
|
163
|
-
a,
|
|
164
|
-
button {
|
|
163
|
+
> a,
|
|
164
|
+
> button {
|
|
165
165
|
outline: none;
|
|
166
166
|
text-decoration: none;
|
|
167
167
|
border-bottom-left-radius: var(--borderRadius000);
|
|
168
168
|
border-bottom-right-radius: var(--borderRadius000);
|
|
169
169
|
}
|
|
170
170
|
max-width: fit-content;
|
|
171
|
-
box-shadow: 0
|
|
171
|
+
box-shadow: 0 var(--spacing050) 0 0 var(--colorsUtilityYin090);
|
|
172
172
|
border-bottom-left-radius: var(--borderRadius025);
|
|
173
173
|
border-bottom-right-radius: var(--borderRadius025);
|
|
174
174
|
`}
|
|
175
175
|
|
|
176
|
-
button {
|
|
176
|
+
> button {
|
|
177
177
|
background-color: transparent;
|
|
178
178
|
border: none;
|
|
179
179
|
padding: 0;
|
|
@@ -3,7 +3,7 @@ import { baseTheme } from "../../../../style/themes";
|
|
|
3
3
|
import { StyledLink } from "../../../link/link.style";
|
|
4
4
|
import { StyledMenuItem } from "../../menu.style";
|
|
5
5
|
import StyledMenuItemWrapper from "../../menu-item/menu-item.style";
|
|
6
|
-
import
|
|
6
|
+
import StyledIcon from "../../../icon/icon.style";
|
|
7
7
|
import menuConfigVariants from "../../menu.config";
|
|
8
8
|
const StyledSubmenuWrapper = styled.div`
|
|
9
9
|
position: relative;
|
|
@@ -94,17 +94,17 @@ const StyledSubmenu = styled.ul`
|
|
|
94
94
|
${!inFullscreenView && menuType && css`
|
|
95
95
|
background-color: ${menuConfigVariants[menuType].submenuItemBackground};
|
|
96
96
|
|
|
97
|
-
a:focus,
|
|
98
|
-
button:focus {
|
|
97
|
+
> a:focus,
|
|
98
|
+
> button:focus {
|
|
99
99
|
background-color: ${menuConfigVariants[menuType].submenuItemBackground};
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
a:hover,
|
|
103
|
-
button:hover {
|
|
102
|
+
> a:hover,
|
|
103
|
+
> button:hover {
|
|
104
104
|
background-color: transparent;
|
|
105
105
|
color: var(--colorsComponentsMenuYang100);
|
|
106
106
|
|
|
107
|
-
[data-component="icon"] {
|
|
107
|
+
> [data-component="icon"] {
|
|
108
108
|
color: var(--colorsComponentsMenuYang100);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
@@ -114,17 +114,26 @@ const StyledSubmenu = styled.ul`
|
|
|
114
114
|
text-decoration: none;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
${
|
|
118
|
-
|
|
117
|
+
> ${StyledIcon} {
|
|
118
|
+
width: 16px;
|
|
119
|
+
height: 16px;
|
|
120
|
+
margin-right: 5px;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
[data-component="icon"] {
|
|
125
|
+
line-height: 20px;
|
|
126
|
+
|
|
127
|
+
&:before {
|
|
128
|
+
line-height: unset;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
|
-
|
|
126
|
-
:
|
|
127
|
-
|
|
131
|
+
span {
|
|
132
|
+
vertical-align: middle;
|
|
133
|
+
|
|
134
|
+
svg {
|
|
135
|
+
height: 16px;
|
|
136
|
+
width: 16px;
|
|
128
137
|
}
|
|
129
138
|
}
|
|
130
139
|
}
|
|
@@ -34,22 +34,6 @@ export const MenuFullscreen = ({
|
|
|
34
34
|
const isDarkVariant = ["dark", "black"].includes(menuType);
|
|
35
35
|
const transitionDuration = 200;
|
|
36
36
|
const locale = useLocale();
|
|
37
|
-
|
|
38
|
-
// TODO: Remove this temporary event handler as part of FE-6078
|
|
39
|
-
const handleFocusedSearchButton = ev => {
|
|
40
|
-
const search = modalRef.current?.querySelector('[data-component="search"]');
|
|
41
|
-
const searchInput = search?.querySelector("input");
|
|
42
|
-
const searchButton = search?.querySelector("button");
|
|
43
|
-
|
|
44
|
-
// if there is no value in the search input the button disappears when the input blurs
|
|
45
|
-
// this means we need to programmatically set focus to the next menu item
|
|
46
|
-
if (searchButton && searchInput && !searchInput.value && searchInput === document.activeElement) {
|
|
47
|
-
ev.preventDefault();
|
|
48
|
-
const elements = Array.from(modalRef.current?.querySelectorAll("a, input, button"));
|
|
49
|
-
const index = elements.indexOf(searchInput);
|
|
50
|
-
elements[index + 2]?.focus();
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
37
|
const flattenedChildren = React.Children.toArray(children);
|
|
54
38
|
const childArray = React.Children.toArray(flattenedChildren.map((child, index) => {
|
|
55
39
|
if (index < flattenedChildren.length - 1) {
|
|
@@ -88,7 +72,6 @@ export const MenuFullscreen = ({
|
|
|
88
72
|
"data-element": dataElement,
|
|
89
73
|
"data-role": dataRole,
|
|
90
74
|
menuType: menuType,
|
|
91
|
-
onKeyDown: ev => Events.isTabKey(ev) && !Events.isShiftKey(ev) && handleFocusedSearchButton(ev),
|
|
92
75
|
ref: modalRef,
|
|
93
76
|
role: "dialog",
|
|
94
77
|
tabIndex: -1
|
|
@@ -7,6 +7,7 @@ import StyledIcon from "../../icon/icon.style";
|
|
|
7
7
|
import StyledButton from "../../button/button.style";
|
|
8
8
|
import menuConfigVariants from "../menu.config";
|
|
9
9
|
import addFocusStyling from "../../../style/utils/add-focus-styling";
|
|
10
|
+
import { StyledLink } from "../../link/link.style";
|
|
10
11
|
const oldFocusStyling = `
|
|
11
12
|
outline: solid 3px var(--colorsSemanticFocus500);
|
|
12
13
|
box-shadow: none;
|
|
@@ -54,10 +55,16 @@ const StyledMenuModal = styled.div`
|
|
|
54
55
|
width: 100vw;
|
|
55
56
|
outline: none;
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
&& {
|
|
59
|
+
${StyledLink} {
|
|
60
|
+
max-width: 100vw;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
${StyledLink} > a,
|
|
64
|
+
${StyledLink} > button,
|
|
65
|
+
> div {
|
|
66
|
+
font-size: var(--fontSizes200);
|
|
67
|
+
}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
${({
|
|
@@ -67,30 +74,9 @@ const StyledMenuModal = styled.div`
|
|
|
67
74
|
background-color: ${menuConfigVariants[menuType].background};
|
|
68
75
|
|
|
69
76
|
&& {
|
|
70
|
-
${
|
|
71
|
-
${StyledSearch} span > [data-component="icon"] {
|
|
72
|
-
color: var(--colorsUtilityMajor200);
|
|
73
|
-
|
|
74
|
-
&:hover {
|
|
75
|
-
color: var(--colorsUtilityMajor150);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
`}
|
|
79
|
-
|
|
80
|
-
${menuType === "light" && css`
|
|
81
|
-
${StyledSearch} span > [data-component="icon"] {
|
|
82
|
-
color: var(--colorsUtilityMajor200);
|
|
83
|
-
|
|
84
|
-
&:hover {
|
|
85
|
-
color: var(--colorsUtilityMajor400);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
`}
|
|
89
|
-
|
|
90
|
-
${StyledSearch} {
|
|
77
|
+
${StyledSearch} {
|
|
91
78
|
${StyledIcon} {
|
|
92
79
|
display: inline-flex;
|
|
93
|
-
margin-right: 0;
|
|
94
80
|
bottom: auto;
|
|
95
81
|
}
|
|
96
82
|
|
|
@@ -55,8 +55,6 @@ export const MenuItem = ({
|
|
|
55
55
|
const focusFromMenu = focusId === menuItemId.current;
|
|
56
56
|
const focusFromSubmenu = submenuFocusId ? submenuFocusId === menuItemId.current : undefined;
|
|
57
57
|
const inputRef = useRef(null);
|
|
58
|
-
const inputIcon = useRef(null);
|
|
59
|
-
inputIcon.current = ref.current ? ref.current.querySelector("[data-element='input-icon-toggle']") : null;
|
|
60
58
|
inputRef.current = ref.current ? ref.current.querySelector("[data-element='input']") : null;
|
|
61
59
|
const focusRef = inputRef.current ? inputRef : ref;
|
|
62
60
|
useEffect(() => {
|
|
@@ -71,18 +69,19 @@ export const MenuItem = ({
|
|
|
71
69
|
};
|
|
72
70
|
}, [registerItem, unregisterItem]);
|
|
73
71
|
useEffect(() => {
|
|
72
|
+
const inputIcon = ref.current?.querySelector("[data-element='input-icon-toggle']");
|
|
74
73
|
if (!openSubmenuId && focusFromSubmenu === undefined && focusFromMenu) {
|
|
75
74
|
/* istanbul ignore else */
|
|
76
75
|
if (focusRef.current) {
|
|
77
76
|
focusRef.current?.focus();
|
|
78
77
|
}
|
|
79
|
-
} else if (focusFromSubmenu && !(shiftTabPressed && inputIcon
|
|
78
|
+
} else if (focusFromSubmenu && !(shiftTabPressed && inputIcon?.getAttribute("tabindex") === "0")) {
|
|
80
79
|
/* istanbul ignore else */
|
|
81
80
|
if (focusRef.current) {
|
|
82
81
|
focusRef.current?.focus();
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
|
-
}, [openSubmenuId, focusFromMenu, focusFromSubmenu,
|
|
84
|
+
}, [openSubmenuId, focusFromMenu, focusFromSubmenu, shiftTabPressed, focusRef]);
|
|
86
85
|
const updateFocusOnClick = useCallback(() => {
|
|
87
86
|
if (updateSubmenuFocusId) {
|
|
88
87
|
updateSubmenuFocusId(menuItemId.current);
|
|
@@ -95,16 +94,17 @@ export const MenuItem = ({
|
|
|
95
94
|
if (ref.current && Events.isEscKey(event)) {
|
|
96
95
|
ref.current?.focus();
|
|
97
96
|
}
|
|
98
|
-
const
|
|
97
|
+
const inputIcon = ref.current?.querySelector("[data-element='input-icon-toggle']");
|
|
98
|
+
const shouldFocusIcon = inputIcon?.getAttribute("tabindex") === "0" && document.activeElement === inputRef.current && inputRef.current?.value;
|
|
99
99
|
|
|
100
100
|
// let natural tab order move focus if input icon is tabbable or input with button exists
|
|
101
|
-
if (Events.isTabKey(event) && (!Events.isShiftKey(event) && shouldFocusIcon || Events.isShiftKey(event) && document.activeElement === inputIcon
|
|
101
|
+
if (Events.isTabKey(event) && (!Events.isShiftKey(event) && shouldFocusIcon || Events.isShiftKey(event) && document.activeElement === inputIcon)) {
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
if (handleSubmenuKeyDown) {
|
|
105
105
|
handleSubmenuKeyDown(event);
|
|
106
106
|
}
|
|
107
|
-
}, [onKeyDown, handleSubmenuKeyDown
|
|
107
|
+
}, [onKeyDown, handleSubmenuKeyDown]);
|
|
108
108
|
const elementProps = {
|
|
109
109
|
className: href || onClick ? "carbon-menu-item--has-link" : "",
|
|
110
110
|
href,
|
|
@@ -149,9 +149,11 @@ const StyledMenuItemWrapper = styled.a.attrs({
|
|
|
149
149
|
${!hasInput && `color: ${menuConfigVariants[menuType].color};`}
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
${
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
${!inFullscreenView && css`
|
|
153
|
+
a > ${StyledIcon}, button > ${StyledIcon} {
|
|
154
|
+
display: inline-block;
|
|
155
|
+
}
|
|
156
|
+
`}
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
${selected && css`
|
|
@@ -313,10 +315,10 @@ const StyledMenuItemWrapper = styled.a.attrs({
|
|
|
313
315
|
}
|
|
314
316
|
|
|
315
317
|
&& {
|
|
316
|
-
a:focus,
|
|
317
|
-
a:hover,
|
|
318
|
-
button:focus,
|
|
319
|
-
button:hover {
|
|
318
|
+
> a:focus,
|
|
319
|
+
> a:hover,
|
|
320
|
+
> button:focus,
|
|
321
|
+
> button:hover {
|
|
320
322
|
background-color: var(--colorsComponentsMenuAutumnStandard600);
|
|
321
323
|
color: var(--colorsComponentsMenuYang100);
|
|
322
324
|
|
|
@@ -4,6 +4,7 @@ import menuConfigVariants from "./menu.config";
|
|
|
4
4
|
import { StyledVerticalWrapper, StyledDivider } from "../vertical-divider/vertical-divider.style";
|
|
5
5
|
import { StyledLink } from "../link/link.style";
|
|
6
6
|
import { baseTheme } from "../../style/themes";
|
|
7
|
+
import StyledMenuItemWrapper from "./menu-item/menu-item.style";
|
|
7
8
|
const StyledMenuWrapper = styled.ul`
|
|
8
9
|
line-height: 40px;
|
|
9
10
|
list-style: none;
|
|
@@ -66,7 +67,9 @@ const StyledMenuItem = styled.li`
|
|
|
66
67
|
}
|
|
67
68
|
`}
|
|
68
69
|
|
|
69
|
-
${
|
|
70
|
+
${StyledMenuItemWrapper} {
|
|
71
|
+
${padding}
|
|
72
|
+
}
|
|
70
73
|
`;
|
|
71
74
|
StyledMenuItem.defaultProps = {
|
|
72
75
|
theme: baseTheme
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default } from "./search.component";
|
|
2
|
-
export type { SearchProps, SearchEvent } from "./search.component";
|
|
2
|
+
export type { SearchProps, SearchEvent, SearchHandle, } from "./search.component";
|
|
@@ -13,7 +13,7 @@ const StyledSearchButton = styled.div`
|
|
|
13
13
|
border-bottom: none;
|
|
14
14
|
|
|
15
15
|
& ${StyledButton} {
|
|
16
|
-
|
|
16
|
+
color: var(--colorsActionMajorYang100);
|
|
17
17
|
border-color: var(--colorsActionMajorTransparent);
|
|
18
18
|
border-bottom-left-radius: var(--borderRadius000);
|
|
19
19
|
border-top-left-radius: var(--borderRadius000);
|
|
@@ -21,13 +21,18 @@ const StyledSearchButton = styled.div`
|
|
|
21
21
|
border-top-right-radius: var(--borderRadius050);
|
|
22
22
|
|
|
23
23
|
:hover {
|
|
24
|
-
background: var(--colorsActionMajor600);
|
|
25
24
|
border-color: var(--colorsActionMajorTransparent);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
width:
|
|
27
|
+
width: fit-content;
|
|
28
|
+
|
|
29
|
+
${StyledIcon}${StyledIcon} {
|
|
30
|
+
color: var(--colorsActionMajorYang100);
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
margin: 0px 0px;
|
|
30
34
|
padding-bottom: 3px;
|
|
35
|
+
|
|
31
36
|
:focus {
|
|
32
37
|
z-index: ${({
|
|
33
38
|
theme
|
|
@@ -17,8 +17,6 @@ export interface SearchProps extends ValidationProps, MarginProps {
|
|
|
17
17
|
defaultValue?: string;
|
|
18
18
|
/** Prop for `id` */
|
|
19
19
|
id?: string;
|
|
20
|
-
/** A callback to retrieve the input reference */
|
|
21
|
-
inputRef?: React.MutableRefObject<HTMLInputElement | null>;
|
|
22
20
|
/** Prop for `name` */
|
|
23
21
|
name?: string;
|
|
24
22
|
/** Prop for `onBlur` events */
|
|
@@ -35,8 +33,11 @@ export interface SearchProps extends ValidationProps, MarginProps {
|
|
|
35
33
|
onKeyDown?: (ev: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
36
34
|
/** Prop for a placeholder */
|
|
37
35
|
placeholder?: string;
|
|
38
|
-
/**
|
|
39
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Pass a boolean to render a search Button with default text.
|
|
38
|
+
* Pass a string to override the text in the search Button
|
|
39
|
+
* */
|
|
40
|
+
searchButton?: boolean | string;
|
|
40
41
|
/**
|
|
41
42
|
* Prop for specifying an input width length.
|
|
42
43
|
* Leaving the `searchWidth` prop with no value will default the width to '100%'
|
|
@@ -47,8 +48,6 @@ export interface SearchProps extends ValidationProps, MarginProps {
|
|
|
47
48
|
* Leaving the `maxWidth` prop with no value will default the width to '100%'
|
|
48
49
|
*/
|
|
49
50
|
maxWidth?: string;
|
|
50
|
-
/** Prop for active search threshold. This must be a positive number */
|
|
51
|
-
threshold?: number;
|
|
52
51
|
/** Prop for `controlled` use */
|
|
53
52
|
value?: string;
|
|
54
53
|
/** Prop to specify the styling of the search component */
|
|
@@ -58,5 +57,9 @@ export interface SearchProps extends ValidationProps, MarginProps {
|
|
|
58
57
|
/** Overrides the default tooltip position */
|
|
59
58
|
tooltipPosition?: "top" | "bottom" | "left" | "right";
|
|
60
59
|
}
|
|
61
|
-
export declare
|
|
60
|
+
export declare type SearchHandle = {
|
|
61
|
+
/** Programmatically focus on root container of Dialog. */
|
|
62
|
+
focus: () => void;
|
|
63
|
+
} | null;
|
|
64
|
+
export declare const Search: React.ForwardRefExoticComponent<SearchProps & React.RefAttributes<SearchHandle>>;
|
|
62
65
|
export default Search;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
|
-
import React, { useState,
|
|
2
|
+
import React, { useState, useRef, useImperativeHandle } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import invariant from "invariant";
|
|
5
5
|
import { filterStyledSystemMarginProps } from "../../style/utils";
|
|
6
6
|
import tagComponent from "../../__internal__/utils/helpers/tags/tags";
|
|
7
7
|
import StyledSearch from "./search.style";
|
|
8
|
-
import StyledSearchButton
|
|
8
|
+
import StyledSearchButton from "./search-button.style";
|
|
9
9
|
import Icon from "../icon";
|
|
10
10
|
import Textbox from "../textbox";
|
|
11
11
|
import Button from "../button";
|
|
12
12
|
import Logger from "../../__internal__/utils/logger";
|
|
13
|
-
|
|
13
|
+
import useLocale from "../../hooks/__internal__/useLocale";
|
|
14
14
|
let deprecateUncontrolledWarnTriggered = false;
|
|
15
15
|
const Search = /*#__PURE__*/React.forwardRef(({
|
|
16
16
|
defaultValue,
|
|
@@ -22,7 +22,6 @@ const Search = /*#__PURE__*/React.forwardRef(({
|
|
|
22
22
|
value,
|
|
23
23
|
id,
|
|
24
24
|
name,
|
|
25
|
-
threshold = 3,
|
|
26
25
|
searchWidth,
|
|
27
26
|
maxWidth,
|
|
28
27
|
searchButton,
|
|
@@ -30,7 +29,6 @@ const Search = /*#__PURE__*/React.forwardRef(({
|
|
|
30
29
|
placeholder,
|
|
31
30
|
variant = "default",
|
|
32
31
|
"aria-label": ariaLabel = "search",
|
|
33
|
-
inputRef,
|
|
34
32
|
tabIndex,
|
|
35
33
|
error,
|
|
36
34
|
warning,
|
|
@@ -40,33 +38,22 @@ const Search = /*#__PURE__*/React.forwardRef(({
|
|
|
40
38
|
}, ref) => {
|
|
41
39
|
const isControlled = value !== undefined;
|
|
42
40
|
const initialValue = isControlled ? value : defaultValue;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
const locale = useLocale();
|
|
42
|
+
const searchRef = useRef(null);
|
|
43
|
+
const inputRef = useRef(null);
|
|
44
|
+
useImperativeHandle(ref, () => ({
|
|
45
|
+
focus() {
|
|
46
|
+
inputRef.current?.focus();
|
|
47
|
+
}
|
|
48
|
+
}), []);
|
|
47
49
|
if (!deprecateUncontrolledWarnTriggered && !isControlled) {
|
|
48
50
|
deprecateUncontrolledWarnTriggered = true;
|
|
49
51
|
Logger.deprecate("Uncontrolled behaviour in `Search` is deprecated and support will soon be removed. Please make sure all your inputs are controlled.");
|
|
50
52
|
}
|
|
51
53
|
!(typeof initialValue === "string") ? process.env.NODE_ENV !== "production" ? invariant(false, "This component has no initial value") : invariant(false) : void 0;
|
|
52
|
-
!(threshold === undefined || typeof threshold === "number" && threshold > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, "Threshold must be a positive number") : invariant(false) : void 0;
|
|
53
54
|
const [searchValue, setSearchValue] = useState(initialValue);
|
|
54
55
|
const [isFocused, setIsFocused] = useState(false);
|
|
55
|
-
const
|
|
56
|
-
useEffect(() => {
|
|
57
|
-
setSearchIsActive(!isControlled ? searchValue.length >= threshold : value.length >= threshold);
|
|
58
|
-
}, [isControlled, searchValue, threshold, value]);
|
|
59
|
-
const [iconType, iconTabIndex] = useMemo(() => {
|
|
60
|
-
const isSearchValueEmpty = !isControlled ? searchValue.length === 0 : value.length === 0;
|
|
61
|
-
const isFocusedOrActive = isFocused || searchIsActive || inputRef?.current === document.activeElement;
|
|
62
|
-
if (!isSearchValueEmpty) {
|
|
63
|
-
return ["cross", 0];
|
|
64
|
-
}
|
|
65
|
-
if (!isFocusedOrActive || threshold === 0 || !searchButton && isSearchValueEmpty) {
|
|
66
|
-
return ["search", -1];
|
|
67
|
-
}
|
|
68
|
-
return [undefined, -1];
|
|
69
|
-
}, [isControlled, searchValue, value, isFocused, searchIsActive, threshold, searchButton, inputRef]);
|
|
56
|
+
const isSearchValueEmpty = !isControlled ? searchValue.length === 0 : value.length === 0;
|
|
70
57
|
let buttonProps = {};
|
|
71
58
|
const handleChange = event => {
|
|
72
59
|
if (onChange) {
|
|
@@ -110,12 +97,15 @@ const Search = /*#__PURE__*/React.forwardRef(({
|
|
|
110
97
|
}
|
|
111
98
|
});
|
|
112
99
|
}
|
|
100
|
+
inputRef.current?.focus();
|
|
113
101
|
};
|
|
114
102
|
const handleMouseDown = event => {
|
|
115
103
|
event.preventDefault();
|
|
116
104
|
};
|
|
117
105
|
const handleBlur = event => {
|
|
118
106
|
setIsFocused(false);
|
|
107
|
+
|
|
108
|
+
/* istanbul ignore else */
|
|
119
109
|
if (onBlur) {
|
|
120
110
|
onBlur(event);
|
|
121
111
|
}
|
|
@@ -128,14 +118,15 @@ const Search = /*#__PURE__*/React.forwardRef(({
|
|
|
128
118
|
onKeyDown(event);
|
|
129
119
|
}
|
|
130
120
|
};
|
|
131
|
-
const
|
|
121
|
+
const searchButtonText = typeof searchButton === "string" ? searchButton : locale.search.searchButtonText();
|
|
122
|
+
const searchHasValue = !isControlled ? !!searchValue?.length : !!value?.length;
|
|
132
123
|
return /*#__PURE__*/React.createElement(StyledSearch, _extends({
|
|
124
|
+
ref: searchRef,
|
|
133
125
|
isFocused: isFocused,
|
|
134
126
|
searchWidth: searchWidth,
|
|
135
127
|
maxWidth: maxWidth,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
showSearchButton: searchButton,
|
|
128
|
+
searchHasValue: searchHasValue,
|
|
129
|
+
showSearchButton: !!searchButton,
|
|
139
130
|
variant: variant,
|
|
140
131
|
mb: 0
|
|
141
132
|
}, filterStyledSystemMarginProps(rest), tagComponent("search", rest), {
|
|
@@ -144,8 +135,8 @@ const Search = /*#__PURE__*/React.forwardRef(({
|
|
|
144
135
|
}, rest), /*#__PURE__*/React.createElement(Textbox, {
|
|
145
136
|
placeholder: placeholder,
|
|
146
137
|
value: !isControlled ? searchValue : value,
|
|
147
|
-
inputIcon:
|
|
148
|
-
iconTabIndex:
|
|
138
|
+
inputIcon: !isSearchValueEmpty ? "cross" : undefined,
|
|
139
|
+
iconTabIndex: !isSearchValueEmpty ? 0 : -1,
|
|
149
140
|
iconOnClick: handleIconClick,
|
|
150
141
|
iconOnMouseDown: handleMouseDown,
|
|
151
142
|
"aria-label": ariaLabel,
|
|
@@ -153,30 +144,33 @@ const Search = /*#__PURE__*/React.forwardRef(({
|
|
|
153
144
|
onBlur: handleBlur,
|
|
154
145
|
onChange: handleChange,
|
|
155
146
|
onKeyDown: handleKeyDown,
|
|
156
|
-
ref:
|
|
147
|
+
ref: inputRef,
|
|
157
148
|
tabIndex: tabIndex,
|
|
158
149
|
error: error,
|
|
159
150
|
warning: warning,
|
|
160
151
|
info: info,
|
|
152
|
+
leftChildren: !searchButton ? /*#__PURE__*/React.createElement(Icon, {
|
|
153
|
+
type: "search",
|
|
154
|
+
ml: 1
|
|
155
|
+
}) : undefined,
|
|
161
156
|
tooltipPosition: tooltipPosition
|
|
162
|
-
}), searchButton && /*#__PURE__*/React.createElement(StyledSearchButton, null,
|
|
157
|
+
}), searchButton && /*#__PURE__*/React.createElement(StyledSearchButton, null, /*#__PURE__*/React.createElement(Button, _extends({
|
|
163
158
|
"aria-label": searchButtonAriaLabel,
|
|
164
159
|
size: "medium",
|
|
165
|
-
px:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
160
|
+
px: 2,
|
|
161
|
+
buttonType: "primary",
|
|
162
|
+
iconPosition: "before",
|
|
163
|
+
iconType: "search"
|
|
164
|
+
}, buttonProps), searchButtonText)));
|
|
169
165
|
});
|
|
170
166
|
if (process.env.NODE_ENV !== "production") {
|
|
171
167
|
Search.propTypes = {
|
|
172
168
|
"aria-label": PropTypes.string,
|
|
169
|
+
"children": PropTypes.node,
|
|
173
170
|
"defaultValue": PropTypes.string,
|
|
174
171
|
"error": PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
175
172
|
"id": PropTypes.string,
|
|
176
173
|
"info": PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
177
|
-
"inputRef": PropTypes.shape({
|
|
178
|
-
"current": PropTypes.oneOfType([PropTypes.oneOf([null]), PropTypes.object]).isRequired
|
|
179
|
-
}),
|
|
180
174
|
"m": PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.oneOf([null]), PropTypes.number, PropTypes.shape({
|
|
181
175
|
"__@toStringTag": PropTypes.string.isRequired,
|
|
182
176
|
"description": PropTypes.string,
|
|
@@ -339,11 +333,10 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
339
333
|
"onFocus": PropTypes.func,
|
|
340
334
|
"onKeyDown": PropTypes.func,
|
|
341
335
|
"placeholder": PropTypes.string,
|
|
342
|
-
"searchButton": PropTypes.bool,
|
|
336
|
+
"searchButton": PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
343
337
|
"searchButtonAriaLabel": PropTypes.string,
|
|
344
338
|
"searchWidth": PropTypes.string,
|
|
345
339
|
"tabIndex": PropTypes.number,
|
|
346
|
-
"threshold": PropTypes.number,
|
|
347
340
|
"tooltipPosition": PropTypes.oneOf(["bottom", "left", "right", "top"]),
|
|
348
341
|
"value": PropTypes.string,
|
|
349
342
|
"variant": PropTypes.oneOf(["dark", "default"]),
|