@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "1.3.345-spage",
3
+ "version": "1.3.345-spec-alpha1",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -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 = headingElement.attributes.hash?.nodeValue;
128
- headingElement.header = headingElement.attributes.header?.nodeValue;
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
- headingElements =
142
- tabPanelItem.querySelectorAll(TOC_HEADER_TAG);
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
- window.removeEventListener("popstate", this.handlePopState);
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
 
@@ -0,0 +1,3 @@
1
+ @import "dxHelpers/reset";
2
+ @import "dxHelpers/text";
3
+ @import "dxHelpers/table";
@@ -1,46 +1,145 @@
1
1
  <template>
2
- <lightning-card title="Fetched Data">
3
- <!-- Display Attributes if they exist -->
2
+ <div class="specification-properties">
4
3
  <template if:true={hasAttributes}>
5
- <h3>Attributes</h3>
6
- <ul>
7
- <template for:each={data.attribute} for:item="attr">
8
- <li key={attr.name}>
9
- <strong>{attr.name}:</strong>
10
- {attr.desc}
11
- </li>
12
- </template>
13
- </ul>
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
- <h3>Methods</h3>
19
- <ul>
20
- <template for:each={data.method} for:item="method">
21
- <li key={method.name}>
22
- <strong>{method.name}:</strong>
23
- {method.desc}
24
- </li>
25
- </template>
26
- </ul>
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
- <h3>Slots</h3>
32
- <ul>
33
- <template for:each={data.slots} for:item="slot">
34
- <li key={slot.name}>
35
- <strong>{slot.name}:</strong>
36
- {slot.desc}
37
- </li>
38
- </template>
39
- </ul>
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={error}>
43
- <p>Error fetching data: {error}</p>
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
- </lightning-card>
144
+ </div>
46
145
  </template>
@@ -1,41 +1,98 @@
1
- import { LightningElement, track } from "lwc";
2
- import { toJson } from "dxUtils/normalizers";
1
+ import { LightningElement, track, api } from "lwc";
2
+ import { Method, Specifiaction } from "typings/custom";
3
3
 
4
- export default class specificationContent extends LightningElement {
5
- @track data: any; // Reactive property to store fetched data
6
- @track error: any; // To track any errors
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.loadData();
24
+ this.fetchComponentMetadata();
11
25
  }
12
26
 
13
- // Method to make the API call
14
- loadData() {
15
- fetch("http://localhost:3002/card") // Sample API URL
16
- .then((response) => response.json()) // Convert response to JSON
17
- .then((result) => {
18
- this.data = toJson(result); // Store data to update UI
19
- this.error = undefined; // Clear any previous errors
20
- })
21
- .catch((error) => {
22
- this.error = error; // Capture any errors
23
- this.data = {}; // Clear data on error
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.data?.attribute;
69
+ return this.attributes?.length > 0;
30
70
  }
31
71
 
32
- // Helper to check if methods exist
33
72
  get hasMethods() {
34
- return this.data?.method;
73
+ return this.methods?.length > 0;
35
74
  }
36
75
 
37
- // Helper to check if slots exist
38
76
  get hasSlots() {
39
- return this.data?.slots;
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
  }