@microsoft/mgt
Version:
The Microsoft Graph Toolkit
167 lines • 6.92 kB
JavaScript
/**
* -------------------------------------------------------------------------------------------
* 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;
};
import { customElement, html, LitElement, property } from 'lit-element';
import { classMap } from 'lit-html/directives/class-map';
import { styles } from './mgt-flyout-css';
/**
* A component to create flyout anchored to an element
*
* @export
* @class MgtFlyout
* @extends {LitElement}
*/
let MgtFlyout = class MgtFlyout extends LitElement {
constructor() {
super(...arguments);
/**
* Gets or sets whether the flyout is visible
*
* @type {string}
* @memberof MgtComponent
*/
this.isOpen = false;
this.renderedOnce = false;
}
/**
* Array of styles to apply to the element. The styles should be defined
* using the `css` tag function.
*/
static get styles() {
return styles;
}
/**
* Invoked when the element is first updated. Implement to perform one time
* work on the element after update.
*
* 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
*/
firstUpdated() {
this.addEventListener('updated', e => {
this.updateFlyout();
});
}
/**
* 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) {
super.updated(changedProps);
this.updateFlyout();
}
/**
* 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() {
return html `
<div class="root">
<div class="anchor">
<slot></slot>
</div>
${this.renderFlyout()}
</div>
`;
}
renderFlyout() {
if (!this.isOpen && !this.renderedOnce) {
return;
}
this.renderedOnce = true;
const classes = {
flyout: true,
visible: this.isOpen
};
return html `
<div class=${classMap(classes)}>
<slot name="flyout"></slot>
</div>
`;
}
updateFlyout() {
const anchor = this.renderRoot.querySelector('.anchor');
const flyout = this.renderRoot.querySelector('.flyout');
if (flyout && anchor) {
let left;
let bottom;
let top;
if (this.isOpen) {
const flyoutRect = flyout.getBoundingClientRect();
const anchorRect = anchor.getBoundingClientRect();
// normalize flyoutrect since we could have moved it before
// need to know where would it render, not where it renders
const flyoutTop = anchorRect.bottom;
const flyoutLeft = anchorRect.left;
const flyoutRight = flyoutLeft + flyoutRect.width;
const flyoutBottom = flyoutTop + flyoutRect.height;
const windowWidth = window.innerWidth && document.documentElement.clientWidth
? Math.min(window.innerWidth, document.documentElement.clientWidth)
: window.innerWidth || document.documentElement.clientWidth;
const windowHeight = window.innerHeight && document.documentElement.clientHeight
? Math.min(window.innerHeight, document.documentElement.clientHeight)
: window.innerHeight || document.documentElement.clientHeight;
if (flyoutRect.width > windowWidth) {
// page width is smaller than flyout, render all the way to the left
left = -flyoutLeft;
}
else if (anchorRect.width >= flyoutRect.width) {
// anchor is large than flyout, render aligned to anchor
left = 0;
}
else {
const centerOffset = flyoutRect.width / 2 - anchorRect.width / 2;
if (flyoutLeft - centerOffset < 0) {
// centered flyout is off screen to the left, render on the left edge
left = -flyoutLeft;
}
else if (flyoutRight - centerOffset > windowWidth) {
// centered flyout is off screen to the right, render on the right edge
left = -(flyoutRight - windowWidth);
}
else {
// render centered
left = -centerOffset;
}
}
if (flyoutRect.height > windowHeight || (windowHeight < flyoutBottom && anchorRect.top < flyoutRect.height)) {
top = -flyoutTop + anchorRect.height;
}
else if (windowHeight < flyoutBottom) {
bottom = anchorRect.height;
}
}
flyout.style.left = typeof left !== 'undefined' ? `${left}px` : '';
flyout.style.bottom = typeof bottom !== 'undefined' ? `${bottom}px` : '';
flyout.style.top = typeof top !== 'undefined' ? `${top}px` : '';
}
}
};
__decorate([
property({
attribute: 'isOpen',
type: Boolean
})
], MgtFlyout.prototype, "isOpen", void 0);
MgtFlyout = __decorate([
customElement('mgt-flyout')
], MgtFlyout);
export { MgtFlyout };
//# sourceMappingURL=mgt-flyout.js.map