@salesforcedevs/docs-components 0.7.0 → 0.7.59-sppage-alpha1
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 +17 -3
- package/package.json +16 -6
- package/src/modules/README.md +41 -0
- package/src/modules/doc/amfModelParser/amfModelParser.ts +674 -0
- package/src/modules/doc/amfReference/amfReference.css +25 -0
- package/src/modules/doc/amfReference/amfReference.html +60 -0
- package/src/modules/doc/amfReference/amfReference.ts +1494 -0
- package/src/modules/doc/amfReference/constants.ts +76 -0
- package/src/modules/doc/amfReference/types.ts +125 -0
- package/src/modules/doc/amfTopic/amfTopic.css +21 -0
- package/src/modules/doc/amfTopic/amfTopic.html +3 -0
- package/src/modules/doc/amfTopic/amfTopic.ts +111 -0
- package/src/modules/doc/amfTopic/types.ts +56 -0
- package/src/modules/doc/amfTopic/utils.ts +136 -0
- package/src/modules/doc/breadcrumbItem/breadcrumbItem.css +51 -0
- package/src/modules/doc/breadcrumbItem/breadcrumbItem.html +5 -0
- package/src/modules/doc/breadcrumbItem/breadcrumbItem.ts +71 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.css +27 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.html +58 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.ts +192 -0
- package/src/modules/doc/content/content.css +94 -70
- package/src/modules/doc/content/content.ts +233 -169
- package/src/modules/doc/contentCallout/contentCallout.css +17 -23
- package/src/modules/doc/contentCallout/contentCallout.html +13 -4
- package/src/modules/doc/contentCallout/contentCallout.ts +16 -3
- package/src/modules/doc/contentLayout/contentLayout.css +131 -0
- package/src/modules/doc/contentLayout/contentLayout.html +64 -0
- package/src/modules/doc/contentLayout/contentLayout.ts +610 -0
- package/src/modules/doc/doDont/doDont.css +47 -0
- package/src/modules/doc/doDont/doDont.html +27 -0
- package/src/modules/doc/doDont/doDont.ts +17 -0
- package/src/modules/doc/header/header.css +70 -37
- package/src/modules/doc/header/header.html +40 -135
- package/src/modules/doc/header/header.ts +29 -78
- package/src/modules/doc/heading/heading.css +33 -0
- package/src/modules/doc/heading/heading.html +14 -0
- package/src/modules/doc/heading/heading.ts +67 -0
- package/src/modules/doc/headingAnchor/headingAnchor.css +33 -0
- package/src/modules/doc/headingAnchor/headingAnchor.html +19 -0
- package/src/modules/doc/headingAnchor/headingAnchor.ts +43 -0
- package/src/modules/doc/headingContent/headingContent.css +53 -0
- package/src/modules/doc/headingContent/headingContent.html +13 -0
- package/src/modules/doc/headingContent/headingContent.ts +30 -0
- package/src/modules/doc/overview/overview.css +40 -0
- package/src/modules/doc/overview/overview.html +34 -0
- package/src/modules/doc/overview/overview.ts +12 -0
- package/src/modules/doc/phase/phase.css +70 -0
- package/src/modules/doc/phase/phase.html +38 -0
- package/src/modules/doc/phase/phase.ts +93 -0
- package/src/modules/doc/specificationContent/specificationContent.css +3 -0
- package/src/modules/doc/specificationContent/specificationContent.html +99 -0
- package/src/modules/doc/specificationContent/specificationContent.ts +56 -0
- package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
- package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
- package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
- package/src/modules/doc/toc/toc.ts +1 -1
- package/src/modules/doc/versionPicker/versionPicker.css +64 -0
- package/src/modules/doc/versionPicker/versionPicker.html +38 -0
- package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
- package/src/modules/doc/xmlContent/types.ts +120 -0
- package/src/modules/doc/xmlContent/utils.ts +163 -0
- package/src/modules/doc/xmlContent/xmlContent.css +54 -0
- package/src/modules/doc/xmlContent/xmlContent.html +52 -0
- package/src/modules/doc/xmlContent/xmlContent.ts +780 -0
- package/src/modules/docHelpers/amfStyle/amfStyle.css +355 -0
- package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
- package/src/modules/docHelpers/status/status.css +22 -0
- package/src/modules/docUtils/searchSyncer/searchSyncer.ts +86 -0
- package/src/modules/docUtils/utils/utils.ts +32 -0
- package/LICENSE +0 -12
- package/src/modules/doc/content/__tests__/content.test.ts +0 -120
- package/src/modules/doc/content/__tests__/mockDocContent.ts +0 -292
- package/src/modules/doc/content/__tests__/mockPageReference.ts +0 -8
- package/src/modules/doc/content/content.stories.ts +0 -108
- package/src/modules/doc/contentCallout/__tests__/contentCallout.test.ts +0 -80
- package/src/modules/doc/contentCallout/__tests__/mockProps.ts +0 -14
- package/src/modules/doc/contentCallout/contentCallout.stories.ts +0 -29
- package/src/modules/doc/contentMedia/__tests__/contentMedia.test.ts +0 -97
- package/src/modules/doc/contentMedia/contentMedia.stories.ts +0 -113
- package/src/modules/doc/header/__tests__/coveoConfig.ts +0 -12
- package/src/modules/doc/header/__tests__/header.test.ts +0 -434
- package/src/modules/doc/header/__tests__/mockNavDevelopers.ts +0 -427
- package/src/modules/doc/header/__tests__/mockNavs.ts +0 -115
- package/src/modules/doc/header/__tests__/mockProps.ts +0 -149
- package/src/modules/doc/header/header.stories.ts +0 -160
- package/src/modules/doc/nav/__tests__/mockAvailableLanguages.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockAvailableVersions.ts +0 -122
- package/src/modules/doc/nav/__tests__/mockPageReference.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockPdfUrl.ts +0 -1
- package/src/modules/doc/nav/__tests__/mockSelectedLanguage.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockSelectedVersion.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockToc.ts +0 -146
- package/src/modules/doc/nav/__tests__/nav.test.ts +0 -58
- package/src/modules/doc/toc/__tests__/mockPageReference.ts +0 -8
- package/src/modules/doc/toc/__tests__/mockToc.ts +0 -146
- package/src/modules/doc/toc/__tests__/toc.test.ts +0 -29
- package/src/modules/doc/toolbar/__tests__/mockAvailableLanguages.ts +0 -8
- package/src/modules/doc/toolbar/__tests__/mockAvailableVersions.ts +0 -122
- package/src/modules/doc/toolbar/__tests__/mockPdfUrl.ts +0 -1
- package/src/modules/doc/toolbar/__tests__/mockSelectedLanguage.ts +0 -8
- package/src/modules/doc/toolbar/__tests__/mockSelectedVersion.ts +0 -8
- package/src/modules/doc/toolbar/__tests__/toolbar.test.ts +0 -44
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
/* eslint-disable @lwc/lwc/no-document-query */
|
|
2
|
+
import { LightningElement, api, track } from "lwc";
|
|
3
|
+
import { closest } from "kagekiri";
|
|
4
|
+
import { toJson } from "dxUtils/normalizers";
|
|
5
|
+
import { highlightTerms } from "dxUtils/highlight";
|
|
6
|
+
import { SearchSyncer } from "docUtils/searchSyncer";
|
|
7
|
+
import type { OptionWithLink } from "typings/custom";
|
|
8
|
+
|
|
9
|
+
type AnchorMap = { [key: string]: { intersect: boolean; id: string } };
|
|
10
|
+
|
|
11
|
+
declare const Sprig: (eventType: string, eventNme: string) => void;
|
|
12
|
+
|
|
13
|
+
const TOC_HEADER_TAG = "doc-heading";
|
|
14
|
+
const RNB_BY_TAB = "docs-tab";
|
|
15
|
+
const HIGHLIGHTABLE_SELECTOR = [
|
|
16
|
+
"p",
|
|
17
|
+
"h1",
|
|
18
|
+
"h2",
|
|
19
|
+
"h3",
|
|
20
|
+
"h4",
|
|
21
|
+
"h5",
|
|
22
|
+
"h6",
|
|
23
|
+
"li",
|
|
24
|
+
"dl",
|
|
25
|
+
"th",
|
|
26
|
+
"td"
|
|
27
|
+
].join(",");
|
|
28
|
+
export const OBSERVER_ATTACH_WAIT_TIME = 500;
|
|
29
|
+
|
|
30
|
+
export default class ContentLayout extends LightningElement {
|
|
31
|
+
@api sidebarValue!: string;
|
|
32
|
+
@api sidebarHeader!: string;
|
|
33
|
+
@api tocTitle!: string;
|
|
34
|
+
@api enableSlotChange = false;
|
|
35
|
+
@api coveoOrganizationId!: string;
|
|
36
|
+
@api coveoPublicAccessToken!: string;
|
|
37
|
+
@api coveoAnalyticsToken!: string;
|
|
38
|
+
@api coveoSearchHub!: string;
|
|
39
|
+
@api coveoAdvancedQueryConfig!: string;
|
|
40
|
+
@api useOldSidebar?: boolean = false;
|
|
41
|
+
@api languages!: OptionWithLink[];
|
|
42
|
+
@api language!: string;
|
|
43
|
+
@api bailHref!: string;
|
|
44
|
+
@api bailLabel!: string;
|
|
45
|
+
|
|
46
|
+
// This is needed for now to prevent failing snapshot tests due to links in the footer
|
|
47
|
+
@api showFooter = false;
|
|
48
|
+
|
|
49
|
+
@api
|
|
50
|
+
get breadcrumbs() {
|
|
51
|
+
return this._breadcrumbs;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
set breadcrumbs(value) {
|
|
55
|
+
if (value) {
|
|
56
|
+
this._breadcrumbs = toJson(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@api
|
|
61
|
+
get sidebarContent() {
|
|
62
|
+
return this._sidebarContent;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
set sidebarContent(value: any) {
|
|
66
|
+
this._sidebarContent = toJson(value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@api
|
|
70
|
+
get tocOptions() {
|
|
71
|
+
return this._tocOptions;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
set tocOptions(value) {
|
|
75
|
+
this._tocOptions = toJson(value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@api
|
|
79
|
+
setSidebarInputValue(searchTerm: string): void {
|
|
80
|
+
(this.template.querySelector("dx-sidebar") as any)?.setInputValue(
|
|
81
|
+
searchTerm
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@track
|
|
86
|
+
private _sidebarContent: unknown;
|
|
87
|
+
|
|
88
|
+
private _breadcrumbs = null;
|
|
89
|
+
|
|
90
|
+
@track
|
|
91
|
+
private _tocOptions!: Array<unknown>;
|
|
92
|
+
|
|
93
|
+
private tocOptionIdsSet = new Set();
|
|
94
|
+
private anchoredElements: AnchorMap = {};
|
|
95
|
+
private lastScrollPosition!: number;
|
|
96
|
+
private observer?: IntersectionObserver;
|
|
97
|
+
private hasRendered: boolean = false;
|
|
98
|
+
private contentLoaded: boolean = false;
|
|
99
|
+
private sidebarOpen: boolean = false;
|
|
100
|
+
private rnbByTab: boolean = false;
|
|
101
|
+
|
|
102
|
+
get shouldDisplayFeedback() {
|
|
103
|
+
return this.contentLoaded && typeof Sprig !== "undefined";
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private setRNBByTab() {
|
|
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({
|
|
167
|
+
callbacks: {
|
|
168
|
+
onSearchChange: (nextSearchString: string): void => {
|
|
169
|
+
this.dispatchHighlightChange(
|
|
170
|
+
new URLSearchParams(nextSearchString).get("q") || ""
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
eventName: "sidebarsearchchange",
|
|
175
|
+
historyMethod: window.history.pushState,
|
|
176
|
+
searchParam: "q",
|
|
177
|
+
shouldStopPropagation: true,
|
|
178
|
+
target: window
|
|
179
|
+
});
|
|
180
|
+
private tocValue?: string = undefined;
|
|
181
|
+
// eslint-disable-next-line no-undef
|
|
182
|
+
private observerTimerId?: NodeJS.Timeout;
|
|
183
|
+
private didScrollToSelectedHash = false;
|
|
184
|
+
private _scrollInterval = 0;
|
|
185
|
+
|
|
186
|
+
get showToc(): boolean {
|
|
187
|
+
return this.tocOptions && this.tocOptions.length > 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ? This could be a good default for pathname in dx-breadcrumbs. Using this getter for now as a workaround.
|
|
191
|
+
get pathname(): string {
|
|
192
|
+
return window.location.pathname;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
get showBreadcrumbs(): boolean {
|
|
196
|
+
return (
|
|
197
|
+
this.breadcrumbs != null && (this.breadcrumbs as any[]).length > 1
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// This event gets triggered when navigating back/forward
|
|
202
|
+
handlePopState = (): void => {
|
|
203
|
+
if (this.showTabBasedRNB) {
|
|
204
|
+
this.restoreTabSelection();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
connectedCallback(): void {
|
|
209
|
+
const hasParentHighlightListener = closest(
|
|
210
|
+
"doc-xml-content",
|
|
211
|
+
this.template.host
|
|
212
|
+
);
|
|
213
|
+
if (!hasParentHighlightListener) {
|
|
214
|
+
window.addEventListener(
|
|
215
|
+
"highlightedtermchange",
|
|
216
|
+
this.updateHighlighted
|
|
217
|
+
);
|
|
218
|
+
this.searchSyncer.init();
|
|
219
|
+
}
|
|
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
|
+
}
|
|
251
|
+
|
|
252
|
+
private selectTabById(tabId: string) {
|
|
253
|
+
const tabs = this.getAllTabs();
|
|
254
|
+
tabs.forEach((tab: any) => {
|
|
255
|
+
if (tab.getAttribute("aria-label") === tabId) {
|
|
256
|
+
tab.click();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
renderedCallback(): void {
|
|
262
|
+
/**
|
|
263
|
+
* Note: We are adding timeout because chrome is optimizing and not triggering recent renderedCallback though elements reference is changed
|
|
264
|
+
* Also we are considering recent renderedCallback
|
|
265
|
+
*/
|
|
266
|
+
this.clearRenderObserverTimer();
|
|
267
|
+
this.observerTimerId = setTimeout(
|
|
268
|
+
this.attachInteractionObserver,
|
|
269
|
+
OBSERVER_ATTACH_WAIT_TIME
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
this.adjustNavPosition();
|
|
273
|
+
window.addEventListener("scroll", this.adjustNavPosition);
|
|
274
|
+
window.addEventListener("resize", this.adjustNavPosition);
|
|
275
|
+
|
|
276
|
+
if (!this.hasRendered) {
|
|
277
|
+
this.hasRendered = true;
|
|
278
|
+
this.setRNBByTab();
|
|
279
|
+
if (this.showTabBasedRNB) {
|
|
280
|
+
window.addEventListener("tabchanged", this.onTabChanged);
|
|
281
|
+
this.restoreTabSelection();
|
|
282
|
+
}
|
|
283
|
+
this.restoreScroll();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
disconnectedCallback(): void {
|
|
288
|
+
this.disconnectObserver();
|
|
289
|
+
window.removeEventListener(
|
|
290
|
+
"highlightedtermchange",
|
|
291
|
+
this.updateHighlighted
|
|
292
|
+
);
|
|
293
|
+
window.removeEventListener("scroll", this.adjustNavPosition);
|
|
294
|
+
window.removeEventListener("resize", this.adjustNavPosition);
|
|
295
|
+
window.removeEventListener("tabchanged", this.onTabChanged);
|
|
296
|
+
window.removeEventListener("popstate", this.handlePopState);
|
|
297
|
+
this.searchSyncer.dispose();
|
|
298
|
+
this.clearRenderObserverTimer();
|
|
299
|
+
|
|
300
|
+
window.clearInterval(this._scrollInterval);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
restoreScroll() {
|
|
304
|
+
document.body.scrollTop = document.documentElement.scrollTop =
|
|
305
|
+
window.history.state?.scrollValue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
clearRenderObserverTimer = () => {
|
|
309
|
+
if (this.observerTimerId) {
|
|
310
|
+
clearTimeout(this.observerTimerId);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
/*
|
|
315
|
+
This is a workaround for the global nav sticky header being decoupled from the doc header & doc phase.
|
|
316
|
+
We have to account for the global nav changing height due to animations.
|
|
317
|
+
*/
|
|
318
|
+
adjustNavPosition = () => {
|
|
319
|
+
const sidebarType = this.useOldSidebar
|
|
320
|
+
? "dx-sidebar-old"
|
|
321
|
+
: "dx-sidebar";
|
|
322
|
+
const sidebarEl = this.template.querySelector(sidebarType);
|
|
323
|
+
const globalNavEl = document.querySelector(
|
|
324
|
+
"hgf-c360nav"
|
|
325
|
+
) as HTMLElement;
|
|
326
|
+
const contextNavEl = document.querySelector(
|
|
327
|
+
"hgf-c360contextnav"
|
|
328
|
+
) as HTMLElement;
|
|
329
|
+
const docHeaderEl = document.querySelector(
|
|
330
|
+
".sticky-doc-header"
|
|
331
|
+
) as HTMLElement;
|
|
332
|
+
|
|
333
|
+
let docPhaseEl = (
|
|
334
|
+
this.template.querySelector("[name=doc-phase]")! as any
|
|
335
|
+
).assignedElements()[0] as HTMLSlotElement;
|
|
336
|
+
|
|
337
|
+
if (!docPhaseEl) {
|
|
338
|
+
docPhaseEl = (
|
|
339
|
+
this.template.querySelector("[name=version-banner]")! as any
|
|
340
|
+
).assignedElements()[0] as HTMLSlotElement;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!sidebarEl || !globalNavEl || !contextNavEl || !docHeaderEl) {
|
|
344
|
+
console.warn("One or more required elements are missing.");
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// sync with the browser to account for any reflows that may have happened
|
|
349
|
+
requestAnimationFrame(() => {
|
|
350
|
+
// ternary is a temporary fix for the global nav height reporting incorrectly on some browsers
|
|
351
|
+
const globalNavHeight =
|
|
352
|
+
(globalNavEl.getBoundingClientRect().height !== 72 ? 0 : 72) +
|
|
353
|
+
contextNavEl.getBoundingClientRect().height;
|
|
354
|
+
const docHeaderHeight = docHeaderEl.getBoundingClientRect().height;
|
|
355
|
+
const totalHeaderHeight = globalNavHeight + docHeaderHeight;
|
|
356
|
+
|
|
357
|
+
// Selecting the doc section heading and RNB here.
|
|
358
|
+
const docHeadingEls = Array.from(
|
|
359
|
+
document.querySelectorAll("doc-heading")
|
|
360
|
+
);
|
|
361
|
+
const rightNavBarEl = this.template.querySelector(".right-nav-bar");
|
|
362
|
+
|
|
363
|
+
sidebarEl.style.setProperty(
|
|
364
|
+
"--dx-c-content-sidebar-sticky-top",
|
|
365
|
+
`${globalNavHeight + docHeaderHeight}px`
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
docHeaderEl.style.setProperty(
|
|
369
|
+
"--dx-g-global-header-height",
|
|
370
|
+
`${globalNavHeight}px`
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
// Adjusting the doc section heading on scroll.
|
|
374
|
+
docHeadingEls.forEach((docHeadingEl) => {
|
|
375
|
+
(docHeadingEl as any).style.scrollMarginTop = docPhaseEl
|
|
376
|
+
? `${
|
|
377
|
+
totalHeaderHeight +
|
|
378
|
+
docPhaseEl.getBoundingClientRect().height +
|
|
379
|
+
40
|
|
380
|
+
}px`
|
|
381
|
+
: `${totalHeaderHeight + 40}px`;
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// Adjusting the right nav bar on scroll.
|
|
385
|
+
if (rightNavBarEl) {
|
|
386
|
+
rightNavBarEl.style.top = docPhaseEl
|
|
387
|
+
? `${
|
|
388
|
+
totalHeaderHeight +
|
|
389
|
+
docPhaseEl.getBoundingClientRect().height
|
|
390
|
+
}px`
|
|
391
|
+
: `${totalHeaderHeight}px`;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// If doc phase element exists, we need to account for its sticky position. Mobile should include the sidebar height (since it becomes sticky aswell).
|
|
395
|
+
if (docPhaseEl) {
|
|
396
|
+
docPhaseEl.style.setProperty(
|
|
397
|
+
"--doc-c-phase-top",
|
|
398
|
+
`${
|
|
399
|
+
window.innerWidth < 769
|
|
400
|
+
? globalNavHeight +
|
|
401
|
+
docHeaderHeight +
|
|
402
|
+
sidebarEl.getBoundingClientRect().height
|
|
403
|
+
: globalNavHeight + docHeaderHeight
|
|
404
|
+
}px`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
updateHighlighted = (event: Event): void =>
|
|
411
|
+
highlightTerms(
|
|
412
|
+
this.querySelectorAll(HIGHLIGHTABLE_SELECTOR),
|
|
413
|
+
(event as CustomEvent<string>).detail
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
attachInteractionObserver = (): void => {
|
|
417
|
+
if (!this.enableSlotChange) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
this.disconnectObserver();
|
|
421
|
+
|
|
422
|
+
const globalNavOffset = `-${getComputedStyle(
|
|
423
|
+
document.documentElement
|
|
424
|
+
).getPropertyValue("--dx-g-doc-header-main-nav-height")}`;
|
|
425
|
+
|
|
426
|
+
this.observer = new IntersectionObserver(
|
|
427
|
+
(entries) => {
|
|
428
|
+
entries.forEach(
|
|
429
|
+
(entry) =>
|
|
430
|
+
(this.anchoredElements[
|
|
431
|
+
entry.target.getAttribute("id")!
|
|
432
|
+
].intersect = entry.isIntersecting)
|
|
433
|
+
);
|
|
434
|
+
this.calculateActualSection();
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
rootMargin: globalNavOffset.trim()
|
|
438
|
+
}
|
|
439
|
+
);
|
|
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
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
onSlotChange(): void {
|
|
466
|
+
this.updateRNB();
|
|
467
|
+
this.contentLoaded = true;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// eslint-disable-next-line no-undef
|
|
471
|
+
private updateTocItems(headingElements: NodeListOf<Element>): void {
|
|
472
|
+
const tocOptions = [];
|
|
473
|
+
|
|
474
|
+
for (const headingElement of headingElements as any) {
|
|
475
|
+
headingElement.id = headingElement.hash;
|
|
476
|
+
|
|
477
|
+
// Update tocOptions from anchorTags only for H2, consider default as 2 as per component
|
|
478
|
+
const headingAriaLevel =
|
|
479
|
+
headingElement.attributes["aria-level"]?.nodeValue || "2";
|
|
480
|
+
const isH2 = headingAriaLevel === "2";
|
|
481
|
+
|
|
482
|
+
if (isH2) {
|
|
483
|
+
const tocItem = {
|
|
484
|
+
anchor: `#${headingElement.hash}`,
|
|
485
|
+
id: headingElement.id,
|
|
486
|
+
label: headingElement.header
|
|
487
|
+
};
|
|
488
|
+
tocOptions.push(tocItem);
|
|
489
|
+
this.tocOptionIdsSet.add(headingElement.id);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
this._tocOptions = tocOptions;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
private disconnectObserver(): void {
|
|
497
|
+
if (this.observer) {
|
|
498
|
+
this.observer.disconnect();
|
|
499
|
+
this.observer = undefined;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// eslint-disable-next-line no-undef
|
|
504
|
+
private scrollToHash(headingElements: NodeListOf<Element>): void {
|
|
505
|
+
let { hash } = window.location;
|
|
506
|
+
if (hash) {
|
|
507
|
+
hash = hash.substr(1);
|
|
508
|
+
|
|
509
|
+
const docHeaderEl = document.querySelector(
|
|
510
|
+
".sticky-doc-header"
|
|
511
|
+
) as HTMLElement;
|
|
512
|
+
const globalNavEl = document.querySelector(
|
|
513
|
+
"hgf-c360nav"
|
|
514
|
+
) as HTMLElement;
|
|
515
|
+
const contextNavEl = document.querySelector(
|
|
516
|
+
"hgf-c360contextnav"
|
|
517
|
+
) as HTMLElement;
|
|
518
|
+
|
|
519
|
+
const headerHeight =
|
|
520
|
+
docHeaderEl?.offsetHeight +
|
|
521
|
+
globalNavEl?.offsetHeight +
|
|
522
|
+
contextNavEl?.offsetHeight;
|
|
523
|
+
|
|
524
|
+
const docPhaseEl = (
|
|
525
|
+
this.template.querySelector("[name=doc-phase]")! as any
|
|
526
|
+
).assignedElements()[0] as HTMLSlotElement;
|
|
527
|
+
|
|
528
|
+
const offset = docPhaseEl
|
|
529
|
+
? headerHeight + docPhaseEl.offsetHeight
|
|
530
|
+
: headerHeight;
|
|
531
|
+
|
|
532
|
+
for (const headingElement of headingElements as any) {
|
|
533
|
+
if (headingElement.getAttribute("id") === hash) {
|
|
534
|
+
this.scrollIntoViewWithOffset(headingElement, offset);
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
private scrollIntoViewWithOffset(
|
|
542
|
+
headingElement: HTMLElement,
|
|
543
|
+
offset: number
|
|
544
|
+
) {
|
|
545
|
+
window.scrollTo({
|
|
546
|
+
behavior: "auto",
|
|
547
|
+
top:
|
|
548
|
+
headingElement.getBoundingClientRect().top -
|
|
549
|
+
document.body.getBoundingClientRect().top -
|
|
550
|
+
offset
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
private calculateActualSection(): void {
|
|
555
|
+
const currentScrollPosition = document.documentElement.scrollTop;
|
|
556
|
+
const id = Object.keys(this.anchoredElements).find(
|
|
557
|
+
(_id) => this.anchoredElements[_id].intersect
|
|
558
|
+
);
|
|
559
|
+
if (id) {
|
|
560
|
+
this.assignElementId(id);
|
|
561
|
+
} else if (currentScrollPosition < this.lastScrollPosition) {
|
|
562
|
+
// The user has scroll up since last update
|
|
563
|
+
this.assignElementId(this.calculatePreviousElementId());
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
this.lastScrollPosition = currentScrollPosition;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
private calculatePreviousElementId(): string | undefined {
|
|
570
|
+
const keys = Object.keys(this.anchoredElements);
|
|
571
|
+
const currentIndex = keys.findIndex((id) => this.tocValue === id);
|
|
572
|
+
|
|
573
|
+
return currentIndex > 0 ? keys[currentIndex - 1] : undefined;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
private assignElementId(id: string | undefined): void {
|
|
577
|
+
// Change toc(RNB) highlight only for H2
|
|
578
|
+
if (this.tocOptionIdsSet.has(id)) {
|
|
579
|
+
this.tocValue = id;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
private dispatchHighlightChange(term: string): void {
|
|
584
|
+
this.dispatchEvent(
|
|
585
|
+
new CustomEvent("highlightedtermchange", {
|
|
586
|
+
detail: term,
|
|
587
|
+
bubbles: true,
|
|
588
|
+
composed: true
|
|
589
|
+
})
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
private updateHighlightsAndSearch(nextSearchString: string): void {
|
|
594
|
+
const nextSearchParam =
|
|
595
|
+
new URLSearchParams(nextSearchString).get("q") || "";
|
|
596
|
+
this.setSidebarInputValue(nextSearchParam);
|
|
597
|
+
this.dispatchHighlightChange(nextSearchParam);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private onToggleSidebar(e: CustomEvent): void {
|
|
601
|
+
this.sidebarOpen = e.detail.open;
|
|
602
|
+
|
|
603
|
+
// eslint-disable-next-line @lwc/lwc/no-document-query
|
|
604
|
+
const footer = document.querySelector("dx-footer") as HTMLElement;
|
|
605
|
+
|
|
606
|
+
if (footer) {
|
|
607
|
+
footer.style.display = this.sidebarOpen ? "none" : "block";
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
@import "dxHelpers/reset";
|
|
2
|
+
@import "dxHelpers/text";
|
|
3
|
+
|
|
4
|
+
.container {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
gap: var(--dx-g-spacing-md);
|
|
8
|
+
flex: 1;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.doc-do-dont-header {
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: var(--dx-g-spacing-sm);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.doc-do-dont-label {
|
|
18
|
+
font-family: var(--dx-g-font-display);
|
|
19
|
+
font-size: var(--dx-g-spacing-md);
|
|
20
|
+
font-weight: var(--dx-g-font-demi);
|
|
21
|
+
line-height: var(--dx-g-spacing-lg);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.doc-do-color {
|
|
25
|
+
color: var(--dx-g-green-vibrant-50);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.doc-dont-color {
|
|
29
|
+
color: var(--dx-g-red-vibrant-30);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.do-dont-image-container {
|
|
33
|
+
display: flex;
|
|
34
|
+
max-height: 480px;
|
|
35
|
+
min-height: 140px;
|
|
36
|
+
padding: var(--dx-g-spacing-3xl) var(--dx-g-spacing-2xl);
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
align-items: center;
|
|
40
|
+
flex: 1;
|
|
41
|
+
border-radius: var(--dx-g-spacing-sm);
|
|
42
|
+
border: 1px solid var(--dx-g-brand-default-color-border-2);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.doc-do-dont-img {
|
|
46
|
+
object-fit: contain;
|
|
47
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="container">
|
|
3
|
+
<div class="doc-do-dont-header">
|
|
4
|
+
<template lwc:if={isDo}>
|
|
5
|
+
<dx-icon
|
|
6
|
+
symbol="success"
|
|
7
|
+
size="large"
|
|
8
|
+
color="green-vibrant-50"
|
|
9
|
+
></dx-icon>
|
|
10
|
+
<div class="doc-do-dont-label doc-do-color">Do</div>
|
|
11
|
+
</template>
|
|
12
|
+
<template lwc:else>
|
|
13
|
+
<dx-icon
|
|
14
|
+
symbol="clear"
|
|
15
|
+
size="large"
|
|
16
|
+
color="red-vibrant-30"
|
|
17
|
+
class="doc-do-dont-icon"
|
|
18
|
+
></dx-icon>
|
|
19
|
+
<div class="doc-do-dont-label doc-dont-color">Don't</div>
|
|
20
|
+
</template>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="do-dont-image-container">
|
|
23
|
+
<img class="doc-do-dont-img" src={imgSrc} alt={caption} />
|
|
24
|
+
</div>
|
|
25
|
+
<div class="dx-text-body-4">{caption}</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LightningElement, api } from "lwc";
|
|
2
|
+
import { normalizeBoolean } from "dxUtils/normalizers";
|
|
3
|
+
|
|
4
|
+
export default class DoDont extends LightningElement {
|
|
5
|
+
@api caption: string = "";
|
|
6
|
+
@api imgSrc!: string;
|
|
7
|
+
_isDo: boolean = false;
|
|
8
|
+
|
|
9
|
+
@api
|
|
10
|
+
get isDo(): boolean {
|
|
11
|
+
return this._isDo;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
set isDo(value) {
|
|
15
|
+
this._isDo = normalizeBoolean(value);
|
|
16
|
+
}
|
|
17
|
+
}
|