@app-studio/web 0.9.14 → 0.9.15

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.
@@ -5742,6 +5742,24 @@ var PieChart = _ref => {
5742
5742
  var {
5743
5743
  getColor
5744
5744
  } = appStudio.useTheme();
5745
+ // Use useElementPosition for intelligent tooltip positioning
5746
+ var {
5747
+ ref: positionRef,
5748
+ relation
5749
+ } = appStudio.useElementPosition({
5750
+ trackChanges: true,
5751
+ trackOnHover: true,
5752
+ trackOnScroll: true,
5753
+ trackOnResize: true
5754
+ });
5755
+ // Create a separate ref for the SVG element
5756
+ var chartRef = React.useRef(null);
5757
+ // Sync the position ref with the chart ref for positioning calculations
5758
+ React.useEffect(() => {
5759
+ if (chartRef.current && positionRef) {
5760
+ positionRef.current = chartRef.current;
5761
+ }
5762
+ }, [chartRef, positionRef]);
5745
5763
  // Calculate chart dimensions
5746
5764
  var size = Math.min(width, height);
5747
5765
  var radius = size / 2 * 0.8;
@@ -5810,12 +5828,30 @@ var PieChart = _ref => {
5810
5828
  return result;
5811
5829
  }, [dataPoints, total, radius, centerX, centerY, donutRadius, animationProgress, isDonut]);
5812
5830
  return /*#__PURE__*/React__default.createElement("svg", {
5831
+ ref: chartRef,
5813
5832
  width: width,
5814
5833
  height: height
5815
5834
  }, slices.map((slice, index) => {
5816
5835
  var handleMouseEnter = e => {
5817
5836
  var tooltipContent = slice.label + ": " + slice.value + " (" + slice.percentage + ")";
5818
- showTooltip(e.clientX, e.clientY, tooltipContent);
5837
+ // Use intelligent positioning based on useElementPosition relation data
5838
+ var x = e.clientX;
5839
+ var y = e.clientY;
5840
+ if (relation && chartRef.current) {
5841
+ var chartRect = chartRef.current.getBoundingClientRect();
5842
+ // Adjust tooltip position based on available space
5843
+ if (relation.space.horizontal === 'left') {
5844
+ x = e.clientX - 100; // Offset tooltip to the left
5845
+ } else {
5846
+ x = e.clientX + 10; // Offset tooltip to the right
5847
+ }
5848
+ if (relation.space.vertical === 'top') {
5849
+ y = e.clientY - 30; // Offset tooltip above
5850
+ } else {
5851
+ y = e.clientY + 10; // Offset tooltip below
5852
+ }
5853
+ }
5854
+ showTooltip(x, y, tooltipContent);
5819
5855
  };
5820
5856
  var handleClick = () => {
5821
5857
  if (onSliceClick) {
@@ -13111,6 +13147,16 @@ var EditableInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13111
13147
  var [mentionStartPos, setMentionStartPos] = React.useState(-1);
13112
13148
  var [selectedMentionIndex, setSelectedMentionIndex] = React.useState(-1);
13113
13149
  var [filteredMentions, setFilteredMentions] = React.useState([]);
13150
+ // Use useElementPosition for intelligent dropdown positioning
13151
+ var {
13152
+ ref: positionRef,
13153
+ relation
13154
+ } = appStudio.useElementPosition({
13155
+ trackChanges: true,
13156
+ trackOnHover: true,
13157
+ trackOnScroll: true,
13158
+ trackOnResize: true
13159
+ });
13114
13160
  // Positioning state for dropdowns
13115
13161
  var [mentionPosition, setMentionPosition] = React.useState({
13116
13162
  x: 0,
@@ -13120,7 +13166,6 @@ var EditableInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13120
13166
  x: 0,
13121
13167
  y: 0
13122
13168
  });
13123
- // Note: Using custom positioning logic for better control over dropdown placement
13124
13169
  // Update the content of the editable div when the value prop changes
13125
13170
  React.useEffect(() => {
13126
13171
  var editableDiv = ref;
@@ -13172,7 +13217,13 @@ var EditableInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13172
13217
  setMentionStartPos(-1);
13173
13218
  setSelectedMentionIndex(-1);
13174
13219
  }, [mentionData, mentionTrigger]);
13175
- // Calculate optimal position for dropdowns
13220
+ // Sync the position ref with the container ref for positioning calculations
13221
+ React.useEffect(() => {
13222
+ if (containerRef.current && positionRef) {
13223
+ positionRef.current = containerRef.current;
13224
+ }
13225
+ }, [containerRef, positionRef]);
13226
+ // Calculate optimal position for dropdowns using useElementPosition
13176
13227
  var calculateDropdownPosition = React.useCallback(function (dropdownHeight) {
13177
13228
  if (dropdownHeight === void 0) {
13178
13229
  dropdownHeight = 200;
@@ -13182,22 +13233,26 @@ var EditableInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13182
13233
  y: 0
13183
13234
  };
13184
13235
  var containerRect = containerRef.current.getBoundingClientRect();
13236
+ // Use relation data for intelligent positioning if available
13237
+ if (relation) {
13238
+ var _useTopPlacement = relation.space.vertical === 'top';
13239
+ return {
13240
+ x: containerRect.left,
13241
+ y: _useTopPlacement ? containerRect.top - dropdownHeight - 8 : containerRect.bottom + 8
13242
+ };
13243
+ }
13244
+ // Fallback to manual calculation if relation data is not available
13185
13245
  var viewportHeight = window.innerHeight;
13186
- var viewportWidth = window.innerWidth;
13187
- // Calculate available space
13188
13246
  var availableSpace = {
13189
13247
  top: containerRect.top,
13190
- bottom: viewportHeight - containerRect.bottom,
13191
- left: containerRect.left,
13192
- right: viewportWidth - containerRect.right
13248
+ bottom: viewportHeight - containerRect.bottom
13193
13249
  };
13194
- // Prefer bottom placement, but use top if not enough space
13195
13250
  var useTopPlacement = availableSpace.bottom < dropdownHeight + 8 && availableSpace.top > availableSpace.bottom;
13196
13251
  return {
13197
13252
  x: containerRect.left,
13198
13253
  y: useTopPlacement ? containerRect.top - dropdownHeight - 8 : containerRect.bottom + 8
13199
13254
  };
13200
- }, []);
13255
+ }, [relation]);
13201
13256
  // Handle focus events
13202
13257
  var handleFocus = React.useCallback(() => {
13203
13258
  setIsFocused(true);
@@ -13403,7 +13458,7 @@ var EditableInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13403
13458
  opacity: 0.7,
13404
13459
  padding: '4px'
13405
13460
  }
13406
- }, "Mentions (Trigger: ", mentionTrigger, ")"))))), showSuggestions && suggestions.length > 0 && !showMentions && isFocused && !value && (/*#__PURE__*/React__default.createElement(appStudio.View, Object.assign({
13461
+ }, "Mentions (Trigger: ", mentionTrigger, ")", relation && (/*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal))))))), showSuggestions && suggestions.length > 0 && !showMentions && isFocused && !value && (/*#__PURE__*/React__default.createElement(appStudio.View, Object.assign({
13407
13462
  position: "fixed",
13408
13463
  left: suggestionPosition.x,
13409
13464
  top: suggestionPosition.y,
@@ -13449,7 +13504,7 @@ var EditableInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13449
13504
  opacity: 0.7,
13450
13505
  padding: '4px'
13451
13506
  }
13452
- }, "Suggestions (Focus-triggered)"))))));
13507
+ }, "Suggestions (Focus-triggered)", relation && (/*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal))))))));
13453
13508
  });
13454
13509
  EditableInput.displayName = 'EditableInput';
13455
13510
 
@@ -17591,109 +17646,103 @@ var DropdownMenuContent = _ref3 => {
17591
17646
  triggerRef
17592
17647
  } = useDropdownMenuContext();
17593
17648
  var contentRef = React.useRef(null);
17649
+ // Use useElementPosition for intelligent positioning
17650
+ var {
17651
+ ref: positionRef,
17652
+ relation
17653
+ } = appStudio.useElementPosition({
17654
+ trackChanges: true,
17655
+ trackOnHover: true,
17656
+ trackOnScroll: true,
17657
+ trackOnResize: true
17658
+ });
17594
17659
  var [optimalPosition, setOptimalPosition] = React.useState({
17595
17660
  x: 0,
17596
17661
  y: 0,
17597
17662
  placement: side
17598
17663
  });
17599
- // Calculate optimal position when the dropdown opens
17664
+ // Sync the position ref with the trigger ref for positioning calculations
17665
+ React.useEffect(() => {
17666
+ if (triggerRef.current && positionRef) {
17667
+ positionRef.current = triggerRef.current;
17668
+ }
17669
+ }, [triggerRef, positionRef, isOpen]);
17670
+ // Calculate optimal position using useElementPosition when the dropdown opens
17600
17671
  React.useEffect(() => {
17601
17672
  if (isOpen && contentRef.current && triggerRef.current) {
17602
- var contentRect = contentRef.current.getBoundingClientRect();
17603
17673
  var triggerRect = triggerRef.current.getBoundingClientRect();
17604
- // Get content dimensions
17605
- var contentWidth = Math.max(contentRect.width || 180, 180);
17606
- var contentHeight = Math.max(contentRect.height || 100, 100);
17607
- // Get viewport dimensions
17608
- var viewportWidth = window.innerWidth;
17609
- var viewportHeight = window.innerHeight;
17610
- // Calculate available space on all sides from the trigger
17611
- var availableSpace = {
17612
- top: triggerRect.top,
17613
- right: viewportWidth - triggerRect.right,
17614
- bottom: viewportHeight - triggerRect.bottom,
17615
- left: triggerRect.left
17616
- };
17617
- // Determine optimal placement based on available space and preferred side
17618
- var placements = [{
17619
- placement: 'bottom',
17620
- space: availableSpace.bottom,
17621
- fits: availableSpace.bottom >= contentHeight + 8,
17622
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
17623
- y: triggerRect.bottom + 8
17624
- }, {
17625
- placement: 'top',
17626
- space: availableSpace.top,
17627
- fits: availableSpace.top >= contentHeight + 8,
17628
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
17629
- y: triggerRect.top - contentHeight - 8
17630
- }, {
17631
- placement: 'right',
17632
- space: availableSpace.right,
17633
- fits: availableSpace.right >= contentWidth + 8,
17634
- x: triggerRect.right + 8,
17635
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
17636
- }, {
17637
- placement: 'left',
17638
- space: availableSpace.left,
17639
- fits: availableSpace.left >= contentWidth + 8,
17640
- x: triggerRect.left - contentWidth - 8,
17641
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
17642
- }];
17643
- // First try the preferred side if it fits
17644
- var preferredPlacement = placements.find(p => p.placement === side && p.fits);
17645
- if (preferredPlacement) {
17646
- setOptimalPosition({
17647
- x: preferredPlacement.x,
17648
- y: preferredPlacement.y,
17649
- placement: preferredPlacement.placement
17650
- });
17651
- return;
17652
- }
17653
- // Otherwise, find the best fitting placement
17654
- var fittingPlacement = placements.find(p => p.fits);
17655
- if (fittingPlacement) {
17656
- setOptimalPosition({
17657
- x: fittingPlacement.x,
17658
- y: fittingPlacement.y,
17659
- placement: fittingPlacement.placement
17660
- });
17661
- return;
17662
- }
17663
- // If nothing fits, choose the placement with the most space
17664
- var bestPlacement = placements.reduce((best, current) => current.space > best.space ? current : best);
17665
- // Ensure the content stays within viewport bounds
17666
- var finalX = bestPlacement.x;
17667
- var finalY = bestPlacement.y;
17668
- if (finalX + contentWidth > viewportWidth) {
17669
- finalX = viewportWidth - contentWidth - 8;
17670
- }
17671
- if (finalX < 8) {
17672
- finalX = 8;
17673
- }
17674
- if (finalY + contentHeight > viewportHeight) {
17675
- finalY = viewportHeight - contentHeight - 8;
17674
+ var placement = side;
17675
+ // Use relation data to determine optimal placement
17676
+ if (relation) {
17677
+ // If preferred side doesn't have enough space, use the side with more space
17678
+ if (side === 'bottom' && relation.space.vertical === 'top') {
17679
+ placement = 'top';
17680
+ } else if (side === 'top' && relation.space.vertical === 'bottom') {
17681
+ placement = 'bottom';
17682
+ } else if (side === 'right' && relation.space.horizontal === 'left') {
17683
+ placement = 'left';
17684
+ } else if (side === 'left' && relation.space.horizontal === 'right') {
17685
+ placement = 'right';
17686
+ }
17676
17687
  }
17677
- if (finalY < 8) {
17678
- finalY = 8;
17688
+ // Calculate position based on optimal placement and alignment
17689
+ var x = 0;
17690
+ var y = 0;
17691
+ switch (placement) {
17692
+ case 'bottom':
17693
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 180 // Estimated content width
17694
+ : triggerRect.left + triggerRect.width / 2 - 90; // Half of estimated width
17695
+ y = triggerRect.bottom + 8;
17696
+ break;
17697
+ case 'top':
17698
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 180 : triggerRect.left + triggerRect.width / 2 - 90;
17699
+ y = triggerRect.top - 8; // Will be adjusted with transform
17700
+ break;
17701
+ case 'right':
17702
+ x = triggerRect.right + 8;
17703
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 100 // Estimated content height
17704
+ : triggerRect.top + triggerRect.height / 2 - 50; // Half of estimated height
17705
+ break;
17706
+ case 'left':
17707
+ x = triggerRect.left - 8; // Will be adjusted with transform
17708
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 100 : triggerRect.top + triggerRect.height / 2 - 50;
17709
+ break;
17679
17710
  }
17680
17711
  setOptimalPosition({
17681
- x: finalX,
17682
- y: finalY,
17683
- placement: bestPlacement.placement
17712
+ x,
17713
+ y,
17714
+ placement
17684
17715
  });
17685
17716
  }
17686
- }, [isOpen, side, align, triggerRef]);
17717
+ }, [isOpen, side, align, triggerRef, relation]);
17687
17718
  if (!isOpen) {
17688
17719
  return null;
17689
17720
  }
17690
- // Create intelligent positioning styles
17691
- var positionStyles = {
17692
- position: 'fixed',
17693
- left: optimalPosition.x,
17694
- top: optimalPosition.y,
17695
- zIndex: 1000
17721
+ // Create intelligent positioning styles with transform for better placement
17722
+ var getPositionStyles = () => {
17723
+ var baseStyles = {
17724
+ position: 'fixed',
17725
+ left: optimalPosition.x,
17726
+ top: optimalPosition.y,
17727
+ zIndex: 1000
17728
+ };
17729
+ // Add transform based on placement for better positioning
17730
+ switch (optimalPosition.placement) {
17731
+ case 'top':
17732
+ return Object.assign({}, baseStyles, {
17733
+ transform: 'translateY(-100%)'
17734
+ });
17735
+ case 'left':
17736
+ return Object.assign({}, baseStyles, {
17737
+ transform: 'translateX(-100%)'
17738
+ });
17739
+ case 'bottom':
17740
+ case 'right':
17741
+ default:
17742
+ return baseStyles;
17743
+ }
17696
17744
  };
17745
+ var positionStyles = getPositionStyles();
17697
17746
  return /*#__PURE__*/React__default.createElement(appStudio.View, Object.assign({
17698
17747
  ref: contentRef,
17699
17748
  id: "dropdown-menu",
@@ -17713,7 +17762,13 @@ var DropdownMenuContent = _ref3 => {
17713
17762
  item: item,
17714
17763
  views: views
17715
17764
  });
17716
- }));
17765
+ }), (/*#__PURE__*/React__default.createElement("div", {
17766
+ style: {
17767
+ fontSize: '10px',
17768
+ opacity: 0.7,
17769
+ padding: '4px'
17770
+ }
17771
+ }, "Placement: ", optimalPosition.placement, relation && (/*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal)))));
17717
17772
  };
17718
17773
  // DropdownMenu Item component
17719
17774
  var DropdownMenuItem = _ref4 => {
@@ -20897,111 +20952,99 @@ var HoverCardContent = _ref3 => {
20897
20952
  contentId,
20898
20953
  triggerId
20899
20954
  } = useHoverCardContext();
20900
- var [optimalPosition, setOptimalPosition] = React.useState({
20901
- x: 0,
20902
- y: 0,
20903
- placement: side
20955
+ // Use useElementPosition for intelligent positioning
20956
+ var {
20957
+ ref: positionRef,
20958
+ relation
20959
+ } = appStudio.useElementPosition({
20960
+ trackChanges: true,
20961
+ trackOnHover: true,
20962
+ trackOnScroll: true,
20963
+ trackOnResize: true
20904
20964
  });
20905
- // Calculate optimal position when the card opens or content dimensions change
20965
+ // Sync the position ref with the trigger ref for positioning calculations
20906
20966
  React.useEffect(() => {
20907
- if (isOpen && contentRef != null && contentRef.current && triggerRef != null && triggerRef.current) {
20908
- var contentRect = contentRef.current.getBoundingClientRect();
20909
- var triggerRect = triggerRef.current.getBoundingClientRect();
20910
- // Get content dimensions
20911
- var contentWidth = Math.max(contentRect.width || 200, 200);
20912
- var contentHeight = Math.max(contentRect.height || 100, 100);
20913
- // Get viewport dimensions
20914
- var viewportWidth = window.innerWidth;
20915
- var viewportHeight = window.innerHeight;
20916
- // Calculate available space on all sides from the trigger
20917
- var availableSpace = {
20918
- top: triggerRect.top,
20919
- right: viewportWidth - triggerRect.right,
20920
- bottom: viewportHeight - triggerRect.bottom,
20921
- left: triggerRect.left
20922
- };
20923
- // Determine optimal placement based on available space and preferred side
20924
- var placements = [{
20925
- placement: 'bottom',
20926
- space: availableSpace.bottom,
20927
- fits: availableSpace.bottom >= contentHeight + sideOffset,
20928
- x: triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
20929
- y: triggerRect.bottom + sideOffset
20930
- }, {
20931
- placement: 'top',
20932
- space: availableSpace.top,
20933
- fits: availableSpace.top >= contentHeight + sideOffset,
20934
- x: triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
20935
- y: triggerRect.top - contentHeight - sideOffset
20936
- }, {
20937
- placement: 'right',
20938
- space: availableSpace.right,
20939
- fits: availableSpace.right >= contentWidth + sideOffset,
20940
- x: triggerRect.right + sideOffset,
20941
- y: triggerRect.top + triggerRect.height / 2 - contentHeight / 2
20942
- }, {
20943
- placement: 'left',
20944
- space: availableSpace.left,
20945
- fits: availableSpace.left >= contentWidth + sideOffset,
20946
- x: triggerRect.left - contentWidth - sideOffset,
20947
- y: triggerRect.top + triggerRect.height / 2 - contentHeight / 2
20948
- }];
20949
- // First try the preferred side if it fits
20950
- var preferredPlacement = placements.find(p => p.placement === side && p.fits);
20951
- if (preferredPlacement) {
20952
- setOptimalPosition({
20953
- x: preferredPlacement.x,
20954
- y: preferredPlacement.y,
20955
- placement: preferredPlacement.placement
20956
- });
20957
- return;
20958
- }
20959
- // Otherwise, find the best fitting placement
20960
- var fittingPlacement = placements.find(p => p.fits);
20961
- if (fittingPlacement) {
20962
- setOptimalPosition({
20963
- x: fittingPlacement.x,
20964
- y: fittingPlacement.y,
20965
- placement: fittingPlacement.placement
20966
- });
20967
- return;
20968
- }
20969
- // If nothing fits, choose the placement with the most space
20970
- var bestPlacement = placements.reduce((best, current) => current.space > best.space ? current : best);
20971
- // Ensure the content stays within viewport bounds
20972
- var finalX = bestPlacement.x;
20973
- var finalY = bestPlacement.y;
20974
- if (finalX + contentWidth > viewportWidth) {
20975
- finalX = viewportWidth - contentWidth - 8;
20976
- }
20977
- if (finalX < 8) {
20978
- finalX = 8;
20979
- }
20980
- if (finalY + contentHeight > viewportHeight) {
20981
- finalY = viewportHeight - contentHeight - 8;
20982
- }
20983
- if (finalY < 8) {
20984
- finalY = 8;
20967
+ if (triggerRef != null && triggerRef.current && (positionRef == null ? void 0 : positionRef.current) !== triggerRef.current) {
20968
+ // Update the position tracking to use the trigger element
20969
+ if (positionRef) {
20970
+ positionRef.current = triggerRef.current;
20985
20971
  }
20986
- setOptimalPosition({
20987
- x: finalX,
20988
- y: finalY,
20989
- placement: bestPlacement.placement
20990
- });
20991
20972
  }
20992
- }, [isOpen, side, sideOffset, contentRef, triggerRef]);
20973
+ }, [triggerRef, positionRef, isOpen]);
20993
20974
  var handleMouseEnter = () => cancelCloseTimer(); // Keep card open if mouse enters content
20994
20975
  var handleMouseLeave = () => closeCard();
20995
20976
  if (!isOpen) {
20996
20977
  return null; // Don't render content if not open
20997
20978
  }
20998
- // Create intelligent positioning styles
20999
- var positionStyles = {
21000
- position: 'fixed',
21001
- left: optimalPosition.x,
21002
- top: optimalPosition.y,
21003
- zIndex: 1000
20979
+ // Create intelligent positioning styles based on useElementPosition relation data
20980
+ var getPositionStyles = () => {
20981
+ if (!relation || !(triggerRef != null && triggerRef.current)) {
20982
+ // Fallback positioning if relation data is not available
20983
+ return {
20984
+ position: 'absolute',
20985
+ top: 0,
20986
+ left: 0,
20987
+ zIndex: 1000
20988
+ };
20989
+ }
20990
+ var triggerRect = triggerRef.current.getBoundingClientRect();
20991
+ var placement = side;
20992
+ // Use relation data to determine optimal placement
20993
+ // If preferred side doesn't have enough space, use the side with more space
20994
+ if (side === 'bottom' && relation.space.vertical === 'top') {
20995
+ placement = 'top';
20996
+ } else if (side === 'top' && relation.space.vertical === 'bottom') {
20997
+ placement = 'bottom';
20998
+ } else if (side === 'right' && relation.space.horizontal === 'left') {
20999
+ placement = 'left';
21000
+ } else if (side === 'left' && relation.space.horizontal === 'right') {
21001
+ placement = 'right';
21002
+ }
21003
+ // Calculate position based on optimal placement
21004
+ var x = 0;
21005
+ var y = 0;
21006
+ switch (placement) {
21007
+ case 'bottom':
21008
+ x = triggerRect.left + triggerRect.width / 2;
21009
+ y = triggerRect.bottom + sideOffset;
21010
+ break;
21011
+ case 'top':
21012
+ x = triggerRect.left + triggerRect.width / 2;
21013
+ y = triggerRect.top - sideOffset;
21014
+ break;
21015
+ case 'right':
21016
+ x = triggerRect.right + sideOffset;
21017
+ y = triggerRect.top + triggerRect.height / 2;
21018
+ break;
21019
+ case 'left':
21020
+ x = triggerRect.left - sideOffset;
21021
+ y = triggerRect.top + triggerRect.height / 2;
21022
+ break;
21023
+ }
21024
+ return {
21025
+ position: 'fixed',
21026
+ left: x,
21027
+ top: y,
21028
+ zIndex: 1000,
21029
+ transform: getTransformOrigin(placement)
21030
+ };
21031
+ };
21032
+ // Helper function to set transform origin for better positioning
21033
+ var getTransformOrigin = placement => {
21034
+ switch (placement) {
21035
+ case 'bottom':
21036
+ return 'translate(-50%, 0)';
21037
+ case 'top':
21038
+ return 'translate(-50%, -100%)';
21039
+ case 'right':
21040
+ return 'translate(0, -50%)';
21041
+ case 'left':
21042
+ return 'translate(-100%, -50%)';
21043
+ default:
21044
+ return 'translate(-50%, 0)';
21045
+ }
21004
21046
  };
21047
+ var positionStyles = getPositionStyles();
21005
21048
  return /*#__PURE__*/React__default.createElement(appStudio.View, Object.assign({
21006
21049
  ref: contentRef,
21007
21050
  id: contentId,
@@ -21018,7 +21061,13 @@ var HoverCardContent = _ref3 => {
21018
21061
  maxWidth: maxWidth,
21019
21062
  // Combine intelligent position styles with user styles
21020
21063
  style: Object.assign({}, positionStyles, userStyle)
21021
- }, views == null ? void 0 : views.container, props), children);
21064
+ }, views == null ? void 0 : views.container, props), children, relation && (/*#__PURE__*/React__default.createElement("div", {
21065
+ style: {
21066
+ fontSize: '10px',
21067
+ opacity: 0.7,
21068
+ marginTop: '4px'
21069
+ }
21070
+ }, "Position: ", relation.position.vertical, "-", relation.position.horizontal, /*#__PURE__*/React__default.createElement("br", null), "More space: ", relation.space.vertical, "-", relation.space.horizontal)));
21022
21071
  };
21023
21072
 
21024
21073
  var _excluded$_ = ["children", "views", "openDelay", "closeDelay"];
@@ -24465,108 +24514,102 @@ var TooltipView = _ref4 => {
24465
24514
  contentId,
24466
24515
  triggerId
24467
24516
  } = useTooltipContext();
24517
+ // Use useElementPosition for intelligent positioning
24518
+ var {
24519
+ ref: positionRef,
24520
+ relation
24521
+ } = appStudio.useElementPosition({
24522
+ trackChanges: true,
24523
+ trackOnHover: true,
24524
+ trackOnScroll: true,
24525
+ trackOnResize: true
24526
+ });
24468
24527
  var [optimalPosition, setOptimalPosition] = React.useState({
24469
24528
  x: 0,
24470
24529
  y: 0,
24471
24530
  placement: position
24472
24531
  });
24473
- // Calculate optimal position when the tooltip opens
24532
+ // Sync the position ref with the trigger ref for positioning calculations
24533
+ React.useEffect(() => {
24534
+ if (triggerRef != null && triggerRef.current && positionRef) {
24535
+ positionRef.current = triggerRef.current;
24536
+ }
24537
+ }, [triggerRef, positionRef, isOpen]);
24538
+ // Calculate optimal position using useElementPosition when the tooltip opens
24474
24539
  React.useEffect(() => {
24475
24540
  if (isOpen && contentRef != null && contentRef.current && triggerRef != null && triggerRef.current) {
24476
- var contentRect = contentRef.current.getBoundingClientRect();
24477
24541
  var triggerRect = triggerRef.current.getBoundingClientRect();
24478
- // Get content dimensions
24479
- var contentWidth = Math.max(contentRect.width || 120, 120);
24480
- var contentHeight = Math.max(contentRect.height || 32, 32);
24481
- // Get viewport dimensions
24482
- var viewportWidth = window.innerWidth;
24483
- var viewportHeight = window.innerHeight;
24484
- // Calculate available space on all sides from the trigger
24485
- var availableSpace = {
24486
- top: triggerRect.top,
24487
- right: viewportWidth - triggerRect.right,
24488
- bottom: viewportHeight - triggerRect.bottom,
24489
- left: triggerRect.left
24490
- };
24491
- // Determine optimal placement based on available space and preferred position
24492
- var placements = [{
24493
- placement: 'top',
24494
- space: availableSpace.top,
24495
- fits: availableSpace.top >= contentHeight + 16,
24496
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
24497
- y: triggerRect.top - contentHeight - 8
24498
- }, {
24499
- placement: 'bottom',
24500
- space: availableSpace.bottom,
24501
- fits: availableSpace.bottom >= contentHeight + 16,
24502
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
24503
- y: triggerRect.bottom + 8
24504
- }, {
24505
- placement: 'right',
24506
- space: availableSpace.right,
24507
- fits: availableSpace.right >= contentWidth + 16,
24508
- x: triggerRect.right + 8,
24509
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
24510
- }, {
24511
- placement: 'left',
24512
- space: availableSpace.left,
24513
- fits: availableSpace.left >= contentWidth + 16,
24514
- x: triggerRect.left - contentWidth - 8,
24515
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
24516
- }];
24517
- // First try the preferred position if it fits
24518
- var preferredPlacement = placements.find(p => p.placement === position && p.fits);
24519
- if (preferredPlacement) {
24520
- setOptimalPosition({
24521
- x: preferredPlacement.x,
24522
- y: preferredPlacement.y,
24523
- placement: preferredPlacement.placement
24524
- });
24525
- return;
24526
- }
24527
- // Otherwise, find the best fitting placement
24528
- var fittingPlacement = placements.find(p => p.fits);
24529
- if (fittingPlacement) {
24530
- setOptimalPosition({
24531
- x: fittingPlacement.x,
24532
- y: fittingPlacement.y,
24533
- placement: fittingPlacement.placement
24534
- });
24535
- return;
24536
- }
24537
- // If nothing fits, choose the placement with the most space
24538
- var bestPlacement = placements.reduce((best, current) => current.space > best.space ? current : best);
24539
- // Ensure the content stays within viewport bounds
24540
- var finalX = bestPlacement.x;
24541
- var finalY = bestPlacement.y;
24542
- if (finalX + contentWidth > viewportWidth) {
24543
- finalX = viewportWidth - contentWidth - 8;
24544
- }
24545
- if (finalX < 8) {
24546
- finalX = 8;
24547
- }
24548
- if (finalY + contentHeight > viewportHeight) {
24549
- finalY = viewportHeight - contentHeight - 8;
24542
+ var placement = position;
24543
+ // Use relation data to determine optimal placement
24544
+ if (relation) {
24545
+ // If preferred position doesn't have enough space, use the position with more space
24546
+ if (position === 'top' && relation.space.vertical === 'bottom') {
24547
+ placement = 'bottom';
24548
+ } else if (position === 'bottom' && relation.space.vertical === 'top') {
24549
+ placement = 'top';
24550
+ } else if (position === 'right' && relation.space.horizontal === 'left') {
24551
+ placement = 'left';
24552
+ } else if (position === 'left' && relation.space.horizontal === 'right') {
24553
+ placement = 'right';
24554
+ }
24550
24555
  }
24551
- if (finalY < 8) {
24552
- finalY = 8;
24556
+ // Calculate position based on optimal placement and alignment
24557
+ var x = 0;
24558
+ var y = 0;
24559
+ switch (placement) {
24560
+ case 'top':
24561
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 120 // Estimated content width
24562
+ : triggerRect.left + triggerRect.width / 2 - 60; // Half of estimated width
24563
+ y = triggerRect.top - 8;
24564
+ break;
24565
+ case 'bottom':
24566
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 120 : triggerRect.left + triggerRect.width / 2 - 60;
24567
+ y = triggerRect.bottom + 8;
24568
+ break;
24569
+ case 'right':
24570
+ x = triggerRect.right + 8;
24571
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 32 // Estimated content height
24572
+ : triggerRect.top + triggerRect.height / 2 - 16; // Half of estimated height
24573
+ break;
24574
+ case 'left':
24575
+ x = triggerRect.left - 8;
24576
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 32 : triggerRect.top + triggerRect.height / 2 - 16;
24577
+ break;
24553
24578
  }
24554
24579
  setOptimalPosition({
24555
- x: finalX,
24556
- y: finalY,
24557
- placement: bestPlacement.placement
24580
+ x,
24581
+ y,
24582
+ placement
24558
24583
  });
24559
24584
  }
24560
- }, [isOpen, position, align, triggerRef, contentRef]);
24585
+ }, [isOpen, position, align, triggerRef, contentRef, relation]);
24561
24586
  // Get arrow styles based on optimal placement
24562
24587
  var arrowStyles = showArrow ? getArrowStyles(optimalPosition.placement) : {};
24563
- // Create intelligent positioning styles
24564
- var positionStyles = {
24565
- position: 'fixed',
24566
- left: optimalPosition.x,
24567
- top: optimalPosition.y,
24568
- zIndex: 1000
24588
+ // Create intelligent positioning styles with transform for better placement
24589
+ var getPositionStyles = () => {
24590
+ var baseStyles = {
24591
+ position: 'fixed',
24592
+ left: optimalPosition.x,
24593
+ top: optimalPosition.y,
24594
+ zIndex: 1000
24595
+ };
24596
+ // Add transform based on placement for better positioning
24597
+ switch (optimalPosition.placement) {
24598
+ case 'top':
24599
+ return Object.assign({}, baseStyles, {
24600
+ transform: 'translateY(-100%)'
24601
+ });
24602
+ case 'left':
24603
+ return Object.assign({}, baseStyles, {
24604
+ transform: 'translateX(-100%)'
24605
+ });
24606
+ case 'bottom':
24607
+ case 'right':
24608
+ default:
24609
+ return baseStyles;
24610
+ }
24569
24611
  };
24612
+ var positionStyles = getPositionStyles();
24570
24613
  return /*#__PURE__*/React__default.createElement(appStudio.View, Object.assign({
24571
24614
  position: "relative",
24572
24615
  display: "inline-block"
@@ -24578,7 +24621,13 @@ var TooltipView = _ref4 => {
24578
24621
  borderRadius: 4,
24579
24622
  boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.15)",
24580
24623
  style: positionStyles
24581
- }, TooltipSizes[size], TooltipVariants[variant], views == null ? void 0 : views.content), typeof content === 'string' ? (/*#__PURE__*/React__default.createElement(appStudio.Text, Object.assign({}, views == null ? void 0 : views.text), content)) : content, showArrow && /*#__PURE__*/React__default.createElement(appStudio.View, Object.assign({}, arrowStyles, views == null ? void 0 : views.arrow)))));
24624
+ }, TooltipSizes[size], TooltipVariants[variant], views == null ? void 0 : views.content), typeof content === 'string' ? (/*#__PURE__*/React__default.createElement(appStudio.Text, Object.assign({}, views == null ? void 0 : views.text), content)) : content, showArrow && /*#__PURE__*/React__default.createElement(appStudio.View, Object.assign({}, arrowStyles, views == null ? void 0 : views.arrow)), (/*#__PURE__*/React__default.createElement("div", {
24625
+ style: {
24626
+ fontSize: '8px',
24627
+ opacity: 0.7,
24628
+ marginTop: '2px'
24629
+ }
24630
+ }, "Placement: ", optimalPosition.placement, relation && (/*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal)))))));
24582
24631
  };
24583
24632
 
24584
24633
  var _excluded$1b = ["content", "children", "position", "align", "size", "variant", "openDelay", "closeDelay", "showArrow", "defaultOpen", "isDisabled", "views"];