@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.
- package/lwc.config.json +2 -1
- package/package.json +29 -28
- package/src/modules/doc/amfReference/amfReference.css +0 -12
- package/src/modules/doc/amfReference/amfReference.html +2 -6
- package/src/modules/doc/amfReference/amfReference.ts +48 -37
- package/src/modules/doc/amfTopic/amfTopic.ts +24 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.html +0 -1
- package/src/modules/doc/componentPlayground/componentPlayground.css +11 -3
- package/src/modules/doc/componentPlayground/componentPlayground.html +4 -4
- package/src/modules/doc/componentPlayground/componentPlayground.ts +69 -1
- package/src/modules/doc/content/content.ts +0 -1
- package/src/modules/doc/contentCallout/contentCallout.css +1 -0
- package/src/modules/doc/contentLayout/contentLayout.html +53 -56
- package/src/modules/doc/contentLayout/contentLayout.ts +82 -43
- package/src/modules/doc/contentMedia/contentMedia.css +1 -1
- package/src/modules/doc/header/header.html +5 -1
- package/src/modules/doc/header/header.ts +10 -0
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +8 -0
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +38 -42
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +116 -15
- package/src/modules/doc/phase/phase.css +0 -7
- package/src/modules/doc/redocReference/redocReference.css +7 -0
- package/src/modules/doc/redocReference/redocReference.html +13 -0
- package/src/modules/doc/redocReference/redocReference.ts +425 -0
- package/src/modules/doc/specificationContent/specificationContent.html +15 -9
- package/src/modules/doc/specificationContent/specificationContent.ts +39 -0
- package/src/modules/doc/superscriptSubscript/superscriptSubscript.html +8 -0
- package/src/modules/doc/superscriptSubscript/superscriptSubscript.ts +16 -0
- package/src/modules/doc/versionPicker/versionPicker.html +2 -0
- package/src/modules/doc/xmlContent/xmlContent.css +0 -10
- package/src/modules/doc/xmlContent/xmlContent.html +11 -8
- package/src/modules/doc/xmlContent/xmlContent.ts +95 -53
- package/src/modules/docHelpers/amfStyle/amfStyle.css +0 -2
- package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +32 -1
- package/src/modules/doc/chat/README.md +0 -179
- package/src/modules/doc/chat/chat.css +0 -818
- package/src/modules/doc/chat/chat.html +0 -241
- package/src/modules/doc/chat/chat.ts +0 -586
- package/src/modules/doc/editFile/editFile.css +0 -514
- package/src/modules/doc/editFile/editFile.html +0 -164
- 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 {
|
|
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
|
|
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(() =>
|
|
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.
|
|
256
|
-
this.
|
|
257
|
-
|
|
258
|
-
|
|
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!, "
|
|
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<
|
|
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<
|
|
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
|
}
|
|
@@ -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:
|
|
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
|