Skip to content

Commit

Permalink
fix(slide-toggle): occasional element jumping (#3311)
Browse files Browse the repository at this point in the history
  • Loading branch information
devversion authored and kara committed Mar 1, 2017
1 parent 09c6386 commit beb0edf
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 62 deletions.
35 changes: 19 additions & 16 deletions src/lib/slide-toggle/slide-toggle.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
<label class="mat-slide-toggle-label" #label>

<div class="mat-slide-toggle-container">
<div class="mat-slide-toggle-bar"></div>

<div class="mat-slide-toggle-thumb-container"
(slidestart)="_onDragStart()"
(slide)="_onDrag($event)"
(slideend)="_onDragEnd()">

<div class="mat-slide-toggle-thumb">
<div class="mat-slide-toggle-ripple" md-ripple
[mdRippleTrigger]="label"
[mdRippleCentered]="true"
[mdRippleDisabled]="disableRipple || disabled">
</div>
</div>
</div>
<div class="mat-slide-toggle-bar">

<input #input class="mat-slide-toggle-input cdk-visually-hidden" type="checkbox"
[id]="inputId"
Expand All @@ -30,7 +15,25 @@
(focus)="_onInputFocus()"
(change)="_onChangeEvent($event)"
(click)="_onInputClick($event)">

<div class="mat-slide-toggle-thumb-container"
(slidestart)="_onDragStart()"
(slide)="_onDrag($event)"
(slideend)="_onDragEnd()">

<div class="mat-slide-toggle-thumb"></div>

<div class="mat-slide-toggle-ripple" md-ripple
[mdRippleTrigger]="label"
[mdRippleCentered]="true"
[mdRippleDisabled]="disableRipple || disabled">
</div>

</div>


</div>

<span class="mat-slide-toggle-content">
<ng-content></ng-content>
</span>
Expand Down
74 changes: 33 additions & 41 deletions src/lib/slide-toggle/slide-toggle.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
@import '../core/style/elevation';
@import '../core/a11y/a11y';


$mat-slide-toggle-width: 36px !default;
$mat-slide-toggle-height: 24px !default;
$mat-slide-toggle-bar-height: 14px !default;
$mat-slide-toggle-thumb-size: 20px !default;
$mat-slide-toggle-bar-border-radius: 8px !default;
$mat-slide-toggle-height: 24px !default;
$mat-slide-toggle-margin: 16px !default;
$mat-slide-toggle-spacing: 8px !default;
$mat-slide-toggle-ripple-radius: 23px !default;
$mat-slide-toggle-bar-width: 36px !default;
$mat-slide-toggle-bar-height: 14px !default;
$mat-slide-toggle-bar-track-width: $mat-slide-toggle-bar-width - $mat-slide-toggle-thumb-size;


.mat-slide-toggle {
Expand All @@ -30,13 +31,12 @@ $mat-slide-toggle-ripple-radius: 23px !default;

&.mat-checked {
.mat-slide-toggle-thumb-container {
transform: translate3d(100%, 0, 0);
transform: translate3d($mat-slide-toggle-bar-track-width, 0, 0);
}
}

&.mat-disabled {

.mat-slide-toggle-label, .mat-slide-toggle-container {
.mat-slide-toggle-label, .mat-slide-toggle-thumb-container {
cursor: default;
}
}
Expand All @@ -55,69 +55,63 @@ $mat-slide-toggle-ripple-radius: 23px !default;
.mat-slide-toggle-label {
display: flex;
flex: 1;
flex-direction: row;
align-items: center;

cursor: pointer;
}

/* If the label should be placed before the thumb then we just change the orders. */
.mat-slide-toggle-label-before {
.mat-slide-toggle-label { order: 1; }
.mat-slide-toggle-container { order: 2; }
}

// Container for the composition of the slide-toggle / switch indicator.
.mat-slide-toggle-container {
cursor: grab;
width: $mat-slide-toggle-width;
height: $mat-slide-toggle-height;

position: relative;
.mat-slide-toggle-bar { order: 2; }
}

/* Apply the margin for slide-toggles and revert it for RTL toggles with labelPosition before. */
[dir='rtl'] .mat-slide-toggle-label-before .mat-slide-toggle-container, .mat-slide-toggle-container {
// Apply the margin for slide-toggles and revert it for RTL toggles with labelPosition before.
[dir='rtl'] .mat-slide-toggle-label-before .mat-slide-toggle-bar,
.mat-slide-toggle-bar {
margin-right: $mat-slide-toggle-spacing;
margin-left: 0;
}

/* Switch the margins in RTL mode and also switch it if the labelPosition is set to before. */
[dir='rtl'], .mat-slide-toggle-label-before {
.mat-slide-toggle-container {
// Switch the margins in RTL mode and also switch it if the labelPosition is set to before.
[dir='rtl'],
.mat-slide-toggle-label-before {
.mat-slide-toggle-bar {
margin-left: $mat-slide-toggle-spacing;
margin-right: 0;
}
}

// The thumb container is responsible for the dragging functionality.
// It moves around and holds the actual circle as a thumb.
// The container includes the visual thumb and the ripple container element.
.mat-slide-toggle-thumb-container {
$thumb-bar-vertical-padding: ($mat-slide-toggle-thumb-size - $mat-slide-toggle-bar-height) / 2;

position: absolute;
top: $mat-slide-toggle-height / 2 - $mat-slide-toggle-thumb-size / 2;
left: 0;
z-index: 1;

width: $mat-slide-toggle-width - $mat-slide-toggle-thumb-size;
width: $mat-slide-toggle-thumb-size;
height: $mat-slide-toggle-thumb-size;
top: -$thumb-bar-vertical-padding;
left: 0;

transform: translate3d(0, 0, 0);

transition: $swift-linear;
transition-property: transform;

cursor: grab;

// Once the thumb container is being dragged around, we remove the transition duration to
// make the drag feeling fast and not delayed.
&.mat-dragging {
transition-duration: 0ms;
}
}

// The thumb will be elevated from the slide-toggle bar.
// Also the thumb is bound to its parent thumb-container, which manages the movement of the thumb.
// The visual thumb element that moves inside of the thumb bar.
// The parent thumb-container container is responsible for the movement of the visual thumb.
.mat-slide-toggle-thumb {
position: absolute;
margin: 0;
left: 0;
top: 0;

height: $mat-slide-toggle-thumb-size;
width: $mat-slide-toggle-thumb-size;
border-radius: 50%;
Expand All @@ -131,16 +125,14 @@ $mat-slide-toggle-ripple-radius: 23px !default;
}

// Horizontal bar for the slide-toggle.
// The slide-toggle bar is shown behind the thumb container.
// The slide-toggle bar is shown behind the movable thumb element.
.mat-slide-toggle-bar {
position: absolute;
left: 1px;
top: $mat-slide-toggle-height / 2 - $mat-slide-toggle-bar-height / 2;
position: relative;

width: $mat-slide-toggle-width - 2px;
width: $mat-slide-toggle-bar-width;
height: $mat-slide-toggle-bar-height;

border-radius: 8px;
border-radius: $mat-slide-toggle-bar-border-radius;

@include cdk-high-contrast {
background: #fff;
Expand Down Expand Up @@ -173,4 +165,4 @@ $mat-slide-toggle-ripple-radius: 23px !default;
border-radius: 50%;
z-index: 1;
pointer-events: none;
}
}
12 changes: 7 additions & 5 deletions src/lib/slide-toggle/slide-toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ class SlideToggleRenderer {
/** Previous checked state before drag started. */
private _previousChecked: boolean;

/** Percentage of the thumb while dragging. */
/** Percentage of the thumb while dragging. Percentage as fraction of 100. */
dragPercentage: number;

/** Whether the thumb is currently being dragged. */
Expand Down Expand Up @@ -333,12 +333,14 @@ class SlideToggleRenderer {

/** Updates the thumb containers position from the specified distance. */
updateThumbPosition(distance: number) {
this.dragPercentage = this._getThumbPercentage(distance);
applyCssTransform(this._thumbEl, `translate3d(${this.dragPercentage}%, 0, 0)`);
this.dragPercentage = this._getDragPercentage(distance);
// Calculate the moved distance based on the thumb bar width.
let dragX = (this.dragPercentage / 100) * this._thumbBarWidth;
applyCssTransform(this._thumbEl, `translate3d(${dragX}px, 0, 0)`);
}

/** Retrieves the percentage of thumb from the moved distance. */
private _getThumbPercentage(distance: number) {
/** Retrieves the percentage of thumb from the moved distance. Percentage as fraction of 100. */
private _getDragPercentage(distance: number) {
let percentage = (distance / this._thumbBarWidth) * 100;

// When the toggle was initially checked, then we have to start the drag at the end.
Expand Down

0 comments on commit beb0edf

Please sign in to comment.