Skip to content

Latest commit

 

History

History
346 lines (236 loc) · 17.1 KB

File metadata and controls

346 lines (236 loc) · 17.1 KB

Contributing

Definition of Done для компонента

Компонент без пользовательской документации, theme contract и ручного checklist считается незавершённым и не принимается.

Explicit DOM principle

RepUI не угадывает намерения разработчика и не создаёт DOM, которого не запросил пользователь. Компонент должен рендерить ровно ту структуру, которую задаёт его API и переданный контент.

Запрещены implicit-преобразования без отдельного явно обоснованного контракта:

  • первый <h1> не превращается автоматически в CardHeader или Title;
  • обычная кнопка не становится автоматически Primary;
  • дочерний ButtonIcon не создаётся без явного запроса;
  • Badge не переносится в Header или Overlay самостоятельно;
  • отсутствующие секции не добавляются «для удобства».

Если компоненту нужна специальная DOM-секция, она должна быть выражена явным API, например {% card_header %}. Если этого тега или параметра нет, секция не появляется. Это сохраняет предсказуемость HTML, облегчает интеграцию с Django и не скрывает структуру от разработчика.

attrs — доверенные имена атрибутов

Параметр attrs — осознанный escape hatch для интеграций Django и HTMX. Он принимает mapping с доверенными именами HTML-атрибутов; RepUI экранирует их значения, но не нормализует и не ограничивает сами имена.

{% button attrs=button_attrs %}Сохранить{% endbutton %}

Передавайте в attrs только mapping, сформированный приложением, а не непроверенные пользовательские ключи. Для известных атрибутов предпочтительнее публичные параметры компонента: например aria_label, hx_get или id.

CSS responsibility layers

RepUI разделяет CSS на четыре уровня ответственности:

Foundation
    ↓
Layout
    ↓
Theme
    ↓
Components

Стрелка означает не зависимость модулей, а порядок ответственности: каждый следующий слой опирается на гарантии предыдущего и не переносит его обязанности к себе. Components могут использовать публичный Layout API, а Theme остаётся набором CSS-токенов и не импортирует модули.

Foundation

critical.css задаёт только стабильную геометрию первого кадра:

  • display, position, flex, grid;
  • min/max/inline/block-size;
  • overflow, contain, box-sizing.

Foundation отвечает на вопрос: «где и какого размера будет элемент?». В нём не должно быть цветов, теней, blur, radius, transition, шрифтов и других декоративных свойств.

Layout

Layout распределяет доступную область между Page, Container, Grid и Stack. Он не навязывает размер содержимому и не отвечает за оформление.

Theme

Theme отвечает на вопрос: «как элемент выглядит?». Здесь находятся background, foreground, border, shadow, radius, filter, opacity и их component tokens.

Components

Component CSS описывает собственную композицию и состояние, но не должен создавать page-level фундамент. Компонентам запрещено самостоятельно задавать body-reset, body { margin: 0 }, 100dvh для всей страницы или подменять Foundation/Layout. Такие требования должны быть вынесены на соответствующий уровень.

Classification checklist

Перед добавлением нового кода ответьте на эти вопросы по порядку:

  1. Это Foundation? Если код касается html, body, reset, 100dvh или page-level overflow, он должен находиться в Foundation.
  2. Это Layout? Если задача разделяет экран, задаёт колонку/строку или растягивает область, используйте Layout.
  3. Это Theme? Если изменение только визуальное — background, color, radius, shadow, blur или spacing — оформите token в Theme.
  4. Только если предыдущие ответы отрицательные, это Component: его задача — поведение и явная композиция.

Зависимости направлены сверху вниз по ответственности, а не наоборот:

Theme не знает о Grid, Grid не знает о Button, Button не знает о Page, а Card не знает о AppBar. Компонент может использовать публичные primitive-слои, но не должен забирать ответственность соседнего или более высокого слоя.

Responsibility test

Перед реализацией попробуйте мысленно удалить новый элемент:

  • если ломается вся страница — это Foundation;
  • если ломается только разметка — это Layout;
  • если меняется только внешний вид — это Theme;
  • если исчезает одна пользовательская возможность — это Component.

Explicit over implicit

RepUI не угадывает намерения разработчика:

  • Card не создаёт Header автоматически;
  • Grid не меняет размеры детей без явного указания;
  • Panel не становится Card;
  • AppBar не раскладывает содержимое;
  • Theme не меняет геометрию;
  • Layout не рисует оформление.

Публичная DOM-структура и поведение должны следовать явному API и переданному контенту.

Unified runtime contract

Если компонент предоставляет optional runtime, он использует единый lifecycle: mount...() должен быть идемпотентным, а возвращаемый handle — содержать element, refresh() и destroy(). Нативные компоненты не эмулируют браузерную семантику только ради общего API: runtime может быть lightweight handle без собственных click/keydown listeners.

Перед добавлением компонента проверьте, что в его каталоге есть:

  • краткое назначение: что это такое и когда его использовать;
  • публичный API: параметры, допустимые значения и defaults;
  • runtime API: функции, события и изменяемое состояние, если они есть;
  • theme contract: токены, fallback-зависимости и порядок переопределения;
  • правила композиции: допустимое содержимое и вложенность;
  • HTMX contract: innerHTML/outerHTML, mount и cleanup;
  • минимальные автоматические тесты: render, defaults, validation и DOM state;
  • короткий Manual checks для проверки глазами и действиями.

Для компонентов с runtime отдельно проверяется отсутствие дублированных listeners после повторного mount или HTMX swap.

Workbench contract

Страница компонента демонстрирует только его публичный контракт. Не нужно показывать внутренние CSS-классы, приватную DOM-структуру, реализацию template tag или приватные JavaScript-функции. Разделы страницы добавляются только если соответствующая возможность действительно есть в публичном API: например, Card и Panel не требуют пустого Runtime API-блока.

Минимальная структура

repui/components/<name>/
├── manifest.py
├── README.md
├── examples.py
├── quality.py
└── tests/
    └── test_<name>.py

Статические файлы и Django templates размещаются по стандартным каталогам repui/static/ и repui/templates/. Если компонент имеет runtime, его API и события описываются в README.md и проверяются в тестах.

Manifest компонента перечисляет только его собственные component assets. Глобальные Foundation, Theme и Layout-файлы подключаются приложением в фиксированном порядке и не должны добавляться в manifest:

"styles": (
    "repui/components/button/button.css",
)

Не добавляйте туда repui/foundation/*, repui/theme/* или repui/layout/*. Это не позволяет одному компоненту изменить порядок фундаментального каскада или случайно перекрыть активную тему.

Шаблон README.md

# ComponentName

## Назначение

Коротко: что делает компонент и когда его использовать.

## Public API

| Параметр | Значения | Default | Описание |
|---|---|---|---|
| `...` | `...` | `...` | `...` |

## Runtime API

Функции, события и состояние. Для stateless-компонента явно написать:
`Runtime API отсутствует`.

## Theme contract

| Token | Fallback | Назначение |
|---|---|---|
| `--rui-component-*` | `...` | `...` |

Порядок переопределения: application theme подключается после RepUI theme.

## Composition

Что можно вкладывать внутрь и в каких layout-контейнерах использовать.

## HTMX contract

Описать допустимый swap, необходимость mount и cleanup.

## Manual checks

- [ ] Основной сценарий работает мышью и клавиатурой.
- [ ] Light и dark отображаются корректно.
- [ ] Runtime-состояние применяется без reload.
- [ ] HTMX swap не создаёт дублированных listeners.

manifest.py

Manifest — машиночитаемый паспорт компонента. Он не заменяет README, но даёт Workbench возможность в будущем собирать каталог, assets и checklist без ручного центрального реестра.

COMPONENT = {
    "name": "component-name",
    "docs": {
        "summary": "Краткое назначение компонента.",
        "manual_checks": (
            "primary-interaction",
            "light-dark-theme",
            "htmx-no-duplicate-listeners",
        ),
    },
    "tokens": {
        "consumes": {
            "--rui-component-background": {
                "type": "color",
                "fallback": "--rui-color-surface",
            },
        },
    },
}

Названия checklist — стабильные machine-readable identifiers, а подробные инструкции остаются в README.md или отдельном документе компонента.

Перед commit

  • обновить README, manifest и checklist;
  • добавить или обновить минимальные тесты;
  • проверить demo в Workbench вручную;
  • выполнить тесты соответствующего компонента и manage.py check;
  • не добавлять скрытую совместимость или fallback без описания в документации.

Архитектурная цель

RepUI предназначена для backend-разработчиков.

Если при проектировании нового API приходится думать категориями Flexbox, CSS Grid, margin collapse или другими деталями браузера, вероятно, API находится на слишком низком уровне.

Публичный API должен описывать намерение разработчика, а не механизм реализации.

Workbench contract

Назначение

Каждый компонент RepUI может содержать собственную Workbench-композицию:

repui/components/<component>/<component>.html

Этот файл не является шаблоном самого компонента. Он предназначен для демонстрации, ручной проверки и объяснения публичного API компонента.

Приложение workbench только обнаруживает и монтирует эту композицию.

Обязательный корень

Workbench-композиция должна иметь один корневой Layout-компонент:

{% container %}
  ...
{% endcontainer %}

или:

{% stack %}
  ...
{% endstack %}

или:

{% grid %}
  ...
{% endgrid %}

Обычный <div> не считается корневым Layout-контрактом.

Запрещено

Workbench-композиция компонента не должна:

  • содержать {% page %};
  • содержать собственный AppBar страницы;
  • содержать sidebar приложения;
  • использовать {% extends %};
  • объявлять или переопределять {% block %};
  • знать URL, views или внутреннюю разметку приложения workbench;
  • зависеть от прикладных шаблонов workbench;
  • требовать специальной инициализации только ради монтирования страницы.

Page, AppBar, sidebar, navigation и рабочая область принадлежат shell приложения workbench.

Разрешено

Workbench-композиция может использовать:

  • публичные Layout-компоненты RepUI;
  • Card, Panel, Button и другие публичные компоненты;
  • обычный семантический HTML;
  • HTMX для локальных демонстраций;
  • runtime API демонстрируемого компонента;
  • прикладные стили, принадлежащие самому компоненту.

Доступный контекст

component
manifest
request

Композиция не должна требовать дополнительного контекста для базового рендера.

Независимость shell

Замена Page на BasePage, изменение AppBar, sidebar или всей оболочки Workbench не должна требовать изменений в файлах:

repui/components/*/*.html

Навигация

каталог компонента существует
→ пункт появляется

<component>.html отсутствует
→ пункт disabled

<component>.html существует и компилируется
→ пункт активен

Главное правило

Добавление нового компонента RepUI не должно требовать изменения кода приложения workbench.