@salesforcedevs/dx-components 0.10.0 → 0.10.1-alpha.100
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 +3 -3
- package/package.json +3 -4
- package/src/.DS_Store +0 -0
- package/src/assets/svg/docs-empty-state-small.svg +72 -0
- package/src/assets/svg/sidebar-loading.svg +34 -0
- package/src/modules/.DS_Store +0 -0
- package/src/modules/dx/.DS_Store +0 -0
- package/src/modules/dx/cardGrid/__tests__/cardMockProps.ts +78 -148
- package/src/modules/dx/cardGrid/cardGrid.css +0 -32
- package/src/modules/dx/cardGrid/cardGrid.html +5 -11
- package/src/modules/dx/codeBlock/__tests__/codeBlock.test.ts +47 -5
- package/src/modules/dx/codeBlock/codeBlock.stories.ts +2 -69
- package/src/modules/dx/codeBlock/codeBlock.ts +43 -22
- package/src/modules/dx/codeBlock/darkTheme.css +0 -1
- package/src/modules/dx/codeBlock/lightTheme.css +0 -1
- package/src/modules/dx/emptyState/__tests__/emptyState.test.ts +29 -10
- package/src/modules/dx/emptyState/__tests__/mockProps.ts +1 -3
- package/src/modules/dx/emptyState/emptyState.css +45 -13
- package/src/modules/dx/emptyState/emptyState.html +6 -4
- package/src/modules/dx/emptyState/emptyState.stories.ts +18 -38
- package/src/modules/dx/emptyState/emptyState.ts +11 -20
- package/src/modules/dx/footer/links.ts +3 -5
- package/src/modules/dx/header/__tests__/mockProps.ts +7 -1
- package/src/modules/dx/headerNav/__tests__/headerNav.test.ts +2 -4
- package/src/modules/dx/headerNav/headerNav.html +8 -6
- package/src/modules/dx/headerNav/headerNav.ts +2 -2
- package/src/modules/dx/headerSearch/headerSearch.html +2 -4
- package/src/modules/dx/headerSearch/headerSearch.ts +19 -25
- package/src/modules/dx/newsletterForm/newsletterForm.html +5 -3
- package/src/modules/dx/popover/popover.ts +11 -7
- package/src/modules/dx/searchResults/coveo.css +314 -111
- package/src/modules/dx/sidebar/__tests__/sidebar.test.ts +0 -70
- package/src/modules/dx/sidebar/sidebar.css +42 -23
- package/src/modules/dx/sidebar/sidebar.html +62 -40
- package/src/modules/dx/sidebar/sidebar.stories.ts +54 -4
- package/src/modules/dx/sidebar/sidebar.ts +126 -66
- package/src/modules/dx/sidebarSearch/__tests__/preloadedState.ts +3459 -0
- package/src/modules/dx/sidebarSearch/__tests__/sidebarSearch.test.ts +44 -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 +358 -0
- package/src/modules/dx/sidebarSearch/utils.ts +2 -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/spinner/__tests__/spinner.test.ts +37 -0
- package/src/modules/dx/spinner/spinner.css +750 -0
- package/src/modules/dx/spinner/spinner.html +6 -0
- package/src/modules/dx/spinner/spinner.stories.ts +69 -0
- package/src/modules/dx/spinner/spinner.ts +20 -0
- package/src/modules/dx/tab/__tests__/tab.test.ts +112 -54
- package/src/modules/dx/tab/tab.css +91 -16
- package/src/modules/dx/tab/tab.html +10 -12
- package/src/modules/dx/tab/tab.stories.ts +57 -0
- package/src/modules/dx/tab/tab.ts +35 -28
- package/src/modules/dx/tooltip/tippy.css +1 -0
- package/src/modules/dx/treeTile/__tests__/treeTile.test.ts +1 -1
- 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/helpers/table/table.css +23 -7
- package/src/modules/utils/coveo/coveo.ts +60 -0
- package/src/modules/utils/highlight/highlight.ts +31 -0
- package/src/modules/utils/normalizers/normalizers.ts +3 -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/regexps/regexps.ts +5 -0
- package/LICENSE +0 -12
- package/src/modules/dx/headerNavOption/__tests__/headerNavOption.test.ts +0 -113
- package/src/modules/dx/headerNavOption/headerNavOption.css +0 -91
- package/src/modules/dx/headerNavOption/headerNavOption.html +0 -9
- package/src/modules/dx/headerNavOption/headerNavOption.ts +0 -31
- package/src/modules/dx/headerSearch/__tests__/mockProps.ts +0 -11
- package/src/modules/dx/tab/__tests__/mockProps.ts +0 -4
- package/src/modules/dx/tabPanel/__tests__/mockProps.ts +0 -4
- package/src/modules/dx/tabPanel/__tests__/tabPanel.test.ts +0 -46
- package/src/modules/dx/tabPanel/tabPanel.css +0 -9
- package/src/modules/dx/tabPanel/tabPanel.html +0 -13
- package/src/modules/dx/tabPanel/tabPanel.ts +0 -27
- package/src/modules/dx/tabs/__tests__/mockProps.ts +0 -3
- package/src/modules/dx/tabs/__tests__/tabs.test.ts +0 -47
- package/src/modules/dx/tabs/tabs.css +0 -7
- package/src/modules/dx/tabs/tabs.html +0 -21
- package/src/modules/dx/tabs/tabs.stories.ts +0 -74
- package/src/modules/dx/tabs/tabs.ts +0 -112
- package/src/modules/dx/tabs/uniqueId.ts +0 -6
|
@@ -3,7 +3,6 @@ import Input from "dx/input";
|
|
|
3
3
|
import { track } from "dx/instrumentation";
|
|
4
4
|
import Sidebar from "dx/sidebar";
|
|
5
5
|
import Tree from "dx/tree";
|
|
6
|
-
import { TreeNode } from "typings/custom";
|
|
7
6
|
import { createMediaMock } from "utils/jest";
|
|
8
7
|
import { createRenderComponent } from "utils/tests";
|
|
9
8
|
import { SAMPLE_TREES } from "./mockProps";
|
|
@@ -536,74 +535,5 @@ describe(TAG, () => {
|
|
|
536
535
|
});
|
|
537
536
|
});
|
|
538
537
|
});
|
|
539
|
-
|
|
540
|
-
describe("search", () => {
|
|
541
|
-
beforeAll(() => {
|
|
542
|
-
jest.useFakeTimers();
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
it("should filter trees element label based on the search text value", () => {
|
|
546
|
-
const testSearchText = " token ";
|
|
547
|
-
const component = renderComponent({
|
|
548
|
-
header: "Cool Title",
|
|
549
|
-
trees: SAMPLE_TREES
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
const searchBox: Input = component.shadowRoot.querySelector(
|
|
553
|
-
"dx-input"
|
|
554
|
-
);
|
|
555
|
-
searchBox.dispatchEvent(
|
|
556
|
-
new CustomEvent("change", {
|
|
557
|
-
detail: testSearchText
|
|
558
|
-
})
|
|
559
|
-
);
|
|
560
|
-
|
|
561
|
-
jest.runAllTimers();
|
|
562
|
-
|
|
563
|
-
return Promise.resolve().then(() => {
|
|
564
|
-
expect(searchBox.value).toBe(testSearchText);
|
|
565
|
-
|
|
566
|
-
const trees: Array<Tree> = component.shadowRoot.querySelectorAll(
|
|
567
|
-
"dx-tree"
|
|
568
|
-
);
|
|
569
|
-
expect(trees).toHaveLength(1);
|
|
570
|
-
const treeNode = trees[0].treeRoot as TreeNode;
|
|
571
|
-
expect(treeNode.name).toBe(SAMPLE_TREES[0].name);
|
|
572
|
-
expect(treeNode.isExpanded).toBe(true);
|
|
573
|
-
expect(treeNode.children).toHaveLength(1);
|
|
574
|
-
expect(treeNode.children![0].name).toMatch(
|
|
575
|
-
testSearchText.trim()
|
|
576
|
-
);
|
|
577
|
-
});
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
it("should not display anything if search text does not match", () => {
|
|
581
|
-
const testSearchText = "this does not exist";
|
|
582
|
-
const component = renderComponent({
|
|
583
|
-
header: "Cool Title",
|
|
584
|
-
trees: SAMPLE_TREES
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
const searchBox: Input = component.shadowRoot.querySelector(
|
|
588
|
-
"dx-input"
|
|
589
|
-
);
|
|
590
|
-
searchBox.dispatchEvent(
|
|
591
|
-
new CustomEvent("change", {
|
|
592
|
-
detail: testSearchText
|
|
593
|
-
})
|
|
594
|
-
);
|
|
595
|
-
|
|
596
|
-
jest.runAllTimers();
|
|
597
|
-
|
|
598
|
-
return Promise.resolve().then(() => {
|
|
599
|
-
expect(searchBox.value).toBe(testSearchText);
|
|
600
|
-
|
|
601
|
-
const tree: Tree = component.shadowRoot.querySelector(
|
|
602
|
-
"dx-tree"
|
|
603
|
-
);
|
|
604
|
-
expect(tree).toBeNull();
|
|
605
|
-
});
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
538
|
});
|
|
609
539
|
});
|
|
@@ -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
|
}
|
|
@@ -146,17 +141,41 @@ dx-tree:not(:last-child) {
|
|
|
146
141
|
--dx-c-input-width: 100%;
|
|
147
142
|
}
|
|
148
143
|
|
|
149
|
-
.no-result {
|
|
150
|
-
flex-grow: 1;
|
|
151
|
-
display: flex;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.no-result dx-empty-state {
|
|
155
|
-
margin: auto;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
144
|
.truncate {
|
|
159
145
|
overflow: hidden;
|
|
160
146
|
text-overflow: ellipsis;
|
|
161
147
|
white-space: nowrap;
|
|
162
148
|
}
|
|
149
|
+
|
|
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;
|
|
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,46 +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>
|
|
51
|
-
</div>
|
|
52
|
-
<div class="sidebar-content" if:true={anyResultMatch}>
|
|
53
|
-
<dx-tree
|
|
54
|
-
for:each={filteredTrees}
|
|
55
|
-
for:item="tree"
|
|
56
|
-
key={tree.key}
|
|
57
|
-
tree-root={tree.tree}
|
|
58
|
-
onselect={onSelect}
|
|
59
|
-
value={value}
|
|
60
|
-
></dx-tree>
|
|
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>
|
|
61
34
|
</div>
|
|
62
|
-
<div class="
|
|
63
|
-
<dx-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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>
|
|
69
44
|
</div>
|
|
70
|
-
|
|
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>
|
|
77
|
+
<dx-empty-state
|
|
78
|
+
class="padding-horizontal"
|
|
79
|
+
title="No Results"
|
|
80
|
+
size="small"
|
|
81
|
+
></dx-empty-state>
|
|
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>
|
|
71
93
|
</div>
|
|
72
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,19 @@
|
|
|
1
1
|
import cx from "classnames";
|
|
2
|
-
import { track } from "dx/instrumentation";
|
|
3
|
-
import { LightningElement, api } from "lwc";
|
|
4
|
-
|
|
2
|
+
import { track as trackAnalytics } from "dx/instrumentation";
|
|
3
|
+
import { LightningElement, api, track } from "lwc";
|
|
4
|
+
import { Result } from "@coveo/headless";
|
|
5
5
|
import { TreeNode, SidebarGtmAction } from "typings/custom";
|
|
6
|
+
import { getSidebarSearchParams } from "utils/coveo";
|
|
6
7
|
import { toJson } from "utils/normalizers";
|
|
7
8
|
|
|
8
|
-
const WAIT_TIME = 500;
|
|
9
9
|
const MOBILE_SIZE_MATCH = "768px";
|
|
10
10
|
const TOGGLE_BUTTON_LABEL = "Toggle Sidebar";
|
|
11
11
|
|
|
12
12
|
export default class Sidebar extends LightningElement {
|
|
13
|
+
@api coveoOrganizationId!: string;
|
|
14
|
+
@api coveoPublicAccessToken!: string;
|
|
15
|
+
@api coveoSearchHub!: string;
|
|
16
|
+
@api coveoAdvancedQueryConfig!: string;
|
|
13
17
|
@api header: string = "";
|
|
14
18
|
|
|
15
19
|
@api
|
|
@@ -27,38 +31,85 @@ export default class Sidebar extends LightningElement {
|
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
set trees(value: string | Array<TreeNode>) {
|
|
30
|
-
let parsedValue = toJson(value);
|
|
34
|
+
let parsedValue = toJson(value) || [];
|
|
31
35
|
if (parsedValue && !Array.isArray(parsedValue)) {
|
|
32
36
|
parsedValue = [parsedValue];
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
parsedValue.forEach((tree: TreeNode) => this.assignValueToLabel(tree));
|
|
36
40
|
|
|
37
|
-
this._trees.
|
|
38
|
-
|
|
41
|
+
this._trees = parsedValue.map((tree: TreeNode) => ({
|
|
42
|
+
key: this.makeKey(),
|
|
43
|
+
tree
|
|
44
|
+
}));
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
private expanded: boolean = true;
|
|
42
48
|
private _toggleHovered: boolean = false;
|
|
43
|
-
private _searchTimeout?: number;
|
|
44
49
|
private _value?: string = undefined;
|
|
50
|
+
|
|
51
|
+
@track
|
|
45
52
|
private _trees!: Array<TreeNode>;
|
|
46
53
|
|
|
47
|
-
private filteredTrees: Array<{ key: string; tree: TreeNode }> = [];
|
|
48
54
|
private mobile: boolean = true;
|
|
49
|
-
private searchText: string = "";
|
|
50
55
|
private matchMedia!: MediaQueryList;
|
|
51
56
|
private valueToLabel: { [key: string]: string } = {};
|
|
52
57
|
|
|
53
|
-
private
|
|
54
|
-
|
|
58
|
+
private isSearchLoading: boolean = true;
|
|
59
|
+
private searchValue: string | null = null;
|
|
60
|
+
private searchResults: Result[] = [];
|
|
61
|
+
private scrollToSelectedSearchResult: boolean = false;
|
|
62
|
+
private selectedSearchResultIndex: number = -1;
|
|
63
|
+
private requestedFetchMoreResults: boolean = false;
|
|
64
|
+
|
|
65
|
+
private get areResultsEmpty(): boolean {
|
|
66
|
+
return (
|
|
67
|
+
(!this.searchResults ||
|
|
68
|
+
(this.searchResults && this.searchResults.length < 1)) &&
|
|
69
|
+
!this.isSearchLoading
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private get isSearchEmpty(): boolean {
|
|
74
|
+
return this.isUserSearching && this.areResultsEmpty;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private get showResultsHeading(): boolean {
|
|
78
|
+
return this.isUserSearching && !this.areResultsEmpty;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private get isUserSearching(): boolean {
|
|
82
|
+
return !!this.searchValue || this.isSearchLoading;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private get showSearchResults(): boolean {
|
|
86
|
+
return (
|
|
87
|
+
!!this.searchValue && !this.isSearchLoading && !this.areResultsEmpty
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private get isNearBottomOfSearchResults(): boolean {
|
|
92
|
+
const scrollArea = this.template.querySelector(
|
|
93
|
+
".sidebar-content-search"
|
|
94
|
+
);
|
|
95
|
+
if (!scrollArea) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const { scrollHeight, scrollTop } = scrollArea;
|
|
100
|
+
const { height } = scrollArea?.getBoundingClientRect();
|
|
101
|
+
|
|
102
|
+
return scrollHeight - scrollTop - height < 300;
|
|
55
103
|
}
|
|
56
104
|
|
|
57
105
|
private get containerClass() {
|
|
58
106
|
return cx("container", {
|
|
59
107
|
collapsed: !this.expanded,
|
|
60
108
|
"container-border-active": this._toggleHovered,
|
|
61
|
-
"container-mobile": this.mobile
|
|
109
|
+
"container-mobile": this.mobile,
|
|
110
|
+
"user-searching": this.isUserSearching,
|
|
111
|
+
"show-tree": !this.isUserSearching,
|
|
112
|
+
"search-empty": this.isSearchEmpty
|
|
62
113
|
});
|
|
63
114
|
}
|
|
64
115
|
|
|
@@ -70,6 +121,19 @@ export default class Sidebar extends LightningElement {
|
|
|
70
121
|
);
|
|
71
122
|
}
|
|
72
123
|
|
|
124
|
+
constructor() {
|
|
125
|
+
super();
|
|
126
|
+
|
|
127
|
+
if (getSidebarSearchParams()) {
|
|
128
|
+
this.isSearchLoading = true;
|
|
129
|
+
this.scrollToSelectedSearchResult = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
renderedCallback() {
|
|
134
|
+
this.initializeSearchScrollPosition();
|
|
135
|
+
}
|
|
136
|
+
|
|
73
137
|
connectedCallback() {
|
|
74
138
|
this.matchMedia = window.matchMedia(
|
|
75
139
|
`(max-width: ${MOBILE_SIZE_MATCH})`
|
|
@@ -97,7 +161,7 @@ export default class Sidebar extends LightningElement {
|
|
|
97
161
|
const sideNavAction: SidebarGtmAction = this.expanded
|
|
98
162
|
? "expand"
|
|
99
163
|
: "collapse";
|
|
100
|
-
|
|
164
|
+
trackAnalytics(event.currentTarget!, "custEv_leftNavLinkClick", {
|
|
101
165
|
sideNavAction,
|
|
102
166
|
clickText: TOGGLE_BUTTON_LABEL
|
|
103
167
|
});
|
|
@@ -111,66 +175,62 @@ export default class Sidebar extends LightningElement {
|
|
|
111
175
|
this._toggleHovered = false;
|
|
112
176
|
}
|
|
113
177
|
|
|
114
|
-
/*
|
|
115
|
-
* Debouncing this method: Do not apply searchText filter as long as this
|
|
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
|
-
}, WAIT_TIME);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private assignFilteredTrees() {
|
|
127
|
-
this.filteredTrees = this._trees
|
|
128
|
-
.map((singleTree) => {
|
|
129
|
-
return {
|
|
130
|
-
key: this.makeKey(),
|
|
131
|
-
tree: this.searchText
|
|
132
|
-
? this.findMatch(
|
|
133
|
-
new RegExp(this.searchText.toLowerCase().trim()),
|
|
134
|
-
singleTree
|
|
135
|
-
)!
|
|
136
|
-
: singleTree
|
|
137
|
-
};
|
|
138
|
-
})
|
|
139
|
-
.filter((filteredTree) => filteredTree.tree);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
178
|
private makeKey(): string {
|
|
143
179
|
return Math.random().toString(36).substring(7);
|
|
144
180
|
}
|
|
145
181
|
|
|
146
|
-
private
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return { ...node, isExpanded: true };
|
|
152
|
-
}
|
|
182
|
+
private onSearchChange(e: CustomEvent) {
|
|
183
|
+
this.requestedFetchMoreResults = false;
|
|
184
|
+
this.searchResults = e.detail.results;
|
|
185
|
+
this.searchValue = e.detail.value;
|
|
186
|
+
}
|
|
153
187
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
188
|
+
private onSearchLoading(e: CustomEvent) {
|
|
189
|
+
if (!e.detail.loading && this.scrollToSelectedSearchResult) {
|
|
190
|
+
this.selectedSearchResultIndex = this.searchResults.findIndex(
|
|
191
|
+
(r) => r.selected
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
this.isSearchLoading = e.detail;
|
|
161
195
|
}
|
|
162
196
|
|
|
163
|
-
private
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
197
|
+
private onSidebarSearchContentScroll() {
|
|
198
|
+
if (this.isSearchLoading) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const search = this.template.querySelector("dx-sidebar-search");
|
|
203
|
+
|
|
204
|
+
if (
|
|
205
|
+
this.isNearBottomOfSearchResults &&
|
|
206
|
+
search &&
|
|
207
|
+
!this.requestedFetchMoreResults
|
|
208
|
+
) {
|
|
209
|
+
this.requestedFetchMoreResults = true;
|
|
210
|
+
search.fetchMoreResults();
|
|
211
|
+
}
|
|
172
212
|
}
|
|
173
213
|
|
|
214
|
+
private initializeSearchScrollPosition = () => {
|
|
215
|
+
if (
|
|
216
|
+
this.scrollToSelectedSearchResult &&
|
|
217
|
+
this.selectedSearchResultIndex >= 0
|
|
218
|
+
) {
|
|
219
|
+
const selectedResult = this.template.querySelector(
|
|
220
|
+
`dx-sidebar-search-result:nth-child(${
|
|
221
|
+
this.selectedSearchResultIndex + 1
|
|
222
|
+
})`
|
|
223
|
+
);
|
|
224
|
+
if (!selectedResult || !selectedResult.parentNode) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
(selectedResult.parentNode as HTMLElement).scrollTop =
|
|
228
|
+
selectedResult.offsetTop -
|
|
229
|
+
(selectedResult.parentNode as HTMLElement).offsetTop;
|
|
230
|
+
this.scrollToSelectedSearchResult = false;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
174
234
|
private assignValueToLabel(node: TreeNode): void {
|
|
175
235
|
this.valueToLabel[node.name] = node.label;
|
|
176
236
|
if (node.children && node.children.length > 0) {
|