@salesforcedevs/docs-components 0.0.4 → 0.0.5-edit

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 (140) hide show
  1. package/lwc.config.json +25 -2
  2. package/package.json +18 -7
  3. package/src/modules/README.md +41 -0
  4. package/src/modules/doc/amfModelParser/amfModelParser.ts +674 -0
  5. package/src/modules/doc/amfReference/amfReference.css +25 -0
  6. package/src/modules/doc/amfReference/amfReference.html +60 -0
  7. package/src/modules/doc/amfReference/amfReference.ts +1494 -0
  8. package/src/modules/doc/amfReference/constants.ts +76 -0
  9. package/src/modules/doc/amfReference/types.ts +125 -0
  10. package/src/modules/doc/amfTopic/amfTopic.css +21 -0
  11. package/src/modules/doc/amfTopic/amfTopic.html +3 -0
  12. package/src/modules/doc/amfTopic/amfTopic.ts +111 -0
  13. package/src/modules/doc/amfTopic/types.ts +56 -0
  14. package/src/modules/doc/amfTopic/utils.ts +136 -0
  15. package/src/modules/doc/breadcrumbItem/breadcrumbItem.css +51 -0
  16. package/src/modules/doc/breadcrumbItem/breadcrumbItem.html +5 -0
  17. package/src/modules/doc/breadcrumbItem/breadcrumbItem.ts +71 -0
  18. package/src/modules/doc/breadcrumbs/breadcrumbs.css +27 -0
  19. package/src/modules/doc/breadcrumbs/breadcrumbs.html +58 -0
  20. package/src/modules/doc/breadcrumbs/breadcrumbs.ts +183 -0
  21. package/src/modules/doc/chat/README.md +179 -0
  22. package/src/modules/doc/chat/chat.css +821 -0
  23. package/src/modules/doc/chat/chat.html +241 -0
  24. package/src/modules/doc/chat/chat.ts +586 -0
  25. package/src/modules/doc/componentPlayground/componentPlayground.css +22 -0
  26. package/src/modules/doc/componentPlayground/componentPlayground.html +20 -0
  27. package/src/modules/doc/componentPlayground/componentPlayground.ts +29 -0
  28. package/src/modules/doc/content/content.css +382 -6
  29. package/src/modules/doc/content/content.html +3 -2
  30. package/src/modules/doc/content/content.ts +287 -110
  31. package/src/modules/doc/contentCallout/contentCallout.css +25 -26
  32. package/src/modules/doc/contentCallout/contentCallout.html +13 -4
  33. package/src/modules/doc/contentCallout/contentCallout.ts +22 -11
  34. package/src/modules/doc/contentLayout/contentLayout.css +13 -0
  35. package/src/modules/doc/contentLayout/contentLayout.html +73 -0
  36. package/src/modules/doc/contentLayout/contentLayout.ts +531 -0
  37. package/src/modules/doc/contentMedia/contentMedia.css +49 -0
  38. package/src/modules/doc/contentMedia/contentMedia.html +23 -0
  39. package/src/modules/doc/contentMedia/contentMedia.ts +34 -0
  40. package/src/modules/doc/doDont/doDont.css +47 -0
  41. package/src/modules/doc/doDont/doDont.html +27 -0
  42. package/src/modules/doc/doDont/doDont.ts +17 -0
  43. package/src/modules/doc/editFile/editFile.css +505 -0
  44. package/src/modules/doc/editFile/editFile.html +164 -0
  45. package/src/modules/doc/editFile/editFile.ts +213 -0
  46. package/src/modules/doc/header/header.css +132 -0
  47. package/src/modules/doc/header/header.html +55 -0
  48. package/src/modules/doc/header/header.ts +120 -0
  49. package/src/modules/doc/heading/heading.css +33 -0
  50. package/src/modules/doc/heading/heading.html +14 -0
  51. package/src/modules/doc/heading/heading.ts +67 -0
  52. package/src/modules/doc/headingAnchor/headingAnchor.css +33 -0
  53. package/src/modules/doc/headingAnchor/headingAnchor.html +19 -0
  54. package/src/modules/doc/headingAnchor/headingAnchor.ts +43 -0
  55. package/src/modules/doc/headingContent/headingContent.css +53 -0
  56. package/src/modules/doc/headingContent/headingContent.html +13 -0
  57. package/src/modules/doc/headingContent/headingContent.ts +30 -0
  58. package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +1 -0
  59. package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +68 -0
  60. package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +168 -0
  61. package/src/modules/doc/nav/nav.css +4 -2
  62. package/src/modules/doc/nav/nav.html +8 -13
  63. package/src/modules/doc/nav/nav.ts +1 -1
  64. package/src/modules/doc/overview/overview.css +40 -0
  65. package/src/modules/doc/overview/overview.html +34 -0
  66. package/src/modules/doc/overview/overview.ts +12 -0
  67. package/src/modules/doc/phase/phase.css +70 -0
  68. package/src/modules/doc/phase/phase.html +38 -0
  69. package/src/modules/doc/phase/phase.ts +93 -0
  70. package/src/modules/doc/specificationContent/specificationContent.css +36 -0
  71. package/src/modules/doc/specificationContent/specificationContent.html +171 -0
  72. package/src/modules/doc/specificationContent/specificationContent.ts +127 -0
  73. package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
  74. package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
  75. package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
  76. package/src/modules/doc/toc/toc.html +11 -6
  77. package/src/modules/doc/toc/toc.ts +2 -6
  78. package/src/modules/doc/toolbar/toolbar.html +8 -1
  79. package/src/modules/doc/toolbar/toolbar.ts +1 -1
  80. package/src/modules/doc/versionPicker/versionPicker.css +64 -0
  81. package/src/modules/doc/versionPicker/versionPicker.html +38 -0
  82. package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
  83. package/src/modules/doc/xmlContent/types.ts +120 -0
  84. package/src/modules/doc/xmlContent/utils.ts +163 -0
  85. package/src/modules/doc/xmlContent/xmlContent.css +54 -0
  86. package/src/modules/doc/xmlContent/xmlContent.html +52 -0
  87. package/src/modules/doc/xmlContent/xmlContent.ts +792 -0
  88. package/src/modules/docHelpers/amfStyle/amfStyle.css +355 -0
  89. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
  90. package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
  91. package/src/modules/docHelpers/status/status.css +22 -0
  92. package/src/modules/docUtils/searchSyncer/searchSyncer.ts +86 -0
  93. package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
  94. package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
  95. package/src/modules/docUtils/utils/utils.ts +32 -0
  96. package/src/modules/doc/container/__benchmarks__/container.benchmark.js +0 -43
  97. package/src/modules/doc/container/__mocks__/mockAvailableLanguages.js +0 -8
  98. package/src/modules/doc/container/__mocks__/mockAvailableVersions.js +0 -122
  99. package/src/modules/doc/container/__mocks__/mockContentFetchResponse.json +0 -5
  100. package/src/modules/doc/container/__mocks__/mockDocContent.js +0 -29
  101. package/src/modules/doc/container/__mocks__/mockNavigationFetchResponse.json +0 -4061
  102. package/src/modules/doc/container/__mocks__/mockPageReference.js +0 -8
  103. package/src/modules/doc/container/__mocks__/mockPdfUrl.js +0 -1
  104. package/src/modules/doc/container/__mocks__/mockSelectedLanguage.js +0 -8
  105. package/src/modules/doc/container/__mocks__/mockSelectedVersion.js +0 -8
  106. package/src/modules/doc/container/__mocks__/mockToc.js +0 -146
  107. package/src/modules/doc/container/__tests__/container.test.ts +0 -82
  108. package/src/modules/doc/container/container.css +0 -33
  109. package/src/modules/doc/container/container.html +0 -23
  110. package/src/modules/doc/container/container.stories.ts +0 -18
  111. package/src/modules/doc/container/container.ts +0 -360
  112. package/src/modules/doc/content/__tests__/content.test.ts +0 -30
  113. package/src/modules/doc/content/__tests__/mockDocContent.ts +0 -29
  114. package/src/modules/doc/content/__tests__/mockPageReference.ts +0 -8
  115. package/src/modules/doc/contentCallout/__tests__/contentCallout.test.ts +0 -80
  116. package/src/modules/doc/contentCallout/__tests__/mockProps.ts +0 -14
  117. package/src/modules/doc/contentCallout/contentCallout.stories.ts +0 -29
  118. package/src/modules/doc/nav/__tests__/mockAvailableLanguages.ts +0 -8
  119. package/src/modules/doc/nav/__tests__/mockAvailableVersions.ts +0 -122
  120. package/src/modules/doc/nav/__tests__/mockPageReference.ts +0 -8
  121. package/src/modules/doc/nav/__tests__/mockPdfUrl.ts +0 -1
  122. package/src/modules/doc/nav/__tests__/mockSelectedLanguage.ts +0 -8
  123. package/src/modules/doc/nav/__tests__/mockSelectedVersion.ts +0 -8
  124. package/src/modules/doc/nav/__tests__/mockToc.ts +0 -146
  125. package/src/modules/doc/nav/__tests__/nav.test.ts +0 -66
  126. package/src/modules/doc/prismcss/prismcss.css +0 -184
  127. package/src/modules/doc/prismjs/prismjs.html +0 -3
  128. package/src/modules/doc/prismjs/prismjs.ts +0 -1842
  129. package/src/modules/doc/search/__tests__/search.test.ts +0 -20
  130. package/src/modules/doc/search/search.html +0 -1
  131. package/src/modules/doc/search/search.ts +0 -3
  132. package/src/modules/doc/toc/__tests__/mockPageReference.ts +0 -8
  133. package/src/modules/doc/toc/__tests__/mockToc.ts +0 -146
  134. package/src/modules/doc/toc/__tests__/toc.test.ts +0 -29
  135. package/src/modules/doc/toolbar/__tests__/mockAvailableLanguages.ts +0 -8
  136. package/src/modules/doc/toolbar/__tests__/mockAvailableVersions.ts +0 -122
  137. package/src/modules/doc/toolbar/__tests__/mockPdfUrl.ts +0 -1
  138. package/src/modules/doc/toolbar/__tests__/mockSelectedLanguage.ts +0 -8
  139. package/src/modules/doc/toolbar/__tests__/mockSelectedVersion.ts +0 -8
  140. package/src/modules/doc/toolbar/__tests__/toolbar.test.ts +0 -44
@@ -0,0 +1,73 @@
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
+ dev-center={devCenter}
15
+ brand={brand}
16
+ >
17
+ <slot name="sidebar-header" slot="version-picker"></slot>
18
+ </dx-sidebar-old>
19
+ </template>
20
+ <template lwc:else>
21
+ <dx-sidebar
22
+ class="is-sticky left-nav-bar"
23
+ trees={sidebarContent}
24
+ value={sidebarValue}
25
+ header={sidebarHeader}
26
+ coveo-organization-id={coveoOrganizationId}
27
+ coveo-public-access-token={coveoPublicAccessToken}
28
+ coveo-search-hub={coveoSearchHub}
29
+ coveo-advanced-query-config={coveoAdvancedQueryConfig}
30
+ ontogglesidebar={onToggleSidebar}
31
+ languages={languages}
32
+ language={language}
33
+ bail-href={bailHref}
34
+ bail-label={bailLabel}
35
+ dev-center={devCenter}
36
+ brand={brand}
37
+ >
38
+ <slot name="sidebar-header" slot="version-picker"></slot>
39
+ </dx-sidebar>
40
+ </template>
41
+ <div class="content-body-doc-phase-container">
42
+ <slot name="doc-phase"></slot>
43
+ <slot name="version-banner"></slot>
44
+ <div class="content-body-container">
45
+ <div class="content-body">
46
+ <!-- <doc-edit-file
47
+ class="edit-file-positioned"
48
+ file-name={sidebarValue}
49
+ title="Edit File"
50
+ ></doc-edit-file> -->
51
+ <doc-breadcrumbs
52
+ lwc:if={showBreadcrumbs}
53
+ breadcrumbs={breadcrumbs}
54
+ ></doc-breadcrumbs>
55
+ <slot onslotchange={onSlotChange}></slot>
56
+ <doc-sprig-survey
57
+ lwc:if={shouldDisplayFeedback}
58
+ ></doc-sprig-survey>
59
+ </div>
60
+ <div lwc:if={showToc} class="right-nav-bar is-sticky">
61
+ <dx-toc
62
+ header={tocTitle}
63
+ options={tocOptions}
64
+ value={tocValue}
65
+ ></dx-toc>
66
+ </div>
67
+ </div>
68
+ <div lwc:if={showFooter} class="footer-container">
69
+ <dx-footer variant="no-signup"></dx-footer>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </template>
@@ -0,0 +1,531 @@
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
+
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
+ @api devCenter: any;
46
+ @api brand: any;
47
+
48
+ // This is needed for now to prevent failing snapshot tests due to links in the footer
49
+ @api showFooter = false;
50
+
51
+ @api
52
+ get breadcrumbs() {
53
+ return this._breadcrumbs;
54
+ }
55
+
56
+ set breadcrumbs(value) {
57
+ if (value) {
58
+ this._breadcrumbs = toJson(value);
59
+ }
60
+ }
61
+
62
+ @api
63
+ get sidebarContent() {
64
+ return this._sidebarContent;
65
+ }
66
+
67
+ set sidebarContent(value: any) {
68
+ this._sidebarContent = toJson(value);
69
+ }
70
+
71
+ @api
72
+ get tocOptions() {
73
+ return this._tocOptions;
74
+ }
75
+
76
+ set tocOptions(value) {
77
+ this._tocOptions = toJson(value);
78
+ }
79
+
80
+ @api
81
+ setSidebarInputValue(searchTerm: string): void {
82
+ (this.template.querySelector("dx-sidebar") as any)?.setInputValue(
83
+ searchTerm
84
+ );
85
+ }
86
+
87
+ @track
88
+ protected _sidebarContent: unknown;
89
+
90
+ protected _breadcrumbs = null;
91
+
92
+ @track
93
+ protected _tocOptions!: Array<unknown>;
94
+
95
+ protected tocOptionIdsSet = new Set();
96
+ protected anchoredElements: AnchorMap = {};
97
+ protected lastScrollPosition!: number;
98
+ protected observer?: IntersectionObserver;
99
+ protected hasRendered: boolean = false;
100
+ protected contentLoaded: boolean = false;
101
+ protected sidebarOpen: boolean = false;
102
+
103
+ get shouldDisplayFeedback() {
104
+ return this.contentLoaded && typeof Sprig !== "undefined";
105
+ }
106
+
107
+ protected searchSyncer = new SearchSyncer({
108
+ callbacks: {
109
+ onSearchChange: (nextSearchString: string): void => {
110
+ this.dispatchHighlightChange(
111
+ new URLSearchParams(nextSearchString).get("q") || ""
112
+ );
113
+ }
114
+ },
115
+ eventName: "sidebarsearchchange",
116
+ historyMethod: window.history.pushState,
117
+ searchParam: "q",
118
+ shouldStopPropagation: true,
119
+ target: window
120
+ });
121
+ protected tocValue?: string = undefined;
122
+ // eslint-disable-next-line no-undef
123
+ protected observerTimerId?: NodeJS.Timeout;
124
+ protected didScrollToSelectedHash = false;
125
+ protected _scrollInterval = 0;
126
+
127
+ get showToc(): boolean {
128
+ return this.tocOptions && this.tocOptions.length > 0;
129
+ }
130
+
131
+ // ? This could be a good default for pathname in dx-breadcrumbs. Using this getter for now as a workaround.
132
+ get pathname(): string {
133
+ return window.location.pathname;
134
+ }
135
+
136
+ get showBreadcrumbs(): boolean {
137
+ return (
138
+ this.breadcrumbs != null && (this.breadcrumbs as any[]).length > 1
139
+ );
140
+ }
141
+
142
+ connectedCallback(): void {
143
+ const hasParentHighlightListener = closest(
144
+ "doc-xml-content",
145
+ this.template.host
146
+ );
147
+ if (!hasParentHighlightListener) {
148
+ window.addEventListener(
149
+ "highlightedtermchange",
150
+ this.updateHighlighted
151
+ );
152
+ this.searchSyncer.init();
153
+ }
154
+ }
155
+
156
+ // Placeholder for childs renderedCallback
157
+ protected postRenderedCallback?(): void;
158
+
159
+ renderedCallback(): void {
160
+ /**
161
+ * Note: We are adding timeout because chrome is optimizing and not triggering recent renderedCallback though elements reference is changed
162
+ * Also we are considering recent renderedCallback
163
+ */
164
+ this.clearRenderObserverTimer();
165
+ this.observerTimerId = setTimeout(
166
+ this.attachInteractionObserver,
167
+ OBSERVER_ATTACH_WAIT_TIME
168
+ );
169
+
170
+ this.adjustNavPosition();
171
+ window.addEventListener("scroll", this.adjustNavPosition);
172
+ window.addEventListener("resize", this.adjustNavPosition);
173
+
174
+ if (!this.hasRendered) {
175
+ this.hasRendered = true;
176
+ this.restoreScroll();
177
+
178
+ // Dynamically call `renderedCallbackForLwcContentLayout` if it exists
179
+ this.postRenderedCallback?.();
180
+ }
181
+ }
182
+
183
+ disconnectedCallback(): void {
184
+ this.disconnectObserver();
185
+ window.removeEventListener(
186
+ "highlightedtermchange",
187
+ this.updateHighlighted
188
+ );
189
+ window.removeEventListener("scroll", this.adjustNavPosition);
190
+ window.removeEventListener("resize", this.adjustNavPosition);
191
+ this.searchSyncer.dispose();
192
+ this.clearRenderObserverTimer();
193
+
194
+ window.clearInterval(this._scrollInterval);
195
+ }
196
+
197
+ restoreScroll() {
198
+ document.body.scrollTop = document.documentElement.scrollTop =
199
+ window.history.state?.scrollValue;
200
+ }
201
+
202
+ clearRenderObserverTimer = () => {
203
+ if (this.observerTimerId) {
204
+ clearTimeout(this.observerTimerId);
205
+ }
206
+ };
207
+
208
+ /*
209
+ This is a workaround for the global nav sticky header being decoupled from the doc header & doc phase.
210
+ We have to account for the global nav changing height due to animations.
211
+ */
212
+ adjustNavPosition = () => {
213
+ const sidebarType = this.useOldSidebar
214
+ ? "dx-sidebar-old"
215
+ : "dx-sidebar";
216
+ const sidebarEl = this.template.querySelector(sidebarType);
217
+ const globalNavEl = document.querySelector(
218
+ "hgf-c360nav"
219
+ ) as HTMLElement;
220
+ const contextNavEl = document.querySelector(
221
+ "hgf-c360contextnav"
222
+ ) as HTMLElement;
223
+ const docHeaderEl = document.querySelector(
224
+ ".sticky-doc-header"
225
+ ) as HTMLElement;
226
+
227
+ let docPhaseEl = (
228
+ this.template.querySelector("[name=doc-phase]")! as any
229
+ ).assignedElements()[0] as HTMLSlotElement;
230
+
231
+ if (!docPhaseEl) {
232
+ docPhaseEl = (
233
+ this.template.querySelector("[name=version-banner]")! as any
234
+ ).assignedElements()[0] as HTMLSlotElement;
235
+ }
236
+
237
+ if (!sidebarEl || !globalNavEl || !contextNavEl || !docHeaderEl) {
238
+ console.warn("One or more required elements are missing.");
239
+ return;
240
+ }
241
+
242
+ // sync with the browser to account for any reflows that may have happened
243
+ requestAnimationFrame(() => {
244
+ // ternary is a temporary fix for the global nav height reporting incorrectly on some browsers
245
+ const globalNavHeight =
246
+ (globalNavEl.getBoundingClientRect().height !== 72 ? 0 : 72) +
247
+ contextNavEl.getBoundingClientRect().height;
248
+ const docHeaderHeight = docHeaderEl.getBoundingClientRect().height;
249
+ const totalHeaderHeight = globalNavHeight + docHeaderHeight;
250
+
251
+ // Selecting the doc section heading and RNB here.
252
+ const docHeadingEls = Array.from(
253
+ document.querySelectorAll("doc-heading")
254
+ );
255
+ const rightNavBarEl = this.template.querySelector(".right-nav-bar");
256
+
257
+ sidebarEl.style.setProperty(
258
+ "--dx-c-content-sidebar-sticky-top",
259
+ `${globalNavHeight + docHeaderHeight}px`
260
+ );
261
+
262
+ docHeaderEl.style.setProperty(
263
+ "--dx-g-global-header-height",
264
+ `${globalNavHeight}px`
265
+ );
266
+
267
+ // Adjusting the doc section heading on scroll.
268
+ docHeadingEls.forEach((docHeadingEl) => {
269
+ (docHeadingEl as any).style.scrollMarginTop = docPhaseEl
270
+ ? `${
271
+ totalHeaderHeight +
272
+ docPhaseEl.getBoundingClientRect().height +
273
+ 40
274
+ }px`
275
+ : `${totalHeaderHeight + 40}px`;
276
+ });
277
+
278
+ // Adjusting the right nav bar on scroll.
279
+ if (rightNavBarEl) {
280
+ rightNavBarEl.style.top = docPhaseEl
281
+ ? `${
282
+ totalHeaderHeight +
283
+ docPhaseEl.getBoundingClientRect().height
284
+ }px`
285
+ : `${totalHeaderHeight}px`;
286
+ }
287
+
288
+ // If doc phase element exists, we need to account for its sticky position. Mobile should include the sidebar height (since it becomes sticky aswell).
289
+ if (docPhaseEl) {
290
+ docPhaseEl.style.setProperty(
291
+ "--doc-c-phase-top",
292
+ `${
293
+ window.innerWidth < 769
294
+ ? globalNavHeight +
295
+ docHeaderHeight +
296
+ sidebarEl.getBoundingClientRect().height
297
+ : globalNavHeight + docHeaderHeight
298
+ }px`
299
+ );
300
+ }
301
+ });
302
+ };
303
+
304
+ updateHighlighted = (event: Event): void =>
305
+ highlightTerms(
306
+ this.querySelectorAll(HIGHLIGHTABLE_SELECTOR),
307
+ (event as CustomEvent<string>).detail
308
+ );
309
+
310
+ protected getHeadingElements() {
311
+ // Note: We are doing document.querySelectorAll as a quick fix as we are not getting heading elements reference this.querySelectorAll
312
+ const headingElements = document.querySelectorAll(TOC_HEADER_TAG);
313
+ return headingElements;
314
+ }
315
+
316
+ updateHeadingForRNB(): void {
317
+ const headingElements = this.getHeadingElements();
318
+ this.addObserverAndScroll(headingElements);
319
+ }
320
+
321
+ addObserverAndScroll(headingElements: any) {
322
+ for (const headingElement of headingElements as any) {
323
+ // Add headingElements to intersectionObserver for highlighting respective RNB item when user scroll
324
+ const id = headingElement.getAttribute("id")!;
325
+ this.anchoredElements[id] = {
326
+ id,
327
+ intersect: false
328
+ };
329
+ this.observer?.observe(headingElement);
330
+ }
331
+
332
+ if (!this.didScrollToSelectedHash) {
333
+ this.didScrollToSelectedHash = true;
334
+ this.scrollToHash(headingElements);
335
+ }
336
+ }
337
+
338
+ attachInteractionObserver = (): void => {
339
+ if (!this.enableSlotChange) {
340
+ return;
341
+ }
342
+ this.disconnectObserver();
343
+
344
+ const globalNavOffset = `-${getComputedStyle(
345
+ document.documentElement
346
+ ).getPropertyValue("--dx-g-doc-header-main-nav-height")}`;
347
+
348
+ this.observer = new IntersectionObserver(
349
+ (entries) => {
350
+ entries.forEach(
351
+ (entry) =>
352
+ (this.anchoredElements[
353
+ entry.target.getAttribute("id")!
354
+ ].intersect = entry.isIntersecting)
355
+ );
356
+ this.calculateActualSection();
357
+ },
358
+ {
359
+ rootMargin: globalNavOffset.trim()
360
+ }
361
+ );
362
+ this.updateHeadingForRNB();
363
+ };
364
+
365
+ // eslint-disable-next-line no-undef
366
+ updateTocItems(headingElements: any): void {
367
+ const tocOptions = [];
368
+
369
+ for (const headingElement of headingElements as any) {
370
+ headingElement.id = headingElement.hash;
371
+
372
+ // Update tocOptions from anchorTags only for H2, consider default as 2 as per component
373
+ const headingAriaLevel =
374
+ headingElement.attributes["aria-level"]?.nodeValue || "2";
375
+ const isH2 = headingAriaLevel === "2";
376
+
377
+ if (isH2) {
378
+ const tocItem = {
379
+ anchor: `#${headingElement.hash}`,
380
+ id: headingElement.id,
381
+ label: headingElement.header
382
+ };
383
+ tocOptions.push(tocItem);
384
+ this.tocOptionIdsSet.add(headingElement.id);
385
+ }
386
+ }
387
+
388
+ this._tocOptions = tocOptions;
389
+ }
390
+
391
+ setHashAndHeaderForDocHeading(headingElements: any) {
392
+ for (const headingElement of headingElements as any) {
393
+ // Sometimes elements hash and header is not being set when slot content is wrapped with div
394
+ if (!headingElement.hash) {
395
+ headingElement.hash = headingElement.attributes.hash?.nodeValue;
396
+ }
397
+
398
+ if (!headingElement.header) {
399
+ headingElement.header =
400
+ headingElement.attributes.header?.nodeValue;
401
+ }
402
+ }
403
+
404
+ this.updateTocItems(headingElements);
405
+ }
406
+
407
+ updateRNB = () => {
408
+ const headingElements = this.getHeadingElements();
409
+ this.setHashAndHeaderForDocHeading(headingElements);
410
+ };
411
+
412
+ onSlotChange(): void {
413
+ this.updateRNB();
414
+ this.contentLoaded = true;
415
+ }
416
+
417
+ protected disconnectObserver(): void {
418
+ if (this.observer) {
419
+ this.observer.disconnect();
420
+ this.observer = undefined;
421
+ }
422
+ }
423
+
424
+ // eslint-disable-next-line no-undef
425
+ protected scrollToHash(headingElements: NodeListOf<Element>): void {
426
+ let { hash } = window.location;
427
+ if (hash) {
428
+ hash = hash.substr(1);
429
+
430
+ const docHeaderEl = document.querySelector(
431
+ ".sticky-doc-header"
432
+ ) as HTMLElement;
433
+ const globalNavEl = document.querySelector(
434
+ "hgf-c360nav"
435
+ ) as HTMLElement;
436
+ const contextNavEl = document.querySelector(
437
+ "hgf-c360contextnav"
438
+ ) as HTMLElement;
439
+
440
+ const headerHeight =
441
+ docHeaderEl?.offsetHeight +
442
+ globalNavEl?.offsetHeight +
443
+ contextNavEl?.offsetHeight;
444
+
445
+ const docPhaseEl = (
446
+ this.template.querySelector("[name=doc-phase]")! as any
447
+ ).assignedElements()[0] as HTMLSlotElement;
448
+
449
+ const offset = docPhaseEl
450
+ ? headerHeight + docPhaseEl.offsetHeight
451
+ : headerHeight;
452
+
453
+ for (const headingElement of headingElements as any) {
454
+ if (headingElement.getAttribute("id") === hash) {
455
+ this.scrollIntoViewWithOffset(headingElement, offset);
456
+ break;
457
+ }
458
+ }
459
+ }
460
+ }
461
+
462
+ protected scrollIntoViewWithOffset(
463
+ headingElement: HTMLElement,
464
+ offset: number
465
+ ) {
466
+ window.scrollTo({
467
+ behavior: "auto",
468
+ top:
469
+ headingElement.getBoundingClientRect().top -
470
+ document.body.getBoundingClientRect().top -
471
+ offset
472
+ });
473
+ }
474
+
475
+ protected calculateActualSection(): void {
476
+ const currentScrollPosition = document.documentElement.scrollTop;
477
+ const id = Object.keys(this.anchoredElements).find(
478
+ (_id) => this.anchoredElements[_id].intersect
479
+ );
480
+ if (id) {
481
+ this.assignElementId(id);
482
+ } else if (currentScrollPosition < this.lastScrollPosition) {
483
+ // The user has scroll up since last update
484
+ this.assignElementId(this.calculatePreviousElementId());
485
+ }
486
+
487
+ this.lastScrollPosition = currentScrollPosition;
488
+ }
489
+
490
+ protected calculatePreviousElementId(): string | undefined {
491
+ const keys = Object.keys(this.anchoredElements);
492
+ const currentIndex = keys.findIndex((id) => this.tocValue === id);
493
+
494
+ return currentIndex > 0 ? keys[currentIndex - 1] : undefined;
495
+ }
496
+
497
+ protected assignElementId(id: string | undefined): void {
498
+ // Change toc(RNB) highlight only for H2
499
+ if (this.tocOptionIdsSet.has(id)) {
500
+ this.tocValue = id;
501
+ }
502
+ }
503
+
504
+ protected dispatchHighlightChange(term: string): void {
505
+ this.dispatchEvent(
506
+ new CustomEvent("highlightedtermchange", {
507
+ detail: term,
508
+ bubbles: true,
509
+ composed: true
510
+ })
511
+ );
512
+ }
513
+
514
+ protected updateHighlightsAndSearch(nextSearchString: string): void {
515
+ const nextSearchParam =
516
+ new URLSearchParams(nextSearchString).get("q") || "";
517
+ this.setSidebarInputValue(nextSearchParam);
518
+ this.dispatchHighlightChange(nextSearchParam);
519
+ }
520
+
521
+ protected onToggleSidebar(e: CustomEvent): void {
522
+ this.sidebarOpen = e.detail.open;
523
+
524
+ // eslint-disable-next-line @lwc/lwc/no-document-query
525
+ const footer = document.querySelector("dx-footer") as HTMLElement;
526
+
527
+ if (footer) {
528
+ footer.style.display = this.sidebarOpen ? "none" : "block";
529
+ }
530
+ }
531
+ }
@@ -0,0 +1,49 @@
1
+ :host {
2
+ --aspect-ratio: 9 / 16; /* the vertical axis is the first number */
3
+ }
4
+
5
+ .content-media-wrapper {
6
+ margin: 36px 0;
7
+ }
8
+
9
+ .content-media-title {
10
+ color: var(--dx-g-blue-vibrant-20);
11
+ font-size: var(--dx-g-text-base);
12
+ font-family: var(--dx-g-font-display);
13
+ font-weight: 500;
14
+ background-color: var(--sds-g-gray-4);
15
+ padding: var(--dx-g-spacing-sm) var(--dx-g-spacing-smd);
16
+ border-top-left-radius: 4px;
17
+ border-top-right-radius: 4px;
18
+ }
19
+
20
+ .content-media-image,
21
+ .content-media-iframe {
22
+ border: 1px solid var(--dx-g-gray-90);
23
+ }
24
+
25
+ .content-media-image img {
26
+ display: block;
27
+ width: 100%;
28
+ }
29
+
30
+ .content-media-iframe {
31
+ position: relative;
32
+ padding-bottom: calc(var(--aspect-ratio, 0.5625) * 100%);
33
+ height: 0;
34
+ }
35
+
36
+ .content-media-iframe iframe {
37
+ position: absolute;
38
+ top: 0;
39
+ left: 0;
40
+ width: 100%;
41
+ height: 100%;
42
+ }
43
+
44
+ .content-media-caption {
45
+ font-family: var(--dx-g-font-sans);
46
+ font-size: var(--dx-g-text-xs);
47
+ margin-top: var(--dx-g-spacing-sm);
48
+ margin-left: var(--dx-g-spacing-smd);
49
+ }
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div class="content-media-wrapper">
3
+ <div class="content-media-container">
4
+ <div if:true={mediaTitle} class="content-media-title">
5
+ {mediaTitle}
6
+ </div>
7
+ <div class={mediaWrapperClass}>
8
+ <img if:true={isImage} src={contentSrc} alt={mediaTitle} />
9
+ <iframe
10
+ if:true={isIframe}
11
+ title={frameTitle}
12
+ width="560"
13
+ height="315"
14
+ src={contentSrc}
15
+ frameborder="0"
16
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
17
+ allowfullscreen
18
+ ></iframe>
19
+ </div>
20
+ </div>
21
+ <div if:true={caption} class="content-media-caption">{caption}</div>
22
+ </div>
23
+ </template>