Skip to content

Commit 156b618

Browse files
authored
fix: position thumb properly at pointer coordinates (#33916)
1 parent a82eb36 commit 156b618

File tree

4 files changed

+95
-7
lines changed

4 files changed

+95
-7
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "fix: position thumb properly at pointer coordinates",
4+
"packageName": "@fluentui/web-components",
5+
"email": "machi@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

packages/web-components/src/slider/slider.spec.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import { expect, test } from '../../test/playwright/index.js';
22
import type { Slider } from './slider.js';
33
import { SliderSize } from './slider.options.js';
44

5+
interface BoundingBox {
6+
x: number;
7+
y: number;
8+
width: number;
9+
height: number;
10+
}
11+
512
test.describe('Slider', () => {
613
test.use({
714
tagName: 'fluent-slider',
@@ -631,4 +638,78 @@ test.describe('Slider', () => {
631638
await expect(wasChanged).resolves.toEqual(true);
632639
});
633640
});
641+
642+
test.describe('thumb position', () => {
643+
test('should follow pointer event coordinates in horizontal orientation', async ({ fastPage, page }) => {
644+
const { element } = fastPage;
645+
646+
const track = element.locator('.track');
647+
const thumb = element.locator('.thumb-container');
648+
const trackBox = (await track.boundingBox()) as BoundingBox;
649+
650+
expect(trackBox).not.toBeNull();
651+
652+
let thumbBox = (await thumb.boundingBox()) as BoundingBox;
653+
expect(thumbBox).not.toBeNull();
654+
655+
const thumbCenterX = thumbBox.x + thumbBox.width / 2;
656+
const thumbCenterY = thumbBox.y + thumbBox.height / 2;
657+
const thumbMoveToX = thumbCenterX - trackBox.width * 0.1;
658+
await page.mouse.move(thumbCenterX, thumbCenterY);
659+
await page.mouse.down();
660+
661+
thumbBox = (await thumb.boundingBox()) as BoundingBox;
662+
expect(thumbBox).not.toBeNull();
663+
expect(thumbBox.x + thumbBox.width / 2).toBeCloseTo(thumbCenterX);
664+
expect(thumbBox.y + thumbBox.height / 2).toBeCloseTo(thumbCenterY);
665+
666+
await page.mouse.move(thumbMoveToX, thumbCenterY);
667+
await page.mouse.up();
668+
const thumbHandle = await thumb.elementHandle();
669+
await thumbHandle?.waitForElementState('stable');
670+
671+
thumbBox = (await thumb.boundingBox()) as BoundingBox;
672+
expect(thumbBox).not.toBeNull();
673+
expect(thumbBox.x + thumbBox.width / 2).toBeCloseTo(thumbMoveToX);
674+
expect(thumbBox.y + thumbBox.height / 2).toBeCloseTo(thumbCenterY);
675+
});
676+
677+
test('should follow pointer event coordinates in vertical orientation', async ({ fastPage, page }) => {
678+
const { element } = fastPage;
679+
await fastPage.setTemplate({ attributes: { orientation: 'vertical' } });
680+
const elementBox = (await element.boundingBox()) as BoundingBox;
681+
682+
expect(elementBox.width).toBeLessThan(elementBox.height);
683+
684+
const track = element.locator('.track');
685+
const thumb = element.locator('.thumb-container');
686+
const trackBox = (await track.boundingBox()) as BoundingBox;
687+
688+
expect(trackBox).not.toBeNull();
689+
690+
let thumbBox = (await thumb.boundingBox()) as BoundingBox;
691+
expect(thumbBox).not.toBeNull();
692+
693+
const thumbCenterX = thumbBox.x + thumbBox.width / 2;
694+
const thumbCenterY = thumbBox.y + thumbBox.height / 2;
695+
const thumbMoveToY = thumbCenterY - trackBox.height * 0.3;
696+
await page.mouse.move(thumbCenterX, thumbCenterY);
697+
await page.mouse.down();
698+
699+
thumbBox = (await thumb.boundingBox()) as BoundingBox;
700+
expect(thumbBox).not.toBeNull();
701+
expect(thumbBox.x + thumbBox.width / 2).toBeCloseTo(thumbCenterX);
702+
expect(thumbBox.y + thumbBox.height / 2).toBeCloseTo(thumbCenterY);
703+
704+
await page.mouse.move(thumbCenterX, thumbMoveToY);
705+
await page.mouse.up();
706+
const thumbHandle = await thumb.elementHandle();
707+
await thumbHandle?.waitForElementState('stable');
708+
709+
thumbBox = (await thumb.boundingBox()) as BoundingBox;
710+
expect(thumbBox).not.toBeNull();
711+
expect(thumbBox.x + thumbBox.width / 2).toBeCloseTo(thumbCenterX);
712+
expect(thumbBox.y + thumbBox.height / 2).toBeCloseTo(thumbMoveToY);
713+
});
714+
});
634715
});

packages/web-components/src/slider/slider.styles.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,6 @@ export const styles = css`
126126
width: var(--track-size);
127127
}
128128
129-
:host(${verticalState}) .track {
130-
top: var(--track-overhang);
131-
bottom: var(--track-overhang);
132-
}
133-
134129
.track::before {
135130
content: '';
136131
position: absolute;

packages/web-components/src/slider/slider.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,10 +717,13 @@ export class Slider extends FASTElement implements SliderConfiguration {
717717

718718
// update the value based on current position
719719
const sourceEvent = window.TouchEvent && event instanceof TouchEvent ? event.touches[0] : (event as PointerEvent);
720+
721+
const thumbWidth = this.thumb.getBoundingClientRect().width;
722+
720723
const eventValue: number =
721724
this.orientation === Orientation.vertical
722725
? sourceEvent.pageY - document.documentElement.scrollTop
723-
: sourceEvent.pageX - document.documentElement.scrollLeft - this.trackLeft;
726+
: sourceEvent.pageX - document.documentElement.scrollLeft - this.trackLeft - thumbWidth / 2;
724727

725728
this.value = `${this.calculateNewValue(eventValue)}`;
726729
};
@@ -772,12 +775,14 @@ export class Slider extends FASTElement implements SliderConfiguration {
772775
documentFn('mouseleave', this.handleWindowPointerUp);
773776
windowFn('pointermove', this.handlePointerMove);
774777

778+
const thumbWidth = this.thumb.getBoundingClientRect().width;
779+
775780
if (event) {
776781
this.setupTrackConstraints();
777782
const controlValue: number =
778783
this.orientation === Orientation.vertical
779784
? event.pageY - document.documentElement.scrollTop
780-
: event.pageX - document.documentElement.scrollLeft - this.trackLeft;
785+
: event.pageX - document.documentElement.scrollLeft - this.trackLeft - thumbWidth / 2;
781786

782787
this.value = `${this.calculateNewValue(controlValue)}`;
783788
}

0 commit comments

Comments
 (0)