refactor(tabs): ts

This commit is contained in:
07akioni 2021-01-24 00:22:53 +08:00
parent ead07b751d
commit 1c85ec61ca
14 changed files with 529 additions and 560 deletions

2
src/global.d.ts vendored
View File

@ -6,7 +6,7 @@ declare global {
}
// TODO: remove it, since it may conflict with user's d.ts
type ConflictKeys = 'title'
type ConflictKeys = 'title' | 'label'
declare module 'vue' {
interface ComponentCustomProps extends Omit<HTMLAttributes, ConflictKeys> {}

View File

@ -1,2 +0,0 @@
export { default as NTab } from './src/Tabs.vue'
export { default as NTabPane } from './src/TabPane.js'

2
src/tabs/index.ts Normal file
View File

@ -0,0 +1,2 @@
export { default as NTab } from './src/Tabs'
export { default as NTabPane } from './src/TabPane'

View File

@ -1,58 +0,0 @@
import { h, withDirectives, vShow, defineComponent } from 'vue'
import { getSlot } from '../../_utils'
export default defineComponent({
name: 'TabPane',
alias: ['TabPanel'],
inject: ['NTab'],
props: {
label: {
type: [String, Number],
default: undefined
},
name: {
type: [String, Number],
required: true
},
disabled: {
type: Boolean,
default: false
},
displayDirective: {
type: String,
default: 'if'
}
},
computed: {
type () {
return this.NTab.type
}
},
created () {
if (this.NTab) {
this.NTab.addPanel(this)
}
},
beforeUnmount () {
if (this.NTab) {
this.NTab.removePanel(this)
}
},
render () {
const show = this.name === this.NTab.value
const useVShow = this.displayDirective === 'show'
return useVShow || show
? withDirectives(
h(
'div',
{
class: 'n-tab-panel',
key: this.name
},
getSlot(this)
),
[[vShow, !useVShow || show]]
)
: null
}
})

70
src/tabs/src/TabPane.ts Normal file
View File

@ -0,0 +1,70 @@
import {
h,
withDirectives,
vShow,
defineComponent,
ExtractPropTypes,
inject,
onBeforeUnmount,
computed,
PropType
} from 'vue'
import { getSlot } from '../../_utils'
const tabPaneProps = {
label: [String, Number] as PropType<string | number>,
name: {
type: [String, Number] as PropType<string | number>,
required: true
},
disabled: {
type: Boolean,
default: false
},
displayDirective: {
type: String as PropType<'if' | 'show'>,
default: 'if'
}
} as const
export type TabPaneProps = ExtractPropTypes<typeof tabPaneProps>
export interface TabsInjection {
value: string | number | null
type: 'line' | 'card'
addPanel: (props: TabPaneProps) => void
removePanel: (props: TabPaneProps) => void
}
export default defineComponent({
name: 'TabPane',
alias: ['TabPanel'],
props: tabPaneProps,
setup (props) {
const NTab = inject<TabsInjection>('NTabs') as TabsInjection
NTab.addPanel(props)
onBeforeUnmount(() => {
NTab.removePanel(props)
})
return {
type: computed(() => NTab.type),
show: computed(() => props.name === NTab.value)
}
},
render () {
const useVShow = this.displayDirective === 'show'
return useVShow || this.show
? withDirectives(
h(
'div',
{
class: 'n-tab-panel',
key: this.name
},
getSlot(this)
),
[[vShow, !useVShow || this.show]]
)
: null
}
})

383
src/tabs/src/Tabs.tsx Normal file
View File

@ -0,0 +1,383 @@
import {
h,
ref,
defineComponent,
computed,
PropType,
provide,
CSSProperties,
watch,
nextTick,
onMounted,
reactive,
toRef,
Ref,
renderSlot
} from 'vue'
import { VResizeObserver } from 'vueuc'
import { throttle } from 'lodash-es'
import { useCompitable, onFontsReady, useMergedState } from 'vooks'
import { NBaseClose } from '../../_base'
import { useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import { warn, createKey, call } from '../../_utils'
import type { MaybeArray } from '../../_utils'
import { tabsLight } from '../styles'
import type { TabsTheme } from '../styles'
import type { TabsInjection, TabPaneProps } from './TabPane'
import style from './styles/index.cssr'
export default defineComponent({
name: 'Tabs',
props: {
...(useTheme.props as ThemeProps<TabsTheme>),
value: [String, Number] as PropType<string | number>,
defaultValue: {
type: [String, Number] as PropType<string | number | null>,
default: null
},
type: {
type: String as PropType<'line' | 'card'>,
default: 'line'
},
closable: {
type: Boolean,
default: false
},
justifyContent: String as PropType<
'space-between' | 'space-around' | 'space-evenly'
>,
labelSize: {
type: String as PropType<'small' | 'medium' | 'large' | 'huge'>,
default: 'medium'
},
navStyle: [String, Object] as PropType<string | CSSProperties>,
onScrollableChange: Function as PropType<
MaybeArray<(value: boolean) => void>
>,
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:value': Function as PropType<
MaybeArray<<T extends string | number>(value: T) => void>
>,
onClose: Function as PropType<MaybeArray<() => void>>,
// deprecated
activeName: {
type: [String, Number] as PropType<string | number | undefined>,
validator: () => {
if (__DEV__) {
warn(
'tabs',
'`active-name` is deprecated, please use `value` instead.'
)
}
return true
},
default: undefined
},
onActiveNameChange: {
type: Function as PropType<
MaybeArray<<T extends string | number>(value: T) => void>
>,
validator: () => {
if (__DEV__) {
warn(
'tabs',
'`on-active-name-change` is deprecated, please use `on-update:value` instead.'
)
}
return true
},
default: undefined
}
},
setup (props) {
const themeRef = useTheme('Tabs', 'Tabs', style, tabsLight, props)
const navRef = ref<HTMLElement | null>(null)
const labelWrapperRef = ref<HTMLElement | null>(null)
const labelBarRef = ref<HTMLElement | null>(null)
let preventYWheel = false
const panelsRef = ref<TabPaneProps[]>([])
const transitionDisabledRef = ref(false)
const compitableValueRef = useCompitable(props, ['activeName', 'value'])
const uncontrolledValueRef = ref(props.defaultValue)
const mergedValueRef = useMergedState(
compitableValueRef,
uncontrolledValueRef
)
const compitableOnValueChangeRef = useCompitable(props, [
'onActiveNameChange',
'onUpdate:value'
])
const labelWrapperStyleRef = computed(() => {
if (!props.justifyContent) return undefined
return {
display: 'flex',
justifyContent: props.justifyContent
}
})
const panelLabelsRef = computed(() => {
return panelsRef.value.map((panel) => panel.label)
})
watch(mergedValueRef, () => {
updateCurrentBarPosition()
})
watch(panelLabelsRef, () => {
void nextTick(updateScrollStatus)
})
function updateScrollStatus (): void {
const { value: navScrollEl } = navRef
if (navScrollEl) {
if (navScrollEl.scrollWidth > navScrollEl.offsetWidth) {
preventYWheel = true
} else {
preventYWheel = false
}
}
}
function addPanel (panelProps: TabPaneProps): void {
panelsRef.value.push(panelProps)
}
function removePanel (panelProps: TabPaneProps): void {
const index = panelsRef.value.findIndex(
(panel) => panel.name === panelProps.name
)
if (~index) {
panelsRef.value.splice(index, 1)
}
}
function updateBarPosition (labelEl: HTMLElement): void {
if (props.type === 'card') return
const { value: labelBarEl } = labelBarRef
if (!labelBarEl) return
if (labelEl) {
labelBarEl.style.left = `${labelEl.offsetLeft}px`
labelBarEl.style.width = '8192px'
labelBarEl.style.maxWidth = `${labelEl.offsetWidth + 1}px`
}
}
function updateCurrentBarPosition (): void {
if (props.type === 'card') return
const value = mergedValueRef.value
for (const panel of panelsRef.value) {
if (panel.name === value) {
const labelEl = navRef.value?.querySelector(
`[data-name="${panel.name}"]`
)
if (labelEl) {
updateBarPosition(labelEl as HTMLElement)
}
break
}
}
}
function handleTabsWheel (e: WheelEvent): void {
if (!preventYWheel || !e.deltaY) return
;(e.currentTarget as HTMLElement).scrollLeft += e.deltaY + e.deltaX
e.preventDefault()
}
function handleTabClick (
e: MouseEvent,
panelName: string | number,
disabled: boolean
): void {
if (!disabled) {
setPanelActive(panelName)
}
}
function setPanelActive (panelName: string | number): void {
const { value: compitableOnValueChange } = compitableOnValueChangeRef
if (compitableOnValueChange) call(compitableOnValueChange, panelName)
}
function handleCloseClick (e: MouseEvent, panel: TabPaneProps): void {
const { onClose } = props
if (onClose) call(onClose, panel.name)
e.stopPropagation()
}
const handleNavResize = throttle(function handleNavResize () {
if (props.type === 'card') {
updateScrollStatus()
} else if (props.type === 'line') {
transitionDisabledRef.value = true
void nextTick(() => {
updateCurrentBarPosition()
transitionDisabledRef.value = false
})
}
}, 64)
const handleScrollContentResize = throttle(
function handleScrollContentResize () {
updateScrollStatus()
},
64
)
provide<TabsInjection>(
'NTabs',
reactive({
type: toRef(props, 'type') as Ref<'line' | 'card'>,
value: mergedValueRef,
removePanel,
addPanel
})
)
onMounted(() => {
updateScrollStatus()
})
onFontsReady(() => {
updateScrollStatus()
updateCurrentBarPosition()
})
return {
mergedValue: mergedValueRef,
compitableOnValueChange: compitableOnValueChangeRef,
navRef,
labelWrapperRef,
labelBarRef,
labelWrapperStyle: labelWrapperStyleRef,
panels: panelsRef,
transitionDisabled: transitionDisabledRef,
handleTabClick,
handleScrollContentResize,
handleNavResize,
handleCloseClick,
handleTabsWheel,
cssVars: computed(() => {
const { labelSize } = props
const {
self: {
labelTextColor,
labelTextColorActive,
labelTextColorHover,
labelTextColorDisabled,
labelBarColor,
closeColor,
closeColorHover,
closeColorPressed,
tabColor,
tabBorderColorActive,
tabTextColor,
tabTextColorActive,
tabBorderColor,
paneTextColor,
tabFontWeight,
tabBorderRadius,
labelFontSizeCard,
[createKey('labelFontSizeLine', labelSize)]: labelFontSizeLine
},
common: { cubicBezierEaseInOut }
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--label-bar-color': labelBarColor,
'--label-font-size-card': labelFontSizeCard,
'--label-font-size-line': labelFontSizeLine,
'--label-text-color': labelTextColor,
'--label-text-color-active': labelTextColorActive,
'--label-text-color-disabled': labelTextColorDisabled,
'--label-text-color-hover': labelTextColorHover,
'--pane-text-color': paneTextColor,
'--tab-border-color': tabBorderColor,
'--tab-border-color-active': tabBorderColorActive,
'--tab-border-radius': tabBorderRadius,
'--close-color': closeColor,
'--close-color-hover': closeColorHover,
'--close-color-pressed': closeColorPressed,
'--tab-color': tabColor,
'--tab-font-weight': tabFontWeight,
'--tab-text-color': tabTextColor,
'--tab-text-color-active': tabTextColorActive
}
})
}
},
render () {
return (
<div
class={[
'n-tabs',
`n-tabs--${this.type}-type`,
`n-tabs--${this.labelSize}-size`,
{
'n-tabs--flex': this.justifyContent
}
]}
style={this.cssVars as CSSProperties}
>
<VResizeObserver onResize={this.handleNavResize}>
{{
default: () => (
<div
ref="navRef"
class="n-tabs-nav"
onWheel={this.handleTabsWheel}
style={this.navStyle}
>
<VResizeObserver onResize={this.handleScrollContentResize}>
{{
default: () => (
<div ref="labelWrapperRef" class="n-tabs-label-wrapper">
<div style={this.labelWrapperStyle}>
{this.panels.map((panel, i) => (
<div
key={i}
data-name={panel.name}
class={[
'n-tabs-label',
{
'n-tabs-label--active':
this.mergedValue === panel.name,
'n-tabs-label--disabled': panel.disabled
}
]}
onClick={(e) =>
this.handleTabClick(
e,
panel.name,
panel.disabled
)
}
>
<span class="n-tabs-label__label">
{panel.label}
</span>
{this.closable && this.type === 'card' ? (
<NBaseClose
class="n-tabs-label__close"
onClick={(e) =>
this.handleCloseClick(e, panel)
}
/>
) : null}
</div>
))}
</div>
{this.type === 'line' ? (
<div
ref="labelBarRef"
class={[
'n-tabs-label-bar',
{
'n-tabs-label-bar--transition-disabled': this
.transitionDisabled
}
]}
/>
) : null}
</div>
)
}}
</VResizeObserver>
</div>
)
}}
</VResizeObserver>
{renderSlot(this.$slots, 'default')}
</div>
)
}
})

View File

@ -1,395 +0,0 @@
<template>
<div
class="n-tabs"
:class="{
[`n-tabs--${type}-type`]: true,
'n-tabs--scroll': showScrollButton,
[`n-tabs--${labelSize}-size`]: labelSize,
[`n-tabs--flex`]: justifyContent
}"
:style="cssVars"
>
<v-resize-observer @resize="handleNavResize">
<div ref="navRef" class="n-tabs-nav" :style="navStyle">
<div
v-if="showScrollButton"
class="n-tabs-nav-scroll-button n-tabs-nav-scroll-button--left"
:class="{
'n-tabs-nav-scroll-button--disabled': leftScrollButtonDisabled
}"
@click="scroll('left')"
>
<n-base-icon>
<backward-icon />
</n-base-icon>
</div>
<div ref="navScrollRef" class="n-tabs-nav-scroll">
<v-resize-observer @resize="handleScrollContentResize">
<div ref="labelWrapperRef" class="n-tabs-label-wrapper">
<div :style="labelWrapperStyle">
<div
v-for="(panel, i) in panels"
:key="i"
:ref="`label(${i})`"
class="n-tabs-label"
:class="{
'n-tabs-label--active': compitableValue === panel.name,
'n-tabs-label--disabled': panel.disabled
}"
@click="handleTabClick($event, panel.name, panel.disabled)"
>
<span class="n-tabs-label__label">{{ panel.label }}</span>
<n-base-close
v-if="closable && typeIsCard"
class="n-tabs-label__close"
@click.stop="handleCloseClick(panel)"
/>
</div>
</div>
<div
v-if="!typeIsCard"
ref="labelBarRef"
class="n-tabs-label-bar"
:class="{
'n-tabs-label-bar--transition-disabled': transitionDisabled
}"
/>
</div>
</v-resize-observer>
</div>
<div
v-if="showScrollButton"
class="n-tabs-nav-scroll-button n-tabs-nav-scroll-button--right"
:class="{
'n-tabs-nav-scroll-button--disabled': rightScrollButtonDisabled
}"
@click="scroll('right')"
>
<n-base-icon>
<forward-icon />
</n-base-icon>
</div>
</div>
</v-resize-observer>
<slot />
</div>
</template>
<script>
import { ref, getCurrentInstance, defineComponent, computed } from 'vue'
import { VResizeObserver } from 'vueuc'
import { throttle } from 'lodash-es'
import { useCompitable, onFontsReady } from 'vooks'
import {
ChevronLeftIcon as BackwardIcon,
ChevronRightIcon as ForwardIcon
} from '../../_base/icons'
import { NBaseIcon, NBaseClose } from '../../_base'
import { useTheme } from '../../_mixins'
import { warn, createKey } from '../../_utils'
import { tabsLight } from '../styles'
import style from './styles/index.cssr.js'
export default defineComponent({
name: 'Tabs',
components: {
NBaseIcon,
BackwardIcon,
ForwardIcon,
NBaseClose,
VResizeObserver
},
provide () {
return {
NTab: this
}
},
props: {
...useTheme.props,
value: {
type: String || Number,
required: true
},
type: {
validator (type) {
return ['line', 'card'].includes(type)
},
default: 'line'
},
closable: {
type: Boolean,
default: false
},
justifyContent: {
validator (value) {
return ['space-between', 'space-around', 'space-evenly'].includes(value)
},
default: undefined
},
labelSize: {
validator (value) {
return ['small', 'medium', 'large', 'huge'].includes(value)
},
default: 'medium'
},
navStyle: {
type: [String, Object],
default: undefined
},
onScrollableChange: {
type: Function,
default: undefined
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:value': {
type: Function,
default: undefined
},
onClose: {
type: Function,
default: undefined
},
// deprecated
activeName: {
validator () {
if (__DEV__) {
warn(
'tabs',
'`active-name` is deprecated, please use `value` instead.'
)
}
return true
},
default: undefined
},
onActiveNameChange: {
validator () {
if (__DEV__) {
warn(
'tabs',
'`on-active-name-change` is deprecated, please use `on-update:value` instead.'
)
}
return true
},
default: undefined
}
},
setup (props) {
const themeRef = useTheme('Tabs', 'Tabs', style, tabsLight, props)
const vm = getCurrentInstance().proxy
onFontsReady(() => {
vm.updateScrollStatus()
if (vm.typeIsLine) {
vm.updateCurrentBarPosition()
}
})
return {
compitableValue: useCompitable(props, ['activeName', 'value']),
compitableOnValueChange: useCompitable(props, [
'onActiveNameChange',
'onUpdate:value'
]),
navScrollRef: ref(null),
labelWrapperRef: ref(null),
navRef: ref(null),
labelBarRef: ref(null),
cssVars: computed(() => {
const { labelSize } = props
const {
self: {
labelTextColor,
labelTextColorActive,
labelTextColorHover,
labelTextColorDisabled,
labelBarColor,
scrollButtonColor,
scrollButtonColorDisabled,
closeColor,
closeColorHover,
closeColorPressed,
tabColor,
tabBorderColorActive,
tabTextColor,
tabTextColorActive,
tabBorderColor,
paneTextColor,
tabFontWeight,
tabBorderRadius,
labelFontSizeCard,
[createKey('labelFontSizeLine', labelSize)]: labelFontSizeLine
},
common: { cubicBezierEaseInOut }
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--label-bar-color': labelBarColor,
'--label-font-size-card': labelFontSizeCard,
'--label-font-size-line': labelFontSizeLine,
'--label-text-color': labelTextColor,
'--label-text-color-active': labelTextColorActive,
'--label-text-color-disabled': labelTextColorDisabled,
'--label-text-color-hover': labelTextColorHover,
'--pane-text-color': paneTextColor,
'--scroll-button-color': scrollButtonColor,
'--scroll-button-color-disabled': scrollButtonColorDisabled,
'--tab-border-color': tabBorderColor,
'--tab-border-color-active': tabBorderColorActive,
'--tab-border-radius': tabBorderRadius,
'--close-color': closeColor,
'--close-color-hover': closeColorHover,
'--close-color-pressed': closeColorPressed,
'--tab-color': tabColor,
'--tab-font-weight': tabFontWeight,
'--tab-text-color': tabTextColor,
'--tab-text-color-active': tabTextColorActive
}
})
}
},
data () {
return {
panels: [],
barStyleInitialized: false,
showScrollButton: false,
leftScrollButtonDisabled: true,
rightScrollButtonDisabled: false,
transitionDisabled: false
}
},
computed: {
typeIsCard () {
return this.type === 'card'
},
typeIsLine () {
return this.type === 'line'
},
labelWrapperStyle () {
if (!this.justifyContent) return null
return {
display: 'flex',
justifyContent: this.justifyContent
}
},
panelLabels () {
return this.panels.map((panel) => panel.label)
}
},
watch: {
compitableValue () {
if (this.typeIsLine) {
this.updateCurrentBarPosition()
}
},
showScrollButton (value) {
const { onScrollableChange } = this
if (onScrollableChange) onScrollableChange(value)
},
panelLabels () {
this.$nextTick(this.updateScrollStatus)
}
},
mounted () {
this.updateScrollStatus()
},
methods: {
scroll (direction) {
const navScroll = this.navScrollRef
const scrollLeft = navScroll.scrollLeft
const labelWrapper = this.labelWrapperRef
const scrollWidth = navScroll.offsetWidth * 0.8
let left = 0
if (direction === 'left') {
left = scrollLeft - scrollWidth
} else {
left = scrollLeft + scrollWidth
}
if (left <= 0) {
this.leftScrollButtonDisabled = true
this.rightScrollButtonDisabled = false
} else if (left >= labelWrapper.offsetWidth - navScroll.offsetWidth) {
this.rightScrollButtonDisabled = true
this.leftScrollButtonDisabled = false
} else {
this.rightScrollButtonDisabled = false
this.leftScrollButtonDisabled = false
}
navScroll.scrollTo({
left,
behavior: 'smooth'
})
},
updateScrollStatus () {
const labelWrapper = this.labelWrapperRef
const nav = this.navRef
if (labelWrapper.offsetWidth > nav.offsetWidth) {
this.showScrollButton = true
} else {
this.showScrollButton = false
}
},
addPanel (panelInstance) {
this.panels.push(panelInstance)
},
removePanel (panelInstance) {
const index = this.panels.findIndex((panel) => panel === panelInstance)
if (~index) {
this.panels.splice(index, 1)
}
},
updateBarPosition (labelEl) {
const labelBarEl = this.labelBarRef
// BUG? this.$el is null
if (labelBarEl && labelEl) {
labelBarEl.style.left = labelEl.offsetLeft + 'px'
labelBarEl.style.width = '8192px'
if (this.type === 'card') {
labelBarEl.style.maxWidth = labelEl.offsetWidth + 'px'
} else {
labelBarEl.style.maxWidth = labelEl.offsetWidth + 1 + 'px'
}
}
},
updateCurrentBarPosition () {
let index = 0
const value = this.compitableValue
const refs = this.$refs
for (const panel of this.panels) {
if (panel.name === value) {
this.updateBarPosition(refs[`label(${index})`])
break
}
index++
}
},
handleTabClick (e, panelName, disabled) {
if (!disabled) {
this.setPanelActive(panelName)
}
},
setPanelActive (panelName) {
const { compitableOnValueChange } = this
if (compitableOnValueChange) compitableOnValueChange(panelName)
},
handleCloseClick (panel) {
const { onClose } = this
if (onClose) onClose(panel.name)
},
handleNavResize: throttle(function handleNavResize () {
if (this.typeIsCard || (this.typeIsLine && !this.justifyContent)) {
this.updateScrollStatus()
}
if (this.typeIsLine) {
this.transitionDisabled = true
this.$nextTick().then(() => {
this.updateCurrentBarPosition()
this.transitionDisabled = false
})
}
}, 64),
handleScrollContentResize: throttle(function handleScrollContentResize () {
this.updateScrollStatus()
}, 64)
}
})
</script>

View File

@ -13,8 +13,6 @@ import { c, cM, cB, cE } from '../../../_utils/cssr'
// --label-text-color-disabled
// --label-text-color-hover
// --pane-text-color
// --scroll-button-color
// --scroll-button-color-disabled
// --tab-border-color
// --tab-border-color-active
// --tab-border-radius
@ -29,17 +27,15 @@ export default cB('tabs', `
border-color .3s var(--bezier);
`, [
cM('flex', [
cB('tabs-nav', [
cB('tabs-nav-scroll', {
cB('tabs-nav', {
width: '100%'
}, [
cB('tabs-label-wrapper', {
width: '100%'
}, [
cB('tabs-label-wrapper', {
width: '100%'
}, [
cB('tabs-label', {
marginRight: 0
})
])
cB('tabs-label', {
marginRight: 0
})
])
])
]),
@ -48,30 +44,13 @@ export default cB('tabs', `
display: flex;
background-clip: padding-box;
transition: border-color .3s var(--bezier);
overflow: auto;
scrollbar-width: none;
`, [
cB('tabs-nav-scroll', {
overflow: 'hidden'
}),
cB('tabs-nav-scroll-button', `
font-size: 20px;
height: 20px;
line-height: 20px;
align-self: center;
cursor: pointer;
color: var(--scroll-button-color);
transition: color .3s var(--bezier);
`, [
cM('left', {
marginRight: '8px'
}),
cM('right', {
marginLeft: '8px'
}),
cM('disabled', {
cursor: 'not-allowed',
color: 'var(--scroll-button-color-disabled)'
})
])
c('&::-webkit-scrollbar', `
width: 0;
height: 0;
`)
]),
cB('tabs-label-wrapper', `
display: inline-block;
@ -128,11 +107,6 @@ export default cB('tabs', `
background-color .3s var(--bezier);
`),
cM('line-type', [
cB('tabs-nav', [
cB('tabs-nav-scroll-button', `
padding-bottom: 4px;
`)
]),
cB('tabs-label', `
box-sizing: border-box;
padding-bottom: 2px;
@ -166,16 +140,6 @@ export default cB('tabs', `
border-top: 1px solid var(--tab-border-color);
border-bottom: 1px solid var(--tab-border-color);
`, [
cB('tabs-nav-scroll-button', [
cM('left', `
margin-left: 2px;
margin-right: 2px;
`),
cM('right', `
margin-left: 2px;
margin-right: 2px;
`)
]),
cB('tabs-label-bar', `
bottom: 0;
border-radius: 0;

View File

@ -1,7 +1,8 @@
import sizeVariables from './_common'
import { commonDark } from '../../_styles/new-common'
import type { TabsTheme } from './light'
export default {
const tabsDark: TabsTheme = {
name: 'Tabs',
common: commonDark,
self (vars) {
@ -9,8 +10,6 @@ export default {
textColor2Overlay,
primaryColor,
textColorDisabledOverlay,
iconColorOverlay,
iconColorDisabledOverlay,
closeColorOverlay,
closeColorHoverOverlay,
closeColorPressedOverlay,
@ -29,8 +28,6 @@ export default {
labelTextColorHover: primaryColor,
labelTextColorDisabled: textColorDisabledOverlay,
labelBarColor: primaryColor,
scrollButtonColor: iconColorOverlay,
scrollButtonColorDisabled: iconColorDisabledOverlay,
closeColor: closeColorOverlay,
closeColorHover: closeColorHoverOverlay,
closeColorPressed: closeColorPressedOverlay,
@ -45,3 +42,5 @@ export default {
}
}
}
export default tabsDark

View File

@ -1,2 +0,0 @@
export { default as tabsDark } from './dark.js'
export { default as tabsLight } from './light.js'

3
src/tabs/styles/index.ts Normal file
View File

@ -0,0 +1,3 @@
export { default as tabsDark } from './dark'
export { default as tabsLight } from './light'
export type { TabsTheme, TabsThemeVars } from './light'

View File

@ -1,48 +0,0 @@
import sizeVariables from './_common'
import { commonLight } from '../../_styles/new-common'
export default {
name: 'Tabs',
common: commonLight,
self (vars) {
const {
textColor2,
primaryColor,
textColorDisabled,
iconColorOverlay,
iconColorDisabledOverlay,
closeColor,
closeColorHover,
closeColorPressed,
tabColorOverlay,
borderColor,
textColor1,
dividerColorOverlay,
fontWeightStrong,
borderRadius,
fontSize
} = vars
return {
...sizeVariables,
labelFontSizeCard: fontSize,
labelTextColor: textColor2,
labelTextColorActive: primaryColor,
labelTextColorHover: primaryColor,
labelTextColorDisabled: textColorDisabled,
labelBarColor: primaryColor,
scrollButtonColor: iconColorOverlay,
scrollButtonColorDisabled: iconColorDisabledOverlay,
closeColor: closeColor,
closeColorHover: closeColorHover,
closeColorPressed: closeColorPressed,
tabColor: tabColorOverlay,
tabBorderColorActive: borderColor,
tabTextColor: textColor2,
tabTextColorActive: textColor1,
tabBorderColor: dividerColorOverlay,
tabFontWeight: fontWeightStrong,
tabBorderRadius: borderRadius,
paneTextColor: textColor2
}
}
}

53
src/tabs/styles/light.ts Normal file
View File

@ -0,0 +1,53 @@
import sizeVariables from './_common'
import { commonLight } from '../../_styles/new-common'
import type { ThemeCommonVars } from '../../_styles/new-common'
import { Theme } from '../../_mixins'
const self = (vars: ThemeCommonVars) => {
const {
textColor2,
primaryColor,
textColorDisabled,
closeColor,
closeColorHover,
closeColorPressed,
tabColorOverlay,
borderColor,
textColor1,
dividerColorOverlay,
fontWeightStrong,
borderRadius,
fontSize
} = vars
return {
...sizeVariables,
labelFontSizeCard: fontSize,
labelTextColor: textColor2,
labelTextColorActive: primaryColor,
labelTextColorHover: primaryColor,
labelTextColorDisabled: textColorDisabled,
labelBarColor: primaryColor,
closeColor: closeColor,
closeColorHover: closeColorHover,
closeColorPressed: closeColorPressed,
tabColor: tabColorOverlay,
tabBorderColorActive: borderColor,
tabTextColor: textColor2,
tabTextColorActive: textColor1,
tabBorderColor: dividerColorOverlay,
tabFontWeight: fontWeightStrong,
tabBorderRadius: borderRadius,
paneTextColor: textColor2
}
}
export type TabsThemeVars = ReturnType<typeof self>
const tabsLight: Theme<TabsThemeVars> = {
name: 'Tabs',
common: commonLight,
self
}
export default tabsLight
export type TabsTheme = typeof tabsLight