feat: initialize Video.js 10 monorepo with core architecture

- Set up monorepo structure with core, HTML, React, and React Native packages
- Add TypeScript configuration with project references
- Create foundational packages: media-store, playback-engine, media, icons
- Implement platform-specific packages for HTML, React, and React Native
- Add comprehensive documentation and development tooling
- Include CLAUDE.md with development guidelines and conventional commits

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Christian Pillsbury
2025-07-29 10:41:46 -07:00
co-authored by Claude
commit 4b0d84e9c8
55 changed files with 3421 additions and 0 deletions
@@ -0,0 +1,84 @@
import { MediaStore, MediaState, MediaStateOwner } from '@vjs-10/media-store';
import { VjsMediaElement } from '@vjs-10/html-media-elements';
export class HTMLMediaStateOwner implements MediaStateOwner {
private element: VjsMediaElement;
private listeners: Map<string, EventListener> = new Map();
constructor(element: VjsMediaElement) {
this.element = element;
this.setupEventListeners();
}
getState(): MediaState {
return {
currentTime: this.element.currentTime,
duration: this.element.duration,
paused: this.element.paused,
volume: this.element.volume,
muted: this.element.muted,
};
}
setState(state: Partial<MediaState>): void {
if (state.currentTime !== undefined && state.currentTime !== this.element.currentTime) {
this.element.currentTime = state.currentTime;
}
if (state.volume !== undefined && state.volume !== this.element.volume) {
this.element.volume = state.volume;
}
if (state.muted !== undefined && state.muted !== this.element.muted) {
this.element.muted = state.muted;
}
}
private setupEventListeners() {
const timeUpdateListener = () => {
this.dispatchStateChange();
};
const playPauseListener = () => {
this.dispatchStateChange();
};
const volumeChangeListener = () => {
this.dispatchStateChange();
};
this.element.addEventListener('vjs-timeupdate', timeUpdateListener);
this.element.addEventListener('vjs-play', playPauseListener);
this.element.addEventListener('vjs-pause', playPauseListener);
this.element.addEventListener('volumechange', volumeChangeListener);
this.listeners.set('timeupdate', timeUpdateListener);
this.listeners.set('play', playPauseListener);
this.listeners.set('pause', playPauseListener);
this.listeners.set('volumechange', volumeChangeListener);
}
private dispatchStateChange() {
this.element.dispatchEvent(new CustomEvent('vjs-state-change', {
detail: this.getState()
}));
}
destroy() {
this.listeners.forEach((listener, event) => {
this.element.removeEventListener(event as any, listener);
});
this.listeners.clear();
}
}
export function connectMediaElementToStore(element: VjsMediaElement, store: MediaStore): HTMLMediaStateOwner {
const owner = new HTMLMediaStateOwner(element);
store.addOwner(owner);
element.addEventListener('vjs-state-change', (event: CustomEvent) => {
store.updateState(event.detail);
});
return owner;
}
export { MediaStore, MediaState, MediaStateOwner } from '@vjs-10/media-store';