برنامه نویسی

مهاجرت از Radix به React Aria: افزایش دسترسی و UX در Argos

در هفت سال گذشته، Argos از کتابخانه های مختلف UI استفاده کرده است. ما با Material UI شروع کردیم، سپس به Ariakit، Radix رفتیم و در نهایت React Aria را انتخاب کردیم.

چرا واکنش آریا؟

ابتدا دسترسی و UX

از نظر من، React Aria پیشرفته ترین کتابخانه مؤلفه از نظر UX و دسترسی است. دوون گووت و تیم او یک کار باورنکردنی انجام داده اند که قلاب ها و اجزای سطح پایینی را ایجاد کرده اند که تجربه سطح بالایی را ارائه می دهند.

توجه به جزئیات قابل توجه است. رویداد مطبوعاتی دکمه طوری طراحی شده است که به طور یکپارچه در تمام پلتفرم ها کار کند و مشکلات رایج را برطرف کند :active و :hover. در مقابل، Radix حتی یک جزء دکمه را ارائه نمی دهد.

علاوه بر این، کار روی منوی فرعی نشان دهنده تعهد آنها به ارائه یک تجربه کاربری برجسته است.

با حمایت یک شرکت بزرگ

React Aria زیربنای React Spectrum است، سیستم طراحی Adobe که برای برنامه های کاربردی وب مانند Photoshop استفاده می شود. سرمایه گذاری قابل توجه Adobe در این فناوری، پشتیبانی طولانی مدت و قابلیت اطمینان را تضمین می کند. در حالی که آریاکیت عالی است و دیگو هاز یک توسعه دهنده با استعداد است، فقدان پشتیبان شرکتی خطرات پایداری را به همراه دارد. اگر توسعه‌دهنده تصمیم به توقف بگیرد، این پروژه می‌تواند متوقف شود و به دلیل فقدان نقشه راه تحت حمایت شرکت، خطر شکستن تغییرات بیشتر است. Radix که توسط WorkOS پشتیبانی می‌شود، نمی‌تواند با منابع و تمرکز Adobe مطابقت داشته باشد.

استراتژی مهاجرت

علیرغم پایگاه کد نسبتاً کوچک Argos، انتقال مؤلفه‌های UI متعدد ما چالش برانگیز بود. ما دو انتخاب داشتیم:

  • انتقال جزء به جزء در چندین PR
  • مهاجرت به یکباره در یک روابط عمومی

من دومی را به دلیل دانش عمیق پروژه و اعتماد به قابلیت های آزمایش بصری خود انتخاب کردم.

تجربه و دانش

با بیش از هشت سال تجربه React و آشنایی گسترده با Argos، توانستم به طور کامل تست کنم و مطمئن شوم که همه چیز به درستی کار می کند. با ساخت و نگهداری کتابخانه های مختلف UI، از جمله Smooth UI، برای این مهاجرت جامع آماده شدم.

اعتماد به نفس با تست بصری

تست بصری، یکی از ویژگی‌های اصلی Argos، اطمینان لازم را برای اطمینان از ثابت ماندن رابط کاربری در طول مهاجرت فراهم کرد. Argos از قابلیت‌های تست بصری خود برای گرفتن عکس‌های فوری رابط کاربری و مقایسه آن‌ها با تصاویر پایه استفاده می‌کند و به ما امکان می‌دهد هر گونه تغییر ناخواسته را تشخیص دهیم. این فرآیند خودکار تضمین می‌کند که حتی کوچک‌ترین اختلافات بصری شناسایی و به‌سرعت برطرف می‌شوند. به دلیل سیستم کاملاً یکپارچه React Aria، انتقال اجزا به صورت جداگانه چالش برانگیز بود، اما آزمایش بصری به ما این امکان را داد که با اطمینان همه چیز را به یکباره جابجا کنیم و از یک انتقال صاف و دقیق اطمینان حاصل کنیم.

مشکلات

React Aria بسیار در دسترس است و کاملاً به الگوهای ARIA پایبند است، که گاهی اوقات به این معنی است که برخی از اقدامات مجاز نیستند. در حالی که کتابخانه هایی مانند Ariakit یا Radix انعطاف پذیری را برای دور زدن برخی از قوانین دسترسی ارائه می دهند، React Aria به خطر نمی افتد. این پایبندی دقیق، یک تجربه واقعی در دسترس را تضمین می کند، اما با محدودیت هایی همراه است که به راه حل های خلاقانه نیاز دارد.

مشکل راهنمای ابزار

به عنوان مثال، غیرممکن است که یک راهنمای ابزار روی چیزی که قابل تمرکز نیست قرار دهید. راهنمای ابزار فقط زمانی کار می کند که مولفه مورد نظر دارای a باشد useFocusable قلاب. این چالش برانگیز بود زیرا ما نکات ابزار زیادی در مورد عناصر غیرقابل تمرکز داریم. من ایجاد کردم TooltipTarget جزء برای تزریق focusableProps و اضافه کرد tabIndex: 0 تا اطمینان حاصل شود که عنصر قابل تمرکز است.

TooltipTarget در کد آرگوس

function TooltipTarget(props: { children: React.ReactElement }) {
  const triggerRef = React.useRef(null);
  const { focusableProps } = useFocusable(props.children.props, triggerRef);

  return React.cloneElement(
    props.children,
    mergeProps(focusableProps, { tabIndex: 0 }, props.children.props, {
      ref: triggerRef,
    }),
  );
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قرار دادن نکات ابزار روی دکمه های غیرفعال

در حالی که آریاکیت اجازه ایجاد دکمه هایی را می دهد که در صورت غیرفعال بودن قابل دسترسی هستند، React Aria این کار را نمی کند. آنها به شدت از مشخصات پیروی می کنند. آنها استفاده از کمک متنی را پیشنهاد می‌کنند زیرا راهنمایی‌های ابزار برای اشتراک‌گذاری اطلاعات کاملاً در دسترس نیستند. اگرچه آنها صحیح هستند، اما گاهی اوقات لازم است که یک راهنمای ابزار را روی یک دکمه غیرفعال قرار دهید. برای این، من دکمه خود را در یک پیچیدم div، حتی اگر ایده آل نباشد.

دکمه غیرفعال در پایگاه کد Argos

export function DisabledReviewButton(props: { tooltip: React.ReactNode }) {
  return (
    <Tooltip content={props.tooltip}>
      <div>
        <Button isDisabled>Review changes</Button>
      </div>
    </Tooltip>
  );
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

منوها منو هستند

قبل از مهاجرت، منوی کاربری Argos با استفاده از Ariakit، از جمله انتخابگر تم ایجاد شد. تکرار کردن آن با React Aria ساده اما غیرممکن بود. React Aria فقط به اجزای خاصی مانند MenuItems، Section، و Header در یک منو تلاش برای استفاده از هر چیز دیگری با خطا مواجه می شود و از کار می افتد.

منو با انتخاب کننده تم

من ساختار منو را با جایگزین کردن منوی فرعی انتخاب کردم. این تجربه را با کاهش کلیک‌ها و افزایش دید آیتم بهبود بخشید.

منو با منوی فرعی تم

قطعات خوب

پیوندها

اجزای پیوند React Aria همه کاره هستند، روتر را انتزاعی می کنند و به طور جهانی در سراسر برنامه کار می کنند. پیوندهای مطلق از لنگرهای بومی استفاده می کنند، در حالی که پیوندهای نسبی با استفاده از ارائه شده حرکت می کنند navigate تابع. این useHref قلاب کامل می دهد href وضوح، که برای روترهای پیشرفته مانند روتر واکنشی که از لینک های تودرتو پشتیبانی می کند بسیار عالی است.

RouterProvider در پایگاه کد آرگوس

import { RouterProvider } from "react-aria-components";
import {
  type NavigateOptions,
  Outlet,
  useHref,
  useNavigate,
} from "react-router-dom";

declare module "react-aria-components" {
  interface RouterConfig {
    routerOptions: NavigateOptions;
  }
}

function useAbsoluteHref(path: string) {
  const relative = useHref(path);
  if (
    path.startsWith("https://") ||
    path.startsWith("http://") ||
    path.startsWith("mailto:")
  ) {
    return path;
  }
  return relative;
}

function Root() {
  const navigate = useNavigate();

  return (
    <RouterProvider navigate={navigate} useHref={useAbsoluteHref}>
      <Outlet />
    RouterProvider>
  );
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

فعل و انفعالات (هاور، فشار داده شده)

یکی از مشکلاتی که من قبل از React Aria با آن مواجه شدم، استایل کردن آن بود :hover اثر :hover حتی اگر دکمه غیرفعال باشد اعمال می شود و باید با استفاده از ترفندهایی مانند [&:not([aria-disabled])]:hover].

React Aria شبیه سازی می کند :hover و :active، جایگزین کردن آنها با [data-hovered] و [data-pressed]. این همه مشکلات را برطرف می کند: [data-hovered] وقتی دکمه غیرفعال است وجود ندارد. [data-pressed] مشکل کجا را برطرف می کند :active حتی اگر نشانگر خود را به خارج از دکمه حرکت دهید اعمال می شود. این رفتار درست است زیرا اگر دکمه ماوس خود را در حالی که روی دکمه قرار ندهید رها کنید، روی آن کلیک نمی‌شود، بنابراین استایل نباید نشان دهد که خواهد بود!

ترکیب بندی

من عاشق مدل ترکیب استفاده شده توسط React Aria Components هستم. به عنوان مثال، یک دیالوگ به صورت زیر ساخته می شود:

<DialogTrigger>
  <Button>Sign up…Button>
  <Modal>
    <Dialog>
      {({ close }) => (
        <form>
          <Heading slot="title">Sign upHeading>
          <TextField autoFocus>
            <Label>First NameLabel>
            <Input />
          TextField>
          <TextField>
            <Label>Last NameLabel>
            <Input />
          TextField>
          <Button onPress={close} style={{ marginTop: 8 }}>
            Submit
          Button>
        form>
      )}
    Dialog>
  Modal>
DialogTrigger>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همچنین می توان از همان گفتگو پیچیده شده در a استفاده کرد Popover تا آن را به یک عنصر غیر وجهی و متنی تبدیل کند.

هر عنصر وظایف خاص خود را دارد و ترکیب بندی را به یک نسیم تبدیل می کند. به عنوان مثال، در آرگوس، من یک Popover جزء مورد استفاده برای Select و Menu. مسئولیت انیمیشن و سبک ظرف را بر عهده دارد.

متن نوشته

React Aria Components با رویکردی واضح و کاربردی طراحی شده است. برای موارد استفاده معمولی، آنها با تکیه بر ترکیبی از اجزا بسیار ساده هستند. با این حال، اگر نیاز به اجرای عملکردهای پیشرفته‌تری دارید، می‌توانید با استفاده از قلاب‌ها و زمینه به قسمت‌های داخلی دسترسی پیدا کنید. این رویکرد دوگانه هم سادگی برای کارهای رایج و هم انعطاف پذیری برای نیازهای پیچیده تر را ارائه می دهد.

به عنوان مثال، می توانید یک قابل استفاده مجدد ایجاد کنید DialogDismiss جزء با استفاده از OverlayTriggerStateContext برای دسترسی به close تابع:

مثال از DialogDismiss در پایگاه کد Argos استفاده می شود

const DialogDismiss = forwardRef<
  HTMLButtonElement,
  {
    children: React.ReactNode;
    onPress?: ButtonProps["onPress"];
    single?: boolean;
  }
>((props, ref) => {
  const state = useContext(OverlayTriggerStateContext);
  return (
    <Button
      ref={ref}
      className={props.single ? "flex-1 justify-center" : undefined}
      variant="secondary"
      onPress={(event) => {
        props.onPress?.(event);
        state.close();
      }}
      autoFocus
    >
      {props.children}
    Button>
  );
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این باعث می شود که چیزی برای آهنگسازی واقعاً نسیم باشد.

نتیجه

React Aria به عنوان بهترین کتابخانه UI که من استفاده کرده ام متمایز است. پایه محکم، توجه دقیق به جزئیات، و تعهد تزلزل ناپذیر به دسترسی، آن را به انتخابی برتر برای برنامه های کاربردی وب مدرن تبدیل کرده است. این کتابخانه نه تنها اجرای اجزای قابل دسترس را ساده می کند، بلکه تجربه کاربری یکپارچه را در همه پلتفرم ها تضمین می کند. React Aria با پشتیبانی Adobe قول پشتیبانی طولانی مدت و قابلیت اطمینان را می دهد. این مهاجرت به طور قابل توجهی Argos را بهبود بخشیده است و ثابت می کند که اولویت بندی دسترسی و تجربه کاربر نه تنها برای ایجاد برنامه های کاربردی وب برجسته ضروری است.

برای جزئیات بیشتر، درخواست کشش در GitHub را بررسی کنید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا