К содержимому
uiify

Оформление

Компоненты предоставляют семантическую разметку и документированный контракт состояния, без визуальных стилей. Оформляйте их обычным CSS, Tailwind или необязательным слоем @gunkin/uiify/styles.

Контракт оформления

Каждая публичная часть напрямую принимает ваши className, style, ref, обработчики событий, нативные свойства и атрибуты data-*. Параллельных свойств вроде contentClassName или triggerClassName нет.

Атрибуты идентичности и состояния принадлежат uiify. Они служат точками привязки стилей: меняйте состояние через свойства или нативное поведение HTML, а не записью в data-state. Пространство имён --uiify-* зарезервировано для геометрии, анимации и значений отдельных экземпляров.

<Popover.Root>
  <Popover.Trigger className="toolbar-trigger">Open</Popover.Trigger>
  <Popover.Content className="toolbar-popover" data-layout="compact">
    Actions
  </Popover.Content>
</Popover.Root>

Именование

Точка привязкиНазначениеПример
Маркеры идентичностиСтабильная идентичность компонента, задаётся uiifydata-uiify-popover
Маркеры анатомииПубличная часть составного компонента, задаётся uiifydata-part="content"
Атрибуты состоянияДоступное только для чтения отражение состояния для селекторовdata-state="open"
Пользовательские свойстваДинамическая геометрия и значения отдельных экземпляров--uiify-anchor-x

У каждого корня с состоянием есть один маркер data-uiify-<component>, значимо само его наличие. У каждой составной части есть одно значение data-part в kebab-case, например trigger, content, item или label. Свойства потребителя не могут переопределить эти значения.

Обычный CSS и Tailwind

[data-uiify-popover][data-part="content"] {
  min-inline-size: 12rem;
}

[data-uiify-popover][data-part="content"][data-state="open"] {
  opacity: 1;
}

/* Tailwind uses the same attributes. */
<div className="data-[state=open]:opacity-100" />

Полиморфизм

as и render заменяют отображаемый элемент. Собственная функция рендеринга должна передавать полученные свойства и ref в DOM-элемент, иначе маркеры, состояние и оформление перестанут работать.

behavior.css обязательна

Эта таблица стилей содержит правила, обеспечивающие работу состояния: позиционирование всплывающих блоков, размеры ::details-content, распространение через :has(), размещение скрытых полей ввода и переходы @starting-style. В ней нет цветов, шрифтов и отступов.

import "@gunkin/uiify/components/behavior.css";

Без неё компоненты отображаются, но их состояние не работает. Импортируйте её один раз в любом месте приложения.

Состояние задаётся атрибутом, а не классом

Компоненты отражают состояние в атрибутах data-* элемента, которому оно принадлежит, поэтому CSS может выбирать его без JavaScript и имён классов. На странице каждого компонента перечислены создаваемые им атрибуты.

.my-trigger[data-state="open"] { … }
.my-item[data-disabled] { … }

/* Native state works the same way, because the state IS native */
.my-panel:popover-open { … }
details[open] > summary { … }

Варианты тоже задаются атрибутами data-*, а не запросами стилей контейнера: контейнер не может запрашивать самого себя.

Значения — в разметке, правила — в таблице стилей

Значения отдельных экземпляров передаются как встроенные пользовательские свойства; все правила находятся в статической таблице стилей. Встроенные стили не поддерживают псевдоклассы, псевдоэлементы, запросы контейнера и @starting-style, а модель состояния зависит от всех этих механизмов.

Встроенные свойства передаются потоком вместе с HTML без расхождений при гидратации, а единственная таблица стилей разбирается один раз и кешируется. CSS-in-JS вместо этого вставляет блоки <style> в каждую границу и не кеширует их между запросами.

Три способа оформления

Собственный CSS. Выбирайте элемент и его атрибуты data-*; переопределять стили по умолчанию не нужно — их нет.

Tailwind. Те же атрибуты работают как варианты, например data-[state=open]:rotate-180. Примеры на сайте переключаются на оформление Tailwind в настройке Style в шапке.

@gunkin/uiify/styles. Необязательный слой обычного CSS со шкалами токенов OKLCH, светлой и тёмной темами и оформлением для каждого компонента — отправная точка, а не требование.

import "@gunkin/uiify/styles/reset";
import "@gunkin/uiify/styles";

Порядок каскада

Всё, что поставляет uiify, находится в именованном слое ниже вашего:

@layer ui.reset, ui.behavior, ui.tokens, ui.theme, app;

Ваш слой всегда имеет приоритет: для переопределений не нужны !important и ухищрения со специфичностью, а рефакторинг библиотеки их не ломает.

На каждой странице компонента перечислены его атрибуты и CSS-переменные, а также готовый к копированию CSS для обоих вариантов оформления.