@streamscloud/kit 0.54.0 → 0.55.0

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.
@@ -15,6 +15,7 @@ export declare class CursorDataLoaderWithSearch<T> implements IDataLoader<T> {
15
15
  });
16
16
  get searchString(): string;
17
17
  get loading(): boolean;
18
+ get initialLoading(): boolean;
18
19
  loadMore: () => Promise<T[]>;
19
20
  reset(): Promise<void>;
20
21
  updateSearchString: (searchString: string | null) => void;
@@ -22,6 +22,9 @@ export class CursorDataLoaderWithSearch {
22
22
  get loading() {
23
23
  return this._loading;
24
24
  }
25
+ get initialLoading() {
26
+ return this._loading && this.items.length === 0;
27
+ }
25
28
  loadMore = async () => {
26
29
  if (this.pending) {
27
30
  return this.pending;
@@ -11,6 +11,7 @@ export declare class CursorDataLoader<T> implements IDataLoader<T> {
11
11
  loadPage: (continuationToken: ContinuationToken) => Promise<CursorResult<T> | null>;
12
12
  });
13
13
  get loading(): boolean;
14
+ get initialLoading(): boolean;
14
15
  loadMore: () => Promise<T[]>;
15
16
  reset(): Promise<void>;
16
17
  private runLoad;
@@ -12,6 +12,9 @@ export class CursorDataLoader {
12
12
  get loading() {
13
13
  return this._loading;
14
14
  }
15
+ get initialLoading() {
16
+ return this._loading && this.items.length === 0;
17
+ }
15
18
  loadMore = async () => {
16
19
  if (this.pending) {
17
20
  return this.pending;
@@ -1,5 +1,7 @@
1
1
  export interface IDataLoader<T> {
2
2
  items: T[];
3
3
  loading: boolean;
4
+ /** Loading with nothing to show yet — first load, or a reload after the list was cleared by a reset. */
5
+ initialLoading: boolean;
4
6
  loadMore: () => Promise<T[]>;
5
7
  }
@@ -13,6 +13,7 @@ export declare class PageDataLoader<T> implements IDataLoader<T> {
13
13
  });
14
14
  get items(): T[];
15
15
  get loading(): boolean;
16
+ get initialLoading(): boolean;
16
17
  loadMore: () => Promise<T[]>;
17
18
  reset: () => Promise<void>;
18
19
  }
@@ -18,6 +18,9 @@ export class PageDataLoader {
18
18
  get loading() {
19
19
  return this._loading;
20
20
  }
21
+ get initialLoading() {
22
+ return this._loading && this._items.length === 0;
23
+ }
21
24
  loadMore = async () => {
22
25
  if (this._loading || !this.canLoadMore) {
23
26
  return [];
@@ -1,28 +1,42 @@
1
1
  <script lang="ts">import { IconSlot } from '../../icon';
2
- let { actions } = $props();
2
+ import PlayerContextMenu from './player-context-menu.svelte';
3
+ let { actions, contextActions = [], contextPosition = 'left-end' } = $props();
3
4
  </script>
4
5
 
5
6
  <div class="mobile-player-buttons">
6
- {#each actions as action (action.icon)}
7
+ {#each actions as action, index (index)}
7
8
  <button type="button" class="mobile-player-buttons__action" disabled={action.disabled} onclick={action.callback}>
8
9
  <span class="mobile-player-buttons__action-icon">
9
10
  <IconSlot icon={action.icon} />
10
11
  </span>
11
12
  </button>
12
13
  {/each}
14
+ {#if contextActions.length}
15
+ <div class="mobile-player-buttons__action mobile-player-buttons__action--menu">
16
+ <PlayerContextMenu actions={contextActions} position={contextPosition} />
17
+ </div>
18
+ {/if}
13
19
  </div>
14
20
 
15
21
  <!--
16
22
  @component
17
23
  A vertically stacked column of player action buttons optimized for mobile touch targets.
24
+ `contextActions` appends an overflow-menu cell below the buttons.
18
25
 
19
- ### Props
20
- | Prop | Type | Description |
26
+ ### CSS Custom Properties
27
+ | Property | Description | Default |
21
28
  |---|---|---|
22
- | `actions` | `PlayerButtonDef[]` | Array of button definitions (icon, callback, disabled state) |
29
+ | `--sc-kit--player-button--color--inactive` | Overflow menu panel background | 60% opacity of `black` |
30
+ | `--sc-kit--player-button--menu--border-color` | Overflow menu panel border | `white` at 15% |
31
+ | `--sc-kit--player-button--menu--item--color` | Overflow menu row text / icon color | `--sc-kit--color--text--on-accent` |
32
+ | `--sc-kit--player-button--menu--item--background--hover` | Overflow menu row hover background | `white` at 12% |
23
33
  -->
24
34
 
25
35
  <style>.mobile-player-buttons {
36
+ --_player-button--color--inactive: var(--sc-kit--player-button--color--inactive, rgb(0 0 0 / 60%));
37
+ --_player-button--menu--border-color: var(--sc-kit--player-button--menu--border-color, rgb(255 255 255 / 15%));
38
+ --_player-button--menu--item-color: var(--sc-kit--player-button--menu--item--color, var(--sc-kit--color--text--on-accent));
39
+ --_player-button--menu--item-background-hover: var(--sc-kit--player-button--menu--item--background--hover, rgb(255 255 255 / 12%));
26
40
  cursor: pointer;
27
41
  display: flex;
28
42
  flex-direction: column;
@@ -30,10 +44,11 @@ A vertically stacked column of player action buttons optimized for mobile touch
30
44
  pointer-events: auto;
31
45
  }
32
46
  .mobile-player-buttons__action {
47
+ --_player-button--cell-padding: var(--sc-kit--space--4);
33
48
  display: flex;
34
49
  justify-content: center;
35
50
  align-items: center;
36
- padding: var(--sc-kit--space--4);
51
+ padding: var(--_player-button--cell-padding);
37
52
  --sc-kit--icon--color: var(--sc-kit--color--text--on-accent);
38
53
  --sc-kit--icon--size: 2rem;
39
54
  --sc-kit--icon--filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.2));
@@ -42,6 +57,15 @@ A vertically stacked column of player action buttons optimized for mobile touch
42
57
  opacity: 0.5;
43
58
  cursor: default;
44
59
  }
60
+ .mobile-player-buttons__action--menu {
61
+ padding: 0;
62
+ min-block-size: calc(var(--sc-kit--icon--size) + 2 * var(--_player-button--cell-padding));
63
+ min-inline-size: calc(var(--sc-kit--icon--size) + 2 * var(--_player-button--cell-padding));
64
+ --sc-kit--popover--content--background: var(--_player-button--color--inactive);
65
+ --sc-kit--popover--content--border-color: var(--_player-button--menu--border-color);
66
+ --sc-kit--popover-item--color: var(--_player-button--menu--item-color);
67
+ --sc-kit--popover-item--background--hover: var(--_player-button--menu--item-background-hover);
68
+ }
45
69
  .mobile-player-buttons__action-icon {
46
70
  display: block;
47
71
  }</style>
@@ -1,14 +1,23 @@
1
- import type { PlayerButtonDef } from './types';
1
+ import type { PlayerButtonDef, PlayerContextActionDef } from './types';
2
+ import type { Placement } from '@floating-ui/dom';
2
3
  type Props = {
3
4
  actions: PlayerButtonDef[];
5
+ /** Rows of an overflow menu rendered as the final cell — an ellipsis trigger opening a popover. Empty ⇒ no menu cell. @default [] */
6
+ contextActions?: PlayerContextActionDef[];
7
+ /** Floating UI placement of the overflow menu panel @default 'left-end' */
8
+ contextPosition?: Placement;
4
9
  };
5
10
  /**
6
11
  * A vertically stacked column of player action buttons optimized for mobile touch targets.
12
+ * `contextActions` appends an overflow-menu cell below the buttons.
7
13
  *
8
- * ### Props
9
- * | Prop | Type | Description |
14
+ * ### CSS Custom Properties
15
+ * | Property | Description | Default |
10
16
  * |---|---|---|
11
- * | `actions` | `PlayerButtonDef[]` | Array of button definitions (icon, callback, disabled state) |
17
+ * | `--sc-kit--player-button--color--inactive` | Overflow menu panel background | 60% opacity of `black` |
18
+ * | `--sc-kit--player-button--menu--border-color` | Overflow menu panel border | `white` at 15% |
19
+ * | `--sc-kit--player-button--menu--item--color` | Overflow menu row text / icon color | `--sc-kit--color--text--on-accent` |
20
+ * | `--sc-kit--player-button--menu--item--background--hover` | Overflow menu row hover background | `white` at 12% |
12
21
  */
13
22
  declare const Cmp: import("svelte").Component<Props, {}, "">;
14
23
  type Cmp = ReturnType<typeof Cmp>;
@@ -1,23 +1,32 @@
1
1
  <script lang="ts">import { IconSlot } from '../../icon';
2
- let { actions, scaleEffect = false, zoom = 1 } = $props();
2
+ import PlayerContextMenu from './player-context-menu.svelte';
3
+ let { actions, contextActions = [], contextPosition = 'left-end', scaleEffect = false, zoom = 1 } = $props();
4
+ const hasMenu = $derived(contextActions.length > 0);
5
+ const cellCount = $derived(actions.length + (hasMenu ? 1 : 0));
3
6
  </script>
4
7
 
5
- {#if actions.length === 1}
6
- {@const action = actions[0]}
7
- <button
8
- type="button"
9
- class="player-button"
10
- style:zoom={zoom}
11
- class:player-button--scale-effect={scaleEffect}
12
- disabled={action.disabled}
13
- onclick={action.callback}>
14
- <span class="player-button__icon">
15
- <IconSlot icon={action.icon} />
16
- </span>
17
- </button>
18
- {:else if actions.length > 1}
8
+ {#if cellCount === 1}
9
+ {#if hasMenu}
10
+ <div class="player-button player-button--menu" style:zoom={zoom}>
11
+ <PlayerContextMenu actions={contextActions} position={contextPosition} />
12
+ </div>
13
+ {:else}
14
+ {@const action = actions[0]}
15
+ <button
16
+ type="button"
17
+ class="player-button"
18
+ style:zoom={zoom}
19
+ class:player-button--scale-effect={scaleEffect}
20
+ disabled={action.disabled}
21
+ onclick={action.callback}>
22
+ <span class="player-button__icon">
23
+ <IconSlot icon={action.icon} />
24
+ </span>
25
+ </button>
26
+ {/if}
27
+ {:else if cellCount > 1}
19
28
  <div class="player-buttons" style:zoom={zoom}>
20
- {#each actions as action (action.icon)}
29
+ {#each actions as action, index (index)}
21
30
  <button
22
31
  type="button"
23
32
  class="player-buttons__action"
@@ -29,26 +38,40 @@ let { actions, scaleEffect = false, zoom = 1 } = $props();
29
38
  </span>
30
39
  </button>
31
40
  {/each}
41
+ {#if hasMenu}
42
+ <div class="player-buttons__action player-buttons__action--menu">
43
+ <PlayerContextMenu actions={contextActions} position={contextPosition} />
44
+ </div>
45
+ {/if}
32
46
  </div>
33
47
  {/if}
34
48
 
35
49
  <!--
36
50
  @component
37
51
  Desktop player action buttons — renders a single circular button or a vertically stacked pill for multiple actions.
52
+ `contextActions` adds an overflow-menu cell as the last item; it counts towards the single / pill split, so one
53
+ action plus a menu renders as a two-cell pill.
38
54
 
39
55
  ### CSS Custom Properties
40
56
  | Property | Description | Default |
41
57
  |---|---|---|
42
58
  | `--sc-kit--player-button--color` | Button background at full opacity | `dark-500` / `black` at 95% |
43
- | `--sc-kit--player-button--color--inactive` | Button background at rest | 60% opacity of `--color` |
59
+ | `--sc-kit--player-button--color--inactive` | Button background at rest — the overflow menu panel takes the same value | 60% opacity of `--color` |
60
+ | `--sc-kit--player-button--menu--border-color` | Overflow menu panel border | `white` at 15% |
61
+ | `--sc-kit--player-button--menu--item--color` | Overflow menu row text / icon color | `--sc-kit--color--text--on-accent` |
62
+ | `--sc-kit--player-button--menu--item--background--hover` | Overflow menu row hover background | `white` at 12% |
44
63
  -->
45
64
 
46
65
  <style>.player-button {
47
66
  --_player-button--color: var(--sc-kit--player-button--color, rgb(0 0 0 / 95%));
48
67
  --_player-button--color--inactive: var(--sc-kit--player-button--color--inactive, rgb(0 0 0 / 60%));
68
+ --_player-button--menu--border-color: var(--sc-kit--player-button--menu--border-color, rgb(255 255 255 / 15%));
69
+ --_player-button--menu--item-color: var(--sc-kit--player-button--menu--item--color, var(--sc-kit--color--text--on-accent));
70
+ --_player-button--menu--item-background-hover: var(--sc-kit--player-button--menu--item--background--hover, rgb(255 255 255 / 12%));
49
71
  --_player-button--icon-scale: 1;
72
+ --_player-button--cell-padding: 0.625rem;
50
73
  pointer-events: auto;
51
- padding: 0.625rem;
74
+ padding: var(--_player-button--cell-padding);
52
75
  display: flex;
53
76
  justify-content: center;
54
77
  align-items: center;
@@ -69,6 +92,18 @@ Desktop player action buttons — renders a single circular button or a vertical
69
92
  .player-button--scale-effect:hover:not(:disabled) {
70
93
  --_player-button--icon-scale: 1.2;
71
94
  }
95
+ .player-button--menu {
96
+ padding: 0;
97
+ min-block-size: calc(var(--sc-kit--icon--size) + 2 * var(--_player-button--cell-padding));
98
+ min-inline-size: calc(var(--sc-kit--icon--size) + 2 * var(--_player-button--cell-padding));
99
+ --sc-kit--popover--content--background: var(--_player-button--color--inactive);
100
+ --sc-kit--popover--content--border-color: var(--_player-button--menu--border-color);
101
+ --sc-kit--popover-item--color: var(--_player-button--menu--item-color);
102
+ --sc-kit--popover-item--background--hover: var(--_player-button--menu--item-background-hover);
103
+ }
104
+ .player-button--menu:hover:not(:disabled) {
105
+ background-color: var(--_player-button--color--inactive);
106
+ }
72
107
  .player-button__icon {
73
108
  display: block;
74
109
  transform: scale(var(--_player-button--icon-scale));
@@ -79,7 +114,7 @@ Desktop player action buttons — renders a single circular button or a vertical
79
114
  }
80
115
  @container (width < 576px) {
81
116
  .player-button {
82
- padding: 0.5rem;
117
+ --_player-button--cell-padding: 0.5rem;
83
118
  --sc-kit--icon--size: 1.5rem;
84
119
  }
85
120
  }
@@ -87,6 +122,9 @@ Desktop player action buttons — renders a single circular button or a vertical
87
122
  .player-buttons {
88
123
  --_player-button--color: var(--sc-kit--player-button--color, rgb(0 0 0 / 95%));
89
124
  --_player-button--color--inactive: var(--sc-kit--player-button--color--inactive, rgb(0 0 0 / 60%));
125
+ --_player-button--menu--border-color: var(--sc-kit--player-button--menu--border-color, rgb(255 255 255 / 15%));
126
+ --_player-button--menu--item-color: var(--sc-kit--player-button--menu--item--color, var(--sc-kit--color--text--on-accent));
127
+ --_player-button--menu--item-background-hover: var(--sc-kit--player-button--menu--item--background--hover, rgb(255 255 255 / 12%));
90
128
  cursor: pointer;
91
129
  display: flex;
92
130
  flex-direction: column;
@@ -98,10 +136,11 @@ Desktop player action buttons — renders a single circular button or a vertical
98
136
  }
99
137
  .player-buttons__action {
100
138
  --_player-button--icon-scale: 1;
139
+ --_player-button--cell-padding: 0.5625rem;
101
140
  display: flex;
102
141
  justify-content: center;
103
142
  align-items: center;
104
- padding: 0.5625rem;
143
+ padding: var(--_player-button--cell-padding);
105
144
  border-radius: 1.25rem;
106
145
  color: var(--sc-kit--color--text--on-accent);
107
146
  --sc-kit--icon--color: var(--sc-kit--color--text--on-accent);
@@ -119,6 +158,18 @@ Desktop player action buttons — renders a single circular button or a vertical
119
158
  --_player-button--icon-scale: 1.2;
120
159
  background-color: transparent;
121
160
  }
161
+ .player-buttons__action--menu {
162
+ padding: 0;
163
+ min-block-size: calc(var(--sc-kit--icon--size) + 2 * var(--_player-button--cell-padding));
164
+ min-inline-size: calc(var(--sc-kit--icon--size) + 2 * var(--_player-button--cell-padding));
165
+ --sc-kit--popover--content--background: var(--_player-button--color--inactive);
166
+ --sc-kit--popover--content--border-color: var(--_player-button--menu--border-color);
167
+ --sc-kit--popover-item--color: var(--_player-button--menu--item-color);
168
+ --sc-kit--popover-item--background--hover: var(--_player-button--menu--item-background-hover);
169
+ }
170
+ .player-buttons__action--menu:hover:not(:disabled) {
171
+ background-color: transparent;
172
+ }
122
173
  .player-buttons__action-icon {
123
174
  display: block;
124
175
  transform: scale(var(--_player-button--icon-scale));
@@ -1,7 +1,12 @@
1
- import type { PlayerButtonDef } from './types';
1
+ import type { PlayerButtonDef, PlayerContextActionDef } from './types';
2
+ import type { Placement } from '@floating-ui/dom';
2
3
  type Props = {
3
4
  /** Array of button definitions (icon, callback, disabled state) */
4
5
  actions: PlayerButtonDef[];
6
+ /** Rows of an overflow menu rendered as the final cell — an ellipsis trigger opening a popover. Empty ⇒ no menu cell. @default [] */
7
+ contextActions?: PlayerContextActionDef[];
8
+ /** Floating UI placement of the overflow menu panel @default 'left-end' */
9
+ contextPosition?: Placement;
5
10
  /** Scale the icon on hover */
6
11
  scaleEffect?: boolean;
7
12
  /** CSS zoom level applied to the button container @default 1 */
@@ -9,12 +14,17 @@ type Props = {
9
14
  };
10
15
  /**
11
16
  * Desktop player action buttons — renders a single circular button or a vertically stacked pill for multiple actions.
17
+ * `contextActions` adds an overflow-menu cell as the last item; it counts towards the single / pill split, so one
18
+ * action plus a menu renders as a two-cell pill.
12
19
  *
13
20
  * ### CSS Custom Properties
14
21
  * | Property | Description | Default |
15
22
  * |---|---|---|
16
23
  * | `--sc-kit--player-button--color` | Button background at full opacity | `dark-500` / `black` at 95% |
17
- * | `--sc-kit--player-button--color--inactive` | Button background at rest | 60% opacity of `--color` |
24
+ * | `--sc-kit--player-button--color--inactive` | Button background at rest — the overflow menu panel takes the same value | 60% opacity of `--color` |
25
+ * | `--sc-kit--player-button--menu--border-color` | Overflow menu panel border | `white` at 15% |
26
+ * | `--sc-kit--player-button--menu--item--color` | Overflow menu row text / icon color | `--sc-kit--color--text--on-accent` |
27
+ * | `--sc-kit--player-button--menu--item--background--hover` | Overflow menu row hover background | `white` at 12% |
18
28
  */
19
29
  declare const Cmp: import("svelte").Component<Props, {}, "">;
20
30
  type Cmp = ReturnType<typeof Cmp>;
@@ -1,25 +1,29 @@
1
1
  <script lang="ts">import { default as MobilePlayerButtons } from './cmp.mobile-player-buttons.svelte';
2
2
  import { default as PlayerButtons } from './cmp.player-buttons.svelte';
3
- let { scaleEffect = false, actions } = $props();
3
+ let { scaleEffect = false, actions, contextActions = [], contextPosition = 'left-end' } = $props();
4
4
  </script>
5
5
 
6
6
  <div class="desktop-controls">
7
- <PlayerButtons actions={actions} scaleEffect={scaleEffect} />
7
+ <PlayerButtons actions={actions} contextActions={contextActions} contextPosition={contextPosition} scaleEffect={scaleEffect} />
8
8
  </div>
9
9
 
10
10
  <div class="mobile-controls">
11
- <MobilePlayerButtons actions={actions} />
11
+ <MobilePlayerButtons actions={actions} contextActions={contextActions} contextPosition={contextPosition} />
12
12
  </div>
13
13
 
14
14
  <!--
15
15
  @component
16
16
  Renders `PlayerButtons` on desktop and `MobilePlayerButtons` on mobile, switching via container query.
17
+ Both branches stay mounted, so `contextActions` builds a menu in each; only the visible one is reachable.
17
18
 
18
- ### Props
19
- | Prop | Type | Default | Description |
20
- |---|---|---|---|
21
- | `actions` | `PlayerButtonDef[]` || Array of button definitions |
22
- | `scaleEffect` | `boolean` | `false` | Whether icons scale on hover (desktop only) |
19
+ ### CSS Custom Properties
20
+ | Property | Description | Default |
21
+ |---|---|---|
22
+ | `--sc-kit--player-button--color` | Button background at full opacity (desktop only the mobile column paints no button background) | `black` at 95% |
23
+ | `--sc-kit--player-button--color--inactive` | Button background at rest the overflow menu panel takes the same value | 60% opacity of `--color` |
24
+ | `--sc-kit--player-button--menu--border-color` | Overflow menu panel border | `white` at 15% |
25
+ | `--sc-kit--player-button--menu--item--color` | Overflow menu row text / icon color | `--sc-kit--color--text--on-accent` |
26
+ | `--sc-kit--player-button--menu--item--background--hover` | Overflow menu row hover background | `white` at 12% |
23
27
  -->
24
28
 
25
29
  <style>.desktop-controls {
@@ -1,16 +1,26 @@
1
- import type { PlayerButtonDef } from './types';
1
+ import type { PlayerButtonDef, PlayerContextActionDef } from './types';
2
+ import type { Placement } from '@floating-ui/dom';
2
3
  type Props = {
3
4
  actions: PlayerButtonDef[];
5
+ /** Rows of an overflow menu rendered as the final cell — an ellipsis trigger opening a popover. Empty ⇒ no menu cell. @default [] */
6
+ contextActions?: PlayerContextActionDef[];
7
+ /** Floating UI placement of the overflow menu panel @default 'left-end' */
8
+ contextPosition?: Placement;
9
+ /** Scale the icon on hover (desktop only) */
4
10
  scaleEffect?: boolean;
5
11
  };
6
12
  /**
7
13
  * Renders `PlayerButtons` on desktop and `MobilePlayerButtons` on mobile, switching via container query.
14
+ * Both branches stay mounted, so `contextActions` builds a menu in each; only the visible one is reachable.
8
15
  *
9
- * ### Props
10
- * | Prop | Type | Default | Description |
11
- * |---|---|---|---|
12
- * | `actions` | `PlayerButtonDef[]` || Array of button definitions |
13
- * | `scaleEffect` | `boolean` | `false` | Whether icons scale on hover (desktop only) |
16
+ * ### CSS Custom Properties
17
+ * | Property | Description | Default |
18
+ * |---|---|---|
19
+ * | `--sc-kit--player-button--color` | Button background at full opacity (desktop only the mobile column paints no button background) | `black` at 95% |
20
+ * | `--sc-kit--player-button--color--inactive` | Button background at rest the overflow menu panel takes the same value | 60% opacity of `--color` |
21
+ * | `--sc-kit--player-button--menu--border-color` | Overflow menu panel border | `white` at 15% |
22
+ * | `--sc-kit--player-button--menu--item--color` | Overflow menu row text / icon color | `--sc-kit--color--text--on-accent` |
23
+ * | `--sc-kit--player-button--menu--item--background--hover` | Overflow menu row hover background | `white` at 12% |
14
24
  */
15
25
  declare const Cmp: import("svelte").Component<Props, {}, "">;
16
26
  type Cmp = ReturnType<typeof Cmp>;
@@ -1,4 +1,4 @@
1
1
  export { default as MobilePlayerButtons } from './cmp.mobile-player-buttons.svelte';
2
2
  export { default as PlayerButtons } from './cmp.player-buttons.svelte';
3
3
  export { default as ResponsivePlayerButtons } from './cmp.responsive-player-buttons.svelte';
4
- export type { PlayerButtonDef } from './types';
4
+ export type { PlayerButtonDef, PlayerContextActionDef } from './types';
@@ -0,0 +1,3 @@
1
+ export declare class PlayerButtonsLocalization {
2
+ get moreActions(): string;
3
+ }
@@ -0,0 +1,12 @@
1
+ import { AppLocale } from '../../../core/locale';
2
+ const loc = {
3
+ moreActions: {
4
+ en: 'More actions',
5
+ no: 'Flere handlinger'
6
+ }
7
+ };
8
+ export class PlayerButtonsLocalization {
9
+ get moreActions() {
10
+ return loc.moreActions[AppLocale.current];
11
+ }
12
+ }
@@ -0,0 +1,20 @@
1
+ <script lang="ts">import { IconSlot } from '../../icon';
2
+ import { IconText } from '../../icon-text';
3
+ import { Popover, PopoverItem } from '../../popover';
4
+ import { PlayerButtonsLocalization } from './player-buttons-localization';
5
+ import IconMoreVertical from '@fluentui/svg-icons/icons/more_vertical_28_regular.svg?raw';
6
+ let { actions, position = 'left-end' } = $props();
7
+ const localization = new PlayerButtonsLocalization();
8
+ </script>
9
+
10
+ <Popover position={position} fixedPosition fillContainer aria-label={localization.moreActions}>
11
+ {#snippet trigger()}
12
+ <IconSlot icon={IconMoreVertical} />
13
+ {/snippet}
14
+
15
+ {#each actions as action (action.label)}
16
+ <PopoverItem disabled={action.disabled} on={{ click: action.callback }}>
17
+ <IconText icon={action.icon} size="sm">{action.label}</IconText>
18
+ </PopoverItem>
19
+ {/each}
20
+ </Popover>
@@ -0,0 +1,9 @@
1
+ import type { PlayerContextActionDef } from './types';
2
+ import type { Placement } from '@floating-ui/dom';
3
+ type Props = {
4
+ actions: PlayerContextActionDef[];
5
+ position?: Placement;
6
+ };
7
+ declare const PlayerContextMenu: import("svelte").Component<Props, {}, "">;
8
+ type PlayerContextMenu = ReturnType<typeof PlayerContextMenu>;
9
+ export default PlayerContextMenu;
@@ -4,3 +4,9 @@ export type PlayerButtonDef = {
4
4
  callback: () => void;
5
5
  disabled?: boolean;
6
6
  };
7
+ export type PlayerContextActionDef = {
8
+ icon: IconProp;
9
+ label: string;
10
+ callback: () => void;
11
+ disabled?: boolean;
12
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",