@glitchlab/react-video-player 1.0.2 → 1.1.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.
package/README.md CHANGED
@@ -100,6 +100,7 @@ No client-component wrapper required.
100
100
  | `muted` | `boolean` | `true` | Mute the video. Required for autoplay in most browsers. |
101
101
  | `loop` | `boolean` | `false` | Loop playback. |
102
102
  | `controls` | `boolean` | `false` | Show native browser controls. |
103
+ | `autoPlay` | `boolean` | `false` | Start playback as soon as the source loads. Browsers block sound-on autoplay, so this only fires when `muted` is also `true` (the default). |
103
104
  | `frameMaxWidth` | `{ desktop?: string; mobile?: string }` | `{ desktop: "960px", mobile: "420px" }` | Max width of the player in each device mode. |
104
105
  | `aspectRatio` | `{ desktop?: AspectRatio; mobile?: AspectRatio }` | `{ desktop: "16/9", mobile: "9/16" }` | Aspect ratio per device mode. `AspectRatio` is `` `${number}/${number}` ``. |
105
106
  | `hlsConfig` | `Hls.HlsConfig` | — | Optional hls.js config. Pass a stable reference (e.g. `useMemo`) to avoid HLS rebuilds. |
@@ -107,6 +108,39 @@ No client-component wrapper required.
107
108
 
108
109
  ---
109
110
 
111
+ ## YouTube URLs
112
+
113
+ Pass any common YouTube URL as `src` and the player swaps the `<video>` element for a privacy-enhanced (`youtube-nocookie.com`) embed inside the same styled frame — no extra prop needed:
114
+
115
+ ```tsx
116
+ <ReactVideoPlayer src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" />
117
+ <ReactVideoPlayer src="https://youtu.be/dQw4w9WgXcQ?t=90" autoPlay />
118
+ <ReactVideoPlayer src="https://www.youtube.com/shorts/dQw4w9WgXcQ" />
119
+ ```
120
+
121
+ Recognised forms: `youtube.com/watch?v=ID`, `youtu.be/ID`, `youtube.com/embed/ID`, `youtube.com/shorts/ID`, `youtube.com/live/ID`, `music.youtube.com/watch?v=ID`, and bare 11-character IDs. A `?t=` / `?start=` timestamp in the URL is honored.
122
+
123
+ ### Which props work over YouTube
124
+
125
+ | Prop | YouTube behavior |
126
+ |---------------------------------------|---------------------------------------------------------------------------------------------------|
127
+ | `muted` | ✅ Mutes the embed (`mute=1`). |
128
+ | `loop` | ✅ Loops the single video (`loop=1` + `playlist=<id>`, YouTube's required workaround). |
129
+ | `controls` | ✅ Shows/hides YouTube's controls (`controls=1` / `controls=0`). |
130
+ | `autoPlay` | ✅ Autoplays (`autoplay=1`). YouTube + browsers force muted autoplay, so `mute=1` is set too — even if `muted={false}`. |
131
+ | `showDeviceToggle` / `defaultDevice` | ✅ The desktop/mobile aspect-ratio toggle still works. |
132
+ | `onClose` | ✅ The close button still renders and fires. |
133
+ | `className` / `frameMaxWidth` / `aspectRatio` | ✅ Frame styling, sizing, and aspect ratio all apply. |
134
+ | `hoverPlay` | ❌ **No effect.** Hover-to-play needs programmatic pause, which requires the YouTube IFrame Player API (not loaded). YouTube's own controls handle starting playback. |
135
+ | `tooltipText` | ❌ **No effect.** The tooltip is attached to the centered play-button overlay, which isn't rendered for YouTube. |
136
+ | `poster` | ❌ **No effect.** YouTube shows its own video thumbnail; a custom poster would require an overlay layer. |
137
+ | `children` (`<track>` captions) | ❌ **No effect.** There's no `<video>` element to attach `<track>` to — use YouTube's own caption settings. |
138
+ | `hlsConfig` | ❌ **No effect.** Not an HLS stream. |
139
+
140
+ > If you need `hoverPlay`, a custom poster, or a play-button overlay over a YouTube video, you'd need the YouTube IFrame Player API integrated — that's not in this build (it'd add a ~30 KB external script). Open an issue if it matters for your use case.
141
+
142
+ ---
143
+
110
144
  ## Examples
111
145
 
112
146
  ### Looping background video, no UI chrome
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),s=require("react"),N=require("hls.js");function H(e){var l,o,t="";if(typeof e=="string"||typeof e=="number")t+=e;else if(typeof e=="object")if(Array.isArray(e)){var i=e.length;for(l=0;l<i;l++)e[l]&&(o=H(e[l]))&&(t&&(t+=" "),t+=o)}else for(o in e)e[o]&&(t&&(t+=" "),t+=o);return t}function m(){for(var e,l,o=0,t="",i=arguments.length;o<i;o++)(e=arguments[o])&&(l=H(e))&&(t&&(t+=" "),t+=l);return t}const I=s.forwardRef(({src:e,hlsConfig:l,isHls:o,children:t,...i},v)=>{const C=s.useRef(null),c=s.useRef(null);s.useImperativeHandle(v,()=>C.current);const x=globalThis.window!==void 0&&N.isSupported(),h=!!o||x&&typeof e=="string"&&e.endsWith(".m3u8");return s.useEffect(()=>{if(!e)return;const n=C.current;if(n){for(c.current&&(c.current.destroy(),c.current=null),n.pause(),n.removeAttribute("src");n.firstChild;)n.firstChild.remove();if(h){const a=new N(l);c.current=a,a.attachMedia(n),a.loadSource(e),a.on(N.Events.ERROR,(d,L)=>{L.fatal&&(a.destroy(),c.current=null)})}else n.src=e,n.load();return()=>{for(c.current&&(c.current.destroy(),c.current=null),n.pause(),n.removeAttribute("src");n.firstChild;)n.firstChild.remove();n.load()}}},[e,h,l]),r.jsx("video",{ref:C,...i,children:t})});I.displayName="HLSPlayer";const P="gvp-icon",y=e=>e?`${P} ${e}`:P,O=({className:e})=>r.jsxs("svg",{className:y(e),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[r.jsx("path",{d:"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"}),r.jsx("path",{d:"M11 15H13",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"}),r.jsx("path",{d:"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"}),r.jsx("path",{d:"M7 22H17",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}),U=({className:e})=>r.jsxs("svg",{className:y(e),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[r.jsx("path",{d:"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"}),r.jsx("path",{d:"M11 19H13",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),r.jsx("path",{d:"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2",stroke:"currentColor",strokeWidth:"2",strokeLinejoin:"round"})]}),$=({className:e})=>r.jsx("svg",{className:y(e),width:"14",height:"14",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:r.jsx("path",{d:"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z",fill:"currentColor"})}),J=({className:e})=>r.jsx("svg",{className:y(e),width:"22",height:"22",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:r.jsx("path",{d:"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z",fill:"currentColor"})}),W=({src:e,poster:l,showDeviceToggle:o=!0,defaultDevice:t="desktop",hoverPlay:i=!1,tooltipText:v,onClose:C,className:c="",muted:x=!0,loop:h=!1,controls:n=!1,frameMaxWidth:a,aspectRatio:d,hlsConfig:L,children:R})=>{const g=s.useRef(null),k=s.useRef(null),[p,S]=s.useState(t),[E,f]=s.useState(!1),[B,w]=s.useState(!1),V=s.useMemo(()=>p==="mobile"?(d==null?void 0:d.mobile)??"9/16":(d==null?void 0:d.desktop)??"16/9",[p,d]),Z=s.useMemo(()=>p==="mobile"?(a==null?void 0:a.mobile)??"420px":(a==null?void 0:a.desktop)??"960px",[p,a]),b=s.useCallback(async()=>{const u=g.current;if(u){if(k.current)try{await k.current}catch{}u.pause()}},[]),j=s.useCallback(async()=>{const u=g.current;if(u)try{u.readyState<2&&u.load();const M=u.play();k.current=M,await M,f(!0)}catch{f(!1)}finally{k.current=null}},[]),q=s.useCallback(()=>{i&&j()},[i,j]),D=s.useCallback(()=>{i&&b().then(()=>f(!1))},[i,b]),T=s.useCallback(async()=>{const u=g.current;u&&(u.paused?await j():(await b(),f(!1)))},[j,b]);return r.jsxs("div",{className:m("gvp-root",c),style:{width:Z,aspectRatio:V},onMouseEnter:()=>{w(!0),q()},onMouseLeave:()=>{w(!1),D()},children:[r.jsx(I,{ref:g,src:e,poster:l,muted:x,loop:h,playsInline:!0,preload:"metadata",controls:n,hlsConfig:L,className:"gvp-video",onPlay:()=>f(!0),onPause:()=>f(!1),children:R}),r.jsx("div",{className:"gvp-vignette"}),o&&r.jsx("div",{className:"gvp-toggle",children:r.jsxs("div",{className:"gvp-toggle-pill",children:[r.jsx("button",{type:"button",onClick:()=>S("desktop"),className:m("gvp-toggle-btn",p==="desktop"&&"is-active"),"aria-label":"Desktop view","aria-pressed":p==="desktop",children:r.jsx(O,{})}),r.jsx("div",{className:"gvp-toggle-divider"}),r.jsx("button",{type:"button",onClick:()=>S("mobile"),className:m("gvp-toggle-btn",p==="mobile"&&"is-active"),"aria-label":"Mobile view","aria-pressed":p==="mobile",children:r.jsx(U,{})})]})}),C&&r.jsx("button",{type:"button",onClick:C,className:"gvp-close","aria-label":"Close",children:r.jsx($,{})}),!E&&r.jsx("div",{className:"gvp-play-wrap",children:r.jsxs("button",{type:"button",onClick:()=>void T(),onMouseEnter:()=>w(!0),onMouseLeave:()=>w(!1),className:"gvp-play","aria-label":"Play",children:[r.jsx(J,{}),v&&B&&r.jsx("span",{className:"gvp-tooltip",role:"tooltip",children:v})]})}),r.jsx("div",{className:"gvp-bottom-fade"})]})};exports.ReactVideoPlayer=W;
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),l=require("react"),S=require("hls.js");function H(e){var n,s,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e)){var a=e.length;for(n=0;n<a;n++)e[n]&&(s=H(e[n]))&&(r&&(r+=" "),r+=s)}else for(s in e)e[s]&&(r&&(r+=" "),r+=s);return r}function P(){for(var e,n,s=0,r="",a=arguments.length;s<a;s++)(e=arguments[s])&&(n=H(e))&&(r&&(r+=" "),r+=n);return r}const R=l.forwardRef(({src:e,hlsConfig:n,isHls:s,children:r,...a},f)=>{const u=l.useRef(null),o=l.useRef(null);l.useImperativeHandle(f,()=>u.current);const y=globalThis.window!==void 0&&S.isSupported(),b=!!s||y&&typeof e=="string"&&e.endsWith(".m3u8");return l.useEffect(()=>{if(!e)return;const i=u.current;if(i){for(o.current&&(o.current.destroy(),o.current=null),i.pause(),i.removeAttribute("src");i.firstChild;)i.firstChild.remove();if(b){const d=new S(n);o.current=d,d.attachMedia(i),d.loadSource(e),d.on(S.Events.ERROR,(h,p)=>{p.fatal&&(d.destroy(),o.current=null)})}else i.src=e,i.load();return()=>{for(o.current&&(o.current.destroy(),o.current=null),i.pause(),i.removeAttribute("src");i.firstChild;)i.firstChild.remove();i.load()}}},[e,b,n]),t.jsx("video",{ref:u,...a,children:r})});R.displayName="HLSPlayer";const T="gvp-icon",N=e=>e?`${T} ${e}`:T,W=({className:e})=>t.jsxs("svg",{className:N(e),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[t.jsx("path",{d:"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"}),t.jsx("path",{d:"M11 15H13",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"}),t.jsx("path",{d:"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"}),t.jsx("path",{d:"M7 22H17",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}),X=({className:e})=>t.jsxs("svg",{className:N(e),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[t.jsx("path",{d:"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"}),t.jsx("path",{d:"M11 19H13",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),t.jsx("path",{d:"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2",stroke:"currentColor",strokeWidth:"2",strokeLinejoin:"round"})]}),G=({className:e})=>t.jsx("svg",{className:N(e),width:"14",height:"14",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:t.jsx("path",{d:"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z",fill:"currentColor"})}),K=({className:e})=>t.jsx("svg",{className:N(e),width:"22",height:"22",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:t.jsx("path",{d:"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z",fill:"currentColor"})});function $(e){if(!e)return null;if(/^[A-Za-z0-9_-]{11}$/.test(e))return e;let n;try{n=new URL(e)}catch{return null}const s=n.hostname.replace(/^www\./,"");if(s==="youtu.be"){const r=n.pathname.slice(1).split("/")[0];return/^[A-Za-z0-9_-]{11}$/.test(r)?r:null}if(s==="youtube.com"||s==="m.youtube.com"||s==="music.youtube.com"||s==="youtube-nocookie.com"){const r=n.searchParams.get("v");if(r&&/^[A-Za-z0-9_-]{11}$/.test(r))return r;const a=/^\/(?:embed|shorts|v|live)\/([A-Za-z0-9_-]{11})/.exec(n.pathname);if(a)return a[1]}return null}function E(e){try{const n=new URL(e),s=n.searchParams.get("t")??n.searchParams.get("start");if(!s)return null;if(/^\d+s?$/.test(s))return Number.parseInt(s,10);const r=/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/.exec(s);if(r){const a=Number.parseInt(r[1]??"0",10),f=Number.parseInt(r[2]??"0",10),u=Number.parseInt(r[3]??"0",10),o=a*3600+f*60+u;return o>0?o:null}}catch{}return null}function Z(e,n={}){const{autoPlay:s=!1,muted:r=!0,loop:a=!1,controls:f=!0,startSeconds:u}=n,o=new URLSearchParams({rel:"0",modestbranding:"1",playsinline:"1",controls:f?"1":"0"});return s?(o.set("autoplay","1"),o.set("mute","1")):r&&o.set("mute","1"),a&&(o.set("loop","1"),o.set("playlist",e)),u&&u>0&&o.set("start",String(u)),`https://www.youtube-nocookie.com/embed/${e}?${o.toString()}`}const Q=({src:e,poster:n,showDeviceToggle:s=!0,defaultDevice:r="desktop",hoverPlay:a=!1,tooltipText:f,onClose:u,className:o="",muted:y=!0,loop:b=!1,controls:i=!1,autoPlay:d=!1,frameMaxWidth:h,aspectRatio:p,hlsConfig:U,children:Y})=>{const w=l.useRef(null),m=l.useRef(null),[v,I]=l.useState(r),[B,g]=l.useState(!1),[V,k]=l.useState(!1),j=l.useMemo(()=>$(e),[e]),C=j!==null,_=l.useMemo(()=>v==="mobile"?(p==null?void 0:p.mobile)??"9/16":(p==null?void 0:p.desktop)??"16/9",[v,p]),z=l.useMemo(()=>v==="mobile"?(h==null?void 0:h.mobile)??"420px":(h==null?void 0:h.desktop)??"960px",[v,h]),q=l.useMemo(()=>j?Z(j,{autoPlay:d,muted:y,loop:b,controls:i,startSeconds:E(e)}):null,[j,e,d,y,b,i]),x=l.useCallback(async()=>{const c=w.current;if(c){if(m.current)try{await m.current}catch{}c.pause()}},[]),L=l.useCallback(async()=>{const c=w.current;if(c)try{c.readyState<2&&c.load();const M=c.play();m.current=M,await M,g(!0)}catch{g(!1)}finally{m.current=null}},[]),D=l.useCallback(()=>{!a||C||L()},[a,C,L]),O=l.useCallback(()=>{!a||C||x().then(()=>g(!1))},[a,C,x]),J=l.useCallback(async()=>{const c=w.current;c&&(c.paused?await L():(await x(),g(!1)))},[L,x]);return t.jsxs("div",{className:P("gvp-root",o),style:{width:z,aspectRatio:_},onMouseEnter:()=>{k(!0),D()},onMouseLeave:()=>{k(!1),O()},children:[C?t.jsx("iframe",{className:"gvp-video gvp-youtube",src:q??void 0,title:"YouTube video player",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowFullScreen:!0,referrerPolicy:"strict-origin-when-cross-origin"}):t.jsx(R,{ref:w,src:e,poster:n,muted:y,loop:b,playsInline:!0,preload:"metadata",controls:i,autoPlay:d,hlsConfig:U,className:"gvp-video",onPlay:()=>g(!0),onPause:()=>g(!1),children:Y}),!C&&t.jsx("div",{className:"gvp-vignette"}),s&&t.jsx("div",{className:"gvp-toggle",children:t.jsxs("div",{className:"gvp-toggle-pill",children:[t.jsx("button",{type:"button",onClick:()=>I("desktop"),className:P("gvp-toggle-btn",v==="desktop"&&"is-active"),"aria-label":"Desktop view","aria-pressed":v==="desktop",children:t.jsx(W,{})}),t.jsx("div",{className:"gvp-toggle-divider"}),t.jsx("button",{type:"button",onClick:()=>I("mobile"),className:P("gvp-toggle-btn",v==="mobile"&&"is-active"),"aria-label":"Mobile view","aria-pressed":v==="mobile",children:t.jsx(X,{})})]})}),u&&t.jsx("button",{type:"button",onClick:u,className:"gvp-close","aria-label":"Close",children:t.jsx(G,{})}),!C&&!B&&t.jsx("div",{className:"gvp-play-wrap",children:t.jsxs("button",{type:"button",onClick:()=>void J(),onMouseEnter:()=>k(!0),onMouseLeave:()=>k(!1),className:"gvp-play","aria-label":"Play",children:[t.jsx(K,{}),f&&V&&t.jsx("span",{className:"gvp-tooltip",role:"tooltip",children:f})]})}),!C&&t.jsx("div",{className:"gvp-bottom-fade"})]})};exports.ReactVideoPlayer=Q;exports.parseYouTubeId=$;exports.parseYouTubeStart=E;exports.youTubeEmbedUrl=Z;
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/HLSPlayer.tsx","../src/utils/icons.tsx","../src/VideoPlayerWrapper.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","\"use client\";\n\nimport Hls from \"hls.js\";\nimport React, { useEffect, useImperativeHandle, useRef } from \"react\";\nimport type { HLSPlayerProps } from \"./types\";\n\nexport const HLSPlayer = React.forwardRef<HTMLVideoElement, HLSPlayerProps>(\n ({ src, hlsConfig, isHls, children, ...videoProps }, forwardedRef) => {\n const internalRef = useRef<HTMLVideoElement | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n\n useImperativeHandle(forwardedRef, () => internalRef.current as HTMLVideoElement);\n\n const canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\n const shouldUseHls =\n Boolean(isHls) || (canUseHlsJs && typeof src === \"string\" && src.endsWith(\".m3u8\"));\n\n useEffect(() => {\n if (!src) return;\n const videoEl = internalRef.current;\n if (!videoEl) return;\n\n // destroy previous\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n\n // reset video element\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n\n if (shouldUseHls) {\n const hls = new Hls(hlsConfig);\n hlsRef.current = hls;\n\n hls.attachMedia(videoEl);\n hls.loadSource(src);\n\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsRef.current = null;\n }\n });\n } else {\n // native playback\n videoEl.src = src;\n videoEl.load();\n }\n\n return () => {\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n videoEl.load();\n };\n }, [src, shouldUseHls, hlsConfig]);\n\n // Captions are the consumer's responsibility — pass <track> elements as children.\n // NOSONAR: typescript:S4084\n return (\n <video ref={internalRef} {...videoProps}>\n {children}\n </video>\n );\n }\n);\n\nHLSPlayer.displayName = \"HLSPlayer\";\nexport default HLSPlayer;\n","\"use client\";\n\nimport React from \"react\";\n\ntype IconProps = { className?: string };\n\nconst baseClass = \"gvp-icon\";\nconst cls = (extra?: string) => (extra ? `${baseClass} ${extra}` : baseClass);\n\nexport const IconDesktop: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path d=\"M7 22H17\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n);\n\nexport const IconMobile: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const IconX: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const IconPlay: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","\"use client\";\n\nimport clsx from \"clsx\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport { HLSPlayer } from \"./HLSPlayer\";\nimport type { DeviceMode, VideoPlayerWrapperProps } from \"./types\";\nimport { IconDesktop, IconMobile, IconPlay, IconX } from \"./utils/icons\";\n\nexport const VideoPlayerWrapper: React.FC<VideoPlayerWrapperProps> = ({\n src,\n poster,\n showDeviceToggle = true,\n defaultDevice = \"desktop\",\n hoverPlay = false,\n tooltipText,\n onClose,\n className = \"\",\n muted = true,\n loop = false,\n controls = false,\n frameMaxWidth: customFrameMaxWidth,\n aspectRatio: customAspectRatio,\n hlsConfig,\n children,\n}) => {\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const playPromiseRef = useRef<Promise<void> | null>(null);\n\n const [device, setDevice] = useState<DeviceMode>(defaultDevice);\n const [isPlaying, setIsPlaying] = useState(false);\n const [showTooltip, setShowTooltip] = useState(false);\n\n const aspectRatio = useMemo(() => {\n return device === \"mobile\"\n ? (customAspectRatio?.mobile ?? \"9/16\")\n : (customAspectRatio?.desktop ?? \"16/9\");\n }, [device, customAspectRatio]);\n\n const frameMaxWidth = useMemo(() => {\n return device === \"mobile\"\n ? (customFrameMaxWidth?.mobile ?? \"420px\")\n : (customFrameMaxWidth?.desktop ?? \"960px\");\n }, [device, customFrameMaxWidth]);\n\n const safePause = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (playPromiseRef.current) {\n try {\n await playPromiseRef.current;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n }, []);\n\n const safePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromiseRef.current = p;\n await p;\n setIsPlaying(true);\n } catch {\n setIsPlaying(false);\n } finally {\n playPromiseRef.current = null;\n }\n }, []);\n\n const hoverStart = useCallback(() => {\n if (!hoverPlay) return;\n void safePlay();\n }, [hoverPlay, safePlay]);\n\n const hoverStop = useCallback(() => {\n if (!hoverPlay) return;\n void safePause().then(() => setIsPlaying(false));\n }, [hoverPlay, safePause]);\n\n const togglePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n setIsPlaying(false);\n }\n }, [safePlay, safePause]);\n\n return (\n // The mouse handlers are a progressive enhancement (hoverPlay + tooltip).\n // Keyboard/click users reach the same actions via the inner <button> elements,\n // so the outer container is intentionally non-interactive at the role level.\n // NOSONAR: typescript:S6848\n <div\n className={clsx(\"gvp-root\", className)}\n style={{ width: frameMaxWidth, aspectRatio }}\n onMouseEnter={() => {\n setShowTooltip(true);\n hoverStart();\n }}\n onMouseLeave={() => {\n setShowTooltip(false);\n hoverStop();\n }}\n >\n <HLSPlayer\n ref={videoRef}\n src={src}\n poster={poster}\n muted={muted}\n loop={loop}\n playsInline\n preload=\"metadata\"\n controls={controls}\n hlsConfig={hlsConfig}\n className=\"gvp-video\"\n onPlay={() => setIsPlaying(true)}\n onPause={() => setIsPlaying(false)}\n >\n {children}\n </HLSPlayer>\n\n <div className=\"gvp-vignette\" />\n\n {showDeviceToggle && (\n <div className=\"gvp-toggle\">\n <div className=\"gvp-toggle-pill\">\n <button\n type=\"button\"\n onClick={() => setDevice(\"desktop\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"desktop\" && \"is-active\"\n )}\n aria-label=\"Desktop view\"\n aria-pressed={device === \"desktop\"}\n >\n <IconDesktop />\n </button>\n\n <div className=\"gvp-toggle-divider\" />\n\n <button\n type=\"button\"\n onClick={() => setDevice(\"mobile\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"mobile\" && \"is-active\"\n )}\n aria-label=\"Mobile view\"\n aria-pressed={device === \"mobile\"}\n >\n <IconMobile />\n </button>\n </div>\n </div>\n )}\n\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"gvp-close\"\n aria-label=\"Close\"\n >\n <IconX />\n </button>\n )}\n\n {!isPlaying && (\n <div className=\"gvp-play-wrap\">\n <button\n type=\"button\"\n onClick={() => void togglePlay()}\n onMouseEnter={() => setShowTooltip(true)}\n onMouseLeave={() => setShowTooltip(false)}\n className=\"gvp-play\"\n aria-label=\"Play\"\n >\n <IconPlay />\n {tooltipText && showTooltip && (\n <span className=\"gvp-tooltip\" role=\"tooltip\">\n {tooltipText}\n </span>\n )}\n </button>\n </div>\n )}\n\n <div className=\"gvp-bottom-fade\" />\n </div>\n );\n};\n\nexport default VideoPlayerWrapper;\n"],"names":["r","t","f","n","o","clsx","HLSPlayer","React","src","hlsConfig","isHls","children","videoProps","forwardedRef","internalRef","useRef","hlsRef","useImperativeHandle","canUseHlsJs","Hls","shouldUseHls","useEffect","videoEl","hls","_evt","data","baseClass","cls","extra","IconDesktop","className","jsxs","jsx","IconMobile","IconX","IconPlay","VideoPlayerWrapper","poster","showDeviceToggle","defaultDevice","hoverPlay","tooltipText","onClose","muted","loop","controls","customFrameMaxWidth","customAspectRatio","videoRef","playPromiseRef","device","setDevice","useState","isPlaying","setIsPlaying","showTooltip","setShowTooltip","aspectRatio","useMemo","frameMaxWidth","safePause","useCallback","el","safePlay","p","hoverStart","hoverStop","togglePlay"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"index.cjs","sources":["../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/HLSPlayer.tsx","../src/utils/icons.tsx","../src/utils/youtube.ts","../src/VideoPlayerWrapper.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","\"use client\";\n\nimport Hls from \"hls.js\";\nimport React, { useEffect, useImperativeHandle, useRef } from \"react\";\nimport type { HLSPlayerProps } from \"./types\";\n\nexport const HLSPlayer = React.forwardRef<HTMLVideoElement, HLSPlayerProps>(\n ({ src, hlsConfig, isHls, children, ...videoProps }, forwardedRef) => {\n const internalRef = useRef<HTMLVideoElement | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n\n useImperativeHandle(forwardedRef, () => internalRef.current as HTMLVideoElement);\n\n const canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\n const shouldUseHls =\n Boolean(isHls) || (canUseHlsJs && typeof src === \"string\" && src.endsWith(\".m3u8\"));\n\n useEffect(() => {\n if (!src) return;\n const videoEl = internalRef.current;\n if (!videoEl) return;\n\n // destroy previous\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n\n // reset video element\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n\n if (shouldUseHls) {\n const hls = new Hls(hlsConfig);\n hlsRef.current = hls;\n\n hls.attachMedia(videoEl);\n hls.loadSource(src);\n\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsRef.current = null;\n }\n });\n } else {\n // native playback\n videoEl.src = src;\n videoEl.load();\n }\n\n return () => {\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n videoEl.load();\n };\n }, [src, shouldUseHls, hlsConfig]);\n\n // Captions are the consumer's responsibility — pass <track> elements as children.\n // NOSONAR: typescript:S4084\n return (\n <video ref={internalRef} {...videoProps}>\n {children}\n </video>\n );\n }\n);\n\nHLSPlayer.displayName = \"HLSPlayer\";\nexport default HLSPlayer;\n","\"use client\";\n\nimport React from \"react\";\n\ntype IconProps = { className?: string };\n\nconst baseClass = \"gvp-icon\";\nconst cls = (extra?: string) => (extra ? `${baseClass} ${extra}` : baseClass);\n\nexport const IconDesktop: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path d=\"M7 22H17\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n);\n\nexport const IconMobile: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const IconX: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const IconPlay: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","/**\n * Extract a YouTube video ID from any common URL form, or `null` if the URL\n * isn't a YouTube link.\n *\n * Recognised:\n * - https://www.youtube.com/watch?v=ID\n * - https://youtube.com/watch?v=ID&t=42\n * - https://youtu.be/ID\n * - https://youtu.be/ID?t=42\n * - https://www.youtube.com/embed/ID\n * - https://www.youtube.com/shorts/ID\n * - https://music.youtube.com/watch?v=ID\n * - bare 11-character video IDs\n */\nexport function parseYouTubeId(input: string): string | null {\n if (!input) return null;\n\n // Bare 11-char ID (YouTube IDs are [A-Za-z0-9_-]{11}).\n if (/^[A-Za-z0-9_-]{11}$/.test(input)) return input;\n\n let url: URL;\n try {\n url = new URL(input);\n } catch {\n return null;\n }\n\n const host = url.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtu.be\") {\n const id = url.pathname.slice(1).split(\"/\")[0];\n return /^[A-Za-z0-9_-]{11}$/.test(id) ? id : null;\n }\n\n if (\n host === \"youtube.com\" ||\n host === \"m.youtube.com\" ||\n host === \"music.youtube.com\" ||\n host === \"youtube-nocookie.com\"\n ) {\n // /watch?v=ID\n const v = url.searchParams.get(\"v\");\n if (v && /^[A-Za-z0-9_-]{11}$/.test(v)) return v;\n\n // /embed/ID, /shorts/ID, /v/ID, /live/ID\n const m = /^\\/(?:embed|shorts|v|live)\\/([A-Za-z0-9_-]{11})/.exec(\n url.pathname\n );\n if (m) return m[1];\n }\n\n return null;\n}\n\n/** Extract a `t`/`start` timestamp (in seconds) from a YouTube URL, if present. */\nexport function parseYouTubeStart(input: string): number | null {\n try {\n const url = new URL(input);\n const t = url.searchParams.get(\"t\") ?? url.searchParams.get(\"start\");\n if (!t) return null;\n // Supports \"90\", \"90s\", \"1m30s\", \"1h2m3s\".\n if (/^\\d+s?$/.test(t)) return Number.parseInt(t, 10);\n const m = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/.exec(t);\n if (m) {\n const h = Number.parseInt(m[1] ?? \"0\", 10);\n const min = Number.parseInt(m[2] ?? \"0\", 10);\n const s = Number.parseInt(m[3] ?? \"0\", 10);\n const total = h * 3600 + min * 60 + s;\n return total > 0 ? total : null;\n }\n } catch {\n /* not a URL */\n }\n return null;\n}\n\nexport interface YouTubeEmbedOptions {\n /** Start playback immediately. Forces `mute` on, since browsers block sound-on autoplay. */\n autoPlay?: boolean;\n /** Mute the player. */\n muted?: boolean;\n /** Loop the video. */\n loop?: boolean;\n /** Show YouTube's player controls. Defaults to `true`. */\n controls?: boolean;\n /** Start offset in seconds. */\n startSeconds?: number | null;\n}\n\n/**\n * Build a privacy-enhanced YouTube embed URL from a video ID and player options.\n *\n * Notes on YouTube's quirks:\n * - `autoplay=1` only takes effect if `mute=1` is also set (browser policy).\n * - single-video loop requires `loop=1` **and** `playlist=<id>`.\n */\nexport function youTubeEmbedUrl(id: string, opts: YouTubeEmbedOptions = {}): string {\n const { autoPlay = false, muted = true, loop = false, controls = true, startSeconds } = opts;\n\n const params = new URLSearchParams({\n rel: \"0\",\n modestbranding: \"1\",\n playsinline: \"1\",\n controls: controls ? \"1\" : \"0\",\n });\n\n if (autoPlay) {\n params.set(\"autoplay\", \"1\");\n params.set(\"mute\", \"1\"); // required for autoplay to actually fire\n } else if (muted) {\n params.set(\"mute\", \"1\");\n }\n\n if (loop) {\n params.set(\"loop\", \"1\");\n params.set(\"playlist\", id); // YouTube needs this for single-video loop\n }\n\n if (startSeconds && startSeconds > 0) {\n params.set(\"start\", String(startSeconds));\n }\n\n return `https://www.youtube-nocookie.com/embed/${id}?${params.toString()}`;\n}\n","\"use client\";\n\nimport clsx from \"clsx\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport { HLSPlayer } from \"./HLSPlayer\";\nimport type { DeviceMode, VideoPlayerWrapperProps } from \"./types\";\nimport { IconDesktop, IconMobile, IconPlay, IconX } from \"./utils/icons\";\nimport { parseYouTubeId, parseYouTubeStart, youTubeEmbedUrl } from \"./utils/youtube\";\n\nexport const VideoPlayerWrapper: React.FC<VideoPlayerWrapperProps> = ({\n src,\n poster,\n showDeviceToggle = true,\n defaultDevice = \"desktop\",\n hoverPlay = false,\n tooltipText,\n onClose,\n className = \"\",\n muted = true,\n loop = false,\n controls = false,\n autoPlay = false,\n frameMaxWidth: customFrameMaxWidth,\n aspectRatio: customAspectRatio,\n hlsConfig,\n children,\n}) => {\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const playPromiseRef = useRef<Promise<void> | null>(null);\n\n const [device, setDevice] = useState<DeviceMode>(defaultDevice);\n const [isPlaying, setIsPlaying] = useState(false);\n const [showTooltip, setShowTooltip] = useState(false);\n\n const youTubeId = useMemo(() => parseYouTubeId(src), [src]);\n const isYouTube = youTubeId !== null;\n\n const aspectRatio = useMemo(() => {\n return device === \"mobile\"\n ? (customAspectRatio?.mobile ?? \"9/16\")\n : (customAspectRatio?.desktop ?? \"16/9\");\n }, [device, customAspectRatio]);\n\n const frameMaxWidth = useMemo(() => {\n return device === \"mobile\"\n ? (customFrameMaxWidth?.mobile ?? \"420px\")\n : (customFrameMaxWidth?.desktop ?? \"960px\");\n }, [device, customFrameMaxWidth]);\n\n const youTubeSrc = useMemo(\n () =>\n youTubeId\n ? youTubeEmbedUrl(youTubeId, {\n autoPlay,\n muted,\n loop,\n controls,\n startSeconds: parseYouTubeStart(src),\n })\n : null,\n [youTubeId, src, autoPlay, muted, loop, controls]\n );\n\n const safePause = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (playPromiseRef.current) {\n try {\n await playPromiseRef.current;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n }, []);\n\n const safePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromiseRef.current = p;\n await p;\n setIsPlaying(true);\n } catch {\n setIsPlaying(false);\n } finally {\n playPromiseRef.current = null;\n }\n }, []);\n\n const hoverStart = useCallback(() => {\n if (!hoverPlay || isYouTube) return;\n void safePlay();\n }, [hoverPlay, isYouTube, safePlay]);\n\n const hoverStop = useCallback(() => {\n if (!hoverPlay || isYouTube) return;\n void safePause().then(() => setIsPlaying(false));\n }, [hoverPlay, isYouTube, safePause]);\n\n const togglePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n setIsPlaying(false);\n }\n }, [safePlay, safePause]);\n\n return (\n // The mouse handlers are a progressive enhancement (hoverPlay + tooltip).\n // Keyboard/click users reach the same actions via the inner <button> elements,\n // so the outer container is intentionally non-interactive at the role level.\n // NOSONAR: typescript:S6848\n <div\n className={clsx(\"gvp-root\", className)}\n style={{ width: frameMaxWidth, aspectRatio }}\n onMouseEnter={() => {\n setShowTooltip(true);\n hoverStart();\n }}\n onMouseLeave={() => {\n setShowTooltip(false);\n hoverStop();\n }}\n >\n {isYouTube ? (\n <iframe\n className=\"gvp-video gvp-youtube\"\n src={youTubeSrc ?? undefined}\n title=\"YouTube video player\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowFullScreen\n referrerPolicy=\"strict-origin-when-cross-origin\"\n />\n ) : (\n <HLSPlayer\n ref={videoRef}\n src={src}\n poster={poster}\n muted={muted}\n loop={loop}\n playsInline\n preload=\"metadata\"\n controls={controls}\n autoPlay={autoPlay}\n hlsConfig={hlsConfig}\n className=\"gvp-video\"\n onPlay={() => setIsPlaying(true)}\n onPause={() => setIsPlaying(false)}\n >\n {children}\n </HLSPlayer>\n )}\n\n {!isYouTube && <div className=\"gvp-vignette\" />}\n\n {showDeviceToggle && (\n <div className=\"gvp-toggle\">\n <div className=\"gvp-toggle-pill\">\n <button\n type=\"button\"\n onClick={() => setDevice(\"desktop\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"desktop\" && \"is-active\"\n )}\n aria-label=\"Desktop view\"\n aria-pressed={device === \"desktop\"}\n >\n <IconDesktop />\n </button>\n\n <div className=\"gvp-toggle-divider\" />\n\n <button\n type=\"button\"\n onClick={() => setDevice(\"mobile\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"mobile\" && \"is-active\"\n )}\n aria-label=\"Mobile view\"\n aria-pressed={device === \"mobile\"}\n >\n <IconMobile />\n </button>\n </div>\n </div>\n )}\n\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"gvp-close\"\n aria-label=\"Close\"\n >\n <IconX />\n </button>\n )}\n\n {!isYouTube && !isPlaying && (\n <div className=\"gvp-play-wrap\">\n <button\n type=\"button\"\n onClick={() => void togglePlay()}\n onMouseEnter={() => setShowTooltip(true)}\n onMouseLeave={() => setShowTooltip(false)}\n className=\"gvp-play\"\n aria-label=\"Play\"\n >\n <IconPlay />\n {tooltipText && showTooltip && (\n <span className=\"gvp-tooltip\" role=\"tooltip\">\n {tooltipText}\n </span>\n )}\n </button>\n </div>\n )}\n\n {!isYouTube && <div className=\"gvp-bottom-fade\" />}\n </div>\n );\n};\n\nexport default VideoPlayerWrapper;\n"],"names":["r","t","f","n","o","clsx","HLSPlayer","React","src","hlsConfig","isHls","children","videoProps","forwardedRef","internalRef","useRef","hlsRef","useImperativeHandle","canUseHlsJs","Hls","shouldUseHls","useEffect","videoEl","hls","_evt","data","baseClass","cls","extra","IconDesktop","className","jsxs","jsx","IconMobile","IconX","IconPlay","parseYouTubeId","input","url","host","id","v","m","parseYouTubeStart","h","min","s","total","youTubeEmbedUrl","opts","autoPlay","muted","loop","controls","startSeconds","params","VideoPlayerWrapper","poster","showDeviceToggle","defaultDevice","hoverPlay","tooltipText","onClose","customFrameMaxWidth","customAspectRatio","videoRef","playPromiseRef","device","setDevice","useState","isPlaying","setIsPlaying","showTooltip","setShowTooltip","youTubeId","useMemo","isYouTube","aspectRatio","frameMaxWidth","youTubeSrc","safePause","useCallback","el","safePlay","p","hoverStart","hoverStop","togglePlay"],"mappings":"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","x_google_ignoreList":[0]}
package/dist/index.d.ts CHANGED
@@ -5,6 +5,25 @@ declare type AspectRatio = `${number}/${number}`;
5
5
 
6
6
  declare type DeviceMode = "desktop" | "mobile";
7
7
 
8
+ /**
9
+ * Extract a YouTube video ID from any common URL form, or `null` if the URL
10
+ * isn't a YouTube link.
11
+ *
12
+ * Recognised:
13
+ * - https://www.youtube.com/watch?v=ID
14
+ * - https://youtube.com/watch?v=ID&t=42
15
+ * - https://youtu.be/ID
16
+ * - https://youtu.be/ID?t=42
17
+ * - https://www.youtube.com/embed/ID
18
+ * - https://www.youtube.com/shorts/ID
19
+ * - https://music.youtube.com/watch?v=ID
20
+ * - bare 11-character video IDs
21
+ */
22
+ export declare function parseYouTubeId(input: string): string | null;
23
+
24
+ /** Extract a `t`/`start` timestamp (in seconds) from a YouTube URL, if present. */
25
+ export declare function parseYouTubeStart(input: string): number | null;
26
+
8
27
  export declare const ReactVideoPlayer: default_2.FC<ReactVideoPlayerProps>;
9
28
 
10
29
  export declare interface ReactVideoPlayerProps {
@@ -30,6 +49,12 @@ export declare interface ReactVideoPlayerProps {
30
49
  loop?: boolean;
31
50
  /** Show native browser controls. Defaults to `false`. */
32
51
  controls?: boolean;
52
+ /**
53
+ * Start playback as soon as the source loads. Defaults to `false`.
54
+ * Browsers block sound-on autoplay, so this only autoplays when `muted`
55
+ * is also `true` (which is the default).
56
+ */
57
+ autoPlay?: boolean;
33
58
  /** Maximum width of the player in each device mode. */
34
59
  frameMaxWidth?: {
35
60
  desktop?: string;
@@ -52,4 +77,26 @@ export declare interface ReactVideoPlayerProps {
52
77
  children?: default_2.ReactNode;
53
78
  }
54
79
 
80
+ declare interface YouTubeEmbedOptions {
81
+ /** Start playback immediately. Forces `mute` on, since browsers block sound-on autoplay. */
82
+ autoPlay?: boolean;
83
+ /** Mute the player. */
84
+ muted?: boolean;
85
+ /** Loop the video. */
86
+ loop?: boolean;
87
+ /** Show YouTube's player controls. Defaults to `true`. */
88
+ controls?: boolean;
89
+ /** Start offset in seconds. */
90
+ startSeconds?: number | null;
91
+ }
92
+
93
+ /**
94
+ * Build a privacy-enhanced YouTube embed URL from a video ID and player options.
95
+ *
96
+ * Notes on YouTube's quirks:
97
+ * - `autoplay=1` only takes effect if `mute=1` is also set (browser policy).
98
+ * - single-video loop requires `loop=1` **and** `playlist=<id>`.
99
+ */
100
+ export declare function youTubeEmbedUrl(id: string, opts?: YouTubeEmbedOptions): string;
101
+
55
102
  export { }
package/dist/index.mjs CHANGED
@@ -1,50 +1,50 @@
1
1
  "use client";
2
- import { jsx as r, jsxs as v } from "react/jsx-runtime";
3
- import X, { useRef as m, useImperativeHandle as _, useEffect as q, useState as M, useMemo as B, useCallback as C } from "react";
4
- import S from "hls.js";
5
- function x(e) {
6
- var o, l, t = "";
2
+ import { jsx as r, jsxs as y } from "react/jsx-runtime";
3
+ import q, { useRef as H, useImperativeHandle as G, useEffect as K, useState as T, useMemo as I, useCallback as w } from "react";
4
+ import $ from "hls.js";
5
+ function R(e) {
6
+ var o, n, t = "";
7
7
  if (typeof e == "string" || typeof e == "number") t += e;
8
8
  else if (typeof e == "object") if (Array.isArray(e)) {
9
- var i = e.length;
10
- for (o = 0; o < i; o++) e[o] && (l = x(e[o])) && (t && (t += " "), t += l);
11
- } else for (l in e) e[l] && (t && (t += " "), t += l);
9
+ var l = e.length;
10
+ for (o = 0; o < l; o++) e[o] && (n = R(e[o])) && (t && (t += " "), t += n);
11
+ } else for (n in e) e[n] && (t && (t += " "), t += n);
12
12
  return t;
13
13
  }
14
- function I() {
15
- for (var e, o, l = 0, t = "", i = arguments.length; l < i; l++) (e = arguments[l]) && (o = x(e)) && (t && (t += " "), t += o);
14
+ function Z() {
15
+ for (var e, o, n = 0, t = "", l = arguments.length; n < l; n++) (e = arguments[n]) && (o = R(e)) && (t && (t += " "), t += o);
16
16
  return t;
17
17
  }
18
- const Z = X.forwardRef(
19
- ({ src: e, hlsConfig: o, isHls: l, children: t, ...i }, h) => {
20
- const p = m(null), a = m(null);
21
- _(h, () => p.current);
22
- const H = globalThis.window !== void 0 && S.isSupported(), g = !!l || H && typeof e == "string" && e.endsWith(".m3u8");
23
- return q(() => {
18
+ const U = q.forwardRef(
19
+ ({ src: e, hlsConfig: o, isHls: n, children: t, ...l }, p) => {
20
+ const i = H(null), s = H(null);
21
+ G(p, () => i.current);
22
+ const b = globalThis.window !== void 0 && $.isSupported(), C = !!n || b && typeof e == "string" && e.endsWith(".m3u8");
23
+ return K(() => {
24
24
  if (!e) return;
25
- const n = p.current;
26
- if (n) {
27
- for (a.current && (a.current.destroy(), a.current = null), n.pause(), n.removeAttribute("src"); n.firstChild; ) n.firstChild.remove();
28
- if (g) {
29
- const s = new S(o);
30
- a.current = s, s.attachMedia(n), s.loadSource(e), s.on(S.Events.ERROR, (d, P) => {
31
- P.fatal && (s.destroy(), a.current = null);
25
+ const a = i.current;
26
+ if (a) {
27
+ for (s.current && (s.current.destroy(), s.current = null), a.pause(), a.removeAttribute("src"); a.firstChild; ) a.firstChild.remove();
28
+ if (C) {
29
+ const c = new $(o);
30
+ s.current = c, c.attachMedia(a), c.loadSource(e), c.on($.Events.ERROR, (f, d) => {
31
+ d.fatal && (c.destroy(), s.current = null);
32
32
  });
33
33
  } else
34
- n.src = e, n.load();
34
+ a.src = e, a.load();
35
35
  return () => {
36
- for (a.current && (a.current.destroy(), a.current = null), n.pause(), n.removeAttribute("src"); n.firstChild; ) n.firstChild.remove();
37
- n.load();
36
+ for (s.current && (s.current.destroy(), s.current = null), a.pause(), a.removeAttribute("src"); a.firstChild; ) a.firstChild.remove();
37
+ a.load();
38
38
  };
39
39
  }
40
- }, [e, g, o]), /* @__PURE__ */ r("video", { ref: p, ...i, children: t });
40
+ }, [e, C, o]), /* @__PURE__ */ r("video", { ref: i, ...l, children: t });
41
41
  }
42
42
  );
43
- Z.displayName = "HLSPlayer";
44
- const V = "gvp-icon", N = (e) => e ? `${V} ${e}` : V, z = ({ className: e }) => /* @__PURE__ */ v(
43
+ U.displayName = "HLSPlayer";
44
+ const x = "gvp-icon", M = (e) => e ? `${x} ${e}` : x, Q = ({ className: e }) => /* @__PURE__ */ y(
45
45
  "svg",
46
46
  {
47
- className: N(e),
47
+ className: M(e),
48
48
  width: "20",
49
49
  height: "20",
50
50
  viewBox: "0 0 24 24",
@@ -83,10 +83,10 @@ const V = "gvp-icon", N = (e) => e ? `${V} ${e}` : V, z = ({ className: e }) =>
83
83
  /* @__PURE__ */ r("path", { d: "M7 22H17", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
84
84
  ]
85
85
  }
86
- ), G = ({ className: e }) => /* @__PURE__ */ v(
86
+ ), A = ({ className: e }) => /* @__PURE__ */ y(
87
87
  "svg",
88
88
  {
89
- className: N(e),
89
+ className: M(e),
90
90
  width: "20",
91
91
  height: "20",
92
92
  viewBox: "0 0 24 24",
@@ -124,10 +124,10 @@ const V = "gvp-icon", N = (e) => e ? `${V} ${e}` : V, z = ({ className: e }) =>
124
124
  )
125
125
  ]
126
126
  }
127
- ), K = ({ className: e }) => /* @__PURE__ */ r(
127
+ ), F = ({ className: e }) => /* @__PURE__ */ r(
128
128
  "svg",
129
129
  {
130
- className: N(e),
130
+ className: M(e),
131
131
  width: "14",
132
132
  height: "14",
133
133
  viewBox: "0 0 14 14",
@@ -142,10 +142,10 @@ const V = "gvp-icon", N = (e) => e ? `${V} ${e}` : V, z = ({ className: e }) =>
142
142
  }
143
143
  )
144
144
  }
145
- ), Q = ({ className: e }) => /* @__PURE__ */ r(
145
+ ), ee = ({ className: e }) => /* @__PURE__ */ r(
146
146
  "svg",
147
147
  {
148
- className: N(e),
148
+ className: M(e),
149
149
  width: "22",
150
150
  height: "22",
151
151
  viewBox: "0 0 16 16",
@@ -160,102 +160,171 @@ const V = "gvp-icon", N = (e) => e ? `${V} ${e}` : V, z = ({ className: e }) =>
160
160
  }
161
161
  )
162
162
  }
163
- ), e1 = ({
163
+ );
164
+ function te(e) {
165
+ if (!e) return null;
166
+ if (/^[A-Za-z0-9_-]{11}$/.test(e)) return e;
167
+ let o;
168
+ try {
169
+ o = new URL(e);
170
+ } catch {
171
+ return null;
172
+ }
173
+ const n = o.hostname.replace(/^www\./, "");
174
+ if (n === "youtu.be") {
175
+ const t = o.pathname.slice(1).split("/")[0];
176
+ return /^[A-Za-z0-9_-]{11}$/.test(t) ? t : null;
177
+ }
178
+ if (n === "youtube.com" || n === "m.youtube.com" || n === "music.youtube.com" || n === "youtube-nocookie.com") {
179
+ const t = o.searchParams.get("v");
180
+ if (t && /^[A-Za-z0-9_-]{11}$/.test(t)) return t;
181
+ const l = /^\/(?:embed|shorts|v|live)\/([A-Za-z0-9_-]{11})/.exec(
182
+ o.pathname
183
+ );
184
+ if (l) return l[1];
185
+ }
186
+ return null;
187
+ }
188
+ function re(e) {
189
+ try {
190
+ const o = new URL(e), n = o.searchParams.get("t") ?? o.searchParams.get("start");
191
+ if (!n) return null;
192
+ if (/^\d+s?$/.test(n)) return Number.parseInt(n, 10);
193
+ const t = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/.exec(n);
194
+ if (t) {
195
+ const l = Number.parseInt(t[1] ?? "0", 10), p = Number.parseInt(t[2] ?? "0", 10), i = Number.parseInt(t[3] ?? "0", 10), s = l * 3600 + p * 60 + i;
196
+ return s > 0 ? s : null;
197
+ }
198
+ } catch {
199
+ }
200
+ return null;
201
+ }
202
+ function ne(e, o = {}) {
203
+ const { autoPlay: n = !1, muted: t = !0, loop: l = !1, controls: p = !0, startSeconds: i } = o, s = new URLSearchParams({
204
+ rel: "0",
205
+ modestbranding: "1",
206
+ playsinline: "1",
207
+ controls: p ? "1" : "0"
208
+ });
209
+ return n ? (s.set("autoplay", "1"), s.set("mute", "1")) : t && s.set("mute", "1"), l && (s.set("loop", "1"), s.set("playlist", e)), i && i > 0 && s.set("start", String(i)), `https://www.youtube-nocookie.com/embed/${e}?${s.toString()}`;
210
+ }
211
+ const ae = ({
164
212
  src: e,
165
213
  poster: o,
166
- showDeviceToggle: l = !0,
214
+ showDeviceToggle: n = !0,
167
215
  defaultDevice: t = "desktop",
168
- hoverPlay: i = !1,
169
- tooltipText: h,
170
- onClose: p,
171
- className: a = "",
172
- muted: H = !0,
173
- loop: g = !1,
174
- controls: n = !1,
175
- frameMaxWidth: s,
216
+ hoverPlay: l = !1,
217
+ tooltipText: p,
218
+ onClose: i,
219
+ className: s = "",
220
+ muted: b = !0,
221
+ loop: C = !1,
222
+ controls: a = !1,
223
+ autoPlay: c = !1,
224
+ frameMaxWidth: f,
176
225
  aspectRatio: d,
177
- hlsConfig: P,
178
- children: D
226
+ hlsConfig: B,
227
+ children: V
179
228
  }) => {
180
- const w = m(null), k = m(null), [u, j] = M(t), [R, f] = M(!1), [T, y] = M(!1), U = B(() => u === "mobile" ? (d == null ? void 0 : d.mobile) ?? "9/16" : (d == null ? void 0 : d.desktop) ?? "16/9", [u, d]), $ = B(() => u === "mobile" ? (s == null ? void 0 : s.mobile) ?? "420px" : (s == null ? void 0 : s.desktop) ?? "960px", [u, s]), b = C(async () => {
181
- const c = w.current;
182
- if (c) {
229
+ const m = H(null), k = H(null), [h, E] = T(t), [_, g] = T(!1), [z, L] = T(!1), N = I(() => te(e), [e]), v = N !== null, Y = I(() => h === "mobile" ? (d == null ? void 0 : d.mobile) ?? "9/16" : (d == null ? void 0 : d.desktop) ?? "16/9", [h, d]), D = I(() => h === "mobile" ? (f == null ? void 0 : f.mobile) ?? "420px" : (f == null ? void 0 : f.desktop) ?? "960px", [h, f]), J = I(
230
+ () => N ? ne(N, {
231
+ autoPlay: c,
232
+ muted: b,
233
+ loop: C,
234
+ controls: a,
235
+ startSeconds: re(e)
236
+ }) : null,
237
+ [N, e, c, b, C, a]
238
+ ), S = w(async () => {
239
+ const u = m.current;
240
+ if (u) {
183
241
  if (k.current)
184
242
  try {
185
243
  await k.current;
186
244
  } catch {
187
245
  }
188
- c.pause();
246
+ u.pause();
189
247
  }
190
- }, []), L = C(async () => {
191
- const c = w.current;
192
- if (c)
248
+ }, []), P = w(async () => {
249
+ const u = m.current;
250
+ if (u)
193
251
  try {
194
- c.readyState < 2 && c.load();
195
- const E = c.play();
196
- k.current = E, await E, f(!0);
252
+ u.readyState < 2 && u.load();
253
+ const j = u.play();
254
+ k.current = j, await j, g(!0);
197
255
  } catch {
198
- f(!1);
256
+ g(!1);
199
257
  } finally {
200
258
  k.current = null;
201
259
  }
202
- }, []), J = C(() => {
203
- i && L();
204
- }, [i, L]), O = C(() => {
205
- i && b().then(() => f(!1));
206
- }, [i, b]), W = C(async () => {
207
- const c = w.current;
208
- c && (c.paused ? await L() : (await b(), f(!1)));
209
- }, [L, b]);
260
+ }, []), O = w(() => {
261
+ !l || v || P();
262
+ }, [l, v, P]), W = w(() => {
263
+ !l || v || S().then(() => g(!1));
264
+ }, [l, v, S]), X = w(async () => {
265
+ const u = m.current;
266
+ u && (u.paused ? await P() : (await S(), g(!1)));
267
+ }, [P, S]);
210
268
  return (
211
269
  // The mouse handlers are a progressive enhancement (hoverPlay + tooltip).
212
270
  // Keyboard/click users reach the same actions via the inner <button> elements,
213
271
  // so the outer container is intentionally non-interactive at the role level.
214
272
  // NOSONAR: typescript:S6848
215
- /* @__PURE__ */ v(
273
+ /* @__PURE__ */ y(
216
274
  "div",
217
275
  {
218
- className: I("gvp-root", a),
219
- style: { width: $, aspectRatio: U },
276
+ className: Z("gvp-root", s),
277
+ style: { width: D, aspectRatio: Y },
220
278
  onMouseEnter: () => {
221
- y(!0), J();
279
+ L(!0), O();
222
280
  },
223
281
  onMouseLeave: () => {
224
- y(!1), O();
282
+ L(!1), W();
225
283
  },
226
284
  children: [
227
- /* @__PURE__ */ r(
228
- Z,
285
+ v ? /* @__PURE__ */ r(
286
+ "iframe",
287
+ {
288
+ className: "gvp-video gvp-youtube",
289
+ src: J ?? void 0,
290
+ title: "YouTube video player",
291
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
292
+ allowFullScreen: !0,
293
+ referrerPolicy: "strict-origin-when-cross-origin"
294
+ }
295
+ ) : /* @__PURE__ */ r(
296
+ U,
229
297
  {
230
- ref: w,
298
+ ref: m,
231
299
  src: e,
232
300
  poster: o,
233
- muted: H,
234
- loop: g,
301
+ muted: b,
302
+ loop: C,
235
303
  playsInline: !0,
236
304
  preload: "metadata",
237
- controls: n,
238
- hlsConfig: P,
305
+ controls: a,
306
+ autoPlay: c,
307
+ hlsConfig: B,
239
308
  className: "gvp-video",
240
- onPlay: () => f(!0),
241
- onPause: () => f(!1),
242
- children: D
309
+ onPlay: () => g(!0),
310
+ onPause: () => g(!1),
311
+ children: V
243
312
  }
244
313
  ),
245
- /* @__PURE__ */ r("div", { className: "gvp-vignette" }),
246
- l && /* @__PURE__ */ r("div", { className: "gvp-toggle", children: /* @__PURE__ */ v("div", { className: "gvp-toggle-pill", children: [
314
+ !v && /* @__PURE__ */ r("div", { className: "gvp-vignette" }),
315
+ n && /* @__PURE__ */ r("div", { className: "gvp-toggle", children: /* @__PURE__ */ y("div", { className: "gvp-toggle-pill", children: [
247
316
  /* @__PURE__ */ r(
248
317
  "button",
249
318
  {
250
319
  type: "button",
251
- onClick: () => j("desktop"),
252
- className: I(
320
+ onClick: () => E("desktop"),
321
+ className: Z(
253
322
  "gvp-toggle-btn",
254
- u === "desktop" && "is-active"
323
+ h === "desktop" && "is-active"
255
324
  ),
256
325
  "aria-label": "Desktop view",
257
- "aria-pressed": u === "desktop",
258
- children: /* @__PURE__ */ r(z, {})
326
+ "aria-pressed": h === "desktop",
327
+ children: /* @__PURE__ */ r(Q, {})
259
328
  }
260
329
  ),
261
330
  /* @__PURE__ */ r("div", { className: "gvp-toggle-divider" }),
@@ -263,49 +332,52 @@ const V = "gvp-icon", N = (e) => e ? `${V} ${e}` : V, z = ({ className: e }) =>
263
332
  "button",
264
333
  {
265
334
  type: "button",
266
- onClick: () => j("mobile"),
267
- className: I(
335
+ onClick: () => E("mobile"),
336
+ className: Z(
268
337
  "gvp-toggle-btn",
269
- u === "mobile" && "is-active"
338
+ h === "mobile" && "is-active"
270
339
  ),
271
340
  "aria-label": "Mobile view",
272
- "aria-pressed": u === "mobile",
273
- children: /* @__PURE__ */ r(G, {})
341
+ "aria-pressed": h === "mobile",
342
+ children: /* @__PURE__ */ r(A, {})
274
343
  }
275
344
  )
276
345
  ] }) }),
277
- p && /* @__PURE__ */ r(
346
+ i && /* @__PURE__ */ r(
278
347
  "button",
279
348
  {
280
349
  type: "button",
281
- onClick: p,
350
+ onClick: i,
282
351
  className: "gvp-close",
283
352
  "aria-label": "Close",
284
- children: /* @__PURE__ */ r(K, {})
353
+ children: /* @__PURE__ */ r(F, {})
285
354
  }
286
355
  ),
287
- !R && /* @__PURE__ */ r("div", { className: "gvp-play-wrap", children: /* @__PURE__ */ v(
356
+ !v && !_ && /* @__PURE__ */ r("div", { className: "gvp-play-wrap", children: /* @__PURE__ */ y(
288
357
  "button",
289
358
  {
290
359
  type: "button",
291
- onClick: () => void W(),
292
- onMouseEnter: () => y(!0),
293
- onMouseLeave: () => y(!1),
360
+ onClick: () => void X(),
361
+ onMouseEnter: () => L(!0),
362
+ onMouseLeave: () => L(!1),
294
363
  className: "gvp-play",
295
364
  "aria-label": "Play",
296
365
  children: [
297
- /* @__PURE__ */ r(Q, {}),
298
- h && T && /* @__PURE__ */ r("span", { className: "gvp-tooltip", role: "tooltip", children: h })
366
+ /* @__PURE__ */ r(ee, {}),
367
+ p && z && /* @__PURE__ */ r("span", { className: "gvp-tooltip", role: "tooltip", children: p })
299
368
  ]
300
369
  }
301
370
  ) }),
302
- /* @__PURE__ */ r("div", { className: "gvp-bottom-fade" })
371
+ !v && /* @__PURE__ */ r("div", { className: "gvp-bottom-fade" })
303
372
  ]
304
373
  }
305
374
  )
306
375
  );
307
376
  };
308
377
  export {
309
- e1 as ReactVideoPlayer
378
+ ae as ReactVideoPlayer,
379
+ te as parseYouTubeId,
380
+ re as parseYouTubeStart,
381
+ ne as youTubeEmbedUrl
310
382
  };
311
383
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/HLSPlayer.tsx","../src/utils/icons.tsx","../src/VideoPlayerWrapper.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","\"use client\";\n\nimport Hls from \"hls.js\";\nimport React, { useEffect, useImperativeHandle, useRef } from \"react\";\nimport type { HLSPlayerProps } from \"./types\";\n\nexport const HLSPlayer = React.forwardRef<HTMLVideoElement, HLSPlayerProps>(\n ({ src, hlsConfig, isHls, children, ...videoProps }, forwardedRef) => {\n const internalRef = useRef<HTMLVideoElement | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n\n useImperativeHandle(forwardedRef, () => internalRef.current as HTMLVideoElement);\n\n const canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\n const shouldUseHls =\n Boolean(isHls) || (canUseHlsJs && typeof src === \"string\" && src.endsWith(\".m3u8\"));\n\n useEffect(() => {\n if (!src) return;\n const videoEl = internalRef.current;\n if (!videoEl) return;\n\n // destroy previous\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n\n // reset video element\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n\n if (shouldUseHls) {\n const hls = new Hls(hlsConfig);\n hlsRef.current = hls;\n\n hls.attachMedia(videoEl);\n hls.loadSource(src);\n\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsRef.current = null;\n }\n });\n } else {\n // native playback\n videoEl.src = src;\n videoEl.load();\n }\n\n return () => {\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n videoEl.load();\n };\n }, [src, shouldUseHls, hlsConfig]);\n\n // Captions are the consumer's responsibility — pass <track> elements as children.\n // NOSONAR: typescript:S4084\n return (\n <video ref={internalRef} {...videoProps}>\n {children}\n </video>\n );\n }\n);\n\nHLSPlayer.displayName = \"HLSPlayer\";\nexport default HLSPlayer;\n","\"use client\";\n\nimport React from \"react\";\n\ntype IconProps = { className?: string };\n\nconst baseClass = \"gvp-icon\";\nconst cls = (extra?: string) => (extra ? `${baseClass} ${extra}` : baseClass);\n\nexport const IconDesktop: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path d=\"M7 22H17\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n);\n\nexport const IconMobile: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const IconX: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const IconPlay: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","\"use client\";\n\nimport clsx from \"clsx\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport { HLSPlayer } from \"./HLSPlayer\";\nimport type { DeviceMode, VideoPlayerWrapperProps } from \"./types\";\nimport { IconDesktop, IconMobile, IconPlay, IconX } from \"./utils/icons\";\n\nexport const VideoPlayerWrapper: React.FC<VideoPlayerWrapperProps> = ({\n src,\n poster,\n showDeviceToggle = true,\n defaultDevice = \"desktop\",\n hoverPlay = false,\n tooltipText,\n onClose,\n className = \"\",\n muted = true,\n loop = false,\n controls = false,\n frameMaxWidth: customFrameMaxWidth,\n aspectRatio: customAspectRatio,\n hlsConfig,\n children,\n}) => {\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const playPromiseRef = useRef<Promise<void> | null>(null);\n\n const [device, setDevice] = useState<DeviceMode>(defaultDevice);\n const [isPlaying, setIsPlaying] = useState(false);\n const [showTooltip, setShowTooltip] = useState(false);\n\n const aspectRatio = useMemo(() => {\n return device === \"mobile\"\n ? (customAspectRatio?.mobile ?? \"9/16\")\n : (customAspectRatio?.desktop ?? \"16/9\");\n }, [device, customAspectRatio]);\n\n const frameMaxWidth = useMemo(() => {\n return device === \"mobile\"\n ? (customFrameMaxWidth?.mobile ?? \"420px\")\n : (customFrameMaxWidth?.desktop ?? \"960px\");\n }, [device, customFrameMaxWidth]);\n\n const safePause = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (playPromiseRef.current) {\n try {\n await playPromiseRef.current;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n }, []);\n\n const safePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromiseRef.current = p;\n await p;\n setIsPlaying(true);\n } catch {\n setIsPlaying(false);\n } finally {\n playPromiseRef.current = null;\n }\n }, []);\n\n const hoverStart = useCallback(() => {\n if (!hoverPlay) return;\n void safePlay();\n }, [hoverPlay, safePlay]);\n\n const hoverStop = useCallback(() => {\n if (!hoverPlay) return;\n void safePause().then(() => setIsPlaying(false));\n }, [hoverPlay, safePause]);\n\n const togglePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n setIsPlaying(false);\n }\n }, [safePlay, safePause]);\n\n return (\n // The mouse handlers are a progressive enhancement (hoverPlay + tooltip).\n // Keyboard/click users reach the same actions via the inner <button> elements,\n // so the outer container is intentionally non-interactive at the role level.\n // NOSONAR: typescript:S6848\n <div\n className={clsx(\"gvp-root\", className)}\n style={{ width: frameMaxWidth, aspectRatio }}\n onMouseEnter={() => {\n setShowTooltip(true);\n hoverStart();\n }}\n onMouseLeave={() => {\n setShowTooltip(false);\n hoverStop();\n }}\n >\n <HLSPlayer\n ref={videoRef}\n src={src}\n poster={poster}\n muted={muted}\n loop={loop}\n playsInline\n preload=\"metadata\"\n controls={controls}\n hlsConfig={hlsConfig}\n className=\"gvp-video\"\n onPlay={() => setIsPlaying(true)}\n onPause={() => setIsPlaying(false)}\n >\n {children}\n </HLSPlayer>\n\n <div className=\"gvp-vignette\" />\n\n {showDeviceToggle && (\n <div className=\"gvp-toggle\">\n <div className=\"gvp-toggle-pill\">\n <button\n type=\"button\"\n onClick={() => setDevice(\"desktop\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"desktop\" && \"is-active\"\n )}\n aria-label=\"Desktop view\"\n aria-pressed={device === \"desktop\"}\n >\n <IconDesktop />\n </button>\n\n <div className=\"gvp-toggle-divider\" />\n\n <button\n type=\"button\"\n onClick={() => setDevice(\"mobile\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"mobile\" && \"is-active\"\n )}\n aria-label=\"Mobile view\"\n aria-pressed={device === \"mobile\"}\n >\n <IconMobile />\n </button>\n </div>\n </div>\n )}\n\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"gvp-close\"\n aria-label=\"Close\"\n >\n <IconX />\n </button>\n )}\n\n {!isPlaying && (\n <div className=\"gvp-play-wrap\">\n <button\n type=\"button\"\n onClick={() => void togglePlay()}\n onMouseEnter={() => setShowTooltip(true)}\n onMouseLeave={() => setShowTooltip(false)}\n className=\"gvp-play\"\n aria-label=\"Play\"\n >\n <IconPlay />\n {tooltipText && showTooltip && (\n <span className=\"gvp-tooltip\" role=\"tooltip\">\n {tooltipText}\n </span>\n )}\n </button>\n </div>\n )}\n\n <div className=\"gvp-bottom-fade\" />\n </div>\n );\n};\n\nexport default VideoPlayerWrapper;\n"],"names":["r","t","f","n","o","clsx","HLSPlayer","React","src","hlsConfig","isHls","children","videoProps","forwardedRef","internalRef","useRef","hlsRef","useImperativeHandle","canUseHlsJs","Hls","shouldUseHls","useEffect","videoEl","hls","_evt","data","baseClass","cls","extra","IconDesktop","className","jsxs","jsx","IconMobile","IconX","IconPlay","VideoPlayerWrapper","poster","showDeviceToggle","defaultDevice","hoverPlay","tooltipText","onClose","muted","loop","controls","customFrameMaxWidth","customAspectRatio","videoRef","playPromiseRef","device","setDevice","useState","isPlaying","setIsPlaying","showTooltip","setShowTooltip","aspectRatio","useMemo","frameMaxWidth","safePause","useCallback","el","safePlay","p","hoverStart","hoverStop","togglePlay"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"index.mjs","sources":["../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/HLSPlayer.tsx","../src/utils/icons.tsx","../src/utils/youtube.ts","../src/VideoPlayerWrapper.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","\"use client\";\n\nimport Hls from \"hls.js\";\nimport React, { useEffect, useImperativeHandle, useRef } from \"react\";\nimport type { HLSPlayerProps } from \"./types\";\n\nexport const HLSPlayer = React.forwardRef<HTMLVideoElement, HLSPlayerProps>(\n ({ src, hlsConfig, isHls, children, ...videoProps }, forwardedRef) => {\n const internalRef = useRef<HTMLVideoElement | null>(null);\n const hlsRef = useRef<Hls | null>(null);\n\n useImperativeHandle(forwardedRef, () => internalRef.current as HTMLVideoElement);\n\n const canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\n const shouldUseHls =\n Boolean(isHls) || (canUseHlsJs && typeof src === \"string\" && src.endsWith(\".m3u8\"));\n\n useEffect(() => {\n if (!src) return;\n const videoEl = internalRef.current;\n if (!videoEl) return;\n\n // destroy previous\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n\n // reset video element\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n\n if (shouldUseHls) {\n const hls = new Hls(hlsConfig);\n hlsRef.current = hls;\n\n hls.attachMedia(videoEl);\n hls.loadSource(src);\n\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsRef.current = null;\n }\n });\n } else {\n // native playback\n videoEl.src = src;\n videoEl.load();\n }\n\n return () => {\n if (hlsRef.current) {\n hlsRef.current.destroy();\n hlsRef.current = null;\n }\n videoEl.pause();\n videoEl.removeAttribute(\"src\");\n while (videoEl.firstChild) videoEl.firstChild.remove();\n videoEl.load();\n };\n }, [src, shouldUseHls, hlsConfig]);\n\n // Captions are the consumer's responsibility — pass <track> elements as children.\n // NOSONAR: typescript:S4084\n return (\n <video ref={internalRef} {...videoProps}>\n {children}\n </video>\n );\n }\n);\n\nHLSPlayer.displayName = \"HLSPlayer\";\nexport default HLSPlayer;\n","\"use client\";\n\nimport React from \"react\";\n\ntype IconProps = { className?: string };\n\nconst baseClass = \"gvp-icon\";\nconst cls = (extra?: string) => (extra ? `${baseClass} ${extra}` : baseClass);\n\nexport const IconDesktop: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path d=\"M7 22H17\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n);\n\nexport const IconMobile: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const IconX: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const IconPlay: React.FC<IconProps> = ({ className }) => (\n <svg\n className={cls(className)}\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","/**\n * Extract a YouTube video ID from any common URL form, or `null` if the URL\n * isn't a YouTube link.\n *\n * Recognised:\n * - https://www.youtube.com/watch?v=ID\n * - https://youtube.com/watch?v=ID&t=42\n * - https://youtu.be/ID\n * - https://youtu.be/ID?t=42\n * - https://www.youtube.com/embed/ID\n * - https://www.youtube.com/shorts/ID\n * - https://music.youtube.com/watch?v=ID\n * - bare 11-character video IDs\n */\nexport function parseYouTubeId(input: string): string | null {\n if (!input) return null;\n\n // Bare 11-char ID (YouTube IDs are [A-Za-z0-9_-]{11}).\n if (/^[A-Za-z0-9_-]{11}$/.test(input)) return input;\n\n let url: URL;\n try {\n url = new URL(input);\n } catch {\n return null;\n }\n\n const host = url.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtu.be\") {\n const id = url.pathname.slice(1).split(\"/\")[0];\n return /^[A-Za-z0-9_-]{11}$/.test(id) ? id : null;\n }\n\n if (\n host === \"youtube.com\" ||\n host === \"m.youtube.com\" ||\n host === \"music.youtube.com\" ||\n host === \"youtube-nocookie.com\"\n ) {\n // /watch?v=ID\n const v = url.searchParams.get(\"v\");\n if (v && /^[A-Za-z0-9_-]{11}$/.test(v)) return v;\n\n // /embed/ID, /shorts/ID, /v/ID, /live/ID\n const m = /^\\/(?:embed|shorts|v|live)\\/([A-Za-z0-9_-]{11})/.exec(\n url.pathname\n );\n if (m) return m[1];\n }\n\n return null;\n}\n\n/** Extract a `t`/`start` timestamp (in seconds) from a YouTube URL, if present. */\nexport function parseYouTubeStart(input: string): number | null {\n try {\n const url = new URL(input);\n const t = url.searchParams.get(\"t\") ?? url.searchParams.get(\"start\");\n if (!t) return null;\n // Supports \"90\", \"90s\", \"1m30s\", \"1h2m3s\".\n if (/^\\d+s?$/.test(t)) return Number.parseInt(t, 10);\n const m = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/.exec(t);\n if (m) {\n const h = Number.parseInt(m[1] ?? \"0\", 10);\n const min = Number.parseInt(m[2] ?? \"0\", 10);\n const s = Number.parseInt(m[3] ?? \"0\", 10);\n const total = h * 3600 + min * 60 + s;\n return total > 0 ? total : null;\n }\n } catch {\n /* not a URL */\n }\n return null;\n}\n\nexport interface YouTubeEmbedOptions {\n /** Start playback immediately. Forces `mute` on, since browsers block sound-on autoplay. */\n autoPlay?: boolean;\n /** Mute the player. */\n muted?: boolean;\n /** Loop the video. */\n loop?: boolean;\n /** Show YouTube's player controls. Defaults to `true`. */\n controls?: boolean;\n /** Start offset in seconds. */\n startSeconds?: number | null;\n}\n\n/**\n * Build a privacy-enhanced YouTube embed URL from a video ID and player options.\n *\n * Notes on YouTube's quirks:\n * - `autoplay=1` only takes effect if `mute=1` is also set (browser policy).\n * - single-video loop requires `loop=1` **and** `playlist=<id>`.\n */\nexport function youTubeEmbedUrl(id: string, opts: YouTubeEmbedOptions = {}): string {\n const { autoPlay = false, muted = true, loop = false, controls = true, startSeconds } = opts;\n\n const params = new URLSearchParams({\n rel: \"0\",\n modestbranding: \"1\",\n playsinline: \"1\",\n controls: controls ? \"1\" : \"0\",\n });\n\n if (autoPlay) {\n params.set(\"autoplay\", \"1\");\n params.set(\"mute\", \"1\"); // required for autoplay to actually fire\n } else if (muted) {\n params.set(\"mute\", \"1\");\n }\n\n if (loop) {\n params.set(\"loop\", \"1\");\n params.set(\"playlist\", id); // YouTube needs this for single-video loop\n }\n\n if (startSeconds && startSeconds > 0) {\n params.set(\"start\", String(startSeconds));\n }\n\n return `https://www.youtube-nocookie.com/embed/${id}?${params.toString()}`;\n}\n","\"use client\";\n\nimport clsx from \"clsx\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport { HLSPlayer } from \"./HLSPlayer\";\nimport type { DeviceMode, VideoPlayerWrapperProps } from \"./types\";\nimport { IconDesktop, IconMobile, IconPlay, IconX } from \"./utils/icons\";\nimport { parseYouTubeId, parseYouTubeStart, youTubeEmbedUrl } from \"./utils/youtube\";\n\nexport const VideoPlayerWrapper: React.FC<VideoPlayerWrapperProps> = ({\n src,\n poster,\n showDeviceToggle = true,\n defaultDevice = \"desktop\",\n hoverPlay = false,\n tooltipText,\n onClose,\n className = \"\",\n muted = true,\n loop = false,\n controls = false,\n autoPlay = false,\n frameMaxWidth: customFrameMaxWidth,\n aspectRatio: customAspectRatio,\n hlsConfig,\n children,\n}) => {\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const playPromiseRef = useRef<Promise<void> | null>(null);\n\n const [device, setDevice] = useState<DeviceMode>(defaultDevice);\n const [isPlaying, setIsPlaying] = useState(false);\n const [showTooltip, setShowTooltip] = useState(false);\n\n const youTubeId = useMemo(() => parseYouTubeId(src), [src]);\n const isYouTube = youTubeId !== null;\n\n const aspectRatio = useMemo(() => {\n return device === \"mobile\"\n ? (customAspectRatio?.mobile ?? \"9/16\")\n : (customAspectRatio?.desktop ?? \"16/9\");\n }, [device, customAspectRatio]);\n\n const frameMaxWidth = useMemo(() => {\n return device === \"mobile\"\n ? (customFrameMaxWidth?.mobile ?? \"420px\")\n : (customFrameMaxWidth?.desktop ?? \"960px\");\n }, [device, customFrameMaxWidth]);\n\n const youTubeSrc = useMemo(\n () =>\n youTubeId\n ? youTubeEmbedUrl(youTubeId, {\n autoPlay,\n muted,\n loop,\n controls,\n startSeconds: parseYouTubeStart(src),\n })\n : null,\n [youTubeId, src, autoPlay, muted, loop, controls]\n );\n\n const safePause = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (playPromiseRef.current) {\n try {\n await playPromiseRef.current;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n }, []);\n\n const safePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromiseRef.current = p;\n await p;\n setIsPlaying(true);\n } catch {\n setIsPlaying(false);\n } finally {\n playPromiseRef.current = null;\n }\n }, []);\n\n const hoverStart = useCallback(() => {\n if (!hoverPlay || isYouTube) return;\n void safePlay();\n }, [hoverPlay, isYouTube, safePlay]);\n\n const hoverStop = useCallback(() => {\n if (!hoverPlay || isYouTube) return;\n void safePause().then(() => setIsPlaying(false));\n }, [hoverPlay, isYouTube, safePause]);\n\n const togglePlay = useCallback(async () => {\n const el = videoRef.current;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n setIsPlaying(false);\n }\n }, [safePlay, safePause]);\n\n return (\n // The mouse handlers are a progressive enhancement (hoverPlay + tooltip).\n // Keyboard/click users reach the same actions via the inner <button> elements,\n // so the outer container is intentionally non-interactive at the role level.\n // NOSONAR: typescript:S6848\n <div\n className={clsx(\"gvp-root\", className)}\n style={{ width: frameMaxWidth, aspectRatio }}\n onMouseEnter={() => {\n setShowTooltip(true);\n hoverStart();\n }}\n onMouseLeave={() => {\n setShowTooltip(false);\n hoverStop();\n }}\n >\n {isYouTube ? (\n <iframe\n className=\"gvp-video gvp-youtube\"\n src={youTubeSrc ?? undefined}\n title=\"YouTube video player\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowFullScreen\n referrerPolicy=\"strict-origin-when-cross-origin\"\n />\n ) : (\n <HLSPlayer\n ref={videoRef}\n src={src}\n poster={poster}\n muted={muted}\n loop={loop}\n playsInline\n preload=\"metadata\"\n controls={controls}\n autoPlay={autoPlay}\n hlsConfig={hlsConfig}\n className=\"gvp-video\"\n onPlay={() => setIsPlaying(true)}\n onPause={() => setIsPlaying(false)}\n >\n {children}\n </HLSPlayer>\n )}\n\n {!isYouTube && <div className=\"gvp-vignette\" />}\n\n {showDeviceToggle && (\n <div className=\"gvp-toggle\">\n <div className=\"gvp-toggle-pill\">\n <button\n type=\"button\"\n onClick={() => setDevice(\"desktop\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"desktop\" && \"is-active\"\n )}\n aria-label=\"Desktop view\"\n aria-pressed={device === \"desktop\"}\n >\n <IconDesktop />\n </button>\n\n <div className=\"gvp-toggle-divider\" />\n\n <button\n type=\"button\"\n onClick={() => setDevice(\"mobile\")}\n className={clsx(\n \"gvp-toggle-btn\",\n device === \"mobile\" && \"is-active\"\n )}\n aria-label=\"Mobile view\"\n aria-pressed={device === \"mobile\"}\n >\n <IconMobile />\n </button>\n </div>\n </div>\n )}\n\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"gvp-close\"\n aria-label=\"Close\"\n >\n <IconX />\n </button>\n )}\n\n {!isYouTube && !isPlaying && (\n <div className=\"gvp-play-wrap\">\n <button\n type=\"button\"\n onClick={() => void togglePlay()}\n onMouseEnter={() => setShowTooltip(true)}\n onMouseLeave={() => setShowTooltip(false)}\n className=\"gvp-play\"\n aria-label=\"Play\"\n >\n <IconPlay />\n {tooltipText && showTooltip && (\n <span className=\"gvp-tooltip\" role=\"tooltip\">\n {tooltipText}\n </span>\n )}\n </button>\n </div>\n )}\n\n {!isYouTube && <div className=\"gvp-bottom-fade\" />}\n </div>\n );\n};\n\nexport default VideoPlayerWrapper;\n"],"names":["r","t","f","n","o","clsx","HLSPlayer","React","src","hlsConfig","isHls","children","videoProps","forwardedRef","internalRef","useRef","hlsRef","useImperativeHandle","canUseHlsJs","Hls","shouldUseHls","useEffect","videoEl","hls","_evt","data","baseClass","cls","extra","IconDesktop","className","jsxs","jsx","IconMobile","IconX","IconPlay","parseYouTubeId","input","url","host","id","v","m","parseYouTubeStart","h","min","s","total","youTubeEmbedUrl","opts","autoPlay","muted","loop","controls","startSeconds","params","VideoPlayerWrapper","poster","showDeviceToggle","defaultDevice","hoverPlay","tooltipText","onClose","customFrameMaxWidth","customAspectRatio","videoRef","playPromiseRef","device","setDevice","useState","isPlaying","setIsPlaying","showTooltip","setShowTooltip","youTubeId","useMemo","isYouTube","aspectRatio","frameMaxWidth","youTubeSrc","safePause","useCallback","el","safePlay","p","hoverStart","hoverStop","togglePlay"],"mappings":"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","x_google_ignoreList":[0]}
package/dist/style.css CHANGED
@@ -1,4 +1,4 @@
1
1
  /*!
2
2
  * @glitchlab/react-video-player styles
3
3
  * Scoped under .gvp-root — no global resets, no theme tokens, safe for any host.
4
- */.gvp-root{position:relative;overflow:hidden;border-radius:1.5rem;background-color:#1717174d;box-shadow:0 25px 50px -12px #00000040;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;margin-left:auto;margin-right:auto;width:100%;box-sizing:border-box}.gvp-root *,.gvp-root *:before,.gvp-root *:after{box-sizing:border-box}.gvp-video{height:100%;width:100%;object-fit:cover;display:block}.gvp-vignette{pointer-events:none;position:absolute;top:0;right:0;bottom:0;left:0;background-image:linear-gradient(to top right,#00000059,#0000,#00000059)}.gvp-bottom-fade{pointer-events:none;position:absolute;bottom:0;left:0;right:0;height:4rem;background-image:linear-gradient(to top,rgb(0 0 0 / .35),transparent)}.gvp-toggle{position:absolute;left:1rem;top:1rem}.gvp-toggle-pill{display:flex;align-items:center;overflow:hidden;border-radius:1rem;background-color:#fffffff2;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(0 0 0 / .05);outline-offset:-1px}.gvp-toggle-btn{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;font-weight:600;cursor:pointer;background:transparent;border:0;color:#737373;transition:color .15s ease;font-family:inherit}.gvp-toggle-btn:hover{color:#404040}.gvp-toggle-btn.is-active{color:#5b21b6}.gvp-toggle-divider{height:1.75rem;width:1px;background-color:#e5e5e5}.gvp-close{position:absolute;right:1rem;top:1rem;display:grid;place-items:center;height:2.5rem;width:2.5rem;border:0;border-radius:9999px;background-color:#00000059;color:#fff;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;cursor:pointer;z-index:10;transition:background-color .15s ease}.gvp-close:hover{background-color:#00000080}.gvp-play-wrap{position:absolute;top:0;right:0;bottom:0;left:0;display:grid;place-items:center}.gvp-play{position:relative;display:grid;place-items:center;height:3.5rem;width:3.5rem;border:0;border-radius:9999px;cursor:pointer;outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;background-color:#5b21b680;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;transition:background-color .2s ease,opacity .2s ease;color:#fff}.gvp-play:hover{background-color:#5b21b6e6}.gvp-tooltip{position:absolute;top:-3rem;left:50%;transform:translate(-50%);white-space:nowrap;border-radius:.75rem;background-color:#000000b3;padding:.375rem .75rem;font-size:.75rem;line-height:1rem;color:#fff;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.gvp-icon{display:block}
4
+ */.gvp-root{position:relative;overflow:hidden;border-radius:1.5rem;background-color:#1717174d;box-shadow:0 25px 50px -12px #00000040;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;margin-left:auto;margin-right:auto;width:100%;box-sizing:border-box}.gvp-root *,.gvp-root *:before,.gvp-root *:after{box-sizing:border-box}.gvp-video{height:100%;width:100%;object-fit:cover;display:block}.gvp-youtube{border:0;object-fit:contain}.gvp-vignette{pointer-events:none;position:absolute;top:0;right:0;bottom:0;left:0;background-image:linear-gradient(to top right,#00000059,#0000,#00000059)}.gvp-bottom-fade{pointer-events:none;position:absolute;bottom:0;left:0;right:0;height:4rem;background-image:linear-gradient(to top,rgb(0 0 0 / .35),transparent)}.gvp-toggle{position:absolute;left:1rem;top:1rem}.gvp-toggle-pill{display:flex;align-items:center;overflow:hidden;border-radius:1rem;background-color:#fffffff2;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(0 0 0 / .05);outline-offset:-1px}.gvp-toggle-btn{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;font-weight:600;cursor:pointer;background:transparent;border:0;color:#737373;transition:color .15s ease;font-family:inherit}.gvp-toggle-btn:hover{color:#404040}.gvp-toggle-btn.is-active{color:#5b21b6}.gvp-toggle-divider{height:1.75rem;width:1px;background-color:#e5e5e5}.gvp-close{position:absolute;right:1rem;top:1rem;display:grid;place-items:center;height:2.5rem;width:2.5rem;border:0;border-radius:9999px;background-color:#00000059;color:#fff;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;cursor:pointer;z-index:10;transition:background-color .15s ease}.gvp-close:hover{background-color:#00000080}.gvp-play-wrap{position:absolute;top:0;right:0;bottom:0;left:0;display:grid;place-items:center}.gvp-play{position:relative;display:grid;place-items:center;height:3.5rem;width:3.5rem;border:0;border-radius:9999px;cursor:pointer;outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;background-color:#5b21b680;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;transition:background-color .2s ease,opacity .2s ease;color:#fff}.gvp-play:hover{background-color:#5b21b6e6}.gvp-tooltip{position:absolute;top:-3rem;left:50%;transform:translate(-50%);white-space:nowrap;border-radius:.75rem;background-color:#000000b3;padding:.375rem .75rem;font-size:.75rem;line-height:1rem;color:#fff;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.gvp-icon{display:block}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glitchlab/react-video-player",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "React video player with HLS support (hls.js), device-mode toggle, hover-to-play, and zero global CSS side-effects. Works with Next.js App Router and TypeScript.",
5
5
  "license": "MIT",
6
6
  "author": "im-fahad",