@nadicodeai/design-system 7.1.3 → 8.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.
- package/DESIGN.md +48 -36
- package/package.json +1 -1
package/DESIGN.md
CHANGED
|
@@ -333,12 +333,12 @@ Every value a role needs is carried by the role token itself; there is no numeri
|
|
|
333
333
|
- **Semantic feedback** (`{colors.success}` = verde with `{colors.success-soft}`/`{colors.success-deep}`; `{colors.error}` = rosso funzionale `#d3302f` with `{colors.error-soft}`/`{colors.error-deep}`; `{colors.warning}` = giallo `#ffc220` with `{colors.warning-soft}`/`{colors.warning-deep}`; `{colors.info}` = cobalto `#1e3cff` with `{colors.info-soft}`/`{colors.info-deep}`): validation, caution, approval, and operational feedback. In each pair the `-soft` value is the tinted tag/banner ground and the `-deep` value is the AA-clearing text on it. On a solid `error` fill (the shadcn `destructive` role) text is white; on a solid `warning` or `success` fill text is ink. The success pair intentionally reuses the link pair's AA-safe verde values; its feedback meaning remains distinct from inline navigation and entity-status semantics.
|
|
334
334
|
- **Accent** (`{colors.accent}` = arancio `#ff5a1f`): a small emphasis mark for exception flags and highlights; it appears as a mark, carries no text, and paints no fill or background. The identically-named shadcn surface role is a different thing — a neutral (`{colors.canvas-soft-2}` light, `{colors.dark-canvas-soft-2}` dark) with no hue.
|
|
335
335
|
- **Verde vivo** (`{colors.verde-vivo}` = `#008c45`, dark `{colors.dark-verde-vivo}` = `#62d494`): Nadia's presence accent. It paints the marks that say *Nadia herself is here*, such as the success beat over her silhouette on Nadia's entry screen. It is a mark colour, never a control fill, a text colour, a link, or a status; `action`, `link`, and `success` keep their jobs. It clears the 3:1 non-text floor on `{colors.canvas}` (4.3:1) and `{colors.dark-canvas}` (11.4:1) and carries no text of its own. White on it is 4.34:1, below AA for normal text, so a label never sits on a `verde-vivo` fill; the ring, halo, or portrait sits on it and the words sit on the canvas.
|
|
336
|
-
- **Workflow States** (`{colors.state-ready}` neutral, `{colors.state-running}` cobalto, `{colors.state-review}` giallo, `{colors.state-blocked}` rosso, `{colors.state-complete}` verde): the left-border/state vocabulary for agentic work surfaces — cobalto means in motion, verde means done. The dark counterparts (`{colors.dark-state-ready}`, `{colors.dark-state-running}`, `{colors.dark-state-review}`, `{colors.dark-state-blocked}`, `{colors.dark-state-complete}`) keep the same functional identity. These colours are carried by non-text state accents only — meter
|
|
336
|
+
- **Workflow States** (`{colors.state-ready}` neutral, `{colors.state-running}` cobalto, `{colors.state-review}` giallo, `{colors.state-blocked}` rosso, `{colors.state-complete}` verde): the left-border/state vocabulary for agentic work surfaces — cobalto means in motion, verde means done. The dark counterparts (`{colors.dark-state-ready}`, `{colors.dark-state-running}`, `{colors.dark-state-review}`, `{colors.dark-state-blocked}`, `{colors.dark-state-complete}`) keep the same functional identity. These colours are carried by non-text state accents only — meter fills, delta marks, and the brand book's own rails; label text stays on the neutral foreground roles for contrast in both themes. Status is not one of their jobs: every status the product renders is the Badge status vocabulary (see `## Status Vocabulary`), which reads from the semantic feedback and link pairs, and the two token sets never cross.
|
|
337
337
|
|
|
338
338
|
### Chart categoricals (functional tier)
|
|
339
339
|
|
|
340
|
-
- **Charts** (`{colors.chart-1}`…`{colors.chart-6}`): the categorical series palette — cobalto, verde, giallo, rosso, plus a functional-only teal and viola. Chart colours belong to data surfaces only; identity planes and generated imagery draw from the Agent identity palette. Two light slots are series-tuned so the set clears the categorical data bands on the white data surface: `chart-3` steps the giallo darker (the identity giallo `{colors.identity-giallo}` overshoots the categorical lightness band and reads too pale as a mark) and `chart-5` makes the teal more chromatic (the raw functional teal otherwise sits under the chroma floor and reads gray). The darker giallo still falls below the 3:1 mark-contrast line and is carried by the always-on legend
|
|
341
|
-
- **Categorical distinguishability**: the same-family neighbours are held apart — `chart-3`/`chart-4` (giallo/rosso) and `chart-2`/`chart-5` (verde/teal) each clear a CIEDE2000 ≥ 20 normal / ≥ 15 deuteranopia-simulated floor, in the light set and the dark-tuned set alike. Two proximities are brand-locked and exempt from the numeric floor: `chart-2`/`chart-4` (verde/rosso, the flag pair, which collapses under red-green deficiency by identity) and `chart-1`/`chart-6` (cobalto/viola, adjacent blue-violet). Charts using the full six carry redundant encoding (
|
|
340
|
+
- **Charts** (`{colors.chart-1}`…`{colors.chart-6}`): the categorical series palette — cobalto, verde, giallo, rosso, plus a functional-only teal and viola. Chart colours belong to data surfaces only; identity planes and generated imagery draw from the Agent identity palette. Two light slots are series-tuned so the set clears the categorical data bands on the white data surface: `chart-3` steps the giallo darker (the identity giallo `{colors.identity-giallo}` overshoots the categorical lightness band and reads too pale as a mark) and `chart-5` makes the teal more chromatic (the raw functional teal otherwise sits under the chroma floor and reads gray). The darker giallo still falls below the 3:1 mark-contrast line and is carried by the always-on legend and the paired table the charting method already mandates — never a per-surface patch. On the dark canvas all six series carry dark-tuned steps (`{colors.dark-chart-1}`…`{colors.dark-chart-6}`), remapped in the `.dark` scope so any consumer reading the semantic token gets the right hue in both modes. Clearing the 3:1 WCAG 1.4.11 data-mark floor is necessary but not sufficient on the black canvas: full-strength hues read as loud blocks there, so each dark step lightens or desaturates while keeping series identity — the dark giallo and teal deliberately stay bright to hold their per-series deuteranopia separation from rosso — and all six clear 3:1 against `{colors.dark-canvas}`.
|
|
341
|
+
- **Categorical distinguishability**: the same-family neighbours are held apart — `chart-3`/`chart-4` (giallo/rosso) and `chart-2`/`chart-5` (verde/teal) each clear a CIEDE2000 ≥ 20 normal / ≥ 15 deuteranopia-simulated floor, in the light set and the dark-tuned set alike. Two proximities are brand-locked and exempt from the numeric floor: `chart-2`/`chart-4` (verde/rosso, the flag pair, which collapses under red-green deficiency by identity) and `chart-1`/`chart-6` (cobalto/viola, adjacent blue-violet). Charts using the full six carry redundant encoding (the legend, position, or the paired table), never hue alone, so these two pairs stay readable under colour-vision deficiency.
|
|
342
342
|
|
|
343
343
|
### Agent identity palette
|
|
344
344
|
|
|
@@ -356,6 +356,24 @@ This achromatic-neutral discipline is not dark-specific: it governs the generate
|
|
|
356
356
|
|
|
357
357
|
## Data Visualization
|
|
358
358
|
|
|
359
|
+
### Chart source
|
|
360
|
+
|
|
361
|
+
Every chart and KPI card is a stock shadcn component. They are pulled from the registry at `https://ui.shadcn.com/r/styles/new-york-v4/<name>.json`, because the `base-nova` style this system uses publishes no chart gallery. The KPI card is the `dashboard-01` block's `section-cards`. `@nadicodeai/ui` owns the pulled files and the card frame each one renders; a page never assembles a chart card by hand and never reaches into a chart's internals from its call site.
|
|
362
|
+
|
|
363
|
+
These are the deviations from what the registry ships. The list is complete: a change to a pulled chart that is not here is drift, and `packages/ui/tests/guards/chart-kit.test.ts` holds each one.
|
|
364
|
+
|
|
365
|
+
1. **Value formatting.** `valueFormatter` prints the exact figure in the tooltip, in the units the surface uses. `axisFormatter` prints the axis as a scale (`1.6B`, `800M`, `$7.5`), because an axis is read for magnitude and a full figure on every tick crowds it.
|
|
366
|
+
2. **Color by entity.** A series takes its color from the entity-color map below, never from its position in the series array. See "Entity-color assignment".
|
|
367
|
+
3. **Value axis.** Always drawn, with five ticks handed to the axis on a 1, 2, 2.5, 5, or 10 step. Left to itself Recharts chooses its own count, and a rounded label then sits on an unrounded position.
|
|
368
|
+
4. **Bar width.** Bars cap at 48px. Stock has no cap, and one category drew a bar the width of the card.
|
|
369
|
+
5. **Reading aids.** The grid is dashed in both directions. The tooltip uses the stock line indicator, with a gap between a row's name and its value so a long name cannot run into the figure. Every multi-series chart has a legend below the plot, left-aligned, a round dot and a name, in the order of the series it names; the stock area and grouped-bar blocks ship without one, and Recharts sorts legend items by key.
|
|
370
|
+
6. **Share of a total.** `chart-bar-stacked` has a `share` layout: one bar split to 100% (`stackOffset="expand"`), for a breakdown with no time axis.
|
|
371
|
+
7. **A chart is a named section.** The card title is a heading at the level the page gives it, and it names the plot through `aria-labelledby`. The plot shows a focus ring while it has keyboard focus: stock hides the outline of the svg that Recharts' `accessibilityLayer` makes focusable.
|
|
372
|
+
|
|
373
|
+
Two things beside the charts also differ from stock. `Progress` takes a `tone` (default, warning, critical) and paints over-cap as a full critical bar. The pulled charts share one card frame, `chart-card`, in place of each file repeating it.
|
|
374
|
+
|
|
375
|
+
Everything else is the registry's: bar geometry and corner radius, tooltip and legend content, animation, and the recharts `accessibilityLayer` as shadcn ships it. This contract mandates no custom mark geometry, no segment gap, and no hidden table twin of a chart.
|
|
376
|
+
|
|
359
377
|
### Entity-color assignment
|
|
360
378
|
|
|
361
379
|
- **Entity-color assignment**: categorical hues (`{colors.chart-1}`…`{colors.chart-6}`) assign in fixed order to entities per page context, and the assignment follows the entity identity, never rank, sort position, or array index. One assignment map exists per surface: the same entity keeps the same color in a chart and its paired table, whether the chart uses one categorical bar per entity or a time series per entity. A filter or re-sort never repaints the entities that remain on screen. Beyond six entities, fold the tail into a single neutral "other" slot (`{colors.muted}` register), never a seventh hue.
|
|
@@ -365,39 +383,33 @@ This achromatic-neutral discipline is not dark-specific: it governs the generate
|
|
|
365
383
|
- **Sequential ramp** (`{colors.chart-seq-1}`…`{colors.chart-seq-5}`, a single cobalto hue running light→dark): ordered magnitude on one hue, never nominal categories, never a rainbow. `{colors.dark-chart-seq-1}`…`{colors.dark-chart-seq-5}` remap in the `.dark` scope like the categorical set, anchor flipped so `dark-chart-seq-1` is the dimmest step and `dark-chart-seq-5` the brightest, each clearing the 3:1 WCAG 1.4.11 data-mark floor against `{colors.dark-canvas}`.
|
|
366
384
|
- **Diverging pair** (`{colors.chart-div-warm}` giallo/amber, `{colors.chart-div-mid}` a neutral mid, `{colors.chart-div-cool}` cobalto; dark counterparts `{colors.dark-chart-div-warm}`, `{colors.dark-chart-div-mid}`, `{colors.dark-chart-div-cool}` remapped in the `.dark` scope the same way): the warm and cool poles carry the sign, the neutral midpoint never carries hue. Meter tracks use a lighter step of the same ramp as their fill.
|
|
367
385
|
|
|
368
|
-
### Meter
|
|
369
|
-
|
|
370
|
-
A meter describes magnitude. The product defines its tone's semantic scope:
|
|
371
|
-
the condition of the measured allowance, for example, or an operational access
|
|
372
|
-
state. Those meanings are not interchangeable. Keep the measure, tone, label,
|
|
373
|
-
and explanation consistent with the chosen scope; a ratio reaching its end
|
|
374
|
-
does not independently establish the state of another capability. The
|
|
375
|
-
foundation does not choose a product's colour entry screens or reinterpret a
|
|
376
|
-
recorded balance as an access guarantee.
|
|
386
|
+
### Meter grammar
|
|
377
387
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
meter maximum. Colour reinforces its defined meaning; it is never the
|
|
384
|
-
only explanation.
|
|
388
|
+
A meter describes magnitude. The carrier is the stock shadcn `Progress`, with
|
|
389
|
+
one `tone` variant: default, warning, or critical. There is no second meter
|
|
390
|
+
geometry, no cap tick, and no separate overflow segment. A value over its cap
|
|
391
|
+
reads as a full bar in the critical tone beside the printed figure, which is
|
|
392
|
+
what states the overage.
|
|
385
393
|
|
|
386
|
-
|
|
394
|
+
The product defines its tone's semantic scope: the condition of the measured
|
|
395
|
+
allowance, for example, or an operational access state. Those meanings are not
|
|
396
|
+
interchangeable. Keep the measure, tone, label, and explanation consistent with
|
|
397
|
+
the chosen scope; a ratio reaching its end does not independently establish the
|
|
398
|
+
state of another capability. The foundation does not choose a product's color
|
|
399
|
+
entry screens or reinterpret a recorded balance as an access guarantee.
|
|
387
400
|
|
|
388
|
-
|
|
401
|
+
A meter keeps an accessible name, the real textual value beside it, and `aria`
|
|
402
|
+
values bounded to the meter maximum. Color reinforces its defined meaning; it
|
|
403
|
+
is never the only explanation.
|
|
389
404
|
|
|
390
405
|
### Delta and trend encoding
|
|
391
406
|
|
|
392
|
-
- **Delta and trend encoding**: a change reads as a
|
|
407
|
+
- **Delta and trend encoding**: a change reads as a shadcn `Badge` in its `outline` variant carrying a lucide trend icon (`TrendingUp`, `TrendingDown`, or `Minus`) and the signed value, followed by the muted phrase "vs {period}" that names what the change is measured against. Never bare signed text, never color alone, and never a ▲ or ▼ glyph. The icon carries the direction; tone follows direction crossed with whether up is good in that context, and a delta whose direction means nothing good or bad stays neutral. Sparklines normalize against a meaningful baseline, never the visible min-max span alone. A ranked "what moved" list uses the same badge as the KPI card, and a figure with no comparison shows no badge rather than a zero change.
|
|
393
408
|
|
|
394
409
|
### Legends and labels
|
|
395
410
|
|
|
396
|
-
- **Legends and labels**: at two or more series
|
|
397
|
-
|
|
398
|
-
### Texture fallback
|
|
399
|
-
|
|
400
|
-
- **Texture fallback**: under forced-colors, print, or an accessibility setting, series distinguish by one directional line texture at 45 or 135 degrees (tone-on-tone, a darker step of the fill's own ramp), ordered with magnitude on value scales, with the arm angle carrying the diverging sign. Texture is never on by default. The two brand-locked categorical pairs (`chart-2`/`chart-4`, `chart-1`/`chart-6`) always require redundant encoding, never hue alone, restating the Chart categoricals distinguishability rule.
|
|
411
|
+
- **Legends and labels**: at two or more series the legend is the registry's `ChartLegendContent`, placed below the chart, left-aligned, and wrapping to a second line. It carries a color dot and the entity name, and nothing else: no maker's mark, no logo tile, no value, no share. A model's mark appears beside its name in tables and lists, where the mark identifies the model (rule `model-shown-with-logo`), never inside a legend. Legend, axis, and label text carries ink tokens (`{colors.ink}`, `{colors.muted}`) and never wears the series color. A single series is titled, not legended. Tooltips enhance a chart and never gate a value.
|
|
412
|
+
- **Accessible alternative**: the chart's accessibility comes from the stock `accessibilityLayer`. A chart ships no visually hidden table twin of itself. Where a page needs the numbers as text, it shows a real table or list that the reader can see, built from the same result the chart reads.
|
|
401
413
|
|
|
402
414
|
## Typography
|
|
403
415
|
|
|
@@ -563,10 +575,10 @@ The material and elevation values are authored in the one `json design-tokens` f
|
|
|
563
575
|
| Material role | Construction | Use |
|
|
564
576
|
| ------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
565
577
|
| Workspace | `dotted-field` on `{colors.material-workspace}` / `{colors.dark-material-workspace}`; no edge or shadow | The continuous work area behind product objects |
|
|
566
|
-
| Resting | Solid fill; `nc-elevation-resting` with its own ring; `{rounded.
|
|
567
|
-
| Raised | Same solid fill; `nc-elevation-raised`; `{rounded.
|
|
568
|
-
| Floating | Same solid fill; `nc-elevation-floating`;
|
|
569
|
-
| Modal | Same solid fill; `nc-elevation-modal`; `{rounded.
|
|
578
|
+
| Resting | Solid fill; `nc-elevation-resting` with its own ring; `{rounded.md}` (6 px) | KPI, card, chart card, table, setting, and persistent content surfaces |
|
|
579
|
+
| Raised | Same solid fill; `nc-elevation-raised`; `{rounded.md}` (6 px) | Active work, a selected object, or an attached inspector above resting siblings |
|
|
580
|
+
| Floating | Same solid fill; `nc-elevation-floating`; `{rounded.md}` (6 px) | Menus, popovers, dropdowns, selects, anchored surfaces, tooltips, and toasts |
|
|
581
|
+
| Modal | Same solid fill; `nc-elevation-modal`; `{rounded.md}` (6 px) | Dialog, sheet, drawer, and takeover |
|
|
570
582
|
| Glass control | Translucent solid fill at 76%, 28 px backdrop blur, and the rung for its physical level with that rung's ring | Floating chrome above our own content: menus, popovers, selects, comboboxes, the command palette, and bars; never a content container |
|
|
571
583
|
|
|
572
584
|
`Card` is the fundamental product container. Its content does not create a second material family: KPIs, Agent cards, settings, and ordinary grouped content use the resting role unless the object is physically raised. Interaction variants may change state or emphasis without changing the material role.
|
|
@@ -581,14 +593,14 @@ On coarse or non-hover input capability, every interactive target is at least 44
|
|
|
581
593
|
|
|
582
594
|
## Shapes
|
|
583
595
|
|
|
584
|
-
|
|
596
|
+
One radius rounds every surface. The reference is the search field: `{rounded.md}` (6 px). A surface never earns a larger corner by sitting higher on the elevation ladder, and no register may reintroduce a second surface radius.
|
|
585
597
|
|
|
586
|
-
- Use `{rounded.
|
|
587
|
-
- Use `{rounded.
|
|
588
|
-
- Use `{rounded.2xl}` (12 px) for compact menus, popovers, dropdowns, and anchored floating surfaces.
|
|
589
|
-
- Use `{rounded.3xl}` (16 px) for resting and raised product content surfaces, detached inspectors, modal dialogs, inset sheets, and takeovers.
|
|
598
|
+
- Use `{rounded.md}` (6 px) for every surface and every control: resting, raised, outlined, floating, and modal surfaces; cards, KPI cards, chart cards, tables, menus, selects, popovers, dropdowns, dialogs, sheets, drawers, takeovers, tooltips, toasts, inspectors; and buttons, inputs, chips, status tags, and small artifacts.
|
|
599
|
+
- Use `{rounded.none}` for structural page rows, frame edges, grid cells, and structural modules.
|
|
590
600
|
- Use `{rounded.full}` only for intrinsically circular identity/avatar chrome and compact control marks whose geometry is inherently round or pill-shaped. It never turns a content surface, button, badge, or navigation item into a pill by default.
|
|
591
601
|
|
|
602
|
+
The radius scale itself is unchanged: `{rounded.xs}` through `{rounded.3xl}` stay exported for inner marks and for geometry a component owns, such as a progress track or a bar end. Only the rung that surfaces take is fixed.
|
|
603
|
+
|
|
592
604
|
Public page-grammar cells are not cards and remain square because their parent frame supplies the visual system. Product cards use the resting material role. A details composition may divide its header and bound individual facts with the outlined role; each edge has one owner and fact cells add no elevation. Grouping does not justify another ring around the same container or a stronger shadow.
|
|
593
605
|
|
|
594
606
|
## Motion
|