@pgcorp/ui-kit 0.1.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/LICENSE +21 -0
- package/README.md +157 -0
- package/docs/accessibility.md +27 -0
- package/docs/getting-started.md +80 -0
- package/docs/licensing.md +30 -0
- package/docs/public-api.md +39 -0
- package/docs/security.md +21 -0
- package/docs/theming.md +35 -0
- package/docs/versioning.md +23 -0
- package/index.ts +3 -0
- package/package.json +592 -0
- package/src/components/icons/_internal/generatedSputnigUiIconMarkup.ts +971 -0
- package/src/components/icons/sputnigUiIcons.ts +530 -0
- package/src/components/layout/SAppShell.vue +232 -0
- package/src/components/layout/SDockRegion.vue +200 -0
- package/src/components/layout/SResizeHandle.vue +251 -0
- package/src/components/layout/SSideMenuButton.vue +104 -0
- package/src/components/layout/SSideMenuRail.vue +47 -0
- package/src/components/layout/SStack.css +25 -0
- package/src/components/layout/SStack.vue +57 -0
- package/src/components/layout/SStatusBarShell.css +15 -0
- package/src/components/layout/SStatusBarShell.vue +26 -0
- package/src/components/layout/SWorkbenchLayout.vue +53 -0
- package/src/components/layout/SWorkbenchPanelShell.css +161 -0
- package/src/components/layout/SWorkbenchPanelShell.vue +286 -0
- package/src/components/layout/_internal/SAppBrand.css +45 -0
- package/src/components/layout/_internal/SAppBrand.vue +37 -0
- package/src/components/layout/_internal/SAppBrandContent.vue +30 -0
- package/src/components/layout/types.ts +28 -0
- package/src/components/shared/_internal/SDialogSurface.css +127 -0
- package/src/components/shared/_internal/SDialogSurface.vue +117 -0
- package/src/components/shared/_internal/SDisclosureSummary.css +92 -0
- package/src/components/shared/_internal/SDisclosureSummary.vue +121 -0
- package/src/components/shared/_internal/SListboxGroup.css +18 -0
- package/src/components/shared/_internal/SListboxGroup.vue +24 -0
- package/src/components/shared/_internal/SMenuItem.css +112 -0
- package/src/components/shared/_internal/SMenuItem.vue +213 -0
- package/src/components/shared/_internal/SMenuLayer.css +21 -0
- package/src/components/shared/_internal/SMenuLayer.vue +48 -0
- package/src/components/shared/_internal/SMenuSeparator.css +5 -0
- package/src/components/shared/_internal/SMenuSeparator.vue +13 -0
- package/src/components/shared/_internal/SToastItem.css +65 -0
- package/src/components/shared/_internal/SToastItem.vue +58 -0
- package/src/components/shared/_internal/STreeNode.vue +761 -0
- package/src/components/shared/_internal/dialogSurface.ts +105 -0
- package/src/components/shared/_internal/focusTrap.ts +40 -0
- package/src/components/shared/_internal/listboxContext.ts +16 -0
- package/src/components/shared/_internal/markerContract.ts +10 -0
- package/src/components/shared/_internal/menuContext.ts +23 -0
- package/src/components/shared/_internal/selectionContract.ts +239 -0
- package/src/components/shared/_internal/sidebarGroupContext.ts +31 -0
- package/src/components/shared/_internal/tabsContext.ts +57 -0
- package/src/components/shared/_internal/treeRuntime.ts +203 -0
- package/src/components/shared/_internal/useSelectionRoving.ts +162 -0
- package/src/components/shared/codeLanguages.ts +168 -0
- package/src/components/shared/complex/SKanbanCard.css +8 -0
- package/src/components/shared/complex/SKanbanCard.vue +76 -0
- package/src/components/shared/complex/SKanbanLane.vue +82 -0
- package/src/components/shared/complex/STree.css +24 -0
- package/src/components/shared/complex/STree.vue +288 -0
- package/src/components/shared/complex/treeAdapter.ts +210 -0
- package/src/components/shared/complex/types.ts +102 -0
- package/src/components/shared/containers/SCloudChrome.css +103 -0
- package/src/components/shared/containers/SCloudChrome.vue +87 -0
- package/src/components/shared/containers/SCloudChromeEmpty.css +10 -0
- package/src/components/shared/containers/SCloudChromeEmpty.vue +18 -0
- package/src/components/shared/containers/SCloudChromeRow.css +78 -0
- package/src/components/shared/containers/SCloudChromeRow.vue +108 -0
- package/src/components/shared/containers/SCollapsiblePanel.css +57 -0
- package/src/components/shared/containers/SCollapsiblePanel.vue +360 -0
- package/src/components/shared/containers/SDrawer.css +60 -0
- package/src/components/shared/containers/SDrawer.vue +86 -0
- package/src/components/shared/containers/SFormGrid.css +26 -0
- package/src/components/shared/containers/SFormGrid.vue +46 -0
- package/src/components/shared/containers/SFormGridItem.css +18 -0
- package/src/components/shared/containers/SFormGridItem.vue +29 -0
- package/src/components/shared/containers/SLeftSidebar.vue +74 -0
- package/src/components/shared/containers/SModal.css +27 -0
- package/src/components/shared/containers/SModal.vue +105 -0
- package/src/components/shared/containers/SPageHeader.css +66 -0
- package/src/components/shared/containers/SPageHeader.vue +45 -0
- package/src/components/shared/containers/SPanel.css +134 -0
- package/src/components/shared/containers/SPanel.vue +169 -0
- package/src/components/shared/containers/SPopover.css +35 -0
- package/src/components/shared/containers/SPopover.vue +551 -0
- package/src/components/shared/containers/SSidebarGroup.css +12 -0
- package/src/components/shared/containers/SSidebarGroup.vue +443 -0
- package/src/components/shared/containers/SSidebarSection.css +41 -0
- package/src/components/shared/containers/SSidebarSection.vue +268 -0
- package/src/components/shared/containers/disclosureSummary.ts +48 -0
- package/src/components/shared/containers/popover.ts +72 -0
- package/src/components/shared/containers/sidebar.ts +206 -0
- package/src/components/shared/controls/SButton.css +274 -0
- package/src/components/shared/controls/SButton.vue +211 -0
- package/src/components/shared/controls/SCheckbox.css +65 -0
- package/src/components/shared/controls/SCheckbox.vue +130 -0
- package/src/components/shared/controls/SCheckboxGroup.vue +134 -0
- package/src/components/shared/controls/SChoiceCards.css +29 -0
- package/src/components/shared/controls/SChoiceCards.vue +145 -0
- package/src/components/shared/controls/SColorSelect.vue +146 -0
- package/src/components/shared/controls/SComboboxTrigger.css +35 -0
- package/src/components/shared/controls/SComboboxTrigger.vue +122 -0
- package/src/components/shared/controls/SContextMenu.css +11 -0
- package/src/components/shared/controls/SContextMenu.vue +186 -0
- package/src/components/shared/controls/SContextToggleButton.vue +64 -0
- package/src/components/shared/controls/SDragHandle.vue +100 -0
- package/src/components/shared/controls/SDropdownMenu.css +5 -0
- package/src/components/shared/controls/SDropdownMenu.vue +188 -0
- package/src/components/shared/controls/SField.css +79 -0
- package/src/components/shared/controls/SField.vue +89 -0
- package/src/components/shared/controls/SFieldGroup.css +58 -0
- package/src/components/shared/controls/SFieldGroup.vue +117 -0
- package/src/components/shared/controls/SFieldLabel.css +12 -0
- package/src/components/shared/controls/SFieldLabel.vue +51 -0
- package/src/components/shared/controls/SInlineTokenEditor.css +61 -0
- package/src/components/shared/controls/SInlineTokenEditor.vue +1081 -0
- package/src/components/shared/controls/SInputText.css +66 -0
- package/src/components/shared/controls/SInputText.vue +321 -0
- package/src/components/shared/controls/SInteractiveSurface.css +72 -0
- package/src/components/shared/controls/SInteractiveSurface.vue +326 -0
- package/src/components/shared/controls/SLink.css +114 -0
- package/src/components/shared/controls/SLink.ts +85 -0
- package/src/components/shared/controls/SLink.vue +114 -0
- package/src/components/shared/controls/SListbox.css +31 -0
- package/src/components/shared/controls/SListbox.vue +388 -0
- package/src/components/shared/controls/SListboxOption.css +63 -0
- package/src/components/shared/controls/SListboxOption.vue +85 -0
- package/src/components/shared/controls/SMarker.css +19 -0
- package/src/components/shared/controls/SMarker.vue +33 -0
- package/src/components/shared/controls/SMenuSurface.css +20 -0
- package/src/components/shared/controls/SMenuSurface.vue +333 -0
- package/src/components/shared/controls/SSegmentedControl.css +38 -0
- package/src/components/shared/controls/SSegmentedControl.vue +134 -0
- package/src/components/shared/controls/SSelect.css +12 -0
- package/src/components/shared/controls/SSelect.vue +338 -0
- package/src/components/shared/controls/STextarea.css +31 -0
- package/src/components/shared/controls/STextarea.vue +316 -0
- package/src/components/shared/controls/_internal/SInlineTokenSurface.vue +224 -0
- package/src/components/shared/controls/menu.ts +178 -0
- package/src/components/shared/data-display/SActionCard.css +6 -0
- package/src/components/shared/data-display/SActionCard.vue +49 -0
- package/src/components/shared/data-display/SActionList.css +15 -0
- package/src/components/shared/data-display/SActionList.vue +34 -0
- package/src/components/shared/data-display/SActionListItem.css +114 -0
- package/src/components/shared/data-display/SActionListItem.vue +230 -0
- package/src/components/shared/data-display/SBadge.css +73 -0
- package/src/components/shared/data-display/SBadge.vue +52 -0
- package/src/components/shared/data-display/SCodeBlock.css +56 -0
- package/src/components/shared/data-display/SCodeBlock.vue +188 -0
- package/src/components/shared/data-display/SCodeEditor.css +178 -0
- package/src/components/shared/data-display/SCodeEditor.vue +274 -0
- package/src/components/shared/data-display/SCodeSearchPanel.vue +327 -0
- package/src/components/shared/data-display/SCopyField.vue +77 -0
- package/src/components/shared/data-display/SDocBlock.css +136 -0
- package/src/components/shared/data-display/SDocBlock.vue +358 -0
- package/src/components/shared/data-display/SEmptyState.css +42 -0
- package/src/components/shared/data-display/SEmptyState.vue +79 -0
- package/src/components/shared/data-display/SExpandableText.vue +314 -0
- package/src/components/shared/data-display/SJsonTree.css +6 -0
- package/src/components/shared/data-display/SJsonTree.vue +111 -0
- package/src/components/shared/data-display/SKeyValueGrid.css +37 -0
- package/src/components/shared/data-display/SKeyValueGrid.vue +277 -0
- package/src/components/shared/data-display/SLinkedSystemsList.vue +270 -0
- package/src/components/shared/data-display/SMessage.css +88 -0
- package/src/components/shared/data-display/SMessage.vue +152 -0
- package/src/components/shared/data-display/SMetricCard.css +32 -0
- package/src/components/shared/data-display/SMetricCard.vue +117 -0
- package/src/components/shared/data-display/SProgressBar.css +84 -0
- package/src/components/shared/data-display/SProgressBar.vue +114 -0
- package/src/components/shared/data-display/SProgressIndicator.css +59 -0
- package/src/components/shared/data-display/SProgressIndicator.vue +104 -0
- package/src/components/shared/data-display/SSectionHeader.css +84 -0
- package/src/components/shared/data-display/SSectionHeader.vue +58 -0
- package/src/components/shared/data-display/SStatus.css +90 -0
- package/src/components/shared/data-display/SStatus.vue +79 -0
- package/src/components/shared/data-display/STable.css +83 -0
- package/src/components/shared/data-display/STable.vue +339 -0
- package/src/components/shared/data-display/SToastContainer.css +53 -0
- package/src/components/shared/data-display/SToastContainer.vue +31 -0
- package/src/components/shared/data-display/STooltip.css +114 -0
- package/src/components/shared/data-display/STooltip.vue +550 -0
- package/src/components/shared/data-display/STooltipAnchor.css +21 -0
- package/src/components/shared/data-display/STooltipAnchor.vue +119 -0
- package/src/components/shared/data-display/SVirtualList.css +24 -0
- package/src/components/shared/data-display/SVirtualList.ts +19 -0
- package/src/components/shared/data-display/SVirtualList.vue +361 -0
- package/src/components/shared/data-display/json.ts +136 -0
- package/src/components/shared/data-display/table.ts +76 -0
- package/src/components/shared/database/SDataGrid.css +3 -0
- package/src/components/shared/database/SDataGrid.vue +464 -0
- package/src/components/shared/database/SSqlEditor.vue +363 -0
- package/src/components/shared/database/dataGrid.ts +61 -0
- package/src/components/shared/feedback/SAsyncState.css +26 -0
- package/src/components/shared/feedback/SAsyncState.vue +190 -0
- package/src/components/shared/graph/SGraphViewport.ts +1 -0
- package/src/components/shared/graph/SGraphViewport.vue +858 -0
- package/src/components/shared/graph/_internal/graphViewportContract.ts +362 -0
- package/src/components/shared/markdown.ts +169 -0
- package/src/components/shared/navigation/SBottomNav.vue +692 -0
- package/src/components/shared/navigation/SBreadcrumbs.css +26 -0
- package/src/components/shared/navigation/SBreadcrumbs.vue +155 -0
- package/src/components/shared/navigation/SCatalogNavigator.css +100 -0
- package/src/components/shared/navigation/SCatalogNavigator.vue +308 -0
- package/src/components/shared/navigation/STab.vue +363 -0
- package/src/components/shared/navigation/STabList.vue +442 -0
- package/src/components/shared/navigation/STabPanel.vue +165 -0
- package/src/components/shared/navigation/STabPanels.vue +33 -0
- package/src/components/shared/navigation/STabs.vue +617 -0
- package/src/components/shared/navigation/SWizardSteps.css +69 -0
- package/src/components/shared/navigation/SWizardSteps.vue +171 -0
- package/src/components/shared/navigation/_internal/SCatalogNavigatorGroup.vue +63 -0
- package/src/components/shared/persona/SPersonaProjectPicker.css +36 -0
- package/src/components/shared/persona/SPersonaProjectPicker.vue +361 -0
- package/src/components/shared/persona/SPersonaRunWorkbench.css +109 -0
- package/src/components/shared/persona/SPersonaRunWorkbench.vue +549 -0
- package/src/components/shared/persona/_internal/SPersonaRunConsole.css +40 -0
- package/src/components/shared/persona/_internal/SPersonaRunConsole.vue +298 -0
- package/src/components/shared/persona/_internal/inventory.ts +110 -0
- package/src/components/shared/persona/_internal/labels.ts +79 -0
- package/src/components/shared/persona/presentation.ts +371 -0
- package/src/components/shared/persona/types.ts +256 -0
- package/src/composables/uiPreferencesReset.ts +52 -0
- package/src/composables/useClipboard.ts +37 -0
- package/src/composables/useDialogOverlay.ts +85 -0
- package/src/composables/useDisclosure.ts +40 -0
- package/src/composables/useFloatingPosition.ts +245 -0
- package/src/composables/useNotifier.ts +26 -0
- package/src/composables/useSidebarPanelState.ts +610 -0
- package/src/internal/codeEditorContract.ts +110 -0
- package/src/internal/codeEditorExtensions.ts +27 -0
- package/src/internal/feedbackPresentation.ts +136 -0
- package/src/internal/fieldSurface.ts +59 -0
- package/src/internal/focusNavigation.ts +69 -0
- package/src/internal/inlineTokenEditorContract.ts +136 -0
- package/src/internal/interactiveElement.ts +33 -0
- package/src/internal/layerStack.ts +202 -0
- package/src/internal/linkTarget.ts +256 -0
- package/src/internal/ownedAttrs.ts +464 -0
- package/src/internal/passiveContentContract.ts +129 -0
- package/src/internal/pointerInteractionLease.ts +81 -0
- package/src/internal/runtimeContract.ts +194 -0
- package/src/internal/runtimeTheme.ts +159 -0
- package/src/internal/semanticSizing.ts +60 -0
- package/src/internal/useMenuLayer.ts +129 -0
- package/src/stores/useNotifierStore.ts +69 -0
- package/src/styles/reference.css +4 -0
- package/src/styles/style.css +151 -0
- package/src/styles/tokens.css +836 -0
- package/src/theme.ts +449 -0
- package/src/types/highlight-js-lib.d.ts +76 -0
- package/src/variants.ts +15 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<SContextMenu
|
|
3
|
+
:items="contextMenuItems ?? []"
|
|
4
|
+
:enabled="hasContextMenu"
|
|
5
|
+
:trigger="contextMenuTrigger"
|
|
6
|
+
boundary-layout="contents"
|
|
7
|
+
@select="$emit('context-menu-select', $event)"
|
|
8
|
+
>
|
|
9
|
+
<div
|
|
10
|
+
v-bind="ownedAttrs.bindings()"
|
|
11
|
+
class="s-tab-container"
|
|
12
|
+
:class="{ 's-tab-container--selected': state.active }"
|
|
13
|
+
:data-close-mode="ctx.closeButtonMode.value"
|
|
14
|
+
:data-disabled="state.disabled || undefined"
|
|
15
|
+
:data-editing="editing || undefined"
|
|
16
|
+
:style="containerStyle"
|
|
17
|
+
role="presentation"
|
|
18
|
+
>
|
|
19
|
+
<button
|
|
20
|
+
ref="tabButtonRef"
|
|
21
|
+
class="s-tab__trigger"
|
|
22
|
+
type="button"
|
|
23
|
+
:style="{ visibility: editing ? 'hidden' : undefined }"
|
|
24
|
+
:disabled="disabled"
|
|
25
|
+
:title="title"
|
|
26
|
+
:aria-hidden="editing || undefined"
|
|
27
|
+
:aria-selected="state.active"
|
|
28
|
+
:aria-controls="state.panelId"
|
|
29
|
+
:aria-label="ariaLabel"
|
|
30
|
+
:id="state.tabId"
|
|
31
|
+
:tabindex="editing ? -1 : state.tabIndex"
|
|
32
|
+
:data-editing="editing || undefined"
|
|
33
|
+
role="tab"
|
|
34
|
+
@click="ctx.activateTab(registrationKey)"
|
|
35
|
+
@focus="ctx.focusTab(registrationKey)"
|
|
36
|
+
@keydown="ctx.handleTabKeydown(registrationKey, $event)"
|
|
37
|
+
>
|
|
38
|
+
<PassiveContentBoundary :contract="passiveContentContract">
|
|
39
|
+
<span
|
|
40
|
+
v-if="$slots.leading"
|
|
41
|
+
class="s-tab__leading"
|
|
42
|
+
:aria-hidden="leadingDecorative ? 'true' : undefined"
|
|
43
|
+
>
|
|
44
|
+
<slot name="leading" />
|
|
45
|
+
</span>
|
|
46
|
+
<span v-if="$slots.default" class="s-tab__label">
|
|
47
|
+
<slot />
|
|
48
|
+
</span>
|
|
49
|
+
<span
|
|
50
|
+
v-if="$slots.trailing"
|
|
51
|
+
class="s-tab__trailing"
|
|
52
|
+
:aria-hidden="trailingDecorative ? 'true' : undefined"
|
|
53
|
+
>
|
|
54
|
+
<slot name="trailing" />
|
|
55
|
+
</span>
|
|
56
|
+
</PassiveContentBoundary>
|
|
57
|
+
</button>
|
|
58
|
+
|
|
59
|
+
<div v-if="editing && $slots.editor" class="s-tab__editor" @click.stop @dblclick.stop>
|
|
60
|
+
<slot name="editor" />
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div
|
|
64
|
+
v-if="hasSiblingActions"
|
|
65
|
+
ref="actionsRef"
|
|
66
|
+
class="s-tab__sibling-actions"
|
|
67
|
+
@click.stop
|
|
68
|
+
@dblclick.stop
|
|
69
|
+
@mousedown.stop
|
|
70
|
+
>
|
|
71
|
+
<slot name="actions" />
|
|
72
|
+
<span v-if="$slots.close" class="s-tab__close">
|
|
73
|
+
<slot name="close" />
|
|
74
|
+
</span>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</SContextMenu>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<script setup lang="ts">
|
|
81
|
+
import {
|
|
82
|
+
computed,
|
|
83
|
+
inject,
|
|
84
|
+
onBeforeUnmount,
|
|
85
|
+
onMounted,
|
|
86
|
+
onUpdated,
|
|
87
|
+
ref,
|
|
88
|
+
type VNodeChild,
|
|
89
|
+
} from 'vue'
|
|
90
|
+
import SContextMenu from '../controls/SContextMenu.vue'
|
|
91
|
+
import type { SMenuEntry, SMenuSelectableEntry } from '../controls/menu'
|
|
92
|
+
import { tabsContextKey, type STabsContext } from '../_internal/tabsContext'
|
|
93
|
+
import {
|
|
94
|
+
PassiveContentBoundary,
|
|
95
|
+
useInteractiveLeafRegistration,
|
|
96
|
+
type PassiveContentContract,
|
|
97
|
+
} from '../../../internal/passiveContentContract'
|
|
98
|
+
import { useOwnedAttrs } from '../../../internal/ownedAttrs'
|
|
99
|
+
|
|
100
|
+
defineOptions({
|
|
101
|
+
inheritAttrs: false,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Публичный контракт участника STabs; selection, IDs и keyboard принадлежат owner STabs.
|
|
106
|
+
* Public STabs participant contract; selection, IDs, and keyboard behavior belong to STabs.
|
|
107
|
+
*/
|
|
108
|
+
export interface Props {
|
|
109
|
+
/** Единственная stable identity selection и panel inventory. / Sole stable selection and panel-inventory identity. */
|
|
110
|
+
name: string
|
|
111
|
+
/** Исключает вкладку из активации и roving focus. / Excludes the tab from activation and roving focus. */
|
|
112
|
+
disabled?: boolean
|
|
113
|
+
/** Нативная подсказка tab trigger. / Native tab-trigger tooltip. */
|
|
114
|
+
title?: string
|
|
115
|
+
/** Явное accessible name для icon-only content. / Explicit accessible name for icon-only content. */
|
|
116
|
+
ariaLabel?: string
|
|
117
|
+
/** Показывает editor sibling и исключает trigger из tab order. / Shows the sibling editor and removes the trigger from tab order. */
|
|
118
|
+
editing?: boolean
|
|
119
|
+
/** Скрывает leading slot от accessibility tree, когда он декоративный. / Hides a decorative leading slot from the accessibility tree. */
|
|
120
|
+
leadingDecorative?: boolean
|
|
121
|
+
/** Скрывает trailing slot от accessibility tree, когда он декоративный. / Hides a decorative trailing slot from the accessibility tree. */
|
|
122
|
+
trailingDecorative?: boolean
|
|
123
|
+
/** Контекстные действия, размещаемые на внешнем host, а не внутри trigger. / Context actions hosted outside the tab trigger. */
|
|
124
|
+
contextMenuItems?: readonly SMenuEntry[]
|
|
125
|
+
/** Событие открытия контекстного меню. / Context-menu opening gesture. */
|
|
126
|
+
contextMenuTrigger?: 'contextmenu' | 'click' | 'both'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
130
|
+
disabled: false,
|
|
131
|
+
title: undefined,
|
|
132
|
+
ariaLabel: undefined,
|
|
133
|
+
editing: false,
|
|
134
|
+
leadingDecorative: true,
|
|
135
|
+
trailingDecorative: true,
|
|
136
|
+
contextMenuItems: undefined,
|
|
137
|
+
contextMenuTrigger: 'contextmenu',
|
|
138
|
+
})
|
|
139
|
+
defineEmits<{
|
|
140
|
+
'context-menu-select': [entry: SMenuSelectableEntry]
|
|
141
|
+
}>()
|
|
142
|
+
const ownedAttrs = useOwnedAttrs({ component: 'STab', owner: 'tab participant container' })
|
|
143
|
+
const slots = defineSlots<{
|
|
144
|
+
/** Основная метка вкладки. / Primary tab label. */
|
|
145
|
+
default?: () => VNodeChild
|
|
146
|
+
/** Leading content; decorative by default. / Leading content; decorative by default. */
|
|
147
|
+
leading?: () => VNodeChild
|
|
148
|
+
/** Trailing content; decorative by default. / Trailing content; decorative by default. */
|
|
149
|
+
trailing?: () => VNodeChild
|
|
150
|
+
/** Focusable actions rendered as trigger siblings. / Focusable actions rendered as trigger siblings. */
|
|
151
|
+
actions?: () => VNodeChild
|
|
152
|
+
/** Close action rendered as a trigger sibling. / Close action rendered as a trigger sibling. */
|
|
153
|
+
close?: () => VNodeChild
|
|
154
|
+
/** Rename/editor control rendered as a trigger sibling. / Rename/editor control rendered as a trigger sibling. */
|
|
155
|
+
editor?: () => VNodeChild
|
|
156
|
+
}>()
|
|
157
|
+
|
|
158
|
+
const maybeCtx = inject<STabsContext>(tabsContextKey)
|
|
159
|
+
if (!maybeCtx) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
'STab должен использоваться внутри STabs. / STab must be used inside STabs.',
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
const ctx = maybeCtx
|
|
165
|
+
|
|
166
|
+
const tabButtonRef = ref<HTMLButtonElement | null>(null)
|
|
167
|
+
const actionsRef = ref<HTMLElement | null>(null)
|
|
168
|
+
const siblingActionsWidth = ref(0)
|
|
169
|
+
let actionsResizeObserver: ResizeObserver | null = null
|
|
170
|
+
let observedActionsElement: HTMLElement | null = null
|
|
171
|
+
|
|
172
|
+
useInteractiveLeafRegistration({ owner: 'STab' })
|
|
173
|
+
const passiveContentContract: PassiveContentContract = {
|
|
174
|
+
owner: 'STab',
|
|
175
|
+
region: 'passive tab trigger content',
|
|
176
|
+
guidance: 'Передайте focusable controls через actions, close или editor slot. / Use the actions, close, or editor slot for focusable controls.',
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const tabElement = (): HTMLElement | null => {
|
|
180
|
+
return tabButtonRef.value
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const registrationKey = ctx.registerTab({
|
|
184
|
+
tabKey: props.name,
|
|
185
|
+
disabled: () => props.disabled,
|
|
186
|
+
element: tabElement,
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
const state = computed(() => ctx.getTabState(registrationKey))
|
|
190
|
+
const hasSiblingActions = computed(() => Boolean(slots.actions || slots.close))
|
|
191
|
+
const hasContextMenu = computed(() => Boolean(props.contextMenuItems?.length))
|
|
192
|
+
const containerStyle = computed(() => {
|
|
193
|
+
const siblingSpace = hasSiblingActions.value ? siblingActionsWidth.value : 0
|
|
194
|
+
const basePaddingInline = 'var(--s-tab-base-padding-inline)'
|
|
195
|
+
const paddingInlineEnd = ctx.closeButtonMode.value === 'overlay' && siblingSpace > 0
|
|
196
|
+
? `calc(${basePaddingInline} + ${siblingSpace}px + var(--s-tab-sibling-actions-gap))`
|
|
197
|
+
: basePaddingInline
|
|
198
|
+
return {
|
|
199
|
+
'--s-tab-sibling-actions-space': `${siblingSpace}px`,
|
|
200
|
+
'--s-tab-padding-inline-start': basePaddingInline,
|
|
201
|
+
'--s-tab-padding-inline-end': paddingInlineEnd,
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
function updateSiblingActionsWidth(): void {
|
|
206
|
+
siblingActionsWidth.value = actionsRef.value?.offsetWidth ?? 0
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function syncActionsResizeObserver(): void {
|
|
210
|
+
const nextElement = actionsRef.value
|
|
211
|
+
if (observedActionsElement === nextElement) return
|
|
212
|
+
actionsResizeObserver?.disconnect()
|
|
213
|
+
actionsResizeObserver = null
|
|
214
|
+
observedActionsElement = nextElement
|
|
215
|
+
if (typeof ResizeObserver !== 'undefined' && nextElement) {
|
|
216
|
+
actionsResizeObserver = new ResizeObserver(updateSiblingActionsWidth)
|
|
217
|
+
actionsResizeObserver.observe(nextElement)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
onMounted(() => {
|
|
222
|
+
updateSiblingActionsWidth()
|
|
223
|
+
syncActionsResizeObserver()
|
|
224
|
+
ctx.notifyTabOrderChanged()
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
onUpdated(() => {
|
|
228
|
+
if (props.name !== registrationKey) {
|
|
229
|
+
throw new Error('STab: name is immutable for the lifetime of a mounted participant')
|
|
230
|
+
}
|
|
231
|
+
updateSiblingActionsWidth()
|
|
232
|
+
syncActionsResizeObserver()
|
|
233
|
+
ctx.notifyTabOrderChanged()
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
onBeforeUnmount(() => {
|
|
237
|
+
actionsResizeObserver?.disconnect()
|
|
238
|
+
observedActionsElement = null
|
|
239
|
+
ctx.unregisterTab(registrationKey)
|
|
240
|
+
})
|
|
241
|
+
</script>
|
|
242
|
+
|
|
243
|
+
<style lang="postcss" scoped>
|
|
244
|
+
@reference "../../../styles/reference.css";
|
|
245
|
+
|
|
246
|
+
.s-tab-container {
|
|
247
|
+
@apply relative box-border inline-flex min-w-0 flex-none items-center whitespace-nowrap;
|
|
248
|
+
flex: var(--s-tab-flex);
|
|
249
|
+
width: var(--s-tab-width);
|
|
250
|
+
min-width: var(--s-tab-min-width);
|
|
251
|
+
max-width: var(--s-tab-max-width);
|
|
252
|
+
height: var(--s-tab-row-height);
|
|
253
|
+
border-bottom: var(--s-tab-indicator-width) solid transparent;
|
|
254
|
+
border-radius: var(--s-tab-radius);
|
|
255
|
+
overflow: hidden;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.s-tab-container--selected {
|
|
259
|
+
border-color: var(--s-tab-selected-border-color);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.s-tab__trigger {
|
|
263
|
+
@apply relative inline-flex min-w-0 flex-1 items-center justify-center border-0 bg-transparent text-sm font-medium leading-5;
|
|
264
|
+
align-self: stretch;
|
|
265
|
+
width: 100%;
|
|
266
|
+
min-height: var(--s-tab-trigger-min-height);
|
|
267
|
+
margin: 0;
|
|
268
|
+
padding-block-start: calc(var(--s-tab-padding-block) + var(--s-tab-content-offset-y));
|
|
269
|
+
padding-block-end: var(--s-tab-padding-block);
|
|
270
|
+
padding-inline-start: var(--s-tab-padding-inline-start);
|
|
271
|
+
padding-inline-end: var(--s-tab-padding-inline-end);
|
|
272
|
+
border-radius: inherit;
|
|
273
|
+
color: var(--s-tab-color);
|
|
274
|
+
cursor: pointer;
|
|
275
|
+
flex-direction: var(--s-tab-direction);
|
|
276
|
+
gap: var(--s-tab-gap);
|
|
277
|
+
font-family: inherit;
|
|
278
|
+
text-align: center;
|
|
279
|
+
touch-action: manipulation;
|
|
280
|
+
transition:
|
|
281
|
+
background-color var(--s-motion-fast) ease,
|
|
282
|
+
color var(--s-motion-fast) ease,
|
|
283
|
+
transform var(--s-motion-fast) ease;
|
|
284
|
+
appearance: none;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.s-tab__trigger:hover:not(:disabled) {
|
|
288
|
+
background-color: var(--s-tab-hover-background);
|
|
289
|
+
color: var(--s-tab-hover-color);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.s-tab__trigger[aria-selected='true'] {
|
|
293
|
+
color: var(--s-tab-selected-color);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.s-tab__trigger:focus-visible {
|
|
297
|
+
z-index: 1;
|
|
298
|
+
outline: var(--s-focus-ring-width) solid var(--s-focus-ring-color);
|
|
299
|
+
outline-offset: var(--s-focus-ring-inset-offset);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.s-tab__trigger:active:not(:disabled) {
|
|
303
|
+
transform: translateY(var(--s-tab-active-translate-y));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.s-tab__trigger:disabled {
|
|
307
|
+
color: var(--s-tab-disabled-color);
|
|
308
|
+
cursor: not-allowed;
|
|
309
|
+
opacity: var(--s-tab-disabled-opacity);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
:global(.dark) .s-tab__trigger {
|
|
313
|
+
color: var(--s-tab-color);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
:global(.dark) .s-tab__trigger:hover:not(:disabled) {
|
|
317
|
+
background-color: var(--s-tab-hover-background);
|
|
318
|
+
color: var(--s-tab-hover-color);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
:global(.dark) .s-tab__trigger[aria-selected='true'] {
|
|
322
|
+
color: var(--s-tab-selected-color);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
:global(.dark) .s-tab__trigger:disabled {
|
|
326
|
+
color: var(--s-tab-disabled-color);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.s-tab__leading,
|
|
330
|
+
.s-tab__trailing,
|
|
331
|
+
.s-tab__close {
|
|
332
|
+
@apply inline-flex shrink-0 items-center;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.s-tab__label {
|
|
336
|
+
display: var(--s-tab-label-display);
|
|
337
|
+
flex: var(--s-tab-label-flex);
|
|
338
|
+
min-width: 0;
|
|
339
|
+
overflow: hidden;
|
|
340
|
+
font-size: var(--s-tab-label-size);
|
|
341
|
+
line-height: var(--s-tab-label-line-height);
|
|
342
|
+
text-overflow: ellipsis;
|
|
343
|
+
white-space: nowrap;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.s-tab__sibling-actions {
|
|
347
|
+
@apply inline-flex shrink-0 items-center gap-0.5;
|
|
348
|
+
z-index: var(--s-layer-sticky);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.s-tab-container[data-close-mode='overlay'] .s-tab__sibling-actions {
|
|
352
|
+
@apply absolute inset-y-0 right-0;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.s-tab-container[data-editing='true'] .s-tab__editor {
|
|
356
|
+
padding-right: calc(var(--s-tab-sibling-actions-space) + var(--s-tab-sibling-actions-gap));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.s-tab__editor {
|
|
360
|
+
@apply absolute inset-0 z-0 flex min-w-0 items-center;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
</style>
|