Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

feat(Embed|Video): add components #1108

Merged
merged 32 commits into from
Apr 10, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f431c27
feat: implements video and video gif component
stuartlong Mar 25, 2019
ffb49f7
Responded to PR comments
stuartlong Mar 28, 2019
449c955
Create Embed component
stuartlong Apr 2, 2019
92fd5c0
Merge branch 'master' into feat/stuartlo/video
layershifter Apr 4, 2019
498865f
Merge branch 'feat/stuartlo/video' of https://github.com/stuartlong/r…
stuartlong Apr 4, 2019
f6a3110
USe AutoControlled component
stuartlong Apr 4, 2019
443f2f4
Respond to code review comments
stuartlong Apr 4, 2019
cebb462
Add some periods
stuartlong Apr 4, 2019
f762d05
Remove redundant conditional in styles
stuartlong Apr 4, 2019
fd55afc
reorder props, add missing propTypes
layershifter Apr 8, 2019
10f77dc
remove unused lodash
layershifter Apr 8, 2019
7e5128d
reorder props, add missing, remove useless
layershifter Apr 8, 2019
4885f72
use trySetState
layershifter Apr 8, 2019
2c25207
use `v` & VideoVariables
layershifter Apr 8, 2019
8667773
move control to a separate slot
layershifter Apr 8, 2019
41581f3
export play and pause icons
layershifter Apr 8, 2019
c2186e2
add stardust icons
layershifter Apr 8, 2019
f71b155
use Icon component, simplify styles
layershifter Apr 8, 2019
1e43a79
Merge branch 'master' of https://github.com/stardust-ui/react into fe…
layershifter Apr 8, 2019
8873cd4
update case
layershifter Apr 8, 2019
a09438a
Merge branch 'master' of https://github.com/stardust-ui/react into fe…
layershifter Apr 9, 2019
82453f5
fix UTs
layershifter Apr 9, 2019
2052501
fix merge issue
layershifter Apr 9, 2019
41fcec4
fix broken UTs
layershifter Apr 9, 2019
15eaf66
fix assignment of muted prop
layershifter Apr 9, 2019
4448b54
fix import
layershifter Apr 9, 2019
dbc89f4
fix condition
layershifter Apr 9, 2019
ae56edc
address comments
layershifter Apr 10, 2019
48618ee
Merge branch 'master' of https://github.com/stardust-ui/react into fe…
layershifter Apr 10, 2019
fff05b3
add changelog entry
layershifter Apr 10, 2019
1e6809a
Merge branch 'master' of https://github.com/stardust-ui/react into fe…
layershifter Apr 10, 2019
dae16b9
update styles
layershifter Apr 10, 2019
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
@@ -0,0 +1,16 @@
import * as React from 'react'
import { Embed, Flex, Text } from '@stardust-ui/react'

const EmbedExample = () => (
<Flex column>
<Embed
placeholder="https://github.com/bower-media-samples/big-buck-bunny-480p-5s/master/poster.jpg"
src="https://github.com/bower-media-samples/big-buck-bunny-1080p-5s/master/video.mp4"
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
playing
variables={{ height: '400px', width: '711.11px' }}
/>
<Text>(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org</Text>
</Flex>
)

export default EmbedExample
16 changes: 16 additions & 0 deletions docs/src/examples/components/Embed/Types/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react'

import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection'

const Types = () => (
<ExampleSection title="Types">
<ComponentExample
title="Embed"
description="A basic embedded GIF."
examplePath="components/Embed/Types/EmbedExample"
/>
</ExampleSection>
)

export default Types
11 changes: 11 additions & 0 deletions docs/src/examples/components/Embed/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as React from 'react'

import Types from './Types'

const EmbedExamples = () => (
<>
<Types />
</>
)

export default EmbedExamples
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react'
import { Video, Text, Flex } from '@stardust-ui/react'

const VideoExample = () => (
<Flex column>
<Video
src="https://github.com/bower-media-samples/big-buck-bunny-480p-30s/master/video.mp4"
variables={{ width: '600px' }}
/>
<Text>(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org</Text>
</Flex>
)

export default VideoExample
16 changes: 16 additions & 0 deletions docs/src/examples/components/Video/Types/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react'

import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection'

const Types = () => (
<ExampleSection title="Types">
<ComponentExample
title="Default"
description="A default Video."
examplePath="components/Video/Types/VideoExample"
/>
</ExampleSection>
)

export default Types
11 changes: 11 additions & 0 deletions docs/src/examples/components/Video/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as React from 'react'

import Types from './Types'

const VideoExamples = () => (
<>
<Types />
</>
)

export default VideoExamples
145 changes: 145 additions & 0 deletions packages/react/src/components/Embed/Embed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import * as PropTypes from 'prop-types'
import * as React from 'react'

import {
createShorthandFactory,
UIComponent,
UIComponentProps,
commonPropTypes,
applyAccessibilityKeyHandlers,
customPropTypes,
} from '../../lib'
import { embedBehavior } from '../../lib/accessibility'
import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibility/types'
import Image from '../Image/Image'
import Video from '../Video/Video'
import Box from '../Box/Box'
import * as _ from 'lodash'

import { ReactProps, ShorthandValue } from '../../types'

export interface EmbedProps extends UIComponentProps {
/**
* Accessibility behavior if overridden by the user.
* @default embedBehavior
* */
accessibility?: Accessibility

/** Video source URL. */
src?: string
stuartlong marked this conversation as resolved.
Show resolved Hide resolved

/** Image source URL for when video isn't playing */
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
placeholder?: string

/** whether the gif should be playing */
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
playing?: boolean

iframe?: ShorthandValue

video?: ShorthandValue
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
}

export interface EmbedState {
isPlaying: boolean
}

/**
* A GIF is a muted segment of a video
* @accessibility
* If GIF should be visible to screen readers, textual representation needs to be provided in 'alt' or 'title' property.
*
* Other considerations:
* - when alt and title property are empty, then Narrator in scan mode navigates to the gif and narrates it as empty paragraph
*/
class Embed extends UIComponent<ReactProps<EmbedProps>, EmbedState> {
static create: Function

static className = 'ui-embed'

static displayName = 'Embed'

static propTypes = {
...commonPropTypes.createCommon({
children: false,
content: false,
}),
iframe: customPropTypes.itemShorthand,
playing: PropTypes.bool,
poster: PropTypes.string,
src: PropTypes.string,
video: customPropTypes.itemShorthand,
}

static defaultProps = {
as: 'span',
accessibility: embedBehavior as Accessibility,
}

public state = {
isPlaying: this.props.playing,
}

shouldComponentUpdate(nextProps: EmbedProps, nextState: EmbedState): boolean {
if (nextProps.playing !== this.props.playing) {
this.setState({ isPlaying: nextProps.playing })
return false
}

return !_.isEqual(this.props, nextProps) || !_.isEqual(nextState, this.state)
}

renderComponent({ ElementType, classes, accessibility, unhandledProps, styles, variables }) {
const { placeholder, src, video, iframe } = this.props

return (
<ElementType
{...unhandledProps}
className={classes.root}
{...accessibility.attributes.root}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
onClick={this.handleClick}
>
{this.state.isPlaying
? Video.create(video || ElementType, {
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
defaultProps: {
src,
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
placeholder,
autoPlay: true,
muted: true,
controls: false,
loop: true,
styles: styles.video,
variables: {
width: variables.width,
height: variables.height,
},
},
})
: Image.create(placeholder, {
defaultProps: {
styles: styles.image,
variables: {
width: variables.width,
height: variables.height,
},
},
})}
{Box.create(iframe, { defaultProps: { as: 'iframe' } })}
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
</ElementType>
)
}

protected actionHandlers: AccessibilityActionHandlers = {
performClick: event => this.handleClick(event),
}

private handleClick = e => {
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
e.stopPropagation()
e.preventDefault()
this.setState({ isPlaying: !this.state.isPlaying })
}
}

Embed.create = createShorthandFactory({ Component: Embed })

export default Embed
74 changes: 74 additions & 0 deletions packages/react/src/components/Video/Video.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as PropTypes from 'prop-types'
import * as React from 'react'

import { createShorthandFactory, UIComponent, UIComponentProps, commonPropTypes } from '../../lib'

import { ReactProps } from '../../types'

export interface VideoProps extends UIComponentProps {
/** Video source URL. */
src?: string

/** Image source URL for when video isn't playing */
poster?: string
stuartlong marked this conversation as resolved.
Show resolved Hide resolved

/** Whether the video should be allowed to play audio */
muted?: boolean

/** Whether the video should start playing when rendered. Autoplay videos must be muted or they will not play immediately in certain browers like Chrome */
autoPlay?: boolean

/** Whether to display the native video controls */
controls?: boolean

/** Whether the video should automatically restart after it ends */
loop?: boolean
}

/**
* An video is a graphicical and audio representation of something.
*/
class Video extends UIComponent<ReactProps<VideoProps>> {
static create: Function

static className = 'ui-video'

static displayName = 'Video'

static propTypes = {
...commonPropTypes.createCommon({
children: false,
content: false,
}),
controls: PropTypes.bool,
autoPlay: PropTypes.bool,
muted: PropTypes.bool,
loop: PropTypes.bool,
}

static defaultProps = {
as: 'video',
controls: true,
autoPlay: false,
muted: false,
}

renderComponent({ ElementType, classes, unhandledProps }) {
const { controls, autoPlay, muted, loop } = this.props

return (
<ElementType
{...unhandledProps}
className={classes.root}
controls={controls}
autoPlay={autoPlay}
loop={loop}
muted={muted}
/>
)
}
}

Video.create = createShorthandFactory({ Component: Video })
stuartlong marked this conversation as resolved.
Show resolved Hide resolved

export default Video
4 changes: 4 additions & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export {
DropdownSearchInputProps,
} from './components/Dropdown/DropdownSearchInput'

export { default as Embed, EmbedProps, EmbedState } from './components/Embed/Embed'

export { default as Flex, FlexProps } from './components/Flex/Flex'
export { default as FlexItem, FlexItemProps } from './components/Flex/FlexItem'

Expand Down Expand Up @@ -155,6 +157,8 @@ export { default as Tree } from './components/Tree'
export { default as Reaction, ReactionProps, ReactionState } from './components/Reaction/Reaction'
export { default as ReactionGroup, ReactionGroupProps } from './components/Reaction/ReactionGroup'

export { default as Video, VideoProps } from './components/Video/Video'

//
// Accessibility
//
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Accessibility } from '../../types'
import * as keyboardKey from 'keyboard-key'

/**
* @description
* GIFs are visual representation only so hidden unless alt or title applied.
*
* Enter/space keys play and pause the gif respectively
*
* @specification
* Sets 'aria-hidden' unless alt or title attribute provided
*/
const embedBehavior: Accessibility = (props: any) => ({
attributes: {
root: {
tabIndex: '0',
'aria-hidden': props['alt'] || props['title'] ? undefined : true,
stuartlong marked this conversation as resolved.
Show resolved Hide resolved
role: 'presentation',
},
},
keyActions: {
root: {
performClick: {
keyCombinations: [{ keyCode: keyboardKey.Enter }, { keyCode: keyboardKey.Spacebar }],
},
},
},
})

export default embedBehavior
1 change: 1 addition & 0 deletions packages/react/src/lib/accessibility/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ export { default as gridBehavior } from './Behaviors/Grid/gridBehavior'
export { default as treeTitleBehavior } from './Behaviors/Tree/treeTitleBehavior'
export { default as dialogBehavior } from './Behaviors/Dialog/dialogBehavior'
export { default as statusBehavior } from './Behaviors/Status/statusBehavior'
export { default as embedBehavior } from './Behaviors/Embed/embedBehavior'
4 changes: 4 additions & 0 deletions packages/react/src/themes/teams/componentStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export { default as DropdownSearchInput } from './components/Dropdown/dropdownSe
export { default as DropdownSelectedItem } from './components/Dropdown/dropdownSelectedItemStyles'
export { default as DropdownItem } from './components/Dropdown/dropdownItemStyles'

export { default as Embed } from './components/Embed/embedStyles'

export { default as Flex } from './components/Flex/flexStyles'
export { default as FlexItem } from './components/Flex/flexItemStyles'

Expand Down Expand Up @@ -73,3 +75,5 @@ export { default as TreeItem } from './components/Tree/treeItemStyles'
export { default as TreeTitle } from './components/Tree/treeTitleStyles'

export { default as Animation } from './components/Animation/animationStyles'

export { default as Video } from './components/Video/videoStyles'
4 changes: 4 additions & 0 deletions packages/react/src/themes/teams/componentVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export {
default as DropdownSelectedItem,
} from './components/Dropdown/dropdownSelectedItemVariables'

export { default as Embed } from './components/Embed/embedVariables'

export { default as Flex } from './components/Flex/flexVariables'
export { default as FlexItem } from './components/Flex/flexItemVariables'

Expand Down Expand Up @@ -67,3 +69,5 @@ export { default as Text } from './components/Text/textVariables'
export { default as TreeTitle } from './components/Tree/treeTitleVariables'

export { default as Animation } from './components/Animation/animationVariables'

export { default as Video } from './components/Video/videoVariables'
Loading