diff --git a/README.md b/README.md index c4a4593..101b083 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,280 @@ -# dom.js +# dom.js — декларативное создание DOM с реактивностью на сигналах -Библиотека для быстрого и удобного построения динамических DOM элементов \ No newline at end of file +Библиотека предоставляет текучий (fluent) API для создания DOM-элементов и реактивного управления ими через собственную систему сигналов. + +## Установка + +```html + +``` + +## Быстрый старт + +```javascript +// Создать кнопку с реактивным текстом +const count = dom.signal(0); + +const button = dom.button('counter') + .cls('btn btn-primary') + .text(count) + .on('click', () => count(count() + 1)) + .done(); + +document.body.appendChild(button); +``` + +## API + +### Сигналы + +Сигнал — реактивный контейнер для значения. При изменении значения все подписчики автоматически уведомляются. + +```javascript +// Создание сигнала +const name = dom.signal('John'); + +// Чтение значения +console.log(name()); // 'John' +console.log(name.value); // 'John' + +// Изменение значения +name('Jane'); +name.value = 'Jane'; + +// Подписка на изменения +const unsubscribe = name.on((newVal, oldVal) => { + console.log(`${oldVal} → ${newVal}`); +}); + +// Отписка +unsubscribe(); +``` + +#### Производные сигналы `.map()` + +Создаёт новый сигнал, значение которого автоматически обновляется при изменении родительского: + +```javascript +const count = dom.signal(1); +const doubled = count.map(x => x * 2); + +console.log(doubled()); // 2 +count(5); +console.log(doubled()); // 10 +``` + +#### Управление памятью `.destroy()` + +Уничтожает сигнал, отписывая его от родителя и очищая всех слушателей: + +```javascript +doubled.destroy(); +``` + +#### Отладка `.chain()` и `.listenerCount()` + +```javascript +console.log(doubled.chain()); // 'signal_a1b2c → signal_a1b2c_map_1' +console.log(count.listenerCount()); // количество подписчиков +``` + +### Создание элементов + +Любой HTML-тег доступен как метод `dom`: + +```javascript +dom.div() //
+dom.div('app') //
+dom.section() //
+dom.span() // +``` + +CamelCase автоматически преобразуется в kebab-case: + +```javascript +dom.viewBox() // +``` + +### Инструкции + +После создания элемента конфигурация задаётся цепочкой инструкций. Все инструкции возвращают прокси элемента для продолжения цепочки. + +| Инструкция | Описание | Пример | +|---|---|---| +| `.id(id)` | Установить id | `.id('main')` | +| `.cls(classes)` | Добавить CSS-классы | `.cls('btn primary')` | +| `.atr(name, value)` | Установить атрибут | `.atr('href', '/home')` | +| `.atrs({...})` | Установить несколько атрибутов | `.atrs({ href: '/', title: 'Home' })` | +| `.css(styles)` | Добавить инлайн-стили | `.css('color: red;')` | +| `.pcss(selector, styles)` | Scoped-стили | `.pcss(':hover', 'color: blue;')` | +| `.mcss(query, styles)` | Media-запросы | `.mcss('(max-width: 768px)', 'font-size: 14px;')` | +| `.text(content)` | Установить текстовое содержимое | `.text('Hello')` | +| `.child(element)` | Добавить дочерний элемент | `.child(dom.span().done())` | +| `.children([...])` | Добавить массив дочерних | `.children([el1, el2])` | + +**Важно:** внутри `.atrs()`, `.children()` и других методов, где значения могут быть сигналами, нужно передавать их явно: + +```javascript +// Передача сигнала в атрибуты +const href = dom.signal('/home'); +dom.a().atr('href', href).done(); +``` + +#### Scoped-стили: `pcss` + +Создаёт стили, привязанные только к этому элементу, с уникальным классом: + +```javascript +dom.button() + .pcss(':hover', 'background: blue; color: white;') + .pcss('::after', 'content: "→";') + .done(); +``` + +Сгенерирует `