Taiga UI — огромная библиотека UI-компонентов для Angular, на которую стоит взглянуть. Но она только вершина айсберга. Мы разрабатывали ее более пяти лет, начав еще на Angular 4. И, будучи любителями декомпозиции, мы создали несколько отдельных независимых проектов, которые помогают нам писать крутые Angular-приложения.
Вам может быть неинтересна Taiga UI, но эти небольшие библиотеки будут полезны и непременно улучшат DX. В этой статье рассмотрим всех членов семьи Taiga UI и разберемся, что делает их достойными внимания.
Web APIs for Angular
Мы с Ромой начинали свои приключения на просторах open source с проекта Web APIs for Angular. Это коллекция крошечных библиотек, оборачивающих браузерные API, такие как Canvas, IntesectionObserver, Web Audio API и другие. Все они следуют принципам:
Минимум вторжений в работу нативного JavaScript
Удобное использование этих API в приложениях в естественном для Angular виде
Это означает декларативные директивы, DI, сервисы и RxJS-потоки там, где на голом JS у вас были бы императивные методы, коллбэки и создание классов вручную. Я уже подробно описывал эту инициативу. В статье можно почитать обо всех существующих библиотеках и узнать, кто внес вклад в проект:
Вряд ли мы уже найдем время на авантюрные дополнения вроде Gamepad API или WebXR API, но это open source, и каждый может помочь его развитию. А если нам в работе потребуется еще какой-то API, то он появится впервые именно там.
Event manager плагины
Работа с событиями под капотом Angular остается малознакомой темой, хотя недавно о ней немного заговорили в Твиттере. Причиной этих разговоров стала наша библиотека.
В Angular мы можем расширять встроенное поведение с помощью DI. К примеру, можно научить Angular понимать, что при написании (click.stop)=”onClick()”
нужно вызвать $event.stopPropagation()
, а затем вызвать обработчик onClick.
Со временем мы собрали коллекцию небольших плагинов. Одни повышают удобство, другие добавляют важные фичи, которых раньше не было в Angular: например, дают возможность слушать события в capture-фазе.
Если вы используете Taiga UI, то все эти плагины уже включены, но они оформлены как отдельная библиотека, которую можно подключить в любой проект. Плагины добавляют модификаторы к стандартным DOM-событиям и CustomEvents. Модификаторы можно комбинировать, что позволит органично выразить немало логики одной строкой. Приведу пример.
Однажды у меня был компонент с формой, которую надо было уметь отправлять и сбрасывать. Хитрость в том, что место запуска этих действий ничего не знало про содержимое формы. Поэтому я использовал ng-content
и нативные кнопки type=”submit”
и type=”reset”
.
После отправки формы она тут же пропадала из DOM, так как была в модальном окне. Из-за динамической работы директивы формы Angular уничтожались раньше, чем могли отреагировать на событие submit
, поэтому происходило обновление страницы — естественная реакция формы на событие отправки. Кроме того, мне требовалась своя логика на сброс формы, а нативное событие reset просто обнуляло все поля ввода.
Вот как выглядела форма после подключения плагинов:
<form
(submit.capture.prevent.silent)="0"
(reset.capture.prevent.stop)="onReset()"
[formGroup]="form"
>
Мы слушаем событие submit
в capture-фазе и вызываем preventDefault()
, так что страница больше не перезагружается. Еще мы накинули модификатор .silent
, чтобы избежать повторного прогона проверки изменений, чем чуть-чуть ускорили работу компонента. И еще слушаем событие reset, снова в capture-фазе. Отменяем действие по умолчанию и останавливаем всплытие, чтобы ни браузер, ни Angular ничего с ним не делали, и запускаем свою логику в onReset()
. Остановка события в capture-фазе полностью предотвращает bubble-фазу.
Пример довольно экстремальный. Но он хорошо иллюстрирует, как с помощью пары слов можно выбраться из хитрой ситуации, обработка которой потребовала бы непростых решений в приложении без плагинов.
У этой библиотеки нет зависимостей, она весит меньше 2 КБ gzip и работает со всеми версиями Angular 12+. Уверен, что с ней станет комфортнее писать код, так что стоит попробовать!
Polymorpheus
Одна из моих любимых Angular-библиотек, потому что она осуществляет важный сдвиг парадигмы. В Angular есть несколько способов создать динамичный контент и несколько способов на него повлиять извне. Можно применить интерполяцию и передать в вызов функции некое входное значение:
{{ showSelected(items.length) }}
showSelected(length: number): string {
return length ? `${length} selected` : `Nothing is selected`
}
Можно использовать ng-template
и ngTemplateOutlet
, передав контекст в качестве входных данных, для чего-то более сложного — HTML, CSS, директив.
<ng-template let-length>
<strong *ngIf=”length else empty”>{{ length }} selected</strong>
<ng-template #empty>Nothing is selected<ng-template>
</ng-template>
Если нужно переиспользовать содержимое между приложениями или же обособить что-то полностью, подойдет ngComponentOutlet
и динамические компоненты. Передавать в них входные данные еще труднее, так как для этого до недавнего времени требовался свой инжектор.
Polymorpheus абстрагируется от сложностей и выбора и позволяет мыслить категориями контента и контекста. Эта библиотека добавляет директиву универсального аутлета, которую можно использовать с примитивами, функциями, шаблонами и компонентами одинаково.
<strong *polymorpheusOutlet=”content as text; context: context”>
{{ text }}
</strong>
В примере выше примитивные значения и результаты вызова функций отобразят <strong>value_or_function_result_here</strong>
. Шаблоны и компоненты будут инстанциированы на месте этой директивы.
С ходу может показаться, что это не так уже впечатляюще. Но стоит освоиться — и с таким подходом вам больше не нужно переживать, что дизайнеры изменят спецификацию компонента для большей визуальной кастомизации.
Maskito
Хоть это и не совсем Angular-проект, упомянуть его стоит обязательно. Maskito — фреймворк-независимая библиотека для маскирования инпутов и самый молодой член семьи.
У библиотеки прозрачный и гибкий API, она работает как с Angular, так и с React, Vue и нативными JavaScript-приложениями. Maskito можно использовать с библиотеками компонентов без прямого доступа к нативному инпуту, она обрабатывает любой способ взаимодействия пользователя: клавиатура, виртуальная клавиатура, автозаполнение, буфер обмена и так далее.
Я говорю о Maskito кратко только потому, что ее главный разработчик Никита уже рассказал про нее подробно:
Широко используемый фреймворк Ionic недавно назвал Maskito официальной рекомендацией для работы с маской в их компонентах. Чтобы узнать больше, можно пройтись по порталу документации.
Поощрительные призы
Есть несколько библиотек, которые мы также поддерживаем, и я бы хотел их упомянуть.
ng-morph помогает нам легко писать сложные схематики для миграции Taiga UI между мажорными версиями с ломающими изменениями. Она представляет собой большой набор инструментов для работы с глобальными преобразованиями кодовой базы через TapeScript AST. Не нужно знать, что делает TypeScript под капотом, достаточно воспользоваться готовыми функциями для изменения TS- и NG-сущностей. Правки выполняются на виртуальной файловой структуре, что позволяет проверить результат и устранить все проблемы до изменения файлов. Можно даже написать юнит-тесты на все функции и скрипты, прежде чем раскатывать их на большие проекты.
ng-dompurify — для тех, кто встречал надпись WARNING: sanitizing HTML stripped some content. Этот крошечный пакет позволяет расширить встроенные возможности Angular-санитайзера известной специализированной библиотекой DOMPurify. Больше информации — в моей старой статье, которая все еще актуальна. Часть про стили можно опустить, так как Angular их больше не проверяет.
@taiga-ui/cdk пригодится как библиотека компонентов, когда не нужна вся Тайга. Самый низкоуровневый пакет совершенно не привязан к внешнему стилю и полностью тришейкается. В нем есть масса полезных вещей для создания своих проектов: абстрактные классы для форм контролов, инструменты для мемоизации, утилиты для работы с RxJS, директивы, сервисы и многое другое.
На прощание
Не так давно все репозитории были объединены в организацию Taiga Family на GitHub. Эти библиотеки разрабатываются и поддерживаются нашей командой в Тинькофф. За ними стоит крупная коммерческая компания, и они активно используются во внутренних проектах. Это значит, что можно рассчитывать на их поддержку и развитие в будущем.
Попробуйте эти библиотеки, и если встретите баг или отсутствие желанных возможностей — не стесняйтесь завести issue в соответствующем GitHub-репозитории. А еще не пожалейте звезды: такое простое действие поможет нам понять, что наши опенсорс-инициативы востребованы и это дело стоит продолжать. Если вы хотите и сами принять участие в развитии наших продуктов — выбирайте задачи с пометкой Contributions welcome или Good first issue, мы будем рады любому вкладу в семью Taiga UI!