@pgcorp/ui-kit 0.8.1 → 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 (113) hide show
  1. package/README.md +332 -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/docs/theming.md +17 -0
  7. package/package.json +108 -50
  8. package/src/components/layout/SAppShell.vue +3 -1
  9. package/src/components/layout/SDockRegion.vue +5 -3
  10. package/src/components/layout/SResizeHandle.vue +45 -5
  11. package/src/components/layout/SWorkbenchPanelShell.vue +4 -2
  12. package/src/components/shared/_internal/SDialogSurface.css +23 -0
  13. package/src/components/shared/_internal/SDialogSurface.vue +9 -2
  14. package/src/components/shared/_internal/SToastItem.css +4 -0
  15. package/src/components/shared/_internal/SToastItem.vue +44 -8
  16. package/src/components/shared/_internal/STreeNode.vue +24 -11
  17. package/src/components/shared/_internal/dialogSurface.ts +7 -1
  18. package/src/components/shared/complex/SKanbanLane.vue +4 -2
  19. package/src/components/shared/containers/SCloudChromeRow.vue +3 -2
  20. package/src/components/shared/containers/SDrawer.css +11 -2
  21. package/src/components/shared/containers/SDrawer.vue +48 -9
  22. package/src/components/shared/containers/SModal.vue +5 -2
  23. package/src/components/shared/containers/SPanel.vue +4 -2
  24. package/src/components/shared/containers/SPopover.vue +7 -3
  25. package/src/components/shared/containers/SUiKitLocaleProvider.vue +57 -0
  26. package/src/components/shared/controls/SButton.css +14 -10
  27. package/src/components/shared/controls/SCombobox.vue +8 -6
  28. package/src/components/shared/controls/SComboboxTrigger.css +7 -4
  29. package/src/components/shared/controls/SComboboxTrigger.vue +5 -2
  30. package/src/components/shared/controls/SContextToggleButton.vue +6 -4
  31. package/src/components/shared/controls/SDragHandle.vue +8 -4
  32. package/src/components/shared/controls/SDropdownMenu.vue +7 -4
  33. package/src/components/shared/controls/SInputText.css +5 -4
  34. package/src/components/shared/controls/SListbox.vue +4 -2
  35. package/src/components/shared/controls/SSelect.vue +4 -2
  36. package/src/components/shared/controls/STextarea.ts +13 -0
  37. package/src/components/shared/controls/STextarea.vue +391 -37
  38. package/src/components/shared/controls/_internal/SInlineTokenSurface.vue +4 -2
  39. package/src/components/shared/data-display/SChart.vue +7 -5
  40. package/src/components/shared/data-display/SChip.vue +3 -1
  41. package/src/components/shared/data-display/SCodeBlock.css +4 -0
  42. package/src/components/shared/data-display/SCodeBlock.vue +46 -22
  43. package/src/components/shared/data-display/SCodeEditor.css +17 -0
  44. package/src/components/shared/data-display/SCodeEditor.vue +173 -8
  45. package/src/components/shared/data-display/SCodeSearchPanel.vue +48 -33
  46. package/src/components/shared/data-display/SCodeWorkspaceEditor.css +13 -0
  47. package/src/components/shared/data-display/SCodeWorkspaceEditor.vue +355 -0
  48. package/src/components/shared/data-display/SControlledToastViewport.css +89 -0
  49. package/src/components/shared/data-display/SControlledToastViewport.vue +205 -0
  50. package/src/components/shared/data-display/SCopyField.vue +12 -10
  51. package/src/components/shared/data-display/SDiffViewer.css +122 -0
  52. package/src/components/shared/data-display/SDiffViewer.vue +499 -0
  53. package/src/components/shared/data-display/SDocBlock.vue +99 -71
  54. package/src/components/shared/data-display/SExpandableText.vue +10 -8
  55. package/src/components/shared/data-display/SJsonTree.vue +4 -2
  56. package/src/components/shared/data-display/SLinkedSystemsList.vue +4 -2
  57. package/src/components/shared/data-display/SMessage.vue +6 -6
  58. package/src/components/shared/data-display/SRichDocument.css +8 -0
  59. package/src/components/shared/data-display/SRichDocument.vue +65 -0
  60. package/src/components/shared/data-display/SScrollViewport.css +53 -0
  61. package/src/components/shared/data-display/SScrollViewport.vue +470 -0
  62. package/src/components/shared/data-display/STable.vue +38 -19
  63. package/src/components/shared/data-display/SToastContainer.vue +22 -17
  64. package/src/components/shared/data-display/SVirtualList.ts +33 -0
  65. package/src/components/shared/data-display/SVirtualList.vue +321 -36
  66. package/src/components/shared/data-display/_internal/SCodeTokenLine.css +72 -0
  67. package/src/components/shared/data-display/_internal/SCodeTokenLine.vue +79 -0
  68. package/src/components/shared/data-display/_internal/SRichBlockNode.css +85 -0
  69. package/src/components/shared/data-display/_internal/SRichBlockNode.vue +282 -0
  70. package/src/components/shared/data-display/_internal/SRichInlineNode.css +6 -0
  71. package/src/components/shared/data-display/_internal/SRichInlineNode.vue +76 -0
  72. package/src/components/shared/data-display/_internal/SRichMath.css +42 -0
  73. package/src/components/shared/data-display/_internal/SRichMath.vue +102 -0
  74. package/src/components/shared/data-display/codeEditor.ts +200 -0
  75. package/src/components/shared/data-display/codeWorkspace.ts +233 -0
  76. package/src/components/shared/data-display/diff.ts +541 -0
  77. package/src/components/shared/data-display/richDocument.ts +876 -0
  78. package/src/components/shared/data-display/scrollViewport.ts +47 -0
  79. package/src/components/shared/data-display/toast.ts +194 -0
  80. package/src/components/shared/database/SDataGrid.vue +7 -4
  81. package/src/components/shared/database/SSqlEditor.vue +39 -39
  82. package/src/components/shared/feedback/SAsyncState.vue +3 -1
  83. package/src/components/shared/graph/SGraphViewport.vue +11 -9
  84. package/src/components/shared/navigation/SBreadcrumbs.vue +8 -5
  85. package/src/components/shared/navigation/SCatalogNavigator.vue +26 -20
  86. package/src/components/shared/navigation/STabList.vue +10 -6
  87. package/src/components/shared/navigation/STabs.vue +15 -11
  88. package/src/components/shared/navigation/SWizardSteps.vue +4 -2
  89. package/src/components/shared/persona/SPersonaProjectPicker.vue +31 -27
  90. package/src/components/shared/persona/SPersonaRunWorkbench.vue +39 -33
  91. package/src/components/shared/persona/_internal/SPersonaRunConsole.vue +8 -6
  92. package/src/components/shared/persona/_internal/labels.ts +66 -57
  93. package/src/components/shared/persona/presentation.ts +140 -110
  94. package/src/composables/useFloatingPosition.ts +39 -2
  95. package/src/composables/useUiKitLocale.ts +17 -0
  96. package/src/internal/codeHighlight.ts +110 -0
  97. package/src/internal/diffEngine.ts +464 -0
  98. package/src/internal/diffRuntime.ts +189 -0
  99. package/src/internal/feedbackPresentation.ts +33 -14
  100. package/src/internal/localeContext.ts +22 -0
  101. package/src/internal/ownedAttrs.ts +8 -0
  102. package/src/internal/runtimeContract.ts +11 -9
  103. package/src/internal/semanticSizing.ts +13 -0
  104. package/src/locales/catalog.ts +634 -0
  105. package/src/locales/locale.ts +472 -0
  106. package/src/locales/messages.generated.ts +1826 -0
  107. package/src/locales/messages.ts +150 -0
  108. package/src/stores/useNotifierStore.ts +61 -44
  109. package/src/styles/tokens.css +23 -2
  110. package/src/theme.ts +59 -32
  111. package/src/workers/diff.worker.ts +73 -0
  112. package/src/workers/diffProtocol.ts +155 -0
  113. package/src/components/shared/data-display/SToastContainer.css +0 -53
@@ -6,7 +6,7 @@
6
6
  :id="inputId"
7
7
  :model-value="validatedSearch"
8
8
  :label="label"
9
- :placeholder="placeholder"
9
+ :placeholder="contract.placeholder"
10
10
  :disabled="disabled"
11
11
  :readonly="readonly"
12
12
  :required="required"
@@ -39,7 +39,7 @@
39
39
  :disabled="disabled"
40
40
  :readonly="readonly"
41
41
  :invalid="invalid"
42
- :empty-label="emptyLabel"
42
+ :empty-label="contract.emptyLabel"
43
43
  focus-mode="activedescendant"
44
44
  :active-value="activeValue"
45
45
  @update:model-value="onListboxUpdate"
@@ -95,6 +95,7 @@ type ComponentProps<TKey extends PublicSelectionKey> = SharedProps<TKey> & {
95
95
 
96
96
  <script setup lang="ts" generic="TKey extends SelectionKey = string">
97
97
  import { computed, nextTick, onBeforeUnmount, shallowRef, useId, watch } from 'vue'
98
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
98
99
  import { useFloatingPosition } from '../../../composables/useFloatingPosition'
99
100
  import { registerLayer, type LayerRegistration } from '../../../internal/layerStack'
100
101
  import { useOwnedAttrs } from '../../../internal/ownedAttrs'
@@ -121,18 +122,19 @@ defineOptions({ inheritAttrs: false })
121
122
  const props = withDefaults(defineProps<ComponentProps<TKey>>(), {
122
123
  filterMode: 'local',
123
124
  label: undefined,
124
- placeholder: 'Начните вводить для поиска',
125
+ placeholder: undefined,
125
126
  disabled: false,
126
127
  readonly: false,
127
128
  required: false,
128
129
  invalid: false,
129
130
  errorMessage: undefined,
130
131
  helpText: undefined,
131
- emptyLabel: 'Нет доступных вариантов',
132
+ emptyLabel: undefined,
132
133
  id: undefined,
133
134
  size: 'md',
134
135
  allowCustomValue: false,
135
136
  })
137
+ const { t } = useUiKitLocale()
136
138
  const emit = defineEmits<{
137
139
  'update:modelValue': [value: TKey | null]
138
140
  'update:search': [value: string]
@@ -162,12 +164,12 @@ const contract = computed(() => ({
162
164
  filterMode: validateExactString(
163
165
  'SCombobox', 'filterMode', props.filterMode, ['local', 'manual'] as const,
164
166
  ),
165
- placeholder: validateNonEmptyString('SCombobox', 'placeholder', props.placeholder),
167
+ placeholder: validateNonEmptyString('SCombobox', 'placeholder', props.placeholder ?? t('forms.searchPlaceholder')),
166
168
  disabled: validateBoolean('SCombobox', 'disabled', props.disabled),
167
169
  readonly: validateBoolean('SCombobox', 'readonly', props.readonly),
168
170
  required: validateBoolean('SCombobox', 'required', props.required),
169
171
  invalid: validateBoolean('SCombobox', 'invalid', props.invalid),
170
- emptyLabel: validateNonEmptyString('SCombobox', 'emptyLabel', props.emptyLabel),
172
+ emptyLabel: validateNonEmptyString('SCombobox', 'emptyLabel', props.emptyLabel ?? t('forms.noOptions')),
171
173
  size: validateExactString('SCombobox', 'size', props.size, ['sm', 'md', 'lg'] as const),
172
174
  allowCustomValue: validateBoolean('SCombobox', 'allowCustomValue', props.allowCustomValue),
173
175
  label: validateOptionalSelectionString('SCombobox', 'label', props.label),
@@ -6,10 +6,13 @@
6
6
 
7
7
  .s-combobox-trigger[data-width='full'] { @apply w-full; }
8
8
  .s-combobox-trigger[data-width='auto'] { @apply w-auto; }
9
- .s-combobox-trigger[data-size='xs'] { min-height: var(--s-control-hitbox-xs); @apply px-2 text-xs; }
10
- .s-combobox-trigger[data-size='sm'] { min-height: var(--s-control-hitbox-sm); @apply px-2.5 text-xs; }
11
- .s-combobox-trigger[data-size='md'] { min-height: var(--s-control-hitbox-md); @apply text-sm; }
12
- .s-combobox-trigger[data-appearance='swatch'] { width: var(--s-control-hitbox-md); @apply justify-center rounded-full border border-transparent bg-transparent p-1; box-shadow: none; }
9
+ .s-combobox-trigger[data-size='xs'] { block-size: var(--s-control-hitbox-xs); @apply px-2 text-xs; }
10
+ .s-combobox-trigger[data-size='sm'] { block-size: var(--s-control-hitbox-sm); @apply px-2.5 text-xs; }
11
+ .s-combobox-trigger[data-size='md'] { block-size: var(--s-control-hitbox-md); @apply text-sm; }
12
+ .s-combobox-trigger[data-appearance='swatch'] { @apply justify-center rounded-full border border-transparent bg-transparent p-1; box-shadow: none; }
13
+ .s-combobox-trigger[data-appearance='swatch'][data-size='xs'] { inline-size: var(--s-control-hitbox-xs); }
14
+ .s-combobox-trigger[data-appearance='swatch'][data-size='sm'] { inline-size: var(--s-control-hitbox-sm); }
15
+ .s-combobox-trigger[data-appearance='swatch'][data-size='md'] { inline-size: var(--s-control-hitbox-md); }
13
16
  .s-combobox-trigger[data-appearance='swatch']:disabled { @apply cursor-not-allowed opacity-50; }
14
17
 
15
18
  .s-combobox-trigger__value {
@@ -29,7 +29,7 @@
29
29
  >
30
30
  <SMarker v-if="marker" :marker="marker" :size="appearance === 'swatch' ? 'lg' : 'sm'" />
31
31
  <span v-if="appearance === 'field'" class="s-combobox-trigger__value">
32
- {{ displayValue || placeholder }}
32
+ {{ displayValue || resolvedPlaceholder }}
33
33
  </span>
34
34
  <span class="s-combobox-trigger__caret" aria-hidden="true">
35
35
  <ChevronsUpDown v-if="appearance === 'field'" />
@@ -40,6 +40,7 @@
40
40
 
41
41
  <script setup lang="ts">
42
42
  import { computed, ref } from 'vue'
43
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
43
44
  import { ChevronDown, ChevronsUpDown } from '../../icons/sputnigUiIcons'
44
45
  import type { InteractiveElementApi } from '../../../internal/interactiveElement'
45
46
  import { useInteractiveLeafRegistration } from '../../../internal/passiveContentContract'
@@ -76,7 +77,7 @@ defineOptions({ inheritAttrs: false })
76
77
 
77
78
  const props = withDefaults(defineProps<Props>(), {
78
79
  displayValue: undefined,
79
- placeholder: 'Выберите значение',
80
+ placeholder: undefined,
80
81
  marker: undefined,
81
82
  appearance: 'field',
82
83
  size: 'md',
@@ -92,6 +93,8 @@ const props = withDefaults(defineProps<Props>(), {
92
93
  taskMappingInternalValue: undefined,
93
94
  taskMappingKind: undefined,
94
95
  })
96
+ const { t } = useUiKitLocale()
97
+ const resolvedPlaceholder = computed(() => props.placeholder ?? t('forms.selectPlaceholder'))
95
98
 
96
99
  const emit = defineEmits<{
97
100
  toggle: [event: MouseEvent | KeyboardEvent]
@@ -17,6 +17,7 @@
17
17
 
18
18
  <script setup lang="ts">
19
19
  import { computed, type Component } from 'vue'
20
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
20
21
  import { Minus, MinusCircle, PlusCircle } from '../../icons/sputnigUiIcons'
21
22
  import { useOwnedAttrs } from '../../../internal/ownedAttrs'
22
23
  import { validateNonEmptyString } from '../../../internal/runtimeContract'
@@ -36,11 +37,12 @@ export interface Props {
36
37
 
37
38
  const props = withDefaults(defineProps<Props>(), {
38
39
  partial: false,
39
- addTitle: 'Добавить в контекст',
40
- removeTitle: 'Убрать из контекста',
40
+ addTitle: undefined,
41
+ removeTitle: undefined,
41
42
  size: 'sm',
42
43
  loading: false,
43
44
  })
45
+ const { t } = useUiKitLocale()
44
46
 
45
47
  const emit = defineEmits<{
46
48
  (e: 'click'): void
@@ -48,8 +50,8 @@ const emit = defineEmits<{
48
50
  const ownedAttrs = useOwnedAttrs({ component: 'SContextToggleButton', owner: 'toggle button' })
49
51
 
50
52
  const accessibleLabels = computed(() => ({
51
- add: validateNonEmptyString('SContextToggleButton', 'addTitle', props.addTitle),
52
- remove: validateNonEmptyString('SContextToggleButton', 'removeTitle', props.removeTitle),
53
+ add: validateNonEmptyString('SContextToggleButton', 'addTitle', props.addTitle ?? t('forms.addToContext')),
54
+ remove: validateNonEmptyString('SContextToggleButton', 'removeTitle', props.removeTitle ?? t('forms.removeFromContext')),
53
55
  }))
54
56
  const accessibleTitle = computed(() => (
55
57
  props.inContext ? accessibleLabels.value.remove : accessibleLabels.value.add
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <SButton
3
3
  v-bind="ownedAttrs.bindings()"
4
- size="sm"
4
+ :size="size"
5
5
  severity="secondary"
6
6
  appearance="ghost"
7
7
  icon-only
@@ -22,20 +22,23 @@
22
22
  <script setup lang="ts">
23
23
  import { computed, ref, watchEffect } from 'vue'
24
24
  import { getSputnigUiIconComponent } from '../../icons/sputnigUiIcons'
25
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
25
26
  import { useOwnedAttrs } from '../../../internal/ownedAttrs'
26
27
  import { validateNonEmptyString } from '../../../internal/runtimeContract'
27
- import SButton from './SButton.vue'
28
+ import SButton, { type SButtonSize } from './SButton.vue'
28
29
 
29
30
  defineOptions({ inheritAttrs: false })
30
31
 
31
32
  const props = withDefaults(defineProps<{
32
33
  label: string
33
34
  orientation?: 'vertical' | 'horizontal'
35
+ size?: SButtonSize
34
36
  canMovePrevious?: boolean
35
37
  canMoveNext?: boolean
36
38
  disabled?: boolean
37
39
  }>(), {
38
40
  orientation: 'vertical',
41
+ size: 'sm',
39
42
  canMovePrevious: false,
40
43
  canMoveNext: false,
41
44
  disabled: false,
@@ -49,14 +52,15 @@ const emit = defineEmits<{
49
52
 
50
53
  const DragIcon = getSputnigUiIconComponent('drag')
51
54
  const ownedAttrs = useOwnedAttrs({ component: 'SDragHandle', owner: 'drag handle command' })
55
+ const { t } = useUiKitLocale()
52
56
  const keyboardActive = ref(false)
53
57
  const validatedLabel = computed(() => validateNonEmptyString('SDragHandle', 'label', props.label))
54
58
  const keyboardShortcuts = computed(() => props.orientation === 'vertical'
55
59
  ? 'Enter Space ArrowUp ArrowDown Escape'
56
60
  : 'Enter Space ArrowLeft ArrowRight Escape')
57
61
  const accessibleLabel = computed(() => keyboardActive.value
58
- ? `Перемещение: ${validatedLabel.value}. Используйте стрелки, Enter — завершить, Escape — отменить`
59
- : `Переместить: ${validatedLabel.value}. Нажмите Enter и используйте стрелки`)
62
+ ? t('layout.dragActive', { label: validatedLabel.value })
63
+ : t('layout.dragIdle', { label: validatedLabel.value }))
60
64
 
61
65
  function setKeyboardActive(active: boolean): void {
62
66
  if (keyboardActive.value === active) return
@@ -13,14 +13,14 @@
13
13
  v-if="isOpen"
14
14
  ref="layerRef"
15
15
  kind="dropdown"
16
- :landmark-label="menuLabel"
16
+ :landmark-label="resolvedMenuLabel"
17
17
  :position="position"
18
18
  :z-index="zIndex"
19
19
  >
20
20
  <SMenuSurface
21
21
  ref="menuSurfaceRef"
22
22
  :id="menuId"
23
- :label="menuLabel"
23
+ :label="resolvedMenuLabel"
24
24
  density="compact"
25
25
  autofocus
26
26
  :initial-focus="initialFocus"
@@ -48,6 +48,7 @@ import {
48
48
  type VNodeRef,
49
49
  } from 'vue'
50
50
  import { useOwnedAttrs, type OwnedAttributeBindings } from '../../../internal/ownedAttrs'
51
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
51
52
  import { useMenuLayer } from '../../../internal/useMenuLayer'
52
53
  import SMenuLayer from '../_internal/SMenuLayer.vue'
53
54
  import type { SMenuLayerApi } from '../_internal/SMenuLayer.vue'
@@ -63,8 +64,10 @@ const props = withDefaults(defineProps<{
63
64
  menuLabel?: string
64
65
  }>(), {
65
66
  align: 'right',
66
- menuLabel: 'Дополнительные действия',
67
+ menuLabel: undefined,
67
68
  })
69
+ const { t } = useUiKitLocale()
70
+ const resolvedMenuLabel = computed(() => props.menuLabel ?? t('dialog.moreActions'))
68
71
  const emit = defineEmits<{
69
72
  select: [entry: SMenuSelectableEntry, event: SMenuActivationEvent]
70
73
  }>()
@@ -180,7 +183,7 @@ function select(item: SMenuSelectableEntry, event: SMenuActivationEvent): void {
180
183
 
181
184
  watchEffect(() => {
182
185
  validateSMenuEntries(props.items)
183
- if (!props.menuLabel.trim()) throw new TypeError('SDropdownMenu: menuLabel must be a non-empty string')
186
+ if (!resolvedMenuLabel.value.trim()) throw new TypeError('SDropdownMenu: menuLabel must be a non-empty string')
184
187
  if (props.align !== 'left' && props.align !== 'right') throw new TypeError("SDropdownMenu: align must be 'left' or 'right'")
185
188
  })
186
189
  </script>
@@ -11,16 +11,17 @@
11
11
  @apply block w-full min-w-0 box-border;
12
12
  }
13
13
 
14
- .s-input-text[data-size='sm'] { @apply px-2.5 py-1.5 text-xs; }
15
- .s-input-text[data-size='md'] { @apply px-3 py-2 text-sm; }
16
- .s-input-text[data-size='lg'] { @apply px-4 py-2.5 text-lg; }
14
+ .s-input-text[data-size='sm'] { block-size: var(--s-control-hitbox-sm); @apply px-2.5 py-0 text-xs; }
15
+ .s-input-text[data-size='md'] { block-size: var(--s-control-hitbox-md); @apply px-3 py-0 text-sm; }
16
+ .s-input-text[data-size='lg'] { block-size: var(--s-control-hitbox-lg); @apply px-4 py-0 text-lg; }
17
17
 
18
18
  .s-input-text--monospace {
19
19
  @apply font-mono;
20
20
  }
21
21
 
22
22
  .s-input-text[data-appearance='grid-cell'] {
23
- @apply h-8 rounded-none border-transparent bg-transparent px-2 py-1 text-sm shadow-none;
23
+ block-size: var(--s-density-row-compact);
24
+ @apply rounded-none border-transparent bg-transparent px-2 py-0 text-sm shadow-none;
24
25
  }
25
26
 
26
27
  .s-input-text[data-appearance='workbench-title'] {
@@ -140,6 +140,7 @@ type ComponentProps<TKey extends PublicSelectionKey> = SharedProps<TKey> & (
140
140
 
141
141
  <script setup lang="ts" generic="TKey extends SelectionKey = string">
142
142
  import { computed, onBeforeUnmount, provide, useId } from 'vue'
143
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
143
144
  import { useOwnedAttrs } from '../../../internal/ownedAttrs'
144
145
  import { useInteractiveLeafRegistration } from '../../../internal/passiveContentContract'
145
146
  import {
@@ -168,12 +169,13 @@ const props = withDefaults(defineProps<ComponentProps<TKey>>(), {
168
169
  readonly: false,
169
170
  invalid: false,
170
171
  variant: 'select',
171
- emptyLabel: 'Нет доступных вариантов',
172
+ emptyLabel: undefined,
172
173
  clearOptionLabel: undefined,
173
174
  id: undefined,
174
175
  focusMode: 'roving',
175
176
  activeValue: undefined,
176
177
  })
178
+ const { t } = useUiKitLocale()
177
179
  const emit = defineEmits<{
178
180
  'update:modelValue': [value: TKey | null] | [value: readonly TKey[]]
179
181
  'update:activeValue': [value: TKey | null]
@@ -200,7 +202,7 @@ const contract = computed(() => {
200
202
  ? `s-listbox-${generatedId}`
201
203
  : validateDomId('SListbox', 'id', props.id),
202
204
  label: validateNonEmptyString('SListbox', 'label', props.label),
203
- emptyLabel: validateNonEmptyString('SListbox', 'emptyLabel', props.emptyLabel),
205
+ emptyLabel: validateNonEmptyString('SListbox', 'emptyLabel', props.emptyLabel ?? t('forms.noOptions')),
204
206
  variant: validateExactString(
205
207
  'SListbox', 'variant', props.variant, ['select', 'color'] as const,
206
208
  ),
@@ -105,6 +105,7 @@ type ComponentProps<TKey extends PublicSelectionKey> = SharedProps<TKey> & (
105
105
 
106
106
  <script setup lang="ts" generic="TKey extends SelectionKey = string">
107
107
  import { computed, nextTick, onBeforeUnmount, ref, useId } from 'vue'
108
+ import { useUiKitLocale } from '../../../composables/useUiKitLocale'
108
109
  import { useFloatingPosition } from '../../../composables/useFloatingPosition'
109
110
  import type { FloatingPlacement } from '../../../composables/useFloatingPosition'
110
111
  import { findRelativeTabTarget } from '../../../internal/focusNavigation'
@@ -135,7 +136,7 @@ defineOptions({ inheritAttrs: false })
135
136
 
136
137
  const props = withDefaults(defineProps<ComponentProps<TKey>>(), {
137
138
  label: undefined,
138
- placeholder: 'Выберите значение',
139
+ placeholder: undefined,
139
140
  disabled: false,
140
141
  readonly: false,
141
142
  required: false,
@@ -151,6 +152,7 @@ const props = withDefaults(defineProps<ComponentProps<TKey>>(), {
151
152
  title: undefined,
152
153
  selectionMode: undefined,
153
154
  })
155
+ const { t } = useUiKitLocale()
154
156
  const emit = defineEmits<{
155
157
  'update:modelValue': [value: TKey | null] | [value: readonly TKey[]]
156
158
  }>()
@@ -176,7 +178,7 @@ const contract = computed(() => {
176
178
  label: props.label === undefined
177
179
  ? undefined
178
180
  : validateNonEmptyString('SSelect', 'label', props.label),
179
- placeholder: validateNonEmptyString('SSelect', 'placeholder', props.placeholder),
181
+ placeholder: validateNonEmptyString('SSelect', 'placeholder', props.placeholder ?? t('forms.selectPlaceholder')),
180
182
  disabled: validateBoolean('SSelect', 'disabled', props.disabled),
181
183
  readonly: validateBoolean('SSelect', 'readonly', props.readonly),
182
184
  required: validateBoolean('SSelect', 'required', props.required),
@@ -0,0 +1,13 @@
1
+ export type {
2
+ Props as STextareaProps,
3
+ STextareaAppearance,
4
+ STextareaAutocomplete,
5
+ STextareaSuggestionPopupRole,
6
+ STextareaSuggestions,
7
+ STextareaReplaceOptions,
8
+ STextareaResizeContract,
9
+ STextareaSelection,
10
+ STextareaSelectionDirection,
11
+ STextareaSize,
12
+ STextareaState,
13
+ } from './STextarea.vue'