کاستومایز
بستهٔ سفارشPackage Box
جعبهٔ مقواییِ سهبعدی که با کلیک نوارچسبش میشکافد، درهایش تا میخورند و برگهٔ سفارش از داخل بالا میآید و رو به شما میچرخد.
وابستگیها
نوع تعامل
کلیک روی جعبه یا دکمهٔ زیرش باز/بستهاش میکند؛ بستن همان فیلمِ بازشدن است بهعکس — کلیکِ وسطِ راه فقط جهت را عوض میکند و چیزی نمیپرد. Escape هم میبندد. دکمهٔ زیرِ جعبه همیشه برای صفحهخوان هست (با `hint={false}` فقط نامرئی میشود) و `aria-expanded`/`aria-controls` میگیرد؛ برگهٔ سفارش هم تا وقتی باز نشده `inert` است تا فوکوس به محتوای پنهان نرود. با `prefers-reduced-motion` کلِ تایملاین در ۱۰ میلیثانیه به مقصد میرسد، پس حالت درست است ولی حرکت پخش نمیشود.
پراپها
گزینههایی که میتونی به کامپوننت بدی؛ ستارهدارها اجباریاند.
openbooleanپیشفرض: undefinedحالتِ بازِ کنترلشده؛ کنارش `onOpenChange` بدهید. ندهید تا خودش مدیریت کند.
defaultOpenbooleanپیشفرض: falseجعبه از اول باز باشد (حالتِ نامکنترلشده).
onOpenChange(open: boolean) => voidپیشفرض: undefinedبا هر باز/بسته شدن صدا زده میشود؛ با `open` میتوانید کنترلشدهاش کنید.
slipPackageSlipمتنِ برگهٔ داخلِ جعبه: عنوان، زیرعنوان، شماره، تاریخ، گیرنده، نشانی، اقلام و مهر. هر فیلدی را ندهید، جاینگهدارِ فارسیاش مینشیند.
childrenReactNodeپیشفرض: undefinedجای برگهٔ پیشفرض؛ در فضای طراحی ۲۴۰×۳۴۰ رندر میشود (بر `slip` مقدم است).
colorsPackageBoxColorsپیشفرض: مقوای طبیعی + مهرِ نارنجی`{ box, tape, paper, ink, accent }`. همهٔ وجهها، سایه و بافتِ کارتون از `box` مشتق میشوند؛ `accent` رنگِ مهر است.
نصب
۱. این آدرس رو یکبار توی components.json بذار تا shadcn مخزن فارسیفای رو بشناسه.
{
"registries": {
"@farsify": "https://farsify.ir/r/{name}.json"
}
}۲. بعد با دستورِ زیر کامپوننت رو نصب کن.
npx shadcn@latest add @farsify/package-boxپیشنیاز: Tailwind CSS v4 و صفحهٔ راستبهچپ dir="rtl".
نمونه
"use client";
import { useState } from "react";
import { PackageBox } from "@/components/farsify/package-box";
const SLIP = {
eyebrow: "برگهٔ بستهبندی",
title: "سفارشتان بسته شد.",
subtitle: "بسته آماده است و بهزودی راه میافتد.",
reference: "شمارهٔ ۴۸۲۱",
date: "۱۵ آبان ۱۴۰۵",
recipient: "سارا احمدی",
address: "تهران، خیابانِ بهشتی، کوچهٔ ۱۲، پلاک ۴",
items: [
{ name: "لامپِ رومیزیِ ساده", qty: 1, price: "۲٬۴۰۰٬۰۰۰" },
{ name: "دفترِ نقطهدار", qty: 1, price: "۱۸۵٬۰۰۰" },
],
total: "۲٬۵۸۵٬۰۰۰ تومان",
// مهر دو سه واژه بیشتر جا ندارد: دایرهٔ ۳۸px است و متنِ بلندتر از دایره میزند بیرون
stamp: "بسته شد",
};
export function OrderReceived() {
return <PackageBox slip={SLIP} />;
}
// باز/بستهٔ کنترلشده از بیرون
const [open, setOpen] = useState(false);
<PackageBox slip={SLIP} open={open} onOpenChange={setOpen} />
// رنگِ مقوا و مهر — تنها رنگهای کامپوننت
<PackageBox slip={SLIP} colors={{ box: "#b07b4a", accent: "#c2552b" }} />
// داخلِ قابِ کوتاه: سقفِ ارتفاع + رزروِ فضا تا صفحه نپرد
<PackageBox slip={SLIP} maxWidth={320} maxHeight={420} reserveSpace />
// بدونِ نوارچسب یا بدونِ نشانههای حمل
<PackageBox slip={SLIP} tape={false} symbols={false} />نکتهها
- این کامپوننت یک شیءِ فیزیکی است، نه چیدمان: محورهای چرخش و مختصاتِ وجهِ آن آینه نمیشوند. متنِ برگه اما کاملاً راستبهچپ است و با `text-start` و `justify-between` خودش برمیگردد.
- ارتفاعِ صحنه از ۳۹۲px (بسته) تا ۶۵۰px (باز) در فضای طراحی میرود. اگر داخلِ قابی کوتاه (کارت، پنل) میگذارید `maxHeight` را هم بدهید وگرنه جعبهٔ باز از قاب بیرون میزند؛ `reserveSpace` هم از پرشِ صفحه جلوگیری میکند.
- برای متنِ برگه، رقمها را فارسی بنویسید و ستونهای عددی را `tabular-fa` کنید تا با تغییرِ مقدار نلرزند. کدِ لاتین (مثلِ SKU) را با `tabular-en` ایزوله کنید.
- `box` را خیلی روشن یا خیلی تیره ندهید: سایه و نورِ هر وجه از همین رنگ مشتق میشود و در دو سرِ طیف، جعبه تخت دیده میشود. مقواهای خاکی و قهوهای بهترین نتیجه را میدهند.
- روی موبایل، هاورِ شناورِ جعبه و `whileTap` هر دو به `prefers-reduced-motion` وابستهاند؛ چیزی برای خاموشکردن دستی لازم نیست.
- متنِ برگه داخلِ `role="document"` با `aria-label` مینشیند و تا باز نشدن `inert` است؛ اگر محتوای تعاملی داخلِ برگه میگذارید، دکمهٔ راهنما را با `hint={false}` از سرِ راه بردارید تا دو کنترل برای یک کار نداشته باشید.
مجوز
کد بعد از نصب مالِ خودته؛ هر تغییری خواستی بده و توی پروژهی خودت نگهش دار. برای پروژههای شخصی و تجاری آزاده، حتی اگه کدت بسته باشه. فقط اسم و لینک فارسیفای رو یه جا توی پروژه نگه دار.