From f005846b2813eb4652b72ea2b428498f37af46bb Mon Sep 17 00:00:00 2001 From: ceyhun-o Date: Wed, 16 Sep 2026 08:58:59 +0200 Subject: [PATCH 1/3] Preserve user text track margins Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- src/UIContainer.ts | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/UIContainer.ts b/src/UIContainer.ts index 6cda4257..547e91cd 100644 --- a/src/UIContainer.ts +++ b/src/UIContainer.ts @@ -49,6 +49,11 @@ export const DEFAULT_TV_USER_IDLE_TIMEOUT = 5; export const DEFAULT_DVR_THRESHOLD = 60; export const FULL_WINDOW_ROOT_CLASS = 'theoplayer-ui-full-window'; +interface TextTrackMargins { + marginTop: number | undefined; + marginBottom: number | undefined; +} + /** * The container element for a THEOplayer UI. * @@ -154,6 +159,9 @@ export class UIContainer extends LitElement { private _hasFirstPlay: boolean = false; private _previewTime: number = NaN; private _activeVideoTrack: MediaTrack | undefined = undefined; + // Track user margins separately so temporary UI margins can be restored. + private _userTextTrackMargins: TextTrackMargins = { marginTop: undefined, marginBottom: undefined }; + private _appliedTextTrackMargins: TextTrackMargins = { marginTop: undefined, marginBottom: undefined }; /** * Creates a new THEOplayer UI container element. @@ -568,6 +576,9 @@ export class UIContainer extends LitElement { } this._player = new ChromelessPlayer(this._playerRef.value, this._configuration); + const { marginTop, marginBottom } = this._player.textTrackStyle; + this._userTextTrackMargins = { marginTop, marginBottom }; + this._appliedTextTrackMargins = { marginTop, marginBottom }; if (this._source) { this._player.source = this._source; this._source = undefined; @@ -1271,10 +1282,32 @@ export class UIContainer extends LitElement { if (player === undefined) { return; } + const textTrackStyle = player.textTrackStyle; + const userMargins = this._userTextTrackMargins; + const appliedMargins = this._appliedTextTrackMargins; + // A value different from the last UI update was set by the user. + if (textTrackStyle.marginTop !== appliedMargins.marginTop) { + userMargins.marginTop = textTrackStyle.marginTop; + } + if (textTrackStyle.marginBottom !== appliedMargins.marginBottom) { + userMargins.marginBottom = textTrackStyle.marginBottom; + } + const topChromeRect = this._topChromeSlotRef.value && getVisibleRect(this._topChromeSlotRef.value); const bottomChromeRect = this._bottomChromeSlotRef.value && getVisibleRect(this._bottomChromeSlotRef.value); - player.textTrackStyle.marginTop = topChromeRect?.height; - player.textTrackStyle.marginBottom = bottomChromeRect?.height; + // Keep cues clear of visible chrome without reducing user margins. + const margins: TextTrackMargins = { + marginTop: maxMargin(userMargins.marginTop, topChromeRect?.height), + marginBottom: maxMargin(userMargins.marginBottom, bottomChromeRect?.height) + }; + + if (textTrackStyle.marginTop !== margins.marginTop) { + textTrackStyle.marginTop = margins.marginTop; + } + if (textTrackStyle.marginBottom !== margins.marginBottom) { + textTrackStyle.marginBottom = margins.marginBottom; + } + this._appliedTextTrackMargins = margins; }; private readonly _onPreviewTimeChange = (rawEvent: Event): void => { @@ -1396,6 +1429,12 @@ declare global { } } +function maxMargin(first: number | undefined, second: number | undefined): number | undefined { + if (first === undefined) return second; + if (second === undefined) return first; + return Math.max(first, second); +} + function getVisibleRect(slot: HTMLSlotElement): Rectangle | undefined { let result: Rectangle | undefined; const children = getSlottedElements(slot).filter(isHTMLElement); From eed2d5c72a90f18a528bb23a880b84e4395487eb Mon Sep 17 00:00:00 2001 From: ceyhun-o Date: Wed, 16 Sep 2026 08:59:07 +0200 Subject: [PATCH 2/3] Expose example player for testing Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- examples/default-ui.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/default-ui.html b/examples/default-ui.html index 0340e111..049d1ec7 100644 --- a/examples/default-ui.html +++ b/examples/default-ui.html @@ -91,6 +91,9 @@

Default UI