birus-ui 0.0.0-stage → 0.3.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.
- package/README.md +232 -2
- package/dist/birus-ui.js +6919 -0
- package/dist/birus-ui.umd.cjs +10 -0
- package/dist/style.css +1 -0
- package/dist/tailwind-preset.js +70 -0
- package/dist/themes.css +217 -0
- package/package.json +41 -4
- package/src/components/BirusAccordion.vue +112 -0
- package/src/components/BirusAlert.vue +114 -0
- package/src/components/BirusAvatar.vue +67 -0
- package/src/components/BirusBadge.vue +64 -0
- package/src/components/BirusBreadcrumb.vue +61 -0
- package/src/components/BirusButton.vue +84 -0
- package/src/components/BirusCard.vue +89 -0
- package/src/components/BirusCheckbox.vue +106 -0
- package/src/components/BirusDialog.vue +127 -0
- package/src/components/BirusDrawer.vue +158 -0
- package/src/components/BirusDropdownMenu.vue +184 -0
- package/src/components/BirusEmptyState.vue +64 -0
- package/src/components/BirusHeading.vue +70 -0
- package/src/components/BirusInput.vue +197 -0
- package/src/components/BirusKbd.vue +43 -0
- package/src/components/BirusPagination.vue +132 -0
- package/src/components/BirusProgress.vue +70 -0
- package/src/components/BirusRadioGroup.vue +157 -0
- package/src/components/BirusSelect.vue +272 -0
- package/src/components/BirusSeparator.vue +72 -0
- package/src/components/BirusSkeleton.vue +46 -0
- package/src/components/BirusSlider.vue +96 -0
- package/src/components/BirusStatCard.vue +106 -0
- package/src/components/BirusStepper.vue +114 -0
- package/src/components/BirusSwitch.vue +76 -0
- package/src/components/BirusTable.vue +126 -0
- package/src/components/BirusTabs.vue +121 -0
- package/src/components/BirusText.vue +74 -0
- package/src/components/BirusTextarea.vue +84 -0
- package/src/components/BirusTimeline.vue +61 -0
- package/src/components/BirusToaster.vue +130 -0
- package/src/components/BirusTooltip.vue +63 -0
- package/src/composables/useBirusTheme.js +144 -0
- package/src/composables/useToast.js +63 -0
- package/src/index.js +116 -0
- package/src/lib-entry.js +3 -0
- package/src/style.css +5 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset Tailwind compartilhável para qualquer projeto Vue ou React que adote o birusUI.
|
|
3
|
+
*/
|
|
4
|
+
export const birusTailwindPreset = {
|
|
5
|
+
darkMode: ['class', '[data-birus-mode="dark"]'],
|
|
6
|
+
theme: {
|
|
7
|
+
extend: {
|
|
8
|
+
fontFamily: {
|
|
9
|
+
sans: ['var(--birus-font-sans, Inter, system-ui, sans-serif)'],
|
|
10
|
+
mono: ['var(--birus-font-mono, "JetBrains Mono", ui-monospace, monospace)'],
|
|
11
|
+
},
|
|
12
|
+
colors: {
|
|
13
|
+
bg: 'hsl(var(--birus-bg) / <alpha-value>)',
|
|
14
|
+
fg: 'hsl(var(--birus-fg) / <alpha-value>)',
|
|
15
|
+
surface: {
|
|
16
|
+
DEFAULT: 'hsl(var(--birus-surface) / <alpha-value>)',
|
|
17
|
+
hover: 'hsl(var(--birus-surface-hover) / <alpha-value>)',
|
|
18
|
+
},
|
|
19
|
+
card: {
|
|
20
|
+
DEFAULT: 'hsl(var(--birus-card) / <alpha-value>)',
|
|
21
|
+
fg: 'hsl(var(--birus-card-fg) / <alpha-value>)',
|
|
22
|
+
},
|
|
23
|
+
popover: {
|
|
24
|
+
DEFAULT: 'hsl(var(--birus-popover) / <alpha-value>)',
|
|
25
|
+
fg: 'hsl(var(--birus-popover-fg) / <alpha-value>)',
|
|
26
|
+
},
|
|
27
|
+
primary: {
|
|
28
|
+
DEFAULT: 'hsl(var(--birus-primary) / <alpha-value>)',
|
|
29
|
+
fg: 'hsl(var(--birus-primary-fg) / <alpha-value>)',
|
|
30
|
+
},
|
|
31
|
+
secondary: {
|
|
32
|
+
DEFAULT: 'hsl(var(--birus-secondary) / <alpha-value>)',
|
|
33
|
+
fg: 'hsl(var(--birus-secondary-fg) / <alpha-value>)',
|
|
34
|
+
},
|
|
35
|
+
muted: {
|
|
36
|
+
DEFAULT: 'hsl(var(--birus-muted) / <alpha-value>)',
|
|
37
|
+
fg: 'hsl(var(--birus-muted-fg) / <alpha-value>)',
|
|
38
|
+
},
|
|
39
|
+
accent: {
|
|
40
|
+
DEFAULT: 'hsl(var(--birus-accent) / <alpha-value>)',
|
|
41
|
+
fg: 'hsl(var(--birus-accent-fg) / <alpha-value>)',
|
|
42
|
+
},
|
|
43
|
+
destructive: {
|
|
44
|
+
DEFAULT: 'hsl(var(--birus-destructive) / <alpha-value>)',
|
|
45
|
+
fg: 'hsl(var(--birus-destructive-fg) / <alpha-value>)',
|
|
46
|
+
},
|
|
47
|
+
success: {
|
|
48
|
+
DEFAULT: 'hsl(var(--birus-success) / <alpha-value>)',
|
|
49
|
+
fg: 'hsl(var(--birus-success-fg) / <alpha-value>)',
|
|
50
|
+
},
|
|
51
|
+
warning: {
|
|
52
|
+
DEFAULT: 'hsl(var(--birus-warning) / <alpha-value>)',
|
|
53
|
+
fg: 'hsl(var(--birus-warning-fg) / <alpha-value>)',
|
|
54
|
+
},
|
|
55
|
+
info: {
|
|
56
|
+
DEFAULT: 'hsl(var(--birus-info) / <alpha-value>)',
|
|
57
|
+
fg: 'hsl(var(--birus-info-fg) / <alpha-value>)',
|
|
58
|
+
},
|
|
59
|
+
border: 'hsl(var(--birus-border) / <alpha-value>)',
|
|
60
|
+
input: 'hsl(var(--birus-input) / <alpha-value>)',
|
|
61
|
+
ring: 'hsl(var(--birus-ring) / <alpha-value>)',
|
|
62
|
+
},
|
|
63
|
+
borderRadius: {
|
|
64
|
+
birus: 'var(--birus-radius)',
|
|
65
|
+
'birus-sm': 'calc(var(--birus-radius) * 0.65)',
|
|
66
|
+
'birus-lg': 'calc(var(--birus-radius) * 1.4)',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
package/dist/themes.css
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/* birusUI Design System Tokens - CSS Variables (Light/Dark + 6 Paletas + Radius) */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--birus-bg: 0 0% 100%;
|
|
5
|
+
--birus-fg: 240 10% 4%;
|
|
6
|
+
--birus-surface: 260 25% 98%;
|
|
7
|
+
--birus-surface-hover: 260 25% 94%;
|
|
8
|
+
--birus-card: 0 0% 100%;
|
|
9
|
+
--birus-card-fg: 240 10% 4%;
|
|
10
|
+
--birus-popover: 0 0% 100%;
|
|
11
|
+
--birus-popover-fg: 240 10% 4%;
|
|
12
|
+
--birus-primary: 262 83% 58%;
|
|
13
|
+
--birus-primary-fg: 0 0% 100%;
|
|
14
|
+
--birus-secondary: 260 25% 94%;
|
|
15
|
+
--birus-secondary-fg: 262 45% 24%;
|
|
16
|
+
--birus-muted: 260 15% 95%;
|
|
17
|
+
--birus-muted-fg: 240 5% 44%;
|
|
18
|
+
--birus-accent: 262 80% 94%;
|
|
19
|
+
--birus-accent-fg: 262 83% 42%;
|
|
20
|
+
--birus-destructive: 0 84% 60%;
|
|
21
|
+
--birus-destructive-fg: 0 0% 100%;
|
|
22
|
+
--birus-success: 142 71% 45%;
|
|
23
|
+
--birus-success-fg: 0 0% 100%;
|
|
24
|
+
--birus-warning: 38 92% 50%;
|
|
25
|
+
--birus-warning-fg: 24 10% 10%;
|
|
26
|
+
--birus-info: 199 89% 48%;
|
|
27
|
+
--birus-info-fg: 0 0% 100%;
|
|
28
|
+
--birus-border: 260 16% 89%;
|
|
29
|
+
--birus-input: 260 16% 86%;
|
|
30
|
+
--birus-ring: 262 83% 58%;
|
|
31
|
+
--birus-radius: 0.5rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.dark,
|
|
35
|
+
[data-birus-mode='dark'] {
|
|
36
|
+
--birus-bg: 240 16% 6%;
|
|
37
|
+
--birus-fg: 250 20% 96%;
|
|
38
|
+
--birus-surface: 244 16% 9%;
|
|
39
|
+
--birus-surface-hover: 244 18% 13%;
|
|
40
|
+
--birus-card: 244 16% 9%;
|
|
41
|
+
--birus-card-fg: 250 20% 96%;
|
|
42
|
+
--birus-popover: 244 18% 11%;
|
|
43
|
+
--birus-popover-fg: 250 20% 96%;
|
|
44
|
+
--birus-primary: 263 86% 66%;
|
|
45
|
+
--birus-primary-fg: 0 0% 100%;
|
|
46
|
+
--birus-secondary: 246 18% 16%;
|
|
47
|
+
--birus-secondary-fg: 250 25% 92%;
|
|
48
|
+
--birus-muted: 246 14% 15%;
|
|
49
|
+
--birus-muted-fg: 245 10% 64%;
|
|
50
|
+
--birus-accent: 262 45% 20%;
|
|
51
|
+
--birus-accent-fg: 263 90% 82%;
|
|
52
|
+
--birus-destructive: 0 72% 51%;
|
|
53
|
+
--birus-destructive-fg: 0 0% 100%;
|
|
54
|
+
--birus-success: 142 69% 48%;
|
|
55
|
+
--birus-success-fg: 144 61% 8%;
|
|
56
|
+
--birus-warning: 38 92% 55%;
|
|
57
|
+
--birus-warning-fg: 24 10% 8%;
|
|
58
|
+
--birus-info: 199 89% 54%;
|
|
59
|
+
--birus-info-fg: 204 80% 8%;
|
|
60
|
+
--birus-border: 246 16% 18%;
|
|
61
|
+
--birus-input: 246 16% 22%;
|
|
62
|
+
--birus-ring: 263 86% 66%;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Radius Presets */
|
|
66
|
+
[data-birus-radius='none'] { --birus-radius: 0px; }
|
|
67
|
+
[data-birus-radius='sm'] { --birus-radius: 0.25rem; }
|
|
68
|
+
[data-birus-radius='md'] { --birus-radius: 0.5rem; }
|
|
69
|
+
[data-birus-radius='lg'] { --birus-radius: 0.75rem; }
|
|
70
|
+
[data-birus-radius='full'] { --birus-radius: 1rem; }
|
|
71
|
+
|
|
72
|
+
/* Emerald Palette */
|
|
73
|
+
[data-birus-theme='emerald'] {
|
|
74
|
+
--birus-surface: 155 25% 98%;
|
|
75
|
+
--birus-surface-hover: 155 24% 94%;
|
|
76
|
+
--birus-primary: 158 74% 39%;
|
|
77
|
+
--birus-secondary: 155 22% 93%;
|
|
78
|
+
--birus-secondary-fg: 160 40% 20%;
|
|
79
|
+
--birus-accent: 158 65% 92%;
|
|
80
|
+
--birus-accent-fg: 158 75% 28%;
|
|
81
|
+
--birus-border: 155 16% 88%;
|
|
82
|
+
--birus-input: 155 16% 84%;
|
|
83
|
+
--birus-ring: 158 74% 39%;
|
|
84
|
+
}
|
|
85
|
+
[data-birus-theme='emerald'][data-birus-mode='dark'] {
|
|
86
|
+
--birus-bg: 162 24% 5%;
|
|
87
|
+
--birus-surface: 162 20% 8%;
|
|
88
|
+
--birus-surface-hover: 162 20% 12%;
|
|
89
|
+
--birus-card: 162 20% 8%;
|
|
90
|
+
--birus-popover: 162 22% 10%;
|
|
91
|
+
--birus-primary: 158 72% 48%;
|
|
92
|
+
--birus-primary-fg: 162 40% 7%;
|
|
93
|
+
--birus-secondary: 160 18% 15%;
|
|
94
|
+
--birus-accent: 158 45% 17%;
|
|
95
|
+
--birus-accent-fg: 158 80% 75%;
|
|
96
|
+
--birus-border: 160 16% 17%;
|
|
97
|
+
--birus-input: 160 16% 21%;
|
|
98
|
+
--birus-ring: 158 72% 48%;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Ocean Palette */
|
|
102
|
+
[data-birus-theme='ocean'] {
|
|
103
|
+
--birus-surface: 205 35% 98%;
|
|
104
|
+
--birus-surface-hover: 205 32% 94%;
|
|
105
|
+
--birus-primary: 204 88% 48%;
|
|
106
|
+
--birus-secondary: 205 30% 93%;
|
|
107
|
+
--birus-secondary-fg: 210 45% 22%;
|
|
108
|
+
--birus-accent: 204 85% 93%;
|
|
109
|
+
--birus-accent-fg: 204 88% 34%;
|
|
110
|
+
--birus-border: 210 20% 89%;
|
|
111
|
+
--birus-input: 210 20% 85%;
|
|
112
|
+
--birus-ring: 204 88% 48%;
|
|
113
|
+
}
|
|
114
|
+
[data-birus-theme='ocean'][data-birus-mode='dark'] {
|
|
115
|
+
--birus-bg: 216 32% 6%;
|
|
116
|
+
--birus-surface: 216 28% 9%;
|
|
117
|
+
--birus-surface-hover: 216 26% 13%;
|
|
118
|
+
--birus-card: 216 28% 9%;
|
|
119
|
+
--birus-popover: 216 28% 11%;
|
|
120
|
+
--birus-primary: 201 92% 55%;
|
|
121
|
+
--birus-primary-fg: 216 40% 7%;
|
|
122
|
+
--birus-secondary: 215 22% 16%;
|
|
123
|
+
--birus-accent: 204 55% 18%;
|
|
124
|
+
--birus-accent-fg: 201 92% 78%;
|
|
125
|
+
--birus-border: 215 20% 18%;
|
|
126
|
+
--birus-input: 215 20% 22%;
|
|
127
|
+
--birus-ring: 201 92% 55%;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Rose Palette */
|
|
131
|
+
[data-birus-theme='rose'] {
|
|
132
|
+
--birus-surface: 345 30% 98%;
|
|
133
|
+
--birus-surface-hover: 345 28% 94%;
|
|
134
|
+
--birus-primary: 346 84% 58%;
|
|
135
|
+
--birus-secondary: 345 24% 94%;
|
|
136
|
+
--birus-secondary-fg: 345 45% 24%;
|
|
137
|
+
--birus-accent: 346 80% 94%;
|
|
138
|
+
--birus-accent-fg: 346 84% 40%;
|
|
139
|
+
--birus-border: 345 18% 89%;
|
|
140
|
+
--birus-input: 345 18% 85%;
|
|
141
|
+
--birus-ring: 346 84% 58%;
|
|
142
|
+
}
|
|
143
|
+
[data-birus-theme='rose'][data-birus-mode='dark'] {
|
|
144
|
+
--birus-bg: 346 22% 6%;
|
|
145
|
+
--birus-surface: 346 18% 9%;
|
|
146
|
+
--birus-surface-hover: 346 18% 13%;
|
|
147
|
+
--birus-card: 346 18% 9%;
|
|
148
|
+
--birus-popover: 346 20% 11%;
|
|
149
|
+
--birus-primary: 346 86% 62%;
|
|
150
|
+
--birus-primary-fg: 0 0% 100%;
|
|
151
|
+
--birus-secondary: 346 16% 16%;
|
|
152
|
+
--birus-accent: 346 48% 19%;
|
|
153
|
+
--birus-accent-fg: 346 90% 80%;
|
|
154
|
+
--birus-border: 346 16% 18%;
|
|
155
|
+
--birus-input: 346 16% 22%;
|
|
156
|
+
--birus-ring: 346 86% 62%;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Amber Palette */
|
|
160
|
+
[data-birus-theme='amber'] {
|
|
161
|
+
--birus-surface: 38 40% 98%;
|
|
162
|
+
--birus-surface-hover: 38 35% 94%;
|
|
163
|
+
--birus-primary: 36 92% 48%;
|
|
164
|
+
--birus-primary-fg: 28 30% 8%;
|
|
165
|
+
--birus-secondary: 38 30% 93%;
|
|
166
|
+
--birus-secondary-fg: 30 45% 20%;
|
|
167
|
+
--birus-accent: 38 88% 92%;
|
|
168
|
+
--birus-accent-fg: 32 90% 30%;
|
|
169
|
+
--birus-border: 36 20% 88%;
|
|
170
|
+
--birus-input: 36 20% 84%;
|
|
171
|
+
--birus-ring: 36 92% 48%;
|
|
172
|
+
}
|
|
173
|
+
[data-birus-theme='amber'][data-birus-mode='dark'] {
|
|
174
|
+
--birus-bg: 28 22% 5%;
|
|
175
|
+
--birus-surface: 28 18% 8%;
|
|
176
|
+
--birus-surface-hover: 28 18% 12%;
|
|
177
|
+
--birus-card: 28 18% 8%;
|
|
178
|
+
--birus-popover: 28 20% 10%;
|
|
179
|
+
--birus-primary: 38 94% 54%;
|
|
180
|
+
--birus-primary-fg: 28 35% 7%;
|
|
181
|
+
--birus-secondary: 28 16% 15%;
|
|
182
|
+
--birus-accent: 36 48% 17%;
|
|
183
|
+
--birus-accent-fg: 38 92% 76%;
|
|
184
|
+
--birus-border: 28 16% 17%;
|
|
185
|
+
--birus-input: 28 16% 21%;
|
|
186
|
+
--birus-ring: 38 94% 54%;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Zinc Minimal Palette */
|
|
190
|
+
[data-birus-theme='zinc'] {
|
|
191
|
+
--birus-surface: 240 5% 98%;
|
|
192
|
+
--birus-surface-hover: 240 5% 94%;
|
|
193
|
+
--birus-primary: 240 6% 10%;
|
|
194
|
+
--birus-primary-fg: 0 0% 98%;
|
|
195
|
+
--birus-secondary: 240 5% 94%;
|
|
196
|
+
--birus-secondary-fg: 240 6% 10%;
|
|
197
|
+
--birus-accent: 240 5% 93%;
|
|
198
|
+
--birus-accent-fg: 240 6% 10%;
|
|
199
|
+
--birus-border: 240 6% 89%;
|
|
200
|
+
--birus-input: 240 6% 85%;
|
|
201
|
+
--birus-ring: 240 6% 10%;
|
|
202
|
+
}
|
|
203
|
+
[data-birus-theme='zinc'][data-birus-mode='dark'] {
|
|
204
|
+
--birus-bg: 240 10% 4%;
|
|
205
|
+
--birus-surface: 240 8% 7%;
|
|
206
|
+
--birus-surface-hover: 240 7% 11%;
|
|
207
|
+
--birus-card: 240 8% 7%;
|
|
208
|
+
--birus-popover: 240 8% 9%;
|
|
209
|
+
--birus-primary: 0 0% 98%;
|
|
210
|
+
--birus-primary-fg: 240 6% 10%;
|
|
211
|
+
--birus-secondary: 240 5% 15%;
|
|
212
|
+
--birus-accent: 240 5% 18%;
|
|
213
|
+
--birus-accent-fg: 0 0% 98%;
|
|
214
|
+
--birus-border: 240 5% 17%;
|
|
215
|
+
--birus-input: 240 5% 21%;
|
|
216
|
+
--birus-ring: 240 5% 84%;
|
|
217
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "birus-ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "birusUI — Design System & Biblioteca de 32 Componentes Acessíveis para Vue 3 em JavaScript Puro, com temas reativos e fácil customização.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/birus-ui.umd.cjs",
|
|
7
|
+
"module": "./dist/birus-ui.js",
|
|
8
|
+
"style": "./dist/style.css",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/birus-ui.js",
|
|
12
|
+
"require": "./dist/birus-ui.umd.cjs"
|
|
13
|
+
},
|
|
14
|
+
"./style.css": "./dist/style.css",
|
|
15
|
+
"./themes.css": "./dist/themes.css",
|
|
16
|
+
"./tailwind-preset": "./dist/tailwind-preset.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"src",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "vite build",
|
|
25
|
+
"prepublishOnly": "vite build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"vue",
|
|
29
|
+
"vue3",
|
|
30
|
+
"design-system",
|
|
31
|
+
"ui-library",
|
|
32
|
+
"components",
|
|
33
|
+
"tailwindcss",
|
|
34
|
+
"cva",
|
|
35
|
+
"shadcn",
|
|
36
|
+
"birus-ui"
|
|
37
|
+
],
|
|
38
|
+
"author": "Gabriel Reis",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"vue": "^3.4.0"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from 'vue';
|
|
3
|
+
import { accordionRootVariants, accordionItemVariants, cn } from '@birus-ui/core';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
items: { type: Array, default: () => [] },
|
|
7
|
+
type: { type: String, default: 'single' },
|
|
8
|
+
variant: { type: String, default: 'default' },
|
|
9
|
+
modelValue: { type: [String, Array], default: undefined },
|
|
10
|
+
defaultOpen: { type: [String, Array], default: undefined },
|
|
11
|
+
class: { type: String, default: '' },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const emit = defineEmits(['update:modelValue']);
|
|
15
|
+
|
|
16
|
+
function normalizeIds(val) {
|
|
17
|
+
if (!val) return [];
|
|
18
|
+
return Array.isArray(val) ? val : [val];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const internalOpenIds = ref(normalizeIds(props.modelValue ?? props.defaultOpen));
|
|
22
|
+
|
|
23
|
+
watch(
|
|
24
|
+
() => props.modelValue,
|
|
25
|
+
(next) => {
|
|
26
|
+
if (next !== undefined) {
|
|
27
|
+
internalOpenIds.value = normalizeIds(next);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const rootClasses = computed(() =>
|
|
33
|
+
cn(accordionRootVariants({ variant: props.variant }), props.class),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
function isOpen(id) {
|
|
37
|
+
return internalOpenIds.value.includes(id);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function toggleItem(item) {
|
|
41
|
+
if (item.disabled) return;
|
|
42
|
+
if (props.type === 'multiple') {
|
|
43
|
+
const nextIds = isOpen(item.id)
|
|
44
|
+
? internalOpenIds.value.filter((x) => x !== item.id)
|
|
45
|
+
: [...internalOpenIds.value, item.id];
|
|
46
|
+
internalOpenIds.value = nextIds;
|
|
47
|
+
emit('update:modelValue', nextIds);
|
|
48
|
+
} else {
|
|
49
|
+
const nextSingle = isOpen(item.id) ? '' : item.id;
|
|
50
|
+
internalOpenIds.value = nextSingle ? [nextSingle] : [];
|
|
51
|
+
emit('update:modelValue', nextSingle);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<div :class="rootClasses">
|
|
58
|
+
<div
|
|
59
|
+
v-for="item in items"
|
|
60
|
+
:key="item.id"
|
|
61
|
+
:class="accordionItemVariants({ variant })"
|
|
62
|
+
>
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
:aria-expanded="isOpen(item.id) ? 'true' : 'false'"
|
|
66
|
+
:disabled="item.disabled"
|
|
67
|
+
:class="[
|
|
68
|
+
'flex w-full items-center justify-between gap-4 px-4 py-3.5 text-left transition-colors',
|
|
69
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',
|
|
70
|
+
item.disabled
|
|
71
|
+
? 'opacity-50 cursor-not-allowed'
|
|
72
|
+
: 'hover:bg-surface-hover/70 cursor-pointer',
|
|
73
|
+
]"
|
|
74
|
+
@click="toggleItem(item)"
|
|
75
|
+
>
|
|
76
|
+
<div class="min-w-0">
|
|
77
|
+
<div class="text-sm font-medium text-fg">{{ item.title }}</div>
|
|
78
|
+
<div v-if="item.subtitle" class="text-xs text-muted-fg mt-0.5">
|
|
79
|
+
{{ item.subtitle }}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
<svg
|
|
83
|
+
:class="[
|
|
84
|
+
'h-4 w-4 shrink-0 text-muted-fg transition-transform duration-200',
|
|
85
|
+
isOpen(item.id) && 'rotate-180 text-primary',
|
|
86
|
+
]"
|
|
87
|
+
viewBox="0 0 24 24"
|
|
88
|
+
fill="none"
|
|
89
|
+
stroke="currentColor"
|
|
90
|
+
stroke-width="2"
|
|
91
|
+
>
|
|
92
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 9l6 6 6-6" />
|
|
93
|
+
</svg>
|
|
94
|
+
</button>
|
|
95
|
+
|
|
96
|
+
<div
|
|
97
|
+
:class="[
|
|
98
|
+
'grid transition-all duration-200 ease-out',
|
|
99
|
+
isOpen(item.id) ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0',
|
|
100
|
+
]"
|
|
101
|
+
>
|
|
102
|
+
<div class="overflow-hidden">
|
|
103
|
+
<div class="px-4 pb-4 pt-1 text-sm text-muted-fg leading-relaxed">
|
|
104
|
+
<slot :name="`item-${item.id}`" :item="item">
|
|
105
|
+
{{ item.content }}
|
|
106
|
+
</slot>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</template>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref } from 'vue';
|
|
3
|
+
import { alertVariants, cn } from '@birus-ui/core';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
variant: { type: String, default: 'default' },
|
|
7
|
+
title: { type: String, default: '' },
|
|
8
|
+
description: { type: String, default: '' },
|
|
9
|
+
dismissible: { type: Boolean, default: false },
|
|
10
|
+
class: { type: String, default: '' },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const emit = defineEmits(['dismiss']);
|
|
14
|
+
|
|
15
|
+
const visible = ref(true);
|
|
16
|
+
|
|
17
|
+
const classes = computed(() =>
|
|
18
|
+
cn(alertVariants({ variant: props.variant }), props.class),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
function handleDismiss() {
|
|
22
|
+
visible.value = false;
|
|
23
|
+
emit('dismiss');
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<Transition
|
|
29
|
+
enter-active-class="transition duration-200 ease-out"
|
|
30
|
+
enter-from-class="opacity-0 -translate-y-1"
|
|
31
|
+
enter-to-class="opacity-100 translate-y-0"
|
|
32
|
+
leave-active-class="transition duration-150 ease-in"
|
|
33
|
+
leave-from-class="opacity-100 scale-100"
|
|
34
|
+
leave-to-class="opacity-0 scale-95"
|
|
35
|
+
>
|
|
36
|
+
<div v-if="visible" role="alert" :class="classes">
|
|
37
|
+
<div class="birus-alert-icon mt-0.5 shrink-0 text-primary">
|
|
38
|
+
<slot name="icon">
|
|
39
|
+
<svg
|
|
40
|
+
v-if="variant === 'success'"
|
|
41
|
+
class="h-5 w-5"
|
|
42
|
+
viewBox="0 0 24 24"
|
|
43
|
+
fill="none"
|
|
44
|
+
stroke="currentColor"
|
|
45
|
+
stroke-width="2"
|
|
46
|
+
>
|
|
47
|
+
<circle cx="12" cy="12" r="10" />
|
|
48
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4" />
|
|
49
|
+
</svg>
|
|
50
|
+
<svg
|
|
51
|
+
v-else-if="variant === 'warning'"
|
|
52
|
+
class="h-5 w-5"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
stroke-width="2"
|
|
57
|
+
>
|
|
58
|
+
<path
|
|
59
|
+
stroke-linecap="round"
|
|
60
|
+
stroke-linejoin="round"
|
|
61
|
+
d="M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"
|
|
62
|
+
/>
|
|
63
|
+
</svg>
|
|
64
|
+
<svg
|
|
65
|
+
v-else-if="variant === 'destructive'"
|
|
66
|
+
class="h-5 w-5"
|
|
67
|
+
viewBox="0 0 24 24"
|
|
68
|
+
fill="none"
|
|
69
|
+
stroke="currentColor"
|
|
70
|
+
stroke-width="2"
|
|
71
|
+
>
|
|
72
|
+
<circle cx="12" cy="12" r="10" />
|
|
73
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M15 9l-6 6m0-6l6 6" />
|
|
74
|
+
</svg>
|
|
75
|
+
<svg
|
|
76
|
+
v-else
|
|
77
|
+
class="h-5 w-5"
|
|
78
|
+
viewBox="0 0 24 24"
|
|
79
|
+
fill="none"
|
|
80
|
+
stroke="currentColor"
|
|
81
|
+
stroke-width="2"
|
|
82
|
+
>
|
|
83
|
+
<circle cx="12" cy="12" r="10" />
|
|
84
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 16v-4m0-4h.01" />
|
|
85
|
+
</svg>
|
|
86
|
+
</slot>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="flex-1 min-w-0 space-y-1">
|
|
90
|
+
<h5 v-if="title" class="text-sm font-semibold leading-tight tracking-tight text-fg">
|
|
91
|
+
{{ title }}
|
|
92
|
+
</h5>
|
|
93
|
+
<div v-if="description || $slots.default" class="text-sm text-muted-fg leading-relaxed">
|
|
94
|
+
<slot>{{ description }}</slot>
|
|
95
|
+
</div>
|
|
96
|
+
<div v-if="$slots.actions" class="pt-2 flex flex-wrap items-center gap-2">
|
|
97
|
+
<slot name="actions" />
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<button
|
|
102
|
+
v-if="dismissible"
|
|
103
|
+
type="button"
|
|
104
|
+
class="shrink-0 rounded-birus-sm p-1 text-muted-fg hover:text-fg hover:bg-surface-hover transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
105
|
+
aria-label="Fechar alerta"
|
|
106
|
+
@click="handleDismiss"
|
|
107
|
+
>
|
|
108
|
+
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
109
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M18 6L6 18M6 6l12 12" />
|
|
110
|
+
</svg>
|
|
111
|
+
</button>
|
|
112
|
+
</div>
|
|
113
|
+
</Transition>
|
|
114
|
+
</template>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from 'vue';
|
|
3
|
+
import { avatarVariants, avatarStatusVariants, cn } from '@birus-ui/core';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
src: { type: String, default: '' },
|
|
7
|
+
alt: { type: String, default: '' },
|
|
8
|
+
name: { type: String, default: '' },
|
|
9
|
+
size: { type: String, default: 'md' },
|
|
10
|
+
shape: { type: String, default: 'circle' },
|
|
11
|
+
status: { type: String, default: undefined },
|
|
12
|
+
class: { type: String, default: '' },
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const imageError = ref(false);
|
|
16
|
+
|
|
17
|
+
watch(
|
|
18
|
+
() => props.src,
|
|
19
|
+
() => {
|
|
20
|
+
imageError.value = false;
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const initials = computed(() => {
|
|
25
|
+
const source = (props.name || props.alt || 'BU').trim();
|
|
26
|
+
const parts = source.split(/\s+/).filter(Boolean);
|
|
27
|
+
if (parts.length === 1) {
|
|
28
|
+
return parts[0].slice(0, 2).toUpperCase();
|
|
29
|
+
}
|
|
30
|
+
return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const containerClasses = computed(() =>
|
|
34
|
+
cn(avatarVariants({ size: props.size, shape: props.shape }), props.class),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const statusClasses = computed(() =>
|
|
38
|
+
props.status
|
|
39
|
+
? avatarStatusVariants({ status: props.status, size: props.size })
|
|
40
|
+
: '',
|
|
41
|
+
);
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<span class="relative inline-flex shrink-0">
|
|
46
|
+
<span :class="containerClasses">
|
|
47
|
+
<img
|
|
48
|
+
v-if="src && !imageError"
|
|
49
|
+
:src="src"
|
|
50
|
+
:alt="alt || name || 'Avatar'"
|
|
51
|
+
class="h-full w-full object-cover"
|
|
52
|
+
@error="imageError = true"
|
|
53
|
+
/>
|
|
54
|
+
<span
|
|
55
|
+
v-else
|
|
56
|
+
class="bg-gradient-to-br from-primary/20 to-accent text-primary font-semibold h-full w-full flex items-center justify-center"
|
|
57
|
+
>
|
|
58
|
+
{{ initials }}
|
|
59
|
+
</span>
|
|
60
|
+
</span>
|
|
61
|
+
<span
|
|
62
|
+
v-if="status"
|
|
63
|
+
:class="statusClasses"
|
|
64
|
+
:aria-label="`Status: ${status}`"
|
|
65
|
+
/>
|
|
66
|
+
</span>
|
|
67
|
+
</template>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import { badgeVariants, cn } from '@birus-ui/core';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
variant: { type: String, default: 'default' },
|
|
7
|
+
size: { type: String, default: 'md' },
|
|
8
|
+
dot: { type: Boolean, default: false },
|
|
9
|
+
removable: { type: Boolean, default: false },
|
|
10
|
+
class: { type: String, default: '' },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const emit = defineEmits(['remove']);
|
|
14
|
+
|
|
15
|
+
const classes = computed(() =>
|
|
16
|
+
cn(
|
|
17
|
+
badgeVariants({
|
|
18
|
+
variant: props.variant,
|
|
19
|
+
size: props.size,
|
|
20
|
+
}),
|
|
21
|
+
props.class,
|
|
22
|
+
),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const dotColorClass = computed(() => {
|
|
26
|
+
switch (props.variant) {
|
|
27
|
+
case 'success':
|
|
28
|
+
return 'bg-success';
|
|
29
|
+
case 'warning':
|
|
30
|
+
return 'bg-warning';
|
|
31
|
+
case 'destructive':
|
|
32
|
+
return 'bg-destructive';
|
|
33
|
+
case 'info':
|
|
34
|
+
return 'bg-info';
|
|
35
|
+
case 'default':
|
|
36
|
+
return 'bg-primary-fg';
|
|
37
|
+
default:
|
|
38
|
+
return 'bg-primary';
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<span :class="classes">
|
|
45
|
+
<span v-if="dot" class="relative flex h-2 w-2 shrink-0" aria-hidden="true">
|
|
46
|
+
<span
|
|
47
|
+
:class="['animate-ping absolute inline-flex h-full w-full rounded-full opacity-75', dotColorClass]"
|
|
48
|
+
/>
|
|
49
|
+
<span :class="['relative inline-flex rounded-full h-2 w-2', dotColorClass]" />
|
|
50
|
+
</span>
|
|
51
|
+
<slot />
|
|
52
|
+
<button
|
|
53
|
+
v-if="removable"
|
|
54
|
+
type="button"
|
|
55
|
+
class="ml-0.5 -mr-1 inline-flex h-4 w-4 items-center justify-center rounded-full opacity-70 hover:opacity-100 hover:bg-black/10 dark:hover:bg-white/15 transition-opacity focus:outline-none"
|
|
56
|
+
aria-label="Remover"
|
|
57
|
+
@click.stop="emit('remove')"
|
|
58
|
+
>
|
|
59
|
+
<svg class="h-3 w-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2">
|
|
60
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M18 6L6 18M6 6l12 12" />
|
|
61
|
+
</svg>
|
|
62
|
+
</button>
|
|
63
|
+
</span>
|
|
64
|
+
</template>
|