@salesforcedevs/docs-components 0.0.2 → 0.0.3-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 (108) hide show
  1. package/lwc.config.json +27 -2
  2. package/package.json +19 -8
  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 +818 -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 +388 -4
  29. package/src/modules/doc/content/content.html +3 -2
  30. package/src/modules/doc/content/content.ts +319 -45
  31. package/src/modules/doc/contentCallout/contentCallout.css +59 -0
  32. package/src/modules/doc/contentCallout/contentCallout.html +22 -0
  33. package/src/modules/doc/contentCallout/contentCallout.ts +65 -0
  34. package/src/modules/doc/contentLayout/contentLayout.css +1 -0
  35. package/src/modules/doc/contentLayout/contentLayout.html +72 -0
  36. package/src/modules/doc/contentLayout/contentLayout.ts +531 -0
  37. package/src/modules/doc/contentMedia/contentMedia.css +49 -0
  38. package/src/modules/doc/contentMedia/contentMedia.html +23 -0
  39. package/src/modules/doc/contentMedia/contentMedia.ts +34 -0
  40. package/src/modules/doc/doDont/doDont.css +47 -0
  41. package/src/modules/doc/doDont/doDont.html +27 -0
  42. package/src/modules/doc/doDont/doDont.ts +17 -0
  43. package/src/modules/doc/editFile/editFile.css +505 -0
  44. package/src/modules/doc/editFile/editFile.html +164 -0
  45. package/src/modules/doc/editFile/editFile.ts +213 -0
  46. package/src/modules/doc/header/header.css +132 -0
  47. package/src/modules/doc/header/header.html +55 -0
  48. package/src/modules/doc/header/header.ts +120 -0
  49. package/src/modules/doc/heading/heading.css +33 -0
  50. package/src/modules/doc/heading/heading.html +14 -0
  51. package/src/modules/doc/heading/heading.ts +67 -0
  52. package/src/modules/doc/headingAnchor/headingAnchor.css +33 -0
  53. package/src/modules/doc/headingAnchor/headingAnchor.html +19 -0
  54. package/src/modules/doc/headingAnchor/headingAnchor.ts +43 -0
  55. package/src/modules/doc/headingContent/headingContent.css +53 -0
  56. package/src/modules/doc/headingContent/headingContent.html +13 -0
  57. package/src/modules/doc/headingContent/headingContent.ts +30 -0
  58. package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +1 -0
  59. package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +68 -0
  60. package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +168 -0
  61. package/src/modules/doc/nav/nav.css +8 -2
  62. package/src/modules/doc/nav/nav.html +10 -7
  63. package/src/modules/doc/nav/nav.ts +33 -29
  64. package/src/modules/doc/overview/overview.css +40 -0
  65. package/src/modules/doc/overview/overview.html +34 -0
  66. package/src/modules/doc/overview/overview.ts +12 -0
  67. package/src/modules/doc/phase/phase.css +70 -0
  68. package/src/modules/doc/phase/phase.html +38 -0
  69. package/src/modules/doc/phase/phase.ts +93 -0
  70. package/src/modules/doc/specificationContent/specificationContent.css +36 -0
  71. package/src/modules/doc/specificationContent/specificationContent.html +171 -0
  72. package/src/modules/doc/specificationContent/specificationContent.ts +127 -0
  73. package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
  74. package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
  75. package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
  76. package/src/modules/doc/toc/toc.css +14 -0
  77. package/src/modules/doc/toc/toc.html +99 -22
  78. package/src/modules/doc/toc/toc.ts +11 -6
  79. package/src/modules/doc/toolbar/toolbar.css +8 -0
  80. package/src/modules/doc/toolbar/toolbar.html +32 -15
  81. package/src/modules/doc/toolbar/toolbar.ts +69 -30
  82. package/src/modules/doc/versionPicker/versionPicker.css +64 -0
  83. package/src/modules/doc/versionPicker/versionPicker.html +38 -0
  84. package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
  85. package/src/modules/doc/xmlContent/types.ts +120 -0
  86. package/src/modules/doc/xmlContent/utils.ts +163 -0
  87. package/src/modules/doc/xmlContent/xmlContent.css +54 -0
  88. package/src/modules/doc/xmlContent/xmlContent.html +52 -0
  89. package/src/modules/doc/xmlContent/xmlContent.ts +792 -0
  90. package/src/modules/docHelpers/amfStyle/amfStyle.css +355 -0
  91. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
  92. package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
  93. package/src/modules/docHelpers/status/status.css +22 -0
  94. package/src/modules/docUtils/searchSyncer/searchSyncer.ts +86 -0
  95. package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
  96. package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
  97. package/src/modules/docUtils/utils/utils.ts +32 -0
  98. package/src/modules/doc/container/__benchmarks__/container.benchmarkrenamed.js +0 -18
  99. package/src/modules/doc/container/container.css +0 -8
  100. package/src/modules/doc/container/container.html +0 -11
  101. package/src/modules/doc/container/container.stories.ts +0 -15
  102. package/src/modules/doc/container/container.ts +0 -164
  103. package/src/modules/doc/content/prismjs.css +0 -184
  104. package/src/modules/doc/content/prismjs.html +0 -3
  105. package/src/modules/doc/content/prismjs.ts +0 -853
  106. package/src/modules/doc/prismcss/prismcss.css +0 -184
  107. package/src/modules/doc/search/search.html +0 -1
  108. package/src/modules/doc/search/search.ts +0 -6
@@ -0,0 +1,213 @@
1
+ import { LightningElement, api, track } from "lwc";
2
+ import cx from "classnames";
3
+ import { normalizeBoolean } from "dxUtils/normalizers";
4
+
5
+ interface ApiResponse {
6
+ success: boolean;
7
+ data?: string;
8
+ message?: string;
9
+ error?: string;
10
+ }
11
+
12
+ export default class EditFile extends LightningElement {
13
+ @api fileName: string = "";
14
+ @api apiEndpoint: string = "/api/edit-file";
15
+ @api title: string = "Edit File";
16
+
17
+ @api
18
+ get disabled() {
19
+ return this._disabled;
20
+ }
21
+
22
+ set disabled(value) {
23
+ this._disabled = normalizeBoolean(value);
24
+ }
25
+
26
+ @track isPopoverOpen: boolean = false;
27
+ @track isLoading: boolean = false;
28
+ @track isSaving: boolean = false;
29
+ @track fileContent: string = "";
30
+ @track originalContent: string = "";
31
+ @track errorMessage: string = "";
32
+
33
+ private _disabled: boolean = false;
34
+
35
+ // API Configuration
36
+ private static readonly FETCH_ENDPOINT = "/api/file/fetch";
37
+ private static readonly SAVE_ENDPOINT = "/api/file/save";
38
+
39
+ get popoverClass() {
40
+ return cx(
41
+ "edit-file-popover",
42
+ this.isPopoverOpen && "edit-file-popover_open"
43
+ );
44
+ }
45
+
46
+ get overlayClass() {
47
+ return cx(
48
+ "edit-file-overlay",
49
+ this.isPopoverOpen && "edit-file-overlay_open"
50
+ );
51
+ }
52
+
53
+ get saveButtonClass() {
54
+ return cx(
55
+ "edit-file-button",
56
+ "edit-file-button_primary",
57
+ (this.isSaving || this.isContentUnchanged) && "edit-file-button_disabled"
58
+ );
59
+ }
60
+
61
+ get isContentUnchanged() {
62
+ return this.fileContent === this.originalContent;
63
+ }
64
+
65
+ // Open the edit file popover
66
+ async handleEditClick() {
67
+ if (this.disabled) return;
68
+
69
+ this.isPopoverOpen = true;
70
+ this.errorMessage = "";
71
+ await this.fetchFileContent();
72
+ }
73
+
74
+ // Fetch file content from API
75
+ private async fetchFileContent() {
76
+ if (!this.fileName) {
77
+ this.errorMessage = "No file specified to edit";
78
+ return;
79
+ }
80
+
81
+ this.isLoading = true;
82
+
83
+ try {
84
+ const response = await fetch(EditFile.FETCH_ENDPOINT, {
85
+ method: "POST",
86
+ headers: {
87
+ "Content-Type": "application/json",
88
+ },
89
+ body: JSON.stringify({
90
+ fileName: this.fileName,
91
+ action: "fetch"
92
+ })
93
+ });
94
+
95
+ if (!response.ok) {
96
+ throw new Error(`Failed to fetch file: ${response.status}`);
97
+ }
98
+
99
+ const data: ApiResponse = await response.json();
100
+
101
+ if (data.success && data.data !== undefined) {
102
+ this.fileContent = data.data;
103
+ this.originalContent = data.data;
104
+ this.errorMessage = "";
105
+ } else {
106
+ this.errorMessage = data.error || data.message || "Failed to load file content";
107
+ }
108
+ } catch (error) {
109
+ console.error("Error fetching file content:", error);
110
+ this.errorMessage = error instanceof Error ? error.message : "Failed to connect to server";
111
+ } finally {
112
+ this.isLoading = false;
113
+ }
114
+ }
115
+
116
+ // Handle content change in textarea
117
+ handleContentChange(event: Event) {
118
+ const target = event.target as HTMLTextAreaElement;
119
+ this.fileContent = target.value;
120
+ }
121
+
122
+ // Handle cancel action
123
+ handleCancel() {
124
+ this.isPopoverOpen = false;
125
+ this.fileContent = "";
126
+ this.originalContent = "";
127
+ this.errorMessage = "";
128
+ this.isLoading = false;
129
+ this.isSaving = false;
130
+
131
+ // Dispatch cancel event
132
+ this.dispatchEvent(
133
+ new CustomEvent("editcancel", {
134
+ detail: { fileName: this.fileName }
135
+ })
136
+ );
137
+ }
138
+
139
+ // Handle save action
140
+ async handleSave() {
141
+ if (this.isSaving || this.isContentUnchanged || this.disabled) return;
142
+
143
+ this.isSaving = true;
144
+ this.errorMessage = "";
145
+
146
+ try {
147
+ const response = await fetch(EditFile.SAVE_ENDPOINT, {
148
+ method: "POST",
149
+ headers: {
150
+ "Content-Type": "application/json",
151
+ },
152
+ body: JSON.stringify({
153
+ fileName: this.fileName,
154
+ content: this.fileContent,
155
+ action: "save"
156
+ })
157
+ });
158
+
159
+ if (!response.ok) {
160
+ throw new Error(`Failed to save file: ${response.status}`);
161
+ }
162
+
163
+ const data: ApiResponse = await response.json();
164
+
165
+ if (data.success) {
166
+ this.originalContent = this.fileContent;
167
+ this.isPopoverOpen = false;
168
+
169
+ // Dispatch success event
170
+ this.dispatchEvent(
171
+ new CustomEvent("editsuccess", {
172
+ detail: {
173
+ fileName: this.fileName,
174
+ content: this.fileContent,
175
+ message: data.message || "File saved successfully"
176
+ }
177
+ })
178
+ );
179
+ } else {
180
+ this.errorMessage = data.error || data.message || "Failed to save file";
181
+ }
182
+ } catch (error) {
183
+ console.error("Error saving file:", error);
184
+ this.errorMessage = error instanceof Error ? error.message : "Failed to connect to server";
185
+ } finally {
186
+ this.isSaving = false;
187
+ }
188
+ }
189
+
190
+ // Handle overlay click to close popover
191
+ handleOverlayClick(event: Event) {
192
+ if (event.target === event.currentTarget) {
193
+ this.handleCancel();
194
+ }
195
+ }
196
+
197
+ // Handle escape key to close popover
198
+ handleKeyDown(event: KeyboardEvent) {
199
+ if (event.key === "Escape" && this.isPopoverOpen) {
200
+ this.handleCancel();
201
+ }
202
+ }
203
+
204
+ connectedCallback() {
205
+ // Add escape key listener
206
+ document.addEventListener("keydown", this.handleKeyDown.bind(this));
207
+ }
208
+
209
+ disconnectedCallback() {
210
+ // Remove escape key listener
211
+ document.removeEventListener("keydown", this.handleKeyDown.bind(this));
212
+ }
213
+ }
@@ -0,0 +1,132 @@
1
+ @import "dxHelpers/commonHeader";
2
+
3
+ dx-logo {
4
+ min-width: fit-content;
5
+ }
6
+
7
+ .dev-center-link {
8
+ display: inline-block;
9
+ padding: var(--dx-g-spacing-smd) var(--dx-g-spacing-lg) 0
10
+ var(--dx-g-global-header-padding-horizontal);
11
+ height: var(--dx-g-spacing-xl);
12
+ }
13
+
14
+ .dev-center-content {
15
+ display: flex;
16
+ align-items: center;
17
+ text-decoration: none;
18
+ color: inherit;
19
+ font-weight: var(--dx-g-font-bold);
20
+ }
21
+
22
+ dx-icon {
23
+ --dx-c-icon-size: var(--dx-g-icon-size-xs);
24
+ --dx-c-icon-color: var(--dx-g-blue-vibrant-20);
25
+ }
26
+
27
+ .dev-center-content > * + * {
28
+ margin-left: 8px; /* Adjust this value to your desired spacing */
29
+ }
30
+
31
+ .header_l2 {
32
+ justify-content: space-between;
33
+ height: var(--dx-g-doc-header-main-nav-height);
34
+ }
35
+
36
+ .has-brand .header_l2 {
37
+ height: var(--dx-g-spacing-3xl);
38
+ }
39
+
40
+ .nav_menu-button {
41
+ --dx-c-button-primary-color: var(--dx-g-blue-vibrant-20);
42
+ --dx-c-button-secondary-color-hover: var(
43
+ --dx-g-brand-default-button-color-background-inactive
44
+ );
45
+ }
46
+
47
+ .has-brand.has-scoped-nav-items {
48
+ border-bottom: 1px solid var(--dx-g-gray-90);
49
+ border-top: 1px solid var(--dx-g-gray-90);
50
+ }
51
+
52
+ .nav_menu-ctas {
53
+ margin-right: var(--dx-g-spacing-sm);
54
+ }
55
+
56
+ header:not(.has-brand) > .header_l1 {
57
+ background: white;
58
+ border-bottom: 1px solid var(--dx-g-gray-90);
59
+ }
60
+
61
+ header:not(.has-brand) > .header_l2 {
62
+ border-bottom: 1px solid var(--dx-g-gray-90);
63
+ border-top: 1px solid var(--dx-g-gray-90);
64
+ }
65
+
66
+ .header_l2_group.header_l2_group-right-ctas {
67
+ align-items: baseline;
68
+ }
69
+
70
+ .has-brand .header_l2_group-title {
71
+ padding: var(--dx-g-spacing-sm) var(--dx-g-spacing-xl)
72
+ calc(var(--dx-g-spacing-smd) - 1px) 0;
73
+ min-width: 320px;
74
+ }
75
+
76
+ .no-header-content {
77
+ border-top: 1px solid var(--dx-g-gray-90);
78
+ }
79
+
80
+ @media (max-width: 768px) {
81
+ .header_l2 {
82
+ padding: 0;
83
+ flex-wrap: wrap;
84
+ height: 100%;
85
+ }
86
+
87
+ .has-nav-items .header_l2 {
88
+ height: initial;
89
+ }
90
+
91
+ .header_l2_group {
92
+ width: 100%;
93
+ }
94
+
95
+ .header_l2_group-title {
96
+ margin-right: 0;
97
+ padding: var(--dx-g-spacing-sm) 0 2px
98
+ var(--dx-g-global-header-padding-horizontal);
99
+ min-height: var(--dx-g-doc-header-main-nav-height);
100
+ }
101
+
102
+ .header_l2_group-nav {
103
+ height: var(--dx-g-spacing-3xl);
104
+ padding: 0;
105
+ margin-top: calc(var(--dx-g-spacing-2xs) + 1px);
106
+ }
107
+
108
+ .header_l2_group-nav_overflow {
109
+ height: var(--dx-g-spacing-3xl);
110
+ margin-right: var(--dx-g-spacing-sm);
111
+ }
112
+
113
+ .subtitle {
114
+ font-weight: var(--dx-g-font-demi);
115
+ letter-spacing: -0.08px;
116
+ }
117
+
118
+ .has-brand .header_l2_group-title {
119
+ margin-right: 0;
120
+ padding: var(--dx-g-spacing-sm) 0 var(--dx-g-spacing-2xs)
121
+ var(--dx-g-global-header-padding-horizontal);
122
+ }
123
+
124
+ .has-scoped-nav-items > .header_l2 {
125
+ height: unset;
126
+ }
127
+
128
+ header:not(.has-brand) > .header_l2 {
129
+ padding-bottom: 0;
130
+ border: 0;
131
+ }
132
+ }
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <template lwc:if={shouldRender}>
3
+ <dx-brand-theme-provider brand={brand}>
4
+ <header class={className}>
5
+ <dx-banner
6
+ lwc:if={showBanner}
7
+ banner-markup={bannerMarkup}
8
+ ></dx-banner>
9
+ <!-- To-Do: Move the devCenter as a new component and use it here, as devCenter is also used in Sidebar now -->
10
+ <div lwc:if={devCenter} class="dev-center-link">
11
+ <a href={devCenter.link} class="dev-center-content">
12
+ <dx-icon symbol="back"></dx-icon>
13
+ <dx-icon
14
+ class="brand-icon"
15
+ lwc:if={devCenter.icon}
16
+ sprite="salesforcebrand"
17
+ symbol={brand}
18
+ size="large"
19
+ ></dx-icon>
20
+ <span class="subtitle dx-text-body-4">
21
+ {devCenter.title}
22
+ </span>
23
+ </a>
24
+ </div>
25
+ <div class="header_l2">
26
+ <div class="header_l2_group header_l2_group-title">
27
+ <a href={headerHref} class="home-link">
28
+ <span class="subtitle dx-text-display-7">
29
+ {subtitle}
30
+ </span>
31
+ </a>
32
+ </div>
33
+ <div
34
+ lwc:if={showScopedNavItems}
35
+ class="header_l2_group header_l2_group-nav"
36
+ >
37
+ <div
38
+ class="header_l2_group-nav_overflow"
39
+ onscroll={onNavScroll}
40
+ >
41
+ <dx-header-nav
42
+ aria-label="Scoped Navigation Bar"
43
+ nav-items={scopedNavItems}
44
+ pathname={pathname}
45
+ ></dx-header-nav>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ </header>
50
+ </dx-brand-theme-provider>
51
+ </template>
52
+ <template lwc:if={shouldHideHeader}>
53
+ <div class="no-header-content"></div>
54
+ </template>
55
+ </template>
@@ -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>