feat(html): integrate fullscreen button into control bar and improve container lifecycle

Complete fullscreen button integration:
- Add fullscreen button to media-skin-default control bar as rightmost control
- Icon styling follows play/pause pattern with proper state-based visibility
- Container state owner lifecycle management in media-container component
- Component factory passes mediaStore reference to support advanced integrations

Control bar layout: Play → Time → Mute → Volume → Fullscreen
Icons change appropriately based on [data-fullscreen] attribute state.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Christian Pillsbury
2025-09-12 08:06:08 -07:00
committed by Christian Pillsbury
co-authored by Claude
parent 7d819dfcd9
commit 465342e431
3 changed files with 33 additions and 1 deletions
+21
View File
@@ -19,6 +19,7 @@ export class MediaContainer extends ConsumerMixin(HTMLElement) {
mediaStore: (mediaStore: any) => {
this._mediaStore = mediaStore;
this._handleMediaSlotChange();
this._registerContainerStateOwner();
},
};
@@ -38,6 +39,26 @@ export class MediaContainer extends ConsumerMixin(HTMLElement) {
this._mediaSlot.addEventListener('slotchange', this._handleMediaSlotChange);
}
connectedCallback() {
super.connectedCallback?.();
this._registerContainerStateOwner();
}
disconnectedCallback() {
super.disconnectedCallback?.();
this._unregisterContainerStateOwner();
}
_registerContainerStateOwner = () => {
if (!this._mediaStore) return;
this._mediaStore.dispatch({ type: 'containerstateownerchangerequest', detail: this });
};
_unregisterContainerStateOwner = () => {
if (!this._mediaStore) return;
this._mediaStore.dispatch({ type: 'containerstateownerchangerequest', detail: null });
};
_handleMediaSlotChange = () => {
const media = this._mediaSlot.assignedElements({ flatten: true })[0];
this._mediaStore.dispatch({ type: 'mediastateownerchangerequest', detail: media });
@@ -5,6 +5,7 @@ import '../components/media-play-button';
import '../components/media-mute-button';
import '../components/media-volume-range';
import '../components/media-time-range';
import '../components/media-fullscreen-button';
import '@vjs-10/html-icons';
export function getTemplateHTML() {
@@ -60,6 +61,12 @@ export function getTemplateHTML() {
display: inline-block;
}
/* Media Fullscreen Button UI/Styles */
media-fullscreen-button:not([data-fullscreen]) .fullscreen-enter-icon,
media-fullscreen-button[data-fullscreen] .fullscreen-exit-icon {
display: inline-block;
}
/* One way to define the "default visible" icon (CJP) */
media-mute-button:not([data-volume-level]) .volume-low-icon,
media-mute-button[data-volume-level=high] .volume-high-icon,
@@ -98,6 +105,10 @@ export function getTemplateHTML() {
<media-volume-off-icon class="icon volume-off-icon"></media-volume-off-icon>
</media-mute-button>
<media-volume-range></media-volume-range>
<media-fullscreen-button class="button">
<media-fullscreen-enter-icon class="icon fullscreen-enter-icon"></media-fullscreen-enter-icon>
<media-fullscreen-exit-icon class="icon fullscreen-exit-icon"></media-fullscreen-exit-icon>
</media-fullscreen-button>
</div>
</div>
</media-container>
@@ -52,7 +52,7 @@ export const toConnectedHTMLComponent = <TState = any>(
// @ts-ignore - Element property access
const props = propsHook(state ?? {}, this);
// @ts-ignore
this._update(props, state);
this._update(props, state, mediaStore);
});
},
};