diff --git a/examples/nextjs/app/wistia-video/page.tsx b/examples/nextjs/app/wistia-video/page.tsx
index 4c140cff..c569555c 100644
--- a/examples/nextjs/app/wistia-video/page.tsx
+++ b/examples/nextjs/app/wistia-video/page.tsx
@@ -13,6 +13,9 @@ export default function Page() {
>
diff --git a/packages/wistia-video-element/test/test.js b/packages/wistia-video-element/test/test.js
index 54e4b2d1..7aff4979 100644
--- a/packages/wistia-video-element/test/test.js
+++ b/packages/wistia-video-element/test/test.js
@@ -61,7 +61,7 @@ test('load promise', async function (t) {
await video.loadComplete;
t.ok(
- loadComplete != video.loadComplete,
+ loadComplete !== video.loadComplete,
'creates a new promise after new src'
);
@@ -86,6 +86,52 @@ test('play promise', async function (t) {
t.ok(!video.paused, 'is playing after video.play()');
});
+test('passes config into Wistia options', async function (t) {
+ const previousWistia = globalThis.Wistia;
+ const previousWq = globalThis._wq;
+
+ try {
+ globalThis.Wistia = {};
+
+ const fakeApi = {
+ elem: () => document.createElement('video'),
+ duration: () => 0,
+ play: () => {},
+ bigPlayButtonEnabled: () => {},
+ releaseChromeless: () => {},
+ requestChromeless: () => {},
+ };
+
+ let pushed;
+ globalThis._wq = {
+ push: (payload) => {
+ pushed = payload;
+ payload.onReady(fakeApi);
+ },
+ };
+
+ const video = await fixture(``);
+
+ // Ensure user config takes precedence over element-derived defaults.
+ video.config = {
+ chromeless: true,
+ playButton: false,
+ playerColor: 'ff0000',
+ };
+
+ video.src = 'https://wesleyluyten.wistia.com/medias/oifkgmxnkb';
+ await video.loadComplete;
+
+ t.ok(pushed?.options, 'push payload includes options');
+ t.equal(pushed.options.chromeless, true, 'config overrides default chromeless');
+ t.equal(pushed.options.playButton, false, 'config overrides default playButton');
+ t.equal(pushed.options.playerColor, 'ff0000', 'config is forwarded into options');
+ } finally {
+ globalThis.Wistia = previousWistia;
+ globalThis._wq = previousWq;
+ }
+});
+
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
diff --git a/packages/wistia-video-element/wistia-video-element.d.ts b/packages/wistia-video-element/wistia-video-element.d.ts
index 67fc775e..182ecf57 100644
--- a/packages/wistia-video-element/wistia-video-element.d.ts
+++ b/packages/wistia-video-element/wistia-video-element.d.ts
@@ -1,10 +1,55 @@
+export type WistiaPluginConfig = Record;
+
+export type WistiaEmbedOptions = {
+ autoPlay?: boolean;
+ controlsVisibleOnLoad?: boolean;
+ copyLinkAndThumbnailEnabled?: boolean;
+ doNotTrack?: boolean;
+ email?: string;
+ endVideoBehavior?: 'default' | 'reset' | 'loop';
+ fakeFullscreen?: boolean;
+ fitStrategy?: 'contain' | 'cover' | 'fill' | 'none';
+ fullscreenButton?: boolean;
+ muted?: boolean;
+ playbackRateControl?: boolean;
+ playbar?: boolean;
+ playButton?: boolean;
+ playerColor?: string;
+ playlistLinks?: boolean;
+ playlistLoop?: boolean;
+ playsinline?: boolean;
+ playPauseNotifier?: boolean;
+ playSuspendedOffScreen?: boolean;
+ preload?: 'metadata' | 'auto' | 'none' | boolean;
+ qualityControl?: boolean;
+ qualityMax?: 224 | 360 | 540 | 720 | 1080 | 3840;
+ qualityMin?: 224 | 360 | 540 | 720 | 1080 | 3840;
+ resumable?: boolean | 'auto';
+ seo?: boolean;
+ settingsControl?: boolean;
+ silentAutoPlay?: boolean | 'allow';
+ smallPlayButton?: boolean;
+ stillUrl?: string;
+ time?: number | string;
+ thumbnailAltText?: string;
+ videoFoam?:
+ | boolean
+ | {
+ minWidth?: number;
+ maxWidth?: number;
+ minHeight?: number;
+ maxHeight?: number;
+ };
+ volume?: number;
+ volumeControl?: boolean;
+ wmode?: string;
+ plugin?: WistiaPluginConfig;
+};
+
export default class CustomVideoElement extends HTMLVideoElement {
static readonly observedAttributes: string[];
- attributeChangedCallback(
- attrName: string,
- oldValue?: string | null,
- newValue?: string | null
- ): void;
+ attributeChangedCallback(attrName: string, oldValue?: string | null, newValue?: string | null): void;
connectedCallback(): void;
disconnectedCallback(): void;
+ config: WistiaEmbedOptions | null;
}
diff --git a/packages/wistia-video-element/wistia-video-element.js b/packages/wistia-video-element/wistia-video-element.js
index 7a8555c3..99aa64da 100644
--- a/packages/wistia-video-element/wistia-video-element.js
+++ b/packages/wistia-video-element/wistia-video-element.js
@@ -28,10 +28,38 @@ if (templateShadowDOM) {
`;
}
+function upgradeProperty(el, prop) {
+ // This is a pattern to update property values that are set before
+ // the custom element is upgraded.
+ // https://web.dev/custom-elements-best-practices/#make-properties-lazy
+ if (Object.hasOwn(el, prop)) {
+ const value = el[prop];
+ // Delete the set property from this instance.
+ delete el[prop];
+ // Set the value again via the (prototype) setter on this class.
+ el[prop] = value;
+ }
+}
+
class WistiaVideoElement extends SuperVideoElement {
static template = templateShadowDOM;
static skipAttributes = ['src'];
+ #config = null;
+
+ constructor() {
+ super();
+ upgradeProperty(this, 'config');
+ }
+
+ get config() {
+ return this.#config;
+ }
+
+ set config(value) {
+ this.#config = value;
+ }
+
get nativeEl() {
return this.api?.elem() ?? this.querySelector('video');
}
@@ -58,6 +86,7 @@ class WistiaVideoElement extends SuperVideoElement {
chromeless: !this.controls,
playButton: this.controls,
muted: this.defaultMuted,
+ ...(this.#config ?? {}),
};
// Sadly the setup/render will not work in the shadow DOM.
@@ -119,14 +148,16 @@ async function loadScript(src, globalName) {
if (!globalName) return import(/* webpackIgnore: true */ src);
if (loadScriptCache[src]) return loadScriptCache[src];
if (self[globalName]) return self[globalName];
- return (loadScriptCache[src] = new Promise((resolve, reject) => {
+ const promise = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.defer = true;
script.src = src;
script.onload = () => resolve(self[globalName]);
script.onerror = reject;
document.head.append(script);
- }));
+ });
+ loadScriptCache[src] = promise;
+ return promise;
}
let idCounter = 0;