Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0a6d0fc

Browse files
RobbertYolijn
authored andcommittedMay 7, 2025·
feat: add YouTubeVideo component for React
1 parent b6cd5bb commit 0a6d0fc

26 files changed

+658
-20
lines changed
 

‎.changeset/like-and-subscribe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@utrecht/component-library-css": minor
3+
---
4+
5+
Add YouTube video CSS component.

‎.changeset/plenty-fans-boil.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@utrecht/youtube-video-react": major
3+
---
4+
5+
Add YouTube video React component.

‎components/youtube-video/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
],
1313
"main": "dist/index.css",
1414
"scripts": {
15-
"build": "rollup -c ../rollup.config.mjs",
15+
"build": "build-css-package",
1616
"clean": "rimraf dist"
1717
},
1818
"devDependencies": {
19-
"rollup": "4.18.0"
19+
"@utrecht/build-utils-css": "workspace:*"
2020
},
2121
"keywords": [
2222
"nl-design-system"

‎components/youtube-video/src/_mixin.scss

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
* Copyright (c) 2021-2025 Gemeente Utrecht
55
*/
66

7-
/* stylelint-disable-next-line block-no-empty */
87
@mixin utrecht-youtube-video {
9-
}
10-
11-
@mixin utrecht-youtube-video--responsive {
12-
block-size: auto;
13-
max-inline-size: 100%;
8+
aspect-ratio: 16 / 9;
149
}
1510

1611
@mixin utrecht-youtube-video--html-iframe {
1712
border-width: 0;
13+
14+
&:not([width]) {
15+
/* stylelint-disable-next-line property-disallowed-list */
16+
width: 100%;
17+
}
18+
19+
&:not([height]) {
20+
/* stylelint-disable-next-line property-disallowed-list */
21+
height: auto;
22+
}
1823
}

‎components/youtube-video/src/index.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
@include utrecht-youtube-video;
1111
}
1212

13-
.utrecht-youtube-video--responsive {
14-
@include utrecht-youtube-video--responsive;
15-
}
16-
1713
.utrecht-youtube-video--html-iframe {
1814
@include utrecht-youtube-video--html-iframe;
1915
}

‎packages/component-library-css/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@
114114
"@utrecht/top-task-link-css": "workspace:*",
115115
"@utrecht/top-task-nav-css": "workspace:*",
116116
"@utrecht/unordered-list-css": "workspace:*",
117-
"@utrecht/url-data-css": "workspace:*"
117+
"@utrecht/url-data-css": "workspace:*",
118+
"@utrecht/youtube-video-css": "workspace:*"
118119
},
119120
"devDependencies": {
120121
"postcss": "8.4.38",

‎packages/component-library-css/src/index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,4 @@
111111
@import "~@utrecht/top-task-nav-css/src/index";
112112
@import "~@utrecht/unordered-list-css/src/index";
113113
@import "~@utrecht/url-data-css/src/index";
114+
@import "~@utrecht/youtube-video-css/src/index";
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"env": {
3+
"jest/globals": true
4+
},
5+
"rules": {
6+
"react/react-in-jsx-scope": "off"
7+
}
8+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# @utrecht/youtube-video-react
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# YouTube Video component
2+
3+
De component ondersteunt alle URL parameters van de YouTube player, als React component property. Lees de documentatie over alle parameters bij de [officiële YouTube Player parameters documentatie](https://developers.google.com/youtube/player_parameters#Parameters).
4+
5+
Je kunt URLs gebruiken van de volgende domeinnamen: `www.youtube.com` of `www.youtube-nocookie.com`.
6+
7+
De API is up-to-date met de YouTube Player versie van 15 augustus 2023.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
presets: [
3+
'@babel/preset-env',
4+
[
5+
'@babel/preset-react',
6+
{
7+
runtime: 'automatic',
8+
},
9+
],
10+
'@babel/preset-typescript',
11+
],
12+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default {
2+
moduleDirectories: ['node_modules', '<rootDir>/'],
3+
testEnvironment: 'jest-environment-jsdom',
4+
testPathIgnorePatterns: ['/dist/'],
5+
moduleNameMapper: {
6+
'^@utrecht/(.*)$': '<rootDir>/../$1/src/',
7+
},
8+
};
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{
2+
"name": "@utrecht/youtube-video-react",
3+
"version": "0.0.0",
4+
"description": "YouTube component for the Municipality of Utrecht based on the NL Design System architecture",
5+
"keywords": [
6+
"nl-design-system"
7+
],
8+
"homepage": "https://github.com/nl-design-system/utrecht/tree/main/packages/components-react/youtube-video-react#readme",
9+
"bugs": {
10+
"url": "https://github.com/nl-design-system/utrecht/issues"
11+
},
12+
"repository": {
13+
"type": "git+ssh",
14+
"url": "git+https://github.com/nl-design-system/utrecht.git",
15+
"directory": "packages/components-react/youtube-video-react"
16+
},
17+
"license": "EUPL-1.2",
18+
"author": "Community for NL Design System",
19+
"type": "module",
20+
"exports": {
21+
".": {
22+
"types": "./dist/index.d.ts",
23+
"import": "./dist/index.mjs"
24+
},
25+
"./css": {
26+
"types": "./dist/css.d.ts",
27+
"import": "./dist/css.mjs"
28+
},
29+
"./README.md": "./README.md",
30+
"./CHANGELOG.md": "./CHANGELOG.md",
31+
"./dist": {
32+
"types": "./dist/index.d.ts",
33+
"import": "./dist/index.mjs"
34+
},
35+
"./dist/index": {
36+
"types": "./dist/index.d.ts",
37+
"import": "./dist/index.mjs"
38+
},
39+
"./dist/index.mjs": {
40+
"types": "./dist/index.d.ts",
41+
"import": "./dist/index.mjs"
42+
},
43+
"./dist/css": {
44+
"types": "./dist/css.d.ts",
45+
"import": "./dist/css.mjs"
46+
},
47+
"./dist/css.mjs": {
48+
"types": "./dist/css.d.ts",
49+
"import": "./dist/css.mjs"
50+
}
51+
},
52+
"files": [
53+
"dist/",
54+
"src/"
55+
],
56+
"scripts": {
57+
"build": "rollup --config ./rollup.config.mjs",
58+
"clean": "rimraf dist *.tsbuildinfo .rollup.cache coverage",
59+
"init": "init-react-package",
60+
"test": "jest --coverage --verbose",
61+
"typecheck": "tsc --noEmit"
62+
},
63+
"dependencies": {
64+
"@utrecht/youtube-video-css": "workspace:*",
65+
"clsx": "2.1.1"
66+
},
67+
"devDependencies": {
68+
"@testing-library/dom": "8.20.1",
69+
"@testing-library/jest-dom": "6.5.0",
70+
"@testing-library/react": "16.0.1",
71+
"@testing-library/user-event": "14.5.1",
72+
"@types/jest": "29.5.13",
73+
"@types/react": "18.3.3",
74+
"@types/testing-library__jest-dom": "5.14.9",
75+
"@utrecht/build-utils-react": "workspace:*",
76+
"jest": "29.7.0",
77+
"jest-environment-jsdom": "29.7.0",
78+
"react": "18.3.1",
79+
"rollup": "4.23.0",
80+
"typescript": "5.6.2"
81+
},
82+
"peerDependencies": {
83+
"@babel/runtime": "^7.23.6",
84+
"react": "18",
85+
"react-dom": "18"
86+
},
87+
"publishConfig": {
88+
"access": "public"
89+
}
90+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createConfig } from '@utrecht/build-utils-react/src/rollup.mjs';
2+
3+
export default createConfig();
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @license EUPL-1.2
3+
* Copyright (c) 2020-2025 Frameless B.V.
4+
* Copyright (c) 2021-2025 Gemeente Utrecht
5+
*/
6+
7+
import css from '@utrecht/youtube-video-css/dist/index.mjs';
8+
import { insertStyle } from './insert-style';
9+
insertStyle(css);
10+
11+
export type { YouTubeVideoProps } from './index';
12+
export { YouTubeVideo } from './index';
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* @license EUPL-1.2
3+
* Copyright (c) 2020-2025 Frameless B.V.
4+
* Copyright (c) 2021-2025 Gemeente Utrecht
5+
*/
6+
7+
import { render } from '@testing-library/react';
8+
import React from 'react';
9+
import { YouTubeVideo } from './index';
10+
import '@testing-library/jest-dom';
11+
12+
describe('Embedded YouTube video', () => {
13+
it('should render a design system BEM class name: utrecht-youtube-video', () => {
14+
const { container } = render(<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" />);
15+
const iframe = container.querySelector('iframe');
16+
expect(iframe).toHaveClass('utrecht-youtube-video');
17+
});
18+
19+
it('must not render any iframe URL, only youtube.com', () => {
20+
const { container } = render(<YouTubeVideo src="https://example.com/" />);
21+
const iframe = container.querySelector('iframe');
22+
expect(iframe).not.toBeInTheDocument();
23+
});
24+
25+
it('must not render an iframe for invalid URLs', () => {
26+
const { container } = render(<YouTubeVideo src="\uFFFD" />);
27+
const iframe = container.querySelector('iframe');
28+
expect(iframe).not.toBeInTheDocument();
29+
});
30+
31+
it('should render the YouTubeVideo component as iframe', () => {
32+
const { container } = render(<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" />);
33+
const iframe = container.querySelector('iframe');
34+
expect(iframe).toBeInTheDocument();
35+
});
36+
37+
it('should disable keyboard controls by default (WCAG 2.1.4)', () => {
38+
const { container } = render(<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" />);
39+
const iframe = container.querySelector('iframe');
40+
expect(iframe?.getAttribute('src')).toContain('disablekb=1');
41+
});
42+
43+
it('should set render width and height', () => {
44+
const { container } = render(
45+
<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" height="320" width="480" />,
46+
);
47+
const iframe = container.querySelector('iframe');
48+
expect(iframe).toBeInTheDocument();
49+
expect(iframe).toHaveAttribute('height', '320');
50+
expect(iframe).toHaveAttribute('width', '480');
51+
});
52+
53+
// Unfortunately React doesn't support this
54+
// Bug report says "Closed" and "fixed", but it still does not work in React 18.3.1
55+
// https://github.com/facebook/react/issues/21098
56+
it.skip('should set render the aspect-ratio CSS to support responsive layouts', () => {
57+
const { container } = render(
58+
<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" height="320" width="480" />,
59+
);
60+
const iframe = container.querySelector('iframe');
61+
expect(iframe).toHaveStyle('aspect-ratio: 480 / 320');
62+
});
63+
64+
it('should add the YouTube parameters as URL param in the `src` attribute', () => {
65+
const title = 'Rick Astley | Never Gonna Give You Up (Official Music Video)';
66+
const params = {
67+
autoplay: '1',
68+
cc_lang_pref: 'nl',
69+
cc_load_policy: '1',
70+
color: 'red',
71+
controls: '0',
72+
disablekb: '1',
73+
enablejsapi: '1',
74+
end: '42',
75+
fs: '0',
76+
hl: 'fr',
77+
iv_load_policy: '3',
78+
list: 'GFq6wH5JR2A',
79+
listType: 'playlist',
80+
loop: '1',
81+
origin: 'https://example.com',
82+
playlist: 'GFq6wH5JR2A',
83+
playsinline: '1',
84+
rel: '0',
85+
start: '42',
86+
widget_referrer: 'https://example.com',
87+
};
88+
const { container } = render(
89+
<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" title={title} {...params} />,
90+
);
91+
const iframe = container.querySelector('iframe');
92+
93+
Object.keys(params).forEach((key) => {
94+
expect(iframe?.getAttribute('src')).toContain(key);
95+
});
96+
97+
Object.keys(params).forEach((key) => {
98+
expect(iframe).not.toHaveAttribute(key);
99+
});
100+
});
101+
102+
it('should not render a title attribute, to avoid a tooltip', () => {
103+
const title = 'Rick Astley | Never Gonna Give You Up (Official Music Video)';
104+
const { container } = render(<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" title={title} />);
105+
const iframe = container.querySelector('iframe');
106+
expect(iframe).not.toHaveAttribute('title');
107+
});
108+
109+
it('should render the title in aria-label', () => {
110+
const title = 'Rick Astley | Never Gonna Give You Up (Official Music Video)';
111+
const { container } = render(<YouTubeVideo src="https://www.youtube.com/watch?v=GFq6wH5JR2A" title={title} />);
112+
const iframe = container.querySelector('iframe');
113+
expect(iframe).toHaveAttribute('aria-label', title);
114+
});
115+
});
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/**
2+
* @license EUPL-1.2
3+
* Copyright (c) 2020-2025 Frameless B.V.
4+
* Copyright (c) 2021-2025 Gemeente Utrecht
5+
*/
6+
7+
import clsx from 'clsx';
8+
import { forwardRef } from 'react';
9+
import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react';
10+
import { isYouTubeURL, stringSort } from './util';
11+
12+
/**
13+
* See: https://developers.google.com/youtube/player_parameters#Parameters
14+
*/
15+
export interface YouTubeVideoProps extends HTMLAttributes<HTMLIFrameElement> {
16+
src: string;
17+
height?: string;
18+
width?: string;
19+
autoplay?: string;
20+
cc_lang_pref?: string;
21+
cc_load_policy?: string;
22+
color?: string;
23+
controls?: string;
24+
disablekb?: string;
25+
enablejsapi?: string;
26+
end?: string;
27+
fs?: string;
28+
hl?: string;
29+
iv_load_policy?: string;
30+
list?: string;
31+
listType?: string;
32+
loop?: string;
33+
origin?: string;
34+
playlist?: string;
35+
playsinline?: string;
36+
rel?: string;
37+
start?: string;
38+
widget_referrer?: string;
39+
}
40+
41+
export const YouTubeVideo = forwardRef(
42+
(
43+
{
44+
children,
45+
autoplay,
46+
cc_lang_pref,
47+
cc_load_policy,
48+
color,
49+
controls,
50+
disablekb = '1',
51+
enablejsapi,
52+
end,
53+
fs,
54+
hl,
55+
iv_load_policy,
56+
list,
57+
listType,
58+
loop,
59+
origin,
60+
playlist,
61+
playsinline,
62+
rel,
63+
start,
64+
widget_referrer,
65+
src,
66+
title,
67+
width,
68+
height,
69+
...restProps
70+
}: PropsWithChildren<YouTubeVideoProps>,
71+
ref: ForwardedRef<HTMLIFrameElement>,
72+
) => {
73+
if (!isYouTubeURL(src)) {
74+
return null;
75+
}
76+
77+
const props: { [index: string]: string | undefined } = {
78+
autoplay,
79+
cc_lang_pref,
80+
cc_load_policy,
81+
color,
82+
controls,
83+
disablekb,
84+
enablejsapi,
85+
end,
86+
fs,
87+
hl,
88+
iv_load_policy,
89+
list,
90+
listType,
91+
loop,
92+
origin,
93+
playlist,
94+
playsinline,
95+
rel,
96+
start,
97+
widget_referrer,
98+
};
99+
100+
const srcURL = new URL(src);
101+
// Sort parameters for predictable results, in unit tests for example
102+
Object.entries(props)
103+
.filter(([, value]) => typeof value === 'string' && !!value)
104+
.sort(([a], [b]) => stringSort(a, b))
105+
.forEach(([key, value]) => {
106+
srcURL.searchParams.set(key, value || '');
107+
});
108+
let style;
109+
if (width && height) {
110+
style = { aspectRatio: parseFloat(width) / parseFloat(height) };
111+
}
112+
113+
return (
114+
<iframe
115+
className={clsx('utrecht-youtube-video', 'utrecht-youtube-video--html-iframe')}
116+
src={srcURL.toString()}
117+
aria-label={title}
118+
width={width}
119+
height={height}
120+
style={style}
121+
{...restProps}
122+
ref={ref}
123+
/>
124+
);
125+
},
126+
);
127+
128+
YouTubeVideo.displayName = 'YouTubeVideo';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const insertStyle = function (css: string) {
2+
if (typeof document !== 'undefined') {
3+
var head = document.head || document.getElementsByTagName('head')[0];
4+
var style = document.createElement('style');
5+
style.appendChild(document.createTextNode(css));
6+
head.appendChild(style);
7+
}
8+
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @license EUPL-1.2
3+
* Copyright (c) 2020-2025 Frameless B.V.
4+
* Copyright (c) 2021-2025 Gemeente Utrecht
5+
*/
6+
import { isYouTubeURL } from './util';
7+
8+
describe('Detect YouTube URL', () => {
9+
const youtube = [
10+
'HTTP://YOUTUBE.COM',
11+
'http://youtube.com',
12+
'http://www.youtube.com',
13+
'http://youtube.com:80',
14+
'https://youtube.com',
15+
'https://www.youtube.com',
16+
'https://youtube.com:443',
17+
'https://www.youtube.com:8080',
18+
'https://youtube-nocookie.com/',
19+
];
20+
const notYoutube = [
21+
'https://example.com',
22+
'https://youtube',
23+
'youtube://GFq6wH5JR2A',
24+
'/www.youtube.com',
25+
'youtube.com',
26+
];
27+
28+
describe('official YouTube domains', () => {
29+
youtube.forEach((url) => {
30+
it(`should accept: ${url}`, () => {
31+
expect(isYouTubeURL(url)).toBe(true);
32+
});
33+
});
34+
});
35+
describe('other domains', () => {
36+
notYoutube.forEach((url) => {
37+
it(`should reject: ${url}`, () => {
38+
expect(isYouTubeURL(url)).toBe(false);
39+
});
40+
});
41+
});
42+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @license EUPL-1.2
3+
* Copyright (c) 2020-2025 Frameless B.V.
4+
* Copyright (c) 2021-2025 Gemeente Utrecht
5+
*/
6+
7+
export const stringSort = (a: string, b: string) => (a === b ? 0 : a > b ? 1 : -1);
8+
9+
export const isYouTubeURL = (src: string) => {
10+
let srcURL;
11+
try {
12+
srcURL = new URL(src);
13+
} catch (e) {
14+
//
15+
}
16+
return !!srcURL && /(^|\.)youtube(-nocookie)?.com$/i.test(srcURL.hostname);
17+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"composite": true
5+
}
6+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../tsconfig.base.json",
3+
"include": ["src/**/*.ts", "src/**/*.tsx"],
4+
"exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"],
5+
"compilerOptions": {
6+
"outDir": "dist",
7+
"rootDir": "src"
8+
}
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"include": ["src/**/*.ts", "src/**/*.tsx"],
4+
"exclude": ["node_modules", "dist"],
5+
"compilerOptions": {
6+
"noEmit": true
7+
}
8+
}

‎packages/storybook-react/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@
151151
"@utrecht/unordered-list-css": "workspace:*",
152152
"@utrecht/vega-visualization-css": "workspace:*",
153153
"@utrecht/web-component-library-react": "workspace:*",
154+
"@utrecht/youtube-video-css": "workspace:*",
155+
"@utrecht/youtube-video-react": "workspace:*",
154156
"@vitejs/plugin-react": "3.1.0",
155157
"babel-loader": "9.1.3",
156158
"clsx": "2.1.1",
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { Meta, StoryObj } from '@storybook/react';
2+
import tokens from '@utrecht/design-tokens/dist/list.mjs';
3+
import tokensDefinition from '@utrecht/youtube-video-css/dist/tokens.mjs';
4+
import readme from '@utrecht/youtube-video-react/README.md?raw';
5+
import { YouTubeVideo } from '@utrecht/youtube-video-react/dist/css.mjs';
6+
import { designTokenStory } from './util.js';
7+
8+
const meta = {
9+
title: 'React Component/YouTube Video',
10+
id: 'react-youtube-video',
11+
component: YouTubeVideo,
12+
args: {},
13+
argTypes: {
14+
src: { description: '', control: 'text', defaultValue: { summary: '', required: true } },
15+
height: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
16+
width: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
17+
autoplay: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
18+
cc_lang_pref: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
19+
cc_load_policy: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
20+
color: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
21+
controls: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
22+
disablekb: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
23+
enablejsapi: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
24+
end: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
25+
fs: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
26+
hl: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
27+
iv_load_policy: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
28+
list: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
29+
listType: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
30+
loop: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
31+
origin: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
32+
playlist: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
33+
playsinline: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
34+
rel: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
35+
start: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
36+
widget_referrer: { description: '', control: 'text', defaultValue: { summary: '', required: false } },
37+
},
38+
parameters: {
39+
tokensPrefix: 'utrecht-youtube-video',
40+
tokens,
41+
tokensDefinition,
42+
docs: {
43+
description: {
44+
component: readme,
45+
},
46+
},
47+
},
48+
} satisfies Meta<typeof YouTubeVideo>;
49+
50+
export default meta;
51+
52+
type Story = StoryObj<typeof meta>;
53+
export const Default: Story = {
54+
args: {
55+
src: 'https://www.youtube.com/embed/WgA8flJjCZ0',
56+
title: 'Onderzoek taalswitch. Webcomponenten voor portalen. Alt-teksten richtlijnen',
57+
},
58+
};
59+
60+
export const Width: Story = {
61+
name: 'Width',
62+
args: {
63+
...Default.args,
64+
width: 250,
65+
},
66+
};
67+
68+
export const Height: Story = {
69+
name: 'Height',
70+
args: {
71+
...Default.args,
72+
height: 250,
73+
},
74+
};
75+
76+
export const WidthHeight: Story = {
77+
name: 'Width and height',
78+
args: {
79+
...Default.args,
80+
width: 250,
81+
height: 250,
82+
},
83+
};
84+
85+
export const DesignTokens = designTokenStory(meta);

‎pnpm-lock.yaml

Lines changed: 71 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.