@dorsk/tsumikit 0.18.9 → 0.19.1

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.
@@ -0,0 +1,102 @@
1
+ <script lang="ts" module>
2
+ // One bar split into proportional segments (e.g. one per season of a series),
3
+ // each filled value/max with its own tone. Token-styled, thin separators.
4
+ export type ProgressSegment = {
5
+ value: number;
6
+ max: number;
7
+ // Fill colour per segment. `muted` renders a faint fill for empty parts.
8
+ tone?: 'accent' | 'success' | 'warn' | 'danger' | 'muted';
9
+ // Native tooltip / accessible name for the segment.
10
+ label?: string;
11
+ };
12
+ </script>
13
+
14
+ <script lang="ts">
15
+ let {
16
+ segments,
17
+ label,
18
+ size = 'md',
19
+ class: klass = ''
20
+ }: {
21
+ segments: ProgressSegment[];
22
+ label?: string;
23
+ // Track height. `sm` is a thin ~5px track for inline rows.
24
+ size?: 'sm' | 'md';
25
+ class?: string;
26
+ } = $props();
27
+
28
+ const totalMax = $derived(segments.reduce((s, seg) => s + Math.max(0, seg.max), 0));
29
+ const totalValue = $derived(
30
+ segments.reduce((s, seg) => s + Math.max(0, Math.min(seg.value, seg.max)), 0)
31
+ );
32
+
33
+ function pct(seg: ProgressSegment): number {
34
+ if (seg.max <= 0) return 0;
35
+ return Math.max(0, Math.min(100, (seg.value / seg.max) * 100));
36
+ }
37
+ </script>
38
+
39
+ <div
40
+ data-tsu="SegmentedProgress"
41
+ class="segmented-progress size-{size} {klass}"
42
+ role="progressbar"
43
+ aria-label={label}
44
+ aria-valuemin={0}
45
+ aria-valuemax={totalMax}
46
+ aria-valuenow={totalValue}
47
+ >
48
+ {#each segments as seg, i (i)}
49
+ <div
50
+ class="segment tone-{seg.tone ?? 'accent'}"
51
+ style="flex-grow: {Math.max(seg.max, 1)}"
52
+ title={seg.label}
53
+ >
54
+ <div class="bar" style="width: {pct(seg)}%"></div>
55
+ </div>
56
+ {/each}
57
+ </div>
58
+
59
+ <style>
60
+ .segmented-progress {
61
+ display: flex;
62
+ width: 100%;
63
+ height: 0.5rem;
64
+ gap: 2px;
65
+ border-radius: var(--r-pill);
66
+ }
67
+ .segmented-progress.size-sm {
68
+ height: 0.3125rem;
69
+ }
70
+ .segment {
71
+ flex: 0 1 0%;
72
+ min-width: 3px;
73
+ height: 100%;
74
+ background: var(--bg-elevated-2);
75
+ overflow: hidden;
76
+ }
77
+ .segment:first-child {
78
+ border-top-left-radius: var(--r-pill);
79
+ border-bottom-left-radius: var(--r-pill);
80
+ }
81
+ .segment:last-child {
82
+ border-top-right-radius: var(--r-pill);
83
+ border-bottom-right-radius: var(--r-pill);
84
+ }
85
+ .bar {
86
+ height: 100%;
87
+ background: var(--fill, var(--accent));
88
+ transition: width 0.2s var(--ease);
89
+ }
90
+ .tone-success {
91
+ --fill: var(--ok);
92
+ }
93
+ .tone-warn {
94
+ --fill: var(--warn);
95
+ }
96
+ .tone-danger {
97
+ --fill: var(--danger);
98
+ }
99
+ .tone-muted {
100
+ --fill: var(--text-faint);
101
+ }
102
+ </style>
@@ -0,0 +1,15 @@
1
+ export type ProgressSegment = {
2
+ value: number;
3
+ max: number;
4
+ tone?: 'accent' | 'success' | 'warn' | 'danger' | 'muted';
5
+ label?: string;
6
+ };
7
+ type $$ComponentProps = {
8
+ segments: ProgressSegment[];
9
+ label?: string;
10
+ size?: 'sm' | 'md';
11
+ class?: string;
12
+ };
13
+ declare const SegmentedProgress: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type SegmentedProgress = ReturnType<typeof SegmentedProgress>;
15
+ export default SegmentedProgress;
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export { default as Icon } from './components/atoms/Icon.svelte';
11
11
  export { default as Input } from './components/atoms/Input.svelte';
12
12
  export { default as Link } from './components/atoms/Link.svelte';
13
13
  export { default as Progress } from './components/atoms/Progress.svelte';
14
+ export { default as SegmentedProgress, type ProgressSegment, } from './components/atoms/SegmentedProgress.svelte';
14
15
  export { default as Select } from './components/atoms/Select.svelte';
15
16
  export { default as Slider } from './components/atoms/Slider.svelte';
16
17
  export { default as Spinner } from './components/atoms/Spinner.svelte';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export { default as Icon } from './components/atoms/Icon.svelte';
16
16
  export { default as Input } from './components/atoms/Input.svelte';
17
17
  export { default as Link } from './components/atoms/Link.svelte';
18
18
  export { default as Progress } from './components/atoms/Progress.svelte';
19
+ export { default as SegmentedProgress, } from './components/atoms/SegmentedProgress.svelte';
19
20
  export { default as Select } from './components/atoms/Select.svelte';
20
21
  export { default as Slider } from './components/atoms/Slider.svelte';
21
22
  export { default as Spinner } from './components/atoms/Spinner.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dorsk/tsumikit",
3
- "version": "0.18.9",
3
+ "version": "0.19.1",
4
4
  "description": "Minimal, dependency-free Svelte 5 + pure-CSS UI kit. Token-driven atoms, molecules & layouts with theming out of the box.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "dev": "vite dev",
46
46
  "build": "vite build",
47
47
  "preview": "vite preview",
48
- "test": "node --test tests/*.test.js",
48
+ "test": "node --import ./tests/register.mjs --test tests/*.test.js",
49
49
  "prepare": "svelte-kit sync && (lefthook install || true)",
50
50
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
51
51
  "lint": "biome check .",