Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(slide-toggle): occasional element jumping #3311

Merged
merged 2 commits into from
Mar 1, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
70 changes: 30 additions & 40 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,61 @@ $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; }
.mat-slide-toggle-bar { 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;
}

/* 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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can you put each selector on its own line (makes it easy to tell its multiple instead of 1 big selector)

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. */
// Switch the margins in RTL mode and also switch it if the labelPosition is set to before.
[dir='rtl'], .mat-slide-toggle-label-before {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it was already like this, but 1 selector per line

.mat-slide-toggle-container {
.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 +123,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 +163,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)`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be better to have a getter that returns {'transform': 'translate3d(...)'} and do [ngStyle]=?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually wanted to keep such logic in the renderer, but I think this is a good idea. I will make the changes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to use ngStyle but actually ran into more issues than advantages.

The slide-toggle would need to trigger a new round of change-detection onDragEnd, so that the drag styles are reverted.

I feel like for the OnPush strategy it is more beneficial to use applyTransform.

}

/** 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