From 66188158b1f4fe265895a93bdaa6950cafaaa1f8 Mon Sep 17 00:00:00 2001 From: Ben Rubin Date: Tue, 19 Jul 2016 21:42:17 -0500 Subject: [PATCH] added mdExpansionPanelIcon directive Added ability to pass options object to expand, collapse, and remove function. currently only animation(boolean) is available Minor changes to animations --- app/pages/group/group.controller.js | 2 +- app/pages/home/home.html | 4 + gulp/config.js | 1 + gulp/jsBuild.js | 2 +- gulpfile.js | 21 ++- package.json | 4 +- src/expansionPanels-theme.scss | 7 +- src/expansionPanels.scss | 146 +++++++++--------- .../ic_keyboard_arrow_right_black_24px.svg | 4 + src/js/expansionPanel.directive.js | 41 +++-- src/js/expansionPanel.service.js | 4 +- src/js/expansionPanelCollapsed.directive.js | 19 ++- src/js/expansionPanelExpanded.directive.js | 17 +- src/js/expansionPanelGroup.directive.js | 8 +- src/js/expansionPanelGroup.service.js | 12 +- src/js/expansionPanelIcon.directive.js | 25 +++ 16 files changed, 191 insertions(+), 126 deletions(-) create mode 100644 src/icons/ic_keyboard_arrow_right_black_24px.svg create mode 100644 src/js/expansionPanelIcon.directive.js diff --git a/app/pages/group/group.controller.js b/app/pages/group/group.controller.js index 2340e43..40acd42 100644 --- a/app/pages/group/group.controller.js +++ b/app/pages/group/group.controller.js @@ -40,7 +40,7 @@ function GroupController($mdExpansionPanelGroup) { setTimeout(function () { change(); - }, 10000) + }, 10000); }); function addTemplated() { diff --git a/app/pages/home/home.html b/app/pages/home/home.html index 02c8561..7f2e8fc 100644 --- a/app/pages/home/home.html +++ b/app/pages/home/home.html @@ -16,6 +16,7 @@

Panels

Title
Summary
+
@@ -23,6 +24,7 @@

Panels

Expanded Title
Expanded Summary
+
@@ -43,6 +45,7 @@

Content

+
Sticky
header and footer will stick
@@ -50,6 +53,7 @@

Content

+
Sticky
header and footer will stick
diff --git a/gulp/config.js b/gulp/config.js index 01c077b..c2acf54 100644 --- a/gulp/config.js +++ b/gulp/config.js @@ -9,5 +9,6 @@ exports.paths = { appCss: ['app/style.css', 'app/**/*.css'], injectCss: ['public/*.css', 'public/**/*.css'], partials: ['app/**/*.html'], + icons: ['src/**/*.svg'], bower: './bower.json' }; diff --git a/gulp/jsBuild.js b/gulp/jsBuild.js index e87c9a6..f70fe7f 100644 --- a/gulp/jsBuild.js +++ b/gulp/jsBuild.js @@ -14,7 +14,7 @@ var gutil = require('gulp-util'); exports.getDevSrc = function (srcs) { srcs = srcs || paths.scripts; - + return function dev() { return gulp.src(srcs, {base: paths.src}) .pipe(wrap('(function(){"use strict";<%= contents %>}());')) diff --git a/gulpfile.js b/gulpfile.js index 4b29a45..6f2c6c4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -5,6 +5,7 @@ var serve = require('gulp-serve'); var gulpSequence = require('gulp-sequence'); var del = require('del'); var bump = require('gulp-bump'); +var templateCache = require('gulp-angular-templatecache'); var KarmaServer = require('karma').Server; @@ -32,12 +33,13 @@ gulp.task('buildLocal', gulpSequence( 'jsSrcBuild', 'jsAppBuild', 'cssBuild', - 'copyPartials' + 'copyPartials', + 'copyIcons' ], 'indexBuild' )); -gulp.task('build', ['jsReleaseBuild', 'cssReleaseBuild']); +gulp.task('build', gulpSequence('buildIconCache', ['jsReleaseBuild', 'cssReleaseBuild'], 'cleanIconCache')); @@ -51,6 +53,21 @@ gulp.task('copyPartials', function () { .pipe(gulp.dest(paths.dest)); }); +gulp.task('copyIcons', function () { + return gulp.src(paths.icons, {base: paths.src}) + .pipe(gulp.dest(paths.dest)); +}); + +gulp.task('buildIconCache', function () { + return gulp.src(paths.icons) + .pipe(templateCache({module: 'material.components.expansionPanels'})) + .pipe(gulp.dest(paths.src)); +}); + +gulp.task('cleanIconCache', function () { + return del('src/templates.js'); +}); + gulp.task('serve', serve({ root: ['public', 'bower_components'], port: 8080 diff --git a/package.json b/package.json index 0f68257..85be90b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "angular-material-expansion-panel", "version": "0.4.8", "author": "Ben Rubin", - "description": "Material Design Expansion Panels.", + "description": "Material Design Expansion Panels for angular material", "keywords": "material, material-design, design, angular, component, expansion, panel, panels", "license": "MIT", "repository": { @@ -13,7 +13,7 @@ "bump": "^0.2.5", "del": "^2.2.0", "gulp": "^3.9.1", - "gulp-angular-templatecache": "^1.8.0", + "gulp-angular-templatecache": "^1.9.1", "gulp-autoprefixer": "^3.1.0", "gulp-bump": "^1.0.0", "gulp-concat": "^2.6.0", diff --git a/src/expansionPanels-theme.scss b/src/expansionPanels-theme.scss index d86c77c..a8e4504 100644 --- a/src/expansionPanels-theme.scss +++ b/src/expansionPanels-theme.scss @@ -18,11 +18,8 @@ md-expansion-panel { border-color: #DDD; } - - .md-expansion-panel-icon-container { - .md-expansion-panel-icon { - color: #999; - } + .md-expansion-panel-icon svg { + fill: #999; } diff --git a/src/expansionPanels.scss b/src/expansionPanels.scss index 3b72338..337c002 100644 --- a/src/expansionPanels.scss +++ b/src/expansionPanels.scss @@ -29,14 +29,16 @@ md-expansion-panel { overflow: hidden; } - &.md-open { - transition: margin-top 0.12s cubic-bezier(0.25, 0.8, 0.25, 1), - margin-bottom 0.12s cubic-bezier(0.25, 0.8, 0.25, 1); - } + &:not(.md-no-animation) { + &.md-open { + transition: margin-top 0.12s cubic-bezier(0.25, 0.8, 0.25, 1), + margin-bottom 0.12s cubic-bezier(0.25, 0.8, 0.25, 1); + } - &.md-close { - transition: margin-top 0.08s cubic-bezier(0.25, 0.8, 0.25, 1), - margin-bottom 0.08s cubic-bezier(0.25, 0.8, 0.25, 1); + &.md-close { + transition: margin-top 0.08s cubic-bezier(0.25, 0.8, 0.25, 1), + margin-bottom 0.08s cubic-bezier(0.25, 0.8, 0.25, 1); + } } } @@ -71,28 +73,36 @@ md-expansion-panel-header .md-summary { /* --- Expansion Panel Collapsed ---- */ -md-expansion-panel-collapsed { - display: flex; - min-height: 48px; - line-height: 48px; - padding: 0 24px; - opacity: 1; - z-index: 2; - box-sizing: border-box; +md-expansion-panel { + md-expansion-panel-collapsed { + display: flex; + min-height: 48px; + line-height: 48px; + padding: 0 24px; + opacity: 1; + z-index: 2; + box-sizing: border-box; - &.md-absolute { - position: absolute; - } + &.md-absolute { + position: absolute; + } - &.md-show { - transition: opacity 0.03s linear; - transition-delay: 0.03s; + &.md-hide { + opacity: 0; + } } - &.md-hide { - transition: opacity 0.1s cubic-bezier(0.25, 0.8, 0.25, 1); - opacity: 0; + &:not(.md-no-animation) { + md-expansion-panel-collapsed { + &.md-show { + transition: opacity 0.03s linear; + } + + &.md-hide { + transition: opacity 0.1s cubic-bezier(0.25, 0.8, 0.25, 1); + } + } } } @@ -101,38 +111,44 @@ md-expansion-panel-collapsed { /* --- Expansion Panel Expanded --- */ -md-expansion-panel-expanded { - display: none; - min-height: 48px; +md-expansion-panel { + md-expansion-panel-expanded { + display: none; + min-height: 48px; - &.md-show { - transition: max-height 0.12s cubic-bezier(0.25, 0.8, 0.25, 1), - opacity 0.12s cubic-bezier(0.25, 0.8, 0.25, 1); - } + &.md-show, + &.md-hide { + display: block; + } - &.md-hide { - transition: max-height 0.08s cubic-bezier(0.25, 0.8, 0.25, 1), - opacity 0.08s cubic-bezier(0.25, 0.8, 0.25, 1); - } + &.md-scroll-y { + overflow-y: auto; + } - &.md-show, - &.md-hide { - display: block; - } + &.md-overflow { + overflow: hidden + } - &.md-scroll-y { - overflow-y: auto; - } - &.md-overflow { - overflow: hidden + md-expansion-panel-content { + display: block; + padding: 16px 24px; + } } + &:not(.md-no-animation) { + md-expansion-panel-expanded { + &.md-show { + transition: max-height 0.12s cubic-bezier(0.25, 0.8, 0.25, 1), + opacity 0.12s cubic-bezier(0.25, 0.8, 0.25, 1); + } - md-expansion-panel-content { - display: block; - padding: 16px 24px; + &.md-hide { + transition: max-height 0.06s cubic-bezier(0.25, 0.8, 0.25, 1), + opacity 0.06s cubic-bezier(0.25, 0.8, 0.25, 1); + } + } } } @@ -211,40 +227,22 @@ md-expansion-panel-footer { /* --- expand icon --- */ md-expansion-panel { - .md-expansion-panel-icon-container { - &:first-child { - padding-right: 12px; + &:not(.md-no-animation) { + .md-expansion-panel-icon { + transition: transform 0.6s cubic-bezier(0.25, 0.8, 0.25, 1); } + } - - .md-expansion-panel-icon { - &:after { - font-family: 'mdMaterialIcons'; - font-size: 18px; - font-weight: 600; - display: block; - content: '\e315'; - position: relative; - speak: none; - transform: rotate(0deg); - transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); - } + .md-expansion-panel-icon { + &:first-child { + margin-right: 18px; } } &.md-open { - > { - md-expansion-panel-collasped, - md-expansion-panel-header { - .md-expansion-panel-icon-container { - .md-expansion-panel-icon { - &:after { - transform: rotate(90deg); - } - } - } - } + .md-expansion-panel-icon { + transform: rotate(90deg); } } } diff --git a/src/icons/ic_keyboard_arrow_right_black_24px.svg b/src/icons/ic_keyboard_arrow_right_black_24px.svg new file mode 100644 index 0000000..5c1e3e4 --- /dev/null +++ b/src/icons/ic_keyboard_arrow_right_black_24px.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/js/expansionPanel.directive.js b/src/js/expansionPanel.directive.js index 07a614b..083637d 100644 --- a/src/js/expansionPanel.directive.js +++ b/src/js/expansionPanel.directive.js @@ -165,9 +165,10 @@ function expansionPanelDirective() { - function expand() { + function expand(options) { if (isOpen === true || isDisabled === true) { return; } isOpen = true; + options = options || {}; var deferred = $q.defer(); @@ -177,45 +178,57 @@ function expansionPanelDirective() { $element.removeClass('md-close'); $element.addClass('md-open'); + if (options.animation === false) { + $element.addClass('md-no-animation'); + } else { + $element.removeClass('md-no-animation'); + } initEvents(); - collapsedCtrl.hide(); - expandedCtrl.show(); + collapsedCtrl.hide(options); + expandedCtrl.show(options); - if (headerCtrl) { headerCtrl.show(); } - if (footerCtrl) { footerCtrl.show(); } + if (headerCtrl) { headerCtrl.show(options); } + if (footerCtrl) { footerCtrl.show(options); } $timeout(function () { deferred.resolve(); - }, ANIMATION_TIME); + }, options.animation === false ? 0 : ANIMATION_TIME); return deferred.promise; } - function collapse() { + function collapse(options) { if (isOpen === false) { return; } isOpen = false; + options = options || {}; var deferred = $q.defer(); $element.addClass('md-close'); $element.removeClass('md-open'); + if (options.animation === false) { + $element.addClass('md-no-animation'); + } else { + $element.removeClass('md-no-animation'); + } killEvents(); - collapsedCtrl.show(); - expandedCtrl.hide(); + collapsedCtrl.show(options); + expandedCtrl.hide(options); - if (headerCtrl) { headerCtrl.hide(); } - if (footerCtrl) { footerCtrl.hide(); } + if (headerCtrl) { headerCtrl.hide(options); } + if (footerCtrl) { footerCtrl.hide(options); } $timeout(function () { deferred.resolve(); - }, ANIMATION_TIME); + }, options.animation === false ? 0 : ANIMATION_TIME); return deferred.promise; } - function remove(noAnimation) { + function remove(options) { + options = options || {}; var deferred = $q.defer(); if (vm.epxansionPanelGroupCtrl) { @@ -227,7 +240,7 @@ function expansionPanelDirective() { deregister = undefined; } - if (noAnimation === true || isOpen === false) { + if (options.animation === false || isOpen === false) { $scope.$destroy(); $element.remove(); deferred.resolve(); diff --git a/src/js/expansionPanel.service.js b/src/js/expansionPanel.service.js index e23fe02..30148dd 100644 --- a/src/js/expansionPanel.service.js +++ b/src/js/expansionPanel.service.js @@ -14,8 +14,8 @@ angular * @example * $mdExpansionPanel('comonentId').then(function (instance) { * instance.exapand(); - * instance.collapse(); - * instance.remove(); + * instance.collapse({animation: false}); + * instance.remove({animation: false}); * instance.onRemove(function () {}); * }); */ diff --git a/src/js/expansionPanelCollapsed.directive.js b/src/js/expansionPanelCollapsed.directive.js index 3203348..c3cc687 100644 --- a/src/js/expansionPanelCollapsed.directive.js +++ b/src/js/expansionPanelCollapsed.directive.js @@ -36,18 +36,20 @@ function expansionPanelCollapsedDirective($animateCss) { }); - function hide() { + function hide(options) { // set width to maintian demensions when element is set to postion: absolute element.css('width', element[0].offsetWidth + 'px'); - // set min height so the expansion panel does not shrink when collapsed element is set to position: absolute expansionPanelCtrl.$element.css('min-height', element[0].offsetHeight + 'px'); - $animateCss(element, { + var animationParams = { addClass: 'md-absolute md-hide', from: {opacity: 1}, to: {opacity: 0} - }) + }; + if (options.animation === false) { animationParams.duration = 0; } + console.log(animationParams); + $animateCss(element, animationParams) .start() .then(function () { element.removeClass('md-hide'); @@ -56,17 +58,18 @@ function expansionPanelCollapsedDirective($animateCss) { } - function show() { + function show(options) { element.css('display', ''); - // set width to maintian demensions when element is set to postion: absolute element.css('width', element[0].parentNode.offsetWidth + 'px'); - $animateCss(element, { + var animationParams = { addClass: 'md-show', from: {opacity: 0}, to: {opacity: 1} - }) + }; + if (options.animation === false) { animationParams.duration = 0; } + $animateCss(element, animationParams) .start() .then(function () { element.removeClass('md-absolute md-show'); diff --git a/src/js/expansionPanelExpanded.directive.js b/src/js/expansionPanelExpanded.directive.js index c361e34..7fb1016 100644 --- a/src/js/expansionPanelExpanded.directive.js +++ b/src/js/expansionPanelExpanded.directive.js @@ -40,15 +40,17 @@ function expansionPanelExpandedDirective($animateCss) { - function hide() { + function hide(options) { var height = setHeight ? setHeight : element[0].scrollHeight + 'px'; element.addClass('md-hide md-overflow'); element.removeClass('md-show md-scroll-y'); - $animateCss(element, { + var animationParams = { from: {'max-height': height, opacity: 1}, to: {'max-height': '48px', opacity: 0} - }) + }; + if (options.animation === false) { animationParams.duration = 0; } + $animateCss(element, animationParams) .start() .then(function () { element.css('display', 'none'); @@ -57,17 +59,18 @@ function expansionPanelExpandedDirective($animateCss) { } - function show() { + function show(options) { element.css('display', ''); element.addClass('md-show md-overflow'); - // use passed in height or the contents height var height = setHeight ? setHeight : element[0].scrollHeight + 'px'; - $animateCss(element, { + var animationParams = { from: {'max-height': '48px', opacity: 0}, to: {'max-height': height, opacity: 1} - }) + }; + if (options.animation === false) { animationParams.duration = 0; } + $animateCss(element, animationParams) .start() .then(function () { diff --git a/src/js/expansionPanelGroup.directive.js b/src/js/expansionPanelGroup.directive.js index 56f3acc..425ac92 100644 --- a/src/js/expansionPanelGroup.directive.js +++ b/src/js/expansionPanelGroup.directive.js @@ -95,13 +95,13 @@ function expansionPanelGroupDirective() { closeOthers(componentId); } - function remove(componentId, noAnimation) { - return panels[componentId].remove(noAnimation); + function remove(componentId, options) { + return panels[componentId].remove(options); } - function removeAll(noAnimation) { + function removeAll(options) { Object.keys(panels).forEach(function (panelId) { - panels[panelId].remove(noAnimation); + panels[panelId].remove(options); }); } diff --git a/src/js/expansionPanelGroup.service.js b/src/js/expansionPanelGroup.service.js index 4fe666a..6260612 100644 --- a/src/js/expansionPanelGroup.service.js +++ b/src/js/expansionPanelGroup.service.js @@ -19,8 +19,8 @@ angular * controller: 'Controller' * }); * instance.add('cardComponentId', {local: localData}); - * instance.remove('cardComponentId'); - * instance.removeAll(); + * instance.remove('cardComponentId', {animation: false}); + * instance.removeAll({animation: false}); * }); */ expansionPanelGroupService.$inject = ['$mdComponentRegistry', '$mdUtil', '$mdExpansionPanel', '$templateRequest', '$rootScope', '$compile', '$controller', '$q', '$log']; @@ -91,12 +91,12 @@ function expansionPanelGroupService($mdComponentRegistry, $mdUtil, $mdExpansionP instance.register(name, options); } - function remove(componentId) { - return instance.remove(componentId); + function remove(componentId, options) { + return instance.remove(componentId, options); } - function removeAll(noAnimation) { - instance.removeAll(noAnimation); + function removeAll(options) { + instance.removeAll(options); } function onChange(callback) { diff --git a/src/js/expansionPanelIcon.directive.js b/src/js/expansionPanelIcon.directive.js new file mode 100644 index 0000000..0600dbb --- /dev/null +++ b/src/js/expansionPanelIcon.directive.js @@ -0,0 +1,25 @@ +angular + .module('material.components.expansionPanels') + .directive('mdExpansionPanelIcon', mdExpansionPanelIconDirective); + + + +/** + * @ngdoc directive + * @name mdExpansionPanelIcon + * @module material.components.expansionPanels + * + * @restrict E + * + * @description + * `mdExpansionPanelIcon` can be used in both `md-expansion-panel-collapsed` and `md-expansion-panel-header` as the first or last element. + * Adding this will provide a animated arrow for expanded and collapsed states + **/ +function mdExpansionPanelIconDirective() { + var directive = { + restrict: 'E', + template: '', + replace: true + }; + return directive; +}