@salesforcedevs/docs-components 1.3.345-spage → 1.3.345-spec-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 +1 -1
- package/src/modules/doc/contentLayout/contentLayout.ts +42 -5
- package/src/modules/doc/specificationContent/specificationContent.css +3 -0
- package/src/modules/doc/specificationContent/specificationContent.html +133 -34
- package/src/modules/doc/specificationContent/specificationContent.ts +82 -25
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ declare const Sprig: (eventType: string, eventNme: string) => void;
|
|
|
12
12
|
|
|
13
13
|
const TOC_HEADER_TAG = "doc-heading";
|
|
14
14
|
const RNB_BY_TAB = "docs-tab";
|
|
15
|
+
const SPECIFICATION_TAB_TITLE = "Specification";
|
|
15
16
|
const HIGHLIGHTABLE_SELECTOR = [
|
|
16
17
|
"p",
|
|
17
18
|
"h1",
|
|
@@ -116,6 +117,13 @@ export default class ContentLayout extends LightningElement {
|
|
|
116
117
|
this.updateRNB();
|
|
117
118
|
};
|
|
118
119
|
|
|
120
|
+
onRNBClick = () => {
|
|
121
|
+
const currentTab = this.getSelectedTabId();
|
|
122
|
+
if (currentTab === SPECIFICATION_TAB_TITLE) {
|
|
123
|
+
this.didScrollToSelectedHash = false;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
119
127
|
private getTabPanelList() {
|
|
120
128
|
return document.querySelector("dx-tab-panel-list");
|
|
121
129
|
}
|
|
@@ -124,8 +132,14 @@ export default class ContentLayout extends LightningElement {
|
|
|
124
132
|
const headingElements = this.getHeadingElements();
|
|
125
133
|
headingElements.forEach((headingElement: any) => {
|
|
126
134
|
// Sometimes elements hash and header is not being set when slot content is wrapped with div
|
|
127
|
-
headingElement.hash
|
|
128
|
-
|
|
135
|
+
if (!headingElement.hash) {
|
|
136
|
+
headingElement.hash = headingElement.attributes.hash?.nodeValue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!headingElement.header) {
|
|
140
|
+
headingElement.header =
|
|
141
|
+
headingElement.attributes.header?.nodeValue;
|
|
142
|
+
}
|
|
129
143
|
});
|
|
130
144
|
this.updateTocItems(headingElements);
|
|
131
145
|
};
|
|
@@ -138,8 +152,19 @@ export default class ContentLayout extends LightningElement {
|
|
|
138
152
|
tabPanelListItem?.querySelectorAll("dx-tab-panel");
|
|
139
153
|
for (const tabPanelItem of tabPanels) {
|
|
140
154
|
if (tabPanelItem.active) {
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
// This is needed for Specification tab content
|
|
156
|
+
const specificationElement = tabPanelItem.querySelector(
|
|
157
|
+
"doc-specification-content"
|
|
158
|
+
);
|
|
159
|
+
if (specificationElement) {
|
|
160
|
+
headingElements =
|
|
161
|
+
specificationElement.shadowRoot.querySelectorAll(
|
|
162
|
+
TOC_HEADER_TAG
|
|
163
|
+
);
|
|
164
|
+
} else {
|
|
165
|
+
headingElements =
|
|
166
|
+
tabPanelItem.querySelectorAll(TOC_HEADER_TAG);
|
|
167
|
+
}
|
|
143
168
|
break;
|
|
144
169
|
}
|
|
145
170
|
}
|
|
@@ -278,6 +303,11 @@ export default class ContentLayout extends LightningElement {
|
|
|
278
303
|
this.setRNBByTab();
|
|
279
304
|
if (this.showTabBasedRNB) {
|
|
280
305
|
window.addEventListener("tabchanged", this.onTabChanged);
|
|
306
|
+
window.addEventListener(
|
|
307
|
+
"specificationdatarendered",
|
|
308
|
+
this.onTabChanged
|
|
309
|
+
);
|
|
310
|
+
window.addEventListener("selectedcontent", this.onRNBClick);
|
|
281
311
|
this.restoreTabSelection();
|
|
282
312
|
}
|
|
283
313
|
this.restoreScroll();
|
|
@@ -293,7 +323,14 @@ export default class ContentLayout extends LightningElement {
|
|
|
293
323
|
window.removeEventListener("scroll", this.adjustNavPosition);
|
|
294
324
|
window.removeEventListener("resize", this.adjustNavPosition);
|
|
295
325
|
window.removeEventListener("tabchanged", this.onTabChanged);
|
|
296
|
-
|
|
326
|
+
if (this.showTabBasedRNB) {
|
|
327
|
+
window.removeEventListener(
|
|
328
|
+
"specificationdatarendered",
|
|
329
|
+
this.onTabChanged
|
|
330
|
+
);
|
|
331
|
+
window.removeEventListener("selectedcontent", this.onRNBClick);
|
|
332
|
+
window.removeEventListener("popstate", this.handlePopState);
|
|
333
|
+
}
|
|
297
334
|
this.searchSyncer.dispose();
|
|
298
335
|
this.clearRenderObserverTimer();
|
|
299
336
|
|
|
@@ -1,46 +1,145 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<!-- Display Attributes if they exist -->
|
|
2
|
+
<div class="specification-properties">
|
|
4
3
|
<template if:true={hasAttributes}>
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
<doc-heading
|
|
5
|
+
header="Attributes"
|
|
6
|
+
hash="attributes"
|
|
7
|
+
aria-level="2"
|
|
8
|
+
id="attributes"
|
|
9
|
+
></doc-heading>
|
|
10
|
+
<table>
|
|
11
|
+
<thead>
|
|
12
|
+
<tr>
|
|
13
|
+
<th>Name</th>
|
|
14
|
+
<th>Description</th>
|
|
15
|
+
<th>Type</th>
|
|
16
|
+
<th>Default</th>
|
|
17
|
+
<th>Required</th>
|
|
18
|
+
</tr>
|
|
19
|
+
</thead>
|
|
20
|
+
<tbody>
|
|
21
|
+
<template for:each={attributes} for:item="attribute">
|
|
22
|
+
<tr key={attribute.name}>
|
|
23
|
+
<td>{attribute.nameInKebabCase}</td>
|
|
24
|
+
<td>{attribute.description}</td>
|
|
25
|
+
<td>{attribute.type}</td>
|
|
26
|
+
<td>{attribute.default}</td>
|
|
27
|
+
<td>
|
|
28
|
+
<template lwc:if={attribute.required}>
|
|
29
|
+
<dx-icon
|
|
30
|
+
symbol="success"
|
|
31
|
+
size="large"
|
|
32
|
+
color="green-vibrant-65"
|
|
33
|
+
></dx-icon>
|
|
34
|
+
</template>
|
|
35
|
+
</td>
|
|
36
|
+
</tr>
|
|
37
|
+
</template>
|
|
38
|
+
</tbody>
|
|
39
|
+
</table>
|
|
14
40
|
</template>
|
|
15
41
|
|
|
16
|
-
<!-- Display Methods if they exist -->
|
|
17
42
|
<template if:true={hasMethods}>
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
<doc-heading
|
|
44
|
+
header="Methods"
|
|
45
|
+
hash="methods"
|
|
46
|
+
aria-level="2"
|
|
47
|
+
id="methods"
|
|
48
|
+
></doc-heading>
|
|
49
|
+
<table>
|
|
50
|
+
<thead>
|
|
51
|
+
<tr>
|
|
52
|
+
<th>Name</th>
|
|
53
|
+
<th>Description</th>
|
|
54
|
+
<th>Argument Name</th>
|
|
55
|
+
<th>Argument Type</th>
|
|
56
|
+
<th>Argument Description</th>
|
|
57
|
+
</tr>
|
|
58
|
+
</thead>
|
|
59
|
+
<tbody>
|
|
60
|
+
<template for:each={processedMethods} for:item="method">
|
|
61
|
+
<template if:true={method.firstArgument}>
|
|
62
|
+
<tr key={method.name}>
|
|
63
|
+
<td rowspan={method.arguments.length}>
|
|
64
|
+
{method.nameInKebabCase}
|
|
65
|
+
</td>
|
|
66
|
+
<td rowspan={method.arguments.length}>
|
|
67
|
+
{method.description}
|
|
68
|
+
</td>
|
|
69
|
+
<td>{method.firstArgument.name}</td>
|
|
70
|
+
<td>{method.firstArgument.type}</td>
|
|
71
|
+
<td>{method.firstArgument.description}</td>
|
|
72
|
+
</tr>
|
|
73
|
+
<template
|
|
74
|
+
for:each={method.remainingArguments}
|
|
75
|
+
for:item="arg"
|
|
76
|
+
>
|
|
77
|
+
<tr key={arg.name}>
|
|
78
|
+
<td>{arg.name}</td>
|
|
79
|
+
<td>{arg.type}</td>
|
|
80
|
+
<td>{arg.description}</td>
|
|
81
|
+
</tr>
|
|
82
|
+
</template>
|
|
83
|
+
</template>
|
|
84
|
+
<template if:false={method.firstArgument}>
|
|
85
|
+
<tr key={method.name}>
|
|
86
|
+
<td>{method.nameInKebabCase}</td>
|
|
87
|
+
<td>{method.description}</td>
|
|
88
|
+
<td colspan="3"></td>
|
|
89
|
+
</tr>
|
|
90
|
+
</template>
|
|
91
|
+
</template>
|
|
92
|
+
</tbody>
|
|
93
|
+
</table>
|
|
27
94
|
</template>
|
|
28
95
|
|
|
29
|
-
<!-- Display Slots if they exist -->
|
|
30
96
|
<template if:true={hasSlots}>
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
97
|
+
<doc-heading
|
|
98
|
+
header="Slots"
|
|
99
|
+
hash="slots"
|
|
100
|
+
aria-level="2"
|
|
101
|
+
id="slots"
|
|
102
|
+
></doc-heading>
|
|
103
|
+
<table>
|
|
104
|
+
<thead>
|
|
105
|
+
<tr>
|
|
106
|
+
<th>Name</th>
|
|
107
|
+
<th>Description</th>
|
|
108
|
+
</tr>
|
|
109
|
+
</thead>
|
|
110
|
+
<tbody>
|
|
111
|
+
<template for:each={slots} for:item="slot">
|
|
112
|
+
<tr key={slot.name}>
|
|
113
|
+
<td>{slot.nameInKebabCase}</td>
|
|
114
|
+
<td>{slot.description}</td>
|
|
115
|
+
</tr>
|
|
116
|
+
</template>
|
|
117
|
+
</tbody>
|
|
118
|
+
</table>
|
|
40
119
|
</template>
|
|
41
120
|
|
|
42
|
-
<template if:true={
|
|
43
|
-
<
|
|
121
|
+
<template if:true={hasEvents}>
|
|
122
|
+
<doc-heading
|
|
123
|
+
header="Events"
|
|
124
|
+
hash="events"
|
|
125
|
+
aria-level="2"
|
|
126
|
+
></doc-heading>
|
|
127
|
+
<table>
|
|
128
|
+
<thead>
|
|
129
|
+
<tr>
|
|
130
|
+
<th>Name</th>
|
|
131
|
+
<th>Description</th>
|
|
132
|
+
</tr>
|
|
133
|
+
</thead>
|
|
134
|
+
<tbody>
|
|
135
|
+
<template for:each={events} for:item="event">
|
|
136
|
+
<tr key={event.name}>
|
|
137
|
+
<td>{event.nameInKebabCase}</td>
|
|
138
|
+
<td>{event.description}</td>
|
|
139
|
+
</tr>
|
|
140
|
+
</template>
|
|
141
|
+
</tbody>
|
|
142
|
+
</table>
|
|
44
143
|
</template>
|
|
45
|
-
</
|
|
144
|
+
</div>
|
|
46
145
|
</template>
|
|
@@ -1,41 +1,98 @@
|
|
|
1
|
-
import { LightningElement, track } from "lwc";
|
|
2
|
-
import {
|
|
1
|
+
import { LightningElement, track, api } from "lwc";
|
|
2
|
+
import { Method, Specifiaction } from "typings/custom";
|
|
3
3
|
|
|
4
|
-
export default class
|
|
5
|
-
@track data: any;
|
|
6
|
-
|
|
4
|
+
export default class SpecificationContent extends LightningElement {
|
|
5
|
+
@track data: any;
|
|
6
|
+
// TODO: added these default values for testing, will drop this once the backend is ready.
|
|
7
|
+
@api component: string = "button";
|
|
8
|
+
@api type: string = "lwc";
|
|
9
|
+
@api subType: string = "lightning";
|
|
10
|
+
|
|
11
|
+
/* TODO: The actual URL is as follows:
|
|
12
|
+
* http://api.salesforce.com/doc-platform/developer/v1/{type}/{sub-type}/{component-name}
|
|
13
|
+
* Until the API integration is ready, we will go ahead with mocked-router-url.
|
|
14
|
+
*/
|
|
15
|
+
@api routerUrl: string =
|
|
16
|
+
"https://cx-mock-router-internal-07a18d7b3f61.herokuapp.com";
|
|
17
|
+
|
|
18
|
+
private attributes: Specifiaction[] = [];
|
|
19
|
+
private methods: Method[] = [];
|
|
20
|
+
private slots: Specifiaction[] = [];
|
|
21
|
+
private events: Specifiaction[] = [];
|
|
7
22
|
|
|
8
|
-
// Lifecycle method to fetch data when the component is inserted into the DOM
|
|
9
23
|
connectedCallback() {
|
|
10
|
-
this.
|
|
24
|
+
this.fetchComponentMetadata();
|
|
11
25
|
}
|
|
12
26
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
async fetchComponentMetadata() {
|
|
28
|
+
const url = `${this.routerUrl}/${this.type}/${this.subType}/${this.component}`;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const response = await fetch(url);
|
|
32
|
+
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
// TODO: Will add loader and show error as follow-up
|
|
35
|
+
throw new Error(`Failed to fetch: ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const result = await response.json();
|
|
39
|
+
this.data = result;
|
|
40
|
+
({
|
|
41
|
+
attributes: this.attributes,
|
|
42
|
+
methods: this.methods,
|
|
43
|
+
slots: this.slots,
|
|
44
|
+
events: this.events
|
|
45
|
+
} = this.data);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
this.data = {};
|
|
48
|
+
console.error("fetchComponentMetadata() failed for:" + url);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* This getting is doing the data processing for Method to display the nested tables.
|
|
54
|
+
*/
|
|
55
|
+
get processedMethods() {
|
|
56
|
+
return this.methods.map((method) => {
|
|
57
|
+
const [firstArgument, ...remainingArguments] =
|
|
58
|
+
method.arguments || [];
|
|
59
|
+
return {
|
|
60
|
+
...method,
|
|
61
|
+
firstArgument,
|
|
62
|
+
remainingArguments,
|
|
63
|
+
hasArguments: method.arguments && method.arguments.length > 0
|
|
64
|
+
};
|
|
65
|
+
});
|
|
25
66
|
}
|
|
26
67
|
|
|
27
|
-
// Helper to check if attributes exist
|
|
28
68
|
get hasAttributes() {
|
|
29
|
-
return this.
|
|
69
|
+
return this.attributes?.length > 0;
|
|
30
70
|
}
|
|
31
71
|
|
|
32
|
-
// Helper to check if methods exist
|
|
33
72
|
get hasMethods() {
|
|
34
|
-
return this.
|
|
73
|
+
return this.methods?.length > 0;
|
|
35
74
|
}
|
|
36
75
|
|
|
37
|
-
// Helper to check if slots exist
|
|
38
76
|
get hasSlots() {
|
|
39
|
-
return this.
|
|
77
|
+
return this.slots?.length > 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get hasEvents() {
|
|
81
|
+
return this.events?.length > 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
renderedCallback(): void {
|
|
85
|
+
this.notifySpecificationDataRendered();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
notifySpecificationDataRendered() {
|
|
89
|
+
// Dispatch a custom event to notify the specification tab has rendered.
|
|
90
|
+
this.dispatchEvent(
|
|
91
|
+
new CustomEvent("specificationdatarendered", {
|
|
92
|
+
detail: { name: "doc-specification-content" },
|
|
93
|
+
bubbles: true,
|
|
94
|
+
composed: true
|
|
95
|
+
})
|
|
96
|
+
);
|
|
40
97
|
}
|
|
41
98
|
}
|