هر کامپوننت شخصیتی دارد که می‌توانید تغییرش دهید: فنری که با آن حرکت می‌کند، کاری که دکمه زیر انگشت شما انجام می‌دهد، نحوهٔ ظاهر شدن دیالوگ‌ها و منوها، شکل و اندازهٔ گوشه‌هایشان و فضایی که اشغال می‌کنند. هر کدام از این‌ها یا یک اتریبیوت است برای همهٔ محتوای درون یک عنصر، یا یک ورودی برای یک کامپوننت خاص.

یک اتریبیوت، یک زیردرخت کامل

اتریبیوت‌های data-nui-* را برای کل اپ روی <body> بگذارید، یا برای بخشی از آن روی هر عنصر دلخواه. نزدیک‌ترین اتریبیوت برنده است؛ پس می‌توانید آن‌ها را تودرتو کنید. این اتریبیوت‌ها فقط متغیرهای CSS را تنظیم می‌کنند؛ برای همین با هر فریم‌ورکی، یا حتی بدون فریم‌ورک، یکسان کار می‌کنند.

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>

یک کامپوننت

در Angular، دایرکتیوهای nuiButton، nuiDialog و nuiMenu همین مقادیر را به‌صورت ورودی می‌گیرند. ورودی‌هایی که تنظیمشان نکنید، از اتریبیوت‌های پیرامونشان پیروی می‌کنند.

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>

فنرها، کامپایل‌شده به CSS

حرکت در اینجا فیزیک فنر است: سختی، میرایی و جرم به‌جای مدت‌زمان و منحنی. کامپایلر توکن‌ها معادلهٔ هر فنر را حل می‌کند و آن را به شکل زمان لازم برای آرام گرفتن و یک تابع زمان‌بندی linear() در CSS می‌نویسد؛ به این ترتیب حرکت بدون JavaScript روی کامپوزیتور (compositor) اجرا می‌شود. شش فنر به‌صورت توکن ارائه می‌شوند، از --nui-spring-snappy تا --nui-spring-mechanical، و --nui-motion فنری را که در حال استفاده است نگه می‌دارد.

هر فنر دیگری هم فقط با یک ورودی در دسترس است. Angular آن را در زمان اجرا با همان حل‌کننده کامپایل می‌کند و springTransition() کد CSS لازم را برای عناصر خودتان در اختیارتان می‌گذارد.

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}`;

هر چیزی در این میان

پیش‌تنظیم‌ها فقط میان‌بر هستند. برای هر چیز دیگری، متغیرهای CSS را خودتان تنظیم کنید: هر transform دلخواه برای --nui-press و --nui-enter، و هر عددی برای --nui-radius-scale و --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;
}

دسترس‌پذیری

وقتی سیستم درخواست کاهش حرکت می‌کند، فنرها آنی می‌شوند و جلوه‌های فشردن و انیمیشن‌های ورود دیگر حرکتی ندارند. تراکم هرگز یک کنترل را کوچک‌تر از اندازهٔ هدف ۲۴ پیکسلی WCAG 2.2 نمی‌کند و هیچ پیش‌تنظیمی به رنگ‌ها دست نمی‌زند؛ پس همهٔ بررسی‌های کنتراست همچنان معتبرند. مرورگرهایی که از corner-shape پشتیبانی نمی‌کنند، همهٔ گوشه‌ها را گرد رسم می‌کنند.