{"version":3,"sources":["jsdelivr-header.js","/npm/@stream-io/src/core/components/Audio/Audio.tsx","/npm/@stream-io/src/core/components/Audio/ParticipantsAudio.tsx","/npm/@stream-io/src/core/components/ParticipantView/ParticipantViewContext.tsx","/npm/@stream-io/src/hooks/useFloatingUIPreset.ts","/npm/@stream-io/src/hooks/usePersistedDevicePreferences.ts","/npm/@stream-io/src/hooks/useScrollPosition.ts","/npm/@stream-io/src/hooks/useRequestPermission.ts","/npm/@stream-io/src/hooks/useDeviceList.tsx","/npm/@stream-io/src/components/Menu/MenuToggle.tsx","/npm/@stream-io/src/components/Menu/GenericMenu.tsx","/npm/@stream-io/src/components/Icon/Icon.tsx","/npm/@stream-io/src/core/hooks/usePictureInPictureState.ts","/npm/@stream-io/src/core/components/ParticipantView/ParticipantActionsContextMenu.tsx","/npm/@stream-io/src/utilities/isComponentType.ts","/npm/@stream-io/src/utilities/chunk.ts","/npm/@stream-io/src/utilities/applyElementToRef.ts","/npm/@stream-io/src/core/components/Video/BaseVideo.tsx","/npm/@stream-io/src/core/components/Video/BaseVideoPlaceholder.tsx","/npm/@stream-io/src/core/components/Video/DefaultVideoPlaceholder.tsx","/npm/@stream-io/src/core/components/Video/DefaultPictureInPicturePlaceholder.tsx","/npm/@stream-io/src/core/components/Video/Video.tsx","/npm/@stream-io/src/core/hooks/useTrackElementVisibility.ts","/npm/@stream-io/src/components/Avatar/Avatar.tsx","/npm/@stream-io/src/components/BackgroundFilters/BackgroundFilters.tsx","/npm/@stream-io/src/components/Button/IconButton.tsx","/npm/@stream-io/src/components/Button/CompositeButton.tsx","/npm/@stream-io/src/components/Button/TextButton.tsx","/npm/@stream-io/src/components/CallControls/AcceptCallButton.tsx","/npm/@stream-io/src/components/Notification/Notification.tsx","/npm/@stream-io/src/components/Notification/PermissionNotification.tsx","/npm/@stream-io/src/components/Notification/SpeakingWhileMutedNotification.tsx","/npm/@stream-io/src/components/Notification/RecordingInProgressNotification.tsx","/npm/@stream-io/src/components/LoadingIndicator/LoadingIndicator.tsx","/npm/@stream-io/src/components/Tooltip/Tooltip.tsx","/npm/@stream-io/src/components/Tooltip/hooks/useEnterLeaveHandlers.ts","/npm/@stream-io/src/components/Tooltip/WithTooltip.tsx","/npm/@stream-io/src/components/CallControls/RecordCallButton.tsx","/npm/@stream-io/src/components/Reaction/Reaction.tsx","/npm/@stream-io/src/components/CallControls/ReactionsButton.tsx","/npm/@stream-io/src/utilities/callControlHandler.ts","/npm/@stream-io/src/components/CallControls/ScreenShareButton.tsx","/npm/@stream-io/src/components/DeviceSettings/AudioVolumeIndicator.tsx","/npm/@stream-io/src/components/DropdownSelect/DropdownSelect.tsx","/npm/@stream-io/src/components/DeviceSettings/DeviceSelector.tsx","/npm/@stream-io/src/components/DeviceSettings/SpeakerTest.tsx","/npm/@stream-io/src/components/DeviceSettings/DeviceSelectorAudio.tsx","/npm/@stream-io/src/components/DeviceSettings/DeviceSelectorVideo.tsx","/npm/@stream-io/src/components/DeviceSettings/DeviceSettings.tsx","/npm/@stream-io/src/components/CallControls/ToggleAudioButton.tsx","/npm/@stream-io/src/components/CallControls/ToggleVideoButton.tsx","/npm/@stream-io/src/components/CallControls/CancelCallButton.tsx","/npm/@stream-io/src/components/CallControls/CallControls.tsx","/npm/@stream-io/src/components/CallStats/CallStats.tsx","/npm/@stream-io/src/components/CallControls/CallStatsButton.tsx","/npm/@stream-io/src/components/CallControls/ToggleAudioOutputButton.tsx","/npm/@stream-io/src/components/CallParticipantsList/BlockedUserListing.tsx","/npm/@stream-io/src/components/CallParticipantsList/CallParticipantListHeader.tsx","/npm/@stream-io/src/components/CallParticipantsList/CallParticipantListingItem.tsx","/npm/@stream-io/src/components/CallParticipantsList/CallParticipantListing.tsx","/npm/@stream-io/src/components/CallParticipantsList/EmptyParticipantSearchList.tsx","/npm/@stream-io/src/components/Search/SearchInput.tsx","/npm/@stream-io/src/components/Search/SearchResults.tsx","/npm/@stream-io/src/components/Search/hooks/useSearch.ts","/npm/@stream-io/src/components/CallParticipantsList/CallParticipantsList.tsx","/npm/@stream-io/src/components/CallPreview/CallPreview.tsx","/npm/@stream-io/src/components/CallRecordingList/CallRecordingListHeader.tsx","/npm/@stream-io/src/components/CallRecordingList/CallRecordingListItem.tsx","/npm/@stream-io/src/components/CallRecordingList/EmptyCallRecordingListing.tsx","/npm/@stream-io/src/components/CallRecordingList/LoadingCallRecordingListing.tsx","/npm/@stream-io/src/components/CallRecordingList/CallRecordingList.tsx","/npm/@stream-io/src/components/NoiseCancellation/NoiseCancellationProvider.tsx","/npm/@stream-io/src/components/RingingCall/RingingCallControls.tsx","/npm/@stream-io/src/components/RingingCall/RingingCall.tsx","/npm/@stream-io/src/components/Permissions/PermissionRequests.tsx","/npm/@stream-io/src/components/StreamTheme/StreamTheme.tsx","/npm/@stream-io/src/components/VideoPreview/VideoPreview.tsx","/npm/@stream-io/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx","/npm/@stream-io/src/core/components/ParticipantView/ParticipantView.tsx","/npm/@stream-io/src/core/components/StreamCall/StreamCall.tsx","/npm/@stream-io/src/translations/index.ts","/npm/@stream-io/src/core/components/StreamVideo/StreamVideo.tsx","/npm/@stream-io/src/utilities/filter.ts","/npm/@stream-io/src/core/components/CallLayout/hooks.ts","/npm/@stream-io/src/core/components/CallLayout/LivestreamLayout.tsx","/npm/@stream-io/src/core/components/CallLayout/PaginatedGridLayout.tsx","/npm/@stream-io/src/core/hooks/useCalculateHardLimit.ts","/npm/@stream-io/src/core/components/CallLayout/SpeakerLayout.tsx","/npm/@stream-io/src/core/components/CallLayout/PipLayout.tsx","/npm/@stream-io/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx","/npm/@stream-io/index.ts"],"names":[],"mappings":"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","file":"/npm/@stream-io/video-react-sdk@1.27.0/dist/index.cjs.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@stream-io/video-react-sdk@1.27.0/dist/index.cjs.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import { ComponentPropsWithoutRef, useEffect, useState } from 'react';\nimport {\n  AudioTrackType,\n  StreamVideoParticipant,\n} from '@stream-io/video-client';\nimport { useCall } from '@stream-io/video-react-bindings';\n\nexport type AudioProps = ComponentPropsWithoutRef<'audio'> & {\n  /**\n   * The participant whose audio stream we want to play.\n   */\n  participant: StreamVideoParticipant;\n\n  /**\n   * The type of audio stream to play for the given participant.\n   * The default value is `audioTrack`.\n   */\n  trackType?: AudioTrackType;\n};\n\nexport const Audio = ({\n  participant,\n  trackType = 'audioTrack',\n  ...rest\n}: AudioProps) => {\n  const call = useCall();\n  const [audioElement, setAudioElement] = useState<HTMLAudioElement | null>(\n    null,\n  );\n  const { userId, sessionId } = participant;\n\n  useEffect(() => {\n    if (!call || !audioElement) return;\n    const cleanup = call.bindAudioElement(audioElement, sessionId, trackType);\n    return () => {\n      cleanup?.();\n    };\n  }, [call, sessionId, audioElement, trackType]);\n\n  return (\n    <audio\n      autoPlay\n      {...rest}\n      ref={setAudioElement}\n      data-user-id={userId}\n      data-session-id={sessionId}\n      data-track-type={trackType}\n    />\n  );\n};\n\nAudio.displayName = 'Audio';\n","import { ComponentProps, Fragment } from 'react';\nimport {\n  hasAudio,\n  hasScreenShareAudio,\n  StreamVideoParticipant,\n} from '@stream-io/video-client';\nimport { Audio } from './Audio';\n\nexport type ParticipantsAudioProps = {\n  /**\n   * The participants to play audio for.\n   */\n  participants: StreamVideoParticipant[];\n\n  /**\n   * Props to pass to the underlying `Audio` components.\n   */\n  audioProps?: ComponentProps<typeof Audio>;\n};\n\nexport const ParticipantsAudio = (props: ParticipantsAudioProps) => {\n  const { participants, audioProps } = props;\n  return (\n    <>\n      {participants.map((participant) => {\n        if (participant.isLocalParticipant) return null;\n        const { audioStream, screenShareAudioStream, sessionId } = participant;\n\n        const hasAudioTrack = hasAudio(participant);\n        const audioTrackElement = hasAudioTrack && audioStream && (\n          <Audio\n            {...audioProps}\n            trackType=\"audioTrack\"\n            participant={participant}\n          />\n        );\n\n        const hasScreenShareAudioTrack = hasScreenShareAudio(participant);\n        const screenShareAudioTrackElement = hasScreenShareAudioTrack &&\n          screenShareAudioStream && (\n            <Audio\n              {...audioProps}\n              trackType=\"screenShareAudioTrack\"\n              participant={participant}\n            />\n          );\n\n        return (\n          <Fragment key={sessionId}>\n            {audioTrackElement}\n            {screenShareAudioTrackElement}\n          </Fragment>\n        );\n      })}\n    </>\n  );\n};\n\nParticipantsAudio.displayName = 'ParticipantsAudio';\n","import { createContext, useContext } from 'react';\nimport { ParticipantViewProps } from './ParticipantView';\n\nexport type ParticipantViewContextValue = Required<\n  Pick<ParticipantViewProps, 'participant' | 'trackType'>\n> & {\n  participantViewElement?: HTMLDivElement | null;\n  videoElement?: HTMLVideoElement | null;\n  videoPlaceholderElement?: HTMLDivElement | null;\n};\n\nexport const ParticipantViewContext = createContext<\n  ParticipantViewContextValue | undefined\n>(undefined);\n\nexport const useParticipantViewContext = () =>\n  useContext(ParticipantViewContext) as ParticipantViewContextValue;\n","import { useEffect } from 'react';\nimport type { UseFloatingOptions } from '@floating-ui/react';\nimport {\n  autoUpdate,\n  flip,\n  offset,\n  shift,\n  size,\n  useFloating,\n} from '@floating-ui/react';\n\nexport const useFloatingUIPreset = ({\n  middleware = [],\n  placement,\n  strategy,\n  offset: offsetInPx = 10,\n}: Pick<UseFloatingOptions, 'placement' | 'strategy' | 'middleware'> & {\n  offset?: number;\n}) => {\n  const {\n    refs,\n    x,\n    y,\n    update,\n    elements: { domReference, floating },\n    context,\n  } = useFloating({\n    placement,\n    strategy,\n    middleware: [\n      offset(offsetInPx),\n      shift(),\n      flip(),\n      size({\n        padding: 10,\n        apply: ({ availableHeight, elements }) => {\n          Object.assign(elements.floating.style, {\n            maxHeight: `${availableHeight}px`,\n          });\n        },\n      }),\n      ...middleware,\n    ],\n  });\n\n  // handle window resizing\n  useEffect(() => {\n    if (!domReference || !floating) return;\n\n    const cleanup = autoUpdate(domReference, floating, update);\n\n    return () => cleanup();\n  }, [domReference, floating, update]);\n\n  return { refs, x, y, domReference, floating, strategy, context };\n};\n","import { useEffect, useState } from 'react';\nimport { CallingState, InputDeviceStatus } from '@stream-io/video-client';\nimport { useCallStateHooks } from '@stream-io/video-react-bindings';\n\nexport type LocalDevicePreference = {\n  selectedDeviceId: string;\n  selectedDeviceLabel: string;\n  muted?: boolean;\n};\n\nexport type LocalDevicePreferences = {\n  // Array is preference history with latest preferences first.\n  // Single preference still acceptable for backwards compatibility.\n  [type in DeviceKey]?: LocalDevicePreference | LocalDevicePreference[];\n};\n\ntype DeviceKey = 'microphone' | 'camera' | 'speaker';\n\ntype DeviceState<K extends DeviceKey> = {\n  [ManagerKey in K]: DeviceManagerLike;\n} & {\n  isMute?: boolean;\n  devices: MediaDeviceInfo[];\n  selectedDevice: string | undefined;\n};\n\ninterface DeviceManagerLike {\n  state: { selectedDevice: string | undefined; status?: InputDeviceStatus };\n  select: (deviceId: string) => Promise<void> | void;\n  enable?: () => Promise<void>;\n  disable?: () => Promise<void>;\n}\n\nconst defaultDevice = 'default';\n\n/**\n * This hook will apply and persist the device preferences from local storage.\n *\n * @param key the key to use for local storage.\n */\nexport const usePersistedDevicePreferences = (\n  key: string = '@stream-io/device-preferences',\n): void => {\n  const {\n    useCallSettings,\n    useCallCallingState,\n    useMicrophoneState,\n    useCameraState,\n    useSpeakerState,\n  } = useCallStateHooks();\n  const settings = useCallSettings();\n  const callingState = useCallCallingState();\n\n  const microphoneState: DeviceState<'microphone'> = useMicrophoneState();\n  const cameraState: DeviceState<'camera'> = useCameraState();\n  const speakerState: DeviceState<'speaker'> = useSpeakerState();\n\n  const [applyingState, setApplyingState] = useState<\n    'idle' | 'applying' | 'applied'\n  >('idle');\n\n  // when the camera is disabled on call type level, we should discard\n  // any stored camera preferences.\n  const cameraDevices = settings?.video?.enabled ? cameraState.devices : false;\n  useEffect(\n    function apply() {\n      if (\n        callingState === CallingState.LEFT ||\n        microphoneState.devices.length === 0 ||\n        (Array.isArray(cameraDevices) && cameraDevices.length === 0) ||\n        speakerState.devices.length === 0 ||\n        !settings ||\n        applyingState !== 'idle'\n      ) {\n        return;\n      }\n\n      setApplyingState('applying');\n\n      (async () => {\n        const { audio, video } = settings;\n        for (const [deviceKey, state, defaultMuted, enabledInCallType] of [\n          ['microphone', microphoneState, !audio.mic_default_on, true],\n          ['camera', cameraState, !video.camera_default_on, video.enabled],\n          ['speaker', speakerState, false, true],\n        ] as const) {\n          const preferences = parseLocalDevicePreferences(key);\n          const preference = preferences[deviceKey];\n          const manager = (\n            state as DeviceState<'camera' | 'microphone' | 'speaker'>\n          )[deviceKey];\n\n          const applyPromise = preference\n            ? applyLocalDevicePreference(\n                manager,\n                [preference].flat(),\n                deviceKey === 'camera' ? cameraDevices || [] : state.devices,\n                enabledInCallType,\n              )\n            : applyMutedState(manager, defaultMuted, enabledInCallType);\n\n          await applyPromise.catch((err) => {\n            console.warn(\n              `Failed to apply ${deviceKey} device preferences`,\n              err,\n            );\n          });\n        }\n      })().finally(() =>\n        setApplyingState((state) => (state === 'applying' ? 'applied' : state)),\n      );\n    },\n    [\n      applyingState,\n      callingState,\n      cameraState,\n      cameraDevices,\n      key,\n      microphoneState,\n      microphoneState.devices,\n      settings,\n      speakerState,\n      speakerState.devices,\n    ],\n  );\n\n  useEffect(\n    function persist() {\n      if (callingState === CallingState.LEFT || applyingState !== 'applied') {\n        return;\n      }\n\n      for (const [deviceKey, devices, selectedDevice, isMute] of [\n        [\n          'camera',\n          cameraDevices || [],\n          cameraState.selectedDevice,\n          cameraState.isMute,\n        ],\n        [\n          'microphone',\n          microphoneState.devices,\n          microphoneState.selectedDevice,\n          microphoneState.isMute,\n        ],\n        [\n          'speaker',\n          speakerState.devices,\n          speakerState.selectedDevice,\n          speakerState.isMute,\n        ],\n      ] as const) {\n        try {\n          patchLocalDevicePreference(key, deviceKey, {\n            devices,\n            selectedDevice,\n            isMute,\n          });\n        } catch (err) {\n          console.warn(`Failed to save ${deviceKey} device preferences`, err);\n        }\n      }\n    },\n    [\n      applyingState,\n      callingState,\n      cameraDevices,\n      cameraState.isMute,\n      cameraState.selectedDevice,\n      key,\n      microphoneState.devices,\n      microphoneState.isMute,\n      microphoneState.selectedDevice,\n      speakerState.devices,\n      speakerState.isMute,\n      speakerState.selectedDevice,\n    ],\n  );\n};\n\n// const usePersistedDevicePreference = <K extends DeviceKey>(\n//   key: string,\n//   deviceKey: K,\n//   state: DeviceState<K>,\n//   defaultMuted?: boolean,\n// ): void => {\n//   const { useCallCallingState } = useCallStateHooks();\n//   const callingState = useCallCallingState();\n//   const [applyingState, setApplyingState] = useState<\n//     'idle' | 'applying' | 'applied'\n//   >('idle');\n//   const manager = state[deviceKey];\n\n//   useEffect(\n//     function apply() {\n//       if (\n//         callingState === CallingState.LEFT ||\n//         !state.devices?.length ||\n//         typeof defaultMuted !== 'boolean' ||\n//         applyingState !== 'idle'\n//       ) {\n//         return;\n//       }\n\n//       const preferences = parseLocalDevicePreferences(key);\n//       const preference = preferences[deviceKey];\n\n//       setApplyingState('applying');\n\n//       if (!manager.state.selectedDevice) {\n//         const applyPromise = preference\n//           ? applyLocalDevicePreference(\n//               manager,\n//               [preference].flat(),\n//               state.devices,\n//             )\n//           : applyMutedState(manager, defaultMuted);\n\n//         applyPromise\n//           .catch((err) => {\n//             console.warn(\n//               `Failed to apply ${deviceKey} device preferences`,\n//               err,\n//             );\n//           })\n//           .finally(() => setApplyingState('applied'));\n//       } else {\n//         setApplyingState('applied');\n//       }\n//     },\n//     [\n//       applyingState,\n//       callingState,\n//       defaultMuted,\n//       deviceKey,\n//       key,\n//       manager,\n//       state.devices,\n//     ],\n//   );\n\n//   useEffect(\n//     function persist() {\n//       if (\n//         callingState === CallingState.LEFT ||\n//         !state.devices?.length ||\n//         applyingState !== 'applied'\n//       ) {\n//         return;\n//       }\n\n//       try {\n//         patchLocalDevicePreference(key, deviceKey, {\n//           devices: state.devices,\n//           selectedDevice: state.selectedDevice,\n//           isMute: state.isMute,\n//         });\n//       } catch (err) {\n//         console.warn(`Failed to save ${deviceKey} device preferences`, err);\n//       }\n//     },\n//     [\n//       applyingState,\n//       callingState,\n//       deviceKey,\n//       key,\n//       state.devices,\n//       state.isMute,\n//       state.selectedDevice,\n//     ],\n//   );\n// };\n\nconst parseLocalDevicePreferences = (key: string): LocalDevicePreferences => {\n  const preferencesStr = window.localStorage.getItem(key);\n  let preferences: LocalDevicePreferences = {};\n\n  if (preferencesStr) {\n    try {\n      preferences = JSON.parse(preferencesStr);\n\n      if (Object.hasOwn(preferences, 'mic')) {\n        // for backwards compatibility\n        preferences.microphone = (\n          preferences as { mic: LocalDevicePreference }\n        ).mic;\n      }\n    } catch {\n      /* assume preferences are empty */\n    }\n  }\n\n  return preferences;\n};\n\nconst patchLocalDevicePreference = (\n  key: string,\n  deviceKey: DeviceKey,\n  state: Pick<DeviceState<never>, 'devices' | 'selectedDevice' | 'isMute'>,\n): void => {\n  const preferences = parseLocalDevicePreferences(key);\n  const nextPreference = getSelectedDevicePreference(\n    state.devices,\n    state.selectedDevice,\n  );\n  const preferenceHistory = [preferences[deviceKey] ?? []]\n    .flat()\n    .filter(\n      (p) =>\n        p.selectedDeviceId !== nextPreference.selectedDeviceId &&\n        (p.selectedDeviceLabel === '' ||\n          p.selectedDeviceLabel !== nextPreference.selectedDeviceLabel),\n    );\n\n  window.localStorage.setItem(\n    key,\n    JSON.stringify({\n      ...preferences,\n      mic: undefined, // for backwards compatibility\n      [deviceKey]: [\n        {\n          ...nextPreference,\n          muted: state.isMute,\n        } satisfies LocalDevicePreference,\n        ...preferenceHistory,\n      ].slice(0, 3),\n    }),\n  );\n};\n\nconst applyLocalDevicePreference = async (\n  manager: DeviceManagerLike,\n  preference: LocalDevicePreference[],\n  devices: MediaDeviceInfo[],\n  enabledInCallType: boolean,\n): Promise<void> => {\n  let muted: boolean | undefined;\n\n  for (const p of preference) {\n    muted ??= p.muted;\n\n    if (p.selectedDeviceId === defaultDevice) {\n      break;\n    }\n\n    const device =\n      devices.find((d) => d.deviceId === p.selectedDeviceId) ??\n      devices.find((d) => d.label === p.selectedDeviceLabel);\n\n    if (device) {\n      if (!manager.state.selectedDevice) {\n        await manager.select(device.deviceId);\n      }\n\n      muted = p.muted;\n      break;\n    }\n  }\n\n  if (typeof muted === 'boolean') {\n    await applyMutedState(manager, muted, enabledInCallType);\n  }\n};\n\nconst applyMutedState = async (\n  manager: DeviceManagerLike,\n  muted: boolean,\n  enabledInCallType: boolean,\n) => {\n  if (enabledInCallType && !manager.state.status) {\n    await manager[muted ? 'disable' : 'enable']?.();\n  }\n};\n\nconst getSelectedDevicePreference = (\n  devices: MediaDeviceInfo[],\n  selectedDevice: string | undefined,\n): Pick<LocalDevicePreference, 'selectedDeviceId' | 'selectedDeviceLabel'> => ({\n  selectedDeviceId: selectedDevice || defaultDevice,\n  selectedDeviceLabel:\n    devices?.find((d) => d.deviceId === selectedDevice)?.label ?? '',\n});\n","import { useEffect, useState } from 'react';\n\nconst SCROLL_THRESHOLD = 10;\n\n/**\n * Hook which observes element's scroll position and returns text value based on the\n * position of the scrollbar (`top`, `bottom`, `between` and `null` if no scrollbar is available)\n */\nexport const useVerticalScrollPosition = (\n  scrollElement: HTMLElement | null,\n  threshold: number = SCROLL_THRESHOLD,\n) => {\n  const [scrollPosition, setScrollPosition] = useState<\n    'top' | 'bottom' | 'between' | null\n  >(null);\n\n  useEffect(() => {\n    if (!scrollElement) return;\n\n    const scrollHandler = () => {\n      const element = scrollElement;\n\n      const hasVerticalScrollbar = element.scrollHeight > element.clientHeight;\n\n      if (!hasVerticalScrollbar) return setScrollPosition(null);\n\n      const isAtTheTop = element.scrollTop <= threshold;\n      if (isAtTheTop) return setScrollPosition('top');\n\n      const isAtTheBottom =\n        Math.abs(\n          element.scrollHeight - element.scrollTop - element.clientHeight,\n        ) <= threshold;\n\n      if (isAtTheBottom) return setScrollPosition('bottom');\n\n      setScrollPosition('between');\n    };\n\n    const resizeObserver = new ResizeObserver(scrollHandler);\n    resizeObserver.observe(scrollElement);\n\n    scrollElement.addEventListener('scroll', scrollHandler);\n    return () => {\n      scrollElement.removeEventListener('scroll', scrollHandler);\n      resizeObserver.disconnect();\n    };\n  }, [scrollElement, threshold]);\n\n  return scrollPosition;\n};\n\nexport const useHorizontalScrollPosition = (\n  scrollElement: HTMLElement | null,\n  threshold: number = SCROLL_THRESHOLD,\n) => {\n  const [scrollPosition, setScrollPosition] = useState<\n    'start' | 'end' | 'between' | null\n  >(null);\n\n  useEffect(() => {\n    if (!scrollElement) return;\n\n    const scrollHandler = () => {\n      const element = scrollElement;\n\n      const hasHorizontalScrollbar = element.scrollWidth > element.clientWidth;\n\n      if (!hasHorizontalScrollbar) return setScrollPosition(null);\n\n      const isAtTheStart = element.scrollLeft <= threshold;\n      if (isAtTheStart) return setScrollPosition('start');\n\n      const isAtTheEnd =\n        Math.abs(\n          element.scrollWidth - element.scrollLeft - element.clientWidth,\n        ) <= threshold;\n\n      if (isAtTheEnd) return setScrollPosition('end');\n\n      setScrollPosition('between');\n    };\n\n    const resizeObserver = new ResizeObserver(scrollHandler);\n    resizeObserver.observe(scrollElement);\n\n    scrollElement.addEventListener('scroll', scrollHandler);\n    return () => {\n      scrollElement.removeEventListener('scroll', scrollHandler);\n      resizeObserver.disconnect();\n    };\n  }, [scrollElement, threshold]);\n\n  return scrollPosition;\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport { OwnCapability } from '@stream-io/video-client';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\n\nexport const useRequestPermission = (permission: OwnCapability) => {\n  const call = useCall();\n  const { useHasPermissions } = useCallStateHooks();\n  const hasPermission = useHasPermissions(permission);\n  const [isAwaitingPermission, setIsAwaitingPermission] = useState(false); // TODO: load with possibly pending state\n\n  useEffect(() => {\n    const reset = () => setIsAwaitingPermission(false);\n\n    if (hasPermission) reset();\n  }, [hasPermission]);\n\n  const requestPermission = useCallback(async () => {\n    if (hasPermission) return true;\n\n    const canRequestPermission =\n      !!call?.permissionsContext.canRequest(permission);\n    if (isAwaitingPermission || !canRequestPermission) return false;\n\n    setIsAwaitingPermission(true);\n\n    try {\n      await call?.requestPermissions({\n        permissions: [permission],\n      });\n    } catch (error) {\n      setIsAwaitingPermission(false);\n      throw new Error(`requestPermission failed: ${error}`);\n    }\n\n    return false;\n  }, [call, hasPermission, isAwaitingPermission, permission]);\n\n  return {\n    requestPermission,\n    hasPermission,\n    canRequestPermission: !!call?.permissionsContext.canRequest(permission),\n    isAwaitingPermission,\n  };\n};\n","import { useI18n } from '@stream-io/video-react-bindings';\nimport { useMemo } from 'react';\n\nexport interface DeviceListItem {\n  deviceId: string;\n  label: string;\n  isSelected: boolean;\n}\n\n/**\n * Utility hook that helps render a list of devices or implement a device selector.\n * Compared to someting like `useCameraState().devices`, it has some handy features:\n * 1. Adds the \"Default\" device to the list if applicable (either the user did not\n * select a device, or a previously selected device is no longer available).\n * 2. Maps the device list to a format more suitable for rendering.\n */\nexport function useDeviceList(\n  devices: MediaDeviceInfo[],\n  selectedDeviceId: string | undefined,\n): {\n  deviceList: DeviceListItem[];\n  selectedDeviceInfo: DeviceListItem;\n  selectedIndex: number;\n} {\n  const { t } = useI18n();\n\n  return useMemo(() => {\n    let selectedDeviceInfo: DeviceListItem | null = null;\n    let selectedIndex: number | null = null;\n\n    const deviceList: DeviceListItem[] = devices.map((d, i) => {\n      const isSelected = d.deviceId === selectedDeviceId;\n      const device = { deviceId: d.deviceId, label: d.label, isSelected };\n\n      if (isSelected) {\n        selectedDeviceInfo = device;\n        selectedIndex = i;\n      }\n\n      return device;\n    });\n\n    if (selectedDeviceInfo === null || selectedIndex === null) {\n      const defaultDevice = {\n        deviceId: 'default',\n        label: t('Default'),\n        isSelected: true,\n      };\n\n      selectedDeviceInfo = defaultDevice;\n      selectedIndex = 0;\n      deviceList.unshift(defaultDevice);\n    }\n\n    return { deviceList, selectedDeviceInfo, selectedIndex };\n  }, [devices, selectedDeviceId, t]);\n}\n","import {\n  ComponentType,\n  createContext,\n  PropsWithChildren,\n  RefAttributes,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport {\n  FloatingOverlay,\n  FloatingPortal,\n  Placement,\n  Strategy,\n  UseFloatingReturn,\n} from '@floating-ui/react';\n\nimport { useFloatingUIPreset } from '../../hooks';\n\nexport type ToggleMenuButtonProps<E extends HTMLElement = HTMLButtonElement> = {\n  menuShown: boolean;\n} & RefAttributes<E>;\n\nexport enum MenuVisualType {\n  PORTAL = 'portal',\n  MENU = 'menu',\n}\n\nexport type MenuToggleProps<E extends HTMLElement> = PropsWithChildren<{\n  ToggleButton: ComponentType<ToggleMenuButtonProps<E>>;\n  placement?: Placement;\n  strategy?: Strategy;\n  offset?: number;\n  visualType?: MenuVisualType;\n  onToggle?: (menuShown: boolean) => void;\n}>;\n\nexport type MenuContextValue = {\n  close?: () => void;\n};\n\n/**\n * Used to provide utility APIs to the components rendered inside the portal.\n */\nconst MenuContext = createContext<MenuContextValue>({});\n\n/**\n * Access to the closes MenuContext.\n */\nexport const useMenuContext = (): MenuContextValue => {\n  return useContext(MenuContext);\n};\n\nconst MenuPortal = ({\n  children,\n  refs,\n}: PropsWithChildren<{\n  refs: UseFloatingReturn['refs'];\n}>) => {\n  const portalId = useMemo(\n    () => `str-video-portal-${Math.random().toString(36).substring(2, 9)}`,\n    [],\n  );\n\n  return (\n    <>\n      <div id={portalId} className=\"str-video__portal\" />\n      <FloatingOverlay>\n        <FloatingPortal id={portalId}>\n          <div className=\"str-video__portal-content\" ref={refs.setFloating}>\n            {children}\n          </div>\n        </FloatingPortal>\n      </FloatingOverlay>\n    </>\n  );\n};\n\nexport const MenuToggle = <E extends HTMLElement>({\n  ToggleButton,\n  placement = 'top-start',\n  strategy = 'absolute',\n  offset,\n  visualType = MenuVisualType.MENU,\n  children,\n  onToggle,\n}: MenuToggleProps<E>) => {\n  const [menuShown, setMenuShown] = useState(false);\n  const toggleHandler = useRef(onToggle);\n  toggleHandler.current = onToggle;\n\n  const { floating, domReference, refs, x, y } = useFloatingUIPreset({\n    placement,\n    strategy,\n    offset,\n  });\n\n  useEffect(() => {\n    const parentDocument = domReference?.ownerDocument;\n\n    const handleClick = (event: MouseEvent) => {\n      if (!floating && domReference?.contains(event.target as Node)) {\n        setMenuShown(true);\n        toggleHandler.current?.(true);\n      } else if (floating && !floating?.contains(event.target as Node)) {\n        setMenuShown(false);\n        toggleHandler.current?.(false);\n      }\n    };\n\n    const handleKeyDown = (event: KeyboardEvent) => {\n      if (\n        event.key && // key can be undefined in some browsers\n        event.key.toLowerCase() === 'escape' &&\n        !event.altKey &&\n        !event.ctrlKey\n      ) {\n        setMenuShown(false);\n        toggleHandler.current?.(false);\n      }\n    };\n    parentDocument?.addEventListener('click', handleClick, { capture: true });\n    parentDocument?.addEventListener('keydown', handleKeyDown);\n    return () => {\n      parentDocument?.removeEventListener('click', handleClick, {\n        capture: true,\n      });\n      parentDocument?.removeEventListener('keydown', handleKeyDown);\n    };\n  }, [floating, domReference]);\n\n  return (\n    <>\n      {menuShown && (\n        <MenuContext.Provider value={{ close: () => setMenuShown(false) }}>\n          {visualType === MenuVisualType.PORTAL ? (\n            <MenuPortal refs={refs} children={children} />\n          ) : visualType === MenuVisualType.MENU ? (\n            <div\n              className=\"str-video__menu-container\"\n              ref={refs.setFloating}\n              style={{\n                position: strategy,\n                top: y ?? 0,\n                left: x ?? 0,\n                overflowY: 'auto',\n              }}\n              role=\"menu\"\n              children={children}\n            />\n          ) : null}\n        </MenuContext.Provider>\n      )}\n      <ToggleButton menuShown={menuShown} ref={refs.setReference} />\n    </>\n  );\n};\n","import { ComponentProps, MouseEvent, PropsWithChildren, useRef } from 'react';\n\nexport const GenericMenu = ({\n  children,\n  onItemClick,\n}: PropsWithChildren<{\n  onItemClick?: (e: MouseEvent) => void;\n}>) => {\n  const ref = useRef<HTMLUListElement>(null);\n  return (\n    <ul\n      className=\"str-video__generic-menu\"\n      ref={ref}\n      onClick={(e) => {\n        if (\n          onItemClick &&\n          e.target !== ref.current &&\n          ref.current?.contains(e.target as Node)\n        ) {\n          onItemClick(e);\n        }\n      }}\n    >\n      {children}\n    </ul>\n  );\n};\n\nexport const GenericMenuButtonItem = ({\n  children,\n  ...rest\n}: Omit<ComponentProps<'button'>, 'ref'>) => {\n  return (\n    <li className=\"str-video__generic-menu--item\">\n      <button {...rest}>{children}</button>\n    </li>\n  );\n};\n","import clsx from 'clsx';\n\nexport type IconProps = {\n  icon: string;\n  className?: string;\n};\n\nexport const Icon = ({ className, icon }: IconProps) => (\n  <span\n    className={clsx(\n      'str-video__icon',\n      icon && `str-video__icon--${icon}`,\n      className,\n    )}\n  />\n);\n","import { useEffect, useState } from 'react';\n\nexport function usePictureInPictureState(videoElement?: HTMLVideoElement) {\n  const [isPiP, setIsPiP] = useState(\n    document.pictureInPictureElement === videoElement,\n  );\n\n  if (!videoElement && isPiP) setIsPiP(false);\n\n  useEffect(() => {\n    if (!videoElement) return;\n\n    const handlePiP = () => {\n      setIsPiP(document.pictureInPictureElement === videoElement);\n    };\n\n    videoElement.addEventListener('enterpictureinpicture', handlePiP);\n    videoElement.addEventListener('leavepictureinpicture', handlePiP);\n\n    return () => {\n      videoElement.removeEventListener('enterpictureinpicture', handlePiP);\n      videoElement.removeEventListener('leavepictureinpicture', handlePiP);\n    };\n  }, [videoElement]);\n\n  return isPiP;\n}\n","import { useEffect, useState } from 'react';\nimport { Restricted, useCall, useI18n } from '@stream-io/video-react-bindings';\nimport {\n  hasAudio,\n  hasScreenShare,\n  hasScreenShareAudio,\n  hasVideo,\n  OwnCapability,\n} from '@stream-io/video-client';\nimport { useParticipantViewContext } from './ParticipantViewContext';\nimport {\n  GenericMenu,\n  GenericMenuButtonItem,\n  useMenuContext,\n} from '../../../components/Menu';\nimport { Icon } from '../../../components/Icon';\nimport { usePictureInPictureState } from '../../hooks/usePictureInPictureState';\n\nexport const ParticipantActionsContextMenu = () => {\n  const { participant, participantViewElement, videoElement } =\n    useParticipantViewContext();\n  const [fullscreenModeOn, setFullscreenModeOn] = useState(\n    !!document.fullscreenElement,\n  );\n  const call = useCall();\n  const isPiP = usePictureInPictureState(videoElement ?? undefined);\n  const { t } = useI18n();\n\n  const { pin, sessionId, userId } = participant;\n\n  const hasAudioTrack = hasAudio(participant);\n  const hasVideoTrack = hasVideo(participant);\n  const hasScreenShareTrack = hasScreenShare(participant);\n  const hasScreenShareAudioTrack = hasScreenShareAudio(participant);\n\n  const blockUser = () => call?.blockUser(userId);\n  const kickUser = () => call?.kickUser({ user_id: userId });\n  const muteAudio = () => call?.muteUser(userId, 'audio');\n  const muteVideo = () => call?.muteUser(userId, 'video');\n  const muteScreenShare = () => call?.muteUser(userId, 'screenshare');\n  const muteScreenShareAudio = () =>\n    call?.muteUser(userId, 'screenshare_audio');\n\n  const grantPermission = (permission: string) => () => {\n    call?.updateUserPermissions({\n      user_id: userId,\n      grant_permissions: [permission],\n    });\n  };\n\n  const revokePermission = (permission: string) => () => {\n    call?.updateUserPermissions({\n      user_id: userId,\n      revoke_permissions: [permission],\n    });\n  };\n\n  const toggleParticipantPin = () => {\n    if (pin) {\n      call?.unpin(sessionId);\n    } else {\n      call?.pin(sessionId);\n    }\n  };\n\n  const pinForEveryone = () => {\n    call\n      ?.pinForEveryone({ user_id: userId, session_id: sessionId })\n      .catch((err) => {\n        console.error(`Failed to pin participant ${userId}`, err);\n      });\n  };\n\n  const unpinForEveryone = () => {\n    call\n      ?.unpinForEveryone({ user_id: userId, session_id: sessionId })\n      .catch((err) => {\n        console.error(`Failed to unpin participant ${userId}`, err);\n      });\n  };\n\n  const toggleFullscreenMode = () => {\n    if (!fullscreenModeOn) {\n      return participantViewElement?.requestFullscreen().catch(console.error);\n    }\n    return document.exitFullscreen().catch(console.error);\n  };\n\n  useEffect(() => {\n    // handles the case when fullscreen mode is toggled externally,\n    // e.g., by pressing ESC key or some other keyboard shortcut\n    const handleFullscreenChange = () => {\n      setFullscreenModeOn(!!document.fullscreenElement);\n    };\n    document.addEventListener('fullscreenchange', handleFullscreenChange);\n    return () => {\n      document.removeEventListener('fullscreenchange', handleFullscreenChange);\n    };\n  }, []);\n\n  const togglePictureInPicture = () => {\n    if (videoElement && !isPiP) {\n      return videoElement\n        .requestPictureInPicture()\n        .catch(console.error) as Promise<void>;\n    }\n\n    return document.exitPictureInPicture().catch(console.error);\n  };\n\n  const { close } = useMenuContext() || {};\n  return (\n    <GenericMenu onItemClick={close}>\n      <GenericMenuButtonItem\n        onClick={toggleParticipantPin}\n        disabled={pin && !pin.isLocalPin}\n      >\n        <Icon icon=\"pin\" />\n        {pin ? t('Unpin') : t('Pin')}\n      </GenericMenuButtonItem>\n      <Restricted requiredGrants={[OwnCapability.PIN_FOR_EVERYONE]}>\n        <GenericMenuButtonItem\n          onClick={pinForEveryone}\n          disabled={pin && !pin.isLocalPin}\n        >\n          <Icon icon=\"pin\" />\n          {t('Pin for everyone')}\n        </GenericMenuButtonItem>\n        <GenericMenuButtonItem\n          onClick={unpinForEveryone}\n          disabled={!pin || pin.isLocalPin}\n        >\n          <Icon icon=\"pin\" />\n          {t('Unpin for everyone')}\n        </GenericMenuButtonItem>\n      </Restricted>\n      <Restricted requiredGrants={[OwnCapability.BLOCK_USERS]}>\n        <GenericMenuButtonItem onClick={blockUser}>\n          <Icon icon=\"not-allowed\" />\n          {t('Block')}\n        </GenericMenuButtonItem>\n      </Restricted>\n      <Restricted requiredGrants={[OwnCapability.KICK_USER]}>\n        <GenericMenuButtonItem onClick={kickUser}>\n          <Icon icon=\"kick-user\" />\n          {t('Kick')}\n        </GenericMenuButtonItem>\n      </Restricted>\n      <Restricted requiredGrants={[OwnCapability.MUTE_USERS]}>\n        {hasVideoTrack && (\n          <GenericMenuButtonItem onClick={muteVideo}>\n            <Icon icon=\"camera-off-outline\" />\n            {t('Turn off video')}\n          </GenericMenuButtonItem>\n        )}\n        {hasScreenShareTrack && (\n          <GenericMenuButtonItem onClick={muteScreenShare}>\n            <Icon icon=\"screen-share-off\" />\n            {t('Turn off screen share')}\n          </GenericMenuButtonItem>\n        )}\n        {hasAudioTrack && (\n          <GenericMenuButtonItem onClick={muteAudio}>\n            <Icon icon=\"no-audio\" />\n            {t('Mute audio')}\n          </GenericMenuButtonItem>\n        )}\n        {hasScreenShareAudioTrack && (\n          <GenericMenuButtonItem onClick={muteScreenShareAudio}>\n            <Icon icon=\"no-audio\" />\n            {t('Mute screen share audio')}\n          </GenericMenuButtonItem>\n        )}\n      </Restricted>\n      {participantViewElement &&\n        typeof participantViewElement.requestFullscreen !== 'undefined' && (\n          <GenericMenuButtonItem onClick={toggleFullscreenMode}>\n            {t('{{ direction }} fullscreen', {\n              direction: fullscreenModeOn ? t('Leave') : t('Enter'),\n            })}\n          </GenericMenuButtonItem>\n        )}\n      {videoElement && document.pictureInPictureEnabled && (\n        <GenericMenuButtonItem onClick={togglePictureInPicture}>\n          {t('{{ direction }} picture-in-picture', {\n            direction: isPiP ? t('Leave') : t('Enter'),\n          })}\n        </GenericMenuButtonItem>\n      )}\n      <Restricted requiredGrants={[OwnCapability.UPDATE_CALL_PERMISSIONS]}>\n        <GenericMenuButtonItem\n          onClick={grantPermission(OwnCapability.SEND_AUDIO)}\n        >\n          {t('Allow audio')}\n        </GenericMenuButtonItem>\n        <GenericMenuButtonItem\n          onClick={grantPermission(OwnCapability.SEND_VIDEO)}\n        >\n          {t('Allow video')}\n        </GenericMenuButtonItem>\n        <GenericMenuButtonItem\n          onClick={grantPermission(OwnCapability.SCREENSHARE)}\n        >\n          {t('Allow screen sharing')}\n        </GenericMenuButtonItem>\n\n        <GenericMenuButtonItem\n          onClick={revokePermission(OwnCapability.SEND_AUDIO)}\n        >\n          {t('Disable audio')}\n        </GenericMenuButtonItem>\n        <GenericMenuButtonItem\n          onClick={revokePermission(OwnCapability.SEND_VIDEO)}\n        >\n          {t('Disable video')}\n        </GenericMenuButtonItem>\n        <GenericMenuButtonItem\n          onClick={revokePermission(OwnCapability.SCREENSHARE)}\n        >\n          {t('Disable screen sharing')}\n        </GenericMenuButtonItem>\n      </Restricted>\n    </GenericMenu>\n  );\n};\n","import { ComponentType, isValidElement, ReactElement } from 'react';\n\nexport const isComponentType = <T extends {}>(\n  elementOrComponent?: ComponentType<T> | ReactElement | null,\n): elementOrComponent is ComponentType<T> => {\n  return elementOrComponent === null\n    ? false\n    : !isValidElement(elementOrComponent);\n};\n","export const chunk = <T extends unknown[]>(array: T, size: number) => {\n  const chunkCount = Math.ceil(array.length / size);\n\n  return Array.from(\n    { length: chunkCount },\n    (_, index) => array.slice(size * index, size * index + size) as T,\n  );\n};\n","import type { ForwardedRef } from 'react';\n\nexport const applyElementToRef = <T extends HTMLElement | null>(\n  ref: ForwardedRef<T>,\n  element: T,\n) => {\n  if (!ref) return;\n\n  if (typeof ref === 'function') return ref(element);\n\n  ref.current = element;\n};\n","import { ComponentPropsWithRef, forwardRef, useEffect, useState } from 'react';\nimport { Browsers } from '@stream-io/video-client';\n\nimport { applyElementToRef } from '../../../utilities';\n\nexport type BaseVideoProps = ComponentPropsWithRef<'video'> & {\n  stream?: MediaStream;\n};\n\n/**\n * @description Extends video element with `stream` property\n * (`srcObject`) to reactively handle stream changes\n */\nexport const BaseVideo = forwardRef<HTMLVideoElement, BaseVideoProps>(\n  function BaseVideo({ stream, ...rest }, ref) {\n    const [videoElement, setVideoElement] = useState<HTMLVideoElement | null>(\n      null,\n    );\n\n    useEffect(() => {\n      if (!videoElement || !stream) return;\n      if (stream === videoElement.srcObject) return;\n\n      videoElement.srcObject = stream;\n      if (Browsers.isSafari() || Browsers.isFirefox()) {\n        // Firefox and Safari have some timing issue\n        setTimeout(() => {\n          videoElement.srcObject = stream;\n          videoElement.play().catch((e) => {\n            console.error(`Failed to play stream`, e);\n          });\n        }, 0);\n      }\n\n      return () => {\n        videoElement.pause();\n        videoElement.srcObject = null;\n      };\n    }, [stream, videoElement]);\n\n    return (\n      <video\n        autoPlay\n        playsInline\n        {...rest}\n        ref={(element) => {\n          applyElementToRef(ref, element);\n          setVideoElement(element);\n        }}\n      />\n    );\n  },\n);\n","import { ComponentProps, RefAttributes, forwardRef, useState } from 'react';\nimport type { StreamVideoParticipant } from '@stream-io/video-client';\n\nexport type BaseVideoPlaceholderProps = {\n  participant: StreamVideoParticipant;\n} & RefAttributes<HTMLDivElement> &\n  ComponentProps<'div'>;\n\nexport const BaseVideoPlaceholder = forwardRef<\n  HTMLDivElement,\n  BaseVideoPlaceholderProps\n>(function DefaultVideoPlaceholder({ participant, style, children }, ref) {\n  const [error, setError] = useState(false);\n  const name = participant.name || participant.userId;\n  return (\n    <div className=\"str-video__video-placeholder\" style={style} ref={ref}>\n      {(!participant.image || error) &&\n        (name ? (\n          <InitialsFallback name={name} />\n        ) : (\n          <div className=\"str-video__video-placeholder__no-video-label\">\n            {children}\n          </div>\n        ))}\n      {participant.image && !error && (\n        <img\n          onError={() => setError(true)}\n          alt={name}\n          className=\"str-video__video-placeholder__avatar\"\n          src={participant.image}\n        />\n      )}\n    </div>\n  );\n});\n\nconst InitialsFallback = (props: { name: string }) => {\n  const { name } = props;\n  const initials = name\n    .split(' ')\n    .slice(0, 2)\n    .map((n) => n[0])\n    .join('');\n  return (\n    <div className=\"str-video__video-placeholder__initials-fallback\">\n      {initials}\n    </div>\n  );\n};\n","import { forwardRef } from 'react';\nimport { useI18n } from '@stream-io/video-react-bindings';\nimport {\n  BaseVideoPlaceholder,\n  type BaseVideoPlaceholderProps,\n} from './BaseVideoPlaceholder';\n\nexport type VideoPlaceholderProps = BaseVideoPlaceholderProps;\n\nexport const DefaultVideoPlaceholder = forwardRef<\n  HTMLDivElement,\n  VideoPlaceholderProps\n>(function DefaultVideoPlaceholder(props, ref) {\n  const { t } = useI18n();\n  return (\n    <BaseVideoPlaceholder ref={ref} {...props}>\n      {t('Video is disabled')}\n    </BaseVideoPlaceholder>\n  );\n});\n","import { forwardRef } from 'react';\nimport { useI18n } from '@stream-io/video-react-bindings';\nimport {\n  BaseVideoPlaceholder,\n  type BaseVideoPlaceholderProps,\n} from './BaseVideoPlaceholder';\n\nexport type PictureInPicturePlaceholderProps = BaseVideoPlaceholderProps;\n\nexport const DefaultPictureInPicturePlaceholder = forwardRef<\n  HTMLDivElement,\n  PictureInPicturePlaceholderProps\n>(function DefaultPictureInPicturePlaceholder(props, ref) {\n  const { t } = useI18n();\n  return (\n    <BaseVideoPlaceholder ref={ref} {...props}>\n      {t('Video is playing in a popup')}\n    </BaseVideoPlaceholder>\n  );\n});\n","import {\n  ComponentPropsWithoutRef,\n  ComponentType,\n  useEffect,\n  useLayoutEffect,\n  useState,\n} from 'react';\nimport {\n  hasPausedTrack,\n  hasScreenShare,\n  hasVideo,\n  StreamVideoParticipant,\n  VideoTrackType,\n  VisibilityState,\n} from '@stream-io/video-client';\nimport clsx from 'clsx';\nimport {\n  DefaultVideoPlaceholder,\n  VideoPlaceholderProps,\n} from './DefaultVideoPlaceholder';\nimport { useCall } from '@stream-io/video-react-bindings';\nimport { usePictureInPictureState } from '../../hooks/usePictureInPictureState';\nimport {\n  DefaultPictureInPicturePlaceholder,\n  PictureInPicturePlaceholderProps,\n} from './DefaultPictureInPicturePlaceholder';\n\nexport type VideoProps = ComponentPropsWithoutRef<'video'> & {\n  /**\n   * Pass false to disable rendering video and render fallback\n   * even if the participant has published video.\n   * @default true\n   */\n  enabled?: boolean;\n  /**\n   * Forces the video to be mirrored or unmirrored. By default, video track\n   * from the local participant is mirrored, and all other videos are not mirrored.\n   */\n  mirror?: boolean;\n  /**\n   * The track type to display.\n   */\n  trackType: VideoTrackType | 'none';\n  /**\n   * The participant represented by this video element.\n   */\n  participant: StreamVideoParticipant;\n  /**\n   * Override the default UI that's visible when a participant turned off their video.\n   * Set it to `null` if you wish to disable the video placeholder.\n   *\n   * @default DefaultVideoPlaceholder\n   */\n  VideoPlaceholder?: ComponentType<VideoPlaceholderProps> | null;\n  /**\n   * Override the default UI that's dispayed in place of the video when it's playing\n   * in picture-in-picture. Set it to `null` if you wish to display the browser's default\n   * placeholder.\n   *\n   * @default DefaultPictureInPicturePlaceholder\n   */\n  PictureInPicturePlaceholder?: ComponentType<PictureInPicturePlaceholderProps> | null;\n  /**\n  /**\n   * An object with setRef functions\n   * meant for exposing some of the internal elements of this component.\n   */\n  refs?: {\n    /**\n     * The video element that's used to play the video stream.\n     * @param element the video element.\n     */\n    setVideoElement?: (element: HTMLVideoElement | null) => void;\n    /**\n     * The video placeholder element that's used when the video stream is not playing.\n     * @param element the video placeholder element.\n     */\n    setVideoPlaceholderElement?: (element: HTMLDivElement | null) => void;\n    setPictureInPicturePlaceholderElement?: (\n      element: HTMLDivElement | null,\n    ) => void;\n  };\n};\n\nexport const Video = ({\n  enabled = true,\n  mirror,\n  trackType,\n  participant,\n  className,\n  VideoPlaceholder = DefaultVideoPlaceholder,\n  PictureInPicturePlaceholder = DefaultPictureInPicturePlaceholder,\n  refs,\n  ...rest\n}: VideoProps) => {\n  const {\n    sessionId,\n    videoStream,\n    screenShareStream,\n    viewportVisibilityState,\n    isLocalParticipant,\n    userId,\n  } = participant;\n\n  const call = useCall();\n  const [videoElement, setVideoElement] = useState<HTMLVideoElement | null>(\n    null,\n  );\n  // start with true, will flip once the video starts playing\n  const [isVideoPaused, setIsVideoPaused] = useState(true);\n  const [isWideMode, setIsWideMode] = useState(true);\n  const isPiP = usePictureInPictureState(videoElement ?? undefined);\n\n  const stream =\n    trackType === 'videoTrack'\n      ? videoStream\n      : trackType === 'screenShareTrack'\n        ? screenShareStream\n        : undefined;\n\n  useLayoutEffect(() => {\n    if (!call || !videoElement || trackType === 'none') return;\n\n    const cleanup = call.bindVideoElement(videoElement, sessionId, trackType);\n\n    return () => {\n      cleanup?.();\n    };\n  }, [call, trackType, sessionId, videoElement]);\n\n  useEffect(() => {\n    if (!stream || !videoElement) return;\n\n    const [track] = stream.getVideoTracks();\n    if (!track) return;\n\n    const handlePlayPause = () => {\n      setIsVideoPaused(videoElement.paused);\n\n      const { width = 0, height = 0 } = track.getSettings();\n      setIsWideMode(width >= height);\n    };\n\n    // playback may have started before we had a chance to\n    // attach the 'play/pause' event listener, so we set the state\n    // here to make sure it's in sync\n    setIsVideoPaused(videoElement.paused);\n\n    videoElement.addEventListener('play', handlePlayPause);\n    videoElement.addEventListener('pause', handlePlayPause);\n    track.addEventListener('unmute', handlePlayPause);\n    return () => {\n      videoElement.removeEventListener('play', handlePlayPause);\n      videoElement.removeEventListener('pause', handlePlayPause);\n      track.removeEventListener('unmute', handlePlayPause);\n\n      // reset the 'pause' state once we unmount the video element\n      setIsVideoPaused(true);\n    };\n  }, [stream, videoElement]);\n\n  if (!call) return null;\n\n  const isPublishingTrack =\n    trackType === 'videoTrack'\n      ? hasVideo(participant)\n      : trackType === 'screenShareTrack'\n        ? hasScreenShare(participant)\n        : false;\n\n  const isInvisible =\n    trackType === 'none' ||\n    viewportVisibilityState?.[trackType] === VisibilityState.INVISIBLE;\n\n  const hasNoVideoOrInvisible =\n    !enabled ||\n    !isPublishingTrack ||\n    isInvisible ||\n    hasPausedTrack(participant, trackType);\n  const mirrorVideo =\n    mirror === undefined\n      ? isLocalParticipant && trackType === 'videoTrack'\n      : mirror;\n  const isScreenShareTrack = trackType === 'screenShareTrack';\n  return (\n    <>\n      {!hasNoVideoOrInvisible && (\n        <video\n          {...rest}\n          className={clsx('str-video__video', className, {\n            'str-video__video--not-playing': isVideoPaused,\n            'str-video__video--tall': !isWideMode,\n            'str-video__video--mirror': mirrorVideo,\n            'str-video__video--screen-share': isScreenShareTrack,\n          })}\n          data-user-id={userId}\n          data-session-id={sessionId}\n          ref={(element) => {\n            setVideoElement(element);\n            refs?.setVideoElement?.(element);\n          }}\n        />\n      )}\n      {isPiP && PictureInPicturePlaceholder && (\n        <PictureInPicturePlaceholder\n          style={{ position: 'absolute' }}\n          participant={participant}\n        />\n      )}\n      {/* TODO: add condition to \"hold\" the placeholder until track unmutes as well */}\n      {(hasNoVideoOrInvisible || isVideoPaused) && VideoPlaceholder && (\n        <VideoPlaceholder\n          style={{ position: 'absolute' }}\n          participant={participant}\n          ref={refs?.setVideoPlaceholderElement}\n        />\n      )}\n    </>\n  );\n};\n\nVideo.displayName = 'Video';\n","import { useEffect } from 'react';\nimport { DynascaleManager, VideoTrackType } from '@stream-io/video-client';\nimport { useCall } from '@stream-io/video-react-bindings';\n\nexport const useTrackElementVisibility = <T extends HTMLElement>({\n  trackedElement,\n  dynascaleManager: propsDynascaleManager,\n  sessionId,\n  trackType,\n}: {\n  trackedElement: T | null;\n  sessionId: string;\n  dynascaleManager?: DynascaleManager;\n  trackType: VideoTrackType | 'none';\n}) => {\n  const call = useCall();\n  const manager = propsDynascaleManager ?? call?.dynascaleManager;\n  useEffect(() => {\n    if (!trackedElement || !manager || !call || trackType === 'none') return;\n    const unobserve = manager.trackElementVisibility(\n      trackedElement,\n      sessionId,\n      trackType,\n    );\n    return () => {\n      unobserve();\n    };\n  }, [trackedElement, manager, call, sessionId, trackType]);\n};\n","import { ComponentProps, CSSProperties, useState } from 'react';\nimport clsx from 'clsx';\n\nexport type AvatarData = {\n  imageSrc?: string;\n  name?: string;\n  style?: CSSProperties & Record<string, string | number>;\n};\n\nexport type AvatarProps = AvatarData & ComponentProps<'img'>;\n\nexport const Avatar = ({\n  imageSrc,\n  name,\n  style,\n  className,\n  ...rest\n}: AvatarProps) => {\n  const [error, setError] = useState(false);\n\n  return (\n    <>\n      {(!imageSrc || error) && name && (\n        <AvatarFallback className={className} style={style} names={[name]} />\n      )}\n      {imageSrc && !error && (\n        <img\n          onError={() => setError(true)}\n          alt=\"avatar\"\n          className={clsx('str-video__avatar', className)}\n          src={imageSrc}\n          style={style}\n          {...rest}\n        />\n      )}\n    </>\n  );\n};\n\ntype AvatarFallbackProps = {\n  names: string[];\n  className?: string;\n  style?: CSSProperties & Record<string, string | number>;\n};\nexport const AvatarFallback = ({\n  className,\n  names,\n  style,\n}: AvatarFallbackProps) => {\n  return (\n    <div\n      className={clsx('str-video__avatar--initials-fallback', className)}\n      style={style}\n    >\n      <div>\n        {names[0][0]}\n        {names[1]?.[0]}\n      </div>\n    </div>\n  );\n};\n","import {\n  createContext,\n  PropsWithChildren,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport { flushSync } from 'react-dom';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\nimport { Call, disposeOfMediaStream } from '@stream-io/video-client';\nimport {\n  BackgroundBlurLevel,\n  BackgroundFilter,\n  createRenderer,\n  isPlatformSupported,\n  isMediaPipePlatformSupported,\n  loadTFLite,\n  loadMediaPipe,\n  PlatformSupportFlags,\n  VirtualBackground,\n  Renderer,\n  TFLite,\n  PerformanceStats,\n} from '@stream-io/video-filters-web';\nimport clsx from 'clsx';\n\n/**\n * Constants for FPS warning calculation.\n * Smooths out quick spikes using an EMA, ignores brief outliers,\n * and uses two thresholds to avoid flickering near the limit.\n */\nconst ALPHA = 0.2;\nconst FPS_WARNING_THRESHOLD_LOWER = 23;\nconst FPS_WARNING_THRESHOLD_UPPER = 25;\nconst DEFAULT_FPS = 30;\nconst DEVIATION_LIMIT = 0.5;\nconst OUTLIER_PERSISTENCE = 5;\n\n/**\n * Configuration for performance metric thresholds.\n */\nexport type BackgroundFiltersPerformanceThresholds = {\n  /**\n   * The lower FPS threshold for triggering a performance warning.\n   * When the EMA FPS falls below this value, a warning is shown.\n   * @default 23\n   */\n  fpsWarningThresholdLower?: number;\n\n  /**\n   * The upper FPS threshold for clearing a performance warning.\n   * When the EMA FPS rises above this value, the warning is cleared.\n   * @default 25\n   */\n  fpsWarningThresholdUpper?: number;\n\n  /**\n   * The default FPS value used as the initial value for the EMA (Exponential Moving Average)\n   * calculation and when stats are unavailable or when resetting the filter.\n   * @default 30\n   */\n  defaultFps?: number;\n};\n\n/**\n * Represents the available background filter processing engines.\n */\nenum FilterEngine {\n  TF,\n  MEDIA_PIPE,\n  NONE,\n}\n\n/**\n * Represents the possible reasons for background filter performance degradation.\n */\nexport enum PerformanceDegradationReason {\n  FRAME_DROP = 'frame-drop',\n  CPU_THROTTLING = 'cpu-throttling',\n}\n\nexport type BackgroundFiltersProps = PlatformSupportFlags & {\n  /**\n   * A list of URLs to use as background images.\n   */\n  backgroundImages?: string[];\n\n  /**\n   * The background filter to apply to the video (by default).\n   * @default undefined no filter applied\n   */\n  backgroundFilter?: BackgroundFilter;\n\n  /**\n   * The URL of the image to use as the background (by default).\n   */\n  backgroundImage?: string;\n\n  /**\n   * The level of blur to apply to the background (by default).\n   * @default 'high'.\n   */\n  backgroundBlurLevel?: BackgroundBlurLevel;\n\n  /**\n   * The base path for the TensorFlow Lite files.\n   * @default 'https://unpkg.com/@stream-io/video-filters-web/mediapipe'.\n   */\n  basePath?: string;\n\n  /**\n   * The path to the TensorFlow Lite WebAssembly file.\n   *\n   * Override this prop to use a custom path to the TensorFlow Lite WebAssembly file\n   * (e.g., if you choose to host it yourself).\n   */\n  tfFilePath?: string;\n\n  /**\n   * The path to the MediaPipe model file.\n   * Override this prop to use a custom path to the MediaPipe model file\n   * (e.g., if you choose to host it yourself).\n   */\n  modelFilePath?: string;\n\n  /**\n   * When true, the filter uses the legacy TensorFlow-based segmentation model.\n   * When false, it uses the default MediaPipe Tasks Vision model.\n   *\n   * Only enable this if you need to mimic the behavior of older SDK versions.\n   */\n  useLegacyFilter?: boolean;\n\n  /**\n   * When a started filter encounters an error, this callback will be executed.\n   * The default behavior (not overridable) is unregistering a failed filter.\n   * Use this callback to display UI error message, disable the corresponding stream,\n   * or to try registering the filter again.\n   */\n  onError?: (error: any) => void;\n\n  /**\n   * Configuration for performance metric thresholds.\n   * Use this to customize when performance warnings are triggered.\n   */\n  performanceThresholds?: BackgroundFiltersPerformanceThresholds;\n};\n\n/**\n * Performance degradation information for background filters.\n *\n * Performance is calculated using an Exponential Moving Average (EMA) of FPS values\n * to smooth out quick spikes and provide stable performance warnings.\n */\nexport type BackgroundFiltersPerformance = {\n  /**\n   * Whether performance is currently degraded.\n   */\n  degraded: boolean;\n  /**\n   * Reasons for performance degradation.\n   */\n  reason?: Array<PerformanceDegradationReason>;\n};\n\nexport type BackgroundFiltersAPI = {\n  /**\n   * Whether the current platform supports the background filters.\n   */\n  isSupported: boolean;\n\n  /**\n   * Indicates whether the background filters engine is loaded and ready.\n   */\n  isReady: boolean;\n\n  /**\n   * Performance information for background filters.\n   */\n  performance: BackgroundFiltersPerformance;\n\n  /**\n   * Disables all background filters applied to the video.\n   */\n  disableBackgroundFilter: () => void;\n\n  /**\n   * Applies a background blur filter to the video.\n   *\n   * @param blurLevel the level of blur to apply to the background.\n   */\n  applyBackgroundBlurFilter: (blurLevel: BackgroundBlurLevel) => void;\n\n  /**\n   * Applies a background image filter to the video.\n   *\n   * @param imageUrl the URL of the image to use as the background.\n   */\n  applyBackgroundImageFilter: (imageUrl: string) => void;\n};\n\n/**\n * The context value for the background filters context.\n */\nexport type BackgroundFiltersContextValue = BackgroundFiltersProps &\n  BackgroundFiltersAPI;\n\n/**\n * The context for the background filters.\n */\nconst BackgroundFiltersContext = createContext<\n  BackgroundFiltersContextValue | undefined\n>(undefined);\n\n/**\n * A hook to access the background filters context API.\n */\nexport const useBackgroundFilters = () => {\n  const context = useContext(BackgroundFiltersContext);\n  if (!context) {\n    throw new Error(\n      'useBackgroundFilters must be used within a BackgroundFiltersProvider',\n    );\n  }\n  return context;\n};\n\n/**\n * Determines which filter engine is available.\n * MEDIA_PIPE is the default unless legacy filters are requested or MediaPipe is unsupported.\n *\n * Returns NONE if neither is supported.\n */\nconst determineEngine = async (\n  useLegacyFilter: boolean | undefined,\n  forceSafariSupport: boolean | undefined,\n  forceMobileSupport: boolean | undefined,\n): Promise<FilterEngine> => {\n  const isTfPlatformSupported = await isPlatformSupported({\n    forceSafariSupport,\n    forceMobileSupport,\n  });\n\n  if (useLegacyFilter) {\n    return isTfPlatformSupported ? FilterEngine.TF : FilterEngine.NONE;\n  }\n\n  const isMediaPipeSupported = await isMediaPipePlatformSupported({\n    forceSafariSupport,\n    forceMobileSupport,\n  });\n\n  return isMediaPipeSupported ? FilterEngine.MEDIA_PIPE : FilterEngine.NONE;\n};\n\n/**\n * A provider component that enables the use of background filters in your app.\n *\n * Please make sure you have the `@stream-io/video-filters-web` package installed\n * in your project before using this component.\n */\nexport const BackgroundFiltersProvider = (\n  props: PropsWithChildren<BackgroundFiltersProps>,\n) => {\n  const {\n    children,\n    backgroundImages = [],\n    backgroundFilter: bgFilterFromProps = undefined,\n    backgroundImage: bgImageFromProps = undefined,\n    backgroundBlurLevel: bgBlurLevelFromProps = undefined,\n    tfFilePath,\n    modelFilePath,\n    useLegacyFilter,\n    basePath,\n    onError,\n    performanceThresholds,\n    forceSafariSupport,\n    forceMobileSupport,\n  } = props;\n\n  const call = useCall();\n  const { useCallStatsReport } = useCallStateHooks();\n  const callStatsReport = useCallStatsReport();\n\n  const [backgroundFilter, setBackgroundFilter] = useState(bgFilterFromProps);\n  const [backgroundImage, setBackgroundImage] = useState(bgImageFromProps);\n  const [backgroundBlurLevel, setBackgroundBlurLevel] =\n    useState(bgBlurLevelFromProps);\n\n  const [showLowFpsWarning, setShowLowFpsWarning] = useState<boolean>(false);\n\n  const fpsWarningThresholdLower =\n    performanceThresholds?.fpsWarningThresholdLower ??\n    FPS_WARNING_THRESHOLD_LOWER;\n  const fpsWarningThresholdUpper =\n    performanceThresholds?.fpsWarningThresholdUpper ??\n    FPS_WARNING_THRESHOLD_UPPER;\n  const defaultFps = performanceThresholds?.defaultFps ?? DEFAULT_FPS;\n\n  const emaRef = useRef<number>(defaultFps);\n  const outlierStreakRef = useRef<number>(0);\n\n  const handleStats = useCallback(\n    (stats: PerformanceStats) => {\n      const fps = stats?.fps;\n      if (fps === undefined || fps === null) {\n        emaRef.current = defaultFps;\n        outlierStreakRef.current = 0;\n        setShowLowFpsWarning(false);\n        return;\n      }\n\n      const prevEma = emaRef.current;\n      const deviation = Math.abs(fps - prevEma) / prevEma;\n\n      const isOutlier = fps < prevEma && deviation > DEVIATION_LIMIT;\n      outlierStreakRef.current = isOutlier ? outlierStreakRef.current + 1 : 0;\n      if (isOutlier && outlierStreakRef.current < OUTLIER_PERSISTENCE) return;\n\n      emaRef.current = ALPHA * fps + (1 - ALPHA) * prevEma;\n\n      setShowLowFpsWarning((prev) => {\n        if (prev && emaRef.current > fpsWarningThresholdUpper) return false;\n        if (!prev && emaRef.current < fpsWarningThresholdLower) return true;\n\n        return prev;\n      });\n    },\n    [fpsWarningThresholdLower, fpsWarningThresholdUpper, defaultFps],\n  );\n\n  const performance: BackgroundFiltersPerformance = useMemo(() => {\n    if (!backgroundFilter) {\n      return { degraded: false };\n    }\n\n    const reasons: Array<PerformanceDegradationReason> = [];\n\n    if (showLowFpsWarning) {\n      reasons.push(PerformanceDegradationReason.FRAME_DROP);\n    }\n\n    const qualityLimitationReasons =\n      callStatsReport?.publisherStats?.qualityLimitationReasons;\n\n    if (\n      showLowFpsWarning &&\n      qualityLimitationReasons &&\n      qualityLimitationReasons?.includes('cpu')\n    ) {\n      reasons.push(PerformanceDegradationReason.CPU_THROTTLING);\n    }\n\n    return {\n      degraded: reasons.length > 0,\n      reason: reasons.length > 0 ? reasons : undefined,\n    };\n  }, [\n    showLowFpsWarning,\n    callStatsReport?.publisherStats?.qualityLimitationReasons,\n    backgroundFilter,\n  ]);\n\n  const prevDegradedRef = useRef<boolean | undefined>(undefined);\n  useEffect(() => {\n    const currentDegraded = performance.degraded;\n    const prevDegraded = prevDegradedRef.current;\n\n    if (\n      !!backgroundFilter &&\n      prevDegraded !== undefined &&\n      prevDegraded !== currentDegraded\n    ) {\n      call?.tracer.trace('backgroundFilters.performance', {\n        degraded: currentDegraded,\n        reason: performance?.reason,\n        fps: emaRef.current,\n      });\n    }\n    prevDegradedRef.current = currentDegraded;\n  }, [\n    performanceThresholds,\n    performance.degraded,\n    performance.reason,\n    backgroundFilter,\n    call?.tracer,\n  ]);\n\n  const applyBackgroundImageFilter = useCallback((imageUrl: string) => {\n    setBackgroundFilter('image');\n    setBackgroundImage(imageUrl);\n  }, []);\n\n  const applyBackgroundBlurFilter = useCallback(\n    (blurLevel: BackgroundBlurLevel = 'high') => {\n      setBackgroundFilter('blur');\n      setBackgroundBlurLevel(blurLevel);\n    },\n    [],\n  );\n\n  const disableBackgroundFilter = useCallback(() => {\n    setBackgroundFilter(undefined);\n    setBackgroundImage(undefined);\n    setBackgroundBlurLevel(undefined);\n\n    emaRef.current = defaultFps;\n    outlierStreakRef.current = 0;\n    setShowLowFpsWarning(false);\n  }, [defaultFps]);\n\n  const [engine, setEngine] = useState<FilterEngine>(FilterEngine.NONE);\n  const [isSupported, setIsSupported] = useState(false);\n  useEffect(() => {\n    determineEngine(\n      useLegacyFilter,\n      forceSafariSupport,\n      forceMobileSupport,\n    ).then((determinedEngine) => {\n      setEngine(determinedEngine);\n      setIsSupported(determinedEngine !== FilterEngine.NONE);\n    });\n  }, [forceMobileSupport, forceSafariSupport, useLegacyFilter]);\n\n  const [tfLite, setTfLite] = useState<TFLite>();\n  useEffect(() => {\n    if (engine !== FilterEngine.TF) return;\n\n    loadTFLite({ basePath, modelFilePath, tfFilePath })\n      .then(setTfLite)\n      .catch((err) => console.error('Failed to load TFLite', err));\n  }, [basePath, engine, modelFilePath, tfFilePath]);\n\n  const [mediaPipe, setMediaPipe] = useState<ArrayBuffer>();\n  useEffect(() => {\n    if (engine !== FilterEngine.MEDIA_PIPE) return;\n\n    loadMediaPipe({\n      basePath: basePath,\n      modelPath: modelFilePath,\n    })\n      .then(setMediaPipe)\n      .catch((err) => console.error('Failed to preload MediaPipe', err));\n  }, [engine, modelFilePath, basePath]);\n\n  const handleError = useCallback(\n    (error: any) => {\n      console.warn(\n        '[filters] Filter encountered an error and will be disabled',\n      );\n      disableBackgroundFilter();\n      onError?.(error);\n    },\n    [disableBackgroundFilter, onError],\n  );\n\n  const isReady = useLegacyFilter ? !!tfLite : !!mediaPipe;\n  return (\n    <BackgroundFiltersContext.Provider\n      value={{\n        isSupported,\n        performance,\n        isReady,\n        backgroundImage,\n        backgroundBlurLevel,\n        backgroundFilter,\n        disableBackgroundFilter,\n        applyBackgroundBlurFilter,\n        applyBackgroundImageFilter,\n        backgroundImages,\n        tfFilePath,\n        modelFilePath,\n        basePath,\n        onError: handleError,\n      }}\n    >\n      {children}\n      {isReady && (\n        <BackgroundFilters\n          tfLite={tfLite}\n          engine={engine}\n          onStats={handleStats}\n        />\n      )}\n    </BackgroundFiltersContext.Provider>\n  );\n};\n\nconst BackgroundFilters = (props: {\n  tfLite?: TFLite;\n  engine: FilterEngine;\n  onStats: (stats: PerformanceStats) => void;\n}) => {\n  const call = useCall();\n  const { children, start } = useRenderer(props.tfLite, call, props.engine);\n  const { onError, backgroundFilter } = useBackgroundFilters();\n  const handleErrorRef = useRef<((error: any) => void) | undefined>(undefined);\n  handleErrorRef.current = onError;\n\n  const handleStatsRef = useRef<\n    ((stats: PerformanceStats) => void) | undefined\n  >(undefined);\n  handleStatsRef.current = props.onStats;\n\n  useEffect(() => {\n    if (!call || !backgroundFilter) return;\n\n    const { unregister } = call.camera.registerFilter((ms) => {\n      return start(\n        ms,\n        (error) => handleErrorRef.current?.(error),\n        (stats: PerformanceStats) => handleStatsRef.current?.(stats),\n      );\n    });\n    return () => {\n      unregister().catch((err) => console.warn(`Can't unregister filter`, err));\n    };\n  }, [call, start, backgroundFilter]);\n\n  return children;\n};\n\nconst useRenderer = (\n  tfLite: TFLite | undefined,\n  call: Call | undefined,\n  engine: FilterEngine,\n) => {\n  const {\n    backgroundFilter,\n    backgroundBlurLevel,\n    backgroundImage,\n    modelFilePath,\n    basePath,\n  } = useBackgroundFilters();\n\n  const videoRef = useRef<HTMLVideoElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const bgImageRef = useRef<HTMLImageElement>(null);\n  const [videoSize, setVideoSize] = useState<{ width: number; height: number }>(\n    {\n      width: 1920,\n      height: 1080,\n    },\n  );\n\n  const start = useCallback(\n    (\n      ms: MediaStream,\n      onError?: (error: any) => void,\n      onStats?: (stats: PerformanceStats) => void,\n    ) => {\n      let outputStream: MediaStream | undefined;\n      let processor: VirtualBackground | undefined;\n      let renderer: Renderer | undefined;\n\n      const output = new Promise<MediaStream>((resolve, reject) => {\n        if (!backgroundFilter) {\n          reject(new Error('No filter specified'));\n          return;\n        }\n\n        const videoEl = videoRef.current;\n        const canvasEl = canvasRef.current;\n        const bgImageEl = bgImageRef.current;\n\n        const [track] = ms.getVideoTracks();\n\n        if (!track) {\n          reject(new Error('No video tracks in input media stream'));\n          return;\n        }\n\n        if (engine === FilterEngine.MEDIA_PIPE) {\n          call?.tracer.trace('backgroundFilters.enable', {\n            backgroundFilter,\n            backgroundBlurLevel,\n            backgroundImage,\n            engine,\n          });\n\n          if (!videoEl) {\n            reject(new Error('Renderer started before elements are ready'));\n            return;\n          }\n\n          const trackSettings = track.getSettings();\n          flushSync(() =>\n            setVideoSize({\n              width: trackSettings.width ?? 0,\n              height: trackSettings.height ?? 0,\n            }),\n          );\n\n          processor = new VirtualBackground(\n            track,\n            {\n              basePath: basePath,\n              modelPath: modelFilePath,\n              backgroundBlurLevel,\n              backgroundImage,\n              backgroundFilter,\n            },\n            { onError, onStats },\n          );\n          processor\n            .start()\n            .then((processedTrack) => {\n              outputStream = new MediaStream([processedTrack]);\n              resolve(outputStream);\n            })\n            .catch((error) => {\n              reject(error);\n            });\n\n          return;\n        }\n\n        if (engine === FilterEngine.TF) {\n          if (!videoEl || !canvasEl || (backgroundImage && !bgImageEl)) {\n            reject(new Error('Renderer started before elements are ready'));\n            return;\n          }\n\n          videoEl.srcObject = ms;\n          videoEl.play().then(\n            () => {\n              const trackSettings = track.getSettings();\n              flushSync(() =>\n                setVideoSize({\n                  width: trackSettings.width ?? 0,\n                  height: trackSettings.height ?? 0,\n                }),\n              );\n              call?.tracer.trace('backgroundFilters.enable', {\n                backgroundFilter,\n                backgroundBlurLevel,\n                backgroundImage,\n                engine,\n              });\n\n              if (!tfLite) {\n                reject(new Error('TensorFlow Lite not loaded'));\n                return;\n              }\n\n              renderer = createRenderer(\n                tfLite,\n                videoEl,\n                canvasEl,\n                {\n                  backgroundFilter,\n                  backgroundBlurLevel,\n                  backgroundImage: bgImageEl ?? undefined,\n                },\n                onError,\n              );\n              outputStream = canvasEl.captureStream();\n\n              resolve(outputStream);\n            },\n            () => {\n              reject(new Error('Could not play the source video stream'));\n            },\n          );\n          return;\n        }\n\n        reject(new Error('No supported engine available'));\n      });\n\n      return {\n        output,\n        stop: () => {\n          call?.tracer.trace('backgroundFilters.disable', null);\n          processor?.stop();\n          renderer?.dispose();\n          if (videoRef.current) videoRef.current.srcObject = null;\n          if (outputStream) disposeOfMediaStream(outputStream);\n        },\n      };\n    },\n    [\n      backgroundBlurLevel,\n      backgroundFilter,\n      backgroundImage,\n      call?.tracer,\n      tfLite,\n      engine,\n      modelFilePath,\n      basePath,\n    ],\n  );\n\n  const children = (\n    <div className=\"str-video__background-filters\">\n      <video\n        className={clsx(\n          'str-video__background-filters__video',\n          videoSize.height > videoSize.width &&\n            'str-video__background-filters__video--tall',\n        )}\n        ref={videoRef}\n        playsInline\n        muted\n        controls={false}\n        {...videoSize}\n      />\n      {backgroundImage && (\n        <img\n          className=\"str-video__background-filters__background-image\"\n          alt=\"Background\"\n          ref={bgImageRef}\n          crossOrigin=\"anonymous\"\n          src={backgroundImage}\n          {...videoSize}\n        />\n      )}\n      <canvas\n        className=\"str-video__background-filters__target-canvas\"\n        {...videoSize}\n        ref={canvasRef}\n      />\n    </div>\n  );\n\n  return { start, children };\n};\n","import { ComponentProps, ForwardedRef, forwardRef } from 'react';\nimport clsx from 'clsx';\n\nimport { Icon, IconProps } from '../Icon';\n\nexport type ButtonWithIconProps = {\n  enabled?: boolean;\n  variant?: string;\n} & ComponentProps<'button'> &\n  IconProps;\n\nexport const IconButton = forwardRef(function IconButton(\n  props: ButtonWithIconProps,\n  ref: ForwardedRef<HTMLButtonElement>,\n) {\n  const { icon, enabled, variant, onClick, className, ...rest } = props;\n  return (\n    <button\n      className={clsx('str-video__call-controls__button', className, {\n        [`str-video__call-controls__button--variant-${variant}`]: variant,\n        'str-video__call-controls__button--enabled': enabled,\n      })}\n      onClick={(e) => {\n        e.preventDefault();\n        onClick?.(e);\n      }}\n      ref={ref}\n      {...rest}\n    >\n      <Icon icon={icon} />\n    </button>\n  );\n});\n","import clsx from 'clsx';\nimport { MenuToggle, ToggleMenuButtonProps } from '../Menu';\nimport {\n  ComponentProps,\n  ComponentType,\n  forwardRef,\n  PropsWithChildren,\n  ReactElement,\n} from 'react';\nimport { Placement } from '@floating-ui/react';\n\nimport { IconButton } from './IconButton';\nimport { isComponentType } from '../../utilities';\n\nexport type IconButtonWithMenuProps<E extends HTMLElement = HTMLButtonElement> =\n  PropsWithChildren<{\n    active?: boolean;\n    Menu?: ComponentType | ReactElement | null;\n    caption?: string;\n    className?: string;\n    menuPlacement?: Placement;\n    menuOffset?: number;\n    ToggleMenuButton?: ComponentType<ToggleMenuButtonProps<E>>;\n    variant?: 'primary' | 'secondary';\n    onMenuToggle?: (menuShown: boolean) => void;\n  }> &\n    ComponentProps<'button'>;\n\nexport const CompositeButton = forwardRef<\n  HTMLDivElement,\n  IconButtonWithMenuProps\n>(function CompositeButton(\n  {\n    disabled,\n    caption,\n    children,\n    className,\n    active,\n    Menu,\n    menuPlacement,\n    menuOffset,\n    title,\n    ToggleMenuButton = DefaultToggleMenuButton,\n    variant,\n    onClick,\n    onMenuToggle,\n    ...restButtonProps\n  },\n  ref,\n) {\n  return (\n    <div\n      className={clsx('str-video__composite-button', className, {\n        'str-video__composite-button--caption': caption,\n        'str-video__composite-button--menu': Menu,\n      })}\n      title={title}\n      ref={ref}\n    >\n      <div\n        className={clsx('str-video__composite-button__button-group', {\n          'str-video__composite-button__button-group--active': active,\n          'str-video__composite-button__button-group--active-primary':\n            active && variant === 'primary',\n          'str-video__composite-button__button-group--active-secondary':\n            active && variant === 'secondary',\n          'str-video__composite-button__button-group--disabled': disabled,\n        })}\n      >\n        <button\n          type=\"button\"\n          className=\"str-video__composite-button__button\"\n          onClick={(e) => {\n            e.preventDefault();\n            onClick?.(e);\n          }}\n          disabled={disabled}\n          {...restButtonProps}\n        >\n          {children}\n        </button>\n        {Menu && (\n          <MenuToggle\n            offset={menuOffset}\n            placement={menuPlacement}\n            ToggleButton={ToggleMenuButton}\n            onToggle={onMenuToggle}\n          >\n            {isComponentType(Menu) ? <Menu /> : Menu}\n          </MenuToggle>\n        )}\n      </div>\n      {caption && (\n        <div className=\"str-video__composite-button__caption\">{caption}</div>\n      )}\n    </div>\n  );\n});\n\nconst DefaultToggleMenuButton = forwardRef<\n  HTMLButtonElement,\n  ToggleMenuButtonProps\n>(function DefaultToggleMenuButton({ menuShown }, ref) {\n  return (\n    <IconButton\n      className={clsx('str-video__menu-toggle-button', {\n        'str-video__menu-toggle-button--active': menuShown,\n      })}\n      icon={menuShown ? 'caret-down' : 'caret-up'}\n      ref={ref}\n    />\n  );\n});\n","import { ComponentProps } from 'react';\n\nexport const TextButton = ({\n  children,\n  ...rest\n}: Omit<ComponentProps<'button'>, 'ref' | 'className'>) => {\n  return (\n    <button {...rest} className=\"str-video__text-button\">\n      {children}\n    </button>\n  );\n};\n","import { MouseEventHandler, useCallback } from 'react';\nimport { IconButton } from '../Button';\nimport { useCall } from '@stream-io/video-react-bindings';\n\nexport type AcceptCallButtonProps = {\n  disabled?: boolean;\n  onClick?: MouseEventHandler<HTMLButtonElement>;\n  onAccept?: () => void;\n};\n\nexport const AcceptCallButton = ({\n  disabled,\n  onAccept,\n  onClick,\n}: AcceptCallButtonProps) => {\n  const call = useCall();\n  const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(\n    async (e) => {\n      if (onClick) {\n        onClick(e);\n      } else if (call) {\n        await call.join();\n        onAccept?.();\n      }\n    },\n    [onClick, onAccept, call],\n  );\n  return (\n    <IconButton\n      disabled={disabled}\n      icon=\"call-accept\"\n      variant=\"success\"\n      data-testid=\"accept-call-button\"\n      onClick={handleClick}\n    />\n  );\n};\n","import { PropsWithChildren, ReactNode, useEffect } from 'react';\nimport clsx from 'clsx';\nimport { Placement } from '@floating-ui/react';\nimport { useFloatingUIPreset } from '../../hooks';\n\nexport type NotificationProps = {\n  message?: ReactNode;\n  isVisible?: boolean;\n  visibilityTimeout?: number;\n  resetIsVisible?: () => void;\n  placement?: Placement;\n  className?: string;\n  iconClassName?: string | null;\n  close?: () => void;\n};\n\nexport const Notification = (props: PropsWithChildren<NotificationProps>) => {\n  const {\n    isVisible,\n    message,\n    children,\n    visibilityTimeout,\n    resetIsVisible,\n    placement = 'top',\n    className,\n    iconClassName = 'str-video__notification__icon',\n    close,\n  } = props;\n\n  const { refs, x, y, strategy } = useFloatingUIPreset({\n    placement,\n    strategy: 'absolute',\n  });\n\n  useEffect(() => {\n    if (!isVisible || !visibilityTimeout || !resetIsVisible) return;\n\n    const timeout = setTimeout(() => {\n      resetIsVisible();\n    }, visibilityTimeout);\n\n    return () => clearTimeout(timeout);\n  }, [isVisible, resetIsVisible, visibilityTimeout]);\n\n  return (\n    <div ref={refs.setReference}>\n      {isVisible && (\n        <div\n          className={clsx('str-video__notification', className)}\n          ref={refs.setFloating}\n          style={{\n            position: strategy,\n            top: y ?? 0,\n            left: x ?? 0,\n            overflowY: 'auto',\n          }}\n        >\n          {iconClassName && <i className={iconClassName} />}\n          <span className=\"str-video__notification__message\">{message}</span>\n          {close ? (\n            <i\n              className=\"str-video__icon str-video__icon--close str-video__notification__close\"\n              onClick={close}\n            />\n          ) : null}\n        </div>\n      )}\n      {children}\n    </div>\n  );\n};\n","import { Notification } from './Notification';\nimport { OwnCapability } from '@stream-io/video-client';\nimport {\n  PropsWithChildren,\n  useCallback,\n  useEffect,\n  useRef,\n  useState,\n} from 'react';\nimport { useCallStateHooks } from '@stream-io/video-react-bindings';\n\nexport type PermissionNotificationProps = PropsWithChildren<{\n  /**\n   * Set this to true if there is ongoing request for the permission.\n   */\n  isAwaitingApproval: boolean;\n\n  /**\n   * The message to display in the notification once\n   * the requested permission is granted.\n   */\n  messageApproved: string;\n\n  /**\n   * The message to display in the notification once a permission\n   * is revoked.\n   */\n  messageRevoked: string;\n\n  /**\n   * The message to display in the notification while\n   * the requested permission is awaiting approval.\n   */\n  messageAwaitingApproval: string;\n\n  /**\n   * The permission to check for.\n   */\n  permission: OwnCapability;\n\n  /**\n   * The time in milliseconds to display the notification.\n   * Defaults to 3500ms.\n   */\n  visibilityTimeout?: number;\n}>;\n\nexport const PermissionNotification = (props: PermissionNotificationProps) => {\n  const {\n    permission,\n    isAwaitingApproval,\n    messageApproved,\n    messageAwaitingApproval,\n    messageRevoked,\n    visibilityTimeout = 3500,\n    children,\n  } = props;\n  const { useHasPermissions } = useCallStateHooks();\n  const hasPermission = useHasPermissions(permission);\n  const prevHasPermission = useRef(hasPermission);\n  const [showNotification, setShowNotification] = useState<\n    'granted' | 'revoked'\n  >();\n  useEffect(() => {\n    if (prevHasPermission.current === hasPermission) return;\n\n    if (hasPermission) {\n      setShowNotification('granted');\n      prevHasPermission.current = true;\n    } else {\n      setShowNotification('revoked');\n      prevHasPermission.current = false;\n    }\n  }, [hasPermission]);\n\n  const resetIsVisible = useCallback(() => setShowNotification(undefined), []);\n  if (isAwaitingApproval) {\n    return (\n      <Notification\n        isVisible={isAwaitingApproval && !hasPermission}\n        message={messageAwaitingApproval}\n      >\n        {children}\n      </Notification>\n    );\n  }\n\n  return (\n    <Notification\n      isVisible={!!showNotification}\n      visibilityTimeout={visibilityTimeout}\n      resetIsVisible={resetIsVisible}\n      message={\n        showNotification === 'granted' ? messageApproved : messageRevoked\n      }\n    >\n      {children}\n    </Notification>\n  );\n};\n","import { PropsWithChildren } from 'react';\nimport { Placement } from '@floating-ui/react';\n\nimport { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';\nimport { Notification } from './Notification';\n\nexport type SpeakingWhileMutedNotificationProps = {\n  /**\n   * Text message displayed by the notification.\n   */\n  text?: string;\n  placement?: Placement;\n};\n\nexport const SpeakingWhileMutedNotification = ({\n  children,\n  text,\n  placement,\n}: PropsWithChildren<SpeakingWhileMutedNotificationProps>) => {\n  const { useMicrophoneState } = useCallStateHooks();\n  const { isSpeakingWhileMuted } = useMicrophoneState();\n  const { t } = useI18n();\n\n  const message = text ?? t('You are muted. Unmute to speak.');\n  return (\n    <Notification\n      message={message}\n      isVisible={isSpeakingWhileMuted}\n      placement={placement || 'top-start'}\n    >\n      {children}\n    </Notification>\n  );\n};\n","import { PropsWithChildren, useEffect, useState } from 'react';\nimport {\n  useI18n,\n  useToggleCallRecording,\n} from '@stream-io/video-react-bindings';\nimport { Notification } from './Notification';\n\nexport type RecordingInProgressNotificationProps = {\n  text?: string;\n};\n\nexport const RecordingInProgressNotification = ({\n  children,\n  text,\n}: PropsWithChildren<RecordingInProgressNotificationProps>) => {\n  const { t } = useI18n();\n  const { isCallRecordingInProgress } = useToggleCallRecording();\n\n  const [isVisible, setVisible] = useState(false);\n\n  const message = text ?? t('Recording in progress...');\n\n  useEffect(() => {\n    if (isCallRecordingInProgress) {\n      setVisible(true);\n    } else {\n      setVisible(false);\n    }\n  }, [isCallRecordingInProgress]);\n\n  return (\n    <Notification\n      message={message}\n      iconClassName=\"str-video__icon str-video__icon--recording-on\"\n      isVisible={isVisible}\n      placement=\"top-start\"\n      close={() => setVisible(false)}\n    >\n      {children}\n    </Notification>\n  );\n};\n","import clsx from 'clsx';\n\nexport type LoadingIndicatorProps = {\n  className?: string;\n  /** String will be injected into class and later used to apply as a CSS mask-image to an element as data URL */\n  type?: string;\n  /** Text to be displayed under the loading indicator icon */\n  text?: string;\n  /** Tooltip to be displayed on hover */\n  tooltip?: string;\n};\n\nexport const LoadingIndicator = ({\n  className,\n  type = 'spinner',\n  text,\n  tooltip,\n}: LoadingIndicatorProps) => {\n  return (\n    <div\n      className={clsx('str-video__loading-indicator', className)}\n      title={tooltip}\n    >\n      <div className={clsx('str-video__loading-indicator__icon', type)}></div>\n      {text && <p className=\"str-video__loading-indicator-text\">{text}</p>}\n    </div>\n  );\n};\n","import { PropsWithChildren, useEffect, useRef } from 'react';\nimport clsx from 'clsx';\nimport { useFloatingUIPreset } from '../../hooks';\nimport { FloatingArrow, Placement, arrow } from '@floating-ui/react';\n\nexport type TooltipProps<T extends HTMLElement> = PropsWithChildren<{\n  /** Reference element to which the tooltip should attach to */\n  referenceElement: T | null;\n  /** Additional class applied to the tooltip root element */\n  tooltipClassName?: string;\n  /** Popper's modifier (offset) property - [xAxis offset, yAxis offset], default [0, 10] */\n  offset?: [number, number];\n  /** Popper's placement property defining default position of the tooltip, default 'top' */\n  tooltipPlacement?: Placement;\n  /** Tells component whether to render its contents */\n  visible?: boolean;\n}>;\n\nexport const Tooltip = <T extends HTMLElement>({\n  children,\n  referenceElement,\n  tooltipClassName,\n  tooltipPlacement = 'top',\n  visible = false,\n}: TooltipProps<T>) => {\n  const arrowRef = useRef<SVGSVGElement>(null);\n  const { refs, x, y, strategy, context } = useFloatingUIPreset({\n    placement: tooltipPlacement,\n    strategy: 'absolute',\n    middleware: [arrow({ element: arrowRef })],\n  });\n\n  useEffect(() => {\n    refs.setReference(referenceElement);\n  }, [referenceElement, refs]);\n\n  if (!visible) return null;\n\n  return (\n    <div\n      className={clsx('str-video__tooltip', tooltipClassName)}\n      ref={refs.setFloating}\n      style={{\n        position: strategy,\n        top: y ?? 0,\n        left: x ?? 0,\n      }}\n    >\n      <FloatingArrow\n        ref={arrowRef}\n        context={context}\n        fill=\"var(--str-video__tooltip--background-color)\"\n      />\n      {children}\n    </div>\n  );\n};\n","import { MouseEventHandler, useCallback, useState } from 'react';\n\nexport const useEnterLeaveHandlers = <T extends HTMLElement>({\n  onMouseEnter,\n  onMouseLeave,\n}: Partial<\n  Record<'onMouseEnter' | 'onMouseLeave', MouseEventHandler<T>>\n> = {}) => {\n  const [tooltipVisible, setTooltipVisible] = useState(false);\n\n  const handleMouseEnter: MouseEventHandler<T> = useCallback(\n    (e) => {\n      setTooltipVisible(true);\n      onMouseEnter?.(e);\n    },\n    [onMouseEnter],\n  );\n\n  const handleMouseLeave: MouseEventHandler<T> = useCallback(\n    (e) => {\n      setTooltipVisible(false);\n      onMouseLeave?.(e);\n    },\n    [onMouseLeave],\n  );\n\n  return { handleMouseEnter, handleMouseLeave, tooltipVisible };\n};\n","import { ComponentProps, useState } from 'react';\nimport { Tooltip, TooltipProps } from './Tooltip';\nimport { useEnterLeaveHandlers } from './hooks';\n\ntype WithPopupProps = ComponentProps<'div'> &\n  Omit<TooltipProps<HTMLDivElement>, 'referenceElement' | 'children'> & {\n    tooltipDisabled?: boolean;\n  };\n\n// todo: duplicate of CallParticipantList.tsx#MediaIndicator - refactor to a single component\nexport const WithTooltip = ({\n  title,\n  tooltipClassName,\n  tooltipPlacement,\n  tooltipDisabled,\n  ...props\n}: WithPopupProps) => {\n  const { handleMouseEnter, handleMouseLeave, tooltipVisible } =\n    useEnterLeaveHandlers<HTMLDivElement>();\n  const [tooltipAnchor, setTooltipAnchor] = useState<HTMLDivElement | null>(\n    null,\n  );\n  const tooltipActuallyVisible =\n    !tooltipDisabled && Boolean(title) && tooltipVisible;\n\n  return (\n    <>\n      <Tooltip\n        referenceElement={tooltipAnchor}\n        visible={tooltipActuallyVisible}\n        tooltipClassName={tooltipClassName}\n        tooltipPlacement={tooltipPlacement}\n      >\n        {title || ''}\n      </Tooltip>\n      <div\n        ref={setTooltipAnchor}\n        onMouseEnter={handleMouseEnter}\n        onMouseLeave={handleMouseLeave}\n        {...props}\n      />\n    </>\n  );\n};\n","import { forwardRef } from 'react';\n\nimport { OwnCapability } from '@stream-io/video-client';\nimport {\n  Restricted,\n  useI18n,\n  useToggleCallRecording,\n} from '@stream-io/video-react-bindings';\nimport { CompositeButton } from '../Button/';\nimport { Icon } from '../Icon';\nimport {\n  MenuToggle,\n  MenuVisualType,\n  ToggleMenuButtonProps,\n  useMenuContext,\n} from '../Menu';\nimport { LoadingIndicator } from '../LoadingIndicator';\nimport { WithTooltip } from '../Tooltip';\n\nexport type RecordCallButtonProps = {\n  caption?: string;\n};\n\nconst RecordEndConfirmation = () => {\n  const { t } = useI18n();\n  const { toggleCallRecording, isAwaitingResponse } = useToggleCallRecording();\n\n  const { close } = useMenuContext();\n\n  return (\n    <div className=\"str-video__end-recording__confirmation\">\n      <div className=\"str-video__end-recording__header\">\n        <Icon icon=\"recording-on\" />\n        <h2 className=\"str-video__end-recording__heading\">\n          {t('End recording')}\n        </h2>\n      </div>\n      <p className=\"str-video__end-recording__description\">\n        {t('Are you sure you want end the recording?')}\n      </p>\n      <div className=\"str-video__end-recording__actions\">\n        <CompositeButton variant=\"secondary\" onClick={close}>\n          {t('Cancel')}\n        </CompositeButton>\n        <CompositeButton variant=\"primary\" onClick={toggleCallRecording}>\n          {isAwaitingResponse ? <LoadingIndicator /> : t('End recording')}\n        </CompositeButton>\n      </div>\n    </div>\n  );\n};\n\nconst ToggleEndRecordingMenuButton = forwardRef<\n  HTMLDivElement,\n  ToggleMenuButtonProps\n>(function ToggleEndRecordingMenuButton(props, ref) {\n  return (\n    <CompositeButton\n      ref={ref}\n      active={true}\n      variant=\"secondary\"\n      data-testid=\"recording-stop-button\"\n    >\n      <Icon icon=\"recording-off\" />\n    </CompositeButton>\n  );\n});\n\nexport const RecordCallConfirmationButton = ({\n  caption,\n}: {\n  caption?: string;\n}) => {\n  const { t } = useI18n();\n  const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } =\n    useToggleCallRecording();\n\n  if (isCallRecordingInProgress) {\n    return (\n      <Restricted\n        requiredGrants={[\n          OwnCapability.START_RECORD_CALL,\n          OwnCapability.STOP_RECORD_CALL,\n        ]}\n      >\n        <MenuToggle\n          ToggleButton={ToggleEndRecordingMenuButton}\n          visualType={MenuVisualType.PORTAL}\n        >\n          <RecordEndConfirmation />\n        </MenuToggle>\n      </Restricted>\n    );\n  }\n\n  const title = isAwaitingResponse\n    ? t('Waiting for recording to start...')\n    : (caption ?? t('Record call'));\n\n  return (\n    <Restricted\n      requiredGrants={[\n        OwnCapability.START_RECORD_CALL,\n        OwnCapability.STOP_RECORD_CALL,\n      ]}\n    >\n      <WithTooltip title={title}>\n        <CompositeButton\n          active={isCallRecordingInProgress}\n          caption={caption}\n          variant=\"secondary\"\n          data-testid=\"recording-start-button\"\n          onClick={isAwaitingResponse ? undefined : toggleCallRecording}\n        >\n          {isAwaitingResponse ? (\n            <LoadingIndicator />\n          ) : (\n            <Icon icon=\"recording-off\" />\n          )}\n        </CompositeButton>\n      </WithTooltip>\n    </Restricted>\n  );\n};\n\nexport const RecordCallButton = ({ caption }: RecordCallButtonProps) => {\n  const { t } = useI18n();\n  const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } =\n    useToggleCallRecording();\n\n  let title = caption ?? t('Record call');\n\n  if (isAwaitingResponse) {\n    title = isCallRecordingInProgress\n      ? t('Waiting for recording to stop...')\n      : t('Waiting for recording to start...');\n  }\n\n  return (\n    <Restricted\n      requiredGrants={[\n        OwnCapability.START_RECORD_CALL,\n        OwnCapability.STOP_RECORD_CALL,\n      ]}\n    >\n      <CompositeButton\n        active={isCallRecordingInProgress}\n        caption={caption}\n        variant=\"secondary\"\n        data-testid={\n          isCallRecordingInProgress\n            ? 'recording-stop-button'\n            : 'recording-start-button'\n        }\n        title={title}\n        onClick={isAwaitingResponse ? undefined : toggleCallRecording}\n      >\n        {isAwaitingResponse ? (\n          <LoadingIndicator />\n        ) : (\n          <Icon\n            icon={isCallRecordingInProgress ? 'recording-on' : 'recording-off'}\n          />\n        )}\n      </CompositeButton>\n    </Restricted>\n  );\n};\n","import { useEffect } from 'react';\nimport { StreamVideoParticipant } from '@stream-io/video-client';\nimport { useCall } from '@stream-io/video-react-bindings';\n\nexport type ReactionProps = {\n  participant: StreamVideoParticipant;\n  hideAfterTimeoutInMs?: number;\n  emojiReactionMap?: Record<string, string>;\n};\n\nexport const defaultEmojiReactionMap: Record<string, string> = {\n  ':like:': '👍',\n  ':raise-hand:': '✋',\n  ':fireworks:': '🎉',\n  ':dislike:': '👎',\n  ':heart:': '❤️',\n  ':smile:': '😀',\n};\n\nexport const Reaction = ({\n  participant: { reaction, sessionId },\n  hideAfterTimeoutInMs = 5500,\n  emojiReactionMap = defaultEmojiReactionMap,\n}: ReactionProps) => {\n  const call = useCall();\n\n  useEffect(() => {\n    if (!call || !reaction) return;\n\n    const timeoutId = setTimeout(() => {\n      call.resetReaction(sessionId);\n    }, hideAfterTimeoutInMs);\n\n    return () => {\n      clearTimeout(timeoutId);\n    };\n  }, [call, hideAfterTimeoutInMs, reaction, sessionId]);\n\n  if (!reaction) return null;\n\n  const { emoji_code: emojiCode } = reaction;\n\n  return (\n    <div className=\"str-video__reaction\">\n      <span className=\"str-video__reaction__emoji\">\n        {emojiCode && emojiReactionMap[emojiCode]}\n      </span>\n    </div>\n  );\n};\n","import { forwardRef } from 'react';\nimport clsx from 'clsx';\n\nimport { OwnCapability, StreamReaction } from '@stream-io/video-client';\nimport { Restricted, useCall, useI18n } from '@stream-io/video-react-bindings';\n\nimport {\n  MenuToggle,\n  MenuVisualType,\n  ToggleMenuButtonProps,\n  useMenuContext,\n} from '../Menu';\nimport { CompositeButton } from '../Button';\nimport { defaultEmojiReactionMap } from '../Reaction';\nimport { Icon } from '../Icon';\nimport { WithTooltip } from '../Tooltip';\n\nexport const defaultReactions: StreamReaction[] = [\n  {\n    type: 'reaction',\n    emoji_code: ':like:',\n  },\n  {\n    // TODO OL: use `prompt` type?\n    type: 'raised-hand',\n    emoji_code: ':raise-hand:',\n  },\n  {\n    type: 'reaction',\n    emoji_code: ':fireworks:',\n  },\n  {\n    type: 'reaction',\n    emoji_code: ':dislike:',\n  },\n  {\n    type: 'reaction',\n    emoji_code: ':heart:',\n  },\n  {\n    type: 'reaction',\n    emoji_code: ':smile:',\n  },\n];\n\nexport interface ReactionsButtonProps {\n  reactions?: StreamReaction[];\n}\n\nexport const ReactionsButton = ({\n  reactions = defaultReactions,\n}: ReactionsButtonProps) => {\n  return (\n    <Restricted requiredGrants={[OwnCapability.CREATE_REACTION]}>\n      <MenuToggle\n        placement=\"top\"\n        ToggleButton={ToggleReactionsMenuButton}\n        visualType={MenuVisualType.MENU}\n      >\n        <DefaultReactionsMenu reactions={reactions} />\n      </MenuToggle>\n    </Restricted>\n  );\n};\n\nconst ToggleReactionsMenuButton = forwardRef<\n  HTMLDivElement,\n  ToggleMenuButtonProps\n>(function ToggleReactionsMenuButton({ menuShown }, ref) {\n  const { t } = useI18n();\n  return (\n    <WithTooltip title={t('Reactions')} tooltipDisabled={menuShown}>\n      <CompositeButton ref={ref} active={menuShown} variant=\"primary\">\n        <Icon icon=\"reactions\" />\n      </CompositeButton>\n    </WithTooltip>\n  );\n});\n\nexport interface DefaultReactionsMenuProps {\n  reactions: StreamReaction[];\n  layout?: 'horizontal' | 'vertical';\n}\n\nexport const DefaultReactionsMenu = ({\n  reactions,\n  layout = 'horizontal',\n}: DefaultReactionsMenuProps) => {\n  const call = useCall();\n  const { close } = useMenuContext();\n  return (\n    <div\n      className={clsx('str-video__reactions-menu', {\n        'str-video__reactions-menu--horizontal': layout === 'horizontal',\n        'str-video__reactions-menu--vertical': layout === 'vertical',\n      })}\n    >\n      {reactions.map((reaction) => (\n        <button\n          key={reaction.emoji_code}\n          type=\"button\"\n          className=\"str-video__reactions-menu__button\"\n          onClick={() => {\n            call?.sendReaction(reaction);\n            close?.();\n          }}\n        >\n          {reaction.emoji_code && defaultEmojiReactionMap[reaction.emoji_code]}\n        </button>\n      ))}\n    </div>\n  );\n};\n","export type PropsWithErrorHandler<T = unknown> = T & {\n  /**\n   * Will be called if the call control action failed with an error (e.g. user didn't grant a\n   * browser permission to enable a media device). If no callback is provided, just logs the error.\n   * @param error Exception which caused call control action to fail\n   */\n  onError?: (error: unknown) => void;\n};\n\n/**\n * Wraps an event handler, silencing and logging exceptions (excluding the NotAllowedError\n * DOMException, which is a normal situation handled by the SDK)\n *\n * @param props component props, including the onError callback\n * @param handler event handler to wrap\n */\nexport const createCallControlHandler = (\n  props: PropsWithErrorHandler,\n  handler: () => Promise<void>,\n): (() => Promise<void>) => {\n  return async () => {\n    try {\n      await handler();\n    } catch (error) {\n      if (props.onError) {\n        props.onError(error);\n        return;\n      }\n\n      if (!isNotAllowedError(error)) {\n        console.error('Call control handler failed', error);\n      }\n    }\n  };\n};\n\nfunction isNotAllowedError(error: unknown): error is DOMException {\n  return error instanceof DOMException && error.name === 'NotAllowedError';\n}\n","import { OwnCapability } from '@stream-io/video-client';\nimport {\n  Restricted,\n  useCallStateHooks,\n  useI18n,\n  UseInputMediaDeviceOptions,\n} from '@stream-io/video-react-bindings';\nimport { CompositeButton } from '../Button/';\nimport { PermissionNotification } from '../Notification';\nimport { useRequestPermission } from '../../hooks';\nimport { Icon } from '../Icon';\nimport { WithTooltip } from '../Tooltip';\nimport {\n  PropsWithErrorHandler,\n  createCallControlHandler,\n} from '../../utilities/callControlHandler';\n\nexport type ScreenShareButtonProps = PropsWithErrorHandler<\n  {\n    caption?: string;\n  } & UseInputMediaDeviceOptions\n>;\n\nexport const ScreenShareButton = (props: ScreenShareButtonProps) => {\n  const { t } = useI18n();\n  const { caption, optimisticUpdates } = props;\n\n  const { useHasOngoingScreenShare, useScreenShareState, useCallSettings } =\n    useCallStateHooks();\n  const isSomeoneScreenSharing = useHasOngoingScreenShare();\n  const { hasPermission, requestPermission, isAwaitingPermission } =\n    useRequestPermission(OwnCapability.SCREENSHARE);\n\n  const callSettings = useCallSettings();\n  const isScreenSharingAllowed = callSettings?.screensharing.enabled;\n\n  const { screenShare, optionsAwareIsMute, isTogglePending } =\n    useScreenShareState({\n      optimisticUpdates,\n    });\n  const amIScreenSharing = !optionsAwareIsMute;\n  const disableScreenShareButton =\n    (!amIScreenSharing &&\n      (isSomeoneScreenSharing || isScreenSharingAllowed === false)) ||\n    (!optimisticUpdates && isTogglePending);\n  const handleClick = createCallControlHandler(props, async () => {\n    if (!hasPermission) {\n      await requestPermission();\n    } else {\n      await screenShare.toggle();\n    }\n  });\n\n  return (\n    <Restricted requiredGrants={[OwnCapability.SCREENSHARE]}>\n      <PermissionNotification\n        permission={OwnCapability.SCREENSHARE}\n        isAwaitingApproval={isAwaitingPermission}\n        messageApproved={t('You can now share your screen.')}\n        messageAwaitingApproval={t('Awaiting for an approval to share screen.')}\n        messageRevoked={t('You can no longer share your screen.')}\n      >\n        <WithTooltip title={caption ?? t('Share screen')}>\n          <CompositeButton\n            active={isSomeoneScreenSharing || amIScreenSharing}\n            caption={caption}\n            variant=\"primary\"\n            data-testid={\n              isSomeoneScreenSharing\n                ? 'screen-share-stop-button'\n                : 'screen-share-start-button'\n            }\n            disabled={disableScreenShareButton}\n            onClick={handleClick}\n          >\n            <Icon\n              icon={\n                isSomeoneScreenSharing ? 'screen-share-on' : 'screen-share-off'\n              }\n            />\n          </CompositeButton>\n        </WithTooltip>\n      </PermissionNotification>\n    </Restricted>\n  );\n};\n","import { useEffect, useState } from 'react';\nimport { createSoundDetector } from '@stream-io/video-client';\nimport { useCallStateHooks } from '@stream-io/video-react-bindings';\nimport { Icon } from '../Icon';\n\nexport const AudioVolumeIndicator = () => {\n  const { useMicrophoneState } = useCallStateHooks();\n  const { isEnabled, mediaStream } = useMicrophoneState();\n  const [audioLevel, setAudioLevel] = useState(0);\n\n  useEffect(() => {\n    if (!isEnabled || !mediaStream) return;\n    const disposeSoundDetector = createSoundDetector(\n      mediaStream,\n      ({ audioLevel: al }) => setAudioLevel(al),\n      { detectionFrequencyInMs: 80, destroyStreamOnStop: false },\n    );\n    return () => {\n      disposeSoundDetector().catch(console.error);\n    };\n  }, [isEnabled, mediaStream]);\n\n  return (\n    <div className=\"str-video__audio-volume-indicator\">\n      <Icon icon={isEnabled ? 'mic' : 'mic-off'} />\n      <div className=\"str-video__audio-volume-indicator__bar\">\n        <div\n          className=\"str-video__audio-volume-indicator__bar-value\"\n          style={{ transform: `scaleX(${audioLevel / 100})` }}\n        />\n      </div>\n    </div>\n  );\n};\n","import {\n  createContext,\n  ReactElement,\n  ReactNode,\n  useCallback,\n  useContext,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport clsx from 'clsx';\nimport {\n  autoUpdate,\n  flip,\n  FloatingFocusManager,\n  FloatingList,\n  useClick,\n  useDismiss,\n  useFloating,\n  useInteractions,\n  useListItem,\n  useListNavigation,\n  useRole,\n  useTypeahead,\n} from '@floating-ui/react';\n\nimport { Icon } from '../Icon';\n\ninterface SelectContextValue {\n  activeIndex: number | null;\n  selectedIndex: number | null;\n  getItemProps: ReturnType<typeof useInteractions>['getItemProps'];\n  handleSelect: (index: number | null) => void;\n}\n\nconst SelectContext = createContext<SelectContextValue>(\n  {} as SelectContextValue,\n);\n\nconst Select = (props: {\n  children: ReactNode;\n  icon?: string;\n  defaultSelectedLabel: string;\n  defaultSelectedIndex: number;\n  handleSelect: (index: number) => void;\n}) => {\n  const {\n    children,\n    icon,\n    defaultSelectedLabel,\n    defaultSelectedIndex,\n    handleSelect: handleSelectProp,\n  } = props;\n  const [isOpen, setIsOpen] = useState(false);\n  const [activeIndex, setActiveIndex] = useState<number | null>(null);\n  const [selectedIndex, setSelectedIndex] = useState<number | null>(\n    defaultSelectedIndex,\n  );\n  const [selectedLabel, setSelectedLabel] = useState<string | null>(\n    defaultSelectedLabel,\n  );\n\n  const { refs, context } = useFloating({\n    placement: 'bottom-start',\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    whileElementsMounted: autoUpdate,\n    middleware: [flip()],\n  });\n\n  const elementsRef = useRef<Array<HTMLElement | null>>([]);\n  const labelsRef = useRef<Array<string | null>>([]);\n\n  const handleSelect = useCallback(\n    (index: number | null) => {\n      setSelectedIndex(index);\n      handleSelectProp(index || 0);\n      setIsOpen(false);\n      if (index !== null) {\n        setSelectedLabel(labelsRef.current[index]);\n      }\n    },\n    [handleSelectProp],\n  );\n\n  const handleTypeaheadMatch = (index: number | null) => {\n    if (isOpen) {\n      setActiveIndex(index);\n    } else {\n      handleSelect(index);\n    }\n  };\n\n  const listNav = useListNavigation(context, {\n    listRef: elementsRef,\n    activeIndex,\n    selectedIndex,\n    onNavigate: setActiveIndex,\n  });\n  const typeahead = useTypeahead(context, {\n    listRef: labelsRef,\n    activeIndex,\n    selectedIndex,\n    onMatch: handleTypeaheadMatch,\n  });\n  const click = useClick(context);\n  const dismiss = useDismiss(context);\n  const role = useRole(context, { role: 'listbox' });\n\n  const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(\n    [listNav, typeahead, click, dismiss, role],\n  );\n\n  const selectContext = useMemo(\n    () => ({\n      activeIndex,\n      selectedIndex,\n      getItemProps,\n      handleSelect,\n    }),\n    [activeIndex, selectedIndex, getItemProps, handleSelect],\n  );\n\n  return (\n    <div className=\"str-video__dropdown\">\n      <div\n        className=\"str-video__dropdown-selected\"\n        ref={refs.setReference}\n        tabIndex={0}\n        {...getReferenceProps()}\n      >\n        <label className=\"str-video__dropdown-selected__label\">\n          {icon && (\n            <Icon className=\"str-video__dropdown-selected__icon\" icon={icon} />\n          )}\n          {selectedLabel}\n        </label>\n        <Icon\n          className=\"str-video__dropdown-selected__chevron\"\n          icon={isOpen ? 'chevron-up' : 'chevron-down'}\n        />\n      </div>\n      <SelectContext.Provider value={selectContext}>\n        {isOpen && (\n          <FloatingFocusManager context={context} modal={false}>\n            <div\n              className=\"str-video__dropdown-list\"\n              ref={refs.setFloating}\n              {...getFloatingProps()}\n            >\n              <FloatingList elementsRef={elementsRef} labelsRef={labelsRef}>\n                {children}\n              </FloatingList>\n            </div>\n          </FloatingFocusManager>\n        )}\n      </SelectContext.Provider>\n    </div>\n  );\n};\n\nexport type DropDownSelectOptionProps = {\n  label: string;\n  selected?: boolean;\n  icon?: string;\n};\n\nexport const DropDownSelectOption = (props: DropDownSelectOptionProps) => {\n  const { selected, label, icon } = props;\n  const { getItemProps, handleSelect } = useContext(SelectContext);\n  const { ref, index } = useListItem();\n  return (\n    <div\n      className={clsx('str-video__dropdown-option', {\n        'str-video__dropdown-option--selected': selected,\n      })}\n      ref={ref}\n      {...getItemProps({\n        onClick: () => handleSelect(index),\n      })}\n    >\n      {icon && <Icon className=\"str-video__dropdown-icon\" icon={icon} />}\n      <span className=\"str-video__dropdown-label\">{label}</span>\n    </div>\n  );\n};\n\nexport const DropDownSelect = (props: {\n  icon?: string;\n  defaultSelectedLabel: string;\n  defaultSelectedIndex: number;\n  handleSelect: (index: number) => void;\n  children:\n    | ReactElement<DropDownSelectOptionProps>\n    | ReactElement<DropDownSelectOptionProps>[];\n}) => {\n  const {\n    children,\n    icon,\n    handleSelect,\n    defaultSelectedLabel,\n    defaultSelectedIndex,\n  } = props;\n  return (\n    <Select\n      icon={icon}\n      handleSelect={handleSelect}\n      defaultSelectedIndex={defaultSelectedIndex}\n      defaultSelectedLabel={defaultSelectedLabel}\n    >\n      {children}\n    </Select>\n  );\n};\n","import clsx from 'clsx';\nimport { ChangeEventHandler, PropsWithChildren, useCallback } from 'react';\n\nimport { useDeviceList } from '../../hooks';\nimport { DropDownSelect, DropDownSelectOption } from '../DropdownSelect';\nimport { useMenuContext } from '../Menu';\n\ntype DeviceSelectorOptionProps = {\n  id: string;\n  label: string;\n  name?: string;\n  selected?: boolean;\n  value: string;\n  disabled?: boolean;\n  defaultChecked?: boolean;\n  onChange?: ChangeEventHandler<HTMLInputElement>;\n};\n\nconst DeviceSelectorOption = ({\n  disabled,\n  id,\n  label,\n  onChange,\n  name,\n  selected,\n  defaultChecked,\n  value,\n}: DeviceSelectorOptionProps) => {\n  return (\n    <label\n      className={clsx('str-video__device-settings__option', {\n        'str-video__device-settings__option--selected': selected,\n        'str-video__device-settings__option--disabled': disabled,\n      })}\n      htmlFor={id}\n    >\n      <input\n        type=\"radio\"\n        name={name}\n        onChange={onChange}\n        value={value}\n        id={id}\n        checked={selected}\n        defaultChecked={defaultChecked}\n        disabled={disabled}\n      />\n      {label}\n    </label>\n  );\n};\n\nexport type DeviceSelectorType = 'audioinput' | 'audiooutput' | 'videoinput';\n\nconst DeviceSelectorList = (\n  props: PropsWithChildren<{\n    devices: MediaDeviceInfo[];\n    type: DeviceSelectorType;\n    selectedDeviceId?: string;\n    title?: string;\n    onChange?: (deviceId: string) => void;\n  }>,\n) => {\n  const {\n    devices = [],\n    selectedDeviceId,\n    title,\n    type,\n    onChange,\n    children,\n  } = props;\n  const { close } = useMenuContext();\n  const { deviceList } = useDeviceList(devices, selectedDeviceId);\n\n  return (\n    <div className=\"str-video__device-settings__device-kind\">\n      {title && (\n        <div className=\"str-video__device-settings__device-selector-title\">\n          {title}\n        </div>\n      )}\n      {deviceList.map((device) => {\n        return (\n          <DeviceSelectorOption\n            id={`${type}--${device.deviceId}`}\n            value={device.deviceId}\n            label={device.label}\n            key={device.deviceId}\n            onChange={(e) => {\n              const deviceId = e.target.value;\n              if (deviceId !== 'default') {\n                onChange?.(deviceId);\n              }\n              close?.();\n            }}\n            name={type}\n            selected={device.isSelected}\n          />\n        );\n      })}\n      {children}\n    </div>\n  );\n};\n\nconst DeviceSelectorDropdown = (props: {\n  devices: MediaDeviceInfo[];\n  selectedDeviceId?: string;\n  title?: string;\n  onChange?: (deviceId: string) => void;\n  icon: string;\n}) => {\n  const { devices = [], selectedDeviceId, title, onChange, icon } = props;\n  const { deviceList, selectedDeviceInfo, selectedIndex } = useDeviceList(\n    devices,\n    selectedDeviceId,\n  );\n\n  const handleSelect = useCallback(\n    (index: number) => {\n      const deviceId = deviceList[index].deviceId;\n      if (deviceId !== 'default') {\n        onChange?.(deviceId);\n      }\n    },\n    [deviceList, onChange],\n  );\n\n  return (\n    <div className=\"str-video__device-settings__device-kind\">\n      <div className=\"str-video__device-settings__device-selector-title\">\n        {title}\n      </div>\n      <DropDownSelect\n        icon={icon}\n        defaultSelectedIndex={selectedIndex}\n        defaultSelectedLabel={selectedDeviceInfo.label}\n        handleSelect={handleSelect}\n      >\n        {deviceList.map((device) => (\n          <DropDownSelectOption\n            key={device.deviceId}\n            icon={icon}\n            label={device.label}\n            selected={device.isSelected}\n          />\n        ))}\n      </DropDownSelect>\n    </div>\n  );\n};\n\nexport const DeviceSelector = (\n  props: PropsWithChildren<{\n    devices: MediaDeviceInfo[];\n    icon: string;\n    type: DeviceSelectorType;\n    selectedDeviceId?: string;\n    title?: string;\n    onChange?: (deviceId: string) => void;\n    visualType?: 'list' | 'dropdown';\n  }>,\n) => {\n  const { visualType = 'list', icon, ...rest } = props;\n\n  if (visualType === 'list') {\n    return <DeviceSelectorList {...rest} />;\n  }\n  return <DeviceSelectorDropdown {...rest} icon={icon} />;\n};\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';\nimport { CompositeButton } from '../Button';\nimport { Icon } from '../Icon';\n\n/**\n * SpeakerTest component that plays a test audio through the selected speaker.\n * This allows users to verify their audio output device is working correctly.\n */\nexport const SpeakerTest = (props: { audioUrl?: string }) => {\n  const { useSpeakerState } = useCallStateHooks();\n  const { selectedDevice } = useSpeakerState();\n  const audioElementRef = useRef<HTMLAudioElement | null>(null);\n  const [isPlaying, setIsPlaying] = useState(false);\n  const { t } = useI18n();\n\n  const {\n    audioUrl = `https://unpkg.com/${process.env.PKG_NAME}@${process.env.PKG_VERSION}/assets/piano.mp3`,\n  } = props;\n\n  // Update audio output device when selection changes\n  useEffect(() => {\n    const audio = audioElementRef.current;\n    if (!audio || !selectedDevice) return;\n\n    // Set the sinkId to route audio to the selected speaker\n    if ('setSinkId' in audio) {\n      audio.setSinkId(selectedDevice).catch((err) => {\n        console.error('Failed to set audio output device:', err);\n      });\n    }\n  }, [selectedDevice]);\n\n  const handleStartTest = useCallback(async () => {\n    const audio = audioElementRef.current;\n    if (!audio) return;\n\n    audio.src = audioUrl;\n\n    try {\n      if (isPlaying) {\n        audio.pause();\n        audio.currentTime = 0;\n        setIsPlaying(false);\n      } else {\n        await audio.play();\n        setIsPlaying(true);\n      }\n    } catch (err) {\n      console.error('Failed to play test audio:', err);\n      setIsPlaying(false);\n    }\n  }, [isPlaying, audioUrl]);\n\n  const handleAudioEnded = useCallback(() => setIsPlaying(false), []);\n  return (\n    <div className=\"str-video__speaker-test\">\n      <audio\n        ref={audioElementRef}\n        onEnded={handleAudioEnded}\n        onPause={handleAudioEnded}\n      />\n      <CompositeButton\n        className=\"str-video__speaker-test__button\"\n        onClick={handleStartTest}\n        type=\"button\"\n      >\n        <div className=\"str-video__speaker-test__button-content\">\n          <Icon icon=\"speaker\" />\n          {isPlaying ? t('Stop test') : t('Test speaker')}\n        </div>\n      </CompositeButton>\n    </div>\n  );\n};\n","import { useCallStateHooks } from '@stream-io/video-react-bindings';\nimport { DeviceSelector } from './DeviceSelector';\nimport { AudioVolumeIndicator } from './AudioVolumeIndicator';\nimport { SpeakerTest } from './SpeakerTest';\n\nexport type DeviceSelectorAudioInputProps = {\n  title?: string;\n  visualType?: 'list' | 'dropdown';\n  volumeIndicatorVisible?: boolean;\n};\n\nexport const DeviceSelectorAudioInput = ({\n  title,\n  visualType,\n  volumeIndicatorVisible = true,\n}: DeviceSelectorAudioInputProps) => {\n  const { useMicrophoneState } = useCallStateHooks();\n  const { microphone, selectedDevice, devices } = useMicrophoneState();\n\n  return (\n    <DeviceSelector\n      devices={devices || []}\n      selectedDeviceId={selectedDevice}\n      type=\"audioinput\"\n      onChange={async (deviceId) => {\n        await microphone.select(deviceId);\n      }}\n      title={title}\n      visualType={visualType}\n      icon=\"mic\"\n    >\n      {volumeIndicatorVisible && (\n        <>\n          <hr className=\"str-video__device-settings__separator\" />\n          <AudioVolumeIndicator />\n        </>\n      )}\n    </DeviceSelector>\n  );\n};\n\nexport type DeviceSelectorAudioOutputProps = {\n  title?: string;\n  visualType?: 'list' | 'dropdown';\n  speakerTestVisible?: boolean;\n  speakerTestAudioUrl?: string;\n};\n\nexport const DeviceSelectorAudioOutput = ({\n  title,\n  visualType,\n  speakerTestVisible = true,\n  speakerTestAudioUrl,\n}: DeviceSelectorAudioOutputProps) => {\n  const { useSpeakerState } = useCallStateHooks();\n  const { speaker, selectedDevice, devices, isDeviceSelectionSupported } =\n    useSpeakerState();\n\n  if (!isDeviceSelectionSupported) return null;\n\n  return (\n    <DeviceSelector\n      devices={devices}\n      type=\"audiooutput\"\n      selectedDeviceId={selectedDevice}\n      onChange={(deviceId) => {\n        speaker.select(deviceId);\n      }}\n      title={title}\n      visualType={visualType}\n      icon=\"speaker\"\n    >\n      {speakerTestVisible && (\n        <>\n          <hr className=\"str-video__device-settings__separator\" />\n          <SpeakerTest audioUrl={speakerTestAudioUrl} />\n        </>\n      )}\n    </DeviceSelector>\n  );\n};\n","import { DeviceSelector } from './DeviceSelector';\nimport { useCallStateHooks } from '@stream-io/video-react-bindings';\n\nexport type DeviceSelectorVideoProps = {\n  title?: string;\n  visualType?: 'list' | 'dropdown';\n};\n\nexport const DeviceSelectorVideo = ({\n  title,\n  visualType,\n}: DeviceSelectorVideoProps) => {\n  const { useCameraState } = useCallStateHooks();\n  const { camera, devices, selectedDevice } = useCameraState();\n\n  return (\n    <DeviceSelector\n      devices={devices || []}\n      type=\"videoinput\"\n      selectedDeviceId={selectedDevice}\n      onChange={async (deviceId) => {\n        await camera.select(deviceId);\n      }}\n      title={title}\n      visualType={visualType}\n      icon=\"camera\"\n    />\n  );\n};\n","import { forwardRef } from 'react';\nimport { useI18n } from '@stream-io/video-react-bindings';\nimport clsx from 'clsx';\nimport { MenuToggle, MenuVisualType, ToggleMenuButtonProps } from '../Menu';\nimport {\n  DeviceSelectorAudioInput,\n  DeviceSelectorAudioOutput,\n} from './DeviceSelectorAudio';\nimport { DeviceSelectorVideo } from './DeviceSelectorVideo';\nimport { IconButton } from '../Button';\n\nexport type DeviceSettingsProps = {\n  visualType?: MenuVisualType;\n};\n\nexport const DeviceSettings = ({\n  visualType = MenuVisualType.MENU,\n}: DeviceSettingsProps) => {\n  return (\n    <MenuToggle\n      placement=\"bottom-end\"\n      ToggleButton={ToggleDeviceSettingsMenuButton}\n      visualType={visualType}\n    >\n      <Menu />\n    </MenuToggle>\n  );\n};\n\nconst Menu = () => {\n  const { t } = useI18n();\n  return (\n    <div className=\"str-video__device-settings\">\n      <DeviceSelectorVideo title={t('Select a Camera')} />\n      <DeviceSelectorAudioInput title={t('Select a Mic')} />\n      <DeviceSelectorAudioOutput title={t('Select Speakers')} />\n    </div>\n  );\n};\n\nconst ToggleDeviceSettingsMenuButton = forwardRef<\n  HTMLButtonElement,\n  ToggleMenuButtonProps\n>(function ToggleDeviceSettingsMenuButton({ menuShown }, ref) {\n  const { t } = useI18n();\n  return (\n    <IconButton\n      className={clsx('str-video__device-settings__button', {\n        'str-video__device-settings__button--active': menuShown,\n      })}\n      title={t('Toggle device menu')}\n      icon=\"device-settings\"\n      ref={ref}\n    />\n  );\n});\n","import { OwnCapability } from '@stream-io/video-client';\nimport {\n  Restricted,\n  useCallStateHooks,\n  useI18n,\n  type UseInputMediaDeviceOptions,\n} from '@stream-io/video-react-bindings';\nimport clsx from 'clsx';\nimport { CompositeButton, IconButtonWithMenuProps } from '../Button';\nimport { DeviceSelectorAudioInput } from '../DeviceSettings';\nimport { PermissionNotification } from '../Notification';\nimport { useRequestPermission } from '../../hooks';\nimport { Icon } from '../Icon';\nimport { WithTooltip } from '../Tooltip';\nimport { useState } from 'react';\nimport {\n  createCallControlHandler,\n  PropsWithErrorHandler,\n} from '../../utilities/callControlHandler';\n\nexport type ToggleAudioPreviewButtonProps = PropsWithErrorHandler<\n  Pick<\n    IconButtonWithMenuProps,\n    'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'\n  > &\n    UseInputMediaDeviceOptions\n>;\n\nexport const ToggleAudioPreviewButton = (\n  props: ToggleAudioPreviewButtonProps,\n) => {\n  const {\n    caption,\n    Menu = DeviceSelectorAudioInput,\n    menuPlacement = 'top',\n    onMenuToggle,\n    optimisticUpdates,\n    ...restCompositeButtonProps\n  } = props;\n  const { t } = useI18n();\n  const { useMicrophoneState } = useCallStateHooks();\n  const {\n    microphone,\n    hasBrowserPermission,\n    isPromptingPermission,\n    optionsAwareIsMute,\n    isTogglePending,\n  } = useMicrophoneState({ optimisticUpdates });\n  const [tooltipDisabled, setTooltipDisabled] = useState(false);\n  const handleClick = createCallControlHandler(props, () =>\n    microphone.toggle(),\n  );\n\n  return (\n    <WithTooltip\n      title={\n        !hasBrowserPermission\n          ? t('Check your browser audio permissions')\n          : (caption ?? t('Mic'))\n      }\n      tooltipDisabled={tooltipDisabled}\n    >\n      <CompositeButton\n        active={optionsAwareIsMute}\n        caption={caption}\n        className={clsx(\n          !hasBrowserPermission && 'str-video__device-unavailable',\n        )}\n        variant=\"secondary\"\n        disabled={\n          !hasBrowserPermission || (!optimisticUpdates && isTogglePending)\n        }\n        data-testid={\n          optionsAwareIsMute\n            ? 'preview-audio-unmute-button'\n            : 'preview-audio-mute-button'\n        }\n        onClick={handleClick}\n        Menu={Menu}\n        menuPlacement={menuPlacement}\n        {...restCompositeButtonProps}\n        onMenuToggle={(shown) => {\n          setTooltipDisabled(shown);\n          onMenuToggle?.(shown);\n        }}\n      >\n        <Icon icon={!optionsAwareIsMute ? 'mic' : 'mic-off'} />\n        {!hasBrowserPermission && (\n          <span\n            className=\"str-video__no-media-permission\"\n            title={t('Check your browser audio permissions')}\n            children=\"!\"\n          />\n        )}\n        {isPromptingPermission && (\n          <span\n            className=\"str-video__pending-permission\"\n            title={t('Waiting for permission')}\n            children=\"?\"\n          />\n        )}\n      </CompositeButton>\n    </WithTooltip>\n  );\n};\n\nexport type ToggleAudioPublishingButtonProps = PropsWithErrorHandler<\n  Pick<\n    IconButtonWithMenuProps,\n    'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'\n  > &\n    UseInputMediaDeviceOptions\n>;\n\nexport const ToggleAudioPublishingButton = (\n  props: ToggleAudioPublishingButtonProps,\n) => {\n  const { t } = useI18n();\n  const {\n    caption,\n    Menu = <DeviceSelectorAudioInput visualType=\"list\" />,\n    menuPlacement = 'top',\n    onMenuToggle,\n    optimisticUpdates,\n    ...restCompositeButtonProps\n  } = props;\n\n  const { hasPermission, requestPermission, isAwaitingPermission } =\n    useRequestPermission(OwnCapability.SEND_AUDIO);\n\n  const { useMicrophoneState } = useCallStateHooks();\n  const {\n    microphone,\n    hasBrowserPermission,\n    isPromptingPermission,\n    isTogglePending,\n    optionsAwareIsMute,\n  } = useMicrophoneState({ optimisticUpdates });\n\n  const [tooltipDisabled, setTooltipDisabled] = useState(false);\n  const handleClick = createCallControlHandler(props, async () => {\n    if (!hasPermission) {\n      await requestPermission();\n    } else {\n      await microphone.toggle();\n    }\n  });\n\n  return (\n    <Restricted requiredGrants={[OwnCapability.SEND_AUDIO]}>\n      <PermissionNotification\n        permission={OwnCapability.SEND_AUDIO}\n        isAwaitingApproval={isAwaitingPermission}\n        messageApproved={t('You can now speak.')}\n        messageAwaitingApproval={t('Awaiting for an approval to speak.')}\n        messageRevoked={t('You can no longer speak.')}\n      >\n        <WithTooltip\n          title={\n            !hasPermission\n              ? t('You have no permission to share your audio')\n              : !hasBrowserPermission\n                ? t('Check your browser mic permissions')\n                : (caption ?? t('Mic'))\n          }\n          tooltipDisabled={tooltipDisabled}\n        >\n          <CompositeButton\n            active={optionsAwareIsMute}\n            caption={caption}\n            variant=\"secondary\"\n            disabled={\n              !hasBrowserPermission ||\n              !hasPermission ||\n              // disable button while the toggle action is pending when not using optimistic updates\n              (!optimisticUpdates && isTogglePending)\n            }\n            data-testid={\n              optionsAwareIsMute ? 'audio-unmute-button' : 'audio-mute-button'\n            }\n            onClick={handleClick}\n            Menu={Menu}\n            menuPlacement={menuPlacement}\n            menuOffset={16}\n            {...restCompositeButtonProps}\n            onMenuToggle={(shown) => {\n              setTooltipDisabled(shown);\n              onMenuToggle?.(shown);\n            }}\n          >\n            <Icon icon={optionsAwareIsMute ? 'mic-off' : 'mic'} />\n            {(!hasBrowserPermission || !hasPermission) && (\n              <span className=\"str-video__no-media-permission\">!</span>\n            )}\n            {isPromptingPermission && (\n              <span\n                className=\"str-video__pending-permission\"\n                title={t('Waiting for permission')}\n              >\n                ?\n              </span>\n            )}\n          </CompositeButton>\n        </WithTooltip>\n      </PermissionNotification>\n    </Restricted>\n  );\n};\n","import {\n  Restricted,\n  useCallStateHooks,\n  useI18n,\n  UseInputMediaDeviceOptions,\n} from '@stream-io/video-react-bindings';\nimport clsx from 'clsx';\nimport { OwnCapability } from '@stream-io/video-client';\nimport { CompositeButton, IconButtonWithMenuProps } from '../Button/';\nimport { DeviceSelectorVideo } from '../DeviceSettings';\nimport { PermissionNotification } from '../Notification';\nimport { useRequestPermission } from '../../hooks';\nimport { Icon } from '../Icon';\nimport { WithTooltip } from '../Tooltip';\nimport { useState } from 'react';\nimport {\n  createCallControlHandler,\n  PropsWithErrorHandler,\n} from '../../utilities/callControlHandler';\n\nexport type ToggleVideoPreviewButtonProps = PropsWithErrorHandler<\n  Pick<\n    IconButtonWithMenuProps,\n    'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'\n  > &\n    UseInputMediaDeviceOptions\n>;\n\nexport const ToggleVideoPreviewButton = (\n  props: ToggleVideoPreviewButtonProps,\n) => {\n  const {\n    caption,\n    Menu = DeviceSelectorVideo,\n    menuPlacement = 'top',\n    onMenuToggle,\n    optimisticUpdates,\n    ...restCompositeButtonProps\n  } = props;\n  const { t } = useI18n();\n  const { useCameraState } = useCallStateHooks();\n  const {\n    camera,\n    hasBrowserPermission,\n    isPromptingPermission,\n    isTogglePending,\n    optionsAwareIsMute,\n  } = useCameraState({ optimisticUpdates });\n  const [tooltipDisabled, setTooltipDisabled] = useState(false);\n  const handleClick = createCallControlHandler(props, () => camera.toggle());\n\n  return (\n    <WithTooltip\n      title={\n        !hasBrowserPermission\n          ? t('Check your browser video permissions')\n          : (caption ?? t('Video'))\n      }\n      tooltipDisabled={tooltipDisabled}\n    >\n      <CompositeButton\n        active={optionsAwareIsMute}\n        caption={caption}\n        className={clsx(\n          !hasBrowserPermission && 'str-video__device-unavailable',\n        )}\n        variant=\"secondary\"\n        data-testid={\n          optionsAwareIsMute\n            ? 'preview-video-unmute-button'\n            : 'preview-video-mute-button'\n        }\n        onClick={handleClick}\n        disabled={\n          !hasBrowserPermission || (!optimisticUpdates && isTogglePending)\n        }\n        Menu={Menu}\n        menuPlacement={menuPlacement}\n        {...restCompositeButtonProps}\n        onMenuToggle={(shown) => {\n          setTooltipDisabled(shown);\n          onMenuToggle?.(shown);\n        }}\n      >\n        <Icon icon={!optionsAwareIsMute ? 'camera' : 'camera-off'} />\n        {!hasBrowserPermission && (\n          <span\n            className=\"str-video__no-media-permission\"\n            title={t('Check your browser video permissions')}\n            children=\"!\"\n          />\n        )}\n        {isPromptingPermission && (\n          <span\n            className=\"str-video__pending-permission\"\n            title={t('Waiting for permission')}\n            children=\"?\"\n          />\n        )}\n      </CompositeButton>\n    </WithTooltip>\n  );\n};\n\ntype ToggleVideoPublishingButtonProps = PropsWithErrorHandler<\n  Pick<\n    IconButtonWithMenuProps,\n    'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'\n  > &\n    UseInputMediaDeviceOptions\n>;\n\nexport const ToggleVideoPublishingButton = (\n  props: ToggleVideoPublishingButtonProps,\n) => {\n  const { t } = useI18n();\n  const {\n    caption,\n    Menu = <DeviceSelectorVideo visualType=\"list\" />,\n    menuPlacement = 'top',\n    onMenuToggle,\n    optimisticUpdates,\n    ...restCompositeButtonProps\n  } = props;\n\n  const { hasPermission, requestPermission, isAwaitingPermission } =\n    useRequestPermission(OwnCapability.SEND_VIDEO);\n\n  const { useCameraState, useCallSettings } = useCallStateHooks();\n  const {\n    camera,\n    optionsAwareIsMute,\n    hasBrowserPermission,\n    isPromptingPermission,\n    isTogglePending,\n  } = useCameraState({ optimisticUpdates });\n  const callSettings = useCallSettings();\n  const isPublishingVideoAllowed = callSettings?.video.enabled;\n  const [tooltipDisabled, setTooltipDisabled] = useState(false);\n  const handleClick = createCallControlHandler(props, async () => {\n    if (!hasPermission) {\n      await requestPermission();\n    } else {\n      await camera.toggle();\n    }\n  });\n\n  return (\n    <Restricted requiredGrants={[OwnCapability.SEND_VIDEO]}>\n      <PermissionNotification\n        permission={OwnCapability.SEND_VIDEO}\n        isAwaitingApproval={isAwaitingPermission}\n        messageApproved={t('You can now share your video.')}\n        messageAwaitingApproval={t(\n          'Awaiting for an approval to share your video.',\n        )}\n        messageRevoked={t('You can no longer share your video.')}\n      >\n        <WithTooltip\n          title={\n            !hasPermission\n              ? t('You have no permission to share your video')\n              : !hasBrowserPermission\n                ? t('Check your browser video permissions')\n                : !isPublishingVideoAllowed\n                  ? t('Video publishing is disabled by the system')\n                  : caption || t('Video')\n          }\n          tooltipDisabled={tooltipDisabled}\n        >\n          <CompositeButton\n            active={optionsAwareIsMute}\n            caption={caption}\n            variant=\"secondary\"\n            disabled={\n              !hasBrowserPermission ||\n              !hasPermission ||\n              !isPublishingVideoAllowed ||\n              (!optimisticUpdates && isTogglePending)\n            }\n            data-testid={\n              optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button'\n            }\n            onClick={handleClick}\n            Menu={Menu}\n            menuPlacement={menuPlacement}\n            menuOffset={16}\n            {...restCompositeButtonProps}\n            onMenuToggle={(shown) => {\n              setTooltipDisabled(shown);\n              onMenuToggle?.(shown);\n            }}\n          >\n            <Icon icon={optionsAwareIsMute ? 'camera-off' : 'camera'} />\n            {(!hasBrowserPermission ||\n              !hasPermission ||\n              !isPublishingVideoAllowed) && (\n              <span className=\"str-video__no-media-permission\">!</span>\n            )}\n            {isPromptingPermission && (\n              <span\n                className=\"str-video__pending-permission\"\n                title={t('Waiting for permission')}\n              >\n                ?\n              </span>\n            )}\n          </CompositeButton>\n        </WithTooltip>\n      </PermissionNotification>\n    </Restricted>\n  );\n};\n","import { forwardRef, MouseEventHandler, useCallback } from 'react';\nimport { OwnCapability } from '@stream-io/video-client';\nimport { Restricted, useCall, useI18n } from '@stream-io/video-react-bindings';\n\nimport { MenuToggle, ToggleMenuButtonProps } from '../Menu';\n\nimport { IconButton } from '../Button';\nimport { Icon } from '../Icon';\nimport { WithTooltip } from '../Tooltip';\n\nconst EndCallMenu = (props: {\n  onLeave: MouseEventHandler<HTMLButtonElement>;\n  onEnd: MouseEventHandler<HTMLButtonElement>;\n}) => {\n  const { onLeave, onEnd } = props;\n  const { t } = useI18n();\n  return (\n    <div className=\"str-video__end-call__confirmation\">\n      <button\n        className=\"str-video__button str-video__end-call__leave\"\n        type=\"button\"\n        data-testid=\"leave-call-button\"\n        onClick={onLeave}\n      >\n        <Icon\n          className=\"str-video__button__icon str-video__end-call__leave-icon\"\n          icon=\"logout\"\n        />\n        {t('Leave call')}\n      </button>\n      <Restricted requiredGrants={[OwnCapability.END_CALL]}>\n        <button\n          className=\"str-video__button str-video__end-call__end\"\n          type=\"button\"\n          data-testid=\"end-call-for-all-button\"\n          onClick={onEnd}\n        >\n          <Icon\n            className=\"str-video__button__icon str-video__end-call__end-icon\"\n            icon=\"call-end\"\n          />\n          {t('End call for all')}\n        </button>\n      </Restricted>\n    </div>\n  );\n};\n\nconst CancelCallToggleMenuButton = forwardRef<\n  HTMLButtonElement,\n  ToggleMenuButtonProps\n>(function CancelCallToggleMenuButton({ menuShown }, ref) {\n  const { t } = useI18n();\n  return (\n    <WithTooltip title={t('Leave call')} tooltipDisabled={menuShown}>\n      <IconButton\n        icon={menuShown ? 'close' : 'call-end'}\n        variant={menuShown ? 'active' : 'danger'}\n        data-testid=\"leave-call-button\"\n        ref={ref}\n      />\n    </WithTooltip>\n  );\n});\n\nexport type CancelCallButtonProps = {\n  disabled?: boolean;\n  caption?: string;\n  onClick?: MouseEventHandler<HTMLButtonElement>;\n  onLeave?: () => void;\n};\n\nexport const CancelCallConfirmButton = ({\n  onClick,\n  onLeave,\n}: CancelCallButtonProps) => {\n  const call = useCall();\n\n  const handleLeave: MouseEventHandler<HTMLButtonElement> = useCallback(\n    async (e) => {\n      if (onClick) {\n        onClick(e);\n      } else if (call) {\n        await call.leave();\n        onLeave?.();\n      }\n    },\n    [onClick, onLeave, call],\n  );\n\n  const handleEndCall: MouseEventHandler<HTMLButtonElement> = useCallback(\n    async (e) => {\n      if (onClick) {\n        onClick(e);\n      } else if (call) {\n        await call.endCall();\n        onLeave?.();\n      }\n    },\n    [onClick, onLeave, call],\n  );\n\n  return (\n    <MenuToggle placement=\"top-start\" ToggleButton={CancelCallToggleMenuButton}>\n      <EndCallMenu onEnd={handleEndCall} onLeave={handleLeave} />\n    </MenuToggle>\n  );\n};\n\nexport const CancelCallButton = ({\n  disabled,\n  caption,\n  onClick,\n  onLeave,\n}: CancelCallButtonProps) => {\n  const call = useCall();\n  const { t } = useI18n();\n  const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(\n    async (e) => {\n      if (onClick) {\n        onClick(e);\n      } else if (call) {\n        await call.leave();\n        onLeave?.();\n      }\n    },\n    [onClick, onLeave, call],\n  );\n  return (\n    <IconButton\n      disabled={disabled}\n      icon=\"call-end\"\n      variant=\"danger\"\n      title={caption ?? t('Leave call')}\n      data-testid=\"cancel-call-button\"\n      onClick={handleClick}\n    />\n  );\n};\n","import { OwnCapability } from '@stream-io/video-client';\nimport { Restricted } from '@stream-io/video-react-bindings';\nimport { SpeakingWhileMutedNotification } from '../Notification';\nimport { RecordCallButton } from './RecordCallButton';\nimport { ReactionsButton } from './ReactionsButton';\nimport { ScreenShareButton } from './ScreenShareButton';\nimport { ToggleAudioPublishingButton } from './ToggleAudioButton';\nimport { ToggleVideoPublishingButton } from './ToggleVideoButton';\nimport { CancelCallButton } from './CancelCallButton';\n\nexport type CallControlsProps = {\n  onLeave?: () => void;\n};\n\nexport const CallControls = ({ onLeave }: CallControlsProps) => (\n  <div className=\"str-video__call-controls\">\n    <Restricted requiredGrants={[OwnCapability.SEND_AUDIO]}>\n      <SpeakingWhileMutedNotification>\n        <ToggleAudioPublishingButton />\n      </SpeakingWhileMutedNotification>\n    </Restricted>\n    <Restricted requiredGrants={[OwnCapability.SEND_VIDEO]}>\n      <ToggleVideoPublishingButton />\n    </Restricted>\n    <Restricted requiredGrants={[OwnCapability.CREATE_REACTION]}>\n      <ReactionsButton />\n    </Restricted>\n    <Restricted requiredGrants={[OwnCapability.SCREENSHARE]}>\n      <ScreenShareButton />\n    </Restricted>\n    <Restricted\n      requiredGrants={[\n        OwnCapability.START_RECORD_CALL,\n        OwnCapability.STOP_RECORD_CALL,\n      ]}\n    >\n      <RecordCallButton />\n    </Restricted>\n    <CancelCallButton onLeave={onLeave} />\n  </div>\n);\n","import { lazy, ReactNode, Suspense, useEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\nimport {\n  AggregatedStatsReport,\n  CallStatsReport,\n  SfuModels,\n} from '@stream-io/video-client';\nimport { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';\nimport { useFloating, useHover, useInteractions } from '@floating-ui/react';\nimport { Icon } from '../Icon';\n\nconst CallStatsLatencyChart = lazy(() => import('./CallStatsLatencyChart'));\n\nenum Status {\n  GOOD = 'Good',\n  OK = 'Ok',\n  BAD = 'Bad',\n}\n\nexport type CallStatsProps = {\n  latencyLowBound?: number;\n  latencyHighBound?: number;\n  showCodecInfo?: boolean;\n  LatencyChartSuspenseFallback?: ReactNode;\n};\n\nexport const CallStats = (props: CallStatsProps) => {\n  const {\n    latencyLowBound = 75,\n    latencyHighBound = 400,\n    showCodecInfo = false,\n    LatencyChartSuspenseFallback = null,\n  } = props;\n  const [latencyBuffer, setLatencyBuffer] = useState<\n    Array<{ x: number; y: number }>\n  >(() => {\n    const now = Date.now();\n    return Array.from({ length: 20 }, (_, i) => ({ x: now + i, y: 0 }));\n  });\n\n  const { t } = useI18n();\n  const [publishBitrate, setPublishBitrate] = useState('-');\n  const [subscribeBitrate, setSubscribeBitrate] = useState('-');\n  const previousStats = useRef<CallStatsReport>(undefined);\n  const { useCallStatsReport } = useCallStateHooks();\n  const callStatsReport = useCallStatsReport();\n\n  useEffect(() => {\n    if (!callStatsReport) return;\n    if (!previousStats.current) {\n      previousStats.current = callStatsReport;\n      return;\n    }\n    const previousCallStatsReport = previousStats.current;\n    setPublishBitrate(() => {\n      return calculatePublishBitrate(previousCallStatsReport, callStatsReport);\n    });\n    setSubscribeBitrate(() => {\n      return calculateSubscribeBitrate(\n        previousCallStatsReport,\n        callStatsReport,\n      );\n    });\n\n    setLatencyBuffer((latencyBuf) => {\n      const newLatencyBuffer = latencyBuf.slice(-19);\n      newLatencyBuffer.push({\n        x: callStatsReport.timestamp,\n        y: callStatsReport.publisherStats.averageRoundTripTimeInMs,\n      });\n      return newLatencyBuffer;\n    });\n\n    previousStats.current = callStatsReport;\n  }, [callStatsReport]);\n\n  const latencyComparison = {\n    lowBound: latencyLowBound,\n    highBound: latencyHighBound,\n    value: callStatsReport?.publisherStats.averageRoundTripTimeInMs || 0,\n  };\n\n  return (\n    <div className=\"str-video__call-stats\">\n      {callStatsReport && (\n        <>\n          <div className=\"str-video__call-stats__header\">\n            <h3 className=\"str-video__call-stats__heading\">\n              <Icon\n                className=\"str-video__call-stats__icon\"\n                icon=\"call-latency\"\n              />\n              {t('Call Latency')}\n            </h3>\n            <p className=\"str-video__call-stats__description\">\n              {t(\n                'Very high latency values may reduce call quality, cause lag, and make the call less enjoyable.',\n              )}\n            </p>\n          </div>\n\n          <div className=\"str-video__call-stats__latencychart\">\n            <Suspense fallback={LatencyChartSuspenseFallback}>\n              <CallStatsLatencyChart values={latencyBuffer} />\n            </Suspense>\n          </div>\n\n          <div className=\"str-video__call-stats__header\">\n            <h3 className=\"str-video__call-stats__heading\">\n              <Icon\n                className=\"str-video__call-stats__icon\"\n                icon=\"network-quality\"\n              />\n              {t('Call performance')}\n            </h3>\n            <p className=\"str-video__call-stats__description\">\n              {t('Review the key data points below to assess call performance')}\n            </p>\n          </div>\n\n          <div className=\"str-video__call-stats__card-container\">\n            <StatCard label={t('Region')} value={callStatsReport.datacenter} />\n            <StatCard\n              label={t('Latency')}\n              value={`${callStatsReport.publisherStats.averageRoundTripTimeInMs} ms.`}\n              comparison={latencyComparison}\n            />\n            <StatCard\n              label={t('Receive jitter')}\n              value={`${callStatsReport.subscriberStats.averageJitterInMs} ms.`}\n              comparison={{\n                ...latencyComparison,\n                value: callStatsReport.subscriberStats.averageJitterInMs,\n              }}\n            />\n            <StatCard\n              label={t('Publish jitter')}\n              value={`${callStatsReport.publisherStats.averageJitterInMs} ms.`}\n              comparison={{\n                ...latencyComparison,\n                value: callStatsReport.publisherStats.averageJitterInMs,\n              }}\n            />\n            <StatCard\n              label={`${t('Publish resolution')}${showCodecInfo ? formatCodec(callStatsReport) : ''}`}\n              value={toFrameSize(callStatsReport.publisherStats)}\n            />\n            <StatCard\n              label={t('Publish quality drop reason')}\n              value={callStatsReport.publisherStats.qualityLimitationReasons}\n            />\n            <StatCard\n              label={t('Receiving resolution')}\n              value={toFrameSize(callStatsReport.subscriberStats)}\n            />\n            <StatCard\n              label={t('Receive quality drop reason')}\n              value={callStatsReport.subscriberStats.qualityLimitationReasons}\n            />\n            <StatCard label={t('Publish bitrate')} value={publishBitrate} />\n            <StatCard label={t('Receiving bitrate')} value={subscribeBitrate} />\n          </div>\n        </>\n      )}\n    </div>\n  );\n};\n\nconst StatCardExplanation = (props: { description: string }) => {\n  const { description } = props;\n  const [isOpen, setIsOpen] = useState(false);\n\n  const { refs, floatingStyles, context } = useFloating({\n    open: isOpen,\n    onOpenChange: setIsOpen,\n  });\n\n  const hover = useHover(context);\n\n  const { getReferenceProps, getFloatingProps } = useInteractions([hover]);\n\n  return (\n    <>\n      <div\n        className=\"str-video__call-explanation\"\n        ref={refs.setReference}\n        {...getReferenceProps()}\n      >\n        <Icon className=\"str-video__call-explanation__icon\" icon=\"info\" />\n      </div>\n      {isOpen && (\n        <div\n          className=\"str-video__call-explanation__description\"\n          ref={refs.setFloating}\n          style={floatingStyles}\n          {...getFloatingProps()}\n        >\n          {description}\n        </div>\n      )}\n    </>\n  );\n};\n\nconst StatsTag = (props: { children: ReactNode; status: Status }) => {\n  const { children, status } = props;\n  return (\n    <div\n      className={clsx('str-video__call-stats__tag', {\n        'str-video__call-stats__tag--good': status === Status.GOOD,\n        'str-video__call-stats__tag--ok': status === Status.OK,\n        'str-video__call-stats__tag--bad': status === Status.BAD,\n      })}\n    >\n      <div className=\"str-video__call-stats__tag__text\">{children}</div>\n    </div>\n  );\n};\n\nexport const StatCard = (props: {\n  label: string;\n  value: string | ReactNode;\n  description?: string;\n  comparison?: { value: number; highBound: number; lowBound: number };\n}) => {\n  const { label, value, description, comparison } = props;\n\n  const { t } = useI18n();\n  const status = comparison ? toStatus(comparison) : undefined;\n\n  return (\n    <div className=\"str-video__call-stats__card\">\n      <div className=\"str-video__call-stats__card-content\">\n        <div className=\"str-video__call-stats__card-label\">\n          {label}\n          {description && <StatCardExplanation description={description} />}\n        </div>\n        <div className=\"str-video__call-stats__card-value\">{value}</div>\n      </div>\n      {status && <StatsTag status={status}>{t(status)}</StatsTag>}\n    </div>\n  );\n};\n\nconst toStatus = (config: {\n  value: number;\n  lowBound: number;\n  highBound: number;\n}): Status => {\n  const { value, lowBound, highBound } = config;\n  if (value <= lowBound) return Status.GOOD;\n  if (value >= lowBound && value <= highBound) return Status.OK;\n  if (value >= highBound) return Status.BAD;\n  return Status.GOOD;\n};\n\nconst toFrameSize = (stats: AggregatedStatsReport) => {\n  const {\n    highestFrameWidth: w,\n    highestFrameHeight: h,\n    highestFramesPerSecond: fps,\n  } = stats;\n  let size = `-`;\n  if (w && h) {\n    size = `${w}x${h}`;\n    if (fps) {\n      size += `@${fps}fps.`;\n    }\n  }\n  return size;\n};\n\nconst formatCodec = (callStatsReport: CallStatsReport): string => {\n  const { codecPerTrackType } = callStatsReport.publisherStats;\n  if (!codecPerTrackType || !codecPerTrackType[SfuModels.TrackType.VIDEO]) {\n    return '';\n  }\n  const [, name] = codecPerTrackType[SfuModels.TrackType.VIDEO].split('/');\n  return name ? ` (${name})` : '';\n};\n\nconst calculatePublishBitrate = (\n  previousCallStatsReport: CallStatsReport,\n  callStatsReport: CallStatsReport,\n) => {\n  const {\n    publisherStats: {\n      totalBytesSent: previousTotalBytesSent,\n      timestamp: previousTimestamp,\n    },\n  } = previousCallStatsReport;\n\n  const {\n    publisherStats: { totalBytesSent, timestamp },\n  } = callStatsReport;\n\n  const bytesSent = totalBytesSent - previousTotalBytesSent;\n  const timeElapsed = timestamp - previousTimestamp;\n  return `${((bytesSent * 8) / timeElapsed).toFixed(2)} kbps`;\n};\n\nconst calculateSubscribeBitrate = (\n  previousCallStatsReport: CallStatsReport,\n  callStatsReport: CallStatsReport,\n) => {\n  const {\n    subscriberStats: {\n      totalBytesReceived: previousTotalBytesReceived,\n      timestamp: previousTimestamp,\n    },\n  } = previousCallStatsReport;\n\n  const {\n    subscriberStats: { totalBytesReceived, timestamp },\n  } = callStatsReport;\n\n  const bytesReceived = totalBytesReceived - previousTotalBytesReceived;\n  const timeElapsed = timestamp - previousTimestamp;\n  return `${((bytesReceived * 8) / timeElapsed).toFixed(2)} kbps`;\n};\n","import { forwardRef } from 'react';\nimport { useI18n } from '@stream-io/video-react-bindings';\n\nimport { CallStats } from '../CallStats';\nimport { CompositeButton } from '../Button/';\nimport { MenuToggle, ToggleMenuButtonProps } from '../Menu';\nimport { Icon } from '../Icon';\n\nexport type CallStatsButtonProps = {\n  caption?: string;\n};\n\nexport const CallStatsButton = () => (\n  <MenuToggle placement=\"top-end\" ToggleButton={ToggleMenuButton}>\n    <CallStats />\n  </MenuToggle>\n);\n\nconst ToggleMenuButton = forwardRef<\n  HTMLDivElement,\n  ToggleMenuButtonProps<HTMLDivElement> & CallStatsButtonProps\n>(function ToggleMenuButton(props, ref) {\n  const { t } = useI18n();\n  const { caption, menuShown } = props;\n\n  return (\n    <CompositeButton\n      ref={ref}\n      active={menuShown}\n      caption={caption}\n      title={caption || t('Statistics')}\n      data-testid=\"stats-button\"\n    >\n      <Icon icon=\"stats\" />\n    </CompositeButton>\n  );\n});\n","import { CompositeButton, IconButtonWithMenuProps } from '../Button';\nimport { useI18n } from '@stream-io/video-react-bindings';\nimport { Icon } from '../Icon';\nimport { DeviceSelectorAudioOutput } from '../DeviceSettings';\nimport { WithTooltip } from '../Tooltip';\nimport { useState } from 'react';\n\nexport type ToggleAudioOutputButtonProps = Pick<\n  IconButtonWithMenuProps,\n  'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'\n>;\n\nexport const ToggleAudioOutputButton = (\n  props: ToggleAudioOutputButtonProps,\n) => {\n  const { t } = useI18n();\n  const {\n    caption,\n    Menu = DeviceSelectorAudioOutput,\n    menuPlacement = 'top',\n    onMenuToggle,\n  } = props;\n  const [tooltipDisabled, setTooltipDisabled] = useState(false);\n\n  return (\n    <WithTooltip\n      title={caption || t('Speakers')}\n      tooltipDisabled={tooltipDisabled}\n    >\n      <CompositeButton\n        Menu={Menu}\n        menuPlacement={menuPlacement}\n        caption={caption}\n        data-testid=\"audio-output-button\"\n        onMenuToggle={(shown) => {\n          setTooltipDisabled(shown);\n          onMenuToggle?.(shown);\n        }}\n      >\n        <Icon icon=\"speaker\" />\n      </CompositeButton>\n    </WithTooltip>\n  );\n};\n","import { Restricted, useCall } from '@stream-io/video-react-bindings';\nimport { OwnCapability } from '@stream-io/video-client';\n\nimport { TextButton } from '../Button';\n\nexport const BlockedUserListing = ({ data }: { data: string[] }) => {\n  if (!data.length) return null;\n\n  return (\n    <>\n      <div className=\"str-video__participant-listing\">\n        {data.map((userId) => (\n          <BlockedUserListingItem key={userId} userId={userId} />\n        ))}\n      </div>\n    </>\n  );\n};\n\nconst BlockedUserListingItem = ({ userId }: { userId: string }) => {\n  const call = useCall();\n\n  const unblockUserClickHandler = () => {\n    if (userId) call?.unblockUser(userId);\n  };\n\n  return (\n    <div className=\"str-video__participant-listing-item\">\n      <div className=\"str-video__participant-listing-item__display-name\">\n        {userId}\n      </div>\n      <Restricted requiredGrants={[OwnCapability.BLOCK_USERS]}>\n        <TextButton onClick={unblockUserClickHandler}>Unblock</TextButton>\n      </Restricted>\n    </div>\n  );\n};\n","import { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';\n\nimport { IconButton } from '../Button';\n\nexport type CallParticipantListHeaderProps = {\n  /**\n   * Click event listener function to be invoked to dismiss / hide the CallParticipantsList from the UI.\n   */\n  onClose: () => void;\n};\n\nexport const CallParticipantListHeader = ({\n  onClose,\n}: CallParticipantListHeaderProps) => {\n  const { useParticipants, useAnonymousParticipantCount } = useCallStateHooks();\n  const participants = useParticipants();\n  const anonymousParticipantCount = useAnonymousParticipantCount();\n  const { t } = useI18n();\n\n  return (\n    <div className=\"str-video__participant-list-header\">\n      <div className=\"str-video__participant-list-header__title\">\n        {t('Participants')}{' '}\n        <span className=\"str-video__participant-list-header__title-count\">\n          [{participants.length}]\n        </span>\n        {anonymousParticipantCount > 0 && (\n          <span className=\"str-video__participant-list-header__title-anonymous\">\n            {t('Anonymous', { count: anonymousParticipantCount })}\n          </span>\n        )}\n      </div>\n      <IconButton\n        onClick={onClose}\n        className=\"str-video__participant-list-header__close-button\"\n        icon=\"close\"\n      />\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport { ComponentProps, ComponentType, forwardRef } from 'react';\nimport { useConnectedUser, useI18n } from '@stream-io/video-react-bindings';\nimport {\n  hasAudio,\n  hasVideo,\n  isPinned,\n  StreamVideoParticipant,\n} from '@stream-io/video-client';\nimport { IconButton } from '../Button';\nimport { MenuToggle, ToggleMenuButtonProps } from '../Menu';\nimport { WithTooltip } from '../Tooltip';\nimport { Avatar } from '../Avatar';\nimport { ParticipantActionsContextMenu } from '../../core/components/ParticipantView/ParticipantActionsContextMenu';\nimport { ParticipantViewContext } from '../../core/components/ParticipantView/ParticipantViewContext';\n\ntype CallParticipantListingItemProps = {\n  /** Participant object be rendered */\n  participant: StreamVideoParticipant;\n  /** Custom component used to display participant's name */\n  DisplayName?: ComponentType<{ participant: StreamVideoParticipant }>;\n};\nexport const CallParticipantListingItem = ({\n  participant,\n  DisplayName = DefaultDisplayName,\n}: CallParticipantListingItemProps) => {\n  const isAudioOn = hasAudio(participant);\n  const isVideoOn = hasVideo(participant);\n  const isPinnedOn = isPinned(participant);\n\n  const { t } = useI18n();\n\n  return (\n    <div className=\"str-video__participant-listing-item\">\n      <Avatar name={participant.name} imageSrc={participant.image} />\n      <DisplayName participant={participant} />\n      <div className=\"str-video__participant-listing-item__media-indicator-group\">\n        <MediaIndicator\n          title={isAudioOn ? t('Microphone on') : t('Microphone off')}\n          className={clsx(\n            'str-video__participant-listing-item__icon',\n            `str-video__participant-listing-item__icon-${\n              isAudioOn ? 'mic' : 'mic-off'\n            }`,\n          )}\n        />\n        <MediaIndicator\n          title={isVideoOn ? t('Camera on') : t('Camera off')}\n          className={clsx(\n            'str-video__participant-listing-item__icon',\n            `str-video__participant-listing-item__icon-${\n              isVideoOn ? 'camera' : 'camera-off'\n            }`,\n          )}\n        />\n        {isPinnedOn && (\n          <MediaIndicator\n            title={t('Pinned')}\n            className={clsx(\n              'str-video__participant-listing-item__icon',\n              'str-video__participant-listing-item__icon-pinned',\n            )}\n          />\n        )}\n\n        <MenuToggle placement=\"bottom-end\" ToggleButton={ToggleButton}>\n          <ParticipantViewContext.Provider\n            value={{ participant, trackType: 'none' }}\n          >\n            <ParticipantActionsContextMenu />\n          </ParticipantViewContext.Provider>\n        </MenuToggle>\n      </div>\n    </div>\n  );\n};\n\nconst MediaIndicator = (props: ComponentProps<'div'>) => (\n  <WithTooltip {...props} />\n);\n\ntype DisplayNameProps = {\n  /** Participant object that provides the data from which display name can be generated */\n  participant: StreamVideoParticipant;\n};\n\nconst DefaultDisplayName = ({ participant }: DisplayNameProps) => {\n  const connectedUser = useConnectedUser();\n  const { t } = useI18n();\n\n  const meFlag = participant.userId === connectedUser?.id ? t('Me') : '';\n  const nameOrId = participant.name || participant.userId || t('Unknown');\n  let displayName;\n  if (!participant.name) {\n    displayName = meFlag || nameOrId || t('Unknown');\n  } else if (meFlag) {\n    displayName = `${nameOrId} (${meFlag})`;\n  } else {\n    displayName = nameOrId;\n  }\n\n  return (\n    <WithTooltip\n      className=\"str-video__participant-listing-item__display-name\"\n      title={displayName}\n    >\n      {displayName}\n    </WithTooltip>\n  );\n};\n\nconst ToggleButton = forwardRef<HTMLButtonElement, ToggleMenuButtonProps>(\n  function ToggleButton(props, ref) {\n    return <IconButton enabled={props.menuShown} icon=\"ellipsis\" ref={ref} />;\n  },\n);\n","import { ComponentType } from 'react';\nimport { StreamVideoParticipant } from '@stream-io/video-client';\nimport { CallParticipantListingItem } from './CallParticipantListingItem';\n\nexport type CallParticipantListingProps = {\n  /** Array of participant objects to be rendered */\n  data: StreamVideoParticipant[];\n  Header?: ComponentType;\n};\n\nexport const CallParticipantListing = ({\n  data,\n}: CallParticipantListingProps) => (\n  <div className=\"str-video__participant-listing\">\n    {data.map((participant) => (\n      <CallParticipantListingItem\n        key={participant.sessionId}\n        participant={participant}\n      />\n    ))}\n  </div>\n);\n","import { useI18n } from '@stream-io/video-react-bindings';\n\nexport const EmptyParticipantSearchList = () => {\n  const { t } = useI18n();\n  return (\n    <div className=\"str-video__participant-list--empty\">\n      {t('No participants found')}\n    </div>\n  );\n};\n","import { ComponentProps, useEffect, useState } from 'react';\nimport clsx from 'clsx';\n\ntype SearchInputProps = ComponentProps<'input'> & {\n  /**\n   * Resets the search to its initial state.\n   * The function is called when Esc key or inputs clear button are pressed\n   */\n  exitSearch: () => void;\n  /**\n   * Flag to signal, whether search input elements should be rendered as active\n   */\n  isActive: boolean;\n};\nexport const SearchInput = ({\n  exitSearch,\n  isActive,\n  ...rest\n}: SearchInputProps) => {\n  const [inputElement, setInputElement] = useState<HTMLInputElement | null>(\n    null,\n  );\n  useEffect(() => {\n    if (!inputElement) return;\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key.toLowerCase() === 'escape') exitSearch();\n    };\n\n    inputElement.addEventListener('keydown', handleKeyDown);\n\n    return () => {\n      inputElement.removeEventListener('keydown', handleKeyDown);\n    };\n  }, [exitSearch, inputElement]);\n\n  return (\n    <div\n      className={clsx('str-video__search-input__container', {\n        'str-video__search-input__container--active': isActive,\n      })}\n    >\n      <input placeholder=\"Search\" {...rest} ref={setInputElement} />\n      {isActive ? (\n        <button\n          className=\"str-video__search-input__clear-btn\"\n          onClick={exitSearch}\n        >\n          <span className=\"str-video__search-input__icon--active\" />\n        </button>\n      ) : (\n        <span className=\"str-video__search-input__icon\" />\n      )}\n    </div>\n  );\n};\n","import { ComponentType } from 'react';\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../LoadingIndicator';\nimport { SearchController } from './hooks';\n\nexport type SearchResultListProps<T> = {\n  data: T[];\n};\n\nexport type SearchResultsProps<T> = Pick<\n  SearchController<T>,\n  'searchResults' | 'searchQueryInProgress'\n> & {\n  /** Component to be displayed, when empty array of search results is provided */\n  EmptySearchResultComponent: ComponentType;\n  /** Component will be used to render non-empty array of search results  */\n  SearchResultList: ComponentType<SearchResultListProps<T>>;\n  /** Component to be displayed while the search query request is in progress */\n  LoadingIndicator?: ComponentType;\n};\n\nexport function SearchResults<T>({\n  EmptySearchResultComponent,\n  LoadingIndicator = DefaultLoadingIndicator,\n  searchQueryInProgress,\n  searchResults,\n  SearchResultList,\n}: SearchResultsProps<T>) {\n  if (searchQueryInProgress) {\n    return (\n      <div className=\"str-video__search-results--loading\">\n        <LoadingIndicator />\n      </div>\n    );\n  }\n  if (!searchResults.length) {\n    return <EmptySearchResultComponent />;\n  }\n\n  return <SearchResultList data={searchResults} />;\n}\n","import { useEffect, useRef, useState } from 'react';\n\nexport type SearchController<T> = {\n  /** Flag signals that the search request is flight await the response */\n  searchQueryInProgress: boolean;\n  /** Array of items returned by the search query */\n  searchResults: T[];\n};\n\nexport type UseSearchParams<T> = {\n  /** Search function performing the search request */\n  searchFn: (searchQuery: string) => Promise<T[]>;\n  /** Debounce interval applied to the search function */\n  debounceInterval?: number;\n  /** Search query string */\n  searchQuery?: string;\n};\n\nexport const useSearch = <T>({\n  debounceInterval = 200,\n  searchFn,\n  searchQuery = '',\n}: UseSearchParams<T>): SearchController<T> => {\n  const [searchResults, setSearchResults] = useState<T[]>([]);\n  const [searchQueryInProgress, setSearchQueryInProgress] = useState(false);\n\n  const searchFnRef = useRef(searchFn);\n  searchFnRef.current = searchFn;\n\n  useEffect(() => {\n    if (!searchQuery.length) {\n      setSearchQueryInProgress(false);\n      setSearchResults([]);\n      return;\n    }\n\n    setSearchQueryInProgress(true);\n\n    const timeout = setTimeout(async () => {\n      try {\n        const results = await searchFnRef.current(searchQuery);\n        setSearchResults(results);\n      } catch (error) {\n        console.error(error);\n      } finally {\n        setSearchQueryInProgress(false);\n      }\n    }, debounceInterval);\n\n    return () => {\n      clearTimeout(timeout);\n    };\n  }, [debounceInterval, searchQuery]);\n\n  return {\n    searchQueryInProgress,\n    searchResults,\n  };\n};\n","import {\n  Dispatch,\n  forwardRef,\n  SetStateAction,\n  useCallback,\n  useState,\n} from 'react';\nimport {\n  Restricted,\n  useCall,\n  useCallStateHooks,\n  useI18n,\n} from '@stream-io/video-react-bindings';\nimport {\n  name,\n  OwnCapability,\n  StreamVideoParticipant,\n} from '@stream-io/video-client';\n\nimport { BlockedUserListing } from './BlockedUserListing';\nimport { IconButton, TextButton } from '../Button';\nimport { CallParticipantListHeader } from './CallParticipantListHeader';\nimport { CallParticipantListing } from './CallParticipantListing';\nimport { EmptyParticipantSearchList } from './EmptyParticipantSearchList';\nimport { LoadingIndicator } from '../LoadingIndicator';\nimport { SearchInput, SearchResults } from '../Search';\nimport { useSearch, UseSearchParams } from '../Search/hooks';\nimport {\n  GenericMenu,\n  GenericMenuButtonItem,\n  MenuToggle,\n  ToggleMenuButtonProps,\n} from '../Menu';\n\ntype CallParticipantListProps = {\n  /** Click event listener function to be invoked in order to dismiss/hide the CallParticipantsList from the UI */\n  onClose: () => void;\n  /** Custom function to override the searching logic of active participants */\n  activeUsersSearchFn?: UseSearchParams<StreamVideoParticipant>['searchFn'];\n  /** Custom function to override the searching logic of blocked users */\n  blockedUsersSearchFn?: UseSearchParams<string>['searchFn'];\n  /** Interval in ms, during which the participant search calls will be debounced. The default value is 200ms. */\n  debounceSearchInterval?: number;\n};\n\nconst UserListTypes = {\n  active: 'Active users',\n  blocked: 'Blocked users',\n} as const;\n\nexport const CallParticipantsList = ({\n  onClose,\n  activeUsersSearchFn,\n  blockedUsersSearchFn,\n  debounceSearchInterval,\n}: CallParticipantListProps) => {\n  const [searchQuery, setSearchQuery] = useState('');\n  const [userListType, setUserListType] =\n    useState<keyof typeof UserListTypes>('active');\n\n  const exitSearch = useCallback(() => setSearchQuery(''), []);\n\n  return (\n    <div className=\"str-video__participant-list\">\n      <CallParticipantListHeader onClose={onClose} />\n      <SearchInput\n        value={searchQuery}\n        onChange={({ currentTarget }) => setSearchQuery(currentTarget.value)}\n        exitSearch={exitSearch}\n        isActive={!!searchQuery}\n      />\n      <CallParticipantListContentHeader\n        userListType={userListType}\n        setUserListType={setUserListType}\n      />\n      <div className=\"str-video__participant-list__content\">\n        {userListType === 'active' && (\n          <ActiveUsersSearchResults\n            searchQuery={searchQuery}\n            activeUsersSearchFn={activeUsersSearchFn}\n            debounceSearchInterval={debounceSearchInterval}\n          />\n        )}\n        {userListType === 'blocked' && (\n          <BlockedUsersSearchResults\n            searchQuery={searchQuery}\n            blockedUsersSearchFn={blockedUsersSearchFn}\n            debounceSearchInterval={debounceSearchInterval}\n          />\n        )}\n      </div>\n    </div>\n  );\n};\n\nconst CallParticipantListContentHeader = ({\n  userListType,\n  setUserListType,\n}: {\n  userListType: keyof typeof UserListTypes;\n  setUserListType: Dispatch<SetStateAction<keyof typeof UserListTypes>>;\n}) => {\n  const call = useCall();\n  const { t } = useI18n();\n\n  const muteAll = useCallback(() => {\n    call?.muteAllUsers('audio');\n  }, [call]);\n\n  return (\n    <div className=\"str-video__participant-list__content-header\">\n      <div className=\"str-video__participant-list__content-header-title\">\n        {userListType === 'active' && (\n          <Restricted\n            requiredGrants={[OwnCapability.MUTE_USERS]}\n            hasPermissionsOnly\n          >\n            <TextButton onClick={muteAll}>{t('Mute all')}</TextButton>\n          </Restricted>\n        )}\n      </div>\n      <MenuToggle placement=\"bottom-end\" ToggleButton={ToggleButton}>\n        <GenericMenu>\n          {(\n            Object.keys(UserListTypes) as Array<keyof typeof UserListTypes>\n          ).map((lt) => (\n            <GenericMenuButtonItem\n              key={lt}\n              aria-selected={lt === userListType}\n              onClick={() => setUserListType(lt)}\n            >\n              {UserListTypes[lt]}\n            </GenericMenuButtonItem>\n          ))}\n        </GenericMenu>\n      </MenuToggle>\n    </div>\n  );\n};\n\nconst ActiveUsersSearchResults = ({\n  searchQuery,\n  activeUsersSearchFn: activeUsersSearchFnFromProps,\n  debounceSearchInterval,\n}: Pick<\n  CallParticipantListProps,\n  'activeUsersSearchFn' | 'debounceSearchInterval'\n> & { searchQuery: string }) => {\n  const { useParticipants } = useCallStateHooks();\n  const participants = useParticipants({ sortBy: name });\n\n  const activeUsersSearchFn = useCallback(\n    async (queryString: string) => {\n      const queryRegExp = new RegExp(queryString, 'i');\n      return participants.filter((p) => p.name.match(queryRegExp));\n    },\n    [participants],\n  );\n\n  const { searchQueryInProgress, searchResults } = useSearch({\n    searchFn: activeUsersSearchFnFromProps ?? activeUsersSearchFn,\n    debounceInterval: debounceSearchInterval,\n    searchQuery,\n  });\n\n  return (\n    <SearchResults<StreamVideoParticipant>\n      EmptySearchResultComponent={EmptyParticipantSearchList}\n      LoadingIndicator={LoadingIndicator}\n      searchQueryInProgress={searchQueryInProgress}\n      searchResults={searchQuery ? searchResults : participants}\n      SearchResultList={CallParticipantListing}\n    />\n  );\n};\n\nconst BlockedUsersSearchResults = ({\n  blockedUsersSearchFn: blockedUsersSearchFnFromProps,\n  debounceSearchInterval,\n  searchQuery,\n}: Pick<\n  CallParticipantListProps,\n  'blockedUsersSearchFn' | 'debounceSearchInterval'\n> & { searchQuery: string }) => {\n  const { useCallBlockedUserIds } = useCallStateHooks();\n  const blockedUsers = useCallBlockedUserIds();\n\n  const blockedUsersSearchFn = useCallback(\n    async (queryString: string) => {\n      const queryRegExp = new RegExp(queryString, 'i');\n      return blockedUsers.filter((userId) => userId.match(queryRegExp));\n    },\n    [blockedUsers],\n  );\n\n  const { searchQueryInProgress, searchResults } = useSearch({\n    searchFn: blockedUsersSearchFnFromProps ?? blockedUsersSearchFn,\n    debounceInterval: debounceSearchInterval,\n    searchQuery,\n  });\n\n  return (\n    <SearchResults<string>\n      EmptySearchResultComponent={EmptyParticipantSearchList}\n      LoadingIndicator={LoadingIndicator}\n      searchQueryInProgress={searchQueryInProgress}\n      searchResults={searchQuery ? searchResults : blockedUsers}\n      SearchResultList={BlockedUserListing}\n    />\n  );\n};\n\nconst ToggleButton = forwardRef<HTMLButtonElement, ToggleMenuButtonProps>(\n  function ToggleButton(props, ref) {\n    return <IconButton enabled={props.menuShown} icon=\"filter\" ref={ref} />;\n  },\n);\n","import clsx from 'clsx';\nimport { CSSProperties, useEffect, useState } from 'react';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\n\nexport type CallPreviewProps = {\n  /**\n   * Additional CSS class name to apply to the CallPreview element.\n   */\n  className?: string;\n\n  /**\n   * Additional CSS properties to apply to the CallPreview element.\n   */\n  style?: CSSProperties;\n};\n\nexport const CallPreview = (props: CallPreviewProps) => {\n  const { className, style } = props;\n  const call = useCall();\n  const { useCallThumbnail } = useCallStateHooks();\n  const thumbnail = useCallThumbnail();\n\n  const [imageRef, setImageRef] = useState<HTMLImageElement | null>(null);\n  useEffect(() => {\n    if (!imageRef || !call) return;\n    const cleanup = call.bindCallThumbnailElement(imageRef);\n    return () => cleanup();\n  }, [imageRef, call]);\n\n  if (!thumbnail) return null;\n\n  return (\n    <img\n      className={clsx('str-video__call-preview', className)}\n      style={style}\n      alt=\"Call Preview Thumbnail\"\n      ref={setImageRef}\n    />\n  );\n};\n","import { CallRecording } from '@stream-io/video-client';\nimport { useI18n } from '@stream-io/video-react-bindings';\nimport { IconButton } from '../Button';\n\nexport type CallRecordingListHeaderProps = {\n  /** Array of CallRecording objects */\n  callRecordings: CallRecording[];\n  /** Callback to be invoked when the refresh button is clicked */\n  onRefresh?: () => void;\n};\n\nexport const CallRecordingListHeader = ({\n  callRecordings,\n  onRefresh,\n}: CallRecordingListHeaderProps) => {\n  const { t } = useI18n();\n  return (\n    <div className=\"str-video__call-recording-list__header\">\n      <div className=\"str-video__call-recording-list__title\">\n        <span>{t('Call Recordings')}</span>\n        {callRecordings.length ? <span>({callRecordings.length})</span> : null}\n      </div>\n      {onRefresh && (\n        <IconButton icon=\"refresh\" title={t('Refresh')} onClick={onRefresh} />\n      )}\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport { CallRecording } from '@stream-io/video-client';\nimport { Icon } from '../Icon';\n\nexport type CallRecordingListItemProps = {\n  /** CallRecording object to represent */\n  recording: CallRecording;\n};\n\nconst dateFormat = (date: string) => {\n  const format = new Date(date);\n  return format.toTimeString().split(' ')[0];\n};\nexport const CallRecordingListItem = ({\n  recording,\n}: CallRecordingListItemProps) => {\n  return (\n    <li className=\"str-video__call-recording-list__item\">\n      <div className=\"str-video__call-recording-list__table-cell str-video__call-recording-list__filename\">\n        {recording.filename}\n      </div>\n      <div className=\"str-video__call-recording-list__table-cell str-video__call-recording-list__time\">\n        {dateFormat(recording.start_time)}\n      </div>\n      <div className=\"str-video__call-recording-list__table-cell str-video__call-recording-list__time\">\n        {dateFormat(recording.end_time)}\n      </div>\n      <div className=\"str-video__call-recording-list__table-cell str-video__call-recording-list__download\">\n        <a\n          className={clsx(\n            'str-video__call-recording-list-item__action-button',\n            'str-video__call-recording-list-item__action-button--download',\n          )}\n          role=\"button\"\n          href={recording.url}\n          download={recording.filename}\n          title=\"Download the recording\"\n        >\n          <Icon icon=\"download\" />\n        </a>\n      </div>\n    </li>\n  );\n};\n","export const EmptyCallRecordingListing = () => {\n  return (\n    <div className=\"str-video__call-recording-list__listing str-video__call-recording-list__listing--empty\">\n      <div className=\"str-video__call-recording-list__listing--icon-empty\" />\n      <p className=\"str-video__call-recording-list__listing--text-empty\">\n        {/* todo: introduce i18n to enable text customization */}\n        No recordings available\n      </p>\n    </div>\n  );\n};\n","import { CallRecording } from '@stream-io/video-client';\nimport { CallRecordingListItem } from './CallRecordingListItem';\nimport { LoadingIndicator } from '../LoadingIndicator';\n\nexport type LoadingCallRecordingListProps = {\n  /** Array of CallRecording objects */\n  callRecordings: CallRecording[];\n};\n\nexport const LoadingCallRecordingListing = ({\n  callRecordings,\n}: LoadingCallRecordingListProps) => {\n  return (\n    <>\n      {callRecordings.map((recording) => (\n        <CallRecordingListItem recording={recording} key={recording.filename} />\n      ))}\n      <LoadingIndicator text=\"Recording getting ready\" />\n    </>\n  );\n};\n","import { ComponentType } from 'react';\nimport { CallRecording } from '@stream-io/video-client';\n\nimport {\n  CallRecordingListHeader as DefaultCallRecordingListHeader,\n  CallRecordingListHeaderProps,\n} from './CallRecordingListHeader';\nimport {\n  CallRecordingListItem as DefaultCallRecordingListItem,\n  CallRecordingListItemProps,\n} from './CallRecordingListItem';\nimport { EmptyCallRecordingListing as DefaultEmptyCallRecordingList } from './EmptyCallRecordingListing';\nimport {\n  LoadingCallRecordingListing as DefaultLoadingCallRecordingList,\n  LoadingCallRecordingListProps,\n} from './LoadingCallRecordingListing';\n\nexport type CallRecordingListProps = {\n  /** Array of CallRecording objects to be displayed */\n  callRecordings: CallRecording[];\n  /** Custom component to replace the default header implementation */\n  CallRecordingListHeader?: ComponentType<CallRecordingListHeaderProps>;\n  /** Custom component to replace the default list item implementation */\n  CallRecordingListItem?: ComponentType<CallRecordingListItemProps>;\n  /** Custom component to replace the default empty list component implementation */\n  EmptyCallRecordingList?: ComponentType;\n  /** Signals that a request for new list of CallRecording object has been initiated */\n  loading?: boolean;\n  /** Custom component to be rendered when loading is true */\n  LoadingCallRecordingList?: ComponentType<LoadingCallRecordingListProps>;\n  /** Callback to be invoked when the refresh button is clicked */\n  onRefresh?: () => void;\n};\n\nexport const CallRecordingList = ({\n  callRecordings,\n  CallRecordingListHeader = DefaultCallRecordingListHeader,\n  CallRecordingListItem = DefaultCallRecordingListItem,\n  EmptyCallRecordingList = DefaultEmptyCallRecordingList,\n  loading,\n  LoadingCallRecordingList = DefaultLoadingCallRecordingList,\n  onRefresh,\n}: CallRecordingListProps) => {\n  return (\n    <div className=\"str-video__call-recording-list\">\n      <CallRecordingListHeader\n        callRecordings={callRecordings}\n        onRefresh={onRefresh}\n      />\n      <div className=\"str-video__call-recording-list__listing\">\n        {loading ? (\n          <LoadingCallRecordingList callRecordings={callRecordings} />\n        ) : callRecordings.length ? (\n          <>\n            <ul className=\"str-video__call-recording-list__list\">\n              <li className=\"str-video__call-recording-list__item\">\n                <div className=\"str-video__call-recording-list__filename\">\n                  Name\n                </div>\n                <div className=\"str-video__call-recording-list__time\">\n                  Start time\n                </div>\n                <div className=\"str-video__call-recording-list__time\">\n                  End time\n                </div>\n                <div className=\"str-video__call-recording-list__download\"></div>\n              </li>\n            </ul>\n            <ul className=\"str-video__call-recording-list__list\">\n              {callRecordings.map((recording) => (\n                <CallRecordingListItem\n                  recording={recording}\n                  key={recording.filename}\n                />\n              ))}\n            </ul>\n          </>\n        ) : (\n          <EmptyCallRecordingList />\n        )}\n      </div>\n    </div>\n  );\n};\n","import {\n  createContext,\n  PropsWithChildren,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport {\n  NoiseCancellationSettingsModeEnum,\n  OwnCapability,\n} from '@stream-io/video-client';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\nimport type { INoiseCancellation } from '@stream-io/audio-filters-web';\n\nexport type NoiseCancellationProviderProps = {\n  /**\n   * The noise cancellation instance to use.\n   */\n  noiseCancellation: INoiseCancellation;\n};\n\n/**\n * The Noise Cancellation API.\n */\nexport type NoiseCancellationAPI = {\n  /**\n   * A boolean providing information whether Noise Cancelling functionalities\n   * are supported on this platform and for the current user.\n   */\n  isSupported: boolean | undefined;\n  /**\n   * Provides information whether Noise Cancellation is active or not.\n   */\n  isEnabled: boolean;\n  /**\n   * Allows you to temporarily enable or disable the Noise Cancellation filters.\n   *\n   * @param enabled a boolean or a setter.\n   */\n  setEnabled: (enabled: boolean | ((value: boolean) => boolean)) => void;\n\n  /**\n   * Sets the noise suppression level (0-100).\n   *\n   * @param level 0 for no suppression, 100 for maximum suppression.\n   */\n  setSuppressionLevel: (level: number) => void;\n};\n\nconst NoiseCancellationContext = createContext<NoiseCancellationAPI | null>(\n  null,\n);\n\n/**\n * Exposes the NoiseCancellation API.\n * Throws an error if used outside <NoiseCancellationProvider />.\n */\nexport const useNoiseCancellation = (): NoiseCancellationAPI => {\n  const context = useContext(NoiseCancellationContext);\n  if (!context) {\n    throw new Error(\n      'useNoiseCancellation must be used within a NoiseCancellationProvider',\n    );\n  }\n  return context;\n};\n\nexport const NoiseCancellationProvider = (\n  props: PropsWithChildren<NoiseCancellationProviderProps>,\n) => {\n  const { children, noiseCancellation } = props;\n  const call = useCall();\n  const { useCallSettings, useHasPermissions } = useCallStateHooks();\n  const settings = useCallSettings();\n  const noiseCancellationAllowed = !!(\n    settings &&\n    settings.audio.noise_cancellation &&\n    settings.audio.noise_cancellation.mode !==\n      NoiseCancellationSettingsModeEnum.DISABLED\n  );\n\n  const hasCapability = useHasPermissions(\n    OwnCapability.ENABLE_NOISE_CANCELLATION,\n  );\n  const [isSupportedByBrowser, setIsSupportedByBrowser] = useState<boolean>();\n  useEffect(() => {\n    const result = noiseCancellation.isSupported();\n    if (typeof result === 'boolean') {\n      setIsSupportedByBrowser(result);\n    } else {\n      result\n        .then((s) => setIsSupportedByBrowser(s))\n        .catch((err) =>\n          console.error(\n            `Can't determine if noise cancellation is supported`,\n            err,\n          ),\n        );\n    }\n  }, [noiseCancellation]);\n\n  const isSupported =\n    isSupportedByBrowser && hasCapability && noiseCancellationAllowed;\n\n  const [isEnabled, setIsEnabled] = useState(false);\n  const deinit = useRef<Promise<void>>(undefined);\n  useEffect(() => {\n    if (!call || !isSupported) return;\n    noiseCancellation.isEnabled().then((e) => setIsEnabled(e));\n    const unsubscribe = noiseCancellation.on('change', (v) => setIsEnabled(v));\n    const init = (deinit.current || Promise.resolve())\n      .then(() => noiseCancellation.init({ tracer: call.tracer }))\n      .then(() => call.microphone.enableNoiseCancellation(noiseCancellation))\n      .catch((e) => console.error(`Can't initialize noise cancellation`, e));\n\n    return () => {\n      deinit.current = init\n        .then(() => call.microphone.disableNoiseCancellation())\n        .then(() => noiseCancellation.dispose())\n        .then(() => unsubscribe());\n    };\n  }, [call, isSupported, noiseCancellation]);\n\n  const contextValue = useMemo<NoiseCancellationAPI>(\n    () => ({\n      isSupported,\n      isEnabled,\n      setSuppressionLevel: (level) => {\n        if (!noiseCancellation) return;\n        noiseCancellation.setSuppressionLevel(level);\n      },\n      setEnabled: (enabledOrSetter) => {\n        if (!noiseCancellation) return;\n        const enable =\n          typeof enabledOrSetter === 'function'\n            ? enabledOrSetter(isEnabled)\n            : enabledOrSetter;\n        if (enable) {\n          noiseCancellation.enable();\n        } else {\n          noiseCancellation.disable();\n        }\n      },\n    }),\n    [isEnabled, isSupported, noiseCancellation],\n  );\n  return (\n    <NoiseCancellationContext.Provider value={contextValue}>\n      {children}\n    </NoiseCancellationContext.Provider>\n  );\n};\n","import { CallingState } from '@stream-io/video-client';\nimport { AcceptCallButton, CancelCallButton } from '../CallControls';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\n\nexport const RingingCallControls = () => {\n  const call = useCall();\n  const { useCallCallingState } = useCallStateHooks();\n  const callCallingState = useCallCallingState();\n\n  if (!call) return null;\n\n  const buttonsDisabled = callCallingState !== CallingState.RINGING;\n  return (\n    <div className=\"str-video__pending-call-controls\">\n      {call.isCreatedByMe ? (\n        <CancelCallButton disabled={buttonsDisabled} />\n      ) : (\n        <>\n          <AcceptCallButton disabled={buttonsDisabled} />\n          <CancelCallButton\n            onClick={() => {\n              const reason = call.isCreatedByMe ? 'cancel' : 'decline';\n              call.leave({ reject: true, reason });\n            }}\n            disabled={buttonsDisabled}\n          />\n        </>\n      )}\n    </div>\n  );\n};\n","import { CallingState, UserResponse } from '@stream-io/video-client';\nimport {\n  useCall,\n  useCallStateHooks,\n  useConnectedUser,\n  useI18n,\n} from '@stream-io/video-react-bindings';\nimport { Avatar } from '../Avatar';\nimport { RingingCallControls } from './RingingCallControls';\n\nconst CALLING_STATE_TO_LABEL: Record<CallingState, string> = {\n  [CallingState.JOINING]: 'Joining',\n  [CallingState.RINGING]: 'Ringing',\n  [CallingState.MIGRATING]: 'Migrating',\n  [CallingState.RECONNECTING]: 'Re-connecting',\n  [CallingState.RECONNECTING_FAILED]: 'Failed',\n  [CallingState.OFFLINE]: 'No internet connection',\n  [CallingState.IDLE]: '',\n  [CallingState.UNKNOWN]: '',\n  [CallingState.JOINED]: 'Joined',\n  [CallingState.LEFT]: 'Left call',\n};\n\nexport type RingingCallProps = {\n  /**\n   * Whether to include the current user in the list of members to show.\n   * @default false.\n   */\n  includeSelf?: boolean;\n\n  /**\n   * The maximum number of members to show.\n   * @default 3.\n   */\n  totalMembersToShow?: number;\n};\n\nexport const RingingCall = (props: RingingCallProps) => {\n  const { includeSelf = false, totalMembersToShow = 3 } = props;\n  const call = useCall();\n  const { t } = useI18n();\n  const { useCallCallingState, useCallMembers } = useCallStateHooks();\n  const callingState = useCallCallingState();\n  const members = useCallMembers();\n  const connectedUser = useConnectedUser();\n\n  if (!call) return null;\n\n  // take the first N members to show their avatars\n  const membersToShow: UserResponse[] = (members || [])\n    .slice(0, totalMembersToShow)\n    .map(({ user }) => user)\n    .filter((user) => user.id !== connectedUser?.id || includeSelf);\n  if (\n    includeSelf &&\n    !membersToShow.find((user) => user.id === connectedUser?.id)\n  ) {\n    // if the current user is not in the initial batch of members,\n    // replace the first item in membersToShow array with the current user\n    const self = members.find(({ user }) => user.id === connectedUser?.id);\n    if (self) {\n      membersToShow.splice(0, 1, self.user);\n    }\n  }\n\n  const callingStateLabel = CALLING_STATE_TO_LABEL[callingState];\n\n  return (\n    <div className=\"str-video__call-panel str-video__call-panel--ringing\">\n      <div className=\"str-video__call-panel__members-list\">\n        {membersToShow.map((user) => (\n          <div key={user.id} className=\"str-video__call-panel__member-box\">\n            <Avatar name={user.name} imageSrc={user.image} />\n            {user.name && (\n              <div className=\"str-video__member_details\">\n                <span className=\"str-video__member_name\">{user.name}</span>\n              </div>\n            )}\n          </div>\n        ))}\n      </div>\n\n      {callingStateLabel && (\n        <div className=\"str-video__call-panel__calling-state-label\">\n          {t(callingStateLabel)}\n        </div>\n      )}\n\n      {[CallingState.RINGING, CallingState.JOINING].includes(callingState) && (\n        <RingingCallControls />\n      )}\n    </div>\n  );\n};\n","import {\n  ButtonHTMLAttributes,\n  ComponentProps,\n  forwardRef,\n  Fragment,\n  PropsWithChildren,\n  useEffect,\n  useState,\n} from 'react';\nimport {\n  OwnCapability,\n  PermissionRequestEvent,\n  UserResponse,\n} from '@stream-io/video-client';\nimport {\n  TranslatorFunction,\n  useCall,\n  useCallStateHooks,\n  useI18n,\n} from '@stream-io/video-react-bindings';\nimport clsx from 'clsx';\n\nimport { useFloatingUIPreset } from '../../hooks';\n\nconst byNameOrId = (a: UserResponse, b: UserResponse) => {\n  if (a.name && b.name && a.name < b.name) return -1;\n  if (a.name && b.name && a.name > b.name) return 1;\n  if (a.id < b.id) return -1;\n  if (a.id > b.id) return 1;\n  return 0;\n};\n\ntype HandleUpdatePermission = (\n  request: PermissionRequestEvent,\n  type: 'grant' | 'revoke' | 'dismiss',\n) => () => Promise<void>;\n\nexport const PermissionRequests = () => {\n  const call = useCall();\n  const { useLocalParticipant, useHasPermissions } = useCallStateHooks();\n  const localParticipant = useLocalParticipant();\n  const [expanded, setExpanded] = useState(false);\n  const [permissionRequests, setPermissionRequests] = useState<\n    PermissionRequestEvent[]\n  >([]);\n  const canUpdateCallPermissions = useHasPermissions(\n    OwnCapability.UPDATE_CALL_PERMISSIONS,\n  );\n\n  const localUserId = localParticipant?.userId;\n  useEffect(() => {\n    if (!call || !canUpdateCallPermissions) return;\n    return call.on('call.permission_request', (event) => {\n      if (event.user.id !== localUserId) {\n        setPermissionRequests((requests) =>\n          [...requests, event].sort((a, b) => byNameOrId(a.user, b.user)),\n        );\n      }\n    });\n  }, [call, canUpdateCallPermissions, localUserId]);\n\n  const handleUpdatePermission: HandleUpdatePermission = (request, type) => {\n    return async () => {\n      const { user, permissions } = request;\n      switch (type) {\n        case 'grant':\n          await call?.grantPermissions(user.id, permissions);\n          break;\n        case 'revoke':\n          await call?.revokePermissions(user.id, permissions);\n          break;\n        default:\n          break;\n      }\n      setPermissionRequests((requests) =>\n        requests.filter((r) => r !== request),\n      );\n    };\n  };\n\n  const { refs, x, y, strategy } = useFloatingUIPreset({\n    placement: 'bottom',\n    strategy: 'absolute',\n  });\n\n  // don't render anything if there are no permission requests\n  if (permissionRequests.length === 0) return null;\n\n  return (\n    <div className=\"str-video__permission-requests\" ref={refs.setReference}>\n      <div className=\"str-video__permission-requests__notification\">\n        <span className=\"str-video__permission-requests__notification__message\">\n          {permissionRequests.length} pending permission requests\n        </span>\n        <Button\n          type=\"button\"\n          onClick={() => {\n            setExpanded((e) => !e);\n          }}\n        >\n          {expanded ? 'Hide requests' : 'Show requests'}\n        </Button>\n      </div>\n      {expanded && (\n        <PermissionRequestList\n          ref={refs.setFloating}\n          style={{\n            position: strategy,\n            top: y ?? 0,\n            left: x ?? 0,\n            overflowY: 'auto',\n          }}\n          permissionRequests={permissionRequests}\n          handleUpdatePermission={handleUpdatePermission}\n        />\n      )}\n    </div>\n  );\n};\n\nexport type PermissionRequestListProps = ComponentProps<'div'> & {\n  permissionRequests: PermissionRequestEvent[];\n  handleUpdatePermission: HandleUpdatePermission;\n};\n\nexport const PermissionRequestList = forwardRef<\n  HTMLDivElement,\n  PermissionRequestListProps\n>(function PermissionRequestList(props, ref) {\n  const { permissionRequests, handleUpdatePermission, ...rest } = props;\n\n  const { t } = useI18n();\n\n  return (\n    <div className=\"str-video__permission-requests-list\" ref={ref} {...rest}>\n      {permissionRequests.map((request, reqIndex) => {\n        const { user, permissions } = request;\n        return (\n          <Fragment key={`${user.id}/${reqIndex}`}>\n            {permissions.map((permission) => (\n              <div className=\"str-video__permission-request\" key={permission}>\n                <div className=\"str-video__permission-request__message\">\n                  {messageForPermission(user.name || user.id, permission, t)}\n                </div>\n                <Button\n                  className=\"str-video__permission-request__button--allow\"\n                  type=\"button\"\n                  onClick={handleUpdatePermission(request, 'grant')}\n                >\n                  {t('Allow')}\n                </Button>\n                <Button\n                  className=\"str-video__permission-request__button--reject\"\n                  type=\"button\"\n                  onClick={handleUpdatePermission(request, 'revoke')}\n                >\n                  {t('Revoke')}\n                </Button>\n                <Button\n                  className=\"str-video__permission-request__button--reject\"\n                  type=\"button\"\n                  onClick={handleUpdatePermission(request, 'dismiss')}\n                >\n                  {t('Dismiss')}\n                </Button>\n              </div>\n            ))}\n          </Fragment>\n        );\n      })}\n    </div>\n  );\n});\n\nconst Button = (\n  props: PropsWithChildren<ButtonHTMLAttributes<HTMLButtonElement>>,\n) => {\n  const { className, ...rest } = props;\n  return (\n    <button\n      className={clsx('str-video__permission-request__button', className)}\n      {...rest}\n    />\n  );\n};\n\nconst messageForPermission = (\n  userName: string,\n  permission: string,\n  t: TranslatorFunction,\n) => {\n  switch (permission) {\n    case OwnCapability.SEND_AUDIO:\n      return t('{{ userName }} is requesting to speak', { userName });\n    case OwnCapability.SEND_VIDEO:\n      return t('{{ userName }} is requesting to share their camera', {\n        userName,\n      });\n    case OwnCapability.SCREENSHARE:\n      return t('{{ userName }} is requesting to present their screen', {\n        userName,\n      });\n    default:\n      return t('{{ userName }} is requesting permission: {{ permission }}', {\n        userName,\n        permission,\n      });\n  }\n};\n","import { ElementType, HTMLProps, PropsWithChildren } from 'react';\nimport clsx from 'clsx';\n\nexport type StreamThemeProps = HTMLProps<HTMLElement> & {\n  as?: ElementType;\n};\n\nexport const StreamTheme = ({\n  as: Component = 'div',\n  className,\n  children,\n  ...props\n}: PropsWithChildren<StreamThemeProps>) => {\n  return (\n    <Component {...props} className={clsx('str-video', className)}>\n      {children}\n    </Component>\n  );\n};\n","import { ComponentType } from 'react';\nimport clsx from 'clsx';\nimport { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';\nimport { BaseVideo } from '../../core/components/Video';\nimport { LoadingIndicator } from '../LoadingIndicator';\n\nconst DefaultDisabledVideoPreview = () => {\n  const { t } = useI18n();\n  return (\n    <div className=\"str_video__video-preview__disabled-video-preview\">\n      {t('Video is disabled')}\n    </div>\n  );\n};\n\nconst DefaultNoCameraPreview = () => {\n  const { t } = useI18n();\n  return (\n    <div className=\"str_video__video-preview__no-camera-preview\">\n      {t('No camera found')}\n    </div>\n  );\n};\n\nexport type VideoPreviewProps = {\n  /**\n   * Additional CSS class name to apply to the root element.\n   */\n  className?: string;\n  /**\n   * Enforces mirroring of the video on the X axis. Defaults to true.\n   */\n  mirror?: boolean;\n  /**\n   * Component rendered when user turns off the video.\n   */\n  DisabledVideoPreview?: ComponentType;\n  /**\n   * Component rendered when no camera devices are available.\n   */\n  NoCameraPreview?: ComponentType;\n  /**\n   * Component rendered above the BaseVideo until the video is ready (meaning until the play event is emitted).\n   */\n  StartingCameraPreview?: ComponentType;\n};\n\nexport const VideoPreview = ({\n  className,\n  mirror = true,\n  DisabledVideoPreview = DefaultDisabledVideoPreview,\n  NoCameraPreview = DefaultNoCameraPreview,\n  StartingCameraPreview = LoadingIndicator,\n}: VideoPreviewProps) => {\n  const { useCameraState } = useCallStateHooks();\n  const { devices, status, isMute, mediaStream } = useCameraState();\n\n  let contents;\n  if (isMute && devices?.length === 0) {\n    contents = <NoCameraPreview />;\n  } else if (status === 'enabled') {\n    const loading = !mediaStream;\n    contents = (\n      <>\n        {mediaStream && (\n          <BaseVideo\n            stream={mediaStream}\n            className={clsx('str-video__video-preview', {\n              'str-video__video-preview--mirror': mirror,\n              'str-video__video-preview--loading': loading,\n            })}\n          />\n        )}\n        {loading && <StartingCameraPreview />}\n      </>\n    );\n  } else {\n    contents = <DisabledVideoPreview />;\n  }\n\n  return (\n    <div className={clsx('str-video__video-preview-container', className)}>\n      {contents}\n    </div>\n  );\n};\n","import { ComponentType, forwardRef } from 'react';\nimport { Placement } from '@floating-ui/react';\nimport {\n  hasAudio,\n  hasPausedTrack,\n  hasScreenShare,\n  hasVideo,\n  SfuModels,\n} from '@stream-io/video-client';\nimport { useCall, useI18n } from '@stream-io/video-react-bindings';\nimport clsx from 'clsx';\n\nimport {\n  Icon,\n  IconButton,\n  MenuToggle,\n  Notification,\n  ToggleMenuButtonProps,\n} from '../../../components';\nimport { ParticipantActionsContextMenu as DefaultParticipantActionsContextMenu } from './ParticipantActionsContextMenu';\nimport { Reaction } from '../../../components/Reaction';\nimport { useParticipantViewContext } from './ParticipantViewContext';\n\nexport type DefaultParticipantViewUIProps = {\n  /**\n   * Turns on/off the status indicator icons (mute, connection quality, etc...).\n   */\n  indicatorsVisible?: boolean;\n  /**\n   * Placement of the context menu component when opened\n   */\n  menuPlacement?: Placement;\n  /**\n   * Option to show/hide menu button component\n   */\n  showMenuButton?: boolean;\n  /**\n   * Custom component to render the context menu\n   */\n  ParticipantActionsContextMenu?: ComponentType;\n};\n\nconst ToggleButton = forwardRef<HTMLButtonElement, ToggleMenuButtonProps>(\n  function ToggleButton(props, ref) {\n    return <IconButton enabled={props.menuShown} icon=\"ellipsis\" ref={ref} />;\n  },\n);\n\nexport const DefaultScreenShareOverlay = () => {\n  const call = useCall();\n  const { t } = useI18n();\n\n  const stopScreenShare = () => {\n    call?.screenShare.disable().catch((err) => {\n      console.error('Failed to stop screen sharing:', err);\n    });\n  };\n\n  return (\n    <div className=\"str-video__screen-share-overlay\">\n      <Icon icon=\"screen-share-off\" />\n      <span className=\"str-video__screen-share-overlay__title\">\n        {t('You are presenting your screen')}\n      </span>\n      <button\n        onClick={stopScreenShare}\n        type=\"button\"\n        className=\"str-video__screen-share-overlay__button\"\n      >\n        <Icon icon=\"close\" /> {t('Stop Screen Sharing')}\n      </button>\n    </div>\n  );\n};\n\nexport const DefaultParticipantViewUI = ({\n  indicatorsVisible = true,\n  menuPlacement = 'bottom-start',\n  showMenuButton = true,\n  ParticipantActionsContextMenu = DefaultParticipantActionsContextMenu,\n}: DefaultParticipantViewUIProps) => {\n  const { participant, trackType } = useParticipantViewContext();\n  const isScreenSharing = hasScreenShare(participant);\n\n  if (\n    participant.isLocalParticipant &&\n    isScreenSharing &&\n    trackType === 'screenShareTrack'\n  ) {\n    return (\n      <>\n        <DefaultScreenShareOverlay />\n        <ParticipantDetails indicatorsVisible={indicatorsVisible} />\n      </>\n    );\n  }\n\n  return (\n    <>\n      {showMenuButton && (\n        <MenuToggle\n          strategy=\"fixed\"\n          placement={menuPlacement}\n          ToggleButton={ToggleButton}\n        >\n          <ParticipantActionsContextMenu />\n        </MenuToggle>\n      )}\n      <Reaction participant={participant} />\n      <ParticipantDetails indicatorsVisible={indicatorsVisible} />\n    </>\n  );\n};\n\nexport const ParticipantDetails = ({\n  indicatorsVisible = true,\n}: Pick<DefaultParticipantViewUIProps, 'indicatorsVisible'>) => {\n  const { participant, trackType } = useParticipantViewContext();\n  const {\n    isLocalParticipant,\n    connectionQuality,\n    pin,\n    sessionId,\n    name,\n    userId,\n  } = participant;\n  const call = useCall();\n\n  const { t } = useI18n();\n  const connectionQualityAsString =\n    !!connectionQuality &&\n    SfuModels.ConnectionQuality[connectionQuality].toLowerCase();\n\n  const hasAudioTrack = hasAudio(participant);\n  const hasVideoTrack = hasVideo(participant);\n  const canUnpin = !!pin && pin.isLocalPin;\n  const isTrackPaused =\n    trackType !== 'none' ? hasPausedTrack(participant, trackType) : false;\n\n  return (\n    <>\n      <div className=\"str-video__participant-details\">\n        <span className=\"str-video__participant-details__name\">\n          {name || userId}\n\n          {indicatorsVisible && !hasAudioTrack && (\n            <span className=\"str-video__participant-details__name--audio-muted\" />\n          )}\n          {indicatorsVisible && !hasVideoTrack && (\n            <span className=\"str-video__participant-details__name--video-muted\" />\n          )}\n          {indicatorsVisible && isTrackPaused && (\n            <span\n              title={t('Video paused due to insufficient bandwidth')}\n              className=\"str-video__participant-details__name--track-paused\"\n            />\n          )}\n          {indicatorsVisible && canUnpin && (\n            // TODO: remove this monstrosity once we have a proper design\n            <span\n              title={t('Unpin')}\n              onClick={() => call?.unpin(sessionId)}\n              className=\"str-video__participant-details__name--pinned\"\n            />\n          )}\n          {indicatorsVisible && <SpeechIndicator />}\n        </span>\n      </div>\n      {indicatorsVisible && (\n        <Notification\n          isVisible={\n            isLocalParticipant &&\n            connectionQuality === SfuModels.ConnectionQuality.POOR\n          }\n          message={t('Poor connection quality')}\n        >\n          {connectionQualityAsString && (\n            <span\n              className={clsx(\n                'str-video__participant-details__connection-quality',\n                `str-video__participant-details__connection-quality--${connectionQualityAsString}`,\n              )}\n              title={connectionQualityAsString}\n            />\n          )}\n        </Notification>\n      )}\n    </>\n  );\n};\n\nexport const SpeechIndicator = () => {\n  const { participant } = useParticipantViewContext();\n  const { isSpeaking, isDominantSpeaker } = participant;\n  return (\n    <span\n      className={clsx(\n        'str-video__speech-indicator',\n        isSpeaking && 'str-video__speech-indicator--speaking',\n        isDominantSpeaker && 'str-video__speech-indicator--dominant',\n      )}\n    >\n      <span className=\"str-video__speech-indicator__bar\" />\n      <span className=\"str-video__speech-indicator__bar\" />\n      <span className=\"str-video__speech-indicator__bar\" />\n    </span>\n  );\n};\n","import {\n  ComponentType,\n  forwardRef,\n  ReactElement,\n  useMemo,\n  useState,\n} from 'react';\nimport clsx from 'clsx';\nimport {\n  hasAudio,\n  hasScreenShareAudio,\n  hasVideo,\n  StreamVideoParticipant,\n  VideoTrackType,\n} from '@stream-io/video-client';\nimport { useCallStateHooks } from '@stream-io/video-react-bindings';\n\nimport { Audio } from '../Audio';\nimport { Video, VideoProps } from '../Video';\nimport { useTrackElementVisibility } from '../../hooks';\nimport { DefaultParticipantViewUI } from './DefaultParticipantViewUI';\nimport { applyElementToRef, isComponentType } from '../../../utilities';\nimport { ParticipantViewContext } from './ParticipantViewContext';\n\nexport type ParticipantViewProps = {\n  /**\n   * The participant whose video/audio stream we want to play.\n   */\n  participant: StreamVideoParticipant;\n\n  /**\n   * Override the default UI for rendering participant information/actions.\n   * pass `null` if you wish to not render anything\n   * @default DefaultParticipantViewUI\n   */\n  ParticipantViewUI?: ComponentType | ReactElement | null;\n\n  /**\n   * The kind of video stream to play for the given participant.\n   * The default value is `videoTrack`.\n   * You can use `none` if you're building an audio-only call.\n   */\n  trackType?: VideoTrackType | 'none';\n\n  /**\n   * Forces participant's video to be mirrored or unmirrored. By default, video track\n   * from the local participant is mirrored, and all other videos are not mirrored.\n   */\n  mirror?: boolean;\n\n  /**\n   * This prop is only useful for advanced use-cases (for example, building your own layout).\n   * When set to `true` it will mute the give participant's audio stream on the client side.\n   * The local participant is always muted.\n   */\n  muteAudio?: boolean;\n\n  /**\n   * An object with set functions meant for exposing the video\n   * and video placeholder elements to the integrators.\n   * It's useful when you want to attach custom event handlers to these elements.\n   * - `refs.setVideoElement`\n   * - `refs.setVideoPlaceholderElement`\n   */\n  refs?: VideoProps['refs'];\n\n  /**\n   * Custom class applied to the root DOM element.\n   */\n  className?: string;\n} & Pick<VideoProps, 'VideoPlaceholder' | 'PictureInPicturePlaceholder'>;\n\nexport const ParticipantView = forwardRef<HTMLDivElement, ParticipantViewProps>(\n  function ParticipantView(\n    {\n      participant,\n      trackType = 'videoTrack',\n      mirror,\n      muteAudio,\n      refs: { setVideoElement, setVideoPlaceholderElement } = {},\n      className,\n      VideoPlaceholder,\n      PictureInPicturePlaceholder,\n      ParticipantViewUI = DefaultParticipantViewUI as ComponentType,\n    },\n    ref,\n  ) {\n    const { isLocalParticipant, isSpeaking, isDominantSpeaker, sessionId } =\n      participant;\n\n    const hasAudioTrack = hasAudio(participant);\n    const hasVideoTrack = hasVideo(participant);\n    const hasScreenShareAudioTrack = hasScreenShareAudio(participant);\n\n    const [trackedElement, setTrackedElement] = useState<HTMLDivElement | null>(\n      null,\n    );\n\n    const [contextVideoElement, setContextVideoElement] =\n      useState<HTMLVideoElement | null>(null);\n\n    const [contextVideoPlaceholderElement, setContextVideoPlaceholderElement] =\n      useState<HTMLDivElement | null>(null);\n\n    // TODO: allow to pass custom ViewportTracker instance from props\n    useTrackElementVisibility({\n      sessionId,\n      trackedElement,\n      trackType,\n    });\n\n    const { useIncomingVideoSettings } = useCallStateHooks();\n    const { isParticipantVideoEnabled } = useIncomingVideoSettings();\n\n    const participantViewContextValue = useMemo(\n      () => ({\n        participant,\n        participantViewElement: trackedElement,\n        videoElement: contextVideoElement,\n        videoPlaceholderElement: contextVideoPlaceholderElement,\n        trackType,\n      }),\n      [\n        contextVideoElement,\n        contextVideoPlaceholderElement,\n        participant,\n        trackedElement,\n        trackType,\n      ],\n    );\n\n    const videoRefs: VideoProps['refs'] = useMemo(\n      () => ({\n        setVideoElement: (element) => {\n          setVideoElement?.(element);\n          setContextVideoElement(element);\n        },\n        setVideoPlaceholderElement: (element) => {\n          setVideoPlaceholderElement?.(element);\n          setContextVideoPlaceholderElement(element);\n        },\n      }),\n      [setVideoElement, setVideoPlaceholderElement],\n    );\n\n    return (\n      <div\n        data-testid=\"participant-view\"\n        ref={(element) => {\n          applyElementToRef(ref, element);\n          setTrackedElement(element);\n        }}\n        className={clsx(\n          'str-video__participant-view',\n          isDominantSpeaker && 'str-video__participant-view--dominant-speaker',\n          isSpeaking && 'str-video__participant-view--speaking',\n          !hasVideoTrack && 'str-video__participant-view--no-video',\n          !hasAudioTrack && 'str-video__participant-view--no-audio',\n          className,\n        )}\n      >\n        <ParticipantViewContext.Provider value={participantViewContextValue}>\n          {/* mute the local participant, as we don't want to hear ourselves */}\n          {!isLocalParticipant && !muteAudio && (\n            <>\n              {hasAudioTrack && (\n                <Audio participant={participant} trackType=\"audioTrack\" />\n              )}\n              {hasScreenShareAudioTrack && (\n                <Audio\n                  participant={participant}\n                  trackType=\"screenShareAudioTrack\"\n                />\n              )}\n            </>\n          )}\n          <Video\n            VideoPlaceholder={VideoPlaceholder}\n            PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n            participant={participant}\n            trackType={trackType}\n            refs={videoRefs}\n            enabled={\n              isLocalParticipant ||\n              trackType !== 'videoTrack' ||\n              isParticipantVideoEnabled(participant.sessionId)\n            }\n            mirror={mirror}\n            autoPlay\n          />\n          {isComponentType(ParticipantViewUI) ? (\n            <ParticipantViewUI />\n          ) : (\n            ParticipantViewUI\n          )}\n        </ParticipantViewContext.Provider>\n      </div>\n    );\n  },\n);\n\nParticipantView.displayName = 'ParticipantView';\n","import { ComponentType, PropsWithChildren } from 'react';\nimport {\n  StreamCallProvider,\n  StreamCallProviderProps,\n} from '@stream-io/video-react-bindings';\n\n// re-exporting the StreamCallProvider as StreamCall\nexport const StreamCall: ComponentType<\n  PropsWithChildren<StreamCallProviderProps>\n> = StreamCallProvider;\n\nStreamCall.displayName = 'StreamCall';\n","import en from './en.json';\n\nexport const translations = { en };\n","import {\n  StreamVideoProps,\n  StreamVideoProvider,\n} from '@stream-io/video-react-bindings';\nimport { PropsWithChildren } from 'react';\nimport { translations } from '../../../translations';\n\nexport const StreamVideo = (props: PropsWithChildren<StreamVideoProps>) => {\n  return (\n    <StreamVideoProvider translationsOverrides={translations} {...props} />\n  );\n};\n\nStreamVideo.displayName = 'StreamVideo';\n","export type Filter<T> =\n  | { $and: Array<Filter<T>> }\n  | { $or: Array<Filter<T>> }\n  | { $not: Filter<T> }\n  | Conditions<T>;\n\ntype Conditions<T> = {\n  [K in keyof T]?: T[K] extends Array<infer E>\n    ? ArrayOperator<E>\n    : ScalarOperator<T[K]>;\n};\n\nexport type ScalarOperator<T> =\n  | EqOperator<T>\n  | NeqOperator<T>\n  | InOperator<T>\n  | GtOperator<T>\n  | GteOperator<T>\n  | LtOperator<T>\n  | LteOperator<T>\n  | T;\n\nexport type ArrayOperator<T> = ContainsOperator<T>;\n\nexport type AutocompleteOperator<T> = { $autocomplete: T };\nexport type EqOperator<T> = { $eq: T };\nexport type GtOperator<T> = { $gt: T };\nexport type GteOperator<T> = { $gte: T };\nexport type LtOperator<T> = { $lt: T };\nexport type LteOperator<T> = { $lte: T };\nexport type NeqOperator<T> = { $neq: T };\nexport type InOperator<T> = { $in: Array<T> };\nexport type ContainsOperator<T> = { $contains: T };\n\nexport function applyFilter<T>(obj: T, filter: Filter<T>): boolean {\n  if ('$and' in filter) {\n    return filter.$and.every((f) => applyFilter(obj, f));\n  }\n\n  if ('$or' in filter) {\n    return filter.$or.some((f) => applyFilter(obj, f));\n  }\n\n  if ('$not' in filter) {\n    return !applyFilter(obj, filter.$not);\n  }\n\n  return checkConditions(obj, filter);\n}\n\ntype DateString = string;\nconst isDateString = (value: unknown): value is DateString =>\n  typeof value === 'string' &&\n  /^((?:(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?))(Z|[+-]\\d{2}:\\d{2})?)$/.test(\n    value,\n  );\n\nfunction checkConditions<T>(obj: T, conditions: Conditions<T>): boolean {\n  let match = true;\n\n  for (const key of Object.keys(conditions) as Array<keyof T>) {\n    const operator = conditions[key];\n    const maybeOperator = operator && typeof operator === 'object';\n    let value: T[keyof T] | number = obj[key];\n\n    if (value instanceof Date) {\n      value = value.getTime();\n    } else if (isDateString(value)) {\n      value = new Date(value).getTime();\n    }\n\n    if (maybeOperator && '$eq' in operator) {\n      const eqOperator = operator as EqOperator<typeof value>;\n      const eqOperatorValue = isDateString(eqOperator.$eq)\n        ? new Date(eqOperator.$eq).getTime()\n        : eqOperator.$eq;\n      match &&= eqOperatorValue === value;\n    } else if (maybeOperator && '$neq' in operator) {\n      const neqOperator = operator as NeqOperator<typeof value>;\n      match &&= neqOperator.$neq !== value;\n    } else if (maybeOperator && '$in' in operator) {\n      const inOperator = operator as InOperator<typeof value>;\n      match &&= inOperator.$in.includes(value);\n    } else if (maybeOperator && '$contains' in operator) {\n      if (Array.isArray(value)) {\n        const containsOperator = operator as ContainsOperator<\n          (typeof value)[number]\n        >;\n        match &&= value.includes(containsOperator.$contains);\n      } else {\n        match = false;\n      }\n    } else if (maybeOperator && '$gt' in operator) {\n      const gtOperator = operator as GtOperator<typeof value>;\n      const gtOperatorValue = isDateString(gtOperator.$gt)\n        ? new Date(gtOperator.$gt).getTime()\n        : gtOperator.$gt;\n      match &&= value > gtOperatorValue;\n    } else if (maybeOperator && '$gte' in operator) {\n      const gteOperator = operator as GteOperator<typeof value>;\n      const gteOperatorValue = isDateString(gteOperator.$gte)\n        ? new Date(gteOperator.$gte).getTime()\n        : gteOperator.$gte;\n      match &&= value >= gteOperatorValue;\n    } else if (maybeOperator && '$lt' in operator) {\n      const ltOperator = operator as LtOperator<typeof value>;\n      const ltOperatorValue = isDateString(ltOperator.$lt)\n        ? new Date(ltOperator.$lt).getTime()\n        : ltOperator.$lt;\n      match &&= value < ltOperatorValue;\n    } else if (maybeOperator && '$lte' in operator) {\n      const lteOperator = operator as LteOperator<typeof value>;\n      const lteOperatorValue = isDateString(lteOperator.$lte)\n        ? new Date(lteOperator.$lte).getTime()\n        : lteOperator.$lte;\n      match &&= value <= lteOperatorValue;\n      // } else if (maybeOperator && '$autocomplete' in operator) {\n      // TODO: regexp solution maybe?\n      // match &&= false;\n    } else {\n      const eqValue = operator as typeof value;\n      match &&= eqValue === value;\n    }\n\n    if (!match) {\n      return false;\n    }\n  }\n\n  return true;\n}\n","import { useEffect, useMemo } from 'react';\nimport {\n  Call,\n  CallTypes,\n  combineComparators,\n  Comparator,\n  defaultSortPreset,\n  hasAudio,\n  hasScreenShare,\n  hasVideo,\n  isPinned,\n  paginatedLayoutSortPreset,\n  screenSharing,\n  speakerLayoutSortPreset,\n  StreamVideoParticipant,\n} from '@stream-io/video-client';\nimport { useCallStateHooks } from '@stream-io/video-react-bindings';\nimport { applyFilter, Filter } from '../../../utilities/filter';\n\nexport type FilterableParticipant = Pick<\n  StreamVideoParticipant,\n  'userId' | 'isSpeaking' | 'isDominantSpeaker' | 'name' | 'roles'\n> & {\n  isPinned: boolean;\n  hasVideo: boolean;\n  hasAudio: boolean;\n  hasScreenShare: boolean;\n};\n\nexport type ParticipantFilter = Filter<FilterableParticipant>;\nexport type ParticipantPredicate = (\n  participant: StreamVideoParticipant,\n) => boolean;\n\nexport const useFilteredParticipants = ({\n  excludeLocalParticipant = false,\n  filterParticipants,\n}: {\n  excludeLocalParticipant?: boolean;\n  filterParticipants?: ParticipantFilter | ParticipantPredicate;\n}) => {\n  const { useParticipants, useRemoteParticipants } = useCallStateHooks();\n  const allParticipants = useParticipants();\n  const remoteParticipants = useRemoteParticipants();\n  return useMemo(() => {\n    const unfilteredParticipants = excludeLocalParticipant\n      ? remoteParticipants\n      : allParticipants;\n\n    return filterParticipants\n      ? applyParticipantsFilter(unfilteredParticipants, filterParticipants)\n      : unfilteredParticipants;\n  }, [\n    allParticipants,\n    remoteParticipants,\n    excludeLocalParticipant,\n    filterParticipants,\n  ]);\n};\n\nexport const applyParticipantsFilter = (\n  participants: StreamVideoParticipant[],\n  filter: ParticipantPredicate | ParticipantFilter,\n) => {\n  const filterCallback =\n    typeof filter === 'function'\n      ? filter\n      : (participant: StreamVideoParticipant) =>\n          applyFilter(\n            {\n              userId: participant.userId,\n              isSpeaking: participant.isSpeaking,\n              isDominantSpeaker: participant.isDominantSpeaker,\n              name: participant.name,\n              roles: participant.roles,\n              isPinned: isPinned(participant),\n              hasVideo: hasVideo(participant),\n              hasAudio: hasAudio(participant),\n              hasScreenShare: hasScreenShare(participant),\n            },\n            filter,\n          );\n\n  return participants.filter(filterCallback);\n};\n\nexport const usePaginatedLayoutSortPreset = (call: Call | undefined) => {\n  useEffect(() => {\n    if (!call) return;\n    call.setSortParticipantsBy(paginatedLayoutSortPreset);\n    return () => {\n      resetSortPreset(call);\n    };\n  }, [call]);\n};\n\nexport const useSpeakerLayoutSortPreset = (\n  call: Call | undefined,\n  isOneOnOneCall: boolean,\n) => {\n  useEffect(() => {\n    if (!call) return;\n    // always show the remote participant in the spotlight\n    if (isOneOnOneCall) {\n      call.setSortParticipantsBy(combineComparators(screenSharing, loggedIn));\n    } else {\n      call.setSortParticipantsBy(speakerLayoutSortPreset);\n    }\n    return () => {\n      resetSortPreset(call);\n    };\n  }, [call, isOneOnOneCall]);\n};\n\nexport const useRawRemoteParticipants = () => {\n  const { useRawParticipants } = useCallStateHooks();\n  const rawParticipants = useRawParticipants();\n  return useMemo(\n    () => rawParticipants.filter((p) => !p.isLocalParticipant),\n    [rawParticipants],\n  );\n};\n\nconst resetSortPreset = (call: Call) => {\n  // reset the sorting to the default for the call type\n  const callConfig = CallTypes.get(call.type);\n  call.setSortParticipantsBy(\n    callConfig.options.sortParticipantsBy || defaultSortPreset,\n  );\n};\n\nconst loggedIn: Comparator<StreamVideoParticipant> = (a, b) => {\n  if (a.isLocalParticipant) return 1;\n  if (b.isLocalParticipant) return -1;\n  return 0;\n};\n","import clsx from 'clsx';\nimport {\n  ComponentType,\n  ReactElement,\n  useCallback,\n  useEffect,\n  useState,\n} from 'react';\nimport {\n  useCall,\n  useCallStateHooks,\n  useI18n,\n} from '@stream-io/video-react-bindings';\nimport { hasScreenShare } from '@stream-io/video-client';\nimport { ParticipantView, useParticipantViewContext } from '../ParticipantView';\nimport { ParticipantsAudio } from '../Audio';\nimport {\n  usePaginatedLayoutSortPreset,\n  useRawRemoteParticipants,\n} from './hooks';\n\n/**\n * The props for the {@link LivestreamLayout} component.\n */\nexport type LivestreamLayoutProps = {\n  /**\n   * Whether the livestream is muted. Defaults to `false`.\n   */\n  muted?: boolean;\n\n  /**\n   * Whether to show the participant count. Defaults to `true`.\n   */\n  showParticipantCount?: boolean;\n\n  /**\n   * Whether to enable fullscreen mode. Defaults to `true`.\n   */\n  enableFullScreen?: boolean;\n\n  /**\n   * Whether to show the duration of the call. Defaults to `true`.\n   */\n  showDuration?: boolean;\n\n  /**\n   * Whether to show the live badge. Defaults to `true`.\n   */\n  showLiveBadge?: boolean;\n\n  /**\n   * Whether to show the speaker name. Defaults to `false`.\n   */\n  showSpeakerName?: boolean;\n\n  /**\n   * When set to `false` disables mirroring of the local participant's video.\n   * @default true\n   */\n  mirrorLocalParticipantVideo?: boolean;\n\n  /**\n   * The props to pass to the floating participant element.\n   */\n  floatingParticipantProps?: LivestreamLayoutProps & {\n    /**\n     * The position of the floating participant element. Defaults to `top-right`.\n     */\n    position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n  };\n\n  /**\n   * Override the default participant view overlay UI.\n   */\n  ParticipantViewUI?: ComponentType | ReactElement | null;\n};\n\nexport const LivestreamLayout = (props: LivestreamLayoutProps) => {\n  const { useParticipants, useHasOngoingScreenShare } = useCallStateHooks();\n  const call = useCall();\n  const participants = useParticipants();\n  const [currentSpeaker] = participants;\n  const remoteParticipants = useRawRemoteParticipants();\n  const hasOngoingScreenShare = useHasOngoingScreenShare();\n  const presenter = hasOngoingScreenShare\n    ? participants.find(hasScreenShare)\n    : undefined;\n\n  usePaginatedLayoutSortPreset(call);\n\n  const { floatingParticipantProps, muted, ParticipantViewUI } = props;\n  const overlay = ParticipantViewUI ?? (\n    <ParticipantOverlay\n      showParticipantCount={props.showParticipantCount}\n      showDuration={props.showDuration}\n      showLiveBadge={props.showLiveBadge}\n      showSpeakerName={props.showSpeakerName}\n      enableFullScreen={props.enableFullScreen}\n    />\n  );\n\n  const floatingParticipantOverlay =\n    hasOngoingScreenShare &&\n    (ParticipantViewUI ?? (\n      <ParticipantOverlay\n        // these elements aren't needed for the video feed\n        showParticipantCount={\n          floatingParticipantProps?.showParticipantCount ?? false\n        }\n        showDuration={floatingParticipantProps?.showDuration ?? false}\n        showLiveBadge={floatingParticipantProps?.showLiveBadge ?? false}\n        showSpeakerName={floatingParticipantProps?.showSpeakerName ?? true}\n        enableFullScreen={floatingParticipantProps?.enableFullScreen ?? true}\n      />\n    ));\n\n  return (\n    <div className=\"str-video__livestream-layout__wrapper\">\n      {!muted && <ParticipantsAudio participants={remoteParticipants} />}\n      {hasOngoingScreenShare && presenter && (\n        <ParticipantView\n          className=\"str-video__livestream-layout__screen-share\"\n          participant={presenter}\n          ParticipantViewUI={overlay}\n          trackType=\"screenShareTrack\"\n          muteAudio // audio is rendered by ParticipantsAudio\n        />\n      )}\n      {currentSpeaker && (\n        <ParticipantView\n          className={clsx(\n            hasOngoingScreenShare &&\n              clsx(\n                'str-video__livestream-layout__floating-participant',\n                `str-video__livestream-layout__floating-participant--${\n                  floatingParticipantProps?.position ?? 'top-right'\n                }`,\n              ),\n          )}\n          participant={currentSpeaker}\n          ParticipantViewUI={floatingParticipantOverlay || overlay}\n          mirror={\n            props.mirrorLocalParticipantVideo !== false ? undefined : false\n          }\n          muteAudio // audio is rendered by ParticipantsAudio\n        />\n      )}\n    </div>\n  );\n};\n\nLivestreamLayout.displayName = 'LivestreamLayout';\n\n/**\n * The props for the {@link LivestreamLayout} component.\n */\nexport type BackstageLayoutProps = {\n  /**\n   * Whether to show the counter for participants that joined before\n   * the livestream went live. Defaults to `true`.\n   */\n  showEarlyParticipantCount?: boolean;\n};\n\nexport const BackstageLayout = (props: BackstageLayoutProps) => {\n  const { showEarlyParticipantCount = true } = props;\n  const { useParticipantCount, useCallStartsAt } = useCallStateHooks();\n  const participantCount = useParticipantCount();\n  const startsAt = useCallStartsAt();\n  const { t } = useI18n();\n\n  return (\n    <div className=\"str-video__livestream-layout__wrapper\">\n      <div className=\"str-video__livestream-layout__backstage\">\n        {startsAt && (\n          <span className=\"str-video__livestream-layout__starts-at\">\n            {startsAt.getTime() < Date.now()\n              ? t('Livestream starts soon')\n              : t('Livestream starts at {{ startsAt }}', { startsAt })}\n          </span>\n        )}\n        {showEarlyParticipantCount && (\n          <span className=\"str-video__livestream-layout__early-viewers-count\">\n            {t('{{ count }} participants joined early', {\n              count: participantCount,\n            })}\n          </span>\n        )}\n      </div>\n    </div>\n  );\n};\n\nBackstageLayout.displayName = 'BackstageLayout';\n\nconst ParticipantOverlay = (props: {\n  enableFullScreen?: boolean;\n  showParticipantCount?: boolean;\n  showDuration?: boolean;\n  showLiveBadge?: boolean;\n  showSpeakerName?: boolean;\n}) => {\n  const {\n    enableFullScreen = true,\n    showParticipantCount = true,\n    showDuration = true,\n    showLiveBadge = true,\n    showSpeakerName = false,\n  } = props;\n  const overlayBarVisible =\n    enableFullScreen ||\n    showParticipantCount ||\n    showDuration ||\n    showLiveBadge ||\n    showSpeakerName;\n  const { participant } = useParticipantViewContext();\n  const { useParticipantCount } = useCallStateHooks();\n  const participantCount = useParticipantCount();\n  const duration = useUpdateCallDuration();\n  const toggleFullScreen = useToggleFullScreen();\n  const { t } = useI18n();\n  return (\n    <div className=\"str-video__livestream-layout__overlay\">\n      {overlayBarVisible && (\n        <div className=\"str-video__livestream-layout__overlay__bar\">\n          {showLiveBadge && (\n            <span className=\"str-video__livestream-layout__live-badge\">\n              {t('Live')}\n            </span>\n          )}\n          {showParticipantCount && (\n            <span className=\"str-video__livestream-layout__viewers-count\">\n              {participantCount}\n            </span>\n          )}\n          {showSpeakerName && (\n            <span\n              className=\"str-video__livestream-layout__speaker-name\"\n              title={participant.name || participant.userId || ''}\n            >\n              {participant.name || participant.userId || ''}\n            </span>\n          )}\n          {showDuration && (\n            <span className=\"str-video__livestream-layout__duration\">\n              {formatDuration(duration)}\n            </span>\n          )}\n          {enableFullScreen && (\n            <span\n              className=\"str-video__livestream-layout__go-fullscreen\"\n              onClick={toggleFullScreen}\n            />\n          )}\n        </div>\n      )}\n    </div>\n  );\n};\n\nconst useUpdateCallDuration = () => {\n  const { useIsCallLive, useCallSession } = useCallStateHooks();\n  const isCallLive = useIsCallLive();\n  const session = useCallSession();\n  const [duration, setDuration] = useState(() => {\n    if (!session || !session.live_started_at) return 0;\n    const liveStartTime = new Date(session.live_started_at);\n    const now = new Date();\n    return Math.floor((now.getTime() - liveStartTime.getTime()) / 1000);\n  });\n\n  useEffect(() => {\n    if (!isCallLive) return;\n    const interval = setInterval(() => {\n      setDuration((d) => d + 1);\n    }, 1000);\n    return () => {\n      clearInterval(interval);\n    };\n  }, [isCallLive]);\n\n  return duration;\n};\n\nconst useToggleFullScreen = () => {\n  const { participantViewElement } = useParticipantViewContext();\n  const [isFullscreen, setIsFullscreen] = useState(\n    !!document.fullscreenElement,\n  );\n  useEffect(() => {\n    const handler = () => setIsFullscreen(!!document.fullscreenElement);\n    document.addEventListener('fullscreenchange', handler);\n    return () => {\n      document.removeEventListener('fullscreenchange', handler);\n    };\n  }, []);\n  return useCallback(() => {\n    if (isFullscreen) {\n      document.exitFullscreen().catch((err) => {\n        console.error('Failed to exit fullscreen', err);\n      });\n    } else {\n      participantViewElement?.requestFullscreen().catch((err) => {\n        console.error('Failed to enter fullscreen', err);\n      });\n    }\n  }, [isFullscreen, participantViewElement]);\n};\n\nconst formatDuration = (durationInMs: number) => {\n  const days = Math.floor(durationInMs / 86400);\n  const hours = Math.floor(durationInMs / 3600);\n  const minutes = Math.floor((durationInMs % 3600) / 60);\n  const seconds = durationInMs % 60;\n\n  return `${days ? days + ' ' : ''}${hours ? hours + ':' : ''}${\n    minutes < 10 ? '0' : ''\n  }${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;\n};\n","import { useEffect, useMemo, useState } from 'react';\nimport { useCall } from '@stream-io/video-react-bindings';\nimport { StreamVideoParticipant } from '@stream-io/video-client';\nimport clsx from 'clsx';\n\nimport {\n  DefaultParticipantViewUI,\n  ParticipantView,\n  ParticipantViewProps,\n} from '../ParticipantView';\nimport { ParticipantsAudio } from '../Audio';\nimport { IconButton } from '../../../components';\nimport { chunk } from '../../../utilities';\nimport {\n  ParticipantFilter,\n  ParticipantPredicate,\n  useFilteredParticipants,\n  usePaginatedLayoutSortPreset,\n  useRawRemoteParticipants,\n} from './hooks';\n\nconst GROUP_SIZE = 16;\n\ntype PaginatedGridLayoutGroupProps = {\n  /**\n   * The group of participants to render.\n   */\n  group: Array<StreamVideoParticipant>;\n} & Pick<\n  ParticipantViewProps,\n  'VideoPlaceholder' | 'PictureInPicturePlaceholder' | 'mirror'\n> &\n  Required<Pick<ParticipantViewProps, 'ParticipantViewUI'>>;\n\nconst PaginatedGridLayoutGroup = ({\n  group,\n  mirror,\n  VideoPlaceholder,\n  PictureInPicturePlaceholder,\n  ParticipantViewUI,\n}: PaginatedGridLayoutGroupProps) => {\n  return (\n    <div\n      className={clsx('str-video__paginated-grid-layout__group', {\n        'str-video__paginated-grid-layout--one': group.length === 1,\n        'str-video__paginated-grid-layout--two-four':\n          group.length >= 2 && group.length <= 4,\n        'str-video__paginated-grid-layout--five-nine':\n          group.length >= 5 && group.length <= 9,\n      })}\n    >\n      {group.map((participant) => (\n        <ParticipantView\n          key={participant.sessionId}\n          participant={participant}\n          muteAudio\n          mirror={mirror}\n          VideoPlaceholder={VideoPlaceholder}\n          PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n          ParticipantViewUI={ParticipantViewUI}\n        />\n      ))}\n    </div>\n  );\n};\n\nexport type PaginatedGridLayoutProps = {\n  /**\n   * The number of participants to display per page.\n   */\n  groupSize?: number;\n\n  /**\n   * Whether to exclude the local participant from the grid.\n   * @default false\n   */\n  excludeLocalParticipant?: boolean;\n\n  /**\n   * Predicate to filter call participants or a filter object.\n   * @example\n   * // With a predicate:\n   * <PaginatedGridLayout\n   *   filterParticipants={p => p.roles.includes('student')}\n   * />\n   * @example\n   * // With a filter object:\n   * <PaginatedGridLayout\n   *   filterParticipants={{\n   *     $or: [\n   *       { roles: { $contains: 'student' } },\n   *       { isPinned: true },\n   *     ],\n   *   }}\n   * />\n   */\n  filterParticipants?: ParticipantPredicate | ParticipantFilter;\n\n  /**\n   * When set to `false` disables mirroring of the local partipant's video.\n   * @default true\n   */\n  mirrorLocalParticipantVideo?: boolean;\n\n  /**\n   * Turns on/off the pagination arrows.\n   * @default true\n   */\n  pageArrowsVisible?: boolean;\n\n  /**\n   * Whether the layout is muted. Defaults to `false`.\n   */\n  muted?: boolean;\n} & Pick<\n  ParticipantViewProps,\n  'ParticipantViewUI' | 'VideoPlaceholder' | 'PictureInPicturePlaceholder'\n>;\n\nexport const PaginatedGridLayout = (props: PaginatedGridLayoutProps) => {\n  const {\n    groupSize = (props.groupSize || 0) > 0\n      ? props.groupSize || GROUP_SIZE\n      : GROUP_SIZE,\n    excludeLocalParticipant = false,\n    filterParticipants,\n    mirrorLocalParticipantVideo = true,\n    pageArrowsVisible = true,\n    VideoPlaceholder,\n    ParticipantViewUI = DefaultParticipantViewUI,\n    PictureInPicturePlaceholder,\n    muted,\n  } = props;\n  const [page, setPage] = useState(0);\n  const [\n    paginatedGridLayoutWrapperElement,\n    setPaginatedGridLayoutWrapperElement,\n  ] = useState<HTMLDivElement | null>(null);\n\n  const call = useCall();\n  const remoteParticipants = useRawRemoteParticipants();\n  const participants = useFilteredParticipants({\n    excludeLocalParticipant,\n    filterParticipants,\n  });\n\n  usePaginatedLayoutSortPreset(call);\n\n  useEffect(() => {\n    if (!paginatedGridLayoutWrapperElement || !call) return;\n\n    const cleanup = call.setViewport(paginatedGridLayoutWrapperElement);\n\n    return () => cleanup();\n  }, [paginatedGridLayoutWrapperElement, call]);\n\n  // only used to render video elements\n  const participantGroups = useMemo(\n    () => chunk(participants, groupSize),\n    [participants, groupSize],\n  );\n\n  const pageCount = participantGroups.length;\n\n  // update page when page count is reduced and selected page no longer exists\n  useEffect(() => {\n    if (page > pageCount - 1) {\n      setPage(Math.max(0, pageCount - 1));\n    }\n  }, [page, pageCount]);\n\n  const selectedGroup = participantGroups[page];\n  const mirror = mirrorLocalParticipantVideo ? undefined : false;\n\n  if (!call) return null;\n\n  return (\n    <div\n      className=\"str-video__paginated-grid-layout__wrapper\"\n      ref={setPaginatedGridLayoutWrapperElement}\n    >\n      {!muted && <ParticipantsAudio participants={remoteParticipants} />}\n      <div className=\"str-video__paginated-grid-layout\">\n        {pageArrowsVisible && pageCount > 1 && (\n          <IconButton\n            icon=\"caret-left\"\n            disabled={page === 0}\n            onClick={() =>\n              setPage((currentPage) => Math.max(0, currentPage - 1))\n            }\n          />\n        )}\n        {selectedGroup && (\n          <PaginatedGridLayoutGroup\n            group={selectedGroup}\n            mirror={mirror}\n            VideoPlaceholder={VideoPlaceholder}\n            ParticipantViewUI={ParticipantViewUI}\n            PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n          />\n        )}\n        {pageArrowsVisible && pageCount > 1 && (\n          <IconButton\n            disabled={page === pageCount - 1}\n            icon=\"caret-right\"\n            onClick={() =>\n              setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1))\n            }\n          />\n        )}\n      </div>\n    </div>\n  );\n};\n\nPaginatedGridLayout.displayName = 'PaginatedGridLayout';\n","import { useEffect, useState } from 'react';\n\nexport const useCalculateHardLimit = (\n  /**\n   * Element that stretches to 100% of the whole layout component\n   */\n  wrapperElement: HTMLDivElement | null,\n  /**\n   * Element that directly hosts individual `ParticipantView` (or wrapper) elements\n   */\n  hostElement: HTMLDivElement | null,\n  limit?: 'dynamic' | number,\n) => {\n  const [calculatedLimit, setCalculatedLimit] = useState<{\n    vertical: number | null;\n    horizontal: number | null;\n  }>({\n    vertical: typeof limit === 'number' ? limit : null,\n    horizontal: typeof limit === 'number' ? limit : null,\n  });\n\n  useEffect(() => {\n    if (\n      !hostElement ||\n      !wrapperElement ||\n      typeof limit === 'number' ||\n      typeof limit === 'undefined'\n    )\n      return;\n\n    let childWidth: number | null = null;\n    let childHeight: number | null = null;\n\n    const resizeObserver = new ResizeObserver((entries, observer) => {\n      // this part should ideally run as little times as possible\n      // get child measurements and disconnect\n      // does not consider dynamically sized children\n      // this hook is for SpeakerLayout use only, where children in the bar are fixed size\n      if (entries.length > 1) {\n        const child = hostElement.firstChild as HTMLElement | null;\n\n        if (child) {\n          childHeight = child.clientHeight;\n          childWidth = child.clientWidth;\n          observer.unobserve(hostElement);\n        }\n      }\n\n      // keep the state at { vertical: 1, horizontal: 1 }\n      // until we get the proper child measurements\n      if (childHeight === null || childWidth === null) return;\n\n      const vertical = Math.floor(wrapperElement.clientHeight / childHeight);\n      const horizontal = Math.floor(wrapperElement.clientWidth / childWidth);\n\n      setCalculatedLimit((pv) => {\n        if (pv.vertical !== vertical || pv.horizontal !== horizontal)\n          return { vertical, horizontal };\n        return pv;\n      });\n    });\n\n    resizeObserver.observe(wrapperElement);\n    resizeObserver.observe(hostElement);\n\n    return () => {\n      resizeObserver.disconnect();\n    };\n  }, [hostElement, limit, wrapperElement]);\n\n  return calculatedLimit;\n};\n","import { useEffect, useState } from 'react';\nimport clsx from 'clsx';\nimport { hasScreenShare } from '@stream-io/video-client';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\n\nimport {\n  DefaultParticipantViewUI,\n  ParticipantView,\n  ParticipantViewProps,\n} from '../ParticipantView';\nimport { IconButton } from '../../../components';\nimport {\n  useHorizontalScrollPosition,\n  useVerticalScrollPosition,\n} from '../../../hooks';\nimport {\n  ParticipantFilter,\n  ParticipantPredicate,\n  useFilteredParticipants,\n  useRawRemoteParticipants,\n  useSpeakerLayoutSortPreset,\n} from './hooks';\nimport { useCalculateHardLimit } from '../../hooks/useCalculateHardLimit';\nimport { ParticipantsAudio } from '../Audio';\n\nexport type SpeakerLayoutProps = {\n  /**\n   * The UI to be used for the participant in the spotlight.\n   */\n  ParticipantViewUISpotlight?: ParticipantViewProps['ParticipantViewUI'];\n\n  /**\n   * The UI to be used for the participants in the participants bar.\n   */\n  ParticipantViewUIBar?: ParticipantViewProps['ParticipantViewUI'];\n\n  /**\n   * The position of the participants who are not in focus.\n   * Providing `null` will hide the bar.\n   */\n  participantsBarPosition?: 'top' | 'bottom' | 'left' | 'right' | null;\n\n  /**\n   * Hard limits the number of the participants rendered in the participants bar.\n   * Providing string `dynamic` will calculate hard limit based on screen width/height.\n   */\n  participantsBarLimit?: 'dynamic' | number;\n\n  /**\n   * When set to `true` will exclude the local participant from layout.\n   * @default false\n   */\n  excludeLocalParticipant?: boolean;\n\n  /**\n   * Predicate to filter call participants or a filter object.\n   * @example\n   * // With a predicate:\n   * <SpeakerLayout\n   *   filterParticipants={p => p.roles.includes('student')}\n   * />\n   * @example\n   * // With a filter object:\n   * <SpeakerLayout\n   *   filterParticipants={{\n   *     $or: [\n   *       { roles: { $contains: 'student' } },\n   *       { isPinned: true },\n   *     ],\n   *   }}\n   * />\n   */\n  filterParticipants?: ParticipantPredicate | ParticipantFilter;\n\n  /**\n   * When set to `false` disables mirroring of the local participant's video.\n   * @default true\n   */\n  mirrorLocalParticipantVideo?: boolean;\n\n  /**\n   * Turns on/off the pagination arrows.\n   * @default true\n   */\n  pageArrowsVisible?: boolean;\n\n  /**\n   * Whether the layout is muted. Defaults to `false`.\n   */\n  muted?: boolean;\n} & Pick<\n  ParticipantViewProps,\n  'VideoPlaceholder' | 'PictureInPicturePlaceholder'\n>;\n\nconst DefaultParticipantViewUIBar = () => (\n  <DefaultParticipantViewUI menuPlacement=\"top-end\" />\n);\n\nexport const SpeakerLayout = ({\n  ParticipantViewUIBar = DefaultParticipantViewUIBar,\n  ParticipantViewUISpotlight = DefaultParticipantViewUI,\n  VideoPlaceholder,\n  PictureInPicturePlaceholder,\n  participantsBarPosition = 'bottom',\n  participantsBarLimit,\n  mirrorLocalParticipantVideo = true,\n  excludeLocalParticipant = false,\n  filterParticipants,\n  pageArrowsVisible = true,\n  muted,\n}: SpeakerLayoutProps) => {\n  const call = useCall();\n  const { useParticipants } = useCallStateHooks();\n  const allParticipants = useParticipants();\n  const remoteParticipants = useRawRemoteParticipants();\n  const [participantInSpotlight, ...otherParticipants] =\n    useFilteredParticipants({ excludeLocalParticipant, filterParticipants });\n  const [participantsBarWrapperElement, setParticipantsBarWrapperElement] =\n    useState<HTMLDivElement | null>(null);\n  const [participantsBarElement, setParticipantsBarElement] =\n    useState<HTMLDivElement | null>(null);\n  const [buttonsWrapperElement, setButtonsWrapperElement] =\n    useState<HTMLDivElement | null>(null);\n\n  const isSpeakerScreenSharing =\n    participantInSpotlight && hasScreenShare(participantInSpotlight);\n  const hardLimit = useCalculateHardLimit(\n    buttonsWrapperElement,\n    participantsBarElement,\n    participantsBarLimit,\n  );\n\n  const isVertical =\n    participantsBarPosition === 'left' || participantsBarPosition === 'right';\n  const isHorizontal =\n    participantsBarPosition === 'top' || participantsBarPosition === 'bottom';\n\n  useEffect(() => {\n    if (!participantsBarWrapperElement || !call) return;\n\n    const cleanup = call.setViewport(participantsBarWrapperElement);\n\n    return () => cleanup();\n  }, [participantsBarWrapperElement, call]);\n\n  const isOneOnOneCall = allParticipants.length === 2;\n  useSpeakerLayoutSortPreset(call, isOneOnOneCall);\n\n  let participantsWithAppliedLimit = otherParticipants;\n\n  const hardLimitToApply = isVertical\n    ? hardLimit.vertical\n    : hardLimit.horizontal;\n\n  if (\n    typeof participantsBarLimit !== 'undefined' &&\n    hardLimitToApply !== null\n  ) {\n    participantsWithAppliedLimit = otherParticipants.slice(\n      0,\n      // subtract 1 if speaker is sharing screen as\n      // that one is rendered independently from otherParticipants array\n      hardLimitToApply - (isSpeakerScreenSharing ? 1 : 0),\n    );\n  }\n\n  const mirror = mirrorLocalParticipantVideo ? undefined : false;\n\n  if (!call) return null;\n\n  const renderParticipantsBar =\n    participantsBarPosition &&\n    (participantsWithAppliedLimit.length > 0 || isSpeakerScreenSharing);\n  return (\n    <div className=\"str-video__speaker-layout__wrapper\">\n      {!muted && <ParticipantsAudio participants={remoteParticipants} />}\n      <div\n        className={clsx(\n          'str-video__speaker-layout',\n          participantsBarPosition &&\n            `str-video__speaker-layout--variant-${participantsBarPosition}`,\n        )}\n      >\n        <div className=\"str-video__speaker-layout__spotlight\">\n          {participantInSpotlight && (\n            <ParticipantView\n              participant={participantInSpotlight}\n              muteAudio={true}\n              mirror={mirror}\n              trackType={\n                isSpeakerScreenSharing ? 'screenShareTrack' : 'videoTrack'\n              }\n              ParticipantViewUI={ParticipantViewUISpotlight}\n              VideoPlaceholder={VideoPlaceholder}\n              PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n            />\n          )}\n        </div>\n        {renderParticipantsBar && (\n          <div\n            ref={setButtonsWrapperElement}\n            className=\"str-video__speaker-layout__participants-bar-buttons-wrapper\"\n          >\n            <div\n              className=\"str-video__speaker-layout__participants-bar-wrapper\"\n              ref={setParticipantsBarWrapperElement}\n            >\n              <div\n                ref={setParticipantsBarElement}\n                className=\"str-video__speaker-layout__participants-bar\"\n              >\n                {isSpeakerScreenSharing && (\n                  <div\n                    className=\"str-video__speaker-layout__participant-tile\"\n                    key={participantInSpotlight.sessionId}\n                  >\n                    <ParticipantView\n                      participant={participantInSpotlight}\n                      ParticipantViewUI={ParticipantViewUIBar}\n                      VideoPlaceholder={VideoPlaceholder}\n                      PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n                      mirror={mirror}\n                      muteAudio={true}\n                    />\n                  </div>\n                )}\n                {participantsWithAppliedLimit.map((participant) => (\n                  <div\n                    className=\"str-video__speaker-layout__participant-tile\"\n                    key={participant.sessionId}\n                  >\n                    <ParticipantView\n                      participant={participant}\n                      ParticipantViewUI={ParticipantViewUIBar}\n                      VideoPlaceholder={VideoPlaceholder}\n                      PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n                      mirror={mirror}\n                      muteAudio={true}\n                    />\n                  </div>\n                ))}\n              </div>\n            </div>\n            {pageArrowsVisible && isVertical && (\n              <VerticalScrollButtons\n                scrollWrapper={participantsBarWrapperElement}\n              />\n            )}\n            {pageArrowsVisible && isHorizontal && (\n              <HorizontalScrollButtons\n                scrollWrapper={participantsBarWrapperElement}\n              />\n            )}\n          </div>\n        )}\n      </div>\n    </div>\n  );\n};\n\nSpeakerLayout.displayName = 'SpeakerLayout';\n\ntype ScrollButtonsProps<T extends HTMLElement> = {\n  scrollWrapper: T | null;\n};\n\nconst HorizontalScrollButtons = <T extends HTMLElement>({\n  scrollWrapper,\n}: ScrollButtonsProps<T>) => {\n  const scrollPosition = useHorizontalScrollPosition(scrollWrapper);\n\n  const scrollStartClickHandler = () => {\n    scrollWrapper?.scrollBy({ left: -150, behavior: 'smooth' });\n  };\n\n  const scrollEndClickHandler = () => {\n    scrollWrapper?.scrollBy({ left: 150, behavior: 'smooth' });\n  };\n  return (\n    <>\n      {scrollPosition && scrollPosition !== 'start' && (\n        <IconButton\n          onClick={scrollStartClickHandler}\n          icon=\"caret-left\"\n          className=\"str-video__speaker-layout__participants-bar--button-left\"\n        />\n      )}\n      {scrollPosition && scrollPosition !== 'end' && (\n        <IconButton\n          onClick={scrollEndClickHandler}\n          icon=\"caret-right\"\n          className=\"str-video__speaker-layout__participants-bar--button-right\"\n        />\n      )}\n    </>\n  );\n};\n\nconst VerticalScrollButtons = <T extends HTMLElement>({\n  scrollWrapper,\n}: ScrollButtonsProps<T>) => {\n  const scrollPosition = useVerticalScrollPosition(scrollWrapper);\n\n  const scrollTopClickHandler = () => {\n    scrollWrapper?.scrollBy({ top: -150, behavior: 'smooth' });\n  };\n\n  const scrollBottomClickHandler = () => {\n    scrollWrapper?.scrollBy({ top: 150, behavior: 'smooth' });\n  };\n  return (\n    <>\n      {scrollPosition && scrollPosition !== 'top' && (\n        <IconButton\n          onClick={scrollTopClickHandler}\n          icon=\"caret-up\"\n          className=\"str-video__speaker-layout__participants-bar--button-top\"\n        />\n      )}\n      {scrollPosition && scrollPosition !== 'bottom' && (\n        <IconButton\n          onClick={scrollBottomClickHandler}\n          icon=\"caret-down\"\n          className=\"str-video__speaker-layout__participants-bar--button-bottom\"\n        />\n      )}\n    </>\n  );\n};\n","import { useCall, useI18n } from '@stream-io/video-react-bindings';\nimport { useEffect, useState } from 'react';\n\nimport { hasScreenShare } from '@stream-io/video-client';\nimport { Icon } from '../../../components';\nimport { ParticipantsAudio } from '../Audio';\nimport {\n  DefaultParticipantViewUI,\n  ParticipantView,\n  ParticipantViewProps,\n} from '../ParticipantView';\nimport {\n  ParticipantFilter,\n  ParticipantPredicate,\n  useFilteredParticipants,\n  usePaginatedLayoutSortPreset,\n  useRawRemoteParticipants,\n} from './hooks';\n\nexport type PipLayoutProps = {\n  /**\n   * Whether to exclude the local participant from the grid.\n   * @default false\n   */\n  excludeLocalParticipant?: boolean;\n\n  /**\n   * Predicate to filter call participants or a filter object.\n   * @example\n   * // With a predicate:\n   * <PipLayout\n   *   filterParticipants={p => p.roles.includes('student')}\n   * />\n   * @example\n   * // With a filter object:\n   * <PipLayout\n   *   filterParticipants={{\n   *     $or: [\n   *       { roles: { $contains: 'student' } },\n   *       { isPinned: true },\n   *     ],\n   *   }}\n   * />\n   */\n  filterParticipants?: ParticipantPredicate | ParticipantFilter;\n\n  /**\n   * When set to `false` disables mirroring of the local partipant's video.\n   * @default true\n   */\n  mirrorLocalParticipantVideo?: boolean;\n} & Pick<ParticipantViewProps, 'ParticipantViewUI' | 'VideoPlaceholder'>;\n\nconst Pip = (props: PipLayoutProps) => {\n  const { t } = useI18n();\n  const {\n    excludeLocalParticipant = false,\n    filterParticipants,\n    mirrorLocalParticipantVideo = true,\n    VideoPlaceholder,\n    ParticipantViewUI = DefaultParticipantViewUI,\n  } = props;\n  const [layoutWrapperElement, setLayoutWrapperElement] =\n    useState<HTMLDivElement | null>(null);\n\n  const call = useCall();\n  const participants = useFilteredParticipants({\n    excludeLocalParticipant,\n    filterParticipants,\n  });\n  const screenSharingParticipant = participants.find((p) => hasScreenShare(p));\n\n  usePaginatedLayoutSortPreset(call);\n\n  useEffect(() => {\n    if (!layoutWrapperElement || !call) return;\n    return call.setViewport(layoutWrapperElement);\n  }, [layoutWrapperElement, call]);\n\n  const mirror = mirrorLocalParticipantVideo ? undefined : false;\n\n  if (!call) return null;\n\n  return (\n    <div className=\"str-video__pip-layout\" ref={setLayoutWrapperElement}>\n      {screenSharingParticipant &&\n        (screenSharingParticipant.isLocalParticipant ? (\n          <div className=\"str-video__pip-screen-share-local\">\n            <Icon icon=\"screen-share-off\" />\n            <span className=\"str-video__pip-screen-share-local__title\">\n              {t('You are presenting your screen')}\n            </span>\n          </div>\n        ) : (\n          <ParticipantView\n            participant={screenSharingParticipant}\n            trackType=\"screenShareTrack\"\n            muteAudio\n            mirror={false}\n            VideoPlaceholder={VideoPlaceholder}\n            ParticipantViewUI={ParticipantViewUI}\n          />\n        ))}\n      {participants.map((participant) => (\n        <ParticipantView\n          key={participant.sessionId}\n          participant={participant}\n          muteAudio\n          mirror={mirror}\n          VideoPlaceholder={VideoPlaceholder}\n          ParticipantViewUI={ParticipantViewUI}\n        />\n      ))}\n    </div>\n  );\n};\n\nPip.displayName = 'PipLayout.Pip';\n\nconst Host = () => {\n  const remoteParticipants = useRawRemoteParticipants();\n  return <ParticipantsAudio participants={remoteParticipants} />;\n};\n\nHost.displayName = 'PipLayout.Host';\n\nexport const PipLayout = { Pip, Host };\n","import { PropsWithChildren, useEffect, useState } from 'react';\nimport { Call, CallingState } from '@stream-io/video-client';\nimport {\n  useCall,\n  useCallStateHooks,\n  useEffectEvent,\n  useStreamVideoClient,\n} from '@stream-io/video-react-bindings';\nimport {\n  BackstageLayout,\n  BackstageLayoutProps,\n  LivestreamLayout,\n  LivestreamLayoutProps,\n  StreamCall,\n} from '../../core';\n\nexport type LivestreamPlayerProps = {\n  /**\n   * The call type. Usually `livestream`.\n   */\n  callType: string;\n  /**\n   * The call ID.\n   */\n  callId: string;\n  /**\n   * Determines when the viewer joins the call.\n   *\n   * `\"asap\"` behavior means joining the call as soon as it is possible\n   * (either the `join_ahead_time_seconds` setting allows it, or the user\n   * has the capability to join backstage).\n   *\n   * `\"live\"` behavior means joining the call when it goes live.\n   *\n   * @default \"asap\"\n   */\n  joinBehavior?: 'asap' | 'live';\n  /**\n   * The props for the {@link LivestreamLayout} component.\n   */\n  layoutProps?: LivestreamLayoutProps;\n  /**\n   * The props for the {@link BackstageLayout} component.\n   */\n  backstageProps?: BackstageLayoutProps;\n  /**\n   * Callback to handle errors while fetching or joining livestream.\n   */\n  onError?: (error: any) => void;\n};\n\nexport const LivestreamPlayer = (\n  props: PropsWithChildren<LivestreamPlayerProps>,\n) => {\n  const { callType, callId, children, ...restProps } = props;\n  const client = useStreamVideoClient();\n  const [call, setCall] = useState<Call>();\n  const onError = useEffectEvent(props.onError ?? (() => {}));\n\n  useEffect(() => {\n    if (!client) return;\n    const myCall = client.call(callType, callId);\n    setCall(myCall);\n    myCall.get().catch((e) => {\n      console.error('Failed to fetch call', e);\n      onError(e);\n    });\n    return () => {\n      myCall.leave().catch((e) => {\n        console.error('Failed to leave call', e);\n      });\n      setCall(undefined);\n    };\n  }, [callId, callType, client]);\n\n  if (!call) {\n    return null;\n  }\n\n  return (\n    <StreamCall call={call}>\n      <LivestreamCall {...restProps} />\n      {children}\n    </StreamCall>\n  );\n};\n\nconst LivestreamCall = (props: {\n  joinBehavior?: 'asap' | 'live';\n  layoutProps?: LivestreamLayoutProps;\n  backstageProps?: BackstageLayoutProps;\n  onError?: (error: any) => void;\n}) => {\n  const call = useLivestreamCall(props);\n  const { useIsCallLive } = useCallStateHooks();\n  const isLive = useIsCallLive();\n\n  if (!call) return null;\n\n  if (isLive) {\n    return <LivestreamLayout {...props.layoutProps} />;\n  }\n\n  return <BackstageLayout {...props.backstageProps} />;\n};\n\nconst useLivestreamCall = (props: {\n  joinBehavior?: 'asap' | 'live';\n  onError?: (error: any) => void;\n}) => {\n  const call = useCall();\n  const { useIsCallLive, useOwnCapabilities } = useCallStateHooks();\n  const canJoinLive = useIsCallLive();\n  const canJoinEarly = useCanJoinEarly();\n  const canJoinBackstage =\n    useOwnCapabilities()?.includes('join-backstage') ?? false;\n  const canJoinAsap = canJoinLive || canJoinEarly || canJoinBackstage;\n  const joinBehavior = props.joinBehavior ?? 'asap';\n  const canJoin =\n    (joinBehavior === 'asap' && canJoinAsap) ||\n    (joinBehavior === 'live' && canJoinLive);\n  const onError = useEffectEvent(props.onError ?? (() => {}));\n\n  useEffect(() => {\n    if (call && call.state.callingState === CallingState.IDLE && canJoin) {\n      call.join().catch((e) => {\n        console.error('Failed to join call', e);\n        onError(e);\n      });\n    }\n  }, [call, canJoin]);\n\n  return call;\n};\n\nconst useCanJoinEarly = () => {\n  const { useCallStartsAt, useCallSettings } = useCallStateHooks();\n  const startsAt = useCallStartsAt();\n  const settings = useCallSettings();\n  const joinAheadTimeSeconds = settings?.backstage.join_ahead_time_seconds;\n  const [canJoinEarly, setCanJoinEarly] = useState(() =>\n    checkCanJoinEarly(startsAt, joinAheadTimeSeconds),\n  );\n\n  useEffect(() => {\n    if (!canJoinEarly) {\n      const handle = setInterval(() => {\n        setCanJoinEarly(checkCanJoinEarly(startsAt, joinAheadTimeSeconds));\n      }, 1000);\n\n      return () => clearInterval(handle);\n    }\n  }, [canJoinEarly, startsAt, joinAheadTimeSeconds]);\n\n  return canJoinEarly;\n};\n\nconst checkCanJoinEarly = (\n  startsAt: Date | undefined,\n  joinAheadTimeSeconds: number | undefined,\n) => {\n  if (!startsAt) {\n    return false;\n  }\n\n  return Date.now() >= +startsAt - (joinAheadTimeSeconds ?? 0) * 1000;\n};\n","import { setSdkInfo, SfuModels } from '@stream-io/video-client';\n\nexport * from '@stream-io/video-client';\nexport * from '@stream-io/video-react-bindings';\n\nexport * from './src/core';\n\nexport * from './src/components';\nexport * from './src/wrappers';\nexport * from './src/translations';\nexport {\n  useHorizontalScrollPosition,\n  useVerticalScrollPosition,\n  useRequestPermission,\n  usePersistedDevicePreferences,\n  useDeviceList,\n} from './src/hooks';\nexport { applyFilter, type Filter } from './src/utilities/filter';\n\nconst [major, minor, patch] = (\n  process.env.PKG_VERSION || '0.0.0-development'\n).split('.');\n\nsetSdkInfo({\n  type: SfuModels.SdkType.REACT,\n  major,\n  minor,\n  patch,\n});\n"]}