Skip to content

Commit

Permalink
feat: slider touch issue fix
Browse files Browse the repository at this point in the history
  • Loading branch information
shivajivarma committed Jul 7, 2024
1 parent 9371204 commit c817317
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 48 deletions.
10 changes: 5 additions & 5 deletions astro-docs/src/pages/components/slider/_sections/usage.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
import HighlighterCard from '../../../../components/HighlighterCard.astro';
---
<HighlighterCard lang={'html'}>
<goat-slider id='slider' value='30'></goat-slider>
<goat-slider id='slider' value='30' step='2'></goat-slider>
</HighlighterCard>

<script is:inline>
const slider = document.querySelector('#slider');
slider.addEventListener('goat:change', e => {
myConsole.log(JSON.stringify({ event: 'goat:change', detail: e.detail }, null, 4));
slider.addEventListener('goat-slider--change', e => {
myConsole.warn(JSON.stringify(e.detail, null, 4), e.type);
});
slider.addEventListener('goat:input', e => {
myConsole.log(JSON.stringify({ event: 'goat:input', detail: e.detail }, null, 4));
slider.addEventListener('goat-slider--input', e => {
myConsole.log(JSON.stringify(e.detail, null, 4), e.type);
});
</script>
18 changes: 12 additions & 6 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1209,10 +1209,11 @@ export namespace Components {
* If true, the user cannot interact with the button. Defaults to `false`.
*/
"disabled": boolean;
"format": 'number' | 'time';
/**
* function to format the value of the input
*/
"formatter": (value: string | number) => string;
"getComponentId": () => Promise<string>;
"hideInput": boolean;
"hideLabels": boolean;
"max": number;
"min": number;
/**
Expand All @@ -1235,6 +1236,8 @@ export namespace Components {
* Sets focus on the native `input` in `ion-input`. Use this method instead of the global `input.focus()`.
*/
"setFocus": () => Promise<void>;
"showOnlySlider": boolean;
"step": number;
/**
* The input field value.
*/
Expand Down Expand Up @@ -4129,9 +4132,10 @@ declare namespace LocalJSX {
* If true, the user cannot interact with the button. Defaults to `false`.
*/
"disabled"?: boolean;
"format"?: 'number' | 'time';
"hideInput"?: boolean;
"hideLabels"?: boolean;
/**
* function to format the value of the input
*/
"formatter"?: (value: string | number) => string;
"max"?: number;
"min"?: number;
/**
Expand All @@ -4154,6 +4158,8 @@ declare namespace LocalJSX {
* If true, required icon is show. Defaults to `false`.
*/
"required"?: boolean;
"showOnlySlider"?: boolean;
"step"?: number;
/**
* The input field value.
*/
Expand Down
105 changes: 68 additions & 37 deletions src/components/input-controls/slider/slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
DRAG_STOP_EVENT_TYPES,
getComponentIndex,
isInViewport,
secondsToHHMMSS,
throttle,
} from '../../../utils/utils';

Expand Down Expand Up @@ -47,17 +46,20 @@ export class Slider implements ComponentInterface, InputComponentInterface {

@Prop() max: number = 100;

@Prop() hideLabels: boolean = false;
@Prop() showOnlySlider: boolean = false;

@Prop() hideInput: boolean = false;

@Prop() format: 'number' | 'time' = 'number';
/**
* function to format the value of the input
*/
@Prop() formatter: (value: string | number) => string;

/**
* The input field value.
*/
@Prop({ mutable: true }) value?: number = 0;

@Prop({ mutable: true }) step: number = 1;

/**
* If true, required icon is show. Defaults to `false`.
*/
Expand Down Expand Up @@ -130,6 +132,8 @@ export class Slider implements ComponentInterface, InputComponentInterface {

@Element() elm!: HTMLElement;
private nativeElement?: HTMLInputElement;

private inputValue: number;
@State() hasFocus = false;
@State() needsOnRelease = false;
private displayElement?: HTMLElement;
Expand All @@ -145,6 +149,18 @@ export class Slider implements ComponentInterface, InputComponentInterface {
this.elm.removeAttribute(name);
}
});

this.inputValue = this.value;
}

componentDidLoad() {
this.#computeSliderWidth();

const resizeObserver = new ResizeObserver(() => {
this.#computeSliderWidth();
});

resizeObserver.observe(this.elm);
}

onWheel = event => {
Expand All @@ -163,9 +179,7 @@ export class Slider implements ComponentInterface, InputComponentInterface {
delta = -event.detail / 3;
}

this.value = parseInt(String(this.value)) + delta;

this.updateValue();
this.updateValue(parseInt(String(this.value)) + delta * this.step);
};

onDragStart = event => {
Expand Down Expand Up @@ -194,7 +208,7 @@ export class Slider implements ComponentInterface, InputComponentInterface {
* Unregisters "drag" and "drag stop" event handlers and calls sets the flag
* indicating that the `onRelease` callback should be called.
*/
onDragStop = () => {
onDragStop = event => {
// Do nothing if component is disabled
if (this.disabled || this.readonly) {
return;
Expand All @@ -210,13 +224,18 @@ export class Slider implements ComponentInterface, InputComponentInterface {
this.elm?.ownerDocument.removeEventListener(element, this.onDrag);
});

this.goatChange.emit({
value: this.value,
});
let clientX: number;
if (event.type === 'touchend') {
clientX = event.changedTouches[0].clientX;
} else {
clientX = event.clientX;
}

this.updateByPosition(clientX);
};

openTooltip = (target, open) => {
document.dispatchEvent(
window.dispatchEvent(
new CustomEvent('goat-tooltip-open', {
detail: {
target: target,
Expand All @@ -234,20 +253,31 @@ export class Slider implements ComponentInterface, InputComponentInterface {

this.openTooltip(this.thumbElement, true);

this.updateByPosition(event.clientX);
let clientX: number;
if (event.type === 'touchstart' || event.type === 'touchmove') {
clientX = event.touches[0].clientX;
} else {
clientX = event.clientX;
}

this.updateByPosition(clientX);
};

updateByPosition = current => {
updateByPosition(current) {
const start = this.slideElement.getBoundingClientRect().left;
const total = this.slideElement.getBoundingClientRect().width;
this.value = parseInt(
const value = parseInt(
String(((current - start) / total) * (this.max - this.min)),
);
this.updateValue(value);
this.inputValue = this.value;
}

this.updateValue();
};
updateValue = newValue => {
const oldValue = this.value;

this.value = Math.round(newValue / this.step) * this.step;

updateValue = () => {
if (this.value == null || this.value < this.min) {
this.value = this.min;
} else if (this.value > this.max) {
Expand All @@ -257,6 +287,12 @@ export class Slider implements ComponentInterface, InputComponentInterface {
this.goatInput.emit({
value: this.value,
});

if (oldValue !== this.value) {
this.goatChange.emit({
value: this.value,
});
}
};

onDrag = throttle(this._onDrag, 1, {
Expand All @@ -283,19 +319,14 @@ export class Slider implements ComponentInterface, InputComponentInterface {
this.hasFocus = true;
};

private getFormattedValue(value) {
if (this.format === 'time') return secondsToHHMMSS(value);
private getFormattedValue(value: string | number) {
if (this.formatter) return this.formatter(value);
return value;
}

componentDidLoad() {
setTimeout(() => this.computeSliderWidth(), 1);
}

private computeSliderWidth() {
//monaco.languages.typescript.javascriptDefaults.addExtraLib(this.extraLibs);
#computeSliderWidth() {
if (this.slideElementWidth == null && !isInViewport(this.elm)) {
setTimeout(() => this.computeSliderWidth(), 80);
setTimeout(() => this.#computeSliderWidth(), 100);
return;
}

Expand All @@ -307,7 +338,7 @@ export class Slider implements ComponentInterface, InputComponentInterface {
<Host has-value={this.hasValue()} has-focus={this.hasFocus}>
<div class="slider-container">
<div class="slider-wrapper">
{!this.hideLabels && (
{!this.showOnlySlider && (
<div class="slider-range-label">
<span>{this.getFormattedValue(this.min)}</span>
</div>
Expand All @@ -316,12 +347,12 @@ export class Slider implements ComponentInterface, InputComponentInterface {
class={{ 'slider': true, 'has-focus': this.hasFocus }}
ref={elm => (this.slideElement = elm)}
onMouseDown={this.onDragStart}
onTouchStart={this.onDragStart}
onWheel={this.onWheel}
>
<div
class="slider__thumb"
onBlur={this.blurHandler}
onTouchStart={this.onDragStart}
onFocus={this.focusHandler}
ref={elm => (this.thumbElement = elm)}
onMouseOver={_e => {
Expand All @@ -336,7 +367,8 @@ export class Slider implements ComponentInterface, InputComponentInterface {
style={{
left: `${
(this.value * (this.slideElementWidth | 0)) /
(this.max - this.min)
(this.max - this.min) -
8
}px`,
}}
></div>
Expand All @@ -351,23 +383,22 @@ export class Slider implements ComponentInterface, InputComponentInterface {
}}
></div>
</div>
{!this.hideLabels && (
{!this.showOnlySlider && (
<div class="slider-range-label">
<span>{this.getFormattedValue(this.max)}</span>
</div>
)}
</div>
{!this.hideInput ? (
{!this.showOnlySlider ? (
<div class="slide-input">
<goat-number
class="input"
value={this.value}
value={this.inputValue}
size="sm"
hide-actions={true}
onGoat-change={e => {
onGoat-number--input={e => {
e.stopPropagation();
this.value = e.target.value;
this.updateValue();
this.updateValue(e.target.value);
}}
onGoat-input={e => {
e.stopPropagation();
Expand Down

0 comments on commit c817317

Please sign in to comment.