Skip to content

Commit

Permalink
feat: let user interact with core player from react player (#276)
Browse files Browse the repository at this point in the history
* feat: let user interact with core player from react player

* fix: avoid constantly handling resize

* chore: address comments
  • Loading branch information
justusmattern27 authored Sep 22, 2024
1 parent c83cc72 commit 656efc5
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 6 deletions.
9 changes: 6 additions & 3 deletions packages/2d/src/lib/scenes/Scene2D.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,12 @@ export class Scene2D extends GeneratorScene<View2D> implements Inspectable {
}

public inspectPosition(x: number, y: number): InspectedElement | null {
return this.execute(
() => this.getView().hit(new Vector2(x, y))?.key ?? null,
);
const node = this.getNodeByPosition(x, y);
return node?.key;
}

public getNodeByPosition(x: number, y: number): Node | null {
return this.execute(() => this.getView().hit(new Vector2(x, y)) ?? null);
}

public validateInspection(
Expand Down
56 changes: 53 additions & 3 deletions packages/player-react/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';
import {ComponentProps, useEffect, useRef, useState} from 'react';
import {Player as CorePlayer} from '@revideo/core';
import {ComponentProps, useCallback, useEffect, useRef, useState} from 'react';
import {Controls} from './controls';
import './styles.css';
import {shouldShowControls} from './utils';
Expand Down Expand Up @@ -42,6 +43,8 @@ interface PlayerProps {

onDurationChange?: (duration: number) => void;
onTimeUpdate?: (currentTime: number) => void;
onPlayerReady?: (player: CorePlayer) => void;
onPlayerResize?: (rect: DOMRectReadOnly) => void;
}

export function Player({
Expand All @@ -62,6 +65,8 @@ export function Player({

onDurationChange = () => {},
onTimeUpdate = () => {},
onPlayerReady = () => {},
onPlayerResize = () => {},
}: PlayerProps) {
const [playingState, setPlaying] = useState(playing);
const [isMouseOver, setIsMouseOver] = useState(false);
Expand All @@ -70,7 +75,11 @@ export function Player({
const [duration, setDuration] = useState(-1);

const focus = useRef(false);
const playerRef = useRef<HTMLDivElement>(null);
const playerRef = useRef<HTMLDivElement | null>(null);
const wrapperRef = useRef<HTMLDivElement | null>(null);
const lastRect = useRef<DOMRectReadOnly | null>(null);

const onClickHandler = controls ? () => setPlaying(prev => !prev) : undefined;

/**
* Sync the playing prop with the player's own state when it changes.
Expand Down Expand Up @@ -121,6 +130,44 @@ export function Player({
}
};

const handlePlayerReady = (event: Event) => {
const player = (event as CustomEvent).detail;
if (player) {
onPlayerReady(player);
}
};

const handlePlayerResize = useCallback(
(entries: ResizeObserverEntry[]) => {
const [firstEntry] = entries;
if (!firstEntry || !wrapperRef.current) {
return;
}

const newRect = firstEntry.contentRect;
const sameWidth = newRect.width === lastRect.current.width;
const sameHeight = newRect.height === lastRect.current.height;
if (lastRect.current && sameWidth && sameHeight) {
return;
}

lastRect.current = newRect;
onPlayerResize(newRect);
},
[onPlayerResize],
);

useEffect(() => {
if (!wrapperRef.current) return;

const resizeObserver = new ResizeObserver(handlePlayerResize);
resizeObserver.observe(wrapperRef.current);

return () => {
resizeObserver.disconnect();
};
}, [handlePlayerResize]);

/**
* Import the player and add all event listeners.
*/
Expand All @@ -129,11 +176,13 @@ export function Player({

playerRef.current?.addEventListener('timeupdate', handleTimeUpdate);
playerRef.current?.addEventListener('duration', handleDurationUpdate);
playerRef.current?.addEventListener('playerready', handlePlayerReady);
document.addEventListener('keydown', handleKeyDown);

return () => {
playerRef.current?.removeEventListener('timeupdate', handleTimeUpdate);
playerRef.current?.removeEventListener('duration', handleDurationUpdate);
playerRef.current?.removeEventListener('playerready', handlePlayerReady);
document.removeEventListener('keydown', handleKeyDown);
const frameElement = document.getElementById('revideo-2d-frame');
if (frameElement) {
Expand Down Expand Up @@ -165,6 +214,7 @@ export function Player({
return (
<div data-player="true" style={{display: 'contents'}}>
<div
ref={wrapperRef}
className="p-relative p-cursor-default p-focus:outline-none"
onFocus={() => (focus.current = true)}
onBlur={() => (focus.current = false)}
Expand All @@ -177,7 +227,7 @@ export function Player({
ref={playerRef}
src={src}
playing={String(playingState)}
onClick={() => setPlaying(prev => !prev)}
onClick={onClickHandler}
variables={JSON.stringify(variables)}
looping={looping ? 'true' : 'false'}
width={width}
Expand Down
1 change: 1 addition & 0 deletions packages/player-react/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class RevideoPlayer extends HTMLElement {
this.player.togglePlayback(this.playing);

this.setState(State.Ready);
this.dispatchEvent(new CustomEvent('playerready', {detail: this.player}));
}

public attributeChangedCallback(name: string, _: any, newValue: any) {
Expand Down

0 comments on commit 656efc5

Please sign in to comment.