@cross-nft-marketplace/auction-house-nft-components
Version:
NFT Media Rendering Components
111 lines (110 loc) • 5.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Audio = exports.AudioRenderer = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const useSyncRef_1 = require("../utils/useSyncRef");
const MediaLoader_1 = require("./MediaLoader");
const RendererConfig_1 = require("./RendererConfig");
const FakeWaveformCanvas = ({ audioRef, uri, audioColors, }) => {
const canvasRef = (0, react_1.useRef)(null);
const [width, setWidth] = (0, react_1.useState)();
const updateWidth = (0, react_1.useCallback)(() => {
var _a, _b, _c;
const newWidth = (_c = (_b = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect()) === null || _c === void 0 ? void 0 : _c.width;
if (newWidth && newWidth !== width) {
setWidth(newWidth);
}
}, [canvasRef.current]);
(0, react_1.useEffect)(() => {
updateWidth();
window.addEventListener("resize", updateWidth);
return () => {
window.removeEventListener("resize", updateWidth);
};
}, [updateWidth]);
const uriEntropy = (0, react_1.useMemo)(() => uri
.split("")
.reduce((last, char) => last ^ (last + char.charCodeAt(0)), 0), [uri]);
(0, react_1.useEffect)(() => {
updateCanvasLines();
const updateInterval = setInterval(updateCanvasLines, 1000);
return () => clearInterval(updateInterval);
}, [width]);
const seekAudio = (0, react_1.useCallback)((evt) => {
if (audioRef.current && canvasRef.current && width) {
const position = (evt.clientX - canvasRef.current.getBoundingClientRect().left) /
width;
audioRef.current.currentTime = position * audioRef.current.duration;
audioRef.current.play();
updateCanvasLines();
}
}, [audioRef.current, width]);
const height = 200;
const updateCanvasLines = (0, react_1.useCallback)(() => {
if (canvasRef.current && width && audioRef.current) {
const context = canvasRef.current.getContext("2d");
if (!context) {
return;
}
context.clearRect(0, 0, width, height);
for (let i = 0; i < width; i += 5) {
const sinRnd = Math.sin(i + uriEntropy) * 10000;
const lineHeight = Math.floor(Math.min(Math.sin((i / width) * 0.2) +
2 * (sinRnd - Math.floor(sinRnd)) * 40, height));
if (audioRef.current.currentTime / audioRef.current.duration >
i / width) {
context.fillStyle = audioColors.progressColor;
}
else {
context.fillStyle = audioColors.waveformColor;
}
context.fillRect(i, (height - lineHeight) / 2, 2, lineHeight);
}
}
}, [canvasRef.current, audioRef.current, width]);
return ((0, jsx_runtime_1.jsx)("canvas", { ref: canvasRef, height: height, width: width, onClick: seekAudio }));
};
exports.AudioRenderer = (0, react_1.forwardRef)(({ request, media, getStyles, a11yIdPrefix, theme }, ref) => {
const uri = media === null || media === void 0 ? void 0 : media.url;
const { props, loading, error } = (0, MediaLoader_1.useMediaObjectProps)({
uri,
request,
a11yIdPrefix,
getStyles,
preferredIPFSGateway: theme.preferredIPFSGateway,
});
const audioRef = (0, react_1.useRef)(null);
(0, useSyncRef_1.useSyncRef)(audioRef, ref);
const [playing, setPlaying] = (0, react_1.useState)(false);
const wrapper = (0, react_1.useRef)();
const togglePlay = (0, react_1.useCallback)((evt) => {
evt.preventDefault();
evt.stopPropagation();
if (audioRef.current) {
if (playing) {
audioRef.current.pause();
}
else {
audioRef.current.play();
}
}
}, [audioRef.current, playing]);
(0, react_1.useEffect)(() => {
if (!audioRef.current) {
return;
}
if (playing) {
audioRef.current.play();
}
else {
audioRef.current.pause();
}
}, [audioRef.current, playing]);
const playingText = playing ? "Pause" : "Play";
return ((0, jsx_runtime_1.jsx)(MediaLoader_1.MediaLoader, { getStyles: getStyles, loading: loading, error: error, children: (0, jsx_runtime_1.jsxs)("div", { ref: wrapper, ...getStyles("mediaAudioWrapper"), children: [!loading && ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { "aria-live": "polite", "aria-pressed": playing ? true : false, onClick: togglePlay, title: playingText, ...getStyles("mediaPlayButton", undefined, { playing }), children: playingText }), (0, jsx_runtime_1.jsx)("div", { ...getStyles("mediaAudioWaveform"), children: (0, jsx_runtime_1.jsx)(FakeWaveformCanvas, { uri: uri || "", audioRef: audioRef, audioColors: theme.audioColors }) })] })), (0, jsx_runtime_1.jsx)("audio", { loop: true, ref: audioRef, preload: "auto", playsInline: true, onPlay: () => setPlaying(true), onPause: () => setPlaying(false), ...props, onLoadedData: props.onLoad, onCanPlayThrough: props.onLoad, onLoad: undefined })] }) }));
});
exports.Audio = {
supportedMimeTypes: [RendererConfig_1.MIME_TYPES_CONTENT.AUDIO],
render: exports.AudioRenderer,
};