@salesforcedevs/docs-components 1.28.5-redoc-alpha → 1.28.5-redoc-alpha1

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.28.5-redoc-alpha",
3
+ "version": "1.28.5-redoc-alpha1",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -38,6 +38,7 @@ type NavigationItem = {
38
38
  isExpanded: boolean;
39
39
  children: ParsedMarkdownTopic[];
40
40
  isChildrenLoading: boolean;
41
+ renderWith?: string;
41
42
  };
42
43
 
43
44
  export default class AmfReference extends LightningElement {
@@ -147,6 +148,19 @@ export default class AmfReference extends LightningElement {
147
148
 
148
149
  this._amfConfigList = this._referenceSetConfig.refList || [];
149
150
 
151
+ // If the framework didn't tag the reference, infer redoc rendering
152
+ // from the config shape: spec-based references with no AMF URL are
153
+ // shipped as raw spec sources for Redoc to render directly.
154
+ this._amfConfigList.forEach((amfConfig) => {
155
+ if (
156
+ !amfConfig.renderWith &&
157
+ amfConfig.referenceType !== REFERENCE_TYPES.markdown &&
158
+ !amfConfig.amf
159
+ ) {
160
+ amfConfig.renderWith = RENDER_WITH.redoc;
161
+ }
162
+ });
163
+
150
164
  this._amfConfigList.forEach((amfConfig) => {
151
165
  this._amfConfigMap.set(amfConfig.id, amfConfig);
152
166
  });
@@ -252,6 +266,7 @@ export default class AmfReference extends LightningElement {
252
266
 
253
267
  _boundOnApiNavigationChanged;
254
268
  _boundUpdateSelectedItemFromUrlQuery;
269
+ _boundOnPageShow;
255
270
 
256
271
  constructor() {
257
272
  super();
@@ -260,6 +275,7 @@ export default class AmfReference extends LightningElement {
260
275
  this.onApiNavigationChanged.bind(this);
261
276
  this._boundUpdateSelectedItemFromUrlQuery =
262
277
  this.updateSelectedItemFromUrlQuery.bind(this);
278
+ this._boundOnPageShow = this.onPageShow.bind(this);
263
279
  }
264
280
 
265
281
  connectedCallback(): void {
@@ -271,6 +287,7 @@ export default class AmfReference extends LightningElement {
271
287
  "popstate",
272
288
  this._boundUpdateSelectedItemFromUrlQuery
273
289
  );
290
+ window.addEventListener("pageshow", this._boundOnPageShow);
274
291
  }
275
292
 
276
293
  disconnectedCallback(): void {
@@ -282,6 +299,22 @@ export default class AmfReference extends LightningElement {
282
299
  "popstate",
283
300
  this._boundUpdateSelectedItemFromUrlQuery
284
301
  );
302
+ window.removeEventListener("pageshow", this._boundOnPageShow);
303
+ }
304
+
305
+ /**
306
+ * On bfcache restore, reset the sidebar selection so the tree re-syncs
307
+ * its highlighted tile with the current URL.
308
+ */
309
+ protected onPageShow(event: PageTransitionEvent): void {
310
+ if (!event.persisted) {
311
+ return;
312
+ }
313
+ const currentPath = window.location.pathname;
314
+ this.selectedSidebarValue = "";
315
+ Promise.resolve().then(() => {
316
+ this.selectedSidebarValue = currentPath;
317
+ });
285
318
  }
286
319
 
287
320
  renderedCallback(): void {
@@ -535,7 +568,8 @@ export default class AmfReference extends LightningElement {
535
568
  amfConfig.isSelected ||
536
569
  this.isExpandChildrenEnabled(amfConfig.id),
537
570
  children: navItemChildren,
538
- isChildrenLoading
571
+ isChildrenLoading,
572
+ renderWith: amfConfig.renderWith
539
573
  };
540
574
  this.parentReferenceUrls.push(amfConfig.href);
541
575
  }
@@ -5,27 +5,3 @@
5
5
  var(--dx-g-spacing-xl)
6
6
  );
7
7
  }
8
-
9
- .redoc-project-header {
10
- display: flex;
11
- flex-direction: column;
12
- gap: var(--dx-g-spacing-2xs);
13
- padding: var(--dx-g-spacing-s) var(--dx-g-spacing-m);
14
- }
15
-
16
- .redoc-project-back {
17
- display: inline-flex;
18
- align-items: center;
19
- gap: var(--dx-g-spacing-xs);
20
- color: var(--dx-g-blue-vibrant-50);
21
- text-decoration: none;
22
- width: fit-content;
23
- }
24
-
25
- .redoc-project-back:hover .redoc-project-title {
26
- text-decoration: underline;
27
- }
28
-
29
- .redoc-spec-title {
30
- margin: 0;
31
- }
@@ -8,22 +8,6 @@
8
8
  ></dx-error>
9
9
  </template>
10
10
  <template lwc:else>
11
- <div lwc:if={showRedocHeader} class="redoc-project-header">
12
- <a
13
- lwc:if={projectTitle}
14
- class="redoc-project-back"
15
- href="#"
16
- onclick={onBackClick}
17
- >
18
- <dx-icon sprite="utility" symbol="back" size="small"></dx-icon>
19
- <span class="redoc-project-title dx-text-body-4">
20
- {projectTitle}
21
- </span>
22
- </a>
23
- <h2 lwc:if={specTitle} class="redoc-spec-title dx-text-display-6">
24
- {specTitle}
25
- </h2>
26
- </div>
27
11
  <slot></slot>
28
12
  </template>
29
13
  </template>
@@ -2,6 +2,7 @@
2
2
  import { createElement, LightningElement, api } from "lwc";
3
3
  import DocPhase from "doc/phase";
4
4
  import DxFooter from "dx/footer";
5
+ import DxIcon from "dx/icon";
5
6
  import SprigSurvey from "doc/sprigSurvey";
6
7
  import { throttle } from "throttle-debounce";
7
8
  import { pollUntil } from "dxUtils/async";
@@ -17,6 +18,7 @@ declare const Sprig: (eventType: string, eventName: string) => void;
17
18
  type ReferenceItem = {
18
19
  source: string;
19
20
  href: string;
21
+ title?: string;
20
22
  isSelected?: boolean;
21
23
  docPhase?: string | null;
22
24
  };
@@ -77,11 +79,28 @@ export default class RedocReference extends LightningElement {
77
79
  */
78
80
  @api projectTitle: string | null = null;
79
81
 
82
+ private _specTitle: string | null = null;
83
+
80
84
  /** Title of the currently selected spec, shown beneath the project title. */
81
- @api specTitle: string | null = null;
85
+ @api
86
+ get specTitle(): string | null {
87
+ if (this._specTitle) {
88
+ return this._specTitle;
89
+ }
90
+ return this.getSelectedReference()?.title ?? null;
91
+ }
82
92
 
93
+ set specTitle(value: string | null) {
94
+ this._specTitle = value;
95
+ }
96
+
97
+ /**
98
+ * Whether to show the project header (only for multi-spec reference sets).
99
+ */
83
100
  get showRedocHeader(): boolean {
84
- return !!(this.projectTitle || this.specTitle);
101
+ const refCount = this._referenceConfig?.refList?.length ?? 0;
102
+ const isMultiSpecSet = refCount > 1;
103
+ return isMultiSpecSet && !!(this.projectTitle || this.specTitle);
85
104
  }
86
105
 
87
106
  /**
@@ -332,6 +351,9 @@ export default class RedocReference extends LightningElement {
332
351
 
333
352
  this.appendFooterItems(apiContentDiv);
334
353
 
354
+ // Inject the multi-spec project header into Redoc's left menu only.
355
+ this.insertProjectHeaderInMenu(redocContainer);
356
+
335
357
  // Wait for footer to be rendered before updating styles
336
358
  requestAnimationFrame(() => {
337
359
  this.updateRedocThirdColumnStyle(redocContainer);
@@ -344,6 +366,80 @@ export default class RedocReference extends LightningElement {
344
366
  }
345
367
  }
346
368
 
369
+ /**
370
+ * Inserts the project header into Redoc for multi-spec reference sets.
371
+ */
372
+ private insertProjectHeaderInMenu(redocContainer: HTMLElement): void {
373
+ if (!this.showRedocHeader) {
374
+ return;
375
+ }
376
+ const menuContent =
377
+ redocContainer.querySelector<HTMLElement>(".menu-content");
378
+ if (
379
+ menuContent &&
380
+ !menuContent.querySelector(":scope > .redoc-project-header")
381
+ ) {
382
+ menuContent.insertBefore(
383
+ this.buildProjectHeaderDom(),
384
+ menuContent.firstChild
385
+ );
386
+ }
387
+
388
+ const apiContent =
389
+ redocContainer.querySelector<HTMLElement>(".api-content");
390
+ if (
391
+ apiContent &&
392
+ !apiContent.querySelector(":scope > .redoc-project-header")
393
+ ) {
394
+ apiContent.insertBefore(
395
+ this.buildProjectHeaderDom(),
396
+ apiContent.firstChild
397
+ );
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Builds a fresh project-title/spec-title header DOM node.
403
+ */
404
+ private buildProjectHeaderDom(): HTMLElement {
405
+ const wrapper = document.createElement("div");
406
+ wrapper.className = "redoc-project-header";
407
+
408
+ if (this.projectTitle) {
409
+ const backLink = document.createElement("a");
410
+ backLink.className = "redoc-project-back";
411
+ backLink.href = "#";
412
+ backLink.addEventListener("click", (event) => {
413
+ event.preventDefault();
414
+ window.history.back();
415
+ });
416
+ // 16x16 utility/back icon. dx-icon size="medium" maps to
417
+ // --dx-g-icon-size-md (16px).
418
+ const iconEl = createElement("dx-icon", { is: DxIcon });
419
+ Object.assign(iconEl, {
420
+ sprite: "utility",
421
+ symbol: "back",
422
+ size: "medium"
423
+ });
424
+ iconEl.classList.add("redoc-project-back-arrow");
425
+ const label = document.createElement("span");
426
+ label.className = "redoc-project-title";
427
+ label.textContent = this.projectTitle;
428
+ backLink.appendChild(iconEl);
429
+ backLink.appendChild(label);
430
+ wrapper.appendChild(backLink);
431
+ }
432
+
433
+ if (this.specTitle) {
434
+ const specEl = document.createElement("h2");
435
+ specEl.className = "redoc-spec-title";
436
+ specEl.textContent = this.specTitle;
437
+ wrapper.appendChild(specEl);
438
+ }
439
+
440
+ return wrapper;
441
+ }
442
+
347
443
  // Waits for Redoc's API content element to be rendered
348
444
  private async waitForApiContent(
349
445
  container: HTMLElement