# vanilla-beans спецификация

> Этот документ разъясняет понятия и сущности.

## Назначение библиотеки
**vanilla-beans** - нормализованная библиотека, предназначена для разработки пользовательских интерфейсов любой сложности и динамичности. Предоставляет возможность создания собственных компонентов - **beans** и объединения их в сложные композиты, непосредственно используя возможности HTML, Javascript и DOM API.

## Краткое описание
**vanilla-beans** - это тонкая надстройка над HTML и DOM API, не создаэт своего собственного окружения, не диктует правила и не изолирует Вас от возможностей WEB платформы. Всё, что можно делать с HTML и Javascript, можно делать с компонентами **vanilla-beans**. Декларация компонента, - это HTML для описания структуры компонента и Javascript для описания его поведения.

Компонент описывается наиболее очевидным для связки HTML и Javascript образом.

Библиотека экстремально лёгкая и быстрая. 

Крайне проста в освоении, достаточно знания основ HTML, Javascript и DOM API. 

Декларацию компонента может без подготовки понять любой человек, знакомый с этими основами.

Библиотека и идеи, на которых она построена просты и очевидны. 

Идеальна для обучения.

**vanilla-beans, не является альтернативой Web Components, прекрасно с ними совмещается в обе стороны.**

- [Термины и определения](#термины-и-определения)
- [Состав библиотеки](#состав-библиотеки)
- [Расширение HTML](#расширение-html) для использования в BeansModule declaration
- [Жизненный цикл бина](#жизненный-цикл-бина) - хэндлеры и коллбэки
- [Init script](#init-script) - скрипт инициализации
- [Built-in beans](#built-in-beans) - втроенные компоненты

## Термины и определения

### Bean
Композитный компонент, - основной строительный блок для построения пользовательского интерфейса, имеет своё дерево DOM, поведение и [жизненный цикл](#жизненный-цикл-бина). Может составляться из стандартных элементов, Custom Elements и других бинов.

### Bean declaration
Декларация бина - HTML разметка и (опционально) скрипт инициализации, описывающий поведение и обработчики событий жизненного цикла.

Минимальая декларация бина на базе элемента DIV:

```html
<div beans-as="my-bean"></div>

```
Парсинг декларации осуществляется штатными средствами браузера. HTML комментарии игнрируются при парсинге.

### BeanDescriptor
Дескриптор бина - внутреннее представление бина в репозитории, создаётся библиотекой из декларации бина.

### BeanInstance
Экземпляр бина, - DOM Node с подмешанными методами и обработчиками событий жизненного цикла, не содержит специфичных **beans-ххх** атрибутов. Создаётся библиотекой из BeanDescriptor

### BeansModule declaration
Текстовый файл или строка с набором деклараций бинов и импортом других BeansModule (аналогично модулям ESM), так-же может импортировать модули CommonJs (без зависимостей) и CSS файлы.

### BeansModule
Набор BeanDescriptor's в репозитории, создаётся бибиотекой из BeansModule declaration.

### Factory
Фабрика, связанная с конкретным BeansModule, готовая к инициализации контекстом приложения. Имеет интерфейс:

```ts
{
    with: ($context: any) => {
        create: (
            tag: string, 
            attributes: {[name]: string}
        ) => BeanInstance | Element
    }
}
```

### FactoryInitiated
Фабрика, связанная с конкретным BeansModule, инициированная контекстом приложения.

### Application
Приложение, в котором используются бины. Объединяется через **Application context**

### Application context
Произвольный объект, определяемый разработчиком приложения, который передаётся во все бины одного приложения через аргумент [скрипта инициализации](#init-script) **$context**.

**$context** может содержать, например, ссылку на контроллер, общий диспетчер сообщений, менеджер состояний, набор настроек, всё что полезно, - в зависимости от реализуемой архитектуры приложения.

## Состав библиотеки

### Модули
- [factory/factory.mjs](../lib/factory/factory.mjs) экспортирует по умолчанию фабричный метод **factory**, возвращающий экземпляр [Factory](#factory), принимает в качестве аргумента ключ (src) зарегистрированного модуля.

- [loader/load-vanilla-beans.mjs](../lib/loader/load-vanilla-beans.mjs) асинхронный загрузчик модулей, имеет интерфейс
```
    (src: string, callback: (factory: Factory) => void) => void
```

в аргументе коллбэка возвращается экземпляр [Factory](#factory), соответствуюший аргументу **src**.

### Сборки



## Расширение HTML
> **для использования в BeansModule declaration**

Библиотека расширяет HTML, вводя специальные тэги и атрибуты для использования в [BeansModule declaration](#beansmodule-declaration).

**Ни тэги, ни аттрибуты из ниже перечисленных не попадают в результирующее дерево DOM.**

### Tags
Добавлен только один тэг

#### <a name="BEANS-IMPORT">&lt;BEANS-IMPORT&gt;</a> используется в [BeansModule declaration](#beansnodule-declaration)  для подключения зависимостей. должен располагаться на верхнем уровне декларации модуля. 

```html
--imports
<beans-import type="html" src="./module.html" beans-as="my-module"></beans-import>
<beans-import type="cjs" src="../js/module.js" beans-as="my-script"></beans-import>
<beans-import type="css" src="../css/module.css" beans-as="my-stylesheet"></beans-import>

--beans declarations
.......

```

Настраивается атрибутами 

- **type** - тип подключаемого ресурса, может принимать значения 

    - **html** - для подключения [BeansModule declaration](#beansmodule-declaration)
    - **cjs** - для подключения модуля CommonJs, модуль CJS не должен иметь зависимостей.
    - **css** - для подключения файла css

    не обязательный, по умолчанию **"html"**

- **src** - относительный или абсолютный адрес подключаемого ресурса (URL или имя файла)

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

- **beans-as** - имя подключаемого ресурса для использования в декларациях бинов и скриптах инициализации

    обязательный, значение должно быть уникальным для тэгов BEANS-IMPORT в пределах [BeansModule declaration](#beansmodule-declaration), значение должно быть допустимым для использования в тэгах XML и не содержать символ "**.**" (точка)

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

### Атрибуты, используемые в [Bean declaration](#bean-declaration)
В декларациях бинов могут применяться семь дополнительных атрибутов

- **beans-as** - объявляет имя декларируемого бина для использования в других декларациях, располагается в корневом элементе декларируемого бина, значение не чувствительно к регистру. Значение может быть любой строкой.

    обязателен для [декларации нового бина](#bean-declaration).

- **beans-tagname** - может применяться в корневом элементе [Bean declaration](#bean-declaration) и в любом элементе внутри [Bean declaration](#bean-declaration), используется для подмены базового тэга, на основе которго создаётся бин, может принимать имя бина, имя станартного или пользовательского элемента, применяется в [BeanDescriptor](#beandescriptor) вместо **element.tagName**. Нужен для того, чтобы можно было использовать любой тэг в любом месте декларации.

    Значение не чувствительно к регистру, если указывает на имя бина или тэг HTML.

- **beans-usetag** - может применяться так-же как и **beans-tagname**, но не перекрывает имя бина, применяется в момент создания [экземпляра](#beaninstance). Нужен для того, чтобы из любого компонента создавать любые тэги.

- **beans-ref** - имя ссылки на элемент, для использования в [скрипте инициализации](#init-script)

- **beans-body** - указывает элемент в поддереве бина, в который будут монтироваться ноды извне, в бине может располагаться только один элемент с тэгом **beans-body**

- **beans-shadow** - атрибут указвает на то, что данный элемент будет иметь теневое дерево, значение атрибута - параметры теневого дерева в форме "param1=value1;param2=value2". Может создавать теневое дерево как для всего бина, так и для любого элемента в его поддереве.

- **beans-style** - используется только совместно с **beans-shadow**, значение - список имён импортированных файлов CSS, разделённых ";" (точка с запятой). Стили подключаются по возможности в **adoptedStyleSheets**, при невозможности подключения в **adoptedStyleSheets** добавляются как элементы **&lt;STYLE&gt;**

В декларациях бинов могут применяться любые другие атрибуты.

Использование атрибута **xmlns** означает, что элемент и его поддерево будут создаваться с соответсвующим **NAMESPACE**.

Пример декларации BeansModule с одним Bean, по имени "**root**" и теневым деревом.

```xml
-- импорты
<beans-import type="css" beans-as="mystyle" src="../css/my-style.css"></beans-import>
<beans-import type="css" beans-as="nextstyle" src="../css/next-style.css"></beans-import>

<beans-import type="html" beans-as="module1" src="./module1.html"></beans-import>
<beans-import type="html" beans-as="module2" src="./module2.html"></beans-import>

-- декларации бинов
<div beans-as="root" 
    beans-shadow="
        mode = closed;
        delegatesFocus = true;
    " 
    beans-style="mystyle; nextstyle;">

    <h1>Title!</h1>
    <ul>
        <module1.root beans-ref="first" beans-usetag="li">
        </module1.root>
        <module2.root beans-ref="second" beans-usetag="li">
        </module2.root>
    </ul>
    <script>
```

- **[Init script](#init-script)**
    
```xml
    </script>
</div>
```

## Жизненный цикл бина
Vanilla Bean в течении своей жизни проходит через следующие этвпы: 

- Создание - create
- Монтирование в документ - mount
- Начала обслуживания - start
- Обновление данных - update
- Окончание обслуживания - stop
- Демонтирование из документа - unmount
- Уничтожение - destroy

Для того, чтобы Bean мог реагировать на эти события предусмотрены хендлеры жизненного цикла 

- mount - 

```js
beanMount: (target: Node, before?: Node | number) => void
```
- unmount -
```ts
beanUnmount: () => void
```
- start -
```ts
beanStart: () => void
```

- stop -
```ts
beanStop: () => void
```

- update - 
```ts
beanUpdate: (data: any, options?: any, additional?: any) => void
```

- drstroy -
```ts
beanDestroy: () => void
```

- create - Для этого события нет специального хендлера, всё что нужно сделать при создании экземпляра Bean можно сделать в **Init script**, он вызывается автоматически, когда Вы вызываете

factory.create('your-bean-name')


## Init script 


## Built-in beans



