mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(slide-toggle): invert the thumb and slide gesture in rtl (#12284)
This commit is contained in:
committed by
Joey Perrott
parent
f9d37571ce
commit
9a191b344d
@@ -11,6 +11,7 @@ ng_module(
|
||||
deps = [
|
||||
"//src/lib/core",
|
||||
"//src/cdk/a11y",
|
||||
"//src/cdk/bidi",
|
||||
"//src/cdk/coercion",
|
||||
"//src/cdk/observers",
|
||||
"//src/cdk/platform",
|
||||
|
||||
@@ -33,6 +33,10 @@ $mat-slide-toggle-bar-track-width: $mat-slide-toggle-bar-width - $mat-slide-togg
|
||||
&.mat-checked {
|
||||
.mat-slide-toggle-thumb-container {
|
||||
transform: translate3d($mat-slide-toggle-bar-track-width, 0, 0);
|
||||
|
||||
[dir='rtl'] & {
|
||||
transform: translate3d(-$mat-slide-toggle-bar-track-width, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +119,11 @@ $mat-slide-toggle-bar-track-width: $mat-slide-toggle-bar-width - $mat-slide-togg
|
||||
._mat-animation-noopable & {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
[dir='rtl'] & {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The visual thumb element that moves inside of the thumb bar.
|
||||
@@ -147,8 +156,15 @@ $mat-slide-toggle-bar-track-width: $mat-slide-toggle-bar-width - $mat-slide-togg
|
||||
.mat-slide-toggle-input {
|
||||
// Move the input to the bottom and in the middle of the thumb.
|
||||
// Visual improvement to properly show browser popups when being required.
|
||||
$horizontal-offset: $mat-slide-toggle-thumb-size / 2;
|
||||
|
||||
bottom: 0;
|
||||
left: $mat-slide-toggle-thumb-size / 2;
|
||||
left: $horizontal-offset;
|
||||
|
||||
[dir='rtl'] & {
|
||||
left: auto;
|
||||
right: $horizontal-offset;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-slide-toggle-bar,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {ComponentFixture, fakeAsync, flushMicrotasks, TestBed, tick} from '@angu
|
||||
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
|
||||
import {defaultRippleAnimationConfig} from '@angular/material/core';
|
||||
import {By, HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
|
||||
import {BidiModule, Direction} from '@angular/cdk/bidi';
|
||||
import {TestGestureConfig} from '../slider/test-gesture-config';
|
||||
import {MAT_SLIDE_TOGGLE_DEFAULT_OPTIONS} from './slide-toggle-config';
|
||||
import {MatSlideToggle, MatSlideToggleChange, MatSlideToggleModule} from './index';
|
||||
@@ -18,7 +19,7 @@ describe('MatSlideToggle without forms', () => {
|
||||
mutationObserverCallbacks = [];
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [MatSlideToggleModule],
|
||||
imports: [MatSlideToggleModule, BidiModule],
|
||||
declarations: [
|
||||
SlideToggleBasic,
|
||||
SlideToggleWithTabindexAttr,
|
||||
@@ -493,6 +494,29 @@ describe('MatSlideToggle without forms', () => {
|
||||
expect(slideThumbContainer.classList).not.toContain('mat-dragging');
|
||||
}));
|
||||
|
||||
it('should drag from start to end in RTL', fakeAsync(() => {
|
||||
testComponent.direction = 'rtl';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(slideToggle.checked).toBe(false);
|
||||
|
||||
gestureConfig.emitEventForElement('slidestart', slideThumbContainer);
|
||||
|
||||
expect(slideThumbContainer.classList).toContain('mat-dragging');
|
||||
|
||||
gestureConfig.emitEventForElement('slide', slideThumbContainer, {
|
||||
deltaX: -200 // Arbitrary, large delta that will be clamped to the end of the slide-toggle.
|
||||
});
|
||||
|
||||
gestureConfig.emitEventForElement('slideend', slideThumbContainer);
|
||||
|
||||
// Flush the timeout for the slide ending.
|
||||
tick();
|
||||
|
||||
expect(slideToggle.checked).toBe(true);
|
||||
expect(slideThumbContainer.classList).not.toContain('mat-dragging');
|
||||
}));
|
||||
|
||||
it('should drag from end to start', fakeAsync(() => {
|
||||
slideToggle.checked = true;
|
||||
|
||||
@@ -513,6 +537,29 @@ describe('MatSlideToggle without forms', () => {
|
||||
expect(slideThumbContainer.classList).not.toContain('mat-dragging');
|
||||
}));
|
||||
|
||||
it('should drag from end to start in RTL', fakeAsync(() => {
|
||||
testComponent.direction = 'rtl';
|
||||
fixture.detectChanges();
|
||||
|
||||
slideToggle.checked = true;
|
||||
|
||||
gestureConfig.emitEventForElement('slidestart', slideThumbContainer);
|
||||
|
||||
expect(slideThumbContainer.classList).toContain('mat-dragging');
|
||||
|
||||
gestureConfig.emitEventForElement('slide', slideThumbContainer, {
|
||||
deltaX: 200 // Arbitrary, large delta that will be clamped to the end of the slide-toggle.
|
||||
});
|
||||
|
||||
gestureConfig.emitEventForElement('slideend', slideThumbContainer);
|
||||
|
||||
// Flush the timeout for the slide ending.
|
||||
tick();
|
||||
|
||||
expect(slideToggle.checked).toBe(false);
|
||||
expect(slideThumbContainer.classList).not.toContain('mat-dragging');
|
||||
}));
|
||||
|
||||
it('should not drag when disabled', fakeAsync(() => {
|
||||
slideToggle.disabled = true;
|
||||
|
||||
@@ -943,7 +990,7 @@ describe('MatSlideToggle with forms', () => {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<mat-slide-toggle [required]="isRequired"
|
||||
<mat-slide-toggle [dir]="direction" [required]="isRequired"
|
||||
[disabled]="isDisabled"
|
||||
[color]="slideColor"
|
||||
[id]="slideId"
|
||||
@@ -976,6 +1023,7 @@ class SlideToggleBasic {
|
||||
labelPosition: string;
|
||||
toggleTriggered: number = 0;
|
||||
dragTriggered: number = 0;
|
||||
direction: Direction = 'ltr';
|
||||
|
||||
onSlideClick: (event?: Event) => void = () => {};
|
||||
onSlideChange = (event: MatSlideToggleChange) => this.lastEvent = event;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {FocusMonitor, FocusOrigin} from '@angular/cdk/a11y';
|
||||
import {Directionality} from '@angular/cdk/bidi';
|
||||
import {coerceBooleanProperty} from '@angular/cdk/coercion';
|
||||
import {Platform} from '@angular/cdk/platform';
|
||||
import {
|
||||
@@ -193,7 +194,8 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
|
||||
private _ngZone: NgZone,
|
||||
@Inject(MAT_SLIDE_TOGGLE_DEFAULT_OPTIONS)
|
||||
public defaults: MatSlideToggleDefaultOptions,
|
||||
@Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string) {
|
||||
@Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string,
|
||||
@Optional() private _dir?: Directionality) {
|
||||
super(elementRef);
|
||||
this.tabIndex = parseInt(tabIndex) || 0;
|
||||
}
|
||||
@@ -330,9 +332,10 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
|
||||
|
||||
_onDrag(event: HammerInput) {
|
||||
if (this._dragging) {
|
||||
this._dragPercentage = this._getDragPercentage(event.deltaX);
|
||||
const direction = this._dir && this._dir.value === 'rtl' ? -1 : 1;
|
||||
this._dragPercentage = this._getDragPercentage(event.deltaX * direction);
|
||||
// Calculate the moved distance based on the thumb bar width.
|
||||
const dragX = (this._dragPercentage / 100) * this._thumbBarWidth;
|
||||
const dragX = (this._dragPercentage / 100) * this._thumbBarWidth * direction;
|
||||
this._thumbEl.nativeElement.style.transform = `translate3d(${dragX}px, 0, 0)`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user