feat(store): skin store setup (#298)

This commit is contained in:
rahim
2026-01-07 15:45:46 +11:00
committed by GitHub
parent 836c32952c
commit b2e2b88e19
17 changed files with 273 additions and 156 deletions
@@ -0,0 +1,3 @@
import { FrostedSkinElement } from '../skins/frosted';
FrostedSkinElement.define();
+12
View File
@@ -0,0 +1,12 @@
export { FrostedSkinElement } from './skin';
export {
create as createStore,
extendConfig,
RequestController,
SelectorController,
StoreAttachMixin,
StoreMixin,
StoreProviderMixin,
TasksController,
} from './store';
+57
View File
@@ -0,0 +1,57 @@
import type { Mixin } from '@videojs/utils/types';
import { ReactiveElement } from '@lit/reactive-element';
import { StoreMixin } from './store';
/**
* Frosted skin custom element.
*
* Uses shadow DOM with a slot for video elements. Controls will be added in future updates.
*
* @example Basic usage (after calling define)
* ```html
* <vjs-frosted-skin>
* <video src="video.mp4"></video>
* </vjs-frosted-skin>
* ```
*
* @example Define with default tag
* ```ts
* import { FrostedSkinElement } from '@videojs/html/skins/frosted';
* FrostedSkinElement.define();
* ```
*
* @example Define with custom tag
* ```ts
* FrostedSkinElement.define('my-player');
* ```
*
* @example Define with extended store
* ```ts
* import { createStore } from '@videojs/store/lit';
* import { extendConfig, FrostedSkinElement } from '@videojs/html/skins/frosted';
*
* const { StoreMixin } = createStore(extendConfig({ slices: [chaptersSlice] }));
* FrostedSkinElement.define('my-player', StoreMixin);
* ```
*/
export class FrostedSkinElement extends ReactiveElement {
static tagName = 'vjs-frosted-skin';
/**
* Registers this element with the custom elements registry.
*
* @param tagName - Custom element tag name (defaults to 'vjs-frosted-skin')
* @param mixin - Mixin to apply (defaults to StoreMixin)
*/
static define(tagName = this.tagName, mixin: Mixin<FrostedSkinElement, ReactiveElement> = StoreMixin): void {
customElements.define(tagName, mixin(this));
}
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = '<slot></slot>';
}
}
+41
View File
@@ -0,0 +1,41 @@
import type { AnySlice, StoreConfig } from '@videojs/store';
import { media } from '@videojs/core/dom';
import { extendConfig as extendBaseConfig } from '@videojs/store';
import { createStore } from '@videojs/store/lit';
const baseConfig = {
slices: [...media.all],
};
/**
* Extends frosted skin config.
*
* @example
* ```ts
* import { createStore } from '@videojs/store/lit';
* import { extendConfig, FrostedSkinElement } from '@videojs/html/skins/frosted';
* import { chaptersSlice } from './slices/chapters';
*
* const { StoreMixin } = createStore(
* extendConfig({ slices: [chaptersSlice] })
* );
*
* FrostedSkinElement.define('my-player', El => StoreMixin(El));
* ```
*/
export function extendConfig<Slices extends AnySlice<HTMLMediaElement>[] = []>(
extension?: Partial<StoreConfig<HTMLMediaElement, Slices>>,
) {
return extendBaseConfig(baseConfig, extension);
}
export const {
StoreMixin,
StoreProviderMixin,
StoreAttachMixin,
SelectorController,
RequestController,
TasksController,
create,
} = createStore(baseConfig);