From 4191637f9f02c05feedaad39bde1e1491ffe938c Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Thu, 10 May 2018 14:51:45 +0200 Subject: [PATCH] refactor(range): move logic to stateless - float steps are possible - improved performance - state is in a single place - fix when value changes dynamically - fix jumpy gesture --- core/src/components.d.ts | 17 +- core/src/components/range-knob/range-knob.tsx | 35 +- core/src/components/range-knob/readme.md | 8 +- core/src/components/range/range-interface.ts | 13 + core/src/components/range/range.tsx | 425 +++++++----------- core/src/components/range/readme.md | 16 - .../components/range/test/basic/index.html | 25 +- core/src/interface.d.ts | 1 + 8 files changed, 226 insertions(+), 314 deletions(-) create mode 100644 core/src/components/range/range-interface.ts diff --git a/core/src/components.d.ts b/core/src/components.d.ts index f9d2db1251..4e670eb252 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -42,6 +42,7 @@ import { GestureConfig, GestureDetail, InputChangeEvent, + Knob, LoadingOptions, Menu, MenuChangeEventDetail, @@ -4494,14 +4495,14 @@ declare global { namespace StencilComponents { interface IonRangeKnob { 'disabled': boolean; - 'knob': string; + 'knob': Knob; 'labelId': string; 'max': number; 'min': number; 'pin': boolean; 'pressed': boolean; 'ratio': number; - 'val': number; + 'value': number; } } @@ -4525,7 +4526,7 @@ declare global { namespace JSXElements { export interface IonRangeKnobAttributes extends HTMLAttributes { 'disabled'?: boolean; - 'knob'?: string; + 'knob'?: Knob; 'labelId'?: string; 'max'?: number; 'min'?: number; @@ -4534,7 +4535,7 @@ declare global { 'pin'?: boolean; 'pressed'?: boolean; 'ratio'?: number; - 'val'?: number; + 'value'?: number; } } } @@ -4580,14 +4581,6 @@ declare global { * If true, a pin with integer value is shown when the knob is pressed. Defaults to `false`. */ 'pin': boolean; - /** - * Returns the ratio of the knob's is current location, which is a number between `0` and `1`. If two knobs are used, this property represents the lower value. - */ - 'ratio': () => number; - /** - * Returns the ratio of the upper value's is current location, which is a number between `0` and `1`. If there is only one knob, then this will return `null`. - */ - 'ratioUpper': () => number | null; /** * If true, the knob snaps to tick marks evenly spaced based on the step property value. Defaults to `false`. */ diff --git a/core/src/components/range-knob/range-knob.tsx b/core/src/components/range-knob/range-knob.tsx index b946555a14..4531d0fd2f 100644 --- a/core/src/components/range-knob/range-knob.tsx +++ b/core/src/components/range-knob/range-knob.tsx @@ -1,19 +1,20 @@ import { Component, Event, EventEmitter, Listen, Prop } from '@stencil/core'; +import { Knob } from '../../interface'; @Component({ tag: `ion-range-knob` }) export class RangeKnob { - @Prop() pressed = false; - @Prop() pin = false; + @Prop() pressed!: boolean; + @Prop() pin!: boolean; @Prop() min!: number; @Prop() max!: number; - @Prop() val!: number; - @Prop() disabled = false; - @Prop() labelId!: string; - @Prop() knob!: string; + @Prop() value!: number; @Prop() ratio!: number; + @Prop() disabled!: boolean; + @Prop() labelId!: string; + @Prop() knob!: Knob; @Event() ionIncrease!: EventEmitter; @Event() ionDecrease!: EventEmitter; @@ -25,6 +26,7 @@ export class RangeKnob { this.ionDecrease.emit({isIncrease: false, knob: this.knob}); ev.preventDefault(); ev.stopPropagation(); + } else if (keyCode === KEY_RIGHT || keyCode === KEY_UP) { this.ionIncrease.emit({isIncrease: true, knob: this.knob}); ev.preventDefault(); @@ -32,34 +34,33 @@ export class RangeKnob { } } - leftPos(val: number) { - return `${val * 100}%`; - } - hostData() { + const {value, min, max} = this; + const pos = this.ratio * 100; return { class: { + 'range-knob-handle': true, 'range-knob-pressed': this.pressed, - 'range-knob-min': this.val === this.min || this.val === undefined, - 'range-knob-max': this.val === this.max + 'range-knob-min': value === min, + 'range-knob-max': value === max }, style: { - 'left': this.leftPos(this.ratio) + 'left': `${pos}%` }, 'role': 'slider', 'tabindex': this.disabled ? -1 : 0, - 'aria-valuemin': this.min, - 'aria-valuemax': this.max, + 'aria-valuemin': min, + 'aria-valuemax': max, 'aria-disabled': this.disabled, 'aria-labelledby': this.labelId, - 'aria-valuenow': this.val + 'aria-valuenow': value }; } render() { if (this.pin) { return [ - , + ,