fix: handle button clicking scrolling multiple views

This commit is contained in:
Tanner Reits
2024-10-18 17:19:27 -04:00
parent 88b9af9a44
commit d6f7cc86ab

View File

@ -29,6 +29,8 @@ export class Segment implements ComponentInterface {
private segmentViewEl?: HTMLIonSegmentViewElement | null = null; private segmentViewEl?: HTMLIonSegmentViewElement | null = null;
private nextButtonIndex?: number;
private io?: IntersectionObserver; private io?: IntersectionObserver;
@Element() el!: HTMLIonSegmentElement; @Element() el!: HTMLIonSegmentElement;
@ -250,10 +252,7 @@ export class Segment implements ComponentInterface {
const buttons = this.getButtons(); const buttons = this.getButtons();
const button = buttons[index]; const button = buttons[index];
const buttonRect = button.getBoundingClientRect(); return button.offsetLeft;
const segmentRect = this.el.getBoundingClientRect();
return this.el.scrollLeft + buttonRect.x - segmentRect.x;
} }
private addIntersectionObserver() { private addIntersectionObserver() {
@ -479,11 +478,23 @@ export class Segment implements ComponentInterface {
// Find the next valid button (i.e. we need to ignore any disabled buttons) // Find the next valid button (i.e. we need to ignore any disabled buttons)
const nextIndex = const nextIndex =
scrollDistance > 0 this.nextButtonIndex ??
(scrollDistance > 0
? findIndexFrom(buttons, (ref) => !ref.disabled, currentIndex + 1) ? findIndexFrom(buttons, (ref) => !ref.disabled, currentIndex + 1)
: findIndexFromReverse(buttons, (ref) => !ref.disabled, currentIndex - 1); : findIndexFromReverse(buttons, (ref) => !ref.disabled, currentIndex - 1));
if (nextIndex >= 0 && nextIndex < buttons.length) { if (nextIndex >= 0 && nextIndex < buttons.length) {
// Figure out the number of disabled buttons between the current and next button
const disabledButtons = (
nextIndex > currentIndex ? buttons.slice(currentIndex, nextIndex) : buttons.slice(nextIndex, currentIndex)
).filter((button) => button.disabled).length;
// Adjust the scroll distance percentage based on the number of "views" scrolled
// We need to do this because all subsequent calculations are based on the assumption that
// only one view can be scrolled at a time, but this is not the case when clicking a segment button
const adjustedScrollDistancePercentage =
scrollDistancePercentage / (Math.abs(nextIndex - currentIndex) - disabledButtons);
const nextButton = buttons[nextIndex]; const nextButton = buttons[nextIndex];
const nextButtonWidth = nextButton.getBoundingClientRect().width; const nextButtonWidth = nextButton.getBoundingClientRect().width;
@ -491,7 +502,7 @@ export class Segment implements ComponentInterface {
// Scale the width based on the width of the next button // Scale the width based on the width of the next button
const diff = nextButtonWidth - currentButtonWidth; const diff = nextButtonWidth - currentButtonWidth;
const width = currentButtonWidth + diff * scrollDistancePercentage; const width = currentButtonWidth + diff * adjustedScrollDistancePercentage;
const indicatorStyles = getComputedStyle(indicator); const indicatorStyles = getComputedStyle(indicator);
const indicatorPadding = const indicatorPadding =
parseFloat(indicatorStyles.paddingLeft.replace('px', '')) + parseFloat(indicatorStyles.paddingLeft.replace('px', '')) +
@ -501,14 +512,15 @@ export class Segment implements ComponentInterface {
// Translate the indicator based on the scroll distance // Translate the indicator based on the scroll distance
const distanceToNextButton = this.distanceToButton(nextIndex); const distanceToNextButton = this.distanceToButton(nextIndex);
const distanceToCurrentButton = this.distanceToButton(currentIndex); const distanceToCurrentButton = this.distanceToButton(currentIndex);
indicator.style.left = indicator.style.left =
scrollDistance > 0 scrollDistance > 0
? `${ ? `${
distanceToCurrentButton + (distanceToNextButton - distanceToCurrentButton) * scrollDistancePercentage distanceToCurrentButton +
(distanceToNextButton - distanceToCurrentButton) * adjustedScrollDistancePercentage
}px` }px`
: `${ : `${
distanceToCurrentButton - (distanceToCurrentButton - distanceToNextButton) * scrollDistancePercentage distanceToCurrentButton -
(distanceToCurrentButton - distanceToNextButton) * adjustedScrollDistancePercentage
}px`; }px`;
const standardize_color = (str: string) => { const standardize_color = (str: string) => {
@ -535,7 +547,7 @@ export class Segment implements ComponentInterface {
return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`; return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`;
}; };
// Function to calculate the color in between based on percentage // Function to calculate the color in between based on percentage
const interpolateColor = (percentage = scrollDistancePercentage) => { const interpolateColor = (percentage = adjustedScrollDistancePercentage) => {
const currentColor = standardize_color(getComputedStyle(currentButton).getPropertyValue('--indicator-color')); const currentColor = standardize_color(getComputedStyle(currentButton).getPropertyValue('--indicator-color'));
const nextColor = standardize_color(getComputedStyle(nextButton).getPropertyValue('--indicator-color')); const nextColor = standardize_color(getComputedStyle(nextButton).getPropertyValue('--indicator-color'));
@ -568,6 +580,7 @@ export class Segment implements ComponentInterface {
if (ev.composedPath().includes(segmentViewEl) || dispatchedFrom?.contains(segmentEl)) { if (ev.composedPath().includes(segmentViewEl) || dispatchedFrom?.contains(segmentEl)) {
this.value = ev.detail.activeContentId; this.value = ev.detail.activeContentId;
this.nextButtonIndex = undefined;
this.emitValueChange(); this.emitValueChange();
} }
} }
@ -756,6 +769,7 @@ export class Segment implements ComponentInterface {
if (current !== previous) { if (current !== previous) {
if (this.segmentViewEl) { if (this.segmentViewEl) {
this.nextButtonIndex = this.getButtons().findIndex((button) => button.value === current.value);
this.updateSegmentView(current.value); this.updateSegmentView(current.value);
} else { } else {
this.value = current.value; this.value = current.value;