@streamscloud/kit 0.23.0 → 0.25.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.
Files changed (35) hide show
  1. package/dist/styles/_semantic.scss +16 -0
  2. package/dist/ui/badge/cmp.badge.svelte +30 -19
  3. package/dist/ui/badge/cmp.badge.svelte.d.ts +5 -3
  4. package/dist/ui/badge/index.d.ts +1 -1
  5. package/dist/ui/badge/types.d.ts +2 -1
  6. package/dist/ui/grid-card/fields/cmp.grid-card-progress-field.svelte +5 -60
  7. package/dist/ui/grid-card/fields/cmp.grid-card-progress-field.svelte.d.ts +5 -17
  8. package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte +9 -8
  9. package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte.d.ts +6 -5
  10. package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte +26 -9
  11. package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte.d.ts +7 -5
  12. package/dist/ui/page-toolbar/cmp.toolbar-value-stepper.svelte +8 -8
  13. package/dist/ui/page-toolbar/cmp.toolbar-value-stepper.svelte.d.ts +4 -4
  14. package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte +11 -6
  15. package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte.d.ts +7 -4
  16. package/dist/ui/page-toolbar/toolbar-sort-select-localization.d.ts +1 -0
  17. package/dist/ui/page-toolbar/toolbar-sort-select-localization.js +5 -1
  18. package/dist/ui/page-toolbar/toolbar-view-controls-localization.d.ts +1 -0
  19. package/dist/ui/page-toolbar/toolbar-view-controls-localization.js +5 -1
  20. package/dist/ui/progress-bar/cmp.progress-bar.svelte +111 -0
  21. package/dist/ui/progress-bar/cmp.progress-bar.svelte.d.ts +37 -0
  22. package/dist/ui/progress-bar/index.d.ts +2 -0
  23. package/dist/ui/progress-bar/index.js +1 -0
  24. package/dist/ui/progress-bar/progress-bar-localization.d.ts +3 -0
  25. package/dist/ui/progress-bar/progress-bar-localization.js +9 -0
  26. package/dist/ui/progress-bar/types.d.ts +7 -0
  27. package/dist/ui/progress-bar/types.js +1 -0
  28. package/dist/ui/table/table-cells/table-badge-cell.svelte +1 -1
  29. package/dist/ui/table/table-cells/table-cell.svelte +0 -3
  30. package/dist/ui/table/table-cells/table-image-cell.svelte +19 -2
  31. package/dist/ui/table/types.d.ts +6 -9
  32. package/dist/ui/table/types.js +1 -1
  33. package/package.json +5 -1
  34. package/dist/ui/table/table-cells/table-custom-cell.svelte +0 -5
  35. package/dist/ui/table/table-cells/table-custom-cell.svelte.d.ts +0 -38
@@ -61,6 +61,22 @@
61
61
  --sc-kit--color--info--hover: light-dark(#{$color-blue-700}, #{$color-blue-300});
62
62
  --sc-kit--color--info--soft: light-dark(#{$color-blue-50}, #{$color-blue-900});
63
63
 
64
+ // ============================================================
65
+ // COLOR — TONES (categorical palette; fg + soft bg, component-neutral)
66
+ // ============================================================
67
+ --sc-kit--tone--gray--fg: light-dark(#{$color-neutral-500}, #{$color-neutral-400});
68
+ --sc-kit--tone--gray--bg: light-dark(#{$color-neutral-50}, #{$color-dark-600});
69
+ --sc-kit--tone--blue--fg: light-dark(#{$color-blue-500}, #{$color-blue-400});
70
+ --sc-kit--tone--blue--bg: light-dark(#{$color-blue-50}, #{$color-blue-900});
71
+ --sc-kit--tone--green--fg: light-dark(#{$color-green-500}, #{$color-green-400});
72
+ --sc-kit--tone--green--bg: light-dark(#{$color-green-50}, #{$color-green-900});
73
+ --sc-kit--tone--red--fg: light-dark(#{$color-red-500}, #{$color-red-400});
74
+ --sc-kit--tone--red--bg: light-dark(#{$color-red-50}, #{$color-red-900});
75
+ --sc-kit--tone--orange--fg: light-dark(#{$color-orange-500}, #{$color-orange-400});
76
+ --sc-kit--tone--orange--bg: light-dark(#{$color-orange-100}, #{$color-orange-900});
77
+ --sc-kit--tone--teal--fg: light-dark(#3d7068, #5f938a);
78
+ --sc-kit--tone--teal--bg: light-dark(#eef4f3, #16302b);
79
+
64
80
  // ============================================================
65
81
  // COLOR — OVERLAYS
66
82
  // ============================================================
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">import { IconSlot } from '../icon';
2
- const { variant = 'neutral', size = 'md', style = 'soft', fullWidth = false, icon, children } = $props();
2
+ const { variant = 'neutral', size = 'md', style = 'soft', shape = 'pill', fullWidth = false, icon, children } = $props();
3
3
  </script>
4
4
 
5
- <span class="badge badge--{size} badge--{variant}-{style}" class:badge--full={fullWidth}>
5
+ <span class="badge badge--{size} badge--{variant}-{style}" class:badge--square={shape === 'square'} class:badge--full={fullWidth}>
6
6
  {#if icon}
7
7
  <span class="badge__icon" aria-hidden="true"><IconSlot icon={icon} /></span>
8
8
  {/if}
@@ -11,7 +11,7 @@ const { variant = 'neutral', size = 'md', style = 'soft', fullWidth = false, ico
11
11
 
12
12
  <!--
13
13
  @component
14
- Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default) for a calm tinted fill that pairs with body content. Optional leading `icon` renders in its own slot; the text content keeps its own ellipsis when it overflows.
14
+ Status indicator, pill-shaped by default (`shape="square"` for a 4px-radius chip). Use `solid` for stronger emphasis, `soft` (default) for a calm tinted fill that pairs with body content. Optional leading `icon` renders in its own slot; the text content keeps its own ellipsis when it overflows.
15
15
 
16
16
  ### CSS Custom Properties
17
17
  | Property | Description | Default |
@@ -20,7 +20,7 @@ Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default
20
20
  | `--sc-kit--badge--background` | Background color | per variant + style |
21
21
  | `--sc-kit--badge--height` | Badge height | per size (20 / 24px) |
22
22
  | `--sc-kit--badge--padding-inline` | Horizontal padding | `0.875rem 0.75rem` |
23
- | `--sc-kit--badge--border-radius` | Corner radius | `var(--sc-kit--radius--pill)` |
23
+ | `--sc-kit--badge--border-radius` | Corner radius | `shape="square"` → `var(--sc-kit--radius--sm)`, else `var(--sc-kit--radius--pill)` |
24
24
  | `--sc-kit--badge--font-size` | Content font size | per size |
25
25
  | `--sc-kit--badge--icon-size` | Leading icon size | per size (14 / 16px) |
26
26
  | `--sc-kit--badge--font-weight` | Font weight | `var(--sc-kit--font-weight--medium)` |
@@ -57,6 +57,9 @@ Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default
57
57
  text-overflow: ellipsis;
58
58
  white-space: nowrap;
59
59
  }
60
+ .badge--square {
61
+ --_badge--border-radius: var(--sc-kit--badge--border-radius, var(--sc-kit--radius--sm));
62
+ }
60
63
  .badge--full {
61
64
  display: flex;
62
65
  width: 100%;
@@ -73,42 +76,50 @@ Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default
73
76
  --_badge--icon-size: var(--sc-kit--badge--icon-size, 1rem);
74
77
  }
75
78
  .badge--neutral-soft {
76
- --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--text--secondary));
77
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--bg--active));
79
+ --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--tone--gray--fg));
80
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--gray--bg));
78
81
  }
79
82
  .badge--accent-soft {
80
- --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--accent));
81
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--accent--soft));
83
+ --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--tone--blue--fg));
84
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--blue--bg));
85
+ }
86
+ .badge--auxiliary-soft {
87
+ --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--tone--teal--fg));
88
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--teal--bg));
82
89
  }
83
90
  .badge--success-soft {
84
- --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--success));
85
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--success--soft));
91
+ --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--tone--green--fg));
92
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--green--bg));
86
93
  }
87
94
  .badge--warning-soft {
88
- --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--warning));
89
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--warning--soft));
95
+ --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--tone--orange--fg));
96
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--orange--bg));
90
97
  }
91
98
  .badge--danger-soft {
92
- --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--danger));
93
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--danger--soft));
99
+ --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--tone--red--fg));
100
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--red--bg));
94
101
  }
95
102
  .badge--neutral-solid {
96
103
  --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--bg--panel));
97
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--text--secondary));
104
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--gray--fg));
98
105
  }
99
106
  .badge--accent-solid {
100
107
  --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--text--on-accent));
101
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--accent));
108
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--blue--fg));
109
+ }
110
+ .badge--auxiliary-solid {
111
+ --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--text--on-accent));
112
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--teal--fg));
102
113
  }
103
114
  .badge--success-solid {
104
115
  --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--text--on-accent));
105
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--success));
116
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--green--fg));
106
117
  }
107
118
  .badge--warning-solid {
108
119
  --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--text--primary));
109
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--warning));
120
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--orange--fg));
110
121
  }
111
122
  .badge--danger-solid {
112
123
  --_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--text--on-accent));
113
- --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--color--danger));
124
+ --_badge--background: var(--sc-kit--badge--background, var(--sc-kit--tone--red--fg));
114
125
  }</style>
@@ -1,5 +1,5 @@
1
1
  import { type IconProp } from '../icon';
2
- import type { BadgeVariant } from './types';
2
+ import type { BadgeShape, BadgeVariant } from './types';
3
3
  import type { Snippet } from 'svelte';
4
4
  type Props = {
5
5
  /** Color variant @default 'neutral' */
@@ -8,6 +8,8 @@ type Props = {
8
8
  size?: 'sm' | 'md';
9
9
  /** Filled chip vs soft-tinted fill @default 'soft' */
10
10
  style?: 'soft' | 'solid';
11
+ /** Corner style — pill (fully rounded) vs square (4px radius). @default 'pill' */
12
+ shape?: BadgeShape;
11
13
  /** Stretch to fill the parent's inline axis, centering the content. @default false */
12
14
  fullWidth?: boolean;
13
15
  /** Optional leading icon. */
@@ -15,7 +17,7 @@ type Props = {
15
17
  children: Snippet;
16
18
  };
17
19
  /**
18
- * Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default) for a calm tinted fill that pairs with body content. Optional leading `icon` renders in its own slot; the text content keeps its own ellipsis when it overflows.
20
+ * Status indicator, pill-shaped by default (`shape="square"` for a 4px-radius chip). Use `solid` for stronger emphasis, `soft` (default) for a calm tinted fill that pairs with body content. Optional leading `icon` renders in its own slot; the text content keeps its own ellipsis when it overflows.
19
21
  *
20
22
  * ### CSS Custom Properties
21
23
  * | Property | Description | Default |
@@ -24,7 +26,7 @@ type Props = {
24
26
  * | `--sc-kit--badge--background` | Background color | per variant + style |
25
27
  * | `--sc-kit--badge--height` | Badge height | per size (20 / 24px) |
26
28
  * | `--sc-kit--badge--padding-inline` | Horizontal padding | `0.875rem 0.75rem` |
27
- * | `--sc-kit--badge--border-radius` | Corner radius | `var(--sc-kit--radius--pill)` |
29
+ * | `--sc-kit--badge--border-radius` | Corner radius | `shape="square"` → `var(--sc-kit--radius--sm)`, else `var(--sc-kit--radius--pill)` |
28
30
  * | `--sc-kit--badge--font-size` | Content font size | per size |
29
31
  * | `--sc-kit--badge--icon-size` | Leading icon size | per size (14 / 16px) |
30
32
  * | `--sc-kit--badge--font-weight` | Font weight | `var(--sc-kit--font-weight--medium)` |
@@ -1,2 +1,2 @@
1
1
  export { default as Badge } from './cmp.badge.svelte';
2
- export type { BadgeVariant } from './types';
2
+ export type { BadgeShape, BadgeVariant } from './types';
@@ -1 +1,2 @@
1
- export type BadgeVariant = 'neutral' | 'accent' | 'success' | 'warning' | 'danger';
1
+ export type BadgeVariant = 'neutral' | 'accent' | 'auxiliary' | 'success' | 'warning' | 'danger';
2
+ export type BadgeShape = 'pill' | 'square';
@@ -1,69 +1,14 @@
1
- <script lang="ts">import GridCardField from './cmp.grid-card-field.svelte';
1
+ <script lang="ts">import { ProgressBar } from '../../progress-bar';
2
+ import GridCardField from './cmp.grid-card-field.svelte';
2
3
  const { label, stage, stages } = $props();
3
- const currentStage = $derived(stages[Math.max(0, Math.min(stage, stages.length - 1))]);
4
- const currentLabel = $derived(currentStage?.label ?? '');
5
4
  </script>
6
5
 
7
6
  <GridCardField label={label}>
8
- <div class="grid-card-progress-field">
9
- <div
10
- class="grid-card-progress-field__bar"
11
- role="progressbar"
12
- aria-valuemin={1}
13
- aria-valuemax={stages.length}
14
- aria-valuenow={stage + 1}
15
- aria-label={currentLabel}>
16
- {#each stages as s, i (i)}
17
- <span class="grid-card-progress-field__segment" class:grid-card-progress-field__segment--filled={i <= stage} style:--_seg-color={s.color}></span>
18
- {/each}
19
- </div>
20
- {#if currentLabel}
21
- <span class="grid-card-progress-field__label">{currentLabel}</span>
22
- {/if}
23
- </div>
7
+ <ProgressBar stage={stage} stages={stages} />
24
8
  </GridCardField>
25
9
 
26
10
  <!--
27
11
  @component
28
- Multi-stage workflow progress indicator. Pass `stages` as an array of `{ color, label? }`
29
- descriptors the bar renders one segment per stage; segments `0..stage` (inclusive) are
30
- filled with the per-stage color, the rest are muted. Consumer supplies the per-stage color
31
- (string — any valid CSS color or `var(--sc-kit--color--*)` reference). Useful for content
32
- lifecycle indicators (Ideas → Draft → Review → Scheduled → Published).
33
-
34
- ### CSS Custom Properties
35
- | Property | Description | Default |
36
- |---|---|---|
37
- | `--sc-kit--grid-card-progress-field--segment--height` | Bar segment height | `4px` |
38
- | `--sc-kit--grid-card-progress-field--segment--gap` | Gap between segments | `2px` |
39
- | `--sc-kit--grid-card-progress-field--segment--background--empty` | Empty segment color | `var(--sc-kit--color--bg--active)` |
12
+ Grid-card field pairing a field label with a multi-stage `ProgressBar`. See `ProgressBar`
13
+ (`@streamscloud/kit/ui/progress-bar`) for the bar's own CSS Custom Properties.
40
14
  -->
41
-
42
- <style>.grid-card-progress-field {
43
- --_gcp--seg-height: var(--sc-kit--grid-card-progress-field--segment--height, 0.25rem);
44
- --_gcp--seg-gap: var(--sc-kit--grid-card-progress-field--segment--gap, 0.125rem);
45
- --_gcp--seg-empty: var(--sc-kit--grid-card-progress-field--segment--background--empty, var(--sc-kit--color--bg--active));
46
- display: flex;
47
- flex-direction: column;
48
- gap: 0.125rem;
49
- min-width: 0;
50
- }
51
- .grid-card-progress-field__bar {
52
- display: flex;
53
- gap: var(--_gcp--seg-gap);
54
- width: 100%;
55
- }
56
- .grid-card-progress-field__segment {
57
- flex: 1;
58
- height: var(--_gcp--seg-height);
59
- background: var(--_gcp--seg-empty);
60
- border-radius: 0.0625rem;
61
- }
62
- .grid-card-progress-field__segment--filled {
63
- background: var(--_seg-color);
64
- }
65
- .grid-card-progress-field__label {
66
- font-size: 0.625rem;
67
- color: var(--sc-kit--color--text--secondary);
68
- line-height: var(--sc-kit--leading--tight);
69
- }</style>
@@ -1,29 +1,17 @@
1
+ import { type ProgressBarStage } from '../../progress-bar';
1
2
  type Props = {
2
3
  label: string;
3
4
  /** Current stage index, 0-based. Stages 0..stage (inclusive) are filled. */
4
5
  stage: number;
5
6
  /**
6
7
  * Stage descriptors — at minimum `{ color }` per stage (consumer provides the CSS color).
7
- * Length determines the total segment count. Pass arbitrary number of stages.
8
+ * Length determines the total segment count.
8
9
  */
9
- stages: {
10
- color: string;
11
- label?: string;
12
- }[];
10
+ stages: ProgressBarStage[];
13
11
  };
14
12
  /**
15
- * Multi-stage workflow progress indicator. Pass `stages` as an array of `{ color, label? }`
16
- * descriptors the bar renders one segment per stage; segments `0..stage` (inclusive) are
17
- * filled with the per-stage color, the rest are muted. Consumer supplies the per-stage color
18
- * (string — any valid CSS color or `var(--sc-kit--color--*)` reference). Useful for content
19
- * lifecycle indicators (Ideas → Draft → Review → Scheduled → Published).
20
- *
21
- * ### CSS Custom Properties
22
- * | Property | Description | Default |
23
- * |---|---|---|
24
- * | `--sc-kit--grid-card-progress-field--segment--height` | Bar segment height | `4px` |
25
- * | `--sc-kit--grid-card-progress-field--segment--gap` | Gap between segments | `2px` |
26
- * | `--sc-kit--grid-card-progress-field--segment--background--empty` | Empty segment color | `var(--sc-kit--color--bg--active)` |
13
+ * Grid-card field pairing a field label with a multi-stage `ProgressBar`. See `ProgressBar`
14
+ * (`@streamscloud/kit/ui/progress-bar`) for the bar's own CSS Custom Properties.
27
15
  */
28
16
  declare const Cmp: import("svelte").Component<Props, {}, "">;
29
17
  type Cmp = ReturnType<typeof Cmp>;
@@ -4,7 +4,7 @@ const { icon, 'aria-label': ariaLabel, size = 'sm', active = false, disabled = f
4
4
 
5
5
  {#if presentational}
6
6
  <span class="toolbar-icon-button toolbar-icon-button--{size}" class:toolbar-icon-button--active={active}>
7
- <Icon src={icon} size="md" />
7
+ <Icon src={icon} size={size === 'sm' ? 'control-md' : 'md'} />
8
8
  </span>
9
9
  {:else}
10
10
  <button
@@ -15,28 +15,29 @@ const { icon, 'aria-label': ariaLabel, size = 'sm', active = false, disabled = f
15
15
  aria-label={ariaLabel}
16
16
  aria-pressed={active}
17
17
  onclick={() => on?.click?.()}>
18
- <Icon src={icon} size="md" />
18
+ <Icon src={icon} size={size === 'sm' ? 'control-md' : 'md'} />
19
19
  </button>
20
20
  {/if}
21
21
 
22
22
  <!--
23
23
  @component
24
- A flat, square toolbar icon button (28px at `sm`, 32px at `md`, with a 20px glyph). Background appears on
25
- hover only; `active` tints the glyph with the accent color (no background). Pass `presentational` to render
26
- a non-interactive `<span>` for use inside a wrapper that owns the click + semantics (e.g. a Popover trigger).
27
- Shared by `ToolbarViewControls` and the `ToolbarFilterSelect` icon trigger so they stay visually identical.
24
+ A flat, square toolbar icon button (28px at `sm`, 32px at `md`, with a 16px glyph at `sm` / 20px at `md`).
25
+ Background appears on hover only; `active` tints the glyph with the primary text color (no background). Pass
26
+ `presentational` to render a non-interactive `<span>` for use inside a wrapper that owns the click +
27
+ semantics (e.g. a Popover trigger). Shared by `ToolbarViewControls` and the `ToolbarSortSelect` icon trigger
28
+ so they stay visually identical.
28
29
 
29
30
  ### CSS Custom Properties
30
31
  | Property | Description | Default |
31
32
  |---|---|---|
32
33
  | `--sc-kit--toolbar-icon-button--color` | Idle glyph color | `var(--sc-kit--color--text--muted)` |
33
- | `--sc-kit--toolbar-icon-button--color--active` | Active glyph color | `var(--sc-kit--color--accent)` |
34
+ | `--sc-kit--toolbar-icon-button--color--active` | Active glyph color | `var(--sc-kit--color--text--primary)` |
34
35
  | `--sc-kit--toolbar-icon-button--background--hover` | Hover background | `var(--sc-kit--color--bg--hover)` |
35
36
  -->
36
37
 
37
38
  <style>.toolbar-icon-button {
38
39
  --_tib--color: var(--sc-kit--toolbar-icon-button--color, var(--sc-kit--color--text--muted));
39
- --_tib--color-active: var(--sc-kit--toolbar-icon-button--color--active, var(--sc-kit--color--accent));
40
+ --_tib--color-active: var(--sc-kit--toolbar-icon-button--color--active, var(--sc-kit--color--text--primary));
40
41
  --_tib--background-hover: var(--sc-kit--toolbar-icon-button--background--hover, var(--sc-kit--color--bg--hover));
41
42
  --_tib--size: var(--_tib--size-height);
42
43
  --sc-kit--icon--color: var(--_tib--color);
@@ -15,16 +15,17 @@ type Props = {
15
15
  };
16
16
  };
17
17
  /**
18
- * A flat, square toolbar icon button (28px at `sm`, 32px at `md`, with a 20px glyph). Background appears on
19
- * hover only; `active` tints the glyph with the accent color (no background). Pass `presentational` to render
20
- * a non-interactive `<span>` for use inside a wrapper that owns the click + semantics (e.g. a Popover trigger).
21
- * Shared by `ToolbarViewControls` and the `ToolbarFilterSelect` icon trigger so they stay visually identical.
18
+ * A flat, square toolbar icon button (28px at `sm`, 32px at `md`, with a 16px glyph at `sm` / 20px at `md`).
19
+ * Background appears on hover only; `active` tints the glyph with the primary text color (no background). Pass
20
+ * `presentational` to render a non-interactive `<span>` for use inside a wrapper that owns the click +
21
+ * semantics (e.g. a Popover trigger). Shared by `ToolbarViewControls` and the `ToolbarSortSelect` icon trigger
22
+ * so they stay visually identical.
22
23
  *
23
24
  * ### CSS Custom Properties
24
25
  * | Property | Description | Default |
25
26
  * |---|---|---|
26
27
  * | `--sc-kit--toolbar-icon-button--color` | Idle glyph color | `var(--sc-kit--color--text--muted)` |
27
- * | `--sc-kit--toolbar-icon-button--color--active` | Active glyph color | `var(--sc-kit--color--accent)` |
28
+ * | `--sc-kit--toolbar-icon-button--color--active` | Active glyph color | `var(--sc-kit--color--text--primary)` |
28
29
  * | `--sc-kit--toolbar-icon-button--background--hover` | Hover background | `var(--sc-kit--color--bg--hover)` |
29
30
  */
30
31
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -1,12 +1,14 @@
1
- <script lang="ts" generics="S">import ToolbarFilterSelect from './cmp.toolbar-filter-select.svelte';
1
+ <script lang="ts" generics="S">import { Button } from '../button';
2
+ import ToolbarFilterSelect from './cmp.toolbar-filter-select.svelte';
2
3
  import ToolbarIconButton from './cmp.toolbar-icon-button.svelte';
3
4
  import ToolbarSectionTitle from './cmp.toolbar-section-title.svelte';
4
5
  import { ToolbarSortSelectLocalization } from './toolbar-sort-select-localization';
5
6
  import IconFilter from '@fluentui/svg-icons/icons/filter_20_regular.svg?raw';
6
- const { options, value, label, size = 'sm', icon, compare, on } = $props();
7
+ const { options, value, label, size = 'sm', trigger = 'icon', compare, on } = $props();
7
8
  const localization = new ToolbarSortSelectLocalization();
8
9
  const orderByLabel = $derived(label ?? localization.orderBy);
9
10
  const selection = $derived([value]);
11
+ const resolvedTrigger = $derived(typeof trigger === 'function' ? trigger : trigger === 'button' ? buttonTrigger : iconTrigger);
10
12
  const onChange = (next) => {
11
13
  if (next.length > 0) {
12
14
  on?.change?.(next[0]);
@@ -14,18 +16,33 @@ const onChange = (next) => {
14
16
  };
15
17
  </script>
16
18
 
17
- <ToolbarFilterSelect label={orderByLabel} single footer={false} size={size} options={options} value={selection} compare={compare} on={{ change: onChange }}>
19
+ {#snippet iconTrigger()}
20
+ <ToolbarIconButton presentational icon={IconFilter} size={size} />
21
+ {/snippet}
22
+
23
+ {#snippet buttonTrigger()}
24
+ <Button type="presentational" variant="secondary" size={size} icon={IconFilter}>{localization.sorting}</Button>
25
+ {/snippet}
26
+
27
+ <ToolbarFilterSelect
28
+ label={orderByLabel}
29
+ single
30
+ footer={false}
31
+ size={size}
32
+ options={options}
33
+ value={selection}
34
+ compare={compare}
35
+ trigger={resolvedTrigger}
36
+ on={{ change: onChange }}>
18
37
  {#snippet header()}
19
38
  <ToolbarSectionTitle>{orderByLabel}</ToolbarSectionTitle>
20
39
  {/snippet}
21
- {#snippet trigger()}
22
- <ToolbarIconButton presentational icon={icon ?? IconFilter} size={size} />
23
- {/snippet}
24
40
  </ToolbarFilterSelect>
25
41
 
26
42
  <!--
27
43
  @component
28
- A toolbar sort control: a `ToolbarFilterSelect` in single-select mode behind a flat icon trigger
29
- (`ToolbarIconButton`), with an `Order by` section title above the options. Stand-alone, or composed into
30
- `ToolbarViewControls` via its `prepend` snippet.
44
+ A toolbar sort control: a `ToolbarFilterSelect` in single-select mode behind a `trigger` — `'icon'`
45
+ (default, flat icon button), `'button'` (labelled secondary button), or a custom snippet with an
46
+ `Order by` section title above the options. Stand-alone, or composed into `ToolbarViewControls` via
47
+ its `prepend` snippet.
31
48
  -->
@@ -1,4 +1,5 @@
1
1
  import type { SelectItem } from '../select';
2
+ import type { Snippet } from 'svelte';
2
3
  declare function $$render<S>(): {
3
4
  props: {
4
5
  options: SelectItem<S>[];
@@ -7,8 +8,8 @@ declare function $$render<S>(): {
7
8
  label?: string;
8
9
  /** Button size preset — sm = 28px, md = 32px. @default 'sm' */
9
10
  size?: "sm" | "md";
10
- /** Trigger glyph (a string SVG source). @default a filter glyph */
11
- icon?: string;
11
+ /** Presentational trigger — `'icon'` (flat icon button), `'button'` (labelled secondary button), or a custom snippet. The popover owns the click and is named by `label`. @default 'icon' */
12
+ trigger?: "icon" | "button" | Snippet;
12
13
  /** Equality comparator — required when `S` is an object. */
13
14
  compare?: (a: S, b: S) => boolean;
14
15
  on?: {
@@ -35,9 +36,10 @@ interface $$IsomorphicComponent {
35
36
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
36
37
  }
37
38
  /**
38
- * A toolbar sort control: a `ToolbarFilterSelect` in single-select mode behind a flat icon trigger
39
- * (`ToolbarIconButton`), with an `Order by` section title above the options. Stand-alone, or composed into
40
- * `ToolbarViewControls` via its `prepend` snippet.
39
+ * A toolbar sort control: a `ToolbarFilterSelect` in single-select mode behind a `trigger` — `'icon'`
40
+ * (default, flat icon button), `'button'` (labelled secondary button), or a custom snippet with an
41
+ * `Order by` section title above the options. Stand-alone, or composed into `ToolbarViewControls` via
42
+ * its `prepend` snippet.
41
43
  */
42
44
  declare const Cmp: $$IsomorphicComponent;
43
45
  type Cmp<S> = InstanceType<typeof Cmp<S>>;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">import { CONTROL_ICON_SIZE, Icon, scaleUp } from '../icon';
2
2
  import { ToolbarValueStepperLocalization } from './toolbar-value-stepper-localization';
3
- import IconChevronLeft from '@fluentui/svg-icons/icons/chevron_left_16_regular.svg?raw';
4
- import IconChevronRight from '@fluentui/svg-icons/icons/chevron_right_16_regular.svg?raw';
3
+ import IconAdd from '@fluentui/svg-icons/icons/add_16_regular.svg?raw';
4
+ import IconSubtract from '@fluentui/svg-icons/icons/subtract_16_regular.svg?raw';
5
5
  const { value, min = 0, max = 100, step = 1, valueSuffix = '', size = 'sm', on } = $props();
6
6
  const localization = new ToolbarValueStepperLocalization();
7
7
  const iconSize = $derived(scaleUp(CONTROL_ICON_SIZE[size]));
@@ -17,25 +17,25 @@ const increase = () => {
17
17
 
18
18
  <div class="toolbar-value-stepper toolbar-value-stepper--{size}" role="group" aria-label={localization.value}>
19
19
  <button type="button" class="toolbar-value-stepper__btn" onclick={decrease} disabled={atMin} aria-label={localization.decreaseValue}>
20
- <Icon src={IconChevronLeft} size={iconSize} />
20
+ <Icon src={IconSubtract} size={iconSize} />
21
21
  </button>
22
22
  <span class="toolbar-value-stepper__value">{value}{valueSuffix}</span>
23
23
  <button type="button" class="toolbar-value-stepper__btn" onclick={increase} disabled={atMax} aria-label={localization.increaseValue}>
24
- <Icon src={IconChevronRight} size={iconSize} />
24
+ <Icon src={IconAdd} size={iconSize} />
25
25
  </button>
26
26
  </div>
27
27
 
28
28
  <!--
29
29
  @component
30
- A compact `[<] value [>]` stepper for toolbars — increment / decrement a numeric value between `min`
31
- and `max` by `step`, with an optional `valueSuffix` (e.g. ` %`). Bound arrows disable at the limits.
30
+ A compact `[] value [+]` stepper for toolbars — increment / decrement a numeric value between `min`
31
+ and `max` by `step`, with an optional `valueSuffix` (e.g. ` %`). The / + buttons disable at the limits.
32
32
  Shares the field-height preset so it lines up with other toolbar controls.
33
33
 
34
34
  ### CSS Custom Properties
35
35
  | Property | Description | Default |
36
36
  |---|---|---|
37
- | `--sc-kit--toolbar-value-stepper--value--min-inline-size` | Min width of the value readout (keeps arrows from shifting) | `2.25rem` |
38
- | `--sc-kit--toolbar-value-stepper--icon--color` | Arrow icon color | `var(--sc-kit--color--accent)` |
37
+ | `--sc-kit--toolbar-value-stepper--value--min-inline-size` | Min width of the value readout (keeps the buttons from shifting) | `2.25rem` |
38
+ | `--sc-kit--toolbar-value-stepper--icon--color` | Button icon color | `var(--sc-kit--color--accent)` |
39
39
  -->
40
40
 
41
41
  <style>.toolbar-value-stepper {
@@ -15,15 +15,15 @@ type Props = {
15
15
  };
16
16
  };
17
17
  /**
18
- * A compact `[<] value [>]` stepper for toolbars — increment / decrement a numeric value between `min`
19
- * and `max` by `step`, with an optional `valueSuffix` (e.g. ` %`). Bound arrows disable at the limits.
18
+ * A compact `[] value [+]` stepper for toolbars — increment / decrement a numeric value between `min`
19
+ * and `max` by `step`, with an optional `valueSuffix` (e.g. ` %`). The / + buttons disable at the limits.
20
20
  * Shares the field-height preset so it lines up with other toolbar controls.
21
21
  *
22
22
  * ### CSS Custom Properties
23
23
  * | Property | Description | Default |
24
24
  * |---|---|---|
25
- * | `--sc-kit--toolbar-value-stepper--value--min-inline-size` | Min width of the value readout (keeps arrows from shifting) | `2.25rem` |
26
- * | `--sc-kit--toolbar-value-stepper--icon--color` | Arrow icon color | `var(--sc-kit--color--accent)` |
25
+ * | `--sc-kit--toolbar-value-stepper--value--min-inline-size` | Min width of the value readout (keeps the buttons from shifting) | `2.25rem` |
26
+ * | `--sc-kit--toolbar-value-stepper--icon--color` | Button icon color | `var(--sc-kit--color--accent)` |
27
27
  */
28
28
  declare const Cmp: import("svelte").Component<Props, {}, "">;
29
29
  type Cmp = ReturnType<typeof Cmp>;
@@ -3,8 +3,9 @@ import ToolbarIconButton from './cmp.toolbar-icon-button.svelte';
3
3
  import { ToolbarViewControlsLocalization } from './toolbar-view-controls-localization';
4
4
  import IconAppsList from '@fluentui/svg-icons/icons/apps_list_20_regular.svg?raw';
5
5
  import IconGrid from '@fluentui/svg-icons/icons/grid_20_regular.svg?raw';
6
+ import IconCard from '@fluentui/svg-icons/icons/square_20_regular.svg?raw';
6
7
  import { untrack } from 'svelte';
7
- const { view, size = 'sm', viewStorageKey, prepend, on } = $props();
8
+ const { view, size = 'sm', showCard = false, viewStorageKey, prepend, on } = $props();
8
9
  const localization = new ToolbarViewControlsLocalization();
9
10
  let storage = null;
10
11
  $effect(() => untrack(() => {
@@ -13,7 +14,7 @@ $effect(() => untrack(() => {
13
14
  }
14
15
  storage = LocalStorageItem.of(viewStorageKey);
15
16
  const saved = storage.get();
16
- if (saved === 'list' || saved === 'grid') {
17
+ if (saved === 'list' || saved === 'grid' || (saved === 'card' && showCard)) {
17
18
  on?.viewChange?.(saved);
18
19
  }
19
20
  }));
@@ -29,22 +30,26 @@ const setView = (next) => {
29
30
  {/if}
30
31
  <ToolbarIconButton icon={IconAppsList} size={size} active={view === 'list'} aria-label={localization.listView} on={{ click: () => setView('list') }} />
31
32
  <ToolbarIconButton icon={IconGrid} size={size} active={view === 'grid'} aria-label={localization.gridView} on={{ click: () => setView('grid') }} />
33
+ {#if showCard}
34
+ <ToolbarIconButton icon={IconCard} size={size} active={view === 'card'} aria-label={localization.cardView} on={{ click: () => setView('card') }} />
35
+ {/if}
32
36
  </div>
33
37
 
34
38
  <!--
35
39
  @component
36
40
  A toolbar view switcher: a `list` / `grid` toggle built on the shared `ToolbarIconButton` (flat, 28px at
37
- `sm` / 32px at `md`, 20px glyph). Pass `viewStorageKey` to persist the view across reloads, and compose a
38
- leading control — e.g. `ToolbarSortSelect` — through the `prepend` snippet.
41
+ `sm` / 32px at `md`, 20px glyph), with an opt-in `card` button via `showCard`. Pass `viewStorageKey` to
42
+ persist the view across reloads, and compose a leading control — e.g. `ToolbarSortSelect` — through the
43
+ `prepend` snippet.
39
44
 
40
45
  ### CSS Custom Properties
41
46
  | Property | Description | Default |
42
47
  |---|---|---|
43
- | `--sc-kit--toolbar-view-controls--gap` | Gap between the controls | `var(--sc-kit--space--3)` |
48
+ | `--sc-kit--toolbar-view-controls--gap` | Gap between the controls | `var(--sc-kit--space--2)` |
44
49
  -->
45
50
 
46
51
  <style>.toolbar-view-controls {
47
- --_tvc--gap: var(--sc-kit--toolbar-view-controls--gap, var(--sc-kit--space--3));
52
+ --_tvc--gap: var(--sc-kit--toolbar-view-controls--gap, var(--sc-kit--space--2));
48
53
  display: inline-flex;
49
54
  align-items: center;
50
55
  gap: var(--_tvc--gap);
@@ -1,9 +1,11 @@
1
1
  import type { Snippet } from 'svelte';
2
- type ViewMode = 'list' | 'grid';
2
+ type ViewMode = 'list' | 'grid' | 'card';
3
3
  type Props = {
4
4
  view: ViewMode;
5
5
  /** Button size preset — sm = 28px, md = 32px. @default 'sm' */
6
6
  size?: 'sm' | 'md';
7
+ /** Reveal the `card` view button alongside list / grid. @default false */
8
+ showCard?: boolean;
7
9
  /** Persist the view mode under this localStorage key. */
8
10
  viewStorageKey?: string;
9
11
  /** Leading content before the view toggle — e.g. a composed `ToolbarSortSelect`. */
@@ -14,13 +16,14 @@ type Props = {
14
16
  };
15
17
  /**
16
18
  * A toolbar view switcher: a `list` / `grid` toggle built on the shared `ToolbarIconButton` (flat, 28px at
17
- * `sm` / 32px at `md`, 20px glyph). Pass `viewStorageKey` to persist the view across reloads, and compose a
18
- * leading control — e.g. `ToolbarSortSelect` — through the `prepend` snippet.
19
+ * `sm` / 32px at `md`, 20px glyph), with an opt-in `card` button via `showCard`. Pass `viewStorageKey` to
20
+ * persist the view across reloads, and compose a leading control — e.g. `ToolbarSortSelect` — through the
21
+ * `prepend` snippet.
19
22
  *
20
23
  * ### CSS Custom Properties
21
24
  * | Property | Description | Default |
22
25
  * |---|---|---|
23
- * | `--sc-kit--toolbar-view-controls--gap` | Gap between the controls | `var(--sc-kit--space--3)` |
26
+ * | `--sc-kit--toolbar-view-controls--gap` | Gap between the controls | `var(--sc-kit--space--2)` |
24
27
  */
25
28
  declare const Cmp: import("svelte").Component<Props, {}, "">;
26
29
  type Cmp = ReturnType<typeof Cmp>;
@@ -1,3 +1,4 @@
1
1
  export declare class ToolbarSortSelectLocalization {
2
2
  get orderBy(): string;
3
+ get sorting(): string;
3
4
  }
@@ -1,9 +1,13 @@
1
1
  import { AppLocale } from '../../core/locale';
2
2
  const loc = {
3
- orderBy: { en: 'Order by', no: 'Sorter etter' }
3
+ orderBy: { en: 'Order by', no: 'Sorter etter' },
4
+ sorting: { en: 'Sorting', no: 'Sortering' }
4
5
  };
5
6
  export class ToolbarSortSelectLocalization {
6
7
  get orderBy() {
7
8
  return loc.orderBy[AppLocale.current];
8
9
  }
10
+ get sorting() {
11
+ return loc.sorting[AppLocale.current];
12
+ }
9
13
  }
@@ -2,4 +2,5 @@ export declare class ToolbarViewControlsLocalization {
2
2
  get label(): string;
3
3
  get listView(): string;
4
4
  get gridView(): string;
5
+ get cardView(): string;
5
6
  }
@@ -2,7 +2,8 @@ import { AppLocale } from '../../core/locale';
2
2
  const loc = {
3
3
  label: { en: 'View options', no: 'Visningsalternativer' },
4
4
  listView: { en: 'List view', no: 'Listevisning' },
5
- gridView: { en: 'Grid view', no: 'Rutenettvisning' }
5
+ gridView: { en: 'Grid view', no: 'Rutenettvisning' },
6
+ cardView: { en: 'Card view', no: 'Kortvisning' }
6
7
  };
7
8
  export class ToolbarViewControlsLocalization {
8
9
  get label() {
@@ -14,4 +15,7 @@ export class ToolbarViewControlsLocalization {
14
15
  get gridView() {
15
16
  return loc.gridView[AppLocale.current];
16
17
  }
18
+ get cardView() {
19
+ return loc.cardView[AppLocale.current];
20
+ }
17
21
  }
@@ -0,0 +1,111 @@
1
+ <script lang="ts">import { Tooltip } from '../tooltip';
2
+ import { ProgressBarLocalization } from './progress-bar-localization';
3
+ import { PROGRESS_BAR_TONES } from './types';
4
+ const { stage, stages, variant = 'bar', showLabel = true } = $props();
5
+ const localization = new ProgressBarLocalization();
6
+ const currentStage = $derived(stages[Math.max(0, Math.min(stage, stages.length - 1))]);
7
+ const currentLabel = $derived(currentStage?.label ?? '');
8
+ const tooltipLabel = $derived(!showLabel ? currentLabel : '');
9
+ const segmentColor = (s) => {
10
+ const value = s.color ?? 'gray';
11
+ return PROGRESS_BAR_TONES.includes(value) ? `var(--sc-kit--tone--${value}--fg)` : value;
12
+ };
13
+ </script>
14
+
15
+ <div class="progress-bar" class:progress-bar--pips={variant === 'pips'}>
16
+ {#if tooltipLabel}
17
+ <Tooltip text={tooltipLabel}>
18
+ {@render track()}
19
+ </Tooltip>
20
+ {:else}
21
+ {@render track()}
22
+ {/if}
23
+ {#if showLabel && currentLabel}
24
+ <span class="progress-bar__label">{currentLabel}</span>
25
+ {/if}
26
+ </div>
27
+
28
+ {#snippet track()}
29
+ <div
30
+ class="progress-bar__track"
31
+ role="progressbar"
32
+ aria-valuemin={1}
33
+ aria-valuemax={stages.length}
34
+ aria-valuenow={stage + 1}
35
+ aria-valuetext={currentLabel || undefined}
36
+ aria-label={localization.label}>
37
+ {#each stages as s, i (i)}
38
+ <span class="progress-bar__segment" class:progress-bar__segment--filled={i <= stage} style:--_--pb--segment-color={segmentColor(s)}></span>
39
+ {/each}
40
+ </div>
41
+ {/snippet}
42
+
43
+ <!--
44
+ @component
45
+ Multi-stage workflow progress indicator. Pass `stages` as an array of `{ color, label? }`
46
+ descriptors — the bar renders one segment per stage; segments `0..stage` (inclusive) are filled,
47
+ the rest use the empty-segment color. Each stage's `color` is either a named tone from the shared
48
+ palette (same schemes as `Badge`, e.g. `'green'`) or a raw CSS color / `var(--sc-kit--*)`. Useful
49
+ for content-lifecycle indicators (Ideas → Draft → Review → Scheduled → Published) in cards, table
50
+ cells, or post pages. `variant="pips"` renders compact fixed-size ticks (left-aligned) instead of
51
+ full-width segments — for dense table cells. `showLabel={false}` drops the inline current-stage
52
+ label (e.g. in a compact table cell) and surfaces it in a hover tooltip instead.
53
+
54
+ ### CSS Custom Properties
55
+ | Property | Description | Default |
56
+ |---|---|---|
57
+ | `--sc-kit--progress-bar--segment--height` | Segment height | `bar` 4px / `pips` 12px |
58
+ | `--sc-kit--progress-bar--segment--width` | Segment width | `bar` auto (stretches) / `pips` 6px |
59
+ | `--sc-kit--progress-bar--segment--gap` | Gap between segments | `bar` 2px / `pips` 4px |
60
+ | `--sc-kit--progress-bar--segment--border-radius` | Segment corner radius | `bar` 1px / `pips` 2px |
61
+ | `--sc-kit--progress-bar--segment--background--empty` | Empty segment color | `var(--sc-kit--color--bg--active)` |
62
+ | `--sc-kit--progress-bar--track--padding-block` | Vertical padding around the bar (enlarges the hover/click target) | `5px` |
63
+ -->
64
+
65
+ <style>.progress-bar {
66
+ --_pb--seg-height: var(--sc-kit--progress-bar--segment--height, var(--_pb--seg-height-default, 0.25rem));
67
+ --_pb--seg-gap: var(--sc-kit--progress-bar--segment--gap, var(--_pb--seg-gap-default, 0.125rem));
68
+ --_pb--seg-width: var(--sc-kit--progress-bar--segment--width, var(--_pb--seg-width-default, auto));
69
+ --_pb--seg-radius: var(--sc-kit--progress-bar--segment--border-radius, var(--_pb--seg-radius-default, 0.0625rem));
70
+ --_pb--seg-empty: var(--sc-kit--progress-bar--segment--background--empty, var(--sc-kit--color--bg--active));
71
+ --_pb--track-padding-block: var(--sc-kit--progress-bar--track--padding-block, 0.3125rem);
72
+ --_pb--seg-flex: 1;
73
+ --_pb--track-width: 100%;
74
+ display: flex;
75
+ flex-direction: column;
76
+ gap: 0.125rem;
77
+ width: 100%;
78
+ min-width: 0;
79
+ }
80
+ .progress-bar--pips {
81
+ --_pb--seg-height-default: 0.75rem;
82
+ --_pb--seg-gap-default: 0.25rem;
83
+ --_pb--seg-width-default: 0.375rem;
84
+ --_pb--seg-radius-default: 0.125rem;
85
+ --_pb--seg-flex: 0 0 auto;
86
+ --_pb--track-width: auto;
87
+ align-items: flex-start;
88
+ }
89
+ .progress-bar__track {
90
+ display: flex;
91
+ align-items: center;
92
+ gap: var(--_pb--seg-gap);
93
+ width: var(--_pb--track-width);
94
+ padding-block: var(--_pb--track-padding-block);
95
+ }
96
+ .progress-bar__segment {
97
+ --_pb--seg-color: var(--_--pb--segment-color);
98
+ flex: var(--_pb--seg-flex);
99
+ width: var(--_pb--seg-width);
100
+ height: var(--_pb--seg-height);
101
+ background: var(--_pb--seg-empty);
102
+ border-radius: var(--_pb--seg-radius);
103
+ }
104
+ .progress-bar__segment--filled {
105
+ background: var(--_pb--seg-color);
106
+ }
107
+ .progress-bar__label {
108
+ font-size: 0.625rem;
109
+ color: var(--sc-kit--color--text--secondary);
110
+ line-height: var(--sc-kit--leading--tight);
111
+ }</style>
@@ -0,0 +1,37 @@
1
+ import { type ProgressBarStage } from './types';
2
+ type Props = {
3
+ /** Current stage index, 0-based. Stages 0..stage (inclusive) are filled. */
4
+ stage: number;
5
+ /**
6
+ * Stage descriptors — at minimum `{ color }` per stage (consumer provides the CSS color).
7
+ * Length determines the total segment count.
8
+ */
9
+ stages: ProgressBarStage[];
10
+ /** Segment shape — `bar` = full-width stretched segments, `pips` = compact fixed-size ticks (e.g. a table cell). @default 'bar' */
11
+ variant?: 'bar' | 'pips';
12
+ /** Show the current stage's label below the bar. When `false`, the label surfaces in a tooltip on hover instead. @default true */
13
+ showLabel?: boolean;
14
+ };
15
+ /**
16
+ * Multi-stage workflow progress indicator. Pass `stages` as an array of `{ color, label? }`
17
+ * descriptors — the bar renders one segment per stage; segments `0..stage` (inclusive) are filled,
18
+ * the rest use the empty-segment color. Each stage's `color` is either a named tone from the shared
19
+ * palette (same schemes as `Badge`, e.g. `'green'`) or a raw CSS color / `var(--sc-kit--*)`. Useful
20
+ * for content-lifecycle indicators (Ideas → Draft → Review → Scheduled → Published) in cards, table
21
+ * cells, or post pages. `variant="pips"` renders compact fixed-size ticks (left-aligned) instead of
22
+ * full-width segments — for dense table cells. `showLabel={false}` drops the inline current-stage
23
+ * label (e.g. in a compact table cell) and surfaces it in a hover tooltip instead.
24
+ *
25
+ * ### CSS Custom Properties
26
+ * | Property | Description | Default |
27
+ * |---|---|---|
28
+ * | `--sc-kit--progress-bar--segment--height` | Segment height | `bar` 4px / `pips` 12px |
29
+ * | `--sc-kit--progress-bar--segment--width` | Segment width | `bar` auto (stretches) / `pips` 6px |
30
+ * | `--sc-kit--progress-bar--segment--gap` | Gap between segments | `bar` 2px / `pips` 4px |
31
+ * | `--sc-kit--progress-bar--segment--border-radius` | Segment corner radius | `bar` 1px / `pips` 2px |
32
+ * | `--sc-kit--progress-bar--segment--background--empty` | Empty segment color | `var(--sc-kit--color--bg--active)` |
33
+ * | `--sc-kit--progress-bar--track--padding-block` | Vertical padding around the bar (enlarges the hover/click target) | `5px` |
34
+ */
35
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
36
+ type Cmp = ReturnType<typeof Cmp>;
37
+ export default Cmp;
@@ -0,0 +1,2 @@
1
+ export { default as ProgressBar } from './cmp.progress-bar.svelte';
2
+ export type { ProgressBarStage, ProgressBarTone } from './types';
@@ -0,0 +1 @@
1
+ export { default as ProgressBar } from './cmp.progress-bar.svelte';
@@ -0,0 +1,3 @@
1
+ export declare class ProgressBarLocalization {
2
+ get label(): string;
3
+ }
@@ -0,0 +1,9 @@
1
+ import { AppLocale } from '../../core/locale';
2
+ const loc = {
3
+ label: { en: 'Progress', no: 'Fremdrift' }
4
+ };
5
+ export class ProgressBarLocalization {
6
+ get label() {
7
+ return loc.label[AppLocale.current];
8
+ }
9
+ }
@@ -0,0 +1,7 @@
1
+ export declare const PROGRESS_BAR_TONES: readonly ["gray", "blue", "green", "red", "orange", "teal"];
2
+ export type ProgressBarTone = (typeof PROGRESS_BAR_TONES)[number];
3
+ export type ProgressBarStage = {
4
+ /** A named tone from the shared palette (→ `--sc-kit--tone--<tone>--fg`) or any raw CSS color / `var(--sc-kit--*)`. @default 'gray' */
5
+ color?: ProgressBarTone | (string & {});
6
+ label?: string;
7
+ };
@@ -0,0 +1 @@
1
+ export const PROGRESS_BAR_TONES = ['gray', 'blue', 'green', 'red', 'orange', 'teal'];
@@ -6,7 +6,7 @@ const variant = $derived(column.variantFactory ? column.variantFactory(item) : '
6
6
 
7
7
  {#if getValueForColumn(column, item) !== null}
8
8
  <div class="table-badge-cell" class:table-badge-cell--centered={centered}>
9
- <Badge variant={variant} fullWidth={column.fullWidth}>{getValueForColumn(column, item)}</Badge>
9
+ <Badge variant={variant} shape={column.shape ?? 'pill'} fullWidth={column.fullWidth}>{getValueForColumn(column, item)}</Badge>
10
10
  </div>
11
11
  {/if}
12
12
 
@@ -5,7 +5,6 @@ import { default as TableBadgeCell } from './table-badge-cell.svelte';
5
5
  import { default as TableButtonCell } from './table-button-cell.svelte';
6
6
  import { default as TableByCell } from './table-by-cell.svelte';
7
7
  import { default as TableCheckboxCell } from './table-checkbox-cell.svelte';
8
- import { default as TableCustomCell } from './table-custom-cell.svelte';
9
8
  import { default as TableIconCell } from './table-icon-cell.svelte';
10
9
  import { default as TableImageCell } from './table-image-cell.svelte';
11
10
  import { default as TableMoveRowCell } from './table-move-row-cell.svelte';
@@ -52,8 +51,6 @@ const changeItemPosition = (target, positionChange) => {
52
51
  <TableByCell column={def} item={item} />
53
52
  {:else if def.type === 'checkbox'}
54
53
  <TableCheckboxCell item={item} selection={model.selection} />
55
- {:else if def.type === 'custom'}
56
- <TableCustomCell column={def} item={item} />
57
54
  {:else if def.type === 'icon'}
58
55
  <TableIconCell column={def} item={item} centered={column.centered} />
59
56
  {:else if def.type === 'image'}
@@ -21,6 +21,14 @@ const getValueForColumn = (column, item) => (column.valueFactory ? column.valueF
21
21
  </div>
22
22
  </ProportionalContainer>
23
23
  </div>
24
+ {:else if column.format === 'vertical-cover'}
25
+ <div class="table-image-cell__image table-image-cell__image--vertical-cover">
26
+ <Image src={getValueForColumn(column, item)} />
27
+ </div>
28
+ {:else if column.format === 'horizontal-cover'}
29
+ <div class="table-image-cell__image table-image-cell__image--horizontal-cover">
30
+ <Image src={getValueForColumn(column, item)} />
31
+ </div>
24
32
  {/if}
25
33
  </div>
26
34
 
@@ -35,6 +43,7 @@ const getValueForColumn = (column, item) => (column.valueFactory ? column.valueF
35
43
  justify-content: center;
36
44
  }
37
45
  .table-image-cell__image {
46
+ --_table-image-cell--cover-height: var(--_table-image-cell--image--size, 2.5em);
38
47
  display: flex;
39
48
  justify-content: center;
40
49
  align-items: center;
@@ -51,10 +60,18 @@ const getValueForColumn = (column, item) => (column.valueFactory ? column.valueF
51
60
  }
52
61
  .table-image-cell__image--contain {
53
62
  --sc-kit--image--object-fit: contain;
54
- height: 2.5em;
63
+ height: var(--_table-image-cell--cover-height);
55
64
  }
56
65
  .table-image-cell__image--cover {
57
- height: 2.5em;
66
+ height: var(--_table-image-cell--cover-height);
67
+ }
68
+ .table-image-cell__image--vertical-cover {
69
+ height: var(--_table-image-cell--cover-height);
70
+ width: calc(var(--_table-image-cell--cover-height) * 9 / 16);
71
+ }
72
+ .table-image-cell__image--horizontal-cover {
73
+ height: var(--_table-image-cell--cover-height);
74
+ width: calc(var(--_table-image-cell--cover-height) * 16 / 9);
58
75
  }
59
76
  .table-image-cell__cover-image-placer {
60
77
  width: 100%;
@@ -1,15 +1,14 @@
1
1
  import type { Repository } from '../../core/repository';
2
- import type { BadgeVariant } from '../badge';
2
+ import type { BadgeShape, BadgeVariant } from '../badge';
3
3
  import type { ButtonSize, ButtonVariant } from '../button';
4
- import { DynamicComponentModel } from '../dynamic-component';
5
4
  import type { IconProp } from '../icon';
6
5
  import type { Snippet } from 'svelte';
7
6
  export type WithId = {
8
7
  id: string;
9
8
  };
10
9
  export type IAnyTableColumn<T> = IOneOfTableColumn<T>;
11
- export type IOneOfTableColumn<T> = ITableBadgeColumn<T> | ITableButtonColumn<T> | ITableByColumn<T> | ITableCheckboxColumn | ITableCustomColumn<T> | ITableIconColumn<T> | ITableImageColumn<T> | ITableMoveRowColumn | ITableSnippetColumn<T> | ITableTextColumn<T>;
12
- export type TableColumnType = 'actions' | 'badge' | 'button' | 'by' | 'checkbox' | 'custom' | 'icon' | 'image' | 'move-row' | 'snippet' | 'text';
10
+ export type IOneOfTableColumn<T> = ITableBadgeColumn<T> | ITableButtonColumn<T> | ITableByColumn<T> | ITableCheckboxColumn | ITableIconColumn<T> | ITableImageColumn<T> | ITableMoveRowColumn | ITableSnippetColumn<T> | ITableTextColumn<T>;
11
+ export type TableColumnType = 'actions' | 'badge' | 'button' | 'by' | 'checkbox' | 'icon' | 'image' | 'move-row' | 'snippet' | 'text';
13
12
  interface ITableColumnBase {
14
13
  type: TableColumnType;
15
14
  fixedCssWidth?: string;
@@ -37,6 +36,8 @@ export interface ITableBadgeColumn<T> extends ITableColumn<T> {
37
36
  valueFactory?: ((item: T) => string) | null;
38
37
  /** Stretch the badge to fill the column width. @default false */
39
38
  fullWidth?: boolean;
39
+ /** Corner style of the rendered badge. @default 'pill' */
40
+ shape?: BadgeShape;
40
41
  }
41
42
  export interface ITableByColumn<T> extends ITableColumn<T> {
42
43
  type: 'by';
@@ -68,10 +69,6 @@ export interface ITableButtonColumn<T> extends ITableColumn<T> {
68
69
  export interface ITableCheckboxColumn extends ITableColumnBase {
69
70
  type: 'checkbox';
70
71
  }
71
- export interface ITableCustomColumn<T> extends ITableColumn<T> {
72
- type: 'custom';
73
- componentFactory: (item: T) => DynamicComponentModel;
74
- }
75
72
  export interface ITableIconColumn<T> extends ITableColumn<T> {
76
73
  type: 'icon';
77
74
  iconFactory?: ((item: T) => IconProp) | null;
@@ -101,7 +98,7 @@ export interface ITableTextColumn<T> extends ITableColumn<T> {
101
98
  valueFactory?: ((item: T) => string) | null;
102
99
  }
103
100
  export type TableTextColumnFormat = 'text' | 'html' | 'money' | 'date' | 'date-time';
104
- export type TableImageColumnFormat = 'circle' | 'square-contain' | 'square-cover';
101
+ export type TableImageColumnFormat = 'circle' | 'square-contain' | 'square-cover' | 'vertical-cover' | 'horizontal-cover';
105
102
  export type TableItemAction<T> = {
106
103
  title: string;
107
104
  icon?: IconProp;
@@ -1 +1 @@
1
- import { DynamicComponentModel } from '../dynamic-component';
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",
@@ -335,6 +335,10 @@
335
335
  "types": "./dist/ui/progress/index.d.ts",
336
336
  "svelte": "./dist/ui/progress/index.js"
337
337
  },
338
+ "./ui/progress-bar": {
339
+ "types": "./dist/ui/progress-bar/index.d.ts",
340
+ "svelte": "./dist/ui/progress-bar/index.js"
341
+ },
338
342
  "./ui/proportional-container": {
339
343
  "types": "./dist/ui/proportional-container/index.d.ts",
340
344
  "svelte": "./dist/ui/proportional-container/index.js"
@@ -1,5 +0,0 @@
1
- <script lang="ts" generics="T extends {id: string}">import { DynamicComponent } from '../../dynamic-component';
2
- let { item, column } = $props();
3
- </script>
4
-
5
- <DynamicComponent model={column.componentFactory(item)} />
@@ -1,38 +0,0 @@
1
- import type { ITableCustomColumn } from '../types';
2
- declare function $$render<T extends {
3
- id: string;
4
- }>(): {
5
- props: {
6
- item: T;
7
- column: ITableCustomColumn<T>;
8
- };
9
- exports: {};
10
- bindings: "";
11
- slots: {};
12
- events: {};
13
- };
14
- declare class __sveltets_Render<T extends {
15
- id: string;
16
- }> {
17
- props(): ReturnType<typeof $$render<T>>['props'];
18
- events(): ReturnType<typeof $$render<T>>['events'];
19
- slots(): ReturnType<typeof $$render<T>>['slots'];
20
- bindings(): "";
21
- exports(): {};
22
- }
23
- interface $$IsomorphicComponent {
24
- new <T extends {
25
- id: string;
26
- }>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
27
- $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
28
- } & ReturnType<__sveltets_Render<T>['exports']>;
29
- <T extends {
30
- id: string;
31
- }>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
32
- z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
33
- }
34
- declare const TableCustomCell: $$IsomorphicComponent;
35
- type TableCustomCell<T extends {
36
- id: string;
37
- }> = InstanceType<typeof TableCustomCell<T>>;
38
- export default TableCustomCell;