@archbase/components 3.0.25 → 4.0.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.
Files changed (168) hide show
  1. package/dist/buttons/ArchbaseSpeedDial.d.ts +59 -0
  2. package/dist/buttons/index.d.ts +2 -0
  3. package/dist/charts/ArchbaseArcGauge.d.ts +55 -0
  4. package/dist/charts/ArchbaseGantt.d.ts +70 -0
  5. package/dist/charts/ArchbaseLinearGauge.d.ts +55 -0
  6. package/dist/charts/ArchbaseResourceTimeline.d.ts +61 -0
  7. package/dist/charts/ArchbaseSparkline.d.ts +45 -0
  8. package/dist/charts/index.d.ts +10 -0
  9. package/dist/containers/ArchbaseExpansionPanel.d.ts +60 -0
  10. package/dist/containers/ArchbaseFloatingPanel.d.ts +91 -0
  11. package/dist/containers/index.d.ts +4 -0
  12. package/dist/datagrid/export/ArchbaseDataGridExcelExport.d.ts +67 -0
  13. package/dist/datagrid/export/index.d.ts +2 -0
  14. package/dist/datagrid/index.d.ts +1 -0
  15. package/dist/display/ArchbaseAnimationWrapper.d.ts +73 -0
  16. package/dist/display/ArchbaseBarcodeGenerator.d.ts +50 -0
  17. package/dist/display/ArchbaseCarousel.d.ts +100 -0
  18. package/dist/display/ArchbaseCodeViewer.d.ts +63 -0
  19. package/dist/display/ArchbaseDiffViewer.d.ts +41 -0
  20. package/dist/display/ArchbaseJsonTree.d.ts +34 -0
  21. package/dist/display/ArchbaseLightbox.d.ts +89 -0
  22. package/dist/display/ArchbaseMarquee.d.ts +46 -0
  23. package/dist/display/ArchbasePhotoAlbum.d.ts +58 -0
  24. package/dist/display/ArchbaseQRCode.d.ts +44 -0
  25. package/dist/display/ArchbaseTooltipRich.d.ts +82 -0
  26. package/dist/display/ArchbaseVirtualList.d.ts +116 -0
  27. package/dist/display/index.d.ts +24 -0
  28. package/dist/editors/ArchbaseAIPromptInput.d.ts +69 -0
  29. package/dist/editors/ArchbaseAsyncMultiSelect.d.ts +1 -1
  30. package/dist/editors/ArchbaseAsyncSelect.d.ts +1 -1
  31. package/dist/editors/ArchbaseBarcodeScanner.d.ts +63 -0
  32. package/dist/editors/ArchbaseCepInput.d.ts +26 -0
  33. package/dist/editors/ArchbaseColorGradientPicker.d.ts +80 -0
  34. package/dist/editors/ArchbaseCpfCnpjInput.d.ts +21 -0
  35. package/dist/editors/ArchbaseCurrencyInput.d.ts +25 -0
  36. package/dist/editors/ArchbaseDualListbox.d.ts +61 -0
  37. package/dist/editors/ArchbaseInPlaceEditor.d.ts +67 -0
  38. package/dist/editors/ArchbaseLightGrid.d.ts +56 -0
  39. package/dist/editors/ArchbaseMentionInput.d.ts +75 -0
  40. package/dist/editors/ArchbaseMultiEmail.d.ts +53 -0
  41. package/dist/editors/ArchbaseMultiViewCalendar.d.ts +47 -0
  42. package/dist/editors/ArchbaseNumberStepper.d.ts +66 -0
  43. package/dist/editors/ArchbaseOTPInput.d.ts +27 -0
  44. package/dist/editors/ArchbasePhoneInput.d.ts +52 -0
  45. package/dist/editors/ArchbaseRangeSlider.d.ts +22 -0
  46. package/dist/editors/ArchbaseSignaturePad.d.ts +60 -0
  47. package/dist/editors/ArchbaseSpeechToTextInput.d.ts +106 -0
  48. package/dist/editors/ArchbaseSpreadsheet.d.ts +56 -0
  49. package/dist/editors/ArchbaseTagInput.d.ts +55 -0
  50. package/dist/editors/index.d.ts +40 -0
  51. package/dist/feedback/ArchbaseChunkProgressBar.d.ts +35 -0
  52. package/dist/feedback/ArchbaseRipple.d.ts +43 -0
  53. package/dist/feedback/ArchbaseSkeleton.d.ts +115 -0
  54. package/dist/feedback/index.d.ts +6 -0
  55. package/dist/filters/ArchbaseColumnSelector.d.ts +38 -0
  56. package/dist/filters/index.d.ts +2 -0
  57. package/dist/forms/ArchbaseFieldArray.d.ts +80 -0
  58. package/dist/forms/ArchbaseFormWizard.d.ts +73 -0
  59. package/dist/forms/ArchbaseStepper.d.ts +51 -0
  60. package/dist/forms/index.d.ts +8 -0
  61. package/dist/forms/useArchbaseFormWizard.d.ts +74 -0
  62. package/dist/hooks/index.d.ts +2 -0
  63. package/dist/hooks/useArchbaseConfirm.d.ts +59 -0
  64. package/dist/image/editor/index.d.ts +43 -4
  65. package/dist/image/index.d.ts +1 -0
  66. package/dist/index.css +1 -1
  67. package/dist/index.d.ts +1 -0
  68. package/dist/index.js +22510 -13820
  69. package/dist/list/ArchbaseTreeList.d.ts +76 -0
  70. package/dist/list/index.d.ts +2 -0
  71. package/dist/navigation/ArchbaseActionSheet.d.ts +70 -0
  72. package/dist/navigation/ArchbaseAppBar.d.ts +63 -0
  73. package/dist/navigation/ArchbaseBottomNavigation.d.ts +61 -0
  74. package/dist/navigation/ArchbaseContextMenu.d.ts +76 -0
  75. package/dist/navigation/ArchbaseKeyboardShortcuts.d.ts +85 -0
  76. package/dist/navigation/ArchbaseSpotlight.d.ts +69 -0
  77. package/dist/navigation/index.d.ts +12 -0
  78. package/dist/notification/ArchbaseNotificationCenter.d.ts +56 -0
  79. package/dist/notification/index.d.ts +2 -0
  80. package/dist/onboarding/ArchbaseOnboardingTour.d.ts +27 -76
  81. package/dist/viewers/ArchbaseDocViewer.d.ts +40 -0
  82. package/dist/viewers/ArchbasePdfBuilder.d.ts +53 -0
  83. package/dist/viewers/ArchbaseXmlViewer.d.ts +36 -0
  84. package/dist/viewers/index.d.ts +6 -0
  85. package/package.json +41 -18
  86. package/src/buttons/ArchbaseSpeedDial.tsx +282 -0
  87. package/src/buttons/index.ts +3 -0
  88. package/src/charts/ArchbaseArcGauge.tsx +325 -0
  89. package/src/charts/ArchbaseGantt.tsx +494 -0
  90. package/src/charts/ArchbaseLinearGauge.tsx +288 -0
  91. package/src/charts/ArchbaseResourceTimeline.tsx +433 -0
  92. package/src/charts/ArchbaseSparkline.tsx +193 -0
  93. package/src/charts/index.ts +20 -1
  94. package/src/containers/ArchbaseExpansionPanel.tsx +208 -0
  95. package/src/containers/ArchbaseFloatingPanel.tsx +448 -0
  96. package/src/containers/index.ts +17 -0
  97. package/src/datagrid/components/pagination/grid-pagination.tsx +2 -2
  98. package/src/datagrid/export/ArchbaseDataGridExcelExport.tsx +293 -0
  99. package/src/datagrid/export/index.ts +8 -0
  100. package/src/datagrid/index.tsx +2 -0
  101. package/src/display/ArchbaseAnimationWrapper.tsx +272 -0
  102. package/src/display/ArchbaseBarcodeGenerator.tsx +303 -0
  103. package/src/display/ArchbaseCarousel.tsx +679 -0
  104. package/src/display/ArchbaseCodeViewer.tsx +271 -0
  105. package/src/display/ArchbaseDiffViewer.tsx +108 -0
  106. package/src/display/ArchbaseJsonTree.tsx +150 -0
  107. package/src/display/ArchbaseLightbox.tsx +279 -0
  108. package/src/display/ArchbaseMarquee.tsx +268 -0
  109. package/src/display/ArchbasePhotoAlbum.tsx +415 -0
  110. package/src/display/ArchbaseQRCode.tsx +137 -0
  111. package/src/display/ArchbaseTooltipRich.tsx +317 -0
  112. package/src/display/ArchbaseVirtualList.tsx +618 -0
  113. package/src/display/index.ts +94 -1
  114. package/src/editors/ArchbaseAIPromptInput.tsx +432 -0
  115. package/src/editors/ArchbaseBarcodeScanner.tsx +570 -0
  116. package/src/editors/ArchbaseCepInput.tsx +173 -0
  117. package/src/editors/ArchbaseColorGradientPicker.tsx +460 -0
  118. package/src/editors/ArchbaseCpfCnpjInput.tsx +193 -0
  119. package/src/editors/ArchbaseCurrencyInput.tsx +100 -0
  120. package/src/editors/ArchbaseDualListbox.tsx +671 -0
  121. package/src/editors/ArchbaseInPlaceEditor.tsx +406 -0
  122. package/src/editors/ArchbaseLightGrid.tsx +538 -0
  123. package/src/editors/ArchbaseMentionInput.tsx +384 -0
  124. package/src/editors/ArchbaseMultiEmail.tsx +367 -0
  125. package/src/editors/ArchbaseMultiViewCalendar.tsx +439 -0
  126. package/src/editors/ArchbaseNumberStepper.tsx +219 -0
  127. package/src/editors/ArchbaseOTPInput.tsx +133 -0
  128. package/src/editors/ArchbaseOperationHoursEditor.tsx +1 -1
  129. package/src/editors/ArchbasePhoneInput.tsx +355 -0
  130. package/src/editors/ArchbaseRangeSlider.tsx +109 -0
  131. package/src/editors/ArchbaseSignaturePad.tsx +425 -0
  132. package/src/editors/ArchbaseSpeechToTextInput.tsx +444 -0
  133. package/src/editors/ArchbaseSpreadsheet.tsx +388 -0
  134. package/src/editors/ArchbaseTagInput.tsx +326 -0
  135. package/src/editors/index.tsx +92 -0
  136. package/src/feedback/ArchbaseChunkProgressBar.tsx +156 -0
  137. package/src/feedback/ArchbaseRipple.tsx +278 -0
  138. package/src/feedback/ArchbaseSkeleton.tsx +419 -0
  139. package/src/feedback/index.ts +22 -1
  140. package/src/filters/ArchbaseColumnSelector.tsx +268 -0
  141. package/src/filters/index.ts +2 -0
  142. package/src/forms/ArchbaseFieldArray.tsx +305 -0
  143. package/src/forms/ArchbaseFormWizard.tsx +284 -0
  144. package/src/forms/ArchbaseStepper.tsx +137 -0
  145. package/src/forms/index.ts +24 -2
  146. package/src/forms/useArchbaseFormWizard.ts +283 -0
  147. package/src/hooks/index.ts +12 -0
  148. package/src/hooks/useArchbaseConfirm.ts +293 -0
  149. package/src/image/editor/functions/image-processing.ts +5 -0
  150. package/src/image/editor/index.tsx +305 -391
  151. package/src/image/index.ts +1 -0
  152. package/src/index.ts +3 -0
  153. package/src/list/ArchbaseTreeList.tsx +422 -0
  154. package/src/list/index.ts +3 -0
  155. package/src/navigation/ArchbaseActionSheet.tsx +301 -0
  156. package/src/navigation/ArchbaseAppBar.tsx +233 -0
  157. package/src/navigation/ArchbaseBottomNavigation.tsx +243 -0
  158. package/src/navigation/ArchbaseContextMenu.tsx +298 -0
  159. package/src/navigation/ArchbaseKeyboardShortcuts.tsx +472 -0
  160. package/src/navigation/ArchbaseSpotlight.tsx +483 -0
  161. package/src/navigation/index.ts +48 -1
  162. package/src/notification/ArchbaseNotificationCenter.tsx +502 -0
  163. package/src/notification/index.ts +2 -0
  164. package/src/onboarding/ArchbaseOnboardingTour.tsx +229 -102
  165. package/src/viewers/ArchbaseDocViewer.tsx +584 -0
  166. package/src/viewers/ArchbasePdfBuilder.tsx +291 -0
  167. package/src/viewers/ArchbaseXmlViewer.tsx +142 -0
  168. package/src/viewers/index.ts +12 -0
@@ -0,0 +1,502 @@
1
+ /**
2
+ * ArchbaseNotificationCenter — centro de notificacoes com icone de sino,
3
+ * badge de nao-lidas e painel (Popover ou Drawer) com lista de notificacoes.
4
+ * Implementado com componentes Mantine puros, sem dependencias externas alem de date-fns.
5
+ * @status stable
6
+ */
7
+ import {
8
+ ActionIcon,
9
+ Badge,
10
+ Box,
11
+ Button,
12
+ Divider,
13
+ Drawer,
14
+ Flex,
15
+ Group,
16
+ Indicator,
17
+ MantineSize,
18
+ Popover,
19
+ ScrollArea,
20
+ Stack,
21
+ Text,
22
+ Tooltip,
23
+ UnstyledButton,
24
+ useMantineColorScheme,
25
+ useMantineTheme,
26
+ } from '@mantine/core';
27
+ import type { FloatingPosition } from '@mantine/core';
28
+ import { useDisclosure } from '@mantine/hooks';
29
+ import {
30
+ IconBell,
31
+ IconBellOff,
32
+ IconCheck,
33
+ IconChecks,
34
+ IconCircleCheck,
35
+ IconExclamationCircle,
36
+ IconInfoCircle,
37
+ IconAlertTriangle,
38
+ IconTrash,
39
+ IconX,
40
+ } from '@tabler/icons-react';
41
+ import React, { CSSProperties, ReactNode, useMemo } from 'react';
42
+ import { formatDistanceToNow } from 'date-fns';
43
+ import { ptBR } from 'date-fns/locale';
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Types
47
+ // ---------------------------------------------------------------------------
48
+
49
+ export interface ArchbaseNotificationItem {
50
+ id: string;
51
+ title: string;
52
+ message: string;
53
+ type?: 'info' | 'success' | 'warning' | 'error';
54
+ read: boolean;
55
+ createdAt: Date;
56
+ icon?: ReactNode;
57
+ action?: { label: string; onClick: () => void };
58
+ metadata?: Record<string, any>;
59
+ }
60
+
61
+ export interface ArchbaseNotificationCenterProps {
62
+ /** Lista de notificacoes a exibir */
63
+ notifications: ArchbaseNotificationItem[];
64
+ /** Callback ao marcar uma notificacao como lida */
65
+ onMarkAsRead?: (id: string) => void;
66
+ /** Callback ao marcar todas como lidas */
67
+ onMarkAllAsRead?: () => void;
68
+ /** Callback ao remover uma notificacao */
69
+ onRemove?: (id: string) => void;
70
+ /** Callback ao limpar todas as notificacoes */
71
+ onClearAll?: () => void;
72
+ /** Callback ao clicar em uma notificacao */
73
+ onClick?: (notification: ArchbaseNotificationItem) => void;
74
+ /** Modo de renderizacao: popover ou drawer */
75
+ renderAs?: 'drawer' | 'popover';
76
+ /** Posicao do popover (ignorado no modo drawer) */
77
+ position?: FloatingPosition;
78
+ /** Largura do painel */
79
+ width?: number;
80
+ /** Altura maxima da area de scroll */
81
+ maxHeight?: number;
82
+ /** Titulo do painel */
83
+ title?: string;
84
+ /** Mensagem quando nao ha notificacoes */
85
+ emptyMessage?: string;
86
+ /** Mostrar badge com contagem de nao-lidas */
87
+ showBadge?: boolean;
88
+ /** Tamanho do botao */
89
+ buttonSize?: MantineSize;
90
+ /** Variante do botao */
91
+ buttonVariant?: string;
92
+ /** Estilo customizado do wrapper */
93
+ style?: CSSProperties;
94
+ /** Classe CSS customizada */
95
+ className?: string;
96
+ }
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // Helpers
100
+ // ---------------------------------------------------------------------------
101
+
102
+ const TYPE_COLORS: Record<string, string> = {
103
+ info: 'blue',
104
+ success: 'green',
105
+ warning: 'yellow',
106
+ error: 'red',
107
+ };
108
+
109
+ function defaultIconForType(type: string) {
110
+ switch (type) {
111
+ case 'success':
112
+ return <IconCircleCheck size={20} />;
113
+ case 'warning':
114
+ return <IconAlertTriangle size={20} />;
115
+ case 'error':
116
+ return <IconExclamationCircle size={20} />;
117
+ default:
118
+ return <IconInfoCircle size={20} />;
119
+ }
120
+ }
121
+
122
+ function relativeTime(date: Date): string {
123
+ try {
124
+ return formatDistanceToNow(date, { addSuffix: true, locale: ptBR });
125
+ } catch {
126
+ return '';
127
+ }
128
+ }
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // Sub-components
132
+ // ---------------------------------------------------------------------------
133
+
134
+ interface NotificationItemRowProps {
135
+ notification: ArchbaseNotificationItem;
136
+ onMarkAsRead?: (id: string) => void;
137
+ onRemove?: (id: string) => void;
138
+ onClick?: (notification: ArchbaseNotificationItem) => void;
139
+ }
140
+
141
+ function NotificationItemRow({ notification, onMarkAsRead, onRemove, onClick }: NotificationItemRowProps) {
142
+ const theme = useMantineTheme();
143
+ const { colorScheme } = useMantineColorScheme();
144
+ const isDark = colorScheme === 'dark';
145
+ const type = notification.type ?? 'info';
146
+ const color = TYPE_COLORS[type] ?? 'blue';
147
+ const icon = notification.icon ?? defaultIconForType(type);
148
+
149
+ return (
150
+ <UnstyledButton
151
+ onClick={() => {
152
+ if (!notification.read && onMarkAsRead) {
153
+ onMarkAsRead(notification.id);
154
+ }
155
+ onClick?.(notification);
156
+ }}
157
+ style={{
158
+ display: 'block',
159
+ width: '100%',
160
+ padding: '10px 12px',
161
+ borderRadius: theme.radius.sm,
162
+ backgroundColor: notification.read
163
+ ? 'transparent'
164
+ : isDark
165
+ ? theme.colors.dark[6]
166
+ : theme.colors.gray[0],
167
+ cursor: 'pointer',
168
+ transition: 'background-color 150ms ease',
169
+ }}
170
+ onMouseOver={(e) => {
171
+ (e.currentTarget as HTMLElement).style.backgroundColor = isDark
172
+ ? theme.colors.dark[5]
173
+ : theme.colors.gray[1];
174
+ }}
175
+ onMouseOut={(e) => {
176
+ (e.currentTarget as HTMLElement).style.backgroundColor = notification.read
177
+ ? 'transparent'
178
+ : isDark
179
+ ? theme.colors.dark[6]
180
+ : theme.colors.gray[0];
181
+ }}
182
+ >
183
+ <Flex gap="sm" align="flex-start">
184
+ {/* Icon */}
185
+ <Box
186
+ style={{
187
+ color: theme.colors[color]?.[isDark ? 4 : 6] ?? color,
188
+ flexShrink: 0,
189
+ marginTop: 2,
190
+ }}
191
+ >
192
+ {icon}
193
+ </Box>
194
+
195
+ {/* Content */}
196
+ <Box style={{ flex: 1, minWidth: 0 }}>
197
+ <Flex justify="space-between" align="center" gap={4}>
198
+ <Text
199
+ size="sm"
200
+ fw={notification.read ? 400 : 600}
201
+ truncate
202
+ style={{ flex: 1 }}
203
+ >
204
+ {notification.title}
205
+ </Text>
206
+ {!notification.read && (
207
+ <Box
208
+ style={{
209
+ width: 8,
210
+ height: 8,
211
+ borderRadius: '50%',
212
+ backgroundColor: theme.colors[color]?.[isDark ? 4 : 6] ?? color,
213
+ flexShrink: 0,
214
+ }}
215
+ />
216
+ )}
217
+ </Flex>
218
+
219
+ <Text size="xs" c="dimmed" lineClamp={2} mt={2}>
220
+ {notification.message}
221
+ </Text>
222
+
223
+ <Flex justify="space-between" align="center" mt={6}>
224
+ <Text size="xs" c="dimmed">
225
+ {relativeTime(notification.createdAt)}
226
+ </Text>
227
+
228
+ <Group gap={4}>
229
+ {notification.action && (
230
+ <Button
231
+ size="compact-xs"
232
+ variant="light"
233
+ color={color}
234
+ onClick={(e) => {
235
+ e.stopPropagation();
236
+ notification.action!.onClick();
237
+ }}
238
+ >
239
+ {notification.action.label}
240
+ </Button>
241
+ )}
242
+ {!notification.read && onMarkAsRead && (
243
+ <Tooltip label="Marcar como lida" withArrow>
244
+ <ActionIcon
245
+ size="xs"
246
+ variant="subtle"
247
+ color="gray"
248
+ onClick={(e) => {
249
+ e.stopPropagation();
250
+ onMarkAsRead(notification.id);
251
+ }}
252
+ >
253
+ <IconCheck size={14} />
254
+ </ActionIcon>
255
+ </Tooltip>
256
+ )}
257
+ {onRemove && (
258
+ <Tooltip label="Remover" withArrow>
259
+ <ActionIcon
260
+ size="xs"
261
+ variant="subtle"
262
+ color="gray"
263
+ onClick={(e) => {
264
+ e.stopPropagation();
265
+ onRemove(notification.id);
266
+ }}
267
+ >
268
+ <IconX size={14} />
269
+ </ActionIcon>
270
+ </Tooltip>
271
+ )}
272
+ </Group>
273
+ </Flex>
274
+ </Box>
275
+ </Flex>
276
+ </UnstyledButton>
277
+ );
278
+ }
279
+
280
+ // ---------------------------------------------------------------------------
281
+ // Panel content (shared between Popover and Drawer)
282
+ // ---------------------------------------------------------------------------
283
+
284
+ interface PanelContentProps {
285
+ notifications: ArchbaseNotificationItem[];
286
+ sortedNotifications: ArchbaseNotificationItem[];
287
+ unreadCount: number;
288
+ title: string;
289
+ emptyMessage: string;
290
+ maxHeight: number;
291
+ onMarkAsRead?: (id: string) => void;
292
+ onMarkAllAsRead?: () => void;
293
+ onRemove?: (id: string) => void;
294
+ onClearAll?: () => void;
295
+ onClick?: (notification: ArchbaseNotificationItem) => void;
296
+ }
297
+
298
+ function PanelContent({
299
+ sortedNotifications,
300
+ unreadCount,
301
+ title,
302
+ emptyMessage,
303
+ maxHeight,
304
+ onMarkAsRead,
305
+ onMarkAllAsRead,
306
+ onRemove,
307
+ onClearAll,
308
+ onClick,
309
+ }: PanelContentProps) {
310
+ const { colorScheme } = useMantineColorScheme();
311
+ const isDark = colorScheme === 'dark';
312
+
313
+ return (
314
+ <Stack gap={0}>
315
+ {/* Header */}
316
+ <Flex justify="space-between" align="center" px="md" py="sm">
317
+ <Group gap="xs">
318
+ <Text fw={600} size="md">
319
+ {title}
320
+ </Text>
321
+ {unreadCount > 0 && (
322
+ <Badge size="sm" variant="filled" color="blue" circle={unreadCount < 100}>
323
+ {unreadCount}
324
+ </Badge>
325
+ )}
326
+ </Group>
327
+ {unreadCount > 0 && onMarkAllAsRead && (
328
+ <Tooltip label="Marcar todas como lidas" withArrow>
329
+ <ActionIcon variant="subtle" color="blue" onClick={onMarkAllAsRead}>
330
+ <IconChecks size={18} />
331
+ </ActionIcon>
332
+ </Tooltip>
333
+ )}
334
+ </Flex>
335
+
336
+ <Divider />
337
+
338
+ {/* Body */}
339
+ {sortedNotifications.length === 0 ? (
340
+ <Stack align="center" justify="center" py="xl" gap="xs">
341
+ <IconBellOff
342
+ size={48}
343
+ style={{
344
+ color: isDark ? '#5c5f66' : '#adb5bd',
345
+ }}
346
+ />
347
+ <Text size="sm" c="dimmed">
348
+ {emptyMessage}
349
+ </Text>
350
+ </Stack>
351
+ ) : (
352
+ <ScrollArea.Autosize mah={maxHeight} type="auto" offsetScrollbars>
353
+ <Stack gap={2} p="xs">
354
+ {sortedNotifications.map((notification) => (
355
+ <NotificationItemRow
356
+ key={notification.id}
357
+ notification={notification}
358
+ onMarkAsRead={onMarkAsRead}
359
+ onRemove={onRemove}
360
+ onClick={onClick}
361
+ />
362
+ ))}
363
+ </Stack>
364
+ </ScrollArea.Autosize>
365
+ )}
366
+
367
+ {/* Footer */}
368
+ {sortedNotifications.length > 0 && onClearAll && (
369
+ <>
370
+ <Divider />
371
+ <Flex justify="center" py="xs">
372
+ <Button
373
+ variant="subtle"
374
+ color="gray"
375
+ size="compact-sm"
376
+ leftSection={<IconTrash size={14} />}
377
+ onClick={onClearAll}
378
+ >
379
+ Limpar todas
380
+ </Button>
381
+ </Flex>
382
+ </>
383
+ )}
384
+ </Stack>
385
+ );
386
+ }
387
+
388
+ // ---------------------------------------------------------------------------
389
+ // Main component
390
+ // ---------------------------------------------------------------------------
391
+
392
+ export function ArchbaseNotificationCenter(props: ArchbaseNotificationCenterProps) {
393
+ const {
394
+ notifications,
395
+ onMarkAsRead,
396
+ onMarkAllAsRead,
397
+ onRemove,
398
+ onClearAll,
399
+ onClick,
400
+ renderAs = 'popover',
401
+ position = 'bottom-end',
402
+ width = 380,
403
+ maxHeight = 500,
404
+ title = 'Notificações',
405
+ emptyMessage = 'Nenhuma notificação',
406
+ showBadge = true,
407
+ buttonSize = 'lg',
408
+ buttonVariant = 'subtle',
409
+ style,
410
+ className,
411
+ } = props;
412
+
413
+ const [opened, { open, close, toggle }] = useDisclosure(false);
414
+
415
+ const unreadCount = useMemo(
416
+ () => notifications.filter((n) => !n.read).length,
417
+ [notifications],
418
+ );
419
+
420
+ const sortedNotifications = useMemo(() => {
421
+ return [...notifications].sort((a, b) => {
422
+ // Unread first
423
+ if (a.read !== b.read) return a.read ? 1 : -1;
424
+ // Then by createdAt descending
425
+ return b.createdAt.getTime() - a.createdAt.getTime();
426
+ });
427
+ }, [notifications]);
428
+
429
+ const bellButton = (
430
+ <Indicator
431
+ disabled={!showBadge || unreadCount === 0}
432
+ label={unreadCount > 99 ? '99+' : unreadCount}
433
+ size={18}
434
+ color="red"
435
+ offset={4}
436
+ processing={unreadCount > 0}
437
+ >
438
+ <ActionIcon
439
+ variant={buttonVariant as any}
440
+ size={buttonSize}
441
+ onClick={toggle}
442
+ aria-label="Abrir central de notificações"
443
+ >
444
+ <IconBell size={22} />
445
+ </ActionIcon>
446
+ </Indicator>
447
+ );
448
+
449
+ const panelProps: PanelContentProps = {
450
+ notifications,
451
+ sortedNotifications,
452
+ unreadCount,
453
+ title,
454
+ emptyMessage,
455
+ maxHeight,
456
+ onMarkAsRead,
457
+ onMarkAllAsRead,
458
+ onRemove,
459
+ onClearAll,
460
+ onClick,
461
+ };
462
+
463
+ if (renderAs === 'drawer') {
464
+ return (
465
+ <Box style={style} className={className}>
466
+ {bellButton}
467
+ <Drawer
468
+ opened={opened}
469
+ onClose={close}
470
+ position="right"
471
+ size={width}
472
+ title={undefined}
473
+ withCloseButton={false}
474
+ padding={0}
475
+ >
476
+ <PanelContent {...panelProps} />
477
+ </Drawer>
478
+ </Box>
479
+ );
480
+ }
481
+
482
+ return (
483
+ <Box style={style} className={className}>
484
+ <Popover
485
+ opened={opened}
486
+ onClose={close}
487
+ position={position}
488
+ width={width}
489
+ shadow="lg"
490
+ radius="md"
491
+ withArrow
492
+ >
493
+ <Popover.Target>{bellButton}</Popover.Target>
494
+ <Popover.Dropdown p={0} style={{ overflow: 'hidden' }}>
495
+ <PanelContent {...panelProps} />
496
+ </Popover.Dropdown>
497
+ </Popover>
498
+ </Box>
499
+ );
500
+ }
501
+
502
+ ArchbaseNotificationCenter.displayName = 'ArchbaseNotificationCenter';
@@ -2,3 +2,5 @@ export { ArchbaseNotifications } from './ArchbaseNotifications';
2
2
  export { ArchbaseAlert } from './ArchbaseAlert';
3
3
  export type { ArchbaseAlertProps } from './ArchbaseAlert';
4
4
  export { ArchbaseDialog, CustomShowErrorModal } from './ArchbaseDialog';
5
+ export { ArchbaseNotificationCenter } from './ArchbaseNotificationCenter';
6
+ export type { ArchbaseNotificationCenterProps, ArchbaseNotificationItem } from './ArchbaseNotificationCenter';