From 2a86270e5a140349f677cd716ab756bdada9ee15 Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Wed, 13 Jul 2016 14:17:17 -0700 Subject: [PATCH] feat(menu): add md-menu standalone component --- package.json | 3 +- scripts/release/enact-release.sh | 15 +- scripts/release/stage-release.sh | 44 +++++- src/components/button/_button-base.scss | 9 +- src/components/button/package.json | 4 +- src/components/card/package.json | 4 +- src/components/checkbox/package.json | 4 +- src/components/grid-list/package.json | 4 +- src/components/icon/package.json | 4 +- src/components/input/package.json | 4 +- src/components/list/package.json | 4 +- src/components/menu/menu.html | 4 + src/components/menu/menu.scss | 47 ++++++ src/components/menu/menu.ts | 14 +- src/components/menu/package.json | 4 +- src/components/progress-bar/package.json | 4 +- src/components/progress-circle/package.json | 4 +- src/components/radio/package.json | 4 +- src/components/sidenav/package.json | 4 +- src/components/slide-toggle/package.json | 4 +- src/components/tabs/package.json | 4 +- src/components/toolbar/package.json | 4 +- src/core/package.json | 2 +- src/core/style/_mixins.scss | 12 ++ src/demo-app/menu/menu-demo.html | 6 +- src/demo-app/menu/test.ts | 164 ++++++++++++++++++++ src/demo-app/tsconfig.json | 1 + 27 files changed, 332 insertions(+), 49 deletions(-) create mode 100644 src/demo-app/menu/test.ts diff --git a/package.json b/package.json index c95e6de949d9..7ba2e64cfbf1 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "deploy": "firebase deploy", "webdriver-manager": "webdriver-manager" }, - "version": "2.0.0-alpha.6", + "version": "2.0.0-alpha.6-2", "license": "MIT", "engines": { "node": ">= 4.2.1 < 5" @@ -43,6 +43,7 @@ "zone.js": "0.6.12" }, "devDependencies": { + "@angular/compiler-cli": "^0.4.1", "add-stream": "^1.0.0", "angular-cli": "^1.0.0-beta.9", "broccoli-autoprefixer": "^4.1.0", diff --git a/scripts/release/enact-release.sh b/scripts/release/enact-release.sh index 7a2a279d63a2..f4dbbc2b25b7 100755 --- a/scripts/release/enact-release.sh +++ b/scripts/release/enact-release.sh @@ -1,5 +1,10 @@ #!/usr/bin/env bash +# Run this script after running `stage-release.sh` to publish the packages staged to deploy/ +# Optionally uses the first argument as the tag for the release (such as "next"). +# This script should be run from the root of the material2 repo. + + # `npm whoami` errors and dies if you're not logged in, # so we redirect the stderr output to /dev/null since we don't care. NPM_USER=$(npm whoami 2> /dev/null) @@ -9,11 +14,15 @@ if [ "${NPM_USER}" != "angular2-material" ]; then exit fi +NPM_TAG="latest" +if [ "$1" ] ; then + NPM_TAG=${1} +fi + set -ex -for package in ./deploy/* -do - npm publish --access public ${package} +for package in ./deploy/* ; do + npm publish --access public ${package} --tag ${NPM_TAG} done # Always log out of npm when publish is complete. diff --git a/scripts/release/stage-release.sh b/scripts/release/stage-release.sh index a82e065926eb..8f260ba3eedf 100755 --- a/scripts/release/stage-release.sh +++ b/scripts/release/stage-release.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -exu +set -xu # Stages a release by putting everything that should be packaged and released # into the ./deploy folder. This script should be run from the root of the @@ -12,14 +12,45 @@ set -exu rm -rf ./dist rm -rf ./deploy -# Perform a build with the modified tsconfig.json. +# deploy/ serves as a working directory to stage the release. +mkdir deploy + +# Start off by building normally. +ng build + +# We need to remove moduleId for the ngc build. We do this by simply commenting out with a +# distinguishing marker and then undoing those lines after we've generated the .metadata.json files. +grep -lr "moduleId:" ./src/ | xargs sed -i 's|moduleId:|//MODULE moduleId:|g' + +# Run tsc directly first so that the output directories match what ngc is expecting. This is +# different from what the CLI will output for *demo-app*, but we don't care about the output for +# demo-app when we're staging a release (only components/ and core/). +tsc -p ./src/demo-app + +# Now run ngc to generate the .metadata.json files. Our tsconfig is configred with +# skipTemplateCodegen, so only the metadata files are actually generated. +./node_modules/.bin/ngc -p ./src/demo-app + +# Restore the moduleIds. +grep -lr "//MODULE " ./src/ | xargs sed -i 's|//MODULE ||g' + +# At this point, we have all of our .metadata.json files, which is all we care about from ngc. +# Temporarily copy them over to deploy/ so we can cut a clean build. +# Use rsync since we want to preserve the directory structure and `cp --parents` won't work on OSX. +find ./dist/{components,core} -iname "*.metadata.json" | xargs -i rsync -Rq {} ./deploy/ + +# Wipe away dist and perform a clean build. +rm -rf ./dist ng build # Inline the css and html into the component ts files. npm run inline-resources -# deploy/ serves as a working directory to stage the release. -mkdir deploy +# Move the .metadata.json files back to where we want them. +(cd ./deploy ; find ./ -iname "*.metadata.json" | xargs -i rsync -Rq {} ../) + +# Clear the deploy/ directory again now that we've pulled the metadata out of it. +rm -rf ./deploy/* # Copy all components/ to deploy/ cp -R ./dist/components/* ./deploy/ @@ -27,4 +58,9 @@ cp -R ./dist/components/* ./deploy/ # Copy the core/ directory directly into ./deploy cp -R ./dist/core/ ./deploy/core/ +# Remove test files from deploy/ +find ./deploy -iname "*.spec.d.ts" | xargs rm +find ./deploy -iname "*.spec.js" | xargs rm +find ./deploy -iname "*.spec.js.map" | xargs rm + # To test the packages, simply `npm install` the package directories. diff --git a/src/components/button/_button-base.scss b/src/components/button/_button-base.scss index 1856ec13010c..d7e08889d405 100644 --- a/src/components/button/_button-base.scss +++ b/src/components/button/_button-base.scss @@ -1,6 +1,7 @@ @import 'variables'; @import 'elevation'; +@import 'mixins'; // TODO(jelbourn): This goes away. @import 'default-theme'; @@ -34,12 +35,7 @@ $md-mini-fab-padding: 8px !default; position: relative; // Reset browser + + + \ No newline at end of file diff --git a/src/demo-app/menu/test.ts b/src/demo-app/menu/test.ts new file mode 100644 index 000000000000..d91d295856cb --- /dev/null +++ b/src/demo-app/menu/test.ts @@ -0,0 +1,164 @@ +import {Component, Directive, ViewChild,AfterViewInit, QueryList, ViewChildren, Input, Output, HostBinding, EventEmitter, OnInit, TemplateRef, ViewContainerRef, ViewEncapsulation, HostListener, Injectable, ElementRef} from '@angular/core'; +import { + Overlay, + OverlayState, + OverlayOrigin, + OVERLAY_PROVIDERS, + OVERLAY_DIRECTIVES, + ComponentPortal, + PORTAL_DIRECTIVES, + OverlayRef, + TemplatePortal +} from '@angular2-material/core/core'; +import {ConnectedOverlayDirective} from '@angular2-material/core/overlay/overlay-directives'; +import {MD_BUTTON_DIRECTIVES} from '@angular2-material/button/button'; +import {MD_ICON_DIRECTIVES, MdIconRegistry} from '@angular2-material/icon/icon'; +import {MD_TOOLBAR_DIRECTIVES} from '@angular2-material/toolbar/toolbar'; + +@Directive({ + selector: '[md-menu-trigger]', + providers: [OVERLAY_PROVIDERS], + exportAs: 'menuTrigger' +}) +export class MdMenuTrigger implements AfterViewInit { + _templatePortal: TemplatePortal; + _overlayRef: OverlayRef; + menuOpen: boolean = false; + + @Input('md-menu-trigger') menu: MdMenu; + + constructor(private _overlay: Overlay, private _viewContainerRef: ViewContainerRef, + private _element: ElementRef) { + } + + ngAfterViewInit() { + this._createOverlay(); + this.menu.closeEvent.subscribe(() => { + this.close(); + }); + } + + _createOverlay() { + this._templatePortal = new TemplatePortal(this.menu.templateRef, this._viewContainerRef); + let overlayConfig = new OverlayState(); + let orientation: 'start' | 'end'; + console.log(this.menu.position) + orientation = this.menu.position === 'before' ? 'end' : 'start'; + overlayConfig.positionStrategy = + this._overlay.position().connectedTo( + this._element, + {originX: orientation, originY: 'top'}, + {overlayX: orientation, overlayY: 'top'}); + + this._overlay.create(overlayConfig).then(ref => { + this._overlayRef = ref; + }); + } + + @HostListener('click') + toggle() { + this.menuOpen ? this.close() : this.open(); + } + + open() { + this._overlayRef.attach(this._templatePortal); + this.menu.setMenuState(true); + this.menuOpen = true; + } + + close() { + this._overlayRef.detach(); + this.menu.setMenuState(false); + this.menuOpen = false; + + } +} + +@Component({ + selector: 'md-menu', + template: ` + +
+ `, + styles: [` + .md-menu-backdrop { + top: 0; + bottom: 0; + left: 0; + right: 0; + position: fixed; + } + + .md-menu { + box-shadow: 0px 3px 1px -2px rgba(0,0,0,0.2), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12); + background: white; + } + + [md-menu-item] { + display: block; + min-width: 112px; + height: 48px; + font-size: 16px; + background: none; + border: none; + background: white; + cursor: pointer; + } + + [md-menu-item]:hover:not([disabled]) { + background: rgba(0,0,0,0.04); + } + + + `], + exportAs: 'mdMenu', + encapsulation: ViewEncapsulation.None +}) +export class MdMenu { + @HostBinding('class.menu-open') _menuOpen = false; + @Input('position') position: string; + closeEvent = new EventEmitter(); + + @ViewChild(TemplateRef) private _templateRef: TemplateRef; + + get templateRef() { return this._templateRef }; + + emitCloseEvent() { + this.closeEvent.emit(null); + } + + setMenuState(bool: boolean): void { + this._menuOpen = bool; + } +} + +@Component({ + moduleId: module.id, + selector: 'menu-demo', + templateUrl: 'menu-demo.html', + styleUrls: ['menu-demo.css'], + directives: [OVERLAY_DIRECTIVES, MdMenu, MdMenuTrigger, MD_BUTTON_DIRECTIVES, MD_ICON_DIRECTIVES, MD_TOOLBAR_DIRECTIVES], + providers: [OVERLAY_PROVIDERS, MdIconRegistry], + encapsulation: ViewEncapsulation.None +}) +export class MenuDemo { + selected: string = '--'; + selectedLast: string = '--'; + select(item: string) { + this.selected = item; + } + + selectLast(item:string) { + this.selectedLast = item; + } + + @ViewChildren(MdMenuTrigger) triggers: QueryList; + + openMenu(menu: string) { + (menu === 'last') ? this.triggers.last.open() : this.triggers.first.open(); + } +} diff --git a/src/demo-app/tsconfig.json b/src/demo-app/tsconfig.json index 7259b770083b..e7f03b00d9c9 100644 --- a/src/demo-app/tsconfig.json +++ b/src/demo-app/tsconfig.json @@ -28,6 +28,7 @@ }, "angularCompilerOptions": { "genDir": "../../dist", + "skipTemplateCodegen": true, "debug": true }, "files": [