diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e0d8c94841..37314fb1be 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -64,8 +64,8 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} PUBLISH_FLAG: ${{ github.event.inputs.publishFlag || github.event.client_payload.slash_command.args.unnamed.arg1 || 'alpha' }} - - name: Delay for 2 minutes - run: sleep 120 + - name: Delay for 1 minute + run: sleep 60 - name: Notify slack success if: github.event.inputs.publishFlag == 'latest' && success() diff --git a/packages/roomkit-react/src/Accordion/Accordion.tsx b/packages/roomkit-react/src/Accordion/Accordion.tsx index 2329201935..d7b86ce14d 100644 --- a/packages/roomkit-react/src/Accordion/Accordion.tsx +++ b/packages/roomkit-react/src/Accordion/Accordion.tsx @@ -64,15 +64,15 @@ export const AccordionRoot = StyledAccordion; export const AccordionItem = StyledItem; export const AccordionHeader: React.FC< - PropsWithChildren + PropsWithChildren > = React.forwardRef< HTMLButtonElement, - PropsWithChildren ->(({ children, iconStyles, css, ...props }, forwardedRef) => ( + PropsWithChildren +>(({ children, iconStyles, css, chevronID, ...props }, forwardedRef) => ( {children} - + )); diff --git a/packages/roomkit-react/src/IconButton/IconButton.tsx b/packages/roomkit-react/src/IconButton/IconButton.tsx index c66cc5b0a8..297137cfb6 100644 --- a/packages/roomkit-react/src/IconButton/IconButton.tsx +++ b/packages/roomkit-react/src/IconButton/IconButton.tsx @@ -25,19 +25,14 @@ export const IconButton = styled('button', { '&[disabled]': { opacity: 0.5, cursor: 'not-allowed', + backgroundColor: '$secondary_dim', + color: '$on_primary_high', }, '&:focus': { outline: 'none', }, variants: { active: { - false: { - backgroundColor: '$secondary_dim', - color: '$on_primary_high', - '&:not([disabled]):hover': { - backgroundColor: '$secondary_default', - }, - }, true: { '&:not([disabled]):hover': { backgroundColor: '$on_surface_low', diff --git a/packages/roomkit-react/src/Prebuilt/IconButton.tsx b/packages/roomkit-react/src/Prebuilt/IconButton.tsx index 3694779ad8..e66d9a6330 100644 --- a/packages/roomkit-react/src/Prebuilt/IconButton.tsx +++ b/packages/roomkit-react/src/Prebuilt/IconButton.tsx @@ -7,22 +7,18 @@ const IconButton = styled(BaseIconButton, { border: '1px solid $border_bright', bg: '$background_dim', r: '$1', + '&[disabled]': { + opacity: 0.5, + cursor: 'not-allowed', + backgroundColor: '$secondary_dim', + color: '$on_primary_high', + }, variants: { active: { true: { color: '$on_surface_high', backgroundColor: 'transparent', }, - false: { - border: '1px solid transparent', - color: '$on_primary_high', - }, - }, - disabled: { - true: { - backgroundColor: '$surface_brighter', - color: '$on_surface_low', - }, }, }, }); diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx b/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx index 5ae0033156..8615b3bac4 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx @@ -9,7 +9,7 @@ import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane // @ts-ignore: No implicit Any import { SIDE_PANE_OPTIONS } from '../../common/constants'; -export const ChatToggle = () => { +export const ChatToggle = ({ onClick }: { onClick?: () => void }) => { const countUnreadMessages = useHMSStore(selectUnreadHMSMessagesCount); const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT); const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT); @@ -21,7 +21,7 @@ export const ChatToggle = () => { }} > - + (onClick ? onClick() : toggleChat())} active={!isChatOpen} data-testid="chat_btn"> diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx index d24485c900..0747fcb219 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx @@ -324,12 +324,15 @@ const HandRaisedAccordionParticipantActions = ({ peerId, role }: { peerId: strin peerId, role, }); + if (!shouldShowStageRoleChange) { + return null; + } return ( <> - {shouldShowStageRoleChange && !isInStage && ( + {!isInStage && ( diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/RoleAccordion.tsx b/packages/roomkit-react/src/Prebuilt/components/Footer/RoleAccordion.tsx index ce931ae60c..5bb8bf5c80 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/RoleAccordion.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/RoleAccordion.tsx @@ -93,6 +93,7 @@ export const RoleAccordion = ({ return ( ) : null} - {isHandRaisedAccordion && ( + {isHandRaisedAccordion && canBringToStage && ( <> - {canBringToStage && ( - - )} + + )} diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/WhiteboardToggle.tsx b/packages/roomkit-react/src/Prebuilt/components/Footer/WhiteboardToggle.tsx index a6abde09c3..0cb9efd262 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/WhiteboardToggle.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/WhiteboardToggle.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useWhiteboard } from '@100mslive/react-sdk'; +import { useScreenShare, useWhiteboard } from '@100mslive/react-sdk'; import { PencilDrawIcon } from '@100mslive/react-icons'; import { Tooltip } from '../../..'; // @ts-ignore: No implicit Any @@ -9,14 +9,28 @@ import { ToastManager } from '../Toast/ToastManager'; export const WhiteboardToggle = () => { const { toggle, open, isOwner } = useWhiteboard(); + const { screenSharingPeerId, amIScreenSharing } = useScreenShare(); + const remoteScreenShare = screenSharingPeerId && !amIScreenSharing; + const disabled = remoteScreenShare || (open && !isOwner); + if (!toggle) { return null; } return ( - + { + if (disabled) { + return; + } try { await toggle(); } catch (error) { @@ -24,7 +38,7 @@ export const WhiteboardToggle = () => { } }} active={!open} - disabled={open && !isOwner} + disabled={disabled} data-testid="whiteboard_btn" > diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx index d022f05a23..a673afef4a 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx @@ -9,6 +9,7 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => { size: '100%', position: 'relative', justifyContent: 'center', + transition: 'all 0.3s ease-in-out', '@md': { height: 'auto', '& video': { diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayPauseButton.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayPauseButton.tsx index 2c950ab34b..ef29a128ae 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayPauseButton.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayPauseButton.tsx @@ -9,8 +9,8 @@ export const PlayPauseButton = ({ height = 20, }: { isPaused: boolean; - width: number; - height: number; + width?: number; + height?: number; }) => { const { hlsPlayer } = useHMSPlayerContext(); const onClick = async (event: MouseEvent) => { diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayPauseSeekControls.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayPauseSeekControls.tsx new file mode 100644 index 0000000000..03267dbaca --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayPauseSeekControls.tsx @@ -0,0 +1,158 @@ +import React from 'react'; +import { useMedia } from 'react-use'; +import { BackwardArrowIcon, ForwardArrowIcon } from '@100mslive/react-icons'; +import { Box, Flex } from '../../../Layout'; +import { Text } from '../../../Text'; +import { config } from '../../../Theme'; +import { PlayPauseButton } from './PlayPauseButton'; +import { SeekControl } from './SeekControl'; +import { useIsLandscape } from '../../common/hooks'; + +// desktop buttons +export const PlayPauseSeekControls = ({ + isPaused, + onSeekTo, +}: { + isPaused: boolean; + onSeekTo: (value: number) => void; +}) => { + return ( + <> + { + e.stopPropagation(); + onSeekTo(-10); + }} + title="backward" + > + + + + { + e.stopPropagation(); + onSeekTo(10); + }} + title="forward" + > + + + + ); +}; + +// overlay handlers +export const PlayPauseSeekOverlayControls = ({ + isPaused, + showControls, + hoverControlsVisible, +}: { + isPaused: boolean; + showControls: boolean; + hoverControlsVisible: { + seekBackward: boolean; + seekForward: boolean; + pausePlay: boolean; + }; +}) => { + const isMobile = useMedia(config.media.md); + const isLandscape = useIsLandscape(); + + if (!isMobile && !isLandscape) { + // show desktopOverflow icons + return ( + <> + + + + + + 10 secs + + + + + + + + + + + 10 secs + + + + ); + } + + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/SeekControls.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/SeekControl.tsx similarity index 91% rename from packages/roomkit-react/src/Prebuilt/components/HMSVideo/SeekControls.tsx rename to packages/roomkit-react/src/Prebuilt/components/HMSVideo/SeekControl.tsx index 830ed0a082..20ba919045 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/SeekControls.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/SeekControl.tsx @@ -1,7 +1,7 @@ import React, { MouseEventHandler } from 'react'; import { IconButton, Tooltip } from '../../..'; -export const SeekControls = ({ +export const SeekControl = ({ title, onClick, children, @@ -9,7 +9,7 @@ export const SeekControls = ({ }: { title: string; onClick?: MouseEventHandler; - css: any; + css?: any; children: React.ReactNode; }) => { return ( diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx index c2e637c10a..42f9eaafc4 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx @@ -25,8 +25,12 @@ export const VideoProgress = ({ if (videoEl.buffered.length > 0) { bufferProgress = Math.floor(getPercentage(videoEl.buffered?.end(0), duration)); } - setVideoProgress(isNaN(videoProgress) ? 0 : videoProgress); - setBufferProgress(isNaN(bufferProgress) ? 0 : bufferProgress); + if (!isNaN(videoProgress)) { + setVideoProgress(videoProgress); + } + if (!isNaN(bufferProgress)) { + setBufferProgress(bufferProgress); + } }, [videoEl]); const timeupdateHandler = useCallback(() => { if (!videoEl || seekProgress) { @@ -42,7 +46,7 @@ export const VideoProgress = ({ return function cleanup() { videoEl?.removeEventListener('timeupdate', timeupdateHandler); }; - }, [timeupdateHandler, videoEl]); + }, [setProgress, timeupdateHandler, videoEl]); const onProgress = (progress: number[]) => { const progress1 = Math.floor(getPercentage(progress[0], 100)); diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.ts b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.ts index e85f278b49..2a488a597c 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.ts +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.ts @@ -2,15 +2,13 @@ import { LeftControls, RightControls, VideoControls } from './Controls'; // @ts-ignore import { HMSVideo } from './HMSVideo'; -import { PlayPauseButton } from './PlayPauseButton'; -import { SeekControls } from './SeekControls'; +import { PlayPauseSeekControls, PlayPauseSeekOverlayControls } from './PlayPauseSeekControls'; import { VideoProgress } from './VideoProgress'; import { VideoTime } from './VideoTime'; import { VolumeControl } from './VolumeControl'; export const HMSVideoPlayer = { Root: HMSVideo, - PlayPauseButton: PlayPauseButton, Progress: VideoProgress, Duration: VideoTime, Volume: VolumeControl, @@ -19,5 +17,8 @@ export const HMSVideoPlayer = { Left: LeftControls, Right: RightControls, }, - Seeker: SeekControls, + PlayPauseSeekControls: { + Overlay: PlayPauseSeekOverlayControls, + Button: PlayPauseSeekControls, + }, }; diff --git a/packages/roomkit-react/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx b/packages/roomkit-react/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx index e6e9be3b62..cf36bc6c3f 100644 --- a/packages/roomkit-react/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx @@ -25,9 +25,9 @@ const IconSection = styled(IconButton, { p: '$4', r: '$1', bg: 'transparent', - borderTopRightRadius: 0, + borderTopRightRadius: '0 !important', borderColor: '$border_bright', - borderBottomRightRadius: 0, + borderBottomRightRadius: '0 !important', position: 'relative', '&:not([disabled]):focus-visible': { zIndex: 1, @@ -41,8 +41,8 @@ const IconSection = styled(IconButton, { ...variants, hideOptions: { true: { - borderTopRightRadius: '$1', - borderBottomRightRadius: '$1', + borderTopRightRadius: '$1 !important', + borderBottomRightRadius: '$1 !important', }, }, }, @@ -53,10 +53,10 @@ const OptionsSection = styled(IconButton, { h: '$14', p: '$4 $2', r: '$1', - borderTopLeftRadius: 0, + borderTopLeftRadius: '0 !important', borderColor: '$border_bright', - borderBottomLeftRadius: 0, - borderLeftWidth: 0, + borderBottomLeftRadius: '0 !important', + borderLeftWidth: '0 !important', position: 'relative', '&:not([disabled]):focus-visible': { zIndex: 1, diff --git a/packages/roomkit-react/src/Prebuilt/components/VideoLayouts/GridLayout.tsx b/packages/roomkit-react/src/Prebuilt/components/VideoLayouts/GridLayout.tsx index 6d64429aea..82b1d47186 100644 --- a/packages/roomkit-react/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/VideoLayouts/GridLayout.tsx @@ -5,12 +5,14 @@ import { selectLocalPeerRoleName, selectPeers, selectPeerScreenSharing, + selectWhiteboard, useHMSStore, useHMSVanillaStore, } from '@100mslive/react-sdk'; import { EqualProminence } from './EqualProminence'; import { RoleProminence } from './RoleProminence'; import { ScreenshareLayout } from './ScreenshareLayout'; +import { WhiteboardLayout } from './WhiteboardLayout'; // @ts-ignore: No implicit Any import { usePinnedTrack, useSetAppDataByKey } from '../AppData/useUISettings'; import { VideoTileContext } from '../hooks/useVideoTileLayout'; @@ -40,6 +42,7 @@ export const GridLayout = ({ hide_metadata_on_tile = false, }: GridLayoutProps) => { const peerSharing = useHMSStore(selectPeerScreenSharing); + const whiteboard = useHMSStore(selectWhiteboard); const pinnedTrack = usePinnedTrack(); const peers = useHMSStore(selectPeers); const localPeerRole = useHMSStore(selectLocalPeerRoleName); @@ -53,9 +56,9 @@ export const GridLayout = ({ )) || pinnedTrack; const updatedPeers = useMemo(() => { - // remove screenshare peer from active speaker sorting - if (activeScreensharePeerId) { - return peers.filter(peer => peer.id !== activeScreensharePeerId); + // remove screenshare/whiteboard peer from active speaker sorting + if (activeScreensharePeerId || whiteboard?.open) { + return peers.filter(peer => peer.id !== activeScreensharePeerId || peer.customerUserId !== whiteboard?.owner); } if (isInsetEnabled) { const isLocalPeerPinned = localPeerID === pinnedTrack?.peerId; @@ -67,7 +70,16 @@ export const GridLayout = ({ } } return peers; - }, [isInsetEnabled, activeScreensharePeerId, localPeerRole, localPeerID, prominentRoles, peers, pinnedTrack]); + }, [ + isInsetEnabled, + whiteboard, + activeScreensharePeerId, + localPeerRole, + localPeerID, + prominentRoles, + peers, + pinnedTrack, + ]); const vanillaStore = useHMSVanillaStore(); const [sortedPeers, setSortedPeers] = useState(updatedPeers); const peersSorter = useMemo(() => new PeersSorter(vanillaStore), [vanillaStore]); @@ -104,6 +116,17 @@ export const GridLayout = ({ /> ); + } else if (whiteboard?.open) { + return ( + + + + ); } else if (isRoleProminence) { return ( diff --git a/packages/roomkit-react/src/Prebuilt/components/VideoLayouts/WhiteboardLayout.tsx b/packages/roomkit-react/src/Prebuilt/components/VideoLayouts/WhiteboardLayout.tsx new file mode 100644 index 0000000000..56155fec88 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/VideoLayouts/WhiteboardLayout.tsx @@ -0,0 +1,95 @@ +import React, { useEffect, useMemo } from 'react'; +import { useMedia } from 'react-use'; +import { selectPeerByCondition, selectWhiteboard, useHMSStore, useWhiteboard } from '@100mslive/react-sdk'; +import { Box } from '../../../Layout'; +import { config as cssConfig } from '../../../Theme'; +import { InsetTile } from '../InsetTile'; +import { SecondaryTiles } from '../SecondaryTiles'; +import { LayoutMode } from '../Settings/LayoutSettings'; +import { LayoutProps } from './interface'; +import { ProminenceLayout } from './ProminenceLayout'; +// @ts-ignore: No implicit Any +import { useSetUiSettings } from '../AppData/useUISettings'; +import { UI_SETTINGS } from '../../common/constants'; + +const WhiteboardEmbed = () => { + const isMobile = useMedia(cssConfig.media.md); + const { iframeRef } = useWhiteboard(isMobile); + + return ( + +