semantic-ui-react
Version: 
The official Semantic-UI-React integration.
181 lines (147 loc) • 5.14 kB
JavaScript
import cx from 'clsx'
import PropTypes from 'prop-types'
import React from 'react'
import {
  ModernAutoControlledComponent as Component,
  childrenUtils,
  createHTMLIframe,
  customPropTypes,
  getElementType,
  getUnhandledProps,
  useKeyOnly,
} from '../../lib'
import Icon from '../../elements/Icon'
/**
 * An embed displays content from other websites like YouTube videos or Google Maps.
 */
export default class Embed extends Component {
  getSrc() {
    const {
      autoplay = true,
      brandedUI = false,
      color = '#444444',
      hd = true,
      id,
      source,
      url,
    } = this.props
    if (source === 'youtube') {
      return [
        `//www.youtube.com/embed/${id}`,
        '?autohide=true',
        `&autoplay=${autoplay}`,
        `&color=${encodeURIComponent(color)}`,
        `&hq=${hd}`,
        '&jsapi=false',
        `&modestbranding=${brandedUI}`,
        `&rel=${brandedUI ? 0 : 1}`,
      ].join('')
    }
    if (source === 'vimeo') {
      return [
        `//player.vimeo.com/video/${id}`,
        '?api=false',
        `&autoplay=${autoplay}`,
        '&byline=false',
        `&color=${encodeURIComponent(color)}`,
        '&portrait=false',
        '&title=false',
      ].join('')
    }
    return url
  }
  handleClick = (e) => {
    const { onClick } = this.props
    const { active } = this.state
    if (onClick) onClick(e, { ...this.props, active: true })
    if (!active) this.setState({ active: true })
  }
  render() {
    const { aspectRatio, className, icon, placeholder } = this.props
    const { active } = this.state
    const classes = cx('ui', aspectRatio, useKeyOnly(active, 'active'), 'embed', className)
    const rest = getUnhandledProps(Embed, this.props)
    const ElementType = getElementType(Embed, this.props)
    const iconShorthand = icon !== undefined ? icon : 'video play'
    return (
      <ElementType {...rest} className={classes} onClick={this.handleClick}>
        {Icon.create(iconShorthand, { autoGenerateKey: false })}
        {placeholder && <img className='placeholder' src={placeholder} />}
        {this.renderEmbed()}
      </ElementType>
    )
  }
  renderEmbed() {
    const { children, content, iframe, source } = this.props
    const { active } = this.state
    if (!active) return null
    if (!childrenUtils.isNil(children)) return <div className='embed'>{children}</div>
    if (!childrenUtils.isNil(content)) return <div className='embed'>{content}</div>
    return (
      <div className='embed'>
        {createHTMLIframe(childrenUtils.isNil(iframe) ? this.getSrc() : iframe, {
          defaultProps: {
            allowFullScreen: false,
            frameBorder: 0,
            height: '100%',
            scrolling: 'no',
            src: this.getSrc(),
            title: `Embedded content from ${source}.`,
            width: '100%',
          },
          autoGenerateKey: false,
        })}
      </div>
    )
  }
}
Embed.propTypes = {
  /** An element type to render as (string or function). */
  as: PropTypes.elementType,
  /** An embed can be active. */
  active: PropTypes.bool,
  /** An embed can specify an alternative aspect ratio. */
  aspectRatio: PropTypes.oneOf(['4:3', '16:9', '21:9']),
  /** Setting to true or false will force autoplay. */
  autoplay: customPropTypes.every([customPropTypes.demand(['source']), PropTypes.bool]),
  /** Whether to show networks branded UI like title cards, or after video calls to action. */
  brandedUI: customPropTypes.every([customPropTypes.demand(['source']), PropTypes.bool]),
  /** Primary content. */
  children: PropTypes.node,
  /** Additional classes. */
  className: PropTypes.string,
  /** Specifies a default chrome color with Vimeo or YouTube. */
  color: customPropTypes.every([customPropTypes.demand(['source']), PropTypes.string]),
  /** Shorthand for primary content. */
  content: customPropTypes.contentShorthand,
  /** Initial value of active. */
  defaultActive: PropTypes.bool,
  /** Whether to prefer HD content. */
  hd: customPropTypes.every([customPropTypes.demand(['source']), PropTypes.bool]),
  /** Specifies an icon to use with placeholder content. */
  icon: customPropTypes.itemShorthand,
  /** Specifies an id for source. */
  id: customPropTypes.every([customPropTypes.demand(['source']), PropTypes.string]),
  /** Shorthand for HTML iframe. */
  iframe: customPropTypes.every([
    customPropTypes.demand(['source']),
    customPropTypes.itemShorthand,
  ]),
  /**
   * Сalled on click.
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {object} data - All props and proposed value.
   */
  onClick: PropTypes.func,
  /** A placeholder image for embed. */
  placeholder: PropTypes.string,
  /** Specifies a source to use. */
  source: customPropTypes.every([
    customPropTypes.disallow(['sourceUrl']),
    PropTypes.oneOf(['youtube', 'vimeo']),
  ]),
  /** Specifies a url to use for embed. */
  url: customPropTypes.every([customPropTypes.disallow(['source']), PropTypes.string]),
}
Embed.autoControlledProps = ['active']