fix(range): implement RTL (from PR 17157) (#17384)

- MD PIN fixes not committed because they depend on mixin changes

references #17012
This commit is contained in:
Abdelaziz Bennouna
2019-02-12 20:34:48 +00:00
committed by Brandy Carney
parent d0a9fac5c7
commit 4f203bc230
3 changed files with 76 additions and 16 deletions

View File

@ -105,6 +105,11 @@
@include border-radius(50%, 50%, 50%, 0); @include border-radius(50%, 50%, 50%, 0);
@include margin-horizontal(-13px, null); @include margin-horizontal(-13px, null);
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute; position: absolute;
width: 26px; width: 26px;

View File

@ -79,6 +79,11 @@
null null
); );
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute; position: absolute;
width: var(--knob-handle-size); width: var(--knob-handle-size);
@ -95,6 +100,12 @@
.range-bar { .range-bar {
@include border-radius(var(--bar-border-radius)); @include border-radius(var(--bar-border-radius));
@include position(calc((var(--height) - var(--bar-height)) / 2), null, null, 0); @include position(calc((var(--height) - var(--bar-height)) / 2), null, null, 0);
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute; position: absolute;
width: 100%; width: 100%;
@ -113,6 +124,11 @@
calc(50% - var(--knob-size) / 2) calc(50% - var(--knob-size) / 2)
); );
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute; position: absolute;
width: var(--knob-size); width: var(--knob-size);

View File

@ -235,7 +235,11 @@ export class Range implements ComponentInterface {
const currentX = detail.currentX; const currentX = detail.currentX;
// figure out which knob they started closer to // figure out which knob they started closer to
const ratio = clamp(0, (currentX - rect.left) / rect.width, 1); let ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
if (document.dir === 'rtl') {
ratio = 1 - ratio;
}
this.pressedKnob = this.pressedKnob =
!this.dualKnobs || !this.dualKnobs ||
Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio) Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio)
@ -262,6 +266,10 @@ export class Range implements ComponentInterface {
// update the knob being interacted with // update the knob being interacted with
const rect = this.rect; const rect = this.rect;
let ratio = clamp(0, (currentX - rect.left) / rect.width, 1); let ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
if (document.dir === 'rtl') {
ratio = 1 - ratio;
}
if (this.snaps) { if (this.snaps) {
// snaps the ratio to the current value // snaps the ratio to the current value
ratio = valueToRatio( ratio = valueToRatio(
@ -353,31 +361,56 @@ export class Range implements ComponentInterface {
render() { render() {
const { min, max, step, ratioLower, ratioUpper } = this; const { min, max, step, ratioLower, ratioUpper } = this;
const barL = `${ratioLower * 100}%`; const barStart = `${ratioLower * 100}%`;
const barR = `${100 - ratioUpper * 100}%`; const barEnd = `${100 - ratioUpper * 100}%`;
const isRTL = document.dir === 'rtl';
const start = isRTL ? 'right' : 'left';
const end = isRTL ? 'left' : 'right';
const ticks = []; const ticks = [];
if (this.snaps) { if (this.snaps) {
for (let value = min; value <= max; value += step) { for (let value = min; value <= max; value += step) {
const ratio = valueToRatio(value, min, max); const ratio = valueToRatio(value, min, max);
ticks.push({
const tick: any = {
ratio, ratio,
active: ratio >= ratioLower && ratio <= ratioUpper, active: ratio >= ratioLower && ratio <= ratioUpper,
left: `${ratio * 100}%` };
});
tick[start] = `${ratio * 100}%`;
ticks.push(tick);
} }
} }
const tickStyle = (tick: any) => {
const style: any = {};
style[start] = tick[start];
return style;
};
const barStyle = () => {
const style: any = {};
style[start] = barStart;
style[end] = barEnd;
return style;
};
return [ return [
<slot name="start"></slot>, <slot name="start"></slot>,
<div class="range-slider" ref={el => this.rangeSlider = el}> <div class="range-slider" ref={el => this.rangeSlider = el}>
{ticks.map(t => ( {ticks.map(tick => (
<div <div
style={{ left: t.left }} style={tickStyle(tick)}
role="presentation" role="presentation"
class={{ class={{
'range-tick': true, 'range-tick': true,
'range-tick-active': t.active 'range-tick-active': tick.active
}} }}
/> />
))} ))}
@ -386,10 +419,7 @@ export class Range implements ComponentInterface {
<div <div
class="range-bar range-bar-active" class="range-bar range-bar-active"
role="presentation" role="presentation"
style={{ style={barStyle()}
left: barL,
right: barR
}}
/> />
{ renderKnob({ { renderKnob({
@ -435,6 +465,17 @@ interface RangeKnob {
} }
function renderKnob({ knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard }: RangeKnob) { function renderKnob({ knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard }: RangeKnob) {
const isRTL = document.dir === 'rtl';
const start = isRTL ? 'right' : 'left';
const knobStyle = () => {
const style: any = {};
style[start] = `${ratio * 100}%`;
return style;
};
return ( return (
<div <div
onKeyDown={(ev: KeyboardEvent) => { onKeyDown={(ev: KeyboardEvent) => {
@ -458,9 +499,7 @@ function renderKnob({ knob, value, ratio, min, max, disabled, pressed, pin, hand
'range-knob-min': value === min, 'range-knob-min': value === min,
'range-knob-max': value === max 'range-knob-max': value === max
}} }}
style={{ style={knobStyle()}
'left': `${ratio * 100}%`
}}
role="slider" role="slider"
tabindex={disabled ? -1 : 0} tabindex={disabled ? -1 : 0}
aria-valuemin={min} aria-valuemin={min}