اندازهٔ پیش‌فرض کنترل‌ها (ControlSizeProvider)

یک اندازه برای همهٔ کنترل‌های یک ردیف، بدون نوشتن size روی تک‌تک آن‌ها

معرفی

ControlSizeProvider اندازهٔ پیش‌فرض کنترل‌هایی را که در جدول «کنترل‌هایی که از Provider پیروی می‌کنند» آمده‌اند، برای هر چیزی که داخلش قرار می‌گیرد تعیین می‌کند. کنترلی که size خودش را داشته باشد همان را نگه می‌دارد؛ بقیه اندازهٔ Provider را می‌گیرند، و قاب بیرونی هر کدام دقیقاً به ارتفاع همان پله می‌شود. خودش هیچ عنصری رندر نمی‌کند.

قاعدهٔ «همهٔ کنترل‌های یک ردیف، یک اندازه» پیش از این فقط با نوشتن size روی تک‌تک کنترل‌ها اجرا می‌شد، و پیش‌فرض خود کنترل‌ها با هم فرق داشت. این جزء آن قاعده را به کد می‌آورد. از نسخهٔ 4.0 پیش‌فرض‌ها دو تا هستند: دکمه‌ها و کنترل‌های دکمه‌مانند sm (30 پیکسل)، فیلدهای فرم md (38 پیکسل). هر ردیفی که هر دو را کنار هم دارد (نوار ابزار، ردیف فیلتر) باید یک اندازه بگیرد؛ PageToolbar و FilterBar این کار را خودشان می‌کنند، و ردیف‌های اقدامِ خود سیستم طراحی هم: سرِ کارت نمودار (ChartCardHeader)، actions و primaryAction سربرگ صفحه (PageHeader، PageHeaderAside)، actions در FormHeader و نوار بالای SiteHeader کنترل‌های بی size خود را sm می‌کنند، مگر یک Provider بیرونی اندازهٔ دیگری بدهد.

چه زمانی استفاده کنیم:

  • برای یک ردیف کنترل از خودتان که نوارابزار صفحه نیست، مثل ردیف فیلتر داخل یک پنل کناری؛ یا برای ردیفی از سیستم طراحی که باید فشرده‌تر از sm باشد (مثلاً xs در سرِ کارت نمودار، مثل نمونهٔ زیر).
  • وقتی کنترل سفارشی خودتان باید از همان اندازهٔ ردیف پیروی کند: با useControlSize() آن را بخوانید.

چه زمانی استفاده نکنیم:

  • دور نوارابزار صفحه (نوارابزاری که ListPage از search و filters می‌سازد): اندازه و عرض کنترل‌هایش را خودش تعیین می‌کند.
  • دور کل صفحه یا کل برنامه: چگالی را سیستم طراحی تعیین می‌کند، نه هر محصول. Provider برای یک ردیف یا یک ظرف کوچک است.
  • برای فرم صفحه: فیلدهای فرمی که در خود صفحه است اندازه و عرض پیش‌فرض خودشان را دارند. تنها استثنا فرم کوچک داخل یک لایهٔ رویی (مثلاً پاپ‌اور) است که باید اندازهٔ دیگری بگیرد؛ بخش «هر لایهٔ رویی از نو شروع می‌کند» را ببینید.
بدون ControlSizeProvider: هر کنترل اندازه و عرض پیش‌فرض خودش را دارد
روند منشن‌ها
داخل <ControlSizeProvider size="xs" controlWidth="intrinsic">: یک اندازه برای کل ردیف و عرض به‌اندازهٔ محتوا
روند منشن‌ها

استفاده

import {
  Button,
  ChartCardHeader,
  ControlSizeProvider,
  PeriodSelector,
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@partodata/ui'
import { Icons } from '@partodata/ui/icons'

export function TrendHeader({ period, onPeriodChange }: { period: string; onPeriodChange: (v: string) => void }) {
  return (
    <ChartCardHeader
      title="روند منشن‌ها"
      actions={
        <ControlSizeProvider size="xs" controlWidth="intrinsic">
          <PeriodSelector value={period} onValueChange={onPeriodChange} />
          <Select defaultValue="line">
            <SelectTrigger aria-label="نوع نمودار">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="line">خطی</SelectItem>
              <SelectItem value="bar">ستونی</SelectItem>
            </SelectContent>
          </Select>
          <Button variant="ghost" icon={<Icons.download />} aria-label="خروجی نمودار" />
        </ControlSizeProvider>
      }
    />
  )
}

برای یک ردیف، controlWidth="intrinsic" را همیشه کنار size بنویسید؛ بدون آن SelectTrigger، Input و جست‌وجو کل عرض ردیف را می‌گیرند.

Context این جزء بین همهٔ مسیرهای وارد کردن مشترک است: Provider از @partodata/ui/control-size به دکمه‌ای که از @partodata/ui یا @partodata/ui/button آمده هم می‌رسد.

حالت‌ها و انواع

کنترل‌هایی که از Provider پیروی می‌کنند

کنترلبیرون از Providerداخل Provider
Button با متنsm (30)اندازهٔ Provider
Button فقط‌آیکون (icon بدون children)مربع sm (30)مربعی به ارتفاع همان اندازه
Input، SelectTrigger، SearchInput، MultiSelect، Autocompletemd (38)اندازهٔ Provider
DatePicker، DateRangePickermd (38)اندازهٔ Provider
NativeSelectmd (38)اندازهٔ Provider
PeriodSelector، ViewToggle، ToggleGroup تک‌انتخابیsm (قاب 30)اندازهٔ Provider؛ قاب هم‌قد ردیف
Toggle، ToggleGroup چندانتخابیsmاندازهٔ Provider
DataTableFacetedFilter، FilterBarClearsmاندازهٔ Provider
DataTableColumnVisibilityToggle، DataTableExportButtonsm (تا 3٫x xs)اندازهٔ Provider
ThemeToggle (@partodata/ui/theme-toggle)مربع sm (30)مربعی به ارتفاع همان اندازه
UserMenu (trigger)دایرهٔ sm (30؛ تا 3٫x 32)دایره‌ای به ارتفاع همان اندازه
TabsList (فقط sm/md/lg: 30 / 38 / 42)sm (30)xs ← sm، xl ← lg، بقیه همان

کنترل‌هایی که روی Button یا Input ساخته شده‌اند هم پیروی می‌کنند: Input با هر kind و آدورنمنت، و دکمهٔ DateTimePicker.

عمداً پیروی نمی‌کنند: Checkbox، Switch، RadioGroup، FilterChip، CopyButton و InputGroupButton. این‌ها روی مقیاس ارتفاع کنترل‌ها نیستند و کنار یا داخل کنترل دیگری با اندازهٔ خودشان می‌نشینند.

قاب هر کنترل دقیقاً به ارتفاع پله

ارتفاع قاب بیرونی هر کنترل جدول همان عدد پله است: 26، 30، 38، 42 یا 50 پیکسل. این کنترل‌ها برای رسیدن به آن کمی جمع‌وجورتر چیده می‌شوند:

  • کنترل‌های قطعه‌ای (PeriodSelector، ViewToggle، ToggleGroup تک‌انتخابی): گزینه‌ها داخل یک ریل با حاشیهٔ یک‌پیکسلی و فاصلهٔ دوپیکسلی هستند، پس هر گزینه 6 پیکسل کوتاه‌تر از پله است تا کل ریل هم‌قد ردیف شود.
  • MultiSelect: فاصلهٔ عمودی داخلش کمتر می‌شود تا یک خط برچسب‌های انتخاب‌شده (یا متن راهنما) روی همان پله بنشیند. اگر برچسب‌ها به خط دوم بروند، بلندتر می‌شود.

از نسخهٔ 4.0 این هندسه بیرون از Provider هم برقرار است (تا 3٫x بیرون از Provider کنترل قطعه‌ای 6 پیکسل بلندتر از دکمهٔ هم‌اندازه‌اش بود). TabsList هم از 4.0 روی همین نردبان است (30، 38، 42؛ تا 3٫x 32، 36، 40)، پس کنار دکمهٔ هم‌اندازه‌اش هم‌قد است؛ xs و xl ندارد و به نزدیک‌ترین پله می‌رود.

لمس: حداقل 38 پیکسل

روی اشاره‌گر درشت (گوشی و تبلت) یا زیر data-touch روی <html> (مینی‌اپ پیام‌رسان) هر کنترل روی نردبان دست‌کم 38 پیکسل است و دکمه‌ها، انتخابگرها و کلیدها ناحیهٔ لمس 44 پیکسلی هم دارند؛ کنترل قطعه‌ای کلاً 38 پیکسل می‌شود. این یک حداقل است، پس اندازهٔ sm نوار ابزار، Provider یا ردیف فرم آن را پایین نگه نمی‌دارد و کل ردیف با هم بالا می‌رود؛ روی دسکتاپ همان 30 پیکسل می‌ماند. تنها راه نگه داشتن اندازهٔ دسکتاپ روی دستگاه لمسی data-touch="off" روی آن بخش است. جزئیات، و کنترل‌هایی که بیرون از این کف‌اند، در اندازه و تراکم.

اندازهٔ صریح برنده است

<ControlSizeProvider size="xs">
  <Button variant="default">خروجی</Button>
  <Button variant="default" size="md">
    گزارش کامل
  </Button>
</ControlSizeProvider>

دکمهٔ اول 26 پیکسل (اندازهٔ Provider) و دکمهٔ دوم 38 پیکسل (md خودش) است.

هر لایهٔ رویی از نو شروع می‌کند

هر سطحی که روی صفحه باز می‌شود، یعنی Dialog، AlertDialog، Sheet، Drawer، Popover، DropdownMenu، ContextMenu و HoverCard، کنترل‌هایش را با پیش‌فرض سیستم طراحی می‌چیند: اندازهٔ sm و عرض کامل. این قاعده حتی وقتی برقرار است که دکمهٔ بازکننده داخل Provider یا PageToolbar باشد. یعنی فرم فیلتری که از نوارابزار در یک پاپ‌اور باز می‌شود، مثل هر فرم دیگری کل عرض پاپ‌اور را می‌گیرد.

اگر کنترل‌های یک پاپ‌اور باید اندازهٔ دیگری داشته باشند، Provider را داخل PopoverContent بگذارید.

<PopoverContent>
  <ControlSizeProvider size="xs">
    <Input aria-label="از تاریخ" />
    <Button variant="default">اعمال</Button>
  </ControlSizeProvider>
</PopoverContent>

عرض ذاتی: controlWidth="intrinsic"

Input، SelectTrigger، SearchInput، MultiSelect، Autocomplete و انتخابگرهای تاریخ به‌طور پیش‌فرض کل عرض ظرفشان را می‌گیرند، که در یک ردیف یعنی هر کدام یک خط کامل. با controlWidth="intrinsic" هر کدام به‌اندازهٔ محتوایش می‌شود، SearchInput عرض نام‌دار --layout-search-width (256 پیکسل) را می‌گیرد، و انتخابگرهای تاریخ مثل autoWidth رفتار می‌کنند. کلاس عرض یا autoWidth صریح روی کنترل همچنان برنده است.

پیش‌فرض fill است، چون Provider دو کاربرد دارد و فقط یکی از آن‌ها ردیف است: Provider ردیف (سرِ کارت، ردیف فیلتر پنل) همیشه controlWidth="intrinsic" می‌گیرد، و Provider داخل یک لایهٔ رویی (فرم یک پاپ‌اور) کنترل‌ها را مثل هر فرمی تمام‌عرض نگه می‌دارد. داخل PageToolbar لازم نیست چیزی بنویسید؛ خود نوارابزار intrinsic است.

<ControlSizeProvider size="xs" controlWidth="intrinsic">
  <SearchInput placeholder="جست‌وجو" />
  <Select>
    <SelectTrigger aria-label="مرتب‌سازی">
      <SelectValue placeholder="جدیدترین" />
    </SelectTrigger>
  </Select>
</ControlSizeProvider>

Providerهای تودرتو

نزدیک‌ترین Provider برنده است. Provider درونی‌ای که controlWidth ندارد، عرض را از Provider بیرونی می‌گیرد.

راهنمای استفاده

بکنید

  • برای یک ردیف کنترل، یک Provider با size و controlWidth="intrinsic" بگذارید و size و کلاس عرض را از تک‌تک کنترل‌ها بردارید.
  • دکمهٔ فقط‌آیکون را با icon (یا iconEnd) و aria-label بسازید تا داخل ردیف مربعی و هم‌قد بقیه شود. برچسبی که گاهی نمایش داده نمی‌شود ({!isMobile && 'خروجی'}) هم وقتی false است دکمه را مربعی می‌کند.
  • در کنترل سفارشی، اندازه را با useControlSize() بخوانید و اگر undefined بود پیش‌فرض خودتان را بگذارید.

نکنید

  • Provider را دور کل صفحه یا layout برنامه نگذارید.
  • داخل یک ردیف به بعضی کنترل‌ها size متفاوت ندهید؛ همین تفاوت است که ردیف را ناهم‌قد می‌کند.
  • دور PageToolbar Provider دیگری نگذارید؛ نوارابزار اندازهٔ خودش را دارد.

Props

ControlSizeProvider

Prop

Type

useControlSize

useControlSize(): 'xs' | 'sm' | 'md' | 'lg' | 'xl' | undefined — اندازهٔ نزدیک‌ترین Provider، یا undefined بیرون از هر Provider.

دسترسی‌پذیری

  • Provider هیچ عنصر و نقشی به صفحه اضافه نمی‌کند؛ فقط اندازه عوض می‌شود.
  • دکمهٔ فقط‌آیکون مربعی همچنان به aria-label نیاز دارد.
  • اندازهٔ xs (26 پیکسل) برای ردیف‌های متراکم است؛ برای کنترل‌هایی که هدف لمسی اصلی‌اند اندازهٔ بزرگ‌تر انتخاب کنید.

کامپوننت‌های مرتبط

  • PageToolbar — ردیف فیلتر و اقدامی که ListPage می‌سازد (مستقیم فقط درون CustomPage)؛ همین Provider را با controlWidth="intrinsic" برای کنترل‌هایش می‌گذارد، پس برای نوارابزار صفحه به Provider جداگانه نیاز ندارید.
  • FilterBar — ردیف فیلتر؛ FilterBarClear داخل Provider هم‌قد بقیهٔ ردیف می‌شود.
  • اندازه و چگالی — مقیاس پنج‌پله‌ای که این جزء از آن انتخاب می‌کند.
  • Button — اگر فقط یک دکمه اندازهٔ دیگری لازم دارد، size خودش را بدهید، نه Provider.