@salesforcedevs/docs-components 0.56.2 → 0.56.3-example

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 (80) hide show
  1. package/lwc.config.json +10 -2
  2. package/package.json +19 -13
  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 +42 -21
  6. package/src/modules/doc/amfReference/amfReference.ts +1022 -341
  7. package/src/modules/doc/amfReference/constants.ts +76 -0
  8. package/src/modules/doc/amfReference/types.ts +45 -13
  9. package/src/modules/doc/amfTopic/amfTopic.css +20 -0
  10. package/src/modules/doc/amfTopic/amfTopic.ts +35 -18
  11. package/src/modules/doc/amfTopic/types.ts +15 -13
  12. package/src/modules/doc/amfTopic/utils.ts +12 -6
  13. package/src/modules/doc/breadcrumbItem/breadcrumbItem.css +2 -1
  14. package/src/modules/doc/breadcrumbItem/breadcrumbItem.html +1 -1
  15. package/src/modules/doc/breadcrumbItem/breadcrumbItem.ts +22 -0
  16. package/src/modules/doc/breadcrumbs/breadcrumbs.css +9 -1
  17. package/src/modules/doc/breadcrumbs/breadcrumbs.html +44 -34
  18. package/src/modules/doc/breadcrumbs/breadcrumbs.ts +62 -23
  19. package/src/modules/doc/componentPlayground/componentPlayground.css +22 -0
  20. package/src/modules/doc/componentPlayground/componentPlayground.html +20 -0
  21. package/src/modules/doc/componentPlayground/componentPlayground.ts +42 -0
  22. package/src/modules/doc/content/content.css +70 -76
  23. package/src/modules/doc/content/content.html +1 -0
  24. package/src/modules/doc/content/content.ts +26 -47
  25. package/src/modules/doc/contentCallout/contentCallout.css +15 -7
  26. package/src/modules/doc/contentCallout/contentCallout.html +13 -4
  27. package/src/modules/doc/contentCallout/contentCallout.ts +14 -2
  28. package/src/modules/doc/contentLayout/contentLayout.css +1 -100
  29. package/src/modules/doc/contentLayout/contentLayout.html +30 -17
  30. package/src/modules/doc/contentLayout/contentLayout.ts +354 -65
  31. package/src/modules/doc/doDont/doDont.css +47 -0
  32. package/src/modules/doc/doDont/doDont.html +27 -0
  33. package/src/modules/doc/doDont/doDont.ts +17 -0
  34. package/src/modules/doc/header/header.css +65 -36
  35. package/src/modules/doc/header/header.html +41 -139
  36. package/src/modules/doc/header/header.ts +54 -76
  37. package/src/modules/doc/heading/heading.css +16 -37
  38. package/src/modules/doc/heading/heading.html +4 -4
  39. package/src/modules/doc/heading/heading.ts +12 -10
  40. package/src/modules/doc/headingAnchor/headingAnchor.css +2 -2
  41. package/src/modules/doc/headingAnchor/headingAnchor.ts +2 -2
  42. package/src/modules/doc/headingContent/headingContent.css +6 -8
  43. package/src/modules/doc/headingContent/headingContent.html +9 -15
  44. package/src/modules/doc/headingContent/headingContent.ts +2 -14
  45. package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +1 -0
  46. package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +68 -0
  47. package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +256 -0
  48. package/src/modules/doc/overview/overview.css +40 -0
  49. package/src/modules/doc/overview/overview.html +34 -0
  50. package/src/modules/doc/overview/overview.ts +12 -0
  51. package/src/modules/doc/phase/phase.css +18 -3
  52. package/src/modules/doc/phase/phase.html +15 -3
  53. package/src/modules/doc/phase/phase.ts +44 -8
  54. package/src/modules/doc/specificationContent/specificationContent.css +36 -0
  55. package/src/modules/doc/specificationContent/specificationContent.html +167 -0
  56. package/src/modules/doc/specificationContent/specificationContent.ts +127 -0
  57. package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
  58. package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
  59. package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
  60. package/src/modules/doc/toc/toc.ts +1 -1
  61. package/src/modules/doc/versionPicker/versionPicker.css +64 -0
  62. package/src/modules/doc/versionPicker/versionPicker.html +38 -0
  63. package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
  64. package/src/modules/doc/xmlContent/types.ts +12 -3
  65. package/src/modules/doc/xmlContent/utils.ts +17 -12
  66. package/src/modules/doc/xmlContent/xmlContent.css +32 -3
  67. package/src/modules/doc/xmlContent/xmlContent.html +41 -15
  68. package/src/modules/doc/xmlContent/xmlContent.ts +295 -95
  69. package/src/modules/docHelpers/amfStyle/amfStyle.css +10 -45
  70. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
  71. package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
  72. package/src/modules/docHelpers/status/status.css +1 -1
  73. package/src/modules/docUtils/{SearchSyncer/SearchSyncer.ts → searchSyncer/searchSyncer.ts} +1 -0
  74. package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
  75. package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
  76. package/src/modules/docUtils/utils/utils.ts +32 -0
  77. package/LICENSE +0 -12
  78. package/src/modules/doc/amfReference/route-meta.ts +0 -22
  79. package/src/modules/docBaseElements/lightningElementWithState/lightningElementWithState.ts +0 -93
  80. 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,17 +25,28 @@ const HIGHLIGHTABLE_SELECTOR = [
20
25
  "th",
21
26
  "td"
22
27
  ].join(",");
28
+ export const OBSERVER_ATTACH_WAIT_TIME = 500;
23
29
 
24
30
  export default class ContentLayout extends LightningElement {
25
- @api sidebarValue: string;
26
- @api sidebarHeader: string;
27
- @api tocTitle: string;
31
+ @api sidebarValue!: string;
32
+ @api sidebarHeader!: string;
33
+ @api tocTitle!: string;
28
34
  @api enableSlotChange = false;
29
35
  @api coveoOrganizationId!: string;
30
36
  @api coveoPublicAccessToken!: string;
37
+ @api coveoAnalyticsToken!: string;
31
38
  @api coveoSearchHub!: string;
32
39
  @api coveoAdvancedQueryConfig!: string;
33
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;
34
50
 
35
51
  @api
36
52
  get breadcrumbs() {
@@ -48,7 +64,7 @@ export default class ContentLayout extends LightningElement {
48
64
  return this._sidebarContent;
49
65
  }
50
66
 
51
- set sidebarContent(value) {
67
+ set sidebarContent(value: any) {
52
68
  this._sidebarContent = toJson(value);
53
69
  }
54
70
 
@@ -63,25 +79,33 @@ export default class ContentLayout extends LightningElement {
63
79
 
64
80
  @api
65
81
  setSidebarInputValue(searchTerm: string): void {
66
- this.template.querySelector("dx-sidebar")?.setInputValue(searchTerm);
82
+ (this.template.querySelector("dx-sidebar") as any)?.setInputValue(
83
+ searchTerm
84
+ );
67
85
  }
68
86
 
69
87
  @track
70
- private _sidebarContent: unknown;
88
+ protected _sidebarContent: unknown;
71
89
 
72
- private _breadcrumbs = null;
90
+ protected _breadcrumbs = null;
73
91
 
74
92
  @track
75
- private _tocOptions: Array<unknown>;
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
+ }
76
106
 
77
- private anchoredElements: AnchorMap = {};
78
- private lastScrollPosition: number;
79
- private observer?: IntersectionObserver;
80
- private searchSyncer = new SearchSyncer({
107
+ protected searchSyncer = new SearchSyncer({
81
108
  callbacks: {
82
- onUrlChange: (nextSearchString: string): void => {
83
- this.updateHighlightsAndSearch(nextSearchString);
84
- },
85
109
  onSearchChange: (nextSearchString: string): void => {
86
110
  this.dispatchHighlightChange(
87
111
  new URLSearchParams(nextSearchString).get("q") || ""
@@ -94,7 +118,11 @@ export default class ContentLayout extends LightningElement {
94
118
  shouldStopPropagation: true,
95
119
  target: window
96
120
  });
97
- private tocValue?: string = undefined;
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;
98
126
 
99
127
  get showToc(): boolean {
100
128
  return this.tocOptions && this.tocOptions.length > 0;
@@ -105,6 +133,12 @@ export default class ContentLayout extends LightningElement {
105
133
  return window.location.pathname;
106
134
  }
107
135
 
136
+ get showBreadcrumbs(): boolean {
137
+ return (
138
+ this.breadcrumbs != null && (this.breadcrumbs as any[]).length > 1
139
+ );
140
+ }
141
+
108
142
  connectedCallback(): void {
109
143
  const hasParentHighlightListener = closest(
110
144
  "doc-xml-content",
@@ -119,85 +153,326 @@ export default class ContentLayout extends LightningElement {
119
153
  }
120
154
  }
121
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
+
122
183
  disconnectedCallback(): void {
123
184
  this.disconnectObserver();
124
185
  window.removeEventListener(
125
186
  "highlightedtermchange",
126
187
  this.updateHighlighted
127
188
  );
189
+ window.removeEventListener("scroll", this.adjustNavPosition);
190
+ window.removeEventListener("resize", this.adjustNavPosition);
128
191
  this.searchSyncer.dispose();
192
+ this.clearRenderObserverTimer();
193
+
194
+ window.clearInterval(this._scrollInterval);
129
195
  }
130
196
 
131
- updateHighlighted = (event: Event): void =>
132
- highlightTerms(
133
- this.querySelectorAll(HIGHLIGHTABLE_SELECTOR),
134
- (event as CustomEvent<string>).detail
135
- );
197
+ restoreScroll() {
198
+ document.body.scrollTop = document.documentElement.scrollTop =
199
+ window.history.state?.scrollValue;
200
+ }
136
201
 
137
- onSlotChange(event: Event): void {
138
- if (!this.enableSlotChange) {
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.");
139
239
  return;
140
240
  }
141
241
 
142
- this.disconnectObserver();
143
- this.observer = new IntersectionObserver((entries) => {
144
- entries.forEach(
145
- (entry) =>
146
- (this.anchoredElements[
147
- entry.target.getAttribute("id")
148
- ].intersect = entry.isIntersecting)
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`
149
265
  );
150
- this.calculateActualSection();
151
- });
152
266
 
153
- const anchoredTags = (event.target as HTMLSlotElement)
154
- .assignedElements()
155
- .filter(({ tagName }) => tagName === TOC_HEADER_TAG)
156
- .map((tag) => {
157
- tag.id = tag.hash;
158
- return tag;
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`;
159
276
  });
160
277
 
161
- this._tocOptions = anchoredTags.map((tag) => ({
162
- anchor: `#${tag.hash}`,
163
- id: tag.id,
164
- label: tag.title
165
- }));
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
+ }
166
287
 
167
- this.scrollToHash(anchoredTags);
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
+ };
168
303
 
169
- anchoredTags.forEach((section) => {
170
- const id = section.getAttribute("id");
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")!;
171
325
  this.anchoredElements[id] = {
172
326
  id,
173
327
  intersect: false
174
328
  };
175
- this.observer.observe(section);
176
- });
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;
177
389
  }
178
390
 
179
- private disconnectObserver(): void {
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 {
180
418
  if (this.observer) {
181
419
  this.observer.disconnect();
182
- this.observer = null;
420
+ this.observer = undefined;
183
421
  }
184
422
  }
185
423
 
186
- private scrollToHash(anchoredTags: Array<Element>): void {
424
+ // eslint-disable-next-line no-undef
425
+ protected scrollToHash(headingElements: NodeListOf<Element>): void {
187
426
  let { hash } = window.location;
188
-
189
427
  if (hash) {
190
428
  hash = hash.substr(1);
191
- const toScrollElement = anchoredTags.find(
192
- (element) => element.getAttribute("id") === hash
193
- );
194
- if (toScrollElement) {
195
- toScrollElement.scrollIntoView({ behavior: "auto" });
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
+ }
196
458
  }
197
459
  }
198
460
  }
199
461
 
200
- private calculateActualSection(): void {
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 {
201
476
  const currentScrollPosition = document.documentElement.scrollTop;
202
477
  const id = Object.keys(this.anchoredElements).find(
203
478
  (_id) => this.anchoredElements[_id].intersect
@@ -212,18 +487,21 @@ export default class ContentLayout extends LightningElement {
212
487
  this.lastScrollPosition = currentScrollPosition;
213
488
  }
214
489
 
215
- private calculatePreviousElementId(): string {
490
+ protected calculatePreviousElementId(): string | undefined {
216
491
  const keys = Object.keys(this.anchoredElements);
217
492
  const currentIndex = keys.findIndex((id) => this.tocValue === id);
218
493
 
219
494
  return currentIndex > 0 ? keys[currentIndex - 1] : undefined;
220
495
  }
221
496
 
222
- private assignElementId(id: string): void {
223
- this.tocValue = id;
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
+ }
224
502
  }
225
503
 
226
- private dispatchHighlightChange(term: string): void {
504
+ protected dispatchHighlightChange(term: string): void {
227
505
  this.dispatchEvent(
228
506
  new CustomEvent("highlightedtermchange", {
229
507
  detail: term,
@@ -233,10 +511,21 @@ export default class ContentLayout extends LightningElement {
233
511
  );
234
512
  }
235
513
 
236
- private updateHighlightsAndSearch(nextSearchString: string): void {
514
+ protected updateHighlightsAndSearch(nextSearchString: string): void {
237
515
  const nextSearchParam =
238
516
  new URLSearchParams(nextSearchString).get("q") || "";
239
517
  this.setSidebarInputValue(nextSearchParam);
240
518
  this.dispatchHighlightChange(nextSearchParam);
241
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
+ }
242
531
  }
@@ -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
+ }