Skip to content

Commit

Permalink
feat(player/react): default layout slots
Browse files Browse the repository at this point in the history
  • Loading branch information
mihar-22 committed Dec 18, 2023
1 parent c416a1e commit 209d400
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,40 @@ import {
DefaultTimeSlider,
DefaultVolumeSlider,
} from './shared-layout';
import { slot, useDefaultAudioLayoutSlots } from './slots';

/* -------------------------------------------------------------------------------------------------
* DefaultAudioLayoutLarge
* -----------------------------------------------------------------------------------------------*/

function DefaultAudioLayoutLarge() {
function DefaultAudioLargeLayout() {
const slots = useDefaultAudioLayoutSlots()?.largeLayout;
return (
<>
<Captions className="vds-captions" />
<Controls.Root className="vds-controls">
<Controls.Group className="vds-controls-group">
<DefaultTimeSlider />
{slot(slots, 'timeSlider', <DefaultTimeSlider />)}
</Controls.Group>
<Controls.Group className="vds-controls-group">
<DefaultSeekButton seconds={-10} tooltip="top start" />
<DefaultPlayButton tooltip="top center" />
<DefaultSeekButton seconds={10} tooltip="top center" />
<DefaultTimeInfo />
<DefaultChapterTitle />
<DefaultMuteButton tooltip="top center" />
<DefaultVolumeSlider />
<DefaultCaptionButton tooltip="top center" />
<DefaultAudioMenus />
{slot(
slots,
'seekBackwardButton',
<DefaultSeekButton seconds={-10} tooltip="top start" />,
)}
{slot(slots, 'playButton', <DefaultPlayButton tooltip="top center" />)}
{slot(
slots,
'seekForwardButton',
<DefaultSeekButton seconds={10} tooltip="top center" />,
)}
<DefaultTimeInfo slots={slots} />
{slot(slots, 'chapterTitle', <DefaultChapterTitle />)}
{slot(slots, 'muteButton', <DefaultMuteButton tooltip="top center" />)}
{slot(slots, 'volumeSlider', <DefaultVolumeSlider />)}
{slot(slots, 'captionButton', <DefaultCaptionButton tooltip="top center" />)}
<DefaultAudioMenus slots={slots} />
</Controls.Group>
</Controls.Root>
</>
);
}

DefaultAudioLayoutLarge.displayName = 'DefaultAudioLayoutLarge';
export { DefaultAudioLayoutLarge };
DefaultAudioLargeLayout.displayName = 'DefaultAudioLargeLayout';
export { DefaultAudioLargeLayout };
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,25 @@ import {
DefaultSeekButton,
DefaultTimeSlider,
} from './shared-layout';
import { slot, useDefaultAudioLayoutSlots } from './slots';

/* -------------------------------------------------------------------------------------------------
* DefaultAudioLayoutSmall
* -----------------------------------------------------------------------------------------------*/

function DefaultAudioLayoutSmall() {
function DefaultAudioSmallLayout() {
const slots = useDefaultAudioLayoutSlots()?.smallLayout;
return (
<>
<Captions className="vds-captions" />
{slot(slots, 'captions', <Captions className="vds-captions" />)}
<Controls.Root className="vds-controls">
<Controls.Group className="vds-controls-group">
<DefaultLivePlayButton />
<DefaultMuteButton tooltip="top start" />
<DefaultLiveButton />
<DefaultChapterTitle />
<DefaultCaptionButton tooltip="top center" />
<DefaultAudioMenus />
{slot(slots, 'livePlayButton', <DefaultLivePlayButton />)}
{slot(slots, 'muteButton', <DefaultMuteButton tooltip="top start" />)}
{slot(slots, 'liveButton', <DefaultLiveButton />)}
{slot(slots, 'chapterTitle', <DefaultChapterTitle />)}
{slot(slots, 'captionButton', <DefaultCaptionButton tooltip="top center" />)}
<DefaultAudioMenus slots={slots} />
</Controls.Group>

<Controls.Group className="vds-controls-group">
<DefaultTimeSlider />
{slot(slots, 'timeSlider', <DefaultTimeSlider />)}
</Controls.Group>

<DefaultTimeControlsGroup />
Expand All @@ -44,8 +42,8 @@ function DefaultAudioLayoutSmall() {
);
}

DefaultAudioLayoutSmall.displayName = 'DefaultAudioLayoutSmall';
export { DefaultAudioLayoutSmall };
DefaultAudioSmallLayout.displayName = 'DefaultAudioSmallLayout';
export { DefaultAudioSmallLayout };

/* -------------------------------------------------------------------------------------------------
* DefaultLivePlayButton
Expand All @@ -64,12 +62,13 @@ DefaultLivePlayButton.displayName = 'DefaultLivePlayButton';
* -----------------------------------------------------------------------------------------------*/

function DefaultTimeControlsGroup() {
const live = useMediaState('live');
const live = useMediaState('live'),
slots = useDefaultAudioLayoutSlots()?.smallLayout;
return !live ? (
<Controls.Group className="vds-controls-group">
<Time className="vds-time" type="current" />
{slot(slots, 'currentTime', <Time className="vds-time" type="current" />)}
<div className="vds-controls-spacer" />
<Time className="vds-time" type="duration" />
{slot(slots, 'endTime', <Time className="vds-time" type="duration" />)}
</Controls.Group>
) : null;
}
Expand All @@ -81,13 +80,14 @@ DefaultTimeControlsGroup.displayName = 'DefaultTimeControlsGroup';
* -----------------------------------------------------------------------------------------------*/

function DefaultBottomControlsGroup() {
const canSeek = useMediaState('canSeek');
const canSeek = useMediaState('canSeek'),
slots = useDefaultAudioLayoutSlots()?.smallLayout;
return canSeek ? (
<Controls.Group className="vds-controls-group">
<div className="vds-controls-spacer" />
<DefaultSeekButton seconds={-10} tooltip="top center" />
<DefaultPlayButton tooltip="top center" />
<DefaultSeekButton seconds={10} tooltip="top center" />
{slot(slots, 'seekBackwardButton', <DefaultSeekButton seconds={-10} tooltip="top center" />)}
{slot(slots, 'playButton', <DefaultPlayButton tooltip="top center" />)}
{slot(slots, 'seekForwardButton', <DefaultSeekButton seconds={10} tooltip="top center" />)}
<div className="vds-controls-spacer" />
</Controls.Group>
) : null;
Expand Down
11 changes: 6 additions & 5 deletions packages/react/src/components/layouts/default/audio-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as React from 'react';

import { DefaultAudioLayoutLarge } from './audio-layout-large';
import { DefaultAudioLayoutSmall } from './audio-layout-small';
import { DefaultAudioLargeLayout } from './audio-layout-large';
import { DefaultAudioSmallLayout } from './audio-layout-small';
import { createDefaultMediaLayout, type DefaultMediaLayoutProps } from './shared-layout';
import type { DefaultAudioLayoutSlots } from './slots';

/* -------------------------------------------------------------------------------------------------
* DefaultAudioLayout
Expand All @@ -11,11 +12,11 @@ import { createDefaultMediaLayout, type DefaultMediaLayoutProps } from './shared
const MediaLayout = createDefaultMediaLayout({
type: 'audio',
smLayoutWhen: '(width < 576)',
SmallLayout: DefaultAudioLayoutSmall,
LargeLayout: DefaultAudioLayoutLarge,
SmallLayout: DefaultAudioSmallLayout,
LargeLayout: DefaultAudioLargeLayout,
});

export interface DefaultAudioLayoutProps extends DefaultMediaLayoutProps {}
export interface DefaultAudioLayoutProps extends DefaultMediaLayoutProps<DefaultAudioLayoutSlots> {}

/**
* The audio layout is our production-ready UI that's displayed when the media view type is set to
Expand Down
20 changes: 17 additions & 3 deletions packages/react/src/components/layouts/default/audio-menus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@ import * as React from 'react';

import { DefaultLayoutContext } from './context';
import { DefaultChaptersMenu, DefaultSettingsMenu } from './shared-layout';
import { slot, type DefaultLayoutMenuSlotName, type Slots } from './slots';

/* -------------------------------------------------------------------------------------------------
* DefaultAudioMenus
* -----------------------------------------------------------------------------------------------*/

function DefaultAudioMenus() {
function DefaultAudioMenus({ slots }: { slots?: Slots<DefaultLayoutMenuSlotName> }) {
const { isSmallLayout, noModal } = React.useContext(DefaultLayoutContext),
placement = noModal ? 'top end' : !isSmallLayout ? 'top end' : null;
return (
<>
<DefaultChaptersMenu tooltip="top" placement={placement} portalClass="vds-audio-layout" />
<DefaultSettingsMenu tooltip="top end" placement={placement} portalClass="vds-audio-layout" />
{slot(
slots,
'chaptersMenu',
<DefaultChaptersMenu tooltip="top" placement={placement} portalClass="vds-audio-layout" />,
)}
{slot(
slots,
'settingsMenu',
<DefaultSettingsMenu
tooltip="top end"
placement={placement}
portalClass="vds-audio-layout"
slots={slots}
/>,
)}
</>
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/components/layouts/default/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface DefaultLayoutContext {
menuGroup: 'top' | 'bottom';
noModal: boolean;
Icons: DefaultLayoutIcons;
slots?: unknown;
}

export function useDefaultLayoutLang(word: keyof DefaultLayoutTranslations) {
Expand Down
7 changes: 7 additions & 0 deletions packages/react/src/components/layouts/default/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
export * from './ui';
export type {
DefaultLayoutSlots,
DefaultAudioLayoutSlots,
DefaultVideoLayoutSlots,
DefaultLayoutSlotName,
DefaultLayoutMenuSlotName,
} from './slots';
export * from './icons';
export * from './context';
40 changes: 32 additions & 8 deletions packages/react/src/components/layouts/default/shared-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import * as TooltipBase from '../../ui/tooltip';
import { RemotionSliderThumbnail, RemotionThumbnail } from '../remotion-ui';
import { DefaultLayoutContext, useDefaultLayoutLang } from './context';
import type { DefaultLayoutIcon, DefaultLayoutIcons } from './icons';
import { slot, type DefaultLayoutMenuSlotName, type Slots } from './slots';

/* -------------------------------------------------------------------------------------------------
* Types
Expand All @@ -49,13 +50,14 @@ interface DefaultMediaMenuProps {
tooltip: TooltipBase.ContentProps['placement'];
placement: MenuBase.ContentProps['placement'];
portalClass?: string;
slots?: Slots<DefaultLayoutMenuSlotName>;
}

/* -------------------------------------------------------------------------------------------------
* DefaultMediaLayout
* -----------------------------------------------------------------------------------------------*/

export interface DefaultMediaLayoutProps extends PrimitivePropsWithRef<'div'> {
export interface DefaultMediaLayoutProps<Slots = unknown> extends PrimitivePropsWithRef<'div'> {
children?: React.ReactNode;
/**
* The icons to be rendered and displayed inside the layout.
Expand Down Expand Up @@ -112,6 +114,10 @@ export interface DefaultMediaLayoutProps extends PrimitivePropsWithRef<'div'> {
* @defaultValue false
*/
noModal?: boolean;
/**
* Provide additional content to be inserted in specific positions.
*/
slots?: Slots;
}

export interface CreateDefaultMediaLayout {
Expand Down Expand Up @@ -142,6 +148,7 @@ export function createDefaultMediaLayout({
noModal = false,
menuGroup = 'bottom',
hideQualityBitrate = false,
slots,
children,
...props
},
Expand Down Expand Up @@ -173,6 +180,7 @@ export function createDefaultMediaLayout({
hideQualityBitrate,
noModal,
menuGroup,
slots,
Icons: icons,
}}
>
Expand Down Expand Up @@ -483,12 +491,18 @@ export { DefaultLiveButton };
* DefaultTimeGroup
* -----------------------------------------------------------------------------------------------*/

function DefaultTimeGroup() {
interface DefaultTimeGroupSlots {
currentTime?: React.ReactNode;
timeSeparator?: React.ReactNode;
endTime?: React.ReactNode;
}

function DefaultTimeGroup({ slots }: { slots?: DefaultTimeGroupSlots }) {
return (
<div className="vds-time-group">
<Time className="vds-time" type="current" />
<div className="vds-time-divider">/</div>
<Time className="vds-time" type="duration" />
{slot(slots, 'currentTime', <Time className="vds-time" type="current" />)}
{slot(slots, 'timeSeparator', <div className="vds-time-divider">/</div>)}
{slot(slots, 'endTime', <Time className="vds-time" type="duration" />)}
</div>
);
}
Expand All @@ -500,9 +514,17 @@ export { DefaultTimeGroup };
* DefaultTimeInfo
* -----------------------------------------------------------------------------------------------*/

function DefaultTimeInfo() {
interface DefaultTimeInfoSlots extends DefaultTimeGroupSlots {
liveButton?: React.ReactNode;
}

function DefaultTimeInfo({ slots }: { slots?: DefaultTimeInfoSlots }) {
const live = useMediaState('live');
return live ? <DefaultLiveButton /> : <DefaultTimeGroup />;
return live ? (
slot(slots, 'liveButton', <DefaultLiveButton />)
) : (
<DefaultTimeGroup slots={slots} />
);
}

DefaultTimeInfo.displayName = 'DefaultTimeInfo';
Expand Down Expand Up @@ -596,7 +618,7 @@ export { DefaultChaptersMenu };
* DefaultSettingsMenu
* -----------------------------------------------------------------------------------------------*/

function DefaultSettingsMenu({ tooltip, placement, portalClass }: DefaultMediaMenuProps) {
function DefaultSettingsMenu({ tooltip, placement, portalClass, slots }: DefaultMediaMenuProps) {
const { $state } = useReactContext(mediaContext)!,
{ showMenuDelay, Icons, isSmallLayout, menuGroup, noModal } =
React.useContext(DefaultLayoutContext),
Expand Down Expand Up @@ -627,10 +649,12 @@ function DefaultSettingsMenu({ tooltip, placement, portalClass }: DefaultMediaMe
placement={placement}
offset={$offset}
>
{slot(slots, 'settingsMenuStartItems', null)}
<DefaultAudioSubmenu />
<DefaultSpeedSubmenu />
<DefaultQualitySubmenu />
<DefaultCaptionSubmenu />
{slot(slots, 'settingsMenuEndItems', null)}
</MenuBase.Content>
);

Expand Down
Loading

0 comments on commit 209d400

Please sign in to comment.