diff --git a/packages/react-sdk/docusaurus/docs/React/02-guides/10-sorting-api.mdx b/packages/react-sdk/docusaurus/docs/React/02-guides/10-sorting-api.mdx index 86532a8a3d..bf51a1232c 100644 --- a/packages/react-sdk/docusaurus/docs/React/02-guides/10-sorting-api.mdx +++ b/packages/react-sdk/docusaurus/docs/React/02-guides/10-sorting-api.mdx @@ -1,5 +1,5 @@ --- -title: Participant sorting +title: Participant Sorting description: Overview of the Sorting API used to sort call participants. --- diff --git a/packages/react-sdk/docusaurus/docs/React/03-ui-components/utility/reaction.mdx b/packages/react-sdk/docusaurus/docs/React/03-ui-components/utility/reaction.mdx index f47f7992ed..cfe9436326 100644 --- a/packages/react-sdk/docusaurus/docs/React/03-ui-components/utility/reaction.mdx +++ b/packages/react-sdk/docusaurus/docs/React/03-ui-components/utility/reaction.mdx @@ -3,8 +3,67 @@ id: reaction title: Reaction --- -:::warning +Reaction component is used to display emojis in real-time for a specified amount of time. You can utilise this functionality, for example, to notify other participants that you want to speak by "raising hand". Our default sorting algorithm will push participants with raised hand to the top of the list for better visibility. Learn more about reaction events and their customization in the [Reactions & Custom Events guide](../../../guides/reactions-and-custom-events) and see how sorting works in the [Participant Sorting guide](../../../guides/sorting-api). -TODO: write about https://github.com/GetStream/stream-video-js/blob/main/packages/react-sdk/src/components/Reaction/Reaction.tsx +The SDK comes with the `defaultEmojiReactionMap` which consists of three reactions: -::: +- `:like:` (renders 👍) +- `:raise-hand:` (renders ✋) +- `:fireworks:`: (renders 🎉) + +You can extend `Reaction` component with your custom map if you need to through `emojiReactionMap` property. + +![Reaction component preview](../../assets/03-ui-components/reaction.png) + +## General usage + +Our `DefaultParticipantViewUI` already comes with the `Reaction` component built in but if you're building your custom `ParticipantViewUI` here's how you'd incorporate the `Reaction` component into your UI: + +```tsx +import { + Reaction, + useParticipantViewContext, + defaultEmojiReactionMap, +} from '@stream-io/video-react-sdk'; + +const customEmojiReactionMap = { + ...defaultEmojiReactionMap, + ':lol:': '😂', +}; + +export const CustomParticipantViewUI = () => { + const { participant } = useParticipantViewContext(); + return ( + <> + + {/* your other custom UI elements */} + + ); +}; +``` + +## Final steps + +Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the [ParticipantView customizations guide](../../../ui-cookbook/participant-view-customizations). + +## Props + +### `participant` + +| Type | +| --------------------------------------------------------------------------------------------------------------- | +| [`StreamVideoParticipant`](https://github.com/GetStream/stream-video-js/blob/main/packages/client/src/types.ts) | + +The participant whose reaction the component should display. + +### `hideAfterTimeoutInMs` + +| Type | +| ----------------------- | +| `number` \| `undefined` | + +Timeout in miliseconds after which the component resets [participant reaction state](../../../guides/reactions-and-custom-events/#clearing-reactions). diff --git a/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/03-custom-label.mdx b/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/03-custom-label.mdx index dfeb5c20db..2b7a9b0861 100644 --- a/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/03-custom-label.mdx +++ b/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/03-custom-label.mdx @@ -59,17 +59,17 @@ const ParticipantDetails = () => { export const CustomParticipantViewUI = () => { return ( -
+ <> - {/* other UI components... */} -
+ {/* your other custom UI elements */} + ); }; ``` ## Final steps -Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the aforementioned [participant view customizations guide](../participant-view-customizations). +Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the aforementioned [ParticipantView customizations guide](../participant-view-customizations). ```tsx import { useParticipants } from '@stream-io/video-react-sdk'; @@ -78,12 +78,12 @@ import { CustomParticipantViewUI } from '../ParticipantViewUI'; import { CustomVideoPlaceholder } from '../VideoPlaceholder'; export const CustomCallLayout = () => { - const otherParticipants = useParticipants(); + const participants = useParticipants(); return (
- {/* other UI components */} - {otherParticipants.map((participant) => ( + {/* your other custom UI elements */} + {participants.map((participant) => (
{ return ( <> - {/* other UI components... */} + {/* your other custom UI elements */} ); }; @@ -64,4 +64,4 @@ const CustomParticipantViewUI = () => { ## Final steps -Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the aforementioned [participant view customizations guide](../../ui-cookbook/participant-view-customizations). +Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the aforementioned [ParticipantView customizations guide](../../ui-cookbook/participant-view-customizations). diff --git a/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/12-connection-unstable.mdx b/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/12-connection-unstable.mdx index ffc1a27af2..8a910b85de 100644 --- a/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/12-connection-unstable.mdx +++ b/packages/react-sdk/docusaurus/docs/React/06-ui-cookbook/12-connection-unstable.mdx @@ -29,17 +29,17 @@ const PoorConnectionNotification = () => { export const CustomParticipantViewUI = () => { return ( -
+ <> - {/* other UI components... */} -
+ {/* your other custom UI elements */} + ); }; ``` ## Final steps -Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the [participant view customizations guide](../participant-view-customizations). +Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the [ParticipantView customizations guide](../participant-view-customizations). ```tsx import { useParticipants } from '@stream-io/video-react-sdk'; @@ -52,7 +52,7 @@ export const CustomCallLayout = () => { return (
- {/* other UI components */} + {/* your other custom UI elements */} {otherParticipants.map((participant) => (
{ ## Final steps -Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the [participant view customizations guide](../../ui-cookbook/participant-view-customizations). +Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the [ParticipantView customizations guide](../../ui-cookbook/participant-view-customizations). diff --git a/packages/react-sdk/docusaurus/docs/React/10-advanced/12-picture-in-picture.mdx b/packages/react-sdk/docusaurus/docs/React/10-advanced/12-picture-in-picture.mdx index a10bddedc4..d19f5903cc 100644 --- a/packages/react-sdk/docusaurus/docs/React/10-advanced/12-picture-in-picture.mdx +++ b/packages/react-sdk/docusaurus/docs/React/10-advanced/12-picture-in-picture.mdx @@ -72,4 +72,4 @@ const CustomParticipantViewUI = () => { ## Final steps -Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the [participant view customizations guide](../../ui-cookbook/participant-view-customizations). +Now we can pass this custom `ParticipantViewUI` component down to our call layout components or directly to `ParticipantView` component in our custom call layout as described in the [ParticipantView customizations guide](../../ui-cookbook/participant-view-customizations). diff --git a/packages/react-sdk/docusaurus/docs/React/assets/03-ui-components/reaction.png b/packages/react-sdk/docusaurus/docs/React/assets/03-ui-components/reaction.png new file mode 100644 index 0000000000..faf9217a04 Binary files /dev/null and b/packages/react-sdk/docusaurus/docs/React/assets/03-ui-components/reaction.png differ diff --git a/packages/react-sdk/src/components/CallControls/ReactionsButton.tsx b/packages/react-sdk/src/components/CallControls/ReactionsButton.tsx index 76cc78da4c..5c74a59a80 100644 --- a/packages/react-sdk/src/components/CallControls/ReactionsButton.tsx +++ b/packages/react-sdk/src/components/CallControls/ReactionsButton.tsx @@ -2,7 +2,7 @@ import { OwnCapability, StreamReaction } from '@stream-io/video-client'; import { Restricted, useCall } from '@stream-io/video-react-bindings'; import { CompositeButton, IconButton } from '../Button'; -import { defaultEmojiReactions } from '../Reaction'; +import { defaultEmojiReactionMap } from '../Reaction'; export const defaultReactions: StreamReaction[] = [ { @@ -66,7 +66,7 @@ export const DefaultReactionsMenu = ({ call?.sendReaction(reaction); }} > - {reaction.emoji_code && defaultEmojiReactions[reaction.emoji_code]} + {reaction.emoji_code && defaultEmojiReactionMap[reaction.emoji_code]} ))}
diff --git a/packages/react-sdk/src/components/Reaction/Reaction.tsx b/packages/react-sdk/src/components/Reaction/Reaction.tsx index b39a3235e0..98362f9fa8 100644 --- a/packages/react-sdk/src/components/Reaction/Reaction.tsx +++ b/packages/react-sdk/src/components/Reaction/Reaction.tsx @@ -1,47 +1,46 @@ -import { useEffect, useState } from 'react'; -import { Call, StreamReaction } from '@stream-io/video-client'; -import clsx from 'clsx'; +import { useEffect } from 'react'; +import { StreamVideoParticipant } from '@stream-io/video-client'; +import { useCall } from '@stream-io/video-react-bindings'; export type ReactionProps = { - reaction: StreamReaction; - sessionId: string; - call: Call; + participant: StreamVideoParticipant; hideAfterTimeoutInMs?: number; + emojiReactionMap?: Record; }; -export const defaultEmojiReactions: Record = { +export const defaultEmojiReactionMap: Record = { ':like:': '👍', ':raise-hand:': '✋', ':fireworks:': '🎉', }; -export const Reaction = (props: ReactionProps) => { - const { reaction, sessionId, call, hideAfterTimeoutInMs = 5500 } = props; - const [isShowing, setIsShowing] = useState(false); +export const Reaction = ({ + participant: { reaction, sessionId }, + hideAfterTimeoutInMs = 5500, + emojiReactionMap = defaultEmojiReactionMap, +}: ReactionProps) => { + const call = useCall(); + useEffect(() => { - let timeoutId: NodeJS.Timeout; - if (reaction) { - setIsShowing(true); - timeoutId = setTimeout(() => { - setIsShowing(false); - call.resetReaction(sessionId); - }, hideAfterTimeoutInMs); - } + if (!call || !reaction) return; + + const timeoutId = setTimeout(() => { + call.resetReaction(sessionId); + }, hideAfterTimeoutInMs); + return () => { clearTimeout(timeoutId); }; }, [call, hideAfterTimeoutInMs, reaction, sessionId]); - const { emoji_code } = reaction; + if (!reaction) return null; + + const { emoji_code: emojiCode } = reaction; + return ( -
+
- {emoji_code && defaultEmojiReactions[emoji_code]} + {emojiCode && emojiReactionMap[emojiCode]}
); diff --git a/packages/react-sdk/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx b/packages/react-sdk/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx index e5cb149d43..858c8dd005 100644 --- a/packages/react-sdk/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +++ b/packages/react-sdk/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx @@ -68,10 +68,9 @@ export const DefaultParticipantViewUI = ({ menuPlacement = 'bottom-end', showMenuButton = true, }: DefaultParticipantViewUIProps) => { - const call = useCall()!; const { participant, participantViewElement, videoMode, videoElement } = useParticipantViewContext(); - const { reaction, sessionId, publishedTracks } = participant; + const { publishedTracks } = participant; const hasScreenShare = publishedTracks.includes( SfuModels.TrackType.SCREEN_SHARE, @@ -104,9 +103,7 @@ export const DefaultParticipantViewUI = ({ /> )} - {reaction && ( - - )} + ); diff --git a/packages/styling/src/Reaction/Reaction-layout.scss b/packages/styling/src/Reaction/Reaction-layout.scss index fd1cf29f86..a7772a96ed 100644 --- a/packages/styling/src/Reaction/Reaction-layout.scss +++ b/packages/styling/src/Reaction/Reaction-layout.scss @@ -2,12 +2,6 @@ position: absolute; right: 0.875rem; bottom: 0.875rem; - opacity: 0; - transition: opacity 0.2s ease-out; - - &.str-video__reaction--visible { - opacity: 1; - } .str-video__reaction__emoji { display: flex;