@cavicode/uikit-webadmin (1.0.2)

Published 2026-09-01 18:06:18 +03:00 by CaviCode

Installation

@cavicode:registry=
npm install @cavicode/uikit-webadmin@1.0.2
"@cavicode/uikit-webadmin": "1.0.2"

About this package

@cavicode/uikit-webadmin

Vue 3 UI-компоненты административных интерфейсов CaviCode/HVZ.

Установка

npm install @cavicode/uikit-webadmin

.npmrc:

@cavicode:registry=https://git.cavicode.tech/api/packages/cavicode/npm/

@tanstack/vue-table встроен в package bundle. Отдельная установка нужна только consumer, который напрямую импортирует его runtime API или типы.

Nuxt 4

// plugins/uikit.ts
import CavicodeUIKitWebadmin from '@cavicode/uikit-webadmin'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(CavicodeUIKitWebadmin)
})
// nuxt.config.ts
export default defineNuxtConfig({
  css: ['@cavicode/uikit-webadmin/style.css'],
})

Для template types consumer добавляет GlobalComponents augmentation. Nuxt components[] не подходит: опубликованный dist содержит compiled JS и .d.ts, а не каталог исходных .vue.

Tailwind v4 consumer должен импортировать package CSS в общий pipeline и сканировать compiled dist:

@import "tailwindcss";
@import "@cavicode/uikit-webadmin/style.css";
@source "../../../node_modules/@cavicode/uikit-webadmin/dist";

Путь @source зависит от расположения consumer stylesheet.

Компоненты (46)

  • Поля: UiInput, UiTextarea, UiSelect, UiCheckbox, UiRadio, UiColorInput, UiSearchInput.
  • Кнопки и иконки: UiButton, UiIconButton, UiIcon.
  • Формы/layout: UiFormField, UiFormGrid, UiCard, UiMetricCard, UiAlert.
  • Диалоги: UiModal, UiConfirmDialog, UiDrawer.
  • Таблицы: UiDataTable, UiSimpleTable, UiTableSearch, UiTableToolbar.
  • Навигация: UiPagination, UiTabs, UiPageHeader, UiBreadcrumbs, UiNavbar, UiSidebar, UiMenu, UiTooltip.
  • Состояния: UiState, UiStatusBadge, UiToast, UiSpinner, UiSkeleton, UiProgress.
  • Прочее: UiDropdown, UiMediaPicker, UiOrderControls, UiBarChart, UiLineChart, UiPieChart, UiTag, UiDefinitionList, UiDateDivider, UiLogConsole.

Базовый API 0.2

UiInput, UiTextarea, UiSelect, UiSearchInput, UiColorInput и UiDropdown используют размеры sm | md | lg. Поля связывают hint/error/success с контролом через aria-describedby; UiInput, UiTextarea и UiSearchInput поддерживают clearable и событие clear.

UiInput предоставляет slots prefix и suffix:

<UiInput v-model="amount" label="Сумма" clearable>
  <template #suffix></template>
</UiInput>

UiDropdown теперь выводит label визуально и поддерживает hint, error, success, required, loading, а также slots selection, option и empty. По умолчанию control занимает всю ширину контейнера. Prop fit-content сжимает trigger по выбранному тексту (не шире контейнера), при этом popup остаётся не уже trigger, расширяется под длинные option labels и ограничивается viewport:

<UiDropdown v-model="branchId" :options="branches" fit-content />

UiButton поддерживает loading, loading-text, block, icon, icon-position и href. В loading-state повторный action блокируется:

<UiButton icon="save" :loading="saving" loading-text="Сохраняем">
  Сохранить
</UiButton>

UiIcon выводит встроенные SVG по типизированному имени UiIconName, переданный Vue-компонент или slot. Icon font и внешняя загрузка шрифтов не требуются.

Breaking changes 0.2

  • UiFormField рендерит корневой div, а не label. Для связи кастомного контрола передаётся prop for; это исключает невалидные вложенные label.
  • UiRadio без name не создаёт уникальное имя. Для нативной keyboard-группы consumer передаёт одинаковый name всем radio.
  • DOM и CSS-классы базовых полей изменены; использовать внутренние селекторы компонентов как consumer API нельзя.

Навигация и overlays 0.3

UiNavbar и UiSidebar предоставляют структуру приложения и не зависят от router. UiSidebar поддерживает v-model:collapsed; для мобильной панели используется отдельный UiDrawer.

<UiSidebar v-model:collapsed="collapsed" collapsible>
  <template #default="{ collapsed }">...</template>
</UiSidebar>

UiBreadcrumbs принимает массив { label, href?, icon?, disabled? }. UiMenu принимает typed items и предоставляет activator props, которые нужно передать реальной кнопке через v-bind:

<UiMenu :items="actions" @select="runAction">
  <template #activator="{ props }">
    <UiButton v-bind="props">Действия</UiButton>
  </template>
</UiMenu>

Такая же схема activator используется у UiTooltip, чтобы aria-describedby и keyboard handlers находились на фокусируемом элементе.

Общий overlay stack

UiModal и UiDrawer используют общий stack, body lock, focus trap и focus restoration. При открытии нового modal layer нижние слои получают inert. UiDropdown, UiMenu и UiTooltip закрываются при смене stack, поэтому teleport-popover не может остаться активным над неактивным modal/drawer.

Политика модальных окон

UiModal по умолчанию не закрывается кликом по overlay или клавишей Escape. Пользователь закрывает окно только крестиком либо явным consumer action «Отмена»/«Закрыть»; программное закрытие через v-model="false" после успешной операции работает как обычно. Props close-on-overlay и close-on-escape с default false предназначены только для осознанных исключений.

Для дополнительного времени, статуса или другого содержимого справа от заголовка используется typed slot header-extra:

<UiModal v-model="open" title="Занятие">
  <template #header-extra><UiStatusBadge label="Проведено" /></template>
  <!-- Содержимое -->
</UiModal>

На экранах шириной до 768 px все UiModal разворачиваются на весь фактически видимый viewport, в том числе при открытой экранной клавиатуре, с учётом safe area и отдельной прокруткой body. Несколько открытых modal используют общий body lock, располагаются по порядку стека и корректно передают фокус верхнему окну либо внешнему opener после закрытия всего стека. Неактивные слои стека получают inert и скрываются от accessibility tree; только верхнее окно является modal и обрабатывает клавиатуру. UiDrawer по умолчанию закрывается по overlay и Escape. Popover закрываются по Escape/клику снаружи и при изменении общего overlay stack.

UiDataTable автоматически распознаёт строковый заголовок ID и ограничивает колонку диапазоном 72–112 px без переноса цифр. В UiSimpleTable для той же семантики consumer ставит table-id-column на соответствующие th и td.

Для реестров, которые на телефоне должны становиться карточками, используется opt-in prop mobile-cards. Роль колонки задаётся через ColumnDef.meta:

const columns = [
  { accessorKey: 'name', header: 'Название', meta: { mobileRole: 'title' } },
  { accessorKey: 'status', header: 'Статус', meta: { mobileRole: 'badge' } },
  { accessorKey: 'note', header: 'Комментарий', meta: { mobileFullWidth: true } },
  { id: 'actions', header: '', meta: { mobileRole: 'actions' }, cell: renderActions },
]

Поддерживаются роли title, subtitle, badge, field и actions, а также mobileLabel, mobileHidden и mobileFullWidth. По умолчанию колонка выводится как обычное поле. Desktop-представление при этом остаётся таблицей.

Таблицы 0.4

UiDataTable использует manual sorting/filtering: библиотека хранит и эмитит state, но server filtering, sorting и page slice выполняет consumer. Все состояния могут работать controlled через v-model:

<UiDataTable
  v-model:sorting="sorting"
  v-model:row-selection="selection"
  v-model:column-visibility="visibility"
  v-model:column-filters="filters"
  v-model:global-filter="search"
  v-model:page-size="pageSize"
  :data="pageRows"
  :columns="columns"
  :get-row-id="row => String(row.id)"
  toolbar
  searchable
  selectable
  show-column-visibility
/>

Для selection между страницами обязателен стабильный get-row-id; без него TanStack использует индекс строки текущего массива. selection-change содержит только загруженные выбранные rows, а row-selection-change — полный map ID.

Default toolbar поддерживает debounced search, slot filters, slot actions, selection actions, видимость колонок и page size. Его можно заменить slot toolbar или использовать UiTableToolbar отдельно. loading и empty также имеют slots.

UiPagination сохраняет 0-based page, но теперь поддерживает номера страниц, first/last, sibling-count, compact mode и show-jump. На узком viewport номера скрываются, оставляя touch-friendly direction controls.

Media и charts 1.0

UiMediaPicker применяет одну consumer policy к file dialog и drag-and-drop. Форматы задаются через MIME, wildcard или расширение; размеры указываются в bytes. Upload lifecycle остаётся у consumer и передаётся keyed map через file-states:

<UiMediaPicker
  v-model="files"
  :accept="['image/*', '.pdf']"
  :max-files="3"
  :max-file-size="10 * 1024 * 1024"
  :file-states="uploadStates"
  @add="upload"
  @rejected="showValidationErrors"
/>

UiBarChart, UiLineChart и UiPieChart используют общий набор props: loading, loading-text, empty-text, aria-label, show-legend, show-data, format-value и controlled v-model:selected-index. Marks доступны с клавиатуры и эмитят select; loading, empty и legend можно заменить slots. Bar/line дополнительно управляют grid и axes, pie — inner-radius и center value.

<UiLineChart
  v-model:selected-index="selectedPoint"
  :data="points"
  :loading="loading"
  :format-value="formatMoney"
  show-legend
/>

В UiDateDivider режим table рендерит валидную пару tr/td; количество колонок таблицы передаётся через colspan.

Consumer-owned state

UiToast и UiConfirmDialog презентационные. Consumer передаёт props и обрабатывает emits; Nuxt composables в пакет не переносятся.

Charts используют generic data:

type UiBarChartDatum = { label: string; value: number; color?: string }
type UiLineChartPoint = { label?: string; date: string; value: number }
type UiPieChartDatum = { label: string; value: number; color?: string }

Метрики 1.1

UiMetricCard отображает единичный KPI с типизированной иконкой, пояснением, цветовым тоном и slots icon, default, detail, aside. Компонент адаптивен и подходит для dashboard без consumer-копирования рамок, типографики и состояний:

<UiMetricCard
  label="Расчётная зарплата"
  value="42 500 ₽"
  detail="за август 2026"
  icon="payments"
  tone="success"
/>

Миграция на 1.0

Breaking changes и удаляемые consumer workarounds перечислены в docs/solutions/uikit-1-migration.md.

Ограничения версии 1.0.0

  • Upload transport и lifecycle файлов не входят в UiMediaPicker.
  • Charts ожидают неотрицательные значения; отрицательные pie values не строятся.
  • Export ./theme не предоставляет отдельный runtime API: tokens входят в общий style.css.

Разработка

npm ci
npm run typecheck
npm run build

npm run build также выполняет vue-tsc --noEmit. Тестов и lint script сейчас нет; изменения компонентов требуют проверки package build и consumer builds.

Dependencies

Development dependencies

ID Version
@tanstack/vue-table ^8.21.3
@types/node ^26.2.0
@vitejs/plugin-vue ^5.2.1
@vue/tsconfig ^0.7.0
sass-embedded ^1.100.0
tailwindcss ^4.3.3
typescript ^5.6.0
vite ^6.0.0
vite-plugin-dts ^4.5.0
vue ^3.5.0
vue-tsc ^3.3.8

Peer dependencies

ID Version
vue ^3.5.0
Details
npm
2026-09-01 18:06:18 +03:00
2
UNLICENSED
221 KiB
Assets (1)
Versions (15) View all
1.4.0 2026-09-13
1.3.0 2026-09-13
1.2.0 2026-09-06
1.1.3 2026-09-03
1.1.1 2026-09-03