@salesforcedevs/dx-components 1.32.0-alpha.1 → 1.32.0-alpha.11
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/package.json +2 -2
- package/src/modules/dx/searchResults/searchResults.css +5 -3
- package/src/modules/dx/searchResults/searchResults.html +3 -0
- package/src/modules/dx/searchResults/searchResults.ts +18 -0
- package/src/modules/dx/sidebar/sidebar.ts +37 -22
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +19 -1
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.css +35 -17
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/dx-components",
|
|
3
|
-
"version": "1.32.0-alpha.
|
|
3
|
+
"version": "1.32.0-alpha.11",
|
|
4
4
|
"description": "DX Lightning web components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"luxon": "3.4.4",
|
|
45
45
|
"msw": "^2.12.4"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "96c307120f036a8eed8b2b741938db9dba806953"
|
|
48
48
|
}
|
|
@@ -310,7 +310,7 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
|
|
|
310
310
|
bottom: var(--dx-result-inner-gap-y);
|
|
311
311
|
left: var(--dx-result-inner-gap-x);
|
|
312
312
|
right: var(--dx-result-inner-gap-x);
|
|
313
|
-
background: var(--dx-g-
|
|
313
|
+
background: var(--dx-g-cloud-blue-vibrant-95);
|
|
314
314
|
border-radius: var(--dx-g-spacing-xs);
|
|
315
315
|
pointer-events: none;
|
|
316
316
|
z-index: 0;
|
|
@@ -326,7 +326,7 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
|
|
|
326
326
|
outline: none;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
/* Pseudo: 8px from text
|
|
329
|
+
/* Pseudo: 8px from text; inner ring container/hover (cloud blue 95), outer blue-vibrant-20 */
|
|
330
330
|
.dx-result:focus-within::before {
|
|
331
331
|
content: "";
|
|
332
332
|
position: absolute;
|
|
@@ -334,8 +334,10 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
|
|
|
334
334
|
bottom: var(--dx-result-inner-gap-y);
|
|
335
335
|
left: var(--dx-result-inner-gap-x);
|
|
336
336
|
right: var(--dx-result-inner-gap-x);
|
|
337
|
-
border:
|
|
337
|
+
border: none;
|
|
338
338
|
border-radius: var(--dx-g-spacing-xs);
|
|
339
|
+
box-shadow: 0 0 0 2px var(--dx-g-cloud-blue-vibrant-95),
|
|
340
|
+
0 0 0 4px var(--dx-g-blue-vibrant-20);
|
|
339
341
|
pointer-events: none;
|
|
340
342
|
z-index: 2;
|
|
341
343
|
}
|
|
@@ -15,6 +15,7 @@ interface SearchResultDisplay {
|
|
|
15
15
|
href: string;
|
|
16
16
|
matchedText: string;
|
|
17
17
|
uniqueId: string;
|
|
18
|
+
resultIndex: number;
|
|
18
19
|
openInNewTab: string | undefined;
|
|
19
20
|
rel: string | undefined;
|
|
20
21
|
}
|
|
@@ -129,11 +130,28 @@ export default class SearchResults extends LightningElement {
|
|
|
129
130
|
href,
|
|
130
131
|
matchedText: item.matchedText ?? "",
|
|
131
132
|
uniqueId: href || `result-${index}`,
|
|
133
|
+
resultIndex: index + 1,
|
|
132
134
|
openInNewTab: isExternal ? "_blank" : undefined,
|
|
133
135
|
rel: isExternal ? "noopener noreferrer" : undefined
|
|
134
136
|
};
|
|
135
137
|
}
|
|
136
138
|
|
|
139
|
+
private onSearchResultClick(e: MouseEvent) {
|
|
140
|
+
const anchor = e.currentTarget as HTMLAnchorElement;
|
|
141
|
+
const index = Number(anchor.dataset.index ?? "0");
|
|
142
|
+
const title = anchor.dataset.title ?? "";
|
|
143
|
+
const href = anchor.href ?? "";
|
|
144
|
+
trackGTM(anchor, "custEv_scopedSearchlinkClick", {
|
|
145
|
+
click_text: title,
|
|
146
|
+
click_url: href,
|
|
147
|
+
element_title: title,
|
|
148
|
+
element_type: "link",
|
|
149
|
+
content_category: "documentation",
|
|
150
|
+
search_term: this.query,
|
|
151
|
+
search_result_position: index
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
137
155
|
private trackSearchResultsOnce(term: string, resultCount: number) {
|
|
138
156
|
if (this.didTrackThisSearch) {
|
|
139
157
|
return;
|
|
@@ -51,7 +51,6 @@ export default class Sidebar extends SidebarBase {
|
|
|
51
51
|
private searchValue: string | null = null;
|
|
52
52
|
private searchResults: SidebarSearchResult[] = [];
|
|
53
53
|
private scrollToSelectedSearchResult: boolean = false;
|
|
54
|
-
private selectedSearchResultIndex: number = -1;
|
|
55
54
|
private requestedFetchMoreResults: boolean = false;
|
|
56
55
|
|
|
57
56
|
private get areResultsEmpty(): boolean {
|
|
@@ -162,16 +161,18 @@ export default class Sidebar extends SidebarBase {
|
|
|
162
161
|
|
|
163
162
|
private onSearchChange(e: CustomEvent) {
|
|
164
163
|
this.requestedFetchMoreResults = false;
|
|
164
|
+
const isFirstSearchHydration = this.searchValue === null;
|
|
165
|
+
const hasSelectedResult = (e.detail.results || []).some(
|
|
166
|
+
(result: SidebarSearchResult) => !!result.selected
|
|
167
|
+
);
|
|
168
|
+
if (isFirstSearchHydration && hasSelectedResult) {
|
|
169
|
+
this.scrollToSelectedSearchResult = true;
|
|
170
|
+
}
|
|
165
171
|
this.searchResults = e.detail.results;
|
|
166
172
|
this.searchValue = e.detail.value;
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
private onSearchLoading(e: CustomEvent) {
|
|
170
|
-
if (!e.detail.loading && this.scrollToSelectedSearchResult) {
|
|
171
|
-
this.selectedSearchResultIndex = this.searchResults.findIndex(
|
|
172
|
-
(r) => r.selected
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
176
|
this.isSearchLoading = e.detail;
|
|
176
177
|
}
|
|
177
178
|
|
|
@@ -196,23 +197,37 @@ export default class Sidebar extends SidebarBase {
|
|
|
196
197
|
}
|
|
197
198
|
|
|
198
199
|
private initializeSearchScrollPosition() {
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
200
|
+
if (!this.scrollToSelectedSearchResult || this.isSearchLoading) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const selectedSearchResultIndex = this.searchResults.findIndex(
|
|
205
|
+
(r) => r.selected
|
|
206
|
+
);
|
|
207
|
+
if (selectedSearchResultIndex < 0) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const searchContent = this.template.querySelector(
|
|
212
|
+
".sidebar-content-search"
|
|
213
|
+
) as HTMLElement | null;
|
|
214
|
+
const allResultItems = searchContent?.querySelectorAll(
|
|
215
|
+
"dx-sidebar-search-result"
|
|
216
|
+
);
|
|
217
|
+
const selectedResult =
|
|
218
|
+
(allResultItems?.[selectedSearchResultIndex] as HTMLElement) ||
|
|
219
|
+
null;
|
|
220
|
+
if (!searchContent || !selectedResult) {
|
|
221
|
+
return;
|
|
215
222
|
}
|
|
223
|
+
|
|
224
|
+
window.requestAnimationFrame(() => {
|
|
225
|
+
selectedResult.scrollIntoView({
|
|
226
|
+
block: "start",
|
|
227
|
+
inline: "nearest"
|
|
228
|
+
});
|
|
229
|
+
this.scrollToSelectedSearchResult = false;
|
|
230
|
+
});
|
|
216
231
|
}
|
|
217
232
|
|
|
218
233
|
private assignValueToLabel(node: TreeNode): void {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import debounce from "debounce";
|
|
3
|
+
import { track as trackGTM } from "dxUtils/analytics";
|
|
3
4
|
import {
|
|
4
5
|
type Data360SearchCacheItem,
|
|
5
6
|
type Data360SearchResultItem,
|
|
@@ -85,6 +86,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
85
86
|
private value: string = "";
|
|
86
87
|
private didRender = false;
|
|
87
88
|
private data360SearchInitialized: boolean = false;
|
|
89
|
+
private didTrackThisSearch: boolean = false;
|
|
88
90
|
|
|
89
91
|
private get isDropdownOpen() {
|
|
90
92
|
return (
|
|
@@ -173,11 +175,13 @@ export default class SidebarSearch extends LightningElement {
|
|
|
173
175
|
|
|
174
176
|
private async fetchDataCloudSearch(): Promise<void> {
|
|
175
177
|
try {
|
|
176
|
-
const
|
|
178
|
+
const query = this.value.trim();
|
|
179
|
+
const rawResults = await fetchSearch(query);
|
|
177
180
|
const results: SidebarSearchResult[] = rawResults.map(
|
|
178
181
|
this.normalizeDataCloudResult
|
|
179
182
|
);
|
|
180
183
|
this.dispatchChange(results);
|
|
184
|
+
this.trackSearchResultsOnce(query, results.length);
|
|
181
185
|
const cacheItems: Data360SearchCacheItem[] = results.map((r) => ({
|
|
182
186
|
title: r.title,
|
|
183
187
|
titleHighlights: r.titleHighlights,
|
|
@@ -198,6 +202,19 @@ export default class SidebarSearch extends LightningElement {
|
|
|
198
202
|
}
|
|
199
203
|
}
|
|
200
204
|
|
|
205
|
+
private trackSearchResultsOnce(term: string, resultCount: number): void {
|
|
206
|
+
if (this.didTrackThisSearch || !term) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
this.didTrackThisSearch = true;
|
|
210
|
+
trackGTM(this.template.host, "custEv_scopedSearch", {
|
|
211
|
+
search_term: term,
|
|
212
|
+
search_category: "",
|
|
213
|
+
search_type: "site search",
|
|
214
|
+
search_result_count: resultCount
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
201
218
|
private dispatchChange(results: SidebarSearchResult[]) {
|
|
202
219
|
this.dispatchEvent(
|
|
203
220
|
new CustomEvent("change", {
|
|
@@ -279,6 +296,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
279
296
|
|
|
280
297
|
private handleValueChange(isSyncingSearchValue = false) {
|
|
281
298
|
if (this.value) {
|
|
299
|
+
this.didTrackThisSearch = false;
|
|
282
300
|
this.dispatchOnLoading(true);
|
|
283
301
|
this.submitSearch(isSyncingSearchValue);
|
|
284
302
|
} else {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
@import "dxHelpers/text";
|
|
3
3
|
@import "dxHelpers/commonTreeItem";
|
|
4
4
|
|
|
5
|
-
/* List item states
|
|
5
|
+
/* List item states: Default, Hover (blue-vibrant-50 text only), Selected (cloud blue bar), Focus */
|
|
6
6
|
a {
|
|
7
7
|
display: flex;
|
|
8
8
|
flex-direction: column;
|
|
@@ -10,8 +10,7 @@ a {
|
|
|
10
10
|
|
|
11
11
|
/* Match "Results" heading alignment. Less item padding so total height unchanged when box has more inner padding. */
|
|
12
12
|
.sidebar-item {
|
|
13
|
-
padding: var(--dx-g-spacing-
|
|
14
|
-
var(--dx-g-spacing-xs) var(--dx-c-sidebar-left-padding);
|
|
13
|
+
padding: 0 var(--dx-g-spacing-lg) 0 var(--dx-c-sidebar-left-padding);
|
|
15
14
|
background: transparent;
|
|
16
15
|
transition: background-color var(--dx-g-transition-hue-1x, 0.1s ease);
|
|
17
16
|
overflow: visible;
|
|
@@ -26,32 +25,51 @@ a {
|
|
|
26
25
|
transition: background-color var(--dx-g-transition-hue-1x, 0.1s ease);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
/* Hover:
|
|
30
|
-
.sidebar-item:not(.sidebar-item-selected):hover .
|
|
31
|
-
|
|
28
|
+
/* Hover: no background; text → blue-vibrant-50 (.title / .description set their own colors) */
|
|
29
|
+
.sidebar-item:not(.sidebar-item-selected):hover .title {
|
|
30
|
+
color: var(--dx-g-blue-vibrant-50);
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
.sidebar-item:not(.sidebar-item-selected):hover .description {
|
|
34
|
+
--dx-g-text-body-color: var(--dx-g-blue-vibrant-50);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Selected: full-width cloud blue bar + 4px blue-vibrant-40 left accent; text matches unselected */
|
|
35
38
|
.sidebar-item-selected {
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
background: var(--dx-g-cloud-blue-vibrant-95);
|
|
40
|
+
border-radius: 0;
|
|
41
|
+
box-shadow: inset var(--dx-g-spacing-xs) 0 0 0 var(--dx-g-blue-vibrant-40);
|
|
42
|
+
|
|
43
|
+
/* Override commonTreeItem selected text color so .title / .description tokens apply */
|
|
44
|
+
color: unset !important;
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
.sidebar-item-selected .search-result {
|
|
41
|
-
|
|
48
|
+
position: relative;
|
|
49
|
+
z-index: 1;
|
|
50
|
+
background: transparent;
|
|
42
51
|
color: inherit;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
/* Focus:
|
|
54
|
+
/* Focus: same ring for selected and unselected (inner .search-result, not full-width bar) */
|
|
46
55
|
.sidebar-item:focus-visible {
|
|
47
56
|
outline: none !important;
|
|
48
57
|
}
|
|
49
58
|
|
|
59
|
+
/* Override commonTreeItem selected:focus padding/outline so focus matches unselected */
|
|
60
|
+
.sidebar-item-selected:focus-visible {
|
|
61
|
+
padding-top: 0;
|
|
62
|
+
padding-bottom: 0;
|
|
63
|
+
outline: none !important;
|
|
64
|
+
}
|
|
65
|
+
|
|
50
66
|
.sidebar-item:focus-visible .search-result {
|
|
51
|
-
outline:
|
|
52
|
-
outline-offset: 0;
|
|
67
|
+
outline: none;
|
|
53
68
|
border-radius: var(--dx-g-spacing-xs);
|
|
54
69
|
border: none;
|
|
70
|
+
|
|
71
|
+
/* White inner ring reads clearly on selected (cloud 95) and hover backgrounds */
|
|
72
|
+
box-shadow: 0 0 0 2px white, 0 0 0 4px var(--dx-g-blue-vibrant-60);
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
.search-text {
|
|
@@ -63,6 +81,7 @@ a {
|
|
|
63
81
|
}
|
|
64
82
|
|
|
65
83
|
.description {
|
|
84
|
+
line-clamp: 3;
|
|
66
85
|
-webkit-line-clamp: 3;
|
|
67
86
|
overflow-wrap: break-word;
|
|
68
87
|
|
|
@@ -74,6 +93,9 @@ a {
|
|
|
74
93
|
|
|
75
94
|
.title {
|
|
76
95
|
color: var(--dx-g-text-heading-color);
|
|
96
|
+
line-height: 18px;
|
|
97
|
+
display: block;
|
|
98
|
+
margin-bottom: 4px;
|
|
77
99
|
}
|
|
78
100
|
|
|
79
101
|
/* Match full-doc search highlight: light yellow from dx-css-variables */
|
|
@@ -81,7 +103,3 @@ a {
|
|
|
81
103
|
background-color: var(--dx-g-yellow-vibrant-90);
|
|
82
104
|
font-weight: 700;
|
|
83
105
|
}
|
|
84
|
-
|
|
85
|
-
a > *:not(:last-child) {
|
|
86
|
-
margin-bottom: var(--dx-g-spacing-xs);
|
|
87
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import cx from "classnames";
|
|
3
|
+
import { track } from "dxUtils/analytics";
|
|
3
4
|
import { HighlightedSections } from "typings/custom";
|
|
4
5
|
|
|
5
6
|
const toChunks = (value: string, highlights: HighlightedSections) => {
|
|
@@ -72,6 +73,13 @@ export default class SidebarSearchResult extends LightningElement {
|
|
|
72
73
|
|
|
73
74
|
private onClick(e: PointerEvent) {
|
|
74
75
|
e.preventDefault();
|
|
76
|
+
track(e.currentTarget!, "custEv_scopedSearchItemSelected", {
|
|
77
|
+
click_text: this.header,
|
|
78
|
+
click_url: this.href,
|
|
79
|
+
element_title: this.header,
|
|
80
|
+
element_type: "link",
|
|
81
|
+
content_category: "documentation"
|
|
82
|
+
});
|
|
75
83
|
this.select();
|
|
76
84
|
window.location.href = this.href;
|
|
77
85
|
}
|