feat(site): list required css imports per skin in preset reference (#1521)

This commit is contained in:
Renzo Delfino
2026-06-12 14:57:42 -03:00
committed by GitHub
parent 4a81e048a1
commit 1145f09e52
9 changed files with 34 additions and 20 deletions
@@ -549,6 +549,7 @@ export { generateFeatureReferences } from './feature-handler.js';
export interface PresetSkinDef { export interface PresetSkinDef {
name: string; name: string;
tagName?: string; tagName?: string;
cssImport?: string;
} }
export interface PresetReference { export interface PresetReference {
@@ -384,7 +384,7 @@ function scanHtmlDirectory(scanDir: string): { skins: PresetSkinDef[]; mediaElem
return { skins, mediaElement }; return { skins, mediaElement };
} }
function scanReactDirectory(scanDir: string, barrelPath: string): PresetSkinDef[] { function scanReactDirectory(scanDir: string, barrelPath: string, presetName: string): PresetSkinDef[] {
const skins: PresetSkinDef[] = []; const skins: PresetSkinDef[] = [];
if (!fs.existsSync(scanDir)) return skins; if (!fs.existsSync(scanDir)) return skins;
@@ -397,11 +397,16 @@ function scanReactDirectory(scanDir: string, barrelPath: string): PresetSkinDef[
for (const file of files) { for (const file of files) {
const filePath = path.join(scanDir, file); const filePath = path.join(scanDir, file);
const exports = extractValueExports(filePath); const exports = extractValueExports(filePath);
const basename = path.basename(file, path.extname(file));
const cssFile = path.join(scanDir, `${basename}.css`);
const cssImport = fs.existsSync(cssFile) ? `@videojs/react/${presetName}/${basename}.css` : undefined;
for (const name of exports) { for (const name of exports) {
if (isFeatureBundle(name)) continue; if (isFeatureBundle(name)) continue;
if (isReactSkin(name)) { if (isReactSkin(name)) {
skins.push({ name }); const skin: PresetSkinDef = { name };
if (cssImport) skin.cssImport = cssImport;
skins.push(skin);
} }
} }
} }
@@ -426,7 +431,7 @@ function buildPresetReference(preset: PresetInfo, featureBundleMap: Map<string,
// Scan React directory for skins, read barrel for media element // Scan React directory for skins, read barrel for media element
const reactSkins = preset.react const reactSkins = preset.react
? scanReactDirectory(preset.react.scanDir, preset.react.barrelPath) ? scanReactDirectory(preset.react.scanDir, preset.react.barrelPath, preset.name)
: ([] as PresetSkinDef[]); : ([] as PresetSkinDef[]);
const reactMediaElement = preset.react ? findReactMediaElement(preset.react.barrelPath) : undefined; const reactMediaElement = preset.react ? findReactMediaElement(preset.react.barrelPath) : undefined;
@@ -940,9 +940,14 @@ describe('Preset pipeline (end-to-end)', () => {
expect(ref.html.mediaElement).toBeUndefined(); expect(ref.html.mediaElement).toBeUndefined();
}); });
it('detects React skins', () => { it('detects React skins with CSS imports', () => {
const skins = findPreset('video')!.reference.react.skins; const skins = findPreset('video')!.reference.react.skins;
expect(skins).toEqual(expect.arrayContaining([{ name: 'VideoSkin' }, { name: 'MinimalVideoSkin' }])); expect(skins).toEqual(
expect.arrayContaining([
{ name: 'VideoSkin', cssImport: '@videojs/react/video/skin.css' },
{ name: 'MinimalVideoSkin', cssImport: '@videojs/react/video/minimal-skin.css' },
])
);
}); });
it('excludes React tailwind skins', () => { it('excludes React tailwind skins', () => {
@@ -981,9 +986,9 @@ describe('Preset pipeline (end-to-end)', () => {
expect(ref.html.mediaElement).toBeUndefined(); expect(ref.html.mediaElement).toBeUndefined();
}); });
it('detects single React skin', () => { it('detects single React skin with CSS import', () => {
const skins = findPreset('audio')!.reference.react.skins; const skins = findPreset('audio')!.reference.react.skins;
expect(skins).toEqual([{ name: 'AudioSkin' }]); expect(skins).toEqual([{ name: 'AudioSkin', cssImport: '@videojs/react/audio/skin.css' }]);
}); });
it('detects React media element', () => { it('detects React media element', () => {
@@ -1022,7 +1027,7 @@ describe('Preset pipeline (end-to-end)', () => {
expect(skinNames).not.toContain('BackgroundVideoPlayerElement'); expect(skinNames).not.toContain('BackgroundVideoPlayerElement');
}); });
it('detects React skin', () => { it('detects React skin without CSS import when no CSS file exists', () => {
const skins = findPreset('background')!.reference.react.skins; const skins = findPreset('background')!.reference.react.skins;
expect(skins).toEqual([{ name: 'BackgroundVideoSkin' }]); expect(skins).toEqual([{ name: 'BackgroundVideoSkin' }]);
}); });
@@ -142,17 +142,16 @@ const listFormat = new Intl.ListFormat('en', { style: 'long', type: 'unit' });
<dd> <dd>
<FrameworkCase frameworks={["react"]}> <FrameworkCase frameworks={["react"]}>
{preset.react.skins.length > 0 {preset.react.skins.length > 0
? listFormat ? preset.react.skins.map((skin) => (
.formatToParts( <div class="mb-2 last:mb-0">
preset.react.skins.map((s) => s.name), <MarkdownCode class="inline-block whitespace-nowrap">{`<${skin.name}>`}</MarkdownCode>
) {skin.cssImport && (
.map((part) => <div class="mt-0.5">
part.type === "element" ? ( <MarkdownCode class="text-code inline-block whitespace-nowrap">{`import '${skin.cssImport}';`}</MarkdownCode>
<MarkdownCode class="inline-block whitespace-nowrap">{`<${part.value}>`}</MarkdownCode> </div>
) : ( )}
<span>{part.value}</span> </div>
), ))
)
: "–"} : "–"}
</FrameworkCase> </FrameworkCase>
<FrameworkCase frameworks={["html"]}> <FrameworkCase frameworks={["html"]}>
+1 -1
View File
@@ -105,7 +105,7 @@ There are currently two options for styling:
<FrameworkCase frameworks={["react"]}> <FrameworkCase frameworks={["react"]}>
- Vanilla CSS where you import the stylesheet in your app. This is the default. - Vanilla CSS — import the stylesheet listed for each skin in the [preset table](#skins-features-and-presets). This is the default.
- Tailwind where you [eject](../how-to/customize-skins#ejecting) the skin and use Tailwind classnames in your app. - Tailwind where you [eject](../how-to/customize-skins#ejecting) the skin and use Tailwind classnames in your app.
</FrameworkCase> </FrameworkCase>
+1
View File
@@ -6,6 +6,7 @@ import { z } from 'astro/zod';
export const PresetSkinDefSchema = z.object({ export const PresetSkinDefSchema = z.object({
name: z.string(), name: z.string(),
tagName: z.string().optional(), tagName: z.string().optional(),
cssImport: z.string().optional(),
}); });
export const PresetReferenceSchema = z.object({ export const PresetReferenceSchema = z.object({