@salesforcedevs/dx-components 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lwc.config.json +1 -0
- package/package.json +3 -3
- package/src/assets/svg/sidebar-loading.svg +34 -0
- package/src/modules/dx/header/__tests__/mockProps.ts +7 -1
- package/src/modules/dx/headerSearch/__tests__/headerSearch.test.ts +24 -39
- package/src/modules/dx/headerSearch/__tests__/mockProps.ts +2 -7
- package/src/modules/dx/headerSearch/headerSearch.ts +13 -19
- package/src/modules/dx/lazy/lazy.ts +0 -7
- package/src/modules/dx/sidebar/__tests__/mockSearchChangeEmptyEvent.ts +6 -0
- package/src/modules/dx/sidebar/__tests__/mockSearchChangeEvent.ts +527 -0
- package/src/modules/dx/sidebar/__tests__/sidebar.test.ts +210 -247
- package/src/modules/dx/sidebar/sidebar.css +40 -17
- package/src/modules/dx/sidebar/sidebar.html +58 -34
- package/src/modules/dx/sidebar/sidebar.stories.ts +54 -4
- package/src/modules/dx/sidebar/sidebar.ts +141 -73
- package/src/modules/dx/sidebarOld/__tests__/mockProps.ts +178 -0
- package/src/modules/dx/sidebarOld/__tests__/sidebarOld.test.ts +574 -0
- package/src/modules/dx/sidebarOld/sidebarOld.css +158 -0
- package/src/modules/dx/sidebarOld/sidebarOld.html +70 -0
- package/src/modules/dx/sidebarOld/sidebarOld.stories.ts +139 -0
- package/src/modules/dx/sidebarOld/sidebarOld.ts +187 -0
- package/src/modules/dx/sidebarSearch/__tests__/mockPreloadedState.ts +8843 -0
- package/src/modules/dx/sidebarSearch/__tests__/sidebarSearch.test.ts +113 -0
- package/src/modules/dx/sidebarSearch/sidebarSearch.css +3 -0
- package/src/modules/dx/sidebarSearch/sidebarSearch.html +26 -0
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +421 -0
- package/src/modules/dx/sidebarSearchResult/__tests__/sidebarSearchResult.test.ts +55 -0
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.css +36 -0
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.html +14 -0
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +56 -0
- package/src/modules/dx/treeTile/__tests__/treeTile.test.ts +27 -38
- package/src/modules/dx/treeTile/treeTile.css +3 -19
- package/src/modules/dx/treeTile/treeTile.html +4 -1
- package/src/modules/dx/treeTile/treeTile.ts +2 -2
- package/src/modules/helpers/sidebar/sidebar.css +21 -0
- package/src/modules/utils/coveo/coveo.ts +69 -0
- package/src/modules/utils/highlight/__tests__/highlight.test.ts +108 -0
- package/src/modules/utils/highlight/__tests__/mockProps.ts +45 -0
- package/src/modules/utils/highlight/highlight.ts +2 -1
- package/src/modules/utils/jest/jest.ts +35 -0
- package/src/modules/utils/recentSearches/__tests__/recentSearches.test.ts +79 -0
- package/src/modules/utils/recentSearches/recentSearches.ts +57 -0
- package/src/modules/utils/tests/tests.ts +18 -11
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
--dx-c-sidebar-vertical-padding: var(--dx-g-spacing-md);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
dx-empty-state {
|
|
17
|
+
--dx-c-empty-state-background: var(--sds-g-gray-2);
|
|
18
|
+
--dx-c-empty-state-image-width: 400px;
|
|
19
|
+
|
|
20
|
+
display: none;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
dx-tree:not(:last-child) {
|
|
17
24
|
margin-bottom: var(--dx-g-spacing-sm);
|
|
18
25
|
}
|
|
@@ -57,14 +64,6 @@ dx-tree:not(:last-child) {
|
|
|
57
64
|
transition: var(--dx-g-transition-transform-2x);
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
.container.collapsed {
|
|
61
|
-
width: var(--dx-g-spacing-xl);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.collapsed .header-toggle-button {
|
|
65
|
-
transform: rotate(180deg);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
67
|
.container {
|
|
69
68
|
background-color: var(--dx-g-gray-95);
|
|
70
69
|
display: flex;
|
|
@@ -74,12 +73,12 @@ dx-tree:not(:last-child) {
|
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
.container:not(.container-mobile) {
|
|
77
|
-
--border-color:
|
|
76
|
+
--border-color: transparent;
|
|
78
77
|
--left-spacing: calc(
|
|
79
78
|
var(--dx-c-sidebar-left-padding) - var(--dx-g-spacing-md)
|
|
80
79
|
);
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
box-shadow: 2px 0 0 0 var(--border-color);
|
|
83
82
|
min-height: var(--dx-c-sidebar-min-height);
|
|
84
83
|
padding: var(--dx-c-sidebar-vertical-padding) 0
|
|
85
84
|
var(--dx-c-sidebar-vertical-padding) var(--left-spacing);
|
|
@@ -94,10 +93,6 @@ dx-tree:not(:last-child) {
|
|
|
94
93
|
--border-color: transparent;
|
|
95
94
|
}
|
|
96
95
|
|
|
97
|
-
.container:hover .header-toggle-button {
|
|
98
|
-
--dx-c-button-opacity: 1;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
96
|
.container.container-border-active {
|
|
102
97
|
--border-color: var(--dx-c-sidebar-button-color);
|
|
103
98
|
}
|
|
@@ -152,7 +147,35 @@ dx-tree:not(:last-child) {
|
|
|
152
147
|
white-space: nowrap;
|
|
153
148
|
}
|
|
154
149
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
150
|
+
.loading-skeleton {
|
|
151
|
+
margin-top: var(--dx-g-spacing-md);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.search-empty.container dx-empty-state {
|
|
155
|
+
display: block;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.user-searching.container .sidebar-content-tree {
|
|
159
|
+
display: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.show-tree.container .sidebar-content-search {
|
|
163
|
+
display: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.container.collapsed {
|
|
167
|
+
width: var(--dx-g-spacing-xl);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.container.collapsed .header-toggle-button {
|
|
171
|
+
transform: rotate(180deg);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.container.collapsed .sidebar-header,
|
|
175
|
+
.container.collapsed .sidebar-content {
|
|
176
|
+
display: none;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.container:hover .header-toggle-button {
|
|
180
|
+
--dx-c-button-opacity: 1;
|
|
158
181
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class={containerClass}>
|
|
2
|
+
<div class={containerClass} part="container">
|
|
3
3
|
<div
|
|
4
4
|
if:true={mobile}
|
|
5
5
|
class="header padding-horizontal"
|
|
@@ -27,44 +27,68 @@
|
|
|
27
27
|
onmouseenter={onToggleMouseEnter}
|
|
28
28
|
onmouseleave={onToggleMouseLeave}
|
|
29
29
|
></dx-button>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
<h2 class="dx-text-heading-4 header-title">{header}</h2>
|
|
35
|
-
<slot name="header"></slot>
|
|
36
|
-
</div>
|
|
37
|
-
<div class="search">
|
|
38
|
-
<dx-input
|
|
39
|
-
class="search-box"
|
|
40
|
-
type="search"
|
|
41
|
-
placeholder="Search this list..."
|
|
42
|
-
role="search"
|
|
43
|
-
aria-label="Content Search"
|
|
44
|
-
icon-symbol="search"
|
|
45
|
-
size="small"
|
|
46
|
-
value={searchText}
|
|
47
|
-
onchange={onSearchChange}
|
|
48
|
-
shortcut-key="j"
|
|
49
|
-
></dx-input>
|
|
50
|
-
</div>
|
|
30
|
+
<div class="sidebar-header padding-horizontal">
|
|
31
|
+
<div class="header" if:false={mobile}>
|
|
32
|
+
<h2 class="dx-text-heading-4 header-title">{header}</h2>
|
|
33
|
+
<slot name="header"></slot>
|
|
51
34
|
</div>
|
|
52
|
-
<div class="
|
|
53
|
-
<dx-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
></dx-
|
|
35
|
+
<div class="search">
|
|
36
|
+
<dx-sidebar-search
|
|
37
|
+
onchange={onSearchChange}
|
|
38
|
+
onloading={onSearchLoading}
|
|
39
|
+
coveo-organization-id={coveoOrganizationId}
|
|
40
|
+
coveo-public-access-token={coveoPublicAccessToken}
|
|
41
|
+
coveo-search-hub={coveoSearchHub}
|
|
42
|
+
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
43
|
+
></dx-sidebar-search>
|
|
61
44
|
</div>
|
|
45
|
+
<h2
|
|
46
|
+
class="results-heading dx-text-heading-6"
|
|
47
|
+
if:true={showResultsHeading}
|
|
48
|
+
>
|
|
49
|
+
Results
|
|
50
|
+
</h2>
|
|
51
|
+
</div>
|
|
52
|
+
<div
|
|
53
|
+
class="sidebar-content sidebar-content-search"
|
|
54
|
+
onscroll={onSidebarSearchContentScroll}
|
|
55
|
+
>
|
|
56
|
+
<img
|
|
57
|
+
if:true={isSearchLoading}
|
|
58
|
+
class="loading-skeleton padding-horizontal"
|
|
59
|
+
src="/assets/svg/sidebar-loading.svg"
|
|
60
|
+
alt="loading"
|
|
61
|
+
/>
|
|
62
|
+
<template
|
|
63
|
+
if:true={showSearchResults}
|
|
64
|
+
for:each={searchResults}
|
|
65
|
+
for:item="result"
|
|
66
|
+
>
|
|
67
|
+
<dx-sidebar-search-result
|
|
68
|
+
description-highlights={result.excerptHighlights}
|
|
69
|
+
description={result.excerpt}
|
|
70
|
+
href={result.href}
|
|
71
|
+
key={result.uniqueId}
|
|
72
|
+
selected={result.selected}
|
|
73
|
+
title-highlights={result.titleHighlights}
|
|
74
|
+
title={result.title}
|
|
75
|
+
></dx-sidebar-search-result>
|
|
76
|
+
</template>
|
|
62
77
|
<dx-empty-state
|
|
63
78
|
class="padding-horizontal"
|
|
64
|
-
size="small"
|
|
65
79
|
title="No Results"
|
|
66
|
-
|
|
80
|
+
size="small"
|
|
67
81
|
></dx-empty-state>
|
|
68
|
-
</
|
|
82
|
+
</div>
|
|
83
|
+
<div class="sidebar-content sidebar-content-tree">
|
|
84
|
+
<dx-tree
|
|
85
|
+
for:each={trees}
|
|
86
|
+
for:item="tree"
|
|
87
|
+
key={tree.key}
|
|
88
|
+
tree-root={tree.tree}
|
|
89
|
+
onselect={onSelect}
|
|
90
|
+
value={value}
|
|
91
|
+
></dx-tree>
|
|
92
|
+
</div>
|
|
69
93
|
</div>
|
|
70
94
|
</template>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SAMPLE_TREES, SAMPLE_TREES_WITH_METHODS } from "./__tests__/mockProps";
|
|
2
|
-
|
|
3
1
|
import { html } from "lit-html";
|
|
2
|
+
import { coveoXMLDocsConfig, coveoSFDocsConfig } from "../../utils/coveo/coveo";
|
|
3
|
+
import { SAMPLE_TREES, SAMPLE_TREES_WITH_METHODS } from "./__tests__/mockProps";
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
title: "dx/dx-sidebar",
|
|
@@ -33,18 +33,48 @@ const styles = (addStyles: string = "") => html`
|
|
|
33
33
|
${addStyles}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
dx-sidebar::part(container) {
|
|
37
|
+
height: 100vh;
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
body.sb-main-padded.sb-show-main {
|
|
37
41
|
padding: 0;
|
|
38
42
|
}
|
|
43
|
+
|
|
44
|
+
#root-inner {
|
|
45
|
+
display: flex;
|
|
46
|
+
height: 100%;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
doc-content {
|
|
50
|
+
padding: 20px;
|
|
51
|
+
}
|
|
39
52
|
</style>
|
|
40
53
|
`;
|
|
41
54
|
|
|
42
|
-
export const
|
|
43
|
-
${styles("--dx-c-sidebar-min-height:
|
|
55
|
+
export const XMLDocs = (args: any) => html`
|
|
56
|
+
${styles("--dx-c-sidebar-min-height: 100%;")}
|
|
57
|
+
|
|
58
|
+
<dx-sidebar
|
|
59
|
+
header="${args.header}"
|
|
60
|
+
trees="${JSON.stringify(args.trees)}"
|
|
61
|
+
coveo-organization-id="${coveoXMLDocsConfig.coveoOrganizationId}"
|
|
62
|
+
coveo-public-access-token="${coveoXMLDocsConfig.coveoPublicAccessToken}"
|
|
63
|
+
coveo-search-hub="${coveoXMLDocsConfig.coveoSearchHub}"
|
|
64
|
+
coveo-advanced-query-config="${coveoXMLDocsConfig.coveoAdvancedQueryConfig}"
|
|
65
|
+
></dx-sidebar>
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
export const SFDocs = (args: any) => html`
|
|
69
|
+
${styles("--dx-c-sidebar-min-height: 100%;")}
|
|
44
70
|
|
|
45
71
|
<dx-sidebar
|
|
46
72
|
header="${args.header}"
|
|
47
73
|
trees="${JSON.stringify(args.trees)}"
|
|
74
|
+
coveo-organization-id="${coveoSFDocsConfig.coveoOrganizationId}"
|
|
75
|
+
coveo-public-access-token="${coveoSFDocsConfig.coveoPublicAccessToken}"
|
|
76
|
+
coveo-search-hub="${coveoSFDocsConfig.coveoSearchHub}"
|
|
77
|
+
coveo-advanced-query-config="${coveoSFDocsConfig.coveoAdvancedQueryConfig}"
|
|
48
78
|
></dx-sidebar>
|
|
49
79
|
`;
|
|
50
80
|
|
|
@@ -58,6 +88,10 @@ export const WidthAndMinHeightVariables = (args: any) => html`
|
|
|
58
88
|
<dx-sidebar
|
|
59
89
|
header="${args.header}"
|
|
60
90
|
trees="${JSON.stringify(args.trees)}"
|
|
91
|
+
coveo-organization-id="${coveoXMLDocsConfig.coveoOrganizationId}"
|
|
92
|
+
coveo-public-access-token="${coveoXMLDocsConfig.coveoPublicAccessToken}"
|
|
93
|
+
coveo-search-hub="${coveoXMLDocsConfig.coveoSearchHub}"
|
|
94
|
+
coveo-advanced-query-config="${coveoXMLDocsConfig.coveoAdvancedQueryConfig}"
|
|
61
95
|
></dx-sidebar>
|
|
62
96
|
`;
|
|
63
97
|
|
|
@@ -80,6 +114,10 @@ export const WidthDrivenByContainer = (args: any) => html`
|
|
|
80
114
|
header="${args.header}"
|
|
81
115
|
trees="${JSON.stringify(args.trees)}"
|
|
82
116
|
value="${args.value}"
|
|
117
|
+
coveo-organization-id="${coveoXMLDocsConfig.coveoOrganizationId}"
|
|
118
|
+
coveo-public-access-token="${coveoXMLDocsConfig.coveoPublicAccessToken}"
|
|
119
|
+
coveo-search-hub="${coveoXMLDocsConfig.coveoSearchHub}"
|
|
120
|
+
coveo-advanced-query-config="${coveoXMLDocsConfig.coveoAdvancedQueryConfig}"
|
|
83
121
|
></dx-sidebar>
|
|
84
122
|
</div>
|
|
85
123
|
`;
|
|
@@ -92,6 +130,10 @@ export const WithBadges = (args: any) => html`
|
|
|
92
130
|
header="${args.header}"
|
|
93
131
|
trees="${JSON.stringify(SAMPLE_TREES_WITH_METHODS)}"
|
|
94
132
|
value="${args.value}"
|
|
133
|
+
coveo-organization-id="${coveoXMLDocsConfig.coveoOrganizationId}"
|
|
134
|
+
coveo-public-access-token="${coveoXMLDocsConfig.coveoPublicAccessToken}"
|
|
135
|
+
coveo-search-hub="${coveoXMLDocsConfig.coveoSearchHub}"
|
|
136
|
+
coveo-advanced-query-config="${coveoXMLDocsConfig.coveoAdvancedQueryConfig}"
|
|
95
137
|
></dx-sidebar>
|
|
96
138
|
</div>
|
|
97
139
|
`;
|
|
@@ -109,6 +151,10 @@ export const PositionSticky = ({ header, trees, value }: any) => html`
|
|
|
109
151
|
header="${header}"
|
|
110
152
|
trees="${JSON.stringify(trees)}"
|
|
111
153
|
value="${value}"
|
|
154
|
+
coveo-organization-id="${coveoXMLDocsConfig.coveoOrganizationId}"
|
|
155
|
+
coveo-public-access-token="${coveoXMLDocsConfig.coveoPublicAccessToken}"
|
|
156
|
+
coveo-search-hub="${coveoXMLDocsConfig.coveoSearchHub}"
|
|
157
|
+
coveo-advanced-query-config="${coveoXMLDocsConfig.coveoAdvancedQueryConfig}"
|
|
112
158
|
></dx-sidebar>
|
|
113
159
|
`;
|
|
114
160
|
|
|
@@ -133,6 +179,10 @@ export const UseSlot = ({ header, trees, value }: any) => html`
|
|
|
133
179
|
header="${header}"
|
|
134
180
|
trees="${JSON.stringify(trees)}"
|
|
135
181
|
value="${value}"
|
|
182
|
+
coveo-organization-id="${coveoXMLDocsConfig.coveoOrganizationId}"
|
|
183
|
+
coveo-public-access-token="${coveoXMLDocsConfig.coveoPublicAccessToken}"
|
|
184
|
+
coveo-search-hub="${coveoXMLDocsConfig.coveoSearchHub}"
|
|
185
|
+
coveo-advanced-query-config="${coveoXMLDocsConfig.coveoAdvancedQueryConfig}"
|
|
136
186
|
>
|
|
137
187
|
<span slot="header">I'm in the sidebar</span>
|
|
138
188
|
</dx-sidebar>
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import cx from "classnames";
|
|
2
|
-
import { track } from "dx/instrumentation";
|
|
3
|
-
import { LightningElement, api } from "lwc";
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { track as trackAnalytics } from "dx/instrumentation";
|
|
3
|
+
import { LightningElement, api, track } from "lwc";
|
|
4
|
+
import {
|
|
5
|
+
TreeNode,
|
|
6
|
+
SidebarGtmAction,
|
|
7
|
+
SidebarSearchResult
|
|
8
|
+
} from "typings/custom";
|
|
9
|
+
import { getSidebarSearchParams } from "utils/coveo";
|
|
6
10
|
import { toJson } from "utils/normalizers";
|
|
11
|
+
import SidebarSearch from "dx/sidebarSearch";
|
|
7
12
|
|
|
8
|
-
const WAIT_TIME = 500;
|
|
9
13
|
const MOBILE_SIZE_MATCH = "768px";
|
|
10
14
|
const TOGGLE_BUTTON_LABEL = "Toggle Sidebar";
|
|
11
15
|
|
|
12
16
|
export default class Sidebar extends LightningElement {
|
|
17
|
+
@api coveoOrganizationId!: string;
|
|
18
|
+
@api coveoPublicAccessToken!: string;
|
|
19
|
+
@api coveoSearchHub!: string;
|
|
20
|
+
@api coveoAdvancedQueryConfig!: string;
|
|
13
21
|
@api header: string = "";
|
|
14
22
|
|
|
15
23
|
@api
|
|
@@ -27,38 +35,94 @@ export default class Sidebar extends LightningElement {
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
set trees(value: string | Array<TreeNode>) {
|
|
30
|
-
let parsedValue = toJson(value);
|
|
38
|
+
let parsedValue = toJson(value) || [];
|
|
31
39
|
if (parsedValue && !Array.isArray(parsedValue)) {
|
|
32
40
|
parsedValue = [parsedValue];
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
parsedValue.forEach((tree: TreeNode) => this.assignValueToLabel(tree));
|
|
44
|
+
|
|
45
|
+
this._trees = parsedValue.map((tree: TreeNode) => ({
|
|
46
|
+
key: this.makeKey(),
|
|
47
|
+
tree
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
@api
|
|
52
|
+
setInputValue(searchTerm: string) {
|
|
53
|
+
(
|
|
54
|
+
this.template.querySelector(
|
|
55
|
+
"dx-sidebar-search"
|
|
56
|
+
) as unknown as SidebarSearch
|
|
57
|
+
)?.setInputValue(searchTerm);
|
|
39
58
|
}
|
|
40
59
|
|
|
41
60
|
private expanded: boolean = true;
|
|
42
61
|
private _toggleHovered: boolean = false;
|
|
43
|
-
private _searchTimeout?: number;
|
|
44
62
|
private _value?: string = undefined;
|
|
63
|
+
|
|
64
|
+
@track
|
|
45
65
|
private _trees!: Array<TreeNode>;
|
|
46
66
|
|
|
47
|
-
private filteredTrees: Array<{ key: string; tree: TreeNode }> = [];
|
|
48
67
|
private mobile: boolean = true;
|
|
49
|
-
private searchText: string = "";
|
|
50
68
|
private matchMedia!: MediaQueryList;
|
|
51
69
|
private valueToLabel: { [key: string]: string } = {};
|
|
52
70
|
|
|
53
|
-
private
|
|
54
|
-
|
|
71
|
+
private isSearchLoading: boolean = false;
|
|
72
|
+
private searchValue: string | null = null;
|
|
73
|
+
private searchResults: SidebarSearchResult[] = [];
|
|
74
|
+
private scrollToSelectedSearchResult: boolean = false;
|
|
75
|
+
private selectedSearchResultIndex: number = -1;
|
|
76
|
+
private requestedFetchMoreResults: boolean = false;
|
|
77
|
+
|
|
78
|
+
private get areResultsEmpty(): boolean {
|
|
79
|
+
return (
|
|
80
|
+
(!this.searchResults ||
|
|
81
|
+
(this.searchResults && this.searchResults.length < 1)) &&
|
|
82
|
+
!this.isSearchLoading
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private get isSearchEmpty(): boolean {
|
|
87
|
+
return this.isUserSearching && this.areResultsEmpty;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private get showResultsHeading(): boolean {
|
|
91
|
+
return this.isUserSearching && !this.areResultsEmpty;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private get isUserSearching(): boolean {
|
|
95
|
+
return !!this.searchValue || this.isSearchLoading;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private get showSearchResults(): boolean {
|
|
99
|
+
return (
|
|
100
|
+
!!this.searchValue && !this.isSearchLoading && !this.areResultsEmpty
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private get isNearBottomOfSearchResults(): boolean {
|
|
105
|
+
const scrollArea = this.template.querySelector(
|
|
106
|
+
".sidebar-content-search"
|
|
107
|
+
);
|
|
108
|
+
if (!scrollArea) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const { scrollHeight, scrollTop } = scrollArea;
|
|
113
|
+
const { height } = scrollArea?.getBoundingClientRect();
|
|
114
|
+
|
|
115
|
+
return scrollHeight - scrollTop - height < 300;
|
|
55
116
|
}
|
|
56
117
|
|
|
57
118
|
private get containerClass() {
|
|
58
119
|
return cx("container", {
|
|
59
120
|
collapsed: !this.expanded,
|
|
60
121
|
"container-border-active": this._toggleHovered,
|
|
61
|
-
"container-mobile": this.mobile
|
|
122
|
+
"container-mobile": this.mobile,
|
|
123
|
+
"user-searching": this.isUserSearching,
|
|
124
|
+
"show-tree": !this.isUserSearching,
|
|
125
|
+
"search-empty": this.isSearchEmpty
|
|
62
126
|
});
|
|
63
127
|
}
|
|
64
128
|
|
|
@@ -70,6 +134,19 @@ export default class Sidebar extends LightningElement {
|
|
|
70
134
|
);
|
|
71
135
|
}
|
|
72
136
|
|
|
137
|
+
constructor() {
|
|
138
|
+
super();
|
|
139
|
+
|
|
140
|
+
if (getSidebarSearchParams()) {
|
|
141
|
+
this.isSearchLoading = true;
|
|
142
|
+
this.scrollToSelectedSearchResult = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
renderedCallback() {
|
|
147
|
+
this.initializeSearchScrollPosition();
|
|
148
|
+
}
|
|
149
|
+
|
|
73
150
|
connectedCallback() {
|
|
74
151
|
this.matchMedia = window.matchMedia(
|
|
75
152
|
`(max-width: ${MOBILE_SIZE_MATCH})`
|
|
@@ -97,7 +174,7 @@ export default class Sidebar extends LightningElement {
|
|
|
97
174
|
const sideNavAction: SidebarGtmAction = this.expanded
|
|
98
175
|
? "expand"
|
|
99
176
|
: "collapse";
|
|
100
|
-
|
|
177
|
+
trackAnalytics(event.currentTarget!, "custEv_leftNavLinkClick", {
|
|
101
178
|
sideNavAction,
|
|
102
179
|
clickText: TOGGLE_BUTTON_LABEL
|
|
103
180
|
});
|
|
@@ -111,71 +188,62 @@ export default class Sidebar extends LightningElement {
|
|
|
111
188
|
this._toggleHovered = false;
|
|
112
189
|
}
|
|
113
190
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* function is being called to avoid running the recursivity logic very often.
|
|
117
|
-
**/
|
|
118
|
-
private onSearchChange(event: CustomEvent) {
|
|
119
|
-
this.searchText = event.detail;
|
|
120
|
-
window.clearTimeout(this._searchTimeout);
|
|
121
|
-
this._searchTimeout = window.setTimeout(() => {
|
|
122
|
-
this.assignFilteredTrees();
|
|
123
|
-
this.dispatchEvent(
|
|
124
|
-
new CustomEvent("highlightedtermchange", {
|
|
125
|
-
detail: this.searchText,
|
|
126
|
-
composed: true,
|
|
127
|
-
bubbles: true
|
|
128
|
-
})
|
|
129
|
-
);
|
|
130
|
-
}, WAIT_TIME);
|
|
191
|
+
private makeKey(): string {
|
|
192
|
+
return Math.random().toString(36).substring(7);
|
|
131
193
|
}
|
|
132
194
|
|
|
133
|
-
private
|
|
134
|
-
this.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
key: this.makeKey(),
|
|
138
|
-
tree: this.searchText
|
|
139
|
-
? this.findMatch(
|
|
140
|
-
new RegExp(this.searchText.toLowerCase().trim()),
|
|
141
|
-
singleTree
|
|
142
|
-
)!
|
|
143
|
-
: singleTree
|
|
144
|
-
};
|
|
145
|
-
})
|
|
146
|
-
.filter((filteredTree) => filteredTree.tree);
|
|
195
|
+
private onSearchChange(e: CustomEvent) {
|
|
196
|
+
this.requestedFetchMoreResults = false;
|
|
197
|
+
this.searchResults = e.detail.results;
|
|
198
|
+
this.searchValue = e.detail.value;
|
|
147
199
|
}
|
|
148
200
|
|
|
149
|
-
private
|
|
150
|
-
|
|
201
|
+
private onSearchLoading(e: CustomEvent) {
|
|
202
|
+
if (!e.detail.loading && this.scrollToSelectedSearchResult) {
|
|
203
|
+
this.selectedSearchResultIndex = this.searchResults.findIndex(
|
|
204
|
+
(r) => r.selected
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
this.isSearchLoading = e.detail;
|
|
151
208
|
}
|
|
152
209
|
|
|
153
|
-
private
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
): TreeNode | undefined {
|
|
157
|
-
if (valuePattern.test(node.label.toLowerCase())) {
|
|
158
|
-
return { ...node, isExpanded: true };
|
|
210
|
+
private onSidebarSearchContentScroll() {
|
|
211
|
+
if (this.isSearchLoading) {
|
|
212
|
+
return;
|
|
159
213
|
}
|
|
160
214
|
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
215
|
+
const search = this.template.querySelector(
|
|
216
|
+
"dx-sidebar-search"
|
|
217
|
+
) as unknown as SidebarSearch;
|
|
218
|
+
|
|
219
|
+
if (
|
|
220
|
+
this.isNearBottomOfSearchResults &&
|
|
221
|
+
search &&
|
|
222
|
+
!this.requestedFetchMoreResults
|
|
223
|
+
) {
|
|
224
|
+
this.requestedFetchMoreResults = true;
|
|
225
|
+
search.fetchMoreResults();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private initializeSearchScrollPosition() {
|
|
230
|
+
if (
|
|
231
|
+
this.scrollToSelectedSearchResult &&
|
|
232
|
+
this.selectedSearchResultIndex >= 0
|
|
233
|
+
) {
|
|
234
|
+
const selectedResult = this.template.querySelector(
|
|
235
|
+
`dx-sidebar-search-result:nth-child(${
|
|
236
|
+
this.selectedSearchResultIndex + 1
|
|
237
|
+
})`
|
|
238
|
+
);
|
|
239
|
+
if (!selectedResult || !selectedResult.parentNode) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
(selectedResult.parentNode as HTMLElement).scrollTop =
|
|
243
|
+
selectedResult.offsetTop -
|
|
244
|
+
(selectedResult.parentNode as HTMLElement).offsetTop;
|
|
245
|
+
this.scrollToSelectedSearchResult = false;
|
|
246
|
+
}
|
|
179
247
|
}
|
|
180
248
|
|
|
181
249
|
private assignValueToLabel(node: TreeNode): void {
|