@janovix/blocks 1.0.0-rc.4 → 1.0.0-rc.5

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 CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > Shared UI components for Janovix applications
4
4
 
5
+ A collection of reusable, accessible UI components built with React, Radix UI, and Tailwind CSS. Designed for use across all Janovix applications.
6
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
@@ -18,56 +20,631 @@ This package requires the following peer dependencies:
18
20
  pnpm add react react-dom next-themes lucide-react motion
19
21
  ```
20
22
 
23
+ ## Configuration
24
+
25
+ ### Tailwind CSS
26
+
27
+ Configure your Tailwind CSS to include this package:
28
+
29
+ ```js
30
+ // tailwind.config.js
31
+ module.exports = {
32
+ content: [
33
+ // ... your other content paths
34
+ "./node_modules/@janovix/blocks/dist/**/*.js",
35
+ ],
36
+ // ... rest of your config
37
+ };
38
+ ```
39
+
21
40
  ## Components
22
41
 
23
42
  ### ThemeSwitcher
24
43
 
25
- A theme switcher component that integrates with `next-themes`.
44
+ A theme switcher component that integrates with `next-themes`. Supports light, dark, and system themes.
45
+
46
+ **Features:**
47
+
48
+ - Multiple variants (default, mini)
49
+ - Multiple sizes (sm, md, lg)
50
+ - Multiple shapes (rounded, pill)
51
+ - Internationalization support
52
+
53
+ **Usage:**
26
54
 
27
55
  ```tsx
28
56
  import { ThemeSwitcher } from "@janovix/blocks";
29
57
 
30
58
  // Default usage
31
- <ThemeSwitcher />
59
+ <ThemeSwitcher />;
32
60
 
33
61
  // With custom labels (for i18n)
34
62
  <ThemeSwitcher
35
- labels={{
36
- theme: "Theme",
37
- system: "System",
38
- light: "Light",
39
- dark: "Dark",
40
- }}
41
- />
63
+ labels={{
64
+ theme: "Theme",
65
+ system: "System",
66
+ light: "Light",
67
+ dark: "Dark",
68
+ }}
69
+ />;
42
70
 
43
71
  // Mini variant (icon only with dropdown)
44
- <ThemeSwitcher variant="mini" />
72
+ <ThemeSwitcher variant="mini" />;
45
73
 
46
- // Different sizes
47
- <ThemeSwitcher size="sm" />
48
- <ThemeSwitcher size="md" />
49
- <ThemeSwitcher size="lg" />
74
+ // Different sizes and shapes
75
+ <ThemeSwitcher size="sm" shape="pill" />;
76
+ ```
77
+
78
+ **Props:**
50
79
 
51
- // Different shapes
52
- <ThemeSwitcher shape="rounded" />
53
- <ThemeSwitcher shape="pill" />
80
+ ```typescript
81
+ interface ThemeSwitcherProps {
82
+ variant?: "default" | "mini";
83
+ size?: "sm" | "md" | "lg";
84
+ shape?: "rounded" | "pill";
85
+ showIcon?: boolean;
86
+ labels?: ThemeSwitcherLabels;
87
+ className?: string;
88
+ }
54
89
  ```
55
90
 
56
- ## Styling
91
+ ---
57
92
 
58
- This package uses Tailwind CSS classes. You need to configure your Tailwind CSS to include this package:
93
+ ### LanguageSwitcher
59
94
 
60
- ```js
61
- // tailwind.config.js
62
- module.exports = {
63
- content: [
64
- // ... your other content paths
65
- "./node_modules/@janovix/blocks/dist/**/*.js",
66
- ],
67
- // ... rest of your config
95
+ A language switcher component with support for multiple languages and display variants.
96
+
97
+ **Features:**
98
+
99
+ - Multiple variants (default, mini)
100
+ - Multiple sizes (sm, md, lg)
101
+ - Dropdown positioning control
102
+ - Language flag/icon support
103
+ - Internationalization support
104
+
105
+ **Usage:**
106
+
107
+ ```tsx
108
+ import { LanguageSwitcher } from "@janovix/blocks";
109
+
110
+ const languages = [
111
+ { key: "en", label: "EN", nativeName: "English" },
112
+ { key: "es", label: "ES", nativeName: "Español" },
113
+ ];
114
+
115
+ <LanguageSwitcher
116
+ languages={languages}
117
+ currentLanguage="en"
118
+ onLanguageChange={(key) => setLanguage(key)}
119
+ labels={{ language: "Language" }}
120
+ />;
121
+
122
+ // Mini variant
123
+ <LanguageSwitcher
124
+ variant="mini"
125
+ languages={languages}
126
+ currentLanguage="en"
127
+ onLanguageChange={(key) => setLanguage(key)}
128
+ />;
129
+
130
+ // With icon
131
+ <LanguageSwitcher
132
+ languages={languages}
133
+ currentLanguage="en"
134
+ onLanguageChange={(key) => setLanguage(key)}
135
+ showIcon
136
+ />;
137
+ ```
138
+
139
+ **Props:**
140
+
141
+ ```typescript
142
+ interface LanguageSwitcherProps {
143
+ languages: Language[];
144
+ currentLanguage: string;
145
+ onLanguageChange: (languageKey: string) => void;
146
+ variant?: "default" | "mini";
147
+ size?: "sm" | "md" | "lg";
148
+ dropdownAlign?: "start" | "center" | "end";
149
+ showIcon?: boolean;
150
+ labels?: LanguageSwitcherLabels;
151
+ className?: string;
152
+ }
153
+
154
+ interface Language {
155
+ key: string;
156
+ label: string;
157
+ nativeName: string;
158
+ }
159
+ ```
160
+
161
+ ---
162
+
163
+ ### AvatarEditor
164
+
165
+ An interactive avatar editor with zoom, rotation, and flip controls.
166
+
167
+ **Features:**
168
+
169
+ - Image zoom (0.1x - 3x)
170
+ - Image rotation (0° - 360°)
171
+ - Horizontal/vertical flip
172
+ - Real-time preview
173
+ - Customizable size
174
+ - Mouse wheel zoom support
175
+ - Drag to reposition
176
+
177
+ **Usage:**
178
+
179
+ ```tsx
180
+ import { AvatarEditor } from "@janovix/blocks";
181
+
182
+ <AvatarEditor
183
+ value={avatarData}
184
+ onChange={(editedImage) => {
185
+ console.log("Edited image:", editedImage);
186
+ }}
187
+ />;
188
+
189
+ // With custom size and grid
190
+ <AvatarEditor
191
+ value={avatarData}
192
+ onChange={setAvatarData}
193
+ size={280}
194
+ showGrid={true}
195
+ />;
196
+
197
+ // With custom output settings
198
+ <AvatarEditor
199
+ value={avatarData}
200
+ onChange={setAvatarData}
201
+ outputSize={512}
202
+ outputFormat="jpeg"
203
+ outputQuality={0.95}
204
+ />;
205
+
206
+ // With large controls for mobile/touch
207
+ <AvatarEditor
208
+ value={avatarData}
209
+ onChange={setAvatarData}
210
+ controlSize="large"
211
+ />;
212
+ ```
213
+
214
+ **Props:**
215
+
216
+ ```typescript
217
+ interface AvatarEditorProps {
218
+ value?: string | null;
219
+ onChange?: (dataUrl: string | null) => void;
220
+ size?: number;
221
+ showGrid?: boolean;
222
+ outputSize?: number;
223
+ outputFormat?: "png" | "jpeg" | "webp";
224
+ outputQuality?: number;
225
+ controlSize?: "default" | "large";
226
+ className?: string;
227
+ }
228
+ ```
229
+
230
+ ---
231
+
232
+ ### AvatarEditorDialog
233
+
234
+ A dialog wrapper for the AvatarEditor component with upload functionality.
235
+
236
+ **Features:**
237
+
238
+ - File upload with drag & drop
239
+ - Image preview
240
+ - Integrated AvatarEditor
241
+ - Cancel/Save actions
242
+ - File type validation (image/\*)
243
+
244
+ **Usage:**
245
+
246
+ ```tsx
247
+ import { AvatarEditorDialog } from "@janovix/blocks";
248
+
249
+ <AvatarEditorDialog
250
+ isOpen={isOpen}
251
+ onOpenChange={setIsOpen}
252
+ onSave={(editedImage) => {
253
+ console.log("Saving image:", editedImage);
254
+ }}
255
+ title="Edit Avatar"
256
+ uploadLabel="Upload Image"
257
+ cancelLabel="Cancel"
258
+ saveLabel="Save"
259
+ />;
260
+ ```
261
+
262
+ **Props:**
263
+
264
+ ```typescript
265
+ interface AvatarEditorDialogProps {
266
+ isOpen: boolean;
267
+ onOpenChange: (open: boolean) => void;
268
+ onSave: (editedImage: string) => void;
269
+ title?: string;
270
+ uploadLabel?: string;
271
+ cancelLabel?: string;
272
+ saveLabel?: string;
273
+ }
274
+ ```
275
+
276
+ ---
277
+
278
+ ### NotificationsWidget
279
+
280
+ A compact notification bell widget with popover display, sound alerts, and animations.
281
+
282
+ **Features:**
283
+
284
+ - Bell icon with unread count badge
285
+ - Popover with scrollable notification list
286
+ - Multiple notification types (info, success, warning, error)
287
+ - Sound notifications (chime, bell, pop, ding)
288
+ - Pulse animations (ring, glow, bounce)
289
+ - Mark as read/dismiss actions
290
+ - Click-to-navigate support
291
+ - Customizable colors, sizes, and sounds
292
+
293
+ **Usage:**
294
+
295
+ ```tsx
296
+ import { NotificationsWidget, Notification } from "@janovix/blocks";
297
+
298
+ const notifications: Notification[] = [
299
+ {
300
+ id: "1",
301
+ title: "New message",
302
+ message: "You have a new message from John",
303
+ type: "info",
304
+ timestamp: new Date(),
305
+ read: false,
306
+ },
307
+ {
308
+ id: "2",
309
+ title: "Task completed",
310
+ message: "Your export task finished successfully",
311
+ type: "success",
312
+ timestamp: new Date(Date.now() - 1000 * 60 * 5),
313
+ read: false,
314
+ },
315
+ ];
316
+
317
+ <NotificationsWidget
318
+ notifications={notifications}
319
+ onMarkAsRead={(id) => markAsRead(id)}
320
+ onMarkAllAsRead={() => markAllAsRead()}
321
+ onDismiss={(id) => dismiss(id)}
322
+ onClearAll={() => clearAll()}
323
+ onNotificationClick={(notification) => {
324
+ if (notification.href) {
325
+ router.push(notification.href);
326
+ }
327
+ }}
328
+ playSound
329
+ soundType="chime"
330
+ size="md"
331
+ dotColor="red"
332
+ pulseStyle="ring"
333
+ />;
334
+
335
+ // Minimal usage
336
+ <NotificationsWidget
337
+ notifications={notifications}
338
+ onMarkAsRead={(id) => markAsRead(id)}
339
+ />;
340
+
341
+ // Custom configuration
342
+ <NotificationsWidget
343
+ notifications={notifications}
344
+ onMarkAsRead={(id) => markAsRead(id)}
345
+ size="lg"
346
+ dotColor="primary"
347
+ soundType="bell"
348
+ pulseStyle="glow"
349
+ maxVisible={10}
350
+ title="Alerts"
351
+ emptyMessage="No alerts"
352
+ />;
353
+ ```
354
+
355
+ **Props:**
356
+
357
+ ```typescript
358
+ interface NotificationsWidgetProps {
359
+ notifications: Notification[];
360
+ onMarkAsRead?: (id: string) => void;
361
+ onMarkAllAsRead?: () => void;
362
+ onDismiss?: (id: string) => void;
363
+ onClearAll?: () => void;
364
+ onNotificationClick?: (notification: Notification) => void;
365
+ size?: "sm" | "md" | "lg";
366
+ maxVisible?: number; // Default: 5
367
+ playSound?: boolean; // Default: true
368
+ soundUrl?: string; // Custom sound file URL
369
+ soundType?: "chime" | "bell" | "pop" | "ding" | "none"; // Default: "chime"
370
+ soundCooldown?: number; // Default: 2000ms
371
+ className?: string;
372
+ emptyMessage?: string; // Default: "No notifications"
373
+ title?: string; // Default: "Notifications"
374
+ dotColor?: "red" | "blue" | "green" | "amber" | "purple" | "primary"; // Default: "red"
375
+ showPulse?: boolean; // Default: true
376
+ pulseStyle?: "ring" | "glow" | "bounce" | "none"; // Default: "ring"
377
+ }
378
+
379
+ interface Notification {
380
+ id: string;
381
+ title: string;
382
+ message?: string;
383
+ type?: "info" | "success" | "warning" | "error"; // Default: "info"
384
+ timestamp: Date;
385
+ read?: boolean;
386
+ href?: string; // Optional link for click navigation
387
+ }
388
+ ```
389
+
390
+ ---
391
+
392
+ ## UI Primitives
393
+
394
+ The package also exports underlying UI primitives that can be used independently:
395
+
396
+ ### Button
397
+
398
+ ```tsx
399
+ import { Button } from "@janovix/blocks";
400
+
401
+ <Button variant="default">Click me</Button>;
402
+ <Button variant="outline" size="sm">
403
+ Small
404
+ </Button>;
405
+ <Button variant="ghost" size="icon">
406
+ <Icon />
407
+ </Button>;
408
+ ```
409
+
410
+ ### Dialog
411
+
412
+ ```tsx
413
+ import {
414
+ Dialog,
415
+ DialogTrigger,
416
+ DialogContent,
417
+ DialogHeader,
418
+ DialogTitle,
419
+ DialogDescription,
420
+ DialogFooter,
421
+ } from "@janovix/blocks";
422
+
423
+ <Dialog>
424
+ <DialogTrigger>Open</DialogTrigger>
425
+ <DialogContent>
426
+ <DialogHeader>
427
+ <DialogTitle>Title</DialogTitle>
428
+ <DialogDescription>Description</DialogDescription>
429
+ </DialogHeader>
430
+ {/* Content */}
431
+ <DialogFooter>{/* Actions */}</DialogFooter>
432
+ </DialogContent>
433
+ </Dialog>;
434
+ ```
435
+
436
+ ### Drawer
437
+
438
+ ```tsx
439
+ import {
440
+ Drawer,
441
+ DrawerTrigger,
442
+ DrawerContent,
443
+ DrawerHeader,
444
+ DrawerTitle,
445
+ } from "@janovix/blocks";
446
+
447
+ <Drawer>
448
+ <DrawerTrigger>Open</DrawerTrigger>
449
+ <DrawerContent>
450
+ <DrawerHeader>
451
+ <DrawerTitle>Title</DrawerTitle>
452
+ </DrawerHeader>
453
+ {/* Content */}
454
+ </DrawerContent>
455
+ </Drawer>;
456
+ ```
457
+
458
+ ### DropdownMenu
459
+
460
+ ```tsx
461
+ import {
462
+ DropdownMenu,
463
+ DropdownMenuTrigger,
464
+ DropdownMenuContent,
465
+ DropdownMenuItem,
466
+ } from "@janovix/blocks";
467
+
468
+ <DropdownMenu>
469
+ <DropdownMenuTrigger>Open</DropdownMenuTrigger>
470
+ <DropdownMenuContent>
471
+ <DropdownMenuItem>Item 1</DropdownMenuItem>
472
+ <DropdownMenuItem>Item 2</DropdownMenuItem>
473
+ </DropdownMenuContent>
474
+ </DropdownMenu>;
475
+ ```
476
+
477
+ ### Popover
478
+
479
+ ```tsx
480
+ import { Popover, PopoverTrigger, PopoverContent } from "@janovix/blocks";
481
+
482
+ <Popover>
483
+ <PopoverTrigger>Open</PopoverTrigger>
484
+ <PopoverContent>Content here</PopoverContent>
485
+ </Popover>;
486
+ ```
487
+
488
+ ### ScrollArea
489
+
490
+ ```tsx
491
+ import { ScrollArea } from "@janovix/blocks";
492
+
493
+ <ScrollArea className="h-[200px]">{/* Scrollable content */}</ScrollArea>;
494
+ ```
495
+
496
+ ### Slider
497
+
498
+ ```tsx
499
+ import { Slider } from "@janovix/blocks";
500
+
501
+ <Slider
502
+ value={[50]}
503
+ onValueChange={(value) => setValue(value[0])}
504
+ max={100}
505
+ step={1}
506
+ />;
507
+ ```
508
+
509
+ ### Toggle
510
+
511
+ ```tsx
512
+ import { Toggle } from "@janovix/blocks";
513
+
514
+ <Toggle pressed={isPressed} onPressedChange={setIsPressed}>
515
+ Toggle me
516
+ </Toggle>;
517
+ ```
518
+
519
+ ### Tooltip
520
+
521
+ ```tsx
522
+ import {
523
+ Tooltip,
524
+ TooltipTrigger,
525
+ TooltipContent,
526
+ TooltipProvider,
527
+ } from "@janovix/blocks";
528
+
529
+ <TooltipProvider>
530
+ <Tooltip>
531
+ <TooltipTrigger>Hover me</TooltipTrigger>
532
+ <TooltipContent>Tooltip text</TooltipContent>
533
+ </Tooltip>
534
+ </TooltipProvider>;
535
+ ```
536
+
537
+ ---
538
+
539
+ ## Utilities
540
+
541
+ ### cn (Class Name utility)
542
+
543
+ A utility function for conditionally merging Tailwind CSS classes.
544
+
545
+ ```tsx
546
+ import { cn } from "@janovix/blocks";
547
+
548
+ const className = cn("base-class", condition && "conditional-class", {
549
+ "another-class": someCondition,
550
+ });
551
+ ```
552
+
553
+ ---
554
+
555
+ ## TypeScript Support
556
+
557
+ All components are fully typed with TypeScript. Import types as needed:
558
+
559
+ ```tsx
560
+ import type {
561
+ ThemeSwitcherProps,
562
+ LanguageSwitcherProps,
563
+ Language,
564
+ AvatarEditorProps,
565
+ AvatarEditorDialogProps,
566
+ NotificationsWidgetProps,
567
+ Notification,
568
+ NotificationType,
569
+ } from "@janovix/blocks";
570
+ ```
571
+
572
+ ---
573
+
574
+ ## Best Practices
575
+
576
+ ### Internationalization
577
+
578
+ All text-based components accept label props for i18n:
579
+
580
+ ```tsx
581
+ import { useTranslation } from "your-i18n-library";
582
+
583
+ const { t } = useTranslation();
584
+
585
+ <ThemeSwitcher
586
+ labels={{
587
+ theme: t("theme"),
588
+ light: t("light"),
589
+ dark: t("dark"),
590
+ system: t("system"),
591
+ }}
592
+ />;
593
+ ```
594
+
595
+ ### Theme Integration
596
+
597
+ Components use CSS variables for theming. Ensure your app provides these variables:
598
+
599
+ ```css
600
+ :root {
601
+ --background: 0 0% 100%;
602
+ --foreground: 222.2 84% 4.9%;
603
+ --primary: 222.2 47.4% 11.2%;
604
+ --muted: 210 40% 96.1%;
605
+ --border: 214.3 31.8% 91.4%;
606
+ /* ... other variables */
607
+ }
608
+ ```
609
+
610
+ ### Notification Management
611
+
612
+ For `NotificationsWidget`, implement a notification management system:
613
+
614
+ ```tsx
615
+ // Example notification manager
616
+ const [notifications, setNotifications] = useState<Notification[]>([]);
617
+
618
+ const markAsRead = (id: string) => {
619
+ setNotifications((prev) =>
620
+ prev.map((n) => (n.id === id ? { ...n, read: true } : n)),
621
+ );
622
+ };
623
+
624
+ const dismiss = (id: string) => {
625
+ setNotifications((prev) => prev.filter((n) => n.id !== id));
626
+ };
627
+
628
+ const addNotification = (notification: Omit<Notification, "id">) => {
629
+ const id = crypto.randomUUID();
630
+ setNotifications((prev) => [{ ...notification, id }, ...prev]);
68
631
  };
69
632
  ```
70
633
 
634
+ ---
635
+
636
+ ## Contributing
637
+
638
+ This package is maintained as part of the Janovix monorepo. See the main repository for contribution guidelines.
639
+
71
640
  ## License
72
641
 
73
- MIT
642
+ Proprietary - Janovix © 2026
643
+
644
+ ## Version
645
+
646
+ Current version: `1.0.0-rc.4`
647
+
648
+ ## Support
649
+
650
+ For issues or questions, contact the Janovix development team or open an issue in the repository.