newOS for Developers

Back to Overview

MediaComponent

output155 lines

A universal media renderer that automatically selects the appropriate component based on content type (image, video, text, or fallback).

Source Path
apps/web/Components/MediaComponents/MediaComponent.tsx
Package

@newos/web

Content Type Registry

const contentTypeElements: Record<string, ContentElement> = {
  default:      UniversalComponent,    // Fallback for unknown types
  "image/jpeg": ImageComponent,
  "image/png":  ImageComponent,
  "image/gif":  ImageComponent,
  "video/mp4":  VideoComponent,
  "text/plain": TextMediaComponent,
  "text/html":  TextMediaComponent,
};

Props (ContentImageProps)

MediaComponent: ContentElement = (props: ContentImageProps) => {
  contentType?: string;         // MIME type for component selection
  thumbnail?: boolean;          // Thumbnail mode (default: true)
  content?: string;             // Text content for TextMediaComponent
  contentUrl?: string;          // URL for media content
  agents?: UserReadPublicResponse[];
  mode?: "chat" | undefined;    // Affects border-radius styling
  height?: string | number;     // Container height
  width?: string | number;      // Container width
  eagerDisplay?: boolean;       // Skip visibility check
  mediaContentMode?: string;    // If includes "none", skip text overlay
  // ...additional props passed to sub-components
}

Component Selection Logic

1. Look up contentType in registry, fallback to "default"
2. If type is default OR text/plain with no content → use UniversalComponent
3. If not text type but has content prop → render TextMediaComponent as overlay
4. Wrap in visibility observer for lazy loading (unless eagerDisplay)

Key Features

Lazy Loading

Uses useVisibilityOnce hook with 150ms threshold to only render content when visible in viewport. Override with eagerDisplay=true.

Text Overlay

For non-text content types, automatically renders TextMediaComponentas an extra overlay if content prop exists. Skip with mediaContentMode="none".

Mode-Based Styling

mode="chat" removes border-radius (0px) for seamless chat bubble integration. Default mode uses 18px border-radius.

Error Handling

Catches errors via onError callback and stores in state. Error state triggers error display (currently minimal implementation).

Responsive Width

For text/plain content without mode, sets minWidth: 300pxand centers on mobile using useIsWideScreen hook.

Edge Cases & Gotchas

Thumbnail Default — The thumbnail prop defaults to truevia thumbnail ?? true. Pass explicit false for full-size rendering.
Non-Thumbnail Path — When thumbnail=false, the component renders without the visibility observer wrapper, potentially affecting performance.
Unknown Content Types — Content types not in the registry fall through toUniversalComponent, which attempts generic rendering.
CSS Class — Uses ant-image-size class from Ant Design for consistent image sizing.

Sub-Components

ImageComponent

Handles JPEG, PNG, GIF images with lazy loading and thumbnail generation.

VideoComponent

MP4 video player with custom controls.

TextMediaComponent

Rich text renderer for plain text and HTML content with typewriter effects.

UniversalComponent

Fallback component for unknown content types, attempts best-effort rendering.

Related Components

PostWidgetFolderCoreuseVisibilityOnce