@aidenlx/player
Version:
Headless web components that make integrating media on the a web a breeze.
56 lines (42 loc) • 1.69 kB
text/typescript
import { camelToKebabCase, DisposalBin } from '@vidstack/foundation';
import type { ReactiveControllerHost } from 'lit';
import type { MediaContext } from '../MediaContext';
import { mediaStoreContext } from '../store';
export abstract class MediaStyleController {
protected _disposal = new DisposalBin();
protected _consumer: ReturnType<typeof mediaStoreContext['consume']>;
constructor(
protected readonly _host: ReactiveControllerHost & HTMLElement,
protected readonly _mediaProps: (keyof MediaContext)[],
) {
this._consumer = mediaStoreContext.consume(_host);
_host.addController({
hostConnected: this._hostConnected.bind(this),
hostDisconnected: this._hostDisconnected.bind(this),
});
}
protected _hostConnected() {
for (const propName of this._mediaProps) {
const store = this._consumer.value[propName];
if (store) {
const attrName = this._getMediaAttrName(propName);
const unsub = store.subscribe(($v) => {
this._handleValueChange(propName, attrName, $v);
});
this._disposal.add(unsub);
}
}
}
protected _hostDisconnected() {
for (const propName of this._mediaProps) {
this._handleDisconnect(propName, this._getMediaAttrName(propName));
}
this._disposal.empty();
}
protected _getMediaAttrName(propName: string) {
// Replacing `media` because we don't want stuff like `media-media-type`.
return `media-${camelToKebabCase(propName.replace('media', ''))}`;
}
protected abstract _handleValueChange(propName: string, attrName: string, value: unknown);
protected abstract _handleDisconnect(propName: string, attrName: string);
}