diff --git a/packages/vidstack/src/core/api/player-state.ts b/packages/vidstack/src/core/api/player-state.ts index 52881f475..532a63dcf 100644 --- a/packages/vidstack/src/core/api/player-state.ts +++ b/packages/vidstack/src/core/api/player-state.ts @@ -4,7 +4,7 @@ import { isNumber } from 'maverick.js/std'; import type { LogLevel } from '../../foundation/logger/log-level'; import type { MediaProviderLoader } from '../../providers/types'; -import { canOrientScreen, IS_IPHONE } from '../../utils/support'; +import { canOrientScreen, IS_IPAD, IS_IPHONE } from '../../utils/support'; import type { VideoQuality } from '../quality/video-quality'; import { getTimeRangesEnd, getTimeRangesStart, TimeRange } from '../time-ranges'; import type { AudioTrack } from '../tracks/audio/audio-tracks'; @@ -42,9 +42,9 @@ export const mediaState = new State({ controls: false, get iOSControls() { return ( - IS_IPHONE && this.mediaType === 'video' && - (!this.playsInline || (!fscreen.fullscreenEnabled && this.fullscreen)) + ((IS_IPHONE && !this.playsInline) || + ((IS_IPHONE || IS_IPAD) && !fscreen.fullscreenEnabled && this.fullscreen)) ); }, get nativeControls() { diff --git a/packages/vidstack/src/elements/define/sliders/slider-chapters-element.ts b/packages/vidstack/src/elements/define/sliders/slider-chapters-element.ts index 536c9019b..a029ea592 100644 --- a/packages/vidstack/src/elements/define/sliders/slider-chapters-element.ts +++ b/packages/vidstack/src/elements/define/sliders/slider-chapters-element.ts @@ -26,8 +26,14 @@ export class MediaSliderChaptersElement extends Host(HTMLElement, SliderChapters static tagName = 'media-slider-chapters'; #template: HTMLTemplateElement | null = null; + #connectedRanOnce: Boolean = false; protected onConnect(): void { + // onConnect can run more than once (eg, Phoenix LiveView after navigation) + if (this.#connectedRanOnce) return; + + this.#connectedRanOnce = true; + // Animation frame required as some frameworks append late for some reason. requestScopedAnimationFrame(() => { if (!this.connectScope) return; diff --git a/packages/vidstack/src/utils/support.ts b/packages/vidstack/src/utils/support.ts index 55dd26f54..e849cdd2a 100644 --- a/packages/vidstack/src/utils/support.ts +++ b/packages/vidstack/src/utils/support.ts @@ -3,6 +3,11 @@ import { isFunction, isUndefined, waitTimeout } from 'maverick.js/std'; export const UA = __SERVER__ ? '' : navigator?.userAgent.toLowerCase() || ''; export const IS_IOS = !__SERVER__ && /iphone|ipad|ipod|ios|crios|fxios/i.test(UA); export const IS_IPHONE = !__SERVER__ && /(iphone|ipod)/gi.test(navigator?.platform || ''); + +/** iPads report a Mac platform/UA since iPadOS 13. **/ +const IS_TOUCH_MAC = navigator?.platform === 'MacIntel' && navigator?.maxTouchPoints > 1; +export const IS_IPAD = !__SERVER__ && (/ipad/.test(UA) || IS_TOUCH_MAC); + export const IS_CHROME = !__SERVER__ && !!window.chrome; export const IS_IOS_CHROME = !__SERVER__ && /crios/i.test(UA); export const IS_SAFARI = !__SERVER__ && (!!window.safari || IS_IOS);