Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,11 @@ export interface ICalloutProps extends React.Props<Callout | CalloutContent> {
* Set max height of callout
* When not set the callout will expand with contents up to the bottom of the screen
*/
targetElement?: HTMLElement;

/**
* Classnames for the parent element
*/
parentClassName?: string;
calloutMaxHeight?: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export class CalloutContent extends BaseComponent<ICalloutProps, ICalloutState>
beakStyle,
children,
beakWidth,
parentClassName,
calloutWidth,
finalHeight,
backgroundColor,
Expand Down Expand Up @@ -149,10 +150,7 @@ export class CalloutContent extends BaseComponent<ICalloutProps, ICalloutState>
let beakVisible = isBeakVisible && (!!target);

let content = (
<div
ref={ this._resolveRef('_hostElement') }
className={ css('ms-Callout-container', styles.container) }
>
<div ref={ this._resolveRef('_hostElement') } className={ css('ms-Callout-container', styles.container, parentClassName) }>
<div
className={
mergeStyles(
Expand Down Expand Up @@ -211,6 +209,7 @@ export class CalloutContent extends BaseComponent<ICalloutProps, ICalloutState>
if (this.state.positions && !preventDismissOnScroll) {
this._dismissOnLostFocus(ev);
}
this._updatePosition();
}

protected _dismissOnLostFocus(ev: Event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,9 @@ export interface ITeachingBubbleProps extends React.Props<TeachingBubble | Teach
* Callback when the TeachingBubble tries to close.
*/
onDismiss?: (ev?: any) => void;

/**
* Variant for the coachMark
*/
isCoachmark?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,178 @@
border-color: $ms-color-white;
}
}

/*
TEACHING BUBBLE
*/
$coachmarkCircleRadius: 50%;
@mixin coachmarkPopWiggleSettings {
animation-duration: 2.55s;
animation-timing-function: linear;
animation-direction: normal;
animation-iteration-count: infinite;
animation-delay: 0s;
}

@mixin coachMarkAnimateOutTransition {
transition: border-radius 250ms, width 500ms, height 500ms cubic-bezier(0.5, 0, 0, 1);
}

.coachmarkIsWiggling {
@include coachmarkPopWiggleSettings();
animation-name: pop;
cursor: pointer;

:global(.ms-Callout) {
@include coachmarkPopWiggleSettings();
animation-name: wiggle;
}
}

.coachmarkCalloutContainer .bodyContent,
.coachmarkCalloutContainer .content {
overflow: hidden;
}

.coachmarkCalloutContainer {
:global(.ms-Callout),
.content {
width: 50px;
height: 50px;
border-radius: $coachmarkCircleRadius;
position: relative;
@include coachMarkAnimateOutTransition();

:global(.ms-Callout-beak) {
left: -4px !important;
box-shadow: 0;
}
}
}

.coachmarkCalloutContainer :global(.ms-Callout) {
:global(.ms-Callout-beakCurtain) {
background-color: $ms-color-themePrimary;
border-radius: $coachmarkCircleRadius;
@include coachMarkAnimateOutTransition();
}

:global(.ms-Callout-main) {
border-radius: $coachmarkCircleRadius;
@include coachMarkAnimateOutTransition();
}
}

.coachmarkCalloutContainer .bodyContent {
transition: transform 500ms cubic-bezier(0.5, 0, 0, 1);
transform: scale(0);
transform-origin: top left;
}

.icon {
color: $ms-color-white;
font-size: 24px;
width: 24px;
height: 24px;
margin-top: 13px;
margin-left: 13px;
transition: opacity 100ms, transform 100ms cubic-bezier(0.33, 0, 0.66, 1);
}

.coachmarkIsAnimating .icon {
opacity: 0.8;
transform: scale(0);
display: none;
}

.coachmarkIsAnimating {
:global(.ms-Callout),
.content {
border-radius: 1px;
width: 362px;
height: 116px;

:global(.ms-Callout-beakCurtain) {
border-radius: 0;
}

:global(.ms-Callout-main) {
border-radius: 0;
}
}
}

.coachmarkIsAnimating .bodyContent {
display: block;
transform: scale(1);
}

.coachmarkIsAnimating .content {
border-radius: 0;
width: 362px;
height: 116px;
}

@keyframes pop {
0% {
transform: translate(102.31px, 103.31px);
animation-timing-function: linear;
}
17.65% {
transform: translate(102.31px, 103.31px);
animation-timing-function: cubic-bezier(0.62, 0, 0.56, 1);
}
40.52% {
transform: translate(102.31px, 100.81px);
animation-timing-function: cubic-bezier(0.58, 0, 0, 1);
}
55.56% {
transform: translate(102.31px, 114.31px);
animation-timing-function: cubic-bezier(1, 0, 0.56, 1);
}
73.2% {
transform: translate(102.31px, 100.81px);
animation-timing-function: cubic-bezier(0.58, 0, 0.67, 1);
}
84.31% {
transform: translate(102.31px, 103.31px);
animation-timing-function: linear;
}
100% {
transform: translate(102.31px, 103.31px);
}
}

@keyframes wiggle {
0% {
transform: rotate(0deg);
animation-timing-function: linear;
}
47.06% {
transform: rotate(0deg);
animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1);
}
50.33% {
transform: rotate(5deg);
animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1);
}
53.59% {
transform: rotate(-5deg);
animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1);
}
56.86% {
transform: rotate(5deg);
animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1);
}
60.13% {
transform: rotate(-5deg);
animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1);
}
63.4% {
transform: rotate(0deg);
animation-timing-function: linear;
}
100% {
transform: rotate(0deg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const styles: any = stylesImport;

export interface ITeachingBubbleState {
isTeachingBubbleVisible?: boolean;
isCoachmarkAnimating?: boolean;
isCoachmarkWiggling?: boolean;
}

export class TeachingBubble extends BaseComponent<ITeachingBubbleProps, ITeachingBubbleState> {
Expand All @@ -26,26 +28,73 @@ export class TeachingBubble extends BaseComponent<ITeachingBubbleProps, ITeachin
}
};

private _currentHeight: number;
private _currentWidth: number;
private _coachmark: HTMLDivElement;

// Constructor
constructor(props: ITeachingBubbleProps) {
super(props);

this.state = {
isCoachmarkAnimating: false,
isCoachmarkWiggling: props.isCoachmark // If it's not a Coachmark then we dont want to start animating the TeachingBubble right away
};
}

public componentDidMount() {
const rect = this._coachmark.getBoundingClientRect();
const height = rect.height;
const width = rect.width;
}

public render() {
let { calloutProps, targetElement } = this.props;
let { calloutProps, targetElement, isCoachmark } = this.props;

const classes = css(
'ms-TeachingBubble',
styles.root,
{
['ms-TeachingBubble--coachmark']: isCoachmark!
}
);

return (
<Callout
className={ css('ms-TeachingBubble', styles.root) }
className={ classes }
ref={ this._resolveRef('_callout') }
target={ targetElement }
parentClassName={ css({
[styles.coachmarkCalloutContainer]: isCoachmark,
[styles.coachmarkIsWiggling]: this.state.isCoachmarkWiggling,
[styles.coachmarkIsAnimating]: this.state.isCoachmarkAnimating
}) }
{...calloutProps}
>
<TeachingBubbleContent { ...this.props } />
<div
className={ css({
[styles.animationLayer]: isCoachmark!,
['TeachingBubble-animationLayer']: isCoachmark!
}) }
onClick={ this._onClickHandler }
ref={ this._resolveRef('_coachmark') }
>
<TeachingBubbleContent { ...this.props } />
</div>
</Callout>
);
}

private _onClickHandler() {
this.setState({
isCoachmarkAnimating: true,
isCoachmarkWiggling: false
});
}

private _coachmarkOnClickHandler() {

// Set the height and width of the element

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ import { ITeachingBubbleProps } from './TeachingBubble.Props';
import { ITeachingBubbleState } from './TeachingBubble';
import { PrimaryButton, DefaultButton, IconButton } from '../../Button';
import { Image, ImageFit } from '../../Image';
import { Icon, IconName } from '../../Icon';
import * as stylesImport from './TeachingBubble.scss';
const styles: any = stylesImport;

export interface ITeachingBubbleClassNames {
base?: string;
variant?: string;
}

export class TeachingBubbleContent extends BaseComponent<ITeachingBubbleProps, ITeachingBubbleState> {

// Specify default props values
Expand All @@ -22,6 +28,10 @@ export class TeachingBubbleContent extends BaseComponent<ITeachingBubbleProps, I
imageFit: ImageFit.cover,
width: 364,
height: 130
},
classNames: {
base: 'ms-TeachingBubble',
variant: ''
}
};

Expand All @@ -38,13 +48,20 @@ export class TeachingBubbleContent extends BaseComponent<ITeachingBubbleProps, I
}

public render() {
let { illustrationImage, primaryButtonProps, secondaryButtonProps, headline, hasCondensedHeadline, hasCloseIcon, onDismiss, closeButtonAriaLabel } = this.props;
let { illustrationImage, primaryButtonProps, secondaryButtonProps, headline, hasCondensedHeadline, hasCloseIcon, onDismiss, closeButtonAriaLabel, isCoachmark } = this.props;

let imageContent;
let headerContent;
let bodyContent;
let footerContent;
let closeButton;
let coachMarkIcon;

if (isCoachmark) {
coachMarkIcon = (
<Icon className={ css('TeachingBubble-icon', styles.icon) } iconName={ 'Lightbulb' } />
);
}

if (illustrationImage && illustrationImage.src) {
imageContent = (
Expand Down Expand Up @@ -113,7 +130,8 @@ export class TeachingBubbleContent extends BaseComponent<ITeachingBubbleProps, I
}

return (
<div className={ css('ms-TeachingBubble-content') }>
<div className={ css('ms-TeachingBubble-content', styles.content) }>
{ coachMarkIcon }
{ imageContent }
{ closeButton }
<div className={ css('ms-TeachingBubble-bodycontent', styles.bodyContent) }>
Expand Down
Loading