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

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,632 @@ 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 drag controls.
166
+
167
+ **Features:**
168
+
169
+ - Image zoom via UI buttons and slider (0.5x - 3x)
170
+ - Image rotation in 15° increments (0° - 360°)
171
+ - Drag to reposition image
172
+ - Real-time preview with circular crop
173
+ - Customizable editor size
174
+ - Optional grid overlay for alignment
175
+ - Reset all transforms
176
+ - Touch-optimized controls for mobile
177
+
178
+ **Usage:**
179
+
180
+ ```tsx
181
+ import { AvatarEditor } from "@janovix/blocks";
182
+
183
+ <AvatarEditor
184
+ value={avatarData}
185
+ onChange={(editedImage) => {
186
+ console.log("Edited image:", editedImage);
187
+ }}
188
+ />;
189
+
190
+ // With custom size and grid
191
+ <AvatarEditor
192
+ value={avatarData}
193
+ onChange={setAvatarData}
194
+ size={280}
195
+ showGrid={true}
196
+ />;
197
+
198
+ // With custom output settings
199
+ <AvatarEditor
200
+ value={avatarData}
201
+ onChange={setAvatarData}
202
+ outputSize={512}
203
+ outputFormat="jpeg"
204
+ outputQuality={0.95}
205
+ />;
206
+
207
+ // With large controls for mobile/touch
208
+ <AvatarEditor
209
+ value={avatarData}
210
+ onChange={setAvatarData}
211
+ controlSize="large"
212
+ />;
213
+ ```
214
+
215
+ **Props:**
216
+
217
+ ```typescript
218
+ interface AvatarEditorProps {
219
+ value?: string | null;
220
+ onChange?: (dataUrl: string | null) => void;
221
+ size?: number;
222
+ showGrid?: boolean;
223
+ outputSize?: number;
224
+ outputFormat?: "png" | "jpeg" | "webp";
225
+ outputQuality?: number;
226
+ controlSize?: "default" | "large";
227
+ className?: string;
228
+ }
229
+ ```
230
+
231
+ ---
232
+
233
+ ### AvatarEditorDialog
234
+
235
+ A dialog wrapper for the AvatarEditor component with upload functionality.
236
+
237
+ **Features:**
238
+
239
+ - File upload with drag & drop
240
+ - Image preview
241
+ - Integrated AvatarEditor
242
+ - Cancel/Save actions
243
+ - File type validation (image/\*)
244
+
245
+ **Usage:**
246
+
247
+ ```tsx
248
+ import { AvatarEditorDialog } from "@janovix/blocks";
249
+
250
+ <AvatarEditorDialog
251
+ isOpen={isOpen}
252
+ onOpenChange={setIsOpen}
253
+ onSave={(editedImage) => {
254
+ console.log("Saving image:", editedImage);
255
+ }}
256
+ title="Edit Avatar"
257
+ uploadLabel="Upload Image"
258
+ cancelLabel="Cancel"
259
+ saveLabel="Save"
260
+ />;
261
+ ```
262
+
263
+ **Props:**
264
+
265
+ ```typescript
266
+ interface AvatarEditorDialogProps {
267
+ isOpen: boolean;
268
+ onOpenChange: (open: boolean) => void;
269
+ onSave: (editedImage: string) => void;
270
+ title?: string;
271
+ uploadLabel?: string;
272
+ cancelLabel?: string;
273
+ saveLabel?: string;
274
+ }
275
+ ```
276
+
277
+ ---
278
+
279
+ ### NotificationsWidget
280
+
281
+ A compact notification bell widget with popover display, sound alerts, and animations.
282
+
283
+ **Features:**
284
+
285
+ - Bell icon with unread count badge
286
+ - Popover with scrollable notification list
287
+ - Multiple notification types (info, success, warning, error)
288
+ - Sound notifications (chime, bell, pop, ding)
289
+ - Pulse animations (ring, glow, bounce)
290
+ - Mark as read/dismiss actions
291
+ - Click-to-navigate support
292
+ - Customizable colors, sizes, and sounds
293
+
294
+ **Usage:**
295
+
296
+ ```tsx
297
+ import { NotificationsWidget, Notification } from "@janovix/blocks";
298
+
299
+ const notifications: Notification[] = [
300
+ {
301
+ id: "1",
302
+ title: "New message",
303
+ message: "You have a new message from John",
304
+ type: "info",
305
+ timestamp: new Date(),
306
+ read: false,
307
+ },
308
+ {
309
+ id: "2",
310
+ title: "Task completed",
311
+ message: "Your export task finished successfully",
312
+ type: "success",
313
+ timestamp: new Date(Date.now() - 1000 * 60 * 5),
314
+ read: false,
315
+ },
316
+ ];
317
+
318
+ <NotificationsWidget
319
+ notifications={notifications}
320
+ onMarkAsRead={(id) => markAsRead(id)}
321
+ onMarkAllAsRead={() => markAllAsRead()}
322
+ onDismiss={(id) => dismiss(id)}
323
+ onClearAll={() => clearAll()}
324
+ onNotificationClick={(notification) => {
325
+ if (notification.href) {
326
+ router.push(notification.href);
327
+ }
328
+ }}
329
+ playSound
330
+ soundType="chime"
331
+ size="md"
332
+ dotColor="red"
333
+ pulseStyle="ring"
334
+ />;
335
+
336
+ // Minimal usage
337
+ <NotificationsWidget
338
+ notifications={notifications}
339
+ onMarkAsRead={(id) => markAsRead(id)}
340
+ />;
341
+
342
+ // Custom configuration
343
+ <NotificationsWidget
344
+ notifications={notifications}
345
+ onMarkAsRead={(id) => markAsRead(id)}
346
+ size="lg"
347
+ dotColor="primary"
348
+ soundType="bell"
349
+ pulseStyle="glow"
350
+ maxVisible={10}
351
+ title="Alerts"
352
+ emptyMessage="No alerts"
353
+ />;
354
+ ```
355
+
356
+ **Props:**
357
+
358
+ ```typescript
359
+ interface NotificationsWidgetProps {
360
+ notifications: Notification[];
361
+ onMarkAsRead?: (id: string) => void;
362
+ onMarkAllAsRead?: () => void;
363
+ onDismiss?: (id: string) => void;
364
+ onClearAll?: () => void;
365
+ onNotificationClick?: (notification: Notification) => void;
366
+ size?: "sm" | "md" | "lg";
367
+ maxVisible?: number; // Default: 5
368
+ playSound?: boolean; // Default: true
369
+ soundUrl?: string; // Custom sound file URL
370
+ soundType?: "chime" | "bell" | "pop" | "ding" | "none"; // Default: "chime"
371
+ soundCooldown?: number; // Default: 2000ms
372
+ className?: string;
373
+ emptyMessage?: string; // Default: "No notifications"
374
+ title?: string; // Default: "Notifications"
375
+ dotColor?: "red" | "blue" | "green" | "amber" | "purple" | "primary"; // Default: "red"
376
+ showPulse?: boolean; // Default: true
377
+ pulseStyle?: "ring" | "glow" | "bounce" | "none"; // Default: "ring"
378
+ }
379
+
380
+ interface Notification {
381
+ id: string;
382
+ title: string;
383
+ message?: string;
384
+ type?: "info" | "success" | "warning" | "error"; // Default: "info"
385
+ timestamp: Date;
386
+ read?: boolean;
387
+ href?: string; // Optional link for click navigation
388
+ }
389
+ ```
390
+
391
+ ---
392
+
393
+ ## UI Primitives
394
+
395
+ The package also exports underlying UI primitives that can be used independently:
396
+
397
+ ### Button
398
+
399
+ ```tsx
400
+ import { Button } from "@janovix/blocks";
401
+
402
+ <Button variant="default">Click me</Button>;
403
+ <Button variant="outline" size="sm">
404
+ Small
405
+ </Button>;
406
+ <Button variant="ghost" size="icon">
407
+ <Icon />
408
+ </Button>;
409
+ ```
410
+
411
+ ### Dialog
412
+
413
+ ```tsx
414
+ import {
415
+ Dialog,
416
+ DialogTrigger,
417
+ DialogContent,
418
+ DialogHeader,
419
+ DialogTitle,
420
+ DialogDescription,
421
+ DialogFooter,
422
+ } from "@janovix/blocks";
423
+
424
+ <Dialog>
425
+ <DialogTrigger>Open</DialogTrigger>
426
+ <DialogContent>
427
+ <DialogHeader>
428
+ <DialogTitle>Title</DialogTitle>
429
+ <DialogDescription>Description</DialogDescription>
430
+ </DialogHeader>
431
+ {/* Content */}
432
+ <DialogFooter>{/* Actions */}</DialogFooter>
433
+ </DialogContent>
434
+ </Dialog>;
435
+ ```
436
+
437
+ ### Drawer
438
+
439
+ ```tsx
440
+ import {
441
+ Drawer,
442
+ DrawerTrigger,
443
+ DrawerContent,
444
+ DrawerHeader,
445
+ DrawerTitle,
446
+ } from "@janovix/blocks";
447
+
448
+ <Drawer>
449
+ <DrawerTrigger>Open</DrawerTrigger>
450
+ <DrawerContent>
451
+ <DrawerHeader>
452
+ <DrawerTitle>Title</DrawerTitle>
453
+ </DrawerHeader>
454
+ {/* Content */}
455
+ </DrawerContent>
456
+ </Drawer>;
457
+ ```
458
+
459
+ ### DropdownMenu
460
+
461
+ ```tsx
462
+ import {
463
+ DropdownMenu,
464
+ DropdownMenuTrigger,
465
+ DropdownMenuContent,
466
+ DropdownMenuItem,
467
+ } from "@janovix/blocks";
468
+
469
+ <DropdownMenu>
470
+ <DropdownMenuTrigger>Open</DropdownMenuTrigger>
471
+ <DropdownMenuContent>
472
+ <DropdownMenuItem>Item 1</DropdownMenuItem>
473
+ <DropdownMenuItem>Item 2</DropdownMenuItem>
474
+ </DropdownMenuContent>
475
+ </DropdownMenu>;
476
+ ```
477
+
478
+ ### Popover
479
+
480
+ ```tsx
481
+ import { Popover, PopoverTrigger, PopoverContent } from "@janovix/blocks";
482
+
483
+ <Popover>
484
+ <PopoverTrigger>Open</PopoverTrigger>
485
+ <PopoverContent>Content here</PopoverContent>
486
+ </Popover>;
487
+ ```
488
+
489
+ ### ScrollArea
490
+
491
+ ```tsx
492
+ import { ScrollArea } from "@janovix/blocks";
493
+
494
+ <ScrollArea className="h-[200px]">{/* Scrollable content */}</ScrollArea>;
495
+ ```
496
+
497
+ ### Slider
498
+
499
+ ```tsx
500
+ import { Slider } from "@janovix/blocks";
501
+
502
+ <Slider
503
+ value={[50]}
504
+ onValueChange={(value) => setValue(value[0])}
505
+ max={100}
506
+ step={1}
507
+ />;
508
+ ```
509
+
510
+ ### Toggle
511
+
512
+ ```tsx
513
+ import { Toggle } from "@janovix/blocks";
514
+
515
+ <Toggle pressed={isPressed} onPressedChange={setIsPressed}>
516
+ Toggle me
517
+ </Toggle>;
518
+ ```
519
+
520
+ ### Tooltip
521
+
522
+ ```tsx
523
+ import {
524
+ Tooltip,
525
+ TooltipTrigger,
526
+ TooltipContent,
527
+ TooltipProvider,
528
+ } from "@janovix/blocks";
529
+
530
+ <TooltipProvider>
531
+ <Tooltip>
532
+ <TooltipTrigger>Hover me</TooltipTrigger>
533
+ <TooltipContent>Tooltip text</TooltipContent>
534
+ </Tooltip>
535
+ </TooltipProvider>;
536
+ ```
537
+
538
+ ---
539
+
540
+ ## Utilities
541
+
542
+ ### cn (Class Name utility)
543
+
544
+ A utility function for conditionally merging Tailwind CSS classes.
545
+
546
+ ```tsx
547
+ import { cn } from "@janovix/blocks";
548
+
549
+ const className = cn("base-class", condition && "conditional-class", {
550
+ "another-class": someCondition,
551
+ });
552
+ ```
553
+
554
+ ---
555
+
556
+ ## TypeScript Support
557
+
558
+ All components are fully typed with TypeScript. Import types as needed:
559
+
560
+ ```tsx
561
+ import type {
562
+ ThemeSwitcherProps,
563
+ LanguageSwitcherProps,
564
+ Language,
565
+ AvatarEditorProps,
566
+ AvatarEditorDialogProps,
567
+ NotificationsWidgetProps,
568
+ Notification,
569
+ NotificationType,
570
+ } from "@janovix/blocks";
571
+ ```
572
+
573
+ ---
574
+
575
+ ## Best Practices
576
+
577
+ ### Internationalization
578
+
579
+ All text-based components accept label props for i18n:
580
+
581
+ ```tsx
582
+ import { useTranslation } from "your-i18n-library";
583
+
584
+ const { t } = useTranslation();
585
+
586
+ <ThemeSwitcher
587
+ labels={{
588
+ theme: t("theme"),
589
+ light: t("light"),
590
+ dark: t("dark"),
591
+ system: t("system"),
592
+ }}
593
+ />;
594
+ ```
595
+
596
+ ### Theme Integration
597
+
598
+ Components use CSS variables for theming. Ensure your app provides these variables:
599
+
600
+ ```css
601
+ :root {
602
+ --background: 0 0% 100%;
603
+ --foreground: 222.2 84% 4.9%;
604
+ --primary: 222.2 47.4% 11.2%;
605
+ --muted: 210 40% 96.1%;
606
+ --border: 214.3 31.8% 91.4%;
607
+ /* ... other variables */
608
+ }
609
+ ```
610
+
611
+ ### Notification Management
612
+
613
+ For `NotificationsWidget`, implement a notification management system:
614
+
615
+ ```tsx
616
+ // Example notification manager
617
+ const [notifications, setNotifications] = useState<Notification[]>([]);
618
+
619
+ const markAsRead = (id: string) => {
620
+ setNotifications((prev) =>
621
+ prev.map((n) => (n.id === id ? { ...n, read: true } : n)),
622
+ );
623
+ };
624
+
625
+ const dismiss = (id: string) => {
626
+ setNotifications((prev) => prev.filter((n) => n.id !== id));
627
+ };
628
+
629
+ const addNotification = (notification: Omit<Notification, "id">) => {
630
+ const id = crypto.randomUUID();
631
+ setNotifications((prev) => [{ ...notification, id }, ...prev]);
68
632
  };
69
633
  ```
70
634
 
635
+ ---
636
+
637
+ ## Contributing
638
+
639
+ This package is maintained as part of the Janovix monorepo. See the main repository for contribution guidelines.
640
+
71
641
  ## License
72
642
 
73
- MIT
643
+ Proprietary - Janovix © 2026
644
+
645
+ ## Version
646
+
647
+ Current version: `1.0.0-rc.4`
648
+
649
+ ## Support
650
+
651
+ For issues or questions, contact the Janovix development team or open an issue in the repository.