@signal9/era-ui 20.0.0 → 22.0.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,3 +1,38 @@
1
+ <script lang="ts" module>
2
+ import { tv } from '../../utils/index.js';
3
+
4
+ /*
5
+ * A meter reports a LEVEL inside a known range — disk usage, a quota, a
6
+ * score — so "how is this level doing" is the one thing it exists to say,
7
+ * and it was the one thing it could not say. Consumers were reaching past
8
+ * the component for it (`class="[&>div]:bg-destructive"`), which reaches
9
+ * through a private child and breaks the moment the fill's markup changes.
10
+ *
11
+ * The tones are the library's five, spelled exactly as Badge and Button
12
+ * spell them, so a meter beside a badge that both read "warning" render the
13
+ * same hue. `default` stays bg-fg: a meter with nothing to report should not
14
+ * look like it is reporting something.
15
+ *
16
+ * The tone is on the FILL, not the track. The track is the well the value
17
+ * sits in — it belongs to the container, not to the reading — so tinting it
18
+ * would say "this whole control is in a warning state" rather than "the
19
+ * value has reached the warning band".
20
+ */
21
+ export const meterFillVariants = tv({
22
+ base: 'h-full w-full transition-transform duration-base ease-base',
23
+ variants: {
24
+ tone: {
25
+ default: 'bg-fg',
26
+ accent: 'bg-primary',
27
+ destructive: 'bg-destructive',
28
+ success: 'bg-success',
29
+ warning: 'bg-warning'
30
+ }
31
+ },
32
+ defaultVariants: { tone: 'default' }
33
+ });
34
+ </script>
35
+
1
36
  <script lang="ts">
2
37
  import { Meter } from 'bits-ui';
3
38
  import { cn } from '../../utils/index.js';
@@ -7,9 +42,21 @@
7
42
  value = 0,
8
43
  min = 0,
9
44
  max = 100,
45
+ tone = 'default',
10
46
  class: className,
11
47
  ...restProps
12
- }: Meter.RootProps = $props();
48
+ }: Meter.RootProps & {
49
+ /**
50
+ * The band this reading falls in. Tone is the fill's colour only — the
51
+ * track stays neutral, because the well belongs to the control and the
52
+ * fill belongs to the value.
53
+ *
54
+ * Tone carries no semantics on its own: a meter in the destructive band
55
+ * still needs an accessible label saying what has run out. Pair it with
56
+ * `aria-label` / a visible label, never rely on the hue alone.
57
+ */
58
+ tone?: 'default' | 'accent' | 'destructive' | 'success' | 'warning';
59
+ } = $props();
13
60
 
14
61
  let percentage = $derived(((value - min) / (max - min)) * 100);
15
62
  </script>
@@ -19,6 +66,7 @@
19
66
  {value}
20
67
  {min}
21
68
  {max}
69
+ data-tone={tone}
22
70
  class={cn(
23
71
  'h-(--era-sp) w-full overflow-hidden rounded-control bg-elevated shadow-well',
24
72
  className
@@ -26,7 +74,7 @@
26
74
  {...restProps}
27
75
  >
28
76
  <div
29
- class="h-full w-full bg-fg transition-transform duration-base ease-base"
77
+ class={meterFillVariants({ tone })}
30
78
  style="transform: translateX(-{100 - percentage}%)"
31
79
  ></div>
32
80
  </Meter.Root>
@@ -1,4 +1,41 @@
1
+ export declare const meterFillVariants: import("tailwind-variants").TVReturnType<{
2
+ tone: {
3
+ default: "bg-fg";
4
+ accent: "bg-primary";
5
+ destructive: "bg-destructive";
6
+ success: "bg-success";
7
+ warning: "bg-warning";
8
+ };
9
+ }, undefined, "h-full w-full transition-transform duration-base ease-base", {
10
+ tone: {
11
+ default: "bg-fg";
12
+ accent: "bg-primary";
13
+ destructive: "bg-destructive";
14
+ success: "bg-success";
15
+ warning: "bg-warning";
16
+ };
17
+ }, undefined, import("tailwind-variants").TVReturnTypeLike<{
18
+ tone: {
19
+ default: "bg-fg";
20
+ accent: "bg-primary";
21
+ destructive: "bg-destructive";
22
+ success: "bg-success";
23
+ warning: "bg-warning";
24
+ };
25
+ }, undefined>>;
1
26
  import { Meter } from 'bits-ui';
2
- declare const Meter: import("svelte").Component<Meter.RootProps, {}, "ref">;
27
+ type $$ComponentProps = Meter.RootProps & {
28
+ /**
29
+ * The band this reading falls in. Tone is the fill's colour only — the
30
+ * track stays neutral, because the well belongs to the control and the
31
+ * fill belongs to the value.
32
+ *
33
+ * Tone carries no semantics on its own: a meter in the destructive band
34
+ * still needs an accessible label saying what has run out. Pair it with
35
+ * `aria-label` / a visible label, never rely on the hue alone.
36
+ */
37
+ tone?: 'default' | 'accent' | 'destructive' | 'success' | 'warning';
38
+ };
39
+ declare const Meter: import("svelte").Component<$$ComponentProps, {}, "ref">;
3
40
  type Meter = ReturnType<typeof Meter>;
4
41
  export default Meter;
@@ -6,8 +6,17 @@
6
6
  let { ref = $bindable(null), class: className, ...restProps }: TimeField.InputProps = $props();
7
7
  </script>
8
8
 
9
+ <!-- A TEXT FIELD'S SIDE PADDING IS DELIBERATELY NOT ITS CONCENTRIC INSET.
10
+ --era-field-px is the room where typed text STARTS — purpose-named in
11
+ density.css and floored at 0.5rem because the derived 6.8px read cramped at
12
+ dense — while the segment boxes inside are chip-tier and centre 1px from the
13
+ top. So this row is 8px at the sides against 1px above and below, on
14
+ purpose, and it says so rather than being quietly skipped by
15
+ layout/wall-is-isotropic's heuristics: a claim a reviewer can check beats a
16
+ silence. -->
9
17
  <TimeField.Input
10
18
  bind:ref
19
+ data-era-anisotropic
11
20
  data-input-field
12
21
  class={cn(
13
22
  inputVariants(),
@@ -10,8 +10,17 @@
10
10
  }: TimeRangeField.InputProps = $props();
11
11
  </script>
12
12
 
13
+ <!-- A TEXT FIELD'S SIDE PADDING IS DELIBERATELY NOT ITS CONCENTRIC INSET.
14
+ --era-field-px is the room where typed text STARTS — purpose-named in
15
+ density.css and floored at 0.5rem because the derived 6.8px read cramped at
16
+ dense — while the segment boxes inside are chip-tier and centre 1px from the
17
+ top. So this row is 8px at the sides against 1px above and below, on
18
+ purpose, and it says so rather than being quietly skipped by
19
+ layout/wall-is-isotropic's heuristics: a claim a reviewer can check beats a
20
+ silence. -->
13
21
  <TimeRangeField.Input
14
22
  bind:ref
23
+ data-era-anisotropic
15
24
  data-input-field
16
25
  class={cn(
17
26
  inputVariants(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signal9/era-ui",
3
- "version": "20.0.0",
3
+ "version": "22.0.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev --host",
6
6
  "build": "vite build && npm run prepack",
@@ -25,9 +25,12 @@
25
25
  "check:classes": "node --experimental-strip-types scripts/check-classes.ts",
26
26
  "check:twmerge": "node --experimental-strip-types scripts/check-twmerge.ts",
27
27
  "build:llm-docs": "node --experimental-strip-types scripts/build-llm-docs.ts",
28
- "prebuild": "npm run check:surfaces && npm run check:tokens && npm run check:routes && npm run check:canonical && npm run check:layers && npm run check:themes && npm run check:classes && npm run check:twmerge && npm run build:llm-docs",
29
- "validate": "npm run check && npm run lint && npm run format:check && npm run check:surfaces && npm run check:tokens && npm run check:routes && npm run check:canonical && npm run check:layers && npm run check:themes && npm run check:classes && npm run check:twmerge",
30
- "test": "npm run test:visual"
28
+ "prebuild": "npm run check:surfaces && npm run check:tokens && npm run check:routes && npm run check:canonical && npm run check:layers && npm run check:themes && npm run check:classes && npm run check:twmerge && npm run check:doc-tokens && npm run check:audit-controls && npm run check:specimen-coverage && npm run build:llm-docs",
29
+ "validate": "npm run check && npm run lint && npm run format:check && npm run check:surfaces && npm run check:tokens && npm run check:routes && npm run check:canonical && npm run check:layers && npm run check:themes && npm run check:classes && npm run check:twmerge && npm run check:doc-tokens && npm run check:audit-controls && npm run check:specimen-coverage",
30
+ "test": "npm run test:visual",
31
+ "check:doc-tokens": "node --experimental-strip-types scripts/check-doc-tokens.ts",
32
+ "check:audit-controls": "node --experimental-strip-types scripts/check-audit-controls.ts",
33
+ "check:specimen-coverage": "node --experimental-strip-types scripts/check-specimen-coverage.ts"
31
34
  },
32
35
  "files": [
33
36
  "dist",
package/skill/SKILL.md CHANGED
@@ -64,13 +64,13 @@ Named for the ROLE each rung plays, never for its size — a scale whose names
64
64
  can invert is a scale nobody reads correctly (this library once shipped an
65
65
  `xxs` that was bigger than its `xs`).
66
66
 
67
- | Tier | Height | Square | Radius | Use for |
68
- | --------- | ----------- | ------------- | ---------------- | ------------------------------------------- |
69
- | `icon` | `h-icon` | `size-icon` | `rounded-icon` | a lucide glyph, switch thumbs |
70
- | `pill` | `h-pill` | `size-pill` | `rounded-pill` | a badge/chip nested INSIDE a control |
71
- | `chip` | `h-chip` | `size-chip` | `rounded-chip` | standalone pills, switch tracks, KV |
72
- | `control` | `h-control` | `size-control`| `rounded-control`| buttons, inputs, selects, triggers |
73
- | `bar` | `h-bar` | `size-bar` | `rounded-bar` | bars, containers, dialog headers |
67
+ | Tier | Height | Square | Radius | Use for |
68
+ | --------- | ----------- | -------------- | ----------------- | ------------------------------------ |
69
+ | `icon` | `h-icon` | `size-icon` | `rounded-icon` | a lucide glyph, switch thumbs |
70
+ | `pill` | `h-pill` | `size-pill` | `rounded-pill` | a badge/chip nested INSIDE a control |
71
+ | `chip` | `h-chip` | `size-chip` | `rounded-chip` | standalone pills, switch tracks, KV |
72
+ | `control` | `h-control` | `size-control` | `rounded-control` | buttons, inputs, selects, triggers |
73
+ | `bar` | `h-bar` | `size-bar` | `rounded-bar` | bars, containers, dialog headers |
74
74
 
75
75
  `min-h-*`, `min-w-*` and `w-*` exist across the same rungs. There is no escape
76
76
  hatch here any more: `min-w-control` is a real class, because role names collide
@@ -90,8 +90,11 @@ corners axis.
90
90
  give EVERY element the radius of its OWN height tier, center children with
91
91
  the matching concentric inset, and nested corners share a center of
92
92
  curvature automatically. The concentric insets are advanced enough to stay
93
- token-form: `--era-xs-inset-sm` (xs inside sm, = sp/2), `--era-xxs-inset-md`,
94
- `--era-xs-inset-md`, `--era-xs-inset-lg`, `--era-sm-inset-lg`.
93
+ token-form, and each is named for the pair it centres:
94
+ `--era-icon-inset-chip` (an icon inside a chip, = sp/2),
95
+ `--era-icon-inset-pill`, `--era-pill-inset-control`, `--era-pill-inset-chip`,
96
+ `--era-icon-inset-control`, `--era-icon-inset-bar`, `--era-chip-inset-control`,
97
+ `--era-chip-inset-bar`.
95
98
 
96
99
  **The trap**: a container's radius follows its corner REGION's tier, never its
97
100
  overall bulk. A large panel whose corners are formed by a chip-tier handle bar