niuma-ui 1.0.0 → 1.0.2
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/CHANGELOG.md +50 -1
- package/NOTICE +2 -2
- package/package.json +13 -5
- package/src/__tests__/RsButton.spec.ts +47 -0
- package/src/__tests__/RsCard.spec.ts +160 -1
- package/src/__tests__/RsConfirmDialog.spec.ts +127 -0
- package/src/__tests__/RsContextMenu.spec.ts +12 -0
- package/src/__tests__/RsDateTimePicker.spec.ts +11 -0
- package/src/__tests__/RsDescriptions.spec.ts +50 -0
- package/src/__tests__/RsDialog.spec.ts +117 -0
- package/src/__tests__/RsDrawer.spec.ts +96 -3
- package/src/__tests__/RsDynamicTags.spec.ts +52 -0
- package/src/__tests__/RsForm.spec.ts +245 -1
- package/src/__tests__/RsInput.spec.ts +15 -1
- package/src/__tests__/RsMenu.spec.ts +406 -14
- package/src/__tests__/RsPagination.spec.ts +67 -2
- package/src/__tests__/RsSelect.spec.ts +42 -1
- package/src/__tests__/RsSwitch.spec.ts +44 -0
- package/src/__tests__/RsTable.a11y.spec.ts +83 -0
- package/src/__tests__/RsTable.dom-baseline.spec.ts +87 -0
- package/src/__tests__/RsTable.perf.spec.ts +23 -4
- package/src/__tests__/RsTable.spec.ts +63 -8
- package/src/__tests__/RsTable.ssr.spec.ts +71 -0
- package/src/__tests__/RsTable.summary.spec.ts +45 -0
- package/src/__tests__/RsTabs.spec.ts +102 -4
- package/src/__tests__/RsTerminal.spec.ts +1 -1
- package/src/__tests__/RsTimePicker.spec.ts +11 -0
- package/src/__tests__/RsUpload.spec.ts +62 -6
- package/src/__tests__/createRsDialog.spec.ts +145 -0
- package/src/__tests__/form-rules.spec.ts +76 -0
- package/src/__tests__/perf-budgets.ts +32 -0
- package/src/__tests__/rs-table-api.spec.ts +206 -0
- package/src/__tests__/rs-table-compat-matrix.spec.ts +108 -0
- package/src/__tests__/rs-table-echarts-adapter.spec.ts +43 -0
- package/src/__tests__/rs-table-grid-nav.spec.ts +63 -0
- package/src/__tests__/rs-table-isolation.spec.ts +158 -0
- package/src/__tests__/split-pane-utils.spec.ts +21 -0
- package/src/__tests__/table-chart-utils.spec.ts +88 -0
- package/src/__tests__/table-summary-utils.spec.ts +62 -0
- package/src/__tests__/table-utils.spec.ts +124 -0
- package/src/__tests__/theme.spec.ts +25 -0
- package/src/__tests__/useRsTableColumnResize.spec.ts +25 -0
- package/src/__tests__/useRsTableCore.perf.spec.ts +170 -0
- package/src/components/RsAlert.vue +212 -0
- package/src/components/RsButton.vue +145 -21
- package/src/components/RsCard.vue +200 -16
- package/src/components/RsConfirmDialog.vue +215 -28
- package/src/components/RsContextMenu.vue +51 -13
- package/src/components/RsDatePicker.vue +267 -34
- package/src/components/RsDateTimePicker.vue +19 -2
- package/src/components/RsDescriptions.vue +186 -0
- package/src/components/RsDescriptionsItem.vue +32 -0
- package/src/components/RsDialog.vue +363 -51
- package/src/components/RsDivider.vue +89 -0
- package/src/components/RsDrawer.vue +558 -33
- package/src/components/RsDropdown.vue +33 -2
- package/src/components/RsDynamicTags.vue +517 -0
- package/src/components/RsForm.vue +97 -8
- package/src/components/RsInput.vue +80 -82
- package/src/components/RsInputNumber.vue +64 -23
- package/src/components/RsLabel.vue +20 -5
- package/src/components/RsLoadingBar.vue +151 -0
- package/src/components/RsMenu.vue +73 -15
- package/src/components/RsMenuItems.vue +147 -9
- package/src/components/RsPagination.vue +93 -14
- package/src/components/RsRadio.vue +81 -0
- package/src/components/RsRadioItem.vue +156 -0
- package/src/components/RsSelect.vue +67 -58
- package/src/components/RsSplitPane.vue +69 -1
- package/src/components/RsSwitch.vue +179 -0
- package/src/components/RsTable.vue +653 -2555
- package/src/components/RsTabs.vue +415 -83
- package/src/components/RsTag.vue +191 -0
- package/src/components/RsTerminal.vue +3 -3
- package/src/components/RsTimePicker.vue +44 -5
- package/src/components/RsTimePickerColumns.vue +136 -77
- package/src/components/RsToaster.vue +58 -18
- package/src/components/RsTree.vue +39 -21
- package/src/components/RsUpload.vue +145 -12
- package/src/components/RsVNodeHost.vue +20 -0
- package/src/components/button-utils.ts +39 -0
- package/src/components/context-menu-utils.ts +6 -0
- package/src/components/date-picker-utils.ts +84 -4
- package/src/components/descriptions-utils.ts +24 -0
- package/src/components/dialog-utils.ts +147 -0
- package/src/components/dialog-window.ts +74 -9
- package/src/components/drawer-utils.ts +73 -0
- package/src/components/form-rules.ts +257 -0
- package/src/components/form-utils.ts +52 -2
- package/src/components/menu-utils.ts +11 -0
- package/src/components/overlay-utils.ts +3 -0
- package/src/components/radio-utils.ts +12 -0
- package/src/components/reka.ts +5 -0
- package/src/components/select-utils.ts +21 -2
- package/src/components/split-pane-utils.ts +65 -12
- package/src/components/table/RsTableBody.vue +217 -0
- package/src/components/table/RsTableBodyRow.vue +90 -1
- package/src/components/table/RsTableColGroup.vue +41 -0
- package/src/components/table/RsTableHeader.vue +158 -0
- package/src/components/table/RsTableSummaryRow.vue +52 -0
- package/src/components/table/rs-table-api.ts +99 -0
- package/src/components/table/rs-table-compat-matrix.ts +71 -0
- package/src/components/table/rs-table-echarts-adapter.ts +81 -0
- package/src/components/table/rs-table-feature-host.ts +178 -0
- package/src/components/table/rs-table-grid-nav.ts +122 -0
- package/src/components/table/rs-table-header-types.ts +47 -0
- package/src/components/table/rs-table-module-registry.ts +72 -0
- package/src/components/table/rs-table-props.ts +274 -0
- package/src/components/table/rs-table-view-context.ts +258 -0
- package/src/components/table/rs-table.css +84 -6
- package/src/components/table/table-chart-utils.ts +165 -0
- package/src/components/table/table-features.ts +284 -0
- package/src/components/table/table-summary-utils.ts +194 -0
- package/src/components/table-utils.ts +452 -2
- package/src/components/tabs-utils.ts +142 -2
- package/src/components/terminal-utils.ts +1 -1
- package/src/components/terminal-wheel.ts +1 -1
- package/src/components/time-picker-utils.ts +76 -3
- package/src/components/upload-utils.ts +122 -0
- package/src/components/virtual-list-utils.ts +15 -2
- package/src/composables/assembleRsTableApi.ts +79 -0
- package/src/composables/bindRsTableViewContext.ts +269 -0
- package/src/composables/createRsDialog.ts +357 -0
- package/src/composables/createRsTableEditEmitBridge.ts +38 -0
- package/src/composables/useRsLoadingBar.ts +36 -0
- package/src/composables/useRsTable.ts +134 -0
- package/src/composables/useRsTableA11y.ts +52 -0
- package/src/composables/useRsTableChartBridge.ts +79 -0
- package/src/composables/useRsTableColumnLayout.ts +320 -0
- package/src/composables/useRsTableColumnResize.ts +244 -0
- package/src/composables/useRsTableColumnVirtual.ts +180 -0
- package/src/composables/useRsTableColumns.ts +200 -0
- package/src/composables/useRsTableContextMenu.ts +257 -0
- package/src/composables/useRsTableCore.ts +256 -0
- package/src/composables/useRsTableEditActions.ts +606 -0
- package/src/composables/useRsTableEditLayer.ts +251 -0
- package/src/composables/useRsTableEngine.ts +357 -0
- package/src/composables/useRsTableGridKeyboard.ts +123 -0
- package/src/composables/useRsTableHeadless.ts +137 -0
- package/src/composables/useRsTableInteraction.ts +433 -0
- package/src/composables/useRsTableScrollHost.ts +75 -0
- package/src/composables/useRsTableScrollLayout.ts +255 -0
- package/src/composables/useRsTableSelectionSource.ts +89 -0
- package/src/composables/useRsTableShell.ts +416 -0
- package/src/composables/useRsTableShellChrome.ts +170 -0
- package/src/composables/useRsTableSummary.ts +113 -0
- package/src/composables/useRsTableViewProvide.ts +263 -0
- package/src/composables/useRsTableVirtual.ts +154 -0
- package/src/composables/useRsTabsNav.ts +4 -0
- package/src/composables/useTableEdit.ts +1 -1
- package/src/icons/lucide.ts +2 -2
- package/src/index.ts +309 -9
- package/src/locale/messages.ts +30 -0
- package/src/styles.css +305 -52
- package/src/theme/brand.example.css +21 -2
- package/src/theme/presets.ts +4 -0
- package/src/theme/types.ts +67 -0
- package/src/components/RsTableColgroup.vue +0 -17
- package/src/components/RsTableHeaderRow.vue +0 -30
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, nextTick, ref } from 'vue'
|
|
2
|
+
import { computed, nextTick, ref, useSlots } from 'vue'
|
|
3
3
|
import {
|
|
4
4
|
DropdownMenuContent,
|
|
5
5
|
DropdownMenuItem,
|
|
@@ -13,12 +13,20 @@ import {
|
|
|
13
13
|
} from './reka'
|
|
14
14
|
import { useRsI18n } from '../composables/useRsI18n'
|
|
15
15
|
import { useRsTabsNav } from '../composables/useRsTabsNav'
|
|
16
|
+
import RsContextMenu from './RsContextMenu.vue'
|
|
16
17
|
import RsIcon from './RsIcon.vue'
|
|
17
18
|
import {
|
|
19
|
+
buildTabContextMenuItems,
|
|
20
|
+
getNextTabAfterBatchClose,
|
|
18
21
|
getNextTabAfterClose,
|
|
19
22
|
isTabClosable,
|
|
23
|
+
isTabFixed,
|
|
20
24
|
isTabRenamable,
|
|
25
|
+
resolveTabsToClose,
|
|
21
26
|
type RsTabItem,
|
|
27
|
+
type RsTabsCloseAction,
|
|
28
|
+
type RsTabsContentGap,
|
|
29
|
+
type RsTabsJustify,
|
|
22
30
|
type RsTabsOverflow,
|
|
23
31
|
type RsTabsSize,
|
|
24
32
|
type RsTabsVariant,
|
|
@@ -31,39 +39,77 @@ const props = withDefaults(
|
|
|
31
39
|
items: RsTabItem[]
|
|
32
40
|
size?: RsTabsSize
|
|
33
41
|
variant?: RsTabsVariant
|
|
42
|
+
/**
|
|
43
|
+
* 仅渲染导航栏,不渲染内容面板;内容由业务自行根据 v-model 切换。
|
|
44
|
+
* 需要内容插槽且无外框时,用 borderless 替代(保留具名内容插槽)。
|
|
45
|
+
*/
|
|
34
46
|
panelless?: boolean
|
|
47
|
+
/**
|
|
48
|
+
* 无外框:去掉 body/nav 边框与底色,内容区默认无内边距。
|
|
49
|
+
* 适合嵌在 Card 内的登录 Tab 等,业务无需 :deep 清边框。
|
|
50
|
+
*/
|
|
51
|
+
borderless?: boolean
|
|
52
|
+
/**
|
|
53
|
+
* 标题栏与内容区间距(borderless 下控制 panel 上边距)。
|
|
54
|
+
* 也可用样式覆盖 --rs-tabs-content-gap。
|
|
55
|
+
*/
|
|
56
|
+
contentGap?: RsTabsContentGap
|
|
57
|
+
/**
|
|
58
|
+
* 标签栏对齐方式;stretch/evenly 用于等分铺满,避免业务 :deep 改 list。
|
|
59
|
+
*/
|
|
60
|
+
justify?: RsTabsJustify
|
|
35
61
|
closable?: boolean
|
|
36
62
|
addable?: boolean
|
|
37
63
|
maxCount?: number
|
|
38
64
|
/** 双击标签重命名 */
|
|
39
65
|
renamable?: boolean
|
|
40
|
-
/**
|
|
66
|
+
/** 按住标签拖动排序(整项可拖,不展示手柄) */
|
|
41
67
|
draggable?: boolean
|
|
42
68
|
/** 标签过多:scroll 横向滚动 · dropdown 折叠到「更多」 */
|
|
43
69
|
overflow?: RsTabsOverflow | false
|
|
70
|
+
/**
|
|
71
|
+
* 顶栏导航右键菜单:关闭 / 关闭其他 / 关闭左侧 / 关闭右侧 / 关闭全部
|
|
72
|
+
*(对齐 GTabs / Chrome / VS Code 多页签)
|
|
73
|
+
*/
|
|
74
|
+
contextMenu?: boolean
|
|
75
|
+
/**
|
|
76
|
+
* 切换前校验(对齐 Ant Design Tabs beforeLeave)。
|
|
77
|
+
* 返回 false 时阻止切换;支持异步。
|
|
78
|
+
*/
|
|
79
|
+
beforeLeave?: (to: string, from: string) => boolean | void | Promise<boolean | void>
|
|
44
80
|
}>(),
|
|
45
81
|
{
|
|
46
82
|
size: 'md',
|
|
47
83
|
variant: 'line',
|
|
48
84
|
panelless: false,
|
|
85
|
+
borderless: false,
|
|
86
|
+
contentGap: 'none',
|
|
87
|
+
justify: 'start',
|
|
49
88
|
closable: false,
|
|
50
89
|
addable: false,
|
|
51
90
|
renamable: false,
|
|
52
91
|
draggable: false,
|
|
53
92
|
overflow: false,
|
|
93
|
+
contextMenu: false,
|
|
54
94
|
},
|
|
55
95
|
)
|
|
56
96
|
|
|
57
97
|
const emit = defineEmits<{
|
|
58
98
|
close: [value: string]
|
|
99
|
+
/** 批量关闭(右键菜单 / 中键以外的批量动作),values 为待移除的标签 value */
|
|
100
|
+
closeBatch: [values: string[], action: RsTabsCloseAction, anchor?: string]
|
|
59
101
|
add: []
|
|
60
102
|
rename: [value: string, label: string]
|
|
61
103
|
reorder: [dragValue: string, dropValue: string]
|
|
104
|
+
/** 右键菜单选中动作 */
|
|
105
|
+
contextMenu: [action: RsTabsCloseAction, value: string]
|
|
62
106
|
}>()
|
|
63
107
|
|
|
108
|
+
const slots = useSlots()
|
|
64
109
|
const { t } = useRsI18n()
|
|
65
110
|
const itemsRef = computed(() => props.items)
|
|
66
111
|
const overflowMode = computed(() => props.overflow)
|
|
112
|
+
const hasExtra = computed(() => Boolean(slots.extra))
|
|
67
113
|
const canAdd = computed(() => {
|
|
68
114
|
if (!props.addable) return false
|
|
69
115
|
if (props.maxCount == null) return true
|
|
@@ -73,6 +119,7 @@ const canAdd = computed(() => {
|
|
|
73
119
|
const navRef = ref<HTMLElement | null>(null)
|
|
74
120
|
const measureRef = ref<HTMLElement | null>(null)
|
|
75
121
|
const overflowWrapRef = ref<HTMLElement | null>(null)
|
|
122
|
+
const extraRef = ref<HTMLElement | null>(null)
|
|
76
123
|
|
|
77
124
|
const {
|
|
78
125
|
navViewportRef,
|
|
@@ -96,6 +143,7 @@ const {
|
|
|
96
143
|
navRef,
|
|
97
144
|
measureRef,
|
|
98
145
|
overflowRef: overflowWrapRef,
|
|
146
|
+
extraRef,
|
|
99
147
|
addButtonWidth: 36,
|
|
100
148
|
})
|
|
101
149
|
|
|
@@ -104,6 +152,7 @@ const renameDraft = ref('')
|
|
|
104
152
|
const dragValue = ref<string | null>(null)
|
|
105
153
|
const dragOverValue = ref<string | null>(null)
|
|
106
154
|
let renameInputEl: HTMLInputElement | null = null
|
|
155
|
+
let leaveLock = false
|
|
107
156
|
|
|
108
157
|
function setRenameInputRef(el: unknown, item: RsTabItem) {
|
|
109
158
|
if (!(el instanceof HTMLInputElement) || renamingValue.value !== item.value) return
|
|
@@ -127,17 +176,78 @@ const moreLabel = computed(() => {
|
|
|
127
176
|
return t('tabs.more')
|
|
128
177
|
})
|
|
129
178
|
|
|
179
|
+
const contextMenuLabels = computed(() => ({
|
|
180
|
+
close: t('tabs.closeTab'),
|
|
181
|
+
closeOthers: t('tabs.closeOthers'),
|
|
182
|
+
closeLeft: t('tabs.closeLeft'),
|
|
183
|
+
closeRight: t('tabs.closeRight'),
|
|
184
|
+
closeAll: t('tabs.closeAll'),
|
|
185
|
+
}))
|
|
186
|
+
|
|
130
187
|
function closeAriaLabel(item: RsTabItem): string {
|
|
131
188
|
return t('tabs.close', 'Close {label}').replace('{label}', item.label)
|
|
132
189
|
}
|
|
133
190
|
|
|
191
|
+
function contextItemsFor(item: RsTabItem) {
|
|
192
|
+
return buildTabContextMenuItems(
|
|
193
|
+
props.items,
|
|
194
|
+
item,
|
|
195
|
+
props.closable,
|
|
196
|
+
contextMenuLabels.value,
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function labelTitle(item: RsTabItem): string | undefined {
|
|
201
|
+
return item.label.length > 12 ? item.label : undefined
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function onSelectTab(next: string | number): Promise<void> {
|
|
205
|
+
const value = String(next)
|
|
206
|
+
if (value === model.value || leaveLock) return
|
|
207
|
+
if (props.beforeLeave) {
|
|
208
|
+
leaveLock = true
|
|
209
|
+
try {
|
|
210
|
+
const ok = await props.beforeLeave(value, model.value)
|
|
211
|
+
if (ok === false) return
|
|
212
|
+
} finally {
|
|
213
|
+
leaveLock = false
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
model.value = value
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function applyCloseValues(
|
|
220
|
+
values: string[],
|
|
221
|
+
action: RsTabsCloseAction,
|
|
222
|
+
anchor?: string,
|
|
223
|
+
): void {
|
|
224
|
+
if (!values.length) return
|
|
225
|
+
if (action === 'close' && values.length === 1) {
|
|
226
|
+
const closed = values[0]!
|
|
227
|
+
const next = getNextTabAfterClose(props.items, closed, model.value)
|
|
228
|
+
if (next && model.value === closed) model.value = next
|
|
229
|
+
emit('close', closed)
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const remaining = props.items.filter((item) => !values.includes(item.value))
|
|
234
|
+
const next = getNextTabAfterBatchClose(remaining, model.value, anchor)
|
|
235
|
+
if (next !== undefined && next !== model.value) model.value = next
|
|
236
|
+
else if (next === undefined) model.value = ''
|
|
237
|
+
emit('closeBatch', values, action, anchor)
|
|
238
|
+
}
|
|
239
|
+
|
|
134
240
|
function onCloseTab(item: RsTabItem): void {
|
|
135
241
|
if (item.disabled || !isTabClosable(item, props.closable)) return
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
242
|
+
applyCloseValues([item.value], 'close', item.value)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function onContextSelect(actionKey: string, item: RsTabItem): void {
|
|
246
|
+
const action = actionKey as RsTabsCloseAction
|
|
247
|
+
if (!['close', 'others', 'left', 'right', 'all'].includes(action)) return
|
|
248
|
+
const values = resolveTabsToClose(props.items, action, item.value, props.closable)
|
|
249
|
+
emit('contextMenu', action, item.value)
|
|
250
|
+
applyCloseValues(values, action, item.value)
|
|
141
251
|
}
|
|
142
252
|
|
|
143
253
|
function onAddTab(): void {
|
|
@@ -146,7 +256,26 @@ function onAddTab(): void {
|
|
|
146
256
|
}
|
|
147
257
|
|
|
148
258
|
function onOverflowSelect(value: string): void {
|
|
149
|
-
|
|
259
|
+
void onSelectTab(value)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** 中键关闭(对齐浏览器 / VS Code 页签) */
|
|
263
|
+
function onTabAuxClick(item: RsTabItem, event: MouseEvent): void {
|
|
264
|
+
if (event.button !== 1) return
|
|
265
|
+
event.preventDefault()
|
|
266
|
+
onCloseTab(item)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** 纵向滚轮转为横向滚动(scroll 溢出模式) */
|
|
270
|
+
function onNavWheel(event: WheelEvent): void {
|
|
271
|
+
if (!useScrollOverflow.value) return
|
|
272
|
+
const viewport = navViewportRef.value
|
|
273
|
+
if (!viewport) return
|
|
274
|
+
if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) return
|
|
275
|
+
if (viewport.scrollWidth <= viewport.clientWidth) return
|
|
276
|
+
event.preventDefault()
|
|
277
|
+
viewport.scrollLeft += event.deltaY
|
|
278
|
+
onNavScroll()
|
|
150
279
|
}
|
|
151
280
|
|
|
152
281
|
async function startRename(item: RsTabItem): Promise<void> {
|
|
@@ -170,8 +299,24 @@ function commitRename(item: RsTabItem): void {
|
|
|
170
299
|
cancelRename()
|
|
171
300
|
}
|
|
172
301
|
|
|
302
|
+
function canDragItem(item: RsTabItem): boolean {
|
|
303
|
+
return props.draggable && !item.disabled && !isTabFixed(item)
|
|
304
|
+
}
|
|
305
|
+
|
|
173
306
|
function onDragStart(item: RsTabItem, event: DragEvent): void {
|
|
174
|
-
if (!
|
|
307
|
+
if (!canDragItem(item)) {
|
|
308
|
+
event.preventDefault()
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
// 关闭 / 重命名控件上不启动拖拽,避免误触
|
|
312
|
+
const target = event.target
|
|
313
|
+
if (
|
|
314
|
+
target instanceof Element &&
|
|
315
|
+
target.closest('.rs-tabs__close, .rs-tabs__rename-input')
|
|
316
|
+
) {
|
|
317
|
+
event.preventDefault()
|
|
318
|
+
return
|
|
319
|
+
}
|
|
175
320
|
dragValue.value = item.value
|
|
176
321
|
event.dataTransfer?.setData('text/plain', item.value)
|
|
177
322
|
if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'
|
|
@@ -179,6 +324,7 @@ function onDragStart(item: RsTabItem, event: DragEvent): void {
|
|
|
179
324
|
|
|
180
325
|
function onDragOver(item: RsTabItem, event: DragEvent): void {
|
|
181
326
|
if (!props.draggable || !dragValue.value || dragValue.value === item.value) return
|
|
327
|
+
if (isTabFixed(item)) return
|
|
182
328
|
event.preventDefault()
|
|
183
329
|
dragOverValue.value = item.value
|
|
184
330
|
}
|
|
@@ -190,7 +336,7 @@ function onDragLeave(item: RsTabItem): void {
|
|
|
190
336
|
function onDrop(item: RsTabItem, event: DragEvent): void {
|
|
191
337
|
if (!props.draggable || !dragValue.value) return
|
|
192
338
|
event.preventDefault()
|
|
193
|
-
if (dragValue.value !== item.value) {
|
|
339
|
+
if (dragValue.value !== item.value && !isTabFixed(item)) {
|
|
194
340
|
emit('reorder', dragValue.value, item.value)
|
|
195
341
|
}
|
|
196
342
|
dragValue.value = null
|
|
@@ -206,18 +352,24 @@ function onDragEnd(): void {
|
|
|
206
352
|
|
|
207
353
|
<template>
|
|
208
354
|
<TabsRoot
|
|
209
|
-
|
|
355
|
+
:model-value="model"
|
|
210
356
|
class="rs-tabs"
|
|
211
357
|
:class="[
|
|
212
358
|
`rs-tabs--${variant}`,
|
|
213
359
|
`rs-tabs--${size}`,
|
|
360
|
+
`rs-tabs--justify-${justify}`,
|
|
361
|
+
`rs-tabs--content-gap-${contentGap}`,
|
|
214
362
|
{
|
|
215
363
|
'rs-tabs--panelless': panelless,
|
|
364
|
+
'rs-tabs--borderless': borderless,
|
|
216
365
|
'rs-tabs--scrollable': useScrollOverflow,
|
|
217
366
|
'rs-tabs--dropdown-overflow': useDropdownOverflow,
|
|
367
|
+
'rs-tabs--has-extra': hasExtra,
|
|
368
|
+
'rs-tabs--draggable': draggable,
|
|
218
369
|
},
|
|
219
370
|
]"
|
|
220
371
|
:aria-label="t('tabs.label')"
|
|
372
|
+
@update:model-value="onSelectTab"
|
|
221
373
|
>
|
|
222
374
|
<div :class="panelless ? 'rs-tabs__shell' : 'rs-tabs__body'">
|
|
223
375
|
<div
|
|
@@ -258,72 +410,86 @@ function onDragEnd(): void {
|
|
|
258
410
|
ref="navViewportRef"
|
|
259
411
|
class="rs-tabs__nav-viewport"
|
|
260
412
|
@scroll="onNavScroll"
|
|
413
|
+
@wheel="onNavWheel"
|
|
261
414
|
>
|
|
262
415
|
<TabsList class="rs-tabs__list">
|
|
263
|
-
<
|
|
416
|
+
<RsContextMenu
|
|
264
417
|
v-for="item in tabBarItems"
|
|
265
418
|
:key="item.value"
|
|
266
|
-
:
|
|
267
|
-
:disabled="
|
|
268
|
-
|
|
269
|
-
:class="{
|
|
270
|
-
'rs-tabs__trigger--dragging': dragValue === item.value,
|
|
271
|
-
'rs-tabs__trigger--drag-over': dragOverValue === item.value,
|
|
272
|
-
}"
|
|
273
|
-
:data-tab-value="item.value"
|
|
274
|
-
@dragover="onDragOver(item, $event)"
|
|
275
|
-
@dragleave="onDragLeave(item)"
|
|
276
|
-
@drop="onDrop(item, $event)"
|
|
419
|
+
:items="contextItemsFor(item)"
|
|
420
|
+
:disabled="!contextMenu"
|
|
421
|
+
@select="(key) => onContextSelect(key, item)"
|
|
277
422
|
>
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
423
|
+
<TabsTrigger
|
|
424
|
+
:value="item.value"
|
|
425
|
+
:disabled="item.disabled"
|
|
426
|
+
class="rs-tabs__trigger"
|
|
427
|
+
:class="{
|
|
428
|
+
'rs-tabs__trigger--dragging': dragValue === item.value,
|
|
429
|
+
'rs-tabs__trigger--drag-over': dragOverValue === item.value,
|
|
430
|
+
'rs-tabs__trigger--fixed': isTabFixed(item),
|
|
431
|
+
'rs-tabs__trigger--movable': canDragItem(item),
|
|
432
|
+
}"
|
|
433
|
+
:data-tab-value="item.value"
|
|
434
|
+
:data-fixed="isTabFixed(item) ? 'true' : undefined"
|
|
435
|
+
:draggable="canDragItem(item) || undefined"
|
|
283
436
|
@dragstart="onDragStart(item, $event)"
|
|
437
|
+
@dragover="onDragOver(item, $event)"
|
|
438
|
+
@dragleave="onDragLeave(item)"
|
|
439
|
+
@drop="onDrop(item, $event)"
|
|
284
440
|
@dragend="onDragEnd"
|
|
285
|
-
@
|
|
286
|
-
@click.stop
|
|
287
|
-
>
|
|
288
|
-
<RsIcon name="grip-vertical" :size="12" />
|
|
289
|
-
</span>
|
|
290
|
-
<RsIcon v-if="item.icon" :name="item.icon" :size="14" class="rs-tabs__icon" />
|
|
291
|
-
<input
|
|
292
|
-
v-if="renamingValue === item.value"
|
|
293
|
-
:ref="(el) => setRenameInputRef(el, item)"
|
|
294
|
-
v-model="renameDraft"
|
|
295
|
-
class="rs-tabs__rename-input"
|
|
296
|
-
:aria-label="t('tabs.rename')"
|
|
297
|
-
:placeholder="t('tabs.renamePlaceholder')"
|
|
298
|
-
@keydown.enter.prevent="commitRename(item)"
|
|
299
|
-
@keydown.escape.prevent="cancelRename"
|
|
300
|
-
@blur="commitRename(item)"
|
|
301
|
-
@mousedown.stop
|
|
302
|
-
@click.stop
|
|
303
|
-
@dblclick.stop
|
|
304
|
-
/>
|
|
305
|
-
<span
|
|
306
|
-
v-else
|
|
307
|
-
class="rs-tabs__label"
|
|
308
|
-
@dblclick.stop="startRename(item)"
|
|
309
|
-
>
|
|
310
|
-
{{ item.label }}
|
|
311
|
-
</span>
|
|
312
|
-
<span v-if="item.badge != null && item.badge !== ''" class="rs-tabs__badge">
|
|
313
|
-
{{ item.badge }}
|
|
314
|
-
</span>
|
|
315
|
-
<button
|
|
316
|
-
v-if="isTabClosable(item, closable)"
|
|
317
|
-
type="button"
|
|
318
|
-
class="rs-tabs__close"
|
|
319
|
-
:aria-label="closeAriaLabel(item)"
|
|
320
|
-
:disabled="item.disabled"
|
|
321
|
-
@mousedown.stop.prevent
|
|
322
|
-
@click.stop="onCloseTab(item)"
|
|
441
|
+
@auxclick="onTabAuxClick(item, $event)"
|
|
323
442
|
>
|
|
324
|
-
<RsIcon
|
|
325
|
-
|
|
326
|
-
|
|
443
|
+
<RsIcon
|
|
444
|
+
v-if="isTabFixed(item)"
|
|
445
|
+
name="pin"
|
|
446
|
+
:size="12"
|
|
447
|
+
class="rs-tabs__pin"
|
|
448
|
+
/>
|
|
449
|
+
<RsIcon v-if="item.icon" :name="item.icon" :size="14" class="rs-tabs__icon" />
|
|
450
|
+
<input
|
|
451
|
+
v-if="renamingValue === item.value"
|
|
452
|
+
:ref="(el) => setRenameInputRef(el, item)"
|
|
453
|
+
v-model="renameDraft"
|
|
454
|
+
class="rs-tabs__rename-input"
|
|
455
|
+
:aria-label="t('tabs.rename')"
|
|
456
|
+
:placeholder="t('tabs.renamePlaceholder')"
|
|
457
|
+
draggable="false"
|
|
458
|
+
@keydown.enter.prevent="commitRename(item)"
|
|
459
|
+
@keydown.escape.prevent="cancelRename"
|
|
460
|
+
@blur="commitRename(item)"
|
|
461
|
+
@mousedown.stop
|
|
462
|
+
@click.stop
|
|
463
|
+
@dblclick.stop
|
|
464
|
+
@dragstart.stop.prevent
|
|
465
|
+
/>
|
|
466
|
+
<span
|
|
467
|
+
v-else
|
|
468
|
+
class="rs-tabs__label"
|
|
469
|
+
:title="labelTitle(item)"
|
|
470
|
+
@dblclick.stop="startRename(item)"
|
|
471
|
+
>
|
|
472
|
+
{{ item.label }}
|
|
473
|
+
</span>
|
|
474
|
+
<span v-if="item.badge != null && item.badge !== ''" class="rs-tabs__badge">
|
|
475
|
+
{{ item.badge }}
|
|
476
|
+
</span>
|
|
477
|
+
<button
|
|
478
|
+
v-if="isTabClosable(item, closable)"
|
|
479
|
+
type="button"
|
|
480
|
+
class="rs-tabs__close"
|
|
481
|
+
:aria-label="closeAriaLabel(item)"
|
|
482
|
+
:disabled="item.disabled"
|
|
483
|
+
draggable="false"
|
|
484
|
+
@mousedown.stop.prevent
|
|
485
|
+
@click.stop="onCloseTab(item)"
|
|
486
|
+
@auxclick.stop.prevent
|
|
487
|
+
@dragstart.stop.prevent
|
|
488
|
+
>
|
|
489
|
+
<RsIcon name="x" :size="12" />
|
|
490
|
+
</button>
|
|
491
|
+
</TabsTrigger>
|
|
492
|
+
</RsContextMenu>
|
|
327
493
|
</TabsList>
|
|
328
494
|
</div>
|
|
329
495
|
|
|
@@ -379,6 +545,10 @@ function onDragEnd(): void {
|
|
|
379
545
|
>
|
|
380
546
|
<RsIcon name="chevron-right" :size="14" />
|
|
381
547
|
</button>
|
|
548
|
+
|
|
549
|
+
<div v-if="hasExtra" ref="extraRef" class="rs-tabs__extra">
|
|
550
|
+
<slot name="extra" />
|
|
551
|
+
</div>
|
|
382
552
|
</div>
|
|
383
553
|
|
|
384
554
|
<template v-if="!panelless">
|
|
@@ -402,6 +572,14 @@ function onDragEnd(): void {
|
|
|
402
572
|
display: flex;
|
|
403
573
|
flex-direction: column;
|
|
404
574
|
width: 100%;
|
|
575
|
+
/* 标题与内容间距;可由 contentGap 或样式覆盖 */
|
|
576
|
+
--rs-tabs-content-gap: 0px;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/* 非激活面板必须彻底隐藏,避免多页内容叠层 */
|
|
580
|
+
.rs-tabs__panel[data-state='inactive'],
|
|
581
|
+
.rs-tabs__panel[hidden] {
|
|
582
|
+
display: none !important;
|
|
405
583
|
}
|
|
406
584
|
|
|
407
585
|
.rs-tabs__shell,
|
|
@@ -416,6 +594,7 @@ function onDragEnd(): void {
|
|
|
416
594
|
display: flex;
|
|
417
595
|
align-items: stretch;
|
|
418
596
|
min-width: 0;
|
|
597
|
+
width: 100%;
|
|
419
598
|
}
|
|
420
599
|
|
|
421
600
|
.rs-tabs__nav-viewport {
|
|
@@ -499,17 +678,25 @@ function onDragEnd(): void {
|
|
|
499
678
|
box-shadow: inset 0 -2px 0 0 var(--rs-primary);
|
|
500
679
|
}
|
|
501
680
|
|
|
502
|
-
.rs-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
681
|
+
.rs-tabs__trigger--fixed {
|
|
682
|
+
font-weight: 500;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.rs-tabs--draggable .rs-tabs__trigger--movable {
|
|
506
686
|
cursor: grab;
|
|
507
687
|
}
|
|
508
688
|
|
|
509
|
-
.rs-
|
|
689
|
+
.rs-tabs--draggable .rs-tabs__trigger--movable:active,
|
|
690
|
+
.rs-tabs--draggable .rs-tabs__trigger--dragging {
|
|
510
691
|
cursor: grabbing;
|
|
511
692
|
}
|
|
512
693
|
|
|
694
|
+
.rs-tabs__pin {
|
|
695
|
+
flex: 0 0 auto;
|
|
696
|
+
color: var(--rs-placeholder);
|
|
697
|
+
opacity: 0.85;
|
|
698
|
+
}
|
|
699
|
+
|
|
513
700
|
.rs-tabs__icon {
|
|
514
701
|
flex: 0 0 auto;
|
|
515
702
|
color: currentColor;
|
|
@@ -517,6 +704,9 @@ function onDragEnd(): void {
|
|
|
517
704
|
|
|
518
705
|
.rs-tabs__label {
|
|
519
706
|
min-width: 0;
|
|
707
|
+
max-width: 12rem;
|
|
708
|
+
overflow: hidden;
|
|
709
|
+
text-overflow: ellipsis;
|
|
520
710
|
}
|
|
521
711
|
|
|
522
712
|
.rs-tabs__rename-input {
|
|
@@ -567,7 +757,9 @@ function onDragEnd(): void {
|
|
|
567
757
|
background: transparent;
|
|
568
758
|
color: var(--rs-muted);
|
|
569
759
|
cursor: pointer;
|
|
570
|
-
|
|
760
|
+
/* 非激活:默认隐藏,悬停标签时再显示;占位保留避免宽度跳动 */
|
|
761
|
+
opacity: 0;
|
|
762
|
+
pointer-events: none;
|
|
571
763
|
transition:
|
|
572
764
|
opacity var(--rs-transition-fast),
|
|
573
765
|
background var(--rs-transition-fast),
|
|
@@ -575,8 +767,10 @@ function onDragEnd(): void {
|
|
|
575
767
|
}
|
|
576
768
|
|
|
577
769
|
.rs-tabs__trigger:hover .rs-tabs__close,
|
|
770
|
+
.rs-tabs__trigger:focus-within .rs-tabs__close,
|
|
578
771
|
.rs-tabs__trigger[data-state='active'] .rs-tabs__close {
|
|
579
772
|
opacity: 1;
|
|
773
|
+
pointer-events: auto;
|
|
580
774
|
}
|
|
581
775
|
|
|
582
776
|
.rs-tabs__close:hover:not(:disabled) {
|
|
@@ -586,14 +780,40 @@ function onDragEnd(): void {
|
|
|
586
780
|
|
|
587
781
|
.rs-tabs__close:focus-visible {
|
|
588
782
|
outline: none;
|
|
783
|
+
opacity: 1;
|
|
784
|
+
pointer-events: auto;
|
|
589
785
|
box-shadow: 0 0 0 var(--rs-focus-ring-width, 2px) var(--rs-focus-ring);
|
|
590
786
|
}
|
|
591
787
|
|
|
592
788
|
.rs-tabs__close:disabled {
|
|
593
|
-
opacity: 0.38;
|
|
594
789
|
cursor: not-allowed;
|
|
595
790
|
}
|
|
596
791
|
|
|
792
|
+
.rs-tabs__trigger:hover .rs-tabs__close:disabled,
|
|
793
|
+
.rs-tabs__trigger:focus-within .rs-tabs__close:disabled,
|
|
794
|
+
.rs-tabs__trigger[data-state='active'] .rs-tabs__close:disabled {
|
|
795
|
+
opacity: 0.38;
|
|
796
|
+
pointer-events: none;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/* 触摸设备无悬停:可关闭标签始终显示关闭按钮 */
|
|
800
|
+
@media (hover: none) {
|
|
801
|
+
.rs-tabs__close {
|
|
802
|
+
opacity: 0.85;
|
|
803
|
+
pointer-events: auto;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.rs-tabs__trigger[data-state='active'] .rs-tabs__close {
|
|
807
|
+
opacity: 1;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.rs-tabs__close:disabled,
|
|
811
|
+
.rs-tabs__trigger[data-state='active'] .rs-tabs__close:disabled {
|
|
812
|
+
opacity: 0.38;
|
|
813
|
+
pointer-events: none;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
597
817
|
.rs-tabs__add,
|
|
598
818
|
.rs-tabs__scroll-btn {
|
|
599
819
|
display: inline-flex;
|
|
@@ -624,6 +844,17 @@ function onDragEnd(): void {
|
|
|
624
844
|
background: var(--rs-surface-hover);
|
|
625
845
|
}
|
|
626
846
|
|
|
847
|
+
.rs-tabs__extra {
|
|
848
|
+
display: inline-flex;
|
|
849
|
+
flex: 0 0 auto;
|
|
850
|
+
align-items: center;
|
|
851
|
+
align-self: stretch;
|
|
852
|
+
gap: var(--rs-space-xs);
|
|
853
|
+
margin-inline-start: auto;
|
|
854
|
+
padding-inline: var(--rs-space-sm);
|
|
855
|
+
border-inline-start: 1px solid var(--rs-border-subtle);
|
|
856
|
+
}
|
|
857
|
+
|
|
627
858
|
.rs-tabs__overflow-wrap {
|
|
628
859
|
display: flex;
|
|
629
860
|
flex: 0 0 auto;
|
|
@@ -734,6 +965,7 @@ function onDragEnd(): void {
|
|
|
734
965
|
.rs-tabs--dropdown-overflow.rs-tabs--line .rs-tabs__nav {
|
|
735
966
|
align-items: stretch;
|
|
736
967
|
padding-inline: 0;
|
|
968
|
+
border-bottom: 1px solid var(--rs-border-subtle);
|
|
737
969
|
}
|
|
738
970
|
|
|
739
971
|
.rs-tabs--dropdown-overflow.rs-tabs--line .rs-tabs__list {
|
|
@@ -761,10 +993,6 @@ function onDragEnd(): void {
|
|
|
761
993
|
background: var(--rs-primary);
|
|
762
994
|
}
|
|
763
995
|
|
|
764
|
-
.rs-tabs--dropdown-overflow.rs-tabs--line .rs-tabs__nav {
|
|
765
|
-
border-bottom: 1px solid var(--rs-border-subtle);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
996
|
.rs-tabs--line.rs-tabs--sm .rs-tabs__more {
|
|
769
997
|
min-height: var(--rs-control-height-sm);
|
|
770
998
|
padding: 0 var(--rs-space-sm);
|
|
@@ -789,12 +1017,14 @@ function onDragEnd(): void {
|
|
|
789
1017
|
}
|
|
790
1018
|
|
|
791
1019
|
.rs-tabs--line .rs-tabs__add,
|
|
792
|
-
.rs-tabs--line .rs-tabs__scroll-btn
|
|
1020
|
+
.rs-tabs--line .rs-tabs__scroll-btn,
|
|
1021
|
+
.rs-tabs--line .rs-tabs__extra {
|
|
793
1022
|
min-height: var(--rs-control-height-md);
|
|
794
1023
|
}
|
|
795
1024
|
|
|
796
1025
|
.rs-tabs--line.rs-tabs--sm .rs-tabs__add,
|
|
797
|
-
.rs-tabs--line.rs-tabs--sm .rs-tabs__scroll-btn
|
|
1026
|
+
.rs-tabs--line.rs-tabs--sm .rs-tabs__scroll-btn,
|
|
1027
|
+
.rs-tabs--line.rs-tabs--sm .rs-tabs__extra {
|
|
798
1028
|
min-height: var(--rs-control-height-sm);
|
|
799
1029
|
}
|
|
800
1030
|
|
|
@@ -829,8 +1059,17 @@ function onDragEnd(): void {
|
|
|
829
1059
|
font-size: var(--rs-font-size-xs);
|
|
830
1060
|
}
|
|
831
1061
|
|
|
832
|
-
.rs-tabs--line.rs-tabs--panelless .rs-
|
|
1062
|
+
.rs-tabs--line.rs-tabs--panelless .rs-tabs__nav {
|
|
833
1063
|
border-bottom: 1px solid var(--rs-border);
|
|
1064
|
+
background: var(--rs-surface);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
.rs-tabs--line.rs-tabs--panelless .rs-tabs__list {
|
|
1068
|
+
border-bottom: none;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
.rs-tabs--line.rs-tabs--panelless.rs-tabs--has-extra .rs-tabs__extra {
|
|
1072
|
+
background: transparent;
|
|
834
1073
|
}
|
|
835
1074
|
|
|
836
1075
|
/* —— segmented —— */
|
|
@@ -948,4 +1187,97 @@ function onDragEnd(): void {
|
|
|
948
1187
|
.rs-tabs--card.rs-tabs--panelless .rs-tabs__list {
|
|
949
1188
|
padding-bottom: var(--rs-space-sm);
|
|
950
1189
|
}
|
|
1190
|
+
|
|
1191
|
+
.rs-tabs--card .rs-tabs__extra {
|
|
1192
|
+
align-self: center;
|
|
1193
|
+
margin-bottom: 0;
|
|
1194
|
+
border-inline-start: none;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
/* —— contentGap:标题与内容间距(borderless 默认 0,业务可设 sm/md/lg/xl) —— */
|
|
1198
|
+
.rs-tabs--content-gap-sm {
|
|
1199
|
+
--rs-tabs-content-gap: var(--rs-space-sm);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
.rs-tabs--content-gap-md {
|
|
1203
|
+
--rs-tabs-content-gap: var(--rs-space-md);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
.rs-tabs--content-gap-lg {
|
|
1207
|
+
--rs-tabs-content-gap: var(--rs-space-lg);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
.rs-tabs--content-gap-xl {
|
|
1211
|
+
--rs-tabs-content-gap: var(--rs-space-xl);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/* —— borderless:无外框 / 无导航底色(业务用具名插槽,无需 :deep) —— */
|
|
1215
|
+
.rs-tabs--borderless.rs-tabs--line .rs-tabs__body,
|
|
1216
|
+
.rs-tabs--borderless.rs-tabs--segmented .rs-tabs__body,
|
|
1217
|
+
.rs-tabs--borderless.rs-tabs--card .rs-tabs__body {
|
|
1218
|
+
border: none;
|
|
1219
|
+
border-radius: 0;
|
|
1220
|
+
background: transparent;
|
|
1221
|
+
box-shadow: none;
|
|
1222
|
+
overflow: visible;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
.rs-tabs--borderless .rs-tabs__shell,
|
|
1226
|
+
.rs-tabs--borderless .rs-tabs__nav,
|
|
1227
|
+
.rs-tabs--borderless .rs-tabs__list,
|
|
1228
|
+
.rs-tabs--borderless .rs-tabs__nav-viewport {
|
|
1229
|
+
border: none;
|
|
1230
|
+
border-bottom: none;
|
|
1231
|
+
background: transparent;
|
|
1232
|
+
box-shadow: none;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.rs-tabs--borderless.rs-tabs--line .rs-tabs__list,
|
|
1236
|
+
.rs-tabs--borderless.rs-tabs--line.rs-tabs--panelless .rs-tabs__nav,
|
|
1237
|
+
.rs-tabs--borderless.rs-tabs--dropdown-overflow.rs-tabs--line .rs-tabs__nav {
|
|
1238
|
+
border-bottom: none;
|
|
1239
|
+
background: transparent;
|
|
1240
|
+
padding-inline: 0;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.rs-tabs--borderless .rs-tabs__panel,
|
|
1244
|
+
.rs-tabs--borderless .rs-tabs__panel-inner {
|
|
1245
|
+
padding: 0;
|
|
1246
|
+
border: none;
|
|
1247
|
+
background: transparent;
|
|
1248
|
+
box-shadow: none;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.rs-tabs--borderless .rs-tabs__panel-inner {
|
|
1252
|
+
padding-top: var(--rs-tabs-content-gap);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
.rs-tabs--borderless.rs-tabs--card .rs-tabs__panel-inner {
|
|
1256
|
+
border-top: none;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/* —— justify:标签栏对齐(stretch/evenly 铺满,免业务 :deep) —— */
|
|
1260
|
+
.rs-tabs--justify-center .rs-tabs__list {
|
|
1261
|
+
justify-content: center;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
.rs-tabs--justify-evenly .rs-tabs__list {
|
|
1265
|
+
width: 100%;
|
|
1266
|
+
justify-content: space-evenly;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.rs-tabs--justify-stretch .rs-tabs__list {
|
|
1270
|
+
display: flex;
|
|
1271
|
+
width: 100%;
|
|
1272
|
+
justify-content: stretch;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
.rs-tabs--justify-stretch .rs-tabs__trigger {
|
|
1276
|
+
flex: 1 1 0;
|
|
1277
|
+
justify-content: center;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
.rs-tabs--justify-stretch.rs-tabs--line .rs-tabs__trigger[data-state='active']::after {
|
|
1281
|
+
inset-inline: 18%;
|
|
1282
|
+
}
|
|
951
1283
|
</style>
|