diff --git a/.changeset/angry-lamps-dream.md b/.changeset/angry-lamps-dream.md new file mode 100644 index 00000000..7d414abb --- /dev/null +++ b/.changeset/angry-lamps-dream.md @@ -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 diff --git a/packages/fetch-api/public/index.tsx b/packages/fetch-api/public/index.tsx index 59a4c2f0..801df209 100644 --- a/packages/fetch-api/public/index.tsx +++ b/packages/fetch-api/public/index.tsx @@ -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') @@ -145,3 +154,4 @@ text() textTrending() animate() searchVideos() +relatedClips() diff --git a/packages/fetch-api/src/api.ts b/packages/fetch-api/src/api.ts index dd2e4240..6a2064e9 100644 --- a/packages/fetch-api/src/api.ts +++ b/packages/fetch-api/src/api.ts @@ -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' @@ -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') @@ -172,9 +172,10 @@ export class GiphyFetch { * @param {SubcategoriesOptions} options * @returns {Promise} **/ - related(id: string, options?: RelatedOptions): Promise { + related(id: string, options: RelatedOptions = {}): Promise { + 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, diff --git a/packages/fetch-api/src/option-types.ts b/packages/fetch-api/src/option-types.ts index eccc4f50..1c3f7df9 100644 --- a/packages/fetch-api/src/option-types.ts +++ b/packages/fetch-api/src/option-types.ts @@ -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 } diff --git a/packages/react-components/src/components/gif.tsx b/packages/react-components/src/components/gif.tsx index 1d56777b..34c29098 100644 --- a/packages/react-components/src/components/gif.tsx +++ b/packages/react-components/src/components/gif.tsx @@ -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; } @@ -46,11 +31,6 @@ export const getColor = () => GRID_COLORS[Math.round(Math.random() * (GRID_COLOR const hoverTimeoutDelay = 200 -type ContainerProps = HTMLProps & { href?: string; borderRadius: number } -const Container = (props: ContainerProps) => ( - )} /> -) - export type EventProps = { // fired every time the gif is show onGifVisible?: (gif: IGif, e?: SyntheticEvent) => void @@ -67,6 +47,7 @@ export type EventProps = { type GifProps = { gif: IGif width: number + percentWidth?: string height?: number backgroundColor?: string className?: string @@ -99,6 +80,7 @@ const RenderOnClient = ({ children }: { children: ReactNode }) => { const Gif = ({ gif, width, + percentWidth, height: forcedHeight, onGifRightClick = noop, className = '', @@ -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 = @@ -247,17 +234,21 @@ const Gif = ({ (gif.is_sticker ? `url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4AQMAAACSSKldAAAABlBMVEUhIiIWFhYoSqvJAAAAGElEQVQY02MAAv7///8PWxqIPwDZw5UGABtgwz2xhFKxAAAAAElFTkSuQmCC') 0 0` : defaultBgColor.current) + + const overflow = borderRadius ? 'hidden' : 'unset' return ( ) => onGifRightClick(gif, e)} onKeyPress={onKeyPress} tabIndex={tabIndex} + ref={container} > -
- - - {getAltText(gif)} {}} - /> - - {Overlay && ( - // only render the overlay on the client since it depends on shouldShowMedia - - {shouldShowMedia && } - - )} -
+ + + {getAltText(gif)} {}} + /> + + {Overlay && ( + // only render the overlay on the client since it depends on shouldShowMedia + + {shouldShowMedia && } + + )}
) } diff --git a/packages/react-components/stories/gif.stories.tsx b/packages/react-components/stories/gif.stories.tsx index 003e5e75..6a265936 100644 --- a/packages/react-components/stories/gif.stories.tsx +++ b/packages/react-components/stories/gif.stories.tsx @@ -18,9 +18,10 @@ type GifComponentProps = React.ComponentProps type GifDemoProps = Omit & { 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() const fetch = useCallback(async () => { @@ -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} @@ -64,6 +66,9 @@ const meta: Meta = { noLink: { control: { type: 'boolean' }, }, + percentWidth: { + control: { type: 'text' }, + }, }, args: { id: 'ZEU9ryYGZzttn0Cva7', @@ -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) => , + overlay: (props: GifOverlayProps) => , }, } diff --git a/packages/react-components/stories/grid.stories.tsx b/packages/react-components/stories/grid.stories.tsx index 7b00c9f3..40ca16c8 100644 --- a/packages/react-components/stories/grid.stories.tsx +++ b/packages/react-components/stories/grid.stories.tsx @@ -86,6 +86,12 @@ const meta: Meta = { noLink: { control: { type: 'boolean' }, }, + columns: { + control: { type: 'number' }, + }, + gutter: { + control: { type: 'number' }, + }, }, args: { noLink: false,