@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.
@@ -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$3 = `<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>`;
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$3 : HELP_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$2 = `<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>`;
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$2 } })] }));
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$1 = `<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>`;
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$1 } }))] }));
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;