Skip to content

Commit 3781711

Browse files
committed
working flyout
1 parent 2de2181 commit 3781711

File tree

4 files changed

+129
-74
lines changed

4 files changed

+129
-74
lines changed

index.html

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,19 @@
3333
<!-- <mgt-mock-provider></mgt-mock-provider> -->
3434

3535
<mgt-login></mgt-login>
36-
<!-- <mgt-person person-query="me" show-name show-email person-card="click"></mgt-person>
37-
<mgt-tasks></mgt-tasks> -->
36+
<mgt-person person-query="me" person-card="click"></mgt-person>
37+
<mgt-agenda></mgt-agenda>
3838

3939
<mgt-flyout>
4040
<div>hello</div>
4141
<div slot="flyout">you</div>
4242
</mgt-flyout>
43+
44+
<script>
45+
let flyout = document.querySelector('mgt-flyout');
46+
flyout.addEventListener('click', () => {
47+
flyout.isOpen = !flyout.isOpen;
48+
});
49+
</script>
4350
</body>
4451
</html>

src/components/mgt-person/mgt-person.scss

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,24 @@ mgt-person .user-email {
137137
-ms-grid-row: 2;
138138
}
139139

140-
.root .flyout {
141-
display: none;
142-
position: absolute;
143-
z-index: 1;
144-
opacity: 0;
145-
transition-property: opacity;
146-
transition-duration: 0.1s;
140+
.flyout {
147141
padding: 8px;
148142
}
149143

150-
.root .flyout.visible {
151-
display: inline-block;
152-
opacity: 1;
153-
&.openLeft {
154-
right: 0;
155-
}
156-
}
144+
// .root .flyout {
145+
// display: none;
146+
// position: absolute;
147+
// z-index: 1;
148+
// opacity: 0;
149+
// transition-property: opacity;
150+
// transition-duration: 0.1s;
151+
// padding: 8px;
152+
// }
153+
154+
// .root .flyout.visible {
155+
// display: inline-block;
156+
// opacity: 1;
157+
// &.openLeft {
158+
// right: 0;
159+
// }
160+
// }

src/components/mgt-person/mgt-person.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
*/
77

88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
9-
import { customElement, html, property, PropertyValues } from 'lit-element';
9+
import { customElement, html, property, PropertyValues, TemplateResult } from 'lit-element';
1010
import { classMap } from 'lit-html/directives/class-map';
1111
import { styleMap } from 'lit-html/directives/style-map';
1212
import { Providers } from '../../Providers';
1313
import { ProviderState } from '../../providers/IProvider';
1414
import '../../styles/fabric-icon-font';
1515
import { getEmailFromGraphEntity } from '../../utils/GraphHelpers';
1616
import { MgtPersonCard } from '../mgt-person-card/mgt-person-card';
17+
import '../sub-components/mgt-flyout/mgt-flyout';
1718
import { MgtTemplatedComponent } from '../templatedComponent';
1819
import { PersonCardInteraction } from './../PersonCardInteraction';
1920
import { styles } from './mgt-person-css';
@@ -170,16 +171,40 @@ export class MgtPerson extends MgtTemplatedComponent {
170171
</div>
171172
`;
172173

174+
const image = this.getImage();
175+
173176
return html`
174177
<div
175178
class="root"
176179
@mouseenter=${this._handleMouseEnter}
177180
@mouseleave=${this._handleMouseLeave}
178181
@click=${this._handleMouseClick}
179182
>
180-
${person} ${this.renderPersonCard()}
183+
${this.renderFlyout(person)}
181184
</div>
182185
`;
186+
187+
// ${person} ${this.renderPersonCard()}
188+
}
189+
190+
public renderFlyout(anchor: TemplateResult) {
191+
if (this.personCardInteraction === PersonCardInteraction.none) {
192+
return anchor;
193+
}
194+
195+
const image = this.getImage();
196+
197+
return html`
198+
<mgt-flyout .isOpen=${this._isPersonCardVisible}>
199+
${anchor}
200+
<div slot="flyout" class="flyout">
201+
${this.renderTemplate('person-card', { person: this.personDetails, personImage: image }) ||
202+
html`
203+
<mgt-person-card .personDetails=${this.personDetails} .personImage=${image}> </mgt-person-card>
204+
`}
205+
</div>
206+
</mgt-flyout>
207+
`;
183208
}
184209

185210
/**
@@ -319,7 +344,8 @@ export class MgtPerson extends MgtTemplatedComponent {
319344

320345
private _hidePersonCard() {
321346
this._isPersonCardVisible = false;
322-
const personCard = this.querySelector('mgt-person-card') as MgtPersonCard;
347+
const personCard = (this.querySelector('mgt-person-card') ||
348+
this.renderRoot.querySelector('mgt-person-card')) as MgtPersonCard;
323349
if (personCard) {
324350
personCard.isExpanded = false;
325351
}

src/components/sub-components/mgt-flyout/mgt-flyout.ts

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { css, customElement, html, LitElement, property } from 'lit-element';
2-
import { PersonCardInteraction } from '../../PersonCardInteraction';
3-
1+
import { css, customElement, html, LitElement, property, PropertyValues } from 'lit-element';
2+
import { classMap } from 'lit-html/directives/class-map';
3+
import { styles } from './mgt-flyout-css';
44
/**
55
*
66
*
@@ -15,42 +15,23 @@ export class MgtFlyout extends LitElement {
1515
* using the `css` tag function.
1616
*/
1717
static get styles() {
18-
return css`
19-
.title {
20-
color: red;
21-
}
22-
`;
18+
return styles;
2319
}
2420

25-
// TODO: create new type
26-
@property({
27-
attribute: 'person-card',
28-
converter: (value, type) => {
29-
value = value.toLowerCase();
30-
if (typeof PersonCardInteraction[value] === 'undefined') {
31-
return PersonCardInteraction.none;
32-
} else {
33-
return PersonCardInteraction[value];
34-
}
35-
}
36-
})
37-
public personCardInteraction: PersonCardInteraction = PersonCardInteraction.hover;
38-
3921
/**
4022
*
4123
*
4224
* @type {string}
4325
* @memberof MgtComponent
4426
*/
4527
@property({
46-
attribute: 'my-title',
47-
type: String
28+
attribute: 'isOpen',
29+
type: Boolean
4830
})
49-
public myTitle: string = 'My First Component';
50-
private _mouseLeaveTimeout;
51-
private _mouseEnterTimeout;
52-
private _openLeft: boolean = false;
53-
private _openUp: boolean = false;
31+
public isOpen: boolean = false;
32+
33+
private renderedOnce = false;
34+
5435
@property({ attribute: false }) private _isPersonCardVisible: boolean = false;
5536
@property({ attribute: false }) private _personCardShouldRender: boolean = false;
5637

@@ -84,47 +65,84 @@ export class MgtFlyout extends LitElement {
8465
*/
8566
public firstUpdated() {}
8667

68+
/**
69+
* Invoked whenever the element is updated. Implement to perform
70+
* post-updating tasks via DOM APIs, for example, focusing an element.
71+
*
72+
* Setting properties inside this method will trigger the element to update
73+
* again after this update cycle completes.
74+
*
75+
* * @param changedProperties Map of changed properties with old values
76+
*/
77+
protected updated(changedProps: PropertyValues) {
78+
super.updated(changedProps);
79+
80+
const anchor = this.renderRoot.querySelector('.anchor');
81+
const flyout = this.renderRoot.querySelector('.flyout') as HTMLElement;
82+
if (flyout && anchor) {
83+
const flyoutRect = flyout.getBoundingClientRect();
84+
const anchorRect = anchor.getBoundingClientRect();
85+
86+
const windowWidth = window.innerWidth || document.documentElement.clientWidth;
87+
const windowHeight = window.innerHeight || document.documentElement.clientHeight;
88+
89+
let left: number;
90+
let right: number;
91+
let top: number;
92+
let bottom: number;
93+
94+
if (anchorRect.width >= flyoutRect.width) {
95+
left = 0;
96+
} else {
97+
const centerOffset = flyoutRect.width / 2 - anchorRect.width / 2;
98+
99+
if (anchorRect.left - centerOffset < 0) {
100+
left = -anchorRect.left;
101+
} else {
102+
left = -centerOffset;
103+
} // todo check if offscreen to the right and move left
104+
}
105+
106+
flyout.style.left = left ? `${left}px` : '';
107+
flyout.style.right = right ? `${right}px` : '';
108+
flyout.style.top = top ? `${top}px` : '';
109+
flyout.style.bottom = bottom ? `${bottom}px` : '';
110+
}
111+
}
112+
87113
/**
88114
* Invoked on each update to perform rendering tasks. This method must return
89115
* a lit-html TemplateResult. Setting properties inside this method will *not*
90116
* trigger the element to update.
91117
*/
92118
protected render() {
93119
return html`
94-
<div
95-
class="root"
96-
@mouseenter=${this._handleMouseEnter}
97-
@mouseleave=${this._handleMouseLeave}
98-
@click=${this._handleMouseClick}
99-
>
100-
<slot></slot>
101-
<slot name="flyout"></slot>
120+
<div class="root">
121+
<div class="anchor">
122+
<slot></slot>
123+
</div>
124+
${this.renderFlyout()}
102125
</div>
103126
`;
104127
}
105128

106-
private _handleMouseClick() {
107-
if (this.personCardInteraction === PersonCardInteraction.click && !this._isPersonCardVisible) {
108-
this._showPersonCard();
109-
} else {
110-
this._hidePersonCard();
111-
}
112-
}
113-
114-
private _handleMouseEnter(e: MouseEvent) {
115-
if (this.personCardInteraction !== PersonCardInteraction.hover) {
129+
private renderFlyout() {
130+
if (!this.isOpen && !this.renderedOnce) {
116131
return;
117132
}
118133

119-
clearTimeout(this._mouseEnterTimeout);
120-
clearTimeout(this._mouseLeaveTimeout);
121-
this._mouseEnterTimeout = setTimeout(this._showPersonCard.bind(this), 500);
122-
}
134+
this.renderedOnce = true;
135+
136+
const classes = {
137+
flyout: true,
138+
visible: this.isOpen
139+
};
123140

124-
private _handleMouseLeave(e: MouseEvent) {
125-
clearTimeout(this._mouseEnterTimeout);
126-
clearTimeout(this._mouseLeaveTimeout);
127-
this._mouseLeaveTimeout = setTimeout(this._hidePersonCard.bind(this), 500);
141+
return html`
142+
<div class=${classMap(classes)}>
143+
<slot name="flyout"></slot>
144+
</div>
145+
`;
128146
}
129147

130148
private _showPersonCard() {

0 commit comments

Comments
 (0)