@salesforcedevs/docs-components 0.0.17-chat → 0.0.19-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
|
@@ -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 (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 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
|
+
bottom: 20px;
|
|
5
|
+
right: 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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
+
bottom: 15px;
|
|
303
|
+
right: 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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
+
bottom: 10px;
|
|
336
|
+
right: 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
|
-
|
|
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
|
-
|
|
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"
|
|
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
|
-
|
|
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
|
}
|