@pgcorp/ui-kit 0.7.3 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +161 -8
- package/docs/accessibility.md +12 -0
- package/docs/getting-started.md +32 -2
- package/docs/public-api.md +27 -2
- package/package.json +18 -3
- package/src/components/shared/codeLanguages.ts +2 -107
- package/src/components/shared/containers/SPanel.css +32 -1
- package/src/components/shared/containers/SPanel.vue +4 -0
- package/src/components/shared/controls/SCheckbox.vue +2 -2
- package/src/components/shared/controls/SInteractiveSurface.css +54 -4
- package/src/components/shared/controls/SInteractiveSurface.vue +45 -31
- package/src/components/shared/controls/SListbox.vue +4 -4
- package/src/components/shared/controls/SSwitch.vue +2 -2
- package/src/components/shared/data-display/SActionCard.css +6 -2
- package/src/components/shared/data-display/SActionCard.vue +13 -3
- package/src/components/shared/data-display/SActionListItem.css +7 -8
- package/src/components/shared/data-display/SActionListItem.vue +21 -18
- package/src/components/shared/data-display/SChart.css +149 -0
- package/src/components/shared/data-display/SChart.vue +493 -0
- package/src/components/shared/data-display/SChip.css +24 -0
- package/src/components/shared/data-display/SChip.vue +30 -6
- package/src/components/shared/data-display/SCodeBlock.css +68 -0
- package/src/components/shared/data-display/SCodeBlock.vue +102 -16
- package/src/components/shared/data-display/SMetricCard.css +1 -0
- package/src/components/shared/data-display/SMetricCard.vue +1 -0
- package/src/components/shared/data-display/STable.vue +120 -145
- package/src/components/shared/data-display/chart.ts +54 -0
- package/src/components/shared/navigation/STabList.vue +0 -3
- package/src/internal/chartGeometry.ts +852 -0
- package/src/internal/codeLanguageIdentity.ts +89 -0
- package/src/internal/lazyCodeEditor.ts +1 -0
- package/src/internal/linkTarget.ts +1 -3
- package/src/internal/ownedAttrs.ts +1 -0
- package/src/internal/useBinaryInput.ts +9 -2
- package/src/styles/tailwind.css +3 -0
- package/src/styles/tokens.css +33 -0
package/README.md
CHANGED
|
@@ -46,14 +46,32 @@ owns their single runtime instances.
|
|
|
46
46
|
|
|
47
47
|
## Быстрый старт / Quick start
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Создайте корневой CSS entrypoint приложения. Интеграционный stylesheet подключает
|
|
50
|
+
стили и typography plugin, а явный `@source` регистрирует source-SFC пакета:
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
Create the application's root CSS entrypoint. The integration stylesheet includes
|
|
53
|
+
the styles and typography plugin, while an explicit `@source` registers the package SFCs:
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
@import "tailwindcss";
|
|
57
|
+
@import "@pgcorp/ui-kit/tailwind.css";
|
|
58
|
+
@source "../node_modules/@pgcorp/ui-kit";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`@source` обязателен: Tailwind 4 не сканирует dependencies автоматически, а путь
|
|
62
|
+
разрешается относительно CSS-файла приложения. Runtime-импорт `reference.css`
|
|
63
|
+
не требуется. / `@source` is required because Tailwind 4 does not scan
|
|
64
|
+
dependencies automatically; the path resolves relative to the application CSS.
|
|
65
|
+
No runtime `reference.css` import is required.
|
|
66
|
+
|
|
67
|
+
Подключите CSS, Pinia и router в entrypoint приложения:
|
|
68
|
+
|
|
69
|
+
Import the CSS, Pinia, and router from the application entrypoint:
|
|
52
70
|
|
|
53
71
|
```ts
|
|
54
72
|
import { createPinia } from 'pinia'
|
|
55
73
|
import { createApp } from 'vue'
|
|
56
|
-
import '
|
|
74
|
+
import './styles.css'
|
|
57
75
|
|
|
58
76
|
import App from './App.vue'
|
|
59
77
|
import router from './router'
|
|
@@ -102,7 +120,7 @@ monorepo alias or copied UI-kit files.
|
|
|
102
120
|
| Layout | App shell, dock regions, stacks, workbench layout | `layout/SAppShell.vue`, `layout/SStack.vue`, `layout/SWorkbenchLayout.vue` |
|
|
103
121
|
| Controls | Buttons, fields, inputs, switches, selects, comboboxes, menus | `shared/controls/SButton.vue`, `shared/controls/SSwitch.vue`, `shared/controls/SCombobox.vue` |
|
|
104
122
|
| Containers | Panels, modal, drawer, popover, sidebars | `shared/containers/SPanel.vue`, `shared/containers/SModal.vue`, `shared/containers/SPopover.vue` |
|
|
105
|
-
| Data display | Tables, chips, status, progress, code, JSON, tooltips | `shared/data-display/STable.vue`, `shared/data-display/
|
|
123
|
+
| Data display | Tables, charts, metric cards, chips, status, progress, code, JSON, tooltips | `shared/data-display/STable.vue`, `shared/data-display/SChart.vue`, `shared/data-display/SMetricCard.vue` |
|
|
106
124
|
| Navigation | Tabs, breadcrumbs, catalog navigation, wizard | `shared/navigation/STabs.vue`, `shared/navigation/SBreadcrumbs.vue`, `shared/navigation/SWizardSteps.vue` |
|
|
107
125
|
| Complex surfaces | Tree, Kanban, data grid, SQL editor, graph | `shared/complex/STree.vue`, `shared/database/SDataGrid.vue`, `shared/graph/SGraphViewport.vue` |
|
|
108
126
|
| Runtime | Themes, variants, icons, composables, stores | `theme`, `variants`, `icons`, `composables/useNotifier`, `stores/useNotifierStore` |
|
|
@@ -121,6 +139,13 @@ controlled keys и доменный контент, не копирует checkb
|
|
|
121
139
|
`STable` owns selection and disclosure columns. Consumers provide controlled
|
|
122
140
|
keys and domain content instead of copying checkboxes, disclosures, or CSS:
|
|
123
141
|
|
|
142
|
+
```ts
|
|
143
|
+
import type {
|
|
144
|
+
STableColumn,
|
|
145
|
+
STableSort,
|
|
146
|
+
} from '@pgcorp/ui-kit/shared/data-display/table'
|
|
147
|
+
```
|
|
148
|
+
|
|
124
149
|
```vue
|
|
125
150
|
<STable
|
|
126
151
|
v-model:selected-row-keys="selectedRowKeys"
|
|
@@ -180,6 +205,124 @@ authoritative prop update becomes the base for subsequent actions.
|
|
|
180
205
|
/>
|
|
181
206
|
```
|
|
182
207
|
|
|
208
|
+
### Графики и метрики / Charts and metrics
|
|
209
|
+
|
|
210
|
+
`SChart` является единым semantic owner для line, area, grouped/stacked bar,
|
|
211
|
+
pie и donut. Размеры `compact`, `sm`, `md`, `lg`, оси, сетка, легенда,
|
|
212
|
+
маркеры, подписи, auto/fixed domain и таблица данных задаются typed props.
|
|
213
|
+
Компонент пересчитывает SVG-геометрию по фактическому контейнеру, сохраняет
|
|
214
|
+
читаемую типографику и переносит длинные подписи категорий на узкой ширине.
|
|
215
|
+
|
|
216
|
+
`SChart` is the single semantic owner for line, area, grouped/stacked bar, pie,
|
|
217
|
+
and donut charts. Typed props control `compact`, `sm`, `md`, and `lg` sizes,
|
|
218
|
+
axes, grid, legend, markers, labels, auto/fixed domains, and the data table. The
|
|
219
|
+
component recomputes SVG geometry for its actual container, preserves readable
|
|
220
|
+
typography, and wraps long category labels at narrow widths.
|
|
221
|
+
|
|
222
|
+
Форматированные подписи шкалы Y участвуют в расчёте поля графика. Крайние
|
|
223
|
+
подписи X привязаны к границам plot-area, поэтому `x-labels="auto"` сохраняет
|
|
224
|
+
полные начальное и конечное значения и не обрезает их краем SVG. Если ширины
|
|
225
|
+
контейнера физически недостаточно, визуальная подпись сокращается, а полное
|
|
226
|
+
значение остаётся в tooltip и доступной таблице данных.
|
|
227
|
+
|
|
228
|
+
Formatted Y-axis labels participate in plot-gutter calculation. Endpoint
|
|
229
|
+
X labels are anchored to the plot boundaries, so `x-labels="auto"` preserves
|
|
230
|
+
the full first and last values instead of clipping them at the SVG edge. When
|
|
231
|
+
the container is physically too narrow, the visual label is shortened while
|
|
232
|
+
the full value remains available through the tooltip and accessible data table.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import type {
|
|
236
|
+
SChartCategory,
|
|
237
|
+
SChartSeries,
|
|
238
|
+
} from '@pgcorp/ui-kit/shared/data-display/chart'
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```vue
|
|
242
|
+
<SChart
|
|
243
|
+
type="area"
|
|
244
|
+
:categories="categories"
|
|
245
|
+
:series="series"
|
|
246
|
+
:accessibility="{
|
|
247
|
+
mode: 'label',
|
|
248
|
+
label: 'Нагрузка VPN по часам',
|
|
249
|
+
description: 'Входящий и исходящий трафик',
|
|
250
|
+
}"
|
|
251
|
+
x-axis-label="Час"
|
|
252
|
+
y-axis-label="Мбит/с"
|
|
253
|
+
legend="top"
|
|
254
|
+
/>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Для компактного тренда `SMetricCard` предоставляет слот `#chart`. Декоративный
|
|
258
|
+
график внутри уже озвученной карточки использует
|
|
259
|
+
`accessibility.mode="decorative"` и `data-table-presentation="none"`;
|
|
260
|
+
содержательный самостоятельный график сохраняет default assistive data table.
|
|
261
|
+
|
|
262
|
+
`SMetricCard` exposes `#chart` for a compact trend. A decorative chart inside an
|
|
263
|
+
already labelled card uses `accessibility.mode="decorative"` with
|
|
264
|
+
`data-table-presentation="none"`; a meaningful standalone chart keeps the
|
|
265
|
+
default assistive data table.
|
|
266
|
+
|
|
267
|
+
### Действия chip и адаптивный header панели / Chip actions and responsive panel header
|
|
268
|
+
|
|
269
|
+
`SChip` принимает typed `surface` contract для статичного, action и link
|
|
270
|
+
режимов и эмитит `activate`. Закрытие остаётся отдельным sibling-действием, не
|
|
271
|
+
вложенной кнопкой. `SPanel` использует `header-layout="auto"` для переноса
|
|
272
|
+
действий под заголовок по container width; `inline` и `stacked` доступны как
|
|
273
|
+
явные варианты композиции.
|
|
274
|
+
|
|
275
|
+
`SChip` accepts the typed `surface` contract for static, action, and link modes
|
|
276
|
+
and emits `activate`. Closing remains a separate sibling action rather than a
|
|
277
|
+
nested button. `SPanel` uses `header-layout="auto"` to move actions below the
|
|
278
|
+
title based on container width; `inline` and `stacked` remain explicit layout
|
|
279
|
+
options.
|
|
280
|
+
|
|
281
|
+
Action/link chip всегда сохраняет видимый интерактивный контур, включая
|
|
282
|
+
`severity="secondary"` на subtle-поверхности; static chip не получает ложного
|
|
283
|
+
affordance. Для строк и карточек с дополнительными controls используйте
|
|
284
|
+
`SActionCard#actions` или `SActionListItem#actions`. `actions-layout`/
|
|
285
|
+
`trailing-layout` задаёт `inline`, `stacked` или container-responsive
|
|
286
|
+
композицию. Основное действие и trailing controls остаются sibling-элементами
|
|
287
|
+
внутри одной визуальной поверхности, без вложенных интерактивных элементов и
|
|
288
|
+
дублирования рамки.
|
|
289
|
+
|
|
290
|
+
Action and link chips always retain a visible interactive outline, including a
|
|
291
|
+
`secondary` chip on a subtle surface; static chips do not gain a false action
|
|
292
|
+
affordance. For rows and cards with additional controls, use
|
|
293
|
+
`SActionCard#actions` or `SActionListItem#actions`. The `actions-layout` and
|
|
294
|
+
`trailing-layout` props select `inline`, `stacked`, or container-responsive
|
|
295
|
+
composition. The primary action and trailing controls remain siblings inside a
|
|
296
|
+
single visual surface, with no nested interactive elements or duplicated
|
|
297
|
+
chrome.
|
|
298
|
+
|
|
299
|
+
### Лёгкий и редактируемый код / Lightweight and editable code
|
|
300
|
+
|
|
301
|
+
`SCodeBlock` загружает CodeMirror отдельным async chunk только для
|
|
302
|
+
`presentation="editor"`. Для read-only текста, логов и конфигурации используйте
|
|
303
|
+
`presentation="plain"`: header, copy action, accessible name, line numbers и
|
|
304
|
+
semantic viewport сохраняются, а editor/language runtime не загружается.
|
|
305
|
+
|
|
306
|
+
`SCodeBlock` loads CodeMirror in a separate async chunk only for
|
|
307
|
+
`presentation="editor"`. Use `presentation="plain"` for read-only text, logs,
|
|
308
|
+
and configuration: the header, copy action, accessible name, line numbers, and
|
|
309
|
+
semantic viewport remain available without loading the editor/language runtime.
|
|
310
|
+
|
|
311
|
+
```vue
|
|
312
|
+
<SCodeBlock
|
|
313
|
+
:code="diagnostic"
|
|
314
|
+
:language="{ mode: 'explicit', id: 'text' }"
|
|
315
|
+
presentation="plain"
|
|
316
|
+
aria-label="Диагностика подключения"
|
|
317
|
+
/>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Plain presentation допускает только `readOnly=true` и явно отклоняет
|
|
321
|
+
editor-only `interceptKeys`, `nextSelectionPos` и `applySelection`.
|
|
322
|
+
|
|
323
|
+
Plain presentation accepts `readOnly=true` only and explicitly rejects the
|
|
324
|
+
editor-only `interceptKeys`, `nextSelectionPos`, and `applySelection` contracts.
|
|
325
|
+
|
|
183
326
|
### Подсказка на части действия / Tooltip for part of an action
|
|
184
327
|
|
|
185
328
|
Обычный tooltip использует combined `trigger`. Для пассивного фрагмента внутри
|
|
@@ -207,14 +350,24 @@ button and owns ARIA/focus, while `pointerTarget` is applied to a passive
|
|
|
207
350
|
|
|
208
351
|
## Темы и стили / Themes and styles
|
|
209
352
|
|
|
210
|
-
Для
|
|
353
|
+
Для приложения на Tailwind 4 подключайте integration entrypoint после собственного
|
|
354
|
+
`@import "tailwindcss"`:
|
|
211
355
|
|
|
212
|
-
For a
|
|
356
|
+
For a Tailwind 4 application, import the integration entrypoint after the
|
|
357
|
+
application's own `@import "tailwindcss"`:
|
|
213
358
|
|
|
214
|
-
```
|
|
215
|
-
import
|
|
359
|
+
```css
|
|
360
|
+
@import "tailwindcss";
|
|
361
|
+
@import "@pgcorp/ui-kit/tailwind.css";
|
|
362
|
+
@source "../node_modules/@pgcorp/ui-kit";
|
|
216
363
|
```
|
|
217
364
|
|
|
365
|
+
`tailwind.css` включает `style.css`, dark variant и required typography plugin.
|
|
366
|
+
`reference.css` предназначен для compile-time `@reference` в component styles.
|
|
367
|
+
/ `tailwind.css` includes `style.css`, the dark variant, and the required
|
|
368
|
+
typography plugin. `reference.css` is a compile-time `@reference` target for
|
|
369
|
+
component styles.
|
|
370
|
+
|
|
218
371
|
Для token-only интеграции доступен отдельный entrypoint:
|
|
219
372
|
|
|
220
373
|
A separate entrypoint is available for token-only integration:
|
package/docs/accessibility.md
CHANGED
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
Consumer обязан передавать человекочитаемые labels и не заменять семантику
|
|
14
14
|
компонента локальными DOM listeners или CSS.
|
|
15
15
|
|
|
16
|
+
`SChart` требует явный `accessibility` contract. Содержательный график получает
|
|
17
|
+
accessible name через `mode: 'label'` или `mode: 'labelledby'` и по умолчанию
|
|
18
|
+
рендерит assistive data table. `mode: 'decorative'` допустим только когда те же
|
|
19
|
+
данные уже выражены ближайшим владельцем; для него задаётся
|
|
20
|
+
`dataTablePresentation: 'none'` либо видимая таблица.
|
|
21
|
+
|
|
16
22
|
## English
|
|
17
23
|
|
|
18
24
|
Interactive semantics belong to UI-kit leaf components. They own:
|
|
@@ -25,3 +31,9 @@ Interactive semantics belong to UI-kit leaf components. They own:
|
|
|
25
31
|
|
|
26
32
|
Consumers must provide human-readable labels and must not replace component
|
|
27
33
|
semantics with local DOM listeners or CSS.
|
|
34
|
+
|
|
35
|
+
`SChart` requires an explicit `accessibility` contract. A meaningful chart gets
|
|
36
|
+
an accessible name through `mode: 'label'` or `mode: 'labelledby'` and renders
|
|
37
|
+
an assistive data table by default. `mode: 'decorative'` is valid only when a
|
|
38
|
+
nearby owner already expresses the same data; it uses
|
|
39
|
+
`dataTablePresentation: 'none'` or a visible table.
|
package/docs/getting-started.md
CHANGED
|
@@ -13,11 +13,26 @@ Consumer отвечает за единственные экземпляры `vu
|
|
|
13
13
|
|
|
14
14
|
### Подключение
|
|
15
15
|
|
|
16
|
+
UI-kit публикует source-SFC и использует Tailwind 4 utilities. Подключите Tailwind
|
|
17
|
+
и package integration entrypoint в корневом CSS приложения:
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
@import "tailwindcss";
|
|
21
|
+
@import "@pgcorp/ui-kit/tailwind.css";
|
|
22
|
+
@source "../node_modules/@pgcorp/ui-kit";
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`tailwind.css` подключает полные стили UI-kit и typography plugin. Tailwind 4 не
|
|
26
|
+
сканирует зависимости автоматически, поэтому `@source` обязателен и задаётся
|
|
27
|
+
относительно этого CSS-файла. Импорт `reference.css` consumer-у не нужен. Если
|
|
28
|
+
source root приложения задаётся явно, сохраните его на собственном
|
|
29
|
+
`@import "tailwindcss" source("…")`.
|
|
30
|
+
|
|
16
31
|
```ts
|
|
17
32
|
import { createApp } from 'vue'
|
|
18
33
|
import { createPinia } from 'pinia'
|
|
19
34
|
import router from './router'
|
|
20
|
-
import '
|
|
35
|
+
import './styles.css'
|
|
21
36
|
|
|
22
37
|
import App from './App.vue'
|
|
23
38
|
|
|
@@ -53,11 +68,26 @@ instances.
|
|
|
53
68
|
|
|
54
69
|
### Setup
|
|
55
70
|
|
|
71
|
+
The UI kit publishes source SFCs and uses Tailwind 4 utilities. Import Tailwind
|
|
72
|
+
and the package integration entrypoint from the application's root CSS:
|
|
73
|
+
|
|
74
|
+
```css
|
|
75
|
+
@import "tailwindcss";
|
|
76
|
+
@import "@pgcorp/ui-kit/tailwind.css";
|
|
77
|
+
@source "../node_modules/@pgcorp/ui-kit";
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`tailwind.css` includes the complete UI-kit styles and enables the typography
|
|
81
|
+
plugin. Tailwind 4 does not scan dependencies automatically, so the `@source`
|
|
82
|
+
line is required and resolves relative to this CSS file. Consumers do not need
|
|
83
|
+
a `reference.css` import. If the application uses an explicit source root, keep
|
|
84
|
+
it on its own `@import "tailwindcss" source("…")`.
|
|
85
|
+
|
|
56
86
|
```ts
|
|
57
87
|
import { createApp } from 'vue'
|
|
58
88
|
import { createPinia } from 'pinia'
|
|
59
89
|
import router from './router'
|
|
60
|
-
import '
|
|
90
|
+
import './styles.css'
|
|
61
91
|
|
|
62
92
|
import App from './App.vue'
|
|
63
93
|
|
package/docs/public-api.md
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
- `shared/navigation/*` — tabs, breadcrumbs, catalog navigation и wizard steps;
|
|
15
15
|
- `shared/database/*`, `shared/graph/*`, `shared/persona/*` — доменные сложные поверхности;
|
|
16
16
|
- `composables/*`, `stores/*`, `theme`, `variants`, `icons` — typed runtime modules;
|
|
17
|
-
- `
|
|
17
|
+
- `tailwind.css` — полный Tailwind 4 integration entrypoint;
|
|
18
|
+
- `style.css`, `tokens.css`, `reference.css` — global styles, token-only и compile-time reference entrypoints.
|
|
18
19
|
|
|
19
20
|
Компонентный contract выражается через typed props, slots, events и exposed
|
|
20
21
|
methods. Внутренний DOM, CSS-классы и private modules не являются API.
|
|
@@ -25,6 +26,17 @@ UI-kit-owned атрибуты `data-s-*` относятся к внутренн
|
|
|
25
26
|
compiler регистрирует их без межфайлового filesystem type resolver.
|
|
26
27
|
Публикуемый production-source компилируется с `target/lib: ES2020`, совпадающим
|
|
27
28
|
с baseline `@vue/tsconfig/tsconfig.dom.json`, и не требует скрытых полифиллов.
|
|
29
|
+
Типы таблицы импортируются из `shared/data-display/table`, типы графиков — из
|
|
30
|
+
`shared/data-display/chart`. `SChart` объединяет line/area/bar/pie/donut,
|
|
31
|
+
responsive geometry, semantic palette и доступную таблицу данных. `SMetricCard`
|
|
32
|
+
принимает компактный график через `#chart`. `SCodeBlock` сохраняет CodeMirror за
|
|
33
|
+
async boundary; `presentation="plain"` является lightweight read-only контрактом
|
|
34
|
+
без загрузки editor runtime. `SChip.surface` владеет action/link семантикой, а
|
|
35
|
+
`SPanel.headerLayout` — inline/stacked/auto компоновкой заголовка и действий.
|
|
36
|
+
`SInteractiveSurface#actions` и использующие его `SActionCard`/
|
|
37
|
+
`SActionListItem` держат primary activation и дополнительные controls
|
|
38
|
+
sibling-элементами внутри одного chrome; `actionsLayout`/`trailingLayout`
|
|
39
|
+
управляют inline, stacked и container-responsive раскладкой.
|
|
28
40
|
|
|
29
41
|
## English
|
|
30
42
|
|
|
@@ -40,7 +52,8 @@ Primary groups:
|
|
|
40
52
|
- `shared/navigation/*` — tabs, breadcrumbs, catalog navigation, and wizard steps;
|
|
41
53
|
- `shared/database/*`, `shared/graph/*`, `shared/persona/*` — complex domain surfaces;
|
|
42
54
|
- `composables/*`, `stores/*`, `theme`, `variants`, `icons` — typed runtime modules;
|
|
43
|
-
- `
|
|
55
|
+
- `tailwind.css` — the complete Tailwind 4 integration entrypoint;
|
|
56
|
+
- `style.css`, `tokens.css`, `reference.css` — global styles, token-only, and compile-time reference entrypoints.
|
|
44
57
|
|
|
45
58
|
Component contracts are expressed through typed props, slots, events, and exposed
|
|
46
59
|
methods. Internal DOM, CSS classes, and private modules are not API.
|
|
@@ -51,3 +64,15 @@ Public source SFCs declare runtime props and events locally, so the consumer Vue
|
|
|
51
64
|
compiler registers them without a cross-file filesystem type resolver.
|
|
52
65
|
Published production source compiles with the `target/lib: ES2020` baseline from
|
|
53
66
|
`@vue/tsconfig/tsconfig.dom.json` and does not require implicit polyfills.
|
|
67
|
+
Table types are imported from `shared/data-display/table`; chart types are
|
|
68
|
+
imported from `shared/data-display/chart`. `SChart` unifies
|
|
69
|
+
line/area/bar/pie/donut charts, responsive geometry, the semantic palette, and
|
|
70
|
+
an accessible data table. `SMetricCard` accepts a compact chart through
|
|
71
|
+
`#chart`. `SCodeBlock` keeps CodeMirror behind an async boundary;
|
|
72
|
+
`presentation="plain"` is the lightweight read-only contract that does not load
|
|
73
|
+
the editor runtime. `SChip.surface` owns action/link semantics, while
|
|
74
|
+
`SPanel.headerLayout` owns inline/stacked/auto title and action composition.
|
|
75
|
+
`SInteractiveSurface#actions` and its `SActionCard`/`SActionListItem`
|
|
76
|
+
compositions keep primary activation and additional controls as siblings inside
|
|
77
|
+
one chrome; `actionsLayout`/`trailingLayout` control inline, stacked, and
|
|
78
|
+
container-responsive layout.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgcorp/ui-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Typed Vue 3 design system with accessible components, semantic themes, and workbench patterns.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.ts",
|
|
@@ -270,6 +270,9 @@
|
|
|
270
270
|
"shared/controls/STextarea.vue": [
|
|
271
271
|
"src/components/shared/controls/STextarea.vue"
|
|
272
272
|
],
|
|
273
|
+
"shared/data-display/chart": [
|
|
274
|
+
"src/components/shared/data-display/chart.ts"
|
|
275
|
+
],
|
|
273
276
|
"shared/data-display/json": [
|
|
274
277
|
"src/components/shared/data-display/json.ts"
|
|
275
278
|
],
|
|
@@ -285,6 +288,9 @@
|
|
|
285
288
|
"shared/data-display/SBadge.vue": [
|
|
286
289
|
"src/components/shared/data-display/SBadge.vue"
|
|
287
290
|
],
|
|
291
|
+
"shared/data-display/SChart.vue": [
|
|
292
|
+
"src/components/shared/data-display/SChart.vue"
|
|
293
|
+
],
|
|
288
294
|
"shared/data-display/SChip.vue": [
|
|
289
295
|
"src/components/shared/data-display/SChip.vue"
|
|
290
296
|
],
|
|
@@ -357,6 +363,9 @@
|
|
|
357
363
|
"shared/data-display/SVirtualList.vue": [
|
|
358
364
|
"src/components/shared/data-display/SVirtualList.vue"
|
|
359
365
|
],
|
|
366
|
+
"shared/data-display/table": [
|
|
367
|
+
"src/components/shared/data-display/table.ts"
|
|
368
|
+
],
|
|
360
369
|
"shared/database/SDataGrid.vue": [
|
|
361
370
|
"src/components/shared/database/SDataGrid.vue"
|
|
362
371
|
],
|
|
@@ -428,7 +437,8 @@
|
|
|
428
437
|
"sideEffects": [
|
|
429
438
|
"./src/styles/style.css",
|
|
430
439
|
"./src/styles/tokens.css",
|
|
431
|
-
"./src/styles/reference.css"
|
|
440
|
+
"./src/styles/reference.css",
|
|
441
|
+
"./src/styles/tailwind.css"
|
|
432
442
|
],
|
|
433
443
|
"exports": {
|
|
434
444
|
".": "./index.ts",
|
|
@@ -501,11 +511,13 @@
|
|
|
501
511
|
"./shared/controls/SSelect.vue": "./src/components/shared/controls/SSelect.vue",
|
|
502
512
|
"./shared/controls/SSwitch.vue": "./src/components/shared/controls/SSwitch.vue",
|
|
503
513
|
"./shared/controls/STextarea.vue": "./src/components/shared/controls/STextarea.vue",
|
|
514
|
+
"./shared/data-display/chart": "./src/components/shared/data-display/chart.ts",
|
|
504
515
|
"./shared/data-display/json": "./src/components/shared/data-display/json.ts",
|
|
505
516
|
"./shared/data-display/SActionCard.vue": "./src/components/shared/data-display/SActionCard.vue",
|
|
506
517
|
"./shared/data-display/SActionList.vue": "./src/components/shared/data-display/SActionList.vue",
|
|
507
518
|
"./shared/data-display/SActionListItem.vue": "./src/components/shared/data-display/SActionListItem.vue",
|
|
508
519
|
"./shared/data-display/SBadge.vue": "./src/components/shared/data-display/SBadge.vue",
|
|
520
|
+
"./shared/data-display/SChart.vue": "./src/components/shared/data-display/SChart.vue",
|
|
509
521
|
"./shared/data-display/SChip.vue": "./src/components/shared/data-display/SChip.vue",
|
|
510
522
|
"./shared/data-display/SCodeBlock.vue": "./src/components/shared/data-display/SCodeBlock.vue",
|
|
511
523
|
"./shared/data-display/SCodeEditor.vue": "./src/components/shared/data-display/SCodeEditor.vue",
|
|
@@ -530,6 +542,7 @@
|
|
|
530
542
|
"./shared/data-display/STooltipTarget.vue": "./src/components/shared/data-display/STooltipTarget.vue",
|
|
531
543
|
"./shared/data-display/SVirtualList": "./src/components/shared/data-display/SVirtualList.ts",
|
|
532
544
|
"./shared/data-display/SVirtualList.vue": "./src/components/shared/data-display/SVirtualList.vue",
|
|
545
|
+
"./shared/data-display/table": "./src/components/shared/data-display/table.ts",
|
|
533
546
|
"./shared/database/SDataGrid.vue": "./src/components/shared/database/SDataGrid.vue",
|
|
534
547
|
"./shared/database/SSqlEditor.vue": "./src/components/shared/database/SSqlEditor.vue",
|
|
535
548
|
"./shared/feedback/SAsyncState.vue": "./src/components/shared/feedback/SAsyncState.vue",
|
|
@@ -551,6 +564,7 @@
|
|
|
551
564
|
"./shared/persona/types": "./src/components/shared/persona/types.ts",
|
|
552
565
|
"./stores/useNotifierStore": "./src/stores/useNotifierStore.ts",
|
|
553
566
|
"./style.css": "./src/styles/style.css",
|
|
567
|
+
"./tailwind.css": "./src/styles/tailwind.css",
|
|
554
568
|
"./theme": "./src/theme.ts",
|
|
555
569
|
"./tokens.css": "./src/styles/tokens.css",
|
|
556
570
|
"./variants": "./src/variants.ts"
|
|
@@ -575,6 +589,7 @@
|
|
|
575
589
|
"graphology": "^0.26.0",
|
|
576
590
|
"highlight.js": "^11.11.1",
|
|
577
591
|
"@lucide/vue": "^1.16.0",
|
|
592
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
578
593
|
"marked": "^17.0.3",
|
|
579
594
|
"sigma": "^3.0.3",
|
|
580
595
|
"tailwindcss": "^4.2.0",
|
|
@@ -583,7 +598,7 @@
|
|
|
583
598
|
},
|
|
584
599
|
"devDependencies": {
|
|
585
600
|
"@storybook/vue3-vite": "10.5.3",
|
|
586
|
-
"@tailwindcss/
|
|
601
|
+
"@tailwindcss/postcss": "^4.2.0",
|
|
587
602
|
"@types/node": "^25.3.0",
|
|
588
603
|
"@vitejs/plugin-vue": "^6.0.4",
|
|
589
604
|
"@vitest/coverage-v8": "^4.0.18",
|
|
@@ -7,60 +7,10 @@ import { nginx } from '@codemirror/legacy-modes/mode/nginx'
|
|
|
7
7
|
import { shell } from '@codemirror/legacy-modes/mode/shell'
|
|
8
8
|
import {
|
|
9
9
|
type CodeEditorLanguageContract,
|
|
10
|
-
validateCodeEditorLanguage,
|
|
11
10
|
} from '../../internal/codeEditorContract'
|
|
11
|
+
import { resolveCodeLanguageKey } from '../../internal/codeLanguageIdentity'
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const SPECIAL_FILENAMES: Record<string, string> = {
|
|
16
|
-
'cmakelists.txt': 'cmake',
|
|
17
|
-
'dockerfile': 'dockerfile',
|
|
18
|
-
'docker-compose.yml': 'yaml',
|
|
19
|
-
'docker-compose.yaml': 'yaml',
|
|
20
|
-
'compose.yml': 'yaml',
|
|
21
|
-
'compose.yaml': 'yaml',
|
|
22
|
-
'.env': 'properties',
|
|
23
|
-
'.env.example': 'properties',
|
|
24
|
-
'.env.local': 'properties',
|
|
25
|
-
'.env.development': 'properties',
|
|
26
|
-
'.env.production': 'properties',
|
|
27
|
-
'makefile': 'makefile',
|
|
28
|
-
'nginx.conf': 'nginx',
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const LANGUAGE_ALIASES: Record<string, string> = {
|
|
32
|
-
bash: 'shell',
|
|
33
|
-
'c#': 'cs',
|
|
34
|
-
csharp: 'cs',
|
|
35
|
-
env: 'properties',
|
|
36
|
-
fish: 'shell',
|
|
37
|
-
handlebars: 'handlebars',
|
|
38
|
-
htm: 'html',
|
|
39
|
-
js: 'javascript',
|
|
40
|
-
jsonc: 'json',
|
|
41
|
-
json5: 'json',
|
|
42
|
-
log: 'text',
|
|
43
|
-
make: 'makefile',
|
|
44
|
-
md: 'markdown',
|
|
45
|
-
mk: 'makefile',
|
|
46
|
-
plaintext: 'text',
|
|
47
|
-
proto3: 'proto',
|
|
48
|
-
ps1: 'powershell',
|
|
49
|
-
psm1: 'powershell',
|
|
50
|
-
psd1: 'powershell',
|
|
51
|
-
py: 'python',
|
|
52
|
-
pyw: 'python',
|
|
53
|
-
pyi: 'python',
|
|
54
|
-
rbw: 'ruby',
|
|
55
|
-
sh: 'shell',
|
|
56
|
-
shellsession: 'shell',
|
|
57
|
-
ts: 'typescript',
|
|
58
|
-
text: 'text',
|
|
59
|
-
txt: 'text',
|
|
60
|
-
yaml: 'yaml',
|
|
61
|
-
yml: 'yaml',
|
|
62
|
-
zsh: 'shell',
|
|
63
|
-
}
|
|
13
|
+
export { resolveCodeLanguageKey } from '../../internal/codeLanguageIdentity'
|
|
64
14
|
|
|
65
15
|
const LEGACY_CODEMIRROR_LANGUAGES: Record<string, Extension> = {
|
|
66
16
|
dockerfile: StreamLanguage.define(dockerFile),
|
|
@@ -88,65 +38,10 @@ type SupportedCodeMirrorLanguage = Parameters<typeof loadLanguage>[0]
|
|
|
88
38
|
|
|
89
39
|
const SUPPORTED_CODEMIRROR_LANGUAGES = new Set<SupportedCodeMirrorLanguage>(langNames)
|
|
90
40
|
|
|
91
|
-
function normalizeDetectedToken(value: NullableText): string | null {
|
|
92
|
-
if (!value) {
|
|
93
|
-
return null
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const normalized = value.trim().toLowerCase().replace(/^\./, '')
|
|
97
|
-
if (!normalized) {
|
|
98
|
-
return null
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return LANGUAGE_ALIASES[normalized] ?? normalized
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function resolveLanguageFromFilePath(filePath: NullableText): string | null {
|
|
105
|
-
if (!filePath) {
|
|
106
|
-
return null
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const normalizedPath = filePath.trim().toLowerCase()
|
|
110
|
-
if (!normalizedPath) {
|
|
111
|
-
return null
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const basename = normalizedPath.split('/').pop() ?? normalizedPath
|
|
115
|
-
if (SPECIAL_FILENAMES[basename]) {
|
|
116
|
-
return SPECIAL_FILENAMES[basename]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (basename.startsWith('dockerfile.')) {
|
|
120
|
-
return 'dockerfile'
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!basename.includes('.')) {
|
|
124
|
-
return null
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const extension = basename.split('.').pop()
|
|
128
|
-
return normalizeDetectedToken(extension)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
41
|
function isSupportedCodeMirrorLanguage(value: string): value is SupportedCodeMirrorLanguage {
|
|
132
42
|
return SUPPORTED_CODEMIRROR_LANGUAGES.has(value as SupportedCodeMirrorLanguage)
|
|
133
43
|
}
|
|
134
44
|
|
|
135
|
-
export function resolveCodeLanguageKey(input: CodeEditorLanguageContract): string {
|
|
136
|
-
const language = validateCodeEditorLanguage('codeLanguages', input)
|
|
137
|
-
if (language.mode === 'explicit') {
|
|
138
|
-
return LANGUAGE_ALIASES[language.id] ?? language.id
|
|
139
|
-
}
|
|
140
|
-
const detected = resolveLanguageFromFilePath(language.filePath)
|
|
141
|
-
if (!detected) {
|
|
142
|
-
throw new RangeError(
|
|
143
|
-
`codeLanguages: невозможно определить язык по filePath ${JSON.stringify(language.filePath)}. `
|
|
144
|
-
+ `/ codeLanguages: cannot detect a language from filePath ${JSON.stringify(language.filePath)}.`,
|
|
145
|
-
)
|
|
146
|
-
}
|
|
147
|
-
return detected
|
|
148
|
-
}
|
|
149
|
-
|
|
150
45
|
export function getCodeMirrorLanguageExtension(input: CodeEditorLanguageContract): Extension | null {
|
|
151
46
|
const languageKey = resolveCodeLanguageKey(input)
|
|
152
47
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
@apply relative flex flex-col rounded-lg border bg-surface-0 dark:bg-surface-800 border-surface-200 dark:border-surface-700;
|
|
5
5
|
@apply text-surface-700 dark:text-surface-300;
|
|
6
6
|
@apply min-h-0 min-w-0 w-full flex-none; /* предотвращаем горизонтальное распирание, панель заполняет доступную ширину; flex-none исключает сжатие панелей в flex-контейнерах */
|
|
7
|
+
container-type: inline-size;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
.s-panel[data-grow='true'] {
|
|
@@ -70,10 +71,40 @@
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
.s-panel-header-right {
|
|
73
|
-
@apply flex
|
|
74
|
+
@apply flex min-w-0 shrink-0 flex-wrap items-center;
|
|
74
75
|
gap: var(--s-space-content-gap);
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
.s-panel-header[data-header-layout='stacked'] {
|
|
79
|
+
@apply flex-col items-stretch;
|
|
80
|
+
gap: var(--s-space-content-gap);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.s-panel-header[data-header-layout='stacked'] .s-panel-header-right {
|
|
84
|
+
@apply w-full shrink justify-start;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.s-panel-header[data-header-layout='stacked'] .s-panel-title {
|
|
88
|
+
@apply whitespace-normal;
|
|
89
|
+
overflow-wrap: anywhere;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@container (max-width: 30rem) {
|
|
93
|
+
.s-panel-header[data-header-layout='auto']:has(.s-panel-header-right > *) {
|
|
94
|
+
@apply flex-col items-stretch;
|
|
95
|
+
gap: var(--s-space-content-gap);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.s-panel-header[data-header-layout='auto']:has(.s-panel-header-right > *) .s-panel-header-right {
|
|
99
|
+
@apply w-full shrink justify-start;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.s-panel-header[data-header-layout='auto']:has(.s-panel-header-right > *) .s-panel-title {
|
|
103
|
+
@apply whitespace-normal;
|
|
104
|
+
overflow-wrap: anywhere;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
77
108
|
.s-panel-content {
|
|
78
109
|
/* Базово без внутренних скроллов; прокрутка включается только для grow-панелей */
|
|
79
110
|
@apply min-h-0 min-w-0 w-full; /* безопасная ширина для любых сеток/инпутов внутри */
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
<div
|
|
19
19
|
v-if="title || $slots.actions || $slots.header"
|
|
20
20
|
class="s-panel-header"
|
|
21
|
+
:data-header-layout="headerLayout"
|
|
21
22
|
>
|
|
22
23
|
<div class="s-panel-header-left">
|
|
23
24
|
<slot name="header">
|
|
@@ -119,6 +120,8 @@ export interface Props {
|
|
|
119
120
|
surfaceOverflow?: 'visible' | 'clip'
|
|
120
121
|
/** DOM id общего footer/status region. / DOM id of the shared footer/status region. */
|
|
121
122
|
footerId?: string
|
|
123
|
+
/** Адаптация heading/actions: auto складывает actions под heading при нехватке места. / Heading/actions adaptation: auto stacks actions below the heading when space is constrained. */
|
|
124
|
+
headerLayout?: 'auto' | 'inline' | 'stacked'
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -141,6 +144,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
141
144
|
surfaceElevation: 'flat',
|
|
142
145
|
surfaceOverflow: 'visible',
|
|
143
146
|
footerId: undefined,
|
|
147
|
+
headerLayout: 'auto',
|
|
144
148
|
})
|
|
145
149
|
|
|
146
150
|
const slots = useSlots()
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<template #default="field">
|
|
14
14
|
<span class="s-checkbox-control">
|
|
15
15
|
<input
|
|
16
|
-
ref="
|
|
16
|
+
:ref="setInputElement"
|
|
17
17
|
v-bind="ownedAttrs.bindings()"
|
|
18
18
|
:id="field.controlId"
|
|
19
19
|
type="checkbox"
|
|
@@ -84,10 +84,10 @@ const ownedAttrs = useOwnedAttrs({ component: 'SCheckbox', owner: 'native checkb
|
|
|
84
84
|
useInteractiveLeafRegistration({ owner: 'SCheckbox' })
|
|
85
85
|
const {
|
|
86
86
|
checkedValue,
|
|
87
|
-
inputEl,
|
|
88
87
|
inputId,
|
|
89
88
|
onChange,
|
|
90
89
|
onClick,
|
|
90
|
+
setInputElement,
|
|
91
91
|
} = useBinaryInput({
|
|
92
92
|
owner: 'SCheckbox',
|
|
93
93
|
inputName: 'checkbox',
|