@redocly/theme 0.54.0-next.0 → 0.54.0-next.2
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/lib/components/CodeBlock/CodeBlockContainer.js +4 -0
- package/lib/components/CodeBlock/variables.js +1 -0
- package/lib/components/Feedback/Mood.js +13 -2
- package/lib/components/Feedback/Rating.js +13 -2
- package/lib/components/Feedback/Scale.js +13 -2
- package/lib/components/Feedback/Sentiment.js +13 -2
- package/lib/components/Image/Image.d.ts +1 -0
- package/lib/components/Image/Image.js +66 -16
- package/lib/components/Search/SearchDialog.js +19 -9
- package/lib/components/Search/SearchInput.js +7 -9
- package/lib/core/constants/search.d.ts +1 -0
- package/lib/core/constants/search.js +2 -1
- package/lib/core/hooks/__mocks__/index.d.ts +1 -0
- package/lib/core/hooks/__mocks__/index.js +1 -0
- package/lib/core/hooks/__mocks__/use-input-key-commands.d.ts +3 -0
- package/lib/core/hooks/__mocks__/use-input-key-commands.js +7 -0
- package/lib/core/hooks/index.d.ts +1 -0
- package/lib/core/hooks/index.js +1 -0
- package/lib/core/hooks/menu/use-nested-menu.js +7 -1
- package/lib/core/hooks/search/use-recent-searches.js +48 -25
- package/lib/core/hooks/use-input-key-commands.d.ts +8 -0
- package/lib/core/hooks/use-input-key-commands.js +71 -0
- package/lib/markdoc/tags/img.js +3 -0
- package/package.json +2 -2
- package/src/components/CodeBlock/CodeBlockContainer.tsx +4 -0
- package/src/components/CodeBlock/variables.ts +1 -0
- package/src/components/Feedback/Mood.tsx +15 -2
- package/src/components/Feedback/Rating.tsx +15 -2
- package/src/components/Feedback/Scale.tsx +15 -2
- package/src/components/Feedback/Sentiment.tsx +15 -4
- package/src/components/Image/Image.tsx +72 -20
- package/src/components/Search/SearchDialog.tsx +83 -58
- package/src/components/Search/SearchInput.tsx +9 -12
- package/src/core/constants/search.ts +2 -0
- package/src/core/hooks/__mocks__/index.ts +1 -0
- package/src/core/hooks/__mocks__/use-input-key-commands.ts +3 -0
- package/src/core/hooks/index.ts +1 -0
- package/src/core/hooks/menu/use-nested-menu.ts +9 -1
- package/src/core/hooks/search/use-recent-searches.ts +57 -24
- package/src/core/hooks/use-input-key-commands.ts +98 -0
- package/src/markdoc/tags/img.ts +3 -0
|
@@ -176,6 +176,10 @@ const CodeBlockContainerComponent = styled_components_1.default.pre `
|
|
|
176
176
|
display: flex;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
.tree-view-comment {
|
|
180
|
+
color: var(--code-block-tree-view-comment-color);
|
|
181
|
+
}
|
|
182
|
+
|
|
179
183
|
.tree-view-branch {
|
|
180
184
|
color: var(--code-block-tree-view-lines-color);
|
|
181
185
|
}
|
|
@@ -132,6 +132,7 @@ exports.code = (0, styled_components_1.css) `
|
|
|
132
132
|
*/
|
|
133
133
|
--code-block-tree-view-icon-font-family: 'TreeViewIcons'; // @presenter FontFamily
|
|
134
134
|
--code-block-tree-view-lines-color: var(--border-color-primary); // @presenter Color
|
|
135
|
+
--code-block-tree-view-comment-color: var(--input-content-placeholder-color); // @presenter Color
|
|
135
136
|
|
|
136
137
|
// @tokens End
|
|
137
138
|
`;
|
|
@@ -157,10 +157,15 @@ function Mood({ settings, onSubmit, className }) {
|
|
|
157
157
|
}, onChange: setReasons })),
|
|
158
158
|
displayComment && (React.createElement(Comment_1.Comment, { standAlone: false, onSubmit: ({ comment }) => setComment(comment), settings: { label: renderCommentLabel(score) } })))),
|
|
159
159
|
displayFeedbackEmail && (React.createElement(StyledFormOptionalFields, null,
|
|
160
|
-
React.createElement(
|
|
160
|
+
React.createElement(InputLabel, { "data-translation-key": "feedback.settings.optionalEmail.label" }, (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.label) ||
|
|
161
161
|
translate('feedback.settings.optionalEmail.label', 'Your email (optional, for follow-up)')),
|
|
162
162
|
React.createElement(EmailInput, { onChange: onEmailChange, placeholder: (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.placeholder) ||
|
|
163
|
-
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email
|
|
163
|
+
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email, onKeyDown: (e) => {
|
|
164
|
+
if (e.key === 'Enter') {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
onSubmitMoodForm();
|
|
167
|
+
}
|
|
168
|
+
} }))),
|
|
164
169
|
displaySubmitBnt && (React.createElement(ButtonsContainer, null,
|
|
165
170
|
React.createElement(Button_1.Button, { onClick: onCancelMoodForm, variant: "text", size: "small" }, "Cancel"),
|
|
166
171
|
React.createElement(Button_1.Button, { type: "submit", variant: "secondary", size: "small" }, "Submit"))))));
|
|
@@ -199,6 +204,12 @@ const Label = styled_components_1.default.h4 `
|
|
|
199
204
|
|
|
200
205
|
margin: 0;
|
|
201
206
|
`;
|
|
207
|
+
const InputLabel = styled_components_1.default.h4 `
|
|
208
|
+
font-weight: var(--font-weight-regular);
|
|
209
|
+
font-size: var(--feedback-font-size);
|
|
210
|
+
line-height: var(--feedback-line-height);
|
|
211
|
+
margin: 0;
|
|
212
|
+
`;
|
|
202
213
|
const ButtonsContainer = styled_components_1.default.div `
|
|
203
214
|
display: flex;
|
|
204
215
|
justify-content: end;
|
|
@@ -102,10 +102,15 @@ function Rating({ settings, onSubmit, className }) {
|
|
|
102
102
|
translate('feedback.settings.comment.label', 'Please share your feedback with us.'),
|
|
103
103
|
} })))),
|
|
104
104
|
displayFeedbackEmail && (React.createElement(StyledFormOptionalFields, null,
|
|
105
|
-
React.createElement(
|
|
105
|
+
React.createElement(InputLabel, { "data-translation-key": "feedback.settings.optionalEmail.label" }, (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.label) ||
|
|
106
106
|
translate('feedback.settings.optionalEmail.label', 'Your email (optional, for follow-up)')),
|
|
107
107
|
React.createElement(EmailInput, { onChange: onEmailChange, placeholder: (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.placeholder) ||
|
|
108
|
-
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email
|
|
108
|
+
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email, onKeyDown: (e) => {
|
|
109
|
+
if (e.key === 'Enter') {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
onSubmitRatingForm();
|
|
112
|
+
}
|
|
113
|
+
} }))),
|
|
109
114
|
displaySubmitBnt && (React.createElement(ButtonsContainer, null,
|
|
110
115
|
React.createElement(Button_1.Button, { onClick: onCancelRatingForm, variant: "text", size: "small" }, "Cancel"),
|
|
111
116
|
React.createElement(Button_1.Button, { onClick: onSubmitRatingForm, variant: "secondary", size: "small" }, "Submit"))))));
|
|
@@ -143,6 +148,12 @@ const Label = styled_components_1.default.h4 `
|
|
|
143
148
|
color: var(--feedback-header-text-color);
|
|
144
149
|
margin: 0;
|
|
145
150
|
`;
|
|
151
|
+
const InputLabel = styled_components_1.default.h4 `
|
|
152
|
+
font-weight: var(--font-weight-regular);
|
|
153
|
+
font-size: var(--feedback-font-size);
|
|
154
|
+
line-height: var(--feedback-line-height);
|
|
155
|
+
margin: 0;
|
|
156
|
+
`;
|
|
146
157
|
const ButtonsContainer = styled_components_1.default.div `
|
|
147
158
|
display: flex;
|
|
148
159
|
justify-content: end;
|
|
@@ -109,10 +109,15 @@ function Scale({ settings, onSubmit, className }) {
|
|
|
109
109
|
translate('feedback.settings.comment.label', 'Please share your feedback with us.'),
|
|
110
110
|
} }))),
|
|
111
111
|
displayFeedbackEmail && (React.createElement(StyledFormOptionalFields, null,
|
|
112
|
-
React.createElement(
|
|
112
|
+
React.createElement(InputLabel, { "data-translation-key": "feedback.settings.optionalEmail.label" }, (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.label) ||
|
|
113
113
|
translate('feedback.settings.optionalEmail.label', 'Your email (optional, for follow-up)')),
|
|
114
114
|
React.createElement(EmailInput, { onChange: onEmailChange, placeholder: (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.placeholder) ||
|
|
115
|
-
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email
|
|
115
|
+
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email, onKeyDown: (e) => {
|
|
116
|
+
if (e.key === 'Enter') {
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
onSubmitScaleForm();
|
|
119
|
+
}
|
|
120
|
+
} }))),
|
|
116
121
|
displaySubmitBnt && (React.createElement(ButtonsContainer, null,
|
|
117
122
|
React.createElement(Button_1.Button, { "data-translation-key": "feedback.settings.comment.cancel", onClick: handleCancel, variant: "text", size: "small" }, translate('feedback.settings.comment.cancel', 'Cancel')),
|
|
118
123
|
React.createElement(Button_1.Button, { "data-translation-key": "feedback.settings.scale.send", type: "submit", variant: "secondary", size: "small" }, translate('feedback.settings.scale.send', 'Submit')))))));
|
|
@@ -132,6 +137,12 @@ const Label = styled_components_1.default.h4 `
|
|
|
132
137
|
margin: 0;
|
|
133
138
|
width: 100%;
|
|
134
139
|
`;
|
|
140
|
+
const InputLabel = styled_components_1.default.h4 `
|
|
141
|
+
font-weight: var(--font-weight-regular);
|
|
142
|
+
font-size: var(--feedback-font-size);
|
|
143
|
+
line-height: var(--feedback-line-height);
|
|
144
|
+
margin: 0;
|
|
145
|
+
`;
|
|
135
146
|
const SubLabelContainer = styled_components_1.default.div `
|
|
136
147
|
display: flex;
|
|
137
148
|
justify-content: space-between;
|
|
@@ -141,10 +141,15 @@ function Sentiment({ settings, onSubmit, className }) {
|
|
|
141
141
|
}, onChange: setReasons })),
|
|
142
142
|
displayComment && (React.createElement(Comment_1.Comment, { standAlone: false, onSubmit: ({ comment }) => setComment(comment), settings: { label: commentLabel } })))),
|
|
143
143
|
displayFeedbackEmail && (React.createElement(StyledFormOptionalFields, null,
|
|
144
|
-
React.createElement(
|
|
144
|
+
React.createElement(InputLabel, { "data-translation-key": "feedback.settings.optionalEmail.label" }, (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.label) ||
|
|
145
145
|
translate('feedback.settings.optionalEmail.label', 'Your email (optional, for follow-up)')),
|
|
146
146
|
React.createElement(EmailInput, { onChange: onEmailChange, placeholder: (optionalEmailSettings === null || optionalEmailSettings === void 0 ? void 0 : optionalEmailSettings.placeholder) ||
|
|
147
|
-
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email
|
|
147
|
+
translate('feedback.settings.optionalEmail.placeholder', 'yourname@example.com'), type: "email", required: !!email, onKeyDown: (e) => {
|
|
148
|
+
if (e.key === 'Enter') {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
onSubmitSentimentForm();
|
|
151
|
+
}
|
|
152
|
+
} }))),
|
|
148
153
|
displaySubmitBnt && (React.createElement(ButtonsContainer, null,
|
|
149
154
|
React.createElement(Button_1.Button, { onClick: onCancelSentimentForm, variant: "text", size: "small" }, "Cancel"),
|
|
150
155
|
React.createElement(Button_1.Button, { onClick: onSubmitSentimentForm, variant: "secondary", size: "small" }, "Submit"))))));
|
|
@@ -163,6 +168,12 @@ const Label = styled_components_1.default.h4 `
|
|
|
163
168
|
color: var(--feedback-header-text-color);
|
|
164
169
|
margin: 0;
|
|
165
170
|
`;
|
|
171
|
+
const InputLabel = styled_components_1.default.h4 `
|
|
172
|
+
font-weight: var(--font-weight-regular);
|
|
173
|
+
font-size: var(--feedback-font-size);
|
|
174
|
+
line-height: var(--feedback-line-height);
|
|
175
|
+
margin: 0;
|
|
176
|
+
`;
|
|
166
177
|
const StyledForm = styled_components_1.default.form `
|
|
167
178
|
width: 100%;
|
|
168
179
|
gap: var(--spacing-sm);
|
|
@@ -1,30 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.Image = Image;
|
|
7
|
-
const react_1 =
|
|
30
|
+
const react_1 = __importStar(require("react"));
|
|
8
31
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
9
32
|
const utils_1 = require("../../core/utils");
|
|
10
33
|
function Image(props) {
|
|
11
|
-
const { src, srcSet, alt, className, width, height, border, style, withLightbox } = props;
|
|
12
|
-
const
|
|
13
|
-
const
|
|
34
|
+
const { src, srcSet, alt, className, width, height, border, style, withLightbox, lightboxStyle } = props;
|
|
35
|
+
const lightboxContainerRef = (0, react_1.useRef)(null);
|
|
36
|
+
const [lightboxImage, setLightboxImage] = (0, react_1.useState)(undefined);
|
|
37
|
+
const parsedSourceSetMap = (0, react_1.useMemo)(() => {
|
|
14
38
|
return srcSet ? (0, utils_1.parseSrcSet)(srcSet) : new Map();
|
|
15
39
|
}, [srcSet]);
|
|
16
|
-
const
|
|
40
|
+
const handleLightboxKeyDown = (0, react_1.useCallback)((e) => {
|
|
41
|
+
e.stopPropagation();
|
|
42
|
+
if (e.key === 'Escape') {
|
|
43
|
+
setLightboxImage(undefined);
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const handleImageClick = (0, react_1.useCallback)((src) => {
|
|
17
47
|
if (!withLightbox || lightboxImage) {
|
|
18
48
|
return;
|
|
19
49
|
}
|
|
20
50
|
setLightboxImage(src);
|
|
21
|
-
};
|
|
22
|
-
const handleCloseLightbox = () => {
|
|
51
|
+
}, [withLightbox, lightboxImage]);
|
|
52
|
+
const handleCloseLightbox = (0, react_1.useCallback)(() => {
|
|
23
53
|
setLightboxImage(undefined);
|
|
24
|
-
};
|
|
54
|
+
}, []);
|
|
55
|
+
(0, react_1.useEffect)(() => {
|
|
56
|
+
var _a;
|
|
57
|
+
if (lightboxImage) {
|
|
58
|
+
(_a = lightboxContainerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
59
|
+
}
|
|
60
|
+
}, [lightboxImage]);
|
|
25
61
|
const combinedStyles = Object.assign(Object.assign(Object.assign({}, (withLightbox && { cursor: 'pointer' })), (border && { border })), (typeof style === 'string' ? { cssText: style } : style));
|
|
62
|
+
const lightboxOverlayStyles = typeof lightboxStyle === 'string' ? { cssText: lightboxStyle } : lightboxStyle;
|
|
26
63
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
27
|
-
lightboxImage ? (react_1.default.createElement(LightboxContainer, { onClick: handleCloseLightbox },
|
|
64
|
+
lightboxImage ? (react_1.default.createElement(LightboxContainer, { ref: lightboxContainerRef, onClick: handleCloseLightbox, onKeyDown: handleLightboxKeyDown, tabIndex: 0 },
|
|
65
|
+
react_1.default.createElement(Overlay, { style: lightboxOverlayStyles }),
|
|
28
66
|
react_1.default.createElement(Image, { src: lightboxImage, alt: alt }))) : null,
|
|
29
67
|
src ? (react_1.default.createElement("img", { src: src, alt: alt, className: className, width: width, height: height, style: combinedStyles, onClick: () => handleImageClick(src) })) : (Array.from(parsedSourceSetMap).map(([key, value]) => (react_1.default.createElement(ColorModeAwareImage, { key: key, colorMode: key, src: value, alt: alt, className: className, width: width, height: height, "$withLightbox": withLightbox, style: combinedStyles, onClick: () => handleImageClick(value) }))))));
|
|
30
68
|
}
|
|
@@ -37,20 +75,32 @@ const ColorModeAwareImage = styled_components_1.default.img `
|
|
|
37
75
|
cursor: pointer;
|
|
38
76
|
`}
|
|
39
77
|
`;
|
|
78
|
+
const Overlay = styled_components_1.default.div `
|
|
79
|
+
background-color: var(--bg-color-modal-overlay);
|
|
80
|
+
grid-column: 1 / 2;
|
|
81
|
+
grid-row: 1 / 2;
|
|
82
|
+
height: 100%;
|
|
83
|
+
width: 100%;
|
|
84
|
+
z-index: -1;
|
|
85
|
+
`;
|
|
40
86
|
const LightboxContainer = styled_components_1.default.div `
|
|
87
|
+
display: grid;
|
|
88
|
+
height: 100vh;
|
|
89
|
+
left: 0;
|
|
41
90
|
position: fixed;
|
|
42
91
|
top: 0;
|
|
43
|
-
|
|
44
|
-
width: 100%;
|
|
45
|
-
height: 100%;
|
|
46
|
-
background-color: var(--bg-color-modal-overlay);
|
|
92
|
+
width: 100vw;
|
|
47
93
|
z-index: var(--z-index-overlay);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
94
|
+
|
|
95
|
+
&:focus {
|
|
96
|
+
outline: none;
|
|
97
|
+
}
|
|
51
98
|
|
|
52
99
|
img {
|
|
53
100
|
cursor: pointer;
|
|
101
|
+
grid-column: 1 / 2;
|
|
102
|
+
grid-row: 1 / 2;
|
|
103
|
+
margin: auto;
|
|
54
104
|
max-width: 90%;
|
|
55
105
|
max-height: 90%;
|
|
56
106
|
}
|
|
@@ -59,6 +59,7 @@ function SearchDialog({ onClose, className }) {
|
|
|
59
59
|
const autoSearchDisabled = mode !== 'search';
|
|
60
60
|
const { query, setQuery, filter, setFilter, items, isSearchLoading, facets, setLoadMore, advancedSearch, askAi, groupField, } = useSearch(product === null || product === void 0 ? void 0 : product.name, autoSearchDisabled);
|
|
61
61
|
const { isFilterOpen, onFilterToggle, onFilterChange, onFilterReset, onFacetReset, onQuickFilterReset, } = (0, hooks_1.useSearchFilter)(filter, setFilter);
|
|
62
|
+
const { addSearchHistoryItem } = (0, hooks_1.useRecentSearches)();
|
|
62
63
|
const aiSearch = useAiSearch({ filter });
|
|
63
64
|
const searchInputRef = (0, react_1.useRef)(null);
|
|
64
65
|
const modalRef = (0, react_1.useRef)(null);
|
|
@@ -66,7 +67,15 @@ function SearchDialog({ onClose, className }) {
|
|
|
66
67
|
const firstSearchResultRef = (0, react_1.useRef)(null);
|
|
67
68
|
const searchKeysWithResults = items ? Object.keys(items).filter((key) => { var _a; return (_a = items[key]) === null || _a === void 0 ? void 0 : _a.length; }) : [];
|
|
68
69
|
const { translate } = useTranslate();
|
|
69
|
-
(0,
|
|
70
|
+
const handleClose = (0, react_1.useCallback)(() => {
|
|
71
|
+
var _a;
|
|
72
|
+
const value = (_a = searchInputRef === null || searchInputRef === void 0 ? void 0 : searchInputRef.current) === null || _a === void 0 ? void 0 : _a.value;
|
|
73
|
+
if (value) {
|
|
74
|
+
addSearchHistoryItem(value);
|
|
75
|
+
}
|
|
76
|
+
onClose();
|
|
77
|
+
}, [addSearchHistoryItem, onClose]);
|
|
78
|
+
(0, hooks_1.useDialogHotKeys)(modalRef, handleClose);
|
|
70
79
|
const focusSearchInput = () => {
|
|
71
80
|
requestAnimationFrame(() => {
|
|
72
81
|
var _a;
|
|
@@ -79,16 +88,16 @@ function SearchDialog({ onClose, className }) {
|
|
|
79
88
|
}
|
|
80
89
|
}, [mode, aiSearch.isGeneratingResponse, setQuery]);
|
|
81
90
|
(0, react_1.useEffect)(focusSearchInput, []);
|
|
82
|
-
const handleOverlayClick = (event) => {
|
|
91
|
+
const handleOverlayClick = (0, react_1.useCallback)((event) => {
|
|
83
92
|
var _a;
|
|
84
93
|
const target = event.target;
|
|
85
94
|
if (typeof target.className !== 'string')
|
|
86
95
|
return;
|
|
87
96
|
if ((_a = target.className) === null || _a === void 0 ? void 0 : _a.includes(' overlay')) {
|
|
88
|
-
|
|
97
|
+
handleClose();
|
|
89
98
|
}
|
|
90
|
-
};
|
|
91
|
-
const mapItem = (item, index, results, innerRef) => {
|
|
99
|
+
}, [handleClose]);
|
|
100
|
+
const mapItem = (0, react_1.useCallback)((item, index, results, innerRef) => {
|
|
92
101
|
var _a;
|
|
93
102
|
let itemProduct;
|
|
94
103
|
if (!product && item.document.product) {
|
|
@@ -99,6 +108,7 @@ function SearchDialog({ onClose, className }) {
|
|
|
99
108
|
: undefined;
|
|
100
109
|
}
|
|
101
110
|
return (react_1.default.createElement(SearchItem_1.SearchItem, { key: `${index}-${item.document.id}`, item: item, product: itemProduct, innerRef: innerRef, onClick: () => {
|
|
111
|
+
addSearchHistoryItem(query);
|
|
102
112
|
otelTelemetry.send('search.result.clicked', {
|
|
103
113
|
query,
|
|
104
114
|
url: item.document.url,
|
|
@@ -107,8 +117,8 @@ function SearchDialog({ onClose, className }) {
|
|
|
107
117
|
search_engine: mode,
|
|
108
118
|
});
|
|
109
119
|
} }));
|
|
110
|
-
};
|
|
111
|
-
const showLoadMore = (groupKey, currentCount = 0) => {
|
|
120
|
+
}, [product, products, addSearchHistoryItem, query, otelTelemetry, mode]);
|
|
121
|
+
const showLoadMore = (0, react_1.useCallback)((groupKey, currentCount = 0) => {
|
|
112
122
|
const groupFacet = facets.find((facet) => facet.field === groupField);
|
|
113
123
|
let needLoadMore = false;
|
|
114
124
|
if (groupFacet) {
|
|
@@ -122,7 +132,7 @@ function SearchDialog({ onClose, className }) {
|
|
|
122
132
|
needLoadMore = groupValue ? groupValue.count > currentCount : false;
|
|
123
133
|
}
|
|
124
134
|
return needLoadMore;
|
|
125
|
-
};
|
|
135
|
+
}, [facets, groupField]);
|
|
126
136
|
const showResults = !!((filter && filter.length) || query);
|
|
127
137
|
const showSearchFilterButton = advancedSearch && mode === 'search';
|
|
128
138
|
const showAiSearchButton = askAi && mode === 'search';
|
|
@@ -220,7 +230,7 @@ function SearchDialog({ onClose, className }) {
|
|
|
220
230
|
isSearchLoading && (react_1.default.createElement(SearchLoading, null,
|
|
221
231
|
react_1.default.createElement(SpinnerLoader_1.SpinnerLoader, { size: "16px", color: "var(--search-input-icon-color)" }),
|
|
222
232
|
translate('search.loading', 'Loading...'))),
|
|
223
|
-
react_1.default.createElement(SearchCancelButton, { "data-translation-key": "search.cancel", variant: "secondary", size: "small", onClick:
|
|
233
|
+
react_1.default.createElement(SearchCancelButton, { "data-translation-key": "search.cancel", variant: "secondary", size: "small", onClick: handleClose }, translate('search.cancel', 'Cancel'))))))));
|
|
224
234
|
}
|
|
225
235
|
const SearchOverlay = styled_components_1.default.div `
|
|
226
236
|
position: fixed;
|
|
@@ -14,26 +14,24 @@ const CloseFilledIcon_1 = require("../../icons/CloseFilledIcon/CloseFilledIcon")
|
|
|
14
14
|
const ChevronLeftIcon_1 = require("../../icons/ChevronLeftIcon/ChevronLeftIcon");
|
|
15
15
|
function SearchInput({ placeholder, value, onChange, isLoading, showReturnButton, inputRef, onReturn, onSubmit, className, }) {
|
|
16
16
|
const { useTelemetry } = (0, hooks_1.useThemeHooks)();
|
|
17
|
+
const { addSearchHistoryItem } = (0, hooks_1.useRecentSearches)();
|
|
17
18
|
const telemetry = useTelemetry();
|
|
19
|
+
const { onKeyDown } = (0, hooks_1.useInputKeyCommands)({
|
|
20
|
+
onEnter: (event) => onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(event),
|
|
21
|
+
onClear: () => addSearchHistoryItem(value),
|
|
22
|
+
});
|
|
18
23
|
const stopPropagation = (event) => event.stopPropagation();
|
|
19
24
|
const handleOnChange = (event) => {
|
|
20
25
|
onChange(event.target.value);
|
|
21
26
|
};
|
|
22
27
|
const handleOnReset = () => {
|
|
23
28
|
onChange('');
|
|
29
|
+
addSearchHistoryItem(value);
|
|
24
30
|
telemetry.send('search_input_reset_button_clicked', {});
|
|
25
31
|
};
|
|
26
|
-
const handleOnKeyUp = (e) => {
|
|
27
|
-
if (!onSubmit) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (e.key === 'Enter') {
|
|
31
|
-
onSubmit(e);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
32
|
return (react_1.default.createElement(SearchInputWrapper, { "data-component-name": "Search/SearchInput", className: className },
|
|
35
33
|
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, ref: inputRef, placeholder: placeholder, onChange: handleOnChange, onClick: stopPropagation,
|
|
34
|
+
react_1.default.createElement(SearchInputField, { value: value, ref: inputRef, placeholder: placeholder, onChange: handleOnChange, onClick: stopPropagation, onKeyDown: onKeyDown }),
|
|
37
35
|
!!value && (react_1.default.createElement(ResetButton, { variant: "ghost", onClick: handleOnReset, icon: react_1.default.createElement(CloseFilledIcon_1.CloseFilledIcon, null), tabIndex: -1 }))));
|
|
38
36
|
}
|
|
39
37
|
const SearchInputWrapper = styled_components_1.default.div `
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AI_SEARCH_ERROR_CONFIG = exports.AiSearchConversationRole = exports.AiSearchError = void 0;
|
|
3
|
+
exports.SEARCH_DEBOUNCE_TIME_MS = exports.AI_SEARCH_ERROR_CONFIG = exports.AiSearchConversationRole = exports.AiSearchError = void 0;
|
|
4
4
|
var AiSearchError;
|
|
5
5
|
(function (AiSearchError) {
|
|
6
6
|
AiSearchError["Unauthorized"] = "ai_search_unauthorized";
|
|
@@ -37,4 +37,5 @@ exports.AI_SEARCH_ERROR_CONFIG = {
|
|
|
37
37
|
[AiSearchError.EmptyResponse]: defaultErrorConfig,
|
|
38
38
|
[AiSearchError.ErrorProcessingResponse]: defaultErrorConfig,
|
|
39
39
|
};
|
|
40
|
+
exports.SEARCH_DEBOUNCE_TIME_MS = 300;
|
|
40
41
|
//# sourceMappingURL=search.js.map
|
|
@@ -25,3 +25,4 @@ export * from '../../../core/hooks/search/use-search-dialog';
|
|
|
25
25
|
export * from '../../../core/hooks/use-language-picker';
|
|
26
26
|
export * from '../../../core/hooks/__mocks__/use-element-size';
|
|
27
27
|
export * from '../../../core/hooks/__mocks__/use-time-ago';
|
|
28
|
+
export * from '../../../core/hooks/__mocks__/use-input-key-commands';
|
|
@@ -41,4 +41,5 @@ __exportStar(require("../../../core/hooks/search/use-search-dialog"), exports);
|
|
|
41
41
|
__exportStar(require("../../../core/hooks/use-language-picker"), exports);
|
|
42
42
|
__exportStar(require("../../../core/hooks/__mocks__/use-element-size"), exports);
|
|
43
43
|
__exportStar(require("../../../core/hooks/__mocks__/use-time-ago"), exports);
|
|
44
|
+
__exportStar(require("../../../core/hooks/__mocks__/use-input-key-commands"), exports);
|
|
44
45
|
//# sourceMappingURL=index.js.map
|
|
@@ -35,3 +35,4 @@ export * from '../../core/hooks/code-walkthrough/use-code-panel';
|
|
|
35
35
|
export * from '../../core/hooks/code-walkthrough/use-renderable-files';
|
|
36
36
|
export * from '../../core/hooks/use-element-size';
|
|
37
37
|
export * from '../../core/hooks/use-time-ago';
|
|
38
|
+
export * from '../../core/hooks/use-input-key-commands';
|
package/lib/core/hooks/index.js
CHANGED
|
@@ -51,4 +51,5 @@ __exportStar(require("../../core/hooks/code-walkthrough/use-code-panel"), export
|
|
|
51
51
|
__exportStar(require("../../core/hooks/code-walkthrough/use-renderable-files"), exports);
|
|
52
52
|
__exportStar(require("../../core/hooks/use-element-size"), exports);
|
|
53
53
|
__exportStar(require("../../core/hooks/use-time-ago"), exports);
|
|
54
|
+
__exportStar(require("../../core/hooks/use-input-key-commands"), exports);
|
|
54
55
|
//# sourceMappingURL=index.js.map
|
|
@@ -38,8 +38,14 @@ function useNestedMenu({ item, labelRef, nestedMenuRef }) {
|
|
|
38
38
|
},
|
|
39
39
|
});
|
|
40
40
|
function scrollIfNeeded(el, centerIfNeeded = false) {
|
|
41
|
+
const rect = el.getBoundingClientRect();
|
|
42
|
+
const isInViewport = rect.top >= 0 &&
|
|
43
|
+
rect.left >= 0 &&
|
|
44
|
+
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
45
|
+
rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
46
|
+
// Only scroll if element is in viewport to prevent page jumping
|
|
41
47
|
// @ts-ignore
|
|
42
|
-
if (typeof el.scrollIntoViewIfNeeded === 'function') {
|
|
48
|
+
if (isInViewport && typeof el.scrollIntoViewIfNeeded === 'function') {
|
|
43
49
|
// @ts-ignore
|
|
44
50
|
el.scrollIntoViewIfNeeded(centerIfNeeded);
|
|
45
51
|
}
|
|
@@ -5,35 +5,58 @@ const react_1 = require("react");
|
|
|
5
5
|
const utils_1 = require("../../../core/utils");
|
|
6
6
|
const RECENT_SEARCHES_KEY = 'recentSearches';
|
|
7
7
|
const RECENT_SEARCHES_LIMIT = 5;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
8
|
+
const createRecentSearchesStore = () => {
|
|
9
|
+
const subscribers = new Set();
|
|
10
|
+
let cachedSnapshot;
|
|
11
|
+
const getSnapshot = () => {
|
|
12
|
+
if (!(0, utils_1.isBrowser)())
|
|
13
|
+
return [];
|
|
14
|
+
if (cachedSnapshot)
|
|
15
|
+
return cachedSnapshot;
|
|
16
|
+
try {
|
|
17
|
+
const stored = localStorage.getItem(RECENT_SEARCHES_KEY);
|
|
18
|
+
cachedSnapshot = stored ? JSON.parse(stored) : [];
|
|
19
|
+
return cachedSnapshot;
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
cachedSnapshot = [];
|
|
23
|
+
return cachedSnapshot;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const updateItems = (value, isAdd) => {
|
|
27
|
+
if (!(0, utils_1.isBrowser)())
|
|
28
|
+
return;
|
|
29
|
+
const currentItems = getSnapshot();
|
|
30
|
+
const valueIndex = currentItems.indexOf(value);
|
|
31
|
+
if (valueIndex !== -1) {
|
|
32
|
+
currentItems.splice(valueIndex, 1);
|
|
33
|
+
}
|
|
34
|
+
if (isAdd) {
|
|
35
|
+
currentItems.unshift(value);
|
|
36
|
+
}
|
|
37
|
+
const limitedItems = currentItems.slice(0, RECENT_SEARCHES_LIMIT);
|
|
38
|
+
localStorage.setItem(RECENT_SEARCHES_KEY, JSON.stringify(limitedItems));
|
|
39
|
+
cachedSnapshot = limitedItems;
|
|
40
|
+
subscribers.forEach((callback) => callback());
|
|
41
|
+
};
|
|
42
|
+
const subscribe = (callback) => {
|
|
43
|
+
subscribers.add(callback);
|
|
44
|
+
return () => subscribers.delete(callback);
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
getSnapshot,
|
|
48
|
+
subscribe,
|
|
49
|
+
updateItems,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
const recentSearchesStore = createRecentSearchesStore();
|
|
30
53
|
const useRecentSearches = () => {
|
|
31
|
-
const
|
|
54
|
+
const items = (0, react_1.useSyncExternalStore)(recentSearchesStore.subscribe, recentSearchesStore.getSnapshot, () => []);
|
|
32
55
|
const addSearchHistoryItem = (0, react_1.useCallback)((value) => {
|
|
33
|
-
|
|
56
|
+
recentSearchesStore.updateItems(value, true);
|
|
34
57
|
}, []);
|
|
35
58
|
const removeSearchHistoryItem = (0, react_1.useCallback)((value) => {
|
|
36
|
-
|
|
59
|
+
recentSearchesStore.updateItems(value, false);
|
|
37
60
|
}, []);
|
|
38
61
|
return { items, addSearchHistoryItem, removeSearchHistoryItem };
|
|
39
62
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type Action = 'selectAll' | 'escape' | 'clear' | 'enter' | 'paste';
|
|
2
|
+
type ActionHandlers = {
|
|
3
|
+
[key in `on${Capitalize<Action>}`]?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
4
|
+
};
|
|
5
|
+
export declare function useInputKeyCommands(actionHandlers?: ActionHandlers): {
|
|
6
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
7
|
+
};
|
|
8
|
+
export {};
|