@nadicodeai/ui 10.1.0 → 12.1.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.
- package/AGENTS.md +39 -24
- package/README.md +58 -124
- package/dist/agent-orb.d.ts +1 -1
- package/dist/agent-orb.d.ts.map +1 -1
- package/dist/assets/brand/index.json +1 -1
- package/dist/components/action-menu.js +1 -1
- package/dist/components/agent-card.d.ts.map +1 -1
- package/dist/components/agent-card.js +2 -4
- package/dist/components/agent-orb.d.ts +11 -5
- package/dist/components/agent-orb.d.ts.map +1 -1
- package/dist/components/agent-orb.js +8 -6
- package/dist/components/alert.js +3 -3
- package/dist/components/badge.js +6 -6
- package/dist/components/brand-field.d.ts +2 -0
- package/dist/components/brand-field.d.ts.map +1 -1
- package/dist/components/brand-field.js +3 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +4 -5
- package/dist/components/carousel.js +2 -2
- package/dist/components/chart-bar-horizontal.js +1 -1
- package/dist/components/chart.js +1 -1
- package/dist/components/command.js +1 -1
- package/dist/components/context-menu.js +1 -1
- package/dist/components/diff-count.js +1 -1
- package/dist/components/dropdown-menu.js +3 -3
- package/dist/components/footer.d.ts +4 -7
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +1 -4
- package/dist/components/item.js +1 -1
- package/dist/components/kpi-card.js +2 -2
- package/dist/components/label-system.d.ts +1 -5
- package/dist/components/label-system.d.ts.map +1 -1
- package/dist/components/label-system.js +2 -6
- package/dist/components/menu-choice-row.js +1 -1
- package/dist/components/menubar.js +1 -1
- package/dist/components/object-workspace.js +1 -1
- package/dist/components/progress.js +1 -1
- package/dist/components/scope-switcher.d.ts +24 -0
- package/dist/components/scope-switcher.d.ts.map +1 -0
- package/dist/components/scope-switcher.js +34 -0
- package/dist/components/settings-section.d.ts +2 -1
- package/dist/components/settings-section.d.ts.map +1 -1
- package/dist/components/settings-section.js +2 -2
- package/dist/components/status-dot.js +1 -1
- package/dist/components/status-row.js +1 -1
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +1 -1
- package/dist/components/tabs.d.ts +11 -5
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +37 -5
- package/dist/components/tooltip.js +1 -1
- package/dist/components/trend-badge.d.ts.map +1 -1
- package/dist/components/trend-badge.js +1 -2
- package/dist/eslint/index.js +4 -0
- package/dist/eslint/rules/jsx-class-utility.js +1 -1
- package/dist/eslint/rules/no-shadcn-appearance-override.js +3 -3
- package/dist/eslint/rules/one-control-height.js +94 -0
- package/dist/eslint/rules/settings-section-description.js +45 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/agent-orb-motion.d.ts +1 -0
- package/dist/internal/agent-orb-motion.d.ts.map +1 -1
- package/dist/internal/agent-orb-motion.js +6 -3
- package/dist/internal/agent-orb.d.ts +10 -2
- package/dist/internal/agent-orb.d.ts.map +1 -1
- package/dist/internal/agent-orb.js +19 -9
- package/dist/internal/assistant-ui/attachment.js +4 -4
- package/dist/internal/assistant-ui/follow-up-suggestions.js +1 -1
- package/dist/internal/assistant-ui/markdown-text.js +4 -4
- package/dist/internal/assistant-ui/reasoning.js +2 -2
- package/dist/internal/assistant-ui/thread.d.ts.map +1 -1
- package/dist/internal/assistant-ui/thread.js +11 -9
- package/dist/internal/assistant-ui/tool-group.js +2 -2
- package/dist/styles/components.css +9 -5
- package/dist/styles/globals.css +43 -0
- package/package.json +3 -4
- package/dist/components/handoff-banner.d.ts +0 -9
- package/dist/components/handoff-banner.d.ts.map +0 -1
- package/dist/components/handoff-banner.js +0 -6
- package/docs/activity.md +0 -113
- package/docs/agent-orb.md +0 -168
- package/docs/component-classification.md +0 -45
- package/docs/consuming-cross-repo.md +0 -116
- package/docs/contract.md +0 -388
- package/docs/icon-assets.md +0 -106
- package/docs/migration/1.0.0.md +0 -75
- package/docs/migration/10.0.0.md +0 -144
- package/docs/migration/2.0.0.md +0 -69
- package/docs/migration/6.0.0.md +0 -30
- package/docs/migration/9.0.0.md +0 -35
- package/docs/migration/base-ui-migration.md +0 -62
- package/docs/model-identity.md +0 -18
- package/docs/product-compositions.md +0 -96
- package/docs/product-sections.md +0 -200
|
@@ -27,13 +27,17 @@
|
|
|
27
27
|
* The one glass material (DESIGN.md "Elevation & Depth"): floating chrome —
|
|
28
28
|
* menus, popovers, selects, comboboxes, the command palette, and bars — may
|
|
29
29
|
* carry it; content surfaces stay solid. Glass composites only over our own
|
|
30
|
-
* content
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
30
|
+
* content. Its edge is the floating rung's recipe, whose inset top highlight
|
|
31
|
+
* and inner hairline only show once the fill turns translucent. A fine grain
|
|
32
|
+
* over the fill keeps the blurred colour behind it from banding. Declared as a
|
|
33
|
+
* utility so variant prefixes can gate it (navigation-menu's non-viewport
|
|
34
|
+
* popup). Reduced transparency falls back to the same solid surface at the
|
|
35
|
+
* same elevation.
|
|
34
36
|
*/
|
|
35
37
|
@utility nc-glass {
|
|
36
|
-
background:
|
|
38
|
+
background:
|
|
39
|
+
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNDAnIGhlaWdodD0nMTQwJz48ZmlsdGVyIGlkPSdnJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nLjg1JyBudW1PY3RhdmVzPScyJyBzdGl0Y2hUaWxlcz0nc3RpdGNoJy8+PGZlQ29sb3JNYXRyaXggdHlwZT0nc2F0dXJhdGUnIHZhbHVlcz0nMCcvPjwvZmlsdGVyPjxyZWN0IHdpZHRoPScxMDAlJyBoZWlnaHQ9JzEwMCUnIGZpbHRlcj0ndXJsKCNnKScgb3BhY2l0eT0nLjA1Jy8+PC9zdmc+"),
|
|
40
|
+
color-mix(in srgb, var(--popover) var(--nc-material-glass-opacity), transparent);
|
|
37
41
|
backdrop-filter: blur(var(--nc-material-glass-blur)) saturate(var(--nc-material-glass-saturation));
|
|
38
42
|
|
|
39
43
|
@media (prefers-reduced-transparency: reduce) {
|
package/dist/styles/globals.css
CHANGED
|
@@ -29,6 +29,49 @@
|
|
|
29
29
|
*/
|
|
30
30
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
31
31
|
|
|
32
|
+
/*
|
|
33
|
+
* Dark mode carries height in tone (DESIGN.md "Elevation & Depth"): the page
|
|
34
|
+
* stays true black and each rung's surface is one fixed step lighter. The rung
|
|
35
|
+
* sets the card and popover roles on its own element, so whichever role that
|
|
36
|
+
* surface paints with takes the rung's tone, whatever order the classes land
|
|
37
|
+
* in. A rung behind a variant prefix keeps the page's roles. In light every
|
|
38
|
+
* tone is the solid white. This belongs to the application
|
|
39
|
+
* stylesheet, not components.css, because a host keeps its own roles.
|
|
40
|
+
*/
|
|
41
|
+
@layer components {
|
|
42
|
+
.nc-elevation-resting {
|
|
43
|
+
--card: var(--nc-material-resting);
|
|
44
|
+
--popover: var(--nc-material-resting);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.nc-elevation-raised {
|
|
48
|
+
--card: var(--nc-material-raised);
|
|
49
|
+
--popover: var(--nc-material-raised);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.nc-elevation-floating {
|
|
53
|
+
--card: var(--nc-material-floating);
|
|
54
|
+
--popover: var(--nc-material-floating);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.nc-elevation-modal {
|
|
58
|
+
--card: var(--nc-material-modal);
|
|
59
|
+
--popover: var(--nc-material-modal);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/*
|
|
63
|
+
* A lifted dark surface is lighter than the soft steps the hover, selected
|
|
64
|
+
* and keycap fills take on the black page, so on it those fills step up
|
|
65
|
+
* from its own tone instead: 8% of the foreground over the surface. Light
|
|
66
|
+
* surfaces are white, where the soft steps already read.
|
|
67
|
+
*/
|
|
68
|
+
:where(.dark)
|
|
69
|
+
:is(.nc-elevation-resting, .nc-elevation-raised, .nc-elevation-floating, .nc-elevation-modal) {
|
|
70
|
+
--accent: color-mix(in oklab, var(--popover) 92%, var(--foreground));
|
|
71
|
+
--muted: color-mix(in oklab, var(--popover) 92%, var(--foreground));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
32
75
|
@layer base {
|
|
33
76
|
* {
|
|
34
77
|
@apply border-border outline-ring;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nadicodeai/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -52,8 +52,7 @@
|
|
|
52
52
|
"LICENSES",
|
|
53
53
|
"NOTICE",
|
|
54
54
|
"README.md",
|
|
55
|
-
"AGENTS.md"
|
|
56
|
-
"docs"
|
|
55
|
+
"AGENTS.md"
|
|
57
56
|
],
|
|
58
57
|
"scripts": {
|
|
59
58
|
"dev": "node scripts/dev-build.mjs --watch",
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
"@assistant-ui/react": "0.15.21",
|
|
73
72
|
"@assistant-ui/react-markdown": "0.14.16",
|
|
74
73
|
"@base-ui/react": "^1.8.0",
|
|
75
|
-
"@nadicodeai/design-system": "
|
|
74
|
+
"@nadicodeai/design-system": "12.1.1",
|
|
76
75
|
"class-variance-authority": "^0.7.1",
|
|
77
76
|
"clsx": "^2.1.1",
|
|
78
77
|
"cmdk": "^1.1.1",
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
declare function HandoffBanner({ className, reason, destination, children, ...props }: Omit<React.ComponentProps<"div">, "children"> & {
|
|
3
|
-
reason?: string;
|
|
4
|
-
destination?: string;
|
|
5
|
-
/** Escape hatch: rich banner content that replaces the serializable model. */
|
|
6
|
-
children?: React.ReactNode;
|
|
7
|
-
}): React.JSX.Element;
|
|
8
|
-
export { HandoffBanner };
|
|
9
|
-
//# sourceMappingURL=handoff-banner.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handoff-banner.d.ts","sourceRoot":"","sources":["../../src/components/handoff-banner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,MAAM,EACN,WAAW,EACX,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,qBAWA;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cn } from "../lib/utils.js";
|
|
3
|
-
function HandoffBanner({ className, reason, destination, children, ...props }) {
|
|
4
|
-
return (_jsx("div", { "data-slot": "handoff-banner", className: cn("nc-handoff-banner", className), ...props, children: children ?? (_jsxs(_Fragment, { children: [destination != null && _jsx("span", { "data-slot": "handoff-banner-destination", children: destination }), reason != null && _jsx("span", { "data-slot": "handoff-banner-reason", children: reason })] })) }));
|
|
5
|
-
}
|
|
6
|
-
export { HandoffBanner };
|
package/docs/activity.md
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# System activity
|
|
2
|
-
|
|
3
|
-
Who does the work decides how it looks.
|
|
4
|
-
|
|
5
|
-
An Agent's work shows that Agent's orb in its state and a sentence saying what
|
|
6
|
-
it is doing; [AgentOrb](agent-orb.md) owns it, and Nadia connecting is her
|
|
7
|
-
ribbon, working. Everything on this page is the *system's* own work: a save, a
|
|
8
|
-
sign-in, a refresh, a page load. An orb means an Agent, so system work never
|
|
9
|
-
takes one.
|
|
10
|
-
|
|
11
|
-
| The wait | What it shows |
|
|
12
|
-
| --- | --- |
|
|
13
|
-
| Under about a second | The control's own label changes to its pending word. Nothing else. |
|
|
14
|
-
| Past a second | One `WaitingLine` beside the work, and nothing else moves. |
|
|
15
|
-
| Measurable | `Progress` with a written count ("120 di 240 fatture"). |
|
|
16
|
-
| A page load | `Skeleton` placeholders in the shape of the content, still. |
|
|
17
|
-
|
|
18
|
-
One wait gets one indicator. Separately progressing operations may each have
|
|
19
|
-
one. A request waiting for a person is not a wait: queued, paused, offline,
|
|
20
|
-
blocked, successful and failed conditions take the status or feedback
|
|
21
|
-
treatment. An account being active is not an activity.
|
|
22
|
-
|
|
23
|
-
## The pending label
|
|
24
|
-
|
|
25
|
-
The control keeps its place, its size and its icon; only its word changes, and
|
|
26
|
-
the caller marks the control `disabled` and `aria-busy` so the change is
|
|
27
|
-
announced as well as read.
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
import { PendingLabel } from "@nadicodeai/ui/components/pending-label";
|
|
31
|
-
|
|
32
|
-
<Button aria-busy={saving || undefined} disabled={saving} type="submit">
|
|
33
|
-
<PendingLabel pending={saving} pendingLabel="Salvataggio…">
|
|
34
|
-
Salva modifiche
|
|
35
|
-
</PendingLabel>
|
|
36
|
-
</Button>;
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
`pending` and `pendingLabel` are required; the children are the idle label. It
|
|
40
|
-
renders a `span` carrying `data-slot="pending-label"` and, while pending,
|
|
41
|
-
`data-pending="true"`. It adds no mark of its own: a control that had an icon
|
|
42
|
-
keeps that icon, unchanged, throughout the wait.
|
|
43
|
-
|
|
44
|
-
## The waiting line
|
|
45
|
-
|
|
46
|
-
A 2 px track of ink with a 32% segment crossing it linearly on the `wait`
|
|
47
|
-
token, after one second of waiting. Before that second the track is there and
|
|
48
|
-
empty, unannounced, so the line arriving moves nothing around it; a wait the
|
|
49
|
-
person barely notices does not deserve movement, and a control that flashed an
|
|
50
|
-
indicator for 200 ms reads as a glitch.
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
import { WaitingLine } from "@nadicodeai/ui/components/waiting-line";
|
|
54
|
-
|
|
55
|
-
<WaitingLine label="Caricamento delle fatture" />;
|
|
56
|
-
|
|
57
|
-
<div>
|
|
58
|
-
<p>Stiamo preparando il documento.</p>
|
|
59
|
-
<WaitingLine decorative />
|
|
60
|
-
</div>;
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
A meaningful standalone line takes `label` and announces itself as a status;
|
|
64
|
-
`decorative` removes its accessible name when the text beside it already says
|
|
65
|
-
what is happening. Width comes from the caller (`className="w-24"`, or the
|
|
66
|
-
full width of the region it belongs to); height, ink, segment and timing are
|
|
67
|
-
the component's and are not tunable. The one-second delay is
|
|
68
|
-
`WAITING_LINE_DELAY_MS`, exported so a test can name it rather than guess it.
|
|
69
|
-
|
|
70
|
-
Reduced motion drops the travel and breathes the full line in opacity, so a
|
|
71
|
-
wait still reads as a wait. The rule lives in
|
|
72
|
-
`packages/design-system/src/css/motion.css` as `.nc-anim-wait`, with the rest
|
|
73
|
-
of the motion vocabulary.
|
|
74
|
-
|
|
75
|
-
Product code unmounts the line when the operation ends or cannot proceed.
|
|
76
|
-
|
|
77
|
-
## Measurable and still
|
|
78
|
-
|
|
79
|
-
`Progress` carries work whose completed amount is known, always beside a
|
|
80
|
-
written count. When work will become measurable, reserve the progress
|
|
81
|
-
treatment from the start so the transition does not move the layout. Never
|
|
82
|
-
invent a percentage.
|
|
83
|
-
|
|
84
|
-
`Skeleton` is a still placeholder shaped like the content behind it. It does
|
|
85
|
-
not pulse. Do not show a skeleton and a waiting line for the same wait: the
|
|
86
|
-
placeholders already say the page is arriving.
|
|
87
|
-
|
|
88
|
-
## What retired
|
|
89
|
-
|
|
90
|
-
`ActivityOrb` and `mountActivityOrb`, `Spinner`, `GlyphSpinner`, Sonner's
|
|
91
|
-
spinning loading icon, the raw `LoaderCircle` spinners in `feedback-state`,
|
|
92
|
-
`installer-shell`, `automation-section` and `confirm-dialog`, the assistant-ui
|
|
93
|
-
attachment, tool-fallback and tool-group spinners, and the shimmer text on the
|
|
94
|
-
reasoning, tool-fallback and tool-group triggers. With them went the
|
|
95
|
-
`thinking-orbs` system-activity palette, the `tw-shimmer` dependency and the
|
|
96
|
-
duplicate `@utility shimmer`, and the unused `nc-anim-typing` and
|
|
97
|
-
`nc-anim-shimmer` hooks.
|
|
98
|
-
|
|
99
|
-
Where one of those marked a running state inside a component, the state is now
|
|
100
|
-
said in words and marked with a still glyph: an installer step and an
|
|
101
|
-
automation row take `CircleDotIcon`, and a running tool call says "Running
|
|
102
|
-
tool". A status badge never moves; its word and its mark carry the state.
|
|
103
|
-
|
|
104
|
-
## Ownership and source
|
|
105
|
-
|
|
106
|
-
The components own the delay, the geometry, the ink and the motion. The
|
|
107
|
-
application owns the request, the retry, the copy, the completion and the
|
|
108
|
-
recovery. The decision behind this page is
|
|
109
|
-
[the nadicode design system ADR](../../../docs/adr/2026-09-23-the-nadicode-design-system.md);
|
|
110
|
-
the design-system side of it is
|
|
111
|
-
[`DESIGN.md`, "## System activity"](../../design-system/DESIGN.md#system-activity).
|
|
112
|
-
The distinction between measured and unmeasured progress follows
|
|
113
|
-
[Apple's progress guidance](https://developer.apple.com/design/human-interface-guidelines/progress-indicators).
|
package/docs/agent-orb.md
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# Agent orbs
|
|
2
|
-
|
|
3
|
-
`AgentOrb` is the one Agent identity in every product: seven structures from
|
|
4
|
-
`thinking-orbs` 0.3.1, each painted in one chosen colour, and Nadia's own
|
|
5
|
-
striped ribbon. These are persistent appearance choices, not activity states.
|
|
6
|
-
No other Agent form, avatar or portrait exists; a custom picture a person
|
|
7
|
-
uploads in Nadia is theirs, not an identity this package draws.
|
|
8
|
-
|
|
9
|
-
| Form | Structure | Upstream preset |
|
|
10
|
-
| --- | --- | --- |
|
|
11
|
-
| `ribbon` | Flowing dotted bands | `composing` |
|
|
12
|
-
| `lattice` | Rotating particle bands | `solving` |
|
|
13
|
-
| `orbit` | Particles on tilted orbits | `working` |
|
|
14
|
-
| `globe` | Dotted globe and scanning meridian | `searching` |
|
|
15
|
-
| `network` | Connected constellation | `connecting` |
|
|
16
|
-
| `braid` | Interwoven strands | `weaving` |
|
|
17
|
-
| `morph` | Changing geometric contour | `shaping` |
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## Nadia
|
|
21
|
-
|
|
22
|
-
`form="nadia"` is the ribbon striped along its whole length, across its width:
|
|
23
|
-
azzurro (`--nc-identity-azzurro`), verde, the orb's own pigment, and rosso.
|
|
24
|
-
The third stripe is the white of the tricolore; it takes the inherited text
|
|
25
|
-
colour so it stays visible as ink on a white ground. The stripes are fixed:
|
|
26
|
-
the same four at every size, in both themes and in every state, and nobody
|
|
27
|
-
chooses them. Each dot keeps its lane through the engine's depth sort, so a
|
|
28
|
-
stripe never changes colour as the ribbon turns. Her motion is the ribbon's.
|
|
29
|
-
|
|
30
|
-
## Stored appearance
|
|
31
|
-
|
|
32
|
-
Nadia stores an Agent's look in its profile and reports it to the Portal on
|
|
33
|
-
every check-in; the Portal renders it and never writes it.
|
|
34
|
-
`@nadicodeai/ui/components/agent-orb-appearance` is the one reading of those
|
|
35
|
-
strings, server-safe so a server can resolve a row before it renders:
|
|
36
|
-
|
|
37
|
-
| Field | Stored as |
|
|
38
|
-
| --- | --- |
|
|
39
|
-
| `shape` | `orb:orbit`, `orb:ribbon`, `orb:lattice`, `orb:globe`, `orb:network`, `orb:braid`, `orb:morph` |
|
|
40
|
-
| `color` | The design system's identity hex of cobalto, verde or arancio, or null; or a rosso an Agent chose before rosso left the picker |
|
|
41
|
-
|
|
42
|
-
`resolveAgentOrb(stored, { root })` returns the form and colour to draw. The
|
|
43
|
-
root Agent is Nadia and draws `nadia` whatever is stored. An unknown or empty
|
|
44
|
-
shape draws `orbit`; an unknown or empty colour draws the inherited text
|
|
45
|
-
colour, which is also the default a picker's reset restores. Paint a colour
|
|
46
|
-
with `agentOrbColorTokens[color]`. Each retired `forma:` spelling resolves to
|
|
47
|
-
its own orb, so an Agent keeps a distinct look until someone changes it.
|
|
48
|
-
|
|
49
|
-
## The three colours
|
|
50
|
-
|
|
51
|
-
A person chooses cobalto, verde or arancio, or nothing, which leaves the orb
|
|
52
|
-
the inherited text colour. All three clear 3:1 against both the white and the
|
|
53
|
-
black canvas, so a chosen orb stays visible in either theme; giallo does not
|
|
54
|
-
(1.6:1 on white) and is not offered.
|
|
55
|
-
|
|
56
|
-
Rosso is not offered either. It is exactly the error red, so a red Agent beside
|
|
57
|
-
a red "Bloccato" badge read as a broken Agent rather than a chosen colour.
|
|
58
|
-
Nadia keeps rosso in her own stripes, where it is one of four and says nothing
|
|
59
|
-
on its own. An Agent that chose rosso before it left the picker keeps a colour:
|
|
60
|
-
`resolveAgentOrb` maps a stored `rosso`, by name or by the `#d3302f` hex, to
|
|
61
|
-
arancio, the nearest hue that is not a status. That is a mapping on the way in,
|
|
62
|
-
not an offer on the way out — `agentOrbColors` is what a picker shows, and it
|
|
63
|
-
has three entries.
|
|
64
|
-
|
|
65
|
-
The appearance is a person's choice, never derived: do not infer it from a name,
|
|
66
|
-
an id hash or a role. A machine check-in is not Agent activity, so a surface that
|
|
67
|
-
only knows check-ins draws the orb idle. The form does not select a job, tools or runtime status. Do not switch it when
|
|
68
|
-
an Agent starts searching or solving. Applications own the persisted form,
|
|
69
|
-
colour, name and status; names beside avatars provide exact identification.
|
|
70
|
-
|
|
71
|
-
## Component
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
import { AgentOrb } from "@nadicodeai/ui/components/agent-orb";
|
|
75
|
-
|
|
76
|
-
<AgentOrb form="ribbon" color="var(--nc-identity-cobalto)" size={32} label="Research" />;
|
|
77
|
-
<AgentOrb form="nadia" size={32} label="Nadia" />;
|
|
78
|
-
<AgentOrb form="globe" presence="over-picture" size={96} state="working" label="Ricerca" />;
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
`form` is required. `color` accepts one CSS colour, including a customer-chosen
|
|
82
|
-
colour or a canonical token. Omit it to inherit text colour. This configurable
|
|
83
|
-
artwork is not a new palette for controls or status. Every particle and line
|
|
84
|
-
of a chosen form uses the same pigment, and on Nadia each stripe keeps its own;
|
|
85
|
-
opacity, not another colour, creates depth. Working
|
|
86
|
-
releases occasional coloured flourishes; Done repeats the same arcs,
|
|
87
|
-
arrowheads, rings and sparkles in a short celebration around
|
|
88
|
-
that single-colour identity, using the existing chart and warning tokens. Choose a
|
|
89
|
-
colour visible on the intended background. A deliberately black pigment on a
|
|
90
|
-
black surface is not automatically recoloured.
|
|
91
|
-
|
|
92
|
-
A native startup screen paints an orb before React loads through
|
|
93
|
-
`mountAgentOrb(canvas, { form, size, presence, state, paused })` from
|
|
94
|
-
`@nadicodeai/ui/agent-orb`, the React-free entry beside
|
|
95
|
-
`@nadicodeai/ui/activity`. It is the renderer `AgentOrb` itself mounts, with
|
|
96
|
-
the same motion, states and presence; the caller supplies the canvas and the
|
|
97
|
-
adjacent name, and calls `destroy()` when React replaces the startup surface.
|
|
98
|
-
Import `@nadicodeai/ui/globals.css` with it: the renderer inherits the CSS ink
|
|
99
|
-
and reads the colour tokens from the element.
|
|
100
|
-
|
|
101
|
-
Sizes are 20, 24, 32, 40, 64, 96 and 160 CSS pixels. Menu sizes through 32 use
|
|
102
|
-
the upstream compact density; larger sizes use its detailed profile. `paused`
|
|
103
|
-
holds the current frame and resumes without resetting the appearance. An
|
|
104
|
-
accessible image requires `label`; use `decorative` beside an existing name.
|
|
105
|
-
The component is Canvas 2D, not WebGL. It reuses the vendor's portable geometry
|
|
106
|
-
API because the stock React component only offers monochrome light/dark ink,
|
|
107
|
-
not a configurable pigment.
|
|
108
|
-
|
|
109
|
-
Motion is limited to 30 painted frames per second. Offscreen and hidden orbs
|
|
110
|
-
stop scheduling animation. Unmount removes the frame request and observers.
|
|
111
|
-
DPR is capped at two. Without Canvas 2D, the accessible name remains
|
|
112
|
-
available.
|
|
113
|
-
|
|
114
|
-
The engine paints the box the canvas occupies, not the `size` it was given: a
|
|
115
|
-
`ResizeObserver` follows the element, and the backing store and the geometry's
|
|
116
|
-
density profile both come from the measured CSS pixels. `size` sets that box
|
|
117
|
-
through `--nc-agent-orb-size` in a class, so a caller whose layout decides the
|
|
118
|
-
size overrides it with its own sizing class and the orb stays sharp at
|
|
119
|
-
whatever width it lands on. The declared size still stands in before layout
|
|
120
|
-
has measured anything, on a server render and in a test environment without
|
|
121
|
-
layout.
|
|
122
|
-
|
|
123
|
-
`presence` decides how loudly one orb reads on its ground, per mount, never
|
|
124
|
-
as a module setting: two orbs on one page can want different weights.
|
|
125
|
-
`plain`, the default, is the interface's own ink. `over-picture` multiplies
|
|
126
|
-
ink by 2.3 and every dot and line radius by 1.9, for an orb drawn on a
|
|
127
|
-
photograph, where the plain weights sink into the image. Nadia on open sky
|
|
128
|
-
keeps `plain`.
|
|
129
|
-
|
|
130
|
-
Reduced motion turns movement off and keeps opacity and colour. A thinking or
|
|
131
|
-
working orb breathes between full ink and 0.45 over 1.6 s, ease-in-out, so
|
|
132
|
-
busy still reads as busy; its geometry does not turn, and the state cue
|
|
133
|
-
breathes with the body. Every other state, idle, waiting, blocked and done
|
|
134
|
-
included, holds one still frame. The preference is observed live.
|
|
135
|
-
|
|
136
|
-
`state` accepts idle, working, waiting, blocked, thinking and done, and every
|
|
137
|
-
surface passes the Agent's real one: only Agents move on their own, so motion
|
|
138
|
-
on a screen means an Agent is working and a still orb means it is not. Idle
|
|
139
|
-
holds one still pose and schedules no frame after its first paint; a surface
|
|
140
|
-
that knows only check-ins draws idle, because a machine check-in is not Agent
|
|
141
|
-
activity. Geometry and state gestures have separate clocks. Each form has its
|
|
142
|
-
own geometry pace, shared across avatar sizes, which Working and Thinking
|
|
143
|
-
keep; Morph holds a contour for about 1.6 seconds and changes it over one
|
|
144
|
-
second. Waiting holds its pose; Blocked makes one gentle interrupted effort
|
|
145
|
-
and stops.
|
|
146
|
-
V7 keeps the material free-standing and intact:
|
|
147
|
-
no gear, thought bubble, pause, exclamation mark or check is cut into the form.
|
|
148
|
-
Working and Thinking preserve the native geometry: do not stretch, flatten,
|
|
149
|
-
fold or emit copies of the orb to convey either state. Working uses one open,
|
|
150
|
-
tapered multicoloured ribbon passing behind and in front of the orb on a
|
|
151
|
-
7.2-second loop. Thinking uses three persistent coloured dots above the orb,
|
|
152
|
-
with sequential opacity and slight size pulses on a 3.6-second loop.
|
|
153
|
-
The distinct symbols remain visible throughout both cycles. Done repeats
|
|
154
|
-
the ribbon in three celebratory sweeps and then rests. Changing `motionKey`
|
|
155
|
-
replays it. These exterior cues use the celebration palette; the body keeps
|
|
156
|
-
its configured pigment.
|
|
157
|
-
No state has an enclosing circle. Keep a nearby status label where exact
|
|
158
|
-
state identification matters, including reduced motion and compact sizes.
|
|
159
|
-
|
|
160
|
-
In the Portal, [`agent-identity.tsx`](../../../apps/portal/src/components/agent-identity.tsx)
|
|
161
|
-
draws every Agent, in its lists, Agent workspace and the sign-in, sign-up and
|
|
162
|
-
Get Nadia pages, and `src/lib/agent-orb.ts` maps what a machine reported to
|
|
163
|
-
the state drawn. It also gives an orb a `travelId`, which wraps it in React's
|
|
164
|
-
`<ViewTransition>` so the same orb travels from a list row into the Agent's
|
|
165
|
-
page; `apps/portal/docs/design-doctrine.md` owns that rule. Inspect them in
|
|
166
|
-
the running local Portal for compact and full-size appearances.
|
|
167
|
-
|
|
168
|
-
[Upstream library and presets](https://libraries.dev/orbs), MIT licensed.
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Component Classification
|
|
2
|
-
|
|
3
|
-
This file records the ownership class for U4 product compositions. The package may render standard product UI, but consuming apps own app behavior, data, persistence, and product-specific promises.
|
|
4
|
-
|
|
5
|
-
If first-party shadcn or assistant-ui registry source already covers the same
|
|
6
|
-
generic product UI, do not add a parallel nadicode package API. Use the
|
|
7
|
-
registry item in the consuming app and adapt it there with app-owned data,
|
|
8
|
-
copy, and behavior.
|
|
9
|
-
|
|
10
|
-
## Removed Direct Reinventions
|
|
11
|
-
|
|
12
|
-
| Removed API | Registry source to use instead | Reason |
|
|
13
|
-
| --- | --- | --- |
|
|
14
|
-
| Package-level `DataTable`, `DataTableColumnControls`, `DataTableEmptyState`, `DataTableState` | [shadcn Data Table guide](https://ui.shadcn.com/docs/components/base/data-table), `@shadcn/table`, and the table in `@shadcn/dashboard-01` | These are first-party composition sources for sorting, visibility, filtering, and pagination. Portal retains its app-owned `DataTable` adapter for registry and URL behavior. |
|
|
15
|
-
| `CommandPalette`, `ModelPickerCommand`, `SessionPickerCommand` | `@shadcn/command` and its `CommandDialog` export ([Command guide](https://ui.shadcn.com/docs/components/base/command)) | The command primitive and dialog composition are already supplied; model/session execution is app behavior. |
|
|
16
|
-
| `ChartCard`, `MetricChart`, `semanticChartColors` | The package chart kit, owned by [`contract.md`](contract.md) | shadcn already ships the chart primitives and blocks the kit is pulled from; metric aggregation and chart choice are app behavior. |
|
|
17
|
-
|
|
18
|
-
## Retained Package Compositions
|
|
19
|
-
|
|
20
|
-
| Component | Classification | Built on | Required states | Package-owned accessibility | Fixture |
|
|
21
|
-
| --- | --- | --- | --- | --- | --- |
|
|
22
|
-
| `ActionMenu` | Canonical record-action composition. | shadcn `Button` and `DropdownMenu`. | closed, open, keyboard selection, focus return. | Required accessible trigger name; inherited menu mechanics. | `../src/components/action-menu.test.tsx` |
|
|
23
|
-
| `SettingsSection` | nadicode product composition. | shadcn Card slots, Separator, and FieldGroup. | header, field group, and divided action footer. | Section structure; consumer owns the form transaction. | `../src/components/settings-section.test.tsx` |
|
|
24
|
-
| `SettingsField` | nadicode product composition. | shadcn Field, FieldLabel, FieldDescription, and FieldError. | valid, invalid, required, and disabled field rows. | Render callback supplies the control's label and message associations in server and client components. | `../src/components/settings-section.test.tsx` |
|
|
25
|
-
| `FeedbackState` | Net-new central product state composition adapted from shadcn empty-state patterns. | shadcn `Empty` and lucide status icons. | `empty`, `loading`, `saving`, `error`, `permission`, `offline`, `no-results`, `fatal`. | `role="status"` for loading/saving; `role="alert"` for error, permission, offline, and fatal. | `../tests/guards/product-compositions.test.ts` |
|
|
26
|
-
|
|
27
|
-
## App-Owned Boundaries
|
|
28
|
-
|
|
29
|
-
Keep these out of `@nadicodeai/ui`:
|
|
30
|
-
|
|
31
|
-
- data fetching, React Query, routers, server actions, desktop IPC, terminal runtime code, and persistence;
|
|
32
|
-
- login/signup routes, OTP/two-factor flows, auth provider choices, recovery flows, session mutation, and analytics;
|
|
33
|
-
- permission decisions, tenant/customer scoping, and policy enforcement;
|
|
34
|
-
- app-specific product copy, page IA, and route-specific ordering;
|
|
35
|
-
- fake proof, invented customer names, invented metrics, or placeholder testimonials.
|
|
36
|
-
|
|
37
|
-
## Fixture Guidance
|
|
38
|
-
|
|
39
|
-
U4 fixtures should use nadicode-relevant work objects:
|
|
40
|
-
|
|
41
|
-
- briefing agents, review agents, approval queues, sessions, models, workspace defaults, files, pairing codes, and weekly approvals;
|
|
42
|
-
- controlled state examples for sorting, selection, visibility, validation, loading, saving, offline, permission, and fatal states;
|
|
43
|
-
- no external network, browser, customer PII, signed contracts, financials, or fake proof.
|
|
44
|
-
|
|
45
|
-
Browser-driven tests stay out of the default Vitest suite. U4 fixtures render through static and SSR-friendly tests only.
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# Consuming `@nadicodeai/ui` Cross-Repo
|
|
2
|
-
|
|
3
|
-
This is the contract for an external repo — the Nadia repo, sibling Nadia web,
|
|
4
|
-
desktop, or any consumer outside this monorepo — installing `@nadicodeai/ui`
|
|
5
|
-
from published npm rather than the workspace source.
|
|
6
|
-
|
|
7
|
-
## Version pinning
|
|
8
|
-
|
|
9
|
-
Pin the UI package to an exact version, never `latest` or a caret/tilde range:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm view @nadicodeai/ui version
|
|
13
|
-
npm install @nadicodeai/ui@<exact-version> react@^19 react-dom@^19 tailwindcss@^4 @tailwindcss/postcss@^4
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
`@nadicodeai/ui` pins and installs its `@nadicodeai/design-system` runtime
|
|
17
|
-
dependency exactly. A React consumer does not declare that dependency directly
|
|
18
|
-
just to use UI components or the UI stylesheet.
|
|
19
|
-
|
|
20
|
-
The package installs its Agent UI implementation exactly. Consumers import
|
|
21
|
-
presentation, runtime primitives, providers, hooks, and types through
|
|
22
|
-
`@nadicodeai/ui/agents`; they do not install or import assistant-ui packages
|
|
23
|
-
directly. A protocol-specific runtime adapter remains a direct consumer
|
|
24
|
-
dependency because the application owns transport and message state.
|
|
25
|
-
|
|
26
|
-
Declare `@nadicodeai/design-system` directly only when the app intentionally
|
|
27
|
-
uses a separate public design-system API, such as a font/logo asset or the
|
|
28
|
-
static CSS interface for a separate non-React surface. Pin that direct
|
|
29
|
-
dependency to the version required by the installed
|
|
30
|
-
UI release:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm view @nadicodeai/ui@<exact-version> dependencies.@nadicodeai/design-system
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## CSS interface
|
|
37
|
-
|
|
38
|
-
Import one stylesheet once at the React app root:
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
import "@nadicodeai/ui/globals.css";
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
`@nadicodeai/ui/globals.css` is the complete React style interface. It composes
|
|
45
|
-
Tailwind v4, shadcn, and the complete design-system CSS module, and it declares
|
|
46
|
-
the four `nc-elevation-*` utilities over the generated elevation tokens.
|
|
47
|
-
Consumers do not add a second border or ring to package-owned elevated roots.
|
|
48
|
-
Do not import `@nadicodeai/design-system/css`, generated theme files, or CSS
|
|
49
|
-
partials beside it. The package declares its own built component sources; Tailwind's
|
|
50
|
-
normal automatic detection covers the consumer application. The app still owns
|
|
51
|
-
its PostCSS configuration, theme provider, and persisted mode preference.
|
|
52
|
-
|
|
53
|
-
That stylesheet also delivers the brand typeface. The design-system CSS module
|
|
54
|
-
declares the `@font-face` rules for Geist and Geist Mono and loads the packaged
|
|
55
|
-
woff2 files, so a consuming app must not add its own font loader for those two
|
|
56
|
-
families. A framework loader on top registers a second, differently sourced face
|
|
57
|
-
for the same family names, which downloads the fonts twice and leaves no defined
|
|
58
|
-
winner. Import files under `@nadicodeai/design-system/assets/fonts/*` only when
|
|
59
|
-
the consumer wants the faces without the CSS module; that is one of the
|
|
60
|
-
intentional direct-API cases described above.
|
|
61
|
-
|
|
62
|
-
## Strict ESLint interface
|
|
63
|
-
|
|
64
|
-
The package exports the same design-system rules used by this repository. Add
|
|
65
|
-
the flat config after the consumer's framework and TypeScript configs:
|
|
66
|
-
|
|
67
|
-
```js
|
|
68
|
-
import nadicodeai from "@nadicodeai/ui/eslint";
|
|
69
|
-
|
|
70
|
-
export default [
|
|
71
|
-
// Framework, parser, and TypeScript configs first.
|
|
72
|
-
...nadicodeai.configs["flat/strict"],
|
|
73
|
-
];
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Every rule in this config is an error. The config rejects generated `nc-*`
|
|
77
|
-
utilities that do not exist in the installed design-system release, arbitrary
|
|
78
|
-
radius values that exactly duplicate a generated token, source deep imports,
|
|
79
|
-
raw design values, native visible controls, and appearance overrides on shared
|
|
80
|
-
UI primitives. An arbitrary radius remains valid when no generated radius has
|
|
81
|
-
the same value. Consumers may compose domain-specific components from the
|
|
82
|
-
public UI package; the rules govern package boundaries and design values, not
|
|
83
|
-
the shape of a consumer's JSX tree.
|
|
84
|
-
|
|
85
|
-
## nadicode logo
|
|
86
|
-
|
|
87
|
-
React surfaces name the company with the wordmark from the UI package:
|
|
88
|
-
|
|
89
|
-
```tsx
|
|
90
|
-
import { BrandWordmark } from "@nadicodeai/ui/components/brand";
|
|
91
|
-
|
|
92
|
-
<BrandWordmark alt="nadicode" />;
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Use `BrandMark`, the plain n, where the name does not fit. The n is cut from the
|
|
96
|
-
wordmark, so never place the two together. Static consumers that need files
|
|
97
|
-
instead of React declare the design-system dependency directly and use the
|
|
98
|
-
documented SVG or PNG package routes in `packages/design-system/README.md`.
|
|
99
|
-
|
|
100
|
-
## Base UI API breaks (migrating from Radix-era components)
|
|
101
|
-
|
|
102
|
-
`@nadicodeai/ui@0.5.0+` is Base UI only; the Radix-era compatibility layer is
|
|
103
|
-
gone. Full catalog and rationale: `docs/migration/base-ui-migration.md`. What
|
|
104
|
-
a consumer actually hits when porting call sites:
|
|
105
|
-
|
|
106
|
-
- No `asChild`. Use Base UI's `render` prop; when the rendered element isn't
|
|
107
|
-
a native `<button>`, also pass `nativeButton={false}`.
|
|
108
|
-
- Menu items (`DropdownMenuItem`, `ContextMenuItem`, `MenubarItem`) use
|
|
109
|
-
`onClick`, not `onSelect`.
|
|
110
|
-
- State attributes are `data-checked`/`data-unchecked` and
|
|
111
|
-
`data-open`/`data-closed`, not a single `data-state` value.
|
|
112
|
-
- `Accordion` and `ToggleGroup` values are always arrays — pass `multiple`
|
|
113
|
-
for multi-select instead of `type="single" | "multiple"`.
|
|
114
|
-
- `TooltipProvider` takes `delay`, not `delayDuration`.
|
|
115
|
-
- Disclosure panels (`CollapsibleContent`, etc.) take `keepMounted`, not
|
|
116
|
-
`forceMount`.
|