@pgcorp/ui-kit 0.9.0 → 0.10.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.
Files changed (105) hide show
  1. package/README.md +188 -9
  2. package/docs/getting-started.md +135 -0
  3. package/docs/public-api.md +53 -4
  4. package/docs/rich-document.md +216 -0
  5. package/docs/scroll-viewport.md +167 -0
  6. package/package.json +103 -50
  7. package/src/components/layout/SAppShell.vue +3 -1
  8. package/src/components/layout/SDockRegion.vue +5 -3
  9. package/src/components/layout/SWorkbenchPanelShell.vue +4 -2
  10. package/src/components/shared/_internal/SDialogSurface.css +5 -0
  11. package/src/components/shared/_internal/SDialogSurface.vue +3 -1
  12. package/src/components/shared/_internal/SToastItem.css +4 -0
  13. package/src/components/shared/_internal/SToastItem.vue +44 -8
  14. package/src/components/shared/_internal/STreeNode.vue +24 -11
  15. package/src/components/shared/complex/SKanbanLane.vue +4 -2
  16. package/src/components/shared/containers/SCloudChromeRow.vue +3 -2
  17. package/src/components/shared/containers/SDrawer.vue +5 -2
  18. package/src/components/shared/containers/SModal.vue +5 -2
  19. package/src/components/shared/containers/SPanel.vue +4 -2
  20. package/src/components/shared/containers/SPopover.vue +7 -3
  21. package/src/components/shared/containers/SUiKitLocaleProvider.vue +57 -0
  22. package/src/components/shared/controls/SButton.css +14 -10
  23. package/src/components/shared/controls/SCombobox.vue +8 -6
  24. package/src/components/shared/controls/SComboboxTrigger.css +7 -4
  25. package/src/components/shared/controls/SComboboxTrigger.vue +5 -2
  26. package/src/components/shared/controls/SContextToggleButton.vue +6 -4
  27. package/src/components/shared/controls/SDragHandle.vue +8 -4
  28. package/src/components/shared/controls/SDropdownMenu.vue +7 -4
  29. package/src/components/shared/controls/SInputText.css +5 -4
  30. package/src/components/shared/controls/SListbox.vue +4 -2
  31. package/src/components/shared/controls/SSelect.vue +4 -2
  32. package/src/components/shared/controls/_internal/SInlineTokenSurface.vue +4 -2
  33. package/src/components/shared/data-display/SChart.vue +7 -5
  34. package/src/components/shared/data-display/SChip.vue +3 -1
  35. package/src/components/shared/data-display/SCodeBlock.css +4 -0
  36. package/src/components/shared/data-display/SCodeBlock.vue +42 -20
  37. package/src/components/shared/data-display/SCodeEditor.css +17 -0
  38. package/src/components/shared/data-display/SCodeEditor.vue +173 -8
  39. package/src/components/shared/data-display/SCodeSearchPanel.vue +48 -33
  40. package/src/components/shared/data-display/SCodeWorkspaceEditor.css +13 -0
  41. package/src/components/shared/data-display/SCodeWorkspaceEditor.vue +355 -0
  42. package/src/components/shared/data-display/SControlledToastViewport.css +89 -0
  43. package/src/components/shared/data-display/SControlledToastViewport.vue +205 -0
  44. package/src/components/shared/data-display/SCopyField.vue +12 -10
  45. package/src/components/shared/data-display/SDiffViewer.css +122 -0
  46. package/src/components/shared/data-display/SDiffViewer.vue +499 -0
  47. package/src/components/shared/data-display/SDocBlock.vue +99 -71
  48. package/src/components/shared/data-display/SExpandableText.vue +10 -8
  49. package/src/components/shared/data-display/SJsonTree.vue +4 -2
  50. package/src/components/shared/data-display/SLinkedSystemsList.vue +4 -2
  51. package/src/components/shared/data-display/SMessage.vue +6 -6
  52. package/src/components/shared/data-display/SRichDocument.css +8 -0
  53. package/src/components/shared/data-display/SRichDocument.vue +65 -0
  54. package/src/components/shared/data-display/SScrollViewport.css +53 -0
  55. package/src/components/shared/data-display/SScrollViewport.vue +470 -0
  56. package/src/components/shared/data-display/STable.vue +38 -19
  57. package/src/components/shared/data-display/SToastContainer.vue +22 -17
  58. package/src/components/shared/data-display/_internal/SCodeTokenLine.css +72 -0
  59. package/src/components/shared/data-display/_internal/SCodeTokenLine.vue +79 -0
  60. package/src/components/shared/data-display/_internal/SRichBlockNode.css +85 -0
  61. package/src/components/shared/data-display/_internal/SRichBlockNode.vue +282 -0
  62. package/src/components/shared/data-display/_internal/SRichInlineNode.css +6 -0
  63. package/src/components/shared/data-display/_internal/SRichInlineNode.vue +76 -0
  64. package/src/components/shared/data-display/_internal/SRichMath.css +42 -0
  65. package/src/components/shared/data-display/_internal/SRichMath.vue +102 -0
  66. package/src/components/shared/data-display/codeEditor.ts +200 -0
  67. package/src/components/shared/data-display/codeWorkspace.ts +233 -0
  68. package/src/components/shared/data-display/diff.ts +541 -0
  69. package/src/components/shared/data-display/richDocument.ts +876 -0
  70. package/src/components/shared/data-display/scrollViewport.ts +47 -0
  71. package/src/components/shared/data-display/toast.ts +194 -0
  72. package/src/components/shared/database/SDataGrid.vue +7 -4
  73. package/src/components/shared/database/SSqlEditor.vue +39 -39
  74. package/src/components/shared/feedback/SAsyncState.vue +3 -1
  75. package/src/components/shared/graph/SGraphViewport.vue +11 -9
  76. package/src/components/shared/navigation/SBreadcrumbs.vue +8 -5
  77. package/src/components/shared/navigation/SCatalogNavigator.vue +26 -20
  78. package/src/components/shared/navigation/STabList.vue +10 -6
  79. package/src/components/shared/navigation/STabs.vue +15 -11
  80. package/src/components/shared/navigation/SWizardSteps.vue +4 -2
  81. package/src/components/shared/persona/SPersonaProjectPicker.vue +31 -27
  82. package/src/components/shared/persona/SPersonaRunWorkbench.vue +39 -33
  83. package/src/components/shared/persona/_internal/SPersonaRunConsole.vue +8 -6
  84. package/src/components/shared/persona/_internal/labels.ts +66 -57
  85. package/src/components/shared/persona/presentation.ts +140 -110
  86. package/src/composables/useFloatingPosition.ts +39 -2
  87. package/src/composables/useUiKitLocale.ts +17 -0
  88. package/src/internal/codeHighlight.ts +110 -0
  89. package/src/internal/diffEngine.ts +464 -0
  90. package/src/internal/diffRuntime.ts +189 -0
  91. package/src/internal/feedbackPresentation.ts +33 -14
  92. package/src/internal/localeContext.ts +22 -0
  93. package/src/internal/ownedAttrs.ts +8 -0
  94. package/src/internal/runtimeContract.ts +11 -9
  95. package/src/internal/semanticSizing.ts +13 -0
  96. package/src/locales/catalog.ts +634 -0
  97. package/src/locales/locale.ts +472 -0
  98. package/src/locales/messages.generated.ts +1826 -0
  99. package/src/locales/messages.ts +150 -0
  100. package/src/stores/useNotifierStore.ts +61 -44
  101. package/src/styles/tokens.css +20 -2
  102. package/src/theme.ts +59 -32
  103. package/src/workers/diff.worker.ts +73 -0
  104. package/src/workers/diffProtocol.ts +155 -0
  105. package/src/components/shared/data-display/SToastContainer.css +0 -53
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pgcorp/ui-kit",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Typed Vue 3 design system with accessible components, semantic themes, and workbench patterns.",
5
5
  "type": "module",
6
6
  "types": "./index.ts",
@@ -37,7 +37,7 @@
37
37
  "email": "remand-gambol4g@icloud.com"
38
38
  },
39
39
  "engines": {
40
- "node": ">=20.19.0",
40
+ "node": "^22.22.2 || ^24.15.0 || ^26.0.0",
41
41
  "npm": ">=10.9.2 <12"
42
42
  },
43
43
  "publishConfig": {
@@ -46,17 +46,21 @@
46
46
  },
47
47
  "scripts": {
48
48
  "audit:composition": "node ./scripts/check-composition.mjs --mode audit",
49
+ "audit:owned-strings": "node ./scripts/audit-kit-owned-strings.mjs",
49
50
  "build": "vite build",
50
51
  "check:composition": "node ./scripts/check-composition.mjs --mode check",
51
52
  "check:composition-contract": "node ./scripts/check-composition.mjs --mode contract",
53
+ "check:owned-strings": "node ./scripts/audit-kit-owned-strings.mjs --check",
52
54
  "check:proof": "node ./scripts/check-proof-contract.mjs",
53
55
  "check:proof-contract": "vitest --config ./vitest.config.ts --run src/__tests__/proof-contract.spec.ts src/__tests__/proof-sync.spec.ts",
54
56
  "check:proof-drift": "node ./scripts/sync-proof-contract.mjs --check",
55
57
  "check:package-exports": "node ./scripts/sync-package-exports.mjs --check",
58
+ "check:locale-runtime": "node ./scripts/sync-locale-runtime.mjs --check",
56
59
  "check:publish": "node ./scripts/check-publish-contract.mjs",
57
60
  "pack:dry-run": "npm pack --dry-run --json --cache ../../.cache/npm/ui-kit-publish",
58
61
  "smoke:package": "node ./scripts/smoke-published-package.mjs",
59
62
  "sync:package-exports": "node ./scripts/sync-package-exports.mjs --write",
63
+ "sync:locale-runtime": "node ./scripts/sync-locale-runtime.mjs --write",
60
64
  "sync:proof": "node ./scripts/sync-proof-contract.mjs --write",
61
65
  "type-check": "vue-tsc --noEmit -p tsconfig.json",
62
66
  "type-check:test": "vue-tsc --noEmit -p tsconfig.vitest.json",
@@ -87,6 +91,9 @@
87
91
  "composables/useSidebarPanelState": [
88
92
  "src/composables/useSidebarPanelState.ts"
89
93
  ],
94
+ "composables/useUiKitLocale": [
95
+ "src/composables/useUiKitLocale.ts"
96
+ ],
90
97
  "icons": [
91
98
  "src/components/icons/sputnigUiIcons.ts"
92
99
  ],
@@ -189,6 +196,9 @@
189
196
  "shared/containers/SSidebarSection.vue": [
190
197
  "src/components/shared/containers/SSidebarSection.vue"
191
198
  ],
199
+ "shared/containers/SUiKitLocaleProvider.vue": [
200
+ "src/components/shared/containers/SUiKitLocaleProvider.vue"
201
+ ],
192
202
  "shared/controls/menu": [
193
203
  "src/components/shared/controls/menu.ts"
194
204
  ],
@@ -276,9 +286,21 @@
276
286
  "shared/data-display/chart": [
277
287
  "src/components/shared/data-display/chart.ts"
278
288
  ],
289
+ "shared/data-display/codeEditor": [
290
+ "src/components/shared/data-display/codeEditor.ts"
291
+ ],
292
+ "shared/data-display/codeWorkspace": [
293
+ "src/components/shared/data-display/codeWorkspace.ts"
294
+ ],
295
+ "shared/data-display/diff": [
296
+ "src/components/shared/data-display/diff.ts"
297
+ ],
279
298
  "shared/data-display/json": [
280
299
  "src/components/shared/data-display/json.ts"
281
300
  ],
301
+ "shared/data-display/richDocument": [
302
+ "src/components/shared/data-display/richDocument.ts"
303
+ ],
282
304
  "shared/data-display/SActionCard.vue": [
283
305
  "src/components/shared/data-display/SActionCard.vue"
284
306
  ],
@@ -306,9 +328,21 @@
306
328
  "shared/data-display/SCodeSearchPanel.vue": [
307
329
  "src/components/shared/data-display/SCodeSearchPanel.vue"
308
330
  ],
331
+ "shared/data-display/SCodeWorkspaceEditor.vue": [
332
+ "src/components/shared/data-display/SCodeWorkspaceEditor.vue"
333
+ ],
334
+ "shared/data-display/SControlledToastViewport.vue": [
335
+ "src/components/shared/data-display/SControlledToastViewport.vue"
336
+ ],
309
337
  "shared/data-display/SCopyField.vue": [
310
338
  "src/components/shared/data-display/SCopyField.vue"
311
339
  ],
340
+ "shared/data-display/scrollViewport": [
341
+ "src/components/shared/data-display/scrollViewport.ts"
342
+ ],
343
+ "shared/data-display/SDiffViewer.vue": [
344
+ "src/components/shared/data-display/SDiffViewer.vue"
345
+ ],
312
346
  "shared/data-display/SDocBlock.vue": [
313
347
  "src/components/shared/data-display/SDocBlock.vue"
314
348
  ],
@@ -339,6 +373,12 @@
339
373
  "shared/data-display/SProgressIndicator.vue": [
340
374
  "src/components/shared/data-display/SProgressIndicator.vue"
341
375
  ],
376
+ "shared/data-display/SRichDocument.vue": [
377
+ "src/components/shared/data-display/SRichDocument.vue"
378
+ ],
379
+ "shared/data-display/SScrollViewport.vue": [
380
+ "src/components/shared/data-display/SScrollViewport.vue"
381
+ ],
342
382
  "shared/data-display/SSectionHeader.vue": [
343
383
  "src/components/shared/data-display/SSectionHeader.vue"
344
384
  ],
@@ -369,6 +409,9 @@
369
409
  "shared/data-display/table": [
370
410
  "src/components/shared/data-display/table.ts"
371
411
  ],
412
+ "shared/data-display/toast": [
413
+ "src/components/shared/data-display/toast.ts"
414
+ ],
372
415
  "shared/database/SDataGrid.vue": [
373
416
  "src/components/shared/database/SDataGrid.vue"
374
417
  ],
@@ -452,6 +495,7 @@
452
495
  "./composables/useFloatingPosition": "./src/composables/useFloatingPosition.ts",
453
496
  "./composables/useNotifier": "./src/composables/useNotifier.ts",
454
497
  "./composables/useSidebarPanelState": "./src/composables/useSidebarPanelState.ts",
498
+ "./composables/useUiKitLocale": "./src/composables/useUiKitLocale.ts",
455
499
  "./icons": "./src/components/icons/sputnigUiIcons.ts",
456
500
  "./layout/SAppShell.vue": "./src/components/layout/SAppShell.vue",
457
501
  "./layout/SDockRegion.vue": "./src/components/layout/SDockRegion.vue",
@@ -487,6 +531,7 @@
487
531
  "./shared/containers/SPopover.vue": "./src/components/shared/containers/SPopover.vue",
488
532
  "./shared/containers/SSidebarGroup.vue": "./src/components/shared/containers/SSidebarGroup.vue",
489
533
  "./shared/containers/SSidebarSection.vue": "./src/components/shared/containers/SSidebarSection.vue",
534
+ "./shared/containers/SUiKitLocaleProvider.vue": "./src/components/shared/containers/SUiKitLocaleProvider.vue",
490
535
  "./shared/controls/menu": "./src/components/shared/controls/menu.ts",
491
536
  "./shared/controls/SButton.vue": "./src/components/shared/controls/SButton.vue",
492
537
  "./shared/controls/SCheckbox.vue": "./src/components/shared/controls/SCheckbox.vue",
@@ -516,7 +561,11 @@
516
561
  "./shared/controls/STextarea": "./src/components/shared/controls/STextarea.ts",
517
562
  "./shared/controls/STextarea.vue": "./src/components/shared/controls/STextarea.vue",
518
563
  "./shared/data-display/chart": "./src/components/shared/data-display/chart.ts",
564
+ "./shared/data-display/codeEditor": "./src/components/shared/data-display/codeEditor.ts",
565
+ "./shared/data-display/codeWorkspace": "./src/components/shared/data-display/codeWorkspace.ts",
566
+ "./shared/data-display/diff": "./src/components/shared/data-display/diff.ts",
519
567
  "./shared/data-display/json": "./src/components/shared/data-display/json.ts",
568
+ "./shared/data-display/richDocument": "./src/components/shared/data-display/richDocument.ts",
520
569
  "./shared/data-display/SActionCard.vue": "./src/components/shared/data-display/SActionCard.vue",
521
570
  "./shared/data-display/SActionList.vue": "./src/components/shared/data-display/SActionList.vue",
522
571
  "./shared/data-display/SActionListItem.vue": "./src/components/shared/data-display/SActionListItem.vue",
@@ -526,7 +575,11 @@
526
575
  "./shared/data-display/SCodeBlock.vue": "./src/components/shared/data-display/SCodeBlock.vue",
527
576
  "./shared/data-display/SCodeEditor.vue": "./src/components/shared/data-display/SCodeEditor.vue",
528
577
  "./shared/data-display/SCodeSearchPanel.vue": "./src/components/shared/data-display/SCodeSearchPanel.vue",
578
+ "./shared/data-display/SCodeWorkspaceEditor.vue": "./src/components/shared/data-display/SCodeWorkspaceEditor.vue",
579
+ "./shared/data-display/SControlledToastViewport.vue": "./src/components/shared/data-display/SControlledToastViewport.vue",
529
580
  "./shared/data-display/SCopyField.vue": "./src/components/shared/data-display/SCopyField.vue",
581
+ "./shared/data-display/scrollViewport": "./src/components/shared/data-display/scrollViewport.ts",
582
+ "./shared/data-display/SDiffViewer.vue": "./src/components/shared/data-display/SDiffViewer.vue",
530
583
  "./shared/data-display/SDocBlock.vue": "./src/components/shared/data-display/SDocBlock.vue",
531
584
  "./shared/data-display/SEmptyState.vue": "./src/components/shared/data-display/SEmptyState.vue",
532
585
  "./shared/data-display/SExpandableText.vue": "./src/components/shared/data-display/SExpandableText.vue",
@@ -537,6 +590,8 @@
537
590
  "./shared/data-display/SMetricCard.vue": "./src/components/shared/data-display/SMetricCard.vue",
538
591
  "./shared/data-display/SProgressBar.vue": "./src/components/shared/data-display/SProgressBar.vue",
539
592
  "./shared/data-display/SProgressIndicator.vue": "./src/components/shared/data-display/SProgressIndicator.vue",
593
+ "./shared/data-display/SRichDocument.vue": "./src/components/shared/data-display/SRichDocument.vue",
594
+ "./shared/data-display/SScrollViewport.vue": "./src/components/shared/data-display/SScrollViewport.vue",
540
595
  "./shared/data-display/SSectionHeader.vue": "./src/components/shared/data-display/SSectionHeader.vue",
541
596
  "./shared/data-display/SStatus.vue": "./src/components/shared/data-display/SStatus.vue",
542
597
  "./shared/data-display/STable.vue": "./src/components/shared/data-display/STable.vue",
@@ -547,6 +602,7 @@
547
602
  "./shared/data-display/SVirtualList": "./src/components/shared/data-display/SVirtualList.ts",
548
603
  "./shared/data-display/SVirtualList.vue": "./src/components/shared/data-display/SVirtualList.vue",
549
604
  "./shared/data-display/table": "./src/components/shared/data-display/table.ts",
605
+ "./shared/data-display/toast": "./src/components/shared/data-display/toast.ts",
550
606
  "./shared/database/SDataGrid.vue": "./src/components/shared/database/SDataGrid.vue",
551
607
  "./shared/database/SSqlEditor.vue": "./src/components/shared/database/SSqlEditor.vue",
552
608
  "./shared/feedback/SAsyncState.vue": "./src/components/shared/feedback/SAsyncState.vue",
@@ -574,65 +630,62 @@
574
630
  "./variants": "./src/variants.ts"
575
631
  },
576
632
  "peerDependencies": {
577
- "pinia": "^3.0.4",
578
- "vue": "^3.5.0",
579
- "vue-router": "^5.0.0"
633
+ "@vue/devtools-api": "^8.2.1",
634
+ "pinia": "^4.0.3",
635
+ "vue": "^3.5.43",
636
+ "vue-router": "^5.3.1"
580
637
  },
581
638
  "dependencies": {
582
- "@codemirror/autocomplete": "^6.20.1",
583
- "@codemirror/language": "^6.11.3",
584
- "@codemirror/legacy-modes": "^6.5.2",
585
- "@codemirror/lint": "^6.9.5",
586
- "@codemirror/state": "^6.5.4",
639
+ "@codemirror/autocomplete": "^6.20.3",
640
+ "@codemirror/language": "^6.12.4",
641
+ "@codemirror/legacy-modes": "^6.5.4",
642
+ "@codemirror/lint": "^6.9.7",
643
+ "@codemirror/state": "^6.7.5",
587
644
  "@codemirror/theme-one-dark": "^6.1.3",
588
- "@codemirror/view": "^6.39.15",
589
- "@uiw/codemirror-extensions-langs": "^4.25.8",
645
+ "@codemirror/view": "^6.43.12",
646
+ "@uiw/codemirror-extensions-langs": "^4.25.11",
590
647
  "codemirror": "6.0.2",
591
648
  "codemirror-lang-makefile": "^0.1.1",
592
649
  "dompurify": "^3.4.16",
593
650
  "graphology": "^0.26.0",
594
- "highlight.js": "^11.11.1",
595
- "@lucide/vue": "^1.16.0",
596
- "@tailwindcss/typography": "^0.5.19",
597
- "marked": "^17.0.3",
651
+ "highlight.js": "^11.12.0",
652
+ "katex": "0.18.7",
653
+ "@lucide/vue": "^1.47.0",
654
+ "@tailwindcss/typography": "^0.5.20",
655
+ "marked": "^18.0.13",
598
656
  "sigma": "^3.0.3",
599
- "tailwindcss": "^4.2.0",
600
- "uuid": "^13.0.0",
657
+ "tailwindcss": "^4.3.3",
658
+ "uuid": "^14.0.2",
601
659
  "vue-codemirror": "^6.1.1"
602
660
  },
603
661
  "devDependencies": {
604
- "@storybook/vue3-vite": "10.5.3",
605
- "@tailwindcss/postcss": "^4.2.0",
606
- "@types/node": "^25.3.0",
607
- "@vitejs/plugin-vue": "^6.0.4",
608
- "@vitest/coverage-v8": "^4.1.11",
609
- "@vitest/eslint-plugin": "1.6.20",
610
- "@vue/compiler-dom": "3.5.39",
611
- "@vue/compiler-sfc": "3.5.39",
662
+ "@storybook/vue3-vite": "10.6.0",
663
+ "@tailwindcss/postcss": "^4.3.3",
664
+ "@types/node": "^22.20.4",
665
+ "@vitejs/plugin-vue": "^6.0.9",
666
+ "@vitest/coverage-v8": "^5.0.1",
667
+ "@vitest/eslint-plugin": "1.6.27",
668
+ "@vue/compiler-dom": "3.5.43",
669
+ "@vue/compiler-sfc": "3.5.43",
670
+ "@vue/devtools-api": "^8.2.1",
612
671
  "@vue/eslint-config-prettier": "^10.2.0",
613
- "@vue/test-utils": "^2.4.6",
614
- "date-fns": "^4.1.0",
615
- "eslint": "^10.0.0",
616
- "eslint-plugin-vue": "^10.8.0",
617
- "jsdom": "^28.1.0",
618
- "pinia": "^3.0.4",
619
- "postcss": "8.5.26",
620
- "postcss-selector-parser": "7.1.4",
621
- "storybook": "10.5.3",
622
- "typescript": "^5.9.3",
623
- "typescript-eslint": "^8.60.0",
624
- "vite": "^7.3.1",
625
- "vite-plugin-dts": "^4.5.4",
626
- "vitest": "^4.1.11",
627
- "vue": "^3.5.28",
628
- "vue-eslint-parser": "^10.4.0",
629
- "vue-router": "^5.0.3",
630
- "vue-tsc": "^3.2.4"
631
- },
632
- "overrides": {
633
- "glob": "13.0.6",
634
- "js-beautify": {
635
- "glob": "13.0.6"
636
- }
672
+ "@vue/test-utils": "2.5.1",
673
+ "date-fns": "^4.4.0",
674
+ "eslint": "^10.11.0",
675
+ "eslint-plugin-vue": "^10.11.0",
676
+ "jsdom": "^30.1.0",
677
+ "pinia": "^4.0.3",
678
+ "postcss": "8.5.28",
679
+ "postcss-selector-parser": "7.1.6",
680
+ "storybook": "10.6.0",
681
+ "typescript": "^6.0.3",
682
+ "typescript-eslint": "^8.70.0",
683
+ "vite": "^8.3.0",
684
+ "vite-plugin-dts": "^5.1.0",
685
+ "vitest": "^5.0.1",
686
+ "vue": "^3.5.43",
687
+ "vue-eslint-parser": "^10.4.1",
688
+ "vue-router": "^5.3.1",
689
+ "vue-tsc": "^3.3.11"
637
690
  }
638
691
  }
@@ -4,6 +4,7 @@ import type { RouteLocationRaw } from 'vue-router'
4
4
  import { hasOwn } from '../../internal/es2020'
5
5
  import { useOwnedAttrs } from '../../internal/ownedAttrs'
6
6
  import { validateNonEmptyString } from '../../internal/runtimeContract'
7
+ import { useUiKitLocale } from '../../composables/useUiKitLocale'
7
8
  import SBadge from '../shared/data-display/SBadge.vue'
8
9
  import SPanel from '../shared/containers/SPanel.vue'
9
10
  import SLink from '../shared/controls/SLink.vue'
@@ -57,6 +58,7 @@ interface RuntimeProps extends SharedProps {
57
58
  }
58
59
 
59
60
  const props = defineProps<RuntimeProps>()
61
+ const { t } = useUiKitLocale()
60
62
  function requireComponentInstance() {
61
63
  const instance = getCurrentInstance()
62
64
  if (!instance) throw new Error('SAppShell: component instance unavailable during setup')
@@ -121,7 +123,7 @@ const shell = computed<ResolvedShell>(() => {
121
123
  navigationLabel: validateNonEmptyString(
122
124
  'SAppShell',
123
125
  'navigationLabel',
124
- props.navigationLabel ?? 'Основная навигация',
126
+ props.navigationLabel ?? t('navigation.main'),
125
127
  ),
126
128
  pageBadgeLabel: props.pageBadgeLabel ?? '',
127
129
  pageBadgeSeverity: props.pageBadgeSeverity ?? 'info',
@@ -39,6 +39,7 @@
39
39
 
40
40
  <script setup lang="ts">
41
41
  import { computed, ref, type CSSProperties } from 'vue'
42
+ import { useUiKitLocale } from '../../composables/useUiKitLocale'
42
43
  import { useOwnedAttrs } from '../../internal/ownedAttrs'
43
44
  import {
44
45
  validateBoolean,
@@ -79,6 +80,7 @@ const props = withDefaults(defineProps<{
79
80
  hideResizeHandleOnNarrow: false,
80
81
  responsiveSize: 'fixed',
81
82
  })
83
+ const { t } = useUiKitLocale()
82
84
 
83
85
  const emit = defineEmits<{
84
86
  (event: 'resize-start', pointerEvent: PointerEvent): void
@@ -122,9 +124,9 @@ const resolvedResizeLabel = computed(() => {
122
124
  if (props.resizeLabel !== undefined) {
123
125
  return validateNonEmptyString('SDockRegion', 'resizeLabel', props.resizeLabel)
124
126
  }
125
- if (contract.value.placement === 'bottom') return 'Изменить высоту нижней панели'
126
- if (contract.value.placement === 'left') return 'Изменить ширину левой панели'
127
- return 'Изменить ширину правой панели'
127
+ if (contract.value.placement === 'bottom') return t('layout.resizeBottomPanel')
128
+ if (contract.value.placement === 'left') return t('layout.resizeLeftPanel')
129
+ return t('layout.resizeRightPanel')
128
130
  })
129
131
 
130
132
  function handleResizeStart(event: PointerEvent): void {
@@ -91,6 +91,7 @@
91
91
 
92
92
  <script setup lang="ts">
93
93
  import { computed, onBeforeUnmount, onMounted, ref, useSlots, watch } from 'vue'
94
+ import { useUiKitLocale } from '../../composables/useUiKitLocale'
94
95
  import SAsyncState from '../shared/feedback/SAsyncState.vue'
95
96
  import { useOwnedAttrs } from '../../internal/ownedAttrs'
96
97
  import {
@@ -130,6 +131,7 @@ const props = withDefaults(defineProps<{
130
131
  secondaryStickyHeader: false,
131
132
  secondaryResponsiveStack: false,
132
133
  })
134
+ const { t } = useUiKitLocale()
133
135
 
134
136
  const slots = useSlots()
135
137
  const ownedAttrs = useOwnedAttrs({ component: 'SWorkbenchPanelShell', owner: 'workbench panel root' })
@@ -170,8 +172,8 @@ const showSecondary = computed(() =>
170
172
  const isBottomDock = computed(() => props.secondaryPlacement === 'bottom-dock')
171
173
  const dockPlacement = computed<'right' | 'bottom'>(() => isBottomDock.value ? 'bottom' : 'right')
172
174
  const secondaryResizeLabel = computed(() => isBottomDock.value
173
- ? 'Изменить высоту нижней панели'
174
- : 'Изменить ширину боковой панели')
175
+ ? t('layout.resizeBottomPanel')
176
+ : t('layout.resizeSidePanel'))
175
177
  const secondaryResizeTestId = computed(() => isBottomDock.value
176
178
  ? 'workbench-shell-resize-handle-bottom'
177
179
  : 'workbench-shell-resize-handle-right')
@@ -4,6 +4,11 @@
4
4
  box-shadow: var(--s-elevation-overlay);
5
5
  }
6
6
 
7
+ .s-dialog-surface:focus-visible {
8
+ outline: var(--s-focus-ring-width) solid var(--s-focus-ring-color);
9
+ outline-offset: var(--s-focus-ring-inset-offset);
10
+ }
11
+
7
12
  .s-dialog-surface[data-presentation='modal'] {
8
13
  @apply w-full transform overflow-hidden rounded-2xl p-6 text-left align-middle transition-all;
9
14
  @apply bg-surface-0 dark:bg-surface-800;
@@ -26,7 +26,7 @@
26
26
  icon-only
27
27
  appearance="text"
28
28
  size="sm"
29
- aria-label="Закрыть"
29
+ :aria-label="t('dialog.close')"
30
30
  @click="requestClose"
31
31
  />
32
32
  </component>
@@ -55,6 +55,7 @@
55
55
 
56
56
  <script setup lang="ts">
57
57
  import { computed, useId, useSlots, type ComponentPublicInstance } from 'vue'
58
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
58
59
 
59
60
  import { X } from '../../icons/sputnigUiIcons'
60
61
  import SButton from '../controls/SButton.vue'
@@ -78,6 +79,7 @@ const props = defineProps<{
78
79
  const emit = defineEmits<{
79
80
  'request-close': []
80
81
  }>()
82
+ const { t } = useUiKitLocale()
81
83
 
82
84
  defineSlots<{
83
85
  header?: () => unknown
@@ -28,6 +28,10 @@
28
28
  word-break: break-word;
29
29
  }
30
30
 
31
+ .s-toast-actions {
32
+ @apply mt-2 flex flex-wrap gap-2;
33
+ }
34
+
31
35
  .s-toast-close {
32
36
  @apply ml-auto shrink-0;
33
37
  }
@@ -5,6 +5,10 @@
5
5
  :role="liveAttributes.role"
6
6
  :aria-live="liveAttributes.ariaLive"
7
7
  :aria-atomic="liveAttributes.ariaAtomic"
8
+ @mouseenter="emit('lifetime-pause', notification.id, 'pointer')"
9
+ @mouseleave="emit('lifetime-resume', notification.id, 'pointer')"
10
+ @focusin="emit('lifetime-pause', notification.id, 'focus')"
11
+ @focusout="onFocusOut"
8
12
  >
9
13
  <div class="s-toast-icon">
10
14
  <component
@@ -20,40 +24,61 @@
20
24
  <p v-if="notification.message" class="s-toast-body">
21
25
  {{ notification.message }}
22
26
  </p>
27
+ <div v-if="notification.actions?.length" class="s-toast-actions">
28
+ <SButton
29
+ v-for="action in notification.actions"
30
+ :key="action.id"
31
+ size="xs"
32
+ severity="secondary"
33
+ :appearance="action.appearance ?? 'soft'"
34
+ :label="action.label"
35
+ @click="emit('action', { notificationId: notification.id, actionId: action.id })"
36
+ />
37
+ </div>
23
38
  </div>
24
39
 
25
- <div class="s-toast-close">
40
+ <div v-if="notification.dismissible !== false" class="s-toast-close">
26
41
  <SButton
27
- size="sm"
42
+ size="xs"
28
43
  appearance="ghost"
29
44
  icon-only
30
45
  :leading-icon="X"
31
- aria-label="Закрыть"
46
+ :aria-label="t('feedback.closeNotification')"
32
47
  @click="emit('dismiss', notification.id)"
33
48
  />
34
49
  </div>
35
50
  </div>
36
51
  </template>
37
52
 
38
- <script setup lang="ts">
53
+ <script setup lang="ts" generic="Id extends SToastId = string, ActionId extends SToastActionId = string">
39
54
  import { computed } from 'vue'
55
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
40
56
 
41
57
  import { X } from '../../icons/sputnigUiIcons'
42
58
  import { resolveFeedbackLive, resolveFeedbackPresentation } from '../../../internal/feedbackPresentation'
43
59
  import { resolveSemanticToneBinding } from '../../../internal/semanticTone'
44
- import type { Notification } from '../../../stores/useNotifierStore';
60
+ import type {
61
+ SToastActionId,
62
+ SToastActionIntent,
63
+ SToastId,
64
+ SToastPresentation,
65
+ } from '../data-display/toast'
45
66
  import SButton from '../controls/SButton.vue'
46
67
 
47
68
  defineOptions({ inheritAttrs: false })
48
69
 
49
70
  const props = defineProps<{
50
- notification: Notification
71
+ notification: SToastPresentation<Id, ActionId>
51
72
  }>()
52
73
 
53
74
  const emit = defineEmits<{
54
- dismiss: [id: string]
75
+ dismiss: [id: Id]
76
+ action: [intent: SToastActionIntent<Id, ActionId>]
77
+ 'lifetime-pause': [id: Id, reason: 'pointer' | 'focus']
78
+ 'lifetime-resume': [id: Id, reason: 'pointer' | 'focus']
55
79
  }>()
56
- const presentation = computed(() => resolveFeedbackPresentation(props.notification.severity))
80
+ const { t } = useUiKitLocale()
81
+ const presentation = computed(() => resolveFeedbackPresentation(props.notification.severity, t))
57
82
  const toneBinding = computed(() => resolveSemanticToneBinding(
58
83
  'SToastItem',
59
84
  'notification.severity',
@@ -61,5 +86,16 @@ const toneBinding = computed(() => resolveSemanticToneBinding(
61
86
  ['info', 'success', 'warn', 'danger'] as const,
62
87
  ))
63
88
  const liveAttributes = computed(() => resolveFeedbackLive(props.notification.severity, 'auto'))
89
+
90
+ function onFocusOut(event: FocusEvent): void {
91
+ const currentTarget = event.currentTarget
92
+ const relatedTarget = event.relatedTarget
93
+ if (
94
+ currentTarget instanceof HTMLElement
95
+ && relatedTarget instanceof Node
96
+ && currentTarget.contains(relatedTarget)
97
+ ) return
98
+ emit('lifetime-resume', props.notification.id, 'focus')
99
+ }
64
100
  </script>
65
101
  <style lang="postcss" src="./SToastItem.css" scoped></style>
@@ -217,6 +217,7 @@
217
217
 
218
218
  <script setup lang="ts" generic="T extends object, K extends SelectionKey">
219
219
  import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref } from 'vue'
220
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
220
221
  import type { PropType } from 'vue'
221
222
  import { Check, ChevronDown, ChevronRight, Minus } from '../../icons/sputnigUiIcons'
222
223
  import {
@@ -247,6 +248,7 @@ const props = defineProps<{
247
248
  position: number
248
249
  setSize: number
249
250
  }>()
251
+ const { t } = useUiKitLocale()
250
252
 
251
253
  const slots = defineSlots<{
252
254
  'col-left': (props: STreeNodeContentScope<T, K>) => unknown
@@ -336,12 +338,14 @@ const nodeIndent = computed(() => {
336
338
  if (runtime.density.value === 'compact') return `${props.level * 0.85 + 0.25}rem`
337
339
  return `${props.level === 0 ? 1 : props.level * 1.5}rem`
338
340
  })
339
- const toggleLabel = computed(() =>
340
- `${isExpanded.value ? 'Свернуть' : 'Развернуть'} узел ${nodeLabel.value}`,
341
- )
342
- const selectionLabel = computed(() =>
343
- `${isSelected.value || isPartiallySelected.value ? 'Снять выбор' : 'Выбрать'}: ${nodeLabel.value}`,
344
- )
341
+ const toggleLabel = computed(() => t(
342
+ isExpanded.value ? 'tree.collapseNode' : 'tree.expandNode',
343
+ { label: nodeLabel.value },
344
+ ))
345
+ const selectionLabel = computed(() => t(
346
+ isSelected.value || isPartiallySelected.value ? 'tree.deselectNode' : 'tree.selectNode',
347
+ { label: nodeLabel.value },
348
+ ))
345
349
  const selectionPressedState = computed(() => isPartiallySelected.value ? 'mixed' : isSelected.value)
346
350
  const selectionCheckedState = computed(() => isPartiallySelected.value ? 'mixed' : isSelected.value)
347
351
 
@@ -689,7 +693,7 @@ onBeforeUnmount(() => {
689
693
  }
690
694
 
691
695
  .s-tree-node-wrapper--compact .s-tree-node {
692
- min-height: var(--s-control-hitbox-xs);
696
+ min-height: var(--s-control-hitbox-2xs);
693
697
  gap: 0.25rem;
694
698
  padding: 0 0.25rem;
695
699
  }
@@ -709,6 +713,10 @@ onBeforeUnmount(() => {
709
713
  padding-right: 0.78rem;
710
714
  }
711
715
 
716
+ .s-tree-node-wrapper--overlay-actions > .s-tree-node-hitbox .s-tree-node-content-shell {
717
+ position: relative;
718
+ }
719
+
712
720
  .s-tree-node-wrapper--overlay-actions .s-tree-node-right {
713
721
  position: relative;
714
722
  z-index: var(--s-layer-sticky);
@@ -716,7 +724,7 @@ onBeforeUnmount(() => {
716
724
  justify-content: flex-end;
717
725
  }
718
726
 
719
- .s-tree-node-wrapper--overlay-actions .s-tree-node-actions {
727
+ .s-tree-node-wrapper--overlay-actions > .s-tree-node-hitbox .s-tree-node-actions {
720
728
  position: absolute;
721
729
  top: 50%;
722
730
  right: 0.42rem;
@@ -727,17 +735,22 @@ onBeforeUnmount(() => {
727
735
  background: color-mix(in srgb, var(--color-surface-0) 98%, transparent);
728
736
  box-shadow: -18px 0 24px color-mix(in srgb, var(--color-surface-0) 86%, transparent);
729
737
  opacity: 0;
738
+ pointer-events: none;
730
739
  transform: translateY(-50%);
731
740
  transition: opacity var(--s-motion-fast) ease, transform var(--s-motion-fast) ease;
732
741
  }
733
742
 
734
- .s-tree-node-wrapper--overlay-actions .s-tree-node-actions--has-persistent {
743
+ .s-tree-node-wrapper--overlay-actions > .s-tree-node-hitbox .s-tree-node-actions--has-persistent {
735
744
  opacity: 1;
745
+ pointer-events: auto;
736
746
  }
737
747
 
738
- .s-tree-node-wrapper--overlay-actions .s-tree-node:hover .s-tree-node-actions,
739
- .s-tree-node-wrapper--overlay-actions .s-tree-node:focus-within .s-tree-node-actions {
748
+ .s-tree-node-wrapper--overlay-actions > .s-tree-node-hitbox:hover > .s-tree-node-row > .s-tree-node-content-shell > .s-tree-node-actions,
749
+ .s-tree-node-wrapper--overlay-actions > .s-tree-node-hitbox:focus-within > .s-tree-node-row > .s-tree-node-content-shell > .s-tree-node-actions,
750
+ .s-tree-node-wrapper--overlay-actions > .s-tree-node-hitbox:hover .s-tree-node > .s-tree-node-right > .s-tree-node-actions,
751
+ .s-tree-node-wrapper--overlay-actions > .s-tree-node-hitbox:focus-within .s-tree-node > .s-tree-node-right > .s-tree-node-actions {
740
752
  opacity: 1;
753
+ pointer-events: auto;
741
754
  transform: translate(-0.04rem, -50%);
742
755
  }
743
756
 
@@ -25,6 +25,7 @@
25
25
 
26
26
  <script setup lang="ts">
27
27
  import { computed, type VNodeChild } from 'vue'
28
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
28
29
  import { useOwnedAttrs } from '../../../internal/ownedAttrs'
29
30
  import { validateBoundedInteger, validateNonEmptyString } from '../../../internal/runtimeContract'
30
31
  import SStack from '../../layout/SStack.vue'
@@ -50,11 +51,12 @@ export interface Props {
50
51
  }
51
52
 
52
53
  const props = withDefaults(defineProps<Props>(), {
53
- emptyText: 'Нет элементов',
54
+ emptyText: undefined,
54
55
  defaultOpen: true,
55
56
  open: undefined,
56
57
  density: 'compact',
57
58
  })
59
+ const { t } = useUiKitLocale()
58
60
 
59
61
  defineEmits<{
60
62
  (e: 'update:open', value: boolean): void
@@ -75,7 +77,7 @@ const validatedCount = computed(() => validateBoundedInteger(
75
77
  const validatedEmptyText = computed(() => validateNonEmptyString(
76
78
  'SKanbanLane',
77
79
  'emptyText',
78
- props.emptyText,
80
+ props.emptyText ?? t('kanban.empty'),
79
81
  ))
80
82
 
81
83
  const ownedAttrs = useOwnedAttrs({ component: 'SKanbanLane', owner: 'collapsible lane composition' })