@salesforcedevs/docs-components 0.56.2-seo-test16 → 0.56.2-snyk

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 (76) hide show
  1. package/lwc.config.json +10 -2
  2. package/package.json +13 -12
  3. package/src/modules/doc/{amfReference/utils.ts → amfModelParser/amfModelParser.ts} +10 -5
  4. package/src/modules/doc/amfReference/amfReference.css +23 -3
  5. package/src/modules/doc/amfReference/amfReference.html +34 -21
  6. package/src/modules/doc/amfReference/amfReference.ts +264 -73
  7. package/src/modules/doc/amfReference/types.ts +4 -12
  8. package/src/modules/doc/amfTopic/amfTopic.css +20 -0
  9. package/src/modules/doc/amfTopic/amfTopic.ts +35 -18
  10. package/src/modules/doc/amfTopic/types.ts +15 -13
  11. package/src/modules/doc/amfTopic/utils.ts +12 -6
  12. package/src/modules/doc/breadcrumbItem/breadcrumbItem.css +2 -1
  13. package/src/modules/doc/breadcrumbItem/breadcrumbItem.html +1 -1
  14. package/src/modules/doc/breadcrumbItem/breadcrumbItem.ts +22 -0
  15. package/src/modules/doc/breadcrumbs/breadcrumbs.css +9 -1
  16. package/src/modules/doc/breadcrumbs/breadcrumbs.html +44 -34
  17. package/src/modules/doc/breadcrumbs/breadcrumbs.ts +62 -23
  18. package/src/modules/doc/componentPlayground/componentPlayground.css +22 -0
  19. package/src/modules/doc/componentPlayground/componentPlayground.html +15 -0
  20. package/src/modules/doc/componentPlayground/componentPlayground.ts +20 -0
  21. package/src/modules/doc/content/content.css +70 -76
  22. package/src/modules/doc/content/content.ts +20 -16
  23. package/src/modules/doc/contentCallout/contentCallout.css +15 -7
  24. package/src/modules/doc/contentCallout/contentCallout.html +13 -4
  25. package/src/modules/doc/contentCallout/contentCallout.ts +14 -2
  26. package/src/modules/doc/contentLayout/contentLayout.css +1 -100
  27. package/src/modules/doc/contentLayout/contentLayout.html +26 -17
  28. package/src/modules/doc/contentLayout/contentLayout.ts +312 -70
  29. package/src/modules/doc/doDont/doDont.css +47 -0
  30. package/src/modules/doc/doDont/doDont.html +27 -0
  31. package/src/modules/doc/doDont/doDont.ts +17 -0
  32. package/src/modules/doc/header/header.css +65 -36
  33. package/src/modules/doc/header/header.html +40 -139
  34. package/src/modules/doc/header/header.ts +32 -77
  35. package/src/modules/doc/heading/heading.css +16 -37
  36. package/src/modules/doc/heading/heading.html +4 -4
  37. package/src/modules/doc/heading/heading.ts +12 -10
  38. package/src/modules/doc/headingAnchor/headingAnchor.css +2 -2
  39. package/src/modules/doc/headingAnchor/headingAnchor.ts +2 -2
  40. package/src/modules/doc/headingContent/headingContent.css +6 -8
  41. package/src/modules/doc/headingContent/headingContent.html +9 -15
  42. package/src/modules/doc/headingContent/headingContent.ts +2 -14
  43. package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +1 -0
  44. package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +64 -0
  45. package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +168 -0
  46. package/src/modules/doc/overview/overview.css +40 -0
  47. package/src/modules/doc/overview/overview.html +34 -0
  48. package/src/modules/doc/overview/overview.ts +12 -0
  49. package/src/modules/doc/phase/phase.css +18 -3
  50. package/src/modules/doc/phase/phase.html +15 -3
  51. package/src/modules/doc/phase/phase.ts +44 -8
  52. package/src/modules/doc/specificationContent/specificationContent.css +31 -0
  53. package/src/modules/doc/specificationContent/specificationContent.html +164 -0
  54. package/src/modules/doc/specificationContent/specificationContent.ts +121 -0
  55. package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
  56. package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
  57. package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
  58. package/src/modules/doc/toc/toc.ts +1 -1
  59. package/src/modules/doc/versionPicker/versionPicker.css +64 -0
  60. package/src/modules/doc/versionPicker/versionPicker.html +38 -0
  61. package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
  62. package/src/modules/doc/xmlContent/types.ts +12 -3
  63. package/src/modules/doc/xmlContent/utils.ts +17 -12
  64. package/src/modules/doc/xmlContent/xmlContent.css +32 -3
  65. package/src/modules/doc/xmlContent/xmlContent.html +33 -15
  66. package/src/modules/doc/xmlContent/xmlContent.ts +278 -88
  67. package/src/modules/docHelpers/amfStyle/amfStyle.css +10 -45
  68. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
  69. package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
  70. package/src/modules/docHelpers/status/status.css +1 -1
  71. package/src/modules/docUtils/{SearchSyncer/SearchSyncer.ts → searchSyncer/searchSyncer.ts} +1 -0
  72. package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
  73. package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
  74. package/src/modules/docUtils/utils/utils.ts +32 -0
  75. package/src/modules/docBaseElements/lightningElementWithState/lightningElementWithState.ts +0 -93
  76. package/src/modules/docHelpers/phaseContentLayout/phaseContentLayout.css +0 -39
@@ -1,12 +1,17 @@
1
+ /* eslint-disable @lwc/lwc/no-document-query */
1
2
  import { LightningElement, api, track } from "lwc";
2
3
  import { closest } from "kagekiri";
3
4
  import { toJson } from "dxUtils/normalizers";
4
5
  import { highlightTerms } from "dxUtils/highlight";
5
- import { SearchSyncer } from "docUtils/SearchSyncer";
6
+ import { SearchSyncer } from "docUtils/searchSyncer";
7
+ import type { OptionWithLink } from "typings/custom";
6
8
 
7
9
  type AnchorMap = { [key: string]: { intersect: boolean; id: string } };
8
10
 
9
- const TOC_HEADER_TAG = "DOC-HEADING";
11
+ declare const Sprig: (eventType: string, eventNme: string) => void;
12
+
13
+ const TOC_HEADER_TAG = "doc-heading";
14
+
10
15
  const HIGHLIGHTABLE_SELECTOR = [
11
16
  "p",
12
17
  "h1",
@@ -20,18 +25,26 @@ const HIGHLIGHTABLE_SELECTOR = [
20
25
  "th",
21
26
  "td"
22
27
  ].join(",");
23
- const OBSERVER_ATTACH_WAIT_TIME = 500;
28
+ export const OBSERVER_ATTACH_WAIT_TIME = 500;
24
29
 
25
30
  export default class ContentLayout extends LightningElement {
26
- @api sidebarValue: string;
27
- @api sidebarHeader: string;
28
- @api tocTitle: string;
31
+ @api sidebarValue!: string;
32
+ @api sidebarHeader!: string;
33
+ @api tocTitle!: string;
29
34
  @api enableSlotChange = false;
30
35
  @api coveoOrganizationId!: string;
31
36
  @api coveoPublicAccessToken!: string;
37
+ @api coveoAnalyticsToken!: string;
32
38
  @api coveoSearchHub!: string;
33
39
  @api coveoAdvancedQueryConfig!: string;
34
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;
35
48
 
36
49
  @api
37
50
  get breadcrumbs() {
@@ -49,7 +62,7 @@ export default class ContentLayout extends LightningElement {
49
62
  return this._sidebarContent;
50
63
  }
51
64
 
52
- set sidebarContent(value) {
65
+ set sidebarContent(value: any) {
53
66
  this._sidebarContent = toJson(value);
54
67
  }
55
68
 
@@ -64,25 +77,33 @@ export default class ContentLayout extends LightningElement {
64
77
 
65
78
  @api
66
79
  setSidebarInputValue(searchTerm: string): void {
67
- this.template.querySelector("dx-sidebar")?.setInputValue(searchTerm);
80
+ (this.template.querySelector("dx-sidebar") as any)?.setInputValue(
81
+ searchTerm
82
+ );
68
83
  }
69
84
 
70
85
  @track
71
- private _sidebarContent: unknown;
86
+ protected _sidebarContent: unknown;
72
87
 
73
- private _breadcrumbs = null;
88
+ protected _breadcrumbs = null;
74
89
 
75
90
  @track
76
- private _tocOptions: Array<unknown>;
91
+ protected _tocOptions!: Array<unknown>;
92
+
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;
100
+
101
+ get shouldDisplayFeedback() {
102
+ return this.contentLoaded && typeof Sprig !== "undefined";
103
+ }
77
104
 
78
- private anchoredElements: AnchorMap = {};
79
- private lastScrollPosition: number;
80
- private observer?: IntersectionObserver;
81
- private searchSyncer = new SearchSyncer({
105
+ protected searchSyncer = new SearchSyncer({
82
106
  callbacks: {
83
- onUrlChange: (nextSearchString: string): void => {
84
- this.updateHighlightsAndSearch(nextSearchString);
85
- },
86
107
  onSearchChange: (nextSearchString: string): void => {
87
108
  this.dispatchHighlightChange(
88
109
  new URLSearchParams(nextSearchString).get("q") || ""
@@ -95,9 +116,11 @@ export default class ContentLayout extends LightningElement {
95
116
  shouldStopPropagation: true,
96
117
  target: window
97
118
  });
98
- private tocValue?: string = undefined;
99
- private observerTimerId = null;
100
- private didScrollToSelectedHash = false;
119
+ protected tocValue?: string = undefined;
120
+ // eslint-disable-next-line no-undef
121
+ protected observerTimerId?: NodeJS.Timeout;
122
+ protected didScrollToSelectedHash = false;
123
+ protected _scrollInterval = 0;
101
124
 
102
125
  get showToc(): boolean {
103
126
  return this.tocOptions && this.tocOptions.length > 0;
@@ -108,6 +131,12 @@ export default class ContentLayout extends LightningElement {
108
131
  return window.location.pathname;
109
132
  }
110
133
 
134
+ get showBreadcrumbs(): boolean {
135
+ return (
136
+ this.breadcrumbs != null && (this.breadcrumbs as any[]).length > 1
137
+ );
138
+ }
139
+
111
140
  connectedCallback(): void {
112
141
  const hasParentHighlightListener = closest(
113
142
  "doc-xml-content",
@@ -122,6 +151,9 @@ export default class ContentLayout extends LightningElement {
122
151
  }
123
152
  }
124
153
 
154
+ // Placeholder for childs renderedCallback
155
+ protected postRenderedCallback?(): void;
156
+
125
157
  renderedCallback(): void {
126
158
  /**
127
159
  * Note: We are adding timeout because chrome is optimizing and not triggering recent renderedCallback though elements reference is changed
@@ -132,6 +164,18 @@ export default class ContentLayout extends LightningElement {
132
164
  this.attachInteractionObserver,
133
165
  OBSERVER_ATTACH_WAIT_TIME
134
166
  );
167
+
168
+ this.adjustNavPosition();
169
+ window.addEventListener("scroll", this.adjustNavPosition);
170
+ window.addEventListener("resize", this.adjustNavPosition);
171
+
172
+ if (!this.hasRendered) {
173
+ this.hasRendered = true;
174
+ this.restoreScroll();
175
+
176
+ // Dynamically call `renderedCallbackForLwcContentLayout` if it exists
177
+ this.postRenderedCallback?.();
178
+ }
135
179
  }
136
180
 
137
181
  disconnectedCallback(): void {
@@ -140,8 +184,17 @@ export default class ContentLayout extends LightningElement {
140
184
  "highlightedtermchange",
141
185
  this.updateHighlighted
142
186
  );
187
+ window.removeEventListener("scroll", this.adjustNavPosition);
188
+ window.removeEventListener("resize", this.adjustNavPosition);
143
189
  this.searchSyncer.dispose();
144
190
  this.clearRenderObserverTimer();
191
+
192
+ window.clearInterval(this._scrollInterval);
193
+ }
194
+
195
+ restoreScroll() {
196
+ document.body.scrollTop = document.documentElement.scrollTop =
197
+ window.history.state?.scrollValue;
145
198
  }
146
199
 
147
200
  clearRenderObserverTimer = () => {
@@ -150,99 +203,274 @@ export default class ContentLayout extends LightningElement {
150
203
  }
151
204
  };
152
205
 
153
- updateHighlighted = (event: Event): void =>
154
- highlightTerms(
155
- this.querySelectorAll(HIGHLIGHTABLE_SELECTOR),
156
- (event as CustomEvent<string>).detail
157
- );
206
+ /*
207
+ This is a workaround for the global nav sticky header being decoupled from the doc header & doc phase.
208
+ We have to account for the global nav changing height due to animations.
209
+ */
210
+ adjustNavPosition = () => {
211
+ const sidebarType = this.useOldSidebar
212
+ ? "dx-sidebar-old"
213
+ : "dx-sidebar";
214
+ const sidebarEl = this.template.querySelector(sidebarType);
215
+ const globalNavEl = document.querySelector(
216
+ "hgf-c360nav"
217
+ ) as HTMLElement;
218
+ const contextNavEl = document.querySelector(
219
+ "hgf-c360contextnav"
220
+ ) as HTMLElement;
221
+ const docHeaderEl = document.querySelector(
222
+ ".sticky-doc-header"
223
+ ) as HTMLElement;
224
+
225
+ let docPhaseEl = (
226
+ this.template.querySelector("[name=doc-phase]")! as any
227
+ ).assignedElements()[0] as HTMLSlotElement;
228
+
229
+ if (!docPhaseEl) {
230
+ docPhaseEl = (
231
+ this.template.querySelector("[name=version-banner]")! as any
232
+ ).assignedElements()[0] as HTMLSlotElement;
233
+ }
158
234
 
159
- attachInteractionObserver = (): void => {
160
- if (!this.enableSlotChange) {
235
+ if (!sidebarEl || !globalNavEl || !contextNavEl || !docHeaderEl) {
236
+ console.warn("One or more required elements are missing.");
161
237
  return;
162
238
  }
163
- this.disconnectObserver();
164
- this.observer = new IntersectionObserver((entries) => {
165
- entries.forEach(
166
- (entry) =>
167
- (this.anchoredElements[
168
- entry.target.getAttribute("id")
169
- ].intersect = entry.isIntersecting)
239
+
240
+ // sync with the browser to account for any reflows that may have happened
241
+ requestAnimationFrame(() => {
242
+ // ternary is a temporary fix for the global nav height reporting incorrectly on some browsers
243
+ const globalNavHeight =
244
+ (globalNavEl.getBoundingClientRect().height !== 72 ? 0 : 72) +
245
+ contextNavEl.getBoundingClientRect().height;
246
+ const docHeaderHeight = docHeaderEl.getBoundingClientRect().height;
247
+ const totalHeaderHeight = globalNavHeight + docHeaderHeight;
248
+
249
+ // Selecting the doc section heading and RNB here.
250
+ const docHeadingEls = Array.from(
251
+ document.querySelectorAll("doc-heading")
252
+ );
253
+ const rightNavBarEl = this.template.querySelector(".right-nav-bar");
254
+
255
+ sidebarEl.style.setProperty(
256
+ "--dx-c-content-sidebar-sticky-top",
257
+ `${globalNavHeight + docHeaderHeight}px`
258
+ );
259
+
260
+ docHeaderEl.style.setProperty(
261
+ "--dx-g-global-header-height",
262
+ `${globalNavHeight}px`
170
263
  );
171
- this.calculateActualSection();
264
+
265
+ // Adjusting the doc section heading on scroll.
266
+ docHeadingEls.forEach((docHeadingEl) => {
267
+ (docHeadingEl as any).style.scrollMarginTop = docPhaseEl
268
+ ? `${
269
+ totalHeaderHeight +
270
+ docPhaseEl.getBoundingClientRect().height +
271
+ 40
272
+ }px`
273
+ : `${totalHeaderHeight + 40}px`;
274
+ });
275
+
276
+ // Adjusting the right nav bar on scroll.
277
+ if (rightNavBarEl) {
278
+ rightNavBarEl.style.top = docPhaseEl
279
+ ? `${
280
+ totalHeaderHeight +
281
+ docPhaseEl.getBoundingClientRect().height
282
+ }px`
283
+ : `${totalHeaderHeight}px`;
284
+ }
285
+
286
+ // If doc phase element exists, we need to account for its sticky position. Mobile should include the sidebar height (since it becomes sticky aswell).
287
+ if (docPhaseEl) {
288
+ docPhaseEl.style.setProperty(
289
+ "--doc-c-phase-top",
290
+ `${
291
+ window.innerWidth < 769
292
+ ? globalNavHeight +
293
+ docHeaderHeight +
294
+ sidebarEl.getBoundingClientRect().height
295
+ : globalNavHeight + docHeaderHeight
296
+ }px`
297
+ );
298
+ }
172
299
  });
300
+ };
301
+
302
+ updateHighlighted = (event: Event): void =>
303
+ highlightTerms(
304
+ this.querySelectorAll(HIGHLIGHTABLE_SELECTOR),
305
+ (event as CustomEvent<string>).detail
306
+ );
173
307
 
308
+ protected getHeadingElements() {
174
309
  // Note: We are doing document.querySelectorAll as a quick fix as we are not getting heading elements reference this.querySelectorAll
175
310
  const headingElements = document.querySelectorAll(TOC_HEADER_TAG);
176
- for (const headingElement of headingElements) {
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) {
177
321
  // Add headingElements to intersectionObserver for highlighting respective RNB item when user scroll
178
- const id = headingElement.getAttribute("id");
322
+ const id = headingElement.getAttribute("id")!;
179
323
  this.anchoredElements[id] = {
180
324
  id,
181
325
  intersect: false
182
326
  };
183
- this.observer.observe(headingElement);
327
+ this.observer?.observe(headingElement);
184
328
  }
329
+
185
330
  if (!this.didScrollToSelectedHash) {
186
331
  this.didScrollToSelectedHash = true;
187
332
  this.scrollToHash(headingElements);
188
333
  }
189
- };
334
+ }
190
335
 
191
- onSlotChange(event: Event): void {
192
- const slotElements = (
193
- event.target as HTMLSlotElement
194
- ).assignedElements();
336
+ attachInteractionObserver = (): void => {
337
+ if (!this.enableSlotChange) {
338
+ return;
339
+ }
340
+ this.disconnectObserver();
195
341
 
196
- if (slotElements.length) {
197
- const slotContentElement = slotElements[0];
198
- const headingElements =
199
- slotContentElement.ownerDocument?.getElementsByTagName(
200
- TOC_HEADER_TAG
342
+ const globalNavOffset = `-${getComputedStyle(
343
+ document.documentElement
344
+ ).getPropertyValue("--dx-g-doc-header-main-nav-height")}`;
345
+
346
+ this.observer = new IntersectionObserver(
347
+ (entries) => {
348
+ entries.forEach(
349
+ (entry) =>
350
+ (this.anchoredElements[
351
+ entry.target.getAttribute("id")!
352
+ ].intersect = entry.isIntersecting)
201
353
  );
202
- for (const headingElement of headingElements) {
203
- // Sometimes elements hash is not being set when slot content is wrapped with div
204
- headingElement.hash =
205
- headingElement.attributes.hash?.nodeValue;
354
+ this.calculateActualSection();
355
+ },
356
+ {
357
+ rootMargin: globalNavOffset.trim()
206
358
  }
207
- const tocOptions = [];
208
- for (const headingElement of headingElements) {
209
- headingElement.id = headingElement.hash;
359
+ );
360
+ this.updateHeadingForRNB();
361
+ };
362
+
363
+ // eslint-disable-next-line no-undef
364
+ updateTocItems(headingElements: any): void {
365
+ const tocOptions = [];
366
+
367
+ for (const headingElement of headingElements as any) {
368
+ headingElement.id = headingElement.hash;
369
+
370
+ // Update tocOptions from anchorTags only for H2, consider default as 2 as per component
371
+ const headingAriaLevel =
372
+ headingElement.attributes["aria-level"]?.nodeValue || "2";
373
+ const isH2 = headingAriaLevel === "2";
210
374
 
211
- // Update tocOptions from anchorTags
375
+ if (isH2) {
212
376
  const tocItem = {
213
377
  anchor: `#${headingElement.hash}`,
214
378
  id: headingElement.id,
215
- label: headingElement.title
379
+ label: headingElement.header
216
380
  };
217
381
  tocOptions.push(tocItem);
382
+ this.tocOptionIdsSet.add(headingElement.id);
218
383
  }
384
+ }
385
+
386
+ this._tocOptions = tocOptions;
387
+ }
219
388
 
220
- this._tocOptions = tocOptions;
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
+ }
221
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;
222
413
  }
223
414
 
224
- private disconnectObserver(): void {
415
+ protected disconnectObserver(): void {
225
416
  if (this.observer) {
226
417
  this.observer.disconnect();
227
- this.observer = null;
418
+ this.observer = undefined;
228
419
  }
229
420
  }
230
421
 
231
422
  // eslint-disable-next-line no-undef
232
- private scrollToHash(headingElements: NodeListOf<Element>): void {
423
+ protected scrollToHash(headingElements: NodeListOf<Element>): void {
233
424
  let { hash } = window.location;
234
425
  if (hash) {
235
426
  hash = hash.substr(1);
236
- for (const headingElement of headingElements) {
427
+
428
+ const docHeaderEl = document.querySelector(
429
+ ".sticky-doc-header"
430
+ ) as HTMLElement;
431
+ const globalNavEl = document.querySelector(
432
+ "hgf-c360nav"
433
+ ) as HTMLElement;
434
+ const contextNavEl = document.querySelector(
435
+ "hgf-c360contextnav"
436
+ ) as HTMLElement;
437
+
438
+ const headerHeight =
439
+ docHeaderEl?.offsetHeight +
440
+ globalNavEl?.offsetHeight +
441
+ contextNavEl?.offsetHeight;
442
+
443
+ const docPhaseEl = (
444
+ this.template.querySelector("[name=doc-phase]")! as any
445
+ ).assignedElements()[0] as HTMLSlotElement;
446
+
447
+ const offset = docPhaseEl
448
+ ? headerHeight + docPhaseEl.offsetHeight
449
+ : headerHeight;
450
+
451
+ for (const headingElement of headingElements as any) {
237
452
  if (headingElement.getAttribute("id") === hash) {
238
- headingElement.scrollIntoView({ behavior: "auto" });
453
+ this.scrollIntoViewWithOffset(headingElement, offset);
239
454
  break;
240
455
  }
241
456
  }
242
457
  }
243
458
  }
244
459
 
245
- private calculateActualSection(): void {
460
+ protected scrollIntoViewWithOffset(
461
+ headingElement: HTMLElement,
462
+ offset: number
463
+ ) {
464
+ window.scrollTo({
465
+ behavior: "auto",
466
+ top:
467
+ headingElement.getBoundingClientRect().top -
468
+ document.body.getBoundingClientRect().top -
469
+ offset
470
+ });
471
+ }
472
+
473
+ protected calculateActualSection(): void {
246
474
  const currentScrollPosition = document.documentElement.scrollTop;
247
475
  const id = Object.keys(this.anchoredElements).find(
248
476
  (_id) => this.anchoredElements[_id].intersect
@@ -257,18 +485,21 @@ export default class ContentLayout extends LightningElement {
257
485
  this.lastScrollPosition = currentScrollPosition;
258
486
  }
259
487
 
260
- private calculatePreviousElementId(): string {
488
+ protected calculatePreviousElementId(): string | undefined {
261
489
  const keys = Object.keys(this.anchoredElements);
262
490
  const currentIndex = keys.findIndex((id) => this.tocValue === id);
263
491
 
264
492
  return currentIndex > 0 ? keys[currentIndex - 1] : undefined;
265
493
  }
266
494
 
267
- private assignElementId(id: string): void {
268
- this.tocValue = id;
495
+ protected assignElementId(id: string | undefined): void {
496
+ // Change toc(RNB) highlight only for H2
497
+ if (this.tocOptionIdsSet.has(id)) {
498
+ this.tocValue = id;
499
+ }
269
500
  }
270
501
 
271
- private dispatchHighlightChange(term: string): void {
502
+ protected dispatchHighlightChange(term: string): void {
272
503
  this.dispatchEvent(
273
504
  new CustomEvent("highlightedtermchange", {
274
505
  detail: term,
@@ -278,10 +509,21 @@ export default class ContentLayout extends LightningElement {
278
509
  );
279
510
  }
280
511
 
281
- private updateHighlightsAndSearch(nextSearchString: string): void {
512
+ protected updateHighlightsAndSearch(nextSearchString: string): void {
282
513
  const nextSearchParam =
283
514
  new URLSearchParams(nextSearchString).get("q") || "";
284
515
  this.setSidebarInputValue(nextSearchParam);
285
516
  this.dispatchHighlightChange(nextSearchParam);
286
517
  }
518
+
519
+ protected onToggleSidebar(e: CustomEvent): void {
520
+ this.sidebarOpen = e.detail.open;
521
+
522
+ // eslint-disable-next-line @lwc/lwc/no-document-query
523
+ const footer = document.querySelector("dx-footer") as HTMLElement;
524
+
525
+ if (footer) {
526
+ footer.style.display = this.sidebarOpen ? "none" : "block";
527
+ }
528
+ }
287
529
  }
@@ -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
+ }