@bbki.ng/bb-msg-history 1.0.0 → 2.0.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/components/bb-custom-avatar.d.ts +20 -0
- package/dist/components/bb-custom-avatar.js +145 -0
- package/dist/components/bb-letter-avatar.d.ts +14 -0
- package/dist/components/bb-letter-avatar.js +61 -0
- package/dist/components/bb-loading-overlay.d.ts +14 -0
- package/dist/components/bb-loading-overlay.js +89 -0
- package/dist/components/bb-message-bubble.d.ts +19 -0
- package/dist/components/bb-message-bubble.js +116 -0
- package/dist/components/bb-message.d.ts +27 -0
- package/dist/components/bb-message.js +174 -0
- package/dist/components/bb-msg-history.d.ts +111 -0
- package/dist/components/bb-msg-history.js +473 -0
- package/dist/components/bb-scroll-button.d.ts +16 -0
- package/dist/components/bb-scroll-button.js +161 -0
- package/dist/components/bb-timestamp.d.ts +15 -0
- package/dist/components/bb-timestamp.js +59 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.js +7 -0
- package/dist/const/styles.js +0 -33
- package/dist/contexts/author-context.d.ts +8 -0
- package/dist/contexts/author-context.js +6 -0
- package/dist/controllers/scroll-controller.d.ts +52 -0
- package/dist/controllers/scroll-controller.js +138 -0
- package/dist/core/renderer.js +1 -9
- package/dist/parsers/base.d.ts +21 -0
- package/dist/parsers/base.js +1 -0
- package/dist/parsers/default-parser.d.ts +10 -0
- package/dist/parsers/default-parser.js +40 -0
- package/dist/parsers/index.d.ts +2 -0
- package/dist/parsers/index.js +1 -0
- package/dist/utils/message-builder.d.ts +0 -4
- package/dist/utils/message-builder.js +0 -15
- package/dist/utils/tooltip.d.ts +11 -2
- package/dist/utils/tooltip.js +56 -13
- package/package.json +1 -1
- package/src/const/styles.ts +0 -33
- package/src/core/renderer.ts +1 -11
- package/src/utils/message-builder.ts +0 -15
- package/src/utils/tooltip.ts +0 -16
package/dist/utils/tooltip.js
CHANGED
|
@@ -1,17 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Tooltip utilities for avatar hover effects
|
|
3
|
+
*
|
|
4
|
+
* Tooltips use position: fixed to escape overflow clipping from scrollable containers.
|
|
5
|
+
* Position is calculated on mouseenter and updated on scroll to prevent staleness.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Position a tooltip relative to its avatar wrapper
|
|
9
|
+
* Centers horizontally and places above the avatar
|
|
10
|
+
*/
|
|
11
|
+
function positionTooltip(wrapper, tooltip) {
|
|
12
|
+
const rect = wrapper.getBoundingClientRect();
|
|
13
|
+
const tooltipRect = tooltip.getBoundingClientRect();
|
|
14
|
+
// Center horizontally relative to viewport
|
|
15
|
+
let left = rect.left + rect.width / 2 - tooltipRect.width / 2;
|
|
16
|
+
// Viewport boundary check - keep tooltip within viewport
|
|
17
|
+
const padding = 8;
|
|
18
|
+
left = Math.max(padding, Math.min(left, window.innerWidth - tooltipRect.width - padding));
|
|
19
|
+
// Position above avatar
|
|
20
|
+
const top = rect.top - tooltipRect.height - 8;
|
|
21
|
+
tooltip.style.left = `${left}px`;
|
|
22
|
+
tooltip.style.top = `${top}px`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Setup tooltip positioning for a single avatar wrapper element
|
|
26
|
+
*/
|
|
27
|
+
export function setupTooltipForElement(wrapper) {
|
|
28
|
+
const tooltip = wrapper.querySelector('.avatar-tooltip');
|
|
29
|
+
if (!tooltip)
|
|
30
|
+
return;
|
|
31
|
+
let scrollContainer = null;
|
|
32
|
+
const handleMouseEnter = () => {
|
|
33
|
+
// Find the scrollable container (if any)
|
|
34
|
+
scrollContainer = wrapper.closest('.history');
|
|
35
|
+
// Initial position
|
|
36
|
+
positionTooltip(wrapper, tooltip);
|
|
37
|
+
// Add scroll listener to update position during scroll
|
|
38
|
+
if (scrollContainer) {
|
|
39
|
+
scrollContainer.addEventListener('scroll', handleScroll, { passive: true });
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const handleMouseLeave = () => {
|
|
43
|
+
// Remove scroll listener when not hovering
|
|
44
|
+
if (scrollContainer) {
|
|
45
|
+
scrollContainer.removeEventListener('scroll', handleScroll);
|
|
46
|
+
scrollContainer = null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const handleScroll = () => {
|
|
50
|
+
positionTooltip(wrapper, tooltip);
|
|
51
|
+
};
|
|
52
|
+
wrapper.addEventListener('mouseenter', handleMouseEnter);
|
|
53
|
+
wrapper.addEventListener('mouseleave', handleMouseLeave);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Setup tooltips for all avatar wrappers in the shadow root
|
|
4
57
|
*/
|
|
5
58
|
export function setupTooltips(shadowRoot) {
|
|
6
|
-
shadowRoot.querySelectorAll('.avatar-wrapper').forEach(
|
|
7
|
-
wrapper.addEventListener('mouseenter', () => {
|
|
8
|
-
const tooltip = wrapper.querySelector('.avatar-tooltip');
|
|
9
|
-
if (!tooltip)
|
|
10
|
-
return;
|
|
11
|
-
const rect = wrapper.getBoundingClientRect();
|
|
12
|
-
const tooltipRect = tooltip.getBoundingClientRect();
|
|
13
|
-
tooltip.style.left = `${rect.left + rect.width / 2 - tooltipRect.width / 2}px`;
|
|
14
|
-
tooltip.style.top = `${rect.top - tooltipRect.height - 8}px`;
|
|
15
|
-
});
|
|
16
|
-
});
|
|
59
|
+
shadowRoot.querySelectorAll('.avatar-wrapper').forEach(setupTooltipForElement);
|
|
17
60
|
}
|
package/package.json
CHANGED
package/src/const/styles.ts
CHANGED
|
@@ -160,7 +160,6 @@ export const MAIN_STYLES = `
|
|
|
160
160
|
background: #ffffff;
|
|
161
161
|
border-radius: 50%;
|
|
162
162
|
overflow: hidden;
|
|
163
|
-
cursor: help;
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
.avatar-wrapper--hidden {
|
|
@@ -183,38 +182,6 @@ export const MAIN_STYLES = `
|
|
|
183
182
|
height: 100%;
|
|
184
183
|
}
|
|
185
184
|
|
|
186
|
-
/* Hover tooltip */
|
|
187
|
-
.avatar-tooltip {
|
|
188
|
-
position: fixed;
|
|
189
|
-
padding: 0.25rem 0.5rem;
|
|
190
|
-
background: ${THEME.gray[800]};
|
|
191
|
-
color: ${THEME.gray[50]};
|
|
192
|
-
font-size: 0.75rem;
|
|
193
|
-
border-radius: 0.25rem;
|
|
194
|
-
white-space: nowrap;
|
|
195
|
-
opacity: 0;
|
|
196
|
-
visibility: hidden;
|
|
197
|
-
pointer-events: none;
|
|
198
|
-
z-index: 10;
|
|
199
|
-
font-weight: 500;
|
|
200
|
-
letter-spacing: 0.02em;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
.avatar-tooltip::after {
|
|
204
|
-
content: '';
|
|
205
|
-
position: absolute;
|
|
206
|
-
top: calc(100% - 1px);
|
|
207
|
-
left: 50%;
|
|
208
|
-
transform: translateX(-50%);
|
|
209
|
-
border: 4px solid transparent;
|
|
210
|
-
border-top-color: ${THEME.gray[800]};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.avatar-wrapper:hover .avatar-tooltip {
|
|
214
|
-
opacity: 1;
|
|
215
|
-
visibility: visible;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
185
|
/* Message content area */
|
|
219
186
|
.msg-content {
|
|
220
187
|
display: flex;
|
package/src/core/renderer.ts
CHANGED
|
@@ -2,9 +2,8 @@ import type { AuthorOptions, Message } from '../types/index.js';
|
|
|
2
2
|
import type { ProcessedMessage } from './message-processor.js';
|
|
3
3
|
import { EMPTY_STYLES, LOADING_STYLES, MAIN_STYLES } from '../const/styles.js';
|
|
4
4
|
import { resolveAuthorConfig } from '../utils/author-resolver.js';
|
|
5
|
-
import { buildMessageRowHtml
|
|
5
|
+
import { buildMessageRowHtml } from '../utils/message-builder.js';
|
|
6
6
|
import { buildScrollButtonHtml } from '../utils/scroll-button.js';
|
|
7
|
-
import { setupTooltips } from '../utils/tooltip.js';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* State for incremental message appending
|
|
@@ -149,9 +148,6 @@ export class Renderer {
|
|
|
149
148
|
scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
150
149
|
}
|
|
151
150
|
|
|
152
|
-
// Re-setup tooltips for new content
|
|
153
|
-
setupTooltips(this.shadowRoot);
|
|
154
|
-
|
|
155
151
|
return { wasAtBottom };
|
|
156
152
|
}
|
|
157
153
|
|
|
@@ -205,12 +201,6 @@ export class Renderer {
|
|
|
205
201
|
|
|
206
202
|
container.insertAdjacentHTML('beforeend', msgHtml);
|
|
207
203
|
|
|
208
|
-
// Setup tooltip for new element
|
|
209
|
-
const newWrapper = container.lastElementChild?.querySelector('.avatar-wrapper');
|
|
210
|
-
if (newWrapper) {
|
|
211
|
-
setupTooltipForElement(newWrapper);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
204
|
return {
|
|
215
205
|
success: true,
|
|
216
206
|
lastAuthor: message.author,
|
|
@@ -10,7 +10,6 @@ export function buildAvatarHtml(author: string, config: AuthorConfig, showAvatar
|
|
|
10
10
|
<div class="avatar-wrapper ${showAvatar ? '' : 'avatar-wrapper--hidden'}"
|
|
11
11
|
data-author="${escapeHtml(author)}">
|
|
12
12
|
<div class="avatar">${config.avatar}</div>
|
|
13
|
-
<div class="avatar-tooltip">${escapeHtml(author)}</div>
|
|
14
13
|
</div>
|
|
15
14
|
`;
|
|
16
15
|
}
|
|
@@ -68,17 +67,3 @@ export function buildMessageRowHtml(
|
|
|
68
67
|
</div>
|
|
69
68
|
`;
|
|
70
69
|
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Setup tooltip for a single avatar wrapper element
|
|
74
|
-
*/
|
|
75
|
-
export function setupTooltipForElement(wrapper: Element): void {
|
|
76
|
-
wrapper.addEventListener('mouseenter', () => {
|
|
77
|
-
const tooltip = wrapper.querySelector('.avatar-tooltip') as HTMLElement;
|
|
78
|
-
if (!tooltip) return;
|
|
79
|
-
const rect = wrapper.getBoundingClientRect();
|
|
80
|
-
const tooltipRect = tooltip.getBoundingClientRect();
|
|
81
|
-
tooltip.style.left = `${rect.left + rect.width / 2 - tooltipRect.width / 2}px`;
|
|
82
|
-
tooltip.style.top = `${rect.top - tooltipRect.height - 8}px`;
|
|
83
|
-
});
|
|
84
|
-
}
|
package/src/utils/tooltip.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Setup dynamic tooltip positioning
|
|
3
|
-
* Tooltips are positioned fixed to avoid overflow clipping from parent containers
|
|
4
|
-
*/
|
|
5
|
-
export function setupTooltips(shadowRoot: ShadowRoot): void {
|
|
6
|
-
shadowRoot.querySelectorAll('.avatar-wrapper').forEach(wrapper => {
|
|
7
|
-
wrapper.addEventListener('mouseenter', () => {
|
|
8
|
-
const tooltip = wrapper.querySelector('.avatar-tooltip') as HTMLElement;
|
|
9
|
-
if (!tooltip) return;
|
|
10
|
-
const rect = wrapper.getBoundingClientRect();
|
|
11
|
-
const tooltipRect = tooltip.getBoundingClientRect();
|
|
12
|
-
tooltip.style.left = `${rect.left + rect.width / 2 - tooltipRect.width / 2}px`;
|
|
13
|
-
tooltip.style.top = `${rect.top - tooltipRect.height - 8}px`;
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
}
|