From 5718b525b44c9942c946df4a6173e906bf028f94 Mon Sep 17 00:00:00 2001 From: Derek Louie Date: Tue, 15 Mar 2016 11:57:54 -0700 Subject: [PATCH] Adding checkboxes to angular material stuff --- src/components/checkbox/checkbox-theme.scss | 72 +++++---- src/components/checkbox/checkbox.scss | 144 ++++++++++-------- .../select/demoOptionGroups/index.html | 5 +- .../select/demoOptionGroups/script.js | 10 ++ src/components/select/select-theme.scss | 9 ++ src/components/select/select.js | 7 + src/components/select/select.scss | 17 +++ src/components/select/select.spec.js | 24 +++ 8 files changed, 189 insertions(+), 99 deletions(-) diff --git a/src/components/checkbox/checkbox-theme.scss b/src/components/checkbox/checkbox-theme.scss index 96728c870b8..afe6ebabab6 100644 --- a/src/components/checkbox/checkbox-theme.scss +++ b/src/components/checkbox/checkbox-theme.scss @@ -1,11 +1,46 @@ -md-checkbox.md-THEME_NAME-theme { +@mixin checkbox-primary($checkedSelector: '.md-checked') { + .md-ripple { + color: '{{primary-600}}'; + } + + &#{$checkedSelector} .md-ripple { + color: '{{background-600}}'; + } + + .md-ink-ripple { + color: '{{foreground-2}}'; + } + + &#{$checkedSelector} .md-ink-ripple { + color: '{{primary-color-0.87}}'; + } + + ._md-icon { + border-color: '{{foreground-2}}'; + } + + &#{$checkedSelector} ._md-icon { + background-color: '{{primary-color-0.87}}'; + } + + &#{$checkedSelector}.md-focused ._md-container:before { + background-color: '{{primary-color-0.26}}'; + } + &#{$checkedSelector} ._md-icon:after { + border-color: '{{primary-contrast-0.87}}'; + } +} + +md-checkbox.md-THEME_NAME-theme { .md-ripple { color: '{{accent-600}}'; } + &.md-checked .md-ripple { color: '{{background-600}}'; } + &.md-checked.md-focused ._md-container:before { background-color: '{{accent-color-0.26}}'; } @@ -21,6 +56,7 @@ md-checkbox.md-THEME_NAME-theme { ._md-icon { border-color: '{{foreground-2}}'; } + &.md-checked ._md-icon { background-color: '{{accent-color-0.87}}'; } @@ -31,35 +67,7 @@ md-checkbox.md-THEME_NAME-theme { &:not([disabled]) { &.md-primary { - .md-ripple { - color: '{{primary-600}}'; - } - &.md-checked .md-ripple { - color: '{{background-600}}'; - } - - .md-ink-ripple { - color: '{{foreground-2}}'; - } - - &.md-checked .md-ink-ripple { - color: '{{primary-color-0.87}}'; - } - - ._md-icon { - border-color: '{{foreground-2}}'; - } - &.md-checked ._md-icon { - background-color: '{{primary-color-0.87}}'; - } - - &.md-checked.md-focused ._md-container:before { - background-color: '{{primary-color-0.26}}'; - } - - &.md-checked ._md-icon:after { - border-color: '{{primary-contrast-0.87}}'; - } + @include checkbox-primary; } &.md-warn { @@ -78,12 +86,15 @@ md-checkbox.md-THEME_NAME-theme { ._md-icon { border-color: '{{foreground-2}}'; } + &.md-checked ._md-icon { background-color: '{{warn-color-0.87}}'; } + &.md-checked.md-focused:not([disabled]) ._md-container:before { background-color: '{{warn-color-0.26}}'; } + &.md-checked ._md-icon:after { border-color: '{{background-200}}'; } @@ -91,7 +102,6 @@ md-checkbox.md-THEME_NAME-theme { } &[disabled] { - ._md-icon { border-color: '{{foreground-3}}'; } diff --git a/src/components/checkbox/checkbox.scss b/src/components/checkbox/checkbox.scss index cdc4ca77b7e..11978ba1301 100644 --- a/src/components/checkbox/checkbox.scss +++ b/src/components/checkbox/checkbox.scss @@ -6,46 +6,15 @@ $checkbox-border-width: 2px !default; $checkbox-text-margin: 10px !default; $checkbox-top: 12px !default; -.md-inline-form { - md-checkbox { - margin: 19px 0 18px; - } -} - -md-checkbox { - box-sizing: border-box; - display: inline-block; - margin-bottom: $checkbox-margin; - white-space: nowrap; - cursor: pointer; - outline: none; - user-select: none; - position: relative; - min-width: $checkbox-width; - min-height: $checkbox-width; - @include rtl(margin-left, 0, $checkbox-margin); - @include rtl(margin-right, $checkbox-margin, 0); - - &:last-of-type { - margin-left: 0; - margin-right: 0; - } - - &.md-focused:not([disabled]) { - ._md-container:before { - left: -8px; - top: -8px; - right: -8px; - bottom: -8px; - } - - &:not(.md-checked) { - ._md-container:before { - background-color: rgba(0, 0, 0, 0.12); - } - } - } - +// This mixin allows a user to use the md-checkbox css outside of the +// md-checkbox directive. +// See src/components/select/select.scss for an example. +@mixin checkbox-container( + $checkedSelector: '.md-checked', + $width: $checkbox-width, + $height: $checkbox-height, + $border-width: $checkbox-border-width, + $border-radius: $checkbox-border-radius) { ._md-container { position: absolute; top: 50%; @@ -54,11 +23,11 @@ md-checkbox { box-sizing: border-box; display: inline-block; - width: $checkbox-width; - height: $checkbox-height; + width: $width; + height: $height; @include rtl(left, 0, auto); @include rtl(right, auto, 0); - + &:before { box-sizing: border-box; background-color: transparent; @@ -97,10 +66,6 @@ md-checkbox { } } - &.md-align-top-left > div._md-container { - top: $checkbox-top; - } - // unchecked ._md-icon { box-sizing: border-box; @@ -108,15 +73,31 @@ md-checkbox { position: absolute; top: 0; left: 0; - width: $checkbox-width; - height: $checkbox-height; - border-width: $checkbox-border-width; + width: $width; + height: $height; + border-width: $border-width; border-style: solid; - border-radius: $checkbox-border-radius; + border-radius: $border-radius; } - &.md-checked ._md-icon { + &#{$checkedSelector} ._md-icon { border: none; + + &:after { + box-sizing: border-box; + transform: rotate(45deg); + position: absolute; + left: $width / 3; + top: $width / 9; + display: table; + width: $width / 3; + height: $width * 2 / 3; + border-width: $border-width; + border-style: solid; + border-top: 0; + border-left: 0; + content: ''; + } } // disabled @@ -124,22 +105,53 @@ md-checkbox { cursor: default; } +} - &.md-checked ._md-icon:after { - box-sizing: border-box; - transform: rotate(45deg); - position: absolute; - left: $checkbox-width / 3; - top: $checkbox-width / 9; - display: table; - width: $checkbox-width / 3; - height: $checkbox-width * 2 / 3; - border-width: $checkbox-border-width; - border-style: solid; - border-top: 0; - border-left: 0; - content: ''; +.md-inline-form { + md-checkbox { + margin: 19px 0 18px; } +} + +md-checkbox { + box-sizing: border-box; + display: inline-block; + margin-bottom: $checkbox-margin; + white-space: nowrap; + cursor: pointer; + outline: none; + user-select: none; + position: relative; + min-width: $checkbox-width; + min-height: $checkbox-width; + @include rtl(margin-left, 0, $checkbox-margin); + @include rtl(margin-right, $checkbox-margin, 0); + + &:last-of-type { + margin-left: 0; + margin-right: 0; + } + + &.md-focused:not([disabled]) { + ._md-container:before { + left: -8px; + top: -8px; + right: -8px; + bottom: -8px; + } + + &:not(.md-checked) { + ._md-container:before { + background-color: rgba(0, 0, 0, 0.12); + } + } + } + + &.md-align-top-left > div._md-container { + top: $checkbox-top; + } + + @include checkbox-container; ._md-label { box-sizing: border-box; diff --git a/src/components/select/demoOptionGroups/index.html b/src/components/select/demoOptionGroups/index.html index daa5570f4eb..b3df40ddd1a 100644 --- a/src/components/select/demoOptionGroups/index.html +++ b/src/components/select/demoOptionGroups/index.html @@ -10,7 +10,7 @@

Pick your pizza below

- + {{topping.name}} @@ -20,6 +20,7 @@

Pick your pizza below

-

You ordered a {{size.toLowerCase()}} pizza with {{topping.toLowerCase()}}.

+

You ordered a {{size.toLowerCase()}} pizza with + {{printSelectedToppings()}}.

diff --git a/src/components/select/demoOptionGroups/script.js b/src/components/select/demoOptionGroups/script.js index 5e45025801e..e03bdbc94e4 100644 --- a/src/components/select/demoOptionGroups/script.js +++ b/src/components/select/demoOptionGroups/script.js @@ -17,4 +17,14 @@ angular { category: 'veg', name: 'Green Pepper' }, { category: 'veg', name: 'Green Olives' } ]; + $scope.selectedToppings = []; + $scope.printSelectedToppings = function printSelectedToppings(){ + // If there is more than one topping, we add an 'and' and an oxford + // comma to be gramatically correct. + if (this.selectedToppings.length > 1) { + var lastTopping = ', and ' + this.selectedToppings.slice(-1)[0]; + return this.selectedToppings.slice(0,-1).join(', ') + lastTopping; + } + return this.selectedToppings.join(''); + }; }); diff --git a/src/components/select/select-theme.scss b/src/components/select/select-theme.scss index ee704ff5e55..bc9c49e7603 100644 --- a/src/components/select/select-theme.scss +++ b/src/components/select/select-theme.scss @@ -75,3 +75,12 @@ md-select-menu.md-THEME_NAME-theme { } } } + + +[md-checkbox-enabled].md-THEME_NAME-theme { + @include checkbox-primary('[selected]'); + + md-option ._md-text { + color: '{{background-900-0.87}}'; + } +} diff --git a/src/components/select/select.js b/src/components/select/select.js index 453dca413cc..cd280df8a0f 100755 --- a/src/components/select/select.js +++ b/src/components/select/select.js @@ -12,6 +12,8 @@ var SELECT_EDGE_MARGIN = 8; var selectNextId = 0; +var CHECKBOX_SELECTION_INDICATOR = + angular.element('
'); angular.module('material.components.select', [ 'material.core', @@ -776,6 +778,11 @@ function OptionDirective($mdButtonInkRipple, $mdUtil) { var optionCtrl = ctrls[0]; var selectCtrl = ctrls[1]; + if (selectCtrl.isMultiple) { + element.attr('md-checkbox-enabled', ''); + element.prepend(CHECKBOX_SELECTION_INDICATOR.clone()); + } + if (angular.isDefined(attr.ngValue)) { scope.$watch(attr.ngValue, setOptionValue); } else if (angular.isDefined(attr.value)) { diff --git a/src/components/select/select.scss b/src/components/select/select.scss index b89940974d0..ef58a3524d6 100755 --- a/src/components/select/select.scss +++ b/src/components/select/select.scss @@ -1,3 +1,6 @@ +$select-checkbox-border-radius: 2px !default; +$select-checkbox-border-width: 2px !default; +$select-checkbox-width: rem(1.4) !default; $select-option-height: 48px; $select-option-padding: 16px; $select-container-padding: 16px; @@ -230,3 +233,17 @@ md-optgroup { border: 1px solid #fff; } } + +md-select-menu[multiple] { + md-option[md-checkbox-enabled] { + @include rtl(padding-left, $select-option-padding * 2.5, $select-option-padding); + @include rtl(padding-right, $select-option-padding, $select-option-padding * 2.5); + + @include checkbox-container('[selected]'); + + ._md-container { + @include rtl(margin-left, $select-option-padding * (2 / 3), auto); + @include rtl(margin-right, auto, $select-option-padding * (2 / 3)); + } + } +} diff --git a/src/components/select/select.spec.js b/src/components/select/select.spec.js index be0961f5708..550fa5ed787 100755 --- a/src/components/select/select.spec.js +++ b/src/components/select/select.spec.js @@ -241,10 +241,21 @@ describe('', function() { '' + '')($rootScope).find('md-select'); var label = select.find('md-select-value'); + var options = select.find('md-option'); + $rootScope.$digest(); expect(label.text()).toBe('Two'); expect(label.hasClass('md-select-placeholder')).toBe(false); + + + // Ensure every md-option element does not have a checkbox prepended to it. + for (var i = 0; i < options.length; i++) { + var checkBoxContainer = options[i].querySelector('._md-container'); + var checkBoxIcon = options[i].querySelector('._md-icon'); + expect(checkBoxContainer).toBe(null); + expect(checkBoxIcon).toBe(null); + } })); it('supports rendering multiple', inject(function($rootScope, $compile) { @@ -258,11 +269,24 @@ describe('', function() { '' + '')($rootScope).find('md-select'); var label = select.find('md-select-value'); + var options = select.find('md-option'); + var container; + var icon; + $rootScope.$digest(); $rootScope.$digest(); expect(label.text()).toBe('One, Three'); expect(label.hasClass('md-select-placeholder')).toBe(false); + + // Ensure every md-option element has a checkbox prepended to it. + for (var i = 0; i < options.length; i++) { + var checkBoxContainer = options[i].querySelector('._md-container'); + var checkBoxIcon = options[i].querySelector('._md-icon'); + expect(checkBoxContainer).not.toBe(null); + expect(checkBoxIcon).not.toBe(null); + } + })); it('supports raw html', inject(function($rootScope, $compile, $sce) {