Mundarija (43)
- Bu darsda
- 1. Nega bu kerak?
- 2. shadcn/ui qanday ishlaydi
- 2.1 To'rt qism
- 2.2 Registr elementi ichida
- 2.3 Asos: Radix yoki Base UI
- 3. Tailwind v4 vazifalar da
- 3.1 O'rnatish
- 3.2 Preflight'siz kirish
- 3.3 Nega eski CSS qatlamda bo'lishi shart
- 4. Tokenlar @theme ga
- 4.1 18-qism tokenlari Tailwind nomlar fazosida
- 4.2 Qorong'i rejim: light-dark() qatlamda
- 4.3 shadcn'ning tema usuli
- 5. cva va cn(): Tugma
- 5.1 Variantlar jadvali
- 5.2 Tur jadvaldan keladi
- 5.3 cn() = faqat clsx
- 5.4 asChild: shadcn Button ichida
- 6. @/ alias va components.json
- 6.1 Alias — to'rt joyda
- 6.2 components.json
- 7. shadcn CLI: haqiqiy oqim va tuzoqlar
- 7.1 init Tailwind'ni topmadi
- 7.2 add: fayllar bor, lekin…
- 7.3 To'g'ri oqim
- 7.4 Yangilash muammosi
- 8. Vazifalar qadami: Tailwind v4 va Tugma (holat 02)
- 8.1 Branch va paketlar
- 8.2 Fayllar
- 8.3 src/ui/cn.ts
- 8.4 src/ui/Tugma.tsx
- 8.5 Natija
- 8.6 Commit
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): bo'sh joylarni to'ldiring
- 2-mashq (o'rta): «Bahor» nishoni
- 3-mashq (qiyin): Tugma ga asChild
- 4-mashq: vazifalar qadami
- 11. Real ishda
- Xulosa
- Manbalar
shadcn/ui I: qanday ishlaydi va sozlash — Tailwind v4, cn, cva va CLI
Qisqacha: shadcn/ui — npm paket emas.
npx shadcn add buttonbuyrug'i registrdan komponent kodini olib,src/papkangizga yozadi. Bu kod to'rt narsaga tayanadi: Tailwind sinflari, CSS o'zgaruvchilaridagi tokenlar,cn()yordamchisi va@/alias. Ularni loyihada qayerda topishni CLIcomponents.jsonfaylidan o'qiydi. CLI kodni ko'chiradi, lekin versiyani tekshirmaydi — eng yangi paketni^bilan qo'shishi mumkin. Shuning uchun haradddan keyingit diffo'qiladi va versiyalar qotiriladi.
Bu darsda
- shadcn/ui'ning to'rt qismini (registr, CLI,
components.json, sizning fayllaringiz) va ular qanday bog'lanishini tushuntirasiz. vazifalarga Tailwind v4 ni preflight'siz ulaysiz va 18-qism tokenlarini@themega ko'chirasiz — ko'rinish bir pikselga ham o'zgarmaydi.Tugmanicvabilan qayta yozasiz,cn()nega faqatclsxekanini raqam bilan asoslaysiz.@/alias vacomponents.jsonni sozlaysiz, shadcn CLI'ning haqiqiy chiqishidagi to'rt tuzoqni taniysiz.
Oldin bilishingiz kerak: UI kutubxonalar xaritasi, Tailwind CSS 3: @theme, Tailwind CSS 4: cn(), cva, Path alias, Dizayn tizimi: tokenlar.
1. Nega bu kerak?
O'tgan darsda copy-paste yondashuvini ko'rdik: kod src/ ga ko'chadi va sizniki bo'ladi. Keyingi darsda vazifalar ga shu yo'l bilan birinchi komponentni — Radix menyusini qo'shamiz. Lekin bugun buni qilsak, ko'chirilgan fayl ishlamaydi.
Sababi — shadcn komponenti "yolg'iz" emas. Uning bitta qatorini o'qiymiz:
<button className={cn(buttonVariants({ variant }), className)} />Bu qatorda to'rt narsa bor va ularning hech biri vazifalar da hali yo'q:
buttonVariantsichida Tailwind sinflari (bg-primary,h-9) — Tailwind ulanmagan bo'lsa, ular oddiy so'z bo'lib qoladi.bg-primary— token: rang qiymati CSS o'zgaruvchisida turadi.cn()—import { cn } from "@/lib/utils"dan keladi.@/— papka taxallusi (alias): sozlanmasa, import topilmaydi.
Hayotiy o'xshatish: yangi oshxona jihozini olib keldingiz. Ishlashi uchun uyda to'g'ri rozetka, quvur va joy kerak. Avval uyni tayyorlaysiz, keyin jihozni ulaysiz. Bu dars — "uyni tayyorlash".
2. shadcn/ui qanday ishlaydi
2.1 To'rt qism
sequenceDiagram
participant D as Siz
participant C as shadcn CLI
participant J as components.json
participant R as Registr
D->>C: npx shadcn add dropdown-menu
C->>J: papkalar, alias, stil?
C->>R: dropdown-menu.json
R-->>C: fayllar matni + bog'liqliklar
C->>D: src/ui/dropdown-menu.tsx
C->>D: npm install (bog'liqliklar)Nimaga qarang: CLI hech narsani "o'rnatmaydi" — u fayl yozadi va npm'ni chaqiradi. Qaysi papkaga yozishni, importlarni qanday yozishni components.json dan oladi.
- Registr — komponentlar katalogi (o'tgan darsda tanishdik). Har komponent — bitta JSON.
- CLI —
npx shadcn@<versiya>(npx — paketni o'rnatmasdan bir marta ishga tushirish). components.json— loyihangiz haqida CLI uchun "pasport".- Sizning fayllaringiz — CLI yozib bo'lgach, ular oddiy kod. CLI ularni boshqa kuzatmaydi.
2.2 Registr elementi ichida
Registrdagi bitta komponent — radix-nova uslubidagi dropdown-menu. Uni ui.shadcn.com dan o'qidik (2026-10-17; content — fayl matni, qisqartirilgan):
{
"name": "dropdown-menu",
"type": "registry:ui",
"dependencies": ["cn"],
"files": [
{
"path": "registry/radix-nova/ui/dropdown-menu.tsx",
"type": "registry:ui",
"content": "\"use client\" … import { cn } from \"cn\" …"
}
]
}Nimaga qarang: JSON — oddiy ma'lumot, fayl matni uning ichida satr bo'lib turibdi.
dependencies— npm paketlar, CLI ularni o'rnatadi. Bu yerda faqatcn— nega, «shadcn CLI» bo'limida ko'ramiz.files— fayl matnlari, CLI ularni yozadi.
content boshidagi import { cn } from "cn" ni eslab qoling — u keyinroq tuzoq bo'lib chiqadi. Fayl ichidagi importlar (@/…) yozishdan oldin components.json dagi alias'larga moslanadi — hech bo'lmasa shunday bo'lishi kerak. Kanonda bu va'da to'liq bajarilmadi — «shadcn CLI» bo'limida ko'ramiz.
2.3 Asos: Radix yoki Base UI
shadcn/ui ikki headless kutubxona ustida ishlaydi. init da tanlanadi: -b radix yoki -b base. shadcn 4 ning standarti — Base UI. O'tgan darsdagi o'lchovni eslang: Base UI varianti — 93.2 KB va 0 CSP buzilishi, Radix + sonner — 90.8 KB va 4 buzilish.
vazifalar kanoni baribir Radix da qoldi. Sababi: keyingi ikki dars Radix'ning o'zi haqida (shadcn/ui II, Radix chuqur). Menyuni modal={false} bilan ishlatsak, Radix ham CSP'ni buzmaydi — o'lchovi Radix chuqur darsida. Buni halol aytamiz: CSP nuqtai nazaridan Base UI yaxshiroq natija ko'rsatdi. Yangi loyihada uni birinchi navbatda sinab ko'ring.
3. Tailwind v4 vazifalar da
3.1 O'rnatish
Tailwind'ni CSS qismida o'rgangansiz. React + Vite loyihasida ulash — o'sha ikki paket:
npm i -D --save-exact tailwindcss@4.3.3 @tailwindcss/vite@4.3.3-D — faqat build uchun: brauzerga paketning o'zi emas, u yasagan CSS boradi. vite.config.ts da plagin (kanondan):
import tailwindcss from "@tailwindcss/vite";
// ...
plugins: [
react(),
// 20/#02: Tailwind CSS v4 — vazifalar.css dagi @import/@theme ni
// qayta ishlaydi, src/ dagi sinflardan faqat ishlatilganlarini
// yozadi
tailwindcss(),
// ...
],3.2 Preflight'siz kirish
Odatdagi kirish — bitta qator: @import "tailwindcss";. U uch qismni ulaydi: tokenlar (theme), preflight (Tailwind'ning reset'i) va utilitalar. vazifalar da preflight'ni ATAYLAB ulamadik. U h1 ni oddiy matn o'lchamiga tushiradi, ro'yxat belgilarini va chegaralarni olib tashlaydi. Bu 18-qismdan beri sozlangan ko'rinishni buzardi.
Kanondagi src/vazifalar.css boshi (izohlar qisqartirilgan):
/* Qatlamlar tartibi: keyingisi oldingisidan ustun */
@layer theme, base, components, utilities;
@import "tailwindcss/theme.css" layer(theme);
/* source("./") — sinflar faqat src/ dan qidiriladi
(testlar, skriptlar va README dagi so'zlar CSS'ga tushmasin) */
@import "tailwindcss/utilities.css" layer(utilities) source("./");
@import "./asos.css" layer(base);Uch qaror:
- Preflight yo'q —
theme.cssvautilities.cssalohida ulanadi (Tailwind hujjatidagi usul). Brauzer tekshiruvi:h1— brauzer standarti, 32 px. source("./")— Tailwind sinf nomlarini faqatsrc/dan qidiradi. Aks holda README'dagi "flex" so'zi ham CSS'ga sinf bo'lib tushardi.- Eski CSS —
asos.cssga,baseqatlamiga. 13–19-qismlardagi hamma qoida shu faylga ko'chdi.
3.3 Nega eski CSS qatlamda bo'lishi shart
Tailwind CSS 3 darsidan eslang: qatlamsiz CSS har qanday qatlamdan ustun. Agar asos.css dagi button { padding: … } qatlamsiz qolsa, tugmaga yozilgan har px-4 utilitasi yutqazadi. Specificity'si kichik bo'lsa ham shunday, chunki qatlam tartibi specificity'dan oldin tekshiriladi.
@import "./asos.css" layer(base) bilan eski qoidalar eng past qatlamga tushdi. Endi utilita yozilgan joyda utilita yutadi, yozilmagan joyda eski qoida ishlaydi. Natija — kanon o'lchovi (natijalar/02-korinish.txt, 412 va 1280 px):
00-v9 → 02: 204/204 element, 3876 xususiyat, farq 0204 element, har birining 19 ta hisoblangan xususiyati (rang, o'lcham, chegara…) Tailwind'dan oldin va keyin solishtirildi — farq 0. Ilova ko'rinishi bir pikselga ham o'zgarmadi.
Tekshirib ko'ring:
@import "./asos.css" layer(base);o'rniga@import "./asos.css";(qatlamsiz) yozilsa,<Tugma className="px-6">ning chap-o'ng bo'shlig'i qancha bo'ladi?
Javob
asos.css dagi button qoidasidagi padding: --spacing(2) --spacing(3) — ya'ni 0.75rem (12 px). Qatlamsiz CSS utilities qatlamidan ustun, shuning uchun px-6 (1.5rem) ishlamaydi. Bunday xato juda chalg'itadi: DevTools'da px-6 ko'rinadi, lekin ustidan chizilgan bo'ladi. Davosi — eski CSS'ni qatlamga qo'yish.
4. Tokenlar @theme ga
4.1 18-qism tokenlari Tailwind nomlar fazosida
Dizayn tizimi darsida tokenlarni :root da e'lon qilgandik. Endi ular @theme ga ko'chdi. Nom — Tailwind nomlar fazosi (namespace) + bizning nom:
| Eski (18/#33) | Yangi (@theme) |
Utilita |
|---|---|---|
--rang-asosiy |
--color-asosiy |
bg-asosiy, text-asosiy |
--burchak |
--radius-burchak |
rounded-burchak |
--bosish (44 px) |
--spacing-bosish |
min-h-bosish |
--joy-2 |
Tailwind'ning --spacing |
p-2 (0.5rem) |
Kanondan (qisqartirilgan):
@theme {
/* standart palitra o'chiriladi: faqat ilova ranglari */
--color-*: initial;
--color-matn: #1f2a24;
--color-yuza: #fff;
--color-asosiy: #1f6f4a;
--color-xato: #b3261e;
--radius-burchak: 0.5rem;
/* Bosiladigan element balandligi: 44 px — WCAG 2.5.5 */
--spacing-bosish: 2.75rem;
}--color-*: initial — Tailwind'ning tayyor palitrasi (red-500, slate-700 …) o'chadi. Endi tasodifiy bg-blue-600 ishlamaydi: CSS'ga hech narsa yozilmaydi. Faqat ilova ranglari qoladi — dizayn tizimini buzish qiyinlashadi.
4.2 Qorong'i rejim: light-dark() qatlamda
18-qismda qorong'i rejim light-dark() va color-scheme bilan qilingan edi. Uni @supports bilan o'ralgan: eski brauzer yorug' zaxirani ko'radi. Lekin @theme ichida @supports yozib bo'lmaydi. Shuning uchun haqiqiy qiymatlar base qatlamida almashtiriladi:
@layer base {
@supports (color: light-dark(white, black)) {
:root {
color-scheme: light dark;
--color-asosiy: light-dark(#1f6f4a, #7fd1a5);
/* ... qolgan ranglar */
}
}
}Bu yerda dark: varianti umuman kerak emas. bg-asosiy doim var(--color-asosiy), o'zgaruvchining qiymati esa rejimga qarab almashadi. Bu — CSS o'zgaruvchilari bilan tema: sinflar o'zgarmaydi, faqat qiymatlar.
4.3 shadcn'ning tema usuli
shadcn ham aynan shu g'oyani ishlatadi, faqat nomlari boshqa. init yozadigan CSS — ui.shadcn.com «Theming» sahifasidagi Tailwind v4 namunasidan (2026-10-17, qisqartirilgan):
:root {
--background: oklch(1 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
}
.dark {
--background: oklch(0.145 0 0);
/* ... */
}
@theme inline {
--color-background: var(--background);
--color-primary: var(--primary);
}Qiymatlar :root va .dark da, @theme inline (C-98 dagi "ko'prik") ularni utilitalarga ulaydi: bg-primary. Qorong'i rejim — .dark klassi bilan. components.json dagi "cssVariables": true — "ranglar CSS o'zgaruvchilarida" degani.
Bizning tokenlar shadcn nomlariga mos emas: bg-primary emas, bg-asosiy. Ikki yo'l bor: shadcn nomlariga o'tish yoki ko'chirilgan komponentdagi sinflarni o'zimiznikiga almashtirish. Kanon ikkinchisini tanladi — 18-qismdan beri butun ilova asosiy, yuza, xato bilan yashaydi. Almashtirishning o'zi keyingi darsda bo'ladi (bg-popover → bg-yuza).
5. cva va cn(): Tugma
5.1 Variantlar jadvali
18-qismda Tugma variantni data-variant atributiga aylantirardi, ranglar esa CSS'da edi. Endi variant to'g'ridan-to'g'ri sinflarga aylanadi — C-99 dagi cva, shadcn'ning Button i ham shu naqshda. Natija oynasida cva va clsx ishlaydi, Tailwind esa yo'q. Shuning uchun quyida tugmalar bezaksiz chiqadi: biz faqat hosil bo'lgan sinf nomlarini konsolda ko'ramiz.
import { cva } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import { clsx } from "clsx";
import type { ClassValue } from "clsx";
import type { ComponentPropsWithoutRef } from "react";
function cn(...classes: ClassValue[]): string {
return clsx(classes);
}
const tugmaSinflari = cva(
"tugma min-h-bosish rounded-burchak border px-3 py-2",
{
variants: {
variant: {
oddiy: "border-chegara bg-yuza text-matn",
asosiy: "border-asosiy bg-asosiy text-asosiy-ustida",
xavfli: "border-xato bg-yuza text-xato",
},
},
defaultVariants: { variant: "oddiy" },
},
);
type Props = ComponentPropsWithoutRef<"button"> &
VariantProps<typeof tugmaSinflari>;
function Tugma({
variant,
type = "button",
className,
...rest
}: Props) {
return (
<button
type={type}
className={cn(tugmaSinflari({ variant }), className)}
{...rest}
/>
);
}
export default function App() {
const logClasses = (el: HTMLDivElement | null) => {
if (!el) return;
for (const b of el.querySelectorAll("button")) {
console.log(b.className);
}
};
return (
<div ref={logClasses}>
<Tugma>Bekor qilish</Tugma>
<Tugma variant="xavfli" className="ml-2">
O'chirish
</Tugma>
</div>
);
}Konsolda:
tugma min-h-bosish rounded-burchak border px-3 py-2 border-chegara bg-yuza text-matn
tugma min-h-bosish rounded-burchak border px-3 py-2 border-xato bg-yuza text-xato ml-2Birinchi tugmada variant berilmadi — defaultVariants dagi oddiy sinflari qo'shildi. Ikkinchisida — xavfli va chaqiruvchi bergan ml-2 (joylashuv). tugma sinfi qoldi: asos.css dagi eski qoidalar va testlar unga tayanadi.
5.2 Tur jadvaldan keladi
VariantProps<typeof tugmaSinflari> — variant ning turi jadvalning o'zidan olinadi. Jadvalga yangi variant qo'shsangiz, tur o'zi kengayadi. Mavjud bo'lmagan variant esa tsc xatosi:
import { cva } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
const tugmaSinflari = cva("tugma", {
variants: { variant: { oddiy: "a", xavfli: "b" } },
});
type Props = VariantProps<typeof tugmaSinflari>;
const props: Props = { variant: "qizil" };Xato:
TS2322: Type '"qizil"' is not assignable to type '"oddiy" | "xavfli" | null | undefined'.Tarjimasi: ""qizil" turi "oddiy" | "xavfli" | null | undefined turiga mos kelmaydi." null ham ruxsat: cva da variant: null — "variant sinfini qo'shma" degani. Tugmaning API'si (Komponent API'sini loyihalash) o'zgarmadi: chaqiruvchilarning birortasiga tegilmadi.
5.3 cn() = faqat clsx
C-99 darsida cn() ni clsx + tailwind-merge deb o'rgangan edik. tailwind-merge to'qnashuvchi sinflardan oxirgisini qoldiradi: cn("px-3", "px-4") → "px-4". Kanondagi cn esa faqat clsx:
import { clsx } from "clsx";
console.log(clsx("px-3", "px-4"));
console.log(clsx("tugma", false && "faol", { xato: true }));Konsolda:
px-3 px-4
tugma xatoIkkala px ham qoldi — qaysi biri yutishini CSS fayldagi tartib hal qiladi. Nega merge yo'q? O'lchadik (natijalar/02-cn-hajm.txt, birinchi yuklash JS, gzip):
- v9 (Tailwind'siz)151,4 KB
- clsx + cva (kanon)151,9 KB
- + tailwind-merge 3.7.0160,6 KB
- shadcn'ning cn 0.4.0 + cva162,8 KB
Manba: O'lchandi: holat 02, Vite 8.3.3, gzip -9, natijalar/02-cn-hajm.txt, 2026-10-14
clsx va cva — atigi +0.5 KB. tailwind-merge yana +8.8 KB qo'shardi: u Tailwind'ning butun sinf tizimini biladigan kichik "tahlilchi". shadcn 4 CLI esa endi cn ni alohida cn paketidan (0.4.0) oladi — cva bilan birga +11.4 KB.
Merge'siz yashash uchun kanon qoidasi (TEXNIK-QARZ.md, 53-band): komponentga className faqat qo'shimcha uchun — joylashuv (ml-2, flex-1). Rang va o'lcham — faqat variant orqali. Shunda to'qnashuvchi sinf umuman berilmaydi. Komponentlar kutubxonasi kattalashsa yoki tashqaridan className bilan bezash kerak bo'lsa, tailwind-merge qo'shiladi.
Tekshirib ko'ring: Kanon qoidasiga ko'ra
<Tugma className="bg-xato">yozish to'g'rimi?
Javob
Yo'q. bg-xato — rang, tugmaSinflari dagi bg-yuza bilan to'qnashadi. Merge yo'q, ikkalasi ham qoladi, yutadigan sinf CSS'dagi tartibga bog'liq — natija tasodifiy. To'g'ri yo'l — variant: variant="xavfli" yoki jadvalga yangi variant qo'shish. className — faqat joylashuv uchun (ml-2).
5.4 asChild: shadcn Button ichida
Polymorphic komponentlar darsida va'da bergan edik: shadcn Button asChild ni Radix Slot bilan qiladi. Natija oynasida @radix-ui/react-slot bor — haqiqiy kutubxona bilan ko'ramiz:
import { Slot } from "@radix-ui/react-slot";
import { clsx } from "clsx";
function Button({ asChild = false, className, ...props }) {
// shadcn naqshi: asChild bo'lsa — o'z tegi yo'q,
// sinflar bolasiga "kiyiladi"
const Comp = asChild ? Slot : "button";
return <Comp className={clsx("tugma", className)} {...props} />;
}
export default function App() {
return (
<nav ref={(el) => el && console.log(el.innerHTML)}>
<Button>Saqlash</Button>
<Button asChild className="havola">
<a href="/menyu">Menyu</a>
</Button>
</nav>
);
}Konsolda:
<button class="tugma">Saqlash</button><a href="/menyu" class="tugma havola">Menyu</a>Ikkinchi "tugma" — aslida <a>. Slot o'z tegini chizmadi, sinflarni bolasiga birlashtirdi: havola tugma ko'rinishida, lekin havola bo'lib qoladi. Shunday qilib Link (React Router) ham <Button asChild> ichida ishlaydi. Tugma kanonda asChild siz — vazifalar da bunga ehtiyoj hali yo'q.
6. @/ alias va components.json
6.1 Alias — to'rt joyda
Path alias darsida @/ ni sinab ko'rib, vazifalar ga qo'shmagan edik: nisbiy yo'llar yetardi. Endi sabab bor — shadcn CLI fayllarni @/ importlari bilan yozadi. O'sha darsdagi qoida: har vosita alias'ni alohida biladi.
| Fayl | Kim uchun | Nima yoziladi |
|---|---|---|
tsconfig.app.json |
tsc, tahrirlovchi | "paths": { "@/*": ["./src/*"] } |
tsconfig.json (ildiz) |
shadcn CLI | xuddi shu paths |
vite.config.ts |
dev va build | resolve.alias |
vitest.config.ts |
komponent testlari | resolve.alias |
Ildiz tsconfig.json — yangilik. U odatda faqat references saqlaydi, lekin shadcn CLI alias'ni aynan shu fayldan qidiradi. Kanonda alias'siz birinchi urinishda CLI "Validating import alias" qadamida to'xtagan. Vite va Vitest tsconfig'ni o'qimaydi — shuning uchun ularda alohida:
resolve: {
alias: {
// import "@/ui/cn.ts" → src/ui/cn.ts (tsconfig.app.json
// "paths" bilan bir xil; Vite tsconfig'ni o'zi o'qimaydi)
"@": resolve(import.meta.dirname, "src"),
},
},Bitta istisno: node --test tekshiradigan sof .ts fayllar nisbiy yo'lda qoladi. Node alias'ni bilmaydi (Path alias darsidagi #/ — Node'ning o'z yo'li). Qoida: @/ — faqat Vite ko'radigan fayllarda.
6.2 components.json
Kanondagi fayl, to'liq:
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "radix-nova",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/vazifalar.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/komponentlar",
"utils": "@/ui/cn",
"ui": "@/ui",
"lib": "@/ui",
"hooks": "@/hooklar"
}
}| Maydon | Ma'nosi |
|---|---|
style |
komponentlar uslubi va asosi: radix-nova — Radix ustidagi shadcn 4 uslubi |
rsc |
React Server Components: false — bizda server komponent yo'q (Next.js qismida) |
tailwind.css |
tokenlar va @import qaysi faylda |
tailwind.config |
bo'sh — v4 da JS konfiguratsiya yo'q |
aliases.ui |
add fayllarni qayerga yozadi: @/ui → src/ui/ |
aliases.utils |
cn qayerdan import qilinadi: @/ui/cn |
iconLibrary: "lucide" — komponentlar ichidagi ikonkalar lucide-react dan (Ikonkalar darsida). Diqqat qiling: utils alias'i yozilgan. Keyingi bo'limda CLI uni hisobga olmaganini ko'ramiz.
7. shadcn CLI: haqiqiy oqim va tuzoqlar
Kanonda holat 02 ning nusxasida haqiqiy CLI ishga tushirildi: shadcn@4.21.4, Node 24.21.0, npm 11.19.0 (natijalar/02-shadcn-cli.txt). Login so'ralmadi.
7.1 init Tailwind'ni topmadi
npx shadcn@4.21.4 init -b radix -p nova -y --no-monorepoChiqish (fayldan):
✔ Preflight checks.
✔ Verifying framework. Found Vite.
✖ Validating Tailwind CSS. Found v4.
✔ Validating import alias.
No Tailwind CSS configuration found ... Install Tailwind CSS then try again.Tarjimasi: "Tailwind CSS konfiguratsiyasi topilmadi… Tailwind CSS'ni o'rnatib, qayta urinib ko'ring." Tailwind o'rnatilgan va ishlayapti-ku! Sabab: init CSS faylda aynan @import "tailwindcss" qatorini qidiradi. Bizda preflight'siz kirish — theme.css va utilities.css alohida. CLI uni tanimaydi. Yechim — init siz: components.json ni qo'lda yozish (yuqoridagi fayl). add uchun shu yetadi.
Tuzoq №1: CLI "Tailwind yo'q" desa, Tailwind'ni qayta o'rnatishga shoshilmang. CLI faqat bitta odatiy shaklni taniydi.
7.2 add: fayllar bor, lekin…
npx shadcn@4.21.4 add dropdown-menu tooltip -y✔ Created 2 files: src\ui\dropdown-menu.tsx, src\ui\tooltip.tsxFayllar components.json dagi "ui": "@/ui" bo'yicha to'g'ri joyga yozildi. Endi git diff va tsc -b:
src/ui/dropdown-menu.tsx(3,55): error TS2307: Cannot find module 'radix-ui'
src/ui/dropdown-menu.tsx(4,45): error TS2307: Cannot find module 'lucide-react'
src/ui/tooltip.tsx(5,45): error TS2307: Cannot find module 'radix-ui'Tarjimasi: "radix-ui modulini topib bo'lmadi" (tsc'ning to'liq xabari davomida "or its corresponding type declarations" — "yoki uning tur e'lonlarini"). To'rtta tuzoq birdan ko'rindi:
- Tuzoq №2 —
cnboshqa joydan. Fayllarimport { cn } from "cn"deb yozilgan — registr JSON'idagi o'sha qator («Registr elementi ichida» bo'limi): npm'dagicnpaketidan.components.jsondagi"utils": "@/ui/cn"ishlatilmadi.package.jsonga esa"cn": "0.4.0"qo'shildi — bizning@/ui/cn.tso'rniga (cvabilan birga +11.4 KB,clsxbilan esa +0.5). - Tuzoq №3 — bog'liqliklar o'rnatilmadi.
radix-novauslubida registr elementi faqatcnni so'raydi: CLIradix-uivalucide-reactniinito'rnatgan deb hisoblaydi. Bizinitqilmadik — demak ular yo'q, uchta TS2307. - Tuzoq №4 — eng yangi versiya.
new-yorkuslubida CLIradix-uini qo'shdi — 1.8.1, ikki kun oldin chiqqan versiya. Kursning qoidasi esa — 7 kundan yangi reliz olinmaydi. - Tuzoq №5 —
^. Loyihada.npmrcdagisave-exactbo'lmasa,"radix-ui": "^1.8.1"yoziladi (Semver): keyinginpm installyana yangisini olishi mumkin.save-exactbo'lsa ham CLI versiyani tanlamaydi, faqat^ni olib tashlaydi.
7.3 To'g'ri oqim
Kanon xulosasi — CLI'ga ishoning, lekin tekshiring:
git status # toza bo'lsin: CLI nima qilganini ko'rasiz
npx shadcn@4.21.4 add dropdown-menu
git diff # yangi fayllar va package.json
npm i -E @radix-ui/react-dropdown-menu@2.1.25 # qo'lda, aniq
npm run check # tsc, lint, testlar- CLI versiyasi aniq (
shadcn@4.21.4,@latestemas) — bugungi buyruq ertaga ham o'sha natijani bersin. git diff— CLI qo'shgan importlar va paketlarni o'qing:"cn", eng yangiradix-ui,^.- Paketlarni o'zingiz qotiring:
-E(--save-exact), 7 kundan eski versiya. - Importlarni moslang:
cn→@/ui/cn.ts, umumiyradix-ui→ alohida@radix-ui/react-dropdown-menu(sababi keyingi darsda), sinflar → tokenlarimiz.
Kanondagi src/ui/ fayllari aynan shunday paydo bo'ldi: CLI chiqishi qisqartirildi va moslandi. Qismlar, data-slot atributlari va eksport nomlari CLI'nikiga mos. Batafsil — keyingi darsda.
7.4 Yangilash muammosi
Ertaga shadcn registrida dropdown-menu ning tuzatilgan versiyasi chiqsa, u sizga o'zi kelmaydi. Qayta add qilsangiz, CLI faylni registrdagi variant bilan almashtiradi — siz qilgan moslashlar o'sha faylda bo'lsa, ular yo'qoladi. Shuning uchun oqim yana o'sha: toza git status → add → git diff → kerakli qatorlarni qo'lda saqlash. Xulq qatlami (Radix) esa npm paketi — uning tuzatishlari odatdagi npm yangilanishi bilan keladi.
Diqqat: Eski maqolalarda
npx shadcn-ui@latest initni ko'rasiz — paketning eski nomi. Hozirgisi —shadcn. Tailwind v3 loyihalarida esatailwind.config.jsvatailwindcss-animateuchraydi; v4 da ularning o'rnida CSS'dagi@themevatw-animate-css(Tailwind CSS 5).
8. Vazifalar qadami: Tailwind v4 va Tugma (holat 02)
8.1 Branch va paketlar
- Branch:
feat/tailwind
git switch -c feat/tailwind
npm i -D -E tailwindcss@4.3.3 @tailwindcss/vite@4.3.3
npm i -E clsx@2.1.1 class-variance-authority@0.7.1clsx va cva — dependencies da: ular brauzerga boradi. Tailwind — devDependencies da: brauzerga faqat u yasagan CSS boradi.
8.2 Fayllar
| Fayl | O'zgarish |
|---|---|
src/vazifalar.css |
Tailwind kirishi: qatlamlar, @import, @theme |
src/asos.css |
yangi: eski qoidalar, var(--rang-*) → var(--color-*) |
src/ui/cn.ts, src/ui/Tugma.tsx |
cn va cva |
vite.config.ts, vitest.config.ts |
Tailwind plagini, @/ alias |
tsconfig.json, tsconfig.app.json |
paths |
components.json, knip.json |
yangi |
index.html dagi <link rel="stylesheet" href="src/vazifalar.css"> o'zgarmadi: Vite shu havolani ko'rib, CSS'ni Tailwind plaginidan o'tkazadi.
knip.json nima uchun? knip ishlatilmagan paket va fayllarni topadi. U asos.css ni ham, tailwindcss paketini ham "hech kim import qilmaydi" deb xato topardi. Sababi, ular faqat CSS @import orqali ulangan. "entry": ["src/vazifalar.css"] — knip'ga CSS kirish nuqtasini ko'rsatadi.
8.3 src/ui/cn.ts
Kanondan (izohlar qisqartirilgan):
// cn.ts — sinflarni birlashtirish (20/#02): clsx — shartli
// sinflar ("a", ochiq && "b", { c: bool }) bitta satrga.
// tailwind-merge YO'Q — o'lchandi (natijalar/02-cn-hajm.txt):
// birinchi yuklash gzip +8.8 KB. Qoida: komponentga className faqat
// QO'SHIMCHA uchun (joylashuv), rang/o'lcham — variant orqali
// (TEXNIK-QARZ 53)
import { clsx } from "clsx";
import type { ClassValue } from "clsx";
export function cn(...sinflar: ClassValue[]): string {
return clsx(sinflar);
}8.4 src/ui/Tugma.tsx
Jadval qismi va komponent (kanondan, aynan):
import { cn } from "@/ui/cn.ts";
const tugmaSinflari = cva(
"tugma min-h-bosish rounded-burchak border px-3 py-2 disabled:opacity-60",
{
variants: {
variant: {
oddiy: "border-chegara bg-yuza text-matn",
asosiy: "border-asosiy bg-asosiy text-asosiy-ustida",
xavfli: "border-xato bg-yuza text-xato",
},
},
defaultVariants: { variant: "oddiy" },
},
);
export function Tugma({
variant,
type = "button",
className,
ref,
...qolgan
}: Props) {
return (
<button
ref={ref}
type={type}
className={cn(tugmaSinflari({ variant }), className)}
{...qolgan}
/>
);
}@/ui/cn.ts — birinchi @/ import. disabled:opacity-60 — holat varianti (Tailwind CSS 2). asos.css dagi .tugma[data-variant="…"] qoidalari o'chirildi — ularning ishini endi cva qiladi.
8.5 Natija
Kanon tekshiruvi (natijalar/tekshiruv-02.txt): build, npm test (node:test 198, Vitest 67), lint, format, tip, knip — hammasi toza. Hajm (gzip): birinchi yuklash JS 151.4 → 151.9 KB, CSS 2.5 → 3.1 KB. CSS o'sdi — endi unda tokenlar va ishlatilgan utilitalar bor.
Ko'rinish farqi — 0, axe — 0 buzilish. Brauzer tekshiruvlari: 13–17-qismning 159 tasi, 18-qismning 72 tasi, 19-qismning 100 tasi o'tdi. 20-qismning yangi tekshiruvi e2e-20.mjs (brauzer-tekshiruv/natija-20-02.txt):
✅ qatlamlar tartibi: theme, base, components, utilities: ["theme","base","components","utilities"]
✅ Tugma (cva): .tugma, 44 px, fon — --color-asosiy: [true,"44px",true]
✅ preflight yo'q: h1 — brauzer standarti (2em = 32px): "32px"
✅ Tailwind: CSP buzilishi yo'q: []
✅ konsolda xato yo'q: []To'rtinchi qatorga qarang: Tailwind CSP'ni buzmaydi. U CSS'ni build paytida faylga yozadi, sahifaga <style> qo'shmaydi. CSS-in-JS kitlardan farqi shu (o'tgan dars).
8.6 Commit
git add -A
git commit -m "feat: Tailwind v4 (preflight'siz), tokenlar @theme'da, Tugma — cva"Kanonda @/ alias va components.json keyinroq, alohida commit bilan qo'shilgan: build: @/ alias (tsconfig paths, vite/vitest) va components.json — shadcn CLI uchun. Siz ikkalasini bitta branch'da ketma-ket ikki commit qilishingiz mumkin. Holat 02 jami 13 fayl, +1208 −465 qator. Qatorlarning asosiy qismi — vazifalar.css ning asos.css ga ko'chishi va package-lock.json.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Tailwind sinfi yozilgan, lekin ta'sir yo'q | eski CSS qatlamsiz — utilitalardan ustun | eski CSS'ni layer(base) bilan |
| Sinf CSS'ga umuman tushmadi | fayl source() dan tashqarida yoki nom yig'ilgan (bg-${rang}) |
source, to'liq sinf nomi (C-99) |
bg-blue-600 ishlamaydi |
--color-*: initial |
tokenlardan foydalaning — bu ataylab |
Vitest: Failed to resolve import "@/ui/cn.ts" |
alias faqat vite.config.ts da |
vitest.config.ts ga ham |
TS2307: Cannot find module 'radix-ui' |
CLI bog'liqlikni o'rnatmadi | npm i -E <paket>@<versiya> |
package.json da "radix-ui": "^1.8.1" |
CLI eng yangisini ^ bilan qo'shdi |
aniq, 7 kundan eski versiya |
init: "No Tailwind CSS configuration found" |
preflight'siz kirish | components.json qo'lda |
10. Mashqlar
Mashqlar kurs/mashqlar/20/02-shadcn-sozlash/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): bo'sh joylarni to'ldiring
- Tailwind'ning reset qismi:
- Qatlamsiz CSS qatlamdagi CSS'dan:
--color-asosiytokenidan hosil bo'ladigan fon utilitasi:bg-- shadcn CLI papka va alias'larni o'qiydigan fayl:
- Kanondagi
cn()ichida faqat:
Yechim
Preflight — Tailwind'ning reset'i, vazifalar da ulanmagan. Qatlamsiz CSS har qatlamdan ustun — shuning uchun eski qoidalar layer(base) ga ko'chdi. @theme dagi --color-asosiy → bg-asosiy, text-asosiy, border-asosiy. components.json — CLI uchun loyiha pasporti. cn = clsx: tailwind-merge +8.8 KB bo'lgani uchun kirmadi.
2-mashq (o'rta): «Bahor» nishoni
«Bahor» buyurtmalar ro'yxatida holat nishoni (badge) kerak. cva bilan nishonSinflari yozing:
- asos:
nishon rounded-burchak px-2; holatvarianti:yangi→bg-belgi text-matn,tayyor→bg-asosiy text-asosiy-ustida,bekor→bg-yuza text-xato;olchamvarianti:kichik→text-sm,katta→text-lg;- sukut bo'yicha:
holat: "yangi",olcham: "kichik"; compoundVariants:bekorvakattabirga bo'lsa — qo'shimchafont-bold(C-99 dagi kabi).
Konsolga uch chaqiruvni chiqaring: sukut bilan, { holat: "tayyor" }, { holat: "bekor", olcham: "katta" }.
Yechim
import { cva } from "class-variance-authority";
const nishonSinflari = cva("nishon rounded-burchak px-2", {
variants: {
holat: {
yangi: "bg-belgi text-matn",
tayyor: "bg-asosiy text-asosiy-ustida",
bekor: "bg-yuza text-xato",
},
olcham: { kichik: "text-sm", katta: "text-lg" },
},
compoundVariants: [
{ holat: "bekor", olcham: "katta", class: "font-bold" },
],
defaultVariants: { holat: "yangi", olcham: "kichik" },
});
console.log(nishonSinflari());
console.log(nishonSinflari({ holat: "tayyor" }));
console.log(nishonSinflari({ holat: "bekor", olcham: "katta" }));Konsolda:
nishon rounded-burchak px-2 bg-belgi text-matn text-sm
nishon rounded-burchak px-2 bg-asosiy text-asosiy-ustida text-sm
nishon rounded-burchak px-2 bg-yuza text-xato text-lg font-boldTartib: asos → variantlar (jadvaldagi tartibda) → compoundVariants. Ikkinchi chaqiruvda olcham berilmadi — sukutdagi kichik olindi. font-bold faqat uchinchisida: ikki shart birga bajarildi.
3-mashq (qiyin): Tugma ga asChild
«cva va cn(): Tugma» bo'limidagi Tugma ni «asChild: shadcn Button ichida» bo'limidagi g'oya bilan birlashtiring:
- yangi prop
asChild(sukut —false); asChildbo'lsa —Slot(@radix-ui/react-slot), aks holda"button";type="button"faqat haqiqiy<button>ga berilsin:<a type="button">noto'g'ri HTML;- sinflar — o'sha
tugmaSinflarijadvalidan.
Sinov: <Tugma>Saqlash</Tugma> va <Tugma asChild variant="asosiy"><a href="/menyu">Menyu</a></Tugma> ni chizing va nav ning innerHTML ini konsolga chiqaring.
Yechim
import { Slot } from "@radix-ui/react-slot";
import { cva } from "class-variance-authority";
import { clsx } from "clsx";
const tugmaSinflari = cva("tugma rounded-burchak px-3", {
variants: {
variant: {
oddiy: "bg-yuza text-matn",
asosiy: "bg-asosiy text-asosiy-ustida",
},
},
defaultVariants: { variant: "oddiy" },
});
function Tugma({ asChild = false, variant, className, ...rest }) {
const Comp = asChild ? Slot : "button";
// type faqat <button> uchun; Slot'da bolaning o'z atributlari
const typeProp = asChild ? {} : { type: "button" };
return (
<Comp
{...typeProp}
className={clsx(tugmaSinflari({ variant }), className)}
{...rest}
/>
);
}
export default function App() {
return (
<nav ref={(el) => el && console.log(el.innerHTML)}>
<Tugma>Saqlash</Tugma>
<Tugma asChild variant="asosiy">
<a href="/menyu">Menyu</a>
</Tugma>
</nav>
);
}Konsolda:
<button type="button" class="tugma rounded-burchak px-3 bg-yuza text-matn">Saqlash</button><a href="/menyu" class="tugma rounded-burchak px-3 bg-asosiy text-asosiy-ustida">Menyu</a>Havola asosiy variantdagi tugma sinflarini oldi, lekin <a> bo'lib qoldi. Malika uni "havola" deb eshitadi, Ctrl + bosish esa yangi tabda ochadi. type esa faqat haqiqiy tugmada. shadcn Button ham aynan shunday tuzilgan — farqi, unda cn va o'lcham (size) varianti bor.
4-mashq: vazifalar qadami
feat/tailwind branch'ida «Vazifalar qadami» ni bajaring: paketlar, vazifalar.css + asos.css, @theme tokenlari, ui/cn.ts, Tugma — cva, @/ alias (to'rt joy), components.json, knip.json. npm run check toza bo'lsin. Keyin:
- DevTools → Elements'da
<h1>ning shrift o'lchamini (Computed) Tailwind'dan oldingi bilan solishtiring. - Biror tugmaga vaqtincha
className="bg-blue-600"yozing va natijaga qarang. vitest.config.tsdan alias'ni vaqtincha olib tashlab,npm testni ishga tushiring.
Yechim
- 32 px — o'zgarmagan: preflight ulanmagan,
h1brauzer standartida qoldi. - Hech narsa o'zgarmaydi:
--color-*: initialstandart palitrani o'chirgan,bg-blue-600uchun CSS yozilmaydi. Bu himoya — dizayn tizimidan tashqari rang ishlamaydi. - Vitest
Tugma.tsxdagi@/ui/cn.tsimportini topa olmaydi vaTugmani ishlatadigan testlar yiqiladi. Alias'ni qaytaring — vitest tsconfig'ni ham, vite.config.ts ni ham o'qimaydi.
11. Real ishda
- Yangi loyiha: ko'p jamoalar
npm create vite→ Tailwind →npx shadcn initbilan boshlaydi. Odatiy loyihadainitmuammosiz o'tadi. Muammo — mavjud, o'z CSS'i bor loyihaga qo'shishda, xuddi biznikidek. - Kod ko'rib chiqish (code review)da: shadcn
adddan keyingi PR'da avvalpackage.jsonqarashadi — qanday paketlar, qanday versiyalar,^bormi. - Dizayn tizimi jamoalari tokenlarni
@themeda ushlaydi va o'z registrini yuritadi: boshqa loyihalarnpx shadcn add https://…/tugma.jsonbilan oladi. - Intervyu savollari: "shadcn/ui'ni qanday yangilaysiz?", "
cn()ichida nima bor va nega?", "cvanima beradi?", "Tailwind v4 da preflight nima?", "@/alias'ni qayerlarda sozlash kerak?".
Xulosa
- shadcn/ui: registr → CLI →
src/dagi fayl; CLIcomponents.jsondan papka va alias'larni o'qiydi. - Tailwind v4
vazifalarda preflight'siz:theme.css+utilities.css source("./"), eski CSS —layer(base); ko'rinish farqi 0. - Tokenlar
@themeda (--color-asosiy→bg-asosiy),--color-*: initial; qorong'i rejim —light-dark()bilan,dark:siz. Tugma—cvajadvali, turVariantPropsdan;cn=clsx(+0.5 KB),tailwind-mergeyo'q (+8.8 KB) — className faqat joylashuv uchun.@/— tsconfig (ikkala), Vite, Vitest; Node testlari nisbiy yo'lda.- CLI tuzoqlari:
initTailwind'ni tanimadi,cnpaketdan, bog'liqliklar yo'q (TS2307), eng yangi versiya va^—git diffvanpm i -Ebilan.
Keyingi dars: shadcn/ui II: real ilovada asosiy komponentlar — dashboard'ning shadcn "g'ishtlari" va vazifalar ga ko'chirilgan DropdownMenu: bandlar turlari, modal={false} va <main> dagi portal (o'lchovi bilan sababi — Radix chuqur da), narxi +27.2 KB.
Manbalar
- shadcn/ui: "Installation — Vite", "components.json", "CLI", "Registry", "Theming" — ui.shadcn.com/docs
- Tailwind CSS v4: "Installing with Vite", "Preflight" (preflight'siz ulash), "Theme variables", "Detecting classes in source files" — tailwindcss.com/docs
- class-variance-authority 0.7.1: "Variants", "Compound Variants", "TypeScript" — cva.style/docs
- clsx 2.1.1 — github.com/lukeed/clsx; tailwind-merge — github.com/dcastil/tailwind-merge
- Radix: "Slot" — radix-ui.com/primitives/docs/utilities/slot
- shadcn registr elementi: ui.shadcn.com/r/styles/radix-nova/dropdown-menu.json (2026-10-17)
- Kanon:
vazifalarholat 02,natijalar/02-shadcn-cli.txt,02-cn-hajm.txt,02-korinish.txt,tekshiruv-02.txt(2026-10-14)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!