From 3e61ef65a96d7ec2ce7a597c5db288954375c2d2 Mon Sep 17 00:00:00 2001 From: Rahim Date: Wed, 24 Jun 2026 14:38:13 -0700 Subject: [PATCH] refactor(core): simplify component manifests --- packages/core/scripts/generate-components.ts | 6 +- .../scripts/tests/generate-components.test.ts | 24 ++--- .../airplay-button-component.ts | 2 +- .../ui/alert-dialog/alert-dialog-component.ts | 14 +-- .../buffering-indicator-component.ts | 2 +- .../captions-button-component.ts | 2 +- .../captions-radio-group-component.ts | 2 +- .../ui/cast-button/cast-button-component.ts | 2 +- .../core/ui/container/container-component.ts | 2 +- .../core/ui/controls/controls-component.ts | 8 +- .../ui/error-dialog/error-dialog-component.ts | 14 +-- .../fullscreen-button-component.ts | 2 +- .../src/core/ui/gesture/gesture-component.ts | 2 +- .../src/core/ui/hotkey/hotkey-component.ts | 2 +- .../ui/live-button/live-button-component.ts | 2 +- packages/core/src/core/ui/manifest.ts | 93 +++++++++---------- .../core/src/core/ui/menu/menu-component.ts | 32 +++---- .../ui/mute-button/mute-button-component.ts | 2 +- .../src/core/ui/overlay/overlay-component.ts | 2 +- .../ui/pip-button/pip-button-component.ts | 2 +- .../ui/play-button/play-button-component.ts | 2 +- .../playback-rate-button-component.ts | 2 +- .../playback-rate-radio-group-component.ts | 2 +- .../src/core/ui/popover/popover-component.ts | 12 +-- .../src/core/ui/poster/poster-component.ts | 2 +- .../quality-radio-group-component.ts | 2 +- .../ui/seek-button/seek-button-component.ts | 2 +- .../seek-indicator-component.ts | 8 +- .../src/core/ui/slider/slider-component.ts | 26 +++--- .../status-announcer-component.ts | 2 +- .../status-indicator-component.ts | 8 +- .../src/core/ui/tests/jsx-runtime.test-d.tsx | 38 ++++---- .../src/core/ui/tests/jsx-runtime.test.ts | 14 +-- .../core/src/core/ui/text/text-component.ts | 2 +- .../core/ui/thumbnail/thumbnail-component.ts | 2 +- .../ui/time-slider/time-slider-component.ts | 18 ++-- .../core/src/core/ui/time/time-component.ts | 10 +- .../src/core/ui/tooltip/tooltip-component.ts | 18 ++-- .../volume-indicator-component.ts | 10 +- .../volume-slider/volume-slider-component.ts | 16 ++-- packages/core/src/jsx-runtime.ts | 57 +++++++----- packages/react/skins.compiler.config.ts | 1 - .../tests/skins-compiler-config.test.ts | 2 +- .../default-video.generated.tailwind.tsx | 7 +- packages/skins/src/default/video.skin.tsx | 3 +- 45 files changed, 239 insertions(+), 244 deletions(-) diff --git a/packages/core/scripts/generate-components.ts b/packages/core/scripts/generate-components.ts index 76e1564c..0b7ef4b4 100644 --- a/packages/core/scripts/generate-components.ts +++ b/packages/core/scripts/generate-components.ts @@ -49,11 +49,7 @@ export function defineComponentsConfig()({ ... }). - return ( - ts.isCallExpression(callee) && ts.isIdentifier(callee.expression) && callee.expression.text === 'defineComponent' - ); + return ts.isIdentifier(callee) && callee.text === 'defineComponent'; } function findDefaultExportCall(sourceFile: ts.SourceFile): ts.CallExpression | null { diff --git a/packages/core/scripts/tests/generate-components.test.ts b/packages/core/scripts/tests/generate-components.test.ts index e4c24671..0b85a856 100644 --- a/packages/core/scripts/tests/generate-components.test.ts +++ b/packages/core/scripts/tests/generate-components.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest'; import { generateComponents } from '../generate-components'; -const STUB = 'const defineComponent: any = () => (m: any) => m; const defineComponentPart: any = () => ({});'; +const STUB = 'const defineComponent: any = (m?: any) => m ?? {};'; function setup(): { dir: string; output: string; pattern: string } { const dir = mkdtempSync(join(tmpdir(), 'videojs-components-')); @@ -21,10 +21,10 @@ function setup(): { dir: string; output: string; pattern: string } { join(dir, 'play-button', 'play-button-component.ts'), `import { PlayButtonDataAttrs } from './play-button-data-attrs'; ${STUB} - export default defineComponent<{ disabled?: boolean }>()({ + export default defineComponent<{ disabled?: boolean }>({ name: 'PlayButton', dataAttrs: PlayButtonDataAttrs, - });` + });` ); writeFileSync(join(dir, 'slider', 'slider-data-attrs.ts'), `export const SliderDataAttrs = {} as const;`); @@ -32,20 +32,20 @@ function setup(): { dir: string; output: string; pattern: string } { join(dir, 'slider', 'slider-component.ts'), `import { SliderDataAttrs } from './slider-data-attrs'; ${STUB} - export default defineComponent()({ - name: 'Slider', - parts: { - Root: defineComponentPart<{ orientation?: 'horizontal' | 'vertical' }>(), - Track: defineComponentPart(), - }, - dataAttrs: SliderDataAttrs, - });` + export default defineComponent({ + name: 'Slider', + parts: { + Root: defineComponent<{ orientation?: 'horizontal' | 'vertical' }>(), + Track: defineComponent(), + }, + dataAttrs: SliderDataAttrs, + });` ); writeFileSync( join(dir, 'hotkey', 'hotkey-component.ts'), `${STUB} - export default defineComponent()({ name: 'Hotkey' });` + export default defineComponent({ name: 'Hotkey' });` ); return { dir, output: join(dir, 'out.ts'), pattern: join(dir, '*/*-component.ts') }; diff --git a/packages/core/src/core/ui/airplay-button/airplay-button-component.ts b/packages/core/src/core/ui/airplay-button/airplay-button-component.ts index e70ed0bc..ad0fe7f6 100644 --- a/packages/core/src/core/ui/airplay-button/airplay-button-component.ts +++ b/packages/core/src/core/ui/airplay-button/airplay-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { AirPlayButtonDataAttrs } from './airplay-button-data-attrs'; import type { AirPlayButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'AirPlayButton', dataAttrs: AirPlayButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/alert-dialog/alert-dialog-component.ts b/packages/core/src/core/ui/alert-dialog/alert-dialog-component.ts index b27e3c65..075a0af5 100644 --- a/packages/core/src/core/ui/alert-dialog/alert-dialog-component.ts +++ b/packages/core/src/core/ui/alert-dialog/alert-dialog-component.ts @@ -1,15 +1,15 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import { AlertDialogDataAttrs } from './alert-dialog-data-attrs'; import type { AlertDialogProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'AlertDialog', parts: { - Root: defineComponentPart(), - Popup: defineComponentPart(), - Title: defineComponentPart(), - Description: defineComponentPart(), - Close: defineComponentPart(), + Root: defineComponent(), + Popup: defineComponent(), + Title: defineComponent(), + Description: defineComponent(), + Close: defineComponent(), }, dataAttrs: AlertDialogDataAttrs, }); diff --git a/packages/core/src/core/ui/buffering-indicator/buffering-indicator-component.ts b/packages/core/src/core/ui/buffering-indicator/buffering-indicator-component.ts index db4dfdd0..5b8b9b9f 100644 --- a/packages/core/src/core/ui/buffering-indicator/buffering-indicator-component.ts +++ b/packages/core/src/core/ui/buffering-indicator/buffering-indicator-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { BufferingIndicatorDataAttrs } from './buffering-indicator-data-attrs'; import type { BufferingIndicatorProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'BufferingIndicator', dataAttrs: BufferingIndicatorDataAttrs, }); diff --git a/packages/core/src/core/ui/captions-button/captions-button-component.ts b/packages/core/src/core/ui/captions-button/captions-button-component.ts index 144071c9..b42a6e2f 100644 --- a/packages/core/src/core/ui/captions-button/captions-button-component.ts +++ b/packages/core/src/core/ui/captions-button/captions-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { CaptionsButtonDataAttrs } from './captions-button-data-attrs'; import type { CaptionsButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'CaptionsButton', dataAttrs: CaptionsButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/captions-radio-group/captions-radio-group-component.ts b/packages/core/src/core/ui/captions-radio-group/captions-radio-group-component.ts index 787f70db..1cb7c520 100644 --- a/packages/core/src/core/ui/captions-radio-group/captions-radio-group-component.ts +++ b/packages/core/src/core/ui/captions-radio-group/captions-radio-group-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { CaptionsRadioGroupDataAttrs } from './captions-radio-group-data-attrs'; import type { CaptionsRadioGroupProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'CaptionsRadioGroup', dataAttrs: CaptionsRadioGroupDataAttrs, }); diff --git a/packages/core/src/core/ui/cast-button/cast-button-component.ts b/packages/core/src/core/ui/cast-button/cast-button-component.ts index 71b65d84..7ac7acb7 100644 --- a/packages/core/src/core/ui/cast-button/cast-button-component.ts +++ b/packages/core/src/core/ui/cast-button/cast-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { CastButtonDataAttrs } from './cast-button-data-attrs'; import type { CastButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'CastButton', dataAttrs: CastButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/container/container-component.ts b/packages/core/src/core/ui/container/container-component.ts index 7f11c11d..6cec4f5b 100644 --- a/packages/core/src/core/ui/container/container-component.ts +++ b/packages/core/src/core/ui/container/container-component.ts @@ -1,6 +1,6 @@ import { defineComponent } from '../manifest'; import type { ContainerProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'Container', }); diff --git a/packages/core/src/core/ui/controls/controls-component.ts b/packages/core/src/core/ui/controls/controls-component.ts index 1254fb0f..4678a356 100644 --- a/packages/core/src/core/ui/controls/controls-component.ts +++ b/packages/core/src/core/ui/controls/controls-component.ts @@ -1,11 +1,11 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import { ControlsDataAttrs } from './controls-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'Controls', parts: { - Root: defineComponentPart(), - Group: defineComponentPart(), + Root: defineComponent(), + Group: defineComponent(), }, dataAttrs: ControlsDataAttrs, }); diff --git a/packages/core/src/core/ui/error-dialog/error-dialog-component.ts b/packages/core/src/core/ui/error-dialog/error-dialog-component.ts index eaee1fe8..b16550fe 100644 --- a/packages/core/src/core/ui/error-dialog/error-dialog-component.ts +++ b/packages/core/src/core/ui/error-dialog/error-dialog-component.ts @@ -1,15 +1,15 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import { ErrorDialogDataAttrs } from './error-dialog-data-attrs'; import type { ErrorDialogProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'ErrorDialog', parts: { - Root: defineComponentPart(), - Popup: defineComponentPart(), - Title: defineComponentPart(), - Description: defineComponentPart(), - Close: defineComponentPart(), + Root: defineComponent(), + Popup: defineComponent(), + Title: defineComponent(), + Description: defineComponent(), + Close: defineComponent(), }, dataAttrs: ErrorDialogDataAttrs, }); diff --git a/packages/core/src/core/ui/fullscreen-button/fullscreen-button-component.ts b/packages/core/src/core/ui/fullscreen-button/fullscreen-button-component.ts index ab976440..64abe3d0 100644 --- a/packages/core/src/core/ui/fullscreen-button/fullscreen-button-component.ts +++ b/packages/core/src/core/ui/fullscreen-button/fullscreen-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { FullscreenButtonDataAttrs } from './fullscreen-button-data-attrs'; import type { FullscreenButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'FullscreenButton', dataAttrs: FullscreenButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/gesture/gesture-component.ts b/packages/core/src/core/ui/gesture/gesture-component.ts index e07c08da..1a7f18b3 100644 --- a/packages/core/src/core/ui/gesture/gesture-component.ts +++ b/packages/core/src/core/ui/gesture/gesture-component.ts @@ -1,6 +1,6 @@ import { defineComponent } from '../manifest'; import type { GestureProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'Gesture', }); diff --git a/packages/core/src/core/ui/hotkey/hotkey-component.ts b/packages/core/src/core/ui/hotkey/hotkey-component.ts index e02dff07..7e3cd571 100644 --- a/packages/core/src/core/ui/hotkey/hotkey-component.ts +++ b/packages/core/src/core/ui/hotkey/hotkey-component.ts @@ -1,6 +1,6 @@ import { defineComponent } from '../manifest'; import type { HotkeyProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'Hotkey', }); diff --git a/packages/core/src/core/ui/live-button/live-button-component.ts b/packages/core/src/core/ui/live-button/live-button-component.ts index 5f90bdaa..faeb98b4 100644 --- a/packages/core/src/core/ui/live-button/live-button-component.ts +++ b/packages/core/src/core/ui/live-button/live-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { LiveButtonDataAttrs } from './live-button-data-attrs'; import type { LiveButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'LiveButton', dataAttrs: LiveButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/manifest.ts b/packages/core/src/core/ui/manifest.ts index 287f6148..42f7aa15 100644 --- a/packages/core/src/core/ui/manifest.ts +++ b/packages/core/src/core/ui/manifest.ts @@ -5,63 +5,56 @@ export type EmptyProps = { readonly [__EMPTY_PROPS__]?: never; }; -export interface ComponentPart { +export interface ComponentDefinition< + Props extends object = EmptyProps, + Parts extends ComponentRecord | undefined = undefined, +> { + name?: string | undefined; + parts?: Parts | undefined; + dataAttrs?: Record | undefined; readonly [__PROPS_BRAND__]?: Props; } -export interface ComponentPartGroup { - parts: Parts; +export type ComponentRecord = Record>; +export type ComponentManifest< + Props extends object = any, + Parts extends ComponentRecord | undefined = ComponentRecord | undefined, +> = ComponentDefinition & { name: string }; + +type ComponentOptions = Omit< + ComponentDefinition, + typeof __PROPS_BRAND__ +>; + +export function hasParts( + component: ComponentDefinition +): component is ComponentDefinition & { parts: Parts } { + return Boolean(component.parts); } -export type ComponentPartRecord = Record | ComponentPartGroup>; +export type InferProps = T extends ComponentDefinition ? Props : never; -export interface ComponentManifest { - name: string; - dataAttrs?: Record; - readonly [__PROPS_BRAND__]?: Props; -} - -export interface ComponentGroupManifest { - name: string; - parts: Parts; - dataAttrs?: Record; -} - -export type AnyComponentManifest = ComponentManifest | ComponentGroupManifest; - -type ComponentDefinition = Omit, typeof __PROPS_BRAND__>; -type ComponentGroupDefinition = ComponentGroupManifest; - -interface DefineComponentFactory { - (manifest: ComponentGroupDefinition): ComponentGroupManifest; - (manifest: ComponentDefinition): ComponentManifest; -} - -export type InferProps = - T extends ComponentManifest ? Props : T extends ComponentPart ? Props : never; - -export type InferParts = - T extends ComponentGroupManifest - ? keyof Parts - : T extends ComponentPartGroup - ? keyof Parts - : never; +export type InferParts = T extends ComponentDefinition ? keyof NonNullable : never; export type InferPartProps = - T extends ComponentGroupManifest ? (K extends keyof Parts ? InferProps : never) : never; + T extends ComponentDefinition + ? K extends keyof NonNullable + ? InferProps[K]> + : never + : never; -export function defineComponentPart(): ComponentPart { - return {} as ComponentPart; -} - -export function defineComponentPartGroup( - parts: Parts -): ComponentPartGroup { - return { parts }; -} - -/** Define a component manifest. */ -export function defineComponent(): DefineComponentFactory { - return ((manifest: ComponentDefinition | ComponentGroupDefinition) => - manifest) as DefineComponentFactory; +export function defineComponent(): ComponentDefinition; +export function defineComponent< + Props extends object = EmptyProps, + const Parts extends ComponentRecord | undefined = undefined, +>(options: ComponentOptions & { name: string }): ComponentManifest; +export function defineComponent< + Props extends object = EmptyProps, + const Parts extends ComponentRecord | undefined = undefined, +>(options: ComponentOptions): ComponentDefinition; +export function defineComponent< + Props extends object = EmptyProps, + const Parts extends ComponentRecord | undefined = undefined, +>(options?: ComponentOptions): ComponentDefinition { + return (options ?? {}) as ComponentDefinition; } diff --git a/packages/core/src/core/ui/menu/menu-component.ts b/packages/core/src/core/ui/menu/menu-component.ts index 3567714f..97b217d6 100644 --- a/packages/core/src/core/ui/menu/menu-component.ts +++ b/packages/core/src/core/ui/menu/menu-component.ts @@ -1,4 +1,4 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import { MenuDataAttrs } from './menu-data-attrs'; import type { MenuBackProps, @@ -11,23 +11,23 @@ import type { MenuTriggerProps, } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'Menu', parts: { - Root: defineComponentPart(), - Trigger: defineComponentPart(), - Content: defineComponentPart(), - View: defineComponentPart(), - Back: defineComponentPart(), - Group: defineComponentPart(), - GroupLabel: defineComponentPart(), - Item: defineComponentPart(), - ItemIndicator: defineComponentPart(), - ItemValue: defineComponentPart(), - CheckboxItem: defineComponentPart(), - RadioGroup: defineComponentPart(), - RadioItem: defineComponentPart(), - Separator: defineComponentPart(), + Root: defineComponent(), + Trigger: defineComponent(), + Content: defineComponent(), + View: defineComponent(), + Back: defineComponent(), + Group: defineComponent(), + GroupLabel: defineComponent(), + Item: defineComponent(), + ItemIndicator: defineComponent(), + ItemValue: defineComponent(), + CheckboxItem: defineComponent(), + RadioGroup: defineComponent(), + RadioItem: defineComponent(), + Separator: defineComponent(), }, dataAttrs: MenuDataAttrs, }); diff --git a/packages/core/src/core/ui/mute-button/mute-button-component.ts b/packages/core/src/core/ui/mute-button/mute-button-component.ts index e765b9e4..a791968c 100644 --- a/packages/core/src/core/ui/mute-button/mute-button-component.ts +++ b/packages/core/src/core/ui/mute-button/mute-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { MuteButtonDataAttrs } from './mute-button-data-attrs'; import type { MuteButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'MuteButton', dataAttrs: MuteButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/overlay/overlay-component.ts b/packages/core/src/core/ui/overlay/overlay-component.ts index 360acdfb..b6381a02 100644 --- a/packages/core/src/core/ui/overlay/overlay-component.ts +++ b/packages/core/src/core/ui/overlay/overlay-component.ts @@ -1,7 +1,7 @@ import { defineComponent } from '../manifest'; import { OverlayDataAttrs } from './overlay-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'Overlay', dataAttrs: OverlayDataAttrs, }); diff --git a/packages/core/src/core/ui/pip-button/pip-button-component.ts b/packages/core/src/core/ui/pip-button/pip-button-component.ts index 8cf51b0a..08bc2794 100644 --- a/packages/core/src/core/ui/pip-button/pip-button-component.ts +++ b/packages/core/src/core/ui/pip-button/pip-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { PiPButtonDataAttrs } from './pip-button-data-attrs'; import type { PiPButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'PiPButton', dataAttrs: PiPButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/play-button/play-button-component.ts b/packages/core/src/core/ui/play-button/play-button-component.ts index cae06609..c209dec8 100644 --- a/packages/core/src/core/ui/play-button/play-button-component.ts +++ b/packages/core/src/core/ui/play-button/play-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { PlayButtonDataAttrs } from './play-button-data-attrs'; import type { PlayButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'PlayButton', dataAttrs: PlayButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/playback-rate-button/playback-rate-button-component.ts b/packages/core/src/core/ui/playback-rate-button/playback-rate-button-component.ts index 8a5a0198..6ff66436 100644 --- a/packages/core/src/core/ui/playback-rate-button/playback-rate-button-component.ts +++ b/packages/core/src/core/ui/playback-rate-button/playback-rate-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { PlaybackRateButtonDataAttrs } from './playback-rate-button-data-attrs'; import type { PlaybackRateButtonProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'PlaybackRateButton', dataAttrs: PlaybackRateButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/playback-rate-radio-group/playback-rate-radio-group-component.ts b/packages/core/src/core/ui/playback-rate-radio-group/playback-rate-radio-group-component.ts index 697cb297..e4a2e569 100644 --- a/packages/core/src/core/ui/playback-rate-radio-group/playback-rate-radio-group-component.ts +++ b/packages/core/src/core/ui/playback-rate-radio-group/playback-rate-radio-group-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import { PlaybackRateRadioGroupDataAttrs } from './playback-rate-radio-group-data-attrs'; import type { PlaybackRateRadioGroupProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'PlaybackRateRadioGroup', dataAttrs: PlaybackRateRadioGroupDataAttrs, }); diff --git a/packages/core/src/core/ui/popover/popover-component.ts b/packages/core/src/core/ui/popover/popover-component.ts index 0ffd2133..c4a770a7 100644 --- a/packages/core/src/core/ui/popover/popover-component.ts +++ b/packages/core/src/core/ui/popover/popover-component.ts @@ -1,14 +1,14 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import { PopoverDataAttrs } from './popover-data-attrs'; import type { PopoverProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'Popover', parts: { - Root: defineComponentPart(), - Trigger: defineComponentPart(), - Popup: defineComponentPart(), - Arrow: defineComponentPart(), + Root: defineComponent(), + Trigger: defineComponent(), + Popup: defineComponent(), + Arrow: defineComponent(), }, dataAttrs: PopoverDataAttrs, }); diff --git a/packages/core/src/core/ui/poster/poster-component.ts b/packages/core/src/core/ui/poster/poster-component.ts index 7d478f93..df7e0a2e 100644 --- a/packages/core/src/core/ui/poster/poster-component.ts +++ b/packages/core/src/core/ui/poster/poster-component.ts @@ -1,7 +1,7 @@ import { defineComponent } from '../manifest'; import { PosterDataAttrs } from './poster-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'Poster', dataAttrs: PosterDataAttrs, }); diff --git a/packages/core/src/core/ui/quality-radio-group/quality-radio-group-component.ts b/packages/core/src/core/ui/quality-radio-group/quality-radio-group-component.ts index bdba33f3..6b088f81 100644 --- a/packages/core/src/core/ui/quality-radio-group/quality-radio-group-component.ts +++ b/packages/core/src/core/ui/quality-radio-group/quality-radio-group-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import type { QualityRadioGroupProps } from './props'; import { QualityRadioGroupDataAttrs } from './quality-radio-group-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'QualityRadioGroup', dataAttrs: QualityRadioGroupDataAttrs, }); diff --git a/packages/core/src/core/ui/seek-button/seek-button-component.ts b/packages/core/src/core/ui/seek-button/seek-button-component.ts index 58c4d1ee..b49eda60 100644 --- a/packages/core/src/core/ui/seek-button/seek-button-component.ts +++ b/packages/core/src/core/ui/seek-button/seek-button-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import type { SeekButtonProps } from './props'; import { SeekButtonDataAttrs } from './seek-button-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'SeekButton', dataAttrs: SeekButtonDataAttrs, }); diff --git a/packages/core/src/core/ui/seek-indicator/seek-indicator-component.ts b/packages/core/src/core/ui/seek-indicator/seek-indicator-component.ts index 1c13434a..8c0259b5 100644 --- a/packages/core/src/core/ui/seek-indicator/seek-indicator-component.ts +++ b/packages/core/src/core/ui/seek-indicator/seek-indicator-component.ts @@ -1,12 +1,12 @@ import { SeekIndicatorDataAttrs } from '../input-feedback/seek-indicator-data-attrs'; -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import type { SeekIndicatorProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'SeekIndicator', parts: { - Root: defineComponentPart(), - Value: defineComponentPart(), + Root: defineComponent(), + Value: defineComponent(), }, dataAttrs: SeekIndicatorDataAttrs, }); diff --git a/packages/core/src/core/ui/slider/slider-component.ts b/packages/core/src/core/ui/slider/slider-component.ts index b9c7ad37..5d6ae040 100644 --- a/packages/core/src/core/ui/slider/slider-component.ts +++ b/packages/core/src/core/ui/slider/slider-component.ts @@ -1,21 +1,23 @@ -import { defineComponent, defineComponentPart, defineComponentPartGroup } from '../manifest'; +import { defineComponent } from '../manifest'; import type { SliderProps, SliderValueProps } from './props'; import { SliderDataAttrs } from './slider-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'Slider', parts: { - Root: defineComponentPart(), - Track: defineComponentPart(), - Fill: defineComponentPart(), - Buffer: defineComponentPart(), - Thumb: defineComponentPart(), - Thumbnail: defineComponentPartGroup({ - Root: defineComponentPart(), - Image: defineComponentPart(), + Root: defineComponent(), + Track: defineComponent(), + Fill: defineComponent(), + Buffer: defineComponent(), + Thumb: defineComponent(), + Thumbnail: defineComponent({ + parts: { + Root: defineComponent(), + Image: defineComponent(), + }, }), - Preview: defineComponentPart(), - Value: defineComponentPart(), + Preview: defineComponent(), + Value: defineComponent(), }, dataAttrs: SliderDataAttrs, }); diff --git a/packages/core/src/core/ui/status-announcer/status-announcer-component.ts b/packages/core/src/core/ui/status-announcer/status-announcer-component.ts index 9a301572..082913c2 100644 --- a/packages/core/src/core/ui/status-announcer/status-announcer-component.ts +++ b/packages/core/src/core/ui/status-announcer/status-announcer-component.ts @@ -1,6 +1,6 @@ import { defineComponent } from '../manifest'; import type { StatusAnnouncerProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'StatusAnnouncer', }); diff --git a/packages/core/src/core/ui/status-indicator/status-indicator-component.ts b/packages/core/src/core/ui/status-indicator/status-indicator-component.ts index 97e91bee..15dd0d9d 100644 --- a/packages/core/src/core/ui/status-indicator/status-indicator-component.ts +++ b/packages/core/src/core/ui/status-indicator/status-indicator-component.ts @@ -1,12 +1,12 @@ import { StatusIndicatorDataAttrs } from '../input-feedback/status-indicator-data-attrs'; -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import type { StatusIndicatorProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'StatusIndicator', parts: { - Root: defineComponentPart(), - Value: defineComponentPart(), + Root: defineComponent(), + Value: defineComponent(), }, dataAttrs: StatusIndicatorDataAttrs, }); diff --git a/packages/core/src/core/ui/tests/jsx-runtime.test-d.tsx b/packages/core/src/core/ui/tests/jsx-runtime.test-d.tsx index 4b0b0b2b..7429abec 100644 --- a/packages/core/src/core/ui/tests/jsx-runtime.test-d.tsx +++ b/packages/core/src/core/ui/tests/jsx-runtime.test-d.tsx @@ -5,63 +5,63 @@ import { createComponent, Slot } from '../../../jsx-runtime'; import type { ContainerProps } from '../container/props'; import type { GestureProps } from '../gesture/props'; import type { HotkeyProps } from '../hotkey/props'; -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; const PlayButton = createComponent( - defineComponent()({ + defineComponent({ name: 'PlayButton', }) ); const Slider = createComponent( - defineComponent<{ orientation?: 'horizontal' | 'vertical'; thumbAlignment?: 'center' | 'edge' }>()({ + defineComponent({ name: 'Slider', parts: { - Root: defineComponentPart<{ orientation?: 'horizontal' | 'vertical'; thumbAlignment?: 'center' | 'edge' }>(), - Track: defineComponentPart(), - Fill: defineComponentPart(), - Thumb: defineComponentPart(), - Value: defineComponentPart<{ type?: 'current' | 'pointer' }>(), + Root: defineComponent<{ orientation?: 'horizontal' | 'vertical'; thumbAlignment?: 'center' | 'edge' }>(), + Track: defineComponent(), + Fill: defineComponent(), + Thumb: defineComponent(), + Value: defineComponent<{ type?: 'current' | 'pointer' }>(), }, }) ); const Time = createComponent( - defineComponent()({ + defineComponent({ name: 'Time', parts: { - Value: defineComponentPart<{ type: 'current' | 'duration' }>(), + Value: defineComponent<{ type: 'current' | 'duration' }>(), }, }) ); const Menu = createComponent( - defineComponent()({ + defineComponent({ name: 'Menu', parts: { - Root: defineComponentPart(), - Trigger: defineComponentPart<{ type?: 'quality' | 'playback-rate' | 'captions'; disabled?: boolean }>(), - RadioGroup: defineComponentPart<{ value: string; onValueChange: (value: string) => void }>(), - RadioItem: defineComponentPart<{ value: string; disabled?: boolean }>(), - ItemIndicator: defineComponentPart<{ checked?: boolean; forceMount?: boolean }>(), + Root: defineComponent(), + Trigger: defineComponent<{ type?: 'quality' | 'playback-rate' | 'captions'; disabled?: boolean }>(), + RadioGroup: defineComponent<{ value: string; onValueChange: (value: string) => void }>(), + RadioItem: defineComponent<{ value: string; disabled?: boolean }>(), + ItemIndicator: defineComponent<{ checked?: boolean; forceMount?: boolean }>(), }, }) ); const Container = createComponent( - defineComponent()({ + defineComponent({ name: 'Container', }) ); const Hotkey = createComponent( - defineComponent()({ + defineComponent({ name: 'Hotkey', }) ); const Gesture = createComponent( - defineComponent()({ + defineComponent({ name: 'Gesture', }) ); diff --git a/packages/core/src/core/ui/tests/jsx-runtime.test.ts b/packages/core/src/core/ui/tests/jsx-runtime.test.ts index fe35b940..8fbbe818 100644 --- a/packages/core/src/core/ui/tests/jsx-runtime.test.ts +++ b/packages/core/src/core/ui/tests/jsx-runtime.test.ts @@ -1,18 +1,20 @@ import { describe, expect, it } from 'vitest'; import { createComponent } from '../../../jsx-runtime'; -import { defineComponent, defineComponentPart, defineComponentPartGroup } from '../manifest'; +import { defineComponent } from '../manifest'; describe('createComponent', () => { it('creates nested component parts with dotted part paths', () => { const Slider = createComponent( - defineComponent()({ + defineComponent({ name: 'Slider', parts: { - Root: defineComponentPart(), - Thumbnail: defineComponentPartGroup({ - Root: defineComponentPart(), - Image: defineComponentPart(), + Root: defineComponent(), + Thumbnail: defineComponent({ + parts: { + Root: defineComponent(), + Image: defineComponent(), + }, }), }, }) diff --git a/packages/core/src/core/ui/text/text-component.ts b/packages/core/src/core/ui/text/text-component.ts index bfdad25d..6afa4e54 100644 --- a/packages/core/src/core/ui/text/text-component.ts +++ b/packages/core/src/core/ui/text/text-component.ts @@ -1,5 +1,5 @@ import { defineComponent } from '../manifest'; -export default defineComponent()({ +export default defineComponent({ name: 'Text', }); diff --git a/packages/core/src/core/ui/thumbnail/thumbnail-component.ts b/packages/core/src/core/ui/thumbnail/thumbnail-component.ts index 74fe8660..b927ad52 100644 --- a/packages/core/src/core/ui/thumbnail/thumbnail-component.ts +++ b/packages/core/src/core/ui/thumbnail/thumbnail-component.ts @@ -2,7 +2,7 @@ import { defineComponent } from '../manifest'; import type { ThumbnailProps } from './props'; import { ThumbnailDataAttrs } from './thumbnail-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'Thumbnail', dataAttrs: ThumbnailDataAttrs, }); diff --git a/packages/core/src/core/ui/time-slider/time-slider-component.ts b/packages/core/src/core/ui/time-slider/time-slider-component.ts index a0b9b62d..4dc6690e 100644 --- a/packages/core/src/core/ui/time-slider/time-slider-component.ts +++ b/packages/core/src/core/ui/time-slider/time-slider-component.ts @@ -1,18 +1,18 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import type { SliderValueProps } from '../slider/props'; import type { TimeSliderProps } from './props'; import { TimeSliderDataAttrs } from './time-slider-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'TimeSlider', parts: { - Root: defineComponentPart(), - Track: defineComponentPart(), - Fill: defineComponentPart(), - Buffer: defineComponentPart(), - Thumb: defineComponentPart(), - Preview: defineComponentPart(), - Value: defineComponentPart(), + Root: defineComponent(), + Track: defineComponent(), + Fill: defineComponent(), + Buffer: defineComponent(), + Thumb: defineComponent(), + Preview: defineComponent(), + Value: defineComponent(), }, dataAttrs: TimeSliderDataAttrs, }); diff --git a/packages/core/src/core/ui/time/time-component.ts b/packages/core/src/core/ui/time/time-component.ts index 1913313b..934fc35f 100644 --- a/packages/core/src/core/ui/time/time-component.ts +++ b/packages/core/src/core/ui/time/time-component.ts @@ -1,13 +1,13 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import type { TimeProps } from './props'; import { TimeDataAttrs } from './time-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'Time', parts: { - Group: defineComponentPart(), - Separator: defineComponentPart(), - Value: defineComponentPart(), + Group: defineComponent(), + Separator: defineComponent(), + Value: defineComponent(), }, dataAttrs: TimeDataAttrs, }); diff --git a/packages/core/src/core/ui/tooltip/tooltip-component.ts b/packages/core/src/core/ui/tooltip/tooltip-component.ts index f0adbb6c..fafb3b19 100644 --- a/packages/core/src/core/ui/tooltip/tooltip-component.ts +++ b/packages/core/src/core/ui/tooltip/tooltip-component.ts @@ -1,17 +1,17 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import type { TooltipProps } from './props'; import { TooltipDataAttrs } from './tooltip-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'Tooltip', parts: { - Provider: defineComponentPart(), - Root: defineComponentPart(), - Trigger: defineComponentPart(), - Popup: defineComponentPart(), - Arrow: defineComponentPart(), - Label: defineComponentPart(), - Shortcut: defineComponentPart(), + Provider: defineComponent(), + Root: defineComponent(), + Trigger: defineComponent(), + Popup: defineComponent(), + Arrow: defineComponent(), + Label: defineComponent(), + Shortcut: defineComponent(), }, dataAttrs: TooltipDataAttrs, }); diff --git a/packages/core/src/core/ui/volume-indicator/volume-indicator-component.ts b/packages/core/src/core/ui/volume-indicator/volume-indicator-component.ts index acbd58d8..4f19a934 100644 --- a/packages/core/src/core/ui/volume-indicator/volume-indicator-component.ts +++ b/packages/core/src/core/ui/volume-indicator/volume-indicator-component.ts @@ -1,13 +1,13 @@ import { VolumeIndicatorDataAttrs } from '../input-feedback/volume-indicator-data-attrs'; -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import type { VolumeIndicatorProps } from './props'; -export default defineComponent()({ +export default defineComponent({ name: 'VolumeIndicator', parts: { - Root: defineComponentPart(), - Fill: defineComponentPart(), - Value: defineComponentPart(), + Root: defineComponent(), + Fill: defineComponent(), + Value: defineComponent(), }, dataAttrs: VolumeIndicatorDataAttrs, }); diff --git a/packages/core/src/core/ui/volume-slider/volume-slider-component.ts b/packages/core/src/core/ui/volume-slider/volume-slider-component.ts index 5f17b0ef..0e2b73a2 100644 --- a/packages/core/src/core/ui/volume-slider/volume-slider-component.ts +++ b/packages/core/src/core/ui/volume-slider/volume-slider-component.ts @@ -1,17 +1,17 @@ -import { defineComponent, defineComponentPart } from '../manifest'; +import { defineComponent } from '../manifest'; import type { SliderValueProps } from '../slider/props'; import type { VolumeSliderProps } from './props'; import { VolumeSliderDataAttrs } from './volume-slider-data-attrs'; -export default defineComponent()({ +export default defineComponent({ name: 'VolumeSlider', parts: { - Root: defineComponentPart(), - Track: defineComponentPart(), - Fill: defineComponentPart(), - Thumb: defineComponentPart(), - Preview: defineComponentPart(), - Value: defineComponentPart(), + Root: defineComponent(), + Track: defineComponent(), + Fill: defineComponent(), + Thumb: defineComponent(), + Preview: defineComponent(), + Value: defineComponent(), }, dataAttrs: VolumeSliderDataAttrs, }); diff --git a/packages/core/src/jsx-runtime.ts b/packages/core/src/jsx-runtime.ts index 1d8f4a1a..26c1dab3 100644 --- a/packages/core/src/jsx-runtime.ts +++ b/packages/core/src/jsx-runtime.ts @@ -1,10 +1,9 @@ -import type { - AnyComponentManifest, - ComponentGroupManifest, - ComponentPart, - ComponentPartGroup, - ComponentPartRecord, - InferProps, +import { + type ComponentDefinition, + type ComponentManifest, + type ComponentRecord, + hasParts, + type InferProps, } from './core/ui/manifest'; export const VIDEOJS_NODE = Symbol.for('@videojs/node'); @@ -41,21 +40,26 @@ export interface Component { readonly $$component: { name: string; part: string | null }; } -type InferPartNodeProps = Node extends ComponentPart ? Props : never; +type InferComponentNodeProps = Node extends ComponentDefinition ? Props : never; -type PartComponentProps = [NonNullable>] extends [never] +type ComponentNodeProps = [NonNullable>] extends [never] ? EmptyProps - : NonNullable>; + : NonNullable>; -type CompoundComponent = { - [K in keyof Parts & string]: Parts[K] extends ComponentPartGroup - ? CompoundComponent - : Component>; +type CompoundComponent = { + [K in keyof Parts & string]: Parts[K] extends ComponentDefinition + ? ChildParts extends ComponentRecord + ? CompoundComponent + : Component> + : Component>; }; -export type CreateComponentResult = M extends ComponentGroupManifest - ? CompoundComponent - : Component>; +export type CreateComponentResult = + M extends ComponentDefinition + ? Parts extends ComponentRecord + ? CompoundComponent + : Component> + : Component>; function createRuntimeComponentPart(name: string, part: string | null): Component { const fn = (_props: BaseProps & Props): ComponentNode => { @@ -69,23 +73,28 @@ function createRuntimeComponentPart(name: string, part: st export const Slot = createRuntimeComponentPart('Slot', null); -export function createComponent(manifest: M): CreateComponentResult { - if (!('parts' in manifest)) { - return createRuntimeComponentPart(manifest.name, null) as CreateComponentResult; +export function createComponent(manifest: ComponentManifest): Component; +export function createComponent( + manifest: ComponentManifest +): CompoundComponent; +export function createComponent(manifest: ComponentManifest): Component | Record { + if (!hasParts(manifest)) { + return createRuntimeComponentPart(manifest.name, null); } - return createComponentParts(manifest.name, manifest.parts) as CreateComponentResult; + return createComponentParts(manifest.name, manifest.parts); } -function createComponentParts(name: string, parts: ComponentPartRecord, prefix = ''): Record { +function createComponentParts(name: string, parts: ComponentRecord, prefix = ''): Record { const compound: Record = {}; for (const part of Object.keys(parts)) { const path = prefix ? `${prefix}.${part}` : part; const value = parts[part]!; - compound[part] = - 'parts' in value ? createComponentParts(name, value.parts, path) : createRuntimeComponentPart(name, path); + compound[part] = hasParts(value) + ? createComponentParts(name, value.parts, path) + : createRuntimeComponentPart(name, path); } return compound; diff --git a/packages/react/skins.compiler.config.ts b/packages/react/skins.compiler.config.ts index 13c8c04b..adb9c7c4 100644 --- a/packages/react/skins.compiler.config.ts +++ b/packages/react/skins.compiler.config.ts @@ -62,7 +62,6 @@ export default defineConfig({ code.create.jsx.element(Poster, { src: code.create.value.onlyIf({ value: 'poster', condition: isString }), render: code.create.value.onlyIf({ value: 'poster', condition: isRenderProp }), - className: code.create.value.identifier('posterClass'), }) ); }, diff --git a/packages/react/src/presets/tests/skins-compiler-config.test.ts b/packages/react/src/presets/tests/skins-compiler-config.test.ts index 7c4469c4..185a1c07 100644 --- a/packages/react/src/presets/tests/skins-compiler-config.test.ts +++ b/packages/react/src/presets/tests/skins-compiler-config.test.ts @@ -54,7 +54,7 @@ describe('skins compiler config', () => { expect(compactCode).toContain(compact('')); expect(compactCode).toContain( compact( - '{poster && }' + '{poster && }' ) ); expect(compactCode).toContain(compact('')); diff --git a/packages/react/src/presets/video/default-video.generated.tailwind.tsx b/packages/react/src/presets/video/default-video.generated.tailwind.tsx index 07b21a88..a0ecb6aa 100644 --- a/packages/react/src/presets/video/default-video.generated.tailwind.tsx +++ b/packages/react/src/presets/video/default-video.generated.tailwind.tsx @@ -18,7 +18,6 @@ import { pipIcon, playIcon, popup, - poster as posterClass, seek, slider, thumbnail, @@ -92,11 +91,7 @@ export function DefaultVideoSkin({ className, children, poster, ...rest }: Defau {children} {poster && ( - + )} diff --git a/packages/skins/src/default/video.skin.tsx b/packages/skins/src/default/video.skin.tsx index 2b199444..91b2c247 100644 --- a/packages/skins/src/default/video.skin.tsx +++ b/packages/skins/src/default/video.skin.tsx @@ -62,7 +62,6 @@ import { pipIcon, playIcon, popup, - poster as posterClass, seek, slider, thumbnail, @@ -84,7 +83,7 @@ export function DefaultVideoSkin({ className, children }: DefaultVideoSkinProps) {children} - +