Skip to content

Commit

Permalink
Merge pull request #409 from Giphy/react-components/gif-remove-wrappe…
Browse files Browse the repository at this point in the history
…r-el-css

react-components: add percentWidth prop for Gif. fetch-api: add type videos to related fetch
  • Loading branch information
giannif authored Aug 2, 2023
2 parents 62de1ae + ad0f108 commit de1c0a5
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 60 deletions.
8 changes: 8 additions & 0 deletions .changeset/angry-lamps-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@giphy/react-components': minor
'@giphy/js-fetch-api': minor
---

react-components: percentWidth prop on gif allows you to display a Gif component using a css percentage value

fetch-api: add type videos to related end point
12 changes: 11 additions & 1 deletion packages/fetch-api/public/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,22 @@ const gifByCategory = async () => {
}
const related = async () => {
try {
const result = await gf.related('3oEjHGr1Fhz0kyv8Ig')
const result = await gf.related('3oEjHGr1Fhz0kyv8Ig', { limit: 4 })
console.log('related', result)
} catch (error) {
console.error('related', error)
}
}

const relatedClips = async () => {
try {
const result = await gf.related('W2nuhlWbyVmV73jIsc', { type: 'videos' })
console.log('related videos', result)
} catch (error) {
console.error('related videos', error)
}
}

const animate = async () => {
try {
const result = await gf.animate('hello')
Expand Down Expand Up @@ -145,3 +154,4 @@ text()
textTrending()
animate()
searchVideos()
relatedClips()
7 changes: 4 additions & 3 deletions packages/fetch-api/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable no-dupe-class-members */
import { GifID } from '@giphy/js-types'
import { getPingbackId } from '@giphy/js-util'
import qs from 'qs'
import { normalizeGif, normalizeGifs } from './normalize/gif'
Expand All @@ -14,7 +15,6 @@ import {
TypeOption,
} from './option-types'
import request from './request'
import { GifID } from '@giphy/js-types'
import { CategoriesResult, ChannelsResult, GifResult, GifsResult, NonPaginatedGifsResult } from './result-types'

const getType = (options?: TypeOption): MediaType => (options && options.type ? options.type : 'gifs')
Expand Down Expand Up @@ -172,9 +172,10 @@ export class GiphyFetch {
* @param {SubcategoriesOptions} options
* @returns {Promise<GifsResult>}
**/
related(id: string, options?: RelatedOptions): Promise<GifsResult> {
related(id: string, options: RelatedOptions = {}): Promise<GifsResult> {
const { type = 'gifs' } = options
return request(
`${options?.type === 'stickers' ? 'stickers' : 'gifs'}/related?${this.getQS({
`${type}/related?${this.getQS({
gif_id: id,
rating: 'pg-13',
...options,
Expand Down
2 changes: 1 addition & 1 deletion packages/fetch-api/src/option-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface PaginationOptions {
export interface CategoriesOptions extends PaginationOptions {}
export interface SubcategoriesOptions extends PaginationOptions {}
export interface RelatedOptions extends PaginationOptions {
type?: 'gifs' | 'stickers' // no 'text' support, overrride MediaType
type?: 'gifs' | 'stickers' | 'videos' // no 'text' support, overrride MediaType
rating?: Rating
}

Expand Down
96 changes: 43 additions & 53 deletions packages/react-components/src/components/gif.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,17 @@ import { giphyBlue, giphyGreen, giphyPurple, giphyRed, giphyYellow } from '@giph
import { IGif, IUser, ImageAllTypes } from '@giphy/js-types'
import { Logger, getAltText, getBestRendition, getGifHeight } from '@giphy/js-util'
import 'intersection-observer'
import React, {
ElementType,
HTMLAttributes,
HTMLProps,
ReactNode,
SyntheticEvent,
useContext,
useEffect,
useRef,
useState,
} from 'react'
import styled, { css } from 'styled-components'
import React, { ElementType, ReactNode, SyntheticEvent, useContext, useEffect, useRef, useState } from 'react'
import styled from 'styled-components'
import * as pingback from '../util/pingback'
import AttributionOverlay from './attribution/overlay'
import VerifiedBadge from './attribution/verified-badge'
import { PingbackContext } from './pingback-context-manager'
import { GifOverlayProps } from './types'

const GifContainer = styled.div<{ borderRadius?: number }>`
const Container = styled.div`
position: relative;
display: block;
${(props) =>
props.borderRadius &&
css`
border-radius: ${props.borderRadius}px;
overflow: hidden;
`}
img {
display: block;
}
Expand All @@ -46,11 +31,6 @@ export const getColor = () => GRID_COLORS[Math.round(Math.random() * (GRID_COLOR

const hoverTimeoutDelay = 200

type ContainerProps = HTMLProps<HTMLElement> & { href?: string; borderRadius: number }
const Container = (props: ContainerProps) => (
<GifContainer as={props.href ? 'a' : 'div'} {...(props as HTMLAttributes<HTMLDivElement>)} />
)

export type EventProps = {
// fired every time the gif is show
onGifVisible?: (gif: IGif, e?: SyntheticEvent<HTMLElement, Event>) => void
Expand All @@ -67,6 +47,7 @@ export type EventProps = {
type GifProps = {
gif: IGif
width: number
percentWidth?: string
height?: number
backgroundColor?: string
className?: string
Expand Down Expand Up @@ -99,6 +80,7 @@ const RenderOnClient = ({ children }: { children: ReactNode }) => {
const Gif = ({
gif,
width,
percentWidth,
height: forcedHeight,
onGifRightClick = noop,
className = '',
Expand Down Expand Up @@ -239,6 +221,11 @@ const Gif = ({
}
}, [])
const height = forcedHeight || getGifHeight(gif, width)
let percentHeight: string | undefined
if (percentWidth) {
const ratio = Math.round((height / width) * 100)
percentHeight = `${ratio}%`
}
const bestRendition = getBestRendition(gif.images, width, height)
const rendition = gif.images[bestRendition.renditionName] as ImageAllTypes
const background =
Expand All @@ -247,51 +234,54 @@ const Gif = ({
(gif.is_sticker
? `url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4AQMAAACSSKldAAAABlBMVEUhIiIWFhYoSqvJAAAAGElEQVQY02MAAv7///8PWxqIPwDZw5UGABtgwz2xhFKxAAAAAElFTkSuQmCC') 0 0`
: defaultBgColor.current)

const overflow = borderRadius ? 'hidden' : 'unset'
return (
<Container
as={noLink ? 'div' : 'a'}
href={noLink ? undefined : gif.url}
data-giphy-id={gif.id}
data-giphy-is-sticker={gif.is_sticker}
style={{
width,
height,
width: percentWidth || width,
height: percentHeight || height,
overflow,
borderRadius,
...style,
}}
borderRadius={borderRadius}
className={[Gif.className, className].join(' ')}
onMouseOver={onMouseOver}
onMouseLeave={onMouseLeave}
onClick={onClick}
onContextMenu={(e: SyntheticEvent<HTMLElement, Event>) => onGifRightClick(gif, e)}
onKeyPress={onKeyPress}
tabIndex={tabIndex}
ref={container}
>
<div style={{ width, height, position: 'relative' }} ref={container}>
<picture>
<source
type="image/webp"
srcSet={shouldShowMedia ? rendition.webp : placeholder}
suppressHydrationWarning
/>
<img
ref={image}
suppressHydrationWarning
className={[Gif.imgClassName, loadedClassname].join(' ')}
src={shouldShowMedia ? rendition.url : placeholder}
style={{ background }}
width={width}
height={height}
alt={getAltText(gif)}
onLoad={shouldShowMedia ? onImageLoad : () => {}}
/>
</picture>
{Overlay && (
// only render the overlay on the client since it depends on shouldShowMedia
<RenderOnClient>
{shouldShowMedia && <Overlay gif={gif} isHovered={isHovered} width={width} height={height} />}
</RenderOnClient>
)}
</div>
<picture>
<source
type="image/webp"
srcSet={shouldShowMedia ? rendition.webp : placeholder}
suppressHydrationWarning
/>
<img
ref={image}
suppressHydrationWarning
className={[Gif.imgClassName, loadedClassname].join(' ')}
src={shouldShowMedia ? rendition.url : placeholder}
style={{ background }}
width="100%"
height="100%"
alt={getAltText(gif)}
onLoad={shouldShowMedia ? onImageLoad : () => {}}
/>
</picture>
{Overlay && (
// only render the overlay on the client since it depends on shouldShowMedia
<RenderOnClient>
{shouldShowMedia && <Overlay gif={gif} isHovered={isHovered} width={width} height={height} />}
</RenderOnClient>
)}
</Container>
)
}
Expand Down
15 changes: 13 additions & 2 deletions packages/react-components/stories/gif.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ type GifComponentProps = React.ComponentProps<typeof GifComponent>

type GifDemoProps = Omit<GifComponentProps, 'gif'> & {
id: string
scale: string
}

const GifDemo = ({ id, width, height, noLink, borderRadius, overlay, ...other }: GifDemoProps) => {
const GifDemo = ({ id, width, height, noLink, borderRadius, percentWidth, overlay, ...other }: GifDemoProps) => {
const [gif, setGif] = useState<IGif>()

const fetch = useCallback(async () => {
Expand All @@ -38,6 +39,7 @@ const GifDemo = ({ id, width, height, noLink, borderRadius, overlay, ...other }:
tabIndex={1}
borderRadius={borderRadius}
gif={gif}
percentWidth={percentWidth}
width={width}
height={height}
noLink={noLink}
Expand All @@ -64,6 +66,9 @@ const meta: Meta<typeof GifDemo> = {
noLink: {
control: { type: 'boolean' },
},
percentWidth: {
control: { type: 'text' },
},
},
args: {
id: 'ZEU9ryYGZzttn0Cva7',
Expand All @@ -84,11 +89,17 @@ export const GifWithOverlay: Story = {
},
}

export const GifThatStretches: Story = {
args: {
percentWidth: '50%',
},
}

export const GifWithVideoOverlayFillVideo: Story = {
args: {
id: '3BNRWBatePBETD7Bfg',
height: 300,
overlay: (props: GifOverlayProps) => <VideoOverlay {...props} width={number('width', 500)} />,
overlay: (props: GifOverlayProps) => <VideoOverlay {...props} width={number('width', 300)} />,
},
}

Expand Down
6 changes: 6 additions & 0 deletions packages/react-components/stories/grid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ const meta: Meta<typeof Grid> = {
noLink: {
control: { type: 'boolean' },
},
columns: {
control: { type: 'number' },
},
gutter: {
control: { type: 'number' },
},
},
args: {
noLink: false,
Expand Down

0 comments on commit de1c0a5

Please sign in to comment.