@xhub-short/ui
v0.1.0-beta.9
Published
Presentation layer (Lego Components) for XHub-short SDK
Readme
@xhub-short/ui
Headless UI Components for Short Video SDK
Overview
This package provides headless React components for the XHub-short SDK. Components are designed to be:
- 🎯 Headless: All data via props, no SDK coupling
- 📦 Tree-shakeable: Import only what you need
- 🎨 Themeable: CSS variables for customization
- 🚀 Performant: <5KB per component (gzipped)
- 🌙 Dark mode ready: Automatic theme support
Installation
pnpm add @xhub-short/uiUsage
Option A: Import from SDK (Recommended)
For most users, import pre-wired components from @xhub-short/sdk:
import { VideoFeed, VideoSlot, ActionBar } from '@xhub-short/sdk';
function App() {
return (
<ShortVideoProvider config={...}>
<VideoFeed>
{(video) => (
<VideoSlot video={video}>
<ActionBar />
</VideoSlot>
)}
</VideoFeed>
</ShortVideoProvider>
);
}Option B: Granular Imports (Smaller Bundle)
For optimal tree-shaking, use granular imports:
// Only bundles VideoFeed (~3-5KB) instead of all components
import { VideoFeed } from '@xhub-short/ui/VideoFeed';
import { VideoSlot } from '@xhub-short/ui/VideoSlot';Option C: Headless Components (Custom State Management)
For full control with your own state management:
import { VideoFeedHeadless } from '@xhub-short/ui';
function CustomFeed() {
// Your own state management
const [videos, setVideos] = useState([]);
const [activeIndex, setActiveIndex] = useState(0);
return (
<VideoFeedHeadless
feedState={{ videos, isLoading: false }}
swipeState={{ activeIndex, isSwiping: false }}
onIndexChange={setActiveIndex}
/>
);
}Bundle Optimization
This package is optimized for minimal bundle size:
| Import Pattern | Bundle Size |
|----------------|-------------|
| from '@xhub-short/ui' (all) | ~30-50KB |
| from '@xhub-short/ui/VideoFeed' | ~3-5KB |
| from '@xhub-short/ui/ActionBar' | ~2-3KB |
Verify Bundle Size
pnpm build
./scripts/check-bundle-size.shCreating New Components
Use the template in src/components/_template/:
# Copy template
cp -r src/components/_template src/components/MyComponent
# Rename files
mv src/components/MyComponent/TemplateComponent.tsx src/components/MyComponent/MyComponent.tsx
mv src/components/MyComponent/TemplateComponent.css.ts src/components/MyComponent/MyComponent.css.ts
mv src/components/MyComponent/TemplateComponent.test.tsx src/components/MyComponent/MyComponent.test.tsx
# Update index.ts exports
# Update component names and CSSComponent Structure
src/components/MyComponent/
├── index.ts # Entry point (exports)
├── MyComponent.tsx # Main component
├── MyComponent.css.ts # Per-component CSS string
└── MyComponent.test.tsx # TestsKey Patterns
- CSS Injection: Use
useInsertionEffectwithinjectComponentCSS - Props Only: No SDK imports, all data via props
- CSS Variables: Use
var(--sv-*)for theming - BEM Naming:
sv-component,sv-component__element,sv-component--modifier
CSS Theming
Components use CSS variables for theming:
/* Override in your app */
:root {
--sv-bg-primary: #000;
--sv-text-primary: #fff;
--sv-color-accent: #ff0050;
--sv-font-family: 'Urbanist', sans-serif;
}See src/styles/README.md for full theming documentation.
Architecture
@xhub-short/ui (this package)
├── Headless Components (VideoFeedHeadless, etc.)
├── Per-component CSS injection
└── NO SDK dependency
↓ imported by
@xhub-short/sdk
├── Wired Components (VideoFeed, etc.)
├── HOC Factory (injects SDK hooks)
└── Re-exports for host appsDevelopment
# Build
pnpm build
# Watch mode
pnpm dev
# Type check
pnpm typecheck
# Test
pnpm test
# Check bundle size
pnpm build:checkAvailable Components
| Component | Status | Size (gzip) | |-----------|--------|-------------| | VideoFeed | 🚧 Phase 4 | ~4KB | | VideoSlot | 🚧 Phase 4 | ~3KB | | VideoPlayer | 🚧 Phase 4 | ~3KB | | ActionBar | 🚧 Phase 4 | ~2KB | | ProgressBar | 🚧 Phase 4 | ~1KB | | AuthorInfo | 🚧 Phase 4 | ~2KB | | Skeleton | 🚧 Phase 4 | ~1KB | | ErrorBoundary | 🚧 Phase 4 | ~1KB |
License
MIT
