@nysds/nys-video 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ export * from "./nys-video";
@@ -0,0 +1,71 @@
1
+ import { LitElement } from "lit";
2
+ declare global {
3
+ interface Window {
4
+ YT: any;
5
+ onYouTubeIframeAPIReady: () => void;
6
+ }
7
+ }
8
+ export declare class NysVideo extends LitElement {
9
+ static styles: import("lit").CSSResult;
10
+ /** Full YouTube URL — required. Component will not render if invalid. */
11
+ id: string;
12
+ /** Title text for the thumbnail of the video */
13
+ titleText: string;
14
+ /** Full YouTube URL — required. Component will not render if invalid. */
15
+ videourl: string;
16
+ /**
17
+ * Largest size for the video player.
18
+ * If not set, size is determined automatically by viewport width.
19
+ */
20
+ size: "full" | "md" | "sm" | "";
21
+ loading: "lazy" | "eager";
22
+ /** Time in seconds where playback begins. **/
23
+ starttime: number;
24
+ /**
25
+ * Custom thumbnail image path.
26
+ * Falls back to YouTube's auto-generated thumbnail if not provided.
27
+ */
28
+ thumbnail: string | null;
29
+ /** Triggers autoplay when the iframe loads */
30
+ autoplay: boolean;
31
+ /** Prevents the video from being played */
32
+ disabled: boolean;
33
+ /** Tracks whether the user has clicked to load the player */
34
+ private _playerActive;
35
+ /** Screen reader announcement text */
36
+ private _announcement;
37
+ /** Tracks whether an ad is currently playing to suppress false "Video is playing" announcements */
38
+ private _adPlaying;
39
+ constructor();
40
+ connectedCallback(): void;
41
+ disconnectedCallback(): void;
42
+ /**
43
+ * Functions
44
+ * --------------------------------------------------------------------------
45
+ */
46
+ private _isValidYouTubeUrl;
47
+ private _getVideoId;
48
+ private _getThumbnailUrl;
49
+ private _getEmbedUrl;
50
+ /**
51
+ * Because I need to know if Youtube ADs are playing, I need to call YT's API.
52
+ * Hence, the YT API setup below. The VO has 2 types of announcements:
53
+ * - "Advertisement is playing"
54
+ * - "Video is playing"
55
+ *
56
+ * YT IFrame Player API: https://developers.google.com/youtube/iframe_api_reference
57
+ */
58
+ private _announceVideoVO;
59
+ /**
60
+ * Event Handlers
61
+ * --------------------------------------------------------------------------
62
+ */
63
+ private _handleThumbnailClick;
64
+ /**
65
+ * Render Helpers
66
+ * --------------------------------------------------------------------------
67
+ */
68
+ private _renderAnnouncer;
69
+ private _renderPlayIcon;
70
+ render(): import("lit-html").TemplateResult<1>;
71
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,240 @@
1
+ import { LitElement as u, unsafeCSS as p, html as s } from "lit";
2
+ import { property as n, state as c } from "lit/decorators.js";
3
+ /*!
4
+ * █▄ █ █ █ █▀▀▀█ █▀▀▄ █▀▀▀█
5
+ * █ █ █ █▄▄▄█ ▀▀▀▄▄ █ █ ▀▀▀▄▄
6
+ * █ ▀█ █ █▄▄▄█ █▄▄▀ █▄▄▄█
7
+ *
8
+ * Video Component v1.15.0
9
+ * Part of the New York State Design System
10
+ * Repository: https://github.com/its-hcd/nysds
11
+ * License: MIT
12
+ */
13
+ const h = '@charset "UTF-8";:host{--_nys-video-width: fit-content;--_nys-video-height: var(--nys-size-600, 48px);--_nys-video-radius: var(--nys-radius-lg, 8px);--_nys-video-padding: var(--nys-space-100, 8px);--_nys-video-gap: var(--nys-space-100, 8px);--_nys-video-font-size: var(--nys-font-size-ui-md, 16px);--_nys-video-font-weight: var(--nys-font-weight-semibold, 600);--_nys-video-line-height: var(--nys-font-lineheight-ui-md, 24px);--_nys-video-font-family: var( --nys-font-family-ui, var( --nys-font-family-sans, "Proxima Nova", "Helvetica Neue", "Helvetica", "Arial", sans-serif ) );--_nys-video-background-color--play-button: var( --nys-color-black-transparent-600, rgba(27, 27, 27, .6) );--_nys-video-outline-color--play-button: var(--nys-color-focus, #004dd1);--_nys-video-svg-color--play-button: var( --nys-color-white-transparent-400, rgba(255, 255, 255, .4) );--_nys-video-color--title-text: var(--nys-color-text-reverse, #ffffff);--_nys-video-background-color--title-text: var( --nys-color-ink, var(--nys-color-neutral-900, #1b1b1b) );--_nys-video-padding--title-text: var(--nys-space-250, 20px)}.nys-video--full{width:100%}.nys-video--md{width:100%;max-width:675px;min-width:440px}.nys-video--sm{width:100%;min-width:320px;max-width:439px}:host([size=full]) .nys-video .nys-video__title-text{position:absolute;bottom:0;--_nys-video-background-color--title-text: var( --nys-color-black-transparent-900, rgba(27, 27, 27, .9) )}@media(min-width:480px){.nys-video:not(.nys-video--sm):not(.nys-video--md) .nys-video__title-text{position:absolute;bottom:0;--_nys-video-background-color--title-text: var( --nys-color-black-transparent-900, rgba(27, 27, 27, .9) )}}.nys-video{border-radius:var(--_nys-video-radius);display:flex;flex-direction:column;position:relative;overflow:hidden}.nys-video .nys-video__ratio-box{aspect-ratio:16/9;position:relative}.nys-video .nys-video__ratio-box iframe,.nys-video .nys-video__ratio-box .nys-video__thumbnail{position:absolute;top:0;left:0;width:100%;height:100%;display:block;border:none}.nys-video .nys-video__ratio-box .nys-video__thumbnail{cursor:pointer;padding:0;background-color:none}.nys-video .nys-video__ratio-box .nys-video__thumbnail img{width:100%;height:100%;object-fit:cover}.nys-video .nys-video__ratio-box .nys-video__thumbnail .nys-video__play-icon{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:96px;height:96px;background-color:var(--_nys-video-background-color--play-button);border:none;border-radius:50%;display:flex;align-items:center;justify-content:center;pointer-events:none}.nys-video .nys-video__ratio-box .nys-video__thumbnail .nys-video__play-icon svg{display:flex;margin-left:10px}.nys-video .nys-video__ratio-box .nys-video__thumbnail .nys-video__play-icon:focus-visible{outline:3.5px solid var(--_nys-video-outline-color--play-button);outline-offset:1px}.nys-video .nys-video__ratio-box .nys-video__thumbnail:hover .nys-video__play-icon{--_nys-video-background-color--play-button: var( --nys-color-black-transparent-700, rgba(27, 27, 27, .7) )}.nys-video .nys-video__ratio-box .nys-video__thumbnail:active .nys-video__play-icon{--_nys-video-background-color--play-button: var( --nys-color-black-transparent-800, rgba(27, 27, 27, .8) )}.nys-video--disabled .nys-video__ratio-box{cursor:not-allowed}.nys-video--disabled .nys-video__ratio-box .nys-video__thumbnail{pointer-events:none}.nys-video--disabled .nys-video__ratio-box .nys-video__thumbnail .nys-video__play-icon{--_nys-video-background-color--play-button: var( --nys-color-black-transparent-200, rgba(27, 27, 27, .2) )}.nys-video--disabled .nys-video__ratio-box .nys-video__thumbnail .nys-video__play-icon svg{fill:var(--_nys-video-svg-color--play-button)}.nys-video .nys-video__title-text{width:100%;padding:var(--_nys-video-padding--title-text);background-color:var(--_nys-video-background-color--title-text);box-sizing:border-box;color:var(--_nys-video-color--title-text);display:flex;justify-content:start;font-family:var(--_nys-video-font-family);font-size:var(--_nys-video-font-size);font-weight:var(--_nys-video-font-weight);line-height:var(--_nys-video-line-height)}.nys-video .nys-video__title-text p{margin:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;border:0}';
14
+ var _ = Object.defineProperty, o = (y, e, t, r) => {
15
+ for (var a = void 0, d = y.length - 1, v; d >= 0; d--)
16
+ (v = y[d]) && (a = v(e, t, a) || a);
17
+ return a && _(e, t, a), a;
18
+ };
19
+ let b = 0;
20
+ const l = class l extends u {
21
+ // Lifecycle Methods
22
+ constructor() {
23
+ super(), this.id = "", this.titleText = "", this.videourl = "", this.size = "", this.loading = "lazy", this.starttime = 0, this.thumbnail = null, this.autoplay = !1, this.disabled = !1, this._playerActive = !1, this._announcement = "", this._adPlaying = !1;
24
+ }
25
+ // Generate a unique ID if one is not provided
26
+ connectedCallback() {
27
+ super.connectedCallback(), this.id || (this.id = `nys-video-${Date.now()}-${b++}`), this.autoplay && this._announceVideoVO();
28
+ }
29
+ disconnectedCallback() {
30
+ super.disconnectedCallback();
31
+ }
32
+ /**
33
+ * Functions
34
+ * --------------------------------------------------------------------------
35
+ */
36
+ _isValidYouTubeUrl() {
37
+ return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(
38
+ this.videourl
39
+ );
40
+ }
41
+ _getVideoId() {
42
+ const e = /(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([^?&]+)/, t = this.videourl.match(e);
43
+ return t ? t[1] : null;
44
+ }
45
+ _getThumbnailUrl() {
46
+ return this.thumbnail ? this.thumbnail : `https://img.youtube.com/vi/${this._getVideoId()}/maxresdefault.jpg`;
47
+ }
48
+ _getEmbedUrl() {
49
+ const e = this._getVideoId();
50
+ if (!e) return null;
51
+ const t = new URLSearchParams({
52
+ autoplay: "1",
53
+ enablejsapi: "1",
54
+ ...this.autoplay && { mute: "1" },
55
+ ...this.starttime > 0 && { start: String(this.starttime) }
56
+ });
57
+ return `https://www.youtube.com/embed/${e}?${t}`;
58
+ }
59
+ /**
60
+ * Because I need to know if Youtube ADs are playing, I need to call YT's API.
61
+ * Hence, the YT API setup below. The VO has 2 types of announcements:
62
+ * - "Advertisement is playing"
63
+ * - "Video is playing"
64
+ *
65
+ * YT IFrame Player API: https://developers.google.com/youtube/iframe_api_reference
66
+ */
67
+ _announceVideoVO() {
68
+ const e = () => {
69
+ this.updateComplete.then(() => {
70
+ const t = this.shadowRoot?.querySelector("iframe");
71
+ t && new window.YT.Player(t, {
72
+ events: {
73
+ onStateChange: (r) => {
74
+ this._adPlaying || r.data === window.YT.PlayerState.PLAYING && (this._announcement = this.autoplay ? "Video is playing, muted" : "Video is playing", setTimeout(() => this._announcement = "", 1e3));
75
+ },
76
+ // // NOTE: onAdStateChange is not officially documented by YouTube.
77
+ // It is a real event fired by the IFrame player, discovered through community reverse-engineering
78
+ onAdStateChange: (r) => {
79
+ this._adPlaying = r.data === window.YT.PlayerState.PLAYING, this._adPlaying && (this._announcement = "Advertisement is playing", setTimeout(() => this._announcement = "", 1e3));
80
+ }
81
+ }
82
+ });
83
+ });
84
+ };
85
+ if (window.YT?.Player)
86
+ e();
87
+ else {
88
+ if (!document.getElementById("yt-iframe-api")) {
89
+ const t = document.createElement("script");
90
+ t.id = "yt-iframe-api", t.src = "https://www.youtube.com/iframe_api", document.head.appendChild(t);
91
+ }
92
+ window.onYouTubeIframeAPIReady = e;
93
+ }
94
+ }
95
+ /**
96
+ * Event Handlers
97
+ * --------------------------------------------------------------------------
98
+ */
99
+ _handleThumbnailClick() {
100
+ this.disabled || (this._playerActive = !0, this.updateComplete.then(() => {
101
+ const e = this.shadowRoot?.querySelector("iframe");
102
+ e && e.addEventListener(
103
+ "load",
104
+ () => {
105
+ e.focus();
106
+ },
107
+ { once: !0 }
108
+ );
109
+ }), this._announceVideoVO());
110
+ }
111
+ /**
112
+ * Render Helpers
113
+ * --------------------------------------------------------------------------
114
+ */
115
+ _renderAnnouncer() {
116
+ return s`
117
+ <div
118
+ aria-live="assertive"
119
+ aria-atomic="true"
120
+ class="nys-video__announcer sr-only"
121
+ >
122
+ ${this._announcement}
123
+ </div>
124
+ `;
125
+ }
126
+ _renderPlayIcon() {
127
+ return this.disabled ? s`<svg
128
+ aria-hidden="true"
129
+ xmlns="http://www.w3.org/2000/svg"
130
+ width="31"
131
+ height="35"
132
+ viewBox="0 0 31 35"
133
+ fill="none"
134
+ >
135
+ <path
136
+ d="M29.4221 15.7357L2.568 0.231711C1.42656 -0.426849 0 0.396831 0 1.71395V32.7229C0 34.041 1.42656 34.8647 2.568 34.2052L29.4221 18.7012C30.5635 18.0426 30.5635 16.3952 29.4221 15.7357Z"
137
+ fill="white"
138
+ fill-opacity="0.4"
139
+ />
140
+ </svg>` : s`<svg
141
+ aria-hidden="true"
142
+ width="31"
143
+ height="35"
144
+ viewBox="0 0 31 35"
145
+ fill="none"
146
+ xmlns="http://www.w3.org/2000/svg"
147
+ >
148
+ <path
149
+ d="M29.4221 15.7357L2.568 0.231711C1.42656 -0.426849 0 0.396831 0 1.71395V32.7229C0 34.041 1.42656 34.8647 2.568 34.2052L29.4221 18.7012C30.5635 18.0426 30.5635 16.3952 29.4221 15.7357Z"
150
+ fill="white"
151
+ />
152
+ </svg>`;
153
+ }
154
+ render() {
155
+ if (!this._isValidYouTubeUrl())
156
+ return s``;
157
+ const e = this._getEmbedUrl();
158
+ if (!e) return s``;
159
+ const t = this.size || "md";
160
+ return !this._playerActive && !this.autoplay ? s`
161
+ <div
162
+ class="nys-video nys-video--${t} ${this.disabled ? "nys-video--disabled" : ""}"
163
+ >
164
+ ${this._renderAnnouncer()}
165
+ <div class="nys-video__ratio-box">
166
+ <div
167
+ class="nys-video__thumbnail"
168
+ @click=${this._handleThumbnailClick}
169
+ >
170
+ <img src=${this._getThumbnailUrl()} alt="" />
171
+ <button
172
+ class="nys-video__play-icon"
173
+ aria-label="Play ${this.titleText}"
174
+ ?disabled=${this.disabled}
175
+ >
176
+ ${this._renderPlayIcon()}
177
+ </button>
178
+ </div>
179
+ </div>
180
+ ${this.titleText && s`<div class="nys-video__title-text">
181
+ <p>${this.titleText}</p>
182
+ </div>`}
183
+ </div>
184
+ ` : s`<div class="nys-video nys-video--${t}">
185
+ ${this._renderAnnouncer()}
186
+ <div class="nys-video__ratio-box">
187
+ <iframe
188
+ tabindex="0"
189
+ src=${e}
190
+ title=${this.titleText}
191
+ aria-label=${this.titleText}
192
+ loading=${this.loading}
193
+ allowfullscreen
194
+ frameborder="0"
195
+ allow="accelerometer;autoplay;clipboard-write; encrypted-media; gyroscope; picture-in-picture"
196
+ ></iframe>
197
+ </div>
198
+ </div>`;
199
+ }
200
+ };
201
+ l.styles = p(h);
202
+ let i = l;
203
+ o([
204
+ n({ type: String, reflect: !0 })
205
+ ], i.prototype, "id");
206
+ o([
207
+ n({ type: String, reflect: !0 })
208
+ ], i.prototype, "titleText");
209
+ o([
210
+ n({ type: String })
211
+ ], i.prototype, "videourl");
212
+ o([
213
+ n({ type: String, reflect: !0 })
214
+ ], i.prototype, "size");
215
+ o([
216
+ n({ type: String })
217
+ ], i.prototype, "loading");
218
+ o([
219
+ n({ type: Number })
220
+ ], i.prototype, "starttime");
221
+ o([
222
+ n({ type: String })
223
+ ], i.prototype, "thumbnail");
224
+ o([
225
+ n({ type: Boolean })
226
+ ], i.prototype, "autoplay");
227
+ o([
228
+ n({ type: Boolean, reflect: !0 })
229
+ ], i.prototype, "disabled");
230
+ o([
231
+ c()
232
+ ], i.prototype, "_playerActive");
233
+ o([
234
+ c()
235
+ ], i.prototype, "_announcement");
236
+ customElements.get("nys-video") || customElements.define("nys-video", i);
237
+ export {
238
+ i as NysVideo
239
+ };
240
+ //# sourceMappingURL=nys-video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nys-video.js","sources":["../src/nys-video.ts"],"sourcesContent":["import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property, state } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./nys-video.scss?inline\";\n\ndeclare global {\n interface Window {\n YT: any;\n onYouTubeIframeAPIReady: () => void;\n }\n}\n\nlet videoIdCounter = 0;\n\nexport class NysVideo extends LitElement {\n static styles = unsafeCSS(styles);\n\n /** Full YouTube URL — required. Component will not render if invalid. */\n @property({ type: String, reflect: true }) id = \"\";\n\n /** Title text for the thumbnail of the video */\n @property({ type: String, reflect: true }) titleText = \"\";\n\n /** Full YouTube URL — required. Component will not render if invalid. */\n @property({ type: String }) videourl = \"\";\n\n /**\n * Largest size for the video player.\n * If not set, size is determined automatically by viewport width.\n */\n @property({ type: String, reflect: true }) size: \"full\" | \"md\" | \"sm\" | \"\" =\n \"\";\n\n @property({ type: String }) loading: \"lazy\" | \"eager\" = \"lazy\";\n\n // /** Accessible label describing the video content **/\n // @property({ type: String }) ariaLabel = \"\";\n\n /** Time in seconds where playback begins. **/\n @property({ type: Number }) starttime = 0;\n\n /**\n * Custom thumbnail image path.\n * Falls back to YouTube's auto-generated thumbnail if not provided.\n */\n @property({ type: String }) thumbnail: string | null = null;\n\n /** Triggers autoplay when the iframe loads */\n @property({ type: Boolean }) autoplay = false;\n\n /** Prevents the video from being played */\n @property({ type: Boolean, reflect: true }) disabled = false;\n\n /** Tracks whether the user has clicked to load the player */\n @state() private _playerActive = false;\n\n /** Screen reader announcement text */\n @state() private _announcement = \"\";\n\n /** Tracks whether an ad is currently playing to suppress false \"Video is playing\" announcements */\n private _adPlaying = false;\n\n // Lifecycle Methods\n constructor() {\n super();\n }\n\n // Generate a unique ID if one is not provided\n connectedCallback() {\n super.connectedCallback();\n if (!this.id) {\n this.id = `nys-video-${Date.now()}-${videoIdCounter++}`;\n }\n\n if (this.autoplay) {\n this._announceVideoVO();\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n }\n\n /**\n * Functions\n * --------------------------------------------------------------------------\n */\n private _isValidYouTubeUrl(): boolean {\n return /^(https?:\\/\\/)?(www\\.)?(youtube\\.com|youtu\\.be)\\/.+/.test(\n this.videourl,\n );\n }\n\n private _getVideoId() {\n const regExp =\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/|shorts\\/)|youtu\\.be\\/)([^?&]+)/;\n const match = this.videourl.match(regExp);\n return match ? match[1] : null;\n }\n\n private _getThumbnailUrl() {\n if (this.thumbnail) return this.thumbnail;\n const videoId = this._getVideoId();\n return `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`;\n }\n\n private _getEmbedUrl() {\n const videoId = this._getVideoId();\n if (!videoId) return null;\n\n const params = new URLSearchParams({\n autoplay: \"1\",\n enablejsapi: \"1\",\n ...(this.autoplay && { mute: \"1\" }),\n ...(this.starttime > 0 && { start: String(this.starttime) }),\n });\n\n return `https://www.youtube.com/embed/${videoId}?${params}`;\n }\n\n /**\n * Because I need to know if Youtube ADs are playing, I need to call YT's API.\n * Hence, the YT API setup below. The VO has 2 types of announcements:\n * - \"Advertisement is playing\"\n * - \"Video is playing\"\n *\n * YT IFrame Player API: https://developers.google.com/youtube/iframe_api_reference\n */\n private _announceVideoVO() {\n const setup = () => {\n this.updateComplete.then(() => {\n const iframe = this.shadowRoot?.querySelector(\"iframe\");\n if (!iframe) return;\n\n new window.YT.Player(iframe, {\n events: {\n onStateChange: (event: { data: number }) => {\n if (this._adPlaying) return;\n\n if (event.data === window.YT.PlayerState.PLAYING) {\n this._announcement = this.autoplay\n ? \"Video is playing, muted\"\n : \"Video is playing\";\n setTimeout(() => (this._announcement = \"\"), 1000);\n }\n },\n // // NOTE: onAdStateChange is not officially documented by YouTube.\n // It is a real event fired by the IFrame player, discovered through community reverse-engineering\n onAdStateChange: (event: { data: number }) => {\n this._adPlaying = event.data === window.YT.PlayerState.PLAYING;\n\n if (this._adPlaying) {\n this._announcement = \"Advertisement is playing\";\n setTimeout(() => (this._announcement = \"\"), 1000);\n }\n },\n },\n });\n });\n };\n\n // The window.YT is YouTube's API object. If already loaded, run setup immediately.\n if (window.YT?.Player) {\n setup();\n } else {\n if (!document.getElementById(\"yt-iframe-api\")) {\n const script = document.createElement(\"script\");\n script.id = \"yt-iframe-api\";\n script.src = \"https://www.youtube.com/iframe_api\";\n document.head.appendChild(script);\n }\n window.onYouTubeIframeAPIReady = setup;\n }\n }\n\n /**\n * Event Handlers\n * --------------------------------------------------------------------------\n */\n\n private _handleThumbnailClick() {\n if (this.disabled) return;\n this._playerActive = true;\n\n this.updateComplete.then(() => {\n const iframe = this.shadowRoot?.querySelector(\"iframe\");\n if (!iframe) return;\n\n iframe.addEventListener(\n \"load\",\n () => {\n iframe.focus();\n },\n { once: true },\n );\n });\n\n this._announceVideoVO();\n }\n\n /**\n * Render Helpers\n * --------------------------------------------------------------------------\n */\n private _renderAnnouncer() {\n return html`\n <div\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n class=\"nys-video__announcer sr-only\"\n >\n ${this._announcement}\n </div>\n `;\n }\n\n private _renderPlayIcon() {\n return this.disabled\n ? html`<svg\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"31\"\n height=\"35\"\n viewBox=\"0 0 31 35\"\n fill=\"none\"\n >\n <path\n d=\"M29.4221 15.7357L2.568 0.231711C1.42656 -0.426849 0 0.396831 0 1.71395V32.7229C0 34.041 1.42656 34.8647 2.568 34.2052L29.4221 18.7012C30.5635 18.0426 30.5635 16.3952 29.4221 15.7357Z\"\n fill=\"white\"\n fill-opacity=\"0.4\"\n />\n </svg>`\n : html`<svg\n aria-hidden=\"true\"\n width=\"31\"\n height=\"35\"\n viewBox=\"0 0 31 35\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M29.4221 15.7357L2.568 0.231711C1.42656 -0.426849 0 0.396831 0 1.71395V32.7229C0 34.041 1.42656 34.8647 2.568 34.2052L29.4221 18.7012C30.5635 18.0426 30.5635 16.3952 29.4221 15.7357Z\"\n fill=\"white\"\n />\n </svg>`;\n }\n\n render() {\n if (!this._isValidYouTubeUrl()) {\n return html``;\n }\n\n const embedUrl = this._getEmbedUrl();\n if (!embedUrl) return html``;\n\n // Use explicit size if set, otherwise fall back to auto-computed size\n const effectiveSize = this.size || \"md\";\n\n /**\n * Show thumbnail first, unless until user clicks or developer sets \"autoplay\".\n * Then, swap to iframe.\n */\n if (!this._playerActive && !this.autoplay) {\n return html`\n <div\n class=\"nys-video nys-video--${effectiveSize} ${this.disabled\n ? \"nys-video--disabled\"\n : \"\"}\"\n >\n ${this._renderAnnouncer()}\n <div class=\"nys-video__ratio-box\">\n <div\n class=\"nys-video__thumbnail\"\n @click=${this._handleThumbnailClick}\n >\n <img src=${this._getThumbnailUrl()} alt=\"\" />\n <button\n class=\"nys-video__play-icon\"\n aria-label=\"Play ${this.titleText}\"\n ?disabled=${this.disabled}\n >\n ${this._renderPlayIcon()}\n </button>\n </div>\n </div>\n ${this.titleText &&\n html`<div class=\"nys-video__title-text\">\n <p>${this.titleText}</p>\n </div>`}\n </div>\n `;\n }\n\n return html`<div class=\"nys-video nys-video--${effectiveSize}\">\n ${this._renderAnnouncer()}\n <div class=\"nys-video__ratio-box\">\n <iframe\n tabindex=\"0\"\n src=${embedUrl}\n title=${this.titleText}\n aria-label=${this.titleText}\n loading=${this.loading}\n allowfullscreen\n frameborder=\"0\"\n allow=\"accelerometer;autoplay;clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n ></iframe>\n </div>\n </div>`;\n }\n}\n\nif (!customElements.get(\"nys-video\")) {\n customElements.define(\"nys-video\", NysVideo);\n}\n"],"names":["videoIdCounter","_NysVideo","LitElement","regExp","match","videoId","params","setup","iframe","event","script","html","embedUrl","effectiveSize","unsafeCSS","styles","NysVideo","__decorateClass","property","state"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@nysds/nys-video",
3
+ "version": "1.15.0",
4
+ "description": "The Video Player component from the NYS Design System.",
5
+ "module": "dist/nys-video.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/nys-video.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "type": "module",
14
+ "files": [
15
+ "dist/"
16
+ ],
17
+ "scripts": {
18
+ "dev": "tsc --emitDeclarationOnly && vite",
19
+ "build": "tsc --emitDeclarationOnly && vite build",
20
+ "test": "vite build && wtr",
21
+ "build:watch": "tsc --emitDeclarationOnly && vite build --watch",
22
+ "test:watch": "vite build && wtr --watch",
23
+ "lit-analyze": "lit-analyzer '*.ts'"
24
+ },
25
+ "dependencies": {
26
+ },
27
+ "devDependencies": {
28
+ "lit": "^3.3.1",
29
+ "typescript": "^5.9.3",
30
+ "vite": "^7.3.1"
31
+ },
32
+ "keywords": [
33
+ "new-york-state",
34
+ "design-system",
35
+ "web-components",
36
+ "lit",
37
+ "nys",
38
+ "video"
39
+ ],
40
+ "author": "New York State Design System Team",
41
+ "license": "MIT"
42
+ }
43
+