@salesforcedevs/docs-components 0.7.59-sppage-alpha2 → 0.7.76-alpha

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 (39) hide show
  1. package/lwc.config.json +3 -0
  2. package/package.json +9 -4
  3. package/src/modules/doc/amfReference/amfReference.css +0 -12
  4. package/src/modules/doc/amfReference/amfReference.html +1 -6
  5. package/src/modules/doc/amfReference/amfReference.ts +10 -37
  6. package/src/modules/doc/amfTopic/amfTopic.ts +24 -0
  7. package/src/modules/doc/breadcrumbs/breadcrumbs.html +0 -1
  8. package/src/modules/doc/breadcrumbs/breadcrumbs.ts +14 -23
  9. package/src/modules/doc/componentPlayground/componentPlayground.css +30 -0
  10. package/src/modules/doc/componentPlayground/componentPlayground.html +20 -0
  11. package/src/modules/doc/componentPlayground/componentPlayground.ts +97 -0
  12. package/src/modules/doc/content/content.html +1 -0
  13. package/src/modules/doc/content/content.ts +7 -33
  14. package/src/modules/doc/contentCallout/contentCallout.css +1 -0
  15. package/src/modules/doc/contentLayout/contentLayout.css +27 -123
  16. package/src/modules/doc/contentLayout/contentLayout.html +42 -36
  17. package/src/modules/doc/contentLayout/contentLayout.ts +152 -204
  18. package/src/modules/doc/contentMedia/contentMedia.css +1 -1
  19. package/src/modules/doc/header/header.html +8 -3
  20. package/src/modules/doc/header/header.ts +49 -10
  21. package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +9 -0
  22. package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +64 -0
  23. package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +269 -0
  24. package/src/modules/doc/phase/phase.css +0 -7
  25. package/src/modules/doc/redocReference/redocReference.css +7 -0
  26. package/src/modules/doc/redocReference/redocReference.html +13 -0
  27. package/src/modules/doc/redocReference/redocReference.ts +427 -0
  28. package/src/modules/doc/specificationContent/specificationContent.css +33 -0
  29. package/src/modules/doc/specificationContent/specificationContent.html +94 -16
  30. package/src/modules/doc/specificationContent/specificationContent.ts +131 -21
  31. package/src/modules/doc/versionPicker/versionPicker.html +2 -0
  32. package/src/modules/doc/xmlContent/xmlContent.css +0 -10
  33. package/src/modules/doc/xmlContent/xmlContent.html +11 -8
  34. package/src/modules/doc/xmlContent/xmlContent.ts +76 -57
  35. package/src/modules/docHelpers/amfStyle/amfStyle.css +0 -2
  36. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +160 -0
  37. package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
  38. package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
  39. package/src/modules/docUtils/utils/utils.ts +1 -1
@@ -0,0 +1,427 @@
1
+ /* eslint-disable @lwc/lwc/no-document-query */
2
+ import { createElement, LightningElement, api } from "lwc";
3
+ import DocPhase from "doc/phase";
4
+ import DxFooter from "dx/footer";
5
+ import SprigSurvey from "doc/sprigSurvey";
6
+ import { throttle } from "throttle-debounce";
7
+ import { pollUntil } from "dxUtils/async";
8
+
9
+ declare global {
10
+ interface Window {
11
+ Redoc: any;
12
+ }
13
+ }
14
+
15
+ declare const Sprig: (eventType: string, eventName: string) => void;
16
+
17
+ type ReferenceItem = {
18
+ source: string;
19
+ href: string;
20
+ isSelected?: boolean;
21
+ docPhase?: string | null;
22
+ };
23
+
24
+ type ReferenceConfig = {
25
+ refList: ReferenceItem[];
26
+ };
27
+
28
+ const SCROLL_THROTTLE_DELAY = 50;
29
+ const ELEMENT_TIMEOUT = 10000;
30
+ const ELEMENT_CHECK_INTERVAL = 100;
31
+
32
+ export default class RedocReference extends LightningElement {
33
+ private _referenceConfig: ReferenceConfig = { refList: [] };
34
+ private _parentDocPhaseInfo: string | null = null;
35
+ private redocInitialized = false;
36
+
37
+ private docHeaderElement: Element | null = null;
38
+ private docPhaseWrapperElement: Element | null = null;
39
+ private lastSidebarTop = 0;
40
+
41
+ showError = false;
42
+
43
+ @api
44
+ get referenceConfig(): ReferenceConfig {
45
+ return this._referenceConfig;
46
+ }
47
+
48
+ set referenceConfig(value: string | ReferenceConfig) {
49
+ try {
50
+ const refConfig =
51
+ typeof value === "string" ? JSON.parse(value) : value;
52
+ this._referenceConfig = refConfig;
53
+ } catch (error) {
54
+ this._referenceConfig = { refList: [] };
55
+ this.showErrorUI(
56
+ "Failed to parse reference configuration data",
57
+ error
58
+ );
59
+ }
60
+ }
61
+
62
+ @api
63
+ get docPhaseInfo(): string | null {
64
+ return this._parentDocPhaseInfo;
65
+ }
66
+
67
+ set docPhaseInfo(value: string) {
68
+ this._parentDocPhaseInfo = value;
69
+ }
70
+
71
+ connectedCallback(): void {
72
+ window.addEventListener("scroll", this.handleScrollAndResize);
73
+ window.addEventListener("resize", this.handleScrollAndResize);
74
+ }
75
+
76
+ renderedCallback(): void {
77
+ if (!this.redocInitialized) {
78
+ this.redocInitialized = true;
79
+ this.initializeRedoc();
80
+ }
81
+ }
82
+
83
+ disconnectedCallback(): void {
84
+ window.removeEventListener("scroll", this.handleScrollAndResize);
85
+ window.removeEventListener("resize", this.handleScrollAndResize);
86
+
87
+ this.handleScrollAndResize?.cancel?.();
88
+
89
+ // Clean up cached DOM element references to prevent memory leaks
90
+ this.docHeaderElement = null;
91
+ this.docPhaseWrapperElement = null;
92
+ }
93
+
94
+ // Displays error UI and logs error message for debugging
95
+ private showErrorUI(message: string, error?: any): void {
96
+ this.showError = true;
97
+ console.error(message, error);
98
+ }
99
+
100
+ private getRedocContainer(): HTMLElement | null {
101
+ return document.querySelector(".redoc-container");
102
+ }
103
+
104
+ private getSelectedReference(): ReferenceItem | null {
105
+ return (
106
+ this._referenceConfig?.refList?.find((ref) => ref.isSelected) ||
107
+ this._referenceConfig?.refList?.[0]
108
+ );
109
+ }
110
+
111
+ private getDocPhaseInfo(): string | null {
112
+ if (this._parentDocPhaseInfo) {
113
+ return this._parentDocPhaseInfo;
114
+ }
115
+ const selectedRef = this.getSelectedReference();
116
+ return selectedRef?.docPhase
117
+ ? JSON.stringify(selectedRef.docPhase)
118
+ : null;
119
+ }
120
+
121
+ // Extracts numeric value from CSS custom properties
122
+ private getGlobalCSSVariableValue(variableName: string): number {
123
+ const value = getComputedStyle(
124
+ document.documentElement
125
+ ).getPropertyValue(variableName);
126
+ return parseInt(value, 10) || 0;
127
+ }
128
+
129
+ /*
130
+ ** Since we could not use --dx-g-global-header-height as getPropertyValue returns a calc expression,
131
+ ** we are using the respective CSS variables to calculate the height.
132
+ */
133
+ private getGlobalHeaderHeight(): number {
134
+ const rowHeight = this.getGlobalCSSVariableValue(
135
+ "--dx-g-global-header-nav-row-height"
136
+ );
137
+ const rowCount = this.getGlobalCSSVariableValue(
138
+ "--dx-g-global-header-nav-row-count"
139
+ );
140
+ return rowHeight * rowCount;
141
+ }
142
+
143
+ // Gets doc header height with element caching for performance
144
+ private getDocHeaderHeight(): number {
145
+ if (!this.docHeaderElement) {
146
+ this.docHeaderElement =
147
+ document.querySelector(".sticky-doc-header");
148
+ }
149
+ return this.docHeaderElement?.getBoundingClientRect()?.height || 0;
150
+ }
151
+
152
+ // Gets doc phase wrapper height with element caching for performance
153
+ private getDocPhaseWrapperHeight(): number {
154
+ if (!this.docPhaseWrapperElement) {
155
+ this.docPhaseWrapperElement =
156
+ document.querySelector(".doc-phase-wrapper");
157
+ }
158
+ return (
159
+ this.docPhaseWrapperElement?.getBoundingClientRect()?.height || 0
160
+ );
161
+ }
162
+
163
+ calculateHeaderOffset = () => {
164
+ const globalHeaderHeight = this.getGlobalHeaderHeight();
165
+ const docHeaderHeight = this.getDocHeaderHeight();
166
+ return globalHeaderHeight + docHeaderHeight;
167
+ };
168
+
169
+ // Dynamic scroll offset calculation that Redoc will call
170
+ calculateScrollYOffset = () => {
171
+ const headerOffset = this.calculateHeaderOffset();
172
+ const phaseHeight = this.getDocPhaseWrapperHeight();
173
+ return headerOffset + phaseHeight;
174
+ };
175
+
176
+ // Updates sidebar positioning based on current header heights
177
+ private updateSidebarPosition = () => {
178
+ requestAnimationFrame(() => {
179
+ const redocContainer = this.getRedocContainer();
180
+ if (!redocContainer) {
181
+ return;
182
+ }
183
+
184
+ const currentSidebarTop = this.calculateHeaderOffset();
185
+ if (currentSidebarTop === this.lastSidebarTop) {
186
+ return;
187
+ }
188
+
189
+ const sidebarTopValue = `${currentSidebarTop}px`;
190
+ this.template.host.style.setProperty(
191
+ "--doc-c-redoc-sidebar-top",
192
+ sidebarTopValue
193
+ );
194
+ this.lastSidebarTop = currentSidebarTop;
195
+ });
196
+ };
197
+
198
+ // Updates browser URL while preserving query params and hash
199
+ private updateUrlWithReference(selectedRef: ReferenceItem): void {
200
+ if (selectedRef?.href) {
201
+ const parentReferencePath = selectedRef.href;
202
+ const currentUrl = window.location;
203
+ const existingParams = currentUrl.search + currentUrl.hash;
204
+
205
+ window.history.pushState(
206
+ {},
207
+ "",
208
+ `${parentReferencePath}${existingParams}`
209
+ );
210
+ }
211
+ }
212
+
213
+ private handleScrollAndResize = throttle(
214
+ SCROLL_THROTTLE_DELAY,
215
+ () => !this.showError && this.updateSidebarPosition()
216
+ );
217
+
218
+ // Initializes Redoc library with selected reference configuration
219
+ private async initializeRedoc(): Promise<void> {
220
+ try {
221
+ await this.waitForRedoc();
222
+
223
+ const redocContainer = this.getRedocContainer();
224
+ if (!redocContainer) {
225
+ this.showErrorUI("Redoc container is not found.");
226
+ return;
227
+ }
228
+
229
+ const selectedRef = this.getSelectedReference();
230
+ if (selectedRef) {
231
+ this.updateUrlWithReference(selectedRef);
232
+
233
+ const specUrl = selectedRef.source;
234
+ if (!specUrl) {
235
+ this.showErrorUI("Spec URL not found.");
236
+ return;
237
+ }
238
+
239
+ window.Redoc.init(
240
+ specUrl,
241
+ {
242
+ // Auto-expand HTTP 200 and 400 response sections
243
+ expandResponses: "200,400",
244
+ // Dynamic scroll offset to account for headers
245
+ scrollYOffset: this.calculateScrollYOffset
246
+ },
247
+ redocContainer,
248
+ (error: any) => {
249
+ if (error) {
250
+ this.showErrorUI(
251
+ "Failed to show Reference UI using Redoc: ",
252
+ error
253
+ );
254
+ } else {
255
+ this.integrateCustomComponents();
256
+ }
257
+ }
258
+ );
259
+ }
260
+ } catch (error) {
261
+ this.showErrorUI("Failed to load Redoc library:", error);
262
+ }
263
+ }
264
+
265
+ // Polls for Redoc library availability with timeout
266
+ private async waitForRedoc(timeout = ELEMENT_TIMEOUT): Promise<void> {
267
+ const success = await pollUntil(
268
+ () => !!window.Redoc,
269
+ ELEMENT_CHECK_INTERVAL,
270
+ timeout
271
+ );
272
+
273
+ if (!success) {
274
+ throw new Error(
275
+ "Redoc library failed to load within timeout period"
276
+ );
277
+ }
278
+ }
279
+
280
+ // Integrates custom elements (doc phase, footer, survey) into Redoc container
281
+ private async integrateCustomComponents(): Promise<void> {
282
+ try {
283
+ const redocContainer = this.getRedocContainer();
284
+ if (!redocContainer) {
285
+ return;
286
+ }
287
+
288
+ const apiContentDiv = await this.waitForApiContent(redocContainer);
289
+ apiContentDiv.setAttribute("lwc:dom", "manual");
290
+
291
+ const docPhaseInfo = this.getDocPhaseInfo();
292
+ if (docPhaseInfo) {
293
+ this.insertDocPhase(apiContentDiv, docPhaseInfo);
294
+ }
295
+
296
+ if (typeof Sprig !== "undefined") {
297
+ this.insertSprigSurvey(apiContentDiv);
298
+ }
299
+
300
+ this.insertFooter(apiContentDiv);
301
+
302
+ // Wait for footer to be rendered before updating styles
303
+ requestAnimationFrame(() => {
304
+ this.updateRedocThirdColumnStyle(redocContainer);
305
+
306
+ // Fix initial hash scroll after doc phase insertion
307
+ this.handleInitialHashScrollFix();
308
+ });
309
+ } catch (error) {
310
+ this.showErrorUI("Failed to integrate custom components:", error);
311
+ }
312
+ }
313
+
314
+ // Waits for Redoc's API content element to be rendered
315
+ private async waitForApiContent(
316
+ container: HTMLElement
317
+ ): Promise<HTMLElement> {
318
+ const success = await pollUntil(
319
+ () => !!container.querySelector(".api-content"),
320
+ ELEMENT_CHECK_INTERVAL,
321
+ ELEMENT_TIMEOUT
322
+ );
323
+
324
+ if (!success) {
325
+ throw new Error(
326
+ "Redoc API content element not found within timeout period"
327
+ );
328
+ }
329
+
330
+ return container.querySelector<HTMLElement>(".api-content")!;
331
+ }
332
+
333
+ // Creates and inserts doc phase component at container start
334
+ private insertDocPhase(container: HTMLElement, docPhaseInfo: string): void {
335
+ const wrapper = document.createElement("div");
336
+ wrapper.className = "doc-phase-wrapper";
337
+ container.insertBefore(wrapper, container.firstChild);
338
+
339
+ const docPhaseElement = createElement("doc-phase", { is: DocPhase });
340
+ Object.assign(docPhaseElement, { docPhaseInfo });
341
+ wrapper.appendChild(docPhaseElement);
342
+ }
343
+
344
+ // Appends footer component to container
345
+ private insertFooter(container: HTMLElement): void {
346
+ const footerElement = createElement("dx-footer", { is: DxFooter });
347
+ Object.assign(footerElement, { variant: "no-signup" });
348
+ container.appendChild(footerElement);
349
+ }
350
+
351
+ // Appends Sprig survey component to container
352
+ private insertSprigSurvey(container: HTMLElement): void {
353
+ const wrapper = document.createElement("div");
354
+ wrapper.className = "sprig-survey-wrapper";
355
+ container.appendChild(wrapper);
356
+
357
+ const feedbackElement = createElement("doc-sprig-survey", {
358
+ is: SprigSurvey
359
+ });
360
+ wrapper.appendChild(feedbackElement);
361
+ }
362
+
363
+ // Adjusts third column bottom position to prevent footer overlap
364
+ private updateRedocThirdColumnStyle(redocContainer: HTMLElement): void {
365
+ const footer = redocContainer.querySelector(
366
+ ".redoc-wrap .api-content dx-footer"
367
+ ) as HTMLElement;
368
+ if (!footer) {
369
+ console.warn(
370
+ "Footer element not found, skipping third column styling"
371
+ );
372
+ return;
373
+ }
374
+
375
+ const redocThirdColumnElement = redocContainer.querySelector(
376
+ ".redoc-wrap > div:last-child"
377
+ ) as HTMLElement;
378
+ if (!redocThirdColumnElement) {
379
+ console.warn(
380
+ "Third column element not found, skipping third column styling"
381
+ );
382
+ return;
383
+ }
384
+
385
+ const footerHeight = footer.getBoundingClientRect()?.height || 0;
386
+ const footerMarginTop = parseInt(
387
+ getComputedStyle(this.template.host).getPropertyValue(
388
+ "--dx-footer-margin-top"
389
+ ),
390
+ 10
391
+ );
392
+
393
+ redocThirdColumnElement.style.setProperty(
394
+ "bottom",
395
+ `${footerHeight + footerMarginTop}px`
396
+ );
397
+ }
398
+
399
+ // Fixes initial hash scroll positioning after doc phase insertion
400
+ private handleInitialHashScrollFix(): void {
401
+ const hash = window.location.hash;
402
+ if (!hash || hash.length <= 1) {
403
+ return;
404
+ }
405
+
406
+ // Small delay to ensure all components are fully rendered
407
+ requestAnimationFrame(() => {
408
+ const targetId = hash.substring(1);
409
+ const targetElement = document.getElementById(targetId);
410
+
411
+ if (!targetElement) {
412
+ return;
413
+ }
414
+
415
+ const elementTop =
416
+ (targetElement.getBoundingClientRect()?.top || 0) +
417
+ window.pageYOffset;
418
+ const scrollOffset = this.calculateScrollYOffset();
419
+ const correctedScrollPosition = elementTop - scrollOffset;
420
+
421
+ window.scrollTo({
422
+ top: correctedScrollPosition,
423
+ behavior: "smooth"
424
+ });
425
+ });
426
+ }
427
+ }
@@ -1,3 +1,36 @@
1
1
  @import "dxHelpers/reset";
2
2
  @import "dxHelpers/text";
3
3
  @import "dxHelpers/table";
4
+
5
+ .code {
6
+ color: #181818;
7
+ font-family: Courier, var(--dx-g-font-mono);
8
+ font-size: var(--dx-g-text-sm);
9
+ line-height: 150%;
10
+ background-color: #f4f4f4;
11
+ }
12
+
13
+ table {
14
+ width: 100%;
15
+ }
16
+
17
+ .specification-properties table {
18
+ display: table;
19
+ }
20
+
21
+ .left-border {
22
+ border-left: 1px solid var(--dx-g-gray-90);
23
+ }
24
+
25
+ .icon-cell {
26
+ text-align: center;
27
+ }
28
+
29
+ .icon {
30
+ display: inline-block;
31
+ }
32
+
33
+ .loader {
34
+ pointer-events: none;
35
+ bottom: 30%;
36
+ }
@@ -1,58 +1,130 @@
1
1
  <template>
2
- <div title="properties">
3
- <template if:true={hasAttributes}>
2
+ <div class="specification-properties">
3
+ <dx-spinner
4
+ size="large"
5
+ variant="brand"
6
+ class="loader"
7
+ if:true={isLoading}
8
+ ></dx-spinner>
9
+ <dx-error-fallback lwc:if={showError}></dx-error-fallback>
10
+ <dx-error-fallback
11
+ lwc:if={showNoSpecifications}
12
+ title="No specifications to show"
13
+ description="No specifications are available for this component or API module. When specifications are defined, they'll appear here."
14
+ ></dx-error-fallback>
15
+ <template lwc:if={hasAttributes}>
4
16
  <doc-heading
5
17
  header="Attributes"
6
18
  hash="attributes"
7
19
  aria-level="2"
20
+ id="attributes"
8
21
  ></doc-heading>
9
22
  <table>
10
23
  <thead>
11
24
  <tr>
12
25
  <th>Name</th>
13
26
  <th>Description</th>
27
+ <th>Type</th>
28
+ <th>Default</th>
29
+ <th>Required</th>
14
30
  </tr>
15
31
  </thead>
16
32
  <tbody>
17
33
  <template for:each={attributes} for:item="attribute">
18
34
  <tr key={attribute.name}>
19
- <td>{attribute.nameInKebabCase}</td>
35
+ <td>
36
+ <span class="code">
37
+ <template lwc:if={isModelAura}>
38
+ {attribute.name}
39
+ </template>
40
+ <template lwc:else>
41
+ {attribute.nameInKebabCase}
42
+ </template>
43
+ </span>
44
+ </td>
20
45
  <td>{attribute.description}</td>
46
+ <td>{attribute.type}</td>
47
+ <td>{attribute.default}</td>
48
+ <td class="icon-cell">
49
+ <template lwc:if={attribute.required}>
50
+ <dx-icon
51
+ symbol="success"
52
+ size="large"
53
+ color="green-vibrant-65"
54
+ class="icon"
55
+ ></dx-icon>
56
+ </template>
57
+ </td>
21
58
  </tr>
22
59
  </template>
23
60
  </tbody>
24
61
  </table>
25
62
  </template>
26
63
 
27
- <template if:true={hasMethods}>
64
+ <template lwc:if={hasMethods}>
28
65
  <doc-heading
29
66
  header="Methods"
30
67
  hash="methods"
31
68
  aria-level="2"
69
+ id="methods"
32
70
  ></doc-heading>
33
71
  <table>
34
72
  <thead>
35
73
  <tr>
36
74
  <th>Name</th>
37
75
  <th>Description</th>
76
+ <th>Argument Name</th>
77
+ <th>Argument Type</th>
78
+ <th>Argument Description</th>
38
79
  </tr>
39
80
  </thead>
40
81
  <tbody>
41
- <template for:each={methods} for:item="method">
42
- <tr key={method.name}>
43
- <td>{method.nameInKebabCase}</td>
44
- <td>{method.description}</td>
45
- </tr>
82
+ <template for:each={processedMethods} for:item="method">
83
+ <template lwc:if={method.firstArgument}>
84
+ <tr key={method.name}>
85
+ <td rowspan={method.arguments.length}>
86
+ <span class="code">{method.name}</span>
87
+ </td>
88
+ <td rowspan={method.arguments.length}>
89
+ {method.description}
90
+ </td>
91
+ <td class={method.cssForMultipleArguments}>
92
+ {method.firstArgument.name}
93
+ </td>
94
+ <td>{method.firstArgument.type}</td>
95
+ <td>{method.firstArgument.description}</td>
96
+ </tr>
97
+ <template
98
+ for:each={method.remainingArguments}
99
+ for:item="arg"
100
+ >
101
+ <tr key={arg.name}>
102
+ <td>{arg.name}</td>
103
+ <td>{arg.type}</td>
104
+ <td>{arg.description}</td>
105
+ </tr>
106
+ </template>
107
+ </template>
108
+ <template lwc:else>
109
+ <tr key={method.name}>
110
+ <td>
111
+ <span class="code">{method.name}</span>
112
+ </td>
113
+ <td>{method.description}</td>
114
+ <td colspan="3"></td>
115
+ </tr>
116
+ </template>
46
117
  </template>
47
118
  </tbody>
48
119
  </table>
49
120
  </template>
50
121
 
51
- <template if:true={hasSlots}>
122
+ <template lwc:if={hasSlots}>
52
123
  <doc-heading
53
124
  header="Slots"
54
125
  hash="slots"
55
126
  aria-level="2"
127
+ id="slots"
56
128
  ></doc-heading>
57
129
  <table>
58
130
  <thead>
@@ -64,7 +136,9 @@
64
136
  <tbody>
65
137
  <template for:each={slots} for:item="slot">
66
138
  <tr key={slot.name}>
67
- <td>{slot.nameInKebabCase}</td>
139
+ <td>
140
+ <span class="code">{slot.nameInKebabCase}</span>
141
+ </td>
68
142
  <td>{slot.description}</td>
69
143
  </tr>
70
144
  </template>
@@ -72,7 +146,7 @@
72
146
  </table>
73
147
  </template>
74
148
 
75
- <template if:true={hasEvents}>
149
+ <template lwc:if={hasEvents}>
76
150
  <doc-heading
77
151
  header="Events"
78
152
  hash="events"
@@ -86,10 +160,14 @@
86
160
  </tr>
87
161
  </thead>
88
162
  <tbody>
89
- <template for:each={slots} for:item="slot">
90
- <tr key={slot.name}>
91
- <td>{slot.nameInKebabCase}</td>
92
- <td>{slot.description}</td>
163
+ <template for:each={processedEvents} for:item="event">
164
+ <tr key={event.name}>
165
+ <td>
166
+ <span class="code">
167
+ {event.nameCapitalized}
168
+ </span>
169
+ </td>
170
+ <td>{event.description}</td>
93
171
  </tr>
94
172
  </template>
95
173
  </tbody>