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,31 +1,27 @@
<template>
<div :class="divClasses">
<ul :class="ulClasses">
<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 :class="divClasses">
<ul :class="ulClasses">
<tab-pane
v-for="(item, id) in tabsChildren"
:key="id"
:active="modelValueRef === item.props.name"
:name="item.props.name"
:disabled="item.props.disabled"
:title="item.props.title"
/>
</ul>
</div>
<slot/>
</div>
</template>
<script lang="ts" setup>
import { TAB_ACTIVATE_INJECTION_KEY, TAB_STYLE_INJECTION_KEY } from './config'
import { useTabsClasses } from './useTabsClasses'
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'
@@ -34,7 +30,38 @@ const props = defineProps({
type: String as PropType<TabsVariant>,
default: 'default',
},
modelValue: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:modelValue'])
const { ulClasses, divClasses } = useTabsClasses(props)
</script>
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>

View File

@@ -1,28 +1,27 @@
<template>
<div>
<ul class="">
<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>
<slot />
</div>
</template>
<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>

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'