mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(store): skin store setup (#298)
This commit is contained in:
+36
-122
@@ -36,7 +36,8 @@ Implement React and DOM bindings for Video.js 10's store, enabling:
|
||||
| Primitives context | `useStoreContext()` internal hook for primitive UI components |
|
||||
| displayName | For React DevTools component naming |
|
||||
| Component types | Namespace pattern: `Skin.Props` via `namespace Skin { export type Props }` |
|
||||
| Element define | `FrostedSkinElement.define(tagName, { mixins })` for declarative setup |
|
||||
| Element define | `FrostedSkinElement.define(tagName?, mixin?)` - pass mixin directly |
|
||||
| Slot handling | Default slot (`<slot></slot>`) - no `slot="media"` attribute needed |
|
||||
| Config extension | `extendConfig()` uses `uniqBy` + `composeCallbacks` from utils |
|
||||
| Provider resolution | Isolated by default; `inherit` prop to use parent store from context |
|
||||
| Store instance | `create()` method for imperative store creation |
|
||||
@@ -232,108 +233,18 @@ export { extendConfig, Provider } from './store';
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Frosted Skin (HTML)
|
||||
## Phase 6: Frosted Skin [DONE]
|
||||
|
||||
### 6.1 Store config
|
||||
> Refer to [PR #298](https://github.com/videojs/v10/pull/298) for implementation details.
|
||||
|
||||
**File:** `packages/html/src/skins/frosted/store.ts`
|
||||
React and HTML frosted skin store setup:
|
||||
|
||||
```typescript
|
||||
import type { AnySlice, StoreConfig } from '@videojs/store';
|
||||
- React: `Provider`, `Skin`, `extendConfig`, `createStore` in `@videojs/react/skins/frosted`
|
||||
- HTML: `FrostedSkinElement`, `StoreMixin`, `extendConfig` in `@videojs/html/skins/frosted`
|
||||
- Auto-define entry: `@videojs/html/define/vjs-frosted-skin` for CDN usage
|
||||
- `StoreAttachMixin` uses default slot (no `slot="media"` attribute needed)
|
||||
|
||||
import { extendConfig as extendBaseConfig } from '@videojs/store';
|
||||
import { createStore } from '@videojs/store/lit';
|
||||
|
||||
import { media } from './slices'; // internal - re-exported from @videojs/html
|
||||
|
||||
/** Base config for frosted skin. */
|
||||
const baseConfig = {
|
||||
slices: [media.playback] as const,
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends frosted skin config with additional slices/hooks.
|
||||
* Composes lifecycle hooks (both called, base first).
|
||||
*/
|
||||
export function extendConfig<S extends readonly AnySlice[] = readonly []>(extension?: Partial<StoreConfig<any, S>>) {
|
||||
return extendBaseConfig(baseConfig, extension);
|
||||
}
|
||||
|
||||
export const { StoreMixin, StoreProviderMixin, StoreAttachMixin, context } = createStore(extendConfig());
|
||||
```
|
||||
|
||||
### 6.2 Skin component
|
||||
|
||||
**File:** `packages/html/src/skins/frosted/skin.ts`
|
||||
|
||||
```typescript
|
||||
import { StoreAttachMixin, StoreMixin, StoreProviderMixin } from './store';
|
||||
|
||||
type Mixin = <T extends Constructor<HTMLElement>>(Base: T) => T;
|
||||
|
||||
export interface DefineOptions {
|
||||
/** Mixins to apply. Defaults to [StoreMixin] (combined provider + attach). */
|
||||
mixins?: Mixin[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Frosted skin element. Empty for now - controls will be added later.
|
||||
* Uses shadow DOM with slot for video element.
|
||||
*/
|
||||
export class FrostedSkinElement extends HTMLElement {
|
||||
/** Default tag name for this element. */
|
||||
static tagName = 'vjs-frosted-skin';
|
||||
|
||||
/**
|
||||
* Define this element with the custom elements registry.
|
||||
*
|
||||
* @example
|
||||
* // Default: combined provider + attach
|
||||
* FrostedSkinElement.define('vjs-frosted-skin');
|
||||
*
|
||||
* @example
|
||||
* // Granular mixin control (e.g., attach only, inherit provider from parent)
|
||||
* FrostedSkinElement.define('vjs-thumbnail', { mixins: [StoreAttachMixin] });
|
||||
*
|
||||
* @example
|
||||
* // Custom store with extended slices
|
||||
* const { StoreMixin } = createStore(extendConfig({ slices: [chaptersSlice] }));
|
||||
* FrostedSkinElement.define('my-extended-player', { mixins: [StoreMixin] });
|
||||
*/
|
||||
static define(tagName: string, options: DefineOptions = {}) {
|
||||
const { mixins = [StoreMixin] } = options;
|
||||
|
||||
// Apply mixins in order (right to left composition)
|
||||
const Mixed = mixins.reduceRight((Base, mixin) => mixin(Base), this as typeof FrostedSkinElement);
|
||||
customElements.define(tagName, Mixed);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const shadow = this.attachShadow({ mode: 'open' });
|
||||
shadow.innerHTML = `<slot></slot>`;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 Define export
|
||||
|
||||
**File:** `packages/html/src/define/vjs-frosted-skin.ts`
|
||||
|
||||
```typescript
|
||||
import { FrostedSkinElement } from '../skins/frosted/skin';
|
||||
|
||||
FrostedSkinElement.define('vjs-frosted-skin');
|
||||
```
|
||||
|
||||
### 6.4 Exports
|
||||
|
||||
**File:** `packages/html/src/skins/frosted/index.ts`
|
||||
|
||||
```typescript
|
||||
export { FrostedSkinElement } from './skin';
|
||||
export type { DefineOptions } from './skin';
|
||||
export { context, extendConfig, StoreAttachMixin, StoreMixin, StoreProviderMixin } from './store';
|
||||
```
|
||||
**Note:** Don't export `context` from skins (causes unique symbol type issues). Users can import from `@videojs/store/lit` if needed.
|
||||
|
||||
---
|
||||
|
||||
@@ -501,17 +412,20 @@ function ChaptersPanel() {
|
||||
Where `my-player.js` contains:
|
||||
|
||||
```typescript
|
||||
import { createStore, media } from '@videojs/html';
|
||||
import { ReactiveElement } from '@lit/reactive-element';
|
||||
import { media } from '@videojs/core/dom';
|
||||
import { createStore } from '@videojs/store/lit';
|
||||
|
||||
const { StoreMixin } = createStore({
|
||||
slices: [media.playback],
|
||||
slices: [...media.all],
|
||||
});
|
||||
|
||||
// Create custom element with store provider and auto-attach
|
||||
class MyPlayer extends StoreMixin(HTMLElement) {
|
||||
connectedCallback() {
|
||||
class MyPlayer extends StoreMixin(ReactiveElement) {
|
||||
constructor() {
|
||||
super();
|
||||
const shadow = this.attachShadow({ mode: 'open' });
|
||||
shadow.innerHTML = `<slot></slot>`;
|
||||
shadow.innerHTML = '<slot></slot>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +453,7 @@ import { chaptersSlice } from './slices/chapters.js';
|
||||
// Extend frosted config with custom slice (merges with base slices)
|
||||
const { StoreMixin } = createStore(extendConfig({ slices: [chaptersSlice] }));
|
||||
|
||||
FrostedSkinElement.define('my-extended-skin', { mixins: [StoreMixin] });
|
||||
FrostedSkinElement.define('my-extended-skin', StoreMixin);
|
||||
```
|
||||
|
||||
---
|
||||
@@ -683,9 +597,9 @@ packages/html/src/
|
||||
- Shared types: `OptimisticResult` discriminated union in `src/shared/types.ts` ✓
|
||||
- Tests: 13 new tests for React hook ✓
|
||||
|
||||
8. **Phase 6**: Skins
|
||||
- React skin (Provider, Skin, extendConfig)
|
||||
- HTML skin (FrostedSkinElement, extendConfig)
|
||||
8. **Phase 6**: Skins **[DONE - PR #298]**
|
||||
- React skin (Provider, Skin, extendConfig) ✓
|
||||
- HTML skin (FrostedSkinElement, extendConfig) ✓
|
||||
|
||||
Each phase includes tests.
|
||||
|
||||
@@ -814,15 +728,15 @@ Use `types` + `default` format to match existing packages.
|
||||
|
||||
### Related Issues
|
||||
|
||||
| Issue | Title | Description | Status |
|
||||
| ----- | ------------------- | --------------------------------------- | ------ |
|
||||
| #218 | Store | Parent tracking issue | Open |
|
||||
| #285 | Queue Task Refactor | Unified tasks map, status discriminator | Closed |
|
||||
| #228 | Optimistic Updates | useMutation, useOptimistic | Open |
|
||||
| #229 | React Bindings | createStore, hooks, context | Closed |
|
||||
| #230 | Lit Bindings | Controllers, mixins, context | Closed |
|
||||
| #239 | DOM Media Slices | media slices | Closed |
|
||||
| #231 | Skin Stores | Skin store configuration | Open |
|
||||
| Issue | Title | Description | Status |
|
||||
| ----- | ------------------- | --------------------------------------- | ---------------- |
|
||||
| #218 | Store | Parent tracking issue | Open |
|
||||
| #285 | Queue Task Refactor | Unified tasks map, status discriminator | Closed |
|
||||
| #228 | Optimistic Updates | useMutation, useOptimistic | Open |
|
||||
| #229 | React Bindings | createStore, hooks, context | Closed |
|
||||
| #230 | Lit Bindings | Controllers, mixins, context | Closed |
|
||||
| #239 | DOM Media Slices | media slices | Closed |
|
||||
| #231 | Skin Stores | Skin store configuration | Closed (PR #298) |
|
||||
|
||||
### PR Strategy
|
||||
|
||||
@@ -875,9 +789,9 @@ PR #291: Optimistic Hooks/Controllers [DONE]
|
||||
├── Tests: 13 new tests for React hook ✓
|
||||
└── Closes #228
|
||||
|
||||
PR F: Skins
|
||||
├── React skin (Provider, Skin, extendConfig)
|
||||
├── HTML skin (FrostedSkinElement, extendConfig)
|
||||
PR #298: Skins [DONE]
|
||||
├── React skin (Provider, Skin, extendConfig) ✓
|
||||
├── HTML skin (FrostedSkinElement, extendConfig) ✓
|
||||
├── References #218
|
||||
└── Closes #231
|
||||
```
|
||||
@@ -885,12 +799,12 @@ PR F: Skins
|
||||
### Dependency Graph
|
||||
|
||||
```
|
||||
PR #283 ───> PR #287 ───> PR #288 ───> PR #290 ───> PR #291 ───> PR F (Skins)
|
||||
PR #283 ───> PR #287 ───> PR #288 ───> PR #290 ───> PR #291 ───> PR #298 (Skins)
|
||||
└──> PR #289 (done) ────────────────────────┘
|
||||
└──> PR #292 (done) ────────────────────────┘
|
||||
```
|
||||
|
||||
PRs are sequential. PR #288, #289, #292 can technically parallel after PR #287, but we'll do them sequentially for easier review.
|
||||
All PRs merged. Store bindings implementation complete.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./skins/frosted": {
|
||||
"types": "./dist/skins/frosted.d.ts",
|
||||
"default": "./dist/skins/frosted.js"
|
||||
},
|
||||
"./define/vjs-frosted-skin": {
|
||||
"types": "./dist/define/vjs-frosted-skin.d.ts",
|
||||
"default": "./dist/define/vjs-frosted-skin.js"
|
||||
}
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
@@ -32,6 +40,7 @@
|
||||
"clean": "rm -rf dist types"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lit/reactive-element": "^2.1.2",
|
||||
"@videojs/core": "workspace:*",
|
||||
"@videojs/store": "workspace:*",
|
||||
"@videojs/utils": "workspace:*"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { FrostedSkinElement } from '../skins/frosted';
|
||||
|
||||
FrostedSkinElement.define();
|
||||
@@ -0,0 +1,12 @@
|
||||
export { FrostedSkinElement } from './skin';
|
||||
|
||||
export {
|
||||
create as createStore,
|
||||
extendConfig,
|
||||
RequestController,
|
||||
SelectorController,
|
||||
StoreAttachMixin,
|
||||
StoreMixin,
|
||||
StoreProviderMixin,
|
||||
TasksController,
|
||||
} from './store';
|
||||
@@ -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>';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -6,13 +6,9 @@ import { defineConfig } from 'tsdown';
|
||||
export default defineConfig({
|
||||
entry: {
|
||||
index: 'src/index.ts',
|
||||
// 'skins/frosted': 'src/skins/frosted/index.ts',
|
||||
'skins/frosted': 'src/skins/frosted/index.ts',
|
||||
// 'skins/minimal': 'src/skins/minimal/index.ts',
|
||||
// ...defineFiles.reduce((entries, file) => {
|
||||
// const name = file.replace(/\.ts$/, '');
|
||||
// entries[`define/${name}`] = `src/define/${file}`;
|
||||
// return entries;
|
||||
// }, {} as Record<string, string>),
|
||||
'define/vjs-frosted-skin': 'src/define/vjs-frosted-skin.ts',
|
||||
},
|
||||
platform: 'browser',
|
||||
format: 'es',
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./skins/frosted": {
|
||||
"types": "./dist/skins/frosted.d.ts",
|
||||
"default": "./dist/skins/frosted.js"
|
||||
}
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -3,5 +3,8 @@
|
||||
// Media
|
||||
export { Video, type VideoProps } from './media/video';
|
||||
|
||||
// Slices (re-export for convenience)
|
||||
export { media } from '@videojs/core/dom';
|
||||
|
||||
// Store
|
||||
export * from '@videojs/store/react';
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
'use client';
|
||||
|
||||
export { Skin, type SkinProps } from './skin';
|
||||
|
||||
export {
|
||||
create as createStore,
|
||||
extendConfig,
|
||||
Provider,
|
||||
useRequest,
|
||||
useSelector,
|
||||
useStore,
|
||||
useTasks,
|
||||
} from './store';
|
||||
@@ -0,0 +1,33 @@
|
||||
'use client';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export interface SkinProps {
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example
|
||||
* ```tsx
|
||||
* import { Video } from '@videojs/react';
|
||||
* import { Provider, Skin } from '@videojs/react/skins/frosted';
|
||||
*
|
||||
* function App() {
|
||||
* return (
|
||||
* <Provider>
|
||||
* <Skin>
|
||||
* <Video src="video.mp4" />
|
||||
* </Skin>
|
||||
* </Provider>
|
||||
* );
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function Skin({ children, className }: SkinProps): React.JSX.Element {
|
||||
return <div className={`vjs-frosted-skin ${className ?? ''}`.trim()}>{children}</div>;
|
||||
}
|
||||
|
||||
export namespace Skin {
|
||||
export type Props = SkinProps;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
'use client';
|
||||
|
||||
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/react';
|
||||
|
||||
const baseConfig = {
|
||||
slices: [...media.all],
|
||||
displayName: 'FrostedSkin',
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends frosted skin config.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { createStore } from '@videojs/store/react';
|
||||
* import { extendConfig } from '@videojs/react/skins/frosted';
|
||||
* import { chaptersSlice } from './slices/chapters';
|
||||
*
|
||||
* const { Provider, useSelector } = createStore(
|
||||
* extendConfig({ slices: [chaptersSlice] })
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export function extendConfig<S extends AnySlice<HTMLMediaElement>[] = []>(
|
||||
extension?: Partial<StoreConfig<HTMLMediaElement, S>>,
|
||||
) {
|
||||
return extendBaseConfig(baseConfig, extension);
|
||||
}
|
||||
|
||||
export const {
|
||||
Provider,
|
||||
create,
|
||||
useStore,
|
||||
useSelector,
|
||||
useRequest,
|
||||
useTasks,
|
||||
} = createStore(baseConfig);
|
||||
@@ -3,8 +3,7 @@ import { defineConfig } from 'tsdown';
|
||||
export default defineConfig({
|
||||
entry: {
|
||||
index: './src/index.ts',
|
||||
// 'skins/frosted': './src/skins/frosted/index.ts',
|
||||
// 'skins/minimal': './src/skins/minimal/index.ts',
|
||||
'skins/frosted': './src/skins/frosted/index.ts',
|
||||
},
|
||||
platform: 'browser',
|
||||
format: 'es',
|
||||
|
||||
@@ -208,7 +208,6 @@ export function createStore<Slices extends AnySlice[]>(config: CreateStoreConfig
|
||||
const StoreAttachMixin = createStoreAttachMixin<Slices>(context);
|
||||
const StoreMixin = createStoreMixin<Slices>(context, create);
|
||||
|
||||
// Bound controllers - context is pre-bound
|
||||
class SelectorController<Value> extends SelectorControllerBase<ProvidedStore, Value> {
|
||||
constructor(host: CreateStoreHost, selector: (state: State) => Value) {
|
||||
super(host, context, selector);
|
||||
|
||||
@@ -14,7 +14,7 @@ import { isNull } from '@videojs/utils/predicate';
|
||||
* Creates a mixin that consumes a store from context and auto-attaches media elements.
|
||||
*
|
||||
* - Requests store from context (must have a provider ancestor)
|
||||
* - Observes slotted elements for `<video slot="media">` or `<audio slot="media">`
|
||||
* - Observes slotted elements for `<video>` or `<audio>` in the default slot
|
||||
* - Falls back to light DOM children if no shadow root
|
||||
* - Calls `store.attach(mediaElement)` when found
|
||||
* - Cleans up on disconnect
|
||||
@@ -51,7 +51,7 @@ export function createStoreAttachMixin<Slices extends AnySlice[]>(
|
||||
|
||||
const shadow = this.shadowRoot;
|
||||
if (shadow) {
|
||||
const slot = querySlot(shadow, 'media');
|
||||
const slot = querySlot(shadow, '');
|
||||
if (slot) this.#disposer.add(listen(slot, 'slotchange', () => this.#attachMedia()));
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ export function createStoreAttachMixin<Slices extends AnySlice[]>(
|
||||
isHTMLMediaElement(el) ? el : el.querySelector('video, audio');
|
||||
|
||||
const media = this.shadowRoot
|
||||
? getSlottedElement(this.shadowRoot, 'media', findMedia)
|
||||
? getSlottedElement(this.shadowRoot, '', findMedia)
|
||||
: this.querySelector('video, audio');
|
||||
|
||||
if (store.target !== media) {
|
||||
|
||||
@@ -4,10 +4,10 @@ import { createLitTestStore, setupDomCleanup, TestBaseElement, uniqueTag } from
|
||||
|
||||
setupDomCleanup();
|
||||
|
||||
// Helper to create shadow root with named media slot
|
||||
function createShadowWithSlot(el: HTMLElement): void {
|
||||
function createShadowWithSlot(el: HTMLElement): ShadowRoot {
|
||||
const shadow = el.attachShadow({ mode: 'open' });
|
||||
shadow.innerHTML = '<slot name="media"></slot>';
|
||||
shadow.innerHTML = '<slot></slot>';
|
||||
return shadow;
|
||||
}
|
||||
|
||||
describe('createStoreMixin', () => {
|
||||
@@ -17,8 +17,7 @@ describe('createStoreMixin', () => {
|
||||
|
||||
class TestElement extends StoreMixin(TestBaseElement) {
|
||||
override createRenderRoot() {
|
||||
createShadowWithSlot(this);
|
||||
return this.shadowRoot!;
|
||||
return createShadowWithSlot(this);
|
||||
}
|
||||
}
|
||||
customElements.define(tagName, TestElement);
|
||||
@@ -37,15 +36,13 @@ describe('createStoreMixin', () => {
|
||||
|
||||
class TestElement extends StoreMixin(TestBaseElement) {
|
||||
override createRenderRoot() {
|
||||
createShadowWithSlot(this);
|
||||
return this.shadowRoot!;
|
||||
return createShadowWithSlot(this);
|
||||
}
|
||||
}
|
||||
customElements.define(tagName, TestElement);
|
||||
|
||||
const el = document.createElement(tagName) as TestElement;
|
||||
const video = document.createElement('video');
|
||||
video.slot = 'media';
|
||||
el.appendChild(video);
|
||||
document.body.appendChild(el);
|
||||
await el.updateComplete;
|
||||
@@ -85,15 +82,13 @@ describe('createStoreMixin', () => {
|
||||
|
||||
class TestElement extends StoreMixin(TestBaseElement) {
|
||||
override createRenderRoot() {
|
||||
createShadowWithSlot(this);
|
||||
return this.shadowRoot!;
|
||||
return createShadowWithSlot(this);
|
||||
}
|
||||
}
|
||||
customElements.define(tagName, TestElement);
|
||||
|
||||
const el = document.createElement(tagName) as TestElement;
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.slot = 'media';
|
||||
const video = document.createElement('video');
|
||||
wrapper.appendChild(video);
|
||||
el.appendChild(wrapper);
|
||||
@@ -112,15 +107,13 @@ describe('createStoreMixin', () => {
|
||||
|
||||
class TestElement extends StoreMixin(TestBaseElement) {
|
||||
override createRenderRoot() {
|
||||
createShadowWithSlot(this);
|
||||
return this.shadowRoot!;
|
||||
return createShadowWithSlot(this);
|
||||
}
|
||||
}
|
||||
customElements.define(tagName, TestElement);
|
||||
|
||||
const el = document.createElement(tagName) as TestElement;
|
||||
const audio = document.createElement('audio');
|
||||
audio.slot = 'media';
|
||||
el.appendChild(audio);
|
||||
document.body.appendChild(el);
|
||||
await el.updateComplete;
|
||||
@@ -137,17 +130,14 @@ describe('createStoreMixin', () => {
|
||||
|
||||
class TestElement extends StoreMixin(TestBaseElement) {
|
||||
override createRenderRoot() {
|
||||
createShadowWithSlot(this);
|
||||
return this.shadowRoot!;
|
||||
return createShadowWithSlot(this);
|
||||
}
|
||||
}
|
||||
customElements.define(tagName, TestElement);
|
||||
|
||||
const el = document.createElement(tagName) as TestElement;
|
||||
const video1 = document.createElement('video');
|
||||
video1.slot = 'media';
|
||||
const video2 = document.createElement('video');
|
||||
video2.slot = 'media';
|
||||
el.appendChild(video1);
|
||||
el.appendChild(video2);
|
||||
document.body.appendChild(el);
|
||||
|
||||
Generated
+7
-4
@@ -330,6 +330,9 @@ importers:
|
||||
|
||||
packages/html:
|
||||
dependencies:
|
||||
'@lit/reactive-element':
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2
|
||||
'@videojs/core':
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
@@ -8947,7 +8950,7 @@ snapshots:
|
||||
sirv: 3.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.3)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.3)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)
|
||||
|
||||
'@vitest/utils@3.2.4':
|
||||
dependencies:
|
||||
@@ -10016,7 +10019,7 @@ snapshots:
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1))
|
||||
@@ -10058,7 +10061,7 @@ snapshots:
|
||||
tinyglobby: 0.2.15
|
||||
unrs-resolver: 1.11.1
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -10134,7 +10137,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)):
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.9
|
||||
|
||||
Reference in New Issue
Block a user