feat: made all components reactive

This commit is contained in:
Alexandr
2022-07-05 19:31:05 +03:00
parent 917c21cc84
commit 3c342e4473
15 changed files with 310 additions and 131 deletions

View File

@@ -1,8 +1,24 @@
<template> <template>
<div class="vp-raw"> <div class="vp-raw">
<tabs /> <tabs v-model="activeTab">
<tab name="first" title="Проверка">
Проверка
</tab>
<tab name="second" title=роверка1">
Проверка 2
</tab>
<tab name="third" title=роверка2">
Проверка 3
</tab>
<tab name="fourth" title=роверка3" :disabled="true">
Проверка 4
</tab>
</tabs>
current tab: {{ activeTab }}
</div> </div>
</template> </template>
<script setup> <script setup>
import { Tabs } from '../../../../src/index' import { ref } from 'vue'
import { Tabs, Tab } from '../../../../src/index'
const activeTab = ref('')
</script> </script>

View File

@@ -28,7 +28,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { PropType } from 'vue' import type { PropType } from 'vue'
import { useAlertClasses } from './useAlertClasses' import { useAlertClasses } from './useAlertClasses'
import { onBeforeUnmount, ref } from 'vue' import { onBeforeUnmount, ref, toRefs } from 'vue'
export type AlertType = 'info' | 'danger' | 'success' | 'warning' | 'dark' export type AlertType = 'info' | 'danger' | 'success' | 'warning' | 'dark'
@@ -59,7 +59,7 @@ const props = defineProps({
}, },
}) })
const { alertClasses, textClasses, closeClasses, contentClasses, titleClasses } = useAlertClasses(props) const { alertClasses, textClasses, closeClasses, contentClasses, titleClasses } = useAlertClasses(toRefs(props))
const visible = ref(true) const visible = ref(true)

View File

@@ -41,11 +41,11 @@ const closeButtonClasses: Record<AlertType, string> = {
} }
export type UseAlertClassesProps = { export type UseAlertClassesProps = {
type: AlertType type: Ref<AlertType>
border: boolean border: Ref<boolean>
icon: boolean icon: Ref<boolean>
inline: boolean inline: Ref<boolean>
title: string title: Ref<string>
} }
export function useAlertClasses(props: UseAlertClassesProps): { export function useAlertClasses(props: UseAlertClassesProps): {
@@ -59,40 +59,40 @@ export function useAlertClasses(props: UseAlertClassesProps): {
const alertClasses = computed<string>(() => { const alertClasses = computed<string>(() => {
return classNames( return classNames(
defaultAlertClasses, defaultAlertClasses,
alertTypeClasses[props.type], alertTypeClasses[props.type.value],
textClasses.value, textClasses.value,
props.border ? alertBorderClasses[props.type] : 'rounded-lg', // rounded only if no border props.border.value ? alertBorderClasses[props.type.value] : 'rounded-lg', // rounded only if no border
props.inline ? 'flex' : '', props.inline.value ? 'flex' : '',
) )
}) })
const textClasses = computed<string>(() => { const textClasses = computed<string>(() => {
return classNames( return classNames(
alertTextClasses[props.type], alertTextClasses[props.type.value],
) )
}) })
const closeClasses = computed<string>(() => { const closeClasses = computed<string>(() => {
return classNames( return classNames(
defaultCloseButtonClasses, defaultCloseButtonClasses,
closeButtonClasses[props.type], closeButtonClasses[props.type.value],
) )
}) })
const contentClasses = computed<string>(() => { const contentClasses = computed<string>(() => {
if(!props.inline) return classNames('mt-2 mb-4') if(!props.inline.value) return classNames('mt-2 mb-4')
if(!props.icon && !props.title) return '' if(!props.icon.value && !props.title.value) return ''
return classNames(!props.title ? 'ml-3' : 'ml-1') return classNames(!props.title.value ? 'ml-3' : 'ml-1')
}) })
const titleClasses = computed<string>(() => { const titleClasses = computed<string>(() => {
if(!props.icon || !props.inline) return classNames( if(!props.icon.value || !props.inline.value) return classNames(
'font-medium', 'font-medium',
!props.inline ? 'text-lg ml-2' : '', !props.inline.value ? 'text-lg ml-2' : '',
) )
return classNames( return classNames(
'font-medium ml-3', 'font-medium ml-3',
!props.inline ? 'text-lg' : '', !props.inline.value ? 'text-lg' : '',
) )
}) })

View File

@@ -28,7 +28,7 @@
</button> </button>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue' import { computed, toRefs } from 'vue'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import Spinner from '../Spinner/Spinner.vue' import Spinner from '../Spinner/Spinner.vue'
import { useButtonClasses } from './useButtonClasses' import { useButtonClasses } from './useButtonClasses'
@@ -89,7 +89,7 @@ const isOutlineGradient = computed(() => props.outline && props.gradient)
const loadingPrefix = computed(() => props.loading && props.loadingPosition === 'prefix') const loadingPrefix = computed(() => props.loading && props.loadingPosition === 'prefix')
const loadingSuffix = computed(() => props.loading && props.loadingPosition === 'suffix') const loadingSuffix = computed(() => props.loading && props.loadingPosition === 'suffix')
const { wrapperClasses, spanClasses } = useButtonClasses(props) const { wrapperClasses, spanClasses } = useButtonClasses(toRefs(props))
const { color: spinnerColor, size: spinnerSize } = useButtonSpinner(props) const { color: spinnerColor, size: spinnerSize } = useButtonSpinner(toRefs(props))
</script> </script>

View File

@@ -144,15 +144,15 @@ const buttonShadowClasses: Record<ButtonMonochromeGradient, string> = {
} }
export type UseButtonClassesProps = { export type UseButtonClassesProps = {
pill: boolean pill: Ref<boolean>
disabled: boolean disabled: Ref<boolean>
loading: boolean loading: Ref<boolean>
outline: boolean outline: Ref<boolean>
size: ButtonSize size: Ref<ButtonSize>
square: boolean square: Ref<boolean>
color: ButtonVariant color: Ref<ButtonVariant>
gradient: ButtonGradient | null gradient: Ref<ButtonGradient | null>
shadow: ButtonMonochromeGradient | '' | null shadow: Ref<ButtonMonochromeGradient | '' | null>
} }
const simpleGradients = ['blue', 'green', 'cyan', 'teal', 'lime', 'red', 'pink', 'purple'] const simpleGradients = ['blue', 'green', 'cyan', 'teal', 'lime', 'red', 'pink', 'purple']
@@ -162,64 +162,64 @@ export function useButtonClasses(props: UseButtonClassesProps): { wrapperClasses
const slots = useSlots() const slots = useSlots()
const sizeClasses = computed(() => { const sizeClasses = computed(() => {
if (props.square) return buttonSquareSizeClasses[props.size] if (props.square.value) return buttonSquareSizeClasses[props.size.value]
return buttonSizeClasses[props.size] return buttonSizeClasses[props.size.value]
}) })
const bindClasses = computed(() => { const bindClasses = computed(() => {
const isGradient = !!props.gradient const isGradient = !!props.gradient.value
const isColor = !!props.color const isColor = !!props.color.value
const isOutline = props.outline const isOutline = props.outline.value
let hoverClass = '' let hoverClass = ''
let backgroundClass = '' let backgroundClass = ''
if (isGradient && isOutline) { // GRADIENT AND OUTLINE if (isGradient && isOutline) { // GRADIENT AND OUTLINE
if (!simpleGradients.includes(props.gradient!)) { if (!simpleGradients.includes(props.gradient.value!)) {
backgroundClass = buttonOutlineGradientClasses.default[props.gradient as unknown as keyof typeof buttonOutlineGradientClasses.default] backgroundClass = buttonOutlineGradientClasses.default[props.gradient.value as unknown as keyof typeof buttonOutlineGradientClasses.default]
if(!props.disabled) if(!props.disabled.value)
hoverClass = buttonOutlineGradientClasses.hover[props.gradient as unknown as keyof typeof buttonOutlineGradientClasses.hover] hoverClass = buttonOutlineGradientClasses.hover[props.gradient.value as unknown as keyof typeof buttonOutlineGradientClasses.hover]
} else { } else {
console.warn(`cannot use outline prop with "${props.gradient}" gradient`) // TODO: prettify console.warn(`cannot use outline prop with "${props.gradient.value}" gradient`) // TODO: prettify
} }
} else if (isGradient) { // JUST GRADIENT } else if (isGradient) { // JUST GRADIENT
backgroundClass = buttonGradientClasses.default[props.gradient!] backgroundClass = buttonGradientClasses.default[props.gradient.value!]
if(!props.disabled) if(!props.disabled.value)
hoverClass = buttonGradientClasses.hover[props.gradient!] hoverClass = buttonGradientClasses.hover[props.gradient.value!]
} else if (isColor && isOutline) { // COLOR AND OUTLINE } else if (isColor && isOutline) { // COLOR AND OUTLINE
if (!alternativeColors.includes(props.color)) { if (!alternativeColors.includes(props.color.value)) {
backgroundClass = buttonOutlineColorClasses.default[props.color as unknown as keyof typeof buttonOutlineColorClasses.default] backgroundClass = buttonOutlineColorClasses.default[props.color.value as unknown as keyof typeof buttonOutlineColorClasses.default]
if(!props.disabled) if(!props.disabled.value)
hoverClass = buttonOutlineColorClasses.hover[props.color as unknown as keyof typeof buttonOutlineColorClasses.hover] hoverClass = buttonOutlineColorClasses.hover[props.color.value as unknown as keyof typeof buttonOutlineColorClasses.hover]
} else { } else {
console.warn(`cannot use outline prop with "${props.color}" color`) // TODO: prettify console.warn(`cannot use outline prop with "${props.color.value}" color`) // TODO: prettify
} }
} else { // JUST COLOR } else { // JUST COLOR
backgroundClass = buttonColorClasses.default[props.color] backgroundClass = buttonColorClasses.default[props.color.value]
if(!props.disabled) if(!props.disabled.value)
hoverClass = buttonColorClasses.hover[props.color] hoverClass = buttonColorClasses.hover[props.color.value]
} }
let shadowClass = '' let shadowClass = ''
if (props.shadow === '') { if (props.shadow.value === '') {
// if shadow prop passed without value - try to find color for shadow by gradient // if shadow prop passed without value - try to find color for shadow by gradient
if (props.gradient && simpleGradients.includes(props.gradient)) { if (props.gradient.value && simpleGradients.includes(props.gradient.value!)) {
shadowClass = buttonShadowClasses[props.gradient as unknown as keyof typeof buttonShadowClasses] shadowClass = buttonShadowClasses[props.gradient.value as unknown as keyof typeof buttonShadowClasses]
} }
} else if (typeof props.shadow === 'string') { } else if (typeof props.shadow.value === 'string') {
// if provided color for shadow - use it // if provided color for shadow - use it
if (simpleGradients.includes(props.shadow)) { if (simpleGradients.includes(props.shadow.value)) {
shadowClass = buttonShadowClasses[props.shadow as unknown as keyof typeof buttonShadowClasses] shadowClass = buttonShadowClasses[props.shadow.value as unknown as keyof typeof buttonShadowClasses]
} }
} }
@@ -227,19 +227,19 @@ export function useButtonClasses(props: UseButtonClassesProps): { wrapperClasses
backgroundClass, backgroundClass,
hoverClass, hoverClass,
shadowClass, shadowClass,
props.pill ? '!rounded-full' : '', props.pill.value ? '!rounded-full' : '',
props.disabled ? 'cursor-not-allowed opacity-50' : '', props.disabled.value ? 'cursor-not-allowed opacity-50' : '',
(isGradient && isOutline) ? 'p-0.5' : sizeClasses.value, (isGradient && isOutline) ? 'p-0.5' : sizeClasses.value,
(slots.prefix || slots.suffix || props.loading) ? 'inline-flex items-center' : '', (slots.prefix || slots.suffix || props.loading.value) ? 'inline-flex items-center' : '',
) )
}) })
const spanClasses = computed(() => { const spanClasses = computed(() => {
if (!!props.gradient && props.outline) { // ONLY FOR GRADIENT OUTLINE BUTTON if (!!props.gradient.value && props.outline.value) { // ONLY FOR GRADIENT OUTLINE BUTTON
return classNames( return classNames(
'relative bg-white dark:bg-gray-900 rounded-md inline-flex items-center', 'relative bg-white dark:bg-gray-900 rounded-md inline-flex items-center',
sizeClasses.value, sizeClasses.value,
!props.disabled ? 'group-hover:bg-opacity-0 transition-all ease-in duration-75' : '', !props.disabled.value ? 'group-hover:bg-opacity-0 transition-all ease-in duration-75' : '',
) )
} }
return '' return ''

View File

@@ -1,13 +1,13 @@
import type {ButtonGradient, ButtonSize, ButtonVariant} from './Button.vue' import type { ButtonGradient, ButtonSize, ButtonVariant } from './Button.vue'
import type {SpinnerColor, SpinnerSize} from '../Spinner/Spinner.vue' import type { SpinnerColor, SpinnerSize } from '../Spinner/Spinner.vue'
import type {Ref} from 'vue' import type { Ref } from 'vue'
import {computed} from 'vue' import { computed } from 'vue'
export type UseButtonSpinnerProps = { export type UseButtonSpinnerProps = {
outline: boolean outline: Ref<boolean>
size: ButtonSize size: Ref<ButtonSize>
color: ButtonVariant color: Ref<ButtonVariant>
gradient: ButtonGradient | null gradient: Ref<ButtonGradient | null>
} }
export function useButtonSpinner(props: UseButtonSpinnerProps): { size: Ref<SpinnerSize>, color: Ref<SpinnerColor> } { export function useButtonSpinner(props: UseButtonSpinnerProps): { size: Ref<SpinnerSize>, color: Ref<SpinnerColor> } {
@@ -15,26 +15,26 @@ export function useButtonSpinner(props: UseButtonSpinnerProps): { size: Ref<Spin
lg: '5', md: '4', sm: '3', xl: '6', xs: '2.5', lg: '5', md: '4', sm: '3', xl: '6', xs: '2.5',
} }
const size = computed<SpinnerSize>(() => { const size = computed<SpinnerSize>(() => {
return btnSizeSpinnerSizeMap[props.size] return btnSizeSpinnerSizeMap[props.size.value]
}) })
const color = computed<SpinnerColor>(() => { const color = computed<SpinnerColor>(() => {
if(!props.outline) return 'white' if(!props.outline.value) return 'white'
if(props.gradient) { if(props.gradient.value) {
if(props.gradient.includes('purple')) return 'purple' if(props.gradient.value.includes('purple')) return 'purple'
else if(props.gradient.includes('blue')) return 'blue' else if(props.gradient.value.includes('blue')) return 'blue'
else if(props.gradient.includes('pink')) return 'pink' else if(props.gradient.value.includes('pink')) return 'pink'
else if(props.gradient.includes('red')) return 'red' else if(props.gradient.value.includes('red')) return 'red'
return 'white' return 'white'
} }
if(['alternative', 'dark', 'light'].includes(props.color)) { if(['alternative', 'dark', 'light'].includes(props.color.value)) {
return 'white' return 'white'
} else if(props.color === 'default') { } else if(props.color.value === 'default') {
return 'blue' return 'blue'
} }
return props.color as SpinnerColor return props.color.value as SpinnerColor
}) })
return { return {

View File

@@ -7,6 +7,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { PropType } from 'vue' import type { PropType } from 'vue'
import { useSpinnerClasses } from './useSpinnerClasses' import { useSpinnerClasses } from './useSpinnerClasses'
import { toRefs } from 'vue'
export type SpinnerSize = '0' | 'px' | '0.5' | '1' | '1.5' | '2' | '2.5' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' export type SpinnerSize = '0' | 'px' | '0.5' | '1' | '1.5' | '2' | '2.5' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12'
export type SpinnerColor = 'blue' | 'gray' | 'green' | 'red' | 'yellow' | 'pink' | 'purple' | 'white' export type SpinnerColor = 'blue' | 'gray' | 'green' | 'red' | 'yellow' | 'pink' | 'purple' | 'white'
@@ -22,5 +23,5 @@ const props = defineProps({
}, },
}) })
const { spinnerClasses } = useSpinnerClasses(props) const { spinnerClasses } = useSpinnerClasses(toRefs(props))
</script> </script>

View File

@@ -35,14 +35,14 @@ const colors: Record<SpinnerColor, string> = {
} }
export type UseSpinnerClassesProps = { export type UseSpinnerClassesProps = {
size: SpinnerSize size: Ref<SpinnerSize>
color: SpinnerColor color: Ref<SpinnerColor>
} }
export function useSpinnerClasses(props: UseSpinnerClassesProps): { spinnerClasses: Ref<string> } { export function useSpinnerClasses(props: UseSpinnerClassesProps): { spinnerClasses: Ref<string> } {
const sizeClasses = computed(() => sizes[props.size]) const sizeClasses = computed(() => sizes[props.size.value])
const colorClasses = computed(() => colors[props.color]) const colorClasses = computed(() => colors[props.color.value])
const bgColorClasses = computed(() => 'text-gray-200 dark:text-gray-600') const bgColorClasses = computed(() => 'text-gray-200 dark:text-gray-600')
const animateClasses = computed(() => 'animate-spin') const animateClasses = computed(() => 'animate-spin')

View File

@@ -1,31 +1,27 @@
<template> <template>
<div :class="divClasses"> <div>
<ul :class="ulClasses"> <div :class="divClasses">
<li class="mr-2"> <ul :class="ulClasses">
<a href="#" aria-current="page" <tab-pane
class="inline-block p-4 text-blue-600 bg-gray-100 rounded-t-lg active dark:bg-gray-800 dark:text-blue-500">Profile</a> v-for="(item, id) in tabsChildren"
</li> :key="id"
<li class="mr-2"> :active="modelValueRef === item.props.name"
<a href="#" :name="item.props.name"
class="inline-block p-4 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 dark:hover:text-gray-300">Dashboard</a> :disabled="item.props.disabled"
</li> :title="item.props.title"
<li class="mr-2"> />
<a href="#" </ul>
class="inline-block p-4 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 dark:hover:text-gray-300">Settings</a> </div>
</li> <slot/>
<li class="mr-2">
<a href="#"
class="inline-block p-4 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 dark:hover:text-gray-300">Contacts</a>
</li>
<li>
<a class="inline-block p-4 text-gray-400 rounded-t-lg cursor-not-allowed dark:text-gray-500">Disabled</a>
</li>
</ul>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { TAB_ACTIVATE_INJECTION_KEY, TAB_STYLE_INJECTION_KEY } from './config'
import { useTabsClasses } from './useTabsClasses' import { useTabsClasses } from './useTabsClasses'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import { computed, provide, useSlots } from 'vue'
import { flatten } from '../../utils/flatten'
import TabPane from './components/TabPane/TabPane.vue'
export type TabsVariant = 'default' | 'underline' | 'pills' export type TabsVariant = 'default' | 'underline' | 'pills'
@@ -34,7 +30,38 @@ const props = defineProps({
type: String as PropType<TabsVariant>, type: String as PropType<TabsVariant>,
default: 'default', default: 'default',
}, },
modelValue: {
type: String,
default: '',
},
}) })
const emit = defineEmits(['update:modelValue'])
const { ulClasses, divClasses } = useTabsClasses(props) const { ulClasses, divClasses } = useTabsClasses(props)
provide(TAB_STYLE_INJECTION_KEY, props.variant)
const slots = useSlots()
const defaultSlot = slots.default
const tabsChildren = computed(() => {
return defaultSlot
? flatten(defaultSlot()).filter((v) => {
return (v.type as { __FLOWBITE_TAB__?: true }).__FLOWBITE_TAB__
})
: []
})
const modelValueRef = computed({
get: () => props.modelValue,
set: (value: string) => emit('update:modelValue', value),
})
const onActivate = (value: string) => {
modelValueRef.value = value
}
provide(TAB_ACTIVATE_INJECTION_KEY, onActivate)
</script> </script>

View File

@@ -1,28 +1,27 @@
<template> <template>
<div> <div>
<ul class=""> <slot />
<li class="mr-2">
<a href="#" aria-current="page"
class="inline-block p-4 text-blue-600 bg-gray-100 rounded-t-lg active dark:bg-gray-800 dark:text-blue-500">Profile</a>
</li>
<li class="mr-2">
<a href="#"
class="inline-block p-4 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 dark:hover:text-gray-300">Dashboard</a>
</li>
<li class="mr-2">
<a href="#"
class="inline-block p-4 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 dark:hover:text-gray-300">Settings</a>
</li>
<li class="mr-2">
<a href="#"
class="inline-block p-4 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 dark:hover:text-gray-300">Contacts</a>
</li>
<li>
<a class="inline-block p-4 text-gray-400 rounded-t-lg cursor-not-allowed dark:text-gray-500">Disabled</a>
</li>
</ul>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
defineProps({
name: {
type: String,
required: true,
},
title: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
})
</script>
<script lang="ts">
export default {
__FLOWBITE_TAB__: true, // add this to easily find tab components from tabs
}
</script> </script>

View File

@@ -0,0 +1,53 @@
<template>
<li>
<div :class="tabClasses" @click="tryActivateTab">
{{ title }}
</div>
</li>
</template>
<script lang="ts" setup>
import { inject, toRefs } from 'vue'
import { TAB_ACTIVATE_INJECTION_KEY, TAB_STYLE_INJECTION_KEY } from '../../config'
import type { TabsVariant } from '../../Tabs.vue'
import { useTabClasses } from './useTabClasses'
const props = defineProps({
name: {
type: String,
required: true,
},
title: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
active: {
type: Boolean,
default: false,
},
})
const variant = inject<TabsVariant>(TAB_STYLE_INJECTION_KEY)
if(!variant) {
console.warn('you can\'t use Tab outside of Tabs component. No tab style injection found')
}
const onActivate = inject<(value: string) => void>(TAB_ACTIVATE_INJECTION_KEY)
if(!onActivate) {
console.warn('you can\'t use Tab outside of Tabs component. No tab activate injection found')
}
const tryActivateTab = () => {
if(props.disabled) return
if(!onActivate) return console.warn('no onActivate')
onActivate(props.name)
}
const { tabClasses } = useTabClasses({
...toRefs(props),
variant,
})
</script>

View File

@@ -0,0 +1,48 @@
import type { Ref } from 'vue'
import { computed } from 'vue'
import type { TabsVariant } from '../../Tabs.vue'
export type TabClassMap = { disabled: string, default: string, active: string }
export type UseTabClassesProps = {
variant?: TabsVariant
active: Ref<boolean>
disabled: Ref<boolean>
}
const defaultTabClasses: TabClassMap = {
default: 'cursor-pointer inline-block p-4 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800 dark:hover:text-gray-300',
active: 'cursor-pointer inline-block p-4 text-blue-600 bg-gray-100 rounded-t-lg active dark:bg-gray-800 dark:text-blue-500',
disabled: 'inline-block p-4 text-gray-400 rounded-t-lg cursor-not-allowed dark:text-gray-500',
}
const underlineTabClasses: TabClassMap = {
default: 'cursor-pointer inline-block p-4 rounded-t-lg border-b-2 border-transparent hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300',
active: 'cursor-pointer inline-block p-4 text-blue-600 rounded-t-lg border-b-2 border-blue-600 active dark:text-blue-500 dark:border-blue-500',
disabled: 'inline-block p-4 text-gray-400 rounded-t-lg cursor-not-allowed dark:text-gray-500',
}
const pillsTabClasses: TabClassMap = {
default: 'cursor-pointer inline-block py-3 px-4 rounded-lg hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 dark:hover:text-white',
active: 'cursor-pointer inline-block py-3 px-4 text-white bg-blue-600 rounded-lg active',
disabled: 'inline-block py-3 px-4 text-gray-400 cursor-not-allowed dark:text-gray-500',
}
export function useTabClasses(props: UseTabClassesProps): {
tabClasses: Ref<string>,
} {
const tabClasses = computed(() => {
const tabClassType: keyof TabClassMap = props.active.value ? 'active' : props.disabled.value ? 'disabled' : 'default'
if(props.variant === 'default')
return defaultTabClasses[tabClassType]
else if(props.variant === 'underline')
return underlineTabClasses[tabClassType]
else if (props.variant === 'pills')
return pillsTabClasses[tabClassType]
return ''
})
return {
tabClasses,
}
}

View File

@@ -0,0 +1,2 @@
export const TAB_STYLE_INJECTION_KEY = 'flowbite-tab-style-injection'
export const TAB_ACTIVATE_INJECTION_KEY = 'flowbite-tab-activate-func-injection'

33
src/utils/flatten.ts Normal file
View File

@@ -0,0 +1,33 @@
import { Fragment, createTextVNode, Comment } from 'vue'
import type { VNodeChild, VNode } from 'vue'
// o(n) flatten
export function flatten (
vNodes: VNodeChild[],
filterCommentNode = true,
result: VNode[] = [],
): VNode[] {
vNodes.forEach((vNode) => {
if (vNode === null) return
if (typeof vNode !== 'object') {
if (typeof vNode === 'string' || typeof vNode === 'number') {
result.push(createTextVNode(String(vNode)))
}
return
}
if (Array.isArray(vNode)) {
flatten(vNode, filterCommentNode, result)
return
}
if (vNode.type === Fragment) {
if (vNode.children === null) return
if (Array.isArray(vNode.children)) {
flatten(vNode.children, filterCommentNode, result)
}
// rawSlot
} else if (vNode.type !== Comment) {
result.push(vNode)
}
})
return result
}