@pillar-ai/sdk 0.1.0 → 0.1.2
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/api/client.d.ts +0 -28
- package/dist/components/index.d.ts +0 -1
- package/dist/core/Pillar.d.ts +0 -13
- package/dist/core/config.d.ts +0 -8
- package/dist/core/events.d.ts +0 -9
- package/dist/index.d.ts +2 -2
- package/dist/pillar.esm.js +6 -782
- package/dist/pillar.js +6 -782
- package/dist/store/index.d.ts +0 -1
- package/package.json +5 -12
- package/dist/pillar.esm.js.map +0 -1
- package/dist/pillar.js.map +0 -1
- package/dist/pillar.min.js +0 -2
- package/dist/pillar.min.js.map +0 -1
package/dist/pillar.esm.js
CHANGED
|
@@ -737,13 +737,6 @@ class APIClient {
|
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
// ============================================================================
|
|
740
|
-
// Tooltips
|
|
741
|
-
// ============================================================================
|
|
742
|
-
async getTooltips(ids) {
|
|
743
|
-
const params = ids?.length ? `?ids=${ids.join(',')}` : '';
|
|
744
|
-
return this.fetch(`/sdk/tooltips/${params}`);
|
|
745
|
-
}
|
|
746
|
-
// ============================================================================
|
|
747
740
|
// Suggested Questions
|
|
748
741
|
// ============================================================================
|
|
749
742
|
/**
|
|
@@ -1672,7 +1665,7 @@ class EdgeTrigger {
|
|
|
1672
1665
|
}
|
|
1673
1666
|
|
|
1674
1667
|
const HELP_ICON = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>`;
|
|
1675
|
-
const CLOSE_ICON$
|
|
1668
|
+
const CLOSE_ICON$2 = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`;
|
|
1676
1669
|
const FLOATING_BUTTON_STYLES = `
|
|
1677
1670
|
.pillar-floating-button {
|
|
1678
1671
|
position: fixed;
|
|
@@ -1776,7 +1769,7 @@ function FloatingButtonContent({ position, label, onClick, panelOpen, }) {
|
|
|
1776
1769
|
onClick();
|
|
1777
1770
|
}, [onClick]);
|
|
1778
1771
|
const isIconOnly = !label;
|
|
1779
|
-
const icon = panelOpen ? CLOSE_ICON$
|
|
1772
|
+
const icon = panelOpen ? CLOSE_ICON$2 : HELP_ICON;
|
|
1780
1773
|
const className = [
|
|
1781
1774
|
'pillar-floating-button',
|
|
1782
1775
|
`pillar-floating-button--${position}`,
|
|
@@ -3332,7 +3325,7 @@ const PLAN_STYLES = `
|
|
|
3332
3325
|
|
|
3333
3326
|
const BACK_ICON = `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd"/></svg>`;
|
|
3334
3327
|
const HOME_ICON = `<svg viewBox="0 0 20 20" fill="currentColor"><path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"/></svg>`;
|
|
3335
|
-
const CLOSE_ICON$
|
|
3328
|
+
const CLOSE_ICON$1 = `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/></svg>`;
|
|
3336
3329
|
const VIEW_TITLES = {
|
|
3337
3330
|
home: 'Assistant',
|
|
3338
3331
|
chat: 'Assistant',
|
|
@@ -3350,11 +3343,11 @@ function Header({ currentView, customTitle, hideNavigation = false }) {
|
|
|
3350
3343
|
const handleClose = () => {
|
|
3351
3344
|
closePanel();
|
|
3352
3345
|
};
|
|
3353
|
-
return (u$2("header", { class: "_pillar-header pillar-header", children: [u$2("div", { class: "_pillar-header-left pillar-header-left", children: [showBack && (u$2("button", { class: "_pillar-icon-btn pillar-icon-btn pillar-back-btn", onClick: handleBack, "aria-label": "Go back", type: "button", dangerouslySetInnerHTML: { __html: BACK_ICON } })), showHome && (u$2("button", { class: "_pillar-icon-btn pillar-icon-btn pillar-home-btn", onClick: handleHome, "aria-label": "Go to home", type: "button", dangerouslySetInnerHTML: { __html: HOME_ICON } })), u$2("span", { class: "_pillar-header-title pillar-header-title", children: title })] }), u$2("button", { class: "_pillar-icon-btn pillar-icon-btn pillar-close-btn", onClick: handleClose, "aria-label": "Close assistant panel", type: "button", dangerouslySetInnerHTML: { __html: CLOSE_ICON$
|
|
3346
|
+
return (u$2("header", { class: "_pillar-header pillar-header", children: [u$2("div", { class: "_pillar-header-left pillar-header-left", children: [showBack && (u$2("button", { class: "_pillar-icon-btn pillar-icon-btn pillar-back-btn", onClick: handleBack, "aria-label": "Go back", type: "button", dangerouslySetInnerHTML: { __html: BACK_ICON } })), showHome && (u$2("button", { class: "_pillar-icon-btn pillar-icon-btn pillar-home-btn", onClick: handleHome, "aria-label": "Go to home", type: "button", dangerouslySetInnerHTML: { __html: HOME_ICON } })), u$2("span", { class: "_pillar-header-title pillar-header-title", children: title })] }), u$2("button", { class: "_pillar-icon-btn pillar-icon-btn pillar-close-btn", onClick: handleClose, "aria-label": "Close assistant panel", type: "button", dangerouslySetInnerHTML: { __html: CLOSE_ICON$1 } })] }));
|
|
3354
3347
|
}
|
|
3355
3348
|
|
|
3356
3349
|
// Close icon SVG
|
|
3357
|
-
const CLOSE_ICON
|
|
3350
|
+
const CLOSE_ICON = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`;
|
|
3358
3351
|
// Quote icon for highlighted text
|
|
3359
3352
|
const QUOTE_ICON = `<svg viewBox="0 0 24 24" fill="currentColor"><path d="M4.583 17.321C3.553 16.227 3 15 3 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 01-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179zm10 0C13.553 16.227 13 15 13 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 01-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179z"/></svg>`;
|
|
3360
3353
|
/**
|
|
@@ -3386,7 +3379,7 @@ function ContextTag({ context, onRemove, readOnly = false }) {
|
|
|
3386
3379
|
e.stopPropagation();
|
|
3387
3380
|
onRemove?.(context.id);
|
|
3388
3381
|
};
|
|
3389
|
-
return (u$2("div", { class: "_pillar-context-tag pillar-context-tag", title: tooltip, children: [u$2("span", { class: "_pillar-context-tag-icon pillar-context-tag-icon", dangerouslySetInnerHTML: { __html: icon } }), u$2("span", { class: "_pillar-context-tag-label pillar-context-tag-label", children: label }), !readOnly && onRemove && (u$2("button", { class: "_pillar-context-tag-remove pillar-context-tag-remove", onClick: handleRemove, "aria-label": "Remove context", type: "button", dangerouslySetInnerHTML: { __html: CLOSE_ICON
|
|
3382
|
+
return (u$2("div", { class: "_pillar-context-tag pillar-context-tag", title: tooltip, children: [u$2("span", { class: "_pillar-context-tag-icon pillar-context-tag-icon", dangerouslySetInnerHTML: { __html: icon } }), u$2("span", { class: "_pillar-context-tag-label pillar-context-tag-label", children: label }), !readOnly && onRemove && (u$2("button", { class: "_pillar-context-tag-remove pillar-context-tag-remove", onClick: handleRemove, "aria-label": "Remove context", type: "button", dangerouslySetInnerHTML: { __html: CLOSE_ICON } }))] }));
|
|
3390
3383
|
}
|
|
3391
3384
|
function ContextTagList({ contexts, onRemove, readOnly = false }) {
|
|
3392
3385
|
if (contexts.length === 0) {
|
|
@@ -7515,741 +7508,6 @@ class TextSelectionManager {
|
|
|
7515
7508
|
}
|
|
7516
7509
|
}
|
|
7517
7510
|
|
|
7518
|
-
/**
|
|
7519
|
-
* Positioning utilities for tooltips and floating elements
|
|
7520
|
-
*/
|
|
7521
|
-
/**
|
|
7522
|
-
* Gets the bounding rect of an element
|
|
7523
|
-
*/
|
|
7524
|
-
function getElementRect(element) {
|
|
7525
|
-
const rect = element.getBoundingClientRect();
|
|
7526
|
-
return {
|
|
7527
|
-
x: rect.left + window.scrollX,
|
|
7528
|
-
y: rect.top + window.scrollY,
|
|
7529
|
-
width: rect.width,
|
|
7530
|
-
height: rect.height,
|
|
7531
|
-
};
|
|
7532
|
-
}
|
|
7533
|
-
/**
|
|
7534
|
-
* Gets the viewport rect
|
|
7535
|
-
*/
|
|
7536
|
-
function getViewportRect() {
|
|
7537
|
-
return {
|
|
7538
|
-
x: window.scrollX,
|
|
7539
|
-
y: window.scrollY,
|
|
7540
|
-
width: window.innerWidth,
|
|
7541
|
-
height: window.innerHeight,
|
|
7542
|
-
};
|
|
7543
|
-
}
|
|
7544
|
-
/**
|
|
7545
|
-
* Calculates available space in each direction from an element
|
|
7546
|
-
*/
|
|
7547
|
-
function getAvailableSpace(anchor, viewport, padding = 8) {
|
|
7548
|
-
return {
|
|
7549
|
-
top: anchor.y - viewport.y - padding,
|
|
7550
|
-
bottom: viewport.y + viewport.height - (anchor.y + anchor.height) - padding,
|
|
7551
|
-
left: anchor.x - viewport.x - padding,
|
|
7552
|
-
right: viewport.x + viewport.width - (anchor.x + anchor.width) - padding,
|
|
7553
|
-
auto: 0, // Not used for space calculation
|
|
7554
|
-
};
|
|
7555
|
-
}
|
|
7556
|
-
/**
|
|
7557
|
-
* Determines the best position for a floating element
|
|
7558
|
-
*/
|
|
7559
|
-
function getBestPosition(anchor, floating, options) {
|
|
7560
|
-
if (options.position !== 'auto') {
|
|
7561
|
-
return options.position;
|
|
7562
|
-
}
|
|
7563
|
-
const viewport = getViewportRect();
|
|
7564
|
-
const space = getAvailableSpace(anchor, viewport, options.padding);
|
|
7565
|
-
const offset = options.offset || 8;
|
|
7566
|
-
// Check if each position has enough space
|
|
7567
|
-
const fits = {
|
|
7568
|
-
top: space.top >= floating.height + offset,
|
|
7569
|
-
bottom: space.bottom >= floating.height + offset,
|
|
7570
|
-
left: space.left >= floating.width + offset,
|
|
7571
|
-
right: space.right >= floating.width + offset,
|
|
7572
|
-
};
|
|
7573
|
-
// Priority: bottom, top, right, left
|
|
7574
|
-
if (fits.bottom)
|
|
7575
|
-
return 'bottom';
|
|
7576
|
-
if (fits.top)
|
|
7577
|
-
return 'top';
|
|
7578
|
-
if (fits.right)
|
|
7579
|
-
return 'right';
|
|
7580
|
-
if (fits.left)
|
|
7581
|
-
return 'left';
|
|
7582
|
-
// If nothing fits, use the position with most space
|
|
7583
|
-
const sorted = Object.entries(space)
|
|
7584
|
-
.filter(([key]) => key !== 'auto')
|
|
7585
|
-
.sort(([, a], [, b]) => b - a);
|
|
7586
|
-
return sorted[0][0];
|
|
7587
|
-
}
|
|
7588
|
-
/**
|
|
7589
|
-
* Calculates the position of a floating element relative to an anchor
|
|
7590
|
-
*/
|
|
7591
|
-
function calculatePosition(anchor, floating, options) {
|
|
7592
|
-
const { alignment = 'center', offset = 8, padding = 8, arrowSize = 8, } = options;
|
|
7593
|
-
const viewport = getViewportRect();
|
|
7594
|
-
const position = getBestPosition(anchor, floating, options);
|
|
7595
|
-
let x = 0;
|
|
7596
|
-
let y = 0;
|
|
7597
|
-
let arrowX;
|
|
7598
|
-
let arrowY;
|
|
7599
|
-
// Calculate base position
|
|
7600
|
-
switch (position) {
|
|
7601
|
-
case 'top':
|
|
7602
|
-
y = anchor.y - floating.height - offset;
|
|
7603
|
-
x = getAlignedX(anchor, floating, alignment);
|
|
7604
|
-
arrowX = anchor.x + anchor.width / 2 - arrowSize / 2;
|
|
7605
|
-
break;
|
|
7606
|
-
case 'bottom':
|
|
7607
|
-
y = anchor.y + anchor.height + offset;
|
|
7608
|
-
x = getAlignedX(anchor, floating, alignment);
|
|
7609
|
-
arrowX = anchor.x + anchor.width / 2 - arrowSize / 2;
|
|
7610
|
-
break;
|
|
7611
|
-
case 'left':
|
|
7612
|
-
x = anchor.x - floating.width - offset;
|
|
7613
|
-
y = getAlignedY(anchor, floating, alignment);
|
|
7614
|
-
arrowY = anchor.y + anchor.height / 2 - arrowSize / 2;
|
|
7615
|
-
break;
|
|
7616
|
-
case 'right':
|
|
7617
|
-
x = anchor.x + anchor.width + offset;
|
|
7618
|
-
y = getAlignedY(anchor, floating, alignment);
|
|
7619
|
-
arrowY = anchor.y + anchor.height / 2 - arrowSize / 2;
|
|
7620
|
-
break;
|
|
7621
|
-
}
|
|
7622
|
-
// Constrain to viewport
|
|
7623
|
-
x = Math.max(viewport.x + padding, Math.min(x, viewport.x + viewport.width - floating.width - padding));
|
|
7624
|
-
y = Math.max(viewport.y + padding, Math.min(y, viewport.y + viewport.height - floating.height - padding));
|
|
7625
|
-
// Adjust arrow position relative to constrained floating element
|
|
7626
|
-
if (arrowX !== undefined) {
|
|
7627
|
-
arrowX = Math.max(x + arrowSize, Math.min(arrowX, x + floating.width - arrowSize * 2));
|
|
7628
|
-
arrowX -= x; // Make relative to floating element
|
|
7629
|
-
}
|
|
7630
|
-
if (arrowY !== undefined) {
|
|
7631
|
-
arrowY = Math.max(y + arrowSize, Math.min(arrowY, y + floating.height - arrowSize * 2));
|
|
7632
|
-
arrowY -= y; // Make relative to floating element
|
|
7633
|
-
}
|
|
7634
|
-
return { x, y, position, arrowX, arrowY };
|
|
7635
|
-
}
|
|
7636
|
-
function getAlignedX(anchor, floating, alignment) {
|
|
7637
|
-
switch (alignment) {
|
|
7638
|
-
case 'start':
|
|
7639
|
-
return anchor.x;
|
|
7640
|
-
case 'end':
|
|
7641
|
-
return anchor.x + anchor.width - floating.width;
|
|
7642
|
-
case 'center':
|
|
7643
|
-
default:
|
|
7644
|
-
return anchor.x + anchor.width / 2 - floating.width / 2;
|
|
7645
|
-
}
|
|
7646
|
-
}
|
|
7647
|
-
function getAlignedY(anchor, floating, alignment) {
|
|
7648
|
-
switch (alignment) {
|
|
7649
|
-
case 'start':
|
|
7650
|
-
return anchor.y;
|
|
7651
|
-
case 'end':
|
|
7652
|
-
return anchor.y + anchor.height - floating.height;
|
|
7653
|
-
case 'center':
|
|
7654
|
-
default:
|
|
7655
|
-
return anchor.y + anchor.height / 2 - floating.height / 2;
|
|
7656
|
-
}
|
|
7657
|
-
}
|
|
7658
|
-
|
|
7659
|
-
const ARROW_ICON = `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>`;
|
|
7660
|
-
const INFO_ICON = `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path></svg>`;
|
|
7661
|
-
const CLOSE_ICON = `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>`;
|
|
7662
|
-
function TooltipContent({ data, anchor, trigger, position: preferredPosition, isVisible, onLearnMore, onHide, onMouseEnter, onMouseLeave, }) {
|
|
7663
|
-
const tooltipRef = A(null);
|
|
7664
|
-
const arrowRef = A(null);
|
|
7665
|
-
const [positionClass, setPositionClass] = d$3(preferredPosition);
|
|
7666
|
-
const [style, setStyle] = d$3({ left: 0, top: 0 });
|
|
7667
|
-
const [arrowStyle, setArrowStyle] = d$3({});
|
|
7668
|
-
const updatePosition = q$1(() => {
|
|
7669
|
-
if (!tooltipRef.current || !isVisible)
|
|
7670
|
-
return;
|
|
7671
|
-
const anchorRect = getElementRect(anchor);
|
|
7672
|
-
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
7673
|
-
const result = calculatePosition(anchorRect, { width: tooltipRect.width, height: tooltipRect.height }, {
|
|
7674
|
-
position: preferredPosition,
|
|
7675
|
-
offset: 10,
|
|
7676
|
-
arrowSize: 12,
|
|
7677
|
-
});
|
|
7678
|
-
setStyle({ left: result.x, top: result.y });
|
|
7679
|
-
setPositionClass(result.position);
|
|
7680
|
-
if (result.arrowX !== undefined) {
|
|
7681
|
-
setArrowStyle({ left: result.arrowX });
|
|
7682
|
-
}
|
|
7683
|
-
if (result.arrowY !== undefined) {
|
|
7684
|
-
setArrowStyle({ top: result.arrowY });
|
|
7685
|
-
}
|
|
7686
|
-
}, [anchor, preferredPosition, isVisible]);
|
|
7687
|
-
y$2(() => {
|
|
7688
|
-
if (isVisible) {
|
|
7689
|
-
// Initial position calculation
|
|
7690
|
-
requestAnimationFrame(updatePosition);
|
|
7691
|
-
// Update on scroll/resize
|
|
7692
|
-
window.addEventListener('scroll', updatePosition, true);
|
|
7693
|
-
window.addEventListener('resize', updatePosition);
|
|
7694
|
-
return () => {
|
|
7695
|
-
window.removeEventListener('scroll', updatePosition, true);
|
|
7696
|
-
window.removeEventListener('resize', updatePosition);
|
|
7697
|
-
};
|
|
7698
|
-
}
|
|
7699
|
-
}, [isVisible, updatePosition]);
|
|
7700
|
-
const handleLearnMore = (e) => {
|
|
7701
|
-
e.stopPropagation();
|
|
7702
|
-
if (data.article_slug) {
|
|
7703
|
-
onLearnMore?.(data.article_slug);
|
|
7704
|
-
}
|
|
7705
|
-
};
|
|
7706
|
-
const handleClose = (e) => {
|
|
7707
|
-
e.stopPropagation();
|
|
7708
|
-
onHide();
|
|
7709
|
-
};
|
|
7710
|
-
const className = `pillar-tooltip pillar-tooltip--${positionClass}${isVisible ? ' pillar-tooltip--visible' : ''}`;
|
|
7711
|
-
return (u$2("div", { ref: tooltipRef, class: className, role: "tooltip", style: {
|
|
7712
|
-
left: `${style.left}px`,
|
|
7713
|
-
top: `${style.top}px`,
|
|
7714
|
-
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: [u$2("div", { class: "pillar-tooltip__content", dangerouslySetInnerHTML: { __html: data.content_html || data.content } }), data.show_learn_more && data.article_slug && (u$2("button", { class: "pillar-tooltip__learn-more", onClick: handleLearnMore, type: "button", children: [data.article_title || 'Learn more', u$2("span", { dangerouslySetInnerHTML: { __html: ARROW_ICON } })] })), trigger === 'click' && (u$2("button", { class: "pillar-tooltip__close", onClick: handleClose, "aria-label": "Close tooltip", type: "button", dangerouslySetInnerHTML: { __html: CLOSE_ICON } })), u$2("div", { ref: arrowRef, class: "pillar-tooltip__arrow", style: arrowStyle })] }));
|
|
7715
|
-
}
|
|
7716
|
-
/**
|
|
7717
|
-
* Tooltip class that manages a single tooltip instance
|
|
7718
|
-
* Uses Preact for rendering but maintains imperative control
|
|
7719
|
-
*/
|
|
7720
|
-
class Tooltip {
|
|
7721
|
-
constructor(data, anchor, options) {
|
|
7722
|
-
this.container = null;
|
|
7723
|
-
this.iconElement = null;
|
|
7724
|
-
this.isVisible = false;
|
|
7725
|
-
this.hideTimeout = null;
|
|
7726
|
-
this.handleMouseEnter = () => {
|
|
7727
|
-
if (this.hideTimeout) {
|
|
7728
|
-
clearTimeout(this.hideTimeout);
|
|
7729
|
-
this.hideTimeout = null;
|
|
7730
|
-
}
|
|
7731
|
-
this.show();
|
|
7732
|
-
};
|
|
7733
|
-
this.handleMouseLeave = () => {
|
|
7734
|
-
// Delay hide to allow moving to tooltip
|
|
7735
|
-
this.hideTimeout = setTimeout(() => this.hide(), 100);
|
|
7736
|
-
};
|
|
7737
|
-
// Handler for when mouse enters the tooltip element itself
|
|
7738
|
-
this.handleTooltipMouseEnter = () => {
|
|
7739
|
-
if (this.hideTimeout) {
|
|
7740
|
-
clearTimeout(this.hideTimeout);
|
|
7741
|
-
this.hideTimeout = null;
|
|
7742
|
-
}
|
|
7743
|
-
};
|
|
7744
|
-
// Handler for when mouse leaves the tooltip element
|
|
7745
|
-
this.handleTooltipMouseLeave = () => {
|
|
7746
|
-
// Delay hide to allow moving back to anchor
|
|
7747
|
-
this.hideTimeout = setTimeout(() => this.hide(), 100);
|
|
7748
|
-
};
|
|
7749
|
-
this.handleClick = (e) => {
|
|
7750
|
-
e.stopPropagation();
|
|
7751
|
-
this.toggle();
|
|
7752
|
-
};
|
|
7753
|
-
this.handleDocumentClick = () => {
|
|
7754
|
-
if (this.isVisible) {
|
|
7755
|
-
this.hide();
|
|
7756
|
-
}
|
|
7757
|
-
};
|
|
7758
|
-
this.handleFocus = () => {
|
|
7759
|
-
this.show();
|
|
7760
|
-
};
|
|
7761
|
-
this.handleBlur = () => {
|
|
7762
|
-
this.hide();
|
|
7763
|
-
};
|
|
7764
|
-
this.handleKeyDown = (e) => {
|
|
7765
|
-
if (e.key === 'Escape' && this.isVisible) {
|
|
7766
|
-
this.hide();
|
|
7767
|
-
}
|
|
7768
|
-
};
|
|
7769
|
-
this.id = `tooltip-${Math.random().toString(36).slice(2, 9)}`;
|
|
7770
|
-
this.data = data;
|
|
7771
|
-
this.anchor = anchor;
|
|
7772
|
-
this.options = options;
|
|
7773
|
-
}
|
|
7774
|
-
init() {
|
|
7775
|
-
// Create container for portal rendering
|
|
7776
|
-
this.container = document.createElement('div');
|
|
7777
|
-
this.container.id = this.id;
|
|
7778
|
-
document.body.appendChild(this.container);
|
|
7779
|
-
// Add icon if trigger is 'icon'
|
|
7780
|
-
if (this.options.trigger === 'icon') {
|
|
7781
|
-
this.createIcon();
|
|
7782
|
-
}
|
|
7783
|
-
// Bind events
|
|
7784
|
-
this.bindEvents();
|
|
7785
|
-
}
|
|
7786
|
-
show() {
|
|
7787
|
-
if (this.isVisible)
|
|
7788
|
-
return;
|
|
7789
|
-
if (this.hideTimeout) {
|
|
7790
|
-
clearTimeout(this.hideTimeout);
|
|
7791
|
-
this.hideTimeout = null;
|
|
7792
|
-
}
|
|
7793
|
-
this.isVisible = true;
|
|
7794
|
-
this.renderTooltip();
|
|
7795
|
-
this.options.onShow?.();
|
|
7796
|
-
}
|
|
7797
|
-
hide() {
|
|
7798
|
-
if (!this.isVisible)
|
|
7799
|
-
return;
|
|
7800
|
-
this.isVisible = false;
|
|
7801
|
-
this.renderTooltip();
|
|
7802
|
-
// Remove from DOM after animation
|
|
7803
|
-
this.hideTimeout = setTimeout(() => {
|
|
7804
|
-
this.options.onHide?.();
|
|
7805
|
-
}, 150);
|
|
7806
|
-
}
|
|
7807
|
-
toggle() {
|
|
7808
|
-
if (this.isVisible) {
|
|
7809
|
-
this.hide();
|
|
7810
|
-
}
|
|
7811
|
-
else {
|
|
7812
|
-
this.show();
|
|
7813
|
-
}
|
|
7814
|
-
}
|
|
7815
|
-
destroy() {
|
|
7816
|
-
if (this.hideTimeout) {
|
|
7817
|
-
clearTimeout(this.hideTimeout);
|
|
7818
|
-
}
|
|
7819
|
-
this.unbindEvents();
|
|
7820
|
-
// Unmount Preact component
|
|
7821
|
-
if (this.container) {
|
|
7822
|
-
G$1(null, this.container);
|
|
7823
|
-
this.container.remove();
|
|
7824
|
-
}
|
|
7825
|
-
this.iconElement?.remove();
|
|
7826
|
-
this.container = null;
|
|
7827
|
-
this.iconElement = null;
|
|
7828
|
-
}
|
|
7829
|
-
// ============================================================================
|
|
7830
|
-
// Private Methods
|
|
7831
|
-
// ============================================================================
|
|
7832
|
-
renderTooltip() {
|
|
7833
|
-
if (!this.container)
|
|
7834
|
-
return;
|
|
7835
|
-
// Only pass hover handlers if trigger is 'hover'
|
|
7836
|
-
const hoverHandlers = this.options.trigger === 'hover'
|
|
7837
|
-
? {
|
|
7838
|
-
onMouseEnter: this.handleTooltipMouseEnter,
|
|
7839
|
-
onMouseLeave: this.handleTooltipMouseLeave,
|
|
7840
|
-
}
|
|
7841
|
-
: {};
|
|
7842
|
-
G$1(u$2(TooltipContent, { data: this.data, anchor: this.anchor, trigger: this.options.trigger, position: this.options.position, isVisible: this.isVisible, onLearnMore: this.options.onLearnMore, onHide: () => this.hide(), ...hoverHandlers }), this.container);
|
|
7843
|
-
}
|
|
7844
|
-
createIcon() {
|
|
7845
|
-
const icon = document.createElement('span');
|
|
7846
|
-
icon.className = 'pillar-tooltip-icon';
|
|
7847
|
-
icon.innerHTML = INFO_ICON;
|
|
7848
|
-
icon.setAttribute('aria-label', 'More information');
|
|
7849
|
-
icon.setAttribute('role', 'button');
|
|
7850
|
-
icon.setAttribute('tabindex', '0');
|
|
7851
|
-
this.anchor.insertAdjacentElement('afterend', icon);
|
|
7852
|
-
this.iconElement = icon;
|
|
7853
|
-
}
|
|
7854
|
-
bindEvents() {
|
|
7855
|
-
const target = this.options.trigger === 'icon' ? this.iconElement : this.anchor;
|
|
7856
|
-
if (!target)
|
|
7857
|
-
return;
|
|
7858
|
-
switch (this.options.trigger) {
|
|
7859
|
-
case 'hover':
|
|
7860
|
-
target.addEventListener('mouseenter', this.handleMouseEnter);
|
|
7861
|
-
target.addEventListener('mouseleave', this.handleMouseLeave);
|
|
7862
|
-
break;
|
|
7863
|
-
case 'click':
|
|
7864
|
-
case 'icon':
|
|
7865
|
-
target.addEventListener('click', this.handleClick);
|
|
7866
|
-
document.addEventListener('click', this.handleDocumentClick);
|
|
7867
|
-
break;
|
|
7868
|
-
case 'focus':
|
|
7869
|
-
target.addEventListener('focus', this.handleFocus);
|
|
7870
|
-
target.addEventListener('blur', this.handleBlur);
|
|
7871
|
-
break;
|
|
7872
|
-
}
|
|
7873
|
-
document.addEventListener('keydown', this.handleKeyDown);
|
|
7874
|
-
}
|
|
7875
|
-
unbindEvents() {
|
|
7876
|
-
const target = this.options.trigger === 'icon' ? this.iconElement : this.anchor;
|
|
7877
|
-
if (!target)
|
|
7878
|
-
return;
|
|
7879
|
-
target.removeEventListener('mouseenter', this.handleMouseEnter);
|
|
7880
|
-
target.removeEventListener('mouseleave', this.handleMouseLeave);
|
|
7881
|
-
target.removeEventListener('click', this.handleClick);
|
|
7882
|
-
target.removeEventListener('focus', this.handleFocus);
|
|
7883
|
-
target.removeEventListener('blur', this.handleBlur);
|
|
7884
|
-
document.removeEventListener('click', this.handleDocumentClick);
|
|
7885
|
-
document.removeEventListener('keydown', this.handleKeyDown);
|
|
7886
|
-
}
|
|
7887
|
-
}
|
|
7888
|
-
|
|
7889
|
-
/**
|
|
7890
|
-
* Tooltip CSS Styles
|
|
7891
|
-
* Injected into the document head
|
|
7892
|
-
*/
|
|
7893
|
-
const TOOLTIP_STYLES = `
|
|
7894
|
-
/* Pillar Tooltip Styles */
|
|
7895
|
-
.pillar-tooltip {
|
|
7896
|
-
position: absolute;
|
|
7897
|
-
z-index: 99999;
|
|
7898
|
-
max-width: 320px;
|
|
7899
|
-
padding: 12px 16px;
|
|
7900
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
7901
|
-
font-size: 14px;
|
|
7902
|
-
line-height: 1.5;
|
|
7903
|
-
color: #1a1a1a;
|
|
7904
|
-
background: #ffffff;
|
|
7905
|
-
border-radius: 8px;
|
|
7906
|
-
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
7907
|
-
pointer-events: auto;
|
|
7908
|
-
opacity: 0;
|
|
7909
|
-
transform: scale(0.95);
|
|
7910
|
-
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
7911
|
-
}
|
|
7912
|
-
|
|
7913
|
-
.pillar-tooltip.pillar-tooltip--visible {
|
|
7914
|
-
opacity: 1;
|
|
7915
|
-
transform: scale(1);
|
|
7916
|
-
}
|
|
7917
|
-
|
|
7918
|
-
.pillar-tooltip__content {
|
|
7919
|
-
margin: 0;
|
|
7920
|
-
}
|
|
7921
|
-
|
|
7922
|
-
.pillar-tooltip__content p {
|
|
7923
|
-
margin: 0 0 8px;
|
|
7924
|
-
}
|
|
7925
|
-
|
|
7926
|
-
.pillar-tooltip__content p:last-child {
|
|
7927
|
-
margin-bottom: 0;
|
|
7928
|
-
}
|
|
7929
|
-
|
|
7930
|
-
.pillar-tooltip__content a {
|
|
7931
|
-
color: #2563eb;
|
|
7932
|
-
text-decoration: none;
|
|
7933
|
-
}
|
|
7934
|
-
|
|
7935
|
-
.pillar-tooltip__content a:hover {
|
|
7936
|
-
text-decoration: underline;
|
|
7937
|
-
}
|
|
7938
|
-
|
|
7939
|
-
.pillar-tooltip__learn-more {
|
|
7940
|
-
display: inline-flex;
|
|
7941
|
-
align-items: center;
|
|
7942
|
-
gap: 4px;
|
|
7943
|
-
margin-top: 12px;
|
|
7944
|
-
padding: 6px 12px;
|
|
7945
|
-
font-size: 13px;
|
|
7946
|
-
font-weight: 500;
|
|
7947
|
-
color: #2563eb;
|
|
7948
|
-
background: #eff6ff;
|
|
7949
|
-
border: none;
|
|
7950
|
-
border-radius: 6px;
|
|
7951
|
-
cursor: pointer;
|
|
7952
|
-
transition: background 0.15s ease;
|
|
7953
|
-
}
|
|
7954
|
-
|
|
7955
|
-
.pillar-tooltip__learn-more:hover {
|
|
7956
|
-
background: #dbeafe;
|
|
7957
|
-
}
|
|
7958
|
-
|
|
7959
|
-
.pillar-tooltip__learn-more svg {
|
|
7960
|
-
width: 14px;
|
|
7961
|
-
height: 14px;
|
|
7962
|
-
}
|
|
7963
|
-
|
|
7964
|
-
/* Arrow */
|
|
7965
|
-
.pillar-tooltip__arrow {
|
|
7966
|
-
position: absolute;
|
|
7967
|
-
width: 12px;
|
|
7968
|
-
height: 12px;
|
|
7969
|
-
background: #ffffff;
|
|
7970
|
-
transform: rotate(45deg);
|
|
7971
|
-
box-shadow: -1px -1px 0 0 rgba(0, 0, 0, 0.05);
|
|
7972
|
-
}
|
|
7973
|
-
|
|
7974
|
-
.pillar-tooltip--top .pillar-tooltip__arrow {
|
|
7975
|
-
bottom: -6px;
|
|
7976
|
-
box-shadow: 1px 1px 0 0 rgba(0, 0, 0, 0.05);
|
|
7977
|
-
}
|
|
7978
|
-
|
|
7979
|
-
.pillar-tooltip--bottom .pillar-tooltip__arrow {
|
|
7980
|
-
top: -6px;
|
|
7981
|
-
}
|
|
7982
|
-
|
|
7983
|
-
.pillar-tooltip--left .pillar-tooltip__arrow {
|
|
7984
|
-
right: -6px;
|
|
7985
|
-
box-shadow: 1px -1px 0 0 rgba(0, 0, 0, 0.05);
|
|
7986
|
-
}
|
|
7987
|
-
|
|
7988
|
-
.pillar-tooltip--right .pillar-tooltip__arrow {
|
|
7989
|
-
left: -6px;
|
|
7990
|
-
box-shadow: -1px 1px 0 0 rgba(0, 0, 0, 0.05);
|
|
7991
|
-
}
|
|
7992
|
-
|
|
7993
|
-
/* Tooltip Icon (for icon trigger) */
|
|
7994
|
-
.pillar-tooltip-icon {
|
|
7995
|
-
display: inline-flex;
|
|
7996
|
-
align-items: center;
|
|
7997
|
-
justify-content: center;
|
|
7998
|
-
width: 16px;
|
|
7999
|
-
height: 16px;
|
|
8000
|
-
margin-left: 4px;
|
|
8001
|
-
vertical-align: middle;
|
|
8002
|
-
color: #6b7280;
|
|
8003
|
-
cursor: help;
|
|
8004
|
-
transition: color 0.15s ease;
|
|
8005
|
-
}
|
|
8006
|
-
|
|
8007
|
-
.pillar-tooltip-icon:hover {
|
|
8008
|
-
color: #2563eb;
|
|
8009
|
-
}
|
|
8010
|
-
|
|
8011
|
-
.pillar-tooltip-icon svg {
|
|
8012
|
-
width: 100%;
|
|
8013
|
-
height: 100%;
|
|
8014
|
-
}
|
|
8015
|
-
|
|
8016
|
-
/* Close button */
|
|
8017
|
-
.pillar-tooltip__close {
|
|
8018
|
-
position: absolute;
|
|
8019
|
-
top: 8px;
|
|
8020
|
-
right: 8px;
|
|
8021
|
-
display: flex;
|
|
8022
|
-
align-items: center;
|
|
8023
|
-
justify-content: center;
|
|
8024
|
-
width: 20px;
|
|
8025
|
-
height: 20px;
|
|
8026
|
-
padding: 0;
|
|
8027
|
-
color: #9ca3af;
|
|
8028
|
-
background: none;
|
|
8029
|
-
border: none;
|
|
8030
|
-
border-radius: 4px;
|
|
8031
|
-
cursor: pointer;
|
|
8032
|
-
transition: color 0.15s ease, background 0.15s ease;
|
|
8033
|
-
}
|
|
8034
|
-
|
|
8035
|
-
.pillar-tooltip__close:hover {
|
|
8036
|
-
color: #1a1a1a;
|
|
8037
|
-
background: #f3f4f6;
|
|
8038
|
-
}
|
|
8039
|
-
|
|
8040
|
-
.pillar-tooltip__close svg {
|
|
8041
|
-
width: 12px;
|
|
8042
|
-
height: 12px;
|
|
8043
|
-
}
|
|
8044
|
-
`;
|
|
8045
|
-
|
|
8046
|
-
/**
|
|
8047
|
-
* Tooltip Manager
|
|
8048
|
-
* Scans DOM for tooltip elements and manages their lifecycle
|
|
8049
|
-
*/
|
|
8050
|
-
const TOOLTIP_ATTRIBUTE = 'data-pillar-tooltip';
|
|
8051
|
-
const TOOLTIP_TRIGGER_ATTR = 'data-pillar-trigger';
|
|
8052
|
-
const TOOLTIP_POSITION_ATTR = 'data-pillar-position';
|
|
8053
|
-
class TooltipManager {
|
|
8054
|
-
constructor(config, api, events) {
|
|
8055
|
-
this.tooltips = new Map();
|
|
8056
|
-
this.tooltipData = new Map();
|
|
8057
|
-
this.observer = null;
|
|
8058
|
-
this.stylesInjected = false;
|
|
8059
|
-
this.config = config;
|
|
8060
|
-
this.api = api;
|
|
8061
|
-
this.events = events;
|
|
8062
|
-
}
|
|
8063
|
-
/**
|
|
8064
|
-
* Initialize the tooltip manager
|
|
8065
|
-
*/
|
|
8066
|
-
async init() {
|
|
8067
|
-
// Inject styles
|
|
8068
|
-
if (!this.stylesInjected) {
|
|
8069
|
-
injectStyles(document, TOOLTIP_STYLES, 'pillar-tooltip-styles');
|
|
8070
|
-
this.stylesInjected = true;
|
|
8071
|
-
}
|
|
8072
|
-
// Initial scan
|
|
8073
|
-
await this.scan();
|
|
8074
|
-
// Set up mutation observer for dynamic content
|
|
8075
|
-
this.setupObserver();
|
|
8076
|
-
}
|
|
8077
|
-
/**
|
|
8078
|
-
* Scan DOM for tooltip elements and initialize them
|
|
8079
|
-
*/
|
|
8080
|
-
async scan() {
|
|
8081
|
-
const elements = document.querySelectorAll(`[${TOOLTIP_ATTRIBUTE}]`);
|
|
8082
|
-
if (elements.length === 0)
|
|
8083
|
-
return;
|
|
8084
|
-
// Collect all tooltip IDs
|
|
8085
|
-
const tooltipIds = new Set();
|
|
8086
|
-
elements.forEach((el) => {
|
|
8087
|
-
const id = el.getAttribute(TOOLTIP_ATTRIBUTE);
|
|
8088
|
-
if (id && !this.tooltipData.has(id)) {
|
|
8089
|
-
tooltipIds.add(id);
|
|
8090
|
-
}
|
|
8091
|
-
});
|
|
8092
|
-
// Fetch tooltip data if needed
|
|
8093
|
-
if (tooltipIds.size > 0) {
|
|
8094
|
-
try {
|
|
8095
|
-
const data = await this.api.getTooltips(Array.from(tooltipIds));
|
|
8096
|
-
data.forEach((tooltip) => {
|
|
8097
|
-
this.tooltipData.set(tooltip.tooltip_id, tooltip);
|
|
8098
|
-
});
|
|
8099
|
-
}
|
|
8100
|
-
catch (error) {
|
|
8101
|
-
console.warn('[Pillar] Failed to fetch tooltip data:', error);
|
|
8102
|
-
}
|
|
8103
|
-
}
|
|
8104
|
-
// Initialize tooltips for each element
|
|
8105
|
-
elements.forEach((element) => {
|
|
8106
|
-
const tooltipId = element.getAttribute(TOOLTIP_ATTRIBUTE);
|
|
8107
|
-
if (!tooltipId)
|
|
8108
|
-
return;
|
|
8109
|
-
// Skip if already initialized
|
|
8110
|
-
const existingKey = this.getElementKey(element);
|
|
8111
|
-
if (this.tooltips.has(existingKey))
|
|
8112
|
-
return;
|
|
8113
|
-
// Get tooltip data
|
|
8114
|
-
const data = this.tooltipData.get(tooltipId);
|
|
8115
|
-
if (!data) {
|
|
8116
|
-
console.warn(`[Pillar] No data found for tooltip: ${tooltipId}`);
|
|
8117
|
-
return;
|
|
8118
|
-
}
|
|
8119
|
-
// Create tooltip
|
|
8120
|
-
this.createTooltip(element, data);
|
|
8121
|
-
});
|
|
8122
|
-
}
|
|
8123
|
-
/**
|
|
8124
|
-
* Show a specific tooltip
|
|
8125
|
-
*/
|
|
8126
|
-
show(tooltipId) {
|
|
8127
|
-
for (const [key, tooltip] of this.tooltips) {
|
|
8128
|
-
const element = document.querySelector(`[data-pillar-tooltip-key="${key}"]`);
|
|
8129
|
-
const dataId = element?.getAttribute(TOOLTIP_ATTRIBUTE);
|
|
8130
|
-
if (dataId === tooltipId) {
|
|
8131
|
-
tooltip.show();
|
|
8132
|
-
return;
|
|
8133
|
-
}
|
|
8134
|
-
}
|
|
8135
|
-
}
|
|
8136
|
-
/**
|
|
8137
|
-
* Hide a specific tooltip
|
|
8138
|
-
*/
|
|
8139
|
-
hide(tooltipId) {
|
|
8140
|
-
for (const [key, tooltip] of this.tooltips) {
|
|
8141
|
-
const element = document.querySelector(`[data-pillar-tooltip-key="${key}"]`);
|
|
8142
|
-
const dataId = element?.getAttribute(TOOLTIP_ATTRIBUTE);
|
|
8143
|
-
if (dataId === tooltipId) {
|
|
8144
|
-
tooltip.hide();
|
|
8145
|
-
return;
|
|
8146
|
-
}
|
|
8147
|
-
}
|
|
8148
|
-
}
|
|
8149
|
-
/**
|
|
8150
|
-
* Destroy the tooltip manager
|
|
8151
|
-
*/
|
|
8152
|
-
destroy() {
|
|
8153
|
-
// Stop observer
|
|
8154
|
-
this.observer?.disconnect();
|
|
8155
|
-
this.observer = null;
|
|
8156
|
-
// Destroy all tooltips
|
|
8157
|
-
this.tooltips.forEach((tooltip) => tooltip.destroy());
|
|
8158
|
-
this.tooltips.clear();
|
|
8159
|
-
this.tooltipData.clear();
|
|
8160
|
-
// Remove styles
|
|
8161
|
-
document.getElementById('pillar-tooltip-styles')?.remove();
|
|
8162
|
-
this.stylesInjected = false;
|
|
8163
|
-
}
|
|
8164
|
-
// ============================================================================
|
|
8165
|
-
// Private Methods
|
|
8166
|
-
// ============================================================================
|
|
8167
|
-
createTooltip(element, data) {
|
|
8168
|
-
const trigger = element.getAttribute(TOOLTIP_TRIGGER_ATTR) ||
|
|
8169
|
-
data.trigger ||
|
|
8170
|
-
this.config.tooltips.defaultTrigger;
|
|
8171
|
-
const position = element.getAttribute(TOOLTIP_POSITION_ATTR) ||
|
|
8172
|
-
data.position ||
|
|
8173
|
-
'auto';
|
|
8174
|
-
const tooltip = new Tooltip(data, element, {
|
|
8175
|
-
trigger,
|
|
8176
|
-
position,
|
|
8177
|
-
onLearnMore: () => {
|
|
8178
|
-
// Emit event
|
|
8179
|
-
this.events.emit('tooltip:click', { tooltipId: data.tooltip_id });
|
|
8180
|
-
// Open panel via Pillar instance
|
|
8181
|
-
Promise.resolve().then(function () { return Pillar$1; }).then(({ Pillar }) => {
|
|
8182
|
-
Pillar.getInstance()?.open();
|
|
8183
|
-
});
|
|
8184
|
-
},
|
|
8185
|
-
onShow: () => {
|
|
8186
|
-
this.events.emit('tooltip:shown', { tooltipId: data.tooltip_id });
|
|
8187
|
-
},
|
|
8188
|
-
onHide: () => {
|
|
8189
|
-
this.events.emit('tooltip:hidden', { tooltipId: data.tooltip_id });
|
|
8190
|
-
},
|
|
8191
|
-
});
|
|
8192
|
-
tooltip.init();
|
|
8193
|
-
this.tooltips.set(this.getElementKey(element), tooltip);
|
|
8194
|
-
}
|
|
8195
|
-
setupObserver() {
|
|
8196
|
-
this.observer = new MutationObserver((mutations) => {
|
|
8197
|
-
let needsScan = false;
|
|
8198
|
-
for (const mutation of mutations) {
|
|
8199
|
-
// Check added nodes
|
|
8200
|
-
for (const node of mutation.addedNodes) {
|
|
8201
|
-
if (node instanceof HTMLElement) {
|
|
8202
|
-
if (node.hasAttribute(TOOLTIP_ATTRIBUTE) ||
|
|
8203
|
-
node.querySelector(`[${TOOLTIP_ATTRIBUTE}]`)) {
|
|
8204
|
-
needsScan = true;
|
|
8205
|
-
break;
|
|
8206
|
-
}
|
|
8207
|
-
}
|
|
8208
|
-
}
|
|
8209
|
-
// Check removed nodes
|
|
8210
|
-
for (const node of mutation.removedNodes) {
|
|
8211
|
-
if (node instanceof HTMLElement) {
|
|
8212
|
-
this.handleRemovedElement(node);
|
|
8213
|
-
}
|
|
8214
|
-
}
|
|
8215
|
-
if (needsScan)
|
|
8216
|
-
break;
|
|
8217
|
-
}
|
|
8218
|
-
if (needsScan) {
|
|
8219
|
-
this.scan();
|
|
8220
|
-
}
|
|
8221
|
-
});
|
|
8222
|
-
this.observer.observe(document.body, {
|
|
8223
|
-
childList: true,
|
|
8224
|
-
subtree: true,
|
|
8225
|
-
});
|
|
8226
|
-
}
|
|
8227
|
-
handleRemovedElement(element) {
|
|
8228
|
-
// Check if this element or any child has a tooltip
|
|
8229
|
-
const key = this.getElementKey(element);
|
|
8230
|
-
if (this.tooltips.has(key)) {
|
|
8231
|
-
this.tooltips.get(key)?.destroy();
|
|
8232
|
-
this.tooltips.delete(key);
|
|
8233
|
-
}
|
|
8234
|
-
// Check children
|
|
8235
|
-
element.querySelectorAll(`[${TOOLTIP_ATTRIBUTE}]`).forEach((child) => {
|
|
8236
|
-
const childKey = this.getElementKey(child);
|
|
8237
|
-
if (this.tooltips.has(childKey)) {
|
|
8238
|
-
this.tooltips.get(childKey)?.destroy();
|
|
8239
|
-
this.tooltips.delete(childKey);
|
|
8240
|
-
}
|
|
8241
|
-
});
|
|
8242
|
-
}
|
|
8243
|
-
getElementKey(element) {
|
|
8244
|
-
let key = element.dataset.pillarTooltipKey;
|
|
8245
|
-
if (!key) {
|
|
8246
|
-
key = `tooltip-${Math.random().toString(36).slice(2, 9)}`;
|
|
8247
|
-
element.dataset.pillarTooltipKey = key;
|
|
8248
|
-
}
|
|
8249
|
-
return key;
|
|
8250
|
-
}
|
|
8251
|
-
}
|
|
8252
|
-
|
|
8253
7511
|
/**
|
|
8254
7512
|
* Product Context Types for Pillar SDK
|
|
8255
7513
|
*
|
|
@@ -8435,10 +7693,6 @@ const DEFAULT_CONFIG = {
|
|
|
8435
7693
|
label: 'Assistant',
|
|
8436
7694
|
style: 'edge',
|
|
8437
7695
|
},
|
|
8438
|
-
tooltips: {
|
|
8439
|
-
enabled: true,
|
|
8440
|
-
defaultTrigger: 'hover',
|
|
8441
|
-
},
|
|
8442
7696
|
urlParams: {
|
|
8443
7697
|
enabled: true,
|
|
8444
7698
|
prefix: 'pillar-',
|
|
@@ -8491,10 +7745,6 @@ function resolveConfig(config) {
|
|
|
8491
7745
|
...DEFAULT_CONFIG.floatingButton,
|
|
8492
7746
|
...config.floatingButton,
|
|
8493
7747
|
},
|
|
8494
|
-
tooltips: {
|
|
8495
|
-
...DEFAULT_CONFIG.tooltips,
|
|
8496
|
-
...config.tooltips,
|
|
8497
|
-
},
|
|
8498
7748
|
urlParams: {
|
|
8499
7749
|
...DEFAULT_CONFIG.urlParams,
|
|
8500
7750
|
...config.urlParams,
|
|
@@ -9224,7 +8474,6 @@ class Pillar {
|
|
|
9224
8474
|
this._api = null;
|
|
9225
8475
|
this._mcpClient = null;
|
|
9226
8476
|
this._planExecutor = null;
|
|
9227
|
-
this._tooltipManager = null;
|
|
9228
8477
|
this._textSelectionManager = null;
|
|
9229
8478
|
this._panel = null;
|
|
9230
8479
|
this._floatingButton = null;
|
|
@@ -9456,24 +8705,6 @@ class Pillar {
|
|
|
9456
8705
|
// Emit event
|
|
9457
8706
|
this._events.emit('textSelection:change', { enabled });
|
|
9458
8707
|
}
|
|
9459
|
-
/**
|
|
9460
|
-
* Manually trigger tooltip scan
|
|
9461
|
-
*/
|
|
9462
|
-
scanTooltips() {
|
|
9463
|
-
this._tooltipManager?.scan();
|
|
9464
|
-
}
|
|
9465
|
-
/**
|
|
9466
|
-
* Show a specific tooltip
|
|
9467
|
-
*/
|
|
9468
|
-
showTooltip(tooltipId) {
|
|
9469
|
-
this._tooltipManager?.show(tooltipId);
|
|
9470
|
-
}
|
|
9471
|
-
/**
|
|
9472
|
-
* Hide a specific tooltip
|
|
9473
|
-
*/
|
|
9474
|
-
hideTooltip(tooltipId) {
|
|
9475
|
-
this._tooltipManager?.hide(tooltipId);
|
|
9476
|
-
}
|
|
9477
8708
|
/**
|
|
9478
8709
|
* Mount the panel to a specific container element.
|
|
9479
8710
|
* Used for manual mounting mode (e.g., from React component).
|
|
@@ -10162,11 +9393,6 @@ class Pillar {
|
|
|
10162
9393
|
// Create shared root container for all Pillar UI elements
|
|
10163
9394
|
// Uses isolation: isolate to create a new stacking context
|
|
10164
9395
|
this._rootContainer = this._createRootContainer();
|
|
10165
|
-
// Initialize tooltips if enabled
|
|
10166
|
-
if (this._config.tooltips.enabled) {
|
|
10167
|
-
this._tooltipManager = new TooltipManager(this._config, this._api, this._events);
|
|
10168
|
-
await this._tooltipManager.init();
|
|
10169
|
-
}
|
|
10170
9396
|
// Initialize panel if enabled
|
|
10171
9397
|
if (this._config.panel.enabled) {
|
|
10172
9398
|
this._panel = new Panel(this._config, this._api, this._events, this._rootContainer);
|
|
@@ -10232,7 +9458,6 @@ class Pillar {
|
|
|
10232
9458
|
* Internal cleanup
|
|
10233
9459
|
*/
|
|
10234
9460
|
_destroy() {
|
|
10235
|
-
this._tooltipManager?.destroy();
|
|
10236
9461
|
this._textSelectionManager?.destroy();
|
|
10237
9462
|
this._panel?.destroy();
|
|
10238
9463
|
this._floatingButton?.destroy();
|
|
@@ -10257,7 +9482,6 @@ class Pillar {
|
|
|
10257
9482
|
// Clear task handlers
|
|
10258
9483
|
this._taskHandlers.clear();
|
|
10259
9484
|
this._anyTaskHandler = null;
|
|
10260
|
-
this._tooltipManager = null;
|
|
10261
9485
|
this._textSelectionManager = null;
|
|
10262
9486
|
this._panel = null;
|
|
10263
9487
|
this._floatingButton = null;
|