@dorsk/tsumikit 0.18.8 → 0.19.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.
|
@@ -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;
|
|
@@ -367,13 +367,18 @@
|
|
|
367
367
|
outline: 2px solid var(--accent);
|
|
368
368
|
outline-offset: -2px;
|
|
369
369
|
}
|
|
370
|
+
/* The handle overhangs the panel edge by 6px, but never past the host
|
|
371
|
+
container: when the panel fills it (edge at the window border), the
|
|
372
|
+
overhang would land off-screen and be ungrabbable, so the shift clamps to
|
|
373
|
+
the leftover space and the lost overhang is added back inside instead. */
|
|
370
374
|
.resize-handle {
|
|
375
|
+
--handle-shift: max(-6px, calc(var(--panel-current-width) - 100cqw));
|
|
371
376
|
position: absolute;
|
|
372
377
|
top: 0;
|
|
373
|
-
right: -
|
|
378
|
+
right: var(--handle-shift);
|
|
374
379
|
bottom: 0;
|
|
375
380
|
z-index: 2;
|
|
376
|
-
width:
|
|
381
|
+
width: calc(18px + var(--handle-shift));
|
|
377
382
|
padding: 0;
|
|
378
383
|
background: transparent;
|
|
379
384
|
border: 0;
|
|
@@ -382,7 +387,7 @@
|
|
|
382
387
|
}
|
|
383
388
|
.right .resize-handle {
|
|
384
389
|
right: auto;
|
|
385
|
-
left: -
|
|
390
|
+
left: var(--handle-shift);
|
|
386
391
|
}
|
|
387
392
|
.resize-handle::after {
|
|
388
393
|
content: '';
|
|
@@ -428,6 +433,11 @@
|
|
|
428
433
|
.collapsed .panel {
|
|
429
434
|
box-shadow: none;
|
|
430
435
|
}
|
|
436
|
+
/* The 85cqw cap guarantees free space beside the panel, but the clamp
|
|
437
|
+
above reads --panel-current-width, which the cap may exceed. */
|
|
438
|
+
.resize-handle {
|
|
439
|
+
--handle-shift: -6px;
|
|
440
|
+
}
|
|
431
441
|
.main {
|
|
432
442
|
height: 100%;
|
|
433
443
|
}
|
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