@streamscloud/kit 0.51.1 → 0.53.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.
@@ -1,9 +1,9 @@
1
1
  <script lang="ts">import { BreadcrumbLocalization } from './breadcrumb-localization';
2
- let { items, separator = '/' } = $props();
2
+ let { items, separator = '/', underline = 'hover' } = $props();
3
3
  const localization = new BreadcrumbLocalization();
4
4
  </script>
5
5
 
6
- <div class="breadcrumb" role="navigation" aria-label={localization.navLabel}>
6
+ <div class="breadcrumb breadcrumb--underline-{underline}" role="navigation" aria-label={localization.navLabel}>
7
7
  {#each items as item, i (item.label + i)}
8
8
  {#if i > 0}<span class="breadcrumb__separator" aria-hidden="true">{separator}</span>{/if}
9
9
  {#if i === items.length - 1}
@@ -26,7 +26,8 @@ A horizontal trail of crumbs ending at the current page. Each non-last item rend
26
26
  - `<button>` styled like an anchor when only `item.on.click` is set (callback-only mode),
27
27
  - plain text `<span>` when neither is set.
28
28
 
29
- The last item is always plain text with `aria-current="page"`.
29
+ The last item is always plain text with `aria-current="page"`. `underline` decides whether the crumb
30
+ links show their underline on hover only (default), always, or never.
30
31
 
31
32
  ### CSS Custom Properties
32
33
  | Property | Description | Default |
@@ -46,6 +47,8 @@ The last item is always plain text with `aria-current="page"`.
46
47
  --_breadcrumb--link-color: var(--sc-kit--breadcrumb--link--color, var(--sc-kit--color--text--secondary));
47
48
  --_breadcrumb--link-color-hover: var(--sc-kit--breadcrumb--link--color--hover, var(--sc-kit--color--accent));
48
49
  --_breadcrumb--current-color: var(--sc-kit--breadcrumb--current--color, var(--sc-kit--color--text--primary));
50
+ --_breadcrumb--link-text-decoration: none;
51
+ --_breadcrumb--link-text-decoration-hover: underline;
49
52
  display: inline-flex;
50
53
  align-items: center;
51
54
  flex-wrap: wrap;
@@ -54,14 +57,20 @@ The last item is always plain text with `aria-current="page"`.
54
57
  line-height: var(--sc-kit--leading--tight);
55
58
  color: var(--_breadcrumb--color);
56
59
  }
60
+ .breadcrumb--underline-always {
61
+ --_breadcrumb--link-text-decoration: underline;
62
+ }
63
+ .breadcrumb--underline-never {
64
+ --_breadcrumb--link-text-decoration-hover: none;
65
+ }
57
66
  .breadcrumb__link {
58
67
  color: var(--_breadcrumb--link-color);
59
- text-decoration: none;
68
+ text-decoration: var(--_breadcrumb--link-text-decoration);
60
69
  transition: color var(--sc-kit--duration--base) var(--sc-kit--ease--default);
61
70
  }
62
71
  .breadcrumb__link:hover {
63
72
  color: var(--_breadcrumb--link-color-hover);
64
- text-decoration: underline;
73
+ text-decoration: var(--_breadcrumb--link-text-decoration-hover);
65
74
  }
66
75
  .breadcrumb__link:focus-visible {
67
76
  outline: 2px solid var(--sc-kit--color--border--focus);
@@ -3,6 +3,8 @@ type Props = {
3
3
  items: BreadcrumbItem[];
4
4
  /** Separator character between crumbs. @default '/' */
5
5
  separator?: string;
6
+ /** When the crumb links show their underline: only on hover, permanently, or not at all. @default 'hover' */
7
+ underline?: 'hover' | 'always' | 'never';
6
8
  };
7
9
  /**
8
10
  * A horizontal trail of crumbs ending at the current page. Each non-last item renders as:
@@ -11,7 +13,8 @@ type Props = {
11
13
  * - `<button>` styled like an anchor when only `item.on.click` is set (callback-only mode),
12
14
  * - plain text `<span>` when neither is set.
13
15
  *
14
- * The last item is always plain text with `aria-current="page"`.
16
+ * The last item is always plain text with `aria-current="page"`. `underline` decides whether the crumb
17
+ * links show their underline on hover only (default), always, or never.
15
18
  *
16
19
  * ### CSS Custom Properties
17
20
  * | Property | Description | Default |
@@ -1,4 +1,4 @@
1
- <script lang="ts">let { href, variant = 'default', external = false, on, children } = $props();
1
+ <script lang="ts">let { href, variant = 'default', underline = 'hover', external = false, on, children } = $props();
2
2
  const isAnchor = $derived(href !== undefined);
3
3
  const target = $derived(isAnchor && external ? '_blank' : undefined);
4
4
  const rel = $derived(isAnchor && external ? 'noopener noreferrer' : undefined);
@@ -6,11 +6,11 @@ export {};
6
6
  </script>
7
7
 
8
8
  {#if isAnchor}
9
- <a class="link link--{variant}" href={href} target={target} rel={rel} onclick={(e) => on?.click?.(e)}>
9
+ <a class="link link--{variant} link--underline-{underline}" href={href} target={target} rel={rel} onclick={(e) => on?.click?.(e)}>
10
10
  {@render children()}
11
11
  </a>
12
12
  {:else}
13
- <button type="button" class="link link--{variant}" onclick={(e) => on?.click?.(e)}>
13
+ <button type="button" class="link link--{variant} link--underline-{underline}" onclick={(e) => on?.click?.(e)}>
14
14
  {@render children()}
15
15
  </button>
16
16
  {/if}
@@ -19,8 +19,8 @@ export {};
19
19
  @component
20
20
  A semantic link with three color variants. `default` reads as the standard accent link; `subtle`
21
21
  sits inline in body text with a secondary tint that picks up on hover; `danger` is for destructive
22
- navigation hints (e.g. "delete this account"). All variants animate color on hover and gain an
23
- underline.
22
+ navigation hints (e.g. "delete this account"). All variants animate color on hover; `underline`
23
+ decides whether the underline shows on hover only (default), always, or never.
24
24
 
25
25
  Renders as an `<a>` when `href` is set, otherwise as `<button type="button">` styled identically —
26
26
  useful for callback-only actions that read as inline links (e.g. "edit this", "show more"). The
@@ -40,30 +40,38 @@ useful for callback-only actions that read as inline links (e.g. "edit this", "s
40
40
  --_link--color-subtle-hover: var(--sc-kit--link--color--hover, var(--sc-kit--color--text--primary));
41
41
  --_link--color-danger: var(--sc-kit--link--color, var(--sc-kit--color--danger));
42
42
  --_link--color-danger-hover: var(--sc-kit--link--color--hover, var(--sc-kit--color--danger--hover));
43
- text-decoration: none;
43
+ --_link--text-decoration: none;
44
+ --_link--text-decoration-hover: underline;
45
+ text-decoration: var(--_link--text-decoration);
44
46
  cursor: pointer;
45
47
  transition: color var(--sc-kit--duration--base) var(--sc-kit--ease--default);
46
48
  }
49
+ .link:hover {
50
+ text-decoration: var(--_link--text-decoration-hover);
51
+ }
52
+ .link--underline-always {
53
+ --_link--text-decoration: underline;
54
+ }
55
+ .link--underline-never {
56
+ --_link--text-decoration-hover: none;
57
+ }
47
58
  .link--default {
48
59
  color: var(--_link--color-default);
49
60
  }
50
61
  .link--default:hover {
51
62
  color: var(--_link--color-default-hover);
52
- text-decoration: underline;
53
63
  }
54
64
  .link--subtle {
55
65
  color: var(--_link--color-subtle);
56
66
  }
57
67
  .link--subtle:hover {
58
68
  color: var(--_link--color-subtle-hover);
59
- text-decoration: underline;
60
69
  }
61
70
  .link--danger {
62
71
  color: var(--_link--color-danger);
63
72
  }
64
73
  .link--danger:hover {
65
74
  color: var(--_link--color-danger-hover);
66
- text-decoration: underline;
67
75
  }
68
76
  .link:focus-visible {
69
77
  outline: 2px solid var(--sc-kit--color--border--focus);
@@ -5,6 +5,8 @@ type Props = {
5
5
  href?: string;
6
6
  /** Visual variant. @default 'default' */
7
7
  variant?: LinkVariant;
8
+ /** When the underline shows: only on hover, permanently, or not at all. @default 'hover' */
9
+ underline?: 'hover' | 'always' | 'never';
8
10
  /** External link — opens in a new tab and adds `rel="noopener noreferrer"`. Ignored in button mode. */
9
11
  external?: boolean;
10
12
  on?: {
@@ -15,8 +17,8 @@ type Props = {
15
17
  /**
16
18
  * A semantic link with three color variants. `default` reads as the standard accent link; `subtle`
17
19
  * sits inline in body text with a secondary tint that picks up on hover; `danger` is for destructive
18
- * navigation hints (e.g. "delete this account"). All variants animate color on hover and gain an
19
- * underline.
20
+ * navigation hints (e.g. "delete this account"). All variants animate color on hover; `underline`
21
+ * decides whether the underline shows on hover only (default), always, or never.
20
22
  *
21
23
  * Renders as an `<a>` when `href` is set, otherwise as `<button type="button">` styled identically —
22
24
  * useful for callback-only actions that read as inline links (e.g. "edit this", "show more"). The
@@ -2,7 +2,7 @@ export { default as Table } from './cmp.table.svelte';
2
2
  export { default as DraggableTable } from './cmp.table-draggable.svelte';
3
3
  export { default as TableColumnsManager } from './table-columns-manager/cmp.table-columns-manager.svelte';
4
4
  export { default as TableGroupActions } from './table-group-actions/cmp.table-group-actions.svelte';
5
- export type { ColumnsConfig, TableColumnSortDirection, TableColumnType, TableImageColumnFormat, TableItemAction, TableTextColumnFormat, TableOrderByState, PageQuery, IAnyTableColumn } from './types';
5
+ export type { ColumnsConfig, TableColumnSortDirection, TableColumnType, TableItemAction, TableOrderByState, PageQuery, IAnyTableColumn } from './types';
6
6
  export type { TableGroupAction } from './table-group-actions/types.svelte';
7
7
  export { TableModel } from './table-model.svelte';
8
8
  export { pickDirectionFromOrderByState, generatePagination } from './service';
@@ -14,6 +14,7 @@ const getDateValueForColumn = (column, item) => {
14
14
  };
15
15
  const dateTime = $derived(getDateValueForColumn(column, item));
16
16
  const by = $derived(column.byValueFactory ? column.byValueFactory(item) : null);
17
+ const underline = $derived(column.underline ?? 'hover');
17
18
  const getHref = (by) => {
18
19
  return column.hrefFactory ? column.hrefFactory(by) : null;
19
20
  };
@@ -26,7 +27,7 @@ const navigateToUser = (event, by) => {
26
27
  };
27
28
  </script>
28
29
 
29
- <span class="table-by-cell">
30
+ <span class="table-by-cell table-by-cell--underline-{underline}">
30
31
  {#if dateTime}
31
32
  {#if by}
32
33
  <span class="table-by-cell__by">
@@ -73,6 +74,8 @@ const navigateToUser = (event, by) => {
73
74
  <style>.table-by-cell {
74
75
  --_table-by-cell--font-size: var(--sc-kit--table--cell--font-size, 0.875em);
75
76
  --_table-by-cell--no-date--color: var(--sc-kit--color--text--muted);
77
+ --_table-by-cell--name-text-decoration: none;
78
+ --_table-by-cell--name-text-decoration-hover: underline;
76
79
  height: 3.125em;
77
80
  min-height: 3.125em;
78
81
  max-height: 3.125em;
@@ -113,12 +116,18 @@ const navigateToUser = (event, by) => {
113
116
  white-space: nowrap;
114
117
  overflow: hidden;
115
118
  }
119
+ .table-by-cell--underline-always {
120
+ --_table-by-cell--name-text-decoration: underline;
121
+ }
122
+ .table-by-cell--underline-never {
123
+ --_table-by-cell--name-text-decoration-hover: none;
124
+ }
116
125
  .table-by-cell__name--link {
117
126
  color: inherit;
118
- text-decoration: none;
127
+ text-decoration: var(--_table-by-cell--name-text-decoration);
119
128
  }
120
129
  .table-by-cell__name--link:hover {
121
- text-decoration: underline;
130
+ text-decoration: var(--_table-by-cell--name-text-decoration-hover);
122
131
  }
123
132
  .table-by-cell__by-image {
124
133
  display: flex;
@@ -65,6 +65,8 @@ export interface ITableByColumn<T> extends ITableColumn<T> {
65
65
  id: string;
66
66
  handle: string;
67
67
  }) => void) | null;
68
+ /** When the person-name link shows its underline: only on hover, permanently, or not at all. @default 'hover' */
69
+ underline?: 'hover' | 'always' | 'never';
68
70
  }
69
71
  export interface ITableButtonColumn<T> extends ITableColumn<T> {
70
72
  type: 'button';
@@ -83,7 +85,7 @@ export interface ITableIconColumn<T> extends ITableColumn<T> {
83
85
  export interface ITableImageColumn<T> extends ITableColumn<T> {
84
86
  type: 'image';
85
87
  valueFactory?: ((item: T) => string) | null;
86
- format?: TableImageColumnFormat;
88
+ format?: 'circle' | 'square-contain' | 'square-cover' | 'vertical-cover' | 'horizontal-cover';
87
89
  coverAspectRatio?: number;
88
90
  sizeCss?: string;
89
91
  }
@@ -98,13 +100,11 @@ export interface ITableSnippetColumn<T> extends ITableColumn<T> {
98
100
  }
99
101
  export interface ITableTextColumn<T> extends ITableColumn<T> {
100
102
  type: 'text';
101
- format?: TableTextColumnFormat | null;
103
+ format?: 'text' | 'html' | 'money' | 'date' | 'date-time' | null;
102
104
  /** @default 1 */
103
105
  maxLines?: number | 'single-line-no-trim' | null;
104
106
  valueFactory?: ((item: T) => string) | null;
105
107
  }
106
- export type TableTextColumnFormat = 'text' | 'html' | 'money' | 'date' | 'date-time';
107
- export type TableImageColumnFormat = 'circle' | 'square-contain' | 'square-cover' | 'vertical-cover' | 'horizontal-cover';
108
108
  export type TableItemAction<T> = {
109
109
  title: string;
110
110
  icon?: IconProp;
@@ -196,6 +196,7 @@ const onTimeUpdate = () => {
196
196
  }
197
197
  percentageCompleted = video.currentTime / video.duration || 0;
198
198
  notifyProgress();
199
+ on?.timeUpdate?.({ id, seconds: video.currentTime });
199
200
  };
200
201
  const onLoaded = () => {
201
202
  setVolume(MediaVolumeManager.volumeLevel);
@@ -238,6 +239,7 @@ const handleSeek = (percent) => {
238
239
  video.currentTime = video.duration * percent;
239
240
  percentageCompleted = percent;
240
241
  notifyProgress();
242
+ on?.timeUpdate?.({ id, seconds: video.currentTime });
241
243
  }
242
244
  };
243
245
  </script>
@@ -38,6 +38,15 @@ type Props = {
38
38
  }) => void;
39
39
  /** Fires on timeupdate with the completion ratio (0-1) */
40
40
  progress?: (value: number) => void;
41
+ /**
42
+ * Fires on timeupdate with the raw playback position in seconds. Position-change
43
+ * samples, not a heartbeat: nothing fires while paused, seeks fire once, and a
44
+ * stopped/reset player emits a trailing `seconds: 0`.
45
+ */
46
+ timeUpdate?: (data: {
47
+ id: string;
48
+ seconds: number;
49
+ }) => void;
41
50
  ended?: (data: {
42
51
  id: string;
43
52
  src: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.51.1",
3
+ "version": "0.53.0",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",