@eric-emg/symphiq-components 1.2.59 → 1.2.61

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.
@@ -193,24 +193,11 @@ class TooltipService {
193
193
  // Insight tooltips can be quite tall, so need more space
194
194
  const HORIZONTAL_THRESHOLD = 200;
195
195
  const VERTICAL_THRESHOLD = type === 'insight' ? 350 : 200;
196
- // Calculate effective boundaries
197
- let leftBound = 0;
198
- let rightBound = window.innerWidth;
199
- let topBound = 0;
200
- let bottomBound = window.innerHeight;
201
- // If there's a scroll container, adjust boundaries relative to it
202
- if (this.scrollContainer) {
203
- const containerRect = this.scrollContainer.getBoundingClientRect();
204
- leftBound = containerRect.left;
205
- rightBound = containerRect.right;
206
- topBound = containerRect.top;
207
- bottomBound = containerRect.bottom;
208
- }
209
- // Calculate space available around target element
210
- const spaceLeft = targetRect.left - leftBound;
211
- const spaceRight = rightBound - targetRect.right;
212
- const spaceTop = targetRect.top - topBound;
213
- const spaceBelow = bottomBound - targetRect.bottom;
196
+ // Calculate space available around target element (using window bounds)
197
+ const spaceLeft = targetRect.left;
198
+ const spaceRight = window.innerWidth - targetRect.right;
199
+ const spaceTop = targetRect.top;
200
+ const spaceBelow = window.innerHeight - targetRect.bottom;
214
201
  // Check left edge
215
202
  if (position === 'left' && spaceLeft < HORIZONTAL_THRESHOLD) {
216
203
  adjustedPosition = 'right';
@@ -1027,6 +1014,35 @@ class ChartThemeService {
1027
1014
  }]
1028
1015
  }], null, null); })();
1029
1016
 
1017
+ class MetricFormatterService {
1018
+ constructor() {
1019
+ this.cache = new Map();
1020
+ }
1021
+ formatMetricName(name) {
1022
+ if (!name)
1023
+ return '';
1024
+ if (!this.cache.has(name)) {
1025
+ const formatted = name
1026
+ .replace(/_/g, ' ')
1027
+ .toLowerCase()
1028
+ .replace(/\b\w/g, l => l.toUpperCase());
1029
+ this.cache.set(name, formatted);
1030
+ }
1031
+ return this.cache.get(name);
1032
+ }
1033
+ clearCache() {
1034
+ this.cache.clear();
1035
+ }
1036
+ static { this.ɵfac = function MetricFormatterService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MetricFormatterService)(); }; }
1037
+ static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: MetricFormatterService, factory: MetricFormatterService.ɵfac, providedIn: 'root' }); }
1038
+ }
1039
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MetricFormatterService, [{
1040
+ type: Injectable,
1041
+ args: [{
1042
+ providedIn: 'root'
1043
+ }]
1044
+ }], null, null); })();
1045
+
1030
1046
  const _c0$b = a0 => ["skeleton-loader", "rounded-lg", "relative", "overflow-hidden", a0];
1031
1047
  const _c1$3 = a0 => ["skeleton-shimmer-overlay", "absolute", "inset-0", "bg-gradient-to-r", a0];
1032
1048
  class SkeletonLoaderComponent {
@@ -11096,8 +11112,7 @@ class TooltipContainerComponent {
11096
11112
  return true;
11097
11113
  const position = this.tooltipPosition();
11098
11114
  const tooltipWidth = 384;
11099
- const container = this.scrollContainer();
11100
- const viewportWidth = container?.clientWidth || window.innerWidth;
11115
+ const padding = 10;
11101
11116
  // For 'auto' positioning, always center horizontally
11102
11117
  if (position === 'auto') {
11103
11118
  return true;
@@ -11105,8 +11120,8 @@ class TooltipContainerComponent {
11105
11120
  if (position === 'top' || position === 'bottom') {
11106
11121
  const centerPosition = rect.left + rect.width / 2;
11107
11122
  const halfWidth = tooltipWidth / 2;
11108
- const wouldGoOffLeft = centerPosition - halfWidth < 10;
11109
- const wouldGoOffRight = centerPosition + halfWidth > viewportWidth - 10;
11123
+ const wouldGoOffLeft = centerPosition - halfWidth < padding;
11124
+ const wouldGoOffRight = centerPosition + halfWidth > window.innerWidth - padding;
11110
11125
  return !wouldGoOffLeft && !wouldGoOffRight;
11111
11126
  }
11112
11127
  return false;
@@ -11156,26 +11171,17 @@ class TooltipContainerComponent {
11156
11171
  const position = this.tooltipPosition();
11157
11172
  const mousePos = this.mousePosition();
11158
11173
  const tooltipWidth = 384;
11159
- const container = this.scrollContainer();
11160
- // Calculate effective viewport boundaries
11161
- let leftBound = 10;
11162
- let rightBound = window.innerWidth - 10;
11163
- // If there's a scroll container, constrain to its boundaries
11164
- if (container) {
11165
- const containerRect = container.getBoundingClientRect();
11166
- leftBound = Math.max(10, containerRect.left + 10);
11167
- rightBound = Math.min(window.innerWidth - 10, containerRect.right - 10);
11168
- }
11174
+ const padding = 10;
11169
11175
  // Handle 'auto' positioning with mouse coordinates
11170
11176
  if (position === 'auto' && mousePos) {
11171
11177
  const halfWidth = tooltipWidth / 2;
11172
11178
  let leftPos = mousePos.x;
11173
11179
  // Keep tooltip in bounds
11174
- if (leftPos - halfWidth < leftBound) {
11175
- leftPos = leftBound + halfWidth;
11180
+ if (leftPos - halfWidth < padding) {
11181
+ leftPos = padding + halfWidth;
11176
11182
  }
11177
- else if (leftPos + halfWidth > rightBound) {
11178
- leftPos = rightBound - halfWidth;
11183
+ else if (leftPos + halfWidth > window.innerWidth - padding) {
11184
+ leftPos = window.innerWidth - padding - halfWidth;
11179
11185
  }
11180
11186
  return leftPos;
11181
11187
  }
@@ -11185,15 +11191,15 @@ class TooltipContainerComponent {
11185
11191
  const centerPosition = rect.left + rect.width / 2;
11186
11192
  const halfWidth = tooltipWidth / 2;
11187
11193
  // Check if centered tooltip would go off bounds
11188
- const wouldGoOffLeft = centerPosition - halfWidth < leftBound;
11189
- const wouldGoOffRight = centerPosition + halfWidth > rightBound;
11194
+ const wouldGoOffLeft = centerPosition - halfWidth < padding;
11195
+ const wouldGoOffRight = centerPosition + halfWidth > window.innerWidth - padding;
11190
11196
  if (wouldGoOffLeft) {
11191
- // Align to left bound
11192
- return leftBound;
11197
+ // Align to left edge with padding
11198
+ return padding + halfWidth;
11193
11199
  }
11194
11200
  else if (wouldGoOffRight) {
11195
- // Align to right bound
11196
- return rightBound - tooltipWidth;
11201
+ // Align to right edge with padding
11202
+ return window.innerWidth - padding - halfWidth;
11197
11203
  }
11198
11204
  else {
11199
11205
  // Center normally (transform will be applied)
@@ -11202,25 +11208,17 @@ class TooltipContainerComponent {
11202
11208
  }
11203
11209
  case 'left': {
11204
11210
  const leftPosition = rect.left - tooltipWidth - 8;
11205
- // If tooltip would go off left bound, position it to the right instead
11206
- if (leftPosition < leftBound) {
11207
- const rightPosition = rect.right + 8;
11208
- if (rightPosition + tooltipWidth > rightBound) {
11209
- return leftBound;
11210
- }
11211
- return rightPosition;
11211
+ // If tooltip would go off left edge, position it to the right instead
11212
+ if (leftPosition < padding) {
11213
+ return rect.right + 8;
11212
11214
  }
11213
11215
  return leftPosition;
11214
11216
  }
11215
11217
  case 'right': {
11216
11218
  const rightPosition = rect.right + 8;
11217
- // If tooltip would go off right bound, position it to the left instead
11218
- if (rightPosition + tooltipWidth > rightBound) {
11219
- const leftPosition = rect.left - tooltipWidth - 8;
11220
- if (leftPosition < leftBound) {
11221
- return leftBound;
11222
- }
11223
- return leftPosition;
11219
+ // If tooltip would go off right edge, position it to the left instead
11220
+ if (rightPosition + tooltipWidth > window.innerWidth - padding) {
11221
+ return rect.left - tooltipWidth - 8;
11224
11222
  }
11225
11223
  return rightPosition;
11226
11224
  }
@@ -11235,16 +11233,7 @@ class TooltipContainerComponent {
11235
11233
  const position = this.tooltipPosition();
11236
11234
  const mousePos = this.mousePosition();
11237
11235
  const type = this.tooltipType();
11238
- const container = this.scrollContainer();
11239
- // Calculate effective viewport boundaries
11240
- let topBound = 10;
11241
- let bottomBound = window.innerHeight - 10;
11242
- // If there's a scroll container, constrain to its boundaries
11243
- if (container) {
11244
- const containerRect = container.getBoundingClientRect();
11245
- topBound = Math.max(10, containerRect.top + 10);
11246
- bottomBound = Math.min(window.innerHeight - 10, containerRect.bottom - 10);
11247
- }
11236
+ const padding = 10;
11248
11237
  // Estimate tooltip height based on type
11249
11238
  let estimatedHeight = 100;
11250
11239
  if (type === 'insight') {
@@ -11258,28 +11247,28 @@ class TooltipContainerComponent {
11258
11247
  const offset = 20; // Offset from mouse cursor
11259
11248
  let topPos = mousePos.y + offset;
11260
11249
  // If tooltip would go off bottom, position above cursor
11261
- if (topPos + estimatedHeight > bottomBound) {
11250
+ if (topPos + estimatedHeight > window.innerHeight - padding) {
11262
11251
  topPos = mousePos.y - estimatedHeight - offset;
11263
11252
  }
11264
11253
  // Ensure it doesn't go off top
11265
- if (topPos < topBound) {
11266
- topPos = topBound;
11254
+ if (topPos < padding) {
11255
+ topPos = padding;
11267
11256
  }
11268
11257
  return topPos;
11269
11258
  }
11270
11259
  switch (position) {
11271
11260
  case 'top': {
11272
11261
  const topPosition = rect.top - estimatedHeight - 8;
11273
- // If tooltip would go off top bound, position it below instead
11274
- if (topPosition < topBound) {
11262
+ // If tooltip would go off top edge, position it below instead
11263
+ if (topPosition < padding) {
11275
11264
  return rect.bottom + 8;
11276
11265
  }
11277
11266
  return topPosition;
11278
11267
  }
11279
11268
  case 'bottom': {
11280
11269
  const bottomPosition = rect.bottom + 8;
11281
- // If tooltip would go off bottom bound, position it above instead
11282
- if (bottomPosition + estimatedHeight > bottomBound) {
11270
+ // If tooltip would go off bottom edge, position it above instead
11271
+ if (bottomPosition + estimatedHeight > window.innerHeight - padding) {
11283
11272
  return rect.top - estimatedHeight - 8;
11284
11273
  }
11285
11274
  return bottomPosition;
@@ -11288,8 +11277,8 @@ class TooltipContainerComponent {
11288
11277
  case 'right': {
11289
11278
  const centerPosition = rect.top + rect.height / 2 - estimatedHeight / 2;
11290
11279
  // Keep within bounds
11291
- const maxTop = bottomBound - estimatedHeight;
11292
- return Math.max(topBound, Math.min(centerPosition, maxTop));
11280
+ const maxTop = window.innerHeight - padding - estimatedHeight;
11281
+ return Math.max(padding, Math.min(centerPosition, maxTop));
11293
11282
  }
11294
11283
  default:
11295
11284
  return rect.top - estimatedHeight - 8;
@@ -23665,6 +23654,7 @@ class SymphiqFunnelAnalysisPreviewComponent {
23665
23654
  this.tooltipDataService = inject(TooltipDataService);
23666
23655
  this.tooltipService = inject(TooltipService);
23667
23656
  this.competitiveScoreService = inject(CompetitiveScoreService);
23657
+ this.metricFormatter = inject(MetricFormatterService);
23668
23658
  // Analysis data - use sample data if useSampleData is true, otherwise use provided data
23669
23659
  this.analysisData = computed(() => {
23670
23660
  if (this.useSampleData()) {
@@ -23903,18 +23893,7 @@ class SymphiqFunnelAnalysisPreviewComponent {
23903
23893
  return getTrendClasses(trend, this.viewMode());
23904
23894
  }
23905
23895
  getMetricLabel(metric) {
23906
- const labels = {
23907
- 'SESSIONS': 'Sessions',
23908
- 'ACTIVE_USERS': 'Users',
23909
- 'BOUNCE_RATE': 'Bounce Rate',
23910
- 'PURCHASES': 'Purchases',
23911
- 'ECOMMERCE_PURCHASES': 'Purchases',
23912
- 'ADD_TO_CARTS': 'Add to Cart',
23913
- 'CHECKOUTS': 'Checkouts',
23914
- 'ECOMMERCE_CONVERSION_RATE': 'Conv Rate',
23915
- 'AVERAGE_ORDER_VALUE': 'AOV'
23916
- };
23917
- return labels[metric.metric || ''] || metric.metric || 'Metric';
23896
+ return this.metricFormatter.formatMetricName(metric.metric || '') || 'Metric';
23918
23897
  }
23919
23898
  formatMetricValue(metric) {
23920
23899
  const value = metric.currentValue || 0;
@@ -24259,7 +24238,7 @@ class SymphiqFunnelAnalysisPreviewComponent {
24259
24238
  <symphiq-tooltip-container />
24260
24239
  `, styles: ["@keyframes statusPulse{0%,to{opacity:1}50%{opacity:.6}}.status-pulse{animation:statusPulse 2s ease-in-out infinite}\n"] }]
24261
24240
  }], () => [], { analysisInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "funnelAnalysis", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], useSampleData: [{ type: i0.Input, args: [{ isSignal: true, alias: "useSampleData", required: false }] }], scrollElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollElement", required: false }] }], onViewAnalysis: [{ type: i0.Output, args: ["onViewAnalysis"] }] }); })();
24262
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SymphiqFunnelAnalysisPreviewComponent, { className: "SymphiqFunnelAnalysisPreviewComponent", filePath: "lib/components/funnel-analysis-preview/symphiq-funnel-analysis-preview.component.ts", lineNumber: 216 }); })();
24241
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SymphiqFunnelAnalysisPreviewComponent, { className: "SymphiqFunnelAnalysisPreviewComponent", filePath: "lib/components/funnel-analysis-preview/symphiq-funnel-analysis-preview.component.ts", lineNumber: 217 }); })();
24263
24242
 
24264
24243
  const _c0$3 = ["chartdiv"];
24265
24244
  class LineChartComponent {
@@ -26282,5 +26261,5 @@ var areaChart_component = /*#__PURE__*/Object.freeze({
26282
26261
  * Generated bundle index. Do not edit.
26283
26262
  */
26284
26263
 
26285
- export { AreaChartComponent, BarChartComponent, BreakdownSectionComponent, ChartContainerComponent, ChartThemeService, CompetitivePositioningSummaryComponent, FUNNEL_ANALYSIS, FunnelOrderService, InsightCardComponent, LineChartComponent, MetricCardComponent, MobileBottomNavComponent, MobileFABComponent, ModalComponent, ModalService, OverallAssessmentComponent, PieChartComponent, SkeletonLoaderComponent, SymphiqFunnelAnalysisDashboardComponent, SymphiqFunnelAnalysisPreviewComponent, TooltipContainerComponent, TooltipDataService, TooltipDirective, TooltipService, ViewModeService, getBadgeLabelClasses, getButtonClasses, getCompetitiveBadgeClasses, getContainerClasses, getFooterClasses, getGradeBadgeClasses, getHeaderClasses, getInsightsBadgeClasses, getInsightsCardClasses, getMetricLabelClasses, getMetricMiniCardClasses, getMetricValueClasses, getNarrativeTextClasses, getRevenueCardClasses, getRevenueIconClasses, getStatusBadgeClasses, getStatusDotClasses, getStatusIconClasses, getStatusSummaryClasses, getSubtitleClasses, getTitleClasses, getTrendClasses, getTrendIconClasses, getTrendValueClasses, isLightMode };
26264
+ export { AreaChartComponent, BarChartComponent, BreakdownSectionComponent, ChartContainerComponent, ChartThemeService, CompetitivePositioningSummaryComponent, FUNNEL_ANALYSIS, FunnelOrderService, InsightCardComponent, LineChartComponent, MetricCardComponent, MetricFormatterService, MobileBottomNavComponent, MobileFABComponent, ModalComponent, ModalService, OverallAssessmentComponent, PieChartComponent, SkeletonLoaderComponent, SymphiqFunnelAnalysisDashboardComponent, SymphiqFunnelAnalysisPreviewComponent, TooltipContainerComponent, TooltipDataService, TooltipDirective, TooltipService, ViewModeService, getBadgeLabelClasses, getButtonClasses, getCompetitiveBadgeClasses, getContainerClasses, getFooterClasses, getGradeBadgeClasses, getHeaderClasses, getInsightsBadgeClasses, getInsightsCardClasses, getMetricLabelClasses, getMetricMiniCardClasses, getMetricValueClasses, getNarrativeTextClasses, getRevenueCardClasses, getRevenueIconClasses, getStatusBadgeClasses, getStatusDotClasses, getStatusIconClasses, getStatusSummaryClasses, getSubtitleClasses, getTitleClasses, getTrendClasses, getTrendIconClasses, getTrendValueClasses, isLightMode };
26286
26265
  //# sourceMappingURL=symphiq-components.mjs.map