@redocly/theme 0.52.0-next.3 → 0.52.0-next.4

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 (37) hide show
  1. package/lib/components/Button/Button.d.ts +1 -0
  2. package/lib/components/Button/Button.js +2 -1
  3. package/lib/components/Dropdown/Dropdown.js +1 -1
  4. package/lib/components/Link/Link.js +2 -2
  5. package/lib/components/Search/FilterFields/SearchFilterFieldTags.js +12 -5
  6. package/lib/components/Search/SearchDialog.js +78 -27
  7. package/lib/components/Search/SearchInput.d.ts +2 -2
  8. package/lib/components/Search/SearchInput.js +4 -4
  9. package/lib/components/Search/SearchItem.d.ts +3 -1
  10. package/lib/components/Search/SearchItem.js +53 -28
  11. package/lib/components/Search/variables.js +0 -1
  12. package/lib/components/Select/Select.js +6 -3
  13. package/lib/components/Select/SelectInput.d.ts +1 -0
  14. package/lib/components/Select/SelectInput.js +13 -2
  15. package/lib/components/Tag/Tag.d.ts +3 -1
  16. package/lib/components/Tag/Tag.js +2 -2
  17. package/lib/components/UserMenu/UserMenu.js +1 -1
  18. package/lib/core/hooks/menu/use-collapse.js +0 -1
  19. package/lib/core/hooks/use-dialog-hotkeys.js +1 -2
  20. package/lib/icons/ReturnKeyIcon/ReturnKeyIcon.d.ts +3 -0
  21. package/lib/icons/ReturnKeyIcon/ReturnKeyIcon.js +18 -0
  22. package/package.json +2 -2
  23. package/src/components/Button/Button.tsx +4 -1
  24. package/src/components/Dropdown/Dropdown.tsx +0 -1
  25. package/src/components/Link/Link.tsx +2 -1
  26. package/src/components/Search/FilterFields/SearchFilterFieldTags.tsx +13 -4
  27. package/src/components/Search/SearchDialog.tsx +126 -52
  28. package/src/components/Search/SearchInput.tsx +10 -3
  29. package/src/components/Search/SearchItem.tsx +89 -55
  30. package/src/components/Search/variables.ts +0 -1
  31. package/src/components/Select/Select.tsx +7 -2
  32. package/src/components/Select/SelectInput.tsx +14 -2
  33. package/src/components/Tag/Tag.tsx +6 -0
  34. package/src/components/UserMenu/UserMenu.tsx +1 -1
  35. package/src/core/hooks/menu/use-collapse.ts +0 -1
  36. package/src/core/hooks/use-dialog-hotkeys.ts +1 -1
  37. package/src/icons/ReturnKeyIcon/ReturnKeyIcon.tsx +13 -0
@@ -15,6 +15,7 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
15
15
  icon?: JSX.Element;
16
16
  iconPosition?: 'left' | 'right';
17
17
  title?: string;
18
+ tabIndex?: number;
18
19
  onClick?: (e?: any) => void;
19
20
  type?: 'button' | 'submit' | 'reset';
20
21
  }
@@ -154,7 +154,8 @@ const StyledButton = styled_components_1.default.button.attrs((props) => ({
154
154
  `}
155
155
  `;
156
156
  const ButtonComponent = (props) => {
157
- const button = (react_1.default.createElement(StyledButton, Object.assign({ "data-component-name": "Button/Button" }, props, { iconOnly: !props.children && props.icon !== null, tabIndex: props.to ? -1 : undefined }),
157
+ const tabIndex = 'tabIndex' in props ? props.tabIndex : props.to ? -1 : undefined;
158
+ const button = (react_1.default.createElement(StyledButton, Object.assign({ "data-component-name": "Button/Button" }, props, { iconOnly: !props.children && props.icon !== null, tabIndex: tabIndex }),
158
159
  props.icon && props.iconPosition !== 'right' && props.icon,
159
160
  props.children,
160
161
  props.icon && props.iconPosition === 'right' && props.icon));
@@ -56,7 +56,7 @@ function Dropdown({ children, className, active, trigger, triggerEvent = 'click'
56
56
  };
57
57
  (0, hooks_1.useOutsideClick)(dropdownRef, handleClose);
58
58
  const triggerChild = react_1.default.Children.only(trigger);
59
- const dropdownTrigger = (0, react_1.cloneElement)(triggerChild, Object.assign(Object.assign(Object.assign(Object.assign({ onClick: triggerEvent === 'click' ? handleToggle : undefined, icon: withArrow ? isOpen ? react_1.default.createElement(ChevronUpIcon_1.ChevronUpIcon, null) : react_1.default.createElement(ChevronDownIcon_1.ChevronDownIcon, null) : undefined }, (withArrow ? { iconPosition: 'right' } : {})), { tabIndex: 0 }), triggerChild.props), { onKeyDown: triggerEvent === 'click' ? handleKeyDown : undefined }));
59
+ const dropdownTrigger = (0, react_1.cloneElement)(triggerChild, Object.assign(Object.assign(Object.assign({ onClick: triggerEvent === 'click' ? handleToggle : undefined, icon: withArrow ? isOpen ? react_1.default.createElement(ChevronUpIcon_1.ChevronUpIcon, null) : react_1.default.createElement(ChevronDownIcon_1.ChevronDownIcon, null) : undefined }, (withArrow ? { iconPosition: 'right' } : {})), triggerChild.props), { onKeyDown: triggerEvent === 'click' ? handleKeyDown : undefined }));
60
60
  return (react_1.default.createElement(DropdownWrapper, Object.assign({ "data-component-name": "Dropdown/Dropdown", "data-testid": "dropdown" }, dataAttributes, { className: className, ref: dropdownRef, onPointerEnter: triggerEvent === 'hover' ? handleOpen : undefined, onPointerLeave: triggerEvent === 'hover' ? handleClose : undefined, onClick: onClick }),
61
61
  dropdownTrigger,
62
62
  react_1.default.createElement(ChildrenWrapper, { placement: placement, alignment: alignment, isOpen: isOpen, onClick: closeOnClick ? handleChildClick : undefined }, children)));
@@ -46,9 +46,9 @@ function Link(props) {
46
46
  return React.createElement(LinkComponent, Object.assign({}, props));
47
47
  }
48
48
  else {
49
- const { active: _, httpVerb: _1, hasActiveSubItem: _2, routeSlug: _3, external: _4 } = props, filteredProps = __rest(props, ["active", "httpVerb", "hasActiveSubItem", "routeSlug", "external"]);
49
+ const { active: _, httpVerb: _1, hasActiveSubItem: _2, routeSlug: _3, external: _4, innerRef } = props, filteredProps = __rest(props, ["active", "httpVerb", "hasActiveSubItem", "routeSlug", "external", "innerRef"]);
50
50
  // We omit "active" property to avoid "Warning: Received `false` for a non-boolean attribute `active`."
51
- return React.createElement(react_router_dom_1.Link, Object.assign({ ref: filteredProps.innerRef }, filteredProps));
51
+ return React.createElement(react_router_dom_1.Link, Object.assign({ ref: innerRef }, filteredProps));
52
52
  }
53
53
  }
54
54
  //# sourceMappingURL=Link.js.map
@@ -11,11 +11,18 @@ function SearchFilterFieldTags({ className, facet, selectedValues, onChange, })
11
11
  return (react_1.default.createElement(FilterTagsWrapper, { "data-component-name": "Search/FilterFields/SearchFilterFieldTags", className: className }, facet.values.map((facetCount, index) => {
12
12
  const { value, count, isCounterVisible } = facetCount;
13
13
  const active = selectedValues.includes(value);
14
- return (react_1.default.createElement(FilterTagWrapper, { key: `${count}-${index}`, color: value, onClick: () => {
15
- const values = active
16
- ? selectedValues.filter((item) => item !== value)
17
- : [...selectedValues, value];
18
- onChange(values);
14
+ const updateSelectedValues = () => {
15
+ const values = active
16
+ ? selectedValues.filter((item) => item !== value)
17
+ : [...selectedValues, value];
18
+ onChange(values);
19
+ };
20
+ return (react_1.default.createElement(FilterTagWrapper, { key: `${count}-${index}`, tabIndex: 0, color: value, onClick: () => {
21
+ updateSelectedValues();
22
+ }, onKeyDown: (e) => {
23
+ if (e.key === 'Enter') {
24
+ updateSelectedValues();
25
+ }
19
26
  }, active: active, borderless: true },
20
27
  value,
21
28
  " ",
@@ -46,6 +46,7 @@ const SpinnerLoader_1 = require("../../components/Loaders/SpinnerLoader");
46
46
  const SearchAiDialog_1 = require("../../components/Search/SearchAiDialog");
47
47
  const SettingsIcon_1 = require("../../icons/SettingsIcon/SettingsIcon");
48
48
  const AiStarsIcon_1 = require("../../icons/AiStarsIcon/AiStarsIcon");
49
+ const ReturnKeyIcon_1 = require("../../icons/ReturnKeyIcon/ReturnKeyIcon");
49
50
  const ChevronLeftIcon_1 = require("../../icons/ChevronLeftIcon/ChevronLeftIcon");
50
51
  const EditIcon_1 = require("../../icons/EditIcon/EditIcon");
51
52
  function SearchDialog({ onClose, className }) {
@@ -59,14 +60,25 @@ function SearchDialog({ onClose, className }) {
59
60
  const { query, setQuery, filter, setFilter, items, isSearchLoading, facets, setLoadMore, advancedSearch, askAi, groupField, } = useSearch(product === null || product === void 0 ? void 0 : product.name, autoSearchDisabled);
60
61
  const { isFilterOpen, onFilterToggle, onFilterChange, onFilterReset, onFacetReset, onQuickFilterReset, } = (0, hooks_1.useSearchFilter)(filter, setFilter);
61
62
  const aiSearch = useAiSearch({ filter });
63
+ const searchInputRef = (0, react_1.useRef)(null);
62
64
  const modalRef = (0, react_1.useRef)(null);
65
+ const aiQueryRef = (0, react_1.useRef)(null);
66
+ const firstSearchResultRef = (0, react_1.useRef)(null);
67
+ const searchKeysWithResults = items ? Object.keys(items).filter((key) => { var _a; return (_a = items[key]) === null || _a === void 0 ? void 0 : _a.length; }) : [];
63
68
  const { translate } = useTranslate();
64
69
  (0, hooks_1.useDialogHotKeys)(modalRef, onClose);
70
+ const focusSearchInput = () => {
71
+ requestAnimationFrame(() => {
72
+ var _a;
73
+ (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
74
+ });
75
+ };
65
76
  (0, react_1.useEffect)(() => {
66
77
  if (mode === 'ai-dialog' && aiSearch.isGeneratingResponse) {
67
78
  setQuery('');
68
79
  }
69
80
  }, [mode, aiSearch.isGeneratingResponse, setQuery]);
81
+ (0, react_1.useEffect)(focusSearchInput, []);
70
82
  const handleOverlayClick = (event) => {
71
83
  var _a;
72
84
  const target = event.target;
@@ -76,7 +88,7 @@ function SearchDialog({ onClose, className }) {
76
88
  onClose();
77
89
  }
78
90
  };
79
- const mapItem = (item, index, results) => {
91
+ const mapItem = (item, index, results, innerRef) => {
80
92
  var _a;
81
93
  let itemProduct;
82
94
  if (!product && item.document.product) {
@@ -86,7 +98,7 @@ function SearchDialog({ onClose, className }) {
86
98
  ? { name: resolvedProduct.name, icon: resolvedProduct.icon }
87
99
  : undefined;
88
100
  }
89
- return (react_1.default.createElement(SearchItem_1.SearchItem, { key: `${index}-${item.document.id}`, item: item, product: itemProduct, onClick: () => {
101
+ return (react_1.default.createElement(SearchItem_1.SearchItem, { key: `${index}-${item.document.id}`, item: item, product: itemProduct, innerRef: innerRef, onClick: () => {
90
102
  otelTelemetry.send('search.result.clicked', {
91
103
  query,
92
104
  url: item.document.url,
@@ -123,12 +135,17 @@ function SearchDialog({ onClose, className }) {
123
135
  product.name,
124
136
  react_1.default.createElement(CloseIcon_1.CloseIcon, { onClick: () => setProduct(undefined), color: "--icon-color-additional" }))),
125
137
  mode === 'search' ? (react_1.default.createElement(react_1.default.Fragment, null,
126
- react_1.default.createElement(SearchInput_1.SearchInput, { value: query, onChange: setQuery, placeholder: translate('search.label', 'Search docs...'), isLoading: isSearchLoading, onSubmit: showAiSearchButton
127
- ? () => {
128
- setMode('ai-dialog');
129
- aiSearch.askQuestion(query);
138
+ react_1.default.createElement(SearchInput_1.SearchInput, { value: query, onChange: setQuery, placeholder: translate('search.label', 'Search docs...'), isLoading: isSearchLoading, inputRef: searchInputRef, onSubmit: () => {
139
+ var _a;
140
+ if (isSearchLoading)
141
+ return;
142
+ if (showAiSearchButton && aiQueryRef.current) {
143
+ aiQueryRef.current.focus();
130
144
  }
131
- : undefined, "data-translation-key": "search.label" }),
145
+ else {
146
+ (_a = firstSearchResultRef.current) === null || _a === void 0 ? void 0 : _a.focus();
147
+ }
148
+ }, "data-translation-key": "search.label" }),
132
149
  showHeaderButtons && (react_1.default.createElement(SearchHeaderButtons, null,
133
150
  showAiSearchButton ? (react_1.default.createElement(SearchAiButton, { icon: react_1.default.createElement(AiStarsIcon_1.AiStarsIcon, { gradient: true }), onClick: () => {
134
151
  setMode('ai-dialog');
@@ -140,9 +157,12 @@ function SearchDialog({ onClose, className }) {
140
157
  react_1.default.createElement(Button_1.Button, { variant: "secondary", onClick: () => {
141
158
  setMode('search');
142
159
  aiSearch.clearConversation();
143
- }, icon: react_1.default.createElement(ChevronLeftIcon_1.ChevronLeftIcon, null) }, translate('search.ai.backToSearch', 'Back to search')),
144
- react_1.default.createElement(Button_1.Button, { variant: "secondary", disabled: !aiSearch.conversation.length, onClick: () => aiSearch.clearConversation(), icon: react_1.default.createElement(EditIcon_1.EditIcon, null) }, translate('search.ai.newConversation', 'New conversation'))))),
160
+ focusSearchInput();
161
+ }, tabIndex: 0, icon: react_1.default.createElement(ChevronLeftIcon_1.ChevronLeftIcon, null) }, translate('search.ai.backToSearch', 'Back to search')),
162
+ react_1.default.createElement(Button_1.Button, { variant: "secondary", disabled: !aiSearch.conversation.length, onClick: () => aiSearch.clearConversation(), tabIndex: 0, icon: react_1.default.createElement(EditIcon_1.EditIcon, null) }, translate('search.ai.newConversation', 'New conversation'))))),
145
163
  react_1.default.createElement(SearchDialogBody, null, mode === 'search' ? (react_1.default.createElement(react_1.default.Fragment, null,
164
+ advancedSearch && isFilterOpen && (react_1.default.createElement(SearchDialogBodyFilterView, null,
165
+ react_1.default.createElement(SearchFilter_1.SearchFilter, { facets: facets, filter: filter, query: query, quickFilterFields: [groupField], onFilterChange: onFilterChange, onFilterReset: onFilterReset, onFacetReset: onFacetReset }))),
146
166
  react_1.default.createElement(SearchDialogBodyMainView, null,
147
167
  react_1.default.createElement(SearchGroups_1.SearchGroups, { facets: facets, searchFilter: filter, onFilterChange: onFilterChange, onQuickFilterReset: onQuickFilterReset, groupField: groupField }),
148
168
  showAiSearchItem && (react_1.default.createElement(SearchWithAI, { onClick: () => {
@@ -150,27 +170,48 @@ function SearchDialog({ onClose, className }) {
150
170
  if (query.trim()) {
151
171
  aiSearch.askQuestion(query);
152
172
  }
153
- }, tabIndex: 0, role: "option", "aria-selected": "true" },
173
+ }, onKeyDown: (e) => {
174
+ if (e.key === 'Enter') {
175
+ setMode('ai-dialog');
176
+ if (query.trim()) {
177
+ aiSearch.askQuestion(query);
178
+ }
179
+ }
180
+ }, ref: aiQueryRef, tabIndex: 0, role: "option", "aria-selected": "true" },
154
181
  react_1.default.createElement(AiStarsIcon_1.AiStarsIcon, { color: "var(--search-ai-icon-color)", size: "36px", background: "var(--search-ai-icon-bg-color)", margin: "0 var(--spacing-md) 0 0", borderRadius: "var(--border-radius-lg)" }),
155
182
  react_1.default.createElement(Typography_1.Typography, { fontWeight: "var(--font-weight-semibold)" }, query),
156
183
  react_1.default.createElement(Typography_1.Typography, null,
157
184
  "- ",
158
185
  translate('search.ai.label', 'Ask AI assistant')),
159
- react_1.default.createElement(ReturnKey, null, "\u23CE"))),
160
- showResults ? (items && Object.keys(items).some((key) => { var _a; return (_a = items[key]) === null || _a === void 0 ? void 0 : _a.length; }) ? (Object.keys(items).map((key) => {
161
- var _a, _b, _c;
162
- return ((_a = items[key]) === null || _a === void 0 ? void 0 : _a.length) ? (react_1.default.createElement(react_1.Fragment, { key: key },
163
- react_1.default.createElement(SearchGroupTitle, { "data-testid": "search-group-title" }, key), (_b = items[key]) === null || _b === void 0 ? void 0 :
164
- _b.map(mapItem),
165
- showLoadMore(key, ((_c = items[key]) === null || _c === void 0 ? void 0 : _c.length) || 0) && (react_1.default.createElement(SearchGroupFooter, { "data-translation-key": "search.showMore", onClick: () => { var _a; return setLoadMore({ groupKey: key, offset: ((_a = items[key]) === null || _a === void 0 ? void 0 : _a.length) || 0 }); } }, translate('search.showMore', 'Show more'))))) : null;
186
+ react_1.default.createElement(ReturnKeyIcon_1.ReturnKeyIcon, { color: "var(--search-item-text-color)" }))),
187
+ showResults ? (searchKeysWithResults.length ? (searchKeysWithResults.map((key, searchGroupKeyIdx) => {
188
+ const searchResultItems = items[key];
189
+ if (searchResultItems === null || searchResultItems === void 0 ? void 0 : searchResultItems.length) {
190
+ return (react_1.default.createElement(react_1.Fragment, { key: key },
191
+ react_1.default.createElement(SearchGroupTitle, { "data-testid": "search-group-title" }, key),
192
+ searchResultItems.map((item, idx, resultsArr) => mapItem(item, idx, resultsArr, searchGroupKeyIdx === 0 ? firstSearchResultRef : undefined)),
193
+ showLoadMore(key, searchResultItems.length || 0) && (react_1.default.createElement(SearchGroupFooter, { tabIndex: 0, "data-translation-key": "search.showMore", onKeyDown: (e) => {
194
+ if (e.key === 'Enter') {
195
+ setLoadMore({
196
+ groupKey: key,
197
+ offset: searchResultItems.length || 0,
198
+ });
199
+ }
200
+ }, onClick: () => setLoadMore({
201
+ groupKey: key,
202
+ offset: searchResultItems.length || 0,
203
+ }) }, translate('search.showMore', 'Show more')))));
204
+ }
205
+ return null;
166
206
  })) : isSearchLoading ? (react_1.default.createElement(SearchMessage, { "data-translation-key": "search.loading" },
167
207
  react_1.default.createElement(SpinnerLoader_1.SpinnerLoader, { size: "26px", color: "var(--search-input-icon-color)" }),
168
208
  translate('search.loading', 'Loading...'))) : (react_1.default.createElement(SearchMessage, { "data-translation-key": "search.noResults" },
169
209
  react_1.default.createElement("b", null, translate('search.noResults.title', 'No results'))))) : (react_1.default.createElement(react_1.default.Fragment, null,
170
- react_1.default.createElement(SearchRecent_1.SearchRecent, { onSelect: setQuery }),
171
- react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))),
172
- advancedSearch && mode === 'search' && isFilterOpen && (react_1.default.createElement(SearchDialogBodyFilterView, null,
173
- react_1.default.createElement(SearchFilter_1.SearchFilter, { facets: facets, filter: filter, query: query, quickFilterFields: [groupField], onFilterChange: onFilterChange, onFilterReset: onFilterReset, onFacetReset: onFacetReset }))))) : (react_1.default.createElement(SearchAiDialog_1.SearchAiDialog, { initialMessage: query, response: aiSearch.response, isGeneratingResponse: aiSearch.isGeneratingResponse, error: aiSearch.error, resources: aiSearch.resources, conversation: aiSearch.conversation, setConversation: aiSearch.setConversation, onMessageSent: aiSearch.askQuestion }))),
210
+ react_1.default.createElement(SearchRecent_1.SearchRecent, { onSelect: (query) => {
211
+ setQuery(query);
212
+ focusSearchInput();
213
+ } }),
214
+ react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))))) : (react_1.default.createElement(SearchAiDialog_1.SearchAiDialog, { initialMessage: query, response: aiSearch.response, isGeneratingResponse: aiSearch.isGeneratingResponse, error: aiSearch.error, resources: aiSearch.resources, conversation: aiSearch.conversation, setConversation: aiSearch.setConversation, onMessageSent: aiSearch.askQuestion }))),
174
215
  react_1.default.createElement(SearchDialogFooter, null, mode === 'ai-dialog' ? (react_1.default.createElement(AiDisclaimer, null, translate('search.ai.disclaimer', 'AI search might provide incomplete or incorrect results. Verify important information.'))) : (react_1.default.createElement(react_1.default.Fragment, null,
175
216
  react_1.default.createElement(SearchShortcuts, null,
176
217
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "search.keys.navigate", combination: "Tab", text: translate('search.keys.navigate', 'to navigate') }),
@@ -243,7 +284,7 @@ const AiDialogHeaderWrapper = styled_components_1.default.div `
243
284
  `;
244
285
  const SearchDialogBody = styled_components_1.default.div `
245
286
  display: flex;
246
- flex-direction: row;
287
+ flex-direction: row-reverse;
247
288
  flex: 1;
248
289
  min-height: 0;
249
290
  overflow: hidden;
@@ -354,22 +395,32 @@ const SearchWithAI = styled_components_1.default.div `
354
395
  text-decoration: none;
355
396
  white-space: normal;
356
397
  outline: none;
357
- border: none;
398
+ border-top: 1px solid var(--search-item-border-color);
399
+ border-bottom: 1px solid var(--search-item-border-color);
358
400
 
359
401
  transition: all 0.3s ease;
360
402
 
403
+ ${ReturnKeyIcon_1.ReturnKeyIcon} {
404
+ opacity: 0;
405
+ }
406
+
361
407
  &:focus,
362
408
  &:hover {
363
409
  color: var(--search-item-text-color-hover);
364
410
  background-color: var(--search-item-bg-color-hover);
411
+
412
+ ${ReturnKeyIcon_1.ReturnKeyIcon} {
413
+ opacity: 1;
414
+ }
415
+ }
416
+
417
+ &:focus {
418
+ border-top: 1px solid var(--search-item-border-color-focused);
419
+ border-bottom: 1px solid var(--search-item-border-color-focused);
365
420
  }
366
421
 
367
422
  & > :first-child {
368
423
  margin-right: var(--spacing-xs);
369
424
  }
370
425
  `;
371
- const ReturnKey = (0, styled_components_1.default)(Typography_1.Typography) `
372
- color: var(--search-item-text-color);
373
- margin-left: auto;
374
- `;
375
426
  //# sourceMappingURL=SearchDialog.js.map
@@ -7,7 +7,7 @@ export type SearchInputProps = {
7
7
  isLoading: boolean;
8
8
  showReturnButton?: boolean;
9
9
  onReturn?: () => void;
10
- onSubmit?: () => void;
10
+ onSubmit?: (evt: React.KeyboardEvent<HTMLInputElement>) => void;
11
11
  className?: string;
12
12
  };
13
- export declare function SearchInput({ placeholder, value, onChange, isLoading, showReturnButton, onReturn, onSubmit, className, }: SearchInputProps): JSX.Element;
13
+ export declare function SearchInput({ placeholder, value, onChange, isLoading, showReturnButton, inputRef, onReturn, onSubmit, className, }: SearchInputProps): JSX.Element;
@@ -12,7 +12,7 @@ const Button_1 = require("../../components/Button/Button");
12
12
  const hooks_1 = require("../../core/hooks");
13
13
  const CloseFilledIcon_1 = require("../../icons/CloseFilledIcon/CloseFilledIcon");
14
14
  const ChevronLeftIcon_1 = require("../../icons/ChevronLeftIcon/ChevronLeftIcon");
15
- function SearchInput({ placeholder, value, onChange, isLoading, showReturnButton, onReturn, onSubmit, className, }) {
15
+ function SearchInput({ placeholder, value, onChange, isLoading, showReturnButton, inputRef, onReturn, onSubmit, className, }) {
16
16
  const { useTelemetry } = (0, hooks_1.useThemeHooks)();
17
17
  const telemetry = useTelemetry();
18
18
  const stopPropagation = (event) => event.stopPropagation();
@@ -28,13 +28,13 @@ function SearchInput({ placeholder, value, onChange, isLoading, showReturnButton
28
28
  return;
29
29
  }
30
30
  if (e.key === 'Enter') {
31
- onSubmit();
31
+ onSubmit(e);
32
32
  }
33
33
  };
34
34
  return (react_1.default.createElement(SearchInputWrapper, { "data-component-name": "Search/SearchInput", className: className },
35
35
  showReturnButton ? (react_1.default.createElement(Button_1.Button, { icon: react_1.default.createElement(ChevronLeftIcon_1.ChevronLeftIcon, null), onClick: onReturn })) : value && isLoading ? (react_1.default.createElement(Spinner_1.Spinner, { size: "24px", color: "--search-input-icon-color" })) : (react_1.default.createElement(SearchIcon_1.SearchIcon, { size: "24px", color: "--search-input-icon-color" })),
36
- react_1.default.createElement(SearchInputField, { value: value, placeholder: placeholder, onChange: handleOnChange, onClick: stopPropagation, onKeyUp: handleOnKeyUp }),
37
- !!value && (react_1.default.createElement(ResetButton, { variant: "ghost", onClick: handleOnReset, icon: react_1.default.createElement(CloseFilledIcon_1.CloseFilledIcon, null) }))));
36
+ react_1.default.createElement(SearchInputField, { value: value, ref: inputRef, placeholder: placeholder, onChange: handleOnChange, onClick: stopPropagation, onKeyUp: handleOnKeyUp }),
37
+ !!value && (react_1.default.createElement(ResetButton, { variant: "ghost", onClick: handleOnReset, icon: react_1.default.createElement(CloseFilledIcon_1.CloseFilledIcon, null), tabIndex: -1 }))));
38
38
  }
39
39
  const SearchInputWrapper = styled_components_1.default.div `
40
40
  display: flex;
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import type { SearchItemData } from '../../core/types';
2
3
  type ActiveItem<T> = T & {
3
4
  active?: boolean;
@@ -10,6 +11,7 @@ export type SearchItemProps = {
10
11
  icon?: string;
11
12
  };
12
13
  className?: string;
14
+ innerRef?: React.ForwardedRef<HTMLAnchorElement>;
13
15
  };
14
- export declare function SearchItem({ onClick, item, className, product }: SearchItemProps): JSX.Element;
16
+ export declare function SearchItem({ onClick, item, className, product, innerRef, }: SearchItemProps): JSX.Element;
15
17
  export {};
@@ -35,7 +35,8 @@ const Image_1 = require("../../components/Image/Image");
35
35
  const SearchHighlight_1 = require("../../components/Search/SearchHighlight");
36
36
  const Badge_1 = require("../../components/Badge/Badge");
37
37
  const utils_1 = require("../../core/utils");
38
- function SearchItem({ onClick, item, className, product }) {
38
+ const ReturnKeyIcon_1 = require("../../icons/ReturnKeyIcon/ReturnKeyIcon");
39
+ function SearchItem({ onClick, item, className, product, innerRef, }) {
39
40
  var _a, _b, _c, _d;
40
41
  const ref = (0, react_1.useRef)();
41
42
  (0, react_1.useEffect)(() => {
@@ -47,33 +48,45 @@ function SearchItem({ onClick, item, className, product }) {
47
48
  const { document, highlight } = item;
48
49
  const parameter = highlight.parameters && highlight.parameters.length ? highlight.parameters[0] : null;
49
50
  const shouldShowPath = document.path && ((_a = document.path) === null || _a === void 0 ? void 0 : _a.length) > 1;
50
- return (react_1.default.createElement(SearchItemWrapper, { className: className, to: document.url, onClick: onClick, tabIndex: 0, innerRef: ref, "data-component-name": "Search/SearchItem" },
51
- react_1.default.createElement(SearchItemHeader, null,
52
- product && (react_1.default.createElement(SearchItemProductTag, { "data-testid": "search-item-product-tag" },
53
- react_1.default.createElement(Image_1.Image, { src: product.icon }),
54
- product.name)),
55
- document.httpMethod ? (react_1.default.createElement(SearchItemOperation, null,
56
- react_1.default.createElement(SearchItemOperationTag, { color: document.httpMethod }, document.httpMethod.toUpperCase()),
57
- highlight.httpPath ? (0, SearchHighlight_1.searchHighlight)(highlight.httpPath) : document.httpPath)) : null,
58
- react_1.default.createElement(SearchItemTitleWrapper, null,
59
- react_1.default.createElement(SearchItemTitle, null, highlight.title ? (0, SearchHighlight_1.searchHighlight)(highlight.title) : document.title),
60
- document.deprecated ? react_1.default.createElement(SearchItemBadge, { deprecated: true }, "Deprecated") : null,
61
- document.badges
62
- ? document.badges.map(({ name, color }) => (react_1.default.createElement(SearchItemBadge, { color: color || 'var(--color-info-base)', key: name }, name)))
63
- : null),
64
- react_1.default.createElement(SearchItemDescription, null, highlight.text ? (0, SearchHighlight_1.searchHighlight)(highlight.text) : (0, utils_1.trimText)(document.text))),
65
- parameter ? (react_1.default.createElement(SearchItemPlace, null,
66
- react_1.default.createElement("div", null,
67
- (0, SearchHighlight_1.searchHighlight)(parameter.place),
68
- ` `,
69
- ((_b = parameter.path) === null || _b === void 0 ? void 0 : _b.length) ? (0, SearchHighlight_1.searchHighlight)((_c = parameter.path) === null || _c === void 0 ? void 0 : _c.join(' → ')) + ' → ' : '',
70
- (0, SearchHighlight_1.searchHighlight)(parameter.name)),
71
- react_1.default.createElement("div", null, (0, SearchHighlight_1.searchHighlight)(parameter.description)))) : (shouldShowPath && (react_1.default.createElement(SearchItemPath, null, highlight.path && highlight.path.length
72
- ? (0, SearchHighlight_1.searchHighlight)(highlight.path.join(' → '))
73
- : (_d = document.path) === null || _d === void 0 ? void 0 : _d.join(' '))))));
51
+ return (react_1.default.createElement(SearchItemWrapper, { className: className, to: document.url, onClick: onClick, tabIndex: 0, innerRef: (el) => {
52
+ ref.current = el;
53
+ if (!innerRef)
54
+ return;
55
+ if (typeof innerRef === 'function') {
56
+ innerRef(el);
57
+ }
58
+ else {
59
+ innerRef.current = el;
60
+ }
61
+ }, "data-component-name": "Search/SearchItem" },
62
+ react_1.default.createElement(SearchItemContent, null,
63
+ react_1.default.createElement(SearchItemHeader, null,
64
+ product && (react_1.default.createElement(SearchItemProductTag, { "data-testid": "search-item-product-tag" },
65
+ react_1.default.createElement(Image_1.Image, { src: product.icon }),
66
+ product.name)),
67
+ document.httpMethod ? (react_1.default.createElement(SearchItemOperation, null,
68
+ react_1.default.createElement(SearchItemOperationTag, { color: document.httpMethod }, document.httpMethod.toUpperCase()),
69
+ highlight.httpPath ? (0, SearchHighlight_1.searchHighlight)(highlight.httpPath) : document.httpPath)) : null,
70
+ react_1.default.createElement(SearchItemTitleWrapper, null,
71
+ react_1.default.createElement(SearchItemTitle, null, highlight.title ? (0, SearchHighlight_1.searchHighlight)(highlight.title) : document.title),
72
+ document.deprecated ? react_1.default.createElement(SearchItemBadge, { deprecated: true }, "Deprecated") : null,
73
+ document.badges
74
+ ? document.badges.map(({ name, color }) => (react_1.default.createElement(SearchItemBadge, { color: color || 'var(--color-info-base)', key: name }, name)))
75
+ : null),
76
+ react_1.default.createElement(SearchItemDescription, null, highlight.text ? (0, SearchHighlight_1.searchHighlight)(highlight.text) : (0, utils_1.trimText)(document.text))),
77
+ parameter ? (react_1.default.createElement(SearchItemPlace, null,
78
+ react_1.default.createElement("div", null,
79
+ (0, SearchHighlight_1.searchHighlight)(parameter.place),
80
+ ` → `,
81
+ ((_b = parameter.path) === null || _b === void 0 ? void 0 : _b.length) ? (0, SearchHighlight_1.searchHighlight)((_c = parameter.path) === null || _c === void 0 ? void 0 : _c.join(' → ')) + ' → ' : '',
82
+ (0, SearchHighlight_1.searchHighlight)(parameter.name)),
83
+ react_1.default.createElement("div", null, (0, SearchHighlight_1.searchHighlight)(parameter.description)))) : (shouldShowPath && (react_1.default.createElement(SearchItemPath, null, highlight.path && highlight.path.length
84
+ ? (0, SearchHighlight_1.searchHighlight)(highlight.path.join(' → '))
85
+ : (_d = document.path) === null || _d === void 0 ? void 0 : _d.join(' → '))))),
86
+ react_1.default.createElement(ReturnKeyIcon_1.ReturnKeyIcon, { color: "var(--search-item-text-color)" })));
74
87
  }
75
88
  const SearchItemWrapper = (0, styled_components_1.default)(Link_1.Link) `
76
- display: block;
89
+ display: flex;
77
90
  padding: var(--search-item-padding);
78
91
  color: var(--search-item-text-color);
79
92
  background-color: var(--search-item-bg-color);
@@ -84,17 +97,29 @@ const SearchItemWrapper = (0, styled_components_1.default)(Link_1.Link) `
84
97
  border-top: 1px solid var(--search-item-border-color);
85
98
  border-bottom: 1px solid var(--search-item-border-color);
86
99
 
87
- &:hover {
100
+ ${ReturnKeyIcon_1.ReturnKeyIcon} {
101
+ align-self: center;
102
+ opacity: 0;
103
+ }
104
+
105
+ &:hover,
106
+ &:focus {
88
107
  color: var(--search-item-text-color-hover);
89
108
  background-color: var(--search-item-bg-color-hover);
109
+
110
+ ${ReturnKeyIcon_1.ReturnKeyIcon} {
111
+ opacity: 1;
112
+ }
90
113
  }
91
114
 
92
115
  &:focus {
93
- background-color: var(--search-item-bg-color-active);
94
116
  border-top: 1px solid var(--search-item-border-color-focused);
95
117
  border-bottom: 1px solid var(--search-item-border-color-focused);
96
118
  }
97
119
  `;
120
+ const SearchItemContent = styled_components_1.default.section `
121
+ flex: 1 1 auto;
122
+ `;
98
123
  const SearchItemHeader = styled_components_1.default.div `
99
124
  position: relative;
100
125
  `;
@@ -52,7 +52,6 @@ exports.search = (0, styled_components_1.css) `
52
52
  --search-item-path-text-color: var(--text-color-description); // @presenter Color
53
53
  --search-item-bg-color: transparent; // @presenter Color
54
54
  --search-item-bg-color-hover: var(--layer-color-ontonal-hover); // @presenter Color
55
- --search-item-bg-color-active: var(--layer-color); // @presenter Color
56
55
  --search-item-border-color-focused: var(--color-blue-4); // @presenter Color
57
56
  --search-item-border-color: transparent; // @presenter Color
58
57
  --search-item-padding: var(--spacing-sm) var(--spacing-lg);
@@ -51,6 +51,7 @@ function Select(props) {
51
51
  };
52
52
  const [selectedOptions, setSelectedOptions] = (0, react_1.useState)(getSelectedOptionsFromPropsValue());
53
53
  const selectRef = (0, react_1.useRef)(null);
54
+ const selectInputRef = (0, react_1.useRef)(null);
54
55
  const [searchValue, setSearchValue] = (0, react_1.useState)(null);
55
56
  const [dropdownActive, setDropdownActive] = (0, react_1.useState)(false);
56
57
  const [filteredOptions, setFilteredOptions] = (0, react_1.useState)(options);
@@ -86,6 +87,7 @@ function Select(props) {
86
87
  // eslint-disable-next-line react-hooks/exhaustive-deps
87
88
  }, [searchValue]);
88
89
  const selectHandler = (selectedOption) => {
90
+ var _a;
89
91
  const newSelectedOptions = multiple
90
92
  ? isSelected(selectedOption)
91
93
  ? selectedOptions.filter((option) => option.value !== selectedOption.value)
@@ -105,6 +107,7 @@ function Select(props) {
105
107
  if (!multiple) {
106
108
  setStickyInputValue('');
107
109
  }
110
+ (_a = selectInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
108
111
  };
109
112
  const searchHandler = (e) => {
110
113
  const targetValue = e.target.value;
@@ -147,11 +150,11 @@ function Select(props) {
147
150
  const isSelected = (option) => {
148
151
  return !!selectedOptions.find((selectOption) => selectOption.value === option.value || selectOption.value === option.label);
149
152
  };
150
- const renderDefaultInput = () => {
151
- return (react_1.default.createElement(SelectInput_1.SelectInput, { id: inputId, selectedOptions: selectedOptions, searchValue: searchValue, placeholder: placeholder, stickyValue: stickyInputValue, multiple: multiple, searchable: searchable, clearable: clearable, customIcon: icon, onlyIcon: onlyIcon, clearHandler: clearHandler, searchHandler: searchHandler, inputBlurHandler: inputBlurHandler, inputFocusHandler: inputFocusHandler, clickHandler: inputClickHandler }));
153
+ const renderDefaultInput = (inputRef) => {
154
+ return (react_1.default.createElement(SelectInput_1.SelectInput, { id: inputId, selectedOptions: selectedOptions, searchValue: searchValue, placeholder: placeholder, stickyValue: stickyInputValue, multiple: multiple, searchable: searchable, clearable: clearable, customIcon: icon, inputRef: inputRef, onlyIcon: onlyIcon, clearHandler: clearHandler, searchHandler: searchHandler, inputBlurHandler: inputBlurHandler, inputFocusHandler: inputFocusHandler, clickHandler: inputClickHandler }));
152
155
  };
153
156
  return (react_1.default.createElement(exports.SelectWrapper, Object.assign({ "data-component-name": "Select/Select", ref: selectRef }, dataAttributes, { disabled: disabled, "data-testid": dataTestId, className: className }),
154
- react_1.default.createElement(SelectDropdown, { closeOnClick: !multiple, withArrow: withArrow, trigger: renderInput ? renderInput() : renderDefaultInput(), triggerEvent: triggerEvent, placement: placement, alignment: alignment, active: !renderInput ? dropdownActive : undefined },
157
+ react_1.default.createElement(SelectDropdown, { closeOnClick: !multiple, withArrow: withArrow, trigger: renderInput ? renderInput() : renderDefaultInput(selectInputRef), triggerEvent: triggerEvent, placement: placement, alignment: alignment, active: !renderInput ? dropdownActive : undefined },
155
158
  react_1.default.createElement(SelectDropdownMenu, { footer: footer }, filteredOptions.length === 0 ? (react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, { disabled: true }, "No results")) : (filteredOptions.map((option, index) => {
156
159
  return (react_1.default.createElement(react_1.Fragment, { key: index },
157
160
  react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, { onAction: () => selectHandler(option), prefix: !hideCheckmarkIcon &&
@@ -12,6 +12,7 @@ type SelectInputProps<T> = {
12
12
  multiple?: boolean;
13
13
  searchable?: boolean;
14
14
  clearable?: boolean;
15
+ inputRef?: React.ForwardedRef<HTMLInputElement>;
15
16
  clearHandler?: (value?: any) => void;
16
17
  inputBlurHandler?: (e?: any) => void;
17
18
  inputFocusHandler?: (e?: any) => void;
@@ -43,7 +43,6 @@ function SelectInput(props) {
43
43
  };
44
44
  const onKeyDownHandler = (e) => {
45
45
  var _a;
46
- e.stopPropagation();
47
46
  if (e.key === 'Backspace' && !searchValue && selectedOptions.length) {
48
47
  clearHandler === null || clearHandler === void 0 ? void 0 : clearHandler(selectedOptions[selectedOptions.length - 1]);
49
48
  (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
@@ -72,7 +71,19 @@ function SelectInput(props) {
72
71
  const selectInput = (react_1.default.createElement(SelectInternalInput, { value: searchValue ||
73
72
  (!multiple && !stickyValue && selectedOptions.length
74
73
  ? selectedOptions[0].label || selectedOptions[0].value
75
- : ''), placeholder: searchValue || (multiple && selectedOptions.length) ? '' : stickyValue || placeholder, onChange: onChangeHandler, onKeyDown: onKeyDownHandler, onBlur: onBlurHandler, ref: inputRef, width: multiple ? (!searchValue && selectedOptions.length ? '10px' : 'auto') : '100%' }));
74
+ : ''), placeholder: searchValue || (multiple && selectedOptions.length) ? '' : stickyValue || placeholder, onChange: onChangeHandler, onKeyDown: onKeyDownHandler, onBlur: onBlurHandler, ref: (input) => {
75
+ if (!input)
76
+ return;
77
+ inputRef.current = input;
78
+ if (!props.inputRef)
79
+ return;
80
+ if (typeof props.inputRef === 'function') {
81
+ props.inputRef(input);
82
+ }
83
+ else {
84
+ props.inputRef.current = input;
85
+ }
86
+ }, width: multiple ? (!searchValue && selectedOptions.length ? '10px' : 'auto') : '100%' }));
76
87
  const simpleValue = selectedOptions.length ? (selectedOptions[0].label || selectedOptions[0].element || selectedOptions[0].value) : (react_1.default.createElement(SelectInternalInputPlaceholder, null, placeholder));
77
88
  const multipleValues = selectedOptions.length ? (selectTags) : (react_1.default.createElement(SelectInternalInputPlaceholder, null, placeholder));
78
89
  return (react_1.default.createElement(exports.SelectInputWrapper, Object.assign({}, props, { id: id, onFocus: onFocusHandler, onClick: onClickHandler }),
@@ -17,9 +17,11 @@ export type TagProps = {
17
17
  size?: string;
18
18
  icon?: React.ReactNode;
19
19
  active?: boolean;
20
+ tabIndex?: number;
20
21
  onClick?: (event: React.MouseEvent) => void;
22
+ onKeyDown?: (event: React.KeyboardEvent) => void;
21
23
  onClose?: (event: React.MouseEvent) => void;
22
24
  };
23
- export declare function Tag({ children, color, icon, active, closable, onClick, onClose, size, borderless, withStatusDot, statusDotColor, ...otherProps }: TagProps): JSX.Element;
25
+ export declare function Tag({ children, color, icon, active, closable, tabIndex, onClick, onKeyDown, onClose, size, borderless, withStatusDot, statusDotColor, ...otherProps }: TagProps): JSX.Element;
24
26
  export declare const ContentWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
25
27
  export {};
@@ -21,8 +21,8 @@ const styled_components_1 = __importDefault(require("styled-components"));
21
21
  const CloseIcon_1 = require("../../icons/CloseIcon/CloseIcon");
22
22
  const CheckmarkFilledIcon_1 = require("../../icons/CheckmarkFilledIcon/CheckmarkFilledIcon");
23
23
  function Tag(_a) {
24
- var { children, color, icon, active, closable, onClick, onClose, size, borderless, withStatusDot, statusDotColor = 'var(--tag-status-dot-color-default)' } = _a, otherProps = __rest(_a, ["children", "color", "icon", "active", "closable", "onClick", "onClose", "size", "borderless", "withStatusDot", "statusDotColor"]);
25
- return (react_1.default.createElement(TagWrapper, Object.assign({ "data-component-name": "Tag/Tag", borderless: borderless, color: color, size: size, onClick: onClick, hasCloseButton: closable }, otherProps),
24
+ var { children, color, icon, active, closable, tabIndex, onClick, onKeyDown, onClose, size, borderless, withStatusDot, statusDotColor = 'var(--tag-status-dot-color-default)' } = _a, otherProps = __rest(_a, ["children", "color", "icon", "active", "closable", "tabIndex", "onClick", "onKeyDown", "onClose", "size", "borderless", "withStatusDot", "statusDotColor"]);
25
+ return (react_1.default.createElement(TagWrapper, Object.assign({ tabIndex: tabIndex, "data-component-name": "Tag/Tag", borderless: borderless, color: color, size: size, onClick: onClick, onKeyDown: onKeyDown, hasCloseButton: closable }, otherProps),
26
26
  withStatusDot ? react_1.default.createElement(StatusDot, { color: statusDotColor }) : icon ? icon : null,
27
27
  react_1.default.createElement(exports.ContentWrapper, null, children),
28
28
  closable && (react_1.default.createElement(CloseButton, { onClick: (event) => {
@@ -38,7 +38,7 @@ function UserMenu({ className }) {
38
38
  react_1.default.createElement(LogoutMenuItem_1.LogoutMenuItem, { key: "logout" }),
39
39
  ];
40
40
  return (react_1.default.createElement(UserMenuWrapper, { "data-component-name": "UserMenu/UserMenu" },
41
- react_1.default.createElement(StyledDropdown, { className: className, alignment: "end", trigger: react_1.default.createElement(UserMenuTrigger, { role: "button" },
41
+ react_1.default.createElement(StyledDropdown, { className: className, alignment: "end", trigger: react_1.default.createElement(UserMenuTrigger, { role: "button", tabIndex: 0 },
42
42
  react_1.default.createElement(UserAvatar_1.UserAvatar, { picture: userData.picture })) },
43
43
  react_1.default.createElement(DropdownMenu_1.DropdownMenu, null, items))));
44
44
  }
@@ -167,7 +167,6 @@ function useEvent(callback) {
167
167
  (0, react_1.useEffect)(() => {
168
168
  ref.current = callback;
169
169
  });
170
- // eslint-disable-next-line react-hooks/exhaustive-deps
171
170
  return (0, react_1.useCallback)(((...args) => { var _a; return (_a = ref.current) === null || _a === void 0 ? void 0 : _a.call(ref, ...args); }), []);
172
171
  }
173
172
  //# sourceMappingURL=use-collapse.js.map
@@ -22,12 +22,11 @@ function useDialogHotKeys(ref, onClose) {
22
22
  }
23
23
  };
24
24
  const onFocusableElementsHandler = () => {
25
- var _a, _b;
25
+ var _a;
26
26
  const focusableElements = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('input, [href], [tabindex]:not([tabindex="-1"])');
27
27
  if (focusableElements && focusableElements.length > 0) {
28
28
  firstFocusableRef.current = focusableElements[0];
29
29
  lastFocusableRef.current = focusableElements[focusableElements.length - 1];
30
- (_b = firstFocusableRef.current) === null || _b === void 0 ? void 0 : _b.focus();
31
30
  }
32
31
  };
33
32
  (0, react_1.useEffect)(() => {
@@ -0,0 +1,3 @@
1
+ export declare const ReturnKeyIcon: import("styled-components").StyledComponent<"span", any, import("../../components/Typography/Typography").TypographyProps & {
2
+ 'data-component-name': string;
3
+ }, "data-component-name">;