avbridge 2.7.0 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/player.d.cts CHANGED
@@ -283,6 +283,9 @@ interface AvbridgeVideoElementEventMap {
283
283
  buffered: TimeRanges;
284
284
  }>;
285
285
  loadstart: CustomEvent<Record<string, never>>;
286
+ fitchange: CustomEvent<{
287
+ fit: "contain" | "cover" | "fill";
288
+ }>;
286
289
  }
287
290
 
288
291
  /**
@@ -297,7 +300,7 @@ interface AvbridgeVideoElementEventMap {
297
300
  */
298
301
 
299
302
  declare class AvbridgePlayerElement extends HTMLElement {
300
- static readonly observedAttributes: ("src" | "muted" | "autoplay" | "loop" | "preload" | "poster" | "playsinline" | "crossorigin" | "disableremoteplayback" | "preferstrategy")[];
303
+ static readonly observedAttributes: ("src" | "muted" | "autoplay" | "loop" | "preload" | "poster" | "playsinline" | "crossorigin" | "disableremoteplayback" | "preferstrategy" | "fit" | "show-fit")[];
301
304
  private _video;
302
305
  private _playBtn;
303
306
  private _overlayBtn;
@@ -328,6 +331,8 @@ declare class AvbridgePlayerElement extends HTMLElement {
328
331
  private _statsEl;
329
332
  private _statsInterval;
330
333
  private _eventCleanup;
334
+ private _updateToolbarEmpty;
335
+ private _toolbarTop;
331
336
  constructor();
332
337
  private _template;
333
338
  private _bindEvents;
@@ -357,6 +362,11 @@ declare class AvbridgePlayerElement extends HTMLElement {
357
362
  private _scheduleHide;
358
363
  /** Track whether the last interaction was touch so click handler can skip. */
359
364
  private _lastPointerTypeWasTouch;
365
+ /** True if the event's composed path passes through consumer-slotted toolbar
366
+ * content. Slotted content lives in the light DOM so `.closest(".avp-toolbar-top")`
367
+ * on the event target won't find the shadow-DOM wrapper — `composedPath()`
368
+ * does. */
369
+ private _isToolbarEvent;
360
370
  private _onContainerClick;
361
371
  private _onContainerDblClick;
362
372
  private _onPointerDown;
@@ -506,14 +516,17 @@ declare class UnifiedPlayer {
506
516
  * 3. Give consumers a `<video>`-compatible primitive they can wrap with
507
517
  * their own UI.
508
518
  *
509
- * **It is not a player UI framework.** The tag name `<avbridge-player>` is
510
- * reserved for a future controls-bearing element. See
519
+ * **It is not a player UI framework.** For YouTube-style chrome (seek
520
+ * bar, play/pause, settings menu, fullscreen, auto-hiding controls) use
521
+ * `<avbridge-player>` — it wraps this element with a full UI. See
511
522
  * `docs/dev/WEB_COMPONENT_SPEC.md` for the full spec, lifecycle invariants,
512
523
  * and edge case list.
513
524
  */
514
525
 
515
526
  /** Strategy preference passed via the `preferstrategy` attribute. */
516
527
  type PreferredStrategy = "auto" | StrategyName;
528
+ /** Fit mode — how the video fills the element's box. Mirrors CSS object-fit. */
529
+ type FitMode = "contain" | "cover" | "fill";
517
530
  /**
518
531
  * `HTMLElement` is a browser-only global. SSR frameworks (Next.js, Astro,
519
532
  * Remix, etc.) commonly import library modules on the server to extract
@@ -586,12 +599,26 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
586
599
  * native fails.
587
600
  */
588
601
  private _preferredStrategy;
602
+ /** Current fit mode. Applied to the inner `<video>` via object-fit, and
603
+ * to the fallback canvas via the `--avbridge-fit` CSS custom property on
604
+ * the stage wrapper (see `src/strategies/fallback/video-renderer.ts`). */
605
+ private _fit;
606
+ /** The stage wrapper — the element the canvas attaches into, and where
607
+ * the `--avbridge-fit` CSS custom property lives. */
608
+ private _stageEl;
589
609
  /** Set if currentTime was assigned before the player was ready. */
590
610
  private _pendingSeek;
591
611
  /** Set if play() was called before the player was ready. */
592
612
  private _pendingPlay;
593
613
  /** MutationObserver tracking light-DOM `<track>` children. */
594
614
  private _trackObserver;
615
+ /** Document-level fullscreenchange handler — installed while connected so
616
+ * the element can lock/unlock screen orientation to match the video's
617
+ * intrinsic aspect. */
618
+ private _fullscreenChangeHandler;
619
+ /** True if we successfully called screen.orientation.lock() on the last
620
+ * fullscreen entry. Used to know whether to unlock on exit. */
621
+ private _orientationLocked;
595
622
  constructor();
596
623
  connectedCallback(): void;
597
624
  disconnectedCallback(): void;
@@ -635,6 +662,8 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
635
662
  set preload(value: "none" | "metadata" | "auto");
636
663
  get diagnostics(): boolean;
637
664
  set diagnostics(value: boolean);
665
+ get fit(): FitMode;
666
+ set fit(value: FitMode);
638
667
  get preferredStrategy(): PreferredStrategy;
639
668
  set preferredStrategy(value: PreferredStrategy);
640
669
  get currentTime(): number;
@@ -724,6 +753,36 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
724
753
  language?: string;
725
754
  format?: "vtt" | "srt";
726
755
  }): Promise<void>;
756
+ /**
757
+ * Disable the automatic `screen.orientation.lock()` that runs on
758
+ * fullscreen entry. Set when you want to honor the device's native
759
+ * auto-rotate instead of matching the video's intrinsic orientation.
760
+ */
761
+ get noOrientationLock(): boolean;
762
+ set noOrientationLock(value: boolean);
763
+ /** Called whenever `document.fullscreenchange` fires. If this element (or
764
+ * any of its ancestors) is now fullscreen, derive the target orientation
765
+ * from the video's intrinsic size and call `screen.orientation.lock()`.
766
+ * On exit, release the lock we took. iOS Safari rejects `lock()` — we
767
+ * swallow the rejection so nothing breaks on that path. */
768
+ private _onFullscreenChange;
769
+ /** Walk composed-tree ancestors to see if `target` is this element or
770
+ * any ancestor across shadow boundaries. `Node.contains()` can't cross
771
+ * shadow roots, so when `<avbridge-player>` (the fullscreen element)
772
+ * hosts this `<avbridge-video>` inside its shadow DOM, `contains()`
773
+ * returns false. */
774
+ private _isInsideOrEquals;
775
+ /** Derive "landscape" / "portrait" from the intrinsic video dimensions.
776
+ * Returns null when dimensions aren't known yet or the video is square.
777
+ * Uses `videoWidth` / `videoHeight` from the inner `<video>`, which the
778
+ * browser sets to the display-aspect-corrected size (so anamorphic
779
+ * content is judged by its display aspect, not pixel aspect). */
780
+ private _desiredOrientation;
781
+ /** Attempt to lock screen orientation. Swallows rejections — iOS Safari
782
+ * doesn't implement `lock()`, and desktop / non-fullscreen contexts will
783
+ * reject too. Records success so we know whether to unlock on exit. */
784
+ private _lockOrientation;
785
+ private _releaseOrientationLock;
727
786
  /** Force a (re-)bootstrap if a source is currently set. */
728
787
  load(): Promise<void>;
729
788
  /**
package/dist/player.d.ts CHANGED
@@ -283,6 +283,9 @@ interface AvbridgeVideoElementEventMap {
283
283
  buffered: TimeRanges;
284
284
  }>;
285
285
  loadstart: CustomEvent<Record<string, never>>;
286
+ fitchange: CustomEvent<{
287
+ fit: "contain" | "cover" | "fill";
288
+ }>;
286
289
  }
287
290
 
288
291
  /**
@@ -297,7 +300,7 @@ interface AvbridgeVideoElementEventMap {
297
300
  */
298
301
 
299
302
  declare class AvbridgePlayerElement extends HTMLElement {
300
- static readonly observedAttributes: ("src" | "muted" | "autoplay" | "loop" | "preload" | "poster" | "playsinline" | "crossorigin" | "disableremoteplayback" | "preferstrategy")[];
303
+ static readonly observedAttributes: ("src" | "muted" | "autoplay" | "loop" | "preload" | "poster" | "playsinline" | "crossorigin" | "disableremoteplayback" | "preferstrategy" | "fit" | "show-fit")[];
301
304
  private _video;
302
305
  private _playBtn;
303
306
  private _overlayBtn;
@@ -328,6 +331,8 @@ declare class AvbridgePlayerElement extends HTMLElement {
328
331
  private _statsEl;
329
332
  private _statsInterval;
330
333
  private _eventCleanup;
334
+ private _updateToolbarEmpty;
335
+ private _toolbarTop;
331
336
  constructor();
332
337
  private _template;
333
338
  private _bindEvents;
@@ -357,6 +362,11 @@ declare class AvbridgePlayerElement extends HTMLElement {
357
362
  private _scheduleHide;
358
363
  /** Track whether the last interaction was touch so click handler can skip. */
359
364
  private _lastPointerTypeWasTouch;
365
+ /** True if the event's composed path passes through consumer-slotted toolbar
366
+ * content. Slotted content lives in the light DOM so `.closest(".avp-toolbar-top")`
367
+ * on the event target won't find the shadow-DOM wrapper — `composedPath()`
368
+ * does. */
369
+ private _isToolbarEvent;
360
370
  private _onContainerClick;
361
371
  private _onContainerDblClick;
362
372
  private _onPointerDown;
@@ -506,14 +516,17 @@ declare class UnifiedPlayer {
506
516
  * 3. Give consumers a `<video>`-compatible primitive they can wrap with
507
517
  * their own UI.
508
518
  *
509
- * **It is not a player UI framework.** The tag name `<avbridge-player>` is
510
- * reserved for a future controls-bearing element. See
519
+ * **It is not a player UI framework.** For YouTube-style chrome (seek
520
+ * bar, play/pause, settings menu, fullscreen, auto-hiding controls) use
521
+ * `<avbridge-player>` — it wraps this element with a full UI. See
511
522
  * `docs/dev/WEB_COMPONENT_SPEC.md` for the full spec, lifecycle invariants,
512
523
  * and edge case list.
513
524
  */
514
525
 
515
526
  /** Strategy preference passed via the `preferstrategy` attribute. */
516
527
  type PreferredStrategy = "auto" | StrategyName;
528
+ /** Fit mode — how the video fills the element's box. Mirrors CSS object-fit. */
529
+ type FitMode = "contain" | "cover" | "fill";
517
530
  /**
518
531
  * `HTMLElement` is a browser-only global. SSR frameworks (Next.js, Astro,
519
532
  * Remix, etc.) commonly import library modules on the server to extract
@@ -586,12 +599,26 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
586
599
  * native fails.
587
600
  */
588
601
  private _preferredStrategy;
602
+ /** Current fit mode. Applied to the inner `<video>` via object-fit, and
603
+ * to the fallback canvas via the `--avbridge-fit` CSS custom property on
604
+ * the stage wrapper (see `src/strategies/fallback/video-renderer.ts`). */
605
+ private _fit;
606
+ /** The stage wrapper — the element the canvas attaches into, and where
607
+ * the `--avbridge-fit` CSS custom property lives. */
608
+ private _stageEl;
589
609
  /** Set if currentTime was assigned before the player was ready. */
590
610
  private _pendingSeek;
591
611
  /** Set if play() was called before the player was ready. */
592
612
  private _pendingPlay;
593
613
  /** MutationObserver tracking light-DOM `<track>` children. */
594
614
  private _trackObserver;
615
+ /** Document-level fullscreenchange handler — installed while connected so
616
+ * the element can lock/unlock screen orientation to match the video's
617
+ * intrinsic aspect. */
618
+ private _fullscreenChangeHandler;
619
+ /** True if we successfully called screen.orientation.lock() on the last
620
+ * fullscreen entry. Used to know whether to unlock on exit. */
621
+ private _orientationLocked;
595
622
  constructor();
596
623
  connectedCallback(): void;
597
624
  disconnectedCallback(): void;
@@ -635,6 +662,8 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
635
662
  set preload(value: "none" | "metadata" | "auto");
636
663
  get diagnostics(): boolean;
637
664
  set diagnostics(value: boolean);
665
+ get fit(): FitMode;
666
+ set fit(value: FitMode);
638
667
  get preferredStrategy(): PreferredStrategy;
639
668
  set preferredStrategy(value: PreferredStrategy);
640
669
  get currentTime(): number;
@@ -724,6 +753,36 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
724
753
  language?: string;
725
754
  format?: "vtt" | "srt";
726
755
  }): Promise<void>;
756
+ /**
757
+ * Disable the automatic `screen.orientation.lock()` that runs on
758
+ * fullscreen entry. Set when you want to honor the device's native
759
+ * auto-rotate instead of matching the video's intrinsic orientation.
760
+ */
761
+ get noOrientationLock(): boolean;
762
+ set noOrientationLock(value: boolean);
763
+ /** Called whenever `document.fullscreenchange` fires. If this element (or
764
+ * any of its ancestors) is now fullscreen, derive the target orientation
765
+ * from the video's intrinsic size and call `screen.orientation.lock()`.
766
+ * On exit, release the lock we took. iOS Safari rejects `lock()` — we
767
+ * swallow the rejection so nothing breaks on that path. */
768
+ private _onFullscreenChange;
769
+ /** Walk composed-tree ancestors to see if `target` is this element or
770
+ * any ancestor across shadow boundaries. `Node.contains()` can't cross
771
+ * shadow roots, so when `<avbridge-player>` (the fullscreen element)
772
+ * hosts this `<avbridge-video>` inside its shadow DOM, `contains()`
773
+ * returns false. */
774
+ private _isInsideOrEquals;
775
+ /** Derive "landscape" / "portrait" from the intrinsic video dimensions.
776
+ * Returns null when dimensions aren't known yet or the video is square.
777
+ * Uses `videoWidth` / `videoHeight` from the inner `<video>`, which the
778
+ * browser sets to the display-aspect-corrected size (so anamorphic
779
+ * content is judged by its display aspect, not pixel aspect). */
780
+ private _desiredOrientation;
781
+ /** Attempt to lock screen orientation. Swallows rejections — iOS Safari
782
+ * doesn't implement `lock()`, and desktop / non-fullscreen contexts will
783
+ * reject too. Records success so we know whether to unlock on exit. */
784
+ private _lockOrientation;
785
+ private _releaseOrientationLock;
727
786
  /** Force a (re-)bootstrap if a source is currently set. */
728
787
  load(): Promise<void>;
729
788
  /**