@salesforcedevs/docs-components 0.0.1-edit → 0.0.1-superscript

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 (41) hide show
  1. package/lwc.config.json +2 -1
  2. package/package.json +29 -28
  3. package/src/modules/doc/amfReference/amfReference.css +0 -12
  4. package/src/modules/doc/amfReference/amfReference.html +2 -6
  5. package/src/modules/doc/amfReference/amfReference.ts +48 -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/componentPlayground/componentPlayground.css +11 -3
  9. package/src/modules/doc/componentPlayground/componentPlayground.html +4 -4
  10. package/src/modules/doc/componentPlayground/componentPlayground.ts +69 -1
  11. package/src/modules/doc/content/content.ts +0 -1
  12. package/src/modules/doc/contentCallout/contentCallout.css +1 -0
  13. package/src/modules/doc/contentLayout/contentLayout.html +53 -56
  14. package/src/modules/doc/contentLayout/contentLayout.ts +82 -43
  15. package/src/modules/doc/contentMedia/contentMedia.css +1 -1
  16. package/src/modules/doc/header/header.html +5 -1
  17. package/src/modules/doc/header/header.ts +10 -0
  18. package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +8 -0
  19. package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +38 -42
  20. package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +116 -15
  21. package/src/modules/doc/phase/phase.css +0 -7
  22. package/src/modules/doc/redocReference/redocReference.css +7 -0
  23. package/src/modules/doc/redocReference/redocReference.html +13 -0
  24. package/src/modules/doc/redocReference/redocReference.ts +425 -0
  25. package/src/modules/doc/specificationContent/specificationContent.html +15 -9
  26. package/src/modules/doc/specificationContent/specificationContent.ts +39 -0
  27. package/src/modules/doc/superscriptSubscript/superscriptSubscript.html +8 -0
  28. package/src/modules/doc/superscriptSubscript/superscriptSubscript.ts +16 -0
  29. package/src/modules/doc/versionPicker/versionPicker.html +2 -0
  30. package/src/modules/doc/xmlContent/xmlContent.css +0 -10
  31. package/src/modules/doc/xmlContent/xmlContent.html +11 -8
  32. package/src/modules/doc/xmlContent/xmlContent.ts +95 -53
  33. package/src/modules/docHelpers/amfStyle/amfStyle.css +0 -2
  34. package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +32 -1
  35. package/src/modules/doc/chat/README.md +0 -179
  36. package/src/modules/doc/chat/chat.css +0 -818
  37. package/src/modules/doc/chat/chat.html +0 -241
  38. package/src/modules/doc/chat/chat.ts +0 -586
  39. package/src/modules/doc/editFile/editFile.css +0 -514
  40. package/src/modules/doc/editFile/editFile.html +0 -164
  41. package/src/modules/doc/editFile/editFile.ts +0 -213
@@ -1,9 +1,7 @@
1
1
  /* eslint-disable @lwc/lwc/no-document-query */
2
2
  import { api, track } from "lwc";
3
- import { normalizeBoolean } from "dxUtils/normalizers";
4
3
  import { FetchContent } from "./utils";
5
4
  import {
6
- CoveoAdvancedQueryXMLConfig,
7
5
  DocLanguage,
8
6
  DocVersion,
9
7
  TreeNode,
@@ -11,11 +9,12 @@ import {
11
9
  SiderbarFooter,
12
10
  HistoryState,
13
11
  PageReference,
14
- TocMap
12
+ TocMap,
13
+ ContentData
15
14
  } from "./types";
16
15
  import { SearchSyncer } from "docUtils/searchSyncer";
17
16
  import { LightningElementWithState } from "dxBaseElements/lightningElementWithState";
18
- import { logCoveoPageView, oldVersionDocInfo } from "docUtils/utils";
17
+ import { oldVersionDocInfo } from "docUtils/utils";
19
18
  import { Breadcrumb, DocPhaseInfo, Language } from "typings/custom";
20
19
  import { track as trackGTM } from "dxUtils/analytics";
21
20
  import DOMPurify from "dompurify";
@@ -41,11 +40,8 @@ export default class DocXmlContent extends LightningElementWithState<{
41
40
  internalLinkClicked: boolean;
42
41
  }> {
43
42
  @api apiDomain = "https://developer.salesforce.com";
44
- @api coveoOrganizationId!: string;
45
- @api coveoPublicAccessToken!: string;
46
- @api coveoAnalyticsToken!: string;
47
- @api coveoSearchHub!: string;
48
43
  @api hideFooter = false;
44
+ @api displayReadingTime = false;
49
45
 
50
46
  @api
51
47
  get allLanguages(): Array<Language> {
@@ -58,21 +54,13 @@ export default class DocXmlContent extends LightningElementWithState<{
58
54
  }
59
55
  }
60
56
 
61
- @api
62
- get enableCoveo() {
63
- return this._enableCoveo;
64
- }
65
-
66
- set enableCoveo(value) {
67
- this._enableCoveo = normalizeBoolean(value);
68
- }
69
-
70
57
  private availableLanguages: Array<DocLanguage> = [];
71
58
  @track private availableVersions: Array<DocVersion> = [];
72
59
  private contentProvider?: FetchContent;
73
60
  private docContent = "";
74
61
  private language?: DocLanguage | null = null;
75
- private loaded = false;
62
+ private displayContent = false;
63
+ private display404 = false;
76
64
  private _pageHeader?: Header;
77
65
  private pdfUrl = "";
78
66
  private tocMap: TocMap = {};
@@ -81,7 +69,6 @@ export default class DocXmlContent extends LightningElementWithState<{
81
69
  private docTitle = "";
82
70
  private _pathName = "";
83
71
  private listenerAttached = false;
84
- private _enableCoveo?: boolean = false;
85
72
  private sidebarFooterContent: SiderbarFooter = { ...defaultSidebarFooter };
86
73
  private latestVersion = false;
87
74
  private previewVersion = false;
@@ -90,6 +77,10 @@ export default class DocXmlContent extends LightningElementWithState<{
90
77
  return !this.hideFooter;
91
78
  }
92
79
 
80
+ private get computedReadingTime(): number | undefined {
81
+ return this.displayReadingTime ? this.readingTime : undefined;
82
+ }
83
+
93
84
  private searchSyncer = new SearchSyncer({
94
85
  callbacks: {
95
86
  onSearchChange: (nextSearchString: string): void => {
@@ -161,6 +152,7 @@ export default class DocXmlContent extends LightningElementWithState<{
161
152
 
162
153
  @track private pageReference: PageReference = {};
163
154
  @track breadcrumbs: Array<Breadcrumb> = [];
155
+ @track readingTime?: number;
164
156
 
165
157
  constructor() {
166
158
  super();
@@ -185,7 +177,13 @@ export default class DocXmlContent extends LightningElementWithState<{
185
177
  this.apiDomain,
186
178
  this.allLanguages
187
179
  );
188
- this.fetchDocument().then(() => (this.loaded = true));
180
+ this.fetchDocument().then((content: any) => {
181
+ if (content) {
182
+ this.displayContent = true;
183
+ } else {
184
+ this.display404 = true;
185
+ }
186
+ });
189
187
  window.addEventListener("popstate", this.handlePopState);
190
188
 
191
189
  this.searchSyncer.init();
@@ -252,35 +250,13 @@ export default class DocXmlContent extends LightningElementWithState<{
252
250
  // Coveo is enabled and the version is greater than 51 (within the latest 3 versions)
253
251
  // TODO: we need a better fix for version number check
254
252
  return !(
255
- this.enableCoveo &&
256
- this.coveoOrganizationId &&
257
- this.coveoPublicAccessToken &&
258
- (!this.version?.releaseVersion ||
259
- (this.version?.releaseVersion &&
260
- parseInt(
261
- this.version.releaseVersion.replace("v", ""),
262
- 10
263
- ) >= 53))
253
+ !this.version?.releaseVersion ||
254
+ (this.version?.releaseVersion &&
255
+ parseInt(this.version.releaseVersion.replace("v", ""), 10) >=
256
+ 53)
264
257
  );
265
258
  }
266
259
 
267
- private get coveoAdvancedQueryConfig(): CoveoAdvancedQueryXMLConfig {
268
- const config: {
269
- locale?: string;
270
- topicid?: string;
271
- version?: string;
272
- } = {
273
- locale: this.languageId,
274
- topicid: this.deliverable
275
- };
276
-
277
- if (this.releaseVersionId && this.releaseVersionId !== "noversion") {
278
- config.version = this.releaseVersionId;
279
- }
280
-
281
- return config;
282
- }
283
-
284
260
  private get pageHeader(): Header {
285
261
  if (!this._pageHeader) {
286
262
  this._pageHeader = document.querySelector("doc-header")!;
@@ -385,7 +361,7 @@ export default class DocXmlContent extends LightningElementWithState<{
385
361
  );
386
362
  this.pageReference.docId = this.language!.url;
387
363
 
388
- trackGTM(event.target!, "custEv_ctaLinkClick", {
364
+ trackGTM(event.target!, "custEv_linkClick", {
389
365
  click_text: event.detail,
390
366
  element_title: "language selector",
391
367
  click_url: `${window.location.origin}${this.pageReferenceToString(
@@ -463,7 +439,7 @@ export default class DocXmlContent extends LightningElementWithState<{
463
439
  );
464
440
  }
465
441
 
466
- async fetchDocument(): Promise<void> {
442
+ async fetchDocument(): Promise<string> {
467
443
  this.setState({
468
444
  isFetchingDocument: true
469
445
  });
@@ -477,7 +453,7 @@ export default class DocXmlContent extends LightningElementWithState<{
477
453
  this.setState({
478
454
  isFetchingDocument: false
479
455
  });
480
- return;
456
+ return "";
481
457
  }
482
458
 
483
459
  this.docTitle = data.docTitle;
@@ -509,11 +485,11 @@ export default class DocXmlContent extends LightningElementWithState<{
509
485
  data.id
510
486
  ) {
511
487
  try {
512
- await this.fetchContent();
488
+ const moreData = await this.fetchContent();
513
489
  this.setState({
514
490
  isFetchingDocument: false
515
491
  });
516
- return;
492
+ return moreData.content;
517
493
  } catch (error) {
518
494
  this.pageReference.contentDocumentId = `${data.id}.htm`;
519
495
  this.pageReference.hash = "";
@@ -523,13 +499,27 @@ export default class DocXmlContent extends LightningElementWithState<{
523
499
  }
524
500
 
525
501
  this.docContent = data.content;
502
+ this.calculateReadingTime(data.content);
526
503
  this.addMetatags();
527
504
  this.setState({
528
505
  isFetchingDocument: false
529
506
  });
507
+
508
+ // Track page view when a new document is loaded
509
+ trackGTM(this.template.host, "doc_page_view", {
510
+ page_path: this.pageReferenceToString(this.pageReference),
511
+ doc_id: this.pageReference.docId,
512
+ content_document_id: this.pageReference.contentDocumentId,
513
+ deliverable: this.pageReference.deliverable,
514
+ language: this.language?.id,
515
+ version: this.version?.id,
516
+ article_name: this.getArticleName()
517
+ });
518
+
519
+ return data.content;
530
520
  }
531
521
 
532
- async fetchContent(): Promise<void> {
522
+ async fetchContent(): Promise<ContentData> {
533
523
  this.setState({
534
524
  isFetchingContent: true
535
525
  });
@@ -544,15 +534,31 @@ export default class DocXmlContent extends LightningElementWithState<{
544
534
 
545
535
  if (data) {
546
536
  this.docContent = data.content;
537
+ this.calculateReadingTime(data.content);
547
538
  this.addMetatags();
548
539
 
549
540
  if (!this.pageReference.hash) {
550
541
  document.body.scrollIntoView();
551
542
  }
543
+
544
+ // Track page view when new content is loaded (navigation within same document)
545
+ // Note: breadcrumbs will be built after this in updatePageReference,
546
+ // but we need to build them here to get article_name
547
+ this.buildBreadcrumbs();
548
+ trackGTM(this.template.host, "doc_page_view", {
549
+ page_path: this.pageReferenceToString(this.pageReference),
550
+ doc_id: this.pageReference.docId,
551
+ content_document_id: this.pageReference.contentDocumentId,
552
+ deliverable: this.pageReference.deliverable,
553
+ language: this.language?.id,
554
+ version: this.version?.id,
555
+ article_name: this.getArticleName()
556
+ });
552
557
  }
553
558
  this.setState({
554
559
  isFetchingContent: false
555
560
  });
561
+ return data;
556
562
  }
557
563
 
558
564
  updateHeaderAndSidebarFooter(): void {
@@ -579,7 +585,6 @@ export default class DocXmlContent extends LightningElementWithState<{
579
585
  }
580
586
 
581
587
  updateUrl(method = HistoryState.PUSH_STATE): void {
582
- logCoveoPageView(this.coveoOrganizationId, this.coveoAnalyticsToken);
583
588
  window.history[method](
584
589
  {},
585
590
  "docs",
@@ -665,6 +670,15 @@ export default class DocXmlContent extends LightningElementWithState<{
665
670
  return this.breadcrumbs && this.breadcrumbs.length > 1;
666
671
  }
667
672
 
673
+ private getArticleName(): string | undefined {
674
+ if (!this.breadcrumbs || this.breadcrumbs.length === 0) {
675
+ return undefined;
676
+ }
677
+ // Join all breadcrumb labels with "/" to create article name
678
+ // e.g., "Tooling API Objects/FieldDefinition"
679
+ return this.breadcrumbs.map((crumb) => crumb.label).join("/");
680
+ }
681
+
668
682
  private buildBreadcrumbs(): void {
669
683
  const { contentDocumentId } = this.pageReference;
670
684
  if (!contentDocumentId) {
@@ -789,4 +803,32 @@ export default class DocXmlContent extends LightningElementWithState<{
789
803
  private get showVersionPicker(): boolean {
790
804
  return !this.disableVersion;
791
805
  }
806
+
807
+ private calculateReadingTime(content: string): void {
808
+ if (!this.displayReadingTime) {
809
+ this.readingTime = undefined;
810
+ return;
811
+ }
812
+
813
+ if (!content) {
814
+ this.readingTime = undefined;
815
+ return;
816
+ }
817
+
818
+ // Strip HTML tags and get text content
819
+ const div = document.createElement("div");
820
+ div.innerHTML = DOMPurify.sanitize(content);
821
+ const textContent = div.textContent || div.innerText || "";
822
+
823
+ // Count words (split by whitespace and filter out empty strings)
824
+ const wordCount = textContent
825
+ .trim()
826
+ .split(/\s+/)
827
+ .filter((word) => word.length > 0).length;
828
+
829
+ // Calculate reading time: (wordCount / 240) + 1, rounded
830
+ const readingTimeMinutes = Math.round(wordCount / 240 + 1);
831
+ this.readingTime =
832
+ readingTimeMinutes > 0 ? readingTimeMinutes : undefined;
833
+ }
792
834
  }
@@ -174,8 +174,6 @@ api-security-documentation {
174
174
  --http-code-snippet-container-background-color: rgb(250 250 250);
175
175
  --http-code-snippet-container-padding: var(--dx-g-spacing-md);
176
176
 
177
- /* prism */
178
-
179
177
  /* --code-operator-value-background-color */
180
178
  }
181
179
 
@@ -24,6 +24,19 @@ doc-breadcrumbs {
24
24
  margin-bottom: var(--dx-g-spacing-2xl);
25
25
  }
26
26
 
27
+ .read {
28
+ display: flex;
29
+ align-items: center;
30
+ gap: var(--dx-g-spacing-xs, 8px);
31
+ margin-bottom: var(--dx-g-spacing-lg, 16px);
32
+ color: var(--dx-g-gray-30, #3e3e3c);
33
+ font-size: var(--dx-g-font-size-sm, 14px);
34
+ }
35
+
36
+ .read svg {
37
+ flex-shrink: 0;
38
+ }
39
+
27
40
  dx-sidebar,
28
41
  dx-sidebar-old {
29
42
  --dx-c-sidebar-vertical-padding: var(--dx-g-spacing-md);
@@ -57,6 +70,22 @@ dx-toc {
57
70
  .content-body-doc-phase-container {
58
71
  flex: 1;
59
72
  border-left: 1px solid var(--dx-g-gray-90);
73
+ min-width: 0;
74
+ }
75
+
76
+ .doc-phase-wrapper,
77
+ .version-wrapper {
78
+ /* NOTE: If you are changing z-index value here, ensure it's less than z-index of dx-sidebar in contentLayout.css */
79
+ z-index: var(--dx-g-z-index-100);
80
+ }
81
+
82
+ .doc-phase-wrapper {
83
+ position: sticky;
84
+ }
85
+
86
+ /* We don't want second component to sticky */
87
+ .version-wrapper {
88
+ position: static;
60
89
  }
61
90
 
62
91
  .content-body-container {
@@ -74,9 +103,10 @@ dx-toc {
74
103
 
75
104
  .content-body {
76
105
  margin: var(--dx-g-spacing-md) 0 0;
77
- max-width: 900px;
106
+ max-width: 1000px;
78
107
  flex: 1;
79
108
  width: 0;
109
+ word-break: break-word;
80
110
  }
81
111
 
82
112
  .is-sticky {
@@ -116,6 +146,7 @@ dx-toc {
116
146
 
117
147
  .content-body-container {
118
148
  padding-right: 0;
149
+ padding-left: 0;
119
150
  overflow-x: auto;
120
151
  margin-bottom: calc(var(--dx-g-spacing-5xl) + 4px);
121
152
  }
@@ -1,179 +0,0 @@
1
- # Sliding Chat Component (doc-chat)
2
-
3
- A self-contained sliding chat component with a floating trigger button that can be embedded in any layout, perfect for customer support, documentation help, or any conversational interface.
4
-
5
- ## Features
6
-
7
- - 🎯 **Sliding Component**: Slides in/out with smooth animations
8
- - 🔘 **Floating Trigger**: Built-in floating button to open chat (bottom-right corner)
9
- - 💬 **Real-time Chat**: Interactive messaging with typing indicators
10
- - 🎨 **Modern Design**: Clean, responsive interface with subtle animations
11
- - ⚙️ **Configurable**: Customizable title, placeholder, and assistant name
12
- - 📱 **Mobile Friendly**: Full-width on mobile devices
13
- - ♿ **Accessible**: ARIA labels and keyboard navigation
14
- - 🎭 **Storybook Ready**: Multiple story variations for testing
15
-
16
- ## Basic Usage
17
-
18
- The component is completely self-contained with a built-in floating trigger button:
19
-
20
- ```html
21
- <doc-chat
22
- title="Customer Support"
23
- placeholder="How can we help you today?"
24
- assistant-name="Support Bot"
25
- is-open="false"
26
- show-timestamp="true"
27
- ></doc-chat>
28
- ```
29
-
30
- That's it! The component will automatically show a floating chat button in the bottom-right corner when closed, and slide in the chat interface when opened.
31
-
32
- ## Properties
33
-
34
- | Property | Type | Default | Description |
35
- |----------|------|---------|-------------|
36
- | `title` | String | `"Chat"` | Title displayed in the chat header |
37
- | `placeholder` | String | `"Type your message..."` | Placeholder text for input field |
38
- | `assistant-name` | String | `"Assistant"` | Name of the assistant/bot |
39
- | `disabled` | Boolean | `false` | Disables the chat functionality |
40
- | `show-timestamp` | Boolean | `false` | Shows timestamps on messages |
41
- | `is-open` | Boolean | `false` | Controls sidebar visibility |
42
-
43
- ## Methods
44
-
45
- | Method | Description |
46
- |--------|-------------|
47
- | `openChat()` | Opens the chat sidebar |
48
- | `closeChat()` | Closes the chat sidebar |
49
-
50
- ## Events
51
-
52
- | Event | Description | Detail |
53
- |-------|-------------|--------|
54
- | `chatopened` | Fired when chat is opened | `{ opened: true }` |
55
- | `chatclosed` | Fired when chat is closed | `{ closed: true }` |
56
-
57
- ## Integration Example
58
-
59
- ### Simple Integration (Self-Contained)
60
- ```html
61
- <!-- The component includes its own trigger button -->
62
- <doc-chat
63
- title="Customer Support"
64
- placeholder="How can we help you today?"
65
- assistant-name="Support Bot"
66
- show-timestamp="true"
67
- is-open="false"
68
- ></doc-chat>
69
- ```
70
-
71
- ### Advanced Integration (With Custom Triggers)
72
- ```html
73
- <!-- Optional: Custom trigger button -->
74
- <button id="chat-trigger" onclick="openSupportChat()">
75
- 💬 Need Help?
76
- </button>
77
-
78
- <!-- Chat component -->
79
- <doc-chat
80
- id="support-chat"
81
- title="Customer Support"
82
- placeholder="How can we help you today?"
83
- assistant-name="Support Bot"
84
- show-timestamp="true"
85
- is-open="false"
86
- ></doc-chat>
87
- ```
88
-
89
- ### JavaScript
90
- ```javascript
91
- // Optional: Custom trigger function
92
- function openSupportChat() {
93
- const chat = document.getElementById('support-chat');
94
- chat.openChat();
95
- }
96
-
97
- // Listen for chat events
98
- document.getElementById('support-chat').addEventListener('chatclosed', (event) => {
99
- console.log('Chat was closed');
100
- });
101
-
102
- document.getElementById('support-chat').addEventListener('chatopened', (event) => {
103
- console.log('Chat was opened');
104
- });
105
- ```
106
-
107
- ## Styling
108
-
109
- The component uses CSS custom properties for easy theming:
110
-
111
- ```css
112
- doc-chat {
113
- --chat-width: 400px;
114
- --chat-z-index: 1000;
115
- --chat-transition-duration: 0.3s;
116
- --chat-header-bg: #f8f9fa;
117
- --chat-primary-color: #0066cc;
118
- --chat-border-color: #e0e0e0;
119
- }
120
- ```
121
-
122
- ## Responsive Behavior
123
-
124
- - **Desktop**: Fixed width component (400px)
125
- - **Tablet**: Full width component
126
- - **Mobile**: Full width component
127
-
128
- ## Accessibility
129
-
130
- - ARIA labels for screen readers
131
- - Keyboard navigation support
132
- - High contrast mode support
133
- - Reduced motion preferences respected
134
-
135
- ## Assistant Response Simulation
136
-
137
- The component includes a built-in response simulation system that responds to:
138
-
139
- - **Greetings**: "Hello", "Hi" → Friendly greeting
140
- - **Help requests**: "Help" → Assistance offer
141
- - **Documentation**: "Documentation", "Docs" → Navigation help
142
- - **General messages**: Contextual responses
143
-
144
- ### Replacing with Real API
145
-
146
- To integrate with a real chat API, replace the `simulateAssistantResponse` method:
147
-
148
- ```javascript
149
- // Replace this method in your extended component
150
- simulateAssistantResponse(userMessage) {
151
- // Call your chat API
152
- fetch('/api/chat', {
153
- method: 'POST',
154
- headers: { 'Content-Type': 'application/json' },
155
- body: JSON.stringify({ message: userMessage })
156
- })
157
- .then(response => response.json())
158
- .then(data => {
159
- this.addMessage(data.response, 'assistant');
160
- });
161
- }
162
- ```
163
-
164
- ## Browser Support
165
-
166
- - Chrome 80+
167
- - Firefox 72+
168
- - Safari 13+
169
- - Edge 80+
170
-
171
- ## Examples
172
-
173
- Check out the Storybook examples for various use cases:
174
-
175
- - **Default**: Basic chat setup
176
- - **With Timestamps**: Shows message timestamps
177
- - **Interactive Demo**: Fully functional example
178
- - **Mobile View**: Mobile device simulation
179
- - **Chat Trigger Example**: Integration patterns