@salesforcedevs/docs-components 1.20.13-redocly1 → 1.20.13-redocly3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "1.20.13-redocly1",
3
+ "version": "1.20.13-redocly3",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -1,8 +1,21 @@
1
1
  <template>
2
- <slot></slot>
3
- <dx-error-fallback
4
- if:true={showError}
5
- title={title}
6
- description={description}
7
- ></dx-error-fallback>
2
+ <template lwc:if={showServerError}>
3
+ <dx-error
4
+ header="We lost communication with the space station."
5
+ subtitle="We encountered a server-related issue. (Don't worry, we're on it.) Refresh your browser or try again later."
6
+ image=""
7
+ code="500"
8
+ ></dx-error>
9
+ </template>
10
+ <template lwc:elseif={showError}>
11
+ <dx-error
12
+ header="Head back to the space station"
13
+ subtitle="Looks like this page vaporized"
14
+ code="404"
15
+ image="https://a.sfdcstatic.com/developer-website/images/404.svg"
16
+ ></dx-error>
17
+ </template>
18
+ <template lwc:else>
19
+ <slot></slot>
20
+ </template>
8
21
  </template>
@@ -3,6 +3,7 @@ import { createElement, LightningElement, api } from "lwc";
3
3
  import DocPhase from "doc/phase";
4
4
  import DxFooter from "dx/footer";
5
5
  import SprigSurvey from "doc/sprigSurvey";
6
+ import { throttle } from "throttle-debounce";
6
7
 
7
8
  declare global {
8
9
  interface Window {
@@ -22,20 +23,20 @@ type ReferenceConfig = {
22
23
  };
23
24
 
24
25
  declare const Sprig: (eventType: string, eventNme: string) => void;
26
+ const FOOTER_MARGIN_TOP = 142;
27
+ const DEFAULT_TIMEOUT = 200;
28
+ const REDOC_TIMEOUT = 10000;
29
+ const REDOC_CHECK_TIMEOUT = 100;
25
30
 
26
31
  export default class RedocReference extends LightningElement {
27
32
  private _referenceConfig: ReferenceConfig = { refList: [] };
28
33
  private _parentDocPhaseInfo: string | null = null;
29
34
 
30
35
  private layoutTimeoutId: number | null = null;
31
- private isScrolling: boolean = false;
32
- private previousTopValue = "";
33
36
  private redocInitialized = false;
34
37
 
35
38
  showError = false;
36
- title: string = "API Documentation Unavailable";
37
- description: string =
38
- "This API reference is currently unavailable. Please try again later.";
39
+ showServerError = false;
39
40
 
40
41
  @api
41
42
  get referenceConfig(): ReferenceConfig {
@@ -48,9 +49,7 @@ export default class RedocReference extends LightningElement {
48
49
  typeof value === "string" ? JSON.parse(value) : value;
49
50
  this._referenceConfig = refConfig;
50
51
  } catch (error) {
51
- this.title = "Failed to parse reference configuration data";
52
- this.description =
53
- "An error occurred while reading/parsing the reference configuration. Please check the config file for syntax errors or invalid references and try again.";
52
+ this.showServerError = true;
54
53
  console.error(
55
54
  "Failed to parse reference configuration data",
56
55
  error
@@ -69,12 +68,12 @@ export default class RedocReference extends LightningElement {
69
68
  }
70
69
 
71
70
  connectedCallback(): void {
72
- window.addEventListener("scroll", this.handleScrollWithThrottle);
73
- window.addEventListener("resize", this.handleScrollWithThrottle);
71
+ window.addEventListener("scroll", this.handleScroll);
72
+ window.addEventListener("resize", this.handleScroll);
74
73
  }
75
74
 
76
75
  renderedCallback(): void {
77
- if (!this.redocInitialized && window.Redoc) {
76
+ if (!this.redocInitialized) {
78
77
  this.initializeRedoc();
79
78
  }
80
79
  }
@@ -85,8 +84,8 @@ export default class RedocReference extends LightningElement {
85
84
  this.layoutTimeoutId = null;
86
85
  }
87
86
 
88
- window.removeEventListener("scroll", this.handleScrollWithThrottle);
89
- window.removeEventListener("resize", this.handleScrollWithThrottle);
87
+ window.removeEventListener("scroll", this.handleScroll);
88
+ window.removeEventListener("resize", this.handleScroll);
90
89
  }
91
90
 
92
91
  @api
@@ -94,23 +93,17 @@ export default class RedocReference extends LightningElement {
94
93
  this._parentDocPhaseInfo = docPhaseInfo;
95
94
  }
96
95
 
97
- private handleScrollWithThrottle = () => {
98
- if (!this.isScrolling) {
99
- this.isScrolling = true;
100
-
101
- setTimeout(() => {
102
- this.adjustPosition();
103
- }, 200);
104
-
105
- this.isScrolling = false;
106
- }
107
- };
108
-
109
96
  private adjustPosition = () => {
110
97
  const redocContainer = this.getRedocContainer();
111
98
  const sidebarMenuElement = redocContainer?.querySelector(
112
99
  ".redoc-wrap .menu-content"
113
100
  ) as HTMLElement;
101
+ const footer = redocContainer?.querySelector(
102
+ ".redoc-wrap .api-content dx-footer"
103
+ ) as HTMLElement;
104
+ const rightSidebar = redocContainer?.querySelector(
105
+ ".redoc-wrap > div:last-child"
106
+ ) as HTMLElement;
114
107
 
115
108
  requestAnimationFrame(() => {
116
109
  const globalNavElement = document.querySelector("hgf-c360nav");
@@ -119,6 +112,16 @@ export default class RedocReference extends LightningElement {
119
112
  const docHeaderElement =
120
113
  document.querySelector(".sticky-doc-header");
121
114
 
115
+ if (rightSidebar) {
116
+ rightSidebar.style.setProperty(
117
+ "bottom",
118
+ `${
119
+ (footer.getBoundingClientRect().height || 0) +
120
+ FOOTER_MARGIN_TOP
121
+ }px`
122
+ );
123
+ }
124
+
122
125
  if (sidebarMenuElement) {
123
126
  const globalNavHeight =
124
127
  globalNavElement?.getBoundingClientRect().height || 0;
@@ -131,17 +134,19 @@ export default class RedocReference extends LightningElement {
131
134
  globalNavHeight + contextNavHeight + docHeaderHeight
132
135
  }px`;
133
136
 
134
- if (calculatedTopValue !== this.previousTopValue) {
135
- sidebarMenuElement.style.setProperty(
136
- "--doc-c-redoc-sidebar-top",
137
- calculatedTopValue
138
- );
139
- this.previousTopValue = calculatedTopValue;
140
- }
137
+ sidebarMenuElement.style.setProperty(
138
+ "--doc-c-redoc-sidebar-top",
139
+ calculatedTopValue
140
+ );
141
141
  }
142
142
  });
143
143
  };
144
144
 
145
+ private handleScroll = throttle(
146
+ DEFAULT_TIMEOUT,
147
+ () => !this.showServerError && !this.showError && this.adjustPosition()
148
+ );
149
+
145
150
  private getDocPhaseInfo(): string | null {
146
151
  if (this._parentDocPhaseInfo) {
147
152
  return this._parentDocPhaseInfo;
@@ -177,8 +182,11 @@ export default class RedocReference extends LightningElement {
177
182
  }
178
183
  }
179
184
 
180
- private initializeRedoc(): void {
185
+ private async initializeRedoc(): Promise<void> {
181
186
  try {
187
+ this.redocInitialized = true;
188
+
189
+ await this.waitForRedoc();
182
190
  const selectedRef = this.getSelectedReference();
183
191
  if (selectedRef) {
184
192
  this.updateUrlWithReference(selectedRef);
@@ -186,68 +194,107 @@ export default class RedocReference extends LightningElement {
186
194
  const specUrl = selectedRef.source;
187
195
  const redocContainer = this.getRedocContainer();
188
196
  if (specUrl && redocContainer) {
189
- this.redocInitialized = true;
190
- window.Redoc.init(
191
- specUrl,
192
- {
193
- expandResponses: "200,400"
194
- },
195
- redocContainer,
196
- () => {
197
- this.insertCustomLayoutElements();
198
- }
199
- );
197
+ try {
198
+ window.Redoc.init(
199
+ specUrl,
200
+ {
201
+ expandResponses: "200,400"
202
+ },
203
+ redocContainer,
204
+ () => {
205
+ this.insertCustomLayoutElements();
206
+ }
207
+ );
208
+ } catch (error) {
209
+ this.showServerError = true;
210
+ console.error("Failed to load Redoc:", error);
211
+ }
200
212
  } else {
201
213
  this.showError = true;
202
- console.error(
203
- "Failed to initialize Redoc, required params missing."
204
- );
205
214
  }
206
215
  }
207
216
  } catch (error) {
208
- this.title = "Failed to load API specification";
209
- this.description =
210
- "An error occurred while trying to initialize Redoc. This may be due to a missing or invalid source in the configuration file, or a network connectivity issue. Please verify the source path and your internet connection and try again.";
211
- console.error("Failed to load API specification", error);
212
- this.showError = true;
217
+ this.showServerError = true;
218
+ console.error("Failed to initialize Redoc:", error);
213
219
  }
214
220
  }
215
221
 
216
- private insertCustomLayoutElements(): void {
217
- const redocContainer = this.getRedocContainer();
218
- const apiContentDiv = redocContainer?.querySelector(".api-content");
219
- if (apiContentDiv) {
220
- (apiContentDiv as HTMLElement).setAttribute("lwc:dom", "manual");
222
+ private waitForRedoc(timeout = REDOC_TIMEOUT): Promise<void> {
223
+ return new Promise((resolve, reject) => {
224
+ let resolved = false;
225
+ const startTime = Date.now();
226
+
227
+ const check = () => {
228
+ if (window.Redoc && !resolved) {
229
+ resolved = true;
230
+ resolve();
231
+ return;
232
+ }
233
+
234
+ if (Date.now() - startTime > timeout) {
235
+ reject(new Error("Redoc load timeout"));
236
+ return;
237
+ }
238
+
239
+ setTimeout(check, REDOC_CHECK_TIMEOUT);
240
+ };
241
+
242
+ check();
243
+ });
244
+ }
245
+
246
+ private async insertCustomLayoutElements(): Promise<void> {
247
+ try {
248
+ const redocContainer = this.getRedocContainer();
249
+
250
+ if (redocContainer) {
251
+ const apiContentDiv = await this.waitForApiContent(
252
+ redocContainer
253
+ );
254
+ apiContentDiv.setAttribute("lwc:dom", "manual");
221
255
 
222
- try {
223
256
  const docPhaseInfo = this.getDocPhaseInfo();
224
257
  if (docPhaseInfo) {
225
- this.insertDocPhase(
226
- apiContentDiv as HTMLElement,
227
- docPhaseInfo
228
- );
258
+ this.insertDocPhase(apiContentDiv, docPhaseInfo);
229
259
  }
230
260
 
231
261
  if (typeof Sprig !== "undefined") {
232
- this.insertSprigSurvey(apiContentDiv as HTMLElement);
262
+ this.insertSprigSurvey(apiContentDiv);
233
263
  }
234
264
 
235
- this.insertFooter(apiContentDiv as HTMLElement);
236
- } catch (error) {
237
- this.showError = true;
238
- console.error(
239
- "Error showing banner and footer elements",
240
- error
241
- );
265
+ this.insertFooter(apiContentDiv);
242
266
  }
243
- } else {
244
- this.layoutTimeoutId = window.setTimeout(
245
- () => this.insertCustomLayoutElements(),
246
- 100
247
- );
267
+ } catch (error) {
268
+ this.showServerError = true;
269
+ console.error("Failed to insert layout elements:", error);
248
270
  }
249
271
  }
250
272
 
273
+ private waitForApiContent(container: HTMLElement): Promise<HTMLElement> {
274
+ return new Promise((resolve, reject) => {
275
+ const start = Date.now();
276
+
277
+ const check = () => {
278
+ const div =
279
+ container.querySelector<HTMLElement>(".api-content");
280
+
281
+ if (div) {
282
+ resolve(div);
283
+ return;
284
+ }
285
+
286
+ if (Date.now() - start > DEFAULT_TIMEOUT) {
287
+ reject(new Error("API content load timeout"));
288
+ return;
289
+ }
290
+
291
+ setTimeout(check, DEFAULT_TIMEOUT);
292
+ };
293
+
294
+ check();
295
+ });
296
+ }
297
+
251
298
  private insertDocPhase(container: HTMLElement, docPhaseInfo: string): void {
252
299
  const docPhaseElement = createElement("doc-phase", { is: DocPhase });
253
300
  Object.assign(docPhaseElement, { docPhaseInfo });
@@ -270,11 +317,9 @@ export default class RedocReference extends LightningElement {
270
317
  is: SprigSurvey
271
318
  });
272
319
 
273
- // targeting the last element of middle section of page
274
- const targetElement =
275
- container.lastElementChild?.firstElementChild?.firstElementChild;
276
- if (targetElement) {
277
- targetElement.appendChild(feedbackElement);
278
- }
320
+ const wrapper = document.createElement("div");
321
+ wrapper.className = "sprig-survey-wrapper";
322
+ wrapper.appendChild(feedbackElement);
323
+ container.appendChild(wrapper);
279
324
  }
280
325
  }