diff --git a/packages/@mantine/core/src/components/FloatingIndicator/FloatingIndicator.test.tsx b/packages/@mantine/core/src/components/FloatingIndicator/FloatingIndicator.test.tsx
index 4fa6a5bbe64..4ac27e62615 100644
--- a/packages/@mantine/core/src/components/FloatingIndicator/FloatingIndicator.test.tsx
+++ b/packages/@mantine/core/src/components/FloatingIndicator/FloatingIndicator.test.tsx
@@ -1,4 +1,4 @@
-import { tests } from '@mantine-tests/core';
+import { render, tests } from '@mantine-tests/core';
import {
FloatingIndicator,
FloatingIndicatorProps,
@@ -22,4 +22,43 @@ describe('@mantine/core/FloatingIndicator', () => {
displayName: '@mantine/core/FloatingIndicator',
stylesApiSelectors: ['root'],
});
+
+ it('normalizes geometry when parent container is scaled', () => {
+ const parent = document.createElement('div');
+ const target = document.createElement('div');
+ const indicatorRef = { current: document.createElement('div') };
+
+ Object.defineProperty(parent, 'offsetWidth', { value: 200, configurable: true });
+ Object.defineProperty(parent, 'offsetHeight', { value: 100, configurable: true });
+
+ jest.spyOn(parent, 'getBoundingClientRect').mockReturnValue({
+ top: 100,
+ left: 100,
+ width: 100,
+ height: 50,
+ bottom: 150,
+ right: 200,
+ x: 100,
+ y: 100,
+ toJSON: () => {},
+ });
+
+ jest.spyOn(target, 'getBoundingClientRect').mockReturnValue({
+ top: 125,
+ left: 150,
+ width: 50,
+ height: 25,
+ bottom: 150,
+ right: 200,
+ x: 150,
+ y: 125,
+ toJSON: () => {},
+ });
+
+ render();
+
+ expect(indicatorRef.current.style.width).toBe('100px');
+ expect(indicatorRef.current.style.height).toBe('50px');
+ expect(indicatorRef.current.style.transform).toBe('translateY(50px) translateX(100px)');
+ });
});
diff --git a/packages/@mantine/core/src/components/FloatingIndicator/use-floating-indicator.ts b/packages/@mantine/core/src/components/FloatingIndicator/use-floating-indicator.ts
index 899b6d6d74f..86517423124 100644
--- a/packages/@mantine/core/src/components/FloatingIndicator/use-floating-indicator.ts
+++ b/packages/@mantine/core/src/components/FloatingIndicator/use-floating-indicator.ts
@@ -54,6 +54,9 @@ export function useFloatingIndicator({
const targetRect = target.getBoundingClientRect();
const parentRect = parent.getBoundingClientRect();
+ const scaleX = parent.offsetWidth === 0 ? 1 : parentRect.width / parent.offsetWidth;
+ const scaleY = parent.offsetHeight === 0 ? 1 : parentRect.height / parent.offsetHeight;
+
const targetComputedStyle = window.getComputedStyle(target);
const parentComputedStyle = window.getComputedStyle(parent);
@@ -63,10 +66,10 @@ export function useFloatingIndicator({
toInt(targetComputedStyle.borderLeftWidth) + toInt(parentComputedStyle.borderLeftWidth);
const position = {
- top: targetRect.top - parentRect.top - borderTopWidth,
- left: targetRect.left - parentRect.left - borderLeftWidth,
- width: targetRect.width,
- height: targetRect.height,
+ top: (targetRect.top - parentRect.top) / scaleY - borderTopWidth,
+ left: (targetRect.left - parentRect.left) / scaleX - borderLeftWidth,
+ width: targetRect.width / scaleX,
+ height: targetRect.height / scaleY,
};
ref.current.style.transform = `translateY(${position.top}px) translateX(${position.left}px)`;
diff --git a/packages/@mantine/core/src/components/SegmentedControl/SegmentedControl.story.tsx b/packages/@mantine/core/src/components/SegmentedControl/SegmentedControl.story.tsx
index 800698430dc..a193c3b8554 100644
--- a/packages/@mantine/core/src/components/SegmentedControl/SegmentedControl.story.tsx
+++ b/packages/@mantine/core/src/components/SegmentedControl/SegmentedControl.story.tsx
@@ -166,3 +166,21 @@ export function NextToInput() {
{sizes}
);
}
+
+export function ScaledAncestor() {
+ return (
+
+ );
+}