@streamscloud/kit 0.1.12-1772041668184 → 0.2.0-1772457727942

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,5 +1,5 @@
1
1
  import { sineInOut } from 'svelte/easing';
2
- export const slideHorizontally = (node, { delay = 0, duration = 400, easing = sineInOut } = {}) => {
2
+ export const slideHorizontally = (node, { delay = 0, duration = 250, easing = sineInOut } = {}) => {
3
3
  const style = getComputedStyle(node);
4
4
  const isHtmlElement = (n) => n.nodeType === Node.ELEMENT_NODE;
5
5
  const children = Array.from(node.children).filter(isHtmlElement);
@@ -70,14 +70,15 @@
70
70
  max-height: 100%;
71
71
  }
72
72
 
73
- @mixin scrollbar($thumb-color: var(--scrollbar--thumb-color, #7d7d7d), $track-color: var(--scrollbar--track-color, transparent)) {
73
+
74
+ @mixin scrollbar($thumb-color: var(--scrollbar--thumb-color, light-dark(#999999, #333333)), $track-color: var(--scrollbar--track-color, transparent)) {
74
75
  --_cross-browser-scrollbar--thumb-color: #{$thumb-color};
75
76
  --_cross-browser-scrollbar--track-color: #{$track-color};
76
77
 
77
78
  @include _cross-browser-scrollbar;
78
79
  }
79
80
 
80
- @mixin scrollbar-on-hover($thumb-color: var(--scrollbar--thumb-color, #7d7d7d), $track-color: var(--scrollbar--track-color, transparent)) {
81
+ @mixin scrollbar-on-hover($thumb-color: var(--scrollbar--thumb-color, light-dark(#999999, #333333)), $track-color: var(--scrollbar--track-color, transparent)) {
81
82
  --_cross-browser-scrollbar--thumb-color: transparent;
82
83
  --_cross-browser-scrollbar--track-color: transparent;
83
84
 
@@ -0,0 +1,24 @@
1
+ @use 'sass:list';
2
+
3
+ $transition-duration-fast: 150ms;
4
+ $transition-duration-base: 250ms;
5
+ $transition-duration-slow: 350ms;
6
+
7
+ $transition-easing-default: cubic-bezier(0.4, 0, 0.2, 1);
8
+ $transition-easing-in: cubic-bezier(0.4, 0, 1, 1);
9
+ $transition-easing-out: cubic-bezier(0, 0, 0.2, 1);
10
+
11
+ // Transition mixin
12
+ // Usage:
13
+ // @include transition(opacity);
14
+ // @include transition(background-color color, $transition-duration-fast);
15
+ // @include transition(width, $transition-duration-slow, linear);
16
+ @mixin transition($properties: all, $duration: $transition-duration-base, $easing: $transition-easing-default) {
17
+ $result: ();
18
+
19
+ @each $property in $properties {
20
+ $result: list.append($result, $property $duration $easing, comma);
21
+ }
22
+
23
+ transition: $result;
24
+ }
@@ -121,7 +121,7 @@ input[type=number] {
121
121
  textarea {
122
122
  vertical-align: top;
123
123
  resize: vertical;
124
- --_cross-browser-scrollbar--thumb-color: var(--scrollbar--thumb-color, #7d7d7d);
124
+ --_cross-browser-scrollbar--thumb-color: var(--scrollbar--thumb-color, light-dark(#999999, #333333));
125
125
  --_cross-browser-scrollbar--track-color: var(--scrollbar--track-color, transparent);
126
126
  }
127
127
  textarea::-webkit-scrollbar {
@@ -53,7 +53,7 @@ export {};
53
53
  justify-content: var(--_button--justify-content);
54
54
  align-items: center;
55
55
  vertical-align: middle;
56
- transition: background-color linear 0.2s, color linear 0.2s, border-color linear 0.2s, filter linear 0.2s;
56
+ transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1), color 250ms cubic-bezier(0.4, 0, 0.2, 1), border-color 250ms cubic-bezier(0.4, 0, 0.2, 1), filter 250ms cubic-bezier(0.4, 0, 0.2, 1);
57
57
  white-space: nowrap;
58
58
  cursor: pointer;
59
59
  }
@@ -104,7 +104,7 @@ A structured dialog panel with header (title + close button), scrollable body, a
104
104
  min-height: 0;
105
105
  overflow-y: auto;
106
106
  padding: var(--_dialog--body--padding-block) var(--_dialog--body--padding-inline);
107
- --_cross-browser-scrollbar--thumb-color: var(--scrollbar--thumb-color, #7d7d7d);
107
+ --_cross-browser-scrollbar--thumb-color: var(--scrollbar--thumb-color, light-dark(#999999, #333333));
108
108
  --_cross-browser-scrollbar--track-color: var(--scrollbar--track-color, transparent);
109
109
  }
110
110
  .dialog__body::-webkit-scrollbar {
@@ -26,4 +26,8 @@ export type DialogInit<TData = void, TResult = void, TCancelResult = void> = {
26
26
  /** Mount target for the dialog element. Useful for shadow DOM isolation. Defaults to `document.body`. */
27
27
  host?: ParentNode;
28
28
  };
29
+ /** Adds an optional `dialogHost` field to any dialog data type. Helper functions strip it and pass to `Dialogs.open({ host })`. */
30
+ export type DialogHostable<T> = T & {
31
+ dialogHost?: ParentNode;
32
+ };
29
33
  export {};
@@ -1,5 +1,6 @@
1
1
  export { Dialogs } from './dialogs.svelte';
2
2
  export { DialogController } from './dialog-controller';
3
+ export { type DialogHostable } from './dialog-data';
3
4
  export { DIALOG_SIZES, type DialogPosition, type DialogResult, type DialogSize } from './types.svelte';
4
5
  export { default as Dialog } from './cmp.dialog.svelte';
5
6
  export { default as DialogButton } from './cmp.dialog-button.svelte';
@@ -1,5 +1,6 @@
1
1
  export { Dialogs } from './dialogs.svelte';
2
2
  export { DialogController } from './dialog-controller';
3
+ export {} from './dialog-data';
3
4
  export { DIALOG_SIZES } from './types.svelte';
4
5
  export { default as Dialog } from './cmp.dialog.svelte';
5
6
  export { default as DialogButton } from './cmp.dialog-button.svelte';
@@ -135,8 +135,10 @@ const initPopper = (node) => {
135
135
  {/if}
136
136
  </button>
137
137
  {#if opened}
138
- <div use:initPopper class="dropdown__content" role="tooltip" tabindex="-1">
139
- {@render children()}
138
+ <div use:initPopper class="dropdown__popper" role="tooltip" tabindex="-1">
139
+ <div class="dropdown__content">
140
+ {@render children()}
141
+ </div>
140
142
  </div>
141
143
  {/if}
142
144
  </div>
@@ -179,10 +181,25 @@ A Popper.js-powered dropdown that positions content relative to a trigger elemen
179
181
  opacity: 0.5;
180
182
  pointer-events: none;
181
183
  }
184
+ .dropdown__popper {
185
+ z-index: 999;
186
+ }
182
187
  .dropdown__content {
183
188
  width: max-content;
184
- z-index: 999;
189
+ transform-origin: top left;
190
+ animation: dropdown-appear 150ms cubic-bezier(0, 0, 0.2, 1) both;
185
191
  }
186
192
  .dropdown :global([data-popper-escaped]) {
187
193
  visibility: hidden !important;
194
+ }
195
+
196
+ @keyframes dropdown-appear {
197
+ from {
198
+ opacity: 0;
199
+ transform: scale(0.95) translateY(-4px);
200
+ }
201
+ to {
202
+ opacity: 1;
203
+ transform: scale(1) translateY(0);
204
+ }
188
205
  }</style>
@@ -8,7 +8,7 @@ export {};
8
8
 
9
9
  <style>.html-block {
10
10
  display: contents;
11
- word-break: break-word;
11
+ overflow-wrap: break-word;
12
12
  font-size: 0.875em;
13
13
  line-height: 1.4;
14
14
  font-weight: normal;
@@ -1,4 +1,4 @@
1
- import { type DialogResult } from '../dialog';
1
+ import { type DialogHostable, type DialogResult } from '../dialog';
2
2
  import type { MediaViewerData } from './types';
3
3
  /**
4
4
  * Opens a full-screen media viewer dialog for images and videos.
@@ -9,6 +9,7 @@ import type { MediaViewerData } from './types';
9
9
  * - `index` — zero-based index of the initially visible item
10
10
  * - `backgroundOpacity` — backdrop opacity (default `0.6`)
11
11
  * - `carouselMode` — carousel navigation mode (default `'arrows-with-counts'`)
12
+ * - `dialogHost` — mount target for the dialog element (default `document.body`)
12
13
  */
13
- export declare const openMediaViewer: (data: MediaViewerData) => Promise<DialogResult<void>>;
14
+ export declare const openMediaViewer: (data: DialogHostable<MediaViewerData>) => Promise<DialogResult<void>>;
14
15
  export type { MediaViewerData, MediaViewerItem, MediaViewerItemType } from './types';
@@ -9,10 +9,13 @@ import { default as MediaViewerDialog } from './cmp.media-viewer-dialog.svelte';
9
9
  * - `index` — zero-based index of the initially visible item
10
10
  * - `backgroundOpacity` — backdrop opacity (default `0.6`)
11
11
  * - `carouselMode` — carousel navigation mode (default `'arrows-with-counts'`)
12
+ * - `dialogHost` — mount target for the dialog element (default `document.body`)
12
13
  */
13
14
  export const openMediaViewer = (data) => {
15
+ const { dialogHost, ...rest } = data;
14
16
  return Dialogs.open({
15
17
  view: MediaViewerDialog,
16
- data
18
+ data: rest,
19
+ host: dialogHost
17
20
  });
18
21
  };
@@ -4,7 +4,7 @@ const { item } = $props();
4
4
  let containerWidth = $state(0);
5
5
  let containerHeight = $state(0);
6
6
  const fittedSize = $derived.by(() => {
7
- if (containerWidth === 0 || containerHeight === 0) {
7
+ if (containerWidth === 0 || containerHeight === 0 || item.width === 0 || item.height === 0) {
8
8
  return { width: 0, height: 0 };
9
9
  }
10
10
  const aspectRatio = item.width / item.height;
@@ -176,7 +176,6 @@ const onKeyPress = Utils.throttle((e) => {
176
176
  const notifyIndexChanged = () => {
177
177
  on?.indexChanged?.(selectedIndex);
178
178
  };
179
- notifyIndexChanged();
180
179
  const setIndex = (index) => {
181
180
  if (index < 0) {
182
181
  animationIndex = 0;
@@ -195,10 +194,10 @@ const setIndex = (index) => {
195
194
  }, 600);
196
195
  };
197
196
  const loadPrevious = Utils.throttle(() => {
198
- setIndex(--selectedIndex);
197
+ setIndex(selectedIndex - 1);
199
198
  }, animationDuration);
200
199
  const loadNext = Utils.throttle(() => {
201
- setIndex(++selectedIndex);
200
+ setIndex(selectedIndex + 1);
202
201
  }, animationDuration);
203
202
  $effect(() => {
204
203
  if (previousItems && items !== previousItems) {
@@ -158,7 +158,7 @@ A draggable media seek bar with a track, filled portion, and scrubber handle. Su
158
158
  transform: translate(-50%, -50%);
159
159
  z-index: 1;
160
160
  opacity: var(--_seek-bar--scrubber-opacity);
161
- transition: opacity 0.2s ease-in-out;
161
+ transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
162
162
  }
163
163
  .seek-bar__scrubber.is-dragging, .seek-bar__scrubber:focus {
164
164
  --_seek-bar--scrubber-opacity: 1;
@@ -58,6 +58,7 @@ $effect(() => untrack(() => {
58
58
  PlaybackManager.unregisterPlayer(id);
59
59
  };
60
60
  }));
61
+ let latestEntry = null;
61
62
  // Intersection observer for lazy loading and autoplay-on-appearance
62
63
  $effect(() => {
63
64
  if (!videoContainerRef) {
@@ -70,12 +71,13 @@ $effect(() => {
70
71
  return;
71
72
  }
72
73
  const [entry] = entries;
74
+ latestEntry = entry;
73
75
  if ((entry.isIntersecting || allowPreloading) && !video.src) {
74
76
  video.src = src;
75
77
  video.load();
76
78
  if (autoplayState === true) {
77
79
  const handleCanPlay = () => {
78
- if (entry.isIntersecting) {
80
+ if (latestEntry?.isIntersecting) {
79
81
  void play();
80
82
  autoplayState = false;
81
83
  }
@@ -96,7 +98,7 @@ $effect(() => {
96
98
  }
97
99
  if (entry.intersectionRatio >= 0.6) {
98
100
  const handleCanPlay = () => {
99
- if (entry.intersectionRatio >= 0.6) {
101
+ if (latestEntry && latestEntry.intersectionRatio >= 0.6) {
100
102
  void play();
101
103
  }
102
104
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.1.12-1772041668184",
3
+ "version": "0.2.0-1772457727942",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",
@@ -216,6 +216,9 @@
216
216
  },
217
217
  "./styles/theme": {
218
218
  "sass": "./dist/styles/_theme.scss"
219
+ },
220
+ "./styles/transitions": {
221
+ "sass": "./dist/styles/_transitions.scss"
219
222
  }
220
223
  },
221
224
  "dependencies": {