--- name: screenfull-fullscreen-api description: Implement fullscreen functionality using screenfull library for cross-browser fullscreen support in ng-events project license: MIT --- # Screenfull Fullscreen API Skill This skill guides the implementation of fullscreen functionality using the screenfull library in the ng-events construction site management system. ## When to Use This Skill **Triggers**: "fullscreen", "screenfull", "full screen mode", "toggle fullscreen", "exit fullscreen" Use this skill when: - Adding fullscreen toggle buttons - Creating fullscreen viewers (images, videos, dashboards) - Implementing presentation modes - Building immersive UI experiences - Providing fullscreen for specific components ## Installation & Setup ```bash # Already installed in package.json yarn add screenfull@^6.0.2 ``` ## Core Patterns ### 1. Basic Fullscreen Toggle ```typescript import { Component, inject, signal } from '@angular/core'; import screenfull from 'screenfull'; @Component({ selector: 'app-fullscreen-toggle', standalone: true, template: ` ` }) export class FullscreenToggleComponent { isFullscreen = signal(false); toggleFullscreen(): void { if (screenfull.isEnabled) { screenfull.toggle(); this.updateFullscreenState(); // Listen for fullscreen changes screenfull.on('change', () => { this.updateFullscreenState(); }); } else { console.warn('Fullscreen API not supported'); } } private updateFullscreenState(): void { this.isFullscreen.set(screenfull.isFullscreen); } } ``` ### 2. Fullscreen Specific Element ```typescript import { Component, ElementRef, ViewChild, signal } from '@angular/core'; import screenfull from 'screenfull'; @Component({ selector: 'app-dashboard-fullscreen', standalone: true, template: `

Construction Progress Dashboard

`, styles: [` .dashboard-container { position: relative; background: white; padding: 20px; } .dashboard-container:-webkit-full-screen { background: #1f1f1f; color: white; } .dashboard-container:fullscreen { background: #1f1f1f; color: white; } .btn-fullscreen { position: absolute; top: 20px; right: 20px; } `] }) export class DashboardFullscreenComponent { @ViewChild('dashboardContainer', { static: true }) container!: ElementRef; isFullscreen = signal(false); toggleFullscreen(): void { if (screenfull.isEnabled) { screenfull.toggle(this.container.nativeElement); screenfull.on('change', () => { this.isFullscreen.set(screenfull.isFullscreen); }); } } } ``` ### 3. Image Gallery Fullscreen ```typescript import { Component, signal } from '@angular/core'; import screenfull from 'screenfull'; import { NzImageModule } from 'ng-zorro-antd/image'; @Component({ selector: 'app-construction-photos', standalone: true, imports: [NzImageModule], template: ` @if (currentPhoto()) {

{{ currentPhoto()!.title }}

{{ currentPhoto()!.description }}

{{ currentPhoto()!.date | date }}
} `, styles: [` .photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; } .photo-item { position: relative; cursor: pointer; overflow: hidden; border-radius: 4px; } .photo-item img { width: 100%; height: 200px; object-fit: cover; transition: transform 0.3s; } .photo-item:hover img { transform: scale(1.1); } .photo-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.3s; } .photo-item:hover .photo-overlay { opacity: 1; } .fullscreen-viewer { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.95); display: flex; align-items: center; justify-content: center; z-index: 9999; } .fullscreen-viewer img { max-width: 90%; max-height: 90%; object-fit: contain; } .close-btn { position: absolute; top: 20px; right: 20px; background: rgba(255, 255, 255, 0.2); border: none; color: white; font-size: 24px; cursor: pointer; padding: 10px; border-radius: 4px; } .photo-info { position: absolute; bottom: 20px; left: 20px; color: white; text-align: left; } `] }) export class ConstructionPhotosComponent { photos = signal([ { id: '1', title: 'Foundation Work', description: 'Foundation concrete pouring', thumbnailUrl: 'assets/photos/thumb1.jpg', fullUrl: 'assets/photos/full1.jpg', date: new Date() } // ... more photos ]); currentPhoto = signal(null); viewFullscreen(photo: Photo): void { this.currentPhoto.set(photo); if (screenfull.isEnabled) { const viewer = document.querySelector('.fullscreen-viewer'); if (viewer) { screenfull.request(viewer as HTMLElement); screenfull.on('change', () => { if (!screenfull.isFullscreen) { this.currentPhoto.set(null); } }); } } } exitFullscreen(): void { if (screenfull.isEnabled && screenfull.isFullscreen) { screenfull.exit(); } this.currentPhoto.set(null); } } ``` ### 4. Presentation Mode ```typescript import { Component, signal, OnInit, OnDestroy } from '@angular/core'; import screenfull from 'screenfull'; @Component({ selector: 'app-presentation-mode', standalone: true, template: `

{{ currentSlide().title }}

{{ currentSlideIndex() + 1 }} / {{ slides().length }}
`, styles: [` .presentation-container { background: white; padding: 20px; } .presentation-active { background: #1a1a1a; color: white; padding: 40px; } .presentation-active .slide-content { font-size: 1.5em; } `] }) export class PresentationModeComponent implements OnInit, OnDestroy { slides = signal([ { title: 'Project Overview', content: '

Construction Site Progress

Q4 2025 Update

' }, { title: 'Milestones Achieved', content: '' } // ... more slides ]); currentSlideIndex = signal(0); isPresenting = signal(false); currentSlide = computed(() => this.slides()[this.currentSlideIndex()]); ngOnInit(): void { // Listen for keyboard shortcuts document.addEventListener('keydown', this.handleKeyPress.bind(this)); } ngOnDestroy(): void { document.removeEventListener('keydown', this.handleKeyPress.bind(this)); if (screenfull.isEnabled) { screenfull.off('change'); } } togglePresentation(): void { if (screenfull.isEnabled) { screenfull.toggle(); screenfull.on('change', () => { this.isPresenting.set(screenfull.isFullscreen); }); } } nextSlide(): void { if (this.currentSlideIndex() < this.slides().length - 1) { this.currentSlideIndex.update(i => i + 1); } } previousSlide(): void { if (this.currentSlideIndex() > 0) { this.currentSlideIndex.update(i => i - 1); } } private handleKeyPress(event: KeyboardEvent): void { if (!this.isPresenting()) return; switch (event.key) { case 'ArrowRight': case 'PageDown': this.nextSlide(); break; case 'ArrowLeft': case 'PageUp': this.previousSlide(); break; case 'Escape': if (screenfull.isEnabled && screenfull.isFullscreen) { screenfull.exit(); } break; } } } ``` ## API Reference ### screenfull Methods ```typescript // Check if fullscreen API is supported screenfull.isEnabled // boolean // Toggle fullscreen screenfull.toggle() // Toggle document screenfull.toggle(element) // Toggle specific element // Request fullscreen screenfull.request() // Request for document screenfull.request(element) // Request for specific element // Exit fullscreen screenfull.exit() // Check if currently fullscreen screenfull.isFullscreen // boolean // Get fullscreen element screenfull.element // Element | null // Event listeners screenfull.on('change', () => {}) screenfull.on('error', (event) => {}) screenfull.off('change', handler) ``` ## Integration Checklist When using screenfull: - [ ] Check `screenfull.isEnabled` before using API - [ ] Handle browser compatibility gracefully - [ ] Clean up event listeners on component destroy - [ ] Provide exit fullscreen button - [ ] Test on different browsers (Chrome, Firefox, Safari) - [ ] Handle keyboard shortcuts (Escape to exit) - [ ] Style fullscreen mode appropriately - [ ] Consider mobile browsers (limited support) ## Best Practices ### DO ✅ - Always check `screenfull.isEnabled` before use - Provide clear UI to exit fullscreen - Use Escape key to exit fullscreen - Style fullscreen elements appropriately - Clean up event listeners - Handle errors gracefully ### DON'T ❌ - Assume fullscreen API is always available - Force fullscreen without user interaction - Forget to remove event listeners - Ignore mobile browser limitations - Use fullscreen for sensitive actions ## Browser Compatibility | Browser | Support | |---------|---------| | Chrome | ✅ Full support | | Firefox | ✅ Full support | | Safari | ✅ Full support (iOS limited) | | Edge | ✅ Full support | | iOS Safari | ⚠️ Limited (video only) | | Android Chrome | ✅ Full support | ## References - [screenfull.js GitHub](https://github.com/sindresorhus/screenfull.js) - [Fullscreen API MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API) - [Can I Use Fullscreen](https://caniuse.com/fullscreen) --- **Version**: 1.0.0 **Compatible with**: screenfull 6.0.x **Last Updated**: 2025-12-25