@bbki.ng/bb-msg-history 0.11.2 → 0.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/component.d.ts +7 -0
- package/dist/component.js +41 -5
- package/dist/const/styles.js +5 -0
- package/package.json +1 -1
- package/src/component.ts +53 -6
- package/src/const/styles.ts +5 -0
package/dist/component.d.ts
CHANGED
|
@@ -41,6 +41,13 @@ export declare class BBMsgHistory extends HTMLElement {
|
|
|
41
41
|
* el.appendMessage({ author: 'bob', text: 'How are you?' });
|
|
42
42
|
*/
|
|
43
43
|
appendMessage(message: Message): this;
|
|
44
|
+
/**
|
|
45
|
+
* Scroll to the bottom of the message history.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* el.scrollToBottom(); // Scroll with smooth animation
|
|
49
|
+
*/
|
|
50
|
+
scrollToBottom(): this;
|
|
44
51
|
private _appendSingleMessage;
|
|
45
52
|
connectedCallback(): void;
|
|
46
53
|
disconnectedCallback(): void;
|
package/dist/component.js
CHANGED
|
@@ -6,7 +6,7 @@ import { buildMessageRowHtml, setupTooltipForElement } from './utils/message-bui
|
|
|
6
6
|
import { buildScrollButtonHtml } from './utils/scroll-button.js';
|
|
7
7
|
export class BBMsgHistory extends HTMLElement {
|
|
8
8
|
static get observedAttributes() {
|
|
9
|
-
return ['theme', 'loading', 'hide-scroll-bar', 'infinite'];
|
|
9
|
+
return ['theme', 'loading', 'hide-scroll-bar', 'infinite', 'hide-scroll-button'];
|
|
10
10
|
}
|
|
11
11
|
constructor() {
|
|
12
12
|
super();
|
|
@@ -19,7 +19,7 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
19
19
|
this.attachShadow({ mode: 'open' });
|
|
20
20
|
}
|
|
21
21
|
attributeChangedCallback(name) {
|
|
22
|
-
if (name === 'theme' || name === 'loading' || name === 'hide-scroll-bar' || name === 'infinite') {
|
|
22
|
+
if (name === 'theme' || name === 'loading' || name === 'hide-scroll-bar' || name === 'infinite' || name === 'hide-scroll-button') {
|
|
23
23
|
this.render();
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -76,6 +76,26 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
76
76
|
this._setupMutationObserver();
|
|
77
77
|
return this;
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Scroll to the bottom of the message history.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* el.scrollToBottom(); // Scroll with smooth animation
|
|
84
|
+
*/
|
|
85
|
+
scrollToBottom() {
|
|
86
|
+
if (this.hasAttribute('infinite')) {
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
const container = this.shadowRoot?.querySelector('.history');
|
|
90
|
+
if (!container) {
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
container.scrollTo({
|
|
94
|
+
top: container.scrollHeight,
|
|
95
|
+
behavior: 'smooth',
|
|
96
|
+
});
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
79
99
|
_appendSingleMessage(message) {
|
|
80
100
|
const container = this.shadowRoot.querySelector('.history');
|
|
81
101
|
// If empty state or no container, do full render first
|
|
@@ -133,6 +153,12 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
133
153
|
if (scrollButton && this._scrollButtonVisible) {
|
|
134
154
|
this._scrollButtonVisible = false;
|
|
135
155
|
scrollButton.classList.remove('visible');
|
|
156
|
+
// Dispatch hide event
|
|
157
|
+
this.dispatchEvent(new CustomEvent('bb-scrollbuttonhide', {
|
|
158
|
+
bubbles: true,
|
|
159
|
+
composed: true,
|
|
160
|
+
detail: { visible: false }
|
|
161
|
+
}));
|
|
136
162
|
}
|
|
137
163
|
}
|
|
138
164
|
}
|
|
@@ -233,12 +259,13 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
233
259
|
<div class="loading-spinner"></div>
|
|
234
260
|
</div>`
|
|
235
261
|
: '';
|
|
262
|
+
const hideScrollButton = this.hasAttribute('hide-scroll-button');
|
|
236
263
|
this.shadowRoot.innerHTML = `
|
|
237
264
|
<style>${MAIN_STYLES}${LOADING_STYLES}</style>
|
|
238
265
|
<div class="history" role="log" aria-live="polite" aria-label="Message history">
|
|
239
266
|
${messagesHtml}
|
|
240
267
|
</div>
|
|
241
|
-
${buildScrollButtonHtml()}
|
|
268
|
+
${hideScrollButton ? '' : buildScrollButtonHtml()}
|
|
242
269
|
${loadingOverlay}
|
|
243
270
|
`;
|
|
244
271
|
this._setupAfterRender();
|
|
@@ -276,9 +303,12 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
276
303
|
_setupAfterRender() {
|
|
277
304
|
requestAnimationFrame(() => {
|
|
278
305
|
const container = this.shadowRoot.querySelector('.history');
|
|
279
|
-
const
|
|
306
|
+
const hideScrollButton = this.hasAttribute('hide-scroll-button');
|
|
307
|
+
const scrollButton = hideScrollButton
|
|
308
|
+
? null
|
|
309
|
+
: this.shadowRoot.querySelector('.scroll-to-bottom');
|
|
280
310
|
const isInfinite = this.hasAttribute('infinite');
|
|
281
|
-
if (container && !isInfinite) {
|
|
311
|
+
if (container && !isInfinite && !hideScrollButton) {
|
|
282
312
|
// Mark as programmatic scroll to prevent triggering user scroll detection
|
|
283
313
|
this._isProgrammaticScroll = true;
|
|
284
314
|
container.scrollTop = container.scrollHeight;
|
|
@@ -338,6 +368,12 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
338
368
|
if (shouldShow !== this._scrollButtonVisible) {
|
|
339
369
|
this._scrollButtonVisible = shouldShow;
|
|
340
370
|
button.classList.toggle('visible', shouldShow);
|
|
371
|
+
// Dispatch custom event
|
|
372
|
+
this.dispatchEvent(new CustomEvent(shouldShow ? 'bb-scrollbuttonshow' : 'bb-scrollbuttonhide', {
|
|
373
|
+
bubbles: true,
|
|
374
|
+
composed: true,
|
|
375
|
+
detail: { visible: shouldShow }
|
|
376
|
+
}));
|
|
341
377
|
}
|
|
342
378
|
};
|
|
343
379
|
// Initialize last scroll position
|
package/dist/const/styles.js
CHANGED
|
@@ -71,6 +71,11 @@ export const MAIN_STYLES = `
|
|
|
71
71
|
display: none;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/* Hide scroll button when explicitly disabled */
|
|
75
|
+
:host([hide-scroll-button]) .scroll-to-bottom {
|
|
76
|
+
display: none;
|
|
77
|
+
}
|
|
78
|
+
|
|
74
79
|
/* Scroll to bottom button */
|
|
75
80
|
.scroll-to-bottom {
|
|
76
81
|
position: absolute;
|
package/package.json
CHANGED
package/src/component.ts
CHANGED
|
@@ -17,7 +17,7 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
17
17
|
private _lastScrollTop = 0;
|
|
18
18
|
|
|
19
19
|
static get observedAttributes() {
|
|
20
|
-
return ['theme', 'loading', 'hide-scroll-bar', 'infinite'];
|
|
20
|
+
return ['theme', 'loading', 'hide-scroll-bar', 'infinite', 'hide-scroll-button'];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
constructor() {
|
|
@@ -26,7 +26,7 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
attributeChangedCallback(name: string) {
|
|
29
|
-
if (name === 'theme' || name === 'loading' || name === 'hide-scroll-bar' || name === 'infinite') {
|
|
29
|
+
if (name === 'theme' || name === 'loading' || name === 'hide-scroll-bar' || name === 'infinite' || name === 'hide-scroll-button') {
|
|
30
30
|
this.render();
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -92,6 +92,30 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
92
92
|
return this;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Scroll to the bottom of the message history.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* el.scrollToBottom(); // Scroll with smooth animation
|
|
100
|
+
*/
|
|
101
|
+
scrollToBottom(): this {
|
|
102
|
+
if (this.hasAttribute('infinite')) {
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const container = this.shadowRoot?.querySelector('.history') as HTMLElement | null;
|
|
107
|
+
if (!container) {
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
container.scrollTo({
|
|
112
|
+
top: container.scrollHeight,
|
|
113
|
+
behavior: 'smooth',
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
|
|
95
119
|
private _appendSingleMessage(message: Message): void {
|
|
96
120
|
const container = this.shadowRoot!.querySelector('.history') as HTMLElement;
|
|
97
121
|
|
|
@@ -170,6 +194,15 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
170
194
|
if (scrollButton && this._scrollButtonVisible) {
|
|
171
195
|
this._scrollButtonVisible = false;
|
|
172
196
|
scrollButton.classList.remove('visible');
|
|
197
|
+
|
|
198
|
+
// Dispatch hide event
|
|
199
|
+
this.dispatchEvent(
|
|
200
|
+
new CustomEvent('bb-scrollbuttonhide', {
|
|
201
|
+
bubbles: true,
|
|
202
|
+
composed: true,
|
|
203
|
+
detail: { visible: false }
|
|
204
|
+
})
|
|
205
|
+
);
|
|
173
206
|
}
|
|
174
207
|
}
|
|
175
208
|
}
|
|
@@ -293,12 +326,14 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
293
326
|
</div>`
|
|
294
327
|
: '';
|
|
295
328
|
|
|
329
|
+
const hideScrollButton = this.hasAttribute('hide-scroll-button');
|
|
330
|
+
|
|
296
331
|
this.shadowRoot!.innerHTML = `
|
|
297
332
|
<style>${MAIN_STYLES}${LOADING_STYLES}</style>
|
|
298
333
|
<div class="history" role="log" aria-live="polite" aria-label="Message history">
|
|
299
334
|
${messagesHtml}
|
|
300
335
|
</div>
|
|
301
|
-
${buildScrollButtonHtml()}
|
|
336
|
+
${hideScrollButton ? '' : buildScrollButtonHtml()}
|
|
302
337
|
${loadingOverlay}
|
|
303
338
|
`;
|
|
304
339
|
|
|
@@ -345,17 +380,20 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
345
380
|
private _setupAfterRender(): void {
|
|
346
381
|
requestAnimationFrame(() => {
|
|
347
382
|
const container = this.shadowRoot!.querySelector('.history') as HTMLElement;
|
|
348
|
-
const
|
|
383
|
+
const hideScrollButton = this.hasAttribute('hide-scroll-button');
|
|
384
|
+
const scrollButton = hideScrollButton
|
|
385
|
+
? null
|
|
386
|
+
: (this.shadowRoot!.querySelector('.scroll-to-bottom') as HTMLButtonElement);
|
|
349
387
|
const isInfinite = this.hasAttribute('infinite');
|
|
350
388
|
|
|
351
|
-
if (container && !isInfinite) {
|
|
389
|
+
if (container && !isInfinite && !hideScrollButton) {
|
|
352
390
|
// Mark as programmatic scroll to prevent triggering user scroll detection
|
|
353
391
|
this._isProgrammaticScroll = true;
|
|
354
392
|
container.scrollTop = container.scrollHeight;
|
|
355
393
|
requestAnimationFrame(() => {
|
|
356
394
|
this._isProgrammaticScroll = false;
|
|
357
395
|
});
|
|
358
|
-
this._setupScrollTracking(container, scrollButton
|
|
396
|
+
this._setupScrollTracking(container, scrollButton!, { skipInitialCheck: true });
|
|
359
397
|
}
|
|
360
398
|
|
|
361
399
|
if (scrollButton && !isInfinite) {
|
|
@@ -420,6 +458,15 @@ export class BBMsgHistory extends HTMLElement {
|
|
|
420
458
|
if (shouldShow !== this._scrollButtonVisible) {
|
|
421
459
|
this._scrollButtonVisible = shouldShow;
|
|
422
460
|
button.classList.toggle('visible', shouldShow);
|
|
461
|
+
|
|
462
|
+
// Dispatch custom event
|
|
463
|
+
this.dispatchEvent(
|
|
464
|
+
new CustomEvent(shouldShow ? 'bb-scrollbuttonshow' : 'bb-scrollbuttonhide', {
|
|
465
|
+
bubbles: true,
|
|
466
|
+
composed: true,
|
|
467
|
+
detail: { visible: shouldShow }
|
|
468
|
+
})
|
|
469
|
+
);
|
|
423
470
|
}
|
|
424
471
|
};
|
|
425
472
|
|
package/src/const/styles.ts
CHANGED
|
@@ -72,6 +72,11 @@ export const MAIN_STYLES = `
|
|
|
72
72
|
display: none;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/* Hide scroll button when explicitly disabled */
|
|
76
|
+
:host([hide-scroll-button]) .scroll-to-bottom {
|
|
77
|
+
display: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
75
80
|
/* Scroll to bottom button */
|
|
76
81
|
.scroll-to-bottom {
|
|
77
82
|
position: absolute;
|