@outbook/webcomponents-player 1.3.1 → 1.3.3

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.
@@ -1,12 +1,17 @@
1
- import { virtual } from 'haunted';
2
1
  import { html } from 'lit';
3
2
  import { TypeIcon } from '@outbook/webcomponents-type-icon/shadow';
4
- import { skip_next, skip_previous, play_arrow, pause, stop } from '@outbook/icons';
3
+ import {
4
+ skip_next,
5
+ skip_previous,
6
+ play_arrow,
7
+ pause,
8
+ stop
9
+ } from '@outbook/icons';
5
10
  import { ifDefined } from 'lit/directives/if-defined.js';
6
11
  import { isEventClick, isKeyEnterOrKeySpace } from 'a11y-key-conjurer';
7
12
  import { classMap } from 'lit/directives/class-map.js';
8
13
 
9
- export const Controls = virtual(({ props, handleAudio, literals = {} }) => {
14
+ export function Controls({ props, handleAudio, literals = {} }) {
10
15
  const { isPlaying = false, playlist, indexSelected } = props;
11
16
  const controlsDisabled = !Number.isInteger(indexSelected);
12
17
  const controlItems = [
@@ -57,15 +62,15 @@ export const Controls = virtual(({ props, handleAudio, literals = {} }) => {
57
62
  }
58
63
 
59
64
  return html`
60
- <div class="myth-controls">
61
- <ul class="myth-controls__items">
65
+ <div class="player-controls">
66
+ <ul class="player-controls__items">
62
67
  ${controlItems.map(item => {
63
68
  const buttonClasses = classMap({
64
- 'myth-controls__button': true,
69
+ 'player-controls__button': true,
65
70
  'is-disabled': item.isDisabled
66
71
  });
67
72
  return html`
68
- <li class="myth-controls__item">
73
+ <li class="player-controls__item">
69
74
  <button
70
75
  class="${buttonClasses}"
71
76
  aria-label="${item.label}"
@@ -79,7 +84,7 @@ export const Controls = virtual(({ props, handleAudio, literals = {} }) => {
79
84
  ${TypeIcon({
80
85
  icon: item.icon,
81
86
  icons: { skip_next, skip_previous, play_arrow, pause, stop },
82
- extraClasses: 'myth-controls__icon'
87
+ extraClasses: 'player-controls__icon'
83
88
  })}
84
89
  </button>
85
90
  </li>
@@ -88,4 +93,4 @@ export const Controls = virtual(({ props, handleAudio, literals = {} }) => {
88
93
  </ul>
89
94
  </div>
90
95
  `;
91
- });
96
+ }
@@ -32,18 +32,18 @@ export const Playlist = virtual(
32
32
  };
33
33
  }
34
34
  return html`
35
- <div class="myth-playlist" id="${listId}">
36
- <ul class="myth-playlist__items">
35
+ <div class="player-playlist" id="${listId}">
36
+ <ul class="player-playlist__items">
37
37
  ${_playlist.map((item, index) => {
38
38
  const isPlayingItem = indexSelected === index;
39
39
  const itemClasses = classMap({
40
- 'myth-playlist__item': true,
40
+ 'player-playlist__item': true,
41
41
  'is-playing': isPlayingItem
42
42
  });
43
43
  return html`
44
44
  <li class="${itemClasses}" data-playlist-item="${index}">
45
45
  <div
46
- class="myth-playlist__item-button"
46
+ class="player-playlist__item-button"
47
47
  tabindex="0"
48
48
  role="button"
49
49
  @click="${handleButton(index)}"
@@ -53,13 +53,13 @@ export const Playlist = virtual(
53
53
  ${showIconIsPlaying && isPlayingItem
54
54
  ? html`
55
55
  <div
56
- class="myth-playlist__item-block myth-playlist__item-playing-icon"
56
+ class="player-playlist__item-block player-playlist__item-playing-icon"
57
57
  >
58
58
  ${TypeIcon({
59
59
  icon: isPlaying ? 'play_arrow' : 'pause',
60
60
  icons: { play_arrow, pause },
61
61
  extraClasses:
62
- 'myth-playlist__item-playing-icon-inner'
62
+ 'player-playlist__item-playing-icon-inner'
63
63
  })}
64
64
  </div>
65
65
  `
@@ -67,13 +67,13 @@ export const Playlist = virtual(
67
67
  ${showTrackNumber
68
68
  ? html`
69
69
  <div
70
- class="myth-playlist__item-block myth-item-text size-small"
70
+ class="player-playlist__item-block track-text__item size-small"
71
71
  >
72
72
  ${item.trackNumber || index + 1}
73
73
  </div>
74
74
  `
75
75
  : nothing}
76
- <div class="myth-playlist__item-block">
76
+ <div class="player-playlist__item-block">
77
77
  ${TrackText({
78
78
  title: item.title,
79
79
  artist: item.artist,
@@ -82,11 +82,11 @@ export const Playlist = virtual(
82
82
  </div>
83
83
  ${item.duration || showFileExtension
84
84
  ? html`
85
- <div class="myth-playlist__item-group is-last-right">
85
+ <div class="player-playlist__item-group is-last-right">
86
86
  ${ItemDuration({ duration: item.duration })}
87
87
  ${showFileExtension
88
88
  ? html`
89
- <div class="myth-playlist__item-block">
89
+ <div class="player-playlist__item-block">
90
90
  ${BadgeFileExtension({ text: item.format })}
91
91
  </div>
92
92
  `
@@ -1,17 +1,16 @@
1
- import { virtual } from 'haunted';
2
1
  import { html } from 'lit';
3
2
  import {
4
3
  readable as formatTime,
5
4
  iso as formatTimeDuration
6
5
  } from 'mystic-format-time';
7
6
 
8
- export const ItemDuration = virtual(({ duration }) => {
7
+ export function ItemDuration({ duration }) {
9
8
  return html`
10
9
  <time
11
- class="myth-playlist__item-block myth-item-text size-small"
10
+ class="player-playlist__item-block track-text__item size-small"
12
11
  datetime="${formatTimeDuration(duration)}"
13
12
  >
14
13
  ${formatTime(duration)}
15
14
  </time>
16
15
  `;
17
- });
16
+ }
@@ -6,7 +6,7 @@ export const ShowCover = ({ cover }) => {
6
6
  return html`
7
7
  ${PlayerArtwork({
8
8
  src1x: cover ? getCover(cover) : undefined,
9
- extraClasses: 'myth-playlist__item-block myth-playlist__item-image'
9
+ extraClasses: 'player-playlist__item-block player-playlist__item-image'
10
10
  })}
11
11
  `;
12
12
  };
@@ -1,33 +1,29 @@
1
- import { virtual } from 'haunted';
2
1
  import { html } from 'lit';
3
2
  import { TrackText } from '../track-text/index.js';
4
3
  import { getCover } from '../get-cover.js';
5
4
  import { PlayerArtwork } from '@outbook/webcomponents-player-artwork';
6
5
 
7
- export const TrackInfo = virtual(
8
- ({ track = {}, indexSelected, literals = {} }) => {
9
- const hasTrackInfo = Number.isInteger(indexSelected);
10
- const cover =
11
- hasTrackInfo && track.cover ? getCover(track.cover) : undefined;
12
- return html`
13
- <div class="myth-track-info">
14
- <div class="myth-track-info__inner">
15
- ${PlayerArtwork({
16
- src1x: cover,
17
- extraClasses: 'myth-track-info__image'
18
- })}
19
- <div class="myth-track-info__data">
20
- ${hasTrackInfo
21
- ? TrackText({
22
- title: track.title,
23
- artist: track.artist,
24
- album: track.album,
25
- hasTrackInfo
26
- })
27
- : TrackText({ title: literals.noPlaying, hasTrackInfo })}
28
- </div>
6
+ export function TrackInfo({ track = {}, indexSelected, literals = {} }) {
7
+ const hasTrackInfo = Number.isInteger(indexSelected);
8
+ const cover = hasTrackInfo && track.cover ? getCover(track.cover) : undefined;
9
+ return html`
10
+ <div class="track-info">
11
+ <div class="track-info__inner">
12
+ ${PlayerArtwork({
13
+ src1x: cover,
14
+ extraClasses: 'track-info__image'
15
+ })}
16
+ <div class="track-info__data">
17
+ ${hasTrackInfo
18
+ ? TrackText({
19
+ title: track.title,
20
+ artist: track.artist,
21
+ album: track.album,
22
+ hasTrackInfo
23
+ })
24
+ : TrackText({ title: literals.noPlaying, hasTrackInfo })}
29
25
  </div>
30
26
  </div>
31
- `;
32
- }
33
- );
27
+ </div>
28
+ `;
29
+ }
@@ -1,20 +1,19 @@
1
- import { virtual } from 'haunted';
2
1
  import { html, nothing } from 'lit';
3
2
 
4
- export const TrackText = virtual(({ artist, album, title, hasTrackInfo }) => {
3
+ export function TrackText({ artist, album, title, hasTrackInfo }) {
5
4
  return html`
6
- <div class="myth-track-text">
5
+ <div class="track-text">
7
6
  <div
8
- class="myth-item-text"
7
+ class="track-text__item"
9
8
  data-test-id="player-data-${hasTrackInfo ? 'title' : 'stopped'}"
10
9
  >
11
10
  ${title}
12
11
  </div>
13
- <div class="myth-item-text size-small">
12
+ <div class="track-text__item size-small">
14
13
  ${artist ? html`<span>${artist}</span>` : nothing}
15
14
  ${artist && album ? html`<span> / </span>` : nothing}
16
15
  ${album ? html`<span>${album}</span>` : nothing}
17
16
  </div>
18
17
  </div>
19
18
  `;
20
- });
19
+ }
@@ -3,7 +3,7 @@
3
3
  @use '../_lib/variables';
4
4
 
5
5
  @mixin style() {
6
- .myth-controls {
6
+ .player-controls {
7
7
  --_controls-color: light-dark(
8
8
  var(--_accent-950),
9
9
  var(--_accent-100)
@@ -12,27 +12,27 @@
12
12
  }
13
13
 
14
14
  @container player (width >= #{variables.$player-widht-m}) {
15
- .myth-controls {
15
+ .player-controls {
16
16
  --_controls-size: #{measures.$baseline * 7};
17
17
  }
18
18
  }
19
19
 
20
20
  @container player (width >= #{variables.$player-widht-l}) {
21
- .myth-controls {
21
+ .player-controls {
22
22
  --_controls-size: #{measures.$baseline * 8};
23
23
  }
24
24
  }
25
25
 
26
- .myth-controls,
27
- .myth-controls__items {
26
+ .player-controls,
27
+ .player-controls__items {
28
28
  width: auto;
29
29
  }
30
30
 
31
- .myth-controls__items {
31
+ .player-controls__items {
32
32
  display: flex;
33
33
  }
34
34
 
35
- .myth-controls__button {
35
+ .player-controls__button {
36
36
  background: transparent;
37
37
  border: 0;
38
38
  color: var(--_controls-color);
@@ -43,7 +43,7 @@
43
43
  opacity: 0.4;
44
44
  }
45
45
  }
46
- .myth-controls__icon {
46
+ .player-controls__icon {
47
47
  width: var(--_controls-size);
48
48
  height: var(--_controls-size);
49
49
  }
@@ -4,7 +4,7 @@
4
4
  @use '../_lib/variables';
5
5
 
6
6
  @mixin style() {
7
- .myth-playlist {
7
+ .player-playlist {
8
8
  --_playlist-font-weight: normal;
9
9
  --_playlist-font-size: #{measures.$baseline * 1.5};
10
10
  --_playlist-font-size-small: #{measures.$baseline * 1.25};
@@ -19,16 +19,22 @@
19
19
  }
20
20
  }
21
21
 
22
+ @container player (width >= #{variables.$player-widht-m}) {
23
+ .player-playlist {
24
+ --_playlist-font-size: #{measures.$baseline * 1.75};
25
+ --_playlist-font-size-small: #{measures.$baseline * 1.5};
26
+ }
27
+ }
22
28
  @container player (width >= #{variables.$player-widht-l}) {
23
- .myth-playlist {
29
+ .player-playlist {
24
30
  --_playlist-font-size: #{measures.$baseline * 2};
25
- --_playlist-font-size-small: #{measures.$baseline * 1.5};
31
+ --_playlist-font-size-small: #{measures.$baseline * 1.75};
26
32
  --_playlist-item-image-size: #{measures.$baseline * 8};
27
33
  }
28
34
  }
29
35
 
30
- .myth-playlist {
31
- .myth-item-text {
36
+ .player-playlist {
37
+ .track-text__item {
32
38
  font-weight: var(--_playlist-font-weight);
33
39
  font-size: var(--_playlist-font-size);
34
40
  line-height: 150%;
@@ -38,12 +44,12 @@
38
44
  }
39
45
  }
40
46
 
41
- .myth-playlist__items {
47
+ .player-playlist__items {
42
48
  padding: 0;
43
49
  position: relative;
44
50
  }
45
51
 
46
- .myth-playlist__item {
52
+ .player-playlist__item {
47
53
  position: relative;
48
54
  border-bottom: 1px solid var(--_separator-color);
49
55
  &.is-playing {
@@ -63,7 +69,7 @@
63
69
  }
64
70
  }
65
71
 
66
- .myth-playlist__item-button {
72
+ .player-playlist__item-button {
67
73
  display: flex;
68
74
  padding: #{measures.$baseline};
69
75
  position: relative;
@@ -73,9 +79,12 @@
73
79
  }
74
80
  }
75
81
 
76
- .myth-playlist__item-group,
77
- .myth-playlist__item-block {
82
+ .player-playlist__item-group,
83
+ .player-playlist__item-block {
84
+ display: flex;
85
+ align-items: center;
78
86
  margin-left: #{measures.$baseline * 2};
87
+ height: var(--_playlist-item-image-size);
79
88
  &:first-child {
80
89
  margin-left: 0;
81
90
  }
@@ -85,25 +94,20 @@
85
94
  }
86
95
  }
87
96
 
88
- .myth-playlist__item-image {
97
+ .player-playlist__item-image {
89
98
  width: var(--_playlist-item-image-size);
90
99
  height: var(--_playlist-item-image-size);
91
100
  flex-shrink: 0;
92
101
  }
93
102
 
94
- .myth-playlist__item-group {
95
- display: flex;
96
- align-items: center;
97
- }
98
-
99
- .myth-playlist__item-playing-icon {
103
+ .player-playlist__item-playing-icon {
100
104
  width: #{measures.$baseline * 2};
101
105
  height: #{measures.$baseline * 2};
102
106
  display: flex;
103
107
  align-items: center;
104
108
  }
105
109
 
106
- .myth-playlist__item-playing-icon-inner {
110
+ .player-playlist__item-playing-icon-inner {
107
111
  width: 100%;
108
112
  aspect-ratio: 1 / 1;
109
113
  }
@@ -4,7 +4,7 @@
4
4
  @mixin style() {
5
5
  $height-xs: measures.$baseline * 8;
6
6
 
7
- .myth-track-info {
7
+ .track-info {
8
8
  --track-info--flex-direction: row;
9
9
  --track-info--image-width: #{measures.$baseline * 8};
10
10
  --track-info--image-separation-horizontal: #{measures.$baseline * 2};
@@ -12,7 +12,7 @@
12
12
  --track-info--height: #{$height-xs};
13
13
  }
14
14
  @container player (width >= #{variables.$player-widht-m}) {
15
- .myth-track-info {
15
+ .track-info {
16
16
  --track-info--flex-direction: column;
17
17
  --track-info--image-width: 100%;
18
18
  --track-info--image-separation-horizontal: 0;
@@ -22,11 +22,11 @@
22
22
  }
23
23
 
24
24
 
25
- .myth-track-info__inner {
25
+ .track-info__inner {
26
26
  display: flex;
27
27
  flex-direction: var(--track-info--flex-direction);
28
28
  height: var(--track-info--height);
29
- .myth-item-text {
29
+ .track-text__item {
30
30
  font-size: #{measures.$baseline * 2};
31
31
  line-height: 150%;
32
32
  &.size-small {
@@ -35,7 +35,7 @@
35
35
  }
36
36
  }
37
37
 
38
- .myth-track-info__image {
38
+ .track-info__image {
39
39
  width: var(--track-info--image-width);
40
40
  flex-shrink: 0;
41
41
  display: flex;
@@ -47,7 +47,7 @@
47
47
  }
48
48
  }
49
49
 
50
- .myth-track-info__data {
50
+ .track-info__data {
51
51
  display: flex;
52
52
  align-items: center;
53
53
  }
@@ -1,4 +1,4 @@
1
1
  /* eslint-disable */
2
2
  import { css } from 'lit';
3
3
 
4
- export default css`.skeleton-loader{--pulse-bg-start: blue;--pulse-bg-end: red}@keyframes colorPulse{from{background-color:var(--pulse-bg-start)}to{background-color:var(--pulse-bg-end)}}.skeleton-loader{background-color:var(--pulse-bg-start);animation:colorPulse 3.2s ease infinite alternate-reverse;opacity:.3}:host{display:block;color-scheme:inherit;--_accent-0: var(--outbook-player--color-accent-0, oklch(100% 0 0deg));--_accent-50: var(--outbook-player--color-accent-50, oklch(98.5% 0 0deg));--_accent-100: var(--outbook-player--color-accent-100, oklch(97% 0 0deg));--_accent-200: var(--outbook-player--color-accent-200, oklch(92.2% 0 0deg));--_accent-300: var(--outbook-player--color-accent-300, oklch(87% 0 0deg));--_accent-400: var(--outbook-player--color-accent-400, oklch(70.8% 0 0deg));--_accent-500: var(--outbook-player--color-accent-500, oklch(55.6% 0 0deg));--_accent-600: var(--outbook-player--color-accent-600, oklch(43.9% 0 0deg));--_accent-700: var(--outbook-player--color-accent-700, oklch(37.1% 0 0deg));--_accent-800: var(--outbook-player--color-accent-800, oklch(26.9% 0 0deg));--_accent-900: var(--outbook-player--color-accent-900, oklch(20.5% 0 0deg));--_accent-950: var(--outbook-player--color-accent-950, oklch(14.5% 0 0deg));--_accent-1000: var(--outbook-player--color-accent-1000, oklch(0% 0 0deg));--pulse-bg-start: light-dark( var(--_accent-100), var(--_accent-600) );--pulse-bg-end: light-dark( var(--_accent-600), var(--_accent-500) );--outbook-badge-file-extension--border-color: light-dark( oklch(37.1% 0 0deg), oklch(87% 0 0deg) );--outbook-badge-file-extension--text-color: light-dark( oklch(14.5% 0 0deg), oklch(100% 0 0deg) );--outbook-scrollable--indicator-color: light-dark( var(--_accent-900), var(--_accent-200) );--outbook-player-timeline--background: light-dark( var(--_accent-200), var(--_accent-800) );--outbook-player-timeline--background-completed: light-dark( var(--_accent-800), var(--_accent-200) );--outbook-player-timeline--chapter--mark-color: light-dark( oklch(14.5% 0 0deg), oklch(98.5% 0 0deg) );--outbook-player-timeline--chapter-played-mark-color: light-dark( oklch(98.5% 0 0deg), oklch(14.5% 0 0deg) );--_text-color: light-dark(oklch(20.5% 0 0deg), oklch(100% 0 0deg));--_background-color: light-dark(oklch(98.5% 0 0deg), oklch(20.5% 0 0deg));--_separator-color: light-dark(oklch(92.2% 0 0deg), oklch(43.9% 0 0deg));--_link-color: light-dark(var(--_accent-700), var(--_accent-200));--_link-color-hover: light-dark(var(--_accent-500), var(--_accent-50))}*{box-sizing:border-box;padding:0;margin:0}ul,ol,li{list-style:none}a,button,[role=button],[role=link]{cursor:pointer}a[disabled],button[disabled],[role=button][disabled],[role=link][disabled]{cursor:default}.mythical-player{container-name:player;container-type:inline-size;height:var(--_main-height, 32rem);background-color:var(--_background-color);position:relative}.mythical-player::after,.mythical-player::before{content:"";height:100%;width:100%;position:absolute;left:0;top:0}.mythical-player.has-gradient::after{opacity:.65;background-color:var(--_background-color)}.mythical-player::before{opacity:.45;background:linear-gradient(145deg, var(--_accent-400) 0%, var(--_accent-500) 25%, var(--_accent-600) 50%, var(--_accent-700) 75%, var(--_accent-800) 100%)}.mythical-player.has-gradient::before{opacity:1;background:linear-gradient(145deg, var(--player--main-color-0) 0%, var(--player--main-color-1) 25%, var(--player--main-color-2) 50%, var(--player--main-color-3) 75%, var(--player--main-color-4) 100%)}@container player (width < 768px){.mythical-player__inner{--player--flex-direction: column;--_secondary-block-width: unset;--_secondary-block-min-width: unset}}@container player (width >= 768px){.mythical-player__inner{--player--flex-direction: row;--_secondary-block-width: 25%;--_secondary-block-min-width: 20rem}}.mythical-player__inner{display:flex;flex-direction:column;height:100%;color:var(--_text-color);position:relative;z-index:2}.mythical-player__body{display:flex;flex-direction:var(--player--flex-direction);flex:1 0 0;overflow:hidden}.mythical-player__playlist{overflow:hidden;padding:0 0 0 0.5rem;display:flex;flex:1 0 0}.mythical-player__track-info{width:var(--_secondary-block-width);min-width:var(--_secondary-block-min-width);padding:0.5rem}.mythical-player__controls{display:flex;justify-content:center;margin-top:-1rem}.mythical-player__controls,.mythical-player__timeline{position:relative}.mythical-player__timeline{padding:0 0.5rem}.myth-controls{--_controls-color: light-dark( var(--_accent-950), var(--_accent-100) );--_controls-size: 3rem}@container player (width >= 768px){.myth-controls{--_controls-size: 3.5rem}}@container player (width >= 1024px){.myth-controls{--_controls-size: 4rem}}.myth-controls,.myth-controls__items{width:auto}.myth-controls__items{display:flex}.myth-controls__button{background:rgba(0,0,0,0);border:0;color:var(--_controls-color)}.myth-controls__button:focus-visible{outline:var(--outbook-outline--color, light-dark(oklch(48.8% 0.243 264.376deg), oklch(88.2% 0.059 254.128deg))) solid 2px;outline-offset:-4px}.myth-controls__button.is-disabled{opacity:.4}.myth-controls__icon{width:var(--_controls-size);height:var(--_controls-size)}.myth-playlist{--_playlist-font-weight: normal;--_playlist-font-size: 0.75rem;--_playlist-font-size-small: 0.625rem;--_playlist-item-background-color: transparent;--_playlist-item-image-size: 3rem}.myth-playlist .is-playing{--_playlist-font-weight: 600;--_playlist-item-background-color: var(--_accent-200)}.ambient-dark .myth-playlist .is-playing{--_playlist-item-background-color: var(--_accent-700)}@container player (width >= 1024px){.myth-playlist{--_playlist-font-size: 1rem;--_playlist-font-size-small: 0.75rem;--_playlist-item-image-size: 4rem}}.myth-playlist .myth-item-text{font-weight:var(--_playlist-font-weight);font-size:var(--_playlist-font-size);line-height:150%}.myth-playlist .myth-item-text.size-small{font-size:var(--_playlist-font-size-small)}.myth-playlist__items{padding:0;position:relative}.myth-playlist__item{position:relative;border-bottom:1px solid var(--_separator-color)}.myth-playlist__item.is-playing:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;opacity:.45}@keyframes colorPulse{from{background-color:var(--pulse-bg-start)}to{background-color:var(--pulse-bg-end)}}.myth-playlist__item.is-playing:before{background-color:var(--pulse-bg-start);animation:colorPulse 3.2s ease infinite alternate-reverse;opacity:.3}.myth-playlist__item:last-child{border-bottom:0}.myth-playlist__item-button{display:flex;padding:0.5rem;position:relative;align-items:center}.myth-playlist__item-button:focus-visible{outline:var(--outbook-outline--color, light-dark(oklch(48.8% 0.243 264.376deg), oklch(88.2% 0.059 254.128deg))) solid 2px;outline-offset:-4px}.myth-playlist__item-group,.myth-playlist__item-block{margin-left:1rem}.myth-playlist__item-group:first-child,.myth-playlist__item-block:first-child{margin-left:0}.myth-playlist__item-group.is-last-right,.myth-playlist__item-block.is-last-right{margin-left:auto;padding-left:0.5rem}.myth-playlist__item-image{width:var(--_playlist-item-image-size);height:var(--_playlist-item-image-size);flex-shrink:0}.myth-playlist__item-group{display:flex;align-items:center}.myth-playlist__item-playing-icon{width:1rem;height:1rem;display:flex;align-items:center}.myth-playlist__item-playing-icon-inner{width:100%;aspect-ratio:1/1}.myth-track-info{--track-info--flex-direction: row;--track-info--image-width: 4rem;--track-info--image-separation-horizontal: 1rem;--track-info--image-separation-vertical: 0;--track-info--height: 4rem}@container player (width >= 768px){.myth-track-info{--track-info--flex-direction: column;--track-info--image-width: 100%;--track-info--image-separation-horizontal: 0;--track-info--image-separation-vertical: 1rem;--track-info--height: auto}}.myth-track-info__inner{display:flex;flex-direction:var(--track-info--flex-direction);height:var(--track-info--height)}.myth-track-info__inner .myth-item-text{font-size:1rem;line-height:150%}.myth-track-info__inner .myth-item-text.size-small{font-size:0.75rem}.myth-track-info__image{width:var(--track-info--image-width);flex-shrink:0;display:flex;align-items:center;margin-right:var(--track-info--image-separation-horizontal);margin-bottom:var(--track-info--image-separation-vertical)}.myth-track-info__image>*{width:100%}.myth-track-info__data{display:flex;align-items:center}`;
4
+ export default css`.skeleton-loader{--pulse-bg-start: blue;--pulse-bg-end: red}@keyframes colorPulse{from{background-color:var(--pulse-bg-start)}to{background-color:var(--pulse-bg-end)}}.skeleton-loader{background-color:var(--pulse-bg-start);animation:colorPulse 3.2s ease infinite alternate-reverse;opacity:.3}:host{display:block;color-scheme:inherit;--_accent-0: var(--outbook-player--color-accent-0, oklch(100% 0 0deg));--_accent-50: var(--outbook-player--color-accent-50, oklch(98.5% 0 0deg));--_accent-100: var(--outbook-player--color-accent-100, oklch(97% 0 0deg));--_accent-200: var(--outbook-player--color-accent-200, oklch(92.2% 0 0deg));--_accent-300: var(--outbook-player--color-accent-300, oklch(87% 0 0deg));--_accent-400: var(--outbook-player--color-accent-400, oklch(70.8% 0 0deg));--_accent-500: var(--outbook-player--color-accent-500, oklch(55.6% 0 0deg));--_accent-600: var(--outbook-player--color-accent-600, oklch(43.9% 0 0deg));--_accent-700: var(--outbook-player--color-accent-700, oklch(37.1% 0 0deg));--_accent-800: var(--outbook-player--color-accent-800, oklch(26.9% 0 0deg));--_accent-900: var(--outbook-player--color-accent-900, oklch(20.5% 0 0deg));--_accent-950: var(--outbook-player--color-accent-950, oklch(14.5% 0 0deg));--_accent-1000: var(--outbook-player--color-accent-1000, oklch(0% 0 0deg));--pulse-bg-start: light-dark( var(--_accent-100), var(--_accent-600) );--pulse-bg-end: light-dark( var(--_accent-600), var(--_accent-500) );--outbook-badge-file-extension--border-color: light-dark( oklch(37.1% 0 0deg), oklch(87% 0 0deg) );--outbook-badge-file-extension--text-color: light-dark( oklch(14.5% 0 0deg), oklch(100% 0 0deg) );--outbook-scrollable--indicator-color: light-dark( var(--_accent-900), var(--_accent-200) );--outbook-player-timeline--background: light-dark( var(--_accent-200), var(--_accent-800) );--outbook-player-timeline--background-completed: light-dark( var(--_accent-800), var(--_accent-200) );--outbook-player-timeline--chapter--mark-color: light-dark( oklch(14.5% 0 0deg), oklch(98.5% 0 0deg) );--outbook-player-timeline--chapter-played-mark-color: light-dark( oklch(98.5% 0 0deg), oklch(14.5% 0 0deg) );--_text-color: light-dark(oklch(20.5% 0 0deg), oklch(100% 0 0deg));--_background-color: light-dark(oklch(98.5% 0 0deg), oklch(20.5% 0 0deg));--_separator-color: light-dark(oklch(92.2% 0 0deg), oklch(43.9% 0 0deg));--_link-color: light-dark(var(--_accent-700), var(--_accent-200));--_link-color-hover: light-dark(var(--_accent-500), var(--_accent-50))}*{box-sizing:border-box;padding:0;margin:0}ul,ol,li{list-style:none}a,button,[role=button],[role=link]{cursor:pointer}a[disabled],button[disabled],[role=button][disabled],[role=link][disabled]{cursor:default}.player{container-name:player;container-type:inline-size;height:var(--_main-height, 32rem);background-color:var(--_background-color);position:relative}.player::after,.player::before{content:"";height:100%;width:100%;position:absolute;left:0;top:0}.player.has-gradient::after{opacity:.65;background-color:var(--_background-color)}.player::before{opacity:.45;background:linear-gradient(145deg, var(--_accent-400) 0%, var(--_accent-500) 25%, var(--_accent-600) 50%, var(--_accent-700) 75%, var(--_accent-800) 100%)}.player.has-gradient::before{opacity:1;background:linear-gradient(145deg, var(--player--main-color-0) 0%, var(--player--main-color-1) 25%, var(--player--main-color-2) 50%, var(--player--main-color-3) 75%, var(--player--main-color-4) 100%)}@container player (width < 768px){.player__inner{--player--flex-direction: column;--_secondary-block-width: unset;--_secondary-block-min-width: unset}}@container player (width >= 768px){.player__inner{--player--flex-direction: row;--_secondary-block-width: 25%;--_secondary-block-min-width: 20rem}}.player__inner{display:flex;flex-direction:column;height:100%;color:var(--_text-color);position:relative;z-index:2}.player__body{display:flex;flex-direction:var(--player--flex-direction);flex:1 0 0;overflow:hidden}.player__playlist{overflow:hidden;padding:0 0 0 0.5rem;display:flex;flex:1 0 0}.player__track-info{width:var(--_secondary-block-width);min-width:var(--_secondary-block-min-width);padding:0.5rem}.player__controls{display:flex;justify-content:center;margin-top:-1rem}.player__controls,.player__timeline{position:relative}.player__timeline{padding:0 0.5rem}.player-controls{--_controls-color: light-dark( var(--_accent-950), var(--_accent-100) );--_controls-size: 3rem}@container player (width >= 768px){.player-controls{--_controls-size: 3.5rem}}@container player (width >= 1024px){.player-controls{--_controls-size: 4rem}}.player-controls,.player-controls__items{width:auto}.player-controls__items{display:flex}.player-controls__button{background:rgba(0,0,0,0);border:0;color:var(--_controls-color)}.player-controls__button:focus-visible{outline:var(--outbook-outline--color, light-dark(oklch(48.8% 0.243 264.376deg), oklch(88.2% 0.059 254.128deg))) solid 2px;outline-offset:-4px}.player-controls__button.is-disabled{opacity:.4}.player-controls__icon{width:var(--_controls-size);height:var(--_controls-size)}.player-playlist{--_playlist-font-weight: normal;--_playlist-font-size: 0.75rem;--_playlist-font-size-small: 0.625rem;--_playlist-item-background-color: transparent;--_playlist-item-image-size: 3rem}.player-playlist .is-playing{--_playlist-font-weight: 600;--_playlist-item-background-color: var(--_accent-200)}.ambient-dark .player-playlist .is-playing{--_playlist-item-background-color: var(--_accent-700)}@container player (width >= 768px){.player-playlist{--_playlist-font-size: 0.875rem;--_playlist-font-size-small: 0.75rem}}@container player (width >= 1024px){.player-playlist{--_playlist-font-size: 1rem;--_playlist-font-size-small: 0.875rem;--_playlist-item-image-size: 4rem}}.player-playlist .track-text__item{font-weight:var(--_playlist-font-weight);font-size:var(--_playlist-font-size);line-height:150%}.player-playlist .track-text__item.size-small{font-size:var(--_playlist-font-size-small)}.player-playlist__items{padding:0;position:relative}.player-playlist__item{position:relative;border-bottom:1px solid var(--_separator-color)}.player-playlist__item.is-playing:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;opacity:.45}@keyframes colorPulse{from{background-color:var(--pulse-bg-start)}to{background-color:var(--pulse-bg-end)}}.player-playlist__item.is-playing:before{background-color:var(--pulse-bg-start);animation:colorPulse 3.2s ease infinite alternate-reverse;opacity:.3}.player-playlist__item:last-child{border-bottom:0}.player-playlist__item-button{display:flex;padding:0.5rem;position:relative;align-items:center}.player-playlist__item-button:focus-visible{outline:var(--outbook-outline--color, light-dark(oklch(48.8% 0.243 264.376deg), oklch(88.2% 0.059 254.128deg))) solid 2px;outline-offset:-4px}.player-playlist__item-group,.player-playlist__item-block{display:flex;align-items:center;margin-left:1rem;height:var(--_playlist-item-image-size)}.player-playlist__item-group:first-child,.player-playlist__item-block:first-child{margin-left:0}.player-playlist__item-group.is-last-right,.player-playlist__item-block.is-last-right{margin-left:auto;padding-left:0.5rem}.player-playlist__item-image{width:var(--_playlist-item-image-size);height:var(--_playlist-item-image-size);flex-shrink:0}.player-playlist__item-playing-icon{width:1rem;height:1rem;display:flex;align-items:center}.player-playlist__item-playing-icon-inner{width:100%;aspect-ratio:1/1}.track-info{--track-info--flex-direction: row;--track-info--image-width: 4rem;--track-info--image-separation-horizontal: 1rem;--track-info--image-separation-vertical: 0;--track-info--height: 4rem}@container player (width >= 768px){.track-info{--track-info--flex-direction: column;--track-info--image-width: 100%;--track-info--image-separation-horizontal: 0;--track-info--image-separation-vertical: 1rem;--track-info--height: auto}}.track-info__inner{display:flex;flex-direction:var(--track-info--flex-direction);height:var(--track-info--height)}.track-info__inner .track-text__item{font-size:1rem;line-height:150%}.track-info__inner .track-text__item.size-small{font-size:0.75rem}.track-info__image{width:var(--track-info--image-width);flex-shrink:0;display:flex;align-items:center;margin-right:var(--track-info--image-separation-horizontal);margin-bottom:var(--track-info--image-separation-vertical)}.track-info__image>*{width:100%}.track-info__data{display:flex;align-items:center}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outbook/webcomponents-player",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "main": "player.js",
5
5
  "type": "module",
6
6
  "private": false,
@@ -33,8 +33,9 @@
33
33
  "mystic-format-time": "1.0.2",
34
34
  "@outbook/webcomponents-scrollable": ">=1.0.0",
35
35
  "@outbook/webcomponents-type-icon": ">=1.1.2",
36
- "@outbook/webcomponents-badge-file-extension": ">=1.2.0",
36
+ "@outbook/webcomponents-badge-file-extension": ">=1.2.1",
37
37
  "@outbook/webcomponents-player-artwork": ">=1.0.0",
38
+ "@outbook/webcomponents-player-timeline": ">=1.0.1",
38
39
  "@outbook/icons": ">=1.3.0"
39
40
  },
40
41
  "devDependencies": {
package/player.js CHANGED
@@ -233,17 +233,16 @@ function ComponentPlayer(element) {
233
233
  }
234
234
 
235
235
  const mainClasses = classMap({
236
- 'mythical-player': true,
237
- 'root-container': true,
236
+ player: true,
238
237
  'has-gradient': hasProminentColors
239
238
  });
240
239
 
241
240
  return literals
242
241
  ? html`
243
242
  <div class="${mainClasses}" style="${prominentColors}">
244
- <div class="mythical-player__inner">
245
- <div class="mythical-player__body">
246
- <div class="mythical-player__playlist">
243
+ <div class="player__inner">
244
+ <div class="player__body">
245
+ <div class="player__playlist">
247
246
  ${Scrollable({
248
247
  extraClasses: 'scrollable--default',
249
248
  eventScrollToPlayingItem: true,
@@ -260,7 +259,7 @@ function ComponentPlayer(element) {
260
259
  }
261
260
  })}
262
261
  </div>
263
- <div class="mythical-player__track-info">
262
+ <div class="player__track-info">
264
263
  ${TrackInfo({
265
264
  indexSelected,
266
265
  track: playlist[indexSelected],
@@ -268,16 +267,13 @@ function ComponentPlayer(element) {
268
267
  })}
269
268
  </div>
270
269
  </div>
271
- <div
272
- class="mythical-player__timeline"
273
- @reposition="${handleReposition}"
274
- >
270
+ <div class="player__timeline" @reposition="${handleReposition}">
275
271
  ${PlayerTimeline({
276
272
  duration: totalTime,
277
273
  currentTime
278
274
  })}
279
275
  </div>
280
- <div class="mythical-player__controls">
276
+ <div class="player__controls">
281
277
  ${Controls({
282
278
  props: { isPlaying, playlist, indexSelected },
283
279
  handleAudio,
package/_lib/hooks.js DELETED
@@ -1,23 +0,0 @@
1
- import { useEffect } from 'haunted';
2
-
3
- export function useDocumentEvent(eventName, handler, condition) {
4
- useEffect(() => {
5
- if (condition) {
6
- document.addEventListener(eventName, handler);
7
- return () => {
8
- document.removeEventListener(eventName, handler);
9
- };
10
- }
11
- }, [eventName, handler, condition]);
12
- }
13
-
14
- export function useWindowEvent(eventName, handler, condition = true) {
15
- useEffect(() => {
16
- if (condition) {
17
- window.addEventListener(eventName, handler);
18
- return () => {
19
- window.removeEventListener(eventName, handler);
20
- };
21
- }
22
- }, [eventName, handler, condition]);
23
- }
@@ -1,42 +0,0 @@
1
- import {
2
- isEventClick,
3
- isKeyArrowLeft,
4
- isKeyArrowRight
5
- } from 'a11y-key-conjurer';
6
-
7
- const SKIP_TIME = 10;
8
-
9
- function handleClick(ev, getMediaElement) {
10
- const audioElement = getMediaElement();
11
- const target = ev.currentTarget;
12
- const rect = target.getBoundingClientRect();
13
- const x = ev.clientX - rect.left;
14
- const percent = (100 * x) / target.offsetWidth;
15
- audioElement.currentTime = (audioElement.duration / 100) * percent;
16
- }
17
-
18
- function handleArrows({ multiplier }, getMediaElement) {
19
- const audioElement = getMediaElement();
20
- const newTime = audioElement.currentTime + SKIP_TIME * multiplier;
21
- const duration = audioElement.duration;
22
- audioElement.currentTime =
23
- newTime > 0 ? (newTime < duration ? newTime : duration) : 0;
24
- }
25
-
26
- function handleArrowLeft(ev, getMediaElement) {
27
- handleArrows({ ev, multiplier: -1 }, getMediaElement);
28
- }
29
-
30
- function handleArrowRight(ev, getMediaElement) {
31
- handleArrows({ ev, multiplier: 1 }, getMediaElement);
32
- }
33
-
34
- export function handleTimeline(ev, getMediaElement) {
35
- if (isEventClick(ev)) {
36
- handleClick(ev, getMediaElement);
37
- } else if (isKeyArrowLeft(ev)) {
38
- handleArrowLeft(ev, getMediaElement);
39
- } else if (isKeyArrowRight(ev)) {
40
- handleArrowRight(ev, getMediaElement);
41
- }
42
- }
@@ -1,121 +0,0 @@
1
- import { html, nothing } from 'lit';
2
- import { component, useState } from 'haunted';
3
- import { classMap } from 'lit/directives/class-map.js';
4
- import { handleTimeline } from './_lib/handle-timeline.js';
5
- import { readable as formatTime } from 'mystic-format-time';
6
-
7
- function getChapter({ targetTime, chapters }) {
8
- const selected = chapters.find(
9
- chapter =>
10
- targetTime >= chapter.start / 1000 && targetTime < chapter.end / 1000
11
- );
12
- return selected?.tags?.title || null;
13
- }
14
-
15
- function TimelineComponent(element) {
16
- const { props } = element;
17
- const {
18
- totalTime,
19
- currentTime = 0, // keep currentTime here for the INITIAL render, but we won't rely on it for updates
20
- currentItem = {},
21
- getMediaElement,
22
- id
23
- } = props;
24
-
25
- const [timePosition, setTimePosition] = useState(null);
26
- const chapters = currentItem?.metadata?.chapters || [];
27
-
28
- function handleTimelineIn(ev) {
29
- const target = ev.currentTarget;
30
- const leftPosition = ev.layerX;
31
- const targetWidth = target.offsetWidth;
32
- const targetTime = (leftPosition * totalTime) / targetWidth;
33
- setTimePosition({
34
- visual: formatTime(targetTime),
35
- chapter:
36
- chapters.length > 0 ? getChapter({ targetTime, chapters }) : null,
37
- left: leftPosition
38
- });
39
- }
40
-
41
- function handleTimelineOut() {
42
- setTimePosition(null);
43
- }
44
-
45
- function fnHandleTimeline(ev) {
46
- handleTimeline(ev, getMediaElement);
47
- }
48
-
49
- return html`
50
- <div class="timeline">
51
- <div
52
- class="timeline__track"
53
- @click="${fnHandleTimeline}"
54
- @keydown="${fnHandleTimeline}"
55
- @mousemove="${handleTimelineIn}"
56
- @mouseout="${handleTimelineOut}"
57
- role="progressbar"
58
- tabindex="0"
59
- >
60
- <div
61
- id="bar-${id}"
62
- class="timeline__completed"
63
- style="width: 0;"
64
- ></div>
65
- </div>
66
- <div class="timeline__numbers">
67
- <div id="txt-${id}">00:00</div>
68
- <div>${formatTime(totalTime)}</div>
69
- </div>
70
-
71
- ${chapters.map(chapter => {
72
- const limitClasses = {
73
- 'timeline__chapter-limit': true,
74
- 'timeline__chapter-limit--played': currentTime > chapter.start / 1000
75
- };
76
- const position = (100 / totalTime) * (chapter.start / 1000);
77
- return html`
78
- <div
79
- class="${classMap(limitClasses)}"
80
- style="--timeline--chapter-limit-position: ${position}%;"
81
- ></div>
82
- `;
83
- })}
84
- ${timePosition === null
85
- ? nothing
86
- : html`
87
- <div
88
- class="timeline__tooltip"
89
- style="--timeline-tooltip-position: ${timePosition.left}px;"
90
- >
91
- <div class="timeline__tooltip-inner">
92
- ${timePosition.chapter
93
- ? html`<span class="timeline__tooltip-chapter-title"
94
- >${timePosition.chapter}</span
95
- >`
96
- : nothing}
97
- <span class="timeline__tooltip-time"
98
- >${timePosition.visual}</span
99
- >
100
- </div>
101
- </div>
102
- `}
103
- </div>
104
- `;
105
- }
106
-
107
- if (!customElements.get('mythical-player-timeline')) {
108
- customElements.define(
109
- 'mythical-player-timeline',
110
- component(TimelineComponent, {
111
- observedAttributes: [],
112
- useShadowDOM: false
113
- })
114
- );
115
- }
116
-
117
- export function Timeline(props) {
118
- return html`<mythical-player-timeline
119
- .props="${props}"
120
- ></mythical-player-timeline>`;
121
- }