@reinvented/design 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/DESIGN_GUIDE.md +148 -0
  2. package/README.md +39 -162
  3. package/docs/components/index.md +50 -0
  4. package/docs/conventions.md +74 -0
  5. package/docs/layouts/index.md +32 -0
  6. package/docs/patterns/index.md +39 -0
  7. package/docs/rules.md +43 -0
  8. package/docs/visual-polish.md +141 -0
  9. package/package.json +40 -61
  10. package/src/components/ui/avatar/Avatar.vue +14 -0
  11. package/src/components/ui/avatar/index.ts +1 -0
  12. package/src/components/ui/badge/Badge.vue +27 -0
  13. package/src/components/ui/badge/index.ts +1 -0
  14. package/src/components/ui/button/Button.vue +66 -0
  15. package/src/components/ui/button/index.ts +1 -0
  16. package/src/components/ui/card/Card.vue +13 -0
  17. package/src/components/ui/card/CardContent.vue +7 -0
  18. package/src/components/ui/card/CardDescription.vue +7 -0
  19. package/src/components/ui/card/CardFooter.vue +7 -0
  20. package/src/components/ui/card/CardHeader.vue +9 -0
  21. package/src/components/ui/card/CardTitle.vue +7 -0
  22. package/src/components/ui/card/index.ts +6 -0
  23. package/src/components/ui/input/Input.vue +23 -0
  24. package/src/components/ui/input/index.ts +1 -0
  25. package/src/components/ui/lib/utils.ts +2 -0
  26. package/src/components/ui/scroll-area/ScrollArea.vue +13 -0
  27. package/src/components/ui/scroll-area/index.ts +1 -0
  28. package/src/components/ui/separator/Separator.vue +16 -0
  29. package/src/components/ui/separator/index.ts +1 -0
  30. package/src/components/ui/skeleton/Skeleton.vue +9 -0
  31. package/src/components/ui/skeleton/index.ts +1 -0
  32. package/src/env.d.ts +7 -0
  33. package/src/index.ts +209 -0
  34. package/src/lib/utils.ts +7 -0
  35. package/src/patterns/DetailView.vue +46 -0
  36. package/src/patterns/EmptyState.vue +27 -0
  37. package/src/patterns/FormView.vue +34 -0
  38. package/src/patterns/ListView.vue +45 -0
  39. package/src/styles/index.css +4 -0
  40. package/src/styles/tokens.css +144 -0
  41. package/tailwind.config.js +108 -0
  42. package/tsconfig.json +7 -0
  43. package/dist/index.css +0 -1890
  44. package/dist/index.d.ts +0 -406
  45. package/dist/index.js +0 -1721
  46. package/dist/index.js.map +0 -1
  47. package/tailwind.config.ts +0 -174
@@ -0,0 +1,141 @@
1
+ # Visual Polish Guide
2
+
3
+ Standards for animations, transitions, loading patterns, and interaction polish.
4
+
5
+ ## Transition Durations
6
+
7
+ | Duration | Use |
8
+ |----------|-----|
9
+ | `duration-150` (150ms) | Hover states, color changes, opacity |
10
+ | `duration-200` (200ms) | Modals open/close, tooltips, popovers |
11
+ | `duration-300` (300ms) | Page transitions, slide-ins, expanded sections |
12
+
13
+ **Easing**: Use `ease-out` for entrances, `ease-in` for exits, `ease-in-out` for state changes.
14
+
15
+ ## Modal Animations
16
+
17
+ ```vue
18
+ <!-- Dialog with fade + scale -->
19
+ <DialogContent class="
20
+ data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95
21
+ data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95
22
+ duration-200
23
+ ">
24
+ ```
25
+
26
+ ## List Item Animations
27
+
28
+ ```vue
29
+ <TransitionGroup name="list" tag="div">
30
+ <Card v-for="item in items" :key="item.id">
31
+ <!-- content -->
32
+ </Card>
33
+ </TransitionGroup>
34
+
35
+ <style>
36
+ .list-enter-active { transition: all 0.3s ease-out; }
37
+ .list-leave-active { transition: all 0.2s ease-in; }
38
+ .list-enter-from { opacity: 0; transform: translateY(8px); }
39
+ .list-leave-to { opacity: 0; transform: translateX(-16px); }
40
+ .list-move { transition: transform 0.3s ease; }
41
+ </style>
42
+ ```
43
+
44
+ ## Button Loading State
45
+
46
+ ```vue
47
+ <script setup>
48
+ import { ref } from 'vue'
49
+ import { Button } from '@reinvented/design'
50
+ import { Loader2 } from 'lucide-vue-next'
51
+
52
+ const saving = ref(false)
53
+ async function handleSave() {
54
+ saving.value = true
55
+ try {
56
+ await saveMutation()
57
+ } finally {
58
+ saving.value = false
59
+ }
60
+ }
61
+ </script>
62
+
63
+ <template>
64
+ <Button :disabled="saving" @click="handleSave">
65
+ <Loader2 v-if="saving" class="w-4 h-4 mr-2 animate-spin" />
66
+ {{ saving ? 'Saving...' : 'Save' }}
67
+ </Button>
68
+ </template>
69
+ ```
70
+
71
+ ## Skeleton Loading
72
+
73
+ Skeletons must match the shape of the actual content:
74
+
75
+ ```vue
76
+ <!-- Skeleton for a card list -->
77
+ <div class="space-y-4">
78
+ <div v-for="i in 3" :key="i" class="p-4 border rounded-lg">
79
+ <div class="flex items-center gap-3">
80
+ <Skeleton class="w-10 h-10 rounded-full" />
81
+ <div class="flex-1 space-y-2">
82
+ <Skeleton class="h-4 w-3/4" />
83
+ <Skeleton class="h-3 w-1/2" />
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ ```
89
+
90
+ ## Toast Notifications
91
+
92
+ ```vue
93
+ <script setup>
94
+ import { toast } from '@reinvented/design'
95
+
96
+ // Success
97
+ toast.success('Task created')
98
+
99
+ // Error with action
100
+ toast.error('Failed to save', {
101
+ action: { label: 'Retry', onClick: () => handleSave() }
102
+ })
103
+
104
+ // Promise-based (auto shows loading → success/error)
105
+ toast.promise(saveMutation(), {
106
+ loading: 'Saving...',
107
+ success: 'Saved!',
108
+ error: 'Failed to save'
109
+ })
110
+ </script>
111
+ ```
112
+
113
+ ## Focus Management
114
+
115
+ - **Modal open**: Focus first interactive element inside the modal
116
+ - **Modal close**: Return focus to the trigger element
117
+ - **After delete**: Focus the next item in the list (or empty state)
118
+ - **After create**: Focus the newly created item (or close modal and show toast)
119
+ - **Tab order**: Logical reading order, top-to-bottom, left-to-right
120
+
121
+ ## Hover Effects
122
+
123
+ ```vue
124
+ <!-- Card with hover lift -->
125
+ <Card class="transition-shadow duration-150 hover:shadow-md cursor-pointer">
126
+
127
+ <!-- Button with subtle scale on press -->
128
+ <Button class="active:scale-[0.98] transition-transform duration-150">
129
+ ```
130
+
131
+ ## Optimistic Updates
132
+
133
+ Use for:
134
+ - Toggles (like/unlike, pin/unpin)
135
+ - Status changes (mark complete)
136
+ - Reordering (drag and drop)
137
+
138
+ Do NOT use for:
139
+ - Creation (need server-generated ID)
140
+ - Deletion (hard to undo if server rejects)
141
+ - Complex mutations (multiple side effects)
package/package.json CHANGED
@@ -1,74 +1,53 @@
1
1
  {
2
2
  "name": "@reinvented/design",
3
- "version": "0.1.0",
4
- "description": "Reinvented platform design system — premium UI components and tokens",
5
- "license": "MIT",
6
- "author": "Reinvented",
7
- "repository": {
8
- "type": "git",
9
- "url": "https://github.com/reinvented/ri-flex"
10
- },
3
+ "version": "0.2.0",
11
4
  "type": "module",
12
- "publishConfig": {
13
- "access": "public"
5
+ "main": "./src/index.ts",
6
+ "exports": {
7
+ ".": "./src/index.ts",
8
+ "./styles": "./src/styles/index.css",
9
+ "./tokens": "./src/styles/tokens.css",
10
+ "./src/styles/*": "./src/styles/*",
11
+ "./src/*": "./src/*",
12
+ "./tailwind.config.js": "./tailwind.config.js",
13
+ "./patterns/*": "./src/patterns/*"
14
14
  },
15
15
  "files": [
16
- "dist",
17
- "tailwind.config.ts",
18
- "README.md"
16
+ "src/",
17
+ "docs/",
18
+ "tailwind.config.js",
19
+ "tsconfig.json",
20
+ "DESIGN_GUIDE.md"
19
21
  ],
20
- "main": "./dist/index.js",
21
- "types": "./dist/index.d.ts",
22
- "exports": {
23
- ".": {
24
- "import": "./dist/index.js",
25
- "types": "./dist/index.d.ts"
26
- },
27
- "./css": "./dist/index.css",
28
- "./tailwind": "./tailwind.config.ts"
22
+ "scripts": {
23
+ "build": "vue-tsc --noEmit",
24
+ "lint": "eslint src"
29
25
  },
30
26
  "peerDependencies": {
31
- "react": "^18 || ^19",
32
- "react-dom": "^18 || ^19"
27
+ "vue": "^3.5.0"
33
28
  },
34
29
  "dependencies": {
35
- "@radix-ui/react-avatar": "^1.1.2",
36
- "@radix-ui/react-checkbox": "^1.1.3",
37
- "@radix-ui/react-dialog": "^1.1.4",
38
- "@radix-ui/react-dropdown-menu": "^2.1.4",
39
- "@radix-ui/react-label": "^2.1.1",
40
- "@radix-ui/react-popover": "^1.1.4",
41
- "@radix-ui/react-scroll-area": "^1.2.2",
42
- "@radix-ui/react-select": "^2.1.4",
43
- "@radix-ui/react-separator": "^1.1.1",
44
- "@radix-ui/react-slot": "^1.1.1",
45
- "@radix-ui/react-switch": "^1.1.2",
46
- "@radix-ui/react-tabs": "^1.1.2",
47
- "@radix-ui/react-toast": "^1.2.4",
48
- "@radix-ui/react-tooltip": "^1.1.6",
49
- "class-variance-authority": "^0.7.1",
50
- "clsx": "^2.1.1",
51
- "cmdk": "^1.0.4",
52
- "lucide-react": "^0.469.0",
53
- "tailwind-merge": "^2.6.0"
30
+ "class-variance-authority": "^0.7.0",
31
+ "clsx": "^2.1.0",
32
+ "tailwind-merge": "^2.6.0",
33
+ "lucide-vue-next": "^0.460.0",
34
+ "radix-vue": "^1.9.0",
35
+ "@vueuse/core": "^11.0.0",
36
+ "embla-carousel-vue": "^8.5.0",
37
+ "vaul-vue": "^0.2.0",
38
+ "vee-validate": "^4.14.0",
39
+ "@vee-validate/zod": "^4.14.0",
40
+ "zod": "^3.23.0",
41
+ "vue-sonner": "^1.2.0",
42
+ "v-calendar": "^3.1.0",
43
+ "@tanstack/vue-table": "^8.21.0"
54
44
  },
55
45
  "devDependencies": {
56
- "@types/react": "^18.3.18",
57
- "@types/react-dom": "^18.3.5",
58
- "autoprefixer": "^10.4.20",
59
- "postcss": "^8.4.49",
60
- "postcss-cli": "^11.0.1",
61
- "postcss-import": "^16.1.1",
62
- "tailwindcss": "^3.4.17",
63
- "tsup": "^8.3.6",
64
- "typescript": "^5.7.3",
65
- "@reinvented/tsconfig": "0.0.0"
66
- },
67
- "scripts": {
68
- "build": "tsup && postcss src/index.css -o dist/index.css",
69
- "dev": "tsup --watch",
70
- "lint": "eslint .",
71
- "typecheck": "tsc --noEmit",
72
- "clean": "rm -rf dist"
46
+ "vue": "^3.5.0",
47
+ "typescript": "^5.6.0",
48
+ "vue-tsc": "^2.1.0",
49
+ "tailwindcss": "^3.4.0",
50
+ "autoprefixer": "^10.4.0",
51
+ "postcss": "^8.4.0"
73
52
  }
74
- }
53
+ }
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class']; src?: string; alt?: string; fallback?: string }
5
+ const props = defineProps<Props>()
6
+ </script>
7
+ <template>
8
+ <span :class="cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', props.class)">
9
+ <img v-if="src" :src="src" :alt="alt" class="aspect-square h-full w-full object-cover" />
10
+ <span v-else class="flex h-full w-full items-center justify-center rounded-full bg-muted text-sm font-medium">
11
+ {{ fallback || '?' }}
12
+ </span>
13
+ </span>
14
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Avatar } from './Avatar.vue'
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes, computed } from 'vue'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import { cn } from '../lib/utils'
5
+
6
+ const badgeVariants = cva(
7
+ 'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
12
+ secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
13
+ destructive: 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
14
+ outline: 'text-foreground',
15
+ success: 'border-transparent bg-success text-success-foreground shadow',
16
+ warning: 'border-transparent bg-warning text-warning-foreground shadow',
17
+ },
18
+ },
19
+ defaultVariants: { variant: 'default' },
20
+ }
21
+ )
22
+
23
+ type BadgeVariants = VariantProps<typeof badgeVariants>
24
+ interface Props { variant?: BadgeVariants['variant']; class?: HTMLAttributes['class'] }
25
+ const props = withDefaults(defineProps<Props>(), { variant: 'default' })
26
+ </script>
27
+ <template><div :class="cn(badgeVariants({ variant }), props.class)"><slot /></div></template>
@@ -0,0 +1 @@
1
+ export { default as Badge } from './Badge.vue'
@@ -0,0 +1,66 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes, computed } from 'vue'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import { cn } from '../lib/utils'
5
+
6
+ const buttonVariants = cva(
7
+ 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
12
+ destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
13
+ outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
14
+ secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
15
+ ghost: 'hover:bg-accent hover:text-accent-foreground',
16
+ link: 'text-primary underline-offset-4 hover:underline',
17
+ success: 'bg-success text-success-foreground shadow-sm hover:bg-success/90',
18
+ },
19
+ size: {
20
+ default: 'h-9 px-4 py-2',
21
+ xs: 'h-7 rounded px-2 text-xs',
22
+ sm: 'h-8 rounded-md px-3 text-xs',
23
+ lg: 'h-10 rounded-md px-8',
24
+ xl: 'h-12 rounded-lg px-10 text-base',
25
+ icon: 'h-9 w-9',
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ variant: 'default',
30
+ size: 'default',
31
+ },
32
+ }
33
+ )
34
+
35
+ export type ButtonVariants = VariantProps<typeof buttonVariants>
36
+
37
+ interface Props {
38
+ variant?: ButtonVariants['variant']
39
+ size?: ButtonVariants['size']
40
+ as?: string
41
+ class?: HTMLAttributes['class']
42
+ disabled?: boolean
43
+ }
44
+
45
+ const props = withDefaults(defineProps<Props>(), {
46
+ as: 'button',
47
+ variant: 'default',
48
+ size: 'default',
49
+ })
50
+
51
+ const delegatedProps = computed(() => {
52
+ const { class: _, ...rest } = props
53
+ return rest
54
+ })
55
+ </script>
56
+
57
+ <template>
58
+ <component
59
+ :is="as"
60
+ :class="cn(buttonVariants({ variant, size }), props.class)"
61
+ :disabled="disabled"
62
+ v-bind="delegatedProps"
63
+ >
64
+ <slot />
65
+ </component>
66
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Button } from './Button.vue'
@@ -0,0 +1,13 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes, computed } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+
5
+ interface Props { class?: HTMLAttributes['class'] }
6
+ const props = defineProps<Props>()
7
+ </script>
8
+
9
+ <template>
10
+ <div :class="cn('rounded-xl border bg-card text-card-foreground shadow', props.class)">
11
+ <slot />
12
+ </div>
13
+ </template>
@@ -0,0 +1,7 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class'] }
5
+ const props = defineProps<Props>()
6
+ </script>
7
+ <template><div :class="cn('p-6 pt-0', props.class)"><slot /></div></template>
@@ -0,0 +1,7 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class'] }
5
+ const props = defineProps<Props>()
6
+ </script>
7
+ <template><p :class="cn('text-sm text-muted-foreground', props.class)"><slot /></p></template>
@@ -0,0 +1,7 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class'] }
5
+ const props = defineProps<Props>()
6
+ </script>
7
+ <template><div :class="cn('flex items-center p-6 pt-0', props.class)"><slot /></div></template>
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class'] }
5
+ const props = defineProps<Props>()
6
+ </script>
7
+ <template>
8
+ <div :class="cn('flex flex-col space-y-1.5 p-6', props.class)"><slot /></div>
9
+ </template>
@@ -0,0 +1,7 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class'] }
5
+ const props = defineProps<Props>()
6
+ </script>
7
+ <template><h3 :class="cn('font-semibold leading-none tracking-tight', props.class)"><slot /></h3></template>
@@ -0,0 +1,6 @@
1
+ export { default as Card } from './Card.vue'
2
+ export { default as CardHeader } from './CardHeader.vue'
3
+ export { default as CardTitle } from './CardTitle.vue'
4
+ export { default as CardDescription } from './CardDescription.vue'
5
+ export { default as CardContent } from './CardContent.vue'
6
+ export { default as CardFooter } from './CardFooter.vue'
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props {
5
+ class?: HTMLAttributes['class']
6
+ type?: string
7
+ placeholder?: string
8
+ modelValue?: string | number
9
+ disabled?: boolean
10
+ }
11
+ const props = withDefaults(defineProps<Props>(), { type: 'text' })
12
+ const emit = defineEmits<{ 'update:modelValue': [value: string] }>()
13
+ </script>
14
+ <template>
15
+ <input
16
+ :type="type"
17
+ :value="modelValue"
18
+ :placeholder="placeholder"
19
+ :disabled="disabled"
20
+ :class="cn('flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', props.class)"
21
+ @input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
22
+ />
23
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Input } from './Input.vue'
@@ -0,0 +1,2 @@
1
+ // Re-export from the canonical lib/utils location
2
+ export { cn } from '../../../lib/utils'
@@ -0,0 +1,13 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class']; orientation?: 'horizontal' | 'vertical' }
5
+ const props = withDefaults(defineProps<Props>(), { orientation: 'vertical' })
6
+ </script>
7
+ <template>
8
+ <div :class="cn('relative overflow-hidden', props.class)" :style="{ overflow: 'auto' }">
9
+ <div class="h-full w-full rounded-[inherit]">
10
+ <slot />
11
+ </div>
12
+ </div>
13
+ </template>
@@ -0,0 +1 @@
1
+ export { default as ScrollArea } from './ScrollArea.vue'
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class']; orientation?: 'horizontal' | 'vertical' }
5
+ const props = withDefaults(defineProps<Props>(), { orientation: 'horizontal' })
6
+ </script>
7
+ <template>
8
+ <div
9
+ role="separator"
10
+ :class="cn(
11
+ 'shrink-0 bg-border',
12
+ orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',
13
+ props.class
14
+ )"
15
+ />
16
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Separator } from './Separator.vue'
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes } from 'vue'
3
+ import { cn } from '../lib/utils'
4
+ interface Props { class?: HTMLAttributes['class'] }
5
+ const props = defineProps<Props>()
6
+ </script>
7
+ <template>
8
+ <div :class="cn('animate-pulse rounded-md bg-primary/10', props.class)" />
9
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Skeleton } from './Skeleton.vue'
package/src/env.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module '*.vue' {
4
+ import type { DefineComponent } from 'vue'
5
+ const component: DefineComponent<{}, {}, any>
6
+ export default component
7
+ }