@proj-airi/ui 0.8.0-alpha.6 → 0.8.0-beta.1

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@proj-airi/ui",
3
3
  "type": "module",
4
- "version": "0.8.0-alpha.6",
4
+ "version": "0.8.0-beta.1",
5
5
  "description": "A collection of UI components that used by Project AIRI",
6
6
  "author": {
7
7
  "name": "Moeru AI Project AIRI Team",
@@ -0,0 +1,118 @@
1
+ <script setup lang="ts">
2
+ import { BidirectionalTransition } from '@proj-airi/ui'
3
+ import { computed } from 'vue'
4
+
5
+ // Define button variants for better type safety and maintainability
6
+ type ButtonVariant = 'primary' | 'secondary' | 'secondary-muted' | 'danger' | 'caution'
7
+
8
+ type ButtonTheme
9
+ = | 'default'
10
+ // | 'dimmed'
11
+ // | 'lightened'
12
+
13
+ // Define size options for better flexibility
14
+ type ButtonSize = 'sm' | 'md' | 'lg'
15
+
16
+ interface ButtonProps {
17
+ toggled?: boolean // Optional toggled state for toggle buttons
18
+ icon?: string // Icon class name
19
+ label?: string // Button text label
20
+ disabled?: boolean // Disabled state
21
+ loading?: boolean // Loading state
22
+ variant?: ButtonVariant // Button style variant
23
+ size?: ButtonSize // Button size variant
24
+ theme?: ButtonTheme // Button theme
25
+ block?: boolean // Full width button
26
+ }
27
+
28
+ const props = withDefaults(defineProps<ButtonProps>(), {
29
+ toggled: false,
30
+ variant: 'primary',
31
+ disabled: false,
32
+ loading: false,
33
+ size: 'md',
34
+ theme: 'default',
35
+ block: false,
36
+ })
37
+
38
+ const isDisabled = computed(() => props.disabled || props.loading)
39
+
40
+ // Extract variant styles for better organization
41
+ const variantClasses: Record<ButtonVariant, {
42
+ default: {
43
+ default: string
44
+ nonToggled?: string
45
+ toggled?: string
46
+ }
47
+ }> = {
48
+ 'primary': {
49
+ default: {
50
+ default: 'bg-primary-500/15 hover:bg-primary-500/20 active:bg-primary-500/30 dark:bg-primary-700/30 dark:hover:bg-primary-700/40 dark:active:bg-primary-700/30 focus:ring-primary-300/60 dark:focus:ring-primary-600/30 border-2 border-solid border-primary-500/5 dark:border-primary-900/40 text-primary-950 dark:text-primary-100',
51
+ },
52
+ },
53
+ 'secondary': {
54
+ default: {
55
+ default: 'bg-neutral-100/55 hover:bg-neutral-400/20 active:bg-neutral-400/30 dark:bg-neutral-700/60 dark:hover:bg-neutral-700/80 dark:active:bg-neutral-700/60 focus:ring-neutral-300/30 dark:focus:ring-neutral-600/60 dark:focus:ring-neutral-600/30 border-2 border-solid border-neutral-300/30 dark:border-neutral-700/30 text-neutral-950 dark:text-neutral-100',
56
+ },
57
+ },
58
+ 'secondary-muted': {
59
+ default: {
60
+ default: 'hover:bg-neutral-50/50 active:bg-neutral-50/90 hover:dark:bg-neutral-800/50 active:dark:bg-neutral-800/90 border-2 border-solid border-neutral-100/60 dark:border-neutral-800/30 focus:ring-neutral-300/30 dark:focus:ring-neutral-600/60 dark:focus:ring-neutral-600/30',
61
+ nonToggled: 'bg-neutral-50/70 dark:bg-neutral-800/70 text-neutral-500 dark:text-neutral-400',
62
+ toggled: 'bg-white/90 dark:bg-neutral-500/70 ring-neutral-300/30 dark:ring-neutral-600/60 ring-2 dark:ring-neutral-600/30 text-primary-500 dark:text-primary-100',
63
+ },
64
+ },
65
+ 'danger': {
66
+ default: {
67
+ default: 'bg-red-500/15 hover:bg-red-500/20 active:bg-red-500/30 dark:bg-red-700/30 dark:hover:bg-red-700/40 dark:active:bg-red-700/30 focus:ring-red-300/30 dark:focus:ring-red-600/60 dark:focus:ring-red-600/30 border-2 border-solid border-red-200/30 dark:border-red-900/30 text-red-950 dark:text-red-100',
68
+ },
69
+ },
70
+ 'caution': {
71
+ default: {
72
+ default: 'bg-amber-400/20 hover:bg-amber-400/25 active:bg-amber-400/35 dark:bg-amber-500/20 dark:hover:bg-amber-500/30 dark:active:bg-amber-500/35 focus:ring-amber-300/40 dark:focus:ring-amber-400/40 border-2 border-solid border-amber-300/40 dark:border-amber-500/40 text-amber-900 dark:text-amber-50',
73
+ },
74
+ },
75
+ }
76
+
77
+ // Extract size styles for better organization
78
+ const sizeClasses: Record<ButtonSize, string> = {
79
+ sm: 'px-3 py-1.5 text-xs',
80
+ md: 'px-4 py-2 text-sm',
81
+ lg: 'px-6 py-3 text-base',
82
+ }
83
+
84
+ // Base classes that are always applied
85
+ const baseClasses = computed(() => [
86
+ 'rounded-lg font-medium outline-none',
87
+ 'transition-all duration-200 ease-in-out',
88
+ 'disabled:cursor-not-allowed disabled:opacity-50',
89
+ 'backdrop-blur-md',
90
+ props.block ? 'w-full' : '',
91
+ sizeClasses[props.size],
92
+ variantClasses[props.variant][props.theme].default,
93
+ props.toggled ? variantClasses[props.variant][props.theme].toggled || '' : variantClasses[props.variant][props.theme].nonToggled || '',
94
+ { 'opacity-50 cursor-not-allowed': isDisabled.value },
95
+ 'focus:ring-2',
96
+ ])
97
+ </script>
98
+
99
+ <template>
100
+ <button
101
+ :disabled="isDisabled"
102
+ :class="baseClasses"
103
+ >
104
+ <div class="flex flex-row items-center justify-center gap-2">
105
+ <BidirectionalTransition
106
+ from-class="opacity-0 mr-0! w-0!"
107
+ active-class="transition-[width,margin] ease-in-out overflow-hidden transition-100"
108
+ >
109
+ <div v-if="loading || icon" class="w-4">
110
+ <div v-if="loading" class="i-svg-spinners:ring-resize h-4 w-4" />
111
+ <div v-else-if="icon" class="h-4 w-4" :class="icon" />
112
+ </div>
113
+ </BidirectionalTransition>
114
+ <span v-if="label">{{ label }}</span>
115
+ <slot v-else />
116
+ </div>
117
+ </button>
118
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Button } from './Button.vue'
package/src/index.ts CHANGED
@@ -2,5 +2,6 @@ import './fallback.css'
2
2
 
3
3
  export * from './components/Animations'
4
4
  export * from './components/Form'
5
+ export * from './components/Misc'
5
6
  export * from './composables/use-deferred-mount'
6
7
  export * from './composables/use-theme'