Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 4717cb2

Browse files
committed
refactor(switch): refactor to match new spec
1 parent ea42c1e commit 4717cb2

File tree

8 files changed

+264
-67
lines changed

8 files changed

+264
-67
lines changed

src/components/checkbox/checkbox.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant,
8787
0: {}
8888
}, attr, [ngModelCtrl]);
8989

90-
element.on('click', listener);
90+
// Used by switch. in Switch, we don't want click listeners; we have more granular
91+
// touchup/touchdown listening.
92+
if (!attr.mdNoClick) {
93+
element.on('click', listener);
94+
}
9195
element.on('keypress', keypressHandler);
9296
ngModelCtrl.$render = render;
9397

src/components/switch/_switch.scss

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,80 @@
1-
$switch-width: $baseline-grid * 8;
1+
$switch-width: 36px !default;
2+
$switch-height: $baseline-grid * 3 !default;
3+
$switch-bar-height: 14px !default;
4+
$switch-thumb-size: 20px !default;
25

36
md-switch {
4-
display: block;
5-
position: relative;
6-
height: $baseline-grid * 3;
7-
margin: $baseline-grid;
87

98
display: flex;
109
align-items: center;
1110

12-
.md-switch-bar {
11+
.md-container {
12+
width: $switch-width;
13+
height: $switch-height;
14+
position: relative;
15+
user-select: none;
16+
margin-right: 8px;
17+
}
18+
19+
.md-text {
20+
border: 1px solid transparent;
21+
}
22+
23+
.md-bar {
24+
left: 1px;
25+
width: $switch-width - 2px;
26+
top: $switch-height / 2 - $switch-bar-height / 2;
27+
height: $switch-bar-height;
28+
border-radius: 8px;
1329
position: absolute;
14-
left: $baseline-grid * 2;
15-
top: $baseline-grid * 1.5;
16-
width: $baseline-grid * 4;
17-
height: 1px;
18-
pointer-events: none;
1930
}
2031

21-
/* used also in _radio-button.scss */
22-
.md-switch-thumb {
32+
.md-thumb-container {
33+
top: $switch-height / 2 - $switch-thumb-size / 2;
34+
left: 0;
35+
width: $switch-width - $switch-thumb-size;
36+
position: absolute;
37+
transform: translate3d(0,0,0);
38+
z-index: 1;
39+
}
40+
&.md-checked .md-thumb-container {
41+
transform: translate3d(100%,0,0);
42+
}
43+
44+
.md-thumb {
2345
position: absolute;
2446
margin: 0;
2547
left: 0;
2648
top: 0;
2749
outline: none;
50+
height: $switch-thumb-size;
51+
width: $switch-thumb-size;
52+
border-radius: 50%;
53+
box-shadow: $whiteframe-shadow-z1;
2854

29-
.md-container {
55+
.md-ripple-container {
3056
position: absolute;
31-
transition: transform 0.2s linear;
32-
transform: translate3d(0,0,0);
33-
}
34-
&.md-checked .md-container {
35-
transform: translate3d($switch-width - 16,0,0);
57+
display: block;
58+
width: auto;
59+
height: auto;
60+
left: -$switch-thumb-size;
61+
top: -$switch-thumb-size;
62+
right: -$switch-thumb-size;
63+
bottom: -$switch-thumb-size;
3664
}
65+
}
3766

38-
.md-label {
39-
margin-left: $baseline-grid * 9;
67+
&.transition {
68+
.md-bar,
69+
.md-thumb-container,
70+
.md-thumb {
71+
transition: $swift-ease-in-out;
72+
transition-property: transform, background-color;
73+
}
74+
.md-bar,
75+
.md-thumb {
76+
transition-delay: 0.05s;
4077
}
4178
}
79+
4280
}

src/components/switch/demoBasicUsage/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="inset">
1+
<div class="inset" ng-controller="SwitchDemoCtrl">
22
<md-switch ng-model="data.cb1" aria-label="Switch 1">
33
Switch 1: {{ data.cb1 }}
44
</md-switch>
@@ -11,7 +11,7 @@
1111
Switch (Disabled)
1212
</md-switch>
1313

14-
<md-switch ng-disabled="true" aria-label="Disabled active switch" ng-model="data.cb4" ng-init="data.cb4=true">
14+
<md-switch ng-disabled="true" aria-label="Disabled active switch" ng-model="data.cb4">
1515
Switch (Disabled, Active)
1616
</md-switch>
1717

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
angular.module('switchDemo1', ['ngMaterial']);
1+
angular.module('switchDemo1', ['ngMaterial'])
2+
.controller('SwitchDemoCtrl', function($scope) {
3+
$scope.data = {
4+
cb1: true,
5+
cb2: 'nope',
6+
cb4: true
7+
};
8+
});
Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,46 @@
1-
$switch-color: $foreground-secondary-color !default;
2-
$switch-focus-color: map-get($foreground-color-palette, '1000');
1+
$switch-color-palette: $primary-color-palette !default;
2+
$switch-off-color-palette: $foreground-color-palette !default;
3+
4+
$switch-on-color: map-get($switch-color-palette, '500') !default;
5+
$switch-on-bar-color: rgba($switch-on-color, 0.5) !default;
6+
7+
$switch-off-color: map-get($switch-off-color-palette, '50') !default;
8+
$switch-off-bar-color: map-get($switch-off-color-palette, '500') !default;
9+
10+
$switch-disabled-color: map-get($switch-off-color-palette, '400') !default;
11+
$switch-disabled-bar-color: rgba(#000, 0.12);
312

413
md-switch.md-#{$theme-name}-theme {
5-
.md-switch-bar {
6-
background-color: $switch-color;
14+
.md-thumb {
15+
background-color: $switch-off-color;
16+
}
17+
.md-bar {
18+
background-color: $switch-off-bar-color;
19+
}
20+
21+
&.md-checked {
22+
.md-thumb {
23+
background-color: $switch-on-color;
24+
}
25+
.md-bar {
26+
background-color: $switch-on-bar-color;
27+
}
728
}
8-
.md-switch-thumb {
9-
&:focus .md-label {
10-
border: 1px dotted black;
29+
30+
&[disabled] {
31+
.md-thumb {
32+
background-color: $switch-disabled-color;
33+
}
34+
.md-bar {
35+
background-color: $switch-disabled-bar-color;
1136
}
1237
}
38+
39+
&:focus {
40+
.md-text {
41+
border-color: black;
42+
border-style: dotted;
43+
}
44+
}
45+
1346
}

src/components/switch/switch.js

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99

1010
angular.module('material.components.switch', [
1111
'material.core',
12-
'material.components.checkbox',
13-
'material.components.radioButton'
12+
'material.components.checkbox'
1413
])
1514
.directive('mdSwitch', MdSwitch);
1615

@@ -47,30 +46,90 @@ angular.module('material.components.switch', [
4746
*
4847
* </hljs>
4948
*/
50-
function MdSwitch(mdCheckboxDirective, mdRadioButtonDirective, $mdTheming) {
49+
function MdSwitch(mdCheckboxDirective, $mdTheming, $mdUtil, $document, $mdConstant, $parse, $$rAF) {
5150
var checkboxDirective = mdCheckboxDirective[0];
52-
var radioButtonDirective = mdRadioButtonDirective[0];
5351

5452
return {
5553
restrict: 'E',
5654
transclude: true,
5755
template:
58-
'<div class="md-switch-bar"></div>' +
59-
'<div class="md-switch-thumb">' +
60-
radioButtonDirective.template +
56+
'<div class="md-container">' +
57+
'<div class="md-bar"></div>' +
58+
'<div class="md-thumb-container">' +
59+
'<div class="md-thumb" md-ink-ripple md-ink-ripple-checkbox></div>' +
60+
'</div>'+
61+
'</div>' +
62+
'<div ng-transclude class="md-text">' +
6163
'</div>',
6264
require: '?ngModel',
6365
compile: compile
6466
};
6567

6668
function compile(element, attr) {
67-
var thumb = angular.element(element[0].querySelector('.md-switch-thumb'));
68-
var checkboxLink = checkboxDirective.compile(thumb, attr);
69+
var checkboxLink = checkboxDirective.compile(element, attr);
6970

70-
return function (scope, element, attr, ngModelCtrl) {
71-
$mdTheming(element);
72-
return checkboxLink(scope, thumb, attr, ngModelCtrl);
71+
return function (scope, element, attr, ngModel) {
72+
ngModel = ngModel || $mdUtil.fakeNgModel();
73+
var disabledGetter = $parse(attr.ngDisabled);
74+
var thumbContainer = angular.element(element[0].querySelector('.md-thumb-container'));
75+
var switchContainer = angular.element(element[0].querySelector('.md-container'));
76+
77+
// no transition on initial load
78+
$$rAF(function() {
79+
element.addClass('transition');
80+
});
81+
82+
// Tell the checkbox we don't want a click listener.
83+
// Our drag listener tells us everything, using more granular events.
84+
attr.mdNoClick = true;
85+
checkboxLink(scope, element, attr, ngModel);
86+
87+
$mdUtil.pannable(scope, switchContainer);
88+
89+
// These events are triggered by setup drag
90+
switchContainer.on('$md.panstart', onPanStart)
91+
.on('$md.pan', onPan)
92+
.on('$md.panend', onPanEnd);
93+
94+
function onPanStart(ev, drag) {
95+
// Don't go if ng-disabled===true
96+
if (disabledGetter(scope)) return ev.preventDefault();
97+
98+
drag.width = thumbContainer.prop('offsetWidth');
99+
element.removeClass('transition');
100+
}
101+
function onPan(ev, drag) {
102+
var percent = drag.distance / drag.width;
103+
104+
//if checked, start from right. else, start from left
105+
var translate = ngModel.$viewValue ? 1 - percent : -percent;
106+
// Make sure the switch stays inside its bounds, 0-1%
107+
translate = Math.max(0, Math.min(1, translate));
108+
109+
thumbContainer.css($mdConstant.CSS.TRANSFORM, 'translate3d(' + (100*translate) + '%,0,0)');
110+
drag.translate = translate;
111+
}
112+
function onPanEnd(ev, drag) {
113+
if (disabledGetter(scope)) return false;
114+
115+
element.addClass('transition');
116+
thumbContainer.css($mdConstant.CSS.TRANSFORM, '');
117+
118+
// We changed if there is no distance (this is a click a click),
119+
// or if the drag distance is >50% of the total.
120+
var isChanged = Math.abs(drag.distance || 0) < 5 ||
121+
(ngModel.$viewValue ? drag.translate < 0.5 : drag.translate > 0.5);
122+
if (isChanged) {
123+
scope.$apply(function() {
124+
ngModel.$setViewValue(!ngModel.$viewValue);
125+
ngModel.$render();
126+
});
127+
}
128+
}
73129
};
74130
}
131+
132+
75133
}
134+
76135
})();

0 commit comments

Comments
 (0)