@livepeer-frameworks/player-svelte 0.0.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.
- package/dist/DevModePanel.svelte +650 -0
- package/dist/DevModePanel.svelte.d.ts +31 -0
- package/dist/DvdLogo.svelte +213 -0
- package/dist/DvdLogo.svelte.d.ts +7 -0
- package/dist/Icons.svelte +27 -0
- package/dist/Icons.svelte.d.ts +25 -0
- package/dist/IdleScreen.svelte +752 -0
- package/dist/IdleScreen.svelte.d.ts +11 -0
- package/dist/LoadingScreen.svelte +689 -0
- package/dist/LoadingScreen.svelte.d.ts +7 -0
- package/dist/Player.svelte +482 -0
- package/dist/Player.svelte.d.ts +26 -0
- package/dist/PlayerControls.svelte +739 -0
- package/dist/PlayerControls.svelte.d.ts +20 -0
- package/dist/SeekBar.svelte +274 -0
- package/dist/SeekBar.svelte.d.ts +25 -0
- package/dist/SkipIndicator.svelte +95 -0
- package/dist/SkipIndicator.svelte.d.ts +14 -0
- package/dist/SpeedIndicator.svelte +38 -0
- package/dist/SpeedIndicator.svelte.d.ts +8 -0
- package/dist/StatsPanel.svelte +155 -0
- package/dist/StatsPanel.svelte.d.ts +27 -0
- package/dist/StreamStateOverlay.svelte +266 -0
- package/dist/StreamStateOverlay.svelte.d.ts +18 -0
- package/dist/SubtitleRenderer.svelte +234 -0
- package/dist/SubtitleRenderer.svelte.d.ts +41 -0
- package/dist/ThumbnailOverlay.svelte +96 -0
- package/dist/ThumbnailOverlay.svelte.d.ts +11 -0
- package/dist/TitleOverlay.svelte +47 -0
- package/dist/TitleOverlay.svelte.d.ts +9 -0
- package/dist/assets/logomark.svg +56 -0
- package/dist/components/VolumeIcons.svelte +53 -0
- package/dist/components/VolumeIcons.svelte.d.ts +10 -0
- package/dist/global.d.ts +15 -0
- package/dist/icons/FullscreenExitIcon.svelte +33 -0
- package/dist/icons/FullscreenExitIcon.svelte.d.ts +8 -0
- package/dist/icons/FullscreenIcon.svelte +33 -0
- package/dist/icons/FullscreenIcon.svelte.d.ts +8 -0
- package/dist/icons/PauseIcon.svelte +28 -0
- package/dist/icons/PauseIcon.svelte.d.ts +8 -0
- package/dist/icons/PictureInPictureIcon.svelte +28 -0
- package/dist/icons/PictureInPictureIcon.svelte.d.ts +8 -0
- package/dist/icons/PlayIcon.svelte +27 -0
- package/dist/icons/PlayIcon.svelte.d.ts +8 -0
- package/dist/icons/SeekToLiveIcon.svelte +30 -0
- package/dist/icons/SeekToLiveIcon.svelte.d.ts +8 -0
- package/dist/icons/SettingsIcon.svelte +40 -0
- package/dist/icons/SettingsIcon.svelte.d.ts +8 -0
- package/dist/icons/SkipBackIcon.svelte +32 -0
- package/dist/icons/SkipBackIcon.svelte.d.ts +8 -0
- package/dist/icons/SkipForwardIcon.svelte +32 -0
- package/dist/icons/SkipForwardIcon.svelte.d.ts +8 -0
- package/dist/icons/StatsIcon.svelte +29 -0
- package/dist/icons/StatsIcon.svelte.d.ts +8 -0
- package/dist/icons/VolumeOffIcon.svelte +29 -0
- package/dist/icons/VolumeOffIcon.svelte.d.ts +8 -0
- package/dist/icons/VolumeUpIcon.svelte +34 -0
- package/dist/icons/VolumeUpIcon.svelte.d.ts +8 -0
- package/dist/icons/index.d.ts +17 -0
- package/dist/icons/index.js +17 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +54 -0
- package/dist/player.css +2 -0
- package/dist/stores/index.d.ts +15 -0
- package/dist/stores/index.js +21 -0
- package/dist/stores/playbackQuality.d.ts +43 -0
- package/dist/stores/playbackQuality.js +107 -0
- package/dist/stores/playerContext.d.ts +73 -0
- package/dist/stores/playerContext.js +166 -0
- package/dist/stores/playerController.d.ts +178 -0
- package/dist/stores/playerController.js +358 -0
- package/dist/stores/playerSelection.d.ts +84 -0
- package/dist/stores/playerSelection.js +159 -0
- package/dist/stores/streamState.d.ts +44 -0
- package/dist/stores/streamState.js +314 -0
- package/dist/stores/viewerEndpoints.d.ts +48 -0
- package/dist/stores/viewerEndpoints.js +178 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +4 -0
- package/dist/ui/Badge.svelte +21 -0
- package/dist/ui/Badge.svelte.d.ts +32 -0
- package/dist/ui/Button.svelte +42 -0
- package/dist/ui/Button.svelte.d.ts +35 -0
- package/dist/ui/Slider.svelte +100 -0
- package/dist/ui/Slider.svelte.d.ts +17 -0
- package/dist/ui/badge.d.ts +6 -0
- package/dist/ui/badge.js +10 -0
- package/dist/ui/button.d.ts +8 -0
- package/dist/ui/button.js +21 -0
- package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte +34 -0
- package/dist/ui/context-menu/ContextMenuCheckboxItem.svelte.d.ts +31 -0
- package/dist/ui/context-menu/ContextMenuContent.svelte +17 -0
- package/dist/ui/context-menu/ContextMenuContent.svelte.d.ts +7 -0
- package/dist/ui/context-menu/ContextMenuItem.svelte +22 -0
- package/dist/ui/context-menu/ContextMenuItem.svelte.d.ts +8 -0
- package/dist/ui/context-menu/ContextMenuLabel.svelte +22 -0
- package/dist/ui/context-menu/ContextMenuLabel.svelte.d.ts +8 -0
- package/dist/ui/context-menu/ContextMenuPortal.svelte +11 -0
- package/dist/ui/context-menu/ContextMenuPortal.svelte.d.ts +6 -0
- package/dist/ui/context-menu/ContextMenuRadioItem.svelte +21 -0
- package/dist/ui/context-menu/ContextMenuRadioItem.svelte.d.ts +31 -0
- package/dist/ui/context-menu/ContextMenuSeparator.svelte +14 -0
- package/dist/ui/context-menu/ContextMenuSeparator.svelte.d.ts +6 -0
- package/dist/ui/context-menu/ContextMenuShortcut.svelte +19 -0
- package/dist/ui/context-menu/ContextMenuShortcut.svelte.d.ts +7 -0
- package/dist/ui/context-menu/ContextMenuSubContent.svelte +20 -0
- package/dist/ui/context-menu/ContextMenuSubContent.svelte.d.ts +7 -0
- package/dist/ui/context-menu/ContextMenuSubTrigger.svelte +34 -0
- package/dist/ui/context-menu/ContextMenuSubTrigger.svelte.d.ts +8 -0
- package/dist/ui/context-menu/index.d.ts +17 -0
- package/dist/ui/context-menu/index.js +17 -0
- package/package.json +51 -0
- package/src/DevModePanel.svelte +650 -0
- package/src/DvdLogo.svelte +213 -0
- package/src/Icons.svelte +27 -0
- package/src/IdleScreen.svelte +739 -0
- package/src/LoadingScreen.svelte +674 -0
- package/src/Player.svelte +483 -0
- package/src/PlayerControls.svelte +752 -0
- package/src/SeekBar.svelte +274 -0
- package/src/SkipIndicator.svelte +95 -0
- package/src/SpeedIndicator.svelte +37 -0
- package/src/StatsPanel.svelte +155 -0
- package/src/StreamStateOverlay.svelte +266 -0
- package/src/SubtitleRenderer.svelte +234 -0
- package/src/ThumbnailOverlay.svelte +96 -0
- package/src/TitleOverlay.svelte +47 -0
- package/src/assets/logomark.svg +56 -0
- package/src/components/VolumeIcons.svelte +53 -0
- package/src/global.d.ts +15 -0
- package/src/icons/FullscreenExitIcon.svelte +33 -0
- package/src/icons/FullscreenIcon.svelte +33 -0
- package/src/icons/PauseIcon.svelte +28 -0
- package/src/icons/PictureInPictureIcon.svelte +28 -0
- package/src/icons/PlayIcon.svelte +27 -0
- package/src/icons/SeekToLiveIcon.svelte +30 -0
- package/src/icons/SettingsIcon.svelte +40 -0
- package/src/icons/SkipBackIcon.svelte +32 -0
- package/src/icons/SkipForwardIcon.svelte +32 -0
- package/src/icons/StatsIcon.svelte +29 -0
- package/src/icons/VolumeOffIcon.svelte +29 -0
- package/src/icons/VolumeUpIcon.svelte +34 -0
- package/src/icons/index.ts +18 -0
- package/src/index.ts +84 -0
- package/src/player.css +2 -0
- package/src/stores/index.ts +88 -0
- package/src/stores/playbackQuality.ts +137 -0
- package/src/stores/playerContext.ts +221 -0
- package/src/stores/playerController.ts +568 -0
- package/src/stores/playerSelection.ts +216 -0
- package/src/stores/streamState.ts +367 -0
- package/src/stores/viewerEndpoints.ts +224 -0
- package/src/types.ts +6 -0
- package/src/ui/Badge.svelte +21 -0
- package/src/ui/Button.svelte +42 -0
- package/src/ui/Slider.svelte +100 -0
- package/src/ui/badge.ts +20 -0
- package/src/ui/button.ts +35 -0
- package/src/ui/context-menu/ContextMenuCheckboxItem.svelte +34 -0
- package/src/ui/context-menu/ContextMenuContent.svelte +17 -0
- package/src/ui/context-menu/ContextMenuItem.svelte +22 -0
- package/src/ui/context-menu/ContextMenuLabel.svelte +22 -0
- package/src/ui/context-menu/ContextMenuPortal.svelte +11 -0
- package/src/ui/context-menu/ContextMenuRadioItem.svelte +21 -0
- package/src/ui/context-menu/ContextMenuSeparator.svelte +14 -0
- package/src/ui/context-menu/ContextMenuShortcut.svelte +19 -0
- package/src/ui/context-menu/ContextMenuSubContent.svelte +20 -0
- package/src/ui/context-menu/ContextMenuSubTrigger.svelte +34 -0
- package/src/ui/context-menu/index.ts +36 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte store for Gateway GraphQL endpoint resolution with retry logic.
|
|
3
|
+
*
|
|
4
|
+
* Port of useViewerEndpoints.ts React hook to Svelte 5 stores.
|
|
5
|
+
*/
|
|
6
|
+
import { writable, derived } from 'svelte/store';
|
|
7
|
+
const MAX_RETRIES = 3;
|
|
8
|
+
const INITIAL_DELAY_MS = 500;
|
|
9
|
+
/**
|
|
10
|
+
* Fetch with exponential backoff retry
|
|
11
|
+
*/
|
|
12
|
+
async function fetchWithRetry(url, options, maxRetries = MAX_RETRIES, initialDelay = INITIAL_DELAY_MS) {
|
|
13
|
+
let lastError = null;
|
|
14
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
15
|
+
try {
|
|
16
|
+
const response = await fetch(url, options);
|
|
17
|
+
return response;
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
lastError = e instanceof Error ? e : new Error('Fetch failed');
|
|
21
|
+
// Don't retry on abort
|
|
22
|
+
if (options.signal?.aborted) {
|
|
23
|
+
throw lastError;
|
|
24
|
+
}
|
|
25
|
+
// Wait before retrying (exponential backoff)
|
|
26
|
+
if (attempt < maxRetries - 1) {
|
|
27
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
28
|
+
console.warn(`[viewerEndpoints] Retry ${attempt + 1}/${maxRetries - 1} after ${delay}ms`);
|
|
29
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
throw lastError ?? new Error('Gateway unreachable after retries');
|
|
34
|
+
}
|
|
35
|
+
const initialState = {
|
|
36
|
+
endpoints: null,
|
|
37
|
+
status: 'idle',
|
|
38
|
+
error: null,
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Create a viewer endpoints resolver store for Gateway GraphQL queries.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```svelte
|
|
45
|
+
* <script>
|
|
46
|
+
* import { createEndpointResolver } from './stores/viewerEndpoints';
|
|
47
|
+
*
|
|
48
|
+
* const resolver = createEndpointResolver({
|
|
49
|
+
* gatewayUrl: 'https://gateway.example.com/graphql',
|
|
50
|
+
* contentType: 'live',
|
|
51
|
+
* contentId: 'my-stream',
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* $: endpoints = $resolver.endpoints;
|
|
55
|
+
* $: status = $resolver.status;
|
|
56
|
+
* </script>
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function createEndpointResolver(options) {
|
|
60
|
+
const { gatewayUrl, contentType, contentId, authToken } = options;
|
|
61
|
+
const store = writable(initialState);
|
|
62
|
+
let abortController = null;
|
|
63
|
+
let mounted = true;
|
|
64
|
+
/**
|
|
65
|
+
* Fetch endpoints from Gateway
|
|
66
|
+
*/
|
|
67
|
+
async function fetchEndpoints() {
|
|
68
|
+
if (!gatewayUrl || !contentType || !contentId || !mounted)
|
|
69
|
+
return;
|
|
70
|
+
// Abort previous request
|
|
71
|
+
abortController?.abort();
|
|
72
|
+
abortController = new AbortController();
|
|
73
|
+
store.update(s => ({ ...s, status: 'loading', error: null }));
|
|
74
|
+
try {
|
|
75
|
+
const graphqlEndpoint = gatewayUrl.replace(/\/$/, '');
|
|
76
|
+
const query = `
|
|
77
|
+
query ResolveViewer($contentType: String!, $contentId: String!) {
|
|
78
|
+
resolveViewerEndpoint(contentType: $contentType, contentId: $contentId) {
|
|
79
|
+
primary { nodeId baseUrl protocol url geoDistance loadScore outputs }
|
|
80
|
+
fallbacks { nodeId baseUrl protocol url geoDistance loadScore outputs }
|
|
81
|
+
metadata { contentType contentId title description durationSeconds status isLive viewers recordingSizeBytes clipSource createdAt }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
85
|
+
const res = await fetchWithRetry(graphqlEndpoint, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: {
|
|
88
|
+
'Content-Type': 'application/json',
|
|
89
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
90
|
+
},
|
|
91
|
+
body: JSON.stringify({ query, variables: { contentType, contentId } }),
|
|
92
|
+
signal: abortController.signal,
|
|
93
|
+
});
|
|
94
|
+
if (!res.ok)
|
|
95
|
+
throw new Error(`Gateway GQL error ${res.status}`);
|
|
96
|
+
const payload = await res.json();
|
|
97
|
+
if (payload.errors?.length) {
|
|
98
|
+
throw new Error(payload.errors[0]?.message || 'GraphQL error');
|
|
99
|
+
}
|
|
100
|
+
const resp = payload.data?.resolveViewerEndpoint;
|
|
101
|
+
const primary = resp?.primary;
|
|
102
|
+
const fallbacks = Array.isArray(resp?.fallbacks) ? resp.fallbacks : [];
|
|
103
|
+
if (!primary)
|
|
104
|
+
throw new Error('No endpoints');
|
|
105
|
+
// Parse outputs JSON string (GraphQL returns JSON scalar as string)
|
|
106
|
+
if (primary.outputs && typeof primary.outputs === 'string') {
|
|
107
|
+
try {
|
|
108
|
+
primary.outputs = JSON.parse(primary.outputs);
|
|
109
|
+
}
|
|
110
|
+
catch { }
|
|
111
|
+
}
|
|
112
|
+
if (fallbacks) {
|
|
113
|
+
fallbacks.forEach((fb) => {
|
|
114
|
+
if (fb.outputs && typeof fb.outputs === 'string') {
|
|
115
|
+
try {
|
|
116
|
+
fb.outputs = JSON.parse(fb.outputs);
|
|
117
|
+
}
|
|
118
|
+
catch { }
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
store.set({
|
|
123
|
+
endpoints: { primary, fallbacks, metadata: resp?.metadata },
|
|
124
|
+
status: 'ready',
|
|
125
|
+
error: null,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
if (abortController?.signal.aborted || !mounted)
|
|
130
|
+
return;
|
|
131
|
+
const message = e instanceof Error ? e.message : 'Unknown gateway error';
|
|
132
|
+
console.error('[viewerEndpoints] Gateway resolution failed:', message);
|
|
133
|
+
store.set({
|
|
134
|
+
endpoints: null,
|
|
135
|
+
status: 'error',
|
|
136
|
+
error: message,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Manual refetch
|
|
142
|
+
*/
|
|
143
|
+
function refetch() {
|
|
144
|
+
fetchEndpoints();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Cleanup
|
|
148
|
+
*/
|
|
149
|
+
function destroy() {
|
|
150
|
+
mounted = false;
|
|
151
|
+
abortController?.abort();
|
|
152
|
+
abortController = null;
|
|
153
|
+
store.set(initialState);
|
|
154
|
+
}
|
|
155
|
+
// Auto-fetch on creation if params are valid
|
|
156
|
+
if (gatewayUrl && contentType && contentId) {
|
|
157
|
+
fetchEndpoints();
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
subscribe: store.subscribe,
|
|
161
|
+
refetch,
|
|
162
|
+
destroy,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
// Convenience derived stores
|
|
166
|
+
export function createDerivedEndpoints(store) {
|
|
167
|
+
return derived(store, $state => $state.endpoints);
|
|
168
|
+
}
|
|
169
|
+
export function createDerivedPrimaryEndpoint(store) {
|
|
170
|
+
return derived(store, $state => $state.endpoints?.primary ?? null);
|
|
171
|
+
}
|
|
172
|
+
export function createDerivedMetadata(store) {
|
|
173
|
+
return derived(store, $state => $state.endpoints?.metadata ?? null);
|
|
174
|
+
}
|
|
175
|
+
export function createDerivedStatus(store) {
|
|
176
|
+
return derived(store, $state => $state.status);
|
|
177
|
+
}
|
|
178
|
+
export default createEndpointResolver;
|
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '@livepeer-frameworks/player-core';
|
|
3
|
+
import { badgeVariants, type BadgeVariant } from './badge';
|
|
4
|
+
|
|
5
|
+
type $$Props = {
|
|
6
|
+
variant?: BadgeVariant;
|
|
7
|
+
class?: string;
|
|
8
|
+
} & Record<string, any>;
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
variant = "default",
|
|
12
|
+
class: className = "",
|
|
13
|
+
...rest
|
|
14
|
+
}: $$Props = $props();
|
|
15
|
+
|
|
16
|
+
let mergedClasses = $derived(cn(badgeVariants(variant, className)));
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<div class={mergedClasses} {...rest}>
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type BadgeVariant } from './badge';
|
|
2
|
+
type $$Props = {
|
|
3
|
+
variant?: BadgeVariant;
|
|
4
|
+
class?: string;
|
|
5
|
+
} & Record<string, any>;
|
|
6
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
7
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
8
|
+
$$bindings?: Bindings;
|
|
9
|
+
} & Exports;
|
|
10
|
+
(internal: unknown, props: Props & {
|
|
11
|
+
$$events?: Events;
|
|
12
|
+
$$slots?: Slots;
|
|
13
|
+
}): Exports & {
|
|
14
|
+
$set?: any;
|
|
15
|
+
$on?: any;
|
|
16
|
+
};
|
|
17
|
+
z_$$bindings?: Bindings;
|
|
18
|
+
}
|
|
19
|
+
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
20
|
+
default: any;
|
|
21
|
+
} ? Props extends Record<string, never> ? any : {
|
|
22
|
+
children?: any;
|
|
23
|
+
} : {});
|
|
24
|
+
declare const Badge: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<$$Props, {
|
|
25
|
+
default: {};
|
|
26
|
+
}>, {
|
|
27
|
+
[evt: string]: CustomEvent<any>;
|
|
28
|
+
}, {
|
|
29
|
+
default: {};
|
|
30
|
+
}, {}, "">;
|
|
31
|
+
type Badge = InstanceType<typeof Badge>;
|
|
32
|
+
export default Badge;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '@livepeer-frameworks/player-core';
|
|
3
|
+
import { buttonVariants, type ButtonSize, type ButtonVariant } from './button';
|
|
4
|
+
import { getContext, setContext } from 'svelte';
|
|
5
|
+
|
|
6
|
+
type $$Props = {
|
|
7
|
+
variant?: ButtonVariant;
|
|
8
|
+
size?: ButtonSize;
|
|
9
|
+
class?: string;
|
|
10
|
+
asChild?: boolean;
|
|
11
|
+
type?: "button" | "submit" | "reset";
|
|
12
|
+
} & Record<string, any>;
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
variant = "default",
|
|
16
|
+
size = "default",
|
|
17
|
+
class: className = "",
|
|
18
|
+
asChild = false,
|
|
19
|
+
type = "button",
|
|
20
|
+
...rest
|
|
21
|
+
}: $$Props = $props();
|
|
22
|
+
|
|
23
|
+
let Comp: string = "button";
|
|
24
|
+
if (asChild) {
|
|
25
|
+
Comp = getContext('__svelte_slot_element') || 'div';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Set context for potential nested slots (though less common for Button)
|
|
29
|
+
setContext('__svelte_slot_element', Comp);
|
|
30
|
+
|
|
31
|
+
let mergedClasses = $derived(cn(buttonVariants(variant, size, className)));
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
{#if asChild}
|
|
35
|
+
<svelte:element this={Comp} class={mergedClasses} {...rest}>
|
|
36
|
+
<slot />
|
|
37
|
+
</svelte:element>
|
|
38
|
+
{:else}
|
|
39
|
+
<button class={mergedClasses} type={type} {...rest}>
|
|
40
|
+
<slot />
|
|
41
|
+
</button>
|
|
42
|
+
{/if}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ButtonSize, type ButtonVariant } from './button';
|
|
2
|
+
type $$Props = {
|
|
3
|
+
variant?: ButtonVariant;
|
|
4
|
+
size?: ButtonSize;
|
|
5
|
+
class?: string;
|
|
6
|
+
asChild?: boolean;
|
|
7
|
+
type?: "button" | "submit" | "reset";
|
|
8
|
+
} & Record<string, any>;
|
|
9
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
10
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
11
|
+
$$bindings?: Bindings;
|
|
12
|
+
} & Exports;
|
|
13
|
+
(internal: unknown, props: Props & {
|
|
14
|
+
$$events?: Events;
|
|
15
|
+
$$slots?: Slots;
|
|
16
|
+
}): Exports & {
|
|
17
|
+
$set?: any;
|
|
18
|
+
$on?: any;
|
|
19
|
+
};
|
|
20
|
+
z_$$bindings?: Bindings;
|
|
21
|
+
}
|
|
22
|
+
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
23
|
+
default: any;
|
|
24
|
+
} ? Props extends Record<string, never> ? any : {
|
|
25
|
+
children?: any;
|
|
26
|
+
} : {});
|
|
27
|
+
declare const Button: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<$$Props, {
|
|
28
|
+
default: {};
|
|
29
|
+
}>, {
|
|
30
|
+
[evt: string]: CustomEvent<any>;
|
|
31
|
+
}, {
|
|
32
|
+
default: {};
|
|
33
|
+
}, {}, "">;
|
|
34
|
+
type Button = InstanceType<typeof Button>;
|
|
35
|
+
export default Button;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Slider as BitsSlider } from "bits-ui";
|
|
3
|
+
import { cn } from "@livepeer-frameworks/player-core";
|
|
4
|
+
|
|
5
|
+
type $$Props = {
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
step?: number;
|
|
9
|
+
value?: number;
|
|
10
|
+
orientation?: "horizontal" | "vertical";
|
|
11
|
+
className?: string;
|
|
12
|
+
showTrack?: boolean;
|
|
13
|
+
trackClassName?: string;
|
|
14
|
+
thumbClassName?: string;
|
|
15
|
+
hoverThumb?: boolean;
|
|
16
|
+
accentColor?: boolean;
|
|
17
|
+
oninput?: (value: number) => void;
|
|
18
|
+
} & Record<string, any>;
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
min = 0,
|
|
22
|
+
max = 100,
|
|
23
|
+
step = 1,
|
|
24
|
+
value = 0,
|
|
25
|
+
orientation = "horizontal",
|
|
26
|
+
className = "",
|
|
27
|
+
trackClassName = "",
|
|
28
|
+
thumbClassName = "",
|
|
29
|
+
showTrack = true,
|
|
30
|
+
hoverThumb = false,
|
|
31
|
+
accentColor = false,
|
|
32
|
+
oninput = undefined,
|
|
33
|
+
...rest
|
|
34
|
+
}: $$Props = $props();
|
|
35
|
+
|
|
36
|
+
// Colors based on accentColor prop
|
|
37
|
+
const rangeColorClass = $derived(accentColor ? "bg-[hsl(var(--tn-cyan,195_100%_50%))]" : "bg-white/90");
|
|
38
|
+
const thumbColorClass = $derived(accentColor ? "bg-[hsl(var(--tn-cyan,195_100%_50%))]" : "bg-white");
|
|
39
|
+
|
|
40
|
+
function handleValueChange(newValue: number) {
|
|
41
|
+
value = newValue;
|
|
42
|
+
if (oninput) {
|
|
43
|
+
// Defensive: ensure we pass a valid finite number (prevents NaN propagation)
|
|
44
|
+
if (typeof newValue === 'number' && Number.isFinite(newValue)) {
|
|
45
|
+
oninput(newValue);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<div
|
|
52
|
+
class={cn(
|
|
53
|
+
"group relative flex touch-none select-none items-center cursor-pointer",
|
|
54
|
+
orientation === "horizontal" ? "w-full h-5" : "h-full flex-col w-5",
|
|
55
|
+
className
|
|
56
|
+
)}
|
|
57
|
+
>
|
|
58
|
+
<BitsSlider.Root
|
|
59
|
+
type="single"
|
|
60
|
+
{min}
|
|
61
|
+
{max}
|
|
62
|
+
{step}
|
|
63
|
+
{value}
|
|
64
|
+
onValueChange={handleValueChange}
|
|
65
|
+
{orientation}
|
|
66
|
+
class="w-full h-full relative flex items-center"
|
|
67
|
+
{...rest}
|
|
68
|
+
>
|
|
69
|
+
{#if showTrack}
|
|
70
|
+
<div
|
|
71
|
+
class={cn(
|
|
72
|
+
"absolute rounded-full bg-white/30 transition-all duration-150",
|
|
73
|
+
orientation === "horizontal"
|
|
74
|
+
? "inset-x-0 h-1 group-hover:h-1.5"
|
|
75
|
+
: "inset-y-0 w-1 group-hover:w-1.5",
|
|
76
|
+
trackClassName
|
|
77
|
+
)}
|
|
78
|
+
>
|
|
79
|
+
<BitsSlider.Range
|
|
80
|
+
class={cn(
|
|
81
|
+
"absolute rounded-full transition-all duration-150",
|
|
82
|
+
orientation === "horizontal" ? "h-full" : "w-full bottom-0",
|
|
83
|
+
rangeColorClass
|
|
84
|
+
)}
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
{/if}
|
|
88
|
+
<BitsSlider.Thumb
|
|
89
|
+
index={0}
|
|
90
|
+
class={cn(
|
|
91
|
+
"block rounded-full border-0 cursor-pointer shadow-md transition-all duration-150",
|
|
92
|
+
"w-2.5 h-2.5 group-hover:w-3.5 group-hover:h-3.5",
|
|
93
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/50",
|
|
94
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
95
|
+
thumbColorClass,
|
|
96
|
+
thumbClassName
|
|
97
|
+
)}
|
|
98
|
+
/>
|
|
99
|
+
</BitsSlider.Root>
|
|
100
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type $$Props = {
|
|
2
|
+
min?: number;
|
|
3
|
+
max?: number;
|
|
4
|
+
step?: number;
|
|
5
|
+
value?: number;
|
|
6
|
+
orientation?: "horizontal" | "vertical";
|
|
7
|
+
className?: string;
|
|
8
|
+
showTrack?: boolean;
|
|
9
|
+
trackClassName?: string;
|
|
10
|
+
thumbClassName?: string;
|
|
11
|
+
hoverThumb?: boolean;
|
|
12
|
+
accentColor?: boolean;
|
|
13
|
+
oninput?: (value: number) => void;
|
|
14
|
+
} & Record<string, any>;
|
|
15
|
+
declare const Slider: import("svelte").Component<$$Props, {}, "">;
|
|
16
|
+
type Slider = ReturnType<typeof Slider>;
|
|
17
|
+
export default Slider;
|
package/dist/ui/badge.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const badgeVariants = (variant = "default", className) => {
|
|
2
|
+
const baseClasses = "inline-flex items-center rounded-full border border-transparent px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 ring-offset-background";
|
|
3
|
+
const variants = {
|
|
4
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
|
5
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
6
|
+
outline: "border-border text-foreground"
|
|
7
|
+
};
|
|
8
|
+
const selectedVariant = variants[variant] || variants.default;
|
|
9
|
+
return `${baseClasses} ${selectedVariant} ${className || ""}`;
|
|
10
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const buttonVariants: (variant?: ButtonVariant, size?: ButtonSize, className?: string) => string;
|
|
2
|
+
export type ButtonVariant = "default" | "secondary" | "ghost" | "outline" | "destructive" | "subtle" | "link";
|
|
3
|
+
export type ButtonSize = "default" | "sm" | "lg" | "icon";
|
|
4
|
+
export type ButtonProps = {
|
|
5
|
+
variant?: ButtonVariant;
|
|
6
|
+
size?: ButtonSize;
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const buttonVariants = (variant = "default", size = "default", className) => {
|
|
2
|
+
const baseClasses = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ring-offset-background";
|
|
3
|
+
const variants = {
|
|
4
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
5
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
6
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
7
|
+
outline: "border border-border bg-transparent hover:bg-accent hover:text-accent-foreground",
|
|
8
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
9
|
+
subtle: "bg-muted text-muted-foreground hover:bg-muted/80",
|
|
10
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
11
|
+
};
|
|
12
|
+
const sizes = {
|
|
13
|
+
default: "h-10 px-4 py-2",
|
|
14
|
+
sm: "h-9 rounded-md px-3",
|
|
15
|
+
lg: "h-11 rounded-md px-8",
|
|
16
|
+
icon: "h-9 w-9"
|
|
17
|
+
};
|
|
18
|
+
const selectedVariant = variants[variant] || variants.default;
|
|
19
|
+
const selectedSize = sizes[size] || sizes.default;
|
|
20
|
+
return `${baseClasses} ${selectedVariant} ${selectedSize} ${className || ""}`;
|
|
21
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ContextMenu } from "bits-ui";
|
|
3
|
+
import { cn } from "@livepeer-frameworks/player-core";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
class: className,
|
|
7
|
+
checked = false,
|
|
8
|
+
...rest
|
|
9
|
+
}: { class?: string; checked?: boolean } & Record<string, any> = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<ContextMenu.CheckboxItem
|
|
13
|
+
class={cn("fw-context-menu-checkbox", className)}
|
|
14
|
+
{checked}
|
|
15
|
+
{...rest}
|
|
16
|
+
>
|
|
17
|
+
<div class="fw-context-menu-indicator">
|
|
18
|
+
{#if checked}
|
|
19
|
+
<svg
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
viewBox="0 0 24 24"
|
|
22
|
+
fill="none"
|
|
23
|
+
stroke="currentColor"
|
|
24
|
+
stroke-width="2"
|
|
25
|
+
stroke-linecap="round"
|
|
26
|
+
stroke-linejoin="round"
|
|
27
|
+
class="h-4 w-4"
|
|
28
|
+
>
|
|
29
|
+
<polyline points="20 6 9 17 4 12" />
|
|
30
|
+
</svg>
|
|
31
|
+
{/if}
|
|
32
|
+
</div>
|
|
33
|
+
<slot />
|
|
34
|
+
</ContextMenu.CheckboxItem>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
class?: string;
|
|
3
|
+
checked?: boolean;
|
|
4
|
+
} & Record<string, any>;
|
|
5
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
6
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
7
|
+
$$bindings?: Bindings;
|
|
8
|
+
} & Exports;
|
|
9
|
+
(internal: unknown, props: Props & {
|
|
10
|
+
$$events?: Events;
|
|
11
|
+
$$slots?: Slots;
|
|
12
|
+
}): Exports & {
|
|
13
|
+
$set?: any;
|
|
14
|
+
$on?: any;
|
|
15
|
+
};
|
|
16
|
+
z_$$bindings?: Bindings;
|
|
17
|
+
}
|
|
18
|
+
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
19
|
+
default: any;
|
|
20
|
+
} ? Props extends Record<string, never> ? any : {
|
|
21
|
+
children?: any;
|
|
22
|
+
} : {});
|
|
23
|
+
declare const ContextMenuCheckboxItem: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<$$ComponentProps, {
|
|
24
|
+
default: {};
|
|
25
|
+
}>, {
|
|
26
|
+
[evt: string]: CustomEvent<any>;
|
|
27
|
+
}, {
|
|
28
|
+
default: {};
|
|
29
|
+
}, {}, "">;
|
|
30
|
+
type ContextMenuCheckboxItem = InstanceType<typeof ContextMenuCheckboxItem>;
|
|
31
|
+
export default ContextMenuCheckboxItem;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ContextMenu } from "bits-ui";
|
|
3
|
+
import { cn } from "@livepeer-frameworks/player-core";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
children,
|
|
7
|
+
class: className,
|
|
8
|
+
...rest
|
|
9
|
+
}: { children?: any; class?: string } = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<ContextMenu.Content
|
|
13
|
+
class={cn("fw-player-surface fw-context-menu", className)}
|
|
14
|
+
{...rest}
|
|
15
|
+
>
|
|
16
|
+
{@render children?.()}
|
|
17
|
+
</ContextMenu.Content>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ContextMenu } from "bits-ui";
|
|
3
|
+
import { cn } from "@livepeer-frameworks/player-core";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
children,
|
|
7
|
+
class: className,
|
|
8
|
+
inset = false,
|
|
9
|
+
...rest
|
|
10
|
+
}: { children?: any; class?: string; inset?: boolean } & Record<string, any> = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<ContextMenu.Item
|
|
14
|
+
class={cn(
|
|
15
|
+
"fw-context-menu-item",
|
|
16
|
+
inset && "fw-context-menu-item--inset",
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
{...rest}
|
|
20
|
+
>
|
|
21
|
+
{@render children?.()}
|
|
22
|
+
</ContextMenu.Item>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
children?: any;
|
|
3
|
+
class?: string;
|
|
4
|
+
inset?: boolean;
|
|
5
|
+
} & Record<string, any>;
|
|
6
|
+
declare const ContextMenuItem: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type ContextMenuItem = ReturnType<typeof ContextMenuItem>;
|
|
8
|
+
export default ContextMenuItem;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ContextMenu } from "bits-ui";
|
|
3
|
+
import { cn } from "@livepeer-frameworks/player-core";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
children,
|
|
7
|
+
class: className,
|
|
8
|
+
inset = false,
|
|
9
|
+
...rest
|
|
10
|
+
}: { children?: any; class?: string; inset?: boolean } & Record<string, any> = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<ContextMenu.GroupHeading
|
|
14
|
+
class={cn(
|
|
15
|
+
"fw-context-menu-label",
|
|
16
|
+
inset && "fw-context-menu-item--inset",
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
{...rest}
|
|
20
|
+
>
|
|
21
|
+
{@render children?.()}
|
|
22
|
+
</ContextMenu.GroupHeading>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
children?: any;
|
|
3
|
+
class?: string;
|
|
4
|
+
inset?: boolean;
|
|
5
|
+
} & Record<string, any>;
|
|
6
|
+
declare const ContextMenuLabel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type ContextMenuLabel = ReturnType<typeof ContextMenuLabel>;
|
|
8
|
+
export default ContextMenuLabel;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ContextMenu } from "bits-ui";
|
|
3
|
+
|
|
4
|
+
let { children, ...rest }: { children?: any } = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<ContextMenu.Portal {...rest}>
|
|
8
|
+
<div class="fw-player-surface">
|
|
9
|
+
{@render children?.()}
|
|
10
|
+
</div>
|
|
11
|
+
</ContextMenu.Portal>
|