@streamscloud/embeddable 13.2.0 → 13.3.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.
@@ -111,8 +111,9 @@ const onJoinMembershipClick = () => __awaiter(void 0, void 0, void 0, function*
111
111
  display: flex;
112
112
  flex-wrap: nowrap;
113
113
  margin-top: 0.25rem;
114
- gap: 8.125rem;
115
114
  align-items: center;
115
+ max-width: 19.6875rem;
116
+ justify-content: space-between;
116
117
  /* Set 'container-type: inline-size;' to reference container*/
117
118
  }
118
119
  @container (width < 576px) {
@@ -139,6 +139,7 @@ let { context } = $props();
139
139
  max-width: 4rem;
140
140
  }
141
141
  .header-mobile__texts {
142
+ flex: 1;
142
143
  display: flex;
143
144
  flex-direction: column;
144
145
  gap: 0.25rem;
@@ -77,6 +77,7 @@ const localization = $derived(new DiscoverViewLocalization(context.locale));
77
77
  flex: 1;
78
78
  scrollbar-gutter: stable both-edges;
79
79
  padding-inline: 1.875rem;
80
+ overflow-x: hidden;
80
81
  overflow-y: auto;
81
82
  --_cross-browser-scrollbar--thumb-color: transparent;
82
83
  --_cross-browser-scrollbar--track-color: transparent;
@@ -168,6 +168,7 @@ const variables = $derived.by(() => {
168
168
  overflow-x: auto;
169
169
  padding-inline: var(--_post-viewer--attachments-horizontal--padding-inline);
170
170
  scrollbar-width: none;
171
+ overscroll-behavior: none;
171
172
  }
172
173
  .attachments-horizontal__item {
173
174
  position: relative;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">import { Image } from '../../../ui/image';
2
- import { Slider } from '../../../ui/slider';
2
+ import { SliderHorizontal } from '../../../ui/player/slider-horizontal';
3
3
  import { Video } from '../../../ui/video';
4
4
  let { id, media, locale, autoplay = 'on-appearance', on } = $props();
5
5
  </script>
@@ -26,11 +26,11 @@ let { id, media, locale, autoplay = 'on-appearance', on } = $props();
26
26
  {#if media.items.length === 1}
27
27
  {@render mediaItem(media.items[0])}
28
28
  {:else if media.items.length > 1}
29
- <Slider items={media.items} initialIndex={media.currentIndex} locale={locale} on={{ indexChanged: (index) => (media.currentIndex = index) }}>
29
+ <SliderHorizontal items={media.items} initialIndex={media.currentIndex} locale={locale} on={{ indexChanged: (index) => (media.currentIndex = index) }}>
30
30
  {#snippet children(item)}
31
31
  {@render mediaItem(item)}
32
32
  {/snippet}
33
- </Slider>
33
+ </SliderHorizontal>
34
34
  {/if}
35
35
  </div>
36
36
 
@@ -1,4 +1,5 @@
1
- <script lang="ts">import { createWheelAdapter } from './wheel-gestures-adapter';
1
+ <script lang="ts">import { TouchSynchronizer } from '../utils';
2
+ import { createWheelAdapter } from './wheel-gestures-adapter';
2
3
  import { onDestroy, onMount, untrack } from 'svelte';
3
4
  let { buffer, on, children } = $props();
4
5
  let slidesRef;
@@ -43,21 +44,27 @@ onMount(() => {
43
44
  let touchStartY = 0;
44
45
  let touchMoveY = 0;
45
46
  let touchStartTime = 0;
46
- let isVerticalSwipe = false;
47
+ let swipeState = 'not-initialized';
47
48
  window.addEventListener(`keydown`, onKeyPress);
48
49
  slidesRef.addEventListener('touchstart', (e) => {
50
+ TouchSynchronizer.touchStarted(slidesRef);
49
51
  // The movement gets all janky if there's a transition on the elements.
50
52
  slidesRef.classList.toggle('animate', false);
51
53
  touchStartX = e.changedTouches[0].screenX;
52
54
  touchStartY = e.changedTouches[0].screenY;
53
55
  touchStartTime = Date.now();
54
- isVerticalSwipe = false;
56
+ swipeState = 'not-initialized';
55
57
  }, { passive: true });
56
58
  slidesRef.addEventListener('touchmove', (e) => {
57
- if (isVerticalSwipe) {
59
+ if (swipeState === 'vertical') {
58
60
  // Already determined this is a vertical swipe
59
61
  e.preventDefault();
60
62
  e.stopPropagation();
63
+ TouchSynchronizer.touchMovePropagationBlocked(slidesRef);
64
+ }
65
+ else if (swipeState === 'horizontal') {
66
+ // Already determined this is a horizontal swipe
67
+ return;
61
68
  }
62
69
  const touchCurrentX = e.changedTouches[0].screenX;
63
70
  const touchCurrentY = e.changedTouches[0].screenY;
@@ -67,9 +74,10 @@ onMount(() => {
67
74
  if (diffX > 10 || diffY > 10) {
68
75
  if (diffY > diffX) {
69
76
  // Vertical swipe - handle it
70
- isVerticalSwipe = true;
77
+ swipeState = 'vertical';
71
78
  e.preventDefault();
72
79
  e.stopPropagation();
80
+ TouchSynchronizer.touchMovePropagationBlocked(slidesRef);
73
81
  const newPosition = touchCurrentY;
74
82
  const diff = newPosition - touchStartY;
75
83
  if ((diff > 0 && buffer.canLoadPrevious) || (diff < 0 && buffer.canLoadNext)) {
@@ -79,28 +87,27 @@ onMount(() => {
79
87
  }
80
88
  else {
81
89
  // Horizontal swipe - allow child to handle
82
- isVerticalSwipe = false;
90
+ swipeState = 'horizontal';
83
91
  return;
84
92
  }
85
93
  }
86
94
  }, { passive: false });
87
95
  slidesRef.addEventListener('touchend', (e) => {
88
- const touchEndX = e.changedTouches[0].screenX;
89
- const touchEndY = e.changedTouches[0].screenY;
90
- const diffX = Math.abs(touchEndX - touchStartX);
91
- const diffY = Math.abs(touchEndY - touchStartY);
96
+ const reset = () => {
97
+ swipeTransition = 0;
98
+ touchMoveY = 0;
99
+ };
92
100
  // Check if this is a vertical swipe
93
- if (diffX > diffY) {
101
+ if (swipeState !== 'vertical') {
94
102
  // Horizontal swipe - don't handle and don't block
103
+ reset();
95
104
  return;
96
105
  }
97
106
  // This is a vertical swipe - block propagation
98
107
  e.stopPropagation();
108
+ TouchSynchronizer.touchEndPropatationBlocked(slidesRef);
109
+ TouchSynchronizer.touchEnded(slidesRef);
99
110
  slidesRef.classList.toggle('animate', true);
100
- const reset = () => {
101
- swipeTransition = 0;
102
- touchMoveY = 0;
103
- };
104
111
  const isFastSwipe = Date.now() - touchStartTime < 300;
105
112
  if (!touchMoveY || (!isFastSwipe && Math.abs(touchMoveY) < sliderHeight / 6)) {
106
113
  return reset();
@@ -1,7 +1,8 @@
1
- <script lang="ts">import { runningInBrowser } from '../../core/browser';
2
- import { Utils } from '../../core/utils';
3
- import { HtmlHelper } from '../../core/utils/html-helper';
4
- import { Icon } from '../icon';
1
+ <script lang="ts">import { runningInBrowser } from '../../../core/browser';
2
+ import { Utils } from '../../../core/utils';
3
+ import { HtmlHelper } from '../../../core/utils/html-helper';
4
+ import { Icon } from '../../icon';
5
+ import { TouchSynchronizer } from '../utils';
5
6
  import { SliderLocalization } from './slider-localization';
6
7
  import { SliderMode } from './types';
7
8
  import IconChevronLeft from '@fluentui/svg-icons/icons/chevron_left_20_regular.svg?raw';
@@ -13,13 +14,14 @@ let { items, sliderMode = SliderMode.ArrowsWithCounts, dotsConfig = {
13
14
  }, locale, initialIndex, autoSlideMs = 0, on, children } = $props();
14
15
  const localization = $derived.by(() => new SliderLocalization(locale));
15
16
  const itemIndices = $derived(items.map((_, index) => index));
16
- const animationDuration = 850;
17
+ const animationDuration = 300;
17
18
  let previousItems = $state.raw(undefined);
18
19
  let selectedIndex = $state(initialIndex);
19
20
  let animationIndex = $state(null);
20
21
  let interval;
21
22
  let slidesRef;
22
23
  let sliderWidth = $state(0);
24
+ let swipeTransition = $state(0);
23
25
  let resizeObserver;
24
26
  onMount(() => {
25
27
  notifyIndexChanged();
@@ -28,19 +30,26 @@ onMount(() => {
28
30
  });
29
31
  let touchStartX = 0;
30
32
  let touchStartY = 0;
33
+ let touchMoveX = 0;
31
34
  let touchStartTime = 0;
32
- let isHorizontalSwipe = false;
35
+ let swipeState = 'not-initialized';
33
36
  slidesRef.addEventListener('touchstart', (e) => {
37
+ TouchSynchronizer.touchStarted(slidesRef);
38
+ slidesRef.classList.toggle('animate', false);
34
39
  touchStartX = e.changedTouches[0].screenX;
35
40
  touchStartY = e.changedTouches[0].screenY;
36
41
  touchStartTime = Date.now();
37
- isHorizontalSwipe = false;
42
+ swipeState = 'not-initialized';
38
43
  }, { passive: true });
39
44
  slidesRef.addEventListener('touchmove', (e) => {
40
- if (isHorizontalSwipe) {
45
+ if (swipeState === 'horizontal') {
41
46
  // Already determined this is a horizontal swipe
42
47
  e.preventDefault();
43
48
  e.stopPropagation();
49
+ TouchSynchronizer.touchMovePropagationBlocked(slidesRef);
50
+ }
51
+ else if (swipeState === 'vertical') {
52
+ // Already determined this is a vertical swipe
44
53
  return;
45
54
  }
46
55
  const touchCurrentX = e.changedTouches[0].screenX;
@@ -51,39 +60,49 @@ onMount(() => {
51
60
  if (diffX > 10 || diffY > 10) {
52
61
  if (diffX > diffY) {
53
62
  // Horizontal swipe - block vertical scroll
54
- isHorizontalSwipe = true;
63
+ swipeState = 'horizontal';
55
64
  e.preventDefault();
56
65
  e.stopPropagation();
66
+ TouchSynchronizer.touchMovePropagationBlocked(slidesRef);
67
+ touchMoveX = touchCurrentX - touchStartX;
68
+ const basePosition = -sliderWidth * (animationIndex === null ? selectedIndex + 1 : animationIndex);
69
+ swipeTransition = basePosition + touchMoveX;
57
70
  }
58
71
  else {
59
72
  // Vertical swipe - allow parent to handle
60
- isHorizontalSwipe = false;
73
+ swipeState = 'vertical';
61
74
  }
62
75
  }
63
- });
76
+ }, { passive: false });
64
77
  slidesRef.addEventListener('touchend', (e) => {
65
- const touchEndX = e.changedTouches[0].screenX;
66
- const touchEndY = e.changedTouches[0].screenY;
67
- const diffX = Math.abs(touchEndX - touchStartX);
68
- const diffY = Math.abs(touchEndY - touchStartY);
78
+ const reset = () => {
79
+ swipeTransition = 0;
80
+ touchMoveX = 0;
81
+ };
69
82
  // Check if this is a horizontal swipe
70
- if (diffY > diffX) {
83
+ if (swipeState !== 'horizontal') {
84
+ reset();
71
85
  return;
72
86
  }
73
87
  // This is a horizontal swipe - block propagation
74
88
  e.stopPropagation();
75
89
  e.preventDefault();
90
+ slidesRef.classList.toggle('animate', true);
91
+ TouchSynchronizer.touchEndPropatationBlocked(slidesRef);
92
+ TouchSynchronizer.touchEnded(slidesRef);
76
93
  const isFastSwipe = Date.now() - touchStartTime < 300;
77
- if (!isFastSwipe && diffX < sliderWidth / 6) {
94
+ if (!isFastSwipe && Math.abs(touchMoveX) < sliderWidth / 6) {
95
+ reset();
78
96
  return;
79
97
  }
80
- if (touchEndX < touchStartX) {
98
+ if (touchMoveX < 0) {
81
99
  loadNext();
82
100
  }
83
- if (touchEndX > touchStartX) {
101
+ else {
84
102
  loadPrevious();
85
103
  }
86
- });
104
+ reset();
105
+ }, { passive: false });
87
106
  slidesRef.addEventListener('transitionend', (e) => {
88
107
  e.stopPropagation();
89
108
  if (animationIndex !== null && animationIndex > items.length - 1) {
@@ -166,16 +185,23 @@ const setIndex = (index) => {
166
185
  };
167
186
  const loadPrevious = Utils.throttle(() => {
168
187
  setIndex(--selectedIndex);
169
- }, 800);
188
+ }, animationDuration);
170
189
  const loadNext = Utils.throttle(() => {
171
190
  setIndex(++selectedIndex);
172
- }, 800);
191
+ }, animationDuration);
173
192
  $effect(() => {
174
193
  if (previousItems && items !== previousItems) {
175
194
  setIndex(0);
176
195
  }
177
196
  previousItems = items;
178
197
  });
198
+ const styles = $derived.by(() => {
199
+ const values = [
200
+ `transform: translateX(${swipeTransition || (items.length > 1 ? -sliderWidth * (animationIndex === null ? selectedIndex + 1 : animationIndex) : 0)}px)`,
201
+ `--_slider-horizontal--animation: ${animationDuration}ms ease-out transform`
202
+ ];
203
+ return values.join(';');
204
+ });
179
205
  const showClassicArrowsAndDots = $derived([SliderMode.ArrowsAndDots, SliderMode.ArrowsOnly, SliderMode.DotsOnly, SliderMode.DotsOnlyBelow].includes(sliderMode));
180
206
  </script>
181
207
 
@@ -186,12 +212,9 @@ const showClassicArrowsAndDots = $derived([SliderMode.ArrowsAndDots, SliderMode.
186
212
  class:slider--dots-only={sliderMode === SliderMode.DotsOnly}
187
213
  class:slider--dots-only-below={sliderMode === SliderMode.DotsOnlyBelow}
188
214
  class:slider--arrows-with-counts={sliderMode === SliderMode.ArrowsWithCounts}>
189
- <div
190
- class="slider__slides"
191
- bind:this={slidesRef}
192
- style={`transform: translateX(${items.length > 1 ? -sliderWidth * (animationIndex === null ? selectedIndex + 1 : animationIndex) : 0}px)`}>
215
+ <div class="slider__slides" bind:this={slidesRef} style={styles}>
193
216
  {#if items.length > 1}
194
- <div class="slider__slide" data-before>
217
+ <div class="slider__slide">
195
218
  {#if children}
196
219
  {@render children(items[items.length - 1])}
197
220
  {/if}
@@ -268,7 +291,7 @@ const showClassicArrowsAndDots = $derived([SliderMode.ArrowsAndDots, SliderMode.
268
291
  height: 100%;
269
292
  }
270
293
  .slider__slides:global(.animate) {
271
- transition: 800ms ease-out transform;
294
+ transition: var(--_slider-horizontal--animation);
272
295
  }
273
296
  .slider__slide {
274
297
  display: flex;
@@ -1,4 +1,4 @@
1
- import type { Locale } from '../../core/locale';
1
+ import type { Locale } from '../../../core/locale';
2
2
  import { type SliderDotsConfig, SliderMode } from './types';
3
3
  import { type Snippet } from 'svelte';
4
4
  declare class __sveltets_Render<T> {
@@ -0,0 +1,2 @@
1
+ export { default as SliderHorizontal } from './cmp.slider.svelte';
2
+ export { SliderMode, type SliderDotsConfig } from './types';
@@ -0,0 +1,2 @@
1
+ export { default as SliderHorizontal } from './cmp.slider.svelte';
2
+ export { SliderMode } from './types';
@@ -1,4 +1,4 @@
1
- import { type Locale } from '../../core/locale';
1
+ import { type Locale } from '../../../core/locale';
2
2
  export declare class SliderLocalization {
3
3
  nOfM: (n: number, m: number) => string;
4
4
  constructor(locale: Locale);
@@ -1,4 +1,4 @@
1
- import {} from '../../core/locale';
1
+ import {} from '../../../core/locale';
2
2
  export class SliderLocalization {
3
3
  nOfM;
4
4
  constructor(locale) {
@@ -0,0 +1 @@
1
+ export { TouchSynchronizer } from './touch-synchronizer';
@@ -0,0 +1 @@
1
+ export { TouchSynchronizer } from './touch-synchronizer';
@@ -0,0 +1,7 @@
1
+ export declare class TouchSynchronizer {
2
+ private static listeners;
3
+ static touchStarted: (ref: HTMLElement) => void;
4
+ static touchMovePropagationBlocked: (ref: HTMLElement) => void;
5
+ static touchEndPropatationBlocked: (ref: HTMLElement) => void;
6
+ static touchEnded: (ref: HTMLElement) => void;
7
+ }
@@ -0,0 +1,21 @@
1
+ export class TouchSynchronizer {
2
+ static listeners = [];
3
+ static touchStarted = (ref) => {
4
+ TouchSynchronizer.listeners.push(ref);
5
+ };
6
+ static touchMovePropagationBlocked = (ref) => {
7
+ const otherListeners = TouchSynchronizer.listeners.filter((r) => r !== ref);
8
+ otherListeners.forEach((r) => {
9
+ r.dispatchEvent(new TouchEvent('touchend', { cancelable: false }));
10
+ });
11
+ };
12
+ static touchEndPropatationBlocked = (ref) => {
13
+ const otherListeners = TouchSynchronizer.listeners.filter((r) => r !== ref);
14
+ otherListeners.forEach((r) => {
15
+ r.dispatchEvent(new TouchEvent('touchend', { cancelable: false }));
16
+ });
17
+ };
18
+ static touchEnded = (ref) => {
19
+ TouchSynchronizer.listeners = TouchSynchronizer.listeners.filter((r) => r !== ref);
20
+ };
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/embeddable",
3
- "version": "13.2.0",
3
+ "version": "13.3.0",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,2 +0,0 @@
1
- export { default as Slider } from './cmp.slider.svelte';
2
- export { SliderMode, type SliderDotsConfig } from './types';
@@ -1,2 +0,0 @@
1
- export { default as Slider } from './cmp.slider.svelte';
2
- export { SliderMode } from './types';