@pgcorp/ui-kit
| Install | |
|---|---|
npm install @pgcorp/ui-kit |
|
| Latest Version: | 0.36.0 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Oct 19, 2026 |
| Links: | npm |
@pgcorp/ui-kit
Типизированная дизайн-система PGCorp для Vue 3: от базовых controls до полноценных workbench-интерфейсов.
A typed PGCorp design system for Vue 3, spanning foundational controls and complete workbench interfaces.
Vue 3 · TypeScript · exact public exports · 6 themes · MIT
Что входит / What is included
- Vue Single-File Components с типизированными props, slots, events и exposed methods. Vue Single-File Components with typed props, slots, events, and exposed methods.
- Controls, navigation, containers, data display, overlays и layout-примитивы. Controls, navigation, containers, data display, overlays, and layout primitives.
- Таблицы, деревья, редакторы, graph surfaces и составные workbench-компоненты. Tables, trees, editors, graph surfaces, and composed workbench components.
- Semantic CSS tokens и шесть светлых и тёмных тем. Semantic CSS tokens and six light and dark themes.
- Контракты keyboard navigation, focus, ARIA, loading, disabled, invalid и error states. Contracts for keyboard navigation, focus, ARIA, loading, disabled, invalid, and error states.
- Только явные package exports: wildcard и private source imports отсутствуют. Explicit package exports only, with no wildcards or private source imports.
Выборы и рабочие инспекторы / Choices and workspace inspectors
SCheckboxGroup.appearance="plain" | "cards" | "rows" и density задают
многократный выбор через общую choice surface и native checkbox owner.
SChoiceCards использует ту же визуальную основу с radio semantics.
busy, readonly и disabled имеют самостоятельные контракты.
columns="auto" у checkbox/radio-групп следует ширине контейнера через
общую шкалу колонок; числовое количество остаётся явным.
Составные подписи checkbox/switch выравниваются по первой строке общего SField.
См. контракт выбора.
SDrawer.density="compact" задаёт компактные поля header/body/footer и
центрирует заголовок относительно Close, сохраняя длинный текст, native hitbox,
scroll owner и retained content lifetime.
SModal.returnFocus и SDrawer.returnFocus предоставляют guarded workflow
successor, если открывший элемент удалён; SCollapsiblePanel.getSummaryElement()
возвращает настоящий summary owner без дополнительной остановки Tab.
returnFocusIntent задаёт явный successor даже при живом opener; opener и
null выбирают стандартный возврат и отмену. STextarea.getFocusTarget()
предоставляет nullable native destination без изменения focus/selection.
См. плотность Drawer
и жизненный цикл overlay.
Checkbox groups and radio cards share a substantive choice surface while
retaining their distinct native selection semantics.
Container-sized columns="auto" uses one shared column foundation while exact
numeric column counts retain their explicit contract. Compact drawer density
controls shared chrome and content spacing without changing lifetime or modality.
Cycle-bound returnFocus supplies an explicit workflow successor when the
original opener retires. returnFocusIntent explicitly selects a successor even
with a live opener, standard opener restoration, or cancellation. The typed
STextarea.getFocusTarget() exposes a nullable destination without changing focus
or selection. The linked guides describe states, validation and focus
priority in Russian and English.
Асинхронные состояния / Async states
SAsyncStateBlock предоставляет синхронный block/overlay entry без table row/cell
модулей и CSS. SAsyncState поддерживает тот же state/slot contract и отдельный
standalone table-row с обязательным colspan. Состояния, validation и live
announcements принадлежат одному общему owner.
В STable и табличном представлении SDataGrid сообщение состояния занимает
видимую ширину native viewport и переносится внутри неё при сохранённой
горизонтальной прокрутке. Колонки, положение прокрутки и scroll owner сохраняются.
См. контракт async-состояний.
SAsyncStateBlock exposes synchronous block/overlay feedback without table
row/cell modules or CSS. The comprehensive SAsyncState also supports standalone
table rows. Both entries share validation, state presentation and accessibility;
the guide separates import closure guarantees from application bundle budgets.
In STable and the table presentation of SDataGrid, state feedback wraps
within the visible native viewport at any retained horizontal offset. Columns,
scroll position, and scroll ownership are preserved.
Закрываемые вкладки и SSR / Closable tabs and SSR
STab #close, #actions и #editor сохраняют Vue owner и состояние через
Teleport в keyed targets вне role=tablist. Tab triggers принадлежат одному
semantic tablist; auxiliary controls используют его общий scroll/layout owner.
Editing сохраняет настоящий disabled tab и размещает редактор вне tablist.
Props/slots задают reserve/overlay и hover/always presentation; touch не требует
hover. Родитель подтверждает удаление и выбирает активную вкладку.
Keyed-перестановка сохраняет mounted auxiliary control, его черновик,
выделение и текущий keyboard focus; native Tab order соответствует порядку
участников. Focused auxiliary host остаётся подключённым при перестановке
соседей: native blur/focus events не подавляются, программный refocus не
выполняется. Намеренный внешний focus, blur и focus нового popup сохраняют
свою обычную семантику.
SSR-приложение вызывает assembleUiKitSsrTeleports из @pgcorp/ui-kit/ssr
после renderToString, затем размещает оставшиеся host Teleports. Контракт
сборки и гидратации описан в docs/ssr.md.
Public auxiliary slots preserve their Vue owner and local state outside the
semantic tablist. SSR applications assemble package-owned Teleports through
@pgcorp/ui-kit/ssr and retain responsibility for their host Teleports.
Keyed reordering retains the mounted auxiliary control, draft, selection,
and current keyboard focus while native Tab order follows participant order.
The focused auxiliary host remains connected while its siblings move;
native blur/focus events are not suppressed and no programmatic refocus is
performed. Intentional external focus, blur, and a new popup's focus retain
their normal semantics.
See the SSR contract for assembly and hydration.
Полные option-каталоги / Complete option catalogs
SListbox.virtualization задаёт measured viewport над полным набором options:
{ viewportHeight, estimatedItemHeight, overscan? }. Keyboard navigation, groups,
clear, disabled и multiple selection работают по всему каталогу. Для external
focus owner событие active-descendant-change передаёт ID смонтированной option
в STextarea.suggestions. Полный контракт и примеры включены в пакет: docs/listbox.md.
Активная option при внешнем focus имеет общий видимый focus ring; selection
background/check отображают выбранное значение независимо от активного пункта.
SListbox.virtualization provides a measured viewport over the complete option
catalog. Keyboard navigation and selection use the full inventory; the
active-descendant-change event supplies a mounted option ID to an external
focus owner. The package includes the complete contract and examples in docs/listbox.md.
The externally active option displays the shared visible focus ring; selection
background/check independently represent the selected value.
Связь поля и popup / Field-to-popup relationship
SSelect и SCombobox публикуют aria-controls только при смонтированном
доступном popup; aria-expanded отражает его фактическое присутствие.
Закрытие и скрытие owner удаляют ссылку, не меняя native trigger и стабильный
ID popup при повторном открытии. Нативный aria-activedescendant у SCombobox также
ссылается только на отрисованный вариант. Приложение использует публичные
props, доступное имя и роль; native ARIA-связями владеет компонент.
SSelect and SCombobox expose aria-controls only for their mounted,
admitted popup; aria-expanded reflects its actual presence. Closing or hiding
the owner removes the reference while retaining the native trigger and stable
popup id across reopening. SCombobox exposes aria-activedescendant only for
a rendered option. Applications use public props, names and roles; the component
owns native ARIA relationships.
Выбор в toolbar / Toolbar selection
SSelect.appearance="toolbar" отображает выбранное значение и одну стрелку
без постоянной видимой рамки или тени. Hover/open используют общую field surface,
keyboard focus — общий focus ring. field является значением по умолчанию;
swatch предназначен для marker-only выбора цвета. Тип SSelectAppearance
экспортируется из того же публичного модуля.
<SSelect
v-model="model"
:options="modelOptions"
appearance="toolbar"
size="xs"
aria-label="Модель сессии"
/>
Размеры xs/sm/md задают hitbox 32/36/40 px. Ширина принадлежит layout-контейнеру;
длинное выбранное имя усекается, а полные имена доступны в listbox. Toolbar popup
не уже trigger и ограничен viewport; обычный field popup совпадает с шириной
trigger. Single/multiple selection, группировка и markers используют общий
SListbox, без отдельного menu/button-контроллера.
readonly сохраняет Tab stop, но запрещает открытие. disabled исключает control
из Tab order; host использует его для недоступного или загружаемого каталога.
Отдельного loading prop нет. Переход в disabled/readonly закрывает открываемый
или открытый popup, сохраняя model и намеренный внешний focus. При снятии
блокировки требуется новое явное открытие.
SSelect.appearance="toolbar" displays the selected value and one chevron with
no permanent visible frame or shadow. Hover/open and keyboard focus share the
field foundation. The default is field; swatch is the marker-only color
presentation. SSelectAppearance is exported from the public component module.
Sizes xs/sm/md retain 32/36/40 px hitboxes. The layout container owns width;
long selected labels truncate while full option labels remain in the listbox.
The toolbar popup is at least as wide as its trigger and viewport-bounded;
the default field popup matches trigger width. Selection and grouping use the
same SListbox owner. readonly remains tabbable without admitting opening;
disabled is the host's unavailable/loading admission policy, not a loading
prop. Becoming blocked retires pending/open popup work without changing the
model or stealing external focus. Unblocking requires a new explicit opening.
Адаптивная строка / Adaptive controls
SControlBar и SControlBarItem измеряют actual demands, сохраняют единственный
экземпляр каждого control и предлагают typed overflow projection.
Активный control и его popup остаются видимыми; обязательные участники
переносятся целиком. SSelect.width="fit" использует фактическое содержимое,
width="full" сохраняет ширину поля; controlled open отделён от selection.
Композиция, strict identity, доступность и SSR описаны в
контракте адаптивной строки.
SControlBar and SControlBarItem measure actual demands and retain each
control instance. The overflow slot projects domain actions; active popup
owners remain visible and mandatory participants wrap as whole controls.
SSelect.width="fit" provides intrinsic width, while full is the default.
Controlled open is independent of selection. See the contract above for
identity, focus, allocation and SSR requirements.
Измеряемый прогресс / Measured progress
SProgressBar использует один numerical/accessibility owner для shape="linear"
и shape="circular". Линейная форма является default. Круговая форма имеет
размеры xs/sm/md = 24/28/32 px и требует явный value от 0 до 100 в
mode="determinate". showValue выводит округлённое число в центре;
aria-valuenow сохраняет точное значение, включая дробную часть.
valueText передаёт доступное предметное описание, например tokens/limit.
Существующий scoped default slot форматирует только linear label и получает
точный value; circular label принадлежит владельцу и отклоняет default slot.
Компактная моноширинная метка принадлежит SProgressBar: общий --font-mono,
размеры шрифта xs/sm/md = 8/9/10 px, межсимвольный интервал -0.05em и
line-height: normal задаются семантическими токенами --s-progress-ring-value-*.
Host-гарнитура должна содержать цифры, ≈ и ? и сохранять читаемость и зазор
между полной меткой ≈100 и кольцом во всех трёх размерах. Произвольная
гарнитура не гарантирует эту геометрию.
accuracy="estimated" требует valueText и показывает приблизительность.
mode="unknown" требует valueText, не принимает value и не сообщает
aria-valuenow. Эти состояния статичны. mode="indeterminate" обозначает
выполняющуюся операцию, не принимает showValue и учитывает reduced motion.
severity управляет semantic palette, а не выводится из процента автоматически.
<SProgressBar
:accessibility="{ mode: 'label', label: 'Заполнение контекста' }"
shape="circular"
size="md"
:value="37.5"
value-text="37 500 из 100 000 токенов"
show-value
severity="info"
/>
<SProgressBar
:accessibility="{ mode: 'label', label: 'Заполнение контекста' }"
shape="circular"
mode="unknown"
value-text="Размер контекста недоступен"
show-value
/>
Для действия показатель помещается в default slot SButton с
iconOnly, shape="circle", size="lg", density="default" и
appearance="ghost": штатная
контрольная область равна 48×48 px, то есть не меньше 44 px. Внутренний
показатель использует accessibility.mode="decorative"; действие, доступное
имя с точным значением и tooltip bindings принадлежат внешней кнопке.
Показатель не создаёт вложенный control или дополнительную остановку Tab.
SProgressBar shares numerical and accessibility ownership across linear and
circular shapes. Circular xs/sm/md sizes are 24/28/32 px. Determinate circular
progress requires an explicit value in 0–100; central display rounds the
percentage while aria-valuenow retains its exact precision. valueText
supplies a domain description such as tokens/limit. Estimated progress requires
valueText and a visible approximation marker. Explicit unknown progress
requires valueText, rejects value, omits aria-valuenow, and remains static.
Severity is consumer-selected rather than inferred from a percentage. The
existing scoped default slot formats linear labels and receives the exact
value. Circular labels are owner-controlled and reject a supplied default slot.
SProgressBar owns compact monospace typography through the shared --font-mono
and semantic --s-progress-ring-value-* tokens: xs/sm/md font sizes are
8/9/10 px, letter spacing is -0.05em, and line height is normal.
A host font must cover digits, ≈, and ? and retain readability and clearance
between the full ≈100 label and the ring at all three sizes. Arbitrary font
metrics are not guaranteed to fit this geometry.
For an actionable indicator, place decorative progress in the default slot of
a circular SButton with iconOnly, size="lg", default density, and
appearance="ghost": its target is
48×48 px, not exactly 44 px. The inner progress is decorative; the button owns
focus, the action, the accessible name, and tooltip bindings.
Установка / Installation
npm install @pgcorp/ui-kit @vue/devtools-api vue pinia vue-router
| Требование / Requirement | Версия / Version |
|---|---|
| Node.js | ^22.22.2 || ^24.15.0 || ^26.0.0 |
| npm | >=10.9.2 <12 |
| Vue | ^3.5.43 |
| Pinia | ^4.0.3 |
| Vue Devtools API | ^8.2.1 |
| Vue Router | ^5.3.1 |
| Build tool | Vite with Vue SFC support |
vue, pinia, @vue/devtools-api и vue-router являются peer dependencies. Consumer-приложение
владеет их единственными runtime-экземплярами.
vue, pinia, @vue/devtools-api, and vue-router are peer dependencies. The consumer application
owns their single runtime instances.
Tailwind/PostCSS принадлежат build-контуру приложения и объявляются его прямыми dev dependencies. / Tailwind/PostCSS belong to the application's build pipeline and must be declared as its direct dev dependencies.
npm install -D tailwindcss@^4.3.3 @tailwindcss/postcss@^4.3.3 postcss@^8.5.28
postcss.config.mjs:
export default { plugins: { '@tailwindcss/postcss': {} } }
Контракт установки: Tailwind CSS с PostCSS. / Setup contract: Tailwind CSS with PostCSS.
Быстрый старт / Quick start
Создайте корневой CSS entrypoint приложения. style.css подключает общую основу
кита, а явный @source регистрирует собранные модули пакета:
Create the application's root CSS entrypoint. style.css includes the kit's shared
foundation, while an explicit @source registers the built package modules:
@import "tailwindcss";
@import "@pgcorp/ui-kit/style.css";
@source "../node_modules/@pgcorp/ui-kit";
@source обязателен: Tailwind 4 не сканирует dependencies автоматически, а путь
разрешается относительно CSS-файла приложения. Runtime-импорт reference.css
не требуется. / @source is required because Tailwind 4 does not scan
dependencies automatically; the path resolves relative to the application CSS.
No runtime reference.css import is required.
SDocBlock загружает полную document typography вместе со своим component-модулем,
включая lazy imports. Для собственной HTML-разметки с prose, prose-sm,
dark:prose-invert и not-prose используйте tailwind.css вместо style.css:
этот entrypoint добавляет полный typography plugin к общей основе.
SDocBlock loads its complete document typography with its component module,
including lazy imports. For application-owned HTML using prose, prose-sm,
dark:prose-invert, and not-prose, use tailwind.css instead of style.css:
that entrypoint adds the complete typography plugin to the shared foundation.
Подключите CSS, Pinia и router в entrypoint приложения:
Import the CSS, Pinia, and router from the application entrypoint:
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import './styles.css'
import App from './App.vue'
import router from './router'
createApp(App)
.use(createPinia())
.use(router)
.mount('#app')
Импортируйте каждый компонент через точный публичный subpath:
Import every component through its exact public subpath:
<script setup lang="ts">
import SPanel from '@pgcorp/ui-kit/shared/containers/SPanel.vue'
import SButton from '@pgcorp/ui-kit/shared/controls/SButton.vue'
</script>
<template>
<SPanel
title="Профиль"
description="Настройки рабочей области"
:heading-level="2"
content-layout="stack"
content-gap="content"
>
<SButton appearance="solid" severity="primary">
Сохранить
</SButton>
</SPanel>
</template>
Production build должен разрешать package exports напрямую, без alias на исходный monorepo и без копирования файлов UI-kit.
The production build must resolve package exports directly, without a source monorepo alias or copied UI-kit files.
Локализация / Localization
UI-kit поддерживает en, ru, zh-CN и zh-TW. Без provider используется
ru; SUiKitLocaleProvider задаёт локаль для одного Vue subtree и не создаёт
дополнительный DOM-элемент. / The UI kit supports en, ru, zh-CN, and
zh-TW. Without a provider it uses ru; SUiKitLocaleProvider selects a
locale for one Vue subtree without adding a DOM element.
<script setup lang="ts">
import SUiKitLocaleProvider from '@pgcorp/ui-kit/shared/containers/SUiKitLocaleProvider.vue'
import type { UiKitLocale } from '@pgcorp/ui-kit/composables/useUiKitLocale'
const locale: UiKitLocale = 'en'
</script>
<template>
<SUiKitLocaleProvider :locale="locale">
<AppWorkspace />
</SUiKitLocaleProvider>
</template>
Provider переводит только kit-owned visible/assistive copy. Доменные данные и
пользовательский контент остаются ответственностью consumer. Вложенные provider
наследуют ближайший context и принимают типизированный messages override. /
The provider translates kit-owned visible and assistive copy only. Domain data
and user content remain consumer-owned. Nested providers inherit the nearest
context and accept a typed messages override.
Уведомления / Notifications
SControlledToastViewport отображает readonly application records и возвращает
serializable dismiss, action и lifetime-expired intents. Consumer остаётся
владельцем массива, порядка, ID и durable history. Режим consumer не создаёт
таймеры; режим viewport управляет только presentation lifetime и ставит его на
паузу при hover/focus. / SControlledToastViewport renders readonly application
records and emits serializable dismiss, action, and lifetime-expired
intents. The consumer owns the array, ordering, IDs, and durable history. The
consumer mode creates no timers; the viewport mode owns presentation
lifetime only and pauses it on hover/focus.
import type { SToastPresentation } from '@pgcorp/ui-kit/shared/data-display/toast'
import SControlledToastViewport from '@pgcorp/ui-kit/shared/data-display/SControlledToastViewport.vue'
SUiKitNotifierProvider маршрутизирует внутренний feedback SCodeBlock,
SCopyField, SExpandableText и SDocBlock в typed application-owned sink.
Provider не создаёт DOM, Pinia store, IDs, history или timers; async publisher
ожидается вызывающим действием. Host связывает intent со своим publisher и
SControlledToastViewport. / SUiKitNotifierProvider routes internal feedback
from SCodeBlock, SCopyField, SExpandableText, and SDocBlock to a typed,
application-owned sink. It creates no DOM, Pinia store, IDs, history, or timers;
the calling action awaits an asynchronous publisher. The host connects intents
to its publisher and SControlledToastViewport.
import SUiKitNotifierProvider from '@pgcorp/ui-kit/shared/containers/SUiKitNotifierProvider.vue'
import type { SUiKitNotificationIntent, SUiKitNotificationSink } from '@pgcorp/ui-kit/composables/useNotifier'
Контекст выбирается в setup, ближайший provider владеет маршрутом; смена sink
действует на следующее уведомление. Контракт и интеграция / Contract and integration.
Context is selected during setup; the nearest provider owns routing, and sink
replacement applies to the next notification.
При отсутствии provider SToastContainer и useNotifier образуют автономный convenience-контракт для
одного Pinia root. Store хранит не более 100 history records и освобождает свои
таймеры через $dispose()/$reset(). / Without a provider, SToastContainer and useNotifier
provide the autonomous convenience contract for one Pinia root. The store keeps
at most 100 history records and releases its timers through $dispose()/$reset().
Безопасные rich documents / Safe rich documents
SRichDocument отображает закрытую versioned SRichDocumentV1 AST без raw
HTML, VNodes, callbacks и trust flags. Внешний JSON проверяется через
validateRichDocument и validateRichDocumentResources; ошибки содержат
stable code и точный node path. Consumer-owned resources связываются по ID, а
link/resource/action effects возвращаются как typed intents. Link-node с
current: true выражает текущее назначение через aria-current="page".
Task lists, deletion, keyboard, sup/sub, disclosure и scoped footnotes имеют
собственные serializable nodes; raw markup для этих семантик не требуется.
Типизированный semantic profile включает hard breaks, inline/picture media,
rich summary/header content, definitions, ruby и структурные таблицы с
header associations, spans и footer. STable, SDataGrid и rich tables
используют общих native table owners. Якоря и повторные сноски имеют локальный
scope, раскрывают целевую секцию и переводят фокус без изменения истории.
heading.presentation: 'assistive' сохраняет нативный уровень, содержимое,
scoped anchors и IDREFs, визуально скрывая сам heading вне normal flow.
Значение по умолчанию — visible; интерактивные потомки в assistive heading
отклоняются с точным node path. GFM producer сохраняет скрытый heading сносок
и его describedBy references, не передавая raw class.
Вложенные блоки адаптируются к ширине контейнера при resize. Длинные строки
code fences имеют локальную горизонтальную прокрутку; viewport document
сохраняет полную высоту кода.
SRichDocument renders the closed, versioned SRichDocumentV1 AST without raw
HTML, VNodes, callbacks, or trust flags. External JSON is checked with
validateRichDocument and validateRichDocumentResources; failures include a
stable code and exact node path. Consumer-owned resources are joined by ID, and
link/resource/action effects are emitted as typed intents. A link node with
current: true exposes the current destination through aria-current="page".
Task lists, deletion, keyboard, sup/sub, disclosure, and scoped footnotes use
dedicated serializable nodes; these semantics never require raw markup.
The typed semantic profile includes hard breaks, inline/picture media, rich
summary/header content, definitions, ruby, and structural tables with header
associations, spans, and a footer. STable, SDataGrid, and rich tables share
native table owners. Anchors and repeated footnotes are scoped locally, reveal
their target disclosure, and move focus without changing browser history.
heading.presentation: 'assistive' retains the native level, content, scoped
anchors, and IDREFs while placing the heading outside normal flow. The default
is visible; interactive descendants fail at their exact node path. A GFM
producer preserves its hidden footnote heading and description references
without passing raw classes.
Nested blocks adapt to the container width on resize. Long code-fence lines
scroll horizontally within the block; the document viewport preserves the
complete code height.
SCheckbox presentation="inline" и SField contentFlow="phrasing" сохраняют
phrasing content model внутри текста. SLink предоставляет actual native
getElement()/focus() и semantic props domId, language, direction,
ariaLabel, ariaLabelledby, ariaDescribedby; IDREFs задаются непустыми DOM
идентификаторами через один ASCII-пробел без автоматического исправления ввода.
variant="document" принимает passive flow content в default slot напрямую
внутри native anchor, включая pre/table. Вложенные interactive descendants
и tabindex запрещены; document wrap принадлежит самому anchor.
/ SCheckbox presentation="inline" and SField contentFlow="phrasing" preserve
the phrasing content model inside text. SLink exposes the actual native
getElement()/focus() and the semantic props listed above; IDREFs are explicit
non-empty DOM identities separated by one ASCII space, without input repair.
variant="document" accepts passive flow content directly inside the native
anchor, including pre/table. Interactive descendants and nested tabindex
are rejected; the anchor owns document wrapping.
import SRichDocument from '@pgcorp/ui-kit/shared/data-display/SRichDocument.vue'
import {
validateRichDocument,
validateRichDocumentResources,
type SRichDocumentV1,
} from '@pgcorp/ui-kit/shared/data-display/richDocument'
Code highlighting and KaTeX load through local lazy chunks; SSR uses safe text
fallbacks. Полный security, resource, event и versioning contract описан в
docs/rich-document.md. / The complete security,
resource, event, and versioning contract is documented in
docs/rich-document.md.
Области прокрутки / Scroll viewports
SScrollViewport.radius="inherit" согласует native clipping и контур фокуса с
округлой оболочкой SPopover; token-sized значения задают углы самостоятельной
области. Default none сохраняет прямоугольную форму. Контракт углов и фокуса.
SScrollViewport владеет именованной или явно anonymous scroll областью, осями x/y/both,
semantic block size, overscroll policy и root-only keyboard navigation.
Событие scroll-state возвращает normalized physical и writing-mode-aware
semantic offsets. Exposed API предоставляет focus, scrollToBoundary и
reveal, но не открывает DOM owner.
semanticRole="region" — default именованного landmark; group задаёт
вложенную область без landmark, в том числе повторяемые журналы с одинаковыми
именами. focusPolicy="always" сохраняет выбранную роль и имя;
focusPolicy="overflow" добавляет их и Tab stop только при переполнении разрешённой оси. Имя задаётся
ровно одним из accessibleLabel и accessibleLabelledby для region/group.
semanticRole="none" опускает native role/name и запрещает name props, сохраняя
focus/keyboard policy. scrolling="delegated" сохраняет visible natural flow
без отдельного owner; disabled использует clip. domId задаёт typed viewport id.
blockSize="content"
сохраняет естественную высоту, maxBlockSize="none|sm|md|lg" ограничивает её
общей шкалой viewport. Таблицы STable, SDataGrid и rich-document используют
этот общий scroll owner: пустые и пассивные таблицы доступны клавиатуре при
переполнении, вложенные controls сохраняют собственную клавиатуру.
При исчезновении переполнения focused root сохраняет tabindex="-1" до blur;
он не добавляет остановку Tab и не переносит фокус.
SScrollViewport owns a named or explicitly anonymous scroll area, x/y/both axes, semantic
block size, overscroll policy, and root-only keyboard navigation. The
scroll-state event provides normalized physical and writing-mode-aware
semantic offsets. Its exposed API provides focus, scrollToBoundary, and
reveal without exposing the DOM owner.
semanticRole="region" is the default named landmark; group represents
a nested non-landmark area, including repeated logs with identical names.
focusPolicy="always" retains the selected role and name;
focusPolicy="overflow" adds them and a Tab stop only when an enabled axis overflows. Exactly one
of accessibleLabel and accessibleLabelledby supplies the region/group name.
semanticRole="none" omits native role/name and rejects naming props while
retaining focus/keyboard policy. scrolling="delegated" keeps visible natural
flow without a local owner; disabled clips. domId supplies the typed viewport id.
blockSize="content" retains intrinsic height; maxBlockSize="none|sm|md|lg"
uses the shared viewport limit scale. STable, SDataGrid, and rich-document
tables compose this scroll owner: overflowing empty and passive tables are
keyboard reachable, while nested controls retain their own keyboard behavior.
When overflow disappears, a focused root retains tabindex="-1" until blur;
it adds no Tab stop and does not move focus.
resizeBoundaries?: readonly SScrollViewportResizeBoundary[] задаёт physical
edge и обязательный canonical hitbox соседнего boundary-разделителя.
Default [] не резервирует clearance. Постоянная пассивная sizing frame
включает physical padding (hitbox token - 1px) / 2 в свой внешний logical
size/max/fill budget; native viewport сохраняет domId, consumer data-*,
ARIA, focus, keyboard, API и observer. $el обозначает frame, не native scroll
owner; для команд используется exposed API, для hooks — domId или data-*.
Frame не добавляет landmark, Tab stop или второй scroll controller. /
resizeBoundaries?: readonly SScrollViewportResizeBoundary[] declares physical
edge and required canonical hitbox for an adjacent boundary divider.
Default [] reserves no clearance. The stable passive sizing frame includes
physical padding (hitbox token - 1px) / 2 in its outer logical size/max/fill
budget; the native viewport retains domId, consumer data-*, ARIA, focus,
keyboard, API and its observer. $el identifies the frame, not the native
scroll owner; commands use the exposed API and hooks use domId or data-*.
The frame adds no landmark, Tab stop or second scroll controller.
import SScrollViewport from '@pgcorp/ui-kit/shared/data-display/SScrollViewport.vue'
import type {
SScrollViewportApi,
SScrollViewportResizeBoundary,
SScrollViewportSemanticRole,
SScrollViewportState,
} from '@pgcorp/ui-kit/shared/data-display/scrollViewport'
SScrollViewportResizeBoundary доступен также из корневого @pgcorp/ui-kit. /
SScrollViewportResizeBoundary is also exported from @pgcorp/ui-kit.
Вложенные inputs, editors и terminals сохраняют собственную клавиатуру,
selection и native copy. Полный axes, state, API и lifecycle contract описан в
docs/scroll-viewport.md. /
Nested inputs, editors, and terminals retain their keyboard behavior,
selection, and native copy. The complete axes, state, API, and lifecycle
contract is documented in
docs/scroll-viewport.md.
SPanel компонует canonical owner через scrollBehavior,
contentAccessibility и contentFocusPolicy, без отдельной реализации focus
или клавиатуры. Built heading задаёт точное SSR-safe имя; untitled/custom header
используют anonymous owner либо явное имя приложения. /
SPanel composes the canonical owner through scrollBehavior,
contentAccessibility and contentFocusPolicy, without separate focus or
keyboard mechanics. A built heading provides an exact SSR-safe name;
untitled/custom headers use an anonymous owner or an explicit application name.
contentGeometry="flow | fill" независимо задаёт natural или bounded высоту
содержимого; fill требует grow и конечной высоты внешней композиции.
При отсутствии prop сохраняется grow+child → fill, остальные комбинации → flow.
SLeftSidebar явно выбирает fill для всех режимов прокрутки. /
contentGeometry="flow | fill" independently selects natural or bounded content
height; fill requires grow and a finite outer composition height. Omission
preserves grow+child → fill and flow for other combinations. SLeftSidebar
explicitly selects fill for every scrolling mode.
SPanel.resizeBoundaries передаёт тот же canonical type только собственному
content viewport. self и auto+grow сохраняют его scrolling; body
делегирует scrolling внешнему owner, child — вложенному reader. Для nested
reader clearance задаётся на самом reader через его публичный API, не
наследуется из prop панели. Padding, end inset и contentGeometry сохраняют
собственные контракты. /
SPanel.resizeBoundaries forwards the same canonical type only to its own
content viewport. self and auto+grow retain its scrolling; body delegates
to an outer owner and child to a nested reader. Nested-reader clearance is
declared on that reader's public API, not inherited from the panel prop.
Padding, end inset and contentGeometry retain their own contracts.
Полный контракт / Full contract:
docs/panel.md.
Карта компонентов / Component map
| Группа / Group | Назначение / Purpose | Примеры exports / Example exports |
|---|---|---|
| Layout | App shell, dock regions, stacks, workbench layout | layout/SAppShell.vue, layout/SStack.vue, layout/SWorkbenchLayout.vue |
| Controls | Buttons, fields, inputs, switches, selects, comboboxes, menus | shared/controls/SButton.vue, shared/controls/SSwitch.vue, shared/controls/SCombobox.vue |
| Containers | Panels, modal, drawer, popover, sidebars | shared/containers/SPanel.vue, shared/containers/SModal.vue, shared/containers/SPopover.vue |
| Data display | Tables, charts, metric cards, scroll regions, chips, status, progress, code, JSON, tooltips | shared/data-display/STable.vue, shared/data-display/SChart.vue, shared/data-display/SScrollViewport.vue |
| Navigation | Tabs, breadcrumbs, catalog navigation, wizard | shared/navigation/STabs.vue, shared/navigation/SBreadcrumbs.vue, shared/navigation/SWizardSteps.vue |
| Complex surfaces | Tree, Kanban, data grid, SQL editor, graph | shared/complex/STree.vue, shared/database/SDataGrid.vue, shared/graph/SGraphViewport.vue |
| Runtime | Themes, variants, icons, composables, stores | theme, variants, icons, composables/useNotifier, stores/useNotifierStore |
Полный машинно-читаемый каталог находится в package.json#exports. IDE и
TypeScript показывают доступные subpaths при импорте.
The complete machine-readable catalog is declared in package.json#exports.
IDEs and TypeScript expose the available subpaths during import.
Переносимые строки действий / Wrapping action rows
SStack direction="row" wrap="wrap" align="center" gap="control" размещает
действия рядом и переносит целые controls при нехватке ширины. wrap принимает
nowrap | wrap, default — nowrap; тип SStackWrap экспортируется из
layout/SStack.vue. DOM-порядок и Tab-порядок сохраняются. Stack не задаёт
ширину, hitbox или типографику controls. Длинная подпись кнопки использует её
публичный labelOverflow="wrap". При direction="column" перенос требует
ограниченной высоты контейнера, как в нативном flex layout.
SStack direction="row" wrap="wrap" align="center" gap="control" places
actions side by side and wraps whole controls when inline space is insufficient.
wrap accepts nowrap | wrap, defaulting to nowrap; SStackWrap is exported
from layout/SStack.vue. DOM and Tab order remain unchanged. The stack does not
set control widths, hitboxes, or typography. A long button label uses its public
labelOverflow="wrap". With direction="column", wrapping requires a bounded
container height, following native flex layout.
Пагинация разделяет полный диапазон и группу коротких действий. Контракт и consumer example: Пагинация листов и реестров.
Pagination keeps the full range separate from its short action group. The supported composition and consumer example are documented in Sheet and registry pagination.
Реестры и свободный ввод / Registries and custom values
STable владеет служебными колонками выбора и раскрытия. Consumer передаёт
controlled keys и доменный контент, не копирует checkbox, disclosure или CSS:
STable owns selection and disclosure columns. Consumers provide controlled
keys and domain content instead of copying checkboxes, disclosures, or CSS:
import type {
STableColumn,
STableSort,
} from '@pgcorp/ui-kit/shared/data-display/table'
<STable
v-model:selected-row-keys="selectedRowKeys"
v-model:expanded-row-keys="expandedRowKeys"
:columns="columns"
:data="rows"
:get-row-key="(row) => row.id"
:get-row-label="(row) => row.name"
selection-mode="multiple"
aria-label="Поставщики"
@row-contextmenu="openRowMenu"
>
<template #row-details="{ row }">
<SupplierDetails :supplier="row" />
</template>
</STable>
Для служебных столбцов доступны headerPresentation: 'assistive',
width: '2xs' и width: 'content'. SCombobox принимает новое строковое
значение через allow-custom-value; SPageHeader сочетает appearance="bare"
с title-presentation="assistive" для доступного заголовка без визуальной полосы.
Utility columns support headerPresentation: 'assistive', width: '2xs', and
width: 'content'. SCombobox accepts a new string value with
allow-custom-value; SPageHeader combines appearance="bare" with
title-presentation="assistive" for an accessible zero-chrome heading.
Составная сортировка использует controlled v-model:sorts: consumer задаёт
sort-mode="multiple" и передаёт ordered STableSort[]. Клик по
заголовку добавляет критерий, меняет направление или удаляет его; номер возле
заголовка показывает приоритет. Таблица не переставляет строки самостоятельно.
Multi-column sorting uses controlled v-model:sorts: the consumer sets
sort-mode="multiple" and provides an ordered STableSort[]. Header activation
adds a descriptor, changes its direction, or removes it; the visible number is
the priority. The table never reorders rows on its own.
Последовательные действия заголовков формируют внутренний intent draft до
подтверждения controlled prop. Consumer может применить sort/sorts через
store или асинхронный render-cycle: второй критерий не теряет первый. Любое
authoritative обновление prop становится новой базой следующих действий.
Sequential header actions update an internal intent draft until the controlled
prop is acknowledged. Consumers may apply sort or sorts through a store or
an asynchronous render cycle without losing an earlier criterion. Any
authoritative prop update becomes the base for subsequent actions.
<STable
v-model:sorts="sorts"
:columns="columns"
:data="sortedRows"
:get-row-key="(row) => row.id"
sort-mode="multiple"
aria-label="Позиции прайс-листа"
/>
Графики и метрики / Charts and metrics
SChart является единым semantic owner для line, area, grouped/stacked bar,
pie и donut. Размеры compact, sm, md, lg, оси, сетка, легенда,
маркеры, подписи, auto/fixed domain и таблица данных задаются typed props.
Компонент пересчитывает SVG-геометрию по фактическому контейнеру, сохраняет
читаемую типографику и переносит длинные подписи категорий на узкой ширине.
SChart is the single semantic owner for line, area, grouped/stacked bar, pie,
and donut charts. Typed props control compact, sm, md, and lg sizes,
axes, grid, legend, markers, labels, auto/fixed domains, and the data table. The
component recomputes SVG geometry for its actual container, preserves readable
typography, and wraps long category labels at narrow widths.
Форматированные подписи шкалы Y участвуют в расчёте поля графика. Крайние
подписи X привязаны к границам plot-area, поэтому x-labels="auto" сохраняет
полные начальное и конечное значения и не обрезает их краем SVG. Если ширины
контейнера физически недостаточно, визуальная подпись сокращается, а полное
значение остаётся в tooltip и доступной таблице данных.
Formatted Y-axis labels participate in plot-gutter calculation. Endpoint
X labels are anchored to the plot boundaries, so x-labels="auto" preserves
the full first and last values instead of clipping them at the SVG edge. When
the container is physically too narrow, the visual label is shortened while
the full value remains available through the tooltip and accessible data table.
import type {
SChartCategory,
SChartSeries,
} from '@pgcorp/ui-kit/shared/data-display/chart'
<SChart
type="area"
:categories="categories"
:series="series"
:accessibility="{
mode: 'label',
label: 'Нагрузка VPN по часам',
description: 'Входящий и исходящий трафик',
}"
x-axis-label="Час"
y-axis-label="Мбит/с"
legend="top"
/>
Для компактного тренда SMetricCard предоставляет слот #chart. Декоративный
график внутри уже озвученной карточки использует
accessibility.mode="decorative" и data-table-presentation="none";
содержательный самостоятельный график сохраняет default assistive data table.
SMetricCard exposes #chart for a compact trend. A decorative chart inside an
already labelled card uses accessibility.mode="decorative" with
data-table-presentation="none"; a meaningful standalone chart keeps the
default assistive data table.
Сравнение исходников / Source diff
SDiffViewer является semantic owner для exact-text diff. before.text и
after.text сравниваются без нормализации переводов строк или содержимого;
label, revision и language являются metadata. layout="unified" сохраняет
единый горизонтальный scroll для длинных строк, layout="split" показывает
равные колонки с переносом кода. viewport использует те же semantic размеры,
что и code surfaces.
SDiffViewer is the semantic owner for exact-text diff. before.text and
after.text are compared without newline or payload normalization; label,
revision, and language are metadata. layout="unified" preserves one
horizontal scroll surface for long lines, while layout="split" renders equal
columns with wrapped code. viewport uses the same semantic sizes as the code
surfaces.
import type {
SDiffResult,
SDiffSource,
} from '@pgcorp/ui-kit/shared/data-display/diff'
import SDiffViewer from '@pgcorp/ui-kit/shared/data-display/SDiffViewer.vue'
<SDiffViewer
v-model:expanded-gap-ids="expandedGapIds"
:before="baseSource"
:after="currentSource"
:context-lines="3"
layout="split"
viewport="expanded"
ariaLabel="Изменения конфигурации"
@computed="handleComputed"
@retry="handleRetry"
/>
contextLines задаёт число видимых неизменённых строк вокруг каждого hunk.
Без expandedGapIds компонент владеет раскрытием gap; с
v-model:expanded-gap-ids consumer применяет intent как controlled state.
computed передаёт валидированный SDiffResult, retry сообщает о повторном
запуске после ошибки. Для синхронного вычисления вне интерактивной поверхности
экспортируется computeDiff(before, after, options).
contextLines selects the unchanged lines around each hunk. Without
expandedGapIds, the component owns gap expansion; with
v-model:expanded-gap-ids, the consumer applies expansion intents as controlled
state. computed provides a validated SDiffResult, and retry reports a
retry after an error. computeDiff(before, after, options) is exported for
synchronous computation outside an interactive surface.
Строки виртуализируются независимо от размера source. Дорогие интерактивные вычисления выполняются через управляемый worker: смена source отменяет и освобождает прежнюю работу, unmount освобождает активный worker, а результат неактуального поколения не попадает в UI. Consumer не создаёт worker и не управляет его жизненным циклом.
Lines are virtualized independently of source size. Expensive interactive computations use a managed worker: source replacement cancels and releases the previous job, unmount releases the active worker, and stale-generation results never reach the UI. Consumers neither create the worker nor manage its lifecycle.
Действия chip и адаптивный header панели / Chip actions and responsive panel header
SChip принимает typed surface contract для статичного, action и link
режимов и эмитит activate. Закрытие остаётся отдельным sibling-действием, не
вложенной кнопкой. SPanel использует header-layout="auto" для переноса
группы действий под полный заголовок, если собственная ширина heading/actions
и semantic gap не помещаются в content width шапки. При достаточном месте обе
группы остаются inline; фиксированного breakpoint нет. Описание переносится
в выделенной heading ширине и не задаёт intrinsic ширину группы. Действия
внутри группы могут переноситься; inline сохраняет одну внешнюю строку,
а stacked всегда размещает действия под заголовком.
SLeftSidebar.headerLayout передаёт тот же режим SPanel, с default auto;
компактная шапка с одной action использует inline без consumer CSS.
SChip accepts the typed surface contract for static, action, and link modes
and emits activate. Closing remains a separate sibling action rather than a
nested button. SPanel uses header-layout="auto" to move actions below the
complete title when the intrinsic heading/action widths and semantic gap do not
fit the header's content width. Both groups remain inline when they fit; there
is no fixed breakpoint. The description wraps within the allocated heading
width without defining its intrinsic width. Actions within their group can
wrap; inline retains one outer row and stacked always places actions below
the heading.
SLeftSidebar.headerLayout delegates the same axis to SPanel, defaulting to
auto; a compact title and action may use inline without consumer CSS.
Action/link chip всегда сохраняет видимый интерактивный контур, включая
severity="secondary" на subtle-поверхности; static chip не получает ложного
affordance. Для строк и карточек с дополнительными controls используйте
SActionCard#actions или SActionListItem#actions. actions-layout/
trailing-layout задаёт inline, stacked или container-responsive
композицию. Основное действие и trailing controls остаются sibling-элементами
внутри одной визуальной поверхности, без вложенных интерактивных элементов и
дублирования рамки.
Action and link chips always retain a visible interactive outline, including a
secondary chip on a subtle surface; static chips do not gain a false action
affordance. For rows and cards with additional controls, use
SActionCard#actions or SActionListItem#actions. The actions-layout and
trailing-layout props select inline, stacked, or container-responsive
composition. The primary action and trailing controls remain siblings inside a
single visual surface, with no nested interactive elements or duplicated
chrome.
SActionListItem предоставляет постоянный #leading, краткий #metadata и
actionsVisibility="interaction" для обмена metadata/actions в одной
trailing-области. Keyboard, touch и недоступный primary сохраняют прямой доступ
к действиям. tooltipTrigger у List/Card передаётся canonical activation owner.
trailingWidth="stable" — default: exchange-область резервирует ширину обоих
наборов без суммирования. trailingWidth="current" при interaction учитывает
только текущие metadata или actions в normal flow; скрытый набор не резервирует
место. Смена policy сохраняет mounted controls, focus, draft и overlay lifetime;
вложенные строки задают policy независимо. Тип ActionListItemTrailingWidth
экспортируется из shared/data-display/SActionListItem.vue.
appearance="card" | "plain" | "bare" у SActionListItem и SActionCard
передаётся владельцу SInteractiveSurface: default card задаёт карточную
поверхность, plain — прозрачный idle-фон и рамку, bare — отсутствие рамки
и clipping. Выделение, tone, hover/focus и lifetime слотов сохраняются.
SActionList.surface="plain" управляет списком, а не видом его строк.
titleOverflow="wrap" показывает полный буквальный title, включая пробелы и
переводы строк, в доступной ширине; default ellipsis сохраняет однострочное
усечение. Политика принадлежит собственному title, не вложенным строкам.
Публичный тип ActionListItemTitleOverflow экспортируется из .vue subpath.
В stacked и узкой responsive-композиции статусы и действия переносятся по ширине
карточки; полные подписи отдельных действий сохраняют собственную строку.
API, размеры, RTL и пример композиции: action-list-item.md.
#body="{ disabled }" у List/Card размещает полноширинный редактор под
primary/actions без вложения в activation. Высота определяется содержимым;
consumer владеет раскрытием и явно передаёт disabled полям. С body fill означает
минимальное заполнение, а внешний viewport владеет прокруткой.
SActionList.maxHeight="none" — default: список сохраняет естественную высоту
и видимое переполнение, не создаёт собственный scroll container и не удерживает
wheel-прокрутку над обычными строками внутри внешнего viewport. sm/md/lg
ограничивают высоту, включают собственную прокрутку списка и удерживают её
цепочку на границе.
SActionListItem provides persistent #leading, short #metadata and
actionsVisibility="interaction" to exchange metadata/actions within one
trailing region. Keyboard, touch and unavailable primary retain direct action
access. List/Card tooltipTrigger forwards to the canonical activation owner.
trailingWidth="stable" is the default: the exchange region reserves both
regions' widths without adding them. With interaction, trailingWidth="current"
uses only the current metadata or actions in normal flow; the hidden region
reserves no space. Policy changes retain mounted controls, focus, drafts and
overlay lifetime; nested rows choose their own policy. The public
ActionListItemTrailingWidth type is exported from shared/data-display/SActionListItem.vue.
SActionListItem and SActionCard forward appearance="card" | "plain" | "bare"
to SInteractiveSurface: default card supplies card chrome, plain keeps a
transparent idle background and border, and bare removes the border and
clipping. Selection, tone, hover/focus and slot lifetime remain intact.
SActionList.surface="plain" controls the list, not its rows' appearance.
titleOverflow="wrap" displays the complete literal title, preserving spaces
and line breaks within the available width; default ellipsis keeps
single-line truncation. The policy belongs to the own title, not nested rows.
The public ActionListItemTitleOverflow type is exported from the .vue subpath.
Stacked and narrow responsive compositions wrap status regions and actions to
the card width while preserving complete ordinary action labels.
API, sizing, RTL and composition example: action-list-item.md.
List/Card #body="{ disabled }" places a full-width editor below primary/actions,
outside activation. Height is content-driven; consumers own expansion and bind
disabled to their fields. With body, fill is minimum-fill and an outer viewport
owns scrolling.
SActionList.maxHeight="none" is the default: the list keeps its natural height
and visible overflow, does not create its own scroll container, and lets wheel
input over ordinary rows reach the outer viewport. sm/md/lg cap height,
enable the list's own scrolling, and contain its scroll chain at the boundary.
Лёгкий и редактируемый код / Lightweight and editable code
SCodeBlock загружает CodeMirror отдельным async chunk только для
presentation="editor". Для read-only текста, логов и конфигурации используйте
presentation="plain": header, copy action, accessible name, line numbers и
semantic viewport сохраняются, а editor/language runtime не загружается.
SCodeBlock loads CodeMirror in a separate async chunk only for
presentation="editor". Use presentation="plain" for read-only text, logs,
and configuration: the header, copy action, accessible name, line numbers, and
semantic viewport remain available without loading the editor/language runtime.
Read-only plain и highlighted используют именованную group на native
pre: требуется ровно один ariaLabel/ariaLabelledby, включая пустой вывод.
Текст остаётся доступным внутри группы; номера строк скрыты от screen reader.
code.textContent сохраняет буквальный source, включая пустой текст и
завершающие newline. Номера строк расположены вне code; высота пустых строк
задаётся layout без текстовых struts. DOM Range и кнопка Copy возвращают
исходник точно. Нативное выделение и keyboard Copy следуют rendered-text
правилам браузера для pre; номера или синтетические символы исключены.
focus() и Tab фокусируют саму поверхность. PageDown/Home/End прокручивают её
нативно при переполнении выбранного viewport, без дополнительных tab stops.
Scroll-контейнер удерживает boundary-прокрутку внутри себя; Tab выходит к
следующему control.
Отрисовка текста после раскрытия и возврата в viewport принадлежит SCodeBlock;
потребителю не нужны чтение геометрии, принудительный focus или CSS-переопределения.
Read-only plain and highlighted expose a named group on the native pre.
Exactly one ariaLabel/ariaLabelledby is required, including empty output.
Text remains readable within the group; line numbers are hidden from screen
readers. focus() and Tab focus the surface itself. PageDown/Home/End use native
scrolling when its viewport overflows, without additional tab stops.
The scroll container contains boundary scrolling; Tab exits to the next control.
code.textContent retains the literal source, including empty text and trailing
newlines. Line numbers live outside code; empty-row height is layout-owned,
without text struts. DOM Range and the Copy action return the exact source.
Native selection and keyboard Copy follow the browser's rendered-text rules
for pre, excluding line numbers and synthetic characters.
SCodeBlock owns text paint after disclosure and viewport return; consumers do
not need geometry reads, forced focus, or CSS overrides.
<SCodeBlock
:code="diagnostic"
:language="{ mode: 'explicit', id: 'text' }"
presentation="plain"
aria-label="Диагностика подключения"
/>
Plain presentation допускает только readOnly=true и явно отклоняет
editor-only interceptKeys, nextSelectionPos и applySelection.
Plain presentation accepts readOnly=true only and explicitly rejects the
editor-only interceptKeys, nextSelectionPos, and applySelection contracts.
headerActions и явный headerActionContext добавляют consumer-owned действия
к шапке SCodeBlock; headerActionsPresentation="menu" использует общее меню.
header-action сохраняет точные code/language и source identity. Для
SRichDocument используются sparse codeActions и codeActionSource принятого
snapshot; code-action адресует конкретный fence. Типы и occurrence helper
экспортируются из shared/data-display/codeActions. Выполнение остаётся у
приложения. Контракт: rich-document.md.
SCodeBlock header actions use an explicit source context and inline/menu
presentation; SRichDocument binds actions to exact accepted-snapshot code
occurrences through its sidecar API. Typed intents retain literal code/language
and source identity. Execution remains application-owned.
SCodeEditor сохраняет одну native view/history при изменении theme, language,
capabilities и controlled source. Mixed LF/CRLF/CR и literal UTF-16 offsets
сохраняются в undo/redo, включая разные длины и separator-only replacements.
captureSource() и applyEdits() предоставляют serializable optimistic batch
с одной isolated Undo/Redo transaction, mapped selection и защитой от stale source.
Контракт: code-editor.md.
SCodeEditor retains one native view/history across configuration and
controlled source updates; undo/redo preserves mixed literal separators and
UTF-16 coordinates, including length and separator-only replacements.
captureSource() and applyEdits() provide serializable optimistic batches
with one isolated Undo/Redo transaction, mapped selections and stale-source guards.
--font-mono задаёт общую гарнитуру исходного текста редактора и diff.
SCodeEditor наследует токен через CodeMirror scroller для контента и номеров
строк; SDiffViewer использует тот же токен для строк и gutter. Базовый стек
включает IBM Plex Mono и системные моноширинные гарнитуры macOS, Windows и
Linux. Приложение задаёт гарнитуру на host-контейнере без .cm-* CSS.
--font-mono owns the editor and diff source family. SCodeEditor inherits
the token through the CodeMirror scroller for text and line numbers;
SDiffViewer uses it for lines and gutters. The default stack includes IBM
Plex Mono and platform monospace families for macOS, Windows and Linux.
Applications configure the host token without .cm-* CSS overrides.
Принятые матрицы и команды редактора / Accepted matrices and editor commands
SDataGrid.mode="matrix" показывает принятую readonly страницу буквальных строк,
используя общих table/scroll owners и bounded виртуализацию обеих осей.
Host сохраняет source, paging и чтение файлов; props реестра и редактирования
не смешиваются с matrix API. Полное значение active cell доступно через
SKeyValueGrid.valueWhitespace="preserve". Контракт и пример:
data-grid.md.
SDataGrid.mode="matrix" presents an accepted read-only literal-string page
through shared table/scroll owners and bounded two-axis virtualization. Source,
paging and file reads remain host-owned; records/editing props cannot mix with
matrix APIs. The active value uses SKeyValueGrid.valueWhitespace="preserve".
See the data-grid contract.
Detect-язык редактора допускает unknownLanguage="plain-text" для неизвестных
текстовых файлов, сохраняя parsers поддерживаемых языков.
Публичный shared/codeLanguages предоставляет immutable
getCodeLanguageCatalogue() с canonical id, aliases и extensions для 82 языков
миграционного каталога и отдельного Octave. Неоднозначное .pp требует явного
языка; .m обозначает Objective-C. Подсветка использует CodeMirror без runtime
Monaco, workers или language services. Контракт:
code-languages.md.
capabilities.keyInterceptorPolicy="always" разрешает host-команды в focused
locked editor без разрешения ввода. / Editor detection accepts explicit
unknownLanguage="plain-text" for unknown text files while retaining supported
parsers; capabilities.keyInterceptorPolicy="always" permits host commands in
a focused locked editor without unlocking input.
Пассивный текст и подписи ячеек / Passive text and cell labels
SText принимает точный text, включая пустую строку и пробелы.
typography="body" | "title" | "label" | "meta" задаёт визуальную роль;
default body не создаёт heading semantics. overflow="wrap" сохраняет
переносы и полное содержимое, ellipsis ограничивает представление одной
строкой, сохраняя исходный текст в DOM. monospace меняет только семейство
шрифта и по умолчанию выключен. Пассивный span не создаёт роль или Tab stop.
Body/title/label используют 14/24 px, meta — 12/20 px на root 16 px;
типографические роли сохраняются при monospace.
Цвет принадлежит --s-text-body-foreground, --s-text-title-foreground
(также для label) и --s-text-meta-foreground. Внутри SButton текст всех
ролей следует цвету пассивного содержимого кнопки, включая hover/pressed/focus,
без изменения размера и начертания.
Ячейка с названием и путём использует SStack gap="none" fill="container", SText с
typography="label" и typography="meta" overflow="ellipsis".
Для полного пути при hover и keyboard focus композиция использует
STooltip и STooltipAnchor width="full" с одним доступным именем.
Стек занимает доступную ширину anchor.
STable сохраняет собственный focus owner строки; SText не добавляет остановок табуляции.
Внутри интерактивного предка используется split-контракт focusOwner /
pointerTarget: focus принадлежит предку, а SText.getElement() связывает
пассивную цель. Обёртка STooltipAnchor внутри кнопки не применяется.
SText accepts exact text, including an empty string and whitespace.
typography="body" | "title" | "label" | "meta" selects visual typography;
the default body does not create heading semantics. The default
overflow="wrap" preserves line breaks and full content; ellipsis presents
one bounded line while retaining the original DOM text. monospace changes
only the font family and defaults to false. The passive span adds neither a
role nor a Tab stop.
Body/title/label use 14/24 px and meta uses 12/20 px at a 16 px root;
monospace retains the selected typography metrics.
Color belongs to --s-text-body-foreground, --s-text-title-foreground
(also for label), and --s-text-meta-foreground. Inside SButton, every
role follows the button's passive-content foreground across hover/pressed/focus
without changing its size or weight.
Compose a name/path cell with SStack gap="none" fill="container", a label SText, and a
meta SText overflow="ellipsis". STooltip with a full-width
STooltipAnchor provides one named focus stop for the complete path.
The stack explicitly fills the anchor's available width.
STable retains its row focus owner; SText adds no tab stops.
Inside an interactive ancestor, use the existing split focusOwner /
pointerTarget contract and SText.getElement() for the passive target;
the ancestor retains focus ownership, without a nested tooltip anchor.
Пустое рабочее пространство / Empty workspace
SEmptyState presentation="hero" размещает декоративную иконку, заголовок,
описание и действия вертикально по центру. Компонент занимает доступную ширину
без рамки, фона, margin, p
Related Packages
An Application Interface System for Vue — accessible components, design tokens a...
Vue 3 component library by Shtab — 30+ typed components, design tokens, light/da...
Strand UI - Vue 3 component library built on the Strand Design Language
Version History
| Version | Released | License |
|---|---|---|
| 0.36.0 | MIT | |
| 0.35.0 | MIT | |
| 0.34.2 | MIT | |
| 0.34.1 | MIT | |
| 0.34.0 | MIT | |
| 0.31.2 | MIT | |
| 0.31.1 | MIT | |
| 0.31.0 | MIT | |
| 0.30.0 | MIT | |
| 0.29.1 | MIT | |
| 0.29.0 | MIT | |
| 0.28.3 | MIT | |
| 0.28.2 | MIT | |
| 0.28.1 | MIT | |
| 0.28.0 | MIT | |
| 0.27.1 | MIT | |
| 0.27.0 | MIT | |
| 0.26.1 | MIT | |
| 0.26.0 | MIT | |
| 0.25.1 | MIT | |
| 0.25.0 | MIT | |
| 0.24.0 | MIT | |
| 0.23.1 | MIT | |
| 0.23.0 | MIT | |
| 0.22.0 | MIT | |
| 0.21.0 | MIT | |
| 0.20.0 | MIT | |
| 0.19.0 | MIT | |
| 0.18.0 | MIT | |
| 0.17.1 | MIT |
Showing the latest 30 of 56. See every release on npm