@salesforcedevs/docs-components 0.0.0 → 0.0.1-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 (84) hide show
  1. package/lwc.config.json +11 -2
  2. package/package.json +14 -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 +34 -21
  6. package/src/modules/doc/amfReference/amfReference.ts +225 -92
  7. package/src/modules/doc/amfReference/types.ts +3 -11
  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.ts +17 -10
  13. package/src/modules/doc/breadcrumbs/breadcrumbs.html +7 -9
  14. package/src/modules/doc/breadcrumbs/breadcrumbs.ts +30 -34
  15. package/src/modules/doc/chat/README.md +179 -0
  16. package/src/modules/doc/chat/chat.css +818 -0
  17. package/src/modules/doc/chat/chat.html +241 -0
  18. package/src/modules/doc/chat/chat.ts +586 -0
  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 +29 -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 +24 -45
  25. package/src/modules/doc/contentCallout/contentCallout.css +10 -7
  26. package/src/modules/doc/contentCallout/contentCallout.html +11 -4
  27. package/src/modules/doc/contentCallout/contentCallout.ts +8 -1
  28. package/src/modules/doc/contentLayout/contentLayout.css +1 -98
  29. package/src/modules/doc/contentLayout/contentLayout.html +37 -19
  30. package/src/modules/doc/contentLayout/contentLayout.ts +298 -89
  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/editFile/editFile.css +514 -0
  35. package/src/modules/doc/editFile/editFile.html +164 -0
  36. package/src/modules/doc/editFile/editFile.ts +213 -0
  37. package/src/modules/doc/header/header.css +65 -36
  38. package/src/modules/doc/header/header.html +41 -139
  39. package/src/modules/doc/header/header.ts +54 -76
  40. package/src/modules/doc/heading/heading.css +16 -37
  41. package/src/modules/doc/heading/heading.html +4 -4
  42. package/src/modules/doc/heading/heading.ts +12 -10
  43. package/src/modules/doc/headingAnchor/headingAnchor.css +2 -2
  44. package/src/modules/doc/headingAnchor/headingAnchor.ts +2 -2
  45. package/src/modules/doc/headingContent/headingContent.css +1 -1
  46. package/src/modules/doc/headingContent/headingContent.html +2 -2
  47. package/src/modules/doc/headingContent/headingContent.ts +2 -2
  48. package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +1 -0
  49. package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +68 -0
  50. package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +168 -0
  51. package/src/modules/doc/overview/overview.css +40 -0
  52. package/src/modules/doc/overview/overview.html +34 -0
  53. package/src/modules/doc/overview/overview.ts +12 -0
  54. package/src/modules/doc/phase/phase.css +18 -3
  55. package/src/modules/doc/phase/phase.html +12 -2
  56. package/src/modules/doc/phase/phase.ts +44 -8
  57. package/src/modules/doc/specificationContent/specificationContent.css +36 -0
  58. package/src/modules/doc/specificationContent/specificationContent.html +171 -0
  59. package/src/modules/doc/specificationContent/specificationContent.ts +127 -0
  60. package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
  61. package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
  62. package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
  63. package/src/modules/doc/toc/toc.html +1 -3
  64. package/src/modules/doc/toc/toc.ts +1 -1
  65. package/src/modules/doc/toolbar/toolbar.ts +6 -6
  66. package/src/modules/doc/versionPicker/versionPicker.css +64 -0
  67. package/src/modules/doc/versionPicker/versionPicker.html +38 -0
  68. package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
  69. package/src/modules/doc/xmlContent/types.ts +9 -3
  70. package/src/modules/doc/xmlContent/utils.ts +3 -1
  71. package/src/modules/doc/xmlContent/xmlContent.css +26 -4
  72. package/src/modules/doc/xmlContent/xmlContent.html +29 -17
  73. package/src/modules/doc/xmlContent/xmlContent.ts +212 -79
  74. package/src/modules/docHelpers/amfStyle/amfStyle.css +6 -6
  75. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
  76. package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
  77. package/src/modules/docHelpers/status/status.css +1 -1
  78. package/src/modules/docUtils/{SearchSyncer/SearchSyncer.ts → searchSyncer/searchSyncer.ts} +1 -0
  79. package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
  80. package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
  81. package/src/modules/docUtils/utils/utils.ts +32 -0
  82. package/LICENSE +0 -12
  83. package/src/modules/docBaseElements/lightningElementWithState/lightningElementWithState.ts +0 -93
  84. package/src/modules/docHelpers/phaseContentLayout/phaseContentLayout.css +0 -39
@@ -1,93 +1,76 @@
1
1
  import { api } from "lwc";
2
2
  import cx from "classnames";
3
- import type { OptionWithNested, OptionWithLink } from "typings/custom";
3
+ import type { OptionWithNested, DevCenterConfig } from "typings/custom";
4
4
  import { HeaderBase } from "dxBaseElements/headerBase";
5
- import { toJson } from "dxUtils/normalizers";
6
- import get from "lodash.get";
5
+ import { toJson, normalizeBoolean } from "dxUtils/normalizers";
7
6
 
8
7
  const TABLET_MATCH = "980px";
9
- const MOBILE_MATCH = "880px";
10
- const SMALL_MOBILE_MATCH = "740px";
8
+ const MOBILE_MATCH = "768px";
9
+
10
+ const isStorybook = () => {
11
+ const { host } = window.location;
12
+ return (
13
+ host === "localhost:6006" || /^dsc-comp.*\.herokuapp\.com$/.test(host)
14
+ );
15
+ };
11
16
 
12
17
  export default class Header extends HeaderBase {
13
18
  @api langValuePath: string = "id"; // allows to override how language property is interpreted, follows valuePath dropdown api.
14
19
  @api headerHref: string = "/";
15
20
 
16
21
  @api
17
- get scopedNavItems() {
18
- return this._scopedNavItems;
22
+ get hideDocHeader() {
23
+ return this._hideDocHeader;
19
24
  }
20
25
 
21
- set scopedNavItems(value) {
22
- this._scopedNavItems = toJson(value);
26
+ set hideDocHeader(value) {
27
+ this._hideDocHeader = normalizeBoolean(value);
23
28
  }
24
29
 
25
30
  @api
26
- get languages() {
27
- return this._languages;
31
+ get scopedNavItems() {
32
+ return this._scopedNavItems;
28
33
  }
29
34
 
30
- set languages(value) {
31
- this._languages = toJson(value);
35
+ set scopedNavItems(value) {
36
+ this._scopedNavItems = toJson(value);
32
37
  }
33
38
 
34
39
  @api
35
- get language() {
36
- return this._language;
40
+ get devCenter(): DevCenterConfig {
41
+ return this._devCenter;
37
42
  }
38
43
 
39
- set language(value) {
40
- if (this._language !== value) {
41
- this._language = value;
42
- }
44
+ set devCenter(value) {
45
+ this._devCenter = toJson(value);
43
46
  }
44
47
 
45
- private _language: string | null = null;
46
- private _languages!: OptionWithLink[];
47
48
  private _scopedNavItems!: OptionWithNested[];
48
- private smallMobile = false;
49
- private smallMobileMatchMedia!: MediaQueryList;
50
49
  private tablet = false;
51
50
  private tabletMatchMedia!: MediaQueryList;
51
+ private shouldRender: boolean = false;
52
+ private showDocDivider: boolean = false;
53
+ private _devCenter!: DevCenterConfig;
54
+ private _hideDocHeader: boolean = false;
52
55
 
53
56
  protected mobileBreakpoint(): string {
54
57
  return MOBILE_MATCH;
55
58
  }
56
59
 
57
- private get hasScopedNavItems(): boolean {
58
- return this.scopedNavItems && this.scopedNavItems.length > 0;
59
- }
60
-
61
- private get showDesktopNavItems(): boolean {
62
- return !this.mobile && this.hasNavItems;
63
- }
64
-
65
- private get showSignup(): boolean {
66
- return this.signupLink
67
- ? (this.tablet && !this.isSearchOpen) || !this.tablet
68
- : false;
69
- }
70
-
71
- private get hasLanguages(): boolean {
72
- return !!(this.languages && this.languages.length);
73
- }
74
-
75
- private get showMobileLanguages(): boolean {
76
- return this.smallMobile && this.hasLanguages;
77
- }
78
-
79
- private get languageLabel(): string {
60
+ private get showScopedNavItems(): boolean {
80
61
  return (
81
- (this.language &&
82
- this.languages.find(
83
- (lang) => get(lang, this.langValuePath) === this.language
84
- )?.label) ||
85
- this.languages[0].label
62
+ this.scopedNavItems &&
63
+ this.scopedNavItems.length > 0 &&
64
+ !this.hideDocHeader
86
65
  );
87
66
  }
88
67
 
89
- private get showMenuButton(): boolean {
90
- return this.mobile && this.hasNavItems;
68
+ /**
69
+ * This function returns true if the hideDocHeader is true and the view is not mobile.
70
+ * Also we need to show the header border in case the doc is hidden or if the brand information doesn't exists.
71
+ */
72
+ private get shouldHideHeader(): boolean {
73
+ return (this.hideDocHeader && !this.mobile) || this.showDocDivider;
91
74
  }
92
75
 
93
76
  connectedCallback(): void {
@@ -98,14 +81,23 @@ export default class Header extends HeaderBase {
98
81
  this.onTabletChange(this.tabletMatchMedia);
99
82
  this.tabletMatchMedia.addEventListener("change", this.onTabletChange);
100
83
 
101
- this.smallMobileMatchMedia = window.matchMedia(
102
- `(max-width: ${SMALL_MOBILE_MATCH})`
103
- );
104
- this.onSmallMobileChange(this.smallMobileMatchMedia);
105
- this.smallMobileMatchMedia.addEventListener(
106
- "change",
107
- this.onSmallMobileChange
108
- );
84
+ if (
85
+ (!this.shouldHideHeader &&
86
+ window.location.pathname.includes("/docs/") &&
87
+ window.location.pathname !== "/docs/apis") ||
88
+ window.location.pathname ===
89
+ "/tableau/embedding-playground/overview" ||
90
+ isStorybook()
91
+ ) {
92
+ this.shouldRender = true;
93
+ }
94
+
95
+ if (this.shouldRender && window.location.pathname.includes("/docs/")) {
96
+ if (!this.brand && !this.mobile) {
97
+ this.shouldRender = false;
98
+ this.showDocDivider = true;
99
+ }
100
+ }
109
101
  }
110
102
 
111
103
  disconnectedCallback(): void {
@@ -114,29 +106,15 @@ export default class Header extends HeaderBase {
114
106
  "change",
115
107
  this.onTabletChange
116
108
  );
117
-
118
- this.smallMobileMatchMedia.removeEventListener(
119
- "change",
120
- this.onSmallMobileChange
121
- );
122
109
  }
123
110
 
124
111
  private onTabletChange = (e: MediaQueryListEvent | MediaQueryList) =>
125
112
  (this.tablet = e.matches);
126
113
 
127
- private onSmallMobileChange = (e: MediaQueryListEvent | MediaQueryList) =>
128
- (this.smallMobile = e.matches);
129
-
130
114
  protected additionalClasses(): string {
131
115
  return cx(
132
116
  this.brand && "has-brand",
133
- this.hasScopedNavItems && "has-scoped-nav-items"
117
+ this.showScopedNavItems && "has-scoped-nav-items"
134
118
  );
135
119
  }
136
-
137
- private onLangChange(event: CustomEvent<string>): void {
138
- const { detail } = event;
139
- this._language = detail;
140
- this.dispatchEvent(new CustomEvent("langchange", { detail }));
141
- }
142
120
  }
@@ -1,54 +1,33 @@
1
- h1,
2
- h2,
3
- h3,
4
- h4,
5
- h5,
6
- h6 {
7
- color: var(--dx-g-blue-vibrant-20);
8
- font-family: var(--dx-g-font-display);
9
- font-weight: var(--dx-g-font-demi);
10
- }
1
+ @import "dxHelpers/text";
11
2
 
12
- .display-3 {
13
- margin: 0 0 24px 0;
14
- font-size: var(--dx-g-text-3xl);
15
- letter-spacing: -0.85px;
16
- line-height: var(--dx-g-text-4xl);
3
+ h1 {
4
+ margin: var(--dx-g-spacing-2xl) 0 var(--dx-g-spacing-md) 0;
17
5
  }
18
6
 
19
- .display-3 doc-heading-content {
20
- --doc-c-heading-anchor-button-bottom: 8px;
7
+ h1 doc-heading-content {
8
+ --doc-c-heading-anchor-button-bottom: 9.5px;
21
9
  }
22
10
 
23
- .display-4 {
24
- margin: var(--dx-g-spacing-xl) 0 var(--dx-g-spacing-md) 0;
25
- font-size: var(--dx-g-text-xl);
26
- letter-spacing: -0.1px;
27
- line-height: var(--dx-g-spacing-lg);
11
+ h2 {
12
+ margin: var(--dx-g-spacing-2xl) 0 var(--dx-g-spacing-md) 0;
28
13
  }
29
14
 
30
- .display-4 doc-heading-content {
31
- --doc-c-heading-anchor-button-bottom: -3px;
15
+ h2 doc-heading-content {
16
+ --doc-c-heading-anchor-button-bottom: 3px;
32
17
  }
33
18
 
34
- .display-5 {
35
- margin: var(--dx-g-spacing-lg) 0 var(--dx-g-spacing-md) 0;
36
- font-size: var(--dx-g-text-lg);
37
- letter-spacing: -0.1px;
38
- line-height: var(--dx-g-spacing-lg);
19
+ h3 {
20
+ margin: var(--dx-g-spacing-xl) 0 var(--dx-g-spacing-md) 0;
39
21
  }
40
22
 
41
- .display-5 doc-heading-content {
42
- --doc-c-heading-anchor-button-bottom: -4px;
23
+ h3 doc-heading-content {
24
+ --doc-c-heading-anchor-button-bottom: -0.5px;
43
25
  }
44
26
 
45
- .display-6 {
46
- margin: var(--dx-g-spacing-md) 0 var(--dx-g-spacing-sm) 0;
47
- font-size: var(--dx-g-text-base);
48
- letter-spacing: 0;
49
- line-height: var(--dx-g-spacing-mlg);
27
+ h4 {
28
+ margin: var(--dx-g-spacing-lg) 0 var(--dx-g-spacing-sm) 0;
50
29
  }
51
30
 
52
- .display-6 doc-heading-content {
31
+ h4 doc-heading-content {
53
32
  --doc-c-heading-anchor-button-bottom: -6px;
54
33
  }
@@ -1,14 +1,14 @@
1
1
  <template>
2
2
  <h1 class={className} if:true={isAriaLevelOne}>
3
- <doc-heading-content title={title} hash={hash}></doc-heading-content>
3
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
4
4
  </h1>
5
5
  <h2 class={className} if:true={isAriaLevelTwo}>
6
- <doc-heading-content title={title} hash={hash}></doc-heading-content>
6
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
7
7
  </h2>
8
8
  <h3 class={className} if:true={isAriaLevelThree}>
9
- <doc-heading-content title={title} hash={hash}></doc-heading-content>
9
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
10
10
  </h3>
11
11
  <h4 class={className} if:true={isAriaLevelFour}>
12
- <doc-heading-content title={title} hash={hash}></doc-heading-content>
12
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
13
13
  </h4>
14
14
  </template>
@@ -1,22 +1,24 @@
1
1
  import { LightningElement, api } from "lwc";
2
2
 
3
- export const displayLevels = ["3", "4", "5", "6"];
4
-
5
- export const ariaLevels = ["1", "2", "3", "4"];
6
-
7
3
  export const ariaDisplayLevels: { [key: string]: string } = {
8
- "1": "3",
9
- "2": "4",
10
- "3": "5",
11
- "4": "6"
4
+ "1": "4",
5
+ "2": "5",
6
+ "3": "6",
7
+ "4": "8"
12
8
  };
13
9
 
10
+ export const ariaLevels = Object.keys(ariaDisplayLevels);
11
+
12
+ export const displayLevels = Object.values(ariaDisplayLevels);
13
+
14
+ // @ts-ignore: Really Dark Magic (TM) to do with ariaLevel needing explicit getter/setters
14
15
  export default class Heading extends LightningElement {
15
- @api title: string = "";
16
+ @api header: string = "";
16
17
  @api hash: string | null = null;
17
18
 
18
19
  @api
19
20
  private get ariaLevel(): string {
21
+ // Really Dark Magic (TM)
20
22
  return this._ariaLevel || "2";
21
23
  }
22
24
  private set ariaLevel(value: string | null) {
@@ -60,6 +62,6 @@ export default class Heading extends LightningElement {
60
62
  }
61
63
 
62
64
  private get className(): string {
63
- return `display-${this.displayLevel}`;
65
+ return `dx-text-display-${this.displayLevel}`;
64
66
  }
65
67
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  button {
4
4
  opacity: 0;
5
- color: rgb(11, 92, 171);
5
+ color: rgb(11 92 171);
6
6
  }
7
7
 
8
8
  button:hover {
@@ -17,7 +17,7 @@ button:focus {
17
17
 
18
18
  button:focus-visible {
19
19
  border-radius: 4px;
20
- border: 2px solid rgb(11, 92, 171);
20
+ border: 2px solid rgb(11 92 171);
21
21
  }
22
22
 
23
23
  .icon-wrapper {
@@ -6,7 +6,7 @@ export default class HeadingAnchor extends LightningElement {
6
6
  @api iconSize?: IconSize = "override";
7
7
  @api iconSprite?: IconSprite = "utility";
8
8
  @api iconSymbol?: IconSymbol;
9
- @api title: string = "";
9
+ @api header: string = "";
10
10
  @api urlText: string = "";
11
11
 
12
12
  label: string = "Copy link to clipboard";
@@ -22,7 +22,7 @@ export default class HeadingAnchor extends LightningElement {
22
22
  }, 2000);
23
23
 
24
24
  try {
25
- if (this.title && this.urlText) {
25
+ if (this.header && this.urlText) {
26
26
  const [hostUrl] = window.location.href.split("#");
27
27
  const url = `${hostUrl}#${this.urlText}`;
28
28
  await navigator.clipboard.writeText(url);
@@ -23,7 +23,7 @@ button {
23
23
  bottom: var(--doc-c-heading-anchor-button-bottom);
24
24
  left: 0;
25
25
  opacity: 0;
26
- color: rgb(11, 92, 171);
26
+ color: rgb(11 92 171);
27
27
  display: flex;
28
28
  justify-content: center;
29
29
  align-items: center;
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <template if:false={hash}>{title}</template>
2
+ <template if:false={hash}>{header}</template>
3
3
  <template if:true={hash}>
4
- <span class="title">{title}&nbsp;</span>
4
+ <span class="title">{header}&nbsp;</span>
5
5
  <dx-tooltip placement="top" label={label}>
6
6
  <span class="button-container">
7
7
  <button onclick={copy} aria-label="copy">
@@ -1,7 +1,7 @@
1
1
  import { LightningElement, api } from "lwc";
2
2
 
3
3
  export default class HeadingContent extends LightningElement {
4
- @api title: string = "";
4
+ @api header: string = "";
5
5
  @api hash: string | null = null;
6
6
 
7
7
  label: string = "Copy link to clipboard";
@@ -18,7 +18,7 @@ export default class HeadingContent extends LightningElement {
18
18
  }, 2000);
19
19
 
20
20
  try {
21
- if (this.title && this.hash) {
21
+ if (this.header && this.hash) {
22
22
  const [hostUrl] = window.location.href.split("#");
23
23
  const url = `${hostUrl}#${this.hash}`;
24
24
  await navigator.clipboard.writeText(url);
@@ -0,0 +1 @@
1
+ @import "docHelpers/contentLayoutStyle";
@@ -0,0 +1,68 @@
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-breadcrumbs
47
+ lwc:if={showBreadcrumbs}
48
+ breadcrumbs={breadcrumbs}
49
+ ></doc-breadcrumbs>
50
+ <slot onslotchange={onSlotChange}></slot>
51
+ <doc-sprig-survey
52
+ lwc:if={shouldDisplayFeedback}
53
+ ></doc-sprig-survey>
54
+ </div>
55
+ <div lwc:if={showToc} class="right-nav-bar is-sticky">
56
+ <dx-toc
57
+ header={tocTitle}
58
+ options={tocOptions}
59
+ value={tocValue}
60
+ ></dx-toc>
61
+ </div>
62
+ </div>
63
+ <div lwc:if={showFooter} class="footer-container">
64
+ <dx-footer variant="no-signup"></dx-footer>
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </template>
@@ -0,0 +1,168 @@
1
+ import ContentLayout from "doc/contentLayout";
2
+
3
+ const TOC_HEADER_TAG = "doc-heading";
4
+ const RNB_BY_TAB = "docs-tab";
5
+ const SPECIFICATION_TAB_TITLE = "Specification";
6
+ export const OBSERVER_ATTACH_WAIT_TIME = 500;
7
+
8
+ export default class LwcContentLayout extends ContentLayout {
9
+ private rnbByTab: boolean = false;
10
+
11
+ private setRNBByTab() {
12
+ const tabPanelListItem: any = this.getTabPanelList();
13
+ this.rnbByTab = tabPanelListItem?.id === RNB_BY_TAB ? true : false;
14
+ }
15
+
16
+ get showTabBasedRNB() {
17
+ return this.rnbByTab;
18
+ }
19
+
20
+ onRNBClick = (event: CustomEvent) => {
21
+ event.stopPropagation();
22
+ const currentTab = this.getSelectedTabId();
23
+ if (currentTab === SPECIFICATION_TAB_TITLE) {
24
+ this.didScrollToSelectedHash = false;
25
+ }
26
+ };
27
+
28
+ onTabChanged = () => {
29
+ this.updateRNB();
30
+ };
31
+
32
+ private getTabPanelList() {
33
+ // eslint-disable-next-line @lwc/lwc/no-document-query
34
+ return document.querySelector("dx-tab-panel-list");
35
+ }
36
+
37
+ protected getHeadingElements() {
38
+ let headingElements = super.getHeadingElements();
39
+ if (this.showTabBasedRNB) {
40
+ const tabPanelListItem: any = this.getTabPanelList();
41
+ const tabPanels =
42
+ tabPanelListItem?.querySelectorAll("dx-tab-panel");
43
+ for (const tabPanelItem of tabPanels) {
44
+ if (tabPanelItem.active) {
45
+ // This is needed for Specification tab content
46
+ const specificationElement = tabPanelItem.querySelector(
47
+ "doc-specification-content"
48
+ );
49
+ if (specificationElement) {
50
+ headingElements =
51
+ specificationElement.shadowRoot.querySelectorAll(
52
+ TOC_HEADER_TAG
53
+ );
54
+ } else {
55
+ headingElements =
56
+ tabPanelItem.querySelectorAll(TOC_HEADER_TAG);
57
+ }
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ return headingElements;
63
+ }
64
+
65
+ private updateURL() {
66
+ const tabs = this.getAllTabs();
67
+ const selectedTabId = this.getSelectedTabId();
68
+ tabs.forEach((tab: any) => {
69
+ if (tab.getAttribute("aria-selected") === "true") {
70
+ const tabID = tab.getAttribute("aria-label");
71
+ const url = new URL(window.location.href);
72
+ if (selectedTabId !== tabID) {
73
+ url.searchParams.set("type", tabID);
74
+ url.hash = "";
75
+ window.history.pushState({}, "", url.toString());
76
+ }
77
+ }
78
+ });
79
+ }
80
+
81
+ // This event gets triggered when navigating back/forward
82
+ handlePopState = (): void => {
83
+ if (this.showTabBasedRNB) {
84
+ this.restoreTabSelection();
85
+ }
86
+ };
87
+
88
+ connectedCallback(): void {
89
+ super.connectedCallback();
90
+ window.addEventListener("popstate", this.handlePopState);
91
+ }
92
+
93
+ private getSelectedTabId() {
94
+ const urlParams = new URLSearchParams(window.location.search);
95
+ const selectedTabId = urlParams.get("type");
96
+ return selectedTabId;
97
+ }
98
+
99
+ private restoreTabSelection() {
100
+ requestAnimationFrame(() => {
101
+ const selectedTabId = this.getSelectedTabId();
102
+ if (selectedTabId) {
103
+ this.selectTabById(selectedTabId);
104
+ }
105
+ });
106
+ }
107
+
108
+ private getAllTabs(): any[] {
109
+ const tabPanelListItem: any = this.getTabPanelList();
110
+ if (tabPanelListItem?.shadowRoot) {
111
+ return Array.from(
112
+ tabPanelListItem.shadowRoot.querySelectorAll(
113
+ "dx-tab-panel-item"
114
+ )
115
+ ).map((tabPanelItem: any) =>
116
+ tabPanelItem.shadowRoot.querySelector("button")
117
+ );
118
+ }
119
+ return [];
120
+ }
121
+
122
+ private selectTabById(tabId: string) {
123
+ const tabs = this.getAllTabs();
124
+ tabs.forEach((tab: any) => {
125
+ if (tab.getAttribute("aria-label") === tabId) {
126
+ tab.click();
127
+ }
128
+ });
129
+ }
130
+
131
+ postRenderedCallback(): void {
132
+ this.setRNBByTab();
133
+ if (this.showTabBasedRNB) {
134
+ window.addEventListener("tabchanged", this.onTabChanged);
135
+ window.addEventListener(
136
+ "specificationdatarendered",
137
+ this.onTabChanged
138
+ );
139
+ window.addEventListener("selectedcontent", (event) =>
140
+ this.onRNBClick(event as CustomEvent)
141
+ );
142
+ this.restoreTabSelection();
143
+ }
144
+ }
145
+
146
+ disconnectedCallback(): void {
147
+ super.disconnectedCallback();
148
+ if (this.showTabBasedRNB) {
149
+ window.removeEventListener("tabchanged", this.onTabChanged);
150
+ window.removeEventListener(
151
+ "specificationdatarendered",
152
+ this.onTabChanged
153
+ );
154
+ window.removeEventListener("selectedcontent", (event) =>
155
+ this.onRNBClick(event as CustomEvent)
156
+ );
157
+ window.removeEventListener("popstate", this.handlePopState);
158
+ }
159
+ }
160
+
161
+ updateHeadingForRNB(): void {
162
+ // We only need to update URL in case of /docs and ignore if tabs are used anywhere else in DSC
163
+ if (this.showTabBasedRNB) {
164
+ this.updateURL();
165
+ }
166
+ super.updateHeadingForRNB();
167
+ }
168
+ }
@@ -0,0 +1,40 @@
1
+ doc-phase {
2
+ --doc-c-phase-top: calc(
3
+ var(--dx-g-global-header-height) + var(--dx-g-doc-header-height)
4
+ );
5
+ }
6
+
7
+ dx-section {
8
+ --dx-c-section-padding-top: 0;
9
+ --dx-c-section-padding-bottom: var(--dx-g-spacing-2xl);
10
+ }
11
+
12
+ dx-section::part(content) {
13
+ max-width: 1280px;
14
+ margin: auto;
15
+ }
16
+
17
+ dx-group-text:first-of-type {
18
+ margin-top: var(--dx-g-spacing-2xl);
19
+ }
20
+
21
+ dx-group-text.features {
22
+ margin-top: var(--dx-g-spacing-xl);
23
+ margin-bottom: var(--dx-g-spacing-xl);
24
+ }
25
+
26
+ .content {
27
+ padding-right: var(--dx-g-spacing-xl);
28
+ }
29
+
30
+ @media (max-width: 1024px) {
31
+ .content {
32
+ padding-right: 0;
33
+ }
34
+ }
35
+
36
+ @media (max-width: 800px) {
37
+ dx-group-text.description {
38
+ margin-top: var(--dx-g-spacing-lg);
39
+ }
40
+ }