diff --git a/packages/office-ui-fabric-react/src/components/Callout/Callout.Props.ts b/packages/office-ui-fabric-react/src/components/Callout/Callout.Props.ts index 4234e34676e148..f3eb2f09f5fcc4 100644 --- a/packages/office-ui-fabric-react/src/components/Callout/Callout.Props.ts +++ b/packages/office-ui-fabric-react/src/components/Callout/Callout.Props.ts @@ -182,5 +182,11 @@ export interface ICalloutProps extends React.Props { * 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; } diff --git a/packages/office-ui-fabric-react/src/components/Callout/CalloutContent.tsx b/packages/office-ui-fabric-react/src/components/Callout/CalloutContent.tsx index d36fab507d8772..4fe78390b4dc52 100644 --- a/packages/office-ui-fabric-react/src/components/Callout/CalloutContent.tsx +++ b/packages/office-ui-fabric-react/src/components/Callout/CalloutContent.tsx @@ -115,6 +115,7 @@ export class CalloutContent extends BaseComponent beakStyle, children, beakWidth, + parentClassName, calloutWidth, finalHeight, backgroundColor, @@ -149,10 +150,7 @@ export class CalloutContent extends BaseComponent let beakVisible = isBeakVisible && (!!target); let content = ( -
+
if (this.state.positions && !preventDismissOnScroll) { this._dismissOnLostFocus(ev); } + this._updatePosition(); } protected _dismissOnLostFocus(ev: Event) { diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/CoachmarkTeachingBubble/CoachmarkTeachingBubble.scss b/packages/office-ui-fabric-react/src/components/TeachingBubble/CoachmarkTeachingBubble/CoachmarkTeachingBubble.scss new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/CoachmarkTeachingBubble/CoachmarkTeachingBubble.tsx b/packages/office-ui-fabric-react/src/components/TeachingBubble/CoachmarkTeachingBubble/CoachmarkTeachingBubble.tsx new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.Props.ts b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.Props.ts index 4b89b02c031a3e..2911ba6a0bb077 100644 --- a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.Props.ts +++ b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.Props.ts @@ -65,4 +65,9 @@ export interface ITeachingBubbleProps extends React.Props void; + + /** + * Variant for the coachMark + */ + isCoachmark?: boolean; } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.scss b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.scss index 02aaea2427a953..c6bcefd1421f2a 100644 --- a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.scss +++ b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.scss @@ -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); + } +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.tsx b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.tsx index dac3e47553102c..fbd18ca5889999 100644 --- a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.tsx +++ b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubble.tsx @@ -11,6 +11,8 @@ const styles: any = stylesImport; export interface ITeachingBubbleState { isTeachingBubbleVisible?: boolean; + isCoachmarkAnimating?: boolean; + isCoachmarkWiggling?: boolean; } export class TeachingBubble extends BaseComponent { @@ -26,26 +28,73 @@ export class TeachingBubble extends BaseComponent - +
+ +
); } + + private _onClickHandler() { + this.setState({ + isCoachmarkAnimating: true, + isCoachmarkWiggling: false + }); + } + + private _coachmarkOnClickHandler() { + + // Set the height and width of the element + + } } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubbleContent.tsx b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubbleContent.tsx index c0f6a47e2e559b..dd7fd0aaf4ad26 100644 --- a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubbleContent.tsx +++ b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubbleContent.tsx @@ -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 { // Specify default props values @@ -22,6 +28,10 @@ export class TeachingBubbleContent extends BaseComponent + ); + } if (illustrationImage && illustrationImage.src) { imageContent = ( @@ -113,7 +130,8 @@ export class TeachingBubbleContent extends BaseComponent +
+ { coachMarkIcon } { imageContent } { closeButton }
diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubblePage.tsx b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubblePage.tsx index a81a265ce96db5..c9b9216757ad2f 100644 --- a/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubblePage.tsx +++ b/packages/office-ui-fabric-react/src/components/TeachingBubble/TeachingBubblePage.tsx @@ -9,12 +9,14 @@ import { import { TeachingBubbleBasicExample } from './examples/TeachingBubble.Basic.Example'; import { TeachingBubbleCondensedExample } from './examples/TeachingBubble.Condensed.Example'; import { TeachingBubbleIllustrationExample } from './examples/TeachingBubble.Illustration.Example'; +import { TeachingBubbleCoachmarkExample } from './examples/TeachingBubble.Coachmark.Example'; import { ComponentStatus } from '../../demo/ComponentStatus/ComponentStatus'; import { TeachingBubbleStatus } from './TeachingBubble.checklist'; const TeachingBubbleBasicExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/TeachingBubble/examples/TeachingBubble.Basic.Example.tsx') as string; const TeachingBubbleCondensedExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/TeachingBubble/examples/TeachingBubble.Condensed.Example.tsx') as string; const TeachingBubbleIllustrationExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/TeachingBubble/examples/TeachingBubble.Basic.Example.tsx') as string; +const TeachingBubbleCoachmarkExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/TeachingBubble/examples/TeachingBubble.Coachmark.Example.tsx') as string; export class TeachingBubblePage extends React.Component { public render() { @@ -33,6 +35,9 @@ export class TeachingBubblePage extends React.Component { + + + } propertiesTables={ diff --git a/packages/office-ui-fabric-react/src/components/TeachingBubble/examples/TeachingBubble.Coachmark.Example.tsx b/packages/office-ui-fabric-react/src/components/TeachingBubble/examples/TeachingBubble.Coachmark.Example.tsx new file mode 100644 index 00000000000000..248d079773149b --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/TeachingBubble/examples/TeachingBubble.Coachmark.Example.tsx @@ -0,0 +1,58 @@ +/* tslint:disable:no-unused-variable */ +import * as React from 'react'; +/* tslint:enable:no-unused-variable */ + +import { DefaultButton, IButtonProps } from 'office-ui-fabric-react/lib/Button'; +import { TeachingBubble } from 'office-ui-fabric-react/lib/TeachingBubble'; + +export interface ITeachingBubbleBasicExampleState { + isTeachingBubbleVisible?: boolean; +} + +export class TeachingBubbleCoachmarkExample extends React.Component { + private _menuButtonElement: HTMLElement; + + public constructor() { + super(); + + this._onDismiss = this._onDismiss.bind(this); + + this.state = { + isTeachingBubbleVisible: false, + }; + } + + public render() { + let { isTeachingBubbleVisible } = this.state; + + return ( +
+ this._menuButtonElement = menuButton }> + + + { isTeachingBubbleVisible ? ( +
+ + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Facere, nulla, ipsum? Molestiae quis aliquam magni harum non? + +
+ ) : (null) } +
+ ); + } + + private _onDismiss(ev: any) { + this.setState({ + isTeachingBubbleVisible: !this.state.isTeachingBubbleVisible + }); + } +}