UNPKG

@remotion/player

Version:

React component for embedding a Remotion preview into your app

130 lines (128 loc) • 5.31 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import React, { useCallback, useMemo, useRef, useState } from 'react'; import { Internals, random } from 'remotion'; import { ICON_SIZE, VolumeOffIcon, VolumeOnIcon } from './icons.js'; import { useHoverState } from './use-hover-state.js'; const BAR_HEIGHT = 5; const KNOB_SIZE = 12; export const VOLUME_SLIDER_WIDTH = 100; export const MediaVolumeSlider = ({ displayVerticalVolumeSlider }) => { const [mediaMuted, setMediaMuted] = Internals.useMediaMutedState(); const [mediaVolume, setMediaVolume] = Internals.useMediaVolumeState(); const [focused, setFocused] = useState(false); const parentDivRef = useRef(null); const inputRef = useRef(null); const hover = useHoverState(parentDivRef, false); // Need to import it from React to fix React 17 ESM support. const randomId = // eslint-disable-next-line react-hooks/rules-of-hooks typeof React.useId === 'undefined' ? 'volume-slider' : React.useId(); const [randomClass] = useState(() => `__remotion-volume-slider-${random(randomId)}`.replace('.', '')); const isMutedOrZero = mediaMuted || mediaVolume === 0; const onVolumeChange = useCallback((e) => { setMediaVolume(parseFloat(e.target.value)); }, [setMediaVolume]); const onBlur = () => { setTimeout(() => { // We need a small delay to check which element was focused next, // and if it wasn't the volume slider, we hide it if (document.activeElement !== inputRef.current) { setFocused(false); } }, 10); }; const isVolume0 = mediaVolume === 0; const onClick = useCallback(() => { if (isVolume0) { setMediaVolume(1); setMediaMuted(false); return; } setMediaMuted((mute) => !mute); }, [isVolume0, setMediaMuted, setMediaVolume]); const parentDivStyle = useMemo(() => { return { display: 'inline-flex', background: 'none', border: 'none', justifyContent: 'center', alignItems: 'center', touchAction: 'none', ...(displayVerticalVolumeSlider && { position: 'relative' }), }; }, [displayVerticalVolumeSlider]); const volumeContainer = useMemo(() => { return { display: 'inline', width: ICON_SIZE, height: ICON_SIZE, cursor: 'pointer', appearance: 'none', background: 'none', border: 'none', padding: 0, }; }, []); const sliderContainer = useMemo(() => { const paddingLeft = 5; const common = { paddingLeft, height: ICON_SIZE, width: VOLUME_SLIDER_WIDTH, }; if (displayVerticalVolumeSlider) { return { ...common, position: 'absolute', transform: `rotate(-90deg) translateX(${VOLUME_SLIDER_WIDTH / 2 + ICON_SIZE / 2}px)`, }; } return { ...common, }; }, [displayVerticalVolumeSlider]); const inputStyle = useMemo(() => { const commonStyle = { WebkitAppearance: 'none', backgroundColor: 'rgba(255, 255, 255, 0.5)', borderRadius: BAR_HEIGHT / 2, cursor: 'pointer', height: BAR_HEIGHT, width: VOLUME_SLIDER_WIDTH, backgroundImage: `linear-gradient( to right, white ${mediaVolume * 100}%, rgba(255, 255, 255, 0) ${mediaVolume * 100}% )`, }; if (displayVerticalVolumeSlider) { return { ...commonStyle, bottom: ICON_SIZE + VOLUME_SLIDER_WIDTH / 2, }; } return commonStyle; }, [displayVerticalVolumeSlider, mediaVolume]); const sliderStyle = ` .${randomClass}::-webkit-slider-thumb { -webkit-appearance: none; background-color: white; border-radius: ${KNOB_SIZE / 2}px; box-shadow: 0 0 2px black; height: ${KNOB_SIZE}px; width: ${KNOB_SIZE}px; } .${randomClass}::-moz-range-thumb { -webkit-appearance: none; background-color: white; border-radius: ${KNOB_SIZE / 2}px; box-shadow: 0 0 2px black; height: ${KNOB_SIZE}px; width: ${KNOB_SIZE}px; } `; return (_jsxs("div", { ref: parentDivRef, style: parentDivStyle, children: [_jsx("style", { // eslint-disable-next-line react/no-danger dangerouslySetInnerHTML: { __html: sliderStyle, } }), _jsx("button", { "aria-label": isMutedOrZero ? 'Unmute sound' : 'Mute sound', title: isMutedOrZero ? 'Unmute sound' : 'Mute sound', onClick: onClick, onBlur: onBlur, onFocus: () => setFocused(true), style: volumeContainer, type: "button", children: isMutedOrZero ? _jsx(VolumeOffIcon, {}) : _jsx(VolumeOnIcon, {}) }), (focused || hover) && !mediaMuted && !Internals.isIosSafari() ? (_jsx("div", { style: sliderContainer, children: _jsx("input", { ref: inputRef, "aria-label": "Change volume", className: randomClass, max: 1, min: 0, onBlur: () => setFocused(false), onChange: onVolumeChange, step: 0.01, type: "range", value: mediaVolume, style: inputStyle }) })) : null] })); };