-
Notifications
You must be signed in to change notification settings - Fork 2.9k
ActivityItem: add pulsing beacon animation #4553
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 22 commits
c6375df
ae0330c
6594e6e
47322e9
939b111
85b8a8e
ef56748
f512b49
830dbfa
67012f2
6825f5e
d39777b
2b10ed2
fdce482
f11b3be
6bfa48a
a9a585c
adab2d1
34a7662
8cfafdc
c9721b3
7f970f6
7cf1078
c11b9cd
fd41b49
e346cf9
8509ff9
295a03b
6570a10
d35b27f
57aa539
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "changes": [ | ||
| { | ||
| "comment": "PulsingBeaconAnimationStyles: Distinguish between single and double pulse.", | ||
| "packageName": "@uifabric/styling", | ||
| "type": "minor" | ||
| } | ||
| ], | ||
| "packageName": "@uifabric/styling", | ||
| "email": "lynam.emily@gmail.com" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "changes": [ | ||
| { | ||
| "packageName": "office-ui-fabric-react", | ||
| "comment": "ActivityItem: Added the pulsing beacon animation for the compact size.", | ||
| "type": "minor" | ||
| } | ||
| ], | ||
| "packageName": "office-ui-fabric-react", | ||
| "email": "lynam.emily@gmail.com" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,22 +2,66 @@ import { | |
| concatStyleSets, | ||
| ITheme, | ||
| getTheme, | ||
| HighContrastSelector | ||
| HighContrastSelector, | ||
| keyframes, | ||
| PulsingBeaconAnimationStyles | ||
| } from '../../Styling'; | ||
| import { | ||
| memoizeFunction | ||
| } from '../../Utilities'; | ||
| import { IActivityItemStyles } from './ActivityItem.types'; | ||
| import { IActivityItemStyles, IActivityItemProps } from './ActivityItem.types'; | ||
|
|
||
| const DEFAULT_PERSONA_SIZE = '32px'; | ||
| const COMPACT_PERSONA_SIZE = '16px'; | ||
| const DEFAULT_ICON_SIZE = '16px'; | ||
| const COMPACT_ICON_SIZE = '13px'; | ||
| const ANIMATION_INNER_DIMENSION = '4px'; | ||
| const ANIMATION_OUTER_DIMENSION = '28px'; | ||
| const ANIMATION_BORDER_WIDTH = '4px'; | ||
|
|
||
| export const getStyles = memoizeFunction(( | ||
| props: IActivityItemProps, | ||
| theme: ITheme = getTheme(), | ||
| customStyles?: IActivityItemStyles | ||
| ): IActivityItemStyles => { | ||
|
|
||
| const continuousPulse = PulsingBeaconAnimationStyles.continuousPulseAnimationSingle( | ||
| props.beaconColorOne!, | ||
| props.beaconColorTwo!, | ||
| ANIMATION_INNER_DIMENSION, | ||
| ANIMATION_OUTER_DIMENSION, | ||
| ANIMATION_BORDER_WIDTH | ||
| ); | ||
|
|
||
| const fadeIn: string = keyframes({ | ||
| from: { opacity: 0, }, | ||
| to: { opacity: 1, } | ||
| }); | ||
|
|
||
| const slideIn: string = keyframes({ | ||
| from: { transform: 'translateX(-10px)' }, | ||
| to: { transform: 'translateX(0)' } | ||
| }); | ||
|
|
||
| const continuousPulseAnimation = { | ||
| animationName: continuousPulse, | ||
| animationIterationCount: '1', | ||
| animationDuration: '.8s', | ||
| zIndex: 1000 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if this is within its own stacking context, then just set z-index to 2
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (because no other z-indexes elsewhere will matter) |
||
| }; | ||
|
|
||
| const slideInAnimation = { | ||
| animationName: slideIn, | ||
| animationIterationCount: '1', | ||
| animationDuration: '.5s', | ||
| }; | ||
|
|
||
| const fadeInAnimation = { | ||
| animationName: fadeIn, | ||
| animationIterationCount: '1', | ||
| animationDuration: '.5s', | ||
| }; | ||
|
|
||
| const ActivityItemStyles: IActivityItemStyles = { | ||
|
|
||
| root: [ | ||
|
|
@@ -29,7 +73,23 @@ export const getStyles = memoizeFunction(( | |
| lineHeight: '17px', | ||
| boxSizing: 'border-box', | ||
| color: theme.palette.neutralSecondary | ||
| } | ||
| }, | ||
| (props.isCompact && props.animateBeaconSignal) && fadeInAnimation | ||
| ], | ||
|
|
||
| pulsingBeacon: [ | ||
| { | ||
| position: 'absolute', | ||
| top: '50%', | ||
| left: '50%', | ||
| transform: 'translate(-50%, -50%)', | ||
| width: '0px', | ||
| height: '0px', | ||
| borderRadius: '225px', | ||
| borderStyle: 'solid', | ||
| opacity: 0 | ||
| }, | ||
| (props.isCompact && props.animateBeaconSignal) && continuousPulseAnimation | ||
| ], | ||
|
|
||
| isCompactRoot: { | ||
|
|
@@ -63,13 +123,18 @@ export const getStyles = memoizeFunction(( | |
|
|
||
| isCompactIcon: { | ||
| height: COMPACT_PERSONA_SIZE, | ||
| minWidth: COMPACT_PERSONA_SIZE, | ||
| fontSize: COMPACT_ICON_SIZE, | ||
| lineHeight: COMPACT_ICON_SIZE, | ||
| color: theme.palette.themePrimary, | ||
| marginTop: '1px', | ||
| position: 'relative', | ||
| display: 'flex', | ||
| justifyContent: 'center', | ||
| alignItems: 'center', | ||
| selectors: { | ||
| '.ms-Persona-imageArea': { | ||
| marginTop: '-2px', | ||
| margin: '-2px 0 0 -2px', | ||
| border: '2px solid' + theme.palette.white, | ||
| borderRadius: '50%', | ||
| selectors: { | ||
|
|
@@ -101,9 +166,12 @@ export const getStyles = memoizeFunction(( | |
| overflow: 'visible' | ||
| }, | ||
|
|
||
| activityContent: { | ||
| padding: '0 8px' | ||
| }, | ||
| activityContent: [ | ||
| { | ||
| padding: '0 8px' | ||
| }, | ||
| (props.isCompact && props.animateBeaconSignal) && slideInAnimation | ||
| ], | ||
|
|
||
| activityText: { | ||
| display: 'inline' | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,11 @@ import { getStyles } from './ActivityItem.styles'; | |
| import { PersonaSize, PersonaCoin, IPersonaSharedProps } from '../../Persona'; | ||
|
|
||
| export class ActivityItem extends BaseComponent<IActivityItemProps, {}> { | ||
| public static defaultProps: Partial<IActivityItemProps> = { | ||
| beaconColorOne: '#00FFEC', | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need themable colors for this or is it just a shine?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. verify this looks okay in a dark theme
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I got the colors from Coachmark - confirming with design what to do here.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We switched to comparable theme colors. @phkuo how do you suggest testing dark theme? Is there a SP palette we can plug-in to the demo site? |
||
| beaconColorTwo: '#005EDD' | ||
| }; | ||
|
|
||
| constructor(props: IActivityItemProps) { | ||
| super(props); | ||
| } | ||
|
|
@@ -19,7 +24,9 @@ export class ActivityItem extends BaseComponent<IActivityItemProps, {}> { | |
| onRenderActivityDescription = this._onRenderActivityDescription, | ||
| onRenderComments = this._onRenderComments, | ||
| onRenderTimeStamp = this._onRenderTimeStamp, | ||
| styles: customStyles | ||
| styles: customStyles, | ||
| animateBeaconSignal, | ||
| isCompact | ||
| } = this.props; | ||
|
|
||
| const classNames = this._getClassNames(this.props); | ||
|
|
@@ -29,6 +36,9 @@ export class ActivityItem extends BaseComponent<IActivityItemProps, {}> { | |
|
|
||
| { (this.props.activityPersonas || this.props.activityIcon || this.props.onRenderIcon) && | ||
| <div className={ classNames.activityTypeIcon }> | ||
| { animateBeaconSignal && isCompact && | ||
| <div className={ classNames.pulsingBeacon } /> | ||
| } | ||
| { onRenderIcon(this.props) } | ||
| </div> | ||
| } | ||
|
|
@@ -122,6 +132,6 @@ export class ActivityItem extends BaseComponent<IActivityItemProps, {}> { | |
| } | ||
|
|
||
| private _getClassNames(props: IActivityItemProps): IActivityItemClassNames { | ||
| return getClassNames(getStyles(undefined, props.styles), props.className!, props.activityPersonas!, props.isCompact!); | ||
| return getClassNames(getStyles(props, undefined, props.styles), props.className!, props.activityPersonas!, props.isCompact!); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a way to do this without z-index? z-index can be deceptive unless you can guarantee your own stacking context
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I do need some z-index during the animation so that it animates over the icon / persona and the text. But it's only for within the Item itself so I lowered it. - I'll push that change once the master build is fixed.