@salesforcedevs/docs-components 1.3.376 → 1.3.387
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 +2 -0
- package/package.json +2 -2
- package/src/modules/doc/contentLayout/contentLayout.css +1 -131
- package/src/modules/doc/contentLayout/contentLayout.ts +86 -167
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +1 -0
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +64 -0
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +168 -0
- package/src/modules/doc/specificationContent/specificationContent.css +31 -0
- package/src/modules/doc/specificationContent/specificationContent.html +164 -0
- package/src/modules/doc/specificationContent/specificationContent.ts +114 -0
- package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
package/lwc.config.json
CHANGED
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
"doc/contentLayout",
|
|
14
14
|
"doc/contentMedia",
|
|
15
15
|
"doc/docXmlContent",
|
|
16
|
+
"doc/lwcContentLayout",
|
|
16
17
|
"doc/header",
|
|
17
18
|
"doc/heading",
|
|
18
19
|
"doc/headingAnchor",
|
|
19
20
|
"doc/overview",
|
|
20
21
|
"doc/phase",
|
|
22
|
+
"doc/specificationContent",
|
|
21
23
|
"doc/versionPicker",
|
|
22
24
|
"doc/xmlContent",
|
|
23
25
|
"docUtils/utils"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/docs-components",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.387",
|
|
4
4
|
"description": "Docs Lightning web components for DSC",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "index.js",
|
|
@@ -24,5 +24,5 @@
|
|
|
24
24
|
"@types/lodash.orderby": "4.6.9",
|
|
25
25
|
"@types/lodash.uniqby": "4.7.9"
|
|
26
26
|
},
|
|
27
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "5181a287c393b41fe90d9e23c054421eaa1d2e72"
|
|
28
28
|
}
|
|
@@ -1,131 +1 @@
|
|
|
1
|
-
|
|
2
|
-
--dx-c-content-vertical-spacing: var(--dx-g-spacing-lg);
|
|
3
|
-
--dx-c-content-sidebar-sticky-top: calc(
|
|
4
|
-
var(--dx-g-global-header-height) + var(--dx-g-doc-header-height)
|
|
5
|
-
);
|
|
6
|
-
--dx-c-sidebar-height: calc(
|
|
7
|
-
100vh -
|
|
8
|
-
calc(
|
|
9
|
-
var(--dx-g-global-header-height) + var(--dx-g-doc-header-height)
|
|
10
|
-
)
|
|
11
|
-
);
|
|
12
|
-
--dx-c-content-scroll-margin-top: calc(
|
|
13
|
-
var(--dx-g-global-header-height) + var(--dx-g-doc-header-height) +
|
|
14
|
-
var(--dx-g-spacing-2xl)
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
display: block;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
doc-breadcrumbs {
|
|
21
|
-
--dx-c-popover-z-index: 5;
|
|
22
|
-
|
|
23
|
-
display: block;
|
|
24
|
-
margin-bottom: var(--dx-g-spacing-2xl);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
dx-sidebar,
|
|
28
|
-
dx-sidebar-old {
|
|
29
|
-
--dx-c-sidebar-vertical-padding: var(--dx-g-spacing-md);
|
|
30
|
-
|
|
31
|
-
z-index: calc(var(--dx-g-z-index-100) + 5);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
dx-toc {
|
|
35
|
-
--dx-c-toc-width: unset;
|
|
36
|
-
|
|
37
|
-
height: calc(100% - var(--dx-c-content-vertical-spacing) * 2);
|
|
38
|
-
margin: var(--dx-c-content-vertical-spacing) 0;
|
|
39
|
-
overflow-y: auto;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
dx-sidebar,
|
|
43
|
-
dx-toc {
|
|
44
|
-
display: block;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/* offset page jump link due to fixed header */
|
|
48
|
-
::slotted(doc-heading) {
|
|
49
|
-
scroll-margin-top: var(--dx-c-content-scroll-margin-top);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.content {
|
|
53
|
-
display: flex;
|
|
54
|
-
position: relative;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.content-body-doc-phase-container {
|
|
58
|
-
flex: 1;
|
|
59
|
-
border-left: 1px solid var(--dx-g-gray-90);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.content-body-container {
|
|
63
|
-
display: flex;
|
|
64
|
-
flex-direction: row;
|
|
65
|
-
justify-content: center;
|
|
66
|
-
max-width: var(--dx-g-doc-content-max-width);
|
|
67
|
-
|
|
68
|
-
/* Derived this manually by substracting (topHeader, doc header, banner and the content). */
|
|
69
|
-
min-height: 62vh;
|
|
70
|
-
margin: auto;
|
|
71
|
-
padding: 0 var(--dx-g-global-header-padding-horizontal);
|
|
72
|
-
margin-bottom: calc(2 * (var(--dx-g-spacing-5xl) + 4px));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.content-body {
|
|
76
|
-
margin: var(--dx-g-spacing-md) 0 0;
|
|
77
|
-
max-width: 900px;
|
|
78
|
-
flex: 1;
|
|
79
|
-
width: 0;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.is-sticky {
|
|
83
|
-
align-self: flex-start;
|
|
84
|
-
position: sticky;
|
|
85
|
-
top: var(--dx-c-content-sidebar-sticky-top);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.right-nav-bar {
|
|
89
|
-
margin-left: var(--dx-g-spacing-2xl);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@media screen and (max-width: 1024px) {
|
|
93
|
-
.right-nav-bar {
|
|
94
|
-
display: none;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@media screen and (max-width: 800px) {
|
|
99
|
-
.content-body {
|
|
100
|
-
margin-top: var(--dx-c-content-vertical-spacing);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.content-body-doc-phase-container {
|
|
104
|
-
border-left: 0;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@media screen and (max-width: 768px) {
|
|
109
|
-
.is-sticky {
|
|
110
|
-
width: 100%;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.content {
|
|
114
|
-
flex-direction: column;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.content-body-container {
|
|
118
|
-
padding-right: 0;
|
|
119
|
-
overflow-x: auto;
|
|
120
|
-
margin-bottom: calc(var(--dx-g-spacing-5xl) + 4px);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.left-nav-bar {
|
|
124
|
-
height: unset;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.content-body {
|
|
128
|
-
margin-left: var(--dx-g-spacing-mlg, 20px);
|
|
129
|
-
margin-right: var(--dx-g-spacing-mlg, 20px);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
1
|
+
@import "docHelpers/contentLayoutStyle";
|
|
@@ -11,7 +11,7 @@ type AnchorMap = { [key: string]: { intersect: boolean; id: string } };
|
|
|
11
11
|
declare const Sprig: (eventType: string, eventNme: string) => void;
|
|
12
12
|
|
|
13
13
|
const TOC_HEADER_TAG = "doc-heading";
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
const HIGHLIGHTABLE_SELECTOR = [
|
|
16
16
|
"p",
|
|
17
17
|
"h1",
|
|
@@ -83,87 +83,26 @@ export default class ContentLayout extends LightningElement {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
@track
|
|
86
|
-
|
|
86
|
+
protected _sidebarContent: unknown;
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
protected _breadcrumbs = null;
|
|
89
89
|
|
|
90
90
|
@track
|
|
91
|
-
|
|
91
|
+
protected _tocOptions!: Array<unknown>;
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
private rnbByTab: boolean = false;
|
|
93
|
+
protected tocOptionIdsSet = new Set();
|
|
94
|
+
protected anchoredElements: AnchorMap = {};
|
|
95
|
+
protected lastScrollPosition!: number;
|
|
96
|
+
protected observer?: IntersectionObserver;
|
|
97
|
+
protected hasRendered: boolean = false;
|
|
98
|
+
protected contentLoaded: boolean = false;
|
|
99
|
+
protected sidebarOpen: boolean = false;
|
|
101
100
|
|
|
102
101
|
get shouldDisplayFeedback() {
|
|
103
102
|
return this.contentLoaded && typeof Sprig !== "undefined";
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
const tabPanelListItem: any = this.getTabPanelList();
|
|
108
|
-
this.rnbByTab = tabPanelListItem?.id === RNB_BY_TAB ? true : false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
get showTabBasedRNB() {
|
|
112
|
-
return this.rnbByTab;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
onTabChanged = () => {
|
|
116
|
-
this.updateRNB();
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
private getTabPanelList() {
|
|
120
|
-
return document.querySelector("dx-tab-panel-list");
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
updateRNB = () => {
|
|
124
|
-
const headingElements = this.getHeadingElements();
|
|
125
|
-
headingElements.forEach((headingElement: any) => {
|
|
126
|
-
// Sometimes elements hash and header is not being set when slot content is wrapped with div
|
|
127
|
-
headingElement.hash = headingElement.attributes.hash?.nodeValue;
|
|
128
|
-
headingElement.header = headingElement.attributes.header?.nodeValue;
|
|
129
|
-
});
|
|
130
|
-
this.updateTocItems(headingElements);
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
private getHeadingElements() {
|
|
134
|
-
let headingElements = document.querySelectorAll(TOC_HEADER_TAG);
|
|
135
|
-
if (this.showTabBasedRNB) {
|
|
136
|
-
const tabPanelListItem: any = this.getTabPanelList();
|
|
137
|
-
const tabPanels =
|
|
138
|
-
tabPanelListItem?.querySelectorAll("dx-tab-panel");
|
|
139
|
-
for (const tabPanelItem of tabPanels) {
|
|
140
|
-
if (tabPanelItem.active) {
|
|
141
|
-
headingElements =
|
|
142
|
-
tabPanelItem.querySelectorAll(TOC_HEADER_TAG);
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return headingElements;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private updateURL() {
|
|
151
|
-
const tabs = this.getAllTabs();
|
|
152
|
-
const selectedTabId = this.getSelectedTabId();
|
|
153
|
-
tabs.forEach((tab: any) => {
|
|
154
|
-
if (tab.getAttribute("aria-selected") === "true") {
|
|
155
|
-
const tabID = tab.getAttribute("aria-label");
|
|
156
|
-
const url = new URL(window.location.href);
|
|
157
|
-
if (selectedTabId !== tabID) {
|
|
158
|
-
url.searchParams.set("type", tabID);
|
|
159
|
-
url.hash = "";
|
|
160
|
-
window.history.pushState({}, "", url.toString());
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private searchSyncer = new SearchSyncer({
|
|
105
|
+
protected searchSyncer = new SearchSyncer({
|
|
167
106
|
callbacks: {
|
|
168
107
|
onSearchChange: (nextSearchString: string): void => {
|
|
169
108
|
this.dispatchHighlightChange(
|
|
@@ -177,11 +116,11 @@ export default class ContentLayout extends LightningElement {
|
|
|
177
116
|
shouldStopPropagation: true,
|
|
178
117
|
target: window
|
|
179
118
|
});
|
|
180
|
-
|
|
119
|
+
protected tocValue?: string = undefined;
|
|
181
120
|
// eslint-disable-next-line no-undef
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
121
|
+
protected observerTimerId?: NodeJS.Timeout;
|
|
122
|
+
protected didScrollToSelectedHash = false;
|
|
123
|
+
protected _scrollInterval = 0;
|
|
185
124
|
|
|
186
125
|
get showToc(): boolean {
|
|
187
126
|
return this.tocOptions && this.tocOptions.length > 0;
|
|
@@ -198,13 +137,6 @@ export default class ContentLayout extends LightningElement {
|
|
|
198
137
|
);
|
|
199
138
|
}
|
|
200
139
|
|
|
201
|
-
// This event gets triggered when navigating back/forward
|
|
202
|
-
handlePopState = (): void => {
|
|
203
|
-
if (this.showTabBasedRNB) {
|
|
204
|
-
this.restoreTabSelection();
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
140
|
connectedCallback(): void {
|
|
209
141
|
const hasParentHighlightListener = closest(
|
|
210
142
|
"doc-xml-content",
|
|
@@ -217,46 +149,10 @@ export default class ContentLayout extends LightningElement {
|
|
|
217
149
|
);
|
|
218
150
|
this.searchSyncer.init();
|
|
219
151
|
}
|
|
220
|
-
window.addEventListener("popstate", this.handlePopState);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
private getSelectedTabId() {
|
|
224
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
225
|
-
const selectedTabId = urlParams.get("type");
|
|
226
|
-
return selectedTabId;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
private restoreTabSelection() {
|
|
230
|
-
requestAnimationFrame(() => {
|
|
231
|
-
const selectedTabId = this.getSelectedTabId();
|
|
232
|
-
if (selectedTabId) {
|
|
233
|
-
this.selectTabById(selectedTabId);
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
private getAllTabs(): any[] {
|
|
239
|
-
const tabPanelListItem: any = this.getTabPanelList();
|
|
240
|
-
if (tabPanelListItem?.shadowRoot) {
|
|
241
|
-
return Array.from(
|
|
242
|
-
tabPanelListItem.shadowRoot.querySelectorAll(
|
|
243
|
-
"dx-tab-panel-item"
|
|
244
|
-
)
|
|
245
|
-
).map((tabPanelItem: any) =>
|
|
246
|
-
tabPanelItem.shadowRoot.querySelector("button")
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
return [];
|
|
250
152
|
}
|
|
251
153
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
tabs.forEach((tab: any) => {
|
|
255
|
-
if (tab.getAttribute("aria-label") === tabId) {
|
|
256
|
-
tab.click();
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
}
|
|
154
|
+
// Placeholder for childs renderedCallback
|
|
155
|
+
protected postRenderedCallback?(): void;
|
|
260
156
|
|
|
261
157
|
renderedCallback(): void {
|
|
262
158
|
/**
|
|
@@ -275,12 +171,10 @@ export default class ContentLayout extends LightningElement {
|
|
|
275
171
|
|
|
276
172
|
if (!this.hasRendered) {
|
|
277
173
|
this.hasRendered = true;
|
|
278
|
-
this.setRNBByTab();
|
|
279
|
-
if (this.showTabBasedRNB) {
|
|
280
|
-
window.addEventListener("tabchanged", this.onTabChanged);
|
|
281
|
-
this.restoreTabSelection();
|
|
282
|
-
}
|
|
283
174
|
this.restoreScroll();
|
|
175
|
+
|
|
176
|
+
// Dynamically call `renderedCallbackForLwcContentLayout` if it exists
|
|
177
|
+
this.postRenderedCallback?.();
|
|
284
178
|
}
|
|
285
179
|
}
|
|
286
180
|
|
|
@@ -292,8 +186,6 @@ export default class ContentLayout extends LightningElement {
|
|
|
292
186
|
);
|
|
293
187
|
window.removeEventListener("scroll", this.adjustNavPosition);
|
|
294
188
|
window.removeEventListener("resize", this.adjustNavPosition);
|
|
295
|
-
window.removeEventListener("tabchanged", this.onTabChanged);
|
|
296
|
-
window.removeEventListener("popstate", this.handlePopState);
|
|
297
189
|
this.searchSyncer.dispose();
|
|
298
190
|
this.clearRenderObserverTimer();
|
|
299
191
|
|
|
@@ -413,6 +305,34 @@ export default class ContentLayout extends LightningElement {
|
|
|
413
305
|
(event as CustomEvent<string>).detail
|
|
414
306
|
);
|
|
415
307
|
|
|
308
|
+
protected getHeadingElements() {
|
|
309
|
+
// Note: We are doing document.querySelectorAll as a quick fix as we are not getting heading elements reference this.querySelectorAll
|
|
310
|
+
const headingElements = document.querySelectorAll(TOC_HEADER_TAG);
|
|
311
|
+
return headingElements;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
updateHeadingForRNB(): void {
|
|
315
|
+
const headingElements = this.getHeadingElements();
|
|
316
|
+
this.addObserverAndScroll(headingElements);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
addObserverAndScroll(headingElements: any) {
|
|
320
|
+
for (const headingElement of headingElements as any) {
|
|
321
|
+
// Add headingElements to intersectionObserver for highlighting respective RNB item when user scroll
|
|
322
|
+
const id = headingElement.getAttribute("id")!;
|
|
323
|
+
this.anchoredElements[id] = {
|
|
324
|
+
id,
|
|
325
|
+
intersect: false
|
|
326
|
+
};
|
|
327
|
+
this.observer?.observe(headingElement);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (!this.didScrollToSelectedHash) {
|
|
331
|
+
this.didScrollToSelectedHash = true;
|
|
332
|
+
this.scrollToHash(headingElements);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
416
336
|
attachInteractionObserver = (): void => {
|
|
417
337
|
if (!this.enableSlotChange) {
|
|
418
338
|
return;
|
|
@@ -437,38 +357,11 @@ export default class ContentLayout extends LightningElement {
|
|
|
437
357
|
rootMargin: globalNavOffset.trim()
|
|
438
358
|
}
|
|
439
359
|
);
|
|
440
|
-
|
|
441
|
-
// Note: We are doing document.querySelectorAll as a quick fix as we are not getting heading elements reference this.querySelectorAll
|
|
442
|
-
const headingElements = this.getHeadingElements();
|
|
443
|
-
|
|
444
|
-
// We only need to update URL in case of /docs and ignore if tabs are used anywhere else in DSC
|
|
445
|
-
if (this.showTabBasedRNB) {
|
|
446
|
-
this.updateURL();
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
for (const headingElement of headingElements as any) {
|
|
450
|
-
// Add headingElements to intersectionObserver for highlighting respective RNB item when user scroll
|
|
451
|
-
const id = headingElement.getAttribute("id")!;
|
|
452
|
-
this.anchoredElements[id] = {
|
|
453
|
-
id,
|
|
454
|
-
intersect: false
|
|
455
|
-
};
|
|
456
|
-
this.observer.observe(headingElement);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (!this.didScrollToSelectedHash) {
|
|
460
|
-
this.didScrollToSelectedHash = true;
|
|
461
|
-
this.scrollToHash(headingElements);
|
|
462
|
-
}
|
|
360
|
+
this.updateHeadingForRNB();
|
|
463
361
|
};
|
|
464
362
|
|
|
465
|
-
onSlotChange(): void {
|
|
466
|
-
this.updateRNB();
|
|
467
|
-
this.contentLoaded = true;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
363
|
// eslint-disable-next-line no-undef
|
|
471
|
-
|
|
364
|
+
updateTocItems(headingElements: any): void {
|
|
472
365
|
const tocOptions = [];
|
|
473
366
|
|
|
474
367
|
for (const headingElement of headingElements as any) {
|
|
@@ -493,7 +386,33 @@ export default class ContentLayout extends LightningElement {
|
|
|
493
386
|
this._tocOptions = tocOptions;
|
|
494
387
|
}
|
|
495
388
|
|
|
496
|
-
|
|
389
|
+
setHashAndHeaderForDocHeading(headingElements: any) {
|
|
390
|
+
for (const headingElement of headingElements as any) {
|
|
391
|
+
// Sometimes elements hash and header is not being set when slot content is wrapped with div
|
|
392
|
+
if (!headingElement.hash) {
|
|
393
|
+
headingElement.hash = headingElement.attributes.hash?.nodeValue;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (!headingElement.header) {
|
|
397
|
+
headingElement.header =
|
|
398
|
+
headingElement.attributes.header?.nodeValue;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
this.updateTocItems(headingElements);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
updateRNB = () => {
|
|
406
|
+
const headingElements = this.getHeadingElements();
|
|
407
|
+
this.setHashAndHeaderForDocHeading(headingElements);
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
onSlotChange(): void {
|
|
411
|
+
this.updateRNB();
|
|
412
|
+
this.contentLoaded = true;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
protected disconnectObserver(): void {
|
|
497
416
|
if (this.observer) {
|
|
498
417
|
this.observer.disconnect();
|
|
499
418
|
this.observer = undefined;
|
|
@@ -501,7 +420,7 @@ export default class ContentLayout extends LightningElement {
|
|
|
501
420
|
}
|
|
502
421
|
|
|
503
422
|
// eslint-disable-next-line no-undef
|
|
504
|
-
|
|
423
|
+
protected scrollToHash(headingElements: NodeListOf<Element>): void {
|
|
505
424
|
let { hash } = window.location;
|
|
506
425
|
if (hash) {
|
|
507
426
|
hash = hash.substr(1);
|
|
@@ -538,7 +457,7 @@ export default class ContentLayout extends LightningElement {
|
|
|
538
457
|
}
|
|
539
458
|
}
|
|
540
459
|
|
|
541
|
-
|
|
460
|
+
protected scrollIntoViewWithOffset(
|
|
542
461
|
headingElement: HTMLElement,
|
|
543
462
|
offset: number
|
|
544
463
|
) {
|
|
@@ -551,7 +470,7 @@ export default class ContentLayout extends LightningElement {
|
|
|
551
470
|
});
|
|
552
471
|
}
|
|
553
472
|
|
|
554
|
-
|
|
473
|
+
protected calculateActualSection(): void {
|
|
555
474
|
const currentScrollPosition = document.documentElement.scrollTop;
|
|
556
475
|
const id = Object.keys(this.anchoredElements).find(
|
|
557
476
|
(_id) => this.anchoredElements[_id].intersect
|
|
@@ -566,21 +485,21 @@ export default class ContentLayout extends LightningElement {
|
|
|
566
485
|
this.lastScrollPosition = currentScrollPosition;
|
|
567
486
|
}
|
|
568
487
|
|
|
569
|
-
|
|
488
|
+
protected calculatePreviousElementId(): string | undefined {
|
|
570
489
|
const keys = Object.keys(this.anchoredElements);
|
|
571
490
|
const currentIndex = keys.findIndex((id) => this.tocValue === id);
|
|
572
491
|
|
|
573
492
|
return currentIndex > 0 ? keys[currentIndex - 1] : undefined;
|
|
574
493
|
}
|
|
575
494
|
|
|
576
|
-
|
|
495
|
+
protected assignElementId(id: string | undefined): void {
|
|
577
496
|
// Change toc(RNB) highlight only for H2
|
|
578
497
|
if (this.tocOptionIdsSet.has(id)) {
|
|
579
498
|
this.tocValue = id;
|
|
580
499
|
}
|
|
581
500
|
}
|
|
582
501
|
|
|
583
|
-
|
|
502
|
+
protected dispatchHighlightChange(term: string): void {
|
|
584
503
|
this.dispatchEvent(
|
|
585
504
|
new CustomEvent("highlightedtermchange", {
|
|
586
505
|
detail: term,
|
|
@@ -590,14 +509,14 @@ export default class ContentLayout extends LightningElement {
|
|
|
590
509
|
);
|
|
591
510
|
}
|
|
592
511
|
|
|
593
|
-
|
|
512
|
+
protected updateHighlightsAndSearch(nextSearchString: string): void {
|
|
594
513
|
const nextSearchParam =
|
|
595
514
|
new URLSearchParams(nextSearchString).get("q") || "";
|
|
596
515
|
this.setSidebarInputValue(nextSearchParam);
|
|
597
516
|
this.dispatchHighlightChange(nextSearchParam);
|
|
598
517
|
}
|
|
599
518
|
|
|
600
|
-
|
|
519
|
+
protected onToggleSidebar(e: CustomEvent): void {
|
|
601
520
|
this.sidebarOpen = e.detail.open;
|
|
602
521
|
|
|
603
522
|
// eslint-disable-next-line @lwc/lwc/no-document-query
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "docHelpers/contentLayoutStyle";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="content">
|
|
3
|
+
<template lwc:if={useOldSidebar}>
|
|
4
|
+
<dx-sidebar-old
|
|
5
|
+
class="is-sticky left-nav-bar"
|
|
6
|
+
trees={sidebarContent}
|
|
7
|
+
value={sidebarValue}
|
|
8
|
+
header={sidebarHeader}
|
|
9
|
+
ontogglesidebar={onToggleSidebar}
|
|
10
|
+
languages={languages}
|
|
11
|
+
language={language}
|
|
12
|
+
bail-href={bailHref}
|
|
13
|
+
bail-label={bailLabel}
|
|
14
|
+
>
|
|
15
|
+
<slot name="sidebar-header" slot="version-picker"></slot>
|
|
16
|
+
</dx-sidebar-old>
|
|
17
|
+
</template>
|
|
18
|
+
<template lwc:else>
|
|
19
|
+
<dx-sidebar
|
|
20
|
+
class="is-sticky left-nav-bar"
|
|
21
|
+
trees={sidebarContent}
|
|
22
|
+
value={sidebarValue}
|
|
23
|
+
header={sidebarHeader}
|
|
24
|
+
coveo-organization-id={coveoOrganizationId}
|
|
25
|
+
coveo-public-access-token={coveoPublicAccessToken}
|
|
26
|
+
coveo-search-hub={coveoSearchHub}
|
|
27
|
+
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
28
|
+
ontogglesidebar={onToggleSidebar}
|
|
29
|
+
languages={languages}
|
|
30
|
+
language={language}
|
|
31
|
+
bail-href={bailHref}
|
|
32
|
+
bail-label={bailLabel}
|
|
33
|
+
>
|
|
34
|
+
<slot name="sidebar-header" slot="version-picker"></slot>
|
|
35
|
+
</dx-sidebar>
|
|
36
|
+
</template>
|
|
37
|
+
<div class="content-body-doc-phase-container">
|
|
38
|
+
<slot name="doc-phase"></slot>
|
|
39
|
+
<slot name="version-banner"></slot>
|
|
40
|
+
<div class="content-body-container">
|
|
41
|
+
<div class="content-body">
|
|
42
|
+
<doc-breadcrumbs
|
|
43
|
+
lwc:if={showBreadcrumbs}
|
|
44
|
+
breadcrumbs={breadcrumbs}
|
|
45
|
+
></doc-breadcrumbs>
|
|
46
|
+
<slot onslotchange={onSlotChange}></slot>
|
|
47
|
+
<doc-sprig-survey
|
|
48
|
+
lwc:if={shouldDisplayFeedback}
|
|
49
|
+
></doc-sprig-survey>
|
|
50
|
+
</div>
|
|
51
|
+
<div lwc:if={showToc} class="right-nav-bar is-sticky">
|
|
52
|
+
<dx-toc
|
|
53
|
+
header={tocTitle}
|
|
54
|
+
options={tocOptions}
|
|
55
|
+
value={tocValue}
|
|
56
|
+
></dx-toc>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<div lwc:if={showFooter} class="footer-container">
|
|
60
|
+
<dx-footer variant="no-signup"></dx-footer>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import ContentLayout from "doc/contentLayout";
|
|
2
|
+
|
|
3
|
+
const TOC_HEADER_TAG = "doc-heading";
|
|
4
|
+
const RNB_BY_TAB = "docs-tab";
|
|
5
|
+
const SPECIFICATION_TAB_TITLE = "Specification";
|
|
6
|
+
export const OBSERVER_ATTACH_WAIT_TIME = 500;
|
|
7
|
+
|
|
8
|
+
export default class LwcContentLayout extends ContentLayout {
|
|
9
|
+
private rnbByTab: boolean = false;
|
|
10
|
+
|
|
11
|
+
private setRNBByTab() {
|
|
12
|
+
const tabPanelListItem: any = this.getTabPanelList();
|
|
13
|
+
this.rnbByTab = tabPanelListItem?.id === RNB_BY_TAB ? true : false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get showTabBasedRNB() {
|
|
17
|
+
return this.rnbByTab;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
onRNBClick = (event: CustomEvent) => {
|
|
21
|
+
event.stopPropagation();
|
|
22
|
+
const currentTab = this.getSelectedTabId();
|
|
23
|
+
if (currentTab === SPECIFICATION_TAB_TITLE) {
|
|
24
|
+
this.didScrollToSelectedHash = false;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
onTabChanged = () => {
|
|
29
|
+
this.updateRNB();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
private getTabPanelList() {
|
|
33
|
+
// eslint-disable-next-line @lwc/lwc/no-document-query
|
|
34
|
+
return document.querySelector("dx-tab-panel-list");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected getHeadingElements() {
|
|
38
|
+
let headingElements = super.getHeadingElements();
|
|
39
|
+
if (this.showTabBasedRNB) {
|
|
40
|
+
const tabPanelListItem: any = this.getTabPanelList();
|
|
41
|
+
const tabPanels =
|
|
42
|
+
tabPanelListItem?.querySelectorAll("dx-tab-panel");
|
|
43
|
+
for (const tabPanelItem of tabPanels) {
|
|
44
|
+
if (tabPanelItem.active) {
|
|
45
|
+
// This is needed for Specification tab content
|
|
46
|
+
const specificationElement = tabPanelItem.querySelector(
|
|
47
|
+
"doc-specification-content"
|
|
48
|
+
);
|
|
49
|
+
if (specificationElement) {
|
|
50
|
+
headingElements =
|
|
51
|
+
specificationElement.shadowRoot.querySelectorAll(
|
|
52
|
+
TOC_HEADER_TAG
|
|
53
|
+
);
|
|
54
|
+
} else {
|
|
55
|
+
headingElements =
|
|
56
|
+
tabPanelItem.querySelectorAll(TOC_HEADER_TAG);
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return headingElements;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private updateURL() {
|
|
66
|
+
const tabs = this.getAllTabs();
|
|
67
|
+
const selectedTabId = this.getSelectedTabId();
|
|
68
|
+
tabs.forEach((tab: any) => {
|
|
69
|
+
if (tab.getAttribute("aria-selected") === "true") {
|
|
70
|
+
const tabID = tab.getAttribute("aria-label");
|
|
71
|
+
const url = new URL(window.location.href);
|
|
72
|
+
if (selectedTabId !== tabID) {
|
|
73
|
+
url.searchParams.set("type", tabID);
|
|
74
|
+
url.hash = "";
|
|
75
|
+
window.history.pushState({}, "", url.toString());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// This event gets triggered when navigating back/forward
|
|
82
|
+
handlePopState = (): void => {
|
|
83
|
+
if (this.showTabBasedRNB) {
|
|
84
|
+
this.restoreTabSelection();
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
connectedCallback(): void {
|
|
89
|
+
super.connectedCallback();
|
|
90
|
+
window.addEventListener("popstate", this.handlePopState);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private getSelectedTabId() {
|
|
94
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
95
|
+
const selectedTabId = urlParams.get("type");
|
|
96
|
+
return selectedTabId;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private restoreTabSelection() {
|
|
100
|
+
requestAnimationFrame(() => {
|
|
101
|
+
const selectedTabId = this.getSelectedTabId();
|
|
102
|
+
if (selectedTabId) {
|
|
103
|
+
this.selectTabById(selectedTabId);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private getAllTabs(): any[] {
|
|
109
|
+
const tabPanelListItem: any = this.getTabPanelList();
|
|
110
|
+
if (tabPanelListItem?.shadowRoot) {
|
|
111
|
+
return Array.from(
|
|
112
|
+
tabPanelListItem.shadowRoot.querySelectorAll(
|
|
113
|
+
"dx-tab-panel-item"
|
|
114
|
+
)
|
|
115
|
+
).map((tabPanelItem: any) =>
|
|
116
|
+
tabPanelItem.shadowRoot.querySelector("button")
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private selectTabById(tabId: string) {
|
|
123
|
+
const tabs = this.getAllTabs();
|
|
124
|
+
tabs.forEach((tab: any) => {
|
|
125
|
+
if (tab.getAttribute("aria-label") === tabId) {
|
|
126
|
+
tab.click();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
postRenderedCallback(): void {
|
|
132
|
+
this.setRNBByTab();
|
|
133
|
+
if (this.showTabBasedRNB) {
|
|
134
|
+
window.addEventListener("tabchanged", this.onTabChanged);
|
|
135
|
+
window.addEventListener(
|
|
136
|
+
"specificationdatarendered",
|
|
137
|
+
this.onTabChanged
|
|
138
|
+
);
|
|
139
|
+
window.addEventListener("selectedcontent", (event) =>
|
|
140
|
+
this.onRNBClick(event as CustomEvent)
|
|
141
|
+
);
|
|
142
|
+
this.restoreTabSelection();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
disconnectedCallback(): void {
|
|
147
|
+
super.disconnectedCallback();
|
|
148
|
+
if (this.showTabBasedRNB) {
|
|
149
|
+
window.removeEventListener("tabchanged", this.onTabChanged);
|
|
150
|
+
window.removeEventListener(
|
|
151
|
+
"specificationdatarendered",
|
|
152
|
+
this.onTabChanged
|
|
153
|
+
);
|
|
154
|
+
window.removeEventListener("selectedcontent", (event) =>
|
|
155
|
+
this.onRNBClick(event as CustomEvent)
|
|
156
|
+
);
|
|
157
|
+
window.removeEventListener("popstate", this.handlePopState);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
updateHeadingForRNB(): void {
|
|
162
|
+
// We only need to update URL in case of /docs and ignore if tabs are used anywhere else in DSC
|
|
163
|
+
if (this.showTabBasedRNB) {
|
|
164
|
+
this.updateURL();
|
|
165
|
+
}
|
|
166
|
+
super.updateHeadingForRNB();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@import "dxHelpers/reset";
|
|
2
|
+
@import "dxHelpers/text";
|
|
3
|
+
@import "dxHelpers/table";
|
|
4
|
+
|
|
5
|
+
.code {
|
|
6
|
+
color: #181818;
|
|
7
|
+
font-family: Courier, var(--dx-g-font-mono);
|
|
8
|
+
font-size: var(--dx-g-text-sm);
|
|
9
|
+
line-height: 150%;
|
|
10
|
+
background-color: #f4f4f4;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
table {
|
|
14
|
+
width: 100%;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.specification-properties table {
|
|
18
|
+
display: table;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.left-border {
|
|
22
|
+
border-left: 1px solid var(--dx-g-gray-90);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.icon-cell {
|
|
26
|
+
text-align: center;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.icon {
|
|
30
|
+
display: inline-block;
|
|
31
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="specification-properties">
|
|
3
|
+
<template lwc:if={hasAttributes}>
|
|
4
|
+
<doc-heading
|
|
5
|
+
header="Attributes"
|
|
6
|
+
hash="attributes"
|
|
7
|
+
aria-level="2"
|
|
8
|
+
id="attributes"
|
|
9
|
+
></doc-heading>
|
|
10
|
+
<table>
|
|
11
|
+
<thead>
|
|
12
|
+
<tr>
|
|
13
|
+
<th>Name</th>
|
|
14
|
+
<th>Description</th>
|
|
15
|
+
<th>Type</th>
|
|
16
|
+
<th>Default</th>
|
|
17
|
+
<th>Required</th>
|
|
18
|
+
</tr>
|
|
19
|
+
</thead>
|
|
20
|
+
<tbody>
|
|
21
|
+
<template for:each={attributes} for:item="attribute">
|
|
22
|
+
<tr key={attribute.name}>
|
|
23
|
+
<td>
|
|
24
|
+
<span class="code">
|
|
25
|
+
{attribute.nameInKebabCase}
|
|
26
|
+
</span>
|
|
27
|
+
</td>
|
|
28
|
+
<td>{attribute.description}</td>
|
|
29
|
+
<td>{attribute.type}</td>
|
|
30
|
+
<td>{attribute.default}</td>
|
|
31
|
+
<td class="icon-cell">
|
|
32
|
+
<template lwc:if={attribute.required}>
|
|
33
|
+
<dx-icon
|
|
34
|
+
symbol="success"
|
|
35
|
+
size="large"
|
|
36
|
+
color="green-vibrant-65"
|
|
37
|
+
class="icon"
|
|
38
|
+
></dx-icon>
|
|
39
|
+
</template>
|
|
40
|
+
</td>
|
|
41
|
+
</tr>
|
|
42
|
+
</template>
|
|
43
|
+
</tbody>
|
|
44
|
+
</table>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<template lwc:if={hasMethods}>
|
|
48
|
+
<doc-heading
|
|
49
|
+
header="Methods"
|
|
50
|
+
hash="methods"
|
|
51
|
+
aria-level="2"
|
|
52
|
+
id="methods"
|
|
53
|
+
></doc-heading>
|
|
54
|
+
<table>
|
|
55
|
+
<thead>
|
|
56
|
+
<tr>
|
|
57
|
+
<th>Name</th>
|
|
58
|
+
<th>Description</th>
|
|
59
|
+
<th>Argument Name</th>
|
|
60
|
+
<th>Argument Type</th>
|
|
61
|
+
<th>Argument Description</th>
|
|
62
|
+
</tr>
|
|
63
|
+
</thead>
|
|
64
|
+
<tbody>
|
|
65
|
+
<template for:each={processedMethods} for:item="method">
|
|
66
|
+
<template lwc:if={method.firstArgument}>
|
|
67
|
+
<tr key={method.name}>
|
|
68
|
+
<td rowspan={method.arguments.length}>
|
|
69
|
+
<span class="code">
|
|
70
|
+
{method.nameInKebabCase}
|
|
71
|
+
</span>
|
|
72
|
+
</td>
|
|
73
|
+
<td rowspan={method.arguments.length}>
|
|
74
|
+
{method.description}
|
|
75
|
+
</td>
|
|
76
|
+
<td class={method.cssForMultipleArguments}>
|
|
77
|
+
{method.firstArgument.name}
|
|
78
|
+
</td>
|
|
79
|
+
<td>{method.firstArgument.type}</td>
|
|
80
|
+
<td>{method.firstArgument.description}</td>
|
|
81
|
+
</tr>
|
|
82
|
+
<template
|
|
83
|
+
for:each={method.remainingArguments}
|
|
84
|
+
for:item="arg"
|
|
85
|
+
>
|
|
86
|
+
<tr key={arg.name}>
|
|
87
|
+
<td>{arg.name}</td>
|
|
88
|
+
<td>{arg.type}</td>
|
|
89
|
+
<td>{arg.description}</td>
|
|
90
|
+
</tr>
|
|
91
|
+
</template>
|
|
92
|
+
</template>
|
|
93
|
+
<template lwc:else>
|
|
94
|
+
<tr key={method.name}>
|
|
95
|
+
<td>
|
|
96
|
+
<span class="code">
|
|
97
|
+
{method.nameInKebabCase}
|
|
98
|
+
</span>
|
|
99
|
+
</td>
|
|
100
|
+
<td>{method.description}</td>
|
|
101
|
+
<td colspan="3"></td>
|
|
102
|
+
</tr>
|
|
103
|
+
</template>
|
|
104
|
+
</template>
|
|
105
|
+
</tbody>
|
|
106
|
+
</table>
|
|
107
|
+
</template>
|
|
108
|
+
|
|
109
|
+
<template lwc:if={hasSlots}>
|
|
110
|
+
<doc-heading
|
|
111
|
+
header="Slots"
|
|
112
|
+
hash="slots"
|
|
113
|
+
aria-level="2"
|
|
114
|
+
id="slots"
|
|
115
|
+
></doc-heading>
|
|
116
|
+
<table>
|
|
117
|
+
<thead>
|
|
118
|
+
<tr>
|
|
119
|
+
<th>Name</th>
|
|
120
|
+
<th>Description</th>
|
|
121
|
+
</tr>
|
|
122
|
+
</thead>
|
|
123
|
+
<tbody>
|
|
124
|
+
<template for:each={slots} for:item="slot">
|
|
125
|
+
<tr key={slot.name}>
|
|
126
|
+
<td>
|
|
127
|
+
<span class="code">{slot.nameInKebabCase}</span>
|
|
128
|
+
</td>
|
|
129
|
+
<td>{slot.description}</td>
|
|
130
|
+
</tr>
|
|
131
|
+
</template>
|
|
132
|
+
</tbody>
|
|
133
|
+
</table>
|
|
134
|
+
</template>
|
|
135
|
+
|
|
136
|
+
<template lwc:if={hasEvents}>
|
|
137
|
+
<doc-heading
|
|
138
|
+
header="Events"
|
|
139
|
+
hash="events"
|
|
140
|
+
aria-level="2"
|
|
141
|
+
></doc-heading>
|
|
142
|
+
<table>
|
|
143
|
+
<thead>
|
|
144
|
+
<tr>
|
|
145
|
+
<th>Name</th>
|
|
146
|
+
<th>Description</th>
|
|
147
|
+
</tr>
|
|
148
|
+
</thead>
|
|
149
|
+
<tbody>
|
|
150
|
+
<template for:each={events} for:item="event">
|
|
151
|
+
<tr key={event.name}>
|
|
152
|
+
<td>
|
|
153
|
+
<span class="code">
|
|
154
|
+
{event.nameInKebabCase}
|
|
155
|
+
</span>
|
|
156
|
+
</td>
|
|
157
|
+
<td>{event.description}</td>
|
|
158
|
+
</tr>
|
|
159
|
+
</template>
|
|
160
|
+
</tbody>
|
|
161
|
+
</table>
|
|
162
|
+
</template>
|
|
163
|
+
</div>
|
|
164
|
+
</template>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { LightningElement, track, api } from "lwc";
|
|
2
|
+
import { Method, Specification } from "typings/custom";
|
|
3
|
+
import debounce from "debounce";
|
|
4
|
+
|
|
5
|
+
export default class SpecificationContent extends LightningElement {
|
|
6
|
+
@track data: any;
|
|
7
|
+
// TODO: added these default values for testing, will drop this once the backend is ready.
|
|
8
|
+
@api component: string = "button";
|
|
9
|
+
@api model: string = "lwc";
|
|
10
|
+
@api namespace: string = "lightning";
|
|
11
|
+
|
|
12
|
+
/* TODO: The actual URL is as follows:
|
|
13
|
+
* http://api.salesforce.com/doc-platform/developer/v1/{type}/{sub-type}/{component-name}
|
|
14
|
+
* Until the API integration is ready, we will go ahead with mocked-router-url.
|
|
15
|
+
*/
|
|
16
|
+
@api apiBaseUrl: string =
|
|
17
|
+
"https://cx-mock-router-internal-07a18d7b3f61.herokuapp.com";
|
|
18
|
+
|
|
19
|
+
private attributes: Specification[] = [];
|
|
20
|
+
private methods: Method[] = [];
|
|
21
|
+
private slots: Specification[] = [];
|
|
22
|
+
private events: Specification[] = [];
|
|
23
|
+
|
|
24
|
+
/* TODO: For now setting the timeout to 300ms,
|
|
25
|
+
* post integration with CX-Router API will test and change if required.
|
|
26
|
+
*/
|
|
27
|
+
private debouncedNotifyDataRendered = debounce(() => {
|
|
28
|
+
this.notifySpecificationDataRendered();
|
|
29
|
+
}, 300);
|
|
30
|
+
|
|
31
|
+
connectedCallback() {
|
|
32
|
+
this.fetchComponentMetadata();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async fetchComponentMetadata() {
|
|
36
|
+
const url = `${this.apiBaseUrl}/${this.model}/${this.namespace}/${this.component}`;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch(url);
|
|
40
|
+
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
// TODO: Will add loader and show error as follow-up
|
|
43
|
+
throw new Error(`Failed to fetch: ${response.statusText}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const result = await response.json();
|
|
47
|
+
this.data = result;
|
|
48
|
+
({
|
|
49
|
+
attributes: this.attributes,
|
|
50
|
+
methods: this.methods,
|
|
51
|
+
slots: this.slots,
|
|
52
|
+
events: this.events
|
|
53
|
+
} = this.data);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
this.data = {};
|
|
56
|
+
console.error("fetchComponentMetadata() failed for:" + url);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* This getter is to preprocess the methods for easier rendering in the template.
|
|
62
|
+
* Each method is augmented with additional properties:
|
|
63
|
+
* - `firstArgument`: The first argument (if any).
|
|
64
|
+
* - `remainingArguments`: All other arguments (if any).
|
|
65
|
+
* - `hasArguments`: A boolean indicating whether the method has arguments or not.
|
|
66
|
+
*/
|
|
67
|
+
get processedMethods(): Method[] {
|
|
68
|
+
return this.methods.map((method) => {
|
|
69
|
+
const [firstArgument, ...remainingArguments] =
|
|
70
|
+
method.arguments || [];
|
|
71
|
+
return {
|
|
72
|
+
...method,
|
|
73
|
+
firstArgument,
|
|
74
|
+
remainingArguments,
|
|
75
|
+
hasArguments: method.arguments && method.arguments.length > 0,
|
|
76
|
+
cssForMultipleArguments:
|
|
77
|
+
remainingArguments.length > 0 ? "left-border" : ""
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get hasAttributes() {
|
|
83
|
+
return this.attributes?.length > 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get hasMethods() {
|
|
87
|
+
return this.methods?.length > 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get hasSlots() {
|
|
91
|
+
return this.slots?.length > 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get hasEvents() {
|
|
95
|
+
return this.events?.length > 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
renderedCallback(): void {
|
|
99
|
+
if (this.data) {
|
|
100
|
+
this.debouncedNotifyDataRendered();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
notifySpecificationDataRendered() {
|
|
105
|
+
// Dispatch a custom event to notify the specification tab has rendered.
|
|
106
|
+
this.dispatchEvent(
|
|
107
|
+
new CustomEvent("specificationdatarendered", {
|
|
108
|
+
detail: { name: "doc-specification-content" },
|
|
109
|
+
bubbles: true,
|
|
110
|
+
composed: true
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
--dx-c-content-vertical-spacing: var(--dx-g-spacing-lg);
|
|
3
|
+
--dx-c-content-sidebar-sticky-top: calc(
|
|
4
|
+
var(--dx-g-global-header-height) + var(--dx-g-doc-header-height)
|
|
5
|
+
);
|
|
6
|
+
--dx-c-sidebar-height: calc(
|
|
7
|
+
100vh -
|
|
8
|
+
calc(
|
|
9
|
+
var(--dx-g-global-header-height) + var(--dx-g-doc-header-height)
|
|
10
|
+
)
|
|
11
|
+
);
|
|
12
|
+
--dx-c-content-scroll-margin-top: calc(
|
|
13
|
+
var(--dx-g-global-header-height) + var(--dx-g-doc-header-height) +
|
|
14
|
+
var(--dx-g-spacing-2xl)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
display: block;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
doc-breadcrumbs {
|
|
21
|
+
--dx-c-popover-z-index: 5;
|
|
22
|
+
|
|
23
|
+
display: block;
|
|
24
|
+
margin-bottom: var(--dx-g-spacing-2xl);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
dx-sidebar,
|
|
28
|
+
dx-sidebar-old {
|
|
29
|
+
--dx-c-sidebar-vertical-padding: var(--dx-g-spacing-md);
|
|
30
|
+
|
|
31
|
+
z-index: calc(var(--dx-g-z-index-100) + 5);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
dx-toc {
|
|
35
|
+
--dx-c-toc-width: unset;
|
|
36
|
+
|
|
37
|
+
height: calc(100% - var(--dx-c-content-vertical-spacing) * 2);
|
|
38
|
+
margin: var(--dx-c-content-vertical-spacing) 0;
|
|
39
|
+
overflow-y: auto;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
dx-sidebar,
|
|
43
|
+
dx-toc {
|
|
44
|
+
display: block;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* offset page jump link due to fixed header */
|
|
48
|
+
::slotted(doc-heading) {
|
|
49
|
+
scroll-margin-top: var(--dx-c-content-scroll-margin-top);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.content {
|
|
53
|
+
display: flex;
|
|
54
|
+
position: relative;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.content-body-doc-phase-container {
|
|
58
|
+
flex: 1;
|
|
59
|
+
border-left: 1px solid var(--dx-g-gray-90);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.content-body-container {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: row;
|
|
65
|
+
justify-content: center;
|
|
66
|
+
max-width: var(--dx-g-doc-content-max-width);
|
|
67
|
+
|
|
68
|
+
/* Derived this manually by substracting (topHeader, doc header, banner and the content). */
|
|
69
|
+
min-height: 62vh;
|
|
70
|
+
margin: auto;
|
|
71
|
+
padding: 0 var(--dx-g-global-header-padding-horizontal);
|
|
72
|
+
margin-bottom: calc(2 * (var(--dx-g-spacing-5xl) + 4px));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.content-body {
|
|
76
|
+
margin: var(--dx-g-spacing-md) 0 0;
|
|
77
|
+
max-width: 900px;
|
|
78
|
+
flex: 1;
|
|
79
|
+
width: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.is-sticky {
|
|
83
|
+
align-self: flex-start;
|
|
84
|
+
position: sticky;
|
|
85
|
+
top: var(--dx-c-content-sidebar-sticky-top);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.right-nav-bar {
|
|
89
|
+
margin-left: var(--dx-g-spacing-2xl);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@media screen and (max-width: 1024px) {
|
|
93
|
+
.right-nav-bar {
|
|
94
|
+
display: none;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@media screen and (max-width: 800px) {
|
|
99
|
+
.content-body {
|
|
100
|
+
margin-top: var(--dx-c-content-vertical-spacing);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.content-body-doc-phase-container {
|
|
104
|
+
border-left: 0;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@media screen and (max-width: 768px) {
|
|
109
|
+
.is-sticky {
|
|
110
|
+
width: 100%;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.content {
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.content-body-container {
|
|
118
|
+
padding-right: 0;
|
|
119
|
+
overflow-x: auto;
|
|
120
|
+
margin-bottom: calc(var(--dx-g-spacing-5xl) + 4px);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.left-nav-bar {
|
|
124
|
+
height: unset;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.content-body {
|
|
128
|
+
margin-left: var(--dx-g-spacing-mlg, 20px);
|
|
129
|
+
margin-right: var(--dx-g-spacing-mlg, 20px);
|
|
130
|
+
}
|
|
131
|
+
}
|