@streamscloud/kit 0.1.12-1772032209109 → 0.1.12-1772041668184
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/ui/dialog/dialogs.svelte.js +3 -3
- package/dist/ui/media-viewer-dialog/cmp.media-viewer-dialog.svelte +1 -1
- package/dist/ui/media-viewer-dialog/index.d.ts +1 -0
- package/dist/ui/media-viewer-dialog/index.js +1 -0
- package/dist/ui/media-viewer-dialog/types.d.ts +2 -0
- package/dist/ui/player/carousel/cmp.carousel.svelte +23 -2
- package/dist/ui/player/carousel/cmp.carousel.svelte.d.ts +2 -0
- package/dist/ui/player/feed-slider/cmp.feed-slider.svelte +3 -5
- package/dist/ui/player/utils/index.d.ts +1 -0
- package/dist/ui/player/utils/index.js +1 -0
- package/dist/ui/player/{feed-slider → utils}/wheel-gestures-adapter.d.ts +6 -2
- package/dist/ui/player/{feed-slider → utils}/wheel-gestures-adapter.js +22 -13
- package/package.json +1 -1
|
@@ -62,14 +62,14 @@ export class DialogsContainer {
|
|
|
62
62
|
if (this._savedOverflow !== null) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
|
-
this._savedOverflow = document.
|
|
66
|
-
document.
|
|
65
|
+
this._savedOverflow = document.documentElement.style.overflow;
|
|
66
|
+
document.documentElement.style.overflow = 'hidden';
|
|
67
67
|
};
|
|
68
68
|
unlockBodyScroll = () => {
|
|
69
69
|
if (this._savedOverflow === null) {
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
|
-
document.
|
|
72
|
+
document.documentElement.style.overflow = this._savedOverflow;
|
|
73
73
|
this._savedOverflow = null;
|
|
74
74
|
};
|
|
75
75
|
}
|
|
@@ -18,7 +18,7 @@ $effect(() => untrack(() => {
|
|
|
18
18
|
{#if data.items.length === 1}
|
|
19
19
|
<MediaViewerItem item={data.items[0]} />
|
|
20
20
|
{:else}
|
|
21
|
-
<Carousel items={data.items} initialIndex={data.index} mode=
|
|
21
|
+
<Carousel items={data.items} initialIndex={data.index} mode={data.carouselMode ?? 'arrows-with-counts'} wheelNavigation on={{ indexChanged: () => {} }}>
|
|
22
22
|
{#snippet children(item)}
|
|
23
23
|
<MediaViewerItem item={item} />
|
|
24
24
|
{/snippet}
|
|
@@ -8,6 +8,7 @@ import type { MediaViewerData } from './types';
|
|
|
8
8
|
* - `items` — array of media items to display
|
|
9
9
|
* - `index` — zero-based index of the initially visible item
|
|
10
10
|
* - `backgroundOpacity` — backdrop opacity (default `0.6`)
|
|
11
|
+
* - `carouselMode` — carousel navigation mode (default `'arrows-with-counts'`)
|
|
11
12
|
*/
|
|
12
13
|
export declare const openMediaViewer: (data: MediaViewerData) => Promise<DialogResult<void>>;
|
|
13
14
|
export type { MediaViewerData, MediaViewerItem, MediaViewerItemType } from './types';
|
|
@@ -8,6 +8,7 @@ import { default as MediaViewerDialog } from './cmp.media-viewer-dialog.svelte';
|
|
|
8
8
|
* - `items` — array of media items to display
|
|
9
9
|
* - `index` — zero-based index of the initially visible item
|
|
10
10
|
* - `backgroundOpacity` — backdrop opacity (default `0.6`)
|
|
11
|
+
* - `carouselMode` — carousel navigation mode (default `'arrows-with-counts'`)
|
|
11
12
|
*/
|
|
12
13
|
export const openMediaViewer = (data) => {
|
|
13
14
|
return Dialogs.open({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CarouselMode } from '../player/carousel';
|
|
1
2
|
export type MediaViewerItemType = 'image' | 'video';
|
|
2
3
|
export type MediaViewerItem = {
|
|
3
4
|
url: string;
|
|
@@ -10,4 +11,5 @@ export type MediaViewerData = {
|
|
|
10
11
|
items: MediaViewerItem[];
|
|
11
12
|
index: number;
|
|
12
13
|
backgroundOpacity?: number;
|
|
14
|
+
carouselMode?: CarouselMode;
|
|
13
15
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang="ts" generics="T">import { Utils, isBrowser } from '../../../core/utils';
|
|
2
2
|
import { Icon } from '../../icon';
|
|
3
|
-
import { TouchSynchronizer } from '../utils';
|
|
3
|
+
import { TouchSynchronizer, createWheelAdapter } from '../utils';
|
|
4
4
|
import { CarouselLocalization } from './carousel-localization';
|
|
5
5
|
import IconChevronLeft from '@fluentui/svg-icons/icons/chevron_left_20_regular.svg?raw';
|
|
6
6
|
import IconChevronRight from '@fluentui/svg-icons/icons/chevron_right_20_regular.svg?raw';
|
|
7
7
|
import { onDestroy, onMount, untrack } from 'svelte';
|
|
8
|
-
let { items, mode = 'arrows-with-counts', initialIndex, autoSlideMs = 0, on, dot, children } = $props();
|
|
8
|
+
let { items, mode = 'arrows-with-counts', initialIndex, autoSlideMs = 0, wheelNavigation = false, on, dot, children } = $props();
|
|
9
9
|
const localization = new CarouselLocalization();
|
|
10
10
|
const itemIndices = $derived(items.map((_, index) => index));
|
|
11
11
|
const animationDuration = 300;
|
|
@@ -17,6 +17,20 @@ let slidesRef;
|
|
|
17
17
|
let sliderWidth = $state(0);
|
|
18
18
|
let swipeTransition = $state(0);
|
|
19
19
|
let resizeObserver;
|
|
20
|
+
let wheelAdapter = null;
|
|
21
|
+
const wheelCallbacks = {
|
|
22
|
+
canLoadNext: () => items.length > 1,
|
|
23
|
+
canLoadPrevious: () => items.length > 1,
|
|
24
|
+
onTrigger: (direction) => {
|
|
25
|
+
if (direction === 'next') {
|
|
26
|
+
loadNext();
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
loadPrevious();
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
getAnimationDurationMs: () => animationDuration
|
|
33
|
+
};
|
|
20
34
|
onMount(() => {
|
|
21
35
|
notifyIndexChanged();
|
|
22
36
|
setTimeout(() => {
|
|
@@ -132,6 +146,12 @@ onMount(() => {
|
|
|
132
146
|
if (isBrowser()) {
|
|
133
147
|
window.addEventListener(`keydown`, onKeyPress);
|
|
134
148
|
}
|
|
149
|
+
if (wheelNavigation) {
|
|
150
|
+
wheelAdapter = createWheelAdapter(slidesRef, {
|
|
151
|
+
axis: 'x',
|
|
152
|
+
cbs: wheelCallbacks
|
|
153
|
+
});
|
|
154
|
+
}
|
|
135
155
|
});
|
|
136
156
|
onDestroy(() => {
|
|
137
157
|
if (resizeObserver) {
|
|
@@ -143,6 +163,7 @@ onDestroy(() => {
|
|
|
143
163
|
window.clearInterval(interval);
|
|
144
164
|
}
|
|
145
165
|
}
|
|
166
|
+
wheelAdapter?.destroy();
|
|
146
167
|
});
|
|
147
168
|
const onKeyPress = Utils.throttle((e) => {
|
|
148
169
|
if (e.key === 'ArrowLeft') {
|
|
@@ -10,6 +10,8 @@ declare function $$render<T>(): {
|
|
|
10
10
|
mode?: CarouselMode;
|
|
11
11
|
/** Auto-advance interval in ms; 0 disables auto-sliding @default 0 */
|
|
12
12
|
autoSlideMs?: number;
|
|
13
|
+
/** Convert vertical mouse wheel scroll to slide navigation @default false */
|
|
14
|
+
wheelNavigation?: boolean;
|
|
13
15
|
on?: {
|
|
14
16
|
/** Fires after the active slide changes */
|
|
15
17
|
indexChanged: (index: number) => void;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
<script lang="ts" generics="T extends { id: string }">import { TouchSynchronizer } from '../utils';
|
|
2
|
-
import { createWheelAdapter } from './wheel-gestures-adapter';
|
|
1
|
+
<script lang="ts" generics="T extends { id: string }">import { TouchSynchronizer, createWheelAdapter } from '../utils';
|
|
3
2
|
import { onDestroy, onMount, untrack } from 'svelte';
|
|
4
3
|
let { buffer, on, children } = $props();
|
|
5
4
|
let slidesRef;
|
|
@@ -142,11 +141,10 @@ const wheelCallbacks = {
|
|
|
142
141
|
canLoadNext: () => buffer.canLoadNext,
|
|
143
142
|
canLoadPrevious: () => buffer.canLoadPrevious,
|
|
144
143
|
onTrigger: (direction) => {
|
|
145
|
-
|
|
146
|
-
if (direction > 0) {
|
|
144
|
+
if (direction === 'next') {
|
|
147
145
|
buffer.loadNext();
|
|
148
146
|
}
|
|
149
|
-
else
|
|
147
|
+
else {
|
|
150
148
|
buffer.loadPrevious();
|
|
151
149
|
}
|
|
152
150
|
},
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
export type WheelAdapterAxis = 'x' | 'y';
|
|
2
|
+
export type WheelAdapterDirection = 'next' | 'previous';
|
|
1
3
|
export type WheelAdapterCallbacks = {
|
|
2
4
|
canLoadNext: () => boolean;
|
|
3
5
|
canLoadPrevious: () => boolean;
|
|
4
|
-
onTrigger: (direction:
|
|
6
|
+
onTrigger: (direction: WheelAdapterDirection) => void;
|
|
5
7
|
getAnimationDurationMs: () => number;
|
|
6
8
|
};
|
|
7
9
|
/**
|
|
8
10
|
* Minimal, robust wheel adapter:
|
|
9
|
-
* -
|
|
11
|
+
* - Configurable axis: 'y' reads Y only; 'x' prefers X but remaps Y when X is negligible
|
|
12
|
+
* - EMA over velocity to smooth noisy streams (esp. on Windows)
|
|
10
13
|
* - Cooldown blocks triggers while animation runs
|
|
11
14
|
* - Mouse fallback: if velocity is near zero but delta is large, treat as a discrete "kick"
|
|
12
15
|
*/
|
|
13
16
|
export declare const createWheelAdapter: (target: HTMLElement, params: {
|
|
17
|
+
axis?: WheelAdapterAxis;
|
|
14
18
|
cbs: WheelAdapterCallbacks;
|
|
15
19
|
}) => {
|
|
16
20
|
destroy(): void;
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import { WheelGestures } from 'wheel-gestures';
|
|
3
3
|
/**
|
|
4
4
|
* Minimal, robust wheel adapter:
|
|
5
|
-
* -
|
|
5
|
+
* - Configurable axis: 'y' reads Y only; 'x' prefers X but remaps Y when X is negligible
|
|
6
|
+
* - EMA over velocity to smooth noisy streams (esp. on Windows)
|
|
6
7
|
* - Cooldown blocks triggers while animation runs
|
|
7
8
|
* - Mouse fallback: if velocity is near zero but delta is large, treat as a discrete "kick"
|
|
8
9
|
*/
|
|
9
10
|
export const createWheelAdapter = (target, params) => {
|
|
10
|
-
const { cbs } = params;
|
|
11
|
+
const { axis = 'y', cbs } = params;
|
|
11
12
|
// Tunables
|
|
12
13
|
const PEAK_THRESHOLD = 0.4; // EMA magnitude threshold to consider as a "peak"
|
|
13
14
|
const ACCEL_THRESHOLD = 0.02; // minimal directional EMA rise to count as real acceleration
|
|
@@ -30,41 +31,49 @@ export const createWheelAdapter = (target, params) => {
|
|
|
30
31
|
}, cbs.getAnimationDurationMs() + 100);
|
|
31
32
|
};
|
|
32
33
|
const fire = (direction) => {
|
|
33
|
-
|
|
34
|
-
if ((direction > 0 && !cbs.canLoadNext()) || (direction < 0 && !cbs.canLoadPrevious())) {
|
|
34
|
+
if ((direction === 'next' && !cbs.canLoadNext()) || (direction === 'previous' && !cbs.canLoadPrevious())) {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
isAnimating = true;
|
|
38
38
|
cbs.onTrigger(direction);
|
|
39
39
|
startCooldown();
|
|
40
40
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const getAxisValues = (axisDelta, axisVelocity) => {
|
|
42
|
+
if (axis === 'y') {
|
|
43
|
+
return [axisDelta[1], axisVelocity[1]];
|
|
44
|
+
}
|
|
45
|
+
// axis === 'x': prefer X, fall back to Y (remap vertical scroll to horizontal)
|
|
46
|
+
if (Math.abs(axisDelta[0]) >= Math.abs(axisDelta[1])) {
|
|
47
|
+
return [axisDelta[0], axisVelocity[0]];
|
|
48
|
+
}
|
|
49
|
+
return [axisDelta[1], axisVelocity[1]];
|
|
50
|
+
};
|
|
51
|
+
wheelGestures.on('wheel', ({ axisDelta, axisVelocity }) => {
|
|
52
|
+
const [delta, velocity] = getAxisValues(axisDelta, axisVelocity);
|
|
44
53
|
// Tracking only: always update EMA and compute signs/acceleration
|
|
45
54
|
previousEmaVelocity = emaVelocity;
|
|
46
|
-
emaVelocity += (
|
|
55
|
+
emaVelocity += (velocity - emaVelocity) * EMA_ALPHA;
|
|
47
56
|
const emaMagnitude = Math.abs(emaVelocity);
|
|
48
|
-
const velocitySign = Math.sign(emaVelocity) || Math.sign(
|
|
57
|
+
const velocitySign = Math.sign(emaVelocity) || Math.sign(velocity);
|
|
49
58
|
const emaAcceleration = emaVelocity - previousEmaVelocity;
|
|
50
59
|
// During animation we only track; no arming, no triggering
|
|
51
60
|
if (isAnimating) {
|
|
52
61
|
return;
|
|
53
62
|
}
|
|
54
63
|
// Path 1: mouse-like discrete kick (platform-agnostic via delta/velocity ratio)
|
|
55
|
-
const absDelta = Math.abs(
|
|
56
|
-
const absVel = Math.abs(
|
|
64
|
+
const absDelta = Math.abs(delta);
|
|
65
|
+
const absVel = Math.abs(velocity);
|
|
57
66
|
const stepRatio = absDelta / Math.max(1e-6, absVel);
|
|
58
67
|
const isMouseLikeKick = absDelta >= MOUSE_DELTA_KICK && stepRatio >= MOUSE_STEP_RATIO_KICK;
|
|
59
68
|
if (isMouseLikeKick) {
|
|
60
|
-
const direction =
|
|
69
|
+
const direction = delta > 0 ? 'next' : 'previous';
|
|
61
70
|
fire(direction);
|
|
62
71
|
return;
|
|
63
72
|
}
|
|
64
73
|
// Path 2: trackpad/inertia via EMA acceleration and peak gating
|
|
65
74
|
const isAcceleratingInDirection = velocitySign !== 0 && emaAcceleration * velocitySign > ACCEL_THRESHOLD;
|
|
66
75
|
if (isAcceleratingInDirection && emaMagnitude > PEAK_THRESHOLD) {
|
|
67
|
-
const direction = velocitySign > 0 ?
|
|
76
|
+
const direction = velocitySign > 0 ? 'next' : 'previous';
|
|
68
77
|
fire(direction);
|
|
69
78
|
}
|
|
70
79
|
});
|