@feugene/granularity 0.21.0 → 0.23.0
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/dist/chunks/config-BTCOJO5z2.js.map +1 -0
- package/dist/chunks/config-B_qi4Fma.js.map +1 -0
- package/dist/chunks/config-Baj7Wvx-.js.map +1 -0
- package/dist/chunks/{config-BKvX0q10.js → config-C5mO5DYZ.js} +10 -1
- package/dist/chunks/config-C5mO5DYZ.js.map +1 -0
- package/dist/chunks/config-CIcynHGr.js +96 -0
- package/dist/chunks/config-CIcynHGr.js.map +1 -0
- package/dist/chunks/{config-BsuDM3Hb.js → config-CKULiuvc.js} +15 -1
- package/dist/chunks/config-CKULiuvc.js.map +1 -0
- package/dist/chunks/{config-jyZq8XKL.js → config-DCwQBMmJ.js} +12 -3
- package/dist/chunks/config-DCwQBMmJ.js.map +1 -0
- package/dist/chunks/config-QaIc_gRa.js.map +1 -0
- package/dist/chunks/config-eXB87DOi.js.map +1 -0
- package/dist/chunks/copy-DChChcq-.js +29 -0
- package/dist/chunks/copy-DChChcq-.js.map +1 -0
- package/dist/chunks/{trending-up-Bf9AQmoq.js → deltaTone-B5OoS1vo.js} +19 -1
- package/dist/chunks/deltaTone-B5OoS1vo.js.map +1 -0
- package/dist/chunks/{en-CwAr3C_x.js → en-DCCFP4qu.js} +12 -2
- package/dist/chunks/{en-CwAr3C_x.js.map → en-DCCFP4qu.js.map} +1 -1
- package/dist/chunks/{es-TR4g2I4A.js → es-CT34HBVM.js} +12 -2
- package/dist/chunks/{es-TR4g2I4A.js.map → es-CT34HBVM.js.map} +1 -1
- package/dist/chunks/{es-Do1q9_SF.js → es-DdJsxlUr.js} +3 -3
- package/dist/chunks/{es-Do1q9_SF.js.map → es-DdJsxlUr.js.map} +1 -1
- package/dist/chunks/{generated-Do60Aq2I.js → generated-CiCrGDQO.js} +49 -0
- package/dist/chunks/{generated-Do60Aq2I.js.map → generated-CiCrGDQO.js.map} +1 -1
- package/dist/chunks/{granular-provider-BW2uopTG.js → granular-provider-CQKhl5C_.js} +10 -8
- package/dist/chunks/granular-provider-CQKhl5C_.js.map +1 -0
- package/dist/chunks/{ru-Bm-zWJ3F.js → ru-CLiAMwrx.js} +12 -2
- package/dist/chunks/{ru-Bm-zWJ3F.js.map → ru-CLiAMwrx.js.map} +1 -1
- package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-CW3zY1ee.js → GrCodeBlock-BmXCLgLS.js} +4 -30
- package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-CW3zY1ee.js.map → GrCodeBlock-BmXCLgLS.js.map} +1 -1
- package/dist/components/GrCodeBlock/index.js +2 -2
- package/dist/components/GrDelta/chunks/{GrDelta-BMmpYz8K.js → GrDelta-DFvxNpmN.js} +0 -0
- package/dist/components/GrDelta/chunks/GrDelta-DFvxNpmN.js.map +1 -0
- package/dist/components/GrDelta/index.js +3 -2
- package/dist/components/GrDescriptionList/chunks/{GrDescriptionList-pXh1LZEe.js → GrDescriptionList-2zFXzX83.js} +15 -4
- package/dist/components/GrDescriptionList/chunks/GrDescriptionList-2zFXzX83.js.map +1 -0
- package/dist/components/GrDescriptionList/index.js +2 -2
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-LOaFSCyd.js → GrDropdownMenu-DyS6dWDp.js} +2 -2
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-LOaFSCyd.js.map → GrDropdownMenu-DyS6dWDp.js.map} +1 -1
- package/dist/components/GrDropdownMenu/index.js +2 -2
- package/dist/components/GrFilePreview/chunks/{GrFilePreview-rbE3zL9w.js → GrFilePreview-D0Bt-0nn.js} +1 -1
- package/dist/components/GrFilePreview/chunks/{GrFilePreview-rbE3zL9w.js.map → GrFilePreview-D0Bt-0nn.js.map} +1 -1
- package/dist/components/GrFilePreview/index.js +2 -2
- package/dist/components/GrJsonViewer/chunks/GrJsonViewer-DFUppRNb.js +389 -0
- package/dist/components/GrJsonViewer/chunks/GrJsonViewer-DFUppRNb.js.map +1 -0
- package/dist/components/GrJsonViewer/index.js +3 -0
- package/dist/components/GrList/chunks/{GrList-BUzFRa8-.js → GrList-BRYhpqIe.js} +3 -3
- package/dist/components/GrList/chunks/GrList-BRYhpqIe.js.map +1 -0
- package/dist/components/GrList/index.js +2 -2
- package/dist/components/GrList/styles.css +1 -1
- package/dist/components/GrRadio/index.js +1 -1
- package/dist/components/GrRadioGroup/index.js +1 -1
- package/dist/components/GrRating/chunks/{GrRating-BiAVT9H7.js → GrRating-BSEtaibx.js} +1 -1
- package/dist/components/GrRating/chunks/{GrRating-BiAVT9H7.js.map → GrRating-BSEtaibx.js.map} +1 -1
- package/dist/components/GrRating/index.js +2 -2
- package/dist/components/GrStatistic/chunks/{GrStatistic-DkzWUAw1.js → GrStatistic-C7wQECeS.js} +20 -4
- package/dist/components/GrStatistic/chunks/GrStatistic-C7wQECeS.js.map +1 -0
- package/dist/components/GrStatistic/index.js +1 -1
- package/dist/components/GrTabPanels/index.js +1 -1
- package/dist/granular-provider-node.js +1 -1
- package/dist/granular-provider.js +1 -1
- package/dist/i18n/all.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.js +21 -18
- package/dist/theme.js +1 -1
- package/dist/tokens.js +1 -1
- package/dist/types/components/GrDelta/index.d.ts +1 -0
- package/dist/types/components/GrDescriptionList/GrDescriptionList.vue.d.ts +6 -2
- package/dist/types/components/GrDescriptionList/grDescriptionListStyles.d.ts +12 -5
- package/dist/types/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +1 -1
- package/dist/types/components/GrDropdownMenu/grDropdownMenuStyles.d.ts +10 -1
- package/dist/types/components/GrFilePreview/index.d.ts +1 -0
- package/dist/types/components/GrInput/GrInput.vue.d.ts +1 -1
- package/dist/types/components/GrJsonViewer/GrJsonViewer.vue.d.ts +129 -0
- package/dist/types/components/GrJsonViewer/config.d.ts +1 -0
- package/dist/types/components/GrJsonViewer/defaults.d.ts +23 -0
- package/dist/types/components/GrJsonViewer/grJsonViewerStyles.d.ts +57 -0
- package/dist/types/components/GrJsonViewer/index.d.ts +9 -0
- package/dist/types/components/GrJsonViewer/jsonToNodes.d.ts +47 -0
- package/dist/types/components/GrJsonViewer/safelist.d.ts +1 -0
- package/dist/types/components/GrList/grListStyles.d.ts +13 -0
- package/dist/types/components/GrNumberInput/GrNumberInput.vue.d.ts +1 -1
- package/dist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts +1 -1
- package/dist/types/components/GrStatistic/GrStatistic.vue.d.ts +12 -2
- package/dist/types/components/GrStatistic/defaults.d.ts +6 -0
- package/dist/types/granular-provider/shared.d.ts +1 -0
- package/dist/types/i18n/messages/en.d.ts +18 -0
- package/dist/types/i18n/messages/es.d.ts +18 -0
- package/dist/types/i18n/messages/ru.d.ts +18 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/internal/granularityFormat.d.ts +26 -0
- package/dist/web-types.json +136 -6
- package/package.json +5 -1
- package/dist/chunks/config-BKvX0q10.js.map +0 -1
- package/dist/chunks/config-BTCOJO5z.js.map +0 -1
- package/dist/chunks/config-B_qi4Fma2.js.map +0 -1
- package/dist/chunks/config-Baj7Wvx-2.js.map +0 -1
- package/dist/chunks/config-BsuDM3Hb.js.map +0 -1
- package/dist/chunks/config-QaIc_gRa2.js.map +0 -1
- package/dist/chunks/config-eXB87DOi2.js.map +0 -1
- package/dist/chunks/config-jyZq8XKL.js.map +0 -1
- package/dist/chunks/granular-provider-BW2uopTG.js.map +0 -1
- package/dist/chunks/trending-up-Bf9AQmoq.js.map +0 -1
- package/dist/components/GrDelta/chunks/GrDelta-BMmpYz8K.js.map +0 -1
- package/dist/components/GrDescriptionList/chunks/GrDescriptionList-pXh1LZEe.js.map +0 -1
- package/dist/components/GrList/chunks/GrList-BUzFRa8-.js.map +0 -1
- package/dist/components/GrStatistic/chunks/GrStatistic-DkzWUAw1.js.map +0 -1
- /package/dist/chunks/{config-BTCOJO5z.js → config-BTCOJO5z2.js} +0 -0
- /package/dist/chunks/{config-B_qi4Fma2.js → config-B_qi4Fma.js} +0 -0
- /package/dist/chunks/{config-Baj7Wvx-2.js → config-Baj7Wvx-.js} +0 -0
- /package/dist/chunks/{config-QaIc_gRa2.js → config-QaIc_gRa.js} +0 -0
- /package/dist/chunks/{config-eXB87DOi2.js → config-eXB87DOi.js} +0 -0
package/dist/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
|
|
3
3
|
"name": "@feugene/granularity",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.23.0",
|
|
5
5
|
"framework": "vue",
|
|
6
6
|
"js-types-syntax": "typescript",
|
|
7
7
|
"description-markup": "markdown",
|
|
@@ -2734,7 +2734,7 @@
|
|
|
2734
2734
|
},
|
|
2735
2735
|
{
|
|
2736
2736
|
"name": "divided",
|
|
2737
|
-
"description": "Отбивать пары линиями.",
|
|
2737
|
+
"description": "Отбивать пары линиями. В `flow` не применяется.",
|
|
2738
2738
|
"default": "undefined",
|
|
2739
2739
|
"value": {
|
|
2740
2740
|
"kind": "expression",
|
|
@@ -2752,6 +2752,7 @@
|
|
|
2752
2752
|
},
|
|
2753
2753
|
{
|
|
2754
2754
|
"name": "columns",
|
|
2755
|
+
"description": "Колонки сетки. В `flow` не применяются: строка колонок не имеет.",
|
|
2755
2756
|
"default": "undefined",
|
|
2756
2757
|
"value": {
|
|
2757
2758
|
"kind": "expression",
|
|
@@ -2760,7 +2761,7 @@
|
|
|
2760
2761
|
},
|
|
2761
2762
|
{
|
|
2762
2763
|
"name": "layout",
|
|
2763
|
-
"description": "`inline` — подпись слева колонкой; `stacked` — над
|
|
2764
|
+
"description": "`inline` — подпись слева колонкой; `stacked` — над значением; `flow` — пары текут по строке с переносом (метаданные внутри пункта списка).",
|
|
2764
2765
|
"default": "undefined",
|
|
2765
2766
|
"value": {
|
|
2766
2767
|
"kind": "expression",
|
|
@@ -3450,8 +3451,8 @@
|
|
|
3450
3451
|
},
|
|
3451
3452
|
{
|
|
3452
3453
|
"name": "contentClass",
|
|
3453
|
-
"description": "Дополнительные классы content
|
|
3454
|
-
"default": "\"
|
|
3454
|
+
"description": "Дополнительные классы content-контейнера.",
|
|
3455
|
+
"default": "\"\"",
|
|
3455
3456
|
"value": {
|
|
3456
3457
|
"kind": "expression",
|
|
3457
3458
|
"type": "string | undefined"
|
|
@@ -5397,6 +5398,126 @@
|
|
|
5397
5398
|
]
|
|
5398
5399
|
}
|
|
5399
5400
|
},
|
|
5401
|
+
{
|
|
5402
|
+
"name": "GrJsonViewer",
|
|
5403
|
+
"source": {
|
|
5404
|
+
"module": "@feugene/granularity/components/GrJsonViewer",
|
|
5405
|
+
"symbol": "GrJsonViewer"
|
|
5406
|
+
},
|
|
5407
|
+
"props": [
|
|
5408
|
+
{
|
|
5409
|
+
"name": "size",
|
|
5410
|
+
"default": "undefined",
|
|
5411
|
+
"value": {
|
|
5412
|
+
"kind": "expression",
|
|
5413
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\" | undefined"
|
|
5414
|
+
}
|
|
5415
|
+
},
|
|
5416
|
+
{
|
|
5417
|
+
"name": "ariaLabel",
|
|
5418
|
+
"description": "Имя области для скринридера. Безымянное дерево объявляется просто «дерево».",
|
|
5419
|
+
"default": "undefined",
|
|
5420
|
+
"value": {
|
|
5421
|
+
"kind": "expression",
|
|
5422
|
+
"type": "string | undefined"
|
|
5423
|
+
}
|
|
5424
|
+
},
|
|
5425
|
+
{
|
|
5426
|
+
"name": "virtual",
|
|
5427
|
+
"description": "Оставлять в DOM только окно вокруг вьюпорта. Требует `maxHeight`.",
|
|
5428
|
+
"default": "false",
|
|
5429
|
+
"value": {
|
|
5430
|
+
"kind": "expression",
|
|
5431
|
+
"type": "boolean | undefined"
|
|
5432
|
+
}
|
|
5433
|
+
},
|
|
5434
|
+
{
|
|
5435
|
+
"name": "maxHeight",
|
|
5436
|
+
"description": "Высота области просмотра: число — пиксели, строка — как есть.",
|
|
5437
|
+
"default": "undefined",
|
|
5438
|
+
"value": {
|
|
5439
|
+
"kind": "expression",
|
|
5440
|
+
"type": "string | number | undefined"
|
|
5441
|
+
}
|
|
5442
|
+
},
|
|
5443
|
+
{
|
|
5444
|
+
"name": "copyable",
|
|
5445
|
+
"description": "Кнопка копирования узла в строке.",
|
|
5446
|
+
"default": "undefined",
|
|
5447
|
+
"value": {
|
|
5448
|
+
"kind": "expression",
|
|
5449
|
+
"type": "boolean | undefined"
|
|
5450
|
+
}
|
|
5451
|
+
},
|
|
5452
|
+
{
|
|
5453
|
+
"name": "rootLabel",
|
|
5454
|
+
"description": "Подпись корня. По умолчанию `$` — так адресуют путь JSONPath и dev-tools.",
|
|
5455
|
+
"default": "undefined",
|
|
5456
|
+
"value": {
|
|
5457
|
+
"kind": "expression",
|
|
5458
|
+
"type": "string | undefined"
|
|
5459
|
+
}
|
|
5460
|
+
},
|
|
5461
|
+
{
|
|
5462
|
+
"name": "defaultExpandDepth",
|
|
5463
|
+
"description": "Сколько уровней раскрыто изначально.",
|
|
5464
|
+
"default": "undefined",
|
|
5465
|
+
"value": {
|
|
5466
|
+
"kind": "expression",
|
|
5467
|
+
"type": "number | undefined"
|
|
5468
|
+
}
|
|
5469
|
+
},
|
|
5470
|
+
{
|
|
5471
|
+
"name": "maxStringLength",
|
|
5472
|
+
"description": "Длина строкового значения, после которой показ обрезается. Не косметика: запрос к модели с картинкой в base64 — это один лист на сотни тысяч символов, и ни свёртка, ни виртуализация по строкам его не берут. Копирование при этом отдаёт значение целиком.",
|
|
5473
|
+
"default": "undefined",
|
|
5474
|
+
"value": {
|
|
5475
|
+
"kind": "expression",
|
|
5476
|
+
"type": "number | undefined"
|
|
5477
|
+
}
|
|
5478
|
+
},
|
|
5479
|
+
{
|
|
5480
|
+
"name": "maxArrayItems",
|
|
5481
|
+
"description": "Сколько элементов массива разбирать до заглушки «ещё N».",
|
|
5482
|
+
"default": "undefined",
|
|
5483
|
+
"value": {
|
|
5484
|
+
"kind": "expression",
|
|
5485
|
+
"type": "number | undefined"
|
|
5486
|
+
}
|
|
5487
|
+
},
|
|
5488
|
+
{
|
|
5489
|
+
"name": "searchable",
|
|
5490
|
+
"description": "Поле поиска над деревом. Выключено — поиск остаётся на `filter()` из `defineExpose`.",
|
|
5491
|
+
"default": "undefined",
|
|
5492
|
+
"value": {
|
|
5493
|
+
"kind": "expression",
|
|
5494
|
+
"type": "boolean | undefined"
|
|
5495
|
+
}
|
|
5496
|
+
},
|
|
5497
|
+
{
|
|
5498
|
+
"name": "value",
|
|
5499
|
+
"required": true,
|
|
5500
|
+
"description": "Показываемое значение. `unknown`, потому что приходит из БД или чужого сервиса.",
|
|
5501
|
+
"value": {
|
|
5502
|
+
"kind": "expression",
|
|
5503
|
+
"type": "unknown"
|
|
5504
|
+
}
|
|
5505
|
+
}
|
|
5506
|
+
],
|
|
5507
|
+
"slots": [
|
|
5508
|
+
{
|
|
5509
|
+
"name": "leaf",
|
|
5510
|
+
"description": "Значение листа: ссылка, дата, денежная сумма — оформление знает приложение."
|
|
5511
|
+
}
|
|
5512
|
+
],
|
|
5513
|
+
"js": {
|
|
5514
|
+
"events": [
|
|
5515
|
+
{
|
|
5516
|
+
"name": "copy"
|
|
5517
|
+
}
|
|
5518
|
+
]
|
|
5519
|
+
}
|
|
5520
|
+
},
|
|
5400
5521
|
{
|
|
5401
5522
|
"name": "GrKbd",
|
|
5402
5523
|
"source": {
|
|
@@ -8950,7 +9071,7 @@
|
|
|
8950
9071
|
{
|
|
8951
9072
|
"name": "tone",
|
|
8952
9073
|
"description": "Тон значения; точечно перекрывается `--gr-statistic-value-color`.",
|
|
8953
|
-
"default": "
|
|
9074
|
+
"default": "undefined",
|
|
8954
9075
|
"value": {
|
|
8955
9076
|
"kind": "expression",
|
|
8956
9077
|
"type": "\"primary\" | \"neutral\" | \"success\" | \"warning\" | \"danger\" | \"info\" | \"slate\" | \"azure\" | undefined"
|
|
@@ -9063,6 +9184,15 @@
|
|
|
9063
9184
|
"type": "string | undefined"
|
|
9064
9185
|
}
|
|
9065
9186
|
},
|
|
9187
|
+
{
|
|
9188
|
+
"name": "polarity",
|
|
9189
|
+
"description": "Что считать хорошим: тон выводится из знака самого значения. Для выручки рост — успех, для себестоимости и оттока — наоборот. Явный `tone` сильнее: выведенный тон — умолчание, а не диктат.",
|
|
9190
|
+
"default": "undefined",
|
|
9191
|
+
"value": {
|
|
9192
|
+
"kind": "expression",
|
|
9193
|
+
"type": "GrDeltaPolarity | undefined"
|
|
9194
|
+
}
|
|
9195
|
+
},
|
|
9066
9196
|
{
|
|
9067
9197
|
"name": "decimalSeparator",
|
|
9068
9198
|
"description": "Десятичный разделитель. Сильнее локали; без него и без локали — точка.",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feugene/granularity",
|
|
3
3
|
"description": "Granularity design system package with Vue 3 components, consumed via the `@feugene/unocss-preset-granular` preset.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.23.0",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Evgeniy Fureev",
|
|
@@ -209,6 +209,10 @@
|
|
|
209
209
|
"types": "./dist/types/components/GrInputTag/index.d.ts",
|
|
210
210
|
"import": "./dist/components/GrInputTag/index.js"
|
|
211
211
|
},
|
|
212
|
+
"./components/GrJsonViewer": {
|
|
213
|
+
"types": "./dist/types/components/GrJsonViewer/index.d.ts",
|
|
214
|
+
"import": "./dist/components/GrJsonViewer/index.js"
|
|
215
|
+
},
|
|
212
216
|
"./components/GrKbd": {
|
|
213
217
|
"types": "./dist/types/components/GrKbd/index.d.ts",
|
|
214
218
|
"import": "./dist/components/GrKbd/index.js"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-BKvX0q10.js","names":[],"sources":["../../src/components/GrDropdownMenu/grDropdownMenuStyles.ts","../../src/components/GrDropdownMenu/safelist.ts","../../src/components/GrDropdownMenu/config.ts"],"sourcesContent":["export type GrDropdownMenuItemAlign = 'left' | 'center' | 'right'\nexport type GrDropdownMenuItemVariant = 'default' | 'danger'\nexport type GrDropdownMenuHeaderAlign = GrDropdownMenuItemAlign\nexport type GrDropdownMenuColumnAlign = GrDropdownMenuItemAlign\nexport type GrDropdownMenuColumnsCount = 2 | 3 | 4\n\nexport const alignClass: Record<GrDropdownMenuItemAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n}\n\nexport const textAlignClass: Record<GrDropdownMenuHeaderAlign, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n}\n\nexport const colsClass: Record<GrDropdownMenuColumnsCount, string> = {\n 2: 'grid-cols-2',\n 3: 'grid-cols-3',\n 4: 'grid-cols-4',\n}\n\nexport const itemBaseClass = 'w-full min-h-10 px-4 py-2.5 flex items-center gap-2 text-[length:var(--gr-text-sm)] transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]'\n\n// Насыщенный тон как цвет текста запрещён — для текста есть `-text`-роль.\nexport const itemVariantClass: Record<GrDropdownMenuItemVariant, string> = {\n default: 'text-[var(--gr-fg)]',\n danger: 'text-[var(--gr-danger-text)]',\n}\n\nexport const itemInteractiveClass = 'cursor-pointer hover:bg-[var(--gr-accent)] hover:text-[var(--gr-accent-fg)]'\n\n// Disabled гасится фоном, а не `opacity`: прозрачность разбавляет выверенные на\n// AA токены текста. `pointer-events-none` оставлен — он же гасит hover.\nexport const itemDisabledClass = 'cursor-not-allowed pointer-events-none bg-[var(--gr-muted)] text-[var(--gr-muted-fg)]'\n\nexport const itemIndicatorClass = 'h-3.5 w-3.5 shrink-0'\nexport const itemShortcutClass = 'ml-auto pl-4 text-[length:var(--gr-text-xs)] text-[var(--gr-muted-fg)]'\n\nexport const headerClass = 'px-4 py-2 text-[length:var(--gr-text-xs)] tracking-wide text-[var(--gr-muted-fg)]'\n\nexport const listBaseClass = 'w-full'\nexport const dividersClass = 'divide-y divide-[var(--gr-brd)]'\nexport const borderTopClass = 'border-t border-[var(--gr-brd)]'\nexport const borderBottomClass = 'border-b border-[var(--gr-brd)]'\n\nexport const columnsBaseClass = 'w-full grid divide-x divide-[var(--gr-brd)]'\nexport const columnBaseClass = 'px-3 py-2 flex items-center'\n\nexport const dividerClass = 'border-t border-[var(--gr-brd)]'\nexport const dividerInsetClass = 'mx-2'\n\nexport function grDropdownMenuItemClass(options: {\n align: GrDropdownMenuItemAlign\n variant: GrDropdownMenuItemVariant\n disabled: boolean\n}): string {\n return [\n itemBaseClass,\n alignClass[options.align],\n options.disabled ? itemDisabledClass : itemVariantClass[options.variant],\n options.disabled ? '' : itemInteractiveClass,\n ].filter(Boolean).join(' ')\n}\n\nexport function grDropdownMenuListClass(options: {\n dividers: boolean\n borderTop: boolean\n borderBottom: boolean\n}): string {\n return [\n listBaseClass,\n options.dividers ? dividersClass : '',\n options.borderTop ? borderTopClass : '',\n options.borderBottom ? borderBottomClass : '',\n ].filter(Boolean).join(' ')\n}\n","import { splitClassTokens } from '../shared/classTokens'\n\nimport {\n alignClass,\n borderBottomClass,\n borderTopClass,\n colsClass,\n columnBaseClass,\n columnsBaseClass,\n dividerClass,\n dividerInsetClass,\n dividersClass,\n headerClass,\n itemBaseClass,\n itemDisabledClass,\n itemIndicatorClass,\n itemInteractiveClass,\n itemShortcutClass,\n itemVariantClass,\n listBaseClass,\n textAlignClass,\n} from './grDropdownMenuStyles'\n\n/**\n * Классы каталога живут в `.ts`-хелпере, а его бандлер волен вынести в общий\n * `dist/chunks/` — вне области скана компонента. Симптом промаха тут особенно\n * незаметный: размеры пунктов на месте, а выравнивание, колонки и цвета\n * пропали. Гейт — `src/__tests__/safelist.test.ts`.\n */\nexport const grDropdownMenuSafelist = [...new Set([\n ...Object.values(alignClass).flatMap(splitClassTokens),\n ...Object.values(textAlignClass).flatMap(splitClassTokens),\n ...Object.values(colsClass).flatMap(splitClassTokens),\n ...Object.values(itemVariantClass).flatMap(splitClassTokens),\n ...splitClassTokens(itemBaseClass),\n ...splitClassTokens(itemInteractiveClass),\n ...splitClassTokens(itemDisabledClass),\n ...splitClassTokens(itemIndicatorClass),\n ...splitClassTokens(itemShortcutClass),\n ...splitClassTokens(headerClass),\n ...splitClassTokens(listBaseClass),\n ...splitClassTokens(dividersClass),\n ...splitClassTokens(borderTopClass),\n ...splitClassTokens(borderBottomClass),\n ...splitClassTokens(columnsBaseClass),\n ...splitClassTokens(columnBaseClass),\n ...splitClassTokens(dividerClass),\n ...splitClassTokens(dividerInsetClass),\n])]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grDropdownMenuSafelist } from './safelist'\n\nexport const grDropdownMenuConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDropdownMenu',\n dependencies: ['GrDropdown'],\n safelist: grDropdownMenuSafelist,\n})\n"],"mappings":";;;AAMA,IAAa,aAAsD;CACjE,MAAM;CACN,QAAQ;CACR,OAAO;AACT;AAEA,IAAa,iBAA4D;CACvE,MAAM;CACN,QAAQ;CACR,OAAO;AACT;AAEA,IAAa,YAAwD;CACnE,GAAG;CACH,GAAG;CACH,GAAG;AACL;AAEA,IAAa,gBAAgB;AAG7B,IAAa,mBAA8D;CACzE,SAAS;CACT,QAAQ;AACV;AAEA,IAAa,uBAAuB;AAIpC,IAAa,oBAAoB;AAEjC,IAAa,qBAAqB;AAClC,IAAa,oBAAoB;AAEjC,IAAa,cAAc;AAE3B,IAAa,gBAAgB;AAC7B,IAAa,gBAAgB;AAC7B,IAAa,iBAAiB;AAC9B,IAAa,oBAAoB;AAEjC,IAAa,mBAAmB;AAChC,IAAa,kBAAkB;AAE/B,IAAa,eAAe;AAC5B,IAAa,oBAAoB;AAEjC,SAAgB,wBAAwB,SAI7B;CACT,OAAO;EACL;EACA,WAAW,QAAQ;EACnB,QAAQ,WAAW,oBAAoB,iBAAiB,QAAQ;EAChE,QAAQ,WAAW,KAAK;CAC1B,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AAC5B;AAEA,SAAgB,wBAAwB,SAI7B;CACT,OAAO;EACL;EACA,QAAQ,WAAW,gBAAgB;EACnC,QAAQ,YAAY,iBAAiB;EACrC,QAAQ,eAAe,oBAAoB;CAC7C,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AAC5B;;;;;;;;;ACjDA,IAAa,yBAAyB,CAAC,mBAAG,IAAI,IAAI;CAC9C,GAAG,OAAO,OAAO,UAAU,CAAC,CAAC,QAAQ,gBAAgB;CACrD,GAAG,OAAO,OAAO,cAAc,CAAC,CAAC,QAAQ,gBAAgB;CACzD,GAAG,OAAO,OAAO,SAAS,CAAC,CAAC,QAAQ,gBAAgB;CACpD,GAAG,OAAO,OAAO,gBAAgB,CAAC,CAAC,QAAQ,gBAAgB;CAC3D,GAAG,iBAAiB,aAAa;CACjC,GAAG,iBAAiB,oBAAoB;CACxC,GAAG,iBAAiB,iBAAiB;CACrC,GAAG,iBAAiB,kBAAkB;CACtC,GAAG,iBAAiB,iBAAiB;CACrC,GAAG,iBAAiB,WAAW;CAC/B,GAAG,iBAAiB,aAAa;CACjC,GAAG,iBAAiB,aAAa;CACjC,GAAG,iBAAiB,cAAc;CAClC,GAAG,iBAAiB,iBAAiB;CACrC,GAAG,iBAAiB,gBAAgB;CACpC,GAAG,iBAAiB,eAAe;CACnC,GAAG,iBAAiB,YAAY;CAChC,GAAG,iBAAiB,iBAAiB;AACzC,CAAC,CAAC;;;AC5CF,IAAa,uBAAuB,wBAAwB,OAAO,KAAK,KAAK;CAC3E,MAAM;CACN,cAAc,CAAC,YAAY;CAC3B,UAAU;AACZ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-BTCOJO5z.js","names":[],"sources":["../../src/components/GrRadio/safelist.ts","../../src/components/GrRadio/config.ts"],"sourcesContent":["import { splitClassTokens } from '../shared/classTokens'\nimport { grButtonSafelist } from '../GrButton/safelist'\nimport {\n grRadioButtonDisabledCheckedClass,\n grRadioButtonDisabledClass,\n grRadioControlCheckedClass,\n grRadioControlDisabledClass,\n grRadioControlInvalidClass,\n grRadioControlUncheckedClass,\n grRadioControlSizes,\n grRadioDescriptionSizes,\n grRadioDotBaseClass,\n grRadioDotSizes,\n grRadioDotCheckedClass,\n grRadioDotDisabledClass,\n grRadioDotUncheckedClass,\n grRadioEnabledClass,\n grRadioLabelCheckedColorClass,\n grRadioLabelColorClass,\n grRadioLabelSizes,\n grRadioRootDisabledClass,\n grRadioRootReadonlyClass,\n grRadioRootEnabledClass,\n} from './grRadioStyles'\n\nexport const grRadioSafelist = [...new Set([\n ...grButtonSafelist,\n ...splitClassTokens(grRadioEnabledClass),\n ...splitClassTokens(grRadioButtonDisabledClass),\n ...splitClassTokens(grRadioButtonDisabledCheckedClass),\n ...splitClassTokens(grRadioRootDisabledClass),\n ...splitClassTokens(grRadioRootEnabledClass),\n ...splitClassTokens(grRadioRootReadonlyClass),\n ...splitClassTokens(grRadioControlCheckedClass),\n ...splitClassTokens(grRadioControlUncheckedClass),\n ...splitClassTokens(grRadioControlDisabledClass),\n ...splitClassTokens(grRadioControlInvalidClass),\n ...splitClassTokens(grRadioDotCheckedClass),\n ...splitClassTokens(grRadioDotUncheckedClass),\n ...splitClassTokens(grRadioDotDisabledClass),\n ...splitClassTokens(grRadioDotBaseClass),\n ...Object.values(grRadioControlSizes).flatMap(splitClassTokens),\n ...Object.values(grRadioDotSizes).flatMap(splitClassTokens),\n ...Object.values(grRadioLabelSizes).flatMap(splitClassTokens),\n ...Object.values(grRadioDescriptionSizes).flatMap(splitClassTokens),\n ...splitClassTokens(grRadioLabelColorClass),\n ...splitClassTokens(grRadioLabelCheckedColorClass),\n])]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grRadioSafelist } from './safelist'\n\nexport const grRadioConfig = defineGranularComponent(import.meta.url, {\n name: 'GrRadio',\n dependencies: ['GrButton'],\n safelist: grRadioSafelist,\n})"],"mappings":";;;;;AAyBA,IAAa,kBAAkB,CAAC,mBAAG,IAAI,IAAI;CACzC,GAAG;CACH,GAAG,iBAAiB,mBAAmB;CACvC,GAAG,iBAAiB,0BAA0B;CAC9C,GAAG,iBAAiB,iCAAiC;CACrD,GAAG,iBAAiB,wBAAwB;CAC5C,GAAG,iBAAiB,uBAAuB;CAC3C,GAAG,iBAAiB,wBAAwB;CAC5C,GAAG,iBAAiB,0BAA0B;CAC9C,GAAG,iBAAiB,4BAA4B;CAChD,GAAG,iBAAiB,2BAA2B;CAC/C,GAAG,iBAAiB,0BAA0B;CAC9C,GAAG,iBAAiB,sBAAsB;CAC1C,GAAG,iBAAiB,wBAAwB;CAC5C,GAAG,iBAAiB,uBAAuB;CAC3C,GAAG,iBAAiB,mBAAmB;CACvC,GAAG,OAAO,OAAO,mBAAmB,CAAC,CAAC,QAAQ,gBAAgB;CAC9D,GAAG,OAAO,OAAO,eAAe,CAAC,CAAC,QAAQ,gBAAgB;CAC1D,GAAG,OAAO,OAAO,iBAAiB,CAAC,CAAC,QAAQ,gBAAgB;CAC5D,GAAG,OAAO,OAAO,uBAAuB,CAAC,CAAC,QAAQ,gBAAgB;CAClE,GAAG,iBAAiB,sBAAsB;CAC1C,GAAG,iBAAiB,6BAA6B;AACnD,CAAC,CAAC;;;AC3CF,IAAa,gBAAgB,wBAAwB,OAAO,KAAK,KAAK;CACpE,MAAM;CACN,cAAc,CAAC,UAAU;CACzB,UAAU;AACZ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-B_qi4Fma2.js","names":[],"sources":["../../src/components/GrCodeBlock/grCodeBlockStyles.ts","../../src/components/GrCodeBlock/safelist.ts","../../src/components/GrCodeBlock/config.ts"],"sourcesContent":["import type { GrComponentSize } from '../shared/sizes'\n\nimport type { GrCodeTokenKind } from './tokenizeJson'\n\n/**\n * Классы `GrCodeBlock`.\n *\n * Роли подсветки перечислены целиком, по литералу на ветку: UnoCSS сканирует\n * исходный текст файла, и собранное шаблонной строкой имя уехало бы в CSS как\n * литерал.\n */\n\n/**\n * Зацепка собственного CSS компонента (номера строк). Не утилита: CSS она не\n * порождает, поэтому в `safelist` не идёт — там гейт справедливо считает такую\n * запись мёртвой.\n */\nexport const codeBlockHookClass = 'gr-code-block'\n\n/** Включает колонку номеров. Тоже зацепка, не утилита. */\nexport const codeBlockNumberedClass = 'gr-code-block--numbered'\n\n/**\n * Поверхность держит корень, а не `<pre>`: кнопка копирования стоит рядом со\n * скроллером, и жёлоб под неё обязан быть частью блока, а не полем страницы.\n */\nexport const codeBlockRootClass = 'relative rounded-[var(--gr-radius-md)] bg-[var(--gr-code-block-bg,var(--gr-muted))] text-[var(--gr-code-block-fg,var(--gr-fg))]'\n\n/**\n * Полоса под кнопку: 28 px самой кнопки плюс отбивка `right-1`.\n *\n * Кнопка не может висеть поверх `<pre>`: полосу прокрутки браузер рисует у\n * правого края скроллера, в тех же 8–15 px, и накрытую кнопкой её не ухватить\n * мышью. Отступами это не лечится — их пришлось бы взять больше ширины самой\n * кнопки, и «угол» перестал бы быть углом. Витринный `doc/CodeBlock.vue` решает\n * то же самое шапкой; у пакетного блока шапки нет, поэтому место отдаётся\n * жёлобом.\n */\nexport const codeBlockGutterClass = 'pr-9'\n\n/** Браузерный отступ `<pre>`: фон и радиус живут на корне, полю здесь не место. */\nexport const codeBlockSurfaceClass = 'm-0'\n\n/** Скроллер обязан показывать фокус: он стоит в таб-порядке. */\nexport const codeBlockScrollClass = 'overflow-auto focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]'\n\nexport const codeBlockWrapClass = 'whitespace-pre-wrap break-words'\nexport const codeBlockNowrapClass = 'whitespace-pre'\n\n/** Кнопка копирования: правый верхний угол, внутри жёлоба. */\nexport const codeBlockCopyClass = 'absolute right-1 top-1 z-[1]'\n\nexport const codeBlockPaddings: Record<GrComponentSize, string> = {\n xs: 'p-2',\n sm: 'p-2.5',\n md: 'p-3',\n lg: 'p-4',\n}\n\nexport const codeBlockTextSizes: Record<GrComponentSize, string> = {\n xs: 'text-[length:var(--gr-control-text-3xs)]',\n sm: 'text-[length:var(--gr-control-text-2xs)]',\n md: 'text-[length:var(--gr-control-text-xs)]',\n lg: 'text-[length:var(--gr-control-text-sm)]',\n}\n\n/**\n * Роли подсветки. Дефолты — ссылки на `-text`-роли темы: они переключаются\n * вместе с ней, поэтому подсветка работает в обеих без своего theme-слоя.\n *\n * Число взято от `azure`, а не от `info`: `info` — синий в двух шагах от индиго\n * `primary`, и пара «ключ ↔ число» давала ΔE 9.4 в светлой теме и 7.8 в тёмной.\n * В `{\"count\": 42}` эти два цвета стоят через двоеточие и читались бы как один.\n * С `azure` расстояние 53.8 и 16.6. Гейт — `grCodeBlockContrast.test.ts`.\n */\nexport const codeTokenClass: Record<GrCodeTokenKind, string> = {\n key: 'text-[var(--gr-code-block-key,var(--gr-primary-text))]',\n string: 'text-[var(--gr-code-block-string,var(--gr-success-text))]',\n number: 'text-[var(--gr-code-block-number,var(--gr-azure-text))]',\n literal: 'text-[var(--gr-code-block-literal,var(--gr-warning-text))]',\n punctuation: 'text-[var(--gr-code-block-fg,var(--gr-fg))]',\n plain: '',\n}\n","import { splitClassTokens } from '../shared/classTokens'\n\nimport {\n codeBlockCopyClass,\n codeBlockGutterClass,\n codeBlockNowrapClass,\n codeBlockPaddings,\n codeBlockRootClass,\n codeBlockScrollClass,\n codeBlockSurfaceClass,\n codeBlockTextSizes,\n codeBlockWrapClass,\n codeTokenClass,\n} from './grCodeBlockStyles'\n\n// Классы из вычисляемых мап (роль токена, размер) UnoCSS сканом не находит —\n// только safelist. Литералы хелпера туда же: на сборке он уезжает в общий чанк.\n//\n// `codeBlockHookClass` и `codeBlockNumberedClass` сюда НЕ идут: это селекторы\n// собственного `<style>` компонента, CSS из них не порождается, и гейт\n// `documentedConfig` справедливо считал бы такую запись мёртвой.\nexport const grCodeBlockSafelist = [...new Set([\n ...splitClassTokens(codeBlockRootClass),\n ...splitClassTokens(codeBlockSurfaceClass),\n ...splitClassTokens(codeBlockScrollClass),\n ...splitClassTokens(codeBlockWrapClass),\n ...splitClassTokens(codeBlockNowrapClass),\n ...splitClassTokens(codeBlockCopyClass),\n ...splitClassTokens(codeBlockGutterClass),\n ...Object.values(codeBlockPaddings).flatMap(splitClassTokens),\n ...Object.values(codeBlockTextSizes).flatMap(splitClassTokens),\n ...Object.values(codeTokenClass).flatMap(splitClassTokens),\n])]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grCodeBlockSafelist } from './safelist'\n\nexport const grCodeBlockConfig = defineGranularComponent(import.meta.url, {\n name: 'GrCodeBlock',\n dependencies: ['GrButton'],\n safelist: grCodeBlockSafelist,\n})\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,IAAa,qBAAqB;;AAGlC,IAAa,yBAAyB;;;;;AAMtC,IAAa,qBAAqB;;;;;;;;;;;AAYlC,IAAa,uBAAuB;;AAMpC,IAAa,uBAAuB;AAEpC,IAAa,qBAAqB;AAClC,IAAa,uBAAuB;;AAGpC,IAAa,qBAAqB;AAElC,IAAa,oBAAqD;CAChE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAa,qBAAsD;CACjE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;;;;;;;;AAWA,IAAa,iBAAkD;CAC7D,KAAK;CACL,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,aAAa;CACb,OAAO;AACT;;;AC7DA,IAAa,sBAAsB,CAAC,mBAAG,IAAI,IAAI;CAC7C,GAAG,iBAAiB,kBAAkB;CACtC,GAAG,iBAAA,KAAsC;CACzC,GAAG,iBAAiB,oBAAoB;CACxC,GAAG,iBAAiB,kBAAkB;CACtC,GAAG,iBAAiB,oBAAoB;CACxC,GAAG,iBAAiB,kBAAkB;CACtC,GAAG,iBAAiB,oBAAoB;CACxC,GAAG,OAAO,OAAO,iBAAiB,CAAC,CAAC,QAAQ,gBAAgB;CAC5D,GAAG,OAAO,OAAO,kBAAkB,CAAC,CAAC,QAAQ,gBAAgB;CAC7D,GAAG,OAAO,OAAO,cAAc,CAAC,CAAC,QAAQ,gBAAgB;AAC3D,CAAC,CAAC;;;AC5BF,IAAa,oBAAoB,wBAAwB,OAAO,KAAK,KAAK;CACxE,MAAM;CACN,cAAc,CAAC,UAAU;CACzB,UAAU;AACZ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-Baj7Wvx-2.js","names":[],"sources":["../../src/components/GrRating/grRatingStyles.ts","../../src/components/GrRating/safelist.ts","../../src/components/GrRating/config.ts"],"sourcesContent":["import type { GrComponentSize } from '../shared/sizes'\n\nimport type { GrTone } from '../shared/tones'\n\nexport type GrRatingSize = GrComponentSize\nexport type GrRatingTone = GrTone\n\n/**\n * Кастомизация через CSS-переменные (на самом компоненте или любом предке):\n *\n * - `--gr-rating-color` — цвет «залитых» символов (по умолчанию — из `tone`).\n * - `--gr-rating-void-color` — цвет «пустых» символов.\n * - `--gr-rating-symbol-size` — размер символа (по умолчанию — из `size`).\n */\n\n// Размер символа — дефолт для `--gr-rating-symbol-size`.\nexport const ratingSymbolSizeBySize: Record<GrRatingSize, string> = {\n xs: 'h-[var(--gr-rating-symbol-size,0.875rem)] w-[var(--gr-rating-symbol-size,0.875rem)]',\n sm: 'h-[var(--gr-rating-symbol-size,1rem)] w-[var(--gr-rating-symbol-size,1rem)]',\n md: 'h-[var(--gr-rating-symbol-size,1.25rem)] w-[var(--gr-rating-symbol-size,1.25rem)]',\n lg: 'h-[var(--gr-rating-symbol-size,1.5rem)] w-[var(--gr-rating-symbol-size,1.5rem)]',\n}\n\nexport const ratingGapBySize: Record<GrRatingSize, string> = {\n xs: 'gap-0.5',\n sm: 'gap-0.5',\n md: 'gap-1',\n lg: 'gap-1.5',\n}\n\nexport const ratingTextSizeBySize: Record<GrRatingSize, string> = {\n xs: 'text-[length:var(--gr-control-text-2xs)]',\n sm: 'text-[length:var(--gr-control-text-xs)]',\n md: 'text-[length:var(--gr-control-text-sm)]',\n lg: 'text-[length:var(--gr-rating-font-size-lg,15px)]',\n}\n\n// Цвет заливки по тону. `--gr-rating-color` перекрывает тон точечно.\nexport const ratingFillClassByTone: Record<GrRatingTone, string> = {\n primary: 'text-[var(--gr-rating-color,var(--gr-primary))]',\n neutral: 'text-[var(--gr-rating-color,var(--gr-fg))]',\n success: 'text-[var(--gr-rating-color,var(--gr-success))]',\n warning: 'text-[var(--gr-rating-color,var(--gr-warning))]',\n danger: 'text-[var(--gr-rating-color,var(--gr-danger))]',\n info: 'text-[var(--gr-rating-color,var(--gr-info))]',\n slate: 'text-[var(--gr-rating-color,var(--gr-slate))]',\n azure: 'text-[var(--gr-rating-color,var(--gr-azure))]',\n}\n\n// «Пустой» символ: приглушённая заливка, чтобы шкала читалась целиком.\nexport const ratingVoidClass = 'text-[var(--gr-rating-void-color,color-mix(in_srgb,var(--gr-muted-fg)_35%,transparent))]'\n\nexport const ratingDisabledClass = 'cursor-not-allowed text-[var(--gr-disabled-fg)]'\n\nexport const ratingRootBaseClass = 'inline-flex items-center rounded-[var(--gr-radius-control)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--gr-bg)]'\n\nexport function ratingRootClass(options: { size: GrRatingSize, disabled: boolean, interactive: boolean }): string {\n return [\n ratingRootBaseClass,\n ratingGapBySize[options.size],\n // Недоступная шкала гасится токеном, а не `opacity`: прозрачность\n // разбавляет выверенные на AA токены и роняет контраст подписи.\n options.disabled ? ratingDisabledClass : (options.interactive ? 'cursor-pointer' : ''),\n ]\n .filter(Boolean)\n .join(' ')\n}\n\nexport function ratingSymbolClass(size: GrRatingSize): string {\n return `relative block shrink-0 ${ratingSymbolSizeBySize[size]}`\n}\n","import { splitClassTokens } from '../shared/classTokens'\nimport {\n ratingDisabledClass,\n ratingFillClassByTone,\n ratingGapBySize,\n ratingRootBaseClass,\n ratingSymbolSizeBySize,\n ratingTextSizeBySize,\n ratingVoidClass,\n} from './grRatingStyles'\n\n// Всё, что живёт в `grRatingStyles.ts`: и вычисляемые мапы (size/tone), и\n// строковые литералы. Хелпер бандлер волен вынести в общий `dist/chunks/`,\n// который не попадает в область скана компонента — гейт `src/__tests__/safelist.test.ts`.\nexport const grRatingSafelist = [...new Set([\n ...Object.values(ratingSymbolSizeBySize).flatMap(splitClassTokens),\n ...Object.values(ratingGapBySize).flatMap(splitClassTokens),\n ...Object.values(ratingTextSizeBySize).flatMap(splitClassTokens),\n ...Object.values(ratingFillClassByTone).flatMap(splitClassTokens),\n ...splitClassTokens(ratingVoidClass),\n ...splitClassTokens(ratingRootBaseClass),\n ...splitClassTokens(ratingDisabledClass),\n ...splitClassTokens('cursor-pointer'),\n ...splitClassTokens('relative block shrink-0 tabular-nums'),\n])]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grRatingSafelist } from './safelist'\n\nexport const grRatingConfig = defineGranularComponent(import.meta.url, {\n name: 'GrRating',\n safelist: grRatingSafelist,\n})\n"],"mappings":";;;;;;;;;;AAgBA,IAAa,yBAAuD;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAa,kBAAgD;CAC3D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAa,uBAAqD;CAChE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAGA,IAAa,wBAAsD;CACjE,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,OAAO;CACP,OAAO;AACT;AAGA,IAAa,kBAAkB;AAE/B,IAAa,sBAAsB;AAEnC,IAAa,sBAAsB;AAEnC,SAAgB,gBAAgB,SAAkF;CAChH,OAAO;EACL;EACA,gBAAgB,QAAQ;EAGxB,QAAQ,WAAW,sBAAuB,QAAQ,cAAc,mBAAmB;CACrF,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;AAEA,SAAgB,kBAAkB,MAA4B;CAC5D,OAAO,2BAA2B,uBAAuB;AAC3D;;;ACxDA,IAAa,mBAAmB,CAAC,mBAAG,IAAI,IAAI;CAC1C,GAAG,OAAO,OAAO,sBAAsB,CAAC,CAAC,QAAQ,gBAAgB;CACjE,GAAG,OAAO,OAAO,eAAe,CAAC,CAAC,QAAQ,gBAAgB;CAC1D,GAAG,OAAO,OAAO,oBAAoB,CAAC,CAAC,QAAQ,gBAAgB;CAC/D,GAAG,OAAO,OAAO,qBAAqB,CAAC,CAAC,QAAQ,gBAAgB;CAChE,GAAG,iBAAiB,eAAe;CACnC,GAAG,iBAAiB,mBAAmB;CACvC,GAAG,iBAAiB,mBAAmB;CACvC,GAAG,iBAAiB,gBAAgB;CACpC,GAAG,iBAAiB,sCAAsC;AAC5D,CAAC,CAAC;;;ACpBF,IAAa,iBAAiB,wBAAwB,OAAO,KAAK,KAAK;CACrE,MAAM;CACN,UAAU;AACZ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-BsuDM3Hb.js","names":[],"sources":["../../src/components/GrList/grListStyles.ts","../../src/components/GrList/safelist.ts","../../src/components/GrList/config.ts"],"sourcesContent":["export type GrListItemDensity = 'compact' | 'regular'\n\n/**\n * Классы `GrList`/`GrListItem`.\n *\n * Единственный источник правды для шаблонов и safelist: до этого карта\n * плотности жила в SFC, а её копия — строковыми литералами прямо в `config.ts`,\n * и разойтись они могли молча.\n */\n\nexport const densityPadding: Record<GrListItemDensity, string> = {\n compact: 'px-4 py-2',\n regular: 'px-4 py-3',\n}\n\nexport const itemLayoutClass = 'flex items-start justify-between gap-4'\n\n/** Интерактивная строка занимает всю ширину пункта — кликабельна вся, а не текст. */\nexport const itemInteractiveClass = 'w-full text-left transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] focus-visible:ring-inset'\n\nexport const itemHoverClass = 'cursor-pointer hover:bg-[var(--gr-muted)]'\n\n/**\n * Заблокированная строка гасится фоном и цветом, а не `opacity`: прозрачность\n * разбавляет выверенные на AA токены текста.\n */\nexport const itemDisabledClass = 'cursor-not-allowed bg-[var(--gr-muted)] text-[var(--gr-muted-fg)]'\n\nexport const dividedClass = 'divide-y divide-[var(--gr-brd)]'\n\nexport const emptyClass = 'px-4 py-6 text-center text-[length:var(--gr-text-sm)] text-[var(--gr-muted-fg)]'\n\n/** Заголовок и описание строки. Оба нужны обеим веткам пункта — интерактивной и обычной. */\nexport const itemTitleClass = 'text-[length:var(--gr-text-sm)] font-700'\nexport const itemDescriptionClass = 'mt-0.5 text-[length:var(--gr-text-sm)] text-[var(--gr-muted-fg)]'\n\nexport const loadingRowClass = 'px-4 py-3'\n\nexport function grListItemPaddingClass(density: GrListItemDensity): string {\n return densityPadding[density]\n}\n","import { splitClassTokens } from '../shared/classTokens'\nimport {\n densityPadding,\n dividedClass,\n emptyClass,\n itemDescriptionClass,\n itemDisabledClass,\n itemHoverClass,\n itemInteractiveClass,\n itemLayoutClass,\n itemTitleClass,\n loadingRowClass,\n} from './grListStyles'\n\nexport const grListSafelist = [...new Set([\n ...Object.values(densityPadding).flatMap(splitClassTokens),\n ...splitClassTokens(itemLayoutClass),\n ...splitClassTokens(itemTitleClass),\n ...splitClassTokens(itemDescriptionClass),\n ...splitClassTokens(itemInteractiveClass),\n ...splitClassTokens(itemHoverClass),\n ...splitClassTokens(itemDisabledClass),\n ...splitClassTokens(dividedClass),\n ...splitClassTokens(emptyClass),\n ...splitClassTokens(loadingRowClass),\n])]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grListSafelist } from './safelist'\n\nexport const grListConfig = defineGranularComponent(import.meta.url, {\n name: 'GrList',\n safelist: grListSafelist,\n dependencies: ['GrCard', 'GrSkeleton'],\n})\n"],"mappings":";;;;;;;;;;AAUA,IAAa,iBAAoD;CAC/D,SAAS;CACT,SAAS;AACX;AAEA,IAAa,kBAAkB;;AAG/B,IAAa,uBAAuB;AAEpC,IAAa,iBAAiB;;;;;AAM9B,IAAa,oBAAoB;AAEjC,IAAa,eAAe;AAE5B,IAAa,aAAa;;AAG1B,IAAa,iBAAiB;AAC9B,IAAa,uBAAuB;AAEpC,IAAa,kBAAkB;AAE/B,SAAgB,uBAAuB,SAAoC;CACzE,OAAO,eAAe;AACxB;;;AC1BA,IAAa,iBAAiB,CAAC,mBAAG,IAAI,IAAI;CACxC,GAAG,OAAO,OAAO,cAAc,CAAC,CAAC,QAAQ,gBAAgB;CACzD,GAAG,iBAAiB,eAAe;CACnC,GAAG,iBAAiB,cAAc;CAClC,GAAG,iBAAiB,oBAAoB;CACxC,GAAG,iBAAiB,oBAAoB;CACxC,GAAG,iBAAiB,cAAc;CAClC,GAAG,iBAAiB,iBAAiB;CACrC,GAAG,iBAAiB,YAAY;CAChC,GAAG,iBAAiB,UAAU;CAC9B,GAAG,iBAAiB,eAAe;AACrC,CAAC,CAAC;;;ACrBF,IAAa,eAAe,wBAAwB,OAAO,KAAK,KAAK;CACnE,MAAM;CACN,UAAU;CACV,cAAc,CAAC,UAAU,YAAY;AACvC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-QaIc_gRa2.js","names":[],"sources":["../../src/components/GrRadioGroup/config.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nexport const grRadioGroupConfig = defineGranularComponent(import.meta.url, {\n name: 'GrRadioGroup',\n dependencies: ['GrButtonGroup', 'GrRadio'],\n})\n"],"mappings":";;AAEA,IAAa,qBAAqB,wBAAwB,OAAO,KAAK,KAAK;CACzE,MAAM;CACN,cAAc,CAAC,iBAAiB,SAAS;AAC3C,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-eXB87DOi2.js","names":[],"sources":["../../src/components/GrTabPanels/config.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\n/**\n * Granular-конфиг семейства `GrTabPanels` (контейнер `GrTabPanels` + панель\n * `GrTabPanel`). Companion к `GrTabs` для ARIA-связки `tab`↔`tabpanel`.\n */\nexport const grTabPanelsConfig = defineGranularComponent(import.meta.url, {\n name: 'GrTabPanels',\n})\n"],"mappings":";;;;;;AAMA,IAAa,oBAAoB,wBAAwB,OAAO,KAAK,KAAK,EACxE,MAAM,cACR,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-jyZq8XKL.js","names":[],"sources":["../../src/components/GrDescriptionList/grDescriptionListStyles.ts","../../src/components/GrDescriptionList/safelist.ts","../../src/components/GrDescriptionList/config.ts"],"sourcesContent":["import type { GrComponentSize } from '../shared/sizes'\nimport type { GrTone } from '../shared/tones'\n\n/**\n * Классы `GrDescriptionList`.\n *\n * Тон перечислен целиком по одному литералу на ветку: UnoCSS сканирует исходный\n * текст файла, и собранное шаблонной строкой имя уехало бы в CSS литералом.\n */\n\n/** `inline` — подпись колонкой слева; `stacked` — над значением. */\nexport type GrDescriptionLayout = 'inline' | 'stacked'\n\nexport type GrDescriptionDensity = 'regular' | 'compact'\n\n/** Сколько колонок пар. Длинный список читается в две. */\nexport type GrDescriptionColumns = 1 | 2\n\n// `m-0` — у нативного `<dl>` есть браузерные отступы, и без сброса список\n// разъезжается по вертикали. Ряды разводит `--gr-description-list-row-gap`,\n// потому что зазор здесь — точка кастомизации, а не ступень шкалы.\nexport const descriptionRootClass = 'm-0 grid gap-x-4 [row-gap:var(--gr-description-list-row-gap,0.375rem)]'\n\nexport const descriptionColumnsClass: Record<GrDescriptionColumns, string> = {\n 1: 'grid-cols-1',\n // Пара — элемент сетки, поэтому между колонками она не рвётся. `column-count`\n // рвал бы: он раскладывает поток, а не блоки.\n 2: 'grid-cols-1 sm:grid-cols-2',\n}\n\nexport const descriptionPairInlineClass = 'flex min-w-0 items-baseline gap-2'\nexport const descriptionPairStackedClass = 'min-w-0'\n\nexport const descriptionDividedClass = 'border-b border-[var(--gr-description-list-divider,var(--gr-brd))] pb-1 last:border-b-0 last:pb-0'\n\n// `shrink-0` держит колонку подписей ровной: иначе длинное значение сжимало бы\n// подпись, и значения переставали бы стоять в колонку — ровно то, ради чего\n// раскладка `inline` и существует.\nexport const descriptionLabelInlineClass = 'shrink-0 text-[var(--gr-description-list-label-color,var(--gr-muted-fg))]'\nexport const descriptionLabelStackedClass = 'text-[var(--gr-description-list-label-color,var(--gr-muted-fg))]'\n\n// `break-words` обязателен: в парах живут идентификаторы, хеши и `X-Request-Id`,\n// и без переноса они выталкивают вёрстку.\nexport const descriptionValueClass = 'm-0 min-w-0 break-words'\n\n/** Тон — только у значения: красная подпись читается как «поле сломано». */\nexport const descriptionValueToneClass: Record<GrTone, string> = {\n primary: 'text-[var(--gr-primary-text)]',\n neutral: '',\n success: 'text-[var(--gr-success-text)]',\n warning: 'text-[var(--gr-warning-text)]',\n danger: 'text-[var(--gr-danger-text)]',\n info: 'text-[var(--gr-info-text)]',\n slate: 'text-[var(--gr-slate-text)]',\n azure: 'text-[var(--gr-azure-text)]',\n}\n\nexport const descriptionSizeClass: Record<GrComponentSize, string> = {\n xs: 'text-[length:var(--gr-control-text-2xs)]',\n sm: 'text-[length:var(--gr-control-text-xs)]',\n md: 'text-[length:var(--gr-control-text-sm)]',\n lg: 'text-[length:var(--gr-control-text-md)]',\n}\n\nexport const descriptionDensityClass: Record<GrDescriptionDensity, string> = {\n regular: '',\n compact: '[row-gap:var(--gr-description-list-row-gap,0.125rem)]',\n}\n","import { splitClassTokens } from '../shared/classTokens'\n\nimport {\n descriptionColumnsClass,\n descriptionDensityClass,\n descriptionDividedClass,\n descriptionLabelInlineClass,\n descriptionLabelStackedClass,\n descriptionPairInlineClass,\n descriptionPairStackedClass,\n descriptionRootClass,\n descriptionSizeClass,\n descriptionValueClass,\n descriptionValueToneClass,\n} from './grDescriptionListStyles'\n\n// Классы из вычисляемых мап (тон, размер, колонки) UnoCSS сканом не находит —\n// только safelist. Литералы хелпера туда же: на сборке он уезжает в общий чанк.\nexport const grDescriptionListSafelist = [...new Set([\n ...splitClassTokens(descriptionRootClass),\n ...splitClassTokens(descriptionPairInlineClass),\n ...splitClassTokens(descriptionPairStackedClass),\n ...splitClassTokens(descriptionDividedClass),\n ...splitClassTokens(descriptionLabelInlineClass),\n ...splitClassTokens(descriptionLabelStackedClass),\n ...splitClassTokens(descriptionValueClass),\n ...Object.values(descriptionColumnsClass).flatMap(splitClassTokens),\n ...Object.values(descriptionValueToneClass).flatMap(splitClassTokens),\n ...Object.values(descriptionSizeClass).flatMap(splitClassTokens),\n ...Object.values(descriptionDensityClass).flatMap(splitClassTokens),\n])]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grDescriptionListSafelist } from './safelist'\n\nexport const grDescriptionListConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDescriptionList',\n safelist: grDescriptionListSafelist,\n})\n"],"mappings":";;;AAqBA,IAAa,uBAAuB;AAEpC,IAAa,0BAAgE;CAC3E,GAAG;CAGH,GAAG;AACL;AAEA,IAAa,6BAA6B;AAC1C,IAAa,8BAA8B;AAE3C,IAAa,0BAA0B;AAKvC,IAAa,8BAA8B;AAC3C,IAAa,+BAA+B;AAI5C,IAAa,wBAAwB;;AAGrC,IAAa,4BAAoD;CAC/D,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,OAAO;CACP,OAAO;AACT;AAEA,IAAa,uBAAwD;CACnE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAa,0BAAgE;CAC3E,SAAS;CACT,SAAS;AACX;;;ACjDA,IAAa,4BAA4B,CAAC,mBAAG,IAAI,IAAI;CACnD,GAAG,iBAAiB,oBAAoB;CACxC,GAAG,iBAAiB,0BAA0B;CAC9C,GAAG,iBAAiB,2BAA2B;CAC/C,GAAG,iBAAiB,uBAAuB;CAC3C,GAAG,iBAAiB,2BAA2B;CAC/C,GAAG,iBAAiB,4BAA4B;CAChD,GAAG,iBAAiB,qBAAqB;CACzC,GAAG,OAAO,OAAO,uBAAuB,CAAC,CAAC,QAAQ,gBAAgB;CAClE,GAAG,OAAO,OAAO,yBAAyB,CAAC,CAAC,QAAQ,gBAAgB;CACpE,GAAG,OAAO,OAAO,oBAAoB,CAAC,CAAC,QAAQ,gBAAgB;CAC/D,GAAG,OAAO,OAAO,uBAAuB,CAAC,CAAC,QAAQ,gBAAgB;AACpE,CAAC,CAAC;;;AC1BF,IAAa,0BAA0B,wBAAwB,OAAO,KAAK,KAAK;CAC9E,MAAM;CACN,UAAU;AACZ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"granular-provider-BW2uopTG.js","names":[],"sources":["../../src/components/GrDialog/config.ts","../../src/components/GrResponseErrorBanner/config.ts","../../src/granular-provider/shared.ts","../../src/granular-provider/index.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grDialogSafelist } from './safelist'\n\nexport const grDialogConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDialog',\n dependencies: ['GrButton', 'GrModal'],\n safelist: grDialogSafelist,\n})\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nexport const grResponseErrorBannerConfig = defineGranularComponent(import.meta.url, {\n name: 'GrResponseErrorBanner',\n dependencies: ['GrAlert', 'GrButton'],\n})\n","// `id`, `theme.*`, `packageBaseUrl` и реестр компонентов провайдера.\n//\n// Все `new URL('../styles/...', import.meta.url)` обязаны лежать именно здесь:\n// `shared.ts` в одной директории с `index.ts` / `node.ts`, поэтому\n// относительные пути совпадают. Для браузера безопасно — бандлеры\n// транслируют такие литералы в статические asset-URL.\n//\n// `apps/showcase/scripts/generate-component-api.mjs` читает список компонентов\n// из `Object.keys(granularityComponentConfigs)` через vite SSR.\nimport {\n defineGranularProvider,\n type GranularComponentDescriptor,\n type GranularProvider,\n resolvePackageBaseUrl,\n} from '@feugene/unocss-preset-granular/contract'\n// <granularity:components:imports> — блок генерируется `yarn generate:registry`\nimport { grAlertConfig } from '../components/GrAlert/config'\nimport { grAutocompleteConfig } from '../components/GrAutocomplete/config'\nimport { grAvatarConfig } from '../components/GrAvatar/config'\nimport { grBadgeConfig } from '../components/GrBadge/config'\nimport { grBadgeWrapConfig } from '../components/GrBadgeWrap/config'\nimport { grBottomNavConfig } from '../components/GrBottomNav/config'\nimport { grBreadcrumbsConfig } from '../components/GrBreadcrumbs/config'\nimport { grButtonConfig } from '../components/GrButton/config'\nimport { grButtonGroupConfig } from '../components/GrButtonGroup/config'\nimport { grCardConfig } from '../components/GrCard/config'\nimport { grCheckboxConfig } from '../components/GrCheckbox/config'\nimport { grCheckboxGroupConfig } from '../components/GrCheckboxGroup/config'\nimport { grCodeBlockConfig } from '../components/GrCodeBlock/config'\nimport { grCollapseConfig } from '../components/GrCollapse/config'\nimport { grColorPickerConfig } from '../components/GrColorPicker/config'\nimport { grCommandPaletteConfig } from '../components/GrCommandPalette/config'\nimport { grConfigProviderConfig } from '../components/GrConfigProvider/config'\nimport { grConfirmDialogConfig } from '../components/GrConfirmDialog/config'\nimport { grDataTableConfig } from '../components/GrDataTable/config'\nimport { grDeltaConfig } from '../components/GrDelta/config'\nimport { grDescriptionListConfig } from '../components/GrDescriptionList/config'\nimport { grDialogConfig } from '../components/GrDialog/config'\nimport { grDialogServiceConfig } from '../components/GrDialogService/config'\nimport { grDividerConfig } from '../components/GrDivider/config'\nimport { grDrawerConfig } from '../components/GrDrawer/config'\nimport { grDropdownConfig } from '../components/GrDropdown/config'\nimport { grDropdownMenuConfig } from '../components/GrDropdownMenu/config'\nimport { grEmptyStateConfig } from '../components/GrEmptyState/config'\nimport { grFilePreviewConfig } from '../components/GrFilePreview/config'\nimport { grFileUploadConfig } from '../components/GrFileUpload/config'\nimport { grFormConfig } from '../components/GrForm/config'\nimport { grFormFieldConfig } from '../components/GrFormField/config'\nimport { grFormFileConfig } from '../components/GrFormFile/config'\nimport { grFormSectionConfig } from '../components/GrFormSection/config'\nimport { grIconConfig } from '../components/GrIcon/config'\nimport { grImageViewerConfig } from '../components/GrImageViewer/config'\nimport { grInputConfig } from '../components/GrInput/config'\nimport { grInputTagConfig } from '../components/GrInputTag/config'\nimport { grKbdConfig } from '../components/GrKbd/config'\nimport { grLinkConfig } from '../components/GrLink/config'\nimport { grListConfig } from '../components/GrList/config'\nimport { grLoadingConfig } from '../components/GrLoading/config'\nimport { grModalConfig } from '../components/GrModal/config'\nimport { grNavbarConfig } from '../components/GrNavbar/config'\nimport { grNumberInputConfig } from '../components/GrNumberInput/config'\nimport { grPaginationConfig } from '../components/GrPagination/config'\nimport { grPopoverConfig } from '../components/GrPopover/config'\nimport { grProgressBarConfig } from '../components/GrProgressBar/config'\nimport { grProgressCircleConfig } from '../components/GrProgressCircle/config'\nimport { grPromptDialogConfig } from '../components/GrPromptDialog/config'\nimport { grRadioConfig } from '../components/GrRadio/config'\nimport { grRadioGroupConfig } from '../components/GrRadioGroup/config'\nimport { grRatingConfig } from '../components/GrRating/config'\nimport { grResponseErrorBannerConfig } from '../components/GrResponseErrorBanner/config'\nimport { grSegmentedConfig } from '../components/GrSegmented/config'\nimport { grSelectConfig } from '../components/GrSelect/config'\nimport { grSidebarConfig } from '../components/GrSidebar/config'\nimport { grSkeletonConfig } from '../components/GrSkeleton/config'\nimport { grSliderConfig } from '../components/GrSlider/config'\nimport { grSortableListConfig } from '../components/GrSortableList/config'\nimport { grSplitterConfig } from '../components/GrSplitter/config'\nimport { grStatisticConfig } from '../components/GrStatistic/config'\nimport { grSwitchConfig } from '../components/GrSwitch/config'\nimport { grTableConfig } from '../components/GrTable/config'\nimport { grTabPanelsConfig } from '../components/GrTabPanels/config'\nimport { grTabsConfig } from '../components/GrTabs/config'\nimport { grTextareaConfig } from '../components/GrTextarea/config'\nimport { grTimelineConfig } from '../components/GrTimeline/config'\nimport { grToasterConfig } from '../components/GrToaster/config'\nimport { grTooltipConfig } from '../components/GrTooltip/config'\nimport { grTreeConfig } from '../components/GrTree/config'\nimport { grTreeSelectConfig } from '../components/GrTreeSelect/config'\n// </granularity:components:imports>\n\n/** Идентификатор провайдера — совпадает с именем пакета. */\nexport const GRANULARITY_PROVIDER_ID = '@feugene/granularity'\n\n// Не заменять на `new URL('..', import.meta.url)`: Vite и rolldown распознают\n// этот литерал и подставляют `data:`-URL, после чего scan-директории пустеют.\nconst packageBaseUrl = resolvePackageBaseUrl(import.meta.url)\n\n/** Встроенные темы пакета. Единственный источник правды о списке тем. */\nexport const granularityThemeNames = ['light', 'dark'] as const\nexport type GranularityThemeName = (typeof granularityThemeNames)[number]\n\n/** Темы, активные по умолчанию, если окружение не переопределяет выбор. */\nexport const granularityDefaultThemes: readonly GranularityThemeName[] = ['light']\n\nconst theme = {\n baseCssUrl: new URL('../styles/base.css', import.meta.url).href,\n tokensCssUrl: new URL('../styles/tokens.css', import.meta.url).href,\n themes: {\n light: new URL('../styles/themes/light.css', import.meta.url).href,\n dark: new URL('../styles/themes/dark.css', import.meta.url).href,\n },\n defaultThemes: granularityDefaultThemes,\n} as const\n\n/**\n * Реестр публичных компонентов. Ключи совпадают с subpath-экспортом\n * `@feugene/granularity/components/<Name>`.\n */\nexport const granularityComponentConfigs = {\n // <granularity:components:registry> — блок генерируется `yarn generate:registry`\n GrAlert: grAlertConfig,\n GrAutocomplete: grAutocompleteConfig,\n GrAvatar: grAvatarConfig,\n GrBadge: grBadgeConfig,\n GrBadgeWrap: grBadgeWrapConfig,\n GrBottomNav: grBottomNavConfig,\n GrBreadcrumbs: grBreadcrumbsConfig,\n GrButton: grButtonConfig,\n GrButtonGroup: grButtonGroupConfig,\n GrCard: grCardConfig,\n GrCheckbox: grCheckboxConfig,\n GrCheckboxGroup: grCheckboxGroupConfig,\n GrCodeBlock: grCodeBlockConfig,\n GrCollapse: grCollapseConfig,\n GrColorPicker: grColorPickerConfig,\n GrCommandPalette: grCommandPaletteConfig,\n GrConfigProvider: grConfigProviderConfig,\n GrConfirmDialog: grConfirmDialogConfig,\n GrDataTable: grDataTableConfig,\n GrDelta: grDeltaConfig,\n GrDescriptionList: grDescriptionListConfig,\n GrDialog: grDialogConfig,\n GrDialogService: grDialogServiceConfig,\n GrDivider: grDividerConfig,\n GrDrawer: grDrawerConfig,\n GrDropdown: grDropdownConfig,\n GrDropdownMenu: grDropdownMenuConfig,\n GrEmptyState: grEmptyStateConfig,\n GrFilePreview: grFilePreviewConfig,\n GrFileUpload: grFileUploadConfig,\n GrForm: grFormConfig,\n GrFormField: grFormFieldConfig,\n GrFormFile: grFormFileConfig,\n GrFormSection: grFormSectionConfig,\n GrIcon: grIconConfig,\n GrImageViewer: grImageViewerConfig,\n GrInput: grInputConfig,\n GrInputTag: grInputTagConfig,\n GrKbd: grKbdConfig,\n GrLink: grLinkConfig,\n GrList: grListConfig,\n GrLoading: grLoadingConfig,\n GrModal: grModalConfig,\n GrNavbar: grNavbarConfig,\n GrNumberInput: grNumberInputConfig,\n GrPagination: grPaginationConfig,\n GrPopover: grPopoverConfig,\n GrProgressBar: grProgressBarConfig,\n GrProgressCircle: grProgressCircleConfig,\n GrPromptDialog: grPromptDialogConfig,\n GrRadio: grRadioConfig,\n GrRadioGroup: grRadioGroupConfig,\n GrRating: grRatingConfig,\n GrResponseErrorBanner: grResponseErrorBannerConfig,\n GrSegmented: grSegmentedConfig,\n GrSelect: grSelectConfig,\n GrSidebar: grSidebarConfig,\n GrSkeleton: grSkeletonConfig,\n GrSlider: grSliderConfig,\n GrSortableList: grSortableListConfig,\n GrSplitter: grSplitterConfig,\n GrStatistic: grStatisticConfig,\n GrSwitch: grSwitchConfig,\n GrTable: grTableConfig,\n GrTabPanels: grTabPanelsConfig,\n GrTabs: grTabsConfig,\n GrTextarea: grTextareaConfig,\n GrTimeline: grTimelineConfig,\n GrToaster: grToasterConfig,\n GrTooltip: grTooltipConfig,\n GrTree: grTreeConfig,\n GrTreeSelect: grTreeSelectConfig,\n // </granularity:components:registry>\n}\n\nexport type GranularityComponentName = keyof typeof granularityComponentConfigs\n\n/** Базовый набор компонентов в порядке реестра. */\nconst baseComponents: readonly GranularComponentDescriptor[] = Object.values(\n granularityComponentConfigs,\n)\n\n/**\n * Собирает granular-provider пакета.\n *\n * `overrides` — точка расширения для потребителя: дескриптор с именем из\n * базового реестра заменяет его, остальные дописываются в конец.\n */\nexport function createGranularityProvider(\n overrides: readonly GranularComponentDescriptor[] = [],\n): GranularProvider {\n const overrideByName = new Map(\n overrides.map(component => [component.name, component]),\n )\n const components: GranularComponentDescriptor[] = [\n ...baseComponents.map(component => overrideByName.get(component.name) ?? component),\n ...overrides.filter(component => !baseComponents.some(base => base.name === component.name)),\n ]\n\n return defineGranularProvider({\n id: GRANULARITY_PROVIDER_ID,\n contractVersion: 1,\n packageBaseUrl,\n components,\n theme,\n })\n}\n","import { createGranularityProvider } from './shared'\n\nexport * from './shared'\n\nexport const granularityProvider = createGranularityProvider()\n\nexport default granularityProvider\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAa,iBAAiB,wBAAwB,OAAO,KAAK,KAAK;CACrE,MAAM;CACN,cAAc,CAAC,YAAY,SAAS;CACpC,UAAU;AACZ,CAAC;;;ACND,IAAa,8BAA8B,wBAAwB,OAAO,KAAK,KAAK;CAClF,MAAM;CACN,cAAc,CAAC,WAAW,UAAU;AACtC,CAAC;;;;ACsFD,IAAa,0BAA0B;AAIvC,IAAM,iBAAiB,sBAAsB,OAAO,KAAK,GAAG;;AAG5D,IAAa,wBAAwB,CAAC,SAAS,MAAM;;AAIrD,IAAa,2BAA4D,CAAC,OAAO;AAEjF,IAAM,QAAQ;CACZ,YAAY,IAAA,IAAA,q5KAAA,KAAA,OAAA,KAAA,GAAA,CAA8C,CAAC;CAC3D,cAAc,IAAA,IAAA,ykXAAA,KAAA,OAAA,KAAA,GAAA,CAAgD,CAAC;CAC/D,QAAQ;EACN,OAAO,IAAA,IAAA,qjYAAA,KAAA,OAAA,KAAA,GAAA,CAAsD,CAAC;EAC9D,MAAM,IAAA,IAAA,yxSAAA,KAAA,OAAA,KAAA,GAAA,CAAqD,CAAC;CAC9D;CACA,eAAe;AACjB;;;;;AAMA,IAAa,8BAA8B;CAEzC,SAAS;CACT,gBAAgB;CAChB,UAAU;CACV,SAAS;CACT,aAAa;CACb,aAAa;CACb,eAAe;CACf,UAAU;CACV,eAAe;CACf,QAAQ;CACR,YAAY;CACZ,iBAAiB;CACjB,aAAa;CACb,YAAY;CACZ,eAAe;CACf,kBAAkB;CAClB,kBAAkB;CAClB,iBAAiB;CACjB,aAAa;CACb,SAAS;CACT,mBAAmB;CACnB,UAAU;CACV,iBAAiB;CACjB,WAAW;CACX,UAAU;CACV,YAAY;CACZ,gBAAgB;CAChB,cAAc;CACd,eAAe;CACf,cAAc;CACd,QAAQ;CACR,aAAa;CACb,YAAY;CACZ,eAAe;CACf,QAAQ;CACR,eAAe;CACf,SAAS;CACT,YAAY;CACZ,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,SAAS;CACT,UAAU;CACV,eAAe;CACf,cAAc;CACd,WAAW;CACX,eAAe;CACf,kBAAkB;CAClB,gBAAgB;CAChB,SAAS;CACT,cAAc;CACd,UAAU;CACV,uBAAuB;CACvB,aAAa;CACb,UAAU;CACV,WAAW;CACX,YAAY;CACZ,UAAU;CACV,gBAAgB;CAChB,YAAY;CACZ,aAAa;CACb,UAAU;CACV,SAAS;CACT,aAAa;CACb,QAAQ;CACR,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,WAAW;CACX,QAAQ;CACR,cAAc;AAEhB;;AAKA,IAAM,iBAAyD,OAAO,OACpE,2BACF;;;;;;;AAQA,SAAgB,0BACd,YAAoD,CAAC,GACnC;CAClB,MAAM,iBAAiB,IAAI,IACzB,UAAU,KAAI,cAAa,CAAC,UAAU,MAAM,SAAS,CAAC,CACxD;CAMA,OAAO,uBAAuB;EAC5B,IAAI;EACJ,iBAAiB;EACjB;EACA,aARA,GAAG,eAAe,KAAI,cAAa,eAAe,IAAI,UAAU,IAAI,KAAK,SAAS,GAClF,GAAG,UAAU,QAAO,cAAa,CAAC,eAAe,MAAK,SAAQ,KAAK,SAAS,UAAU,IAAI,CAAC,CAO3F;EACA;CACF,CAAC;AACH;;;AC9NA,IAAa,sBAAsB,0BAA0B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"trending-up-Bf9AQmoq.js","names":[],"sources":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrDelta-BMmpYz8K.js","names":[],"sources":["../../../../src/internal/granularityFormat.ts","../../../../src/components/GrDelta/deltaTone.ts","../../../../src/components/GrDelta/GrDelta.vue","../../../../src/components/GrDelta/GrDelta.vue"],"sourcesContent":["/**\n * Форматирование чисел и дат по локали.\n *\n * Своё, а не из `@feugene/fint-i18n`: тот объявлен **опциональной** peer-зависимостью,\n * и пакет обязан работать без него. Под капотом всё равно `Intl`, то есть\n * результат совпадает с `useI18nFormat()` библиотеки — расхождения между\n * приложением с i18n и без него не возникает.\n *\n * Инстансы `Intl` кэшируются: их построение примерно на порядок дороже самого\n * форматирования. Кэш ограничен и сбрасывается целиком — иначе сгенерированные\n * на лету опции растили бы его без предела.\n */\n\nconst CACHE_LIMIT = 64\n\nconst numberFormats = new Map<string, Intl.NumberFormat>()\nconst dateFormats = new Map<string, Intl.DateTimeFormat>()\n\nfunction cacheKey(locale: string, options?: object): string {\n return options ? `${locale}\u0000${JSON.stringify(options)}` : locale\n}\n\nfunction take<T>(cache: Map<string, T>, key: string, create: () => T): T {\n const cached = cache.get(key)\n if (cached) return cached\n\n const created = create()\n if (cache.size >= CACHE_LIMIT) cache.clear()\n cache.set(key, created)\n\n return created\n}\n\n/**\n * Локаль приходит из настроек приложения, а `Intl` бросает на некорректном\n * теге. Форматирование не имеет права уронить рендер, поэтому неизвестный тег\n * сводим к `en`.\n */\nexport function formatNumber(\n locale: string,\n value: number | bigint,\n options?: Intl.NumberFormatOptions,\n): string {\n try {\n return take(numberFormats, cacheKey(locale, options), () => new Intl.NumberFormat(locale, options)).format(value)\n }\n catch {\n return take(numberFormats, cacheKey('en', options), () => new Intl.NumberFormat('en', options)).format(value)\n }\n}\n\nexport function formatDate(\n locale: string,\n value: Date | number | string,\n options?: Intl.DateTimeFormatOptions,\n): string {\n const date = value instanceof Date ? value : new Date(value)\n\n // Невалидную дату возвращаем как есть: пустая или «Invalid Date» в интерфейсе\n // хуже, чем исходное значение, но лучше, чем исключение на рендере.\n if (Number.isNaN(date.getTime())) return String(value)\n\n try {\n return take(dateFormats, cacheKey(locale, options), () => new Intl.DateTimeFormat(locale, options)).format(date)\n }\n catch {\n return take(dateFormats, cacheKey('en', options), () => new Intl.DateTimeFormat('en', options)).format(date)\n }\n}\n","/**\n * Выбор тона для величины со знаком.\n *\n * Чистая функция, а не `switch` внутри компонента: ровно этот `switch`\n * расходился по приложениям копиями, и в одной из них нулевое движение\n * красилось зелёным — как поступление.\n */\n\n/** Что считать хорошим ростом. */\nexport type GrDeltaPolarity\n /** Рост — успех: выручка, конверсия, число подписок. */\n = | 'positive-good'\n /** Рост — проблема: себестоимость, время отклика, отток. */\n | 'negative-good'\n /** Знак ничего не говорит о качестве: сальдо, смещение, разница координат. */\n | 'none'\n\nexport type GrDeltaTone = 'success' | 'danger' | 'neutral'\n\n/**\n * Тон величины по её знаку и полярности.\n *\n * Ноль нейтрален при любой полярности: «не изменилось» — третье состояние, и\n * двумя цветами его не выразить. `null` величины нет вовсе — тона у неё тоже\n * нет, это решает вызывающий.\n */\nexport function deltaTone(value: number, polarity: GrDeltaPolarity = 'positive-good'): GrDeltaTone {\n if (polarity === 'none' || value === 0 || Number.isNaN(value)) return 'neutral'\n\n const good = polarity === 'positive-good' ? value > 0 : value < 0\n\n return good ? 'success' : 'danger'\n}\n\n/** Направление стрелки. Ноль стрелки не получает: двигаться было некуда. */\nexport function deltaDirection(value: number): 'up' | 'down' | 'flat' {\n if (Number.isNaN(value) || value === 0) return 'flat'\n return value > 0 ? 'up' : 'down'\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { formatNumber } from '../../internal/granularityFormat'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport IconMinus from '~icons/lucide/minus'\nimport IconTrendingDown from '~icons/lucide/trending-down'\nimport IconTrendingUp from '~icons/lucide/trending-up'\n\nimport { deltaDirection, deltaTone, type GrDeltaPolarity, type GrDeltaTone } from './deltaTone'\nimport {\n deltaArrowClass,\n deltaEmptyClass,\n deltaRootClass,\n deltaSizeClass,\n deltaSuffixClass,\n deltaToneClass,\n} from './grDeltaStyles'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nexport type { GrDeltaPolarity, GrDeltaTone } from './deltaTone'\n\n/**\n * Величина со знаком и тоном **внутри строки текста**: «Дельта: +$0.004».\n *\n * Компонент презентационный: дельту не считает и периоды не сравнивает —\n * «к чему сравнивать» знает приложение. Блочная плитка показателя — `GrStatistic`.\n */\nexport interface GrDeltaProps {\n /** Величина. `null` — её нет; это не ноль. */\n value: number | null\n /** Знаков после запятой. Не задано — как отдаст локаль. */\n precision?: number\n /** Приписка перед числом: валюта, единица. */\n prefix?: string\n /** Приписка после числа: `%`, `мс`. */\n suffix?: string\n /**\n * Что считать хорошим. Для выручки рост — успех, для себестоимости и времени\n * отклика — наоборот; без этого компонент врал бы в половине случаев.\n */\n polarity?: GrDeltaPolarity\n /** Ставить `+` у положительных. Минус подставляет `Intl` сам. */\n showSign?: boolean\n /** Стрелка направления. Декоративна: направление уже в знаке. */\n showArrow?: boolean\n /** Чем печатать отсутствующую величину. */\n emptyText?: string\n /** Локаль форматирования. Не задана — локаль i18n-адаптера. */\n locale?: string\n size?: GrComponentSize\n}\n\nconst props = withDefaults(defineProps<GrDeltaProps>(), {\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n precision: undefined,\n prefix: undefined,\n suffix: undefined,\n polarity: undefined,\n showSign: undefined,\n showArrow: undefined,\n emptyText: undefined,\n locale: undefined,\n size: undefined,\n})\n\nconst { locale } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrDelta' })\nconst resolvedLocale = computed(() => props.locale ?? locale.value ?? 'en')\nconst resolvedPolarity = useGrComponentProp('GrDelta', 'polarity', () => props.polarity, 'positive-good')\nconst resolvedShowSign = useGrComponentProp('GrDelta', 'showSign', () => props.showSign, true)\nconst resolvedShowArrow = useGrComponentProp('GrDelta', 'showArrow', () => props.showArrow, false)\nconst resolvedEmptyText = useGrComponentProp('GrDelta', 'emptyText', () => props.emptyText, '—')\n\nconst isEmpty = computed(() => props.value === null || props.value === undefined)\n\nconst tone = computed<GrDeltaTone>(() => (\n isEmpty.value ? 'neutral' : deltaTone(props.value as number, resolvedPolarity.value)\n))\n\nconst direction = computed(() => (isEmpty.value ? 'flat' : deltaDirection(props.value as number)))\n\n/**\n * Знак — префикс форматирования, а не склейка строки. `'+' + value` уже ломало\n * `GrStatistic`: строка `'+10'` разбирается как число, и разряды теряются.\n */\nconst formatted = computed(() => {\n if (isEmpty.value) return resolvedEmptyText.value\n\n return formatNumber(resolvedLocale.value, props.value as number, {\n signDisplay: resolvedShowSign.value ? 'exceptZero' : 'auto',\n ...(props.precision === undefined\n ? {}\n : { minimumFractionDigits: props.precision, maximumFractionDigits: props.precision }),\n })\n})\n\nconst arrowIcon = computed(() => {\n if (direction.value === 'up') return IconTrendingUp\n if (direction.value === 'down') return IconTrendingDown\n return IconMinus\n})\n\nconst rootClass = computed(() => [\n deltaRootClass,\n deltaSizeClass[resolvedSize.value],\n isEmpty.value ? deltaEmptyClass : deltaToneClass[tone.value],\n].filter(Boolean).join(' '))\n</script>\n\n<template>\n <span data-gr-delta :data-tone=\"isEmpty ? undefined : tone\" :class=\"rootClass\">\n <component\n :is=\"arrowIcon\"\n v-if=\"resolvedShowArrow && !isEmpty\"\n data-gr-delta-arrow\n :class=\"deltaArrowClass\"\n aria-hidden=\"true\"\n />\n\n <span v-if=\"prefix && !isEmpty\" data-gr-delta-prefix>{{ prefix }}</span>\n <span data-gr-delta-value>{{ formatted }}</span>\n <span v-if=\"suffix && !isEmpty\" data-gr-delta-suffix :class=\"deltaSuffixClass\">{{ suffix }}</span>\n </span>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { formatNumber } from '../../internal/granularityFormat'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport IconMinus from '~icons/lucide/minus'\nimport IconTrendingDown from '~icons/lucide/trending-down'\nimport IconTrendingUp from '~icons/lucide/trending-up'\n\nimport { deltaDirection, deltaTone, type GrDeltaPolarity, type GrDeltaTone } from './deltaTone'\nimport {\n deltaArrowClass,\n deltaEmptyClass,\n deltaRootClass,\n deltaSizeClass,\n deltaSuffixClass,\n deltaToneClass,\n} from './grDeltaStyles'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nexport type { GrDeltaPolarity, GrDeltaTone } from './deltaTone'\n\n/**\n * Величина со знаком и тоном **внутри строки текста**: «Дельта: +$0.004».\n *\n * Компонент презентационный: дельту не считает и периоды не сравнивает —\n * «к чему сравнивать» знает приложение. Блочная плитка показателя — `GrStatistic`.\n */\nexport interface GrDeltaProps {\n /** Величина. `null` — её нет; это не ноль. */\n value: number | null\n /** Знаков после запятой. Не задано — как отдаст локаль. */\n precision?: number\n /** Приписка перед числом: валюта, единица. */\n prefix?: string\n /** Приписка после числа: `%`, `мс`. */\n suffix?: string\n /**\n * Что считать хорошим. Для выручки рост — успех, для себестоимости и времени\n * отклика — наоборот; без этого компонент врал бы в половине случаев.\n */\n polarity?: GrDeltaPolarity\n /** Ставить `+` у положительных. Минус подставляет `Intl` сам. */\n showSign?: boolean\n /** Стрелка направления. Декоративна: направление уже в знаке. */\n showArrow?: boolean\n /** Чем печатать отсутствующую величину. */\n emptyText?: string\n /** Локаль форматирования. Не задана — локаль i18n-адаптера. */\n locale?: string\n size?: GrComponentSize\n}\n\nconst props = withDefaults(defineProps<GrDeltaProps>(), {\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n precision: undefined,\n prefix: undefined,\n suffix: undefined,\n polarity: undefined,\n showSign: undefined,\n showArrow: undefined,\n emptyText: undefined,\n locale: undefined,\n size: undefined,\n})\n\nconst { locale } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrDelta' })\nconst resolvedLocale = computed(() => props.locale ?? locale.value ?? 'en')\nconst resolvedPolarity = useGrComponentProp('GrDelta', 'polarity', () => props.polarity, 'positive-good')\nconst resolvedShowSign = useGrComponentProp('GrDelta', 'showSign', () => props.showSign, true)\nconst resolvedShowArrow = useGrComponentProp('GrDelta', 'showArrow', () => props.showArrow, false)\nconst resolvedEmptyText = useGrComponentProp('GrDelta', 'emptyText', () => props.emptyText, '—')\n\nconst isEmpty = computed(() => props.value === null || props.value === undefined)\n\nconst tone = computed<GrDeltaTone>(() => (\n isEmpty.value ? 'neutral' : deltaTone(props.value as number, resolvedPolarity.value)\n))\n\nconst direction = computed(() => (isEmpty.value ? 'flat' : deltaDirection(props.value as number)))\n\n/**\n * Знак — префикс форматирования, а не склейка строки. `'+' + value` уже ломало\n * `GrStatistic`: строка `'+10'` разбирается как число, и разряды теряются.\n */\nconst formatted = computed(() => {\n if (isEmpty.value) return resolvedEmptyText.value\n\n return formatNumber(resolvedLocale.value, props.value as number, {\n signDisplay: resolvedShowSign.value ? 'exceptZero' : 'auto',\n ...(props.precision === undefined\n ? {}\n : { minimumFractionDigits: props.precision, maximumFractionDigits: props.precision }),\n })\n})\n\nconst arrowIcon = computed(() => {\n if (direction.value === 'up') return IconTrendingUp\n if (direction.value === 'down') return IconTrendingDown\n return IconMinus\n})\n\nconst rootClass = computed(() => [\n deltaRootClass,\n deltaSizeClass[resolvedSize.value],\n isEmpty.value ? deltaEmptyClass : deltaToneClass[tone.value],\n].filter(Boolean).join(' '))\n</script>\n\n<template>\n <span data-gr-delta :data-tone=\"isEmpty ? undefined : tone\" :class=\"rootClass\">\n <component\n :is=\"arrowIcon\"\n v-if=\"resolvedShowArrow && !isEmpty\"\n data-gr-delta-arrow\n :class=\"deltaArrowClass\"\n aria-hidden=\"true\"\n />\n\n <span v-if=\"prefix && !isEmpty\" data-gr-delta-prefix>{{ prefix }}</span>\n <span data-gr-delta-value>{{ formatted }}</span>\n <span v-if=\"suffix && !isEmpty\" data-gr-delta-suffix :class=\"deltaSuffixClass\">{{ suffix }}</span>\n </span>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAaA,IAAM,cAAc;AAEpB,IAAM,gCAAgB,IAAI,IAA+B;AAGzD,SAAS,SAAS,QAAgB,SAA0B;CAC1D,OAAO,UAAU,GAAG,OAAO,GAAG,KAAK,UAAU,OAAO,MAAM;AAC5D;AAEA,SAAS,KAAQ,OAAuB,KAAa,QAAoB;CACvE,MAAM,SAAS,MAAM,IAAI,GAAG;CAC5B,IAAI,QAAQ,OAAO;CAEnB,MAAM,UAAU,OAAO;CACvB,IAAI,MAAM,QAAQ,aAAa,MAAM,MAAM;CAC3C,MAAM,IAAI,KAAK,OAAO;CAEtB,OAAO;AACT;;;;;;AAOA,SAAgB,aACd,QACA,OACA,SACQ;CACR,IAAI;EACF,OAAO,KAAK,eAAe,SAAS,QAAQ,OAAO,SAAS,IAAI,KAAK,aAAa,QAAQ,OAAO,CAAC,CAAC,CAAC,OAAO,KAAK;CAClH,QACM;EACJ,OAAO,KAAK,eAAe,SAAS,MAAM,OAAO,SAAS,IAAI,KAAK,aAAa,MAAM,OAAO,CAAC,CAAC,CAAC,OAAO,KAAK;CAC9G;AACF;;;;;;;;;;ACvBA,SAAgB,UAAU,OAAe,WAA4B,iBAA8B;CACjG,IAAI,aAAa,UAAU,UAAU,KAAK,OAAO,MAAM,KAAK,GAAG,OAAO;CAItE,QAFa,aAAa,kBAAkB,QAAQ,IAAI,QAAQ,KAElD,YAAY;AAC5B;;AAGA,SAAgB,eAAe,OAAuC;CACpE,IAAI,OAAO,MAAM,KAAK,KAAK,UAAU,GAAG,OAAO;CAC/C,OAAO,QAAQ,IAAI,OAAO;AAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECkBA,MAAM,QAAQ;EAcd,MAAM,EAAE,WAAW,2BAA2B;EAE9C,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,UAAU,CAAC;EAClF,MAAM,iBAAiB,eAAe,MAAM,UAAU,OAAO,SAAS,IAAI;EAC1E,MAAM,mBAAmB,mBAAmB,WAAW,kBAAkB,MAAM,UAAU,eAAe;EACxG,MAAM,mBAAmB,mBAAmB,WAAW,kBAAkB,MAAM,UAAU,IAAI;EAC7F,MAAM,oBAAoB,mBAAmB,WAAW,mBAAmB,MAAM,WAAW,KAAK;EACjG,MAAM,oBAAoB,mBAAmB,WAAW,mBAAmB,MAAM,WAAW,GAAG;EAE/F,MAAM,UAAU,eAAe,MAAM,UAAU,QAAQ,MAAM,UAAU,KAAA,CAAS;EAEhF,MAAM,OAAO,eACX,QAAQ,QAAQ,YAAY,UAAU,MAAM,OAAiB,iBAAiB,KAAK,CACpF;EAED,MAAM,YAAY,eAAgB,QAAQ,QAAQ,SAAS,eAAe,MAAM,KAAe,CAAE;;;;;EAMjG,MAAM,YAAY,eAAe;GAC/B,IAAI,QAAQ,OAAO,OAAO,kBAAkB;GAE5C,OAAO,aAAa,eAAe,OAAO,MAAM,OAAiB;IAC/D,aAAa,iBAAiB,QAAQ,eAAe;IACrD,GAAI,MAAM,cAAc,KAAA,IACpB,CAAC,IACD;KAAE,uBAAuB,MAAM;KAAW,uBAAuB,MAAM;IAAU;GACvF,CAAC;EACH,CAAC;EAED,MAAM,YAAY,eAAe;GAC/B,IAAI,UAAU,UAAU,MAAM,OAAO;GACrC,IAAI,UAAU,UAAU,QAAQ,OAAO;GACvC,OAAO;EACT,CAAC;EAED,MAAM,YAAY,eAAe;GAC/B;GACA,eAAe,aAAa;GAC5B,QAAQ,QAAQ,kBAAkB,eAAe,KAAK;EACxD,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;;uBAIzB,mBAYO,QAAA;IAZD,iBAAA;IAAe,aAAW,QAAA,QAAU,KAAA,IAAY,KAAA;IAAO,OAAK,eAAE,UAAA,KAAS;;IAGnE,MAAA,iBAAA,KAAiB,CAAK,QAAA,SAAA,UAAA,GAF9B,YAME,wBALK,UAAA,KAAS,GAAA;;KAEd,uBAAA;KACC,OAAK,eAAE,MAAA,eAAA,CAAe;KACvB,eAAY;;IAGF,QAAA,UAAM,CAAK,QAAA,SAAA,UAAA,GAAvB,mBAAwE,QAAxE,YAAwE,gBAAhB,QAAA,MAAM,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;IAC9D,mBAAgD,QAAhD,YAAgD,gBAAnB,UAAA,KAAS,GAAA,CAAA;IAC1B,QAAA,UAAM,CAAK,QAAA,SAAA,UAAA,GAAvB,mBAAkG,QAAA;;KAAlE,wBAAA;KAAsB,OAAK,eAAE,MAAA,gBAAA,CAAgB;uBAAK,QAAA,MAAM,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrDescriptionList-pXh1LZEe.js","names":[],"sources":["../../../../src/components/GrDescriptionList/GrDescriptionList.vue","../../../../src/components/GrDescriptionList/GrDescriptionList.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, useSlots } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport {\n descriptionColumnsClass,\n descriptionDensityClass,\n descriptionDividedClass,\n descriptionLabelInlineClass,\n descriptionLabelStackedClass,\n descriptionPairInlineClass,\n descriptionPairStackedClass,\n descriptionRootClass,\n descriptionSizeClass,\n descriptionValueClass,\n descriptionValueToneClass,\n type GrDescriptionColumns,\n type GrDescriptionDensity,\n type GrDescriptionLayout,\n} from './grDescriptionListStyles'\n\nimport type { GrComponentSize } from '../shared/sizes'\nimport type { GrTone } from '../shared/tones'\n\nexport type {\n GrDescriptionColumns,\n GrDescriptionDensity,\n GrDescriptionLayout,\n} from './grDescriptionListStyles'\n\nexport interface GrDescriptionItem {\n label: string\n /** Значение. `null` и `''` печатаются прочерком — строка не исчезает. */\n value?: string | number | null\n /** Ключ слотов `#value-<name>` и `#label-<name>`. */\n name?: string\n /** Тон значения. Подпись остаётся нейтральной всегда. */\n tone?: GrTone\n}\n\n/**\n * Список пар «характеристика → значение»: настоящий `<dl>` с выравниванием\n * значений в колонку.\n *\n * В отличие от `GrList`, где пункт — это «заголовок с подзаголовком», здесь\n * два разных по роли элемента: термин и его значение.\n */\nexport interface GrDescriptionListProps {\n items: readonly GrDescriptionItem[]\n /** `inline` — подпись слева колонкой; `stacked` — над значением. */\n layout?: GrDescriptionLayout\n /** Ширина колонки подписей при `inline`. */\n labelWidth?: string\n /**\n * Ниже какой ширины контейнера (px) `inline` переключается на `stacked`.\n * В узкой колонке фиксированная подпись выжимает значение в букву на строку.\n */\n stackBelow?: number\n density?: GrDescriptionDensity\n /** Отбивать пары линиями. */\n divided?: boolean\n columns?: GrDescriptionColumns\n /** Чем печатать пустое значение. */\n emptyText?: string\n size?: GrComponentSize\n}\n\nconst props = withDefaults(defineProps<GrDescriptionListProps>(), {\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n layout: undefined,\n labelWidth: undefined,\n stackBelow: undefined,\n density: undefined,\n divided: undefined,\n columns: undefined,\n emptyText: undefined,\n size: undefined,\n})\n\nconst slots = useSlots()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrDescriptionList' })\nconst resolvedLayout = useGrComponentProp('GrDescriptionList', 'layout', () => props.layout, 'inline')\nconst resolvedDensity = useGrComponentProp('GrDescriptionList', 'density', () => props.density, 'regular')\nconst resolvedDivided = useGrComponentProp('GrDescriptionList', 'divided', () => props.divided, false)\nconst resolvedColumns = useGrComponentProp('GrDescriptionList', 'columns', () => props.columns, 1)\nconst resolvedLabelWidth = useGrComponentProp('GrDescriptionList', 'labelWidth', () => props.labelWidth, '11rem')\nconst resolvedEmptyText = useGrComponentProp('GrDescriptionList', 'emptyText', () => props.emptyText, '—')\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst narrow = ref(false)\n\n/**\n * `stackBelow` меряет контейнер, а не вьюпорт: пары живут и в узкой карточке\n * на широком экране. Container query здесь не подходит — порог приходит числом\n * в пропе, а `var()` в условии запроса не работает.\n */\nlet observer: ResizeObserver | null = null\n\nonMounted(() => {\n if (props.stackBelow === undefined || typeof ResizeObserver === 'undefined') return\n\n observer = new ResizeObserver(([entry]) => {\n narrow.value = entry.contentRect.width < (props.stackBelow as number)\n })\n if (rootEl.value) observer.observe(rootEl.value)\n})\n\nonBeforeUnmount(() => {\n observer?.disconnect()\n observer = null\n})\n\n// До монтирования действует заданная раскладка — это же и есть серверный рендер.\nconst effectiveLayout = computed<GrDescriptionLayout>(() => (\n narrow.value ? 'stacked' : resolvedLayout.value\n))\n\nconst isInline = computed(() => effectiveLayout.value === 'inline')\n\nconst rootClass = computed(() => [\n descriptionRootClass,\n descriptionColumnsClass[resolvedColumns.value],\n descriptionSizeClass[resolvedSize.value],\n descriptionDensityClass[resolvedDensity.value],\n].filter(Boolean).join(' '))\n\nconst pairClass = computed(() => [\n isInline.value ? descriptionPairInlineClass : descriptionPairStackedClass,\n resolvedDivided.value ? descriptionDividedClass : '',\n].filter(Boolean).join(' '))\n\nconst labelClass = computed(() => (\n isInline.value ? descriptionLabelInlineClass : descriptionLabelStackedClass\n))\n\nconst labelStyle = computed(() => (isInline.value ? { width: resolvedLabelWidth.value } : undefined))\n\n/**\n * Пустое значение печатается прочерком, а не пропускается: «поле есть, значения\n * нет» и «поля нет» — разные утверждения, и выпавшая строка ломает и\n * выравнивание, и чтение.\n */\nfunction isEmptyValue(item: GrDescriptionItem): boolean {\n return item.value === null || item.value === undefined || item.value === ''\n}\n\nfunction valueClass(item: GrDescriptionItem): string {\n return [\n descriptionValueClass,\n item.tone ? descriptionValueToneClass[item.tone] : '',\n ].filter(Boolean).join(' ')\n}\n\nfunction pairKey(item: GrDescriptionItem, index: number): string {\n return item.name ?? `${item.label}-${index}`\n}\n\nfunction hasSlot(name: string): boolean {\n return Boolean(slots[name])\n}\n</script>\n\n<template>\n <dl ref=\"rootEl\" data-gr-description-list :class=\"rootClass\">\n <!-- Пара оборачивается в `<div>`: `dl > div > dt + dd` валиден по HTML5 и\n нужен для раскладки. Голые `<div>` вместо `dt`/`dd` — то, ради чего\n компонент и заводится. -->\n <div\n v-for=\"(item, index) in items\"\n :key=\"pairKey(item, index)\"\n data-gr-description-pair\n :class=\"pairClass\"\n >\n <dt data-gr-description-label :class=\"labelClass\" :style=\"labelStyle\">\n <slot v-if=\"item.name && hasSlot(`label-${item.name}`)\" :name=\"`label-${item.name}`\" :item=\"item\" />\n <template v-else>\n {{ item.label }}\n </template>\n </dt>\n\n <dd data-gr-description-value :class=\"valueClass(item)\">\n <slot v-if=\"item.name && hasSlot(`value-${item.name}`)\" :name=\"`value-${item.name}`\" :item=\"item\" />\n <template v-else-if=\"isEmptyValue(item)\">\n <slot name=\"empty\" :item=\"item\">\n {{ resolvedEmptyText }}\n </slot>\n </template>\n <template v-else>\n {{ item.value }}\n </template>\n </dd>\n </div>\n </dl>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, useSlots } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport {\n descriptionColumnsClass,\n descriptionDensityClass,\n descriptionDividedClass,\n descriptionLabelInlineClass,\n descriptionLabelStackedClass,\n descriptionPairInlineClass,\n descriptionPairStackedClass,\n descriptionRootClass,\n descriptionSizeClass,\n descriptionValueClass,\n descriptionValueToneClass,\n type GrDescriptionColumns,\n type GrDescriptionDensity,\n type GrDescriptionLayout,\n} from './grDescriptionListStyles'\n\nimport type { GrComponentSize } from '../shared/sizes'\nimport type { GrTone } from '../shared/tones'\n\nexport type {\n GrDescriptionColumns,\n GrDescriptionDensity,\n GrDescriptionLayout,\n} from './grDescriptionListStyles'\n\nexport interface GrDescriptionItem {\n label: string\n /** Значение. `null` и `''` печатаются прочерком — строка не исчезает. */\n value?: string | number | null\n /** Ключ слотов `#value-<name>` и `#label-<name>`. */\n name?: string\n /** Тон значения. Подпись остаётся нейтральной всегда. */\n tone?: GrTone\n}\n\n/**\n * Список пар «характеристика → значение»: настоящий `<dl>` с выравниванием\n * значений в колонку.\n *\n * В отличие от `GrList`, где пункт — это «заголовок с подзаголовком», здесь\n * два разных по роли элемента: термин и его значение.\n */\nexport interface GrDescriptionListProps {\n items: readonly GrDescriptionItem[]\n /** `inline` — подпись слева колонкой; `stacked` — над значением. */\n layout?: GrDescriptionLayout\n /** Ширина колонки подписей при `inline`. */\n labelWidth?: string\n /**\n * Ниже какой ширины контейнера (px) `inline` переключается на `stacked`.\n * В узкой колонке фиксированная подпись выжимает значение в букву на строку.\n */\n stackBelow?: number\n density?: GrDescriptionDensity\n /** Отбивать пары линиями. */\n divided?: boolean\n columns?: GrDescriptionColumns\n /** Чем печатать пустое значение. */\n emptyText?: string\n size?: GrComponentSize\n}\n\nconst props = withDefaults(defineProps<GrDescriptionListProps>(), {\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n layout: undefined,\n labelWidth: undefined,\n stackBelow: undefined,\n density: undefined,\n divided: undefined,\n columns: undefined,\n emptyText: undefined,\n size: undefined,\n})\n\nconst slots = useSlots()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrDescriptionList' })\nconst resolvedLayout = useGrComponentProp('GrDescriptionList', 'layout', () => props.layout, 'inline')\nconst resolvedDensity = useGrComponentProp('GrDescriptionList', 'density', () => props.density, 'regular')\nconst resolvedDivided = useGrComponentProp('GrDescriptionList', 'divided', () => props.divided, false)\nconst resolvedColumns = useGrComponentProp('GrDescriptionList', 'columns', () => props.columns, 1)\nconst resolvedLabelWidth = useGrComponentProp('GrDescriptionList', 'labelWidth', () => props.labelWidth, '11rem')\nconst resolvedEmptyText = useGrComponentProp('GrDescriptionList', 'emptyText', () => props.emptyText, '—')\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst narrow = ref(false)\n\n/**\n * `stackBelow` меряет контейнер, а не вьюпорт: пары живут и в узкой карточке\n * на широком экране. Container query здесь не подходит — порог приходит числом\n * в пропе, а `var()` в условии запроса не работает.\n */\nlet observer: ResizeObserver | null = null\n\nonMounted(() => {\n if (props.stackBelow === undefined || typeof ResizeObserver === 'undefined') return\n\n observer = new ResizeObserver(([entry]) => {\n narrow.value = entry.contentRect.width < (props.stackBelow as number)\n })\n if (rootEl.value) observer.observe(rootEl.value)\n})\n\nonBeforeUnmount(() => {\n observer?.disconnect()\n observer = null\n})\n\n// До монтирования действует заданная раскладка — это же и есть серверный рендер.\nconst effectiveLayout = computed<GrDescriptionLayout>(() => (\n narrow.value ? 'stacked' : resolvedLayout.value\n))\n\nconst isInline = computed(() => effectiveLayout.value === 'inline')\n\nconst rootClass = computed(() => [\n descriptionRootClass,\n descriptionColumnsClass[resolvedColumns.value],\n descriptionSizeClass[resolvedSize.value],\n descriptionDensityClass[resolvedDensity.value],\n].filter(Boolean).join(' '))\n\nconst pairClass = computed(() => [\n isInline.value ? descriptionPairInlineClass : descriptionPairStackedClass,\n resolvedDivided.value ? descriptionDividedClass : '',\n].filter(Boolean).join(' '))\n\nconst labelClass = computed(() => (\n isInline.value ? descriptionLabelInlineClass : descriptionLabelStackedClass\n))\n\nconst labelStyle = computed(() => (isInline.value ? { width: resolvedLabelWidth.value } : undefined))\n\n/**\n * Пустое значение печатается прочерком, а не пропускается: «поле есть, значения\n * нет» и «поля нет» — разные утверждения, и выпавшая строка ломает и\n * выравнивание, и чтение.\n */\nfunction isEmptyValue(item: GrDescriptionItem): boolean {\n return item.value === null || item.value === undefined || item.value === ''\n}\n\nfunction valueClass(item: GrDescriptionItem): string {\n return [\n descriptionValueClass,\n item.tone ? descriptionValueToneClass[item.tone] : '',\n ].filter(Boolean).join(' ')\n}\n\nfunction pairKey(item: GrDescriptionItem, index: number): string {\n return item.name ?? `${item.label}-${index}`\n}\n\nfunction hasSlot(name: string): boolean {\n return Boolean(slots[name])\n}\n</script>\n\n<template>\n <dl ref=\"rootEl\" data-gr-description-list :class=\"rootClass\">\n <!-- Пара оборачивается в `<div>`: `dl > div > dt + dd` валиден по HTML5 и\n нужен для раскладки. Голые `<div>` вместо `dt`/`dd` — то, ради чего\n компонент и заводится. -->\n <div\n v-for=\"(item, index) in items\"\n :key=\"pairKey(item, index)\"\n data-gr-description-pair\n :class=\"pairClass\"\n >\n <dt data-gr-description-label :class=\"labelClass\" :style=\"labelStyle\">\n <slot v-if=\"item.name && hasSlot(`label-${item.name}`)\" :name=\"`label-${item.name}`\" :item=\"item\" />\n <template v-else>\n {{ item.label }}\n </template>\n </dt>\n\n <dd data-gr-description-value :class=\"valueClass(item)\">\n <slot v-if=\"item.name && hasSlot(`value-${item.name}`)\" :name=\"`value-${item.name}`\" :item=\"item\" />\n <template v-else-if=\"isEmptyValue(item)\">\n <slot name=\"empty\" :item=\"item\">\n {{ resolvedEmptyText }}\n </slot>\n </template>\n <template v-else>\n {{ item.value }}\n </template>\n </dd>\n </div>\n </dl>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAoEA,MAAM,QAAQ;EAad,MAAM,QAAQ,SAAS;EAEvB,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,oBAAoB,CAAC;EAC5F,MAAM,iBAAiB,mBAAmB,qBAAqB,gBAAgB,MAAM,QAAQ,QAAQ;EACrG,MAAM,kBAAkB,mBAAmB,qBAAqB,iBAAiB,MAAM,SAAS,SAAS;EACzG,MAAM,kBAAkB,mBAAmB,qBAAqB,iBAAiB,MAAM,SAAS,KAAK;EACrG,MAAM,kBAAkB,mBAAmB,qBAAqB,iBAAiB,MAAM,SAAS,CAAC;EACjG,MAAM,qBAAqB,mBAAmB,qBAAqB,oBAAoB,MAAM,YAAY,OAAO;EAChH,MAAM,oBAAoB,mBAAmB,qBAAqB,mBAAmB,MAAM,WAAW,GAAG;EAEzG,MAAM,SAAS,IAAwB,IAAI;EAC3C,MAAM,SAAS,IAAI,KAAK;;;;;;EAOxB,IAAI,WAAkC;EAEtC,gBAAgB;GACd,IAAI,MAAM,eAAe,KAAA,KAAa,OAAO,mBAAmB,aAAa;GAE7E,WAAW,IAAI,gBAAgB,CAAC,WAAW;IACzC,OAAO,QAAQ,MAAM,YAAY,QAAS,MAAM;GAClD,CAAC;GACD,IAAI,OAAO,OAAO,SAAS,QAAQ,OAAO,KAAK;EACjD,CAAC;EAED,sBAAsB;GACpB,UAAU,WAAW;GACrB,WAAW;EACb,CAAC;EAGD,MAAM,kBAAkB,eACtB,OAAO,QAAQ,YAAY,eAAe,KAC3C;EAED,MAAM,WAAW,eAAe,gBAAgB,UAAU,QAAQ;EAElE,MAAM,YAAY,eAAe;GAC/B;GACA,wBAAwB,gBAAgB;GACxC,qBAAqB,aAAa;GAClC,wBAAwB,gBAAgB;EAC1C,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;EAE3B,MAAM,YAAY,eAAe,CAC/B,SAAS,QAAQ,6BAA6B,6BAC9C,gBAAgB,QAAQ,0BAA0B,EACpD,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;EAE3B,MAAM,aAAa,eACjB,SAAS,QAAQ,8BAA8B,4BAChD;EAED,MAAM,aAAa,eAAgB,SAAS,QAAQ,EAAE,OAAO,mBAAmB,MAAM,IAAI,KAAA,CAAU;;;;;;EAOpG,SAAS,aAAa,MAAkC;GACtD,OAAO,KAAK,UAAU,QAAQ,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU;EAC3E;EAEA,SAAS,WAAW,MAAiC;GACnD,OAAO,CACL,uBACA,KAAK,OAAO,0BAA0B,KAAK,QAAQ,EACrD,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAC5B;EAEA,SAAS,QAAQ,MAAyB,OAAuB;GAC/D,OAAO,KAAK,QAAQ,GAAG,KAAK,MAAM,GAAG;EACvC;EAEA,SAAS,QAAQ,MAAuB;GACtC,OAAO,QAAQ,MAAM,KAAK;EAC5B;;uBAIE,mBA6BK,MAAA;aA7BG;IAAJ,KAAI;IAAS,4BAAA;IAA0B,OAAK,eAAE,UAAA,KAAS;yBAIzD,mBAwBM,UAAA,MAAA,WAvBoB,QAAA,QAAhB,MAAM,UAAK;wBADrB,mBAwBM,OAAA;KAtBH,KAAK,QAAQ,MAAM,KAAK;KACzB,4BAAA;KACC,OAAK,eAAE,UAAA,KAAS;QAEjB,mBAKK,MAAA;KALD,6BAAA;KAA2B,OAAK,eAAE,WAAA,KAAU;KAAG,OAAK,eAAE,WAAA,KAAU;QACtD,KAAK,QAAQ,QAAO,SAAU,KAAK,MAAI,IAAnD,WAAoG,KAAA,QAAA,SAA5B,KAAK,QAAI,EAAW,KAAI,GAAA,KAAA,GAAA,KAAA,GAAA,CAAA,KAAA,UAAA,GAChG,mBAEW,UAAA,EAAA,KAAA,EAAA,GAAA,CAAA,gBAAA,gBADN,KAAK,KAAK,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,GAAA,CAAA,GAIjB,mBAUK,MAAA;KAVD,6BAAA;KAA2B,OAAK,eAAE,WAAW,IAAI,CAAA;QACvC,KAAK,QAAQ,QAAO,SAAU,KAAK,MAAI,IAAnD,WAAoG,KAAA,QAAA,SAA5B,KAAK,QAAI,EAAW,KAAI,GAAA,KAAA,GAAA,KAAA,GAAA,CAAA,IAC3E,aAAa,IAAI,IACpC,WAEO,KAAA,QAAA,SAAA,EAFmB,KAAI,SAEvB,CAAA,gBAAA,gBADF,MAAA,iBAAA,CAAiB,GAAA,CAAA,CAAA,GAAA,KAAA,GAAA,CAAA,KAAA,UAAA,GAGxB,mBAEW,UAAA,EAAA,KAAA,EAAA,GAAA,CAAA,gBAAA,gBADN,KAAK,KAAK,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,GAAA,CAAA,CAAA,GAAA,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrList-BUzFRa8-.js","names":["$slots"],"sources":["../../../../src/components/GrList/GrList.vue","../../../../src/components/GrList/GrList.vue","../../../../src/components/GrList/GrListItem.vue","../../../../src/components/GrList/GrListItem.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T = unknown\">\nimport { computed, onMounted, onUpdated, ref, useSlots, watch } from 'vue'\n\nimport GrCard from '../GrCard'\nimport type { GrCardVariant } from '../GrCard/grCardStyles'\nimport GrSkeleton from '../GrSkeleton/GrSkeleton.vue'\nimport { hasMeaningfulSlotContent } from '../shared/slotNodes'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useVirtualList, type GrVirtualAlign } from '../../composables/useVirtualList'\n\nimport { dividedClass, emptyClass, loadingRowClass } from './grListStyles'\n\nexport interface GrListProps<TItem = unknown> {\n /**\n * Поверхность списка — вариант карточки под ним. `ghost` убирает рамку и\n * тень: список внутри уже существующей карточки не должен давать вторую.\n */\n variant?: GrCardVariant\n /** Показывать ли горизонтальные разделители между элементами (по умолчанию — да). */\n divided?: boolean\n /** Идёт загрузка: вместо пунктов — строки-скелетоны, контейнер помечен `aria-busy`. */\n loading?: boolean\n /** Сколько строк-заглушек показать при `loading`. */\n loadingRows?: number\n /**\n * Список пуст. По умолчанию определяется сам — по содержимому слота; проп\n * нужен там, где потребитель знает лучше (например, слот заполнен\n * заголовками групп, а данных в них нет).\n */\n empty?: boolean\n /** Текст пустого состояния. Слот `#empty` сильнее. */\n emptyText?: string\n /**\n * Данные списка. С ними пункты рисует слот `#item`, а не слот по умолчанию, —\n * и только так список знает размер набора, то есть может его виртуализировать.\n */\n items?: TItem[]\n /** Ключ пункта для `v-for`: имя поля или функция. Без него — индекс. */\n itemKey?: string | ((item: TItem, index: number) => string | number)\n /** Высота видимой части: контейнер становится скроллером. Число — пиксели. */\n maxHeight?: number | string\n /** Держать в DOM только окно вокруг вьюпорта. Требует `items` и `maxHeight`. */\n virtual?: boolean\n /** Оценка высоты пункта до замера. Уточняется по факту при первом рендере. */\n estimatedItemSize?: number\n}\n\nconst props = withDefaults(defineProps<GrListProps<T>>(), {\n // Дефолт живёт в `GrCard` (и его резолвере `GrConfigProvider`), поэтому здесь\n // остаётся `undefined` — иначе список перебивал бы настройку карточки.\n variant: undefined,\n divided: true,\n loading: false,\n loadingRows: 3,\n empty: undefined,\n emptyText: undefined,\n items: undefined,\n itemKey: undefined,\n maxHeight: undefined,\n virtual: false,\n // Строка обычной плотности с заголовком и описанием.\n estimatedItemSize: 56,\n})\n\nconst slots = useSlots()\nconst { t } = useGranularityTranslations()\n\nconst listEl = ref<HTMLElement | null>(null)\n\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.list.empty', 'Nothing here yet'))\n\nconst dataMode = computed(() => props.items !== undefined)\n\n// Пустоту видно по слоту: `v-for` по пустому массиву оставляет фрагмент без\n// узлов, `v-if` — комментарий, и ни то ни другое пунктом списка не является.\nconst isEmpty = computed(() => {\n if (props.empty !== undefined)\n return props.empty\n\n if (dataMode.value)\n return props.items!.length === 0\n\n return !hasMeaningfulSlotContent(slots.default?.() ?? [])\n})\n\nconst showItems = computed(() => !props.loading && !isEmpty.value)\n\n// Разделители нужны только между пунктами: в пустой и загрузочной ветках они\n// оставили бы висящую линию.\nconst listClass = computed(() => (props.divided && showItems.value ? dividedClass : undefined))\n\nconst loadingRowCount = computed(() => Math.max(1, Math.trunc(props.loadingRows)))\n\nconst virtualEnabled = computed(() => props.virtual && dataMode.value && props.maxHeight !== undefined)\n\nconst virtualizer = useVirtualList({\n container: listEl,\n count: () => (virtualEnabled.value && showItems.value ? props.items!.length : 0),\n // Замена массива сбрасывает замеры; append в тот же массив их сохраняет.\n source: () => props.items,\n itemSize: () => props.estimatedItemSize,\n // Первый рендер обязан совпасть с серверным: контейнера ещё нет, и окно\n // считается от объявленной высоты, а не от измеренной.\n viewportSize: () => (typeof props.maxHeight === 'number' ? props.maxHeight : undefined),\n})\n\n/** Окно к отрисовке: при выключенной виртуализации — весь набор. */\nconst renderedItems = computed(() => {\n const items = props.items ?? []\n if (!virtualEnabled.value) return items.map((item, index) => ({ item, index }))\n\n const { start, end } = virtualizer.range.value\n return items.slice(start, end).map((item, offset) => ({ item, index: start + offset }))\n})\n\nfunction keyOf(item: T, index: number): string | number {\n const key = props.itemKey\n if (typeof key === 'function') return key(item, index)\n if (typeof key === 'string') return (item as Record<string, unknown>)[key] as string | number\n\n return index\n}\n\n/**\n * ARIA-набор для пункта.\n *\n * Только в виртуальном режиме: в DOM тогда неполный набор, и без этих атрибутов\n * диктор объявил бы «7 из 20» на списке в пять тысяч. Когда набор в DOM целиком,\n * его размер и позицию браузер считает сам, а руками проставленные атрибуты\n * начинают расходиться с разметкой при любой фильтрации.\n */\nfunction ariaOf(index: number): Record<string, number> {\n if (!virtualEnabled.value) return {}\n\n return { 'aria-setsize': props.items!.length, 'aria-posinset': index + 1 }\n}\n\nconst maxHeightStyle = computed(() => {\n const value = props.maxHeight\n if (value == null) return undefined\n return typeof value === 'number' ? `${value}px` : value\n})\n\nconst listStyle = computed(() => {\n if (props.maxHeight === undefined) return undefined\n\n const scroller = { overflowY: 'auto' as const, maxHeight: maxHeightStyle.value }\n if (!virtualEnabled.value) return scroller\n\n return { ...scroller, ...virtualizer.spacerStyle.value }\n})\n\n/**\n * Замер отрисованных пунктов.\n *\n * Идёт по детям контейнера, а не по `ref` на элементе: пункт рисует слот\n * потребителя, привязать к нему `ref` неоткуда. В виртуальном режиме прямые\n * дети контейнера — ровно окно (распорки живут псевдоэлементами и детьми не\n * считаются), поэтому сопоставление по позиции однозначно.\n */\nfunction measureRendered(): void {\n if (!virtualEnabled.value) return\n // В состояниях loading/empty дети контейнера — скелетоны и заглушки: их\n // высоты записались бы в замеры под индексами будущих строк данных.\n if (!showItems.value) return\n\n const container = listEl.value\n if (!container) return\n\n const { start } = virtualizer.range.value\n const children = container.children\n for (let offset = 0; offset < children.length; offset++) {\n virtualizer.measure(start + offset, children[offset])\n }\n}\n\nonMounted(measureRendered)\nonUpdated(measureRendered)\n\nfunction scrollToIndex(index: number, align?: GrVirtualAlign): void {\n virtualizer.scrollToIndex(index, align)\n}\n\ndefineExpose({ scrollToIndex })\n\nif (import.meta.env?.DEV) {\n watch(\n () => [props.virtual, dataMode.value, props.maxHeight] as const,\n ([virtual, hasItems, maxHeight]) => {\n if (!virtual) return\n\n if (!hasItems) {\n console.warn(\n '[granularity] GrList: `virtual` требует `items` — пункты из слота по умолчанию '\n + 'список не считает и резать окно ему не из чего.',\n )\n }\n else if (maxHeight === undefined) {\n console.warn(\n '[granularity] GrList: `virtual` требует `maxHeight` — без ограничения высоты '\n + 'вьюпорта нет, и в окно попадает весь набор.',\n )\n }\n },\n { immediate: true },\n )\n\n watch(\n () => [dataMode.value, Boolean(slots.item)] as const,\n ([hasItems, hasSlot]) => {\n if (hasItems && !hasSlot) {\n console.warn(\n '[granularity] GrList: с `items` пункты рисует слот `#item` — без него список пуст.',\n )\n }\n },\n { immediate: true },\n )\n\n onMounted(() => {\n if (!virtualEnabled.value) return\n\n const first = listEl.value?.firstElementChild\n if (first && !first.hasAttribute('aria-posinset')) {\n console.warn(\n '[granularity] GrList: при `virtual` пункты обязаны нести `aria-setsize`/`aria-posinset` — '\n + 'пробросьте `aria` из слота `#item`: <GrListItem v-bind=\"aria\" … />. Иначе диктор '\n + 'посчитает набор по отрисованному окну.',\n )\n }\n })\n}\n</script>\n\n<template>\n <GrCard :variant=\"variant\">\n <div\n ref=\"listEl\"\n data-gr-list\n role=\"list\"\n :class=\"listClass\"\n :style=\"listStyle\"\n :tabindex=\"maxHeight === undefined ? undefined : 0\"\n :data-gr-virtual=\"virtualEnabled ? '' : undefined\"\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <template v-if=\"loading\">\n <slot name=\"loading\">\n <div\n v-for=\"row in loadingRowCount\"\n :key=\"row\"\n data-gr-list-loading-row\n :class=\"loadingRowClass\"\n >\n <GrSkeleton />\n </div>\n </slot>\n </template>\n\n <div\n v-else-if=\"isEmpty\"\n data-gr-list-empty\n :class=\"emptyClass\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <template v-else-if=\"dataMode\">\n <template\n v-for=\"entry in renderedItems\"\n :key=\"keyOf(entry.item, entry.index)\"\n >\n <slot\n name=\"item\"\n :item=\"entry.item\"\n :index=\"entry.index\"\n :aria=\"ariaOf(entry.index)\"\n />\n </template>\n </template>\n\n <slot v-else />\n </div>\n </GrCard>\n</template>\n\n<style scoped>\n/* Срезанное сверху и снизу держат псевдоэлементы контейнера: их не за что\n размонтировать, в дереве доступности их нет, а высота приезжает переменными\n в том же патче, что и пункты. Почему не отступы контейнера и не поля крайних\n пунктов — `docs/virtual-list.md`. */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n</style>\n","<script setup lang=\"ts\" generic=\"T = unknown\">\nimport { computed, onMounted, onUpdated, ref, useSlots, watch } from 'vue'\n\nimport GrCard from '../GrCard'\nimport type { GrCardVariant } from '../GrCard/grCardStyles'\nimport GrSkeleton from '../GrSkeleton/GrSkeleton.vue'\nimport { hasMeaningfulSlotContent } from '../shared/slotNodes'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useVirtualList, type GrVirtualAlign } from '../../composables/useVirtualList'\n\nimport { dividedClass, emptyClass, loadingRowClass } from './grListStyles'\n\nexport interface GrListProps<TItem = unknown> {\n /**\n * Поверхность списка — вариант карточки под ним. `ghost` убирает рамку и\n * тень: список внутри уже существующей карточки не должен давать вторую.\n */\n variant?: GrCardVariant\n /** Показывать ли горизонтальные разделители между элементами (по умолчанию — да). */\n divided?: boolean\n /** Идёт загрузка: вместо пунктов — строки-скелетоны, контейнер помечен `aria-busy`. */\n loading?: boolean\n /** Сколько строк-заглушек показать при `loading`. */\n loadingRows?: number\n /**\n * Список пуст. По умолчанию определяется сам — по содержимому слота; проп\n * нужен там, где потребитель знает лучше (например, слот заполнен\n * заголовками групп, а данных в них нет).\n */\n empty?: boolean\n /** Текст пустого состояния. Слот `#empty` сильнее. */\n emptyText?: string\n /**\n * Данные списка. С ними пункты рисует слот `#item`, а не слот по умолчанию, —\n * и только так список знает размер набора, то есть может его виртуализировать.\n */\n items?: TItem[]\n /** Ключ пункта для `v-for`: имя поля или функция. Без него — индекс. */\n itemKey?: string | ((item: TItem, index: number) => string | number)\n /** Высота видимой части: контейнер становится скроллером. Число — пиксели. */\n maxHeight?: number | string\n /** Держать в DOM только окно вокруг вьюпорта. Требует `items` и `maxHeight`. */\n virtual?: boolean\n /** Оценка высоты пункта до замера. Уточняется по факту при первом рендере. */\n estimatedItemSize?: number\n}\n\nconst props = withDefaults(defineProps<GrListProps<T>>(), {\n // Дефолт живёт в `GrCard` (и его резолвере `GrConfigProvider`), поэтому здесь\n // остаётся `undefined` — иначе список перебивал бы настройку карточки.\n variant: undefined,\n divided: true,\n loading: false,\n loadingRows: 3,\n empty: undefined,\n emptyText: undefined,\n items: undefined,\n itemKey: undefined,\n maxHeight: undefined,\n virtual: false,\n // Строка обычной плотности с заголовком и описанием.\n estimatedItemSize: 56,\n})\n\nconst slots = useSlots()\nconst { t } = useGranularityTranslations()\n\nconst listEl = ref<HTMLElement | null>(null)\n\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.list.empty', 'Nothing here yet'))\n\nconst dataMode = computed(() => props.items !== undefined)\n\n// Пустоту видно по слоту: `v-for` по пустому массиву оставляет фрагмент без\n// узлов, `v-if` — комментарий, и ни то ни другое пунктом списка не является.\nconst isEmpty = computed(() => {\n if (props.empty !== undefined)\n return props.empty\n\n if (dataMode.value)\n return props.items!.length === 0\n\n return !hasMeaningfulSlotContent(slots.default?.() ?? [])\n})\n\nconst showItems = computed(() => !props.loading && !isEmpty.value)\n\n// Разделители нужны только между пунктами: в пустой и загрузочной ветках они\n// оставили бы висящую линию.\nconst listClass = computed(() => (props.divided && showItems.value ? dividedClass : undefined))\n\nconst loadingRowCount = computed(() => Math.max(1, Math.trunc(props.loadingRows)))\n\nconst virtualEnabled = computed(() => props.virtual && dataMode.value && props.maxHeight !== undefined)\n\nconst virtualizer = useVirtualList({\n container: listEl,\n count: () => (virtualEnabled.value && showItems.value ? props.items!.length : 0),\n // Замена массива сбрасывает замеры; append в тот же массив их сохраняет.\n source: () => props.items,\n itemSize: () => props.estimatedItemSize,\n // Первый рендер обязан совпасть с серверным: контейнера ещё нет, и окно\n // считается от объявленной высоты, а не от измеренной.\n viewportSize: () => (typeof props.maxHeight === 'number' ? props.maxHeight : undefined),\n})\n\n/** Окно к отрисовке: при выключенной виртуализации — весь набор. */\nconst renderedItems = computed(() => {\n const items = props.items ?? []\n if (!virtualEnabled.value) return items.map((item, index) => ({ item, index }))\n\n const { start, end } = virtualizer.range.value\n return items.slice(start, end).map((item, offset) => ({ item, index: start + offset }))\n})\n\nfunction keyOf(item: T, index: number): string | number {\n const key = props.itemKey\n if (typeof key === 'function') return key(item, index)\n if (typeof key === 'string') return (item as Record<string, unknown>)[key] as string | number\n\n return index\n}\n\n/**\n * ARIA-набор для пункта.\n *\n * Только в виртуальном режиме: в DOM тогда неполный набор, и без этих атрибутов\n * диктор объявил бы «7 из 20» на списке в пять тысяч. Когда набор в DOM целиком,\n * его размер и позицию браузер считает сам, а руками проставленные атрибуты\n * начинают расходиться с разметкой при любой фильтрации.\n */\nfunction ariaOf(index: number): Record<string, number> {\n if (!virtualEnabled.value) return {}\n\n return { 'aria-setsize': props.items!.length, 'aria-posinset': index + 1 }\n}\n\nconst maxHeightStyle = computed(() => {\n const value = props.maxHeight\n if (value == null) return undefined\n return typeof value === 'number' ? `${value}px` : value\n})\n\nconst listStyle = computed(() => {\n if (props.maxHeight === undefined) return undefined\n\n const scroller = { overflowY: 'auto' as const, maxHeight: maxHeightStyle.value }\n if (!virtualEnabled.value) return scroller\n\n return { ...scroller, ...virtualizer.spacerStyle.value }\n})\n\n/**\n * Замер отрисованных пунктов.\n *\n * Идёт по детям контейнера, а не по `ref` на элементе: пункт рисует слот\n * потребителя, привязать к нему `ref` неоткуда. В виртуальном режиме прямые\n * дети контейнера — ровно окно (распорки живут псевдоэлементами и детьми не\n * считаются), поэтому сопоставление по позиции однозначно.\n */\nfunction measureRendered(): void {\n if (!virtualEnabled.value) return\n // В состояниях loading/empty дети контейнера — скелетоны и заглушки: их\n // высоты записались бы в замеры под индексами будущих строк данных.\n if (!showItems.value) return\n\n const container = listEl.value\n if (!container) return\n\n const { start } = virtualizer.range.value\n const children = container.children\n for (let offset = 0; offset < children.length; offset++) {\n virtualizer.measure(start + offset, children[offset])\n }\n}\n\nonMounted(measureRendered)\nonUpdated(measureRendered)\n\nfunction scrollToIndex(index: number, align?: GrVirtualAlign): void {\n virtualizer.scrollToIndex(index, align)\n}\n\ndefineExpose({ scrollToIndex })\n\nif (import.meta.env?.DEV) {\n watch(\n () => [props.virtual, dataMode.value, props.maxHeight] as const,\n ([virtual, hasItems, maxHeight]) => {\n if (!virtual) return\n\n if (!hasItems) {\n console.warn(\n '[granularity] GrList: `virtual` требует `items` — пункты из слота по умолчанию '\n + 'список не считает и резать окно ему не из чего.',\n )\n }\n else if (maxHeight === undefined) {\n console.warn(\n '[granularity] GrList: `virtual` требует `maxHeight` — без ограничения высоты '\n + 'вьюпорта нет, и в окно попадает весь набор.',\n )\n }\n },\n { immediate: true },\n )\n\n watch(\n () => [dataMode.value, Boolean(slots.item)] as const,\n ([hasItems, hasSlot]) => {\n if (hasItems && !hasSlot) {\n console.warn(\n '[granularity] GrList: с `items` пункты рисует слот `#item` — без него список пуст.',\n )\n }\n },\n { immediate: true },\n )\n\n onMounted(() => {\n if (!virtualEnabled.value) return\n\n const first = listEl.value?.firstElementChild\n if (first && !first.hasAttribute('aria-posinset')) {\n console.warn(\n '[granularity] GrList: при `virtual` пункты обязаны нести `aria-setsize`/`aria-posinset` — '\n + 'пробросьте `aria` из слота `#item`: <GrListItem v-bind=\"aria\" … />. Иначе диктор '\n + 'посчитает набор по отрисованному окну.',\n )\n }\n })\n}\n</script>\n\n<template>\n <GrCard :variant=\"variant\">\n <div\n ref=\"listEl\"\n data-gr-list\n role=\"list\"\n :class=\"listClass\"\n :style=\"listStyle\"\n :tabindex=\"maxHeight === undefined ? undefined : 0\"\n :data-gr-virtual=\"virtualEnabled ? '' : undefined\"\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <template v-if=\"loading\">\n <slot name=\"loading\">\n <div\n v-for=\"row in loadingRowCount\"\n :key=\"row\"\n data-gr-list-loading-row\n :class=\"loadingRowClass\"\n >\n <GrSkeleton />\n </div>\n </slot>\n </template>\n\n <div\n v-else-if=\"isEmpty\"\n data-gr-list-empty\n :class=\"emptyClass\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <template v-else-if=\"dataMode\">\n <template\n v-for=\"entry in renderedItems\"\n :key=\"keyOf(entry.item, entry.index)\"\n >\n <slot\n name=\"item\"\n :item=\"entry.item\"\n :index=\"entry.index\"\n :aria=\"ariaOf(entry.index)\"\n />\n </template>\n </template>\n\n <slot v-else />\n </div>\n </GrCard>\n</template>\n\n<style scoped>\n/* Срезанное сверху и снизу держат псевдоэлементы контейнера: их не за что\n размонтировать, в дереве доступности их нет, а высота приезжает переменными\n в том же патче, что и пункты. Почему не отступы контейнера и не поля крайних\n пунктов — `docs/virtual-list.md`. */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, markRaw, useSlots, watch, type Component } from 'vue'\n\nimport {\n grListItemPaddingClass,\n itemDescriptionClass,\n itemDisabledClass,\n itemHoverClass,\n itemInteractiveClass,\n itemLayoutClass,\n itemTitleClass,\n type GrListItemDensity,\n} from './grListStyles'\n\nexport type { GrListItemDensity } from './grListStyles'\n\nexport interface GrListItemProps {\n /** Заголовок строки. Если передан слот `#title`, проп игнорируется. */\n title?: string\n /** Описание под заголовком. Если передан слот `#description`, проп игнорируется. */\n description?: string\n /** Плотность вертикальных отступов: `regular` — 12px, `compact` — 8px. */\n density?: GrListItemDensity\n /** Ссылка: строка становится `<a>`. */\n href?: string\n /** Свой корневой тег строки (`RouterLink`, `Link` от Inertia). Сильнее `href`. */\n as?: string | Component\n /** Кликабельная строка без ссылки — `<button>` с событием `click`. */\n clickable?: boolean\n /** Подсветка при наведении без интерактивности. */\n hoverable?: boolean\n disabled?: boolean\n}\n\nexport interface GrListItemEmits {\n (e: 'click', event: MouseEvent): void\n}\n\nconst props = withDefaults(defineProps<GrListItemProps>(), {\n title: undefined,\n description: undefined,\n density: 'regular',\n href: undefined,\n as: undefined,\n clickable: false,\n hoverable: false,\n disabled: false,\n})\n\nconst emit = defineEmits<GrListItemEmits>()\n\nconst slots = useSlots()\n\nconst hasTitle = computed(() => !!slots.title || !!props.title)\nconst hasDescription = computed(() => !!slots.description || !!props.description)\n\nconst isInteractive = computed(() => !props.disabled && (!!props.as || !!props.href || props.clickable))\n\n/**\n * `role=\"listitem\"` остаётся на обёртке, а строка целиком — вложенный элемент:\n * `<a role=\"listitem\">` потерял бы роль ссылки, а интерактив снаружи разорвал бы\n * связку `list` → `listitem`. Обычная строка идёт по той же схеме, чтобы\n * разметка содержимого была написана один раз, а не по копии на ветку.\n */\nconst rowTag = computed<string | Component>(() => {\n if (!isInteractive.value)\n return 'div'\n\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n\n return props.href ? 'a' : 'button'\n})\n\nconst rowClass = computed(() => [\n itemLayoutClass,\n grListItemPaddingClass(props.density),\n isInteractive.value ? `${itemInteractiveClass} ${itemHoverClass}` : '',\n !isInteractive.value && props.hoverable && !props.disabled ? itemHoverClass : '',\n props.disabled ? itemDisabledClass : '',\n].filter(Boolean).join(' '))\n\nfunction onClick(event: MouseEvent): void {\n // `disabled` сюда попадает вместе с обычной строкой: и то и другое —\n // не-интерактив, а кликов не эмитит ни один.\n if (!isInteractive.value)\n return\n\n emit('click', event)\n}\n\n/** Теги, попадающие в таб-порядок сами. `<a>` — только со ссылкой. */\nfunction isFocusableTag(tag: string): boolean {\n return tag === 'button' || (tag === 'a' && !!props.href)\n}\n\nif (import.meta.env?.DEV) {\n watch(\n () => [isInteractive.value, props.as] as const,\n ([interactive, as]) => {\n // Компонент из `as` (`RouterLink`, Inertia `Link`) рендерит `<a>`, но узнать\n // это до рендера нельзя — предупреждаем только по явно названному тегу.\n if (!interactive || typeof as !== 'string' || isFocusableTag(as)) return\n\n console.warn(\n `[granularity] GrListItem: as=\"${as}\" не попадает в таб-порядок — строка кликается `\n + 'мышью, но не с клавиатуры. Возьмите тег, умеющий фокус (`button`, `a` со ссылкой), '\n + 'или компонент роутера.',\n )\n },\n { immediate: true },\n )\n}\n</script>\n\n<template>\n <div\n data-gr-list-item\n role=\"listitem\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n >\n <component\n :is=\"rowTag\"\n :data-gr-list-item-action=\"isInteractive ? '' : undefined\"\n :type=\"rowTag === 'button' ? 'button' : undefined\"\n :href=\"isInteractive ? href : undefined\"\n :class=\"rowClass\"\n @click=\"onClick\"\n >\n <div v-if=\"$slots.prefix\" class=\"shrink-0\">\n <slot name=\"prefix\" />\n </div>\n <div class=\"min-w-0 flex-1\">\n <div v-if=\"hasTitle\" :class=\"itemTitleClass\">\n <slot name=\"title\">\n{{ title }}\n</slot>\n </div>\n <div\n v-if=\"hasDescription\"\n :class=\"itemDescriptionClass\"\n >\n <slot name=\"description\">\n{{ description }}\n</slot>\n </div>\n </div>\n <div v-if=\"$slots.default\" class=\"shrink-0\">\n <slot />\n </div>\n </component>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, markRaw, useSlots, watch, type Component } from 'vue'\n\nimport {\n grListItemPaddingClass,\n itemDescriptionClass,\n itemDisabledClass,\n itemHoverClass,\n itemInteractiveClass,\n itemLayoutClass,\n itemTitleClass,\n type GrListItemDensity,\n} from './grListStyles'\n\nexport type { GrListItemDensity } from './grListStyles'\n\nexport interface GrListItemProps {\n /** Заголовок строки. Если передан слот `#title`, проп игнорируется. */\n title?: string\n /** Описание под заголовком. Если передан слот `#description`, проп игнорируется. */\n description?: string\n /** Плотность вертикальных отступов: `regular` — 12px, `compact` — 8px. */\n density?: GrListItemDensity\n /** Ссылка: строка становится `<a>`. */\n href?: string\n /** Свой корневой тег строки (`RouterLink`, `Link` от Inertia). Сильнее `href`. */\n as?: string | Component\n /** Кликабельная строка без ссылки — `<button>` с событием `click`. */\n clickable?: boolean\n /** Подсветка при наведении без интерактивности. */\n hoverable?: boolean\n disabled?: boolean\n}\n\nexport interface GrListItemEmits {\n (e: 'click', event: MouseEvent): void\n}\n\nconst props = withDefaults(defineProps<GrListItemProps>(), {\n title: undefined,\n description: undefined,\n density: 'regular',\n href: undefined,\n as: undefined,\n clickable: false,\n hoverable: false,\n disabled: false,\n})\n\nconst emit = defineEmits<GrListItemEmits>()\n\nconst slots = useSlots()\n\nconst hasTitle = computed(() => !!slots.title || !!props.title)\nconst hasDescription = computed(() => !!slots.description || !!props.description)\n\nconst isInteractive = computed(() => !props.disabled && (!!props.as || !!props.href || props.clickable))\n\n/**\n * `role=\"listitem\"` остаётся на обёртке, а строка целиком — вложенный элемент:\n * `<a role=\"listitem\">` потерял бы роль ссылки, а интерактив снаружи разорвал бы\n * связку `list` → `listitem`. Обычная строка идёт по той же схеме, чтобы\n * разметка содержимого была написана один раз, а не по копии на ветку.\n */\nconst rowTag = computed<string | Component>(() => {\n if (!isInteractive.value)\n return 'div'\n\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n\n return props.href ? 'a' : 'button'\n})\n\nconst rowClass = computed(() => [\n itemLayoutClass,\n grListItemPaddingClass(props.density),\n isInteractive.value ? `${itemInteractiveClass} ${itemHoverClass}` : '',\n !isInteractive.value && props.hoverable && !props.disabled ? itemHoverClass : '',\n props.disabled ? itemDisabledClass : '',\n].filter(Boolean).join(' '))\n\nfunction onClick(event: MouseEvent): void {\n // `disabled` сюда попадает вместе с обычной строкой: и то и другое —\n // не-интерактив, а кликов не эмитит ни один.\n if (!isInteractive.value)\n return\n\n emit('click', event)\n}\n\n/** Теги, попадающие в таб-порядок сами. `<a>` — только со ссылкой. */\nfunction isFocusableTag(tag: string): boolean {\n return tag === 'button' || (tag === 'a' && !!props.href)\n}\n\nif (import.meta.env?.DEV) {\n watch(\n () => [isInteractive.value, props.as] as const,\n ([interactive, as]) => {\n // Компонент из `as` (`RouterLink`, Inertia `Link`) рендерит `<a>`, но узнать\n // это до рендера нельзя — предупреждаем только по явно названному тегу.\n if (!interactive || typeof as !== 'string' || isFocusableTag(as)) return\n\n console.warn(\n `[granularity] GrListItem: as=\"${as}\" не попадает в таб-порядок — строка кликается `\n + 'мышью, но не с клавиатуры. Возьмите тег, умеющий фокус (`button`, `a` со ссылкой), '\n + 'или компонент роутера.',\n )\n },\n { immediate: true },\n )\n}\n</script>\n\n<template>\n <div\n data-gr-list-item\n role=\"listitem\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n >\n <component\n :is=\"rowTag\"\n :data-gr-list-item-action=\"isInteractive ? '' : undefined\"\n :type=\"rowTag === 'button' ? 'button' : undefined\"\n :href=\"isInteractive ? href : undefined\"\n :class=\"rowClass\"\n @click=\"onClick\"\n >\n <div v-if=\"$slots.prefix\" class=\"shrink-0\">\n <slot name=\"prefix\" />\n </div>\n <div class=\"min-w-0 flex-1\">\n <div v-if=\"hasTitle\" :class=\"itemTitleClass\">\n <slot name=\"title\">\n{{ title }}\n</slot>\n </div>\n <div\n v-if=\"hasDescription\"\n :class=\"itemDescriptionClass\"\n >\n <slot name=\"description\">\n{{ description }}\n</slot>\n </div>\n </div>\n <div v-if=\"$slots.default\" class=\"shrink-0\">\n <slot />\n </div>\n </component>\n </div>\n</template>\n"],"mappings":"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"}
|