Merge pull request #11 from Chank1e/chank1e/alert
feat: alert, all props made reactive for all components, tabs
This commit is contained in:
@@ -19,5 +19,6 @@ module.exports = {
|
|||||||
'vue/multi-word-component-names': 'off',
|
'vue/multi-word-component-names': 'off',
|
||||||
'comma-dangle': ['error', 'always-multiline'],
|
'comma-dangle': ['error', 'always-multiline'],
|
||||||
'no-multiple-empty-lines': 'error',
|
'no-multiple-empty-lines': 'error',
|
||||||
|
'object-curly-spacing': ['error', 'always'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
18
docs/.postcssrc.js
Normal file
18
docs/.postcssrc.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// https://github.com/vuejs/vitepress/issues/199#issuecomment-1168325262
|
||||||
|
// by default vitepress adds .vp-doc h1|h2|h3...p and others tags inside vitepress document.
|
||||||
|
// here we add :not(:where(.vp-raw *)) selector to use it inside component examples
|
||||||
|
// to prevent component style pollution from .vp-doc styles
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
'tailwindcss': {},
|
||||||
|
'postcss-prefix-selector': {
|
||||||
|
prefix: ':not(:where(.vp-raw *))',
|
||||||
|
includeFiles: [/vp-doc\.css/],
|
||||||
|
transform(prefix, _selector) {
|
||||||
|
const [selector, pseudo = ''] = _selector.split(/(:\S*)$/)
|
||||||
|
return selector + prefix + pseudo
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,9 +16,11 @@ function buildSidebar() {
|
|||||||
|
|
||||||
function getComponents() {
|
function getComponents() {
|
||||||
return [
|
return [
|
||||||
|
{ text: 'Alert', link: '/guide/alert/alert.md' },
|
||||||
{ text: 'Button', link: '/guide/button/button.md' },
|
{ text: 'Button', link: '/guide/button/button.md' },
|
||||||
{ text: 'Button Group', link: '/guide/buttonGroup/buttonGroup.md' },
|
{ text: 'Button Group', link: '/guide/buttonGroup/buttonGroup.md' },
|
||||||
{ text: 'Spinner', link: '/guide/spinner/spinner.md' },
|
{ text: 'Spinner', link: '/guide/spinner/spinner.md' },
|
||||||
|
{ text: 'Tabs', link: '/guide/tabs/tabs.md' },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +29,7 @@ function getComponents() {
|
|||||||
* https://github.com/vuejs/vitepress/blob/master/docs/.vitepress/config.js
|
* https://github.com/vuejs/vitepress/blob/master/docs/.vitepress/config.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
title: 'flowbite-vue vitepress',
|
title: 'Flowbite Vue 3 Components',
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
docsDir: 'docs',
|
docsDir: 'docs',
|
||||||
sidebar: buildSidebar(),
|
sidebar: buildSidebar(),
|
||||||
|
|||||||
208
docs/guide/alert/alert.md
Normal file
208
docs/guide/alert/alert.md
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
<script setup>
|
||||||
|
import AlertTypeExample from './examples/AlertTypeExample.vue';
|
||||||
|
import AlertTitleExample from './examples/AlertTitleExample.vue';
|
||||||
|
import AlertClosableExample from './examples/AlertClosableExample.vue';
|
||||||
|
import AlertBorderExample from './examples/AlertBorderExample.vue';
|
||||||
|
import AlertIconExample from './examples/AlertIconExample.vue';
|
||||||
|
import AlertInlineExample from './examples/AlertInlineExample.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
# Alert
|
||||||
|
|
||||||
|
reference: [https://flowbite.com/docs/components/alert/](https://flowbite.com/docs/components/alert/)
|
||||||
|
|
||||||
|
## Prop - type
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export type AlertType = 'info' | 'danger' | 'success' | 'warning' | 'dark'
|
||||||
|
defineProps({
|
||||||
|
type: {
|
||||||
|
type: String as PropType<AlertType>,
|
||||||
|
default: 'info',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<AlertTypeExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from 'flowbite-vue'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Alert type="info" class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success">Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - title
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<AlertTitleExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from 'flowbite-vue'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Alert type="info" title="Some info title" class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" title="Some warning title" class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" title="Some danger title" class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" title="Some dark title" class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" title="Some success title">Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - closable
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
defineProps({
|
||||||
|
closable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<AlertClosableExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from 'flowbite-vue'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Alert type="info" closable class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" closable class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" closable class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" closable class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" closable>Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - border
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
defineProps({
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<AlertBorderExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from 'flowbite-vue'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Alert type="info" border class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" border class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" border class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" border class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" border>Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - icon
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
defineProps({
|
||||||
|
icon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<AlertIconExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from 'flowbite-vue'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Alert type="info" :icon="false" class="mb-2">Info</Alert>
|
||||||
|
<Alert title="WARNING" type="warning" :icon="false" class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" :icon="false" class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" :icon="false" class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" :icon="false">Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - inline
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
defineProps({
|
||||||
|
inline: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<AlertInlineExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from 'flowbite-vue'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<Alert type="info" title="Info title" :inline="false" class="mb-2">
|
||||||
|
Lorem...
|
||||||
|
</Alert>
|
||||||
|
<Alert type="warning" title="Warning title" :inline="false" class="mb-2">
|
||||||
|
Lorem...
|
||||||
|
</Alert>
|
||||||
|
<Alert type="danger" title="Danger title" :inline="false" class="mb-2">
|
||||||
|
Lorem...
|
||||||
|
</Alert>
|
||||||
|
<Alert closable type="dark" title="Dark title" :inline="false" class="mb-2">
|
||||||
|
Lorem...
|
||||||
|
</Alert>
|
||||||
|
<Alert type="success" title="Success title" :inline="false">
|
||||||
|
Lorem...
|
||||||
|
<template #actions>
|
||||||
|
<Button size="sm" color="green" class="mr-2">
|
||||||
|
Buttons everywhere
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" outline color="green">
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path></svg>
|
||||||
|
</template>
|
||||||
|
And here
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
12
docs/guide/alert/examples/AlertBorderExample.vue
Normal file
12
docs/guide/alert/examples/AlertBorderExample.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw flex flex-col">
|
||||||
|
<Alert type="info" border class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" border class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" border class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" border class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" border>Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from '../../../../src/index'
|
||||||
|
</script>
|
||||||
12
docs/guide/alert/examples/AlertClosableExample.vue
Normal file
12
docs/guide/alert/examples/AlertClosableExample.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw flex flex-col">
|
||||||
|
<Alert type="info" closable class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" closable class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" closable class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" closable class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" closable>Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from '../../../../src/index'
|
||||||
|
</script>
|
||||||
12
docs/guide/alert/examples/AlertIconExample.vue
Normal file
12
docs/guide/alert/examples/AlertIconExample.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw flex flex-col">
|
||||||
|
<Alert type="info" :icon="false" class="mb-2">Info</Alert>
|
||||||
|
<Alert title="WARNING" type="warning" :icon="false" class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" :icon="false" class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" :icon="false" class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" :icon="false">Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from '../../../../src/index'
|
||||||
|
</script>
|
||||||
33
docs/guide/alert/examples/AlertInlineExample.vue
Normal file
33
docs/guide/alert/examples/AlertInlineExample.vue
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw flex flex-col">
|
||||||
|
<Alert type="info" title="Info title" :inline="false" class="mb-2">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda beatae eaque error est eveniet, facere illo labore libero minima molestiae neque nisi non officia quod sed temporibus unde vitae voluptates.
|
||||||
|
</Alert>
|
||||||
|
<Alert type="warning" title="Warning title" :inline="false" class="mb-2">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur cupiditate dicta dolore dolores hic sequi tenetur, vero! Blanditiis consequatur culpa nisi ratione repellat! Delectus dolore magni nemo placeat qui sequi.
|
||||||
|
</Alert>
|
||||||
|
<Alert type="danger" title="Danger title" :inline="false" class="mb-2">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab accusamus accusantium atque cupiditate, dignissimos dolorum, error inventore iste libero minus nihil possimus quasi quia quibusdam quisquam recusandae repellat reprehenderit temporibus.
|
||||||
|
</Alert>
|
||||||
|
<Alert closable type="dark" title="Dark title" :inline="false" class="mb-2">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. A aperiam dolore et, fuga impedit, iusto nam numquam officiis quas, repellat sapiente sit unde vel? Adipisci delectus dolore eius optio sunt.
|
||||||
|
</Alert>
|
||||||
|
<Alert type="success" title="Success title" :inline="false">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias at culpa cupiditate deleniti eos ipsam ipsum, nostrum perspiciatis provident tempore? Aspernatur expedita praesentium voluptatibus. Accusamus explicabo iusto nobis reiciendis temporibus!
|
||||||
|
<template #actions>
|
||||||
|
<Button size="sm" color="green" class="mr-2">
|
||||||
|
Buttons everywhere
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" outline color="green">
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path></svg>
|
||||||
|
</template>
|
||||||
|
And here
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Alert, Button } from '../../../../src/index'
|
||||||
|
</script>
|
||||||
12
docs/guide/alert/examples/AlertTitleExample.vue
Normal file
12
docs/guide/alert/examples/AlertTitleExample.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw flex flex-col">
|
||||||
|
<Alert type="info" title="Some info title" class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" title="Some warning title" class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" title="Some danger title" class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" title="Some dark title" class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success" title="Some success title">Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from '../../../../src/index'
|
||||||
|
</script>
|
||||||
12
docs/guide/alert/examples/AlertTypeExample.vue
Normal file
12
docs/guide/alert/examples/AlertTypeExample.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw flex flex-col">
|
||||||
|
<Alert type="info" class="mb-2">Info</Alert>
|
||||||
|
<Alert type="warning" class="mb-2">Warning</Alert>
|
||||||
|
<Alert type="danger" class="mb-2">Danger</Alert>
|
||||||
|
<Alert type="dark" class="mb-2">Dark</Alert>
|
||||||
|
<Alert type="success">Success</Alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Alert } from '../../../../src/index'
|
||||||
|
</script>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button color="default">Default</Button>
|
<Button color="default">Default</Button>
|
||||||
<Button color="alternative">Alternative</Button>
|
<Button color="alternative">Alternative</Button>
|
||||||
<Button color="dark">Dark</Button>
|
<Button color="dark">Dark</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button color="default" disabled>Default</Button>
|
<Button color="default" disabled>Default</Button>
|
||||||
<Button color="default" outline disabled>Default outline</Button>
|
<Button color="default" outline disabled>Default outline</Button>
|
||||||
<Button gradient="red" disabled>Red gradient</Button>
|
<Button gradient="red" disabled>Red gradient</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button gradient="purple-blue">Purple to blue</Button>
|
<Button gradient="purple-blue">Purple to blue</Button>
|
||||||
<Button gradient="cyan-blue">Cyan to blue</Button>
|
<Button gradient="cyan-blue">Cyan to blue</Button>
|
||||||
<Button gradient="green-blue">Green to blue</Button>
|
<Button gradient="green-blue">Green to blue</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button gradient="blue">Blue</Button>
|
<Button gradient="blue">Blue</Button>
|
||||||
<Button gradient="cyan">Cyan</Button>
|
<Button gradient="cyan">Cyan</Button>
|
||||||
<Button gradient="green">Green</Button>
|
<Button gradient="green">Green</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button gradient="blue" shadow>Blue with blue</Button>
|
<Button gradient="blue" shadow>Blue with blue</Button>
|
||||||
<Button gradient="cyan" shadow>Cyan with cyan</Button>
|
<Button gradient="cyan" shadow>Cyan with cyan</Button>
|
||||||
<Button gradient="green" shadow>Green with green</Button>
|
<Button gradient="green" shadow>Green with green</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button gradient="purple-blue" square>
|
<Button gradient="purple-blue" square>
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex items-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex items-center gap-2 flex-wrap">
|
||||||
<Button gradient="purple-blue" outline :disabled="loading" :loading="loading" @click="loading = !loading" size="xs">
|
<Button gradient="purple-blue" outline :disabled="loading" :loading="loading" @click="loading = !loading" size="xs">
|
||||||
Click me
|
Click me
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button color="default" outline>Default</Button>
|
<Button color="default" outline>Default</Button>
|
||||||
<Button color="dark" outline>Dark</Button>
|
<Button color="dark" outline>Dark</Button>
|
||||||
<Button color="green" outline>Green</Button>
|
<Button color="green" outline>Green</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button gradient="purple-blue" outline>Purple to blue</Button>
|
<Button gradient="purple-blue" outline>Purple to blue</Button>
|
||||||
<Button gradient="cyan-blue" outline>Cyan to blue</Button>
|
<Button gradient="cyan-blue" outline>Cyan to blue</Button>
|
||||||
<Button gradient="green-blue" outline>Green to blue</Button>
|
<Button gradient="green-blue" outline>Green to blue</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button color="default" pill>Default</Button>
|
<Button color="default" pill>Default</Button>
|
||||||
<Button color="alternative" pill>Alternative</Button>
|
<Button color="alternative" pill>Alternative</Button>
|
||||||
<Button color="dark" pill>Dark</Button>
|
<Button color="dark" pill>Dark</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button color="default">
|
<Button color="default">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path></svg>
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path></svg>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex items-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex items-center gap-2 flex-wrap">
|
||||||
<Button size="xs">Extra small - xs</Button>
|
<Button size="xs">Extra small - xs</Button>
|
||||||
<Button size="sm">Small - sm</Button>
|
<Button size="sm">Small - sm</Button>
|
||||||
<Button size="md">Medium - md</Button>
|
<Button size="md">Medium - md</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button gradient="red-yellow" square>
|
<Button gradient="red-yellow" square>
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<Button color="default">
|
<Button color="default">
|
||||||
Choose plan
|
Choose plan
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<button-group>
|
<div class="vp-raw">
|
||||||
<Button>hello world</Button>
|
<button-group>
|
||||||
<Button color="purple">hello world</Button>
|
<Button>hello world</Button>
|
||||||
<Button color="alternative">hello world</Button>
|
<Button color="purple">hello world</Button>
|
||||||
<Button color="red">hello world</Button>
|
<Button color="alternative">hello world</Button>
|
||||||
</button-group>
|
<Button color="red">hello world</Button>
|
||||||
|
</button-group>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ButtonGroup, Button } from '../../../../src/index'
|
import { ButtonGroup, Button } from '../../../../src/index'
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<button-group>
|
<div class="vp-raw">
|
||||||
<Button outline>Button1</Button>
|
<button-group>
|
||||||
<Button outline>Button2</Button>
|
<Button outline>Button1</Button>
|
||||||
<Button outline>Button3</Button>
|
<Button outline>Button2</Button>
|
||||||
<Button outline>
|
<Button outline>Button3</Button>
|
||||||
hello world
|
<Button outline>
|
||||||
<template #suffix>
|
hello world
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
<template #suffix>
|
||||||
</template>
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||||
</Button>
|
</template>
|
||||||
</button-group>
|
</Button>
|
||||||
|
</button-group>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ButtonGroup, Button } from '../../../../src/index'
|
import { ButtonGroup, Button } from '../../../../src/index'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<spinner />
|
<spinner />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<spinner color="blue" size="6" />
|
<spinner color="blue" size="6" />
|
||||||
<spinner color="pink" size="8" />
|
<spinner color="pink" size="8" />
|
||||||
<spinner color="gray" size="10" />
|
<spinner color="gray" size="10" />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex align-center gap-2 flex-wrap">
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
<spinner />
|
<spinner />
|
||||||
<spinner size="6" />
|
<spinner size="6" />
|
||||||
<spinner size="8" />
|
<spinner size="8" />
|
||||||
|
|||||||
23
docs/guide/tabs/examples/TabsDefaultExample.vue
Normal file
23
docs/guide/tabs/examples/TabsDefaultExample.vue
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw">
|
||||||
|
<tabs v-model="activeTab" class="p-5">
|
||||||
|
<tab name="first" title="First">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Explicabo, id, nisi? Enim excepturi id minus molestias quaerat qui rem repudiandae sed tempore ullam voluptate, voluptatum. Consequuntur illum possimus tempora totam.
|
||||||
|
</tab>
|
||||||
|
<tab name="second" title="Second">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda consectetur expedita explicabo facere facilis fugit illo laboriosam minus molestias nulla placeat porro quaerat, quo repellat sapiente similique temporibus voluptate. Nemo!
|
||||||
|
</tab>
|
||||||
|
<tab name="third" title="Third">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus alias assumenda consequatur, dicta eius eos excepturi hic magnam maxime molestias nisi perferendis provident quia. Aliquam consequatur esse ex sit velit.
|
||||||
|
</tab>
|
||||||
|
<tab name="fourth" title="Fourth" :disabled="true">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi deleniti dolores ea eligendi quis, ratione repellat temporibus veniam veritatis voluptates. Distinctio enim eos illo incidunt ipsam provident, quaerat quia vel!
|
||||||
|
</tab>
|
||||||
|
</tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Tabs, Tab } from '../../../../src/index'
|
||||||
|
const activeTab = ref('first')
|
||||||
|
</script>
|
||||||
23
docs/guide/tabs/examples/TabsPillsExample.vue
Normal file
23
docs/guide/tabs/examples/TabsPillsExample.vue
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw">
|
||||||
|
<tabs variant="pills" v-model="activeTab" class="p-5">
|
||||||
|
<tab name="first" title="First">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab aspernatur debitis iste libero molestiae mollitia, optio sunt? A, consectetur distinctio, eaque harum iusto laudantium, molestiae nam odio officia pariatur vitae?
|
||||||
|
</tab>
|
||||||
|
<tab name="second" title="Second">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores autem cupiditate, deleniti eligendi exercitationem magnam maiores, minus pariatur provident quasi qui quidem recusandae rem reprehenderit sapiente sequi sint soluta.
|
||||||
|
</tab>
|
||||||
|
<tab name="third" title="Third">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam animi aperiam assumenda consectetur, dolorem, dolores, ea eos ipsum itaque iure laudantium nostrum nulla numquam perspiciatis provident qui quod totam voluptatem.
|
||||||
|
</tab>
|
||||||
|
<tab name="fourth" title="Fourth" :disabled="true">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto blanditiis cupiditate ea error eveniet hic impedit in labore maxime, minima mollitia nam sapiente sint tempora tempore vel velit veniam, voluptatem.
|
||||||
|
</tab>
|
||||||
|
</tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Tabs, Tab } from '../../../../src/index'
|
||||||
|
const activeTab = ref('first')
|
||||||
|
</script>
|
||||||
23
docs/guide/tabs/examples/TabsUnderlineExample.vue
Normal file
23
docs/guide/tabs/examples/TabsUnderlineExample.vue
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw">
|
||||||
|
<tabs variant="underline" v-model="activeTab" class="p-5">
|
||||||
|
<tab name="first" title="First">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab aspernatur debitis iste libero molestiae mollitia, optio sunt? A, consectetur distinctio, eaque harum iusto laudantium, molestiae nam odio officia pariatur vitae?
|
||||||
|
</tab>
|
||||||
|
<tab name="second" title="Second">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores autem cupiditate, deleniti eligendi exercitationem magnam maiores, minus pariatur provident quasi qui quidem recusandae rem reprehenderit sapiente sequi sint soluta.
|
||||||
|
</tab>
|
||||||
|
<tab name="third" title="Third">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam animi aperiam assumenda consectetur, dolorem, dolores, ea eos ipsum itaque iure laudantium nostrum nulla numquam perspiciatis provident qui quod totam voluptatem.
|
||||||
|
</tab>
|
||||||
|
<tab name="fourth" title="Fourth" :disabled="true">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto blanditiis cupiditate ea error eveniet hic impedit in labore maxime, minima mollitia nam sapiente sint tempora tempore vel velit veniam, voluptatem.
|
||||||
|
</tab>
|
||||||
|
</tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Tabs, Tab } from '../../../../src/index'
|
||||||
|
const activeTab = ref('first')
|
||||||
|
</script>
|
||||||
116
docs/guide/tabs/tabs.md
Normal file
116
docs/guide/tabs/tabs.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<script setup>
|
||||||
|
import TabsDefaultExample from './examples/TabsDefaultExample.vue';
|
||||||
|
import TabsPillsExample from './examples/TabsPillsExample.vue';
|
||||||
|
import TabsUnderlineExample from './examples/TabsUnderlineExample.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
## Prop - variant (default)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export type TabsVariant = 'default' | 'underline' | 'pills'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
variant: {
|
||||||
|
type: String as PropType<TabsVariant>,
|
||||||
|
default: 'default',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<TabsDefaultExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Tabs, Tab } from 'flowbite-vue'
|
||||||
|
const activeTab = ref('first')
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<tabs v-model="activeTab" class="p-5"> <!-- class appends to content DIV for all tabs -->
|
||||||
|
<tab name="first" title="First">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="second" title="Second">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="third" title="Third">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="fourth" title="Fourth" :disabled="true">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
</tabs>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - variant (underline)
|
||||||
|
|
||||||
|
<TabsUnderlineExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Tabs, Tab } from 'flowbite-vue'
|
||||||
|
const activeTab = ref('first')
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<tabs variant="underline" v-model="activeTab" class="p-5"> <!-- class appends to content DIV for all tabs -->
|
||||||
|
<tab name="first" title="First">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="second" title="Second">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="third" title="Third">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="fourth" title="Fourth" :disabled="true">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
</tabs>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - variant (pills)
|
||||||
|
|
||||||
|
<TabsPillsExample />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Tabs, Tab } from 'flowbite-vue'
|
||||||
|
const activeTab = ref('first')
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<tabs variant="pills" v-model="activeTab" class="p-5"> <!-- class appends to content DIV for all tabs -->
|
||||||
|
<tab name="first" title="First">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="second" title="Second">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="third" title="Third">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
<tab name="fourth" title="Fourth" :disabled="true">
|
||||||
|
Lorem...
|
||||||
|
</tab>
|
||||||
|
</tabs>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prop - directive
|
||||||
|
|
||||||
|
Use this props if you want to control which directive to use for rendering every tab content
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export type TabsVariant = 'default' | 'underline' | 'pills'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
directive: {
|
||||||
|
type: String as PropType<'if' | 'show'>,
|
||||||
|
default: 'if',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -2357,6 +2357,12 @@
|
|||||||
"postcss-selector-parser": "^6.0.6"
|
"postcss-selector-parser": "^6.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"postcss-prefix-selector": {
|
||||||
|
"version": "1.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-prefix-selector/-/postcss-prefix-selector-1.16.0.tgz",
|
||||||
|
"integrity": "sha512-rdVMIi7Q4B0XbXqNUEI+Z4E+pueiu/CS5E6vRCQommzdQ/sgsS4dK42U7GX8oJR+TJOtT+Qv3GkNo6iijUMp3Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"postcss-selector-parser": {
|
"postcss-selector-parser": {
|
||||||
"version": "6.0.10",
|
"version": "6.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||||
|
|||||||
@@ -44,7 +44,8 @@
|
|||||||
"eslint-plugin-vue": "^9.1.1",
|
"eslint-plugin-vue": "^9.1.1",
|
||||||
"flowbite": "^1.4.2",
|
"flowbite": "^1.4.2",
|
||||||
"jsdom": "^20.0.0",
|
"jsdom": "^20.0.0",
|
||||||
"postcss": "^8.4.6",
|
"postcss": "^8.4.14",
|
||||||
|
"postcss-prefix-selector": "^1.16.0",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
"tailwindcss": "^3.1.4",
|
"tailwindcss": "^3.1.4",
|
||||||
"typescript": "^4.7.3",
|
"typescript": "^4.7.3",
|
||||||
@@ -53,10 +54,5 @@
|
|||||||
"vitest": "^0.16.0",
|
"vitest": "^0.16.0",
|
||||||
"vue-eslint-parser": "^9.0.3",
|
"vue-eslint-parser": "^9.0.3",
|
||||||
"vue-tsc": "^0.38.2"
|
"vue-tsc": "^0.38.2"
|
||||||
},
|
|
||||||
"postcss": {
|
|
||||||
"plugins": {
|
|
||||||
"tailwindcss": {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
73
src/components/Alert/Alert.vue
Normal file
73
src/components/Alert/Alert.vue
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="alertClasses" role="alert" v-if="visible">
|
||||||
|
<div :class="inline ? 'flex' : 'flex items-center'">
|
||||||
|
<svg v-if="icon" :class="['flex-shrink-0', 'w-5', 'h-5', textClasses]" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path></svg>
|
||||||
|
<span
|
||||||
|
:class="titleClasses"
|
||||||
|
v-if="title"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</span>
|
||||||
|
<button type="button" :class="closeClasses" aria-label="Close" @click="onCloseClick" v-if="!inline && closable">
|
||||||
|
<span class="sr-only">Dismiss</span>
|
||||||
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div :class="contentClasses">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div class="inline-flex items-center" v-if="$slots.actions">
|
||||||
|
<slot name="actions" />
|
||||||
|
</div>
|
||||||
|
<button type="button" :class="closeClasses" aria-label="Close" @click="onCloseClick" v-if="inline && closable">
|
||||||
|
<span class="sr-only">Dismiss</span>
|
||||||
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { useAlertClasses } from './useAlertClasses'
|
||||||
|
import { onBeforeUnmount, ref, toRefs } from 'vue'
|
||||||
|
|
||||||
|
export type AlertType = 'info' | 'danger' | 'success' | 'warning' | 'dark'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String as PropType<AlertType>,
|
||||||
|
default: 'info',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
closable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
inline: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const { alertClasses, textClasses, closeClasses, contentClasses, titleClasses } = useAlertClasses(toRefs(props))
|
||||||
|
|
||||||
|
const visible = ref(true)
|
||||||
|
|
||||||
|
const onCloseClick = () => {
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
console.log('UNMOUNTED')
|
||||||
|
})
|
||||||
|
</script>
|
||||||
106
src/components/Alert/useAlertClasses.ts
Normal file
106
src/components/Alert/useAlertClasses.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import type { AlertType } from './Alert.vue'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
const defaultAlertClasses = 'p-4 text-sm'
|
||||||
|
|
||||||
|
const alertTextClasses: Record<AlertType, string> = {
|
||||||
|
danger: 'text-red-700 dark:text-red-800',
|
||||||
|
dark: 'text-gray-700 dark:text-gray-300',
|
||||||
|
info: 'text-blue-700 dark:text-blue-800',
|
||||||
|
success: 'text-green-700 dark:text-green-800',
|
||||||
|
warning: 'text-yellow-700 dark:text-yellow-800',
|
||||||
|
}
|
||||||
|
|
||||||
|
const alertTypeClasses: Record<AlertType, string> = {
|
||||||
|
danger: 'bg-red-100 dark:bg-red-200',
|
||||||
|
dark: 'bg-gray-100 dark:bg-gray-700',
|
||||||
|
info: 'bg-blue-100 dark:bg-blue-200',
|
||||||
|
success: 'bg-green-100 dark:bg-green-200',
|
||||||
|
warning: 'bg-yellow-100 dark:bg-yellow-200',
|
||||||
|
}
|
||||||
|
|
||||||
|
const alertBorderClasses: Record<AlertType, string> = {
|
||||||
|
danger: 'border-t-4 border-red-500',
|
||||||
|
dark: 'border-t-4 border-gray-500',
|
||||||
|
info: 'border-t-4 border-blue-500',
|
||||||
|
success: 'border-t-4 border-green-500',
|
||||||
|
warning: 'border-t-4 border-yellow-500',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const defaultCloseButtonClasses = 'ml-auto -mx-1.5 -my-1.5 rounded-lg focus:ring-2 p-1.5 inline-flex h-8 w-8'
|
||||||
|
|
||||||
|
const closeButtonClasses: Record<AlertType, string> = {
|
||||||
|
danger: 'hover:bg-red-200 dark:hover:bg-red-300 focus:ring-red-400 bg-red-100 dark:bg-red-200 text-red-500',
|
||||||
|
dark: 'dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white hover:bg-gray-200 focus:ring-gray-400 bg-gray-100 text-gray-500',
|
||||||
|
info: 'hover:bg-blue-200 dark:hover:bg-blue-300 focus:ring-blue-400 bg-blue-100 dark:bg-blue-200 text-blue-500',
|
||||||
|
success: 'bg-green-100 dark:bg-green-200 text-green-500 focus:ring-green-400 hover:bg-green-200 dark:hover:bg-green-300',
|
||||||
|
warning: 'focus:ring-yellow-400 hover:bg-yellow-200 dark:hover:bg-yellow-300 bg-yellow-100 dark:bg-yellow-200 text-yellow-500',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseAlertClassesProps = {
|
||||||
|
type: Ref<AlertType>
|
||||||
|
border: Ref<boolean>
|
||||||
|
icon: Ref<boolean>
|
||||||
|
inline: Ref<boolean>
|
||||||
|
title: Ref<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAlertClasses(props: UseAlertClassesProps): {
|
||||||
|
alertClasses: Ref<string>,
|
||||||
|
textClasses: Ref<string>,
|
||||||
|
closeClasses: Ref<string>,
|
||||||
|
contentClasses: Ref<string>,
|
||||||
|
titleClasses: Ref<string>,
|
||||||
|
} {
|
||||||
|
|
||||||
|
const alertClasses = computed<string>(() => {
|
||||||
|
return classNames(
|
||||||
|
defaultAlertClasses,
|
||||||
|
alertTypeClasses[props.type.value],
|
||||||
|
textClasses.value,
|
||||||
|
props.border.value ? alertBorderClasses[props.type.value] : 'rounded-lg', // rounded only if no border
|
||||||
|
props.inline.value ? 'flex' : '',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const textClasses = computed<string>(() => {
|
||||||
|
return classNames(
|
||||||
|
alertTextClasses[props.type.value],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const closeClasses = computed<string>(() => {
|
||||||
|
return classNames(
|
||||||
|
defaultCloseButtonClasses,
|
||||||
|
closeButtonClasses[props.type.value],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const contentClasses = computed<string>(() => {
|
||||||
|
if(!props.inline.value) return classNames('mt-2 mb-4')
|
||||||
|
if(!props.icon.value && !props.title.value) return ''
|
||||||
|
return classNames(!props.title.value ? 'ml-3' : 'ml-1')
|
||||||
|
})
|
||||||
|
|
||||||
|
const titleClasses = computed<string>(() => {
|
||||||
|
if(!props.icon.value || !props.inline.value) return classNames(
|
||||||
|
'font-medium',
|
||||||
|
!props.inline.value ? 'text-lg ml-2' : '',
|
||||||
|
)
|
||||||
|
return classNames(
|
||||||
|
'font-medium ml-3',
|
||||||
|
!props.inline.value ? 'text-lg' : '',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
alertClasses,
|
||||||
|
textClasses,
|
||||||
|
closeClasses,
|
||||||
|
contentClasses,
|
||||||
|
titleClasses,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import classNames from 'classnames'
|
|||||||
import type { ButtonDuotoneGradient, ButtonGradient, ButtonMonochromeGradient, ButtonSize, ButtonVariant } from './Button.vue'
|
import type { ButtonDuotoneGradient, ButtonGradient, ButtonMonochromeGradient, ButtonSize, ButtonVariant } from './Button.vue'
|
||||||
|
|
||||||
|
|
||||||
const buttonColorClasses: { hover: Record<ButtonVariant, string>, default: Record<ButtonVariant, string> } = {
|
export type ButtonClassMap<T extends string> = { hover: Record<T, string>, default: Record<T, string> }
|
||||||
|
|
||||||
|
const buttonColorClasses: ButtonClassMap<ButtonVariant> = {
|
||||||
default: {
|
default: {
|
||||||
default: 'text-white bg-blue-700 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg dark:bg-blue-600 focus:outline-none dark:focus:ring-blue-800',
|
default: 'text-white bg-blue-700 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg dark:bg-blue-600 focus:outline-none dark:focus:ring-blue-800',
|
||||||
alternative: 'font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600',
|
alternative: 'font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600',
|
||||||
@@ -28,10 +30,7 @@ const buttonColorClasses: { hover: Record<ButtonVariant, string>, default: Reco
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const buttonOutlineColorClasses: {
|
const buttonOutlineColorClasses: ButtonClassMap<Exclude<ButtonVariant, 'light' | 'alternative'>> = {
|
||||||
hover: Record<Exclude<ButtonVariant, 'light' | 'alternative'>, string>,
|
|
||||||
default: Record<Exclude<ButtonVariant, 'light' | 'alternative'>, string>
|
|
||||||
} = {
|
|
||||||
default: {
|
default: {
|
||||||
dark: 'text-gray-900 border border-gray-800 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium rounded-lg text-sm text-center dark:border-gray-600 dark:text-gray-400 dark:focus:ring-gray-800',
|
dark: 'text-gray-900 border border-gray-800 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium rounded-lg text-sm text-center dark:border-gray-600 dark:text-gray-400 dark:focus:ring-gray-800',
|
||||||
default: 'text-blue-700 border border-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm text-center dark:border-blue-500 dark:text-blue-500 dark:focus:ring-blue-800',
|
default: 'text-blue-700 border border-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm text-center dark:border-blue-500 dark:text-blue-500 dark:focus:ring-blue-800',
|
||||||
@@ -51,7 +50,7 @@ const buttonOutlineColorClasses: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const buttonGradientClasses: { hover: Record<ButtonGradient, string>, default: Record<ButtonGradient, string> } = {
|
const buttonGradientClasses: ButtonClassMap<ButtonGradient> = {
|
||||||
hover: {
|
hover: {
|
||||||
'cyan-blue': 'hover:bg-gradient-to-bl',
|
'cyan-blue': 'hover:bg-gradient-to-bl',
|
||||||
'green-blue': 'hover:bg-gradient-to-bl',
|
'green-blue': 'hover:bg-gradient-to-bl',
|
||||||
@@ -88,7 +87,7 @@ const buttonGradientClasses: { hover: Record<ButtonGradient, string>, default: R
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const buttonOutlineGradientClasses: { hover: Record<ButtonDuotoneGradient, string>, default: Record<ButtonDuotoneGradient, string> } = {
|
const buttonOutlineGradientClasses: ButtonClassMap<ButtonDuotoneGradient> = {
|
||||||
default: {
|
default: {
|
||||||
'cyan-blue':
|
'cyan-blue':
|
||||||
'relative inline-flex items-center justify-center overflow-hidden font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-cyan-500 to-blue-500 dark:text-white focus:ring-4 focus:outline-none focus:ring-cyan-200 dark:focus:ring-cyan-800',
|
'relative inline-flex items-center justify-center overflow-hidden font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-cyan-500 to-blue-500 dark:text-white focus:ring-4 focus:outline-none focus:ring-cyan-200 dark:focus:ring-cyan-800',
|
||||||
@@ -145,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']
|
||||||
@@ -163,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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,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 ''
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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')
|
||||||
|
|
||||||
|
|||||||
87
src/components/Tabs/Tabs.vue
Normal file
87
src/components/Tabs/Tabs.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<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>
|
||||||
|
<div v-bind="$attrs">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
TAB_ACTIVATE_INJECTION_KEY,
|
||||||
|
TAB_ACTIVE_NAME_INJECTION_KEY,
|
||||||
|
TAB_STYLE_INJECTION_KEY,
|
||||||
|
TAB_VISIBILITY_DIRECTIVE_INJECTION_KEY,
|
||||||
|
} from './config'
|
||||||
|
import { useTabsClasses } from './useTabsClasses'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { computed, provide, toRef, useSlots } from 'vue'
|
||||||
|
import { flatten } from '../../utils/flatten'
|
||||||
|
import TabPane from './components/TabPane/TabPane.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
variant: {
|
||||||
|
type: String as PropType<TabsVariant>,
|
||||||
|
default: 'default',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
directive: {
|
||||||
|
type: String as PropType<'if' | 'show'>,
|
||||||
|
default: 'if',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
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),
|
||||||
|
})
|
||||||
|
|
||||||
|
provide(TAB_ACTIVE_NAME_INJECTION_KEY, modelValueRef)
|
||||||
|
provide(TAB_VISIBILITY_DIRECTIVE_INJECTION_KEY, toRef(props, 'directive'))
|
||||||
|
|
||||||
|
|
||||||
|
const onActivate = (value: string) => {
|
||||||
|
modelValueRef.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
provide(TAB_ACTIVATE_INJECTION_KEY, onActivate)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TabsVariant = 'default' | 'underline' | 'pills'
|
||||||
|
</script>
|
||||||
42
src/components/Tabs/components/Tab/Tab.vue
Normal file
42
src/components/Tabs/components/Tab/Tab.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="directive === 'if'">
|
||||||
|
<div v-if="activeTab === name">
|
||||||
|
<slot/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="directive === 'show'">
|
||||||
|
<div v-show="activeTab === name">
|
||||||
|
<slot/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { inject } from 'vue'
|
||||||
|
import { TAB_ACTIVE_NAME_INJECTION_KEY, TAB_VISIBILITY_DIRECTIVE_INJECTION_KEY } from '../../config'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const activeTab = inject(TAB_ACTIVE_NAME_INJECTION_KEY, '')
|
||||||
|
const directive = inject(TAB_VISIBILITY_DIRECTIVE_INJECTION_KEY, 'if')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
__FLOWBITE_TAB__: true, // add this to easily find tab components from tabs
|
||||||
|
}
|
||||||
|
</script>
|
||||||
53
src/components/Tabs/components/TabPane/TabPane.vue
Normal file
53
src/components/Tabs/components/TabPane/TabPane.vue
Normal 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>
|
||||||
48
src/components/Tabs/components/TabPane/useTabClasses.ts
Normal file
48
src/components/Tabs/components/TabPane/useTabClasses.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/components/Tabs/config.ts
Normal file
4
src/components/Tabs/config.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const TAB_STYLE_INJECTION_KEY = 'flowbite-tab-style-injection'
|
||||||
|
export const TAB_ACTIVE_NAME_INJECTION_KEY = 'flowbite-tab-active-name-injection'
|
||||||
|
export const TAB_VISIBILITY_DIRECTIVE_INJECTION_KEY = 'flowbite-tab-visibility-directive-injection'
|
||||||
|
export const TAB_ACTIVATE_INJECTION_KEY = 'flowbite-tab-activate-func-injection'
|
||||||
34
src/components/Tabs/useTabsClasses.ts
Normal file
34
src/components/Tabs/useTabsClasses.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import type { Ref } from 'vue'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import type { TabsVariant } from './Tabs.vue'
|
||||||
|
|
||||||
|
export type UseTabsClassesProps = {
|
||||||
|
variant: TabsVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTabsClasses(props: UseTabsClassesProps): {
|
||||||
|
ulClasses: Ref<string>,
|
||||||
|
divClasses: Ref<string>,
|
||||||
|
} {
|
||||||
|
|
||||||
|
const ulClasses = computed(() => {
|
||||||
|
if(props.variant === 'default')
|
||||||
|
return 'flex flex-wrap text-sm font-medium text-center text-gray-500 border-b border-gray-200 dark:border-gray-700 dark:text-gray-400'
|
||||||
|
else if(props.variant === 'pills')
|
||||||
|
return 'flex flex-wrap text-sm font-medium text-center text-gray-500 dark:text-gray-400'
|
||||||
|
else if(props.variant === 'underline')
|
||||||
|
return 'flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500 dark:text-gray-400'
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const divClasses = computed(() => {
|
||||||
|
if(props.variant === 'underline')
|
||||||
|
return 'text-sm font-medium text-center text-gray-500 border-b border-gray-200 dark:text-gray-400 dark:border-gray-700'
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
ulClasses,
|
||||||
|
divClasses,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
export { default as Button } from './components/Button/Button.vue'
|
export { default as Button } from './components/Button/Button.vue'
|
||||||
export { default as Spinner } from './components/Spinner/Spinner.vue'
|
export { default as Spinner } from './components/Spinner/Spinner.vue'
|
||||||
export { default as ButtonGroup } from './components/ButtonGroup/ButtonGroup.vue'
|
export { default as ButtonGroup } from './components/ButtonGroup/ButtonGroup.vue'
|
||||||
|
export { default as Alert } from './components/Alert/Alert.vue'
|
||||||
|
export { default as Tabs } from './components/Tabs/Tabs.vue'
|
||||||
|
export { default as Tab } from './components/Tabs/components/Tab/Tab.vue'
|
||||||
|
|||||||
33
src/utils/flatten.ts
Normal file
33
src/utils/flatten.ts
Normal 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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user