diff --git a/.claude/skills/README.md b/.claude/skills/README.md index 6c70db6f..807771a2 100644 --- a/.claude/skills/README.md +++ b/.claude/skills/README.md @@ -6,7 +6,7 @@ Specialized knowledge for AI agents working on Video.js 10. | Workflow | Load | | -------------------------- | ---------------------------------- | -| Building store/slices | `api` | +| Building store/features | `api` | | Building Lit components | `component` + `aria` | | Building React components | `component` + `aria` | | Writing documentation | `docs` | diff --git a/.claude/skills/api/references/anti-patterns.md b/.claude/skills/api/references/anti-patterns.md index 0dfa3bf9..3eca1efe 100644 --- a/.claude/skills/api/references/anti-patterns.md +++ b/.claude/skills/api/references/anti-patterns.md @@ -172,15 +172,15 @@ const dataAtom = atom(async () => fetch(...)); ```ts // Poor: Unexpected interactions -const volumeSlice = createSlice({ +const volumeFeature = createFeature({ middleware: [logger], // Don't do this }); // Good: Middleware at store level create( logger((...a) => ({ - ...volumeSlice(...a), - ...playbackSlice(...a), + ...volumeFeature(...a), + ...playbackFeature(...a), })) ); ``` diff --git a/.claude/skills/api/references/typescript.md b/.claude/skills/api/references/typescript.md index 305704cc..ef53df01 100644 --- a/.claude/skills/api/references/typescript.md +++ b/.claude/skills/api/references/typescript.md @@ -40,7 +40,7 @@ Capture target/platform type once, let callbacks infer: ```ts // Capture Target type once -const slice = createSlice()({ +const feature = createFeature()({ initialState: { volume: 1 }, getSnapshot: ({ target }) => ({ volume: target.volume }), subscribe: ({ target, update }) => { diff --git a/.claude/skills/api/review/example.md b/.claude/skills/api/review/example.md index 4d9e4a4e..b02af483 100644 --- a/.claude/skills/api/review/example.md +++ b/.claude/skills/api/review/example.md @@ -59,7 +59,7 @@ createPlayer({ src: 'video.mp4', autoplay: true, controls: defaultControls, - slices: [analyticsSlice], + features: [analyticsFeature], }); ``` @@ -82,7 +82,7 @@ player.registerPlugin(keyboard); // Order matters but isn't visible // After const player = createPlayer({ ...config, - slices: [analyticsSlice, keyboardSlice], // Types know exactly what's included + features: [analyticsFeature, keyboardFeature], // Types know exactly what's included }); ``` @@ -166,7 +166,7 @@ interface Player { | -------------------- | ------------------------ | ------------- | --------------------------- | | `autoplay: boolean` | Boolean params confusing | principles.md | Named in config object | | `controls: Config` | Generic name | principles.md | Consider `ui` or `skin` | -| `plugins?: Plugin[]` | Plugin vs Slice naming | state.md | Use "slice" if that's model | +| `plugins?: Plugin[]` | Plugin vs Feature naming | state.md | Use "feature" if that's model | --- @@ -184,7 +184,7 @@ This API has structural problems that will cause long-term pain. The two critica **Positional parameters** make the API hard to use and impossible to extend without breaking changes. Converting to a config object is straightforward and enables future options. -**Runtime plugin registration** loses the type safety and tree-shaking benefits that modern libraries expect. Moving to creation-time composition (like Zustand slices) enables TypeScript to track capabilities and bundlers to eliminate unused code. +**Runtime plugin registration** loses the type safety and tree-shaking benefits that modern libraries expect. Moving to creation-time composition (like Zustand features) enables TypeScript to track capabilities and bundlers to eliminate unused code. The event system's lack of typing is a significant DX issue but not blocking. Consider typed event maps or a subscription pattern like `subscribe(selector, callback)`. @@ -273,7 +273,7 @@ The function signature is the main problem. Converting to a config object would #### [MAJOR] No composition model -Plugins are black boxes. No slice pattern, no middleware composition, no builder chain. +Plugins are black boxes. No feature pattern, no middleware composition, no builder chain. ### Good Patterns @@ -281,7 +281,7 @@ Plugins are black boxes. No slice pattern, no middleware composition, no builder ### Summary -The extensibility model needs a rethink. Look at Zustand slices or tRPC procedures for inspiration—extension through composition at creation time. +The extensibility model needs a rethink. Look at Zustand features or tRPC procedures for inspiration—extension through composition at creation time. diff --git a/.claude/skills/api/review/templates.md b/.claude/skills/api/review/templates.md index 96c2db86..1a66a6cd 100644 --- a/.claude/skills/api/review/templates.md +++ b/.claude/skills/api/review/templates.md @@ -87,7 +87,7 @@ player.registerPlugin(analytics) // After const player = createPlayer({ ...config, -slices: [analyticsSlice], +features: [analyticsFeature], }) ``` diff --git a/.claude/skills/component/references/lit.md b/.claude/skills/component/references/lit.md index 11a07741..fe979dcf 100644 --- a/.claude/skills/component/references/lit.md +++ b/.claude/skills/component/references/lit.md @@ -109,7 +109,7 @@ Mixins are for **store provision only**, not behavior. Behavior goes in controll Creates a mixin that provides a store via context: ```ts -const { StoreProviderMixin } = createStore({ slices: [playbackSlice] }); +const { StoreProviderMixin } = createStore({ features: [playbackFeature] }); class MyPlayer extends StoreProviderMixin(ReactiveElement) { // Store provided to all descendants diff --git a/.claude/skills/docs/SKILL.md b/.claude/skills/docs/SKILL.md index 63360ec6..82814c50 100644 --- a/.claude/skills/docs/SKILL.md +++ b/.claude/skills/docs/SKILL.md @@ -236,18 +236,18 @@ See `templates/component-page.md` for full template. When documenting, understand the package hierarchy: -| Package | Subpaths | Purpose | Doc Focus | -| ----------------------- | ------------------------------- | ------------------------------------- | -------------------------------- | -| `@videojs/utils` | `/dom`, `/predicate`, `/events` | Shared utilities | Utility reference | -| `@videojs/store` | `/lit`, `/react` | State management | Slices, requests, error handling | -| `@videojs/core` | `/dom` | Runtime-agnostic logic + media slices | API reference, concepts | -| `@videojs/html` | `/skins/frosted` | Web Components (Lit) | Component docs, styling | -| `@videojs/react` | — | React adapter | Components, hooks | -| `@videojs/react-native` | — | React Native adapter | Mobile-specific guides | +| Package | Subpaths | Purpose | Doc Focus | +| ----------------------- | ------------------------------- | --------------------------------------- | ---------------------------------- | +| `@videojs/utils` | `/dom`, `/predicate`, `/events` | Shared utilities | Utility reference | +| `@videojs/store` | `/lit`, `/react` | State management | Features, requests, error handling | +| `@videojs/core` | `/dom` | Runtime-agnostic logic + media features | API reference, concepts | +| `@videojs/html` | `/skins/frosted` | Web Components (Lit) | Component docs, styling | +| `@videojs/react` | — | React adapter | Components, hooks | +| `@videojs/react-native` | — | React Native adapter | Mobile-specific guides | **Dependency flow:** `utils → store → core → html / react / react-native` -Document `@videojs/store` as state primitives (slices, requests, guards). +Document `@videojs/store` as state primitives (features, requests, guards). Document `@videojs/html` as Web Components with controllers and mixins. Document framework adapters with framework-native idioms. diff --git a/.claude/skills/docs/patterns/error-docs.md b/.claude/skills/docs/patterns/error-docs.md index c58c420d..42c960da 100644 --- a/.claude/skills/docs/patterns/error-docs.md +++ b/.claude/skills/docs/patterns/error-docs.md @@ -44,7 +44,7 @@ Document which errors are "normal" vs programming errors: ```ts const store = createStore({ - slices: [playbackSlice, volumeSlice], + features: [playbackFeature, volumeFeature], onError: ({ error, request }) => { if (request) { console.error(`${request.name} failed:`, error.code); @@ -120,11 +120,11 @@ function handleError(error: unknown) { ```ts // ❌ Wrong -const store = createStore({ slices: [playbackSlice] }); +const store = createStore({ features: [playbackFeature] }); await store.request.play(); // Error: NO_TARGET // ✅ Correct -const store = createStore({ slices: [playbackSlice] }); +const store = createStore({ features: [playbackFeature] }); store.attach(videoElement); await store.request.play(); ``` diff --git a/.claude/skills/docs/references/state-tooling.md b/.claude/skills/docs/references/state-tooling.md index 049f6b2b..139ae896 100644 --- a/.claude/skills/docs/references/state-tooling.md +++ b/.claude/skills/docs/references/state-tooling.md @@ -44,7 +44,7 @@ That's it. No providers, no boilerplate. **Applicable to Video.js:** - `createPlayerWith*` naming for factory functions -- `sliceWith*` for slice factories +- `featureWith*` for feature factories ### XState Pattern: Visual State Machines diff --git a/.claude/skills/docs/templates/api-reference.md b/.claude/skills/docs/templates/api-reference.md index 64b0d19d..3187e534 100644 --- a/.claude/skills/docs/templates/api-reference.md +++ b/.claude/skills/docs/templates/api-reference.md @@ -307,20 +307,20 @@ console.log(input.prop1, input.prop2); --- -## Slice Template +## Feature Template -For `@videojs/store` slices: +For `@videojs/store` features: ```markdown -## sliceName +## featureName -Brief description of what state this slice manages. +Brief description of what state this feature manages. -import { sliceName } from '@videojs/core/dom'; +import { featureName } from '@videojs/core/dom'; // or -import { createSlice } from '@videojs/store'; +import { createFeature } from '@videojs/store'; -const sliceName = createSlice()({ +const featureName = createFeature()({ initialState: { property1: defaultValue, property2: defaultValue, @@ -358,14 +358,14 @@ return target.property; ### Type Inference -import type { InferSliceState, InferSliceRequests } from '@videojs/store'; +import type { InferFeatureState, InferFeatureRequests } from '@videojs/store'; -type SliceNameState = InferSliceState; -type SliceNameRequests = InferSliceRequests; +type FeatureNameState = InferFeatureState; +type FeatureNameRequests = InferFeatureRequests; ### See Also -- [Related Slice](/api/slices/related) +- [Related Feature](/api/features/related) - [Store Guide](/guides/store) ``` diff --git a/.claude/skills/docs/templates/component-page.md b/.claude/skills/docs/templates/component-page.md index 947e4f67..e8eec79f 100644 --- a/.claude/skills/docs/templates/component-page.md +++ b/.claude/skills/docs/templates/component-page.md @@ -330,7 +330,7 @@ import { createStore } from '@videojs/store/lit'; import { extendConfig } from '@videojs/html/skins/frosted'; const { StoreMixin } = createStore( -extendConfig({ slices: [customSlice] }) +extendConfig({ features: [customFeature] }) ); ElementName.define('custom-name', StoreMixin); @@ -385,10 +385,10 @@ ElementName.define('custom-name', StoreMixin); import { createStore } from '@videojs/store/lit'; import { extendConfig, FrostedSkinElement } from '@videojs/html/skins/frosted'; -import { chaptersSlice } from './slices/chapters'; +import { chaptersFeature } from './features/chapters'; const { StoreMixin } = createStore( -extendConfig({ slices: [chaptersSlice] }) +extendConfig({ features: [chaptersFeature] }) ); FrostedSkinElement.define('my-player', StoreMixin); diff --git a/.claude/skills/docs/templates/readme.md b/.claude/skills/docs/templates/readme.md index 6a71814d..4732c54f 100644 --- a/.claude/skills/docs/templates/readme.md +++ b/.claude/skills/docs/templates/readme.md @@ -152,8 +152,8 @@ Explanation. Core concepts: - Target -- Slices -- Slice Type Inference +- Features +- Feature Type Inference - Requests - Request Metadata - Store @@ -174,7 +174,7 @@ Core concepts: Core concepts: -- Media slices: volumeSlice, playbackSlice, timeSlice, sourceSlice, bufferSlice +- Media features: volumeFeature, playbackFeature, timeFeature, sourceFeature, bufferFeature - `media.all` array - Type exports (VolumeState, PlaybackRequests, etc.) @@ -185,7 +185,7 @@ Core concepts: - FrostedSkinElement - `define()` pattern - Slot-based composition -- Extending with custom slices +- Extending with custom features ### @videojs/react @@ -217,10 +217,10 @@ Always include at top: ```markdown npm install @videojs/store -import { createSlice, createStore } from '@videojs/store'; +import { createFeature, createStore } from '@videojs/store'; const store = createStore({ -slices: [playbackSlice, volumeSlice], +features: [playbackFeature, volumeFeature], }); store.attach(videoElement); @@ -243,10 +243,10 @@ Use when comparing to alternatives: Always show type inference for TypeScript users: ```ts -import type { InferSliceRequests, InferSliceState } from '@videojs/store'; +import type { InferFeatureRequests, InferFeatureState } from '@videojs/store'; -type VolumeState = InferSliceState; -type VolumeRequests = InferSliceRequests; +type VolumeState = InferFeatureState; +type VolumeRequests = InferFeatureRequests; ``` ### Links Footer diff --git a/.claude/skills/git/references/commit.md b/.claude/skills/git/references/commit.md index 2efa2b86..270d3a73 100644 --- a/.claude/skills/git/references/commit.md +++ b/.claude/skills/git/references/commit.md @@ -33,7 +33,7 @@ Use `!` suffix on type for breaking changes: ``` feat(core)!: remove deprecated API -refactor(store)!: rename slice methods +refactor(store)!: rename feature methods ``` The `!` signals breaking changes in the changelog. diff --git a/.claude/skills/git/references/pr.md b/.claude/skills/git/references/pr.md index 8b9b0635..f8165b22 100644 --- a/.claude/skills/git/references/pr.md +++ b/.claude/skills/git/references/pr.md @@ -109,5 +109,5 @@ Fix race condition where rapid play/pause could leave player in inconsistent sta ## Testing -Covered by new test in `media-slice.test.ts`. Manual: rapidly click play/pause. +Covered by new test in `media-feature.test.ts`. Manual: rapidly click play/pause. ``` diff --git a/.claude/skills/git/references/scope.md b/.claude/skills/git/references/scope.md index e902f8c5..f00710bf 100644 --- a/.claude/skills/git/references/scope.md +++ b/.claude/skills/git/references/scope.md @@ -42,7 +42,7 @@ test, utils ```bash # Single package -packages/store/src/slice.ts → store +packages/store/src/feature.ts → store # Multiple files in same package packages/html/src/slider.ts diff --git a/CLAUDE.md b/CLAUDE.md index 0aeb7b9a..6a2d2f2b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -213,13 +213,13 @@ Before writing new helpers, check `@videojs/utils` for existing utilities. | Pattern | Prefix | Example | | ------------------- | -------------- | -------------------------------------- | -| Type inference | `Infer*` | `InferSliceState` | +| Type inference | `Infer*` | `InferFeatureState` | | Type resolution | `Resolve*` | `ResolveRequestHandler` | | Type constraint | `Ensure*` | `EnsureTaskRecord` | -| Union type helpers | `Union*` | `UnionSliceState` | +| Union type helpers | `Union*` | `UnionFeatureState` | | Default loose types | `Default*` | `DefaultTaskRecord` | | Type guards | `is*` | `isStoreError(error)` | -| Factory functions | `create*` | `createQueue()`, `createSlice()` | +| Factory functions | `create*` | `createQueue()`, `createFeature()` | | Falsy wrapper | `Falsy*` | `Falsy` (value that might be falsy) | | Constructor types | `*Constructor` | `Constructor`, `AnyConstructor` | | Mixin types | `Mixin` | `Mixin` | @@ -302,7 +302,7 @@ function isQueue(value: unknown): value is Queue { **`Symbol()` vs `Symbol.for()`:** - Use `Symbol.for('@videojs/*')` for symbols that need cross-realm identity (e.g., metadata that must be recognized across module boundaries) -- Use `Symbol('@videojs/*')` for instance-unique identifiers (e.g., task IDs, slice IDs) +- Use `Symbol('@videojs/*')` for instance-unique identifiers (e.g., task IDs, feature IDs) ### Subscribe Pattern @@ -389,11 +389,11 @@ Never prefix type parameters with `T`. Use descriptive names instead: ```ts // Bad type Mixin = ... -function createStore(...) { ... } +function createStore(...) { ... } // Good type Mixin = ... -function createStore(...) { ... } +function createStore(...) { ... } ``` ### React: Lazy Initialization diff --git a/packages/core/src/dom/index.ts b/packages/core/src/dom/index.ts index f2312a58..4b5227a3 100644 --- a/packages/core/src/dom/index.ts +++ b/packages/core/src/dom/index.ts @@ -1 +1 @@ -export * from './store/slices'; +export * from './store/features'; diff --git a/packages/core/src/dom/store/slices/buffer.ts b/packages/core/src/dom/store/features/buffer.ts similarity index 64% rename from packages/core/src/dom/store/slices/buffer.ts rename to packages/core/src/dom/store/features/buffer.ts index 951310f3..a50922aa 100644 --- a/packages/core/src/dom/store/slices/buffer.ts +++ b/packages/core/src/dom/store/features/buffer.ts @@ -1,14 +1,14 @@ -import type { InferSliceRequests, InferSliceState } from '@videojs/store'; +import type { InferFeatureRequests, InferFeatureState } from '@videojs/store'; -import { createSlice } from '@videojs/store'; +import { createFeature } from '@videojs/store'; import { listen, serializeTimeRanges } from '@videojs/utils/dom'; /** - * Buffer slice for HTMLMediaElement. + * Buffer feature for HTMLMediaElement. * * Tracks buffered and seekable time ranges. Read-only (no requests). */ -export const bufferSlice = createSlice()({ +export const bufferFeature = createFeature()({ initialState: { /** Buffered time ranges as [start, end] tuples. */ buffered: [] as [number, number][], @@ -29,6 +29,6 @@ export const bufferSlice = createSlice()({ request: {}, }); -export type BufferState = InferSliceState; +export type BufferState = InferFeatureState; -export type BufferRequests = InferSliceRequests; +export type BufferRequests = InferFeatureRequests; diff --git a/packages/core/src/dom/store/slices/index.ts b/packages/core/src/dom/store/features/index.ts similarity index 100% rename from packages/core/src/dom/store/slices/index.ts rename to packages/core/src/dom/store/features/index.ts diff --git a/packages/core/src/dom/store/features/media.parts.ts b/packages/core/src/dom/store/features/media.parts.ts new file mode 100644 index 00000000..25232a6c --- /dev/null +++ b/packages/core/src/dom/store/features/media.parts.ts @@ -0,0 +1,15 @@ +import { bufferFeature } from './buffer'; +import { playbackFeature } from './playback'; +import { sourceFeature } from './source'; +import { timeFeature } from './time'; +import { volumeFeature } from './volume'; + +export { + bufferFeature as buffer, + playbackFeature as playback, + sourceFeature as source, + timeFeature as time, + volumeFeature as volume, +}; + +export const all = [bufferFeature, playbackFeature, sourceFeature, timeFeature, volumeFeature] as const; diff --git a/packages/core/src/dom/store/slices/playback.ts b/packages/core/src/dom/store/features/playback.ts similarity index 75% rename from packages/core/src/dom/store/slices/playback.ts rename to packages/core/src/dom/store/features/playback.ts index d791fa2b..d3619d3c 100644 --- a/packages/core/src/dom/store/slices/playback.ts +++ b/packages/core/src/dom/store/features/playback.ts @@ -1,14 +1,14 @@ -import type { InferSliceRequests, InferSliceState } from '@videojs/store'; +import type { InferFeatureRequests, InferFeatureState } from '@videojs/store'; -import { createSlice } from '@videojs/store'; +import { createFeature } from '@videojs/store'; import { listen } from '@videojs/utils/dom'; /** - * Playback slice for HTMLMediaElement. + * Playback feature for HTMLMediaElement. * * Tracks core playback state and provides play/pause control. */ -export const playbackSlice = createSlice()({ +export const playbackFeature = createFeature()({ initialState: { /** Whether playback is paused. */ paused: true, @@ -48,6 +48,6 @@ export const playbackSlice = createSlice()({ }, }); -export type PlaybackState = InferSliceState; +export type PlaybackState = InferFeatureState; -export type PlaybackRequests = InferSliceRequests; +export type PlaybackRequests = InferFeatureRequests; diff --git a/packages/core/src/dom/store/slices/source.ts b/packages/core/src/dom/store/features/source.ts similarity index 72% rename from packages/core/src/dom/store/slices/source.ts rename to packages/core/src/dom/store/features/source.ts index 8c0e3363..a1f9fa03 100644 --- a/packages/core/src/dom/store/slices/source.ts +++ b/packages/core/src/dom/store/features/source.ts @@ -1,14 +1,14 @@ -import type { InferSliceRequests, InferSliceState } from '@videojs/store'; +import type { InferFeatureRequests, InferFeatureState } from '@videojs/store'; -import { createSlice } from '@videojs/store'; +import { createFeature } from '@videojs/store'; import { listen } from '@videojs/utils/dom'; /** - * Source slice for HTMLMediaElement. + * Source feature for HTMLMediaElement. * * Tracks current source and loading state, provides source change control. */ -export const sourceSlice = createSlice()({ +export const sourceFeature = createFeature()({ initialState: { /** Current media source URL (null if none). */ source: null as string | null, @@ -38,6 +38,6 @@ export const sourceSlice = createSlice()({ }, }); -export type SourceState = InferSliceState; +export type SourceState = InferFeatureState; -export type SourceRequests = InferSliceRequests; +export type SourceRequests = InferFeatureRequests; diff --git a/packages/core/src/dom/store/slices/tests/buffer.test.ts b/packages/core/src/dom/store/features/tests/buffer.test.ts similarity index 81% rename from packages/core/src/dom/store/slices/tests/buffer.test.ts rename to packages/core/src/dom/store/features/tests/buffer.test.ts index d4d634a6..3829357b 100644 --- a/packages/core/src/dom/store/slices/tests/buffer.test.ts +++ b/packages/core/src/dom/store/features/tests/buffer.test.ts @@ -1,22 +1,22 @@ import { describe, expect, it, vi } from 'vitest'; -import { bufferSlice } from '../buffer'; +import { bufferFeature } from '../buffer'; -describe('bufferSlice', () => { - describe('slice structure', () => { +describe('bufferFeature', () => { + describe('feature structure', () => { it('has unique id symbol', () => { - expect(bufferSlice.id).toBeTypeOf('symbol'); + expect(bufferFeature.id).toBeTypeOf('symbol'); }); it('has correct initial state', () => { - expect(bufferSlice.initialState).toEqual({ + expect(bufferFeature.initialState).toEqual({ buffered: [], seekable: [], }); }); it('has no request handlers', () => { - expect(Object.keys(bufferSlice.request)).toHaveLength(0); + expect(Object.keys(bufferFeature.request)).toHaveLength(0); }); }); @@ -27,9 +27,9 @@ describe('bufferSlice', () => { seekable: createTimeRanges([[0, 120]]), }); - const snapshot = bufferSlice.getSnapshot({ + const snapshot = bufferFeature.getSnapshot({ target: video, - initialState: bufferSlice.initialState, + initialState: bufferFeature.initialState, }); expect(snapshot).toEqual({ @@ -47,9 +47,9 @@ describe('bufferSlice', () => { seekable: createTimeRanges([[0, 120]]), }); - const snapshot = bufferSlice.getSnapshot({ + const snapshot = bufferFeature.getSnapshot({ target: video, - initialState: bufferSlice.initialState, + initialState: bufferFeature.initialState, }); expect(snapshot.buffered).toEqual([ @@ -68,7 +68,7 @@ describe('bufferSlice', () => { const update = vi.fn(); const controller = new AbortController(); - bufferSlice.subscribe({ target: video, update, signal: controller.signal }); + bufferFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('progress')); expect(update).toHaveBeenCalled(); @@ -82,7 +82,7 @@ describe('bufferSlice', () => { const update = vi.fn(); const controller = new AbortController(); - bufferSlice.subscribe({ target: video, update, signal: controller.signal }); + bufferFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('emptied')); expect(update).toHaveBeenCalled(); diff --git a/packages/core/src/dom/store/slices/tests/playback.test.ts b/packages/core/src/dom/store/features/tests/playback.test.ts similarity index 76% rename from packages/core/src/dom/store/slices/tests/playback.test.ts rename to packages/core/src/dom/store/features/tests/playback.test.ts index f74743bf..d808a10c 100644 --- a/packages/core/src/dom/store/slices/tests/playback.test.ts +++ b/packages/core/src/dom/store/features/tests/playback.test.ts @@ -1,15 +1,15 @@ import { describe, expect, it, vi } from 'vitest'; -import { playbackSlice } from '../playback'; +import { playbackFeature } from '../playback'; -describe('playbackSlice', () => { - describe('slice structure', () => { +describe('playbackFeature', () => { + describe('feature structure', () => { it('has unique id symbol', () => { - expect(playbackSlice.id).toBeTypeOf('symbol'); + expect(playbackFeature.id).toBeTypeOf('symbol'); }); it('has correct initial state', () => { - expect(playbackSlice.initialState).toEqual({ + expect(playbackFeature.initialState).toEqual({ paused: true, ended: false, started: false, @@ -18,18 +18,18 @@ describe('playbackSlice', () => { }); it('has all request handlers', () => { - expect(playbackSlice.request.play).toBeDefined(); - expect(playbackSlice.request.pause).toBeDefined(); + expect(playbackFeature.request.play).toBeDefined(); + expect(playbackFeature.request.pause).toBeDefined(); }); it('request handlers have correct structure', () => { - expect(playbackSlice.request.play).toMatchObject({ + expect(playbackFeature.request.play).toMatchObject({ key: 'play', guard: [], handler: expect.any(Function), }); - expect(playbackSlice.request.pause).toMatchObject({ + expect(playbackFeature.request.pause).toMatchObject({ key: 'pause', guard: [], handler: expect.any(Function), @@ -46,9 +46,9 @@ describe('playbackSlice', () => { readyState: HTMLMediaElement.HAVE_ENOUGH_DATA, }); - const snapshot = playbackSlice.getSnapshot({ + const snapshot = playbackFeature.getSnapshot({ target: video, - initialState: playbackSlice.initialState, + initialState: playbackFeature.initialState, }); expect(snapshot).toEqual({ @@ -65,9 +65,9 @@ describe('playbackSlice', () => { readyState: HTMLMediaElement.HAVE_CURRENT_DATA, }); - const snapshot = playbackSlice.getSnapshot({ + const snapshot = playbackFeature.getSnapshot({ target: video, - initialState: playbackSlice.initialState, + initialState: playbackFeature.initialState, }); expect(snapshot.waiting).toBe(true); @@ -79,9 +79,9 @@ describe('playbackSlice', () => { currentTime: 5, }); - const snapshot = playbackSlice.getSnapshot({ + const snapshot = playbackFeature.getSnapshot({ target: video, - initialState: playbackSlice.initialState, + initialState: playbackFeature.initialState, }); expect(snapshot.started).toBe(true); @@ -93,9 +93,9 @@ describe('playbackSlice', () => { currentTime: 0, }); - const snapshot = playbackSlice.getSnapshot({ + const snapshot = playbackFeature.getSnapshot({ target: video, - initialState: playbackSlice.initialState, + initialState: playbackFeature.initialState, }); expect(snapshot.started).toBe(true); @@ -108,7 +108,7 @@ describe('playbackSlice', () => { const update = vi.fn(); const controller = new AbortController(); - playbackSlice.subscribe({ target: video, update, signal: controller.signal }); + playbackFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('play')); expect(update).toHaveBeenCalled(); @@ -119,7 +119,7 @@ describe('playbackSlice', () => { const update = vi.fn(); const controller = new AbortController(); - playbackSlice.subscribe({ target: video, update, signal: controller.signal }); + playbackFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('pause')); expect(update).toHaveBeenCalled(); @@ -130,7 +130,7 @@ describe('playbackSlice', () => { const update = vi.fn(); const controller = new AbortController(); - playbackSlice.subscribe({ target: video, update, signal: controller.signal }); + playbackFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('ended')); expect(update).toHaveBeenCalled(); @@ -141,7 +141,7 @@ describe('playbackSlice', () => { const update = vi.fn(); const controller = new AbortController(); - playbackSlice.subscribe({ target: video, update, signal: controller.signal }); + playbackFeature.subscribe({ target: video, update, signal: controller.signal }); controller.abort(); video.dispatchEvent(new Event('play')); @@ -155,7 +155,7 @@ describe('playbackSlice', () => { const video = createMockVideo({}); video.play = vi.fn().mockResolvedValue(undefined); - await playbackSlice.request.play.handler(undefined, { + await playbackFeature.request.play.handler(undefined, { target: video, signal: new AbortController().signal, meta: null, @@ -170,7 +170,7 @@ describe('playbackSlice', () => { const video = createMockVideo({}); video.pause = vi.fn(); - playbackSlice.request.pause.handler(undefined, { + playbackFeature.request.pause.handler(undefined, { target: video, signal: new AbortController().signal, meta: null, diff --git a/packages/core/src/dom/store/slices/tests/source.test.ts b/packages/core/src/dom/store/features/tests/source.test.ts similarity index 78% rename from packages/core/src/dom/store/slices/tests/source.test.ts rename to packages/core/src/dom/store/features/tests/source.test.ts index db4b6f6a..8d1f2d9b 100644 --- a/packages/core/src/dom/store/slices/tests/source.test.ts +++ b/packages/core/src/dom/store/features/tests/source.test.ts @@ -1,23 +1,23 @@ import { describe, expect, it, vi } from 'vitest'; -import { sourceSlice } from '../source'; +import { sourceFeature } from '../source'; -describe('sourceSlice', () => { - describe('slice structure', () => { +describe('sourceFeature', () => { + describe('feature structure', () => { it('has unique id symbol', () => { - expect(sourceSlice.id).toBeTypeOf('symbol'); + expect(sourceFeature.id).toBeTypeOf('symbol'); }); it('has correct initial state', () => { - expect(sourceSlice.initialState).toEqual({ + expect(sourceFeature.initialState).toEqual({ source: null, canPlay: false, }); }); it('has changeSource request handler', () => { - expect(sourceSlice.request.changeSource).toBeDefined(); - expect(sourceSlice.request.changeSource).toMatchObject({ + expect(sourceFeature.request.changeSource).toBeDefined(); + expect(sourceFeature.request.changeSource).toMatchObject({ key: 'changeSource', guard: [], handler: expect.any(Function), @@ -33,9 +33,9 @@ describe('sourceSlice', () => { readyState: HTMLMediaElement.HAVE_ENOUGH_DATA, }); - const snapshot = sourceSlice.getSnapshot({ + const snapshot = sourceFeature.getSnapshot({ target: video, - initialState: sourceSlice.initialState, + initialState: sourceFeature.initialState, }); expect(snapshot).toEqual({ @@ -50,9 +50,9 @@ describe('sourceSlice', () => { Object.defineProperty(video, 'currentSrc', { value: '', writable: false }); Object.defineProperty(video, 'readyState', { value: HTMLMediaElement.HAVE_NOTHING, writable: false }); - const snapshot = sourceSlice.getSnapshot({ + const snapshot = sourceFeature.getSnapshot({ target: video, - initialState: sourceSlice.initialState, + initialState: sourceFeature.initialState, }); expect(snapshot.source).toBe(null); @@ -66,7 +66,7 @@ describe('sourceSlice', () => { const update = vi.fn(); const controller = new AbortController(); - sourceSlice.subscribe({ target: video, update, signal: controller.signal }); + sourceFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('canplay')); expect(update).toHaveBeenCalled(); @@ -80,7 +80,7 @@ describe('sourceSlice', () => { const update = vi.fn(); const controller = new AbortController(); - sourceSlice.subscribe({ target: video, update, signal: controller.signal }); + sourceFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('loadstart')); expect(update).toHaveBeenCalled(); @@ -91,7 +91,7 @@ describe('sourceSlice', () => { const update = vi.fn(); const controller = new AbortController(); - sourceSlice.subscribe({ target: video, update, signal: controller.signal }); + sourceFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('emptied')); expect(update).toHaveBeenCalled(); @@ -104,7 +104,7 @@ describe('sourceSlice', () => { const video = createMockVideo({}); video.load = vi.fn(); - const result = sourceSlice.request.changeSource.handler('https://example.com/new.mp4', { + const result = sourceFeature.request.changeSource.handler('https://example.com/new.mp4', { target: video, signal: new AbortController().signal, meta: null, diff --git a/packages/core/src/dom/store/slices/tests/time.test.ts b/packages/core/src/dom/store/features/tests/time.test.ts similarity index 77% rename from packages/core/src/dom/store/slices/tests/time.test.ts rename to packages/core/src/dom/store/features/tests/time.test.ts index 4f736803..325fff61 100644 --- a/packages/core/src/dom/store/slices/tests/time.test.ts +++ b/packages/core/src/dom/store/features/tests/time.test.ts @@ -1,23 +1,23 @@ import { describe, expect, it, vi } from 'vitest'; -import { timeSlice } from '../time'; +import { timeFeature } from '../time'; -describe('timeSlice', () => { - describe('slice structure', () => { +describe('timeFeature', () => { + describe('feature structure', () => { it('has unique id symbol', () => { - expect(timeSlice.id).toBeTypeOf('symbol'); + expect(timeFeature.id).toBeTypeOf('symbol'); }); it('has correct initial state', () => { - expect(timeSlice.initialState).toEqual({ + expect(timeFeature.initialState).toEqual({ currentTime: 0, duration: 0, }); }); it('has seek request handler', () => { - expect(timeSlice.request.seek).toBeDefined(); - expect(timeSlice.request.seek).toMatchObject({ + expect(timeFeature.request.seek).toBeDefined(); + expect(timeFeature.request.seek).toMatchObject({ key: 'seek', guard: [], handler: expect.any(Function), @@ -32,9 +32,9 @@ describe('timeSlice', () => { duration: 120, }); - const snapshot = timeSlice.getSnapshot({ + const snapshot = timeFeature.getSnapshot({ target: video, - initialState: timeSlice.initialState, + initialState: timeFeature.initialState, }); expect(snapshot).toEqual({ @@ -49,9 +49,9 @@ describe('timeSlice', () => { duration: Number.NaN, }); - const snapshot = timeSlice.getSnapshot({ + const snapshot = timeFeature.getSnapshot({ target: video, - initialState: timeSlice.initialState, + initialState: timeFeature.initialState, }); expect(snapshot.duration).toBe(0); @@ -64,7 +64,7 @@ describe('timeSlice', () => { const update = vi.fn(); const controller = new AbortController(); - timeSlice.subscribe({ target: video, update, signal: controller.signal }); + timeFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('timeupdate')); expect(update).toHaveBeenCalled(); @@ -75,7 +75,7 @@ describe('timeSlice', () => { const update = vi.fn(); const controller = new AbortController(); - timeSlice.subscribe({ target: video, update, signal: controller.signal }); + timeFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('durationchange')); expect(update).toHaveBeenCalled(); @@ -86,7 +86,7 @@ describe('timeSlice', () => { const update = vi.fn(); const controller = new AbortController(); - timeSlice.subscribe({ target: video, update, signal: controller.signal }); + timeFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('seeked')); expect(update).toHaveBeenCalled(); @@ -97,7 +97,7 @@ describe('timeSlice', () => { const update = vi.fn(); const controller = new AbortController(); - timeSlice.subscribe({ target: video, update, signal: controller.signal }); + timeFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('emptied')); expect(update).toHaveBeenCalled(); @@ -109,7 +109,7 @@ describe('timeSlice', () => { it('sets currentTime on target and waits for seeked event', async () => { const video = createMockVideo({}); - const resultPromise = timeSlice.request.seek.handler(45, { + const resultPromise = timeFeature.request.seek.handler(45, { target: video, signal: new AbortController().signal, meta: null, @@ -128,7 +128,7 @@ describe('timeSlice', () => { const video = createMockVideo({}); const controller = new AbortController(); - const resultPromise = timeSlice.request.seek.handler(30, { + const resultPromise = timeFeature.request.seek.handler(30, { target: video, signal: controller.signal, meta: null, diff --git a/packages/core/src/dom/store/slices/tests/volume.test.ts b/packages/core/src/dom/store/features/tests/volume.test.ts similarity index 76% rename from packages/core/src/dom/store/slices/tests/volume.test.ts rename to packages/core/src/dom/store/features/tests/volume.test.ts index a1b11147..96e5c275 100644 --- a/packages/core/src/dom/store/slices/tests/volume.test.ts +++ b/packages/core/src/dom/store/features/tests/volume.test.ts @@ -1,23 +1,23 @@ import { describe, expect, it, vi } from 'vitest'; -import { volumeSlice } from '../volume'; +import { volumeFeature } from '../volume'; -describe('volumeSlice', () => { - describe('slice structure', () => { +describe('volumeFeature', () => { + describe('feature structure', () => { it('has unique id symbol', () => { - expect(volumeSlice.id).toBeTypeOf('symbol'); + expect(volumeFeature.id).toBeTypeOf('symbol'); }); it('has correct initial state', () => { - expect(volumeSlice.initialState).toEqual({ + expect(volumeFeature.initialState).toEqual({ volume: 1, muted: false, }); }); it('has all request handlers', () => { - expect(volumeSlice.request.changeVolume).toBeDefined(); - expect(volumeSlice.request.toggleMute).toBeDefined(); + expect(volumeFeature.request.changeVolume).toBeDefined(); + expect(volumeFeature.request.toggleMute).toBeDefined(); }); }); @@ -28,9 +28,9 @@ describe('volumeSlice', () => { muted: false, }); - const snapshot = volumeSlice.getSnapshot({ + const snapshot = volumeFeature.getSnapshot({ target: video, - initialState: volumeSlice.initialState, + initialState: volumeFeature.initialState, }); expect(snapshot).toEqual({ @@ -46,7 +46,7 @@ describe('volumeSlice', () => { const update = vi.fn(); const controller = new AbortController(); - volumeSlice.subscribe({ target: video, update, signal: controller.signal }); + volumeFeature.subscribe({ target: video, update, signal: controller.signal }); video.dispatchEvent(new Event('volumechange')); expect(update).toHaveBeenCalled(); @@ -58,7 +58,7 @@ describe('volumeSlice', () => { it('sets volume on target', () => { const video = createMockVideo({}); - const result = volumeSlice.request.changeVolume.handler(0.7, { + const result = volumeFeature.request.changeVolume.handler(0.7, { target: video, signal: new AbortController().signal, meta: null, @@ -71,7 +71,7 @@ describe('volumeSlice', () => { it('clamps volume to min 0', () => { const video = createMockVideo({}); - volumeSlice.request.changeVolume.handler(-0.5, { + volumeFeature.request.changeVolume.handler(-0.5, { target: video, signal: new AbortController().signal, meta: null, @@ -83,7 +83,7 @@ describe('volumeSlice', () => { it('clamps volume to max 1', () => { const video = createMockVideo({}); - volumeSlice.request.changeVolume.handler(1.5, { + volumeFeature.request.changeVolume.handler(1.5, { target: video, signal: new AbortController().signal, meta: null, @@ -97,7 +97,7 @@ describe('volumeSlice', () => { it('toggles mute from false to true', () => { const video = createMockVideo({ muted: false }); - const result = volumeSlice.request.toggleMute.handler(undefined, { + const result = volumeFeature.request.toggleMute.handler(undefined, { target: video, signal: new AbortController().signal, meta: null, @@ -110,7 +110,7 @@ describe('volumeSlice', () => { it('toggles mute from true to false', () => { const video = createMockVideo({ muted: true }); - const result = volumeSlice.request.toggleMute.handler(undefined, { + const result = volumeFeature.request.toggleMute.handler(undefined, { target: video, signal: new AbortController().signal, meta: null, diff --git a/packages/core/src/dom/store/slices/time.ts b/packages/core/src/dom/store/features/time.ts similarity index 74% rename from packages/core/src/dom/store/slices/time.ts rename to packages/core/src/dom/store/features/time.ts index e00704f8..904c08c9 100644 --- a/packages/core/src/dom/store/slices/time.ts +++ b/packages/core/src/dom/store/features/time.ts @@ -1,14 +1,14 @@ -import type { InferSliceRequests, InferSliceState } from '@videojs/store'; +import type { InferFeatureRequests, InferFeatureState } from '@videojs/store'; -import { createSlice } from '@videojs/store'; +import { createFeature } from '@videojs/store'; import { listen, onEvent } from '@videojs/utils/dom'; /** - * Time slice for HTMLMediaElement. + * Time feature for HTMLMediaElement. * * Tracks current time and duration, provides seek control. */ -export const timeSlice = createSlice()({ +export const timeFeature = createFeature()({ initialState: { /** Current playback position in seconds. */ currentTime: 0, @@ -39,6 +39,6 @@ export const timeSlice = createSlice()({ }, }); -export type TimeState = InferSliceState; +export type TimeState = InferFeatureState; -export type TimeRequests = InferSliceRequests; +export type TimeRequests = InferFeatureRequests; diff --git a/packages/core/src/dom/store/slices/volume.ts b/packages/core/src/dom/store/features/volume.ts similarity index 69% rename from packages/core/src/dom/store/slices/volume.ts rename to packages/core/src/dom/store/features/volume.ts index 5e4a5232..3b050d62 100644 --- a/packages/core/src/dom/store/slices/volume.ts +++ b/packages/core/src/dom/store/features/volume.ts @@ -1,14 +1,14 @@ -import type { InferSliceRequests, InferSliceState } from '@videojs/store'; +import type { InferFeatureRequests, InferFeatureState } from '@videojs/store'; -import { createSlice } from '@videojs/store'; +import { createFeature } from '@videojs/store'; import { listen } from '@videojs/utils/dom'; /** - * Volume slice for HTMLMediaElement. + * Volume feature for HTMLMediaElement. * * Tracks volume and mute state, provides volume control. */ -export const volumeSlice = createSlice()({ +export const volumeFeature = createFeature()({ initialState: { /** Volume level from 0 (silent) to 1 (max). */ volume: 1, @@ -40,6 +40,6 @@ export const volumeSlice = createSlice()({ }, }); -export type VolumeState = InferSliceState; +export type VolumeState = InferFeatureState; -export type VolumeRequests = InferSliceRequests; +export type VolumeRequests = InferFeatureRequests; diff --git a/packages/core/src/dom/store/slices/media.parts.ts b/packages/core/src/dom/store/slices/media.parts.ts deleted file mode 100644 index f3870ff1..00000000 --- a/packages/core/src/dom/store/slices/media.parts.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { bufferSlice } from './buffer'; -import { playbackSlice } from './playback'; -import { sourceSlice } from './source'; -import { timeSlice } from './time'; -import { volumeSlice } from './volume'; - -export { - bufferSlice as buffer, - playbackSlice as playback, - sourceSlice as source, - timeSlice as time, - volumeSlice as volume, -}; - -export const all = [bufferSlice, playbackSlice, sourceSlice, timeSlice, volumeSlice] as const; diff --git a/packages/html/package.json b/packages/html/package.json index 29a320e2..b427c8c9 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -16,14 +16,6 @@ ".": { "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", diff --git a/packages/html/src/define/vjs-frosted-skin.ts b/packages/html/src/define/vjs-frosted-skin.ts deleted file mode 100644 index da7471d6..00000000 --- a/packages/html/src/define/vjs-frosted-skin.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { FrostedSkinElement } from '../skins/frosted'; - -FrostedSkinElement.define(); diff --git a/packages/html/src/skins/frosted/index.ts b/packages/html/src/skins/frosted/index.ts deleted file mode 100644 index c15c454e..00000000 --- a/packages/html/src/skins/frosted/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { FrostedSkinElement } from './skin'; - -export { - create as createStore, - extendConfig, - RequestController, - StateController, - StoreAttachMixin, - StoreMixin, - StoreProviderMixin, - TasksController, -} from './store'; diff --git a/packages/html/src/skins/frosted/skin.ts b/packages/html/src/skins/frosted/skin.ts deleted file mode 100644 index d61a024d..00000000 --- a/packages/html/src/skins/frosted/skin.ts +++ /dev/null @@ -1,57 +0,0 @@ -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 - * - * - * - * ``` - * - * @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 = StoreMixin): void { - customElements.define(tagName, mixin(this)); - } - - constructor() { - super(); - const shadow = this.attachShadow({ mode: 'open' }); - shadow.innerHTML = ''; - } -} diff --git a/packages/html/src/skins/frosted/store.ts b/packages/html/src/skins/frosted/store.ts deleted file mode 100644 index 00a8511c..00000000 --- a/packages/html/src/skins/frosted/store.ts +++ /dev/null @@ -1,41 +0,0 @@ -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[] = []>( - extension?: Partial>, -) { - return extendBaseConfig(baseConfig, extension); -} - -export const { - StoreMixin, - StoreProviderMixin, - StoreAttachMixin, - StateController, - RequestController, - TasksController, - create, -} = createStore(baseConfig); diff --git a/packages/html/tsdown.config.ts b/packages/html/tsdown.config.ts index 9c9b64c9..819af4b5 100644 --- a/packages/html/tsdown.config.ts +++ b/packages/html/tsdown.config.ts @@ -6,9 +6,6 @@ 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', - 'define/vjs-frosted-skin': 'src/define/vjs-frosted-skin.ts', }, platform: 'browser', format: 'es', diff --git a/packages/react/package.json b/packages/react/package.json index 932a6456..aa4de8bb 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -16,10 +16,6 @@ ".": { "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", diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 97428b63..a40d69e7 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -3,7 +3,7 @@ // Media export { Video, type VideoProps } from './media/video'; -// Slices (re-export for convenience) +// Features (re-export for convenience) export { media } from '@videojs/core/dom'; // Store diff --git a/packages/react/src/media/tests/video.test.tsx b/packages/react/src/media/tests/video.test.tsx index 3f03039b..ed347094 100644 --- a/packages/react/src/media/tests/video.test.tsx +++ b/packages/react/src/media/tests/video.test.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react'; -import { createSlice } from '@videojs/store'; +import { createFeature } from '@videojs/store'; import { createStore } from '@videojs/store/react'; import { describe, expect, it, vi } from 'vitest'; @@ -12,7 +12,7 @@ describe('video', () => { muted = false; } - const mockSlice = createSlice()({ + const mockFeature = createFeature()({ initialState: { volume: 1, muted: false }, getSnapshot: ({ target }) => ({ volume: target.volume, @@ -23,7 +23,7 @@ describe('video', () => { }); function createTestStore() { - return createStore({ slices: [mockSlice] }); + return createStore({ features: [mockFeature] }); } it('renders a video element', () => { diff --git a/packages/react/src/media/video.tsx b/packages/react/src/media/video.tsx index f74caadc..b3a6fe28 100644 --- a/packages/react/src/media/video.tsx +++ b/packages/react/src/media/video.tsx @@ -22,7 +22,7 @@ export interface VideoProps extends VideoHTMLAttributes { * import { createStore, media } from '@videojs/react'; * * const { Provider } = createStore({ - * slices: media.all + * features: media.all * }); * * function App() { diff --git a/packages/react/src/skins/frosted/index.ts b/packages/react/src/skins/frosted/index.ts deleted file mode 100644 index 481dcb6a..00000000 --- a/packages/react/src/skins/frosted/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -'use client'; - -export { Skin, type SkinProps } from './skin'; - -export { create as createStore, extendConfig, Provider, useRequest, useSnapshot, useStore, useTasks } from './store'; diff --git a/packages/react/src/skins/frosted/skin.tsx b/packages/react/src/skins/frosted/skin.tsx deleted file mode 100644 index 534cf3b4..00000000 --- a/packages/react/src/skins/frosted/skin.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'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 ( - * - * - * - * - * ); - * } - * ``` - */ -export function Skin({ children, className }: SkinProps): React.JSX.Element { - return
{children}
; -} - -export namespace Skin { - export type Props = SkinProps; -} diff --git a/packages/react/src/skins/frosted/store.ts b/packages/react/src/skins/frosted/store.ts deleted file mode 100644 index 50e285a9..00000000 --- a/packages/react/src/skins/frosted/store.ts +++ /dev/null @@ -1,34 +0,0 @@ -'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, useSnapshot } = createStore( - * extendConfig({ slices: [chaptersSlice] }) - * ); - * ``` - */ -export function extendConfig[] = []>( - extension?: Partial>, -) { - return extendBaseConfig(baseConfig, extension); -} - -export const { Provider, create, useStore, useSnapshot, useRequest, useTasks } = createStore(baseConfig); diff --git a/packages/react/tsdown.config.ts b/packages/react/tsdown.config.ts index 5d037b37..6fb881c8 100644 --- a/packages/react/tsdown.config.ts +++ b/packages/react/tsdown.config.ts @@ -3,7 +3,6 @@ import { defineConfig } from 'tsdown'; export default defineConfig({ entry: { index: './src/index.ts', - 'skins/frosted': './src/skins/frosted/index.ts', }, platform: 'browser', format: 'es', diff --git a/packages/store/README.md b/packages/store/README.md index 4b8c4fb7..0d4cc156 100644 --- a/packages/store/README.md +++ b/packages/store/README.md @@ -20,10 +20,10 @@ npm install @videojs/store - **Write Path**: Send requests, coordinate execution, handle failures ```ts -import { createSlice, createStore } from '@videojs/store'; +import { createFeature, createStore } from '@videojs/store'; const store = createStore({ - slices: [playbackSlice, audioSlice], + features: [playbackFeature, audioFeature], }); store.attach(videoElement); //