@salesforcedevs/docs-components 0.0.17-chat → 0.0.18-chat

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": "0.0.17-chat",
3
+ "version": "0.0.18-chat",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -0,0 +1,179 @@
1
+ # Sliding Chat Component (doc-chat)
2
+
3
+ A self-contained sliding sidebar chat component with a floating trigger button that appears from the right side of the screen, perfect for customer support, documentation help, or any conversational interface.
4
+
5
+ ## Features
6
+
7
+ - 🎯 **Sliding Sidebar**: Slides in from the right side of the screen
8
+ - 🔘 **Floating Trigger**: Built-in floating button to open chat (top-left 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 top-left corner when closed, and a sliding sidebar 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 sidebar (400px)
125
+ - **Tablet**: Full width sidebar
126
+ - **Mobile**: Full viewport width
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
@@ -1,13 +1,80 @@
1
+ /* Floating trigger button */
2
+ .chat-trigger-button {
3
+ position: fixed;
4
+ top: 20px;
5
+ left: 20px;
6
+ width: 60px;
7
+ height: 60px;
8
+ border-radius: 50%;
9
+ background-color: #0066cc;
10
+ color: white;
11
+ border: none;
12
+ cursor: pointer;
13
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
14
+ z-index: 1001;
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ transition: all 0.3s ease;
19
+ animation: pulse 2s infinite;
20
+ }
21
+
22
+ .chat-trigger-button:hover {
23
+ background-color: #0052a3;
24
+ transform: scale(1.1);
25
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
26
+ }
27
+
28
+ .chat-trigger-button:active {
29
+ transform: scale(0.95);
30
+ }
31
+
32
+ .chat-icon {
33
+ width: 28px;
34
+ height: 28px;
35
+ position: absolute;
36
+ }
37
+
38
+ .chat-trigger-text {
39
+ font-size: 10px;
40
+ font-weight: 600;
41
+ text-transform: uppercase;
42
+ letter-spacing: 0.5px;
43
+ margin-top: 20px;
44
+ opacity: 0.9;
45
+ }
46
+
47
+ @keyframes pulse {
48
+ 0% {
49
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 0 rgba(0, 102, 204, 0.7);
50
+ }
51
+ 70% {
52
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 10px rgba(0, 102, 204, 0);
53
+ }
54
+ 100% {
55
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 0 rgba(0, 102, 204, 0);
56
+ }
57
+ }
58
+
59
+ /* Chat container */
1
60
  .chat-container {
61
+ position: fixed;
62
+ top: 0;
63
+ right: 0;
64
+ height: 100vh;
65
+ width: 400px;
66
+ background-color: #ffffff;
67
+ box-shadow: -2px 0 10px rgba(0, 0, 0, 0.1);
68
+ transform: translateX(100%);
69
+ transition: transform 0.3s ease-in-out;
70
+ z-index: 1000;
2
71
  display: flex;
3
72
  flex-direction: column;
4
- border: 1px solid #e0e0e0;
5
- border-radius: 8px;
6
- background-color: #ffffff;
7
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
8
- overflow: hidden;
9
- max-width: 600px;
10
- width: 100%;
73
+ border-left: 1px solid #e0e0e0;
74
+ }
75
+
76
+ .chat-container--open {
77
+ transform: translateX(0);
11
78
  }
12
79
 
13
80
  .chat-container--disabled {
@@ -19,6 +86,34 @@
19
86
  background-color: #f8f9fa;
20
87
  padding: 16px;
21
88
  border-bottom: 1px solid #e0e0e0;
89
+ display: flex;
90
+ align-items: center;
91
+ gap: 12px;
92
+ flex-shrink: 0;
93
+ }
94
+
95
+ .chat-close-button {
96
+ width: 32px;
97
+ height: 32px;
98
+ border: none;
99
+ background: none;
100
+ cursor: pointer;
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ border-radius: 4px;
105
+ transition: background-color 0.2s ease;
106
+ color: #666666;
107
+ }
108
+
109
+ .chat-close-button:hover {
110
+ background-color: #e9ecef;
111
+ color: #333333;
112
+ }
113
+
114
+ .close-icon {
115
+ width: 18px;
116
+ height: 18px;
22
117
  }
23
118
 
24
119
  .chat-title {
@@ -26,14 +121,15 @@
26
121
  font-size: 18px;
27
122
  font-weight: 600;
28
123
  color: #333333;
124
+ flex: 1;
29
125
  }
30
126
 
31
127
  .chat-messages {
32
128
  flex: 1;
33
129
  overflow-y: auto;
34
130
  padding: 16px;
35
- max-height: 300px;
36
131
  scroll-behavior: smooth;
132
+ min-height: 0;
37
133
  }
38
134
 
39
135
  .message-wrapper {
@@ -140,6 +236,7 @@
140
236
  border-top: 1px solid #e0e0e0;
141
237
  padding: 16px;
142
238
  background-color: #ffffff;
239
+ flex-shrink: 0;
143
240
  }
144
241
 
145
242
  .chat-input-container {
@@ -199,24 +296,79 @@
199
296
 
200
297
  /* Responsive design */
201
298
  @media (max-width: 768px) {
299
+ .chat-trigger-button {
300
+ width: 50px;
301
+ height: 50px;
302
+ top: 15px;
303
+ left: 15px;
304
+ }
305
+
306
+ .chat-icon {
307
+ width: 24px;
308
+ height: 24px;
309
+ }
310
+
311
+ .chat-trigger-text {
312
+ font-size: 8px;
313
+ margin-top: 18px;
314
+ }
315
+
202
316
  .chat-container {
203
- max-width: 100%;
204
- border-radius: 0;
205
- border-left: none;
206
- border-right: none;
317
+ width: 100%;
318
+ right: 0;
319
+ transform: translateX(100%);
320
+ }
321
+
322
+ .chat-container--open {
323
+ transform: translateX(0);
207
324
  }
208
325
 
209
326
  .message-content {
210
327
  max-width: 90%;
211
328
  }
329
+ }
330
+
331
+ @media (max-width: 480px) {
332
+ .chat-trigger-button {
333
+ width: 45px;
334
+ height: 45px;
335
+ top: 10px;
336
+ left: 10px;
337
+ }
338
+
339
+ .chat-icon {
340
+ width: 20px;
341
+ height: 20px;
342
+ }
343
+
344
+ .chat-trigger-text {
345
+ font-size: 7px;
346
+ margin-top: 16px;
347
+ }
348
+
349
+ .chat-container {
350
+ width: 100vw;
351
+ }
352
+
353
+ .chat-header {
354
+ padding: 12px;
355
+ }
212
356
 
213
357
  .chat-messages {
214
- max-height: 250px;
358
+ padding: 12px;
359
+ }
360
+
361
+ .chat-input-area {
362
+ padding: 12px;
215
363
  }
216
364
  }
217
365
 
218
366
  /* Accessibility improvements */
219
367
  @media (prefers-reduced-motion: reduce) {
368
+ .chat-trigger-button {
369
+ animation: none;
370
+ }
371
+
220
372
  .typing-dot {
221
373
  animation: none;
222
374
  }
@@ -1,10 +1,34 @@
1
1
  <template>
2
- <div class={chatContainerClass} style={maxHeight}>
2
+ <!-- Floating trigger button - visible when chat is closed -->
3
+ <template lwc:if={showTriggerButton}>
4
+ <button
5
+ class="chat-trigger-button"
6
+ onclick={handleOpenClick}
7
+ aria-label="Open chat"
8
+ >
9
+ <svg class="chat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
10
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>
11
+ </svg>
12
+ <span class="chat-trigger-text">Chat</span>
13
+ </button>
14
+ </template>
15
+
16
+ <!-- Chat sidebar -->
17
+ <div class={chatContainerClass}>
3
18
  <div class="chat-header">
4
19
  <h3 class="chat-title">{title}</h3>
20
+ <button
21
+ class="chat-close-button"
22
+ onclick={handleCloseClick}
23
+ aria-label="Close chat"
24
+ >
25
+ <svg class="close-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
26
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
27
+ </svg>
28
+ </button>
5
29
  </div>
6
30
 
7
- <div class="chat-messages" style={maxHeight}>
31
+ <div class="chat-messages">
8
32
  <template for:each={messagesWithTyping} for:item="message">
9
33
  <div key={message.id} class="message-wrapper" data-sender={message.sender}>
10
34
  <div class="message-content">
@@ -43,7 +67,8 @@
43
67
  type="text"
44
68
  class="chat-input"
45
69
  placeholder={placeholder}
46
- onchange={handleInputChange}
70
+ value={currentMessage}
71
+ oninput={handleInputChange}
47
72
  onkeydown={handleKeyDown}
48
73
  disabled={disabled}
49
74
  />
@@ -35,12 +35,22 @@ export default class Chat extends LightningElement {
35
35
  this._showTimestamp = normalizeBoolean(value);
36
36
  }
37
37
 
38
+ @api
39
+ get isOpen() {
40
+ return this._isOpen;
41
+ }
42
+
43
+ set isOpen(value) {
44
+ this._isOpen = normalizeBoolean(value);
45
+ }
46
+
38
47
  @track messages: ChatMessage[] = [];
39
48
  @track currentMessage: string = "";
40
49
  @track isAssistantTyping: boolean = false;
41
50
 
42
51
  private _disabled: boolean = false;
43
52
  private _showTimestamp: boolean = false;
53
+ private _isOpen: boolean = false;
44
54
  private messageIdCounter: number = 0;
45
55
 
46
56
  connectedCallback() {
@@ -51,10 +61,15 @@ export default class Chat extends LightningElement {
51
61
  get chatContainerClass() {
52
62
  return cx(
53
63
  "chat-container",
54
- this.disabled && "chat-container--disabled"
64
+ this.disabled && "chat-container--disabled",
65
+ this.isOpen && "chat-container--open"
55
66
  );
56
67
  }
57
68
 
69
+ get showTriggerButton() {
70
+ return !this.isOpen;
71
+ }
72
+
58
73
  get messagesWithTyping() {
59
74
  const messages = [...this.messages];
60
75
  if (this.isAssistantTyping) {
@@ -160,4 +175,40 @@ export default class Chat extends LightningElement {
160
175
  get sendButtonDisabled() {
161
176
  return this.disabled || !this.currentMessage.trim();
162
177
  }
178
+
179
+ handleCloseClick() {
180
+ this.isOpen = false;
181
+
182
+ // Dispatch custom event to notify parent components
183
+ this.dispatchEvent(new CustomEvent('chatclosed', {
184
+ detail: { closed: true }
185
+ }));
186
+ }
187
+
188
+ handleOpenClick() {
189
+ this.isOpen = true;
190
+
191
+ // Dispatch custom event to notify parent components
192
+ this.dispatchEvent(new CustomEvent('chatopened', {
193
+ detail: { opened: true }
194
+ }));
195
+ }
196
+
197
+ openChat() {
198
+ this.isOpen = true;
199
+
200
+ // Dispatch custom event to notify parent components
201
+ this.dispatchEvent(new CustomEvent('chatopened', {
202
+ detail: { opened: true }
203
+ }));
204
+ }
205
+
206
+ closeChat() {
207
+ this.isOpen = false;
208
+
209
+ // Dispatch custom event to notify parent components
210
+ this.dispatchEvent(new CustomEvent('chatclosed', {
211
+ detail: { closed: true }
212
+ }));
213
+ }
163
214
  }