@app-studio/web 0.9.13 → 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.
package/dist/web.esm.js CHANGED
@@ -5735,6 +5735,24 @@ var PieChart = _ref => {
5735
5735
  var {
5736
5736
  getColor
5737
5737
  } = useTheme();
5738
+ // Use useElementPosition for intelligent tooltip positioning
5739
+ var {
5740
+ ref: positionRef,
5741
+ relation
5742
+ } = useElementPosition({
5743
+ trackChanges: true,
5744
+ trackOnHover: true,
5745
+ trackOnScroll: true,
5746
+ trackOnResize: true
5747
+ });
5748
+ // Create a separate ref for the SVG element
5749
+ var chartRef = useRef(null);
5750
+ // Sync the position ref with the chart ref for positioning calculations
5751
+ useEffect(() => {
5752
+ if (chartRef.current && positionRef) {
5753
+ positionRef.current = chartRef.current;
5754
+ }
5755
+ }, [chartRef, positionRef]);
5738
5756
  // Calculate chart dimensions
5739
5757
  var size = Math.min(width, height);
5740
5758
  var radius = size / 2 * 0.8;
@@ -5803,12 +5821,30 @@ var PieChart = _ref => {
5803
5821
  return result;
5804
5822
  }, [dataPoints, total, radius, centerX, centerY, donutRadius, animationProgress, isDonut]);
5805
5823
  return /*#__PURE__*/React.createElement("svg", {
5824
+ ref: chartRef,
5806
5825
  width: width,
5807
5826
  height: height
5808
5827
  }, slices.map((slice, index) => {
5809
5828
  var handleMouseEnter = e => {
5810
5829
  var tooltipContent = slice.label + ": " + slice.value + " (" + slice.percentage + ")";
5811
- showTooltip(e.clientX, e.clientY, tooltipContent);
5830
+ // Use intelligent positioning based on useElementPosition relation data
5831
+ var x = e.clientX;
5832
+ var y = e.clientY;
5833
+ if (relation && chartRef.current) {
5834
+ var chartRect = chartRef.current.getBoundingClientRect();
5835
+ // Adjust tooltip position based on available space
5836
+ if (relation.space.horizontal === 'left') {
5837
+ x = e.clientX - 100; // Offset tooltip to the left
5838
+ } else {
5839
+ x = e.clientX + 10; // Offset tooltip to the right
5840
+ }
5841
+ if (relation.space.vertical === 'top') {
5842
+ y = e.clientY - 30; // Offset tooltip above
5843
+ } else {
5844
+ y = e.clientY + 10; // Offset tooltip below
5845
+ }
5846
+ }
5847
+ showTooltip(x, y, tooltipContent);
5812
5848
  };
5813
5849
  var handleClick = () => {
5814
5850
  if (onSliceClick) {
@@ -13104,6 +13140,16 @@ var EditableInput = /*#__PURE__*/forwardRef((_ref, ref) => {
13104
13140
  var [mentionStartPos, setMentionStartPos] = useState(-1);
13105
13141
  var [selectedMentionIndex, setSelectedMentionIndex] = useState(-1);
13106
13142
  var [filteredMentions, setFilteredMentions] = useState([]);
13143
+ // Use useElementPosition for intelligent dropdown positioning
13144
+ var {
13145
+ ref: positionRef,
13146
+ relation
13147
+ } = useElementPosition({
13148
+ trackChanges: true,
13149
+ trackOnHover: true,
13150
+ trackOnScroll: true,
13151
+ trackOnResize: true
13152
+ });
13107
13153
  // Positioning state for dropdowns
13108
13154
  var [mentionPosition, setMentionPosition] = useState({
13109
13155
  x: 0,
@@ -13113,7 +13159,6 @@ var EditableInput = /*#__PURE__*/forwardRef((_ref, ref) => {
13113
13159
  x: 0,
13114
13160
  y: 0
13115
13161
  });
13116
- // Note: Using custom positioning logic for better control over dropdown placement
13117
13162
  // Update the content of the editable div when the value prop changes
13118
13163
  useEffect(() => {
13119
13164
  var editableDiv = ref;
@@ -13165,7 +13210,13 @@ var EditableInput = /*#__PURE__*/forwardRef((_ref, ref) => {
13165
13210
  setMentionStartPos(-1);
13166
13211
  setSelectedMentionIndex(-1);
13167
13212
  }, [mentionData, mentionTrigger]);
13168
- // Calculate optimal position for dropdowns
13213
+ // Sync the position ref with the container ref for positioning calculations
13214
+ useEffect(() => {
13215
+ if (containerRef.current && positionRef) {
13216
+ positionRef.current = containerRef.current;
13217
+ }
13218
+ }, [containerRef, positionRef]);
13219
+ // Calculate optimal position for dropdowns using useElementPosition
13169
13220
  var calculateDropdownPosition = useCallback(function (dropdownHeight) {
13170
13221
  if (dropdownHeight === void 0) {
13171
13222
  dropdownHeight = 200;
@@ -13175,22 +13226,26 @@ var EditableInput = /*#__PURE__*/forwardRef((_ref, ref) => {
13175
13226
  y: 0
13176
13227
  };
13177
13228
  var containerRect = containerRef.current.getBoundingClientRect();
13229
+ // Use relation data for intelligent positioning if available
13230
+ if (relation) {
13231
+ var _useTopPlacement = relation.space.vertical === 'top';
13232
+ return {
13233
+ x: containerRect.left,
13234
+ y: _useTopPlacement ? containerRect.top - dropdownHeight - 8 : containerRect.bottom + 8
13235
+ };
13236
+ }
13237
+ // Fallback to manual calculation if relation data is not available
13178
13238
  var viewportHeight = window.innerHeight;
13179
- var viewportWidth = window.innerWidth;
13180
- // Calculate available space
13181
13239
  var availableSpace = {
13182
13240
  top: containerRect.top,
13183
- bottom: viewportHeight - containerRect.bottom,
13184
- left: containerRect.left,
13185
- right: viewportWidth - containerRect.right
13241
+ bottom: viewportHeight - containerRect.bottom
13186
13242
  };
13187
- // Prefer bottom placement, but use top if not enough space
13188
13243
  var useTopPlacement = availableSpace.bottom < dropdownHeight + 8 && availableSpace.top > availableSpace.bottom;
13189
13244
  return {
13190
13245
  x: containerRect.left,
13191
13246
  y: useTopPlacement ? containerRect.top - dropdownHeight - 8 : containerRect.bottom + 8
13192
13247
  };
13193
- }, []);
13248
+ }, [relation]);
13194
13249
  // Handle focus events
13195
13250
  var handleFocus = useCallback(() => {
13196
13251
  setIsFocused(true);
@@ -13396,7 +13451,7 @@ var EditableInput = /*#__PURE__*/forwardRef((_ref, ref) => {
13396
13451
  opacity: 0.7,
13397
13452
  padding: '4px'
13398
13453
  }
13399
- }, "Mentions (Trigger: ", mentionTrigger, ")"))))), showSuggestions && suggestions.length > 0 && !showMentions && isFocused && !value && (/*#__PURE__*/React.createElement(View, Object.assign({
13454
+ }, "Mentions (Trigger: ", mentionTrigger, ")", relation && (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal))))))), showSuggestions && suggestions.length > 0 && !showMentions && isFocused && !value && (/*#__PURE__*/React.createElement(View, Object.assign({
13400
13455
  position: "fixed",
13401
13456
  left: suggestionPosition.x,
13402
13457
  top: suggestionPosition.y,
@@ -13442,7 +13497,7 @@ var EditableInput = /*#__PURE__*/forwardRef((_ref, ref) => {
13442
13497
  opacity: 0.7,
13443
13498
  padding: '4px'
13444
13499
  }
13445
- }, "Suggestions (Focus-triggered)"))))));
13500
+ }, "Suggestions (Focus-triggered)", relation && (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal))))))));
13446
13501
  });
13447
13502
  EditableInput.displayName = 'EditableInput';
13448
13503
 
@@ -17029,8 +17084,78 @@ var useToggleState = defaultToggled => {
17029
17084
  };
17030
17085
  };
17031
17086
 
17032
- var _excluded$T = ["children", "shape", "variant", "isHovered", "setIsHovered", "isDisabled", "isToggle", "setIsToggled", "onToggle", "views"];
17087
+ var ToggleShapes = {
17088
+ sharp: 0,
17089
+ rounded: 4,
17090
+ pillShaped: 24
17091
+ };
17092
+ /**
17093
+ * Generate toggle variants with proper color combinations based on main color and contrast
17094
+ * Similar to Button's getButtonVariants function
17095
+ */
17096
+ var getToggleVariants = (color, isLight) => ({
17097
+ outline: {
17098
+ backgroundColor: 'transparent',
17099
+ color: color,
17100
+ borderWidth: 1,
17101
+ borderStyle: 'solid',
17102
+ borderColor: color,
17103
+ _hover: {
17104
+ backgroundColor: color,
17105
+ color: isLight ? 'color.black' : 'color.white',
17106
+ transform: 'translateY(-1px)'
17107
+ },
17108
+ _active: {
17109
+ backgroundColor: color,
17110
+ color: isLight ? 'color.black' : 'color.white',
17111
+ transform: 'translateY(0)'
17112
+ },
17113
+ transition: 'all 0.2s ease'
17114
+ },
17115
+ ghost: {
17116
+ backgroundColor: 'transparent',
17117
+ color: color,
17118
+ borderWidth: 0,
17119
+ borderStyle: 'none',
17120
+ borderColor: 'transparent',
17121
+ _hover: {
17122
+ backgroundColor: color,
17123
+ color: isLight ? 'color.black' : 'color.white',
17124
+ transform: 'translateY(-1px)'
17125
+ },
17126
+ _active: {
17127
+ backgroundColor: color,
17128
+ color: isLight ? 'color.black' : 'color.white',
17129
+ transform: 'translateY(0)'
17130
+ },
17131
+ transition: 'all 0.2s ease'
17132
+ },
17133
+ link: {
17134
+ backgroundColor: 'transparent',
17135
+ color: color,
17136
+ borderWidth: 1,
17137
+ borderStyle: 'solid',
17138
+ borderColor: 'transparent',
17139
+ textDecoration: 'underline',
17140
+ textUnderlineOffset: '1px',
17141
+ textDecorationThickness: '1px',
17142
+ _hover: {
17143
+ borderColor: color,
17144
+ textDecorationThickness: '2px',
17145
+ transform: 'translateY(-1px)'
17146
+ },
17147
+ _active: {
17148
+ borderColor: color,
17149
+ textDecorationThickness: '2px',
17150
+ transform: 'translateY(0)'
17151
+ },
17152
+ transition: 'all 0.2s ease'
17153
+ }
17154
+ });
17155
+
17156
+ var _excluded$T = ["children", "shape", "variant", "isHovered", "setIsHovered", "isDisabled", "isToggle", "setIsToggled", "onToggle", "views", "backgroundColor", "color", "themeMode"];
17033
17157
  var ToggleView = _ref => {
17158
+ var _ref2;
17034
17159
  var {
17035
17160
  children,
17036
17161
  shape = 'rounded',
@@ -17041,25 +17166,30 @@ var ToggleView = _ref => {
17041
17166
  isToggle,
17042
17167
  setIsToggled,
17043
17168
  onToggle,
17044
- views
17169
+ views,
17170
+ backgroundColor,
17171
+ // primary candidate for main color
17172
+ color,
17173
+ // 2nd candidate for main color
17174
+ themeMode: elementMode
17045
17175
  } = _ref,
17046
17176
  props = _objectWithoutPropertiesLoose(_ref, _excluded$T);
17047
- var toggleColor = !isDisabled ? 'color.trueGray.400' : 'theme.disabled';
17177
+ /* theme helpers */
17178
+ var {
17179
+ getColor,
17180
+ themeMode
17181
+ } = useTheme();
17182
+ var mode = elementMode != null ? elementMode : themeMode;
17183
+ /* MAIN COLOR – determines the entire palette */
17184
+ var mainColorKey = (_ref2 = backgroundColor != null ? backgroundColor : color) != null ? _ref2 : 'theme.primary';
17185
+ var mainTone = getColor(isDisabled ? 'theme.disabled' : mainColorKey, {
17186
+ themeMode: mode
17187
+ });
17188
+ var tone = contrast(mainTone);
17189
+ /* variant palette */
17190
+ var palette = useMemo(() => getToggleVariants(mainTone, tone === 'light'), [mainTone, tone]);
17191
+ var base = palette[variant];
17048
17192
  var isActive = !!(isToggle || isHovered);
17049
- var toggleVariants = {
17050
- outline: {
17051
- borderWidth: 1,
17052
- borderStyle: 'solid',
17053
- borderColor: 'color.trueGray.400'
17054
- },
17055
- link: {
17056
- borderWidth: 1,
17057
- borderStyle: 'solid',
17058
- borderColor: isActive ? toggleColor : 'transparent',
17059
- textDecoration: 'underline'
17060
- },
17061
- ghost: {}
17062
- };
17063
17193
  var handleHover = () => setIsHovered(!isHovered);
17064
17194
  var handleToggle = () => {
17065
17195
  if (!isDisabled) {
@@ -17076,14 +17206,15 @@ var ToggleView = _ref => {
17076
17206
  role: "Toggle",
17077
17207
  padding: shape === 'pillShaped' ? '10px 12px' : '8px',
17078
17208
  width: "fit-content",
17079
- color: isActive ? 'color.white' : toggleColor,
17080
- backgroundColor: isActive ? toggleColor : 'transparent',
17081
- onMouseEnter: handleHover,
17082
- onMouseLeave: () => setIsHovered(false),
17083
17209
  cursor: isDisabled ? 'not-allowed' : 'pointer',
17084
- borderRadius: shape === 'pillShaped' ? '50px' : '8px',
17085
- onClick: handleToggle
17086
- }, toggleVariants[variant], props, views == null ? void 0 : views.container), children);
17210
+ borderRadius: ToggleShapes[shape],
17211
+ onClick: handleToggle,
17212
+ onMouseEnter: handleHover,
17213
+ onMouseLeave: () => setIsHovered(false)
17214
+ }, base, isActive && {
17215
+ backgroundColor: mainTone,
17216
+ color: tone === 'light' ? 'color.black' : 'color.white'
17217
+ }, props, views == null ? void 0 : views.container), children);
17087
17218
  };
17088
17219
 
17089
17220
  var _excluded$U = ["children", "shape", "variant", "isDisabled", "isToggled", "onToggle"];
@@ -17508,109 +17639,103 @@ var DropdownMenuContent = _ref3 => {
17508
17639
  triggerRef
17509
17640
  } = useDropdownMenuContext();
17510
17641
  var contentRef = useRef(null);
17642
+ // Use useElementPosition for intelligent positioning
17643
+ var {
17644
+ ref: positionRef,
17645
+ relation
17646
+ } = useElementPosition({
17647
+ trackChanges: true,
17648
+ trackOnHover: true,
17649
+ trackOnScroll: true,
17650
+ trackOnResize: true
17651
+ });
17511
17652
  var [optimalPosition, setOptimalPosition] = useState({
17512
17653
  x: 0,
17513
17654
  y: 0,
17514
17655
  placement: side
17515
17656
  });
17516
- // Calculate optimal position when the dropdown opens
17657
+ // Sync the position ref with the trigger ref for positioning calculations
17658
+ useEffect(() => {
17659
+ if (triggerRef.current && positionRef) {
17660
+ positionRef.current = triggerRef.current;
17661
+ }
17662
+ }, [triggerRef, positionRef, isOpen]);
17663
+ // Calculate optimal position using useElementPosition when the dropdown opens
17517
17664
  useEffect(() => {
17518
17665
  if (isOpen && contentRef.current && triggerRef.current) {
17519
- var contentRect = contentRef.current.getBoundingClientRect();
17520
17666
  var triggerRect = triggerRef.current.getBoundingClientRect();
17521
- // Get content dimensions
17522
- var contentWidth = Math.max(contentRect.width || 180, 180);
17523
- var contentHeight = Math.max(contentRect.height || 100, 100);
17524
- // Get viewport dimensions
17525
- var viewportWidth = window.innerWidth;
17526
- var viewportHeight = window.innerHeight;
17527
- // Calculate available space on all sides from the trigger
17528
- var availableSpace = {
17529
- top: triggerRect.top,
17530
- right: viewportWidth - triggerRect.right,
17531
- bottom: viewportHeight - triggerRect.bottom,
17532
- left: triggerRect.left
17533
- };
17534
- // Determine optimal placement based on available space and preferred side
17535
- var placements = [{
17536
- placement: 'bottom',
17537
- space: availableSpace.bottom,
17538
- fits: availableSpace.bottom >= contentHeight + 8,
17539
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
17540
- y: triggerRect.bottom + 8
17541
- }, {
17542
- placement: 'top',
17543
- space: availableSpace.top,
17544
- fits: availableSpace.top >= contentHeight + 8,
17545
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
17546
- y: triggerRect.top - contentHeight - 8
17547
- }, {
17548
- placement: 'right',
17549
- space: availableSpace.right,
17550
- fits: availableSpace.right >= contentWidth + 8,
17551
- x: triggerRect.right + 8,
17552
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
17553
- }, {
17554
- placement: 'left',
17555
- space: availableSpace.left,
17556
- fits: availableSpace.left >= contentWidth + 8,
17557
- x: triggerRect.left - contentWidth - 8,
17558
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
17559
- }];
17560
- // First try the preferred side if it fits
17561
- var preferredPlacement = placements.find(p => p.placement === side && p.fits);
17562
- if (preferredPlacement) {
17563
- setOptimalPosition({
17564
- x: preferredPlacement.x,
17565
- y: preferredPlacement.y,
17566
- placement: preferredPlacement.placement
17567
- });
17568
- return;
17569
- }
17570
- // Otherwise, find the best fitting placement
17571
- var fittingPlacement = placements.find(p => p.fits);
17572
- if (fittingPlacement) {
17573
- setOptimalPosition({
17574
- x: fittingPlacement.x,
17575
- y: fittingPlacement.y,
17576
- placement: fittingPlacement.placement
17577
- });
17578
- return;
17579
- }
17580
- // If nothing fits, choose the placement with the most space
17581
- var bestPlacement = placements.reduce((best, current) => current.space > best.space ? current : best);
17582
- // Ensure the content stays within viewport bounds
17583
- var finalX = bestPlacement.x;
17584
- var finalY = bestPlacement.y;
17585
- if (finalX + contentWidth > viewportWidth) {
17586
- finalX = viewportWidth - contentWidth - 8;
17587
- }
17588
- if (finalX < 8) {
17589
- finalX = 8;
17667
+ var placement = side;
17668
+ // Use relation data to determine optimal placement
17669
+ if (relation) {
17670
+ // If preferred side doesn't have enough space, use the side with more space
17671
+ if (side === 'bottom' && relation.space.vertical === 'top') {
17672
+ placement = 'top';
17673
+ } else if (side === 'top' && relation.space.vertical === 'bottom') {
17674
+ placement = 'bottom';
17675
+ } else if (side === 'right' && relation.space.horizontal === 'left') {
17676
+ placement = 'left';
17677
+ } else if (side === 'left' && relation.space.horizontal === 'right') {
17678
+ placement = 'right';
17679
+ }
17590
17680
  }
17591
- if (finalY + contentHeight > viewportHeight) {
17592
- finalY = viewportHeight - contentHeight - 8;
17593
- }
17594
- if (finalY < 8) {
17595
- finalY = 8;
17681
+ // Calculate position based on optimal placement and alignment
17682
+ var x = 0;
17683
+ var y = 0;
17684
+ switch (placement) {
17685
+ case 'bottom':
17686
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 180 // Estimated content width
17687
+ : triggerRect.left + triggerRect.width / 2 - 90; // Half of estimated width
17688
+ y = triggerRect.bottom + 8;
17689
+ break;
17690
+ case 'top':
17691
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 180 : triggerRect.left + triggerRect.width / 2 - 90;
17692
+ y = triggerRect.top - 8; // Will be adjusted with transform
17693
+ break;
17694
+ case 'right':
17695
+ x = triggerRect.right + 8;
17696
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 100 // Estimated content height
17697
+ : triggerRect.top + triggerRect.height / 2 - 50; // Half of estimated height
17698
+ break;
17699
+ case 'left':
17700
+ x = triggerRect.left - 8; // Will be adjusted with transform
17701
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 100 : triggerRect.top + triggerRect.height / 2 - 50;
17702
+ break;
17596
17703
  }
17597
17704
  setOptimalPosition({
17598
- x: finalX,
17599
- y: finalY,
17600
- placement: bestPlacement.placement
17705
+ x,
17706
+ y,
17707
+ placement
17601
17708
  });
17602
17709
  }
17603
- }, [isOpen, side, align, triggerRef]);
17710
+ }, [isOpen, side, align, triggerRef, relation]);
17604
17711
  if (!isOpen) {
17605
17712
  return null;
17606
17713
  }
17607
- // Create intelligent positioning styles
17608
- var positionStyles = {
17609
- position: 'fixed',
17610
- left: optimalPosition.x,
17611
- top: optimalPosition.y,
17612
- zIndex: 1000
17714
+ // Create intelligent positioning styles with transform for better placement
17715
+ var getPositionStyles = () => {
17716
+ var baseStyles = {
17717
+ position: 'fixed',
17718
+ left: optimalPosition.x,
17719
+ top: optimalPosition.y,
17720
+ zIndex: 1000
17721
+ };
17722
+ // Add transform based on placement for better positioning
17723
+ switch (optimalPosition.placement) {
17724
+ case 'top':
17725
+ return Object.assign({}, baseStyles, {
17726
+ transform: 'translateY(-100%)'
17727
+ });
17728
+ case 'left':
17729
+ return Object.assign({}, baseStyles, {
17730
+ transform: 'translateX(-100%)'
17731
+ });
17732
+ case 'bottom':
17733
+ case 'right':
17734
+ default:
17735
+ return baseStyles;
17736
+ }
17613
17737
  };
17738
+ var positionStyles = getPositionStyles();
17614
17739
  return /*#__PURE__*/React.createElement(View, Object.assign({
17615
17740
  ref: contentRef,
17616
17741
  id: "dropdown-menu",
@@ -17630,7 +17755,13 @@ var DropdownMenuContent = _ref3 => {
17630
17755
  item: item,
17631
17756
  views: views
17632
17757
  });
17633
- }));
17758
+ }), process.env.NODE_ENV === 'development' && (/*#__PURE__*/React.createElement("div", {
17759
+ style: {
17760
+ fontSize: '10px',
17761
+ opacity: 0.7,
17762
+ padding: '4px'
17763
+ }
17764
+ }, "Placement: ", optimalPosition.placement, relation && (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal)))));
17634
17765
  };
17635
17766
  // DropdownMenu Item component
17636
17767
  var DropdownMenuItem = _ref4 => {
@@ -20814,111 +20945,99 @@ var HoverCardContent = _ref3 => {
20814
20945
  contentId,
20815
20946
  triggerId
20816
20947
  } = useHoverCardContext();
20817
- var [optimalPosition, setOptimalPosition] = useState({
20818
- x: 0,
20819
- y: 0,
20820
- placement: side
20948
+ // Use useElementPosition for intelligent positioning
20949
+ var {
20950
+ ref: positionRef,
20951
+ relation
20952
+ } = useElementPosition({
20953
+ trackChanges: true,
20954
+ trackOnHover: true,
20955
+ trackOnScroll: true,
20956
+ trackOnResize: true
20821
20957
  });
20822
- // Calculate optimal position when the card opens or content dimensions change
20958
+ // Sync the position ref with the trigger ref for positioning calculations
20823
20959
  useEffect(() => {
20824
- if (isOpen && contentRef != null && contentRef.current && triggerRef != null && triggerRef.current) {
20825
- var contentRect = contentRef.current.getBoundingClientRect();
20826
- var triggerRect = triggerRef.current.getBoundingClientRect();
20827
- // Get content dimensions
20828
- var contentWidth = Math.max(contentRect.width || 200, 200);
20829
- var contentHeight = Math.max(contentRect.height || 100, 100);
20830
- // Get viewport dimensions
20831
- var viewportWidth = window.innerWidth;
20832
- var viewportHeight = window.innerHeight;
20833
- // Calculate available space on all sides from the trigger
20834
- var availableSpace = {
20835
- top: triggerRect.top,
20836
- right: viewportWidth - triggerRect.right,
20837
- bottom: viewportHeight - triggerRect.bottom,
20838
- left: triggerRect.left
20839
- };
20840
- // Determine optimal placement based on available space and preferred side
20841
- var placements = [{
20842
- placement: 'bottom',
20843
- space: availableSpace.bottom,
20844
- fits: availableSpace.bottom >= contentHeight + sideOffset,
20845
- x: triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
20846
- y: triggerRect.bottom + sideOffset
20847
- }, {
20848
- placement: 'top',
20849
- space: availableSpace.top,
20850
- fits: availableSpace.top >= contentHeight + sideOffset,
20851
- x: triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
20852
- y: triggerRect.top - contentHeight - sideOffset
20853
- }, {
20854
- placement: 'right',
20855
- space: availableSpace.right,
20856
- fits: availableSpace.right >= contentWidth + sideOffset,
20857
- x: triggerRect.right + sideOffset,
20858
- y: triggerRect.top + triggerRect.height / 2 - contentHeight / 2
20859
- }, {
20860
- placement: 'left',
20861
- space: availableSpace.left,
20862
- fits: availableSpace.left >= contentWidth + sideOffset,
20863
- x: triggerRect.left - contentWidth - sideOffset,
20864
- y: triggerRect.top + triggerRect.height / 2 - contentHeight / 2
20865
- }];
20866
- // First try the preferred side if it fits
20867
- var preferredPlacement = placements.find(p => p.placement === side && p.fits);
20868
- if (preferredPlacement) {
20869
- setOptimalPosition({
20870
- x: preferredPlacement.x,
20871
- y: preferredPlacement.y,
20872
- placement: preferredPlacement.placement
20873
- });
20874
- return;
20960
+ if (triggerRef != null && triggerRef.current && (positionRef == null ? void 0 : positionRef.current) !== triggerRef.current) {
20961
+ // Update the position tracking to use the trigger element
20962
+ if (positionRef) {
20963
+ positionRef.current = triggerRef.current;
20875
20964
  }
20876
- // Otherwise, find the best fitting placement
20877
- var fittingPlacement = placements.find(p => p.fits);
20878
- if (fittingPlacement) {
20879
- setOptimalPosition({
20880
- x: fittingPlacement.x,
20881
- y: fittingPlacement.y,
20882
- placement: fittingPlacement.placement
20883
- });
20884
- return;
20885
- }
20886
- // If nothing fits, choose the placement with the most space
20887
- var bestPlacement = placements.reduce((best, current) => current.space > best.space ? current : best);
20888
- // Ensure the content stays within viewport bounds
20889
- var finalX = bestPlacement.x;
20890
- var finalY = bestPlacement.y;
20891
- if (finalX + contentWidth > viewportWidth) {
20892
- finalX = viewportWidth - contentWidth - 8;
20893
- }
20894
- if (finalX < 8) {
20895
- finalX = 8;
20896
- }
20897
- if (finalY + contentHeight > viewportHeight) {
20898
- finalY = viewportHeight - contentHeight - 8;
20899
- }
20900
- if (finalY < 8) {
20901
- finalY = 8;
20902
- }
20903
- setOptimalPosition({
20904
- x: finalX,
20905
- y: finalY,
20906
- placement: bestPlacement.placement
20907
- });
20908
20965
  }
20909
- }, [isOpen, side, sideOffset, contentRef, triggerRef]);
20966
+ }, [triggerRef, positionRef, isOpen]);
20910
20967
  var handleMouseEnter = () => cancelCloseTimer(); // Keep card open if mouse enters content
20911
20968
  var handleMouseLeave = () => closeCard();
20912
20969
  if (!isOpen) {
20913
20970
  return null; // Don't render content if not open
20914
20971
  }
20915
- // Create intelligent positioning styles
20916
- var positionStyles = {
20917
- position: 'fixed',
20918
- left: optimalPosition.x,
20919
- top: optimalPosition.y,
20920
- zIndex: 1000
20972
+ // Create intelligent positioning styles based on useElementPosition relation data
20973
+ var getPositionStyles = () => {
20974
+ if (!relation || !(triggerRef != null && triggerRef.current)) {
20975
+ // Fallback positioning if relation data is not available
20976
+ return {
20977
+ position: 'absolute',
20978
+ top: 0,
20979
+ left: 0,
20980
+ zIndex: 1000
20981
+ };
20982
+ }
20983
+ var triggerRect = triggerRef.current.getBoundingClientRect();
20984
+ var placement = side;
20985
+ // Use relation data to determine optimal placement
20986
+ // If preferred side doesn't have enough space, use the side with more space
20987
+ if (side === 'bottom' && relation.space.vertical === 'top') {
20988
+ placement = 'top';
20989
+ } else if (side === 'top' && relation.space.vertical === 'bottom') {
20990
+ placement = 'bottom';
20991
+ } else if (side === 'right' && relation.space.horizontal === 'left') {
20992
+ placement = 'left';
20993
+ } else if (side === 'left' && relation.space.horizontal === 'right') {
20994
+ placement = 'right';
20995
+ }
20996
+ // Calculate position based on optimal placement
20997
+ var x = 0;
20998
+ var y = 0;
20999
+ switch (placement) {
21000
+ case 'bottom':
21001
+ x = triggerRect.left + triggerRect.width / 2;
21002
+ y = triggerRect.bottom + sideOffset;
21003
+ break;
21004
+ case 'top':
21005
+ x = triggerRect.left + triggerRect.width / 2;
21006
+ y = triggerRect.top - sideOffset;
21007
+ break;
21008
+ case 'right':
21009
+ x = triggerRect.right + sideOffset;
21010
+ y = triggerRect.top + triggerRect.height / 2;
21011
+ break;
21012
+ case 'left':
21013
+ x = triggerRect.left - sideOffset;
21014
+ y = triggerRect.top + triggerRect.height / 2;
21015
+ break;
21016
+ }
21017
+ return {
21018
+ position: 'fixed',
21019
+ left: x,
21020
+ top: y,
21021
+ zIndex: 1000,
21022
+ transform: getTransformOrigin(placement)
21023
+ };
20921
21024
  };
21025
+ // Helper function to set transform origin for better positioning
21026
+ var getTransformOrigin = placement => {
21027
+ switch (placement) {
21028
+ case 'bottom':
21029
+ return 'translate(-50%, 0)';
21030
+ case 'top':
21031
+ return 'translate(-50%, -100%)';
21032
+ case 'right':
21033
+ return 'translate(0, -50%)';
21034
+ case 'left':
21035
+ return 'translate(-100%, -50%)';
21036
+ default:
21037
+ return 'translate(-50%, 0)';
21038
+ }
21039
+ };
21040
+ var positionStyles = getPositionStyles();
20922
21041
  return /*#__PURE__*/React.createElement(View, Object.assign({
20923
21042
  ref: contentRef,
20924
21043
  id: contentId,
@@ -20935,7 +21054,13 @@ var HoverCardContent = _ref3 => {
20935
21054
  maxWidth: maxWidth,
20936
21055
  // Combine intelligent position styles with user styles
20937
21056
  style: Object.assign({}, positionStyles, userStyle)
20938
- }, views == null ? void 0 : views.container, props), children);
21057
+ }, views == null ? void 0 : views.container, props), children, process.env.NODE_ENV === 'development' && relation && (/*#__PURE__*/React.createElement("div", {
21058
+ style: {
21059
+ fontSize: '10px',
21060
+ opacity: 0.7,
21061
+ marginTop: '4px'
21062
+ }
21063
+ }, "Position: ", relation.position.vertical, "-", relation.position.horizontal, /*#__PURE__*/React.createElement("br", null), "More space: ", relation.space.vertical, "-", relation.space.horizontal)));
20939
21064
  };
20940
21065
 
20941
21066
  var _excluded$_ = ["children", "views", "openDelay", "closeDelay"];
@@ -24382,108 +24507,102 @@ var TooltipView = _ref4 => {
24382
24507
  contentId,
24383
24508
  triggerId
24384
24509
  } = useTooltipContext();
24510
+ // Use useElementPosition for intelligent positioning
24511
+ var {
24512
+ ref: positionRef,
24513
+ relation
24514
+ } = useElementPosition({
24515
+ trackChanges: true,
24516
+ trackOnHover: true,
24517
+ trackOnScroll: true,
24518
+ trackOnResize: true
24519
+ });
24385
24520
  var [optimalPosition, setOptimalPosition] = useState({
24386
24521
  x: 0,
24387
24522
  y: 0,
24388
24523
  placement: position
24389
24524
  });
24390
- // Calculate optimal position when the tooltip opens
24525
+ // Sync the position ref with the trigger ref for positioning calculations
24526
+ useEffect(() => {
24527
+ if (triggerRef != null && triggerRef.current && positionRef) {
24528
+ positionRef.current = triggerRef.current;
24529
+ }
24530
+ }, [triggerRef, positionRef, isOpen]);
24531
+ // Calculate optimal position using useElementPosition when the tooltip opens
24391
24532
  useEffect(() => {
24392
24533
  if (isOpen && contentRef != null && contentRef.current && triggerRef != null && triggerRef.current) {
24393
- var contentRect = contentRef.current.getBoundingClientRect();
24394
24534
  var triggerRect = triggerRef.current.getBoundingClientRect();
24395
- // Get content dimensions
24396
- var contentWidth = Math.max(contentRect.width || 120, 120);
24397
- var contentHeight = Math.max(contentRect.height || 32, 32);
24398
- // Get viewport dimensions
24399
- var viewportWidth = window.innerWidth;
24400
- var viewportHeight = window.innerHeight;
24401
- // Calculate available space on all sides from the trigger
24402
- var availableSpace = {
24403
- top: triggerRect.top,
24404
- right: viewportWidth - triggerRect.right,
24405
- bottom: viewportHeight - triggerRect.bottom,
24406
- left: triggerRect.left
24407
- };
24408
- // Determine optimal placement based on available space and preferred position
24409
- var placements = [{
24410
- placement: 'top',
24411
- space: availableSpace.top,
24412
- fits: availableSpace.top >= contentHeight + 16,
24413
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
24414
- y: triggerRect.top - contentHeight - 8
24415
- }, {
24416
- placement: 'bottom',
24417
- space: availableSpace.bottom,
24418
- fits: availableSpace.bottom >= contentHeight + 16,
24419
- x: align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - contentWidth : triggerRect.left + triggerRect.width / 2 - contentWidth / 2,
24420
- y: triggerRect.bottom + 8
24421
- }, {
24422
- placement: 'right',
24423
- space: availableSpace.right,
24424
- fits: availableSpace.right >= contentWidth + 16,
24425
- x: triggerRect.right + 8,
24426
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
24427
- }, {
24428
- placement: 'left',
24429
- space: availableSpace.left,
24430
- fits: availableSpace.left >= contentWidth + 16,
24431
- x: triggerRect.left - contentWidth - 8,
24432
- y: align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - contentHeight : triggerRect.top + triggerRect.height / 2 - contentHeight / 2
24433
- }];
24434
- // First try the preferred position if it fits
24435
- var preferredPlacement = placements.find(p => p.placement === position && p.fits);
24436
- if (preferredPlacement) {
24437
- setOptimalPosition({
24438
- x: preferredPlacement.x,
24439
- y: preferredPlacement.y,
24440
- placement: preferredPlacement.placement
24441
- });
24442
- return;
24443
- }
24444
- // Otherwise, find the best fitting placement
24445
- var fittingPlacement = placements.find(p => p.fits);
24446
- if (fittingPlacement) {
24447
- setOptimalPosition({
24448
- x: fittingPlacement.x,
24449
- y: fittingPlacement.y,
24450
- placement: fittingPlacement.placement
24451
- });
24452
- return;
24453
- }
24454
- // If nothing fits, choose the placement with the most space
24455
- var bestPlacement = placements.reduce((best, current) => current.space > best.space ? current : best);
24456
- // Ensure the content stays within viewport bounds
24457
- var finalX = bestPlacement.x;
24458
- var finalY = bestPlacement.y;
24459
- if (finalX + contentWidth > viewportWidth) {
24460
- finalX = viewportWidth - contentWidth - 8;
24461
- }
24462
- if (finalX < 8) {
24463
- finalX = 8;
24464
- }
24465
- if (finalY + contentHeight > viewportHeight) {
24466
- finalY = viewportHeight - contentHeight - 8;
24535
+ var placement = position;
24536
+ // Use relation data to determine optimal placement
24537
+ if (relation) {
24538
+ // If preferred position doesn't have enough space, use the position with more space
24539
+ if (position === 'top' && relation.space.vertical === 'bottom') {
24540
+ placement = 'bottom';
24541
+ } else if (position === 'bottom' && relation.space.vertical === 'top') {
24542
+ placement = 'top';
24543
+ } else if (position === 'right' && relation.space.horizontal === 'left') {
24544
+ placement = 'left';
24545
+ } else if (position === 'left' && relation.space.horizontal === 'right') {
24546
+ placement = 'right';
24547
+ }
24467
24548
  }
24468
- if (finalY < 8) {
24469
- finalY = 8;
24549
+ // Calculate position based on optimal placement and alignment
24550
+ var x = 0;
24551
+ var y = 0;
24552
+ switch (placement) {
24553
+ case 'top':
24554
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 120 // Estimated content width
24555
+ : triggerRect.left + triggerRect.width / 2 - 60; // Half of estimated width
24556
+ y = triggerRect.top - 8;
24557
+ break;
24558
+ case 'bottom':
24559
+ x = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right - 120 : triggerRect.left + triggerRect.width / 2 - 60;
24560
+ y = triggerRect.bottom + 8;
24561
+ break;
24562
+ case 'right':
24563
+ x = triggerRect.right + 8;
24564
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 32 // Estimated content height
24565
+ : triggerRect.top + triggerRect.height / 2 - 16; // Half of estimated height
24566
+ break;
24567
+ case 'left':
24568
+ x = triggerRect.left - 8;
24569
+ y = align === 'start' ? triggerRect.top : align === 'end' ? triggerRect.bottom - 32 : triggerRect.top + triggerRect.height / 2 - 16;
24570
+ break;
24470
24571
  }
24471
24572
  setOptimalPosition({
24472
- x: finalX,
24473
- y: finalY,
24474
- placement: bestPlacement.placement
24573
+ x,
24574
+ y,
24575
+ placement
24475
24576
  });
24476
24577
  }
24477
- }, [isOpen, position, align, triggerRef, contentRef]);
24578
+ }, [isOpen, position, align, triggerRef, contentRef, relation]);
24478
24579
  // Get arrow styles based on optimal placement
24479
24580
  var arrowStyles = showArrow ? getArrowStyles(optimalPosition.placement) : {};
24480
- // Create intelligent positioning styles
24481
- var positionStyles = {
24482
- position: 'fixed',
24483
- left: optimalPosition.x,
24484
- top: optimalPosition.y,
24485
- zIndex: 1000
24581
+ // Create intelligent positioning styles with transform for better placement
24582
+ var getPositionStyles = () => {
24583
+ var baseStyles = {
24584
+ position: 'fixed',
24585
+ left: optimalPosition.x,
24586
+ top: optimalPosition.y,
24587
+ zIndex: 1000
24588
+ };
24589
+ // Add transform based on placement for better positioning
24590
+ switch (optimalPosition.placement) {
24591
+ case 'top':
24592
+ return Object.assign({}, baseStyles, {
24593
+ transform: 'translateY(-100%)'
24594
+ });
24595
+ case 'left':
24596
+ return Object.assign({}, baseStyles, {
24597
+ transform: 'translateX(-100%)'
24598
+ });
24599
+ case 'bottom':
24600
+ case 'right':
24601
+ default:
24602
+ return baseStyles;
24603
+ }
24486
24604
  };
24605
+ var positionStyles = getPositionStyles();
24487
24606
  return /*#__PURE__*/React.createElement(View, Object.assign({
24488
24607
  position: "relative",
24489
24608
  display: "inline-block"
@@ -24495,7 +24614,13 @@ var TooltipView = _ref4 => {
24495
24614
  borderRadius: 4,
24496
24615
  boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.15)",
24497
24616
  style: positionStyles
24498
- }, TooltipSizes[size], TooltipVariants[variant], views == null ? void 0 : views.content), typeof content === 'string' ? (/*#__PURE__*/React.createElement(Text$1, Object.assign({}, views == null ? void 0 : views.text), content)) : content, showArrow && /*#__PURE__*/React.createElement(View, Object.assign({}, arrowStyles, views == null ? void 0 : views.arrow)))));
24617
+ }, TooltipSizes[size], TooltipVariants[variant], views == null ? void 0 : views.content), typeof content === 'string' ? (/*#__PURE__*/React.createElement(Text$1, Object.assign({}, views == null ? void 0 : views.text), content)) : content, showArrow && /*#__PURE__*/React.createElement(View, Object.assign({}, arrowStyles, views == null ? void 0 : views.arrow)), process.env.NODE_ENV === 'development' && (/*#__PURE__*/React.createElement("div", {
24618
+ style: {
24619
+ fontSize: '8px',
24620
+ opacity: 0.7,
24621
+ marginTop: '2px'
24622
+ }
24623
+ }, "Placement: ", optimalPosition.placement, relation && (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("br", null), "Space: ", relation.space.vertical, "-", relation.space.horizontal)))))));
24499
24624
  };
24500
24625
 
24501
24626
  var _excluded$1b = ["content", "children", "position", "align", "size", "variant", "openDelay", "closeDelay", "showArrow", "defaultOpen", "isDisabled", "views"];