@underverse-ui/underverse 0.2.38 → 0.2.39
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 +412 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,25 +4,81 @@ Docs: https://underverse-sepia.vercel.app/vi/docs/underverse
|
|
|
4
4
|
|
|
5
5
|
**Author:** Tran Van Bach
|
|
6
6
|
|
|
7
|
-
A comprehensive UI component library for React/Next.js applications, extracted from the main project. Built with Tailwind CSS, `clsx`, and `tailwind-merge`.
|
|
7
|
+
A comprehensive UI component library for React/Next.js applications, extracted from the main project. Built with Tailwind CSS, `clsx`, and `tailwind-merge`.
|
|
8
|
+
|
|
9
|
+
## ✨ Features
|
|
10
|
+
|
|
11
|
+
- 🎨 **60+ UI Components** - Buttons, Modals, DatePicker, DataTable, and more
|
|
12
|
+
- 🌐 **Multi-language Support** - Built-in translations for English, Vietnamese, Korean, Japanese
|
|
13
|
+
- ⚡ **Tree-shakeable** - Import only what you need
|
|
14
|
+
- 🔌 **Flexible i18n** - Works with `next-intl` or standalone React
|
|
15
|
+
- 🎯 **TypeScript First** - Full type definitions included
|
|
16
|
+
- 🌙 **Dark Mode Ready** - Supports light/dark themes via CSS variables
|
|
17
|
+
|
|
18
|
+
## Supported Locales
|
|
19
|
+
|
|
20
|
+
| Locale | Language | Flag |
|
|
21
|
+
| ------ | ---------- | ---- |
|
|
22
|
+
| `en` | English | 🇺🇸 |
|
|
23
|
+
| `vi` | Tiếng Việt | 🇻🇳 |
|
|
24
|
+
| `ko` | 한국어 | 🇰🇷 |
|
|
25
|
+
| `ja` | 日本語 | 🇯🇵 |
|
|
8
26
|
|
|
9
27
|
## Requirements
|
|
28
|
+
|
|
10
29
|
- Node >= 18
|
|
11
|
-
- Peer dependencies: `react`, `react-dom
|
|
30
|
+
- Peer dependencies: `react`, `react-dom`
|
|
31
|
+
- Optional: `next`, `next-intl` (for Next.js projects)
|
|
12
32
|
|
|
13
33
|
## Installation
|
|
34
|
+
|
|
14
35
|
```bash
|
|
15
36
|
# Install the package
|
|
16
37
|
npm i @underverse-ui/underverse
|
|
17
38
|
|
|
18
|
-
#
|
|
39
|
+
# For Next.js projects (with next-intl)
|
|
19
40
|
npm i react react-dom next next-intl
|
|
41
|
+
|
|
42
|
+
# For standalone React projects (Vite, CRA, etc.)
|
|
43
|
+
npm i react react-dom
|
|
20
44
|
```
|
|
21
45
|
|
|
22
46
|
## Tailwind CSS Configuration
|
|
47
|
+
|
|
23
48
|
Components use color variables like `primary`, `secondary`, `destructive`, etc. Make sure your Tailwind theme/tokens include these variables.
|
|
24
49
|
|
|
25
|
-
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🚀 Quick Start
|
|
53
|
+
|
|
54
|
+
### Standalone React (Vite, CRA, etc.)
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { TranslationProvider, Button, DatePicker, ToastProvider, useToast } from "@underverse-ui/underverse";
|
|
58
|
+
|
|
59
|
+
function App() {
|
|
60
|
+
return (
|
|
61
|
+
<TranslationProvider locale="vi">
|
|
62
|
+
<ToastProvider>
|
|
63
|
+
<MyComponent />
|
|
64
|
+
</ToastProvider>
|
|
65
|
+
</TranslationProvider>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function MyComponent() {
|
|
70
|
+
const { addToast } = useToast();
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div>
|
|
74
|
+
<DatePicker onChange={(date) => console.log(date)} />
|
|
75
|
+
<Button onClick={() => addToast({ type: "success", message: "Hello!" })}>Click me</Button>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Next.js (with next-intl)
|
|
26
82
|
|
|
27
83
|
```tsx
|
|
28
84
|
import { Button, ToastProvider, useToast } from "@underverse-ui/underverse";
|
|
@@ -31,9 +87,7 @@ function App() {
|
|
|
31
87
|
const { addToast } = useToast();
|
|
32
88
|
return (
|
|
33
89
|
<ToastProvider>
|
|
34
|
-
<Button onClick={() => addToast({ type:
|
|
35
|
-
Click me
|
|
36
|
-
</Button>
|
|
90
|
+
<Button onClick={() => addToast({ type: "success", message: "Hello" })}>Click me</Button>
|
|
37
91
|
</ToastProvider>
|
|
38
92
|
);
|
|
39
93
|
}
|
|
@@ -42,47 +96,146 @@ function App() {
|
|
|
42
96
|
## Exported Components
|
|
43
97
|
|
|
44
98
|
### Core Components
|
|
99
|
+
|
|
45
100
|
- **Buttons:** `Button`
|
|
46
101
|
- **Display:** `Badge`, `Card`, `Avatar`, `Skeleton`, `Progress`
|
|
47
102
|
- **Form Inputs:** `Input`, `Textarea`, `Checkbox`, `Switch`, `Label`
|
|
48
103
|
|
|
49
104
|
### Feedback & Overlays
|
|
105
|
+
|
|
50
106
|
- `Modal`, `ToastProvider`, `useToast`, `Tooltip`, `Popover`, `Sheet` (includes `Drawer`, `SlideOver`, `BottomSheet`, `SidebarSheet`), `Alert`, `GlobalLoading` (includes `PageLoading`, `InlineLoading`, `ButtonLoading`)
|
|
51
107
|
|
|
52
108
|
### Form Controls & Pickers
|
|
109
|
+
|
|
53
110
|
- `RadioGroup`, `Slider`, `DatePicker`, `Combobox`, `MultiCombobox`, `CategoryTreeSelect`
|
|
54
111
|
|
|
55
112
|
### Navigation & Structure
|
|
113
|
+
|
|
56
114
|
- `Breadcrumb`, `Tabs` (includes `SimpleTabs`, `PillTabs`, `VerticalTabs`), `DropdownMenu`, `Pagination`, `Section`, `ScrollArea`
|
|
57
115
|
|
|
58
116
|
### Data Display
|
|
117
|
+
|
|
59
118
|
- `Table`, `DataTable`
|
|
60
119
|
|
|
61
120
|
### Media Components
|
|
121
|
+
|
|
62
122
|
- `SmartImage`, `ImageUpload`, `Carousel`
|
|
63
123
|
|
|
64
124
|
### Utilities
|
|
125
|
+
|
|
65
126
|
- `ClientOnly`, `Loading`, `NotificationModal`, `FloatingContacts`, `AccessDenied`
|
|
66
127
|
- Headless controls: `ThemeToggle`, `LanguageSwitcher`
|
|
67
128
|
- Utility functions: `cn`, `DateUtils`, style constants
|
|
68
129
|
|
|
69
130
|
## Important Notes
|
|
131
|
+
|
|
70
132
|
- Library is i18n‑agnostic: components have sensible English defaults and accept text via props.
|
|
71
133
|
- If your app uses `next-intl`, you can merge our ready‑made messages to localize built‑in texts.
|
|
72
134
|
- `NotificationBell` is not exported (depends on project‑specific API/socket implementations).
|
|
73
135
|
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 📦 Date Utilities
|
|
139
|
+
|
|
140
|
+
The package includes standalone date utilities with locale support (no Next.js required):
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
import { DateUtils } from "@underverse-ui/underverse";
|
|
144
|
+
|
|
145
|
+
// Format dates with locale
|
|
146
|
+
DateUtils.formatDate(new Date(), "ko"); // "2026년 1월 5일"
|
|
147
|
+
DateUtils.formatDate(new Date(), "ja"); // "2026年1月5日"
|
|
148
|
+
DateUtils.formatDate(new Date(), "vi"); // "05/01/2026"
|
|
149
|
+
DateUtils.formatDate(new Date(), "en"); // "January 5, 2026"
|
|
150
|
+
|
|
151
|
+
// Relative time formatting
|
|
152
|
+
DateUtils.formatTimeAgo(new Date(Date.now() - 3600000), "ko"); // "1시간 전"
|
|
153
|
+
DateUtils.formatTimeAgo(new Date(Date.now() - 3600000), "ja"); // "1時間前"
|
|
154
|
+
|
|
155
|
+
// Smart date formatting (Today, Yesterday, or full date)
|
|
156
|
+
DateUtils.formatDateSmart(new Date(), "ja"); // "今日 14:30"
|
|
157
|
+
|
|
158
|
+
// Utility checks
|
|
159
|
+
DateUtils.isToday(new Date()); // true
|
|
160
|
+
DateUtils.isYesterday(new Date(Date.now() - 86400000)); // true
|
|
161
|
+
|
|
162
|
+
// Get day of week
|
|
163
|
+
DateUtils.getDayOfWeek(new Date(), "ko"); // "일요일"
|
|
164
|
+
DateUtils.getDayOfWeek(new Date(), "ja"); // "日曜日"
|
|
165
|
+
|
|
166
|
+
// Form input formatting
|
|
167
|
+
DateUtils.formatDateForInput(new Date()); // "2026-01-05"
|
|
168
|
+
DateUtils.formatDateTimeForInput(new Date()); // "2026-01-05T14:30"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Available Date Functions
|
|
172
|
+
|
|
173
|
+
| Function | Description |
|
|
174
|
+
| ------------------------------- | ----------------------------------- |
|
|
175
|
+
| `formatDate(date, locale)` | Full date format |
|
|
176
|
+
| `formatDateShort(date, locale)` | Short date format |
|
|
177
|
+
| `formatTime(date, locale)` | Time only (HH:mm) |
|
|
178
|
+
| `formatDateTime(date, locale)` | Date + time |
|
|
179
|
+
| `formatTimeAgo(date, locale)` | Relative time (e.g., "2 hours ago") |
|
|
180
|
+
| `formatDateSmart(date, locale)` | Today/Yesterday/Full date |
|
|
181
|
+
| `isToday(date)` | Check if date is today |
|
|
182
|
+
| `isYesterday(date)` | Check if date is yesterday |
|
|
183
|
+
| `getDayOfWeek(date, locale)` | Get localized day name |
|
|
184
|
+
| `formatDateForInput(date)` | YYYY-MM-DD format |
|
|
185
|
+
| `formatDateTimeForInput(date)` | YYYY-MM-DDTHH:mm format |
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 🎨 Animation Utilities
|
|
190
|
+
|
|
191
|
+
The package includes ShadCN-compatible animation utilities:
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import { useShadCNAnimations, injectAnimationStyles, getAnimationStyles } from "@underverse-ui/underverse";
|
|
195
|
+
|
|
196
|
+
// React hook - automatically injects styles on mount
|
|
197
|
+
function MyComponent() {
|
|
198
|
+
useShadCNAnimations();
|
|
199
|
+
return <div className="animate-accordion-down">Content</div>;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Manual injection (for non-React usage)
|
|
203
|
+
injectAnimationStyles();
|
|
204
|
+
|
|
205
|
+
// Get CSS string for custom injection
|
|
206
|
+
const cssString = getAnimationStyles();
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Available Animations
|
|
210
|
+
|
|
211
|
+
| Class | Description |
|
|
212
|
+
| ------------------------------ | ---------------------------- |
|
|
213
|
+
| `animate-accordion-down` | Accordion expand animation |
|
|
214
|
+
| `animate-accordion-up` | Accordion collapse animation |
|
|
215
|
+
| `animate-caret-blink` | Blinking caret cursor |
|
|
216
|
+
| `animate-fade-in` | Fade in effect |
|
|
217
|
+
| `animate-fade-out` | Fade out effect |
|
|
218
|
+
| `animate-slide-in-from-top` | Slide in from top |
|
|
219
|
+
| `animate-slide-in-from-bottom` | Slide in from bottom |
|
|
220
|
+
| `animate-slide-in-from-left` | Slide in from left |
|
|
221
|
+
| `animate-slide-in-from-right` | Slide in from right |
|
|
222
|
+
| `animate-zoom-in` | Zoom in effect |
|
|
223
|
+
| `animate-zoom-out` | Zoom out effect |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
74
227
|
## next-intl Integration (Next.js App Router)
|
|
75
228
|
|
|
76
|
-
1
|
|
229
|
+
1. Configure plugin and time zone (to avoid `ENVIRONMENT_FALLBACK`):
|
|
77
230
|
|
|
78
231
|
```ts
|
|
79
232
|
// next.config.ts
|
|
80
|
-
import createNextIntlPlugin from
|
|
233
|
+
import createNextIntlPlugin from "next-intl/plugin";
|
|
81
234
|
|
|
82
235
|
const withNextIntl = createNextIntlPlugin({
|
|
83
|
-
locales: [
|
|
84
|
-
defaultLocale:
|
|
85
|
-
timeZone:
|
|
236
|
+
locales: ["vi", "en"],
|
|
237
|
+
defaultLocale: "vi",
|
|
238
|
+
timeZone: "Asia/Ho_Chi_Minh", // important for SSR
|
|
86
239
|
});
|
|
87
240
|
|
|
88
241
|
export default withNextIntl({
|
|
@@ -90,18 +243,18 @@ export default withNextIntl({
|
|
|
90
243
|
});
|
|
91
244
|
```
|
|
92
245
|
|
|
93
|
-
2
|
|
246
|
+
2. Merge underverse messages with your app messages:
|
|
94
247
|
|
|
95
248
|
```tsx
|
|
96
249
|
// app/layout.tsx (simplified)
|
|
97
|
-
import {NextIntlClientProvider, getMessages} from
|
|
98
|
-
import {underverseMessages} from
|
|
250
|
+
import { NextIntlClientProvider, getMessages } from "next-intl/server";
|
|
251
|
+
import { underverseMessages } from "@underverse-ui/underverse";
|
|
99
252
|
|
|
100
|
-
export default async function RootLayout({children}:{children: React.ReactNode}) {
|
|
253
|
+
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
|
101
254
|
const appMessages = await getMessages();
|
|
102
|
-
const locale =
|
|
255
|
+
const locale = "vi"; // derive from params/headers
|
|
103
256
|
const uv = underverseMessages[locale] || underverseMessages.en;
|
|
104
|
-
const messages = {...uv, ...appMessages}; // app overrides uv if overlaps
|
|
257
|
+
const messages = { ...uv, ...appMessages }; // app overrides uv if overlaps
|
|
105
258
|
|
|
106
259
|
return (
|
|
107
260
|
<html lang={locale}>
|
|
@@ -115,7 +268,43 @@ export default async function RootLayout({children}:{children: React.ReactNode})
|
|
|
115
268
|
}
|
|
116
269
|
```
|
|
117
270
|
|
|
118
|
-
3
|
|
271
|
+
3. Use components normally. Any built‑in texts (DatePicker/Pagination/DataTable/Alert/ImageUpload…) will use merged messages. You can still override labels via props if desired.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 🌐 TranslationProvider API
|
|
276
|
+
|
|
277
|
+
For standalone React apps (without next-intl):
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
import { TranslationProvider } from "@underverse-ui/underverse";
|
|
281
|
+
|
|
282
|
+
function App() {
|
|
283
|
+
return (
|
|
284
|
+
<TranslationProvider
|
|
285
|
+
locale="ko" // "en" | "vi" | "ko" | "ja"
|
|
286
|
+
translations={{
|
|
287
|
+
// Optional: override default translations
|
|
288
|
+
Common: {
|
|
289
|
+
close: "닫기 (custom)",
|
|
290
|
+
},
|
|
291
|
+
}}
|
|
292
|
+
>
|
|
293
|
+
{children}
|
|
294
|
+
</TranslationProvider>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### TranslationProvider Props
|
|
300
|
+
|
|
301
|
+
| Prop | Type | Default | Description |
|
|
302
|
+
| -------------- | ------------------------------ | ----------- | ---------------------------- |
|
|
303
|
+
| `locale` | `"en" \| "vi" \| "ko" \| "ja"` | `"en"` | Active locale |
|
|
304
|
+
| `translations` | `Translations` | `undefined` | Custom translation overrides |
|
|
305
|
+
| `children` | `ReactNode` | - | Child components |
|
|
306
|
+
|
|
307
|
+
---
|
|
119
308
|
|
|
120
309
|
## Message Keys Summary
|
|
121
310
|
|
|
@@ -126,6 +315,49 @@ export default async function RootLayout({children}:{children: React.ReactNode})
|
|
|
126
315
|
- `Pagination`: navigationLabel, showingResults ({startItem},{endItem},{totalItems}), firstPage, previousPage, previous, nextPage, next, lastPage, pageNumber ({page}), itemsPerPage, search, noOptions
|
|
127
316
|
- `OCR.imageUpload`: dragDropText, browseFiles, supportedFormats
|
|
128
317
|
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 📋 Exported Components
|
|
321
|
+
|
|
322
|
+
### Core Components
|
|
323
|
+
|
|
324
|
+
- **Buttons:** `Button`
|
|
325
|
+
- **Display:** `Badge`, `Card`, `Avatar`, `Skeleton`, `Progress`
|
|
326
|
+
- **Form Inputs:** `Input`, `PasswordInput`, `NumberInput`, `SearchInput`, `Textarea`, `Checkbox`, `Switch`, `Label`, `TagInput`
|
|
327
|
+
|
|
328
|
+
### Feedback & Overlays
|
|
329
|
+
|
|
330
|
+
- `Modal`, `ToastProvider`, `useToast`, `Tooltip`, `Popover`
|
|
331
|
+
- `Sheet` (includes `Drawer`, `SlideOver`, `BottomSheet`, `SidebarSheet`)
|
|
332
|
+
- `Alert`, `GlobalLoading` (includes `PageLoading`, `InlineLoading`, `ButtonLoading`)
|
|
333
|
+
|
|
334
|
+
### Form Controls & Pickers
|
|
335
|
+
|
|
336
|
+
- `RadioGroup`, `Slider`, `DatePicker`, `DateRangePicker`, `TimePicker`, `Calendar`
|
|
337
|
+
- `Combobox`, `MultiCombobox`, `CategoryTreeSelect`, `ColorPicker`
|
|
338
|
+
|
|
339
|
+
### Navigation & Structure
|
|
340
|
+
|
|
341
|
+
- `Breadcrumb`, `Tabs` (includes `SimpleTabs`, `PillTabs`, `VerticalTabs`)
|
|
342
|
+
- `DropdownMenu`, `Pagination`, `SimplePagination`, `CompactPagination`
|
|
343
|
+
- `Section`, `ScrollArea`
|
|
344
|
+
|
|
345
|
+
### Data Display
|
|
346
|
+
|
|
347
|
+
- `Table`, `DataTable`, `List`, `Grid`, `Timeline`
|
|
348
|
+
|
|
349
|
+
### Media Components
|
|
350
|
+
|
|
351
|
+
- `SmartImage`, `ImageUpload`, `Carousel`, `FallingIcons`, `Watermark`
|
|
352
|
+
|
|
353
|
+
### Utilities
|
|
354
|
+
|
|
355
|
+
- `ClientOnly`, `Loading`, `NotificationModal`, `FloatingContacts`, `AccessDenied`
|
|
356
|
+
- `ThemeToggle`, `LanguageSwitcher` (headless)
|
|
357
|
+
- `cn`, `DateUtils`, `useShadCNAnimations`
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
129
361
|
## License
|
|
130
362
|
|
|
131
363
|
MIT
|
|
@@ -143,18 +375,18 @@ These variants avoid app-specific contexts and routing so you can wire them to y
|
|
|
143
375
|
### ThemeToggle (headless)
|
|
144
376
|
|
|
145
377
|
```tsx
|
|
146
|
-
import { ThemeToggle } from
|
|
147
|
-
import type { ThemeToggleProps, ThemeMode } from
|
|
148
|
-
import { useState } from
|
|
378
|
+
import { ThemeToggle } from "@underverse-ui/underverse";
|
|
379
|
+
import type { ThemeToggleProps, ThemeMode } from "@underverse-ui/underverse";
|
|
380
|
+
import { useState } from "react";
|
|
149
381
|
|
|
150
382
|
export default function ExampleThemeToggle() {
|
|
151
|
-
const [theme, setTheme] = useState<ThemeMode>(
|
|
383
|
+
const [theme, setTheme] = useState<ThemeMode>("system");
|
|
152
384
|
return (
|
|
153
385
|
<ThemeToggle
|
|
154
386
|
theme={theme}
|
|
155
387
|
onChange={setTheme}
|
|
156
388
|
// optional labels
|
|
157
|
-
labels={{ heading:
|
|
389
|
+
labels={{ heading: "Theme", light: "Light", dark: "Dark", system: "System" }}
|
|
158
390
|
/>
|
|
159
391
|
);
|
|
160
392
|
}
|
|
@@ -165,15 +397,15 @@ If you use `next-themes` or a custom context, pass your current theme and the se
|
|
|
165
397
|
### LanguageSwitcher (headless)
|
|
166
398
|
|
|
167
399
|
```tsx
|
|
168
|
-
import { LanguageSwitcher } from
|
|
169
|
-
import type { LanguageOption } from
|
|
170
|
-
import { useRouter, usePathname } from
|
|
400
|
+
import { LanguageSwitcher } from "@underverse-ui/underverse";
|
|
401
|
+
import type { LanguageOption } from "@underverse-ui/underverse";
|
|
402
|
+
import { useRouter, usePathname } from "next/navigation";
|
|
171
403
|
|
|
172
404
|
const locales: LanguageOption[] = [
|
|
173
|
-
{ code:
|
|
174
|
-
{ code:
|
|
175
|
-
{ code:
|
|
176
|
-
{ code:
|
|
405
|
+
{ code: "vi", name: "Tiếng Việt", flag: "🇻🇳" },
|
|
406
|
+
{ code: "en", name: "English", flag: "🇺🇸" },
|
|
407
|
+
{ code: "ko", name: "한국어", flag: "🇰🇷" },
|
|
408
|
+
{ code: "ja", name: "日本語", flag: "🇯🇵" },
|
|
177
409
|
];
|
|
178
410
|
|
|
179
411
|
export default function ExampleLanguageSwitcher({ currentLocale }: { currentLocale: string }) {
|
|
@@ -182,18 +414,156 @@ export default function ExampleLanguageSwitcher({ currentLocale }: { currentLoca
|
|
|
182
414
|
|
|
183
415
|
const onSwitch = (code: string) => {
|
|
184
416
|
// Replace first segment as locale, e.g. /vi/... -> /en/...
|
|
185
|
-
const segs = pathname.split(
|
|
186
|
-
segs[1] = code;
|
|
187
|
-
router.push(segs.join(
|
|
417
|
+
const segs = pathname.split("/");
|
|
418
|
+
segs[1] = code;
|
|
419
|
+
router.push(segs.join("/"));
|
|
188
420
|
};
|
|
189
421
|
|
|
190
|
-
return
|
|
191
|
-
<LanguageSwitcher
|
|
192
|
-
locales={locales}
|
|
193
|
-
currentLocale={currentLocale}
|
|
194
|
-
onSwitch={onSwitch}
|
|
195
|
-
labels={{ heading: 'Language' }}
|
|
196
|
-
/>
|
|
197
|
-
);
|
|
422
|
+
return <LanguageSwitcher locales={locales} currentLocale={currentLocale} onSwitch={onSwitch} labels={{ heading: "Language" }} />;
|
|
198
423
|
}
|
|
199
424
|
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## 📁 Full Export Reference
|
|
429
|
+
|
|
430
|
+
```tsx
|
|
431
|
+
// Core Components
|
|
432
|
+
import {
|
|
433
|
+
Button,
|
|
434
|
+
Badge,
|
|
435
|
+
Card,
|
|
436
|
+
Avatar,
|
|
437
|
+
Skeleton,
|
|
438
|
+
Progress,
|
|
439
|
+
Input,
|
|
440
|
+
PasswordInput,
|
|
441
|
+
NumberInput,
|
|
442
|
+
SearchInput,
|
|
443
|
+
Textarea,
|
|
444
|
+
Checkbox,
|
|
445
|
+
Switch,
|
|
446
|
+
Label,
|
|
447
|
+
TagInput,
|
|
448
|
+
} from "@underverse-ui/underverse";
|
|
449
|
+
|
|
450
|
+
// Overlays
|
|
451
|
+
import {
|
|
452
|
+
Modal,
|
|
453
|
+
ToastProvider,
|
|
454
|
+
useToast,
|
|
455
|
+
Tooltip,
|
|
456
|
+
Popover,
|
|
457
|
+
Sheet,
|
|
458
|
+
Drawer,
|
|
459
|
+
SlideOver,
|
|
460
|
+
BottomSheet,
|
|
461
|
+
SidebarSheet,
|
|
462
|
+
Alert,
|
|
463
|
+
GlobalLoading,
|
|
464
|
+
PageLoading,
|
|
465
|
+
InlineLoading,
|
|
466
|
+
ButtonLoading,
|
|
467
|
+
} from "@underverse-ui/underverse";
|
|
468
|
+
|
|
469
|
+
// Pickers
|
|
470
|
+
import {
|
|
471
|
+
DatePicker,
|
|
472
|
+
DateRangePicker,
|
|
473
|
+
TimePicker,
|
|
474
|
+
Calendar,
|
|
475
|
+
Combobox,
|
|
476
|
+
MultiCombobox,
|
|
477
|
+
CategoryTreeSelect,
|
|
478
|
+
ColorPicker,
|
|
479
|
+
RadioGroup,
|
|
480
|
+
Slider,
|
|
481
|
+
} from "@underverse-ui/underverse";
|
|
482
|
+
|
|
483
|
+
// Navigation
|
|
484
|
+
import {
|
|
485
|
+
Breadcrumb,
|
|
486
|
+
Tabs,
|
|
487
|
+
SimpleTabs,
|
|
488
|
+
PillTabs,
|
|
489
|
+
VerticalTabs,
|
|
490
|
+
DropdownMenu,
|
|
491
|
+
Pagination,
|
|
492
|
+
SimplePagination,
|
|
493
|
+
CompactPagination,
|
|
494
|
+
Section,
|
|
495
|
+
ScrollArea,
|
|
496
|
+
} from "@underverse-ui/underverse";
|
|
497
|
+
|
|
498
|
+
// Data Display
|
|
499
|
+
import { Table, DataTable, List, Grid, Timeline, Watermark } from "@underverse-ui/underverse";
|
|
500
|
+
|
|
501
|
+
// Media
|
|
502
|
+
import { SmartImage, ImageUpload, Carousel, FallingIcons } from "@underverse-ui/underverse";
|
|
503
|
+
|
|
504
|
+
// Utilities
|
|
505
|
+
import {
|
|
506
|
+
cn,
|
|
507
|
+
DateUtils,
|
|
508
|
+
useShadCNAnimations,
|
|
509
|
+
injectAnimationStyles,
|
|
510
|
+
ClientOnly,
|
|
511
|
+
Loading,
|
|
512
|
+
NotificationModal,
|
|
513
|
+
FloatingContacts,
|
|
514
|
+
AccessDenied,
|
|
515
|
+
ThemeToggle,
|
|
516
|
+
LanguageSwitcher,
|
|
517
|
+
} from "@underverse-ui/underverse";
|
|
518
|
+
|
|
519
|
+
// i18n
|
|
520
|
+
import {
|
|
521
|
+
TranslationProvider,
|
|
522
|
+
useUnderverseTranslations,
|
|
523
|
+
useUnderverseLocale,
|
|
524
|
+
underverseMessages,
|
|
525
|
+
getUnderverseMessages,
|
|
526
|
+
} from "@underverse-ui/underverse";
|
|
527
|
+
|
|
528
|
+
// Types
|
|
529
|
+
import type {
|
|
530
|
+
ButtonProps,
|
|
531
|
+
InputProps,
|
|
532
|
+
DatePickerProps,
|
|
533
|
+
ComboboxProps,
|
|
534
|
+
PaginationProps,
|
|
535
|
+
DataTableColumn,
|
|
536
|
+
Locale,
|
|
537
|
+
Translations,
|
|
538
|
+
} from "@underverse-ui/underverse";
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## 🧪 Testing
|
|
544
|
+
|
|
545
|
+
### Test with React (Vite)
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
# Create new Vite project
|
|
549
|
+
npm create vite@latest my-test-app -- --template react-ts
|
|
550
|
+
cd my-test-app
|
|
551
|
+
|
|
552
|
+
# Install underverse
|
|
553
|
+
npm i @underverse-ui/underverse
|
|
554
|
+
|
|
555
|
+
# Add Tailwind CSS
|
|
556
|
+
npm i -D tailwindcss postcss autoprefixer
|
|
557
|
+
npx tailwindcss init -p
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Test with Next.js
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
# Create new Next.js project
|
|
564
|
+
npx create-next-app@latest my-test-app --typescript --tailwind
|
|
565
|
+
cd my-test-app
|
|
566
|
+
|
|
567
|
+
# Install underverse
|
|
568
|
+
npm i @underverse-ui/underverse next-intl
|
|
569
|
+
```
|