@salesforcedevs/dx-components 1.28.7-alpha.9 → 1.29.0-ssgalpha2
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/lwc.config.json +0 -1
- package/package.json +2 -3
- package/src/modules/dx/searchResults/searchResults.css +2 -52
- package/src/modules/dx/searchResults/searchResults.html +91 -84
- package/src/modules/dx/searchResults/searchResults.ts +478 -157
- package/src/modules/dx/sidebar/sidebar.html +4 -0
- package/src/modules/dx/sidebar/sidebar.ts +7 -7
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +347 -59
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +4 -4
- package/src/modules/dxUtils/shiki/shiki.ts +9 -12
- package/src/modules/dxUtils/shikiGrammars/shikiGrammars.ts +151 -41
- package/LICENSE +0 -12
- package/src/modules/dxUtils/dataCloudSearch/dataCloudSearch.ts +0 -100
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
<dx-sidebar-search
|
|
49
49
|
onchange={onSearchChange}
|
|
50
50
|
onloading={onSearchLoading}
|
|
51
|
+
coveo-organization-id={coveoOrganizationId}
|
|
52
|
+
coveo-public-access-token={coveoPublicAccessToken}
|
|
53
|
+
coveo-search-hub={coveoSearchHub}
|
|
54
|
+
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
51
55
|
></dx-sidebar-search>
|
|
52
56
|
</div>
|
|
53
57
|
<slot name="version-picker"></slot>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import cx from "classnames";
|
|
2
2
|
import { api, track } from "lwc";
|
|
3
3
|
import { TreeNode, SidebarSearchResult } from "typings/custom";
|
|
4
|
+
import { getSidebarSearchParams } from "dxUtils/coveo";
|
|
4
5
|
import { toJson } from "dxUtils/normalizers";
|
|
5
6
|
import SidebarSearch from "dx/sidebarSearch";
|
|
6
7
|
import { SidebarBase } from "dxBaseElements/sidebarBase";
|
|
7
8
|
|
|
8
9
|
const MOBILE_SIZE_MATCH = "768px";
|
|
9
10
|
|
|
10
|
-
const getSearchQueryParam = (): string | null =>
|
|
11
|
-
typeof window !== "undefined"
|
|
12
|
-
? new URLSearchParams(window.location.search).get("q")
|
|
13
|
-
: null;
|
|
14
|
-
|
|
15
11
|
export default class Sidebar extends SidebarBase {
|
|
12
|
+
@api coveoOrganizationId!: string;
|
|
13
|
+
@api coveoPublicAccessToken!: string;
|
|
14
|
+
@api coveoSearchHub!: string;
|
|
15
|
+
@api coveoAdvancedQueryConfig!: string;
|
|
16
16
|
@api header: string = "";
|
|
17
17
|
|
|
18
18
|
@api
|
|
@@ -130,7 +130,7 @@ export default class Sidebar extends SidebarBase {
|
|
|
130
130
|
constructor() {
|
|
131
131
|
super();
|
|
132
132
|
|
|
133
|
-
if (
|
|
133
|
+
if (getSidebarSearchParams()) {
|
|
134
134
|
this.isSearchLoading = true;
|
|
135
135
|
this.scrollToSelectedSearchResult = true;
|
|
136
136
|
}
|
|
@@ -175,7 +175,7 @@ export default class Sidebar extends SidebarBase {
|
|
|
175
175
|
this.isSearchLoading = e.detail;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
private onSidebarSearchContentScroll(scrollEvent
|
|
178
|
+
private onSidebarSearchContentScroll(scrollEvent) {
|
|
179
179
|
if (this.isSearchLoading) {
|
|
180
180
|
return;
|
|
181
181
|
}
|
|
@@ -1,27 +1,75 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import debounce from "debounce";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
Result,
|
|
5
|
+
ResultList,
|
|
6
|
+
Unsubscribe,
|
|
7
|
+
ResultsPerPage,
|
|
8
|
+
SearchBox,
|
|
9
|
+
buildInteractiveResult,
|
|
10
|
+
buildResultList,
|
|
11
|
+
buildResultsPerPage,
|
|
12
|
+
buildSearchBox,
|
|
13
|
+
loadAdvancedSearchQueryActions,
|
|
14
|
+
SearchEngine,
|
|
15
|
+
SearchAppState,
|
|
16
|
+
loadQueryActions
|
|
17
|
+
} from "@coveo/headless";
|
|
18
|
+
import { buildSearchEngine, getSidebarSearchParams } from "dxUtils/coveo";
|
|
7
19
|
import { RecentSearches } from "dxUtils/recentSearches";
|
|
20
|
+
import { toJson } from "dxUtils/normalizers";
|
|
8
21
|
import {
|
|
9
22
|
Option,
|
|
10
23
|
PopoverRequestCloseType,
|
|
11
24
|
SidebarSearchResult
|
|
12
25
|
} from "typings/custom";
|
|
13
26
|
|
|
27
|
+
const RESULT_CLICK_LOCAL_STORAGE_KEY = "dx-sidebar-search-result-click";
|
|
28
|
+
export const SESSION_KEY = "dx-sidebar-search-state";
|
|
29
|
+
|
|
30
|
+
const DEFAULT_RESULT_COUNT = 20;
|
|
14
31
|
const SEARCH_DEBOUNCE_DELAY = 1200;
|
|
15
32
|
|
|
16
33
|
const UserRecentSearches = new RecentSearches();
|
|
17
34
|
|
|
18
|
-
const
|
|
19
|
-
|
|
35
|
+
const normalizeCoveoAdvancedQueryValue = (version: string): string =>
|
|
36
|
+
version?.split(".").join("\\.");
|
|
20
37
|
|
|
21
38
|
export default class SidebarSearch extends LightningElement {
|
|
39
|
+
@api coveoOrganizationId!: string;
|
|
40
|
+
@api coveoPublicAccessToken!: string;
|
|
41
|
+
@api coveoSearchHub!: string;
|
|
42
|
+
@api
|
|
43
|
+
get coveoAdvancedQueryConfig(): { [key: string]: any } {
|
|
44
|
+
return this._coveoAdvancedQueryConfig;
|
|
45
|
+
}
|
|
46
|
+
set coveoAdvancedQueryConfig(value) {
|
|
47
|
+
const jsonValue = toJson(value);
|
|
48
|
+
const hasChanged =
|
|
49
|
+
this._coveoAdvancedQueryConfig &&
|
|
50
|
+
Object.entries(jsonValue).some(
|
|
51
|
+
([key, val]: [string, any]) =>
|
|
52
|
+
this._coveoAdvancedQueryConfig[key] !== val
|
|
53
|
+
);
|
|
54
|
+
this._coveoAdvancedQueryConfig = jsonValue;
|
|
55
|
+
|
|
56
|
+
if (hasChanged && this.engine && this.value !== "") {
|
|
57
|
+
this.dispatchOnLoading(true);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (hasChanged && this.engine) {
|
|
61
|
+
// set advanced filters needs access to the latest coveoAdvancedQueryConfig
|
|
62
|
+
this.setAdvancedFilters(this.engine);
|
|
63
|
+
this.submitSearch(true);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
22
67
|
@api
|
|
23
68
|
public fetchMoreResults() {
|
|
24
|
-
|
|
69
|
+
if (this.resultList?.state?.moreResultsAvailable) {
|
|
70
|
+
this.fetchingMoreResults = true;
|
|
71
|
+
this.resultList.fetchMoreResults();
|
|
72
|
+
}
|
|
25
73
|
}
|
|
26
74
|
|
|
27
75
|
@api
|
|
@@ -37,87 +85,313 @@ export default class SidebarSearch extends LightningElement {
|
|
|
37
85
|
this.dropdownRequestedOpen = value;
|
|
38
86
|
}
|
|
39
87
|
|
|
88
|
+
private _coveoAdvancedQueryConfig!: { [key: string]: any };
|
|
40
89
|
private dropdownRequestedOpen: boolean = false;
|
|
41
90
|
private recentSearches: Option[] = [];
|
|
42
|
-
private
|
|
91
|
+
private unsubscribeFromResultList: Unsubscribe = () => {};
|
|
92
|
+
private resultList: ResultList | null = null;
|
|
93
|
+
private resultsPerPage: ResultsPerPage | null = null;
|
|
94
|
+
private preloadedState?: SearchAppState;
|
|
95
|
+
private searchBox: SearchBox | null = null;
|
|
96
|
+
private value?: string = "";
|
|
97
|
+
private engine: SearchEngine | null = null;
|
|
98
|
+
private fetchingMoreResults: boolean = false;
|
|
43
99
|
private didRender = false;
|
|
44
|
-
|
|
100
|
+
|
|
101
|
+
private get hasCorrectCoveoConfig(): boolean {
|
|
102
|
+
const coveoConfigurations = [
|
|
103
|
+
this.coveoOrganizationId,
|
|
104
|
+
this.coveoPublicAccessToken,
|
|
105
|
+
this.coveoSearchHub,
|
|
106
|
+
this.coveoAdvancedQueryConfig
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
return coveoConfigurations.every(
|
|
110
|
+
(val) =>
|
|
111
|
+
!!val && (typeof val === "string" || typeof val === "object")
|
|
112
|
+
);
|
|
113
|
+
}
|
|
45
114
|
|
|
46
115
|
private get isDropdownOpen() {
|
|
47
116
|
return (
|
|
48
117
|
this.dropdownRequestedOpen &&
|
|
49
|
-
this.recentSearches
|
|
118
|
+
this.recentSearches &&
|
|
119
|
+
this.recentSearches.length > 0 &&
|
|
50
120
|
!this.value
|
|
51
121
|
);
|
|
52
122
|
}
|
|
53
123
|
|
|
54
124
|
constructor() {
|
|
55
125
|
super();
|
|
126
|
+
|
|
56
127
|
this.updateRecentSearches();
|
|
57
|
-
this.value =
|
|
128
|
+
this.value = getSidebarSearchParams() || "";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
disconnectedCallback() {
|
|
132
|
+
this.unsubscribeFromResultList();
|
|
58
133
|
}
|
|
59
134
|
|
|
60
135
|
renderedCallback() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
136
|
+
// in prod some of the critical coveo configuration attributes seem to arrive later
|
|
137
|
+
// so I needed to put this coveo startup flow here where we can wait for them to arrive
|
|
138
|
+
|
|
139
|
+
if (this.hasCorrectCoveoConfig && !this.engine) {
|
|
140
|
+
this.initializeUserSession();
|
|
141
|
+
this.initializeCoveo();
|
|
142
|
+
} else if (!this.hasCorrectCoveoConfig) {
|
|
143
|
+
console.error(
|
|
144
|
+
"Incorrect coveo search configuration provided. All coveo configuration attributes must be defined.",
|
|
145
|
+
{
|
|
146
|
+
coveoOrganizationId: this.coveoOrganizationId,
|
|
147
|
+
coveoPublicAccessToken: this.coveoPublicAccessToken,
|
|
148
|
+
coveoSearchHub: this.coveoSearchHub,
|
|
149
|
+
coveoAdvancedQueryConfig: this.coveoAdvancedQueryConfig
|
|
67
150
|
}
|
|
68
|
-
|
|
69
|
-
this.fetchDataCloudSearch();
|
|
70
|
-
} else {
|
|
71
|
-
this.dispatchOnLoading(false);
|
|
72
|
-
}
|
|
151
|
+
);
|
|
73
152
|
}
|
|
153
|
+
|
|
154
|
+
// If this is the first render and there is a search value, trigger
|
|
155
|
+
// term highlighting
|
|
74
156
|
if (!this.didRender && this.value) {
|
|
75
157
|
this.dispatchHighlightedTermChange();
|
|
76
158
|
}
|
|
159
|
+
|
|
77
160
|
this.didRender = true;
|
|
78
161
|
}
|
|
79
162
|
|
|
80
|
-
private
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
163
|
+
private initializeUserSession() {
|
|
164
|
+
const stringified = window.sessionStorage.getItem(SESSION_KEY);
|
|
165
|
+
|
|
166
|
+
if (!stringified) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const json = JSON.parse(stringified);
|
|
172
|
+
|
|
173
|
+
const hasSameConfig = Object.entries(
|
|
174
|
+
json.coveoAdvancedQueryConfig
|
|
175
|
+
).every(
|
|
176
|
+
([key, value]: [string, any]) =>
|
|
177
|
+
this.coveoAdvancedQueryConfig[key] === value
|
|
178
|
+
);
|
|
179
|
+
const hasSameQuery = json?.state?.query?.q === this.value;
|
|
180
|
+
|
|
181
|
+
if (hasSameConfig && hasSameQuery) {
|
|
182
|
+
this.preloadedState = json?.state;
|
|
183
|
+
} else {
|
|
184
|
+
window.sessionStorage.removeItem(SESSION_KEY);
|
|
185
|
+
}
|
|
186
|
+
} catch (e) {
|
|
187
|
+
console.error(e);
|
|
188
|
+
window.sessionStorage.removeItem(SESSION_KEY);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private initializeCoveo = () => {
|
|
193
|
+
try {
|
|
194
|
+
this.engine = buildSearchEngine({
|
|
195
|
+
organizationId: this.coveoOrganizationId,
|
|
196
|
+
publicAccessToken: this.coveoPublicAccessToken,
|
|
197
|
+
searchHub: this.coveoSearchHub,
|
|
198
|
+
preloadedState: this.preloadedState
|
|
199
|
+
});
|
|
200
|
+
} catch (ex) {
|
|
201
|
+
console.error(`Coveo engine failed to initialize (${ex})`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!this.engine) {
|
|
205
|
+
console.error("Coveo engine failed to initialize!");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (this.preloadedState) {
|
|
210
|
+
const actions = loadQueryActions(this.engine);
|
|
211
|
+
this.engine.dispatch(actions.updateQuery({ q: this.value || "" }));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.resultList = buildResultList(this.engine, {
|
|
215
|
+
options: { fieldsToInclude: ["sfhtml_url__c"] }
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
this.resultsPerPage = buildResultsPerPage(this.engine, {
|
|
219
|
+
initialState: {
|
|
220
|
+
numberOfResults: DEFAULT_RESULT_COUNT
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
this.searchBox = buildSearchBox(this.engine, {
|
|
225
|
+
options: { numberOfSuggestions: 3 }
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
this.setAdvancedFilters(this.engine);
|
|
229
|
+
|
|
230
|
+
this.unsubscribeFromResultList = this.resultList?.subscribe(
|
|
231
|
+
this.onResultListChange
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
if (this.value) {
|
|
235
|
+
this.dispatchHighlightedTermChange();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (!this.preloadedState) {
|
|
239
|
+
if (this.value) {
|
|
240
|
+
this.submitSearch();
|
|
241
|
+
} else {
|
|
242
|
+
this.dispatchOnLoading(false);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
this.syncAnalytics();
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
private syncAnalytics = () => {
|
|
250
|
+
const storedResult = window.localStorage.getItem(
|
|
251
|
+
RESULT_CLICK_LOCAL_STORAGE_KEY
|
|
252
|
+
);
|
|
253
|
+
if (storedResult) {
|
|
254
|
+
const interactiveResult = buildInteractiveResult(this.engine!, {
|
|
255
|
+
options: { result: JSON.parse(storedResult) }
|
|
256
|
+
});
|
|
257
|
+
interactiveResult.cancelPendingSelect();
|
|
258
|
+
interactiveResult.select();
|
|
259
|
+
window.localStorage.removeItem(RESULT_CLICK_LOCAL_STORAGE_KEY);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
private onResultListChange = () => {
|
|
264
|
+
if (!this.resultList) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const { isLoading, firstSearchExecuted, results } =
|
|
269
|
+
this.resultList.state;
|
|
270
|
+
|
|
271
|
+
if ((!firstSearchExecuted && !isLoading) || !this.value) {
|
|
272
|
+
// coveo search is firing off some unwanted payloads on startup
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!isLoading) {
|
|
277
|
+
this.dispatchOnChangeEvent(results);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (!this.fetchingMoreResults) {
|
|
281
|
+
this.dispatchOnLoading(isLoading);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!isLoading && this.fetchingMoreResults) {
|
|
285
|
+
this.fetchingMoreResults = false;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
private setAdvancedFilters(engine: SearchEngine) {
|
|
290
|
+
const aq = Object.entries(this.coveoAdvancedQueryConfig).reduce(
|
|
291
|
+
(result, [key, value]) =>
|
|
292
|
+
`${result}(@${key}=="${normalizeCoveoAdvancedQueryValue(
|
|
293
|
+
value
|
|
294
|
+
)}")`,
|
|
295
|
+
""
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
const registerSearchQueryAction = loadAdvancedSearchQueryActions(
|
|
299
|
+
engine
|
|
300
|
+
).registerAdvancedSearchQueries({
|
|
301
|
+
aq: aq
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
engine.dispatch(registerSearchQueryAction);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private normalizeCoveoResult = (result: Result): SidebarSearchResult => {
|
|
308
|
+
const {
|
|
309
|
+
clickUri,
|
|
310
|
+
excerpt,
|
|
311
|
+
excerptHighlights,
|
|
312
|
+
raw: { sfhtml_url__c },
|
|
313
|
+
title,
|
|
314
|
+
titleHighlights,
|
|
315
|
+
uniqueId
|
|
316
|
+
} = result;
|
|
317
|
+
|
|
318
|
+
// discussion about this normalization here: https://salesforce-internal.slack.com/archives/C020S6784JX/p1639506238376600
|
|
319
|
+
|
|
320
|
+
let pathname, queryParam;
|
|
321
|
+
if (sfhtml_url__c) {
|
|
322
|
+
pathname = `/docs/${sfhtml_url__c}`;
|
|
323
|
+
} else {
|
|
324
|
+
const isNestedGuide = clickUri.includes("/guide/");
|
|
325
|
+
const url = new URL(clickUri);
|
|
326
|
+
const extension =
|
|
327
|
+
isNestedGuide && !url.pathname?.endsWith(".html")
|
|
328
|
+
? ".html"
|
|
329
|
+
: "";
|
|
330
|
+
pathname = `${url.pathname}${extension}`;
|
|
331
|
+
queryParam = url.search;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let href;
|
|
335
|
+
let isSelected = false;
|
|
336
|
+
const isReferenceUrl = clickUri.includes("/references/");
|
|
337
|
+
if (isReferenceUrl) {
|
|
338
|
+
if (queryParam) {
|
|
339
|
+
href = `${pathname}${queryParam}&q=${this.value}`;
|
|
340
|
+
} else {
|
|
341
|
+
href = `${pathname}?q=${this.value}`;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
//NOTE: This is specific to references related comparison
|
|
345
|
+
const resultHrefWithMetaQuery = `${pathname}${queryParam}`;
|
|
346
|
+
|
|
347
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
348
|
+
const metaQueryParam = urlParams.get("meta");
|
|
349
|
+
|
|
350
|
+
let currentUrlPathWithQuery = window.location.pathname;
|
|
351
|
+
if (metaQueryParam) {
|
|
352
|
+
currentUrlPathWithQuery = `${currentUrlPathWithQuery}?meta=${metaQueryParam}`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
isSelected = resultHrefWithMetaQuery === currentUrlPathWithQuery;
|
|
356
|
+
} else {
|
|
357
|
+
href = `${pathname}?q=${this.value}`;
|
|
358
|
+
isSelected = pathname === window.location.pathname;
|
|
359
|
+
}
|
|
360
|
+
|
|
90
361
|
return {
|
|
91
|
-
title
|
|
92
|
-
titleHighlights
|
|
93
|
-
excerpt
|
|
94
|
-
excerptHighlights
|
|
95
|
-
uniqueId
|
|
362
|
+
title,
|
|
363
|
+
titleHighlights,
|
|
364
|
+
excerpt,
|
|
365
|
+
excerptHighlights,
|
|
366
|
+
uniqueId,
|
|
96
367
|
href,
|
|
97
368
|
selected: isSelected,
|
|
98
|
-
select: () =>
|
|
369
|
+
select: () =>
|
|
370
|
+
window.localStorage.setItem(
|
|
371
|
+
RESULT_CLICK_LOCAL_STORAGE_KEY,
|
|
372
|
+
JSON.stringify(result)
|
|
373
|
+
)
|
|
99
374
|
};
|
|
100
375
|
};
|
|
101
376
|
|
|
102
|
-
private
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
this.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
console.error("Data Cloud Search request failed", err);
|
|
111
|
-
this.dispatchChange([]);
|
|
112
|
-
} finally {
|
|
113
|
-
this.dispatchOnLoading(false);
|
|
114
|
-
}
|
|
377
|
+
private updateSessionStorage() {
|
|
378
|
+
window.sessionStorage.setItem(
|
|
379
|
+
SESSION_KEY,
|
|
380
|
+
JSON.stringify({
|
|
381
|
+
coveoAdvancedQueryConfig: this.coveoAdvancedQueryConfig,
|
|
382
|
+
state: this.engine?.state
|
|
383
|
+
})
|
|
384
|
+
);
|
|
115
385
|
}
|
|
116
386
|
|
|
117
|
-
private
|
|
387
|
+
private dispatchOnChangeEvent(results: Result[]) {
|
|
388
|
+
this.updateSessionStorage();
|
|
118
389
|
this.dispatchEvent(
|
|
119
390
|
new CustomEvent("change", {
|
|
120
|
-
detail: {
|
|
391
|
+
detail: {
|
|
392
|
+
results: results.map(this.normalizeCoveoResult),
|
|
393
|
+
value: this.value
|
|
394
|
+
}
|
|
121
395
|
})
|
|
122
396
|
);
|
|
123
397
|
}
|
|
@@ -153,12 +427,19 @@ export default class SidebarSearch extends LightningElement {
|
|
|
153
427
|
}
|
|
154
428
|
|
|
155
429
|
private submitSearch = debounce((isSyncingSearchValue = false) => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
430
|
+
if (this.searchBox) {
|
|
431
|
+
UserRecentSearches.add(this.value);
|
|
432
|
+
this.updateRecentSearches();
|
|
433
|
+
|
|
434
|
+
// When `isSyncingSearchValue` is true, we are submitting in a case
|
|
435
|
+
// where the search box is already synced correctly.
|
|
436
|
+
if (!isSyncingSearchValue) {
|
|
437
|
+
this.dispatchSidebarSearchChange(this.value);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
this.searchBox.updateText(this.value || "");
|
|
441
|
+
this.searchBox.submit();
|
|
160
442
|
}
|
|
161
|
-
this.fetchDataCloudSearch();
|
|
162
443
|
}, SEARCH_DEBOUNCE_DELAY);
|
|
163
444
|
|
|
164
445
|
private onClickRecentSearch(e: CustomEvent) {
|
|
@@ -180,6 +461,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
180
461
|
|
|
181
462
|
private onInputChange(e: CustomEvent) {
|
|
182
463
|
this.value = e.detail;
|
|
464
|
+
|
|
183
465
|
this.handleValueChange(false);
|
|
184
466
|
this.dispatchHighlightedTermChange();
|
|
185
467
|
}
|
|
@@ -195,10 +477,16 @@ export default class SidebarSearch extends LightningElement {
|
|
|
195
477
|
private handleValueChange(isSyncingSearchValue = false) {
|
|
196
478
|
if (this.value) {
|
|
197
479
|
this.dispatchOnLoading(true);
|
|
198
|
-
this.
|
|
480
|
+
if (this.searchBox) {
|
|
481
|
+
this.submitSearch(isSyncingSearchValue);
|
|
482
|
+
}
|
|
199
483
|
} else {
|
|
484
|
+
// coveo's reaction to an empty value triggers a return of results
|
|
485
|
+
// bootlegging our own ux here`
|
|
200
486
|
this.dispatchOnLoading(false);
|
|
201
|
-
this.
|
|
487
|
+
this.dispatchOnChangeEvent([]);
|
|
488
|
+
// Empty search values are not submitted for search, so we need to manually
|
|
489
|
+
// trigger a search change on our own here
|
|
202
490
|
this.dispatchSidebarSearchChange(this.value);
|
|
203
491
|
}
|
|
204
492
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import cx from "classnames";
|
|
3
|
-
import {
|
|
3
|
+
import { CoveoHighlights } from "typings/custom";
|
|
4
4
|
|
|
5
|
-
const toChunks = (value: string, highlights:
|
|
5
|
+
const toChunks = (value: string, highlights: CoveoHighlights) => {
|
|
6
6
|
if (!highlights || highlights.length < 1) {
|
|
7
7
|
return [
|
|
8
8
|
{
|
|
@@ -51,11 +51,11 @@ const toChunks = (value: string, highlights: HighlightedSections) => {
|
|
|
51
51
|
|
|
52
52
|
export default class SidebarSearchResult extends LightningElement {
|
|
53
53
|
@api description!: string;
|
|
54
|
-
@api descriptionHighlights!:
|
|
54
|
+
@api descriptionHighlights!: CoveoHighlights;
|
|
55
55
|
@api href!: string;
|
|
56
56
|
@api selected!: boolean;
|
|
57
57
|
@api header!: string;
|
|
58
|
-
@api titleHighlights!:
|
|
58
|
+
@api titleHighlights!: CoveoHighlights;
|
|
59
59
|
@api select!: Function;
|
|
60
60
|
|
|
61
61
|
private get titleChunks() {
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import type { BundledLanguage, BundledTheme, HighlighterCore } from "shiki";
|
|
2
|
+
import * as shiki from "shiki";
|
|
3
|
+
import { transformerColorizedBrackets } from "@shikijs/colorized-brackets";
|
|
2
4
|
import { getCustomLanguageGrammars } from "dxUtils/shikiGrammars";
|
|
3
5
|
|
|
4
|
-
let shikiModulePromise: Promise<typeof import("shiki")> | null = null;
|
|
5
|
-
let bracketsModulePromise: Promise<
|
|
6
|
-
typeof import("@shikijs/colorized-brackets")
|
|
7
|
-
> | null = null;
|
|
8
|
-
|
|
9
6
|
async function getShiki() {
|
|
10
|
-
return
|
|
7
|
+
return shiki;
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
async function getBrackets() {
|
|
14
|
-
return
|
|
11
|
+
return { transformerColorizedBrackets };
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
interface ShikiSingleton {
|
|
@@ -101,7 +98,7 @@ const OPTIONAL_LANGUAGES: Record<string, any> = {
|
|
|
101
98
|
agentscript: getCustomLanguageGrammars().agentscript
|
|
102
99
|
};
|
|
103
100
|
|
|
104
|
-
// Initialize Shiki highlighter
|
|
101
|
+
// Initialize Shiki highlighter
|
|
105
102
|
async function initializeShiki(): Promise<HighlighterCore> {
|
|
106
103
|
if (shikiInstance.highlighter) {
|
|
107
104
|
return shikiInstance.highlighter;
|
|
@@ -113,8 +110,8 @@ async function initializeShiki(): Promise<HighlighterCore> {
|
|
|
113
110
|
|
|
114
111
|
// Assign promise IMMEDIATELY before any async work to prevent race conditions
|
|
115
112
|
shikiInstance.initPromise = (async () => {
|
|
116
|
-
const
|
|
117
|
-
const highlighter = await
|
|
113
|
+
const shikiModule = await getShiki();
|
|
114
|
+
const highlighter = await shikiModule.createHighlighter({
|
|
118
115
|
themes: ["light-plus", "material-theme-darker"],
|
|
119
116
|
langs: CORE_LANGUAGES
|
|
120
117
|
});
|
|
@@ -182,12 +179,12 @@ export async function highlightCode(
|
|
|
182
179
|
mappedLanguage = "text" as BundledLanguage;
|
|
183
180
|
}
|
|
184
181
|
|
|
185
|
-
const { transformerColorizedBrackets } = await getBrackets();
|
|
182
|
+
const { transformerColorizedBrackets: transformer } = await getBrackets();
|
|
186
183
|
|
|
187
184
|
return highlighter.codeToHtml(code, {
|
|
188
185
|
lang: mappedLanguage,
|
|
189
186
|
theme: THEME_MAP[theme],
|
|
190
|
-
transformers: [
|
|
187
|
+
transformers: [transformer()],
|
|
191
188
|
colorReplacements:
|
|
192
189
|
THEME_MAP_COLOR_REPLACEMENTS[theme].colorReplacements
|
|
193
190
|
});
|