Jede Komponente hat eine Persönlichkeit, die du ändern kannst: die Feder, mit der sie sich bewegt, was ein Button unter deinem Finger macht, wie Dialoge und Menüs erscheinen, Form und Größe ihrer Ecken und wie viel Platz sie einnimmt. Jede dieser Eigenschaften ist ein Attribut für alles innerhalb eines Elements oder ein Input für eine einzelne Komponente.

Ein Attribut, ein ganzer Teilbaum

Setze die data-nui-*-Attribute für die ganze App auf <body> oder für einen Teil davon auf ein beliebiges Element. Es gilt jeweils das nächstgelegene, deshalb lassen sie sich verschachteln. Sie setzen nur CSS Custom Properties und funktionieren daher mit jedem Framework gleich – oder ganz ohne.

customize.html
<body data-nui-motion="bouncy" data-nui-corners="squircle">
<!-- Everything here bounces and has squircle corners… -->
<main data-nui-press="squish" data-nui-density="compact">
<!-- …buttons in here squish, and controls are compact… -->
</main>
<aside data-nui-motion="none" data-nui-radius="none">
<!-- …and nothing in here moves or has rounded corners. -->
</aside>
</body>

Eine einzelne Komponente

In Angular nehmen nuiButton, nuiDialog und nuiMenu dieselben Werte als Inputs entgegen. Inputs, die du nicht setzt, richten sich nach den Attributen der umgebenden Elemente.

customize-inputs.html
<button nuiButton press="rubber" motion="elastic">Boing</button>

<dialog nuiDialog [(open)]="editing" enter="flip" corners="squircle">…</dialog>

<button nuiButton [nuiMenuTrigger]="actions">Actions</button>
<div nuiMenu #actions="ngMenu" enter="unfold" motion="mechanical">…</div>

Federn, zu CSS kompiliert

Bewegung ist Federphysik: Steifigkeit, Dämpfung und Masse statt einer Dauer und einer Kurve. Der Token-Compiler berechnet jede Feder und schreibt sie als Dauer bis zum Stillstand und linear()-Easing ins CSS, sodass sie ohne JavaScript auf dem Compositor läuft. Sechs Federn werden als Tokens mitgeliefert, von --nui-spring-snappy bis --nui-spring-mechanical, und --nui-motion enthält die jeweils verwendete.

Jede andere Feder ist nur einen Input entfernt. Angular kompiliert sie zur Laufzeit mit demselben Solver, und springTransition() liefert dir das CSS für deine eigenen Elemente.

customize-spring.ts
import { springTransition } from '@needless-ui/angular';

// In a template, any spring is an input:
// <button nuiButton [spring]="{ stiffness: 900, damping: 12 }">Save</button>

// Anywhere else, compile it yourself:
const wobbly = springTransition({ stiffness: 120, damping: 4, mass: 1.2 });
// '4152ms linear(0, 0.014 0.41%, …, 1)'

const card = document.querySelector<HTMLElement>('.card')!;
card.style.transition = `transform ${wobbly}`;

Alles dazwischen

Die Presets sind nur Abkürzungen. Für alles andere setzt du die Custom Properties selbst: beliebige Transformationen für --nui-press und --nui-enter, beliebige Zahlen für --nui-radius-scale und --nui-density.

customize.css
.checkout {
--nui-motion: var(--nui-spring-jelly);
--nui-press: scale(0.92) rotate(-2deg);
--nui-enter: translateY(100%);
--nui-radius-scale: 1.5;
--nui-density: 1.1;
}

Barrierefreiheit

Wünscht das System reduzierte Bewegung, schrumpfen Federn auf einen Augenblick zusammen, und Druckeffekte und Eingangsanimationen bewegen sich nicht mehr. Die Dichte drückt kein Bedienelement unter die Mindestzielgröße der WCAG 2.2 von 24 px, und kein Preset verändert Farben, sodass jede Kontrastprüfung weiterhin gilt. Browser ohne corner-shape zeichnen alle Ecken rund.