@signal9/era-ui 26.1.1 → 28.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/docs/consumer-import.d.ts +28 -0
  3. package/dist/docs/consumer-import.js +28 -0
  4. package/dist/era-ui.css +1 -1
  5. package/dist/generated-docs/accordion.md +1 -1
  6. package/dist/generated-docs/alert-dialog.md +11 -1
  7. package/dist/generated-docs/combobox.md +1 -1
  8. package/dist/generated-docs/context-menu.md +13 -3
  9. package/dist/generated-docs/date-picker.md +1 -1
  10. package/dist/generated-docs/date-range-picker.md +1 -1
  11. package/dist/generated-docs/dialog.md +11 -1
  12. package/dist/generated-docs/dropdown-menu.md +14 -4
  13. package/dist/generated-docs/link-preview.md +11 -1
  14. package/dist/generated-docs/llms-full.txt +246 -25
  15. package/dist/generated-docs/llms.txt +2 -2
  16. package/dist/generated-docs/manifest.json +72 -18
  17. package/dist/generated-docs/menubar.md +4 -3
  18. package/dist/generated-docs/meter.md +6 -0
  19. package/dist/generated-docs/nav.md +61 -0
  20. package/dist/generated-docs/select.md +2 -2
  21. package/dist/generated-docs/step.md +2 -2
  22. package/dist/generated-docs/timeline.md +32 -0
  23. package/dist/generated-docs/todo.md +3 -0
  24. package/dist/generated-docs/toggle-group.md +1 -0
  25. package/dist/generated-docs/tooltip.md +11 -1
  26. package/dist/generated-docs/tree.md +36 -0
  27. package/dist/generated-docs/utilities.json +5 -1
  28. package/dist/generated-docs/utilities.md +3 -2
  29. package/dist/ui/nav/nav-item.svelte +39 -23
  30. package/dist/ui/nav/nav-item.svelte.d.ts +41 -25
  31. package/package.json +6 -5
  32. package/skill/SKILL.md +13 -4
  33. package/dist/docs/llms-txt.d.ts +0 -2
  34. package/dist/docs/llms-txt.js +0 -100
@@ -5,48 +5,64 @@
5
5
  * `filled` is the raised control: bg-fill and the pressed shadow, held on
6
6
  * hover so it does not spring back up on bevel. Unchanged.
7
7
  *
8
- * `link` needed a different answer, and two obvious ones are wrong.
8
+ * `link` is DECORATION ONLY. The current item is not bolder, and not a
9
+ * different colour. Both of those were tried; here is why neither is here.
9
10
  *
10
- * A full-strength underline alone is the HOVER state — era-link is already
11
- * underlined at rest (currentColor at 30%) and hover resolves it to full ink,
12
- * so a current item painted that way reads as permanently hovered.
11
+ * COLOUR CANNOT CARRY IT. `text-bright` is a zero delta — --color-link IS
12
+ * --color-bright in the default theme — and on themes pointing link at
13
+ * --color-primary or --color-10 it REVERSES the emphasis, turning the
14
+ * current item neutral while its neighbours stay coloured.
13
15
  *
14
- * `text-bright` does nothing. --color-link IS --color-bright in the default
15
- * theme, so the delta is zero — measured, after writing it. Worse, themes
16
- * that point link at --color-primary or --color-10 would have it REVERSE the
17
- * emphasis: the current item goes neutral while its neighbours stay coloured.
16
+ * Knocking the OTHER items back so the current one can read as brighter is
17
+ * the obvious repair, and it does not survive the theme set either. Measured
18
+ * as composited contrast against --color-1, a 70% knock-back leaves
19
+ * sand/light at 3.59:1 — under the 4.5 floor — while every other theme sits
20
+ * between 4.74 and 7.86. The binding constraint is not whether a theme's
21
+ * link hue is muted (signalnine's --color-10 survives fine); it is how much
22
+ * headroom that theme's link had to begin with, and sand's light pair starts
23
+ * at 6.90:1. The deepest knock-back legal everywhere is around 88%, which is
24
+ * not a cue anyone would notice. A consumer who wants it on a theme with the
25
+ * headroom can do it in one line, since the decoration derives from
26
+ * currentColor and follows.
18
27
  *
19
- * So the current face uses the two axes that are independent of whatever hue
20
- * a theme gives links: decoration WEIGHT (2px, which no other state uses) and
21
- * font weight. Both survive every theme, and hover keeps its own meaning for
22
- * the items that are not current.
28
+ * WEIGHT WAS HERE AND IS NOT ANY MORE. It went in as a second axis beside
29
+ * the decoration, then had to be raised 500 -> 600 (012eeed) because in a
30
+ * monospace face 400 -> 500 keeps the advance width and reads as almost
31
+ * nothing — and era's default font axis is mono. That fix was correct about
32
+ * its own facts and wrong about the conclusion: an axis that has to be
33
+ * retuned per font stack is not a second axis, it is a liability with a
34
+ * setting. At 600 it is unmistakable in mono and heavy-handed in sans, which
35
+ * is how the next consumer came to report the opposite complaint — that the
36
+ * current item should not go bold at all.
23
37
  *
24
- * THE FONT WEIGHT IS 600, NOT 500, AND THAT IS THE WHOLE POINT OF IT. era's
25
- * default font axis is mono, and in a monospace face 400 -> 500 is very
26
- * nearly nothing: the glyphs keep their advance width, so there is no shape
27
- * change to notice and only a trace more ink. Rendered at 8x in the shipped
28
- * stack, 400 and 500 are hard to tell apart and 600 is unmistakable. At 500
29
- * the "two axes" were one axis for most consumers, since most of them are on
30
- * the default. Reported by a consumer running a mono nav, who could see the
31
- * decoration doing all the work.
38
+ * The report behind 012eeed already contained the answer: "all the signal
39
+ * was coming from the 2px decoration." That was offered as the problem. It
40
+ * is the solution. The decoration is three-way distinct on its own, in every
41
+ * font and every theme, because it is the same ink at three strengths:
32
42
  *
33
- * 600 costs no layout: measured across weights, the advance width is
34
- * identical in mono, so the bar does not reflow when the route changes.
43
+ * at rest auto thickness, currentColor at 30% (era-link's whisper)
44
+ * hover auto thickness, currentColor at 100%
45
+ * current 2px thickness, currentColor at 100%
46
+ *
47
+ * So a current item cannot read as "permanently hovered" — hover is thin and
48
+ * current is thick, and the two are told apart by the axis neither shares
49
+ * with colour. Dropping the weight also removes the last thing in this
50
+ * variant that could reflow a bar on a route change.
35
51
  */
36
52
  export declare const navItemVariants: import("tailwind-variants").TVReturnType<{
37
53
  variant: {
38
54
  filled: "no-underline aria-[current=page]:bg-fill aria-[current=page]:text-bright aria-[current=page]:shadow-pressed aria-[current=page]:hover:shadow-pressed";
39
- link: "aria-[current=page]:font-semibold aria-[current=page]:decoration-2 aria-[current=page]:[text-decoration-color:currentColor]";
55
+ link: "aria-[current=page]:decoration-2 aria-[current=page]:[text-decoration-color:currentColor]";
40
56
  };
41
57
  }, undefined, undefined, {
42
58
  variant: {
43
59
  filled: "no-underline aria-[current=page]:bg-fill aria-[current=page]:text-bright aria-[current=page]:shadow-pressed aria-[current=page]:hover:shadow-pressed";
44
- link: "aria-[current=page]:font-semibold aria-[current=page]:decoration-2 aria-[current=page]:[text-decoration-color:currentColor]";
60
+ link: "aria-[current=page]:decoration-2 aria-[current=page]:[text-decoration-color:currentColor]";
45
61
  };
46
62
  }, undefined, import("tailwind-variants").TVReturnTypeLike<{
47
63
  variant: {
48
64
  filled: "no-underline aria-[current=page]:bg-fill aria-[current=page]:text-bright aria-[current=page]:shadow-pressed aria-[current=page]:hover:shadow-pressed";
49
- link: "aria-[current=page]:font-semibold aria-[current=page]:decoration-2 aria-[current=page]:[text-decoration-color:currentColor]";
65
+ link: "aria-[current=page]:decoration-2 aria-[current=page]:[text-decoration-color:currentColor]";
50
66
  };
51
67
  }, undefined>>;
52
68
  import type { Snippet } from 'svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signal9/era-ui",
3
- "version": "26.1.1",
3
+ "version": "28.0.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev --host",
6
6
  "build": "vite build && npm run prepack",
@@ -25,15 +25,16 @@
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 check:doc-tokens && npm run check:audit-controls && npm run check:specimen-coverage && npm run check:eslint-rules && npm run check:package-name && npm run check:double-edge && 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 && npm run check:eslint-rules && npm run check:package-name && npm run check:double-edge",
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 check:eslint-rules && npm run check:install && npm run check:double-edge && 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 && npm run check:eslint-rules && npm run check:install && npm run check:double-edge",
30
30
  "test": "npm run test:visual",
31
31
  "check:doc-tokens": "node --experimental-strip-types scripts/check-doc-tokens.ts",
32
32
  "check:audit-controls": "node --experimental-strip-types scripts/check-audit-controls.ts",
33
33
  "check:specimen-coverage": "node --experimental-strip-types scripts/check-specimen-coverage.ts",
34
34
  "check:eslint-rules": "node --experimental-strip-types scripts/check-eslint-rules.ts",
35
- "check:package-name": "node --experimental-strip-types scripts/check-package-name.ts",
36
- "check:double-edge": "node --experimental-strip-types scripts/check-double-edge.ts"
35
+ "check:install": "node --experimental-strip-types scripts/check-install.ts",
36
+ "check:double-edge": "node --experimental-strip-types scripts/check-double-edge.ts",
37
+ "verify:published": "node scripts/verify-published.mjs"
37
38
  },
38
39
  "files": [
39
40
  "dist",
package/skill/SKILL.md CHANGED
@@ -181,10 +181,19 @@ a component into the role. Full reference (including every named scale above):
181
181
 
182
182
  ## Composing the library
183
183
 
184
+ One entry point per component — nothing re-exports them together, so an import
185
+ can never pull in a component you did not ask for. The ROOT is the system layer
186
+ (`cn`, `tv`, the axis registry, `ModeProvider`) and holds no components.
187
+
184
188
  ```svelte
185
189
  <script lang="ts">
186
- import { Button, Badge, OS, AI } from '@signal9/era-ui';
187
- import * as Select from '@signal9/era-ui'; // namespaced parts: Select.Root…
190
+ import { Button } from '@signal9/era-ui/button';
191
+ import { Badge } from '@signal9/era-ui/badge';
192
+ import * as Select from '@signal9/era-ui/select'; // namespaced parts: Select.Root…
193
+ import { Desktop } from '@signal9/era-ui/os';
194
+ import { Conversation } from '@signal9/era-ui/ai/conversation';
195
+
196
+ import { cn } from '@signal9/era-ui'; // the root: system only
188
197
  </script>
189
198
  ```
190
199
 
@@ -192,8 +201,8 @@ a component into the role. Full reference (including every named scale above):
192
201
  through; style via `class` (merged with tailwind-merge, consumer wins — the
193
202
  named classes conflict-resolve against internals, so `class="h-bar"` on a
194
203
  control-tier control just works).
195
- - `OS` (or `@signal9/era-ui/os`): WindowManager + workspaces, Desktop,
196
- Window, Taskbar (built-in command bar). `AI` (or `/ai`): Conversation,
204
+ - `@signal9/era-ui/os`: WindowManager + workspaces, Desktop, Pane, Taskbar
205
+ (built-in command bar), Toaster. `@signal9/era-ui/ai/<part>`: Conversation,
197
206
  Message, Response, PromptInput, Tool/Reasoning/Task over the Step primitive.
198
207
  - List-item keyboard highlight is `data-[highlighted]:bg-hover` — never
199
208
  `hover:text-bright` on items.
@@ -1,2 +0,0 @@
1
- export declare function buildLlmsTxt(origin?: string): string;
2
- export declare function buildLlmsFullTxt(): string;
@@ -1,100 +0,0 @@
1
- import { docs, hasDoc, listEntries } from './index.js';
2
- import { buildUtilitiesIndex } from './css-utilities.js';
3
- import { utilities } from './utilities.js';
4
- import { modes, defaultMode, surfaces, defaultSurface, corners, defaultCorners, fonts, defaultFont, motions, defaultMotion } from '../ui/provider/index.js';
5
- const H1 = '# era-ui';
6
- const MISSION = '> A Svelte 5 + Bits UI component library. Every surface — heights, paddings, radii, gaps — derives from a single spacing atom, so density is a one-attribute override at any scope.';
7
- function orientation(origin) {
8
- const axisList = (arr, dflt) => arr.map((v) => (v === dflt ? `**${v}** (default)` : v)).join(' · ');
9
- return [
10
- '## Using the library',
11
- '',
12
- '```ts',
13
- 'import { Button, Table, Select } from "@signal9/era-ui";',
14
- 'import "@signal9/era-ui/css";',
15
- '```',
16
- '',
17
- 'Named exports wrap a single primitive (`Button`, `Badge`, `Chip`, `Input`, …). Namespace exports compose primitives via sub-components (`Table.Root`, `Table.Row`, `Select.Trigger`, `Dialog.Content`, …). Every wrapper forwards unknown props to its underlying element or bits-ui primitive, so standard HTML attributes (`class`, `style`, event handlers, `aria-*`, `data-*`) work without ceremony.',
18
- '',
19
- '## Scoped overrides',
20
- '',
21
- 'Five orthogonal axes are exposed as HTML attributes on any ancestor. The entire subtree re-tiers through CSS inheritance — no JS, no context provider.',
22
- '',
23
- `- \`data-mode\`: ${axisList(modes, defaultMode)} — adjusts the spacing atom (\`--era-sp\`).`,
24
- `- \`data-surface\`: ${axisList(surfaces, defaultSurface)} — swaps the background treatment.`,
25
- `- \`data-corners\`: ${axisList(corners, defaultCorners)} — scales all radii toward 0.`,
26
- `- \`data-font\`: ${axisList(fonts, defaultFont)} — switches the font stack.`,
27
- `- \`data-motion\`: ${axisList(motions, defaultMotion)} — sets animation speed (\`--era-duration\` / \`--era-ease\`), independent of density.`,
28
- '',
29
- 'The `Mode` component is a thin wrapper that applies these attributes plus optional `primary` / `primaryFg` color overrides to a subtree.',
30
- '',
31
- '## Spacing system',
32
- '',
33
- 'One atom, `--era-sp` (8px dense / 10px balanced / 12px spacious), drives everything. The tier ladder is:',
34
- '',
35
- '```',
36
- 'xs = sp + 6 icons, tight affordances 14 / 16 / 18 px',
37
- 'xxs = sp + 10 nested pill (badge, chip) 18 / 20 / 22 px',
38
- 'sm = 2·sp + 6 standalone pill (kv) 22 / 26 / 30 px',
39
- 'md = 3·sp buttons, inputs, triggers 24 / 30 / 36 px',
40
- 'lg = 4·sp bars, top-level containers 32 / 40 / 48 px',
41
- '```',
42
- '',
43
- 'Heights (`--era-h-*`), insets (`--era-inset-*`), radii (`--era-rd-*`), and concentric gaps (`--era-icon-inset-chip`, `--era-pill-inset-control`, …) are all `calc()` chains off `--era-sp`. Never hard-code pixel values — setting `data-mode` on any ancestor re-derives the whole subtree. Type is the second density input (12 px at dense, 14 px above); the spacing atom moves with it.',
44
- '',
45
- '## Per-component docs',
46
- '',
47
- `Every component has a passive markdown doc at \`${origin}/<slug>.md\`.`,
48
- `Examples: \`${origin}/button.md\`, \`${origin}/select.md\`, \`${origin}/table.md\`.`,
49
- `Full concatenated reference: \`${origin}/llms-full.txt\`.`,
50
- '',
51
- 'Each page is generated from the component source, so props/variants/defaults stay in sync with the code automatically.'
52
- ].join('\n');
53
- }
54
- function utilitiesSection(origin) {
55
- return [
56
- '## CSS utilities',
57
- '',
58
- 'Classes, not components — they need no import beyond the stylesheet. Reach for one of these before hand-rolling the same styling or bending a component into the role.',
59
- '',
60
- ...buildUtilitiesIndex(utilities),
61
- '',
62
- `Full reference (what each emits, when to use it): \`${origin}/utilities.md\`. Machine-readable list: \`${origin}/utilities.json\`.`
63
- ].join('\n');
64
- }
65
- export function buildLlmsTxt(origin = '') {
66
- const entries = listEntries();
67
- const lines = [H1, '', MISSION, '', orientation(origin), ''];
68
- if (entries.length) {
69
- lines.push('## Components', '');
70
- lines.push(entries.map((e) => e.slug).join(', '), '');
71
- }
72
- lines.push(utilitiesSection(origin), '');
73
- return lines.join('\n');
74
- }
75
- // Module-init-cached: the concatenated reference has no request-dependent
76
- // inputs, so we pay its ~80 KB assembly cost once per worker instance instead
77
- // of on every request.
78
- let llmsFullTxtCache;
79
- export function buildLlmsFullTxt() {
80
- if (llmsFullTxtCache !== undefined)
81
- return llmsFullTxtCache;
82
- const entries = listEntries().filter((e) => hasDoc(e.slug));
83
- const parts = [
84
- H1,
85
- '',
86
- MISSION,
87
- '',
88
- orientation(''),
89
- '',
90
- utilitiesSection(''),
91
- '',
92
- '<!-- Full component documentation, concatenated. The utilities page below carries the CSS each utility emits. -->',
93
- ''
94
- ];
95
- for (const e of entries) {
96
- parts.push(`<!-- begin: ${e.slug} -->`, '', docs[e.slug].trim(), '', `<!-- end: ${e.slug} -->`, '');
97
- }
98
- llmsFullTxtCache = parts.join('\n');
99
- return llmsFullTxtCache;
100
- }