@salesforcedevs/dx-components 0.10.1-alpha.13 → 0.10.1-alpha.133

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.
Files changed (55) hide show
  1. package/lwc.config.json +3 -1
  2. package/package.json +2 -2
  3. package/src/assets/svg/docs-empty-state-small.svg +72 -0
  4. package/src/assets/svg/sidebar-loading.svg +34 -0
  5. package/src/modules/dx/cardGrid/__tests__/cardMockProps.ts +78 -148
  6. package/src/modules/dx/codeBlock/codeBlock.stories.ts +2 -69
  7. package/src/modules/dx/codeBlock/codeBlock.ts +5 -1
  8. package/src/modules/dx/codeBlock/darkTheme.css +0 -1
  9. package/src/modules/dx/codeBlock/lightTheme.css +0 -1
  10. package/src/modules/dx/emptyState/__tests__/emptyState.test.ts +29 -9
  11. package/src/modules/dx/emptyState/emptyState.css +14 -0
  12. package/src/modules/dx/emptyState/emptyState.html +2 -2
  13. package/src/modules/dx/emptyState/emptyState.stories.ts +8 -0
  14. package/src/modules/dx/emptyState/emptyState.ts +14 -0
  15. package/src/modules/dx/footer/links.ts +3 -5
  16. package/src/modules/dx/headerNav/__tests__/headerNav.test.ts +2 -4
  17. package/src/modules/dx/headerNav/headerNav.html +8 -6
  18. package/src/modules/dx/headerNav/headerNav.ts +2 -2
  19. package/src/modules/dx/lazy/lazy.ts +0 -7
  20. package/src/modules/dx/newsletterForm/newsletterForm.html +5 -3
  21. package/src/modules/dx/searchResults/coveo.css +314 -111
  22. package/src/modules/dx/sidebar/__tests__/mockDocContent.ts +48 -0
  23. package/src/modules/dx/sidebar/__tests__/mockPageReference.ts +8 -0
  24. package/src/modules/dx/sidebar/sidebar.css +38 -17
  25. package/src/modules/dx/sidebar/sidebar.html +62 -58
  26. package/src/modules/dx/sidebar/sidebar.stories.ts +53 -54
  27. package/src/modules/dx/sidebar/sidebar.ts +99 -10
  28. package/src/modules/dx/sidebarSearch/__tests__/mockPreloadedState.ts +8843 -0
  29. package/src/modules/dx/sidebarSearch/__tests__/sidebarSearch.test.ts +121 -0
  30. package/src/modules/dx/sidebarSearch/sidebarSearch.ts +282 -120
  31. package/src/modules/dx/sidebarSearch/utils.ts +2 -0
  32. package/src/modules/dx/sidebarSearchResult/__tests__/sidebarSearchResult.test.ts +55 -0
  33. package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.css +12 -2
  34. package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.html +1 -1
  35. package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +8 -2
  36. package/src/modules/dx/spinner/__tests__/spinner.test.ts +37 -0
  37. package/src/modules/dx/spinner/spinner.css +750 -0
  38. package/src/modules/dx/spinner/spinner.html +6 -0
  39. package/src/modules/dx/spinner/spinner.stories.ts +69 -0
  40. package/src/modules/dx/spinner/spinner.ts +20 -0
  41. package/src/modules/dx/{headerNavOption/__tests__/headerNavOption.test.ts → tab/__tests__/tab.test.ts} +40 -24
  42. package/src/modules/dx/{headerNavOption/headerNavOption.css → tab/tab.css} +24 -9
  43. package/src/modules/dx/{headerNavOption/headerNavOption.html → tab/tab.html} +5 -1
  44. package/src/modules/dx/tab/tab.stories.ts +57 -0
  45. package/src/modules/dx/{headerNavOption/headerNavOption.ts → tab/tab.ts} +26 -5
  46. package/src/modules/helpers/table/table.css +23 -7
  47. package/src/modules/utils/coveo/coveo.ts +50 -12
  48. package/src/modules/utils/highlight/__tests__/highlight.test.ts +154 -0
  49. package/src/modules/utils/highlight/highlight.ts +32 -0
  50. package/src/modules/utils/jest/jest.ts +35 -0
  51. package/src/modules/utils/normalizers/normalizers.ts +3 -0
  52. package/src/modules/utils/recentSearches/__tests__/recentSearches.test.ts +79 -0
  53. package/src/modules/utils/recentSearches/recentSearches.ts +12 -17
  54. package/src/modules/utils/regexps/regexps.ts +5 -0
  55. package/src/modules/utils/tests/tests.ts +18 -11
@@ -0,0 +1,48 @@
1
+ const noteWithOrderedList = `<div class='box message info'>
2
+ <h4 class='mbs'>Note with ordered list</h4>
3
+ <ol class='ol enumList'>
4
+ <li class='li'>From Setup, enter <kbd class='ph userinput'>Apex Classes</kbd> in the <span
5
+ class='keyword parmname'>Quick
6
+ Find</span> box, then select <strong class='ph uicontrol'>Apex Classes</strong>.</li>
7
+
8
+ <li class='li'>Click <strong class='ph uicontrol'>Edit</strong> next to SiteRegisterController.</li>
9
+
10
+ <li class='li'>Find the <samp class='codeph apex_code'><span class='keyword'>private</span> <span
11
+ class='keyword'>static</span> Id PORTAL_ACCOUNT_ID =
12
+ <span class='string'>'&lt;Account_ID&gt;'</span>;</samp> line and insert the ID for the account that
13
+ you want
14
+ to
15
+ associate with new users. The line should look similar to
16
+ this:
17
+ </li>
18
+
19
+ <li class='li'>Click <strong class='ph uicontrol'>Save</strong>.</li>
20
+ </ol>
21
+ </div>`;
22
+
23
+ export const sampleCodeBlockAndNote = `
24
+ <h1 class='helpHead1'>Using the instanceof Keyword</h1>
25
+ <p class="p">If you need to verify at run time whether an object is actually an instance of a particular class, use the
26
+ <samp class="codeph apex_code"><span class="statement">instanceof</span></samp> keyword.
27
+ The <samp class="codeph apex_code"><span class="statement">instanceof</span></samp> keyword can only be used to
28
+ verify if the target type in the expression on the right of the keyword is a viable
29
+ alternative for the declared type of the expression on the left.
30
+ </p>
31
+ <div class="p">You could add the following check to the <samp class="codeph apex_code">Report</samp>class in the <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_classes_casting.htm" title="In general, all type information is available at run time. This means that Apex enables casting, that is, a data type of one class can be assigned to a data type of another class, but only if one class is a subclass of the other class. Use casting when you want to convert an object from one data type to another.">classes and casting example</a> before you cast the item back into a <samp class="codeph apex_code">CustomReport</samp> object.
32
+ <div class="codeSection apex_code">
33
+ <pre class="codeblock brush:apex">If (Reports.get(0) <span class="statement">instanceof</span> CustomReport) {\n <span class="onelineComment">// Can safely cast it back to a custom report object</span>\n CustomReport c = (CustomReport) Reports.get(0);\n} Else {\n <span class="onelineComment">// Do something with the non-custom-report.</span>\n}</pre>
34
+ </div>
35
+ </div>
36
+ ${noteWithOrderedList}
37
+ <div class="p">
38
+ Follow these steps:
39
+ <ol class="ol enumList">
40
+ <li class="li">Add the data in a .csv file.</li>
41
+ <li class="li">Create a static resource for this file.</li>
42
+ <li class="li">
43
+ Call <samp class="codeph apex_code">Test.loadData</samp> within your test
44
+ method and passing it the sObject type token and the static resource name.
45
+ </li>
46
+ </ol>
47
+ </div>
48
+ `;
@@ -0,0 +1,8 @@
1
+ export default {
2
+ domain: "http://localhost:3000",
3
+ page: "docs",
4
+ docId: "atlas.en-us.apexcode.meta",
5
+ deliverable: "apexcode",
6
+ contentDocumentId: "apex_dev_guide.htm",
7
+ hash: ""
8
+ };
@@ -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: var(--dx-g-gray-95);
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
- border-right: 2px solid var(--border-color);
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,9 +147,35 @@ dx-tree:not(:last-child) {
152
147
  white-space: nowrap;
153
148
  }
154
149
 
155
- dx-empty-state {
156
- --dx-c-empty-state-background: var(--sds-g-gray-2);
157
- --dx-c-empty-state-image-width: 400px;
150
+ .loading-skeleton {
151
+ margin-top: var(--dx-g-spacing-md);
152
+ }
158
153
 
154
+ .search-empty.container dx-empty-state {
159
155
  display: block;
160
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,64 +27,68 @@
27
27
  onmouseenter={onToggleMouseEnter}
28
28
  onmouseleave={onToggleMouseLeave}
29
29
  ></dx-button>
30
-
31
- <template if:true={expanded}>
32
- <div class="padding-horizontal">
33
- <div class="header" if:false={mobile}>
34
- <h2 class="dx-text-heading-4 header-title">{header}</h2>
35
- <slot name="header"></slot>
36
- </div>
37
- <div class="search">
38
- <dx-sidebar-search
39
- onchange={onSearchChange}
40
- onloading={onSearchLoading}
41
- coveo-organization-id={coveoOrganizationId}
42
- coveo-public-access-token={coveoPublicAccessToken}
43
- coveo-search-hub={coveoSearchHub}
44
- coveo-object-type={coveoObjectType}
45
- coveo-language={coveoLanguage}
46
- coveo-release={coveoRelease}
47
- coveo-deliverable={coveoDeliverable}
48
- ></dx-sidebar-search>
49
- </div>
50
- <span if:true={isSearchLoading}>Loading...</span>
51
- <h2
52
- class="results-heading dx-text-heading-6"
53
- if:true={showResultsHeading}
54
- >
55
- Results
56
- </h2>
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>
57
34
  </div>
58
- <div class="sidebar-content">
59
- <dx-tree
60
- if:false={isUserSearching}
61
- for:each={trees}
62
- for:item="tree"
63
- key={tree.key}
64
- tree-root={tree.tree}
65
- onselect={onSelect}
66
- value={value}
67
- ></dx-tree>
68
- <template
69
- if:true={isUserSearching}
70
- for:each={searchResults}
71
- for:item="result"
72
- >
73
- <dx-sidebar-search-result
74
- title={result.title}
75
- title-highlights={result.titleHighlights}
76
- description={result.excerpt}
77
- description-highlights={result.excerptHighlights}
78
- href={result.href}
79
- key={result.uniqueId}
80
- ></dx-sidebar-search-result>
81
- </template>
82
- <dx-empty-state
83
- class="padding-horizontal"
84
- title="No Results"
85
- if:true={isSearchEmpty}
86
- ></dx-empty-state>
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>
87
44
  </div>
88
- </template>
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>
89
93
  </div>
90
94
  </template>
@@ -1,16 +1,7 @@
1
1
  import { html } from "lit-html";
2
+ import { coveoXMLDocsConfig, coveoSFDocsConfig } from "../../utils/coveo/coveo";
2
3
  import { SAMPLE_TREES, SAMPLE_TREES_WITH_METHODS } from "./__tests__/mockProps";
3
4
 
4
- export const coveoConfig = {
5
- coveoOrganizationId: "coveosalesforcetestakshatha",
6
- coveoPublicAccessToken: "xxfeb39525-e402-4e41-a870-7132441f7875",
7
- coveoSearchHub: "Developer_Docs_SS",
8
- coveoObjectType: "HTDeveloperDocumentsC",
9
- coveoLanguage: "en_US",
10
- coveoRelease: "232.0",
11
- coveoDeliverable: "apexcode"
12
- };
13
-
14
5
  export default {
15
6
  title: "dx/dx-sidebar",
16
7
  component: "dx-sidebar",
@@ -42,25 +33,48 @@ const styles = (addStyles: string = "") => html`
42
33
  ${addStyles}
43
34
  }
44
35
 
36
+ dx-sidebar::part(container) {
37
+ height: 100vh;
38
+ }
39
+
45
40
  body.sb-main-padded.sb-show-main {
46
41
  padding: 0;
47
42
  }
43
+
44
+ #root-inner {
45
+ display: flex;
46
+ height: 100%;
47
+ }
48
+
49
+ doc-content {
50
+ padding: 20px;
51
+ }
48
52
  </style>
49
53
  `;
50
54
 
51
- export const Base = (args: any) => html`
52
- ${styles("--dx-c-sidebar-min-height: 100vh;")}
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%;")}
53
70
 
54
71
  <dx-sidebar
55
72
  header="${args.header}"
56
73
  trees="${JSON.stringify(args.trees)}"
57
- coveo-organization-id="${coveoConfig.coveoOrganizationId}"
58
- coveo-public-access-token="${coveoConfig.coveoPublicAccessToken}"
59
- coveo-search-hub="${coveoConfig.coveoSearchHub}"
60
- coveo-object-type="${coveoConfig.coveoObjectType}"
61
- coveo-language="${coveoConfig.coveoLanguage}"
62
- coveo-release="${coveoConfig.coveoRelease}"
63
- coveo-deliverable="${coveoConfig.coveoDeliverable}"
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}"
64
78
  ></dx-sidebar>
65
79
  `;
66
80
 
@@ -74,13 +88,10 @@ export const WidthAndMinHeightVariables = (args: any) => html`
74
88
  <dx-sidebar
75
89
  header="${args.header}"
76
90
  trees="${JSON.stringify(args.trees)}"
77
- coveo-organization-id="${coveoConfig.coveoOrganizationId}"
78
- coveo-public-access-token="${coveoConfig.coveoPublicAccessToken}"
79
- coveo-search-hub="${coveoConfig.coveoSearchHub}"
80
- coveo-object-type="${coveoConfig.coveoObjectType}"
81
- coveo-language="${coveoConfig.coveoLanguage}"
82
- coveo-release="${coveoConfig.coveoRelease}"
83
- coveo-deliverable="${coveoConfig.coveoDeliverable}"
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}"
84
95
  ></dx-sidebar>
85
96
  `;
86
97
 
@@ -103,13 +114,10 @@ export const WidthDrivenByContainer = (args: any) => html`
103
114
  header="${args.header}"
104
115
  trees="${JSON.stringify(args.trees)}"
105
116
  value="${args.value}"
106
- coveo-organization-id="${coveoConfig.coveoOrganizationId}"
107
- coveo-public-access-token="${coveoConfig.coveoPublicAccessToken}"
108
- coveo-search-hub="${coveoConfig.coveoSearchHub}"
109
- coveo-object-type="${coveoConfig.coveoObjectType}"
110
- coveo-language="${coveoConfig.coveoLanguage}"
111
- coveo-release="${coveoConfig.coveoRelease}"
112
- coveo-deliverable="${coveoConfig.coveoDeliverable}"
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}"
113
121
  ></dx-sidebar>
114
122
  </div>
115
123
  `;
@@ -122,13 +130,10 @@ export const WithBadges = (args: any) => html`
122
130
  header="${args.header}"
123
131
  trees="${JSON.stringify(SAMPLE_TREES_WITH_METHODS)}"
124
132
  value="${args.value}"
125
- coveo-organization-id="${coveoConfig.coveoOrganizationId}"
126
- coveo-public-access-token="${coveoConfig.coveoPublicAccessToken}"
127
- coveo-search-hub="${coveoConfig.coveoSearchHub}"
128
- coveo-object-type="${coveoConfig.coveoObjectType}"
129
- coveo-language="${coveoConfig.coveoLanguage}"
130
- coveo-release="${coveoConfig.coveoRelease}"
131
- coveo-deliverable="${coveoConfig.coveoDeliverable}"
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}"
132
137
  ></dx-sidebar>
133
138
  </div>
134
139
  `;
@@ -146,13 +151,10 @@ export const PositionSticky = ({ header, trees, value }: any) => html`
146
151
  header="${header}"
147
152
  trees="${JSON.stringify(trees)}"
148
153
  value="${value}"
149
- coveo-organization-id="${coveoConfig.coveoOrganizationId}"
150
- coveo-public-access-token="${coveoConfig.coveoPublicAccessToken}"
151
- coveo-search-hub="${coveoConfig.coveoSearchHub}"
152
- coveo-object-type="${coveoConfig.coveoObjectType}"
153
- coveo-language="${coveoConfig.coveoLanguage}"
154
- coveo-release="${coveoConfig.coveoRelease}"
155
- coveo-deliverable="${coveoConfig.coveoDeliverable}"
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}"
156
158
  ></dx-sidebar>
157
159
  `;
158
160
 
@@ -177,13 +179,10 @@ export const UseSlot = ({ header, trees, value }: any) => html`
177
179
  header="${header}"
178
180
  trees="${JSON.stringify(trees)}"
179
181
  value="${value}"
180
- coveo-organization-id="${coveoConfig.coveoOrganizationId}"
181
- coveo-public-access-token="${coveoConfig.coveoPublicAccessToken}"
182
- coveo-search-hub="${coveoConfig.coveoSearchHub}"
183
- coveo-object-type="${coveoConfig.coveoObjectType}"
184
- coveo-language="${coveoConfig.coveoLanguage}"
185
- coveo-release="${coveoConfig.coveoRelease}"
186
- coveo-deliverable="${coveoConfig.coveoDeliverable}"
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}"
187
186
  >
188
187
  <span slot="header">I'm in the sidebar</span>
189
188
  </dx-sidebar>
@@ -1,8 +1,9 @@
1
1
  import cx from "classnames";
2
- import { track } from "dx/instrumentation";
3
- import { LightningElement, api } from "lwc";
2
+ import { track as trackAnalytics } from "dx/instrumentation";
3
+ import { LightningElement, api, track } from "lwc";
4
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
9
  const MOBILE_SIZE_MATCH = "768px";
@@ -12,10 +13,7 @@ export default class Sidebar extends LightningElement {
12
13
  @api coveoOrganizationId!: string;
13
14
  @api coveoPublicAccessToken!: string;
14
15
  @api coveoSearchHub!: string;
15
- @api coveoObjectType!: string;
16
- @api coveoLanguage!: string;
17
- @api coveoRelease!: string;
18
- @api coveoDeliverable!: string;
16
+ @api coveoAdvancedQueryConfig!: string;
19
17
  @api header: string = "";
20
18
 
21
19
  @api
@@ -46,18 +44,30 @@ export default class Sidebar extends LightningElement {
46
44
  }));
47
45
  }
48
46
 
47
+ @api
48
+ setInputValue(searchTerm: string) {
49
+ this.template
50
+ .querySelector("dx-sidebar-search")
51
+ .setInputValue(searchTerm);
52
+ }
53
+
49
54
  private expanded: boolean = true;
50
55
  private _toggleHovered: boolean = false;
51
56
  private _value?: string = undefined;
57
+
58
+ @track
52
59
  private _trees!: Array<TreeNode>;
53
60
 
54
61
  private mobile: boolean = true;
55
62
  private matchMedia!: MediaQueryList;
56
63
  private valueToLabel: { [key: string]: string } = {};
57
64
 
58
- private isSearchLoading: boolean = false;
65
+ private isSearchLoading: boolean = true;
59
66
  private searchValue: string | null = null;
60
67
  private searchResults: Result[] = [];
68
+ private scrollToSelectedSearchResult: boolean = false;
69
+ private selectedSearchResultIndex: number = -1;
70
+ private requestedFetchMoreResults: boolean = false;
61
71
 
62
72
  private get areResultsEmpty(): boolean {
63
73
  return (
@@ -76,14 +86,37 @@ export default class Sidebar extends LightningElement {
76
86
  }
77
87
 
78
88
  private get isUserSearching(): boolean {
79
- return !!this.searchValue;
89
+ return !!this.searchValue || this.isSearchLoading;
90
+ }
91
+
92
+ private get showSearchResults(): boolean {
93
+ return (
94
+ !!this.searchValue && !this.isSearchLoading && !this.areResultsEmpty
95
+ );
96
+ }
97
+
98
+ private get isNearBottomOfSearchResults(): boolean {
99
+ const scrollArea = this.template.querySelector(
100
+ ".sidebar-content-search"
101
+ );
102
+ if (!scrollArea) {
103
+ return false;
104
+ }
105
+
106
+ const { scrollHeight, scrollTop } = scrollArea;
107
+ const { height } = scrollArea?.getBoundingClientRect();
108
+
109
+ return scrollHeight - scrollTop - height < 300;
80
110
  }
81
111
 
82
112
  private get containerClass() {
83
113
  return cx("container", {
84
114
  collapsed: !this.expanded,
85
115
  "container-border-active": this._toggleHovered,
86
- "container-mobile": this.mobile
116
+ "container-mobile": this.mobile,
117
+ "user-searching": this.isUserSearching,
118
+ "show-tree": !this.isUserSearching,
119
+ "search-empty": this.isSearchEmpty
87
120
  });
88
121
  }
89
122
 
@@ -95,6 +128,19 @@ export default class Sidebar extends LightningElement {
95
128
  );
96
129
  }
97
130
 
131
+ constructor() {
132
+ super();
133
+
134
+ if (getSidebarSearchParams()) {
135
+ this.isSearchLoading = true;
136
+ this.scrollToSelectedSearchResult = true;
137
+ }
138
+ }
139
+
140
+ renderedCallback() {
141
+ this.initializeSearchScrollPosition();
142
+ }
143
+
98
144
  connectedCallback() {
99
145
  this.matchMedia = window.matchMedia(
100
146
  `(max-width: ${MOBILE_SIZE_MATCH})`
@@ -122,7 +168,7 @@ export default class Sidebar extends LightningElement {
122
168
  const sideNavAction: SidebarGtmAction = this.expanded
123
169
  ? "expand"
124
170
  : "collapse";
125
- track(event.currentTarget!, "custEv_leftNavLinkClick", {
171
+ trackAnalytics(event.currentTarget!, "custEv_leftNavLinkClick", {
126
172
  sideNavAction,
127
173
  clickText: TOGGLE_BUTTON_LABEL
128
174
  });
@@ -141,14 +187,57 @@ export default class Sidebar extends LightningElement {
141
187
  }
142
188
 
143
189
  private onSearchChange(e: CustomEvent) {
190
+ this.requestedFetchMoreResults = false;
144
191
  this.searchResults = e.detail.results;
145
192
  this.searchValue = e.detail.value;
146
193
  }
147
194
 
148
195
  private onSearchLoading(e: CustomEvent) {
196
+ if (!e.detail.loading && this.scrollToSelectedSearchResult) {
197
+ this.selectedSearchResultIndex = this.searchResults.findIndex(
198
+ (r) => r.selected
199
+ );
200
+ }
149
201
  this.isSearchLoading = e.detail;
150
202
  }
151
203
 
204
+ private onSidebarSearchContentScroll() {
205
+ if (this.isSearchLoading) {
206
+ return;
207
+ }
208
+
209
+ const search = this.template.querySelector("dx-sidebar-search");
210
+
211
+ if (
212
+ this.isNearBottomOfSearchResults &&
213
+ search &&
214
+ !this.requestedFetchMoreResults
215
+ ) {
216
+ this.requestedFetchMoreResults = true;
217
+ search.fetchMoreResults();
218
+ }
219
+ }
220
+
221
+ private initializeSearchScrollPosition = () => {
222
+ if (
223
+ this.scrollToSelectedSearchResult &&
224
+ this.selectedSearchResultIndex >= 0
225
+ ) {
226
+ const selectedResult = this.template.querySelector(
227
+ `dx-sidebar-search-result:nth-child(${
228
+ this.selectedSearchResultIndex + 1
229
+ })`
230
+ );
231
+ if (!selectedResult || !selectedResult.parentNode) {
232
+ return;
233
+ }
234
+ (selectedResult.parentNode as HTMLElement).scrollTop =
235
+ selectedResult.offsetTop -
236
+ (selectedResult.parentNode as HTMLElement).offsetTop;
237
+ this.scrollToSelectedSearchResult = false;
238
+ }
239
+ };
240
+
152
241
  private assignValueToLabel(node: TreeNode): void {
153
242
  this.valueToLabel[node.name] = node.label;
154
243
  if (node.children && node.children.length > 0) {