Administrator
  • Joined on 2025-04-12

@ava3v/ui-vue (0.1.175)

Published 2026-09-18 18:59:20 +03:00 by Administrator

Installation

@ava3v:registry=https://git.ava3v.ru/api/packages/Administrator/npm/
npm install @ava3v/ui-vue@0.1.175
"@ava3v/ui-vue": "0.1.175"

About this package

Библиотека UI-компонентов ava3v software для внутренних приложений: реестры с серверной загрузкой, формы, модалки, раскладка. Vue 3 — основной пакет, React — порт с тем же CSS и той же headless-логикой; оба выходят одной версией. Живая документация каждого компонента с пропами, событиями, слотами и кодом на Vue и React — на стенде (`playground/ava3v-playground`, раздел компонента по ключу из [каталога](#12-каталог-компонентов)). Здесь — как это подключить и как оно устроено. История изменений — [react/CHANGELOG.md](react/CHANGELOG.md) (общий для обоих пакетов), релиз — [PUBLISHING.md](PUBLISHING.md).

@ava3v/ui-vue и @ava3v/ui-react

Библиотека UI-компонентов ava3v software для внутренних приложений: реестры с серверной загрузкой, формы, модалки, раскладка. Vue 3 — основной пакет, React — порт с тем же CSS и той же headless-логикой; оба выходят одной версией. Живая документация каждого компонента с пропами, событиями, слотами и кодом на Vue и React — на стенде (playground/ava3v-playground, раздел компонента по ключу из каталога). Здесь — как это подключить и как оно устроено. История изменений — react/CHANGELOG.md (общий для обоих пакетов), релиз — PUBLISHING.md.

Требования: Vue 3.4+ или React 18/19, TypeScript 5. Стили — один файл dist/ui.css.

Содержание

  1. Установка
  2. Быстрый старт
  3. Темы, плотность, токены
  4. Локализация
  5. Оверлеи: модалки, диалоги, попапы, Esc
  6. Уведомления и тултипы
  7. Формы и валидация
  8. Реестр Ava3vDataGrid
  9. Раскладка приложения
  10. React-порт
  11. Стенд, тесты, релиз
  12. Каталог компонентов
  13. Грабли

1. Установка

Пакеты лежат в npm-реестре Gitea. .npmrc в корне проекта:

@ava3v:registry=https://git.ava3v.ru/api/packages/Administrator/npm/
npm install @ava3v/ui-vue      # Vue
npm install @ava3v/ui-react    # React; пиры react и react-dom 18 или 19

write-excel-file — опциональный пир для экспорта грида в XLSX, подгружается лениво. Страницы пакетов: https://git.ava3v.ru/Administrator/-/packages/npm/%40ava3v%2Fui-vue и …%2Fui-react.

2. Быстрый старт

main.ts:

import { createApp } from 'vue'
import { Ava3vTooltipPlugin, setAva3vLocale } from '@ava3v/ui-vue'
import '@ava3v/ui-vue/dist/ui.css'
import App from './App.vue'

const app = createApp(App)
app.use(Ava3vTooltipPlugin, { showDelay: 300 })   // один тултип на всё приложение: data-tooltip / title / v-ava3v-tooltip
setAva3vLocale('ru')
app.mount('#app')

App.vue — два хоста монтируются один раз на приложение, без них notify() и ava3vConfirm() не имеют куда рендериться:

<template>
  <Ava3vSidebarLayout v-model:expanded="expanded">
    <template #drawer="{ expanded: open, toggle }">
      <Ava3vSideNavigation :items="menu" :expanded="open" @toggle="toggle" />
    </template>
    <RouterView />
  </Ava3vSidebarLayout>
  <Ava3vNotify />
  <Ava3vDialogHost />
</template>

Первый экран:

<script setup lang="ts">
import { Ava3vButton, Ava3vDataGrid, Ava3vModal, ava3vConfirm, notify, createRemoteDataStore, type Column } from '@ava3v/ui-vue'

const store = createRemoteDataStore({
  load: (request) => api.post('/api/items', { gridLoadOptions: request }).then(r => r.data),   // GridLoadResponse { data, totalCount }
})
const columns: Column[] = [
  { key: 'name', label: 'Наименование', sortable: true, filterable: true },
  { key: 'qty', label: 'Кол-во', type: 'number', alignment: 'right', format: '#,##0' },
  { key: 'createdAt', label: 'Создан', type: 'date' },          // без format — дата по локали
]
async function remove(row: Item) {
  const { confirmed } = await ava3vConfirm({ text: 'Удалить позицию?', intent: 'danger' })
  if (!confirmed) return
  await api.delete(`/api/items/${row.id}`)
  notify('Удалено', 'success')
  await grid.value!.refresh()
}
</script>

3. Темы, плотность, токены

Светлая тема и обычная плотность по умолчанию. Переключение — атрибуты на <html> или контейнере:

document.documentElement.dataset.theme = 'dark'        // 'light'
document.documentElement.dataset.density = 'compact'   // 'default'

Плотность локально — проп size="compact" у большинства контролов. Все CSS-переменные с префиксом --ava3v- (--ava3v-primary-color, --ava3v-bg-color, --ava3v-padding, --ava3v-font-size…), классы .ava3v-*, компоненты Ava3v*. Токены разнесены по файлам src/styles/variables/: _base.scss, _theme.light.scss, _theme.dark.scss, _mode.default.scss, _mode.compact.scss. Манифест токенов для экрана настройки темы — ava3vThemeTokens (Vue и React) и страница «Theme builder» на стенде.

4. Локализация

Два языка из коробки, ru по умолчанию: setAva3vLocale('en'). В компонентах локаль реактивна: useAva3vLocale() отдаёт словарь, useAva3vLocaleCode() — 'ru' | 'en'; голый computed(() => getAva3vLocale()) реактивным не будет.

Свои строки — патч поверх встроенного словаря, глубокий: задаёте только нужные ключи, новые ключи библиотеки берутся из встроенного. Патч не накапливается между вызовами, собирайте свои строки в одном месте:

import { setAva3vLocaleMessages, type Ava3vLocaleMessagesPatch } from '@ava3v/ui-vue'
const patch: Ava3vLocaleMessagesPatch = { dataGrid: { noData: 'Здесь пока пусто', batchPending: n => `Правок: ${n}` } }
setAva3vLocaleMessages('ru', patch)

Дефолтные тексты списков и пикеров (common.noData, common.loadingText, common.search, common.clear, common.selectAll, common.today, common.timePlaceholder) тоже берутся из словаря; проп компонента (emptyText, searchPlaceholder, …) важнее. Состояние локали лежит на globalThis: страница, где живут и @ava3v/ui-vue, и @ava3v/ui-react, задаёт локаль и патч один раз. Ограничение: подписи Pagination, FilterBuilder, Chart, Scheduler, PivotGrid, Timesheet, HtmlEditor и пресеты DateRangePicker пока переключаются только между ru и en и патчем не переопределяются.

Даты и числа в гриде форматируются по текущей локали (Intl), диалоги и модалки берут подписи кнопок из словаря; setAva3vDialogDefaults({ locale, labels }) переопределяет их для диалогов.

5. Оверлеи: модалки, диалоги, попапы, Esc

Ava3vModal

v-model:visible, title, width/height/maxHeight/fullscreen, loading (оверлей над телом, loading прокидывается в слот footer, чтобы погасить сабмит), closeOnEsc, closeOnBackdrop (клик засчитывается по mousedown и mouseup на подложке: протяжка текста из поля наружу окно не закрывает), draggable, subtitle, closeLabel, topmost/zIndex, режим формы formTitle/formMode/formModeLabels (заголовок «Создание/Редактирование/Просмотр: …»). Слоты header, header-actions (кнопки справа в шапке, перед крестиком), default, footer ({ loading }), overlay (свой слой поверх тела, например прогресс).

Перехват закрытия — форма с несохранёнными изменениями:

<Ava3vModal v-model:visible="open" title="Карточка" :before-close="onBeforeClose" />
<!-- или встроенное подтверждение без своего кода -->
<Ava3vModal v-model:visible="open" title="Карточка" :confirm-close="isDirty" />   <!-- isDirty — флаг приложения: useAva3vForm изменения не отслеживает -->

beforeClose(reason: 'backdrop' | 'escape' | 'closeButton' | 'api') возвращает false или промис с false, и окно остаётся; повторные Esc, пока промис висит, игнорируются. confirmClose задаёт вопрос через ava3vConfirm с фокусом на «Нет»: привычный Enter после Esc форму не выбрасывает. Программное visible = false гард не проходит. Своя кнопка «Отмена» зовёт modalRef.requestClose(), чтобы пройти тот же гард. При размонтировании открытой модалки через v-if фокус возвращается опенеру.

Программные диалоги

const { confirmed } = await ava3vConfirm({ title: 'Удаление', text: 'Удалить запись?', intent: 'danger' })
await ava3vAlert({ text: 'Сохранено' })
const r = await ava3vDialog({ text: 'Сохранить перед выходом?', buttons: 'yesNoCancel', intent: 'warning' })
// r.value: 'yes' | 'no' | 'cancel'; r.confirmed / r.cancelled / r.denied

Требуют <Ava3vDialogHost /> в корне; без него confirmClose модалки падает на window.confirm с предупреждением в консоли. У intent: 'warning' | 'danger' фокус по умолчанию на безопасной кнопке, у обычного вопроса — на подтверждении. Текст можно дать HTML (html), он проходит sanitizeDialogHtml.

Кто получает Esc

Esc обрабатывает только верхний слой overlayManager: модалка, диалог грида (попап-редактор, подтверждение удаления, контекстное меню), Ava3vPopup (и через него Popover, TimePicker, DateRangePicker), Ava3vDrawer, меню колонки и операций грида, полноэкранный Ava3vHtmlEditor, drill-down Ava3vPivotGrid. Слой под ним Esc не видит: закрывается попап, а модалка остаётся. Раскрытые комбобоксы (Select, Lookup, TagBox, DropDownBox, DatePicker) гасят Esc сами, когда фокус в них, и регистрируют слой на случай, когда фокус снаружи.

Свой компонент с попапом или панелью, которая должна перехватывать Esc:

import { useEscapeLayer } from '@ava3v/ui-vue'
useEscapeLayer(() => isOpen.value, () => { isOpen.value = false })   // пока isOpen — вы верхний слой

Без Vue — pushModalEscape(handler) возвращает функцию снятия слоя. Комбобокс, который обрабатывает Esc на своём корне, помечает владельца role="combobox" или aria-haspopup с aria-expanded="true" (OPEN_POPUP_OWNER_SELECTOR) либо вызывает preventDefault. Document- и window-слушатели Esc в компонентах не заводить: их порядок относительно модалки непредсказуем. Vue- и React-модалки на одной странице делят один стек, z-слои и блокировку скролла: состояние менеджера лежит на globalThis (версионированный ключ Symbol.for('ava3v.ui.overlayManager.v2')), а не в модуле каждого бандла; так же общее — состояние локали. Раскрытые Select, Lookup, TagBox, DropDownBox и DatePicker — тоже слои Esc. В React тот же слой — хук useEscapeLayer(open, close) из @ava3v/ui-react.

Попапы

Ava3vPopup — телепорт в body с позиционированием у якоря (target, position, offset), базовый для Popover, TimePicker, DateRangePicker; Ava3vPopover — карточка у якоря по клику или наведению; Ava3vContextMenu — меню с клавиатурой; Ava3vDrawer — панель справа или слева со scrim, inline — поверх позиционированного родителя. Z-слои выдаёт менеджер: попап внутри модалки всегда над ней.

6. Уведомления и тултипы

notify(message, type?, options?) — тосты через <Ava3vNotify />: type success | error | warning | info, шесть позиций, лимит одновременных с очередью, configureNotify({ position, duration, limit }), dismissNotification(id), dismissAllNotifications().

Тултип один на страницу. Три способа: атрибут data-tooltip="Текст" на любом элементе, нативный title (подхватывается и снимается, чтобы не всплывал второй), директива v-ava3v-tooltip="{ text, placement, multiline }". Опции плагина: showDelay, multiline, attributes: { text, placement, disabled } — имена атрибутов (data-tooltip-disabled="true" на предке выключает), data-tooltip-truncate — подсказка только когда текст реально обрезан (шапки грида, лукап). Закрывается по Esc, событие не гасит. У Ava3vButton проп disabledReason гасит кнопку и объясняет почему: тултип, aria-describedby, клик подавлен, кнопка остаётся в обходе с клавиатуры.

7. Формы и валидация

Раскладка: Ava3vFormLayout → секции Ava3vGroup → поля Ava3vFormField (подпись, обязательность, ошибка, режимы показа Ava3vValidationDisplay.Inline | Overlay | Tooltip). Режим формы Ava3vFormMode (create | edit | view) прокидывается полям.

const model = reactive({ name: '', email: '', qty: 0 })
const form = useAva3vForm(model, {
  name: [{ type: 'required' }, { type: 'maxLength', value: 200 }],
  email: [{ type: 'email' }],
  qty: [{ type: 'min', value: 1 }, { type: 'custom', validate: v => v % 10 === 0 || 'Кратно 10' }],
}, { groups: { main: ['name', 'email'] } })

if (!form.validate()) return                 // form.validate('main') — только группа; form.errors — карта
try { await api.save(model) }
catch (e) { form.setErrors(e.response.data.errors) }   // серверные ошибки тем же каналом

Контракт полей ввода: Ava3vInput (inputKind: text, password, email, search, phone, url, integer, decimal; маска, очистка), Ava3vNumberBox (парсинг, min/max, precision), Ava3vTextArea, Ava3vSelect (одиночный, множественный, табличный, remote-store), Ava3vTagBox, Ava3vLookup (табличный попап с поиском по справочнику), Ava3vDatePicker (date | datetime | time), Ava3vDateRangePicker, Ava3vTimePicker, Ava3vCheckBox, Ava3vSwitch, Ava3vRadioGroup, Ava3vSegmentedControl, Ava3vSlider, Ava3vRating, Ava3vFileUploader, Ava3vHtmlEditor. Все с v-model и disabled; readonly/invalid/size — у полей ввода, селектов и пикеров дат (у FileUploader, DateRangePicker, SegmentedControl, Slider, Rating и TextArea набор неполный — смотрите страницу компонента на стенде). Ava3vHtmlEditor очищает HTML по allowlist при записи значения в редактор, при вставке из буфера и на выходе: скрипты, обработчики событий, iframe, javascript:-ссылки и SVG в data: вырезаются, разметка самого редактора (заголовки, списки, таблицы, ссылки, картинки, выравнивание и цвет) сохраняется — открывать чужое описание на редактирование безопасно. Бэкенд всё равно обязан очищать HTML перед показом вне редактора. Ava3vTreeView управляется с клавиатуры (стрелки, Home/End, Enter/пробел; активный узел — aria-activedescendant). Десятичный ввод нормализуется (запятая → точка), modelValue числовых полей — строка при вводе и null при очистке; число даёт Ava3vNumberBox.

8. Реестр Ava3vDataGrid

Реестр данных с серверной или клиентской загрузкой. Ключевые пропы: rows или store, columns, rowKey (обязателен при выделении и редактировании: без него ключ — индекс, и между страницами он не сходится), pageSize, virtualScrolling, showFilterRow, showHeaderFilterButtons, showFilterBuilder, showSearch, showGroupPanel, selectionMode, editingMode, stateStorageKey, keyboardNavigation, masterDetail, columnHidingEnabled. Бэнды задаются вложенными columns[].columns, закрепление — column.fixed. Полный список с описаниями — страница datagrid стенда.

Колонки

const columns: Column[] = [
  { key: 'code', label: 'Код', width: 120, fixed: 'left', sortable: true, filterable: true },
  { key: 'statusId', label: 'Статус', lookup: { dataSource: statuses, valueExpr: 'id', displayExpr: 'name' } },
  { key: 'amount', label: 'Сумма', type: 'number', alignment: 'right', format: '#,##0.00' },
  { key: 'shippedAt', label: 'Отгрузка', type: 'date', format: 'dd.MM.yyyy HH:mm', headerFilter: { mode: 'dateTree', groupInterval: 'month' } },
  { key: 'actions', type: 'actions', showEditActions: true },
]

type: text | number | boolean | date | actions; без type в клиентском режиме тип выводится из данных. format: даты — токены yyyy MM dd HH mm ss, числа — fixedN, thousands, #,##0.00; type="date" без format показывает дату по локали. lookup (массив или словарь), calculateCellValue, calculateDisplayValue, customizeText, cellTemplate/слот cell-<key>, headerTemplate, editable, validationRules, hidingPriority, exportable. Декларативно — <Ava3vDataGridColumn> в слоте по умолчанию; autoGenerateColumns строит колонки из данных, явные накладываются по key.

Серверный режим

Фронт шлёт DataGridBackendRequest (skip, take, sort, columnFilters, filter, search, group, uniqueValues…), бэк отвечает { data, totalCount }. Контракт — docs/datagrid-backend-contract.md, серверная сторона на .NET — пакет Ava3v.Components.Contract из Ava3vLibs (там же массовые операции и интервалы дат). createRemoteDataStore({ load, mapLoadOptions?, mapResponse? }) оборачивает вызов; ответы { items, totalCount } и { results, total } принимаются как есть.

  • Загрузка идёт по сигнатуре запроса: перестановка и скрытие колонок, перерисовка и замена одинаковых фильтров запросов не шлют; замена store — шлёт.
  • refresh()/reload() после мутации всегда шлёт запрос и ждёт именно его, даже если предыдущий ещё летит.
  • serverLoadDebounceMs — дебаунс фильтров и поиска; страница, сортировка, группировка грузятся сразу.
  • События data-loading, data-loaded, data-error; getBackendRequest() — тело текущего запроса, им же описывается «всё по фильтру» для массовых операций.

Фильтры и поиск

Хедер-фильтр (showHeaderFilterButtons): чеклист значений, диапазон для чисел, дерево дат год → месяц → день; значения с сервера — запрос uniqueValues. Строка фильтров (showFilterRow) с операцией на колонку. Конструктор условий (showFilterBuilder, Ava3vFilterBuilder) с группами И/ИЛИ. Условие по колонке-дате сравнивает календарный день: значение 2026-03-05 для «равно», «не равно», «≤», «>» и «между» переводится в полуинтервал дня (>= 2026-03-05 и < 2026-03-06) — одинаково в клиентской фильтрации и в запросе серверу, поэтому колонка с датой-временем (DateTime из .NET) фильтруется так же, как показана. «Не равно» включает пустые даты. Своему коду тот же перевод даёт filterGroupToExpression(group, field => тип) и dateDayConditionExpression. Глобальный поиск (showSearch) по видимым колонкам с подсветкой. Чипы активных условий над таблицей, clearFilters().

Выделение

selectionMode: none | single | multiple; selectByRowClick, showSelectionColumn, allowDeselect (single: повторный клик снимает, false — семантика DevExtreme). v-model:selectedRowKeys; событие selection-change отдаёт selectedRowKeys и selectedRowsData — данные всех выделенных строк, которые грид загружал, включая другие страницы. selectionPersistence: keep (по умолчанию, ключи живут до снятия) или visible (после смены запроса остаются только ключи нового набора). «Выделить всё по фильтру» включается allowSelectAllMatching (лимит selectAllMatchingLimit, 10 000): в событии allMatchingSelected: true и excludedRowKeys, на бэк уходит GridSelectionRequest с телом getBackendRequest(); снимается при смене фильтра, поиска или группировки, сортировка его не трогает. Строки наружу — те же объекты, что пришли: row === rows[i], Set.has(row) работает; менять строку через объект события нельзя, обновляйте rows заменой массива.

Редактирование

editingMode: row (инлайн строка), cell, popup (форма в модалке), batch (панель «Несохранённых правок: N», методы ref saveBatchChanges()/cancelBatchChanges()); allowAdding/allowUpdating/allowDeleting, confirmDelete, колонка actions. События row-inserting, row-updating, row-removing управляют операцией: обработчик синхронно ставит event.cancel = true (операция не применяется, редактор остаётся) либо event.promise = api.save(...) — грид ждёт его. Resolve — операция применяется, в серверном режиме после вставки и удаления данные перезагружаются (не раньше: GET больше не гонится с DELETE); reject — не применяется, редактор остаётся, уходит событие edit-error { operation, key, data, error, message }, сообщение видно в самом гриде (в popup-форме — над кнопками, в инлайн-режимах — полосой над таблицей). Пока грид ждёт promise, «Сохранить» заблокировано и другая правка не начинается; «Отмена» доступна всегда — она бросает ожидание: редактор закрывается, а если promise позже всё же разрешится, данные применятся без вмешательства в текущий редактор. Новая строка рисуется первой поверх сортировки, фильтров и страниц и в любом режиме редактируется целиком; клик мимо новой строки без единого значения в редактируемых колонках отменяет её (addRow({ parentId }) заполняет только служебное поле — такая строка тоже пустая). В дереве черновик так же живёт вне иерархии: «добавить дочерний» встаёт сразу под родителем, после вставки родитель раскрывается. Ожидание row-removing грид не блокирует (редактора нет — нет и «Отмены»): строка приглушается, повторное удаление её же не срабатывает, отказ виден полосой над таблицей. Batch-правки переживают смену серверной страницы, сортировки и фильтра: «Сохранить всё» отправляет события и по строкам вне текущей страницы (с исходными данными), отклонённые остаются в накопленных. validationRules на колонке (required, min, max, pattern, custom). Редакторы — библиотечные Select/DatePicker/CheckBox/Input по типу колонки. Диалоги грида получают Esc первыми и возвращают фокус опенеру.

Группировка, итоги, экспорт, состояние

grouping (v-model:grouping) или column.groupIndex, панель группировки, итоги по группам и всей таблице (summary, groupSummary, allowSummaryConfiguration; в серверном режиме считает бэк). exportToExcel()/exportToCsv() (оба — Promise<number>) по умолчанию выгружают весь набор по текущим фильтрам и сортировке. При клиентской группировке в файле остаются строки-заголовки и итоги групп (все группы раскрыты; итоги, стоящие текстом в шапке группы, — там же); в серверном режиме группы разворачиваются в сортировку. Дерево выгружается в порядке узлов — все загруженные, со свёрнутыми ветками и догруженными детьми (серверное дерево — текущая страница рутов). В серверном режиме грид дочитывает набор сам: store.loadAll(options), если он есть (эндпоинт бэка с ToFlatExport), иначе постранично через store.load (pageSize 1000); больше maxRows (100 000) — ошибка, а не обрезанный файл. rows: 'page' — только экран, selectedOnly — выделенные. CSV: разделитель по локали (ru — ;, иначе русский Excel кладёт строку в одну колонку; свой — csvSeparator), ячейки, начинающиеся с = + - @, получают апостроф (защита от CSV-инъекции; апостроф в CSV виден как символ; числа со знаком, в том числе с единицей или валютой, и телефоны не трогаются; escapeFormulas: false — отключить). В XLSX числовые колонки уходят числами — кроме колонок со справочником, format, customizeText и calculateDisplayValue: они выгружаются текстом, как на экране. Черновик новой строки в файл не попадает. stateStorageKey — грид сам сохраняет и восстанавливает раскладку в localStorage (колонки, ширины, сортировки, фильтры, страница; выделение не сохраняется); getState()/applyState()/resetState()/ exportState()/importState(), событие state-change; при смене DATA_GRID_STATE_VERSION старое состояние не применяется. initialState — стартовая раскладка, сохранённое важнее.

Клавиатура и доступность

keyboardNavigation: стрелки по ячейкам, Enter — редактирование, Space — выделение, focusedRowKey. Таблица — role="grid" с aria-activedescendant, строки с aria-selected, шапка с aria-sort; известное ограничение — шапка отдельной таблицей, columnheader в дерево grid не входят.

Дерево

Ava3vTreeGrid — обёртка над гридом: items, columns, keyExpr, childrenKey (вложенные узлы) либо parentIdExpr + rootValue (плоский источник), hasChildrenExpr, treeColumn, v-model:expandedKeys, selectionMode, searchable. У самого грида дерево включается dataStructure="tree" с childrenExpr, loadChildren для ленивых узлов и перетаскиванием (allowRowReordering). Серверная сторона — TreeDataLoader в Ava3vLibs.

9. Раскладка приложения

Ava3vSidebarLayout (v-model:expanded, слот drawer для Ava3vSideNavigation, scrim) занимает высоту хоста; без сброса html, body, #app { height: 100% } берёт min-height: 100dvh (--ava3v-sidebar-layout-min-height: 0 для встраивания). Колонка контента — скролл-контейнер (overflow: auto): логика на window.scrollY его не увидит, свой скроллер внутри — --ava3v-sidebar-content-overflow: visible. Ava3vToolbar (start/center/end), Ava3vTabs, Ava3vAccordion, Ava3vSplitter, Ava3vStepper, Ava3vBreadcrumbs, Ava3vGroup — секция-карточка с колоночной раскладкой.

10. React-порт

Тот же CSS, те же токены, общая headless-логика (загрузка грида, фильтры, группировка, локаль, overlayManager) импортируется из src/ и обязана быть свободной от Vue: сборка React-пакета падает, если в source map попадает node_modules/vue. Компоненты — свои, с теми же пропами в camelCase и колбэками onXxx вместо событий: onVisibleChange, onSelectionChange, onRowClick. Слоты — пропы-функции (footer: ({ loading }) => …) или children. Ref грида — Ava3vDataGridRef с теми же методами (refresh, getState, applyState, selectAllMatching…). Хосты <Ava3vNotify /> и <Ava3vDialogHost /> монтируются в корне. Ava3vButton принимает autoFocus (диалоги ставят его на кнопку по умолчанию). Отличия: spinner в React нет, используйте Ava3vLoader или Ava3vSkeleton. Эталонный экран «реестр + карточка» — страница «React: реестр + карточка» стенда. Подробнее — react/README.md.

11. Стенд, тесты, релиз

npm run dev --prefix playground/ava3v-playground   # стенд: http://localhost:5133, #/<ключ компонента>, режим Vue/React в шапке
npx vitest run                                     # ~770 тестов Vue + React (jsdom для *.dom.test.ts)
npx vue-tsc -p tsconfig.build.json --noEmit        # типы Vue
cd react && npx tsc --noEmit                       # типы React
npm run build --prefix playground/ava3v-playground # стенд собирается строгим tsconfig — тоже гейт

Документация стенда — playground/ava3v-playground/src/docs/registry/<key>.ts: описание, пропы с дефолтами и контролами, события, слоты, код для Vue и React. Новый проп добавляется в реестр в том же релизе. Релиз — PUBLISHING.md: оба пакета одной версией, npm run build в react/ включает гейт утечки Vue, после публикации поднимаются фронты WareHub и Licensing.

12. Каталог компонентов

Ключ — раздел стенда.

Группа Компонент Ключ Статус Кратко
inputs Ava3vButton button stable типы normal/danger/success/warning, режимы заливки, disabledReason
inputs Ava3vInput input stable текст, пароль, email, телефон, число, маска, очистка, валидация
inputs Ava3vNumberBox numberbox stable число поверх Input: парсинг, min/max, precision
inputs Ava3vTextArea textarea stable многострочное поле, ограничение длины
inputs Ava3vSelect select stable одиночный, множественный, табличный, remote-store
inputs Ava3vTagBox tagbox stable множественный выбор с тегами и «+N»
inputs Ava3vLookup lookup stable выбор из справочника с табличным попапом
inputs Ava3vDropDownBox dropdownbox beta дропдаун с произвольным контентом (дерево с чекбоксами)
inputs Ava3vDropDownButton dropdownbutton stable кнопка с меню действий, split-режим, disabledReason
inputs Ava3vCheckBox checkbox stable флажок, indeterminate
inputs Ava3vSwitch switch stable тумблер
inputs Ava3vRadioGroup radiogroup stable группа радио
inputs Ava3vSegmentedControl segmented stable сегментированный переключатель
inputs Ava3vSlider slider stable значение и диапазон
inputs Ava3vRating rating stable оценка звёздами
inputs Ava3vDatePicker datepicker stable date / datetime / time
inputs Ava3vDateRangePicker daterange stable период с пресетами
inputs Ava3vTimePicker timepicker beta HH:mm с колонками
inputs Ava3vCalendar calendar stable инлайн-календарь с зумом
inputs Ava3vFileUploader fileuploader stable dropzone, превью, фильтр типов
inputs Ava3vGalleryChooser gallerychooser beta выбор изображения из галереи
inputs Ava3vHtmlEditor htmleditor beta форматированный текст, полноэкранный режим
inputs useAva3vForm formvalidation stable headless-валидация форм
data Ava3vDataGrid datagrid stable реестр: сервер/клиент, фильтры, выделение, редактирование, экспорт
data Ava3vTreeGrid treegrid stable дерево в виде таблицы поверх грида
data Ava3vTreeView treeview stable иерархическое дерево с каскадными чекбоксами
data Ava3vList list stable список с выбором и клавиатурой
data Ava3vPagination pagination stable окно страниц, размер страницы
data Ava3vFilterBuilder filterbuilder stable конструктор условий И/ИЛИ
data Ava3vPivotGrid pivotgrid beta сводная таблица с drill-down
data Ava3vChart chart stable bar / line / area / donut на SVG
data Ava3vGauge gauge stable круговая шкала KPI
data Ava3vScheduler scheduler beta планировщик день/неделя/месяц
data Ava3vGantt gantt beta диаграмма Ганта
data Ava3vTimesheet timesheet stable табель строки × периоды с инлайн-правкой
data Ava3vTimeline timeline beta лента событий
data Ava3vChat chatcomponent beta чат-лента
data Ava3vAvatar, Ava3vAvatarGroup avatar stable инициалы, картинка, группа
overlays Ava3vModal modal stable модалка с гардом закрытия
overlays ava3vConfirm / ava3vAlert / ava3vDialog dialog stable программные диалоги
overlays Ava3vDrawer drawer stable выезжающая панель
overlays Ava3vPopover popover stable карточка у якоря
overlays Ava3vContextMenu contextmenu stable контекстное меню с сабменю
overlays тултип tooltip stable плагин, директива, атрибуты
feedback notify notify stable тосты
feedback Ava3vAlert alert stable инлайновый баннер
feedback Ava3vBadge badge stable счётчик, точка
feedback Ava3vTag tag beta тег со статусным цветом и автоконтрастом
feedback Ava3vLoader, Ava3vLoadPanel loader, loadpanel stable индикатор и оверлей загрузки
feedback Ava3vProgressBar progressbar stable прогресс
feedback Ava3vSkeleton skeleton stable скелетоны
feedback Ava3vEmptyState emptystate stable пустое состояние
layout Ava3vSidebarLayout, Ava3vSideNavigation sidebar-layout, sidenav stable раскладка и навигация
layout Ava3vFormLayout, Ava3vGroup, Ava3vFormField formlayout, group stable раскладка форм
layout Ava3vToolbar toolbar stable панель инструментов
layout Ava3vTabs, Ava3vAccordion, Ava3vSplitter, Ava3vStepper, Ava3vBreadcrumbs, Ava3vSortable tabs, accordion, splitter, stepper, breadcrumbs, sortable stable навигация и раскладка
— Ava3vIcon, ava3vIconNames icons stable набор иконок

Страницы без компонента: typography, colors, density, themebuilder.

13. Грабли

  • rowKey обязателен при выделении, редактировании и stateStorageKey: без него ключ строки — индекс.
  • Строки грида не реактивные прокси: правка через объект события не перерисует грид, замените rows.
  • Хосты: notify() без <Ava3vNotify /> и ava3vConfirm() без <Ava3vDialogHost /> ничего не покажут.
  • Esc: не вешайте document/window-слушатели, используйте useEscapeLayer; иначе модалка либо закроется вместе с попапом, либо перестанет закрываться.
  • setAva3vLocaleMessages не накапливается: один патч на приложение.
  • Сайдбар: контент — скролл-контейнер, window.scrollY не растёт; sticky внутри контента липнет к нему.
  • refresh() в клиентском режиме пересобирает строки из rows, в серверном — шлёт запрос.
  • Экспорт идёт по тем же фильтрам без страниц; на бэке MaxTake на него не действует, но GridDataLoaderSettings продукта может ограничить размер.
  • Ломающие изменения до 1.0 возможны в патч-версиях и всегда отмечены в CHANGELOG в секции «Ломающие» — сверяйтесь перед обновлением.

Dependencies

Development Dependencies

ID Version
@types/node ^24.0.7
@types/react ^19.2.17
@types/react-dom ^19.2.3
@vitejs/plugin-vue ^6.0.0
@vue/compiler-sfc ^3.5.17
@vue/tsconfig ^0.7.0
jsdom ^29.1.1
react ^19.2.7
react-dom ^19.2.7
sass ^1.89.2
typescript ~5.8.3
vite ^7.0.0
vitest ^4.1.7
vue ^3.5.17
vue-tsc ^2.2.10
write-excel-file ^4.1.1

Peer Dependencies

ID Version
vue ^3.5.17
write-excel-file ^4.1.1
Details
npm
2026-09-18 18:59:20 +03:00
1
1.6 MiB
Assets (1)
Versions (178) View all
0.1.179 2026-09-26
0.1.178 2026-09-21
0.1.177 2026-09-21
0.1.176 2026-09-20
0.1.175 2026-09-18