@streamscloud/kit 0.40.1 → 0.40.2

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.
@@ -71,6 +71,7 @@ sticky panel headers.
71
71
  | `--sc-kit--page-layout--color` | Page text color | `--sc-kit--color--text--primary` |
72
72
  | `--sc-kit--page-layout--border-color` | Header divider color | `--sc-kit--color--border` |
73
73
  | `--sc-kit--page-layout--title--font-size` | Title font size | `18px` |
74
+ | `--sc-kit--page-layout--header--padding-inline` | Header inline padding | `24px` |
74
75
  -->
75
76
  <style>.page-layout {
76
77
  --_page-layout--background: var(--sc-kit--page-layout--background, var(--sc-kit--color--bg--panel));
@@ -78,6 +79,7 @@ sticky panel headers.
78
79
  --_page-layout--color: var(--sc-kit--page-layout--color, var(--sc-kit--color--text--primary));
79
80
  --_page-layout--border-color: var(--sc-kit--page-layout--border-color, var(--sc-kit--color--border));
80
81
  --_page-layout--title-font-size: var(--sc-kit--page-layout--title--font-size, 1.125rem);
82
+ --_page-layout--header-padding-inline: var(--sc-kit--page-layout--header--padding-inline, 1.5rem);
81
83
  display: flex;
82
84
  flex-direction: column;
83
85
  height: 100%;
@@ -90,7 +92,7 @@ sticky panel headers.
90
92
  align-items: center;
91
93
  justify-content: space-between;
92
94
  height: 4.1875rem;
93
- padding: 1.25rem 1.5rem 0.875rem;
95
+ padding: 1.25rem var(--_page-layout--header-padding-inline) 0.875rem;
94
96
  background: var(--_page-layout--header-background);
95
97
  border-bottom: 1px solid var(--_page-layout--border-color);
96
98
  flex-shrink: 0;
@@ -28,6 +28,7 @@ type Props = {
28
28
  * | `--sc-kit--page-layout--color` | Page text color | `--sc-kit--color--text--primary` |
29
29
  * | `--sc-kit--page-layout--border-color` | Header divider color | `--sc-kit--color--border` |
30
30
  * | `--sc-kit--page-layout--title--font-size` | Title font size | `18px` |
31
+ * | `--sc-kit--page-layout--header--padding-inline` | Header inline padding | `24px` |
31
32
  */
32
33
  declare const Cmp: import("svelte").Component<Props, {}, "">;
33
34
  type Cmp = ReturnType<typeof Cmp>;
@@ -1,11 +1,19 @@
1
- <script lang="ts">import { slideHorizontally, transitionDuration } from '../../core/transitions';
1
+ <script lang="ts">import { horizontalWheelScroll } from '../../core/actions';
2
+ import { slideHorizontally, transitionDuration } from '../../core/transitions';
3
+ import { Icon } from '../icon';
2
4
  import PanelCollapseButton from './cmp.panel-collapse-button.svelte';
3
5
  import { PageLayoutLocalization } from './page-layout-localization';
6
+ import IconChevronLeft from '@fluentui/svg-icons/icons/chevron_left_20_regular.svg?raw';
7
+ import IconChevronRight from '@fluentui/svg-icons/icons/chevron_right_20_regular.svg?raw';
4
8
  import { untrack } from 'svelte';
5
9
  const { panelState, children, id, header, footer, title, actionsLeft, actionsCenter, actionsRight, collapseButtons, hideHeader = false, balanceHeaderCenter = false, resizing = null, borders = [], on } = $props();
6
10
  const localization = new PageLayoutLocalization();
7
11
  const isFlex = untrack(() => !resizing);
12
+ const HEADER_SCROLL_STEP = 160;
8
13
  let panelRef = $state(undefined);
14
+ let headerLeftTrack = $state(undefined);
15
+ let canScrollHeaderLeftBack = $state(false);
16
+ let canScrollHeaderLeftForward = $state(false);
9
17
  const { id: panelId, entry } = untrack(() => panelState.register({
10
18
  id,
11
19
  initialWidth: resizing?.initialWidth ?? null,
@@ -15,6 +23,26 @@ const canResize = $derived(resizing && [resizing.initialWidth, resizing.minWidth
15
23
  const widthCss = $derived(entry.width !== null ? `${entry.width}px` : undefined);
16
24
  const leftCollapseIds = $derived((collapseButtons ?? []).filter((cid) => panelState.get(cid)?.collapseDirection === 'left'));
17
25
  const rightCollapseIds = $derived((collapseButtons ?? []).filter((cid) => panelState.get(cid)?.collapseDirection === 'right'));
26
+ const updateHeaderLeftScrollState = (node) => {
27
+ const { scrollLeft, scrollWidth, clientWidth } = node;
28
+ canScrollHeaderLeftBack = scrollLeft > 0;
29
+ canScrollHeaderLeftForward = scrollLeft < scrollWidth - clientWidth - 1;
30
+ };
31
+ const headerLeftTrackMounted = (node) => {
32
+ headerLeftTrack = node;
33
+ const observer = new ResizeObserver(() => updateHeaderLeftScrollState(node));
34
+ observer.observe(node);
35
+ updateHeaderLeftScrollState(node);
36
+ return {
37
+ destroy: () => observer.disconnect()
38
+ };
39
+ };
40
+ const scrollHeaderLeftBack = () => {
41
+ headerLeftTrack?.scrollBy({ left: -HEADER_SCROLL_STEP, behavior: 'smooth' });
42
+ };
43
+ const scrollHeaderLeftForward = () => {
44
+ headerLeftTrack?.scrollBy({ left: HEADER_SCROLL_STEP, behavior: 'smooth' });
45
+ };
18
46
  $effect(() => {
19
47
  const collapsed = entry.collapsed;
20
48
  untrack(() => {
@@ -117,16 +145,43 @@ $effect(() => {
117
145
  {:else}
118
146
  {#if balanceHeaderCenter || leftCollapseIds.length > 0 || title || actionsLeft}
119
147
  <div class="page-panel__header-left" class:page-panel__header-left--balanced={balanceHeaderCenter}>
120
- {#each leftCollapseIds as cid (cid)}
121
- <PanelCollapseButton panelState={panelState} panelId={cid} />
122
- {/each}
123
- {#if typeof title === 'function'}
124
- {@render title()}
125
- {:else if title}
126
- <span class="page-panel__title">{title}</span>
148
+ {#if canScrollHeaderLeftBack}
149
+ <button
150
+ type="button"
151
+ class="page-panel__header-scroll-btn page-panel__header-scroll-btn--back"
152
+ onclick={scrollHeaderLeftBack}
153
+ aria-label={localization.scrollBack}>
154
+ <Icon src={IconChevronLeft} size="sm" />
155
+ </button>
127
156
  {/if}
128
- {#if actionsLeft}
129
- {@render actionsLeft()}
157
+ <div
158
+ class="page-panel__header-left-track"
159
+ class:page-panel__header-left-track--mask-back={canScrollHeaderLeftBack && !canScrollHeaderLeftForward}
160
+ class:page-panel__header-left-track--mask-forward={canScrollHeaderLeftForward && !canScrollHeaderLeftBack}
161
+ class:page-panel__header-left-track--mask-both={canScrollHeaderLeftBack && canScrollHeaderLeftForward}
162
+ use:headerLeftTrackMounted
163
+ use:horizontalWheelScroll
164
+ onscroll={(e) => updateHeaderLeftScrollState(e.currentTarget)}>
165
+ {#each leftCollapseIds as cid (cid)}
166
+ <PanelCollapseButton panelState={panelState} panelId={cid} />
167
+ {/each}
168
+ {#if typeof title === 'function'}
169
+ {@render title()}
170
+ {:else if title}
171
+ <span class="page-panel__title">{title}</span>
172
+ {/if}
173
+ {#if actionsLeft}
174
+ {@render actionsLeft()}
175
+ {/if}
176
+ </div>
177
+ {#if canScrollHeaderLeftForward}
178
+ <button
179
+ type="button"
180
+ class="page-panel__header-scroll-btn page-panel__header-scroll-btn--forward"
181
+ onclick={scrollHeaderLeftForward}
182
+ aria-label={localization.scrollForward}>
183
+ <Icon src={IconChevronRight} size="sm" />
184
+ </button>
130
185
  {/if}
131
186
  </div>
132
187
  {/if}
@@ -282,13 +337,66 @@ to min / max; Enter / Space toggle collapsed.
282
337
  display: flex;
283
338
  align-self: stretch;
284
339
  align-items: center;
285
- gap: 1rem;
286
340
  min-width: 0;
287
- overflow-x: clip;
341
+ position: relative;
288
342
  }
289
343
  .page-panel__header-left--balanced {
290
344
  justify-self: start;
291
345
  }
346
+ .page-panel__header-left:hover {
347
+ --_scroll-btn-opacity: 1;
348
+ }
349
+ .page-panel__header-left-track {
350
+ --_mask-size: 1.5rem;
351
+ display: flex;
352
+ align-items: center;
353
+ gap: 1rem;
354
+ min-width: 0;
355
+ overflow-x: auto;
356
+ scrollbar-width: none;
357
+ }
358
+ .page-panel__header-left-track::-webkit-scrollbar {
359
+ display: none;
360
+ }
361
+ .page-panel__header-left-track--mask-back {
362
+ mask-image: linear-gradient(to right, transparent 0%, black var(--_mask-size), black 100%);
363
+ }
364
+ .page-panel__header-left-track--mask-forward {
365
+ mask-image: linear-gradient(to right, black 0%, black calc(100% - var(--_mask-size)), transparent 100%);
366
+ }
367
+ .page-panel__header-left-track--mask-both {
368
+ mask-image: linear-gradient(to right, transparent 0%, black var(--_mask-size), black calc(100% - var(--_mask-size)), transparent 100%);
369
+ }
370
+ .page-panel__header-scroll-btn {
371
+ position: absolute;
372
+ top: 0;
373
+ bottom: 0;
374
+ z-index: 1;
375
+ display: flex;
376
+ align-items: center;
377
+ justify-content: center;
378
+ padding: 0 0.25rem;
379
+ background: transparent;
380
+ backdrop-filter: blur(2px);
381
+ border: none;
382
+ cursor: pointer;
383
+ color: var(--sc-kit--color--text--secondary);
384
+ opacity: var(--_scroll-btn-opacity, 0);
385
+ transition: opacity var(--sc-kit--duration--base) var(--sc-kit--ease--default);
386
+ }
387
+ .page-panel__header-scroll-btn:hover {
388
+ color: var(--sc-kit--color--text--primary);
389
+ }
390
+ .page-panel__header-scroll-btn--back {
391
+ left: 0;
392
+ padding-right: 0.625rem;
393
+ background: linear-gradient(to right, var(--_page-panel--header-background) 60%, transparent);
394
+ }
395
+ .page-panel__header-scroll-btn--forward {
396
+ right: 0;
397
+ padding-left: 0.625rem;
398
+ background: linear-gradient(to left, var(--_page-panel--header-background) 60%, transparent);
399
+ }
292
400
  .page-panel__header-center {
293
401
  display: flex;
294
402
  align-items: center;
@@ -4,4 +4,6 @@ export declare class PageLayoutLocalization {
4
4
  get toggleNavigation(): string;
5
5
  get togglePanels(): string;
6
6
  get close(): string;
7
+ get scrollBack(): string;
8
+ get scrollForward(): string;
7
9
  }
@@ -19,6 +19,14 @@ const loc = {
19
19
  close: {
20
20
  en: 'Close',
21
21
  no: 'Lukk'
22
+ },
23
+ scrollBack: {
24
+ en: 'Scroll back',
25
+ no: 'Rull tilbake'
26
+ },
27
+ scrollForward: {
28
+ en: 'Scroll forward',
29
+ no: 'Rull fremover'
22
30
  }
23
31
  };
24
32
  export class PageLayoutLocalization {
@@ -37,4 +45,10 @@ export class PageLayoutLocalization {
37
45
  get close() {
38
46
  return loc.close[AppLocale.current];
39
47
  }
48
+ get scrollBack() {
49
+ return loc.scrollBack[AppLocale.current];
50
+ }
51
+ get scrollForward() {
52
+ return loc.scrollForward[AppLocale.current];
53
+ }
40
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.40.1",
3
+ "version": "0.40.2",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",