UNPKG

@microsoft/mgt

Version:
297 lines • 11 kB
/** * ------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. * See License in the project root for license information. * ------------------------------------------------------------------------------------------- */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { customElement, html, property } from 'lit-element'; import { Providers } from '../../Providers'; import { ProviderState } from '../../providers/IProvider'; import '../../styles/fabric-icon-font'; import { MgtBaseComponent } from '../baseComponent'; import '../mgt-person/mgt-person'; import { styles } from './mgt-login-css'; /** * Web component button and flyout control to facilitate Microsoft identity platform authentication * * @export * @class MgtLogin * @extends {MgtBaseComponent} */ let MgtLogin = class MgtLogin extends MgtBaseComponent { constructor() { super(); this._openLeft = false; /** * determines if login menu popup should be showing * @type {boolean} */ this._showMenu = false; /** * determines if login component is in loading state * @type {boolean} */ this._loading = true; Providers.onProviderUpdated(() => this.loadState()); this.loadState(); this.handleWindowClick = this.handleWindowClick.bind(this); } /** * Array of styles to apply to the element. The styles should be defined * using the `css` tag function. */ static get styles() { return styles; } /** * Invoked each time the custom element is appended into a document-connected element * * @memberof MgtLogin */ connectedCallback() { super.connectedCallback(); window.addEventListener('click', this.handleWindowClick); } /** * Invoked each time the custom element is disconnected from the document's DOM * * @memberof MgtLogin */ disconnectedCallback() { window.removeEventListener('click', this.handleWindowClick); super.disconnectedCallback(); } /** * Initiate login * * @returns {Promise<void>} * @memberof MgtLogin */ login() { return __awaiter(this, void 0, void 0, function* () { if (this.userDetails) { return; } const provider = Providers.globalProvider; if (provider && provider.login) { yield provider.login(); if (provider.state === ProviderState.SignedIn) { this.fireCustomEvent('loginCompleted'); } else { this.fireCustomEvent('loginFailed'); } yield this.loadState(); } }); } /** * * Initiate logout * @returns {Promise<void>} * @memberof MgtLogin */ logout() { return __awaiter(this, void 0, void 0, function* () { if (!this.fireCustomEvent('logoutInitiated')) { return; } const provider = Providers.globalProvider; if (provider && provider.logout) { yield provider.logout(); this.userDetails = null; this._showMenu = false; this.fireCustomEvent('logoutCompleted'); } }); } /** * Invoked whenever the element is updated. Implement to perform * post-updating tasks via DOM APIs, for example, focusing an element. * * Setting properties inside this method will trigger the element to update * again after this update cycle completes. * * * @param _changedProperties Map of changed properties with old values */ updated(changedProps) { if (changedProps.get('_showMenu') === false) { // get popup bounds const popup = this.renderRoot.querySelector('.popup'); if (popup && popup.animate) { this._popupRect = popup.getBoundingClientRect(); // invert variables const deltaX = this._loginButtonRect.left - this._popupRect.left; const deltaY = this._loginButtonRect.top - this._popupRect.top; const deltaW = this._loginButtonRect.width / this._popupRect.width; const deltaH = this._loginButtonRect.height / this._popupRect.height; // play back popup.animate([ { backgroundColor: '#eaeaea', transform: ` translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH}) `, transformOrigin: 'top left' }, { backgroundColor: 'white', transform: 'none', transformOrigin: 'top left' } ], { duration: 100, easing: 'ease-in-out', fill: 'both' }); } } } /** * Invoked on each update to perform rendering tasks. This method must return * a lit-html TemplateResult. Setting properties inside this method will *not* * trigger the element to update. */ render() { const content = this.userDetails ? this.renderLoggedIn() : this.renderLogIn(); return html ` <div class="root"> <button ?disabled="${this._loading}" class="login-button" @click=${this.onClick} role="button"> ${content} </button> ${this.renderMenu()} </div> `; } handleWindowClick(e) { if (e.target === this) { return; } // get popup bounds const popup = this.renderRoot.querySelector('.popup'); if (popup) { this._popupRect = popup.getBoundingClientRect(); this._showMenu = false; } } renderLogIn() { return html ` <i class="login-icon ms-Icon ms-Icon--Contact"></i> <span aria-label="Sign In"> Sign In </span> `; } renderLoggedIn() { if (this.userDetails) { return html ` <mgt-person .personDetails=${this.userDetails} .personImage=${this._image} show-name /> `; } else { return this.renderLogIn(); } } renderMenu() { if (!this.userDetails) { return; } const personComponent = html ` <mgt-person .personDetails=${this.userDetails} .personImage=${this._image} show-name show-email /> `; return html ` <div class="popup ${this._openLeft ? 'open-left' : ''} ${this._showMenu ? 'show-menu' : ''}"> <div class="popup-content"> <div> ${personComponent} </div> <div class="popup-commands"> <ul> <li> <button class="popup-command" @click=${this.logout} aria-label="Sign Out"> Sign Out </button> </li> </ul> </div> </div> </div> `; } loadState() { return __awaiter(this, void 0, void 0, function* () { const provider = Providers.globalProvider; if (provider) { this._loading = true; if (provider.state === ProviderState.SignedIn) { const batch = provider.graph.createBatch(); batch.get('me', 'me', ['user.read']); batch.get('photo', 'me/photo/$value', ['user.read']); const response = yield batch.execute(); this._image = response.photo; this.userDetails = response.me; } else if (provider.state === ProviderState.SignedOut) { this.userDetails = null; } else { // Loading this._showMenu = false; return; } } this._loading = false; }); } onClick(event) { if (this.userDetails) { // get login button bounds const loginButton = this.renderRoot.querySelector('.login-button'); if (loginButton) { this._loginButtonRect = loginButton.getBoundingClientRect(); const leftEdge = this._loginButtonRect.left; const rightEdge = (window.innerWidth || document.documentElement.clientWidth) - this._loginButtonRect.right; this._openLeft = rightEdge < leftEdge; this._showMenu = !this._showMenu; } } else { if (this.fireCustomEvent('loginInitiated')) { this.login(); } } } }; __decorate([ property({ attribute: 'user-details', type: Object }) ], MgtLogin.prototype, "userDetails", void 0); __decorate([ property({ attribute: false }) ], MgtLogin.prototype, "_showMenu", void 0); __decorate([ property({ attribute: false }) ], MgtLogin.prototype, "_loading", void 0); MgtLogin = __decorate([ customElement('mgt-login') ], MgtLogin); export { MgtLogin }; //# sourceMappingURL=mgt-login.js.map