@streamiq/ui
v1.1.0
Published
Render-only cinematic media UI primitives for Streamq — controls, overlays, menus, sliders, subtitle rendering, and layout.
Downloads
133
Maintainers
Readme
@streamiq/ui
Render-only React media primitives for Streamq — controls, overlays, menus, seekbar parts, subtitle layer, layout, animation, focus, accessibility, icons, tokens, and hooks.
Stable
1.0.x. Peer:react≥ 18. Workspace dep:@streamiq/react. No playback engine, no protocol code, no UX orchestration.
Install
npm install @streamiq/ui react react-dom
# Optional themed CSS:
npm install @streamiq/themesWhat this package provides
- Surface —
PlayerSurfaceroot container - Layout —
ControlBar,BottomDock,TopDock,CenterOverlay,Spacer - Controls —
ControlButton,IconButton,ToggleButton,ControlGroup, plusvolume/ - Seekbar —
SeekbarRoot,SeekbarTrack,SeekbarBuffered,SeekbarProgress,SeekbarThumb,SeekbarMarkers,SeekbarTooltip - Subtitles —
SubtitleLayer,SubtitleRegion,SubtitleContainer,SubtitleCue(DOM overlay) - Menus — Radix-style:
MenuRoot,MenuPage,MenuList,MenuItem,MenuRadioGroup,MenuCheckboxItem,MenuHeader,MenuBackButton,MenuShortcut, pluspatterns/ - Overlays —
OverlayRoot,OverlayLayer,OverlayPanel,OverlayBackdrop,OverlayDock,OverlayPortal - Compositions —
BufferingOverlay,CinematicBackdrop,GestureHint, plustop-controls/,bottom-controls/,center-overlay/,subtitle-overlay/,settings-overlay/ - Responsive —
DesktopControlsLayout,MobileControlsLayout - Accessibility —
LiveRegion,VisuallyHidden - Focus —
FocusRing,FocusScope,FocusTrap,RovingFocusGroup,focusable - Animation —
FadeTransition,ScaleTransition,SlideTransition - Time —
TimeDisplay - Icons — tree-shakeable inline SVG (
PlayIcon,PauseIcon,VolumeIcon,FullscreenIcon,PiPIcon,SubtitleIcon,QualityIcon,SettingsIcon,SpeedIcon,KeyboardIcon,BackIcon,ChevronRightIcon,SleepIcon) - Hooks —
useFocusVisible,useHoverState,usePointerType,useReducedMotion - Tokens — design-token bridge for
@streamiq/themes
What this package does NOT provide
- Playback orchestration (
@streamiq/core) - Player runtime logic, visibility timers, gesture/keyboard engines (
@streamiq/player) - Protocol integrations (
@streamiq/hls,@streamiq/dash) - Hooks that subscribe to
Player(@streamiq/react)
Architecture
@streamiq/ui/src
├── surface/ PlayerSurface (root container)
├── layout/ BottomDock, TopDock, ControlBar, CenterOverlay, Spacer
├── controls/ ControlButton, IconButton, ToggleButton, ControlGroup, volume/
├── seekbar/ Compound seekbar primitives
├── subtitles/ DOM subtitle overlay (consumes cue stream)
├── menu/ Compound menu primitives + patterns/
├── overlays/ Backdrop / panel / portal / dock / layer
├── compositions/ Opinionated combinations of the primitives above
├── responsive/ Desktop / mobile controls layouts
├── accessibility/ LiveRegion, VisuallyHidden
├── focus/ FocusRing, FocusScope, FocusTrap, RovingFocusGroup
├── animation/ Fade / Scale / Slide transitions
├── time/ TimeDisplay
├── icons/ Tree-shakeable SVG icons
├── tokens/ Design-token bridge
├── hooks/ useFocusVisible, useHoverState, usePointerType, useReducedMotion
└── utils/ className helpers (clsx-based)Design philosophy
@streamiq/ui is modeled after Radix UI + media-specific primitives + streaming-player overlays. It is not a big customizable player component.
Prop-driven, not hook-driven
Components accept data and callbacks as props. They do not subscribe to player state internally. The consuming layer (@streamiq/player preset, or your app) wires @streamiq/react hooks to @streamiq/ui props:
import { ToggleButton, PlayIcon, PauseIcon } from '@streamiq/ui';
import { usePaused, useTogglePlayback } from '@streamiq/react';
function PlayPauseButton() {
const paused = usePaused();
const toggle = useTogglePlayback();
return (
<ToggleButton
pressed={!paused}
onPressedChange={() => toggle()}
aria-label={paused ? 'Play' : 'Pause'}
>
{paused ? <PlayIcon /> : <PauseIcon />}
</ToggleButton>
);
}Headless-first
All components render with data-streamq-* attributes for styling hooks. Pair with @streamiq/themes for default tokens, or write your own CSS — the components don't ship hard-coded styles in JS.
Tree-shakeable
Every subsystem is a separate module. Import only what you use — unused components are eliminated at build time. CSS sideEffects: *.css only.
Subtitle layer
The subtitle primitives consume the active-cue stream surfaced by @streamiq/react's useActiveCue and the SubtitleStyle tokens from @streamiq/core.
import { SubtitleLayer, SubtitleCue } from '@streamiq/ui';
import { useActiveCues, useSubtitleAnnouncer } from '@streamiq/react';
function Subtitles() {
const cues = useActiveCues();
useSubtitleAnnouncer(cues);
return (
<SubtitleLayer>
{cues.map((cue) => (
<SubtitleCue key={cue.id} cue={cue} />
))}
</SubtitleLayer>
);
}Bundle size
| Budget (.size-limit.json) | Limit |
|-----------------------------|-------|
| Full bundle | 8 kB gzipped |
| { STREAMQ_UI_PACKAGE } | 300 B |
Allowed workspace edges
| Package | May depend on |
|---------|--------------|
| ui | react |
Enforced by pnpm run check:boundaries.
License
MIT
