11import { html } from 'lit-html' ;
2+ import { Component , effect } from 'maverick.js' ;
3+ import { Host } from 'maverick.js/element' ;
4+ import { setAttribute } from 'maverick.js/std' ;
25
6+ import { requestScopedAnimationFrame } from '../../utils/dom' ;
37import { LitElement } from '../lit/lit-element' ;
48
9+ export interface SpinnerProps {
10+ /**
11+ * The horizontal (width) and vertical (height) length of the spinner.
12+ */
13+ size : number ;
14+ /**
15+ * The width of the spinner track and track fill.
16+ */
17+ trackWidth : number ;
18+ /**
19+ * The percentage of the spinner track that should be filled.
20+ */
21+ fillPercent : number ;
22+ }
23+
24+ export class Spinner extends Component < SpinnerProps > {
25+ static props : SpinnerProps = {
26+ size : 96 ,
27+ trackWidth : 8 ,
28+ fillPercent : 50 ,
29+ } ;
30+
31+ protected override onConnect ( el : HTMLElement ) : void {
32+ requestScopedAnimationFrame ( ( ) => {
33+ if ( ! this . connectScope ) return ;
34+
35+ const root = el . querySelector ( 'svg' ) ! ,
36+ track = root . firstElementChild as SVGCircleElement ,
37+ trackFill = track . nextElementSibling as SVGCircleElement ;
38+
39+ effect ( this . _update . bind ( this , root , track , trackFill ) ) ;
40+ } ) ;
41+ }
42+
43+ private _update ( root : SVGSVGElement , track : SVGCircleElement , trackFill : SVGCircleElement ) {
44+ const { size, trackWidth, fillPercent } = this . $props ;
45+ setAttribute ( root , 'width' , size ( ) ) ;
46+ setAttribute ( root , 'height' , size ( ) ) ;
47+ setAttribute ( track , 'stroke-width' , trackWidth ( ) ) ;
48+ setAttribute ( trackFill , 'stroke-width' , trackWidth ( ) ) ;
49+ setAttribute ( trackFill , 'stroke-dashoffset' , 100 - fillPercent ( ) ) ;
50+ }
51+ }
52+
553/**
654 * @docs {@link https://www.vidstack.io/docs/wc/player/components/display/buffering-indicator }
755 * @example
856 * ```html
9- * <media-spinner></media-spinner>
57+ * <!-- default values below -->
58+ * <media-spinner size="84" track-width="8" fill-percent="50"></media-spinner>
1059 * ```
1160 * @example
1261 * ```css
13- * media-spinner {
14- * --size: 84px ;
15- * --track-width: 8px;
16- * --track-color: rgb(255 255 255 / 0.5);
17- * -- track-fill-color: white;
18- * --track-fill-percent: 50 ;
62+ * media-spinner [data-part="track"] {
63+ * color: rgb(255 255 255 / 0.5) ;
64+ * }
65+ *
66+ * media-spinner [data-part=" track-fill"] {
67+ * color: white ;
1968 * }
2069 * ```
2170 */
22- export class MediaSpinnerElement extends LitElement {
71+ export class MediaSpinnerElement extends Host ( LitElement , Spinner ) {
2372 static tagName = 'media-spinner' ;
2473
2574 render ( ) {
2675 return html `
27- < svg
28- fill ="none "
29- viewBox ="0 0 120 120 "
30- aria-hidden ="true "
31- data-part ="root "
32- style ="width: var(--size); height: var(--size) "
33- >
34- < circle
35- cx ="60 "
36- cy ="60 "
37- r ="54 "
38- stroke ="currentColor "
39- data-part ="track "
40- style ="color: var(--track-color); stroke-width: var(--track-width); "
41- > </ circle >
76+ < svg fill ="none " viewBox ="0 0 120 120 " aria-hidden ="true " data-part ="root ">
77+ < circle cx ="60 " cy ="60 " r ="54 " stroke ="currentColor " data-part ="track "> </ circle >
4278 < circle
4379 cx ="60 "
4480 cy ="60 "
@@ -47,7 +83,6 @@ export class MediaSpinnerElement extends LitElement {
4783 pathLength ="100 "
4884 stroke-dasharray ="100 "
4985 data-part ="track-fill "
50- style ="color: var(--track-fill-color); stroke-width: var(--track-width); stroke-dashoffset: calc(100 - var(--track-fill-percent, 50)); "
5186 > </ circle >
5287 </ svg >
5388 ` ;
0 commit comments