@signal9/era-ui 30.4.0 → 30.5.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.
- package/CHANGELOG.md +6 -0
- package/dist/ui/meter/meter.svelte +68 -22
- package/dist/ui/meter/meter.svelte.d.ts +21 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [30.5.0](https://github.com/sig-nine/era-ui/compare/v30.4.0...v30.5.0) (2026-08-16)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **meter:** start and end snippets caption what the range means ([1a6bf54](https://github.com/sig-nine/era-ui/commit/1a6bf544b5b3992649f66c5e9a05f24057f495cd))
|
|
6
|
+
|
|
1
7
|
## [30.4.0](https://github.com/sig-nine/era-ui/compare/v30.3.0...v30.4.0) (2026-08-16)
|
|
2
8
|
|
|
3
9
|
### Features
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
</script>
|
|
36
36
|
|
|
37
37
|
<script lang="ts">
|
|
38
|
+
import type { Snippet } from 'svelte';
|
|
38
39
|
import { Meter } from 'bits-ui';
|
|
39
40
|
import { cn } from '../../utils/index.js';
|
|
40
41
|
|
|
@@ -44,6 +45,8 @@
|
|
|
44
45
|
min = 0,
|
|
45
46
|
max = 100,
|
|
46
47
|
tone = 'default',
|
|
48
|
+
start,
|
|
49
|
+
end,
|
|
47
50
|
class: className,
|
|
48
51
|
...restProps
|
|
49
52
|
}: Meter.RootProps & {
|
|
@@ -57,30 +60,73 @@
|
|
|
57
60
|
* `aria-label` / a visible label, never rely on the hue alone.
|
|
58
61
|
*/
|
|
59
62
|
tone?: 'default' | 'accent' | 'destructive' | 'success' | 'warning' | 'info';
|
|
63
|
+
/**
|
|
64
|
+
* Captions under the two ends of the bar — what the range MEANS.
|
|
65
|
+
*
|
|
66
|
+
* A meter states a proportion and leaves the reader to work out what of.
|
|
67
|
+
* "0m used" on the left and "50h before approval" on the right is not
|
|
68
|
+
* decoration, it is the reading; every consumer of a bare meter ends up
|
|
69
|
+
* hand-rolling the same flex row underneath it, which is where this came
|
|
70
|
+
* from. `start` is left, `end` is right, either may stand alone.
|
|
71
|
+
*
|
|
72
|
+
* NOT ANNOUNCED. They are captions, so a screen reader gets the meter's
|
|
73
|
+
* value and its own `aria-label`, not these. If the range needs saying
|
|
74
|
+
* out loud, say it in the label too — the same rule `tone` carries.
|
|
75
|
+
*
|
|
76
|
+
* THE DOM IS UNCHANGED WITHOUT THEM. With neither snippet this renders
|
|
77
|
+
* exactly the element it always did, so `class` still lands on the track
|
|
78
|
+
* and the geometry audits still walk the same box. Passing one wraps the
|
|
79
|
+
* track in a column, and `class` still lands on the track.
|
|
80
|
+
*/
|
|
81
|
+
start?: Snippet;
|
|
82
|
+
end?: Snippet;
|
|
60
83
|
} = $props();
|
|
61
84
|
|
|
62
85
|
let percentage = $derived(((value - min) / (max - min)) * 100);
|
|
63
86
|
</script>
|
|
64
87
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
{#snippet track()}
|
|
89
|
+
<Meter.Root
|
|
90
|
+
bind:ref
|
|
91
|
+
{value}
|
|
92
|
+
{min}
|
|
93
|
+
{max}
|
|
94
|
+
data-tone={tone}
|
|
95
|
+
class={cn(
|
|
96
|
+
// bg-field, not bg-elevated: the track is recessed (era-track-well), so it
|
|
97
|
+
// wears the recessed tier. See Checkbox for the full version of this note.
|
|
98
|
+
// era-track-well, not shadow-well: the fill below covers the whole box,
|
|
99
|
+
// and an inset shadow paints under its own descendants — so the plain
|
|
100
|
+
// well survived only on the empty side of the value.
|
|
101
|
+
'era-track-well h-(--era-sp) w-full overflow-hidden rounded-control bg-field',
|
|
102
|
+
className
|
|
103
|
+
)}
|
|
104
|
+
{...restProps}
|
|
105
|
+
>
|
|
106
|
+
<div
|
|
107
|
+
class={meterFillVariants({ tone })}
|
|
108
|
+
style="transform: translateX(-{100 - percentage}%)"
|
|
109
|
+
></div>
|
|
110
|
+
</Meter.Root>
|
|
111
|
+
{/snippet}
|
|
112
|
+
|
|
113
|
+
<!--
|
|
114
|
+
The wrapper exists ONLY when a caption does. Rendering it always would change
|
|
115
|
+
the element every existing consumer measures and styles — the same opt-in the
|
|
116
|
+
Button and Chip label boxes are built on, for the same reason.
|
|
117
|
+
|
|
118
|
+
`justify-between` rather than a grid: with one caption it pins to its own end,
|
|
119
|
+
which is what a lone "0 used" or a lone "quota" should do. min-w-0 + truncate
|
|
120
|
+
because a caption is prose and the bar's width is not negotiable.
|
|
121
|
+
-->
|
|
122
|
+
{#if start || end}
|
|
123
|
+
<div class="flex flex-col gap-gutter">
|
|
124
|
+
{@render track()}
|
|
125
|
+
<div class="flex items-baseline justify-between gap-gutter text-body text-muted">
|
|
126
|
+
<span class="min-w-0 truncate">{@render start?.()}</span>
|
|
127
|
+
<span class="min-w-0 truncate text-right">{@render end?.()}</span>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
{:else}
|
|
131
|
+
{@render track()}
|
|
132
|
+
{/if}
|
|
@@ -26,6 +26,7 @@ export declare const meterFillVariants: import("tailwind-variants").TVReturnType
|
|
|
26
26
|
info: "bg-info";
|
|
27
27
|
};
|
|
28
28
|
}, undefined>>;
|
|
29
|
+
import type { Snippet } from 'svelte';
|
|
29
30
|
import { Meter } from 'bits-ui';
|
|
30
31
|
type $$ComponentProps = Meter.RootProps & {
|
|
31
32
|
/**
|
|
@@ -38,6 +39,26 @@ type $$ComponentProps = Meter.RootProps & {
|
|
|
38
39
|
* `aria-label` / a visible label, never rely on the hue alone.
|
|
39
40
|
*/
|
|
40
41
|
tone?: 'default' | 'accent' | 'destructive' | 'success' | 'warning' | 'info';
|
|
42
|
+
/**
|
|
43
|
+
* Captions under the two ends of the bar — what the range MEANS.
|
|
44
|
+
*
|
|
45
|
+
* A meter states a proportion and leaves the reader to work out what of.
|
|
46
|
+
* "0m used" on the left and "50h before approval" on the right is not
|
|
47
|
+
* decoration, it is the reading; every consumer of a bare meter ends up
|
|
48
|
+
* hand-rolling the same flex row underneath it, which is where this came
|
|
49
|
+
* from. `start` is left, `end` is right, either may stand alone.
|
|
50
|
+
*
|
|
51
|
+
* NOT ANNOUNCED. They are captions, so a screen reader gets the meter's
|
|
52
|
+
* value and its own `aria-label`, not these. If the range needs saying
|
|
53
|
+
* out loud, say it in the label too — the same rule `tone` carries.
|
|
54
|
+
*
|
|
55
|
+
* THE DOM IS UNCHANGED WITHOUT THEM. With neither snippet this renders
|
|
56
|
+
* exactly the element it always did, so `class` still lands on the track
|
|
57
|
+
* and the geometry audits still walk the same box. Passing one wraps the
|
|
58
|
+
* track in a column, and `class` still lands on the track.
|
|
59
|
+
*/
|
|
60
|
+
start?: Snippet;
|
|
61
|
+
end?: Snippet;
|
|
41
62
|
};
|
|
42
63
|
declare const Meter: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
43
64
|
type Meter = ReturnType<typeof Meter>;
|