@v-tilt/browser 1.12.0 → 1.13.0
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/dist/array.full.js +1 -1
- package/dist/array.full.js.map +1 -1
- package/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/array.no-external.js +1 -1
- package/dist/chat.js +1 -1
- package/dist/chat.js.map +1 -1
- package/dist/extensions/chat/chat.d.ts +132 -2
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.js +1 -1
- package/package.json +71 -71
|
@@ -35,6 +35,15 @@ export declare class LazyLoadedChat implements LazyLoadedChatInterface {
|
|
|
35
35
|
private _widgetRegistry;
|
|
36
36
|
/** Tracks whether show() was explicitly called (vs open() temporarily revealing the container). */
|
|
37
37
|
private _bubbleExplicitShow;
|
|
38
|
+
private _lastConnectedDistinctId;
|
|
39
|
+
private _unsubscribeIdentity;
|
|
40
|
+
private _unsubscribeReset;
|
|
41
|
+
private _identityChangeInFlight;
|
|
42
|
+
private _userScrolledUp;
|
|
43
|
+
private _unreadNewMessagesCount;
|
|
44
|
+
private _messagesScrollListenerBound;
|
|
45
|
+
private _conversationListenersBound;
|
|
46
|
+
private _channelListListenersBound;
|
|
38
47
|
constructor(instance: VTilt, config?: ChatConfig);
|
|
39
48
|
get isOpen(): boolean;
|
|
40
49
|
get isConnected(): boolean;
|
|
@@ -58,6 +67,26 @@ export declare class LazyLoadedChat implements LazyLoadedChatInterface {
|
|
|
58
67
|
toggle(): void;
|
|
59
68
|
show(): void;
|
|
60
69
|
hide(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Build a stub ChatChannel from a ChatChannelSummary so that
|
|
72
|
+
* `selectChannel` can populate state synchronously while the real
|
|
73
|
+
* `GET /channels/:id` response is in flight. The header reads `ai_mode`
|
|
74
|
+
* and `status` immediately; remaining fields are filled by the response.
|
|
75
|
+
*/
|
|
76
|
+
private _stubChannelFromSummary;
|
|
77
|
+
/**
|
|
78
|
+
* Handle a vTilt identity change (anon → identified, or user → user).
|
|
79
|
+
*
|
|
80
|
+
* Ably enforces that the connection's `clientId` is immutable for the
|
|
81
|
+
* lifetime of a Realtime connection. Authorizing a token with a different
|
|
82
|
+
* `clientId` puts the connection into the terminal `failed` state and
|
|
83
|
+
* produces a 40102 error. The correct response is to fully close the
|
|
84
|
+
* existing client and create a new one with a token bound to the new id.
|
|
85
|
+
*
|
|
86
|
+
* This also clears per-identity state (channels, messages, unread count)
|
|
87
|
+
* since those belong to the previous user.
|
|
88
|
+
*/
|
|
89
|
+
private _handleIdentityChange;
|
|
61
90
|
getChannels(): Promise<void>;
|
|
62
91
|
selectChannel(channelId: string): Promise<void>;
|
|
63
92
|
createChannel(): Promise<void>;
|
|
@@ -93,6 +122,13 @@ export declare class LazyLoadedChat implements LazyLoadedChatInterface {
|
|
|
93
122
|
private _refreshAblyToken;
|
|
94
123
|
/**
|
|
95
124
|
* Subscribe to per-channel messages and typing for a specific conversation.
|
|
125
|
+
*
|
|
126
|
+
* Attach is async; the user may close the widget or switch to a different
|
|
127
|
+
* channel while we are still awaiting `attach()`. In that case
|
|
128
|
+
* `_disconnectChannel()` runs concurrently — it nulls `this._ablyChannel`
|
|
129
|
+
* and calls `detach()`, which makes Ably reject the pending `attach()` with
|
|
130
|
+
* "Attach request superseded by a subsequent detach request". We treat
|
|
131
|
+
* that race as expected: bail out silently instead of logging an error.
|
|
96
132
|
*/
|
|
97
133
|
private _connectChannel;
|
|
98
134
|
/**
|
|
@@ -155,13 +191,107 @@ export declare class LazyLoadedChat implements LazyLoadedChatInterface {
|
|
|
155
191
|
*/
|
|
156
192
|
private _constrainWidgetToViewport;
|
|
157
193
|
private _updateHeader;
|
|
158
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Render the channel-list view with mode-aware diffing.
|
|
196
|
+
*
|
|
197
|
+
* Three modes share a single content container so the click delegation
|
|
198
|
+
* stays bound across them:
|
|
199
|
+
* - empty: no channels and not loading → welcome / CTA screen
|
|
200
|
+
* - skeleton: no channels and loading → shimmer placeholders
|
|
201
|
+
* - populated: 1+ channels → scaffold + diff items by id
|
|
202
|
+
*
|
|
203
|
+
* Only the populated mode preserves item DOM identity; the other two are
|
|
204
|
+
* rare transient states where a full innerHTML write is cheap.
|
|
205
|
+
*/
|
|
206
|
+
private _renderChannelList;
|
|
207
|
+
/**
|
|
208
|
+
* Wire a single delegated click handler on the list container so we don't
|
|
209
|
+
* re-attach per-item listeners on every render.
|
|
210
|
+
*/
|
|
211
|
+
private _setupChannelListDelegation;
|
|
212
|
+
private _createChannelItemNode;
|
|
213
|
+
private _updateChannelItemNode;
|
|
214
|
+
/**
|
|
215
|
+
* Compact fingerprint used to decide whether a channel-item DOM node needs
|
|
216
|
+
* an update. Only includes fields that the rendered HTML depends on.
|
|
217
|
+
*/
|
|
218
|
+
private _channelItemFingerprint;
|
|
219
|
+
private _getEmptyListHTML;
|
|
220
|
+
private _getListScaffoldHTML;
|
|
221
|
+
private _getListSkeletonHTML;
|
|
222
|
+
/**
|
|
223
|
+
* Build a skeleton bubble that mirrors the shape of a real chat message
|
|
224
|
+
* from `_getMessageHTML`: same avatar size (32×32), same bubble padding
|
|
225
|
+
* (12px 16px), same asymmetric border-radius (20/20/20/4 incoming,
|
|
226
|
+
* 20/20/4/20 outgoing), and a meta line underneath sized like the
|
|
227
|
+
* "Sender · 12:34" footer. The shimmer fills the bubble interior — not
|
|
228
|
+
* floating lines — so the placeholder reads as a "loading message"
|
|
229
|
+
* rather than a generic content blob. Width varies per call so the
|
|
230
|
+
* stack of bubbles has visual rhythm instead of looking like a parade
|
|
231
|
+
* of identical rectangles.
|
|
232
|
+
*/
|
|
233
|
+
private _getSkeletonBubbleHTML;
|
|
234
|
+
/**
|
|
235
|
+
* Skeleton placeholder shown while `selectChannel` is loading the
|
|
236
|
+
* messages of an existing conversation. Three alternating bubbles
|
|
237
|
+
* (incoming → outgoing → incoming) imply history is on its way.
|
|
238
|
+
* Bubble widths vary to avoid the "fake repeated rectangles" look.
|
|
239
|
+
*/
|
|
240
|
+
private _getMessageSkeletonHTML;
|
|
241
|
+
/**
|
|
242
|
+
* New-conversation loader shown while `createChannel` (or
|
|
243
|
+
* `sendMessage({channel: 'new'})`) is in flight. A single incoming
|
|
244
|
+
* bubble using *exactly* the same shape, padding, border-radius, and
|
|
245
|
+
* avatar treatment as a real incoming message from `_getMessageHTML`
|
|
246
|
+
* — so when the real greeting arrives it morphs in place rather than
|
|
247
|
+
* snapping to a new layout. The avatar uses the live AI/Support color
|
|
248
|
+
* + icon (identity is known from `_config.aiMode`), and the bubble
|
|
249
|
+
* carries three animated typing dots instead of text, signalling
|
|
250
|
+
* "the assistant is preparing your greeting."
|
|
251
|
+
*/
|
|
252
|
+
private _getNewChannelLoaderHTML;
|
|
159
253
|
private _getChannelItemHTML;
|
|
160
254
|
private _getConversationHTML;
|
|
161
|
-
private _attachChannelListListeners;
|
|
162
255
|
private _attachConversationListeners;
|
|
163
256
|
private _formatRelativeTime;
|
|
257
|
+
/**
|
|
258
|
+
* Render messages with a key-based diff.
|
|
259
|
+
*
|
|
260
|
+
* - Each message node carries `data-msg-key="msg:<id>"` and a fingerprint;
|
|
261
|
+
* if both match what we already have, the node is left untouched.
|
|
262
|
+
* - The "New" divider lives as a sibling node with its own key so it
|
|
263
|
+
* participates in the same diff (no flicker when it moves).
|
|
264
|
+
* - Scroll position is preserved: we only snap to the bottom when the user
|
|
265
|
+
* was already near the bottom or just sent their own message. Otherwise
|
|
266
|
+
* we surface a "↓ N new messages" pill instead of yanking them down.
|
|
267
|
+
* - Newly-inserted message nodes get the `vtilt-msg-enter` class for a
|
|
268
|
+
* subtle fade-in animation. The initial bulk render skips animation.
|
|
269
|
+
*/
|
|
164
270
|
private _renderMessages;
|
|
271
|
+
/**
|
|
272
|
+
* Build the "New" divider node (rendered above the first unread agent/AI
|
|
273
|
+
* message when scrolled into view).
|
|
274
|
+
*/
|
|
275
|
+
private _createMessageDividerNode;
|
|
276
|
+
/**
|
|
277
|
+
* Build a single message DOM node from the message model.
|
|
278
|
+
*/
|
|
279
|
+
private _createMessageNode;
|
|
280
|
+
/**
|
|
281
|
+
* Compact fingerprint used to decide whether a message node needs an update.
|
|
282
|
+
* Streaming AI responses update the content field many times — re-rendering
|
|
283
|
+
* the same DOM lets the cursor and layout stay stable for the user.
|
|
284
|
+
*/
|
|
285
|
+
private _messageFingerprint;
|
|
286
|
+
/**
|
|
287
|
+
* Wire (once per container) a scroll listener that tracks whether the user
|
|
288
|
+
* is reading history above the latest message. Used to suppress auto-scroll
|
|
289
|
+
* and to dismiss the "new messages" pill when the user scrolls back down.
|
|
290
|
+
*/
|
|
291
|
+
private _setupMessagesScrollListener;
|
|
292
|
+
private _isNearBottom;
|
|
293
|
+
private _showNewMessagesPill;
|
|
294
|
+
private _hideNewMessagesPill;
|
|
165
295
|
private _getMessageHTML;
|
|
166
296
|
private _isMessageReadByAgent;
|
|
167
297
|
/**
|