@salesforcedevs/docs-components 0.0.7 → 0.0.9-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 (141) hide show
  1. package/lwc.config.json +25 -2
  2. package/package.json +17 -6
  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 +249 -87
  29. package/src/modules/doc/content/content.html +3 -2
  30. package/src/modules/doc/content/content.ts +272 -152
  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 +21 -10
  34. package/src/modules/doc/contentLayout/contentLayout.css +1 -0
  35. package/src/modules/doc/contentLayout/contentLayout.html +68 -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 +511 -0
  44. package/src/modules/doc/editFile/editFile.html +163 -0
  45. package/src/modules/doc/editFile/editFile.ts +238 -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.ts +1 -1
  63. package/src/modules/doc/overview/overview.css +40 -0
  64. package/src/modules/doc/overview/overview.html +34 -0
  65. package/src/modules/doc/overview/overview.ts +12 -0
  66. package/src/modules/doc/phase/phase.css +70 -0
  67. package/src/modules/doc/phase/phase.html +38 -0
  68. package/src/modules/doc/phase/phase.ts +93 -0
  69. package/src/modules/doc/specificationContent/specificationContent.css +36 -0
  70. package/src/modules/doc/specificationContent/specificationContent.html +171 -0
  71. package/src/modules/doc/specificationContent/specificationContent.ts +127 -0
  72. package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
  73. package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
  74. package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
  75. package/src/modules/doc/toc/toc.html +11 -6
  76. package/src/modules/doc/toc/toc.ts +1 -1
  77. package/src/modules/doc/toolbar/toolbar.html +8 -1
  78. package/src/modules/doc/versionPicker/versionPicker.css +64 -0
  79. package/src/modules/doc/versionPicker/versionPicker.html +38 -0
  80. package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
  81. package/src/modules/doc/xmlContent/types.ts +120 -0
  82. package/src/modules/doc/xmlContent/utils.ts +163 -0
  83. package/src/modules/doc/xmlContent/xmlContent.css +54 -0
  84. package/src/modules/doc/xmlContent/xmlContent.html +52 -0
  85. package/src/modules/doc/xmlContent/xmlContent.ts +792 -0
  86. package/src/modules/docHelpers/amfStyle/amfStyle.css +355 -0
  87. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
  88. package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
  89. package/src/modules/docHelpers/status/status.css +22 -0
  90. package/src/modules/docUtils/searchSyncer/searchSyncer.ts +86 -0
  91. package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
  92. package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
  93. package/src/modules/docUtils/utils/utils.ts +32 -0
  94. package/src/modules/doc/container/__benchmarks__/container.benchmark.js +0 -43
  95. package/src/modules/doc/container/__mocks__/mockAvailableLanguages.js +0 -8
  96. package/src/modules/doc/container/__mocks__/mockAvailableVersions.js +0 -122
  97. package/src/modules/doc/container/__mocks__/mockContentFetchResponse.json +0 -5
  98. package/src/modules/doc/container/__mocks__/mockDocContent.js +0 -29
  99. package/src/modules/doc/container/__mocks__/mockNavigationFetchResponse.json +0 -4061
  100. package/src/modules/doc/container/__mocks__/mockPageReference.js +0 -8
  101. package/src/modules/doc/container/__mocks__/mockPdfUrl.js +0 -1
  102. package/src/modules/doc/container/__mocks__/mockSelectedLanguage.js +0 -8
  103. package/src/modules/doc/container/__mocks__/mockSelectedVersion.js +0 -8
  104. package/src/modules/doc/container/__mocks__/mockToc.js +0 -146
  105. package/src/modules/doc/container/__tests__/container.test.ts +0 -82
  106. package/src/modules/doc/container/container.css +0 -34
  107. package/src/modules/doc/container/container.html +0 -23
  108. package/src/modules/doc/container/container.stories.ts +0 -18
  109. package/src/modules/doc/container/container.ts +0 -356
  110. package/src/modules/doc/content/__tests__/content.test.ts +0 -30
  111. package/src/modules/doc/content/__tests__/mockDocContent.ts +0 -29
  112. package/src/modules/doc/content/__tests__/mockPageReference.ts +0 -8
  113. package/src/modules/doc/contentCallout/__tests__/contentCallout.test.ts +0 -80
  114. package/src/modules/doc/contentCallout/__tests__/mockProps.ts +0 -14
  115. package/src/modules/doc/contentCallout/contentCallout.stories.ts +0 -29
  116. package/src/modules/doc/landing/__tests__/landing.test.ts +0 -32
  117. package/src/modules/doc/landing/__tests__/mockFetch.json +0 -370
  118. package/src/modules/doc/landing/landing.css +0 -66
  119. package/src/modules/doc/landing/landing.html +0 -109
  120. package/src/modules/doc/landing/landing.stories.ts +0 -10
  121. package/src/modules/doc/landing/landing.ts +0 -225
  122. package/src/modules/doc/nav/__tests__/mockAvailableLanguages.ts +0 -8
  123. package/src/modules/doc/nav/__tests__/mockAvailableVersions.ts +0 -122
  124. package/src/modules/doc/nav/__tests__/mockPageReference.ts +0 -8
  125. package/src/modules/doc/nav/__tests__/mockPdfUrl.ts +0 -1
  126. package/src/modules/doc/nav/__tests__/mockSelectedLanguage.ts +0 -8
  127. package/src/modules/doc/nav/__tests__/mockSelectedVersion.ts +0 -8
  128. package/src/modules/doc/nav/__tests__/mockToc.ts +0 -146
  129. package/src/modules/doc/nav/__tests__/nav.test.ts +0 -62
  130. package/src/modules/doc/search/__tests__/search.test.ts +0 -20
  131. package/src/modules/doc/search/search.html +0 -1
  132. package/src/modules/doc/search/search.ts +0 -3
  133. package/src/modules/doc/toc/__tests__/mockPageReference.ts +0 -8
  134. package/src/modules/doc/toc/__tests__/mockToc.ts +0 -146
  135. package/src/modules/doc/toc/__tests__/toc.test.ts +0 -29
  136. package/src/modules/doc/toolbar/__tests__/mockAvailableLanguages.ts +0 -8
  137. package/src/modules/doc/toolbar/__tests__/mockAvailableVersions.ts +0 -122
  138. package/src/modules/doc/toolbar/__tests__/mockPdfUrl.ts +0 -1
  139. package/src/modules/doc/toolbar/__tests__/mockSelectedLanguage.ts +0 -8
  140. package/src/modules/doc/toolbar/__tests__/mockSelectedVersion.ts +0 -8
  141. package/src/modules/doc/toolbar/__tests__/toolbar.test.ts +0 -44
@@ -0,0 +1,120 @@
1
+ import { api } from "lwc";
2
+ import cx from "classnames";
3
+ import type { OptionWithNested, DevCenterConfig } from "typings/custom";
4
+ import { HeaderBase } from "dxBaseElements/headerBase";
5
+ import { toJson, normalizeBoolean } from "dxUtils/normalizers";
6
+
7
+ const TABLET_MATCH = "980px";
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
+ };
16
+
17
+ export default class Header extends HeaderBase {
18
+ @api langValuePath: string = "id"; // allows to override how language property is interpreted, follows valuePath dropdown api.
19
+ @api headerHref: string = "/";
20
+
21
+ @api
22
+ get hideDocHeader() {
23
+ return this._hideDocHeader;
24
+ }
25
+
26
+ set hideDocHeader(value) {
27
+ this._hideDocHeader = normalizeBoolean(value);
28
+ }
29
+
30
+ @api
31
+ get scopedNavItems() {
32
+ return this._scopedNavItems;
33
+ }
34
+
35
+ set scopedNavItems(value) {
36
+ this._scopedNavItems = toJson(value);
37
+ }
38
+
39
+ @api
40
+ get devCenter(): DevCenterConfig {
41
+ return this._devCenter;
42
+ }
43
+
44
+ set devCenter(value) {
45
+ this._devCenter = toJson(value);
46
+ }
47
+
48
+ private _scopedNavItems!: OptionWithNested[];
49
+ private tablet = false;
50
+ private tabletMatchMedia!: MediaQueryList;
51
+ private shouldRender: boolean = false;
52
+ private showDocDivider: boolean = false;
53
+ private _devCenter!: DevCenterConfig;
54
+ private _hideDocHeader: boolean = false;
55
+
56
+ protected mobileBreakpoint(): string {
57
+ return MOBILE_MATCH;
58
+ }
59
+
60
+ private get showScopedNavItems(): boolean {
61
+ return (
62
+ this.scopedNavItems &&
63
+ this.scopedNavItems.length > 0 &&
64
+ !this.hideDocHeader
65
+ );
66
+ }
67
+
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;
74
+ }
75
+
76
+ connectedCallback(): void {
77
+ super.connectedCallback();
78
+ this.tabletMatchMedia = window.matchMedia(
79
+ `(max-width: ${TABLET_MATCH})`
80
+ );
81
+ this.onTabletChange(this.tabletMatchMedia);
82
+ this.tabletMatchMedia.addEventListener("change", this.onTabletChange);
83
+
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
+ }
101
+ }
102
+
103
+ disconnectedCallback(): void {
104
+ super.disconnectedCallback();
105
+ this.tabletMatchMedia.removeEventListener(
106
+ "change",
107
+ this.onTabletChange
108
+ );
109
+ }
110
+
111
+ private onTabletChange = (e: MediaQueryListEvent | MediaQueryList) =>
112
+ (this.tablet = e.matches);
113
+
114
+ protected additionalClasses(): string {
115
+ return cx(
116
+ this.brand && "has-brand",
117
+ this.showScopedNavItems && "has-scoped-nav-items"
118
+ );
119
+ }
120
+ }
@@ -0,0 +1,33 @@
1
+ @import "dxHelpers/text";
2
+
3
+ h1 {
4
+ margin: var(--dx-g-spacing-2xl) 0 var(--dx-g-spacing-md) 0;
5
+ }
6
+
7
+ h1 doc-heading-content {
8
+ --doc-c-heading-anchor-button-bottom: 9.5px;
9
+ }
10
+
11
+ h2 {
12
+ margin: var(--dx-g-spacing-2xl) 0 var(--dx-g-spacing-md) 0;
13
+ }
14
+
15
+ h2 doc-heading-content {
16
+ --doc-c-heading-anchor-button-bottom: 3px;
17
+ }
18
+
19
+ h3 {
20
+ margin: var(--dx-g-spacing-xl) 0 var(--dx-g-spacing-md) 0;
21
+ }
22
+
23
+ h3 doc-heading-content {
24
+ --doc-c-heading-anchor-button-bottom: -0.5px;
25
+ }
26
+
27
+ h4 {
28
+ margin: var(--dx-g-spacing-lg) 0 var(--dx-g-spacing-sm) 0;
29
+ }
30
+
31
+ h4 doc-heading-content {
32
+ --doc-c-heading-anchor-button-bottom: -6px;
33
+ }
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <h1 class={className} if:true={isAriaLevelOne}>
3
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
4
+ </h1>
5
+ <h2 class={className} if:true={isAriaLevelTwo}>
6
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
7
+ </h2>
8
+ <h3 class={className} if:true={isAriaLevelThree}>
9
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
10
+ </h3>
11
+ <h4 class={className} if:true={isAriaLevelFour}>
12
+ <doc-heading-content header={header} hash={hash}></doc-heading-content>
13
+ </h4>
14
+ </template>
@@ -0,0 +1,67 @@
1
+ import { LightningElement, api } from "lwc";
2
+
3
+ export const ariaDisplayLevels: { [key: string]: string } = {
4
+ "1": "4",
5
+ "2": "5",
6
+ "3": "6",
7
+ "4": "8"
8
+ };
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
15
+ export default class Heading extends LightningElement {
16
+ @api header: string = "";
17
+ @api hash: string | null = null;
18
+
19
+ @api
20
+ private get ariaLevel(): string {
21
+ // Really Dark Magic (TM)
22
+ return this._ariaLevel || "2";
23
+ }
24
+ private set ariaLevel(value: string | null) {
25
+ if (value && !ariaLevels.includes(value)) {
26
+ console.error(`Invalid aria-level: "${value}"`);
27
+ return;
28
+ }
29
+ if (value) {
30
+ this._ariaLevel = value;
31
+ }
32
+ }
33
+
34
+ @api
35
+ private get displayLevel(): string {
36
+ return this._displayLevel || ariaDisplayLevels[this.ariaLevel];
37
+ }
38
+ private set displayLevel(value: string | null) {
39
+ if (value && !displayLevels.includes(value)) {
40
+ console.error(`Invalid display-level: "${value}"`);
41
+ value = null;
42
+ }
43
+ if (value) {
44
+ this._displayLevel = value;
45
+ }
46
+ }
47
+
48
+ private _ariaLevel: string | null = null;
49
+ private _displayLevel: string | null = null;
50
+
51
+ private get isAriaLevelOne(): boolean {
52
+ return this.ariaLevel === "1";
53
+ }
54
+ private get isAriaLevelTwo(): boolean {
55
+ return this.ariaLevel === "2";
56
+ }
57
+ private get isAriaLevelThree(): boolean {
58
+ return this.ariaLevel === "3";
59
+ }
60
+ private get isAriaLevelFour(): boolean {
61
+ return this.ariaLevel === "4";
62
+ }
63
+
64
+ private get className(): string {
65
+ return `dx-text-display-${this.displayLevel}`;
66
+ }
67
+ }
@@ -0,0 +1,33 @@
1
+ @import "dxHelpers/reset";
2
+
3
+ button {
4
+ opacity: 0;
5
+ color: rgb(11 92 171);
6
+ }
7
+
8
+ button:hover {
9
+ opacity: 1;
10
+ outline: none;
11
+ }
12
+
13
+ button:focus {
14
+ opacity: 1;
15
+ outline: none;
16
+ }
17
+
18
+ button:focus-visible {
19
+ border-radius: 4px;
20
+ border: 2px solid rgb(11 92 171);
21
+ }
22
+
23
+ .icon-wrapper {
24
+ height: 32px;
25
+ width: 32px;
26
+ display: flex;
27
+ justify-content: center;
28
+ align-items: center;
29
+ }
30
+
31
+ .icon-container {
32
+ --dx-c-icon-size: 18px;
33
+ }
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <dx-tooltip placement="top" label={label}>
3
+ <button
4
+ onclick={onIconClick}
5
+ aria-label={ariaLabel}
6
+ onkeydown={onKeyDown}
7
+ part="headingAnchorIcon"
8
+ >
9
+ <div class="icon-wrapper">
10
+ <dx-icon
11
+ sprite={iconSprite}
12
+ size={iconSize}
13
+ symbol={iconSymbol}
14
+ class="icon-container"
15
+ ></dx-icon>
16
+ </div>
17
+ </button>
18
+ </dx-tooltip>
19
+ </template>
@@ -0,0 +1,43 @@
1
+ import { LightningElement, api } from "lwc";
2
+ import { IconSprite, IconSize, IconSymbol } from "typings/custom";
3
+
4
+ export default class HeadingAnchor extends LightningElement {
5
+ @api ariaLabel: string = "copy";
6
+ @api iconSize?: IconSize = "override";
7
+ @api iconSprite?: IconSprite = "utility";
8
+ @api iconSymbol?: IconSymbol;
9
+ @api header: string = "";
10
+ @api urlText: string = "";
11
+
12
+ label: string = "Copy link to clipboard";
13
+
14
+ private async onIconClick() {
15
+ await this.iconClickHandler();
16
+ }
17
+
18
+ private async iconClickHandler() {
19
+ this.label = "Copied";
20
+ setTimeout(() => {
21
+ this.label = "Copy link to clipboard";
22
+ }, 2000);
23
+
24
+ try {
25
+ if (this.header && this.urlText) {
26
+ const [hostUrl] = window.location.href.split("#");
27
+ const url = `${hostUrl}#${this.urlText}`;
28
+ await navigator.clipboard.writeText(url);
29
+ }
30
+ } catch (error) {
31
+ console.error(error);
32
+ }
33
+ }
34
+
35
+ private async onKeyDown(e: KeyboardEvent) {
36
+ switch (e.key) {
37
+ case "Enter":
38
+ await this.iconClickHandler();
39
+ break;
40
+ default:
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,53 @@
1
+ @import "dxHelpers/reset";
2
+
3
+ :host {
4
+ --doc-c-heading-anchor-button-bottom: 0;
5
+ --doc-c-heading-anchor-icon-size: 18px;
6
+ --button-size: var(--dx-g-spacing-xl);
7
+ }
8
+
9
+ dx-tooltip {
10
+ line-height: var(--button-size);
11
+ padding-right: var(--dx-g-spacing-xs);
12
+ }
13
+
14
+ .button-container {
15
+ height: 100%;
16
+ margin-right: calc(var(--dx-g-spacing-xl) - 4px);
17
+ position: relative;
18
+ padding-right: var(--dx-g-spacing-xs);
19
+ }
20
+
21
+ button {
22
+ position: absolute;
23
+ bottom: var(--doc-c-heading-anchor-button-bottom);
24
+ left: 0;
25
+ opacity: 0;
26
+ color: rgb(11 92 171);
27
+ display: flex;
28
+ justify-content: center;
29
+ align-items: center;
30
+ height: var(--button-size);
31
+ width: var(--button-size);
32
+ border-radius: 4px;
33
+ }
34
+
35
+ dx-icon {
36
+ --dx-c-icon-size: var(--doc-c-heading-anchor-icon-size);
37
+ }
38
+
39
+ .title {
40
+ word-break: break-word;
41
+ }
42
+
43
+ button:focus {
44
+ box-shadow: 0 0 0 2px rgb(11 92 171);
45
+ }
46
+
47
+ button:focus,
48
+ button:hover,
49
+ span:hover dx-tooltip button,
50
+ span:hover ~ dx-tooltip button {
51
+ opacity: 1;
52
+ outline: none;
53
+ }
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <template if:false={hash}>{header}</template>
3
+ <template if:true={hash}>
4
+ <span class="title">{header}&nbsp;</span>
5
+ <dx-tooltip placement="top" label={label}>
6
+ <span class="button-container">
7
+ <button onclick={copy} aria-label="copy">
8
+ <dx-icon size="override" symbol="link"></dx-icon>
9
+ </button>
10
+ </span>
11
+ </dx-tooltip>
12
+ </template>
13
+ </template>
@@ -0,0 +1,30 @@
1
+ import { LightningElement, api } from "lwc";
2
+
3
+ export default class HeadingContent extends LightningElement {
4
+ @api header: string = "";
5
+ @api hash: string | null = null;
6
+
7
+ label: string = "Copy link to clipboard";
8
+ timeout: number | null = null;
9
+
10
+ private async copy() {
11
+ if (this.timeout) {
12
+ window.clearTimeout(this.timeout);
13
+ }
14
+
15
+ this.label = "Copied";
16
+ this.timeout = window.setTimeout(() => {
17
+ this.label = "Copy link to clipboard";
18
+ }, 2000);
19
+
20
+ try {
21
+ if (this.header && this.hash) {
22
+ const [hostUrl] = window.location.href.split("#");
23
+ const url = `${hostUrl}#${this.hash}`;
24
+ await navigator.clipboard.writeText(url);
25
+ }
26
+ } catch (error) {
27
+ console.error(error);
28
+ }
29
+ }
30
+ }
@@ -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
+ }
@@ -7,6 +7,8 @@
7
7
  width: 100%;
8
8
  }
9
9
 
10
- doc-toc {
11
- margin-top: 15px;
10
+ dx-sidebar {
11
+ --dx-c-sidebar-width: unset;
12
+
13
+ display: block;
12
14
  }
@@ -8,7 +8,7 @@ import {
8
8
  SelectedNavigationItem,
9
9
  SelectedLanguage,
10
10
  SelectedVersion
11
- } from "../../../../../../../typings/custom";
11
+ } from "typings/custom";
12
12
 
13
13
  export default class Nav extends LightningElement {
14
14
  @api availableLanguages!: AvailableLanguages;